From afd67c7af87446553d95e44bf9c6461c6ad856d5 Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Tue, 12 Aug 2014 15:13:02 -0400 Subject: [PATCH] Initial import of CVS-v2_8_branch --- AUTHORS | 47 + CODINGSTYLE | 201 + COPYING | 340 + ChangeLog | 14297 ++++++++++++++++ INSTALL | 185 + Makefile.am | 162 + NEWS | 2743 +++ PACKAGE_VERSION | 1 + README | 71 + UPGRADING | 74 + acinclude.m4 | 504 + autogen.sh | 48 + build_win32.bat | 37 + cae/Makefile.am | 55 + cae/cae.cpp | 2276 +++ cae/cae.h | 410 + cae/cae_alsa.cpp | 1893 ++ cae/cae_hpi.cpp | 536 + cae/cae_jack.cpp | 1607 ++ cae/cae_socket.cpp | 55 + cae/cae_socket.h | 50 + conf/Makefile.am | 54 + conf/my.cnf-master | 59 + conf/my.cnf-standby | 78 + conf/rd-bin.conf.in | 51 + conf/rd-sample.ini | 118 + conf/rd.conf-sample | 133 + conf/rd.conf-slax | 45 + conf/rlm_ando.conf | 84 + conf/rlm_facebook.conf | 76 + conf/rlm_filewrite.conf | 111 + conf/rlm_icecast2.conf | 92 + conf/rlm_inno713.conf | 110 + conf/rlm_liqcomp.conf | 78 + conf/rlm_padpoint.conf | 45 + conf/rlm_serial.conf | 129 + conf/rlm_shoutcast1.conf | 82 + conf/rlm_spinitron_plus.conf | 129 + conf/rlm_spottrap.conf | 106 + conf/rlm_twitter.conf | 76 + conf/rlm_udp.conf | 118 + conf/rlm_xds.conf | 58 + conf/rlm_xmpad.conf | 98 + configure.in | 543 + debian/Makefile.am | 68 + debian/README.Debian | 55 + debian/changelog | 387 + debian/compat | 1 + debian/control | 38 + debian/copyright | 15 + debian/librivendell.install | 6 + debian/menu | 42 + debian/patches/00list | 4 + debian/patches/00template | 26 + debian/patches/07_extra_paren.dpatch | 38 + debian/patches/Makefile.am | 29 + debian/rdadmin.desktop | 9 + debian/rdadmin.xpm | 768 + debian/rdairplay.desktop | 9 + debian/rdairplay.xpm | 738 + debian/rdcatch.desktop | 9 + debian/rdcatch.xpm | 780 + debian/rdlibrary.desktop | 9 + debian/rdlibrary.xpm | 788 + debian/rdlogedit.desktop | 9 + debian/rdlogedit.xpm | 751 + debian/rdlogin.desktop | 9 + debian/rdlogin.xpm | 715 + debian/rdlogmanager.desktop | 9 + debian/rdlogmanager.xpm | 745 + debian/rivendell.conffiles | 1 + debian/rivendell.config | 110 + debian/rivendell.docs.in | 9 + debian/rivendell.examples | 2 + debian/rivendell.init | 83 + debian/rivendell.install | 5 + debian/rivendell.logrotate | 27 + debian/rivendell.postinst | 315 + debian/rivendell.postrm | 77 + debian/rivendell.templates | 228 + debian/rules | 117 + docs/ALSA.txt | 42 + docs/ENCODERS.txt | 93 + docs/GPIO.txt | 185 + docs/JACK.txt | 110 + docs/MESSAGE_BOX.txt | 9 + docs/Makefile.am | 62 + docs/NEXGEN_FILTER.txt | 0 docs/NOW+NEXT.txt | 57 + docs/PODCASTING.txt | 132 + docs/RDMONITOR.txt | 58 + docs/RIVENDELL_FILTER.txt | 70 + docs/SAGE_ENDEC.txt | 24 + docs/SWITCHERS.txt | 631 + docs/WIN32.txt | 25 + docs/WINGS_FILTER.txt | 67 + docs/ando_interface.odt | Bin 0 -> 21106 bytes docs/asound.conf-sample | 11 + docs/cae.sxw | Bin 0 -> 15896 bytes docs/catchd.txt | 117 + docs/colors | 44 + docs/copy_split_format.odt | Bin 0 -> 20186 bytes docs/datetime_wildcards.txt | 122 + docs/examples/0320090805.cpi | 4 + docs/examples/0320090805.elr | 4 + docs/examples/0320090805.tfc | 4 + docs/examples/0320090805.vti | 4 + docs/examples/080509T3.LOG | 5 + docs/examples/Makefile.am | 33 + docs/examples/cart_report.asc | 13 + docs/implemented_macros.txt | 48 + docs/pam_rd.txt | 62 + docs/reports.txt | 95 + docs/ripc.txt | 86 + docs/rml.sxw | Bin 0 -> 26168 bytes docs/scheduler_formats.ods | Bin 0 -> 19094 bytes docs/tables/Makefile.am | 80 + docs/tables/audio_perms.txt | 12 + docs/tables/audio_ports.txt | 62 + docs/tables/cart.txt | 52 + docs/tables/cartslots.txt | 23 + docs/tables/clipboard.txt | 34 + docs/tables/clock_perms.txt | 12 + docs/tables/copy_splits.txt | 14 + docs/tables/cuts.txt | 63 + docs/tables/decks.txt | 26 + docs/tables/dropbox_paths.txt | 11 + docs/tables/dropbox_sched_codes.txt | 11 + docs/tables/dropboxes.txt | 28 + docs/tables/encoder_bitrates.txt | 11 + docs/tables/encoder_channels.txt | 11 + docs/tables/encoder_samplerates.txt | 11 + docs/tables/encoders.txt | 13 + docs/tables/extended_panel_names.txt | 13 + docs/tables/feed_perms.txt | 12 + docs/tables/gpis.txt | 14 + docs/tables/gpos.txt | 14 + docs/tables/groups.txt | 21 + docs/tables/isci_xreference.txt | 19 + docs/tables/jack_clients.txt | 11 + docs/tables/livewire_gpio_slots.txt | 14 + docs/tables/log_format.txt | 47 + docs/tables/log_modes.txt | 14 + docs/tables/logs.txt | 28 + docs/tables/nownext_plugins.txt | 13 + docs/tables/panel_names.txt | 13 + docs/tables/panels.txt | 17 + docs/tables/rd_airplay.txt | 81 + docs/tables/rd_catch.txt | 10 + docs/tables/rd_library.txt | 38 + docs/tables/rd_logedit.txt | 27 + docs/tables/rdairplay_channels.txt | 32 + docs/tables/rdpanel_channels.txt | 32 + docs/tables/recordings.txt | 64 + docs/tables/repl_cart_state.txt | 14 + docs/tables/repl_cut_state.txt | 12 + docs/tables/replicator_map.txt | 11 + docs/tables/replicators.txt | 21 + docs/tables/services.txt | 265 + docs/tables/sources.txt | 15 + docs/tables/stations.txt | 77 + docs/tables/svc_rec_format.txt | 41 + docs/tables/triggers.txt | 12 + docs/tables/ttys.txt | 17 + docs/tables/user_perms.txt | 12 + docs/tables/users.txt | 35 + docs/tables/version.txt | 11 + docs/tables/vguest_resources.txt | 20 + docs/tables/web_connections.txt | 11 + docs/web_api.odt | Bin 0 -> 20514 bytes get_distro.sh | 83 + get_target.sh | 42 + helpers/Makefile.am | 55 + helpers/cwrap.cpp | 136 + helpers/cwrap.h | 37 + helpers/jsmin.c | 275 + helpers/rdpack.sh | 50 + helpers/rdtrans.sh | 153 + helpers/rdtransgui.sh | 187 + helpers/setenvvar.sh | 197 + helpers/win32_frag1.txt | 1 + helpers/win32_frag2.txt | 1 + icons/Makefile.am | 130 + icons/admin.xpm | 26 + icons/blueball.xpm | 58 + icons/chain.xpm | 22 + icons/checkmark.xpm | 22 + icons/download.xpm | 22 + icons/ex.xpm | 22 + icons/fillstart.xpm | 25 + icons/fillstop.xpm | 25 + icons/greenball.png | Bin 0 -> 435 bytes icons/greenball.xpm | 58 + icons/greencheckmark.png | Bin 0 -> 217 bytes icons/greencheckmark.xpm | 23 + icons/macro.xpm | 174 + icons/marker.xpm | 23 + icons/mic16.xpm | 95 + icons/music.xpm | 90 + icons/note.xpm | 21 + icons/note2.xpm | 39 + icons/notemarker.xpm | 120 + icons/play.xpm | 26 + icons/post.xpm | 25 + icons/post2.xpm | 27 + icons/post3.xpm | 24 + icons/progressbar.gif | Bin 0 -> 3130 bytes icons/progressbar.xcf | Bin 0 -> 13026 bytes icons/record.xpm | 29 + icons/record2.xpm | 26 + icons/record3.xpm | 26 + icons/redball.png | Bin 0 -> 410 bytes icons/redball.xpm | 58 + icons/redcheckmark.xpm | 63 + icons/redx.png | Bin 0 -> 691 bytes icons/redx.xpm | 121 + icons/rivendell-128x128.png | Bin 0 -> 917 bytes icons/rivendell-128x128.xpm | 138 + icons/rivendell-16x16.png | Bin 0 -> 439 bytes icons/rivendell-16x16.xpm | 53 + icons/rivendell-22x22.png | Bin 0 -> 851 bytes icons/rivendell-22x22.xpm | 119 + icons/rivendell-32x32.png | Bin 0 -> 510 bytes icons/rivendell-32x32.xpm | 42 + icons/rivendell-48x48.png | Bin 0 -> 1024 bytes icons/rivendell-48x48.xpm | 77 + icons/rivendell-64x64.png | Bin 0 -> 675 bytes icons/rivendell-64x64.xpm | 74 + icons/rivendell.ico | Bin 0 -> 766 bytes icons/rivendell.res | Bin 0 -> 868 bytes icons/rml.xpm | 23 + icons/rml2.xpm | 23 + icons/rml3.xpm | 23 + icons/rml5.xpm | 175 + icons/split.xpm | 26 + icons/switch.xpm | 24 + icons/switch2.xpm | 29 + icons/switch3.xpm | 100 + icons/track.xpm | 23 + icons/track_cart.xpm | 26 + icons/traffic.xpm | 167 + icons/trashcan-16x16.xpm | 72 + icons/trashcan-32x32.xpm | 281 + icons/upload.xpm | 22 + icons/user.xpm | 76 + icons/whiteball.png | Bin 0 -> 334 bytes icons/whiteball.xpm | 37 + importers/Makefile.am | 76 + importers/export_slax | 74 + importers/nexgen_filter.cpp | 713 + importers/nexgen_filter.h | 77 + importers/panel_copy.cpp | 219 + importers/panel_copy.h | 48 + importers/rdcatch_copy.cpp | 335 + importers/rdcatch_copy.h | 52 + importers/rivendell_filter.cpp | 497 + importers/rivendell_filter.h | 43 + importers/sas_filter.cpp | 283 + importers/sas_filter.h | 61 + importers/wings_filter.cpp | 329 + importers/wings_filter.h | 71 + install-init.sh | 41 + ios/Makefile.am | 40 + ios/rmlsend/Classes/Makefile.am | 33 + ios/rmlsend/Classes/RMLSendAppDelegate.h | 35 + ios/rmlsend/Classes/RMLSendAppDelegate.m | 104 + ios/rmlsend/Classes/RMLSendViewController.h | 68 + ios/rmlsend/Classes/RMLSendViewController.m | 262 + ios/rmlsend/Classes/TextFieldDelegate.h | 32 + ios/rmlsend/Classes/TextFieldDelegate.m | 35 + ios/rmlsend/Icon.png | Bin 0 -> 5931 bytes ios/rmlsend/MainWindow.xib | 444 + ios/rmlsend/Makefile.am | 48 + ios/rmlsend/RMLSend-Info.plist | 30 + ios/rmlsend/RMLSend.xcodeproj/Makefile.am | 40 + ios/rmlsend/RMLSend.xcodeproj/project.pbxproj | 269 + ios/rmlsend/RMLSendViewController.xib | 732 + ios/rmlsend/RMLSend_Prefix.pch | 25 + ios/rmlsend/main.m | 30 + lib/Makefile.am | 352 + lib/dbversion.h | 32 + lib/export_bmiemr.cpp | 149 + lib/export_deltaflex.cpp | 185 + lib/export_musicclassical.cpp | 135 + lib/export_musicplayout.cpp | 140 + lib/export_musicsummary.cpp | 104 + lib/export_nprsoundex.cpp | 91 + lib/export_radiotraffic.cpp | 124 + lib/export_soundex.cpp | 152 + lib/export_technical.cpp | 178 + lib/export_textlog.cpp | 167 + lib/gpio.h | 125 + lib/gpl2.html | 348 + lib/html_gpl2.cpp | 1149 ++ lib/html_gpl2_win32.cpp | 1169 ++ lib/lib.pro | 312 + lib/librd_cs.ts | 2189 +++ lib/librd_de.ts | 2180 +++ lib/librd_es.ts | 2176 +++ lib/librd_fr.ts | 1773 ++ lib/librd_nb.ts | 2121 +++ lib/librd_nn.ts | 2121 +++ lib/librd_pt_BR.ts | 2131 +++ lib/rd.h | 571 + lib/rdadd_cart.cpp | 282 + lib/rdadd_cart.h | 64 + lib/rdadd_log.cpp | 197 + lib/rdadd_log.h | 76 + lib/rdairplay_conf.cpp | 997 ++ lib/rdairplay_conf.h | 183 + lib/rdaudio_exists.cpp | 35 + lib/rdaudio_exists.h | 29 + lib/rdaudio_port.cpp | 189 + lib/rdaudio_port.h | 55 + lib/rdaudioconvert.cpp | 1819 ++ lib/rdaudioconvert.h | 156 + lib/rdaudioexport.cpp | 279 + lib/rdaudioexport.h | 76 + lib/rdaudioimport.cpp | 319 + lib/rdaudioimport.h | 70 + lib/rdaudioinfo.cpp | 245 + lib/rdaudioinfo.h | 66 + lib/rdaudiosettings.cpp | 76 + lib/rdaudiosettings.h | 49 + lib/rdaudiosettings_dialog.cpp | 507 + lib/rdaudiosettings_dialog.h | 59 + lib/rdbusybar.cpp | 76 + lib/rdbusybar.h | 51 + lib/rdbusydialog.cpp | 74 + lib/rdbusydialog.h | 51 + lib/rdbutton_dialog.cpp | 262 + lib/rdbutton_dialog.h | 84 + lib/rdbutton_panel.cpp | 214 + lib/rdbutton_panel.h | 68 + lib/rdcae.cpp | 664 + lib/rdcae.h | 133 + lib/rdcardselector.cpp | 250 + lib/rdcardselector.h | 77 + lib/rdcart.cpp | 1701 ++ lib/rdcart.h | 178 + lib/rdcart_dialog.cpp | 943 + lib/rdcart_dialog.h | 132 + lib/rdcart_search_text.cpp | 176 + lib/rdcart_search_text.h | 37 + lib/rdcartdrag.cpp | 141 + lib/rdcartdrag.h | 52 + lib/rdcartslot.cpp | 727 + lib/rdcartslot.h | 135 + lib/rdcastsearch.cpp | 78 + lib/rdcastsearch.h | 32 + lib/rdcatch_conf.cpp | 86 + lib/rdcatch_conf.h | 43 + lib/rdcatch_connect.cpp | 364 + lib/rdcatch_connect.h | 104 + lib/rdcddblookup.cpp | 433 + lib/rdcddblookup.h | 91 + lib/rdcddbrecord.cpp | 281 + lib/rdcddbrecord.h | 99 + lib/rdcdplayer.cpp | 555 + lib/rdcdplayer.h | 123 + lib/rdcdripper.cpp | 205 + lib/rdcdripper.h | 62 + lib/rdcheck_daemons.cpp | 133 + lib/rdcheck_daemons.h | 37 + lib/rdcheck_version.cpp | 37 + lib/rdcheck_version.h | 30 + lib/rdclock.cpp | 337 + lib/rdclock.h | 77 + lib/rdcmd_cache.cpp | 105 + lib/rdcmd_cache.h | 50 + lib/rdcmd_switch.cpp | 122 + lib/rdcmd_switch.h | 48 + lib/rdcodetrap.cpp | 125 + lib/rdcodetrap.h | 64 + lib/rdcombobox.cpp | 87 + lib/rdcombobox.h | 53 + lib/rdconf.cpp | 1215 ++ lib/rdconf.h | 118 + lib/rdconfig.cpp | 562 + lib/rdconfig.h | 160 + lib/rdcopyaudio.cpp | 183 + lib/rdcopyaudio.h | 53 + lib/rdcreate_log.cpp | 150 + lib/rdcreate_log.h | 34 + lib/rdcreateauxfieldstable.cpp | 33 + lib/rdcreateauxfieldstable.h | 31 + lib/rdcueedit.cpp | 727 + lib/rdcueedit.h | 116 + lib/rdcueeditdialog.cpp | 116 + lib/rdcueeditdialog.h | 56 + lib/rdcut.cpp | 1614 ++ lib/rdcut.h | 163 + lib/rdcut_dialog.cpp | 675 + lib/rdcut_dialog.h | 106 + lib/rdcut_path.cpp | 55 + lib/rdcut_path.h | 32 + lib/rddatedecode.cpp | 340 + lib/rddatedecode.h | 34 + lib/rddatedialog.cpp | 117 + lib/rddatedialog.h | 62 + lib/rddatepicker.cpp | 351 + lib/rddatepicker.h | 80 + lib/rddb.cpp | 149 + lib/rddb.h | 64 + lib/rddbheartbeat.cpp | 41 + lib/rddbheartbeat.h | 42 + lib/rddebug.cpp | 32 + lib/rddebug.h | 33 + lib/rddeck.cpp | 363 + lib/rddeck.h | 79 + lib/rddelete.cpp | 228 + lib/rddelete.h | 51 + lib/rddownload.cpp | 293 + lib/rddownload.h | 67 + lib/rddropbox.cpp | 353 + lib/rddropbox.h | 84 + lib/rdedit_audio.cpp | 2940 ++++ lib/rdedit_audio.h | 231 + lib/rdedit_panel_name.cpp | 108 + lib/rdedit_panel_name.h | 48 + lib/rdemptycart.cpp | 63 + lib/rdemptycart.h | 49 + lib/rdencoder.cpp | 142 + lib/rdencoder.h | 64 + lib/rdencoderlist.cpp | 90 + lib/rdencoderlist.h | 45 + lib/rdescape_string.cpp | 180 + lib/rdescape_string.h | 31 + lib/rdevent.cpp | 421 + lib/rdevent.h | 90 + lib/rdevent_line.cpp | 1162 ++ lib/rdevent_line.h | 118 + lib/rdevent_player.cpp | 94 + lib/rdevent_player.h | 59 + lib/rdexception_dialog.cpp | 134 + lib/rdexception_dialog.h | 48 + lib/rdexport_settings_dialog.cpp | 936 + lib/rdexport_settings_dialog.h | 72 + lib/rdfeed.cpp | 902 + lib/rdfeed.h | 133 + lib/rdfeedlog.cpp | 138 + lib/rdfeedlog.h | 36 + lib/rdflacdecode.cpp | 144 + lib/rdflacdecode.h | 61 + lib/rdformpost.cpp | 532 + lib/rdformpost.h | 71 + lib/rdgain_envelope.cpp | 113 + lib/rdgain_envelope.h | 56 + lib/rdget_ath.cpp | 130 + lib/rdget_ath.h | 50 + lib/rdgetpasswd.cpp | 115 + lib/rdgetpasswd.h | 50 + lib/rdgpio.cpp | 434 + lib/rdgpio.h | 91 + lib/rdgpioselector.cpp | 95 + lib/rdgpioselector.h | 54 + lib/rdgrid.cpp | 87 + lib/rdgrid.h | 49 + lib/rdgroup.cpp | 487 + lib/rdgroup.h | 81 + lib/rdgroup_list.cpp | 79 + lib/rdgroup_list.h | 46 + lib/rdhotkeylist.cpp | 137 + lib/rdhotkeylist.h | 50 + lib/rdhotkeys.cpp | 321 + lib/rdhotkeys.h | 26 + lib/rdidvalidator.cpp | 52 + lib/rdidvalidator.h | 43 + lib/rdimport_audio.cpp | 700 + lib/rdimport_audio.h | 145 + lib/rdinstancelock.cpp | 105 + lib/rdinstancelock.h | 45 + lib/rdintegerdialog.cpp | 112 + lib/rdintegerdialog.h | 52 + lib/rdintegeredit.cpp | 154 + lib/rdintegeredit.h | 63 + lib/rdlabel.cpp | 141 + lib/rdlabel.h | 61 + lib/rdlibrary_conf.cpp | 422 + lib/rdlibrary_conf.h | 95 + lib/rdlicense.cpp | 91 + lib/rdlicense.h | 51 + lib/rdlineedit.cpp | 49 + lib/rdlineedit.h | 49 + lib/rdlist_groups.cpp | 171 + lib/rdlist_groups.h | 57 + lib/rdlist_logs.cpp | 196 + lib/rdlist_logs.h | 69 + lib/rdlistselector.cpp | 270 + lib/rdlistselector.h | 82 + lib/rdlistsvcs.cpp | 142 + lib/rdlistsvcs.h | 59 + lib/rdlistview.cpp | 126 + lib/rdlistview.h | 58 + lib/rdlistviewitem.cpp | 239 + lib/rdlistviewitem.h | 63 + lib/rdlivewire.cpp | 836 + lib/rdlivewire.h | 134 + lib/rdlivewiredestination.cpp | 142 + lib/rdlivewiredestination.h | 62 + lib/rdlivewiresource.cpp | 167 + lib/rdlivewiresource.h | 69 + lib/rdlog.cpp | 685 + lib/rdlog.h | 101 + lib/rdlog_event.cpp | 1245 ++ lib/rdlog_event.h | 86 + lib/rdlog_line.cpp | 2095 +++ lib/rdlog_line.h | 374 + lib/rdlogedit_conf.cpp | 352 + lib/rdlogedit_conf.h | 87 + lib/rdmacro.cpp | 345 + lib/rdmacro.h | 84 + lib/rdmacro_event.cpp | 342 + lib/rdmacro_event.h | 88 + lib/rdmarker_bar.cpp | 125 + lib/rdmarker_bar.h | 54 + lib/rdmarker_button.cpp | 49 + lib/rdmarker_button.h | 43 + lib/rdmarker_edit.cpp | 69 + lib/rdmarker_edit.h | 49 + lib/rdmatrix.cpp | 794 + lib/rdmatrix.h | 127 + lib/rdmeteraverage.cpp | 51 + lib/rdmeteraverage.h | 42 + lib/rdmixer.cpp | 58 + lib/rdmixer.h | 33 + lib/rdmonitor_config.cpp | 166 + lib/rdmonitor_config.h | 57 + lib/rdnownext.cpp | 209 + lib/rdnownext.h | 33 + lib/rdoneshot.cpp | 72 + lib/rdoneshot.h | 55 + lib/rdpam.cpp | 110 + lib/rdpam.h | 45 + lib/rdpanel_button.cpp | 567 + lib/rdpanel_button.h | 136 + lib/rdpasswd.cpp | 156 + lib/rdpasswd.h | 56 + lib/rdpaths.h.in | 50 + lib/rdpeaksexport.cpp | 229 + lib/rdpeaksexport.h | 62 + lib/rdplay_deck.cpp | 777 + lib/rdplay_deck.h | 150 + lib/rdplaymeter.cpp | 272 + lib/rdplaymeter.h | 81 + lib/rdpodcast.cpp | 402 + lib/rdpodcast.h | 86 + lib/rdprofile.cpp | 249 + lib/rdprofile.h | 72 + lib/rdprofileline.cpp | 61 + lib/rdprofileline.h | 47 + lib/rdprofilesection.cpp | 68 + lib/rdprofilesection.h | 50 + lib/rdpushbutton.cpp | 284 + lib/rdpushbutton.h | 95 + lib/rdrecording.cpp | 955 ++ lib/rdrecording.h | 161 + lib/rdreplicator.cpp | 273 + lib/rdreplicator.h | 74 + lib/rdreport.cpp | 905 + lib/rdreport.h | 129 + lib/rdringbuffer.cpp | 269 + lib/rdringbuffer.h | 73 + lib/rdripc.cpp | 432 + lib/rdripc.h | 95 + lib/rdschedcodes_dialog.cpp | 209 + lib/rdschedcodes_dialog.h | 66 + lib/rdsegmeter.cpp | 506 + lib/rdsegmeter.h | 101 + lib/rdsettings.cpp | 364 + lib/rdsettings.h | 79 + lib/rdsimpleplayer.cpp | 184 + lib/rdsimpleplayer.h | 78 + lib/rdslider.cpp | 853 + lib/rdslider.h | 101 + lib/rdslotbox.cpp | 572 + lib/rdslotbox.h | 119 + lib/rdslotdialog.cpp | 175 + lib/rdslotdialog.h | 67 + lib/rdslotoptions.cpp | 299 + lib/rdslotoptions.h | 67 + lib/rdsocket.cpp | 86 + lib/rdsocket.h | 61 + lib/rdsound_panel.cpp | 1676 ++ lib/rdsound_panel.h | 200 + lib/rdstation.cpp | 710 + lib/rdstation.h | 148 + lib/rdstatus.cpp | 91 + lib/rdstatus.h | 31 + lib/rdstereometer.cpp | 316 + lib/rdstereometer.h | 88 + lib/rdstringlist.cpp | 69 + lib/rdstringlist.h | 41 + lib/rdsvc.cpp | 1602 ++ lib/rdsvc.h | 114 + lib/rdsystem.cpp | 160 + lib/rdsystem.h | 50 + lib/rdsystemuser.cpp | 104 + lib/rdsystemuser.h | 53 + lib/rdtextfile.cpp | 85 + lib/rdtextfile.h | 31 + lib/rdtextvalidator.cpp | 64 + lib/rdtextvalidator.h | 45 + lib/rdtimeedit.cpp | 506 + lib/rdtimeedit.h | 86 + lib/rdtimeengine.cpp | 179 + lib/rdtimeengine.h | 68 + lib/rdtimeevent.cpp | 80 + lib/rdtimeevent.h | 50 + lib/rdtransportbutton.cpp | 793 + lib/rdtransportbutton.h | 84 + lib/rdtrimaudio.cpp | 252 + lib/rdtrimaudio.h | 62 + lib/rdtty.cpp | 258 + lib/rdtty.h | 64 + lib/rdttydevice.cpp | 561 + lib/rdttydevice.h | 288 + lib/rdttydevice_win32.cpp | 368 + lib/rdttyout.cpp | 66 + lib/rdttyout.h | 34 + lib/rdupload.cpp | 291 + lib/rdupload.h | 67 + lib/rdurl.cpp | 64 + lib/rdurl.h | 41 + lib/rduser.cpp | 506 + lib/rduser.h | 113 + lib/rdversion.cpp | 59 + lib/rdversion.h | 37 + lib/rdwavedata.cpp | 684 + lib/rdwavedata.h | 197 + lib/rdwavedata_dialog.cpp | 320 + lib/rdwavedata_dialog.h | 96 + lib/rdwavefile.cpp | 4434 +++++ lib/rdwavefile.h | 1324 ++ lib/rdwavepainter.cpp | 245 + lib/rdwavepainter.h | 64 + lib/rdweb.cpp | 1155 ++ lib/rdweb.h | 96 + lib/rdwebresult.cpp | 156 + lib/rdwebresult.h | 51 + lib/rdwin32.cpp | 30 + lib/rdwin32.h | 29 + lib/rdxport_interface.h | 47 + lib/schedcartlist.cpp | 179 + lib/schedcartlist.h | 64 + lib/schedruleslist.cpp | 168 + lib/schedruleslist.h | 60 + make_slack.in | 187 + pam_rd/Makefile.am | 45 + pam_rd/pam_rd.cpp | 330 + rdadmin/Makefile.am | 240 + rdadmin/add_aux_field.cpp | 178 + rdadmin/add_aux_field.h | 56 + rdadmin/add_encoder.cpp | 151 + rdadmin/add_encoder.h | 52 + rdadmin/add_feed.cpp | 203 + rdadmin/add_feed.h | 59 + rdadmin/add_group.cpp | 231 + rdadmin/add_group.h | 53 + rdadmin/add_hostvar.cpp | 164 + rdadmin/add_hostvar.h | 65 + rdadmin/add_matrix.cpp | 198 + rdadmin/add_matrix.h | 55 + rdadmin/add_replicator.cpp | 163 + rdadmin/add_replicator.h | 51 + rdadmin/add_report.cpp | 152 + rdadmin/add_report.h | 53 + rdadmin/add_schedcodes.cpp | 163 + rdadmin/add_schedcodes.h | 48 + rdadmin/add_station.cpp | 951 + rdadmin/add_station.h | 59 + rdadmin/add_svc.cpp | 181 + rdadmin/add_svc.h | 58 + rdadmin/add_user.cpp | 173 + rdadmin/add_user.h | 56 + rdadmin/autofill_carts.cpp | 223 + rdadmin/autofill_carts.h | 57 + rdadmin/createdb.cpp | 8048 +++++++++ rdadmin/createdb.h | 41 + rdadmin/edit_audios.cpp | 362 + rdadmin/edit_audios.h | 80 + rdadmin/edit_aux_field.cpp | 144 + rdadmin/edit_aux_field.h | 54 + rdadmin/edit_backup.cpp | 171 + rdadmin/edit_backup.h | 58 + rdadmin/edit_cartslots.cpp | 472 + rdadmin/edit_cartslots.h | 85 + rdadmin/edit_channelgpios.cpp | 268 + rdadmin/edit_channelgpios.h | 77 + rdadmin/edit_decks.cpp | 709 + rdadmin/edit_decks.h | 101 + rdadmin/edit_dropbox.cpp | 568 + rdadmin/edit_dropbox.h | 102 + rdadmin/edit_encoder.cpp | 223 + rdadmin/edit_encoder.h | 59 + rdadmin/edit_endpoint.cpp | 289 + rdadmin/edit_endpoint.h | 71 + rdadmin/edit_feed.cpp | 748 + rdadmin/edit_feed.h | 129 + rdadmin/edit_feed_perms.cpp | 178 + rdadmin/edit_feed_perms.h | 53 + rdadmin/edit_gpi.cpp | 336 + rdadmin/edit_gpi.h | 71 + rdadmin/edit_group.cpp | 492 + rdadmin/edit_group.h | 87 + rdadmin/edit_hostvar.cpp | 165 + rdadmin/edit_hostvar.h | 64 + rdadmin/edit_hotkeys.cpp | 495 + rdadmin/edit_hotkeys.h | 84 + rdadmin/edit_jack.cpp | 348 + rdadmin/edit_jack.h | 79 + rdadmin/edit_jack_client.cpp | 138 + rdadmin/edit_jack_client.h | 65 + rdadmin/edit_livewiregpio.cpp | 150 + rdadmin/edit_livewiregpio.h | 57 + rdadmin/edit_matrix.cpp | 1377 ++ rdadmin/edit_matrix.h | 144 + rdadmin/edit_node.cpp | 288 + rdadmin/edit_node.h | 62 + rdadmin/edit_now_next.cpp | 603 + rdadmin/edit_now_next.h | 73 + rdadmin/edit_nownextplugin.cpp | 154 + rdadmin/edit_nownextplugin.h | 53 + rdadmin/edit_rdairplay.cpp | 1165 ++ rdadmin/edit_rdairplay.h | 145 + rdadmin/edit_rdlibrary.cpp | 624 + rdadmin/edit_rdlibrary.h | 78 + rdadmin/edit_rdlogedit.cpp | 626 + rdadmin/edit_rdlogedit.h | 80 + rdadmin/edit_rdpanel.cpp | 516 + rdadmin/edit_rdpanel.h | 81 + rdadmin/edit_replicator.cpp | 392 + rdadmin/edit_replicator.h | 85 + rdadmin/edit_report.cpp | 656 + rdadmin/edit_report.h | 91 + rdadmin/edit_sas_resource.cpp | 180 + rdadmin/edit_sas_resource.h | 62 + rdadmin/edit_schedcodes.cpp | 156 + rdadmin/edit_schedcodes.h | 54 + rdadmin/edit_settings.cpp | 403 + rdadmin/edit_settings.h | 72 + rdadmin/edit_station.cpp | 992 ++ rdadmin/edit_station.h | 119 + rdadmin/edit_svc.cpp | 785 + rdadmin/edit_svc.h | 95 + rdadmin/edit_svc_perms.cpp | 176 + rdadmin/edit_svc_perms.h | 54 + rdadmin/edit_ttys.cpp | 419 + rdadmin/edit_ttys.h | 78 + rdadmin/edit_user.cpp | 616 + rdadmin/edit_user.h | 112 + rdadmin/edit_user_perms.cpp | 177 + rdadmin/edit_user_perms.h | 53 + rdadmin/edit_vguest_resource.cpp | 220 + rdadmin/edit_vguest_resource.h | 66 + rdadmin/globals.h | 52 + rdadmin/help_audios.cpp | 95 + rdadmin/help_audios.h | 47 + rdadmin/importfields.cpp | 517 + rdadmin/importfields.h | 74 + rdadmin/info_banner1.xpm | 70 + rdadmin/info_banner2.xpm | 71 + rdadmin/info_dialog.cpp | 192 + rdadmin/info_dialog.h | 58 + rdadmin/list_aux_fields.cpp | 243 + rdadmin/list_aux_fields.h | 58 + rdadmin/list_dropboxes.cpp | 312 + rdadmin/list_dropboxes.h | 71 + rdadmin/list_encoders.cpp | 314 + rdadmin/list_encoders.h | 68 + rdadmin/list_endpoints.cpp | 738 + rdadmin/list_endpoints.h | 62 + rdadmin/list_feeds.cpp | 359 + rdadmin/list_feeds.h | 67 + rdadmin/list_gpis.cpp | 358 + rdadmin/list_gpis.h | 68 + rdadmin/list_groups.cpp | 496 + rdadmin/list_groups.h | 73 + rdadmin/list_hostvars.cpp | 265 + rdadmin/list_hostvars.h | 62 + rdadmin/list_livewiregpios.cpp | 255 + rdadmin/list_livewiregpios.h | 61 + rdadmin/list_matrices.cpp | 336 + rdadmin/list_matrices.h | 65 + rdadmin/list_nodes.cpp | 279 + rdadmin/list_nodes.h | 62 + rdadmin/list_replicator_carts.cpp | 260 + rdadmin/list_replicator_carts.h | 73 + rdadmin/list_replicators.cpp | 317 + rdadmin/list_replicators.h | 70 + rdadmin/list_reports.cpp | 234 + rdadmin/list_reports.h | 59 + rdadmin/list_sas_resources.cpp | 337 + rdadmin/list_sas_resources.h | 60 + rdadmin/list_schedcodes.cpp | 265 + rdadmin/list_schedcodes.h | 67 + rdadmin/list_stations.cpp | 333 + rdadmin/list_stations.h | 59 + rdadmin/list_svcs.cpp | 227 + rdadmin/list_svcs.h | 58 + rdadmin/list_users.cpp | 345 + rdadmin/list_users.h | 72 + rdadmin/list_vguest_resources.cpp | 371 + rdadmin/list_vguest_resources.h | 61 + rdadmin/login.cpp | 156 + rdadmin/login.h | 59 + rdadmin/mysql_login.cpp | 143 + rdadmin/mysql_login.h | 57 + rdadmin/opendb.cpp | 441 + rdadmin/opendb.h | 34 + rdadmin/rdadmin.cpp | 663 + rdadmin/rdadmin.h | 73 + rdadmin/rdadmin.pro | 180 + rdadmin/rdadmin_cs.ts | 5886 +++++++ rdadmin/rdadmin_de.ts | 5836 +++++++ rdadmin/rdadmin_es.ts | 5838 +++++++ rdadmin/rdadmin_fr.ts | 5364 ++++++ rdadmin/rdadmin_nb.ts | 5823 +++++++ rdadmin/rdadmin_nn.ts | 5823 +++++++ rdadmin/rdadmin_pt_BR.ts | 5816 +++++++ rdadmin/rename_group.cpp | 283 + rdadmin/rename_group.h | 58 + rdadmin/test_import.cpp | 290 + rdadmin/test_import.h | 64 + rdadmin/view_adapters.cpp | 200 + rdadmin/view_adapters.h | 52 + rdadmin/view_node_info.cpp | 356 + rdadmin/view_node_info.h | 75 + rdadmin/xpm_info_banner1.cpp | 1086 ++ rdadmin/xpm_info_banner2.cpp | 1075 ++ rdairplay/Makefile.am | 108 + rdairplay/button_log.cpp | 657 + rdairplay/button_log.h | 101 + rdairplay/colors.h | 99 + rdairplay/edit_event.cpp | 508 + rdairplay/edit_event.h | 97 + rdairplay/globals.h | 54 + rdairplay/hourselector.cpp | 143 + rdairplay/hourselector.h | 62 + rdairplay/lib_listview.cpp | 55 + rdairplay/lib_listview.h | 44 + rdairplay/list_log.cpp | 1595 ++ rdairplay/list_log.h | 158 + rdairplay/list_logs.cpp | 262 + rdairplay/list_logs.h | 65 + rdairplay/local_macros.cpp | 940 + rdairplay/log_play.cpp | 2775 +++ rdairplay/log_play.h | 257 + rdairplay/log_traffic.cpp | 86 + rdairplay/log_traffic.h | 35 + rdairplay/loglinebox.cpp | 929 + rdairplay/loglinebox.h | 151 + rdairplay/mode_display.cpp | 205 + rdairplay/mode_display.h | 61 + rdairplay/nownext.cpp | 140 + rdairplay/pie_counter.cpp | 346 + rdairplay/pie_counter.h | 101 + rdairplay/post_counter.cpp | 189 + rdairplay/post_counter.h | 69 + rdairplay/rdairplay.cpp | 2658 +++ rdairplay/rdairplay.h | 227 + rdairplay/rdairplay.pro | 70 + rdairplay/rdairplay_cs.ts | 700 + rdairplay/rdairplay_de.ts | 700 + rdairplay/rdairplay_es.ts | 700 + rdairplay/rdairplay_fr.ts | 666 + rdairplay/rdairplay_nb.ts | 710 + rdairplay/rdairplay_nn.ts | 710 + rdairplay/rdairplay_pt_BR.ts | 709 + rdairplay/rlmhost.cpp | 528 + rdairplay/rlmhost.h | 106 + rdairplay/start_button.cpp | 250 + rdairplay/start_button.h | 72 + rdairplay/stop_counter.cpp | 172 + rdairplay/stop_counter.h | 57 + rdairplay/wall_clock.cpp | 183 + rdairplay/wall_clock.h | 73 + rdcartslots/Makefile.am | 69 + rdcartslots/local_macros.cpp | 201 + rdcartslots/rdcartslots.cpp | 291 + rdcartslots/rdcartslots.h | 92 + rdcartslots/rdcartslots.pro | 37 + rdcartslots/rdcartslots_de.ts | 25 + rdcartslots/rdcartslots_es.ts | 25 + rdcartslots/rdcartslots_fr.ts | 25 + rdcartslots/rdcartslots_nb.ts | 25 + rdcartslots/rdcartslots_nn.ts | 25 + rdcartslots/rdcartslots_pt_BR.ts | 25 + rdcastmanager/Makefile.am | 83 + rdcastmanager/edit_cast.cpp | 542 + rdcastmanager/edit_cast.h | 87 + rdcastmanager/globals.h | 46 + rdcastmanager/list_casts.cpp | 542 + rdcastmanager/list_casts.h | 93 + rdcastmanager/pick_report_dates.cpp | 320 + rdcastmanager/pick_report_dates.h | 60 + rdcastmanager/rdcastmanager.cpp | 403 + rdcastmanager/rdcastmanager.h | 73 + rdcastmanager/rdcastmanager.pro | 59 + rdcastmanager/rdcastmanager_cs.ts | 367 + rdcastmanager/rdcastmanager_de.ts | 356 + rdcastmanager/rdcastmanager_es.ts | 307 + rdcastmanager/rdcastmanager_fr.ts | 297 + rdcastmanager/rdcastmanager_nb.ts | 355 + rdcastmanager/rdcastmanager_nn.ts | 355 + rdcastmanager/rdcastmanager_pt_BR.ts | 321 + rdcatch/Makefile.am | 97 + rdcatch/add_recording.cpp | 291 + rdcatch/add_recording.h | 69 + rdcatch/catch_listview.cpp | 112 + rdcatch/catch_listview.h | 56 + rdcatch/catch_monitor.cpp | 75 + rdcatch/catch_monitor.h | 49 + rdcatch/colors.h | 52 + rdcatch/deckmon.cpp | 306 + rdcatch/deckmon.h | 84 + rdcatch/edit_cartevent.cpp | 480 + rdcatch/edit_cartevent.h | 87 + rdcatch/edit_download.cpp | 695 + rdcatch/edit_download.h | 105 + rdcatch/edit_playout.cpp | 538 + rdcatch/edit_playout.h | 88 + rdcatch/edit_recording.cpp | 1208 ++ rdcatch/edit_recording.h | 137 + rdcatch/edit_switchevent.cpp | 653 + rdcatch/edit_switchevent.h | 100 + rdcatch/edit_upload.cpp | 769 + rdcatch/edit_upload.h | 106 + rdcatch/globals.h | 51 + rdcatch/list_reports.cpp | 584 + rdcatch/list_reports.h | 59 + rdcatch/rdcatch.cpp | 2585 +++ rdcatch/rdcatch.h | 184 + rdcatch/rdcatch.pro | 58 + rdcatch/rdcatch_cs.ts | 1323 ++ rdcatch/rdcatch_de.ts | 1323 ++ rdcatch/rdcatch_es.ts | 1267 ++ rdcatch/rdcatch_fr.ts | 1257 ++ rdcatch/rdcatch_nb.ts | 1320 ++ rdcatch/rdcatch_nn.ts | 1320 ++ rdcatch/rdcatch_pt_BR.ts | 1323 ++ rdcatch/vbox.cpp | 64 + rdcatch/vbox.h | 50 + rdcatchd/Makefile.am | 57 + rdcatchd/batch.cpp | 550 + rdcatchd/catch_event.cpp | 724 + rdcatchd/catch_event.h | 199 + rdcatchd/local_macros.cpp | 166 + rdcatchd/rdcatchd.cpp | 2736 +++ rdcatchd/rdcatchd.h | 265 + rdcatchd/rdcatchd_socket.cpp | 52 + rdcatchd/rdcatchd_socket.h | 50 + rdhpi/Makefile.am | 95 + rdhpi/rdhpi.pro | 59 + rdhpi/rdhpi_cs.ts | 67 + rdhpi/rdhpi_de.ts | 67 + rdhpi/rdhpi_es.ts | 67 + rdhpi/rdhpi_fr.ts | 67 + rdhpi/rdhpi_nb.ts | 67 + rdhpi/rdhpi_nn.ts | 67 + rdhpi/rdhpi_pt_BR.ts | 67 + rdhpi/rdhpicardselector.cpp | 176 + rdhpi/rdhpicardselector.h | 64 + rdhpi/rdhpiinformation.cpp | 130 + rdhpi/rdhpiinformation.h | 63 + rdhpi/rdhpiplaystream.cpp | 798 + rdhpi/rdhpiplaystream.h | 139 + rdhpi/rdhpirecordstream.cpp | 703 + rdhpi/rdhpirecordstream.h | 137 + rdhpi/rdhpisoundcard.cpp | 996 ++ rdhpi/rdhpisoundcard.h | 238 + rdhpi/rdhpisoundselector.cpp | 71 + rdhpi/rdhpisoundselector.h | 68 + rdlibrary/Makefile.am | 102 + rdlibrary/audio_cart.cpp | 894 + rdlibrary/audio_cart.h | 102 + rdlibrary/audio_controls.h | 55 + rdlibrary/cart_tip.cpp | 46 + rdlibrary/cart_tip.h | 43 + rdlibrary/cdripper.cpp | 740 + rdlibrary/cdripper.h | 130 + rdlibrary/disk_gauge.cpp | 107 + rdlibrary/disk_gauge.h | 56 + rdlibrary/disk_ripper.cpp | 1144 ++ rdlibrary/disk_ripper.h | 150 + rdlibrary/edit_cart.cpp | 1071 ++ rdlibrary/edit_cart.h | 108 + rdlibrary/edit_macro.cpp | 130 + rdlibrary/edit_macro.h | 59 + rdlibrary/edit_notes.cpp | 109 + rdlibrary/edit_notes.h | 56 + rdlibrary/edit_schedulercodes.cpp | 209 + rdlibrary/edit_schedulercodes.h | 56 + rdlibrary/filter.cpp | 133 + rdlibrary/filter.h | 54 + rdlibrary/globals.h | 52 + rdlibrary/lib_listview.cpp | 69 + rdlibrary/lib_listview.h | 45 + rdlibrary/list_reports.cpp | 744 + rdlibrary/list_reports.h | 67 + rdlibrary/macro_cart.cpp | 383 + rdlibrary/macro_cart.h | 93 + rdlibrary/rdlibrary.cpp | 1512 ++ rdlibrary/rdlibrary.h | 155 + rdlibrary/rdlibrary.pro | 66 + rdlibrary/rdlibrary_cs.ts | 1549 ++ rdlibrary/rdlibrary_de.ts | 1526 ++ rdlibrary/rdlibrary_es.ts | 1531 ++ rdlibrary/rdlibrary_fr.ts | 1368 ++ rdlibrary/rdlibrary_nb.ts | 1522 ++ rdlibrary/rdlibrary_nn.ts | 1522 ++ rdlibrary/rdlibrary_pt_BR.ts | 1524 ++ rdlibrary/record_cut.cpp | 1119 ++ rdlibrary/record_cut.h | 148 + rdlibrary/validate_cut.cpp | 77 + rdlibrary/validate_cut.h | 36 + rdlogedit/Makefile.am | 99 + rdlogedit/add_meta.cpp | 154 + rdlogedit/add_meta.h | 57 + rdlogedit/drop_listview.cpp | 56 + rdlogedit/drop_listview.h | 45 + rdlogedit/edit_chain.cpp | 362 + rdlogedit/edit_chain.h | 78 + rdlogedit/edit_log.cpp | 1748 ++ rdlogedit/edit_log.h | 183 + rdlogedit/edit_logline.cpp | 421 + rdlogedit/edit_logline.h | 88 + rdlogedit/edit_marker.cpp | 318 + rdlogedit/edit_marker.h | 76 + rdlogedit/edit_track.cpp | 306 + rdlogedit/edit_track.h | 78 + rdlogedit/globals.h | 52 + rdlogedit/import_track.cpp | 200 + rdlogedit/import_track.h | 66 + rdlogedit/list_listviewitem.cpp | 118 + rdlogedit/list_listviewitem.h | 57 + rdlogedit/list_logs.cpp | 172 + rdlogedit/list_logs.h | 54 + rdlogedit/list_reports.cpp | 338 + rdlogedit/list_reports.h | 66 + rdlogedit/log_listview.cpp | 112 + rdlogedit/log_listview.h | 64 + rdlogedit/rdlogedit.cpp | 913 + rdlogedit/rdlogedit.h | 106 + rdlogedit/rdlogedit.pro | 80 + rdlogedit/rdlogedit_cs.ts | 1103 ++ rdlogedit/rdlogedit_de.ts | 1102 ++ rdlogedit/rdlogedit_es.ts | 1109 ++ rdlogedit/rdlogedit_fr.ts | 1080 ++ rdlogedit/rdlogedit_nb.ts | 1124 ++ rdlogedit/rdlogedit_nn.ts | 1124 ++ rdlogedit/rdlogedit_pt_BR.ts | 1110 ++ rdlogedit/voice_tracker.cpp | 4146 +++++ rdlogedit/voice_tracker.h | 293 + rdlogin/Makefile.am | 72 + rdlogin/rdlogin.cpp | 361 + rdlogin/rdlogin.h | 80 + rdlogin/rdlogin.pro | 43 + rdlogin/rdlogin_cs.ts | 55 + rdlogin/rdlogin_de.ts | 54 + rdlogin/rdlogin_es.ts | 55 + rdlogin/rdlogin_fr.ts | 54 + rdlogin/rdlogin_nb.ts | 55 + rdlogin/rdlogin_nn.ts | 55 + rdlogin/rdlogin_pt_BR.ts | 56 + rdlogmanager/Makefile.am | 124 + rdlogmanager/add_clock.cpp | 172 + rdlogmanager/add_clock.h | 60 + rdlogmanager/add_event.cpp | 174 + rdlogmanager/add_event.h | 60 + rdlogmanager/clock_listview.cpp | 82 + rdlogmanager/clock_listview.h | 58 + rdlogmanager/commandline_ops.cpp | 261 + rdlogmanager/edit_clock.cpp | 767 + rdlogmanager/edit_clock.h | 104 + rdlogmanager/edit_event.cpp | 1673 ++ rdlogmanager/edit_event.h | 175 + rdlogmanager/edit_eventline.cpp | 239 + rdlogmanager/edit_eventline.h | 60 + rdlogmanager/edit_grid.cpp | 344 + rdlogmanager/edit_grid.h | 70 + rdlogmanager/edit_note.cpp | 115 + rdlogmanager/edit_note.h | 53 + rdlogmanager/edit_perms.cpp | 207 + rdlogmanager/edit_perms.h | 61 + rdlogmanager/edit_schedcoderules.cpp | 199 + rdlogmanager/edit_schedcoderules.h | 77 + rdlogmanager/edit_schedrules.cpp | 299 + rdlogmanager/edit_schedrules.h | 72 + rdlogmanager/edit_track.cpp | 115 + rdlogmanager/edit_track.h | 53 + rdlogmanager/generate_log.cpp | 587 + rdlogmanager/generate_log.h | 79 + rdlogmanager/globals.h | 44 + rdlogmanager/import_listview.cpp | 488 + rdlogmanager/import_listview.h | 86 + rdlogmanager/lib_listview.cpp | 57 + rdlogmanager/lib_listview.h | 45 + rdlogmanager/list_clocks.cpp | 698 + rdlogmanager/list_clocks.h | 89 + rdlogmanager/list_events.cpp | 662 + rdlogmanager/list_events.h | 87 + rdlogmanager/list_grids.cpp | 171 + rdlogmanager/list_grids.h | 56 + rdlogmanager/list_svcs.cpp | 223 + rdlogmanager/list_svcs.h | 60 + rdlogmanager/pick_report_dates.cpp | 244 + rdlogmanager/pick_report_dates.h | 56 + rdlogmanager/rdlogmanager.cpp | 502 + rdlogmanager/rdlogmanager.h | 86 + rdlogmanager/rdlogmanager.pro | 101 + rdlogmanager/rdlogmanager_cs.ts | 1375 ++ rdlogmanager/rdlogmanager_de.ts | 1374 ++ rdlogmanager/rdlogmanager_es.ts | 1378 ++ rdlogmanager/rdlogmanager_fr.ts | 1353 ++ rdlogmanager/rdlogmanager_nb.ts | 1405 ++ rdlogmanager/rdlogmanager_nn.ts | 1405 ++ rdlogmanager/rdlogmanager_pt_BR.ts | 1378 ++ rdlogmanager/rename_item.cpp | 158 + rdlogmanager/rename_item.h | 51 + rdlogmanager/svc_rec.cpp | 422 + rdlogmanager/svc_rec.h | 90 + rdlogmanager/svc_rec_dialog.cpp | 141 + rdlogmanager/svc_rec_dialog.h | 63 + rdmonitor/Makefile.am | 75 + rdmonitor/positiondialog.cpp | 176 + rdmonitor/positiondialog.h | 68 + rdmonitor/rdmonitor.cpp | 410 + rdmonitor/rdmonitor.h | 83 + rdmonitor/rdmonitor.pro | 40 + rdmonitor/rdmonitor_cs.ts | 21 + rdmonitor/rdmonitor_de.ts | 21 + rdmonitor/rdmonitor_es.ts | 21 + rdmonitor/rdmonitor_fr.ts | 21 + rdmonitor/rdmonitor_nb.ts | 21 + rdmonitor/rdmonitor_nn.ts | 21 + rdmonitor/rdmonitor_pt_BR.ts | 21 + rdmonitor/status_tip.cpp | 66 + rdmonitor/status_tip.h | 42 + rdpanel/Makefile.am | 71 + rdpanel/globals.h | 45 + rdpanel/rdpanel.cpp | 468 + rdpanel/rdpanel.h | 86 + rdpanel/rdpanel.pro | 36 + rdpanel/rdpanel_cs.ts | 21 + rdpanel/rdpanel_de.ts | 21 + rdpanel/rdpanel_es.ts | 21 + rdpanel/rdpanel_fr.ts | 21 + rdpanel/rdpanel_pt_BR.ts | 21 + rdrepld-suse.in | 147 + rdrepld/Makefile.am | 45 + rdrepld/citadelxds.cpp | 464 + rdrepld/citadelxds.h | 46 + rdrepld/globals.h | 32 + rdrepld/rdrepld.cpp | 301 + rdrepld/rdrepld.h | 65 + rdrepld/replconfig.cpp | 216 + rdrepld/replconfig.h | 83 + rdrepld/replfactory.cpp | 40 + rdrepld/replfactory.h | 43 + rdselect/Makefile.am | 73 + rdselect/rdselect.cpp | 384 + rdselect/rdselect.h | 77 + rdselect/rdselect.pro | 38 + rdselect/rdselect_cs.ts | 45 + rdselect/rdselect_de.ts | 45 + rdselect/rdselect_es.ts | 45 + rdselect/rdselect_fr.ts | 45 + rdselect/rdselect_nb.ts | 45 + rdselect/rdselect_nn.ts | 45 + rdselect/rdselect_pt_BR.ts | 45 + ripcd/Makefile.am | 120 + ripcd/acu1p.cpp | 354 + ripcd/acu1p.h | 82 + ripcd/am16.cpp | 262 + ripcd/am16.h | 99 + ripcd/bt10x1.cpp | 119 + ripcd/bt10x1.h | 56 + ripcd/bt16x1.cpp | 119 + ripcd/bt16x1.h | 56 + ripcd/bt16x2.cpp | 365 + ripcd/bt16x2.h | 71 + ripcd/bt8x2.cpp | 150 + ripcd/bt8x2.h | 56 + ripcd/btacs82.cpp | 436 + ripcd/btacs82.h | 72 + ripcd/btsentinel4web.cpp | 176 + ripcd/btsentinel4web.h | 75 + ripcd/btsrc16.cpp | 346 + ripcd/btsrc16.h | 70 + ripcd/btsrc8iii.cpp | 330 + ripcd/btsrc8iii.h | 69 + ripcd/btss124.cpp | 161 + ripcd/btss124.h | 56 + ripcd/btss164.cpp | 432 + ripcd/btss164.h | 71 + ripcd/btss42.cpp | 418 + ripcd/btss42.h | 71 + ripcd/btss44.cpp | 418 + ripcd/btss44.h | 71 + ripcd/btss82.cpp | 403 + ripcd/btss82.h | 71 + ripcd/globals.h | 37 + ripcd/harlond.cpp | 446 + ripcd/harlond.h | 90 + ripcd/livewire_lwrpaudio.cpp | 266 + ripcd/livewire_lwrpaudio.h | 66 + ripcd/livewire_lwrpgpio.cpp | 227 + ripcd/livewire_lwrpgpio.h | 72 + ripcd/livewire_mcastgpio.cpp | 414 + ripcd/livewire_mcastgpio.h | 92 + ripcd/loaddrivers.cpp | 213 + ripcd/local_audio.cpp | 155 + ripcd/local_audio.h | 53 + ripcd/local_gpio.cpp | 193 + ripcd/local_gpio.h | 63 + ripcd/local_macros.cpp | 936 + ripcd/maint_routines.cpp | 56 + ripcd/quartz1.cpp | 269 + ripcd/quartz1.h | 80 + ripcd/ripcd.cpp | 888 + ripcd/ripcd.h | 138 + ripcd/ripcd.pro | 55 + ripcd/ripcd_connection.cpp | 40 + ripcd/ripcd_connection.h | 46 + ripcd/ripcd_socket.cpp | 54 + ripcd/ripcd_socket.h | 50 + ripcd/sas32000.cpp | 168 + ripcd/sas32000.h | 67 + ripcd/sas64000.cpp | 118 + ripcd/sas64000.h | 54 + ripcd/sas64000gpi.cpp | 170 + ripcd/sas64000gpi.h | 62 + ripcd/sasusi.cpp | 641 + ripcd/sasusi.h | 87 + ripcd/starguide3.cpp | 159 + ripcd/starguide3.h | 59 + ripcd/starguide_feed.cpp | 72 + ripcd/starguide_feed.h | 49 + ripcd/switcher.cpp | 112 + ripcd/switcher.h | 68 + ripcd/unity4000.cpp | 165 + ripcd/unity4000.h | 59 + ripcd/unity_feed.cpp | 59 + ripcd/unity_feed.h | 46 + ripcd/vguest.cpp | 816 + ripcd/vguest.h | 120 + rivendell-gentoo | 69 + rivendell-suse.in | 252 + rivendell.ism | Bin 0 -> 499284 bytes rivendell.pro | 30 + rivendell.spec.in | 1084 ++ rivendell.sys | 67 + rlm/Makefile-example | 42 + rlm/Makefile.am | 90 + rlm/rlm.h | 372 + rlm/rlm_ando.c | 217 + rlm/rlm_facebook.c | 316 + rlm/rlm_filewrite.c | 228 + rlm/rlm_icecast2.c | 295 + rlm/rlm_inno713.c | 253 + rlm/rlm_liqcomp.c | 189 + rlm/rlm_padpoint.c | 175 + rlm/rlm_serial.c | 219 + rlm/rlm_shoutcast1.c | 280 + rlm/rlm_spinitron_plus.c | 386 + rlm/rlm_spottrap.c | 205 + rlm/rlm_test.c | 153 + rlm/rlm_twitter.c | 264 + rlm/rlm_udp.c | 205 + rlm/rlm_xds.c | 301 + rlm/rlm_xmpad.c | 304 + scripts/Makefile.am | 58 + scripts/crc-unity4k.sh | 377 + scripts/kill_rd | 59 + scripts/rd_audio_sync | 82 + scripts/rd_backup | 72 + scripts/rd_backup_system.sh | 105 + scripts/rd_config | 80 + scripts/rd_create_db | 771 + scripts/rd_memmon.sh | 37 + scripts/rd_mysql_enable_host.sh | 52 + scripts/rd_restore_system.sh | 100 + scripts/rdmemcheck.sh | 80 + scripts/sage_endec_rwt.sh | 47 + scripts/start-rdmonitor.sh | 26 + scripts/start_rd | 36 + scripts/start_traverso.sh | 40 + slack-desc.in | 19 + slack_doinst.sh | 29 + tests/Makefile.am | 94 + tests/audio_convert_test.cpp | 202 + tests/audio_convert_test.h | 58 + tests/audio_export_test.cpp | 224 + tests/audio_export_test.h | 60 + tests/audio_import_test.cpp | 164 + tests/audio_import_test.h | 59 + tests/datedecode_test.cpp | 91 + tests/datedecode_test.h | 37 + tests/reserve_carts_test.cpp | 133 + tests/reserve_carts_test.h | 37 + tests/rivendell_standard.txt | 5 + tests/sas_switch_torture.cpp | 189 + tests/sas_switch_torture.h | 63 + tests/sas_torture.cpp | 200 + tests/sas_torture.h | 64 + tests/stringcode_test.cpp | 113 + tests/stringcode_test.h | 37 + tests/test_pam.cpp | 120 + tests/test_pam.h | 44 + tests/timer_test.cpp | 85 + tests/timer_test.h | 49 + tests/upload_test.cpp | 106 + tests/upload_test.h | 55 + tests/visualtraffic.txt | 6 + utils/Makefile.am | 75 + utils/rdalsaconfig/Makefile.am | 55 + utils/rdalsaconfig/alsaitem.cpp | 68 + utils/rdalsaconfig/alsaitem.h | 46 + utils/rdalsaconfig/rdalsa.cpp | 298 + utils/rdalsaconfig/rdalsa.h | 71 + utils/rdalsaconfig/rdalsaconfig.cpp | 388 + utils/rdalsaconfig/rdalsaconfig.h | 84 + utils/rdalsaconfig/rdalsaconfig.pro | 0 utils/rdcheckcuts/Makefile.am | 54 + utils/rdcheckcuts/rdcheckcuts.cpp | 188 + utils/rdcheckcuts/rdcheckcuts.h | 49 + utils/rdcheckcuts/rdcheckcuts.pro | 0 utils/rdchunk/Makefile.am | 72 + utils/rdchunk/rdchunk.cpp | 745 + utils/rdchunk/rdchunk.h | 84 + utils/rdchunk/rdchunk.pro | 28 + utils/rdchunk/rdchunk_de.ts | 373 + utils/rdchunk/rdchunk_es.ts | 373 + utils/rdchunk/rdchunk_fr.ts | 373 + utils/rdchunk/rdchunk_pt_BR.ts | 373 + utils/rdcollect/Makefile.am | 55 + utils/rdcollect/rdcollect.cpp | 214 + utils/rdcollect/rdcollect.h | 57 + utils/rdcollect/rdcollect.pro | 44 + utils/rddbcheck/Makefile.am | 51 + utils/rddbcheck/rddbcheck.cpp | 825 + utils/rddbcheck/rddbcheck.h | 75 + utils/rddelete/Makefile.am | 51 + utils/rddelete/rddelete.cpp | 385 + utils/rddelete/rddelete.h | 82 + utils/rddgimport/Makefile.am | 72 + utils/rddgimport/event.cpp | 88 + utils/rddgimport/event.h | 53 + utils/rddgimport/rddgimport.cpp | 670 + utils/rddgimport/rddgimport.h | 114 + utils/rddgimport/rddgimport.pro | 33 + utils/rddgimport/rddgimport_de.ts | 114 + utils/rddgimport/rddgimport_es.ts | 114 + utils/rddgimport/rddgimport_fr.ts | 114 + utils/rddgimport/rddgimport_nb.ts | 114 + utils/rddgimport/rddgimport_nn.ts | 114 + utils/rddgimport/rddgimport_pt_BR.ts | 114 + utils/rddiscimport/Makefile.am | 73 + utils/rddiscimport/metalibrary.cpp | 226 + utils/rddiscimport/metalibrary.h | 52 + utils/rddiscimport/metarecord.cpp | 337 + utils/rddiscimport/metarecord.h | 105 + utils/rddiscimport/rddiscimport.cpp | 761 + utils/rddiscimport/rddiscimport.h | 131 + utils/rddiscimport/rddiscimport.pro | 35 + utils/rddiscimport/rddiscimport_de.ts | 166 + utils/rddiscimport/rddiscimport_es.ts | 166 + utils/rddiscimport/rddiscimport_fr.ts | 166 + utils/rddiscimport/rddiscimport_nb.ts | 166 + utils/rddiscimport/rddiscimport_nn.ts | 166 + utils/rddiscimport/rddiscimport_pt_BR.ts | 166 + utils/rdgen/Makefile.am | 50 + utils/rdgen/rdgen.c | 317 + utils/rdgen/wavlib.c | 1187 ++ utils/rdgen/wavlib.h | 172 + utils/rdgpimon/Makefile.am | 74 + utils/rdgpimon/gpi_label.cpp | 139 + utils/rdgpimon/gpi_label.h | 55 + utils/rdgpimon/rdgpimon.cpp | 567 + utils/rdgpimon/rdgpimon.h | 96 + utils/rdgpimon/rdgpimon.pro | 31 + utils/rdgpimon/rdgpimon_cs.ts | 54 + utils/rdgpimon/rdgpimon_de.ts | 58 + utils/rdgpimon/rdgpimon_es.ts | 58 + utils/rdgpimon/rdgpimon_fr.ts | 54 + utils/rdgpimon/rdgpimon_nb.ts | 58 + utils/rdgpimon/rdgpimon_nn.ts | 58 + utils/rdgpimon/rdgpimon_pt_BR.ts | 54 + utils/rdhpiinfo/Makefile.am | 52 + utils/rdhpiinfo/change_mode.cpp | 194 + utils/rdhpiinfo/change_mode.h | 61 + utils/rdhpiinfo/rdhpiinfo.cpp | 420 + utils/rdhpiinfo/rdhpiinfo.h | 79 + utils/rdhpiinfo/rdhpiinfo.pro | 0 utils/rdimport/Makefile.am | 51 + utils/rdimport/rdimport.cpp | 1568 ++ utils/rdimport/rdimport.h | 133 + utils/rdmaint/Makefile.am | 49 + utils/rdmaint/rdmaint.cpp | 277 + utils/rdmaint/rdmaint.h | 59 + utils/rdmarkerset/Makefile.am | 53 + utils/rdmarkerset/rdmarkerset.cpp | 349 + utils/rdmarkerset/rdmarkerset.h | 69 + utils/rdpopup/Makefile.am | 49 + utils/rdpopup/rdpopup.cpp | 124 + utils/rdpopup/rdpopup.h | 33 + utils/rdpurgecasts/Makefile.am | 49 + utils/rdpurgecasts/rdpurgecasts.cpp | 178 + utils/rdpurgecasts/rdpurgecasts.h | 49 + utils/rdsoftkeys/Makefile.am | 54 + utils/rdsoftkeys/rdsoftkeys.cpp | 326 + utils/rdsoftkeys/rdsoftkeys.h | 65 + utils/rdsoftkeys/rdsoftkeys.pro | 44 + utils/rmlsend/Makefile.am | 73 + utils/rmlsend/rmlsend.cpp | 562 + utils/rmlsend/rmlsend.h | 98 + utils/rmlsend/rmlsend.pro | 52 + utils/rmlsend/rmlsend_cs.ts | 53 + utils/rmlsend/rmlsend_de.ts | 57 + utils/rmlsend/rmlsend_es.ts | 57 + utils/rmlsend/rmlsend_fr.ts | 53 + utils/rmlsend/rmlsend_nb.ts | 57 + utils/rmlsend/rmlsend_nn.ts | 57 + utils/rmlsend/rmlsend_pt_BR.ts | 57 + utils/sas_shim/Makefile.am | 53 + utils/sas_shim/rc.sas_shim | 159 + utils/sas_shim/sas_shim.cpp | 232 + utils/sas_shim/sas_shim.h | 59 + utils/utils.pro | 26 + web/Makefile.am | 51 + web/rdcastmanager/Makefile.am | 53 + web/rdcastmanager/rdcastmanager.cpp | 1928 +++ web/rdcastmanager/rdcastmanager.h | 94 + web/rdcastmanager/rdcastmanager.js | 39 + web/rdcastmanager/rdcastmanager.pro | 0 web/rdfeed/Makefile.am | 53 + web/rdfeed/rdfeed.pro | 0 web/rdfeed/rdfeed_script.cpp | 397 + web/rdfeed/rdfeed_script.h | 51 + web/rdxport/Makefile.am | 62 + web/rdxport/audioinfo.cpp | 114 + web/rdxport/carts.cpp | 771 + web/rdxport/copyaudio.cpp | 82 + web/rdxport/deleteaudio.cpp | 66 + web/rdxport/export.cpp | 202 + web/rdxport/exportpeaks.cpp | 79 + web/rdxport/groups.cpp | 110 + web/rdxport/import.cpp | 170 + web/rdxport/logs.cpp | 123 + web/rdxport/rdxport.cpp | 287 + web/rdxport/rdxport.h | 72 + web/rdxport/rdxport.pro | 0 web/rdxport/services.cpp | 77 + web/rdxport/trimaudio.cpp | 98 + web/tests/Makefile.am | 96 + web/tests/addcart.html | 41 + web/tests/addcut.html | 29 + web/tests/audioinfo.html | 33 + web/tests/copyaudio.html | 41 + web/tests/delete_audio.html | 33 + web/tests/editcart.html | 43 + web/tests/export.html | 90 + web/tests/exportpeaks.html | 33 + web/tests/import.html | 53 + web/tests/listcart.html | 33 + web/tests/listcarts.html | 37 + web/tests/listcut.html | 33 + web/tests/listcuts.html | 29 + web/tests/listgroup.html | 29 + web/tests/listgroups.html | 25 + web/tests/listlog.html | 29 + web/tests/listlogs.html | 33 + web/tests/listservices.html | 29 + web/tests/removecart.html | 29 + web/tests/removecut.html | 33 + web/tests/trimaudio.html | 37 + web/web.pro | 0 xdg/Makefile.am | 87 + xdg/rdalsaconfig-root-consolehelper | 2 + xdg/rdalsaconfig-root-pam | 4 + xdg/rdhpiinfo-root-consolehelper | 2 + xdg/rdhpiinfo-root-pam | 4 + xdg/rivendell-configuration.directory | 6 + xdg/rivendell-logtools.directory | 6 + xdg/rivendell-rdadmin.desktop | 10 + xdg/rivendell-rdairplay.desktop | 9 + xdg/rivendell-rdalsaconfig-root.desktop | 10 + xdg/rivendell-rdalsaconfig.desktop | 12 + xdg/rivendell-rdcartslots.desktop | 11 + xdg/rivendell-rdcastmanager.desktop | 11 + xdg/rivendell-rdcatch.desktop | 11 + xdg/rivendell-rddgimport.desktop | 11 + xdg/rivendell-rddiscimport.desktop | 11 + xdg/rivendell-rdgpimon.desktop | 11 + xdg/rivendell-rdhpiinfo-root.desktop | 10 + xdg/rivendell-rdhpiinfo.desktop | 12 + xdg/rivendell-rdlibrary.desktop | 11 + xdg/rivendell-rdlogedit.desktop | 11 + xdg/rivendell-rdlogin.desktop | 11 + xdg/rivendell-rdlogmanager.desktop | 11 + xdg/rivendell-rdmonitor.desktop | 11 + xdg/rivendell-rdpanel.desktop | 11 + xdg/rivendell-rdsoftkeys.desktop | 11 + xdg/rivendell-rivendell.directory | 6 + xdg/rivendell-rivendell.menu | 49 + xdg/rivendell-rmlsend.desktop | 10 + xdg/rivendell-utilities.directory | 6 + 1508 files changed, 405304 insertions(+) create mode 100644 AUTHORS create mode 100644 CODINGSTYLE create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 PACKAGE_VERSION create mode 100644 README create mode 100644 UPGRADING create mode 100644 acinclude.m4 create mode 100755 autogen.sh create mode 100644 build_win32.bat create mode 100644 cae/Makefile.am create mode 100644 cae/cae.cpp create mode 100644 cae/cae.h create mode 100644 cae/cae_alsa.cpp create mode 100644 cae/cae_hpi.cpp create mode 100644 cae/cae_jack.cpp create mode 100644 cae/cae_socket.cpp create mode 100644 cae/cae_socket.h create mode 100644 conf/Makefile.am create mode 100644 conf/my.cnf-master create mode 100644 conf/my.cnf-standby create mode 100644 conf/rd-bin.conf.in create mode 100755 conf/rd-sample.ini create mode 100644 conf/rd.conf-sample create mode 100644 conf/rd.conf-slax create mode 100644 conf/rlm_ando.conf create mode 100644 conf/rlm_facebook.conf create mode 100644 conf/rlm_filewrite.conf create mode 100644 conf/rlm_icecast2.conf create mode 100644 conf/rlm_inno713.conf create mode 100644 conf/rlm_liqcomp.conf create mode 100644 conf/rlm_padpoint.conf create mode 100644 conf/rlm_serial.conf create mode 100644 conf/rlm_shoutcast1.conf create mode 100644 conf/rlm_spinitron_plus.conf create mode 100644 conf/rlm_spottrap.conf create mode 100644 conf/rlm_twitter.conf create mode 100644 conf/rlm_udp.conf create mode 100644 conf/rlm_xds.conf create mode 100644 conf/rlm_xmpad.conf create mode 100644 configure.in create mode 100644 debian/Makefile.am create mode 100644 debian/README.Debian create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/librivendell.install create mode 100644 debian/menu create mode 100644 debian/patches/00list create mode 100644 debian/patches/00template create mode 100644 debian/patches/07_extra_paren.dpatch create mode 100644 debian/patches/Makefile.am create mode 100644 debian/rdadmin.desktop create mode 100644 debian/rdadmin.xpm create mode 100644 debian/rdairplay.desktop create mode 100644 debian/rdairplay.xpm create mode 100644 debian/rdcatch.desktop create mode 100644 debian/rdcatch.xpm create mode 100644 debian/rdlibrary.desktop create mode 100644 debian/rdlibrary.xpm create mode 100644 debian/rdlogedit.desktop create mode 100644 debian/rdlogedit.xpm create mode 100644 debian/rdlogin.desktop create mode 100644 debian/rdlogin.xpm create mode 100644 debian/rdlogmanager.desktop create mode 100644 debian/rdlogmanager.xpm create mode 100644 debian/rivendell.conffiles create mode 100644 debian/rivendell.config create mode 100644 debian/rivendell.docs.in create mode 100644 debian/rivendell.examples create mode 100755 debian/rivendell.init create mode 100644 debian/rivendell.install create mode 100644 debian/rivendell.logrotate create mode 100644 debian/rivendell.postinst create mode 100644 debian/rivendell.postrm create mode 100644 debian/rivendell.templates create mode 100755 debian/rules create mode 100644 docs/ALSA.txt create mode 100644 docs/ENCODERS.txt create mode 100644 docs/GPIO.txt create mode 100644 docs/JACK.txt create mode 100644 docs/MESSAGE_BOX.txt create mode 100644 docs/Makefile.am create mode 100644 docs/NEXGEN_FILTER.txt create mode 100644 docs/NOW+NEXT.txt create mode 100644 docs/PODCASTING.txt create mode 100644 docs/RDMONITOR.txt create mode 100644 docs/RIVENDELL_FILTER.txt create mode 100644 docs/SAGE_ENDEC.txt create mode 100644 docs/SWITCHERS.txt create mode 100644 docs/WIN32.txt create mode 100644 docs/WINGS_FILTER.txt create mode 100644 docs/ando_interface.odt create mode 100644 docs/asound.conf-sample create mode 100644 docs/cae.sxw create mode 100644 docs/catchd.txt create mode 100644 docs/colors create mode 100644 docs/copy_split_format.odt create mode 100644 docs/datetime_wildcards.txt create mode 100644 docs/examples/0320090805.cpi create mode 100644 docs/examples/0320090805.elr create mode 100644 docs/examples/0320090805.tfc create mode 100644 docs/examples/0320090805.vti create mode 100644 docs/examples/080509T3.LOG create mode 100644 docs/examples/Makefile.am create mode 100644 docs/examples/cart_report.asc create mode 100644 docs/implemented_macros.txt create mode 100644 docs/pam_rd.txt create mode 100644 docs/reports.txt create mode 100644 docs/ripc.txt create mode 100644 docs/rml.sxw create mode 100644 docs/scheduler_formats.ods create mode 100644 docs/tables/Makefile.am create mode 100644 docs/tables/audio_perms.txt create mode 100644 docs/tables/audio_ports.txt create mode 100644 docs/tables/cart.txt create mode 100644 docs/tables/cartslots.txt create mode 100644 docs/tables/clipboard.txt create mode 100644 docs/tables/clock_perms.txt create mode 100644 docs/tables/copy_splits.txt create mode 100644 docs/tables/cuts.txt create mode 100644 docs/tables/decks.txt create mode 100644 docs/tables/dropbox_paths.txt create mode 100644 docs/tables/dropbox_sched_codes.txt create mode 100644 docs/tables/dropboxes.txt create mode 100644 docs/tables/encoder_bitrates.txt create mode 100644 docs/tables/encoder_channels.txt create mode 100644 docs/tables/encoder_samplerates.txt create mode 100644 docs/tables/encoders.txt create mode 100644 docs/tables/extended_panel_names.txt create mode 100644 docs/tables/feed_perms.txt create mode 100644 docs/tables/gpis.txt create mode 100644 docs/tables/gpos.txt create mode 100644 docs/tables/groups.txt create mode 100644 docs/tables/isci_xreference.txt create mode 100644 docs/tables/jack_clients.txt create mode 100644 docs/tables/livewire_gpio_slots.txt create mode 100644 docs/tables/log_format.txt create mode 100644 docs/tables/log_modes.txt create mode 100644 docs/tables/logs.txt create mode 100644 docs/tables/nownext_plugins.txt create mode 100644 docs/tables/panel_names.txt create mode 100644 docs/tables/panels.txt create mode 100644 docs/tables/rd_airplay.txt create mode 100644 docs/tables/rd_catch.txt create mode 100644 docs/tables/rd_library.txt create mode 100644 docs/tables/rd_logedit.txt create mode 100644 docs/tables/rdairplay_channels.txt create mode 100644 docs/tables/rdpanel_channels.txt create mode 100644 docs/tables/recordings.txt create mode 100644 docs/tables/repl_cart_state.txt create mode 100644 docs/tables/repl_cut_state.txt create mode 100644 docs/tables/replicator_map.txt create mode 100644 docs/tables/replicators.txt create mode 100644 docs/tables/services.txt create mode 100644 docs/tables/sources.txt create mode 100644 docs/tables/stations.txt create mode 100644 docs/tables/svc_rec_format.txt create mode 100644 docs/tables/triggers.txt create mode 100644 docs/tables/ttys.txt create mode 100644 docs/tables/user_perms.txt create mode 100644 docs/tables/users.txt create mode 100644 docs/tables/version.txt create mode 100644 docs/tables/vguest_resources.txt create mode 100644 docs/tables/web_connections.txt create mode 100644 docs/web_api.odt create mode 100755 get_distro.sh create mode 100755 get_target.sh create mode 100644 helpers/Makefile.am create mode 100644 helpers/cwrap.cpp create mode 100644 helpers/cwrap.h create mode 100644 helpers/jsmin.c create mode 100755 helpers/rdpack.sh create mode 100755 helpers/rdtrans.sh create mode 100644 helpers/rdtransgui.sh create mode 100644 helpers/setenvvar.sh create mode 100644 helpers/win32_frag1.txt create mode 100644 helpers/win32_frag2.txt create mode 100644 icons/Makefile.am create mode 100644 icons/admin.xpm create mode 100644 icons/blueball.xpm create mode 100644 icons/chain.xpm create mode 100644 icons/checkmark.xpm create mode 100644 icons/download.xpm create mode 100644 icons/ex.xpm create mode 100644 icons/fillstart.xpm create mode 100644 icons/fillstop.xpm create mode 100644 icons/greenball.png create mode 100644 icons/greenball.xpm create mode 100644 icons/greencheckmark.png create mode 100644 icons/greencheckmark.xpm create mode 100644 icons/macro.xpm create mode 100644 icons/marker.xpm create mode 100644 icons/mic16.xpm create mode 100644 icons/music.xpm create mode 100644 icons/note.xpm create mode 100644 icons/note2.xpm create mode 100644 icons/notemarker.xpm create mode 100644 icons/play.xpm create mode 100644 icons/post.xpm create mode 100644 icons/post2.xpm create mode 100644 icons/post3.xpm create mode 100644 icons/progressbar.gif create mode 100644 icons/progressbar.xcf create mode 100644 icons/record.xpm create mode 100644 icons/record2.xpm create mode 100644 icons/record3.xpm create mode 100644 icons/redball.png create mode 100644 icons/redball.xpm create mode 100644 icons/redcheckmark.xpm create mode 100644 icons/redx.png create mode 100644 icons/redx.xpm create mode 100644 icons/rivendell-128x128.png create mode 100644 icons/rivendell-128x128.xpm create mode 100644 icons/rivendell-16x16.png create mode 100644 icons/rivendell-16x16.xpm create mode 100644 icons/rivendell-22x22.png create mode 100644 icons/rivendell-22x22.xpm create mode 100644 icons/rivendell-32x32.png create mode 100644 icons/rivendell-32x32.xpm create mode 100644 icons/rivendell-48x48.png create mode 100644 icons/rivendell-48x48.xpm create mode 100644 icons/rivendell-64x64.png create mode 100644 icons/rivendell-64x64.xpm create mode 100644 icons/rivendell.ico create mode 100644 icons/rivendell.res create mode 100644 icons/rml.xpm create mode 100644 icons/rml2.xpm create mode 100644 icons/rml3.xpm create mode 100755 icons/rml5.xpm create mode 100644 icons/split.xpm create mode 100644 icons/switch.xpm create mode 100644 icons/switch2.xpm create mode 100644 icons/switch3.xpm create mode 100644 icons/track.xpm create mode 100644 icons/track_cart.xpm create mode 100644 icons/traffic.xpm create mode 100644 icons/trashcan-16x16.xpm create mode 100644 icons/trashcan-32x32.xpm create mode 100644 icons/upload.xpm create mode 100644 icons/user.xpm create mode 100644 icons/whiteball.png create mode 100644 icons/whiteball.xpm create mode 100644 importers/Makefile.am create mode 100755 importers/export_slax create mode 100644 importers/nexgen_filter.cpp create mode 100644 importers/nexgen_filter.h create mode 100644 importers/panel_copy.cpp create mode 100644 importers/panel_copy.h create mode 100644 importers/rdcatch_copy.cpp create mode 100644 importers/rdcatch_copy.h create mode 100644 importers/rivendell_filter.cpp create mode 100644 importers/rivendell_filter.h create mode 100644 importers/sas_filter.cpp create mode 100644 importers/sas_filter.h create mode 100644 importers/wings_filter.cpp create mode 100644 importers/wings_filter.h create mode 100755 install-init.sh create mode 100644 ios/Makefile.am create mode 100644 ios/rmlsend/Classes/Makefile.am create mode 100644 ios/rmlsend/Classes/RMLSendAppDelegate.h create mode 100644 ios/rmlsend/Classes/RMLSendAppDelegate.m create mode 100644 ios/rmlsend/Classes/RMLSendViewController.h create mode 100644 ios/rmlsend/Classes/RMLSendViewController.m create mode 100644 ios/rmlsend/Classes/TextFieldDelegate.h create mode 100644 ios/rmlsend/Classes/TextFieldDelegate.m create mode 100644 ios/rmlsend/Icon.png create mode 100644 ios/rmlsend/MainWindow.xib create mode 100644 ios/rmlsend/Makefile.am create mode 100644 ios/rmlsend/RMLSend-Info.plist create mode 100644 ios/rmlsend/RMLSend.xcodeproj/Makefile.am create mode 100755 ios/rmlsend/RMLSend.xcodeproj/project.pbxproj create mode 100644 ios/rmlsend/RMLSendViewController.xib create mode 100644 ios/rmlsend/RMLSend_Prefix.pch create mode 100644 ios/rmlsend/main.m create mode 100644 lib/Makefile.am create mode 100644 lib/dbversion.h create mode 100644 lib/export_bmiemr.cpp create mode 100644 lib/export_deltaflex.cpp create mode 100644 lib/export_musicclassical.cpp create mode 100644 lib/export_musicplayout.cpp create mode 100644 lib/export_musicsummary.cpp create mode 100644 lib/export_nprsoundex.cpp create mode 100644 lib/export_radiotraffic.cpp create mode 100644 lib/export_soundex.cpp create mode 100644 lib/export_technical.cpp create mode 100644 lib/export_textlog.cpp create mode 100644 lib/gpio.h create mode 100644 lib/gpl2.html create mode 100644 lib/html_gpl2.cpp create mode 100644 lib/html_gpl2_win32.cpp create mode 100644 lib/lib.pro create mode 100644 lib/librd_cs.ts create mode 100644 lib/librd_de.ts create mode 100644 lib/librd_es.ts create mode 100644 lib/librd_fr.ts create mode 100644 lib/librd_nb.ts create mode 100644 lib/librd_nn.ts create mode 100644 lib/librd_pt_BR.ts create mode 100644 lib/rd.h create mode 100644 lib/rdadd_cart.cpp create mode 100644 lib/rdadd_cart.h create mode 100644 lib/rdadd_log.cpp create mode 100644 lib/rdadd_log.h create mode 100644 lib/rdairplay_conf.cpp create mode 100644 lib/rdairplay_conf.h create mode 100644 lib/rdaudio_exists.cpp create mode 100644 lib/rdaudio_exists.h create mode 100644 lib/rdaudio_port.cpp create mode 100644 lib/rdaudio_port.h create mode 100644 lib/rdaudioconvert.cpp create mode 100644 lib/rdaudioconvert.h create mode 100644 lib/rdaudioexport.cpp create mode 100644 lib/rdaudioexport.h create mode 100644 lib/rdaudioimport.cpp create mode 100644 lib/rdaudioimport.h create mode 100644 lib/rdaudioinfo.cpp create mode 100644 lib/rdaudioinfo.h create mode 100644 lib/rdaudiosettings.cpp create mode 100644 lib/rdaudiosettings.h create mode 100644 lib/rdaudiosettings_dialog.cpp create mode 100644 lib/rdaudiosettings_dialog.h create mode 100644 lib/rdbusybar.cpp create mode 100644 lib/rdbusybar.h create mode 100644 lib/rdbusydialog.cpp create mode 100644 lib/rdbusydialog.h create mode 100644 lib/rdbutton_dialog.cpp create mode 100644 lib/rdbutton_dialog.h create mode 100644 lib/rdbutton_panel.cpp create mode 100644 lib/rdbutton_panel.h create mode 100644 lib/rdcae.cpp create mode 100644 lib/rdcae.h create mode 100644 lib/rdcardselector.cpp create mode 100644 lib/rdcardselector.h create mode 100644 lib/rdcart.cpp create mode 100644 lib/rdcart.h create mode 100644 lib/rdcart_dialog.cpp create mode 100644 lib/rdcart_dialog.h create mode 100644 lib/rdcart_search_text.cpp create mode 100644 lib/rdcart_search_text.h create mode 100644 lib/rdcartdrag.cpp create mode 100644 lib/rdcartdrag.h create mode 100644 lib/rdcartslot.cpp create mode 100644 lib/rdcartslot.h create mode 100644 lib/rdcastsearch.cpp create mode 100644 lib/rdcastsearch.h create mode 100644 lib/rdcatch_conf.cpp create mode 100644 lib/rdcatch_conf.h create mode 100644 lib/rdcatch_connect.cpp create mode 100644 lib/rdcatch_connect.h create mode 100644 lib/rdcddblookup.cpp create mode 100644 lib/rdcddblookup.h create mode 100644 lib/rdcddbrecord.cpp create mode 100644 lib/rdcddbrecord.h create mode 100644 lib/rdcdplayer.cpp create mode 100644 lib/rdcdplayer.h create mode 100644 lib/rdcdripper.cpp create mode 100644 lib/rdcdripper.h create mode 100644 lib/rdcheck_daemons.cpp create mode 100644 lib/rdcheck_daemons.h create mode 100644 lib/rdcheck_version.cpp create mode 100644 lib/rdcheck_version.h create mode 100644 lib/rdclock.cpp create mode 100644 lib/rdclock.h create mode 100644 lib/rdcmd_cache.cpp create mode 100644 lib/rdcmd_cache.h create mode 100644 lib/rdcmd_switch.cpp create mode 100644 lib/rdcmd_switch.h create mode 100644 lib/rdcodetrap.cpp create mode 100644 lib/rdcodetrap.h create mode 100644 lib/rdcombobox.cpp create mode 100644 lib/rdcombobox.h create mode 100644 lib/rdconf.cpp create mode 100644 lib/rdconf.h create mode 100644 lib/rdconfig.cpp create mode 100644 lib/rdconfig.h create mode 100644 lib/rdcopyaudio.cpp create mode 100644 lib/rdcopyaudio.h create mode 100644 lib/rdcreate_log.cpp create mode 100644 lib/rdcreate_log.h create mode 100644 lib/rdcreateauxfieldstable.cpp create mode 100644 lib/rdcreateauxfieldstable.h create mode 100644 lib/rdcueedit.cpp create mode 100644 lib/rdcueedit.h create mode 100644 lib/rdcueeditdialog.cpp create mode 100644 lib/rdcueeditdialog.h create mode 100644 lib/rdcut.cpp create mode 100644 lib/rdcut.h create mode 100644 lib/rdcut_dialog.cpp create mode 100644 lib/rdcut_dialog.h create mode 100644 lib/rdcut_path.cpp create mode 100644 lib/rdcut_path.h create mode 100644 lib/rddatedecode.cpp create mode 100644 lib/rddatedecode.h create mode 100644 lib/rddatedialog.cpp create mode 100644 lib/rddatedialog.h create mode 100644 lib/rddatepicker.cpp create mode 100644 lib/rddatepicker.h create mode 100644 lib/rddb.cpp create mode 100644 lib/rddb.h create mode 100644 lib/rddbheartbeat.cpp create mode 100644 lib/rddbheartbeat.h create mode 100644 lib/rddebug.cpp create mode 100644 lib/rddebug.h create mode 100644 lib/rddeck.cpp create mode 100644 lib/rddeck.h create mode 100644 lib/rddelete.cpp create mode 100644 lib/rddelete.h create mode 100644 lib/rddownload.cpp create mode 100644 lib/rddownload.h create mode 100644 lib/rddropbox.cpp create mode 100644 lib/rddropbox.h create mode 100644 lib/rdedit_audio.cpp create mode 100644 lib/rdedit_audio.h create mode 100644 lib/rdedit_panel_name.cpp create mode 100644 lib/rdedit_panel_name.h create mode 100644 lib/rdemptycart.cpp create mode 100644 lib/rdemptycart.h create mode 100644 lib/rdencoder.cpp create mode 100644 lib/rdencoder.h create mode 100644 lib/rdencoderlist.cpp create mode 100644 lib/rdencoderlist.h create mode 100644 lib/rdescape_string.cpp create mode 100644 lib/rdescape_string.h create mode 100644 lib/rdevent.cpp create mode 100644 lib/rdevent.h create mode 100644 lib/rdevent_line.cpp create mode 100644 lib/rdevent_line.h create mode 100644 lib/rdevent_player.cpp create mode 100644 lib/rdevent_player.h create mode 100644 lib/rdexception_dialog.cpp create mode 100644 lib/rdexception_dialog.h create mode 100644 lib/rdexport_settings_dialog.cpp create mode 100644 lib/rdexport_settings_dialog.h create mode 100644 lib/rdfeed.cpp create mode 100644 lib/rdfeed.h create mode 100644 lib/rdfeedlog.cpp create mode 100644 lib/rdfeedlog.h create mode 100644 lib/rdflacdecode.cpp create mode 100644 lib/rdflacdecode.h create mode 100644 lib/rdformpost.cpp create mode 100644 lib/rdformpost.h create mode 100644 lib/rdgain_envelope.cpp create mode 100644 lib/rdgain_envelope.h create mode 100644 lib/rdget_ath.cpp create mode 100644 lib/rdget_ath.h create mode 100644 lib/rdgetpasswd.cpp create mode 100644 lib/rdgetpasswd.h create mode 100644 lib/rdgpio.cpp create mode 100644 lib/rdgpio.h create mode 100644 lib/rdgpioselector.cpp create mode 100644 lib/rdgpioselector.h create mode 100644 lib/rdgrid.cpp create mode 100644 lib/rdgrid.h create mode 100644 lib/rdgroup.cpp create mode 100644 lib/rdgroup.h create mode 100644 lib/rdgroup_list.cpp create mode 100644 lib/rdgroup_list.h create mode 100644 lib/rdhotkeylist.cpp create mode 100644 lib/rdhotkeylist.h create mode 100644 lib/rdhotkeys.cpp create mode 100644 lib/rdhotkeys.h create mode 100644 lib/rdidvalidator.cpp create mode 100644 lib/rdidvalidator.h create mode 100644 lib/rdimport_audio.cpp create mode 100644 lib/rdimport_audio.h create mode 100644 lib/rdinstancelock.cpp create mode 100644 lib/rdinstancelock.h create mode 100644 lib/rdintegerdialog.cpp create mode 100644 lib/rdintegerdialog.h create mode 100644 lib/rdintegeredit.cpp create mode 100644 lib/rdintegeredit.h create mode 100644 lib/rdlabel.cpp create mode 100644 lib/rdlabel.h create mode 100644 lib/rdlibrary_conf.cpp create mode 100644 lib/rdlibrary_conf.h create mode 100644 lib/rdlicense.cpp create mode 100644 lib/rdlicense.h create mode 100644 lib/rdlineedit.cpp create mode 100644 lib/rdlineedit.h create mode 100644 lib/rdlist_groups.cpp create mode 100644 lib/rdlist_groups.h create mode 100644 lib/rdlist_logs.cpp create mode 100644 lib/rdlist_logs.h create mode 100644 lib/rdlistselector.cpp create mode 100644 lib/rdlistselector.h create mode 100644 lib/rdlistsvcs.cpp create mode 100644 lib/rdlistsvcs.h create mode 100644 lib/rdlistview.cpp create mode 100644 lib/rdlistview.h create mode 100644 lib/rdlistviewitem.cpp create mode 100644 lib/rdlistviewitem.h create mode 100644 lib/rdlivewire.cpp create mode 100644 lib/rdlivewire.h create mode 100644 lib/rdlivewiredestination.cpp create mode 100644 lib/rdlivewiredestination.h create mode 100644 lib/rdlivewiresource.cpp create mode 100644 lib/rdlivewiresource.h create mode 100644 lib/rdlog.cpp create mode 100644 lib/rdlog.h create mode 100644 lib/rdlog_event.cpp create mode 100644 lib/rdlog_event.h create mode 100644 lib/rdlog_line.cpp create mode 100644 lib/rdlog_line.h create mode 100644 lib/rdlogedit_conf.cpp create mode 100644 lib/rdlogedit_conf.h create mode 100644 lib/rdmacro.cpp create mode 100644 lib/rdmacro.h create mode 100644 lib/rdmacro_event.cpp create mode 100644 lib/rdmacro_event.h create mode 100644 lib/rdmarker_bar.cpp create mode 100644 lib/rdmarker_bar.h create mode 100644 lib/rdmarker_button.cpp create mode 100644 lib/rdmarker_button.h create mode 100644 lib/rdmarker_edit.cpp create mode 100644 lib/rdmarker_edit.h create mode 100644 lib/rdmatrix.cpp create mode 100644 lib/rdmatrix.h create mode 100644 lib/rdmeteraverage.cpp create mode 100644 lib/rdmeteraverage.h create mode 100644 lib/rdmixer.cpp create mode 100644 lib/rdmixer.h create mode 100644 lib/rdmonitor_config.cpp create mode 100644 lib/rdmonitor_config.h create mode 100644 lib/rdnownext.cpp create mode 100644 lib/rdnownext.h create mode 100644 lib/rdoneshot.cpp create mode 100644 lib/rdoneshot.h create mode 100644 lib/rdpam.cpp create mode 100644 lib/rdpam.h create mode 100644 lib/rdpanel_button.cpp create mode 100644 lib/rdpanel_button.h create mode 100644 lib/rdpasswd.cpp create mode 100644 lib/rdpasswd.h create mode 100644 lib/rdpaths.h.in create mode 100644 lib/rdpeaksexport.cpp create mode 100644 lib/rdpeaksexport.h create mode 100644 lib/rdplay_deck.cpp create mode 100644 lib/rdplay_deck.h create mode 100644 lib/rdplaymeter.cpp create mode 100644 lib/rdplaymeter.h create mode 100644 lib/rdpodcast.cpp create mode 100644 lib/rdpodcast.h create mode 100644 lib/rdprofile.cpp create mode 100644 lib/rdprofile.h create mode 100644 lib/rdprofileline.cpp create mode 100644 lib/rdprofileline.h create mode 100644 lib/rdprofilesection.cpp create mode 100644 lib/rdprofilesection.h create mode 100644 lib/rdpushbutton.cpp create mode 100644 lib/rdpushbutton.h create mode 100644 lib/rdrecording.cpp create mode 100644 lib/rdrecording.h create mode 100644 lib/rdreplicator.cpp create mode 100644 lib/rdreplicator.h create mode 100644 lib/rdreport.cpp create mode 100644 lib/rdreport.h create mode 100644 lib/rdringbuffer.cpp create mode 100644 lib/rdringbuffer.h create mode 100644 lib/rdripc.cpp create mode 100644 lib/rdripc.h create mode 100644 lib/rdschedcodes_dialog.cpp create mode 100644 lib/rdschedcodes_dialog.h create mode 100644 lib/rdsegmeter.cpp create mode 100644 lib/rdsegmeter.h create mode 100644 lib/rdsettings.cpp create mode 100644 lib/rdsettings.h create mode 100644 lib/rdsimpleplayer.cpp create mode 100644 lib/rdsimpleplayer.h create mode 100644 lib/rdslider.cpp create mode 100644 lib/rdslider.h create mode 100644 lib/rdslotbox.cpp create mode 100644 lib/rdslotbox.h create mode 100644 lib/rdslotdialog.cpp create mode 100644 lib/rdslotdialog.h create mode 100644 lib/rdslotoptions.cpp create mode 100644 lib/rdslotoptions.h create mode 100644 lib/rdsocket.cpp create mode 100644 lib/rdsocket.h create mode 100644 lib/rdsound_panel.cpp create mode 100644 lib/rdsound_panel.h create mode 100644 lib/rdstation.cpp create mode 100644 lib/rdstation.h create mode 100644 lib/rdstatus.cpp create mode 100644 lib/rdstatus.h create mode 100644 lib/rdstereometer.cpp create mode 100644 lib/rdstereometer.h create mode 100644 lib/rdstringlist.cpp create mode 100644 lib/rdstringlist.h create mode 100644 lib/rdsvc.cpp create mode 100644 lib/rdsvc.h create mode 100644 lib/rdsystem.cpp create mode 100644 lib/rdsystem.h create mode 100644 lib/rdsystemuser.cpp create mode 100644 lib/rdsystemuser.h create mode 100644 lib/rdtextfile.cpp create mode 100644 lib/rdtextfile.h create mode 100644 lib/rdtextvalidator.cpp create mode 100644 lib/rdtextvalidator.h create mode 100644 lib/rdtimeedit.cpp create mode 100644 lib/rdtimeedit.h create mode 100644 lib/rdtimeengine.cpp create mode 100644 lib/rdtimeengine.h create mode 100644 lib/rdtimeevent.cpp create mode 100644 lib/rdtimeevent.h create mode 100644 lib/rdtransportbutton.cpp create mode 100644 lib/rdtransportbutton.h create mode 100644 lib/rdtrimaudio.cpp create mode 100644 lib/rdtrimaudio.h create mode 100644 lib/rdtty.cpp create mode 100644 lib/rdtty.h create mode 100644 lib/rdttydevice.cpp create mode 100644 lib/rdttydevice.h create mode 100644 lib/rdttydevice_win32.cpp create mode 100644 lib/rdttyout.cpp create mode 100644 lib/rdttyout.h create mode 100644 lib/rdupload.cpp create mode 100644 lib/rdupload.h create mode 100644 lib/rdurl.cpp create mode 100644 lib/rdurl.h create mode 100644 lib/rduser.cpp create mode 100644 lib/rduser.h create mode 100644 lib/rdversion.cpp create mode 100644 lib/rdversion.h create mode 100644 lib/rdwavedata.cpp create mode 100644 lib/rdwavedata.h create mode 100644 lib/rdwavedata_dialog.cpp create mode 100644 lib/rdwavedata_dialog.h create mode 100644 lib/rdwavefile.cpp create mode 100644 lib/rdwavefile.h create mode 100644 lib/rdwavepainter.cpp create mode 100644 lib/rdwavepainter.h create mode 100644 lib/rdweb.cpp create mode 100644 lib/rdweb.h create mode 100644 lib/rdwebresult.cpp create mode 100644 lib/rdwebresult.h create mode 100644 lib/rdwin32.cpp create mode 100644 lib/rdwin32.h create mode 100644 lib/rdxport_interface.h create mode 100644 lib/schedcartlist.cpp create mode 100644 lib/schedcartlist.h create mode 100644 lib/schedruleslist.cpp create mode 100644 lib/schedruleslist.h create mode 100755 make_slack.in create mode 100644 pam_rd/Makefile.am create mode 100644 pam_rd/pam_rd.cpp create mode 100644 rdadmin/Makefile.am create mode 100644 rdadmin/add_aux_field.cpp create mode 100644 rdadmin/add_aux_field.h create mode 100644 rdadmin/add_encoder.cpp create mode 100644 rdadmin/add_encoder.h create mode 100644 rdadmin/add_feed.cpp create mode 100644 rdadmin/add_feed.h create mode 100644 rdadmin/add_group.cpp create mode 100644 rdadmin/add_group.h create mode 100644 rdadmin/add_hostvar.cpp create mode 100644 rdadmin/add_hostvar.h create mode 100644 rdadmin/add_matrix.cpp create mode 100644 rdadmin/add_matrix.h create mode 100644 rdadmin/add_replicator.cpp create mode 100644 rdadmin/add_replicator.h create mode 100644 rdadmin/add_report.cpp create mode 100644 rdadmin/add_report.h create mode 100644 rdadmin/add_schedcodes.cpp create mode 100644 rdadmin/add_schedcodes.h create mode 100644 rdadmin/add_station.cpp create mode 100644 rdadmin/add_station.h create mode 100644 rdadmin/add_svc.cpp create mode 100644 rdadmin/add_svc.h create mode 100644 rdadmin/add_user.cpp create mode 100644 rdadmin/add_user.h create mode 100644 rdadmin/autofill_carts.cpp create mode 100644 rdadmin/autofill_carts.h create mode 100644 rdadmin/createdb.cpp create mode 100644 rdadmin/createdb.h create mode 100644 rdadmin/edit_audios.cpp create mode 100644 rdadmin/edit_audios.h create mode 100644 rdadmin/edit_aux_field.cpp create mode 100644 rdadmin/edit_aux_field.h create mode 100644 rdadmin/edit_backup.cpp create mode 100644 rdadmin/edit_backup.h create mode 100644 rdadmin/edit_cartslots.cpp create mode 100644 rdadmin/edit_cartslots.h create mode 100644 rdadmin/edit_channelgpios.cpp create mode 100644 rdadmin/edit_channelgpios.h create mode 100644 rdadmin/edit_decks.cpp create mode 100644 rdadmin/edit_decks.h create mode 100644 rdadmin/edit_dropbox.cpp create mode 100644 rdadmin/edit_dropbox.h create mode 100644 rdadmin/edit_encoder.cpp create mode 100644 rdadmin/edit_encoder.h create mode 100644 rdadmin/edit_endpoint.cpp create mode 100644 rdadmin/edit_endpoint.h create mode 100644 rdadmin/edit_feed.cpp create mode 100644 rdadmin/edit_feed.h create mode 100644 rdadmin/edit_feed_perms.cpp create mode 100644 rdadmin/edit_feed_perms.h create mode 100644 rdadmin/edit_gpi.cpp create mode 100644 rdadmin/edit_gpi.h create mode 100644 rdadmin/edit_group.cpp create mode 100644 rdadmin/edit_group.h create mode 100644 rdadmin/edit_hostvar.cpp create mode 100644 rdadmin/edit_hostvar.h create mode 100644 rdadmin/edit_hotkeys.cpp create mode 100644 rdadmin/edit_hotkeys.h create mode 100644 rdadmin/edit_jack.cpp create mode 100644 rdadmin/edit_jack.h create mode 100644 rdadmin/edit_jack_client.cpp create mode 100644 rdadmin/edit_jack_client.h create mode 100644 rdadmin/edit_livewiregpio.cpp create mode 100644 rdadmin/edit_livewiregpio.h create mode 100644 rdadmin/edit_matrix.cpp create mode 100644 rdadmin/edit_matrix.h create mode 100644 rdadmin/edit_node.cpp create mode 100644 rdadmin/edit_node.h create mode 100644 rdadmin/edit_now_next.cpp create mode 100644 rdadmin/edit_now_next.h create mode 100644 rdadmin/edit_nownextplugin.cpp create mode 100644 rdadmin/edit_nownextplugin.h create mode 100644 rdadmin/edit_rdairplay.cpp create mode 100644 rdadmin/edit_rdairplay.h create mode 100644 rdadmin/edit_rdlibrary.cpp create mode 100644 rdadmin/edit_rdlibrary.h create mode 100644 rdadmin/edit_rdlogedit.cpp create mode 100644 rdadmin/edit_rdlogedit.h create mode 100644 rdadmin/edit_rdpanel.cpp create mode 100644 rdadmin/edit_rdpanel.h create mode 100644 rdadmin/edit_replicator.cpp create mode 100644 rdadmin/edit_replicator.h create mode 100644 rdadmin/edit_report.cpp create mode 100644 rdadmin/edit_report.h create mode 100644 rdadmin/edit_sas_resource.cpp create mode 100644 rdadmin/edit_sas_resource.h create mode 100644 rdadmin/edit_schedcodes.cpp create mode 100644 rdadmin/edit_schedcodes.h create mode 100644 rdadmin/edit_settings.cpp create mode 100644 rdadmin/edit_settings.h create mode 100644 rdadmin/edit_station.cpp create mode 100644 rdadmin/edit_station.h create mode 100644 rdadmin/edit_svc.cpp create mode 100644 rdadmin/edit_svc.h create mode 100644 rdadmin/edit_svc_perms.cpp create mode 100644 rdadmin/edit_svc_perms.h create mode 100644 rdadmin/edit_ttys.cpp create mode 100644 rdadmin/edit_ttys.h create mode 100644 rdadmin/edit_user.cpp create mode 100644 rdadmin/edit_user.h create mode 100644 rdadmin/edit_user_perms.cpp create mode 100644 rdadmin/edit_user_perms.h create mode 100644 rdadmin/edit_vguest_resource.cpp create mode 100644 rdadmin/edit_vguest_resource.h create mode 100644 rdadmin/globals.h create mode 100644 rdadmin/help_audios.cpp create mode 100644 rdadmin/help_audios.h create mode 100644 rdadmin/importfields.cpp create mode 100644 rdadmin/importfields.h create mode 100644 rdadmin/info_banner1.xpm create mode 100644 rdadmin/info_banner2.xpm create mode 100644 rdadmin/info_dialog.cpp create mode 100644 rdadmin/info_dialog.h create mode 100644 rdadmin/list_aux_fields.cpp create mode 100644 rdadmin/list_aux_fields.h create mode 100644 rdadmin/list_dropboxes.cpp create mode 100644 rdadmin/list_dropboxes.h create mode 100644 rdadmin/list_encoders.cpp create mode 100644 rdadmin/list_encoders.h create mode 100644 rdadmin/list_endpoints.cpp create mode 100644 rdadmin/list_endpoints.h create mode 100644 rdadmin/list_feeds.cpp create mode 100644 rdadmin/list_feeds.h create mode 100644 rdadmin/list_gpis.cpp create mode 100644 rdadmin/list_gpis.h create mode 100644 rdadmin/list_groups.cpp create mode 100644 rdadmin/list_groups.h create mode 100644 rdadmin/list_hostvars.cpp create mode 100644 rdadmin/list_hostvars.h create mode 100644 rdadmin/list_livewiregpios.cpp create mode 100644 rdadmin/list_livewiregpios.h create mode 100644 rdadmin/list_matrices.cpp create mode 100644 rdadmin/list_matrices.h create mode 100644 rdadmin/list_nodes.cpp create mode 100644 rdadmin/list_nodes.h create mode 100644 rdadmin/list_replicator_carts.cpp create mode 100644 rdadmin/list_replicator_carts.h create mode 100644 rdadmin/list_replicators.cpp create mode 100644 rdadmin/list_replicators.h create mode 100644 rdadmin/list_reports.cpp create mode 100644 rdadmin/list_reports.h create mode 100644 rdadmin/list_sas_resources.cpp create mode 100644 rdadmin/list_sas_resources.h create mode 100644 rdadmin/list_schedcodes.cpp create mode 100644 rdadmin/list_schedcodes.h create mode 100644 rdadmin/list_stations.cpp create mode 100644 rdadmin/list_stations.h create mode 100644 rdadmin/list_svcs.cpp create mode 100644 rdadmin/list_svcs.h create mode 100644 rdadmin/list_users.cpp create mode 100644 rdadmin/list_users.h create mode 100644 rdadmin/list_vguest_resources.cpp create mode 100644 rdadmin/list_vguest_resources.h create mode 100644 rdadmin/login.cpp create mode 100644 rdadmin/login.h create mode 100644 rdadmin/mysql_login.cpp create mode 100644 rdadmin/mysql_login.h create mode 100644 rdadmin/opendb.cpp create mode 100644 rdadmin/opendb.h create mode 100644 rdadmin/rdadmin.cpp create mode 100644 rdadmin/rdadmin.h create mode 100644 rdadmin/rdadmin.pro create mode 100644 rdadmin/rdadmin_cs.ts create mode 100644 rdadmin/rdadmin_de.ts create mode 100644 rdadmin/rdadmin_es.ts create mode 100644 rdadmin/rdadmin_fr.ts create mode 100644 rdadmin/rdadmin_nb.ts create mode 100644 rdadmin/rdadmin_nn.ts create mode 100644 rdadmin/rdadmin_pt_BR.ts create mode 100644 rdadmin/rename_group.cpp create mode 100644 rdadmin/rename_group.h create mode 100644 rdadmin/test_import.cpp create mode 100644 rdadmin/test_import.h create mode 100644 rdadmin/view_adapters.cpp create mode 100644 rdadmin/view_adapters.h create mode 100644 rdadmin/view_node_info.cpp create mode 100644 rdadmin/view_node_info.h create mode 100644 rdadmin/xpm_info_banner1.cpp create mode 100644 rdadmin/xpm_info_banner2.cpp create mode 100644 rdairplay/Makefile.am create mode 100644 rdairplay/button_log.cpp create mode 100644 rdairplay/button_log.h create mode 100644 rdairplay/colors.h create mode 100644 rdairplay/edit_event.cpp create mode 100644 rdairplay/edit_event.h create mode 100644 rdairplay/globals.h create mode 100644 rdairplay/hourselector.cpp create mode 100644 rdairplay/hourselector.h create mode 100644 rdairplay/lib_listview.cpp create mode 100644 rdairplay/lib_listview.h create mode 100644 rdairplay/list_log.cpp create mode 100644 rdairplay/list_log.h create mode 100644 rdairplay/list_logs.cpp create mode 100644 rdairplay/list_logs.h create mode 100644 rdairplay/local_macros.cpp create mode 100644 rdairplay/log_play.cpp create mode 100644 rdairplay/log_play.h create mode 100644 rdairplay/log_traffic.cpp create mode 100644 rdairplay/log_traffic.h create mode 100644 rdairplay/loglinebox.cpp create mode 100644 rdairplay/loglinebox.h create mode 100644 rdairplay/mode_display.cpp create mode 100644 rdairplay/mode_display.h create mode 100644 rdairplay/nownext.cpp create mode 100644 rdairplay/pie_counter.cpp create mode 100644 rdairplay/pie_counter.h create mode 100644 rdairplay/post_counter.cpp create mode 100644 rdairplay/post_counter.h create mode 100644 rdairplay/rdairplay.cpp create mode 100644 rdairplay/rdairplay.h create mode 100644 rdairplay/rdairplay.pro create mode 100644 rdairplay/rdairplay_cs.ts create mode 100644 rdairplay/rdairplay_de.ts create mode 100644 rdairplay/rdairplay_es.ts create mode 100644 rdairplay/rdairplay_fr.ts create mode 100644 rdairplay/rdairplay_nb.ts create mode 100644 rdairplay/rdairplay_nn.ts create mode 100644 rdairplay/rdairplay_pt_BR.ts create mode 100644 rdairplay/rlmhost.cpp create mode 100644 rdairplay/rlmhost.h create mode 100644 rdairplay/start_button.cpp create mode 100644 rdairplay/start_button.h create mode 100644 rdairplay/stop_counter.cpp create mode 100644 rdairplay/stop_counter.h create mode 100644 rdairplay/wall_clock.cpp create mode 100644 rdairplay/wall_clock.h create mode 100644 rdcartslots/Makefile.am create mode 100644 rdcartslots/local_macros.cpp create mode 100644 rdcartslots/rdcartslots.cpp create mode 100644 rdcartslots/rdcartslots.h create mode 100644 rdcartslots/rdcartslots.pro create mode 100644 rdcartslots/rdcartslots_de.ts create mode 100644 rdcartslots/rdcartslots_es.ts create mode 100644 rdcartslots/rdcartslots_fr.ts create mode 100644 rdcartslots/rdcartslots_nb.ts create mode 100644 rdcartslots/rdcartslots_nn.ts create mode 100644 rdcartslots/rdcartslots_pt_BR.ts create mode 100644 rdcastmanager/Makefile.am create mode 100644 rdcastmanager/edit_cast.cpp create mode 100644 rdcastmanager/edit_cast.h create mode 100644 rdcastmanager/globals.h create mode 100644 rdcastmanager/list_casts.cpp create mode 100644 rdcastmanager/list_casts.h create mode 100644 rdcastmanager/pick_report_dates.cpp create mode 100644 rdcastmanager/pick_report_dates.h create mode 100644 rdcastmanager/rdcastmanager.cpp create mode 100644 rdcastmanager/rdcastmanager.h create mode 100644 rdcastmanager/rdcastmanager.pro create mode 100644 rdcastmanager/rdcastmanager_cs.ts create mode 100644 rdcastmanager/rdcastmanager_de.ts create mode 100644 rdcastmanager/rdcastmanager_es.ts create mode 100644 rdcastmanager/rdcastmanager_fr.ts create mode 100644 rdcastmanager/rdcastmanager_nb.ts create mode 100644 rdcastmanager/rdcastmanager_nn.ts create mode 100644 rdcastmanager/rdcastmanager_pt_BR.ts create mode 100644 rdcatch/Makefile.am create mode 100644 rdcatch/add_recording.cpp create mode 100644 rdcatch/add_recording.h create mode 100644 rdcatch/catch_listview.cpp create mode 100644 rdcatch/catch_listview.h create mode 100644 rdcatch/catch_monitor.cpp create mode 100644 rdcatch/catch_monitor.h create mode 100644 rdcatch/colors.h create mode 100644 rdcatch/deckmon.cpp create mode 100644 rdcatch/deckmon.h create mode 100644 rdcatch/edit_cartevent.cpp create mode 100644 rdcatch/edit_cartevent.h create mode 100644 rdcatch/edit_download.cpp create mode 100644 rdcatch/edit_download.h create mode 100644 rdcatch/edit_playout.cpp create mode 100644 rdcatch/edit_playout.h create mode 100644 rdcatch/edit_recording.cpp create mode 100644 rdcatch/edit_recording.h create mode 100644 rdcatch/edit_switchevent.cpp create mode 100644 rdcatch/edit_switchevent.h create mode 100644 rdcatch/edit_upload.cpp create mode 100644 rdcatch/edit_upload.h create mode 100644 rdcatch/globals.h create mode 100644 rdcatch/list_reports.cpp create mode 100644 rdcatch/list_reports.h create mode 100644 rdcatch/rdcatch.cpp create mode 100644 rdcatch/rdcatch.h create mode 100644 rdcatch/rdcatch.pro create mode 100644 rdcatch/rdcatch_cs.ts create mode 100644 rdcatch/rdcatch_de.ts create mode 100644 rdcatch/rdcatch_es.ts create mode 100644 rdcatch/rdcatch_fr.ts create mode 100644 rdcatch/rdcatch_nb.ts create mode 100644 rdcatch/rdcatch_nn.ts create mode 100644 rdcatch/rdcatch_pt_BR.ts create mode 100644 rdcatch/vbox.cpp create mode 100644 rdcatch/vbox.h create mode 100644 rdcatchd/Makefile.am create mode 100644 rdcatchd/batch.cpp create mode 100644 rdcatchd/catch_event.cpp create mode 100644 rdcatchd/catch_event.h create mode 100644 rdcatchd/local_macros.cpp create mode 100644 rdcatchd/rdcatchd.cpp create mode 100644 rdcatchd/rdcatchd.h create mode 100644 rdcatchd/rdcatchd_socket.cpp create mode 100644 rdcatchd/rdcatchd_socket.h create mode 100644 rdhpi/Makefile.am create mode 100644 rdhpi/rdhpi.pro create mode 100644 rdhpi/rdhpi_cs.ts create mode 100644 rdhpi/rdhpi_de.ts create mode 100644 rdhpi/rdhpi_es.ts create mode 100644 rdhpi/rdhpi_fr.ts create mode 100644 rdhpi/rdhpi_nb.ts create mode 100644 rdhpi/rdhpi_nn.ts create mode 100644 rdhpi/rdhpi_pt_BR.ts create mode 100644 rdhpi/rdhpicardselector.cpp create mode 100644 rdhpi/rdhpicardselector.h create mode 100644 rdhpi/rdhpiinformation.cpp create mode 100644 rdhpi/rdhpiinformation.h create mode 100644 rdhpi/rdhpiplaystream.cpp create mode 100644 rdhpi/rdhpiplaystream.h create mode 100644 rdhpi/rdhpirecordstream.cpp create mode 100644 rdhpi/rdhpirecordstream.h create mode 100644 rdhpi/rdhpisoundcard.cpp create mode 100644 rdhpi/rdhpisoundcard.h create mode 100644 rdhpi/rdhpisoundselector.cpp create mode 100644 rdhpi/rdhpisoundselector.h create mode 100644 rdlibrary/Makefile.am create mode 100644 rdlibrary/audio_cart.cpp create mode 100644 rdlibrary/audio_cart.h create mode 100644 rdlibrary/audio_controls.h create mode 100644 rdlibrary/cart_tip.cpp create mode 100644 rdlibrary/cart_tip.h create mode 100644 rdlibrary/cdripper.cpp create mode 100644 rdlibrary/cdripper.h create mode 100644 rdlibrary/disk_gauge.cpp create mode 100644 rdlibrary/disk_gauge.h create mode 100644 rdlibrary/disk_ripper.cpp create mode 100644 rdlibrary/disk_ripper.h create mode 100644 rdlibrary/edit_cart.cpp create mode 100644 rdlibrary/edit_cart.h create mode 100644 rdlibrary/edit_macro.cpp create mode 100644 rdlibrary/edit_macro.h create mode 100644 rdlibrary/edit_notes.cpp create mode 100644 rdlibrary/edit_notes.h create mode 100644 rdlibrary/edit_schedulercodes.cpp create mode 100644 rdlibrary/edit_schedulercodes.h create mode 100644 rdlibrary/filter.cpp create mode 100644 rdlibrary/filter.h create mode 100644 rdlibrary/globals.h create mode 100644 rdlibrary/lib_listview.cpp create mode 100644 rdlibrary/lib_listview.h create mode 100644 rdlibrary/list_reports.cpp create mode 100644 rdlibrary/list_reports.h create mode 100644 rdlibrary/macro_cart.cpp create mode 100644 rdlibrary/macro_cart.h create mode 100644 rdlibrary/rdlibrary.cpp create mode 100644 rdlibrary/rdlibrary.h create mode 100644 rdlibrary/rdlibrary.pro create mode 100644 rdlibrary/rdlibrary_cs.ts create mode 100644 rdlibrary/rdlibrary_de.ts create mode 100644 rdlibrary/rdlibrary_es.ts create mode 100644 rdlibrary/rdlibrary_fr.ts create mode 100644 rdlibrary/rdlibrary_nb.ts create mode 100644 rdlibrary/rdlibrary_nn.ts create mode 100644 rdlibrary/rdlibrary_pt_BR.ts create mode 100644 rdlibrary/record_cut.cpp create mode 100644 rdlibrary/record_cut.h create mode 100644 rdlibrary/validate_cut.cpp create mode 100644 rdlibrary/validate_cut.h create mode 100644 rdlogedit/Makefile.am create mode 100644 rdlogedit/add_meta.cpp create mode 100644 rdlogedit/add_meta.h create mode 100644 rdlogedit/drop_listview.cpp create mode 100644 rdlogedit/drop_listview.h create mode 100644 rdlogedit/edit_chain.cpp create mode 100644 rdlogedit/edit_chain.h create mode 100644 rdlogedit/edit_log.cpp create mode 100644 rdlogedit/edit_log.h create mode 100644 rdlogedit/edit_logline.cpp create mode 100644 rdlogedit/edit_logline.h create mode 100644 rdlogedit/edit_marker.cpp create mode 100644 rdlogedit/edit_marker.h create mode 100644 rdlogedit/edit_track.cpp create mode 100644 rdlogedit/edit_track.h create mode 100644 rdlogedit/globals.h create mode 100644 rdlogedit/import_track.cpp create mode 100644 rdlogedit/import_track.h create mode 100644 rdlogedit/list_listviewitem.cpp create mode 100644 rdlogedit/list_listviewitem.h create mode 100644 rdlogedit/list_logs.cpp create mode 100644 rdlogedit/list_logs.h create mode 100644 rdlogedit/list_reports.cpp create mode 100644 rdlogedit/list_reports.h create mode 100644 rdlogedit/log_listview.cpp create mode 100644 rdlogedit/log_listview.h create mode 100644 rdlogedit/rdlogedit.cpp create mode 100644 rdlogedit/rdlogedit.h create mode 100644 rdlogedit/rdlogedit.pro create mode 100644 rdlogedit/rdlogedit_cs.ts create mode 100644 rdlogedit/rdlogedit_de.ts create mode 100644 rdlogedit/rdlogedit_es.ts create mode 100644 rdlogedit/rdlogedit_fr.ts create mode 100644 rdlogedit/rdlogedit_nb.ts create mode 100644 rdlogedit/rdlogedit_nn.ts create mode 100644 rdlogedit/rdlogedit_pt_BR.ts create mode 100644 rdlogedit/voice_tracker.cpp create mode 100644 rdlogedit/voice_tracker.h create mode 100644 rdlogin/Makefile.am create mode 100644 rdlogin/rdlogin.cpp create mode 100644 rdlogin/rdlogin.h create mode 100644 rdlogin/rdlogin.pro create mode 100644 rdlogin/rdlogin_cs.ts create mode 100644 rdlogin/rdlogin_de.ts create mode 100644 rdlogin/rdlogin_es.ts create mode 100644 rdlogin/rdlogin_fr.ts create mode 100644 rdlogin/rdlogin_nb.ts create mode 100644 rdlogin/rdlogin_nn.ts create mode 100644 rdlogin/rdlogin_pt_BR.ts create mode 100644 rdlogmanager/Makefile.am create mode 100644 rdlogmanager/add_clock.cpp create mode 100644 rdlogmanager/add_clock.h create mode 100644 rdlogmanager/add_event.cpp create mode 100644 rdlogmanager/add_event.h create mode 100644 rdlogmanager/clock_listview.cpp create mode 100644 rdlogmanager/clock_listview.h create mode 100644 rdlogmanager/commandline_ops.cpp create mode 100644 rdlogmanager/edit_clock.cpp create mode 100644 rdlogmanager/edit_clock.h create mode 100644 rdlogmanager/edit_event.cpp create mode 100644 rdlogmanager/edit_event.h create mode 100644 rdlogmanager/edit_eventline.cpp create mode 100644 rdlogmanager/edit_eventline.h create mode 100644 rdlogmanager/edit_grid.cpp create mode 100644 rdlogmanager/edit_grid.h create mode 100644 rdlogmanager/edit_note.cpp create mode 100644 rdlogmanager/edit_note.h create mode 100644 rdlogmanager/edit_perms.cpp create mode 100644 rdlogmanager/edit_perms.h create mode 100644 rdlogmanager/edit_schedcoderules.cpp create mode 100644 rdlogmanager/edit_schedcoderules.h create mode 100644 rdlogmanager/edit_schedrules.cpp create mode 100644 rdlogmanager/edit_schedrules.h create mode 100644 rdlogmanager/edit_track.cpp create mode 100644 rdlogmanager/edit_track.h create mode 100644 rdlogmanager/generate_log.cpp create mode 100644 rdlogmanager/generate_log.h create mode 100644 rdlogmanager/globals.h create mode 100644 rdlogmanager/import_listview.cpp create mode 100644 rdlogmanager/import_listview.h create mode 100644 rdlogmanager/lib_listview.cpp create mode 100644 rdlogmanager/lib_listview.h create mode 100644 rdlogmanager/list_clocks.cpp create mode 100644 rdlogmanager/list_clocks.h create mode 100644 rdlogmanager/list_events.cpp create mode 100644 rdlogmanager/list_events.h create mode 100644 rdlogmanager/list_grids.cpp create mode 100644 rdlogmanager/list_grids.h create mode 100644 rdlogmanager/list_svcs.cpp create mode 100644 rdlogmanager/list_svcs.h create mode 100644 rdlogmanager/pick_report_dates.cpp create mode 100644 rdlogmanager/pick_report_dates.h create mode 100644 rdlogmanager/rdlogmanager.cpp create mode 100644 rdlogmanager/rdlogmanager.h create mode 100644 rdlogmanager/rdlogmanager.pro create mode 100644 rdlogmanager/rdlogmanager_cs.ts create mode 100644 rdlogmanager/rdlogmanager_de.ts create mode 100644 rdlogmanager/rdlogmanager_es.ts create mode 100644 rdlogmanager/rdlogmanager_fr.ts create mode 100644 rdlogmanager/rdlogmanager_nb.ts create mode 100644 rdlogmanager/rdlogmanager_nn.ts create mode 100644 rdlogmanager/rdlogmanager_pt_BR.ts create mode 100644 rdlogmanager/rename_item.cpp create mode 100644 rdlogmanager/rename_item.h create mode 100644 rdlogmanager/svc_rec.cpp create mode 100644 rdlogmanager/svc_rec.h create mode 100644 rdlogmanager/svc_rec_dialog.cpp create mode 100644 rdlogmanager/svc_rec_dialog.h create mode 100644 rdmonitor/Makefile.am create mode 100644 rdmonitor/positiondialog.cpp create mode 100644 rdmonitor/positiondialog.h create mode 100644 rdmonitor/rdmonitor.cpp create mode 100644 rdmonitor/rdmonitor.h create mode 100644 rdmonitor/rdmonitor.pro create mode 100644 rdmonitor/rdmonitor_cs.ts create mode 100644 rdmonitor/rdmonitor_de.ts create mode 100644 rdmonitor/rdmonitor_es.ts create mode 100644 rdmonitor/rdmonitor_fr.ts create mode 100644 rdmonitor/rdmonitor_nb.ts create mode 100644 rdmonitor/rdmonitor_nn.ts create mode 100644 rdmonitor/rdmonitor_pt_BR.ts create mode 100644 rdmonitor/status_tip.cpp create mode 100644 rdmonitor/status_tip.h create mode 100644 rdpanel/Makefile.am create mode 100644 rdpanel/globals.h create mode 100644 rdpanel/rdpanel.cpp create mode 100644 rdpanel/rdpanel.h create mode 100644 rdpanel/rdpanel.pro create mode 100644 rdpanel/rdpanel_cs.ts create mode 100644 rdpanel/rdpanel_de.ts create mode 100644 rdpanel/rdpanel_es.ts create mode 100644 rdpanel/rdpanel_fr.ts create mode 100644 rdpanel/rdpanel_pt_BR.ts create mode 100644 rdrepld-suse.in create mode 100644 rdrepld/Makefile.am create mode 100644 rdrepld/citadelxds.cpp create mode 100644 rdrepld/citadelxds.h create mode 100644 rdrepld/globals.h create mode 100644 rdrepld/rdrepld.cpp create mode 100644 rdrepld/rdrepld.h create mode 100644 rdrepld/replconfig.cpp create mode 100644 rdrepld/replconfig.h create mode 100644 rdrepld/replfactory.cpp create mode 100644 rdrepld/replfactory.h create mode 100644 rdselect/Makefile.am create mode 100644 rdselect/rdselect.cpp create mode 100644 rdselect/rdselect.h create mode 100644 rdselect/rdselect.pro create mode 100644 rdselect/rdselect_cs.ts create mode 100644 rdselect/rdselect_de.ts create mode 100644 rdselect/rdselect_es.ts create mode 100644 rdselect/rdselect_fr.ts create mode 100644 rdselect/rdselect_nb.ts create mode 100644 rdselect/rdselect_nn.ts create mode 100644 rdselect/rdselect_pt_BR.ts create mode 100644 ripcd/Makefile.am create mode 100644 ripcd/acu1p.cpp create mode 100644 ripcd/acu1p.h create mode 100644 ripcd/am16.cpp create mode 100644 ripcd/am16.h create mode 100644 ripcd/bt10x1.cpp create mode 100644 ripcd/bt10x1.h create mode 100644 ripcd/bt16x1.cpp create mode 100644 ripcd/bt16x1.h create mode 100644 ripcd/bt16x2.cpp create mode 100644 ripcd/bt16x2.h create mode 100644 ripcd/bt8x2.cpp create mode 100644 ripcd/bt8x2.h create mode 100644 ripcd/btacs82.cpp create mode 100644 ripcd/btacs82.h create mode 100644 ripcd/btsentinel4web.cpp create mode 100644 ripcd/btsentinel4web.h create mode 100644 ripcd/btsrc16.cpp create mode 100644 ripcd/btsrc16.h create mode 100644 ripcd/btsrc8iii.cpp create mode 100644 ripcd/btsrc8iii.h create mode 100644 ripcd/btss124.cpp create mode 100644 ripcd/btss124.h create mode 100644 ripcd/btss164.cpp create mode 100644 ripcd/btss164.h create mode 100644 ripcd/btss42.cpp create mode 100644 ripcd/btss42.h create mode 100644 ripcd/btss44.cpp create mode 100644 ripcd/btss44.h create mode 100644 ripcd/btss82.cpp create mode 100644 ripcd/btss82.h create mode 100644 ripcd/globals.h create mode 100644 ripcd/harlond.cpp create mode 100644 ripcd/harlond.h create mode 100644 ripcd/livewire_lwrpaudio.cpp create mode 100644 ripcd/livewire_lwrpaudio.h create mode 100644 ripcd/livewire_lwrpgpio.cpp create mode 100644 ripcd/livewire_lwrpgpio.h create mode 100644 ripcd/livewire_mcastgpio.cpp create mode 100644 ripcd/livewire_mcastgpio.h create mode 100644 ripcd/loaddrivers.cpp create mode 100644 ripcd/local_audio.cpp create mode 100644 ripcd/local_audio.h create mode 100644 ripcd/local_gpio.cpp create mode 100644 ripcd/local_gpio.h create mode 100644 ripcd/local_macros.cpp create mode 100644 ripcd/maint_routines.cpp create mode 100644 ripcd/quartz1.cpp create mode 100644 ripcd/quartz1.h create mode 100644 ripcd/ripcd.cpp create mode 100644 ripcd/ripcd.h create mode 100644 ripcd/ripcd.pro create mode 100644 ripcd/ripcd_connection.cpp create mode 100644 ripcd/ripcd_connection.h create mode 100644 ripcd/ripcd_socket.cpp create mode 100644 ripcd/ripcd_socket.h create mode 100644 ripcd/sas32000.cpp create mode 100644 ripcd/sas32000.h create mode 100644 ripcd/sas64000.cpp create mode 100644 ripcd/sas64000.h create mode 100644 ripcd/sas64000gpi.cpp create mode 100644 ripcd/sas64000gpi.h create mode 100644 ripcd/sasusi.cpp create mode 100644 ripcd/sasusi.h create mode 100644 ripcd/starguide3.cpp create mode 100644 ripcd/starguide3.h create mode 100644 ripcd/starguide_feed.cpp create mode 100644 ripcd/starguide_feed.h create mode 100644 ripcd/switcher.cpp create mode 100644 ripcd/switcher.h create mode 100644 ripcd/unity4000.cpp create mode 100644 ripcd/unity4000.h create mode 100644 ripcd/unity_feed.cpp create mode 100644 ripcd/unity_feed.h create mode 100644 ripcd/vguest.cpp create mode 100644 ripcd/vguest.h create mode 100755 rivendell-gentoo create mode 100755 rivendell-suse.in create mode 100755 rivendell.ism create mode 100644 rivendell.pro create mode 100644 rivendell.spec.in create mode 100644 rivendell.sys create mode 100644 rlm/Makefile-example create mode 100644 rlm/Makefile.am create mode 100644 rlm/rlm.h create mode 100644 rlm/rlm_ando.c create mode 100644 rlm/rlm_facebook.c create mode 100644 rlm/rlm_filewrite.c create mode 100644 rlm/rlm_icecast2.c create mode 100644 rlm/rlm_inno713.c create mode 100644 rlm/rlm_liqcomp.c create mode 100644 rlm/rlm_padpoint.c create mode 100644 rlm/rlm_serial.c create mode 100644 rlm/rlm_shoutcast1.c create mode 100644 rlm/rlm_spinitron_plus.c create mode 100644 rlm/rlm_spottrap.c create mode 100644 rlm/rlm_test.c create mode 100644 rlm/rlm_twitter.c create mode 100644 rlm/rlm_udp.c create mode 100644 rlm/rlm_xds.c create mode 100644 rlm/rlm_xmpad.c create mode 100644 scripts/Makefile.am create mode 100755 scripts/crc-unity4k.sh create mode 100755 scripts/kill_rd create mode 100755 scripts/rd_audio_sync create mode 100755 scripts/rd_backup create mode 100755 scripts/rd_backup_system.sh create mode 100755 scripts/rd_config create mode 100755 scripts/rd_create_db create mode 100755 scripts/rd_memmon.sh create mode 100755 scripts/rd_mysql_enable_host.sh create mode 100755 scripts/rd_restore_system.sh create mode 100755 scripts/rdmemcheck.sh create mode 100755 scripts/sage_endec_rwt.sh create mode 100755 scripts/start-rdmonitor.sh create mode 100755 scripts/start_rd create mode 100755 scripts/start_traverso.sh create mode 100644 slack-desc.in create mode 100755 slack_doinst.sh create mode 100644 tests/Makefile.am create mode 100644 tests/audio_convert_test.cpp create mode 100644 tests/audio_convert_test.h create mode 100644 tests/audio_export_test.cpp create mode 100644 tests/audio_export_test.h create mode 100644 tests/audio_import_test.cpp create mode 100644 tests/audio_import_test.h create mode 100644 tests/datedecode_test.cpp create mode 100644 tests/datedecode_test.h create mode 100644 tests/reserve_carts_test.cpp create mode 100644 tests/reserve_carts_test.h create mode 100755 tests/rivendell_standard.txt create mode 100644 tests/sas_switch_torture.cpp create mode 100644 tests/sas_switch_torture.h create mode 100644 tests/sas_torture.cpp create mode 100644 tests/sas_torture.h create mode 100644 tests/stringcode_test.cpp create mode 100644 tests/stringcode_test.h create mode 100644 tests/test_pam.cpp create mode 100644 tests/test_pam.h create mode 100644 tests/timer_test.cpp create mode 100644 tests/timer_test.h create mode 100644 tests/upload_test.cpp create mode 100644 tests/upload_test.h create mode 100644 tests/visualtraffic.txt create mode 100644 utils/Makefile.am create mode 100644 utils/rdalsaconfig/Makefile.am create mode 100644 utils/rdalsaconfig/alsaitem.cpp create mode 100644 utils/rdalsaconfig/alsaitem.h create mode 100644 utils/rdalsaconfig/rdalsa.cpp create mode 100644 utils/rdalsaconfig/rdalsa.h create mode 100644 utils/rdalsaconfig/rdalsaconfig.cpp create mode 100644 utils/rdalsaconfig/rdalsaconfig.h create mode 100644 utils/rdalsaconfig/rdalsaconfig.pro create mode 100644 utils/rdcheckcuts/Makefile.am create mode 100644 utils/rdcheckcuts/rdcheckcuts.cpp create mode 100644 utils/rdcheckcuts/rdcheckcuts.h create mode 100644 utils/rdcheckcuts/rdcheckcuts.pro create mode 100644 utils/rdchunk/Makefile.am create mode 100644 utils/rdchunk/rdchunk.cpp create mode 100644 utils/rdchunk/rdchunk.h create mode 100644 utils/rdchunk/rdchunk.pro create mode 100644 utils/rdchunk/rdchunk_de.ts create mode 100644 utils/rdchunk/rdchunk_es.ts create mode 100644 utils/rdchunk/rdchunk_fr.ts create mode 100644 utils/rdchunk/rdchunk_pt_BR.ts create mode 100644 utils/rdcollect/Makefile.am create mode 100644 utils/rdcollect/rdcollect.cpp create mode 100644 utils/rdcollect/rdcollect.h create mode 100644 utils/rdcollect/rdcollect.pro create mode 100644 utils/rddbcheck/Makefile.am create mode 100644 utils/rddbcheck/rddbcheck.cpp create mode 100644 utils/rddbcheck/rddbcheck.h create mode 100644 utils/rddelete/Makefile.am create mode 100644 utils/rddelete/rddelete.cpp create mode 100644 utils/rddelete/rddelete.h create mode 100644 utils/rddgimport/Makefile.am create mode 100644 utils/rddgimport/event.cpp create mode 100644 utils/rddgimport/event.h create mode 100644 utils/rddgimport/rddgimport.cpp create mode 100644 utils/rddgimport/rddgimport.h create mode 100644 utils/rddgimport/rddgimport.pro create mode 100644 utils/rddgimport/rddgimport_de.ts create mode 100644 utils/rddgimport/rddgimport_es.ts create mode 100644 utils/rddgimport/rddgimport_fr.ts create mode 100644 utils/rddgimport/rddgimport_nb.ts create mode 100644 utils/rddgimport/rddgimport_nn.ts create mode 100644 utils/rddgimport/rddgimport_pt_BR.ts create mode 100644 utils/rddiscimport/Makefile.am create mode 100644 utils/rddiscimport/metalibrary.cpp create mode 100644 utils/rddiscimport/metalibrary.h create mode 100644 utils/rddiscimport/metarecord.cpp create mode 100644 utils/rddiscimport/metarecord.h create mode 100644 utils/rddiscimport/rddiscimport.cpp create mode 100644 utils/rddiscimport/rddiscimport.h create mode 100644 utils/rddiscimport/rddiscimport.pro create mode 100644 utils/rddiscimport/rddiscimport_de.ts create mode 100644 utils/rddiscimport/rddiscimport_es.ts create mode 100644 utils/rddiscimport/rddiscimport_fr.ts create mode 100644 utils/rddiscimport/rddiscimport_nb.ts create mode 100644 utils/rddiscimport/rddiscimport_nn.ts create mode 100644 utils/rddiscimport/rddiscimport_pt_BR.ts create mode 100644 utils/rdgen/Makefile.am create mode 100644 utils/rdgen/rdgen.c create mode 100644 utils/rdgen/wavlib.c create mode 100644 utils/rdgen/wavlib.h create mode 100644 utils/rdgpimon/Makefile.am create mode 100644 utils/rdgpimon/gpi_label.cpp create mode 100644 utils/rdgpimon/gpi_label.h create mode 100644 utils/rdgpimon/rdgpimon.cpp create mode 100644 utils/rdgpimon/rdgpimon.h create mode 100644 utils/rdgpimon/rdgpimon.pro create mode 100644 utils/rdgpimon/rdgpimon_cs.ts create mode 100644 utils/rdgpimon/rdgpimon_de.ts create mode 100644 utils/rdgpimon/rdgpimon_es.ts create mode 100644 utils/rdgpimon/rdgpimon_fr.ts create mode 100644 utils/rdgpimon/rdgpimon_nb.ts create mode 100644 utils/rdgpimon/rdgpimon_nn.ts create mode 100644 utils/rdgpimon/rdgpimon_pt_BR.ts create mode 100644 utils/rdhpiinfo/Makefile.am create mode 100644 utils/rdhpiinfo/change_mode.cpp create mode 100644 utils/rdhpiinfo/change_mode.h create mode 100644 utils/rdhpiinfo/rdhpiinfo.cpp create mode 100644 utils/rdhpiinfo/rdhpiinfo.h create mode 100644 utils/rdhpiinfo/rdhpiinfo.pro create mode 100644 utils/rdimport/Makefile.am create mode 100644 utils/rdimport/rdimport.cpp create mode 100644 utils/rdimport/rdimport.h create mode 100644 utils/rdmaint/Makefile.am create mode 100644 utils/rdmaint/rdmaint.cpp create mode 100644 utils/rdmaint/rdmaint.h create mode 100644 utils/rdmarkerset/Makefile.am create mode 100644 utils/rdmarkerset/rdmarkerset.cpp create mode 100644 utils/rdmarkerset/rdmarkerset.h create mode 100644 utils/rdpopup/Makefile.am create mode 100644 utils/rdpopup/rdpopup.cpp create mode 100644 utils/rdpopup/rdpopup.h create mode 100644 utils/rdpurgecasts/Makefile.am create mode 100644 utils/rdpurgecasts/rdpurgecasts.cpp create mode 100644 utils/rdpurgecasts/rdpurgecasts.h create mode 100644 utils/rdsoftkeys/Makefile.am create mode 100644 utils/rdsoftkeys/rdsoftkeys.cpp create mode 100644 utils/rdsoftkeys/rdsoftkeys.h create mode 100644 utils/rdsoftkeys/rdsoftkeys.pro create mode 100644 utils/rmlsend/Makefile.am create mode 100644 utils/rmlsend/rmlsend.cpp create mode 100644 utils/rmlsend/rmlsend.h create mode 100644 utils/rmlsend/rmlsend.pro create mode 100644 utils/rmlsend/rmlsend_cs.ts create mode 100644 utils/rmlsend/rmlsend_de.ts create mode 100644 utils/rmlsend/rmlsend_es.ts create mode 100644 utils/rmlsend/rmlsend_fr.ts create mode 100644 utils/rmlsend/rmlsend_nb.ts create mode 100644 utils/rmlsend/rmlsend_nn.ts create mode 100644 utils/rmlsend/rmlsend_pt_BR.ts create mode 100644 utils/sas_shim/Makefile.am create mode 100755 utils/sas_shim/rc.sas_shim create mode 100644 utils/sas_shim/sas_shim.cpp create mode 100644 utils/sas_shim/sas_shim.h create mode 100644 utils/utils.pro create mode 100644 web/Makefile.am create mode 100644 web/rdcastmanager/Makefile.am create mode 100644 web/rdcastmanager/rdcastmanager.cpp create mode 100644 web/rdcastmanager/rdcastmanager.h create mode 100644 web/rdcastmanager/rdcastmanager.js create mode 100644 web/rdcastmanager/rdcastmanager.pro create mode 100644 web/rdfeed/Makefile.am create mode 100644 web/rdfeed/rdfeed.pro create mode 100644 web/rdfeed/rdfeed_script.cpp create mode 100644 web/rdfeed/rdfeed_script.h create mode 100644 web/rdxport/Makefile.am create mode 100644 web/rdxport/audioinfo.cpp create mode 100644 web/rdxport/carts.cpp create mode 100644 web/rdxport/copyaudio.cpp create mode 100644 web/rdxport/deleteaudio.cpp create mode 100644 web/rdxport/export.cpp create mode 100644 web/rdxport/exportpeaks.cpp create mode 100644 web/rdxport/groups.cpp create mode 100644 web/rdxport/import.cpp create mode 100644 web/rdxport/logs.cpp create mode 100644 web/rdxport/rdxport.cpp create mode 100644 web/rdxport/rdxport.h create mode 100644 web/rdxport/rdxport.pro create mode 100644 web/rdxport/services.cpp create mode 100644 web/rdxport/trimaudio.cpp create mode 100644 web/tests/Makefile.am create mode 100644 web/tests/addcart.html create mode 100644 web/tests/addcut.html create mode 100644 web/tests/audioinfo.html create mode 100644 web/tests/copyaudio.html create mode 100644 web/tests/delete_audio.html create mode 100644 web/tests/editcart.html create mode 100644 web/tests/export.html create mode 100644 web/tests/exportpeaks.html create mode 100644 web/tests/import.html create mode 100644 web/tests/listcart.html create mode 100644 web/tests/listcarts.html create mode 100644 web/tests/listcut.html create mode 100644 web/tests/listcuts.html create mode 100644 web/tests/listgroup.html create mode 100644 web/tests/listgroups.html create mode 100644 web/tests/listlog.html create mode 100644 web/tests/listlogs.html create mode 100644 web/tests/listservices.html create mode 100644 web/tests/removecart.html create mode 100644 web/tests/removecut.html create mode 100644 web/tests/trimaudio.html create mode 100644 web/web.pro create mode 100644 xdg/Makefile.am create mode 100644 xdg/rdalsaconfig-root-consolehelper create mode 100644 xdg/rdalsaconfig-root-pam create mode 100644 xdg/rdhpiinfo-root-consolehelper create mode 100644 xdg/rdhpiinfo-root-pam create mode 100644 xdg/rivendell-configuration.directory create mode 100644 xdg/rivendell-logtools.directory create mode 100644 xdg/rivendell-rdadmin.desktop create mode 100644 xdg/rivendell-rdairplay.desktop create mode 100644 xdg/rivendell-rdalsaconfig-root.desktop create mode 100644 xdg/rivendell-rdalsaconfig.desktop create mode 100644 xdg/rivendell-rdcartslots.desktop create mode 100644 xdg/rivendell-rdcastmanager.desktop create mode 100644 xdg/rivendell-rdcatch.desktop create mode 100644 xdg/rivendell-rddgimport.desktop create mode 100644 xdg/rivendell-rddiscimport.desktop create mode 100644 xdg/rivendell-rdgpimon.desktop create mode 100644 xdg/rivendell-rdhpiinfo-root.desktop create mode 100644 xdg/rivendell-rdhpiinfo.desktop create mode 100644 xdg/rivendell-rdlibrary.desktop create mode 100644 xdg/rivendell-rdlogedit.desktop create mode 100644 xdg/rivendell-rdlogin.desktop create mode 100644 xdg/rivendell-rdlogmanager.desktop create mode 100644 xdg/rivendell-rdmonitor.desktop create mode 100644 xdg/rivendell-rdpanel.desktop create mode 100644 xdg/rivendell-rdsoftkeys.desktop create mode 100644 xdg/rivendell-rivendell.directory create mode 100644 xdg/rivendell-rivendell.menu create mode 100644 xdg/rivendell-rmlsend.desktop create mode 100644 xdg/rivendell-utilities.directory diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..a4da54f8 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,47 @@ +The following folks have contributed to Rivendell: + +Todd Baker + --create-startdate-offset and --create-enddate-offset options for + RDImport(1). + Hotkey system. + +Luigino Bracci + Spanish translation. + +Michael Cheng + The tooLame MPEG Layer 2 encoder. + +Pavel Fric . + Czech Translation (cs) + +Stefan Gabriel + Integrated Music Scheduler + RDLibrary MultiCart Editing Mode + +Federico Grau + JACK driver cleanups, RDAdmin Audio Ports Dialog enhancements. + PAM Authentication Module + +Fred Gleason + Application Architect + +Dan Mills + General Bughunter Extrordinaire + +Eivind Ødegård + Norwegian Translation (nb_NO and nn_NO) + +Michael Papsdorf + German translation (de). + +Alban Peignier + RDImport batch file importer. + RDScheduler music scheduler. + Debian Packaging. + +Daniel Roviriego + Portuguese Translation (pt_BR). + +Scott Spillers + The Icon set + diff --git a/CODINGSTYLE b/CODINGSTYLE new file mode 100644 index 00000000..d3e9d8b7 --- /dev/null +++ b/CODINGSTYLE @@ -0,0 +1,201 @@ +This is the CODINGSTYLE file for the Rivendell package. + + +OVERVIEW: + +Rivendell is a Free Software project to develop a radio broadcast automation +system. This file, CODINGSTYLE, describes how to get the Rivendell code, +coding style guidelines for writing new code, how to submit patches to be +incorporated into the official Rivendell CVS repository, and other code related +information. General info on the Rivendell project can be found at the +http://www.rivendellaudio.org/ web page and also in the README and INSTALLATION +files. + + + +CODING STYLE GUIDELINES: +Please try to write code that fits with the formating style already present. +Some good basic guidelines: + + LINE LENGTH -- Should be short enough to fit onto an eighty character line + without wrapping. This applies to ChangeLog + entries too! While it's not always possible to follow this + rule (quoted literal strings being one place in particular + where it is sometimes necessary to violate it), sticking + with it wherever possible makes life much easier for those + using character mode editing sessions. + + INDENTATION -- Should be two characters per level. + + CLASS NAMES -- Should have the initial letter of each word capitalized, + e.g. 'ThisIsMyClass'. If the class is part of librd, the + name should be prefaced with the uppercase letters 'RD', + e.g. 'RDThisIsMyClass'. + + METHOD NAMES -- Names of class methods should follow the general style used + by Qt. A special convention for Rivendell is to reserve + names beginning with an uppercase letter for private classes + only. + +VARIABLE NAMES -- Class variables should be prefaced with a short base name + that is common to all, followed by an underscore. For + example, the class 'MyClass' might use 'myclass_', as + in 'myclass_foo1', 'myclass_foo2', etc. *All* variables + should be lowercase only, with uppercase being reserved for + class and method names. + +Doxygen is the code documenting system in place. Doxygen style comments placed +in header files can then be processed to generate friendly code documentation. +More information on doxygen can be found here ( +http://www.stack.nl/~dimitri/doxygen/ ). +FIXME: doxygen code samples + + + +CVS GENERAL INFO: + +CVS allows multiple developers to work simultaneously on a project. CVS does +this by keeping a master version of the source code in a central repository on +the cvs.rivendellaudio.org server. Each developer "checks out" a copy of the +source code to their personal workspace. This local copy of the source is +called a sandbox. Developers test and work on the source in their sandboxes +until they reach a mile-point, such as implementing a new feature or fixing a +bug. Developers can then create a patch or commit their changes back to the +central repository. The CVS server auto-magically merges changes from multiple +developers together. Other developers periodically update their sandboxes to +merge changes others have committed to the server. + +Conflicts normally are prevented by developers communicating and by working on +different areas of the source code. It is important that only working code is +committed back into the repository. + +Though CVS has one main program, cvs, that program has a lot of functionality +which is accessed by giving the program different commands. The general syntax +of the cvs program is: + + cvs CVS_OPTIONS COMMAND COMMAND_OPTIONS + +A brief overview of CVS can be found online here ( +http://techweb.rfa.org/grauf/cvs.html ). + + + +CVS READ: + +Any user can get anonymous read-only access to the CVS repository using the +pserver protocol. The module one wishes to check out must be specified as the +module-name (ex: rivendell). cvs.rivendellaudio.org is configured with the +username "cvs" and the password "cvs". Access via the pserver protocol +requires that a user login/logout. + + cvs -d:pserver:cvs@cvs.rivendellaudio.org:/home/cvs/cvsroot login + cvs -d:pserver:cvs@cvs.rivendellaudio.org:/home/cvs/cvsroot checkout rivendell + cvs -d:pserver:cvs@cvs.rivendellaudio.org:/home/cvs/cvsroot logout + + + + +SUBMITTING PATCHES: + +Contributions of patches with fixes or enhancements are welcome. Posting a +patch to the rivendell programmer mailing list ( +rivendell-prog@rivendellaudio.org +http://www.rivendellaudio.org/mailman/listinfo/rivendell-prog ) is the best +approach for anyone to contribute to the project. Established Rivendell +programmers can then review the patch and apply it to the official CVS tree. +Users who contribute significant patches over time may earn the privilege of +CVS write access. + +The cvs diff command may be used to generate patches from a CVS sandbox. This +allows for a user to checkout a cvs sandbox and make changes as needed by +directly editing the files checked out. When done making changes, the cvs +utility can generate the differences, in patch file format, of the sandbox +version to the repository version of a file. Run the following commands from +within the sandbox. + + # see changes made to sandbox against what was checked out from the + # repository + cvs diff FILE + + # see the difference between two versions of a file in the repository + cvs diff -rVERSION_NUMBER -rVERSION_NUMBER FILE + +Additional flags, such as "-u" can be added to produce a "unified context" +style diff. Similarly the output redirector can be used to send the patch to a +file (which can then be emailed to the mailing list). A sample command +follows: + + cvs diff -u FILE > /tmp/FILE_bugfix_2007.03.26.patch + + + +CVS WRITE: + +Contributors who have write access to the Rivendell CVS repository must use +Secure Shell (ssh) as the secure transport for all non-anonymous CVS access. + +To get this set up, you will need to generate a public key and send it to +Federico Grau and the sysadmin team at +Radio Free Asia (RFA), along with the username one wishes to use. As an +example of how to create a public key, use the following command: + + ssh-keygen -t dsa + +This should prompt you for the base filename to put the public and private keys +in, as well as a passphrase (be sure to use a secure one). Assuming that the +default filenames were accepted, you should then have the following two files +in '~/.ssh/': + + id_dsa + id_dsa.pub + +The 'id_dsa.pub' file is the one that gets sent to don Fede. The other is your +secret key, and should be guarded accordingly. You will need this key every +time you access the CVS archive using your selected username. Once (RFA) has +set up your account, all you will need to do is change the CVSROOT string in +your environment or set the cvs command to point to the new server. The form +of the environment string and a sample checkout command follow: + + export CVSROOT=:ext:@cvs.rivendellaudio.org:/home/cvs/cvsroot + cvs checkout rivendell + +A sample checkout command that does not use the environment variable follows: + + cvs -d:ext:@cvs.rivendellaudio.org:/home/cvs/cvsroot checkout rivendell + +You should now be able to checkout, update and commit material as before, the +only difference being that CVS will prompt you for the passphrase of your +private key each time you access the archive. As a convenience the +ssh-agent(1) and ssh-add(1) utilities can be used to securely hold private keys +used for public key authentication without repeatedly prompting for +passphrases. + + +CVS WRITE COMMIT CHECKLIST: + +Before committing changes back to the Rivendell CVS repository the following +guidelines should be completed: + +1) Successful update of CVS without conflicts. +2) Successful compile of CVS without errors. +3) Update the ChangeLog file at the base of the Rivendell source code tree. + The format of the ChangeLog file has the most recent changes at the bottom + of the file. Entries start with a date stamp and have a format like: + + YYYY-MM-DD [HH:MM TIMEZONE] NAME + * Description of change + + A couple examples follow: + 2007-01-09 19:00 EST Federico Grau + * lib/rdcart.cpp lib/rdcut.cpp rdcatch/rdcatch.cpp; corrected i18n + bug by replacing use of QT shortDayName() with libradio + RGetShortDayNameEN() which will always return english day names + regardless of configured locale. + + 2007-02-23 Fred Gleason + * Modified the code in 'lib/rdimport_audio.cpp' to use the + 'RDCart::setMetadata()' and 'RDCut::setMetadata()' methods. +4) CVS Commit of the files changed using the ChangeLog snippet. + + + diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..d60c31a9 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..c87cf640 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,14297 @@ +2002-4-28 Fred Gleason + * Initial package creation + * Created basic structure for Core Audio Engine (ALSA). PW and DC + commands work. + * Created 'conf' directory for sample configurations. + * Created 'cae.conf-sample' in 'conf' directory. +2002-5-8 Fred Gleason + * Fixed up some parser logic in 'main.c' + * Implemented the 'CR' and 'DL' commands. +2002-6-14 Fred Gleason + * Added basic read-only support in RWaveFile + * Started work on CartChunk read support in RWaveFile +2002-6-16 Fred Gleason + * More work on CartChunk support +2002-6-17 Fred Gleason + * More work on CartChunk support +2002-6-18 Fred Gleason + * Finished basic read-only support for CartChunk in RWaveFile. + * Finished basic read-only support for BEXT chunk in RWaveFile. + * Started work on playout support (seekWave() and readWave() + methods in RWaveFile) + * Created RPlayStream class +2002-6-22 Fred Gleason + * Finished basic (QTimer-based) playout support in RPlayStream +2002-6-23 Fred Gleason + * Added autoconf macros for ALSA and HPI detection. + * Added RTransportButton, an audio transport button widget. +2002-6-24 Fred Gleason + * Completed RTransportButton. + * Added RSoundCard, an audio card abstraction class. +2002-6-25 Fred Gleason + * Added HPI support to RPlayStream. + * Reworked RSoundCard to be a shadow of RPvtSoundCard +2002-6-27 Fred Gleason + * Rearranged the public methods in RPlayStream so to make it + possible to change the audio device dynamically. + * Added 'RSoundSelector', an audio device selector widget based on + 'QListBox'. + * Tweaks and cleanups in the HPI code in RPlayStream + * Added ALSA device enumeration in RPvtSoundCard. Still needs + refining. +2002-7-1 Fred Gleason + * Added 'RPlayMeter', a playback audio level meter. + * More work on mixer support in 'RPvtSoundCard'. +2002-7-2 Fred Gleason + * Completed meter & mixer support in 'RPlayStream'. + * Added positioning support to 'RPlayStream'. +2002-7-3 Fred Gleason + * Added autofade support to 'RPvtSoundCard' and 'RPlayStream'. + * Moved all the enums in 'RPvtSoundCard' to 'RSoundCard'. + * Prettied up the layout in 'qwav'. + * Added 'RSlider', an audio- and touchscreen-friendly slider class. + * Moved all audio-related enums into 'RSoundCard' + * Moved all "general purpose" enums into 'Radio' in libradio. +2002-7-8 Fred Gleason + * Got 'RSlider' working in 'Up' mode, for the audio faders. Still + needs work for other orientations. +2002-7-9 Fred Gleason + * Added 'Down' mode for 'RSlider'. + * Added 'Left' and 'Right' modes for 'RSlider', which is now + substantially complete. + * Modified 'RTransportButton' so as to use a proper color palette. + * Added proper disable/enable support to 'RTransportButton' -i.e. + the widget now greys out properly when disabled. + * Deleted 'wavhdr.c'. Ancient history! +2002-7-10 Fred Gleason + * Moved the following widgets to 'libradio': + 'RTransportButton', 'RPlayMeter', 'RSlider', 'RSoundCard', + 'RPvtSoundCard', 'RPlayStream', 'RWaveFile', and 'RSoundSelector'. +2002-7-14 Fred Gleason + * Fixed a bug in 'configure.in' and 'Makefile.am' that was causing + 'make' to attempt to link ALSA and HPI even when those libraries + were not present. +2002-7-15 Fred Gleason + * Changed 'Makefile.am' to be compatible with new libradio layout. + * Added a test to 'configure.in' for libradio. +2002-7-15 Fred Gleason + * Changed 'qwav' to get the name of the wavefile to load via a + dialog box, rather than passing it on the command line. +2002-7-16 Fred Gleason + * Fixed the position slider, which had been broken during the + changes made yesterday. + * Added the feature to 'qwav' where the name of the loaded WAV + file will appear on the title bar. If the WAV file contains a + cart chunk, the title from the cart chunk will appear instead. + * Fixed a bug whereby exiting (using an HPI device) 'qwav' while + audio was playing would cause audio to continue to play out for + up to several seconds after temination, and result in incorrect + level meter reading upon next program startup. +2002-7-21 Fred Gleason + * Added Mext chunk support to 'qwav'. +2002-7-23 Fred Gleason + * Renamed 'qwav.h' to 'rdplay.h'. + * Renamed 'qwav.cpp' to 'rdplay.cpp'. + * Added 'rdrecord.cpp' and 'rdrecord.h', a record application. +2002-7-25 Fred Gleason + * Fixed a bug in 'rdplay.cpp' that was causing the 'Format' button + to display incorrect information on the MPEG Mode and MPEG Flags + fields. + * Fixed formatting of various fields in the 'Cart' button dialog + box. +2002-7-26 Fred Gleason + * Worked on button logic in 'rdrecord' to make it more like a + "real" recorder. +2002-7-29 Fred Gleason + * Added format settings controls to the front panel of 'rdrecord'. + * Added a 'Meta Data' button to 'rdrecord' to bring up a dialog + box to enter meta data info. +2002-7-30 Fred Gleason + * Finished adding meta-data write support to RDRecord. +2002-8-1 Fred Gleason + * Disabled ALSA support in 'configure.in' and 'Makefile.am' + * Added a 'utils' directory for utility programs. + * Imported 'RDPlay' and RDRecord' from the 'sndtools' package. + * Updated NEWS, INSTALL and README for release. + * Changed the version number in 'configure.in' to 0.1.0. + * Imported the ChangeLog from 'sndtools' into this file so as to + preserve the development history for RDRecord and RDPlay. + * Released v0.1.0. +2002-8-2 Fred Gleason + * Added a 'docs' directory for documentation. + * Added 'cart_schema.txt' in the 'docs' directory, describing the + layout of the CART and CUTS tables. +2002-8-3 Fred Gleason + * Added 'cae.h', 'cae.cpp', 'cae_socket.h' and 'cae_socket.cpp', + the beginnings of a new C++ based CAE implementation. +2002-8-6 Fred Gleason + * Implemented the Drop Connection (DC) command in 'cae.cpp'. + * Implemented the Password Authenticate (PW) command in 'cae.cpp'. + * Implemented the Load Playback (LP) command in 'cae.cpp'. + * Implemented the Unload Playback (UP) command in 'cae.cpp'. + * Implemented the Play Position (PP) command in 'cae.cpp'. + * Implemented the Play (PY) command in 'cae.cpp'. + * Implemented the Stop Playback (SP) command in 'cae.cpp'. + * Deleted 'main.c', 'init.c', 'alsa.c', 'conflib.c', conflib.h', + 'globals.c', 'globals.h', 'wavhdr.c' and 'wavhdr.h' from the + 'cae/' directory. All from the (now defunct) C implementation of + CAE. + * Implemented the Load Record (LR) command in 'cae.cpp'. + * Implemented the Unload Record (UR) command in 'cae.cpp'. + * Implemented the Record (RD) command in 'cae.cpp'. + * Implemented the Stop Record (SR) command in 'cae.cpp'. +2002-8-7 Fred Gleason + * Implemented the Record Start (RS) status update in 'cae.cpp' + * Fixed various bugs in 'cae.cpp' to make things work. + * Implemented the and fields in the + Play (PY) command in 'cae.cpp'. The parser demands them, but + they currently do nothing. +2002-8-8 Fred Gleason + * Created a 'docs/tables/' subdirectory to hold database table + layouts. + * Moved 'docs/cart_schema.txt' to 'docs/table/cart.txt' and split + off the CUTS data in it to 'docs/table/cuts.txt' + * Created 'docs/table/users.txt' to document the USERS table. + * Created 'docs/table/services.txt' to document the SERVICES + table. +2002-8-9 Fred Gleason + * Fixed a bug that was causing CAE to segfault when sent a + 'DC!' command while playing a file. + * Implemented the argument to the Play (PY) command, + as specified in CAE Protocol Spec 0.5. + * Implemented the revised speed units (tenths of percent) for + the argument to the Play (PY) command, in corformance + to CAE Protocol Spec 0.5. + * Added a 'AllowNonstandardRates=Yes|No' diretive to 'cae.conf'. +2002-8-19 Fred Gleason + * Added a check at the startup of 'cae' that will exit with an + error if unable to bind the configured TCP socket. + * Increased the maximum number of TCP connections to 'cae' to 32 + and streamlined the signal/slot mechanism for handling them. +2002-8-21 Fred Gleason + * Added a GPL comment header to 'rdplay.h'. +2002-9-27 Fred Gleason + * Added an 'rdadmin' directory. + * Added 'rdadmin.cpp' and 'rdadmin.h'. + * Added 'conf/rd.conf-sample'. +2002-9-30 Fred Gleason + * Added 'rdadmin/login.h' and 'rdadmin/login.cpp' + * Added 'rdadmin/list_users.h' and rdadmin/list_users.cpp'. +2002-10-01 Fred Gleason + * Fixed a bug in RDRecord that was causing a MEXT chunk to be + generated on all files, even, non-MPEG ones. + * Added 'rdadmin/list_users.cpp' and 'rdadmin/list_user.h'. + * Added 'rdadmin/edit_user.cpp' and 'rdadmin/edit_user.h'. +2002-10-02 Fred Gleason + * Added 'lib/rdpasswd.cpp' and 'lib/rdpasswd.h', a password + entry widget. + * Finished User Management support in RDAdmin. +2002-10-03 Fred Gleason + * Added 'ripcd/ripcd.cpp', 'ripcd/ripcd.h', + ripcd/ripcd_socket.cpp' and 'ripcd/ripcd_socket.h', the Rivendell + Interprocess Communication daemon. +2002-10-07 Fred Gleason + * Added 'lib/ripc.cpp' and 'lib/ripc.h', a class for communicating + with ripcd. + * Added RDLogin, a login application. + * Added CUTS and CART table creation to 'scripts/create_db'. + * Added RDLibrary, a cart library manager. Still lots of work + to do! + * Changed the font sizes in RDLogin to bring them into conformance + with the "standard" sizes. +2002-10-08 Fred Gleason + * Fixed a bug in ripcd that was causing it to fail to start when + unable to get a connection to an X server. + * Added SERVICES table creation to 'scripts/create_db'. + * Stubbed out Services management in RDAdmin. +2002-10-09 Fred Gleason + * Completed Services management in RDAdmin. + * Renamed the CART_NUMBER record in CART to NUMBER. +2002-10-10 Fred Gleason + * Completed the 'RDCart' class. + * Started work on the 'RDEditCart' class. + * Started a redesign of the audio permissions scheme to assign + permissions by group rather than by each individual cut. + * Added a GROUPS table. + * Added a AUDIO_PERMS table. + * Removed the SERVICES_* fields from the CART table. + * Added a 'RDGroup' class. Still lots of work to be done. + * Started adding Group Administration support to RDAdmin. +2002-10-17 Fred Gleason + * Removed the ID field from the GROUPS table. + * Completed the 'RDGroups' class. + * Removed the ID field from the SERVICES table. + * Rewrote the 'RDService' class to use synchronous DB updates. + * Rewrote the 'RDUser' class to use synchronous DB updates. + * Rewrote RDAdmin to use the new container classes and DB + structure. +2002-10-18 Fred Gleason + * Completed Group support in RDAdmin. + * Completed preliminary Cart Add/Edit/Delete support in RDLibrary. +2002-10-21 Fred Gleason + * More work on RDLibrary. +2002-10-22 Fred Gleason + * Moved 'RDEditCart' from 'lib/' to 'rdlibrary/'. + * Renamed table DISPLAYS to STATIONS. +2002-10-25 Fred Gleason + * Added a default entry for the 'STATIONS' table in + 'scripts/create_db'. + * Modified 'ripcd' to use the new 'STATIONS' table. + * Modified 'RDLogin' to use the new 'STATIONS' table. + * Modified 'RDAdmin' to use the new 'STATIONS' table. + * Started work on configuration support for RDLibrary in RDAdmin. +2002-10-28 Fred Gleason + * Completed configuration support for RDLibrary in RDAdmin. +2002-10-29 Fred Gleason + * Started work on the Record widget for RDLibrary. + * Renamed 'cae' to 'caed'. + * Changed 'caed' to detach upon startup, unless the '-d' option + is specified. +2002-10-30 Fred Gleason + * Fixed a bug in 'caed' that was causing it to fail at startup + with a 'cannot connect to X server' message. + * Removed parameter defaults from function headers. Needed to get + things to compile under gcc 3.2. + * Added a 'RDCae' class, to abstract a connection to 'caed'. + * More work on the Record Machine in RDLibrary. +2002-10-31 Fred Gleason + * More work on the Record Machine in RDLibrary. +2002-11-04 Fred Gleason + * Completed basic functionality in the Record Machine in + RDLibrary. +2002-11-07 Fred Gleason + * Added destructors to most classes. + * Changed 'caed' to work with the revised 'RSoundCard' class. + * Changed 'rdplay' to work with the revised 'RSoundCard' class. + * Changed 'rdrecord' to work with the revised 'RSoundCard' class. + * Changed 'rdlibrary' to work with the revised 'RSoundCard' class. +2002-11-18 Fred Gleason + * Added AES/EBU support to RDLibrary. + * Added AES/EBU Sync Error Alarm to RDLibrary's Cut Recorder. +2002-11-24 Fred Gleason + * Updated the CAE spec to 0.6. Changed the meaning of the 'layer' + parameter in 'LR' so that 1 = Layer 2 and 2 = Layer 3. + * Changed 'caed' to use the revised spec. + * Changed 'rdlibrary' to use the revised spec. + * Fixed a bug in 'caed' that was causing a segfault upon execution + of a 'UP' command. + * Fixed various bugs in RDLibrary. +2002-11-25 Fred Gleason + * Added an audio editor widget to 'RDLibrary'. Still very + preliminary, lots of work/debugging remains! +2002-12-02 Fred Gleason + * Worked on 'edit_audio.cpp'. +2002-12-03 Fred Gleason + * More work on 'edit_audio.cpp'. Basic waveform display, panning + and scaling now working for PCM16 and MPEG-1 L2 files (with BWF + energy data). +2002-12-04 Fred Gleason + * Rewrite of 'RDLibrary'. HPI_HSUBSYS, RSoundCard and + RDLibraryConf are all now global resources. + * More work on 'edit_audio.cpp'. Audio playout now works. + Playback cursor updates work, but consume insane amounts of CPU. + Lots more work needed. +2002-12-05 Fred Gleason + * Fixed excessive CPU utilization problem in 'edit_audio.cpp'. + * Starting work on cuepoint cursors in 'edit_audio.cpp'. +2002-12-11 Fred Gleason + * More work on 'edit_audio.cpp'. +2002-12-16 Fred Gleason + * Added the TRIGGERS table. + * Brought the table documentation in 'docs/tables' up to date. + * Changed RDCut to be in conformance with new table structure. + * Move work on 'edit_audio.cpp'. +2002-12-17 Fred Gleason + * Added TALK_START_POINT and TALK_END_POINT fields to the CUTS + table. + * Added appropriate methods to 'RDCut' to access TALK_START_POINT + and TALK_END_POINT. + * Lots more work on 'edit_audio.cpp'. Cursors now all work. + Still more work needed. +2002-12-18 Fred Gleason + * Changed the mouse button bindings in 'edit_audio.cpp' so that + Left=position playback cursor, Middle=position selected + meta-cursor. + * Added SEGUE_START_POINT and SEGUE_END_POINT fields to the 'CUTS' + table. + * Added appropriate methods to 'RDCut' to access SEGUE_START_POINT + and SEGUE_END_POINT. + * More work on 'edit_audio.cpp'. +2002-12-20 Fred Gleason + * Changed the cue point fields in the CUTS table to use signed + ints. + * Rearranged the user interface in 'edit_audio.cpp'. +2002-12-23 Fred Gleason + * More work on 'edit_audio.cpp'. +2002-12-24 Fred Gleason + * More work on 'edit_audio.cpp'. Got the counters mostly working, + all play modes work. +2002-12-29 Fred Gleason + * Completed 'edit_audio.cpp'. All functions work. +2002-12-30 Fred Gleason + * Added 'VOX_THRESHOLD', 'TRIM_THRESHOLD', 'RECORD_GPI', + 'PLAY_GPI', 'STOP_GPI', 'DEFAULT_RECORD_MODE' and + 'DEFAULT_TRIM_STATE' fields to the RDLIBRARY table, along with + appropriate accessor methods in 'RDLibraryConf'. + * Added 'WEIGHT' field to the CUTS table, along with appropriate + accessors methods in 'RDCut'. +2002-12-31 Fred Gleason + * Added the new configuration parameters to the RDLibrary module + in RDAdmin. +2003-01-03 Fred Gleason + * Added VOX and AutoTrim support to the Recorder in RDLibrary. + * Fixed a bug in 'RDCae' that was causing random crashes. + * Added a 'CLIPBOARD' table, for storing cut data in the audio + clipboard. + * Added 'toClipboard()' and 'fromClipboard()' methods to 'RDCut'. +2003-01-06 Fred Gleason + * Added clipboard support to RDLibrary. +2003-01-08 Fred Gleason + * Rearranged the order of the play buttons in 'edit_audio.cpp'. + * Changed the region play button so as to take it's accent color + from the currently selected marker color. + * Rearranged the position counters in 'edit_audio.cpp'. + * Swaped the mouse button bindings between Left and Center. + * Added 'START_DATE', 'END_DATE', 'START_DAYPART' and + 'END_DAYPART' fields to the CUTS table, along with appropriate + accessor methods in 'RDCut'. + * Fixed a bug in 'EditRDLibrary' that was causing 'setInputType()' + to write incorrect values into the database. +2003-01-10 Fred Gleason + * Calibrated RDLibrary, RDPlay and RDRecord to use -16 dBFS as + "reference" level. + * Added a level meter to the audio editor in RDLibrary. + * Added lines to the waveform display in RDLibrary's audio editor + to indicate reference level. + * Added 'PLAY_GAIN' field to the 'CUTS' table, along with + appropriate accessor methods in 'RDCut'. + * Added the ability to set the playout gain in the audio editor in + RDLibrary. + * Fixed a bug in the audio editor in RDLibrary that was clipping + the marker arrows when placed at the extreme edges of the waveform + area. + * Added the ability to drag markers in the audio editor in + RDLibrary. +2003-01-13 Fred Gleason + * Changed the marker buttons in RDLibrary's audio editor as + follows: Start >> Cut Start, End >> Cut End, Seg Start >> Segue + Start, Seg End >> Segue End. + * Changed the Region counter label in RDLibrary's audio editor to + reflect the currently selected region. + * Fixed a bug in RDLibrary's audio editor where it was possible to + place a tail marker before it's coresponding head marker. + * Changed RDLibrary's audio editor so that placing a marker will + also place it's complimentary marker at the start/end of the audio + if it does not already exist. + * Removed the ability to remove Cut Start/End markers from the + right-click menu in RDLibrary's audio editor. + * Changed the right-click menu in RDLibrary's audio editor so that + the Talk, Segue and Hook markers can only be deleted in pairs. + * Changed the Talk marker color in RDLibrary's audio editor to + dark yellow. + * Changed the play gain control in RDLibrary's audio editor from a + slider to a large spin box. + * Added head and tail trim buttons to RDLibrary's audio editor, + along with settable thresholds. + * Changed the RDLibrary's audio editor so that the play cursor now + moves automatically to the position of a newly-moved head marker. +2003-01-14 Fred Gleason + * Added typomatic auto-repeat to the Cut Gain buttons in + RDLibrary's audio editor. + * Fixed a bug in RDLibrary's audio editor where placing a TalkEnd + marker would reposition an existing TalkStart marker to the + beginning of the audio cut. + * Fixed a bug in RDLibrary's audio editor where the FadeUp marker + could be positioned after the FadeDown marker, and vice-versa. + * Added 'effectiveStart()' and 'effectiveEnd()' methods to + 'RDCut'. + * Changed RDLibrary's audio editor so that placing a new marker + for the first time will cause it's opposite marker to be placed at + the Start or End marker position, rather than at the absolute + start or end of the audio. + * Fixed a bug in RDLibrary's audio editor that was causing the + incorrect mouse cursor to be displayed in certain areas of the + screen. + * Changed the zoom behavior in RDLibrary's audio editor so that + the playback cursor will always be visible on screen following a + zoom. + * Changed the label on the 'Hook Start' marker button from 'Hook + Strt' to 'Hook Start'. +2003-01-15 Fred Gleason + * Removed the direct HPI dependencies from all code, as part of + preparations for proper ALSA support. All driver dependencies are + now confined to 'libradio'. +2003-01-16 Fred Gleason + * Fixed the Autoconf configuration so as to autodetect and build + both HPI and ALSA support properly. +2003-01-20 Fred Gleason + * Added 'RDGpo', a utility program to test general purpose output + (GPO) devices. + * Added 'RDGpi', a utility program to test general purpose input + (GPI) devices. + * Added 'docs/GPIO.txt', a note on configuring and testing GPIO + devices. +2003-01-21 Fred Gleason + * Added 'GS', 'GI' and 'GO' commands to 'caed', in complaiance + with Core Engine Protocol v0.6. + * Added card usage notes and pinout data to 'docs/GPIO.txt'. + * Added methods for GPIO support to 'RDCae'. +2003-01-21 Fred Gleason + * Added 'start_rd' and 'kill_rd' scripts, for automatically + starting and terminating Rivendell system daemons. + * Added pid logging to 'caed' and 'ripcd'. + * Added 'rdgen' in 'utils/', a program for generating arbitrary + tones in WAV files. Adapted from 'wavgen' in 'wavlib-2.4.2'. + * Renamed 'create_db' as 'rd_create_db'. + * Fixed a bug in 'edit_audio.cpp' that was causing the widget + sometimes to default to 'Loop' mode upon startup without any + indication on the Loop button. + * Fixed a bug in 'edit_audio.cpp' that was causing audio playout + to continue even after exiting the widget. + * Fixed a bug in 'edit_audio.cpp' where repositioning the playback + cursor while playing was generating a spurious pause. + * Changed the behavior of RDLibrary's audio editor so that placing + a tail marker will reposition the play cursor to three seconds + before the tail marker location, or at the corresponding head + marker, if that is close than three seconds before. + * Decreased the default zoom gain in RDLibrary's audio editor by 3 + dB. + * Fixed a bug in 'edit_audio.cpp' that was causing markers to be + displayed even if they were not active. + * Renamed the 'Tail Trim' and 'Head Trim' buttons in RDLibrary's + audio editor to 'Start Trim' and 'End Trim'. + * Renamed the 'Record' button in RDLibrary's cart editor to + 'Record/Label'. + * Changed the font size of the cut buttons in RDLibrary's cart + editor from 16 to 14 point. +2003-01-24 Fred Gleason + * Added some SuSE-specific advice regarding proper placement of + the 'start_rd' script in 'inittab'. + * Fixed a bug in 'edit_audio.cpp' whereby the region length was + being inserted into the overall length counter. + * Fixed a bug in 'edit_audio.cpp' whereby moving the cursors would + corrupt the reference level line display. + * Changed RDLibrary's audio edtiro so that the marker counters' + contents are highlighted when it's coressponding button is depressed. + * Changed RDLibrary's audio editor so that it's possible to + de-select a marker button. With no marker selected, a left mouse + click will now position the playback cursor. + * Fixed a bug in 'edit_audio.cpp' that was causing the 'Hook' + color and label to show up in the region size counter when the + 'Fade Up' button was selected. + * Added a 'Remove Marker' button to RDLibrary's audio editor. + When depressed, pressing one of the marker buttons will delete the + corresponding pair of markers. +2003-01-27 Fred Gleason + * Changed RDLibrary's audio editor so that Cursor Play will stop + at a given marker if one of it's corresponding buttons is + selected. + * Changed RDLibrary's audio editor so that selecting a start + marker button will resposition to play cursor to that marker. + * Changed RDLibrary's audio editor so that selecting an end marker + will reposition the play cursor to three seconds before that + marker, or at it's corresponding start marker, whichever is + closer. + * Removed the Region Play button from RDLibrary's audio editor. + * Relabeled the Stop button as the Pause in RDLibrary's audio + editor. + * Added a Stop button to RDLibrary's audio editor that causes the + playback cursor to be respositioned to it position when one of the + play buttons was activated. + * Changed the key bindings in RDLibrary's audio editor so that the + space bat toggles between Cursor Play and Stop. + * Changed the level range of the playback meter in RDLibrary's + audio editor to be -36 dbFS to -8 dbFS (-20 to +8). + * Fixed a bug in 'edit_audio.cpp' that was causing nonsense values + to appear in the Region counter of RDLibrary's audio editor when + no marker buttons were selected. +2003-02-03 Fred Gleason + * Fixed a bug in the Autoconf configuration that was causing Qt's + Meta Object Compiler (moc) files to be included in distribution + tarballs. +2003-02-05 Fred Gleason + * Began implementing the 'Frankeneditor' layout in RDLibrary's + audio editor. +2003-02-10 Fred Gleason + * Finished implementing the 'Frankeneditor' layout in RDLibrary's + audio editor. + * Added the ability to enter marker positions by typing into the + counter widgets in RDLibrary's audio editor. +2003-02-12 Fred Gleason + * Fixed a bug in 'edit_audio.cpp' that was causing the current + counter readout to lose it's highlighting after a manual data + entry. + * Disabled drag and drop capability in the counters in RDLibrary's + audio editor. + * Changed the parser for the marker counters so as to allow + various shorthand forms of time value entries to work. + * Fixed a bug in 'edit_audio.cpp' that was causing the marker + counters to fail to revert to the previous value if an "out of + bounds" value was keyed in manually. + * Fixed a bug in 'edit_audio.cpp' that was allowing markers to be + placed outside of the Start and End markers. + * Changed the colors for the Fade, Talk and Segue markers in + RDLibrary's audio editor to yellow, blue and cyan, respectively. +2003-02-12 Fred Gleason + * Fixed a bug in 'edit_audio.cpp' that was causing the marker + readout for FadeUp and FadeDown to appear in the wrong position. + * Added a 'Goto' button section to RDLibrary's audio editor, with + 'Cursor', 'Home' and 'End' buttons. + * Fixed a bug in 'edit_audio.cpp' that was preventing Start + markers from being moved to the left and End markers from being + moved to the right. + * Added a 'TAIL_PREROLL' field to the 'RD_LIBRARY' table, along + with appropriate accessor methods in 'RDLibraryConf'. + * Added a 'Tail Preroll' spinbox in the RDLibrary configuration + screen in 'RDAdmin'. + * Modified RDLibrary's audio editor so as to use the + 'TAIL_PREROLL' field value to determine the distance to offset the + play cursor when placing a tail marker. + * Fixed a bug in 'edit_audio.cpp' whereby the Remove Marker + buttono was not being fully reset after pressing a marker button + when in 'Remove' mode. + * Added a 'MarkerButton' class as part of RDLibrary. + * Fixed a bug in 'edit_audio.cpp' that was causing the space bar + to fail to toggle audio playback after operation of a marker + buttons. + * Fixed a bug in 'edit_audio.cpp' that was causing spurious end + markers to be generated when deselecting a start marker button + with no marker placed. +2003-02-18 Fred Gleason + * Changed the behavior of the 'Goto Cursor' button in RDLibrary's + audio editor so as to center the cursor in the waveform display. + * Reworked the layout of Start/End Date and Daypart fields in + RDLibrary's audio recorder. +2003-02-19 Fred Gleason + * Fixed a bug in 'edit_audio.cpp' whereby it was possible to place + the End marker beyond the end of the actual audio. + * Fixed a bug in 'edit_audio.cpp' that had broken looping mode. + * Added a feature whereby the space to the right of the end of the + audio in RDLibrary's audio editor is greyed out. + * Fixed a bug in 'edit_audio.cpp' that was causing a the marker + time field to blank out after it's associated marker button was + deselected. + * Hacked 'edit_audio.cpp' to make the left and right waveforms + appear to align. Still not really convinced that we have this + right. + * Changed RDLibrary's 'MarkerButton' base class from + 'QPushButton' to 'RPushButton'. + * Changed RDLibrary's audio editor so as to make the marker + buttons flash to indicate an active selection. + * Added key bindings for 'Home', 'End' and 'Delete' to RDLibrary's + audio editor. +2003-02-21 Fred Gleason + * Added 'rdlibrary/marker_edit.h' and 'rdlibrary/marker_edit.cpp'. + * Fixed a bug in 'edit_audio.cpp' that was causing the spacebar + to clear the value of a selected marker. + * Fixed a bug in 'edit_audio.cpp' that was causing the marker + arrow positions to fail to update when outside the main frame of + the waveform window. + * Added sanity checks to RDLibrary's audio editor to prevent any + other markers from being present before the Start or after the End + marker. +2003-02-24 Fred Gleason + * Added default values to the 'START_DATE', 'END_DATE', + 'START_DAYPART' and 'END_DAYPART' fields in the 'CUTS' table. + * Removed the 'airDateValid()' and 'daypartValid()' methods from + 'RDCut'. + * Added default value for the 'ORIGIN_DATETIME' field in the + 'CUTS' table. + * Added read-only 'Origin', 'Last Played' and '# of Plays' + controls to RDLibrary's recorder. + * Added a 'Weight' control to RDLibrary's recorder. + * Added a horizontal divider line to the 'Record/Label' and + 'Import/Export' buttons in RDLibrary's cart editor. + * Hid the 'Import/Export' and 'Rip' buttons in RDLibrary's cart + editor. + * Changed RDLibrary's recorder so to use the symbolic workstation + name (as set in RDAdmin) for the origin name, instead of the raw + hostname/display pair. + * Combined the 'ORIGIN_DATETIME' and 'ORIGIN_NAME' fields into one + column in RDLibrary's cart editor cut list. + * Added the 'START_DATE', 'END_DATE', 'START_DAYPART' and + 'END_DAYPART' fields to RDLibrary's cart editor cut list. + * Added accessor methods for 'GROUP_NAME' to 'RDCart'. + * Added a 'Group' control to RDLibrary's cart editor. + * Implemented simple filtering in RDLibrary. + * Added indices for 'ALBUM', 'LABEL' and 'USER_DEFINED' fields in + the 'CART' table. +2003-02-25 Fred Gleason + * Changed the 'START_DATE' and 'END_DATE' fields in the 'CUTS' + table to 'START_DATETIME' and 'END_DATETIME', and updated data + type and accessor methods accordingly. + * Updated RDLibrary's recorder to use the new 'START_DATETIME' and + 'END_DATETIME' fields. + * Fixed a bug in 'marker_edit.cpp' where the 'Home' and 'End' keys + were being processed by the widget instead of being passed + through. + * Changed the behavior of RDLibrary's audio editor so that + positioning of a Start or End marker that leaves a FadeUp or + FadeDown marker outside the active range deletes said marker + instead of relocating it. + * Fixed a bug in 'edit_audio.cpp' where the Region counter was + failing to display the segment time when the FadeUp marker was + selected. + * Disabled drag and drop on the cursor position, autotrim + threshold and cut gain readouts. + * Changed RDLibrary's audio editor so as to make it possible to + manually enter the Cut Gain value using the keyboard. + * Changed the Play cursor in RDLibrary's audio editor to display + reverse color over the waveform. + * Changed the behavior of Play From Cursor mode in RDLibrary's + audio editor so that playback always stops at the End marker. + * Created layouts for 'RECORDINGS', 'DECKS' and 'TTYS' tables in + 'docs/tables/'. + * Added code to create the 'TTYS' table in 'rd_create_db'. + * Added a 'RDTty' class in 'lib/'. + * Added code to create the 'DECKS' table in 'rd_create_db'. + * Added a 'RDDeck' class in 'lib/'. +2003-02-26 Fred Gleason + * Added a 'Configure TTYs' module to RDAdmin->ManageStations. + * Added 'SWITCH_TYPE' and 'TTY_ID' fields to the 'DECKS' table. + * Added a 'Configure RDCatch' module to RDAdmin->ManageStations. + Still a WIP. +2003-02-27 Fred Gleason + * Added an 'EditDecks' class in 'rdadmin'. + * Removed 'Configure' from the configuration button legends in + RDAdmin->Stations. + * Renamed 'TTYs' to 'Serial Ports' in RDAdmin->Stations. + * Created a layout for the 'SOURCES' table in 'docs/tables/'. + * Added code to create the 'SOURCES' table in 'rd_create_db'. + * Added an 'RDSource' class in 'lib/'. + * Added an 'EditSources' class in 'rdadmin/'. + * Added an 'AddSource' class in 'rdadmin/'. + * Added an 'EditSource' class in 'rdadmin/'. + * Completed the 'RDCatch' module in RDAdmin->ManageStations. + * Added code to create the 'RECORDINGS' table in 'rd_create_db'. + * Added an 'RDRecording' class in 'lib/'. + * Stubbed out 'RDCatch' in 'rdcatch/'. +2003-02-28 Fred Gleason + * Added 'STARTDATE_OFFSET' and 'ENDDATE_OFFSET' fields to the + 'RECORDINGS' table, along with appropriate accessor methods. + * Added an 'AddRecording' class in 'rdcatch/'. + * Changed 'RDRecording' to use the 'START_DATE' field as a key + value, rather than 'CUT_NAME'. + * Added an 'EditRecording' class in 'rdcatch/'. + * Removed 'START_TYPE' and 'END_TYPE' fields from the 'RECORDINGS' + table, along with appropriate accessor methods. + * Changed the type of 'GPI_START' and 'GPI_END' fields in the + 'RECORDINGS' table to signed integer, and changed appropriate + accessor methods. +2003-03-02 Fred Gleason + * Changed the Day of the Week fields in RDCatch to display the day + of the week abbreviations, rather than 'Yes' or 'No'. +2003-03-03 Fred Gleason + * Implemented the Head/Tail Audition buttons in RDCatch. + * Added 'PORT_TYPE', 'DEFAULT_FORMAT', 'DEFAULT_CHANNELS', + 'DEFAULT_SAMPRATE', 'DEFAULT_BITRATE' and 'DEFAULT_THRESHOLD' + fields to the 'DECKS' table, along with appropriate accessor + methods. + * Added support for the new 'DECKS' fields to RDCatch module in + RDAdmin->ManageStations. + * Added 'FORMAT', 'CHANNELS', 'SAMPRATE' and 'BITRATE' fields to + the 'RECORDINGS' table, along with appropriate accessor methods. + * Moved the 'Settings' class from 'rdlibrary/' to 'lib/', and + renamed it 'RDSettings'. + * Moved the 'EditSettings' class from 'rdlibrary/' to 'lib/', and + renamed it 'RDEditSettings'. + * Modified RDCatch to make use of the new 'RECORDINGS' fields. +2003-03-04 Fred Gleason + * Fixed a bug in 'rdcatch.cpp' that was throwing a database error + upon startup. + * Created directory 'rdcatchd/'. + * Stubbed out RDCatchd in 'rdcatchd/'. + * Added a 'CatchConnect' class in 'rdcatch/'. + * Basic RDCatchd functions now working. +2003-03-05 Fred Gleason + * Added a 'RDTtyOut()' function in 'lib/'. + * Implemented switcher control in RDCatchd. + * Imported the CAE protocol spec as 'docs/cae.sxw'. + * Added and arguments to the 'RD' command + in the Core AudioEngine spec. Upped the spec version to 0.7. + * Implemented the and arguments in 'caed'. + * Added additional arguments for Start and End GPI in the + 'startRecord()' method in 'RDCae'. + * Implemented Start and End GPI in 'rdcatchd'. +2003-03-06 Fred Gleason + * Fixed a bug in 'caed' that was causing a segfault at startup + when used with no GPIO card. +2003-03-07 Fred Gleason + * Created a layout for the 'AUDIO_PORTS' table in + 'docs/tables/audio_ports.txt'. + * Added a 'RDAudioPort' class in 'lib/'. + * Added an 'Audio Ports' configuration module to + RDAdmin->EditStations. + * Removed the 'Input Type' control from the RDLibrary + configuration module in RDAdmin. + * Removed the 'Input Type' control from the RDCatch + configuration module in RDAdmin. + * Removed the 'portType()' and 'setPortType()' methods from + 'RDDeck'. + * Removed the 'inputType()' and 'setInputType()' methods from + 'RDLibraryConf'. + * Reworked RDLibrary to use the new input port type and level + assignments. + * Reworked RDCatch to use the new input port type and level + assignments. +2003-03-08 Fred Gleason + * Fixed a bug in 'rdlibrary.cpp' that was causing the build to + break. +2003-03-10 Fred Gleason + * Added 'lib/rdmixer.cpp', a container for various mixer + functions. + * Added a 'RDSetPorts()' function to 'RDMixer'. + * Removed the 'DISPLAY' field from the 'STATIONS' table. + * Modified 'RDStation' to reflect the updated 'STATIONS' table + structure. + * Modified RDAdmin's Station modules to use the updated 'STATIONS' + table structure. + * Modified the RIPC spec in 'docs/ripc.txt' to remove the + '' attribute. + * Modified 'ripcd' to use the updated 'STATIONS' table structure + and RIPC spec. + * Modified 'RDRipc' to use the updated 'STATIONS' table structure + and RIPC spec. + * Deleted 'conf/cae.conf'. + * Updated 'conf/rd.conf-sample' to include just the commonly needed + configuration options. + * Created 'conf/rd.conf-full-sample', a complete listing of + available configuration options. + * Fixed a bug in 'RDCatch' that was allow duplicate recordings to + be created. +2003-03-11 Fred Gleason + * Added code to 'RDCatchd' to relinguish root permissions after + startup. + * Added a 'DeckMon' class to 'rdcatch/'. + * Added 'docs/catchd.txt', documenting the IPC protocol for + real-time netcatcher monitoring. + * Added real-time monitoring capability to RDCatch. Still rather + buggy and unstable, and the meters don't work (yet). +2003-03-12 Fred Gleason + * Added sanity checks to RDCatch to prevent creation of recording + entries without a length or destination cut. + * Fixed a bug in 'rdadmin/edit_decks.cpp' that was causing + incorrect values to be written to the database for Default + Threshold'. + * Fixed a bug in 'rdcatch/edit_recording.cpp' where the Threshold + Trim value was not being read properly. + * Added level monitoring support to RDCatchd and CatchConnect. + * Real-time metering now works in RDCatch. + * Added an 'RDCutPath' function in 'lib/'. +2003-03-13 Fred Gleason + * Added an 'RDCutDialog' widget in 'lib/'. + * Added an 'RDCartSearchText()' function in 'lib/'. + * Modified RDLibrary to use 'RDCartSearchText()' for cart + filtering. + * Rearranged the layout of the RDCatch->EditRecordings dialog box. + * Added an 'EDIT_CATCHES_PRIV' field to the 'USERS' table, along + with appropriate accessor methods. + * Fixed a bug in 'lib/rduser.cpp' that was causing read/write of + the 'USERS.ASSIGN_CART_PRIV' field to fail. + * Added support to RDAdmin->EditUsers for the Edit Netcatch + Schedule user attribute. + * Updated RDAdmin to make consistent use of QCheckBox widgets. + * Added user attribute support to RDCatch. + * Fixed a bug in 'rdcatch/deckmon.cpp' where the level meters were + not returning to zero at the conclusion of a recording. + * Fixed a bug in 'lib/rdcut.cpp' that was causing the value for + Cut End Date/Time to fail to be updated. + * Implemented Start/End Date Offsets in RDCatchd. + * Added RDCatchd to the automated daemon management system in + 'scripts/start_rd' and 'scripts/kill_rd'. + * Fixed a bug that was generating a compiler warning in + 'utils/metadialog.cpp'. + * Fixed a bug that was generating a compiler warning in + 'utils/wavlib.c'. + * Fixed a bug that generating a moc warning in + 'rdlibrary/Makefile.am'. + * Added code to 'scripts/rd_create_db' to generate the 'LOGS' + table. + * Added 'docs/tables/log_format.txt', documenting the layout of a + schedule log. +2003-03-14 Fred Gleason + * Fixed a bug in 'rdadmin/edit_audios.cpp' that was causing the + incorrect analog port levels to be generated in the database. + * Fixed up the appearance of the 'Record|Label' button in + RDLibrary->EditCart. + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was causing second and + later decks in the monitoring area to fail to update status + properly. + * Changed the column alignment to right justified for the 'Length' + field in RDCatch. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' where a start/end date + offset was being applied to a recording even when start/end date + tracking was disabled for the cut. +2003-03-18 Fred Gleason + * Fixed a bug in 'rdadmin/list_stations.cpp' that was causing the + upper-left corner of the station list to be slightly overwritten. + * Fixed a bug in 'rdadmin/list_stations.cpp' where deleting a + workstation failed to delete associated netcatcher configuration. + * Added 'RDSetMixerOutputPort()' function in 'lib/rdmixer.cpp'. + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' where the output audio + assignment was being set up incorrectly. + * Fixed a bug in 'rdcatch/rdcatch.cpp' where the output audio + assignment was being set up incorrectly. + * Added code to 'scripts/rd_create_db' to allow upgrade of an + existing database in place. +2003-03-19 Fred Gleason + * Stubbed out RDLogEdit in 'rdlogedit/', a log editor utility. + * Renamed the 'LOGS.OWNER' field to 'LOGS.SERVICE'. + * Added code to 'scripts/rd_create_db' to generate a sample log + when creating a new database. + * Removed 'LOGS.START_DATETIME' and 'LOGS.END_DATETIME' fields. + * Added 'LOGS.START_DATE' and 'LOGS.END_DATE' fields. + * Added an 'RDLog' class in 'lib/rdlog.cpp'. + * Added an 'AddLog' class in 'rdlogedit/add_log.cpp'. + * Added an 'EditLog' class in 'rdlogedit/edit_log.cpp'. + * Added an 'RDLogEvent' class in 'lib/rdlog_event.cpp'. +2003-03-21 Fred Gleason + * Removed the 'PREV_ID' and 'NEXT_ID' fields from the log table + format. + * Added a 'COUNTER' field to the log table format. + * Added an 'RDLogLine' class in 'lib/rdlog_line.cpp'. + * Added an 'RDCreateLog' function in 'lib/rdcreate_log.cpp'. +2003-04-23 Fred Gleason + * Changed 'RDLogEvents' to use the STL for object management. + * Added a 'EditLogLine' class in 'rdlogedit/edit_logline.cpp'. +2003-04-29 Fred Gleason + * Removed the 'COUNTER' field from the log table format. + * Created a 'RDCartDialog' class in 'lib/rdcart_dialog'. +2003-05-08 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp' where starting the program + over a remote X11 link would hang without ever getting a main + window. +2003-05-12 Fred Gleason + * Reworked 'RDRecording' to take the ID value as it's constructor + argument, rather than WORKSTATION,CHANNEL and START_TIME. + * Overhauled 'RDCatch' to allow the Station and Start Time to be + altered for a record event after the event is created. + * Added additional sanity checks for record events in 'RDCatch'. + * Added code to 'rdcatch/rdcatch.cpp' to keep the Record List from + jumping back to the first event in the list after adding or + editing an entry. +2003-05-12 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp' where the Record List would + jump back to the top after adding or editing an entry. + * Fixed a bug in 'rdcatch/edit_recording.cpp' where the correct + station name was not being loaded into the Station selector. + * Fixed a bug in 'rdcatch/edit_recording.cpp' where the list of + available record sources would be blank after creating a new + record event. + * Changed the behavior of 'RDCatch' so that a new record event + defaults to the first available audio source, rther than no source + at all. +2003-05-13 Fred Gleason + * Added an 'RDRipper' class in 'lib/rdripper.cpp'. + * Added 'RDLIBRARY.PARANOIA_LEVEL', 'RDLIBRARY.RIPPER_DEVICE' and + 'RDLIBRARY.RIPPER_LEVEL' fields to the database, along with + appropriate accessor methods in 'RDLibraryConf'. + * Added fields for 'Ripper Device', 'Paranoia Level' and 'Ripper + Level' to 'RDAdmin->Stations->RDLibrary'. + * Added 'scripts/rd_rip_cd' script. +2003-05-14 Fred Gleason + * Finalized the calling convention for 'scripts/rd_rip_cd'. Only + PCM16 support so far. + * Completed the widget layout for the CD Ripper in RDLibrary. +2003-05-15 Fred Gleason + * Added a 'reset()' method to 'RDCut'. + * Moved the 'RDRipper' class from 'lib/' to 'rdlibrary/' and + renamed it 'CdRipper'. + * Added the requirement for CDParanoia and SoX to 'INSTALL'. +2003-05-16 Fred Gleason + * Added a 'rdmpeg2wav' command in 'utils/'. +2003-05-19 Fred Gleason + * Changed 'rdlibrary/edit_audio.cpp' so as to work with the new + 'RWaveFile' 'energy()' method interface. +2003-05-20 Fred Gleason + * Added MPEG-1 Layer 2 support to 'scripts/rd_rip_cd'. + * Updated 'rdlibrary/cdripper.cpp' to use the new calling API for + 'rd_rip_cd'. +2003-05-21 Fred Gleason + * Started adding FreeDB support to the CD ripper. Very much a + WIP. +2003-05-22 Fred Gleason + * Basic FreeDB support now working in the CD ripper. Still needs + to be integrated with mySQL. +2003-05-22 Fred Gleason + * Changed the 'Other' widget in RDLibrary's CD Ripper to support + multi-line text display. + * Added the apply in RDLibrary's CD Ripper to apply FreeDB data to + the underlying cart. +2003-05-23 Fred Gleason + * Fixed a bug in 'scripts/rd_rip_cd' that was causing resamples to + 48 kHz sample rate to fail. + * Fixed a bug in 'rdlibrary/cdripper.cpp' that was causing + normalization to be applied to cd rips even with the + 'Normalization' checkbox cleared. + * Fixed a bug in 'rdlibrary/cdripper.cpp' that was causing + incorrect progress bar updates when ripping to single channel + output. + * Disabled the 'Abort Rip' button in 'rdlibrary/cdripper.cpp'. + * Added field 'RDLIBRARY.CDDB_SERVER', along with appropriate + accessor methods. + * Added a field in RDAdmin->Stations->RDLibrary for specifying the + FreeDB server to use for CD lookups in the ripper. + * Changed 'rdlibrary/cdripper.cpp' to use the FreeDB server data + from the database. +2003-05-27 Fred Gleason + * Added a 'RDPlayDeck' class in 'lib/rdplay_deck.cpp'. + * Stubbed out 'RDAirPlay' in 'rdairplay/', an on-air playout + module. + * Added an 'RDListLogs' class in 'lib/rdlist_logs.cpp'. + * Added a 'LogLineBox' class in 'rdairplay/loglinebox.cpp'. +2003-05-28 Fred Gleason + * Added a 'COUNT' field to the log table format, and updated + appropriate accessor methods. + * Fixed various bugs in 'RDLogEdit' to make it stable and working. + * Changed the default sort column RDLibrary's Cart Editor to + the 'NAME' field. + * Changed the default cut name in RDLibrary's Cut Editor to pad + the numerals with leading zeros. + * Move work on RDAirPlay. +2003-05-30 Fred Gleason + * Rearranged the field order in the track list in RDLibrary's CD + Ripper so that the track type is the last field listed. +2003-06-02 Fred Gleason + * Fixed a bug in 'rdlibrary/edit_audio.cpp' where the play cursor + would sometimes flicker when advancing during playback. + * Fixed a bug in 'rdlibrary/add_cart.cpp' where clicking the + 'Cancel' button in the edit widget of a new cart would fail to + delete the cart. + * Added a sanity check to RDLibrary's Cart Editor to prevent + saving of a cart without an assigned title. + * Fixed a race condition in 'rdlibrary/cdripper.cpp' where + ejecting a CD while a FreeDB lookup was pending would segfault the + program. + * Changed RDLibrary's CD Ripper so that it now places the CD track + title into the cut DESCRIPTION field (as well as the cart TITLE) + when 'Apply FreeDB Values to Cart' is checked. + * Added a widget to RDLibrary's Cart Editor to allow the choice of + cut scheduling policy. + * Fixed a bug in 'scripts'rd_create_db' that was creating dates + in the CUTS table with an incorrect default value. + * More work on RDAirPlay. +2003-06-04 Fred Gleason + * Added an 'RDAudioExists()' function in 'lib/rdaudio_exists.cpp'. + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' where the currently + selected cart would randomly change when exiting out of a cart + edit dialog. + * Fixed a bug in 'rdlibrary/edit_cart.cpp' where the currently + selected cut would randomly change when exiting out of an edit, + record/label or rip dialog. + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' where the currently + selected log would randomly change when exiting out of an edit + dialog. + * Fixed a bug in 'rdlogedit/edit_log.cpp' where the currently + selected event would randomly change when exiting out of an edit + dialog. +2003-06-06 Fred Gleason + * Removed the 'MPEG-1 Layer 3' option from the 'Format' field in + RDAdmin->Stations->RDLibrary. + * Removed the values higher than '192 kbps/chan' from the + 'Bitrate' options in RDAdmin->Stations->RDLibrary. + * Changed the units of the 'Bitrate' field in + RDAdmin->Stations->RDLibrary to 'kbps/chan'. + * Changed the 'Bitrate' field in RDADmin->Stations->RDLibrary to + default to a value of 128 kbps/chan. + * Moved the 'Format', 'Sample Rate' and 'Bitrate' fields from the + 'Defaults' to the 'Settings' section in + RDAdmin->Stations->RDLibrary. + * Removed the values higher than '192 kbps/chan' from the + 'Bitrate' options in RDAdmin->Stations->RDCatch. + * Changed the 'Bitrate' field in RDADmin->Stations->RDCatch to + default to a value of 128 kbps/chan. + * Moved the 'Format', 'Sample Rate' and 'Bitrate' fields from the + 'Defaults' to the 'Settings' section in + RDAdmin->Stations->RDRDCatch. + * Replaced the 'Settings' button with a 'Channels' selector in + RDLibrary->Edit->Record/Label. + * Changed 'rdlibrary/record_cut.cpp' to use the new MPEG-1 + bitrate/chan scheme. + * Changed 'rdlibrary/cdripper.cpp' to use the new MPEG-1 + bitrate/chan scheme. + * Delete 'rdcatch/add_recording.h' and + 'rdcatch/add_recording.cpp'. + * Removed the 'Settings' button from RDCatch->Add and + RDCatch->Edit. + * Added a 'Channels' selector to RDCatch->Add and + RDCatch->Edit. + * Fixed a bug in 'rdcatch/edit_recording.cpp' where the configured + default record parameters were being ignored. +2003-06-09 Fred Gleason + * Added a 'VERSION' table. + * Created an 'RD_VERSION_DATABASE' version constant in 'lib/rd.h' + and initialized it at '1'. + * Created an 'RDVersion' class in 'lib/rdversion.cpp'. + * Created a 'CheckVersion' class in 'rdadmin/checkversion.cpp'. + * Created a 'CreateDb' class in 'rdadmin/createdb.cpp'. + * Created an 'OpenDb" class in 'rdadmin/opendb.cpp'. + * Created a 'MySqlLogin' class in 'rdadmin/mysql_login.cpp'. +2003-06-10 Fred Gleason + * Removed the QSqlDatabase parameter from 'RDUser's constructor. + * Moved 'rdadmin/checkversion.cpp' to 'lib/rdcheck_version.cpp'. + * Moved 'rdadmin/checkversion.h' to 'lib/rdcheck_version.h'. + * Added the ability to specify the text message as part of + 'MySqlLogin's constructor. + * Added 'DBChanges', a text file to track database version + changes. + * Added an 'UpdateDb()' function in 'rdadmin/createdb.cpp'. + * Added an 'RDCheckDaemons()' function in + 'lib/rdcheck_daemons.cpp'. + * Added an 'install-exec-hook' rule to 'rdadmin/Makefile.am' so as + to install RDAdmin SETUID. +2003-06-11 Fred Gleason + * Commented out 'caed', 'RDGpo' and 'RDGpi' from the makefiles so + as to get things to build while overhauling the GPIO stuff in + libradio. +2003-06-13 Fred Gleason + * Changed 'cae/cae.cpp' to work with the new 'RGpio' driver. + * Removed the check for root permissions from 'cae/cae.cpp'. + * Removed 'RDGpi' and 'RDGpo' from 'utils/'. + * Added code to 'ripcd/ripcd.cpp' to properly relinquish root + permissions if started as 'root'. + * Rewrote 'docs/GPIO.txt' to reflect the changes made for the new + GPIO driver. + * Removed the 'SETUID' attribute from 'RDAdmin's binary. +2003-06-16 Fred Gleason + * Added a one second pause after starting each daemon in + 'RDStartDaemons()' before checking status. + * Incremented VERSION.DB to '2'. + * Added a check to 'cae/cae.cpp' to ensure that only one instance + of the program will run at a time. + * Added a check to 'ripcd/ripcd.cpp' to ensure that only one instance + of the program will run at a time. + * Added a check to 'rdcatchd/rdcatchd.cpp' to ensure that only one + instance of the program will run at a time. + * Added an 'RDInitializeDaemons()' function to + 'lib/rdcheck_daemons.cpp'. + * Added a call to 'RDInitializeDaemons()' in + 'rdairplay/rdairplay.cpp'. + * Added a call to 'RDInitializeDaemons()' in + 'rdcatch/rdcatch.cpp'. + * Added a call to 'RDInitializeDaemons()' in + 'rdlibrary/rdlibrary.cpp'. + * Added a call to 'RDInitializeDaemons()' in + 'rdlogedit/rdlogedit.cpp'. + * Added a call to 'RDInitializeDaemons()' in + 'rdlogin/rdlogin.cpp'. + * Rewrote 'INSTALL' to reflect the next installation proceudres. +2003-06-24 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' that was writing incorrect + default daypart values. + * Added an 'RDAirPlay' button to RDAdmin->Stations->Edit. + * Rewrote the font handling code in all of RDAdmin's components to + ensure consistent font sizing. + * Rewrote the font handling code in RDLibrary to ensure consistent + font sizing. +2003-06-25 Fred Gleason + * Added an 'EditRdAirPlay' class in 'rdadmin/edit_rdairplay.cpp'. + * Added an 'RDAIRPLAY' table, along with appropriate code in + 'rdadmin/createdb.cpp'. + * Updated the database version to '3'. + * Added an 'RDAirPlayConf' class in 'lib/rdairplay_conf.cpp'. +2003-06-25 Fred Gleason + * Added the 'auto_increment' attribute to 'RDAIRPLAY.ID'. + * Added the Alter privilege to rduser on mySQL. + * Updated the database version to '4'. +2003-07-08 Fred Gleason + * Added code to 'RDLibrary' to update the 'Length:' field for + carts. + * Fixed a bug in 'lib/rd_filter_string.cpp' that was causing the + GROUP attribute to be omitted from a cart filter search. + * Added the 'GROUP' attribute to the cart list in RDLibrary. + * Fixed a bug in 'rdadmin.cpp' that was causing a seg fault when + deleting objects from the database. + * Renamed the 'CatchConnect' class top 'RDCatchConnect' and moved + it from 'rdcatch/catch_connect.cpp' to 'lib/rdcatch_connect.cpp'. +2003-07-09 Fred Gleason + * Added code to 'rdadmin/edit_station.cpp' to notify RDCatchd when + a deck configuration is changed. +2003-07-11 Fred Gleason + * Fixed a bug in 'rdlibrary/edit_cart.cpp that was throwing a + SIGFPE when processing a cart with no cuts. + * Fixed a bug in 'rdcatch/edit_recording.cpp' that was causing the + source list to be displayed in non-alphabetical order. + * Fixed a bug in 'rdcatch/edit_recording.cpp' that was causing the + number of audio channels to be incorrectly set. + * Changed 'rdccatch/rdcatch.cpp' to set default focus to the + 'Close' button. + * Added the Stop Record (SR) command to RDCatchd. + * Added a 'stop()' slot to 'RDCatchConnect'. + * Added an Abort button to the deck monitor in RDCatch. + * Fixed a sorting bug in 'lib/rdcut_dialog.cpp'. + * Fixed a sorting bug in 'lib/rdcart_dialog.cpp'. + * Added a 'CrTerm' value to RDTty::Termination. + * Added a 'Cr' item to the list of available termination types in + RDAdmin->Stations->Edit->Serial Ports. + * Added support to 'RDTtyOut' for a 'CrTerm' terminator type. + * Changed RDAdmin->Stations->Edit->RDCatch->ConfigureSources to + put default keyboard focus on the serial string input box. +2003-07-14 Fred Gleason + * Added audio playout to RDAirPlay. +2003-07-15 Fred Gleason + * Began reorganizing play decks in RDAirPlay. +2003-07-23 Fred Gleason + * Fixed a bug in 'cae/Makefile.am' that was causing moc files to + fail to be deleted by the various 'make clean' targets. + * Changed the 'CFLAGS =' equate in all the 'Makefile.am's to + 'AM_CFLAGS ='. + * Fixed the font handling code in 'rdairplay/rdairplay.cpp' to + size fonts properly under SuSE 8.2. +2003-07-24 Fred Gleason + * Added a 'SOURCE' field to the log table format. + * Incremented the database version to '5'. + * Added 'SOURCE' field to 'rdadmin/createdb.cpp'. + * Added 'SOURCE' field to 'lib/rdcreate_log.cpp'. + * Added a 'Source' enum to 'lib/rdlog_line.h'. + * Added 'source()' and 'setSource()' methods to + 'lib/rdlog_line.cpp'. + * Added code to 'rdadmin/createdb.cpp' to add the 'SOURCE' field + to existing logs. + * Added a 'cutNumber()' method to 'lib/rdcut.cpp'. + * Imported 'RClock' from libradio into 'rdairplay/wall_clock.cpp'. + * Added 'PostCounter' class in 'rdairplay/post_counter.cpp'. + * Added 'PieCounter' class in 'rdairplay/pie_counter.cpp'. + * Added 'StartButton' class in 'rdairplay/start_button.cpp'. +2003-07-28 Fred Gleason + * Fixed a compile bug in 'rdairplay/edit_log.cpp'. +2003-08-20 Fred Gleason + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was breaking build. +2003-08-22 Fred Gleason + * Reorganized the RDAIRPLAY table to use stream pooling. + * Modified 'rdadmin/createdb.cpp' to use the new RDAIRPLAY table + structures. + * Updated the database version to '6'. + * Updated 'lib/rdairplay_conf.cpp' to use the new RDAIRPLAY table + structure. + * Updated RDAdmin to use the new stream pooling channel assignment + layout. +2003-08-25 Fred Gleason + * Implemented the 'audioExists()' method in 'RDCut'. +2003-09-03 Fred Gleason + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing a + segfault when loading a log. + * Created an 'AudioResources' class in + 'rdairplay/audio_resources.cpp'. + * Added a 'StartEvent()' method in 'rdairplay/rdairplay.cpp'. + * Added an 'id()' method in 'rdairplay/logline.cpp'. + * Added 'rdairplay/globals.h'. +2003-09-04 Fred Gleason + * Got audio playout working with stream pooling. +2003-09-05 Fred Gleason + * Implemented the playback meter in RDAirPlay. + * Implemented the 'position()' signal in RDPlayDeck'. + * Added a 'setTime()' method to 'rdairplay/start_button.cpp'. + * Added a 'setTimer()' method to 'rdairplay/loglinebox.cpp'. + * Added a 'setPort()' method to 'rdairplay/start_button.cpp'. + * Added a 'portText()' method to rdairplay/audio_resources.cpp'. +2003-09-08 Fred Gleason + * Fixed a bug in 'rdairplay/pie_counter.cpp' that was causing + incorrect screen freshing. + * Fixed a bug in 'rdairplay/wallclock.cpp' that was causing the + start and end of the date string to be truncated. + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing a + segfault when pressing a Start button for an empty log line. + * Implemented log advancement. +2003-09-09 Fred Gleason + * Implemented the FadeUp marker in RDAirPlay. + * Implemented the FadeDown marker in RDAirPlay. + * Implemented event stop-down. + * Added an RDLIBRARY.SEGUE_LENGTH field to the database. + * Updated database creation and update code in 'rdadmin/createdb.cpp'. + * Incremented the database version to '7'. + * Added accessor methods for RDLIBRARY.SEGUE_LENGTH in + 'lib/rdairplay_conf.cpp'. + * Added a 'Manual Segue' spin box to RDAdmin->Stations->RDAirPlay. + * Added a 'state()' method to 'lib/rdplay_deck.cpp'. +2003-09-10 Fred Gleason + * Adjusted the geometry of the wall clock widget in RDAirPlay. + * Adjusted the geometry of the post counter widget in RDAirPlay. + * Added a 'setState()' method to 'rdairplay/stop_counter.cpp'. +2003-09-11 Fred Gleason + * Added a master clock timer to 'rdairplay/rdairplay.cpp'. + * Rewrote 'rdairplay/wall_clock.cpp' to use the master clock + timer. + * Removed dead timer code from 'rdairplay/pie_counter.cpp'. + * Rewrote 'rdairplay/stop_counter.cpp' to use the master clock + timer. + * Fixed a bug in 'rdairplay/stop_counter.cpp' that was causing the + counter to enter Stopped mode one second before the actual end of + playout. + * Added a 'ModeDisplay' widget in 'rdairplay/mode_display.cpp'. +2003-09-12 Fred Gleason + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing the + volume setting of unconfigured streams to be turned off at + startup. + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing random + segfaults at the end of events. +2003-09-15 Fred Gleason + * Fixed a bug in 'rdlogedit/edit_logline.cpp' that was causing the + incorrect transition types to be applied to log events. + * Added a 'transType()' method to 'rdairplay/loglinebox.cpp'. + * Added a 'finished()' signal to 'lib/rdplay_deck.cpp'. + * Implemented the beginnings of automatic mode in RDAirPlay. +2003-09-16 Fred Gleason + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing a + segfault at the end of the last event in a log when in Auto mode. + * Added logic to 'rdairplay/loglinebox.cpp' to load a Segue log + event as Play if no Segue marker is set for the underlying cut. + * Added a 'segueLength()' method to 'rdairplay/loglinebox.cpp'. + * Implemented Segue transitions in RDAirPlay. +2003-09-17 Fred Gleason + * Added 'segueLength()' and 'segSegueLength()' methods to + 'lib/rdlog_line.cpp'. + * Fixed a bug in 'rdairplay/loglinebox.cpp' that was causing + incorrect segue time lengths to be generated. + * Fixed a whole set of interrelated bugs in 'rdairplay.cpp', + 'lib/rdlog_line.cpp' and 'lib/rdlog_event.cpp' that were affecting + accurate calculation of next stopdown time in RDAirPlay. +2003-09-18 Fred Gleason + * Changed the size of the Edit Log widget in RDLogEdit to 800x600. + * Added code to 'rdlogedit/edit_log.cpp' and + 'rdlogedit/edit_logline.cpp' so as to put focus on a newly + inserted log event. + * Added up/dow arrow buttons to the event editor dialog in + RDLogEdit. + * Added cut/copy/paste buttons to the event editor dialog in + RDLogEdit. + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' that was causing + incorrect fonts to be displayed under SuSE 8.2. + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was causing + incorrect fonts to be displayed under SuSE 8.2. + * Fixed a bug in 'rdlogedit/add_log.cpp' that was causing + incorrect fonts to be displayed under SuSE 8.2. + * Fixed a bug in 'rdlogedit/edit_logline.cpp' that was causing + incorrect fonts to be displayed under SuSE 8.2. + * Fixed a bug in 'lib/rdcart_dialog.cpp' that was causing + incorrect fonts to be displayed under SuSE 8.2. + * Implemented persistent filter strings in RDLogEdit. + * Created an 'RDListView' class in 'lib/rdlistview.cpp'. +2003-09-19 Fred Gleason + * Implemented an end-of-log marker in RDLogEdit's Edit Log dialog. + * Made the window sizes fixed in RDLogEdit. + * Fixed a bug in 'lib/rdlistview.cpp' that was failing to properly + handle mouse clicks with the Control key pressed. + * Added code to fix the window size in 'lib/rdcart_dialog.cpp'. + * Added code to fix the window size in 'lib/rdcardselector.cpp'. + * Added code to fix the window size in 'lib/rdlist_logs.cpp'. + * Added code to fix the window size in 'lib/rdpasswd.cpp'. + * Added code to fix the window size in 'rdadmin/add_group.cpp'. + * Added code to fix the window size in 'rdadmin/add_source.cpp'. + * Added code to fix the window size in 'rdadmin/add_station.cpp'. + * Added code to fix the window size in 'rdadmin/add_svc.cpp'. + * Added code to fix the window size in 'rdadmin/add_user.cpp'. + * Added code to fix the window size in 'rdadmin/edit_audios.cpp'. + * Added code to fix the window size in 'rdadmin/edit_decks.cpp'. + * Added code to fix the window size in 'rdadmin/edit_group.cpp'. + * Added code to fix the window size in 'rdadmin/edit_rdairplay.cpp'. + * Added code to fix the window size in 'rdadmin/edit_rdlibrary.cpp'. + * Added code to fix the window size in 'rdadmin/edit_source.cpp'. + * Added code to fix the window size in 'rdadmin/edit_sources.cpp'. + * Added code to fix the window size in 'rdadmin/edit_station.cpp'. + * Added code to fix the window size in 'rdadmin/edit_svc.cpp'. + * Added code to fix the window size in 'rdadmin/edit_ttys.cpp'. + * Added code to fix the window size in 'rdadmin/edit_user.cpp'. + * Added code to fix the window size in 'rdadmin/list_groups.cpp'. + * Added code to fix the window size in 'rdadmin/list_stations.cpp'. + * Added code to fix the window size in 'rdadmin/list_svcs.cpp'. + * Added code to fix the window size in 'rdadmin/list_users.cpp'. + * Added code to fix the window size in 'rdadmin/login.cpp'. + * Added code to fix the window size in 'rdadmin/rdadmin.cpp'. + * Added code to fix the window size in 'rdairplay/rdairplay.cpp'. + * Added code to fix the window size in 'rdcatch/deckmon.cpp'. + * Added code to fix the window size in 'rdcatch/edit_recording.cpp'. + * Added code to fix the window size in 'rdcatch/rdcatch.cpp'. + * Added code to fix the window size in 'rdlibrary/add_cart.cpp'. + * Added code to fix the window size in 'rdlibrary/cdripper.cpp'. + * Added code to fix the window size in 'rdlibrary/edit_audio.cpp'. + * Added code to fix the window size in 'rdlibrary/edit_cart.cpp'. + * Added code to fix the window size in 'rdlibrary/filter.cpp'. + * Added code to fix the window size in 'rdlibrary/rdlibrary.cpp'. + * Added code to fix the window size in 'rdlibrary/record_cut.cpp'. + * Added code to fix the window size in 'rdlogin/rdlogin.cpp'. + * Added code to fix the window size in 'utils/metadialog.cpp'. + * Added code to fix the window size in 'utils/rdplay.cpp'. + * Added code to fix the window size in 'utils/rdrecord.cpp'. + * Added 'timeType()' and 'startTime()' methods to + 'rdairplay/loglinebox.cpp'. +2003-09-22 Fred Gleason + * Removed the 'id()', 'timeType()', and 'cartNumber()' methods + from LogLineBox. + * Added a 'GetStartTime()' method to 'rdairplay/rdairplay.cpp'. + * Removed the 'nextStop()' method from 'lib/rdlog_event.cpp'. + * Implemented Hard and Soft TimeSync in RDAirPlay. + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing the + Pie Counter to continue to countdown an event after the event had + been manually stopped. +2003-09-23 Fred Gleason + * Added a 'setMode()' method to 'rdairplay/start_button.cpp'. + * Reduced the size of the Pie Counter in RDAirPlay. + * Relocated the Load Log button in RDAirPlay. + * Added a 'ListLog' widget in 'rdairplay/list_log.cpp'. + * Added an 'RDListViewItem' class in 'lib/rdlistview.cpp'. +2003-09-24 Fred Gleason + * Added 'status()' and 'setStatus()' methods to + 'lib/rdlog_line.cpp'. + * Replaced the 'setOnAir()' with 'setState()' method in + 'rdairplay/list_log.cpp'. +2003-09-25 Fred Gleason + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing the + Full Log widget to "eat" the first event played in a log. + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing later + events to be skipped when manually starting events. +2003-09-29 Fred Gleason + * Added a sound panel widget to RDAirPlay. + * Fixed a bug in 'rdairplay/pie_counter.cpp' that was causing the + pie counter to display ':00' at the end of the countdown. + * Fixed a bug in 'rdairplay/stop_counter.cpp' that was causing the + pie counter to display ':00' at the end of the countdown. +2003-10-01 Fred Gleason + * Fixed a bug in 'rdairplay/loglinebox.cpp' that was preventing + the Cut ID from displaying if it had a value of '0'. + * Added a display field for the Cart Group Name to the line boxes + in RDAirPlay. + * Added code to 'rdlogedit/edit_logline.cpp' to disable the start + time entry when using a time transition type of 'Relative'. + * Implemented color-coded progress bars in RDAirPlay. + * Overhauled the Pie Counter in RDAirPlay. + * Added RDAIRPLAY.PORT3, RDAIRPLAY.OP_MODE,RDAIRPLAY.START_MODE, + RDAIRPLAY.PIE_COUNT_LENGTH and RDAIRPLAY_PIECOUNT_ENDPOINT fields + to the database, along with appropriate accessor methods in + 'lib/rdairplay_conf.cpp'. + * Incremented the database version to '8'. + * Added controls for Cue Output Port, Startup Operation Mode, Pie + Counter Countdown Length and Pie Counter Endpoint to + RDAdmin->Stations->RDAirPlay. +2003-10-03 Fred Gleason + * Fixed a bug in 'rdairplay/mode_display.cpp' that was causing the + color of the mode label to change when the mouse was moved off the + application window. +2003-10-06 Fred Gleason + * Added an 'LogPlay' class in 'rdairplay/log_play.cpp'. + * Added a 'PlaySlot' class in 'rdairplay/play_slot.cpp'. + * Renamed the 'name()' and 'setName()' methods is + 'lib/rdlog_event.cpp' to 'logName()' and 'setLogName()'. +2003-10-07 Fred Gleason + * Fixed a bug in 'rdairplay/audio_resources.cpp' that was causing + the end of the first event in a log to be occasionally cut off. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing segue + transitions to cut off the end of events. +2003-10-08 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing the + 'stop()' slot to fail. + * Added a 'currentLine()' method to 'rdairplay/log_play.cpp'. +2003-10-10 Fred Gleason + * Added 'deck()', 'setDeck()', 'playTime()', 'setPlayTime()', + 'cutNumber()', 'effectiveLength()', 'talkLength()', + 'segueLength()', 'segueTail()' and 'setEvent()' methods to + 'lib/rdlog_line.cpp'. + * Renamed the 'button()' and 'setButton()' methods in + 'rdairplay/audio_resources.cpp' to 'line()' and 'setLine()'. + * Deleted 'rdairplay/play_slot.h' and rdairplay/play_slot.cpp'. +2003-10-13 Fred Gleason + * Added a 'nextTransType()' method to 'lib/rdlog_event.cpp'. + * Implemented the 'Add' function in RDAirPlay. + * Implemented the 'Move' function in RDAirPlay. + * Added RDAIRPLAY.PORT4 and RDAIRPLAY.PORT5 fields to the + database. + * Incremented the database version to '9'. + * Added field in RDAdmin->Stations->RDAirPlay for assigning the + output ports for Aux 1 and Aux 2 log machines. +2003-10-14 Fred Gleason + * Added an 'EditEvent' class in 'rdairplay/edit_event.cpp'. +2003-10-15 Fred Gleason + * Added an 'RDTimeEdit' class in 'lib/rdtimeedit.cpp'. + * Added 'playPosition()' and 'setPlayPosition()' methods to + 'lib'rdlog_line.cpp'. + * Added an id field to the signals in RDPlayDeck. + * Removed the QSignalMappers from LogPlay. + * Removed the 'tickClock()' method from 'rdairplay/log_play.cpp'. + * Added a 'StartNextEvent()' method to 'rdairplay/log_play.cpp. + * Added an 'Auditioning' tag to RDLogLine::Status. +2003-10-20 Fred Gleason + * Fixed a bug in 'rdlibrary/edit_cart.cpp' that was causing a + segfault when closing the Record dialog on a newly-created cut + with no audio. + * Removed dead code in 'rdlibrary/edit_audio.cpp'. + * Fixed a bug in 'rdlibrary/edit_audio.cpp' that was causing the + end marker to move 26 mS closer to the start every time the cut + markers were saved in the Marker Editor. +2003-10-28 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + segfault when manually stopping an event. + * Fixed a bug in 'cae/cae.cpp' that was causing an 'SP' status + replay to be emitted when unloading an already stopped cut. + * Added a 'ButtonLog' widget in 'rdairplay/button_log.cpp'. +2003-11-03 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp that was causing a + segfault when manually stopping an event. + * Reintegrated the pie counter widget into RDAirPlay. + * Rewrote the 'ModeDisplay' widget to operate as a push button. + * Removed the Mode pushbutton from 'rdairplay/rdairplay.cpp'. + * Rewrote the Wall Clock widget in RDAirPlay to be a push button. + * Added a 'RDAirPlayConf::TimeMode' enum. + * Added a 'setTimeMode()' method to 'rdair_play/log_play.cpp'. + * Added a 'setTimeMode()' method to 'rdair_play/start_button.cpp'. + * Added a 'setTimeMode()' method to 'rdair_play/loglinebox.cpp'. +2003-11-04 Fred Gleason + * Added a 'setTimeMode()' method in 'rdairplay/list_log.cpp'. + * Fixed a bug in 'rdairplay/log_play.cpp' that was invalidating + the event start time for past events. + * Added a 'setOpMode()' method to 'rdairplay/list_log.cpp'. + * Reintegrated the Stop Point counter in RDAirPlay. + * Fixed a bug in 'rdairplay/list_log.cpp' that was causing + corruption when a new log was loaded over the top of an already + loaded on in RDAirPlay. + * Fixed a bug in 'rdairplay/stop_counter.cpp' that was failing to + put the Stop Counter into 'Stopped' after manually stopping the + log. +2003-11-06 Fred Gleason + * Added 'TYPE', 'COMMENT', 'LABEL' and 'POST_TIME' fields to the + log table format. + * Updated 'rdadmin/createdb.cpp' to utilize the new fields. + * Updated 'lib/rdcreatelog.cpp' to utilize the new fields. + * Incremented the database version to '10'. + * Updated 'lib/rdlog_line.cpp' to utilize the new fields. + * Added an 'EditMarker' class in 'rdlogedit/edit_marker.cpp'. +2003-11-07 Fred Gleason + * Updated 'rdlogedit/edit_log.cpp' to use the new calling + parameters for 'RTruncateAfterWord()'. + * Updated the 'setEvent()' method in 'lib/rdlog_line.cpp' to + properly deal with marker events. + * Updated 'rdairplay/log_play.cpp' to properly deal with marker + events. + * Updated 'rdairplay/list_log.cpp' to properly deal with marker + events. + * Updated 'rdairplay/button_log.cpp' to properly deal with marker + events. + * Overhauled 'rdairplay/post_counter.cpp' to make it work with + Marker Post Points. Still a WIP. +2003-11-10 Fred Gleason + * Updated 'rdairplay/log_play.cpp' and + 'rdairplay/post_counter.cpp' to get Post Counter to work. +2003-11-12 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing the + Post Point counter to fail to update after inserting a new event. + * Added a 'mouseDoubleLick()' method to + 'rdairplay/loglinebox.cpp'. + * Increased the size of the position knob in RDAirPlay's Event + Editor. + * Added count-up and count-down timers to RDAirPlay's Event + Editor. +2003-11-13 Fred Gleason + * Added an 'AdvanceActiveEvent()' method to + 'rdairplay/log_play.cpp'. + * Renamed the 'topEventChanged()' signal in + 'rdairplay/log_play.cpp' to 'activeEventChanged()'. + * Reimplemented the 'activeEventChanged()' signalling semantics so + as to ensure that the most recently started event is always + the one signalled. + * Fixed a bug in 'rdairplay/button_log.cpp' that was allowing + currently playing events to be available as Add/Delete/Move + targets. + * Added a 'runStatusChanged()' signal to 'rdairplay/log_play.cpp'. + * Added a 'topEventChanged()' signal to 'rdairplay/log_play.cpp'. + * Added 'listViewItem()' and 'setListViewItem()' methods to + 'lib/rdlogline.cpp'. +2003-11-14 Fred Gleason + * Fixed a memory leak in 'rdairplay/wall_clock.cpp'. + * Added 'CHECK_TIMESYNC', 'STATION_PANELS' and 'USER_PANELS' + fields to the RDAIRPLAY table in the database. + * Added a 'PANELS' table to the database. + * Incremented the database version to '12'. + * Added 'checkTimesync()', 'setCheckTimesync()', 'panels()' and + 'setPanels()' methods to 'lib/rdairplay_conf.cpp'. + * Added widgets in RDAdmin->Stations->RDAirPlay for + enabling/disabling time sync checking and setting the number of + sound panels. + * Added a 'setSyncEnabled()' method to 'rdairplay/wall_clock.cpp'. +2003-11-17 Fred Gleason + * Added a 'PanelButton' class in 'rdairplay/panel_button.cpp'. + * Fixed a bug in 'rdadmin/createdb.cpp' where the PANELS.ID field + in the database was being created without the AUTO_INCREMENT + parameter. + * Added indices to the 'PANELS' table to improve panel load/save + speed. + * Incremented the database version to '14'. + * Added a 'ButtonDialog' class in 'rdairplay/button_dialog.cpp'. +2003-11-18 Fred Gleason + * Changed the size of the PANELS.DEFAULT_COLOR field from '6' to + '7'. + * Incremented the database version to '15'. + * Added a 'WrapText()' method to 'rdairplay/panel_button.cpp'. + * Added 'deck()' and 'setDeck()' methods to + 'rdairplay/panel_button.cpp'. +2003-11-19 Fred Gleason + * Added a 'ButtonPanel' class in 'rdairplay/button_panel.cpp'. + * Overhauled the 'SoundPanel' class to use a vector template to + track button data. +2003-11-20 Fred Gleason + * Added 'setStartTime()', 'setLength()' and 'tickClock()' methods + to 'rdairplay/panel_button.cpp'. + * Completed basic SoundPanel functionality. +2003-11-20 Fred Gleason + * Fixed a buffer-overflow bug in 'rdcatchd/rdcatchd.h'. +2003-11-20 Fred Gleason + * Removed the 'Search' button from RDAirPlay's SoundPanel. +2003-11-21 Fred Gleason + * Added an 'InfoDialog' widget in 'rdadmin/info_dialog.cpp'. + * Updated the version number to '0.5.0'. + * Added a 'ViewAdapters' widget in 'rdadmin/view_adapters.cpp'. +2003-11-26 Fred Gleason + * Added a 'helpers' directory. + * Added the 'cwrap' utility in 'helpers/cwrap.cpp'. + * Added banner bitmaps in 'rdadmin/info_banner1.xpm' and + 'rdadmin/info_banner2.xpm'. +2003-12-01 Fred Gleason + * Fixed a bug in 'rdadmin/rdadmin.cpp' that was creating database + backup files without a '.sql' extension. +2003-12-05 Fred Gleason + * Removed 'config.guess' + * Removed 'config.status' + * Removed 'config.sub' + * Removed 'install-sh' + * Removed 'ltmain.sh' + * Removed 'missing' + * Removed 'mkinstalldirs' + * Removed 'depcomp' + * Added 'autogen.sh'. + * Added the 'toolame' MPEG L2 encoder in 'toolame/'. +2003-12-07 Fred Gleason + * Added 'rivendell.spec.in'. + * Added a 'make rpm' target. +2003-12-08 Fred Gleason + * Fixed a bug in 'rdadmin/opendb.cpp' that was causing connection + to a newly-created Rivendell database to fail. + * Added code to 'rdadmin/config.cpp' to autodetect the hostname of + the local machine. + * Removed the 'StationName=' directive from 'conf/rd.conf-sample'. + * Adjusted the fonts in 'rdadmin/info_dialog.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdadmin/list_users.cpp' to look good on + SuSE 9.0. + * Adjusted the layout in 'rdadmin/edit_user.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdadmin/list_groups.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdadmin/list_svcs.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdadmin/list_stations.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdlibrary/filter.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdlibrary/rdlibrary.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdlibrary/edit_cart.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdlibrary/edit_audio.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdlibrary/cdripper.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdairplay/rdairplay.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdairplay/wall_clock.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdairplay/post_counter.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdairplay/stop_counter.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdairplay/mode_display.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdcatch/rdcatch.cpp' to look good on + SuSE 9.0. + * Adjusted the fonts in 'rdcatch/edit_recording.cpp' to look good on + SuSE 9.0. + * Adjusted the layout in 'rdlogedit/edit_log.cpp' to look good on + SuSE 9.0. + * Adjusted the layout in 'rdlogin/rdlogin.cpp' to look good on + SuSE 9.0. + * Added 'GPITest' and 'GPOTest' applications from the 'LibRadio' + package in 'utils/'. +2003-12-08 Fred Gleason + * Fixed a bug in 'rdlibrary/record_cart.cpp' that was causing + recording to fail when the input and output streams were + configured to be different. + * Fixed a bug in 'lib/rdcut_dialog.cpp' that was causing + incorrectly formatted cut data to be returned. + * Fixed a bug in 'lib' rdcardselector.cpp' that was causing the + selector to be abnormally clipped. +2003-12-09 Fred Gleason + * Added an Autoconf check for 'linux/gpio.h'. + * Released as v0.5.0. +2003-12-11 Fred Gleason + * Added 'conf/rd.conf-sample' and 'conf/rd.conf-complete-sample' + to the RPM docs directory. + * Added 'docs/rml.sxw', the specification for the Rivendell Macro + Language. +2003-12-12 Fred Gleason + * Added autoconf support for the MAD library. + * Added an 'RMLSend' utility in 'utils/rmlsend.cpp'. + * Added an 'RDMacro' class in 'lib/rdmacro.cpp'. + * Added the 'MS' and 'ME' commands to the RIPC protocol spec in + 'docs/ripc.txt'. + * Added an 'rmlReceived()' signal to 'lib'rdripc.cpp'. +2003-12-15 Fred Gleason + * Added 'echoRequested()' and 'setEchoRequested()' methods to + 'lib/rdmacor.cpp'. + * Removed 'port()' and 'setPort()' method from 'lib/rdmacro.cpp'. +2003-12-15 Fred Gleason + * Fixed a variety of bugs in the build system so as to compile + properly with soft MPEG support enabled. +2003-12-15 Fred Gleason + * Added the ability to select destination UDP port to RMLSend. +2003-12-15 Fred Gleason + * Added a 'RunLocalMacros()' method in 'ripcd/local_macros.cpp'. + * Added a 'SwitchTake()' method in 'ripcd/local_macros.cpp'. + * Added a 'SwitchAdd()' method in 'ripcd/local_macros.cpp'. + * Added a 'SwitchRemove()' method in 'ripcd/local_macros.cpp'. + * Added a 'SwitchLevel()' method in 'ripcd/local_macros.cpp'. +2003-12-16 Fred Gleason + * Added 'MATRICES', 'INPUTS' and 'OUTPUTS' tables. + * Incremented the database version to 16. + * Created an 'RDMatrix' class in 'lib/rdmatrix.cpp'. + * Added a "Switchers" button to RDAdmin->EditStations. + * Added a 'ListMatrices' dialog in 'rdadmin/list_matrices.cpp'. + * Added an 'AddMatrix' dialog in 'rdadmin/add_matrix.cpp'. + * Added an 'EditMatrix' dialog in 'rdadmin/edit_matrix.cpp'. + * Added an 'EditEndpoints' class in 'rdadmin/edit_endpoints.cpp'. +2003-12-22 Fred Gleason + * Renamed 'rdadmin/edit_endpoints.cpp' to + 'rdadmin/list_endpoints.cpp'. + * Renamed 'rdadmin/edit_endpoints.h' to + 'rdadmin/list_endpoints.h'. + * Created an 'EditEndpoint' widget in 'rdadmin/edit_endpoint.cpp'. + * Added an 'INPUTS.CHANNEL_MODE' field. + * Incremented the database version to 17. + * Added 'inputName()', 'outputName()' and 'inputMode()' methods in + 'lib/rdmatrix.cpp'. +2003-12-23 Fred Gleason + * Added a switcher driver for the SAS32000 in + 'ripcd/sas32000.cpp'. + * Fixed a fencepost error in 'rdadmin/list_endpoints.cpp'. + * Added a 'STATIONS.IPV4_ADDRESS' field. + * Incremented the database version to 18. + * Added 'address()' and 'setAddress()' methods in + 'lib/rdstation.cpp'. + * Added an 'IP Address' field in RDAdmin->Stations. + * Added global definitions in 'rdadmin/globals.h'. + * Created a switcher driver for the SAS64000 in + 'ripcd/sas64000.cpp'. + * Created a SysV-style init script for the Rivendell daemons in + 'rivendell'. + * Added an install rule for 'rc.rivendell' in 'Makefile.am'. + * Released as v0.5.2 +2003-01-05 Fred Gleason + * Added the 'GPI ENABLE' command to 'docs/rml.sxw'. + * Added the 'GPI SET' command to 'docs/rml.sxw'. + * Added the 'GPO SET' command to 'docs/rml.sxw'. + * Added the 'LOGIN' command to 'docs/rml.sxw'. + * Added the 'SERIAL OUT' command to 'docs/rml.sxw'. + * Added the 'SERIAL TRAP' command to 'docs/rml.sxw'. + * Added the 'SET LABEL' command to 'docs/rml.sxw'. + * Added the 'SLEEP' command to 'docs/rml.sxw'. + * Added the 'SWTICH ADD' command to 'docs/rml.sxw'. + * Added the 'SWITCH LEVEL' command to 'docs/rml.sxw'. + * Added the 'SWITCH RELOAD' command to 'docs/rml.sxw'. + * Added the 'SWITCH REMOVE' command to 'docs/rml.sxw'. + * Added the 'SWITCH TAKE' command to 'docs/rml.sxw'. + * Added the 'UDP OUT' command to 'docs/rml.sxw'. + * Added the 'START' command to 'docs/rml.sxw'. + * Added the 'START NEXT' command to 'docs/rml.sxw'. + * Added the 'STOP' command to 'docs/rml.sxw'. + * Added the 'ADD NEXT' command to 'docs/rml.sxw'. + * Added the 'SYNC' command to 'docs/rml.sxw'. + * Added the 'SET MODE' command to 'docs/rml.sxw'. + * Added the 'SELECT WIDGET' command to 'docs/rml.sxw'. + * Added the 'LOAD PANEL' command to 'docs/rml.sxw'. + * Added the 'PLAY PANEL' command to 'docs/rml.sxw'. + * Added the 'STOP PANEL' command to 'docs/rml.sxw'. +2003-01-05 Fred Gleason + * Added a switcher driver for the Unity4000 in + 'ripcd/unity4000.cpp'. + * Added support for the Unity4000 to + RDAdmin->Stations->Switcher/GPIO. + * Added a Unity4000 feed container class in + 'ripcd/unity_feed.cpp'. +2003-01-06 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + segfault when loading an empty log. + * Added a 'Sound Panel' button to RDAirPlay. + * Added the name of the current loaded log to each log machine's + selector button in RDAirPlay. + * Fixed a bug in 'rdairplay/button_log.cpp' that was failing to + clear the log boxes when unloading a log. + * Added support for the BroadcastTools 10x1 to + RDAdmin->Stations->Switcher/GPIO. + * Added a switcher driver for the BroadcastTools 10x1 in + 'ripcd/bt10x1.cpp'. + * Added 'owner()' and 'setOwner()' methods to + 'lib/rdplay_Deck.cpp'. + * Changed the behavior of the Full Log widgets in RDAirPlay so as + to allow the skipping of audio carts without deleting the carts + from the log. +2003-01-08 Fred Gleason + * Added a 'Scroll' button to the Full Log widget in RDAirPlay. + * Added a 'copy()' method to 'lib/rdlog_event.cpp'. + * Added the ability skip and then return to log events in + RDAirPlay. +2003-01-12 Fred Gleason + * Added a switcher driver for MeasurementComputing GPIO cards in + 'ripcd/local_gpio.cpp'. + * Added an 'EVENTS' table to the database. + * Incremented the database version to 19. + * Incrermented the version number to 0.6.0. +2003-01-14 Fred Gleason + * Fixed a bug in 'ripcd/ripcd.cpp' that was causing the daemon to + lockup when send an RML to the echo port from the same host. + * Fixed a bug in 'utils/rmlsend.cpp' that was causing the + 'Response:' field to report failed responses even when echoing was + turned off. + * Incremented the version number to 0.6.1. +2003-01-19 Fred Gleason + * Added a 'CART.MACROS' field to the database. + * Incremented the database version to 20. + * Added an 'RDMacroEvent' class in 'lib/rdmacro_event.cpp'. + * Fixed a bug in 'rdadmin/createdb.cpp' that was causing creation + of a new database to fail. +2003-01-19 Fred Gleason + * Fixed a bug in 'lib/rdripcd.cpp' that was causing user updates + to fail. + * Added a 'Type' selector to the Add Cart dialog in RDLibrary. + * Created an 'AudioCart' widget in 'rdlibrary/audio_cart.cpp'. + * Reworked the code in 'rdlibrary/rdlibrary.cpp', + 'rdlibrary/edit_cart.cpp' and 'rdlibrary/add_cart.cpp' to provide + a consistent list view interface. + * Added an 'updateLength()' method to 'lib'rdcart.cpp'. + * Created a 'MacroCart' widget in 'rdlibrary/macro_cart.cpp'. + * Created an 'EditMacro' dialog in 'rdlibrary/edit_macro.cpp'. +2003-01-20 Fred Gleason + * Added 'exec()' methods to 'lib/rdmacro_event.cpp'. + * Added 'started()' and 'finished()' signals to + 'lib/rdmacro_event.cpp'. + * Added the 'Sleep' macro ('SP') to 'lib/rdmacro.cpp'. + * Added a 'docs/implemented_macros.txt' file. +2004-01-20 Fred Gleason + * Added a 'RECORDINGS.MACRO_CART' field to the database. + * Removed the 'EVENTS' table from the database. + * Incremented the database version to 21. + * Added 'macroCart()' and 'setMacroCart()' methods to + 'lib/rdrecording.cpp'. + * Added logic to 'lib/rdcut_dialog.cpp' so as to only display + audio carts when picking an audio cut. + * Removed the 'DECKS.SWITCH_TYPE' and 'DECKS.TTY_ID' fields from + the database. + * Added 'DECKS.SWITCH_STATION', 'DECKS.SWITCH_MATRIX', + 'DECKS.SWITCH_OUTPUT' and 'DECKS.SWITCH_DELAY' fields to the + database. + * Incremented the database version to 22. + * Removed the 'SwitchType' enum from 'lib/rddecks.h' + * Removed 'switchType()', 'setSwitchType()', 'ttyId()' and + 'setTtyId()' methods from 'lib/rddecks.h'. + * Added 'switchStation()', 'setSwitchStation()', 'switchMatrix()', + 'setSwitchMatrix()', 'switchOutput()', 'setSwitchOutoput()', + 'switchDelay()' and 'setSwitchDelay()' methods to + 'lib'rddeck.cpp'. + * Removed the 'EditSources' class in 'rdadmin/edit_sources.cpp'. + * Removed the 'EditSource' class in 'rdadmin/edit_source.cpp'. + * Removed the 'AddSource' class in 'rdadmin/add_source.cpp'. + * Added 'switchMatrixName()' and 'switchOutputName()' methods to + 'lib/rddeck.cpp'. + * Removed the 'RDSource' class in 'lib/rdsource.cpp'. + * Removed the 'SOURCES' table from the database. + * Added a 'RECORDINGS.SWITCH_INPUT' field to the database. + * Incremented the database version to 23. + * Removed the 'source()' and 'setSource()' methods from + 'lib/rdrecordings.cpp'. + * Added 'switchSource()' and 'setSwitchSource()' methods to + 'lib/rdrecordings.cpp'. + * Added an 'EditCartEvent' class in 'rdcatch/edit_cartevent.cpp'. +2004-01-22 Fred Gleason + * Fixed a bug in 'lib/cart_dialog.cpp' that was causing all cart + types to be displayed even when requesting only macro carts. + * Changed the 'RDCartDialog' widget in 'lib/rdcart_dialog.cpp' so + that a double-click on a cart now implies a click of the 'OK' + button as well. + * Added logic to RDCatch to grey out the audio transport buttons + when a cart event is highlighted. + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was failing to clear a + day of the week flag after deselecting that day from an event. +2004-01-22 Fred Gleason + * Added 'rivendell.spec.in' to EXTRA_DIST. + * Released as v0.7.0. +2004-01-23 Fred Gleason + * Added a 'tests/' directory. + * Added a torture test for the SAS32000 router in + 'tests/sas_torture.cpp'. +2004-01-26 R F + * Changed RDLogEdit to open a log when double clicking it's entry. +2004-01-26 Dan Mills + * Fixed a bug in 'rdairplay/list_log.cpp' that was causing a + segfault when attempting to change the scroll mode on an empty log + machine. +2004-01-26 Fred Gleason + * Added an 'sas_shim' daemon in 'utils/'. + * Added 'RECORDINGS.TYPE' and 'RECORDINGS.SWITCH_OUTPUT' fields to + the database. + * Incremented the database version to 24. + * Added 'type()', 'setType()', 'switchDestination()' and + 'setSwitchDestination()' methods to 'lib/rdrecrodings.cpp'. + * Added an 'EditSwitchEvent' widget in + 'rdcatch/edit_switchevent.cpp'. +2004-01-27 Fred Gleason + * Added 'RA', 'RR' and 'RU' commands to the RDCatchd control + protocol. + * Added 'addEvent()', 'removeEvent()' and 'updateEvent()' slots to + 'lib'rdcatch_connect.cpp'. + * Added a torture test for the SAS32000 router in + 'tests/sas_switch_torture.cpp'. + * Incremented version to v0.7.1. +2004-01-27 Fred Gleason + * Add support for an SAS64000 switcher (via GPI-1600 port) to + RDAdmin. + * Added a switcher driver for the SAS64000 (GPI port) in + 'ripcd/sas64000gpi.cpp'. + * Incremented the version to v0.7.2. +2004-01-28 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing the + events list to be trashed when an 'RU' command was processed. + * Added a 'RECORDINGS.IS_ACTIVE' field to the database. + * Overhauled the day-of-the-week indices in the 'RECORDINGS' table + to work properly with the new database structure. + * Incremented the database version to 25. + * Added 'docs/implemented_macros.txt' to the %doc% list in + 'rivendell.spec.in'. + * Incremented the RPM release level to '2'. + * Added an 'Active' column to the RDCatch event list. + * Added 'isActive()' and 'setIsActive()' methods to + 'lib/rdrecording.cpp'. + * Added an 'Event Active' checkbox to the event editor dialogs in + RDCatch. + * Changed the 'Cart Number' field in RDCatch->EditCartEvent so as + to allow manual entry of a cart number. + * Incremented the version number to v0.7.3. +2004-01-28 Fred Gleason + * Added an events import filter in 'utils/sas_filter.cpp'. +2004-01-28 Fred Gleason + * Added a 'CatchEvent' container class in + 'rdcatchd/catch_event.cpp'. + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was causing the 'RU' + daemon command to be issued with an invalid argument. + * Rewrote RDCatchd to eliminate the need for an event list reload + at midnight. + * Modified 'rivendell' init script to be compliant with LSB 1.3. + * Fixed a bug in 'ripcd/local_macros.cpp' that was causing a + segfault when starting up with no switcher matrices defined. + * Removed the 'SUN_IDX', 'SAT_IDX', 'MON_IDX', 'TUE_IDX', + 'WED_IDX', 'THU_IDX' and 'FRI_IDX' indices from the 'RECORDINGS' + table. + * Fixed a bug in 'rdadmin/createdb.cpp' that was causing creation + of a new database to fail. + * Incremented the database version to 26. +2004-01-28 Fred Gleason + * 'utils/sas_shim' to 'rivendell.spec.in'. + * Created a boot script for 'sas_shim' in 'utils/rc.sas_shim'. + * Incremented the RPM build version to 3. + * Incremented the version number to v0.7.4. +2004-01-30 Fred Gleason + * Fixed a typo in 'configure.in' that was causing 'make rpm' to + fail when used with pre-4.x versions of the rpm tools. + * Incremented the version to v0.7.5. +2004-01-30 Fred Gleason + * Added a qmake configuration to allow RMLSend to be built under + Qt-Windows. + * Fixed a bug in 'utils/rmlsend.cpp' that was causing the title bar + to be obscured under Windows. +2004-02-02 Fred Gleason + * Increased the maximum number of GPIO lines per matrix to 96. + * Removed 'EVENTS' table from the database. + * Added a 'GPIS' table to the database. + * Incremented the database version to 27. + * Added an 'ListGpis' dialog in 'rdadmin/list_gpis.cpp'. + * Added an 'EditGpi' dialog in 'rdadmin/edit_gpi.cpp'. + * Added an 'Execute' RML command ('EX') to /docs/rml.sxw'. + * Added the 'EX' command to 'lib/rdmacro.cpp'. + * Added the 'GI' command to 'lib/rdmacro.cpp'. + * Added an 'ExecuteMacroCart()' method to 'rdcatchd/rdcatchd.cpp'. + * Added 'Execute' RML command to 'docs/implemented_macros.txt'. + * Incremented the version to v0.7.6. +2004-02-03 Fred Gleason + * Fixed a bug in 'ripcd/ripcd.cpp' that was preventing RML command + echos from being properly processed. + * Fixed a bug in 'ripcd/sas32000.cpp' that was preventing an error + echo when sent a 'GO' command. + * Added the 'GPI Set' ('GI') RML command to + 'docs/implemented_macros.txt'. + * Changed the definition of the 'GPI Enable' ('GE') command so as + to support only individual lines as arguments. + Add the 'GE' macro mneumonic to 'rdmacro.cpp'. + * Added the 'GPI Enable' ('GE') RML command to + 'docs/implemented_macros.txt'. + * Added the 'Serial Output' ('SO') command to 'lib/rdmacro.cpp'. + * Documented the 'Serial Reset ('SY') command in 'docs/rml.sxw'. + * Added the 'Serial Reset' ('SY') command to 'lib/rdmacro.cpp'. + * Add the 'Serial Output' ('SO') command to + 'docs/implemented_macros.txt'. + * Incremented the version to 'v0.7.7'. +2004-02-04 Fred Gleason + * Added a 'Clear Serial Trap' ('SC') RML command to + 'docs/rml.sxw'. + * Added the 'Insert Serial Trap' ('SI') and 'Clear Serial Trap' + ('SC') RML commands to 'lib/rdmacro.cpp'. + * Added the 'Insert Serial Trap' ('SI') and 'Clear Serial Trap' + ('SC') RML commands to 'docs/implemented_macros.txt'. + * Added the 'UDP Out' ('UO') RML command to 'lib/rdmacro.cpp'. + * Added the 'UDP Out' ('UO') RML command to + 'docs/implemented_macros.txt'. +2004-02-05 Fred Gleason + * Added a switcher driver for the Broadcast Tools SS 8.2 Dual + Stereo Audio Switcher in 'ripcd/btss82.cpp'. + * Fixed a bug in 'rdadmin/edit_ttys.cpp' where the ripcd(8) + switcher drivers were not receiving notification of changes in TTY + parameters. + * Changed the default number of GPO lines for the BtSs82 driver + from 16 to 8. + * Added a 'docs/SWITCHERS.txt' file for switcher application + notes. + * Incremented the RPM build version to 4. +2004-02-05 R F + * Fixed a bug in 'rdlibrary/edit_cart.cpp' that was causing + duplicate entries to appear in the 'Schedule Cuts' combo box. +2004-02-05 Fred Gleason + * Added a 'no argument' version of the 'Login' RML command to + 'docs/rml.sxw'. + * Added the 'Login' ('LO') RML command to 'lib/rdmacro.cpp'. + * Added the 'Login' ('LO') RML command to + 'lib/implemented_macros.txt'. +2004-02-05 Fred Gleason + * Incremented the version number of 'docs/rml.sxw to '0.1.0'. + * Added a 'RunLocalMacros()' method in + 'rdairplay/local_macros.cpp'. + * Added the 'Label' ('LB') RML command to 'lib/rdmacro.cpp'. + * Added the 'Label' ('LB') RML command to + 'docs/implemented_macros.txt'. +2004-02-11 Fred Gleason + * Changed the default value of all time/date values in the + database to NULL. + * Added a 'valid' parameter to the 'startDateTime()', + 'endDateTime()', 'setStartDateTime()', 'setEndDateTime()', + 'startDaypart()', 'endDaypart()', 'setStartDaypart()' and + 'setEndDaypart()' methods in 'lib/rdcut.cpp'. + * Incremented the database version to 28. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing + recordings to fail in RDCatch. +2004-02-12 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was appending an audio + deck number to the 'Location' values for non-recording events. + * Added an icon for each event listed in RDCatch's event list to + indicate the type of event. + * Moved the 'Source' column in RDCatch's event list to be adjacent + to the 'Destination' column. + * Changed the logic in RDCatch so that Switch Events will display + the programmed switcher output name in the 'Destination' column. + * Moved the display of the programmed cart number for a Macro Cart + Event from the 'Destination' to the 'Source' column in RDCatch. +2004-02-15 Fred Gleason + * Added a sample ALSA '.asoundrc' in '/conf/alsa.conf'. +2004-02-16 Fred Gleason + * Added a 'backgroundColor()' method to 'lib/rdlistviewitem.cpp'. + * Fixed a bug in 'lib/rdlistviewitem.cpp' that was causing text to + be incorrectly aligned. + * Added the ability to display pixmap objects with RDListViewItem. + * Added color definitions for RDCatch in 'rdcatch/colors.h'. + * Added the ability to report on the status of active events in + realtime to RDCatch. + * Added 'status()' and 'setStatus()' methods to + 'lib/catch_event.cpp' + * Added a 'refresh()' slot to 'lib/rdcatch_connect.cpp'. +2004-02-16 Fred Gleason + * Reordered the linker arguments in 'cae/Makefile.am', + 'rdlibrary/Makefile.am' and 'utils/Makefile.am' so as to get + things to link to 'RRingBuffer'. +2004-02-17 Fred Gleason + * Added a 'nextEventData()' slot to 'rdcatch/rdcatch.cpp'. + * Added a 'ShowNextEvents()' method ot 'rdcatch/rdcatch.cpp'. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing a + completed macro event to fail to clear it's status from 'active' + in the events list. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing a + completed record event to fail to clear it's status from 'active' + in the events list. + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was causing the Head, + Tail and Stop Audition buttons to be incorrectly enabled/disabled. +2004-02-17 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing a + completed macro event with no 'SP' commands to fail to clear it's + status from 'active' in the events list. + * Updated the icons in 'rdcatch/macro_xmp.cpp', + rdcatch/swtich_xmp.cpp' and 'rdcatch/record_xpm.cpp'. +2004-02-19 Fred Gleason + * Fixed a bug in 'lib/rdcardselector.cpp' that was causing the + widget to display an incorrect size. + * Added a section for configuring Play Decks to + RDAdmin->ManageStations->RDCatch. + * Added 'Playout' to the 'RDRecording::Type' enumeration. + * Added logic to 'rdcatch/deck.cpp' to properly display Play Deck + status. + * Added an 'EditPlayout' dialog in 'rdcatch/edit_playout.cpp'. + * Added an icon for a Playout Event in 'rdcatch/playout_xpm.cpp'. + * Fixed a bug in 'lib/rdcae.cpp' that was causing the + 'playUnloaded()' signal to fail to be emitted. + * Added a 'serial' parameter to the 'meterLevel()' signal in + 'lib/rdcatch_connect.cpp'. +2004-02-19 Fred Gleason + * Reworked 'cae/cae.cpp' so as to use a global 'RSoundCard' + object. + * Reworked 'rdlibrary/edit_audio.cpp' so as to use a global + 'RSoundCard' object. + * Reworked 'utils/rdplay.cpp' so as to use a global 'RSoundCard' + object. + * Reworked 'utils/rdrecord.cpp' so as to use a global 'RSoundCard' + object. + * Added an 'icons/' directory. + * Added 'play.xpm', 'record.xpm', 'macro.xpm' and 'switch.xpm' + icons in 'icons/'. + * Incremented the version number to '0.7.9'. +2004-03-01 Fred Gleason + * Made RDCatch resizable. + * Added logic to 'rdcatch/edit_recording.cpp' so as to use the + Cart/Cut name as the desfault description for an event. + * Added a 'RECORDINGS.EXIT_CODE' field to the database. + * Incremented the database version to 29. + * Added an 'ExitCode' enumeration to 'lib/rdrecording.h'. + * Fixed a bug in 'lib/rdcut_dialog.cpp' that was causing cut + selection to fail unpredictably. + * Fixed a bug in 'lib/rdcut_dialog.cpp' that was causing the + default cart and cart selections to fail to be highlighted. + * Added a 'RECORDINGS.ONE_SHOT' field to the database. + * Incremented the database version to 30. + * Added 'oneShot()' and 'setOneShot()' methods to + 'lib/rdrecording.cpp'. + * Added a 'PE' (Purge Event) command to 'docs/catchd.txt'. + * Added an 'eventPurged()' signal to RDCatchConnect. + * Added a 'Make OneShot' checkbox to the event editor dialogs in + RDCatch. + * Added 'oneShot()' and 'setOneShot()' methods to + 'rdcatchd/catch_event.cpp'. +2004-03-01 Fred Gleason + * Incremented version number to 0.7.10. +2004-03-08 Fred Gleason + * Fixed a bug in 'rdlibrary/edit_cart.cpp' that was generating + 'Invalid Date' errors when the widget was closed. + * Added code to 'lib/rdlist_log.cpp' to allow a log to be selected + for loading by a doubleclick. + * Fixed a bug in 'rdairplay/loglinebox.cpp' that was causing the + type icon to fail to be cleared. + * Added a 'LogLine()' function to 'rdairplay/rdairplay.cpp'. + * Added cart type icons to RDLibrary. + * Added cart type icons to RDCartDialog. + * Added cart type icons to RDCutDialog. + * Added a Marker icon in 'icons/marker.xpm'. + * Added support for macro carts to 'lib'rdlog_event.cpp. + * Added support for macro carts to RDLogEdit. + * Fixed a bug in 'lib/rdcart_dialog.cpp where a previously + selected card would not be selected by default. + * Added cart type icons to RDAirPlay. +2004-03-09 Fred Gleason + * Added 'line()' and 'setLine()' methods to + 'lib/rdmacro_event.cpp'. + * Added 'macroStartedData()' and 'macroFinishedData()' slots to + 'rdairplay/log_play.cpp'. + * Added 'startTime()' and 'setStartTime()' methods to + 'lib/rdmacro_event.cpp'. +2004-03-16 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing invalid + start times to be displayed for Marker and Macro events. + * Fixed a bug in 'rdairplay/logline_box.cpp' that was causing + metadata for macro carts to fail to appear. + * Added logging to 'caed'. + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was causing the + TITLE field to fail to update after changing a cart on the log + list. +2004-03-30 Fred Gleason + * Added a 'STATIONS.TIME_OFFSET' field to the database. + * Incremented the database version to 31. + * Added 'timeOffset()' and 'setTimeOffset()' methods to + 'lib/rdstation.cpp'. + * Added a 'Time Offset' spinbox to RDAdmin->ManageStations. + * Added time offset support to RDCatch, RDCatchd and RDAirPlay. + * Fixed a buffer overflow bug in 'lib/rdcatch_connect.cpp'. + * Fixed a bug in 'rdcatch/rdcatch.cpp' where the incorrect default + background color was set for events. + * Fixed a bug in 'rdcatch/deckmon.cpp' where the Abort button + would remain disabled during a Record or Playout event. +2004-03-30 Fred Gleason + * Incremented the version to 0.7.11. +2004-04-01 Fred Gleason + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that was corrupting the + cart list when a new cart was created. + * Incremented the version to 0.7.13. +2004-04-06 Fred Gleason + * Fixed a bug in 'rdadmin/edit_rdlibrary.cpp' that was causing the + 'Port' field in the Input and Output selectors to be obscured. + * Fixed a bug in 'lib/rdlog_event.cpp' that was causing Cart + events to be erroneously created as Marker events. + * Changed the Log Line Editor in RDLogEdit so that it's now + possible to enter a cart number directly. + * Added a check to 'rdairplay/rdairplay.cpp' to suppress display + of the playback meter if the selected sound card does not support + output level metering. +2004-04-07 Fred Gleason + * Increased the size of the play meter in RDAirPlay. + * Rearranged the cart filter to sort seperately by fields and cart + group in RDLibrary, RDCatch and RDLogEdit. + * Made RDLibrary resizable. +2004-04-08 Fred Gleason + * Rearranged and added the rest of the CART database fields to the + cart list in RDLibrary. + * Added 'GROUPS.DEFAULT_LOW_CART' and 'GROUPS.DEFAULT_HIGH_CART' + fields to the database. + * Added 'defaultLowCart()', 'setDefaultLowCart()', + 'defaultHighCart()' and 'setDefaultHighCart()' methods to + 'lib/rdgroup.cpp'. + * Added controls to specify the default cart range to + RDAdmin->ManageGroups. + * Added a 'Groups' control to the Add Cart dialog in RDLibrary. + * Added 'CUTS.SUN', 'CUTS.MON', 'CUTS.TUE', 'CUTS.WED', 'CUTS.THU' + 'CUTS.FRI' and 'CUTS.SAT' fields to the database. + * Incremented the database version to 33. + * Added 'dayPart()' and 'setDayPart()' methods to 'lib/rdcut.cpp'. + * Added a 'Day of the Week' daypart section to the Record/Label + widget in RDLibrary. + * Fixed a bug in 'rdlibrary/record_audio.cpp' where the tenths + digit of the record timer was being clipped. + * Added 'ShowAudioCarts' and 'ShowMacroCarts' checkboxes to the + filter section of the main window in RDLibrary. + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that was causing + deletion of carts to fail. +2004-04-09 Fred Gleason + * Added a logfile capability to ripcd(8). + * Fixed a bug in 'rdlibrary/add_cart.cpp' where a new cart was + being created with the incorrect group membership. + * Incremented the version to 0.7.14. +2004-04-12 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was causing the + rdcatchd(8) daemon to fail to receive event updates from RDCatch + when the workstation was configured without any record of playback + decks. + * Added code to disable to 'Recording' and 'Playout' buttons in + the 'Add Event' dialog in RDCatch when no Record or Playout decks + respectively are defined. + * Fixed a bug in rdcatch/rdcatch.cpp' that was causing the frame + of the lowermost Record/Play deck to be clipped by the filter + checkboxes. + * Optimized the Active Events and Today's Events filters in + RDCatch. + * Incremented the version number to 0.7.15. +2004-04-13 Fred Gleason + * Made the default group in the 'Add Cart' dialog persistent + within a single invocation of RDLibrary. + * Adjust the fonts used for day-of-the-week in RDLibrary's Record + widget to be consistent with the rest of the dialog. +2004-04-13 Fred Gleason + * Reimplemented Segue transitions in RDAirPlay. +2004-04-13 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing One Shot + events to be incompletely purged from the capture daemon. + * Incremented the version to 0.7.16. +2004-04-15 Fred Gleason + * Made major changes to RDAirPlay to restore left-side button + functionality. +2004-04-15 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing events + in the middle of a Segue transition to be incorrectly displayed. + * Fixed a bug in 'lib/rdcart.cpp' that was causing RDAirPlay to + segfault when attempting to load a log containing events with + Random cut rotation enabled. +2004-04-15 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing the + 'Next Event' property in RDAirPlay's log machines to fail to be + reset upon loading of a new log. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing Macro + Carts to hang in the 'Playing' state. + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing + erratic operation of the pie widget. +2004-04-18 Fred Gleason + * Added 'portName()' and 'setPortName()' methods to + 'lib/rdlog_line.cpp'. + * Restored the port number identifier to the play buttons in + RDAirPlay. +2004-04-18 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing the + button start times to be incorrect. +2004-04-18 Fred Gleason + * Added a 'GRACE_TIME' field to the log table format. + * Added 'graceTime()' and 'setGraceTime()' methods to + 'lib/rdlog_line.cpp'. + * Rearranged the event time controls in + RDLogEdit->EditLog->EditLine to use the new 'grace time' paradigm. + * Fixed a bug in 'rdairplay/rdairplay.cpp' where the pie counter + was failing to count down to the cart transition time when + configured to do so. + * Fixed a bug in 'rdairplay/list_log.cpp' that was causing the + start times for all played events to be listed as '00:00:00'. +2004-04-19 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' and + 'rdairplay/list_log.cpp' whereby events inserted into the 'next + event' area of the full log widget would be to colored green. + * Restored operation of the manual segue length parameter in + RDAirPlay. +2004-04-19 Fred Gleason + * Fixed multiple bugs in RDAirPlay that was causing incorrect + processing of seque transitions. +2004-04-28 Fred Gleason + * Added the ability to RDAirPlay to load and execute macro carts + in sound panel buttons. +2004-04-28 Fred Gleason + * Stubbed out RDPanel in 'rdpanel/'. +2004-04-28 Fred Gleason + * Implemented a heartbeat pulse command ('HB') in + 'rdcatchd/rdcatchd.cpp'. + * Added a 'heartbeatFailed()' signal to 'lib/catch_connect.cpp'. + * Added code to RDCatch to generate a warning dialog in the event + of a heartbeat timeout to one of the RDCatchd daemons. +2004-04-28 Fred Gleason + * Changed the Edit Switch Event dialog in RDCatch so that + Matrices, Inputs and Outputs are now listed alphabetically. + * Incremented the version to 0.7.17. +2004-04-28 Fred Gleason + * Added RDPanel to the RPM spec file. +2004-04-29 Fred Gleason + * Added a file import script in 'scripts/rd_import_file'. + * Added a file import dialog in 'rdlibrary/import_audio.cpp'. +2004-05-03 Fred Gleason + * Fixed a bug in 'scripts/rd_import_file that was causing PCM16 + output to be incorrectly formatted. + * Added a dependency for 'mysql-shared' to 'riendell.spec.in'. + * Incremented the RPM build version to 5. + * Added additional debug logging to rdcatchd/rdcatchd.cpp'. +2004-05-03 Fred Gleason + * Added the ability to specify directly the input or output + numbers in the RDCatch->EditSwitchEvent. + * Fixed multiple bugs in 'rdlogedit/edit_log.cpp' affecting proper + focus handling. + * Incremented the version to 0.7.18. +2004-05-04 Fred Gleason + * Changed the 'librd' convience library over to use dynamic + linking. + * Incremented the RPM build version to 6. + * Implemented time transitions in RDAirPlay. + * Fixed a bug in 'rdlogedit/edit_log.cpp' where changing the time + field for an event would fail to update when changed from a hard + to a relative time transition. + * Added an 'RDAIRPLAY.TRANS_LENGTH' field to the database. + * Incremented the database version to 35. + * Added 'transLength()' and 'setTransLength()' methods to + 'lib/rdairplay_conf.cpp'. + * Added a 'Forced Segue' control to RDAdmin->Stations->RDAirPlay. + * Fixed a bug in 'rdairplay/loglinebox.cpp' in which a Relative + time would be incorrectly displayed. +2004-05-05 Fred Gleason + * Fixed a bug in 'lib/rdlog_event.cpp' that was causing the + incorrect grace time value to be loaded for log events. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing the + 'Forced Segue' setting to be ignored. + * Fixed a bug in 'rdairplay/button_log.cpp' which all running + events would get scrollbars marked red, instead of just the last + event. +2004-05-06 Fred Gleason + * Implemented the Set Mode [PM] macro. + * Implemented the Push Button [PB] macro. + * Implemented the Make Next [MN] macro. + * Implemented the Start [PL] macro. + * Implemented the Start Next [PN] macro. + * Added a 'stop()' method to 'rdairplay/log_play.cpp'. + * Implemented the Stop [PS] macro. +2004-05-06 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + segfault when adding a new event. + * Implemented the Add Next [PX] macro. +2004-05-07 Fred Gleason + * Incremented the version to 0.7.19. +2004-05-10 Fred Gleason + * Fixed bugs in 'rdcatch/edit_recording.cpp', + 'rdcatch/edit_playout.cpp', 'rdcatch/edit_macroevent.cpp' and + 'rdcatch/edit_switchevent.cpp' where pressing the ESC key would + create a corrupt event record in the RDCatch database. +2004-05-10 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp' where the Scroll button + wouldn't work until after at least one event had been modified. + * Fixed a bug in 'rdcatch/edit_switchevent.cpp' where the Input or + Output number controls would display the incorrect value some + certain circumstances. +2004-05-10 Fred Gleason + * Implemented the Select Widget [PW] macro. + * Added 'setButton()', 'play()', and 'stop()' methods to + 'rdairplay/sound_panel.cpp'. + * Implemented the Play Panel [PP] macro. + * Implemented the Stop Panel [PT] macro. + * Implemented the Load Panel [PE] macro. + * Fixed a bug in 'lib/rdripc.cpp' that was causing random + segfaults when receiving an RML with more than ten arguments. + * Incremented the version to 0.7.20. +2004-05-12 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing general + trainwreck when moving events in a running log. +2004-05-12 Fred Gleason + * Fixed a bug in 'rdairplay/button_log.cpp' that was causing + corrupt button status readouts. + * Added a 'copy()' method to 'rdairplay/log_play.cpp'. + * Implemented the 'Copy' button in RDAirPlay. + * Fixed a bug in 'rdairplay/local_macros.cpp' that was causing + duplicate execution of received macros. + * Implemented the Load Log [LL] macro. +2004-05-12 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing macros + to handle segue transitions incorrectly. + * Fixed a bug in 'rdairplay/button_log.cpp' that was causing start + button start times to be incorrect. +2004-05-13 Fred Gleason + * Fixed a bug in 'rdiarplay/log_play.cpp' that was causing + segfaults when loading a log while playing events. +2004-05-13 Fred Gleason + * Fixed a bug in 'rdairplay/button_log.cpp' where pressing the + Add/Del/Move/Copy buttons would select an active event button + as as potential destination. + * Fixed a bug in 'rdairplay/button_log.cpp where a change in + transport state would result in incorrect start button displays if + in Add/Del/Move/Copy mode. + * Fixed a bug in 'lib/rdlog_event.cpp' that was preventing the + move of an event to the end of a log. + * Implemented sanity checks for the Add/Del/Move/Copy buttons in + the full log widget of RDAirPlay. +2004-05-14 Fred Gleason + * Incremented the version to 0.7.21. +2004-05-18 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + segfault when attempting to execute a Load Log macro that was not + the final event in the log. + * Added code to allow insertion of an event at the end of a log in + RDAirPlay's button widget. + * Fixed a bug that was causing audio file imports to fail if the + pathname of the source file contained one or more spaces. +2004-05-18 Fred Gleason + * Added a 'length()' method to 'lib/rdmacro_event.cpp'. + * Added a 'lengthChanged()' signal to 'rdlibrary/macro_cart.cpp'. + * Added code to 'rdlibrary/edit_cart.cpp' and + 'rdlibrary/macro_cart.cpp' to display the length of a macro cart. + * Fixed a bug in 'rdairplay/loglinebox.cpp' where the length of a + macro cart would be incorrectly displayed. + * Stubbed out a 'Save As' button for RDLogEdit. +2004-05-19 Fred Gleason + * Finished implementing the 'Save As' button for RDLogEdit. + * Implemented a 'Save' button for the Log Editor in RDLogEdit. + * Added a warning dialog when pressing the 'Cancel' button in + RDLogEdit's Log Editor. +2004-05-19 Fred Gleason + * Added a 'POST_POINT' field to the log table format. + * Incremented the database version to 36. + * Added 'postPoint()' and 'setPostPoint()' methods to + 'lib/rdlog_line.cpp'. + * Fixed a bug in 'lib/rdlog_line.cpp' that was leaving the 'grace + time' parameter uninitialized. + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' that was causing a + segfault when trying to insert a new event in a blank log. + * Added a 'Make Post Point' check box to the log event editor in + RDLogEdit. + * Reworked the Marker Editor in RDLogEdit to use the new style + event time/post point scheme. +2004-05-20 Fred Gleason + * Modified 'rdairplay/loglinebox.cpp' to use the new post point + scheme. + * Modified 'rdairplay/list_log.cpp' to use the new post point + scheme. + * Modified 'rdairplay/log_play.cpp' to use the new post point + scheme. + * Removed code for the old post point scheme from + 'rdlogedit/edit_marker.cpp'. + * Removed the 'postTime()' and 'setPostTime()' methods from + 'lib/rdlog_event.cpp'. +2004-05-20 Fred Gleason + * Modified 'rdairplay/edit_event.cpp' to use the new post point + scheme. + * Modified 'rdairplay/loglinebox.cpp' to use the new post point + scheme. + * Incremented the version to 0.7.22. +2004-05-21 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + segfault when executing a macro cart as the last event in a log. + * Fixed a bug in 'rdlogedit/edit_logline.cpp' that was causing + phantom relative start times to generated for events. + * Fixed a bug in 'rdlogedit/edit_marker.cpp' that was causing + phantom relative start times to generated for events. +2004-05-21 Fred Gleason + * Rewrote the 'segueLength()' and 'segueTail()' methods in + 'lib/rdlog_line.cpp' to provide dynamic values. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing changes + in event transition types to be ignored. + * Removed a bunch of dead code from 'rdairplay/loglinebox.cpp'. + * Fixed a bug in 'rdairplay/loglinebox.cpp' whereby doubleclicking + an active event would bring up a modify window. +2004-05-21 Fred Gleason + * Added code to 'rdairplay/rdairplay.cpp' to allow events to be + copied and moved between logs. +2004-05-26 Fred Gleason + * Added a 'cae/cae_hpi.cpp' file to abstract the HPI CAE driver + implementation. +2004-05-26 Fred Gleason + * Removed GPIO support from 'cae/cae.cpp'. +2004-06-01 Fred Gleason + * Modified 'cae/cae.cpp' to implement version 0.8 of the CAE + protocol, using automatic stream management. + * Modified 'lib/rdcae.cpp' to use the new CAE protocol. + * Modified rdlibrary/record_audio.cpp' to use the new CAE + protocol. + * Modified 'rdcatch/rdcatch.cpp' to use the new CAE protocol. + * Modified 'rdcatchd/rdcatchd.cpp' to use the new CAE protocol. + * Modified 'lib/rdplay_deck.cpp' to use the new CAE protocol. + * Added 'setInputVolume()', 'setOutputVolume()', + 'fadeOutputVolume()', 'setInputLevel()', 'setOutputLevel()', + 'setInputMode()', 'setOutputMode()', 'setInputVOXLevel()', + setInputType()', 'inputStatus()', 'enableMetering()', + 'inputMeterUpdate()' and 'outputMeterUpdate()' methods to + 'lib/rdcae.cpp'. + * Added an 'inputStatusChanged()' signal to 'lib/rdcae.cpp'. + * Modified the 'RDSetMixerOutputPort()' and 'RDSetMixerPorts()' + functions in 'lib/rdmixer.cpp' to use the new CAE mixer calls. + * Removed all 'RSound' library dependencies from RDAirPlay. + * Removed all 'RSound' library dependencies from RDAdmin. + * Removed all 'RSound' library dependencies from RDLibrary. + * Removed all 'RSound' library dependencies from RDCatch. + * Removed all 'RSound' library dependencies from RDCatchd. + * Removed all 'RSound' library dependencies from RDLogEdit. + * Removed all 'RSound' library dependencies from RDLogin. + * Removed all 'RSound' library dependencies from RDPanel. + * Removed all 'RSound' library dependencies from ripcd. + * Removed RDPlay, RDRecord and mpeg2wav from the 'utils/' + directory. + * Incremented the RPM release version to 7. +2004-06-01 Fred Gleason + * Converted 'rdairplay/rdairplay.cpp' to use the new mixer calls + in RDCae. + * Converted 'lib/rdplay_deck.cpp' to use the new mixer calls + in RDCae. + * Converted 'rdlibrary/record_cut.cpp' to use the new mixer calls + in RDCae. +2004-06-01 Fred Gleason + * Changed Cae to use RD_MAX_CARDS and RD_MAX_STREAMS instead of + it's own internal size values. + * Increased RD_MAX_STREAMS to 16. +2004-06-02 Fred Gleason + * Fixed a bug in 'cae/cae.cpp' that was causing the 'SR' signal to + fail to be emitted at end of recording. + * Fixed a bug in 'cae/cae_hpi.cpp' that was causing the 'SR' + signal to be emitted when unloading an already stopped recording. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing the + length of a new recording to fail to be updated. + * Restored metering functionality in RDCatch. + * Fixed a port allocation bug in 'rdcatch/rdcatch.cpp'. +2004-06-02 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp' wherein the background + color of a past event was incorrect. +2004-06-02 Fred Gleason + * Reworked the configure script so as to allow simultaneous HPI + and JACK configuration. + * Removed MAD support from the build system. + * Stubbed out a JACK driver for CAE in 'cae/cae_jack.cpp'. +2004-06-03 Fred Gleason + * Fixed a bug in 'cae/cae_hpi.cpp' that prevented 'SP' signals + from being emitted. + * Fixed a bug in 'cae/cae.cpp' that falsely returned errors for an + 'LP' operation. + * Completed stubbing out JACK support in CAE. +2004-06-04 Fred Gleason + * Updated 'docs/cae.sxw' to protocol version 0.9. + * Modified CAE to use CAE protocol v0.9. + * Modfield RDCae to use CAE protocol v0.9. + * Modified RDLibrary to use CAE protocol v0.9. + * Modified RDCatchd to use CAE protocol v0.9. +2004-06-04 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing active + Playout Events to not show up as active in RDCatch. + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was causing Tail + Audition Playout to sporadically fail. +2004-06-05 Fred Gleason + * Removed the 'hpiPlayState()' and 'hpiRecordState()' slots from + 'cae/cae.h'. +2004-06-07 Fred Gleason + * Stubbed out RDLogManager in 'rdlogmanager/'. + * Incremented the RPM Release to 8. + * Added a 'LOGS.TYPE' field to the database. + * Incremented the database version to 37. + * Updated 'lib/rdlist_logs.cpp' to use the new database field. + * Added 'type()' and 'setType()' methods to 'lib/rdlog.cpp'. + * Updated 'rdlogedit/edit_log.cpp' to use the new database field. + * Updated 'rdlogedit/rdlogedit.cpp' to use the new database field. + * Updated 'rdairplay/local_macros.cpp' to use the new database field. +2004-06-08 Fred Gleason + * Added an 'EVENTS' table to the database. + * Created an 'RDEvent' class in 'lib/rdevent.cpp'. + * Created an 'AddEvent' dialog in 'rdlogmanager/add_event.cpp'. +2004-06-09 Fred Gleason + * Made the 'caed', 'ripcd' and 'rdcatchd' SETUID root. + * Moved the location of the PID files to '/var/run/rivendell/'. +2004-06-09 Fred Gleason + * Added a 'LibListView' class in 'rdlogmanager/lib_listview.cpp' + * Added an 'ImportListView' class in + 'rdlogmanager/import_listview.cpp' +2004-06-10 Fred Gleason + * Completed implementing the 'ImportListView' class. +2004-06-10 Fred Gleason + * Transposed the values for 'RDLogLine::Stop' and + 'RDLogLine::Segue'. + * Modified 'rdairplay/edit_event.cpp' to be compatible with the + revised RDLogLine::TransType values. + * Modified 'rdlogedit/edit_logline.cpp' to be compatible with the + revised RDLogLine::TransType values. + * Modified 'rdlogmanager/edit_event.cpp' to be compatible with the + revised RDLogLine::TransType values. + * Incremented the database version to 39. + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was causing logs to + fail to load and save properly. + * Fixed a bug in 'rdlogedit/list_log.cpp' that was causing logs to + fail to load properly. +2004-06-10 Fred Gleason + * Added logic to properly enforce transition codes in first + scheduled event carts in RDLogManager. +2004-06-10 Fred Gleason + * Added an 'EditNote' dialog in 'rdlogmanager/edit_note.cpp'. + * Added the ability to include log note markers in the pre- and + post- import cart lists in RDLogManager. +2004-06-10 Fred Gleason + * Removed the Message and Note controls from RDLogManagers event + editor. + * Fixed a bug in 'lib/rdlog_line.cpp that was causing the group + name to fail to be correctly loaded in the 'loadCart()' method. +2004-06-14 Fred Gleason + * Fixed a bug in 'rdlogmanager/import_listview.cpp' that was + causing the right-button menu to appear in the wrong location. + * Fixed a bug in 'rdlogmanager/import_listview.cpp' that was + causing carts dropped into an import list to be prepended rather + than appended to the list. + * Fixed a bug in 'rdlogmanager/edit_event.cpp' that was causing + the cart filter to return false positive results. + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that was causing + the cart filter to return false positive results. + * Added a 'CLOCKS' table to the database. + * Created an 'RDClock' class in 'lib/rdclock.cpp'. + * Created an 'RDEventLine' class in 'lib/rdevent_line.cpp'. +2004-06-14 Fred Gleason + * Added 'playDeck()' and 'setPlayDeck()' methods to + 'lib/rdlog_line.cpp'. + * Renamed the 'PanelButton' class from 'rdairplay/panel_button.cpp' + to 'RDPanelButton' in 'lib/rdpanel_button.cpp'. + * Fixed a bug in 'cae/caed.cpp' that was causing the wrong audio + resources to be associated with particular connection IDs. +2004-06-15 Fred Gleason + * Removed 'rdairplay/soundpanel.cpp', 'rdairplay/soundpanel.h', + 'rdairplay/panel_button.cpp', 'rdairplay/panel_button.h', + 'rdairplay/button_panel.cpp, 'rdairplay/button_panel.h', + 'rdairplay/button_dialog.cpp', 'rdairplay/button_dialog.h', + 'rdairplay/audio_resources.cpp' and 'rdairplay/audio_resources.h'. +2004-06-15 Fred Gleason + * Retired the 'RDLIBRARY.INPUT_STREAM', 'RDLIBRARY.OUTPUT_STREAM', + 'RDLIBRARY_RECORD_GPI', 'RDLIBRARY.PLAY_GPI' and + 'RDLIBRARY_STOP_GPI' field from the database. + * Removed the 'Stream' field from the RDCardSelector widget in + 'lib/rdcardselector.cpp'. + * Retired the 'RDAIRPLAY.CARD', 'RDAIRPLAY.STREAM0', + 'RDAIRPLAY.STREAM1', 'RDAIRPLAY.STREAM2', 'RDAIRPLAY.STREAM3', + 'RDAIRPLAY.STREAM4', 'RDAIRPLAY.STREAM5', 'RDAIRPLAY.STREAM6', + and 'RDAIRPLAY.STREAM7' fields from the database. + * Added 'RDAIRPLAY.CARD0', 'RDAIRPLAY.CARD1', 'RDAIRPLAY.CARD2', + 'RDAIRPLAY.CARD3' and 'RDAIRPLAY.CARD4' field to the database. + * Incremented the database version to 41. + * Removed the 'stream()' and 'setStream()' methods from + 'lib/rdairplay_conf.cpp'. + * Overhauled the configuration dialog in + RDAdmin->Stations->RDAirPlay to use the new channel assignment + scheme. +2004-06-15 Fred Gleason + * Fixed a bug in 'cae/cae_jack.cpp' that was causing the build to + break when compiled without JACK support enabled. + * Changed the HPI fade profile to Logarithmic. +2004-06-18 Fred Gleason + * Fixed a bug in 'rdlibrary/edit_audio.cpp' that was causing + random audio positioning errors. +2004-06-21 Fred Gleason + * Redesigned meter updates in CAE to use a shared memory IPC. + * Removed the 'enableMetering()' method in 'lib/rdcae.cpp'. + * Removed the 'Meter Enable' [ME], 'Input Level' [IL] and 'Output + Level' [OL] commands from the CAE spec. +2004-06-21 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing Error + events to fail to show up on log displays. + * Fixed a bug in 'rdairplay/loglinebox.cpp' that was causing Error + events to show up with garbage in the button line box. + * Fixed a bug in 'rdlibrary/record_cut.cpp' that was sending + corrupt data to CAE. + * Fixed a bug in 'rdairplay/log_play.cpp' that caused a log + trainwreck when attempting to execute an event when no stream + resources were available. + * Added a 'LogPlayEvent()' method to 'rdairplay/log_play.cpp'. + * Added a 'logPlay()' method in 'lib'rdcut.cpp'. +2004-06-22 Fred Gleason + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing extra + characters to be appended to the name of the loaded log displayed + on the selector buttons. + * Implemented cut weighting and daypart selection in + 'lib/rdcart.cpp'. +2004-06-22 Fred Gleason + * Implemented play-time cut loading in RDAirPlay. + * Implemented outcue display in 'rdairplay/loglinebox.cpp'. + * Fixed a bug in 'rdairplay/log_play.cpp' that was failing to log + the time of a failed event. + * Fixed a bug in 'rdairplay/loglinebox.cpp' that was causing a + segfault when doubleclicking on an empty line box. +2004-06-22 Fred Gleason + * Fixed a bug in 'rdairplay/loglinebox.cpp' that was causing stale + cut data values to appear in line boxes. + * Implemented audition playout in RDAirPlay. +2004-06-23 Fred Gleason + * Fixed a bug in 'rdcatch/edit_recording.cpp' that was causing + the list of available record decks to fail to be loaded. + * Fixed a bug in 'rdcatch/edit_playout.cpp' that was causing the + list of available playout decks to fail to be loaded. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' in which the Start and + End cut markers were being ignored in Playout events. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' which had broken logging. + * Fixed a bug in 'rdcatch/rdcatch.cpp' where the status updates + would display incorrectly if the next event was active when + becoming next. +2004-06-24 Fred Gleason + * Implemented JACK playout support. +2004-06-24 Fred Gleason + * Implemented JACK capture support. +2004-06-25 Fred Gleason + * Fixed a bug in 'rdadmin/edit_rdairplay.cpp' that was applying + incorrect audio channels assignments. + * Fixed a bug in 'rdadmin/rdairplay.cpp' that was causing playout + levels from the Sound Panel to not show up in the audio meters. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing + incorrect port numbers to appear on active Start buttons. + * Implemented session JACK management in caed(8). + * Added Jack documentation in 'docs/JACK.txt' + * Incremented the RPM release level to 9. +2004-06-26 Fred Gleason + * Removed 'conf/alsa.conf'. + * Removed 'DBChanges'. + * Updated 'conf/rd.conf-sample'. + * Incremented the version to 0.8.0. +2004-06-28 Fred Gleason + * Fixed a bug in 'cae'cae_jack.cpp' that was causing the build to + break when building without JACK support. +2004-07-02 Fred Gleason + * Added an 'RDGrid' class in 'lib/rdgrid.cpp'. + * Added 'CLOCK' fields to the 'SERVICES' table. + * Incremented the database version to 42. + * Changed 'Station' to 'Host'. + * Removed the 'DEFAULT' host from the database. + * Added code to 'rdadmin/createdb.cpp' to create a default host + configuration for the local machine. + * Added 'RDAIRPLAY.SHOW_AUX_1' and 'RDAIRPLAY.SHOW_AUX_2' fields + to the database. + * Incremented the database version to 43. + * Added 'showAuxButton()' and 'setShowAuxButton()' methods to + 'lib/rdairplay.cpp'. + * Added 'Show Aux Log' check boxes in + RDAdmin->ManageStations->RDAirPlay. + * Implemented the ability to hide the 'Aux Log 1' and 'Aux Log 2' + buttons in RDAirPlay. +2004-07-05 Fred Gleason + * Added 'setRunState()' and 'exec()' methods to + 'lib/list_logs.cpp'. +2004-07-06 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was throwing a + segfault upon startup if more than eight record/playback decks + were configured. + * Added code to RDAirPlay to prevent a playing log from being + unloaded. + * Added a 'CUTS.LOCAL_COUNTER' field to the database. + * Added 'localCounter()' and 'setLocalCounter()' methods to + 'lib/rdcut.cpp'. + * Incremented the database version to 44. + * Added a 'resetRotation()' method to 'lib/rdcart.cpp'. + * Fixed a bug in 'lib/rdcut.cpp' that was reporting incorrect cut + numbers. + * Fixed a bug in 'rdairplay/loglinebox.cpp' that was failing to + update the count up/down timers when manually positioning the + audio start point. + * Relabeled the fields in RDAirPlay's Event Editor to match those + of RDLogManager's Event Editor. + * Fixed a bug in 'rdairplay/edit_event.cpp' that was causing + multiple simultaneous audition playouts. + * Added a 'playPositionChanged()' method to 'lib/rdlog_line.cpp'. + * Incremented the version to 0.8.1. +2004-07-07 Fred Gleason + * Added code to 'rdairplay/loglinebox.cpp' to display progress bar + in alternative colors if play position has been modified in the + event window. + * Fixed a bug in 'rdlibrary/record_cut.cpp' that was causing + rotation logic to fail after updating the weight value of a cut. + * Fixed a bug in 'rdairplay/log_play.cpp' that was forcing a Segue + transition to Play if the event's selected cut was missing segue + markers. + * Added a 'Stop' button the RDAirPlay's Event Editor. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing an + event to fail to advance when manually starting an event. + * Fixed a bug in 'rdairplay/pie_counter.cpp' that was causing + corrupted displays for event lengths longer than six minutes. + * Modified the Pie Counter in RDAirPlay so as to only display the + talk time countdown starting at :99. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing an + event added after the last event in a log to fail to be made next. + * Incremented the version to 0.8.2. +2004-07-08 Fred Gleason + * Fixed a bug in 'rdlibrary/audio_cart.cpp' that was overwriting + existing cart label information when exiting the CD ripper dialog. + * Fixed a bug in 'rdlibrary/cdripper.cpp' that was allowing the + 'X' button to close the dialog without freeing resources. + * Fixed a bug in 'rdlibrary/edit_cart.cpp' that was causing + unsaved cart label changes to be lost when launching the Edit, + Label, Rip or Import dialogs. + * Fixed a bug in 'rdlibrary/add_cart.cpp' that was leaving + orphaned cuts behind if creation of a new cart was abandoned. + * Fixed a bug in 'lib/rdlog_line.cpp' that was causing invalid + Talk Time marker positions to be generated. + * Added a 'remove()' method to 'lib/rdcart.cpp'. +2004-07-09 Greg Cunningham + * Fixed a bug in 'rdadmin/createdb.cpp' that was causing database + creation to fail. +2004-07-09 Fred Gleason + * Added an exit confirmation dialog box to RDAirPlay. + * Added an 'Alt-X' keybinding to exit RDAirPlay. + * Fixed a bug in 'rdairplay/edit_event.cpp' that was allowing the + 'X' button to close the dialog without freeing resources. + * Fixed a bug in 'rdlibrary/audio_cart.cpp' that was causing + FreeDB data to fail to update the cart label. + * Swapped the position of the 'Edit' and 'Record/Label' buttons in + RDLibrary's Record Dialog. + * Renamed the 'Record/Label' button in RDLibrary's Record Dialog + to 'Cut Info/Record'. + * Added the ability to doubleclick on the Cut entry in RDLibrary's + Record Dialog to bring up the Record Dialog. + * Added a sanity check to prevent blank cart descriptions from + being saved in RDLibrary's Record Dialog. + * Fixed a bug in 'rdairplay/loglinebox.cpp' that was throwing a + segfault when the Wall Clock was clicked with empty Line Boxes. +2004-07-12 Fred Gleason + * Added an 'EVERGREEN.CUTS' field to the database. + * Incremented the database version to 45. + * Added 'evergreen()' and 'setEvergreen()' methods to + 'lib/rdcut.cpp'. + * Added a 'Cut is EVERGREEN' control in RDLibrary's Record Dialog. + * Added 'evergreen()' and 'setEvergreen()' methods in + 'lib/rdlog_line.cpp'. + * Fixed a bug in 'rdlibrary/record_cut.cpp' that was causing cut + dayparting data to fail to be displayed properly. + * Added code to 'rdairplay/log_play.cpp' to dynamically update cut + selection data. +2004-07-13 Fred Gleason + * Added a single-instance lockout to RDLibrary. + * Added a single-instance lockout to RDCatch. + * Added a single-instance lockout to RDAirPlay. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + segfault when an event was inserted into a log at the current play + position. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing false + 'Invalid Cut' errors. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing + inaccurate Post Point countdown values when the transport was + stopped. + * Fixed a bug in 'rdairplay/post_counter.cpp' that was causing + excessive round-off error in countdowns. +2004-07-14 Fred Gleason + * Added an 'averageLength()' method to 'lib/rdcart.cpp'. + * Added a 'LENGTH_DEVIATION.CART' field to the database. + * Added 'lengthDeviation()' and 'setLengthDeviation()' methods to + 'lib/rdcart.cpp'. + * Incremented the database version to 46. + * Added a 'LENGTH DEVIATION' column to the cart list in RDLibrary. + * Added logic to display excessive cut length deviation in YELLOW + or RED in RDLibrary's cart list. + * Added a clause to filter by cart number in + 'lib/rdcart_search_text.cpp'. + * Added logic to 'rdairplay/edit_event.cpp' to prevent a PostPoint + attribute from being set on a non-immediate Hard Start time. + * Added logic to 'rdlogedit/edit_logline.cpp' to prevent a PostPoint + attribute from being set on a non-immediate Hard Start time. + * Added logic to 'rdlogedit/edit_marker.cpp' to prevent a PostPoint + attribute from being set on a non-immediate Hard Start time. +2004-07-15 Fred Gleason + * Added an 'EditChain' dialog in 'rdlogedit/edit_chain.cpp'. + * Added an 'AddMeta' dialog in 'rdlogedit/add_meta.cpp'. + * Implemented Log Chain support in RDLogEdit. + * Added a chain event icon on 'icons/chain.xpm'. + * Implemented Log Chain support in RDAirPlay. +2004-07-16 Fred Gleason + * Added output stream position information to the CAE shared + memory segment. + * Rewrote 'rdlibrary/edit_audio.cpp' to use the new CAE position + data interface. +2004-07-16 Fred Gleason + * Added output stream position code to 'cae/cae_jack.cpp'. + * Restored audio metering in 'rdlibrary/edit_audio.cpp'. + * Incremented the version number to 0.8.3. +2004-07-16 Fred Gleason + * Fixed a bug in 'cae/cae.cpp' that was freezing the JACK graph if + caed(8) was started in non-debugging mode. +2004-07-17 Fred Gleason + * Incremented the package version to 0.8.4. +2004-07-26 Fred Gleason + * Added support for detecting ALSA to 'configure.in'. + * Stubbed out ALSA support in CAE. +2004-07-26 Fred Gleason + * Added a [Format] section to rd.conf(5). + * Added 'SampleRate=' and 'Channels=' directives to the [Format] + section of rd.conf(5). +2004-07-26 Fred Gleason + * Added a [Debug] section to rd.conf(5). + * Added a 'UseRealtime=' directive to the [Debug] section of + rd.conf(5). + * Added code the 'cae/cae_alsa.cpp'. Still a WIP. +2004-07-26 Fred Gleason + * Got a rudimentary version of 'AlsaCallback()' working in + 'cae/cae_alsa.cpp'. +2004-07-27 Fred Gleason + * More work on ALSA support in CAE. +2004-07-28 Fred Gleason + * Added a sysconfig file in 'rivendell.sys'. + * Incremented the RPM release to 10. +2004-07-28 Fred Gleason + * Added a 'DAEMON MANAGEMENT' section to 'docs/JACK.txt'. +2004-08-03 Fred Gleason + * Fixed bugs in 'cae/cae_alsa.cpp' that were causing the build to + break when compiled with ALSA support disabled. +2004-08-04 Fred Gleason + * Added a 'ListClocks' class in 'rdlogmanager/list_clocks.cpp'. + * Added an 'AddClock' class in 'rdlogmanager/add_clock.cpp'. + * Added an 'EditClock' class in 'rdlogmanager/edit_clock.cpp'. + * Added an 'EditEventLine' class in 'rdlogmanager/edit_clock.cpp'. +2004-08-06 Fred Gleason + * Finished the Clock Editor in RDLogManager. +2004-08-06 Fred Gleason + * Added a 'ListGrids' class in 'rdlogmanager/list_grids.cpp'. + * Added an 'EditGrid' class in 'rdlogmanager/edit_grid.cpp'. +2004-08-09 Fred Gleason + * Added 'SERVICES.NAME_FORMAT', 'SERVICES.TFC_PATH', + 'SERVICES.TFC_CART_OFFSET', 'SERVICES.TFC_CART_LENGTH', + 'SERVICES.TFC_START_OFFSET', SERVICES.TFC_START_LENGTH', + 'SERVICES.MUS_PATH', 'SERVICES.MUS_CART_OFFSET', + 'SERIVCES.MUS_CART_LENGTH', 'SERVICES.MUS_START_OFFSET' and + 'SERVICES.MUS_START_LENGTH', 'SERVICES.TFC_WIN_PATH' and + 'SERVICES.MUS_WIN_PATH' fields to the database. + * Incremented the database version to 47. + * Added 'importPath()', 'setImportPath()', 'nameTemplate()', + 'setNameTemplate()', 'importOffset()', 'setImportOffset()', + 'importLength()' and 'setImportLength()' methods to + 'lib/rdsvc.cpp'. + * Added an 'RDDateDecode()' function in 'lib/rddatedecode.cpp'. + * Added a 'TestImport' dialog in 'rdadmin/test_import.cpp'. +2004-08-12 Fred Gleason + * Added a 'generateLog()' method in 'lib/rdclock.cpp'. + * Added a 'generateLog()' method in 'lib/rdevent_line.cpp' + * Added a 'GenerateLog' dialog in 'rdlogmanager/generate_log.cpp'. + * Modified the 'RDSvc' class to inherit 'QObject' in + 'lib/rdsvc.cpp'. + * Added a 'generationProgress()' signal in 'lib/rdsvc.cpp'. + * Added an 'exists()' method to 'lib/rdlog.cpp'. + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was causing the + scheduled start time to fail to be displayed for events without a + Hard time. +2004-08-13 Fred Gleason + * Added 'SERVICES.TFC_LENGTH_OFFSET', + 'SERVICES.TFC_LENGTH_LENGTH', + 'SERVICES.MUS_LENGTH_OFFSET' and 'SERVICES.MUS_LENGTH_LENGTH' + fields to the database. + * Incremented the database version to 47. + * Added audio parser settings for LENGTH to 'rdadmin/edit_svc.cpp'. + * Added a LENGTH parameter to 'rdadmin/test_import.cpp'. + * Fixed a bug in 'rdlogmanager/edit_event.cpp that was causing the + grace time to be forced to 'Start Immediately' for all hard time + events. +2004-08-13 Fred Gleason + * Added an 'AUTOFILLS' table to the database. + * Incremented the database version to 49. + * Added an 'AutofillCarts' dialog in 'rdadmin/autofill_carts.cpp'. + * Added a 'LENGTH' field to the Cart Picker Dialog. +2004-08-13 Fred Gleason + * Added a 'SERVICES.CHAIN_LOG' field to the database. + * Incremented the database version to 50. + * Added 'chainto()' and 'setChainto()' methods to 'lib/rdsvc.cpp'. + * Added a 'Insert CHAIN TO at log end' control in the Edit Service + dialog in RDAdmin. +2004-08-13 Fred Gleason + * Disabled the ALSA driver in 'configure.in'. + * Added code cleanups for exiting the JACK graph. +2004-08-13 Fred Gleason + * Tweaked the JACK cleanup code for better performance under SuSE + 9.1. +2004-08-14 Fred Gleason + * Fixed up font sizing for SuSE 9.1 in 'rdlibrary/rdlibrary.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlibrary/edit_cart.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlibrary/audio_cart.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlibrary/macro_cart.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlibrary/record_cut.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlibrary/edit_audio.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlibrary/import_audio.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlibrary/cdripper.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdcatch/rdcatch.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdcatch/add_recording.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdcatch/edit_recording.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdcatch/edit_playout.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdcatch/edit_cartevent.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdcatch/edit_switchevent.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogedit/rdedit_log.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogedit/rdlogedit.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogedit/add_log.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogedit/edit_logline.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'lib/rdcart_dialog.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogedit/add_meta.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogedit/edit_marker.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogedit/edit_chain.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogmanager/rdlogmanager.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogmanager/edit_event.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlibrary/add_cart.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogin/rdlogin.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdairplay/edit_event.cpp'. +2004-08-15 Fred Gleason + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/login.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/rdadmin.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/list_users.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/add_user.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/edit_user.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/list_groups.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/edit_group.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/add_group.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/list_svcs.cpp'. + * Fixed a formatting layout error in 'rdadmin/edit_svc.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/add_svc.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/edit_station.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/edit_rdlibrary.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/edit_decks.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/edit_rdairplay.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/add_matrix.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/edit_matrix.cpp'. +2004-08-16 Fred Gleason + * Fixed a bug in 'rdlibrary/record_cut.cpp' that was causing + recordings to be corrupt if the Max Length parameter was exceeded. +2004-08-16 Fred Gleason + * Fixed up font sizing for SuSE 9.1 in 'rdlibrary/edit_audio.cpp'. +2004-08-17 Fred Gleason + * Added a default font specification in 'rdadmin/rdadmin.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/edit_svc.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/test_import.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/edit_rdlibrary.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/edit_decks.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdadmin/edit_ttys.cpp'. + * Added a default font specification in + 'rdlogmanager/rdlogmanager.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogmanager/add_event.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogmanager/add_clock.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogmanager/add_grid.cpp'. + * Added a default font specification in 'rdcatch/rdcatch.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdcatch/edit_recording.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdcatch/deckmon.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'lib/rdcut_dialog.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'lib/rdbutton_dialog.cpp'. + * Added a default font specification in 'rdlogedit/rdlogedit.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogedit/edit_log.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogedit/edit_logline.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogedit/edit_marker.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogedit/edit_chain.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlogedit/list_logs.cpp'. + * Added a default font specification in 'rdlibrary/rdlibrary.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlibrary/cdripper.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdlibrary/edit_macro.cpp'. + * Added a default font specification in 'rdlogin/rdlogin.cpp'. + * Added a default font specification in 'rdairplay/rdairplay.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdairplay/start_button.cpp'. + * Fixed up font sizing for SuSE 9.1 in 'rdairplay/list_logs.cpp'. +2004-08-18 Fred Gleason + * Fixed a bug in 'rdcatch/edit_cartevent.cpp' where the station + name would fail to be set to the currently configured value when + the dialog was opened. + * Fixed a bug in 'rdcatch/edit_switchevent.cpp' where the station + name would fail to be set to the currently configured value when + the dialog was opened. + * Incremented the package version to 0.9.0. + * Set the RPM release level to 1. + * Updated the 'INSTALL' file to reflect a requirement for + libradio-0.92.0 or higher. + * Updated the NEWS file. + * Updated the README file. + * Released as 0.9.0. +2004-08-19 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + segfault when loading an empty log. + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was causing events on + remote workstations to fail to update when changed. + * Fixed a bug in 'rdadmin/edit_station.cpp' that was causing + RDCatch configuration changes to fail to propigate to remote + workstations. +2004-08-19 Fred Gleason + * Added 'RDDbBackup()', 'RDDbRestore()' and 'RDDbDelete()' + functions in 'lib/rddbbackup.cpp'. +2004-08-20 Fred Gleason + * Added 'RDCreateLogTableSql()' and 'QStringRDCreateClockTableSql()', + functions in 'lib/rdcreate_log.cpp'. +2004-08-23 Alban Peignier + * Fixed a SQL syntax error in 'lib/rdsvc.cpp'. +2004-08-23 Fred Gleason + * Deleted 'lib/rddbbackup.cpp' and 'lib/rddbbackup.h'. + * Added the Database Backup [DB] RML to 'docs/rml.sxw'. + * Added the Database Backup [DB] RML to 'lib/rdmacro.h'. + * Implemented the Database Backup [DB] RML in + 'ripcd/local_macros.cpp'. + * Added the Database Backup [DB] RML to + 'docs/implemented_macros.txt'. + * Fixed a bug in 'rdlogmanager/edit_eventline.cpp' that caused a + segfault when trying to insert a non-existent event into a clock. +2004-08-23 Fred Gleason + * Added an 'RDconfig' class in 'lib/rdconfig.cpp'. + * Modified RDLogEdit to use the new RDConfig class. + * Deleted 'rdlogedit/config.cpp'. + * Modified RDLogManager to use the new RDConfig class. + * Deleted 'rdlogmanager/config.cpp'. + * Modified RDAdmin to use the new RDConfig class. + * Deleted 'rdadmin/config.cpp'. + * Modified RDAirPlay to use the new RDConfig class. + * Deleted 'rdairplay/config.cpp'. + * Modified RDCatch to use the new RDConfig class. + * Deleted 'rdcatch/config.cpp'. + * Modified RDCatchd to use the new RDConfig class. + * Modified RDLibrary to use the new RDConfig class. + * Deleted 'rdlibrary/config.cpp'. + * Modified RDLogin to use the new RDConfig class. + * Deleted 'rdlogin/config.cpp'. + * Modified RDPanel to use the new RDConfig class. + * Deleted 'rdpanel/config.cpp'. +2004-08-24 Fred Gleason + * Added a QMake project file in 'rivendell.pro'. + * Added a QMake project file in 'utils/utils.pro'. + * Added a QMake project file in 'rdlogedit/rdlogedit.pro'. + * Moved 'utils/rivendell.res' to 'icons/rivendell.res'. + * Added a QMake project file in 'rdlogmanager/rdlogmanager.pro'. + * Added a QMake project file in 'lib/lib.pro'. +2004-08-25 Fred Gleason + * Added an 'RDTimePoint()' function in 'lib/rddebug.cpp'. + * Optimized RDAirPlay to reduce log load and transition times. +2004-08-25 Fred Gleason + * Added 'hardSortColumn()' and 'setHardSortColumn()' methods to + 'lib/rdlistview.cpp'. + * Removed the 'renumbered()' signal from 'rdairplay/log_play.h'. + * Added 'inserted()' and 'removed()' signals to + 'rdairplay/log_play.cpp'. + * Added an 'RD_USE_MYSQL_EXTENSIONS' define to 'lib/rd.h'. + * Added code to 'lib/rdlog_event.cpp' to use mySQL SQL extensions + for saving logs. +2004-08-25 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp where doing a 'Make Next' + was causing events to show a 'No Valid Cut Found' error. +2004-08-25 Alban Peignier + * Added an 'RDImport' batch file importer utility in 'utils/'. +2004-08-25 Fred Gleason + * Modified 'utils/rdimport.cpp' so as to use configuration values + from RDAdmin->ManageHosts->RDLibrary for batch imports. +2004-08-25 Fred Gleason + * Added RDImport to 'rivendell.spec.in'. +2004-08-29 Alban Peignier + * Added support for reading ID3 metadata to 'utils/rdimport.cpp'. +2004-08-29 Fred Gleason + * Added an '--enable-rdimport' switch to 'configure.in' to enable + building of RDImport (requires TagLib). +2004-08-30 Fred Gleason + * Fixed a bug in 'lib'rdlog_event.cpp' that was causing a segfault + when the 'save()' method was called. + * Changed the level meter in RDAirPlay to use a calibrated scale. + * Moved the 'Add Log' dialog from 'rdlogedit/add_log.cpp' to + 'lib/rdadd_log.cpp'. +2004-08-30 Fred Gleason + * Added a 'renamed()' signal to 'rdairplay/log_play.cpp'. + * Fixed a bug in 'rdairplay/list_log.cpp' that broke the automatic + event scrolling in the Full Log list. + * Fixed a bug in 'lib/rdlog_line.cpp' that broke segue crossfades. +2004-08-30 Fred Gleason + * Adjusted fonts in 'rdairplay/loglinebox.cpp' for better + appearance under SuSE 9.1. + * Adjusted fonts in 'rdairplay/pie_counter.cpp' for better + appearance under SuSE 9.1. +2004-08-31 Fred Gleason + * Tweaked the count-up timer location in + 'rdairplay/loglinbox.cpp'. + * Added a 'DiskGauge' widget in 'rdlibrary/disk_gauge.cpp'. + * Added a 'DiskBar' widget in 'rdlibrary/disk_bar.cpp'. +2004-08-31 Fred Gleason + * Fixed a bug in the free space caluation in + 'rdlibrary/disk_gauge.cpp'. + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing the + Pie Counter to not reflect a modified event start time. +2004-09-01 Fred Gleason + * Fixed a bug in 'rdlibrary/edit_audio.cpp' where closing the + dialog with the 'X' button would fail to cancel active audio + playout. + * Fixed a bug in 'rdlibrary/edit_audio.cpp that was causing the + meter to hang at the last registered audio level after pressing + 'Stop' or 'Pause'. + * Fixed a bug in 'cae/cae_hpi.cpp' that was causing CAE to report + an incorrect play position when used with HPI. +2004-09-02 Fred Gleason + * Added autodetection for the TagLib library to 'configure.in'. + * Removed the '--enable-rdimport' option from 'configure.in'. +2004-09-10 Fred Gleason + * Incremented the package version to 0.9.1. +2004-09-13 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing deck + monitors to show 'Offline' status. +2004-09-14 Fred Gleason + * Incremented the package version to 0.9.2. +2004-09-14 Fred Gleason + * Removed GPITest and GPOTest from 'utils/'. +2004-09-15 Fred Gleason + * Added a 'conf/crc-unity4k.sh' script. +2004-09-16 Fred Gleason + * Fixed a bug in 'cae/cae.cpp' that was reporting invalid + AES sync indications. + * Fixed a bug in 'lib/rdcae.cpp' that was reporting invalid + AES sync indications. +2004-09-21 Fred Gleason + * Added 'Left' and 'Right' configurations for LF1 in + 'conf/crc-unity4k.sh'. + * Added a 'Send Command' [CC] macro to 'docs/rml.sxw'. + * Implemented the 'Send Command' [CC] macro. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + lockup when executing a macro cart as the first event in a log. +2004-09-21 Fred Gleason + * Changed the 'Length' field to 'End Time' in + 'rdlogmanager/edit_eventline.cpp'. + * Added an 'End Time' field to 'rdlogmanager/edit_clock.cpp'. +2004-09-22 Fred Gleason + * Added a 'HOSTVARS' table to the database. + * Incremented the database version to 52. + * Added a 'ListHostvars' dialog in 'rdadmin/list_hostvars.cpp'. + * Added an 'EditHostvar' dialog in 'rdadmin/edit_hostvar.cpp'. + * Added an 'AddHostvar' dialog in 'rdadmin/add_hostvar.cpp'. +2004-09-22 Fred Gleason + * Added code to resolve host variables in 'lib/rdripc.cpp'. + * Added code to resolve host variables in 'lib/rdmacro_event.cpp'. + * Fixed a bug in 'rdairplay/wall_clock.cpp' that was causing the + day-of-the-week label to be clipped. +2004-09-23 Fred Gleason + * Incremented the package version to 0.9.3. +2004-10-04 Fred Gleason + * Added build system support for OggVorbis. +2004-10-12 Fred Gleason + * Fixed a bug in 'cae/Makefile.am' that was causing the build to + break. +2004-10-13 Fred Gleason + * Added 'STATIONS.BACKUP_DIR' and 'STATIONS.BACKUP_LIFE' fields to + the database. + * Incremented the database version to 53. + * Added 'backupLife()', 'setBackupLife()', 'backupPath()' and + 'setBackupPath()' methods to 'lib/rdstation.cpp'. + * Added an 'EditBackup' dialog in 'rdadmin/edit_backup.cpp'. +2004-10-14 Fred Gleason + * Added code to purge old automatic database backups in + 'ripcd/ripcd.cpp'. + * Fixed a bug in 'rdadmin/rdadmin.cpp' that was causing KDE to + hang a 'program starting' indication after a failed RDAdmin login. + * Added 'RDMatrix::Bt16x1' and 'RDMatrix::Bt8x2' values to + 'RDMatrix::Type' in 'lib/rdmatrix.h'. + * Added support for the Broadcast Tools 16x1 switcher to RDAdmin. + * Added support for the Broadcast Tools 8x2 switcher to RDAdmin. + * Added a switcher driver for the Broadcast Tools 16x1 in + 'ripcd/bt16x1.cpp'. + * Added a switcher driver for the Broadcast Tools 8x2 in + 'ripcd/bt8x2.cpp'. +2004-10-27 darrick + * Fixed a memory leak in 'lib/rdlog_line.cpp'. +2004-10-27 Fred Gleason + * Fixed a memory leak in 'lib/rdcart_dialog.cpp'. + * Added the Binary Serial Out ('BO') RML to RDMacro. + * Implemented the Binary Serial Out ('BO') RML in + 'ripcd/local_macros.cpp'. + * Added the Binary Serial Out ('BO') RML to + 'doc/implemented_macros.txt'. + * Incremented the package version to 0.9.4. +2004-10-29 Fred Gleason + * Fixed a bug in which the level meter indication in RDAirPlay was + too high if the same output port was assigned to more than one + output. +2004-11-01 Fred Gleason + * Added RDGpiMon, a GPI monitoring utility, in 'utils/'. + * Added a 'GI' command to the RIPC command protocol. + * Added a 'GC' command to the RIPC command protocol. + * Added a 'GM' command to the RIPC command protocol. + * Added notes in 'docs/GPIO.txt' on use of the gameport as a GPIO + device. +2004-11-02 Fred Gleason + * Added additional detail on wiring PC game ports for GPI in + 'docs/GPIO.txt'. + * Incremented the package version to 0.9.5. +2004-11-04 Fred Gleason + * Added sample mySQL configurations in 'conf/my.cnf-master' and + 'conf/my.cnf-standby'. + * Created an audio replication script in 'scripts/rd_audio_sync'. + * Created a configuration manager script in 'scripts/rd_config'. + * Fixed a bug in 'rdlibrary/import_audio.cpp' that broke audio + file importation. +2004-11-04 Fred Gleason + * Fixed a bug in 'docs/Makefile.am' that was causing the RPM build + to break. + * Incremented the package version 0.9.6. +2004-11-06 Fred Gleason + * Added a 'station()' method to 'lib/rdripc.cpp'. + * Fixed a bug in 'lib/rdmacro_event.cpp' that was causing the CC + RML to fail if a host variable was used for the destination + address. + * Incremented the package version to 0.9.7. +2004-11-06 Fred Gleason + * Removed the '-q' flag from the call to 'sox -resample' in + 'scripts/rd_import_audio' to work around a bug in sox(1). + * Removed the '-q' flag from the call to 'sox -resample' in + 'scripts/rd_rip_cd' to work around a bug in sox(1). + * Fixed a bug in 'rdlibrary/cdripper.cpp' that was causing corrupt + audio when simultaneously performing rips on multiple hosts. + * Fixed a bug in 'rdlibrary/import_audio.cpp' that was causing corrupt + audio when simultaneously performing imports on multiple hosts. + * Incremented the package version to 0.9.8. +2004-11-07 Fred Gleason + * Fixed a bug in 'lib/rdcart_dialog.cpp' that threw a segfault fi + the 'OK' button was pushed with an empty cart list. + * Fixed a bug in 'lib/rdcut_dialog.cpp' that threw a segfault fi + the 'OK' button was pushed with empty cart or cut lists. +2004-11-08 Fred Gleason + * Added sanity checks to 'cae/cae.cpp' to prevent caed segfaults + when trying to load non-existent audio resources. + * Added 'RDAIRPLAY.CLEAR_FILTER' and 'RDAIRPLAY.BAR_ACTION' fields + to the database. + * Incremented the database version to 54. + * Added 'clearFilter()', 'setClearFilter()', 'barAction()' and + 'setBarAction()' mmeethods to 'lib/rdairplay_conf.cpp'. + * Added a 'Clear Cart Search Filter' checkbox to + 'rdadmin/edit_rdairplay.cpp'. + * Added a 'Space Bar Action' button group to + 'rdadmin/edit_rdairplay.cpp'. + * Fixed a bug in 'rdairplay/rdairplay.cpp' where last cart + selected in the Add Cart dialog would be highlighted as the + default selection. + * Added a keybinding to RDAdmin where pressing the space bar will + start the next event in the Main Log if enabled in RDAdmin. + * Fixed a bug in 'rdadmin/list_gpis.cpp' where the 'description' + field would be blanked if the Edit dialog was cancelled. + * Fixed a bug in rdadmin/list_gpis.cpp' that was failing to update + the active GPI list when the 'GPIS' table was changed. +2004-11-08 Fred Gleason + * Added code to 'rdairplay/log_play.cpp' to ensure that the + initial playout from a stopped log will always be on the first + fader channel. + * Incremented the package version to 0.9.9. +2004-11-08 Fred Gleason + * Tweaked 'rdadmin/edit_gpi.cpp' for better appearance on SuSE + 9.1. + * Tweaked 'rdlibrary/record_cut.cpp' for better appearance on SuSE + 9.1. + * Fixed a bug in 'rdairplay/rdairplay.cpp' where the name of the + log loaded into the Main Log was not being displayed on the title + bar. +2004-11-09 Fred Gleason + * Added a 'RDAIRPLAY.FLASH_PANEL' field to the database. + * Incremented the database version to 55. + * Added 'flashPnael()' and 'setFlashPanel()' methods to + 'lib/rdairplay_conf.cpp'. + * Added a 'Flash Active Buttons' checkbox to the + RDAdmin->ManageHosts->EditRDAirPlay dialog. + * Fixed a bug in 'rdlibrary/edit_audio.cpp' that was causing + intermittent failure of audio playout and/or audio metering. + * Fixed a bug in 'lib/rdsound_panel.cpp' that was failing to free + a timing resource. + * Incremented the package version to 0.9.10. +2004-11-09 Fred Gleason + * Added the ability to flash active sound panel buttons in + RDAirPlay. + * Fixed a bug in 'rdlibrary/edit_audio.cpp' where the Trim + Threshold was not being initialized to the correct default value. +2004-11-09 Fred Gleason + * Added an 'AutoTrim' widget to the CD Ripper dialog in RDLibrary. + * Added an 'AutoTrim' widget to the File Import dialog in RDLibrary. + * Changed the File Import dialog in RDLibrary so that it now + closes automatically at the end of an import. + * Added 'STATIONS.HEARTBEAT_CART' and + 'STATIONS.HEARTBEAT_INTERVAL' field to the database. + * Incremented the database version to 56. + * Added a 'reloadHeatbeat()' method to 'lib/rdipc.cpp'. + * Added 'heartbeatCart()', 'setHeartbeatCart()', + 'heartbeatInterval()' and 'setHeartbeatInterval()' methods to + 'rdadmin/edit_station.cpp'. +2004-11-09 Fred Gleason + * Added Host Heartbeat capability. +2004-11-09 Fred Gleason + * Incremented package version to 0.9.11. +2004-11-15 Fred Gleason + * Fixed a bug in 'scripts/rd_rip_cd' that was causing + normalization levels to be incorrect. + * Fixed a bug in 'rdairplay/loglinebox.cpp' that was causing the + count-up timer to jitter. + * Added a 'Set Color Label' ['LC'] macro to 'lib/rdmacro.h'. + * Implemented the 'Set Color Label' ['LC'] macro. + * Added a RenameGroup dialog in 'rdadmin/rename_group.cpp'. + * Implemented the ability to rename and combine groups in + RDAdmin->ManageGroups. +2004-11-15 Fred Gleason + * Fixed a bug in 'rdadmin/list_groups.cpp' where deleting a group + would fail to delete member carts. +2004-11-15 Fred Gleason + * Added a text validator class in 'lib/rdtextvalidator.cpp'. + * Added a text validator to 'rdlibrary/edit_cart.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdlibrary/record_audio.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdlibrary/rdlibrary.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'lib/rdcart_dialog.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'lib/rdcut_dialog.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdcatch/edit_cartevent.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdcatch/edit_switchevent.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdcatch/edit_recording.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdcatch/edit_playout.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdlogedit/edit_log.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdlogin/rdlogin.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdlogmanager/edit_event.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdlogmanager/edit_eventline.cpp' to + prevent entering of invalid SQL characters. + * Added a text validator to 'rdadmin/login.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/add_user.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/edit_user.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'lib/rdpasswd.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/add_group.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/edit_group.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/rename_group.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/add_svc.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/edit_svc.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/add_station.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/edit_station.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/edit_rdlibrary.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/edit_ttys.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/edit_matrix.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/edit_gpi.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/edit_endpoint.cpp' to prevent + entering of invalid SQL characters. + * Added a text validator to 'rdadmin/edit_backup.cpp' to prevent + entering of invalid SQL characters. + * Fixed up text layout in 'rdadmin/info_dialog.cpp'. +2004-11-15 Fred Gleason + * Fixed a bug where starting a macro cart as the first event in a + log would segfault RDAirPlay. + * Added code to 'ripcd/local_macros.cpp' to mute the output of a + Unity4000 receiver when commanded to switch to input zero. + * Incremented the package version to 0.9.12. +2004-11-17 Fred Gleason + * Added a text validator to 'rdlibrary/edit_macro.cpp' to prevent + entering of invalid SQL characters. + * Added a 'SERVICE_PERMS' table to the database. + * Incremented the database version to 57. + * Added an 'EditSvcPerms' dialog in 'rdadmin/edit_svc_perms.cpp'. + * Added code to 'rdairplay/list_logs.cpp' to restrict the list of + available logs to those owned by services enabled for the host. + * Added code to 'lib/rdcart_dialog.cpp' to restrict the list of + available carts to those allowed for a given station. + * Added code to 'rdairplay/list_logs.cpp' to restrict the list of + available logs to those matching log start/end date criteria. + * Fixed a bug in'rdlogedit/edit_log.cpp' that was causing + incorrect start and end dates to be loaded. + * Made the Log Edit widget in RDLogEdit resizable. + * Added a 'Group' column to the Log Edit widget in RDLogEdit. + * Added an 'RDGroupList' class in 'lib/rdgroup_list.cpp'. + * Fixed a bug in 'lib/rdlog.cpp' that was returning an incorrect + value for 'service()'. + * Fixed a bug in 'lib/rdlistviewitem.cpp' that was failing to + update the display when changing text color. + * Added code to 'rdlogedit/edit_logline.cpp' so to restrict the + list of available carts to those enabled for the selected service. + * Added code to 'rdlogedit/edit_log.cpp' to prevent saving logs + containing carts that are disabled for the selected service. + * Added code to 'lib/rdbutton_dialog.cpp' so to restrict the + list of available carts to those enabled for the selected service. +2004-11-17 Fred Gleason + * Added 'EXT_START_TIME', 'EXT_LENGTH', 'EXT_DATA' and + 'EXT_EVENT_ID' fields to the log tables in the database. + * Incremented the database version to 58. + * Added 'extStartTime()', 'setExtStartTime()', 'extLength()', + 'setExtLength()', 'extData()', 'setExtData()', 'extEventId()' and + 'setExtEventId()' methods to 'lib/rdlog_line.cpp'. + * Added code to 'lib/rdlog_event.cpp' to handle the new database + fields. + * Added 'SERVICES.TFC_DATA_OFFSET', 'SERVICES.TFC_DATA_LENGTH', + 'SERVICES.TFC_EVENT_ID_OFFSET', 'SERVICES.TFC_EVENT_ID_LENGTH', + 'SERVICES.MUS_DATA_OFFSET', 'SERVICES.MUS_DATA_LENGTH', + 'SERVICES.MUS_EVENT_ID_OFFSET' and 'SERVICES.MUS_EVENT_ID_LENGTH' + fields to the database. + * Incremented the database version to 59. + * Added 'ExtData' and 'ExtEventId' to RDSvc::ImportField in + 'lib/rdsvc.h'. + * Added controls for importing Traffic Contract # and Event ID to + the EditService dialog in RDAdmin. + * Added columns for Traffic Contract # and Event ID to the + TestImport dialog in RDAdmin. +2004-11-17 Fred Gleason + * Added code to 'lib/rdevent_line.cpp' to external traffic system + data into logs. + * Added a sanity check to 'rdlogedit/edit_logline.cpp' to prevent + insertion of a disabled cart. + * Created a *_REC' table format. + * Incremented the database version to 60. + * Added code to 'rdlogedit/rdlogedit.cpp' to delete a _REC table + when the corresponding log is deleted. + * Added a 'LogTraffic()' function in 'rdairplay/log_traffic.cpp'. + * Added a 'TrafficAction' enum to 'lib/rdairplay_conf.h'. + * Added code in 'rdairplay/log_play.cpp' to log event playouts in + the respective reconciliation table. +2004-11-19 Fred Gleason + * Removed the 'CAE_HANDLE' field from the _REC table database + format. + * Added a 'LENGTH' field to the _REC table database format. + * Incremented the database version to 61. + * Added a 'startTime()' method to 'lib/rdpanel_button.cpp'. + * Added code to 'lib/rdsouond_panel.cpp' to record play events in + reconciliation tables. +2004-11-19 Fred Gleason + * Added 'GROUPS_REPORT_TFC' and 'GROUPS.REPORT_MUS' fields to the + database. + * Incremented the database version to 62. + * Added 'exportReport()' and 'setExportReport()' methods to + 'lib/rdgroup.cpp'. + * Added controls to RDAdmin->EditGroups to select which report + types a group should be included in. +2004-11-19 Fred Gleason + * Added 'REPORTS', 'REPORT_SERVICES' and 'REPORT_STATIONS' tables + to the database. + * Incremented the database version to 63. + * Created a 'ListReports' dialog in 'rdadmin/list_reports.cpp'. + * Created an 'EditReport' dialog in 'rdadmin/edit_report.cpp'. + * Created an 'RDReport' class in 'lib/rdreport.cpp'. +2004-11-22 Fred Gleason + * Created an 'AddReport' dialog in 'rdadmin/add_report.cpp'. +2004-11-23 Fred Gleason + * Created a 'GenerateReport' dialog in + 'rdlogmanager/generate_report.cpp'. + * Added 'REPORTS.EXPORT_TFC', 'REPORTS.EXPORT_MUS' and + 'REPORTS.EXPORT_GEN' fields to the database. + * Incremented the database version to 64. + * Added 'exportTypeEnabled()' and 'setExportTypeEnabled()' methods + to 'lib/rdreport.cpp'. + * Added export type controls to the RDAdmin->EditReport dialog. + * Added an 'ExportDeltaflex' dialog in + 'rdlogmanager/export_deltaflex.cpp'. +2004-11-23 Fred Gleason + * Added a 'REPORTS.STATION_ID' field to the database. + * Incremented database version to 65. + * Added 'stationId()' and 'setStationId()' methods to + 'lib/rdreport.cpp'. + * Added a control to set the Station ID in RDAdmin->EditReport. + * Added notes on setting up reports in 'docs/report.txt'. +2004-11-23 Fred Gleason + * Disabled the RIAA Weblog and ASCAP/BMI export filters. + * Updated 'docs/reports.txt'. +2004-11-24 Fred Gleason + * Added a sanity check in 'cae/cae.cpp' for invalid playback + handles. + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing invalid + play handles to be sent to CAE. +2004-11-24 Fred Gleason + * Added RDAirPlayConf::LiveAssist to RDAirPlayConf::OpMode in + 'lib/rdairplay_conf.h'. + * Added code in 'rdairplay/log_play.cpp' to handle manual mode. + * Added code in 'rdairplay/rdairplay.cpp' to handle manual mode. + * Added 'LiveAssist' to the available choices for startup mode in + 'rdadmin/edit_rdairplay.cpp'. + * Changed the default value of the 'RDAIRPLAY.OP_MODE' field in + the database to 2. + * Incremented the database version to 66. +2004-12-06 Fred Gleason + * Fixed Windows build system. + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' that was causing the + top window border to chopped off under Windows. +2004-12-06 Dan Mills + * Fixed a bug in 'rdadmin/createdb.cpp' that was causing creation + of a new database to fail. +2004-12-06 Fred Gleason + * Added 'Paused' to RDLogLine::Status in 'lib/rdlog_line.h'. + * Added an 'RDAIRPLAY.PAUSE_ENABLED' field to the database. + * Incremented the database version to 67. + * Added 'pauseEnabled()' and 'setPauseEnabled()' methods to + 'lib/rdairplay_conf.cpp'. + * Added an 'Enable Paused Events' control to RDAdmin->ManageHosts. + * Added support for Pause Mode to 'rdairplay/list_log.cpp'. + * Added 'Initial' to RDLogLine::StartTimeType in 'lib/rdlog_line.h'. + * Added 'pauseCard()', 'setPauseCard()', 'pausePort()' and + 'setPausePort()' methods to 'lib/rdlog_line.cpp'. +2004-12-08 Fred Gleason + * Fixed bugs in 'rdairplay/rdairplay.cpp that was causing flaky + pie widget operation with paused events. + * Fixed bugs in 'rdairplay/log_play.cpp that was causing flaky + stop counter operation with paused events. + * Added 'lastStartTime()' and 'currentPosition()' methods to + 'lib/rdplay_deck.cpp'. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + segfault when attempting to move an event down across a paused + event. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing corrupt + displays in the Button Log when moving an event up across a paused + event. +2004-12-08 Fred Gleason + * Added a '--check-db' switch to rdadmin(1). +2004-12-08 Fred Gleason + * Added '.RDAIRPLAY.UDP_ADDR0', 'RDAIRPLAY.UDP_PORT0', + 'RDAIRPLAY.UDP_STRING0', '.RDAIRPLAY.UDP_ADDR1', + 'RDAIRPLAY.UDP_PORT1', 'RDAIRPLAY.UDP_STRING1', + '.RDAIRPLAY.UDP_ADDR2', 'RDAIRPLAY.UDP_PORT2', + 'RDAIRPLAY.UDP_STRING2' and 'GROUPS.ENABLE_NOW_NEXT' fields to the + database. + * Incremented the database version to 68. + * Fixed a bug in 'rdadmin/rdadmin.cpp' that was causing + command-line mode of rdadmin(1) to segfault. + * Added 'enableNowNext()' and 'setEnableNowNext()' methods to + 'lib/rdgroup.cpp'. + * Added 'udpAddress()', 'setUdpAddress()', 'udpPort()', + 'setUdpPort()', udpString()' and 'setUdpString()' methods to + 'lib/rdairplay_conf.cpp'. + * Added a 'Transmit Now & Next data' control to Group Editor + dialog in RDAdmin. + * Added an 'EditNowNext' dialog in 'rdadmin/edit_now_next.cpp'. + * Added a doc file in 'docs/NOW+NEXT.txt'. + * Added code in 'rdairplay/log_play.cpp' to implement Now & Next + transmission. + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing a + segfault when attempting to execute a macro cart. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + segfault when attempting to execute a macro cart. +2004-12-09 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' which was allowing the + maximum active event limit to be exceeded. +2004-12-09 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing Now & + Next data to be transmitted regardless of whether it was enabled + in the parent group. +2004-12-09 Fred Gleason + * Added code in 'lib/rdconfig.cpp' to calculate the proper config + file location under Windows. + * Added code in 'lib/rdsvc.cpp' to calculate the proper import + file locations under Windows. +2004-12-09 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that was causing the build + to break under Windows. +2004-12-09 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + segfault when starting the last event in a log. +2004-12-09 Fred Gleason + * Fixed a bug in 'rdadmin/edit_report.cpp' that was preventing + the backslash character from being entered for the Windows export + path. + * Added code in 'lib/rdreport.cpp' to calculate the proper export + file locations under Windows. +2004-12-09 Fred Gleason + * Created a boilerplate Windows configuration file in + 'conf/rd.ini'. + * Added a 'docs/WIN32.txt' file. +2004-12-09 Fred Gleason + * Fixed bugs in 'rdairplay/edit_event.cpp', + 'rdairplay/button_log.cpp' and 'rdairplay/list_log.cpp' that were + preventing paused events from being modified. + * Fixed a bug in 'lib/rdbutton_dialog.cpp' that produced a blank + library selector widget. + * Fixed a bug in 'lib/rdpanel_button.cpp' that was causing idle + SoundPanel buttons to flash. +2004-12-14 Fred Gleason + * Fixed a bug in 'cae/cae_jack.cpp' that was causing the build to + break when built with JACK support disabled. +2004-12-14 Fred Gleason + * Changed LOGPLAY_MAX_PLAYS in 'rdairplay/log_play.h' to 7. + * Changed 'rdairplay/log_play.cpp' so that paused events alternate + faders when restarted. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing corrupt + pie widget displays when switching operational modes during segue + transitions. + * Fixed a bug in 'rdairplay.cpp' that was causing the debug log to + fail to be generated. +2004-12-15 Fred Gleason + * Updated the 'NEWS' file. + * Incremented package version to 0.9.14. +2004-12-16 Fred Gleason + * Fixed a bug in 'rdairplay/list_logs.cpp' that was preventing + events from being added to the end of a log in the Full Log + widgets. + * Removed 'toClipboard()' and 'fromClipboard()' methods from + 'lib/rdcut.cpp'. + * Added a 'copyTo()' method to 'lib/rdcut.cpp'. +2004-12-16 Fred Gleason + * Added a progress dialog to the Paste function in RDLibrary. +2004-12-17 Fred Gleason + * Deleted 'lib/rdpanel.cpp' and 'lib/rdpanel.h'. + * Added 'setLogName()' and 'LogLine()' methods to + 'lib/rdsound_panel.cpp'. +2004-12-17 Michael Figley + * Fixed a bug in 'lib/rdairplay_conf.cpp' that was causing the + build to break under Qt 3.2.x. +2004-12-17 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 0.9.15. +2004-12-17 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' that was causing the build to + break under Windows. +2004-12-20 Dan Mills + * Fixed a bug in 'lib/rdairplay_conf.cpp' that was causing the + Now&Next address to load an invalid value. +2004-12-20 Dan Mills + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing the + pie widget to become corrupt when adding additional events to a + log. +2004-12-27 Fred Gleason + * Added code to clear the shm segment for caed before starting + daemons in 'rivendell'. + * Incremented the package version to 0.9.16. +2004-12-30 Fred Gleason + * Adjusted the geometry of the 'Length' widget in + 'rdcatch/edit_recording.cpp'. + * Fixed a bug in 'liblibrary/cdripper.cpp' that was causing a rip + to proceed over an existing cut even after the user had cancelled + it. + * Added an 'addBannedChar()' method to 'lib/rdtextvalidator.cpp'. + * Added validators to prevent invalid characters in SQL table + names in 'lib/rdadd_log.cpp' and 'rdadmin/edit_svc.cpp'. + * Adjusted the layout of 'rdadmin/edit_svc.cpp' for proper display + on SuSE 9.2. +2004-12-30 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' where resources were not + be freed when an event entered PAUSE mode. +2005-01-04 Fred Gleason + * Added RDImport to the RPM build. +2005-01-04 Dan Mills + * Fixed a bug in 'utils/rdimport.cpp' that was causing imports to + fail. +2005-01-04 Dan Mills + * Fixed a bug in 'rdairplay/list_log.cpp' that was causing incorrect + time format to be dislpayed in the log window when in 12 hour mode. +2005-01-04 Dan Mills + * The stop time was always displayed in 24 hr format, added code to + make it do the right thing, and also cleared up a delay in updating + the time of day clock when changing mode. +2005-01-05 Fred Gleason + * Added a 'MarkerBar' widget in 'rdairplay/marker_bar.cpp'. + * Moved the MarkerEdit widget from 'rdlibrary/' to 'lib/'. + * Moved the MarkerButton widget from 'rdlibrary/' to 'lib/'. + * Added a marker bar widget in 'rdairplay/marker_bar.cpp'. +2005-01-06 Fred Gleason + * Add code to 'lib/rdplay_deck.cpp' to allow the deck state to be + changed directly from Paused to Stopped. + * Overhauled the EditEvent dialog in RDAirPlay for use a new + layout and user interface. +2005-01-10 Fred Gleason + * Added the 'Run Shell Command' ['RN'] macro to 'docs/rml.sxw'. + * Implemented the 'Run Shell Command' ['RN'] macro. +2005-01-10 Fred Gleason + * Added BtAcs82 to RDMatrix::Type in 'lib/rdmatrix.h'. + * Added support for the BroadcastTools ACS 8.2 switcher to + RDAdmin. + * Added a driver for the BroadcastTools ACS 8.2 switcher in + 'ripcd/btacs82.cpp'. +2005-01-10 Fred Gleason + * Corrected notes for the BroadcastTools ACS 8.2 switcher in + 'docs/SWITCHERS.TXT +2005-01-17 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing phantom + signals to be emitted. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.17. +2005-01-19 Fred Gleason + * Added 'MATRICES.PORT_TYPE', 'MATRICES.IP_ADDRESS' and + 'MATRICES.IP_PORT' fields to the database. + * Incremented the database version to 69. + * Added 'portType()', 'setPortType()', 'ipAddress()', + 'setIpAddress()', 'ipPort()' and 'setIpPort()' methods to + to RDMatrix in 'lib/rdmatrix.cpp'. + * Added 'Port Type', 'IP Address' and 'IP Port' controls to the + Edit Matrix dialog in RDAdmin. + * Added an 'SasUse' class in 'lib/sasusi.cpp'. + * Implemented the 'ST' and 'GO' macros for the SAS User Serial + Interface protocol. +2005-01-20 Fred Gleason + * Added automatic connection retries for the SasUsi driver in + 'ripcd/sasusi.cpp'. + * Added the 'Console Label' ['CL'] macro to 'docs/rml.sxw'. + * Implemented the 'Console Label' ['CL'] macro. + * Added the 'Fire Salvo' ['FS'] macro to 'docs/rml.sxw'. + * Implemented the 'Fire Salvo' ['FS'] macro. + * Added the 'Switch Add With Gain' ['SG'] macro to 'docs/rml.sxw'. + * Implemented the 'Switch Add With Gain' ['SG'] macro. + * Added the 'Switch Crosspoint Gain' ['SX'] macro to 'docs/rml.sxw'. + * Implemented the 'Switch Crosspoint Gain' ['SX'] macro. + * Added an entry for the SAS 32KD Audio Switcher to + 'docs/SWITCHERS.txt'. +2005-01-21 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.18. +2005-01-25 Fred Gleason + * Fixed a bug in 'scripts/rd_import_file' that was causing the + temporary WAV file to be written with read-only permissions. +2005-01-26 Fred Gleason + * Fixed a bug in 'rdlogmanager/edit_event.cpp' and + 'rdlogmanager/list_events.cpp' that was causing corrupt event + entries when saving and then cancelling a newly added event. + * Fixed a bug in 'rdlogmanager/edit_event.cpp' that was causing an + incorrect transition type to be shown in the properties string + when events will in the preimport list. + * Adjusted font sizes in 'rdlogmanager/edit_event.cpp' for proper + display under SuSE 9.2. + * Adjusted size of the date control in + 'rdlogmanager/generate_log.cpp' for proper display under SuSE 9.2. + * Adjusted size of the date control in + 'rdlogmanager/generate_report.cpp' for proper display under SuSE + 9.2. + * Fixed a bug in 'rdlibrary/add_cart.cpp' that was allowing + patently invalid cart numbers to be entered. + * Incremented the package version to 0.9.19. +2005-01-27 Fred Gleason + * Fixed a bug in 'conf/crc-unity4k.sh' that was transposing the + Name and Feed for the LF1 service. + * Added 'RDReport::TextLog' to 'RDReport::ExportFilter' in + 'lib/rdreport.h'. + * Added a 'Text Log' item to the report filter selector in + 'rdadmin/edit_report.cpp'. + * Added a 'PLAY_SOURCE' field to the reconciliation table format + in the database. + * Added 'playSource()' and 'setPlaySource()' methods to + 'lib/rdlog_line.cpp'. + * Added 'TrafficAction::TrafficMacro' to + 'RDAirPlayConf::TrafficAction' in 'lib/rdairplay_conf.h'. + * Fixed a bug in 'rdlogmanager/edit_event.cpp' that was causing + 'SaveAs' events to lose their PRE and POST tables. + * Fixed a bug in 'lib/rdclock.cpp' that was causing 'validate()' + to fail to catch all possible overlap errors. +2005-01-27 Fred Gleason + * Fixed a bug in 'rdairplay/edit_event.cpp' that was causing a + segfault when opening the EditEvent dialog for a macro cart event. + * Added logic to 'rdadmin/edit_backup.cpp' to verify the presence + of a backup path. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.20. +2005-01-28 Dan Mills + * Fixed a segfault in rdairplay when station and user panel counts + were both set to one, also fixed some other edge cases in the same + area. + * Added support for 12 Hr time format to post point display. The + countdown is still broken when the postpoint is the other side of + midnight! +2005-01-28 Fred Gleason + * Added 'mpg123' to the 'Requires:' rule in 'rivendell.spec.in'. + * Created an 'RDComboBox' class in 'lib/rdcombobox.cpp'. + * Fixed a bug in 'lib/rdcart_dialog.cpp' that was causing + duplicate entries in the Group Filter list. + * Added Event Attributes to the Event Name column in + 'rdlogmanager/edit_clock.cpp'. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.21. +2005-01-28 Fred Gleason + * Fixed a bug in 'rdairplay/edit_event.cpp' that was causing the + grace time setting for hard events to fail to be saved. + * Fixed a bug in 'rdairplay/loglinebox.cpp' that was failing to + initialize properly the time format string. +2005-01-30 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing the + Grace Time parameter in hard timed events to be ignored. + * Fixed a bug in 'rdairplay/log_play.cpp' where hard timed events + set to 'Make Next' would instead start the event if the log was + stopped down. +2005-01-30 Dan Mills + * Minor documentation changes to the INSTALL file. + Added bc to the prereqs as it is used in rd_import_file. + Added a note about starting jackd BEFORE the rivendell daemons. +2005-01-31 Fred Gleason + * Added a sanity check to RDSvc::import() in 'lib/rdsvc.cpp' to + prevent importation of events with invalid cart numbers. + * Fixed a bug in 'rdlogmanger/generate_log.cpp' that was causing + the warning message for overwriting an existing log to have a + misformatted date. + * Disabled the event length check in RDEventLine::generateLog() in + 'lib/rdevent_line.cpp'. + * Added '/' to the list of banned characters for Event Names and + Clock Names in RDLogManager. + * Added a 'Color' column to the ListEvents and ListClocks widgets + in RDLogManager. + * Added search new file search filters to + 'rdlibrary/import_audio.cpp'. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.22. +2005-01-31 Fred Gleason + * Added 'bc' to the 'Requires:' rule in 'rivendell.spec.in'. + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing a + segfault when pressing one of the AuxLog buttons with soundpanels + disabled. +2005-01-31 Fred Gleason + * Increased LOOK_AHEAD_EVENTS to 5000 in 'rdairplay/log_play.cpp'. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.23. +2005-02-01 Fred Gleason + * Fixed a bug in 'rdlogmanager/list_events.cpp' that was throwing + a segfault when exiting from the EditEvent dialog. + * Fixed a bug in 'rdlogmanager/list_clocks.cpp' that was throwing + a segfault when exiting from the EditClocks dialog. + * Added logic to 'rdlogmanager/list_events.cpp' to detect and + prompt for confirmation before deleting an event that is in use in + one or more clocks. + * Added logic to 'rdlogmanager/list_clocks.cpp' to detect and + prompt for confirmation before deleting a clock that is in use in + one or more grids. +2005-02-01 Fred Gleason + * Added a 'RDLogEvent::validate()' method to + 'lib/rdlog_event.cpp'. + * Added an 'RDExceptionDialog' dialog in + 'lib/rdexception_dialog.cpp; + * Added a 'Check Log' button to RDLogEdit's log editor. + * Added code to run an exception report after generating a new log + in RDLogManager. +2005-02-01 Fred Gleason + * Fixed a bug in 'rdlogmanager/rdlogmanager.pro' that was causing + the build to break under Windows. +2005-02-01 Fred Gleason + * Added a LogLine() call in 'LogPlay::makeNext()' in + 'rdairplay/log_play.cpp'. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.24. +2005-02-07 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that was causing imported + events in RDLogManager to be lost. +2005-02-08 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.25. +2005-02-14 Fred Gleason + * Fixed a bug in 'cae/cae_hpi.cpp' that was causing MPEG recording + to fail. + * Removed all event-length checks from RDEventLine::generateLog() + in 'lib/rdevent_line.cpp'. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.26. +2005-02-17 Fred Gleason + * Added a 'Show DayOfWeek' filter to RDCatch. +2005-02-21 Fred Gleason + * Fixed a bug in 'rdadmin/edit_matrix.cpp' that was causing the + 'Port' control to be enabled for local GPIO devices. + * Fixed a bug in 'utils/rdgpimon.cpp' that was causing the listed + GPI line numbers to be off by one. +2005-02-21 Fred Gleason + * Fixed a bug in 'cae/cae_jack.cpp' that was activating the JACK + connection before allocating all of the callback buffers. +2005-03-01 Fred Gleason + * Added support for the BroadcastTools 16x2 switcher. + * Incremented the package version to 0.9.27. +2005-03-04 Fred Gleason + * Fixed a bug in 'lib/rdcart_dialog.cpp' that was causing an + invalid cart number to be returned if the dialog was cancelled. + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing a + segfault when executing a macro cart. +2005-03-06 Fred Gleason + * Added support for the BroadcastTools SS 12.4 switcher. +2005-03-07 Fred Gleason + * Added an argument to specify machine port to the Start Next 'PN' + RML. +2005-03-07 Fred Gleason + * Added a 'LENGTH' column to the EditLog dialog in RDLogEdit. + * Added a 'group' parameter to the constructor for RDCartDialog + in 'lib/rdcart_dialog.cpp'. + * Added a Talk Stime counter to the cart label in the Button + Widget in RDAirPlay. +2005-03-07 Fred Gleason + * Incremented the package version to 0.9.28. +2005-03-07 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp that was causing the + 'SOURCE' column to fail to be properly updated after editing a + Record Event. +2005-03-08 Fred Gleason + * Added 'RECORDINGS.START_TYPE','RECORDINGS.START_LENGTH', + 'RECORDINGS.START_LINE','RECORDINGS.START_MATRIX', + 'RECORDINGS.START_OFFSET', 'RECORDINGS.END_TYPE', + 'RECORDINGS.END_TIME','RECORDINGS.END_LENGTH','RECORDINGS.END_MATRIX', + and 'RECORDINGS.END_LINE' to the database. + * Incremented the database version to 71. + * Reformatted the EditRecording dialog in 'rdcatch.cpp' to use the + new Start and End parameters. +2005-03-14 Fred Gleason + * Fixed a bug in rdlogedit/edit_log.cpp that was causing segfaults + when editing log events. +2005-03-15 Fred Gleason + * Fixed a bug in 'lib/rdcae.cpp' that was causing a race, + * Fixed a bug in 'lib/rdcatch_connect.cpp' that was causing a race, + * Fixed a bug in 'lib/rdripc.cpp' that was causing a race, + * Fixed a bug in 'cae/cae.cpp' that was causing a race, + * Fixed a bug in 'ripcd/bt16x2.cpp' that was causing a race, + * Fixed a bug in 'ripcd/btacs82.cpp' that was causing a race, + * Fixed a bug in 'ripcd/btss82.cpp' that was causing a race, + * Fixed a bug in 'ripcd/ripcd.cpp' that was causing a race, +2005-03-21 Fred Gleason + * Fixed a bug in 'scripts/rd_rip_cd' that broke normalization. +2005-03-22 Fred Gleason + * Added 'Waiting' to RDeck::Status in 'lib/rddeck.h'. + * Added code to handle the 'Waiting' state to 'rdcatch/deckmon.cpp. + * Added code to handle the 'Waiting' state to 'rdcatch/rdcatch.cpp. + * Implemented the GPI start type in 'rdcatchd/rdcatchd.cpp'. + * Updated the format of the 'END' column for Playout events to + conform to the new scheme. +2005-03-22 Fred Gleason + * Implemented the GPI end type in 'rdcatchd/rdcatchd.cpp'. + * Implemented the LENGTH end type in 'rdcatchd/rdcatchd.cpp'. +2005-03-25 Fred Gleason + * Changed the error dialog in the Cart Record dialog in RDLibrary + so that it merely warns about saving an expired cut, rather than + preventing it. +2005-03-30 Fred Gleason + * Added a 'GROUPS.DEFAULT_CART_TYPE' field to the database. + * Incremented the database version to 72. + * Added 'defaultCartType()' and 'setDefaultCartType()' methods to + RDGroup in 'lib/rdgroup.cpp'. + * Added a 'Default Cart Type' control to the EditGroup dialog in + RDAdmin. + * Added logic to 'rdlibrary/add_cart.cpp' to implement Default + Cart Type preselection. + * Added logic to 'rdlibrary/rdlibrary.cpp' so set the default + group to the currently selected filtering group. +2005-04-04 Fred Gleason + * Added an 'RDAIRPLAY.DEFAULT_TRANS_TYPE' field to the database. + * Incremented the database version to 73. + * Added 'defaultTransType()' and 'setDefaultTransType()' methods + to RDAirPlayConf in 'lib/rdairplay_conf.cpp'. + * Added a 'Default Transition Type' control to the RDAirPlay + configuration dialog in RDAdmin. +2005-04-06 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing duplicate + 'stateChanged()' signals to be emitted. +2005-04-06 Fred Gleason + * Fixed a bug in 'lib/rdlog_line.cpp' that was causing invalid + returns to 'startPoint()' and 'endPoint()'. + * Fixed a bug in 'rdairplay/loglinebox.cpp' that was causing the + Talk Time field to fail to be cleared. + * Change the logic in 'rdairplay/loglinebox.cpp' to show ':00' for + events with zero talk time. + * Fixed a bug in 'rdairplay/edit_event.cpp' that was causing a + segfault when trying to modify an event with no valid cut. +2005-04-06 Fred Gleason + * Added logic to 'lib/rdplay_deck.cpp' so as to prevent a rotator + event from advancing when resuming from a paused state. +2005-04-06 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing the log + to stall when attempting to execute an event with no valid cut. +2005-04-11 Fred Gleason + * Fixed a bug in 'lib/rdlog_line.cpp' that was returning an + invalid segueLength() for cuts with no segue marker set. +2005-04-13 Fred Gleason + * Fixed a bug in 'rdadmin/list_svcs.cpp' that was causing orphaned + service name entries to be left in the 'SERVICE_PERMS', + 'AUDIO_PERMS' and 'AUTOFILLS' tables after deleting the service. + * Fixed a bug in 'rdadmin/list_svcs.cpp' that was causing orphaned + service name entries to be left in the 'SERVICE_PERMS', + 'RDAIRPLAY', 'RDLIBRARY', 'MATRICES', 'GPIS' and 'HOSTVARS' tables + after deleting the host. +2005-04-24 Dan Mills + * Applied patch from darrick to fix 0000007: cae shmctl remove + block bug. Shmctl to remove a pre existing meter block left from + a cae crash is called with memory key but should be called with id + instead. Status set to resolved. +2005-04-24 Fred Gleason + * Added a '[Hacks]' section to rd.conf(5). + * Added a 'UseStreamMeters=' directive in the [Hacks] section of + rd.conf(5). + * Added a hack to 'cae/cae_hpi.cpp' to allow stream meters to be + used if the 'UseStreamMeters=' directive is set to 'Yes'. + * Added a 'useStreamMeters()' method to 'lib/rdconfig.cpp'. + * Added logic to 'rdairplay/rdairplay.cpp' to hide the audio meter + if the 'UseStreamMeters=' directive is set to 'Yes'. + * Updated 'SupportedCards'. +2005-04-24 Fred Gleason + * Fixed a bug in 'rdadmin/edit_deck.cpp' that was setting an + invalid format type in the database. +2005-04-26 Fred Gleason + * Reenabled ALSA build support in 'configure.in'. + * Implemented direct ALSA playout support for + SND_PCM_FORMAT_S32_LE devices in 'cae/cae_alsa.cpp'. +2005-04-28 Fred Gleason + * Implemented direct ALSA playout support for + SND_PCM_FORMAT_S16_LE devices in 'cae/cae_alsa.cpp'. + * Fixed a bug in 'cae/cae.cpp' that was failing to kill active + events when the event's controlling connection terminated. +2005-04-29 Fred Gleason + * Implemented the basic structure for ALSA capture support. +2005-04-29 Fred Gleason + * Implemented direct ALSA capture support for + SND_PCM_FORMAT_S16_LE devices in 'cae/cae_alsa.cpp'. + * Implemented direct ALSA capture support for + SND_PCM_FORMAT_S32_LE devices in 'cae/cae_alsa.cpp'. +2005-04-29 Fred Gleason + * Fixed a bug in 'cae/cae_alsa.cpp' that had broken cursor updates + in RDLibrary's Marker Editor when using ALSA output. + * Added notes on configuration for use with ALSA in 'docs/ALSA.txt'. +2005-04-29 Fred Gleason + * Added notes on building ALSA support in 'INSTALL'. + * Added a '--disable-alsa' switch to the configure script in + 'configure.in'. +2005-05-02 Fred Gleason + * Fixed a bug in 'rdlibrary/record_cut.cpp' that was opening a + connection to CAE using a compiled-in password. +2005-05-03 Fred Gleason + * Enabled log output for inactive and non-matching DOW event list + entries in /rdcatchd/rdcatchd.cpp'. + * Added a test for Secret Rabbit Code in 'configure.in'. + * Implemented on-the-fly sample rate conversion for the JACK + driver. + * Fixed endian-dependencies in 'cae/cae_jack.cpp'. + * Implemented on-the-fly sample rate conversion for the ALSA + driver. +2005-05-03 Fred Gleason + * Added a note on Secret Rabbit Code to 'INSTALL'. +2005-05-04 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing an Abort + of a recording event waiting for a GPI event to be ignored. +2005-05-04 Fred Gleason + * Added an 'exists()' method to RDMatrix in 'lib/rdmatrix.cpp'. + * Added code in 'rdcatch/edit_recording.cpp' to enforce sane + time and GPI values in the Edit Recording dialog. + * Fixed a bug in 'rdcatch/add_recording.cpp' that was causing a + corrupt catch event to be created if the escape key was pressed + while in the Add Event dialog. +2005-05-05 Dan Mills + * Rdlibrary now defaults the start marker to zero and the end + marker to the end of the audio rather then leaving them unset. + *rdlog_line now uses the rdcart class to handle the SQL query + for markers and handles unset markers gracefully. + * Both of these in aid of fixing bug #20. +2005-05-06 Fred Gleason + * Fixed a bug in 'cae/cae_alsa.cpp' that was causing segue + overlaps to be abnormally short. + * Fixed a bug in 'cae/cae_jack.cpp' that was segue overlaps act + like play transitions. + * Fixed a bug in 'cae/cae_jack.cpp' that was causing segue + overlaps to be abnormally short. +2005-05-06 Dan Mills + * Fixed a bug in lib/rdsoundpanel.cpp that was causing RML PT + commands to non configured buttons to crash rdairplay. + Hopefully sorts out bug # 34 +2005-05-08 Dan Mills + * made CAED config error messages more helpful. +2005-05-09 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing events + with a FadeUp marker set to repeat the fadeup when resuming from a + PAUSED state. + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing unreliable + FadeUp operation. + * Fixed a bug in 'cae/cae_jack.cpp' that was causing + FadeUp/FadeDown times to be incorrectly calculated. + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing the state + of the play deck to fail to be initialized correctly when loading + a new event. + * Fixed a bug in 'cae/cae_alsa.cpp' that was causing + FadeUp/FadeDown times to be incorrectly calculated. +2005-05-10 Fred Gleason + * Fixed a bug in 'cae/cae.cpp' that was causing the build to break + when building without SRC support. + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Updated the 'SupportedCards' file. + * Updated the package version to 0.9.31. +2005-05-10 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' that was causing the build to + break under Windows. +2005-05-10 Fred Gleason + * Added a test for the format conversion functions in Secret + Rabbit Code in 'configure.in'. + * Updated the package version to 0.9.32. +2005-05-10 Fred Gleason + * Fixed in a bug in 'configure.in' that was failing to detect the + format conversion functions in Secret Rabbit Code. +2005-05-11 Fred Gleason + * Fixed a bug in 'cae/cae_alsa.cpp' that was causing distorted + playout for ALSA devices using period quantities greater then 2. +2005-05-11 Dan Mills + * Checked in start on fixes for logs crossing midnight issues. + * Attempted to reduce flickering of next stop widget (not totally + successful - it is inherent in updating pixmaps on buttons). +2005-05-16 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was casuing fade + events to use a low limit of RD_MUTE_DEPTH rather than + RD_FADE_DEPTH. + * Fixed in bug in 'cae/cae_alsa.cpp' that was calculating + incorrect fade durations. + * Fixed in bug in 'cae/cae_jack.cpp' that was calculating + incorrect fade durations. +2005-05-16 Fred Gleason + * Fixed bugs in 'rdairplay/log_play.cpp' that was causing a PAUSED + event to resume with the incorrect audio (Mantis #42). + * Updated the package version to 0.9.33. +2005-05-17 Fred Gleason + * Fixed bugs in 'rdlibrary/edit_audio.cpp' that was causing + incorrect calculation of cart length when 'Enforce Length' was + checked. + * Fixed a bug in 'lib/rdcart.cpp' that was causing the + 'updateLength()' method to fail if called with ENFORCE_LENGTH + enabled. + * Added code to 'rdlibrary/rdlibrary.cpp' to show Cart Length in + green if ENFORCE_LENGTH is enabled for that cart. +2005-05-17 Fred Gleason + * Added a 'TS' [Timescale Supported] command to the CAE protocol + spec. + * Incremented the CAE protocol spec version to 0.9.1. + * Implemented a 'TS' [Timescale Supported] command in caed(8). + * Added support for the 'TS' [Timescale Supported] command for the + RDCae class in 'lib/rdcae.cpp'. +2005-05-20 Fred Gleason + * Added 'timescalingActive()' and 'setTimescalingActive()' methods + to RDLogLine in 'lib/rdlog_line.cpp'. + * Added a 'requestTimescale()' method to RDCae in 'lib/rdcae.cpp'. + * Added a 'timescalingSupported()' signal to RDCae in + 'lib/rdcae.h'. + * Added code to 'rdairplay/loglinebox.cpp' to display the Length + field in blue if timescaling is active for the event. + * Implemented timescaling support in RDSoundPanel. + * Fixed a bug in 'lib/rdlog_line.cpp' that was causing + RDLogLine::loadCart() to fail to load the ENFORCE_LENGTH + attribute. +2005-05-20 Fred Gleason + * Added a sanity check to the Edit Cart dialog in RDLibrary to + warn about saving carts with parameters that exceed the + timescaling limits of the system. + * Added logic to grey-out the 'Enforce Length' checkbox in the + Edit Cart dialog when editing a macro cart. +2005-05-23 Fred Gleason + * Added a '%r' Now&Next Now&Next macro. +2005-05-23 Fred Gleason + * Added 'CLOCK_PERMS' and 'EVENT_PERMS' tables to the database. + * Incremented the database version to 74. + * Added a 'Service Associations' dialog box in + 'rdlogmanager/edit_perms.cpp'. + * Added a 'Filter' list in the 'List Events' dialog in + 'rdlogmanager/list_events.cpp'. +2005-05-23 Fred Gleason + * Added a 'Filter' control to RDLogManager's List Events dialog + in 'rdlogmanager/list_events.cpp'. + * Added a 'Filter' control to RDLogManager's List Clocks dialog + in 'rdlogmanager/list_clocks.cpp'. +2005-05-24 Fred Gleason + * Implemented 'AL' ['Set Audio Passthrough Level'] CAE command + support for the HPI driver. + * Added a 'MATRICES.CARD' field to the database. + * Updated the database version to 75. + * Added 'card()' and 'setCard()' methods to RDMatrix in + 'lib/rdmatrix.cpp'. + * Added a 'Local Audio Adapter' switcher driver. + * Implemented the 'ST', 'SA', 'SR' and 'SX' RMLs for the 'Local + Audio Adapter' driver. +2005-05-25 Fred Gleason + * Added a 'Monitor Deck' section to the Edit Decks dialog in + RDAdmin->RDCatch in in 'rdadmin/edit_decks.cpp'. + * Added a 'DECKS.MON_PORT_NUMBER' field to the database. + * Incremented the database version to 76. + * Added 'monitorPortNumber()' and 'setMonitorPortNumber()' methods + to RDDeck in 'lib/rddeck.cpp'. + * Added a 'Monitor Port' control to RDAdmin's Configure RDCatch + dialog in 'rdadmin/edit_decks.cpp'. + * Added a 'monitor()' method to RDCatchConnect in + 'lib/rdcatch_connect.cpp' + * Added a 'monitorChanged()' signal to RDCatchConnect in + 'lib/rdcatch_connect.h'. + * Added code to 'cae/cae.cpp' to mute all passthrough channels + when starting up caed(8). +2005-05-25 Fred Gleason + * Added code to 'rdcatch/deckmon.cpp' to disable the Monitor button + on non-local status monitors. +2005-05-25 Fred Gleason + * Added code to 'rdcatch/rdcatch.cpp' to disable the Monitor button + if no monitor port is configured for the corresponding record + deck. +2005-05-25 Fred Gleason + * Implemented 'AL' ['Set Audio Passthrough Level'] CAE command + support for the JACK driver. +2005-05-27 Fred Gleason + * Fixed a bug in 'cae/cae_alsa.cpp' that was causing incorrect + input meter levels. + * Implemented 'AL' ['Set Audio Passthrough Level'] CAE command + support for the ALSA driver using signed 32 integer sample format. +2005-05-31 Fred Gleason + * Implemented 'AL' ['Set Audio Passthrough Level'] CAE command + support for the ALSA driver using signed 16 integer sample format. + * Fixed a bug in 'cae/cae_jack.cpp' that was causing audio + passthroughs to mute active output streams. +2005-05-31 Fred Gleason + * Added usage notes on the Local Audio Adapter switcher driver to + 'docs/SWITCHERS.txt'. +2005-05-31 Fred Gleason + * Added an input field to 'scripts'rd_import_file' for the source + audio format. + * Fixed a bug in 'scripts/rd_import_file' that had broken imports + to MPEG L2 format. +2005-06-01 Fred Gleason + * Changed 'scripts/rd_import_file' to use mpg321(1) instead of + mpg123(1). +2005-06-01 Fred Gleason + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.34. +2005-06-03 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing incorrect + audio to play in Audition in RDAirPlay (Mantis bug #47). +2005-06-03 Fred Gleason + * Fixed a bug in 'scripts/rd_import_file' that was causing .mp2 + file imports to fail. + * Added import support for ATX file format. +2005-06-03 Fred Gleason + * Fixed a bug in 'utils/rdimport.cpp' that was causing all imports + to fail (Mantis bug #48). +2005-06-05 Fred Gleason + * Moved 'utils/sas_filter.cpp' to 'importers/sas_filter.cpp'. + * Moved 'utils/sas_filter.h' to 'importers/sas_filter.h'. +2005-06-10 Fred Gleason + * Added I18N support to the build system. +2005-06-11 Fred Gleason + * Added the 'tr()' wrapper to strings in 'lib/rdadd_log.cpp'. + * Added the 'tr()' wrapper to strings in 'lib/rdbutton_dialog.cpp'. + * Added the 'tr()' wrapper to strings in 'lib/rdcardselector.cpp'. + * Added the 'tr()' wrapper to strings in 'lib/rdcart_dialog.cpp'. + * Added the 'tr()' wrapper to strings in 'lib/rdcut_dialog.cpp'. + * Added the 'tr()' wrapper to strings in 'lib/rdcut_path.cpp'. + * Added the 'tr()' wrapper to strings in 'lib/rdedit_settings.cpp'. + * Added the 'tr()' wrapper to strings in 'lib/rdexception_dialog.cpp'. + * Added the 'tr()' wrapper to strings in 'lib/rdgpioselector.cpp'. + * Added the 'tr()' wrapper to strings in 'lib/rdpasswd.cpp'. + * Added the 'tr()' wrapper to strings in 'lib/rdsound_panel.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/add_group.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/add_hostvar.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/add_matrix.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/add_report.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/add_station.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/add_svc.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/add_user.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/autofill_carts.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_audios.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_backup.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_decks.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_endpoint.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_gpi.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_group.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_hostvar.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_matrix.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_now_next.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_rdairplay.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_rdlibrary.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_report.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_station.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_svc.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_svc_perms.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_ttys.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/edit_user.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/info_dialog.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/list_endpoints.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/list_gpis.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/list_groups.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/list_hostvars.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/list_matrices.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/list_reports.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/list_stations.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/list_svcs.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/list_users.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/login.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/mysql_login.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/opendb.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/rdadmin.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/rename_group.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/test_import.cpp'. + * Added the 'tr()' wrapper to strings in 'rdadmin/view_adapters.cpp'. + * Added the 'tr()' wrapper to strings in 'rdairplay/edit_event.cpp'. + * Added the 'tr()' wrapper to strings in 'rdairplay/list_log.cpp'. + * Added the 'tr()' wrapper to strings in 'rdairplay/list_logs.cpp'. + * Added the 'tr()' wrapper to strings in 'rdairplay/loglinebox.cpp'. + * Added the 'tr()' wrapper to strings in 'rdairplay/mode_display.cpp'. + * Added the 'tr()' wrapper to strings in 'rdairplay/post_counter.cpp'. + * Added the 'tr()' wrapper to strings in 'rdairplay/rdairplay.cpp'. + * Added the 'tr()' wrapper to strings in 'rdairplay/start_button.cpp'. + * Added the 'tr()' wrapper to strings in 'rdairplay/stop_counter.cpp'. + * Added QT_TR_NOOP() macros to strings in 'rdairplay/colors.h'. + * Added the 'tr()' wrapper to strings in 'rdcatch/add_recording.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/deckmon.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/edit_cartevent.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/edit_recording.cpp'. + * Added the 'tr()' wrapper to strings in + 'rdcatch/edit_switchevent.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/rdcatch.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlibrary/add_cart.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/audio_cart.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/cdripper.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/edit_audio.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/edit_cart.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/edit_macro.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/filter.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/import_audio.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/macro_cart.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/rdlibrary.cpp'. + * Added the 'tr()' wrapper to strings in 'rdcatch/record_cut.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogedit/add_meta.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogedit/edit_chain.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogedit/edit_log.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogedit/edit_logline.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogedit/edit_marker.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogedit/list_logs.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogedit/rdlogedit.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogin/rdlogin.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogmanager/add_clock.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogmanager/add_event.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogmanager/edit_clock.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogmanager/edit_event.cpp'. + * Added the 'tr()' wrapper to strings in + 'rdlogmanager/edit_eventline.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogmanager/edit_grid.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogmanager/edit_note.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogmanager/edit_perms.cpp'. + * Added the 'tr()' wrapper to strings in + 'rdlogmanager/export_deltaflex.cpp'. + * Added the 'tr()' wrapper to strings in + 'rdlogmanager/generate_log.cpp'. + * Added the 'tr()' wrapper to strings in + 'rdlogmanager/generate_Report.cpp'. + * Added the 'tr()' wrapper to strings in + 'rdlogmanager/import_listview.cpp'. + * Added the 'tr()' wrapper to strings in + 'rdlogmanager/list_clocks.cpp'. + * Added the 'tr()' wrapper to strings in + 'rdlogmanager/list_events.cpp'. + * Added the 'tr()' wrapper to strings in + 'rdlogmanager/list_grids.cpp'. + * Added the 'tr()' wrapper to strings in + 'rdlogmanager/rdlogmanager.cpp'. + * Added the 'tr()' wrapper to strings in 'utils/rdgpimon.cpp'. + * Added the 'tr()' wrapper to strings in 'rdlogmanager/rmlsend.cpp'. + * Added code to load translation data in 'utils/rmlsend.cpp'. + * Added code to load translation data in 'utils/rdgpimon.cpp'. + * Added code to load translation data in 'rdadmin/rdadmin.cpp'. + * Added code to load translation data in 'rdairplay/rdairplay.cpp'. + * Added code to load translation data in 'rdcatch/rdcatch.cpp'. + * Added code to load translation data in 'rdlibrary/rdlibrary.cpp'. + * Added code to load translation data in 'rdlibrary/rdlogedit.cpp'. + * Added code to load translation data in 'rdlibrary/rdlogin.cpp'. + * Added code to load translation data in + 'rdlogmanager/rdlogmanager.cpp'. +2005-06-11 Fred Gleason + * Cleaned up code warnings. +2005-06-11 Fred Gleason + * Fixed a bug in 'rdlogin/rdlogin.pro' that was causing the 'make + install' target to break. +2005-06-11 Fred Gleason + * Removed 'local_macros'h' from the HEADERS rule in + 'rdairplay/'rdairplay.pro', which was causing a spurious error + message. +2005-06-12 Dan Mills + * backed out one of the cleanups (lib/rdpanel_button.cpp) that was + causing rdairplay to fail to startup with some button names. + Fixed warnings by scattering a few casts around instead. + Mantis issue # 51. +2005-06-11 Fred Gleason + * Added 'helpers/rdtrans.sh' and 'helpers/rdpack.sh' utilities. +2005-06-12 Fred Gleason + * Retired the 'USERS.ADMIN_USERS_PRIV' field in the database. + * Removed the 'Administer Users' checkbox from + RDAdmin->ManageUsers. + * Retired the 'USERS.ASSIGN_CART_PRIV' field in the database. + * Removed the 'Assign Carts' checkbox from + RDAdmin->ManageUsers. +2005-06-12 Dan Mills + * Fixed uninitialised variable in the post counter class. + It probably did not hurt anything, but I am just trying to be + valgrind clean. +2005-06-12 Fred Gleason + * Removed 'adminUsers()', 'setAdminUsers()', 'assignCarts()' and + 'setAssignCarts()' methods from RDUser in 'lib/rduser.cpp'. + * Added a 'USER_PERMS' table to the database. + * Incremented the database version to 77. + * Added an 'EditUserPerms' dialog in + 'rdadmin/edit_user_perms.cpp'. + * Added an RDAllCartSearchText()' function in + 'lib/rdcartsearchtext.cpp'. +2005-06-12 Fred Gleason + * Added code to 'rdlibrary/edit_carts.cpp' to enforce the 'Modify + Carts' attribute. + * Added code to 'rdlibrary/macro_cart.cpp' to enforce the 'Modify + Carts' attribute. + * Added code to 'rdlibrary/audio_cart.cpp' to enforce the 'Edit + Audio' attribute. +2005-06-13 Fred Gleason + * Added code to 'rdlibrary/add_cart.cpp' to implement user + permissioned groups. + * Added code to 'rdlibrary/record_cut.cpp' to enforce the 'Modify + Carts' attribute. + * Added code to 'rdlibrary/record_cut.cpp' to enforce the 'Edit + Audio' attribute. + * Added code to 'rdlibrary/edit_audio.cpp' to enforce the 'Edit + Audio' attribute. +2005-06-13 Fred Gleason + * Added code to 'rdcatch/rdcatch.cpp' to enforce the 'Edit + Netcatch Schedule' attribute. +2005-06-13 Fred Gleason + * Added code to 'rdlogedit/rdlogedit.cpp' to enforce the 'Create + Log' attribute. + * Added code to 'rdlogedit/rdlogedit.cpp' to enforce the 'Delete + Log' attribute. + * Added code to 'rdlogedit/edit_log.cpp' to enforce the 'Create + Log' attribute. + * Added code to 'rdlogedit/edit_log.cpp' to enforce the 'Add To + Log' attribute. + * Added code to 'rdlogedit/edit_log.cpp' to enforce the 'Remove + From Log' attribute. + * Added code to 'rdlogedit/edit_log.cpp' to enforce the 'Arrange + Log' attribute. +2005-06-13 Fred Gleason + * Added a 'USERS.MODIFY_TEMPLATE_PRIV' field to the database. + * Incremented the database version to 78. + * Added 'RDUser::modifyTemplate()' and + 'RDUser::setModifyTemplate()' methods to 'lib/rduser.cpp'. + * Added a 'Modify Template' control to RDAdmin->EditUser in + 'rdadmin/edit_users.cpp'. + * Added code to 'rdlogmanager/rdlogmanager.cpp' to enforce the 'Create + Log' attribute. + * Added code to 'rdlogmanager/rdlogmanager.cpp' to enforce the + 'Modify Template' attribute. +2005-06-13 Fred Gleason + * Added code to 'rdairplay/rdairplay.cpp' to enforce the + 'Add To Log' attribute. + * Added code to 'rdairplay/rdairplay.cpp' to enforce the + 'Remove From Log' attribute. + * Added code to 'rdairplay/rdairplay.cpp' to enforce the + 'Rearrange Log' attribute. + * Added code to 'rdairplay/rdairplay.cpp' to enforce the + 'Play Log' attribute. + * Added code to 'rdairplay/list_log.cpp' to enforce the + 'Play Log' attribute. + * Added code to 'rdairplay/list_logs.cpp' to enforce the + 'Create Log' attribute. +2005-06-14 Fred Gleason + * Changed the logic in RDAirPlay to restrict the available list of + audio groups to the ORed set of loaded log services. If no logs + are loaded, then use the 'allowed' service set from SERVICE_PERMS + as before. + * Changed the logic in RDLogEdit so that the ability to reassign + log membership to a service is controlled by the 'Create Log' + rather than the 'Modify Log' attribute. +2005-06-15 Fred Gleason + * Added a 'GROUPS.ENFORCE_CART_RANGE' field to the database. + * Incremented the database version to 79. + * Rewrote the 'ListGroups' dialog in 'rdadmin/list_Groups.cpp' to + use a QListView widget. + * Added 'RDGroup::enforceCartRange()' and + 'RDGroup::setEnforceCartRange()' methods in 'lib/rdgroup.cpp'. + * Added an 'Enforce Cart Range' control to the Edit Group dialog + in 'rdadmin/edit_group.cpp'. + * Added code to 'rdadmin/edit_group.cpp' to detect conflicts in + cart number ranges. + * Implemented cart range enforcement in 'rdlibrary/add_cart.cpp'. +2005-06-15 Fred Gleason + * Added logic to RDAdmin->AddGroup to enable all services by + default in 'rdadmin->add_group.cpp'. + * Fixed a bug in 'rdadmin/list_groups.cpp' that was causing the + line for a newly-created group to be stuck in a 'selected' state. + * Added logic to RDAdmin->AddGroup to enable all groups by + default in 'rdadmin->add_svc.cpp'. + * Added logic to RDAdmin->AddGroup to enable all hosts by + default in 'rdadmin->add_svc.cpp'. + * Added logic to RDAdmin->AddGroup to enable all services by + default in 'rdadmin->add_station.cpp'. +2005-06-15 Fred Gleason + * Rewrote RDAdmin's List Users dialog for consistent UI operation. + * Rewrote RDAdmin's List Services dialog for consistent UI operation. + * Rewrote RDAdmin's List Hosts dialog for consistent UI operation. + * Rewrote RDAdmin's List Reports dialog for consistent UI operation. + * Rewrote RDAdmin's List Inputs/Output dialog for consistent UI + operation. +2005-06-15 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' where the Segue, Talk, + Hook and FadeUp/FadeDown markers were not being reset when making + a new recording. +2005-06-15 Dan Mills + * Fixed problem dropping root when euid = 0, but uid !=0. + I think this was the problem at KDAR with rdcatchd creating carts + with root ownership. Mantis bug # 30. +2005-06-15 Fred Gleason + * Fixed a bug in 'rdlogmanager/list_events.cpp' that was causing + the event list to shift focus after editing an event. + * Fixed a bug in 'rdlogmanager/list_clocks.cpp' that was causing + the event list to shift focus after editing a clock. +2005-06-15 Fred Gleason + * Added a 'RenameItem' dialog in 'rdlogmanger/rename_item.cpp'. + * Added a 'Rename' button to the List Events dialog in + RDLogManager. + * Added a 'Rename' button to the List Clocks dialog in + RDLogManager. +2005-06-16 Fred Gleason + * Added the ability in RDLogManager's Grid Editor to right-click + on a clock button to edit the clock. + * Added a 'ClockListview' class in + 'rdlogmanager/clock_listview.cpp'. + * Added the ability in RDLogManager's Clock Editor to right-click + on an event entry to edit the event. +2005-06-16 Fred Gleason + * Fixed a bug in 'rdlibrary/record_cut.cpp' that was causing the + daypart controls to remain active for evergreen cuts. +2005-06-20 Fred Gleason + * Added an importer for the Crown 'Wings' system in + 'importers/wings_filter.cpp'. +2005-06-21 Fred Gleason + * Fixed bug in 'utils/rmlsend.cpp', 'rdlogedit/rdlogedit.cpp' and + 'rdlogmanager/rdlogmanager.cpp' that was causing the build to + break under Windows. +2005-06-23 Fred Gleason + * Disabled installation of sas_filter(1) and wings_filter(1). + * Incremented the package version to 0.9.35. +2005-06-24 Fred Gleason + * Added a 'RDListView::SortType' enum in + 'lib/rdlistview.h'. + * Added 'RDListView::columnSortType()' and + 'RDListView::setColumnSortType()' methods in 'lib/rdlistview.cpp'. + * Fixed a bug in 'rdlibrary/rdlirary.cpp' that was causing the + 'Length' column in the cart list to be sorted alphabetically + rather than by length value. + * Fixed a bug in 'rdlibrary/audio_cart.cpp' that was causing the + 'Length' column in the cart list to be sorted alphabetically + rather than by length value. +2005-06-24 Fred Gleason + * Fixed a bug in 'lib/rdcart_search_text.cpp' that had broken the + Filter in RDLibrary when set to show all carts. +2005-06-24 Fred Gleason + * Added an 'Origin' column to the event list in RDCatch. +2005-06-24 Fred Gleason + * Fixed a bug in 'rdlogmanager/list_events.cpp' that was failing + to refresh the events list after using SaveAs to add new events. + * Fixed a bug in 'rdlogmanager/list_clocks.cpp' that was failing + to refresh the clocks list after using SaveAs to add new clocks. + * Added code to 'rdlogmanager/add_clock.cpp' to default a new + clock name to the name of current clock when doing SaveAs. + * Added code to 'rdlogmanager/add_event.cpp' to default a new + event name to the name of current event when doing SaveAs. +2005-06-24 Fred Gleason + * Added a 'NONE' filter option to the Log Events dialog in + RDLogManager to filter for events that have no service + associations. + * Added a 'NONE' filter option to the Log Clocks dialog in + RDLogManager to filter for clocks that have no service + associations. +2005-06-24 Fred Gleason + * Incremented the package version to 0.9.36. +2005-06-26 Fred Gleason + * Fixed a bug in 'rdairplay/edit_event.cpp' that was prevending + editing of non-audio cart events. +2005-06-26 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that was causing auto + event inserts to go into an infinite loop if inserted near + midnight at the end of a log. + * Added a sanity check to the RDAdmin Add Group dialog in + 'rdadmin/add_group.cpp' to prevent creation of a group with no + name. + * Added a sanity check to the RDAdmin Add User dialog in + 'rdadmin/add_user.cpp' to prevent creation of a user with no + name. + * Fixed a bug in 'rdadmin/add_user.cpp' that was allowing creation + a username containing spaces. + * Added a sanity check to the RDAdmin Add Service dialog in + 'rdadmin/add_svc.cpp' to prevent creation of a service with no + name. + * Added a sanity check to the RDAdmin Add Host dialog in + 'rdadmin/add_station.cpp' to prevent creation of a host with no + name. + * Added logic to RDLogManager's Click List Dialog to place default + focus on the last placed clock on a grid. + * Incremented the version number 0.9.37. +2005-06-29 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing + incorrect outcue data to be displayed for rotating events. + * Fixed a bug in 'rdlibrary/import_audio.cpp' that was causing + imported audio to have an incorrect length assigned when imported + with autotrim enabled. +2005-06-29 Fred Gleason + * Fixed a bug in 'rdairplay/pie_counter.cpp' that was causing + extraneous blue lines to appear in the Pie Widget display. +2005-06-29 Dan Mills + * Backed out change made on the 15th to dropping of root. + Mantis #30, I would swear that I had committed this allready! + Sorry KDAR, this one goes a little deeper then I thought. + Mantis issue reopened. +2005-06-30 Fred Gleason + * Added 'SERVICES.TFC_ANNC_TYPE_OFFSET', + 'SERVICES.TFC_ANNC_TYPE_LENGTH', 'SEVICES.MUS_ANNC_TYPE_OFFSET' + and 'SERVICES.MUS_ANNC_TYPE_LENGTH' fields to the database. + * Added an 'EXT_ANNC_TYPE' field to the log table format. + * Added an 'EVENT_SOURCE' field to the reconciliation table + format. + * Added an 'EXT_ANNC_TYPE' field to the reconciliation table + format. + * Added 'REPORTS.FORCE_TFC' and 'REPORTS.FORCE_MUS' fields to the + database. + * Changed the default value for the 'GROUPS.REPORT_TFC' and + 'GROUPS.REPORT_MUS' fields to 'Y'. + * Incremented the database version to 80. + * Added 'RDLogLine::extAnncType()' and + 'RDLogLine::setExtAnncType()' methods in 'lib/rdlog_line.cpp'. + * Added an 'ImportField::ExtAnncType' to the RDSvc::ImportField + enum in 'lib/rdsvc.h'. + * Added parser parameter controls for the 'Announcement Type' + attribute in 'rdadmin/edit_svc.cpp' + * Added an 'Announcement Type' column in + 'rdadmin/test_import.cpp'. + * Added a 'RDLogLine::clearExternalData()' method in + 'lib/rdlog_line.cpp'. + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was causing + external scheduler data to be propagated into copied log events. + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was causing a + segfault when trying to cut or delete items containing the + '-- End of log --' entry. + * Added checkbox controls to 'rdadmin/edit_report.cpp' to force + export of events originating from the traffic and/or music log to + a report. + * Modified 'rdlogmanager/export_deltaflex.cpp' to produce report + output that conforms to 'DeltaFlex Electronic Log Reconciliation + Standard version 2.01'. +2005-07-01 Fred Gleason + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.38. +2005-07-05 Fred Gleason + * Fixed a bug in 'rdlogmanager/edit_event.cpp' that was causing + the hard time transition type to always show up as 'Stop'. +2005-07-06 Fred Gleason + * Added a 'DiskRipper' dialog in 'rdlibrary/disk_ripper.cpp'. + * Added a 'Clear' button to the Cut Selector dialog in + 'lib/rdcut_dialog.cpp'. +2005-07-07 Fred Gleason + * Added an 'RDCmdCache' class in 'lib/rdcmd_cache.cpp'. + * Rewrote the 'RDCae' class in 'lib/rdcae.cpp' to eliminate a race + condition that was causing trainwreck when processing multiple + 'Load Play' commands. +2005-07-07 Fred Gleason + * Fixed a bug in 'rdadmin/rdadmin.cpp' that was causing the + database to fail to be upgraded to the proper database version + after a database restore. +2005-07-07 Fred Gleason + * Added code to 'rdlibrary/disk_ripper.cpp' to prevent the + assignment of the same cut to multiple CD tracks. +2005-07-07 Fred Gleason + * Incremented the package version to 0.9.39. +2005-07-08 Fred Gleason + * Added an init script for Gentoo Linux in 'rivendell-gentoo'. +2005-07-08 Fred Gleason + * Added logic to 'cae/cae.cpp' to properly assign thread + scheduling policies and priorities. + * Removed code from 'cae/cae.cpp' for dropping root permissions. + * Added code to 'cae/cae_hpi.cpp', 'cae/cae_alsa.cpp' and + 'cae/cae_jack.cpp' to assign proper file ownership when creating a + new file. +2005-07-08 Fred Gleason + * Added a call to 'mlockall()' to 'cae/cae.cpp'. +2005-07-10 Fred Gleason + * Added logic to 'rdadmin/edit_user.cpp' to disallow the assignment + of Production, Traffic or OnAir rights to users with + Administrative rights. + * Modified RDLogin to user a dropdown list of usernames. +2005-07-11 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that was failing to update + the preimport and postimport event lists in the database schema + properly. + * Incremented the database version to 81. + * Incremented the package version to 0.9.40. +2005-07-13 Fred Gleason + * Fixed a bug in 'rdlibrary/disk_ripper.cpp' that was causing only + the last ripped track to have it's CDDB data applied. +2005-07-13 Fred Gleason + * Fixed a bug in 'lib/rdcae.cpp' that was causing CAE to lock up + when RDCae::positionPlay()' was called with a play position past + the end of a load file. +2005-07-13 Fred Gleason + * Incremented the package version to 0.9.41. +2005-07-14 Fred Gleason + * Added a 'Set Display' ['SD'] RML in 'docs/rml.sxw'. +2005-07-14 Fred Gleason + * Added 'RDMatrix::LogtekVguest' to the RDMatrix::Type enum in + 'lib/rdmatrix.h'. + * Added 'INPUTS.ENGINE_NUM', 'INPUTS.DEVICE_NUM', + 'OUTPUTS.ENGINE_NUM' and 'OUTPUTS.DEVICE_NUM' fields to the + database. + * Added support for Logitek Engine ID and Device ID in + 'rdadmin/list_endpoints.cpp' and 'rdadmin/edit_endpoint.cpp'. + * Added 'MATRICES.USERNAME' and 'MATRICES.PASSWORD' field to the + database. + * Incremented the database version to 82. + * Added 'RDMatrix::username()', 'RDMatrix::SetUsername()', + 'RDMatrix::password()' and 'RDMatrix::setPassword()' methods in + 'lib/rdmatrix.cpp'. + * Added 'Username' and 'Password' controls to + 'rdadmin/edit_matrix.cpp'. + * Added a Logitek vGuest driver in 'ripcd/vguest.cpp'. + * Added a 'VGUEST_RESOURCES' table to the database. + * Added a RDMatrix::VguestType enum in 'lib/rdmatrix.h'. + * Added a 'ListVguestResources' dialog in + 'rdadmin/list_vguest_resources.cpp'. + * Added an 'EditVguestResource' dialog in + 'rdadmin/edit_vguest_resource.cpp'. + * Added 'MATRICES.FADERS' and 'MATRICES.DISPLAYS' fields to the + database. + * Added 'Faders' and 'Displays' controls to + 'rdadmin/edit_matrix.cpp'. + * Added a 'Set Display' ['SD'] RML to RDMacro in 'lib/rdmacro.h'. + * Incremented the package version to 0.9.42. +2005-07-14 Fred Gleason + * Commented out RD_USE_MYSQL_EXTENSIONS in 'lib/rd.h'. + * Incremented the package version to 0.9.43. +2005-07-15 Fred Gleason + * Fixed a bug in 'ripcd/ripcd.cpp' that was causing infinite + recursion of certain RML commands. + * Incremented the package version to 0.9.44. +2005-07-15 Fred Gleason + * Fixed a bug in 'scripts/rd_import_file' that was causing imports + of .ATX' files to fail. +2005-07-18 Fred Gleason + * Fixed bugs in 'cae/cae_alsa.cpp', 'cae/cae_hpi.cpp', + 'cae/cae_jack.cpp' and 'cae/cae.cpp' that were causing caed(8) to + trainwreck when processing a 'PP' command with a position value + greater than the length of the open file. + * Added usage notes for the Logitek vGuest driver in + 'docs/SWITCHERS.txt'. + * Updated the 'NEWS' file. +2005-07-18 Fred Gleason + * Incremented the package version to 0.9.45. +2005-07-18 Fred Gleason + * Fixed a bug in 'cae/cae.cpp' that was causing the build to break + when compiled without ALSA support. +2005-07-19 Dan Mills + * Modified the pie timer so that it has a 'last ten seconds' ring. +2005-07-20 Fred Gleason + * Fixed a syntax error in 'rdairplay/pie_counter.cpp' that was + causing the build to break. +2005-07-19 Dan Mills + * Modified the pie timer last seconds ring to use the PIE_COUNTS_LAST + value set in rdadmin rather then a hard coded 10 seconds, this also + appears to have fixed the problem with carts set to transition. +2005-07-20 Fred Gleason + * Fixed a bug in 'lib/rdcart.cpp' that was causing Random cut + scheduling to fail. +2005-07-21 Fred Gleason + * Added an 'install-debian' target to 'Makefile.am'. + * Added a 'debian/' directory for Debian-specific package build + data. + * Added 'changelog', 'control', 'copyright', + 'rivendell.conffiles', rivendell.docs', rivendell.examples', + 'rivendell.init', 'rivendell.postinst', 'rivendell.postrm' and + 'rules' files in 'debian/'. + * Updated the 'Authors' file. +2005-07-21 Fred Gleason + * Added 'Type::Download' and 'Type::Upload' values to + 'RDRecording::Type' in 'lib/rdrecording.h'. + * Added 'ExitCode::Downloading', 'ExitCode::Uploading' and + 'ExitCode::ServerError' values to 'RDRecording::ExitCode' in + 'lib/rdrecording.h'. + * Added a download icon in 'icons/download.xpm'. + * Added an upload icon in 'icons/upload.xpm'. + * Added an Edit Download dialog in 'rdcatch/edit_download.cpp'. + * Added 'RECORDINGS.URL', 'RECORDINGS.URL_USERNAME' and + 'RECORDINGS.URL_PASSWORD' fields to the database. + * Incremented the database version to 83. + * Added 'RDRecording::url()', 'RDRecording::setUrl()', + 'RDRecording:urlUsername()', 'RDRecording::setUrlUsername()', + 'RDRecording::urlPassword()' and 'RDRecording::setUrlPassword()' + methods in 'lib/rdrecording.cpp'. +2005-07-22 Fred Gleason + * Added 'file:' protocol download support to rdcatchd(8). +2005-07-22 Dan Mills + * Modified lib/rdgroup_list.cpp to match irrespective of case. + This fixes a problem where rdimport would import cars where the + group was a lower case vewrsion of the group in the database. + rdlogedit would then refuse to allow these carts to be put into a log. +2005-07-23 Fred Gleason + * Added a 'RDDateTimeDecode()' function in 'lib/rddatedecode.cpp'. + * Implemented date/time wildcards in the URL field for RDCatch + download events. +2005-07-24 Fred Gleason + * Implemented download support for http:, https: ftp: and smb: + protocols in RDCatch. + * Added dependencies for 'wget', 'samba-client' and 'lukemftp' to + 'rivendell.spec.in'. + * Updated the 'INSTALL' file. +2005-07-24 Fred Gleason + * Fixed a bug in 'lib/rdlog_line.cpp' that was causing execution + of macro carts to segfault RDAirPlay. +2005-07-25 Fred Gleason + * Added 'HAVE_OGGENC', 'HAVE_OGG123', 'HAVE_FLAC', 'HAVE_LAME', + 'HAVE_MPG321', 'CARD_DRIVER', 'CARD_NAME', 'CARD_INPUTS', + 'CARD_OUTPUTS', 'HPI_VERSION', 'JACK_VERSION' and + 'ALSA_VERSION' fields to the 'STATIONS' table in the database. + * Incremented the database version to 84. + * Added 'RDStation::scanned()', 'RDStation::setScanned()', + 'RDStation::haveCapability()', 'RDStation::setHaveCapability()', + 'RDStation::cardName()', 'RDStation::setCardName()', + 'RDStation::cardInputs()', 'RDStation::setCardInputs()', + 'RDStation::cardOutputs()', 'RDStation::setCardOutputs()', + 'RDStation::cardDriver()', 'RDStation::setCardDriver()', + 'RDStation::driverVersion()' and 'RDStation::setDriverVersion()' + methods in 'lib/rdstaiton.cpp'. + * Rewrote caed(8) to use the RDConfig configuration class. + * Updated 'docs/ALSA.txt' with info on creating ctl devices. +2005-07-25 Fred Gleason + * Fixed a bug in 'cae/cae.cpp' that was causing a segfault when + started with no HPI devices present. + * Removed the 'View Adapters' button from the System Info dialog + in RDAdmin. + * Added an 'Audio Resources' button to the Edit Hosts dialog in + RDAdmin. +2005-07-27 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing the + 'RDPlayDeck::position()' signal to be issued with invalid position + data. +2005-07-27 Fred Gleason + * Incremented the package version to 0.9.45a. +2005-07-27 Fred Gleason + * Added a check for duplicate stream assignments in int 'LP' + command in 'cae/cae.cpp' + * Incremented the package version to 0.9.45b. +2005-07-27 Fred Gleason + * Fixed an initialization bug in 'lib/rdlog_line.cpp' that was + causing RDAirPlay to semi-randomly segfault when executing macro + carts. + * Fixed a fencepost error in 'rdairplay/log_play.cpp' that was + causing RDAirPlay to lockup when executing a marker as the first + event in a log. +2005-07-27 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + segfault in processing certain Now&Next events. +2005-07-27 Fred Gleason + * Added the ability to base a new host setup on a previous + existing host configuration. +2005-07-27 Fred Gleason + * Added the ability to base a new service setup on a previous + existing service configuration. +2005-07-27 Fred Gleason + * Incremented the packages version to 0.9.46. +2005-07-28 Dan Mills + * Modified the pie timer to use black on white for the + last 10 seconds and to always display the outer ring. +2005-07-29 Fred Gleason + * Fixed a bug in 'lib/rdcae.cpp' that was causing MPEG L2 + recording to fail. +2005-07-29 Fred Gleason + * Applied the fix by Dan Mills to a + bug in 'ripcd/ripcd.cpp' that was causing a race when starting the + RML polling timer. +2005-07-29 Fred Gleason + * Fixed a bug in 'rdadmin/view_adapters.cpp' where + invalid data was displayed for a host with non-initialized data + resource data in RDAdmin->ManageHosts->ViewAudioResources . + * Added 'RDCardSelector::maxCards()', + 'RDCardSelector::setMaxCards()', + 'RDCardSelector::maxPorts()' and 'RDCardSelector::setMaxPorts()' + methods in 'lib/rdcardselector.cpp'. + * Added an 'RDStation::cards()' method in 'lib/rdstation.cpp'. + * Added code to 'rdadmin/edit_rdlibrary.cpp', + 'rdadmin/edit_decks.cpp' and 'rdadmin/edit_rdairplay.cpp' to + enforce sane values for audio channel assignments. +2005-07-29 Fred Gleason ManageHosts->ViewAudioResources + * Added 'RDCardSelector::maxCards()' + 'RDCardSelector::setMaxCards()' + 'RDCardSelector::maxPorts()' and 'RDCardSelector::setMaxPorts() + methods in 'lib/rdcardselector.cpp' + * Added an 'RDStation::cards()' method in 'lib/rdstation.cpp' + * Added code to 'rdadmin/edit_rdlibrary.cpp' + 'rdadmin/edit_decks.cpp' and 'rdadmin/edit_rdairplay.cpp' t + enforce sane values for audio channel assignments +2005-07-29 Dan Mills + * Added a dependency for 'tablib'. +2005-07-29 Fred Gleason + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Updated the 'README' file. + * Updated the package version to 0.9.47. +2005-07-29 Fred Gleason + * Fixed a typo in 'rivendell.spec.in'. +2005-08-01 Fred Gleason + * Added 'RDConfig::mysqlPassword()' and 'RDConfig::mysqlDriver()' + methods in 'lib/rdconfig.cpp'. + * Modified caed(8) in 'cae/caed.cpp' to use the 'Password=' and + 'Driver=' directives from the [mySQL] section of rd.conf(5). + * Modified sas_filter(1) in 'importers/sas_filter.cpp' to use the + RDConfig class. + * Modified wing_filter(1) in 'imports/wings_filter.cpp' to use + the 'Password=' and 'Driver=' directives from the [mySQL] section + of rd.conf(5). + * Modified RDAdmin in 'rdadmin/rdadmin.cpp' and + 'rdadmin/opendb.cpp' to use the 'Password=' and + 'Driver=' directives from the [mySQL] section of rd.conf(5). + * Modified RDAirPlay in 'rdairplay/rdairplay.cpp' to use the + 'Password=' and 'Driver=' directives from the [mySQL] section of + rd.conf(5). + * Modified RDCatch in 'rdcatch/rdcatch.cpp' to use the + 'Password=' and 'Driver=' directives from the [mySQL] section of + rd.conf(5). + * Modified RDCatchd in 'rdcatchd/rdcatchd.cpp' to use the + 'Password=' and 'Driver=' directives from the [mySQL] section of + rd.conf(5). + * Modified RDLibrary in 'rdlibrary/rdlibrary.cpp' to use the + 'Password=' and 'Driver=' directives from the [mySQL] section of + rd.conf(5). + * Modified RDLogEdit in 'rdlogedit/rdlogedit.cpp' to use the + 'Password=' and 'Driver=' directives from the [mySQL] section of + rd.conf(5). + * Modified RDLogin in 'rdlogin/rdlogin.cpp' to use the + 'Password=' and 'Driver=' directives from the [mySQL] section of + rd.conf(5). + * Modified RDLogManager in 'rdlogmanger/rdlogmanager.cpp' to use the + 'Password=' and 'Driver=' directives from the [mySQL] section of + rd.conf(5). + * Modified ripcd(8) in 'ripcd/ripcd.cpp' to use the RDConfig class. + * Modified sas_switch_torture(1) in 'tests/sas_switch_torture.cpp' + to use the RDConfig class. + * Modified sas_torture(1) in 'tests/sas_torture.cpp' + to use the RDConfig class. + * Modified RDGpiMon in 'utils/rdgpimon.cpp' to use the + 'Password=' and 'Driver=' directives from the [mySQL] section of + rd.conf(5). + * Modified RDImport in 'utils/rdimport.cpp' to use the + 'Password=' and 'Driver=' directives from the [mySQL] section of + rd.conf(5). +2005-08-01 Fred Gleason + * Fixed a bug in 'rdlibrary/edit_audio.cpp' that was causing a + label to render with the incorrect font size. + * Added 'RECORDINGS.NORMALIZE_LEVEL' and 'RECORDINGS.QUALITY' + fields to the database. + * Incremented the database version to 85. + * Added an 'EditUpload' dialog in 'rdcatch/edit_upload.cpp'. + * Added an 'RDExportSettingsDialog' dialog in + 'lib/rdexport_settings.cpp'. + * Added 'RDRecording::normalizationLevel()' and + 'RDRecording::setNormalizationLevel()' methods in + 'lib/rdrecording.cpp'. + * Removed the 'RDEditSettings' class in 'lib/rdedit_settings.cpp' + and 'lib/rdedit_settings.h'. +2005-08-01 Fred Gleason + * Fixed a bug in 'rdadmin/list_endpoints.cpp' that was causing + data saves to intermittently fail. +2005-08-02 Fred Gleason + * Added various source files that were missing in the translation + setup. +2005-08-02 Fred Gleason + * Fixd various bugs in 'lib/rdsettings.cpp' and + 'lib/rdexport_settings_dialog.cpp'. +2005-08-02 Fred Gleason + * Added code to 'rdcatch/edit_upload.cpp' to warn when selecting a + host without support for the configured encoding format. + * Added FLAC detection in 'rdadmin/view_adapters.cpp'. +2005-08-02 Fred Gleason + * Disabled the 'Quality' control for FLAC encoding in + 'lib/rdexport_settings_dialog.cpp' + * Added code to set the proper range for the 'Quality' control for + MPEG and OggVorbis encoding in 'lib/rdexport_settings_dialog.cpp'. + * Removed VBR support for MPEG L2 from + 'lib/rdexport_settings_dialog.cpp'. + * Added code to 'rdcatch/rdcatch.cpp' to properly display the + quality value for VBR encodings. +2005-08-02 Fred Gleason + * Created an export script in 'scripts/rd_export_script'. + * Added 'CatchEvent::quality()', 'CatchEvent::setQuality()', + 'CatchEvent::normalizeLevel()' and + 'CatchEvent::setNormalizeLevel()' methods in + 'rdcatchd/catch_event.cpp'. + * Added a 'Normalization' control to the Edit Upload dialog in + 'rdcatch/edit_upload.cpp'. + * Implemented Upload Events in RDCatch for the file: protocol. +2005-08-02 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing the + 'Quality' parameter to be ignored for Upload events. +2005-08-03 Fred Gleason + * Fixed a bug in 'rdcatch/edit_upload.cpp' that was allowing URLs + utilizing the http and https protocols to be entered. + * Implemented Upload Events in RDCatch for the smb: and ftp: + protocols. +2005-08-03 Fred Gleason + * Added 'RDRecording::Interrupted', 'RDRecording::RecordActive', + 'RDRecording::Waiting, and 'RDRecording::PlayActive' values to the + 'RDRecording::ExitCode' enum in 'lib/rdrecording.h'. + * Added code to 'rdcatchd/rdcatchd.cpp' to flag interrupted events + in the database. + * Added code to 'rdcatchd/rdcatchd.cpp' to properly notify new + instances of RDCatch about currently active xload events. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing causing + attempts to abort playout events to fail. + * Added exit code support for Record and Playout events in + RDCatch. +2005-08-03 Fred Gleason + * Added a 'Save As New' button in RDCatch's Edit Switch Event + dialog. +2005-08-03 Fred Gleason + * Added a 'Save As New' button in RDCatch's Edit Macro Event + dialog. + * Added a 'Save As New' button in RDCatch's Edit Download Event + dialog. + * Added a 'Save As New' button in RDCatch's Edit Upload Event + dialog. +2005-08-03 Fred Gleason + * Added a 'Save As New' button in RDCatch's Edit Playout Event + dialog. + * Added a 'Save As New' button in RDCatch's Edit Record Event + dialog. +2005-08-03 Fred Gleason + * Added a command to 'install-init.sh' to create a + '/etc/sysconfig/' if needed, fixes a 'make install' bug on + Debian (Mantis bug #71). +2005-08-03 Fred Gleason + * Fixed a type in 'docs/JACK.txt' (Mantis bug #73). +2005-08-03 Fred Gleason + * Fixed a syntax error in the 'rivendell-suse' init script (Mantis + bug #72). +2005-08-03 Fred Gleason + * Added an 'RDAddLog::closeEvent()' class in 'lib/rdadd_log.cpp' + (Mantis bug #76). + * Added an 'RDCartDialog::closeEvent()' class in + 'lib/rdcard_dialog_log.cpp' (Mantis bug #76). + * Added an 'RDCutDialog::closeEvent()' class in + 'lib/rdcut_dialog.cpp' (Mantis bug #76). + * Added an 'EditLogLine::closeEvent()' class in + 'rdlogedit/edit_logline.cpp' (Mantis bug #76). + * Added an 'EditMarker::closeEvent()' class in + 'rdlogedit/edit_marker.cpp' (Mantis bug #76). + * Added an 'EditChain::closeEvent()' class in + 'rdlogedit/edit_chain.cpp' (Mantis bug #76). + * Added an 'EditLog::closeEvent()' class in + 'rdlogedit/edit_log.cpp' (Mantis bug #76). +2005-08-03 Fred Gleason + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was causing + the wrong event to be selected for editing (Mantis bug #75). +2005-08-05 Fred Gleason + * Fixed a bug in 'rdlibrary/record_cut.cpp' that was causing MPEG + recording to sporadically fail if recording over a cut previously + recorded in PCM16. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was writing an + invalid value into 'RECORDINGS.CODING_FORMAT' when making an MPEG + L2 recording. + * Removed the GPI parameters from the 'RDCae::record()' method in + 'lib/rdcae.cpp'. + * Fixed a bug in 'utils/rdimport.cpp' that was causing imports to + fail when RDLibrary was configured to use MPEG audio encoding. + * Cleaned up error reporting for RDImport in 'utils/rdimport.cpp'. +2005-08-05 Fred Gleason + * Added an 'RDEscapeString()' function in + 'lib/rdescape_string.cpp'. + * Fixed a bug in 'rdlibrary/import_audio.cpp' that was causing + import of files with non-standard characters to fail (Mantis bug + #61). + * Fixed a bug in 'utils/rdimport.cpp' that was causing + import of files with non-standard characters to fail (Mantis bug + #61). +2005-08-05 Fred Gleason + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was causing the + line renumbering on a log to fail when a line was deleted (Mantis + bug #74. +2005-08-05 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that was causing the + 'generateLog()' method to enter an infinite loop if one or more + events in the autotrim list has a zero cart length. +2005-08-06 Fred Gleason + * Added an 'RDMatrix::BtSs164' value to the 'RDMatrix::Type' enum + in 'lib/rdmatrix.h'. + * Added 'BroadcastTools SS16.4' to the list of supported switcher + in RDAdmin. + * Added a switcher driver for the Broadcast Tools SS16.4 switcher + in 'ripcd/btss16.cpp'. + * Added installation notes for the Broadcast Tools SS16.4 switcher + in 'docs/SWITCHER.txt'. +2005-08-06 Fred Gleason + * Fixed a bug in 'lib/rdlog_line.cpp' that was causing Now&Next + data to fail for manually added events. +2005-08-06 Fred Gleason + * Fixed a bug in 'rdairplay/local_macros.cpp' that was casuing + the 'PX' RML to fail if the log had no next event (Mantis bug + #54). +2005-08-06 Fred Gleason + * Fixed a bug in 'ripcd/btss164.cpp' that was causing the 'ST' + macro to fail for outputs greater than eight. +2005-08-06 Fred Gleason + * Fixed a bug in 'ripcd/btss164.cpp' that was causing the 'ST' + macro to fail for outputs greater than eight. + * Removed an unused signal mapping in 'rdcatchd/rdcatchd.cpp'. +2005-08-07 Fred Gleason + * Added an 'RDGroup::nextFreeCart()' method in 'lib/rdgroup.cpp'. + * Rewrote 'rdlibrary/add_cart.cpp' to use the new + 'RDGroup::nextFreeCart()' method. + * Completed the Air Force Wings importer script in + 'importers/wings_filter.cpp'. + * Fixed a bug in 'lib/rdcart_search_text.cpp' that was return + incorrect results from a group cart search. + * Fixed a bug in 'rdadmin/rename_group.cpp' that was corrupting + permission data when merging two groups. +2005-08-07 Fred Gleason + * Incremented the package version to 0.9.48. + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. +2005-08-08 Fred Gleason + * Fixed a bug in 'lib/rdcart_search_text.cpp' that was causing the + cart list in the Cart selection dialogs to be empty if 'ALL' was + selected in the Group selector. +2005-08-08 Fred Gleason + * Fixed a bug in 'rdcatch/edit_recording.cpp' that was preventing + similar record events with different GPI start parameters from + being saved. +2005-08-08 Fred Gleason + * Added an 'RDRecording::DeviceBusy' value to the + 'RDRecording::ExitCode' enum in 'lib/rdrecording.h'. + * Fixed a bug in 'rdcatch/edit_recording.cpp' that was allowing + events to be created zero-length GPI start and stop windows. + * Rewrote rdcatchd(8) to properly handle multiple events scheduled + at the same time and with the same record deck, but with different + GPI and destination cut parameters. +2005-08-08 Fred Gleason + * Implemented GPI start time offset in rdcatchd(8). +2005-08-08 Fred Gleason + * Incremented the package version to 0.9.49. + * Updated the 'NEWS' file. +2005-08-13 Fred Gleason + * Moved 'conf/crc-unity4k.sh' to 'scripts/crc-unity4k.sh'. + * Created an RPM subpackage 'importers', containing the + sas_filter(1), wings_filter(1) and crc-unity4k.sh(1) scripts. +2005-08-16 Fred Gleason + * Added debugging instrumentation code to 'ripcd/ripcd.cpp'. + * Incremented the package version to 0.9.49a. +2005-08-17 Fred Gleason + * Changed the behavior of RDLogin so that the app exits after + successfully changing the current user. +2005-08-17 Fred Gleason + * Changed the default value of the 'RECORDINGS.END_TYPE' field in + the database to '0'. + * Incremented the database version to 86. + * Switched the positions of the 'Length:' and 'Hard Time:' + controls in RDCatch's Edit Recording dialog in + 'rdcatch/edit_recording.cpp'. +2005-08-17 Fred Gleason + * Set the 'Close' button in RDLogManager to be the default. + * Fixed a bug in 'rdlogmanager/edit_event.cpp' where an Event's + service permissions were not being saved as part of a 'Save As' + operation. + * Fixed a bug in 'rdlogmanager/list_event.cpp' where an Event's + service permissions were not being preserved across a Rename. + * Fixed a bug in 'rdlogmanager/edit_clock.cpp' where a Clock's + service permissions were not being saved as part of a 'Save As' + operation. + * Fixed a bug in 'rdlogmanager/list_clock.cpp' where a Clock's + service permissions were not being preserved across a Rename. +2005-08-18 Fred Gleason + * Added code to the Logitek vGuest driver in 'ripcd/vguest.cpp' + to wait a random period of time before attempting to restore + a broken vGuest connection. +2005-08-18 Fred Gleason + * Incremented the package version to 0.9.50. +2005-08-25 Fred Gleason + * Fixed a bug in 'rdlibrary/disk_ripper.cpp' that was causing + tracks ripped without CDDB data to be improperly entered into the + database. +2005-08-29 Fred Gleason + * Added an RDCatch record list copy filter in + 'importers/rdcatch_copy.cpp'. +2005-08-31 Fred Gleason + * Fixed a bug in 'importers/wings_filter.cpp' that failed to set + properly the 'CUTS.START_POINT' and 'CUTS.END_POINT' fields for + each imported cut (Mantis bug #79). + * Fixed a bug in 'utils/rdimport.cpp' that failed to set + properly the 'CUTS.START_POINT' and 'CUTS.END_POINT' fields for + each imported cut (Mantis bug #79). +2005-08-31 Fred Gleason + * Changed the color for the LENGTH field in the cart list in + RDLibrary for timescaled carts from green to blue. +2005-08-31 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.51. +2005-09-01 Fred Gleason + * Added a specification for Rivendell Switcher Language (RSL) in + 'docs/rsl.sxw'. +2005-09-06 Fred Gleason + * Added logging code to 'rdcatchd/rdcatchd.cpp'. +2005-09-06 Fred Gleason + * Fixed a bug in 'rdlogmanager/generate_report.cpp' that was + causing empty reports to be generated if the 'All' box was + selected in RDAdmin->Reports->ExportEventTypes. + * Incremented the package version to 0.9.51a. +2005-09-07 Fred Gleason + * Added a 'disable-gpio' switch to 'configure.in'. +2005-09-07 Fred Gleason + * Fixed a bug in 'scripts/rd_import_file' that causing imports + from single-channel MPEG files to be corrupt. +2005-09-09 Fred Gleason + * Fixed a bug in rdairplay/log_play.cpp' that was causing multiple + entries to be written to the reconciliation database when + repeatedly pausing events. +2005-09-19 Fred Gleason + * Added a 'State' column to the record list in RDCatch. + * Added logic to 'rdcatch/rdcatch.cpp' to prevent editing of an + active event. +2005-09-20 Fred Gleason + * Added an 'EXT_CART_NAME' field to the log tables. + * Added an 'EXT_CART_NAME' field to the reconciliation tables. + * Incremented the database version to 87. + * Fixed a bug in 'rdlogmanager/export_Deltaflex.cpp' that was + causing invalid cart name data to be included in DeltaFlex ELR + reports. + * Fixed a bug in 'rdlogmanager/list_events.cpp' that was causing + segfaults after editing an event. + * Fixed a bug in 'rdlogmanager/edit_clock.cpp' that was allow + clocks to be created with duplicate or non-existent clock codes. + * Fixed a bug in 'rdlogmanager/list_clocks.cpp' that was causing + segfaults after editing a clock. +2005-09-20 Fred Gleason + * Fixed a bug in 'rdlogmanager/generate_log.cpp' that was causing + events near midnight to fail to be imported when used with non-zero + slop times. +2005-09-20 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that was causing import events to + be used more than once in the same import. + * Added code to flag unused import events in RDLogManager's + exception report. +2005-09-21 Fred Gleason + * Added 'RECORDINGS.ALLOW_MULT_RECS' and + 'RECORDINGS.MAX_GPI_REC_LENGTH' fields to the database. + * Incremented the database version to 88. + * Added 'RDRecording::allowMultipleRecordings()', + 'RDRecording::setAllowMultipleRecordings()', + 'RDRecording::maxGpiRecordingLength()' and + 'RDRecording::setMaxGpiRecordingLength()' methods in + 'lib/rdrecording.cpp'. + * Added 'Allow Multiple Recordings' and 'Max Record Length' + control to the Edit Recording dialog in RDCatch. + * Added 'CatchEvent::allowMultipleRecordings()', + 'CatchEvent::setAllowMultipleRecordings()', + 'CatchEvent::maxGpiRecordLength()' and + 'CatchEvent::setMaxGpiRecordLength()' methods in + 'rdcatchd/catch_event.cpp'. + * Implemented the 'Max GPI Record Time' parameter in rdcatchd(8). + * Implemented multiple recordings per event in rdcatchd(8). +2005-09-21 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was displaying only a + single entry when WAITing on multiple events. +2005-09-21 Fred Gleason + * Reenabled import table cleanups in 'lib/rdsvc.cpp'. +2005-09-21 Fred Gleason + * Added a dialog box to report completion of a report in + 'rdlogmanager/generate_report.cpp'. + * Incremented the package version to 0.9.51b. +2005-09-21 Fred Gleason + * Incremented the package version to 0.9.51c. +2005-09-22 Fred Gleason + * Added an 'RDCatchConnect::eventUpdated()' signal in + 'lib/rdcatch_connect.h'. + * Added an 'eventUpdatedData()' slot in 'rdcatch/rdcatch.cpp'. +2005-09-22 Fred Gleason + * Fixed a bug in 'rdairplay/edit_event.cpp' that was causing a + segfault when attempting to modify an event containing an empty + cart. +2005-09-22 Fred Gleason + * Added code to 'rdlibrary/audio_cart.cpp' to show empty cuts with + a red background. + * Added code to 'rdlibrary/audio_cart.cpp' to zero-length audio + carts with a red background. + * Changed the logic in 'RDCart::averageLength()' and + 'RDCart::updateLength()' methods to include only non-zero length + cuts in the calculation of average audio length. + * Fixed a bug in 'rdlibrary/audio_cart.cpp' that was causing cuts + to be deleted even if the confirmation dialog had been answered + 'no'. +2005-09-22 Fred Gleason + * Fixed bugs in 'rdcatchd/rdatchd.cpp' that was causing the deck + status monitors to fail to be initialized properly with decks in + the WAITING state. +2005-09-22 Fred Gleason + * Incremented the package version to 0.9.51d. +2005-09-23 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was causing the 'next + event' indication to fail to update when event parameters were + changed from a remote host. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing + rdcatchd(8) to segfault when attempting to abort a WAITing deck. +2005-09-23 Fred Gleason + * Changed the wording of the 'Allow Multiple Recordings' control + in 'rdcatch/edit_recording.cpp'. +2005-09-23 Fred Gleason + * Added a dialog to RDLibrary's Edit Cart dialog to warn about + deletion of audio when cancelling a newly created cart. +2005-09-23 Fred Gleason + * Added code to force the status of a deck monitor in RDCatch to + 'Idle' if sent an event id of '0'. +2005-09-23 Fred Gleason + * Incremented the package version to 0.9.51e. +2005-09-27 Fred Gleason + * Added 'CART.AVERAGE_LENGTH' and 'CART.ASYNCRONOUS' fields to the + database. + * Renamed the 'RDCart::averageLength() method to + 'RDCart::calculateAverageLength()'. + * Added 'RDCart::averageLength()', 'RDCart::setAverageLength()', + 'RDCart::syncronous()' and 'RDCart::setSyncronous()' methods in + 'lib/rdcart.cpp'. + * Incremented the database version to 89. + * Added an 'RDMacro::length()' method in 'lib/rdmacro.cpp'. + * Added a 'Forced Length' control to the Edit Cart dialog in + RDLibrary. + * Added an 'Execute Asynchronously' check box to the Edit Cart + dialogin in RDLibrary. + * Fixed multiple bugs with handling user responses from 'Yes/No' + message dialog boxes. +2005-09-28 Fred Gleason + * Added 'REPORTS.CART_DIGITS' and 'REPORTS.USE_LEADING_ZEROS' to + the database. + * Incremented the database version to 90. + * Added 'Cart Parameter' control to RDAdmin's Edit Report dialog + box. + * Modified the CBSI DeltaFlex filter in + 'rdlogmanager/export_deltaflex.cpp' to use the leading zeros + parameters. + * Modified the Text Report filter in + 'rdlogmanager/export_textlog.cpp' to use the leading zeros + parameters. +2005-09-28 Fred Gleason + * Fixed a race condition in 'lib/rdcae.cpp' that was causing state + changes sent from caed(8) to be lost under certain circumstances. +2005-09-28 Fred Gleason + * Fixed a bug in 'rdlibrary/edit_cart.cpp' that was allowing users + without the 'Modify Carts' privilege to change the forced length + of carts. + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. +2005-09-28 Fred Gleason + * Incremented the package version to 0.9.52. +2005-09-28 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing the + build to break with Qt 3.2.x. + * Incremented the package version to 0.9.53. +2005-09-30 Fred Gleason + * Added code to 'rdlibrary/audio_cart.cpp' to show evergreen cut + entries with a green background. +2005-09-30 Fred Gleason + * Fixed a bug that was causing the Pie Widget to show invalid + values when executing a macro cart containing a Sleep RML. +2005-10-03 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing the + state of the 'Mon' button to be incorrectly initialized. + * Changed to 'Mon' buttons in RDCatch to use a steady color rather + than flashing. +2005-10-03 Fred Gleason + * Added a 'DECKS.DEFAULT_MONITOR_ON' field to the database. + * Incremented the database version to 91. + * Added a 'Monitor defaults to' control to the Edit Deck dialog in + RDAdmin. + * Implemented default monitor state in 'rdcatchd/rdcatchd.cpp'. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing monitors + to be reset when the 'RD' [Load Deck List] command was processed. +2005-10-03 Fred Gleason + * Added 'RDEvent::autofillSlop()' and 'RDEvent::setAutofillSlop()' + methods in 'lib/rdevent.cpp'. + * Added autofill slop controls in 'rdlogmanager/edit_event.cpp'. + * Implemented warnings for autofill underscheduling in + RDLogManager. +2005-10-04 Fred Gleason + * Removed the 'Hours' field from the Start and End time controls + in 'rdlogmanager/edit_eventline.cpp'. + * Removed the 'Hours' field from the Start and End columns + in 'rdlogmanager/edit_clock.cpp'. + * Removed the 'Hours' field from the Start and End slop controls + in 'rdlogmanager/edit_events.cpp'. + * Changed the 'Grace Time' control in + 'rdlogmanager/edit_events.cpp' to use seperate minutes and seconds + fields. +2005-10-04 Fred Gleason + * Changed the 'Grace Time' control in + 'rdlogedit/edit_logline.cpp' to use seperate minutes and seconds + fields. + * Changed the 'Grace Time' control in + 'rdairplay/edit_event.cpp' to use seperate minutes and seconds + fields. +2005-10-05 Fred Gleason + * Applied a patch from Darrick (Mantis bug #80) to correct + hard-coded audio extension types. +2005-10-05 Fred Gleason + * Added a 'RDMacroEvent::stop()' class in 'lib/rdmacro_event.cpp'. + * Fixed a bug in rdairplay/log_play.cpp' where sending a stop to a + macro cart was ignored (Mantis bug #52). +2005-10-05 Fred Gleason + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing + RDAirPlay to exit even after clicking 'No' to the exit + confirmation dialog. +2005-10-07 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.54. +2005-10-10 Fred Gleason + * Fixed a bug in filename handling in 'lib/rdaudio_exists.cpp'. + * Fixed a bug in filename handling in 'lib/rdcart.cpp'. + * Fixed a bug in filename handling in 'lib/rdcut.cpp'. + * Fixed a bug in filename handling in 'rdlibrary/edit_audio.cpp'. +2005-10-11 Fred Gleason + * Changed the dialog caption in 'rdlibrary/disk_ripper.cpp' to + 'Rip Disk'. + * Changed the dialog caption in 'rdlibrary/edit_audio.cpp' to + include 'Edit Markers'. + * Fixed a bug in 'rdairplay/list_log.cpp' where deleting an event + prior to a Hard Time would cause the Full Log widget to display + the hard time next to the wrong event (Mantis bug #82). +2005-10-11 Fred Gleason + * Added 'StartTimeType::Imported' to the + 'RDLogLine::StartTimeType' enumeration in 'lib/rdlog_line.h'. + * Changed the logic in 'edit_event.cpp' so that clearing the Hard + Time time type in an event restores the original imported start + time. + * Implemented new estimated start time logic for the Full Log + widget in 'rdairplay/log_play.cpp' (Mantis bug #82). +2005-10-11 Fred Gleason + * Fixed a bug in 'rdlibrary/record_cut.cpp' where checking the + 'Evergreen' box would clear the Day of the Week checkboxes. +2005-10-11 Fred Gleason + * Fixed a bug in 'lib/rdlistview.cpp' where pressing the space bar + would fail to advance events in RDAirPlay (Mantis bug #60). +2005-10-11 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.55. +2005-10-17 Fred Gleason + * Added a 'LOGS.IMPORT_DATE' field to the database. + * Added 'FADEUP_POINT', 'FADEUP_GAIN', 'FADEDOWN_POINT', + 'FADEDOWN_GAIN' and 'SEGUE_GAIN' fields to the log table format in + the database. + * Incremented the database version to 93. +2005-10-18 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that was causing a log + generated in RDLogManager to append extra autofill events if the + final hour crossed midnight. +2005-10-19 Fred Gleason + * Implemented the 'FADEUP_POINT', 'FADEUP_GAIN', 'FADEDOWN_POINT', + 'FADEDOWN_GAIN' and 'SEGUE_GAIN' fields in 'RDLogEvent::save()' + and 'RDLogEvent::load()' in 'lib/rdlog_event.cpp'. + * Removed the 'RD_USE_MYSQL_EXTENSIONS' define from 'lib/rd.h'. + * Added an 'RDLogLine::PointerSource' enum in 'lib/rdlog_line.h'. + * Implemented FadeUp, FadeDown and Segue overloading in + 'lib/rdplay_deck.cpp'. +2005-10-20 Fred Gleason + * Added a 'Type::Track' value to the 'RDLogLine::Type' enum in + 'lib/rdlog_line.h'. + * Added a Voice Track icon in 'icons/track.xpm'. + * Implemented the Voice Track Marker log event type in RDLogEdit. + * Implemented the Voice Track Marker log event type in RDAirPlay. + * Implemented the Voice Track Marker log event type in RDLogManager. +2005-10-21 Fred Gleason + * Added 'SERVICES.TRACK_GROUP', 'LOGS.SCHEDULED_TRACKS', + 'LOGS.COMPLETED_TRACKS' and 'CART.OWNER' fields to the + database. + * Incremented the database version to 94. + * Added an icon for audio track carts in 'icons/track_cart.xpm'. + * Added 'RDCart::owner()' and 'RDCart::setOwner()' methods in + 'lib/rdcart.cpp'. + * Implemented Voice Track Cart permissioning in RDLibrary. + * Implemented Voice Track Cart permissioning ifor 'RDCutDialog' in + 'lib/rdcut_dialog.cpp'. + * Implemented Voice Track Cart permissioning in RDCatch. + * Added an 'RDLogLine::Tracker' value to the 'RDLogLine::Source' + enum in 'lib/rdlog_line.h'. + * Added 'RDLog::scheduledTracks()', 'RDLog::completedTracks()', + 'RDLog::remove()', 'RDLog::updateTracks()' and + 'RDLog::removeTracks()' methods in 'lib/rdlog.cpp'. +2005-10-21 Fred Gleason + * Fixed a bug in 'rdlogmanager/generate_log.cpp' that was causing + the track count values for a newly-generated log to fail to be + updated. + * Added a 'Tracks' column to RDLogEdit's log list + 'rdlogedit/rdlogedit.cpp'. + * Added a 'Tracks' field to the head section of the 'EditLog' + dialog in 'rdlogedit/edit_log.cpp'. +2005-10-23 Fred Gleason + * Added a 'USERS.VOICETRACK_LOG_PRIV' field to the database. + * Incremented the database version to 95. + * Fixed a bug in 'rdadmin/createdb.cpp' that was causing the + default 'user' account to be created with the 'MODIFY_TEMPLATE' + permission set to 'no'. + * Added 'RDUser::voicetrackLogs()' and + 'RDUser::setVoicetrackLogs()' methods in 'lib/rduser.cpp'. + * Added a 'Voicetrack Logs' checkbox to the Edit User dialog in + 'rdadmin/edit_user.cpp'. + * Added 'RDSvc::trackGroup()' and 'RDSvc::setTrackGroup()' methods + in 'lib/rdsvc.cpp'. + * Added a 'Voicetrack Group' control to the Edit Service dialog in + 'rdadmin/edit_svc.cpp'. +2005-10-23 Fred Gleason + * Added a 'Voice Track' button to RDLogEdit's main window. + * Added a ListTracks' dialog in 'rdlogedit/list_tracks.cpp'. + * Added a Voice Tracker dialog in 'rdlogedit/voice_tracker.cpp'. +2005-10-24 Fred Gleason + * Added a checkmark icon in 'icons/checkmark.xpm'. + * Added an 'X' icon in 'icons/ex.xpm'. + * Added status icons to the List Tracks dialog in + 'rdlogedit/list_tracks.cpp'. +2005-10-24 Fred Gleason + * Added 'RDListViewItem::line()', ''RDListViewItem::setLine()', + 'RDListViewItem::id()' and ''RDListViewItem::setId()' methods in + 'lib/rdlistviewitem.cpp'. + * Added an 'RDLOGEDIT' table to the database. + * Incremented the database version to 96. + * Added an 'RDLogEditConf' class in 'lib/rdlogedit_conf.cpp'. + * Added an 'RDLogEdit' button in the Edit Hosts dialog in RDAdmin. +2005-10-24 Fred Gleason + * Added 'Next', 'Save', 'Previous', 'Cancel' and 'Ok' buttons to + then Voice Track dialog in 'rdlogedit/voice_track.cpp'. +2005-10-26 Fred Gleason + * Added a meter and transport buttons to the Voice Track dialog in + 'rdlogedit/voice_tracker.cpp'. +2005-10-26 Fred Gleason + * Finished stubbing out the Voice Tracker dialog in + rdlogedit/voice_tracker.cpp'. +2005-10-26 Fred Gleason + * Tweaked positioning of RDAirPlay's meter and label widgets in + 'rdairplay/rdairplay.cpp'. +2005-10-27 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing restart + of paused log events to fail. + * Changed the name of the 'RD_LANGUAGE' environmental variable to + 'RD_LANGUAGES' in 'helpers/rdtrans.sh'. +2005-10-27 Fred Gleason + * Added a 16x16 Rivendell icon in 'icons/rivendell-16x16.xpm'. + * Added a 22x22 Rivendell icon in 'icons/rivendell-22x22.xpm'. + * Added a 32x32 Rivendell icon in 'icons/rivendell-32x32.xpm'. + * Added a 64x64 Rivendell icon in 'icons/rivendell-64x64.xpm'. + * Added a 128x128 Rivendell icon in 'icons/rivendell-128x128.xpm'. + * Tweaked 'rdlogin/rdlogin.cpp' to list the users in alphabetical + order. + * Added code to bind application icon for all GUI modules. +2005-10-27 Fred Gleason + * Added code to disable KDE dialog overriding in 'rdadmin/rdadmin.cpp'. + * Fixed a bug in 'rdadmin/edit_svc.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdadmin/list_groups.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdadmin/list_hostvars.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdadmin/list_reports.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdadmin/list_stations.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdadmin/list_svcs.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdadmin/list_users.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdadmin/opendb.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdadmin/rdadmin.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdadmin/rename_group.cpp' that was causing the + response to a message box dialog to be ignored. + * Added code to disable KDE dialog overriding in + 'rdairplay/rdairplay.cpp'. + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing the + response to a message box dialog to be ignored. + * Added code to disable KDE dialog overriding in 'rdcatch/rdcatch.cpp'. + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdlibrary/add_cart.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdlibrary/audio_cart.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdlibrary/cdripper.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdlibrary/disk_ripper.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdlibrary/edit_cart.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdlibrary/import_audio.cpp' that was causing the + response to a message box dialog to be ignored. + * Added code to disable KDE dialog overriding in + 'rdlibrary/rdlibrary.cpp'. + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdlibrary/record_cut.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was causing the + response to a message box dialog to be ignored. + * Added code to disable KDE dialog overriding in + 'rdlogedit/rdlogedit.cpp'. + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' that was causing the + response to a message box dialog to be ignored. + * Added code to disable KDE dialog overriding in + 'rdlogin/rdlogin.cpp'. + * Fixed a bug in 'rdlogmanager/edit_clock.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdlogmanager/edit_event.cpp' that was causing the + response to a message box dialog to be ignored. + * Fixed a bug in 'rdlogmanager/export_deltaflex.cpp' that was + causing the response to a message box dialog to be ignored. + * Fixed a bug in 'rdlogmanager/export_textlog.cpp' that was + causing the response to a message box dialog to be ignored. + * Fixed a bug in 'rdlogmanager/generate_log.cpp' that was + causing the response to a message box dialog to be ignored. + * Fixed a bug in 'rdlogmanager/list_clocks.cpp' that was + causing the response to a message box dialog to be ignored. + * Fixed a bug in 'rdlogmanager/list_events.cpp' that was + causing the response to a message box dialog to be ignored. + * Added code to disable KDE dialog overriding in + 'rdlogmanager/rdlogmanager.cpp'. + * Added code to disable KDE dialog overriding in + 'utils/rdgpimon.cpp'. + * Added code to disable KDE dialog overriding in + 'utils/rmlsend.cpp'. +2005-11-01 Fred Gleason + * Added an 'xdg/' directory. + * Created XDG entries in 'xdg/rdlibrary.desktop', + 'xdg/rdcatch.desktop', 'xdg/rdairplay.desktop', + 'xdg/rdlogedit.desktop','xdg/rdlogmanager.desktop', + 'xdg/rmlsend.desktop', 'xdg/rdgpimon.desktop' and + 'xdg/rdadmin.desktop'. + * Fixed a bug in 'icons/Makefile.am' that was causing icons to be + left out of the tarball. + * Implemented SuSE desktop integration. +2005-11-01 Fred Gleason + * Added 'LOGS.LOG_EXISTS' and 'USERS.DELETE_REC_PRIV' fields to + the database. + * Incremented the database version to 97. + * Added 'RDLog::logExists()' and 'RDLog::setLogExists()' methods + in 'lib/rdlog.cpp'. + * Added 'RDUser::deleteRec()' and 'RDUser::setDeleteRec()' methods + in 'lib/rduser.cpp'. + * Added a 'Delete ELR Data' control to the Edit User dialog in + 'rdadmin/edit_user.cpp'. + * Added a 'DeleteLog' dialog in 'rdlogedit/delete_log.cpp'. + * Added logic to 'rdairplay/list_logs.cpp' to exclude + partially-deleted logs from the list of available logs to load. + * Added a 'ListRecs' dialog in 'rdlogmanager/list_recs.cpp'. +2005-11-03 Fred Gleason + * Changed the phrase 'ELR Data' to 'Report Data' in + 'rdadmin/edit_user.cpp'. + * Changed the phrase 'ELR Data' to 'Report Data' in + 'rdlogedit/delete_log.cpp'. + * Changed the phrase 'ELR Data' to 'Report Data' in + 'rdlogmanager/rdlogmanager.cpp'. + * Changed the phrase 'ELR Data' to 'Report Data' in + 'rdlogmanager/list_recs.cpp'. +2005-11-03 Fred Gleason + * Fixed a bug in 'rdlibrary/import_audio.cpp' where the response + to the confirm file overwrite dialog was ignored (Mantis bug + #108). +2005-11-03 Fred Gleason + * Changed the default End Date for cuts in + 'rdlibrary/record_cut.cpp' to the current date (Mantis bug #104). +2005-11-03 Fred Gleason + * Changed the sorting of the 'Groups' dropdown control in + 'lib/rdcart_dialog.cpp' so as to list the group names + alphabetically. +2005-11-03 Fred Gleason + * Added 'Enable Group for All Users' and 'Enable Group for All + Services' checkboxes in 'rdadmin/add_group.cpp'. +2005-11-03 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' that was causing cut dayparting + information to be reset when updating audio in a cut. +2005-11-03 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.56. +2005-11-03 Fred Gleason + * Fixed a bug in 'utils/rmlsend.cpp' that was causing the build to + break under Windows. + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' that was causing the + build to break under Windows. + * Fixed a bug in 'rdlogmanager/rdlogmanager.cpp' that was causing + the build to break under Windows. + * Fixed a bug in 'rdlogedit/rdlogedit.pro' that was causing + the build to break under Windows. + * Fixed a bug in 'rdlogmanager/rdlogmanager.pro' that was causing + the build to break under Windows. +2005-11-03 Fred Gleason + * Fixed a bug in 'utils/rmlsend.cpp' that was causing the build to + break under SuSE 9.0. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.57. +2005-11-04 Fred Gleason + * Modified 'rivendell.spec.in' to not require the + 'update_desktop_files' script for desktop menu integration. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.58. +2005-11-07 Fred Gleason + * Fixed a bug in 'rivendell.spec.in' that was causing KDE menu + integration to fail on SuSE 9.3. + * Incremented the package version to 0.9.59. +2005-11-08 Fred Gleason + * Retired the per-log reconciliation table format in + 'doc/tables/rec_format.txt'. + * Added a new per-service reconcilliation table format in + 'doc/tables/svc_rec_format.txt'. + * Added 'RDSvc::create()' and 'RDSvc::remove()' methods in + 'lib/rdsvc.cpp'. + * Added a 'RDAIRPLAY.DEFAULT_SERVICE' field to the database. + * Incremented the database version to 98. + * Added a 'Default Service' control to RDAdmin's Edit RDAirPlay + dialog in 'rdadmin/edit_rdairplay.cpp'. + * Added code to reset RDAIRPLAY.DEFAULT_SERVICE when a referenced + service is deleted in 'lib/rdsvc.cpp'. + * Added code to clone RDAIRPLAY.DEFAULT_SERVICE to a new Station + config in 'rdadmin/add_station.cpp'. + * Modified the 'LogTraffic()' function in + 'rdairplay/log_traffic.cpp' to use the new per-service based + report data logging. + * Added a 'ListSvcs' dialog in 'rdlogmanager/list_svcs.cpp'. + * Added a 'DeleteSvcRec' widget in + 'rdlogmanager/delete_svc_rec.cpp', based upon the 'RDatePicker' + class from LibRadio. + * Added a 'DeleteSvcRecDialog' widget in + 'rdlogmanager/delete_svc_rec_dialog.cpp', based upon the + 'RDatePickerDialog' class from LibRadio. + * Modified 'rdlogmanager/generateReport()' to use service-based + reconciliation data for report generation. + * Removed the 'DeleteLog' dialog in 'rdlogedit/delete_log.cpp'. +2005-11-09 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that was causing creation + of a new database to fail. +2005-11-14 Fred Gleason + * Removed a debugging printf() from 'rdadmin/createdb.cpp'. +2005-11-14 Fred Gleason + * Fixed a bug in 'rdairplay/log_traffic.cpp' that was causing + invalid reconciliation data to be recorded for events crossing + midnight. +2005-11-14 Fred Gleason + * Refactored the interface in RDLogManager to both generate + reports and delete report data under a single button, called + 'Manage Reports'. +2005-11-14 Fred Gleason + * Fixed a bug in 'lib/rduser.cpp' that was causing user + authentication to fail when used with versions of mySQL later than + 4.0.x (Mantis bug #112). +2005-11-14 Fred Gleason + * Fixed a bug in 'lib/rdpasswd.cpp' that was causing incorrect + font sizing on SuSE 9.2. +2005-11-15 Fred Gleason + * Added a 'USERS.CONFIG_PANELS_PRIV' field to the database. + * Added 'RDUser::configPanels()' and 'RDUser::setConfigPanels(); + methods in 'lib/rduser.cpp'. + * Incremented the database version to 99. + * Added a 'Configure System Panels' control to the Edit User + dialog in 'rdadmin/edit_user.cpp'. + * Implemented the 'Configure System Panels' right in + lib/rdsound_panel.cpp'. +2005-11-15 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that was causing duplicate + service entries to be placed into the 'SERVICE_PERMS' table when + creating a new database. +2005-11-15 Fred Gleason + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that was causing a + segfault when clicking a blank portion of the cart list. +2005-11-15 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.60. +2005-11-15 Fred Gleason + * Fixed a bug in 'rdlogmanager/rdlogmanager.pro' that was causing + the build to break under Windows. +2005-11-16 Fred Gleason + * Fixed a bug in 'rdlogmanager/svc_rec_dialog.cpp' that was causing + a segfault under Windows. +2005-11-16 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was loading incorrect + start and end point data. +2005-11-21 Fred Gleason + * Added 'RDLogLine::cutName()' and 'RDLogLine::setCutName()' in + 'lib/rdlog_line.cpp'. + * Fixed a bug in 'lib/rdcart.cpp' that was causing carts with randomly + scheduled cut rotations to report invalid cue point parameters in + RDAirPlay. +2005-11-21 Fred Gleason + * Applied a fix by Darrick for an + overflow bug in 'lib/rdplay_deck.cpp' (Mantis bug #117). +2005-11-21 Fred Gleason + * Fixed a bug in 'rdlibrary/import_audio.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlibrary/audio_cart.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlibrary/cdripper.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlibrary/disk_ripper.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlibrary/edit_cart.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlibrary/record_cut.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdadmin/edit_group.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdadmin/edit_svc.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdadmin/list_groups.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdadmin/list_hostvars.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdadmin/list_matrices.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdadmin/list_svcs.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdadmin/opendb.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdadmin/rdadmin.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdadmin/rename_group.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdairplay/rdairplay.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdcatch/rdcatch.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlogedit/edit_log.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlogmanager/edit_clock.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlogmanager/edit_event.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlogmanager/generate_log.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlogmanager/generate_report.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlogmanager/list_clocks.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlogmanager/list_events.cpp' so that closing the + message box with the 'X' button properly indicates 'No'. + * Fixed a bug in 'rdlogmanager/svc_rec_dialog' so that closing the + message box with the 'X' button properly indicates 'No'. +2005-11-21 Fred Gleason + * Fixed a bug in 'rdlogmanager/list_events.cpp' where canceling an + unsaved new event would still result in a 'phantom' event being + added to the event list (Mantis bug #115). +2005-11-21 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' where the progress bars in + RDAirPlay would freeze when crossing midnight (Mantis bug #114). +2005-11-21 Fred Gleason + * Added an 'RDCart::addCut()' method in 'lib/rdcart.cpp'. + * Changed the behavior of RDLibrary so that carts created at the + moment of clicking the 'Ok' button in the 'Add Cart' dialog, + rather than in the 'Edit Cart' dialog (MAntis feature request #102). + * Changed the behavior of RDLibrary so that a new cart gets a + single default cut created automatically. +2005-11-22 Fred Gleason + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' where closing the + Delete Cart confirmation box by clicking the 'X' button would + delete the cart. + * Fixed a layout error in the Add Cart dialog in + 'rdlbrary/add_cart.cpp'. +2005-11-22 Fred Gleason + * Added code to 'rdlibrary/add_cart.cpp' to fill in a default + title for new carts. + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that was causing the + per-track CD ripper to fail to write FreeDB track data into a new + cart's title. +2005-11-22 Fred Gleason + * Fixed a bug in 'lib/rdcart.cpp' that was causing a segfault when + 'RDCart::selectCart()' was called with a null cut name. +2005-11-22 Fred Gleason + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that was causing the + cart information to fail to be updated in the library list after + clicking the 'Cancel' button in the Edit Cart dialog. +2005-11-22 Fred Gleason + * Updated the 'NEWS' file. + * Updated the package version to 0.9.61. +2005-11-22 Fred Gleason + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that broke the Edit + button. +2005-11-23 Fred Gleason + * Fixed a bug in 'rivendell-suse' that was failing in include + '/usr/local/bin' in the PATH variable when starting the daemons. +2005-11-23 Fred Gleason + * Applied a fix by Eric Dantan Rzewnicki to + correct a bug in 'cae/cae_jack.cpp' that was causing carts to be + skipped in RDAirPlay. +2005-11-28 Fred Gleason + * Added code to 'rdlogedit/voice_tracker.cpp' to audition the + current transition settings in the Voice Tracker dialog. + * Added code to 'rdlogedit/voice_Tracker.cpp' to provide a + scrolling playback cursor in the Voice Tracker dialog. +2005-11-29 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was causing the + 'Yes' and 'No' buttons in the delete confirmation dialog box to be + reversed. +2005-11-29 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing log + events with a Hard Start time set to 'make next if event still + playing' to fail to start if no event was playing. +2005-11-29 Fred Gleason + * Fixed a bug in 'lib/rdescape_string.cpp' in which the ')' was + not being escaped properly (Mantis bug #118). +2005-11-29 Fred Gleason + * Added code to hide the Tracker button in + 'rdlogedit/rdlogedit.cpp'. +2005-11-29 Fred Gleason + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' that was causing the + build to break under Windows. +2005-11-29 Fred Gleason + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' that was causing the + build to break under Linux. +2005-11-29 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.62. +2005-11-29 Fred Gleason + * Fixed a bug in 'lib/rdwavepainter.cpp' that was causing the + build to break on SuSE 9.0. +2005-11-30 Fred Gleason + * Added a 'MainWidget::RefreshItem()' method in + 'rdlogedit/rdlogedit.cpp'. + * Removed the 'MainWidget::SelectRecord()' method in + 'rdlogedit/rdlogedit.cpp'. + * Removed the 'ListTracks' class in 'rdlogedit/list_tracks.cpp'. +2005-12-02 Fred Gleason + * Added an 'RDGainEnvelope' class in 'lib/rdgain_envelope.cpp'. + * Fixed a bug in 'ripcd/local_audio.cpp' where an ST macro would + fail to properly mute the previous assignment. +2005-12-02 Fred Gleason + * Added the ability to audition the head and tail of Upload and + Download events (Mantis feature request #123). +2005-12-05 Fred Gleason + * Added the ability to mute an output from a switcher event in + RDCatch (Mantis feature request #124). +2005-12-05 Fred Gleason + * Added an 'RDCmdSwtich' class in 'lib/rdcmd_switch.cpp'. + * Implemented the ability to specify default logs on the command + line to RDAirPlay (Mantis feature request #125). +2005-12-05 Fred Gleason + * Added a usage message for rdairplay(1) in + 'rdairplay/rdairplay.h'. +2005-12-05 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing + rdcatchd(8) to segfault if two or more playout events were + executed simultaneously with the same deck. +2005-12-05 Fred Gleason + * Fixed a bug in 'rdcatch/edit_playout.cpp' that was allowing + new playout events to be created that conflicted with existing + events. +2005-12-07 Fred Gleason + * Added hostname resolution support to RMLSend. + * Added a CLI interface to RMLSend. +2005-12-07 Fred Gleason + * Added support for '--version' and --help' command-line switches + to RDAdmin. + * Added support for '--version' and --help' command-line switches + to RDCatch. + * Added support for '--version' and --help' command-line switches + to RDLibrary. + * Added support for '--version' and --help' command-line switches + to RDLogEdit. + * Added support for '--version' and --help' command-line switches + to RDLogin. + * Added support for '--version' and --help' command-line switches + to RDLogManager. + * Added support for '--version' and --help' command-line switches + to ripcd(8). + * Added support for '--version' and --help' command-line switches + to rdcatchd(8). + * Added support for '--version' and --help' command-line switches + to caed(8). + * Added support for '--version' and --help' command-line switches + to RDGpiMono. + * Added support for '--version' and --help' command-line switches + to RDImport. + * Added support for '--version' and --help' command-line switches + to sas_shim(8). + * Added support for '--version' and --help' command-line switches + to rdcatch_copy(1). + * Added support for '--version' and --help' command-line switches + to sas_filter(1). + * Added support for '--version' and --help' command-line switches + to wings_filter(1). +2005-12-08 Fred Gleason + * Fixed a bug in 'importers/wings_filter.cpp' that was causing + newly imported cuts to show red in RDLibrary. + * Implemented a feature so that the original filename of cuts + imported through wings_filte(1) is shown in the 'User Defined' + field of the cart label (Mantis feature request #127). +2005-12-09 Fred Gleason + * Added 'Type::StarGuideIII' to the 'RDMatrix::Type' enum in + 'lib/rdmatrix.h'. + * Added a 'StarGuideFeed' class in 'ripcd/starguide_feed.cpp'. + * Added a 'StarGuide3' switcher driver in 'ripcd/starguide3.cpp'. + * Removed code to drop root permissions in 'ripcd/ripcd.cpp'. +2005-12-09 Fred Gleason + * Fixed a bug in 'ripcd/starguide3.cpp' that was sending an + impo\roperly formatted command string. +2005-12-09 Fred Gleason + * Added 'Type::BtSs42' to the 'RDMatrix::Type' enum in + 'lib/rdmatrix.h'. + * Added support for the BroadcastTools SS4.2 switcher in RDAdmin. + * Added a driver for the BroadcastTools SS4.2 switcher in + ripcd/btss42.cpp'. +2005-12-09 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was failing to + honor a STOP transition on the first event of a CHAINed log. +2005-12-09 Fred Gleason + * Fixed a bug in 'rdadmin/list_endpoint.cpp' that was causing the + Provider ID and Service ID values for the StarGuide III driver to + be incremented every time they were saved. +2005-12-09 Fred Gleason + * Fixed a bug in 'log_play.cpp' that was causing Hard Time events + to be missed following a transition across midnight. +2005-12-13 Fred Gleason + * Added an optional third argument to the 'Load Log' [LL] macro to + allow specification of the start line of the loaded log. +2005-12-13 Fred Gleason + * Fixed a race in 'rdairplay/log_play.cpp' that was causing CHAIN + events to occasionally fail to start the chained-to log. +2005-12-13 Fred Gleason + * Changed the 'CHAIN TO' string to 'CHAIN' in + 'rdlogplay/loglinebox.cpp'. +2005-12-13 Fred Gleason + * Fixed bug in 'utils/rmlsend.cpp' that was causing the build to + break under Windows. +2005-12-14 Fred Gleason + * Added a utility for copying sound panel button assignments + between databases is 'importers/panel_copy.cpp'. +2005-12-16 Fred Gleason + * Fixed a bug in 'ripcd/starguide3.cpp' that was generating + corrupt Starguide switching commands. +2005-12-16 Fred Gleason + * Fixed a bug in 'ripcd/starguide3.cpp' that was generating + corrupt Starguide switching commands. +2005-12-16 Fred Gleason + * Updated the 'NEWS' file. + * Updated package version to 0.9.63. +2005-12-16 Fred Gleason + * Hid the 'Voice Track' button in 'rdlogedit/rdlogedit.cpp'. +2005-12-16 Fred Gleason + * Fixed a bug in 'rdairplay/rdairplay.cpp' that was causing the + build to break under SuSE 9.0. + * Fixed a bug in 'utils/rmlsend.cpp' that was causing the + build to break under SuSE 9.0. +2005-12-16 Fred Gleason + * Added information on the Broadcast Tools SS8.2 and StarGuide III + switcher devices in 'docs/SWITCHERS.txt'. +2005-12-19 Fred Gleason + * Removed debugging printfs from 'cae/cae_hpi.cpp'. +2005-12-20 Fred Gleason + * Added code to scroll track waveforms in + 'rdlogedit/voice_tracker.cpp'. +2006-01-03 Fred Gleason + * Added code to 'cae/cae_hpe.cpp', 'cae/cae_alsa.cpp' and + 'cae/cae_jack.cpp' to add a LEVL chunk to PCM16 encoded + recordings. +2006-01-03 Fred Gleason + * Added an 'rdfilewrite' utility in 'utils/rdfilewrite.cpp'. + * Modified 'scripts/rd_import_file' to use rdfilewrite(1) to + generate a LEVL chunk for audio imported to PCM16 format. +2006-01-04 Fred Gleason + * Modified 'scripts/rd_rip_cd' to use rdfilewrite(1) to + generate a LEVL chunk for audio ripped to PCM16 format. +2006-01-04 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' where an RDLogManager + event would not apply the time type parameters when the Pre-Import + Carts list was empty (Mantis bug #129). +2006-01-04 Fred Gleason + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Updated package version to 0.9.64. +2006-01-04 Fred Gleason + * Added rdfilewrite(1) to 'rivendell/spec.in'. +2006-01-10 Fred Gleason + * Fixed a bug in 'rdlogmanager/import_listview.cpp' that was preventing + a STOP transition from being set for the first cart in the + Preimport list. +2006-01-25 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that was causing autofill + events to not be inserted if no items were found to import for the + event. +2006-01-25 Fred Gleason + * Changed the RDCutDialog in 'lib/rdcut_dialog.cpp' to list groups + in alphabetical order. +2006-01-25 Fred Gleason + * Fixed a bug in 'rdlogmanager/rename_item.cpp' that was allowing + an event or clock to be given a name containing invalid + characters. +2006-01-25 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that was causing log data imports + to services containing spaces in their names to fail (Mantis bug + #120). +2006-01-25 Fred Gleason + * Updated the 'NEWS' file. + * Updated package version to 0.9.65. +2006-01-30 Fred Gleason + * Modified 'rivendell-suse' to work properly even in the absence of + a working set of LSB Init scripts. + * Added 'make_slack.in', 'slack-desc.in' and 'slack_doinst.sh' + files. + * Added 'make slack' and 'make slax' build targets. +2006-01-30 Fred Gleason + * Added rdgen(1) to 'make_slack.in'. +2006-01-30 Fred Gleason + * Added a 'conf/rd.conf-slax' file. + * Added an argument to the 'build_slack' to allow the user to + specify the rd.conf(5) file to be included into the package. + * Fixed bug in 'make_slack.in' that was causing the menu items and + icons to fail to be included in the Slackware package. +2006-01-30 Fred Gleason + * Fixed bug in 'make_slack.in' that was causing the icons to fail + to be included in the Slackware package. +2006-01-31 Fred Gleason + * Changed the 'AudioOwner=' entry in 'conf/rd.conf-slax' to 'salem'. + * Changed the default audio owner in 'importers/export_slax' to + '500'. +2006-02-03 Fred Gleason + * Rewrote 'scripts/rd_rip_cd' to use cdda2wav(1) as the ripper + engine. + * Added 'cdda2wav' to the 'Requires:' list in 'rivendell.spec.in'. +2006-02-03 Fred Gleason + Added cdda2wav(1) to the list of dependencies in 'INSTALL'. +2006-02-03 Fred Gleason + * Added CD-TEXT support to the CD Ripper in + 'rdlibrary/cdripper.cpp'. + * Added CD-TEXT support to the Disk Ripper in + 'rdlibrary/disk_ripper.cpp'. +2006-02-03 Fred Gleason + * Added a 'CUTS.ISRC' field to the database. + * Incremented the database version to 100. + * Added 'RDCut::isrc()' and 'RDCut::setIsrc()' methods in + 'lib/rdcut.cpp'. + * Added an 'ISRC' control in the Cut Record dialog in + 'rdlibrary/record_cut.cpp'. + * Added logic to write the ISRC value from the CD ripper to the + database in 'rdlibrary/audio_cart.cpp'. + * Added logic to write the ISRC value from the Disk ripper to the + database in 'rdlibrary/disk_ripper.cpp'. +2006-02-03 Fred Gleason + * Added an 'IsrcFormat' enum in 'lib/rdcut.h'. + * Added code to 'rdlibrary/record.cut.cpp' to properly format ISRC + entries. +2006-02-06 Fred Gleason + * Renamed/Moved the 'AddCart' dialog in 'rdlibrary/add_cart.cpp' + to 'RDAddCart' in 'lib/rdadd_cart.cpp'. + * Added an 'Add New Cart' button to RDCutDialog in + 'lib/rdcut_dialog.cpp'. + * Added an 'RDListGroups' dialog in 'lib/rdlist_groups.cpp'. + * Added an 'RDGroups::freeCartQuantity()' method in + 'lib/rdgroup.cpp'. + * Added a 'Set All New Carts' button to the Disk Ripper dialog in + 'rdlibrary/disk_ripper.cpp'. +2006-02-06 Fred Gleason + * Fixed a bug in 'rivendell-suse' that was causing the script to + fail to detect the presence of the LSB Init functions. +2006-02-06 Fred Gleason + * Removed two debugging printf statements from + 'rdlibrary/disk_ripper.cpp'. +2006-02-06 Fred Gleason + * Adjusted the default size of the Disk Ripper dialog in + 'rdlibrary/disk_ripper.cpp'. +2006-02-08 Fred Gleason + * Modified the generic init script in 'rivendell-suse.in' to use + the install paths provided by Autoconf. +2006-02-08 Fred Gleason + * Modified 'rivendell.spec.in' and 'make_slack.in' to use the + install paths provided by Autoconf. +2006-02-08 Fred Gleason + * Added a 'CatchMonitor' class in 'rdcatch/catch_monitor.cpp'. + * Rewrote 'rdcatch/rd.catch.cpp' so as to eliminate the arbitrary + limit on the number of deck monitors. + * Fixed a bug in 'lib/rdcut_dialog.cpp' that was causing a + segfault. +2006-02-10 Fred Gleason + * Fixed a bug in RDSvc::import() that was causing import of + traffic events with zero length to fail. +2006-02-10 Fred Gleason + * Added logic to RDSvc::import() in 'lib/rdsvc.cpp' and + RDEventLine::generateLog() in 'lib/rdevent_line.cpp' to allow + handling of traffic import events with duplicate times. +2006-02-13 Fred Gleason + * Added a 'VBox' class in 'rdcatch/vbox.cpp'. + * Rewrote 'rdcatch/rdcatch.cpp' so as to allow display of an + arbitrarily large number of Deck Monitor widgets. +2006-02-14 Fred Gleason + * Modified the 'make rpm' target in 'Makefile.am' to properly + clean up the RPM build tree after the build. + * Modified the 'make rpm' target in 'Makefile.am' to move the + finished RPMs to the top source directory. +2006-02-15 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing + downloaded audio cuts to be saved with 'root:root' ownership. +2006-02-15 Fred Gleason + * Fixed a bug in 'rdlibrary/audio_cart.cpp' that was causing the + color highlighting for Evergreen status to fail to be applied + after exiting from the CutInfo/Record dialog [Mantis bug #133]. +2006-02-15 Fred Gleason + * Hid the 'Start Date' and 'End Date' control in the Edit Cart + dialog in 'rdlibrary/edit_cart.cpp'. + * Renamed the 'Year' control to 'Year Released' in the Edit Cart + dialog in 'rdlibrary/edit_cart.cpp'. +2006-02-15 Fred Gleason + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.66. +2006-02-17 Fred Gleason + * Added a 'make zip' target in 'Makefile.am'. +2006-03-01 Fred Gleason + * Fixed a layout error in the Edit Macro Event dialog in + 'rdcatch/edit_cartevent.cpp'. + * Added a '--offline-host-warnings' command-line switch to + RDCatch'. +2006-03-02 Fred Gleason + * Fixed a bug in 'ripcd/sasusi.cpp' that was causing the 'ST' rml + to fail with the SAS64000 switcher. +2006-03-02 Fred Gleason + * Applied a patch from Federico Grau that fixed + buffer overflows in 'cae/cae_jack.cpp'. +2006-03-05 Fred Gleason + * Stubbed out an 'Export' section in the Import Dialog in + 'rdlibrary/import_audio.cpp'. +2006-03-06 Fred Gleason + * Added 'RDSettings::pathName()' 'RDSettings::bytesPerSec()' and + 'RDSettings::defaultExtension()' methods in 'lib/rdsettings.cpp'. + * Finished implementing basic file export support in RDLibrary. +2006-03-07 Fred Gleason + * Applied a patch from Federico Grau to add stereo + mode controls in RDAdmin->ManageHosts->AudioPorts. + * Added 'AUDIO_PORTS.INPUT_[0-7]_MODE' fields to the database. + * Incremented the database version to 101. +2006-03-09 Fred Gleason + * Added 'CART.PUBLISHER' and 'CART.COMPOSER' fields to the + database. + * Incremented the database version to 102. + * Removed 'RDCart::isrc()' and 'RDCart::setIsrc()' methods from + 'lib/rdcart.cpp'. + * Added 'RDCart::publisher()', 'RDCart::setPublisher()', + 'RDCart::composer()' and 'RDCart::setComposer()' methods in + 'lib/rdcart.cpp'. + * Added 'Publisher' and 'Composer' controls to the EditCart dialog + in 'rdlibrary/edit_cart.cpp'. + * Added the 'CART.PUBLISHER' and 'CART.COMPOSER' fields to the + library filter search in 'lib/rdcart_search_text.cpp'. + * Added support for 'tmc' file types in 'scripts/rd_import_file'. + * Added id3lib to the list of libraries to link against. + * Added the '&' character to the list of those escaped by + 'RDEscapeString()' in 'lib/rdescape_string.cpp'. + * Fixed a bug in 'scripts/rd_import_file' that was causing imports + to fail for MPEG files with capitalized extensions. + * Implemented '--single-cart' and '--to-cart' options for + rdimport(1) in 'utils/rdimport.cpp'. + * Added code in 'scripts/rd_import_file' to suppress spurious + error messages from toolame(1). + * Implemented the '--delete-source' option for rdimport(1) in + 'utils/rdimport.cpp'. +2006-03-09 Fred Gleason + * Removed the 'taglib' dependency. +2006-03-10 Fred Gleason + * Applied a patch from Federico Grau that + greys-out inactive controls in RDAdmin's AudioPorts dialog. +2006-03-13 Fred Gleason + * Modified code in 'rdlibrary/import_audio.cpp' so as to use the + 'TMPDIR' environmental variable to determine temporary directory + to use for file imports/exports. + * Modified code in 'utils/rdimport.cpp' so as to use the + 'TMPDIR' environmental variable to determine temporary directory + to use for file imports/exports. + * Fixed a bug in 'importers/Makefile.am' that was causing the + build to break. + * Fixed bugs in 'rdcatchd/rdcatchd.cpp' that was causing + intermittent namespace collisions between various temporary files + used for upload and download events [Mantis bug #119]. + * Modified code in 'rdcatchd/rdcatchd.cpp' so as to use the + 'TMPDIR' environmental variable to determine temporary directory + to use for file imports/exports. +2006-03-13 Fred Gleason + * Added 'Autotrim' and 'Channels' controls to the Edit Download + dialog in 'rdcatch/edit_download.cpp'. + * Implemented support for per-event Channels, Autotrim Threshold + and Normalization Level parameters for Download Events in + 'rdcatchd/rdcatchd.cpp' [Mantis feature request #138]. +2006-03-13 Federico Grau + * Remove un-needed FIXME: comment. +2006-03-14 Fred Gleason + * Added 'Autotrim' and 'Channels' controls to the Edit Recording + dialog in 'rdcatch/edit_download.cpp'. + * Implemented support for per-event Channels, Autotrim Threshold + and Normalization Level parameters for Record Events in + 'rdcatchd/rdcatchd.cpp' [Mantis feature request #138]. +2006-03-14 Fred Gleason + * Fixed bugs in 'rdcatchd/rdcatchd.cpp' that were causing Upload + and Download events with filenames containing '(' or ')' + characters to fail [Mantis bug #137]. +2006-03-14 Fred Gleason + * Added additional sanity checking for the URL field in the Edit + Upload dialog in 'rdcatch/edit_upload.cpp'. + * Added additional sanity checking for the URL field in the Edit + Download dialog in 'rdcatch/edit_download.cpp'. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing imports + and exports to SMB shares that were nested one or more directories + deep to fail. +2006-03-14 Fred Gleason + * Added 'PUBLISHER', 'COMPOSER' and 'ISRC' fields to the + reconciliation table database schema. + * Incremented the database version to 103. +2006-03-15 Fred Gleason + * Added an 'ISRC' fields to the reconciliation table database schema. + * Added 'CART.USAGE_CODE', 'REPORTS.LINES_PER_PAGE', + 'REPORTS.STATION_TYPE' and 'REPORTS.STATION_FORMAT' fields to the + database. + * Incremented the database version to 104. + * Added a 'RDLogLine::UsageCode' enum in 'lib/rdlog_line.h'. + * Added 'RDLogLine::composer()', 'RDLogLine::setComposer()', + 'RDLogLine::publisher()', 'RDLogLine::setPublisher()', + 'RDLogLine::usageCode()' and 'RDLogLine::setUsageCode()' methods + in 'lib/rdlog_line.cpp'. + * Added support for 'PUBLISHER' and 'COMPOSER' fields in + 'RDLogEvent' in 'lib/rdlog_event.cpp'. + * Added 'RDCart::usageCode()' and 'RDCart::setUsageCode()' methods + in 'lib/rdcart.cpp'. + * Added a 'Usage' control to the Edit Cart dialog in + 'rdlibrary/edit_cart.cpp'. + * Fixed a bug in 'lib/rdcart.cpp' that was causing Year metadata + to fail to be applied by 'RDCart::setMetadata()'. + * Added 'ASCAP/BMI Music Log' and 'BMI EMR Electronic Music + Report' report types in 'lib/rdreport.h' and + 'rdadmin/edit_report.cpp'. + * Added 'RDReport::stationType()', 'RDReport::setStationType()', + 'RDReport::stationFormat()', 'RDReport::setStationFormat()', + 'RDReport::linesPerPage()' and 'RDReport::setLinePerPage()' + methods in 'lib/rdreport.cpp'. + * Removed the 'SelectReport' dialog in + 'rdlogmanager/select_report.cpp'. + * Added notes on setting up ASCAP/BMI Music Reports in + 'docs/reports.txt'. +2006-03-16 Fred Gleason + * Fixed a bug in 'utils/rdimport.cpp' that was causing the build + to break on SuSE 9.0. +2006-03-16 Fred Gleason + * Fixed bugs in 'lib/lib.pro', '1lib/rdcut.cpp' and + 'svc_rec_dialog.cpp' that were causing the build to break under + Windows. +2006-03-16 Fred Gleason + * Hid the 'Export Metadata' control in the Import/Export Dialog in + 'rdlibrary/import_audio.cpp'. +2006-03-16 Fred Gleason + * Updated the 'AUTHORS' file. + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Updated the 'README' file. + * Incremented the package version to 0.9.67. +2006-03-20 Fred Gleason + * Fixed a bug in 'lib/rdlog_event.cpp' that broke CHAIN-TO events. +2006-03-20 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.68. +2006-03-22 Fred Gleason + * Added an 'RDCut::pathName()' method in 'lib/rdcut.cpp'. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing audio + for Download events to be saved with 'root' ownership. +2006-03-24 Fred Gleason + * Fixed a bug in 'utils/rmlsend.cpp' that broke sending to remote + hosts. +2006-03-24 Fred Gleason + * Added an 'RDSoftKeys' utility in 'utils/rdsoftkeys.cpp'. +2006-03-24 Federico Grau + * Add more controls to be disabled depending on the audio card + selected. Correct help text (blank to silent). Correct card text + to fit in text box (rdadmin / audio ports). +2006-03-27 Fred Gleason + * Split out the programs in 'utils/' into thier own separate + directories. + * Fixed geometry bug under Windows in + 'utils/rdsoftkeys/rdsoftkeys.cpp'. + * Added RDSoftKey programming examples in 'conf/rd_conf-sample', + conf/rd.ini and 'conf/rd.conf-sample-complete. +2006-03-27 Fred Gleason + * Added syslog(3) calls in 'rdairplay/log_play.cpp', + 'lib/rdcart.cpp' and 'lib/rdlog_line.cpp'. +2006-03-28 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was placing the deck + into a disallowed state when 'RDPlayDeck::stop()' was called on an + already stopped deck. + * Implemented transition editing in 'rdlogedit/voice_tracker.cpp'. +2006-03-28 Federico Grau + * Add "mode" support for cae jack. This will allow for mode settings + (normal, swap, left only, right only) from rdadmin/hosts/audio + ports to be used with jack. +2006-03-30 Fred Gleason + * Added code to 'rdlogedit/edit_log.cpp' to display the Voice + Track icon for voice track log events. + * Added code to 'rdlogedit/voice_tracker.cpp' to display the Voice + Track icon for voice track log events. + * Implemented Track1 functionality in + 'rdlogedit/voice_tracker.cpp'. + * Added code to 'rdlogedit/voice_tracker.cpp' to constrain the + various track transitions to valid ranges. +2006-03-30 Fred Gleason + * Implemented sliding waveforms for two-track transitions in + 'rdlogedit/voice_tracker.cpp'. +2006-03-31 Fred Gleason + * Fixed bugs in 'cae/cae.cpp' that were causing duplicate 'SR' and + 'RD' reply messages to be generated. +2006-03-31 Fred Gleason + * Added a new RDCut constructor in 'lib/rdcut.cpp'. + * Added an 'RDCut::checkInRecording()' method in 'lib/rdcut.cpp'. + * Added code to 'rdlogedit/edit_log.cpp' to deleted track carts + when voice track events are deleted from a log. + * Added live record support to the Voice Tracker dialog in + 'rdlogedit/voice_tracker.cpp'. +2006-04-03 Fred Gleason + * Implemented live recording animation for the Voice Track dialog + in 'rdlogedit/voice_tracker.cpp'. +2006-04-03 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing + the incorrect audio to play when started past the Track2->Track3 + transition. + * Added an 'RDLogLine::clearTrackData()' method in + 'lib/rdlog)line.cpp'. + * Fixed a bug in 'lib/rdlog_line.cpp' that was failing to properly + initialize data for Track events. + * Implemented the 'Do Over' button in the Voice Track dialog in + 'rdlogedit/voice_tracker.cpp'. +2006-04-05 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was preventing + manually stopped events from stopping. +2006-04-05 Fred Gleason + * Added 'RDAIRPLAY.START_RML[0-5]' and 'RDAIRPLAY.STOP_RML[0-5]' + fields to the database. + * Incremented the database version to 105. + * Added 'RDAirPlayConf::startRml()', + 'RDAirPlayConf::setStartRml()', 'RDAirPlayConf::stopRml()' and + 'RDAirPlayConf::setStopRml()' methods in 'lib/rdairplay_conf.cpp'. + * Added debugging code in 'ripcd/vguest.cpp'. + * Added 'Start RML' and 'Stop RML' controls to the Edit RDAirPlay + in 'rdadmin/edit_rdairplay.cpp'. + * Added 'RDPlayDeck::channel()' and 'RDPlayDeck::setChannel()' + methods in 'lib/rdplay_deck.cpp'. + * Implemented Start RML and Stop RML commands in + 'rdairplay/log_play.cpp'. +2006-04-05 Federico Grau + * Corrected error message typo. +2006-04-05 Federico Grau + * Correct some minor logic flaws and typos in cae jack. +2006-04-06 Fred Gleason + * Added 'RDCae::playPortActive()' and 'RDCae::setPlayPortActive()' + methods in 'lib/rdcae.cpp'. + * Added an 'RDEventPlayer' class in 'lib/rdevent_player.cpp'. + * Implemented SoundPanel Start and Stop RML functionality in + 'lib/rdsound_panel.cpp'. +2006-04-06 Fred Gleason + * Implemented wildcard resolution for the Start RML string in + 'rdairplay/log_play.cpp'. + * Implemented wildcard resolution for the Start RML string in + 'lib/rdsound_panel.cpp'. +2006-04-06 Fred Gleason + * Implemented RDAirPlay Cue Start and Stop RML functionality and + wildcard resolution in 'rdairplay/edit_event.cpp'. +2006-04-06 Fred Gleason + * Added an 'output_state' member to the RDMeterBlock structure in + 'lib/rd.h'. + * Added a call to 'RDCae::setPlayPortActive()' in + 'rdlibrary/edit_audio.cpp' and 'rdlibrary/record_cut.cpp'. + * Added calls to 'RDCae::setPlayPortActive()' in + 'rdcatch/rdcatch.cpp'. +2006-04-06 Fred Gleason + * Added a call to 'RDCae::setPlayPortActive()' in + 'rdcatchd/rdcatchd.cpp'. +2006-04-06 Fred Gleason + * Added 'RDAIRPLAY.LOG_RML0', 'RDAIRPLAY.LOG_RML1' and + 'RDAIRPLAY.LOG_RML2' fields to the database. + * Incremented the database version to 106. + * Added 'RDAirPlayConf::logRml()' and 'RDAirPlayConf::setLogRml()' + methods in 'lib/rdairplay_conf.cpp'. + * Added 'RML' controls to the Edit Now&Next dialog in + 'rdadmin/edit_nownext.cpp'. +2006-04-06 Fred Gleason + * Fixed a bug in 'RDMacro::rollupArgs()' in 'lib/rdmacro.cpp'. +2006-04-06 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing MPEG + recordings to sporadically fail. +2006-04-07 Fred Gleason + * Fixed numerous sanity-check issues in the Voice Tracker dialog + in 'rdlogedit/voice_tracker.cpp'. + * Added support for Track Cart icons in RDAirPlay in + 'rdairplay/list_log.cpp' and 'rdairplay/loglinebox.cpp'. + * Added 'RDLOGEDIT.REC_START_CART' and 'RDLOGEDIT.REC_END_CART' + fields to the database. + * Implemented the database version to 107. + * Added 'RDLogeditConf::recStartCart()', + 'RDLogeditConf::setRecStartCart()', 'RDLogeditConf::recEndCart()' + and 'RDLogeditConf::setRectEndCart()' methods in + 'lib/rdlogedit_conf.cpp'. + * Added 'Record Start Cart' and 'Record End Cart' controls to the + RDAdmin->ManageHosts->RDLogEdit dialog in + 'rdadmin/edit_rdlogedit.cpp'. + * Implemented Start and Stop Carts for the Voice Tracker dialog in + 'rdlogedit/voice_tracker.cpp'. +2006-04-10 Fred Gleason + * Implemented the 'Hit Post' function in the Voice Tracker dialog + in 'rdlogedit/voice_tracker.cpp'. +2006-04-10 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing + the Track 3 audio start point to fail to update when moved if + Track 0 was not visible. +2006-04-10 Fred Gleason + * Added code to 'rdlogedit/voice_tracker.cpp' to enable the Voice + Tracker dialog to properly handle a Track as first item in a log. +2006-04-10 Fred Gleason + * Added code to 'rdlogedit/voice_tracker.cpp' to enable the Voice + Tracker dialog to properly handle a Track as last item in a log. +2006-04-11 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing + semi-random variations in the length of recorded tracks. +2006-04-12 Fred Gleason + * Added a 'CART.AVERAGE_SEGUE_LENGTH' field to the database. + * Added 'RDCart::averageSegueLength()' and + 'RDCart::setAverageSegueLength()' methods in 'lib/rdcart.cpp'. + * Incremented the database version to 108. + * Updated the 'RDCart::updateLength()' method to update the + average segue length. +2006-04-13 Fred Gleason + * Fixed a bug in 'rdairplay/list_log.cpp' that was causing logs + saved with 'Save As' to be assigned incorrect Service + associations [Mantis bug #144]. +2006-04-13 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a log + created in RDAirPlay to be saved with no name or Service + association. +2006-04-14 Fred Gleason + * Fixed a bug in 'lib/rdsound_panel.cpp' that broke + reconciliation data recording for SoundPanel playouts [Mantis bug + #139]. +2006-04-14 Fred Gleason + * Added a 'Length' column to RDAirPlay's Full Log widget in + 'rdairplay/list_log.cpp'. +2006-04-21 Fred Gleason + * Fixed a bug in 'cae/cae_alsa.cpp' that was causing segfaults when + running under SLAX. +2006-05-08 Fred Gleason + * Added an 'EVENTS.NESTED_EVENT' field to the database. + * Incremented the database version to 109. + * Added 'RDEvent::nestedEvent()' and 'RDEvent::setNestedEvent()' + methods in 'lib/rdevent.cpp'. + * Added an 'Import inline spots' control to the Edit Event dialog + in 'rdlogmanager/edit_event.cpp'. + * Added 'RDAIRPLAY.CARD[6-9]','RDAIRPLAY.PORT[6-9]', + 'RDAIRPLAY.START_RML[6-9]' and 'RDAIRPLAY.STOP_RML[6-9]' fields to + the database. + * Incremented the database version to 110. + * Added channel assignment controls for four new SoundPanel + outputs in 'rdadmin/edit_rdairplay.cpp'. +2006-05-08 Fred Gleason + * Fixed a bug in 'lib/rdcart.cpp' that was causing randomly + rotated cuts to fail to rotate properly [Mantis bug #140]. +2006-05-15 Fred Gleason + * Fixed a bug in 'cae/cae.cpp' that was causing recording to fail + under ALSA and JACK. +2006-05-15 Fred Gleason + * Added code in 'rdairplay/rdairplay.cpp' to enable the playout + port nunmbers displayed in SoundPanel to be consistent with those + displayed by the Main Log widget. +2006-05-15 Fred Gleason + * Added an 'rddbcheck' utility in 'utils/rddbcheck/'. +2006-05-15 Fred Gleason + * Added a 'Previous Track' button to the Voice Tracker dialog in + 'rdlogedit/voice_tracker.cpp'. +2006-05-16 Fred Gleason + * Changed the default focus policy in the Voice Tracker dialog to + provide a more efficient workflow. + * Changed the behavior of the Voice Tracker dialog so that + pressing 'Done' stops down the playout. +2006-05-16 Fred Gleason + * Added an 'ImportTrack' dialog in 'rdlogedit/import_track.cpp'. + * Reorganized the counters in the Voice Tracker dialog in + 'rdlogedit/voice_tracker.cpp' to more clearly separate the meaning + of the track count and time remaining. + * Increased the height of the Voice Tracker dialog in + 'rdlogedit/voice_tracker.cpp'. + * Added code to 'rdlogedit/voice_tracker.cpp' to keep the log list + automatically centered on the currently selected track. + * Added visual indicators for the Segue and Talk markers in the + Voice Tracker dialog in 'rdlogedit/voice_tracker.cpp'. +2006-05-16 Fred Gleason + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' and + 'rdlogedit/edit_log.cpp' that was causing logs created via the + 'Save As' button to fail to be added to the log list. + * Added code to 'rdlogedit/edit_log.cpp' to add a default + transition type of "Segue" and a default name of "Voice Track" to + new voice track markers. + * Added 'Insert Track' and 'Delete Track' button to the Voice + Tracker dialog in 'rdlogedit/voice_tracker.cpp'. +2006-05-22 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that was causing an extra + auto-fill cart to be inserted if an autofill event was scheduled + to cross midnight. +2006-05-22 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' in which pressing + the 'Next Track' button after reccording a voice track deleted the + newly recorded voice track cart. +2006-05-22 Fred Gleason + * Added an additional 'RDcut::exists()' method in 'lib/rdcut.cpp'. + * Added an 'RDRecording::NoCut' value to the + 'RDRecording::ExitCode' enum in 'lib/rdrecording.h'. + * Added logic to throw an error in RDCatch when an event's + Cart/Cut is missing from then Library [Mantis feature request + #145]. +2006-05-23 Fred Gleason + * Added a 'CUTS.VALIDITY' field to the database. + * Added a 'CART.VALIDITY' field to the database. + * Incremented the database version to 111. + * Implemented conditional Cart/Cut validity checking and + display [Mantis feature requests #84 and #134]. +2006-05-23 Federico Grau + * Fixed a bug in rdlibrary.cpp to not enable the delete button unless a + rivendell user has permissions to delete. +2006-05-26 Fred Gleason + * Fixed a bug in 'lib/rdpanel_button.cpp' that was causing a + lockup when loading a button containing text with no spaces. +2006-05-30 Federico Grau + * make changes to cae.cpp, re-added EchoArges for stop record. Without + it, stop record does not stop for jack. +2006-05-30 Federico Grau + * make changes to cae.cpp, rdcatchd.cpp, ripcd.cpp so log file are + created group writable (umask 0113). + * make changes to rdlibrary (cdripper.cpp disk_ripper.cpp + import_audio.cpp) so files are created group writable. +2006-05-31 Fred Gleason + * Fixed a bug in 'rdairplay/list_log.cpp' that was causing corrupt + log display after moving an event. +2006-05-31 Fred Gleason + * Increased the point size of the text font on the SoundPanel + buttons to 13 in 'lib/rdpanel_button.cpp'. +2006-05-31 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' where adding or + deleting a voice track would fail to update the 'Tracks Remaining' + counter. + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' where the waveform + display would fail to update after adding or deleting a voice + track. + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' where the 'Voice + Tracker' button would be greyed out for logs containing no voice + tracks. +2006-06-05 Fred Gleason + * Rearranged the button in the Voice Tracker dialog in + 'rdlogedit/voice_tracker.cpp'. + * Added colors to the tracker controls in + 'rdlogedit/voice_tracker.cpp'. +2006-06-07 Fred Gleason + * Fixed a bug in 'lib/rdwavepainter.cpp' that was causing + segfaults when trying to paint a waveform with no underlying audio + data. + * Implemented right-side voice tracker scrolling in + 'rdlogedit/voice_tracker.cpp'. + * Changed the name of the 'Tail Preroll' control in + RDAdmin->ManageHosts->RDLogedit to 'Audio Margin' in + 'rdadmin/edit_rdlogedit.cpp'. +2006-06-07 Fred Gleason + * Increased the font size of the Track Length counter in + 'rdlogedit/voice_tracker.cpp'. +2006-06-12 Fred Gleason + * Moved the EditAudio widget from 'rdlibrary/edit_audio.cpp' to + 'lib/rdedit_audio.cpp'. + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing a + segfault when an empty area in the event list was clicked. + * Added a right-click menu for the Voice Tracker dialog's waveform + display area in 'rdlogedit/voice_tracker.cpp'. + * Added an 'Edit Audio Markers' item to the right-click menu in + 'rdlogedit/voice_tracker.cpp'. +2006-06-13 Fred Gleason + * Fixed a typo in 'lib/rdairplay_conf.h' that was causing the + build to break under SuSE 10.1. +2006-06-13 Fred Gleason + * Added code to allow event transitions without Voice Track + markers to be edited in 'rdlogedit/voice_tracker.cpp'. +2006-06-13 Federico Grau + * cae.cpp, undid changes from -r1.84, I had not seen Fred's + corrections on -r1.82. The EchoArgs() is now driver specific + and not needed at the end of Stop Record. +2006-06-15 Fred Gleason + * Added an XDG file for RDLogin in 'xdg/rdlogin.desktop' and + 'rivendell.spec.in'. +2006-06-15 Fred Gleason + * Fixed a bug in 'cae/cae.cpp' that was causing Load Record + commands to fail when the underlying AudioRoot was mounted via + NFS. +2006-06-15 Fred Gleason + * Fixed a bug in 'utils/rddbcheck/rddbcheck.cpp' that was causing + valid voice tracks to be flagged as orphaned. +2006-06-15 Federico Grau + * cae.cpp, add code to ensure the release of sysv shared memory on + exit ofcaed. + - added another signal to catch (SIGHUP) + - set the shared memory to be destroyed upon signal reception in the + SigHandler() + - set the shared memory to be destroyed upon the QApp commitData() + method (called when an X session manager is exiting) + - set the shared memory to be destroyed upon return from the QApp + exec() method. +2006-06-16 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing + incorrect cursor positioning with cuts with start markers greater + than zero. +2006-06-16 Fred Gleason + * Fixed a bug in 'lib/rdlog_event.cpp' that caused a segfault when + the RDLogEvent::blockLength()' method was call with an + out-of-range line number. + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing + incorrect cursor positioning with cuts with start markers greater + than zero. +2006-06-17 Fred Gleason + * Changed the behavior of the Voice Tracker dialog in + 'rdlogedit/voice_tracker.cpp' so that any changes in segue + positions must be confirmed before being written to the log. +2006-06-17 Fred Gleason + * Implemented an 'Undo Segue Changes' item in the right-click + Voice Tracker menu in 'rdlogedit/voice_tracker.cpp'. +2006-06-17 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing incorrect + segue pointer values to be loaded. +2006-06-17 Fred Gleason + * Incremented the package version to 0.9.68kgu2. +2006-06-17 Fred Gleason + * Fixed a bug in 'rivendell.spec.in' that was causing RPM builds + to break. +2006-06-18 Fred Gleason + * Fixed bugs in 'lib/rdcart.cpp' and 'lib/rdlog_line.cpp' that + were causing the build to break under Windows. +2006-06-18 Fred Gleason + * Fixed bugs in 'lib/rdcut.cpp' that was causing the build to + break under Windows. +2006-06-18 Fred Gleason + * Fixed bugs in 'lib/rdmacro_event.cpp' that was causing the build to + break under Windows. +2006-06-18 Fred Gleason + * Added an 'RDLibraryConf::getSettings()' method in + 'lib/rdlibrary_conf.cpp'. + * Added an 'RDLogeditConf::getSettings()' method in + 'lib/rdlogedit_conf.cpp'. + * Added 'RDLOGEDIT.RIPPER_LEVEL' and 'RDLOGEDIT.TRIM_THRESHOLD' + fields to the database. + * Incremented the database version to 112. +2006-06-18 Fred Gleason + * Added 'Normalization Level' and 'AutoTrim Threshold' controls to + the RDLogEdit configuration dialog in + 'rdadmin/edit_rdlogedit.cpp'. + * Added 'RDLogeditConf::ripperLevel()' and + 'RDLogeditConf::trimThreshold()' methods in + 'lib/rdlogedit_conf.cpp. +2006-06-19 Fred Gleason + * Fixed a bug in 'lib/rdlog_line.cpp' that was causing invalid + values to be returned by the 'RDLogLine::segueStartPoint()' and + 'RDLogLine::SegueEndPoint()' methods. + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing + invalid track slide limits to be applied. + * Fixed bugs in 'rdlogedit/voice_tracker.cpp' that was causing + general flakiness when dealing with cuts with non-zero start + markers. +2006-06-19 Fred Gleason + * Added an 'RDLogLine::hasCustomTransition()' method in + 'lib/rdlog_line.cpp'. + * Added an 'RDLogEvent::clearCustomTransition()' method in + 'lib/rdlog_event.cpp'. + * Added code in 'rdlogedit/voice_tracker.cpp' to implement bolded + transition labels to indicate custom transitions. + * Added code in 'rdlogedit/edit_log.cpp' to implement bolded + transition labels to indicate custom transitions. + * Added code in 'rdairplay/loglinebox.cpp' to implement bolded + transition labels to indicate custom transitions. + * Added code in 'rdairplay/list_log.cpp' to implement bolded + transition labels to indicate custom transitions. +2006-06-20 Fred Gleason + * Modified 'lib/rdlog_event.cpp' and 'rdairplay/log_play.cpp' to + handle editing events with custom transitions properly. +2006-06-20 Fred Gleason + * Fixed a bug in 'lib/rdlog_event.cpp' that was causing a sefault + when recording a voice track at the beginning of a log. + * Implemented proper behavior for PLAY and STOP transition in the + VoiceTracker dialog in 'rdlogedit/voice_tracker.cpp'. +2006-06-20 Fred Gleason + * Added a 'LogListView' widget in 'rdlogedit/log_listview.cpp'. + * Added a right-button menu to the log list for the Voice Tracker + dialog in 'rdlogedit/voice_tracker.cpp'. +2006-06-20 Fred Gleason + * Added code in 'rdlogedit/voice_tracker.cpp' to return the + waveform display to the start of the transition after playout. +2006-06-20 Fred Gleason + * Incremented the package version to 0.9.68kgu3. +2006-06-20 Fred Gleason + * Changed the legend of the 'Done' button in the Voice Tracker + dialog to 'Save' in 'rdlogedit/voice_tracker.cpp'. +2006-06-20 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing a + save confirmation dialog to raise after auditioning a modified + cut. +2006-06-20 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' where a changed + transition was not being saved if no other edits were made. +2006-06-21 Fred Gleason + * Altered the Voice Tracker dialog so as to display a gray + background on tracks with PLAY or STOP transitions. +2006-06-21 Fred Gleason + * Increased MAX_GPIO_PINS to 192 in 'lib/rd.h'. +2006-06-21 Fred Gleason + * Added 'SERVICES.MUS_BREAK_STRING' and + 'SERVICES.MUS_TRACK_STRING' fields to the database. + * Changed the default value of 'VGUEST_RESOURCES.SURFACE_NUM' to + '0' in the database. + * Incremented the database version to 113. + * Fixed a bug in 'lib/rdsvc.cpp' that was causing importing logs + for services whose name contained '-' characters to fail. + * Added 'Insert Traffic Break String' and 'Insert Voice Track + String' controls in 'rdadmin/edit_svc.cpp'. + * Added code in 'lib/rdsvc.cpp' and 'lib/rdlog_event.cpp' to + generate embedded track markers from music log imports. +2006-06-21 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was failing + to disable the 'Previous Track' button when audio playout was + active. +2006-06-21 Fred Gleason + * Incremented the package version to '0.9.68kgu4'. +2006-06-22 Fred Gleason + * Added 'LOGS.MUSIC_LINKS', 'LOGS.MUSIC_LINKED', + 'LOGS.TRAFFIC_LINKS' and 'LOGS.TRAFFIC_LINKED' fields to the + database. + * Added 'LINK_EVENT_NAME', 'LINK_START_TIME', 'LINK_LENGTH' and + 'LINK_ID' fields to the log table database schema. +2006-06-22 Fred Gleason + * Incremented the database version to 114. +2006-06-22 Fred Gleason + * Incremented the package version to 0.9.68kgu5. +2006-06-23 Fred Gleason + * Added 'RDLog::isReady()', 'RDLog::linkState()' + 'RDLog::setLinkState()', 'RDLog::linkQuantity()' and + 'RDLog::setLinkQuantity()' methods in 'lib/rdlog.cpp'. + * Added 'RDLog::LinkState' and 'RDLog::Source' enums in + 'lib/rdlog.h'. + * Added 'RDLogLine::linkEventName()', + 'RDLogLine::setLinkEventName()', 'RDLogLine::linkStartTime()', + 'RDLogLine::setLinkStartTime()', 'RDLogLine::linkLength()', + 'RDLogLine::setLinkLength()', 'RDLogLine::linkID()' and + 'RDLogLine::setLinkId()' methods in 'lib/rdlog_line.cpp'. + * Updated 'lib/rdlog_event.cpp' to properly load/save link + metadata. + * Added icons in 'icons/greencheckmark.xpm', + 'icons/redcheckmark.xpm', 'icons/redx.xpm', icons/blueball.xpm', + 'icons/whiteball.xpm', icons/greenball.xpm', 'icons/redball.xpm', + 'icons/traffic.xpm', 'icons/music.xpm', 'icons/mic16.xpm' and + 'icons/notemarker.xpm'. + * Modified 'rdlogedit/edit_log.cpp to display the revised icon + set. + * Modified 'rdlogedit/voice_tracker.cpp to display the revised icon + set. + * Modified 'rdairplay/list_log.cpp to display the revised icon + set. + * Modified 'rdairplay/loglinebox.cpp to display the revised icon + set. + * Modified 'rdairplay/log_play.cpp' to properly execute music and + traffic link events. + * Modified 'rdlogmanager/import_listview.cpp to display the + revised icon set. +2006-06-23 Fred Gleason + * Added status indicators to the GenerateLog dialog in + 'rdlogmanager/generate_log.cpp'. +2006-06-23 Fred Gleason + * Incremented the package version to 0.9.68kgu6. +2006-06-25 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that was generating link + events with incorrect lengths. +2006-06-25 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' where the + transition field of the event list was not updated after clearing + a custom transition. +2006-06-25 Fred Gleason + * Added code to 'lib/rdcae.cpp' to emit a + 'RDCae::isConnected(false) signal upon failure to login to + caed(8). +2006-06-26 Fred Gleason + * Made RDLogEdit(1) resizeable. +2006-06-26 Fred Gleason + * Added a 'ListListviewItem' class in + 'rdlogedit/list_listviewitem.cpp'. + * Added a status icon to the 'TRACKS' column in + 'rdlogedit/rdlogedit.cpp'. +2006-06-27 Federico Grau + * rdcatchd.cpp rdcatchd.h; move LogLine() from MainObject method to + function in the file. + * rdcatchd.cpp; add logging of process exit +2006-06-29 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that broke log imports. +2006-06-30 Fred Gleason + * Moved the ImportAudio dialog in 'rdlibrary/import_audio.cpp' to + RDImportAudio in 'lib/rdimport_audio.cpp'. +2006-07-03 Fred Gleason + * Fixed a bug in 'rdlogedit/list_listviewitem.cpp' that was + causing the incorrect background color to be used for the 'TRACKS' + column. +2006-07-03 Fred Gleason + * Fixed a bug in 'lib/rdimport_audio.cpp' that caused a segfault + when invoked with a NULL RWaveData argument. + * Changed 'RDImportAudio::exec()' to return a '-1' when the + 'Cancel' button is clicked instead of '0'. + * Implemented direct audio importation in the Voice Tracker + dialog. +2006-07-03 Fred Gleason + * Fixed a bug in 'lib'rdevent_line.cpp' that caused corrupt log + linking [Mantis bug #149]. +2006-07-05 Fred Gleason + * Added 'START_HOUR' and 'START_SECS' fields to the import table + schema used by 'RDSvc::import()' in 'lib/rdsvc.cpp'. + * Removed the 'START_TIME' field from the import table schema used + by 'RDSvc::import()' in 'lib/rdsvc.cpp'. + * Modified the Test Import dialog in 'rdadmin/test_import.cpp' to + use the new import table schema. + * Added an 'RDSvc::timeString()' method in 'lib/rdsvc.cpp'. + * Rewrote 'RDEventLine::linkLog()' to use the new import table + schema and enable overscheduled events to be linked properly + [Mantis bug #150]. +2006-07-05 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that was causing + Post-Event carts to fail to be inserted into generated logs + [Mantis bug #151]. +2006-07-05 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that was causing traffic + import links to fail to be inserted when in-lined into a music + import [Mantis bug #152]. +2006-07-05 Fred Gleason + * Fixed a bug in 'rdlogedit/rdlogedit.pro' that was causing the + build to break on Windows. + * Incremented the package version to 0.9.68kgu7. +2006-07-06 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that broke log linking. +2006-07-06 Fred Gleason + * Added an 'RDCut::AudioEnd' enum in 'lib/rdcut.h'. + * Added 'HPI_START' and 'GPIO_START' variables to 'rivendell-sys'. + * Added a '%config' tag to the '/etc/sysconfig/rivendell' file in + 'rivendell.spec.in'. +2006-07-06 Fred Gleason + * Incremented the package version to 0.9.68kgu8. +2006-07-06 Fred Gleason + * Fixed a bug in 'lib/rdlog_event.cpp' that was causing import + links to fail to get the correct grace time when loaded. +2006-07-06 Fred Gleason + * Incremented the package version to 0.9.68kgu9. +2006-07-07 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was making it + impossible to stop playout if the Play button was pressed more + than once. +2006-07-07 Fred Gleason + * Fixed a bug in 'rdairplay/list_log.cpp' that was causing events + showing a [NO AUDIO AVAILABLE] error to fail to receive a red + highlight if not in the next seven events to play. +2006-07-07 Fred Gleason + * Restored Unused Events and AutoFill Error reports for log + linking in RDLogManager in 'lib/rdevent_line.cpp' and + 'lib/rdsvc.cpp'. +2006-07-07 Fred Gleason + * Incremented the package version to 0.9.68kgu10. +2006-07-07 Fred Gleason + * Fixed a bug in 'lib/rdlog_line.cpp' that was causing custom + segue transitions from cuts having no segue markers set in the + library to be truncated. + * Set the Segue Gain for lead tracks in voice tracker transitions + to '0' in 'rdlogedit/voice_tracker.cpp'. +2006-07-07 Fred Gleason + * Incremented the package version to 0.9.68kgu11. +2006-07-07 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that caused + waveform positioning errors when a waveform was dragged past the + end of the first track and auditioned. +2006-07-07 Fred Gleason + * Incremented the package version to 0.9.68kgu12. +2006-07-09 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that caused corrupt + transition data to ben generated when one of the adjacent tracks + contained an empty audio cart. +2006-07-09 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing + the final event event in a transition to be upcut slightly when + being auditioned. +2006-07-09 Fred Gleason + * Fixed a bug in 'rdlogmanager/generate_log.cpp' that was allowing + a lot import to be attempted even when the necessary data was not + available. +2006-07-09 Fred Gleason + * Modified 'rdlibrary/rdlibrary.cpp' so that a user with no + enabled groups causes the 'Add', 'Edit' 'Delete' and 'Rip CD' + buttons to gray out. +2006-07-09 Fred Gleason + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that caused cart + entries to have the incorrect default background color. + * Fixed a bug in 'rdcatch/rdcatch.cpp' that caused event + entries to have the incorrect default background color. +2006-07-09 Fred Gleason + * Added a 'Service' control to the Add Log dialog in + 'lib/rdadd_log.cpp'. +2006-07-09 Fred Gleason + * Added an 'EST TIME' column to the Full Log widget in RDAirPlay + in 'rdairplay/list_log.cpp'. + * Changed the function of the 'TIME' column in the Full Log widget + in RDAirPlay to display only scheduled times. +2006-07-09 Fred Gleason + * Incremented package version to 0.9.68kgu13. +2006-07-10 Fred Gleason + * Changed the 'Import inline spots with the' control in the Edit + Event dialog to 'Import inline traffic with the' in + 'rdlogmanager/edit_event.cpp'. +2006-07-10 Fred Gleason + * Added an 'Inline Traffic' tag to the Properties column in the + List Events dialog in 'rdlogmanager/edit_event.cpp'. +2006-07-10 Fred Gleason + * Fixed a bug in 'rdadmin/edit_report.cpp' where the 'Import + Source: Traffic' checkbox was misplaced. +2006-07-10 Fred Gleason + * Changed the width of the 'LABEL' field in the log schema to + '64'. + * Incremented the database version to 115. +2006-07-10 Fred Gleason + * Added code to 'rdlogedit/voice_tracker.cpp' to disable the + ability to generate voice tracks when no Track Group was set for + the owning service. +2006-07-10 Fred Gleason + * Fixed a race in 'rdlogedit/voice_tracker.cpp' that was allowing + two different voice tracks to receive the same cart number. +2006-07-10 Fred Gleason + * Fixed a bug in 'rdairplay/list_log.cpp' that was preventing a + log from being saved to it's original name. +2006-07-10 Fred Gleason + * Fixed bugs in 'lib/rdlog_lin.cpp' that were causing crashes in + RDAirPlay when executing voicetracked events adjacent to invalid + carts. +2006-07-10 Fred Gleason + * Fixed a bug in 'rdairplay/list_log.cpp' that was causing invalid + carts to not receive the proper error color. +2006-07-10 Fred Gleason + * Incremented the package version to 0.9.68kgu14. +2006-07-11 Fred Gleason + * Fixed a bug in 'lib/rdlog.cpp' that was causing the + RDLog::removeTracks()' method to fail to remove tracks. +2006-07-11 Fred Gleason + * Fixed multiple bugs that were affecting proper handling of log + events consisting of missing audio carts or audio carts with no + valid cut in 'rdairplay/log_play.cpp', 'rdairplay/list_log.cpp' + and 'rdairplay/button_log.cpp' [Mantis bug #153]. +2006-07-11 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' that was allowing a recording to + be checked in without an origin datetime or name. +2006-07-11 Fred Gleason + * Incremented the package version to 0.9.68kgu15. +2006-07-12 Fred Gleason + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was truncating log + name display. +2006-07-13 Fred Gleason + * Added code to 'cae/cae.cpp' to purge stale stream entries from + the handle table upon detection of a duplicate stream assignment. +2006-07-17 Fred Gleason + * Added a 'LINK_EMBEDDED' field to the log table database schema. + * Added a 'SERVICE_TRACK_GROUP' field to the database. + * Incremented the database version to 116. + * Added 'RDLogLine::linkEmbedded()' and + 'RDLogLine::setLinkEmbedded()' methods in 'lib/rdlog_line.cpp'. +2006-07-17 Fred Gleason + * Fixed a typo in 'lib/rdsvc.cpp' that caused the build to break. +2006-07-17 Fred Gleason + * Added logic in 'lib/rdevent_line.cpp' and 'lib/rdsvc.cpp' to + properly unlink embedded log events. +2006-07-17 Fred Gleason + * Added 'ORIGIN_USER' and 'ORIGIN_DATETIME' fields to the log + table database schema. + * Added 'RDLogLine::originUser()', 'RDLogLine::setOriginUser()', + 'RDLogLine::originDateTime() and 'RDLogLine::setOriginDateTime()' + methods in 'lib/rdlog_line.cpp'. + * Incremented the database version to 117. + * Implemented display of the originating user and date/time for + voice tracks in RDLogEdit and RDAirPlay in + 'rdlogedit/edit_log.cpp', 'rdlogedit/voice_tracker.cpp', + 'rdairplay/log_play.cpp' and 'rdairplay/loglinebox.cpp'. +2006-07-17 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing + play to fail when the top track was slid to the right beyond the + start of the audio. + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' where cursor + positioning on the last track was incorrect if the audio had a + non-zero Start marker value. +2006-07-17 Fred Gleason + * Fixed bugs in 'lib/rdsvc.cpp' that was causing creation and + deletion of a service whose name contained hyphens to fail. + * Fixed a bug in 'lib/rdcreate_log.cpp' that was causing creation + and deletion of a service whose name contained hyphens to fail. + * Fixed a bug in 'rdairplay/log_traffic.cpp' that was causing + logging of ELR data to fail for services containing a hyphen in + their name. + * Fixed bugs in 'rdlogmanager/svc_rec.cpp' and + 'rdlogmanager/list_svcs.cpp' that was causing generation of + reports for services whose name contained a hyphen to fail. + * Incremented the package version to 0.9.68kgu16. +2006-07-18 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that caused log generation to + break. +2006-07-18 Fred Gleason + * Incremented the package version to 0.9.68kgu17. +2006-07-18 Fred Gleason + * Moved color definitions for RDLibrary from 'rdlibrary/colors.h' + to 'lib/rd.h'. + * Removed 'rdlibrary/colors.h'. + * Changed the Edit Log dialog in 'rdlogedit/edit_log.cpp' to use + magenta highlighting to indicate carts with an invalid service. + * Changed to warning dialog in 'rdlogedit/edit_log.cpp' to allow + logs containing carts with an invalid service to be saved. + * Added 'RDLogLine::validity()' and 'RDLogLine::setValidity()' + methods in 'lib/rdlog_line.cpp'. + * Updated code in 'lib/rdcart.cpp' to more reliably predict cart + availability. +2006-07-18 Federico Grau + * updated ChangeLog with past CVS changes: + 2006-03-13 + 2006-03-24 + 2006-03-28 + 2006-04-05 + 2006-04-05 + 2006-05-23 + 2006-05-30 + 2006-05-30 + 2006-06-13 + 2006-06-15 + 2006-06-27 +2006-07-18 Federico Grau + * rdcatchd.cpp; remove code to "relinquish" root permissions + (not working and not used). +2006-07-19 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that was causing custom + transition data to be removed from events when linking import + events. +2006-07-19 Fred Gleason + * Added an 'RDEventLine::InsertFirst' enum in 'lib/rdevent_line.h'. + * Added an 'INSERT_FIRST' field to the import table schema in + 'lib/rdsvc.cpp'. + * Fixed a bug in 'rdadmin/test_import.cpp' that was causing the + order of embedded voice tracks and spot breaks to be transposed. + * Fixed a bug in 'lib/rdevent_line.cpp' that was causing the order + of embedded voice tracks and spot breaks to be transposed. +2006-07-19 Fred Gleason + * Incremented the packages version to 0.9.68kgu18. +2006-07-19 Federico Grau + * cae/cae.cpp cae/cae_jack.cpp rdcatch/rdcatch.cpp + rdcatchd/rdcatchd.cpp + ripcd/ripcd.cpp; increased logging and checks of error conditions. + * Makefile.am lib/Makefile.am rdadmin/Makefile.am rdairplay/Makefile.am + rdcatch/Makefile.am rdlibrary/Makefile.am rdlogedit/Makefile.am + rdlogin/Makefile.am rdlogmanager/Makefile.am rdpanel/Makefile.am; + modified + to use DESTDIR. Change INCLUDES to use $top_srcdir instead of ".." . + * pam_rd/ ; add new pam_rd directory with makefile, module, and + corresponding documentation in docs/. Also hooked into main + Makefile.am +2006-07-19 Fred Gleason + * Disabled build of the 'pam_rd/' directory in 'configure.in' and + 'Makefile.am'. +2006-07-19 Federico Grau + * cae/cae_jack.cpp; revert back to jack_client_new() function call to + maintain library compatability with jack 0.80.0 . Maybe at a + later point we can add this feature. +2006-07-20 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that broke import of + external start times for traffic events. +2006-07-20 11:20 EDT Federico Grau + * utils/rdgpimon/Makefile.am utils/rmlsend/Makefile.am; modified to use + DESTDIR. +2006-07-20 Fred Gleason + * Added 'SERVICES.TFC_LABEL_CART', 'SERVICES.TFC_TRACK_CART', + 'SERVICES.MUS_LABEL_CART', 'SERVICES.MUS_TRACK_CART', + 'SERVICES.TFC_TITLE_OFFSET', 'SERVICES.TFC_TITLE_LENGTH', + 'SERVICES.MUS_TITLE_OFFSET' and 'SERVICES.MUS_TITLE_LENGTH' fields + to the database. + * Incremented the database version to 118. + * Added 'RDSvc::labelCart()', 'RDSvc::setLabelCart()', + 'RDSvc::trackCart()' and 'RDSvc::setTrackCart()' methods in + 'lib/rdsvc.cpp'. + * Added 'Note Cart String', 'Track Cart String' and 'Title' + controls in the Edit Service dialog in 'rdadmin/edit_svc.cpp'. +2006-07-20 Fred Gleason + * Incremented the package version to 0.9.68kgu19. +2006-07-21 Fred Gleason + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. +2006-07-21 Fred Gleason + * Incremented the package version to 0.9.69. +2006-07-21 12:25 EDT Federico Grau + * configure.in Makefile.am; add autoconf hooks for pam_rd +2006-07-24 Fred Gleason + * Fixed bugs in 'lib/rdsvc.cpp' and 'lib/rdevent_line.cpp' that + were causing items in the PreImport list of Events to be dropped + when linking a traffic log. +2006-07-24 Fred Gleason + * Incremented the package version to 0.9.69kgu1. +2006-07-25 Fred Gleason + * Fixed a bug in 'scripts/rd_export_file' that broke file exports + where the source file was MPEG encoded. +2006-07-25 Fred Gleason + * Fixed a bug in 'lib/rdimport_audio.cpp' that was causing + non-default settings to be applied to the export format type. +2006-07-25 Fred Gleason + * Added a message box to warn when deleting a cut that is + currently in use by one or more RDCatch events in + 'rdlibrary/audio_cart.cpp'. + * Added a message box to warn when deleting a cart that is + currently in use by one or more RDCatch events in + 'rdlibrary/rdlibrary.cpp'. +2006-07-25 14:08 EDT Federico Grau + * configure.in Makefile.am; use automake conditionals for the + pam_rd hook. +2006-07-26 Fred Gleason + * Added a confirmation dialog before pasting audio into a cut that + already contains audio in 'rdlibrary/audio_cart.cpp' [Mantis + feature request #156]. +2006-07-26 Fred Gleason + * Added 'SERVICES.TFC_HOURS_OFFSET', 'SERVICES.TFC_HOURS_LENGTH', + 'SERVICES.TFC_MINUTES_OFFSET', 'SERVICES.TFC_MINUTES_LENGTH', + 'SERVICES.TFC_SECONDS_OFFSET', 'SERVICES.TFC_SECONDS_LENGTH', + 'SERVICES.MUS_HOURS_OFFSET', 'SERVICES.MUS_HOURS_LENGTH', + 'SERVICES.MUS_MINUTES_OFFSET', 'SERVICES.MUS_MINUTES_LENGTH', + 'SERVICES.MUS_SECONDS_OFFSET' and 'SERVICES.TFC_SECONDS_LENGTH' + fields to the database. + * Retired 'SERVICES.TFC_START_OFFSET', 'SERVICES.TFC_START_LENGTH', + 'SERVICES.MUS_START_OFFSET' and 'SERVICES.MUS_START_LENGTH' fields + in the database. + * Updated the database version to 119. + * Added 'RDSvc::StartHours', 'RDSvc::StartMinutes' and + 'RDSvc::StartSeconds' to 'RDSvc::ImportField' in 'lib/rdsvc.h'. + * Removed 'RDSvc::StartTime' from 'RDSvc::ImportField in + 'lib/rdsvc.h'. + * Added new controls for the Hours, Minutes and Seconds import + parser fields in 'rdadmin/edit_svc.cpp'. + * Modified 'RDSvc::import()' to work with the new parser layout. +2006-07-26 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that was causing missing cart + reports to fail to be generated during log linking. + * Fixed a bug in 'lib/rdsvc.cpp' that was causing missing cart + reports to fail to be displayed after linking the traffic log. +2006-07-26 Fred Gleason + * Incremented the package version to 0.9.69kgu2. +2006-07-27 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing + re-done voice tracks to stop prematurely when being auditioned. +2006-07-28 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing stale + custom transition data to be applied when making a transition + across an already-played event. +2006-07-28 Fred Gleason + * Modfied the import logic in 'RDSvc::import()' so as to detect + the voicetrack string even if buried within a larger string in the + import log. +2006-07-31 Fred Gleason + * Fixed a bug in 'lib/rdimport_audio.cpp' that was causing audio + imports to kill current playouts of the previous audio data. +2006-07-31 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatched.cpp' that was causing audio + downloads to kill current playouts of the previous audio data. +2006-07-31 Fred Gleason + * Fixed a bug in 'cae/cae.cpp' that was causing audio + recordings to kill current playouts of the previous audio data. +2006-07-31 Fred Gleason + * Optimized code in 'rdlibrary/record_cut.cpp' to deal properly + with playing back audio in RDAirPlay while recording is still in + progress. +2006-07-31 Fred Gleason + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that was causing audio + imports to kill current playouts of the previous audio data. +2006-08-01 Federico Grau + * rdairplay/rdairplay.cpp rdcatchd/rdcatchd.cpp ripcd/ripcd.cpp; create + files group writable, using chmod(). +2006-08-01 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing ftp + download to fail if the URL contained a space. +2006-08-01 Fred Gleason + * Fixed a bug in 'rdcatch/edit_recording.cpp' that was causing the + Group List to be empty when attempting to create a new destination + cart. +2006-08-02 Fred Gleason + * Fixed a bug in 'lib/rdcart.cpp' that was causing + RDCart::selectCart()' to return an invalid (zero-length) cart even + if an alternative valid one was available. +2006-08-02 Fred Gleason + * Fixed a bug in 'lib/rdcart.cpp' that was writing invalid + start/end cart datetime values. +2006-08-02 Fred Gleason + * Modified 'lib/rdimport_audio.cpp', 'rdcatchd.rdcatchd.cpp', + 'scripts/rd_import_file' and 'utils/rdimport/rdimport.cpp' to + properly handle play-while-importing. +2006-08-03 Fred Gleason + * Added an 'RDPlayDeck::clear()' method in 'lib/rdplay_deck.cpp'. + * Modified 'lib/rdplay_deck.cpp' and 'rdairplay/log_play.cpp' to + properly handle paused events [Mantis bug #158]. +2006-08-03 Fred Gleason + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Updated the 'AUTHORS' file. + * Incremented the package version to 0.9.70. +2006-08-03 Federico Grau + * cae.cpp, rdcatchd.cpp, ripcd.cpp; add virtual function + saveState() to give the session manager a hint not to restart this + daemon automatically (daemon start order is important and session + managers are not aware of this). +2006-08-04 Fred Gleason + * Moved the 'ListLog::ActionMode' enum in 'rdairplay/list_log.h' + to 'RDAirPlayConf::ActionMode in 'lib/rdairplay_conf.h'. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing + incorrect transition types to be applied for inserted log events. + * Implemented CopyFrom capability from the SoundPanel widget in + RDAirPlay. +2006-08-07 13:05 EDT Federico Grau + * docs/Makefile.am; sorted the EXTRA_DIST documentation list of files, + added pam_rd.txt to the list of documentation. +2006-08-07 13:10 EDT Federico Grau + * make_slack.in, rivendell.spec.in; added pam_rd.txt to + documentation list +2006-08-09 Fred Gleason + * Modified the 'RDLogEvent::load()' method in + 'lib/rdlog_event.cpp' to include the 'FADEUP_POINT' and + 'FADEDOWN_POINT' fields and disregard the 'SEGUE_GAIN' field + in determining custom transition status. + * Changed the default pointer source for + 'RDLogLine::startPoint()', 'RDLogLine::endPoint()' + 'RDLogLine::segueStartPoint()' and 'RDLogLine::segueEndPoint()' + methods in 'lib/rdlog_line.cpp' 'from RDLogLine::CartPointer' to + 'RDLogLine::AutoPointer'. + * Fixed a bug in 'lib/rdplay_deck.cpp' that was failing to refresh + transition parameters in 'RDPlayDeck::setCart()'. + * Added code in 'lib/rdplay_deck.cpp' to allow FadeUp and FadeDown + gain changes to be interpolated when the deck is started in the + middle of a fade. + * Implemented 'rubber-banding' control in the VoiceTracker dialog + in 'rdlogedit/voice_tracker.cpp'. +2006-08-10 12:35 EDT Federico Grau + * pam_rd.cpp; Change behaviour to set the "default user" instead of the + active user. Cleaned up some comments. +2006-08-14 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.71. +2006-08-17 Fred Gleason + * Changed the 'RDLogLine::segueStartPoint()' method so that it + does not return segue point values <= 0. +2006-08-17 Fred Gleason + * Fixed a bug in 'lib/rdpanel_button.cpp' that was causing buttons + to be blank if a word was longer than the available width of the + button. +2006-08-17 Fred Gleason + * Updated the package version to 0.9.71srs0. +2006-08-18 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that was causing slop + factors to be applied twice when linking import events. + * Fixed a bug in 'lib/rdevent_line.cpp' that was causing link + events to slop over into the previous hour if the start slop + factor was greater than the seconds offset. +2006-08-19 Fred Gleason + * Updated the 'NEWS' file. + * Updated the package version to 0.9.72. +2006-08-19 Fred Gleason + * Fixed a bug in 'lib/rdlog_line.cpp' that was causing invalid + values Segue and Talk pointer values to be loaded for cuts with + negative pointer values when timescaling was in effect. +2006-08-19 Fred Gleason + * Updated the package version to 0.9.72srs0. +2006-08-28 Fred Gleason + * Added instrumentation code in 'rdairplay/log_play.cpp' to + determine source of CAE 'Play Stop' commands. + * Incremented the package version to 0.9.72srs1. +2006-08-29 Fred Gleason + * Added a backup utility in 'utils/rdbackup/rdbackup.cpp'. +2006-08-30 Fred Gleason + * Added an [RDBackup] section in rd.conf(5). + * Added an 'RDConfig::destination()' method in 'lib/rdconfig.cpp'. + * Finished RDBackup utility in 'utils/rdbackup/rdbackup.cpp'. +2006-08-30 Fred Gleason + * Incremented the package version to 0.9.72srs2. +2006-09-01 Fred Gleason + * Fixed a race in 'lib/rdplay_deck.cpp' that was causing random + stopdowns of logs. +2006-09-01 Fred Gleason + * Incremented the package version to 0.9.72srs3. +2006-09-01 Fred Gleason + * Fixed a bug in 'lib/rdescape_string.cpp' that was improperly + escaping strings containing an apostrophe. +2006-09-01 Fred Gleason + * Changed the talk time display in RDAirPlay's cart label to use a + bold font. +2006-09-01 Fred Gleason + * Added a 'GROUPS.COLOR' field to the database. + * Added an 'RDLOGEDIT.DEFAULT_TRANS_TYPE' field to the database. + Added 'RDGroup::color()' and 'RDGroup::setColor()' methods in + 'lib/rdgroup.cpp'. + * Added 'RDLogeditConf::defaultTransType()' and + 'RDLogeditConf::setDefaultTransType()' methods in + 'lib/rdlogedit_conf.cpp'. + * Incremented the database version to 120. + * Added a 'Color' button to the Edit Group dialog in + 'rdadmin/edit_group.cpp'. + * Fixed a bug in 'lib/rdlistviewitem.cpp' that was causing custom + colored text to be assigned incorrect font sizes. + * Added code to show the group color in the 'Name' column of the + List Groups dialog in 'rdadmin/list_groups.cpp'. + * Added code to show the group color in the 'Group' column of the + cart list in RDLibrary in 'rdlibrary/rdlibrary.cpp'. + * Added a 'Group' column in the Cart Picker Dialog in + 'lib/rdcart_dialog.cpp'. + * Added a 'Group' column in the Cut Picker Dialog in + 'lib/rdcut_dialog.cpp'. + * Added a 'Group' column to the Full Log widget in RDAirPlay in + 'rdairplay/list_log.cpp'. + * Implemented default transition type in the Edit Log dialog in + 'rdlogedit/edit_log.cpp'. + * Added 'RDLogLine::groupColor()' and 'RDLogLine::setGroupColor()' + methods in 'lib/rdlog_line.cpp'. + * Implemented color group labels in cart labels in + 'rdairplay/loglinebox.cpp'. + * Implemented color group labels in the Edit Log dialog in + 'rdlogedit/edit_log.cpp'. +2006-09-02 Fred Gleason + * Optimized the 'RDLogEvent::load()' method to handle group colors + more efficiently. + * Fixed bugs in 'rdadmin/add_station.cpp' that was causing certain + host config parameters to fail to be copied from the exemplar when + creating a new host entry. +2006-09-02 Fred Gleason + * Fixed bugs in 'lib/rdsvc.cpp' that was causing certain + service config parameters to fail to be copied from the exemplar when + creating a new host entry. +2006-09-02 Fred Gleason + * Modified the cut list in 'rdlibrary/audio_cart.cpp' so as to not + select the first cut by default. +2006-09-03 Fred Gleason + * Added a backup script in 'scripts/rd_backup'. + * Removed the RDBackup utility in 'utils/rdbackup/rdbackup.cpp'. +2006-09-03 Fred Gleason + * Modified 'RDSvc::import()' in 'lib/rdsvc.cpp' so as to associate + embedded break and voicetracks with the following rather than + preceding event. + * Modified the Test Import dialog in 'rdadmin/test_import.cpp' so + as to properly depict the new embedded event logic. + * Modified 'RDEventLine::linkLog()' in 'lib/rdevent_line.cpp' so + as to properly insert embedded events. +2006-09-03 Fred Gleason + * Fixed bugs in 'lib/lib.pro', 'lib/rdlogedit_conf.h' and + 'lib/rdlogedit_conf.cpp' that caused the build to break under + Windows. + * Incremented the package version to 0.9.72srs4. +2006-09-03 Fred Gleason + * Fixed a bug in 'lib/rdlog_event.cpp' that was causing macro + carts to fail to be assigned a group color. +2006-09-03 Fred Gleason + * Fixed a bug in 'rdairplay/loglinebox.cpp' that was causing + spurious group names to be assigned to CHAIN-TO events in the + Button Log widget. +2006-09-03 Fred Gleason + * Fixed a bug in 'RDLogLine::setCart() in 'lib/rdlog_line.cpp' + that was causing the group color value to fail to be loaded. +2006-09-04 Fred Gleason + * Modified 'rdlibrary/audio_cart.cpp' and + 'rdlibrary/edit_cart.cpp' so as to select the cut in the cut list + only when a new cart is being created. +2006-09-04 Fred Gleason + * Fixed a bug in 'rdlogmanager/generate_log.cpp' that was allowing + traffic data to be linked even if pending music data had not been + linked yet. +2006-09-04 Fred Gleason + * Incremented the package version to 0.9.72srs5. +2006-09-04 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was the + incorrect title to be assigned to a track when the following event + was selected in the log list. +2006-09-04 Fred Gleason + * Incremented the package version to 0.9.72srs6. +2006-09-04 Fred Gleason + * Fixed bugs in 'lib/rdlog_line.cpp' that were causing invalid + events to fail to be updated to show proper status when becoming + valid. +2006-09-04 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that was causing incorrect names + to be assigned to voice track markers when linking music data. +2006-09-04 Fred Gleason + * Incremented the package version to 0.9.72srs7. +2006-09-04 Fred Gleason + * Fixed a bug in 'lib/rdlog_line.cpp' that was causing segfaults + when loading a new log min RDAirPlay while a current log was + running. +2006-09-04 Fred Gleason + * Incremented the package version to 0.9.72srs8. +2006-09-05 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing + incorrect transition placements to be saved if the event following + the voicetrack was selected. +2006-09-05 Fred Gleason + * Incremented the package version to 0.9.72srs9. +2006-09-07 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing the + Full Log widget to update the incorrect log event line when moving + an event. +2006-09-07 Fred Gleason + * Fixed a bug in 'rdairplay/list_log.cpp' that allowed a paused + event to be moved. +2006-09-07 Fred Gleason + * Fixed a bug in 'rdairplay/list_log.cpp' that was causing a + segfault when an event was moved to the end of a log. +2006-09-07 Fred Gleason + * Fixed bugs in 'rdairplay/log_play.cpp' and + 'rdairplay/list_log.cpp' that were causing the next event to + revert to the event immediately following a paused event when the + paused event was resumed. +2006-09-07 Fred Gleason + * Fixed a bug in 'rdairplay/list_log.cpp' where a paused event + could not be deleted from the Full Log widget. +2006-09-07 Fred Gleason + * Fixed a bug in 'rdairplay/list_log.cpp' that allowed a paused + event to be moved. +2006-09-07 Fred Gleason + * Fixed a bug in 'rdairplay/list_log.cpp' in which attempting to + move, add or copy an event to a paused event threw a segfault. +2006-09-07 Fred Gleason + * Disabled the ability to copy a marker in + 'rdairplay/list_log.cpp' and 'rdairplay/button_log.cpp'. +2006-09-07 Fred Gleason + * Incremented the package version to 0.9.72srs10. +2006-09-11 Fred Gleason + * Removed filter code to prevent inclusion of aired cart numbers + in DeltaFlex ELR data in 'lib/export_deltaflex.cpp'. +2006-09-11 Fred Gleason + * Added the database schema to the version line in RDAdmin's + Information Dialog in 'rdadmin/info_dialog.cpp'. +2006-09-11 Fred Gleason + * Removed instrumentation code in 'rdairplay/log_play.cpp' to + determine source of CAE 'Play Stop' commands. + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.73. +2006-09-12 Fred Gleason + * Optimized the Broadcast Tools SS 16.4 driver in + 'ripcd/btss164.cpp' so as to enable operation at 38400 bps. +2006-09-14 Fred Gleason + * Added an 'RDLogLine::State' enum in 'lib/rdlog_line.cpp'. + * Rewrote 'rdairplay/log_play.cpp' so as to scan the entire log + for changes in cart status. +2006-09-14 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing timescaled + events to be stopped early. +2006-09-14 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing the Pie + Widget to indicate an upcoming stopdown even when an earlier event + had been made next. +2006-09-15 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing + already-played events to be repeated if a previous event had been + made next. +2006-09-15 Fred Gleason + * Fixed (again) a bug in 'rdairplay/log_play.cpp' that was causing + already-played events to be repeated if a previous event had been + made next. +2006-09-15 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that broke resume from + paused events. +2006-09-15 Fred Gleason + * Incremented the package version to 0.9.73srs0. +2006-09-16 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing events + with hard start times to be started even if they had already + played. +2006-09-16 Fred Gleason + * Incremented the package version to 0.9.73srs1. +2006-09-18 Fred Gleason + * Increased the 'RINGBUFFER_SIZE' define in 'cae/cae.h' to 131072. +2006-09-18 Fred Gleason + * Fixed a security vulnerability in 'ripcd/local_macros.cpp' that + allowed users to execute programs with the 'RN' RML with the + permissions of whatever user started ripcd(8) (normally 'root'). +2006-09-18 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.74. +2006-09-21 Fred Gleason + * Added an 'RDPlayDeck::reset()' method in 'lib/rdplay_deck.cpp'. + * Fixed a race in 'rdairplay/log_play.cpp' that was causing play + streams to fail to be freed after use. +2006-09-21 Fred Gleason + * Incremented the package version to 0.9.74kgu0. +2006-09-21 Fred Gleason + * Fixed a typo in 'scripts/rd_backup' that improperly specified the + site name. +2006-09-25 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing + the track end marker to appear in the wrong location for cuts that + had a non-zero start marker. +2006-09-25 Fred Gleason + * Optimized code in 'rdlogedit/voice_tracker.cpp' so as to work + properly under SuSE 9.2. +2006-09-25 Fred Gleason + * Fixed a bug in 'lib/rdcart.cpp' that caused a cart to show as + conditionally valid even if all underlying cuts had expired. +2006-09-29 18:45 EDT Federico Grau + * lib/rdescape_string.cpp, rdescape_string.h, lib/rdreport.cpp; + Correct a bug with generating reports (MIXDOWN table was not being + created). Added a new function RDEscapeStringSQLColumn() to + lib/rdesacpe_string which now escapes the hostname replacing + periods (and other illegal characters) with underscores. Made use + of the new function in rdreport.cpp. + * rdairplay.cpp; correct comment. +2006-10-10 Fred Gleason + * Implemented the argument for the Start Next [PN] + RML in 'rdairplay/local_macros.cpp' and 'rdairplay/log_play.cpp'. + * Documented the argument for the Start Next [PN] RML + in 'docs/rml.sxw'. +2006-10-10 Fred Gleason + * Fixed a bug in 'lib/rdlog_event.cpp' that was causing the custom + transition attribute to be incorrectly set for non-cart events. + * Fixed a bug in 'lib/rdlog_line.cpp' that was causing custom + transition data to be incompletely reset by the + 'RDLogLine::clearTrackData() method. + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that was causing + orphaned voice tracks when doing over tracks with the following + event selected. +2006-10-10 Fred Gleason + * Removed a debugging printf from 'lib/rdlog_event.cpp'. + * Incremented the package version to 0.9.74kgu1. +2006-10-11 Fred Gleason + * Fixed a bug in 'lib/rdimport_audio.cpp' that was causing the + dialog to close prematurely when exporting audio. +2006-10-11 Fred Gleason + * Removed a debugging printf from 'rdairplay/log_play.cpp'. +2006-10-11 Fred Gleason + * Incremented the package version to 0.9.74kgu2. +2006-10-13 Fred Gleason + * Added 'LOGS.LINK_DATETIME' and 'LOGS.NEXT_ID' fields to the + database. + * Incremented the database version to 121. + * Added 'RDLog::linkDatetime()', 'RDLog::setLinkDatetime()', + 'RDLog::nextId()' and 'RDLog::setNextId()' methods in + 'lib/rdlog.cpp'. + * Fixed a bug in 'lib/rdlog.cpp' that was causing updates of + datetime values to the database to fail. + * Consolidated the 'Play' and 'Stop' buttons in the Full Log + widget into a single combined button in 'rdairplay/list_log.cpp'. + * Added a 'Refresh Log' button in the the Full Log widget in + 'rdairplay/list_log.cpp'. + * Modified the 'RDLog::generateLog()' and 'RDLog::linkLog()' + methods in 'lib/rdsvc.cpp' so as to properly update the + LOGS.NEXT_ID' field. + * Added 'LogPlay::refresh()' and 'LogPlay::isRefreshable()' + methods in 'rdairplay/log_play.cpp'. + * Added a 'LogPlay::refreshabilityChanged()' signal in + 'rdaiplay/log_play.h'. +2006-10-13 Fred Gleason + * Added CVS Id tags to all program source files. +2006-10-16 Fred Gleason + * Added an 'RDLogLine::StartSource' enum in 'lib/rdlog_line.h'. + * Added 'RDLogLine::startSource()' and + 'RDLogLine::setStartSource()' methods in 'lib/rdlog_line.cpp'. + * Implemented start source logging in 'rdairplay/log_traffic.cpp'. + * Added an 'RDReport::ExportTechnical()' method in + 'lib/export_technical.cpp'. + * Implemented start source logging in 'lib/rdsound_panel.cpp'. +2006-10-18 Fred Gleason + * Added an 'EnableMixerLogging=' parameter in the '[Caed]' section + of rd.conf(5) in 'lib/rdconfig.cpp' and 'cae/cae.cpp'. +2006-10-18 Fred Gleason + * Implemented a 'Refresh Log' ['RL'] RML in 'lib/rdmacro.cpp' and + 'rdairplay/local_macros.cpp'. +2006-10-19 Fred Gleason + * Added 'LOGS.MODIFIED_DATETIME', 'LOGS.AUTO_REFRESH' and + 'SERVICES.AUTO_REFRESH' fields to the database. + * Incremented the database version to 122. + * Added 'RDLog::modifiedDatetime()', + 'RDLog::setModifiedDatetime()', 'RDLog::autoRefresh()' and + 'RDLog::setAutoRefresh()' methods in 'lib/rdlog.cpp'. + * Added 'RDSvc::autoRefresh()' and 'RDSvc::setAutoRefresh()' + methods in 'lib/rdsvc.cpp'. + * Added an 'Enable AutoRefresh By Default' control in the Edit + Service dialog in 'rdadmin/edit_svc.cpp'. + * Added a 'Last Modified' column to RDLogEdit in + 'rdlogedit/rdlogedit.cpp'. + * Added an 'Enable AutoRefresh' control to the Edit Log dialog in + 'rdlogedit/edit_log.cpp'. + * Implemented AutoRefresh in 'rdairplay/log_play.cpp'. +2006-10-20 Fred Gleason + * Fixed a bug in 'lib/rdimport_audio.cpp' where the Talk Start + marker was being set to an earlier value then the Start Marker. +2006-10-20 Fred Gleason + * Added a 'Toggle On Air Flag' ['TA'] RML in 'lib/rdmacro.cpp' and + 'ripcd/local_macros.cpp'. + * Added a 'TA' command to RIPC in 'ripcd/ripcd.cpp'. + * Added an 'RDRipc::sendOnairFlag()' method in 'lib/rdripc.cpp'. + * Added an 'RDRipc::onairFlagChanged()' signal in lib/rdripc.h'. + * Added a 'PieCounter::setOnairFlag()' method in + 'rdairplay/pie_counter.cpp'. + * Added an 'ONAIR_FLAG' field to the database schema for '_SRT' + tables. + * Added a 'REPORTS.FILTER_ONAIR_FLAG' field to the database. + * Incremented the database version to 123. + * Added 'RDReport::filterOnairFlag()' and + 'RDReport::setFilterOnairFlag()' methods in 'lib/rdreport.cpp'. +2006-10-20 Fred Gleason + * Fixed a bug in 'ripcd/ripcd.cpp' that was causing the 'TA' + command to be incorrectly processed. + * Added a 'LogPlay::onairFlagChangedData()' slot in + 'rdairplay/log_play.cpp. + * Added an 'Export Only OnAir Events' control to the Edit Report + dialog in 'rdadmin/edit_report.cpp'. +2006-10-24 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that was preventing generation of + an exception report for services containing hyphens in their + names. +2006-10-26 Fred Gleason + * Added an RDTextFile function in 'lib/rdtextfile.cpp'. + * Added a 'List Reports' dialog in 'rdlibrary/list_reports.cpp'. + * Modified RDLogManager and RDLogEdit to use an external editor to + display report results. +2006-10-29 Fred Gleason + * Fixed a race in 'lib/rdplay_deck.cpp' that could cause an active + playout to have it's mixer setting muted. +2006-10-30 Fred Gleason + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was causing macro + carts to be tagged as 'Invalid'. +2006-10-30 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing the + Link Datetime parameter to be reset when saving an existing log. +2006-10-30 Fred Gleason + * Added a HeartbeatInterval=' parameter in the [mySQL] section in + rd.conf(5). + * Added an 'RDConfig::mysqlHeartbeatInterval()' method in + 'lib/rdconfig.cpp'. + * Added an 'RDDbHeartbeat' class in 'lib/rddbheartbeat.cpp'. + * Added an instance of 'RDDbHeartbeat' in + 'rdairplay/rdairplay.cpp', 'rdadmin/rdadmin.cpp', + 'rdcatch/rdcatch.cpp', 'rdlibrary/rdlibrary.cpp', + 'rdlogedit/rdlogedit.cpp', 'rdlogin/rdlog.cpp', + 'rdlogmanager/rdlogmanager.cpp', 'rdpanel/rdpanel.cpp', + 'ripcd/ripcd.cpp', 'utils/rdgpimon/rdgpimon.cpp', + 'utils/rdimport/rdimport.cpp', and 'utils/sas_shim/sas_shim.cpp'. +2006-10-31 Fred Gleason + * Added a Cart Data Dump report in 'rdlibrary/list_reports.cpp'. +2006-11-01 Fred Gleason + * Added a List Reports dialog in 'rdcatch/list_reports.cpp'. + * Implemented an 'RDCatch Events Report' in + 'rdcatch/list_reports.cpp'. +2006-11-01 Fred Gleason + * Implemented an 'RDCatch Upload/Download Report' in + 'rdcatch/list_reports.cpp'. +2006-11-02 Fred Gleason + * Implemented a '--fix-broken-formats' switch for RDImport that + enables a workaround for WAV files with off-by-one errors in the + chunk size structures. + * Implemented a '--use-cartchunk-cutid' switch for RDImport that + causes files to be imported to the cart specified by the CartChunk + CutID parameter associated with each file. +2006-11-03 Fred Gleason + * Added 'RDLogLine::transText()', 'RDLogLine::sourceText()' and + 'RDLogLine::typeText()' methods in 'lib/rdlog_line.cpp'. + * Added a 'List Reports' dialog to the RDLogEdit Edit Log dialog + in 'rdlogedit/list_reports.cpp'. + * Added a 'Log Report' button to RDLogEdit in + 'rdlogedit/rdlogedit.cpp'. +2006-11-06 Fred Gleason + * Added 'SERVICES.TFC_LEN_HOURS_OFFSET', + 'SERVICES.TFC_LEN_HOURS_LENGTH', + 'SERVICES.TFC_LEN_MINUTES_OFFSET', + 'SERVICES.TFC_LEN_MINUTES_LENGTH', + 'SERVICES.TFC_LEN_SECONDS_OFFSET', + 'SERVICES.TFC_LEN_SECONDS_LENGTH', + 'SERVICES.MUS_LEN_HOURS_OFFSET', + 'SERVICES.MUS_LEN_HOURS_LENGTH', + 'SERVICES.MUS_LEN_MINUTES_OFFSET', + 'SERVICES.MUS_LEN_MINUTES_LENGTH', + 'SERVICES.MUS_LEN_SECONDS_OFFSET' and + 'SERVICES.MUS_LEN_SECONDS_LENGTH' to the database. + * Incremented the database version to 124. + * Added 'ImportSource::LengthHours' 'ImportSource::LengthMinutes' + 'ImportSource::LengthSeconds' members to 'RDSvc::ImportSource' in + 'lib/rdsvc.h'. + * Removed the 'Import Source::Length' member from + 'RDSvc::ImportSource' in 'lib/rdsvc.h'. + * Added 'Start Length - Hours', 'Start Length - Minutes' and + 'Start Length - Seconds' controls to the Traffic and Music + sections of the Edit Service dialog in 'rdadmin/edit_svc.cpp'. + * Modified the 'RDSvc::import()' method in 'lib/rdsvc.cpp' to use + the new parser length data fields. +2006-11-06 Fred Gleason + * Incremented the package version to 0.9.76srn0. +2006-11-07 Fred Gleason + * Added a 'REPORTS.SERVICE_NAME' field to the database. + * Added 'ALBUM' and 'LABEL' fields to the reconciliation table + schema in the database. + * Incremented the database version to 125. + * Added 'RDReport::serviceName()' and 'RDReport::setServiceName()' + methods in 'lib/rdreport.cpp'. + * Added a 'Service Name:' control to the Edit Report dialog in + 'rdadmin/edit_report.cpp'. + * Added an 'RDReport::SoundExchange' member to + 'RDReport::ExportFilter' in 'lib/rdreport.h'. + * Added an 'RDReport::ExportSoundEx()' in + 'lib/export_soundex.cpp'. + * Added a Group Report in 'rdadmin/list_groups.cpp'. +2006-11-08 Fred Gleason + * Fixed a layout error in 'rdadmin/edit_svc.cpp' that was + obscuring the end of the 'Insert CHAIN TO at log end' label. + * Fixed a layout error in 'rdlogedit/edit_log.cpp' that was + obscuring the beginning of the 'Enable AutoRefresh' label. +2006-11-13 Fred Gleason + * Fixed a race in 'lib/rdplay_deck.cpp' that was causing a play + stream leak. +2006-11-13 Fred Gleason + * Fixed a bug in 'rdairplay/pie_counter.cpp' that was causing the + Talk Countdown timer to be mislaligned. +2006-11-13 Fred Gleason + * Added 'RDLogLine::incrementPass()' and 'RDLogLine::clearPass()' + methods in 'lib/rdlog_line.cpp'. + * Removed the 'RDLogLine::setPass()' method from + 'lib/rdlog_line.cpp'. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing an + already-played event to be relocated to the end of the log when + removed from the log's database representation and rrefreshed. +2006-11-15 Fred Gleason + * Added an 'RDSimplePlayer' class in 'lib/rdsimpleplayer.cpp'. + * Added Audition and Stop buttons to the Edit Log dialog in + 'rdlogedit/edit_log.cpp'. +2006-11-15 Fred Gleason + * Added Audition and Stop buttons to the Edit Event dialog in + 'rdlogmanager/edit_event.cpp'. +2006-11-17 Fred Gleason + * Added code to the 'LogPlay::clear()' method in + 'rdairplay/log_play.cpp' to properly handle clearing logs with + active events. +2006-11-17 Fred Gleason + * Removed a stale signal/slot connection in + 'rdairplay/list_log.cpp'. +2006-11-20 Fred Gleason + * Changed the return type of the 'WriteSword()' and 'WriteDword()' + functions in 'utils/rdgen/wavlib.h' from int to ssize_t. + * Fixed signedness warning in 'utils/rdgen/wavlib.cpp'. +2006-11-20 Fred Gleason + * Added a 'CatchListView' class in 'rdcatch/catch_listview.cpp'. + * Added a right-click menu to the Event List in RDCatch. +2006-11-20 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was failing to + remove finished events when unloading a log. +2006-11-20 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing an + invalid event to fail to be cleared upon becoming valid if an + attempt had been made previously to play it. +2006-11-20 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that was causing the clock + assignments in the grid of a newly created Service to be offset by + twelve hours from the exemplar Service [Mantis bug #175]. +2006-11-21 Fred Gleason + * Added 'LINK_START_SLOT' and 'LINK_END_SLOP' fields to the log + table schema in the database. + * Incremented the database version to 126. + * Added 'RDLogLine::linkStartSlopt()', + 'RDLogLine::setLinkStartSlop()', 'RDLogLine::linkEndSlop()' and + 'RDLogLine::setLinkEndSlop()' methods in 'lib/rdlog_line.cpp'. + * Fixed a bug in 'lib/rdsvc.cpp' and 'lib/rdevent_line.cpp' that + was cause slop factors to be added to event lengths. +2006-11-21 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that was causing the Cart + Exception report to fail to be generated unless there were also + non-placed events to report. +2006-11-21 Fred Gleason + * Fixed a bug in 'rivendell-suse' that was attempting to start the + daemons even if they were already running. +2006-11-21 Fred Gleason + * Hid the Hook Pointer controls in 'lib/rdedit_audio.cpp'. +2006-11-21 Fred Gleason + * Added a 'ValidateCut()' function in + 'rdlibrary/validate_cut.cpp'. + * Changed the logic in 'rdlibrary/rdlibrary.cpp' so as to show + validity indication for audio carts on the basis of current clock + time (experimental). + * Changed the logic in 'rdlibrary/audio_cart.cpp' so as to show + validity indication for audio cuts on the basis of current clock + time (experimental). +2006-11-21 Fred Gleason + * Fixed a bug in 'rdlibrary/audio_cart.cpp' that was causing + corrupt entries in the 'Start DateTime' and 'End DateTime' columns + of the Cut List. + * Added an error check to the Record/Info dialog in + 'rdlibrary/record_cut.cpp' to prevent saving of a cut with + identical Start and End Dayparts. +2006-11-21 Fred Gleason + * Removed an unused variable in 'rdlibrary/record_cut.cpp'. +2006-11-22 Fred Gleason + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was causing the + build to break on Windows. + * Fixed a bug in 'rdlogmanager/edit_event.cpp' that was causing the + build to break on Windows. + * Fixed a bug in 'lib/lib.pro' that was causing the build to break + on Windows. +2006-11-22 Fred Gleason + * Implemented Win32 support for the 'RDTextFile()' function in + 'lib/rdtextfile.cpp'. +2006-11-27 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that was causing the + database schema to fail to properly update services whose name + contained a hyphen. +2006-11-27 11:45 EST Federico Grau + * rdadmin/rdadmin.cpp, rdpanel/rdpanel.cpp; Corrected bugs with + database login using "rivendell" password instead of the SQL + database password. +2006-11-27 Fred Gleason + * Added a section on configuring SoundExchange Statutory License + Reports in 'docs/reports.txt'. + * Added an 'RDGetAth' dialog in 'lib/rdget_ath.cpp'. + * Removed the 'GenerateReport' dialog in + 'rdlogmanager/generate_report.cpp' and + 'rdlogmanager/generate_report.h'. + * Fixed a bug in 'lib/generate_soundex.cpp' that was generating + incorrect 'PLAY_FREQUENCY' values. +2006-11-27 Fred Gleason + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Incremented package version to 0.9.76. +2006-11-29 Fred Gleason + * Applied a patch by Darrick to + 'utils/rdimport/rdimport.cpp' to correct invalid MPEG bitrate + [Mantis bug #169]. +2006-11-29 Fred Gleason + * Applied a patch by Darrick to + 'scripts/rd_rip_cd' to correct invalid normalization level + [Mantis bug #170]. +2006-11-29 Fred Gleason + * Applied a patch by Darrick to + 'lib/rdcheck_daemons.cpp' to deal correctly with restarting the + daemons correct after an abnormal caed(8) shutdown [Mantis bug + #171]. +2006-11-29 Fred Gleason + * Added 'Set All' and 'Clear All' buttons to the 'Day of Week' + section of the Record Cut dialog in RDLibrary in + 'rdlibrary/record_cut.cpp' [Mantis feature request #172]. +2006-11-29 Fred Gleason + * Applied a patch by 'pota' on Mantis that fixed a bug in + 'rdlibrary/disk_ripper.cpp' that was causing only the last + selected track to be correctly auto-trimmed [Mantis bug #168]. +2006-11-29 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that was causing the + leading imported event to always receive a 'Make Next' attribute + if programmed to use a hard start time [Mantis bug #166]. +2006-11-29 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing macro + carts played from a SoundPanel button to be executed twice [Mantis + bug #167]. +2006-12-01 Fred Gleason + * Reverted the change from 2006-10-29 in 'lib/rdplay_deck.cpp' + that broke PLAY transitions. +2006-12-01 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.77. +2006-12-04 Fred Gleason + * Added an 'RDAIRPLAY.PANEL_PAUSE_ENABLED' field to the database. + * Incremented the database version to 127. + * Added 'RDAirPlayConf::panelPauseEnabled()' and + 'RDAirPlayConf::setPanelPauseEnabled()' methods in + 'lib/rdairplay_conf.cpp'. + * Added an 'Enable Button Pausing' checkbox in + RDAdmin->ManageHosts->RDAirPlay in 'rdadmin/edit_rdairplay.cpp'. + * Added 'RDSoundPanel::pauseEnabled()' and + 'RDSoundPanel::setPauseEnabled()' methods in + 'lib/rdsound_panel.cpp'. + * Added a 'Pause Panel' ['PU'] RML. +2006-12-05 Fred Gleason + * Fixed a bug in 'lib/rdsound_panel.cpp' that was failing to stop + the button timer when the button was paused. +2006-12-05 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that failed to update the + database schema properly for RDLogManager events. + * Incremented the database version to 128. +2006-12-05 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.78. +2006-12-05 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that was creating a corrupt + 'SERVICES' table. +2006-12-05 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.79. +2006-12-06 Fred Gleason + * Removed 'RDLogLine::postPoint()' and 'RDLogLine::setPostPoint()' + methods from 'lib/rdlog_line.cpp'. +2006-12-07 17:30 EST Federico Grau + * rdadmin/createdb.cpp; Removed extra close paren near line 709, + thanks to zotz@100jamz.com and chad.scott@gmail.com for help + identify the problem. +2006-12-08 15:45 EST Federico Grau + * docs/ALSA.txt; updated ALSA documentation to mention global + /etc/asound.conf configuration file. +2006-12-15 Fred Gleason + * Modified the SAS USI switcher driver so as to automatically + populate the input and output names each time the driver is + started. +2006-12-15 Fred Gleason + * Applied a patch from Chad Scott that + fixed a bug where the 'Database=' directive in rd.conf(5) was + ignored when created a new database. +2006-12-15 Fred Gleason + * Added an 'autoinclude.m4' file. + * Added a BNV_HAVE_QT macro in 'autoinclude.m4'. + * Modified the build system to autodetect the presence of Qt. + * Added an AR_HAVE_LIBRADIO macro in 'autoinclude.m4'. + * Modified the build system to autodetect the presence of LibRadio. + * Added an AR_HAVE_LIBRHPI macro in 'autoinclude.m4'. + * Modified the build system to autodetect the presence of LibRHpi. +2006-12-18 Fred Gleason + * Added a 'QT_BIN' export to the 'BNV_HAVE_QT' macro in + 'autoinclude.m4'. +2007-01-03 18:07:43 EST Federico Grau + * pam_rd/Makefile.am; correct pam_rd build problem after change to + BNV_HAVE_QT. +2007-01-09 19:00 EST Federico Grau + * lib/rdcart.cpp lib/rdcut.cpp rdcatch/rdcatch.cpp; corrected i18n bug by + replacing use of QT shortDayName() with libradio RGetShortDayNameEN() + which will always return english day names regardless of configured + locale. +2007-01-24 18:00 EST Federico Grau + * cae/cae_jack.cpp; applied patch from Chad Scott + to correct bug with editor position getting out of sync when jackd + sample rate is not equat to source file. +2007-01-25 17:15 EST Federico Grau + * rdairplay/pie_counter.cpp, rdairplay/pie_counter.h, + rdairplay/rdairplay.cpp; applied patch from Chad Scott + to correct bug with rdairplay pie clock drifting. +2007-02-08 Fred Gleason + * Applied a patch by Eliot Blennerhasset + to add detection of QT_BIN from the path. +2007-02-14 Fred Gleason + * Implemented '%m' [Composer] and '%p' [Publisher] Now & Next macros + in 'rdairplay/log_play.cpp'. + * Added a '--metadata-pattern=' switch to rdimport(1) in + 'utils/rdimport/rdimport.cpp'. +2007-02-15 15:20 EST Federico Grau + * Updated the debian/ directory with progress and ubuntu compatability. + This has been a joint effort by Alban Peignier , + Darrick Servis , and myself. +2007-02-16 Fred Gleason + * Added 'RDAIRPLAY.EXIT_CODE', 'RDAIRPLAY.EXIT_PASSWORD', + 'RDAIRPLAY.LOG,_START_MODE', 'RDAIRPLAY.LOG,_AUTO_RESTART', + 'RDAIRPLAY.LOG_LOG_NAME', 'RDAIRPLAY.LOG_LOG_ID', + 'RDAIRPLAY.LOG_LOG_LINE' and 'RDAIRPLAY.LOG_RUNNING' fields + to the database. + * Incremented the database version to 129. + * Added 'RDAirPlayConf::exitCode()', + 'RDAirPlayConf::setExitCode()', + 'RDAirPlayConf::exitPasswordValid()', + 'RDAirPlayConf::setExitPassword()', 'RDAirPlayConf::startMode()', + 'RDAirPlayConf::setStartMode()', 'RDAirPlayConf::autoRestart()', + 'RDAirPlayConf::setAutoRestart()','RDAirPlayConf::logName()', + 'RDAirPlayConf::setLogName()', 'RDAirPlayConf::logId()', + 'RDAirPlayConf::setLogId()', 'RDAirPlayConf::logLine()', + 'RDAirPlayConf::setLogLine()', 'RDAirPlayConf::currentLog()', + 'RDAirPlayConf::setCurrentLog()', 'RDAirPlay::logRunning()' and + 'RDAirPlay::setLogRunning()' methods in 'lib/rdairplay_conf.cpp'. + * Added code in 'rdcatchd/rdcatchd.cpp' to log the command line + used for upload and download events. + * Remove 'LOG_QUANTITY' define from 'rdairplay/rdairplay.h'. + * Added 'RDAIRPLAY_LOG_QUANTITY' define in 'lib/rd.h'. + * Added an 'RDGetPasswd' dialog in 'lib/rdgetpasswd.cpp'. + * Added an 'RDListLogs' dialog in 'lib/rdlist_logs.cpp'. +2007-02-19 Fred Gleason + * Fixed a bug in 'lib/rdlog_line.cpp' that was causing timescaling + to fail when playing SoundPanel buttons. +2007-02-19 Fred Gleason + * Fixed a bug in 'rdlogedit/edit_log.cpp' that was causing the + specified service attribute to fail to be applied to new logs + created with the 'Save As' function. +2007-02-19 Fred Gleason + * Fixed a bug in 'rdairplay/list_log.cpp' that was causing the + specified service attribute to fail to be applied to new logs + created with the 'Save As' function [Mantis bug #184]. +2007-02-19 Fred Gleason + * Applied a patch by 'pota' that correct spacebar start next event + functionality in RDAirPlay [Mantis bug #183]. +2007-02-19 Fred Gleason + * Fixed a bug in 'rdlibrary/record_cut.cpp' where the Start and + End Daypart times were not being loaded correctly [Mantis bug + #186]. +2007-02-19 Fred Gleason + * Optimized RDAirPlay to quickly unload long logs [Mantis bug + #187]. +2007-02-21 Fred Gleason + * Added an 'RDCATCH' table to the database. + * Incremented the database version to 130. + * Added an 'RDCatchConf' class in 'lib/rdcatch_conf.cpp'. + * Added an 'Error RML' control to RDadmin->ManageHosts->RDCatch in + 'rdadmin/edit_decks.cpp'. + * Added an 'RDRecording::typeString()' method in + 'lib/rdrecording.cpp'. + * Added support for generating error RMLs in + 'rdcatchd/rdcatchd.cpp'. +2007-02-21 Fred Gleason + * Fixed a bug in lib/rdcut.cpp' that was causing incorrect + processing of start/end dates in metadata imports. +2007-02-22 Fred Gleason + * Added file entries to 'EXTRA_DIST=' in 'debian/Makefile.am' to + fix broken 'make dist' rule. +2007-02-22 Fred Gleason + * Added an 'RDTextValidator::stripString()' method in + 'lib/rdtextvalidator.cpp' + * Fixed bugs in 'lib/rdcatch.cpp' an 'lib/rdcut.cpp' that was + causing save of metadata to fail for fields containing quote + characters. +2007-02-22 Fred Gleason + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that was causing a + segfault when rdimport(1) was invoked with no arguments. +2007-02-23 Fred Gleason + * Modified the code in 'lib/rdimport_audio.cpp' to use the + 'RDCart::setMetadata()' and 'RDCut::setMetadata()' methods. +2007-03-01 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing random + crashes when processing upload events with normalization enabled. + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing status + updates in RDCatch to fail when more than one xload event was + active. +2007-03-01 Fred Gleason + * Updated the copyright date in 'rdadmin/info_dialog.cpp'. + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Incremented the package version to 0.9.80. +2007-03-12 Fred Gleason + * Applied 'voice-tracker' patch from Stefan Gabriel + , implements the following: + * Changed RD_VERSION_DATABASE to 131 + * Added SCHED_CODES VARCHAR( 255 ) NULL DEFAULT NULL to table CART in + createdb.cpp + * Added SCHED_GROUP VARCHAR(10), TITLE_SEP INT(10) UNSIGNED, HAVE_CODE + VARCHAR(10), HOR_SEP INT(10) UNSIGNED, HOR_DIST INT(10) UNSIGNED to + table EVENTS in createdb.cpp + * Added ARTISTSEP int(10) UNSIGNED to table CLOCKS in createdb.cpp + * Added new table SCHED_CODES (CODE VARCHAR(10) NOT NULL PRIMARY KEY, + DESCRIPTION VARCHAR(255)) to database in createdb.cpp + * Update DUCK_UP_GAIN and DUCK_DOWN_GAIN to log_LOG tables in + createdb.cpp + * Added DUCK_UP_GAIN INT DEFAULT 0 to lib/rdcreate_log.cpp + * Added DUCK_DOWN_GAIN INT DEFAULT 0 to lib/rdcreate_log.cpp + * Generate table service_STACK (SCHED_STACK_ID int unsigned not null + primary key, CART int unsigned not null, ARTIST varchar(255), + SCHED_CODES varchar(255), SCHEDULED_AT datetime default '1000-01-01 + 00:00:00') if not present in rdlogmanager/generate_log.cpp + * Added code to rdsvc.cpp to delete table service_STACK when a Service + is deleted + * Generate new table clock_RULES ("CODE varchar(10) not null primary + key, MAX_ROW int unsigned, MIN_WAIT int unsigned, NOT_AFTER + varchar(10), + OR_AFTER varchar(10), OR_AFTER_II varchar(10))) if not present in + lib/schedruleslist.cpp + * Handle table clock_RULES like clock_CLK in + rdlogmanager/list_clocks.cpp + * Added rdadmin/edit_rdadmin/schedcodes.cpp, + rdadmin/edit_schedcodes.h, + rdadmin/list_schedcodes.cpp, rdadmin/list_schedcodes.h, + rdadmin/add_schedcodes.cpp, rdadmin/add_schedcodes.h + * Added Scheduler Codes Button to rdadmin + * Added lib/schedruleslist.cpp, lib/schedruleslist.h, + lib/schedcartlist.cpp, lib/schedcartlist.h + * Added schedCodes(), setSchedCodes() and updateSchedCodes methods to + rdcart.cpp + * Added getArtistSep(), setArtistSep(), getRulesModified() and + setRulesModified() methods to rdclock.cpp; added code to handle + artistsep, rules_modified in other methods of rdclock.cpp + * Added SchedGroup(), setSchedGroup(), HaveCode(), setHaveCode(), + titleSep(), setTitleSep() methods in rdevent.cpp; insert a default + TITLE_SEP=100 into the database table, when a new event is created + * Add SchedGroup(), setSchedGroup(), HaveCode(), setHaveCode(), + titleSep(), setTitleSep() methods to rdevent_line.cpp; load + SCHED_GROUP, TITLE_SEP and HAVE_CODE from the EVENTS table in + rdevent_line.cpp + * Added code for scheduling to RDEventLine::generateLog() + * Added rdlibrary/edit_schedulercodes.cpp, + rdlibrary/edit_schedulercodes.h + * Added code to select scheduler codes for a cart in + rdlibrary/edit_cart.cpp + * Added multi editing to rdlibrary/edit_cart.cpp + * Added Scheduler Codes Filter to rdlibrary.cpp + * Added multi selection/deleting/editing to rdlibrary.cpp + * Changed RDListView::keyPressEvent(), + RDListView::contentsMousePressEvent() and + RDListView::contentsMouseReleaseEvent() not to ignore Ctrl during + mouse clicks (for multi-selection in rdlibrary) + * Added rdlogmanager/edit_schedrules.cpp, + rdlogmanager/edit_schedrules.h, rdlogmanager/edit_schedcoderules.cpp, + rdlogmanager/edit_schedcoderules.h + * Added "Scheduler Code" button to edit_clock.cpp + * Added scheduler options to "Import From" line in edit_event.cpp + * Added command line mode to rdlogmanager.cpp + * Added command line mode to rdlogmanager/generate_log.cpp + * Write scheduler reports to exception report in + rdlogmanager/generate_log.cpp + * Added play gain support to rdcatch.cpp + * Added play gain support to rdlibrary/record_cut.cpp + * Added play gain in lib/rdedit_audio.cpp + * Added play gain support to rdsimpleplayer.cpp + * Added play gain support to rdplay_deck.cpp + * Show the Hook buttons in Edit Cut dialog again + * Changed rdlog_event.cpp to handle LOG.DUCK_UP_GAIN and + LOG.DUCK_DOWN_GAIN + * Added blockStartTime() method to rdlog_event.cpp + * Added code to handle duck_up_gain and duck_down_gain in + rdlog_line.cpp + * Fixed: Handle talk times correctly with custom start times in + rdlog_line.cpp + * Changed rdplay_deck.cpp to handle duck gain. + * RDPLAYDECK_DUCKDOWN_LENGTH hardcoded to 750 ms in rdplay_deck.h + * RDPLAYDECK_DUCKUP_LENGTH hardcoded to 1500 ms in rdplay_deck.h + * Added code to support duck gain in log_play.cpp + * Fixed: Handle talk times correctly with custom start times in + rdairplay.cpp + * Fixed popup menu position in rdlogedit/log_listview.cpp + * Added time counter to voice_tracker.cpp + * Added talk time counter to voice_tracker.cpp + * Added "Set Start Point", "Set End Point", "Set to Hook Markers" to + popup menu in voice_tracker.cpp + * Added waveform navigation with '<' and '>' keys and with mouse wheel + to voice_tracker.cpp + * Fixed waveform display and scrolling for custom start and end points + in voice_tracker.cpp + * Added duck gain support during playback in voice_tracker.cpp + * Added duck gain support during recording in voice_tracker.cpp + * Added code to set the duck volumes with the rubber band in + voice_tracker.cpp + * Added code to show the fade and duck volume using the meter in + voice_tracker.cpp + * Added auto segue during recording (like in rdairplay) to + voice_tracker.cpp + * Changed the behavior of "Do Over" for better handling of custom + start and end points + * Changed TRACKER_MB_PER_PIXEL to 42 in voice_tracker.h + * Changed TRACKER_MIN_GAIN to -3000 in voice_tracker.h + * Set TRACKER_FORCED_SEGUE to 1000 ms in voice_tracker.h +2007-03-13 Fred Gleason + * Applied a patch from Stefan Gabriel to fix + missing _PRE and _POST database table upgrades. +2007-03-30 Fred Gleason + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that was causing + imports to randomly fail when running in dropbox mode. +2007-04-01 Stefan Gabriel + * Fixed a bug in 'rdairplay/log_play.cpp': play_next_line was not + initialized in constructor +2007-04-02 17:47 EDT Federico Grau + * CODINGSTYLE; added codingstyle guidelines +2007-04-03 Fred Gleason + * Added 'CODINGSTYLE' to 'EXTRA_DISTS=' rule in 'Makefile.am'. + * Added 'CODINGSTYLE' to '%docs' rule in 'rivendell.spec.in'. +2007-04-03 Fred Gleason + * Added a 'DROPBOXES' table to the database. + * Incremented the database version to 132. + * Added an 'RDDropbox' class in 'lib/rddropbox.cpp'. + * Added a 'ListDropboxes' dialog in 'rdadmin/list_dropboxes.cpp'. + * Added an 'EditDropbox' dialog in 'rdadmin/edit_dropbox.cpp'. + * Added a '--log-mode' switch to rdimport(1) in + 'utils/rdimport/rdimport.cpp'. + * Added code in 'rdcatchd/rdcatchd.cpp' to automatically + start/stop dropbox processes. + * Added an 'RX' [Restart Dropbox] command in 'docs/catchd.txt'. + * Implemented the 'RX' command in 'rdcatchd/rdcatchd.cpp'. + * Added an 'RDCatchConnect::reloadDropboxes()' method in + 'lib/rdcatch_connect.cpp'. +2007-04-03 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that caused the database + schema for the '*_LOGS', '*_PRE' and '*_POST' tables whose names + contained spaces to fail to be updated properly when moving from + DB version 130 -> 131. + * Incremented the database version to 133. +2007-04-06 Fred Gleason + * Fixed bugs in 'lib/lib.pro' and 'rdlogmanager/rdlogmanager.pro' + that caused the build to break under Windows. +2007-04-17 Stefan Gabriel + * Fixed bugs with log refreshing in 'rdairplay/log_play.cpp' and + 'rdairplay/log_play.h' + * Added 'RDLog *track_log' in 'rdlogedit/voice_tracker.cpp' and + 'rdlogedit/voice_tracker.h'. + Added track_log->setModifiedDatetime() in 'VoiceTracker::SaveTrack()' + to enable refreshing with logs changed in voice tracker. +2007-04-28 Dan Mills + * Modified logging in rdairplay/log_play.cpp to log cut number as well + as cart when starting and stopping playback. +2007-05-08 Darrick Servis + * 'Makefile.am' and 'debian/Makefile.am' were cleaning too many files + thus breaking debuild. + * Fixed 'debian/control' and 'debian/rules' to use our version of + toolame. + * Fixed bug in 'rdadmin/opendb.cpp' where localhost was hard coded. + * Fixed bug in 'rdcatch/edit_download.cpp' where logged in user wasn't + passed to RDCutDialog. + * Fixed bug in 'rdlibrary/rdlibrary.cpp' where canceling from EditCart + dialog wasn't accounted for. + * Fixed bug in 'cae/cae.cpp' where LogLine was called before rd_config + was initialized. + * Tied labels to checkboxes and radiobuttons in + 'lib/rdimport_audio.cpp' and 'rdcatch/edit_recordings.cpp'. + * Set import_out_filename_edit to readOnly in + 'lib/rdimport_audio.cpp' as the format is rather picky (path + + filename + audio extension) and there is no validator. The file + selection dialog works well and having two places to input the info is + confusing. +2007-05-15 Stefan Gabriel + * Added autoSegue() method to lib/rdcut.cpp + * Added --segue-level and --segue-level options to rdimport +2007-05-16 17:00 EDT Federico Grau + * scripts/rd_audio_sync; applied patch from Andrew Struiksma + . The script now uses a lockfile to prevent + running multiple times, cleans up partial transfers, and checks + timestamps. +2007-05-26 Stefan Gabriel + * Fixed bugs in rdlogmanager/generate_log.cpp + rdlogmanager/edit_clock.cpp lib/schedruleslist.cpp that could + cause problems with database table creation, when service + name/clock name contains special characters. +2007-06-06 Fred Gleason + * Applied patch from Andrew that fixed + double default button bug in 'rdlogmanager/edit_eventline.cpp'. +2007-06-07 11:15 EDT Federico Grau + * configure.in, debian/Makefile.am, debian/patches/Makefile.am; added + configure support for the debian/patches subdir. +2007-06-08 Fred Gleason + * Added an 'RDPANEL' table to the database. + * Added an 'EXTENDED_PANELS' table to the database. + * Incremented the database version to 134. + * Added an RDPanel configuration dialog in + 'rdadmin/edit_rdpanel.cpp'. + * Completed the RDPanel module in 'rdpanel/'rdpanel.cpp'. + * Added RDPanel to 'rivendell.spec.in'. + * Added RDPanel to 'make_slack.in'. +2007-06-08 Fred Gleason + * Fixed typos regarding the SS4.2 switcher in + 'docs/SWITCHERS.txt'. (Thanks to 'Andrew' + '. +2007-06-12 Fred Gleason + * Added code in 'rdadmin/list_stations.cpp' to delete SoundPanel + data when deleting a Host entry. + * Added code in 'rdadmin/add_station.cpp' to clone SoundPanel + entries when creating a new Host entry. + * Added code in 'rdadmin/list_users.cpp' to delete SoundPanel + data when deleting a User entry. +2007-06-12 Fred Gleason + * Added a 'STATIONS.STARTUP_CART' field to the database. + * Incremented the database version to 135. + * Added 'RDStation::startupCart()' and + 'RDStation::setStartupCart()' methods in 'lib/rdstation.cpp'. + * Added a 'Startup Cart' control to the Edit Host dialog in + 'rdadmin/edit_station.cpp'. + * Implemented startup cart functionality in + 'rdcatchd/rdcatchd.cpp'. +2007-06-12 Fred Gleason + * Documented the 'Macro Timer' ['MT'] RML in 'docs/rml.sxw'. + * Added the 'MT' mneumonic to 'RDMacro::Command' in + 'lib/rdmacro.h' and 'lib/rdmacro.cpp'. + * Implemented the 'Macro Timer' ['MT'] RML in 'ripcd/ripcd.cpp' + and 'ripcd/local_macros.cpp'. + * Added 'Macro Timer' ['MT'] to 'docs/implemented_macros.txt'. +2007-06-14 Fred Gleason + * Fixed a bug in 'ripcd/ripcd.cpp' that was causing the build to + break with some versions of Qt. +2007-06-19 12:15 EDT Federico Grau + * rdadmin/opendb.cpp; add logic to check if creating DB on a remote + server on the same subnet, and if so to create a MySQL user for the + subnet. +2007-06-20 Stefan Gabriel + * Fixed bug in cae/cae_alsa.cpp MainObject::alsaStopPlayback() and + cae/cae_jack.cpp MainObject::alsaStopPlayback() that caused some cuts + to be stopped after a few msecs. + * Fixed bug in cae/cae_jack.cpp JackProcess(): Do not stop playback + in case of a ringbuffer underrun + * Fixed bug in lib/rdplay_deck.cpp RDPlayDeck::setCart() that caused + some cuts to end to soon with random cut rotation. +2007-06-26 12:15 EDT Federico Grau + * docs/SWITCHERS.txt; applied patch from Charles Sagona + . Documented that he found the + SS 8.2 to work at 9600 instead of 19200. +2007-06-29 14:45 EDT Federico Grau + * debian/rivendell.config; increased priority of several debconf dialogs + so they will be seen. +2007-06-30 Stefan Gabriel + * Fixed bug in rdairplay/log_play.cpp LogPlay::StartEvent(): Carts where + skipped with CHAINTO in some cases. + * Fixed problem in rdairplay/log_play.cpp LogPlay::GetNextPlayable() + with the LL macro. +2007-07-06 12:40 EDT Federico Grau + * rdadmin/opendb.cpp; add logic to check if creating DB on localhost. +2007-07-09 Stefan Gabriel + * Added support for special characters - .utf8() with (const char *) + conversions - to rdcut.cpp, rdcart.cpp, rdsound_panel.cpp, + rdimport_audio.cpp, rdcart_search_text.cpp, rdimport.cpp, + rdlibrary.cpp, rdcut_dialog.cpp, rdcart_dialog.cpp, list_reports.cpp, + edit_event.cpp + * Escape "`" and "´" in rdescape_sting.cpp +2007-07-09 Fred Gleason + * Added 'PANEL_NAMES' and 'EXTENDED_PANEL_NAMES' tables to the + database. + * Incremented the database version to 136. + * Increased 'MAX_PANELS' in 'lib/rd.h' to 50. + * Added an 'RDComboBox::setSetupMode()' method in + 'lib/rdcombobox.cpp'. + * Added an 'RDComboBox::setupClicked()' signal in + 'lib/rdcombobox.h'. + * Added an Edit Panel Name dialog in 'lib/rdedit_panel_name.cpp'. + * Replace the 'Up' and 'Down' selector buttons in RDSoundPanel + with a combo box control. + * Added the ability to customize the name of each SoundPanel panel + in RDAirPlay(1) and RDPanel(1). +2007-07-10 Fred Gleason + * Added 'RDLogLine::hookStartPoint()' and + 'RDLogLine::hookEndPoint()' methods in 'lib/rdlog_line.cpp'. + * Added a 'CART.AVERAGE_HOOK_LENGTH' field to the database. + * Incremented the database version to 137. + * Added 'RDCart::averageHookLength()' and + 'RDCart::setAverageHookLength()' methods in 'lib/rdcart.cpp'. + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing incorrect + marker signal generation when playout was started after the + beginning marker of a pair. + * Added a 'Play Hook' control to the SoundPanel widget. +2007-07-10 Fred Gleason + * Added 'RDAIRPLAY.BUTTON_LABEL_TEMPLATE' and + 'RDPANEL.BUTTON_LABEL_TEMPLATE' fields to the database. + * Incremented the database version to 138. + * Added 'RDAirPlayConf::buttonLabelTemplate()' and + 'RDAirPlayConf::setButtonLabelTemplate()' methods in + 'lib/rdairplay_conf.cpp'. + * Added a 'Label Template' control to the + RDAdmin->ManageHosts->RDAirPlay and RDAdmin->ManageHosts->RDPanel + dialogs. +2007-07-10 Fred Gleason + * Removed debugging printf from 'lib/rdimport_audio.cpp'. + * Fixed a bug in 'lib/rdairplay_conf.cpp' that was causing the + 'RDAirPlayConf::setExitPassword()' method to fail to update the + database properly. + * Changed the default value of the 'RDAIRPLAY.EXIT_PASSWORD' + field from NULL to "". + * Incremented the database version to 139. +2007-07-11 Fred Gleason + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that was causing + Delete Cuts mode to fail when operating in dropbox mode. +2007-07-11 Stefan Gabriel + * removed debugging output from rdlogmanager/edit_events.cpp +2007-07-11 Fred Gleason + * Set the Rivendell icon to be the primary application icon for + RDPanel in 'rdpanel/rdpanel.cpp'. +2007-07-13 Fred Gleason + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Updated the 'README' file. + * Incremented the package version to 0.9.81. +2007-07-13 10:45 EDT Federico Grau + * debian/changelog; updated with new release. +2007-07-15 Stefan Gabriel + * fixed a bug in rdaiplay/log_play.cpp GetNextPlayable() that caused + paused cut fail to resume +2007-07-15 Stefan Gabriel + * Added code to lib/rd_button_panel.cpp to enable CopyTo, AddTo and + DeleteTo Sound Panel Buttons with the COPY, ADD and DELTE buttons + * Added code to lib/rdsound_panel.cpp to enable CopyTo, AddTo and + DeleteTo Sound Panel Buttons with the COPY, ADD and DELTE buttons + * Changed RDBaseSearchText() (lib/rdcart_search_text.cpp) to implement + AND (by space) logic when filterinG carts. Use quotes to search for + exact phrase + * Added RDPanelButton::pauseWhenFinished() and + RDPanelButton::setPauseWhenFinished() methods to lib/rdpanel_button.cpp + * Implemented "Do Not Reset When finished" in + RDPanelButton::WriteKeycap() + * Bigger font for countdown of last 10 seconds in + RDPanelButton::WriteKeycap() + * Added 'default: emit stateChanged(play_id,RDPlayDeck::Stopped)' to + RDPlayDeck::clear() + * Added 'Reset All' button (visible instead of 'Setup' when 'Reset' + is pressed) in lib/rdsound_panel.cpp + * Option to set channel when starting an audio cart in + lib/rdsound_panel.cpp (for use with macro) + * Option to Stop or Pause only when audio is play to a specific + channel in lib/rdsound_panel.cpp (for use with macro) + * Option to fade out audio when stopping in lib/rdsound_panel.cpp + (for use with macro) + * Sound buttons can stay active when they are finished or stopped + until they are reseted manually in lib/rdsound_panel.cpp (for use + with macro) + * Option to pass -1 (= 0 in macros) for col and/or row: start first + loaded button that is not active in lib/rdsound_panel.cpp (for use + with macro) + * Added RDSoundPanel::currentNumber() and RDSoundPanel::currentType() + methods to lib/rdsound_panel.cpp + * Enabled CopyFrom playing carts in rdairplay/button_log.cpp + * Enabled audition of playing events in rdairplay/loglinebox.cpp + * Added mouse control of audition deck in rdairplay/edit_event.cpp + * Hide 'Start' button for currently playing log entries in rdairplay/edit_event.cpp + * DoubleClick to Modify in rdairplay/list_log.cpp + * Enabled audition of playing events in rdairplay/list_log.cpp + * Added optional arguments to PP, PS, PT, PU in rdairplay/local_macros.cpp + * Added panel type C (current) to GetPanel() in rdairplay/local_macros.cpp + * Added option to stop only audio on a specific port in rdairplay/log_play.cpp (for macro use) + * Added option to fade out when stopping audio in rdairplay/log_play.cpp (for macro use) + * Added CopyTo, AddTo, DeleteFrom panel buttons to rdairplay/rdairplay.cpp + * Added "Overlap" transition to lib/rdlog_event.cpp, lib/rdlog_line.cpp, lib/rdlog_line.h, + rdadmin/edit_rdairplay.cpp, rdadmin/edit_rdlogedit.cpp, rdairplay/button_log.cpp, + rdairplay/edit_event.cpp, rdairplay/list_log.cpp, rdairplay/loglinebox.cpp, + rdairplay/log_play.cpp, rdairplay/log_play.cpp, rdairplay/pie_counter.cpp, + rdlogedit/edit_chain.cpp, rdlogedit/edit_log.cpp, rdlogedit/edit_logline.cpp, + rdlogedit/edit_marker.cpp, rdlogedit/edit_track.cpp, rdlogedit/log_listview.cpp, + rdlogedit/voice_tracker.cpp, rdlogmanager/edit_event.cpp, rdlogmanager/import_listview.cpp, + * Added macros PD and MD to lib/rdmacro.cpp and lib/rdmacro.h + * Added setDuckVolume() and duckVolume() methods to lib/rdpanel_button.cpp + * Added overlap transition to lib/rdplay_deck.cpp + * Added duckVolume() method to lib/rdplay_deck.cpp + * Added duckVolume() method to lib/rdsound_panel.cpp + * Corrected widget names in rdadmin/edit_rdlibrary.cpp + * Changed LL macro in rdairplay/local_macros.cpp to clear log when no log name is given + * Added macros MD and PD to rdairplay/local_macros.cpp + * Added duckVolume() method to rdairplay/log_play.cpp + * set fadeup/fadedown gain to -3000 in insertCartButtonData() in rdlogedit/edit_log.cpp + * Added overlapData() method in rdlogedit/log_listview.cpp + * Changed mouse wheel behaviour in rdlogedit/voice_tracker.cpp + * Removed all setSegueGain(0) from rdlogedit_voice_tracker.cpp + (replaced by Overlap transition) + * Use 3 tracks for segue changing in rdlogedit/voice_tracker.cpp (LoadTrack() method) + * Fixed a but that cased a waveform jump in VoiceTracker::FinishTrack() + * Added overlapMenuData() method in rdlogmanager/import_listview.cpp + * Added option to allow double quotes in constructor in lib/rdtextvalidator.cpp + * Updated call of RDTextValidator in lib/rdcart.cpp. rdlibrary/rdlibrary.cpp, + rdlogmanager/edit_event.cpp + * Fixed a bug with the cut gain markers in lib/rdedit_audio.cpp + * Changed grace time to msecs in rdairplay/edit_event.cpp, rdairplay/log_play.cpp, + rdlogedit/edit_logline.cpp, + * Changed grace time edit in rdlogedit/edit_chain.cpp, rdlogedit/edit_marker.cpp, + rdlogedit/edit_track.cpp + * Changed rdaiplay/log_play.cpp: Hard Start Times with Make Next do keep a + STOP transition +2007-07-16 Stefan Gabriel + * Updated docs/rml.swx + * lib/rdsound_panel.cpp: Changed geometry of "All" button so it is + visible in rdpanel +2007-07-18 Dan Mills + * Cae now reports positions in miliseconds (not samples) in the + metering data. + * cae/cae_alsa.cpp cae/cae_jack.cpp cae/cae_hpi.cpp lib/rdcae.cpp lib/rdedit_audio.cpp + * This work is a precursor to finally laying the tendency of the + on screen timers in rdairplay to fail to match the audio. +2007-07-19 Dan Mills + * Fixed Mantis 00005 (Start time calculations were broken when + modifying logs in rdairplay). + * rdairplay/log_play.cpp::runningEvents can now take a NULL first + argument. + * Post timer now works correctly in all the cases I have tried. + rdairplay/log_play.cpp rdairplay/log_play.h +2007-07-20 12:40 EDT Federico Grau + * debian/control; added "bc" to the dependency list (used by the + normalizer). +2007-07-20 Stefan Gabriel + * Removed debugging output from rdairplay/log_play.cpp + stateChangedData() + * Changed edit_grace_edit from seconds to msecs in + 'rdairplay/edit_event.cpp' (that was missing in commit 2007-07-15) +2007-7-20 Dan Mills + * Added AC_LANG(C++) to configure.in so we run the tests with the + right toolchain. +2002-7-22 Dan Mills + * Fixed stupid arithetic bug in lib/rdedit_audio.cpp that was causing the cursor + to wrap around at the 65.5 seconds mark. My fault a few patches back. +2007-08-02 12:40 EDT Federico Grau + * debian/rivendell.config rivendell.init rivendell.postinst + rivendell.postrm rivendell.templates; added a debconf option asking the + user how they want to start the rivendell daemons (via the init scripts + for single user mode, or using pam_rd for multi-user support). +2007-08-03 Fred Gleason + * Fixed a bug in 'lib/vguest.cpp' that was causing corrupt + reception of vGuest messages when multiple messages were bundled + in a single TCP packet. +2007-08-03 Dan Mills + * Fixed a partially case sensitive comparison in rdcatch/rdcatch.cpp + that was causing editing to fail on hosts with upper case letters in + their names. +2007-08-03 Dan Mills + * lib/rdcae.cpp fixed a hard crash if the meterblock SHM segment was + not found. This just improves robustness as we used to segfault + without any sort of error message. +2007-08-09 14:35 EDT Federico Grau + * rdcatchd/rdcatchd.cpp; apply patch from Yuri Terleckyj + to correct a typo on passing "fix broken formats" parameter to + rdimport from dropboxes. +2007-08-16 16:30 EDT Federico Grau + * utils/rdimport/rdimport.cpp; correct bug with checking if + CartChunk data is present (isEmpty() does not return reliably + as CartChunk data is filled with \0 to the full field size, + 64 bytes and isEmpty() does not consider that empty). +2007-08-18 Stefan Gabriel + * Fixed a Bug in rdairplay/log_play.cpp GetNextPlayable: Carts with + no vaild cut and a STOP transition could not be started manualy or + with macro. +2007-08-29 Darrick Servis + * lib/rdlog_event.cpp & rdlogedit/edit_log.cpp; added code to show + predicted start times for carts in loglist. +2007-08-31 Fred Gleason + * Added '%h' and '%H' Now & Next wildcards for Event Length in + 'rdairplay/log_play.cpp' and 'lib/rdlog_line.cpp'. +2007-08-31 Fred Gleason + * Added a sanity check in 'ripcd/vguest.cpp' to prevent sending of + text strings longer than 60 characters to Supervisor. +2007-08-31 12:00 EDT Federico Grau + * rdadmin/add_station.cpp; increased the New Host Name field max size + from 20 to 64 (matching the database field capacity) (NOTE: RFC 1035 + states domain name limit to be 255 octets or less. If needed we + may have to increase this to this size in the future). +2007-08-31 Fred Gleason + * Added an 'InsertVoice Track String' control to the 'Traffic + Data Import' section of the Edit Service dialog in + 'rdadmin/edit_svc.cpp'. + * Added 'Note Cart String', 'Title', 'Contract #', 'Event ID' and + 'Annc. Type' controls to the 'Music Data Import' section of the + Edit Service dialog in 'rdadmin/edit_svc.cpp'. + * Added 'SERVICES.TFC_BREAK_STRING' and + 'SERVICES.TFC_TRACK_STRING' fields to the database. + * Incremented the database version to 140. + * Fixed a bug in 'lib/rdsvc.cpp' that was causing adjacent track + and break insert statements in log imports to be transposed. +2007-09-08 Dan Mills + * Fixed Mantis #221 bug in next stop time display when time format + is changed with a stopped cart. +2007-09-08 Dan Mills + * Fixed Mantis #215 Missing 12Hr time format display in log. +2007-09-08 Dan Mills + * Fixed Mantis #222 rdcatchd occasionally segfaulting on startup. +2007-09-08 Dan Mills + * Fixed Mantis #214, incorrect escaping of ';' causing rdimport to fail. +2007-09-08 Dan Mills + * Fixed Mantis #213, Redlineing cuts with zero weight. +2007-09-08 Dan Mills + * Fixed Mantis #211, Log description not updating correctly. +2007-09-08 Darrick Servis + * rdairplay/log_play.cpp and rdairplay/log_play.h: fixed race condition + where FinishEvent() was toasting hard timers. +2007-09-09 Dan Mills + * Fixed Mantis #210, User name length was inconsistent. +2007-09-10 18:05 EDT Federico Grau + * Add option in 'docs/tables/dropboxes.txt', 'lib/rd.h', + 'lib/rddropbox.cpp', 'lib/rddropbox.h', 'rdadmin/createdb.cpp', + 'rdadmin/edit_dropbox.cpp', 'rdadmin/edit_dropbox.h', + 'rdcatchd/rdcatchd.cpp', 'utils/rdimport/rdimport.cpp' and + 'utils/rdimport/rdimport.h' to import files and use the + CartChunk CutID field to populate Rivendell cart title. + - rdimport; has an option (--title-from-cartchunk-cutid) to populate the + cart title using the CartChunk CutID field. + - dropboxes; add a checkbox option to enable the above feature + - docs and database have been updated +2007-09-11 Dan Mills + * Added two snd_pcm_drop calls to the Xrun path in cae_alsa.cpp to + Attempt to improve reliibility of restart after XRun. +2007-09-12 13:45 EDT Federico Grau + * debian/changelog; updated with new release 0.9.82. +2007-09-12 Fred Gleason + * Fixed a bug in 'ripcd/local_macros.cpp' that was causing the + 'UO' RML to fail if the string argument contained one or more + spaces. +2007-09-14 Fred Gleason + * Integrated LibRadio into the Rivendell convienence library in + 'lib/'. + * Integrated LibRHpi in 'rdhpi/'. + * Added a 'PACKAGE_VERSION' file. + * Added 'build_win32.bat', helpers/'win32_frag1.txt' and + 'helpers/win32_frag2.txt' files. +2007-09-14 Fred Gleason + * Added an 'RDHPIInfo' utility in 'utils/rdhpiinfo/' from LibRHpi. + * Updated the 'INSTALL' file. + * Updated the 'README' file. +2007-09-14 Fred Gleason + * Added an InstallShield configuration in 'rivendell.ism'. + * Renamed 'conf/rd.ini' to 'conf/rd-sample.ini'. +2007-09-17 12:00 EDT Federico Grau + * debian/control, debian/copyright, (R)debian/librivendell-dev.install, + debian/librivendell.install, debian/rules; update the debian directory for + the new package layout which includes libradio and librhpi as part of + rivendell itself. +2007-09-17 Fred Gleason + * Updated the 'NEWS' file. + * Updated the package version to 0.9.82. +2007-09-17 14:30 EDT Federico Grau + * debian/Makefile.am; removed reference to librivendell-dev +2007-09-18 Fred Gleason + * Applied a patch from Eliot Blennerhassett + to update an obsolete HPI definition. +2007-09-18 Fred Gleason + * Removed the build dependency for 'gpio.h'. +2007-09-18 Fred Gleason + * Removed extraneous reference to LibRadio and LibRHpi in + 'INSTALL'. +2007-09-18 Fred Gleason + * Updated the 'Coding Style' section of 'CODINGSTYLE'. +2007-09-19 Dan Mills + * Modified average length calculation in lib/rdcart.cpp + Mantis #197 also mentioned in #213. + This will need readressing as the cached time in the db + really needs to be updated periodically as cuts expire. +2007-09-22 Dan Mills + * Big fix to make setting audioroot to places other then /var/snd + work correctly. Also something of a precursor to cleaning up the + way accesses to the config file are handled. +2007-09-22 Dan Mills + * Fixed mantis #233, caed was crashing hard if the card had no outputs, + as is the case for a DVB card. Fix is a bandaid until I can get + the new caed in release shape. +2007-09-24 Fred Gleason + * Added a 'FEEDS' table to the database. + * Added a 'RECORDINGS.FEED_ID' field to the database. + * Added a 'VERSION.LAST_MAINT_DATETIME' field to the database. + * Incremented the database version to 142. + * Added a 'List Feeds' dialog in 'rdadmin/list_feeds.cpp'. + * Added an 'Edit Feed' dialog in 'rdadmin/edit_feed.cpp'. + * Added an 'RDFeed' class in 'lib/rdfeed.cpp'. + * Added an 'Add Feed' dialog in 'rdadmin/add_feed.cpp'. + * Added a 'docs/PODCASTING.txt' file. + * Fixed a bug in 'lib/rdescape_string.cpp' that was improperly + escaping the '%' character'. + * Added an 'RSS FEED' column in 'rdcatch/rdcatch.cpp' + * Added an 'RSS Feed' control to the Edit Upload dialog in + 'rdcatch/edit_upload.cpp'. + * Added 'RDRecording::feedId()', 'RDRecording::setFeedId()' and + 'RDRecording::feedKeyName()' methods in 'lib/rdrecording.cpp'. + * Added an 'RDPodcast' class in 'lib/rdpodcast.cpp'. + * Created an rdcastmanager(1) application in 'rdcastmanager/'. + * Added an 'Edit Podcast' dialog in 'rdcastmanager/edit_cast.cpp'. + * Added an rdpurgecasts(1) utility in 'utils/rdpurgecasts/'. + * Added code to 'ripcd/ripcd.cpp' to run rdpurgecasts(1) + periodically. + * Updated the 'INSTALL' file. +2007-09-24 Fred Gleason + * Rewrote 'rdcatchd/rdcatchd.cpp' to use lftp(1) instead of ftp(1) + for FTP file transfers. + * Updated the dependency list in the 'INSTALL' and + 'rivendell.spec.in' files. +2007-09-24 Fred Gleason + * Added a 'web' subpackage in 'rivendell.spec.in' and 'Makefile.am'. + * Added a 'xdg/rdcastmanager.desktop' file. +2007-09-25 Fred Gleason + * Applied a patch from Eliot Blennerhassett + to enable proper build on Ubuntu. +2007-09-25 Fred Gleason + * Added a 'RDCreateAuxFieldsTable' function in + 'lib/rdcreateauxfieldstable.cpp'. + * Added an 'AUX_FIELDS' table to the database. + * Added _FIELDS' tables to the database. + * Incremented the database version to 143. + * Added a 'ListAuxFields' dialog in 'rdadmin/list_aux_fields.cpp'. + * Added an 'EditAuxField' dialog in 'rdadmin/edit_aux_field.cpp'. + * Added an 'AddAuxField' dialog in 'rdadmin/add_aux_field.cpp'. +2007-09-26 Fred Gleason + * Modified 'rdlibrary/audio_cart.cpp' so that the first cut of a + cart is automatically selected if it is not showing a special + background color. +2007-09-30 Dan Mills + * Fixed Mantis #236 Post point time problems on delete (Also on move). +2007-10-01 Fred Gleason + * Optimized the 'WallClock' class in 'rdairplay/wall_clock.cpp' so + that the time offset value is read only once from the database at + startup. +2007-10-02 Fred Gleason + * Added 'FEEDS.UPLOAD_FORMAT', 'FEEDS.UPLOAD_CHANNELS', + 'FEEDS.UPLOAD_SAMPRATE', 'FEEDS.UPLOAD_BITRATE', + 'FEEDS.UPLOAD_QUALITY' and 'FEEDS.NORMALIZE_LEVEL' fields to + the database. + * Added 'PODCASTS.ITEM_AUTHOR', 'PODCASTS.ITEM_COMMENTS', + 'PODCASTS.ITEM_SOURCE_TEXT' and 'PODCASTS.ITEM_SOURCE_URL' fields + to the database. + * Incremented the database version to 144. + * Modified 'RDExportSettingsDialog' in + 'lib/rdexportsettingsdialog.cpp' to properly handle MPEG2 + encoding parameters (low samplerates/bitrates). + * Added 'RDFeed::uploadFormat()', 'RDFeed::setUploadFormat()', + 'RDFeed::uploadChannels()', 'RDFeed::setUploadChannels()', + 'RDFeed::uploadQuality()', 'RDFeed::setUploadQuality()', + 'RDFeed::uploadBitRate()', 'RDFeed::setUploadBitRate()', + 'RDFeed::uploadSampleRate()', 'RDFeed::setUploadSampleRate(), + 'RDFeed::normalizeLevel()' and 'RDFeed::setNormalizeLevel()' + methods in 'lib/rdfeed.cpp'. + * Added 'RDPodcast::itemAuthor()', 'RDPodcast::setItemAuthor()', + 'RDPodcast::itemComments()', 'RDPodcast::setItemAuthor()', + 'RDPodcast::itemSourceText()', 'RDPodcast::setItemSourceText()', + 'RDPodcast::itemSourceUrl()' and 'RDPodcast::setItemSourceUrl()' + methods in 'lib/rdpodcast.cpp'. + * Added Upload Format controls to the 'EditFeed' dialog in + 'rdadmin/edit_feed.cpp'. + * Added a 'rdcastmanager/globals.h' file. + * Added 'Post from Cart/Cut', 'Post from File' and 'Delete' + buttons to the Edit Cast dialog in 'rdcastmanager/edit_cast.cpp'. +2007-10-02 Fred Gleason + * Fixed a typo in the default Item XML template code in + 'rdadmin/add_feed.h'. +2007-10-02 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that was causing + incorrect metadata pattern values to be passed to dropbox + instances. + * Added code to stop dropboxes in 'rivendell-suse.in' and + 'rivendell-gentoo'. +2007-10-04 Dan Mills + * Monster patch to make database reconnection work. + This touches almost every .cpp file in the system. +2007-10-05 Fred Gleason + * Updated 'lib/rdfeed.cpp', 'lib/rdpodcast.cpp', 'lib/rdcart.cpp', + 'rdadmin/list_dropboxes.cpp', 'rdadmin/list_schedcodes.cpp', + 'rdadmin/list_groups.cpp', 'rdairplay/local_macros.cpp', + 'rdcastmanager/list_casts.cpp', 'rdcatchd/rdcatchd.cpp', + 'rdlibrary/validate_cut.cpp', 'rdlogmanager/list_clocks.cpp', + 'rdlogmanager/list_events.cpp' and 'web/rdfeed/rdfeed.cpp' to use + the 'RDSqlQuery' class. +2007-10-05 Fred Gleason + * Fixed a bug in 'utils/rdpurgecasts/rdpurgecasts.cpp' that was + causing casts with no expiration date set to be deleted. +2007-10-05 Fred Gleason + * Cleaned up error messages from 'rivendell-suse' and + 'rivendell-gentoo' when stopping the daemons on a system with no + dropboxes configured. +2007-10-05 Fred Gleason + * Fixed a bug in 'web/rdfeed/rdfeed.cpp' that was causing XML to + be generated with an incorrect MIME type. + * Added an 'RDTimeZoneName()' function in 'lib/rdconf.cpp'. + * Fixed a bug in 'web/rdfeed/rdfeed.cpp' that was causing + datestamps to be generated in non RFC822-compliant format. +2007-10-08 Fred Gleason + * Added a FEED_PERMS' table to the database. + * Added 'USERS.ADD_PODCAST_PRIV', 'USERS.EDIT_PODCAST_PRIV' and + 'USERS.DELETE_PODCAST_PRIV' fields to the database. + * Incremented the database version to 145. + * Added 'RDUser::addPodcast()', 'RDUser::setAddPodcast()', + 'RDUser::editPodcast()', 'RDUser::setEditPodcast()', + 'RDUser::deletePodcast()' and 'RDUser::setDeletePodcast()' methods + in 'lib/rduser.cpp'. + * Added 'Add Podcasts', 'Edit Podcasts' and 'Delete Podcasts' + controls to the RDAdmin->ManageUsers->EditUser dialog in + 'rdadmin/edit_user.cpp'. + * Implemented the add, edit and delete podcast privileges in + 'rdcastmanager/list_casts.cpp'. + * Fixed a bug in 'lib/rduser.cpp' that was causing the + 'RDUser::phone()' and 'RDUser::setPhone()' methods to fail. + * Added an 'Edit Feed Permissions' dialog in + 'rdadmin/edit_feed_perms.cpp'. + * Added an 'Enable All Users' checkbox in the Add Feed dialog in + 'rdadmin/add_feed.cpp'. +2007-10-08 Fred Gleason + * Added code in 'rdadmin/createdb.cpp' to fix database schema + errors introducted in '_POST' tables by schema update + 87. + * Incremented the database version to 146. + * Rearranged code in 'lib/rdsound_panel.cpp' and + 'rdadmin/test_import.cpp' so as to avoid generating false database + errors. +2007-10-08 Fred Gleason + * Fixed a bug in 'scripts/rd_backup' that was causing backups + older than the $SHELF_LIFE to fail to be purged. +2007-10-10 Fred Gleason + * Added a 'WEB_CONNECTIONS' table to the database. + * Added a 'USERS.ENABLE_WEB' field to the database. + * Incremented the database version to 147. + * Added an 'rdcastmanager' CGI applicaiton in + 'web/rdcastmanager/'. + * Added a CGI handler config for '*.cgi' files in + 'conf/rd-bin.conf.in'. + * Imported CGI handler functions from Lab into 'lib/rdweb.cpp'. + * Added 'RDUser::enableWeb()' and 'RDUser::setEnableWeb()' methods + in 'lib/rduser.cpp'. + * Added an 'Allow Web Logins' control to the Edit User dialog in + 'rdadmin/edit_user.cpp'. + * Fixed a bug in 'rdadmin/edit_user.cpp' where a user's password + could be inadvertently cleared. +2007-10-13 Dan Mills + * Added logging hooks to rddb.cpp and the appropriate code to the + applications to log DB trouble in the log files. +2007-10-13 Dan Mills + * Added caching of the timeOffset value in rdstation.cpp + This reduces the number of DB queries by a lot when logs are running. +2007-10-15 15:00 EDT Federico Grau + * pam_rd/pam_rd.cpp; update for RDUser::checkPassword() change of + interface. +2007-10-15 18:00 EDT Federico Grau + * icons/Makefile.am; modified to use $DESTDIR. +2007-10-17 Fred Gleason + * Fixed a bug in 'lib/lib.pro' that caused the build to break on + Windows. +2007-10-18 Dan Mills + * Fixed crash when setting to export audio as mp3 in + lib/rdexport_settings.cpp (Parameters of function in wrong order). +2007-10-18 Fred Gleason + * Fixed a bug in 'web/rdfeed/rdfeed.cpp' that was causing + truncated XML to be generated with feeds with no custom fields + defined. +2007-10-18 16:15 EDT Federico Grau + * rdlibrary/record_cut.cpp; corrected minor bug with evergreen + enable/disable of air start end date time and day parting controls. +2007-10-19 Fred Gleason + * Added a 'PODCASTS.AUDIO_TIME' field to the database. + * Incremented the database version to 147. + * Added 'RDPodcast::audioTime()' and 'RDPodcast::setAudioTime()' + methods in 'lib/rdpodcast.cpp'. + * Added a 'Length' column to the 'List Casts' dialog in + 'rdcastmanager/list_casts.cpp' + * Added a 'Length' column to the 'Podcasts' form page in + 'web/rdcastmanager/rdcastmanager.cpp'. + * Implemented an '%ITEM_AUDIO_TIME% wildcard in + 'web/rdfeed/rdfeed.cpp'. + * Added code to 'rdcastmanager/list_casts.cpp' to update the + 'PODCASTS.AUDIO_TIME' field when posting new podcasts. + * Added code to 'rdcatchd/rdcatchd.cpp' to update the + 'PODCASTS.AUDIO_TIME' field when posting new podcasts. +2007-10-19 Fred Gleason + * Modified the FTP methods in 'rdcatchd/rdcatchd.cpp' to use + lftp(1) instead of ftp(1). +2007-10-23 Fred Gleason + * Added a 'SWITCHER_NODES' table to the database. + * Incremented the database version to 149. + * Added a 'RDMatrix::LiveWire' member to the 'RDMatrix::Type' enum + in 'lib/rdmatrix.h'. + * Added a 'List LiveWire Nodes' dialog in + 'rdadmin/list_nodes.cpp'. + * Added an 'Edit LiveWire Node' dialog in + 'rdadmin/edit_node.cpp'. + * Added a 'Show LiveWire Node' dialog in + 'rdadmin/show_node.cpp'. + * Added a 'GpiLabel' class in 'utils/rdgpimon/gpi_label.cpp' + * Rewrote the RDGpiMon app to proerly handle non-contiguous GPI + line values. + * Updated 'docs/SWITCHERS.txt'. +2007-10-24 Fred Gleason + * Added code in 'rdadmin/edit_matrix.cpp' to update entries in the + 'GPIS' table to reflect accurately the number of configured GPI + lines in a matrix. +2007-10-26 Fred Gleason + * Fixed a bug in 'web/rdcastmanager/rdcastmanager.cpp' where all + feeds were being listed for remote users regardless of security + settings. +2007-10-26 Fred Gleason + * Fixed a bug in 'web/rdcastmanager/rdcastmanager.cpp' that was + causing the expiration date for casts to be displayed as 'Never' + regardless of the actual value. +2007-10-26 Fred Gleason + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that was causing a + segfault after importing audio. + * Fixed a bug in 'lib/rdcut.cpp' where importing a file with no + metadata was causing a database reconnect. +2007-10-27 Dan Mills + * Fixed bug in cae/cae.cpp where the data returned from LP on + error was in the wrong format for jack and alsa drivers. +2007-10-28 Dan Mills + * Modified lib/rdcardselector.cpp to do the right thing when a + card has zero ports of one type of the other. +2007-10-28 Fred Gleason + * Added an [Alsa] section in rd.conf(5). + * Added 'PeriodQuantity=' and 'PeriodSize=' parameters in the + [Alsa] section of rd.conf(5). + * Added 'RDConfig::alsaPeriodQuantity()' and + 'RDConfig::alsaPeriodSize()' methods in 'lib/rdconfig.cpp'. + * Modified 'cae/cae_alsa.cpp' to use configurable alsa parameters. + * Added an 'RDMeterAverage' class in 'lib/rdmeteraverage.cpp'. + * Implemented averaged meter ballistics for the ALSA driver + 'cae/cae_alsa.cpp'. + * Implemented averaged meter ballistics for the JACK driver + 'cae/cae_jack.cpp'. +2007-10-30 Fred Gleason + * Fixed an error in 'rdadmin/createdb.cpp' where a field was + omitted when creating the 'RDPANEL' table. +2007-10-30 Fred Gleason + * Fixed bugs in 'rdadmin/edit_rdlibrary.cpp', + 'rdadmin/edit_decks.cpp', 'rdadmin/edit_rdairplay.cpp', + 'rdadmin/edit_rdpanel.cpp' and 'rdadmin/rdlogedit.cpp' that was + causing the 'Port' audio selector setting to be set to 'None' + regardless of the actual value in the DB. +2007-10-30 Fred Gleason + * Fixed bugs in 'web/rdfeed/rdfeed.cgg' and + 'web/rdcastmanager/rdcastmanager.cpp' where '&', '<', '>', ''' and + '"' were not being escaped properly. +2007-11-03 Dan Mills + * Fixed hardcoded database name in rdadmin/rdadmin.cpp that was + stopping manual backup and restore working if the dbname was + not Rivendell. + * Fixed spurious db reconnect in lib/rdreport.cpp. + * Fixed misplaced brace in lib/rdplay_deck.cpp that was causing + spurious stop commands to be sent to caed. +2007-11-03 Dan Mills + * Added basic doxygen documentation system support, typing + "make doxygen" in the top level of the tree will create a directory + docs/programming/ with a subdirectory for each documented component. + The next job is to comment the code so doxygen can give intellegent + commentary. +2007-11-06 Fred Gleason + * Modfied 'rdcatchd/rdcatchd.cpp' and 'lib/rdpodcast.cpp' so as to + be able to upload and download files in the root directory of FTP + archives hosted on Microsoft IIS. +2007-11-07 Fred Gleason + * Enabled the 'Lock Tables' privilege when creating the Rivendell + database in 'rdadmin/opendb.cpp'. +2007-11-07 Fred Gleason + * Fixed a bug in 'lib/rdcddblookup.cpp' that was causing detection + of ISRC data to fail. +2007-11-07 Fred Gleason + * Fixed a bug in 'lib/rdedit_audio.cpp' that was causing the + Play Cursor start position to creep backwards over successive + plays. [Mantis bug #198] +2007-11-09 Fred Gleason + * Added 'MATRICES.IP_ADDRESS_2', 'MATRICES.IP_PORT_2', + 'MATRICES.PORT_TYPE_2', 'MATRICES.PORT_2', + 'MATRICES.USERNAME_2' and 'MATRICES.PASSWORD_2' field to the + database. + * Incrmeneted the database version to 150. + * Rearranged the 'Edit Matrix' dialog to clearly indicate Primary + and Backup connection parameters. + * Added the capability to interface with a backup Supervisor + instance in 'ripcd/vguest.cpp'. +2007-11-09 Fred Gleason + * Fixed a bug in 'rdlibrary/record_cut.cpp' that was causing the + cut daypart data to be cleared when opening the 'Record Cut' + dialog. +2007-11-12 Fred Gleason + * Fixed a bug in 'utils/rdgpimon/rdgpimon.cpp' that was causing + garbage cart numbers to be displayed for unassigned GPIs. + * Added an 'RDMatrix::NoPort' value to the 'RDMatrix::PortType' + enum in 'lib/rdmatrix.h'. + * Added the ability to specifiy no backup connection for the + vGuest driver in 'rdadmin/edit_matrix.cpp'. + * Fixed a bug in 'rdadmin/add_station.cpp' that was failing to + copy RDPanel config data from the exemplar. + * Removed debugging printf()s from 'lib/rdcardselector.cpp'. + * Removed obsolete 'HAVE_GPIO' ifdefs that broke local gpio + support. +2007-11-12 Fred Gleason + * Refactored code to eliminate spurious database reconnects in + 'lib/rdlog_event.cpp' and 'rdlogmanager/edit_event.cpp'. +2007-11-12 Fred Gleason + * Refactored code to eliminate spurious database reconnects in + 'lib/rdlog_event.cpp' and 'lib/rdclock.cpp'. + * Fixed a bug in 'rdlogmanager/edit_eventline.cpp' where adding an + event by means of typing in a name without exactly matching the + case of the event name would result in a corrupt clock record + [Mantis #229]. +2007-11-13 Fred Gleason + * Changed the behavior of the 'LL' ['Load Log'] RML so that + passing a '-2' for the start line argument will start the log at + the start only if the transition type of the first log event is + not 'stop'. + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + chained-to log to start even if its initial event had s Stop + transition. +2007-11-13 12:00 EST Federico Grau + * rdairplay/record_cut.cpp, rdairplay/loglinebox.h; added cut + description to the logline display. +2007-11-19 Fred Gleason + * Removed debugging printf() from 'lib/rdcardselector.cpp'. + * Fixed a bug in 'rdadmin/edit_matrix.cpp' that prevented the + opening of the Edit Gpis dialog. +2007-11-19 Fred Gleason + * Reverted a bug fix from 2006-11-20 in 'rdairplay/log_play.cpp' + that was causing invalid audio events to fail to be dismissed + after being started with a hard start time. + * Fixed a bug in 'rdairplay/log_play.cpp that was causing a + segfault when cleaning up after an attempt to play an + invalid event. +2007-11-19 Fred Gleason + * Fixed a race in 'rdairplay/log_play.cpp' that was causing Hard + Timed events to fail to be started if another event was started at + the same time [Mantis #237]. +2007-11-19 Fred Gleason + * Added a LogPlay::refreshStatusChanged() signal in + 'rdairplay/log_play.h'. + * Added a 'Refreshing Log' flag to RDAirPlay in + 'rdairplay/rdairplay.cpp' [Mantis #228]. +2007-11-20 Fred Gleason + * Fixed bugs in 'lib/rdaudio_ports.cpp' that were causing spurious + database reconnects when trying to load/save data for non-existent + ports. + * Added code in 'rdlibrary/record_audio.cpp' to disable the record + button in the Record/Info dialog if no valid input assignment is + defined in RDAdmin. + * Added code in 'lib/rdedit_audio.cpp' to disable the transport + buttons in the Edit Audio dialog if no valid output assignment is + defined in RDAdmin. + * Added code in 'rdcatch/rdcatch.cpp' to disable the Head and Tail + Audition buttons if no valid output assignment is defined in RDAdmin. + * Added code in 'lib/rdsimpleplayer.cpp' to disable the Play and Stop + if no valid output assignment is defined in RDAdmin. +2007-11-29 Fred Gleason + * Added code to create a 'rdfeed.mp3' symlink to 'rdfeed.xml' in + 'web/rdfeed/Makefile.am' and 'rivendell.spec.in'. + * Added functions for manipulating RSS feed logs in + 'lib/rdfeedlog.cpp'. + * Added a 'FEEDS.KEEP_METADATA' field to the database. + * Added 'RDFeed::keppMetadata()' and 'RDFeed::setKeepMetadata()' + methods in 'lib/rdfeed.cpp'. + * Incremented the database version to 151. + * Added a 'Pick Report Date' dialog in + 'rdcastmanager/pick_report_date.cpp'. + * Added a 'Keep Expired Metadata' checkbox to the Edit Feed dialog + in 'rdadmin/edit_feed.cpp'. + * Added a 'Keep Metadata' column to the 'List Feeds' dialog in + 'rdadmin/list_feeds.cpp'. + * Added a RDPodcast::StatusExpired' value to 'RDPodcast::Status' + in 'lib/rdpodcast.h'. + * Added 'whiteball.png' to the list of installed icons in + 'icons/Makefile.am'. + * Added 'Subscription Report' and 'Episode Report' buttons in + 'web/rdcastmanager/rdcastmanager.cpp'. +2007-12-05 Fred Gleason + * Added 'RDPANEL.CARD3', 'RDPANEL.PORT3', 'RDPANEL.START_RML3' and + 'RDPANEL.STOP_RML3' fields to the database. + * Incremented the database version to 152. + * Added audition start and stop buttons and a 'Send to Editor' + button to the 'Select Cart' dialog in 'lib/rdcart_Dialog.cpp'. + * Added a 'Sound Panel Cue Output' control to the 'Edit RDPanel' + dialog in 'rdadmin/edit_rdpanel.cpp'. + * Added 'RDAirPlayConf::editorPath()' and + 'RDAirPlayConf::setEditorPath()' methods in + 'lib/rdstation.cpp'. + * Added an 'Editor Command' control to the Edit Host dialog + in 'rdadmin/edit_station.cpp'. +2007-12-07 11:45 EST Federico Grau + * debian/control; added build dependency libqt3-mt-dev and added lame + binary dependency (for export to mp3 ability). + * debian/Makefile.am, debian/rivendell.docs.in, debian/rules; added + commands to include some more of the documentation files from the root + directory of the source tarball (AUTHORS, Changelog ...) + * debian/rules; added option for configure to install cgi-bin in FHS + location (/usr/ib/cgi-bin/rivendell). + * web/rdfeed/Makefile.am; modified to use $DESTDIR. +2007-12-9 Dan Mills + *lib/rdwavefile.cpp; Added code to (hopefully) make this work on + big endian hardware (PPC), alsa is still going to be broken, but + jack might now work. +2007-12-12 Fred Gleason + * Added an 'STATIONS.FILTER_MODE' field to the database. + * Added 'RDStation::filterMode()' and + 'RDStation::setFilterMode()' methods in 'lib/rdstation.cpp'. + * Added a 'Use Realtime Filtering' checkbox in the Edit Host + dialog in 'rdadmin/edit_station.cpp'. + * Implemented asynchronous filter searches in + 'rdlibrary/rdlibrary.cpp'. + * Implemented asynchronous filter searches in + 'rdlib/rdcart_dialog.cpp'. + * Fixed a bug in 'lib/rdcart_dialog.cpp' that was causing the + calling application to freeze when load a long cart list. + * Fixed a bug in 'lib/rdcut_dialog.cpp' that was causing the + calling application to freeze when load a long cart list. +2007-12-13 15:40 EST Federico Grau + * lib/rdcart_dialog.cpp; add check for empty RDListViewItem results. +2007-12-14 10:55 EST Federico Grau + * lib/rdcart_dialog.cpp; set to stop button to be red, matching other + Rivendell stop buttons. +2007-12-14 Fred Gleason + * Modified 'Makefile.am', 'configure.in' and 'rivendell.spec.in' + to support building on x86_64 architecture. +2007-12-14 Fred Gleason + * Changed RDLIBRARY_STEP_SIZE to 5000 in 'rdlibrary/rdlibrary.h'. + * Removed 'AR_HAVE_LIBRADIO' and 'AR_HAVE_LIBRHPI' macros from + 'acinclude.m4'. + * Added an 'AR_GET_DISTRO' macro in 'acinclude.m4'. + * Added a 'get_distro.sh' file. +2007-12-17 Fred Gleason + * Fixed broken library symlink for x86_64 architecture in + 'rivendell.spec.in'. +2007-12-21 12:20 EST Federico Grau + * rdlibrary/audio_cart.h, rdlibrary/edit_cart.h, rdlibrary/macro_cart.h; + removed unused attribute variable "rdcart_conf". +2007-12-22 Dan Mills + * Added error logging for setting RT scheduling, it no longer reports + sucess if there is a problem. +2007-12-24 Fred Gleason + * Fixed a bug in 'lib/rdsimpleplayer.cpp' that caused a playing + event to fail to be stopped when the player was destroyed. + * Modifed The Simple Player module in 'lib/rdsimpleplayer.cpp' to + allow a new selection to be played without explicitly stopping the + currently playing selection. +2007-12-24 Fred Gleason + * Fixed a font size mismatch in 'rdcastmanager/rdcastmanager.cpp'. + * Added an audio downloads column to the Podcast Subscription + Report in 'rdcastmanager/pick_report_dates.cpp'. + * Added an audio downloads column to the Podcast Subscription + Report in 'web/rdcastmanager/rdcastmanager.cpp'. +2007-12-26 12:45 EST Federico Grau + * cae/cae_alsa.cpp, cae/cae_hpi.cpp, cae/cae_jack.cpp; Added error logging + when there is a problem opening up a stream. +2007-12-26 16:45 EST Federico Grau + * rdlibrary/audio_cart.cpp, rdlibrary/audio_cart.h, + rdlibrary/edit_cart.cpp; extend support for 'Editor Command' to rdlibrary. +2007-12-27 Fred Gleason + * Applied a fixed-size font to the free space indicator in + 'rdlibrary/disk_bar.cpp'. +2007-12-27 10:05 EDT Federico Grau + * debian/changelog; updated in preparation for a new release 0.9.83. +2007-12-29 Fred Gleason + * Applied a patch by Stefan Gabriel that fixed + multiple bugs in the Voice Tracker. + * Removed a debugging printf in 'rdlogedit/voice_tracker.cpp'. + * Changed the text label on the 'No Segue Fade' checkbox in + 'lib/rdedit_audio.cpp'. +2007-12-29 Fred Gleason + * Added an 'RDLIBRARY.ENABLE_EDITOR' field to the database. + * Incremented the database version to 155. + * Added 'RDLibrary::enableEditor()' and + 'RDLibrary::setEnableEditor()' methods in + 'lib/rdlibrary_conf.cpp'. + * Added an 'Allow External Editing' control to the Edit RDLibrary + dialog in 'rdadmin/edit_rdlibrary.cpp'. + * Added logic in the Edit Audio Cart dialog to disable to 'Edit + Audio' button when the current user lacks appropriate rights in + 'rdlibrary/audio_cart.cpp'. +2007-12-31 Fred Gleason + * Refactored the Cart Picker dialog in 'lib/rdcart_dialog.cpp' to + allow use as a persistent object. + * Fixed a bug in 'lib/rdsimpleplayer.cpp' that was causing + audio stream leakage when starting another selection without + stopping the currently playing selection first. + * Fixed a bug in 'lib/rdcart_dialog.cpp' that was causing the + build to break under Windows. + * Modified 'rdlogedit/rdlogedit.cpp' to use 'RDInitDb()' to open + the database connection. +2008-01-02 Fred Gleason + * Fixed a bug in 'rdlogedit/rdlogedit.cpp that was causing a + segfault under Windows. +2008-01-02 Fred Gleason + * Modified SQL code in 'web/rdfeed/rdfeed.cpp' to serve RSS item + data in reverse date order. +2008-01-03 Fred Gleason + * Updated the 'NEWS' file. + * Updated the 'README' file. +2008-01-03 Fred Gleason + * Updated the 'rivendell.ism' file. + * Updated the package version to 0.9.83. +2008-01-03 Fred Gleason + * Fixed a bug in 'rdcastmanager/rdcastmanager.cpp' that was + causing a segfault on xf86_64 architecture. +2008-01-03 Fred Gleason + * Updated the 'NEWS' file. + * Updated the package version to 0.9.84. +2008-01-04 13:00 EST Federico Grau + * implemented several changes to the debian directory to make install + of Rivendell onto Ubuntu smoother. + * debian/control; added jackd as a recommended dependency. + * debian/rivendell.config; modified stdout,stderr redirect to be + "/bin/dash" compatible. + * debian/rivendell.postinst, debian/rivendell.postrm; added code to + detect the display manager in use (ex: kdm, gdm, xdm) automatically. + * debian/rivendell.init; modified code to create /var/run/rivendell + directories, regardless if starting the rivendell daemons via init + scripts or using pam_rd. +2008-01-04 18:45 EST Federico Grau + * rdairplay/log_line.cpp; added check to not delete invalid log lines. +2008-01-07 Fred Gleason + * Refactored the 'RDSoundPanel::SaveButton()' method to prevent a + possible corrupting MySQL race. +2008-01-16 Dan Mills + * Fixed waveform energy data creation on PPC. +2008-01-18 Fred Gleason + * Fixed a bug in 'rdcastmanager/list_feeds.cpp' that cause + cauasing manually generated uploaded to be normalized with + incorrect levels. +2008-01-18 Fred Gleason + * Refactored code in 'lib/rdcddblookup.cpp' to speed up CD access. +2008-01-18 Fred Gleason + * Applied a patch from 'pota' that fixed a bug where + reconciliation data was written to a non-existent table [Mantis + bug #241]. + * Fixed bugs in 'lib/rdsound_panel.cpp' that fixed a problem where + reconciliation data would fail to be recorded for macro cart + playouts. +2008-01-18 Fred Gleason + * Fixed a bug in 'rdairplay/local_macros.cpp' where case mangling + was being handled incorrectly with the log name argument of the + 'Load Log' ['LL'] RML [Mantis bug #208]. +2008-01-23 Fred Gleason + * Added an '%R' wildcard for Now & Next templates to generate + MS-DOS style newlines --e.g. CR/LF instead of just LF -- in + 'rdairplay/log_play.cpp'. +2008-01-30 13:20 EST Federico Grau + * rdadmin/edit_decks.cpp; correct label misplacement (channels), and + correct label text clipping ("Monitor defaults..."). +2008-02-04 16:15 EST Federico Grau + * rdadmin/edit_recording.cpp; added code so newly created recordings use + the default station/deck number of recording channels from rdadmin. +2008-02-15 10:55 EST Federico Grau + * pam_rd/pam_rd.cpp, docs/pam_rd.txt; corrected defect with pam_rd. + previously a user without rivendell credentials would be logged in to + Rivendell as the last successfully logged in user. Now, it logs in as + the default user "user", and can be configured differently via pam + configuration files. + Cleaned up code to fit CODING_STANDARDS (80 col). +2008-02-23 Fred Gleason + * Updated 'utils/rdhpiinfo/rdhpiinfo.cpp' and + 'utils/rdhpiinfo/change_mode.cpp' so RDHpiInfo properly reports + Multichannel Surround mode for the ASI6585. +2008-02-27 Fred Gleason + * Added code in 'utils/rddbcheck/rddbcheck.cpp' to check database + consistency between the 'CLOCKS' and _CLK tables. + * Added code in 'utils/rddbcheck/rddbcheck.cpp' to check database + consistency between the 'EVENTS' and _PRE and _POST tables. +2008-03-01 Dan Mills + * Added code to cae/cae_jack.cpp to check ranges of port and + stream parameters to avoid a crash in the card=0, port = -1 case. +2008-03-02 Dan Mills + * Fixed crash in rdcatchd the first time it is run with a new DB. + lib/rdcatch_conf.cpp - attempt to free sql query twice. +2008-03-02 Dan Mills + * Ammended rdadmin/opendb.cpp to use QSqlQuery rather then RDSqlQuery + to avoid a problem with recursive calls in RProfile. +2008-03-03 Fred Gleason + * Added notes in 'rivendell.sys' to indicate the options for + controlling jackd behavior are deprecated. +2008-03-11 15:26 EDT Federico Grau + * rdlogedit/edit_log.cpp; minor fix in parent widget hierarchy. +2008-03-18 Fred Gleason + * Added a 'MATRICES.LAYER' field to the database. + * Added a 'Layer' control in 'rdadmin/edit_matrix.cpp'. + * Added a switcher driver for the Quartz Type 1 Switcher protocol + in 'ripcd/quartz1.cpp'. + * Added notes on the Quartz Type 1 driver in 'docs/SWITCHERS.txt'. +2008-03-19 Fred Gleason + * Changed the text of the 'No Segue Fade' control in + 'lib/rdedit_audio.cpp' to 'No Fade on Segue Out'. + * Changed the text of the 'No Segue Fade' control in + 'rdairplay/edit_event.cpp' to 'No Fade on Segue Out'. + * Fixed a typo that caused automatic source and destination + node names to fail in the Quartz1 driver in 'ripcd/quartz1.cpp'. +2008-03-21 Dan Mills + * Fixed a bug in rdlogmanager/edit_event.cpp that was causing + a segfault if no configuration changes had been made to + rdlogmanager on a new db. +2008-03-21 Dan Mills + * Modified rdadmin/create_db.cpp to set some minimally sane defaults + and default group names that should serve as an example. +2008-03-24 Fred Gleason + * Fixed a bug in 'ripcd/quartz.cpp' that transposed the source and + destination values. + * Disabled the automatic source and destination read routines in + 'ripcd/quartz1.cpp. +2008-03-24 Fred Gleason + * Modified 'rdadmin/edit_matrix.cpp' to permit dual connections to + be configured for the Quartz1 driver. + * Refactored 'ripcd/quartz1.cpp' to support dual redundant + connections. +2008-03-24 Fred Gleason + * Fixed a bug in 'rdadmin/edit_matrix.cpp' that was failing to + save the IP address for the second TCP/IP connection for + non-vGuest devices. + * Removed a debugging printf in 'ripcd/local_gpio.cpp'. +2008-03-26 Fred Gleason + * Added rdsoftkeys(1) to the Win32 install in 'rivendell.ism'. +2008-03-27 Fred Gleason + * Added a 'LIVEWIRE_START' switch to 'rivendell.sys'. + * Implemented the 'LIVEWIRE_START' sysconfig switch in + 'rivendell-suse.in'. + * Added an 'alsasound' start dependency in 'rivendell-suse.in'. +2008-03-28 Fred Gleason + * Added a '[Logs]' section in rd.conf(5). + * Added 'Facility=', 'LogDirectory=', 'CoreDumpDirectory=' and + 'LogPattern=' directives to the '[Logs]' section in rd.conf(5). + * Added 'RDConfig::logDirectory()', + RDConfig::logCoreDumpDirectory()', 'RDConfig::logPattern()', + and 'RDConfig::RDConfig::log()' methods in 'lib/rdconfig.cpp'. + * Modified 'rdairplay/rdairplay.cpp' and /rdairplay/log_play.cpp' + to use the new logging infrastructure. + * Modified 'cae/cae.cpp', 'cae/cae_alsa.cpp', 'cae/cae_hpi.cpp' + and 'cae/cae_jack.cpp' to use the new logging infrastructure. +2008-03-29 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that caused a segfault + when loading/unloading a log while a Sleep [SP] macro was running + [Mantis bug #245]. +2008-04-01 Fred Gleason + * Added translations for French (fr) and German (de). + * Updated the 'helpers/rdtrans.sh' script. +2008-04-01 16:50 EST Federico Grau + * docs/tables/stations.txt lib/dbversion.h lib/rdadd_log.cpp + lib/rdadd_log.h lib/rdbutton_dialog.cpp lib/rdgroup_list.cpp + lib/rdgroup_list.h lib/rdlist_logs.cpp lib/rdlist_logs.h + lib/rdstation.cpp lib/rdstation.h lib/rduser.cpp lib/rduser.h + rdadmin/createdb.cpp rdadmin/edit_rdairplay.cpp + rdadmin/edit_station.cpp rdadmin/edit_station.h + rdairplay/list_logs.cpp rdairplay/rdairplay.cpp rdlogedit/edit_log.cpp + rdlogedit/list_logs.cpp rdlogedit/rdlogedit.cpp + rdlogmanager/edit_perms.cpp rdlogmanager/generate_log.cpp + rdlogmanager/list_clocks.cpp rdlogmanager/list_events.cpp + rdlogmanager/list_grids.cpp rdlogmanager/list_svcs.cpp + rdlogmanager/rdlogmanager.cpp; added user security option for the + broadcast applications of rivendell, with an rdadmin to toggle this + behaviour on per host/station. +2008-04-02 Fred Gleason + * Disabled random cut rotation in 'lib/rdcart.cpp'. + * Hide the 'Schedule Cuts' control in 'rdlibrary/edit_cart.cpp'. +2008-04-02 10:50 EST Federico Grau + * rdadmin/edit_station.cpp; label text update. +2008-04-02 Fred Gleason + * Changed the text of the 'No Segue Fade at Event End' control in + 'rdlogedit/edit_logline.cpp' to 'No Fade on Segue Out'. + * Added code in 'rdadmin/createdb.cpp' to convert OVERLAP + transitions to SEGUE with the 'No Fade' attribute set. + * Incremented the database version to 158. + * Removed 'RDLogLine::Overlap' from the 'RDLogLine::TransType' + enum in 'lib/rdlog_line.h'. +2008-04-03 09:35 EST Federico Grau + * docs/tables/displays.txt; removed, as this table is no longer used. +2008-04-03 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp that was causing a + segfault if a Refresh [RL] RML was received while executing Sleep + [SP] RML [Mantis bug #248]. +2008-04-03 Fred Gleason + * Removed 'docs/tables/displays.txt' from the files list in + 'rivendell.spec.in'. +2008-04-03 10:50 EST Federico Grau + * make_slack.in, docs/tables/Makefile.am; removed references to + displays.txt (rookie mistake on my part :-/ ) +2008-04-03 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp' that killed database + reconnect logging. + * Tweaked layout of the label for the 'Autotrim Level' control in + 'rdadmin/edit_deck.cpp'. + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' where the last cart in + the cart list was failing to have it's validity color set properly + [Mantis bug #204]. +2008-04-03 Fred Gleason + * Fixed a bug in 'rdcatch/rdcatch.cpp' that was preventing the + 'List Reports' dialog from being opened. +2008-04-03 Fred Gleason + * Added a sleep delay after starting the ASI driver in + 'rivendell-suse.in'. +2008-04-09 Fred Gleason + * Added code in 'rdairplay/log_play.cpp' to defer execution of a + log refresh while executing a Sleep [SP] RML [Mantis bug #249]. +2008-04-09 Fred Gleason + * Fixed a bug in 'rdairplay/pie_counter.cpp' that was causing the + countdown digit background to have the wrong background color + during talk countdowns when the on-air flag was set [Mantis bug + #250]. +2008-04-09 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that caused playouts longer + than 1:11:34.9 to lock up when using timescaling [Mantis bug + #212]. +2008-04-09 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that caused custom segue + transitions to ignore timescaling [Mantis bug #202]. +2008-04-09 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that caused Hook playouts + in RDSoundPanel to be incorrect when timescaling was active. +2008-04-09 Fred Gleason + * Fixed a bug in 'lib/rdconfig.h' that was causing the build to + break on Windows. + * Fixed a bug in 'lib/rdcmdswitch.cpp' that was causing the build to + break on Windows. +2008-04-10 Fred Gleason + * Updated 'conf/rd.conf-sample'. + * Updated 'conf/rd.conf-complete-sample'. + * Updated 'conf/rd-sample.ini'. + * Updated the 'NEWS' file. + * Removed the BETA warning from 'README'. + * Updated 'SupportedCards'. + * Updated 'ToDo'. + * Updated 'rivendell.ism'. + * Incremented the package version to 1.0.0rc0. +2008-04-10 10:05 EDT Federico Grau + * debian/changelog; updated for new release. +2008-04-15 13:15 EDT Federico Grau + * docs/tables/Makefile.am; add to Makefile.am recently added table + documentation files. +2008-04-16 10:15 EDT Federico Grau + * lib/rdlist_logs.cpp; remove duplicate assignment. +2008-04-16 16:26 EDT Federico Grau + * lib/rdsound_panel.h; remove duplicate include statements. +2008-04-17 15:25 EDT Federico Grau + * rdadmin/list_svcs.cpp: correct comment. +2008-04-17 16:30 EDT Federico Grau + * rdadmin/opendb.cpp: format code to fit 80 col. +2008-04-18 11:10 EDT Federico Grau + * rdcastmanager/rdcastmanager.cpp: free cast_user if needed before + re-assigning. +2008-04-20 Fred Gleason + * Added 'RDAIRPLAY.SKIN_PATH' and 'RDPANEL.SKIN_PATH' fields to + the database. + * Incremented the database version to 159. + * Added 'RDAirPlayConf::skinPath()' and + 'RDAirPlayConf::setSkinPath()' methods in + 'lib/rdairplay_conf.cpp'. + * Added a 'Background Image' control in + 'rdadmin/edit_rdairplay.cpp' and 'rdadmin/edit_rdpanel.cpp'. + * Implemented background image display for RDAirPlay(1) and + RDPanel(1). +2008-04-21 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing the + scrollbars and pie widget in RDAirPlay to stop advancing when + playing near the end of a time-streteched event. +2008-04-21 Fred Gleason + * Fixed a bug in 'lib/rdslider.cpp' that was causing incorrect + slider positions to be reported for large position values [Mantis + bug #223]. +2008-04-21 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that was causing a + segfault when seven events were active simultaneously [Mantis bug + #219]. +2008-04-21 Fred Gleason + * Added logic in 'lib/rdplay_deck.cpp' and 'lib/rdlog_line.cpp' to + handle playouts properly with timescaling outside of the supported + range [Mantis bug #146]. +2008-04-22 Fred Gleason + * Added checks in 'rdairplay/rdairplay.cpp' and + 'rdpanel/rdpanel.cpp' to verify that the background image is at + least 1024x738 before using it. +2008-04-22 16:00 EDT Federico Grau + * pam_rd/pam_rd.cpp, rdcastmanager/rdcastmanager.cpp, + rdlogedit/rdlogedit.cpp: replaced string constants with global #define. +2008-04-24 Fred Gleason + * Updated 'NEWS'. + * Updated 'rivendell.ism'. + * Updated the package version to 1.0.0rc1. +2008-04-25 Fred Gleason + * Reverted the bugfix for Mantis bug #202, which broke proper + segue timing when timescaling was active. +2008-05-07 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that caused database + corruption when creating/updating a database on MySQL 4.x. +2008-05-08 Fred Gleason + * Fixed a bug in 'lib/rdplay_deck.cpp' that was causing the end of + audio events to be truncated when played with timescaling applied + and a non-zero Start Marker. + * Corrected the timescaling limit values in 'lib/rd.h' and + 'rdhpi/rdplaystream.h' to reflect actual limits enforced by the + HPI driver. +2008-05-12 Fred Gleason + * Changed the semantics of the 'Play' ['PY'] command in + 'docs/cae.sxw' to specify the 'speed' parameter in thousandths of + a percent rather than tenths of a percent. + * Added an 'RD_TIMESCALE_DIVISOR' define 'lib/rd.h'. + * Updated 'rdhpi/rdplaystream.cpp' to use 'RD_TIMESCALE_DIVISOR'. + * Updated 'lib/rdplay_deck.cpp' to use 'RD_TIMESCALE_DIVISOR'. + * Updated 'lib/rdedit_audio.cpp' to use 'RD_TIMESCALE_DIVISOR'. + * Updated 'lib/rdsimpleplayer.cpp' to use 'RD_TIMESCALE_DIVISOR'. + * Updated 'rdlibrary/record_cut.cpp' to use 'RD_TIMESCALE_DIVISOR'. + * Updated 'rdcatch/rdcatch.cpp' to use 'RD_TIMESCALE_DIVISOR'. + * Updated 'rdcatchd/rdcatchd.cpp' to use 'RD_TIMESCALE_DIVISOR'. +2008-05-12 Fred Gleason + * Updated 'docs/NOW&NEXT.txt'. +2008-05-12 Fred Gleason + * Applied a patch from 'pota' that removed the ability to specify + a Forced Length for macro carts [Mantis bug #251]. +2008-05-12 Fred Gleason + * Updated 'cae/cae_alsa.cpp' to use 'RD_TIMESCALE_DIVISOR'. + * Updated 'cae/cae_jack.cpp' to use 'RD_TIMESCALE_DIVISOR'. +2008-06-13 Fred Gleason + * Added an 'RDChunk' utility in 'utils/rdchunk/'. + * Added an RDWaveFile::Ambos file type in 'lib/rdwavefile.h' and + 'lib/rdwavefile.cpp'. +2008-06-24 Fred Gleason + * Added code to 'utils/rddbcheck/rddbcheck.cpp' to check for and + delete orphaned tables in the database. + * Relocated code to create *_STACK tables from + 'rdlogmanager/generate_log.cpp' to 'lib/rdcreate_log.cpp'. +2008-06-26 Fred Gleason + * Fixed a bug in 'rdcastmanager/list_casts.cpp' that was failing + to clean up temporary files after posting audio from a file. +2008-07-07 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 1.0.0rc2. +2008-07-15 Fred Gleason + * Fixed a bug in 'lib/rdescape_string.cpp' and + 'lib/rdsound_panel.cpp' that caused corruption of sound panel + button assignments when backslash characters were used in button + labels. +2008-07-18 Fred Gleason + * Added a Rivendell import filter in + 'importers/rivendell_filter.cpp'. +2008-07-18 Stefan Gabriel + * Moved code to create *_STACK tables brach to + 'rdlogmanager/generate_log.cpp'. + Note: Stack Tables are not linked to Logs, but to Services; they + are the schedulers history of selected carts. + * Fixed a bug with waveform cursor and samplerate conversion in + cae/cae_hpi.cpp, cae/cae_alsa.cpp, cae/cae_jack.cpp and + lib/rdedit_audio.cpp + * Fixed a bug in lib/rdsimpleplayer.cpp; simpleplayer played on + more then one port under some conditions + * Fixed a bug in rdlogedit/voice_tracker.cpp: added missing + destructors for wavepainters wpg[i] + * Fixed a bug in rdlibrary/edit_cart.cpp that caused a segfault + when editing more than one cart. +2008-07-21 Fred Gleason + * Modified 'lib/rdwavedata.cpp', 'lib/rdwavefile.cpp' and + 'lib/rd_cut.cpp' to handle metadata that specifies start and + position of End, Segue and Talk marker data. +2008-07-21 Fred Gleason + * Added '*.qm' to the 'CLEANFILES=' rule in 'rdhpi/Makefile.am'. +2008-07-22 Fred Gleason + * Fixed a bug in 'get_distro.sh' to was failing to detect SuSE 9.2 + properly. +2008-07-22 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version 1.0.0rc3. +2008-07-22 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' that caused imported cuts to be + assigned an incorrect start and end date. +2008-07-22 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 1.0.0rc4. +2008-07-25 Fred Gleason + * Fixed a bug in 'lib/rdcmd_switch.cpp' that broke the build with + gcc-4.3.1. + * Fixed a bug in 'lib/rdlivewire.cpp' that broke the build with + gcc-4.3.1. + * Fixed a bug in 'rdadmin/edit_user.h' that broke the build with + gcc-4.3.1. + * Fixed a bug in 'rdadmin/edit_group.h' that broke the build with + gcc-4.3.1. + * Fixed a bug in 'rdadmin/edit_svc.h' that broke the build with + gcc-4.3.1. + * Fixed a bug in 'rdadmin/edit_schedcodes.h' that broke the build with + gcc-4.3.1. + * Fixed a bug in 'rdadmin/list_feeds.cpp' that broke the build with + gcc-4.3.1. + * Fixed a bug in 'rdadmin/edit_feed.h' that broke the build with + gcc-4.3.1. + * Fixed a bug in 'rdadmin/ripcd/local_macros.cpp' that broke the + build with gcc-4.3.1. + * Fixed a bug in 'rdlogin/rdlogin.cpp' that broke the build with + gcc-4.3.1. + * Fixed a bug in 'rdlogmanager/rdlogmanager.cpp' that broke the + build with gcc-4.3.1. + * Fixed a bug in 'rdlogmanager/generate_log.cpp' that broke the + build with gcc-4.3.1. + * Fixed a bug in 'utils/rdgpimon/rdgpimon.cpp' that broke the + build with gcc-4.3.1. + * Fixed a bug in 'utils/rdfilewrite/rdfilewrite.cpp' that broke the + build with gcc-4.3.1. + * Fixed a bug in 'utils/rdsoftkeys/rdsoftkeys.cpp' that broke the + build with gcc-4.3.1. +2008-07-31 Fred Gleason + * Added an 'RD_MAX_YEAR' parameter in 'lib/rd.h'. + * Fixed a bug in 'lib/rdwavefile.cpp' where reading a Cart Chunk + structure containing a date with a year later than 8000 AD would + result in an invalid date. +2008-07-31 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' where importing audio + into an existing cut would fail properly to clear the old cut + data. +2008-08-04 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that caused log schedule records + whose title contained a quotation mark to fail to import properly. + * Modified 'rdadmin/edit_svc.cpp' to allow the length of the + 'title' field of log import files to be up to 255 characters + long. +2008-08-04 Fred Gleason + * Modified 'lib/rdcart.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdcut.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdairplay_conf.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rddeck.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rddropbox.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdevent.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdevent_line.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdgroup.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdlibrary_conf.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdlog.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdlogedit_conf.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdmatrix.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdrecording.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdreport.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdstation.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdtty.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rduser.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdconf.cpp' to allow use of string values + containing special characters. + * Modified 'lib/rdcatch_conf.cpp' to allow use of string values + containing special characters. + * Modified 'rdlibrary/edit_cart.cpp' to allow use of special + characters in cart metadata. + * Modified 'rdlibrary/record_cut.cpp' to allow use of special + characters in cart metadata. + * Modified 'rdairplay/log_traffic.cpp' to allow use of special + characters in cart metadata. + * Modified 'rdlogmanager/edit_event.cpp' to allow use of special + characters in library search strings. + * Modified 'rdlogmanager/edit_clock.cpp' to allow use of special + characters in library search strings. +2008-08-05 Fred Gleason + * Applied a patch by Stefan Gabriel that fixed + problems with importing files with names containing UTF-8 encoded + characters. +2008-08-08 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 1.0.0rc5. +2008-08-18 Fred Gleason + * Fixed a bug in 'rdlibrary/cdripper.cpp' and + 'rdlibrary/disk_ripper.cpp' that caused ripped cuts to show + incorrect lengths. +2008-08-18 Fred Gleason + * Fixed a bug in 'cae/cae.cpp' that broke the build when compiling + without JACK support. +2008-08-18 Fred Gleason + * Fixed a bug in 'rivendell' that caused a syntax error on Slackware. + * Updated 'make_slack.in'. +2008-08-18 Fred Gleason + * Fixed a bug in 'lib/rdescape_string.cpp' that handled spaces + incorrectly. + * Fixed a bug in 'rdadmin/edit_station.cpp' that incorrectly + escaped characters for the 'Editor Path' value. +2008-08-19 Fred Gleason + * Reverted a fix in 'lib/rdescape_string.cpp' that handled spaces + incorrectly. +2008-08-19 Fred Gleason + * Updated the 'NEWS' file. + * Updated the package version to 1.0.0rc6. +2008-08-25 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 1.0.1. +2008-09-02 Fred Gleason + * Added code in 'web/rdfeed/rdfeed.cpp' to log http Range: + headers. + * Added a '/.qt/' directory in 'rivendell.spec.in'. + * Fixed a bug in 'web/rdfeed/rdfeed.cpp' that was counting + each incremental http data transfer as a separate download. +2008-09-06 Fred Gleason + * Updated 'make-slack.in' to install icons in the proper location. +2008-09-09 Dan Mills + * Tweaked new database creation to set library playout to card 0 port + 0 by default. +2008-09-09 Dan Mills + * Applied patch from Stefan Gabriel correcting a + signedness issue in the button labelling code that could cause an + rdairplay lockup. Also found another instance a few lines below. + lib/rdlabel.cpp +2008-09-18 Fred Gleason + * Added 'ENCODERS', 'ENCODER_CHANNELS', 'ENCODER_SAMPLERATES', + 'ENCODER_BITRATES' tables to the database. + * Incremented the database version to 160. + Added 'Add Encoder', 'List Encoders' and 'Edit Encoder' dialogs in + 'rdadmin/add_encoder.cpp', 'rdadmin/list_encoders.cpp' and + 'rdadmin/edit_encoder.cpp'. + * Added an 'RDIntegerEdit' widget in 'lib/rdintegeredit.cpp'. + * Added an 'RDIntegerDialog' dialog in 'lib/rdintegerdialog.cpp'. + * Modified 'scripts/rd_export_audio' to handle custom encoders. + * Added code to display custom encoder types in + 'rdadmin/view_adapters.cpp'. + * Modified 'rdcatch/edit_upload.cpp' to handle custom encoder + types properly. + * Modified 'rdcatchd/rdcatchd.cpp' to handle custom encoder types + properly. + * Modified 'rdcastmanager/list_casts.cpp' to handle exports of + custom encoder types properly. + * Added a 'docs/ENCODERS.txt' file. +2008-09-23 Fred Gleason + * Fixed a regression in 'rdcastmanager/list_casts.cpp' that made + it impossible to post content to a feed using a built-in encoder. + * Added a warning in the 'List Encoders' dialog in + 'rdadmin/list_encoders.cpp' when deleting an encoder that is in + use by one or more RSS feeds. +2008-09-26 Fred Gleason + * Added a 'FEEDS.UPLOAD_EXTENSION' field to the database. + * Added 'RDFeed::uploadExtension()' and + 'RDFeed::setUploadExtension()', methods in 'lib/rdfeed.cpp'. + * Modified 'web/rdfeed/rdfeed.cpp' to assign the audio file + extension dynamically. + * Updated the 'docs/PODCASTING.txt' file. +2008-09-30 Fred Gleason + * Added a 'GPOS' table to the database. + * Changed the default value for the 'GPIS.MACRO_CART' field from + '-1' to '0'. + * Incremented the database version to 162. + * Added a 'Configure GPOs' button to the 'Edit Switcher' dialog in + 'rdadmin/edit_matrix.cpp'. + * Added an 'RDOneShot' class in 'lib/rdoneshot.cpp'. + * Modified the BroadcastTools SS8.2 driver in 'ripcd/btss82.cpp' + to work properly with the new GPIO RMLs. + * Modified the BroadcastTools ACS8.2 driver in 'ripcd/btacs82.cpp' + to work properly with the new GPIO RMLs. + * Modified the BroadcastTools 16x2 driver in 'ripcd/bt16x2.cpp' + to work properly with the new GPIO RMLs. + * Modified the BroadcastTools SS16.4 driver in 'ripcd/btss164.cpp' + to work properly with the new GPIO RMLs. + * Modified the BroadcastTools SS4.2 driver in 'ripcd/btss42.cpp' + to work properly with the new GPIO RMLs. + * Modified the SAS 64000gpi driver in 'ripcd/sas64000gpi.cpp' + to work properly with the new GPIO RMLs. + * Modified the SAS USI driver in 'ripcd/sasusi.cpp' to work + properly with the new GPIO RMLs. + * Modified the Local GPIO driver in 'ripcd/local_gpio.cpp' to work + properly with the new GPIO RMLs. + * Added an additional argument to the 'GI' and 'GO' commands in + 'docs/ripc.txt'. + * Added an 'RDRipc::setIgnoreMask()' method in 'lib/rdripc.cpp'. + * Added code in 'ripcd/local_macros.cpp' to upconvert old forms of + the 'GE', 'GI' and 'GO' RMLs to the new syntax. +2008-10-01 Fred Gleason + * Fixed a bug in 'ripcd/local_gpio.cpp' that broke the build on + x86_64 architecture. + * Fixed a bug in 'ripcd/btss82.cpp' that broke the build on + x86_64 architecture. + * Fixed a bug in 'ripcd/btacs82.cpp' that broke the build on + x86_64 architecture. + * Fixed a bug in 'ripcd/bt16x2.cpp' that broke the build on + x86_64 architecture. + * Fixed a bug in 'ripcd/btss164.cpp' that broke the build on + x86_64 architecture. + * Fixed a bug in 'ripcd/btss42.cpp' that broke the build on + x86_64 architecture. + * Fixed a bug in 'ripcd/livewire.cpp' that broke the build on + x86_64 architecture. +2008-10-01 Fred Gleason + * Fixed a bug in 'ripcd/livewire.cpp' that broke GPIO updates when + state was changed via the 'GO' RML. +2008-10-01 Fred Gleason + * Added the 'Record Start' ['RS'] and 'Record Stop' ['RR'] RMLs in + 'lib/rdmacro.cpp. + * Added an 'RDeck::isActive()' method in 'lib/rddeck.cpp'. + * Added an 'RDCATCHD_DYNAMIC_BASE_ID' define in 'lib/rd.h'. +2008-10-08 Fred Gleason + * Added an 'RDLogEvent::lengthToStop()' method in + 'lib/rdlog_event.cpp'. + * Added time length counters to the Edit Log dialog in + 'rdlogedit/edit_log.cpp'. +2008-10-8 Dan Mills + * Fixed segfault in rdimport when importing a .wav with both + TMCentury and an APE tag. lib/rdwavefile.cpp, short circuit + evaluation was the wrong way around. +2008-10-10 Fred Gleason + * Added code in 'lib/rdwavefile.cpp' to read metadata from an + 'av10' chunk (proprietary BE AudioVault format). + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that was causing + the 'fix-broken-formats' switch to fail to repair corrupt chunk + sizes consistently. +2008-10-10 Fred Gleason + * Modified code in 'lib/rdwavefile.cpp' to more reliably and + consistently detect metadata in an 'av10' chunk. +2008-10-10 Fred Gleason + * Fixed a bug in 'lib/rdwavefile.cpp' that was causing 'Category' + data in av10 chunks to be processed as 'Class'. +2008-10-16 Fred Gleason + * Added the ability to import OutCue data from the 'av10' chunk in + 'lib/rdwavefile.cpp'. +2008-10-16 Fred Gleason + * Added code in 'lib/rdwavefile.cpp' to validate pointer + metadata to ensure consistent values. +2008-10-21 Fred Gleason + * Fixed a fencepost error in calculating runtimes for selected + events in the Edit Log dialog in 'rdlogedit/edit_log.cpp'. +2008-10-23 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 1.1.0. +2008-10-24 Fred Gleason + * Fixed a bug in 'rdlogmanager/edit_clock.cpp' that caused + incomplete data to be saved when doing a 'Save As' with a clock + name that contained spaces. +2008-10-24 Fred Gleason + * Fixed a bug in 'rdlogmanager/add_clock.cpp' that caused a + segfault when creating a clock with a name longer than 58 + characters. + * Fixed a bug in 'rdlogmanager/add_event.cpp' that caused a + segfault when creating an event with a name longer than 58 + characters. +2008-10-28 Fred Gleason + * Disabled debugging statements in 'lib/rdcart.cpp'. +2008-10-28 Fred Gleason + * Removed 'Overlap' from the list of transition types in + 'rdadmin/edit_rdairplay.cpp' and 'rdadmin/edit_rdlogedit.cpp'. +2008-11-04 Fred Gleason + * Fixed a bug in 'lib/rdlistselector.h' that caused services with + a common starting character sequence in their names to fail to + show up in the 'Available Services' box in the + RDAdmin->ManagerReports->Edit Report dialog. +2008-11-06 Fred Gleason + * Added support for the '^' conversion flag for date wildcards in + 'lib/rddatedecode.cpp' [as per date(1)]. +2008-11-07 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' where a deferred hard + start would cancel a later, explicitly scheduled hard start. +2008-11-07 Fred Gleason + * Added code in 'ripcd/local_macros.cpp' to log GPIO state + transitions. +2008-11-11 Fred Gleason + * Updated 'NEWS'. + * Updated the copyright date in 'rdadmin/info_dialog.cpp'. + * Incremented the package version to 1.1.1. +2008-11-13 Fred Gleason + * Applied a patch from Alban Peignier + that fixed a bug in 'lib/rdconf.cpp' that broke the build under + Debian. +2008-11-13 Fred Gleason + * Applied a patch from Eliot Blennerhassett + that fixed a bug in + 'lib/rdhpisoundcard.cpp' that broke the build when built against + ASI drivers versions >= 3.09.xx. +2008-11-14 Fred Gleason + * Added a 'RECORDINGS.EVENTDATE_OFFSET' field to the database in + 'rdadmin/createdb.cpp'. + * Incremented the database version to 163 in 'lib/dbversion.h'. + * Added 'RDRecording::eventdateOffset()' and + 'RDRecording::setEventdateOffset()' methods in 'lib/rdrecording.h' + and 'lib/rdrecording.cpp'. + * Added an 'Event Offset' control to the 'Edit Upload' dialog in + 'rdcatch/edit_upload.h' and 'rdcatch/edit_upload.cpp'. + * Added an 'Event Offset' control to the 'Edit Download' dialog in + 'rdcatch/edit_download.h' and 'rdcatch/edit_download.cpp'. + * Added 'CatchEvent::eventdateOffset()' and + 'CatchEvent::setEventdateOffset()' methods in + 'rdcatchd/catch_event.cpp' and 'rdcatchd/catch_event.h'. + * Implemented event date offset for uploads and downloads in + 'rdcatchd/rdcatchd.cpp'. +2008-11-19 Fred Gleason + * Fixed a bug in 'rdcatch/edit_upload.cpp' that caused the + 'Normal: Level' setting to be saved incorrectly. +2008-11-19 Fred Gleason + * Fixed a bug in 'lib/rdsoundpanel.cpp' that caused Hook Mode + playouts to be incorrect for cuts with a non-zero Start Marker + value. +2008-11-19 Fred Gleason + * Refactored code in 'rdairplay/post_counter.cpp', + 'rdairplay/post_counter.h', 'rdairplay/log_play.cpp', + 'rdairplay/log_play.h' and 'rdairplay/rdairplay.cpp' to allow + hard-timed events to execute even if they are not in chronological + order in alog. +2008-11-20 Fred Gleason + * Modified the 'Select Cart' dialog in 'lib/rdcart_dialog.cpp' and + 'lib/rdcart_dialog.h' to be resizable. +2008-11-20 Fred Gleason + * Added a 'scripts/start_traverso.sh' script. +2008-11-21 Fred Gleason + * Added a 'NOWNEXT_PLUGINS' table to the database. + * Incremented the database version to 164. + * Added 'rdairplay/nownext.cpp'. + * Created an 'RLMHost' class in 'rdairplay/rlmhost.cpp' and + 'rdairplay/rlmhost.h'. + * Added an 'rlm/' directory. + * Created an Rivendell Load Module API definition in 'rlm/rlm.h'. + * Added a sample RLM module in 'rlm/rlm.test.c'. +2008-11-25 Fred Gleason + * Added an 'RDResolveNowNext()' function in 'lib/rdnownext.cpp' + and 'lib/rdnownext.h'. + * Added a Loadable Module in 'rlm/rlm_serial.c'. +2008-11-25 Fred Gleason + * Added a sample configuration for the 'rlm_serial' RLM in + 'conf/rlm_serial.conf'. + * Added an example makefile in 'rlm/Makefile-example. + * Added a '-devel' subpackage in 'rivendell.spec.in'. +2008-11-25 Fred Gleason + * Fixed a typo in 'rivendell.spec.in'. +2008-11-26 Fred Gleason + * Changed the 'unsigned' types to 'uint32_t' in the 'rlm_pad' + struct in 'rlm/rlm.h'. + * Added an 'int onair' parameter to the 'RLMPadDataSent' callback + in 'mrlm/rlm.h'. + * Updated the 'rlm_test' plugin in 'rlm/rlm_test.c' to use the + revised callback interface. + * Updated the 'rlm_serial' plugin in 'rlm/rlm_serial.c' to use the + revised callback interface. +2008-11-29 Fred Gleason + * Added a 'DROPBOX_PATHS' table to the database. + * Added 'DROPBOXES.STARTDATE_OFFSET', 'DROPBOXEs.ENDDATE_OFFSET' + and 'DROPBOXES.DELETE_SOURCE' fields to the database. + * Incremented the database version to 165. + * Added 'RDDropbox::deleteSource()', + 'RDDropbox::setDeleteSource()', 'RDDropBox::startdateOffset()', + 'RDDropbox::setStartdateOffset()', RDDropbox::enddateOffset()' and + 'RDDropbox::setEnddateOffset(); methods in 'lib/rddropbox.cpp' and + 'lib/rddropbox.h'. + * Added a 'Delete source files after import' control in the Edit + Dropbox dialog in 'rdadmin/edit_dropbox.cpp' and + 'rdadmin/edit_dropbox.h'. + * Added an 'Offset start date' control in the Edit + Dropbox dialog in 'rdadmin/edit_dropbox.cpp' and + 'rdadmin/edit_dropbox.h'. + * Added an 'Offset end date' control in the Edit + Dropbox dialog in 'rdadmin/edit_dropbox.cpp' and + 'rdadmin/edit_dropbox.h'. + * Added '--persistent-dropbox-id', '--startdate-offset' and + '--enddate-offset' switches to rdimport(1) in + 'utils/rdimport/rdimport.cpp'. + * Added support for the '--persistent-dropbox-id', + '--delete-source', '--startdate-offset' and '--enddate-offset' + switches in rdcatchd(8) in 'rdcatchd/rdcatchd.cpp'. + * Added an rdmaint(1) utility in 'utils/rdmaint/'. +2008-11-29 Fred Gleason + * Added 'GROUPS.CUT_SHELFLIFE', 'GROUPS.DEFAULT_TITLE', + SERVICES.ELR_SHELFLIFE', 'EVENTS.REMARKS', 'CLOCKS.REMARKS' and + 'STATIONS.SYSTEM_MAINT' fields to the database. + * Incremented the database version to 166. + * Added 'RDGroup::cutShelflife()', 'RDGroups::setCutShelfLife()', + 'RDGroup::defaultTitle()' and 'RDGroup::setDefaultTitle()' + methods in 'lib/rdgroup.cpp' and 'lib/rdgroup.h'. + * Added 'RDSvc::elrShelflife()' and 'RDSvc::setElrShelflife()' + methods in 'lib/rdsvc.cpp' and 'lib/rdsvc.h'. + * Added 'RDStation::systemMaint()' and + 'RDStation::setSystemMaint()' methods in 'lib/rdstation.cpp' and + 'lib/rdstation.h'. + * Added 'RDEvent::remarks()' and 'RDEvent::setRemarks()' methods + in 'lib/rdevent.cpp' and 'lib/rdevent.h'. + * Added 'RDClock::remarks()' and 'RDClock::setRemarks()' methods + in 'lib/rdclock.cpp' and 'lib/rdclock.h'. + * Added 'Default Import Title' and 'Purge Expired Cuts' control to + the Edit Group dialog in 'rdadmin/edit_group.cpp' and + 'rdadmin/edit_group.h'. + * Implemented default import titles for RDImport(1) in + 'utils/rdimport/rdimport.cpp'. + * Implemented purging of expired cuts for RDMaint(1) in + 'utils/rdmaint/rdmaint.cpp'. + * Added an 'Include in System Maintenance Pool' control to the + Edit Host dialog in 'rdadmin/edit_station.cpp' and + 'rdadmin/edit_station.h'. + * Added a 'Delete expired ELR data' control to the Edit Service + dialog in 'rdadmin/edit_svc.cpp' and 'rdadmin/edit_svc.h'. + * Added a 'Remarks' control to the Edit Event dialog in + 'rdlogmanager/edit_event.cpp' and 'rdlogmanager/edit_event.h'. + * Added a 'Remarks' control to the Edit Clock dialog in + 'rdlogmanager/edit_clock.cpp' and 'rdlogmanager/edit_clock.h'. + * Implemented purging of expired ELR data for RDMaint(1) in + 'utils/rdmaint/rdmaint.cpp' and 'utils/rdmaint/rdmaint.h'. +2008-11-30 Fred Gleason + * Adjusted size of the Remarks widget under Windows on the Edit + Event dialog in 'rdlogmanager/edit_event.cpp'. + * Fixed a bug in 'lib/schedruleslist.cpp' that was causing a + segfault under Windows. +2008-11-30 Fred Gleason + * Adjusted processing of Cart Chunk timers in 'lib/rdcut.cpp' to + properly handle certain (arguably invalid) cases properly. +2008-11-30 Fred Gleason + * Added an RLM for generating PAD data for XM Satellite Radio in + 'rlm/rlm_xmpad.c'. +2008-11-30 Fred Gleason + * Added 'pam_rd.so' to 'rivendell.spec.in'. +2008-12-01 Fred Gleason + * Added a 'const char *svcname' parameter to the + 'RLMPadDataSent()' callback in 'rlm/rlm.h'. + * Added an RLM for generating UDP PAD updates in 'rlm/rlm_udp.c'. +2008-12-01 Fred Gleason + * Added an RLM for sending PAD updates to the Twitter service in + 'rlm/rlm_twitter.c'. +2008-12-01 Fred Gleason + * Fixed a bug in 'Makefile.am' that kept the '-devel' package from + being copied to the build directory. +2008-12-02 Fred Gleason + * Added an RLM for sending PAD updates to Facebook's 'What are you + doing?' service in 'rlm/rlm_facebook.c'. +2008-12-02 Fred Gleason + * Added the 'rlm_facebook' RLM to 'rivendell.spec.in'. +2008-12-02 Fred Gleason + * Added 'RDAIRPLAY.LOG0_NOW_CART', 'RDAIRPLAY.LOG0_NEXT_CART', + 'RDAIRPLAY.LOG1_NOW_CART', 'RDAIRPLAY.LOG1_NEXT_CART', + 'RDAIRPLAY.LOG2_NOW_CART' and 'RDAIRPLAY.LOG2_NEXT_CART' to the + database. + * Incremented the database version to 167. + * Added 'RDAirPlayConf::logNowCart()', + 'RDAirPlayConf::setLogNowCart()', + 'RDAirPlayConf::logNextCart()' and + 'RDAirPlayConf::setLogNextCart()' methods in + 'lib/rdairplay_conf.cpp' and 'lib/rdairplay_conf.h'. + * Added a 'Set Default Now & Next Cart' ['SN'] RML in + 'lib/rdmacro.h' and 'docs/rml.sxw'. + * Added 'Default Now Cart' and 'Default Next Cart' controls to the + Edit Now & Next dialog in 'rdadmin/edit_now_next.cpp' and + 'rdadmin/edit_now_next.h'. +2008-12-03 Fred Gleason + * Modified the 'LogPlay' class in 'rdairplay/log_play.cpp' and + 'rdairplay/log_play.h' to provide default Now & Next data. + * Implemented the 'Set Default Now & Next Cart' ['SN'] RML in + 'rdairplay/local_macros.cpp'. +2008-12-05 Fred Gleason + * Fixed a regression in 'ripcd/local_macros.cpp' that caused the + argument to the 'GI' RML to be ignored. + * Added instrastructure in 'rdairplay/rdairplay.cpp' to support a + splash screen (currently disabled). +2008-12-08 Fred Gleason + * Added 'GPIS.OFF_MACRO_CART' and 'GPOS.OFF_MACRO_CART' fields to + the database. + * Refactored the List GPIOs dialog in 'rdadmin/list_gpis.cpp' and + 'rdadmin/list_gpis.h' to accomodate the new 'off' transition macro + cart setting. + * Refactored the Edit GPIO dialog in 'rdadmin/edit_gpis.cpp' and + 'rdadmin/edit_gpis.h' to accomodate the new 'off' transition macro + cart setting. + * Modified ripcd(8) to accomodate the new 'off' transition cart + setting in 'ripcd/ripcd.cpp', 'ripcd/ripcd.h' and + 'ripcd/local_macros.cpp' + * Modified the RDRipc class to accomodate the new 'off' transition + cart setting in 'lib/rdripc.cpp' and 'lib/rdripc.h'. +2008-12-08 Fred Gleason + * Added 'SERVICES.DEFAULT_LOG_SHELFLIFE' and 'LOGS.PURGE_DATE' + fields to the database. + * Incremented the database version to 169. + * Added 'RDSvc::defaultLogShelflife()' and + 'RDSvc::setDefaultLogShelflife()' in 'lib/rdsvc.cpp' and + 'lib/rdsvc.h'. + * Added 'RDLog::purgeDate()' and 'RDLog::setPurgeDate()' in + 'lib/rdlog.cpp' and 'lib/rdlog.h'. + * Added a 'Purge logs after' control to the Edit Service + dialog in 'rdadmin/edit_svc.cpp' and 'rdadmin/edit_svc.h'. + * Added a 'Delete log on' control to the Edit Log dialog in + 'rdlogedit/edit_log.cpp' and 'rdlogedit/edit_log.h'. + * Added code to rdmaint(1) to purge expired logs in + 'utils/rdmaint.cpp' and 'utils/rdmaint.h'. +2008-12-08 Fred Gleason + * Increased the width of the 'USERS.LOGIN_NAME' field to 255. + * Increased the width of the 'USERS.FULL_NAME' field to 255. + * Increased the width of the 'FEED_PERMS.USER_NAME' field to 255. + * Increased the width of the 'LOGS.ORIGIN_USER' field to 255. + * Increased the width of the 'ORIGIN_USER' field in the log table + schema. + * Increased the width of the 'STATIONS.USER_NAME' field to 255. + * Increased the width of the 'STATIONS.DEFAULT_NAME' field to 255. + * Increased the width of the 'USER_PERMS.USER_NAME' field to 255. + * Increased the width of the 'WEB_CONNECTIONS.LOGIN_NAME' field to 255. + * Incremented the database version to 170. + * Refactored the List Users dialog in 'rdadmin/list_users.cpp' and + 'rdadmin/list_users.h' to handle long user names better. + * Refactored the Edit User dialog in 'rdadmin/edit_users.cpp' and + 'rdadmin/edit_user.h' to handle long user names better. + * Refactored the Add User dialog in 'rdadmin/add_users.cpp' and + 'rdadmin/add_user.h' to handle long user names better. +2008-12-08 Fred Gleason + * Added 'RLM_PARITY_NONE', 'RLM_PARITY_EVEN' and 'RLM_PARITY_ODD' + defines in 'rlm/rlm.h'. +2008-12-11 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that was throwing a segfault when + generating a log in RDLogManager(1). +2008-12-11 Fred Gleason + * Added code in 'ripcd/local_macros.cpp' to support the old, + deprecated syntax for the 'GI' RML. +2008-12-11 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 1.2.0. +2008-12-12 Fred Gleason + * Applied a patch from Richard Fine + that modifies 'rdcheck_daemons.cpp' to use grep(1) instead of + procfs to detect running processes. +2008-12-12 Fred Gleason + * Applied a patch from Richard Fine + that adds support for importing Ogg metadata in + 'lib/rdwavefile.cpp'. + * Added support for the Ogg 'PERFORMER' metadata tag in + 'lib/rdwavefile.cpp'. +2008-12-13 Fred Gleason + * Fixed a bug in 'lib/rdwavefile.cpp' where the values for the + FLAC 'ARTIST' and 'PERFORMER' tags were transposed. +2008-12-16 Fred Gleason + * Added a workaround in 'lib/rdcut.cpp' to handle incorrect end + times in metadata when the start and end dates are identical. +2008-12-26 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp that could cause a segfault + when loading a log in a non-empty log machine. +2008-12-29 Fred Gleason + * Added a test for 'FLAC__metadata_get_tags' in 'configure.in'. + * Added an #ifdef in 'lib/rdwavefile.cpp' to permit builds against + old versions of libFLAC. +2008-12-29 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 1.2.1. +2009-01-08 Fred Gleason + * Fixed bugs in 'rdairplay/rdairplay.cpp' that caused a segfault + when loading a log with soundpanels disabled. +2009-01-08 Fred Gleason + * Added code in 'rdlibrary/rdlibrary.cpp' to ensure that a + newly-added cart is visible in the cart list. +2009-01-12 Fred Gleason + * Modified 'lib/rdwavefile.cpp' to more reliably detect + mal-formatted MPEG files. +2009-01-13 Fred Gleason + * Fixed a bug in 'lib/rdreport.cpp' that caused Windows export + paths to be saved with double backslash characters. +2009-01-13 Fred Gleason + * Fixed a bug in 'lib/rdreport.cpp' that caused reports to be + truncated when a double quote character was present in a metadata + field. +2009-01-13 Fred Gleason + * Updated the 'NEWS' file. + * Updated the package version to 1.2.2. +2009-01-15 Fred Gleason + * Reworked 'lib/rd_paths.in', 'Makefile.am' and 'rlm/Makefile.am' + to generate the correct path for RLM modules to be generated under + x86_64 architecture. +2009-01-15 Fred Gleason + * Applied a fix from Stefan Gabriel in + 'rdairplay/log_play.cpp' that caused a segfault when used with a + null playout card value. +2009-01-15 Fred Gleason + * Fixed a bug in 'lib/rdsound_panel.cpp' that caused audio playout + to fail for a cart with Enforce Length enabled on a + non-timescaling capable output. +2009-01-30 Fred Gleason + * Fixed a bug in 'rdcastmanager/list_casts.cpp' that failed to + properly clean up temporary files after posting from a audio file. +2009-01-30 Fred Gleason + * Fixed a bug in rdlogmanager/edit_event.cpp' that caused the + cart filter to break when given search terms containing one or + more spaces. +2009-01-30 Fred Gleason + * Added 'FEEDS.CAST_ORDER' and 'PODCASTS.EFFECTIVE_DATE' fields to + the database. + * Incremented the database version to 171. + * Added 'RDFeed:castOrder()' and 'RDFeed::setCastOrder()' methods + in 'lib/rdfeed.cpp' and 'lib/rdfeed.h'. + * Added 'RDPodcast::effectiveDatetime()' and + 'RDPodcast::setEffectiveDatetime()'. + * Added an 'Air Date/Time' control to the Edit Cast dialog in + 'rdcastmanager/edit_cast.cpp' and 'rdcastmanager/edit_cast.h'. + * Added an 'Air Date/Time' field to the Edit Cast screen in + 'web/rdcastmanager/rdcastmanager.cpp'. + * Modified 'web/rdfeed/rdfeed.cpp' to serve the PubDate tag value + from the 'PODCASTS.EFFECTIVE_DATETIME' field. +2009-02-02 Fred Gleason + * Added a 'FEEDS.REDIRECT_PATH' field to the database. + * Incremented the database version to 172. + * Added 'RDFeed::redirectPath()' and 'RDFeed:setRedirectPath()' + methods in 'lib/rdfeed.cpp' and 'lib/rdfeed.h'. + * Added an 'Enable Feed Redirection' control to the Edit Feed + dialog in 'rdadmin/edit_feed.cpp' and 'rdadmin/edit_feed.h'. + * Added support for URI redirection in 'web/rdfeed/rdfeed.cpp'. +2009-02-03 Fred Gleason + * Refactored code in 'rdlogmanager/edit_event.cpp' and + 'lib/rdevent_line.cpp' so as to the the generation of + under-/over-fill warnings when linking non-autofill events. +2009-02-04 Fred Gleason + * Fixed a bug in 'lib/rdcdplayer.cpp' and 'rdlibrary/cdripper.cpp' + that caused the Eject function to fail after ripping tracks. + * Added 'RDCdPlayer::lock()' and 'RDCdPlayer::unlock()' methods in + 'lib/rdcdplayer.cpp' and 'lib/rdcdplayer.h'. + * Added code in 'rdlibrary/disk_ripper.cpp' to eject the CD at + completion of rips. +2009-02-04 Fred Gleason + * Fixed a bug in 'rlm/rlm_xmpad.c' that was causing null PAD + updates to be transmitted. +2009-02-05 Fred Gleason + * Added a 'FEEDS.BASE_PREAMBLE' field to the database. + * Added 'RDFeed::basePreamble()' and 'RDFeed::setBasePremable()' + methods in 'lib/rdfeed.cpp' and 'lib/rdfeed.h'. + * Incremented the database version to 173. + * Added an 'Enclosure Preamble' control to the Edit Feed dialog in + 'rdadmin/edit_feed.cpp' and 'rdadmin/edit_feed.h'. + * Modified 'web/rdfeed/rdfeed.cpp' to insert the enclosure + preamble value in item enclosures. +2009-02-09 Fred Gleason + * Added RDSoftKeys to 'rivendell.spec.in'. +2009-02-09 Fred Gleason + * Added a note in 'GPIO.txt' concerning pin 12 of the joystick + GPIO device. +2009-02-09 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' where importing a file with a + single Start Date or End Date would result in an unplayable cut in + RDAirPlay. +2009-02-10 Fred Gleason + * Added support for escaping characters in 'lib/rdmacro.cpp'. + * Added a 'Message Box' ['MB'] RML in 'lib/rdmacro.cpp' and + 'lib/rdmacro.h'. + * Added an RDPopup(1) utility in 'utils/rdpopup/'. +2009-02-10 Fred Gleason + * Added 'MATRICES.START_CART', 'MATRICES.STOP_CART', + 'MATRICES.START_CART_2' and 'MATRICES.STOP_CART_2' fields to the + database. + * Added 'RDMatrix::startCart()', 'RDMatrix::setStartCart()', + 'RDMatrix::stopCart()' and 'RDMatrix::setStopCart()' methods in + 'lib/rdmatrix.cpp' and 'lib/rdmatrix.h'. + * Added 'Startup Cart' and 'Shutdown Cart' controls to the Edit + Matrix dialog in 'rdadmin/edit_matrix.cpp' and + 'rdadmin/edit_matrix.h'. + * Implemented Start and Stop Cart support for the vGuest driver in + 'ripcd/vguest.cpp' and 'ripcd/vguest.h'. + * Implemented Start and Stop Cart support for the SAS USI driver in + 'ripcd/sasusi.cpp' and 'ripcd/sasusi.h'. +2009-02-12 Fred Gleason + * Implemented logic in the 'RDLogEvent::validate()' method in + 'lib/rdlog_event.cpp' and 'lib/rdlog_event.h' that checks for + valid cuts on the basis of dayparting parameters. + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' that caused the 'Valid + To' column to not be populated with the correct value. + * Added an 'Effective Date' control to the 'List Reports' dialog + in 'rdlogedit/list_reports.cpp' and 'rdlogedit/list_reports.h'. +2009-02-12 Fred Gleason + * Relabled the 'Play' button in the Full Log widget to 'Start' in + 'rdairplay/list_log.cpp'. +2009-02-12 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that broke auto refresh. + * Removed stray debugging printf() in 'rdairplay/rdairplay.cpp'. +2009-02-12 Fred Gleason + * Added a length counter for the Pre- and Post-Import lists in the + Edit Event dialog in 'rdlogmanager/edit_event.cpp, + 'rdlogmanager/edit_event.h', 'rdlogmanager/import_listview.cpp' + and 'rdlogmanager/import_listview.h'. +2009-02-12 Fred Gleason + * Fixed a bug in 'rdlogmanager/list_clocks.cpp' that was causing + bogus 'Clock in Use' warnings to be generated when deleting a + clock. +2009-02-18 Fred Gleason + * Changed the font used for RDPopup(1) in + 'utils/rdpopup/rdpopup.cpp'. + * Added a parameter to the 'Message Box' ['MB'] RML in + 'ripcd/local_macros.cpp'. +2009-02-18 Fred Gleason + * Added a Date/Time stamp to the titlebar of RDPopup(1) in + 'utils/rdpopup/rdpopup.cpp'. +2009-02-23 Fred Gleason + * Added an 'rlm_album' field to the 'rlm_pad' struct in + 'rlm/rlm.h'. + * Incremented 'RLM_VERSION' in 'rlm/rlm.h' to 1. + * Added a plug-in for the ANDO Media Streaming system in + 'rlm/rlm_ando.c'. +2009-02-23 Fred Gleason + * Fixed typos in 'rdadmin/createdb.cpp' and 'rivendell.spec.in'. +2009-02-23 Fred Gleason + * Removed a debugging printf from 'lib/rdlivewire.cpp'. +2009-02-24 Fred Gleason + * Fixed a typo in 'rlm/rlm_xmpad.c' that broke Recording mode. +2009-02-24 Fred Gleason + * Added a 'Password' control to the Edit LiveWire Node dialog in + 'rdadmin/edit_node.cpp and 'rdadmin/edit_node.h'. +2009-03-13 Fred Gleason + * Fixed a bug in 'lib/rdwavefile.cpp' that resulted in incorrect + detection of the bitrate in certain MPEG V2 files. +2009-03-16 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that caused a resource + leak when deleting paused events. +2009-03-17 Fred Gleason + * Enabled code in 'ripcd/local_macros.cpp' to drop root + permissions when executing rdpopup(1). +2009-03-17 Fred Gleason + * Added 'docs/MESSAGE_BOX.txt'. +2009-03-17 Fred Gleason + * Removed debugging printfs from 'rdiaplay/log_play.cpp'. +2009-03-18 Fred Gleason + * Updated the 'NEWS' file. + * Updated the package version to 1.3.0. +2009-03-19 Fred Gleason + * Added an '#include ' statement in + 'utils/rdpopup/rdpopup.cpp'. +2009-03-23 Fred Gleason + * Added a heartbeat message in 'rlm/rlm_ando.c'. +2009-03-24 Fred Gleason + * Added a 'SYSTEM' table to the database. + * Added an 'RDSystem' class in 'lib/rdsystem.cpp' and + 'lib/rdsystem.h'. + * Added a 'System Settings' button in 'rdadmin/rdadmin.cpp'. + * Added an 'Edit System-Wide Settings' dialog in + 'rdadmin/edit_settings.cpp' and 'rdadmin/edit_settings.h'. + * Added code to the Add Cart dialog in 'lib/rdadd_cart.cpp' to + enforce unique cart title restrictions. + * Added code to the Edit Cart dialog in 'rdlibrary/edit_cart.cpp' to + enforce unique cart title restrictions. + * Added code in 'lib/rdcart.cpp' and 'lib/rdcart.h' to enforce + unique cart title restrictions. +2009-03-25 Fred Gleason + * Added 'RDAIRPLAY.SHOW_COUNTERS' and 'RDAIRPLAY.AUDITION_PREROLL' + fields to the database. + * Incremented the database version to 176. + * Added 'RDAirPlayConf::showCounters()', + 'RDAirPlayConf::setShowCounters()', + 'RDAirPlayConf::auditionPreroll()' and + 'RDAirPlayConf::setAuditionPreroll()' methods in + 'lib/rdairplay_conf.cpp' and 'lib/rdairplay_conf.h'. + * Added a 'Display Extra Buttons/Counters' checkbox and a + 'Audition Preroll' control to the Edit RDAirPlay dialog in + 'rdadmin/edit_rdairplay.cpp' and + 'rdadmin/edit_rdairplay.h'. + * Implemented run time counters in the List Log widget in + 'rdairplay/list_log.cpp' and 'rdairplay/list_log.h'. + * Implemented 'Audition Head' and 'Audition Tail' button in the + List Log widget in 'rdairplay/list_log.cpp' and + 'rdairplay/list_log.h'. +2009-03-25 Fred Gleason + * Fixed a bug in 'lib/rdsound_panel.cpp', 'lib/rdsound_panel.h' + and 'rdpanel/rdpanel.cpp' that caused the state of the on-air + flag to not be recorded for ELR when playing a SoundPanel event. +2009-03-30 Fred Gleason + * Added code in 'rdadmin/createdb.cpp' to fix up faulty placement + of the 'RDPANEL.SKIN_PATH' field in the 'PANELS' table. + * Incremented the database version to 177. +2009-03-30 Fred Gleason + * Fixed a typo in 'xdg/rdsoftkeys.desktop'. +2009-03-30 Fred Gleason + * Fixed a bug in 'rdlibrary/list_reports.cpp' that was causing a + random '?' to appear in report entries for macro carts in the Cart + Report. +2009-03-30 Fred Gleason + * Added an 'End' button to the 'Edit Event' dialog in + 'rdairplay/edit_event.cpp'. +2009-03-31 Fred Gleason + * Added code in 'rdcatchd/rdcatchd.cpp', 'rdcatchd/rdcatchd.h' and + 'rdcatchd/local_macros.cpp' to permit back-to-back execution of + 'RR' and 'RS' RMLs. +2009-03-31 Fred Gleason + * Added an 'RDCastSearch()' function in 'lib/rdcastsearch.cpp' and + 'lib/rdcastsearch.h'. + * Added 'Filter', 'Only Show Unexpired Carts' and 'Only Show Active + Carts' controls in the 'Podcast List' dialog in + 'rdcastmanager/list_podcasts.cpp' and + 'rdcastmanager/list_podcasts.h'. + * Added 'Filter', 'Only Show Unexpired Carts' and 'Only Show Active + Carts' controls in the 'Podcast List' screen in + 'web/rdcastmanager/rdcastmanager.cpp' and + 'web/rdcastmanager/rdcastmanager.h'. + * Added a per-episode 'Play' button to the 'Podcast List' screen + in 'web/rdcastmanager/rdcastmanager.cpp' and + 'web/rdcastmanager/rdcastmanager.h'. +2009-04-03 Fred Gleason + * Changed the legend of the 'Rip Disk' button in the full disk + ripper in RDLibrary to 'Rip Disc'. + * Fixed a bug in the Cut Picker dialog where the 'OK' button was + disabled after creating a new cut in 'lib/rdcut_dialog.cpp'. + * Added code in the full disk ripper to disable the 'Rip Disc' + button if no tracks are selected for ripping. + * Added code in the CD track ripper to disable the 'Rip Track' + button if no track is selected for ripping. +2009-04-06 Fred Gleason + * Fixed a bug in 'lib/lib.pro' that broke the build under Windows. +2009-04-06 Fred Gleason + * Refactored the build system in 'pam_rd/Makefile'am' and + 'rivendell.spec.in' to work properly under OpenSuSE 11.1. +2009-04-06 Fred Gleason + * Fixed a typo in 'rivendell.spec.in' that broke the 'make rpm' + target. +2009-04-07 Fred Gleason + * Fixed a bug in 'ripcd/unity4000.cpp' that was causing a segfault + when processing 'ST' RMLs. +2009-04-07 Fred Gleason + * Fixed a bug in 'rdlogmanager/list_grids.cpp' that generated + invalid SQL when operating in User security mode. + * Optimized the SQL statement in the 'RDUser::services()' method + in 'lib/rduser.cpp'. +2009-04-08 Fred Gleason + * Fixed a bug in 'cae/cae.cpp' that failed to lock all memory into + RAM upon startup. +2009-04-08 Fred Gleason + * Added code to log occurances of failed file checkins in + 'lib/rd_cut.cpp'. +2009-04-09 Fred Gleason + * Changed the sort order of podcast episodes to descending in + 'web/rdcastmanager/rdcastmanager.cpp'. +2009-04-10 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 1.4.0. +2009-04-10 Fred Gleason + * Applied a patch from Richard Fine + that fixed a bug in 'autogen.sh' on OS X. +2009-04-13 Fred Gleason + * Fixed a bug in the 'Create Log' dialog in 'lib/rdadd_log.cpp' + that limited the maximum length of log names to 10 characters. +2009-04-13 Fred Gleason + * Fixed a bug in 'utils/rdmaint/rdmaint.cpp' that was failing to + update the 'VERSION.LAST_MAINT_DATETIME' field when running system + maintenance routines. +2009-04-13 Fred Gleason + * Removed debugging log call from 'lib/rdlog_line.cpp'. +2009-04-14 Fred Gleason + * Fixed bugs in 'rdcatchd/rdcatchd.cpp' that broke FTP xloads with + paths containing spaces. +2009-04-27 Fred Gleason + * Fixed bugs in 'helpers/rdtrans.sh' and 'helpers/rdpack.sh'. +2009-04-30 Fred Gleason + * Fixed a bug in 'rlm/rlm_twitter.c' and 'rlm/rlm_facebook.c' that + caused PAD updates to be sent using incorrect account information. +2009-04-30 Fred Gleason + * Fixed a bug in 'rivendell.spec.in' that was installing 'rlm.h' + in the wrong location. +2009-05-06 Fred Gleason + * Added a log warning to notify in case of failure to allocate a + play stream in 'lib/rdcae.cpp'. +2009-05-13 Fred Gleason + * Added an RLM for the Innovonics model 713 RDS encoder in + 'rlm/rlm_inno713.c'. +2009-05-13 Fred Gleason + * Updated 'conf/rlm_inno713.conf'. +2009-05-21 Fred Gleason + * Added a 'RDFormPost' class in 'lib/rdformpost.cpp' and + 'lib/rdformpost.h'. + * Added 'RDFeed::postFile()' and 'RDFeed::postCut()' methods in + 'lib/rdfeed.cpp' and 'lib/rdfeed.h'. + * Added a 'SYSTEM.MAX_POST_LENGTH' field to the database. + * Changed the default value of the 'PODCASTS.STATUS' field from 0 + to 1. + * Incremented the database version to 178. + * Added 'RDSystem::maxPostLength()' and + 'RDSystem::setMaxPostLength()' methods in 'lib/rdsystem.cpp' and + 'lib/rdsystem.h'. + * Added a Maximum Remote Post Length' control to the Edit + System-wide Settings dialog in 'rdadmin/edit_settings.cpp' and + 'rdadmin/edit_settings.h'. + * Renamed 'web/rdfeed/rdfeed.cpp' to + 'web/rdfeed/rdfeed_script.cpp'. + * Renamed 'web/rdfeed/rdfeed.h' to + 'web/rdfeed/rdfeed_script.h'. + * Added a 'Media Link' field to the Edit Podcast screen in + 'web/rdcastmanager/rdcastmanager.cpp'. +2009-05-22 Fred Gleason + * Fixed a bug in 'web/rdcastmanager/rdcastmanager.cpp' that caused + the initial login screen to throw an error. +2009-05-26 Fred Gleason + * Added a 'FEEDS.MEDIA_LINK_MODE' field to the database. + * Incremented the database version to 179. + * Added 'RDFeed::mediaLinkMode()' and 'RDFeed::setMediaLinkMode()' + methods in 'lib/rdfeed.cpp' and 'lib/rdfeed.h'. + * Added an RDFeed::MediaLinkMode' enumeration in 'lib/rdfeed.h'. + * Added a 'Media Link Mode' control to the Edit Feed dialog in + 'rdadmin/edit_feed.cpp' and 'rdadmin/edit_feed.h'. +2009-06-05 Fred Gleason + * Changed the behavior of the 'RDCae::loadPlay()' method so as to + wait indefinitely for caed(8) to return a stream. +2009-06-29 Fred Gleason + * Fixed a bug in 'rdlogmanager/list_clocks.cpp' that resulted in an + inconsistent database state if a newly created clock was closed + with the 'Cancel' button. + * Fixed a bug in 'rdlogmanager/edit_event.cpp' and + 'rdlogmanager/edit_event.h' that resulted in an inconsistent + database state if a newly created event was closed with the 'X' + button. +2009-06-29 Fred Gleason + * Fixed a typo in 'rdlogmanager/edit_grid.cpp' that caused the + 'Edit Grid:' prefix on the Window caption to fail to be displayed. +2009-06-29 Fred Gleason + * Added a 'Clear Hour' item to the hour button right-click menu on + the Edit Grid dialog in 'rdlogmanager/edit_grid.cpp' and + 'rdlogmanager/edit_grid.h'. +2009-06-29 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that caused creation of a + new database to fail. +2009-06-29 Fred Gleason + * Updated the URL in the comments regarding MySQL Identifiers in + 'lib/rdescape_string.h'. + * Fixed a bug in 'rdlogmanager/add_clock.cpp' and + 'rdlogmanager/add_event.cpp' that was allowing invalid characters + to be used in Event and Clock names. +2009-06-29 Fred Gleason + * Fixed a race in 'rdairplay/rdairplay.cpp' where the RIPC + connection would sometimes finish initializing before all + necessary data structures were created. +2009-06-29 Fred Gleason + * Fixed bugs in 'rdairplay/log_play.cpp' to make the Post Point + Counter operate more reliably and consistently. +2009-06-30 Fred Gleason + * Added an animated progress bar in 'icons/progressbar.gif' and + 'icons/progressbar.xcf'. + * Added 'web/rdcastmanager/rdcastmanager.js'. + * Added a JavaScript minification utility in 'helpers/jsmin.c'. +2009-07-01 Fred Gleason + * Fixed a bug in 'lib/rdformpost.cpp' that caused file uploads to + fail from IE 6.0. +2009-07-01 Fred Gleason + * Fixed bugs in 'web/rdcastmanager/rdcastmanager.cpp' that caused + special characters to be corrupted in form fields with IE. +2009-07-01 Fred Gleason + * Fixed a bug in 'cae/cae_jack.cpp' that failed to generate an + 'SP' message when an active playout was stopped. +2009-07-02 Fred Gleason + * Fixed a bug in 'web/rdcastmanager/rdcastmanager.js'. +2009-07-08 Fred Gleason + * Fixed up the head comment in + 'web/rdcastmanager/rdcastmanager.js'. +2009-07-08 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 1.5.0. +2009-08-03 Fred Gleason + * Updated the German (de) translation. + * Added an 'RDAlsaConfig(1) application in 'utils/rdalsaconfig/'. +2009-08-03 Fred Gleason + * Fixed a bug in 'utils/Makefile.am' that caused RDAlsaConfig(1) + to fail to be built when ALSA was configured. +2009-08-03 Fred Gleason + * Implemented the '--manage-daemons' switch in + 'utils/rdalsaconfig/rdalsaconfig.cpp'. + * Added RDAlsaConfig(1) in 'rivendell.spec.in'. +2009-08-03 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that caused the deck's + VOX start threshold value to be used as the normalization level. +2009-08-04 Fred Gleason + * Added an rdaconvert(1) utility in 'utils/rdaconvert/'. +2009-08-04 Fred Gleason + * Optimized sample rate conversion in + 'utils/rdaconvert/rdaconvert.cpp'. + * Added an 'RD_MAX_BANDPASS' compile-time variable in 'lib/rd.h'. +2009-08-04 Fred Gleason + * Refactored 'scripts/rd_import_file','scripts/rd_export_file' and + 'scripts/rd_rip_cd' to use rdaconvert(1) instead of sox(1). + * Refactored 'rdlibrary/cdripper.cpp' and 'rdlibrary/cdripper.h' + to use rdaconvert(1) instead of sox(1). + * Refactored 'rdlibrary/disk_ripper.cpp' and + 'rdlibrary/disk_ripper.h' to use rdaconvert(1) instead of sox(1). + * Fixed a bug in 'lib/rdcut_dialog.cpp' that caused the list of + groups to be populated in reverse alphabetical order. + * Removed the sox(1) dependency in 'rivendell.spec.in' and + 'debian/control'. +2009-08-04 Fred Gleason + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that was causing + carts to be created with a blank title when imported with the + '--title-from-cartchunk-cutid' switch. +2009-08-06 Fred Gleason + * Added a driver for the BroadcastTools SS4.4 in 'lib/rdmatrix.h', + 'lib/rdmatrix.cpp', 'rdadmin/add_matrix.cpp', + 'rdadmin/edit_matrix.cpp', 'rdadmin/list_matrices.cpp', + 'ripcd/btss44.cpp', 'ripcd/btss44.h', 'ripcd/ripcd.h' and + 'ripcd/local_macros.cpp'. + * Updated 'docs/SWITCHERS.txt'. +2009-08-06 Fred Gleason + * Removed the sox(1) requirement from 'INSTALL'. +2009-08-07 Fred Gleason + * Fixed a bug in 'scripts/rd_export_file' that broke exports when + normalization was turned off. + * Fixed a bug in 'rdairplay/log_play.cpp' that caused incorrect + operation of hard start events when the grace time parameter was + non-zero. +2009-08-08 Fred Gleason + * Added a report format for RadioTraffic.com in + 'lib/export_radiotraffic.cpp', 'lib/rdreport.cpp' and + 'lib/rdreport.h'. +2009-08-10 Fred Gleason + * Added 'lib/export_radiotraffic.cpp' in 'lib/lib.pro'. +2009-08-12 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 1.5.1. +2009-08-14 Fred Gleason + * Refactored 'pam_rd/Makefile.am' to build the Rivendell PAM + module correctly. +2009-08-17 Fred Gleason + * Added consistency checks for carts, cuts and audio in + 'utils/rddbcheck/rddbcheck.cpp' and 'utils/rddbcheck/rddbcheck.h'. +2009-08-18 Fred Gleason + * Added 'lib/rdcmd_cache.cpp', 'lib/rdedit_panel_name.cpp', + 'lib/rdlist_groups.cpp', 'lib/rdlist_logs.cpp', + 'lib/rdcmd_cache.h', 'lib/rdedit_panel_name.h', + 'lib/rdlist_groups.h', 'lib/rdlist_logs.h' to 'lib/lib.pro'. +2009-08-19 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that caused events with + a hard start time assigned to be stopped down after being started + early. +2009-08-19 Fred Gleason + * Fixed an uninitialized variable bug in 'lib/rdslider.cpp' and + 'lib/rdslider.h'. + * Fixed an uninitialized variable bug in + 'rdairplay/loglinebox.cpp'. + * Fixed an uninitialized variable bug in 'rdairplay/log_play.cpp'. + * Fixed an uninitialized variable bug in 'rdairplay/pie_counter.cpp'. +2009-08-19 Fred Gleason + * Documented a set of basic 'default' scheduler formats in + 'docs/scheduler_formats.ods'. +2009-08-20 Fred Gleason + * Fixed a bug in 'scripts/rd_export_audio' that broke exports when + the destination path contained one or more spaces. +2009-08-25 Fred Gleason + * Updated the 'NEWS' file. + * Updated the package version to 1.5.2. +2009-09-02 Fred Gleason + * Added an RLM for the LiquidCompass Internet streaming encoder + in 'rlm/rlm_liqcomp.c'. +2009-09-02 Fred Gleason + * Fixed a bug in 'rlm/rlm_ando.c', 'rlm/rlm_serial.c', + 'rlm/rlm_xmpad.c' 'rlm/rlm_udp.c' and 'rlm/rlm_inno713.c' that + caused the Log Selection value for MasterLog to be applied to + Aux1Log and Aux2Log as well. +2009-09-03 Fred Gleason + * Added a 'RDLIBRARY.SRC_CONVERTER' field to the database. + * Incremented the database version to 180. + * Added 'RDLibraryConf::srcConverter()' and + 'RDLibraryConf::setSrcConverter()' methods in + 'lib/rdlibrary_conf.cpp' and 'lib/rdlibrary_conf.h'. + * Added a 'Sample Rate Converter' control to the 'RDLibrary + Config' dialog in 'rdadmin/edit_rdlibrary.cpp' and + 'rdadmin/edit_rdlibrary.h'. + * Added a '--converter=' switch in rdaconvert(1) in + 'utils/rdaconvert.cpp' and 'utils/rdaconvert.h'. + * Hardwired 'SRC_SINC_MEDIUM_QUALITY' as the default sample rate + converter in 'utils/rdaconvert/rdaconver.cpp'. + * Modified 'scripts/rd_export_audio', 'scripts/rd_import_audio' + and 'scripts/rd_rip_cd' to use the new converter parameter. + * Modified 'lib/rdfeed.cpp', 'lib/rdfeed.h', + 'lib/rdimport_dialog.cpp', 'rdcatchd/rdcatchd.cpp', + 'utils/rdimport/rdimport.cpp', 'utils/rdimport/rdimport.h', + 'rdlibrary/cdripper.cpp', 'rdlibrary/disk_ripper.cpp' and + 'web/rdcastmanager/rdcastmanager.cpp' to support the new converter + parameter. +2009-09-04 Fred Gleason + * Fixed a bug in 'utils/rdaconvert/rdaconvert.cpp' that broke + sample rate conversion. +2009-09-18 Fred Gleason + * Fixed a bug in 'cae/cae_alsa.cpp' that caused playout meters to + display incorrect levels for output port numbers > 0. +2009-09-21 Fred Gleason + * Fixed a bug in ::RDLogEvent::validate()' in + 'lib/rdlog_event.cpp' that caused audio carts with no cuts + containing audio to fail to be detected. +2009-09-23 Fred Gleason + * Added code to 'rlm/liq_comp.c' to log PAD updates. +2009-11-10 Fred Gleason + * Fixed a bug in 'rdairplay/local_macros.cpp' that caused + chained-to logs to fail to start if the chain occurred when the + last event was playing and had a STOP transition. +2009-11-17 Fred Gleason + * Fixed a bug in 'lib/rdcart.cpp' that caused the + 'CART.END_DATETIME' field to fail to be set properly. + * Added 'RDLogLine::startDatetime()', + 'RDLogLine::setStartDatetime()', 'RDLogLine::endDatetime()' and + 'RDLogLine::setEndDatetime()' methods in 'lib/rdlog_line.cpp' and + 'lib/rdlog_line.h'. + * Incremented the database version to 181. +2009-11-17 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that caused the Post + Point Counter to be incorrect after moving an event across a post + point. +2009-11-19 Fred Gleason + * Added a 'CART.NOTES' field to the database. + * Incremented the database version to 182. + * Added 'RDCart::notes()' and 'RDCart::setNotes()' methods in + 'lib/rdcart.cpp' and 'lib/rdcart.h'. + * Added an 'EditNotes' dialog in 'rdlibrary/edit_notes.cpp' and + 'rdlibrary/edit_notes.h'. + * Added a 'Show Note Bubbles' control to the RDLibrary main window + in 'rdlibrary/rdlibrary.cpp' and 'rdlibrary/rdlibrary.h'. +2009-11-24 Fred Gleason + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that caused the + '--segue-level' switch to be ignored when used in combination with + the '--metadata-pattern' switch. +2009-11-25 Fred Gleason + * Fixed a bug in 'rdlogmanager/rdlogmanager.cpp' that caused + translations to fail to be loaded at startup. +2009-11-25 Fred Gleason + * Fixed a bug in 'rdlogmanager/edit_event.cpp' that caused the + cart list to be blank when selecting 'ALL' carts using a non-default + langauge. +2009-12-07 Fred Gleason + * Added a 'CounterPoint' format to 'docs/scheduler_formats.ods'. + * Added a copy-split data format in 'docs/copy_split_format.odt'. +2009-12-10 Fred Gleason + * Fixed a bug in 'rdlibrary/edit_cart.cpp' that allowed displayed + the list of available carts in the Edit Cart dialog without + honoring user group restrictions. +2009-12-11 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that caused the 'Sample + Rate Setting' in RDAdmin->ManageHosts->RDLibrary' to be stuck on + 'Best Sinc Interpolartor'. +2009-12-14 Fred Gleason + * Removed debug statements in 'lib/rdevent.cpp'. +2009-12-14 Fred Gleason + * Fixed a bug in 'rdlogmanager/rdlogmanager.cpp' that broke the + build under Windows. +2009-12-17 Fred Gleason + * Updated the 'NEWS' file. + * Incremented the package version to 1.6.0. +2009-12-29 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that caused a Chained-To + log to ignore an initial STOP transition if the initial event was + a Label. +2010-01-12 Fred Gleason + * Added an 'IMPORT_TEMPLATES' table to the database. + * Added 'SERVICES.TFC_IMPORT_TEMPLATE' and + 'SERVICES.MUS_IMPORT_TEMPLATE' fields to the database. + * Incremented the database version to 183. + * Added 'RDSvc::importTemplate()' and 'RDSvc::setImportTemplate()' + methods in 'lib/rdsvc.cpp' and 'lib/rdsvc.h'. + * Refactored import field parameters into a 'ImportFields' widget + in 'rdadmin/importfields.cpp' and 'rdadmin/importfields.h'. + * Added sample file for Rivendell Standard import format in + 'tests/rivendell_standard.txt'. + * Added sample file for VisualTraffic import format in + 'tests/visualtraffic.txt'. +2010-01-13 Fred Gleason + * Added export setting for Music 1 in 'lib/rdreport.cpp' and + 'lib/rdreport.h'. + * Added an import setting for Music 1 in 'rdadmin/createdb.cpp'. + * Incremented the database version to 184. +2010-01-13 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' that caused Segue markers to be + placed beyond the End marker when importing a file with + auto-trimming enabled. +2010-01-20 Fred Gleason + * Implemented the 'RDTimeEdit' widget in 'lib/rdtimeedit.cpp' and + 'lib/rdtimeedit.h'. + * Implemented 1/10th second grace time resolution in + 'rdairplay/edit_event.cpp' and 'rdlogedit/edit_logline.cpp'. + * Removed 'lib/audio_controls.cpp'. + * Implemented 1/10 second forced length resolution in + 'rdlibrary/edit_log.cpp' and 'rdlibrary/audio_controls.h'. +2010-01-21 Fred Gleason + * Fixed a bug in 'rdlogmanager/rdlogmanager.cpp' that caused + translations to fail to be loaded at startup. + * Fixed a bug in 'utils/rdgpimon/rdgpimon.cpp' that caused + translations to fail to be loaded at startup. + * Fixed a bug in 'utils/rmlsend/rmlsend.cpp' that caused + translations to fail to be loaded at startup. + * Added a Norwegian translation (nn_NO). +2010-01-21 Fred Gleason + * Added a Norwegian translation (nb_NO). +2010-01-21 Fred Gleason + * Added a Spanish translation (es). +2010-01-21 Fred Gleason + * Fixed a bug in 'rivendell.spec.in'. +2010-01-23 Fred Gleason + * Optimized code in 'lib/rdwavefile.cpp' so as to load waveform + energy data only if specifically requested. +2010-01-23 Fred Gleason + * Fixed a bug in 'cae/cae_alsa.cpp' that caused a segfault when + handling an xrun. +2010-01-25 Fred Gleason + * Fixed a bug in 'utils/rmlsend/rmlsend.cpp' that broke the build + under Windows. +2010-01-25 Fred Gleason + * Fixed a bug in 'lib/lib.pro' that broke the build under Windows. +2010-01-25 Fred Gleason + * Fixed a bug in 'rdlogmanager/rdlogmanager.cpp' that broke the build + under Windows. +2010-01-26 Fred Gleason + * Added an 'RDLogEvent::exists(QTime &)' method in + 'lib/rdlog_event.cpp' and 'lib/rdlog_event.h'. + * Implemented a sanity check for duplicate start times in the Edit + Log Entry dialog in 'rdlogedit/edit_logline.cpp' and + 'rdlogedit/edit_logline.h'. + * Implemented a sanity check for duplicate start times in the Edit + Event dialog in 'rdairplay/edit_event.cpp' and + 'rdairplay/edit_event.h'. +2010-01-31 Fred Gleason + * Changed the parent class for RDLibrary's main widget from + 'QDialog' to 'QWidget' in 'rdlibrary/rdlibrary.cpp' and + 'rdlibrary/rdlibrary.h'. + * Changed the parent class for RDLogManager's main widget from + 'QDialog' to 'QWidget' in 'rdlogmanager/rdlogmanager.cpp' and + 'rdlogmanager/rdlogmanager.h'. + * Changed the parent class for RDLogin's main widget from + 'QDialog' to 'QWidget' in 'rdlogin/rdlogin.cpp' and + 'rdlogin/rdlogin.h'. +2010-02-01 Fred Gleason + * Added an 'RDCmdSwitch::allProcessed()' method in + 'lib/rdcmd_switch.cpp' and 'lib/rdcmd_switch.h'. + * Added an rdcollect(1) utility in 'utils/rdcollect/'. +2010-02-01 Fred Gleason + * Added 'SERVICES.TFC_PREIMPORT_CMD', + 'SERVICES.TFC_WIN_PREIMPORT_CMD', 'SERVICES.MUS_PREIMPORT_CMD' and + 'SERVICES.MUS_WIN_PREIMPORT_CMD' to the database. + * Incremented the database version to 185. + * Added 'Preimport Command' controls to the 'Edit Service' dialog + in 'rdadmin/edit_svc.cpp' and 'rdadmin/edit_svc.h'. + * Fixed bugs in 'lib/rdconf.cpp' that broke functioning of the + 'RDGetBasePart()' and 'RDGetPathPart()' functions under Windows. +2010-02-01 Fred Gleason + * Fixed a bug in 'utils/rdcollect/Makefile.am' that broke the + build under Windows. + * Added rdcollect(1) to 'rivendell.ism'. +2010-02-02 Fred Gleason + * Implemented line sorting in 'utils/rdcollect/rdcollect.cpp'. + * Added '--hours-offset', '--minutes-offset' and 'seconds-offset' + switches to rdcollect(1) in 'utils/rdcollect/rdcollect.cpp' and + 'utils/rdcollect/rdcollect.h'. +2010-02-02 Fred Gleason + * Fixed a bug in 'rdadmin/edit_svc.cpp' that prevented the use of + '\' characters in the Windows Preimport Command fields. +2010-02-04 Fred Gleason + * Modified the field widths for 'EXT_CART_NAME' and 'EXT_EVENT_ID' + in the import table to match those used in the log table format in + 'lib/rdsvc.cpp'. +2010-02-04 Fred Gleason + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that broke use of the + RETURN key to initiate a library search. +2010-02-04 Fred Gleason + * Fixed a bug in 'rdlogin/rdlogin.cpp' that broke use of the + RETURN key to initiate a login. +2010-02-08 Fred Gleason + * Removed the 'POST_TIME' field from the database log format + schema. + * Changed the type of the 'START_TIME' and 'LINK_START_TIME' + fields in the database log format schema from 'time' to 'int'. + * Changed the type of the 'START_TIME' field in the database + clock format schema from 'time' to 'int'. + * Incremented the database version to 186. + * Modifed 'lib/rdclock.cpp', 'lib/log_event.cpp', + 'lib/rdevent_line.cpp' and 'lib/rdcreate_log.cpp' to process the + new 'START_TIME' and 'LINK_START_TIME' fields correctly. + * Modified the Edit Log Entry dialog to display hard times to 1/10 + second in 'rdlogedit/edit_logline.cpp'. + * Modified the Edit Marker dialog to display hard times to 1/10 + second in 'rdlogedit/edit_marker.cpp'. + * Modified the Edit Voice Track Marker dialog to display hard + times to 1/10 second in 'rdlogedit/edit_track.cpp'. + * Modified the Edit Log Chain dialog to display hard + times to 1/10 second in 'rdlogedit/edit_chain.cpp'. + * Modified the Voice Tracker dialog to display hard + times to 1/10 second in 'rdlogedit/voice_tracker.cpp'. + * Modified the ListLog widget in 'rdairplay/list_log.cpp' and + 'rdairplay/list_log.h' to display hard times to 1/10 second. + * Modified the ButtonLog widget in 'rdairplay/loglinebox.cpp' and + 'rdairplay/loglinebox.h' to display hard times to 1/10 second. + * Modified the Edit Event dialog in 'rdairplay/edit_event.cpp' and + 'rdairplay/edit_event.h' to display hard times to 1/10 second. + * Modified the Edit Clock dialog in 'rdlogmanager/edit_clock.cpp' + to display Start and End times to 1/10 second. + * Modified the Edit Event Assignment dialog in + 'rdlogmanager/edit_eventline.cpp' and 'rdlogmanager/edit_eventline.h' + to display Start and End times to 1/10 second. +2010-02-09 Fred Gleason + * Added 'RDImportDialog::enableAutotrim()', + 'RDImportDialog::setAutotrimLevel()', + 'RDImportDialog::enableNormalization()', + 'RDImportDialog::setNormalizationLevel()' and + 'RDImportDialog::setChannels()' methods in + 'lib/rdimportdialog.cpp' and 'lib/rdimportdialog.h'. + * Added code in 'rdlibrary/audio_cart.cpp' to set the default + position of the 'Autotrim' controls in accordance with settings in + RDAdmin->ManageHosts->RDLibrary. +2010-02-17 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that broke log merging. +2010-02-22 Fred Gleason + * Tweaked key bindings and color layout of the 'RDTimeEdit' widget + to match that of 'QTimeEdit' in 'lib/rdtimeedit.cpp' and + 'lib/rdtimeedit.h'. +2010-02-22 Fred Gleason + * Updated the 'NEWS' file. + * Updated the copyright date in 'rdadmin/info_dialog.cpp'. + * Incremented the package version to 1.7.0. +2010-02-23 Fred Gleason + * Added a check for ID3Lib in 'configure.in'. + * Added ID3Lib to the list of dependencies in 'INSTALL' +2010-02-23 Fred Gleason + * Added a 'CUTS.ISCI' field to the database. + * Added an 'ISCI' field to the reconciliation table format in the + database. + * Incremented the database version to 187. + * Added 'RDCut::isci()' and 'RDCut::setIsci()' methods in + 'lib/rdcut.cpp' and 'lib/rdcut.h'. + * Added an 'ISCI Code' field to the Cut Info/Record dialog in + 'rdlibrary/record_cut.cpp' and 'rdlibrary/record_cut.h'. + * Added 'RDLogLine::isci()' and 'RDLogLine::setIsci()' methods in + 'lib/rdlog_line.cpp and 'lib/rdlog_line.h'. + * Added 'rlm_isrc' and 'rlm_isci' members to the 'rlm_pad' + structure in 'rlm/rlm.h'. + * Incremented RLM_VERSION to 2 in 'rlm/rlm.h'. +2010-03-02 Fred Gleason + * Added an icon in 'icons/split.xpm'. + * Added a 'RDCart::Split' to the 'RDCart::Type' enum in + 'lib/rdcart.h'. + * Added 'Split' to the list of offered cart type in the 'Add Cart' + dialog in 'lib/rdadd_cart.cpp'. + * Modified RDAirplay to support split carts. + * Modified RDLogEdit to support split carts. + * Modified RDLogManager to support split carts. + * Added 'SYSTEM.ENABLE_SPLITS', 'SYSTEM.SPLIT_MAP_PATH', + 'SYSTEM.SPLIT_UPLOAD_URL', 'SYSTEM.SPLIT_UPLOAD_USERNAME', + 'SYSTEM.SPLIT_UPLOAD_PASSWORD', 'SYSTEM.SPLIT_UPLOAD_FORMAT', + 'SYSTEM.SPLIT_UPLOAD_SAMPRATE', 'SYSTEM.SPLIT_UPLOAD_CHANNELS', + and 'SYSTEM.SPLIT_UPLOAD_BITRATE' fields to the database. + * Incremented the database version to 188. + * Added an 'RDCopySplits' class in 'lib/rdcopysplits.cpp' and + 'lib/rdcopysplits.h'. +2010-03-04 Fred Gleason + * Added .html files to the default-handler list in + 'conf/rd-bin.conf.in'. +2010-03-12 Fred Gleason + * Refactored 'configure.in' to detect and report MPEG libraries. + * Added an 'RDAudioConvert' class in 'lib/rdaudioconvert.cpp' and + 'lib/rdaudioconvert.h'. + * Added an 'RDFlacDecode' class in 'lib/rdflacdecode.cpp' and + 'lib/rdflacdecode.h'. + * Added a test harness program in 'tests/audio_convert_test.cpp' + and 'tests/audio_convert_test.h'. +2010-03-12 Fred Gleason + * Added an 'RDFormPost::AutoEncoded' value to the + 'RDFormPost::Encoding' enum in 'lib/rdformpost.cpp' and + 'lib/rdformpost.h'. +2010-03-15 Fred Gleason + * Implemented an 'Export' service in 'web/rdxport/export.cpp'. + * Implemented an 'RDAudioExport' class in 'lib/rdaudioexport.cpp' + and 'lib/rdaudioexport.h'. + * Added an audio export test harness in + 'tests/audio_export_test.cpp' and 'tests/audio_export_test.h'. +2010-03-16 Fred Gleason + * Changed the value of the 'USERS.PASSWORD' field to contain a + non-encrypted value. + * Added an 'RDUser::password()' method in 'lib/rduser.cpp' and + 'lib/rduser.h'. + * Implemented an 'Import' service in 'web/rdxport/import.cpp'. + * Implemented an 'RDAudioImport' class in 'lib/rdaudioimport.cpp' + and 'lib/rdaudioimport.h'. + * Added an audio import test harness in + 'tests/audio_import_test.cpp' and 'tests/audio_import_test.h'. +2010-03-16 Fred Gleason + * Added an 'RDBusyBar' class in 'lib/rdbusybar.cpp' and + 'lib/rdbusybar.h'. + * Refactored the 'RDImportAudio' dialog to use the new Xport + methods. +2010-03-18 Fred Gleason + * Refactored RDImport(1) to use the new Xport methods. +2010-03-18 Fred Gleason + * Refactored RDCatchd(8) to use the new RDAudioConvert class. +2010-03-18 Fred Gleason + * Refactored 'RDFeed' to use the new 'RDAudioConvert' and + 'RDAudioExport' classes in 'lib/rdfeed.cpp' and 'lib/rdfeed.h'. +2010-03-19 Fred Gleason + * Added a dependency for LibParanoia in 'configure.in'. + * Added an 'RDCdRipper' class in 'lib/rdcdripper.cpp' and + 'lib/rdcdripper.h'. + * Refactored the CD rippers in RDLibrary(1) to use the new + 'RDCdRipper' and 'RDAudioImport' classes. +2010-03-19 Fred Gleason + * Documented the Xport service in 'docs/xport_service.odt'. +2010-03-22 Fred Gleason + * Fixed a bug in 'rdadmin/edit_Settings.cpp' that allowed a + password value to be visible. +2010-03-22 Fred Gleason + * Added a 'CUTS.UPLOAD_DATETIME' field to the database. + * Incremented the database version to 189. + * Added 'RDCut::uploadDatetime()' and 'RDCut::setUploadDatetime()' + methods in 'lib/rdcut.cpp' and 'lib/rdcut.h'. + * Added an 'RDAudioUpload' class in 'lib/rdaudioupload.cpp' and + 'lib/rdaudioupload.h'. + * Implemented copy-split uploads in 'rdlibrary/edit_cart.cpp'. + * Added a split-cart exception report in + 'rdlibrary/list_reports.cpp' and 'rdlibrary/list_reports.h'. +2010-03-23 Fred Gleason + * Fixed a bug in 'lib/rdcart.cpp' that caused a corrupt SQL + update. + * Fixed a bug in 'web/rdxport/import.cpp' that caused incorrect + MPEG bitrates to be used. +2010-04-02 Fred Gleason + * Fixed a bug in 'rdlibrary/edit_cart.cpp' that caused a segfault + when creating a split cart with an empty split map file. +2010-04-02 Fred Gleason + * Fixed a bug in 'lib/rdimportaudio.cpp' that caused metadata + to fail to be applied from audio imports. +2010-04-05 Fred Gleason + * Added a 'STATIONS.HAVE_TWOLAME' field to the database. + * Incremented the database version to 190. + * Added a 'HAveTwoLame' value to the 'RDStation::Capability' enum + in 'lib/rdstation.cpp' and 'lib/rdstation.h'. + * Added/Modified code in 'cae/cae.cpp' to detect MAD, TwoLAME and + LAME libraries. +2010-04-05 Fred Gleason + * Fixed a bug in 'lib/rdsound_panel.cpp' that broke writing of ELR + data to the database. +2010-04-05 Fred Gleason + * Fixed a bug in 'cae/cae.cpp' that broke meter level propagation + when running modules as a non-privileged user. +2010-04-05 Fred Gleason + * Added an 'rlm_carttype' field to the 'rlm_pad' structure in + 'rlm/rlm.h'. + * Added 'RLM_CARTTYPE_ALL', 'RLM_CARTTYPE_AUDIO', + 'RLM_CARTTYPE_MACRO' and 'RLM_CARTTYPE_SPLIT' defines in + 'rml/rlm.h'. + * Incremented 'RLM_VERSION' to 3 in 'rlm/rlm.h'. + * Added an 'rlm_xds' RLM in 'rlm/rlm_xds.c'. +2010-04-06 Fred Gleason + * Removed toolame(1) from 'toolame/'. + * Removed toolame(1) from 'make_slack.in'. + * Removed toolame(1) from 'rivendell.spec.in'. + * Removed 'rd_import_audio', 'rd_export_audio' and 'rd_rip_cd' + from 'scripts/'. + * Removed 'rd_import_audio', 'rd_export_audio' and 'rd_rip_cd' + from 'make_slack.in'. + * Removed 'rd_import_audio', 'rd_export_audio' and 'rd_rip_cd' + from 'rivendell.spec.in'. + * Fixed a typo in 'lib/Makefile.am' that broke the 'make zip' + target. +2010-04-19 Fred Gleason + * Added code to fail 'configure' if libsamplerate is not + detected. + * Fixed a bug in 'configure.in' that failed to abort the configure + when LibId3 was not detected. + * Fixed a bug in 'lib/rdaudioconvert.cpp' that broke the build + when configured without Lame or TwoLame support. + * Fixed a bug in 'rdadmin/createdb.cpp' that failed when creating + a new database. +2010-04-20 Fred Gleason + * Added a 'SERVICES.PROGRAM_CODE' field to the database. + * Incremented the database version to 191. + * Added 'RDSvc::programCode()' and 'RDSvc::setProgramCode()' + methods in 'lib/rdsvc.cpp' and 'lib/rdsvc.h'. + * Added a 'Program Code' control to the Edit Service dialog in + 'rdadmin/edit_svc.cpp' and 'rdadmin/edit_svc.h'. + * Defined 'rlm_svc' and 'rlm_svc' structures in 'rlm/rlm.h'. + * Refactored the parameter list of the 'RLMPadDataSent' callback + in 'rlm/rlm.h'. + * Incremented RLM_VERSION to 10 in 'rlm/rlm.h'. + * Ported 'rlm/rlm_test.c' to use the revised RLM API. + * Ported 'rlm/rlm_ando.c' to use the revised RLM API. + * Added PAD update logging to 'rlm/rlm_ando.c'. + * Ported 'rlm/rlm_facebook.c' to use the revised RLM API. + * Added PAD update logging to 'rlm/rlm_facebook.c'. + * Ported 'rlm/rlm_serial.c' to use the revised RLM API. + * Added PAD update logging to 'rlm/rlm_serial.c'. + * Ported 'rlm/rlm_twitter.c' to use the revised RLM API. + * Added PAD update logging to 'rlm/rlm_twitter.c'. + * Ported 'rlm/rlm_udp.c' to use the revised RLM API. + * Added PAD update logging to 'rlm/rlm_udp.c'. + * Ported 'rlm/rlm_xmpad.c' to use the revised RLM API. + * Added PAD update logging to 'rlm/rlm_xmpad.c'. + * Ported 'rlm/rlm_inno713.c' to use the revised RLM API. + * Added PAD update logging to 'rlm/rlm_inno713.c'. + * Ported 'rlm/rlm_liqcomp.c' to use the revised RLM API. + * Added PAD update logging to 'rlm/rlm_liqcomp.c'. + * Added an RLM for the Citadel/X-Digital Systems copy-splitting + system in 'rlm/rlm_xds.c'. +2010-04-20 Fred Gleason + * Fixed a bug in 'lib/rdformpost.cpp' that incorrectly uuencoded + string values. +2010-04-20 Fred Gleason + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that was ignoring + the current system user assignment when importing audio. +2010-04-27 Fred Gleason + * Removed rdaconvert(1) and rdfilewrite(1). +2010-04-29 Fred Gleason + * Fixed a bug in 'web/rdxport/export.cpp' that broke the build + under OpenSuSE 11.2. +2010-04-30 Fred Gleason + * Renamed the data file for the test tone cut to '999999_001.wav' + to be consistent with the standard cut naming convention. + * Added '--mysql-admin-username=' and '--mysql-admin-password=' + switches to RDAdmin(1) in 'rdadmin/rdadmin.cpp'. + * Modified the 'restart' target in 'rivendell-suse.in' to print + notification of service stop and start. + * Modified 'conf/rd.conf-sample' to reflect new default system + user and group. + * Added commands in 'rivendell.spec.in' to configure ALSA devices + and MySQL automatically upon initial installation of the package. +2010-04-30 Fred Gleason + * Added logic in 'rivendell.spec.in' to enable the MySQL service + upon RPM installation. +2010-05-03 Fred Gleason + * Fixed a bug in 'rivendell.spec-in' that created the '/var/snd' + directory with incorrect permissions. + * Fixed a bug in 'rdadmin/createdb.cpp' that created the test tone + data with incorrect permissions. + * Fixed a bug in 'rivendell.spec.in' that installed 'rdxport.cgi' + with incorrect file permissions. + * Fixed a bug in 'rdadmin/createdb.cpp' that failed to enable + podcasting rights for the default user when creating a new + database. + * Fixed a bug in 'lib/rdformpost.cpp' where an empty form variable + would not be read when processing a URL encoded post. +2010-05-03 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' and 'lib/rdcut.h' where the + RDCut::cartNumber()' would return an invalid value if the + underlying cut didn't exist. +2010-05-03 Fred Gleason + * Added #ifdef statements in 'lib/rdaudioimport.cpp', + 'lib/rdaudioexport.cpp' and 'lib/rdupload.cpp' to detect the + presence of the 'CURLE_REMOTE_ACCESS_DENIED' definition. +2010-05-07 Fred Gleason + * Altered the value of the 'Hostname=' parameter in the [mySQL] + section of 'conf/rd.conf-sample' from 'localhost' to '127.0.0.1'. +2010-05-11 Fred Gleason + * Added a 'RDCatchConnect::setExitCode()' method in + 'lib/rdcatch_connect.cpp' and 'lib/rdcatch_connect.h'. + * Added a 'RDCatchConnect::resolveUrl()' method in + 'lib/rdcatch_connect.cpp' and 'lib/rdcatch_connect.h'. + * Refactored rdcatchd(8) to use exec() to dispatch batch jobs. + * Fixed a bug in 'lib/rdpodcast.cpp' that caused FTP uploads to + hang when putting to an archive with a blank password. +2010-05-11 Fred Gleason + * Added an 'RDDownload' class in 'lib/rddownload.cpp' and + 'lib/rddownload.h'. + * Modified rdcatchd(8) to use libcurl for file uploads and + downloads in 'rdcatchd/batch.cpp'. +2010-05-12 Fred Gleason + * Added a 'RECORDINGS.EXIT_TEXT' field to the database. + * Incremented the database schema to 192. + * Added error reporting for Upload/Download event errors in + RDCatch(1). +2010-05-12 Fred Gleason + * Removed the lftp(1) dependency. + * Removed the wget(1) dependency. + * Removed the samba-client dependency. +2010-05-14 Fred Gleason + * Added a driver for the BroadcastTools SRC-8III Serial Remote + Control. + * Added a driver for the BroadcastTools SRC-16 Serial Remote + Control. +2010-05-17 Fred Gleason + * Changed the default behavior of 'make rpm' so as to strip debug + information from binaries. + * Added a '--with-debug' switch in 'configure.in' to enable + generation of debug information in RPMs. +2010-05-17 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' that would cause xload + completion notifications to fail for the first event on the event + list. + * Added a call to syslog() to log unrecognized CURL errors in + 'lib/rdupload.cpp' and 'lib/rddownload.cpp'. + * Added code in 'lib/rdupload.cpp' to treat a partial file upload + as successful. +2010-05-17 Fred Gleason + * Fixed a bug in 'lib/rdaudioconvert.cpp' that caused corrupt + OggVorbis bitreams to be generated. +2010-05-17 Fred Gleason + * Fixed a bug in 'lib/rdflacdecode.cpp' that caused imported FLAC + files to contain silence. + * Tweaked the FLAC generation code to use sixteen bit audio + samples in 'lib/rdaudioconvert.cpp'. +2010-05-17 Fred Gleason + * Fixed a regression in 'rdlibrary/disk_ripper.cpp' that broke + disc ejection after rips. +2010-05-18 Fred Gleason + * Added 'docs/asound.conf-sample'. + * Changed the post-installscript in 'rivendell.spec.in' to use the + sample ALSA configuration instead of dynamically building one. +2010-05-18 Fred Gleason + * Fixed a bug in 'lib/rdcart.cpp' that broke the build under + Windows. + * Fixed a bug in 'lib/lib.pro' that broke the build under Windows. +2010-05-18 Fred Gleason + * Added a conditional compile in 'lib/rdpodcast.cpp' to allow + building under SuSE 10.0. +2010-05-18 Fred Gleason + * Altered the default value for the 'STATIONS.IPV4_ADDRESS' field + to '127.0.0.2'. + * Incremented the database version to 193. +2010-05-18 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that was setting the + default address of the initial workstaiton to '0.0.0.0'. +2010-05-19 Fred Gleason + * Increased 'RIPCD_MAX_CONNECTIONS' from 32 to 64 in + 'ripcd/ripcd.h'. + * Added a syslog call if ripcd(8) drops a connection in + 'ripcd/ripcd.cpp'. +2010-05-21 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that failed to create a + default system-wide settings record when creating a new database. +2010-05-21 Fred Gleason + * Fixed a bug in 'lib/rdpodcast.cpp' that caused a post to have a + zero length when posted from the web client. +2010-05-21 Fred Gleason + * Inserted a two second delay into the 'StopDaemons' subroutine in + 'rivendell-suse.in'. +2010-05-21 Fred Gleason + * Added code in 'rdcatchd/rdcatchd.cpp' to get SCHED_FIFO + permissions for the main rdcatchd(8) process. + * Added code in 'rdcatchd/batch.cpp' to get SCHED_BATCH permissions + for child rdcatchd(8) processes. + * Added code in 'utils/rdimport/rdimport.cpp' to get SCHED_BATCH + permissions when running in dropbox mode. +2010-05-21 Fred Gleason + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that caused + existing cart metadata values to be overwritten when using + rdimport(1) with the '--to-cart' switch. +2010-05-21 Fred Gleason + * Added a LogXloadDebugData=' directive to rd.conf(5). +2010-05-21 Fred Gleason + * Fixed a bug in 'lib/rdupload.cpp', 'lib/rddownload.cpp' and + 'lib/rdpodcast.cpp' that send binary cruft to syslog(3) when + LogXloadDebugData was enabled. +2010-05-24 Fred Gleason + * Fixed a bug in 'rivendell.spec.in' that caused the Rivendell + service to be left in the shutdown state after installation. + * Moved 'mysql' from 'Required-Start:' to 'Should-Start:' in + 'rivendell.suse.in'. +2010-05-24 Fred Gleason + * Added error logging in 'lib/rddownload.cpp' and + 'lib/rdupload.cpp'. +2010-05-24 Fred Gleason + * Fixed a bug in 'rivendell.spec.in' that caused the Rivendell + service to be left in the shutdown state after installation. +2010-05-24 Fred Gleason + * Increased the audio data ringbuffer size to 262,144 in + 'cae/cae.h'. + * Implemented MPEG L2 playout for ALSA devices in 'cae/cae.h', + 'cae/cae.cpp' and 'cae/cae_alsa.cpp'. +2010-06-01 Fred Gleason + * Fixed a bug in 'ripcd/vguest.cpp' that broke system login to + vGuest under OpenSuSE 11.2 i586. +2010-06-02 Fred Gleason + * Fixed a bug in 'rivendell-suse.in' that threw error messages + when stopping an already-stopped Rivendell service. +2010-06-02 Fred Gleason + * Modified 'rdlibrary/disk_gauge.cpp' and 'rdlibrary/disk_gauge.h' + to permit proper formatting under FVWM. +2010-06-03 Fred Gleason + * Fixed a bug in 'rdairplay/rdairplay.cpp' that caused zombie + processes to be created when forking new processes in an RLM. +2010-06-03 Fred Gleason + * Fixed a bug in 'rlm/Makefile.am' that broke the 'make uninstall' + target. +2010-06-07 Fred Gleason + * Implemented MPEG L2 encoding for the ALSA driver. +2010-06-08 Fred Gleason + * Added checks in 'rdlibrary/rdlibrary.cpp' and + 'rdlibrary/audio_cart.cpp' to verify proper deletion of audio when + deleting carts/cuts. +2010-06-08 Fred Gleason + * Added logging to report failure to purge a cut in + 'utils/rdmain/rdmaint.cpp'. + * Added checks in 'rdlogedit/rdlogedit.cpp', + 'rdlogedit/edit_log.cpp' and 'rdlogedit/voice_tracker.cpp' to + verify proper deletion of audio when deleting carts/cuts. +2010-06-08 Fred Gleason + * Added code in 'lib/rdcart_Search_text.cpp' to escape search + strings properly. + * Removed search word character limitations in + 'rdlibrary/rdlibrary.cpp'. + * Removed search word character limitations in + 'lib/rdcut_dialog.cpp'. +2010-06-08 Fred Gleason + * Removed resampler code for ALSA and JACK drivers. +2010-06-10 Fred Gleason + * Implemented MPEG decoding for the JACK driver. +2010-06-10 Fred Gleason + * Fixed a bug in 'cae/cae_alsa.cpp' that failed to handle + end-of-file properly when playing back MPEG audio. +2010-06-10 Fred Gleason + * Fixed a bug in 'cae/cae_alsa.cpp' that caused caed(8) to fail to + emit an 'SP' messages at the end of file playout. +2010-06-10 Fred Gleason + * Implemented MPEG Layer 2 encoding for the JACK driver. +2010-06-10 Fred Gleason + * Added 'UPGRADING'. +2010-06-10 Fred Gleason + * Added a 'SYSTEM.SAMPLE_RATE' field to the database. + * Incremented the database version to 194. + * Added 'RDSystem::sampleRate()' and 'RDSystem::setSampleRate()' + methods in 'lib/rdsystem.cpp' and 'lib/rdsystem.h'. + * Added a 'Sample Rate' control to the System Settings dialog in + 'rdadmin/edit_settings.cpp' and 'rdadmin/edit_Settings.h'. + * Removed 'RDLibraryConf::defaultSampleRate()' and + 'RDLibraryConf::setDefaultSampleRate()' methods in + 'lib/rdlibrary_conf.cpp' and 'lib/rdlibrary_conf.h'. + * Removed the 'Sample Rate:' control from the 'Edit RDLibrary' + dialog in 'rdadmin/edit_rdlibrary.cpp' and + 'rdadmin/edit_rdlibrary.h'. + * Marked the 'RDLIBRARY_CONF.DEFAULT_SAMPRATE' field as RETIRED. + * Removed 'RDLogEditConf::sampleRate()' and + 'RDLogEditConf::setSampleRate()' methods in + 'lib/rdlogedit_conf.cpp' and 'lib/rdlogedit_conf.h'. + * Removed the 'Sample Rate:' control from the 'Edit RDLogEdit' + dialog in 'rdadmin/edit_rdlogedit.cpp' and + 'rdadmin/edit_rdlogedit.h'. + * Marked the 'RDLOGEDIT_CONF.SAMPRATE' field as RETIRED. + * Removed 'RDDeck::sampRate()' and + 'RDDeck::setSampRate()' methods in 'lib/rddeck.cpp' and + 'lib/rddeck.h'. + * Removed the 'Sample Rate:' control from the 'Edit Deck' + dialog in 'rdadmin/edit_decks.cpp' and 'rdadmin/edit_Decks.h'. + * Marked the 'DECKS.DEFAULT_SAMPRATE' field as RETIRED. + * Removed 'RDRecording::sampRate()' and + 'RDRecording::setSampRate()' methods in 'lib/rdrecording.cpp' and + 'lib/rdrecording.h'. + * Marked the 'RECORDINGS.SAMPRATE' field as RETIRED. + * Removed the 'RDConfig::sampleRate()' method in + 'lib/rdconfig.cpp' and 'lib/rdconfig.h'. + * Removed the 'SampleRate=' directive in the '[Format]' section of + 'conf/rd.conf-sample'. + * Changed RD_ALSA_DEFAULT_PERIOD_QUANTITY from '2' to '4' in + 'lib/rd.h'. + * Removed 'RD_ALSA_SAMPLE_RATE_TOLERANCE' from 'lib/rd.h'. + * Modified 'cae/cae_alsa.cpp' to fail initialization of an ALSA + device if the exact correct sample rate is not supported. + * Removed 'conf/rd.conf-complete-sample'. +2010-06-11 Fred Gleason + * Modified 'rdadmin/createdb.cpp' to create the initial test tone + cart using the the 'RD_DEFAULT_SAMPLE_RATE' value from 'lib/rd.h'. + * Modified 'utils/rdgen/rdgen.c' to generate audio using a sample + rate of 48000. +2010-06-11 Fred Gleason + * Updated 'UPGRADING'. + * Updated 'README'. + * Updated 'INSTALL'. + * Removed 'SupportedCards' + * Removed 'ToDo'. +2010-06-14 Fred Gleason + * Added an 'RDPam' class in 'lib/rdpam.cpp' and 'lib/rdpam.h'. + * Added an 'RDSystemUser' class in 'lib/rdsystemuser.cpp' and + 'lib/rdsystemuser.h'. + * Fixed a bug in 'lib/rdupload.cpp' and 'lib/rddownload.cpp' that + permitted 'file:' transfers without validating user permissions. + * Modified 'rdcatch/edit_upload.cpp' and + 'rdcatch/edit_download.cpp' to permit entry of username and + password. + * Modified 'rdcatch/edit_upload.cpp' and + 'rdcatch/edit_download.cpp' to disallow use of 'smb:' protocol. +2010-06-15 Fred Gleason + * Fixed a bug in 'rdlibrry/edit_cart.cpp' that caused the full + list of groups to be displayed when editing multiple carts + regardless of user restrictions. +2010-06-15 Fred Gleason + * Added an 'RD_LIMITED_CART_SEARCH_QUANTITY' value in 'lib/rd.h'. + * Added a 'Show Only First 100 Matches' control in + 'rdlibrary/rdlibrary.cpp', 'rdlibrary/rdlibrary.h'. + * Added a 'Show Only First 100 Matches' control in + 'lib/rdcartdialog.cpp and 'lib/rdcartdialog.h'. + * Added a 'Show Only First 100 Matches' control in + 'lib/rdcutdialog.cpp and 'lib/rdcutdialog.h'. +2010-06-15 Fred Gleason + * Added a rule in 'lib/rdadd_log.cpp' to prevent entry of spaces + in a log names. +2010-06-15 Fred Gleason + * Updated 'UPGRADING'. +2010-06-16 Fred Gleason + * Fixed a bug in 'lib/rdwavefile.cpp' that broke the Xport Import + service. +2010-06-16 Fred Gleason + * Changed invocation order of services in the post script in + 'rivendell.spec.in'. +2010-06-18 Fred Gleason + * Fixed a bug in 'lib/rdupload.cpp' that caused uploads to fail + intermittently with a 'Partial File Transferred' error from libcurl. +2010-06-18 Fred Gleason + * Updated 'INSTALL'. +2010-06-18 Fred Gleason + * Fixed a bug in 'lib/rdfeed.cpp' that caused RDCastManager + uploads to fail intermittently with an 'Unknown Error' message. +2010-06-21 Fred Gleason + * Restored 'RD_ALSA_SAMPLE_RATE_TOLERANCE' from 'lib/rd.h'. +2010-06-21 Fred Gleason + * Added the ability to abort a running import or export in the + Audio Import/Export dialog in 'lib/rdimport_audio.cpp' and + 'lib/rdaudio_import.h'. +2010-06-21 Fred Gleason + * Implemented metadata export in ID3 tags in + 'lib/rdaudioconvert.cpp' and 'lib/rdaudioconvert.h'. + * Added an 'Export File Metadata' check box to the 'Audio + Import/Export' dialog in 'lib/rdimport_audio.cpp'. + * Added an 'ENABLE_METADATA' field to the Export service in + 'web/rdxport/export.cpp' and 'web/tests/export.html'. +2010-06-21 Fred Gleason + * Added a 'RECORDINGS.ENABLE_METADATA' field to the database. + * Incremented the database version to 195. + * Added 'RDRecording::enableMetadata()' and + 'RDRecording::setEnableMetadata()' in 'lib/rdrecording.cpp' and + 'lib./rdrecording.h'. + * Added an 'Update Library Metadata' checkbox to the Edit Download + dialog in 'rdcatch/edit_download.cpp' and + 'rdcatch/edit_download.h'. + * Added an 'Export Library Metadata' checkbox to the Edit Upload + dialog in 'rdcatch/edit_upload.cpp' and + 'rdcatch/edit_upload.h'. +2010-06-21 Fred Gleason + * Implemented the 'dwLevelReference' field in CartChunk exports + for PCM16 exports in 'lib/rdaudioconvert.cpp'. +2010-06-23 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' that threw a segfault when + creating an RDCut with a null cutname. +2010-06-23 Fred Gleason + * Changed the default setting for the '--offline-host-warnings' to + rdcatch(1) from 'yes' to 'no' in 'rdcatch/rdcatch.cpp'. +2010-06-23 Fred Gleason + * Removed the single instance lock from rdcatch(1) in + 'rdcatch/rdcatch.cpp' and 'rdcatch/rdcatch.h'. +2010-06-23 Fred Gleason + * Removed the single instance lock from rdlibrary(1) in + 'rdlibrary/rdlibrary.cpp' and 'rdlibrary/rdlibrary.h'. +2010-06-23 Fred Gleason + * Removed the 'QT_NO_KDE_INTEGRATION' hack from + 'rdadmin/rdadmin.cpp', 'rdairplay/rdairplay.cpp', + 'rdcastmanager/rdcastmanager.cpp', 'rdcatch/rdcatch.cpp', + 'rdlibrary/rdlibrary.cpp', 'rdlogedit/rdlogedit.cpp', + 'rdlogin/rdlogin.cpp', 'rdlogmanager/rdlogmanager.cpp', + 'utils/rdgpimon/rdgpimon.cpp', 'utils/rdsoftkeys/rdsoftkeys.cpp' + and 'utils/rmlsend/rmlsend.cpp'. +2010-06-23 Fred Gleason + * Implemented playout fader number display for rdpanel(1) in + 'rdpanel/rdpanel.cpp'. +2010-06-25 Fred Gleason + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' that caused a segfault + when creating a new log under Windows. +2010-07-02 Fred Gleason + * Added a dependency for ivman(8) in 'rivendell.spec.in'. +2010-07-02 Fred Gleason + * Fixed a bug in 'configure.in' that broke the 'configure' script. +2010-07-02 Fred Gleason + * Added 'DROPBOXES.IMPORT_CREATE_DATES', + 'DROPBOXES.CREATE_STARTDATE_OFFSET' and + 'DROPBOXES.CREATE_ENDDATA_OFFSET' fields to the database. + * Incremented the database version to 196. + * Added ''RDDropbox::createDates()', + 'RDDropbox::setCreateDates()', + 'RDDropbox::createStartdateOffset()', + 'RDDropbox::setCreateStartdateOffset()', + 'RDDropbox::createEnddateOffset()' and + 'RDDropbox::setCreateEnddateOffset()' methods in + 'lib/rddropbox.cpp' and 'lib/rddropbox.h'. + * Added 'Create Dates when no Dates Exist', 'Create start date + offset' and 'Create end date offset' controls to the 'Dropbox + Configuration' dialog in 'rdadmin/edit_dropbox.cpp' and + 'rdadmin/edit_dropbox.h'. + * Added '--create-startdate-offset' and '--create-enddate-offset' + swtiches for RDImport(1) in 'utils/rdimport/rdimport.cpp' and + 'utils/rdimport/rdimport.h'. + * Added code in 'rdcatchd/rdcatchd.cpp' to implement start and end + date creation in dropboxes. +2010-07-06 Fred Gleason + * Added arguments to the post-install script in + 'rivendell.spec.in' to create the 'rivendell' user with a UID of + '150'. + * Added arguments to the post-install script in + 'rivendell.spec.in' to create the 'rivendell' group with a GID of + '150'. +2010-07-06 Fred Gleason + * Removed the 'Split' cart type. +2010-07-07 Fred Gleason + * Added a 'REPLICATORS' table to the database. + * Added a 'REPLICATOR_MAP' table to the database. + * Added a 'REPL_CART_STATE' table to the database. + * Added a 'REPL_CUT_STATE' table to the database. + * Added a 'CART.METADATA_DATETIME' field to the database. + * Added a 'RDCart::WriteTimestamp()' method in 'lib/rdcart.cpp' + and 'lib/rdcart.h'. + * Incremented the database version to 197. + * Added an 'RDReplicator' class in 'lib/rdreplicator.cpp' and + 'lib/rdreplicator.h'. + * Added an 'Add Replicator' dialog in 'rdadmin/add_replicator.cpp' + and 'rdadmin/add_replicator.h'. + * Added an 'Edit Replicator' dialog in 'rdadmin/edit_replicator.cpp' + and 'rdadmin/edit_replicator.h'. + * Added an 'List Replicators' dialog in 'rdadmin/list_replicators.cpp' + and 'rdadmin/list_replicators.h'. +2010-07-09 Fred Gleason + * Added a rdrepld(8) daemon in 'rdrepld/'. + * Added a 'ListGroup' Xport service in 'web/rdxport/groups.cpp'. + * Added a 'ListGroups' Xport service in 'web/rdxport/groups.cpp'. + * Added a 'ListCarts' Xport service in 'web/rdxport/carts.cpp'. + * Added a 'ListCart' Xport service in 'web/rdxport/carts.cpp'. +2010-07-10 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that broke creation of a + new database. +2010-07-10 Fred Gleason + * Fixed a bug in 'lib/rdweb.cpp' that broke XML redndering of + special characters. +2010-07-10 Fred Gleason + * Documented the web services API in 'docs/web_api.ods'. + * Added a 'RDUser::cartAuthorized()' method in 'lib/rduser.cpp' + and 'lib/rduser.h'. + * Added 'ListCut' and 'ListCuts' web methods in + 'web/rdxport/carts.cpp'. +2010-07-10 Fred Gleason + * Removed the sample rate argument from the 'RDCart::addCut()' + method in 'lib/rdcart.cpp' and 'lib/rdcart.h'. +2010-07-11 Fred Gleason + * Added an 'AddCut' web method in 'web/rdxport/carts.cpp'. + * Added a 'RemoveCut' web method in 'web/rdxport/carts.cpp'. + * Added an 'AddCart' web method in 'web/rdxport/carts.cpp'. + * Added a 'RemoveCart' web method in 'web/rdxport/carts.cpp'. + * Added an 'EditCart' web method in 'web/rdxport/carts.cpp'. +2010-07-11 Fred Gleason + * Added RML data to the output of 'RDCart::xml()' in + 'lib/rdcart.cpp' and 'lib/rdcart.h'. +2010-07-11 Fred Gleason + * Added 'MACRO' argument to the 'EditCart' web method in + 'web/rdxport/carts.cpp'. +2010-07-20 Fred Gleason + * Added a SoundTouch dependency in 'configure.in'. + * Added an 'RDAudioConvert::setSpeedRatio()' method in + 'lib/rdaudioconvert.cpp' and 'lib/rdaudioconvert.h'. + * Added a '--speed-ratio' switch in + 'tests/audio_convert_test.cpp'. + * Modified 'web/rdxport/export.cpp' and 'rdrepld/citadelxds.cpp' + to honor enforced lengths in the Library. +2010-07-21 Fred Gleason + * Fixed a bug in 'configure.in' that failed to display an error + when the SoundTouch library was not detected. +2010-07-21 Fred Gleason + * Added a 'TYPE' argument to the ListCarts web method in + 'web/rdxport/carts.cpp'. +2010-07-23 Fred Gleason + * Added 'RDLocalToUtc()', 'RDUtcToLocal()' and + 'RDTimeZoneOffset()' functions in 'lib/rdconf.cpp' and + 'lib/rdconf.h'. + * Added an 'EditCut' web method. +2010-07-23 Fred Gleason + * Added an 'ISCI_XREFERENCE' table to the database. + * Added a 'SYSTEM.ISCI_XREFERENCE_PATH' field to the database. + * Added a 'VERSION.LAST_ISCI_XREFERENCE' field to the database. + * Incremented the database version to 198. + * Added 'RDSystem::isciXreferencePath()' and + 'RDSystem::setIsciXreferencePath()' methods in 'lib/rdsystem.cpp' + and 'lib/rdsystem.h'. + * Added an 'ISCI Cross Reference Path' control to the Edit System + Settings dialog in 'rdadmin/edit_settings.cpp' and + 'rdadmin/edit_settings.h'. + * Added an 'RDStringList' class in 'lib/rdstringlist.cpp' and + 'lib/rdstringlist.h'. +2010-07-26 Fred Gleason + * Implemented filename data from the ISCI cross reference table + into the Citadel XDS replicator. +2010-07-26 Fred Gleason + * Removed the 'RLM_CARTTYPE_SPLIT' define from 'rlm/rlm.h'. + * Added 'rlm_ext_eventid', 'rlm_ext_data' and 'rlm_ext_annctype' + fields to the 'rlm_log' struct in 'rlm/rlm.h'. + * Incremented the 'RLM_VERSION' define to '11' in 'rlm/rlm.h'. +2010-07-26 Fred Gleason + * Refactored the 'rlm_xds' plug-in to utilize ISCI data from the + log instead of the library. +2010-07-26 Fred Gleason + * Documented the DB fields used for ISCI and GUID data for the + 'CounterPoint' log format in 'docs/scheduler_formats.ods'. +2010-07-26 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' and 'lib/rdcart.cpp' that broke + the build under Windows. +2010-07-26 Fred Gleason + * Fixed a bug in 'rivendell.spec.in' that broke the 'make rpm' + target. +2010-07-27 Fred Gleason + * Added a check for illegal filename values in + 'rdrepld/citadelxds.cpp' and 'rdrepld/citadelxds.h'. +2010-07-27 Fred Gleason + * Added indexes to the 'ISCI_XREFERENCE' table; + * Incremented the database version to 199. +2010-07-27 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that caused an incorrect + value to be set for the default sample rate in the 'SYSTEM' table. +2010-07-27 Fred Gleason + * Fixed a typo in 'rivendell.spec.in' that broke the 'make rpm' + target. +2010-07-29 Fred Gleason + * Fixed a bug in 'configure.in' that threw an error when executing + './configure' with no MPEG libraries installed. + * Fixed a bug in 'lib/rdaudioconvert.cpp' that broke the build + when building with no MAD support. +2010-08-03 Fred Gleason + * Fixed a bug in 'rdadmin/rename_group.cpp' that failed to + propagate changes in Group names to the music scheduling dropbox + and replicator subsystems. +2010-08-03 Fred Gleason + * Removed the 'RDReplicator::TypeRivendell' value from + 'RDReplicator::Type' in 'lib/rdreplicator.h'. +2010-08-03 Fred Gleason + * Added a 'RipcdConnection' class in 'ripcd/ripcd_connection.cpp' + and 'ripcd/ripcd_connection.h'. + * Refactored ripcd(8) to remove arbitrary limitation on number of + connections. +2010-08-03 Fred Gleason + * Added a 'Switcher' abstract base class in 'ripcd/switcher.cpp' + and 'ripcd/switcher.h'. + * Refactored the BroadcastTools SS8.2 driver to use the 'Switcher' + base class in 'ripcd/btss82.cpp' and 'ripcd/btss82.h'. + * Refactored the BroadcastTools 10x1 driver to use the 'Switcher' + base class in 'ripcd/bt10x1.cpp' and 'ripcd/bt10x1.h'. + * Refactored the BroadcastTools 16x1 driver to use the 'Switcher' + base class in 'ripcd/bt16x1.cpp' and 'ripcd/bt16x1.h'. + * Refactored the BroadcastTools 16x2 driver to use the 'Switcher' + base class in 'ripcd/bt16x2.cpp' and 'ripcd/bt16x2.h'. + * Refactored the BroadcastTools 8x2 driver to use the 'Switcher' + base class in 'ripcd/bt8x2.cpp' and 'ripcd/bt8x2.h'. + * Refactored the BroadcastTools ACS8.2 driver to use the 'Switcher' + base class in 'ripcd/btacs82.cpp' and 'ripcd/btacs82.h'. + * Refactored the BroadcastTools SRC-16 driver to use the 'Switcher' + base class in 'ripcd/btsrc16.cpp' and 'ripcd/btsrc16.h'. + * Refactored the BroadcastTools SRC-8III driver to use the 'Switcher' + base class in 'ripcd/btsrc8iii.cpp' and 'ripcd/btsrc8iii.h'. + * Refactored the BroadcastTools SS12.4 driver to use the 'Switcher' + base class in 'ripcd/btss124.cpp' and 'ripcd/btss124.h'. + * Refactored the BroadcastTools SS16.4 driver to use the 'Switcher' + base class in 'ripcd/btss164.cpp' and 'ripcd/btss164.h'. + * Refactored the BroadcastTools SS4.2 driver to use the 'Switcher' + base class in 'ripcd/btss42.cpp' and 'ripcd/btss42.h'. + * Refactored the BroadcastTools SS4.4 driver to use the 'Switcher' + base class in 'ripcd/btss44.cpp' and 'ripcd/btss44.h'. + * Refactored the LiveWire driver to use the 'Switcher' + base class in 'ripcd/livewire.cpp' and 'ripcd/livewire.h'. + * Refactored the Local Audio Adapter driver to use the 'Switcher' + base class in 'ripcd/local_audio.cpp' and 'ripcd/local_audio.h'. + * Refactored the Local GPIO driver to use the 'Switcher' + base class in 'ripcd/local_gpio.cpp' and 'ripcd/local_gpio.h'. + * Refactored the Quartz1 driver to use the 'Switcher' + base class in 'ripcd/quartz1.cpp' and 'ripcd/quartz1.h'. + * Refactored the SAS 32000 driver to use the 'Switcher' + base class in 'ripcd/sas32000.cpp' and 'ripcd/sas32000.h'. + * Refactored the SAS 64000 driver to use the 'Switcher' + base class in 'ripcd/sas64000.cpp' and 'ripcd/sas64000.h'. + * Refactored the SAS 64000 GPI driver to use the 'Switcher' + base class in 'ripcd/sas64000gpi.cpp' and 'ripcd/sas64000gpi.h'. + * Refactored the SAS USI driver to use the 'Switcher' + base class in 'ripcd/sasusi.cpp' and 'ripcd/sasusi.h'. + * Refactored the StarGuide III driver to use the 'Switcher' + base class in 'ripcd/starguide3.cpp' and 'ripcd/starguide3.h'. + * Refactored the Unity 4000 driver to use the 'Switcher' + base class in 'ripcd/unity4000.cpp' and 'ripcd/unity4000.h'. + * Refactored the Logitek vGuest driver to use the 'Switcher' + base class in 'ripcd/vguest.cpp' and 'ripcd/vguest.h'. +2010-08-04 Fred Gleason + * Fixed a bug in 'ripcd/local_macros.cpp' that caused 'GI' and + 'GO' messages to be sent without the 'mask' parameter. + * Fixed a bug in 'ripcd/livewire.cpp' that caused GPIO resources + to be misreported. +2010-08-04 Fred Gleason + * Applied patch from Antonio Cardoso Martins + that remedied correctness issues with + Desktop entries in 'xds/'. +2010-08-04 Fred Gleason + * Added a pt_BR translation by Daniel Roviriego + . +2010-08-04 Fred Gleason + * Fixed a bug in 'rdlibrary/disk_ripper.cpp' that failed to apply + the Album metadata. +2010-08-06 Fred Gleason + * Added a 'Label=' parameter to rlm_ando.conf(5) in + 'rlm/rlm_ando.c' and 'conf/rlm_ando.conf'. + * Added an Icecast2 RLM in 'rlm/rlm_icecast.c', adapted from code + contributed by Ferdinand O. Tempel . +2010-08-06 Fred Gleason + * Updated 'UPGRADING'. +2010-08-06 Fred Gleason + * Altered 'rlm/rlm_ando.c' to send event length using 'HH:MM:SS' + format when using the enhanced string mode. +2010-08-06 Fred Gleason + * Fixed a bug in 'acinclude.m4' that broke 'configure'. +2010-08-10 Fred Gleason + * Fixed a bug in 'lib/rdaudioconvert.cpp' that threw a segfault + when decoding MPEG files with large frame lengths. +2010-08-10 Fred Gleason + * Fixed a bug in 'cae/cae_alsa.cpp' that threw a segfault + when decoding MPEG files with large frame lengths. + * Fixed a bug in 'cae/cae_jack.cpp' that threw a segfault + when decoding MPEG files with large frame lengths. +2010-08-19 Fred Gleason + * Updated the 'INSTALL' file. + * Updated the 'NEWS' file. + * Updated the 'UPGRADING' file. + * Incremented the package version to 2.0.0beta0. +2010-08-19 Fred Gleason + * Added Daniel Roviriego to 'AUTHORS'. +2010-08-25 Fred Gleason + * Applied a patch from Stefan Gabriel that + implements playout-only support for OggVorbis cuts. +2010-08-25 Fred Gleason + * Applied updated German (de) translation from Michael Papsdorf + . +2010-09-08 Fred Gleason + * Added a 'STATIONS.WEB_SERVICE_URL' field to the database. + * Incremented the database field to 200. + * Added 'RDStation::webServiceUrl()' and + 'RDStation::setWebServiceUrl()' methods in 'lib/rdstation.cpp' and + 'lib/rdstation.h'. + * Added an 'XPort URL' control to the 'Edit Host' dialog in + 'rdadmin/edit_staion.cpp' and 'rdadmin/edit_staion.h'. +2010-09-10 Fred Gleason + * Implemented the 'Set Output State Flag' and 'Meter Update' + commands for caed(8) in 'cae/cae.cpp', 'lib/rdcae.cpp' and + 'lib/rdcae.h'. + * Removed the 'RDMeterBlock' shared memory segment implementation + in 'lib/rd.h', 'lib/rdcae.cpp', 'lib/rdcae.h', 'cae/cae.cpp', + 'cae/cae.h' and 'pam_rd/pam_rd.cpp'. +2010-09-10 Fred Gleason + * Removed the 'STATIONS.WEB_SERVICE_URL' field from the database. + * Added 'STATIONS.HTTP_STATION' and 'STATIONS.CAE_STATION' to the + database. + * Incremented the database field to 201. + * Added a 'System Services' section to the 'Edit Host' dialog in + 'rdadmin/edit_station.cpp' and 'rdadmin/edit_station.h'. +2010-09-13 Fred Gleason + * Added login in RDAdmin(1) to apply channel assignment limits on + the basis of CAE service redirection. +2010-09-13 Fred Gleason + * Documented an 'Export Peaks' web service in 'docs/web_api.ods'. + * Added a 'RDXPORT_COMMAND_EXPORT_PEAKS' web command code in + 'lib/rdxport_interface.h'. + * Implemented the 'ExportPeaks' web service in + 'web/rdxport/rdxport.cpp', 'web/rdxport/rdxport.h'. and + 'web/rdxport/exportpeaks.cpp'. + * Refactored the 'Edit Audio' dialog in 'lib/edit_audio.cpp' and + 'lib/edit_audio.h' to use the ExportPeaks web service. + * Refactored the 'Voice Tracker' dialog in + 'rdlogedit/voice_tracker.cpp' and 'rdlogedit/voice_tracker.h' to + use the ExportPeaks web service. +2010-09-14 Fred Gleason + * Fixed a bug in 'lib/rdcae.cpp' that caused connections to hang. + * Fixed a bug in 'lib/rdcae.cpp' that broke connections to remote + caed(8) instances. +2010-09-14 Fred Gleason + * Optimized position and output status update code in + 'cae/cae.cpp'. +2010-09-14 Fred Gleason + * Fixed a bug in 'rdcatchd/batch.cpp' that caused the incorrect + sample rate value to be applied when importing audio. +2010-09-16 Fred Gleason + * Added an 'RDHPIRecordStream::samplesRecorded()' class in + 'rdhpi/rdhpirecrodstream.cpp' and 'rdhpi/rdhpirecordsteram.h'. + * Implemented a record length parameter for the return for the + 'Unload Record' [UR] command in caed(8). +2010-09-24 Fred Gleason + * Fixed a bug in 'cae/cae.h' and 'cae/cae_jack.cpp' that broke the + build when JACK was not present. +2010-10-04 Fred Gleason + * Fixed a bug in 'cae/cae_hpi.cpp', 'cae/cae_alsa.cpp' and + 'cae/cae_jack.cpp' that caused playback position to be reported + in samples instead of milliseconds. + * Fixed a bug in 'lib/rdedit_audio.cpp' that caused the playback + cursor to disappear when the transport was stopped in the EditAudio + dialog. +2010-10-04 Todd Baker + * Added RDHOTKEYS table to the database. + * Incremented the database version to 202. + * Added a 'RDHOTKEYLIST' class in 'lib/rdhotkeylist.cpp' and + 'lib/rdhotkeylist.h. + * Added a RDAirplay_Hotkeys class in 'lib/rdairplay_hotkeys.cpp' + and 'lib/rdairplay_hotkeys.h' + * Added 'HotKey' configuration button in 'rdadmin/edit_rdairplay.cpp'. + * Added 'editHotKeys()' methods in 'rdadmin/edit_rdairplay_hotkeys.cpp' + and 'rdadmin/edit_rdairplay_hotkeys.h'. + * Added 'RDHOTKEYS' table creation and upgrade database code to + 'rdadmin/createdb.cpp'. + * Added deletion of 'RDHOTKEYS' table in 'rdadmin/list_stations.cpp'. + * Added 'pauseButtonHotkey()' and 'stopButtonHotkey()' methods + in 'rdairplay/button_log.cpp' and 'rdairplay/button_log.h'. + * Added 'RDHotKeyList' and 'RdHotKeys' objects to + 'rdairplay/rdairplay.cpp' and 'rdairplay/rdairplay.h'. + * Added code to intercept keystrokes and compare/execute commands + when matching hotkeys are found in 'rdairplay/rdairplay.cpp'. +2010-10-04 Fred Gleason + * Added code in 'rdadmin/add_station.cpp' to clone hotkey + assignments. +2010-10-05 Fred Gleason + * Implemented a TrimAudio web service in + 'web/rdxport/trimaudio.cpp'. + * Added a 'RDTrimAudio' class in 'lib/rdtrimaudio.cpp' and + 'lib/rdtrimaudio.h'. + * Fixed a bug in the EditAudio dialog that broke operation of the + Start and End Trim buttons. +2010-10-06 Fred Gleason + * Fixed an uninitialized value bug in 'lib/rdtimeedit.cpp'. + * Fixed an uninitialized value bug in 'rdairplay/pie_counter.cpp'. + * Fixed an uninitialized value bug in 'rdairplay/mode_display.cpp'. +2010-10-06 Fred Gleason + * Added 'scripts/rd_memmon.sh'. +2010-10-06 Fred Gleason + * Updated 'scripts/rd_memmon.sh'. +2010-10-06 Fred Gleason + * Fixed a memory leak in 'lib/rdairplay_hotkeys.cpp'. +2010-10-10 Fred Gleason + * Refactored font management for the Label widget to use a static + table of fonts. +2010-10-10 Fred Gleason + * Refactored the List Logs dialog in 'rdairplay/list_logs.cpp' and + 'rdairplay/list_logs.h' to utilize a single instance per log. +2010-10-10 Fred Gleason + * Modified logic in 'rdlibrary/rdlibrary.cpp', + 'lib/rdcart_dialog.cpp' and 'lib/rdcut_dialog.cpp' to default the + 'Show Only First 100 Matches' to checked. +2010-10-11 Fred Gleason + * Updated 'AUTHORS'. + * Updated 'NEWS'. + * Incremented the package version to 2.0.0beta1. +2010-10-18 Fred Gleason + * Fixed a bug in 'lib/export_deltaflex.cpp' that caused report + generation to hang when the 'EXT_DATA' field contained data longer + than 8 characters. +2010-10-20 Todd Baker + * Replaced rdadmin/edit_rdairplay_hotkeys.cpp and + edit_rdairplay_hotkeys.h with edit_hotkeys.cpp and + edit_hotkeys.h. New edit_hotkeys class is generic and can be used by + any module. + * Replaced lib/rdairplay_hotkeys.cpp and rdairplay_hotkeys.h + with lib/rdhotkeys.cpp and lib/rdhotkeys.h. + * Modified logic in rdairplay/rdairplay.cpp to utilize the + new rdhotkey class structure. +2010-11-08 Fred Gleason + * Added 'docs/ando_interfact.odt'. +2010-11-24 Fred Gleason + * Fixed a bug in 'lib/rdpeaksexport.cpp', 'lib/rdaudioimport.cpp', + 'lib/rdaudioimport.cpp', '/lib/rdcart.cpp', 'lib/rddownload.cpp', + 'lib/rdpodcast.cpp', 'lib/rdtrimaudio.cpp' and 'lib/rdupload.cpp' + that threw a 'URL using bad/illegal format or missing URL' error from + libcurl-7.15.5. +2010-11-24 Fred Gleason + * Made FLAC support optional at build time. +2010-11-24 Fred Gleason + * Fixed a typo in 'lib/rdwavefile.cpp'. +2010-11-24 Fred Gleason + * Added code in 'lib/rdconfig.cpp' to handle cases where + gethostname(2) returns a FQDN instead of just the host part. +2010-11-24 Fred Gleason + * Added support for RedHat/CentOS to the 'make rpm' target. +2010-11-24 Fred Gleason + * Fixed a bug in 'rivendell.spec.in' that placed the Apache + configuration in the wrong place on RedHat/CentOS. +2010-12-03 Fred Gleason + * Added support for RedHat/CentOS in 'get_distro.sh'. +2010-12-06 Fred Gleason + * Fixed a bug in 'rivendell.spec'.in' that broke the + post-installation script on RedHat/CentOS. +2010-12-06 Fred Gleason + * Added code in 'configure.in' to detect CDParanoia on RedHat/CentOS. +2010-12-07 Fred Gleason + * Refactored XDG menu files in 'xdg/'. + * Added --mysql-admin-hostname and --mysql-admin-dbname switches + to RDAdmin(1). +2010-12-08 Fred Gleason + * Fixed a bug in 'rivendell.spec'in' that caused services to not be + initialized properly on RedHat/CentOS. +2010-12-09 Fred Gleason + * Changed the 'Hostname=' parameter in 'conf/rd.conf-sample' from + '127.0.0.1' to 'localhost'. +2010-12-09 Fred Gleason + * Fixed a bug in 'rdhpi/rdhpisoundcard.cpp' that broke the build with + hpklinux-4.04.07. +2010-12-12 Fred Gleason + * Added chkconfig(8) info to 'rivendell-suse.in'. +2010-12-12 Fred Gleason + * Added a check in 'utils/rddbcheck/rddbcheck.cpp' and + 'utils/rddbcheck/rddbcheck.h' to validate audio lengths of data + in '/var/snd' against the values in the CUTS table. +2010-12-12 Fred Gleason + * Fixed a bug in 'rivendell-suse.in' that caused the daemons to be + assigned incorrect boot priorities on RedHat/CentOS. +2010-12-15 Fred Gleason + * Refactored categories in the Desktop files in 'xdg/' to eliminate + duplicate menu appearances. + * Added 'X-KDE-SubstituteUID' and 'X-KDE-Username' attributes in + 'xdg/rivendell-rdhpiinfo.desktop'. +2010-12-16 Fred Gleason + * Added chkconfig(8) entries to 'rdrepld-suse.in'. +2010-12-17 Fred Gleason + * Fixed a bug in 'lib/rdsound_panel.cpp' that allowed users without + the 'Configure System Panels' privilege to edit the name of system + panels. +2010-12-21 Fred Gleason + * Added 'scripts/rdmemcheck.sh'. +2011-01-03 Fred Gleason + * Fixed bugs in 'lib/rdsound_panel.cpp', 'lib/rdsound_panel.h', + 'lib/rdbutton_panel.cpp' and 'lib/rdbutton_panel.h' that caused memory + leaks when changing the active user. +2011-01-04 Fred Gleason + * Fixed a bug in 'lib/rdlog_event.cpp' and 'lib/rdlog_event.h' that + caused memory leaks when unloading a log. +2011-01-04 Fred Gleason + * Fixed a bug in 'lib/rdmacro_event.cpp' and 'lib/rdmacro_event.h' + that caused memory leaks when executing a macro cart. +2011-01-05 Fred Gleason + * Fixed a bug in 'helpers/Makefile.am' that generated a warning from + autoconf(1). +2011-01-05 Fred Gleason + * Added an 'RDGetTextColor()' function in 'lib/rdconf.cpp' and + 'lib/rdconf.h'. + * Refactored the RDPanelButton class to use smoothed bitmap fonts. +2011-01-05 Fred Gleason + * Modified the 'Edit Button' dialog in 'lib/rdbutton_dialog.cpp' so + as to utilized calculated text colors for the 'Color' button. +2011-01-09 Fred Gleason + * Modifed 'lib/rdaudioconvert.cpp' to use SF_FORMAT_FLOAT as the + stage 1->2 file format. + * Fixed a bug in 'lib/rdaudioconvert.cpp' that caused clipping to be + introduced when converting from an MPEG file containing samples with + amplitude above the reference level. +2011-01-10 Fred Gleason + * Added an 'RD_CURL_TIMEOUT' define in 'lib/rd.h'. +2011-01-10 Fred Gleason + * Added a check in 'lib/rdaudioconvert.cpp' to detect loss of sync + in an MPEG bitstream. +2011-01-10 Fred Gleason + * Fixed a bug in 'ripcd/ripcd.cpp' that caused a segfault when + RDGpiMon attempted to monitor a non-configured matrix. +2011-01-10 Fred Gleason + * Modified 'rdairplay/mode_display.cpp' to use color bitmaps. +2011-01-10 Fred Gleason + * Modified 'rdairplay/stop_counter.cpp' to use color bitmaps. +2011-01-11 Fred Gleason + * Modified 'rdairplay/wall_clock.cpp' to use color bitmaps. +2011-01-11 Fred Gleason + * Modified 'rdairplay/post_counter.cpp' to use color bitmaps. +2011-01-12 Fred Gleason + * Fixed a bug in 'lib/rdaudioimport.cpp' that caused an error to be + returned when processing files containing non-ASCII characters in + their name. +2011-01-12 Fred Gleason + * Applied a patch from Bartlomiej Krajewski + that added support for setting + 12-play mode on an ASI 6640 in rdhpiinfo(8). +2011-01-17 Fred Gleason + * Fixed a bug in 'rdairplay/list_logs.cpp' that caused the list of + available logs to fail to be refreshed. +2011-01-19 Fred Gleason + * Fixed a path error in 'scripts/rd_config'. +2011-01-25 Fred Gleason + * Fixed a bug in 'lib/rdwavefile.cpp' and 'lib/rdwavefile.h' where + importation of a IEEE floating point format WAV file would result + in a length of '0' being stored in the database. +2011-01-25 Fred Gleason + * Implemented a 'CopyAudio' XPort service in + 'web/rdxport/copyaudio.cpp', 'web/rdxport/rdxport.cpp' and + 'web/rdxport/rdxport.h'. + * Added a 'RDCopyAudio' class in 'lib/rdcopyaudio.cpp' and + 'lib/rdcopyaudio.h'. + * Modified the 'RDCut::copyTo()' method to use the CopyAudio + web service. +2011-02-11 Fred Gleason + * Added a 'RIPPER_MAX_SECTORS' compile-time variable in 'lib/rd.h'. + * Fixed a bug in 'lib/rdcdripper.cpp' that caused corrupt audio to be + generated when ripping with certain DVD drives. + * Fixed a bug in 'rdadmin/createdb.cpp' that resulted in an incorrect + default value for maximum post size being set when creating a new + database. +2011-02-11 Fred Gleason + * Added exemplar files in 'docs/examples/0320090805.elr', + 'docs/examples/0320090805.tfc', 'docs/examples/0320090805.vti' and + 'docs/examples/cart_report.asc'. + * Corrected a typo in 'docs/scheduler_formats.ods'. +2011-02-11 Fred Gleason + * Tweaked field layout in 'rdairplay/loglinebox.cpp' so as to keep + character descenders from being cut off on RedHat/CentOS. +2011-02-11 Fred Gleason + * Fixed a bug in 'rdairplay/start_button.cpp' that caused corrupt + text display on RedHat/CentOS. +2011-02-11 Fred Gleason + * Fixed a bug in 'rdlibrary/audio_cart.cpp' that caused corrupt + text display on RedHat/CentOS. +2011-02-11 Fred Gleason + * Fixed a bug in 'docs/Makefile.am' that caused the 'configure' script + to fail. +2011-02-14 Fred Gleason + * Added support for including a Win32 setup in an RPM in 'configure.in' + and 'rivendell.spec.in'. +2011-02-14 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' that broke the build on + Windows. +2011-02-15 Fred Gleason + * Fixed a bug in 'web/rdcastmanager/rdcastmanager.cpp' that broke + post uploading on RedHat/CentOS. +2011-02-16 Fred Gleason + * Updated 'NEWS'. + * Removed the beta warning from 'README'. + * Updated 'UPGRADING'. + * Incremented the package version to 2.0.0rc0'. +2011-02-16 Fred Gleason + * Fixed a bug in 'lib/rdexpeakexport.cpp' that broke the build + on some platforms. +2011-02-17 Fred Gleason + * Documented the ExportPeaks and TrimAudio XPort service methods in + 'docs/xport_service.odt'. +2011-02-17 Fred Gleason + * Implemented an AudioInfo Xport service method in + 'web/rdxport/audioinfo.cpp'. + * Added an 'RDAudioInfo' class in 'lib/rdaudioinfo.cpp' and + 'lib/rdaudioinfo.h'. + * Fixed a bug in 'lib/rdedit_audio.cpp' that made it impossible to + display an entire waveform when the end marker was placed near the + start of the cut. +2011-02-21 Fred Gleason + * Fixed a bug in 'rdadmin/opendb.cpp' that displayed creation of a + new database as an error. +2011-03-01 Fred Gleason + * Added the ability to specify destination UDP port in the address + field of the 'Command Send' ['CC'] RML. +2011-03-01 Fred Gleason + * Added 'helpers/setenvvar.sh' and 'helpers/rdtransgui.sh' from + Frederick Henderson . +2011-03-03 Fred Gleason + * Fixed bugs in 'lib/rdedit_audio.cpp' and 'lib/rdaudioinfo.cpp' + that caused segfaults on OpenSuSE 11.2. +2011-03-08 Fred Gleason + * Fixed a bug in 'lib/rdmacro.cpp' that broke delivery of RMLs + via ripcd(8). +2011-03-11 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.0.0rc1. +2011-03-24 Fred Gleason + * Rearranged menu layout in 'xdg/'. +2011-03-25 Fred Gleason + * Added default skin paths paths in 'lib/rdpaths.h.in'. +2011-03-28 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that caused creation of a new + database to fail. +2011-03-28 Fred Gleason + * Fixed a bug in 'rdairplay/loglinebox.cpp' that caused the top + of the title field to clipped in the button widget in RDAirPlay. +2011-04-01 Fred Gleason + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that caused the + '--autotrim-level=' switch to be ignored. +2011-04-01 Fred Gleason + * Changed the interpreter for 'rivendell-suuse.in' from '/bin'sh' + to '/bin/bash'. +2011-04-05 Fred Gleason + * Fixed a regression in 'utils/rdimport/rdimport.cpp' that broke + metadata processing. +2011-04-05 Fred Gleason + * Updated 'NEWS' + * Incremented the package version to 2.0.1. +2011-04-06 Fred Gleason + * Changed the default value of 'RDAIRPLAY.CHECK_TIMESYNC' to 'N'. +2011-04-24 Fred Gleason + * Stubbed out a serial transmission path for the 'rlm_xds' plug-in in + 'rlm/rlm_xds.c'. +2011-04-26 Fred Gleason + * Added support for opto inputs to the SasUsi driver in + 'ripcd/sasusi.cpp'. +2011-05-02 Fred Gleason + * Fixed a bug in 'rdlibrary/edit_cart.cpp' that threw a segfault + when editing multiple carts [Mantis bug #0000004]. +2011-05-02 Fred Gleason + * Applied fixes to 'rivendell-gentoo' from Emery Hemingway + [Mantis bug #0000010]. +2011-05-02 Fred Gleason + * Applied a patch from Andres Vahter to + validate button color selections in 'lib/rdbutton_dialog.cpp' + [Mantis bug #000000007]. +2011-05-02 Fred Gleason + * Fixed a bug in 'lib/rdedit_audio.cpp' that was using sample rate + values from the database instead of those from the AudioInfo web + service [Mantis bug #00000009]. +2011-05-02 Fred Gleason + * Fixed a bug in 'rdcatchd/rdcatchd.cpp' where an invalid sample + rate value was written into the database when processing an import + [Mantis bug #00000009]. +2011-05-03 Fred Gleason + * Reformulated 'lib/rdwavepainter.cpp' to use pow(3) instead of + pow10(3). +2011-05-03 Fred Gleason + * Refactored 'rdlogmanager/rdlogmanager.cpp' and + 'rdlogmanager/generate_log.cpp' to allow batch processing without an + active X server instance [Mantis bug #0000001]. +2011-05-04 Fred Gleason + * Added a _RLMSerialDataReceived() callback to the RLM + API in 'rlm/rlm.h'. + * Incremented RLM_VERSION to 12 in 'rlm/rlm.h'. +2011-05-05 Fred Gleason + * Added ncrelay support to 'rlm/rlm_xds.c'. +2011-05-05 Fred Gleason + * Added a 'TtySpeed=' directive to 'rlm/rlm_xds.c'. +2011-05-06 Fred Gleason + * Added a 'List SAS Resources' dialog in + 'rdadmin/list_sas_resources.cpp' in 'rdadmin/list_sas_resources.h'. + * Added an 'Edit SAS Resource' dialog in + 'rdadmin/edit_sas_resource.cpp' in 'rdadmin/edit_sas_resource.h'. + * Implemented support for source on/off remote control in the SAS USI + driver in 'ripcd/sasusi.cpp'. +2011-05-11 Fred Gleason + * Added 'scripts/rd_mysql_enable_host.sh'. +2011-05-13 Fred Gleason + * Cleaned up warning messages in 'rdhpi/rdhpiplaystream.cpp', + 'rdhpi/rdhpirecrodstream.cpp' and 'rdhpi,rdhpisoundcard.cpp', . +2011-05-13 Fred Gleason + * Fixed a bug in 'lib/rdtrimaudio.cpp' that caused an Internal Error + when attempting to execute the TrimAudio service [Mantis bug #0000013]. +2011-05-18 Fred Gleason + * Removed deprecated HPI functions and data structures from + 'rdhpi/rdhpisoundcard.cpp', 'rdhpi/rdhpisoundcard.h', + 'rdhpi/rdhpiplaystream.cpp', 'rdhpi/rdhpiplaystream.h', + 'rdhpi/rdhpirecrodstream.cpp', 'rdhpi/rdhpirecrodstream.h', + 'utils/rdhpiinfo/rdhpiinfo.cpp', utils/rdhpiinfo/rdhpiinfo.h' and + 'utils/rdhpiinfo/change_mode.cpp'. + * Fixed a bug in 'utils/rdhpiinfo/rdhpiinfo.cpp' that caused the + HPI version string to be malformatted. +2011-05-18 Fred Gleason + * Added 'RDHPIInformation::hpiVersion()' and + 'RDHPIInformation::setHpiVersion()' methods in + 'rdhpi/rdhpiinformation.cpp' and 'rdhpi/rdhpiinformation.h'. + * Removed 'RDHPIInformation::setHpiMajorVersion()' and + 'RDHPIInformation::setHpiMinorVersion()' methods in + 'rdhpi/rdhpiinformation.cpp' and 'rdhpi/rdhpiinformation.h'. + * Modified caed(8) to write active HPI version into the database + at startup in 'cae/cae.cpp', 'cae/cae_hpi.cpp' and 'cae/cae.h'. +2011-05-18 Fred Gleason + * Modified the priority for logging an ISCI cross-reference import + with a missing/invalid cart number to LOG_DEBUG. +2011-05-18 Fred Gleason + * Fixed a bug SoundPanel bug that caused spacebar presses to be + captured by the panel selector widget. +2011-05-19 Fred Gleason + * Changed 'xdg/rivendell-rdhpiinfo.desktop' to require root + credentials before executing. +2011-05-19 Fred Gleason + * Fixed bugs in 'rdhpi/rdhpiplaystream.cpp', + 'rdhpi/rdhpiplaystream.h', 'rdhpi/rdhpirecordstream.cpp' + and 'rdhpi/rdhpirecordstream.h' that broke the build when building + against versions of the ASI driver prior to 3.010.00. +2011-05-20 Fred Gleason + * Fixed a bug in 'rdairplay/loglinebox.cpp' that could throw a + segfault when changing time modes with no log loaded. +2011-05-20 Fred Gleason + * Added 'scripts/rd_backup_system.sh' and + 'scripts/rd_restore_system.sh'. +2011-05-23 Fred Gleason + * Added '--delete' switch to the rsync(1) call in + 'scripts/rd_backup_system.sh'. +2011-05-23 Fred Gleason + * Implemented 'scripts/rd_restore_system.sh'. +2011-05-23 Fred Gleason + * Fixed a bug in 'rdadmin/list_sas_resources.cpp' that resulted in + the resource entries being failed to be created. +2011-05-25 Fred Gleason + * Added logging to 'ripcd/sas_use.cpp'. +2011-05-26 Fred Gleason + * Elevated the priority of syslog messages reporting ISCI + Cross-reference loading and spot uploading from LOG_DEBUG to + LOG_NOTICE in 'rdrepld/citadelxds.cpp'. +2011-05-26 Fred Gleason + * Added logging for SAS USI commands in 'ripcd/sasusi.cpp'. +2011-05-26 Fred Gleason + * Added a call to 'AM_SILENT_RULES' in 'configure.in'. +2011-05-27 Fred Gleason + * Added an iOS version of RMLSend in 'ios/rmlsend/'. +2011-05-27 Fred Gleason + * Optimized the layout for CentOS/RedHat 5 in + 'utils/rdgpimon/gpi_label.cpp' and 'utils/rdgpimon/gpi_label.cpp'. +2011-05-31 Fred Gleason + * Modified RMLSend for iOS to persistently save settings between + invocations. +2011-06-01 Fred Gleason + * Updated 'NEWS'. + * Updated 'INSTALL'. + * Updated the package version to 2.0.2. +2011-06-02 Fred Gleason + * Fixed a bug in 'web/rdfeed/rdfeed_scripts.cpp' that caused the + incorrect URL to be generated for %ITEM_AUDIO_URL% when the media + archive was located on a separate system from the script. +2011-06-21 Fred Gleason + * Added 'RDRecording::sampleRate()' and 'RDRecording::setSampleRate()' + methods in 'lib/rdrecording.cpp' and 'lib/rdrecording.cpp'. + * Fixed a bug in 'rdcatch/edit_upload.cpp' that caused the selected + sample rate to fail to be saved to the recording record. +2011-06-21 Fred Gleason + * Added code to check for valid database schema in 'lib/rddb.cpp'. + * Added '--skip-db-check' flag to ripcd(8) in 'ripcd/ripcd.cpp'. + * Added '--skip-db-check' flag to rdlogin(1) in 'rdlogin/rdlogin.cpp'. + * Added '--skip-db-check' flag to rdlibrary(1) in + 'rdlibrary/rdlibrary.cpp'. + * Added '--skip-db-check' flag to rdcatch(1) in 'rdcatch/rdcatch.cpp'. + * Added '--skip-db-check' flag to rdcatchd(8) in + 'rdcatchd/rdcatchd.cpp'. + * Added '--skip-db-check' flag to rdlogedit(1) in + 'rdlogedit/rdlogedit.cpp'. + * Added '--skip-db-check' flag to rdlogmanager(1) in + 'rdlogmanager/rdlogmanager.cpp'. + * Added '--skip-db-check' flag to rdpanel(1) in 'rdpanel/rdpanel.cpp'. + * Added '--skip-db-check' flag to rdairplay(1) in + 'rdairplay/rdairplay.cpp'. + * Added '--skip-db-check' flag to rdcastmanager(1) in + 'rdcastmanager/rdcastmanager.cpp'. + * Added '--skip-db-check' flag to rdrepld(8) in 'rdrepld/rdrepld.cpp'. + * Added '--skip-db-check' flag to rddbcheck(8) in + 'rddbcheck/rddbcheck.cpp'. + * Implemented database version skew check for 'rdcastmanager.cgi' + in 'web/rdcastmanager/rdcastmanager.cpp'. + * Implemented database version skew check for 'rdfeed.xml' + in 'web/rdfeed/rdfeed_script.cpp'. + * Implemented database version skew check for 'rdxport.cgi' + in 'web/rdxport/rdxport.cpp'. +2011-06-23 Fred Gleason + * Added a 'TimeOut 1200' entry to 'conf/rd-bin.conf.in'. +2011-06-23 Fred Gleason + * Added '--skip-backup' and '--backup-filename=' switches + to RDAdmin(1). +2011-08-30 Fred Gleason + * Added 'RDAudioConvert::ErrorFormatErro' in 'lib/rdaudioconvert.h' + and 'lib/rdaudioconvert.cpp'. + * Fixed a bug in 'web/rdxport/import.cpp' that caused imports with + format errors to not return an error. +2011-08-30 Fred Gleason + * Fixed a bug in 'lib/rdlog_event.cpp' that caused inserted events to + be corrupted in being added to the middle of a log + [Mantis bug #0000017]. +2011-08-30 Fred Gleason + * Tweaked the layout of the Edit Schedule Code dialog in + 'rdadmin/edit_schedcodes.cpp' to render properly under CentOS/RedHat 5. + * Changed the label of the first item in the 'Scheduler Code' control + in 'rdlibrary/rdlibrary.cpp' to 'ALL'. + * Added a 'Scheduler Code' selector to the Select Cart and Select Cut + dialogs in 'lib/rdcart_dialog.cpp', 'lib/rdcart_dialog.h', + 'lib/rdcut_dialog.cpp' and 'lib/rdcut_dialog.h' [Mantis feature + request #0000022]. +2011-09-02 Fred Gleason + * Reformulated code in 'lib/rdlog_event.cpp' that caused the build to + break under some version of gcc(1). +2011-09-06 Fred Gleason + * Fixed a bug in 'rivendell-suse.in' that would cause a silent + failure when attempting to start the daemons when '/var/run/rivendell' + didn't exist [Mantis bug #0000025]. +2011-09-06 Fred Gleason + * Fixed a bug in 'lib/rdlistview.cpp' that allowed non-contiguous + items to be selected [Mantis bug #0000024]. +2011-09-07 Fred Gleason + * Adjusted control sizes in 'rdcastmanager/edit_post.cpp' and + 'rdcastmanager/pick_report_dates.cpp' to render + correctly on RedHat/CentOS 5. +2011-09-09 Fred Gleason + * Modified 'web/rdfeed/rdfeed_script.cpp' to use GMT for processing + date/times [Mantis bug #0000020]. + * Modified 'lib/rdfeed.cpp' to process pocast datetimes in GMT + [Mantis bug #0000020]. + * Modified 'web/rdcastmanager/rdcastmanager.cpp' to process pocast + datetimes in GMT [Mantis bug #0000020]. + * Modified '/rdcastmanager/list_casts.cpp' to process pocast + datetimes in GMT [Mantis bug #0000020]. + * Modified '/rdcastmanager/edit_cast.cpp' to process pocast + datetimes in GMT [Mantis bug #0000020]. + * Fixed a bug in 'web/rdcastmanager/rdcastmanager.cpp' that caused + the last build date value in an RSS feed to fail to be updated + when making a change to a child cast. +2011-09-16 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that caused schema updates + to be incorrectly applied to _SRT tables for services whose names + contained reserved SQL characters. +2011-10-17 Fred Gleason + * Changed the 'REPLICATORS.NORMALIZATION_LEVEL' field data type to + 'int'. + * Added a 'REPL_CART_STATE.REPOST' and + 'REPL_CART_STATE.POSTED_FILENAME' field to the database. + * Incremented the database version to 203. + * Added a 'List Replicator Carts' dialog in + 'rdadmin/list_replicator_carts.cpp' and + 'rdadmin/list_replicator_carts.h'. + * Added an 'RDDelete' class in 'lib/rddelete.cpp' and + 'lib/rddelete.h'. + * Added logic in 'rdrepld/citadelxds.cpp' to automatically purge + remote files. + * Fixed a bug in 'rdrepld/citadelxds.cpp' that failed to process + carts properly when multiple mappings from a single cart were + present in the ISCI cross reference data. +2011-10-17 Fred Gleason + * Fixed a bug in 'lib/rdconf.cpp' that broke the build under + Windows. + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' that broke the build + under Windows. +2011-10-17 Fred Gleason + * Reformulated CURL error processing in 'lib/rdaudioexport.cpp', + 'lib/rdaudioimport.cpp', 'lib/rdaudioinfo.cpp', 'lib/rdcopyaudio.cpp', + 'lib/rddelete.cpp', 'lib/rddownload.cpp', 'lib/rdpeaksexport.cpp', + 'lib/rdtrimaudio.cpp' and 'lib/rdupload.cpp' so as to build properly + against libcurl-7.19.7. +2011-10-27 Fred Gleason + * Fixed a bug in 'lib/rd_cart_search_text.cpp' and + 'rdlibrary/rdlibrary.cpp' that caused cart searches to be broken + when searching for a specific group with no scheduler code + selected. +2011-10-27 Fred Gleason + * Added an import setting for 'The Traffic Light' in + 'rdadmin/createdb.cpp'. + * Incremented the database version to 204. +2011-10-31 Fred Gleason + * Added 'STATIONS.START_JACK' and 'STATIONS.JACK_SERVER_NAME' fields + to the database. + * Incremented the database version to 205. + * Added 'RDStation::startJack()', 'RDStation::setStartJack()', + 'RDStation::jackServerName()' and 'RDStation::setJackServerName()' + methods in 'lib/rdstation.cpp' and 'lib/rdstation.h'. + * Added an 'Edit Jack' dialog in 'rdadmin/edit_jack.cpp' and + 'rdadmin/edit_jack.h'. +2011-10-31 Fred Gleason + * Documented 'Connect JACK Ports' and 'Disconnect JACK Ports' commands + in 'docs/cae.sxw'. + * Implemented 'Connect JACK Ports' and 'Disconnect JACK Ports' commands + in 'cae/cae_jack.cpp' and 'cae/cae.h'. + * Added 'RDCae::connectJackPorts()' and 'RDCae::disconnectJackPorts()' + methods in 'lib/rdcae.cpp' and 'lib/rdcae.h'. + * Added 'Connect Jack Ports' ['JC'] and 'Disconnect Jack Ports' ['JD'] + RMLs in 'lib/rdmacro.cpp' and 'lib/rdmacro.h'. + * Implemented 'Connect Jack Ports' ['JC'] and 'Disconnect Jack Ports' + ['JD'] RMLs in 'ripcd/local_macros.cpp'. +2011-12-02 Fred Gleason + * Removed the '[JackSession]' section from 'conf/rd.conf-sample', + 'conf/rd.conf-slax' and 'conf/rd-sample.ini'. + * Updated the NEWS file. + * Incremented the package version to 2.1.0. +2011-12-03 Fred Gleason + * Fixed a regression in 'rdlogmanager/edit_event.cpp' that broke + cart display in the Library window of the Edit Event dialog. +2011-12-03 Fred Gleason + * Incremented the package version to 2.1.1. +2011-12-21 Fred Gleason + * Added a plug-in for Shoutcast 1.x in 'rlm/rlm_shoutcast1.c'. +2011-12-21 Fred Gleason + * Removed debugging printfs from 'rlm/rlm_icecast2.c'. +2011-12-22 Fred Gleason + * Updated notes on the SAS USI switcher driver in + 'docs/SWITCHERS.txt'. +2011-12-22 Fred Gleason + * Fixed a bug in 'rlm/rlm_icecast2.c' that caused configuration of + second and subsequent plug-in instances to be ignored. + * Modified 'rlm/rlm_icecast2.c' to log full mountpoint path upon + plug-in initialization. + * Modified 'rlm/rlm_icecast2.c' to properly URL escape space + characters. +2011-12-22 Fred Gleason + * Fixed a bug in 'rlm/rlm_shoutcast1.c' that caused configuration of + second and subsequent plug-in instances to be ignored. +2011-12-22 Fred Gleason + * Changed the default Rivendell user in RDDbCheck from 'admin' to + 'user'. + * Fixed a bug in 'utils/rddbadmin/rddbadmin.cpp' that threw a + database error when purging an orphaned voicetrack when the parent + log had been deleted. +2011-12-22 Fred Gleason + * Fixed a bug in 'lib/rdlog.cpp' that caused the + 'RDLog::updateTracks()' method to set incorrect counts of completed + tracks [Mantis bug #0000035]. + * Fixed a bug in 'lib/rdlog.cpp' that caused the + 'RDLog::removeTracks()' method to set fail to delete tracks + [Mantis bug #0000035]. +2011-12-23 Fred Gleason + * Added 'RDAudioConvert::ErroNoSpace' in 'lib/rdaudioconvert.h'. + * Implemented checks for an out of storage space condition when + writing files in 'lib/rdaudioconvert.cpp' [Mantis bug #0000034]. +2011-12-23 Fred Gleason + * Added an 'RDWebError' class in 'lib/rdweberror.cpp' and + 'lib/rdweberror.h'. + * Added an 'RDXMLCgiError()' function in 'lib/rdweb.cpp' and + 'lib/rdweb.h'. + * Modfied the RDXport service in 'web/rdxport/' to use RDXMLCgiError() + for error reporting. + * Modified the RDAudioImport class in 'lib/rdaudioimport.cpp' and + 'lib/rdaudioimport.h' to process and report converter errors. + * Modified the RDAudioExport class in 'lib/rdaudioexport.cpp' and + 'lib/rdaudioexport.h' to process and report converter errors. +2011-12-23 Fred Gleason + * Renamed the 'RDWebError' class in 'lib/rdweberror.cpp' and + 'lib/rdweberror.h' to 'RDWebResult' in 'lib/rdwebresult.cpp' and + 'lib/rdwebresult.h'. + * Renamed the 'RDXMLCgiError()' function to 'RDXMLResult()' in + 'lib/rdweb.cpp' and 'lib/rdweb.h'. + * Added CURL write callbacks in 'lib/rddelete.cpp' and + 'lib/rdcart.cpp'. + * Updated 'docs/web_api.odt' to describe the web service result + code format. +2011-12-28 Fred Gleason + * Fixed a buffer overflow bug in 'ripcd/sasusi.cpp'. +2011-12-28 Fred Gleason + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that caused an + already existing cart to be deleted upon an importation error + when using the '--to-cart' switch [Mantis bug #0000037]. +2011-12-28 Fred Gleason + * Fixed a bug in 'lib/rdweb.h' that broke the build under Windows. +2011-12-28 Fred Gleason + * Fixed a bug in 'rlm/Makefile.am' that broke the 'make rpm' target. +2011-12-30 Fred Gleason + * Applied updated Spanish [es] translation from Luigino Bracci + . +2011-12-30 Fred Gleason + * Updated 'NEWS' + * Incremented the project version to 2.1.2. +2012-01-12 Fred Gleason + * Fixed bugs in 'lib/rdcart_search_text.cpp', 'lib/rdcart_dialog.cpp'. + 'lib/rdcut_dialog.cpp' and 'rdlibrary/rdlibrary.cpp' that caused the + cart list to be empty when running with a non-english langauge + [Mantis bug #0000040]. +2012-01-12 Fred Gleason + * Replaced 'QT_NR_NOOP()' with 'QObject::tr()' in 'lib/rdcart.cpp', + 'lib/rdcopyaudio.cpp', 'lib/rdcut_path.cpp', 'lib/rdlog_line.cpp', + 'lib/rdpeaksexport.cpp', 'lib/rdreport.cpp', 'rdadmin/opendb.cpp', + and 'rdadmin/rdadmin.cpp'. [Mantis bug #0000040]. + * Added 'rdadmin/edit_hotkeys.cpp', 'rdadmin/edit_hotkeys.h', + 'rdadmin/edit_replicator.cpp', 'rdadmin/edit_replicator.h', + 'rdadmin/edit_user_perms.cpp' and 'rdadmin/edit_user_perms.h' + to 'rdadmin/rdadmin.pro'. +2012-01-12 Fred Gleason + * Added 'rdairplay/colors.h' to 'rdairplay/rdairplay.pro'. +2012-01-16 Fred Gleason + * Added 'add_feed.cpp', 'add_feed.h', 'edit_feed.cpp', 'edit_feed.h', + 'list_feeds.cpp', 'list_feeds.h', 'list_aux_fields.cpp', + 'list_aux_fields.h', 'edit_aux_fields.cpp', 'edit_aux_fields.h', + 'add_aux_field.cpp' and 'add_aux_fields.h' to 'rdadmin/rdadmin.pro' + [Mantis bug #0000043]. + * Added 'edit_notes.cpp', 'edit_notes'h', 'edit_schedulercodes.cpp', + 'edit_schedulercodes.h', 'list_reports.cpp' and 'list_reports.h' + to 'rdlibrary/rdlibrary.pro' [Mantis bug #0000043]. + * Added 'edit_schedrules.cpp' and 'edit_schedrules.h' to + 'rdlogmanager/rdlogmanager.pro' [Mantis bug #0000043]. + * Fixed a bug in 'rdlibrary/edit_notes.cpp' that made it impossible + to translate the 'Edit Notes' dialog caption [Mantis bug #0000043]. + * Fixed a bug in 'rdadmin/edit_feeds.cpp' that made it + impossible to translate the 'CHANNEL VALUES' phrase + [Mantis bug #0000043]. +2012-01-17 Fred Gleason + * Added rules in 'xdg/Makefile.am' and 'icons/Makefile.am' to install + desktop elements. +2012-01-26 Fred Gleason + * Fixed a typo in 'rdadmin/rdadin.pro' that caused the + 'Edit Aux Field' dialog to fail to be included in translations. +2012-02-13 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that caused incorrect + hard start parameters to be applied to events from the music + scheduler. +2012-02-13 Fred Gleason + * Added missing entries to 'rdadmin/rdadmin.pro', + 'rdlogedit/rdlogedit.pro', and 'rdcastmanager/rdcastmanager.pro' + [Mantis bug #0000046]. + * Fixed missing tr() call for strings in 'rdadmin/add_matrix.cpp', + '/rdadmin/add_hostvar.cpp', 'rdadmin/edit_audios.cpp', + 'rdadmin/edit_encoder.cpp', 'rdadmin/edit_decks.cpp', + 'rdadmin/createdb.cpp', 'rdadmin/edit_now_next.cpp', + 'rdadmin/list_encoders.cpp', 'rdadmin/help_audios.cpp', + 'rdlogmanager/edit_schedcoderules.cpp', + 'rdlogmanager/edit_schedrules.cpp', 'rdcatch/edit_recording.cpp', + and 'rdairplay/rdairplay.cpp' [Mantis bug #0000046]. +2012-02-13 Fred Gleason + * Fixed a bug in 'rdlogedit/voice_tracker.cpp' that caused a + segfault when selecting the end-of-log marker on an empty log + [Mantis bug #0000047]. +2012-02-13 Fred Gleason + * Removed the 'Schedule Cuts' control from the Edit Cart dialog + in 'rdlibrary/edit_cart.cpp' and 'rdlibrary/edit_cart.h' + [Mantis bug #0000045]. +2012-02-13 Fred Gleason + * Fixed bugs in rdxport(8) that caused temporary files to be + left behind after processing. +2012-02-14 Fred Gleason + * Fixed a bug in 'rdcatchd/batch.cpp' that failed to delete + temp files after upload events. + * Fixed a bug in 'lib/rdfeed.cpp' that failed to delete temp + files after uploading a podcast. +2012-02-16 Fred Gleason + * Applied a fix from Chris Smowton in + 'lib/rdaudioconvert.cpp' for a bug that caused audio distortion + when processing audio containing full-scale samples with + normalization disabled. +2012-02-20 Fred Gleason + * Fixed a bug in 'rdlogmanager/edit_event.cpp' that broke display + of the library in the 'Edit Event' dialog. +2012-02-20 Fred Gleason + * Updaed 'NEWS'. + * Incremented the package version to 2.1.3. +2012-03-02 Fred Gleason + * Fixed a regression in 'rdrepld/citadelxds.cpp' that caused + incorrect normalization levels to be applied when exporting + audio. +2012-03-13 Fred Gleason + * Moved to 'v2_branch' in CVS. +2012-03-30 Fred Gleason + * Fixed a bug in 'ripcd/bt_src16.cpp' that caused the TTY port to + fail to be tagged as in use. +2012-04-02 Fred Gleason + * Backported the 'rlm_spottrap' RLM from CVS-Head. +2012-04-09 Fred Gleason + * Fixed a bug in 'rdlibrary/list_reports.cpp' that broke report + generation when no scheduler code was selected. +2012-04-23 Fred Gleason + * Fixed a bug in 'cae/cae_jack.cpp' that broke the build when + compiled with no MPEG decoding support. + * Fixed a bug in 'cae/cae_alsa.cpp' that broke the build when + compiled with no MPEG decoding support. +2012-04-23 Fred Gleason + * Fixed a bug in 'rdadmin/rdadmin.pro' that made + 'rdadmin/add_encoder.cpp' untranslatable [Mantis bug #0000050]. +2012-04-23 Fred Gleason + * Applied updated Spanish [es] translation from Luigino Bracci + . +2012-04-23 Fred Gleason + * Fixed a bug in 'rdlogmanager/add_clock.cpp', + rdlogmanager/add_clock.h', 'rdlogmanager/add_event.cpp', + 'rdlogmanager/add_event.h', 'rdlogmanager/edit_note.cpp', + 'rdlogmanager/edit_note.h', 'rdlogmanager/edit_perms.cpp', + 'rdlogmanager/edit_perms.h' 'rdlogmanager/editschedcoderules.cpp', + 'rdlogmanager/editschedcoderules.h', 'rdlogmanager/editschedrules.cpp', + 'rdlogmanager/editschedrules.h', 'rdlogmanager/edit_track.cpp', + 'rdlogmanager/edit_track.h', 'rdlogmanager/list_clocks.cpp', + 'rdlogmanager/list_clocks.h', 'rdlogmanager/list_events.cpp', + 'rdlogmanager/list_events.h' that caused cleanup processing to + fail to be performed when the dialog was closed by the window + manager [Mantis bug #0000051]. +2012-04-23 Fred Gleason + * Fixed a bug in 'rdairplay/list_log.cpp' that caused non-cart + log events to be marked red after editing their transition type. +2012-04-23 Fred Gleason + * Fixed a bug in 'lib/rdcut.cpp' that caused pasted carts to fail + to have their play and origin values reset. +2012-05-04 Fred Gleason + * Applied a patch from Eliot Blennerhassett + to support building against + hpklinux-4.10.x. +2012-05-07 Fred Gleason + * Added 'docs/datetime_wildcards.txt'. + * Implemented the '^' and '$' metacharacters in + 'lib/rddatedecode.cpp'. + * Implemented 'e', 'E' and 'p' format characters in + 'lib/rddatedecode.cpp'. +2012-05-07 Fred Gleason + * Added sanity checks to verify marker placement in + 'lib/rdedit_audio.cpp'. +2012-05-10 Fred Gleason + * Fixed a regression in 'rdairplay/list_log.cpp' that broke + background color status indications. +2012-05-10 Fred Gleason + * Modified 'rdcatchd/batch.cpp' to assume anonymous FTP when + processing FTP xloads with a blank username. +2012-05-10 Fred Gleason + * Fixed a regression in 'rdairplay/list_log.cpp' that broke + background color status indications of played meta events. +2012-05-10 Fred Gleason + * Fixed a bug in 'lib/rddownload.cpp' that broke downloads + from URLs with uuencoded characters. + * Fixed a bug in 'lib/rdupload.cpp' that broke downloads + from URLs with uuencoded characters. +2012-05-10 Fred Gleason + * Fixed a bug in 'lib/rddatedecode.cpp' that broke the build + under Windows. +2012-05-11 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.1.4. +2012-05-11 Fred Gleason + * Added code in 'lib/rddb.cpp' to log SQL errors. +2012-06-27 Fred Gleason + * Fixed a initialization bug in 'rdcae/rdcae.cpp' found by + Sascha Ludwig . +2012-07-06 Fred Gleason + * Added an 'rlm_filewrite' RLM in 'rlm/rlm_filewrite.c'. +2012-07-15 Fred Gleason + * Added nexgen_filter(1) importer in 'importers/nexgen_filter.cpp' + and 'importers/nexgen_filter.h'. +2012-07-16 Fred Gleason + * Added 'RDProcessActive()' and 'RDModulesActive()' functions + in 'lib/rdconf.cpp' and 'lib/rdconf.h'. + * Added RDSelect(8) in 'rdselect/'. +2012-07-16 Fred Gleason + * Fixed a bug in 'rivendell.spec.in' that broke the + 'make rpm' target. +2012-07-16 Fred Gleason + * Added 'RDWaveData::hookStartPos()', 'RDWaveData::setHookStartPos()', + 'RDWaveData::hookEndPos()', 'RDWaveData::setHookEndPos()', + 'RDWaveData::fadeUpPos()', 'RDWaveData::setFadeUpPos()', + 'RDWaveData::fadeDownPos()' and 'RDWaveData::setFadeDownPos()' + methods in 'lib/rdwavedata.cpp' and 'lib/rdwavedata.h'. + * Added logic in 'importers/nexgen_filter.cpp' to process + Hook, Start, End and Segue markers properly. +2012-07-17 Fred Gleason + * Added logic to attempt import of audio files with opposite case + in extension type in 'importers/nexgen_filter.cpp' and + 'importers/nexgen_filter.h'. +2012-07-17 Fred Gleason + * Fixed a bug in 'web/rdxport/deleteaudio.cpp' that broke automatic + cut purging. +2012-07-20 Fred Gleason + * Added an 'RDXmlUnescape()' function 'lib/rdweb.cpp' and + 'lib/rdweb.h'. + * Fixed a bug in 'importers/nexgen_filter.cpp' that failed to + process escaped XML strings properly. +2012-07-23 Fred Gleason + * Added 'RDSoundPanel::setText()' and 'RDSoundPanel::setColor()' + methods in 'lib/rdsound_panel.cpp' and 'lib/rdsound_panel.h'. + * Added a 'Label Panel' ['PC'] RML in 'lib/rdmacro.cpp' and + 'lib/rdmacro.h'. +2012-07-24 Fred Gleason + * Fixed a bug in 'lib/rdmixer.cpp' that caused incorrect port + trim level values to be set for HPI audio devices. +2012-07-27 Fred Gleason + * Updated 'NEWS' + * Incremented the package version to 2.1.5. +2012-07-30 Fred Gleason + * Applied a patch from Alban Peignier that + fixed a bug in 'acinclude.m4' that broke the build under + Ubuntu. +2012-08-01 Fred Gleason + * Added a 'qt-devel' dependency in 'rivendell.spec.in'. +2012-08-01 Fred Gleason + * Modified rdcollect(1) in 'utils/rdcollect/rdcollect.cpp' and + 'utils/rdcollect/rdcollect.h' so as to allow the '--source-file=' + option to be used multiple times in a single invocation. +2012-08-02 Fred Gleason + * Fixed a bug in 'rdlibrary/record_cut.cpp' that caused the + overwriting audio warning to fail to be displayed when entering + record ready mode. + * Removed the 'RDCut::audioExists()' method from 'lib/rdcut.cpp' + and 'lib/rdcut.h'. +2012-08-02 Fred Gleason + * Implemented a 'Set Clock Source' ['CS'] command in + 'cae/cae.cpp', 'cae/hpi_cae.cpp' and 'cae/cae.h'. + * Added an 'RDCae::setClockSource()' method in 'lib/rdcae.cpp' + and 'lib/rdcae.h'. +2012-08-05 Fred Gleason + * Added a switcher driver for the Harlond Virtual Mixer in + 'ripcd/harlond.cpp' and 'ripcd/harlond.h'. +2012-08-07 Fred Gleason + * Implemented input mode support for HPI devices in + 'rdhpi/rdsoundcard.cpp'. +2012-08-08 Fred Gleason + * Added '$ar_distro_major' and '$ar_distro_minor' variables to + the AR_GET_DISTRO() macro in 'acinclude.m4' and 'get_distro.sh'. +2012-08-10 Fred Gleason + * Fixed a bug in 'rdairplay/list_logs.cpp' that threw a segfault + when starting RDAirPlay(1) in User Security mode. +2012-08-13 Fred Gleason + * Changed the text of the 'NO SYNC!' alarm to 'AES ALARM' in + 'rdlibrary/record_cut.cpp'. +2012-08-13 Fred Gleason + * Added a 'REPORTS.FILTER_GROUPS' field to the database. + * Added a 'REPORT_GROUPS' table to the database. + * Incremented the database version to 206. + * Added 'Filter by Groups' and 'Allowed Groups' control to + the Edit Report dialog in 'rdadmin/edit_report.cpp' and + 'rdadmin/edit_report.h'. + * Implemented group filtering in 'lib/rdreport.cpp'. +2012-08-13 Fred Gleason + * Added 'rdlogmanager/commandline_ops.cpp'. + * Added '-e' and '-r' switches to RDLogManager(1) in + 'rdlogmanager/rdlogmanager.cpp' and 'rdlogmanager/commandline_ops.cpp'. +2012-08-13 Fred Gleason + * Implemented a 'Music Summary' report in 'lib/export_musicsummary.cpp'. +2012-08-23 Fred Gleason + * Added an RLM for the PadPoint data processor in + 'rlm/rlm_padpoint.c'. +2012-08-24 Fred Gleason + * Added a 'WideOrbit Traffic' record to the 'IMPORT_TEMPLATES' + table. + * Incremented the database version to 207. + * Added 'ExportFilter::WideOrbit' to 'lib/rdreport.cpp' and + 'lib/rdreport.h. +2012-08-28 Fred Gleason + * Applied a patch from Wayne Merricks + that fixed startup focus problem in 'lib/rdsound_panel.cpp'. +2012-08-28 Fred Gleason + * Added an include for 'stdint.h' in 'utils/rdhpiinfo/rdhpiinfo.cpp'. +2012-08-30 Fred Gleason + * Applied a patch by Alban Peignier to allow + building with gcc 4.7. +2012-08-31 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.2.0. +2012-09-06 Fred Gleason + * Fixed a bug in 'lib/rdaudioconvert.cpp' and 'lib/rdaudioconvert.h' + that caused null bytes to be inserted at the beginning of MPEG + Layer 3 exports. +2012-09-06 Fred Gleason + * Fixed a bug in 'web/rdxport/export.cpp' that caused cruft to be + appended to the end of exported audio files. +2012-09-12 Fred Gleason + * Added 'RDWaveData::isci()' and 'RDWaveData::setIsci()' methods + in 'lib/rdwavedata.cpp' and 'lib/rdwavedata.h'. + * Added support for importing ISCI data in + 'importers/nexgen_filter.cpp'. +2012-10-08 Fred Gleason + * Added code in 'lib/rdcart_search_text.cpp' to filter by cut + attributes. +2012-10-09 Fred Gleason + * Fixed a bug in 'rdairplay/loglinebox.cpp' that threw a DB + positioning error when refreshing a log. +2012-10-11 Fred Gleason + * Added 'scripts/sage_endec_rwt.sh'. +2012-10-12 Fred Gleason + * Added 'docs/SAGE_ENDEC.txt'. +2012-10-12 Fred Gleason + * Added rdmonitor(1) in 'rdmonitor/'. + * Added rdcheckcuts(1) in 'utils/rdcheckcuts/'. +2012-10-15 Fred Gleason + * Fixed a bug in 'importers/nexgen.filter.cpp' that broke + audio importation. +2012-10-19 Fred Gleason + * Fixed a regression in 'rdlogmanager/commandline_ops.cpp' that + broke command-line operations when operating with an X11 + connection. +2012-10-19 Fred Gleason + * Added 'lib/rdstatus.cpp' and 'lib/rdstatus.h'. + * Modified RDSelect(8) to indicate current state by means of + an icon. +2012-10-19 Fred Gleason + * Set RDSelect to be installed SETUID 0. +2012-10-19 Fred Gleason + * Fixed a bug in 'rdmonitor/rdmonitor.cpp' that caused the applet + intermittently to start minimized. +2012-10-19 Fred Gleason + * Added 'sage_endec_rwt.sh' to the 'EXTRA_DIST' list in + 'scripts/Makefile.am'. +2012-10-22 Fred Gleason + * Disabled display of RDSelect when only a single configuration + is present in '/etc/rivendell.d/' in 'rdmonitor/rdmonitor.cpp'. +2012-10-22 Fred Gleason + * Added a right-click menu to RDMonitor in 'rdmonitor/rdmonitor.cpp' + and 'rdmonitor/rdmonitor.h'. +2012-10-22 Fred Gleason + * Modified 'rdselect/rdselect.cpp' to position itself properly + in accordance with the position setting of RDMonitor(1). +2012-10-22 Fred Gleason + * Modified the post-installation script in 'rivendell.spec.in' to + convert old rd.conf(5) layout to be compatible with rdmonitor(1). + * Added 'docs/RDMONITOR.txt'. +2012-10-22 Fred Gleason + * Fixed a bug in 'utils/rdcheckcuts/rdcheckcuts.cpp' that broke + the build under CentOS 6. +2012-10-22 Fred Gleason + * Fixed a bug in 'rivendell.spec.in' that broke the 'make rpm' + target. +2012-10-22 Fred Gleason + * Added an 'RDDbValid()' function in 'lib/rdstatus.cpp' and + 'lib/rdstatus.h'. + * Added checks for database schema version to rdmonitor(1) + and rdselect(1). +2012-10-23 Fred Gleason + * Fixed a bug in 'rdmonitor/rdmonitor.cpp' that prevented display + of the status bubble when positioned away from the upper left + corner. +2012-10-23 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.2.1. +2012-11-13 Fred Gleason + * Added a 'JackCommandLine' directive to the [Hacks] section + of rd.conf(5) in 'lib/rdconfig.cpp' and 'lib/rdconfig.h'. +2012-11-13 Fred Gleason + * Added an 'RDAIRPLAY.HOUR_SELECTOR_ENABLED' field to the + database. + * Incremented the database version to 208. + * Added 'RDAirPlayConf::hourSelectorEnabled()' + and 'RDAirPlayConf::setHourSelectorEnabled()' in + 'lib/rdairplay_conf.cpp' and 'lib/rdairplay_conf.h'. + * Added a 'Show Hour Selector' control to the RDAirPlay Config + dialog in 'rdadmin/edit_rdairplay.cpp' and + 'rdadmin/edit_rdairplay.h'. + * Added an HourSelector widget in 'rdairplay/hourselector.cpp' + and 'rdairplay/hourselector.h'. +2012-11-13 Fred Gleason + * Added a 'STATIONS.JACK_COMMAND_LINE' field to the database. + * Added a 'JACK_CLIENTS' table to the database. + * Incremented the database version to 209. + * Added 'RDStation::jackCommandLine()' and + 'RDStation::setJackCommandLine()' methods in 'lib/rdstation.cpp' + and 'lib/rdstation.h'. + * Removed 'JackCommandLine' directive to the [Hacks] section + of rd.conf(5) in 'lib/rdconfig.cpp' and 'lib/rdconfig.h'. +2012-11-13 Fred Gleason + * Stubbed out an 'Edit JACK Client' dialog in + 'rdadmin/edit_jack_client.cpp' and 'rdadmin/edit_jack_client.h'. +2012-11-14 Fred Gleason + * Commented out JACK Client dialog code in 'rdadmin/edit_jack.cpp' + and 'rdadmin/edit_jack.h'. +2012-11-15 Fred Gleason + * Completed JACK Client dialog code in 'rdadmin/edit_jack.cpp' + and 'rdadmin/edit_jack.h'. + * Implemented JACK Client startup in 'cae/cae_jack.cpp' and + 'cae/cae.h'. +2012-11-15 Fred Gleason + * Added 'Load Slot' ['DL'], 'Play Slot' ['DP'], 'Stop Slot' ['DS'] + and 'Execute Breakaway' ['DX'] RMLs in 'docs/rml.sxw', + 'lib/rdmacro.cpp' and 'lib/rdmacro.h'. + * Added RDCartSlots module in 'rdcartslots.cpp'. +2012-11-15 Fred Gleason + * Added a 'CARTSLOTS' table to the database. + * Incremented the database version to 210. + * Added an 'Edit CartSlots' dialog in 'rdadmin/edit_cartslots.cpp' + and 'rdadmin/edit_cartslots.h'. +2012-11-19 Fred Gleason + * Fixed various formatting bugs in 'lib/rdcartslot.cpp'. +2012-11-19 Fred Gleason + * Added RDCartSlots to 'xdg/rivendell-rivendell.menu'. +2012-11-19 Fred Gleason + * Implemented timescaling support for the JACK audio driver in + 'cae/cae_jack.cpp'. +2012-11-19 Fred Gleason + * Fixed a bug in 'lib/rdcartslot.cpp' that broke breakaways when + using a device with no timescaling support. +2012-11-26 Fred Gleason + * Added a 'SYSTEM.TEMP_CART_GROUP' field to the database. + * Incremented the database version to 211. + * Added 'RDSystem::tempCartGroup()' and 'RDSystem::setTempCartGroup()' + methods in 'lib/rdsystem.cpp' and 'lib/rdsystem.h'. + * Added a 'Temporary Cart Group' control to the Edit Settings + dialog in 'rdadmin/edit_settings.cpp' and + 'rdadmin/edit_settings.h'. + * Added a Busy Dialog in 'lib/rdbusydialog.cpp' and + 'lib/rdbusydialog.h'. + * Added a 'Load from File' button to the Cart Picker dialog + in 'lib/rdcart_dialog.cpp' and 'lib/rdcart_dialog.h'. +2012-11-27 Fred Gleason + * Added 'RDSlotOptions::hookMode()' and 'RDSlotOptions::setHookMode()' + methods in 'lib/rdslotoptions.cpp' and 'lib/rdslotoptions.h'. + * Added a 'Play Mode' control to the RDCartSlots Options dialog + in 'lib/rdslotoptions.cpp' and 'lib/rdslotoptions.h'. + * Added 'RDLogLine::hookMode()' and 'RDLogLine::setHookMode()' + methods in 'lib/rdlog_line.cpp' and 'lib/rdlog_line.h'. + * Added 'CARTSLOTS.HOOK_MODE' and 'CARTSLOTS.DEFAULT_HOOK_MODE' + fields to the database. + * Incremented the database version to 212. +2012-11-28 Fred Gleason + * Adjusted field layout in 'lib/rdslotbox.cpp'. +2012-11-28 Fred Gleason + * Added 'STATIONS.CUE_CARD', 'STATIONS.CUE_PORT', + 'STATIONS.CARTSLOT_COLUMNS' and 'STATIONS.CARTSLOT_ROWS' + fields to the database. + * Incremented the database version to 213. + * Added logic in 'rdadmin/edit_cartslots.cpp' and + 'rdadmin/edit_cartslots.h' to ensure sane audio channel assignments. + * Added 'RDStation::cueCard()', 'RDStation::setCueCard()', + 'RDStation::cuePort()' and 'RDStation::setCuePort()' methods + in 'lib/rdstation.cpp' and 'lib/rdstation.h'. + * Added a 'Cue Output' control to the 'Edit Station' dialog + in 'rdadmin/edit_station.cpp' and 'rdadmin/edit_station.h'. + * Removed the 'Audition Deck' controls from the 'Edit Decks' + dialog in 'rdadmin/edit_decks.cpp' and 'rdadmin/edit_decks.h'. + * Modified RDCatch to use cue output assignments from the + 'Edit Station' dialog in 'rdcatch/rdcatch.cpp'. + * Modified RDCartSlots to use cue output assignments from the + 'Edit Station' dialog in 'rdcartslots/rdcartslots.cpp'. +2012-11-28 Fred Gleason + * Added 'RDStation::cartSlotColumns()', + 'RDStation::setCartSlotColumns()', 'RDStation::cartSlotRows()' + and 'RDStation::setCartSLotRows()' in 'lib/rdstation.cpp' and + 'lib/rdstation.h'. + * Added 'Slot Columns' and 'Slot Rows' control to the + 'Edit CartSlot' dialog in 'rdadmin/edit_cartslots.cpp' and + 'rdadmin/edit_cartslots.h'. +2012-11-28 Fred Gleason + * Sorted Makefile entries alphabetically. +2012-11-29 Fred Gleason + * Removed debugging printfs from 'rlm/rlm_shoutcast1.c'. +2012-11-30 Fred Gleason + * Documented an 'Output Stream Meter Level' ['MO'] status command + in 'docs/cae.sxw'. + * Implemented an 'Output Stream Meter Level' ['MO'] status command + in 'cae/cae.cpp', 'cae/cae.h', 'cae/cae_hpi.cpp', + 'cae/cae_jack.cpp', 'cae/cae_alsa.cpp', 'lib/rdcae.cpp' + and 'lib/rdcae.h'. + * Modified 'lib/rdcartslot.cpp' to use stream output metering. +2012-12-03 Fred Gleason + * Fixed bugs in 'lib/rdcart_dialog.cpp' that broke the build + under Windows. + * Fixed a bug in 'rdlogedit/rdlogedit.cpp' that broke the build + under Windows. + * Added 'rdbusybar.cpp' and 'rdbusybar.h' to 'lib/lib.pro'. +2012-12-03 Fred Gleason + * Cleaned up 'make maintainerclean' rules. +2012-12-03 Fred Gleason + * Fixed a regression in 'lib/rdcart_dialog.cpp' that broke the build. +2012-12-03 Fred Gleason + * Fixed a regression in 'Makefile.am' that broke the build. +2012-12-04 Fred Gleason + * Fixed a regression in 'lib/rdplay_deck.cpp' that broke timescale + playout. +2012-12-10 Fred Gleason + * Added an 'Type::Acu1p' entry to the 'RDMatrix::Type' enum in + 'lib/rdmatrix.cpp' and 'lib/rdmatrix.h'. + * Added an 'RDMatrix::typeString()' static method in + 'lib/rdmatrix.cpp' and 'lib/rdmatrix.h'. + * Refactored RDAdmin to place all device-specific configuration + policy in the RDMatrix class. +2012-12-10 Fred Gleason + * Added a switcher driver for the Sine ACU-1 with Prophet firmware + in 'ripcd/acu1p.cpp' and 'ripcd/acu1p.h'. +2012-12-12 Fred Gleason + * Applied a bugfix provided by Max Goldstein to + correct handling of button labels containing spaces in the 'PC' + RML in 'rdairplay/local_macros.cpp'. +2012-12-12 Fred Gleason + * Implemented GPIs for the Sine ACU-1 driver in 'ripcd/acu1p.cpp'. +2012-12-13 Fred Gleason + * Cleaned up warnings in 'lib/rdaudioconvert.cpp', + lib/rdaudioinfo.cpp', 'lib/rdceripper.cpp', 'lib/rdconfig.cpp', + 'lib/rdevent_line.cpp', 'lib/rdevent_player.cpp', + 'lib/rdexport_settings_dialog.cpp', 'lib/rdfeed.cpp', + 'lib/rdflacdecode.cpp', 'lib/rdformpost.cpp', 'lib/rdpam.cpp', + 'lib/rdsettings.cpp', 'lib/rdstringlist.cpp', and 'lib/rdweb.cpp' +2012-12-18 Fred Gleason + * Fixed a bug in 'rdadmin/edit_cartslots.cpp' that made it + impossible to configure any slots beyond the first eight. +2012-12-18 Fred Gleason + * Tweaked layout in 'rdairplay/list_log.cpp' to display properly + under gdm(1). +2012-12-21 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.3.0. +2013-01-01 Fred Gleason + * Added Czech [CS] translation from Pavel Fric . +2013-01-04 Fred Gleason + * Added an RDDgImport(1) utility in 'utils/rddgimport/'. +2013-01-07 Fred Gleason + * Added a 'SERVICES.AUTOSPOT_GROUP' field to the database. + * Incremented the database version to 214. + * Added 'RDSvc::autospotGroup()' and 'RDSvc::setAutospotGroup()' + methods in 'lib/rdsvc.cpp' and 'lib/rdsvc.h'. + * Added an 'AutoSpot Group' control to the Edit Service + dialog in 'rdadmin/edit_svc.cpp' and 'rdadmin/edit_svc.h'. + * Added a 'Service' control to the RDDgImport utility in + 'utils/rddgimport/rddgimport.cpp' and + 'utils/rddgimport/rddgimport.h'. +2013-01-07 Fred Gleason + * Added a 'GROUPS.DELETE_EMPTY_CARTS' field to the database. + * Incremented the database version to 215. + * Added 'RDGroup::deleteEmptyCarts()' and + 'RDGroup::setDeleteEmptyCarts()' methods in 'lib/rdgroup.cpp' + and 'lib/rdgroup.h'. + * Added a 'Delete carts if empty' control to the Edit Group + dialog in 'rdadmin/edit_group.cpp' and 'rdadmin/edit_group.h'. + * Implemented empty cart deletion for rdmaint(1) in + 'utils/rdmaint/rdmain.cpp'. +2013-01-07 Fred Gleason + * Cleaned up warnings in 'lib/rdweb.cpp' and 'lib/rdweb.h'. +2013-01-07 Fred Gleason + * Added 'xdg/rivendell-rddgimport.desktop'. + * Removed strip(1) calls from 'rivendell.spec.in'. + * Added version information to title bar in 'rdadmin/rdadmin.cpp'. + * Added version information to title bar in 'rdairplay/rdairplay.cpp'. + * Added version information to title bar in + 'rdcastmanager/rdcastmanager.cpp'. + * Added version information to title bar in 'rdcatch/rdcatch.cpp'. + * Added version information to title bar in 'rdlibrary/rdlibrary.cpp'. + * Added version information to title bar in 'rdlogedit/rdlogedit.cpp'. + * Added version information to title bar in 'rdpanel/rdpanel.cpp'. + * Added version information to title bar in 'rdselect/rdselect.cpp'. + * Added version information to title bar in + 'utils/rdalsaconfig/rdalsaconfig.cpp'. + * Added version information to title bar in + 'utils/rdgpimon/rdgpimon.cpp'. + * Added version information to title bar in + 'utils/rdhpiinfo/rdhpiinfo.cpp'. + * Added version information to title bar in + 'utils/rdsoftkeys/rdsoftkeys.cpp'. + * Added version information to title bar in + 'utils/rmlsend/rmlsend.cpp'. +2013-01-11 Fred Gleason + * Added RDDgImport(1) to the 'Utilities' menu in + '/xdg/rivendell-rivendell.menu'. +2013-01-11 Fred Gleason + * Added a workaround in 'utils/rddgimport/rddgimport.cpp' to + prevent double entry of spots in the traffic file when outputting + to broken CIFS filesystems that don't honor O_TRUNC. +2013-01-14 Fred Gleason + * Added 'CUTS.ISCI_IDX' and 'CUTS.ISRC_IDX' indices to the database. + * Incremented the database version to 216. + * Optimized RDDgImport(1) to reuse existing spot audio for multiple + logs. +2013-01-14 Fred Gleason + * Fixed a bug in the 'make rpm' target of 'Makefile.am' that failed + to copy all generated RPMs to the build directory. + * Added code to provide a default log template name for new + services in 'lib/rdsvc.cpp'. +2013-01-14 Fred Gleason + * Fixed a bug in 'rdlibrary/list_reports.cpp' that caused the + 'Cart Report' report to be empty. +2013-01-21 Fred Gleason + * Added an 'NPR SoundExchange' report in 'lib/export_nprsoundex.cpp'. + * Added 'RDReport::NprSoundExchange' value to the + 'RDReport::ExportFilter' enum in 'lib/rdreport.h'. +2013-01-21 Fred Gleason + * Fixed a bug in 'utils/rddgimport/rddgimport.cpp' that caused + invalid end dates to be set on cuts. +2013-01-21 Fred Gleason + * Fixed a bug in 'utils/rddgimport/rddgimport.cpp' that caused + a segfault at startup. +2013-01-21 Fred Gleason + * Added the source filename when reporting importer errors + in 'utils/rddgimport/rddgimport.cpp'. +2013-01-21 Fred Gleason + * Fixed a bug in 'lib/lib.pro' that broke the build under + Windows. +2013-01-22 Fred Gleason + * Added an 'Music Playout' report in 'lib/export_musicplayout.cpp'. + * Added 'RDReport::MusicPlayout' value to the + 'RDReport::ExportFilter' enum in 'lib/rdreport.h'. +2013-01-22 Fred Gleason + * Tweaked layout on the 'Select Report Dates' dialog in + 'rdlogmanager/pick_report_dates.cpp'. + * Tweaked layout on the 'Select Date' dialog in + 'lib/rddatepicker.cpp'. +2013-01-22 Fred Gleason + * Tweaked the field widths in the 'Music Playout' report in + 'lib/export_musicplayout.cpp'. +2013-01-22 Fred Gleason + * Added an display of the report location in + 'rdlogmanager/pick_report_dates.cpp'. +2013-01-28 Fred Gleason + * Applied updates to the Czech [CS] translation from + Pavel Fric . +2013-01-28 Fred Gleason + * Updated 'NEWS'. + * Updated the package version to 2.4.0. +2013-01-30 Fred Gleason + * Applied a patch from Al Davis against + 'lib/rddownload.cpp' to add support for 302 redirects. +2013-01-30 Fred Gleason + * Added sanity checks for valid start time fields when importing + schedule files in 'lib/rdsvc.cpp'. +2013-01-30 Fred Gleason + * Fixed a bug in 'lib/rdlivewire.cpp' that broke login with a + Radius engine. +2013-02-04 Fred Gleason + * Fixed a bug in 'utils/rddgimport/rddgimport.cpp' that caused + null cart numbers to be output to the traffic file when + reusing an existing cart. +2013-02-05 Fred Gleason + * Removed a spurious check for overlapping Start Date and End Date + Offsets in 'rdadmin/edit_dropbox.cpp'. +2013-02-07 Fred Gleason + * Added a timer test in 'tests/timer_test.cpp' and + 'test/timer_test.h'. +2013-02-08 Fred Gleason + * Fixed a bug in 'lib/export_deltaflex.cpp', 'lib/export_bmiemr.cpp', + 'lib/nprsoundex.cpp' and 'lib/export_radiotraffic.cpp', + that caused lines to be generated with an extra CR at the end + under Windows. +2013-02-20 Fred Gleason + * Added a 'RDMatrix::LiveWireGpio' value to the 'RDMatrix::Type + enum in 'lib/rdmatrix.cpp' and 'lib/rdmatrix.h'. + * Added a 'Livewire Virtual GPIO' driver in 'ripcd/livewire_gpio.cpp' + and 'ripcd/livewire_gpio.h'. + * Added a 'LIVEWIRE_GPIO_SLOTS' table to the database. + * Incremented the database version to 217. + * Added a 'RDListView::GpioSort' value to the 'RDListView::SortType' + enum in 'lib/rdlistview.h', 'lib/rdlistvieitem.cpp' and + 'lib/rdlistviewitem.h'. + * Added a 'LiveWire GPIOs' button to the 'Edit Matrix' dialog + in 'rdadmin/edit_matrix.cpp' and 'rdadmin/edit_matrix.h'. +2013-02-27 Fred Gleason + * Added import suport for the 'SEC1', 'EOD ' and 'INT ' CartChunk + timers in 'lib/rdwavefile.cpp'. + * Fixed a bug in 'rdlibrary/audio_cart.cpp' that caused all + cut-level metadata to fail to be applied during importation. + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that caused cut-level + metadata to be incorrectly applied. +2013-03-03 Fred Gleason + * Fixed a bug in 'ripcd/livewire_gpio.cpp' that caused GPI events + to be duplicated. +2013-03-03 Fred Gleason + * Cleaned up warnings in 'ripcd/local_gpio.cpp' and + 'ripcd/sas64000.cpp'. +2013-03-03 Fred Gleason + * Fixed a bug in 'ripcd/livewire_gpio.cpp' that caused pulsed + GPI events to be handled incorrectly. +2013-03-05 Fred Gleason + * Added a 'LIVEWIRE_GPIO_SLOTS.IP_ADDRESS' field to the + database. + * Incremented the database version to 218. + * Added 'IP Address' controls to the Livewire GPIO Source + Assignments dialog in 'rdadmin/list_livewiregpios.cpp' and + 'rdadmin/list_livewiregpios.h', 'rdadmin/edit_livewiregpio.cpp' + and 'rdadmin/edit_livewiregpio.h'. + * Implemented the ability to filter GPIO events by surface IP + address in 'ripcd/livewire_gpio.cpp' and 'ripcd/livewire_gpio.h'. +2013-03-05 Fred Gleason + * Fixed a bug in 'rdairplay/log_play.cpp' that caused macro carts + with the asyncronous attribute set to fail to be logged for ELR. +2013-03-06 Fred Gleason + * Fixed a regression in 'rdadmin/edit_livewiregpio.cpp' that + broke the 'Source' control. +2013-03-06 Fred Gleason + * Fixed a bug in 'ripcd/livewire_gpio.cpp' that broke GPO + processing. +2013-03-08 Fred Gleason + * Fixed a bug in 'rdadmin/list_livewiregpios.cpp' that caused + incorrect values to be saved for the 'Surface Address' + parameter. + * Implemented the 'I' option for the 'GO' RML in + 'ripcd/livewire_gpio.cpp'. + * Added an 'RDAIRPLAY_CHANNELS' table to the database. + * Incremented the database version to 219. + * Added an 'Edit Channel GPIO' dialog in + 'rdadmin/edit_channelgpios.cpp'and 'rdadmin/edit_channelgpios.h'. + * Implemented channel GPIO functionality in 'rdairplay/rdairplay.cpp', + 'rdairplay/rdairplay.h', 'rdairplay/log_play.cpp' and + 'rdairplay/log_play.h'. +2013-03-09 Fred Gleason + * Fixed a bug in 'rdairplay/rdairplay.cpp' that caused channel GPIO + operation to be incorrect with non-symmetric configurations. +2013-03-09 Fred Gleason + * Refactored Channel GPIO logic to operate across multiple + log machines in 'rdairplay/log_play.cpp', 'rdairplay/log_play.h', + 'rdairplay/rdairplay.cpp' and 'rdairplay/rdairplay.h'. +2013-03-11 Fred Gleason + * Added 'Edit CPIOs' buttons for SoundPanel channel assignments + in 'rdadmin/edit_rdairplay.cpp'. +2013-03-13 Fred Gleason + * Implemented channel GPIO functionality for the sound panel + in 'lib/rdsound_panel.cpp', 'lib/rdsound_panel.h', + 'rdairplay/rdairplay.cpp' and 'rdairplay/rdairplay.h'. +2013-03-13 Fred Gleason + * Removed the 'Edit GPIOs' button for the Audition / Cue channel + in 'rdadmin/edit_rdairplay.cpp'. +2013-03-13 Fred Gleason + * Added 'RDAIRPLAY_CHANNELS.GPIO_TYPE' and 'RDPANEL_CHANNELS.GPIO_TYPE' + fields to the database. + * Incremented the database version to 220. + * Added 'RDAirPlayConf::gpioType()' and 'RDAirPlayConf::setGpioType()' + methods in 'lib/rdairplay_conf.cpp' and 'lib/rdairplay_conf.h'. + * Added a 'Signalling Type' control to the 'Edit Channel GPIOs' + dialog in 'rdadmin/edit_channelgpios.cpp' and + 'rdadmin/edit_channelgpios.h'. +2013-03-13 Fred Gleason + * Implemented GPIO channel stop for the sound panel in + 'lib/rdsound_panel.cpp' and 'rdairplay/rdairplay.cpp'. +2013-03-13 Fred Gleason + * Fixed a bug in 'rdairplay/rdairplay.cpp' that caused port 2 + channel GPO to fail. +2013-03-13 Fred Gleason + * Added code in 'rdairplay/rdairplay.conf' to remove duplicate + GPIO channel configuration when both Main Log outputs are + configured to use the same port. +2013-03-13 Fred Gleason + * Fixed a bug in 'lib/rdsound_panel.cpp' that caused GPIO stop + events to stop the incorrect buttons. +2013-03-13 Fred Gleason + * Fixed up fonts in dropdown menus in 'utils/rmlsend/rmlsend.cpp'. + * Fixed up fonts in dropdown menus in 'utils/rdgpimon/rdgpimon.cpp'. +2013-03-19 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that caused incorrect + CARD and PORT values to be converted into schema version 220. +2013-03-20 Fred Gleason + * Fixed a bug in 'rdairplay/rdairplay.cpp' that caused a + segfault when processing an invalid channel GPIO event. +2013-03-22 Fred Gleason + * Fixed a bug in 'rdairplay/rdairplay.cpp' that caused GPIO + start events to be ignored when using Level signalling. +2013-03-22 Fred Gleason + * Fixed a regression in 'utils/rdimport/rdimport.cpp' that + metadata patterns. +2013-03-22 Fred Gleason + * Cleaned up a warning in 'utils/rdimport/rdimport.cpp'. +2013-03-22 Fred Gleason + * Applied a fix from Todd Baker + for broken --use-cartchunk-cutid' switch in 'rdcatchd/rdcatchd.cpp'. +2013-03-26 Fred Gleason + * Fixed a bug in 'utils/rddgimport/rddgimport.cpp' that caused + duplicate events to be written to the traffic import file. +2013-03-26 Fred Gleason + * Added PNG Rivendell icons. +2013-03-26 Fred Gleason + * Corrected invalid Encoding entry in 'xdg/rivendell-rdgpimon.desktop', + 'xdg/rivendell-rddgimport.desktop' and + 'xdg/rivendell-rdalsaconfig.desktop'. +2013-03-26 Fred Gleason + * Fixed up fonts in log list in 'rdlogedit/rdlogedit.cpp'. +2013-03-29 Fred Gleason + * Added 'xdg/rdalsaconfig-root-consolehelper', + 'xdg/rdalsaconfig-root-pam', 'xdg/rdhpiinfo-root-consolehelper', + 'xdg/rdhpiinfo-root-pam', 'xdg/rivendell-rdalsaconfig-root.desktop', + and 'xdg/rivendell-rdhpiinfo-root.desktop'. +2013-04-01 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.5.0. +2013-04-29 Fred Gleason + * Added an RDDelete(1) utility in 'utils/rddelete/'. +2013-04-29 Fred Gleason + * Added a 'ChannelsPerPcm=' directive to the [Alsa] section of + rd.conf(5) in 'lib/rdconfig.cpp' and 'lib/rdconfig.h'. +2013-05-10 Fred Gleason + * Added support for the 'INT1' CartChunk timer in + 'lib/rdwavefile.cpp'. +2013-05-10 Fred Gleason + * Added support for PKT files to nexgen_filter(1) in + 'importers/nexgen_filter.cpp' and 'importers/nexgen_filter.h'. +2013-05-14 Fred Gleason + * Modified the 'make rpm' target to work properly even when + no HPI support is present. +2013-05-17 Fred Gleason + * Added casts in 'lib/rdaudioconvert.cpp' to allow building against + SoundTouch v1.7.1. + * Cleaned up a warning in 'lib/rdconf.cpp'. +2013-05-21 Fred Gleason + * Fixed a regression in 'utils/rdimport/rdimport.cpp' that broke + importation of start and end datetimes from cart chunk. +2013-05-21 Fred Gleason + * Fixed a bug in 'lib/rdlog_event.cpp' and 'lib/rdlog.cpp' + that caused queries to fail when processing services whose name + contained a hyphon [Mantis bug #0000069]. +2013-05-21 Fred Gleason + * Fixed various problems with Hook mode in RDCartSlots(1) + [Mantis bug #0000071]. +2013-05-22 Fred Gleason + * Updated 'NEWS' + * Incremented the package version to 2.5.1. +2013-06-17 Fred Gleason + * Fixed a bug in 'lib/rdcuts.cpp' that caused talk markers to + be imported incorrectly via rdimport(1). +2013-06-20 Fred Gleason + * Added an 'RDStringToData()' function in 'lib/rdconf.cpp' + and 'lib/rdconf.h'. + * Documented binary escape syntax in 'docs/rml.sxw'. + * Implemented binary escape syntax for the the 'Serial Out' + ['SO'] and 'UDP Out' ['UO'] RMLs in 'ripcd/local_macros.cpp'. +2013-06-20 Fred Gleason + * Implemented a '--delete-cuts' switch for nexgen_filter(1) + in 'importers/nexgen_filter.cpp' and 'importers/nextgen_filter.h'. +2013-06-26 Fred Gleason + * Fixed a bug in 'cae/cae_alsa.cpp' that caused the 'ChannelsPerPcm=' + parameter in rd.conf(5) to be ignored when starting capture devices. +2013-06-27 Fred Gleason + * Added an 'RDMatrix::Am16' value to the 'RDMatrix::Type' enum + in 'lib/rdmatrix.cpp' and 'lib/rdmatrix.h'. + * Added a driver for the 360 Systems AM16 Audio Crosspoint Switcher + in 'ripcd/am16.cpp' and 'ripcd/am16.h'. + * Updated 'docs/SWITCHERS.txt'. +2013-06-28 Fred Gleason + * Fixed a bug in 'lib/rdcart.cpp' that broke new cut creation when + the cut number reached 999'. + * Added an 'RD_MAX_CUT_NUMBER' define in 'lib/rd.h'. + * Added a check for failure to create a new cut in + 'rdlibrary/audio_cart.cpp', 'rdlibrary/edit_cart.cpp', + 'rdlogedit/voice_tracker.cpp' and 'utils/rdimport/rdimport.cpp'. +2013-07-03 Fred Gleason + * Updated 'NEWS'. + * Updated the package version to 2.5.2. +2013-07-03 Fred Gleason + * Added an overloaded 'RDCdRipp::rip()' method in + 'lib/rdcdripper.cpp' and 'lib/rdcdripper.h'. + * Added multi-track rip support to the 'Rip CD' dialog in + 'rdlibrary/cdripper.cpp' and 'rdlibrary/cdripper.h'. +2013-07-03 Fred Gleason + * Fixed a bug in 'rdlogedit/edit_log.cpp' that allowed access + to the 'Edit Log Entry' dialog even when Arrange Log privilege + was denied. +2013-07-05 Fred Gleason + * Fixed a bug in 'lib/rdcartslot.cpp' that broke ELR logging + for cart slot playouts in Cart Deck mode. +2013-07-05 Fred Gleason + * Added an 'RDCueEdit' widget in 'lib/rdcueedit.cpp' and + 'lib/rdcueedit.h'. + * Added an 'RDMarkerBar' wdiget in 'lib/rdmarker_bar.cpp' + and 'lib/rdmarker_bar.h'. +2013-07-05 Fred Gleason + * Added an 'Edit Cue Point' dialog in 'lib/rdeditcuedialog.cpp' + and 'lib/rdeditcuedialog.h'. + * Added the ability to set custom start and end points in + 'lib/rdcartslot.cpp', 'lib/rdcartslot.h', 'lib/rdslotbox.cpp', + 'lib/rdslotbox.h', 'rdcartslots/rdcartslots.cpp' and + 'rdcartslots/rdcartslots.h'. +2013-07-17 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that caused music and traffic + merges to erroneously report success when executed from the + command line interface of RDLogManager(1). +2013-07-30 Fred Gleason + * Added a description of the error when logging SQL errors in + 'lib/rddb.cpp'. +2013-07-30 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that performed invalid SQL + inserts when processing track and break strings when importing + schedules. +2013-08-09 Fred Gleason + * Fixed a bug in 'rdlogmanager/commandline_ops.cpp' that caused + an error when attempting to generate a report with the CLI + interface when no X server was available. +2013-09-12 Fred Gleason + * Added an 'rlm_spinitron_plus' RLM in 'rlm/rlm_spinitron_plus.c'. + * Renamed the 'Cart Data Dump' report to 'Cart Data Dump (fixed width)" + in 'rdlibrary/list_reports.cpp'. + * Added a 'Cart Data Dump (CSV)' report in 'rdlibrary/list_reports.cpp' + and 'rdlibrary/list_reports.h'. + * Added a 'Prepend Field Names' checkbox to the List Reports dialog + in 'rdlibrary/list_reports.cpp' and 'rdlibrary/list_reports.h'. +2013-09-12 Fred Gleason + * Added a 'log_mode' field to the 'rlm_log' struct in 'rlm/rlm.h'. + * Added 'RLM_LOGMODE_LIVEASSIST', 'RLM_LOGMODE_AUTOMATIC' and + 'RLM_LOGMODE_MANUAL' defines in 'rlm/rlm.h'. + * Incremented 'RLM_VERSION' to 13 in 'rlm/rlm.h'. + * Updated the 'rlm_test' RLM in 'rlm/rlm_test.c' to use the + 'rlm_log->log_mode' field. +2013-09-12 Fred Gleason + * Implemented a 'PlaylistMode=' directive in the configuration + file for the 'rlm_spinitron_plus' RLM in 'rlm/rlm_spinitron_plus.c'. +2013-10-02 Fred Gleason + * Fixed a bug in 'web/rdxport/export.cpp' that broke level + normalization for audio exports. + * Fixed a bug in 'lib/rdimport_audio.cpp' that broke level + normalization for audio exports. +2013-10-03 Fred Gleason + * Added a 'DisableMaintChecks=' parameter to the [Hacks] section + of rd.conf(5). +2013-10-04 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.5.3. +2013-10-11 Fred Gleason + * Applied a patch from Max Goldstein that added + a 'Clear All' button to the Edit Grid dialog in + 'rdlogmanager/edit_grid.cpp' and 'rdlogmanager/edit_grid.h'. +2013-10-11 Fred Gleason + * Corrected misspellings of 'RDXPORT' as 'RDEXPORT' in + 'docs/web_api.odt'. + * Documented a 'ListLogs' command in 'docs/web_api.odt'. + * Added 'RDXPORT_LISTLOGS_COMMAND' in 'lib/rdxport_interface.h'. + * Added an 'RDLog::xml()' method in 'lib/rdlog.cpp' and 'lib/rdlog.h'. + * Implemented the 'ListLogs' command in 'web/rdxport/logs.cpp'. +2013-10-11 Fred Gleason + * Documented a 'ListServices' command in 'docs/web_api.odt'. + * Added 'RDXPORT_LISTSERVICES_COMMAND' in 'lib/rdxport_interface.h'. + * Added an 'RDSvc::xml()' method in 'lib/rdsvc.cpp' and 'lib/rdsvc.h'. + * Implemented the 'ListServices' command in 'web/rdxport/services.cpp'. +2013-10-12 Fred Gleason + * Corrected command value for the 'ListLogs' service in + 'docs/web_api.odt'. +2013-10-13 Fred Gleason + * Documented a 'ListLog' command in 'docs/web_api.odt'. + * Added 'RDXPORT_LISTLOG_COMMAND' in 'lib/rdxport_interface.h'. + * Added an 'RDLogEvent::xml()' method in 'lib/rdlog_event.cpp' + and 'lib/rdlog_event.h'. + * Added an 'RDLogLine::xml()' method in 'lib/rdlog_line.cpp' + and 'lib/rdlog_line.h'. + * Implemented the 'ListLog' command in 'web/rdxport/services.cpp'. +2013-10-15 Fred Gleason + * Fixed bugs in the 'ListLog' command implementation in + 'lib/rdlog_line.cpp'. +2013-10-16 Fred Gleason + * Fixed a buffer overflow bug in 'rlm/rlm_filewrite.c'. +2013-10-16 Fred Gleason + * Defined an 'RLMResolveNowNextEncoded()' function in 'rlm/rlm.h'. + * Added 'RLM_ENCODE_NONE', 'RLM_ENCODE_XML' and 'RLM_ENCODE_URL' + defines in 'rlm/rlm.h'. + * Incremented 'RLM_VERSION' in 'rlm/rlm.h' to 14. + * Added variable field encoding to the 'RDResolveNowNext()' + function in 'lib/rdnownext.cpp' and 'lib/rdnownext.h'. + * Removed the 'RDEscapeWebString()' function from 'lib/rdweb.cpp' + and 'lib/rdweb.h'. + * Added 'RDUrlEscape()' and 'RDUrlUnescape()' functions in + 'lib/rdweb.cpp' and 'lib/rdweb.h'. + * Added a 'stringcode_test' test harness in + 'tests/stringcode_test.cpp' and 'tests/stringcode_test.h'. + * Added support for an 'Encoding=' parameter for + 'conf/rlm_udp.conf' in 'rlm/rlm_udp.c'. +2013-10-16 Fred Gleason + * Added support for an 'Encoding=' parameter for + 'conf/rlm_filewrite.conf' in 'rlm/rlm_filewrite.c'. + * Added support for an 'Encoding=' parameter for + 'conf/rlm_serial.conf' in 'rlm/rlm_serial.c'. +2013-10-23 Fred Gleason + * Added a 'cutNumber' field to the XML schema for the 'ListLog' + method. +2013-10-29 Fred Gleason + * Fixed a bug in 'lib/rdexportpeaks.cpp' that caused a + peaks download error when creating voicetracks using MPEG L2 + format. +2013-10-30 Fred Gleason + * Added 'originUser' and 'originDateTime' fields to the XML schema + for the 'ListLog' method. +2013-10-31 Fred Gleason + * Fixed a bug in 'lib/rdlog_line.cpp' that broke the build + under Windows. +2013-10-31 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that broke the build + under Windows. +2013-11-01 Fred Gleason + * Updated 'NEWS' + * Incremented the package version to 2.5.4. +2013-11-05 Fred Gleason + * Added 'rlm_start_msec', 'rlm_start_sec', 'rlm_start_min', + 'rlm_start_hour', 'rlm_start_day', 'rlm_start_mon' and + 'rlm_start_year' fields to the 'rlm_pad' struct in 'rlm/rlm.h'. + * Incremented 'RLM_VERSION' to 15 in 'rlm/rlm.h'. + * Updated 'rlm/rlm_filewrite.c' to use the start_time fields. + * Updated 'rlm/rlm_test.c' to use the start_time fields. + * Updated 'rlm/rlm_serial.c' to use the start_time fields. + * Updated 'rlm/rlm_udp.c' to use the start_time fields. +2013-11-05 Fred Gleason + * Added support for the LPCore 'Connection Ping' command + in 'ripcd/vguest.cpp' and 'ripcd/vguest.h'. + * Removed repetitious syslog error messages from the vGuest + driver in 'ripcd/vguest.cpp' and 'ripcd/vguest.h'. +2013-11-07 Fred Gleason + * Fixed a bug in 'ripcd/vguest.cpp' that threw a segfault + when destroying a driver instance. +2013-11-07 Fred Gleason + * Modified RDMonitor to support positioning on multi-head displays. +2013-11-09 Fred Gleason + * Modified 'ripcd/livewire_gpio.cpp' and 'ripcd/livewire_gpio.h' + so as not to require a static multicast route to be able to send + GPO commands. +2013-11-11 Fred Gleason + * Modified 'rdmonitor/rdmonitor.cpp' so as to employ unsigned + X and Y offset values. +2013-11-11 Fred Gleason + * Fixed a bug in 'lib/rdimport_audio.cpp' that caused the origin + host name to be set incorrectly when using a non-localhost value + for HTTP Xport value when importing audio in RDLibrary. +2013-11-11 Fred Gleason + * Fixed a bug in 'utils/rdimport/rdimport.cpp' that caused the origin + host name to be set incorrectly when using a non-localhost value + for HTTP Xport value when importing audio in RDImport. +2013-11-12 Fred Gleason + * Added a '--create-db=hostname=' parameter for RDAdmin in + 'rdadmin/rdadmin.cpp' and 'rdadmin/createdb.cpp'. +2013-11-13 Fred Gleason + * Refactored RPM packaging to split the 'rivendell' package into + 'rivendell' and 'rivendell-base'. + * Modified 'rivendell-suse.in' to detect state properly when + using only caed(8). +2013-11-13 Fred Gleason + * Added '[RDSelect]' configuration source to the 'HTTP Xport' and + 'Core Audio Engine' controls in the Edit Host dialog in RDAdmin. +2013-11-13 Fred Gleason + * Debugged RDSelect configuration sources for Xport and CAE + services. +2013-11-15 Fred Gleason + * Fixed a bug in 'lib/rdcart_dialog.cpp' that caused carts to + be listed by alphabetical order rather than by time length when + sorting by the 'Length' column. +2013-11-15 Fred Gleason + * Changed the name of the 'Livewire Virtual GPIO' driver to + 'Livewire Multicast GPIO' in 'lib/rdmatrix.cpp'. +2013-11-15 Fred Gleason + * Added a 'Livewire Virtual GPIO' driver listing in + 'lib/rdmatrix.cpp' and 'lib/rdmatrix.h'. + * Implemented a 'Livewire Virtual GPIO' driver in + 'ripcd/livewire_virtual.cpp' and 'ripcd/livewire_virtual.h'. +2013-11-16 Fred Gleason + * Renamed the 'LiveWire Virtual GPIO' driver to 'LiveWire LWRP GPIO' + in 'lib/rdmatrix.cpp'. + * Renamed 'ripcd/livewire_virtual.cpp' to + 'ripcd/livewire_lwrpgpio.cpp'. + * Renamed 'ripcd/livewire_virtual.h' to + 'ripcd/livewire_lwrpgpio.h'. +2013-11-17 Fred Gleason + * Renamed the 'LiveWire' driver to 'LiveWire LWRP Audio' + in 'lib/rdmatrix.cpp'. + * Renamed 'ripcd/livewire.cpp' to 'ripcd/livewire_lwrpaudio.cpp'. + * Renamed 'ripcd/livewire.h' to 'ripcd/livewire_lwrpaudio.h'. + * Removed GPIO functionality from 'ripcd/livewire_lwrpaudio.cpp' + and 'ripcd/livewire_lwrpaudio.h'. + * Updated 'docs/SWITCHERS.txt'. +2013-11-18 Fred Gleason + * Fixed a bug in 'lib/rdstation.cpp' that broke the build under + Windows. +2013-11-19 Fred Gleason + * Removed a typo in 'conf/rd.conf-sample' that caused the + 'ChannelsPerPcm=' directive in the [Alsa] section to be + read incorrectly. +2013-11-19 Fred Gleason + * Updates 'NEWS'. + * Incremented the package version to 2.5.5. +2013-12-02 Fred Gleason + * Changed the default value of the 'RDLIBRARY.TRIM_THRESHOLD' field + from -3000 to 0. + * Incremented the database version to 221. +2013-12-03 Fred Gleason + * Added an 'RDUser::groups()' method in 'lib/rduser.cpp' and + 'lib/rduser.h'. + * Added an 'RDDiscImport' utility in 'utils/rddiscimport/'. +2013-12-04 Fred Gleason + * Fixed a bug in 'utils/rddiscimport/rddiscimport.cpp' that + caused the first CD track to fail to appear on the track list. + * Fixed a bug in 'utils/rddiscimport/rddiscimport.cpp' that + caused the 'Disc ID' field to be disabled after resizing the + application window. +2013-12-04 Fred Gleason + * Added a sanity check in 'RDCut::getMetadata()' to ensure that + segue position data is consistent when dealing with cuts + with undefined lengths. + * Added code to lock GUI elements when performing rips in + 'utils/rddiscimport.cpp'. +2013-12-04 Fred Gleason + * Added the ability to double-click track entries to disable + ripping in 'utils/rddiscimport.cpp'. +2013-12-04 Fred Gleason + * Added a 'User Defined' control in + 'utils/rddiscimport/rddiscimport.cpp'and + 'utils/rddiscimport/rddiscimport.h'. +2013-12-04 Fred Gleason + * Added support for 'Client' and 'Agency' header fields in + 'utils/rddiscimport/metarecord.cpp', + 'utils/rddiscimport/metarecord.h', + 'utils/rddiscimport/metalibrary.cpp' and + 'utils/rddiscimport/metalibrary.h'. +2013-12-05 Fred Gleason + * Added support for reading metadta from 'AIR1' chunks in WAV + files in 'lib/rdwavefile.cpp' and 'lib/rdwavefile.h'. +2013-12-05 Fred Gleason + * Fixed a bug in 'lib/rdconf.cpp' that broke the build under + Windows. +2013-12-05 Fred Gleason + * Fixed a bug in 'utils/rddiscimport/rddiscimport.cpp' that + threw a segfault when starting with an invalid CDROM device + specified. +2013-12-07 Fred Gleason + * Documented the 'AudioInfo' RDXport command call in + 'docs/webapi.odt'. +2013-12-10 Fred Gleason + * Added support in 'utils/rddiscimport/rddiscimport.cpp' for + CDs with null tracks. +2013-12-10 Fred Gleason + * Added a NaturalLog log file format in 'docs/scheduler_formats.ods'. + * Added a sample file for NaturalLog in 'docs/examples/080509T3.LOG' + * Added a 'NaturalLog' import template to the 'IMPORT_TEMPLATES' + table. + * Incremented the database version to 222. + * Added a report called 'NaturalLog Reconciliation' in + 'lib/rdreport.cpp' and 'lib/rdreport.h'. +2013-12-11 Fred Gleason + * Added a 'CART.CONDUCTOR' field to the database. + * Added a 'CART.SONG_ID' field to the database. + * Added a 'CART.BPM' field to the database. + * Incremented the database version to 223. + * Added 'RDCart::conductor()', 'RDCart::setConductor()', + 'RDCart::songId()', 'RDCart::setSongId()', 'RDCart::beatsPerMinute()', + and 'RDCart::setBeatsPerMinute()' methods in 'lib/rdcart.cpp' and + 'lib/rdcart.h'. + * Added 'RDWaveData::conductor()' and 'RDWaveData::setConductor()' + methods in 'lib/rdwavedata.cpp' and 'lib/rdwavedata.h'. + * Added 'Conductor', 'Song ID' and 'Beats per Minute' controls to + the Edit Cart dialog in 'rdlibrary/edit_cart.cpp' and + 'rdlibrary/edit_cart.h'. +2013-12-11 Fred Gleason + * Added '%r' ['Conductor'] and '%s' ['Song ID'] wildcards for + the '--metadata-pattern=' switch for rdimport(1) in + 'utils/rdimport/rdimport.cpp' and 'utils/rdimport/rdimport.h'. + * Added a '--set-user-defined=' switch for rdimport(1) in + 'utils/rdimport/rdimport.cpp' and 'utils/rdimport/rdimport.h'. +2013-12-11 Fred Gleason + * Added a 'DROPBOXES.SET_USER_DEFINED' field to the database. + * Incremented the database version to 224. + * Added 'RDDropbox::userDefined()' and 'RDDropbox::setUserDefined()' + methods in 'lib/rddropbox.cpp' and 'lib/rddropbox.h'. + * Added a 'User Defined' control to the Edit Dropbox dialog in + 'rdadmin/edit_dropbox.cpp' and 'rdadmin/edit_dropbox.h'. + * Added a 'User Defined' column to the List Dropboxes dialog + in 'rdadmin/list_dropboxes.cpp' and 'rdadmin/list_dropboxes.h'. +2013-12-11 Fred Gleason + * Added 'CART.CONDUCTOR' and 'CART.SONG_ID' fields to the search + fields in 'lib/rdcart_search_text.cpp'. +2013-12-11 Fred Gleason + * Added 'RDLogLine::conductor()', 'RDLogLine::setConductor()', + 'RDLogLine::songId()' and 'RDLogLine::setSongId()' methods in + 'lib/rdlog_line.cpp' and 'lib/rdlog_line.h'. + * Added 'rlm_conductor' and 'rlm_song_id' fields to the 'rlm_pad' + struct in 'rlm/rlm.h'. + * Incremented 'RLM_VERSION' to 16 in 'rlm/rlm.h'. + * Added '%r' and '%R' wildcards for 'conductor' in + 'lib/rdnownext.cpp'. + * Added '%s' and '%S' wildcards for 'song ID' in + 'lib/rdnownext.cpp'. +2013-12-11 Fred Gleason + * Updated sample RLM configuration files in 'conf/' to reflect + new '%r', '%R', '%s' and '%S' wildcards. +2013-12-11 Fred Gleason + * Added 'Composer' and 'Conductor' columns to the Select Cart dialog + in 'lib/rdcart_dialog.cpp'. +2013-12-11 Fred Gleason + * Added 'Composer', 'Conductor' and 'Publisher' columns to the + RDLibrary Cart List in 'rdlibrary/rdlibrary.cpp'. + * Removed the 'Play Order' column from the RDLibrary Cart List + in 'rdlibrary/rdlibrary.cpp'. +2013-12-11 Fred Gleason + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that caused the Group + entry in the Cart List to be incorrect after editing a cart. +2013-12-12 Fred Gleason + * Fixed a regression in 'lib/rdlog_line.cpp' that broke timescaling. +2013-12-13 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.6.0. +2013-12-13 Fred Gleason + * Fixed code in 'rivendell.spec.in' to allow building on SuSE. +2013-12-13 Fred Gleason + * Fixed a bug in 'rivendell.spec.in' that broke the 'make rpm' + target on EL6. +2013-12-15 Fred Gleason + * Fixed a regression in 'rdlibrary/edit_cart.cpp' that broke + multi-cart editing. +2013-12-17 Karl Koscher + * Fixed a small buffer overflow issue with ISRC/ISCI metadata + in RLMHost. +2013-12-20 Fred Gleason + * Increased CAE_MAX_CONNECTIONS to 128 in 'lib/rd.h'. +2013-12-23 Fred Gleason + * Fixed a bug in 'lib/edit_rdpanel.cpp' and 'lib/edit_rdpanel.cpp' + that provided incorrect channel assignment contraints when using + remote CAE services. +2013-12-23 Fred Gleason + * Fixed a bug in 'lib/edit_rdcartslots.cpp' and + 'lib/edit_rdcartslots.cpp' that provided incorrect channel assignment + contraints when using remote CAE services. +2013-12-23 Fred Gleason + * Added code in 'lib/rdpanel_button.cpp' and 'lib/rdsound_panel.cpp' + so as to display 'No Audio' in the length field of a button when + the underlying audio is unavailable. +2013-12-23 Fred Gleason + * Added code in 'rdlibrary/macro_cart.cpp' and + 'rdlibrary/edit_macro.cpp' so that double-clicking on the + 'End of Cart' marker adds a new RML line. + * Added code in 'rdlibrary/macro_cart.cpp' and + 'rdlibrary/edit_macro.cpp' so a new RML line is selected by + default in the Edit Macro dialog. +2013-12-23 Fred Gleason + * Increased size of the 'Edit Macro' dialog in + 'rdlibrary/edit_macro.cpp'. +2013-12-26 Fred Gleason + * Modified 'rdlibrary/audio_cart.cpp' and 'rdlibrary/audio_cart.h' + to allow deletion of multiple cuts simultaneously. +2013-12-26 Fred Gleason + * Fixed a bug in 'rdmonitor/rdmonitor.cpp' that broke host updates. +2013-12-26 Fred Gleason + * Added a desktop entry for RDMonitor. +2013-12-27 Fred Gleason + * Added an 'RDCartDrag' class in 'lib/rdcartdrag.cpp' and + 'lib/rdcartdrag.h'. + * Modified RDLogManager to use RDCartDrag for dragging and dropping + carts. + * Added an 'Allow Cart Dragging' control to the RDLibrary main window + in 'rdlibrary/rdlibrary.cpp' and 'rdlibrary/rdlibrary.h'. + * Added support for dragging carts into the Edit Log dialog + in 'rdlogedit/edit_log.cpp' and 'rdlogedit/edit_log.h'. +2013-12-27 Fred Gleason + * Added support for dragging carts into the Full Log and Button + Log widgets in RDAirPlay. +2013-12-27 Fred Gleason + * Added support for dragging carts into SoundPanel buttons in + 'lib/rdsound_panel.cpp, 'lib/rdsound_panel.h', + 'lib/rdpanel_button.cpp', 'lib/rdpanel_button.h', + 'lib/rdbutton_panel.cpp' and 'lib/rdbutton_panel.h'. +2013-12-27 Fred Gleason + * Added support for dragging carts from SoundPanel buttons in + 'lib/rdpanel_button.cpp' and 'lib/rdpanel_button.h'. +2013-12-27 Fred Gleason + * Added support for dragging carts from the Button Log in + 'rdairplay/loglinebox.cpp' and 'rdairplay/loglinebox.h'. +2013-12-30 Fred Gleason + * Added drag icon support when dragging from SoundPanel buttons + in 'lib/rdcartdrag.cpp'. +2013-12-30 Fred Gleason + * Added support for dropping carts into Cart Slots in + 'lib/rdcartslot.cpp', 'lib/rdcartslot.h', 'lib/rdslotbox.cpp' and + 'lib/rdslotbox.h'. +2013-12-30 Fred Gleason + * Added support for dragging carts from Cart Slots in + 'lib/rdslotbox.cpp' and 'lib/rdslotbox.h'. +2013-12-30 Fred Gleason + * Added button color when dragging and dropping carts. +2013-12-30 Fred Gleason + * Added trash can icons in 'icons/trashcan-16x16.xpm' and + 'icons/trashcan-32x32.xpm'. +2013-12-30 Fred Gleason + * Added the ability to clear a SoundPanel button by dropping an + empty cart in 'lib/rdpanel_button.cpp' and 'lib/rdsound_panel.cpp'. + * Added the ability to delete a log line by dropping an empty cart + in 'rdairplay/rdairplay.cpp'. + * Added the ability to unload a cart slot by dropping an empty cart + in 'lib/rdcartslot.cpp'. + * Added the ability to remove an entry from the pre- or post-import + list in RDLogManager's Edit Event dialog by dropping an empty cart + in 'rdlogmanager/edit_event.cpp'. +2013-12-30 Fred Gleason + * Added an empty cart source to the RDLogManager Edit Event dialog + in 'rdlogmanager/edit_event.cpp'. +2013-12-30 Fred Gleason + * Added an empty cart source to RDAirPlay in 'rdairplay/rdairplay.cpp'. +2013-12-30 Fred Gleason + * Added an empty cart source to RDPanel in 'rdpanel/rdpanel.cpp'. +2013-12-30 Fred Gleason + * Fixed a bug in 'lib/rdcartdrag.cpp' and 'lib/rdcartdrag.h' that + broke the build under Windows. + * Fixed the library layout in RDLogManager's Edit Event dialog + under Windows. +2013-12-31 Sebastien Leblanc + * Fixed a bug in 'lib/rdcart.cpp' that broke compatibility with + MariaDB. +2013-12-31 Fred Gleason + * Added code in 'rdairplay/loglinebox.cpp' and + 'rdairplay/loglinebox.h' to prevent dropping carts onto + active events. +2013-12-31 Fred Gleason + * Adjusted the position of the 'Allow Dragging' control in + 'rdlibrary/rdlibrary.cpp'. +2014-01-02 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.6.1. +2014-01-03 Fred Gleason + * * Fixed a bug in 'rdlogedit/edit_log.cpp' that threw a segfault + when dropping a cart into the end of a log in RDLogEdit's Edit Log + dialog. +2014-01-03 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.6.2. +2014-01-06 Fred Gleason + * Incremented the copyright date to '2002-2014' in + 'rdadmin/info_dialog.cpp'. +2014-01-06 Fred Gleason + * Added '%o', '%O', '%i' and '%I' wildcards in 'lib/rdnownext.cpp'. + * Added 'rlm_outcue' and 'rlm_desciption' fields to the 'rlm_pad' + struct in 'rlm/rlm.h'. + * Incremented 'RLM_VERSION' to 17 in 'rlm/rlm.h'. +2014-01-07 Fred Gleason + * Added 'RDAIRPLAY.TITLE_TEMPLATE', 'RDAIRPLAY.ARTIST_TEMPLATE', + 'RDAIRPLAY.OUTCUE_TEMPLATE' and 'RDAIRPLAY.DESCRIPTION_TEMPLATE' + fields to the database. + * Incremented the database version to 225. + * Added 'RDAirPlayConf::titleTemplate()', + 'RDAirPlayConf::setTitleTemplate()', 'RDAirPlayConf::artistTemplate()', + 'RDAirPlayConf::setArtistTemplate()', + 'RDAirPlayConf::outcueTemplate()', 'RDAirPlayConf::setOutcueTemplate()', + 'RDAirPlayConf::descriptionTemplate()' and + 'RDAirPlayConf::setDescriptionTemplate()' methods in + 'lib/rdairplay_conf.cpp' 'lib/rdairplay_conf.h'. + * Added 'Title Template', 'Artist Template', 'Outcue Template' + and 'Description Template' controls to the RDAirPlay Configuration + dialog in 'rdadmin/edit_rdairplay.cpp' and 'rdadmin/edit_rdairplay.h'. + * Added 'RDLogLine::description()' and 'RDLogLine::setDescription()' + methods in 'lib/rdlog_line.cpp' and 'lib/rdlog_line.h'. + * Implemented customized Title, Artist, Outcue and Description fields + in RDAirPlay's Button Log Widget in 'rdairplay/loglinebox.cpp'. +2014-01-07 Fred Gleason + * Implemented customized Title, Artist, Outcue and Description fields + in RDCartSlot's Cart Labels in 'rdcartslots/rdcartslots.cpp', + 'rdcartslots/rdcartslots.h', 'lib/rdcartslot.cpp' 'lib/rdcartslot.h', + 'lib/rdslotbox.cpp' and 'lib/rdslotbox.h'.. +2014-01-07 Fred Gleason + * Fixed a bug in 'rdcatch/edit_playout.cpp' that threw a segfault + when attmpting to edit a playout event on a setup with no playout + decks. + * Fixed a bug in 'rdcatch/rdcatch.cpp' that would display a + playout deck even when no valid playout deck was defined. +2014-01-07 Fred Gleason + * Fixed a bug in RDLibrary that broke double-clicking on a cart + when cart dragging was enabled in ''rdlibrary/lib_listview.cpp' + and 'rdlibrary/lib_listview.h'. +2014-01-07 Fred Gleason + * Refactored the Disk Gauge widget in RDLibrary to display the + remaining free space below the progress bar in + 'rdlibrary/disk_gauge.cpp' and 'rdlibrary/disk_gauge.h'. + * Removed 'rdlibrary/disk_bar.cpp' and 'rdlibrary/disk_bar.h'. + * Added code to force the GUI style of RDLibrary to 'WindowsStyle'. + * Added code to force the GUI style of RDAdmin to 'WindowsStyle'. + * Added code to force the GUI style of RDAirPlay to 'WindowsStyle'. + * Added code to force the GUI style of RDCartSlots to 'WindowsStyle'. + * Added code to force the GUI style of RDCastManager to 'WindowsStyle'. + * Added code to force the GUI style of RDCatch to 'WindowsStyle'. + * Added code to force the GUI style of RDLogEdit to 'WindowsStyle'. + * Added code to force the GUI style of RDLogin to 'WindowsStyle'. + * Added code to force the GUI style of RDLogManager to 'WindowsStyle'. + * Added code to force the GUI style of RDPanel to 'WindowsStyle'. + * Added code to force the GUI style of RDSelect to 'WindowsStyle'. + * Added code to force the GUI style of RDAlsaConfig to 'WindowsStyle'. + * Added code to force the GUI style of RDChunk to 'WindowsStyle'. + * Added code to force the GUI style of RDDGImport to 'WindowsStyle'. + * Added code to force the GUI style of RDDiscImport to 'WindowsStyle'. + * Added code to force the GUI style of RDGpiMon to 'WindowsStyle'. + * Added code to force the GUI style of RDHPIInfo to 'WindowsStyle'. + * Added code to force the GUI style of RDPopup to 'WindowsStyle'. + * Added code to force the GUI style of RDSoftKeys to 'WindowsStyle'. + * Added code to force the GUI style of RMLSend to 'WindowsStyle'. +2014-01-08 Fred Gleason + * Fixed a bug in 'rdlogedit/edit_log.cpp' that caused the log list + to scroll to the top of the log when a cart was dropped onto the + end of the log. +2014-01-08 Fred Gleason + * Added an 'RDLOGEDIT.ENABLE_SECOND_START' field to the database. + * Incremented the database verison to 226. + * Added 'RDLogeditConf::enableSecondStart()' and + 'RDLogeditConf::setEnableSecondStart()' methods in + 'lib/rdlogedit_conf.cpp' and 'lib/rdlogedit_conf.h'. + * Added an 'Enable 2nd Start Button' control to the Edit RDLogEdit + dialog in 'rdadmin/edit_rdlogedit.cpp' and 'rdadmin/edit_rdlogedit.h'. + * Implemented three-button voice tracking in + 'rdlogedit/voice_tracker.cpp' and 'rdlogedit/voice_tracker.h'. +2014-01-08 Fred Gleason + * Added a 'TYPE_IDX' index to the 'LOGS' table. + * Incremented the database version to 227. + * Implemented RDLogEdit log searching by Service and Filter in + 'rdlogedit/rdlogedit.cpp' and 'rdlogedit/rdlogedit.h'. +2014-01-08 Fred Gleason + * Added an 'RDLIBRARY.LIMIT_SEARCH' field to the database. + * Added an 'RDLIBRARY.SEARCH_LIMITED' field to the database. + * Incremented the database version to 228. + * Added 'RDLibraryConf::limitSearch()', + 'RDLibraryConf::setLimitSearch()', 'RDLibrary::searchLimited()' and + 'RDLibrary::setSearchLimited()' methods in 'lib/rdlibrary_conf.cpp' + and 'lib/rdlibrary_conf.h'. + * Added a 'Limit Searches at Start' control to the Library + Configuration dialog in 'rdadmin/edit_rdlibrary.cpp' and + 'rdadmin/edit_rdlibrary.h'. + * Added code to set default state of the RDLibrary 'Limit Searches...' + control in 'rdlibrary/rdlibrary.cpp' and 'rdlibrry/rdlibrary.h'. +2014-01-08 Fred Gleason + * Fixed a bug in the RDLibrary Record/Info dialog that caused a + warning to be issued when saving an everegreen cut with an expired + end date. +2014-01-09 Fred Gleason + * Tweaked the behavior of the Full Log widget in RDAirPlay so that + it scrolls to display the End of Log marker after a cart is dropped + onto the end of the log. +2014-01-09 Fred Gleason + * Added a '--profile-ripping' option to RDLibrary. + * Disabled CDDA lookups in 'lib/rdcddb_lookup.cpp'. +2014-01-10 Fred Gleason + * Added a 'SERVICES.DESCRIPTION_TEMPLATE' field to the database. + * Incremented the database version to 229. + * Added 'RDSvc::descriptionTemplate()' and + 'RDSvc::setDescriptionTemplate()' methods in 'lib/rdsvc.cpp' and + 'lib/rdsvc.h'. + * Added a 'Description Template' field to the Edit Service dialog + in 'rdadmin/edit_service.cpp' and 'rdadmin/edit_service.h'. + * Implemented description templates in 'lib/rdsvc.cpp'. +2014-01-10 Fred Gleason + * Added code to clone the description template when creating a new + service based on an existing service. +2014-01-10 Fred Gleason + * Added the cart title to the log generation exception report in + 'lib/rdlog_event.cpp'. +2014-01-10 Fred Gleason + * Refactored code in 'lib/rdcdrom.cpp', 'lib/rdcdrom.h', + 'rdlibrary/cdripper.cpp' and 'rdlibrary/cdripper.h' to make disc + ejection work properly. +2014-01-10 Fred Gleason + * Made the List Clocks dialog in RDLogManger resizable in + 'rdlogmanager/list_clocks.cpp' and 'rdlogmanager/list_clocks.h'. + * Made the List Events dialog in RDLogManger resizable in + 'rdlogmanager/list_events.cpp' and 'rdlogmanager/list_events.h'. +2014-01-10 Fred Gleason + * Fixed a bug in 'rdlogedit/edit_log.cpp' that caused the event + list to scroll to the top of the log when dropping a cart onto it. +2014-01-10 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that threw a SQL error + when generating a log with music scheduler events. +2014-01-10 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that caused invalid + external start time data to be generated by the music scheduler + subsystem. +2014-01-13 Fred Gleason + * Fixed a bug in 'rdairplay/nownext.cpp' that caused cruft to be + appended to the log name when sending PAD updates. +2014-01-13 Fred Gleason + * Added an 'EVENT_LENGTH' field to the log database schema. + * Incremented the database version to 230. + * Added a 'RDLog::tableName()' method in 'lib/rdlog.cpp' and + 'lib/rdlog.h'. + * Added a 'RDEvent::preimportTableName()' and + 'RDEvent::postimportTableName()' methods in 'lib/rdevent.cpp' and + 'lib/rdevent.h'. + * Added 'RDLogLine::eventLength()' and 'RDLogLine::setEventLength()' + methods in 'lib/rdlog_line.cpp' and 'lib/rdlog_line.h'. + * Modified 'rdairplay/rlmhost.cpp' to use the length of the + parent RDLogManager event when sending PAD updates for macro + carts. +2014-01-13 Fred Gleason + * Corrected a typo in schema update 225 that set an invalid + metadata wildcard for the description template. +2014-01-13 Fred Gleason + * Added a 'CART.USE_EVENT_LENGTH' field to the database. + * Incremented the database version to 231. + * Added 'RDCart::useEventLength()' and 'RDCart::setUseEventLength()' + methods in 'lib/rdcart.cpp' and 'lib/rdcart.h'. + * Added a 'Use Event Length for Now & Next Updates' control to the + Edit Cart dialog in 'rdlibrary/edit_cart.cpp' and + 'rdlibrary/edit_cart.h'. +2014-01-13 Fred Gleason + * Applied updated Spanish [es] translations from Luigino Bracci + . +2014-01-14 Fred Gleason + * Fixed a bug in 'rdlibrary/edit_cart.cpp' that broke editing of the + 'Conductor' and 'SongID' fields when editing multiple carts. +2014-01-14 Fred Gleason + * Added an 'RDCddbLookup::readIsrc()' method in 'lib/rdcddb_lookup.cpp' + and 'lib/rdcddb_lookup.h'. + * Refactored ISRC lookup in RDLibrary's Single Track Ripper to + optimize performance in 'rdlibrary/cdripper.cpp' and + 'rdlibrary/cdripper.h'. + * Refactored ISRC lookup in RDLibrary's Full Disc Ripper to + optimize performance in 'rdlibrary/disk_ripper.cpp' and + 'rdlibrary/disk_ripper.h'. +2014-01-14 Fred Gleason + * Made RDLibrary's Single Track Ripper resizable in + 'rdlibrary/cdripper.cpp' and 'rdlibrary/cdripper.h'. +2014-01-15 Fred Gleason + * Added an 'RDWaveFile::Aiff' value to the 'RDWaveFile::Type' enum + in 'lib/rdwavefile.h'. + * Added support for AIFF files in 'lib/rdwavefile.cpp' and + 'lib/rdwavefile.h'. +2014-01-15 Fred Gleason + * Fixed a bug in 'rdlog_edit.cpp' that caused tracks to be created + that would not visualize correctly when using a system sample rate + of other than 44100. +2014-01-15 Fred Gleason + * Added an rdmarkerset(8) utility in 'utils/rdmarkerset/'. +2014-01-17 Fred Gleason + * Updated 'NEWS'. + * Updated the package version to 2.7.0. +2014-01-20 Fred Gleason + * Modified drag-and-drop subsystem so that customized button titles + are preserved when dragging between buttons. +2014-01-20 Fred Gleason + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' that caused a segfault + when starting with 'Limit Search Results' in RDAdmin set to 'No'. +2014-01-21 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that set an incorrect value + for the default 'Description' field wildcard. +2014-01-21 Fred Gleason + * Implemented a 'ProcessNullUpdates=' directive in the 'rlm_udp' RLM + in 'rlm/rlm_udp.c'. + * Implemented a 'ProcessNullUpdates=' directive in the 'rlm_serial' RLM + in 'rlm/rlm_serial.c'. +2014-01-21 Fred Gleason + * Fixed a bug in 'rdlibrary/rdlibrary.cpp' and 'rdlibrary/rdlibrary.h' + that threw a segfault when changing the Rivendell user while editing + a cart. +2014-01-21 Fred Gleason + * Fixed a regression in 'rdlibrary/edit_cart.cpp' that failed to + clear previous cut selections after adding a new cut entry. +2014-01-21 Fred Gleason + * Added a confirmation dialog to the 'Change All' operation in + the Edit Grid dialog in 'rdlogmanager/edit_grid.cpp'. +2014-01-21 Fred Gleason + * Reverted code to force GUI style to 'WindowsStyle'. +2014-01-21 Fred Gleason + * Fixed a bug in 'lib/rdlog_event.cpp' that failed to take segue + overlaps into account properly when caluculating log lengths. +2014-02-06 Fred Gleason + * Added 'Album' and 'Label' fields to the RDLibrary cart list in + 'rdlibrary/rdlibrary.cpp'. +2014-02-06 Fred Gleason + * Renamed the 'Label' field in RDAirPlay's Full Log widget to + 'Marker' in 'rdairplay/list_log.cpp'. + * Added 'Album' and 'Label' fields to RDAirPlay's Full Log widget + 'rdairplay/list_log.cpp'. +2014-02-06 Fred Gleason + * Added 'STATIONS.ENABLE_DRAGDROP' and 'STATIONS.ENFORCE_PANEL_SETUP' + fields to the database. + * Incremented the database version to 232. + * Added 'RDStation::enableDragdrop()', 'RDStation::setEnableDragdrop()', + 'RDStation::enforcePanelSetup()' and 'RDStation::setEnforcePanelSetup()' + in 'lib/rdstation.cpp' and 'lib/rdstation.h'. + * Added 'Enable Drag & Drop' and 'Allow Drops on Panels not in + Setup Mode' control to the Edit Host dialog in + 'rdadmin/edit_station.cpp' and 'rdadmin/edit_station.h'. +2014-02-07 Fred Gleason + * Fixed a typo in 'rdairplay/list_log.cpp' that caused log listings + to be in incorrect order. +2014-02-07 Fred Gleason + * Fixed a regression in 'rdlibrary/rdlibrary.cpp' that caused + all macro carts to be displayed as invalid. +2014-02-07 Fred Gleason + * Fixed a bug in 'lib/rdcartslot.cpp' that caused carts containing + cuts of differing lengths to be timescaled even when forced length + was not enabled for the cart. +2014-02-07 Fred Gleason + * Rearranged the layout of the Edit RDAirPlay dialog in + 'rdadmin/edit_rdairplay.conf'. +2014-02-10 Fred Gleason + * Added an 'RDAIRPLAY.LOG_MODE_STYLE' field to the database. + * Added a 'LOG_MODES' table to the database. + * Incremented the database version to 233. + * Added a 'Mode Control Style' control to the Edit RDAirPlay + dialog in 'rdadmin/edit_rdairplay.cpp' and 'rdadmin/edit_rdairplay.h'. + * Replaced the 'Startup Mode' control with individual controls for + each log machine on the Edit RDAirPlay dialog in + 'rdadmin/edit_rdairplay.cpp' and 'rdadmin/edit_rdairplay.h'. + * Implemented independent log mode style for RDAirPlay in + 'rdairplay/rdairplay.cpp', rdairplay/rdairplay.h', + 'rdairplay/mode_display.cpp' and 'rdairplay/mode_display.h'. +2014-02-10 Fred Gleason + * Added a signal handler for SIGTERM and SIGINT to rdmonitor(1) + in 'rdmonitor/rdmonitor.cpp'. +2014-02-11 Fred Gleason + * Added 'STATIONS.CUE_START_CART' and 'STATIONS.CUE_STOP_CART' + fields to the database. + * Incremented the database version to 234. + * Added 'RDStation::cueStartCart()', 'RDStation::setCueStartCart()', + 'RDStation::cueStopCart()' and 'RDStation::setCueStopCart()' + methods in 'lib/rdstation.cpp' and 'lib/rdstation.h'. + * Added 'Start Cart' and 'Stop Cart' controls to the Edit Host + dialog in 'rdadmin/edit_station.cpp' and 'rdadmin/edit_station.h'. + * Removed redundant arguments from the constructor of the + Cart Dialog in 'lib/rdcart_dialog.cpp' and 'lib/rdcart_dialog.h'. + * Changed the behavior of RDLogEdit's cue output so as to follow + the cue settings in the Edit Host dialog in RDAdmin. + * Hid the 'Audition/Cue' controls in the Edit RDAirPlay dialog + in 'rdadmin/edit_rdairplay.cpp' and 'rdadmin/edit_rdairplay.h'. +2014-02-14 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.8.0. +2014-02-16 Fred Gleason + * Added an 'RDMatrix::BtSentinel4Web' value to the 'RDMatrix::Type' + enum in 'lib/rdmatrix.cpp' and 'lib/rdmatrix.h'. + * Added a driver for the Broadcast Tools Sentinel 4 Web AES switcher in + 'ripcd/btsentinel4web.cpp' and 'ripcd/btsentinel4web.h'. +2014-02-18 Fred Gleason + * Fixed a regression in 'rdairplay/lib_listview.cpp' that caused + dropped carts to appear in the wrong location in a log. +2014-02-19 Fred Gleason + * Fixed a bug in 'rdlogedit/edit_log.cpp' that caused the log + to reposition after dropping a cart onto it. +2014-02-19 Fred Gleason + * Fixed a regression in 'rdlibrary/edit_cart.cpp that broke + multi-cart editing. +2014-02-19 Fred Gleason + * Fixed a bug in RDAirPlay's Full Log widget that caused columns + to be misaligned in 'rdairplay/list_log.cpp'. +2014-02-20 Fred Gleason + * Fixed a bug in RDLogEdit's Edit Log screen that failed to process + empty cart drops properly +2014-02-20 Fred Gleason + * Implemented dynamic updating for SoundPanel buttons in + 'lib/rdsound_panel.cpp' and 'lib/rdsound_panel.h'. +2014-02-20 Fred Gleason + * Added 'Recue' button to the Edit Event dialog in + 'rdairplay/edit_event.cpp' and 'rdairplay/edit_event.h'. +2014-02-26 Fred Gleason + * Fixed a bug in 'lib/rdwavefile.cpp' that caused a zero length + to be calculated for MPEG WAV files with a null FACT chunk. +2014-02-26 Fred Gleason + * Cleaned up title display in verbose output from rdimport(1) + in 'utils/rdimport/rdimport.cpp'. +2014-02-28 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.8.1. +2014-03-01 Fred Gleason + * Applied a fix from Brian McGlynn that fixed + a bug in the BroadcastTools SS4.4 driver tht prevented outputs 3 + and 4 from being addressed. +2014-03-01 Fred Gleason + * Applied a fix from Max Goldstein that fixed a + logging bug in RDAirPlay in 'rdiaplay/rdairplay.cpp'. +2014-03-05 Fred Gleason + * Fixed a bug in 'rdadmin/edit_station.cpp' where the Cue Output + audio assignment did not take account of the 'Core Audio Engine' + settings. +2014-03-19 Fred Gleason + * Fixed a bug in 'rdairplay/rlmhost.cpp' that caused RDAirPlay to + segfault when processing multi-byte UTF8 characters. +2014-03-19 Fred Gleason + * Removed (const char *) casts from SQL calls in + 'rdlibrary/rdlibrary.cpp'. + * Removed (const char *) casts from SQL calls in + 'rdlibrary/audio_cart.cpp'. + * Removed (const char *) casts from SQL calls in + 'rdlibrary/disk_ripper.cpp'. + * Removed (const char *) casts from SQL calls in + 'rdlibrary/edit_cart.cpp'. + * Removed (const char *) casts from SQL calls in + 'rdlibrary/list_reports.cpp'. +2014-03-19 Fred Gleason + * Refactored SQL insert in 'rdairplay/log_traffic.cpp' to support + UTF8 characters. + * Refactored SQL insert in 'lib/rdsound_panel.cpp' to support + UTF8 characters. + * Removed (const char *) casts from SQL calls in + 'lib/rdsound_panel.cpp'. +2014-03-21 Fred Gleason + * Regressed UTF8 processing in 'RDSoundPanel::LoadPanel()' to + preserve compatibility with latin1 coding in MySQL in + 'lib/rdsound_panel.cpp'. +2014-05-15 Fred Gleason + * Applied a patch from Chris Smowton to + 'lib/rdaudioconvert.cpp' to fix a buffer overflow bug. +2014-05-16 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.8.2. +2014-05-19 Fred Gleason + * Removed the RDValidator from the 'Title' field in + 'lib/rdadd_cart.cpp'. +2014-05-19 Fred Gleason + * Added 'RDLogLine::cartNotes()' and 'RDLogLine::setCartNotes()' + methods to 'lib/rdlog_line.cpp' and 'lib/rdlog_line.h'. + * Added a 'Cart Notes' control to the 'Edit Event' dialog in + 'rdairplay/edit_event.cpp' anbd 'rdairplay/edit_event.h'. +2014-05-20 Fred Gleason + * Added an 'RDLog::exists()' method in 'lib/rdlog.cpp' and + 'lib/rdlog.h'. + * Implemented a '-P' switch for rdlogmanager(1) in + 'rdlogmanager/commandline_ops.cpp', 'rdlogmanager/rdlogmanager.cpp' + and 'rdlogmanager/rdlogmanager.h'. +2014-05-20 Fred Gleason + * Added code in 'rdlibrary/lib_listview.cpp' to include the group + color when dragging a cart. +2014-05-20 Fred Gleason + * Increased the maximum output string size in 'rlm/rlm_filewrite.c' + to 8192. +2014-05-20 Fred Gleason + * Changed the 'Artist' and 'Album' controls in 'rdlibrary/cdripper.cpp' + to enable editing. +2014-05-20 Fred Gleason + * Changed the 'Artist' and 'Album' controls in + 'rdlibrary/disk_ripper.cpp' to enable editing. +2014-05-20 Fred Gleason + * Added 'Album' and 'Label' columns to the log display in the + Voice Tracker interface in 'rdlogedit/voice_tracker.cpp'. +2014-05-20 Fred Gleason + * Changed the font size of the 'Cart Notes' field in the Edit Event + dialog to 14 point in 'rdairplay/edit_event.cpp'. +2014-05-20 Fred Gleason + * Added an 'RDReport::MusicClassical' to the 'RDReport::ExportFilter' + enumeration in 'lib/rdreport.cpp' and 'lib/rdreport.h'. + * Implemented a 'Classical Music Playout' report in + 'lib/export_musicclassical.cpp'. + * Added 'CONDUCTOR', 'SONG_ID', 'USER_DEFINED' fields to the service + reconciliation tables. + * Incremented the database schema to 236. + * Added support for new ELR table fields in 'rdairplay/log_traffic.cpp'. + * Added support for new ELR table fields in 'lib/rdsound_panel.cpp'. + * Added support for new ELR table fields in 'lib/rdcartslot.cpp'. +2014-05-20 Fred Gleason + * Fixed a bug in 'lib/rdevent_line.cpp' that broke the music scheduler + when working with services with non-escaped characters in the name. +2014-05-20 Fred Gleason + * Added 'RDCart::schedCodesList()', 'RDCart::setSchedCodesList()' + and 'RDCart::addSchedCode()' methods in 'lib/rdcart.cpp' and + 'lib/rdcart.h'. + * Implemented a '--add-scheduler-code=' switch for RDImport(1) in + 'utils/rdimport/rdimport.cpp' and 'utils/rdimport/rdimport.h'. +2014-05-21 Fred Gleason + * Added an 'RDIdValidator' class in 'lib/rdidvalidator.cpp' and + 'lib/rdidvalidator.h'. + * Fixed a bug in 'rdlogedit/edit_log.cpp', 'rdlogedit/rdlogedit.cpp', + 'rdlogedit/voice_tracker.cpp', 'rdairplay/list_log.cpp, + 'rdairplay/local_macros.cpp' and 'rdairplay/log_play.cpp' where log + names containing spaces were incorrectly processed. +2014-05-21 Fred Gleason + * Cleaned up SQL calls to '_LOG' tables in 'lib/rdsvc.cpp' and + 'lib/rdlog.cpp'. + * Added code to strip extraneous whitespace from log names in + 'rdadmin/edit_svc.cpp' and 'lib/rdadd_log.cpp'. +2014-05-21 Fred Gleason + * Added 'REPORTS.START_TIME' and 'REPORTS.END_TIME' fields to + the database. + * Incremented the database schema to 237. + * Added 'RDReport::startTime()', 'RDReport::setStartTime()', + 'RDReport::endTime()' and 'RDReport::setEndTime()' methods in + 'lib/rdreport.cpp' and 'lib/rdreport.h'. + * Added a 'Filter by Daypart' section to the Edit Report dialog + in 'rdadmin/edit_report.cpp' and 'rdadmin/edit_report.h'. +2014-05-21 Fred Gleason + * Added a 'Validity::FutureValid' value to the 'RDCart::Validity' + enumeration in 'lib/rdcart.cpp' and 'lib/rdcart.h'. + * Added a 'Validity::FutureValid' value to the 'RDCut::Validity' + enumeration in 'lib/rdcut.cpp' and 'lib/rdcut.h'. + * Added an 'RD_CART_FUTURE_COLOR' define in 'lib.rd.h'. + * Implemented future validity indication in 'rdlibrary/audio_cart.cpp' + and 'rdlibrary/rdlibrary.cpp'. +2014-05-21 Fred Gleason + * Implemented future validity indication in 'lib/rdlog_line.cpp' + and 'rdlogedit/edit_log.cpp'. +2014-05-21 Fred Gleason + * Added the 'Append Log' ['AL'] RML in 'lib/rdmacro.cpp' and + 'lib/rdmacro.h'. + * Added an 'RDLogEvent::append()' method in 'lib/rdlog_event.cpp' + and 'lib/rdlog_event.h'. + * Added a 'LogPlay::append()' method in 'rdairplay/log_play.cpp' + and 'rdairplay/log_play.h'. +2014-05-27 Fred Gleason + * Refactored the Full Disc Ripper in 'rdlibrary/disk_ripper.cpp' + and 'rdlibrary/disc_ripper.h' to allow ripping from multiple + tracks to single/multiple cuts. +2014-05-28 Fred Gleason + * Added an 'Edit Cart Label' dialog in 'lib/rdwavedata_dialog.cpp' + and 'lib/rdwavedata_dialog.h'. + * Added 'RDWaveData::usageCode()', 'RDWaveData::setUsageCode()', + 'RDWaveData::schedCodes()' and 'RDWaveData::setSchedCodes()' methods + in 'lib/rdwavedata.cpp' and 'lib/rdwavedata.h'. + * Added an 'Edit Scheduler Codes' dialog in + 'lib/rdschedcodes_dialog.cpp' and 'lib/rdschedcodes.h'. +2014-05-29 Fred Gleason + * Added 'CART.PENDING_STATION', CART.PENDING_DATETIME and + 'CART.PENDING_PID' fields to the database. + * Incremented the database version to 238. + * Added 'RDCart::setPending()' and 'RDCart::clearPending()' + methods in 'lib/rdcart.cpp' and 'lib/rdcart.h'. + * Added a 'RDGroup::reserveCarts()' method in 'lib/rdgroups.cpp' + and 'lib/rdgroup.h'. + * Added a 'reserve_carts_test(1)' test harness in 'tests/'. +2014-06-02 Fred Gleason + * Fixed a bug in 'lib/rdsvc.cpp' that caused purge dates to + be calculated on the basis of log creation date rather than air + date when generating logs. +2014-06-02 Fred Gleason + * Fixed a bug in 'lib/rdgroup.cpp' that caused abandoned ripper + carts to remain after closing the Rip Disk dialog. +2014-06-02 Fred Gleason + * Added a check for stale reserved carts in + 'utils/rddbcheck/rddbcheck.cpp' and 'utils/rddbcheck/rddbcheck.h'. +2014-06-02 Fred Gleason + * Fixed a bug in 'rdlibrary/disk_ripper.cpp' to failed to disable + the 'Modify Cart Label' and 'Clear Selection' button when ripping + as disk.. +2014-06-02 Fred Gleason + * Fixed a bug in 'rdlogmanager/clock_listview.cpp' that caused + the right-click menu to appear in the wrong location when the + underlying event list was scrolled down. +2014-06-02 Fred Gleason + * Fixed a bug in 'lib/rdcart.cpp' that broke the build under + Windows. + * Fixed a bug in 'lib/lib.pro' that broke the build under Windows. +2014-06-03 Fred Gleason + * Added a 'DROPBOX_SCHED_CODES' table to the database. + * Incremented the database version to 239. + * Added a 'Scheduler Codes' button to the Edit Dropbox dialog + in 'rdadmin/edit_dropbox.cpp'. +2014-06-04 Fred Gleason + * Updated 'NEWS'. + * Incremented the package version to 2.9.0. +2014-06-05 Fred Gleason + * Fixed a bug in 'rdadmin/createdb.cpp' that caused logs with + '-' in their names to be incorrectly updated. +2014-06-24 Fred Gleason + * Fixed a bug in 'lib/rdport.cpp' that caused reports with + '-' in their hostnames to be incorrectly generated. + * Fixed a bug in 'rdairplay/log_traffic.cpp' that caused ELR data + to be incorrect recorded on systems with '-' in their hostnames. + * Removed the 'RDEscapeStringSQLColumn()' function from + 'lib/rdescape_string.cpp' and 'lib/rdescape_string.h'. +2014-07-14 Fred Gleason + * Added a '--cart-number-offset=' switch to RDImport(1) in + 'utils/rdimport/rdimport.cpp' and 'utils/rdimport/rdimport.h'. + * Extended Scott Studios import support to detect cart numbers + in the SCOT chunk in 'lib/rdwavefile.cpp'. +2014-07-14 Fred Gleason + * Added a '--set-daypart-times' switch to RDImport(1) in + 'utils/rdimport/rdimport.cpp' and 'utils/rdimport/rdimport.h'. +2014-07-15 Fred Gleason + * Extended Scott Studios import support to detect segue marker + data in the SCOT chunk in 'lib/rdwavefile.cpp'. +2014-07-15 Fred Gleason + * Added 'RDWaveData::daypartStartTime()', + 'RDWaveData:setDaypartStartTime()', 'RDWaveData::daypartEndTime()' + and 'RDWaveData::setDaypartEndTime()' methods in 'lib/rdwavdata.cpp' + and 'lib/rdwavedata.h'. diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..b6e4ba0e --- /dev/null +++ b/INSTALL @@ -0,0 +1,185 @@ +This is the installation file for the Rivendell package. + +MANDATORY PREREQUISITES +You will need the following installed and configured properly on your +system before building Rivendell: + +Apache Web Server +Included with most distros, or available from: http://www.apache.org/. + +Cdda2Wav +A CD ripper engine. Included in most distributions, but also available from +http://www.cdda2wav.de/. + +ID3Lib +An audio metadata tag library. Included in most distros, or available at +http://id3lib.sourceforge.net/. + +LibCurl, v7.19.0 or later +A client-side URL transfer library. Included with most distros, or +available at: http://curl.haxx.se/libcurl/. + +LibParanoia +A library for ripping audio CDs. Included in most distributions, but also +available from http://www.xiph.org/paranoia/. + +LibSndFile +An audio file support library, written by Erik de Castro Lopo. Included with +most distros, or you can find it at http://www.mega-nerd.com/libsndfile/. + +mySQL Database Server +Included in most Linux distributions. See http://www.mysql.com/. + +PAM Pluggable Authentication Modules +A suite of shared libraries that enable the local system administrator to +choose how applications authenticate users. Included with virtually all modern +distros, or see http://www.kernel.org/pub/linux/libs/pam/. + +OggVorbis - Open Source Audio Coding Library. Needed for OggVorbis +importing and exporting. Included with most distros, or available at: +http://www.xiph.org/. + +Qt Toolkit, v3.3 or better +Most modern Linux distros include this. It's typically installed as part +of the KDE Desktop Environment, although KDE is by no means required. +It can also be downloaded directly from TrollTech (http://www.trolltech.com/). + +Secret Rabbit Code +A sample-rate converter library, written by Erik de Castro Lopo. Included +with most distros, or you can find it at http://www.mega-nerd.com/SRC/. + +SoundTouch Audio Processing Library +A library for altering the pitch and/or tempo of digital audio data. +Available at http://www.surina.net/soundtouch/. + +X11 Window System +Virtually all Linux distros should include this. + + +OPTIONAL PREREQUISITES +The following components are optional, but needed at build- and run- time in +order for particular features to work: + +One or more audio driver libraries. Choices are: + + AudioScience HPI Driver - v3.00 or greater. + For supporting AudioScience's line of high-end professional audio adapters. + See http://www.audioscience.com/. + + The JACK Audio Connection Kit + A low latency audio server, designed from the ground up for + professional audio work. See http://jackit.sourceforge.net/. + Further information on running Rivendell with the JACK driver can be + found in 'docs/JACK.txt'. + + The Advanced Linux Sound Architecture (ALSA) v1.0 or greater. + The standard soundcard driver for Linux for kernels 2.6.x or later. + See http://www.alsa-project.org/. + +Free Lossless Audio Codec (FLAC), v1.2.x or greater +A "lossless" audio encoding library. Included with most distros, or +available from: http://flac.sourceforge.net/. + +GPIO Driver +A kernel driver for the line of data-acquisition boards from +MeasurementComputing. See http://www.rivendellaudio.org/. + +LAME - MPEG Layer 3 Encoder Library. Needed for MPEG Layer 3 exporting. +Available at http://lame.sourceforge.net/. + +MAD - MPEG Audio Decoder Library. Needed for MPEG importing and playout. +Available at http://www.underbit.com/products/mad/. + +TwoLAME - MPEG Layer 2 Encoder Library. Needed for MPEG Layer 2 exporting and +capture. Available at http://www.twolame.org/. + + +INSTALLATION +There are three major steps to getting a Rivendell system up and +running. They are: + +1) Setting up pre-requisite software + +2) Installing the Rivendell package + +3) Initial configuration + + +1) Setting Up Prerequisites + +The major prerequisite piece of software needed for a functioning +Rivendell system is the mySQL database engine. This needs to +be accessible from the target system (either by running on the local +host, or on a remote system) before Rivendell installation proper +is commenced. In practice, this means that the 'mysqld' daemon is +running and can be connected to using the mysql(1) client. You will +also need a login name/password for an account on the server with +administrative rights. + +The process of configuring mySQL on a given host can be intricate and +is generally beyond the scope of this document. Details can be found +in a number of books on the subject, as well as in the very extensive +documentation that accompanies the server itself. + +If GPIO support is desired, this is also the time to install and test +the kernel GPIO driver. Full installation instructions as well as the +list of currently supported GPIO boards are included in the package. + + +2) Installing the Rivendell Package + +Once the prerequisites are set up, installation is most often a matter of +cd'ing to the top of the Rivendell source tree and typing +'./configure', 'make', followed (as root) by 'make install'. Those +who obtained the source via CVS will need to do './autogen.sh' first. + +The ./configure script will auto-detect what sound drivers (HPI, JACK +or ALSA) are available and enable build support accordingly. To override +this behavior, it's possible to specify '--disable-hpi', +'--disable-jack' or '--disable-alsa' as an argument to './configure'. +Be sure to see the important additional information regarding +configuration in the 'docs/JACK.txt' or 'docs/ALSA.txt' files if you +plan on using those sound driver architectures. + +Rivendell's web services components are installed in the directory specified +by the '--libexecdir=' parameter given to './configure' (default +'EPREFIX/bin'). The proper location will vary widely on different distros +according to how Apache is installed. On SuSE (assuming the default setup), +the proper invocation is '--libexecdir=/srv/www/rd-bin'. Additionally, +Apache itself must be configured to use the specified directory. The +'./configure' script generates a configuration file snippet that can be +included into the Apache configuration to accomplish this in +'conf/rd-bin.conf'. On Ubuntu copy that file to the /etc/apache2/conf.d/ +directory. + + +3) Initial Configuration + +Next, you'll need to install a small configuration file at +'/etc/rd.conf'. A sample can be found in 'conf/rd.conf-sample'. Much +of this can be used unchanged, with the exception of the entries in the +[Identity] section. These should be changed to reflect the user and group +name of the system accounts that will be running Rivendell. + +The directory for the audio sample data next needs to be created, as +so: + + mkdir /var/snd + +This directory should owned, readable, writable and searchable by the user +and group specified in the 'AudioOwner=' and 'AudioGroup=' entires in +'/etc/rd.conf' and readable and searchable by Others (mode 0775). + +Finally, it's time to start things up. Run 'rdadmin' from a shell +prompt. For the first time startup, RDAdmin will prompt for a login +name/password on the mySQL server so that it can create the Rivendell +database. To log into RDAdmin for the first time, enter a User Name of +'admin' with no password. + +Much of the work in Rivendell gets done by three daemon processes, +named 'caed', 'ripcd' and 'rdcatchd'. These daemons *must* be running +before attempting to start any of the Rivendell applications. The +order in which they are started is important, and should be the same +as the order in which they are listed above. For convienence, a Sys-V +style init script called 'rivendell' that can start, stop and restart +the daemons properly is installed in '/etc/init.d/'. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..d6b05004 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,162 @@ +## automake.am +## +## Top level automake.am for Rivendell +## +## Use automake to process this into a Makefile.in +## +## (C) Copyright 2002-2010 Fred Gleason +## +## $Id: Makefile.am,v 1.65.6.6 2013/01/14 16:35:58 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## + +if PAM_RD_AM + PAM_RD_OPT = pam_rd +endif +if HPI_RD_AM + HPI_RD_OPT = rdhpi +endif +if ALSA_RD_AM + ALSACONFIG_RD_OPT = rdalsaconfig +endif +SUBDIRS = icons\ + helpers\ + lib\ + $(HPI_RD_OPT) $(PAM_RD_OPT) rlm\ + scripts\ + conf\ + debian\ + docs\ + xdg\ + cae\ + importers\ + ios\ + rdadmin\ + rdairplay\ + rdcartslots\ + rdcastmanager\ + rdcatch\ + rdcatchd\ + rdlibrary\ + rdlogedit\ + rdlogin\ + rdlogmanager\ + rdmonitor\ + rdpanel\ + rdrepld\ + rdselect\ + ripcd\ + tests\ + utils\ + web + +install-exec-local: + ./install-init.sh $(DESTDIR)$(prefix) + +install-debian: + touch ./building-debian + make install + rm -f ./building-debian + +uninstall-exec: + rm -f /etc/init.d/rdrepld + rm -f /etc/init.d/rivendell + rm -f /etc/sysconfig/rivendell + +rpm: dist + cp rivendell-$(VERSION).tar.gz $(RPM_ROOT)/SOURCES/ + $(RPMBUILD) -ba --target $(ARCH)-$(VENDOR)-linux rivendell.spec + mv $(RPM_ROOT)/RPMS/$(ARCH)/rivendell-*.rpm $(top_srcdir)/ + mv $(RPM_ROOT)/SRPMS/rivendell-*.src.rpm $(top_srcdir)/ + rm $(RPM_ROOT)/SOURCES/rivendell-$(VERSION).tar.gz + rm -rf $(RPM_ROOT)/BUILD/rivendell-$(VERSION) + +slack: all + ./make_slack + +slax: all + rm -f rivendell-$(VERSION)-$(ARCH)-$(RPM_RELEASE).mo + ./make_slack + tgz2mo rivendell-$(VERSION)-$(ARCH)-$(RPM_RELEASE).tgz rivendell-$(VERSION)-$(ARCH)-$(RPM_RELEASE).mo + +zip: dist + tar -zxf rivendell-@VERSION@.tar.gz + zip -r rivendell-@VERSION@.zip rivendell-@VERSION@ + rm -rf rivendell-@VERSION@ + +doxygen: + cd lib && doxygen doxygen.conf + cd cae && doxygen doxygen.conf & + cd rdairplay && doxygen doxygen.conf & + cd rdadmin && doxygen doxygen.conf & + cd rdcatch && doxygen doxygen.conf & + cd rdcatchd && doxygen doxygen.conf & + cd rdlibrary && doxygen doxygen.conf & + cd rdlogedit && doxygen doxygen.conf & + cd rdlogin && doxygen doxygen.conf & + cd rdlogmanager && doxygen doxygen.conf & + cd ripcd && doxygen doxygen.conf & + +EXTRA_DIST = autogen.sh\ + build_win32.bat\ + CODINGSTYLE\ + get_distro.sh\ + get_target.sh\ + install-init.sh\ + make_slack.in\ + PACKAGE_VERSION\ + rdrepld-suse.in\ + rivendell-gentoo\ + rivendell.ism\ + rivendell.pro\ + rivendell.spec.in\ + rivendell-suse.in\ + rivendell.sys\ + slack-desc.in\ + slack_doinst.sh\ + UPGRADING + +CLEANFILES = *~\ + *.mo\ + *.rpm\ + *.tar.gz\ + *.tgz\ + *.zip + +DISTCLEANFILES = config.guess\ + config.sub\ + ltmain.sh\ + make_slack\ + rdrepld-suse\ + rivendell\ + rivendell.spec\ + slack-desc + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + Makefile.in\ + config.guess\ + config.status\ + config.sub\ + configure\ + depcomp\ + install-sh\ + libtool\ + ltmain.sh\ + missing\ + mkinstalldirs\ + rivendell.spec\ + rivendell-suse diff --git a/NEWS b/NEWS new file mode 100644 index 00000000..0f12826d --- /dev/null +++ b/NEWS @@ -0,0 +1,2743 @@ +The NEWS file for the Rivendell package. + +------------------------------------------------------------------------------- +v2.9.0 -- 6/4/2014 + +Changes: + Cart Notes Display. 'Cart Notes' information can now be displayed in + the 'Edit Events' dialog in RDAirPlay. + + RDLogManger Command Line Enhancements. A '-P' switch has been added + to prevent existing logs from being overwritten by batched jobs. + + Report Enhancements. Added a 'Classical Music' as-played report, + as well as the ability to filter all reports on the basis of daypart + range. + + New Scheduler Code Support. Added an '--add-scheduler-code=' switch + to rdimport(1) and the ability to specify a set of scheduler codes to + be added to new carts on a per-dropbox basis in + RDAdmin->ManageHosts->Dropboxes. + + RDLibrary Cart Status Highlighting. Carts whose dayparting indicates + a start time in the future are now highlighted in cyan rather than red. + + New RML. An 'Append Log' ['AL'] RML has been added. + + Full Disc Ripper Enhancements. The Full Disc Ripper ('Rip Disk' in + RDLibrary) has undergone a major overhaul, now allowing for multi-track + rips to a single cut and streamlined assignments of selected tracks to + new carts. + + Various bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 239, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.8.2 -- 5/16/2014 + +Changes: + This is a maintenance release of Rivendell. It fixes several bugs, + but provides no new functionality. Some of the fixes include: + + UTF-8 Character Handling. Improved handling of multi-byte UTF-8 + characters, especially in the RLM subsystem. + + More robust MPEG-1 import support (contributed by Chris Smowden). + + See the ChangeLog for additional details. + +Database Update: + This version of Rivendell uses database schema version 234, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.8.1 -- 2/28/2014 + +Changes: + New Switcher Device. Added support for the Broadcast Tools Sentinel4Web + AES Switcher. + + Cart Recuing. Added a 'Recue' button in RDAirPlay's Edit Event dialog + to allow fast recuing of carts that were inadvertently started. + + Various bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 234, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.8.0 -- 2/14/2014 + +Changes: + Drag and Drop Configurability. It is now possible to enable/disable + drag and drop capability on a per-host basis as well as configure cart drops + to honor the Setup mode on Sound Panels. See RDAdmin->ManageHosts to + configure. + + Metadata Fields. Added 'Album' and 'Label' to the fields + displayed in Cart List in RDLibrary and the Full Log widget in + RDAirPlay. + + Independent Log Modes. It is now possible to configure RDAirPlay so + that log modes (LiveAssist vs. Automatic vs. Manual) can be set + independently for each log machine. See RDAdmin->ManageHosts->RDAirPlay + to configure. + + Cue Channel Assignments. Channel assignments for cue output from all + modules (include that for RDAirPlay) is now configured in + 'RDAdmin->ManageHosts. + + Various bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 234, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.7.0 -- 1/17/2014 + +Changes: + Cart Label Customization. It is now possible to customize the fields + displayed in the Button Log widgets in RDAirPlay and RDCartSlots by + means of templates defined in the 'Display Settings' section of + RDAdmin->ManageHosts->RDAirPlay. + + RLM API Extensions. Added support for 'Outcue' and 'Description' fields + to the RLM API. + + 'Limit Searches' Configuration. Added the ability to specify the + state of the 'Show Only First 100 Matches' checkbox in RDLibrary at + module startup. + + Log Description Template. Added the ability to generate custom log + descriptions by means of a template specified in RDAdmin->ManageServices. + + CD Ripper Optimizations. Optimized CD ripping to work faster and + more reliably. + + Updated Spanish [es] Translation. Provided by Luigino Bracci + . + + Import Format Support. Added support for AIFF audio file imports. + + RDMarkerSet Utility. Added an rdmarkerset(8) command-line utility + to allow Start/End Library markers to be modified on a bulk basis. + + Various bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 231, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.6.2 -- 1/03/2014 + +Changes: + Fixed a bug in RDLogEdit that threw a segfault when dropping a cart + onto the end of a log. + +Database Update: + This version of Rivendell uses database schema version 224, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.6.1 -- 1/02/2014 + +Changes: + Drag and Drop. Added the ability to drag and drop carts within and + between Rivendell modules. + + Useability Tweaks. Modified UI behavior to improve ease of use for + SoundPanels and RDLibrary. See the ChangeLog for details. + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 224, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.6.0 -- 12/13/2013 + +Changes: + RDDiscImport Utility. A utility has been added for bulk importation + of material from audio CDs using external metadata. + + Audio Importation Enhancements. Added support for reading metadata + from WAV files containing 'AIR1' metadata chunks. + + NaturalLog Support. Added a log import preset and reconciliation report + for the 'NaturalLog' traffic system. + + New Library Metadata Fields. Added Library metadata fields for + 'Conductor', 'Song ID' and 'Beats per Minute'. + + New RDImport Option. Added a '--set-user-defined' option to RDImport. + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 224, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.5.5 -- 11/19/2013 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + RLM API Extension. Added new fields to the 'rlm_pad' struct to + allow plug-ins to determine actual and predicted start times for events. + + RDMonitor Enhancements. Extended RDMonitor to allow proper positioning + on multi-head displays. + + LiveWire Switcher Driver Changes. The switcher drivers for LiveWire + have been refactored into three separate drivers: + LWRP Audio - Allows switching of audio routes on LiveWire devices. + + LWRP GPIO - Allows monitoring and control of LiveWire GPIO devices + via LWRP (both virtual and direct). + + Multicast GPIO - Allows monitoring and control of LiveWire console + GPIO without the need for a virtual LWRP device. + + See 'SWITCHERS.txt' for details. + + RDSelect Enhancements. Added support for specifying CAE and RDXport + service assignments via RDSelect configurations. + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 220, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.5.4 -- 11/01/2013 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + RLM API Extension. A RLMResolveNowNextEncoded() function has been + added to the RLM API to provide efficient support for generating XML + and URL encoded data in plug-ins. + + Voice Tracker Fixes. Corrected a bug in the voice tracker that caused + peak data errors when employing MPEG encoding on voice tracks. + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 220, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.5.3 -- 10/04/2013 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + Multitrack Rip Support. It is now possible to rip multiple CD tracks + into a single cut using the single cut ripper in RDLibrary. + + RDCartSlot Enhancements. It is now possible to set custom 'one off' + Start and End cuepoints for events. + + Spinitron Integration. A 'spinitron_plus' RLM has been added that can + be used to log PAD data to the Spinitron playlist service + (http://www.spinitron.com), as well as a cart data export that can be + used to populate Spinitron MusicDB libraries. See the Spinitron + 'Automation Integration' document for details. + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 220, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.5.2 -- 07/03/2013 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + Binary Escape Codes. It is now possible to craft messages for the + 'Serial Out' ['SO'] and 'UDP Out' ['UO'] RMLs containing arbitrary + binary sequences. See the 'BINARY DATA' section of 'docs/rml.sxw' + for details. + + New Switcher Device. A switcher driver has been added for the + 360 Systems AM16 Audio Crosspoint Switcher. See 'docs/SWITCHERS.txt' + for details. + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 220, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.5.1 -- 05/22/2013 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + Mass Object Deletion. Added an rddelete(1) command-line tool to + aid in the mass deletion of carts and logs. Do rddelete --help + for more information. + + NexGen Importer. Added PKT file support to nexgen_filter(1). + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 220, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.5.0 -- 04/01/2013 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + LiveWire Virtual GPIO Driver. Added a fully native virtual GPIO + LiveWire driver for situations where the proprietary software + LiveWire/ALSA driver is not available (e.g. when using an ASI6x85 + adapter). See 'SWITCHERS.txt' for details. + + Console Channel Control. Added the capability to automate + console channel ON/OFF control bidirectionally from RDAirPlay. + (Configured in RDAdmin->ManageHosts->RDAirPlay). + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 220, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.4.0 -- 01/28/2013 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + New Translation. A Czech [CS] translation has been added by + Pavel Fric . + + New Cart/Cut Purge Option. A new option has been added in + RDAdmin->ManageGroups to allow empty carts to be automatically deleted + after purging. + + New Reports. 'NPR SoundExchange' and 'Music Playout' reports + have been added in RDAdmin->ManageReports. + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 216, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.3.0 -- 12/21/2012 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + RDCartSlots Module. A new Rivendell module has been added that is + optimized for use in busy live assist environments, along with four + new RMLs ('Load Slot' ['DL'], 'Play Slot' ['DP'], 'Stop Slot' ['DS'] + and 'Execute Breakaway' ['DX']) for automating its operation. + + RDAirPlay Enhancements. A set of buttons for quickly locating a given + hour has been added to the Full Log widget, enabled by checking the + 'Show Hour Selector' box in RDAdmin->ManageHost->RDAirPlay. + + JACK Enhancements. It is now possible to specify the command-line + used to start jackd(8) and a list of clients to start when + starting the Rivendell service. See RDAdmin->ManageHosts->JackSettings. + + Switcher/GPIO Device Support. Added support for the Sine Systems ACU-1 + switcher. See 'SWITCHERS.txt' for details. + + Cue Output Assignments. Cue output assignments for all modules + except RDAirPlay have now been consolidated into one setting in + RDAirPlay->ManageHosts. + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 213, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.2.1 -- 10/23/2012 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + RDMonitor Module. A persistent desktop applet has been added that + continuously monitors the health of the system and alerts the operator + in the event of any detected problems. See 'RDMONITOR.txt' for usage + and configuration info. + + Sage Digital ENDEC Control. A 'sage_endec_rwt.sh' script has been + added that allows a Required Weekly Test (RWT) to be executed on a + Sage Digital ENDEC via TCP/IP. See 'SAGE_ENDEC.txt' for usage and + configuration info. + + Cut Attribute Searching. The cart filter will now include the + attributes of underlying cuts when searching the library. + + RDCheckCuts Utility. An rdcheckcuts(1) command-line utility has + been added for checking the integrity of the audio store. + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 207, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.2.0 -- 8/31/2012 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + HPI Enhancements. Support for setting input modes for AudioScience + adapters has been added (requires support in the hardware as well). + + Scripting Enhancements. The rdcollect(1) script has been modified + to allow multiple source files to be used. + + Report Enhancements. It is now possible to filter data for reports + by Group membership as well as Service and Host. A new 'Music Summary' + report has also been added. + + New Traffic System Preset. A preset for 'WideOrbit Traffic' has been + added. + + New Rivendell Loadable Module. An 'rlm_padpoint' RLM has been added + that can be used to send PAD data to a PadPoint processor system. + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 207, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.1.5 -- 7/27/2012 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + This is a maintenance release of Rivendell. Some of the issues + addressed include: + + New Rivendell Loadable Module. An 'rlm_filewrite' RLM has been added + that can be used to write PAD data to filesystems. + + NexGen Import Filter. An filter for importing audio from a Prophet + NexGen system has been added. + + New RML. A 'Label Panel' ['PC'] RML has been added that allows + the text and color of SoundPanel buttons to be changed programmatically. + + Multiple System Selector. An 'RDSelect' utility has been added to + allow hosts to be easily switched between multiple database/audio + store instances [experimental]. + + Multiple bug fixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 205, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.1.4 -- 5/11/2012 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + This is a maintenance release of Rivendell. Some of the issues + addressed include: + + RDCatch XLoad Wildcards. Several new wildcards and meta-characters + have been added for specifying URLs in RDCatch, including: + $e -- Day of the month, space padded ( 1 - 12) + $E -- Day of the month, unpadded (1 - 12) + ^ -- Convert value indicated by following format character to all + uppercase. + $ -- Convert the initial character of the value indicated by the + following format character to uppercase. + A complete list of wildcards can be found in 'docs/datetime_wildcards.txt'. + + HPI Compatibility. Updated HPI subsystem to work with the latest + AudioScience driver versions (v4.10.x). + + RDLibrary Reports. Fixed a problem where generated reports would + not accurately reflect the current cart filters. + + A detailed list of all bugfixes can be found in the ChangeLog. + +Database Update: + This version of Rivendell uses database schema version 205, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.1.3 -- 2/20/2012 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + This is a maintemnance release of Rivendell. Some of the inssues + addressed include: + + Temporary File Cleanup. Fixed a bug the resulted in a failure to + removed temporary files after processing audio imports and exports. + + Audio Conversion Processing. Fixed a bug that caused audio distoration + when normalizing files with levels at or near full sample resolution. + + RDLogManager Hard Times. Fixed a bug in RDLogManager that resulted in + incorrect hard start time parameters being inserted when using sources + from the internal music scheduler. + + A detailed list of all bugfixes can be found in the ChangeLog. + +Database Update: + This version of Rivendell uses database schema version 205, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.1.2 -- 12/30/2011 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + Shoutcast RLM. Added an RLM plug-in for ShoutCast D.N.A.S. v1.x. + + Import/Export Error Handling. Reworked error handling for audio + import and export so as to provide more informative and useful + error messages. + + Spanish Translation. Updated Spanish (es) translation, provided + by Luigino Bracci. + + Various Bugfixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 205, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.1.1 -- 11/03/2011 + +Changes: + Fixed a regression that broke display of the Library in the Edit Event + dialog in RDLogManager. + +Database Update: + This version of Rivendell uses database schema version 205, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.1.0 -- 11/02/2011 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + Database Skew Detection. All Rivendell modules will now check that the + correct database schema is in use when starting up; a mismatched schema + will cause the module to abort with a 'database version mismatch' error. + While, for code debugging purposes, this check can be bypassed by adding + the '--skip-db-check' flag to the command line, its use is *strongly* + discouraged in production settings as operating with a skewed database + schema can cause severe database corruption! + + Library Filtering by Scheduler Code. It is now possible to filter + carts by scheduler code in both RDLibrary and the system-wide cart + selector dialog. + + Traffic Light Support. A preset for 'The Traffic Light' traffic system + has been added to list of available scheduler systems in + RDAdmin->ManageServices. + + Enhanced JACK Support. A 'JACK Settings' dialog has been added in + RDAdmin->ManageHosts, making it possible to specify the startup behavior + and name of the JACK server instance for Rivendell to use. Accordingly, + the old syscontrol-based method for specifying JACK startup behavior + should be considered deprecated and will be removed in a future version. + + New RMLs. Two new RMLs, 'Connect JACK Ports' ['JC'] and 'Disconnect + JACK Ports' ['JD'] have been added. Accordingly, use of the [JackSession] + section of rd.conf(5) should be considered deprecated; support for it + will be removed in a future version. + + Miscelaneous Bugfixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 205, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.0.2 -- 06/01/2011 + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Changes: + SAS USI Enhancements. Several enhancements have been added to Universal + Serial Driver for Sierra Automated Systems devices, including the ability + to process opto inputs and source state changes as GPI events. + + RDLogManager X11 Dependencies. It is now possible to run RDLogManager + in batch mode without the need for an active X11 server instance. + + RLM Changes. A new callback has been added to the RLM API to allow + for reception of data from serial devices. + + Full System Backup/Restore Scripts. Sample scripts for performing a + full Rivendell backup and restore (DB+audio) have been added. See + 'scripts/rd_backup_system.sh' and 'scripts/rd_restore_system.sh'. + + AudioScience HPI Cleanups. The HPI driver has been refactored to + eliminate use of deprecated/obsolete functions and data structures. + + RMLSend Smartphone App (Experimental). A version of the RMLSend utility + for Apple iOS has been added. + + Miscelaneous Bugfixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 202, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v2.0.1 -- 04/05/2011 + +This is the first production release of Rivendell 2.x. All changes made +since 2.0.0rc1 have involved fixes for reported bugs and improved +integration with various distributions and desktop environments. See +the ChangeLog for specifics. + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Database Update: + This version of Rivendell uses database schema version 202, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. Due to the + complexity of the schema changes required for this update, the process + may take significantly longer to execute than is commonly the case; + users are cautioned to allow for ample time operationally. +------------------------------------------------------------------------------- +v2.0.0rc1 -- 03/11/2011 + +This is the second release candidate of Rivendell 2.x. All changes made +since 2.0.0rc0 have involved fixes for reported bugs and improved +integration with various distributions and desktop environments. See +the ChangeLog for specifics. + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Database Update: + This version of Rivendell uses database schema version 202, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. Due to the + complexity of the schema changes required for this update, the process + may take significantly longer to execute than is commonly the case; + users are cautioned to allow for ample time operationally. +------------------------------------------------------------------------------- +v2.0.0rc0 -- 02/16/2011 + +This is the first release candidate of Rivendell 2.x. All changes made +since 2.0.0beta1 have involved fixes for reported bugs and improved +integration with various distributions and desktop environments. See +the ChangeLog for specifics. + +If upgrading from a v1.x version of Rivendell, be sure to read the +'UPGRADING' file before proceeding for important information. + +Database Update: + This version of Rivendell uses database schema version 202, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. Due to the + complexity of the schema changes required for this update, the process + may take significantly longer to execute than is commonly the case; + users are cautioned to allow for ample time operationally. +------------------------------------------------------------------------------- +v2.0.0beta1 -- 10/11/2010 + +This is the second BETA release of Rivendell 2.x. Some of the changes +include: + + Component Unbundling. It is now possible to run the caed(8) and rdxport + audio service components on separate hardware from that hosting the other + Rivendell components. Configured in RDAdmin->ManageHosts. + + Configurable Hotkeys. It is now possible to assign shortcut keys for + various functions in RDAirPlay on a host-by-host basis. Configured in + RDAdmin->ManageHost->RDAirPlay->ConfigureHotKeys. + + Various bugfixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 202, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. Due to the + complexity of the schema changes required for this update, the process + may take significantly longer to execute than is commonly the case; + users are cautioned to allow for ample time operationally. +------------------------------------------------------------------------------- +v2.0.0beta0 -- 08/19/2010 + +This is the initial BETA release of Rivendell 2.x. Some of the major changes +over 1.x include: + + MPEG Capture/Playout. Rivendell can now be optionally compiled to + support use of MPEG Layer 2 in the core storage library for all audio + driver families (ALSA and JACK as well as AudioScience HPI). + + Web Services Architecture. Many internal services within Rivendell are now + implemented via a web services API. Among other benefits, this approach + allows these services to be easily accessed by third-party systems by means + of the widely support HTTP protocol. + + Linux User Support. Any 'regular' user account can now access Rivendell; + gone is the concept of a single 'Rivendell User' under which all Rivendell + operations must occur. + + Replicators. Rivendell now sports a generic replication interface that can + be used to create services to transport audio and other Rivendell data + to/from external systems. + +Many other changes too numerous to list here have occurred as well; see the +ChangeLog for details. For a concise summary of changes from the point of +view of a system administator looking to upgrade an existing Rivendell 1.x +system to 2.x, see the file 'UPGRADING'. + +Database Update: + This version of Rivendell uses database schema version 199, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. Due to the + complexity of the schema changes required for this update, the process + may take significantly longer to execute than is commonly the case; + users are cautioned to allow for ample time operationally. +------------------------------------------------------------------------------- +v1.7.0 -- 02/22/2010 + +Changes: + Log Import Format Presets. Added preset import configurations in + RDAdmin->ManageServices for several third-party scheduler systems. + The following systems are supported: + CounterPoint Software + Music 1 + PowerGold + RadioTraffic.com + Rivendell Standard Import + Visual Traffic + + New AsPlayed Report Format. An ELR format for Music 1 in has been + added in RDAdmin->ManageReports. + + Log Import Scripts. It is now possible to specify an optional script to be + run at log import time before regular import processing takes place. This + can be configured in RDAdmin->ManageServices with the 'Preimport Command' + fields. These fields accept the same wildcard sequences as 'Path' fields. + + High-Resolution Timing. This version of Rivendell debuts the ability to + specify the start times and lengths of log events with 1/10 second + precision. + + New Translations. Two Norwegian translations (nn_NO and nb_NO) and a + Spanish translation (es) have been added. + +Database Update: + This version of Rivendell uses database schema version 186, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. Due to the + complexity of the schema changes required for this update, the process + may take significantly longer to execute than is commonly the case; + users are cautioned to allow for ample time operationally. +------------------------------------------------------------------------------- +v1.6.0 -- 12/17/2009 + +Changes: + New RLM Plug-in. A new plug-in for the Liquid Compass Internet encoder has + been added. + + Cart Notes. Added the ability to enter free-form text for each cart in the + Library. This text can then be displayed in a 'help bubble' when floating + the mouse cursor over the cart's entry in the Library cart list. + + Bugfixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 182, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.5.2 -- 08/25/2009 + +This is a maintenance release of Rivendell. The following issues have been +corrected: + + Fixed problems with build the Rivendell Pluggable Authentication Module + (PAM) plug-in. + + Fixed problems with hard-start events in RDAirPlay. + + Added checks in rddbcheck(8) to verify cart/cut/audio consistency. + + Fixed a regression that caused audio exports to fail when the path contained + one or more spaces. + +Database Update: + This version of Rivendell uses database schema version 179, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.5.1 -- 08/12/2009 + +Changes: + New Translation. A German-language (DE) translation has been added. + + ALSA Configuration Tool. An RDAlsaConfig application has been added that + allows ALSA device configuration to be done completely by means of a GUI + interface. + + Removed the requirement for sox(1). + + New Switcher Driver. Added a driver for the BroadcastTools SS4.4 switcher. + + New Report. Added an AsPlayed report for the RadioTraffic traffic system. + + Bugfixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 179, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.5.0 -- 07/08/2009 + +Changes: + New RLM Plug-in. A new plugin-in for the Innovonics model 713 RDS + encoder has been added. + + Podcast System Enhancements. It is now possible to post new episodes via + the remote web interface. + + Bugfixes, particularly affecting the Post Point Counter in RDAirPlay, stream + leakage issues in caed(8) and various database consistency issues in + RDLogManager. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 179, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.4.0 -- 04/10/2009 + +Changes: + Unique Cart Titles. It is now possible to configure the system (in + RDAdmin->SystemSettings) to disallow duplicate cart titles. + + RDAirPlay Full Log Controls. New controls have been added to the Full Log + widget in RDAirPlay to allow the head and tail of carts to be auditioned, as + well as a set of log runtime counters. To make these controls visible, it + is necessary to check the 'Show Extra Buttons/Counters' box in + RDAdmin->ManageHosts->RDAirPlay. + + RDCastManager Enhancements. An Podcast episode filter has been added. Also + added to the online version is the ability to audition each episode by + downloading the media file to the local system. + + Bugfixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 177, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.3.0 -- 03/18/2009 + +Changes: + Podcast System Enhancements. Support has been added to allow + interoperation with third-party podcast traffic measurement and + verification systems. It is also now possible to override the default + ordering of episodes and configure automatic redirection of feed + subscriptions. + + RDLogManager Enhancements. It is now possible to configure log import + under-/over-fill warnings even for non-autofill events. When generating + import warnings, RDLogManager will now warn if the dayparting parameters + would cause a scheduled event to be unplayable at its scheduled time. An + overall length counter has also been added for the Pre- and Post-Import + lists in the Edit Event dialog. + + New RML. A new 'Message Box' ['MB'] RML has been added that allows a + popup message to sent to any Rivendell workstation. (Be sure to see the + 'MESSAGE_BOX.txt' file for information on configuring X11 to work properly + with this feature). + + RLM Changes. An 'rlm_album' field has been added to the metadata fields + and the API version incremented to '1'. A new plugin ('rlm_ando') has been + added to allow interconnection with the Ando Media Ad Injector System. + + Bugfixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 170, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.2.2 -- 01/13/2009 + +This is a maintenance release of Rivendell. The following issues have been +corrected: + + Fixed a bug in RDAirPlay that caused a segfault when loading a log with no + SoundPanels enabled. + + Improved heiristics to detect more reliably mal-formed MPEG import files. + + Fixed a bug in RDLogManager that would generate truncated reports when the + ELR metadata contained double-quote characters. + + Fixed a bug in RDAdmin that caused backslash characters to be 'doubled' + when saved as part of a Windows report export path. + +Database Update: + This version of Rivendell uses database schema version 170, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.2.1 -- 12/29/2008 + +This is a maintenance release of Rivendell. The following issues have been +corrected: + + Several errors in handling metadata values in file imports have been + corrected, and support for detecting Ogg metadata tags added. + + Fixed a bug in RDAirPlay that could cause a segfault when loading a log + over an existing log. + +Database Update: + This version of Rivendell uses database schema version 170, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.2.0 -- 12/11/2008 + +Changes: + RDCatch Download Events. An 'Event Offset' setting has been added to + Download Events to allow date wildcards used in the URL field to be offset + by the indicated number of days. + + Hard Time Handling in Logs. The logic for processing hard start times in + logs has been changed so that a hard time event will be executed when wall + clock time matches regardless of it's place relative to other hard timed + events. + + Now & Next Changes. A new plugin architecture has been added that makes it + possible to create "Rivendell Loadable Modules" (RLMs for short) that can + be used to generate Now & Next PAD data to a wide array of external devices + and services. Runtime plugin configuration is accomplished in + RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. A set of sample + plugins is provided for transmitting data via UDP and serial ports as well + as for interfacing to 'social networking' services such as Twitter and + FaceBook. Information on writing new plugins can be found in the 'rlm.h' + header file. + + Dropbox Changes. Several new dropbox features have been added, including + the ability to configure a box not to delete source files after import + (particularly useful in conjunction with satellite-based audio delivery + services such as AMB-OS and PRSS ContentDepot). Also new is the ability to + apply an automatic date offset to any encoded Start or End Date value of + imported files. + + Automated System Management. It is now possible to configure various + objects to be automatically purged from the system after they expire. For + audio cuts, this can be configured on a group-wide basis in + RDAdmin->ManageGroups, while Logs and ELR data purging can be configured in + RDAdmin->ManageServices. + + RDLogManager Enhancements. A 'Remarks' field has been added to the Event + and Clock dialogs to provide an area for entering free-form text notes. + + GPIO Enhancements. It is now possible to configure separate and + independent macro carts to execute upon the rising and falling state of a + GPIO line. + + Username Length. The previous limit of a maximum of eight characters in a + Rivendell username has been increased to 255, thus allowing for better + integration with external authentication systems such as Active Directory. + + Bugfixes. Several bugfixes have been implemented -- see the ChangeLog for + details. + +Database Update: + This version of Rivendell uses database schema version 170, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.1.1 -- 11/11/2008 + +This is a maintenance release of Rivendell. The following issues have been +corrected: + + Fixed problems in RDLogManager with saving clocks and events with names + longer than 58 characters. + + Removed vestigal 'Overlap' transition type in RDAdmin. + + Corrected a problem in RDAdmin where certain services could not be selected + for inclusion in a report. + + Added support for the '^' metacharacter in import paths in + RDAdmin->ManageServices to allow for uppercasing of date values [see the + date(1) man page for usage]. + + Corrected log machine behavior so that a hard start time event occuring + during a previously deferred hard start event will cancel the deferred + event. + + Added logging for GPIO state transitions in the ripcd(8) log. + +Database Update: + This version of Rivendell uses database schema version 162, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.1.0 -- 10/23/2008 + +Changes: + Custom Encoders. It's now possible to configure Rivendell on a + host-by-host basis to use any command-line audio encoder (e.g. FAAC, + FFmpeg) to drive exports, uploads and podcasts. Information on setting it + up can be found in 'ENCODERS.txt'. + + GPIO Enhancements. The syntax of the 'GPI Set' [GI], 'GPO Set' [GO] + and 'GPI Enable' [GE] RMLs has been extended and the underlying system + modified to allow operation of all three commands with both GPI and GPO + devices. The old syntax is now deprecated, but still supported for + backwards compatibiity. Information on the new syntax can be found in + 'rml.sxw'. + + New Record RMLs. Two new RMLs, 'Start Record Deck' [RS] and 'Stop Record + Deck' [RR] have been added, allowing any RDCatch record deck to be + controlled via RML. Information on the new RMLs can be found in 'rml.sxw'. + + RDLogEdit Runtime Counters. Time counters have been added in the Edit Log + screen in RDLogEdit that show the predicted running time of log events from + the currently selected event to the next STOP and the end of the log, while + highlighting multiple events will display the runtime of the selected + events. + + Metadata Import Enhancements. Support has been added for importing + metadata from files generated by the BE AudioVault system (chunk type + 'av10'). + + +Database Update: + This version of Rivendell uses database schema version 162, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.0.1 -- 08/15/2008 + +Changes: + Incremented the version number to 1.0.1. + +Database Update: + This version of Rivendell uses database schema version 159, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.0.0rc6 -- 08/19/2008 + +Changes: + Fixed a problem where ripped cuts would show an incorrect length if + Autotrim was enabled. + + Fixed a problem with saving the 'Editor Command' field in + RDAdmin->ManageHosts. + + Brought the 'build slack' target for making a Slackware package up to date. + + Fixed a minor build problem when building without JACK support. + +Database Update: + This version of Rivendell uses database schema version 159, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.0.0rc5 -- 08/08/2008 + +Changes: + Fixed broken compile on gcc-4.3.x. + + Removed limitations on using various 'special' (e.g. quotation and + apostrophe) characters in database fields. + + Fixed problems with importing files with UTF-8-encoded names. + +Database Update: + This version of Rivendell uses database schema version 159, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.0.0rc4 -- 07/23/2008 + +Changes: + Fixed a bug that caused audio imports to be assigned incorrect Start and + End dates. + +Database Update: + This version of Rivendell uses database schema version 159, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.0.0rc3 -- 07/22/2008 + +Changes: + Rivendell Import Filter. An import filter for importing carts from + another Rivendell system has been added. See the 'rivendell_filter.TXT' + file for usage information. + + Bugfixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 159, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.0.0rc2 -- 07/07/2008 + +Changes: + AMB-OS AMR-100 Receiver Support. Support has been added for importing + the 'Native MP2' format files generated by the Westport Communications + AMR-100 satellite receiver used by the AMB-OS system. + + RDDbCheck Enhancements. Added a check for orphaned database tables to + RDDbCheck. + + Timescaling Fixes. A bug has been fixed that affected the precision of + timescaling parameters when applied to long-form programs. + + Temp File Cleanup. A bug has been fixed that was causing temporary files + to be left behind after manually posting audio to a podcast feed. + +Database Update: + This version of Rivendell uses database schema version 159, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v1.0.0rc1 -- 04/24/2008 + +Changes: + Skinnable Modules. It's now possible to specify a 1024x738 pixel + 'Background Image' for RDAirPlay and RDPanel in RDAdmin->ManageHosts. + + Bugfixes. See the ChangeLog for details. +------------------------------------------------------------------------------- +v1.0.0rc0 -- 04/10/2008 + +Changes: + New Switcher Device. Support has been added for the 'Quartz' line + of video routing switchers made by Evertz. See the relevant + section in 'docs/SWITCHERS.txt' for details. + + Logging Changes. A [Logs] section has been added to rd.conf(5) for + configuring event logging. Logging can now be done directly to + files (as before) or through the syslog facility. See the comments + in 'conf/rd.conf-sample' for details on setting this up. + + Overlap Transition Retired. The ability to schedule 'Overlap' + transitions in program logs has been removed. The equivalent + functionality can still be achieved by scheduling a 'Segue' + transition with the 'No Fade at Event End' attribute enabled. Any + existing overlap transitions will be automatically converted when + the database schema update is applied. + + Random Cut Rotation Retired. The ability to schedule cuts to rotate + 'randomly' within a cart has been removed, with all cut rotation now + using the original 'sequential' algorithm. + + Bugfixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 158, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v0.9.84 -- 01/03/2008 + +Changes: + Podcasting Subsystem. A major new subsystem has been added that permits + automated generation and posting of audio podcasts from RDCatch, as well as + a new RDCastManager module for manual content posting and management of + existing podcast episodes. RDCastManager is available in both Desktop and + online web-based environments. + + Axia LiveWire Support. Full switcher support for LiveWire node devices has + been added. See the relevant section in 'SWITCHERS.txt' for details. + + Backup Supervisor Support. It is now possible to configure the Logitek + vGuest driver to automatically fail over to a backup Supervisor instance in + the event of failure of the primary Supervisor. + + Cart Auditioning. It is now possible to audition audio in the cart picker + dialog before placement of the cart into a log. + + Audio Editor Integration. It is now possible to configure an external + audio editor to be send audio directly from the cart picker dialog. + + Asynchronous Library Searches. Added the ability to search the Library + asynchronously to allow efficient use with very large libraries. + + BugFixes. A major emphasis in this version of Rivendell has been in + finding and correcting known bugs. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 155, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v0.9.82 -- 09/17/2007 + +Changes: + OVERLAP Transition. A new transition type, called 'OVERLAP' has been + added. Operation is similar to that of a SEGUE, except that audio from + the finishing event is not faded out, but will play at full volumne to the + end of the event. + + Scheduler Integration Enhancements. A number of additions have been + made to allow for greater control and integration between Rivendell and + third-party scheduling tools. These include: + + Music Log Reconciliation. Additional data fields have been added to the + Music Log parser to allow for proper Electronic Log Reconciliation (ELR) + to be configured for Music as well as Traffic logs. + + It's now possible to schedule voice tracks from imported Traffic logs by + means of the 'Insert Voice Track' string setting in + RDAdmin->ManageServices. + + It's now possible to insert a Log Note from imported Music logs by means + of the 'Note Cart String' setting in RDAdmin->ManageServices. + + RDImport Options. A new '--title-from-cartchunk-cutid' switch has been + added to RDImport to allow title data to be extracted from CartChunk CutID + field of imported files. + + Dependency Changes. As of this release, the LibRadio and LibRHpi packages + are supplied 'built-in' as part of the core Rivendell distribution. Thus, + it is NO LONGER NECESSARY to install these packages separately. As part of + this process, a new utility called 'RDHPIInfo' (formerly the 'RHPIInfo + utility in LibRadio) has been added. + + Bug Fixes. A major emphasis of this release has been to fix as many known + bugs as possible. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 141, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. + +------------------------------------------------------------------------------- +v0.9.81 -- 07/13/2007 + +Changes: + Automatic Dropbox Mode. A new dialog, 'RDAdmin->ManageHosts->Dropboxes' + has been added that allows multiple dropbox import services to be easily + configured and modified. + + Integrated Music Scheduler. It is now possible to define music categories + and schedule music playouts with RDLogManager. + + RDPanel Module. A new 'RDPanel' module has been added that consists of a + 'full screen' version of the SoundPanel widget found in RDAirPlay. + Configuration is done in RDAdmin->ManageHosts->RDPanel, and is completely + independent of the configuration of the SoundPanel in RDAirPlay. + + SoundPanel Changes. Several changes in the operation of the SoundPanels + (both in RDAirPlay and RDPanel) have been made, including: + + 1) Improved Panel Navigation. Instead of traversing the set of available + panels linearly by means of left- and right-arrow buttons, the desired + panel can now be selected directly by means of a drop-down menu. + + 2) Nameable Panels. It's now possible to give each panel a user-defined + name. + + 3) Hook Mode. Playouts can be set to play either the full audio content + or just the designated hook material on a playout-by-playout basis. + + 4) Customizable Default Labels. Default button labels can be now defined + by means of wildcards in the 'Label Template' control in + RDAdmin->ManageHosts->RDAirPlay or RDAdmin->ManageHosts->RDPanel. + + Many bugfixes. See the ChangeLog for details. + +Library Versions: + This version requires that, at a minimum, libradio-0.98.0 and + librhpi-0.94.8 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + This version of Rivendell uses database schema version 139, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after upgrading to allow + any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v0.9.80 -- 03/01/2007 + +Changes: + SAS Router Support. The SAS USI driver has been enhanced so that + channel names are now automatically updated from the USI server whenever + the Rivendell daemons are started. + + RDImport Improvements. A 'metadata-pattern=' switch has been added to + RDImport that allows metadata to be read from fields within the filename of + imported files. Do 'rdimport --help' for details. + + New Metadata Format. RDImport and RDLibrary will now import metadata from + WAV files from Scott Studios systems. + + RDCatch Error Alarms. RDCatch can now be configured to generate alarms + (e.g. via e-mail or GPIO) whenever an event encounters an error. See + RDAdmin->ManageHosts->RDCatch. + + RDAirPlay Log Autoloading. RDAirPlay can now be configured to + automatically load and run specified logs at startup time. It can also + be set to automatically load and resume execution of whatever log was + playing at the time of an unexpected system shutdown (e.g. due to power + failure). See RDAdmin->ManageHosts->RDAirPlay. + + Various Bugfixes. See the ChangeLog for details. + +Database Update: + This version of Rivendell uses database schema version 130, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. +------------------------------------------------------------------------------- +v0.9.79 -- 12/05/2006 + +Changes: + Pausing SoundPanel Buttons -- It is now possible to configure + RDAirPlay so that touching a playing SoundPanel button causes the + playout to pause rather than stop. This is enabled by checking the + 'Enable Button Pausing' checkbox in + RDAdmin->ManageHosts->RDAirPlay. + + Bugfixes -- Fixed a database schema problem that was causing Pre- + and Post-Import lists in RDLogManager to appear empty when editing + events. + +See the ChangeLog for further details. + +Library Versions: + This version requires that, at a minimum, libradio-0.97.4 and + librhpi-0.94.7 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + This version of Rivendell uses database schema version 128, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.77 -- 12/01/2006 + +This is a bugfix version of Rivendell. Issues addressed include the +following: + Broken PLAY Transitions -- Fixes random hangs and log stopdowns + between events with PLAY transition type. + + Audio Importation Issues -- Fixes various issues with autotrimming + and level normalization. + + RDLogManager Timed-Start Attributes -- Fixes a problem where an + event would fail receive a Hard Time 'Start Immediately' attribute + if the Pre-Import Carts list was empty. + +See the ChangeLog for further details. + +Library Versions: + This version requires that, at a minimum, libradio-0.97.4 and + librhpi-0.94.7 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + This version of Rivendell uses database schema version 126, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.76 -- 11/27/2006 + +Changes: + New/Extended RMLs -- A new 'Toggle On Air Flag' [TA] RML has been + added that toggles the 'On Air Mode' of RDAirPlay. A new argument + added to the 'Start Next' [PN] RML allows log meta-events to be + automatically skipped (useful primarily when integrating with mixer + surfaces in Manual or LiveAssist modes). + + Log Refreshing -- It is now possible to 'refresh' a log while + playing out, thus preserving the view of what has already been + played in the Full Log widget while still loading updated log + elements. Such refreshing can be done either manually or + configured on either a log-by-log or service-by-service basis to + happen automatically whenever log updates are saved to the database. + + New AsPlayed Reports -- A 'Technical Report' has been added that + captures extended playout information from RDAirPlay (such as the + cause of an event start). A 'SoundExchange Statutory License + Report' has also been added that can be used to generate data in a + format suitable for direct submission of music playout data to + SoundExchange. + + Printable Reports -- It's now possible to generate ASCII-formatted + and printable reports about virtually every aspect of Rivendell + operation, including Cart/Cut lists, Logs, RDCatch events and + more, by touching the 'Reports' button in the respective Rivendell + modules. The choice of external viewer/editor used can be set by + means of the VISUAL environmental variable (default is 'vi' on + Linux, 'Notepad' on Win32). + + Log Data Importer Changes -- The parser parameters for 'Length' in + RDADmin->ManageServices has been split into sections to allow + specification by hours, minutes and seconds as well as the previously + supported plain seconds. + + Audio Auditioning -- It's now possible to audition audio directly + from the Edit Log dialog in RDLogEdit and the Edit Event dialog in + RDLogManager. No attempt is made evaluate rotation logic when + auditioning -- merely the first valid audio found in the selected + cart is played. + + Cart Validity Indication (EXPERIMENTAL) -- The color-coding of + Carts and Cuts in RDLibrary has been altered so as to show the + event's 'playability' *at the instant the event is viewed*. The + yellow 'conditional' indication has been retired. + + Many Bugfixes -- See the ChangeLog for details. + +Library Versions: + This version requires that, at a minimum, libradio-0.97.4 and + librhpi-0.94.7 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + This version of Rivendell uses database schema version 126, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.74 -- 09/18/2006 + +This is a bugfix version of Rivendell. Issues addressed include the +following: + Security Vulnerability -- Allowed users to execute commands with + the Run Shell Command macro with permissions of the user running + the ripcd(8) daemon (normally 'root'). + + Timescaling Playouts -- Fixed a bug that was causing timescaled + events to terminate prematurely under certain circumstances. + + Log Error Checking -- Fixed issues that were preventing changes in + a cart's status in RDLibrary from being properly reflected in an + already-loaded RDAirPlay log. + + JACK/ALSA Playout Optimization -- Increased the size of the audio + ringbuffer for JACK and ALSA drivers. + +See the ChangeLog for further details. + +Library Versions: + This version requires that, at a minimum, libradio-0.97.2 and + librhpi-0.94.7 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + This version of Rivendell uses database schema version 120, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, see RDAdmin->SystemInfo. + + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. +------------------------------------------------------------------------------- +v0.9.73 -- 09/11/2006 + +Changes: + Group Colors -- It is now possible to assign a color to each cart + group, allowing the group to be easily discerned within library + lists and logs. + + RDAirPlay User Interface Tweaks -- The Estimated and Scheduled + start time columns in the Full Log widget have been swapped. + + RDLogManager -- Embedded breaks from the music log are now + associated with the start time of the following music event, rather + than the preceding event. + + Many Bugfixes, especially pertaining to voicetracking and correct + log playout. See the ChangeLog for details. + +AudioScience Driver: + Due to stability issues with the 3.xx ASI driver versions, it is + recommended that v 2.96 or earlier ASI drivers be used with this + version of Rivendell. + +Library Versions: + This version requires that, at a minimum, libradio-0.97.2 and + librhpi-0.94.7 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.71 -- 08/14/2006 + +Changes: + Copying Carts from SoundPanel in RDAirPlay. It's now possible to + copy carts from the SoundPanel button in RDAirPlay when touching the + COPY button. + + VoiceTracker Rubberbanding. Audio fadeup/fadedown points and + levels can now be set independently of the segue overlap in the + Voice Tracker dialog by moving the 'rubberbands' in the waveform + windows. + + Bugfixes. See the ChangeLog for details. + +Library Versions: + This version requires that, at a minimum, libradio-0.97.2 and + librhpi-0.94.7 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.70 -- 08/03/2006 + +Changes: + PAM Authentication Module. Allows the Rivendell user/group + assignment to be dynamically managed by PAM-based login systems. + + Play-While-Recording/Play-While-Importing Capability. It is now + possible to update cut audio content even while the selfsame cut is + playing out in RDAirPlay. (This capability also requires that + the libradio and librhpi packages be upgraded to the indicated + versions in order to function properly). + + BugFixes, especially concerning voicetracking, RDLogManager log + generation and automated downloads in RDCatch. See the ChangeLog + for details. + +Library Versions: + This version requires that, at a minimum, libradio-0.97.2 and + librhpi-0.94.7 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.69 -- 07/20/2006 + +Changes: + Voicetracking. A major new feature in this version, voicetracking + gives operators the ability to insert dynamic, "one-off" audio content to + individual logs as well as the ability to individually customize each segue + transition of a log. Carts for voicetracked content are automatically + created and deleted "on-the-fly" by the system, with no need for individual + cart management in the Library. + + RDLogManager Changes. The sequence for generating logs in RDLogManager has + been completely overhauled, making it now possible to generate a log and + apply voice tracks even before Traffic import data are available (so-called + "incremental log linking"). Several features have also been added to + support operation with music-intensive formats, such as the ability to + schedule embedded voicetracks and spots sets from external music scheduling + systems (currently only tested with RCS Selector). + + RDDBCheck. A utility for checking consistency of the Rivendell database. + For information, do (as root): + + rddbcheck --help + + Many, Many Bugfixes. See the ChangeLog for details. + +Library Versions: + This version requires that, at a minimum, libradio-0.97.1 and + librhpi-0.94.6 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.68 -- 03/20/2006 + +Changes: + Fixed a bug that broke CHAIN-TO events. + +Library Versions: + This version requires that, at a minimum, libradio-0.97.0 and + librhpi-0.94.6 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.67 -- 03/16/2006 + +Changes: + Audio Metadata Import Enhancements. Rivendell will now recognize + and import a wide variety of audio metadata formats, including: + + AES46-2002 (aka "CartChunk") + ID3v1 and ID3v2 Tags + TM Century "GoldWave" Extensions + TM Century "GoldDrive" Format + + RDImport Enhancements. RDImport has been completely rewritten from + scratch, with an eye to improved stability and features (including + 'SingleCart' and 'DropBox' modes). Do 'rdimport --help' at a + command prompt to get a list of the possibilities. + + RDCatch Enhancements. It's now possible to configure AutoTrim and + Normalization of Download Events, as well as Normalization of + Record Events. + + New Report Type. An 'ASCAP/BMI Electronic Music Report' report + format has been added. This uses the so-called "Paris" format to + generate EDI records that can be submitted directly to ASCAP/BMI + for satisfaction of a station's music reporting requirements. New + data fields (including Composer, Publisher and Usage Type) have + also been added to the library to accomodate this functionality. + + Many BugFixes. See the ChangeLog for details. + +------------------------------------------------------------------------------- +v0.9.66 -- 02/15/2006 + +Changes: + CD Ripper Enhancements. Major enhancements have been made to the + CD ripper functionality in the RDLibrary module, including: + + CD-TEXT Support. The rippers now use CD-TEXT data in + preference to the FreeDB. If no CD-TEXT data is found on a + disk, then the FreeDB is searched as before. + + International Standard Recording Code (ISRC) Support. If + found, the rippers will now record the ISRC string from each + track. These strings can be viewed and/or edited in the + 'CutInfo/Record' dialog box. + + Automatic Cart/Cut Generation. In the Full Disk ripper, it's + now possible to rip an entire CD into the system with just a few + mouse clicks. This can be done on a track-by-track basis by + clicking the 'Add New Cart' button in the Select Cut dialog, or + for all the tracks at once by clicking the 'Set All New Carts' + button. + + New Build Targets. It's now possible to build Rivendell as a + Slackware package by doing 'make slack' (requires the Slackware + packaging tools) or as a SLAX module by doing 'make slax' (requires + the Linux-live scripts and the Slackware packaging tools). + + RDCatch Enhancements. The previous hard-coded system-wide limit of + 16 RDCatch decks has been removed, making it possible to configure + and use an arbitrarily large number of decks. + + Miscellaneous Bugfixes. See the ChangeLog. + +Library Versions: + This version requires that, at a minimum, libradio-0.96.1 and + librhpi-0.94.5 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + + +------------------------------------------------------------------------------- +v0.9.65 -- 01/25/2006 + +This is a bugfix release of Rivendell. Among the issues corrected +are: + + RDLogManager issues, including a problem with autofill events when + the associated traffic or music import source had no matching + events. + + Problems with Services whose name contained one or more spaces. + + Full details are in the ChangeLog. + +Library Versions: + This version requires that, at a minimum, libradio-0.95.1 and + librhpi-0.94.4 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.64 -- 01/04/2006 + +Changes: + Waveform Visualization Optimization. Major work has been done on + decreasing the time required to open a cart in RDLibrary's Marker + Editor, for both PCM16 and MPEG formatted audio. + + Bugfixes. See the ChangeLog. + +Library Versions: + This version requires that, at a minimum, libradio-0.95.0 and + librhpi-0.94.4 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.63 -- 12/16/2005 + +Changes: + Version and Help Switches. Every Rivendell module can now be + invoked with a '--version' switch to display the current version, + or a '--help' switch to display a short usage summary. + + Scriptibility Enhancements. Additional command switches have been + added to RMLSend to enable it (and hence, other Rivendell modules) + to be scripted using the full set of Linux CLI utilities (cron(1), + cat(1), etc). Do 'rmlsend --help' for a full list of options. + + Startup Logs in RDAirPlay. It's now possible to specify the + initial logs to load upon startup of RDAirPlay on the command line. + Do 'rdairplay --help' for the options. + + New Switcher Devices. Support has been added for the Broadcast + Tools SS 4.2 audio switcher and StarGuide III satellite receiver. + See the file 'SWITCHERS.txt' for details. + + Bugfixes. See the ChangeLog for details. + +Library Versions: + This version requires that, at a minimum, libradio-0.94.0 and + librhpi-0.94.4 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.62 -- 11/29/2005 + +This is a bugfix release of Rivendell. Among the issues corrected +are: + + A PATH problem in the init script that was causing RDCatch Upload + and Download events to fail. + + Problems with RDAirPlay starting a Hard Timed event reliably under + certain situations. + + See the ChangeLog for a full list. + +Library Versions: + This version requires that, at a minimum, libradio-0.94.0 and + librhpi-0.94.4 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.61 -- 11/22/2005 + +Changes: + RDLibrary Useability Tweaks. When new carts are created in + RDLibrary, they are now considered to officially exist upon clicking + the 'OK' button in the Add Cart dialog, in contradistinction to the + old policy where they didn't 'stick' until 'OK' was clicked in the + Edit Cart dialog. The old way tended to be confusing for many + opertors, as clicking 'Cancel' in the Edit Cart dialog would result + in any recorded audio being deleted. Also then creating a new + cart, RDLibrary will now create a single empty cut within the cart + by default. + + Various Bugfixes. See the ChangeLog for details. + +Library Versions: + This version requires that, at a minimum, libradio-0.94.0 and + librhpi-0.94.4 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.60 -- 11/15/2005 + +Changes: + ELR/Report Data Handling. ELR/Report data is now managed on a + Service-wide basis, rather than being associated with individual + logs. This is reflected in a revamped interface in RDLogManager, + where 'Generate Reports' and 'Delete Report Data' buttons have been + merged into a single 'Manager Report Data' button. + + SoundPanel Configuration Permissioning. A new user right, + 'Configure System Panels', can be used to control which users are + allowed to configure System (type 'S') Sound Panel buttons in + RDAirPlay. + + Various Bugfixes. Including bugs affecting the ability to + generate a new Rivendell database and account lockouts when used + with certain version of mySQL. + +Library Versions: + This version requires that, at a minimum, libradio-0.94.0 and + librhpi-0.94.4 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.58 -- 11/04/2005 + +This release fixes a minor bug in the KDE desktop integration code for +the RPM packaging. For users who do not install from RPM, there is no +difference between this version and v0.9.57. + +------------------------------------------------------------------------------- +v0.9.57 -- 11/03/2005 + +This is primarily a bugfix release of Rivendell. Some minor user +interface tweaks have also been added: + +Changes: + SuSE Desktop Integration. When installing from RPM, items for the + various Rivendell modules will now be added to the Panel Menu in + the 'Applications' and 'System->Desktop Applet' sections. + + Rivendell Icons. A set of Rivendell icons at various resolutions + have been added. They can be found in the package documentation + directory on an RPM installation, or in 'icons/' in the sources. + + Report Data Management. It's now possible to manage report/ELR + data independently of the log it originated from. A new user + attribute, called 'Delete Report Data' configures the right to + delete Report data in the Edit User dialog. Report data can be + deleted either when the parent log is deleted, or by means of a new + 'Delete Report Data' button in RDLogManager. + + Numerous Bugfixes. Including the dilly that was causing responses + to Yes|No dialog boxes to be ignored. See the ChangeLog for details. + +Library Versions: + This version requires that, at a minimum, libradio-0.94.0 and + librhpi-0.94.4 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.55 -- 10/11/2005 + +This is a maintenance/bugfix release of Rivendell. The following +issues have been addressed: + + RDLibrary. + Fixed broken marker editor. + + Fixed loss of 'Day of Week' settings when setting a cut to + 'Evergreen' (Mantis bug #85). + + + RDAirPlay. + Fixed corrupt Hard Time display in Full Log Widget (Mantis bug + #82). + + Fixed failure of space bar to advance events after clicking Full + Log widget (Mantis bug #60). + +Library Versions: + This version requires that, at a minimum, libradio-0.94.0 and + librhpi-0.94.4 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.54 -- 10/06/2005 + +This is primarily a bugfix release of Rivendell. Some minor user +interface tweaks have also been added: + +Changes: + RDLibrary Tweaks. Evergreen cuts in the Edit Cart dialog now show + with a green background. + + RML Behavior. It is now possible to STOP a macro cart running a + 'Sleep' [SP] command in RDAirPlay. + + RDCatch Source Monitoring Tweaks. It is now possible to set the + default state of the source monitors for record decks in RDAdmin, + and have the monitor's state be preserved across multiple + invocations of RDCatch. + + RDLogManagerTweaks. Unneeded and misleading 'Hour' fields have + been removed from time entry fields where appropriate. + +Library Versions: + This version requires that, at a minimum, libradio-0.94.0 and + librhpi-0.94.4 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.53 -- 09/28/2005 + +Changes: + RDCatch Enhancements. It is now possible to configure a single + record 'window' in RDCatch and configure multiple shorter + recordings within that window to be started by means of GPI + closures. + + Asynchronous Macro Carts. It's now possible to designate a macro + cart as to be executed 'Asynchronously', meaning that, when + executed within a log in RDAirPlay, any Sleep ['SP'] RMLs contained + within the cart will not delay subsequent log events, but *will* + delay subsequent RML statements within the cart itself. This can + be useful for achieving various special effects, such as starting a + music bed and then playing a seperately carted dry voiceover on top + of it. + + RDLibrary Enhancements. RDLibrary will now give explicit warning + about various out-of-parameter conditions (like audio carts that + contain no audio). It's now also possible to specify the 'Forced + Length' of a cart (for timescaling purposes) without obscuring the + actual average length of the cart. + + Many Bugfixes. Especially with regard to RDCatch, MPEG encoding + and electronic log reconciliation (ELR) functionality. See the + ChangeLog for details. + +Library Versions: + This version requires that, at a minimum, libradio-0.94.0 and + librhpi-0.94.4 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.51 -- 08/31/2005 + +This version of Rivendell is mostly a bugfix/cleanup release. Changes +are noted below. + +Changes: + Rdcatch_copy(1). This is a new importer filter that can be used to + copy RDCatch events from one Rivendell Host to another, both within + a single database and between two different Rivendell databases. + + Importer Packaging Changes. The utilities in the 'importers/' + subdirectory (wings_filter(1), sas_filter(1), crc-unity4k.sh(1) + and rdcatch_copy(1)) now come packaged in their own seperate RPM, + called 'rivendell-importers'. This is because these utilities are + typically only used once, during system installation, and then + removed. + + Usability Tweaks. Several here and there, mostly to make the + various user interfaces more consistent with each other. See the + ChangeLog for details. + + Various bugfixes. See the ChangeLog for details. + +------------------------------------------------------------------------------- +v0.9.49 -- 08/09/2005 + +Changes: + Fixed a stupid bug that broke browsing in the Cart Selector and Cut + Selector dialog boxes when the group selector was set to 'ALL'. + + RDCatch Enhancements. It's now possible to schedule overlapping + Record events with the same deck but with different GPI and + destination cut parameters. RDCatch will record to the correct + cut on the basis of which GPI was received. + +Library Versions: + This version requires that, at a minimum, libradio-0.93.2 and + librhpi-94.1 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.48 -- 08/07/2005 + +Changes: + Upload Events in RDCatch. It's now possible to schedule the + automatic export and upload of audio files in RDCatch. The + following upload protocols are supported: + FILE + FTP + SMB + + Database Support Cleanups. Added directives to rd.conf(5) to make + it possible for Rivendell to work with RDBMS back-ends other than + mySQL. This feature has not been at all well tested as of yet. + + Import Filter for AirForce 'Wings' System. The filter can be used + to import the entire audio archive of an AirForce 'Wings' system + *in situ*, without requiring reencoding of audio and while + preserving much of the library meta-data from the original system. + See the 'WINGS_FILTER.txt' file in the documentation directory for + more information. + + New Swticher Device Support. Added support for the BroadcastTools + SS16.4 swticher. + + MPEG Cleanups. Many bugfixes regarding the use and handling of + MPEG audio. + + RDLogEdit Fixes. Fixed all known outstanding issues with + RDLogEdit. + + Miscellaneous Bugfixes. See the ChangeLog for details. + +Library Versions: + This version requires that, at a minimum, libradio-0.93.2 and + librhpi-94.1 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.47 -- 07/29/2005 + +Changes: + Download Events in RDCatch. It's now possible to schedule the + automatic download and import of audio files in RDCatch. The + following download protocols are supported: + FILE + FTP + HTTP + HTTPS + SMB + + RDAdmin Changes. A number of features have been added to RDAdmin + to make configuration and management of Rivendell systems easier, + especially for larger sites. These include the ability to create + new Host and Service entries using an already existing Host or + Service as a prototype, as well as the ability to remotely inspect the + audio configuration and capabilities of all systems on the Rivendell + network from a single instance of RDAdmin. Users of the ALSA + driver may also want to consult the 'ALSA.txt' for instructions on + adding an ALSA control device definition to their '.asoundrc' + file. While not strictly necessary, such a control device will + allow Rivendell to provide more specific audio configurtion + information. + + Numerous bugfixes, including the infamous ripcd(8) race condition. + See the ChangeLog for details. + +New Dependencies: + Several new dependencies have been added in this release, for which + new packages may need to be installed. They are: + + lukemftp + samba-client + wget + +Library Versions: + This version requires that, at a minimum, libradio-0.93.1 and + librhpi-94.1 be installed. If installing from RPM, the version of + the currently installed libraries can be determined by doing: + + rpm -q libradio + rpm -q librhpi + +Database Update: + As always, be sure to run RDAdmin immediately after + upgrading to allow any necessary changes to the database schema to + be applied. + +------------------------------------------------------------------------------- +v0.9.45 -- 07/18/2005 + +Changes: + Full Disk Ripping. It's now possible (by touching the 'Rip Disk' + button in RDLibrary's main window) to rip all of the tracks on a CD + to multiple Cart/Cut destinations in a single operation. The + individual track ripper accessed from RDLibrary's Edit Cart dialog + remains as well. + + RDLogin User List. The list of available user names is now shown + in RDLogin as a pulldown list, rather than requiring the user to + enter the name. + + Security System. It's now impossible for the same user to be both + an Administrator and a regular user, and checking the 'Administer + System' box in RDAdmin's User Dialog will now gray out all the + other checkbox choices. This was done to discourage trolling for + admin accounts when using RDLogin (see 'RDLogin User List' above). + + Logitek Audio Engine Support. Full Rivendell integration with + Logitek's Audio Engine system is now possible through use of Logitek's + 'vGuest' control API (part of their 'Supervisor' application). I + would like especially to thank John Davis from Logitek for his + invaluable assistance in getting this working. + + Bugfixes. In particular, bugs affecting audio playout from + RDLibrary's Edit Audio window, as well as problems with saving long + logs. See the ChangeLog for details. + +------------------------------------------------------------------------------- +v0.9.38 -- 07/01/2005 + +Changes: + Security System Cleanups. A lot of time in this release has gone + into ensuring that the various user permission attributes are + correctly and consistently enforced across all of Rivendell's modules. + + Group Permissioning by User. It is now possible to define which + Library Groups will be visible in RDLibrary on a user-by-user + basis. This can be used to effectively 'partition' the Library + into multiple 'sub-libraries'. + + RDAdmin Overhaul. RDAdmin's UI has been overhauled to make it + stylebook-compliant (e.g. doubleclicks now work, focus problems + fixed, etc). In addition, the List Groups dialog has been + substantially expanded and enhanced. + + RDLogManager Overhaul. Likewise, RDLogManager's UI has been + overhauled, with many focus issues corrected. Additionally, + right-click menus have been added in the Edit Clock and Edit Grid + dialogs to permit an underlying Event/Clock object to be directly + edited without having to reascend to the main RDLogManager window. + + Electronic Log Reconciliation. Lots of bugfixes in the ELR + generation routines. Right now, this works only with the Wicks/CBSI + 'DeltaFlex' system. + + Miscellaneous Bugfixes. A great many. See the ChangeLog for + details. + +------------------------------------------------------------------------------- +v0.9.34 -- 06/01/2005 + +Changes: + TSX Timescaling Support. If you have an AudioScience series 61xx + or 62xx card, it is now possible to have playout events in RDAirPlay be + automatically timescaled to the correct length using these cards' + 'TSX Timescaling' feature, by checking the 'Enforce Length' box on + the respective cart label in RDLibrary. + + Event and Clock Filtering. It's now possible to filter the + display of Events and Clocks in RDLogManager in accordance with + their association with one or more Services. + + Audio Passthrough. It's now possible to configure a 'Local Audio + Adapter' switcher device, making it possible to control audio + passing from the inputs to the outputs of the soundcards using + standard switcher control RMLs. See the file 'docs/SWITCHERS.txt' + for details. + + RDCatch Record Deck Monitoring. It's now possible configure a + 'Monitor Port' for each Record Deck in RDCatch for realtime + monitoring of the source audio. + + Bugfixes, especially in the direct ALSA driver. See the ChangeLog + for details. + +------------------------------------------------------------------------------- +v0.9.32 -- 05/10/2005 + +Changes: + Direct ALSA Support. It is now possible to use up to eight ALSA + sound devices directly, without the need to use JACK. See the file + 'docs/ALSA.txt' for information on setting this up. + + RDCatch Changes. RDCatch has been extensively rewritten to support + the use GPI closures for controlling Record Events. The Record + Event dialog has been reorganized accordingly. + + Multiple Sample Rate Support. The JACK driver will now properly + deal with playout of audio that has been encoded with a sampling + rate different from that being used in the active JACK graph. + + Stream Meters Hack. It is now possible to get usable audio meters + in all modules except RDAirPlay with older ASI cards that lack port + metering capability. See the file 'SupportedCards' for details. + + Default Transition Type. It is now possible to specify the default + transition type of newly added events in RDAdmin. + + New Switcher Types. The BroadcastTools 16x2 and 12.4 switchers are + now supported. + + Usability Tweaks. Added many UI tweaks designed to enhance + usability. See the ChangeLog for details. + + Bugfixed. As always, lots of these! See the ChangeLog for details. + +------------------------------------------------------------------------------- +v0.9.26 -- 02/14/2005 + +Changes: + RDLogManger: Change the log generation logic to allow event + overscheduling. + +------------------------------------------------------------------------------- +v0.9.25 -- 02/08/2005 + +Changes: + RDLogManager bugfixes. See the ChangeLog. + +------------------------------------------------------------------------------- +v0.9.24 -- 02/01/2005 + +Changes: + RDLogManager usability enhancements. + + Various bugfixes. See the ChangeLog. + +------------------------------------------------------------------------------- +v0.9.23 -- 01/31/2005 + +Changes: + Various bugfixes. See the ChangeLog. + +------------------------------------------------------------------------------- +v0.9.22 -- 01/31/2005 + +Changes: + Various bugfixes. See the ChangeLog. + +------------------------------------------------------------------------------- +v0.9.21 -- 01/28/2005 + +Changes: + Various bugfixes. See the ChangeLog. + +------------------------------------------------------------------------------- +v0.9.20 -- 01/27/2005 + +Changes: + Various bugfixes. See the ChangeLog. + +------------------------------------------------------------------------------- +v0.9.19 -- 01/26/2005 + +Changes: + Various bugfixes. See the ChangeLog. + +------------------------------------------------------------------------------- +v0.9.18 -- 01/21/2005 + +Changes: + Added support for the SAS 32KD Audio Switcher. + + Added new RMLs: + 'Console Label' [CL] + 'Fire Salvo' [FS] + 'Switch Take With Gain' [SG] + 'Switch Crosspoint Gain' [SX] +------------------------------------------------------------------------------- +v0.9.17 -- 01/17/2005 + +Changes: + Added RDImport to the RPM build for SuSE 9.2. + + Overhauled the Event Editor dialog in RDAirPlay. The new layout is + hopefully more intuitive as well as more stable! + + Added support for the BroadcastTools ACS8.2 switcher. + + Added a 'Run Shell Command' [RN] RML. + + Lots of bugfixes. See the ChangeLog. +------------------------------------------------------------------------------- +v0.9.16 -- 12/27/2004 + +Changes: + Bugfixes for RDAirPlay and the init script. See the ChangeLog. +------------------------------------------------------------------------------- +v0.9.15 -- 12/17/2004 + +Changes: + Bugfixes for RDLibrary and RDAirPlay. See the ChangeLog. +------------------------------------------------------------------------------- +v0.9.14 -- 12/15/2004 + +Changes: + Added automated database backups -- see the 'Database Backup' [DB] RML. + + Added a Windows port for RDLogEdit and RDLogManager. + + Added a 'Gas Gauge' to RDLibrary to show how much free disk space + remains. + + Added a 'SendCommand' [CC] RML, to allow remote execution of RMLs. + + Added Host Variables, a feature that allows RML called to called + with values specific to a given host. See + RDAdmin->ManageHosts->HostVariables. + + Added support for BroadcastTools 8.2 and 16.1 switchers. + + Added a 'Binary Serial Out' [BO] RML. + + Added RDGpiMon, a utility for monitoring the current status of GPI + lines. + + Added a 'SpaceBar Action' control to + RDAdmin->ManageHosts->RDAirPlay to allow the user to specify what + pressing the spacebar does. + + Added a 'Flash Active Events' control to + RDAdmin->ManageHosts->RDAirPlay to specify that active SoundPanel + buttons should flash. + + Added the ability to AutoTrim CD rips and recordings in RDLibrary. + + Added the ability to specify a 'heartbeat cart' to be run + periodically, in RDAdmin->ManageHosts. + + Added a 'Set Color Label' [LC] RML. + + Implemented Service permissions enforcement. + + Implemented Report Exports. See RDAdmin->ManageReports and the + 'reports.txt' file. + + Added LiveAssist mode to RDAirPlay. + + Added the ability to PAUSE active events in RDAirPlay. Must be + enabled in RDAdmin->ManageHosts->RDAirPlay first. + + Added the ability for RDAirPlay to send data concern the + currently-playing and next-to-play events to external systems via + TCP-IP packets. See the 'NOW+NEXT.txt' file for details. + + And, as always, swatted a huge slew of bugs. See the ChangeLog for + details. +------------------------------------------------------------------------------- +v0.9.0 -- 08/18/2004 + +Changes: + A new log generation and merge utility has been added, called + RDLogManager, with the ability to import schedules from most any + third-party traffic or music scheduling system. + + More JACK tweaks -- it's now possible to configure Rivendell's init + script to automatically start and stop jackd(1) as required. See + the 'JACK.txt' file in the 'docs/' directory for details. + + Numerous bugfixes. See the ChangeLog. +------------------------------------------------------------------------------- +v0.8.0 -- 06/26/2004 + +Changes: + The audio driver infrastructure has been completely rewritten to + use dynamic output stream allocation instead of the previous + statically assigned stream values. + + Direct ALSA support has been dropped. In it's place, JACK support + has been implemented. For more information, see 'docs/JACK.txt'. + + Major stability improvements have been made on the primary + Rivendell on-air component, RDAirPlay. + + A bushel of bugfixes throughout. See the ChangeLog for details. +------------------------------------------------------------------------------- +v0.7.9 -- 02/11/2004 + +RDCatch improvements. + +------------------------------------------------------------------------------- +v0.7.8 -- 02/11/2004 + +Test build for Sherrod Munday at SRN. + +------------------------------------------------------------------------------- +v0.7.3 -- 01/28/2004 + +Various bugfixes and UI tweaks. + +------------------------------------------------------------------------------- +v0.7.1 -- 01/27/2004 + +Major changes: + It's now possible to schedule a "switcher event" in RDCatch. + +------------------------------------------------------------------------------- +v0.7.0 -- 01/22/2004 + +Major changes: + + Macro carts are now implemented. + +------------------------------------------------------------------------------- +v0.5.0 -- 12/09/2004 + +The initial BETA release. Testing version only!! + +A complete set of basic tools now exists, as follows: + +RDAdmin -- System administration and configuration + +RDLibrary -- Production library application. + +RDCatch -- Netcatcher control and monitoring + +RDLogin -- Set the current system user + +RDLogEdit -- Generate and edit air logs + +RDAirPlay -- On-air playout application + +------------------------------------------------------------------------------- +v0.1.0 -- 4/28/2002 + +The initial "Friendship 7" release. Contains two programs: + + RDRecord -- A WAV file recorder. + + RDPlay -- A WAV file player. + +Boths utilities support PCM16 and MPEG-1 Layer 2 format and most of +the common meta-data types found in broadcast applications --i.e. BWF +and CartChunk. + +This release has the following major goals: + +1) Provide a thorough shakedown of the AudioScience HPI driver. + +2) Test the wave file implementation (RWaveFile and friends) for + correctness and compatibility with existing systems in the field. + +3) Test the build mechanism in a variety of different distro environments. + +4) Start defining a standard look-and-feel (looking for feedback on + this one). + +------------------------------------------------------------------------------- diff --git a/PACKAGE_VERSION b/PACKAGE_VERSION new file mode 100644 index 00000000..f3ac133c --- /dev/null +++ b/PACKAGE_VERSION @@ -0,0 +1 @@ +2.9.0 \ No newline at end of file diff --git a/README b/README new file mode 100644 index 00000000..aafc62c5 --- /dev/null +++ b/README @@ -0,0 +1,71 @@ +This is the README file for the Rivendell package. + +This software comes with ABSOLUTELY NO WARRANTY. See the file COPYING for +details. + +Welcome to this release of the Rivendell Project. Rivendell aims +to be a robust, functionally complete digital audio system for use in +professional radio broadcast environments. + +See the file INSTALL for installation instructions. If you are upgrading from +a 1.x version of Rivendell, also see the file 'UPGRADING' for important notes +and pointers. + + +OVERVIEW +Rivendell contains a full set of functionality needed to operate a radio +automation system, consisting of the following components: + +RDAdmin +A comprehensive application for the administration and configuration +of Rivendell. + +RDLibrary +The production audio interface. + +RDCatch +The automatic recorder and task scheduler interface. + +RDLogin +A small utility for logging users into and out of the system. + +RDLogEdit +A air log creation, editing and voicetracker tool. + +RDLogManager +A utility for the automatic generation of logs, based on templates. +It also supports importation of schedule information from a wide +variety of third-party traffic and music scheduling systems. + +RDAirPlay +The on-air playout application. + +RDPanel +A 'fullscreen' SoundPanel cartwall application. + +RDCastManager +A utility for posting and managing podcast episodes. + +RDGpiMon +A utility for monitoring GPI line status. + +RDHPIInfo +A utility for configuring AudioScience audio adapters. + +RDAlsaConfig +A utility for configuring ALSA audio adapters. + +RDImport +A command-line utility for batch importing audio along with +accompanying metadata. Do: + + rdimport --help + +from a command prompt for a list of options. + +RMLSend +A GUI and command-line utility for sending Rivendell Macro Language +(RML) commands. + +RDSoftKeys +A lightweight button panel utility for sending RML commands. diff --git a/UPGRADING b/UPGRADING new file mode 100644 index 00000000..a0c86832 --- /dev/null +++ b/UPGRADING @@ -0,0 +1,74 @@ +IMPORTANT NOTE: BE SURE TO SEE THE SECTION ON 'PASSWORD STORAGE' BELOW, +OTHERWISE YOU MAY BE LOCKED OUT OF THE SYSTEM AFTER THE UPDATE! + +This file provides some notes to those performing an upgrade from a v1.x +version to Rivendell. It is an attempt to provide some pointers about things +which have changed, but is in no way a substitute for reading the 'INSTALL' +file and other documentation! + +1) DEPENDENCIES +The set of external packages required to build and run Rivendell has changed +significantly from that required for a 1.x system. See 'INSTALL' for a full +list. + +2) MPEG SUPPORT +This version of Rivendell inaugurates optional support for MPEG Layer 2 +encoding within the core Rivendell audio library for all classes of audio +device (JACK and ALSA as well as AudioScience HPI). To make use of this +feature, it will be necessary to have the appropriate MPEG libraries +properly installed at both build- and run-time. See 'INSTALL' for the +specifics. + +3) FILE OWNERSHIP AND PERMISSIONS +Recommended file ownership and permissions for the '/var/snd' directory and +its contents have changed. These items should be owned by system user and +group accounts created specifically for Rivendell; no 'real' user on the +system should use these accounts. The Rivendell system user and group +accounts are specified in the 'AudioOwner=' and 'AudioGroup=' directives in +the '[Identity]' section of rd.conf(5); see 'conf/rd.conf-sample' for an +example. Permissions for '/var/snd' should be read, write and execute bits +set for User and Group and read, execute for Others (0775), while the contents +should have read, write set for user and group and just read for others (0664). + +4) WEB SERVICES +This version of Rivendell makes use of a web services protocol to accomplish +many functions (audio import, export, ripping, etc). These services require +that a CGI-compliant web server be installed and active on the system. +Any server that complies with CGI-1.1 should work, although as of this writing +only Apache 2.2 has been well tested. A configuration file snippet for Apache +that will configure the target web services directory (set by the +'--libexecdir=' switch passed to './configure') correctly is generated +automatically as part of the build process; it can be found in +'conf/rd-bin.conf' after the build is complete. + +5) PASSWORD STORAGE +The method of storing passwords in the database has changed in Rivendell 2.x, +requiring that all non-null passwords be reset after performing the upgrade. +This means that it is important that the account used to access RDAdmin be set +to use a null (blank) password *before* applying the update, otherwise you +will not be able to access RDAdmin afterwards! Once the update has been +applied, passwords should be re-entered for all user accounts in RDAdmin +(including administrative ones) in the usual manner. + +6) AUDIO SAMPLE RATE +The sample rate to be used for the Rivendell audio library is now a single +system-wide setting (found in RDAdmin->SystemSettings); it is no longer +possible to set sample rates individually per module/workstation. When +updating the schema, Rivendell will default this to the value previously +configured for RDLibrary on a randomly selected host; since this may or may +not be appropriate for your site, checking this value after the update is +recommended. + +7) RDCATCH CHANGES +Upload and Download events in RDCatch that use the 'file:' protocol now +require that a username/password for an appropriate shell user account be +entered. 'Appropriate' here means one with write or read permissions for +the target file, respectively. + +The 'smb:' protocol is no longer supported. + +8) RLM API CHANGES +The parameters passed to the RLMPadDataSent() callback in RLMs have changed; +private plug-ins written for RD 1.x will need to be modified to work with the +new API. (All plug-ins supplied with the Rivendell sources have already been +modified appropriately.) diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 00000000..59b3a44a --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,504 @@ +dnl acinclude.m4 +dnl +dnl Local Autoconf macro definitions for LibRHpi +dnl +dnl (C) Copyright 2006 Fred Gleason +dnl +dnl BNV_HAVE_QT Macro Copyright (C) 2001, 2002, 2003, 2005, 2006 +dnl Bastiaan Veelo +dnl +dnl $Id: acinclude.m4,v 1.7.8.2 2012/08/08 19:48:29 cvs Exp $ +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License version 2 as +dnl published by the Free Software Foundation. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public +dnl License along with this program; if not, write to the Free Software +dnl Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +dnl + +dnl AR_GCC_TARGET() +dnl +dnl Get gcc(1)'s idea of the target architecture, distribution and os. +dnl The following variables are set: +dnl $ar_gcc_arch = Target Architecture (i586, XF86_64, etc) +dnl $ar_gcc_distro = Target Distribution (suse, slackware, etc) +dnl $ar_gcc_os = Target Operating System (linux, solaris, etc) +dnl +AC_DEFUN([AR_GCC_TARGET],[AC_REQUIRE([AC_PROG_CC])] + [ + AC_MSG_CHECKING(target architecture) + ar_gcc_arch=$(./get_target.sh $CC $AWK arch) + ar_gcc_distro=$(./get_target.sh $CC $AWK distro) + ar_gcc_os=$(./get_target.sh $CC $AWK os) + AC_MSG_RESULT([$ar_gcc_arch-$ar_gcc_distro-$ar_gcc_os]) + ] +) + +dnl AR_GET_DISTRO() +dnl +dnl Try to determine the name and version of the distribution running +dnl on the host machine, based on entries in '/etc/'. +dnl The following variables are set: +dnl $ar_distro_name = Distribution Name (SuSE, Debian, etc) +dnl $ar_distro_version = Distribution Version (10.3, 3.1, etc) +dnl $ar_distro_major = Distribution Version Major Number (10, 3, etc) +dnl $ar_distro_minor = Distribution Version Minor Number (3, 1, etc) +dnl +AC_DEFUN([AR_GET_DISTRO],[] + [ + AC_MSG_CHECKING(distribution) + ar_distro_name=$(./get_distro.sh NAME $AWK) + ar_distro_version=$(./get_distro.sh VERSION $AWK) + ar_distro_major=$(./get_distro.sh MAJOR $AWK) + ar_distro_minor=$(./get_distro.sh MINOR $AWK) + AC_MSG_RESULT([$ar_distro_name $ar_distro_version]) + ] +) + +dnl BNV_HAVE_QT [--with-Qt-dir=DIR] [--with-Qt-lib-dir=DIR] [with-Qt-lib=LIB] +dnl BNV_HAVE_QT [--with-Qt-include-dir=DIR] [--with-Qt-bin-dir=DIR] +dnl [--with-Qt-lib-dir=DIR] [--with-Qt-lib=LIB] +dnl +dnl THANKS! This code includes bug fixes and contributions made by: +dnl Tim McClarren, +dnl Dennis R. Weilert, +dnl Qingning Huo, +dnl Brian Mingus, +dnl Jens Hannemann, +dnl Pavel Roskin, +dnl Scott J. Bertin. + +dnl ChangeLog +dnl 2006-03-12 * Hide output of ls and fix an m4 quoting problem (due to Scott J. Bertin). +dnl 2006-02-13 * Check compiler return value instead of parsing the error stream, +dnl which detected warnings as false negatives (due to Jens Hannemann). +dnl 2006-02-02 * Spelling of "Success". +dnl * Fixed unsave test for $bnv_qt_lib without quotes. +dnl * Put dnl in front of all comments. +dnl * Changed -l$bnv_qt_lib_dir into -L$bnv_qt_lib_dir (all due to Pavel Roskin). +dnl 2006-01-19 * Support for 64bit architectures. +dnl * Updated documentation. +dnl 2006-01-18: * Fix "cat: bnv_qt_test.c: No such file or directory" (due to Jens Hannemann). +dnl * Hide output of failing ls. +dnl 2006-01-11: * Check in /Developer on Mac OS X; Check in $QTDIR (due to Brian Mingus). + +dnl Calls BNV_PATH_QT_DIRECT (contained in this file) as a subroutine. +AC_DEFUN([BNV_HAVE_QT], +[ + AC_REQUIRE([AC_PROG_CXX]) + AC_REQUIRE([AC_PATH_X]) + AC_REQUIRE([AC_PATH_XTRA]) + + AC_MSG_CHECKING(for Qt) + + AC_ARG_WITH([Qt-dir], + [ --with-Qt-dir=DIR DIR is equal to $QTDIR if you have followed the + installation instructions of Trolltech. Header + files are in DIR/include, binary utilities are + in DIR/bin. The library is in DIR/lib, unless + --with-Qt-lib-dir is also set.]) + AC_ARG_WITH([Qt-include-dir], + [ --with-Qt-include-dir=DIR + Qt header files are in DIR]) + AC_ARG_WITH([Qt-bin-dir], + [ --with-Qt-bin-dir=DIR Qt utilities such as moc and uic are in DIR]) + AC_ARG_WITH([Qt-lib-dir], + [ --with-Qt-lib-dir=DIR The Qt library is in DIR]) + AC_ARG_WITH([Qt-lib], + [ --with-Qt-lib=LIB Use -lLIB to link with the Qt library]) + if test x"$with_Qt_dir" = x"no" || + test x"$with_Qt_include-dir" = x"no" || + test x"$with_Qt_bin_dir" = x"no" || + test x"$with_Qt_lib_dir" = x"no" || + test x"$with_Qt_lib" = x"no"; then + # user disabled Qt. Leave cache alone. + have_qt="User disabled Qt." + else + # "yes" is a bogus option + if test x"$with_Qt_dir" = xyes; then + with_Qt_dir= + fi + if test x"$with_Qt_include_dir" = xyes; then + with_Qt_include_dir= + fi + if test x"$with_Qt_bin_dir" = xyes; then + with_Qt_bin_dir= + fi + if test x"$with_Qt_lib_dir" = xyes; then + with_Qt_lib_dir= + fi + if test x"$with_Qt_lib" = xyes; then + with_Qt_lib= + fi + # No Qt unless we discover otherwise + have_qt=no + # Check whether we are requested to link with a specific version + if test x"$with_Qt_lib" != x; then + bnv_qt_lib="$with_Qt_lib" + fi + # Check whether we were supplied with an answer already + if test x"$with_Qt_dir" != x; then + have_qt=yes + bnv_qt_dir="$with_Qt_dir" + bnv_qt_include_dir="$with_Qt_dir/include" + bnv_qt_bin_dir="$with_Qt_dir/bin" + bnv_qt_lib_dir="$with_Qt_dir/lib" + # Only search for the lib if the user did not define one already + if test x"$bnv_qt_lib" = x; then + bnv_qt_lib="`ls $bnv_qt_lib_dir/libqt* | sed -n 1p | + sed s@$bnv_qt_lib_dir/lib@@ | [sed s@[.].*@@]`" + fi + bnv_qt_LIBS="-L$bnv_qt_lib_dir -l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + else + # Use cached value or do search, starting with suggestions from + # the command line + AC_CACHE_VAL(bnv_cv_have_qt, + [ + # We are not given a solution and there is no cached value. + bnv_qt_dir=NO + bnv_qt_include_dir=NO + bnv_qt_lib_dir=NO + if test x"$bnv_qt_lib" = x; then + bnv_qt_lib=NO + fi + BNV_PATH_QT_DIRECT + if test "$bnv_qt_dir" = NO || + test "$bnv_qt_include_dir" = NO || + test "$bnv_qt_lib_dir" = NO || + test "$bnv_qt_lib" = NO; then + # Problem with finding complete Qt. Cache the known absence of Qt. + bnv_cv_have_qt="have_qt=no" + else + # Record where we found Qt for the cache. + bnv_cv_have_qt="have_qt=yes \ + bnv_qt_dir=$bnv_qt_dir \ + bnv_qt_include_dir=$bnv_qt_include_dir \ + bnv_qt_bin_dir=$bnv_qt_bin_dir \ + bnv_qt_LIBS=\"$bnv_qt_LIBS\"" + fi + ])dnl + eval "$bnv_cv_have_qt" + fi # all $bnv_qt_* are set + fi # $have_qt reflects the system status + if test x"$have_qt" = xyes; then + QT_CXXFLAGS="-I$bnv_qt_include_dir" + if test x"$bnv_qt_lib" = xqt-mt; then + QT_CXXFLAGS="$QT_CXXFLAGS -DQT_THREAD_SUPPORT" + fi + QT_DIR="$bnv_qt_dir" + QT_LIBS="$bnv_qt_LIBS" + # If bnv_qt_dir is defined, utilities are expected to be in the + # bin subdirectory + if test x"$bnv_qt_dir" != x; then + QT_BIN="$bnv_qt_dir/bin" + if test -x "$bnv_qt_dir/bin/uic"; then + QT_UIC="$bnv_qt_dir/bin/uic" + else + # Old versions of Qt don't have uic + QT_UIC= + fi + QT_MOC="$bnv_qt_dir/bin/moc" + else + # Or maybe we are told where to look for the utilities + if test x"$bnv_qt_bin_dir" != x; then + QT_BIN="$bnv_qt_bin_dir" + if test -x "$bnv_qt_bin_dir/uic"; then + QT_UIC="$bnv_qt_bin_dir/uic" + else + # Old versions of Qt don't have uic + QT_UIC= + fi + QT_MOC="$bnv_qt_bin_dir/moc" + else + # Last possibility is that they are in $PATH + QT_UIC="`which uic`" + QT_MOC="`which moc`" + QT_BIN="`dirname $QT_MOC`" + fi + fi + # All variables are defined, report the result + AC_MSG_RESULT([$have_qt: + QT_CXXFLAGS=$QT_CXXFLAGS + QT_DIR=$QT_DIR + QT_LIBS=$QT_LIBS + QT_BIN=$QT_BIN + QT_UIC=$QT_UIC + QT_MOC=$QT_MOC]) + else + # Qt was not found + QT_CXXFLAGS= + QT_DIR= + QT_LIBS= + QT_BIN= + QT_UIC= + QT_MOC= + AC_MSG_RESULT($have_qt) + fi + AC_SUBST(QT_CXXFLAGS) + AC_SUBST(QT_DIR) + AC_SUBST(QT_LIBS) + AC_SUBST(QT_BIN) + AC_SUBST(QT_UIC) + AC_SUBST(QT_MOC) + + #### Being paranoid: + if test x"$have_qt" = xyes; then + AC_MSG_CHECKING(correct functioning of Qt installation) + AC_CACHE_VAL(bnv_cv_qt_test_result, + [ + cat > bnv_qt_test.h << EOF +#include +class Test : public QObject +{ +Q_OBJECT +public: + Test() {} + ~Test() {} +public slots: + void receive() {} +signals: + void send(); +}; +EOF + + cat > bnv_qt_main.$ac_ext << EOF +#include "bnv_qt_test.h" +#include +int main( int argc, char **argv ) +{ + QApplication app( argc, argv ); + Test t; + QObject::connect( &t, SIGNAL(send()), &t, SLOT(receive()) ); +} +EOF + + bnv_cv_qt_test_result="failure" + bnv_try_1="$QT_MOC bnv_qt_test.h -o moc_bnv_qt_test.$ac_ext >/dev/null 2>/dev/null" + AC_TRY_EVAL(bnv_try_1) + if test x"$ac_status" != x0; then + echo "$bnv_err_1" >&AC_FD_CC + echo "configure: could not run $QT_MOC on:" >&AC_FD_CC + cat bnv_qt_test.h >&AC_FD_CC + else + bnv_try_2="$CXX $QT_CXXFLAGS -c $CXXFLAGS -o moc_bnv_qt_test.o moc_bnv_qt_test.$ac_ext >/dev/null 2>/dev/null" + AC_TRY_EVAL(bnv_try_2) + if test x"$ac_status" != x0; then + echo "$bnv_err_2" >&AC_FD_CC + echo "configure: could not compile:" >&AC_FD_CC + cat moc_bnv_qt_test.$ac_ext >&AC_FD_CC + else + bnv_try_3="$CXX $QT_CXXFLAGS -c $CXXFLAGS -o bnv_qt_main.o bnv_qt_main.$ac_ext >/dev/null 2>/dev/null" + AC_TRY_EVAL(bnv_try_3) + if test x"$ac_status" != x0; then + echo "$bnv_err_3" >&AC_FD_CC + echo "configure: could not compile:" >&AC_FD_CC + cat bnv_qt_main.$ac_ext >&AC_FD_CC + else + bnv_try_4="$CXX -o bnv_qt_main bnv_qt_main.o moc_bnv_qt_test.o $QT_LIBS $LIBS >/dev/null 2>/dev/null" + AC_TRY_EVAL(bnv_try_4) + if test x"$ac_status" != x0; then + echo "$bnv_err_4" >&AC_FD_CC + else + bnv_cv_qt_test_result="success" + fi + fi + fi + fi + ])dnl AC_CACHE_VAL bnv_cv_qt_test_result + AC_MSG_RESULT([$bnv_cv_qt_test_result]); + if test x"$bnv_cv_qt_test_result" = "xfailure"; then + AC_MSG_ERROR([Failed to find matching components of a complete + Qt installation. Try using more options, + see ./configure --help.]) + fi + + rm -f bnv_qt_test.h moc_bnv_qt_test.$ac_ext moc_bnv_qt_test.o \ + bnv_qt_main.$ac_ext bnv_qt_main.o bnv_qt_main + fi +]) + +dnl Internal subroutine of BNV_HAVE_QT +dnl Set bnv_qt_dir bnv_qt_include_dir bnv_qt_bin_dir bnv_qt_lib_dir bnv_qt_lib +AC_DEFUN([BNV_PATH_QT_DIRECT], +[ + ## Binary utilities ## + if test x"$with_Qt_bin_dir" != x; then + bnv_qt_bin_dir=$with_Qt_bin_dir + fi + ## Look for header files ## + if test x"$with_Qt_include_dir" != x; then + bnv_qt_include_dir="$with_Qt_include_dir" + else + # The following header file is expected to define QT_VERSION. + qt_direct_test_header=qglobal.h + # Look for the header file in a standard set of common directories. + bnv_include_path_list=" + /usr/include + `ls -dr ${QTDIR}/include 2>/dev/null` + `ls -dr /usr/include/qt* 2>/dev/null` + `ls -dr /usr/lib/qt*/include 2>/dev/null` + `ls -dr /usr/local/qt*/include 2>/dev/null` + `ls -dr /opt/qt*/include 2>/dev/null` + `ls -dr /Developer/qt*/include 2>/dev/null` + " + for bnv_dir in $bnv_include_path_list; do + if test -r "$bnv_dir/$qt_direct_test_header"; then + bnv_dirs="$bnv_dirs $bnv_dir" + fi + done + # Now look for the newest in this list + bnv_prev_ver=0 + for bnv_dir in $bnv_dirs; do + bnv_this_ver=`egrep -w '#define QT_VERSION' $bnv_dir/$qt_direct_test_header | sed s/'#define QT_VERSION'//` + if expr $bnv_this_ver '>' $bnv_prev_ver > /dev/null; then + bnv_qt_include_dir=$bnv_dir + bnv_prev_ver=$bnv_this_ver + fi + done + fi dnl Found header files. + + # Are these headers located in a traditional Trolltech installation? + # That would be $bnv_qt_include_dir stripped from its last element: + bnv_possible_qt_dir=`dirname $bnv_qt_include_dir` + if (test -x $bnv_possible_qt_dir/bin/moc) && + ((ls $bnv_possible_qt_dir/lib/libqt* > /dev/null 2>/dev/null) || + (ls $bnv_possible_qt_dir/lib64/libqt* > /dev/null 2>/dev/null)); then + # Then the rest is a piece of cake + bnv_qt_dir=$bnv_possible_qt_dir + bnv_qt_bin_dir="$bnv_qt_dir/bin" + if test x"$with_Qt_lib_dir" != x; then + bnv_qt_lib_dir="$with_Qt_lib_dir" + else + if (test -d $bnv_qt_dir/lib64); then + bnv_qt_lib_dir="$bnv_qt_dir/lib64" + else + bnv_qt_lib_dir="$bnv_qt_dir/lib" + fi + fi + # Only look for lib if the user did not supply it already + if test x"$bnv_qt_lib" = xNO; then + bnv_qt_lib="`ls $bnv_qt_lib_dir/libqt* | sed -n 1p | + sed s@$bnv_qt_lib_dir/lib@@ | [sed s@[.].*@@]`" + fi + bnv_qt_LIBS="-L$bnv_qt_lib_dir -l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + else + # There is no valid definition for $QTDIR as Trolltech likes to see it + bnv_qt_dir= + ## Look for Qt library ## + if test x"$with_Qt_lib_dir" != x; then + bnv_qt_lib_dir="$with_Qt_lib_dir" + # Only look for lib if the user did not supply it already + if test x"$bnv_qt_lib" = xNO; then + bnv_qt_lib="`ls $bnv_qt_lib_dir/libqt* | sed -n 1p | + sed s@$bnv_qt_lib_dir/lib@@ | [sed s@[.].*@@]`" + fi + bnv_qt_LIBS="-L$bnv_qt_lib_dir -l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + else + # Normally, when there is no traditional Trolltech installation, + # the library is installed in a place where the linker finds it + # automatically. + # If the user did not define the library name, try with qt + if test x"$bnv_qt_lib" = xNO; then + bnv_qt_lib=qt + fi + qt_direct_test_header=qapplication.h + qt_direct_test_main=" + int argc; + char ** argv; + QApplication app(argc,argv); + " + # See if we find the library without any special options. + # Don't add top $LIBS permanently yet + bnv_save_LIBS="$LIBS" + LIBS="-l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + bnv_qt_LIBS="$LIBS" + bnv_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="-I$bnv_qt_include_dir" + AC_TRY_LINK([#include <$qt_direct_test_header>], + $qt_direct_test_main, + [ + # Success. + # We can link with no special library directory. + bnv_qt_lib_dir= + ], [ + # That did not work. Try the multi-threaded version + echo "Non-critical error, please neglect the above." >&AC_FD_CC + bnv_qt_lib=qt-mt + LIBS="-l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + AC_TRY_LINK([#include <$qt_direct_test_header>], + $qt_direct_test_main, + [ + # Success. + # We can link with no special library directory. + bnv_qt_lib_dir= + ], [ + # That did not work. Try the OpenGL version + echo "Non-critical error, please neglect the above." >&AC_FD_CC + bnv_qt_lib=qt-gl + LIBS="-l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + AC_TRY_LINK([#include <$qt_direct_test_header>], + $qt_direct_test_main, + [ + # Success. + # We can link with no special library directory. + bnv_qt_lib_dir= + ], [ + # That did not work. Maybe a library version I don't know about? + echo "Non-critical error, please neglect the above." >&AC_FD_CC + # Look for some Qt lib in a standard set of common directories. + bnv_dir_list=" + `echo $bnv_qt_includes | sed ss/includess` + /lib + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + /opt/lib64 + /opt/lib + `ls -dr /usr/lib64/qt* 2>/dev/null` + `ls -dr /usr/lib64/qt*/lib64 2>/dev/null` + `ls -dr /usr/lib/qt* 2>/dev/null` + `ls -dr /usr/local/qt* 2>/dev/null` + `ls -dr /opt/qt* 2>/dev/null` + " + for bnv_dir in $bnv_dir_list; do + if ls $bnv_dir/libqt* >/dev/null 2>/dev/null; then + # Gamble that it's the first one... + bnv_qt_lib="`ls $bnv_dir/libqt* | sed -n 1p | + sed s@$bnv_dir/lib@@ | sed s/[[.]].*//`" + bnv_qt_lib_dir="$bnv_dir" + break + fi + done + # Try with that one + LIBS="-l$bnv_qt_lib $X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" + AC_TRY_LINK([#include <$qt_direct_test_header>], + $qt_direct_test_main, + [ + # Success. + # We can link with no special library directory. + bnv_qt_lib_dir= + ], [ + # Leave bnv_qt_lib_dir defined + bnv_qt_lib_dir=bnv_qt_lib_dir + ]) + ]) + ]) + ]) + if test x"$bnv_qt_lib_dir" != x; then + bnv_qt_LIBS="-L$bnv_qt_lib_dir $LIBS" + else + bnv_qt_LIBS="$LIBS" + fi + LIBS="$bnv_save_LIBS" + CXXFLAGS="$bnv_save_CXXFLAGS" + fi dnl $with_Qt_lib_dir was not given + fi dnl Done setting up for non-traditional Trolltech installation +]) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 00000000..e8e1993e --- /dev/null +++ b/autogen.sh @@ -0,0 +1,48 @@ +#!/bin/sh +## +## (C) Copyright 2002-2003 Fred Gleason +## +## $Id: autogen.sh,v 1.5 2010/07/29 19:32:30 cvs Exp $ +## +## Adapted from './autogen.sh' in the Jack Audio Connection Kit. +## Copyright (C) 2001-2003 Paul Davis, et al. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of version 2 of the GNU General Public License as +## published by the Free Software Foundation; +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, +## Boston, MA 02111-1307 USA +## + +libtoolize=libtoolize +if which glibtoolize > /dev/null 2>&1; then + libtoolize=glibtoolize +fi + +$libtoolize --force 2>&1 | sed '/^You should/d' || { + echo "libtool failed, exiting..." + exit 1 +} + +aclocal $ACLOCAL_FLAGS || { + echo "aclocal \$ACLOCAL_FLAGS where \$ACLOCAL_FLAGS= failed, exiting..." + exit 1 +} + +automake --add-missing || { + echo "automake --add-missing failed, exiting..." + exit 1 +} + +autoconf || { + echo "autoconf failed, exiting..." + exit 1 +} diff --git a/build_win32.bat b/build_win32.bat new file mode 100644 index 00000000..8faa0899 --- /dev/null +++ b/build_win32.bat @@ -0,0 +1,37 @@ +@ECHO OFF + +REM build_win32.bat +REM +REM Build Rivendell for Win32. +REM +REM (C) Copyright 2007 Fred Gleason +REM +REM This program is free software; you can redistribute it and/or modify +REM it under the terms of the GNU General Public License as +REM published by the Free Software Foundation; either version 2 of +REM the License, or (at your option) any later version. +REM +REM This program is distributed in the hope that it will be useful, +REM but WITHOUT ANY WARRANTY; without even the implied warranty of +REM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +REM GNU General Public License for more details. +REM +REM You should have received a copy of the GNU General Public +REM License along with this program; if not, write to the Free Software +REM Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +REM +REM Stupid DOS trick to get the package version +REM +copy helpers\win32_frag1.txt + package_version + helpers\win32_frag2.txt helpers\win32_version.bat +call helpers\win32_version.bat +del helpers\win32_version.bat + +REM +REM Build It +REM +qmake -o Makefile rivendell.pro +nmake + + +REM End of build_win32.bat diff --git a/cae/Makefile.am b/cae/Makefile.am new file mode 100644 index 00000000..93e176fe --- /dev/null +++ b/cae/Makefile.am @@ -0,0 +1,55 @@ +## automake.am +## +## Core Audio Engine Makefile.am for Rivendell +## +## Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.33.8.1 2012/11/29 01:37:34 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/rdhpi +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib -L$(top_srcdir)/rdhpi +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = caed + +dist_caed_SOURCES = cae.cpp cae.h\ + cae_alsa.cpp\ + cae_hpi.cpp\ + cae_jack.cpp\ + cae_socket.cpp cae_socket.h + +nodist_caed_SOURCES = moc_cae.cpp\ + moc_cae_socket.cpp + +caed_LDADD = @LIB_RDLIBS@\ + @LIBALSA@\ + @LIBHPI@\ + @LIBJACK@\ + @LIBSRC@\ + @LIBVORBIS@ + +CLEANFILES = *~\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in diff --git a/cae/cae.cpp b/cae/cae.cpp new file mode 100644 index 00000000..a9854bba --- /dev/null +++ b/cae/cae.cpp @@ -0,0 +1,2276 @@ +// cae.cpp +// +// The Core Audio Engine component of Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: cae.cpp,v 1.115.4.3 2012/11/30 16:14:57 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +volatile bool exiting=false; +RDConfig *rd_config; +#ifdef JACK +extern jack_client_t *jack_client; +#endif // JACK + +#define PRINT_COMMANDS + +void LogLine(RDConfig::LogPriority prio,const QString &line) +{ + FILE *file; + + rd_config->log("caed",prio,line); + + if(rd_config->caeLogfile().isEmpty()) { + return; + } + + QDateTime current=QDateTime::currentDateTime(); + + file=fopen(rd_config->caeLogfile(),"a"); + if(file==NULL) { + return; + } + chmod(rd_config->caeLogfile(),S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); + fprintf(file,"%02d/%02d/%4d - %02d:%02d:%02d.%03d : %s\n", + current.date().month(), + current.date().day(), + current.date().year(), + current.time().hour(), + current.time().minute(), + current.time().second(), + current.time().msec(), + (const char *)line); + fclose(file); +} + + +void SigHandler(int signum) +{ + switch(signum) { + case SIGINT: + case SIGTERM: + case SIGHUP: + exiting=true; + break; + } +} + + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"caed",CAED_USAGE); + delete cmd; + + // + // LogLine references rd_config + // + rd_config=new RDConfig(RD_CONF_FILE); + rd_config->load(); + + // + // Make sure we're the only instance running + // + if(CheckDaemon(RD_CAED_PID)) { + LogLine(RDConfig::LogErr, + "ERROR caed aborting - multiple instances not allowed"); + exit(1); + } + + // + // Initialize Data Structures + // + debug=false; + twolame_handle=NULL; + mad_handle=NULL; + if(qApp->argc()>1) { + for(int i=1;iargc();i++) { + if(!strcmp(qApp->argv()[i],"-d")) { + debug=true; + } + } + } + for(int i=0;i<256;i++) { + play_handle[i].card=-1; + play_handle[i].stream=-1; + play_handle[i].owner=-1; + } + next_play_handle=0; + for(int i=0;iok()) { + LogLine(RDConfig::LogErr,"ERROR caed aborting - CaeSocket() server not ok"); + exit(1); + } + connect(server,SIGNAL(connection(int)),this,SLOT(newConnection(int))); + + if(!debug) { + RDDetach(rd_config->logCoreDumpDirectory()); + } + + signal(SIGHUP,SigHandler); + signal(SIGINT,SigHandler); + signal(SIGTERM,SigHandler); + + if(!RDWritePid(RD_PID_DIR,"caed.pid",rd_config->uid())) { + LogLine(RDConfig::LogErr,"can't write pid file"); + fprintf(stderr,"caed: can't write pid file\n"); + exit(1); + } + + // + // Allowcate Meter Socket + // + meter_socket=new QSocketDevice(QSocketDevice::Datagram); + + // + // Open Database + // + QSqlDatabase *db=QSqlDatabase::addDatabase(rd_config->mysqlDriver()); + if(!db) { + LogLine(RDConfig::LogErr,"can't open mySQL database"); + fprintf(stderr,"caed: can't open mySQL database"); + exit(1); + } + db->setDatabaseName(rd_config->mysqlDbname()); + db->setUserName(rd_config->mysqlUsername()); + db->setPassword(rd_config->mysqlPassword()); + db->setHostName(rd_config->mysqlHostname()); + if(!db->open()) { + LogLine(RDConfig::LogErr,"unable to connect to mySQL Server"); + printf("caed: unable to connect to mySQL Server"); + db->removeDatabase(rd_config->mysqlDbname()); + exit(1); + } + + // + // Start Up the Drivers + // + RDStation *station=new RDStation(rd_config->stationName()); + RDSystem *sys=new RDSystem(); + system_sample_rate=sys->sampleRate(); + delete sys; + hpiInit(station); + alsaInit(station); + jackInit(station); + ClearDriverEntries(station); + + // + // Probe Capabilities + // + ProbeCaps(station); + + // + // Close Database Connection + // + station->setScanned(true); + delete station; + db->removeDatabase(rd_config->mysqlDbname()); + + // + // Initialize Mixers + // + InitMixers(); + + // + // Meter Update Timer + // + QTimer *timer=new QTimer(this,"meter_update_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(updateMeters())); + timer->start(RD_METER_UPDATE_INTERVAL); + + // + // Initialize Thread Priorities + // + bool jack_running=false; + int sched_policy=SCHED_OTHER; + struct sched_param sched_params; + int result = 0; + memset(&sched_params,0,sizeof(struct sched_param)); +#ifdef JACK + if(jack_client!=NULL) { + pthread_getschedparam(jack_client_thread_id(jack_client),&sched_policy, + &sched_params); +#ifdef ALSA + for(int i=0;iuseRealtime()) { + if(!jack_running) { + sched_params.sched_priority=rd_config->realtimePriority(); + } + sched_policy=SCHED_FIFO; +#ifdef ALSA + for(int i=0;isched_get_priority_min(sched_policy)) { + sched_params.sched_priority--; + } + int r = pthread_setschedparam(pthread_self(),sched_policy,&sched_params); + if (r) { + result = r; + } + mlockall(MCL_CURRENT|MCL_FUTURE); + if (result){ + LogLine(RDConfig::LogWarning,QString(). + sprintf("Unable to set realtime scheduling: %s", + strerror (result))); + } else { + LogLine(RDConfig::LogInfo,QString(). + sprintf("using realtime scheduling, priority=%d", + sched_params.sched_priority)); + } + } + + // + // Relinquish Root Permissions (if present) + // +/* + if(getuid()==0) { + if(setuid(rd_config->uid())<0) { + perror("cae"); + exit(1); + } +// if(setegid(rd_config->gid())<0) { +// perror("cae"); +// exit(1); +// } + } +*/ + if(rd_config->enableMixerLogging()) { + LogLine(RDConfig::LogNotice,"mixer logging enabled"); + } + LogLine(RDConfig::LogInfo,"cae started"); +} + + +MainObject::~MainObject() { + delete server; +} + +void MainObject::newConnection(int fd) +{ + int i=0; + + while((isetSocket(fd); + connect(socket[i],SIGNAL(readyReadID(int)),this,SLOT(socketData(int))); + connect(socket[i],SIGNAL(connectionClosedID(int)), + this,SLOT(socketKill(int))); +} + + +void MainObject::socketData(int ch) +{ + ParseCommand(ch); +} + + +void MainObject::socketKill(int ch) +{ + KillSocket(ch); +} + + +void MainObject::statePlayUpdate(int card,int stream,int state) +{ + int handle=GetHandle(card,stream); + + if(handle<0) { + return; + } + if(play_owner[card][stream]!=-1) { + switch(state) { + case 1: // Playing + EchoCommand(play_owner[card][stream],(const char *)QString(). + sprintf("PY %d %d %d +!",handle, + play_length[card][stream], + play_speed[card][stream])); + break; + case 2: // Paused + EchoCommand(play_owner[card][stream],(const char *)QString(). + sprintf("SP %d +!",handle)); + break; + case 0: // Stopped + EchoCommand(play_owner[card][stream],(const char *)QString(). + sprintf("SP %d +!",handle)); + break; + } + } +} + + +void MainObject::stateRecordUpdate(int card,int stream,int state) +{ + if(record_owner[card][stream]!=-1) { + switch(state) { + case 0: // Recording + EchoCommand(record_owner[card][stream],(const char *)QString(). + sprintf("RD %d %d %d %d +!",card,stream, + record_length[card][stream], + record_threshold[card][stream])); + break; + + case 4: // Record Started + EchoCommand(record_owner[card][stream],(const char *)QString(). + sprintf("RS %d %d +!",card,stream)); + break; + + case 2: // Paused + case 3: // Stopped + EchoCommand(record_owner[card][stream],(const char *)QString(). + sprintf("SR %d %d +!",card,stream)); + break; + } + } +} + + +void MainObject::updateMeters() +{ + short levels[2]; + unsigned positions[RD_MAX_STREAMS]; + + if(exiting) { + jackFree(); + alsaFree(); + hpiFree(); + RDDeletePid(RD_PID_DIR,"caed.pid"); + LogLine(RDConfig::LogInfo,"cae exiting"); + exit(0); + } + + AlsaClock(); + JackClock(); + + for(int i=0;ireadBlock(buf,256))>0) { + buf[c]=0; + // LogLine(QString().sprintf("RCVD: %s",buf)); + for(int i=0;iclose(); + KillSocket(ch); + return; + } + if(!strcmp(args[ch][0],"PW")) { // Password Authenticate + if(!strcmp(args[ch][1],rd_config->password())) { + auth[ch]=true; + EchoCommand(ch,"PW +!"); + return; + } + else { + auth[ch]=false; + EchoCommand(ch,"PW -!"); + return; + } + } + + // + // Priviledged Commands + // Authentication required to execute these! + // + if(!auth[ch]) { + EchoArgs(ch,'-'); + return; + } + + if(!strcmp(args[ch][0],"LP")) { // Load Playback + if(card<0) { + sprintf(temp,"LP %d %s -1 -1 -!",card,args[ch][2]); + EchoCommand(ch,temp); + return; + } + wavename = rd_config->audioFileName (QString(args[ch][2])); + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiLoadPlayback(card,wavename,&new_stream)) { + sprintf(temp,"LP %d %s -1 -1 -!",card,args[ch][2]); + EchoCommand(ch,temp); + LogLine(RDConfig::LogErr, + QString().sprintf("unable to allocate stream for card %d", + card)); + return; + } + break; + + case RDStation::Alsa: + if(!alsaLoadPlayback(card,wavename,&new_stream)) { + sprintf(temp,"LP %d %s -1 -1 -!",card,args[ch][2]); + EchoCommand(ch,temp); + LogLine(RDConfig::LogErr,QString(). + sprintf("unable to allocate stream for card %d", + card)); + return; + } + break; + + case RDStation::Jack: + if(!jackLoadPlayback(card,wavename,&new_stream)) { + sprintf(temp,"LP %d %s -1 -1 -!",card,args[ch][2]); + EchoCommand(ch,temp); + LogLine(RDConfig::LogErr,QString(). + sprintf("unable to allocate stream for card %d", + card)); + return; + } + break; + + default: + sprintf(temp,"LP %d %s -1 -1 -!",card,args[ch][2]); + EchoCommand(ch,temp); + return; + } + if((handle=GetHandle(card,new_stream))>=0) { + LogLine(RDConfig::LogErr,QString(). + sprintf("*** clearing stale stream assignment, card=%d stream=%d ***",card,new_stream)); + play_handle[handle].card=-1; + play_handle[handle].stream=-1; + play_handle[handle].owner=-1; + } + handle=GetNextHandle(); + play_handle[handle].card=card; + play_handle[handle].stream=new_stream; + play_handle[handle].owner=ch; + play_owner[card][new_stream]=ch; + LogLine(RDConfig::LogInfo,QString(). + sprintf("LoadPlayback Card: %d Stream: %d Name: %s Handle: %d", + card,new_stream,(const char *)wavename,handle)); + sprintf(temp,"LP %d %s %d %d +!",card,args[ch][2],new_stream,handle); + EchoCommand(ch,temp); + return; + } + + if(!strcmp(args[ch][0],"UP")) { // Unload Playback + if((handle=GetHandle(ch,&card,&stream))<0) { + EchoArgs(ch,'-'); + return; + } + card=play_handle[handle].card; + stream=play_handle[handle].stream; + if((play_owner[card][stream]==-1)||(play_owner[card][stream]==ch)) { + switch(cae_driver[card]) { + case RDStation::Hpi: + if(hpiUnloadPlayback(card,stream)) { + play_owner[card][stream]=-1; + LogLine(RDConfig::LogInfo,QString(). + sprintf("UnloadPlayback - Card: %d Stream: %d Handle: %d", + card,stream,handle)); + EchoArgs(ch,'+'); + } + else { + EchoArgs(ch,'-'); + } + break; + + case RDStation::Alsa: + if(alsaUnloadPlayback(card,stream)) { + play_owner[card][stream]=-1; + LogLine(RDConfig::LogInfo,QString(). + sprintf("UnloadPlayback - Card: %d Stream: %d Handle: %d", + card,stream,handle)); + EchoArgs(ch,'+'); + } + else { + EchoArgs(ch,'-'); + } + break; + + case RDStation::Jack: + if(jackUnloadPlayback(card,stream)) { + play_owner[card][stream]=-1; + LogLine(RDConfig::LogInfo,QString(). + sprintf("UnloadPlayback - Card: %d Stream: %d Handle: %d", + card,stream,handle)); + EchoArgs(ch,'+'); + } + else { + EchoArgs(ch,'-'); + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + play_handle[handle].card=-1; + play_handle[handle].stream=-1; + play_handle[handle].owner=-1; + return; + } + else { + EchoArgs(ch,'-'); + } + } + + if(!strcmp(args[ch][0],"PP")) { // Playback Position + if((handle=GetHandle(ch,&card,&stream))<0) { + EchoArgs(ch,'-'); + return; + } + card=play_handle[handle].card; + stream=play_handle[handle].stream; + if(play_owner[card][stream]==ch) { + if(sscanf(args[ch][2],"%d",&pos)!=1) { + EchoArgs(ch,'-'); + return; + } + switch(cae_driver[card]) { + case RDStation::Hpi: + if(hpiPlaybackPosition(card,stream,pos)) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("PlaybackPosition - Card: %d Stream: %d Pos: %d Handle: %d", + card,stream,pos,handle)); + EchoArgs(ch,'+'); + } + else { + LogLine(RDConfig::LogNotice,QString(). + sprintf("*** PlaybackPosition out of bounds - Card: %d Stream: %d Pos: %d Handle: %d***", + card,stream,pos,handle)); + EchoArgs(ch,'-'); + } + break; + + case RDStation::Alsa: + if(alsaPlaybackPosition(card,stream,pos)) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("PlaybackPosition - Card: %d Stream: %d Pos: %d Handle: %d", + card,stream,pos,handle)); + EchoArgs(ch,'+'); + } + else { + EchoArgs(ch,'-'); + } + break; + + case RDStation::Jack: + if(jackPlaybackPosition(card,stream,pos)) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("PlaybackPosition - Card: %d Stream: %d Pos: %d Handle: %d", + card,stream,pos,handle)); + EchoArgs(ch,'+'); + } + else { + EchoArgs(ch,'-'); + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + return; + } + EchoArgs(ch,'-'); + return; + } + + if(!strcmp(args[ch][0],"PY")) { // Play + if((handle=GetHandle(ch,&card,&stream))<0) { + EchoArgs(ch,'-'); + return; + } + card=play_handle[handle].card; + stream=play_handle[handle].stream; + if(sscanf(args[ch][2],"%d",&play_length[card][stream])!=1) { + EchoArgs(ch,'-'); + return; + } + if(sscanf(args[ch][3],"%d",&play_speed[card][stream])!=1) { + EchoArgs(ch,'-'); + return; + } + if(sscanf(args[ch][4],"%d",&flag)!=1) { + EchoArgs(ch,'-'); + return; + } + switch(flag) { + case 0: + play_pitch[card][stream]=false; + break; + case 1: + play_pitch[card][stream]=true; + break; + default: + EchoArgs(ch,'-'); + return; + } + if(play_owner[card][stream]==ch) { + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiPlay(card,stream,play_length[card][stream], + play_speed[card][stream],play_pitch[card][stream], + RD_ALLOW_NONSTANDARD_RATES)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaPlay(card,stream,play_length[card][stream], + play_speed[card][stream],play_pitch[card][stream], + RD_ALLOW_NONSTANDARD_RATES)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackPlay(card,stream,play_length[card][stream], + play_speed[card][stream],play_pitch[card][stream], + RD_ALLOW_NONSTANDARD_RATES)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + LogLine(RDConfig::LogInfo,QString(). + sprintf("Play - Card: %d Stream: %d Handle: %d Length: %d Speed: %d Pitch: %d", + card,stream,handle,play_length[card][stream], + play_speed[card][stream],flag)); + // No command echo for success -- statePlayUpdate() sends it! + return; + } + EchoArgs(ch,'-'); + return; + } + + if(!strcmp(args[ch][0],"SP")) { // Stop Playback + if((handle=GetHandle(ch,&card,&stream))<0) { + EchoArgs(ch,'-'); + return; + } + card=play_handle[handle].card; + stream=play_handle[handle].stream; + if(play_owner[card][stream]==ch) { + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiStopPlayback(card,stream)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaStopPlayback(card,stream)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackStopPlayback(card,stream)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + LogLine(RDConfig::LogInfo,QString(). + sprintf("StopPlayback - Card: %d Stream: %d Handle: %d", + card,stream,handle)); + // EchoArgs(ch,'+'); + return; + } + EchoArgs(ch,'-'); + return; + } + + if(!strcmp(args[ch][0],"TS")) { // Timescale Support + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiTimescaleSupported(card)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackTimescaleSupported(card)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaTimescaleSupported(card)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"LR")) { // Load Record + if((card<0)||(stream<0)) { + EchoArgs(ch,'-'); + return; + } + if(record_owner[card][stream]==-1) { + if(sscanf(args[ch][3],"%d",&coding)!=1) { + EchoArgs(ch,'-'); + return; + } + if(sscanf(args[ch][4],"%d",&channels)!=1) { + EchoArgs(ch,'-'); + return; + } + if(sscanf(args[ch][5],"%d",&sample_rate)!=1) { + EchoArgs(ch,'-'); + return; + } + if(sscanf(args[ch][6],"%d",&bit_rate)!=1) { + EchoArgs(ch,'-'); + return; + } + wavename = rd_config->audioFileName(QString(args[ch][7])); + unlink(wavename); // So we don't trainwreck any current playouts! + unlink(wavename+".energy"); + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiLoadRecord(card,stream,coding,channels,sample_rate,bit_rate, + wavename)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaLoadRecord(card,stream,coding,channels,sample_rate, + bit_rate,wavename)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackLoadRecord(card,stream,coding,channels,sample_rate, + bit_rate,wavename)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + LogLine(RDConfig::LogInfo,QString(). + sprintf("LoadRecord - Card: %d Stream: %d Coding: %d Chans: %d SampRate: %d BitRate: %d Name: %s", + card,stream,coding,channels,sample_rate,bit_rate, + (const char *)wavename)); + record_owner[card][stream]=ch; + EchoArgs(ch,'+'); + } + else { + EchoArgs(ch,'-'); + } + return; + } + + if(!strcmp(args[ch][0],"UR")) { // Unload Record + if((card<0)||(stream<0)) { + EchoArgs(ch,'-'); + return; + } + if((record_owner[card][stream]==-1)||(record_owner[card][stream]==ch)) { + unsigned len=0; + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiUnloadRecord(card,stream,&len)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaUnloadRecord(card,stream,&len)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackUnloadRecord(card,stream,&len)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + record_owner[card][stream]=-1; + LogLine(RDConfig::LogInfo,QString(). + sprintf("UnloadRecord - Card: %d Stream: %d, Length: %u", + card,stream,len)); + EchoCommand(ch,(const char *)QString().sprintf("UR %d %d %u +!", + card,stream, + (unsigned)((double)len*1000.0/(double)system_sample_rate))); + return; + } + else { + EchoArgs(ch,'-'); + return; + } + } + + if(!strcmp(args[ch][0],"RD")) { // Record + if((card<0)||(stream<0)) { + EchoArgs(ch,'-'); + return; + } + if(sscanf(args[ch][3],"%d",&record_length[card][stream])!=1) { + EchoArgs(ch,'-'); + return; + } + if(sscanf(args[ch][4],"%d",&record_threshold[card][stream])!=1) { + EchoArgs(ch,'-'); + return; + } + if(record_owner[card][stream]==ch) { + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiRecord(card,stream,record_length[card][stream], + record_threshold[card][stream])) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaRecord(card,stream,record_length[card][stream], + record_threshold[card][stream])) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackRecord(card,stream,record_length[card][stream], + record_threshold[card][stream])) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + LogLine(RDConfig::LogInfo,QString(). + sprintf("Record - Card: %d Stream: %d Length: %d Thres: %d", + card,stream,record_length[card][stream], + record_threshold[card][stream])); +// EchoArgs(ch,'+'); + return; + } + EchoArgs(ch,'-'); + return; + } + + if(!strcmp(args[ch][0],"SR")) { // Stop Record + if((card<0)||(stream<0)) { + EchoArgs(ch,'-'); + return; + } + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiStopRecord(card,stream)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaStopRecord(card,stream)) { + EchoArgs(ch,'-'); + return; + } + EchoArgs(ch,'+'); + break; + + case RDStation::Jack: + if(!jackStopRecord(card,stream)) { + EchoArgs(ch,'-'); + return; + } + EchoArgs(ch,'+'); + break; + + default: + EchoArgs(ch,'-'); + return; + } + LogLine(RDConfig::LogInfo,QString(). + sprintf("StopRecord - Card: %d Stream: %d", + card,stream)); + return; + } + + if(!strcmp(args[ch][0],"CS")) { // Set Clock Source + if((card<0)||(stream<0)) { + EchoArgs(ch,'-'); + return; + } + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiSetClockSource(card,stream)) { + EchoArgs(ch,'-'); + return; + } + + default: + EchoArgs(ch,'+'); + return; + } + if(rd_config->enableMixerLogging()) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("SetClockSource - Card: %d Source: %d",card,stream)); + } + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"IV")) { // Set Input Volume + if((card<0)||(stream<0)) { + EchoArgs(ch,'-'); + return; + } + sscanf(args[ch][3],"%d",&level); + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiSetInputVolume(card,stream,level)) { + EchoArgs(ch,'-'); + return; + } + + case RDStation::Alsa: + if(!alsaSetInputVolume(card,stream,level)) { + EchoArgs(ch,'-'); + return; + } + + case RDStation::Jack: + if(!jackSetInputVolume(card,stream,level)) { + EchoArgs(ch,'-'); + return; + } + + default: + EchoArgs(ch,'-'); + return; + } + if(rd_config->enableMixerLogging()) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("SetInputVolume - Card: %d Stream: %d Level: %d", + card,stream,level)); + } + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"OV")) { // Set Output Volume + if((card<0)||(stream<0)) { + EchoArgs(ch,'-'); + return; + } + sscanf(args[ch][3],"%d",&port); + sscanf(args[ch][4],"%d",&level); + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiSetOutputVolume(card,stream,port,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaSetOutputVolume(card,stream,port,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackSetOutputVolume(card,stream,port,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + if(rd_config->enableMixerLogging()) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("SetOutputVolume - Card: %d Stream: %d Port: %d Level: %d", + card,stream,port,level)); + } + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"FV")) { // Fade Output Volume + if((card<0)||(stream<0)) { + EchoArgs(ch,'-'); + return; + } + sscanf(args[ch][3],"%d",&port); + sscanf(args[ch][4],"%d",&level); + sscanf(args[ch][5],"%d",&length); + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiFadeOutputVolume(card,stream,port,level,length)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaFadeOutputVolume(card,stream,port,level,length)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackFadeOutputVolume(card,stream,port,level,length)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + if(rd_config->enableMixerLogging()) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("FadeOutputVolume - Card: %d Stream: %d Port: %d Level: %d Length: %d", + card,stream,port,level,length)); + } + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"IL")) { // Set Input Level + sscanf(args[ch][2],"%d",&port); + sscanf(args[ch][3],"%d",&level); + if((card<0)||(port<0)) { + EchoArgs(ch,'-'); + return; + } + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiSetInputLevel(card,port,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaSetInputLevel(card,port,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackSetInputLevel(card,port,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + if(rd_config->enableMixerLogging()) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("SetInputLevel - Card: %d Port: %d Level: %d", + card,port,level)); + } + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"OL")) { // Set Output Level + sscanf(args[ch][2],"%d",&port); + sscanf(args[ch][3],"%d",&level); + if((card<0)||(port<0)) { + EchoArgs(ch,'-'); + return; + } + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiSetOutputLevel(card,port,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaSetOutputLevel(card,port,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackSetOutputLevel(card,port,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + if(rd_config->enableMixerLogging()) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("SetOutputLevel - Card: %d Port: %d Level: %d", + card,port,level)); + } + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"IM")) { // Set Input Mode + sscanf(args[ch][2],"%d",&port); + sscanf(args[ch][3],"%d",&mode); + if((card<0)||(port<0)) { + EchoArgs(ch,'-'); + return; + } + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiSetInputMode(card,port,mode)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaSetInputMode(card,port,mode)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackSetInputMode(card,port,mode)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + if(rd_config->enableMixerLogging()) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("SetInputMode - Card: %d Port: %d Mode: %d", + card,port,mode)); + } + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"OM")) { // Set Output Mode + sscanf(args[ch][2],"%d",&port); + sscanf(args[ch][3],"%d",&mode); + if((card<0)||(port<0)) { + EchoArgs(ch,'-'); + return; + } + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiSetOutputMode(card,port,mode)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaSetOutputMode(card,port,mode)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackSetOutputMode(card,port,mode)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + if(rd_config->enableMixerLogging()) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("SetOutputMode - Card: %d Port: %d Mode: %d", + card,port,mode)); + } + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"IX")) { // Set Input VOX Level + if((card<0)||(stream<0)) { + EchoArgs(ch,'-'); + return; + } + sscanf(args[ch][3],"%d",&level); + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiSetInputVoxLevel(card,stream,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaSetInputVoxLevel(card,stream,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackSetInputVoxLevel(card,stream,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + if(rd_config->enableMixerLogging()) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("SetInputVOXLevel - Card: %d Stream: %d Level: %d", + card,stream,level)); + } + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"IT")) { // Set Input Type + sscanf(args[ch][2],"%d",&port); + sscanf(args[ch][3],"%d",&type); + if((card<0)||(port<0)) { + EchoArgs(ch,'-'); + return; + } + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiSetInputType(card,port,type)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaSetInputType(card,port,type)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackSetInputType(card,port,type)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + if(rd_config->enableMixerLogging()) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("SetInputType - Card: %d Port: %d Type: %d", + card,port,type)); + } + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"AL")) { // Set Passthrough Level + sscanf(args[ch][2],"%d",&in_port); + sscanf(args[ch][3],"%d",&out_port); + sscanf(args[ch][4],"%d",&level); + if((card<0)||(in_port<0)||(out_port<0)) { + EchoArgs(ch,'-'); + return; + } + switch(cae_driver[card]) { + case RDStation::Hpi: + if(!hpiSetPassthroughLevel(card,in_port,out_port,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Alsa: + if(!alsaSetPassthroughLevel(card,in_port,out_port,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + case RDStation::Jack: + if(!jackSetPassthroughLevel(card,in_port,out_port,level)) { + EchoArgs(ch,'-'); + return; + } + break; + + default: + EchoArgs(ch,'-'); + return; + } + if(rd_config->enableMixerLogging()) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("SetPassthroughLevel - Card: %d InPort: %d OutPort: %d Level: %d", + card,in_port,out_port,level)); + } + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"IS")) { // Input Status + sscanf(args[ch][2],"%d",&port); + if((card<0)||(port<0)) { + EchoArgs(ch,'-'); + return; + } + if(hpiGetInputStatus(card,port)) { + EchoCommand(ch,QString().sprintf("IS %d %d 0 +!",card,port)); + } + else { + EchoCommand(ch,QString().sprintf("IS %d %d 1 +!",card,port)); + } + return; + } + + if(!strcmp(args[ch][0],"ME")) { // Meter Enable + sscanf(args[ch][1],"%d",&port); + if((port<0)||(port>0xFFFF)) { + EchoArgs(ch,'-'); + return; + } + meter_port[ch]=port; + EchoArgs(ch,'+'); + SendMeterOutputStatusUpdate(); + return; + } + + if(!strcmp(args[ch][0],"OS")) { // Set Output Status Flag + sscanf(args[ch][1],"%d",&card); + sscanf(args[ch][2],"%d",&port); + sscanf(args[ch][3],"%d",&stream); + if((card<0)||(card>=RD_MAX_CARDS)|| + (port<0)||(port>=RD_MAX_PORTS)|| + (stream<0)||(stream>=RD_MAX_STREAMS)) { + EchoArgs(ch,'-'); + return; + } + output_status_flag[card][port][stream]=args[ch][4][0]=='1'; + SendMeterOutputStatusUpdate(card,port,stream); + EchoArgs(ch,'+'); + return; + } + + if(!strcmp(args[ch][0],"JC")) { // Connect JACK Ports + pos=-1; + for(int i=0;istate()==QSocket::Connection) { +#ifdef PRINT_COMMANDS + printf("CAE: Connection %d sending %s\n",ch,command); +#endif // PRINT_COMMANDS + socket[ch]->writeBlock(command,strlen(command)); + } +} + + +void MainObject::EchoArgs(int ch,const char append) +{ + char command[CAE_MAX_LENGTH+2]; + int l; + + command[0]=0; + for(int i=0;i=0) { + next_play_handle++; + next_play_handle&=0xFF; + } + int handle=next_play_handle; + next_play_handle++; + next_play_handle&=0xFF; + return handle; +} + + +int MainObject::GetHandle(int ch,int *card,int *stream) +{ + int handle; + + if(sscanf(args[ch][1],"%d",&handle)!=1) { + return -1; + } + if((handle<0)||(handle>=256)) { + return -1; + } + if((*card=play_handle[handle].card)<0) { + return -1; + } + if((*stream=play_handle[handle].stream<0)) { + return -1; + } + return handle; +} + + +int MainObject::GetHandle(int card,int stream) +{ + for(int i=0;i<256;i++) { + if((play_handle[i].card==card)&&(play_handle[i].stream==stream)) { + return i; + } + } + return -1; +} + + +void MainObject::ProbeCaps(RDStation *station) +{ + // + // Patent-clear codecs + // +#ifdef HAVE_VORBIS + station->setHaveCapability(RDStation::HaveOggenc,true); + station->setHaveCapability(RDStation::HaveOgg123,true); +#else + station->setHaveCapability(RDStation::HaveOggenc,false); + station->setHaveCapability(RDStation::HaveOgg123,false); +#endif // HAVE_VORBIS +#ifdef HAVE_FLAC + station->setHaveCapability(RDStation::HaveFlac,true); +#else + station->setHaveCapability(RDStation::HaveFlac,false); +#endif // HAVE_FLAC + + // + // MPEG Codecs + // + station->setHaveCapability(RDStation::HaveLame,CheckLame()); + station->setHaveCapability(RDStation::HaveTwoLame,LoadTwoLame()); + station->setHaveCapability(RDStation::HaveMpg321,LoadMad()); + +#ifdef HPI + station->setDriverVersion(RDStation::Hpi,hpiVersion()); +#else + station->setDriverVersion(RDStation::Hpi,"[not enabled]"); +#endif // HPI +#ifdef JACK + // + // FIXME: How can we detect the current JACK version? + // + station->setDriverVersion(RDStation::Jack,"Generic"); +#else + station->setDriverVersion(RDStation::Jack,""); +#endif // JACK +#ifdef ALSA + station->setDriverVersion(RDStation::Alsa, + QString().sprintf("%d.%d.%d", + SND_LIB_MAJOR, + SND_LIB_MINOR, + SND_LIB_SUBMINOR)); +#else + station->setDriverVersion(RDStation::Alsa,""); +#endif // ALSA +} + + +void MainObject::ClearDriverEntries(RDStation *station) +{ + for(int i=0;isetCardDriver(i,RDStation::None); + station->setCardName(i,""); + station->setCardInputs(i,-1); + station->setCardOutputs(i,-1); + } + } +} + + +/* This is an overloaded virtual function to tell a session manager not to restart this daemon. */ +void QApplication::saveState(QSessionManager &sm) { + sm.setRestartHint(QSessionManager::RestartNever); + LogLine(RDConfig::LogDebug,"cae saveState(), set restart hint to Never"); + return; +}; + + +bool MainObject::CheckLame() +{ +#ifdef HAVE_LAME + return dlopen("libmp3lame.so",RTLD_LAZY)!=NULL; +#else + return false; +#endif // HAVE_LAME +} + + +bool MainObject::LoadTwoLame() +{ +#ifdef HAVE_TWOLAME + if((twolame_handle=dlopen("libtwolame.so",RTLD_NOW))==NULL) { + LogLine(RDConfig::LogInfo, + "TwoLAME encoder library not found, MPEG L2 encoding not supported"); + return false; + } + *(void **)(&twolame_init)=dlsym(twolame_handle,"twolame_init"); + *(void **)(&twolame_set_mode)=dlsym(twolame_handle,"twolame_set_mode"); + *(void **)(&twolame_set_num_channels)= + dlsym(twolame_handle,"twolame_set_num_channels"); + *(void **)(&twolame_set_in_samplerate)= + dlsym(twolame_handle,"twolame_set_in_samplerate"); + *(void **)(&twolame_set_out_samplerate)= + dlsym(twolame_handle,"twolame_set_out_samplerate"); + *(void **)(&twolame_set_bitrate)= + dlsym(twolame_handle,"twolame_set_bitrate"); + *(void **)(&twolame_init_params)= + dlsym(twolame_handle,"twolame_init_params"); + *(void **)(&twolame_close)=dlsym(twolame_handle,"twolame_close"); + *(void **)(&twolame_encode_buffer_interleaved)= + dlsym(twolame_handle,"twolame_encode_buffer_interleaved"); + *(void **)(&twolame_encode_buffer_float32_interleaved)= + dlsym(twolame_handle,"twolame_encode_buffer_float32_interleaved"); + *(void **)(&twolame_encode_flush)= + dlsym(twolame_handle,"twolame_encode_flush"); + *(void **)(&twolame_set_energy_levels)= + dlsym(twolame_handle,"twolame_set_energy_levels"); + LogLine(RDConfig::LogInfo, + "Found TwoLAME encoder library, MPEG L2 encoding supported"); + return true; +#else + LogLine(RDConfig::LogInfo,"MPEG L2 encoding not enabled"); + return false; +#endif // HAVE_TWOLAME +} + + +bool MainObject::InitTwoLameEncoder(int card,int stream,int chans,int samprate, + int bitrate) +{ +#ifdef HAVE_TWOLAME + TWOLAME_MPEG_mode mpeg_mode=TWOLAME_STEREO; + + switch(chans) { + case 1: + mpeg_mode=TWOLAME_MONO; + break; + + case 2: + mpeg_mode=TWOLAME_STEREO; + break; + } + if((twolame_lameopts[card][stream]=twolame_init())==NULL) { + LogLine(RDConfig::LogErr,QString().sprintf("unable to initialize twolame instance, card=%d, stream=%d",card,stream)); + return false; + } + twolame_set_mode(twolame_lameopts[card][stream],mpeg_mode); + twolame_set_num_channels(twolame_lameopts[card][stream],chans); + twolame_set_in_samplerate(twolame_lameopts[card][stream],samprate); + twolame_set_out_samplerate(twolame_lameopts[card][stream],samprate); + twolame_set_bitrate(twolame_lameopts[card][stream],bitrate/1000); + twolame_set_energy_levels(twolame_lameopts[card][stream],1); + if(twolame_init_params(twolame_lameopts[card][stream])!=0) { + LogLine(RDConfig::LogErr,QString().sprintf("invalid twolame parameters, card=%d, stream=%d, chans=%d, samprate=%d bitrate=%d", + card,stream,chans,samprate,bitrate)); + return false; + } + return true; +#else + return false; +#endif // HAVE_TWOLAME +} + + +void MainObject::FreeTwoLameEncoder(int card,int stream) +{ +#ifdef HAVE_TWOLAME + if(twolame_lameopts[card][stream]!=NULL) { + twolame_close(&twolame_lameopts[card][stream]); + twolame_lameopts[card][stream]=NULL; + } +#endif // HAVE_TWOLAME +} + + +bool MainObject::LoadMad() +{ +#ifdef HAVE_MAD + if((mad_handle=dlopen("libmad.so",RTLD_NOW))==NULL) { + LogLine(RDConfig::LogInfo, + "MAD decoder library not found, MPEG L2 decoding not supported"); + return false; + } + *(void **)(&mad_stream_init)= + dlsym(mad_handle,"mad_stream_init"); + *(void **)(&mad_frame_init)= + dlsym(mad_handle,"mad_frame_init"); + *(void **)(&mad_synth_init)= + dlsym(mad_handle,"mad_synth_init"); + *(void **)(&mad_stream_buffer)= + dlsym(mad_handle,"mad_stream_buffer"); + *(void **)(&mad_frame_decode)= + dlsym(mad_handle,"mad_frame_decode"); + *(void **)(&mad_synth_frame)= + dlsym(mad_handle,"mad_synth_frame"); + *(void **)(&mad_frame_finish)= + dlsym(mad_handle,"mad_frame_finish"); + *(void **)(&mad_stream_finish)= + dlsym(mad_handle,"mad_stream_finish"); + LogLine(RDConfig::LogInfo, + "Found MAD decoder library, MPEG L2 decoding supported"); + return true; +#else + LogLine(RDConfig::LogInfo,"MPEG L2 decoding not enabled"); + return false; +#endif // HAVE_MAD +} + + +void MainObject::InitMadDecoder(int card,int stream,RDWaveFile *wave) +{ +#ifdef HAVE_MAD + if(mad_active[card][stream]) { + FreeMadDecoder(card,stream); + } + mad_stream_init(&mad_stream[card][stream]); + mad_frame_init(&mad_frame[card][stream]); + mad_synth_init(&mad_synth[card][stream]); + mad_frame_size[card][stream]= + 144*wave->getHeadBitRate()/wave->getSamplesPerSec(); + mad_left_over[card][stream]=0; + mad_active[card][stream]=true; +#endif // HAVE_MAD +} + + +void MainObject::FreeMadDecoder(int card,int stream) +{ +#ifdef HAVE_MAD + if(mad_active[card][stream]) { + mad_synth_finish(&mad_synth[card][stream]); + mad_frame_finish(&mad_frame[card][stream]); + mad_stream_finish(&mad_stream[card][stream]); + mad_frame_size[card][stream]=0; + mad_left_over[card][stream]=0; + mad_active[card][stream]=false; + } +#endif // HAVE_MAD +} + + +void MainObject::SendMeterLevelUpdate(const QString &type,int cardnum, + int portnum,short levels[]) +{ + char msg[1500]; + int n=snprintf(msg,1500,"ML %s %d %d %d %d", + (const char *)type,cardnum,portnum,levels[0],levels[1]); + SendMeterUpdate(msg,n); +} + + +void MainObject::SendStreamMeterLevelUpdate(int cardnum,int streamnum, + short levels[]) +{ + char msg[1500]; + int n=snprintf(msg,1500,"MO %d %d %d %d", + cardnum,streamnum,levels[0],levels[1]); + SendMeterUpdate(msg,n); +} + + +void MainObject::SendMeterPositionUpdate(int cardnum,unsigned pos[]) +{ + char msg[1500]; + int n; + for(unsigned i=0;i0) { + meter_socket->writeBlock(msg,len,socket[i]->peerAddress(),meter_port[i]); + } + } +} + + +int main(int argc,char *argv[]) +{ + int rc; + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + rc=a.exec(); + LogLine(RDConfig::LogDebug,QString().sprintf("cae post a.exec() rc:%d", rc)); + return rc; +} diff --git a/cae/cae.h b/cae/cae.h new file mode 100644 index 00000000..d84dd52a --- /dev/null +++ b/cae/cae.h @@ -0,0 +1,410 @@ +// cae.h +// +// The Core Audio Engine component of Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: cae.h,v 1.79.4.4 2012/11/30 16:14:58 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef CAE_H +#define CAE_H + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HPI +#include +#include +#include +#endif // HPI + +#ifdef ALSA +#include +struct alsa_format { + int card; + pthread_t thread; + snd_pcm_t *pcm; + unsigned channels; + unsigned capture_channels; + snd_pcm_uframes_t buffer_size; + snd_pcm_format_t format; + unsigned sample_rate; + char *card_buffer; + char *passthrough_buffer; + unsigned card_buffer_size; + unsigned periods; + bool exiting; +}; +#endif // ALSA + +#ifdef JACK +#include +#endif // JACK + +#ifdef HAVE_TWOLAME +#include +#endif // HAVE_TWOLAME +#ifdef HAVE_MAD +#include +#endif // HAVE_MAD + +#include +#include +#include + +// +// Debug Options +// +//#define PRINT_COMMANDS + +// +// Global CAE Definitions +// +#define RINGBUFFER_SIZE 262144 +#define CAED_USAGE "[-d]\n\nSupplying the '-d' flag will set 'debug' mode, causing caed(8) to stay\nin the foreground and print debugging info on standard output.\n" + +// +// Function Prototypes +// +void LogLine(RDConfig::LogPriority prio,const QString &line); +void SigHandler(int signum); +extern RDConfig *rd_config; + + +class MainObject : public QObject +{ + Q_OBJECT + public: + MainObject(QObject *parent=0,const char *name=0); + ~MainObject(); + + public slots: + void newConnection(int fd); + + private slots: + void socketData(int); + void socketKill(int); + void statePlayUpdate(int card,int stream,int state); + void stateRecordUpdate(int card,int stream,int state); + void updateMeters(); + + private: + void InitMixers(); + void ParseCommand(int); + void DispatchCommand(int); + void KillSocket(int); + void BroadcastCommand(const char *); + void EchoCommand(int,const char *); + void EchoArgs(int,const char); + bool CheckDaemon(QString); + pid_t GetPid(QString pidfile); + int GetNextHandle(); + int GetHandle(int ch,int *card,int *stream); + int GetHandle(int card,int stream); + void ProbeCaps(RDStation *station); + void ClearDriverEntries(RDStation *station); + void SendMeterLevelUpdate(const QString &type,int cardnum,int portnum, + short levels[]); + void SendStreamMeterLevelUpdate(int cardnum,int streamnum,short levels[]); + void SendMeterPositionUpdate(int cardnum,unsigned pos[]); + void SendMeterOutputStatusUpdate(); + void SendMeterOutputStatusUpdate(int card,int port,int stream); + void SendMeterUpdate(const char *msg,unsigned len); + bool debug; + unsigned system_sample_rate; + Q_INT16 tcp_port; + QServerSocket *server; + QSocketDevice *meter_socket; + RDSocket *socket[CAE_MAX_CONNECTIONS]; + Q_UINT16 meter_port[CAE_MAX_CONNECTIONS]; + char args[CAE_MAX_CONNECTIONS][CAE_MAX_ARGS][CAE_MAX_LENGTH]; + int istate[CAE_MAX_CONNECTIONS]; + int argnum[CAE_MAX_CONNECTIONS]; + int argptr[CAE_MAX_CONNECTIONS]; + bool auth[CAE_MAX_CONNECTIONS]; + RDStation::AudioDriver cae_driver[RD_MAX_CARDS]; + int record_owner[RD_MAX_CARDS][RD_MAX_STREAMS]; + int record_length[RD_MAX_CARDS][RD_MAX_STREAMS]; + int record_threshold[RD_MAX_CARDS][RD_MAX_STREAMS]; + int play_owner[RD_MAX_CARDS][RD_MAX_STREAMS]; + int play_length[RD_MAX_CARDS][RD_MAX_STREAMS]; + int play_speed[RD_MAX_CARDS][RD_MAX_STREAMS]; + bool play_pitch[RD_MAX_CARDS][RD_MAX_STREAMS]; + bool port_status[RD_MAX_CARDS][RD_MAX_PORTS]; + bool output_status_flag[RD_MAX_CARDS][RD_MAX_PORTS][RD_MAX_STREAMS]; + struct { + int card; + int stream; + int owner; + } play_handle[256]; + int next_play_handle; + + // + // HPI Driver + // + private: + void hpiInit(RDStation *station); + void hpiFree(); + QString hpiVersion(); + bool hpiLoadPlayback(int card,QString wavename,int *stream); + bool hpiUnloadPlayback(int card,int stream); + bool hpiPlaybackPosition(int card,int stream,unsigned pos); + bool hpiPlay(int card,int stream,int length,int speed,bool pitch, + bool rates); + bool hpiStopPlayback(int card,int stream); + bool hpiTimescaleSupported(int card); + bool hpiLoadRecord(int card,int port,int coding,int chans,int samprate, + int bitrate,QString wavename); + bool hpiUnloadRecord(int card,int stream,unsigned *len); + bool hpiRecord(int card,int stream,int length,int thres); + bool hpiStopRecord(int card,int stream); + bool hpiSetClockSource(int card,int src); + bool hpiSetInputVolume(int card,int stream,int level); + bool hpiSetOutputVolume(int card,int stream,int port,int level); + bool hpiFadeOutputVolume(int card,int stream,int port,int level,int length); + bool hpiSetInputLevel(int card,int port,int level); + bool hpiSetOutputLevel(int card,int port,int level); + bool hpiSetInputMode(int card,int stream,int mode); + bool hpiSetOutputMode(int card,int stream,int mode); + bool hpiSetInputVoxLevel(int card,int stream,int level); + bool hpiSetInputType(int card,int port,int type); + bool hpiGetInputStatus(int card,int port); + bool hpiGetInputMeters(int card,int port,short levels[2]); + bool hpiGetOutputMeters(int card,int port,short levels[2]); + bool hpiGetStreamOutputMeters(int card,int stream,short levels[2]); + bool hpiSetPassthroughLevel(int card,int in_port,int out_port,int level); + void hpiGetOutputPosition(int card,unsigned *pos); +#ifdef HPI + RDHPISoundCard *sound_card; + RDHPIRecordStream *record[RD_MAX_CARDS][RD_MAX_STREAMS]; + RDHPIPlayStream *play[RD_MAX_CARDS][RD_MAX_STREAMS]; +#endif // HPI + + // + // JACK Driver + // + private slots: + void jackStopTimerData(int stream); + void jackFadeTimerData(int stream); + void jackRecordTimerData(int stream); + + private: + void jackInit(RDStation *station); + void jackFree(); + bool jackLoadPlayback(int card,QString wavename,int *stream); + bool jackUnloadPlayback(int card,int stream); + bool jackPlaybackPosition(int card,int stream,unsigned pos); + bool jackPlay(int card,int stream,int length,int speed,bool pitch, + bool rates); + bool jackStopPlayback(int card,int stream); + bool jackTimescaleSupported(int card); + bool jackLoadRecord(int card,int port,int coding,int chans,int samprate, + int bitrate,QString wavename); + bool jackUnloadRecord(int card,int stream,unsigned *len); + bool jackRecord(int card,int stream,int length,int thres); + bool jackStopRecord(int card,int stream); + bool jackSetInputVolume(int card,int stream,int level); + bool jackSetOutputVolume(int card,int stream,int port,int level); + bool jackFadeOutputVolume(int card,int stream,int port,int level,int length); + bool jackSetInputLevel(int card,int port,int level); + bool jackSetOutputLevel(int card,int port,int level); + bool jackSetInputMode(int card,int stream,int mode); + bool jackSetOutputMode(int card,int stream,int mode); + bool jackSetInputVoxLevel(int card,int stream,int level); + bool jackSetInputType(int card,int port,int type); + bool jackGetInputStatus(int card,int port); + bool jackGetInputMeters(int card,int port,short levels[2]); + bool jackGetOutputMeters(int card,int port,short levels[2]); + bool jackGetStreamOutputMeters(int card,int stream,short levels[2]); + bool jackSetPassthroughLevel(int card,int in_port,int out_port,int level); + void jackGetOutputPosition(int card,unsigned *pos); + void jackConnectPorts(const QString &out,const QString &in); + void jackDisconnectPorts(const QString &out,const QString &in); + int GetJackOutputStream(); + void FreeJackOutputStream(int stream); + void EmptyJackInputStream(int stream,bool done); +#ifdef JACK + void WriteJackBuffer(int stream,jack_default_audio_sample_t *buffer, + unsigned len,bool done); +#endif // JACK + void FillJackOutputStream(int stream); + void JackClock(); + void JackSessionSetup(); + bool jack_connected; + bool jack_activated; +#ifdef JACK + int jack_card; + std::vector jack_clients; + RDWaveFile *jack_record_wave[RD_MAX_STREAMS]; + RDWaveFile *jack_play_wave[RD_MAX_STREAMS]; + short *jack_wave_buffer; + jack_default_audio_sample_t *jack_sample_buffer; + soundtouch::SoundTouch *jack_st_conv[RD_MAX_STREAMS]; + short jack_input_volume_db[RD_MAX_STREAMS]; + short jack_output_volume_db[RD_MAX_PORTS][RD_MAX_STREAMS]; + short jack_passthrough_volume_db[RD_MAX_PORTS][RD_MAX_PORTS]; + short jack_fade_volume_db[RD_MAX_STREAMS]; + short jack_fade_increment[RD_MAX_STREAMS]; + int jack_fade_port[RD_MAX_STREAMS]; + bool jack_fade_up[RD_MAX_STREAMS]; + QTimer *jack_fade_timer[RD_MAX_STREAMS]; + QTimer *jack_stop_timer[RD_MAX_STREAMS]; + QTimer *jack_record_timer[RD_MAX_PORTS]; + int jack_offset[RD_MAX_STREAMS]; + int jack_clock_phase; + unsigned jack_samples_recorded[RD_MAX_STREAMS]; +#endif // JACK + + // + // ALSA Driver + // + private slots: + void alsaStopTimerData(int cardstream); + void alsaFadeTimerData(int cardstream); + void alsaRecordTimerData(int cardport); + + private: + void alsaInit(RDStation *station); + void alsaFree(); + bool alsaLoadPlayback(int card,QString wavename,int *stream); + bool alsaUnloadPlayback(int card,int stream); + bool alsaPlaybackPosition(int card,int stream,unsigned pos); + bool alsaPlay(int card,int stream,int length,int speed,bool pitch, + bool rates); + bool alsaStopPlayback(int card,int stream); + bool alsaTimescaleSupported(int card); + bool alsaLoadRecord(int card,int port,int coding,int chans,int samprate, + int bitrate,QString wavename); + bool alsaUnloadRecord(int card,int stream,unsigned *len); + bool alsaRecord(int card,int stream,int length,int thres); + bool alsaStopRecord(int card,int stream); + bool alsaSetInputVolume(int card,int stream,int level); + bool alsaSetOutputVolume(int card,int stream,int port,int level); + bool alsaFadeOutputVolume(int card,int stream,int port,int level,int length); + bool alsaSetInputLevel(int card,int port,int level); + bool alsaSetOutputLevel(int card,int port,int level); + bool alsaSetInputMode(int card,int stream,int mode); + bool alsaSetOutputMode(int card,int stream,int mode); + bool alsaSetInputVoxLevel(int card,int stream,int level); + bool alsaSetInputType(int card,int port,int type); + bool alsaGetInputStatus(int card,int port); + bool alsaGetInputMeters(int card,int port,short levels[2]); + bool alsaGetOutputMeters(int card,int port,short levels[2]); + bool alsaGetStreamOutputMeters(int card,int stream,short levels[2]); + bool alsaSetPassthroughLevel(int card,int in_port,int out_port,int level); + void alsaGetOutputPosition(int card,unsigned *pos); + void AlsaClock(); +#ifdef ALSA + bool AlsaStartCaptureDevice(QString &dev,int card,snd_pcm_t *pcm); + bool AlsaStartPlayDevice(QString &dev,int card,snd_pcm_t *pcm); + void AlsaInitCallback(); + int GetAlsaOutputStream(int card); + void FreeAlsaOutputStream(int card,int stream); + void EmptyAlsaInputStream(int card,int stream); + void WriteAlsaBuffer(int card,int stream,short *buffer,unsigned len); + void FillAlsaOutputStream(int card,int stream); + struct alsa_format alsa_play_format[RD_MAX_CARDS]; + struct alsa_format alsa_capture_format[RD_MAX_CARDS]; + short alsa_input_volume_db[RD_MAX_CARDS][RD_MAX_STREAMS]; + short alsa_output_volume_db[RD_MAX_CARDS][RD_MAX_PORTS][RD_MAX_STREAMS]; + short alsa_passthrough_volume_db[RD_MAX_CARDS][RD_MAX_PORTS][RD_MAX_PORTS]; + short *alsa_wave_buffer; + RDWaveFile *alsa_record_wave[RD_MAX_CARDS][RD_MAX_STREAMS]; + RDWaveFile *alsa_play_wave[RD_MAX_CARDS][RD_MAX_STREAMS]; + int alsa_offset[RD_MAX_CARDS][RD_MAX_STREAMS]; + QTimer *alsa_fade_timer[RD_MAX_CARDS][RD_MAX_STREAMS]; + QTimer *alsa_stop_timer[RD_MAX_CARDS][RD_MAX_STREAMS]; + QTimer *alsa_record_timer[RD_MAX_CARDS][RD_MAX_PORTS]; + bool alsa_fade_up[RD_MAX_CARDS][RD_MAX_STREAMS]; + short alsa_fade_volume_db[RD_MAX_CARDS][RD_MAX_STREAMS]; + short alsa_fade_increment[RD_MAX_CARDS][RD_MAX_STREAMS]; + int alsa_fade_port[RD_MAX_CARDS][RD_MAX_STREAMS]; + unsigned alsa_samples_recorded[RD_MAX_CARDS][RD_MAX_STREAMS]; +#endif // ALSA + + bool CheckLame(); + + // + // TwoLAME Encoder + // + bool LoadTwoLame(); + bool InitTwoLameEncoder(int card,int stream,int chans,int samprate, + int bitrate); + void FreeTwoLameEncoder(int card,int stream); + void *twolame_handle; +#ifdef HAVE_TWOLAME + twolame_options *(*twolame_init)(void); + void (*twolame_set_mode)(twolame_options *,TWOLAME_MPEG_mode); + void (*twolame_set_num_channels)(twolame_options *,int); + void (*twolame_set_in_samplerate)(twolame_options *,int); + void (*twolame_set_out_samplerate)(twolame_options *,int); + void (*twolame_set_bitrate)(twolame_options *,int); + int (*twolame_init_params)(twolame_options *); + void (*twolame_close)(twolame_options **); + int (*twolame_encode_buffer_interleaved)(twolame_options *,const short int[], + int,unsigned char *,int); + int (*twolame_encode_buffer_float32_interleaved) + (twolame_options *,const float[],int,unsigned char *,int); + int (*twolame_encode_flush)(twolame_options *,unsigned char *,int); + int (*twolame_set_energy_levels)(twolame_options *,int); + twolame_options *twolame_lameopts[RD_MAX_CARDS][RD_MAX_STREAMS]; +#endif // HAVE_TWOLAME + + // + // MAD Decoder + // + bool LoadMad(); + void InitMadDecoder(int card,int stream,RDWaveFile *wave); + void FreeMadDecoder(int card,int stream); + void *mad_handle; +#ifdef HAVE_MAD + void (*mad_stream_init)(struct mad_stream *); + void (*mad_frame_init)(struct mad_frame *); + void (*mad_synth_init)(struct mad_synth *); + void (*mad_stream_buffer)(struct mad_stream *,unsigned char const *, + unsigned long); + int (*mad_frame_decode)(struct mad_frame *, struct mad_stream *); + void (*mad_synth_frame)(struct mad_synth *, struct mad_frame const *); + void (*mad_frame_finish)(struct mad_frame *); + void (*mad_stream_finish)(struct mad_stream *); + struct mad_stream mad_stream[RD_MAX_CARDS][RD_MAX_STREAMS]; + struct mad_frame mad_frame[RD_MAX_CARDS][RD_MAX_STREAMS]; + struct mad_synth mad_synth[RD_MAX_CARDS][RD_MAX_STREAMS]; + bool mad_active[RD_MAX_CARDS][RD_MAX_STREAMS]; + int mad_frame_size[RD_MAX_CARDS][RD_MAX_STREAMS]; + int mad_left_over[RD_MAX_CARDS][RD_MAX_STREAMS]; + unsigned char *mad_mpeg[RD_MAX_CARDS][RD_MAX_STREAMS]; +#endif // HAVE_MAD +}; + + +#endif // CAE_H diff --git a/cae/cae_alsa.cpp b/cae/cae_alsa.cpp new file mode 100644 index 00000000..787c3ca4 --- /dev/null +++ b/cae/cae_alsa.cpp @@ -0,0 +1,1893 @@ +// cae_alsa.cpp +// +// The ALSA Driver for the Core Audio Engine component of Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: cae_alsa.cpp,v 1.48.6.5 2013/06/26 23:18:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include + +#include + +#include +#include +#include + +#include + +#ifdef ALSA +// +// Callback Variables +// +volatile int alsa_input_channels[RD_MAX_CARDS][RD_MAX_PORTS]; +volatile int alsa_output_channels[RD_MAX_CARDS][RD_MAX_STREAMS]; +RDMeterAverage *alsa_input_meter[RD_MAX_CARDS][RD_MAX_PORTS][2]; +RDMeterAverage *alsa_output_meter[RD_MAX_CARDS][RD_MAX_PORTS][2]; +RDMeterAverage *alsa_stream_output_meter[RD_MAX_CARDS][RD_MAX_STREAMS][2]; +volatile double alsa_input_volume[RD_MAX_CARDS][RD_MAX_PORTS]; +volatile double alsa_output_volume[RD_MAX_CARDS][RD_MAX_PORTS][RD_MAX_STREAMS]; +volatile double + alsa_passthrough_volume[RD_MAX_CARDS][RD_MAX_PORTS][RD_MAX_PORTS]; +volatile double alsa_input_vox[RD_MAX_CARDS][RD_MAX_PORTS]; +RDRingBuffer *alsa_play_ring[RD_MAX_CARDS][RD_MAX_STREAMS]; +RDRingBuffer *alsa_record_ring[RD_MAX_CARDS][RD_MAX_PORTS]; +RDRingBuffer *alsa_passthrough_ring[RD_MAX_CARDS][RD_MAX_PORTS]; +volatile bool alsa_playing[RD_MAX_CARDS][RD_MAX_STREAMS]; +volatile bool alsa_stopping[RD_MAX_CARDS][RD_MAX_STREAMS]; +volatile bool alsa_eof[RD_MAX_CARDS][RD_MAX_STREAMS]; +volatile int alsa_output_pos[RD_MAX_CARDS][RD_MAX_STREAMS]; +volatile bool alsa_recording[RD_MAX_CARDS][RD_MAX_PORTS]; +volatile bool alsa_ready[RD_MAX_CARDS][RD_MAX_PORTS]; +volatile int alsa_channels; + + +void AlsaCapture1Callback(struct alsa_format *alsa_format) +{ +} + + +void AlsaCapture2Callback(struct alsa_format *alsa_format) +{ + char alsa_buffer[RINGBUFFER_SIZE]; + int modulo; + short in_meter[RD_MAX_PORTS][2]; + + while(!alsa_format->exiting) { + int s=snd_pcm_readi(alsa_format->pcm,alsa_format->card_buffer, + rd_config->alsaPeriodSize()/(alsa_format->periods*2)); + if(((snd_pcm_state(alsa_format->pcm)!=SND_PCM_STATE_RUNNING)&& + (!alsa_format->exiting))||(s<0)) { + snd_pcm_drop (alsa_format->pcm); + snd_pcm_prepare(alsa_format->pcm); + LogLine(RDConfig::LogNotice,QString(). + sprintf("****** ALSA Capture Xrun - Card: %d ******", + alsa_format->card)); + } + else { + switch(alsa_format->format) { + case SND_PCM_FORMAT_S16_LE: + modulo=alsa_format->channels; + for(unsigned i=0;i<(alsa_format->channels/2);i++) { + if(alsa_recording[alsa_format->card][i]) { + if(alsa_input_volume[alsa_format->card][i]!=0.0) { + switch(alsa_input_channels[alsa_format->card][i]) { + case 1: + for(int k=0;k<(2*s);k++) { + ((short *)alsa_buffer)[k]= + (short)(alsa_input_volume[alsa_format->card][i]* + (double)(((short *)alsa_format-> + card_buffer) + [modulo*k+2*i]))+ + (short)(alsa_input_volume[alsa_format->card][i]* + (double)(((short *)alsa_format-> + card_buffer) + [modulo*k+2*i+1])); + } + alsa_record_ring[alsa_format->card][i]-> + write(alsa_buffer,s*sizeof(short)); + break; + + case 2: + for(int k=0;kcard][i]* + (double)(((short *)alsa_format-> + card_buffer) + [modulo*k+2*i])); + ((short *)alsa_buffer)[2*k+1]= + (short)(alsa_input_volume[alsa_format->card][i]* + (double)(((short *)alsa_format-> + card_buffer) + [modulo*k+2*i+1])); + } + alsa_record_ring[alsa_format->card][i]-> + write(alsa_buffer,s*2*sizeof(short)); + break; + } + } + } + } + + // + // Process Passthroughs + // + for(unsigned i=0;ichannels;i+=2) { + for(unsigned j=0;j<2;j++) { + for(int k=0;kpassthrough_buffer)[2*k+j]= + ((short *)alsa_format-> + card_buffer)[alsa_format->channels*k+2*i+j]; + } + } + if(alsa_passthrough_ring[alsa_format->card][i/2]==NULL) { + printf("RING ERROR Card=%d Port=%d\n",alsa_format->card,i/2); + } + else { + alsa_passthrough_ring[alsa_format->card][i/2]-> + write(alsa_format->passthrough_buffer,4*s); + } + } + + // + // Process Input Meters + // + for(unsigned i=0;ichannels;i+=2) { + for(unsigned j=0;j<2;j++) { + in_meter[i/2][j]=0; + for(int k=0;k + card_buffer)[alsa_format->channels*k+2*i+j]> + in_meter[i][j]) { + in_meter[i][j]= + ((short *)alsa_format-> + card_buffer)[alsa_format->channels*k+2*i+j]; + } + } + alsa_input_meter[alsa_format->card][i/2][j]-> + addValue(((double)in_meter[i/2][j])/32768.0); + } + } + break; + + case SND_PCM_FORMAT_S32_LE: + modulo=alsa_format->channels*2; + for(unsigned i=0;i<(alsa_format->channels/2);i++) { + if(alsa_recording[alsa_format->card][i]) { + if(alsa_input_volume[alsa_format->card][i]!=0.0) { + switch(alsa_input_channels[alsa_format->card][i]) { + case 1: + for(int k=0;k<(2*s);k++) { + ((short *)alsa_buffer)[k]= + (short)(alsa_input_volume[alsa_format->card][i]* + (double)(((short *)alsa_format-> + card_buffer) + [modulo*k+4*i+1]))+ + (short)(alsa_input_volume[alsa_format->card][i]* + (double)(((short *)alsa_format-> + card_buffer) + [modulo*k+4*i+3])); + } + alsa_record_ring[alsa_format->card][i]-> + write(alsa_buffer,s*sizeof(short)); + break; + + case 2: + for(int k=0;kcard][i]* + (double)(((short *)alsa_format->card_buffer) + [modulo*k+4*i+1])); + ((short *)alsa_buffer)[2*k+1]= + (short)(alsa_input_volume[alsa_format->card][i]* + (double)(((short *)alsa_format->card_buffer) + [modulo*k+4*i+3])); + } + alsa_record_ring[alsa_format->card][i]-> + write(alsa_buffer,s*2*sizeof(short)); + break; + } + } + } + } + + // + // Process Passthroughs + // + for(unsigned i=0;ichannels;i+=2) { + for(unsigned j=0;j<2;j++) { + for(int k=0;kpassthrough_buffer)[2*k+j]= + ((short *)alsa_format-> + card_buffer)[alsa_format->channels*2*k+2*i+1+2*j]; + } + } + alsa_passthrough_ring[alsa_format->card][i/2]-> + write(alsa_format->passthrough_buffer,4*s); + } + + // + // Process Input Meters + // + for(unsigned i=0;ichannels;i+=2) { + for(unsigned j=0;j<2;j++) { + in_meter[i/2][j]=0; + for(int k=0;k + card_buffer)[alsa_format->channels*2*k+2*i+1+2*j]> + in_meter[i/2][j]) { + in_meter[i/2][j]= + ((short *)alsa_format-> + card_buffer)[alsa_format->channels*2*k+2*i+1+2*j]; + } + } + alsa_input_meter[alsa_format->card][i/2][j]-> + addValue(((double)in_meter[i/2][j])/32768.0); + } + } + break; + + default: + break; + } + } + } +} + + +void *AlsaCaptureCallback(void *ptr) +{ + struct alsa_format *alsa_format=(struct alsa_format *)ptr; + + signal(SIGTERM,SigHandler); + signal(SIGINT,SigHandler); + + switch(alsa_channels) { + case 1: + AlsaCapture1Callback(alsa_format); + break; + + case 2: + AlsaCapture2Callback(alsa_format); + break; + } + return 0; +} + + +void AlsaPlay1Callback(struct alsa_format *alsa_format) +{ +} + + +void AlsaPlay2Callback(struct alsa_format *alsa_format) +{ + int n=0; + int p; + char alsa_buffer[RINGBUFFER_SIZE]; + int modulo; + short out_meter[RD_MAX_PORTS][2]; + short stream_out_meter=0; + + while(!alsa_format->exiting) { + memset(alsa_format->card_buffer,0,alsa_format->card_buffer_size); + + switch(alsa_format->format) { + case SND_PCM_FORMAT_S16_LE: + for(unsigned j=0;jcard][j]) { + switch(alsa_output_channels[alsa_format->card][j]) { + case 1: + n=alsa_play_ring[alsa_format->card][j]-> + read(alsa_buffer,alsa_format-> + buffer_size/alsa_format->periods)/ + (2*sizeof(short)); + stream_out_meter=0; // Stream Output Meters + for(int k=0;kstream_out_meter) { + stream_out_meter=abs(((short *)alsa_buffer)[k]); + } + } + alsa_stream_output_meter[alsa_format->card][j][0]-> + addValue(((double)stream_out_meter)/32768.0); + alsa_stream_output_meter[alsa_format->card][j][1]-> + addValue(((double)stream_out_meter)/32768.0); + modulo=alsa_format->channels; + for(unsigned i=0;i<(alsa_format->channels/2);i++) { + if(alsa_output_volume[alsa_format->card][i][j]!=0.0) { + for(int k=0;k<(2*n);k++) { + ((short *)alsa_format->card_buffer)[modulo*k+2*i]+= + (short)(alsa_output_volume[alsa_format->card][i][j]* + (double)(((short *)alsa_buffer)[k])); + ((short *)alsa_format->card_buffer)[modulo*k+2*i+1]+= + (short)(alsa_output_volume[alsa_format->card][i][j]* + (double)(((short *)alsa_buffer)[k])); + } + } + } + n*=2; + break; + + case 2: + n=alsa_play_ring[alsa_format->card][j]-> + read(alsa_buffer,alsa_format->buffer_size*2/ + alsa_format->periods)/(2*sizeof(short)); + for(unsigned k=0;k<2;k++) { // Stream Output Meters + stream_out_meter=0; + for(int l=0;lstream_out_meter) { + stream_out_meter=abs(((short *)alsa_buffer)[l+k]); + } + } + alsa_stream_output_meter[alsa_format->card][j][k]-> + addValue(((double)stream_out_meter)/32768.0); + } + modulo=alsa_format->channels; + for(unsigned i=0;i<(alsa_format->channels/2);i++) { + if(alsa_output_volume[alsa_format->card][i][j]!=0.0) { + for(int k=0;kcard_buffer)[modulo*k+2*i]+= + (short)(alsa_output_volume[alsa_format->card][i][j]* + (double)(((short *)alsa_buffer)[2*k])); + ((short *)alsa_format->card_buffer)[modulo*k+2*i+1]+= + (short)(alsa_output_volume[alsa_format->card][i][j]* + (double)(((short *)alsa_buffer)[2*k+1])); + } + } + } + break; + } + alsa_output_pos[alsa_format->card][j]+=n; + if((n==0)&&alsa_eof[alsa_format->card][j]) { + alsa_stopping[alsa_format->card][j]=true; + } + } + } + n=alsa_format->buffer_size/(2*alsa_format->periods); + + // + // Process Passthroughs + // + for(unsigned i=0;icapture_channels;i+=2) { + p=alsa_passthrough_ring[alsa_format->card][i/2]-> + read(alsa_format->passthrough_buffer,4*n)/4; + for(unsigned j=0;jchannels;j+=2) { + if(alsa_passthrough_volume[alsa_format->card][i/2][j/2]>0.0) { + for(unsigned k=0;k<2;k++) { + for(int l=0;l + card_buffer)[alsa_format->channels*l+4*j+1+k]+=(short) + ((double)((short *)alsa_format-> + passthrough_buffer)[2*l+1]* + alsa_passthrough_volume[alsa_format->card][i/2][j/2]); + } + } + } + } + } + + // + // Process Output Meters + // + for(unsigned i=0;ichannels;i+=2) { + unsigned port=i/2; + for(unsigned j=0;j<2;j++) { + out_meter[port][j]=0; + for(unsigned k=0;kbuffer_size;k++) { + if(((short *)alsa_format-> + card_buffer)[alsa_format->channels*k+2*i+j]> + out_meter[i][j]) { + out_meter[i][j]= + ((short *)alsa_format-> + card_buffer)[alsa_format->channels*k+2*i+j]; + } + } + alsa_output_meter[alsa_format->card][i][j]-> + addValue(((double)out_meter[i][j])/32768.0); + } + } + break; + + case SND_PCM_FORMAT_S32_LE: + for(unsigned j=0;jcard][j]) { + switch(alsa_output_channels[alsa_format->card][j]) { + case 1: + n=alsa_play_ring[alsa_format->card][j]-> + read(alsa_buffer,alsa_format->buffer_size/ + alsa_format->periods)/(2*sizeof(short)); + stream_out_meter=0; + for(int k=0;kstream_out_meter) { + stream_out_meter=abs(((short *)alsa_buffer)[k]); + } + } + alsa_stream_output_meter[alsa_format->card][j][0]-> + addValue(((double)stream_out_meter)/32768.0); + alsa_stream_output_meter[alsa_format->card][j][1]-> + addValue(((double)stream_out_meter)/32768.0); + modulo=alsa_format->channels*2; + for(unsigned i=0;i<(alsa_format->channels/2);i++) { + if(alsa_output_volume[alsa_format->card][i][j]!=0.0) { + for(int k=0;k<(2*n);k++) { + ((short *)alsa_format->card_buffer)[modulo*k+4*i+1]+= + (short)(alsa_output_volume[alsa_format->card][i][j]* + (double)(((short *)alsa_buffer)[k])); + ((short *)alsa_format->card_buffer)[modulo*k+4*i+3]+= + (short)(alsa_output_volume[alsa_format->card][i][j]* + (double)(((short *)alsa_buffer)[k])); + } + } + } + n*=2; + break; + + case 2: + n=alsa_play_ring[alsa_format->card][j]-> + read(alsa_buffer,alsa_format->buffer_size*2/ + alsa_format->periods)/(2*sizeof(short)); + for(unsigned k=0;k<2;k++) { // Stream Output Meters + stream_out_meter=0; + for(int l=0;lstream_out_meter) { + stream_out_meter=abs(((short *)alsa_buffer)[l+k]); + } + } + alsa_stream_output_meter[alsa_format->card][j][k]-> + addValue(((double)stream_out_meter)/32768.0); + } + modulo=alsa_format->channels*2; + for(unsigned i=0;i<(alsa_format->channels/2);i++) { + if(alsa_output_volume[alsa_format->card][i][j]!=0.0) { + for(int k=0;kcard_buffer)[modulo*k+4*i+1]+= + (short)(alsa_output_volume[alsa_format->card][i][j]* + (double)(((short *)alsa_buffer)[2*k])); + ((short *)alsa_format->card_buffer)[modulo*k+4*i+3]+= + (short)(alsa_output_volume[alsa_format->card][i][j]* + (double)(((short *)alsa_buffer)[2*k+1])); + } + } + } + break; + } + alsa_output_pos[alsa_format->card][j]+=n; + if((n==0)&&alsa_eof[alsa_format->card][j]) { + alsa_stopping[alsa_format->card][j]=true; + // Empty the ring buffer + while(alsa_play_ring[alsa_format->card][j]-> + read(alsa_buffer,alsa_format->buffer_size*2/ + alsa_format->periods)/(2*sizeof(short))>0); + } + } + } + n=alsa_format->buffer_size/(2*alsa_format->periods); + + // + // Process Passthroughs + // + for(unsigned i=0;icapture_channels;i+=2) { + p=alsa_passthrough_ring[alsa_format->card][i/2]-> + read(alsa_format->passthrough_buffer,4*n)/4; + for(unsigned j=0;jchannels;j+=2) { + if(alsa_passthrough_volume[alsa_format->card][i/2][j/2]>0.0) { + for(unsigned k=0;k<2;k++) { + for(int l=0;l + card_buffer)[alsa_format->channels*2*l+4*j+1+2*k]+= + (short)((double) + ((short *)alsa_format->passthrough_buffer)[2*l]* + alsa_passthrough_volume[alsa_format->card][i/2][j/2]); + ((short *)alsa_format-> + card_buffer)[alsa_format->channels*2*l+4*j+3+2*k]+= + ((short *)alsa_format->passthrough_buffer)[2*l+1]; + } + } + } + } + } + + // + // Process Output Meters + // + for(unsigned i=0;ichannels;i+=2) { + unsigned port=i/2; + for(unsigned j=0;j<2;j++) { + out_meter[port][j]=0; + for(unsigned k=0; + k<(alsa_format->buffer_size*2/alsa_format->periods); + k++) { + if(((short *)alsa_format-> + card_buffer)[alsa_format->channels*2*k+2*i+1+2*j]> + out_meter[port][j]) { + out_meter[port][j]= + ((short *)alsa_format-> + card_buffer)[alsa_format->channels*2*k+2*i+1+2*j]; + } + } + alsa_output_meter[alsa_format->card][port][j]-> + addValue(((double)out_meter[port][j])/32768.0); + } + } + break; + + default: + break; + } + int s=snd_pcm_writei(alsa_format->pcm,alsa_format->card_buffer,n); + if(s!=n) { + if(s<0) { + LogLine(RDConfig::LogNotice, + QString().sprintf("*** alsa error %d: %s",-s,snd_strerror(s))); + } + else { + LogLine(RDConfig::LogNotice, + QString().sprintf("period size mismatch - wrote %d\n",s)); + } + } + if((snd_pcm_state(alsa_format->pcm)!=SND_PCM_STATE_RUNNING)&& + (!alsa_format->exiting)) { + snd_pcm_drop (alsa_format->pcm); + snd_pcm_prepare(alsa_format->pcm); + LogLine(RDConfig::LogNotice,QString(). + sprintf("****** ALSA Playout Xrun - Card: %d ******", + alsa_format->card)); + } + } +} + + +void *AlsaPlayCallback(void *ptr) +{ + struct alsa_format *alsa_format=(struct alsa_format *)ptr; + + signal(SIGTERM,SigHandler); + signal(SIGINT,SigHandler); + + switch(alsa_channels) { + case 1: + AlsaPlay1Callback(alsa_format); + break; + + case 2: + AlsaPlay2Callback(alsa_format); + break; + } + return 0; +} + + +void MainObject::AlsaInitCallback() +{ + int avg_periods= + (330*system_sample_rate)/(1000*rd_config->alsaPeriodSize()); + for(int i=0;ireset(); + alsa_record_ring[i][j]=NULL; + for(int k=0;k=alsa_fade_volume_db[card][stream]) { + level=alsa_fade_volume_db[card][stream]; + alsa_fade_timer[card][stream]->stop(); + } + } + else { + level=alsa_output_volume_db[card][alsa_fade_port[card][stream]][stream]- + alsa_fade_increment[card][stream]; + if(level<=alsa_fade_volume_db[card][stream]) { + level=alsa_fade_volume_db[card][stream]; + alsa_fade_timer[card][stream]->stop(); + } + } + LogLine(RDConfig::LogDebug,QString().sprintf("FadeLevel: %d",level)); + alsaSetOutputVolume(card,stream,alsa_fade_port[card][stream],level); +#endif // ALSA +} + + +void MainObject::alsaRecordTimerData(int cardport) +{ +#ifdef ALSA + int card=cardport/RD_MAX_PORTS; + int stream=cardport-card*RD_MAX_PORTS; + + alsaStopRecord(card,stream); + stateRecordUpdate(card,stream,2); +#endif // ALSA +} + + +void MainObject::alsaInit(RDStation *station) +{ +#ifdef ALSA + QString dev; + int card=0; + snd_pcm_t *pcm_play_handle; + snd_pcm_t *pcm_capture_handle; + snd_ctl_t *snd_ctl; + snd_ctl_card_info_t *card_info=NULL; + bool pcm_opened; + + // + // Initialize Data Structures + // + for(int i=0;ichannels(); + + // + // Stop & Fade Timers + // + QSignalMapper *stop_mapper=new QSignalMapper(this,"stop_mapper"); + connect(stop_mapper,SIGNAL(mapped(int)),this,SLOT(alsaStopTimerData(int))); + QSignalMapper *fade_mapper=new QSignalMapper(this,"fade_mapper"); + connect(fade_mapper,SIGNAL(mapped(int)),this,SLOT(alsaFadeTimerData(int))); + QSignalMapper *record_mapper=new QSignalMapper(this,"record_mapper"); + connect(record_mapper,SIGNAL(mapped(int)), + this,SLOT(alsaRecordTimerData(int))); + for(int i=0;isetMapping(alsa_stop_timer[i][j],i*RD_MAX_STREAMS+j); + connect(alsa_stop_timer[i][j],SIGNAL(timeout()),stop_mapper,SLOT(map())); + alsa_fade_timer[i][j]=new QTimer(this); + fade_mapper->setMapping(alsa_fade_timer[i][j],i*RD_MAX_STREAMS+j); + connect(alsa_fade_timer[i][j],SIGNAL(timeout()),fade_mapper,SLOT(map())); + } + for(int j=0;jsetMapping(alsa_record_timer[i][j],i*RD_MAX_PORTS+j); + connect(alsa_record_timer[i][j],SIGNAL(timeout()), + record_mapper,SLOT(map())); + } + } + + // + // Allocate Temporary Buffers + // + AlsaInitCallback(); + alsa_wave_buffer=new short[RINGBUFFER_SIZE]; + //alsa_resample_buffer=new short[2*RINGBUFFER_SIZE]; + + // + // Start Up Interfaces + // + for(int i=0;isetCardDriver(i,RDStation::Alsa); + if(snd_ctl_open(&snd_ctl,dev,0)<0) { + LogLine(RDConfig::LogNotice,QString(). + sprintf("no control device found for %s", + (const char *)dev)); + station-> + setCardName(i, + QString().sprintf("ALSA Device %s",(const char *)dev)); + } + else { + snd_ctl_card_info_malloc(&card_info); + snd_ctl_card_info(snd_ctl,card_info); + station-> + setCardName(i,snd_ctl_card_info_get_longname(card_info)); + snd_ctl_close(snd_ctl); + } + station-> + setCardInputs(i, + alsa_capture_format[i].channels/rd_config->channels()); + station-> + setCardOutputs(i,alsa_play_format[i].channels/rd_config->channels()); + } + else { + i--; + } + card++; + if(!pcm_opened) { + return; + } + } + } +#endif // ALSA +} + + +void MainObject::alsaFree() +{ +#ifdef ALSA + for(int i=0;iopenWave()) { + LogLine(RDConfig::LogErr,QString().sprintf( + "Error: alsaLoadPlayback(%s) openWave() failed to open file", + (const char *) wavename) ); + delete alsa_play_wave[card][*stream]; + alsa_play_wave[card][*stream]=NULL; + FreeAlsaOutputStream(card,*stream); + *stream=-1; + return false; + } + switch(alsa_play_wave[card][*stream]->getFormatTag()) { + case WAVE_FORMAT_PCM: + case WAVE_FORMAT_VORBIS: + break; + + case WAVE_FORMAT_MPEG: + InitMadDecoder(card,*stream,alsa_play_wave[card][*stream]); + break; + + default: + LogLine(RDConfig::LogErr,QString().sprintf( + "Error: alsaLoadPlayback(%s) getFormatTag()%d || getBistsPerSample()%d failed", + (const char *) wavename, + alsa_play_wave[card][*stream]->getFormatTag(), + alsa_play_wave[card][*stream]->getBitsPerSample() )); + delete alsa_play_wave[card][*stream]; + alsa_play_wave[card][*stream]=NULL; + FreeAlsaOutputStream(card,*stream); + *stream=-1; + return false; + } + alsa_output_channels[card][*stream]= + alsa_play_wave[card][*stream]->getChannels(); + alsa_stopping[card][*stream]=false; + alsa_offset[card][*stream]=0; + alsa_output_pos[card][*stream]=0; + alsa_eof[card][*stream]=false; + alsa_play_ring[card][*stream]->reset(); + FillAlsaOutputStream(card,*stream); + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaUnloadPlayback(int card,int stream) +{ +#ifdef ALSA + if(alsa_play_ring[card][stream]==NULL) { + return false; + } + alsa_playing[card][stream]=false; + switch(alsa_play_wave[card][stream]->getFormatTag()) { + case WAVE_FORMAT_MPEG: + FreeMadDecoder(card,stream); + break; + } + alsa_play_wave[card][stream]->closeWave(); + delete alsa_play_wave[card][stream]; + alsa_play_wave[card][stream]=NULL; + FreeAlsaOutputStream(card,stream); + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaPlaybackPosition(int card,int stream,unsigned pos) +{ +#ifdef ALSA + unsigned offset=0; + + if(alsa_play_format[card].exiting){ + return false; + } + switch(alsa_play_wave[card][stream]->getFormatTag()) { + case WAVE_FORMAT_PCM: + offset=(unsigned)((double)alsa_play_wave[card][stream]->getSamplesPerSec()* + (double)alsa_play_wave[card][stream]->getBlockAlign()* + (double)pos/1000); + alsa_offset[card][stream]= + offset/alsa_play_wave[card][stream]->getBlockAlign(); + offset= + alsa_offset[card][stream]*alsa_play_wave[card][stream]->getBlockAlign(); + break; + + case WAVE_FORMAT_MPEG: + offset=(unsigned)((double)alsa_play_wave[card][stream]->getSamplesPerSec()* + (double)pos/1000); + alsa_offset[card][stream]=offset/1152*1152; + offset=alsa_offset[card][stream]/1152* + alsa_play_wave[card][stream]->getBlockAlign(); + FreeMadDecoder(card,stream); + InitMadDecoder(card,stream,alsa_play_wave[card][stream]); + break; + } + if(alsa_offset[card][stream]> + (int)alsa_play_wave[card][stream]->getSampleLength()) { + return false; + } + alsa_output_pos[card][stream]=0; + alsa_play_wave[card][stream]->seekWave(offset,SEEK_SET); + alsa_eof[card][stream]=false; + alsa_play_ring[card][stream]->reset(); + FillAlsaOutputStream(card,stream); + + if(alsa_playing[card][stream]) { + alsa_stop_timer[card][stream]->stop(); + alsa_stop_timer[card][stream]-> + start(alsa_play_wave[card][stream]->getExtTimeLength()-pos,true); + } + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaPlay(int card,int stream,int length,int speed,bool pitch, + bool rates) +{ +#ifdef ALSA + if((alsa_play_ring[card][stream]==NULL)|| + alsa_playing[card][stream]||(speed!=RD_TIMESCALE_DIVISOR)) { + return false; + } + alsa_playing[card][stream]=true; + if(length>0) { + alsa_stop_timer[card][stream]->start(length,true); + } + statePlayUpdate(card,stream,1); + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaTimescaleSupported(int card) +{ +#ifdef ALSA + return false; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaStopPlayback(int card,int stream) +{ +#ifdef ALSA + if((alsa_play_ring[card][stream]==NULL)||(!alsa_playing[card][stream])) { + return false; + } + alsa_playing[card][stream]=false; + alsa_play_ring[card][stream]->reset(); + alsa_stop_timer[card][stream]->stop(); + statePlayUpdate(card,stream,2); + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaLoadRecord(int card,int stream,int coding,int chans, + int samprate,int bitrate,QString wavename) +{ +#ifdef ALSA + alsa_record_wave[card][stream]=new RDWaveFile(wavename); + switch(coding) { + case 0: // PCM16 + alsa_record_wave[card][stream]->setFormatTag(WAVE_FORMAT_PCM); + alsa_record_wave[card][stream]->setChannels(chans); + alsa_record_wave[card][stream]->setSamplesPerSec(samprate); + alsa_record_wave[card][stream]->setBitsPerSample(16); + break; + + case 2: // MPEG Layer 2 + if(!InitTwoLameEncoder(card,stream,chans,samprate,bitrate)) { + delete alsa_record_wave[card][stream]; + alsa_record_wave[card][stream]=NULL; + return false; + } + alsa_record_wave[card][stream]->setFormatTag(WAVE_FORMAT_MPEG); + alsa_record_wave[card][stream]->setChannels(chans); + alsa_record_wave[card][stream]->setSamplesPerSec(samprate); + alsa_record_wave[card][stream]->setBitsPerSample(16); + alsa_record_wave[card][stream]->setHeadLayer(ACM_MPEG_LAYER2); + switch(chans) { + case 1: + alsa_record_wave[card][stream]->setHeadMode(ACM_MPEG_SINGLECHANNEL); + break; + + case 2: + alsa_record_wave[card][stream]->setHeadMode(ACM_MPEG_STEREO); + break; + + default: + LogLine(RDConfig::LogErr,QString(). + sprintf("requested unsupported channel count %d, card: %d, stream: %d", + chans,card,stream)); + delete alsa_record_wave[card][stream]; + alsa_record_wave[card][stream]=NULL; + return false; + } + alsa_record_wave[card][stream]->setHeadBitRate(bitrate); + alsa_record_wave[card][stream]->setMextChunk(true); + alsa_record_wave[card][stream]->setMextHomogenous(true); + alsa_record_wave[card][stream]->setMextPaddingUsed(false); + alsa_record_wave[card][stream]->setMextHackedBitRate(true); + alsa_record_wave[card][stream]->setMextFreeFormat(false); + alsa_record_wave[card][stream]-> + setMextFrameSize(144*alsa_record_wave[card][stream]->getHeadBitRate()/ + alsa_record_wave[card][stream]->getSamplesPerSec()); + alsa_record_wave[card][stream]->setMextAncillaryLength(5); + alsa_record_wave[card][stream]->setMextLeftEnergyPresent(true); + if(chans>1) { + alsa_record_wave[card][stream]->setMextRightEnergyPresent(true); + } + else { + alsa_record_wave[card][stream]->setMextRightEnergyPresent(false); + } + alsa_record_wave[card][stream]->setMextPrivateDataPresent(false); + break; + + default: + LogLine(RDConfig::LogErr,QString(). + sprintf("requested invalid audio encoding %d, card: %d, stream: %d", + coding,card,stream)); + delete alsa_record_wave[card][stream]; + alsa_record_wave[card][stream]=NULL; + return false; + } + alsa_record_wave[card][stream]->setBextChunk(true); + alsa_record_wave[card][stream]->setLevlChunk(true); + if(!alsa_record_wave[card][stream]->createWave()) { + delete alsa_record_wave[card][stream]; + alsa_record_wave[card][stream]=NULL; + return false; + } + chown((const char *)wavename,rd_config->uid(),rd_config->gid()); + alsa_input_channels[card][stream]=chans; + alsa_record_ring[card][stream]=new RDRingBuffer(RINGBUFFER_SIZE); + alsa_record_ring[card][stream]->reset(); + alsa_ready[card][stream]=true; + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaUnloadRecord(int card,int stream,unsigned *len) +{ +#ifdef ALSA + alsa_recording[card][stream]=false; + alsa_ready[card][stream]=false; + EmptyAlsaInputStream(card,stream); + *len=alsa_samples_recorded[card][stream]; + alsa_samples_recorded[card][stream]=0; + alsa_record_wave[card][stream]->closeWave(*len); + delete alsa_record_wave[card][stream]; + alsa_record_wave[card][stream]=NULL; + delete alsa_record_ring[card][stream]; + alsa_record_ring[card][stream]=NULL; + FreeTwoLameEncoder(card,stream); + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaRecord(int card,int stream,int length,int thres) +{ +#ifdef ALSA + if(!alsa_ready[card][stream]) { + return false; + } + alsa_recording[card][stream]=true; + if(alsa_input_vox[card][stream]==0.0) { + if(length>0) { + alsa_record_timer[card][stream]->start(length,true); + } + stateRecordUpdate(card,stream,4); + } + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaStopRecord(int card,int stream) +{ +#ifdef ALSA + if(!alsa_recording[card][stream]) { + return false; + } + alsa_recording[card][stream]=false; + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaSetInputVolume(int card,int stream,int level) +{ +#ifdef ALSA + if(level>-10000) { + alsa_input_volume[card][stream]=pow10((double)level/2000.0); + alsa_input_volume_db[card][stream]=level; + } + else { + alsa_input_volume[card][stream]=0.0; + alsa_input_volume_db[card][stream]=-10000; + } + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaSetOutputVolume(int card,int stream,int port,int level) +{ +#ifdef ALSA + if(level>-10000) { + alsa_output_volume[card][port][stream]=pow10((double)level/2000.0); + alsa_output_volume_db[card][port][stream]=level; + } + else { + alsa_output_volume[card][port][stream]=0.0; + alsa_output_volume_db[card][port][stream]=-10000; + } + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaFadeOutputVolume(int card,int stream,int port,int level, + int length) +{ +#ifdef ALSA + int diff; + + if(alsa_fade_timer[card][stream]->isActive()) { + alsa_fade_timer[card][stream]->stop(); + } + if(level>alsa_output_volume_db[card][port][stream]) { + alsa_fade_up[card][stream]=true; + diff=level-alsa_output_volume_db[card][port][stream]; + } + else { + alsa_fade_up[card][stream]=false; + diff=alsa_output_volume_db[card][port][stream]-level; + } + alsa_fade_volume_db[card][stream]=level; + alsa_fade_port[card][stream]=port; + alsa_fade_increment[card][stream]=diff*RD_ALSA_FADE_INTERVAL/length; + alsa_fade_timer[card][stream]->start(RD_ALSA_FADE_INTERVAL); + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaSetInputLevel(int card,int port,int level) +{ +#ifdef ALSA + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaSetOutputLevel(int card,int port,int level) +{ +#ifdef ALSA + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaSetInputMode(int card,int stream,int mode) +{ +#ifdef ALSA + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaSetOutputMode(int card,int stream,int mode) +{ +#ifdef ALSA + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaSetInputVoxLevel(int card,int stream,int level) +{ +#ifdef ALSA + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaSetInputType(int card,int port,int type) +{ +#ifdef ALSA + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaGetInputStatus(int card,int port) +{ +#ifdef ALSA + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaGetInputMeters(int card,int port,short levels[2]) +{ +#ifdef ALSA + double meter; + + for(int i=0;i<2;i++) { + + meter=alsa_input_meter[card][port][i]->average(); + if(meter==0.0) { + levels[i]=-10000; + } + else { + levels[i]=(short)(2000.0*log10(meter)); + if(levels[i]<-10000) { + levels[i]=-10000; + } + } + } + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaGetOutputMeters(int card,int port,short levels[2]) +{ +#ifdef ALSA + double meter; + + for(int i=0;i<2;i++) { + meter=alsa_output_meter[card][port][i]->average(); + if(meter==0.0) { + levels[i]=-10000; + } + else { + levels[i]=(short)(2000.0*log10(meter)); + if(levels[i]<-10000) { + levels[i]=-10000; + } + } + } + return true; +#else + return false; +#endif // ALSA +} + + +bool MainObject::alsaGetStreamOutputMeters(int card,int stream,short levels[2]) +{ +#ifdef ALSA + double meter; + + for(int i=0;i<2;i++) { + meter=alsa_stream_output_meter[card][stream][i]->average(); + if(meter==0.0) { + levels[i]=-10000; + } + else { + levels[i]=(short)(2000.0*log10(meter)); + if(levels[i]<-10000) { + levels[i]=-10000; + } + } + } + return true; +#else + return false; +#endif // ALSA +} + + +void MainObject::alsaGetOutputPosition(int card,unsigned *pos) +{// pos is in miliseconds +#ifdef ALSA + for(int i=0;igetSamplesPerSec(); + } + else { + pos[i]=0; + } + } +#endif // ALSA +} + + +bool MainObject::alsaSetPassthroughLevel(int card,int in_port,int out_port, + int level) +{ +#ifdef ALSA + if(level>-10000) { + alsa_passthrough_volume[card][in_port][out_port]= + pow10((double)level/2000.0); + alsa_passthrough_volume_db[card][in_port][out_port]=level; + } + else { + alsa_passthrough_volume[card][in_port][out_port]=0.0; + alsa_passthrough_volume_db[card][in_port][out_port]=-10000; + } + return true; +#else + return false; +#endif // ALSA +} + + +#ifdef ALSA +bool MainObject::AlsaStartCaptureDevice(QString &dev,int card,snd_pcm_t *pcm) +{ + snd_pcm_hw_params_t *hwparams; + snd_pcm_sw_params_t *swparams; + int dir; + int err; + pthread_attr_t pthread_attr; + unsigned sr; + + memset(&alsa_capture_format[card],0,sizeof(struct alsa_format)); + + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_hw_params_any(pcm,hwparams); + + LogLine(RDConfig::LogInfo,QString(). + sprintf("Starting ALSA Capture Device %s:", + (const char *)dev)); + + // + // Access Type + // + if(snd_pcm_hw_params_test_access(pcm,hwparams, + SND_PCM_ACCESS_RW_INTERLEAVED)<0) { + LogLine(RDConfig::LogErr," Interleaved access not supported,"); + LogLine(RDConfig::LogErr," aborting initialization of device."); + return false; + } + snd_pcm_hw_params_set_access(pcm,hwparams,SND_PCM_ACCESS_RW_INTERLEAVED); + + // + // Sample Format + // + if(snd_pcm_hw_params_test_format(pcm,hwparams,SND_PCM_FORMAT_S16_LE)==0) { + alsa_capture_format[card].format=SND_PCM_FORMAT_S16_LE; + LogLine(RDConfig::LogDebug," Format = 16 bit little-endian"); + } + else { + if(snd_pcm_hw_params_test_format(pcm,hwparams,SND_PCM_FORMAT_S32_LE)==0) { + alsa_capture_format[card].format=SND_PCM_FORMAT_S32_LE; + LogLine(RDConfig::LogDebug," Format = 32 bit little-endian"); + } + else { + LogLine(RDConfig::LogErr, + " Neither 16 nor 32 bit little-endian formats available,"); + LogLine(RDConfig::LogErr, + " aborting initialization of device."); + return false; + } + } + snd_pcm_hw_params_set_format(pcm,hwparams,alsa_capture_format[card].format); + + // + // Sample Rate + // + if(alsa_play_format[card].sample_rate>0) { + sr=alsa_play_format[card].sample_rate; + } + else { + sr=system_sample_rate; + } + snd_pcm_hw_params_set_rate_near(pcm,hwparams,&sr,&dir); + if((sr<(system_sample_rate-RD_ALSA_SAMPLE_RATE_TOLERANCE))|| + (sr>(system_sample_rate+RD_ALSA_SAMPLE_RATE_TOLERANCE))) { + LogLine(RDConfig::LogErr, + QString().sprintf(" Asked for sample rate %u, got %u", + system_sample_rate,sr)); + LogLine(RDConfig::LogErr," Sample rate unsupported by device"); + return false; + } + alsa_capture_format[card].sample_rate=sr; + LogLine(RDConfig::LogNotice,QString().sprintf(" SampleRate = %u",sr)); + + // + // Channels + // + if(rd_config->alsaChannelsPerPcm()<0) { + alsa_capture_format[card].channels=rd_config->channels()*RD_MAX_PORTS; + } + else { + alsa_capture_format[card].channels=rd_config->alsaChannelsPerPcm(); + } + snd_pcm_hw_params_set_channels_near(pcm,hwparams, + &alsa_capture_format[card].channels); + alsa_play_format[card].capture_channels=alsa_capture_format[card].channels; + LogLine(RDConfig::LogDebug,QString(). + sprintf(" Aggregate Channels = %u", + alsa_capture_format[card].channels)); + + // + // Buffer Size + // + alsa_capture_format[card].periods=rd_config->alsaPeriodQuantity(); + snd_pcm_hw_params_set_periods_near(pcm,hwparams, + &alsa_capture_format[card].periods,&dir); + LogLine(RDConfig::LogDebug,QString().sprintf(" Periods = %u", + alsa_capture_format[card].periods)); + alsa_capture_format[card].buffer_size= + alsa_capture_format[card].periods*rd_config->alsaPeriodSize(); + snd_pcm_hw_params_set_buffer_size_near(pcm,hwparams, + &alsa_capture_format[card].buffer_size); + LogLine(RDConfig::LogDebug,QString().sprintf(" BufferSize = %u frames", + (unsigned)alsa_capture_format[card].buffer_size)); + + // + // Fire It Up + // + if((err=snd_pcm_hw_params(pcm,hwparams))<0) { + LogLine(RDConfig::LogErr,QString().sprintf(" Device Error: %s,", + (const char *)snd_strerror(err))); + LogLine(RDConfig::LogErr," aborting initialization of device."); + return false; + } + LogLine(RDConfig::LogNotice," Device started successfully"); + switch(alsa_capture_format[card].format) { + case SND_PCM_FORMAT_S16_LE: + alsa_capture_format[card].card_buffer_size= + alsa_capture_format[card].buffer_size* + alsa_capture_format[card].channels*2; + break; + + case SND_PCM_FORMAT_S32_LE: + alsa_capture_format[card].card_buffer_size= + alsa_capture_format[card].buffer_size* + alsa_capture_format[card].channels*4; + break; + + default: + break; + } + alsa_capture_format[card].card_buffer= + new char[alsa_capture_format[card].card_buffer_size]; + alsa_capture_format[card].passthrough_buffer= + new char[alsa_capture_format[card].card_buffer_size]; + alsa_capture_format[card].pcm=pcm; + alsa_capture_format[card].card=card; + // + // Set Wake-up Timing + // + snd_pcm_sw_params_alloca(&swparams); + snd_pcm_sw_params_current(pcm,swparams); + snd_pcm_sw_params_set_avail_min(pcm,swparams,rd_config->alsaPeriodSize()); + if((err=snd_pcm_sw_params(pcm,swparams))<0) { + LogLine(RDConfig::LogErr,QString().sprintf("ALSA Device %s: %s", + (const char *)dev, + (const char *)snd_strerror(err))); + return false; + } + + // + // Start the Callback + // + pthread_attr_init(&pthread_attr); +/* + if(use_realtime) { + pthread_attr_setschedpolicy(&pthread_attr,SCHED_FIFO); + } +*/ + alsa_capture_format[card].exiting = false; + pthread_create(&alsa_capture_format[card].thread,&pthread_attr, + AlsaCaptureCallback,&alsa_capture_format[card]); + return true; +} + + +bool MainObject::AlsaStartPlayDevice(QString &dev,int card,snd_pcm_t *pcm) +{ + snd_pcm_hw_params_t *hwparams; + snd_pcm_sw_params_t *swparams; + int dir; + int err; + pthread_attr_t pthread_attr; + unsigned sr; + + memset(&alsa_play_format[card],0,sizeof(struct alsa_format)); + + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_hw_params_any(pcm,hwparams); + + LogLine(RDConfig::LogNotice,QString().sprintf("Starting ALSA Play Device %s:", + (const char *)dev)); + + // + // Access Type + // + if(snd_pcm_hw_params_test_access(pcm,hwparams, + SND_PCM_ACCESS_RW_INTERLEAVED)<0) { + LogLine(RDConfig::LogErr," Interleaved access not supported,"); + LogLine(RDConfig::LogErr," aborting initialization of device."); + return false; + } + snd_pcm_hw_params_set_access(pcm,hwparams,SND_PCM_ACCESS_RW_INTERLEAVED); + + // + // Sample Format + // + if(snd_pcm_hw_params_test_format(pcm,hwparams,SND_PCM_FORMAT_S16_LE)==0) { + alsa_play_format[card].format=SND_PCM_FORMAT_S16_LE; + LogLine(RDConfig::LogDebug," Format = 16 bit little-endian"); + } + else { + if(snd_pcm_hw_params_test_format(pcm,hwparams,SND_PCM_FORMAT_S32_LE)==0) { + alsa_play_format[card].format=SND_PCM_FORMAT_S32_LE; + LogLine(RDConfig::LogDebug," Format = 32 bit little-endian"); + } + else { + LogLine(RDConfig::LogErr, + " Neither 16 nor 32 bit little-endian formats available,"); + LogLine(RDConfig::LogErr," aborting initialization of device."); + return false; + } + } + snd_pcm_hw_params_set_format(pcm,hwparams,alsa_play_format[card].format); + + // + // Sample Rate + // + sr=system_sample_rate; + snd_pcm_hw_params_set_rate_near(pcm,hwparams,&sr,&dir); + if((sr<(system_sample_rate-RD_ALSA_SAMPLE_RATE_TOLERANCE))|| + (sr>(system_sample_rate+RD_ALSA_SAMPLE_RATE_TOLERANCE))) { + LogLine(RDConfig::LogErr, + QString().sprintf(" Asked for sample rate %u, got %u", + system_sample_rate,sr)); + LogLine(RDConfig::LogErr," Sample rate unsupported by device"); + return false; + } + alsa_play_format[card].sample_rate=sr; + LogLine(RDConfig::LogDebug,QString().sprintf(" SampleRate = %u",sr)); + + // + // Channels + // + if(rd_config->alsaChannelsPerPcm()<0) { + alsa_play_format[card].channels=rd_config->channels()*RD_MAX_PORTS; + } + else { + alsa_play_format[card].channels=rd_config->alsaChannelsPerPcm(); + } + snd_pcm_hw_params_set_channels_near(pcm,hwparams, + &alsa_play_format[card].channels); + LogLine(RDConfig::LogDebug,QString().sprintf(" Aggregate Channels = %u", + alsa_play_format[card].channels)); + + // + // Buffer Size + // + alsa_play_format[card].periods=rd_config->alsaPeriodQuantity(); + snd_pcm_hw_params_set_periods_near(pcm,hwparams, + &alsa_play_format[card].periods,&dir); + LogLine(RDConfig::LogDebug,QString().sprintf(" Periods = %u", + alsa_play_format[card].periods)); + alsa_play_format[card].buffer_size= + alsa_play_format[card].periods*rd_config->alsaPeriodSize(); + snd_pcm_hw_params_set_buffer_size_near(pcm,hwparams, + &alsa_play_format[card].buffer_size); + LogLine(RDConfig::LogDebug,QString(). + sprintf(" BufferSize = %u frames", + (unsigned)alsa_play_format[card].buffer_size)); + + // + // Fire It Up + // + if((err=snd_pcm_hw_params(pcm,hwparams))<0) { + LogLine(RDConfig::LogErr,QString().sprintf(" Device Error: %s,", + (const char *)snd_strerror(err))); + LogLine(RDConfig::LogErr," aborting initialization of device."); + return false; + } + LogLine(RDConfig::LogNotice," Device started successfully"); + switch(alsa_play_format[card].format) { + case SND_PCM_FORMAT_S16_LE: + alsa_play_format[card].card_buffer_size= + alsa_play_format[card].buffer_size*alsa_play_format[card].channels*2; + break; + + case SND_PCM_FORMAT_S32_LE: + alsa_play_format[card].card_buffer_size= + alsa_play_format[card].buffer_size*alsa_play_format[card].channels*4; + break; + + default: + break; + } + alsa_play_format[card].card_buffer= + new char[alsa_play_format[card].card_buffer_size]; + alsa_play_format[card].passthrough_buffer= + new char[alsa_play_format[card].card_buffer_size]; + alsa_play_format[card].pcm=pcm; + alsa_play_format[card].card=card; + + // + // Set Wake-up Timing + // + snd_pcm_sw_params_alloca(&swparams); + snd_pcm_sw_params_current(pcm,swparams); + snd_pcm_sw_params_set_avail_min(pcm,swparams,rd_config->alsaPeriodSize()); + if((err=snd_pcm_sw_params(pcm,swparams))<0) { + LogLine(RDConfig::LogErr,QString().sprintf("ALSA Device %s: %s", + (const char *)dev, + (const char *)snd_strerror(err))); + return false; + } + + // + // Start the Callback + // + pthread_attr_init(&pthread_attr); + /* + if(use_realtime) { + pthread_attr_setschedpolicy(&pthread_attr,SCHED_FIFO); + } + */ + alsa_play_format[card].exiting = false; + pthread_create(&alsa_play_format[card].thread,&pthread_attr, + AlsaPlayCallback,&alsa_play_format[card]); + return true; +} + + +int MainObject::GetAlsaOutputStream(int card) +{ + for(int i=0;i + read((char *)alsa_wave_buffer,alsa_record_ring[card][stream]-> + readSpace()); + WriteAlsaBuffer(card,stream,alsa_wave_buffer,n); +} + + +void MainObject::WriteAlsaBuffer(int card,int stream,short *buffer,unsigned len) +{ + ssize_t s; + unsigned char mpeg[2048]; + unsigned frames; + unsigned n; + + frames=len/(2*alsa_record_wave[card][stream]->getChannels()); + alsa_samples_recorded[card][stream]+=frames; + switch(alsa_record_wave[card][stream]->getFormatTag()) { + case WAVE_FORMAT_PCM: + alsa_record_wave[card][stream]->writeWave(buffer,len); + break; + + case WAVE_FORMAT_MPEG: +#ifdef HAVE_TWOLAME + for(unsigned i=0;iframes) { + n=frames-i; + } + else { + n=1152; + } + if((s=twolame_encode_buffer_interleaved(twolame_lameopts[card][stream], + buffer+i*alsa_record_wave[card][stream]->getChannels(), + n,mpeg,2048))>=0) { + alsa_record_wave[card][stream]->writeWave(mpeg,s); + } + else { + LogLine(RDConfig::LogErr,QString(). + sprintf("TwoLAME encode error, card: %d, stream: %d",card,stream)); + } + } +#endif // HAVE_TWOLAME + break; + } +} + + +void MainObject::FillAlsaOutputStream(int card,int stream) +{ + unsigned mpeg_frames=0; + unsigned frame_offset=0; + int m=0; + int n=0; + double ratio=0.0; + int free=(alsa_play_ring[card][stream]->writeSpace()-1); + if(free<=0) { + return; + } + ratio=(double)alsa_play_format[card].sample_rate/ + (double)alsa_play_wave[card][stream]->getSamplesPerSec(); + switch(alsa_play_wave[card][stream]->getFormatTag()) { + case WAVE_FORMAT_PCM: + case WAVE_FORMAT_VORBIS: + free=(int)((double)free/ratio)/(2*alsa_output_channels[card][stream])* + (2*alsa_output_channels[card][stream]); + n=alsa_play_wave[card][stream]->readWave(alsa_wave_buffer,free); + if(n!=free) { + alsa_eof[card][stream]=true; + alsa_stop_timer[card][stream]->stop(); + } + break; + + case WAVE_FORMAT_MPEG: +#ifdef HAVE_MAD + mpeg_frames=free/(2304*alsa_output_channels[card][stream]); + free=mpeg_frames*2304*alsa_output_channels[card][stream]; + for(unsigned i=0;i + readWave(mad_mpeg[card][stream]+mad_left_over[card][stream], + mad_frame_size[card][stream]); + if(m==mad_frame_size[card][stream]) { + mad_stream_buffer(&mad_stream[card][stream],mad_mpeg[card][stream], + m+mad_left_over[card][stream]); + while(mad_frame_decode(&mad_frame[card][stream], + &mad_stream[card][stream])==0) { + mad_synth_frame(&mad_synth[card][stream],&mad_frame[card][stream]); + n+=(2*alsa_output_channels[card][stream]* + mad_synth[card][stream].pcm.length); + for(int j=0;jstop(); + continue; + } + mad_left_over[card][stream]= + mad_stream[card][stream].bufend-mad_stream[card][stream].next_frame; + memmove(mad_mpeg[card][stream],mad_stream[card][stream].next_frame, + mad_left_over[card][stream]); + } +#endif // HAVE_MAD + break; + } + alsa_play_ring[card][stream]->write((char *)alsa_wave_buffer,n); +} +#endif // ALSA + + +void MainObject::AlsaClock() +{ +#ifdef ALSA + for(int i=0;i +// +// $Id: cae_hpi.cpp,v 1.38.6.2 2012/11/30 16:14:58 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +void MainObject::hpiInit(RDStation *station) +{ +#ifdef HPI + for(int i=0;isetFadeProfile(RD_FADE_TYPE); + for(int i=0;igetCardQuantity();i++) { + cae_driver[i]=RDStation::Hpi; + station->setCardDriver(i,RDStation::Hpi); + station->setCardName(i,sound_card->getCardDescription(i)); + station->setCardInputs(i,sound_card->getCardInputPorts(i)); + station->setCardOutputs(i,sound_card->getCardOutputPorts(i)); + } +#endif // HPI +} + + +void MainObject::hpiFree() +{ +#ifdef HPI + +#endif // HPI +} + + +QString MainObject::hpiVersion() +{ +#ifdef HPI + if(sound_card==NULL) { + return QString("not active"); + } + RDHPIInformation *info=sound_card->hpiInformation(0); + if(info->hpiVersion()==0) { + return QString("not active"); + } + return QString().sprintf("%d.%02d.%02d",info->hpiMajorVersion(), + info->hpiMinorVersion(),info->hpiPointVersion()); +#else + return QString("not enabled"); +#endif // HPI +} + + +bool MainObject::hpiLoadPlayback(int card,QString wavename,int *stream) +{ +#ifdef HPI + RDHPIPlayStream *playstream=new RDHPIPlayStream(sound_card); + playstream->setCard(card); + if(playstream->openWave(wavename)!=RDHPIPlayStream::Ok) { + LogLine(RDConfig::LogNotice,QString().sprintf( + "Error: hpiLoadPlayback(%s) openWave() failed to open file", + (const char *) wavename) ); + delete playstream; + return false; + } + *stream=playstream->getStream(); + play[card][*stream]=playstream; + connect(play[card][*stream],SIGNAL(stateChanged(int,int,int)), + this,SLOT(statePlayUpdate(int,int,int))); + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiUnloadPlayback(int card,int stream) +{ +#ifdef HPI + if(play[card][stream]==NULL) { + return false; + } + if(play[card][stream]->getState()==RDHPIPlayStream::Playing) { + play[card][stream]->pause(); + } + play[card][stream]->disconnect(); + play[card][stream]->closeWave(); + delete play[card][stream]; + play[card][stream]=NULL; + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiPlaybackPosition(int card,int stream,unsigned pos) +{ +#ifdef HPI + if(play[card][stream]==NULL) { + return false; + } + return play[card][stream]-> + setPosition((unsigned)((double)play[card][stream]->getSamplesPerSec()* + (double)pos/1000.0)); +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiPlay(int card,int stream,int length,int speed,bool pitch, + bool rates) +{ +#ifdef HPI + if(play[card][stream]==NULL) { + return false; + } + if(!play[card][stream]->setSpeed(speed,pitch,rates)) { + return false; + } + play[card][stream]->setPlayLength(length); + return play[card][stream]->play(); +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiStopPlayback(int card,int stream) +{ +#ifdef HPI + if(play[card][stream]==NULL) { + return false; + } + play[card][stream]->pause(); + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiTimescaleSupported(int card) +{ +#ifdef HPI + return sound_card->haveTimescaling(card); +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiLoadRecord(int card,int stream,int coding,int chans, + int samprate,int bitrate,QString wavename) +{ +#ifdef HPI + record[card][stream]=new RDHPIRecordStream(sound_card); + connect(record[card][stream],SIGNAL(stateChanged(int,int,int)), + this,SLOT(stateRecordUpdate(int,int,int))); + record[card][stream]->setCard(card); + record[card][stream]->setStream(stream); + record[card][stream]->nameWave(wavename); + record[card][stream]->setChannels(chans); + record[card][stream]->setSamplesPerSec(samprate); + if(coding==0) { // PCM16 + record[card][stream]->setFormatTag(WAVE_FORMAT_PCM); + record[card][stream]->setBitsPerSample(16); + } + if((coding>=1)&&(coding<=2)) { // MPEG-1 + record[card][stream]->setFormatTag(WAVE_FORMAT_MPEG); + record[card][stream]->setHeadLayer(coding); + record[card][stream]->setHeadBitRate(bitrate); + record[card][stream]->setMextChunk(true); + switch(chans) { + case 1: + record[card][stream]->setHeadMode(ACM_MPEG_SINGLECHANNEL); + break; + case 2: + record[card][stream]->setHeadMode(ACM_MPEG_STEREO); + break; + default: + delete record[card][stream]; + record[card][stream]=NULL; + return false; + } + record[card][stream]->setHeadFlags(ACM_MPEG_ID_MPEG1); + } + if(coding>2) { + delete record[card][stream]; + record[card][stream]=NULL; + return false; + } + record[card][stream]->setBextChunk(true); + record[card][stream]->setCartChunk(true); + record[card][stream]->setLevlChunk(true); + if(record[card][stream]->createWave()!=RDHPIRecordStream::Ok) { + delete record[card][stream]; + record[card][stream]=NULL; + return false; + } + chown((const char *)wavename,rd_config->uid(),rd_config->gid()); + if(!record[card][stream]->recordReady()) { + delete record[card][stream]; + record[card][stream]=NULL; + return false; + } + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiUnloadRecord(int card,int stream,unsigned *len) +{ +#ifdef HPI + if(record[card][stream]==NULL) { + return false; + } + if(record[card][stream]->getState()==RDHPIRecordStream::Recording) { + record[card][stream]->pause(); + } + record[card][stream]->disconnect(); + *len=record[card][stream]->samplesRecorded(); + record[card][stream]->closeWave(); + delete record[card][stream]; + record[card][stream]=NULL; + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiRecord(int card,int stream,int length,int thres) +{ +#ifdef HPI + if(record[card][stream]==NULL) { + return false; + } + if(thres!=0) { + if(record[card][stream]->haveInputVOX()) { + record[card][stream]->setInputVOX(thres); + } + else { + return false; + } + } + record[card][stream]->setRecordLength(length); + record[card][stream]->record(); + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiStopRecord(int card,int stream) +{ +#ifdef HPI + if(record[card][stream]==NULL) { + return false; + } + record[card][stream]->pause(); + record[card][stream]->setInputVOX(-10000); + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiSetClockSource(int card,int src) +{ +#ifdef HPI + return sound_card->setClockSource(card,(RDHPISoundCard::ClockSource)src); +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiSetInputVolume(int card,int stream,int level) +{ +#ifdef HPI + sound_card->setInputVolume(card,stream,level); + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiSetOutputVolume(int card,int stream,int port,int level) +{ +#ifdef HPI + sound_card->setOutputVolume(card,stream,port,level); + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiFadeOutputVolume(int card,int stream,int port,int level, + int length) +{ +#ifdef HPI + sound_card->fadeOutputVolume(card,stream,port,level,length); + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiSetInputLevel(int card,int port,int level) +{ +#ifdef HPI + sound_card->setInputLevel(card,port,level); + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiSetOutputLevel(int card,int port,int level) +{ +#ifdef HPI + sound_card->setOutputLevel(card,port,level); + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiSetInputMode(int card,int stream,int mode) +{ +#ifdef HPI + switch(mode) { + case 0: + sound_card->setInputMode(card,stream,RDHPISoundCard::Normal); + break; + + case 1: + sound_card->setInputMode(card,stream,RDHPISoundCard::Swap); + break; + + case 2: + sound_card->setInputMode(card,stream,RDHPISoundCard::LeftOnly); + break; + + case 3: + sound_card->setInputMode(card,stream,RDHPISoundCard::RightOnly); + break; + + default: + return false; + } + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiSetOutputMode(int card,int stream,int mode) +{ +#ifdef HPI + switch(mode) { + case 0: + sound_card->setOutputMode(card,stream,RDHPISoundCard::Normal); + break; + + case 1: + sound_card->setOutputMode(card,stream,RDHPISoundCard::Swap); + break; + + case 2: + sound_card->setOutputMode(card,stream,RDHPISoundCard::LeftOnly); + break; + + case 3: + sound_card->setOutputMode(card,stream,RDHPISoundCard::RightOnly); + break; + + default: + return false; + } + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiSetInputVoxLevel(int card,int stream,int level) +{ +#ifdef HPI + sound_card->setInputStreamVOX(card,stream,level); + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiSetInputType(int card,int port,int type) +{ +#ifdef HPI + switch(type) { + case 0: + sound_card->setInputPortMux(card,port,RDHPISoundCard::LineIn); + break; + + case 1: + sound_card->setInputPortMux(card,port,RDHPISoundCard::AesEbuIn); + break; + + default: + return false; + } + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiGetInputStatus(int card,int port) +{ +#ifdef HPI + if(sound_card->getInputPortError(card,port)!=0) { + return false; + } + return true; +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiGetInputMeters(int card,int port,short levels[2]) +{ +#ifdef HPI + return sound_card->inputStreamMeter(card,port,levels); +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiGetOutputMeters(int card,int port,short levels[2]) +{ +#ifdef HPI + if(rd_config->useStreamMeters()) { + // + // This is UGLY, but needed to semi-support cards (like the ASI4215) + // that lack output port metering. + // + for(int i=0;igetOutputVolume(card,i,port)>-10000) { + return sound_card->outputStreamMeter(card,i,levels); + } + } + levels[0]=-10000; + levels[1]=-10000; + return true; + } + return sound_card->outputPortMeter(card,port,levels); +#else + return false; +#endif // HPI +} + + +bool MainObject::hpiGetStreamOutputMeters(int card,int stream,short levels[2]) +{ +#ifdef HPI + return sound_card->outputStreamMeter(card,stream,levels); +#else + return false; +#endif // HPI +} + + +void MainObject::hpiGetOutputPosition(int card,unsigned *pos) +{ +#ifdef HPI + for(int i=0;icurrentPosition()/ + play[card][i]->getSamplesPerSec(); + } + } +#endif // HPI + return; +} + + +bool MainObject::hpiSetPassthroughLevel(int card,int in_port,int out_port, + int level) +{ +#ifdef HPI + return sound_card->setPassthroughVolume(card,in_port,out_port,level); +#else + return false; +#endif // HPI +} diff --git a/cae/cae_jack.cpp b/cae/cae_jack.cpp new file mode 100644 index 00000000..9d470d12 --- /dev/null +++ b/cae/cae_jack.cpp @@ -0,0 +1,1607 @@ +// cae_jack.cpp +// +// The JACK Driver for the Core Audio Engine component of Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: cae_jack.cpp,v 1.59.4.6 2012/11/30 16:14:58 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#ifdef JACK +// +// Callback Variables +// +jack_client_t *jack_client; +RDMeterAverage *jack_input_meter[RD_MAX_PORTS][2]; +RDMeterAverage *jack_output_meter[RD_MAX_PORTS][2]; +RDMeterAverage *jack_stream_output_meter[RD_MAX_STREAMS][2]; +//volatile jack_default_audio_sample_t jack_input_meter[RD_MAX_PORTS][2]; +//volatile jack_default_audio_sample_t jack_output_meter[RD_MAX_PORTS][2]; +volatile jack_default_audio_sample_t + jack_input_volume[RD_MAX_PORTS]; +volatile jack_default_audio_sample_t + jack_output_volume[RD_MAX_PORTS][RD_MAX_STREAMS]; +volatile jack_default_audio_sample_t + jack_passthrough_volume[RD_MAX_PORTS][RD_MAX_PORTS]; +volatile jack_default_audio_sample_t jack_input_vox[RD_MAX_PORTS]; +jack_port_t *jack_input_port[RD_MAX_PORTS][2]; +jack_port_t *jack_output_port[RD_MAX_PORTS][2]; +volatile int jack_input_channels[RD_MAX_PORTS]; +volatile int jack_output_channels[RD_MAX_STREAMS]; +volatile jack_default_audio_sample_t *jack_input_buffer[RD_MAX_PORTS][2]; +volatile jack_default_audio_sample_t *jack_output_buffer[RD_MAX_PORTS][2]; +RDRingBuffer *jack_play_ring[RD_MAX_STREAMS]; +RDRingBuffer *jack_record_ring[RD_MAX_PORTS]; +volatile bool jack_playing[RD_MAX_STREAMS]; +volatile bool jack_stopping[RD_MAX_STREAMS]; +volatile bool jack_eof[RD_MAX_STREAMS]; +volatile bool jack_recording[RD_MAX_PORTS]; +volatile bool jack_ready[RD_MAX_PORTS]; +volatile int jack_output_pos[RD_MAX_STREAMS]; +volatile unsigned jack_output_sample_rate[RD_MAX_STREAMS]; +volatile unsigned jack_sample_rate; +int jack_input_mode[RD_MAX_CARDS][RD_MAX_PORTS]; +int jack_card_process; // local copy of object member jack_card, for use by the callback process. + + +// +// Callback Buffers +// +jack_default_audio_sample_t jack_callback_buffer[RINGBUFFER_SIZE]; + +int JackProcess(jack_nframes_t nframes, void *arg) +{ + unsigned n=0; + jack_default_audio_sample_t in_meter[2]; + jack_default_audio_sample_t out_meter[2]; + jack_default_audio_sample_t stream_out_meter; + + // + // Ensure Buffers are Valid + // + for(int i=0;i0.0) { + for(int k=0;k<2;k++) { + for(unsigned l=0;l + write((char *)jack_callback_buffer, + nframes*sizeof(jack_default_audio_sample_t))/ + sizeof(jack_default_audio_sample_t); + break; + + case 2: // stereo + for(unsigned j=0;j + write((char *)jack_callback_buffer, + 2*nframes*sizeof(jack_default_audio_sample_t))/ + (2*sizeof(jack_default_audio_sample_t)); + break; + } + } + } + + // + // Process Output Streams + // + for(int i=0;i + read((char *)jack_callback_buffer, + nframes*sizeof(jack_default_audio_sample_t))/ + sizeof(jack_default_audio_sample_t); + stream_out_meter=0.0; + for(unsigned j=0;jstream_out_meter) { + stream_out_meter=fabsf(jack_callback_buffer[j]); + } + } + jack_stream_output_meter[i][0]->addValue(stream_out_meter); + jack_stream_output_meter[i][1]->addValue(stream_out_meter); + break; + + case 2: + n=jack_play_ring[i]-> + read((char *)jack_callback_buffer, + 2*nframes*sizeof(jack_default_audio_sample_t))/ + (2*sizeof(jack_default_audio_sample_t)); + for(unsigned j=0;j<2;j++) { // Stream Output Meters + stream_out_meter=0.0; + for(unsigned k=0;kstream_out_meter) { + stream_out_meter=fabsf(jack_callback_buffer[k+j]); + } + } + jack_stream_output_meter[i][j]->addValue(stream_out_meter); + } + break; + } + for(int j=0;j0.0) { + switch(jack_output_channels[i]) { + case 1: + for(unsigned k=0;kin_meter[1]) + in_meter[1]=jack_input_buffer[i][1][k]; + break; + case 2: // L only + if(jack_input_buffer[i][0][k]>in_meter[0]) + in_meter[0]=jack_input_buffer[i][0][k]; + break; + case 1: // swap + if(jack_input_buffer[i][0][k]>in_meter[1]) + in_meter[1]=jack_input_buffer[i][0][k]; + if(jack_input_buffer[i][1][k]>in_meter[0]) + in_meter[0]=jack_input_buffer[i][1][k]; + break; + case 0: // normal + default: + if(jack_input_buffer[i][0][k]>in_meter[0]) + in_meter[0]=jack_input_buffer[i][0][k]; + if(jack_input_buffer[i][1][k]>in_meter[1]) + in_meter[1]=jack_input_buffer[i][1][k]; + break; + } + } // for nframes + jack_input_meter[i][0]->addValue(in_meter[0]); + jack_input_meter[i][1]->addValue(in_meter[1]); + + // output meters + for(int j=0;j<2;j++) { + out_meter[j]=0.0; + for(unsigned k=0;kout_meter[j]) + out_meter[j]=jack_output_buffer[i][j][k]; + } + jack_output_meter[i][j]->addValue(out_meter[j]); + } + + } // for RD_MAX_PORTS + return 0; +} + + +int JackSampleRate(jack_nframes_t nframes, void *arg) +{ + jack_sample_rate=nframes; + + return 0; +} + + +void JackError(const char *desc) +{ + fprintf(stderr,"caed: Jack error: %s\n",desc); +} + + +void JackShutdown(void *arg) +{ +} + + +void JackInitCallback() +{ + int avg_periods=(int)(330.0*jack_get_sample_rate(jack_client)/ + (1000.0*jack_get_buffer_size(jack_client))); + for(int i=0;istop(); + } + } + else { + level=jack_output_volume_db[jack_fade_port[stream]][stream]+ + jack_fade_increment[stream]; + if(level>=jack_fade_volume_db[stream]) { + level=jack_fade_volume_db[stream]; + jack_fade_timer[stream]->stop(); + } + } + jackSetOutputVolume(jack_card,stream,jack_fade_port[stream],level); +#endif // JACK +} + + +void MainObject::jackRecordTimerData(int stream) +{ +#ifdef JACK + jackStopRecord(jack_card,stream); + stateRecordUpdate(jack_card,stream,2); +#endif // JACK +} + + +void MainObject::jackInit(RDStation *station) +{ +#ifdef JACK + QString sql; + RDSqlQuery *q; + jack_options_t jackopts=JackNullOption; + jack_status_t jackstat=JackFailure; + RDConfig::LogPriority prio=RDConfig::LogDebug; + + jack_connected=false; + jack_activated=false; + + // + // Get Next Available Card Number + // + for(jack_card=0;jack_cardstartJack()) { + QStringList fields=QStringList().split(" ",station->jackCommandLine()); + QProcess *proc=new QProcess(fields,this); + if(proc->start()) { + LogLine(RDConfig::LogDebug,"JACK server started"); + } + else { + LogLine(RDConfig::LogErr,"failed to start JACK server"); + } + sleep(1); + } + + // + // Attempt to Connect to Jack Server + // + jackopts=JackNoStartServer; + if(station->jackServerName().isEmpty()) { + jack_client=jack_client_open(name,jackopts,&jackstat); + } + else { + jack_client=jack_client_open(name,jackopts,&jackstat, + (const char *)station->jackServerName()); + } + if(jack_client==NULL) { + if((jackstat&JackInvalidOption)!=0) { + fprintf (stderr, "invalid or unsupported JACK option\n"); + LogLine(prio,"invalid or unsupported JACK option"); + } + + if((jackstat&JackServerError)!=0) { + fprintf (stderr, "communication error with the JACK server\n"); + LogLine(prio,"communication error with the JACK server"); + } + + if((jackstat&JackNoSuchClient)!=0) { + fprintf (stderr, "requested JACK client does not exist\n"); + LogLine(prio,"requested JACK client does not exist"); + } + + if((jackstat&JackLoadFailure)!=0) { + fprintf (stderr, "unable to load internal JACK client\n"); + LogLine(prio,"unable to load internal JACK client"); + } + + if((jackstat&JackInitFailure)!=0) { + fprintf (stderr, "unable to initialize JACK client\n"); + LogLine(prio,"unable to initialize JACK client"); + } + + if((jackstat&JackShmFailure)!=0) { + fprintf (stderr, "unable to access JACK shared memory\n"); + LogLine(prio,"unable to access JACK shared memory"); + } + + if((jackstat&JackVersionError)!=0) { + fprintf (stderr, "JACK protocol version mismatch\n"); + LogLine(prio,"JACK protocol version mismatch"); + } + + if((jackstat&JackServerStarted)!=0) { + fprintf (stderr, "JACK server started\n"); + LogLine(prio,"JACK server started"); + } + + if((jackstat&JackServerFailed)!=0) { + fprintf (stderr, "unable to communication with JACK server\n"); + LogLine(prio,"unable to communicate with JACK server"); + } + + if((jackstat&JackNameNotUnique)!=0) { + fprintf (stderr, "JACK client name not unique\n"); + LogLine(prio,"JACK client name not unique"); + } + + if((jackstat&JackFailure)!=0) { + fprintf (stderr, "JACK general failure\n"); + LogLine(prio,"JACK general failure"); + } + jack_card=-1; + fprintf (stderr, "no connection to JACK server\n"); + LogLine(prio,"no connection to JACK server"); + return; + } + jack_connected=true; + jack_set_process_callback(jack_client,JackProcess,0); + jack_set_sample_rate_callback(jack_client,JackSampleRate,0); + //jack_set_port_connect_callback(jack_client,JackPortConnectCB,this); +#ifdef HAVE_JACK_INFO_SHUTDOWN + jack_on_info_shutdown(jack_client,JackInfoShutdown,0); +#else + jack_on_shutdown(jack_client,JackShutdown,0); +#endif // HAVE_JACK_INFO_SHUTDOWN + LogLine(RDConfig::LogDebug,"connected to JACK server"); + + // + // Start JACK Clients + // + sql=QString("select DESCRIPTION,COMMAND_LINE from JACK_CLIENTS where ")+ + "STATION_NAME=\""+RDEscapeString(station->name())+"\""; + q=new RDSqlQuery(sql); + while(q->next()) { + QStringList fields=QStringList().split(" ",q->value(1).toString()); + jack_clients.push_back(new QProcess(fields,this)); + if(jack_clients.back()->start()) { + LogLine(RDConfig::LogDebug,"started JACK Client \""+ + q->value(0).toString()+"\""); + } + else { + LogLine(RDConfig::LogWarning,"failed to start JACK Client \""+ + q->value(0).toString()+"\" ["+ + q->value(1).toString()+"]"); + } + sleep(1); + } + delete q; + + // + // Tell the database about us + // + if(jack_connected) { + station->setCardDriver(jack_card,RDStation::Jack); + station->setCardName(jack_card,"JACK Audio Connection Kit"); + station->setCardInputs(jack_card,RD_MAX_PORTS); + station->setCardOutputs(jack_card,RD_MAX_PORTS); + } + + // + // Initialize Data Structures + // + for(int i=0;isetMapping(jack_stop_timer[i],i); + connect(jack_stop_timer[i],SIGNAL(timeout()),stop_mapper,SLOT(map())); + jack_fade_timer[i]=new QTimer(this); + fade_mapper->setMapping(jack_fade_timer[i],i); + connect(jack_fade_timer[i],SIGNAL(timeout()),fade_mapper,SLOT(map())); + } + for(int i=0;isetMapping(jack_record_timer[i],i); + connect(jack_record_timer[i],SIGNAL(timeout()),record_mapper,SLOT(map())); + } + + // + // Register Ports + // + for(int i=0;ikill(); + delete jack_clients[i]; + } + jack_clients.clear(); + if(jack_activated) { + jack_deactivate(jack_client); + } +#endif // JACK +} + + +bool MainObject::jackLoadPlayback(int card,QString wavename,int *stream) +{ +#ifdef JACK + if((*stream=GetJackOutputStream())<0) { + LogLine(RDConfig::LogErr,QString().sprintf( + "Error: jackLoadPlayback(%s) GetJackOutputStream():%d <0", + (const char *) wavename, + *stream) ); + return false; + } + jack_play_wave[*stream]=new RDWaveFile(wavename); + if(!jack_play_wave[*stream]->openWave()) { + LogLine(RDConfig::LogNotice,QString().sprintf( + "Error: jackLoadPlayback(%s) openWave() failed to open file", + (const char *) wavename) ); + delete jack_play_wave[*stream]; + jack_play_wave[*stream]=NULL; + FreeJackOutputStream(*stream); + *stream=-1; + return false; + } + switch(jack_play_wave[*stream]->getFormatTag()) { + case WAVE_FORMAT_PCM: + case WAVE_FORMAT_VORBIS: + break; + + case WAVE_FORMAT_MPEG: + InitMadDecoder(card,*stream,jack_play_wave[*stream]); + break; + + default: + LogLine(RDConfig::LogNotice, + QString().sprintf( + "Error: jackLoadPlayback(%s) getFormatTag()%d || getBistsPerSample()%d failed", + (const char *) wavename, + jack_play_wave[*stream]->getFormatTag(), + jack_play_wave[*stream]->getBitsPerSample() )); + delete jack_play_wave[*stream]; + jack_play_wave[*stream]=NULL; + FreeJackOutputStream(*stream); + *stream=-1; + return false; + } + jack_output_channels[*stream]=jack_play_wave[*stream]->getChannels(); + jack_output_sample_rate[*stream]=jack_play_wave[*stream]->getSamplesPerSec(); + jack_stopping[*stream]=false; + jack_offset[*stream]=0; + jack_output_pos[*stream]=0; + jack_eof[*stream]=false; + FillJackOutputStream(*stream); + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackUnloadPlayback(int card,int stream) +{ +#ifdef JACK + if ((stream <0) || (stream >= RD_MAX_STREAMS)){ + return false; + } + if(jack_play_ring[stream]==NULL) { + return false; + } + jack_playing[stream]=false; + switch(jack_play_wave[stream]->getFormatTag()) { + case WAVE_FORMAT_MPEG: + FreeMadDecoder(card,stream); + break; + } + jack_play_wave[stream]->closeWave(); + delete jack_play_wave[stream]; + jack_play_wave[stream]=NULL; + FreeJackOutputStream(stream); + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackPlaybackPosition(int card,int stream,unsigned pos) +{ +#ifdef JACK + unsigned offset=0; + + if ((stream <0) || (stream >= RD_MAX_STREAMS)){ + return false; + } + jack_eof[stream]=false; + jack_play_ring[stream]->reset(); + + + switch(jack_play_wave[stream]->getFormatTag()) { + case WAVE_FORMAT_PCM: + case WAVE_FORMAT_VORBIS: + offset=(unsigned)((double)jack_play_wave[stream]->getSamplesPerSec()* + (double)jack_play_wave[stream]->getBlockAlign()* + (double)pos/1000); + jack_offset[stream]=offset/jack_play_wave[stream]->getBlockAlign(); + offset=jack_offset[stream]*jack_play_wave[stream]->getBlockAlign(); + break; + + case WAVE_FORMAT_MPEG: + offset=(unsigned)((double)jack_play_wave[stream]->getSamplesPerSec()* + (double)pos/1000); + jack_offset[stream]=offset/1152*1152; + offset=jack_offset[stream]/1152*jack_play_wave[stream]->getBlockAlign(); + FreeMadDecoder(jack_card,stream); + InitMadDecoder(jack_card,stream,jack_play_wave[stream]); + break; + } + if(jack_offset[stream]>(int)jack_play_wave[stream]->getSampleLength()) { + return false; + } + jack_output_pos[stream]=0; + jack_play_wave[stream]->seekWave(offset,SEEK_SET); + FillJackOutputStream(stream); + + if(jack_playing[stream]) { + jack_stop_timer[stream]->stop(); + jack_stop_timer[stream]-> + start(jack_play_wave[stream]->getExtTimeLength()-pos,true); + } + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackPlay(int card,int stream,int length,int speed,bool pitch, + bool rates) +{ +#ifdef JACK + if((stream <0) || (stream >= RD_MAX_STREAMS) || + (jack_play_ring[stream]==NULL)||jack_playing[stream]) { + return false; + } + if(speed!=RD_TIMESCALE_DIVISOR) { + jack_st_conv[stream]=new soundtouch::SoundTouch(); + jack_st_conv[stream]->setTempo((float)speed/RD_TIMESCALE_DIVISOR); + jack_st_conv[stream]->setSampleRate(jack_output_sample_rate[stream]); + jack_st_conv[stream]->setChannels(jack_output_channels[stream]); + } + jack_playing[stream]=true; + if(length>0) { + jack_stop_timer[stream]->start(length,true); + } + statePlayUpdate(card,stream,1); + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackStopPlayback(int card,int stream) +{ +#ifdef JACK + if((stream <0) || (stream>=RD_MAX_STREAMS) || + (jack_play_ring[stream]==NULL)||(!jack_playing[stream])) { + return false; + } + jack_playing[stream]=false; + jack_stop_timer[stream]->stop(); + statePlayUpdate(card,stream,2); + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackTimescaleSupported(int card) +{ +#ifdef JACK + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackLoadRecord(int card,int stream,int coding,int chans, + int samprate,int bitrate,QString wavename) +{ +#ifdef JACK + jack_record_wave[stream]=new RDWaveFile(wavename); + switch(coding) { + case 0: // PCM16 + jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_PCM); + jack_record_wave[stream]->setChannels(chans); + jack_record_wave[stream]->setSamplesPerSec(samprate); + jack_record_wave[stream]->setBitsPerSample(16); + break; + + case 2: // MPEG Layer 2 + if(!InitTwoLameEncoder(card,stream,chans,samprate,bitrate)) { + delete jack_record_wave[stream]; + jack_record_wave[stream]=NULL; + return false; + } + jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_MPEG); + jack_record_wave[stream]->setChannels(chans); + jack_record_wave[stream]->setSamplesPerSec(samprate); + jack_record_wave[stream]->setBitsPerSample(16); + jack_record_wave[stream]->setHeadLayer(ACM_MPEG_LAYER2); + switch(chans) { + case 1: + jack_record_wave[stream]->setHeadMode(ACM_MPEG_SINGLECHANNEL); + break; + + case 2: + jack_record_wave[stream]->setHeadMode(ACM_MPEG_STEREO); + break; + + default: + LogLine(RDConfig::LogErr,QString(). + sprintf("requested unsupported channel count %d, card: %d, stream: %d", + chans,card,stream)); + delete jack_record_wave[stream]; + jack_record_wave[stream]=NULL; + return false; + } + jack_record_wave[stream]->setHeadBitRate(bitrate); + jack_record_wave[stream]->setMextChunk(true); + jack_record_wave[stream]->setMextHomogenous(true); + jack_record_wave[stream]->setMextPaddingUsed(false); + jack_record_wave[stream]->setMextHackedBitRate(true); + jack_record_wave[stream]->setMextFreeFormat(false); + jack_record_wave[stream]-> + setMextFrameSize(144*jack_record_wave[stream]->getHeadBitRate()/ + jack_record_wave[stream]->getSamplesPerSec()); + jack_record_wave[stream]->setMextAncillaryLength(5); + jack_record_wave[stream]->setMextLeftEnergyPresent(true); + if(chans>1) { + jack_record_wave[stream]->setMextRightEnergyPresent(true); + } + else { + jack_record_wave[stream]->setMextRightEnergyPresent(false); + } + jack_record_wave[stream]->setMextPrivateDataPresent(false); + break; + + default: + LogLine(RDConfig::LogErr,QString(). + sprintf("requested invalid audio encoding %d, card: %d, stream: %d", + coding,card,stream)); + delete jack_record_wave[stream]; + jack_record_wave[stream]=NULL; + return false; + } + jack_record_wave[stream]->setBextChunk(true); + jack_record_wave[stream]->setLevlChunk(true); + if(!jack_record_wave[stream]->createWave()) { + delete jack_record_wave[stream]; + jack_record_wave[stream]=NULL; + return false; + } + chown((const char *)wavename,rd_config->uid(),rd_config->gid()); + jack_input_channels[stream]=chans; + jack_record_ring[stream]=new RDRingBuffer(RINGBUFFER_SIZE); + jack_record_ring[stream]->reset(); + jack_ready[stream]=true; + return true; + + /* + if ((stream <0) || (stream >=RD_MAX_PORTS)){ + return false; + } + jack_record_wave[stream]=new RDWaveFile(wavename); + jack_record_wave[stream]->setFormatTag(WAVE_FORMAT_PCM); + jack_record_wave[stream]->setChannels(chans); + jack_record_wave[stream]->setSamplesPerSec(samprate); + jack_record_wave[stream]->setBitsPerSample(16); + jack_record_wave[stream]->setBextChunk(true); + jack_record_wave[stream]->setLevlChunk(true); + if(!jack_record_wave[stream]->createWave()) { + delete jack_record_wave[stream]; + jack_record_wave[stream]=NULL; + return false; + } + chown((const char *)wavename,rd_config->uid(),rd_config->gid()); + jack_input_channels[stream]=chans; + jack_record_ring[stream]=new RDRingBuffer(RINGBUFFER_SIZE); + jack_record_ring[stream]->reset(); + jack_ready[stream]=true; + return true; + */ +#else + return false; +#endif // JACK +} + + +bool MainObject::jackUnloadRecord(int card,int stream,unsigned *len) +{ +#ifdef JACK + if ((stream <0) || (stream >= RD_MAX_PORTS)){ + return false; + } + jack_recording[stream]=false; + jack_ready[stream]=false; + EmptyJackInputStream(stream,true); + *len=jack_samples_recorded[stream]; + jack_samples_recorded[stream]=0; + jack_record_wave[stream]->closeWave(*len); + delete jack_record_wave[stream]; + jack_record_wave[stream]=NULL; + delete jack_record_ring[stream]; + jack_record_ring[stream]=NULL; + FreeTwoLameEncoder(card,stream); + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackRecord(int card,int stream,int length,int thres) +{ +#ifdef JACK + if ((stream <0) || (stream >= RD_MAX_PORTS)){ + return false; + } + if(!jack_ready[stream]) { + return false; + } + jack_recording[stream]=true; + if(jack_input_vox[stream]==0.0) { + if(length>0) { + jack_record_timer[stream]->start(length,true); + } + stateRecordUpdate(card,stream,4); + } + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackStopRecord(int card,int stream) +{ +#ifdef JACK + if ((stream <0) || (stream >= RD_MAX_PORTS)){ + return false; + } + if(!jack_recording[stream]) { + return false; + } + jack_recording[stream]=false; + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackSetInputVolume(int card,int stream,int level) +{ +#ifdef JACK + if ((stream <0) || (stream >= RD_MAX_STREAMS)){ + return false; + } + if(level>-10000) { + jack_input_volume[stream]= + (jack_default_audio_sample_t)pow10((double)level/2000.0); + jack_input_volume_db[stream]=level; + } + else { + jack_input_volume[stream]=0.0; + jack_input_volume_db[stream]=-10000; + } + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackSetOutputVolume(int card,int stream,int port,int level) +{ +#ifdef JACK + if ((stream <0) ||(stream >= RD_MAX_STREAMS) || + (port <0) || (port >= RD_MAX_PORTS)){ + return false; + } + if(level>-10000) { + jack_output_volume[port][stream]= + (jack_default_audio_sample_t)pow10((double)level/2000.0); + jack_output_volume_db[port][stream]=level; + } + else { + jack_output_volume[port][stream]=0.0; + jack_output_volume_db[port][stream]=-10000; + } + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackFadeOutputVolume(int card,int stream,int port,int level, + int length) +{ +#ifdef JACK + int diff; + if ((stream <0) ||(stream >= RD_MAX_STREAMS) || + (port <0) || (port >= RD_MAX_PORTS)){ + return false; + } + if(jack_fade_timer[stream]->isActive()) { + jack_fade_timer[stream]->stop(); + } + if(level>jack_output_volume_db[port][stream]) { + jack_fade_up[stream]=true; + diff=level-jack_output_volume_db[port][stream]; + } + else { + jack_fade_up[stream]=false; + diff=jack_output_volume_db[port][stream]-level; + } + jack_fade_volume_db[stream]=level; + jack_fade_port[stream]=port; + jack_fade_increment[stream]=diff*RD_JACK_FADE_INTERVAL/length; + jack_fade_timer[stream]->start(RD_JACK_FADE_INTERVAL); + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackSetInputLevel(int card,int port,int level) +{ +#ifdef JACK + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackSetOutputLevel(int card,int port,int level) +{ +#ifdef JACK + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackSetInputMode(int card,int stream,int mode) +{ +#ifdef JACK + jack_input_mode[card][stream]=mode; + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackSetOutputMode(int card,int stream,int mode) +{ +#ifdef JACK + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackSetInputVoxLevel(int card,int stream,int level) +{ +#ifdef JACK + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackSetInputType(int card,int port,int type) +{ +#ifdef JACK + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackGetInputStatus(int card,int port) +{ +#ifdef JACK + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackGetInputMeters(int card,int port,short levels[2]) +{ +#ifdef JACK + jack_default_audio_sample_t meter; + if ((port <0) || (port >= RD_MAX_PORTS)){ + return false; + } + for(int i=0;i<2;i++) { + meter=jack_input_meter[port][i]->average(); + if(meter==0.0) { + levels[i]=-10000; + } + else { + levels[i]=(short)(2000.0*log10(meter)); + if(levels[i]<-10000) { + levels[i]=-10000; + } + } + } + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackGetOutputMeters(int card,int port,short levels[2]) +{ +#ifdef JACK + jack_default_audio_sample_t meter; + if ((port <0) || (port >= RD_MAX_PORTS)){ + return false; + } + + for(int i=0;i<2;i++) { + meter=jack_output_meter[port][i]->average(); + if(meter==0.0) { + levels[i]=-10000; + } + else { + levels[i]=(short)(2000.0*log10(meter)); + if(levels[i]<-10000) { + levels[i]=-10000; + } + } + } + return true; +#else + return false; +#endif // JACK +} + + +bool MainObject::jackGetStreamOutputMeters(int card,int stream,short levels[2]) +{ +#ifdef JACK + jack_default_audio_sample_t meter; + if ((stream<0) || (stream>=RD_MAX_STREAMS)){ + return false; + } + + for(int i=0;i<2;i++) { + meter=jack_stream_output_meter[stream][i]->average(); + if(meter==0.0) { + levels[i]=-10000; + } + else { + levels[i]=(short)(2000.0*log10(meter)); + if(levels[i]<-10000) { + levels[i]=-10000; + } + } + } + return true; +#else + return false; +#endif // JACK +} + + +void MainObject::jackGetOutputPosition(int card,unsigned *pos) +{ +#ifdef JACK + for(int i=0;igetSamplesPerSec(); + } + else { + pos[i]=0; + } + } +#endif // JACK +} + +bool MainObject::jackSetPassthroughLevel(int card,int in_port,int out_port, + int level) +{ +#ifdef JACK + if ((in_port <0) || (in_port >= RD_MAX_PORTS) || + (out_port <0) || (out_port >= RD_MAX_PORTS)){ + return false; + } + if(level>-10000) { + jack_passthrough_volume[in_port][out_port]= + (jack_default_audio_sample_t)pow10((double)level/2000.0); + jack_passthrough_volume_db[in_port][out_port]=level; + } + else { + jack_passthrough_volume[in_port][out_port]=0.0; + jack_passthrough_volume_db[in_port][out_port]=-10000; + } + return true; +#else + return false; +#endif // JACK +} + + +void MainObject::jackConnectPorts(const QString &out,const QString &in) +{ +#ifdef JACK + if(jack_card<0) { + return; + } + jack_connect(jack_client,(const char *)in,(const char *)out); +#endif // JACK +} + + +void MainObject::jackDisconnectPorts(const QString &out,const QString &in) +{ +#ifdef JACK + if(jack_card<0) { + return; + } + jack_disconnect(jack_client,(const char *)in,(const char *)out); +#endif // JACK +} + + +int MainObject::GetJackOutputStream() +{ +#ifdef JACK + for(int i=0;i= RD_MAX_STREAMS)){ + return; + } + delete jack_play_ring[stream]; + jack_play_ring[stream]=NULL; + if(jack_st_conv[stream]!=NULL) { + delete jack_st_conv[stream]; + jack_st_conv[stream]=NULL; + } +#else + return; +#endif +} + + +void MainObject::EmptyJackInputStream(int stream,bool done) +{ +#ifdef JACK + if ((stream <0) || (stream >= RD_MAX_STREAMS)){ + return; + } + unsigned n=jack_record_ring[stream]-> + read((char *)jack_sample_buffer,jack_record_ring[stream]->readSpace()); + WriteJackBuffer(stream,jack_sample_buffer,n,done); +#endif // JACK +} + +#ifdef JACK +void MainObject::WriteJackBuffer(int stream,jack_default_audio_sample_t *buffer, + unsigned len,bool done) +{ + ssize_t s; + unsigned char mpeg[2048]; + unsigned frames; + unsigned n; + + frames=len/(sizeof(jack_default_audio_sample_t)* + jack_record_wave[stream]->getChannels()); + jack_samples_recorded[stream]+=frames; + switch(jack_record_wave[stream]->getFormatTag()) { + case WAVE_FORMAT_PCM: + n=len/sizeof(jack_default_audio_sample_t); + src_float_to_short_array(buffer,jack_wave_buffer,n); + jack_record_wave[stream]->writeWave(jack_wave_buffer,n*sizeof(short)); + break; + + case WAVE_FORMAT_MPEG: +#ifdef HAVE_TWOLAME + for(unsigned i=0;iframes) { + n=frames-i; + } + else { + n=1152; + } + if((s=twolame_encode_buffer_float32_interleaved( + twolame_lameopts[jack_card][stream], + buffer+i*jack_record_wave[stream]->getChannels(), + n,mpeg,2048))>=0) { + jack_record_wave[stream]->writeWave(mpeg,s); + } + else { + LogLine(RDConfig::LogErr,QString(). + sprintf("TwoLAME encode error, card: %d, stream: %d",jack_card, + stream)); + } + } + if(done) { + if((s=twolame_encode_flush(twolame_lameopts[jack_card][stream], + mpeg,2048))>=0) { + jack_record_wave[stream]->writeWave(mpeg,s); + } + } +#endif // HAVE_TWOLAME + break; + } +} +#endif // JACK + +void MainObject::FillJackOutputStream(int stream) +{ +#ifdef JACK + int n=0; + unsigned mpeg_frames=0; + unsigned frame_offset=0; + int m=0; + + if ((stream <0) || (stream >= RD_MAX_STREAMS)){ + return; + } + int free= + jack_play_ring[stream]->writeSpace()/sizeof(jack_default_audio_sample_t)-1; + if((free<=0)||(jack_eof[stream]==true)) { + return; + } + switch(jack_play_wave[stream]->getFormatTag()) { + case WAVE_FORMAT_PCM: + case WAVE_FORMAT_VORBIS: + free=(int)free/jack_output_channels[stream]*jack_output_channels[stream]; + n=jack_play_wave[stream]->readWave(jack_wave_buffer,sizeof(short)*free)/ + sizeof(short); + if((n!=free)&&(jack_st_conv[stream]==NULL)) { + jack_eof[stream]=true; + jack_stop_timer[stream]->stop(); + } + src_short_to_float_array(jack_wave_buffer,jack_sample_buffer,n); + break; + + case WAVE_FORMAT_MPEG: +#ifdef HAVE_MAD + mpeg_frames=free/(1152*jack_output_channels[stream]); + free=mpeg_frames*1152*jack_output_channels[stream]; + for(unsigned i=0;i + readWave(mad_mpeg[jack_card][stream]+mad_left_over[jack_card][stream], + mad_frame_size[jack_card][stream]); + if(m==mad_frame_size[jack_card][stream]) { + mad_stream_buffer(&mad_stream[jack_card][stream], + mad_mpeg[jack_card][stream], + m+mad_left_over[jack_card][stream]); + while(mad_frame_decode(&mad_frame[jack_card][stream], + &mad_stream[jack_card][stream])==0) { + mad_synth_frame(&mad_synth[jack_card][stream], + &mad_frame[jack_card][stream]); + n+=(jack_output_channels[stream]* + mad_synth[jack_card][stream].pcm.length); + for(int j=0;jstop(); + continue; + } + mad_left_over[jack_card][stream]= + mad_stream[jack_card][stream].bufend- + mad_stream[jack_card][stream].next_frame; + memmove(mad_mpeg[jack_card][stream], + mad_stream[jack_card][stream].next_frame, + mad_left_over[jack_card][stream]); + } +#endif // HAVE_MAD + break; + } + if(jack_st_conv[stream]==NULL) { + jack_play_ring[stream]-> + write((char *)jack_sample_buffer,n*sizeof(jack_default_audio_sample_t)); + } + else { + jack_st_conv[stream]-> + putSamples(jack_sample_buffer,n/jack_output_channels[stream]); + free=jack_play_ring[stream]->writeSpace()/ + (sizeof(jack_default_audio_sample_t)*jack_output_channels[stream])-1; + while((n=jack_st_conv[stream]-> + receiveSamples(jack_sample_buffer,free))>0) { + jack_play_ring[stream]-> + write((char *)jack_sample_buffer,n* + sizeof(jack_default_audio_sample_t)* + jack_output_channels[stream]); + free=jack_play_ring[stream]->writeSpace()/ + (sizeof(jack_default_audio_sample_t)*jack_output_channels[stream])-1; + } + if((jack_st_conv[stream]->numSamples()==0)&& + (jack_st_conv[stream]->numUnprocessedSamples()==0)) { + jack_eof[stream]=true; + jack_stop_timer[stream]->stop(); + } + } +#endif // JACK +} + + +void MainObject::JackClock() +{ +#ifdef JACK + for(int i=0;isetSource(RD_CONF_FILE); + bool src_ok=false; + bool dest_ok=false; + QString src_tag="Source1"; + QString dest_tag="Destination1"; + QString src=profile->stringValue("JackSession",src_tag,"",&src_ok); + QString dest=profile->stringValue("JackSession",dest_tag,"",&dest_ok); + while(src_ok&&dest_ok) { + if(jack_connect(jack_client,(const char *)src,(const char *)dest)!=0) { + LogLine(RDConfig::LogNotice,QString(). + sprintf("unable to connect %s to %s", + (const char *)src,(const char *)dest)); + } + count++; + src_tag=QString().sprintf("Source%d",count+1); + dest_tag=QString().sprintf("Destination%d",count+1); + src=profile->stringValue("JackSession",src_tag,"",&src_ok); + dest=profile->stringValue("JackSession",dest_tag,"",&dest_ok); + } + delete profile; +#endif // JACK +} diff --git a/cae/cae_socket.cpp b/cae/cae_socket.cpp new file mode 100644 index 00000000..07c7be79 --- /dev/null +++ b/cae/cae_socket.cpp @@ -0,0 +1,55 @@ +// socket.cpp +// +// The Core Audio Engine component of Rivendell +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: cae_socket.cpp,v 1.9 2010/07/29 19:32:30 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +CaeSocket::CaeSocket(Q_UINT16 port,int backlog,QObject *parent, + const char *name) + : QServerSocket(port,0,parent,name) +{ +} + + +CaeSocket::CaeSocket(const QHostAddress &address,Q_UINT16 port,int backlog, + QObject *parent,const char *name) + : QServerSocket(address,port,0,parent,name) +{ +} + + +void CaeSocket::newConnection(int fd) +{ + emit connection(fd); +} diff --git a/cae/cae_socket.h b/cae/cae_socket.h new file mode 100644 index 00000000..d9fc6ad5 --- /dev/null +++ b/cae/cae_socket.h @@ -0,0 +1,50 @@ +// cae_socket.h +// +// The Core Audio Engine component of Rivendell +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: cae_socket.h,v 1.7 2010/07/29 19:32:30 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef SOCKET_H +#define SOCKET_H + +#include +#include +#include +#include + + +class CaeSocket : public QServerSocket +{ + Q_OBJECT + public: + CaeSocket(Q_UINT16 port,int backlog=0,QObject *parent=0, + const char *name=0); + CaeSocket(const QHostAddress &address,Q_UINT16 port,int backlog=0, + QObject *parent=0,const char *name=0); + void newConnection(int socket); + + signals: + void connection(int); + + private: + QServerSocket *socket; +}; + + +#endif diff --git a/conf/Makefile.am b/conf/Makefile.am new file mode 100644 index 00000000..53b13435 --- /dev/null +++ b/conf/Makefile.am @@ -0,0 +1,54 @@ +## automake.am +## +## Top level automake.am for Rivendell +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.16.4.5 2013/09/12 23:26:09 cvs Exp $ +## $Date: 2013/09/12 23:26:09 $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + + +EXTRA_DIST = my.cnf-master\ + my.cnf-standby\ + rd-bin.conf.in\ + rd.conf-sample\ + rd.conf-slax\ + rd-sample.ini\ + rlm_ando.conf\ + rlm_facebook.conf\ + rlm_filewrite.conf\ + rlm_icecast2.conf\ + rlm_inno713.conf\ + rlm_liqcomp.conf\ + rlm_padpoint.conf\ + rlm_serial.conf\ + rlm_shoutcast1.conf\ + rlm_spinitron_plus.conf\ + rlm_spottrap.conf\ + rlm_twitter.conf\ + rlm_udp.conf\ + rlm_xds.conf\ + rlm_xmpad.conf + +CLEANFILES = *~ +DISTCLEANFILES = rdfeed.conf +MAINTAINERCLEANFILES = *~\ + aclocal.m4\ + configure\ + Makefile.in diff --git a/conf/my.cnf-master b/conf/my.cnf-master new file mode 100644 index 00000000..680529d7 --- /dev/null +++ b/conf/my.cnf-master @@ -0,0 +1,59 @@ +# mySQL Configuration file for a Master Rivendell DB. +# +# by Fred Gleason +# +# This is recommended for use on a system acting as a master +# Rivendell server. +# + +# +# The MySQL server +# +[mysqld] +server-id = 1 +port = 3306 +socket = /var/lib/mysql/mysql.sock +skip-locking +key_buffer = 16M +max_allowed_packet = 1M +table_cache = 64 +sort_buffer_size = 512K +net_buffer_length = 8K +myisam_sort_buffer_size = 8M +log-bin + +# +# Client Options +# +[client] +#password = your_password +port = 3306 +socket = /var/lib/mysql/mysql.sock + +# +# The safe_mysqld script +# +[safe_mysqld] +err-log=/var/lib/mysql/mysqld.log + +[mysqldump] +quick +max_allowed_packet = 16M + +[mysql] +no-auto-rehash + +[isamchk] +key_buffer = 20M +sort_buffer_size = 20M +read_buffer = 2M +write_buffer = 2M + +[myisamchk] +key_buffer = 20M +sort_buffer_size = 20M +read_buffer = 2M +write_buffer = 2M + +[mysqlhotcopy] +interactive-timeout diff --git a/conf/my.cnf-standby b/conf/my.cnf-standby new file mode 100644 index 00000000..27db064a --- /dev/null +++ b/conf/my.cnf-standby @@ -0,0 +1,78 @@ +# mySQL configuration file for a Standby Rivendell DB. +# +# by Fred Gleason +# +# This is recommended for use on a system acting as a standby +# Rivendell server. Further information can be found in SRL +# Application Note #3, available at: +# +# http://www.salemradiolabs.com/appnotes/ +# +# IMPORTANT NOTE: +# The 'server-id=' argument *must* be unique for each mySQL server +# across a given Rivendell network, or data replication will not +# work! By convention, the master server is assigned a server-id of +# '1', and standby servers are numbered sequentially starting with +# '100'. + + +# +# The MySQL server +# +[mysqld] +# ##################################################################### +# You will need to customize the 'server-id' entry for your site: +# ##################################################################### +server-id = 100 + +# ##################################################################### +# No changes should be required below here. +# ##################################################################### +port = 3306 +socket = /var/lib/mysql/mysql.sock +skip-locking +key_buffer = 16M +max_allowed_packet = 1M +table_cache = 64 +sort_buffer_size = 512K +net_buffer_length = 8K +myisam_sort_buffer_size = 8M +# master-host = server.example.com +# master-user = repl +# master-password = letmein + +# +# Client Options +# +[client] +#password = your_password +port = 3306 +socket = /var/lib/mysql/mysql.sock + +# +# The safe_mysqld script +# +[safe_mysqld] +err-log=/var/lib/mysql/mysqld.log + +[mysqldump] +quick +max_allowed_packet = 16M + +[mysql] +no-auto-rehash + +[isamchk] +key_buffer = 20M +sort_buffer_size = 20M +read_buffer = 2M +write_buffer = 2M + +[myisamchk] +key_buffer = 20M +sort_buffer_size = 20M +read_buffer = 2M +write_buffer = 2M + +[mysqlhotcopy] +interactive-timeout diff --git a/conf/rd-bin.conf.in b/conf/rd-bin.conf.in new file mode 100644 index 00000000..858a74ea --- /dev/null +++ b/conf/rd-bin.conf.in @@ -0,0 +1,51 @@ +# rdfeed.conf +# +# This is the Apache Web Server configuration for Rivendell. +# +# (C) Copyright 2007,2010 Fred Gleason +# +# $Id: rd-bin.conf.in,v 1.5 2011/06/23 19:47:28 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + + + Options ExecCGI FollowSymLinks + AllowOverride None + Order allow,deny + Allow from all + + SetHandler default-handler + + + SetHandler default-handler + + + SetHandler default-handler + + + SetHandler default-handler + + + SetHandler cgi-script + + + SetHandler cgi-script + + + SetHandler cgi-script + + +ScriptAlias /rd-bin/ "@libexecdir@/" +TimeOut 1200 diff --git a/conf/rd-sample.ini b/conf/rd-sample.ini new file mode 100755 index 00000000..92575b7e --- /dev/null +++ b/conf/rd-sample.ini @@ -0,0 +1,118 @@ +; rd.conf +; +; This is the default configuration file for Rivendell +; +; At the very least, you will need to change the 'AudioOwner=' +; directive to point to a valid account on this machine! +; +; by Fred Gleason +; + +[Identity] +; This section is used to define the default shell account used to +; run the Rivendell modules. +Password=letmein +AudioOwner=rd +AudioGroup=users + +[mySQL] +; The connection parameters for the MySQL server. +Hostname=localhost +Loginname=rduser +Password=letmein +Database=Rivendell +Driver=QMYSQL3 + +[Logs] +; Set the method to be used for logging. Possible values are: +; Syslog = Use the syslog facility. +; File = Log directly to a file. See also the 'LogDirectory=' +; and 'LogPattern=' parameters below. +; None = Don't generate logs at all. +Facility=Syslog + +; The directory to write logs to. Used only if the 'Facility=' +; parameter is set to 'File'. +LogDirectory=/home/rd/rdlogs + +; The directory to to put core files in in the event of a daemon +; crash. For this to work, you must also configure your environment +; to allow the generation of core dumps (e.g. 'ulimit -c unlimited'). +CoreDumpDirectory=/home/rd/rdlogs + +; The name of the file to send logs to. The following wildcards can +; be used: +; %d - The day of the month (01 - 31) +; %h - The hour (00 - 23) +; %M - The month (01 - 12) +; %m - The minute (00 - 59) +; %n - The name of the originating module --e.g. 'rdairplay', 'caed'. +; %s - The second (00 - 60) +; %Y - The four digit year +; This parameter is used only if the 'Facility=' parameter is set to +; 'File'. +LogPattern=%n-%Y%M%d.log + + +[Alsa] +; ALSA Parameters +; (It should seldom be necessary to tweak these) +PeriodQuantity=2 +PeriodSize=1024 + +; [SoftKeys] +; +; This section can be used to program the RDSoftKeys applet, or you +; can use the --map-file= switch to configure multiple soft +; key setups on the same host. +; +; Columns=10 +; +; Command1=hithlum.srlabs.loc:GO 3 1 1 0! +; Legend1=Telos 1 ON +; Color1=red +; +; Command2=hithlum.srlabs.loc:GO 3 2 1 0! +; Legend2=Telos 2 ON +; Color2=red +; + +[Tuning] +; This section defines the realtime parameters used when running +; audio components. Normally, these useful only for debugging. +UseRealtime=Yes +RealtimePriority=9 + +[Format] +; These values are used only by the ALSA driver, to set the basic sample +; rate to use when starting each sound card. Gernerally, you want +; this to match the rate used by files in your library, but some +; cheapie cards will only work with certain rates [e.g. 48000] here. +SampleRate=44100 +Channels=2 + +[Hacks] +; If you are getting no output level meter indications with an older +; ASI card (such as the ASI4215, ASI4113 or ASI4111), try uncommenting +; the following line: +; UseStreamMeters=Yes + +; +; Log Generation (old method, deprecated) +; +; These sections are here strictly for backward compatibility. See +; the [Logs] section for a much more powerful way to configure +; logging. +; +; [RDAirPlay] +; Logfile=/home/rd/rdairplay.log +; +; [RDCatchd] +; Logfile=/home/rd/rdcatchd.log +; +; [Ripcd] +; Logfile=/home/rd/ripcd.log +; +; [Caed] +; Logfile=/home/rd/caed.log +; EnableMixerLogging=No diff --git a/conf/rd.conf-sample b/conf/rd.conf-sample new file mode 100644 index 00000000..8bde569e --- /dev/null +++ b/conf/rd.conf-sample @@ -0,0 +1,133 @@ +; rd.conf +; +; This is the default configuration file for Rivendell +; +; by Fred Gleason +; + +[Identity] +; These entries are used to define the system user and group that will +; own the audio files. +AudioOwner=rivendell +AudioGroup=rivendell + +; This password is used by the various Rivendell modules to log into +; Rivendell system services [caed(8), ripcd(8), rdcatchd(8)]. +Password=letmein + +; This entry is what will appear in RDSelect's list for this configuration. +Label=Default (Local) + +[mySQL] +; The connection parameters for the MySQL server. +Hostname=localhost +Loginname=rduser +Password=letmein +Database=Rivendell +Driver=QMYSQL3 + +[AudioStore] +MountSource= +MountType= +MountOptions=defaults +CaeHostname= +XportHostname= + +[Logs] +; Set the method to be used for logging. Possible values are: +; Syslog = Use the syslog facility. +; File = Log directly to a file. See also the 'LogDirectory=' +; and 'LogPattern=' parameters below. +; None = Don't generate logs at all. +Facility=Syslog + +; The directory to write logs to. Used only if the 'Facility=' +; parameter is set to 'File'. +LogDirectory=/home/rd/rdlogs + +; The directory to to put core files in in the event of a daemon +; crash. For this to work, you must also configure your environment +; to allow the generation of core dumps (e.g. 'ulimit -c unlimited'). +CoreDumpDirectory=/home/rd/rdlogs + +; The name of the file to send logs to. The following wildcards can +; be used: +; %d - The day of the month (01 - 31) +; %h - The hour (00 - 23) +; %M - The month (01 - 12) +; %m - The minute (00 - 59) +; %n - The name of the originating module --e.g. 'rdairplay', 'caed'. +; %s - The second (00 - 60) +; %Y - The four digit year +; This parameter is used only if the 'Facility=' parameter is set to +; 'File'. +LogPattern=%n-%Y%M%d.log + +; Log upload/download debug data. You generally want to enable this only +; when debugging a specific upload/download problem, as *lots* of data +; can be generated. Valid arguments are 'Yes' or 'No'. +LogXloadDebugData=No + +[Alsa] +; ALSA Parameters +; (It should seldom be necessary to tweak these) +PeriodQuantity=4 +PeriodSize=1024 +ChannelsPerPcm=-1 + +; [SoftKeys] +; +; This section can be used to program the RDSoftKeys applet, or you +; can use the --map-file= switch to configure multiple soft +; key setups on the same host. +; +; Columns=10 +; +; Command1=hithlum.srlabs.loc:GO 3 1 1 0! +; Legend1=Telos 1 ON +; Color1=red +; +; Command2=hithlum.srlabs.loc:GO 3 2 1 0! +; Legend2=Telos 2 ON +; Color2=red +; + +[Tuning] +; This section defines the realtime parameters used when running +; audio components. Normally, these are useful only for debugging. +UseRealtime=Yes +RealtimePriority=9 + +[Format] +; This value is used when testing and developing new features in the +; audio drivers. It should never be altered on a production system. +Channels=2 + +[Hacks] +; If you are getting no output level meter indications with an older +; ASI card (such as the ASI4215, ASI4113 or ASI4111), try uncommenting +; the following line: +; UseStreamMeters=Yes + +; Completely disable maintenance checks on this host. +; DisableMaintChecks=Yes + +; +; Log Generation (old method, deprecated) +; +; These sections are here strictly for backward compatibility. See +; the [Logs] section for a much more powerful way to configure +; logging. +; +; [RDAirPlay] +; Logfile=/home/rd/rdairplay.log +; +; [RDCatchd] +; Logfile=/home/rd/rdcatchd.log +; +; [Ripcd] +; Logfile=/home/rd/ripcd.log +; +; [Caed] +; Logfile=/home/rd/caed.log +; EnableMixerLogging=No diff --git a/conf/rd.conf-slax b/conf/rd.conf-slax new file mode 100644 index 00000000..6ca09f29 --- /dev/null +++ b/conf/rd.conf-slax @@ -0,0 +1,45 @@ +; rd.conf +; +; This is the SLAX configuration file for Rivendell +; +; by Fred Gleason +; + +[Identity] +Password=letmein +AudioOwner=salem +AudioGroup=users + +[Tuning] +UseRealtime=Yes +RealtimePriority=9 + +[mySQL] +Hostname=localhost +Loginname=rduser +Password=letmein +Database=Rivendell +Driver=QMYSQL3 + +[Hacks] +; If you are getting no output level meter indications with an older +; ASI card (such as the ASI4215, ASI4113 or ASI4111), tru uncommenting +; the following line: +; UseStreamMeters=Yes + +; +; Log Generation +; +; These are mainly useful for debugging! +; +; [RDAirPlay] +; Logfile=/home/myself/rdairplay.log +; +; [RDCatchd] +; Logfile=/home/myself/rdcatchd.log +; +; [Ripcd] +; Logfile=/home/myself/ripcd.log +; +; [Caed] +; Logfile=/home/myself/caed.log diff --git a/conf/rlm_ando.conf b/conf/rlm_ando.conf new file mode 100644 index 00000000..687a2ca5 --- /dev/null +++ b/conf/rlm_ando.conf @@ -0,0 +1,84 @@ +; rlm_ando.conf +; +; This is the sample configuration file for the 'rlm_ando' module for +; Rivendell, which can be used to output Now & Next data to one or more +; ANDO Media Streaming systems, using one of the following formats: +; +; ^~~<duration>~<group>~<album>~<cartnum>| +; ^<artist>~<title>~<duration>~<group>~<cartnum>~<album>~<label>| +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. + +; Section Header +; +; One section per remote ANDO system is configured, starting with 'System1' and +; working up consecutively +[System1] + +; IP Address +; +; The IP address of the remote ANDO port, in dotted-quad notation. +IpAddress=192.168.10.29 + +; UDP Port +; +; The UDP port number of the remote ANDO system, in the range 0 - 65,535. +UdpPort=5273 + +; Field Definitions. The string to use to populate the <title>, <artist>, +; <album> and <label> fields sent to ANDO each time RDAirPlay changes play +; state. These can include wildcards as placeholders for metadata values. +; +; The <label> field is optional, and should be left blank unless you know +; that your specific ANDO configuration requires it. +; +; The following wildcards are available: +; +; Now Next Field +; ---------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length (in milliseconds) +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +Title=%t +Artist=%a +Album=%l +Label= + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output on this udp port. If set +; to 'Onair', then output will be generated only if RDAirPlay's OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional ANDO systems can be configured by adding new sections... +;[System2] +;IpAddress=192.168.10.22 +;UdpPort=6789 +;Title=%u +;Artist=%a +;Album=%p +;Label= +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_facebook.conf b/conf/rlm_facebook.conf new file mode 100644 index 00000000..459527ef --- /dev/null +++ b/conf/rlm_facebook.conf @@ -0,0 +1,76 @@ +; rlm_facebook.conf +; +; This is the sample configuration file for the 'rlm_facebook' module for +; Rivendell, which can be used to output Now & Next data to one or more +; Facebook accounts. +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. +; +; For information about Facebook, see http://www.facebook.com/. +; +; This module requires the curl(1) network transfer tool, included with most +; Linux distros. It is also available at http://curl.haxx.se/. + + +; Section Header +; +; One section per remote Facebook account is configured, starting with +; 'Facebook1' and working up consecutively +[Facebook1] + +; E-Mail Address +; +; The e-mail address of the Facebook account to which to send updates. +EmailAddress=someone@example.com + +; Password +; +; The password of the Facebook account to which to send updates. +Password=letmein + +; Format String. The string to be output each time RDAirPlay changes +; play state, including any wildcards as placeholders for metadata values. +; The following wildcards are available: +; +; Now Next Field +; ---------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length (in milliseconds) +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +FormatString=Now playing "%t" by "%a" + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output to this account. If set +; to 'Onair', then output will be generated only if RDAirPlays OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional Facebook accounts can be configured by adding new sections... +;[Facebook2] +;EmailAddress=someoneelse@example.com +;Password=letmein +;FormatString=Artist: %a%r +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_filewrite.conf b/conf/rlm_filewrite.conf new file mode 100644 index 00000000..f21061e7 --- /dev/null +++ b/conf/rlm_filewrite.conf @@ -0,0 +1,111 @@ +; rlm_filewrite.conf +; +; This is the sample configuration file for the 'rlm_filewrite' RLM for +; Rivendell, which can be used to write one or more files on the local +; system using Now & Next data. +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. + +; Section Header +; +; One section per file to be written should be configured, starting with +; 'File1' and working up consecutively +[File1] + +; Filename +; +; The full path to the file to be written. The user running RDAirPlay +; must have write permissions for this location. +Filename=/tmp/rlm_filewrite.txt + +; Append Mode +; +; If set to '0', the file will be completely overwritten with the contents +; of each PAD update. If set to '1', each update will be appended to the +; existing contents of the file. +Append=0 + +; Format String. The string to be output each time RDAirPlay changes +; play state, including any wildcards as placeholders for metadata values. +; The following wildcards are available: +; +; Now Next Field +; -------------------------------------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length (in milliseconds) +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +; \r \r Carriage Return (ASCII 13) +; \n \n Linefeed (ASCII 10) +; %d(<dt>) %D(<dt>) The start date/time, formatted according to <dt>. The +; following wildcards are available for <dt>: +; d - The day as a number without a leading zero (1 to 31). +; dd - The day as a number with a leading zero (01 to 31). +; ddd - The abbreviated localized day name ('Mon' or 'Sun'). +; dddd - The long localized day name ('Monday' or 'Sunday'). +; M - The month as a number without a leading zero +; (1 to 12). +; MM - The month as a number with a leading zero (01 to 12). +; MMM - The abbreviated localized month name ('Jan' or 'Dec'). +; MMMM - The long localized month name ("January' or +; 'December'). +; yy - The last two digits of the year. +; yyyy - The full four digits of the year. +; h - The hour without a leading zero (0 - 23, or 1 - 12 +; if using AM/PM display). +; hh - The hour with a leading zero (00 - 23, or 01 -12 if +; using AM/PM display). +; m - The minute without a leading zero (0 - 59). +; mm - The minute with a leading zero (00 - 59). +; s - The second without a leading zero (00 - 60). +; ss - The second with a leading zero (00 - 60). +; z - The milliseconds without a leading zero (0 - 999). +; zzz - The milliseconds with leading zeros (000 - 999). +; AP - Use AM/PM display. The 'AP' will be replaced by +; 'AM' or 'PM' as appropriate. +; ap - Use AM/PM display. The 'ap' will be replaced by +; 'am' or 'pm' as appropriate. +FormatString=NOW: %d(ddd MMM d hh:mm:ss yyyy): %t - %a\nNEXT: %D(ddd MMM d hh:mm:ss yyyy): %T - %A\n + +; Encoding. Defines the set of escapes to be applied to the PAD fields. +; The following options are available: +; +; 0 - Perform no character escaping. +; 1 - "XML" escaping: Escape reserved characters as per XML-v1.0 +; 2 - "Web" escaping: Escape reserved characters as per RFC 2396 Section 2.4 +Encoding=0 + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output. If set to 'Onair', then +; output will be generated only if RDAirPlays OnAir flag is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional files can be written by adding new sections... +; +;[File2] +;Filename=/home/rd/foo2.txt +;Append=1 +;FormatString=%t by %a\r\n +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_icecast2.conf b/conf/rlm_icecast2.conf new file mode 100644 index 00000000..76c8082a --- /dev/null +++ b/conf/rlm_icecast2.conf @@ -0,0 +1,92 @@ +; rlm_icecast2.conf +; +; This is the sample configuration file for the 'rlm_icecast2' module for +; Rivendell, which can be used to update the metadata on an IceCast2 +; mountpoint using Now & Next data. +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. +; +; This module requires the curl(1) network transfer tool, included with most +; Linux distros. It is also available at http://curl.haxx.se/. + + +; Section Header +; +; One section per Icecast2 mountpoint is configured, starting with +; 'Icecast1' and working up consecutively +[Icecast1] + +; User Name +; +; The username of the Icecast2 account to which to send updates. +Username=source + +; Password +; +; The password of the Icecast2 account to which to send updates. +Password=hackme + +; Host Name +; +; The fully-qualified domain name or IP address of the Icecast2 server +Hostname=icecast.example.com + +; Host Port +; +; The TCP port number of the Icecast2 server +Tcpport=8000 + +; Mountpoint +; +; The Icecast2 mountpoint +Mountpoint=/audio.mp3 + +; Format String. The metadata to be sent each time RDAirPlay changes +; play state, including any wildcards as placeholders for metadata values. +; The following wildcards are available: +; +; Now Next Field +; ---------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length (in milliseconds) +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +FormatString=%t + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output to this account. If set +; to 'Onair', then output will be generated only if RDAirPlays OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional Icecast2 mountpoints can be configured by adding new sections... +;[Icecast2] +;Username=source +;Password=letmein +;Hostname=anotherone.example.com +;Tcpport=80 +;Mountpoint=moreaudio.mp3 +;FormatString=%t by %a +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_inno713.conf b/conf/rlm_inno713.conf new file mode 100644 index 00000000..44ba795e --- /dev/null +++ b/conf/rlm_inno713.conf @@ -0,0 +1,110 @@ +; rlm_inno713.conf +; +; This is the sample configuration file for the 'rlm_inno713' module for +; Rivendell, which can be used to output Now & Next data to one or more +; Innovonics model 713 RDS encoders. +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. + +; Section Header +; +; One section per remote RDS unit is configured, starting with 'Rds1' and +; working up consecutively +[Rds1] + +; Two methods of connecting to the unit are supported: TCP/IP or serial. +; +; ***************************************************************************** +; TCP/IP Connection Settings +; IP Address +; +; The IP address of the UDP port to send updates to, in dotted-quad notation. +; If using a serial connection, leave this entry blank! +IpAddress=127.0.0.1 + +; UDP Port +; +; The UDP port number to send updates to, in the range 0 - 65,535. +UdpPort=10001 +; ***************************************************************************** + +; ***************************************************************************** +; Serial Connection Settings +; +; The device file that corresponds to the serial device that is connected +; to the unit. If using a TCP/IP connection, leave this entry blank! +;Device=/dev/ttyS0 + +; Serial Baud Rate (in bps) +Speed=9600 + +; Parity (0=none, 1=even, 2=odd) +Parity=0 + +; Number of bits per data 'word'. +WordSize=8 +; ***************************************************************************** + +; Output Strings. The PAD data to output each time RDAirPlay changes +; play state, including any wildcards as placeholders for metadata values. +; Three different RDS values can be set: +; +; PS -- the standard "static" RDS PS field. +; Dynamic PS -- a special scrolling PS mode that allows strings longer than +; eight characters to be displayed on RDS compliant radios. +; See the model 713 manual for a discussion of the tradeoffs +; between the two PS display modes. +; Radiotext -- Standard RDS radiotext. +; +; The following wildcards are available: +; +; Now Next Field +; ---------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length (in milliseconds) +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +PsString= +DynamicPsString=%t +RadiotextString=%a + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output on this udp port. If set +; to 'Onair', then output will be generated only if RDAirPlays OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional RDS encoders can be configured by adding new sections... +;[Rds2] +;IpAddress=192.168.10.22 +;UdpPort=6789 +;Device=/dev/ttyS0 +;Speed=9600 +;Parity=0 +;WordSize=8 +;PsString= +;DynamicPsString=%t +;RadiotextString=%a +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_liqcomp.conf b/conf/rlm_liqcomp.conf new file mode 100644 index 00000000..91e8cc88 --- /dev/null +++ b/conf/rlm_liqcomp.conf @@ -0,0 +1,78 @@ +; rlm_liqcomp.conf +; +; This is the sample configuration file for the 'rlm_liqcomp' module for +; Rivendell, which can be used to output Now & Next data to one or more +; Liquid Compass Internet streaming encoders, using the following format: +; +; |<title>|<artist>|<cart-num>|<length>|<group>|<album>|<label>|<lf> +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. + +; Section Header +; +; One section per remote encoder is configured, starting with 'System1' and +; working up consecutively +[System1] + +; IP Address +; +; The IP address of the remote encoder, in dotted-quad notation. +IpAddress=192.168.10.22 + +; UDP Port +; +; The UDP port number of the remote encoder, in the range 0 - 65,535. +UdpPort=5273 + +; Field Definitions. The string to use to populate the <title>, <artist>, +; <album> and <label> fields sent to the encoder each time RDAirPlay changes +; play state. These can include wildcards as placeholders for metadata values. +; The following wildcards are available: +; +; Now Next Field +; ---------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length (in milliseconds) +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +Title=%t +Artist=%a +Album=%l +Label=%b + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output on this udp port. If set +; to 'Onair', then output will be generated only if the RDAirPlay OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional encoders can be configured by adding new sections... +;[System2] +;IpAddress=192.168.10.22 +;UdpPort=6789 +;Title=%u +;Artist=%a +;Album=%p +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_padpoint.conf b/conf/rlm_padpoint.conf new file mode 100644 index 00000000..de72788c --- /dev/null +++ b/conf/rlm_padpoint.conf @@ -0,0 +1,45 @@ +; rlm_padpoint.conf +; +; This is the sample configuration file for the 'rlm_padpoint' module for +; Rivendell, which can be used to output Now & Next data to one or more +; PadPoint PAD processors. +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. + +; Section Header +; +; One section per remote UDP port is configured, starting with 'PadPoint1' and +; working up consecutively +[PadPoint1] + +; IP Address +; +; The IP address of the remote PadPoint UDP port, in dotted-quad notation. +IpAddress=192.168.10.30 + +; UDP Port +; +; The UDP port number of the remote PadPoint UDP port, in the range 0 - 65,535. +UdpPort=1234 + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output on this udp port. If set +; to 'Onair', then output will be generated only if RDAirPlays OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional UDP destinations can be configured by adding new sections... +;[Udp2] +;FormatString=Artist: %a%r +;IpAddress=192.168.10.22 +;UdpPort=6789 +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_serial.conf b/conf/rlm_serial.conf new file mode 100644 index 00000000..160635cf --- /dev/null +++ b/conf/rlm_serial.conf @@ -0,0 +1,129 @@ +; rlm_serial.conf +; +; This is the sample configuration file for the 'rlm_serial' module for +; Rivendell, which can be used to output Now & Next data via one or more +; serial ports. +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. +; +; NOTE: The serial ports configured here have NOTHING TO DO with the +; ports configured in RDAdmin! These ports are used strictly by the +; 'rlm_serial' plugin, and will not be usable by any other Rivendell +; component. + +; Section Header +; +; One per serial device to be configured, starting with 'Serial1' and +; working up consecutively +[Serial1] + +; Serial Device +; +; The device file that corresponds to the serial device. +Device=/dev/ttyS0 + +; Serial Baud Rate (in bps) +Speed=9600 + +; Parity (0=none, 1=even, 2=odd) +Parity=0 + +; Number of bits per data 'word'. +WordSize=8 + +; Format String. The string to be output each time RDAirPlay changes +; play state, including any wildcards as placeholders for metadata values. +; The following wildcards are available: +; +; Now Next Field +; -------------------------------------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length (in milliseconds) +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +; \r \r Carriage Return (ASCII 13) +; \n \n Linefeed (ASCII 10) +; %d(<dt>) %D(<dt>) The start date/time, formatted according to <dt>. The +; following wildcards are available for <dt>: +; d - The day as a number without a leading zero (1 to 31). +; dd - The day as a number with a leading zero (01 to 31). +; ddd - The abbreviated localized day name ('Mon' or 'Sun'). +; dddd - The long localized day name ('Monday' or 'Sunday'). +; M - The month as a number without a leading zero +; (1 to 12). +; MM - The month as a number with a leading zero (01 to 12). +; MMM - The abbreviated localized month name ('Jan' or 'Dec'). +; MMMM - The long localized month name ("January' or +; 'December'). +; yy - The last two digits of the year. +; yyyy - The full four digits of the year. +; h - The hour without a leading zero (0 - 23, or 1 - 12 +; if using AM/PM display). +; hh - The hour with a leading zero (00 - 23, or 01 -12 if +; using AM/PM display). +; m - The minute without a leading zero (0 - 59). +; mm - The minute with a leading zero (00 - 59). +; s - The second without a leading zero (00 - 60). +; ss - The second with a leading zero (00 - 60). +; z - The milliseconds without a leading zero (0 - 999). +; zzz - The milliseconds with leading zeros (000 - 999). +; AP - Use AM/PM display. The 'AP' will be replaced by +; 'AM' or 'PM' as appropriate. +; ap - Use AM/PM display. The 'ap' will be replaced by +; 'am' or 'pm' as appropriate. +FormatString=NOW: %d(ddd MMM d hh:mm:ss yyyy): %t - %a\nNEXT: %D(ddd MMM d hh:mm:ss yyyy): %T - %A\n + +; Encoding. Defines the set of escapes to be applied to the PAD fields. +; The following options are available: +; +; 0 - Perform no character escaping. +; 1 - "XML" escaping: Escape reserved characters as per XML-v1.0 +; 2 - "Web" escaping: Escape reserved characters as per RFC 2396 Section 2.4 +Encoding=0 + +; Null Update Handling. Defines how 'null' updates --i.e. those with a cart +; number of '0' -- should be handled. +; +; 0 - Process all updates regardless of cart values. +; 1 - Process update only if the 'now' cart is not null. +; 2 - Process update only if the 'next' cart is not null. +; 3 - Process update only if both the 'now' and 'next' carts are not null. +ProcessNullUpdates=0 + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output on this serial port. If set +; to 'Onair', then output will be generated only if RDAirPlay's OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional serial ports can be configured by adding new sections... +;[Serial2] +;Device=/dev/ttyS1 +;Speed=9600 +;Parity=0 +;WordSize=8 +;FormatString=%t +;ProcessNullUpdates=0 +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_shoutcast1.conf b/conf/rlm_shoutcast1.conf new file mode 100644 index 00000000..91d3f899 --- /dev/null +++ b/conf/rlm_shoutcast1.conf @@ -0,0 +1,82 @@ +; rlm_shoutcast1.conf +; +; This is the sample configuration file for the 'rlm_shoutcast1' module for +; Rivendell, which can be used to update the metadata on an Shoutcast 1.x +; server using Now & Next data. +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. +; +; This module requires the curl(1) network transfer tool, included with most +; Linux distros. It is also available at http://curl.haxx.se/. + + +; Section Header +; +; One section per Shoutcast server instance is configured, starting with +; 'Shoutcast1' and working up consecutively +[Shoutcast1] + +; Password +; +; The password of the Shoutcast server instance to which to send updates. +Password=changeme + +; Host Name +; +; The fully-qualified domain name or IP address of the Shoutcast server +Hostname=shoutcast.example.com + +; Host Port +; +; The TCP port number of the Shoutcast server +Tcpport=8000 + +; Format String. The metadata to be sent each time RDAirPlay changes +; play state, including any wildcards as placeholders for metadata values. +; The following wildcards are available: +; +; Now Next Field +; ---------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length (in milliseconds) +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +FormatString=%t + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output to this account. If set +; to 'Onair', then output will be generated only if RDAirPlays OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional Shoutcast server instances can be configured by adding new +; sections... +; +;[Shoutcast2] +;Password=letmein +;Hostname=anotherone.example.com +;Tcpport=80 +;FormatString=%t by %a +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_spinitron_plus.conf b/conf/rlm_spinitron_plus.conf new file mode 100644 index 00000000..6065be15 --- /dev/null +++ b/conf/rlm_spinitron_plus.conf @@ -0,0 +1,129 @@ +; rlm_spinitron_plus.conf +; +; This is the sample configuration file for the 'rlm_spinitron_plus' module +; for Rivendell, which can be used log Now & Next data to the Spinitron +; online playlist service [http://www.spinitron.com]. +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. +; +; This module requires the curl(1) network transfer tool, included with most +; Linux distros. It is also available at http://curl.haxx.se/. + + +; Section Header +; +; One section per Spinitron account is configured, starting with +; 'Spinitron1' and working up consecutively +[Spinitron1] + +; Station; +; +; The station to be used for the Spinitron account to which to log the +; play-out. +Station=wxyz + +; Username +; +; Username for the Spinitron account to which to log the play-out. +Username=user@example.com + +; Password +; +; The password of the Spinitron account to which to log the play-out. +Password=changeme + +; PlaylistMode +; +; Set the Spinitron playlist mode to use when sending updates. +; +; (For a discussion of the implications of this setting on your +; Spinitron playlists, see Section 3.2 of the 'Spinitron Automation +; Integration' document, available from Spinitron). +; +; The following options are recognized: +; +; Full - Always use the Spinitron 'Full Automation' mode. +; Assist - Always use the Spinitron 'Live Assist' mode. +; Follow - Use the Spinitron 'Full Automation' mode when RDAirPlay +; is in Automatic, otherwise use the Spinitron 'Live Assist' mode. +PlaylistMode=Follow + +; Title. The string to be sent as the 'Title' field for each update, +; including any wildcards as placeholders for metadata values. +; The following wildcards are available: +; +; Now Next Field +; ---------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length (in milliseconds) +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +Title=%t + +; Artist. The string to be sent as the 'Artist' field for each update, +; including any wildcards as placeholders for metadata values. +; (See the 'Title' section above for a list of available wildcards). +Artist=%a + +; Album. The string to be sent as the 'Album' field for each update, +; including any wildcards as placeholders for metadata values. +; (See the 'Title' section above for a list of available wildcards). +Album=%l + +; Label. The string to be sent as the 'Label' field for each update, +; including any wildcards as placeholders for metadata values. +; (See the 'Title' section above for a list of available wildcards). +Label=%b + +; Composer. The string to be sent as the 'Composer' field for each update, +; including any wildcards as placeholders for metadata values. +; (See the 'Title' section above for a list of available wildcards). +Composer=%m + +; Notes. The string to be sent as the 'Notes' field for each update, +; including any wildcards as placeholders for metadata values. +; (See the 'Title' section above for a list of available wildcards). +Notes=%u + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output to this account. If set +; to 'Onair', then output will be generated only if RDAirPlays OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional Spinitron instances can be configured by adding new +; sections... +; +;[Spinitron2] +;Station=abcd +;Username=metoo +;Password=letmein +;Title=%t +;Artist=%a +;Album=%l +;Label=%b +;Composer=%m +;Notes=%u +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_spottrap.conf b/conf/rlm_spottrap.conf new file mode 100644 index 00000000..fd44af61 --- /dev/null +++ b/conf/rlm_spottrap.conf @@ -0,0 +1,106 @@ +; rlm_spottrap.conf +; +; This is the sample configuration file for the 'rlm_spottrap' module for +; Rivendell, which can be used to output Now & Next data to one or more +; remote UDP ports on the basis of Group and Length. +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. +; +; Module configuration consists of a list of rules, each of which consists +; in turn with a set of filter parameters and actions. Each PAD update is +; compared against the filter parameters of each rule. If the filter matches, +; then the rule actions are performed. +; + +; Rule Header +; +; One section per rule is configured, starting with 'Rule1' and +; working up consecutively +[Rule1] + +; FILTER PARAMETERS +; +; Group Name +; +; The name of the Rivendell group to match. +GroupName=BEDS + +; Minimum Length +; +; The minimum length, in milliseconds. A PAD update with a Length of less +; than this value will not be matched. +MinimumLength=0 + +; Maximum Length +; The maximum length, in milliseconds. A PAD update with a Length of more +; than this value will not be matched. +MaximumLength=10000000 + +; ACTION PARAMETERS +; +; IP Address +; +; The IP address of the remote UDP port, in dotted-quad notation. +IpAddress=192.168.10.30 + +; UDP Port +; +; The UDP port number of the remote UDP port, in the range 0 - 65,535. +UdpPort=5859 + +; Format String. The string to be output each time RDAirPlay changes +; play state, including any wildcards as placeholders for metadata values. +; The following wildcards are available: +; +; Now Next Field +; ---------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length (in milliseconds) +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +FormatString=DX 1 %h! + +; Default Format String. Similar to the 'FormatString=' parameter described +; above, but this string is output when the rule *doesn't* match. All of +; the wildcards described in the 'FormatString=' section apply here as well. +DefaultFormatString=DX 1 0! + + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output on this udp port. If set +; to 'Onair', then output will be generated only if RDAirPlay's OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional Rules can be configured by adding new sections... +;[Rule2] +;GroupName=TEST +;MinimumLength=0 +;MaximumLength=1000000 +;FormatString=Artist: %a%r +;DefaultFormatString=Artist: %a%r +;IpAddress=192.168.10.30 +;UdpPort=6789 +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_twitter.conf b/conf/rlm_twitter.conf new file mode 100644 index 00000000..8eba5149 --- /dev/null +++ b/conf/rlm_twitter.conf @@ -0,0 +1,76 @@ +; rlm_twitter.conf +; +; This is the sample configuration file for the 'rlm_twitter' module for +; Rivendell, which can be used to output Now & Next data to one or more +; Twitter accounts. +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. +; +; For information about the Twitter service, see http://www.twitter.com/. +; +; This module requires the curl(1) network transfer tool, included with most +; Linux distros. It is also available at http://curl.haxx.se/. + + +; Section Header +; +; One section per remote Twitter account is configured, starting with +; 'Twitter1' and working up consecutively +[Twitter1] + +; E-Mail Address +; +; The e-mail address of the Twitter account to which to send updates. +EmailAddress=someone@example.com + +; Password +; +; The password of the Twitter account to which to send updates. +Password=letmein + +; Format String. The string to be output each time RDAirPlay changes +; play state, including any wildcards as placeholders for metadata values. +; The following wildcards are available: +; +; Now Next Field +; ---------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length (in milliseconds) +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +FormatString=Now playing "%t" by "%a" + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output to this account. If set +; to 'Onair', then output will be generated only if RDAirPlays OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional Twitter accounts can be configured by adding new sections... +;[Twitter2] +;EmailAddress=someoneelse@example.com +;Password=letmein +;FormatString=Artist: %a%r +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_udp.conf b/conf/rlm_udp.conf new file mode 100644 index 00000000..ef6ed4cb --- /dev/null +++ b/conf/rlm_udp.conf @@ -0,0 +1,118 @@ +; rlm_udp.conf +; +; This is the sample configuration file for the 'rlm_udp' module for +; Rivendell, which can be used to output Now & Next data to one or more +; remote UDP ports. +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. + +; Section Header +; +; One section per remote UDP port is configured, starting with 'Udp1' and +; working up consecutively +[Udp1] + +; IP Address +; +; The IP address of the remote UDP port, in dotted-quad notation. +IpAddress=127.0.0.1 + +; UDP Port +; +; The UDP port number of the remote UDP port, in the range 0 - 65,535. +UdpPort=1234 + +; Format String. The string to be output each time RDAirPlay changes +; play state, including any wildcards as placeholders for metadata values. +; The following wildcards are available: +; +; Now Next Field +; -------------------------------------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length (in milliseconds) +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +; \r \r Carriage Return (ASCII 13) +; \n \n Linefeed (ASCII 10) +; %d(<dt>) %D(<dt>) The start date/time, formatted according to <dt>. The +; following wildcards are available for <dt>: +; d - The day as a number without a leading zero (1 to 31). +; dd - The day as a number with a leading zero (01 to 31). +; ddd - The abbreviated localized day name ('Mon' or 'Sun'). +; dddd - The long localized day name ('Monday' or 'Sunday'). +; M - The month as a number without a leading zero +; (1 to 12). +; MM - The month as a number with a leading zero (01 to 12). +; MMM - The abbreviated localized month name ('Jan' or 'Dec'). +; MMMM - The long localized month name ("January' or +; 'December'). +; yy - The last two digits of the year. +; yyyy - The full four digits of the year. +; h - The hour without a leading zero (0 - 23, or 1 - 12 +; if using AM/PM display). +; hh - The hour with a leading zero (00 - 23, or 01 -12 if +; using AM/PM display). +; m - The minute without a leading zero (0 - 59). +; mm - The minute with a leading zero (00 - 59). +; s - The second without a leading zero (00 - 60). +; ss - The second with a leading zero (00 - 60). +; z - The milliseconds without a leading zero (0 - 999). +; zzz - The milliseconds with leading zeros (000 - 999). +; AP - Use AM/PM display. The 'AP' will be replaced by +; 'AM' or 'PM' as appropriate. +; ap - Use AM/PM display. The 'ap' will be replaced by +; 'am' or 'pm' as appropriate. +FormatString=NOW: %d(ddd MMM d hh:mm:ss yyyy): %t - %a\nNEXT: %D(ddd MMM d hh:mm:ss yyyy): %T - %A\n + +; Encoding. Defines the set of escapes to be applied to the PAD fields. +; The following options are available: +; +; 0 - Perform no character escaping. +; 1 - "XML" escaping: Escape reserved characters as per XML-v1.0 +; 2 - "Web" escaping: Escape reserved characters as per RFC 2396 Section 2.4 +Encoding=0 + +; Null Update Handling. Defines how 'null' updates --i.e. those with a cart +; number of '0' -- should be handled. +; +; 0 - Process all updates regardless of cart values. +; 1 - Process update only if the 'now' cart is not null. +; 2 - Process update only if the 'next' cart is not null. +; 3 - Process update only if both the 'now' and 'next' carts are not null. +ProcessNullUpdates=0 + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output on this udp port. If set +; to 'Onair', then output will be generated only if RDAirPlays OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional UDP destinations can be configured by adding new sections... +;[Udp2] +;FormatString=Artist: %a%r +;IpAddress=192.168.10.22 +;UdpPort=6789 +;ProcessNullUpdates=0 +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_xds.conf b/conf/rlm_xds.conf new file mode 100644 index 00000000..917c19b7 --- /dev/null +++ b/conf/rlm_xds.conf @@ -0,0 +1,58 @@ +; rlm_xds.conf +; +; This is the sample configuration file for the 'rlm_xds' module for +; Rivendell, which can be used to output ISCI data for a Citidel X-Digital +; Vantive system via UDP. +; +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. + +; Section Header +; +; One section per Vantive UDP port is configured, starting with 'Udp1' and +; working up consecutively +[Udp1] + +; IP Address +; +; The IP address of the remote UDP port, in dotted-quad notation. +IpAddress=192.168.20.15 + +; UDP Port +; +; The UDP port number of the remote UDP port, in the range 0 - 65,535. +UdpPort=1234 + +; TTY Device +; +; Use the specified TTY device instead of UDP to send CICs. +TtyDevice=/dev/ttyS0 +TtySpeed=19200 + +; ISCI Prefix +; +; The string to prepend to transmitted ISCI code strings. +; +IsciPrefix=TEST_ + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output on this port. If set +; to 'Onair', then output will be generated only if RDAirPlays OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional Vantive destinations can be configured by adding new sections... +;[Udp2] +;IpAddress=192.168.10.22 +;UdpPort=6789 +;TtyDevice=/dev/ttyS1 +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/conf/rlm_xmpad.conf b/conf/rlm_xmpad.conf new file mode 100644 index 00000000..adf739aa --- /dev/null +++ b/conf/rlm_xmpad.conf @@ -0,0 +1,98 @@ +; rlm_xmpad.conf +; +; This is the sample configuration file for the 'rlm_xmpad' module for +; Rivendell, which can be used to output Now & Next data for an XM +; Satellite Radio channel. +; +; To enable this module, add it to the 'Loadable Modules' list in +; RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. The 'Argument' +; field should point to the location of this file. +; +; NOTE: The serial ports configured here have NOTHING TO DO with the +; ports configured in RDAdmin! These ports are used strictly by the +; 'rlm_serial' plugin, and will not be usable by any other Rivendell +; component. + +; Section Header +; +; One per serial device to be configured, starting with 'Serial1' and +; working up consecutively +[Serial1] + +; Serial Device +; +; The device file that corresponds to the serial device. +Device=/dev/ttyS0 + +; Serial Baud Rate (in bps) +Speed=4800 + +; Parity (0=none, 1=even, 2=odd) +Parity=0 + +; Number of bits per data 'word'. +WordSize=8 + +; Program ID +; A unique integer value, assigned by XM +ProgramID=1000000005 + +; Format Strings. There is one for each line of PAD data (total=2). +; The string is output each time RDAirPlay changes +; play state, including any wildcards as placeholders for metadata values. +; The following wildcards are available: +; +; Now Next Field +; ---------------------------------------------- +; %n %N The Rivendell cart number +; %h %H Event length +; %g %G The Rivendell group name +; %t %T Title +; %a %A Artist +; %l %L Album +; %y %Y Year +; %b %B Record Label +; %c %C Client +; %e %E Agency +; %m %M Composer +; %p %P Publisher +; %r %R Conductor +; %s %S Song ID +; %u %U User Definied +; %o %O Outcue +; %i %I Description +FormatString1=%c +FormatString2=%e + +; Display Size. The maximum length of text to be sent for each line. +DisplaySize1=8 +DisplaySize2=10 + +; Record Flag. Set to 'Yes' to allow recording, or 'No' to disable. +Recording=Yes + +; Heartbeat Interval. Should normally be set to '30'. +HeartbeatInterval=30 + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output on this serial port. If set +; to 'Onair', then output will be generated only if RDAirPlay's OnAir flag +; is active. +MasterLog=Yes +Aux1Log=Yes +Aux2Log=Yes + + +; Additional serial ports can be configured by adding new sections... +;[Serial2] +;Device=/dev/ttyS1 +;Speed=4800 +;Parity=0 +;WordSize=8 +;FormatString1=%t +;FormatString2=%a +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair diff --git a/configure.in b/configure.in new file mode 100644 index 00000000..9bc347bc --- /dev/null +++ b/configure.in @@ -0,0 +1,543 @@ +4dnl configure.in +dnl +dnl Autoconf configuration for Rivendell. +dnl Use autoconf to process this into a configure script +dnl +dnl (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com> +dnl +dnl $Id: configure.in,v 1.247.6.14.2.1 2014/07/15 18:49:45 cvs Exp $ +dnl $Date: 2014/07/15 18:49:45 $ +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License version 2 as +dnl published by the Free Software Foundation. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public +dnl License along with this program; if not, write to the Free Software +dnl Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +dnl + +AC_INIT(rivendell,`cat PACKAGE_VERSION`,Fred Gleason <fredg@paravelsystems.com>) +AM_INIT_AUTOMAKE(rivendell,`cat PACKAGE_VERSION`) +AC_SUBST(RPM_RELEASE,1) +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + +# +# Some Fully Resolved Install Paths +# (for the packaging system and friends) +# +if test ${prefix} = "NONE" ; then + PREFIX=/usr/local + AC_SUBST(LOCAL_PREFIX,/usr/local) +else + PREFIX=${prefix} + AC_SUBST(LOCAL_PREFIX,${prefix}) +fi + +# +# Basic Compiler Checks +# +AC_PROG_CXX +AC_PROG_LIBTOOL +AC_LANG(C++) + +# to avoid rpath usage : +# http://wiki.debian.net/index.cgi?RpathIssue +case ${host} in + *-pc-linux-gnu) + AC_MSG_RESULT([Fixing libtool for -rpath problems.]) + sed < libtool > libtool-2 \ + 's/^hardcode_libdir_flag_spec.*$/hardcode_libdir_flag_spec=" -D__LIBTOOL_IS_A_FOOL__ "/' + mv libtool-2 libtool + chmod 755 libtool + ;; +esac + + +# +# Option Switches +# +AC_ARG_ENABLE(hpi,[ --disable-hpi disable AudioScience HPI sound support], + [HPI_DISABLED=yes],[]) +AC_ARG_ENABLE(jack,[ --disable-jack disable JACK sound support], + [JACK_DISABLED=yes],[]) +AC_ARG_ENABLE(alsa,[ --disable-alsa disable direct ALSA sound support], + [ALSA_DISABLED=yes],[]) +AC_ARG_ENABLE(gpio,[ --disable-gpio disable General Purpose Input/Output GPIO support], + [GPIO_DISABLED=yes],[]) +AC_ARG_ENABLE(pam,[ --disable-pam disable Rivendell PAM pam_rd.so support], + [PAM_DISABLED=yes],[]) +AC_ARG_ENABLE(mad,[ --disable-mad disable MPEG decode support], + [MAD_DISABLED=yes],[]) +AC_ARG_ENABLE(twolame,[ --disable-twolame disable MPEG Layer 2 encode support], + [TWOLAME_DISABLED=yes],[]) +AC_ARG_ENABLE(lame,[ --disable-lame disable MPEG Layer 3 encode support], + [LAME_DISABLED=yes],[]) +AC_ARG_ENABLE(flac,[ --disable-flac disable FLAC encode/decode support], + [FLAC_DISABLED=yes],[]) + +# +# Check for Qt +# +BNV_HAVE_QT +if test $have_qt = "no" ; then + AC_MSG_ERROR([*** Qt toolkit not found, unable to continue ***]) +fi + +# +# Determine the target architecture +# +AR_GCC_TARGET() +AC_SUBST(VENDOR,$ar_gcc_distro) +AC_SUBST(ARCH,$ar_gcc_arch) +if test $ar_gcc_arch = x86_64 ; then + LIB_PATH=$PREFIX/lib64 + AC_SUBST(RD_LIB_PATH,lib64) +else + LIB_PATH=$PREFIX/lib + AC_SUBST(RD_LIB_PATH,lib) +fi + +# +# Determine Distro +# +AR_GET_DISTRO() +AC_SUBST(DISTRO,$ar_gcc_distro) +if test $ar_gcc_distro = suse ; then + AC_SUBST(APACHE_PKG,"apache2") + AC_SUBST(APACHE_CONFIG_DIR,"/etc/apache2/conf.d") + AC_SUBST(CONSOLEHELPER_RDALSACONFIG,"") + AC_SUBST(USERMODE_PKG,"") + AC_SUBST(QT3_MYSQL_PKG,"qt3-mysql") + AC_SUBST(QT3_DEVEL_PKG,"qt3-devel") + AC_SUBST(MYSQL_PKG,"mysql") +else + AC_SUBST(APACHE_PKG,"httpd") + AC_SUBST(APACHE_CONFIG_DIR,"/etc/httpd/conf.d") + AC_SUBST(CONSOLEHELPER_RDALSACONFIG,"/usr/bin/rdalsaconfig-root") + AC_SUBST(USERMODE_PKG,"usermode") + AC_SUBST(QT3_MYSQL_PKG,"qt-MySQL") + if test $ar_distro_major -ge 6 ; then + AC_SUBST(QT3_DEVEL_PKG,"qt3-devel") + else + AC_SUBST(QT3_DEVEL_PKG,"qt-devel") + fi + AC_SUBST(MYSQL_PKG,"mysqld") +fi + +# +# Check for OggVorbis +# +AC_CHECK_HEADER(vorbis/vorbisfile.h,[VORBIS_FOUND=yes],[]) +if test $VORBIS_FOUND = yes ; then + AC_DEFINE(HAVE_VORBIS) + AC_SUBST(LIBVORBIS,"-lvorbisfile -lvorbisenc") +else + AC_SUBST(LIBVORBIS,"") +fi + +# +# Check for Secret Rabbit Code +# +AC_CHECK_HEADER(samplerate.h,[SRC_FOUND=yes],[AC_MSG_ERROR([*** LibSampleRate not found ***])]) +AC_CHECK_FUNC(src_short_to_float_array,[SRC_CONV_FOUND=yes],[]) + +# +# Check for Libsndfile +# +AC_CHECK_HEADER(sndfile.h,[],[AC_MSG_ERROR([*** Libsndfile not found ***])]) + +# +# Check for LibParanoia +# +AC_CHECK_HEADER(cdda_interface.h,[PARANOIA_FOUND=yes],[]) +if test $PARANOIA_FOUND ; then + AC_SUBST(PARANOIA_INCLUDES,"<cdda_interface.h>") +else + # RedHat/CentOS puts this in a subdirectory + AC_CHECK_HEADER(cdda/cdda_interface.h,[PARANOIA_FOUND=yes],[]) + if test $PARANOIA_FOUND ; then + AC_SUBST(PARANOIA_INCLUDES,"<cdda/cdda_interface.h>") + else + AC_MSG_ERROR([*** LibParanoia not found ***]) + fi +fi + +# +# Check for Id3Lib +# +AC_CHECK_HEADER(id3/tag.h,[],[AC_MSG_ERROR([*** Id3Lib not found ***])]) + +# +# Check for LibCurl +# +AC_CHECK_HEADER(curl/curl.h,[],[AC_MSG_ERROR([*** LibCurl not found ***])]) + +# +# Check for PAM +# +AC_CHECK_HEADER(security/pam_appl.h,[],[AC_MSG_ERROR([*** PAM not found ***])]) + +# +# Check for SoundTouch +# +AC_CHECK_HEADER(soundtouch/SoundTouch.h,[],[AC_MSG_ERROR([*** SoundTouch not found ***])]) + +# +# Check for FLAC +# +if test -z $FLAC_DISABLED ; then + AC_CHECK_HEADER(FLAC++/encoder.h,[FLAC_FOUND=yes],[]) + if test $FLAC_FOUND ; then + FLAC_LIBS="-lFLAC -lFLAC++" + AC_DEFINE(HAVE_FLAC) + fi + AC_CHECK_LIB(FLAC,FLAC__metadata_get_tags,[FLAC_METADATA_FOUND=yes],[]) +fi + +# +# Set Hard Library Dependencies +# +AC_SUBST(LIB_RDLIBS,"-lqui -lrd -lcurl -lid3 $FLAC_LIBS -lsndfile -lsamplerate -lcdda_interface -lcdda_paranoia -lcrypt -ldl -lpam -lSoundTouch") + +# +# Setup MPEG Dependencies +# +AC_CHECK_HEADER(mad.h,[MAD_FOUND=yes],[]) +AC_CHECK_HEADER(twolame.h,[TWOLAME_FOUND=yes],[]) +AC_CHECK_HEADER(lame/lame.h,[LAME_FOUND=yes],[]) +if test $MAD_FOUND ; then + if test -z $MAD_DISABLED ; then + AC_DEFINE(HAVE_MAD) + USING_MAD=yes + fi +fi +if test $TWOLAME_FOUND ; then + if test -z $TWOLAME_DISABLED ; then + AC_DEFINE(HAVE_TWOLAME) + USING_TWOLAME=yes + fi +fi +if test $LAME_FOUND ; then + if test -z $LAME_DISABLED ; then + AC_DEFINE(HAVE_LAME) + USING_LAME=yes + fi +fi + +# +# Setup Sound API Dependencies +# +AC_CHECK_HEADER(asihpi/hpi.h,[HPI_FOUND=yes],[]) +AC_CHECK_HEADER(jack/jack.h,[JACK_FOUND=yes],[]) +AC_CHECK_HEADER(alsa/asoundlib.h,[ALSA_FOUND=yes],[]) +if test $HPI_FOUND ; then + if test -z $HPI_DISABLED ; then + USING_HPI=yes + AC_DEFINE(HPI,yes) + AC_SUBST(LIBHPI,"-lrdhpi -lhpi") + AC_SUBST(HPI_FILE1,$LIB_PATH/librdhpi-$VERSION.so) + AC_SUBST(HPI_FILE2,$LIB_PATH/librdhpi.a) + AC_SUBST(HPI_FILE3,$LIB_PATH/librdhpi.la) + AC_SUBST(HPI_FILE4,$LIB_PATH/librdhpi.so) + AC_SUBST(HPI_FILE5,$PREFIX/bin/rdhpiinfo) + if test $ar_gcc_distro = suse ; then + AC_SUBST(HPI_FILE6,"") + else + AC_SUBST(HPI_FILE6,$PREFIX/bin/rdhpiinfo-root) + fi + AC_SUBST(HPI_FILE7,$PREFIX/share/rivendell/rdhpi_es.qm) + AC_SUBST(HPI_FILE8,$PREFIX/share/rivendell/rdhpi_cs.qm) + AC_SUBST(HPI_FILE9,$PREFIX/share/rivendell/rdhpi_de.qm) + AC_SUBST(HPI_FILE10,$PREFIX/share/rivendell/rdhpi_nn.qm) + AC_SUBST(HPI_FILE11,$PREFIX/share/rivendell/rdhpi_nb.qm) + AC_SUBST(HPI_FILE12,$PREFIX/share/rivendell/rdhpi_pt_BR.qm) + AC_SUBST(HPI_FILE13,$PREFIX/share/applications/rivendell-rdhpiinfo-root.desktop) + AC_SUBST(HPI_FILE14,/etc/pam.d/rdhpiinfo-root) + AC_SUBST(HPI_FILE15,/etc/security/console.apps/rdhpiinfo-root) + else + AC_SUBST(LIBHPI,"") + AC_SUBST(HPI_FILE1,"") + AC_SUBST(HPI_FILE2,"") + AC_SUBST(HPI_FILE3,"") + AC_SUBST(HPI_FILE4,"") + AC_SUBST(HPI_FILE5,"") + AC_SUBST(HPI_FILE6,"") + AC_SUBST(HPI_FILE7,"") + AC_SUBST(HPI_FILE8,"") + AC_SUBST(HPI_FILE9,"") + AC_SUBST(HPI_FILE10,"") + AC_SUBST(HPI_FILE11,"") + AC_SUBST(HPI_FILE12,"") + AC_SUBST(HPI_FILE13,"") + AC_SUBST(HPI_FILE14,"") + AC_SUBST(HPI_FILE15,"") + fi +else + AC_SUBST(LIBHPI,"") + AC_SUBST(HPI_FILE1,"") + AC_SUBST(HPI_FILE2,"") + AC_SUBST(HPI_FILE3,"") + AC_SUBST(HPI_FILE4,"") + AC_SUBST(HPI_FILE5,"") + AC_SUBST(HPI_FILE6,"") + AC_SUBST(HPI_FILE7,"") + AC_SUBST(HPI_FILE8,"") + AC_SUBST(HPI_FILE9,"") + AC_SUBST(HPI_FILE10,"") + AC_SUBST(HPI_FILE11,"") + AC_SUBST(HPI_FILE12,"") + AC_SUBST(HPI_FILE13,"") + AC_SUBST(HPI_FILE14,"") + AC_SUBST(HPI_FILE15,"") +fi +AM_CONDITIONAL([HPI_RD_AM], [test "$USING_HPI" = yes]) + +if test $JACK_FOUND ; then + if test -z $JACK_DISABLED ; then + if test -z $SRC_FOUND ; then + AC_MSG_ERROR([*** libsamplerate not found, but is needed for JACK support ***]) + fi + AC_DEFINE(JACK,yes) + AC_SUBST(LIBJACK,-ljack) + SRC_NEEDED=yes + USING_JACK=yes + else + AC_SUBST(LIBJACK,"") + fi +else + AC_SUBST(LIBJACK,"") +fi + +if test $ALSA_FOUND ; then + if test -z $ALSA_DISABLED ; then + if test -z $SRC_FOUND ; then + AC_MSG_ERROR([*** libsamplerate not found, but is needed for ALSA support ***]) + fi + AC_DEFINE(ALSA,yes) + AC_SUBST(LIBALSA,-lasound) + SRC_NEEDED=yes + USING_ALSA=yes + else + AC_SUBST(LIBALSA,"") + fi +else + AC_SUBST(LIBALSA,"") +fi +AM_CONDITIONAL([ALSA_RD_AM], [test "$USING_ALSA" = yes]) + +if test -z $SRC_NEEDED ; then + AC_SUBST(LIBSRC,"") +else + AC_DEFINE(SRC,yes) + AC_SUBST(LIBSRC,-lsamplerate) +fi +if test -z $SRC_CONV_FOUND ; then + AC_MSG_NOTICE([Using local format converters]) +else + AC_MSG_NOTICE([Using SRC format converters]) + AC_DEFINE(HAVE_SRC_CONV,yes) +fi +if test -z $FLAC_METADATA_FOUND ; then + AC_MSG_NOTICE([Ogg Metadata tags will not be supported]) +else + AC_DEFINE(HAVE_FLAC_METADATA,yes) +fi + +# +# pam_rd hooks +# +if test -z $PAM_DISABLED ; then + AC_CHECK_HEADERS([security/pam_modules.h security/_pam_macros.h],[PAM_FOUND=yes],[PAM_FOUND=no;break]) + if test $PAM_FOUND = yes ; then + USING_PAM=yes + fi +fi +AM_CONDITIONAL([PAM_RD_AM], [test "$USING_PAM" = yes]) + +# +# Distro-Specific Stuff +# +if test -f /etc/gentoo-release ; then + rm -f rivendell + ln -s rivendell-gentoo rivendell + AC_MSG_NOTICE([Configured to install Gentoo-specific init script]) +else + rm -f rivendell + ln -s rivendell-suse rivendell + AC_MSG_NOTICE([Configured to install generic init script]) +fi + +# +# Configure RPM Build +# +AC_MSG_CHECKING([for $WIN32_SETUPS/rivendell-$VERSION-$RPM_RELEASE.exe]) +if test -f $WIN32_SETUPS/rivendell-$VERSION-$RPM_RELEASE.exe ; then + AC_MSG_RESULT([yes]) + AC_SUBST(WIN32_SOURCE,"$WIN32_SETUPS/rivendell-$VERSION-$RPM_RELEASE.exe") + AC_SUBST(WIN32_PATH,"/var/win32/rivendell-$VERSION-$RPM_RELEASE.exe") +else + AC_MSG_RESULT([no]) + AC_SUBST(WIN32_SOURCE,"") + AC_SUBST(WIN32_PATH,"") +fi +AC_CHECK_PROG(RPMBUILD_FOUND,rpmbuild,[yes],[]) +if test -z $RPMBUILD_FOUND ; then + AC_SUBST(RPMBUILD,rpm) +else + AC_SUBST(RPMBUILD,rpmbuild) +fi +if test -d /usr/src/redhat ; then + AC_SUBST(RPM_ROOT,/usr/src/redhat) + AC_SUBST(VENDOR,redhat) +else + AC_SUBST(RPM_ROOT,/usr/src/packages) + AC_SUBST(VENDOR,suse) +fi + +AC_CONFIG_FILES([rivendell.spec \ + Makefile \ + make_slack \ + slack-desc \ + rivendell-suse \ + rdrepld-suse \ + conf/rd-bin.conf \ + icons/Makefile \ + helpers/Makefile \ + lib/rdpaths.h \ + lib/Makefile \ + rdhpi/Makefile \ + rlm/Makefile \ + cae/Makefile \ + utils/Makefile \ + utils/rdalsaconfig/Makefile \ + utils/rdcheckcuts/Makefile \ + utils/rdchunk/Makefile \ + utils/rdcollect/Makefile \ + utils/rddbcheck/Makefile \ + utils/rddelete/Makefile \ + utils/rddgimport/Makefile \ + utils/rddiscimport/Makefile \ + utils/rdgen/Makefile \ + utils/rdhpiinfo/Makefile \ + utils/rdgpimon/Makefile \ + utils/rdimport/Makefile \ + utils/rdmaint/Makefile \ + utils/rdmarkerset/Makefile \ + utils/rdpopup/Makefile \ + utils/rdpurgecasts/Makefile \ + utils/rdsoftkeys/Makefile \ + utils/rmlsend/Makefile \ + utils/sas_shim/Makefile \ + web/Makefile \ + web/rdfeed/Makefile \ + web/rdcastmanager/Makefile \ + web/rdxport/Makefile \ + web/tests/Makefile \ + conf/Makefile \ + docs/Makefile \ + docs/tables/Makefile \ + docs/examples/Makefile \ + debian/Makefile \ + debian/patches/Makefile \ + xdg/Makefile \ + rdadmin/Makefile \ + scripts/Makefile \ + ripcd/Makefile \ + rdlogin/Makefile \ + rdlibrary/Makefile \ + rdcatch/Makefile \ + rdcatchd/Makefile \ + rdlogedit/Makefile \ + rdlogmanager/Makefile \ + rdairplay/Makefile \ + rdpanel/Makefile \ + rdcartslots/Makefile \ + rdcastmanager/Makefile \ + rdselect/Makefile \ + rdmonitor/Makefile \ + rdrepld/Makefile \ + tests/Makefile \ + importers/Makefile \ + ios/Makefile \ + ios/rmlsend/Makefile \ + ios/rmlsend/Classes/Makefile \ + ios/rmlsend/RMLSend.xcodeproj/Makefile \ + pam_rd/Makefile ]) +AC_OUTPUT() +chmod 755 make_slack +chmod 755 rivendell-suse +chmod 755 rdrepld-suse + +# +# Configuration Results +# +AC_MSG_NOTICE() +AC_MSG_NOTICE("|-----------------------------------------------------|") +AC_MSG_NOTICE("| *** RIVENDELL CONFIGURATION SUMMARY *** |") +AC_MSG_NOTICE("|-----------------------------------------------------|") +AC_MSG_NOTICE("| Configured Audio Drivers: |") +if test -z $USING_ALSA ; then +AC_MSG_NOTICE("| Advanced Linux Sound Architecture (ALSA) ... No |") +else +AC_MSG_NOTICE("| Advanced Linux Sound Architecture (ALSA) ... Yes |") +fi +if test -z $USING_HPI ; then +AC_MSG_NOTICE("| AudioScience HPI ... No |") +else +AC_MSG_NOTICE("| AudioScience HPI ... Yes |") +fi +if test -z $USING_JACK ; then +AC_MSG_NOTICE("| JACK Audio Connection Kit ... No |") +else +AC_MSG_NOTICE("| JACK Audio Connection Kit ... Yes |") +fi +AC_MSG_NOTICE("| |") +AC_MSG_NOTICE("| Audio Codecs: |") +if test -z $FLAC_FOUND ; then +AC_MSG_NOTICE("| FLAC Encoding/Decoding Support ... No |") +else +AC_MSG_NOTICE("| FLAC Encoding/Decoding Support ... Yes |") +fi +if test -z $USING_MAD ; then +AC_MSG_NOTICE("| MPEG Decoding Support ... No |") +else +AC_MSG_NOTICE("| MPEG Decoding Support ... Yes |") +fi +if test -z $USING_TWOLAME ; then +AC_MSG_NOTICE("| MPEG Layer 2 Encoding Support ... No |") +else +AC_MSG_NOTICE("| MPEG Layer 2 Encoding Support ... Yes |") +fi +if test -z $USING_LAME ; then +AC_MSG_NOTICE("| MPEG Layer 3 Encoding Support ... No |") +else +AC_MSG_NOTICE("| MPEG Layer 3 Encoding Support ... Yes |") +fi +if test -z $VORBIS_FOUND ; then +AC_MSG_NOTICE("| OggVorbis Encoding/Decoding Support ... No |") +else +AC_MSG_NOTICE("| OggVorbis Encoding/Decoding Support ... Yes |") +fi +AC_MSG_NOTICE("| |") +AC_MSG_NOTICE("| Optional Components: |") +if test -z $USING_PAM ; then +AC_MSG_NOTICE("| Rivendell PAM pam_rd.so Support ... No |") +else +AC_MSG_NOTICE("| Rivendell PAM pam_rd.so Support ... Yes |") +fi +AC_MSG_NOTICE("|-----------------------------------------------------|") +AC_MSG_NOTICE() +if test $WIN32_SOURCE ; then +AC_MSG_NOTICE([Including RPM win32 setup from:]) +AC_MSG_NOTICE([ $WIN32_SOURCE]) +AC_MSG_NOTICE() +fi +AC_MSG_NOTICE() +AC_MSG_NOTICE(Now enter 'make' to build the software.) +AC_MSG_NOTICE() diff --git a/debian/Makefile.am b/debian/Makefile.am new file mode 100644 index 00000000..bcf3a99a --- /dev/null +++ b/debian/Makefile.am @@ -0,0 +1,68 @@ +## automake.am +## +## debian/automake.am for Rivendell +## +## Use automake to process this into a Makefile.in +## +## (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +## +## $Id: Makefile.am,v 1.9.14.1 2012/11/29 01:37:35 cvs Exp $ +## $Date: 2012/11/29 01:37:35 $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## + +SUBDIRS = patches + +EXTRA_DIST = changelog\ + compat\ + control\ + copyright\ + librivendell.install\ + menu\ + rdadmin.desktop\ + rdadmin.xpm\ + rdairplay.desktop\ + rdairplay.xpm\ + rdcatch.desktop\ + rdcatch.xpm\ + rdlibrary.desktop\ + rdlibrary.xpm\ + rdlogedit.desktop\ + rdlogedit.xpm\ + rdlogin.desktop\ + rdlogin.xpm\ + rdlogmanager.desktop\ + rdlogmanager.xpm\ + README.Debian\ + rivendell.conffiles\ + rivendell.config\ + rivendell.docs.in\ + rivendell.install\ + rivendell.logrotate\ + rivendell.templates\ + rivendell.examples\ + rivendell.init\ + rivendell.postinst\ + rivendell.postrm\ + rules + +CLEANFILES = *~\ + rivendell.docs\ + substvars + +MAINTAINERCLEANFILES = *~\ + aclocal.m4\ + configure\ + Makefile.in diff --git a/debian/README.Debian b/debian/README.Debian new file mode 100644 index 00000000..935cd53a --- /dev/null +++ b/debian/README.Debian @@ -0,0 +1,55 @@ +# +# Rivendell introduction: +# + +The Rivendell radio broadcast automation solution has been installed. + +The next step is to run the "rdadmin" command with a user that has permissions +to the rivendell system. The first time it will prompt for a MySQL userid and +password that has permissions to connect and create the database. + +Once the database has been created, run the "rdadmin" command again. From this +point on, rdadmin will allow for configuring of Rivendell. + +The default user accounts within Rivendell are "admin" and "user", both with no +password. + + +# +# Creating *nix user accounts that have permission to access Rivendell +# + +# first create the user, such as foouser +adduser foouser + +# add the user to the audio group, so they can access the sound card +adduser foouser audio + +# add the user to the rivendell group, so they can access rivendell resources. +adduser foouser rivendell + + +# +# ALSA Rivendell integration +# +In order for Rivendell to recognize an ALSA sound adapter, there must exist a +standard ALSA configuration file with a card named "rd0" defined. + +The ALSA configuration file can be global (/etc/asound.conf) or per user +(~/.asoundrc). + +Sample contents for the configuration file to define rd0 follow: +pcm.rd0 { + type hw + card 1 +} +ctl.rd0 { + type hw + card 1 +} + +More information on ALSA configuration files can be found here: +http://www.alsa-project.org/alsa-doc/doc-php/asoundrc.php + +More information on Rivendell and ALSA can also be found in +/usr/share/doc/rivendell/ALSA.txt . diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 00000000..ae447738 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,387 @@ +rivendell (1.0.0~rc0-1) unstable; urgency=low + + * New release. + + -- Federico Grau <grauf@rfa.org> Thu, 10 Apr 2008 10:00:25 -0400 + +rivendell (0.9.83-1) unstable; urgency=low + + * New release. + + -- Federico Grau <grauf@rfa.org> Thu, 27 Dec 2007 10:00:58 -0500 + +rivendell (0.9.82-1) unstable; urgency=low + + * New release. + + -- Federico Grau <grauf@rfa.org> Wed, 12 Sep 2007 13:43:18 -0400 + +rivendell (0.9.81-1) unstable; urgency=low + + * New release. + + -- Federico Grau <grauf@rfa.org> Fri, 13 Jul 2007 10:45:59 -0400 + +rivendell (0.9.79-5) unstable; urgency=low + + * Updated copyright with Fred Gleason's new email address. + + -- Federico Grau <grauf@rfa.org> Thu, 15 Feb 2007 12:59:23 -0500 + +rivendell (0.9.79-4) unstable; urgency=low + + * More work on the Audacity integration with Rivendell patch. + + -- Federico Grau <grauf@rfa.org> Tue, 30 Jan 2007 14:44:07 -0500 + +rivendell (0.9.79-3) unstable; urgency=low + + * Test build with 08_audacity patch which add audacity integration to + rivendell (thanks to Panvid Co and Pavel Domsa <pdomsa@seznam.cz> for the + initial patch). + + -- Federico Grau <grauf@rfa.org> Mon, 29 Jan 2007 18:12:14 -0500 + +rivendell (0.9.79-2) unstable; urgency=low + + * Added 07_extra_paren patch which corrects rdadmin/createdb.cpp bug + creating db. + + -- Federico Grau <grauf@rfa.org> Tue, 12 Dec 2006 16:35:52 -0500 + +rivendell (0.9.79-1) unstable; urgency=low + + * New upstream release. + + -- Federico Grau <grauf@rfa.org> Thu, 7 Dec 2006 12:13:31 -0500 + +rivendell (0.9.77-1) unstable; urgency=low + + * New upstream release. + + -- Federico Grau <grauf@rfa.org> Mon, 4 Dec 2006 18:18:10 -0500 + +rivendell (0.9.74-2) unstable; urgency=low + + * Added (and enabled) a patch to escape SQL column names when generating + reports 06_escapesql.dpatch . + + -- Federico Grau <grauf@rfa.org> Fri, 29 Sep 2006 18:42:30 -0400 + +rivendell (0.9.74-1) unstable; urgency=low + + * New upstream release. + * Disabled music scheduler patch. + + -- Federico Grau <grauf@rfa.org> Thu, 28 Sep 2006 12:49:51 -0400 + +rivendell (0.9.73-1.2) unstable; urgency=low + + * Added libhpi-dev to the build-dep list. + * Recompiling with libhpi-dev installed locally. + + -- Henry Rivera <riverah@rfa.org> Thu, 14 Sep 2006 20:46:40 -0400 + +rivendell (0.9.73-1.1) unstable; urgency=low + + * Enabled music scheduler patch. + + -- Henry Rivera <riverah@rfa.org> Thu, 14 Sep 2006 07:31:04 -0400 + +rivendell (0.9.73-1) unstable; urgency=low + + * New upstream release. + * Added libpam0g-dev to the build-dep package list. + + -- Henry Rivera <riverah@rfa.org> Thu, 14 Sep 2006 06:04:49 -0400 + +rivendell (0.9.71-1) unstable; urgency=low + + * New upstream release. + * corrected package description in control. + * Added rdlogin icon (xpm, desktop, menu) to debian dir. + + -- Federico Grau <grauf@rfa.org> Mon, 14 Aug 2006 18:05:46 -0400 + +rivendell (0.9.70-4) unstable; urgency=low + + * This time with the patch enabled :-/ . + + -- Federico Grau <grauf@rfa.org> Wed, 9 Aug 2006 16:38:15 -0400 + +rivendell (0.9.70-3) unstable; urgency=low + + * Add patch 05_pam_rd_hack, with edits to set the DEFAULTUSER instead of + regular user (thus no changes will be required to ripcd to pickup the user + change). + + -- Federico Grau <grauf@rfa.org> Wed, 9 Aug 2006 15:08:19 -0400 + +rivendell (0.9.70-2) unstable; urgency=low + + * Add patch 04_pam_rd_cvs_fixes.dpatch with pam_rd efforts in CVS since + 0.9.70. + * disabled music scheduler patch for now. + + -- Federico Grau <grauf@rfa.org> Wed, 9 Aug 2006 13:43:00 -0400 + +rivendell (0.9.70-1.4) unstable; urgency=low + + * Update with a new music scheduler patch. + + -- Federico Grau <grauf@rfa.org> Wed, 9 Aug 2006 12:44:56 -0400 + +rivendell (0.9.70-1.3) unstable; urgency=low + + * This time with the patch enabled :-/ . + + -- Federico Grau <grauf@rfa.org> Tue, 8 Aug 2006 13:50:23 -0400 + +rivendell (0.9.70-1.2) unstable; urgency=low + + * Update the patch from Stefan Gabrial. + + -- Federico Grau <grauf@rfa.org> Tue, 8 Aug 2006 12:35:46 -0400 + +rivendell (0.9.70-1.1) unstable; urgency=low + + * Applied music scheduler patch from Stefan Gabriel <stg@st-gabriel.de> . + This is debian/patches/10_music_scheduler. + + -- Federico Grau <grauf@rfa.org> Tue, 8 Aug 2006 11:14:27 -0400 + +rivendell (0.9.70-1) unstable; urgency=low + + * New upstream release. + + -- Federico Grau <grauf@rfa.org> Mon, 7 Aug 2006 15:54:57 -0400 + +rivendell (0.9.68-0) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Thu,25 May 2006 12:15:00 +0200 + +rivendell (0.9.64-0) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Mon,23 Jan 2005 10:30:00 +0100 + +rivendell (0.9.63-0) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Sat,17 Dec 2005 11:30:00 +0100 + +rivendell (0.9.62-0) unstable; urgency=low + + * new upstream release + * added alsa dependency + + -- Alban Peignier <alban.peignier@free.fr> Thu,1 Dec 2005 10:00:00 +0100 + +rivendell (0.9.55-0) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Wed,12 Oct 2005 09:30:00 +0200 + +rivendell (0.9.53-0) unstable; urgency=low + + * added menus (patch from Federico Grau <grauf@rfa.org>) + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Sat,01 Oct 2005 11:45:00 +0200 + +rivendell (0.9.51-0) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Wed,31 Aug 2005 22:30:00 +0200 + +rivendell (0.9.49) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Thu,18 Aug 2005 19:10:00 +0200 + +rivendell (0.9.44) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Sat,16 Jul 2005 13:30:00 +0200 + +rivendell (0.9.39) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Mon,11 Jul 2005 12:30:00 +0200 + +rivendell (0.9.38) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Thu,07 Jul 2005 10:30:00 +0200 + +rivendell (0.9.34) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Fri,03 Jun 2005 00:30:00 +0200 + +rivendell (0.9.33+cvs20050523) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Mon,23 May 2005 15:30:00 +0200 + +rivendell (0.9.33) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Sat,21 May 2005 11:50:00 +0200 + +rivendell (0.9.32) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Tue,10 May 2005 23:50:00 +0200 + +rivendell (0.9.28+cvs20050430) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Sat,30 Apr 2005 10:15:00 +0200 + +rivendell (0.9.28) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Wed,09 Mar 2005 10:30:00 +0100 + +rivendell (0.9.26) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Fri,18 Feb 2005 08:45:00 +0100 + +rivendell (0.9.21) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Sun,30 Jan 2005 23:20:00 +0100 + +rivendell (0.9.17-1) unstable; urgency=low + + * fixed the toolame dependency problem (notified by Richard Lamont) + + -- Alban Peignier <alban.peignier@free.fr> Sat,22 Jan 2005 14:40:00 +0100 + +rivendell (0.9.17) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Tue,18 Jan 2005 20:55:00 +0100 + +rivendell (0.9.16) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Tue,28 Dec 2004 10:00:00 +0100 + +rivendell (0.9.15) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Sat,18 Dec 2004 17:00:00 +0100 + +rivendell (0.9.13+cvs20041216-1) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Fri,17 Dec 2004 09:00:00 +0100 + +rivendell (0.9.13+cvs20041209-1) unstable; urgency=low + + * new upstream release + * use "rdadmin --check-db" into the init script + + -- Alban Peignier <alban.peignier@free.fr> Thu,09 Dec 2004 19:40:00 +0100 + +rivendell (0.9.12+cvs20041207-1) unstable; urgency=low + + * fixed a startup daemon problems, now use the AudioOwner defined into rd.conf + + -- Alban Peignier <alban.peignier@free.fr> Mon,07 Dec 2004 19:40:00 +0100 + +rivendell (0.9.12+cvs20041206-1) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Mon,06 Dec 2004 21:40:00 +0100 + +rivendell (0.9.12+cvs20041124-1) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Wed,24 Nov 2004 23:30:00 +0100 + +rivendell (0.9.12+cvs20041124) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Wed,24 Nov 2004 10:30:00 +0100 + +rivendell (0.9.12+cvs20041118) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Thu,18 Nov 2004 08:30:00 +0100 + +rivendell (0.9.12) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Tue,16 Nov 2004 09:30:00 +0100 + +rivendell (0.9.11) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Sat,13 Nov 2004 11:30:00 +0100 + +rivendell (0.9.9) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Mon,04 Nov 2004 20:00:00 +0100 + +rivendell (0.9.4) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Thu, 28 Oct 2004 12:00:00 +0200 + +rivendell (0.9.0+cvs20040831-1) unstable; urgency=low + + * docs directory now is packaged + * ChangeLog is now used as upstream changelog + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Tue, 31 Aug 2004 14:15:00 +0200 + +rivendell (0.9.0+cvs20040829-1) unstable; urgency=low + + * add post installation operations to directories and a rivendell group + * add init.d script to start the daemon + * add configuration examples + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Sun, 29 Aug 2004 11:50:00 +0200 + +rivendell (0.9.0-1) unstable; urgency=low + + * new upstream release + + -- Alban Peignier <alban.peignier@free.fr> Mon, 24 Aug 2004 22:50:00 +0200 diff --git a/debian/compat b/debian/compat new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +4 diff --git a/debian/control b/debian/control new file mode 100644 index 00000000..702ebb23 --- /dev/null +++ b/debian/control @@ -0,0 +1,38 @@ +Source: rivendell +Section: sound +Priority: optional +Maintainer: Alban Peignier <alban.peignier@free.fr> +Build-Depends: debhelper, autoconf, automake1.9, dpatch, libtool, libjack0.80.0-dev | libjack0.100.0-dev, libqt3-mt-dev, libasound2-dev, libsamplerate0-dev, libvorbis-dev, libtag1-dev, libid3-dev, libflac-dev, libpam0g-dev, libhpi-dev +Standards-Version: 3.6.1 + +Package: rivendell +Architecture: i386 +Depends: ${shlibs:Depends}, bc, cdda2wav, cdparanoia, flac, lame, libqt3-mt-mysql | libqt3c102-mt-mysql, libhpi, mpg321, vorbis-tools +Recommends: jackd, logrotate +Description: Rivendell binaries - contains a full set of functionality needed to operate a radio + automation system, consisting of the following components: + . + RDAdmin: a comprehensive application for the administration and configuration + of Rivendell. + . + RDLibrary: the production audio interface. + . + RDCatch: the automatic recorder interface. + . + RDLogin: a small utility for logging users into and out of the system. + . + RDLogEdit: a basic air log creation and editing tool. + . + RDLogManager: a utility for the automatic generation of logs, based on + templates. It also supports importation of schedule information from a wide + variety of third-party traffic and music scheduling systems. + . + RDAirPlay: the on-air playout application. + +Package: librivendell +Architecture: i386 +Depends: ${shlibs:Depends} +Description: Rivendell library - C++ runtime library + Contains a full set of functionality needed to operate a radio + automation system, consisting of the following components. + diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 00000000..7bce3f3b --- /dev/null +++ b/debian/copyright @@ -0,0 +1,15 @@ +This package was debianized by Alban Peignier <alban.peignier@free.fr> on +Tue Aug 24, 2004 22:50:00 +0200 + +It was downloaded from http://www.rivendellaudio.org/rivendell/download.html + +Upstream Author: Fred Gleason <fredg@paravelsystems.com> + +Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com> + + You should have received a copy of the GNU General Public License with the + Debian GNU/Linux distribution in file /usr/share/common-licenses/GPL; if + not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite + 330, Boston, MA 02111-1307 USA + + diff --git a/debian/librivendell.install b/debian/librivendell.install new file mode 100644 index 00000000..dc6d12c3 --- /dev/null +++ b/debian/librivendell.install @@ -0,0 +1,6 @@ +lib/security +usr/lib/librdhpi-*.so +usr/lib/librdhpi.so +usr/lib/librd-*.so +usr/lib/librd.so +usr/share/srlabs/librd*.qm diff --git a/debian/menu b/debian/menu new file mode 100644 index 00000000..a1c816a1 --- /dev/null +++ b/debian/menu @@ -0,0 +1,42 @@ +?package(rivendell):\ + needs="x11"\ + section="Apps/Sound"\ + title="rdadmin" command="/usr/bin/rdadmin" \ + icon="/usr/share/srlabs/rdadmin.xpm" + +?package(rivendell):\ + needs="x11"\ + section="Apps/Sound"\ + title="rdairplay" command="/usr/bin/rdairplay" \ + icon="/usr/share/srlabs/rdairplay.xpm" + +?package(rivendell):\ + needs="x11"\ + section="Apps/Sound"\ + title="rdcatch" command="/usr/bin/rdcatch" \ + icon="/usr/share/srlabs/rdcatch.xpm" + +?package(rivendell):\ + needs="x11"\ + section="Apps/Sound"\ + title="rdlibrary" command="/usr/bin/rdlibrary" \ + icon="/usr/share/srlabs/rdlibrary.xpm" + +?package(rivendell):\ + needs="x11"\ + section="Apps/Sound"\ + title="rdlogedit" command="/usr/bin/rdlogedit" \ + icon="/usr/share/srlabs/rdlogedit.xpm" + +?package(rivendell):\ + needs="x11"\ + section="Apps/Sound"\ + title="rdlogin" command="/usr/bin/rdlogin" \ + icon="/usr/share/srlabs/rdlogin.xpm" + +?package(rivendell):\ + needs="x11"\ + section="Apps/Sound"\ + title="rdlogmanager" command="/usr/bin/rdlogmanager" \ + icon="/usr/share/srlabs/rdlogmanager.xpm" + diff --git a/debian/patches/00list b/debian/patches/00list new file mode 100644 index 00000000..255b42e1 --- /dev/null +++ b/debian/patches/00list @@ -0,0 +1,4 @@ +# This is part of the dpatch infrastructure. +# See dpatch (1) in the man pages for more info. +# Brief summary is to uncomment patches to be applied in this file. +#07_extra_paren diff --git a/debian/patches/00template b/debian/patches/00template new file mode 100644 index 00000000..499e06c6 --- /dev/null +++ b/debian/patches/00template @@ -0,0 +1,26 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# +# template file for dpatch. see dpatch-edit-patch(1) for more details. +# +## +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts +patch_opts="${patch_opts:--f --no-backup-if-mismatch ${2:+-d $2}}" + +if [ $# -lt 1 ]; then + echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" + exit 1 +fi +case "$1" in + -patch) patch $patch_opts -p1 < $0;; + -unpatch) patch $patch_opts -p1 -R < $0;; + *) + echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" + exit 1;; +esac + +exit 0 +@DPATCH@ diff --git a/debian/patches/07_extra_paren.dpatch b/debian/patches/07_extra_paren.dpatch new file mode 100644 index 00000000..5b93c1ff --- /dev/null +++ b/debian/patches/07_extra_paren.dpatch @@ -0,0 +1,38 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# +# template file for dpatch. see dpatch-edit-patch(1) for more details. +# +## +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts +patch_opts="${patch_opts:--f --no-backup-if-mismatch ${2:+-d $2}}" + +if [ $# -lt 1 ]; then + echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" + exit 1 +fi +case "$1" in + -patch) patch $patch_opts -p1 < $0;; + -unpatch) patch $patch_opts -p1 -R < $0;; + *) + echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" + exit 1;; +esac + +exit 0 +@DPATCH@ +diff -urNad rivendell-0.9.79/rdadmin/createdb.cpp /home/grauf/tmp/dpep.gHhh0y/rivendell-0.9.79/rdadmin/createdb.cpp +--- rivendell-0.9.79/rdadmin/createdb.cpp 2006-12-05 14:25:32.000000000 -0500 ++++ /home/grauf/tmp/dpep.gHhh0y/rivendell-0.9.79/rdadmin/createdb.cpp 2006-12-12 16:34:49.000000000 -0500 +@@ -706,7 +706,7 @@ + DEFAULT_TRANS_TYPE int default 0,\ + BAR_ACTION int unsigned default 0,\ + FLASH_PANEL enum('N','Y') default 'N',\ +- PANEL_PAUSE_ENABLED enum('N','Y') default 'N'),\ ++ PANEL_PAUSE_ENABLED enum('N','Y') default 'N',\ + PAUSE_ENABLED enum('N','Y'),\ + DEFAULT_SERVICE char(10),\ + UDP_ADDR0 char(255),\ diff --git a/debian/patches/Makefile.am b/debian/patches/Makefile.am new file mode 100644 index 00000000..8123cf53 --- /dev/null +++ b/debian/patches/Makefile.am @@ -0,0 +1,29 @@ +## automake.am +## +## debian/automake.am for Rivendell +## +## Use automake to process this into a Makefile.in +## +## (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +## +## $Id: Makefile.am,v 1.1 2007/06/07 15:09:43 grauf Exp $ +## $Date: 2007/06/07 15:09:43 $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## + +EXTRA_DIST = 00list 00template 07_extra_paren.dpatch + +CLEANFILES = *~ substvars +MAINTAINERCLEANFILES = *~ Makefile.in diff --git a/debian/rdadmin.desktop b/debian/rdadmin.desktop new file mode 100644 index 00000000..6ba5c01c --- /dev/null +++ b/debian/rdadmin.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=rdadmin +Comment=Rivendell Admin +Exec=rdadmin +Terminal=false +Type=Application +Icon=/usr/share/srlabs/rdadmin.xpm +Categories=Application;AudioVideo; diff --git a/debian/rdadmin.xpm b/debian/rdadmin.xpm new file mode 100644 index 00000000..b1d58b50 --- /dev/null +++ b/debian/rdadmin.xpm @@ -0,0 +1,768 @@ +/* XPM */ +static char * rdadmin_xpm[] = { +"32 32 733 2", +" c None", +". c #3D485E", +"+ c #3D485F", +"@ c #364156", +"# c #3B475D", +"$ c #414F69", +"% c #37435A", +"& c #36425B", +"* c #3B4A68", +"= c #2F3645", +"- c #4B5871", +"; c #505D74", +"> c #4D586E", +", c #454F62", +"' c #606E88", +") c #5B6985", +"! c #414D64", +"~ c #536280", +"{ c #4E5F81", +"] c #3F4E69", +"^ c #435478", +"/ c #384868", +"( c #2E384D", +"_ c #424D5E", +": c #576375", +"< c #57606E", +"[ c #525B6A", +"} c #778192", +"| c #3B414B", +"1 c #8A98A8", +"2 c #404753", +"3 c #758398", +"4 c #4B5669", +"5 c #58667F", +"6 c #51607E", +"7 c #404D68", +"8 c #47587A", +"9 c #394868", +"0 c #364566", +"a c #30353E", +"b c #485468", +"c c #677281", +"d c #484F5D", +"e c #8F96A5", +"f c #3D414E", +"g c #A1A6B3", +"h c #4D5363", +"i c #8992A1", +"j c #686E79", +"k c #E11313", +"l c #3C4454", +"m c #586581", +"n c #6478A1", +"o c #3D4964", +"p c #46587D", +"q c #4A5D87", +"r c #323E5C", +"s c #354464", +"t c #23262D", +"u c #636F7E", +"v c #404551", +"w c #9BA1A7", +"x c #222531", +"y c #C7C8CD", +"z c #393C48", +"A c #A3A6B3", +"B c #7A7D86", +"C c #404557", +"D c #535768", +"E c #8FA0B8", +"F c #5E6983", +"G c #3D465C", +"H c #6A7EA7", +"I c #506285", +"J c #45567B", +"K c #445983", +"L c #3A4A70", +"M c #293246", +"N c #404B5C", +"O c #48505C", +"P c #6F7A88", +"Q c #636570", +"R c #888A94", +"S c #20222B", +"T c #DBDDE2", +"U c #50535F", +"V c #6C6E76", +"W c #D1D3DC", +"X c #2A2E3F", +"Y c #C4C9D3", +"Z c #353A44", +"` c #8092AC", +" . c #7283A0", +".. c #3B4359", +"+. c #3F4C67", +"@. c #5B72A2", +"#. c #425379", +"$. c #3E4C6F", +"%. c #3C4F7A", +"&. c #374668", +"*. c #2A2E35", +"=. c #54627A", +"-. c #9299A1", +";. c #3C404D", +">. c #878996", +",. c #878A99", +"'. c #373E55", +"). c #CCCDD6", +"!. c #767989", +"~. c #3C435E", +"{. c #A8AAB4", +"]. c #565A68", +"^. c #353E56", +"/. c #54617C", +"(. c #86A2D2", +"_. c #5E6F96", +":. c #4A557A", +"<. c #45567D", +"[. c #5975B2", +"}. c #3E4E75", +"|. c #3A4362", +"1. c #202023", +"2. c #627183", +"3. c #394152", +"4. c #B8BBC3", +"5. c #2A2D39", +"6. c #848591", +"7. c #A0A3B3", +"8. c #1C202C", +"9. c #A2A8BE", +"0. c #C9CAD3", +"a. c #212431", +"b. c #4D5164", +"c. c #8B8C95", +"d. c #36384A", +"e. c #4D5160", +"f. c #8495AC", +"g. c #424C72", +"h. c #3B4560", +"i. c #5F749D", +"j. c #6A86B9", +"k. c #526288", +"l. c #5F6D9F", +"m. c #415582", +"n. c #5572B5", +"o. c #2F3D5B", +"p. c #47566D", +"q. c #7D8C9E", +"r. c #33343A", +"s. c #C6C7CF", +"t. c #242A3A", +"u. c #6E7792", +"v. c #CFD1D8", +"w. c #424A62", +"x. c #494C57", +"y. c #DFE0E3", +"z. c #8C8E9C", +"A. c #DDDEE2", +"B. c #838692", +"C. c #404357", +"D. c #8293AB", +"E. c #97AFD1", +"F. c #444C73", +"G. c #4A5579", +"H. c #607DB6", +"I. c #5977B2", +"J. c #333E59", +"K. c #464E6C", +"L. c #4D6399", +"M. c #363F4B", +"N. c #4B596D", +"O. c #8492A4", +"P. c #363A46", +"Q. c #CFD0D4", +"R. c #3F4C6D", +"S. c #3C4256", +"T. c #ECEEF5", +"U. c #5F6169", +"V. c #555B77", +"W. c #8E909D", +"X. c #DCDCE3", +"Y. c #24252D", +"Z. c #616472", +"`. c #E8EBF3", +" + c #A0A9BC", +".+ c #424C70", +"++ c #8BA3C8", +"@+ c #96B6E9", +"#+ c #647AA9", +"$+ c #293044", +"%+ c #46506E", +"&+ c #667BB3", +"*+ c #6A8CD6", +"=+ c #7090DC", +"-+ c #313A54", +";+ c #1F242E", +">+ c #222326", +",+ c #657B92", +"'+ c #3C4558", +")+ c #919FB2", +"!+ c #262C3C", +"~+ c #BEC1CA", +"{+ c #676C7D", +"]+ c #384467", +"^+ c #ADADB5", +"/+ c #C9CDDC", +"(+ c #2A2D3A", +"_+ c #3D4253", +":+ c #C5C6CD", +"<+ c #53586E", +"[+ c #34384B", +"}+ c #4E5365", +"|+ c #C1D2E5", +"1+ c #212331", +"2+ c #3F486A", +"3+ c #7E9BD4", +"4+ c #84AAEF", +"5+ c #5A70A8", +"6+ c #252C3C", +"7+ c #242938", +"8+ c #4B5F90", +"9+ c #5D82D2", +"0+ c #48649F", +"a+ c #273147", +"b+ c #6F8398", +"c+ c #333841", +"d+ c #A0ABB5", +"e+ c #283454", +"f+ c #99A1B7", +"g+ c #A8AFBF", +"h+ c #21283B", +"i+ c #878EA8", +"j+ c #EBECF2", +"k+ c #71778C", +"l+ c #2D344D", +"m+ c #D4D8E4", +"n+ c #BDC0CB", +"o+ c #41465B", +"p+ c #454E73", +"q+ c #464C60", +"r+ c #9AAEC8", +"s+ c #6876A0", +"t+ c #353B57", +"u+ c #272C3C", +"v+ c #3E4C6D", +"w+ c #7DA2EA", +"x+ c #6487CB", +"y+ c #647CAB", +"z+ c #535E85", +"A+ c #2B3550", +"B+ c #3A4E7A", +"C+ c #5170A4", +"D+ c #4C4E51", +"E+ c #8096AC", +"F+ c #2C323F", +"G+ c #B7C4D0", +"H+ c #3C4A6C", +"I+ c #4C5773", +"J+ c #DCDCE1", +"K+ c #5D6A8F", +"L+ c #242D47", +"M+ c #9A9EAD", +"N+ c #DBDBDE", +"O+ c #3F4A70", +"P+ c #404456", +"Q+ c #DFE5F3", +"R+ c #D5E0F0", +"S+ c #3D4453", +"T+ c #3A4568", +"U+ c #4E5982", +"V+ c #6D87B6", +"W+ c #62709E", +"X+ c #555F8A", +"Y+ c #343A4F", +"Z+ c #3F537E", +"`+ c #668EDD", +" @ c #597DC5", +".@ c #303E5C", +"+@ c #3A4357", +"@@ c #445072", +"#@ c #333C52", +"$@ c #44494F", +"%@ c #7C95A3", +"&@ c #262E3D", +"*@ c #A0A9B1", +"=@ c #5E6980", +"-@ c #324576", +";@ c #C8CAD2", +">@ c #9BA3B7", +",@ c #2E3445", +"'@ c #4F5978", +")@ c #D8D9DE", +"!@ c #2B3142", +"~@ c #455681", +"{@ c #565E72", +"]@ c #BFCFD9", +"^@ c #B6CCE5", +"/@ c #5B698A", +"(@ c #23293B", +"_@ c #56638D", +":@ c #7B9DD7", +"<@ c #7DA1E1", +"[@ c #475A80", +"}@ c #434C67", +"|@ c #5C6A98", +"1@ c #677BB2", +"2@ c #6685C4", +"3@ c #6791E1", +"4@ c #7BA5EB", +"5@ c #4B5C7B", +"6@ c #1E2026", +"7@ c #444D55", +"8@ c #79868D", +"9@ c #4B5259", +"0@ c #6B7786", +"a@ c #B1C0D7", +"b@ c #2B334A", +"c@ c #788AAD", +"d@ c #EBEDF2", +"e@ c #66779C", +"f@ c #242C39", +"g@ c #D9DCE2", +"h@ c #C2CEE3", +"i@ c #464F63", +"j@ c #374458", +"k@ c #546173", +"l@ c #97ADC6", +"m@ c #B5D5F7", +"n@ c #8BA3C4", +"o@ c #323A4F", +"p@ c #515D77", +"q@ c #6E8CBE", +"r@ c #729BE0", +"s@ c #779FE7", +"t@ c #455981", +"u@ c #202530", +"v@ c #242832", +"w@ c #2D374D", +"x@ c #55729B", +"y@ c #A9CAD7", +"z@ c #677A89", +"A@ c #465159", +"B@ c #616D7B", +"C@ c #88909B", +"D@ c #2F3747", +"E@ c #CCD7DF", +"F@ c #525C70", +"G@ c #4F638E", +"H@ c #B3B5BA", +"I@ c #BDC0C7", +"J@ c #6C80A8", +"K@ c #DFEDF4", +"L@ c #A6BBCB", +"M@ c #374869", +"N@ c #232A39", +"O@ c #526286", +"P@ c #7288A8", +"Q@ c #A0C5F3", +"R@ c #87A7CE", +"S@ c #384150", +"T@ c #282C35", +"U@ c #4D6083", +"V@ c #8DB7F3", +"W@ c #7DADF3", +"X@ c #7199CA", +"Y@ c #7D9DC6", +"Z@ c #5C71A3", +"`@ c #424E66", +" # c #576478", +".# c #5A6B87", +"+# c #414954", +"@# c #4F5E73", +"## c #B0BCC5", +"$# c #363F4C", +"%# c #BBCDE3", +"&# c #D3E3F0", +"*# c #2A3242", +"=# c #51648B", +"-# c #DEE0E4", +";# c #313E5E", +"># c #374871", +",# c #62728D", +"'# c #C5E2F2", +")# c #A2BCD1", +"!# c #596B91", +"~# c #272C38", +"{# c #484F64", +"]# c #6A7C9E", +"^# c #89ADDB", +"/# c #77869D", +"(# c #454F65", +"_# c #2E3647", +":# c #354258", +"<# c #89AABE", +"[# c #CCE9F5", +"}# c #92B3C9", +"|# c #4D5E76", +"1# c #242935", +"2# c #17181C", +"3# c #4B556B", +"4# c #515F72", +"5# c #89939D", +"6# c #6A7B8E", +"7# c #6B7C8D", +"8# c #D8DBE0", +"9# c #5A6682", +"0# c #2C3D64", +"a# c #EAF0F8", +"b# c #A1B7C2", +"c# c #6E7D8C", +"d# c #5D6D8D", +"e# c #677BA9", +"f# c #6C82AE", +"g# c #97B5D5", +"h# c #A2C5E9", +"i# c #8DB5F4", +"j# c #6B87C8", +"k# c #3A4665", +"l# c #3F4862", +"m# c #545D78", +"n# c #4C5569", +"o# c #9DADC8", +"p# c #2B3A58", +"q# c #798AAF", +"r# c #D4DEF0", +"s# c #454D5E", +"t# c #6D778D", +"u# c #E6EDF2", +"v# c #9FAFCF", +"w# c #29324C", +"x# c #435283", +"y# c #4D5566", +"z# c #B2C3D0", +"A# c #CAE4F1", +"B# c #A3B5CB", +"C# c #4F5464", +"D# c #43454F", +"E# c #656975", +"F# c #85A2BF", +"G# c #9EC5F4", +"H# c #7694C8", +"I# c #3E4B6B", +"J# c #252A37", +"K# c #1E2028", +"L# c #16171C", +"M# c #1F2229", +"N# c #384564", +"O# c #343D54", +"P# c #3A4158", +"Q# c #616D94", +"R# c #333E5F", +"S# c #868EAA", +"T# c #49567A", +"U# c #2A3F72", +"V# c #A6AEBF", +"W# c #333D5B", +"X# c #8690A5", +"Y# c #D0DFF5", +"Z# c #7B88AC", +"`# c #353E5B", +" $ c #454F6E", +".$ c #464E62", +"+$ c #A4B8D4", +"@$ c #A9C6F3", +"#$ c #8599C5", +"$$ c #676F88", +"%$ c #40424B", +"&$ c #97ABD1", +"*$ c #7A98DC", +"=$ c #7293E3", +"-$ c #5F7ABB", +";$ c #627BB1", +">$ c #586988", +",$ c #2B2F3B", +"'$ c #16171B", +")$ c #18191C", +"!$ c #36405E", +"~$ c #5A6896", +"{$ c #2D3244", +"]$ c #909ACA", +"^$ c #3D5189", +"/$ c #475070", +"($ c #7D87B1", +"_$ c #374D8F", +":$ c #262F49", +"<$ c #6876A1", +"[$ c #ABB7E6", +"}$ c #8792BF", +"|$ c #545D7F", +"1$ c #3D4257", +"2$ c #404352", +"3$ c #67708B", +"4$ c #879BDB", +"5$ c #819AE3", +"6$ c #8796C2", +"7$ c #525970", +"8$ c #3D414C", +"9$ c #373C4D", +"0$ c #404C6D", +"a$ c #556BA5", +"b$ c #536DB0", +"c$ c #5874BB", +"d$ c #5770B2", +"e$ c #344164", +"f$ c #3C486C", +"g$ c #515878", +"h$ c #313545", +"i$ c #5E617B", +"j$ c #7E89B8", +"k$ c #2B334C", +"l$ c #A8ADDC", +"m$ c #8492D1", +"n$ c #252A3B", +"o$ c #2B3048", +"p$ c #636C93", +"q$ c #919AC9", +"r$ c #8792BE", +"s$ c #51576E", +"t$ c #575B6C", +"u$ c #5E5F69", +"v$ c #565B6C", +"w$ c #6F7BA2", +"x$ c #7187CC", +"y$ c #6377B4", +"z$ c #5B6581", +"A$ c #4B5169", +"B$ c #535E7E", +"C$ c #6373A1", +"D$ c #566796", +"E$ c #3D4866", +"F$ c #38476D", +"G$ c #37476F", +"H$ c #323646", +"I$ c #394059", +"J$ c #545971", +"K$ c #202128", +"L$ c #696B8C", +"M$ c #2A3A6B", +"N$ c #565F84", +"O$ c #9297CD", +"P$ c #7579A1", +"Q$ c #414B72", +"R$ c #37405F", +"S$ c #525D80", +"T$ c #70779D", +"U$ c #8993C2", +"V$ c #686F8E", +"W$ c #525563", +"X$ c #525462", +"Y$ c #4D4E58", +"Z$ c #454A5E", +"`$ c #68759C", +" % c #3A4872", +".% c #2A324C", +"+% c #1D212D", +"@% c #21232C", +"#% c #3A3C47", +"$% c #303444", +"%% c #191B1E", +"&% c #34394B", +"*% c #404764", +"=% c #484B5E", +"-% c #242632", +";% c #6681CC", +">% c #2D3855", +",% c #424E77", +"'% c #8388B9", +")% c #7C83B8", +"!% c #383E58", +"~% c #404969", +"{% c #434A63", +"]% c #5C6485", +"^% c #717AA6", +"/% c #666E95", +"(% c #5A5F76", +"_% c #4A4C56", +":% c #656B7F", +"<% c #606A84", +"[% c #3B4159", +"}% c #3C4B76", +"|% c #44578F", +"1% c #3C4D7E", +"2% c #364570", +"3% c #303C61", +"4% c #2E364D", +"5% c #323546", +"6% c #444A66", +"7% c #8399CC", +"8% c #6E819E", +"9% c #3E507C", +"0% c #344169", +"a% c #6A79B5", +"b% c #7376A1", +"c% c #565C7B", +"d% c #434D69", +"e% c #4F597A", +"f% c #49506B", +"g% c #5B6381", +"h% c #535C81", +"i% c #5B678F", +"j% c #454B66", +"k% c #40465A", +"l% c #474E69", +"m% c #4D5261", +"n% c #282A2F", +"o% c #24293C", +"p% c #333D59", +"q% c #303C5F", +"r% c #2D2F3B", +"s% c #373D54", +"t% c #3C4057", +"u% c #3F5083", +"v% c #849ABA", +"w% c #334373", +"x% c #344578", +"y% c #525D8F", +"z% c #686E9B", +"A% c #5B6282", +"B% c #424A67", +"C% c #4D5B81", +"D% c #444D65", +"E% c #434B68", +"F% c #5B668C", +"G% c #58638C", +"H% c #465074", +"I% c #414B6E", +"J% c #2F364B", +"K% c #252830", +"L% c #3F4046", +"M% c #343740", +"N% c #191A1E", +"O% c #1A1B21", +"P% c #2D303E", +"Q% c #373E59", +"R% c #3F4154", +"S% c #3C3D50", +"T% c #262C3D", +"U% c #495672", +"V% c #6477A2", +"W% c #3D4D7A", +"X% c #33426E", +"Y% c #363F5F", +"Z% c #4B5171", +"`% c #525875", +" & c #4F5774", +".& c #444C68", +"+& c #485375", +"@& c #3E455E", +"#& c #454F70", +"$& c #56638A", +"%& c #383F57", +"&& c #313A57", +"*& c #3D496E", +"=& c #323D60", +"-& c #364265", +";& c #222736", +">& c #2C2F3D", +",& c #31374C", +"'& c #33374A", +")& c #3A3C4D", +"!& c #1D1F26", +"~& c #303850", +"{& c #4E5B8D", +"]& c #43496D", +"^& c #344068", +"/& c #3B466A", +"(& c #353E5D", +"_& c #49506E", +":& c #454A64", +"<& c #414864", +"[& c #495372", +"}& c #292D3B", +"|& c #3B3D49", +"1& c #1F2128", +"2& c #363C51", +"3& c #1D212F", +"4& c #272A36", +"5& c #2B3146", +"6& c #2F364E", +"7& c #383B4E", +"8& c #3F496A", +"9& c #303751", +"0& c #3A3E55", +"a& c #3C3E52", +"b& c #3A4059", +"c& c #394260", +"d& c #2C334A", +"e& c #383F56", +"f& c #383D51", +"g& c #353A4C", +"h& c #32384C", +"i& c #31374B", +"j& c #333950", +"k& c #282E41", +"l& c #202431", +"m& c #1A1B1F", +"n& c #262B37", +"o& c #282C3D", +"p& c #303547", +"q& c #393D53", +"r& c #32384E", +"s& c #343B54", +"t& c #292C38", +"u& c #2F3242", +"v& c #2C303F", +"w& c #2C2F3C", +"x& c #252832", +"y& c #2D313E", +"z& c #262935", +"A& c #2A2E3C", +"B& c #21242F", +"C& c #20242E", +"D& c #222429", +"E& c #262A3B", +"F& c #1A1C22", +"G& c #282C3B", +"H& c #30364C", +"I& c #333A54", +"J& c #2A3044", +"K& c #272A37", +"L& c #292E3F", +"M& c #2A2F42", +"N& c #272D3F", +"O& c #1E212A", +"P& c #1B1C1F", +"Q& c #1C1E21", +"R& c #1D1F22", +"S& c #22242D", +"T& c #232631", +"U& c #222734", +"V& c #1C1D23", +"W& c #1E1F22", +"X& c #1C1D21", +" . + @ # $ % & * ", +" = - ; > , ' ) ! ~ { ] ^ / ( ", +" _ : < [ } | 1 2 3 4 5 6 7 8 9 0 ", +" a b c d e f g h i j k k l m n o p q r s ", +" t u v w x y z A B C k D k E F G H I J K L M ", +" N O P Q R S T U V W X k Y k Z ` ...+.@.#.$.%.&. ", +" *.=.-.;.>.,.'.).!.~.{.k k ].k k ^./.(._.:.<.[.}.|.1. ", +" 2.3.4.5.6.7.8.9.0.a.b.k c.d.e.k f.g.h.i.j.k.l.m.n.o. ", +" p.q.r.s.t.u.v.w.x.y.z.k k A.B.C.k D.E.6 F.G.H.I.J.K.L.0 ", +" M.N.O.P.Q.R.S.T.U.V.W.X.k Y.Z.`. +k .+++@+#+$+%+&+*+=+-+;+>+ ", +" ,+'+)+!+~+{+]+^+/+(+_+:+k <+[+}+|+k k 1+2+3+4+5+6+7+8+9+0+a+ ", +" b+c+d+e+f+g+h+i+j+k+l+k m+n+o+p+q+r+k s+t+u+v+w+x+y+z+A+B+C+ ", +"D+E+F+G+H+I+J+K+L+M+N+k O+P+Q+R+S+T+U+k k V+W+X+Y+Z+`+ @.@+@@@#@", +"$@%@&@*@=@-@;@>@,@'@)@k !@~@{@]@^@/@(@_@k :@<@[@}@|@1@2@3@4@5@6@", +"7@8@9@0@a@b@c@d@e@f@k g@h@i@j@k@l@m@n@o@k p@q@r@s@t@u@v@w@x@y@z@", +"A@B@C@D@E@F@G@H@I@k k J@K@L@M@N@O@P@Q@R@k S@T@U@V@W@X@Y@Z@`@ #.#", +"+#@###$#%#&#*#=#-#k ;#>#,#'#)#!#~#{#]#^#k k /#(#_#:#<#[#}#|#1#2#", +"3#4#5#6#7#8#9#0#k a#k k k k k k k k k k k k b#c#d#e#f#g#h#i#j#k#", +"l#m#n#o#p#q#r#s#k t#u#v#w#x#y#z#A#B#C#D#E#k F#G#H#I#J#K#L#M#N#O#", +"P#Q#R#S#T#U#V#k k W#X#Y#Z#`# $.$+$@$#$$$%$k k &$*$=$-$;$>$,$'$)$", +" !$~${$]$^$/$k ($_$:$<$[$}$|$1$2$3$4$5$6$7$k 8$9$0$a$b$c$d$e$ ", +" f$g$h$i$j$k$k l$m$n$o$p$q$r$s$t$u$v$w$x$y$k z$A$B$C$D$E$F$G$ ", +" H$I$J$K$L$k M$N$O$P$Q$R$S$T$U$V$W$X$Y$Z$`$k k %.%+%@%#%$%%% ", +" &%*%=%-%k ;%>%,%'%)%!%~%{%]%^%/%(%_%:%<%[%k }%|%1%2%3%4% ", +" 5%6%k k 7%8%9%0%a%b%c%d%e%f%g%h%i%j%k%l%k m%n%o%p%q% ", +" r%s%k t%u%v%D.w%x%y%z%A%B%C%D%E%F%G%H%I%J%K%L%M%N%O% ", +" P%Q%R%S%T%U%V%W%X%Y%Z%`% &.&+&@&#&$&%&&&*&=&-&;& ", +" >&,&'&)&!&~&{&]&^&/&(&_&:&<&%&[&}&|&1&2&;&3& ", +" 4&5&6&7&8&9&0&a&b&c&d&e&f&g&h&i&j&k&l&m& ", +" n&o&p&q&r&s&t&u&v&w&x&y&z&A&B&C& ", +" D&E&F&G&t&H&I&J&K&L&M&N&O&P& ", +" Q&R&S&T&U&V&W&X& "}; diff --git a/debian/rdairplay.desktop b/debian/rdairplay.desktop new file mode 100644 index 00000000..11efcce6 --- /dev/null +++ b/debian/rdairplay.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=rdairplay +Comment=Rivendell Airplay +Exec=rdairplay +Terminal=false +Type=Application +Icon=/usr/share/srlabs/rdairplay.xpm +Categories=Application;AudioVideo; diff --git a/debian/rdairplay.xpm b/debian/rdairplay.xpm new file mode 100644 index 00000000..12281d4a --- /dev/null +++ b/debian/rdairplay.xpm @@ -0,0 +1,738 @@ +/* XPM */ +static char * rdairplay_xpm[] = { +"32 32 703 2", +" c None", +". c #3D485E", +"+ c #3D485F", +"@ c #364156", +"# c #3B475D", +"$ c #414F69", +"% c #37435A", +"& c #36425B", +"* c #3B4A68", +"= c #2F3645", +"- c #4B5871", +"; c #505D74", +"> c #4D586E", +", c #454F62", +"' c #606E88", +") c #5B6985", +"! c #414D64", +"~ c #536280", +"{ c #4E5F81", +"] c #3F4E69", +"^ c #435478", +"/ c #384868", +"( c #2E384D", +"_ c #424D5E", +": c #576375", +"< c #57606E", +"[ c #525B6A", +"} c #778192", +"| c #3B414B", +"1 c #8A98A8", +"2 c #404753", +"3 c #758398", +"4 c #4B5669", +"5 c #58667F", +"6 c #51607E", +"7 c #404D68", +"8 c #47587A", +"9 c #394868", +"0 c #364566", +"a c #30353E", +"b c #E11313", +"c c #484F5D", +"d c #8F96A5", +"e c #3D414E", +"f c #A1A6B3", +"g c #4D5363", +"h c #8992A1", +"i c #686E79", +"j c #545E70", +"k c #8494A9", +"l c #3C4454", +"m c #586581", +"n c #6478A1", +"o c #3D4964", +"p c #46587D", +"q c #4A5D87", +"r c #323E5C", +"s c #354464", +"t c #23262D", +"u c #636F7E", +"v c #222531", +"w c #C7C8CD", +"x c #393C48", +"y c #A3A6B3", +"z c #7A7D86", +"A c #404557", +"B c #BEC3D0", +"C c #535768", +"D c #434B5E", +"E c #5E6983", +"F c #3D465C", +"G c #6A7EA7", +"H c #506285", +"I c #45567B", +"J c #445983", +"K c #3A4A70", +"L c #293246", +"M c #404B5C", +"N c #48505C", +"O c #6F7A88", +"P c #20222B", +"Q c #DBDDE2", +"R c #50535F", +"S c #6C6E76", +"T c #D1D3DC", +"U c #2A2E3F", +"V c #505564", +"W c #C4C9D3", +"X c #5C6374", +"Y c #3C4F7A", +"Z c #374668", +"` c #2A2E35", +" . c #54627A", +".. c #9299A1", +"+. c #3C404D", +"@. c #373E55", +"#. c #CCCDD6", +"$. c #767989", +"%. c #3C435E", +"&. c #A8AAB4", +"*. c #A8AAB8", +"=. c #363B4E", +"-. c #565A68", +";. c #C2CEDA", +">. c #353E56", +",. c #54617C", +"'. c #86A2D2", +"). c #5E6F96", +"!. c #4A557A", +"~. c #45567D", +"{. c #5975B2", +"]. c #3A4362", +"^. c #202023", +"/. c #627183", +"(. c #394152", +"_. c #B8BBC3", +":. c #848591", +"<. c #1C202C", +"[. c #A2A8BE", +"}. c #C9CAD3", +"|. c #212431", +"1. c #4D5164", +"2. c #D7D7DB", +"3. c #8B8C95", +"4. c #36384A", +"5. c #4D5160", +"6. c #8495AC", +"7. c #424C72", +"8. c #3B4560", +"9. c #5F749D", +"0. c #6A86B9", +"a. c #526288", +"b. c #5F6D9F", +"c. c #5572B5", +"d. c #2F3D5B", +"e. c #47566D", +"f. c #7D8C9E", +"g. c #33343A", +"h. c #C6C7CF", +"i. c #6E7792", +"j. c #424A62", +"k. c #494C57", +"l. c #DFE0E3", +"m. c #8C8E9C", +"n. c #22242C", +"o. c #616471", +"p. c #DDDEE2", +"q. c #838692", +"r. c #404357", +"s. c #8293AB", +"t. c #97AFD1", +"u. c #444C73", +"v. c #4A5579", +"w. c #607DB6", +"x. c #5977B2", +"y. c #464E6C", +"z. c #4D6399", +"A. c #363F4B", +"B. c #4B596D", +"C. c #8492A4", +"D. c #363A46", +"E. c #CFD0D4", +"F. c #3C4256", +"G. c #5F6169", +"H. c #555B77", +"I. c #8E909D", +"J. c #DCDCE3", +"K. c #717385", +"L. c #24252D", +"M. c #616472", +"N. c #E8EBF3", +"O. c #A0A9BC", +"P. c #424C70", +"Q. c #8BA3C8", +"R. c #96B6E9", +"S. c #647AA9", +"T. c #293044", +"U. c #46506E", +"V. c #667BB3", +"W. c #313A54", +"X. c #1F242E", +"Y. c #222326", +"Z. c #657B92", +"`. c #3C4558", +" + c #919FB2", +".+ c #262C3C", +"++ c #BEC1CA", +"@+ c #384467", +"#+ c #C9CDDC", +"$+ c #2A2D3A", +"%+ c #3D4253", +"&+ c #C5C6CD", +"*+ c #D6D6DF", +"=+ c #53586E", +"-+ c #34384B", +";+ c #4E5365", +">+ c #C1D2E5", +",+ c #505A79", +"'+ c #212331", +")+ c #3F486A", +"!+ c #7E9BD4", +"~+ c #84AAEF", +"{+ c #5A70A8", +"]+ c #252C3C", +"^+ c #242938", +"/+ c #5D82D2", +"(+ c #48649F", +"_+ c #273147", +":+ c #6F8398", +"<+ c #333841", +"[+ c #A0ABB5", +"}+ c #283454", +"|+ c #99A1B7", +"1+ c #21283B", +"2+ c #EBECF2", +"3+ c #71778C", +"4+ c #2D344D", +"5+ c #4C4E5D", +"6+ c #D4D8E4", +"7+ c #BDC0CB", +"8+ c #41465B", +"9+ c #454E73", +"0+ c #464C60", +"a+ c #A3BEDE", +"b+ c #6876A0", +"c+ c #353B57", +"d+ c #272C3C", +"e+ c #3E4C6D", +"f+ c #7DA2EA", +"g+ c #6487CB", +"h+ c #2B3550", +"i+ c #3A4E7A", +"j+ c #5170A4", +"k+ c #4C4E51", +"l+ c #8096AC", +"m+ c #2C323F", +"n+ c #B7C4D0", +"o+ c #3C4A6C", +"p+ c #DCDCE1", +"q+ c #5D6A8F", +"r+ c #242D47", +"s+ c #DBDBDE", +"t+ c #575D70", +"u+ c #3F4A70", +"v+ c #404456", +"w+ c #DFE5F3", +"x+ c #D5E0F0", +"y+ c #3D4453", +"z+ c #3A4568", +"A+ c #67799B", +"B+ c #9EC0F4", +"C+ c #6D87B6", +"D+ c #62709E", +"E+ c #555F8A", +"F+ c #343A4F", +"G+ c #3F537E", +"H+ c #597DC5", +"I+ c #303E5C", +"J+ c #3A4357", +"K+ c #445072", +"L+ c #333C52", +"M+ c #44494F", +"N+ c #7C95A3", +"O+ c #262E3D", +"P+ c #A0A9B1", +"Q+ c #5E6980", +"R+ c #C8CAD2", +"S+ c #9BA3B7", +"T+ c #2E3445", +"U+ c #D8D9DE", +"V+ c #CAD0E2", +"W+ c #2B3142", +"X+ c #455681", +"Y+ c #565E72", +"Z+ c #BFCFD9", +"`+ c #B6CCE5", +" @ c #5B698A", +".@ c #56638D", +"+@ c #6A7EAB", +"@@ c #7B9DD7", +"#@ c #7DA1E1", +"$@ c #475A80", +"%@ c #677BB2", +"&@ c #6685C4", +"*@ c #6791E1", +"=@ c #7BA5EB", +"-@ c #4B5C7B", +";@ c #1E2026", +">@ c #444D55", +",@ c #79868D", +"'@ c #4B5259", +")@ c #6B7786", +"!@ c #788AAD", +"~@ c #EBEDF2", +"{@ c #66779C", +"]@ c #7B8DAB", +"^@ c #D9DCE2", +"/@ c #C2CEE3", +"(@ c #464F63", +"_@ c #374458", +":@ c #546173", +"<@ c #97ADC6", +"[@ c #B5D5F7", +"}@ c #8BA3C4", +"|@ c #383F4C", +"1@ c #515D77", +"2@ c #455981", +"3@ c #202530", +"4@ c #242832", +"5@ c #2D374D", +"6@ c #55729B", +"7@ c #A9CAD7", +"8@ c #677A89", +"9@ c #465159", +"0@ c #616D7B", +"a@ c #88909B", +"b@ c #2F3747", +"c@ c #525C70", +"d@ c #4F638E", +"e@ c #B3B5BA", +"f@ c #BDC0C7", +"g@ c #313D4E", +"h@ c #6C80A8", +"i@ c #DFEDF4", +"j@ c #A6BBCB", +"k@ c #374869", +"l@ c #232A39", +"m@ c #526286", +"n@ c #7288A8", +"o@ c #A0C5F3", +"p@ c #4D6083", +"q@ c #8DB7F3", +"r@ c #7DADF3", +"s@ c #7199CA", +"t@ c #7D9DC6", +"u@ c #5C71A3", +"v@ c #424E66", +"w@ c #576478", +"x@ c #5A6B87", +"y@ c #414954", +"z@ c #4F5E73", +"A@ c #B0BCC5", +"B@ c #363F4C", +"C@ c #D3E3F0", +"D@ c #2A3242", +"E@ c #51648B", +"F@ c #DEE0E4", +"G@ c #313E5E", +"H@ c #374871", +"I@ c #62728D", +"J@ c #C5E2F2", +"K@ c #A2BCD1", +"L@ c #596B91", +"M@ c #272C38", +"N@ c #484F64", +"O@ c #6A7C9E", +"P@ c #8EBBEB", +"Q@ c #819FC2", +"R@ c #77869D", +"S@ c #454F65", +"T@ c #2E3647", +"U@ c #354258", +"V@ c #89AABE", +"W@ c #CCE9F5", +"X@ c #92B3C9", +"Y@ c #4D5E76", +"Z@ c #242935", +"`@ c #17181C", +" # c #4B556B", +".# c #515F72", +"+# c #89939D", +"@# c #8E9AB4", +"## c #252B3F", +"$# c #42568E", +"%# c #56667D", +"&# c #D9F3FC", +"*# c #BED0D8", +"=# c #6F7586", +"-# c #30333F", +";# c #515667", +"># c #88A5B6", +",# c #C5E7F6", +"'# c #A1B7C2", +")# c #6E7D8C", +"!# c #5D6D8D", +"~# c #677BA9", +"{# c #6C82AE", +"]# c #97B5D5", +"^# c #A2C5E9", +"/# c #8DB5F4", +"(# c #6B87C8", +"_# c #3A4665", +":# c #3F4862", +"<# c #545D78", +"[# c #4C5569", +"}# c #2B3A58", +"|# c #798AAF", +"1# c #D4DEF0", +"2# c #454D5E", +"3# c #374D81", +"4# c #E6EDF2", +"5# c #9FAFCF", +"6# c #29324C", +"7# c #435283", +"8# c #4D5566", +"9# c #B2C3D0", +"0# c #CAE4F1", +"a# c #A3B5CB", +"b# c #4F5464", +"c# c #656975", +"d# c #69768D", +"e# c #85A2BF", +"f# c #9EC5F4", +"g# c #7694C8", +"h# c #3E4B6B", +"i# c #252A37", +"j# c #1E2028", +"k# c #16171C", +"l# c #1F2229", +"m# c #384564", +"n# c #343D54", +"o# c #3A4158", +"p# c #616D94", +"q# c #868EAA", +"r# c #49567A", +"s# c #2A3F72", +"t# c #A6AEBF", +"u# c #999EB2", +"v# c #435A8F", +"w# c #8690A5", +"x# c #D0DFF5", +"y# c #7B88AC", +"z# c #353E5B", +"A# c #454F6E", +"B# c #464E62", +"C# c #A4B8D4", +"D# c #A9C6F3", +"E# c #8599C5", +"F# c #40424B", +"G# c #7F89A4", +"H# c #97ABD1", +"I# c #7A98DC", +"J# c #7293E3", +"K# c #5F7ABB", +"L# c #627BB1", +"M# c #586988", +"N# c #2B2F3B", +"O# c #16171B", +"P# c #18191C", +"Q# c #36405E", +"R# c #2D3244", +"S# c #909ACA", +"T# c #3D5189", +"U# c #475070", +"V# c #ADB5E0", +"W# c #7D87B1", +"X# c #262F49", +"Y# c #6876A1", +"Z# c #ABB7E6", +"`# c #8792BF", +" $ c #545D7F", +".$ c #3D4257", +"+$ c #404352", +"@$ c #67708B", +"#$ c #879BDB", +"$$ c #8796C2", +"%$ c #525970", +"&$ c #3D414C", +"*$ c #373C4D", +"=$ c #404C6D", +"-$ c #556BA5", +";$ c #536DB0", +">$ c #5874BB", +",$ c #5770B2", +"'$ c #344164", +")$ c #515878", +"!$ c #313545", +"~$ c #5E617B", +"{$ c #7E89B8", +"]$ c #2B334C", +"^$ c #48506F", +"/$ c #A8ADDC", +"($ c #252A3B", +"_$ c #2B3048", +":$ c #636C93", +"<$ c #919AC9", +"[$ c #8792BE", +"}$ c #51576E", +"|$ c #575B6C", +"1$ c #5E5F69", +"2$ c #565B6C", +"3$ c #6F7BA2", +"4$ c #6377B4", +"5$ c #6F80AC", +"6$ c #5B6581", +"7$ c #4B5169", +"8$ c #535E7E", +"9$ c #6373A1", +"0$ c #566796", +"a$ c #3D4866", +"b$ c #38476D", +"c$ c #37476F", +"d$ c #394059", +"e$ c #545971", +"f$ c #202128", +"g$ c #696B8C", +"h$ c #656FA5", +"i$ c #2A3A6B", +"j$ c #565F84", +"k$ c #9297CD", +"l$ c #414B72", +"m$ c #37405F", +"n$ c #525D80", +"o$ c #70779D", +"p$ c #8993C2", +"q$ c #686F8E", +"r$ c #525563", +"s$ c #525462", +"t$ c #4D4E58", +"u$ c #68759C", +"v$ c #52649C", +"w$ c #4F64A0", +"x$ c #3A4872", +"y$ c #2A324C", +"z$ c #1D212D", +"A$ c #21232C", +"B$ c #3A3C47", +"C$ c #303444", +"D$ c #191B1E", +"E$ c #34394B", +"F$ c #404764", +"G$ c #484B5E", +"H$ c #242632", +"I$ c #8596DE", +"J$ c #6681CC", +"K$ c #2D3855", +"L$ c #424E77", +"M$ c #7C83B8", +"N$ c #383E58", +"O$ c #404969", +"P$ c #434A63", +"Q$ c #5C6485", +"R$ c #717AA6", +"S$ c #666E95", +"T$ c #5A5F76", +"U$ c #4A4C56", +"V$ c #606A84", +"W$ c #3B4159", +"X$ c #323B56", +"Y$ c #3C4B76", +"Z$ c #44578F", +"`$ c #3C4D7E", +" % c #364570", +".% c #303C61", +"+% c #2E364D", +"@% c #323546", +"#% c #444A66", +"$% c #3D3F4F", +"%% c #404A66", +"&% c #8399CC", +"*% c #6E819E", +"=% c #3E507C", +"-% c #6A79B5", +";% c #7376A1", +">% c #565C7B", +",% c #434D69", +"'% c #4F597A", +")% c #49506B", +"!% c #5B6381", +"~% c #535C81", +"{% c #5B678F", +"]% c #40465A", +"^% c #474E69", +"/% c #5A688F", +"(% c #4D5261", +"_% c #282A2F", +":% c #24293C", +"<% c #333D59", +"[% c #303C5F", +"}% c #2D2F3B", +"|% c #373D54", +"1% c #474A5F", +"2% c #3C4057", +"3% c #3F5083", +"4% c #849ABA", +"5% c #344578", +"6% c #525D8F", +"7% c #686E9B", +"8% c #5B6282", +"9% c #424A67", +"0% c #4D5B81", +"a% c #444D65", +"b% c #434B68", +"c% c #5B668C", +"d% c #58638C", +"e% c #465074", +"f% c #414B6E", +"g% c #2F364B", +"h% c #252830", +"i% c #3F4046", +"j% c #343740", +"k% c #191A1E", +"l% c #1A1B21", +"m% c #2D303E", +"n% c #373E59", +"o% c #3F4154", +"p% c #3C3D50", +"q% c #262C3D", +"r% c #495672", +"s% c #6477A2", +"t% c #33426E", +"u% c #363F5F", +"v% c #4B5171", +"w% c #525875", +"x% c #4F5774", +"y% c #444C68", +"z% c #485375", +"A% c #3E455E", +"B% c #454F70", +"C% c #56638A", +"D% c #383F57", +"E% c #313A57", +"F% c #3D496E", +"G% c #323D60", +"H% c #364265", +"I% c #222736", +"J% c #2C2F3D", +"K% c #31374C", +"L% c #33374A", +"M% c #3A3C4D", +"N% c #1D1F26", +"O% c #303850", +"P% c #4E5B8D", +"Q% c #43496D", +"R% c #344068", +"S% c #3B466A", +"T% c #353E5D", +"U% c #49506E", +"V% c #454A64", +"W% c #414864", +"X% c #495372", +"Y% c #292D3B", +"Z% c #3B3D49", +"`% c #1F2128", +" & c #363C51", +".& c #1D212F", +"+& c #272A36", +"@& c #2B3146", +"#& c #2F364E", +"$& c #383B4E", +"%& c #3F496A", +"&& c #303751", +"*& c #3A3E55", +"=& c #3C3E52", +"-& c #3A4059", +";& c #394260", +">& c #2C334A", +",& c #383F56", +"'& c #383D51", +")& c #353A4C", +"!& c #32384C", +"~& c #31374B", +"{& c #333950", +"]& c #282E41", +"^& c #202431", +"/& c #1A1B1F", +"(& c #262B37", +"_& c #282C3D", +":& c #303547", +"<& c #393D53", +"[& c #32384E", +"}& c #343B54", +"|& c #292C38", +"1& c #2F3242", +"2& c #2C303F", +"3& c #2C2F3C", +"4& c #252832", +"5& c #2D313E", +"6& c #262935", +"7& c #2A2E3C", +"8& c #21242F", +"9& c #20242E", +"0& c #222429", +"a& c #262A3B", +"b& c #1A1C22", +"c& c #282C3B", +"d& c #30364C", +"e& c #333A54", +"f& c #2A3044", +"g& c #272A37", +"h& c #292E3F", +"i& c #2A2F42", +"j& c #272D3F", +"k& c #1E212A", +"l& c #1B1C1F", +"m& c #1C1E21", +"n& c #1D1F22", +"o& c #22242D", +"p& c #232631", +"q& c #222734", +"r& c #1C1D23", +"s& c #1E1F22", +"t& c #1C1D21", +" . + @ # $ % & * ", +" = - ; > , ' ) ! ~ { ] ^ / ( ", +" _ : < [ } | 1 2 3 4 5 6 7 8 9 0 ", +" a b b c d e f g h i j k l m n o p q r s ", +" t u b b v w x y z A B C D b E F G H I J K L ", +" M N O b b P Q R S T U V W X b b b b b b b b Y Z ", +" ` ...+.b b @.#.$.%.&.*.=.-.;.b >.,.'.).!.~.{.b ].^. ", +" /.(._.b :.b <.[.}.|.1.2.3.4.5.b 6.7.8.9.0.a.b.b c.d. ", +" e.f.g.h.b i.b j.k.l.m.n.o.p.q.r.b s.t.6 u.v.w.x.b y.z.0 ", +" A.B.C.D.E.b F.b G.H.I.J.K.L.M.N.O.b P.Q.R.S.T.U.V.b b W.X.Y. ", +" Z.`. +.+++b @+b #+$+%+&+*+=+-+;+>+b ,+'+)+!+~+{+]+^+b /+(+_+ ", +" :+<+[+}+|+b 1+b 2+3+4+5+6+7+8+9+0+b a+b+c+d+e+f+g+b b h+i+j+ ", +"k+l+m+n+o+b p+q+r+b s+t+u+v+w+x+y+z+b A+B+C+D+E+F+G+b H+I+J+K+L+", +"M+N+O+P+Q+b R+S+T+b U+V+W+X+Y+Z+`+ @b .@+@@@#@$@b b %@&@*@=@-@;@", +">@,@'@)@b b !@~@{@b ]@^@/@(@_@:@<@[@}@b |@1@b b b 2@3@4@5@6@7@8@", +"9@0@a@b@b c@d@e@f@b g@h@i@j@k@l@m@n@o@b b b b p@q@r@s@t@u@v@w@x@", +"y@z@A@B@b C@D@E@F@b G@H@I@J@K@L@M@N@O@b P@Q@R@S@T@U@V@W@X@Y@Z@`@", +" #.#+#b b b b b b b @###$#%#&#*#=#-#;#b >#,#'#)#!#~#{#]#^#/#(#_#", +":#<#[#b }#|#1#2#3#b 4#5#6#7#8#9#0#a#b#b c#d#e#f#g#h#i#j#k#l#m#n#", +"o#p#b q#r#s#t#u#v#b w#x#y#z#A#B#C#D#E#b F#5.G#H#I#J#K#L#M#N#O#P#", +" Q#b R#S#T#U#V#W#b X#Y#Z#`# $.$+$@$#$b $$%$D.&$*$=$-$;$>$,$'$ ", +" b )$!$~${$]$^$/$b ($_$:$<$[$}$|$1$2$3$b 4$5$6$7$8$9$0$a$b$c$ ", +"b b d$e$f$g$h$i$j$k$b l$m$n$o$p$q$r$s$t$b u$v$w$x$y$z$A$B$C$D$ ", +"b b E$F$G$H$I$J$K$L$b M$N$O$P$Q$R$S$T$U$b V$W$X$Y$Z$`$ %.%+% ", +"b b @%#%$%%%&%*%=%b -%;%>%,%'%)%!%~%{%b ]%^%/%(%_%:%<%[% ", +" }%|%1%2%3%4%s.b 5%6%7%8%9%0%a%b%c%d%e%f%g%h%i%j%k%l% ", +" m%n%o%p%q%r%s%b t%u%v%w%x%y%z%A%B%C%D%E%F%G%H%I% ", +" J%K%L%M%N%O%P%Q%R%S%T%U%V%W%D%X%Y%Z%`% &I%.& ", +" +&@&#&$&%&&&*&=&-&;&>&,&'&)&!&~&{&]&^&/& ", +" (&_&:&<&[&}&|&1&2&3&4&5&6&7&8&9& ", +" 0&a&b&c&|&d&e&f&g&h&i&j&k&l& ", +" m&n&o&p&q&r&s&t& "}; diff --git a/debian/rdcatch.desktop b/debian/rdcatch.desktop new file mode 100644 index 00000000..dace05f2 --- /dev/null +++ b/debian/rdcatch.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=rdcatch +Comment=Rivendell Catch +Exec=rdcatch +Terminal=false +Type=Application +Icon=/usr/share/srlabs/rdcatch.xpm +Categories=Application;AudioVideo; diff --git a/debian/rdcatch.xpm b/debian/rdcatch.xpm new file mode 100644 index 00000000..7ce9a60b --- /dev/null +++ b/debian/rdcatch.xpm @@ -0,0 +1,780 @@ +/* XPM */ +static char * rdcatch_xpm[] = { +"32 32 745 2", +" c None", +". c #3D485E", +"+ c #3D485F", +"@ c #364156", +"# c #3B475D", +"$ c #414F69", +"% c #37435A", +"& c #36425B", +"* c #3B4A68", +"= c #2F3645", +"- c #4B5871", +"; c #505D74", +"> c #4D586E", +", c #454F62", +"' c #606E88", +") c #5B6985", +"! c #414D64", +"~ c #536280", +"{ c #4E5F81", +"] c #3F4E69", +"^ c #435478", +"/ c #384868", +"( c #2E384D", +"_ c #424D5E", +": c #576375", +"< c #57606E", +"[ c #525B6A", +"} c #778192", +"| c #3B414B", +"1 c #8A98A8", +"2 c #404753", +"3 c #758398", +"4 c #4B5669", +"5 c #58667F", +"6 c #51607E", +"7 c #404D68", +"8 c #47587A", +"9 c #394868", +"0 c #364566", +"a c #30353E", +"b c #485468", +"c c #677281", +"d c #484F5D", +"e c #8F96A5", +"f c #3D414E", +"g c #A1A6B3", +"h c #4D5363", +"i c #8992A1", +"j c #686E79", +"k c #545E70", +"l c #8494A9", +"m c #3C4454", +"n c #586581", +"o c #6478A1", +"p c #3D4964", +"q c #46587D", +"r c #4A5D87", +"s c #323E5C", +"t c #354464", +"u c #23262D", +"v c #636F7E", +"w c #404551", +"x c #9BA1A7", +"y c #222531", +"z c #C7C8CD", +"A c #393C48", +"B c #A3A6B3", +"C c #7A7D86", +"D c #404557", +"E c #BEC3D0", +"F c #535768", +"G c #434B5E", +"H c #8FA0B8", +"I c #5E6983", +"J c #3D465C", +"K c #6A7EA7", +"L c #506285", +"M c #45567B", +"N c #445983", +"O c #3A4A70", +"P c #293246", +"Q c #404B5C", +"R c #48505C", +"S c #6F7A88", +"T c #636570", +"U c #888A94", +"V c #20222B", +"W c #DBDDE2", +"X c #50535F", +"Y c #6C6E76", +"Z c #D1D3DC", +"` c #2A2E3F", +" . c #505564", +".. c #C4C9D3", +"+. c #5C6374", +"@. c #E11313", +"#. c #425379", +"$. c #3E4C6F", +"%. c #3C4F7A", +"&. c #374668", +"*. c #2A2E35", +"=. c #54627A", +"-. c #9299A1", +";. c #3C404D", +">. c #878996", +",. c #878A99", +"'. c #373E55", +"). c #CCCDD6", +"!. c #767989", +"~. c #3C435E", +"{. c #A8AAB4", +"]. c #A8AAB8", +"^. c #363B4E", +"/. c #353E56", +"(. c #54617C", +"_. c #86A2D2", +":. c #5E6F96", +"<. c #3E4E75", +"[. c #3A4362", +"}. c #202023", +"|. c #627183", +"1. c #394152", +"2. c #B8BBC3", +"3. c #2A2D39", +"4. c #848591", +"5. c #A0A3B3", +"6. c #1C202C", +"7. c #A2A8BE", +"8. c #C9CAD3", +"9. c #212431", +"0. c #4D5164", +"a. c #4D5160", +"b. c #AEBFD0", +"c. c #8495AC", +"d. c #424C72", +"e. c #3B4560", +"f. c #5F749D", +"g. c #6A86B9", +"h. c #526288", +"i. c #5F6D9F", +"j. c #415582", +"k. c #5572B5", +"l. c #2F3D5B", +"m. c #47566D", +"n. c #7D8C9E", +"o. c #33343A", +"p. c #C6C7CF", +"q. c #242A3A", +"r. c #6E7792", +"s. c #CFD1D8", +"t. c #424A62", +"u. c #494C57", +"v. c #DFE0E3", +"w. c #8C8E9C", +"x. c #DDDEE2", +"y. c #838692", +"z. c #404357", +"A. c #4F5777", +"B. c #8293AB", +"C. c #97AFD1", +"D. c #444C73", +"E. c #4A5579", +"F. c #607DB6", +"G. c #5977B2", +"H. c #333E59", +"I. c #464E6C", +"J. c #4D6399", +"K. c #363F4B", +"L. c #4B596D", +"M. c #8492A4", +"N. c #363A46", +"O. c #CFD0D4", +"P. c #3F4C6D", +"Q. c #3C4256", +"R. c #ECEEF5", +"S. c #5F6169", +"T. c #555B77", +"U. c #717385", +"V. c #24252D", +"W. c #616472", +"X. c #E8EBF3", +"Y. c #A0A9BC", +"Z. c #222430", +"`. c #424C70", +" + c #8BA3C8", +".+ c #96B6E9", +"++ c #647AA9", +"@+ c #293044", +"#+ c #46506E", +"$+ c #667BB3", +"%+ c #6A8CD6", +"&+ c #7090DC", +"*+ c #313A54", +"=+ c #1F242E", +"-+ c #222326", +";+ c #657B92", +">+ c #3C4558", +",+ c #919FB2", +"'+ c #262C3C", +")+ c #BEC1CA", +"!+ c #676C7D", +"~+ c #384467", +"{+ c #ADADB5", +"]+ c #3D4253", +"^+ c #C5C6CD", +"/+ c #D6D6DF", +"(+ c #53586E", +"_+ c #34384B", +":+ c #4E5365", +"<+ c #C1D2E5", +"[+ c #B1C4E5", +"}+ c #505A79", +"|+ c #212331", +"1+ c #3F486A", +"2+ c #7E9BD4", +"3+ c #84AAEF", +"4+ c #5A70A8", +"5+ c #252C3C", +"6+ c #242938", +"7+ c #4B5F90", +"8+ c #5D82D2", +"9+ c #48649F", +"0+ c #273147", +"a+ c #6F8398", +"b+ c #333841", +"c+ c #A0ABB5", +"d+ c #283454", +"e+ c #99A1B7", +"f+ c #A8AFBF", +"g+ c #21283B", +"h+ c #71778C", +"i+ c #2D344D", +"j+ c #4C4E5D", +"k+ c #D4D8E4", +"l+ c #BDC0CB", +"m+ c #41465B", +"n+ c #454E73", +"o+ c #464C60", +"p+ c #9AAEC8", +"q+ c #A3BEDE", +"r+ c #6876A0", +"s+ c #353B57", +"t+ c #272C3C", +"u+ c #3E4C6D", +"v+ c #7DA2EA", +"w+ c #6487CB", +"x+ c #647CAB", +"y+ c #535E85", +"z+ c #2B3550", +"A+ c #3A4E7A", +"B+ c #5170A4", +"C+ c #4C4E51", +"D+ c #8096AC", +"E+ c #2C323F", +"F+ c #B7C4D0", +"G+ c #3C4A6C", +"H+ c #4C5773", +"I+ c #DCDCE1", +"J+ c #5D6A8F", +"K+ c #9A9EAD", +"L+ c #DBDBDE", +"M+ c #575D70", +"N+ c #3F4A70", +"O+ c #404456", +"P+ c #DFE5F3", +"Q+ c #D5E0F0", +"R+ c #3D4453", +"S+ c #3A4568", +"T+ c #4E5982", +"U+ c #67799B", +"V+ c #9EC0F4", +"W+ c #6D87B6", +"X+ c #62709E", +"Y+ c #555F8A", +"Z+ c #343A4F", +"`+ c #3F537E", +" @ c #668EDD", +".@ c #597DC5", +"+@ c #303E5C", +"@@ c #3A4357", +"#@ c #445072", +"$@ c #333C52", +"%@ c #44494F", +"&@ c #7C95A3", +"*@ c #262E3D", +"=@ c #A0A9B1", +"-@ c #5E6980", +";@ c #324576", +">@ c #C8CAD2", +",@ c #2E3445", +"'@ c #4F5978", +")@ c #D8D9DE", +"!@ c #CAD0E2", +"~@ c #2B3142", +"{@ c #455681", +"]@ c #565E72", +"^@ c #BFCFD9", +"/@ c #B6CCE5", +"(@ c #5B698A", +"_@ c #23293B", +":@ c #56638D", +"<@ c #6A7EAB", +"[@ c #7B9DD7", +"}@ c #7DA1E1", +"|@ c #475A80", +"1@ c #434C67", +"2@ c #5C6A98", +"3@ c #677BB2", +"4@ c #6685C4", +"5@ c #6791E1", +"6@ c #7BA5EB", +"7@ c #4B5C7B", +"8@ c #1E2026", +"9@ c #444D55", +"0@ c #79868D", +"a@ c #4B5259", +"b@ c #6B7786", +"c@ c #B1C0D7", +"d@ c #2B334A", +"e@ c #788AAD", +"f@ c #66779C", +"g@ c #242C39", +"h@ c #7B8DAB", +"i@ c #D9DCE2", +"j@ c #C2CEE3", +"k@ c #464F63", +"l@ c #374458", +"m@ c #546173", +"n@ c #97ADC6", +"o@ c #B5D5F7", +"p@ c #8BA3C4", +"q@ c #323A4F", +"r@ c #383F4C", +"s@ c #515D77", +"t@ c #6E8CBE", +"u@ c #729BE0", +"v@ c #779FE7", +"w@ c #455981", +"x@ c #202530", +"y@ c #242832", +"z@ c #2D374D", +"A@ c #55729B", +"B@ c #A9CAD7", +"C@ c #677A89", +"D@ c #465159", +"E@ c #616D7B", +"F@ c #88909B", +"G@ c #2F3747", +"H@ c #CCD7DF", +"I@ c #525C70", +"J@ c #4F638E", +"K@ c #BDC0C7", +"L@ c #506A96", +"M@ c #313D4E", +"N@ c #6C80A8", +"O@ c #DFEDF4", +"P@ c #A6BBCB", +"Q@ c #374869", +"R@ c #232A39", +"S@ c #526286", +"T@ c #7288A8", +"U@ c #A0C5F3", +"V@ c #87A7CE", +"W@ c #5E7091", +"X@ c #384150", +"Y@ c #282C35", +"Z@ c #4D6083", +"`@ c #8DB7F3", +" # c #7DADF3", +".# c #7199CA", +"+# c #7D9DC6", +"@# c #5C71A3", +"## c #424E66", +"$# c #576478", +"%# c #5A6B87", +"&# c #414954", +"*# c #4F5E73", +"=# c #B0BCC5", +"-# c #363F4C", +";# c #BBCDE3", +"># c #D3E3F0", +",# c #2A3242", +"'# c #DEE0E4", +")# c #B7BEC8", +"!# c #313E5E", +"~# c #374871", +"{# c #62728D", +"]# c #C5E2F2", +"^# c #A2BCD1", +"/# c #596B91", +"(# c #272C38", +"_# c #484F64", +":# c #6A7C9E", +"<# c #89ADDB", +"[# c #8EBBEB", +"}# c #819FC2", +"|# c #77869D", +"1# c #454F65", +"2# c #2E3647", +"3# c #354258", +"4# c #89AABE", +"5# c #CCE9F5", +"6# c #92B3C9", +"7# c #4D5E76", +"8# c #242935", +"9# c #17181C", +"0# c #4B556B", +"a# c #515F72", +"b# c #89939D", +"c# c #6A7B8E", +"d# c #6B7C8D", +"e# c #D8DBE0", +"f# c #5A6682", +"g# c #778195", +"h# c #EAF0F8", +"i# c #8E9AB4", +"j# c #252B3F", +"k# c #42568E", +"l# c #56667D", +"m# c #D9F3FC", +"n# c #BED0D8", +"o# c #6F7586", +"p# c #30333F", +"q# c #515667", +"r# c #6B7794", +"s# c #88A5B6", +"t# c #C5E7F6", +"u# c #A1B7C2", +"v# c #6E7D8C", +"w# c #5D6D8D", +"x# c #677BA9", +"y# c #6C82AE", +"z# c #97B5D5", +"A# c #A2C5E9", +"B# c #8DB5F4", +"C# c #6B87C8", +"D# c #3A4665", +"E# c #3F4862", +"F# c #545D78", +"G# c #4C5569", +"H# c #9DADC8", +"I# c #2B3A58", +"J# c #798AAF", +"K# c #D4DEF0", +"L# c #374D81", +"M# c #6D778D", +"N# c #E6EDF2", +"O# c #9FAFCF", +"P# c #29324C", +"Q# c #435283", +"R# c #4D5566", +"S# c #B2C3D0", +"T# c #CAE4F1", +"U# c #A3B5CB", +"V# c #4F5464", +"W# c #43454F", +"X# c #656975", +"Y# c #69768D", +"Z# c #85A2BF", +"`# c #9EC5F4", +" $ c #7694C8", +".$ c #3E4B6B", +"+$ c #252A37", +"@$ c #1E2028", +"#$ c #16171C", +"$$ c #1F2229", +"%$ c #384564", +"&$ c #343D54", +"*$ c #3A4158", +"=$ c #616D94", +"-$ c #333E5F", +";$ c #868EAA", +">$ c #49567A", +",$ c #2A3F72", +"'$ c #A6AEBF", +")$ c #435A8F", +"!$ c #333D5B", +"~$ c #8690A5", +"{$ c #D0DFF5", +"]$ c #7B88AC", +"^$ c #353E5B", +"/$ c #454F6E", +"($ c #464E62", +"_$ c #A4B8D4", +":$ c #A9C6F3", +"<$ c #8599C5", +"[$ c #676F88", +"}$ c #40424B", +"|$ c #7F89A4", +"1$ c #97ABD1", +"2$ c #7A98DC", +"3$ c #7293E3", +"4$ c #5F7ABB", +"5$ c #627BB1", +"6$ c #586988", +"7$ c #2B2F3B", +"8$ c #16171B", +"9$ c #18191C", +"0$ c #36405E", +"a$ c #5A6896", +"b$ c #2D3244", +"c$ c #909ACA", +"d$ c #3D5189", +"e$ c #475070", +"f$ c #ADB5E0", +"g$ c #374D8F", +"h$ c #262F49", +"i$ c #6876A1", +"j$ c #ABB7E6", +"k$ c #8792BF", +"l$ c #545D7F", +"m$ c #3D4257", +"n$ c #404352", +"o$ c #67708B", +"p$ c #879BDB", +"q$ c #819AE3", +"r$ c #8796C2", +"s$ c #525970", +"t$ c #3D414C", +"u$ c #373C4D", +"v$ c #404C6D", +"w$ c #556BA5", +"x$ c #536DB0", +"y$ c #5874BB", +"z$ c #5770B2", +"A$ c #344164", +"B$ c #3C486C", +"C$ c #515878", +"D$ c #313545", +"E$ c #5E617B", +"F$ c #7E89B8", +"G$ c #2B334C", +"H$ c #48506F", +"I$ c #252A3B", +"J$ c #2B3048", +"K$ c #636C93", +"L$ c #919AC9", +"M$ c #8792BE", +"N$ c #51576E", +"O$ c #575B6C", +"P$ c #5E5F69", +"Q$ c #565B6C", +"R$ c #6F7BA2", +"S$ c #7187CC", +"T$ c #6377B4", +"U$ c #6F80AC", +"V$ c #5B6581", +"W$ c #4B5169", +"X$ c #535E7E", +"Y$ c #6373A1", +"Z$ c #566796", +"`$ c #3D4866", +" % c #38476D", +".% c #37476F", +"+% c #323646", +"@% c #394059", +"#% c #545971", +"$% c #202128", +"%% c #696B8C", +"&% c #656FA5", +"*% c #2A3A6B", +"=% c #565F84", +"-% c #414B72", +";% c #37405F", +">% c #525D80", +",% c #70779D", +"'% c #8993C2", +")% c #686F8E", +"!% c #525563", +"~% c #525462", +"{% c #4D4E58", +"]% c #454A5E", +"^% c #68759C", +"/% c #52649C", +"(% c #4F64A0", +"_% c #3A4872", +":% c #2A324C", +"<% c #1D212D", +"[% c #21232C", +"}% c #3A3C47", +"|% c #303444", +"1% c #191B1E", +"2% c #34394B", +"3% c #404764", +"4% c #484B5E", +"5% c #242632", +"6% c #8596DE", +"7% c #6681CC", +"8% c #2D3855", +"9% c #424E77", +"0% c #8388B9", +"a% c #434A63", +"b% c #5C6485", +"c% c #717AA6", +"d% c #666E95", +"e% c #5A5F76", +"f% c #4A4C56", +"g% c #656B7F", +"h% c #606A84", +"i% c #3B4159", +"j% c #364570", +"k% c #303C61", +"l% c #2E364D", +"m% c #323546", +"n% c #444A66", +"o% c #3D3F4F", +"p% c #404A66", +"q% c #8399CC", +"r% c #6E819E", +"s% c #3E507C", +"t% c #344169", +"u% c #6A79B5", +"v% c #7376A1", +"w% c #565C7B", +"x% c #4D5261", +"y% c #282A2F", +"z% c #24293C", +"A% c #333D59", +"B% c #303C5F", +"C% c #2D2F3B", +"D% c #373D54", +"E% c #474A5F", +"F% c #3C4057", +"G% c #3F5083", +"H% c #849ABA", +"I% c #334373", +"J% c #344578", +"K% c #525D8F", +"L% c #686E9B", +"M% c #5B6282", +"N% c #424A67", +"O% c #4D5B81", +"P% c #444D65", +"Q% c #434B68", +"R% c #5B668C", +"S% c #58638C", +"T% c #465074", +"U% c #414B6E", +"V% c #2F364B", +"W% c #252830", +"X% c #3F4046", +"Y% c #343740", +"Z% c #191A1E", +"`% c #1A1B21", +" & c #2D303E", +".& c #373E59", +"+& c #3F4154", +"@& c #3C3D50", +"#& c #262C3D", +"$& c #495672", +"%& c #6477A2", +"&& c #3D4D7A", +"*& c #33426E", +"=& c #363F5F", +"-& c #4B5171", +";& c #525875", +">& c #4F5774", +",& c #444C68", +"'& c #485375", +")& c #3E455E", +"!& c #454F70", +"~& c #56638A", +"{& c #383F57", +"]& c #313A57", +"^& c #3D496E", +"/& c #323D60", +"(& c #364265", +"_& c #222736", +":& c #2C2F3D", +"<& c #31374C", +"[& c #33374A", +"}& c #3A3C4D", +"|& c #1D1F26", +"1& c #303850", +"2& c #4E5B8D", +"3& c #43496D", +"4& c #344068", +"5& c #3B466A", +"6& c #353E5D", +"7& c #49506E", +"8& c #454A64", +"9& c #414864", +"0& c #495372", +"a& c #292D3B", +"b& c #3B3D49", +"c& c #1F2128", +"d& c #363C51", +"e& c #1D212F", +"f& c #272A36", +"g& c #2B3146", +"h& c #2F364E", +"i& c #383B4E", +"j& c #3F496A", +"k& c #303751", +"l& c #3A3E55", +"m& c #3C3E52", +"n& c #3A4059", +"o& c #394260", +"p& c #2C334A", +"q& c #383F56", +"r& c #383D51", +"s& c #353A4C", +"t& c #32384C", +"u& c #31374B", +"v& c #333950", +"w& c #282E41", +"x& c #202431", +"y& c #1A1B1F", +"z& c #262B37", +"A& c #282C3D", +"B& c #303547", +"C& c #393D53", +"D& c #32384E", +"E& c #343B54", +"F& c #292C38", +"G& c #2F3242", +"H& c #2C303F", +"I& c #2C2F3C", +"J& c #252832", +"K& c #2D313E", +"L& c #262935", +"M& c #2A2E3C", +"N& c #21242F", +"O& c #20242E", +"P& c #222429", +"Q& c #262A3B", +"R& c #1A1C22", +"S& c #282C3B", +"T& c #30364C", +"U& c #333A54", +"V& c #2A3044", +"W& c #272A37", +"X& c #292E3F", +"Y& c #2A2F42", +"Z& c #272D3F", +"`& c #1E212A", +" * c #1B1C1F", +".* c #1C1E21", +"+* c #1D1F22", +"@* c #22242D", +"#* c #232631", +"$* c #222734", +"%* c #1C1D23", +"&* c #1E1F22", +"** c #1C1D21", +" . + @ # $ % & * ", +" = - ; > , ' ) ! ~ { ] ^ / ( ", +" _ : < [ } | 1 2 3 4 5 6 7 8 9 0 ", +" a b c d e f g h i j k l m n o p q r s t ", +" u v w x y z A B C D E F G H I J K L M N O P ", +" Q R S T U V W X Y Z ` ...+.@.@.@.@.@.@.#.$.%.&. ", +" *.=.-.;.>.,.'.).!.~.{.].^.@.@.@./.(._.:.@.@.@.<.[.}. ", +" |.1.2.3.4.5.6.7.8.9.0.@.@.@.a.b.c.d.e.f.g.h.i.j.k.l. ", +" m.n.o.p.q.r.s.t.u.v.w.@.@.x.y.z.A.B.C.6 D.E.F.G.H.I.J.0 ", +" K.L.M.N.O.P.Q.R.S.T.@.@.U.V.W.X.Y.Z.`. +.+++@+#+$+%+&+*+=+-+ ", +" ;+>+,+'+)+!+~+{+@.@.]+^+/+(+_+:+<+[+}+|+1+2+3+4+5+6+7+8+9+0+ ", +" a+b+c+d+e+f+g+@.@.h+i+j+k+l+m+n+o+p+q+r+s+t+u+v+w+x+y+z+A+B+ ", +"C+D+E+F+G+H+I+J+@.K+L+M+N+O+P+Q+R+S+T+U+V+W+X+Y+Z+`+ @.@+@@@#@$@", +"%@&@*@=@-@;@>@@.,@'@)@!@~@{@]@^@/@(@_@:@<@[@}@|@1@2@3@4@5@6@7@8@", +"9@0@a@b@c@d@e@@.f@g@h@i@j@k@l@m@n@o@p@q@r@s@t@u@v@w@x@y@z@A@B@C@", +"D@E@F@G@H@I@J@@.K@L@M@N@O@P@Q@R@S@T@U@V@W@X@Y@Z@`@ #.#+#@###$#%#", +"&#*#=#-#;#>#,#@.'#)#!#~#{#]#^#/#(#_#:#<#[#}#|#1#2#3#4#5#6#7#8#9#", +"0#a#b#c#d#e#f#@.g#h#i#j#k#l#m#n#o#p#q#r#s#t#u#v#w#x#y#z#A#B#C#D#", +"E#F#G#H#I#J#K#@.L#M#N#O#P#Q#R#S#T#U#V#W#X#Y#Z#`# $.$+$@$#$$$%$&$", +"*$=$-$;$>$,$'$@.)$!$~${$]$^$/$($_$:$<$[$}$a.|$1$2$3$4$5$6$7$8$9$", +" 0$a$b$c$d$e$f$@.g$h$i$j$k$l$m$n$o$p$q$r$s$N.t$u$v$w$x$y$z$A$ ", +" B$C$D$E$F$G$H$@.@.I$J$K$L$M$N$O$P$Q$R$S$T$U$V$W$X$Y$Z$`$ %.% ", +" +%@%#%$%%%&%*%=%@.@.-%;%>%,%'%)%!%~%{%]%^%/%(%_%:%<%[%}%|%1% ", +" 2%3%4%5%6%7%8%9%0%@.@.@.a%b%c%d%e%f%g%h%i%@.@.@.@.j%k%l% ", +" m%n%o%p%q%r%s%t%u%v%w%@.@.@.@.@.@.@.@.@.@.x%y%z%A%B% ", +" C%D%E%F%G%H%B.I%J%K%L%M%N%O%P%Q%R%S%T%U%V%W%X%Y%Z%`% ", +" &.&+&@&#&$&%&&&*&=&-&;&>&,&'&)&!&~&{&]&^&/&(&_& ", +" :&<&[&}&|&1&2&3&4&5&6&7&8&9&{&0&a&b&c&d&_&e& ", +" f&g&h&i&j&k&l&m&n&o&p&q&r&s&t&u&v&w&x&y& ", +" z&A&B&C&D&E&F&G&H&I&J&K&L&M&N&O& ", +" P&Q&R&S&F&T&U&V&W&X&Y&Z&`& * ", +" .*+*@*#*$*%*&*** "}; diff --git a/debian/rdlibrary.desktop b/debian/rdlibrary.desktop new file mode 100644 index 00000000..d0ae6e7f --- /dev/null +++ b/debian/rdlibrary.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=rdlibrary +Comment=Rivendell Library +Exec=rdlibrary +Terminal=false +Type=Application +Icon=/usr/share/srlabs/rdlibrary.xpm +Categories=Application;AudioVideo; diff --git a/debian/rdlibrary.xpm b/debian/rdlibrary.xpm new file mode 100644 index 00000000..3ef9412b --- /dev/null +++ b/debian/rdlibrary.xpm @@ -0,0 +1,788 @@ +/* XPM */ +static char * rdlibrary_xpm[] = { +"32 32 753 2", +" c None", +". c #3D485E", +"+ c #3D485F", +"@ c #364156", +"# c #3B475D", +"$ c #414F69", +"% c #37435A", +"& c #36425B", +"* c #3B4A68", +"= c #2F3645", +"- c #4B5871", +"; c #505D74", +"> c #4D586E", +", c #454F62", +"' c #606E88", +") c #5B6985", +"! c #414D64", +"~ c #536280", +"{ c #4E5F81", +"] c #3F4E69", +"^ c #435478", +"/ c #384868", +"( c #2E384D", +"_ c #424D5E", +": c #576375", +"< c #57606E", +"[ c #525B6A", +"} c #778192", +"| c #3B414B", +"1 c #8A98A8", +"2 c #404753", +"3 c #758398", +"4 c #4B5669", +"5 c #58667F", +"6 c #51607E", +"7 c #404D68", +"8 c #47587A", +"9 c #394868", +"0 c #364566", +"a c #30353E", +"b c #485468", +"c c #677281", +"d c #484F5D", +"e c #8F96A5", +"f c #3D414E", +"g c #A1A6B3", +"h c #4D5363", +"i c #8992A1", +"j c #686E79", +"k c #545E70", +"l c #8494A9", +"m c #3C4454", +"n c #586581", +"o c #6478A1", +"p c #3D4964", +"q c #46587D", +"r c #4A5D87", +"s c #323E5C", +"t c #354464", +"u c #23262D", +"v c #636F7E", +"w c #404551", +"x c #E11313", +"y c #222531", +"z c #C7C8CD", +"A c #393C48", +"B c #A3A6B3", +"C c #7A7D86", +"D c #404557", +"E c #BEC3D0", +"F c #535768", +"G c #434B5E", +"H c #8FA0B8", +"I c #5E6983", +"J c #3D465C", +"K c #6A7EA7", +"L c #506285", +"M c #45567B", +"N c #445983", +"O c #3A4A70", +"P c #293246", +"Q c #404B5C", +"R c #48505C", +"S c #6F7A88", +"T c #636570", +"U c #20222B", +"V c #DBDDE2", +"W c #50535F", +"X c #6C6E76", +"Y c #D1D3DC", +"Z c #2A2E3F", +"` c #505564", +" . c #C4C9D3", +".. c #5C6374", +"+. c #353A44", +"@. c #8092AC", +"#. c #7283A0", +"$. c #3B4359", +"%. c #3F4C67", +"&. c #5B72A2", +"*. c #425379", +"=. c #3E4C6F", +"-. c #3C4F7A", +";. c #374668", +">. c #2A2E35", +",. c #54627A", +"'. c #9299A1", +"). c #3C404D", +"!. c #878996", +"~. c #373E55", +"{. c #CCCDD6", +"]. c #767989", +"^. c #3C435E", +"/. c #A8AAB4", +"(. c #A8AAB8", +"_. c #363B4E", +":. c #565A68", +"<. c #C2CEDA", +"[. c #76829B", +"}. c #353E56", +"|. c #54617C", +"1. c #86A2D2", +"2. c #5E6F96", +"3. c #4A557A", +"4. c #45567D", +"5. c #5975B2", +"6. c #3E4E75", +"7. c #3A4362", +"8. c #202023", +"9. c #627183", +"0. c #394152", +"a. c #B8BBC3", +"b. c #2A2D39", +"c. c #848591", +"d. c #1C202C", +"e. c #A2A8BE", +"f. c #C9CAD3", +"g. c #212431", +"h. c #4D5164", +"i. c #D7D7DB", +"j. c #8B8C95", +"k. c #36384A", +"l. c #4D5160", +"m. c #AEBFD0", +"n. c #8495AC", +"o. c #424C72", +"p. c #3B4560", +"q. c #5F749D", +"r. c #6A86B9", +"s. c #526288", +"t. c #5F6D9F", +"u. c #415582", +"v. c #5572B5", +"w. c #2F3D5B", +"x. c #47566D", +"y. c #7D8C9E", +"z. c #33343A", +"A. c #C6C7CF", +"B. c #242A3A", +"C. c #6E7792", +"D. c #CFD1D8", +"E. c #494C57", +"F. c #DFE0E3", +"G. c #8C8E9C", +"H. c #22242C", +"I. c #616471", +"J. c #DDDEE2", +"K. c #838692", +"L. c #404357", +"M. c #4F5777", +"N. c #8293AB", +"O. c #97AFD1", +"P. c #444C73", +"Q. c #4A5579", +"R. c #607DB6", +"S. c #5977B2", +"T. c #333E59", +"U. c #464E6C", +"V. c #4D6399", +"W. c #363F4B", +"X. c #4B596D", +"Y. c #8492A4", +"Z. c #363A46", +"`. c #CFD0D4", +" + c #3F4C6D", +".+ c #3C4256", +"++ c #ECEEF5", +"@+ c #555B77", +"#+ c #8E909D", +"$+ c #DCDCE3", +"%+ c #717385", +"&+ c #24252D", +"*+ c #616472", +"=+ c #E8EBF3", +"-+ c #A0A9BC", +";+ c #222430", +">+ c #424C70", +",+ c #8BA3C8", +"'+ c #96B6E9", +")+ c #647AA9", +"!+ c #293044", +"~+ c #46506E", +"{+ c #667BB3", +"]+ c #6A8CD6", +"^+ c #7090DC", +"/+ c #313A54", +"(+ c #1F242E", +"_+ c #222326", +":+ c #657B92", +"<+ c #3C4558", +"[+ c #919FB2", +"}+ c #262C3C", +"|+ c #BEC1CA", +"1+ c #676C7D", +"2+ c #384467", +"3+ c #ADADB5", +"4+ c #2A2D3A", +"5+ c #3D4253", +"6+ c #C5C6CD", +"7+ c #D6D6DF", +"8+ c #53586E", +"9+ c #34384B", +"0+ c #4E5365", +"a+ c #C1D2E5", +"b+ c #B1C4E5", +"c+ c #505A79", +"d+ c #212331", +"e+ c #3F486A", +"f+ c #7E9BD4", +"g+ c #84AAEF", +"h+ c #5A70A8", +"i+ c #252C3C", +"j+ c #242938", +"k+ c #4B5F90", +"l+ c #5D82D2", +"m+ c #48649F", +"n+ c #273147", +"o+ c #6F8398", +"p+ c #333841", +"q+ c #A0ABB5", +"r+ c #283454", +"s+ c #99A1B7", +"t+ c #A8AFBF", +"u+ c #21283B", +"v+ c #878EA8", +"w+ c #71778C", +"x+ c #2D344D", +"y+ c #4C4E5D", +"z+ c #D4D8E4", +"A+ c #BDC0CB", +"B+ c #41465B", +"C+ c #454E73", +"D+ c #464C60", +"E+ c #9AAEC8", +"F+ c #A3BEDE", +"G+ c #6876A0", +"H+ c #353B57", +"I+ c #272C3C", +"J+ c #3E4C6D", +"K+ c #7DA2EA", +"L+ c #6487CB", +"M+ c #647CAB", +"N+ c #535E85", +"O+ c #2B3550", +"P+ c #3A4E7A", +"Q+ c #5170A4", +"R+ c #4C4E51", +"S+ c #8096AC", +"T+ c #2C323F", +"U+ c #B7C4D0", +"V+ c #3C4A6C", +"W+ c #4C5773", +"X+ c #DCDCE1", +"Y+ c #5D6A8F", +"Z+ c #242D47", +"`+ c #575D70", +" @ c #3F4A70", +".@ c #404456", +"+@ c #DFE5F3", +"@@ c #D5E0F0", +"#@ c #3D4453", +"$@ c #3A4568", +"%@ c #4E5982", +"&@ c #67799B", +"*@ c #9EC0F4", +"=@ c #6D87B6", +"-@ c #62709E", +";@ c #555F8A", +">@ c #343A4F", +",@ c #3F537E", +"'@ c #668EDD", +")@ c #597DC5", +"!@ c #303E5C", +"~@ c #3A4357", +"{@ c #445072", +"]@ c #333C52", +"^@ c #44494F", +"/@ c #7C95A3", +"(@ c #262E3D", +"_@ c #A0A9B1", +":@ c #5E6980", +"<@ c #324576", +"[@ c #C8CAD2", +"}@ c #9BA3B7", +"|@ c #2E3445", +"1@ c #4F5978", +"2@ c #CAD0E2", +"3@ c #2B3142", +"4@ c #455681", +"5@ c #565E72", +"6@ c #BFCFD9", +"7@ c #B6CCE5", +"8@ c #5B698A", +"9@ c #23293B", +"0@ c #56638D", +"a@ c #6A7EAB", +"b@ c #7B9DD7", +"c@ c #7DA1E1", +"d@ c #475A80", +"e@ c #434C67", +"f@ c #5C6A98", +"g@ c #677BB2", +"h@ c #6685C4", +"i@ c #6791E1", +"j@ c #7BA5EB", +"k@ c #4B5C7B", +"l@ c #1E2026", +"m@ c #444D55", +"n@ c #79868D", +"o@ c #4B5259", +"p@ c #6B7786", +"q@ c #B1C0D7", +"r@ c #2B334A", +"s@ c #788AAD", +"t@ c #EBEDF2", +"u@ c #66779C", +"v@ c #242C39", +"w@ c #D9DCE2", +"x@ c #C2CEE3", +"y@ c #464F63", +"z@ c #374458", +"A@ c #546173", +"B@ c #97ADC6", +"C@ c #B5D5F7", +"D@ c #8BA3C4", +"E@ c #323A4F", +"F@ c #383F4C", +"G@ c #515D77", +"H@ c #6E8CBE", +"I@ c #729BE0", +"J@ c #779FE7", +"K@ c #455981", +"L@ c #202530", +"M@ c #242832", +"N@ c #2D374D", +"O@ c #55729B", +"P@ c #A9CAD7", +"Q@ c #677A89", +"R@ c #465159", +"S@ c #616D7B", +"T@ c #88909B", +"U@ c #2F3747", +"V@ c #CCD7DF", +"W@ c #525C70", +"X@ c #4F638E", +"Y@ c #B3B5BA", +"Z@ c #BDC0C7", +"`@ c #506A96", +" # c #6C80A8", +".# c #DFEDF4", +"+# c #A6BBCB", +"@# c #374869", +"## c #232A39", +"$# c #526286", +"%# c #7288A8", +"&# c #A0C5F3", +"*# c #87A7CE", +"=# c #5E7091", +"-# c #384150", +";# c #282C35", +"># c #4D6083", +",# c #8DB7F3", +"'# c #7DADF3", +")# c #7199CA", +"!# c #7D9DC6", +"~# c #5C71A3", +"{# c #424E66", +"]# c #576478", +"^# c #5A6B87", +"/# c #414954", +"(# c #4F5E73", +"_# c #B0BCC5", +":# c #363F4C", +"<# c #BBCDE3", +"[# c #D3E3F0", +"}# c #2A3242", +"|# c #51648B", +"1# c #DEE0E4", +"2# c #B7BEC8", +"3# c #374871", +"4# c #62728D", +"5# c #C5E2F2", +"6# c #A2BCD1", +"7# c #596B91", +"8# c #272C38", +"9# c #484F64", +"0# c #6A7C9E", +"a# c #89ADDB", +"b# c #8EBBEB", +"c# c #819FC2", +"d# c #77869D", +"e# c #454F65", +"f# c #2E3647", +"g# c #354258", +"h# c #89AABE", +"i# c #CCE9F5", +"j# c #92B3C9", +"k# c #4D5E76", +"l# c #242935", +"m# c #17181C", +"n# c #4B556B", +"o# c #515F72", +"p# c #89939D", +"q# c #6A7B8E", +"r# c #6B7C8D", +"s# c #D8DBE0", +"t# c #5A6682", +"u# c #2C3D64", +"v# c #778195", +"w# c #EAF0F8", +"x# c #252B3F", +"y# c #42568E", +"z# c #56667D", +"A# c #D9F3FC", +"B# c #BED0D8", +"C# c #6F7586", +"D# c #30333F", +"E# c #515667", +"F# c #6B7794", +"G# c #88A5B6", +"H# c #C5E7F6", +"I# c #A1B7C2", +"J# c #6E7D8C", +"K# c #5D6D8D", +"L# c #677BA9", +"M# c #6C82AE", +"N# c #97B5D5", +"O# c #A2C5E9", +"P# c #8DB5F4", +"Q# c #6B87C8", +"R# c #3A4665", +"S# c #3F4862", +"T# c #545D78", +"U# c #4C5569", +"V# c #9DADC8", +"W# c #2B3A58", +"X# c #798AAF", +"Y# c #D4DEF0", +"Z# c #454D5E", +"`# c #374D81", +" $ c #6D778D", +".$ c #9FAFCF", +"+$ c #29324C", +"@$ c #435283", +"#$ c #4D5566", +"$$ c #B2C3D0", +"%$ c #CAE4F1", +"&$ c #A3B5CB", +"*$ c #4F5464", +"=$ c #43454F", +"-$ c #656975", +";$ c #69768D", +">$ c #85A2BF", +",$ c #9EC5F4", +"'$ c #7694C8", +")$ c #3E4B6B", +"!$ c #252A37", +"~$ c #1E2028", +"{$ c #16171C", +"]$ c #1F2229", +"^$ c #384564", +"/$ c #343D54", +"($ c #3A4158", +"_$ c #616D94", +":$ c #333E5F", +"<$ c #868EAA", +"[$ c #49567A", +"}$ c #2A3F72", +"|$ c #A6AEBF", +"1$ c #999EB2", +"2$ c #435A8F", +"3$ c #333D5B", +"4$ c #D0DFF5", +"5$ c #7B88AC", +"6$ c #353E5B", +"7$ c #454F6E", +"8$ c #464E62", +"9$ c #A4B8D4", +"0$ c #A9C6F3", +"a$ c #8599C5", +"b$ c #676F88", +"c$ c #40424B", +"d$ c #7F89A4", +"e$ c #97ABD1", +"f$ c #7A98DC", +"g$ c #7293E3", +"h$ c #5F7ABB", +"i$ c #627BB1", +"j$ c #586988", +"k$ c #2B2F3B", +"l$ c #16171B", +"m$ c #18191C", +"n$ c #36405E", +"o$ c #5A6896", +"p$ c #2D3244", +"q$ c #909ACA", +"r$ c #3D5189", +"s$ c #475070", +"t$ c #ADB5E0", +"u$ c #7D87B1", +"v$ c #374D8F", +"w$ c #6876A1", +"x$ c #ABB7E6", +"y$ c #8792BF", +"z$ c #545D7F", +"A$ c #3D4257", +"B$ c #404352", +"C$ c #67708B", +"D$ c #879BDB", +"E$ c #819AE3", +"F$ c #8796C2", +"G$ c #525970", +"H$ c #3D414C", +"I$ c #373C4D", +"J$ c #404C6D", +"K$ c #556BA5", +"L$ c #536DB0", +"M$ c #5874BB", +"N$ c #5770B2", +"O$ c #344164", +"P$ c #3C486C", +"Q$ c #515878", +"R$ c #313545", +"S$ c #5E617B", +"T$ c #7E89B8", +"U$ c #2B334C", +"V$ c #48506F", +"W$ c #A8ADDC", +"X$ c #8492D1", +"Y$ c #2B3048", +"Z$ c #636C93", +"`$ c #919AC9", +" % c #8792BE", +".% c #51576E", +"+% c #575B6C", +"@% c #5E5F69", +"#% c #565B6C", +"$% c #6F7BA2", +"%% c #7187CC", +"&% c #6377B4", +"*% c #6F80AC", +"=% c #5B6581", +"-% c #4B5169", +";% c #535E7E", +">% c #6373A1", +",% c #566796", +"'% c #3D4866", +")% c #38476D", +"!% c #37476F", +"~% c #323646", +"{% c #394059", +"]% c #545971", +"^% c #202128", +"/% c #696B8C", +"(% c #656FA5", +"_% c #2A3A6B", +":% c #565F84", +"<% c #7579A1", +"[% c #414B72", +"}% c #37405F", +"|% c #525D80", +"1% c #70779D", +"2% c #8993C2", +"3% c #686F8E", +"4% c #525563", +"5% c #525462", +"6% c #4D4E58", +"7% c #454A5E", +"8% c #68759C", +"9% c #52649C", +"0% c #4F64A0", +"a% c #3A4872", +"b% c #2A324C", +"c% c #1D212D", +"d% c #21232C", +"e% c #3A3C47", +"f% c #303444", +"g% c #191B1E", +"h% c #34394B", +"i% c #404764", +"j% c #484B5E", +"k% c #242632", +"l% c #8596DE", +"m% c #6681CC", +"n% c #2D3855", +"o% c #8388B9", +"p% c #7C83B8", +"q% c #383E58", +"r% c #404969", +"s% c #434A63", +"t% c #5C6485", +"u% c #717AA6", +"v% c #666E95", +"w% c #5A5F76", +"x% c #4A4C56", +"y% c #656B7F", +"z% c #606A84", +"A% c #3B4159", +"B% c #323B56", +"C% c #3C4B76", +"D% c #44578F", +"E% c #3C4D7E", +"F% c #364570", +"G% c #303C61", +"H% c #2E364D", +"I% c #323546", +"J% c #444A66", +"K% c #3D3F4F", +"L% c #404A66", +"M% c #8399CC", +"N% c #6E819E", +"O% c #2D2F3B", +"P% c #373D54", +"Q% c #474A5F", +"R% c #3C4057", +"S% c #3F5083", +"T% c #849ABA", +"U% c #5B6282", +"V% c #424A67", +"W% c #4D5B81", +"X% c #444D65", +"Y% c #434B68", +"Z% c #5B668C", +"`% c #58638C", +" & c #465074", +".& c #414B6E", +"+& c #2F364B", +"@& c #252830", +"#& c #3F4046", +"$& c #343740", +"%& c #191A1E", +"&& c #1A1B21", +"*& c #2D303E", +"=& c #373E59", +"-& c #3F4154", +";& c #3C3D50", +">& c #262C3D", +",& c #495672", +"'& c #6477A2", +")& c #3D4D7A", +"!& c #33426E", +"~& c #363F5F", +"{& c #4B5171", +"]& c #525875", +"^& c #4F5774", +"/& c #444C68", +"(& c #485375", +"_& c #3E455E", +":& c #454F70", +"<& c #56638A", +"[& c #383F57", +"}& c #313A57", +"|& c #3D496E", +"1& c #323D60", +"2& c #364265", +"3& c #222736", +"4& c #2C2F3D", +"5& c #31374C", +"6& c #33374A", +"7& c #3A3C4D", +"8& c #1D1F26", +"9& c #303850", +"0& c #4E5B8D", +"a& c #43496D", +"b& c #344068", +"c& c #3B466A", +"d& c #353E5D", +"e& c #49506E", +"f& c #454A64", +"g& c #414864", +"h& c #495372", +"i& c #292D3B", +"j& c #3B3D49", +"k& c #1F2128", +"l& c #363C51", +"m& c #1D212F", +"n& c #272A36", +"o& c #2B3146", +"p& c #2F364E", +"q& c #383B4E", +"r& c #3F496A", +"s& c #303751", +"t& c #3A3E55", +"u& c #3C3E52", +"v& c #3A4059", +"w& c #394260", +"x& c #2C334A", +"y& c #383F56", +"z& c #383D51", +"A& c #353A4C", +"B& c #32384C", +"C& c #31374B", +"D& c #333950", +"E& c #282E41", +"F& c #202431", +"G& c #1A1B1F", +"H& c #262B37", +"I& c #282C3D", +"J& c #303547", +"K& c #393D53", +"L& c #32384E", +"M& c #343B54", +"N& c #292C38", +"O& c #2F3242", +"P& c #2C303F", +"Q& c #2C2F3C", +"R& c #252832", +"S& c #2D313E", +"T& c #262935", +"U& c #2A2E3C", +"V& c #21242F", +"W& c #20242E", +"X& c #222429", +"Y& c #262A3B", +"Z& c #1A1C22", +"`& c #282C3B", +" * c #30364C", +".* c #333A54", +"+* c #2A3044", +"@* c #272A37", +"#* c #292E3F", +"$* c #2A2F42", +"%* c #272D3F", +"&* c #1E212A", +"** c #1B1C1F", +"=* c #1C1E21", +"-* c #1D1F22", +";* c #22242D", +">* c #232631", +",* c #222734", +"'* c #1C1D23", +")* c #1E1F22", +"!* c #1C1D21", +" . + @ # $ % & * ", +" = - ; > , ' ) ! ~ { ] ^ / ( ", +" _ : < [ } | 1 2 3 4 5 6 7 8 9 0 ", +" a b c d e f g h i j k l m n o p q r s t ", +" u v w x y z A B C D E F G H I J K L M N O P ", +" Q R S T x U V W X Y Z ` ...+.@.#.$.%.&.*.=.-.;. ", +" >.,.'.).!.x ~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.7.8. ", +" 9.0.a.b.c.x d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w. ", +" x.y.z.A.B.C.D.x E.F.G.H.I.J.K.L.M.N.O.6 P.Q.R.S.T.U.V.0 ", +" W.X.Y.Z.`. +.+++x @+#+$+%+&+*+=+-+;+>+,+'+)+!+~+{+]+^+/+(+_+ ", +" :+<+[+}+|+1+2+3+x 4+5+6+7+8+9+0+a+b+c+d+e+f+g+h+i+j+k+l+m+n+ ", +" o+p+q+r+s+t+u+v+x w+x+y+z+A+B+C+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+ ", +"R+S+T+U+V+W+X+Y+Z+x x `+ @.@+@@@#@$@%@&@*@=@-@;@>@,@'@)@!@~@{@]@", +"^@/@(@_@:@<@[@}@|@1@x 2@3@4@5@6@7@8@9@0@a@b@c@d@e@f@g@h@i@j@k@l@", +"m@n@o@p@q@r@s@t@u@v@x w@x@y@z@A@B@C@D@E@F@G@H@I@J@K@L@M@N@O@P@Q@", +"R@S@T@U@V@W@X@Y@Z@`@x #.#+#@###$#%#&#*#=#-#;#>#,#'#)#!#~#{#]#^#", +"/#(#_#:#<#[#}#|#1#2#x 3#4#5#6#7#8#9#0#a#b#c#d#e#f#g#h#i#j#k#l#m#", +"n#o#p#q#r#s#t#u#v#w#x x#y#z#A#B#C#D#E#F#G#H#I#J#K#L#M#N#O#P#Q#R#", +"S#T#U#V#W#X#Y#Z#`# $x .$+$@$#$$$%$&$*$=$-$;$>$,$'$)$!$~${$]$^$/$", +"($_$:$<$[$}$|$1$2$3$x 4$5$6$7$8$9$0$a$b$c$l.d$e$f$g$h$i$j$k$l$m$", +" n$o$p$q$r$s$t$u$v$x w$x$y$z$A$B$C$D$E$F$G$Z.H$I$J$K$L$M$N$O$ ", +" P$Q$R$S$T$U$V$W$X$x Y$Z$`$ %.%+%@%#%$%%%&%*%=%-%;%>%,%'%)%!% ", +" ~%{%]%^%/%(%_%:%x <%[%}%|%1%2%3%4%5%6%7%8%9%0%a%b%c%d%e%f%g% ", +" h%i%j%k%l%m%n%x o%p%q%r%s%t%u%v%w%x%y%z%A%B%C%D%E%F%G%H% ", +" I%J%K%L%M%N%x x x x x x x x x x x x x x x x x x x x ", +" O%P%Q%R%S%T%x x x x x U%V%W%X%Y%Z%`% &.&+&@&#&$&%&&& ", +" *&=&-&;&>&,&'&)&!&~&{&]&^&/&(&_&:&<&[&}&|&1&2&3& ", +" 4&5&6&7&8&9&0&a&b&c&d&e&f&g&[&h&i&j&k&l&3&m& ", +" n&o&p&q&r&s&t&u&v&w&x&y&z&A&B&C&D&E&F&G& ", +" H&I&J&K&L&M&N&O&P&Q&R&S&T&U&V&W& ", +" X&Y&Z&`&N& *.*+*@*#*$*%*&*** ", +" =*-*;*>*,*'*)*!* "}; diff --git a/debian/rdlogedit.desktop b/debian/rdlogedit.desktop new file mode 100644 index 00000000..06d0bc89 --- /dev/null +++ b/debian/rdlogedit.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=rdlogedit +Comment=Rivendell Logedit +Exec=rdlogedit +Terminal=false +Type=Application +Icon=/usr/share/srlabs/rdlogedit.xpm +Categories=Application;AudioVideo; diff --git a/debian/rdlogedit.xpm b/debian/rdlogedit.xpm new file mode 100644 index 00000000..0666db92 --- /dev/null +++ b/debian/rdlogedit.xpm @@ -0,0 +1,751 @@ +/* XPM */ +static char * rdlogedit_xpm[] = { +"32 32 716 2", +" c None", +". c #3D485E", +"+ c #3D485F", +"@ c #364156", +"# c #3B475D", +"$ c #414F69", +"% c #37435A", +"& c #36425B", +"* c #3B4A68", +"= c #2F3645", +"- c #4B5871", +"; c #505D74", +"> c #4D586E", +", c #454F62", +"' c #606E88", +") c #5B6985", +"! c #414D64", +"~ c #536280", +"{ c #4E5F81", +"] c #3F4E69", +"^ c #435478", +"/ c #384868", +"( c #2E384D", +"_ c #424D5E", +": c #576375", +"< c #57606E", +"[ c #525B6A", +"} c #778192", +"| c #3B414B", +"1 c #8A98A8", +"2 c #404753", +"3 c #758398", +"4 c #4B5669", +"5 c #58667F", +"6 c #51607E", +"7 c #404D68", +"8 c #47587A", +"9 c #394868", +"0 c #364566", +"a c #30353E", +"b c #485468", +"c c #677281", +"d c #484F5D", +"e c #8F96A5", +"f c #3D414E", +"g c #A1A6B3", +"h c #4D5363", +"i c #8992A1", +"j c #686E79", +"k c #545E70", +"l c #8494A9", +"m c #3C4454", +"n c #586581", +"o c #6478A1", +"p c #3D4964", +"q c #46587D", +"r c #4A5D87", +"s c #323E5C", +"t c #354464", +"u c #E11313", +"v c #636F7E", +"w c #404551", +"x c #9BA1A7", +"y c #222531", +"z c #C7C8CD", +"A c #393C48", +"B c #A3A6B3", +"C c #7A7D86", +"D c #404557", +"E c #BEC3D0", +"F c #535768", +"G c #434B5E", +"H c #8FA0B8", +"I c #5E6983", +"J c #3D465C", +"K c #6A7EA7", +"L c #404B5C", +"M c #6F7A88", +"N c #636570", +"O c #888A94", +"P c #20222B", +"Q c #DBDDE2", +"R c #50535F", +"S c #6C6E76", +"T c #D1D3DC", +"U c #2A2E3F", +"V c #505564", +"W c #C4C9D3", +"X c #3F4C67", +"Y c #5B72A2", +"Z c #425379", +"` c #3E4C6F", +" . c #3C4F7A", +".. c #374668", +"+. c #2A2E35", +"@. c #54627A", +"#. c #3C404D", +"$. c #878996", +"%. c #878A99", +"&. c #373E55", +"*. c #CCCDD6", +"=. c #767989", +"-. c #3C435E", +";. c #A8AAB4", +">. c #A8AAB8", +",. c #363B4E", +"'. c #565A68", +"). c #76829B", +"!. c #353E56", +"~. c #54617C", +"{. c #86A2D2", +"]. c #5E6F96", +"^. c #4A557A", +"/. c #45567D", +"(. c #5975B2", +"_. c #3E4E75", +":. c #3A4362", +"<. c #202023", +"[. c #627183", +"}. c #394152", +"|. c #2A2D39", +"1. c #848591", +"2. c #A0A3B3", +"3. c #1C202C", +"4. c #A2A8BE", +"5. c #C9CAD3", +"6. c #212431", +"7. c #4D5164", +"8. c #D7D7DB", +"9. c #8B8C95", +"0. c #36384A", +"a. c #AEBFD0", +"b. c #8495AC", +"c. c #424C72", +"d. c #3B4560", +"e. c #5F749D", +"f. c #6A86B9", +"g. c #526288", +"h. c #5F6D9F", +"i. c #415582", +"j. c #5572B5", +"k. c #2F3D5B", +"l. c #47566D", +"m. c #7D8C9E", +"n. c #33343A", +"o. c #242A3A", +"p. c #6E7792", +"q. c #CFD1D8", +"r. c #424A62", +"s. c #494C57", +"t. c #DFE0E3", +"u. c #8C8E9C", +"v. c #22242C", +"w. c #616471", +"x. c #DDDEE2", +"y. c #838692", +"z. c #4F5777", +"A. c #8293AB", +"B. c #97AFD1", +"C. c #444C73", +"D. c #4A5579", +"E. c #607DB6", +"F. c #5977B2", +"G. c #333E59", +"H. c #464E6C", +"I. c #4D6399", +"J. c #363F4B", +"K. c #4B596D", +"L. c #8492A4", +"M. c #363A46", +"N. c #3F4C6D", +"O. c #3C4256", +"P. c #ECEEF5", +"Q. c #5F6169", +"R. c #555B77", +"S. c #8E909D", +"T. c #DCDCE3", +"U. c #717385", +"V. c #24252D", +"W. c #616472", +"X. c #E8EBF3", +"Y. c #222430", +"Z. c #424C70", +"`. c #8BA3C8", +" + c #96B6E9", +".+ c #647AA9", +"++ c #293044", +"@+ c #46506E", +"#+ c #667BB3", +"$+ c #6A8CD6", +"%+ c #7090DC", +"&+ c #313A54", +"*+ c #1F242E", +"=+ c #222326", +"-+ c #657B92", +";+ c #3C4558", +">+ c #919FB2", +",+ c #262C3C", +"'+ c #676C7D", +")+ c #384467", +"!+ c #ADADB5", +"~+ c #C9CDDC", +"{+ c #2A2D3A", +"]+ c #3D4253", +"^+ c #C5C6CD", +"/+ c #D6D6DF", +"(+ c #53586E", +"_+ c #34384B", +":+ c #4E5365", +"<+ c #B1C4E5", +"[+ c #505A79", +"}+ c #212331", +"|+ c #3F486A", +"1+ c #7E9BD4", +"2+ c #84AAEF", +"3+ c #5A70A8", +"4+ c #252C3C", +"5+ c #242938", +"6+ c #4B5F90", +"7+ c #5D82D2", +"8+ c #48649F", +"9+ c #273147", +"0+ c #6F8398", +"a+ c #333841", +"b+ c #A0ABB5", +"c+ c #283454", +"d+ c #A8AFBF", +"e+ c #21283B", +"f+ c #878EA8", +"g+ c #EBECF2", +"h+ c #71778C", +"i+ c #2D344D", +"j+ c #4C4E5D", +"k+ c #D4D8E4", +"l+ c #BDC0CB", +"m+ c #41465B", +"n+ c #454E73", +"o+ c #9AAEC8", +"p+ c #A3BEDE", +"q+ c #6876A0", +"r+ c #353B57", +"s+ c #272C3C", +"t+ c #3E4C6D", +"u+ c #7DA2EA", +"v+ c #6487CB", +"w+ c #647CAB", +"x+ c #535E85", +"y+ c #2B3550", +"z+ c #3A4E7A", +"A+ c #5170A4", +"B+ c #4C4E51", +"C+ c #8096AC", +"D+ c #2C323F", +"E+ c #B7C4D0", +"F+ c #3C4A6C", +"G+ c #DCDCE1", +"H+ c #5D6A8F", +"I+ c #242D47", +"J+ c #9A9EAD", +"K+ c #DBDBDE", +"L+ c #575D70", +"M+ c #3F4A70", +"N+ c #404456", +"O+ c #DFE5F3", +"P+ c #D5E0F0", +"Q+ c #3D4453", +"R+ c #4E5982", +"S+ c #67799B", +"T+ c #9EC0F4", +"U+ c #6D87B6", +"V+ c #62709E", +"W+ c #555F8A", +"X+ c #343A4F", +"Y+ c #3F537E", +"Z+ c #668EDD", +"`+ c #597DC5", +" @ c #303E5C", +".@ c #3A4357", +"+@ c #445072", +"@@ c #333C52", +"#@ c #44494F", +"$@ c #7C95A3", +"%@ c #262E3D", +"&@ c #A0A9B1", +"*@ c #5E6980", +"=@ c #C8CAD2", +"-@ c #9BA3B7", +";@ c #2E3445", +">@ c #4F5978", +",@ c #D8D9DE", +"'@ c #CAD0E2", +")@ c #2B3142", +"!@ c #455681", +"~@ c #565E72", +"{@ c #BFCFD9", +"]@ c #B6CCE5", +"^@ c #23293B", +"/@ c #56638D", +"(@ c #6A7EAB", +"_@ c #7B9DD7", +":@ c #7DA1E1", +"<@ c #475A80", +"[@ c #434C67", +"}@ c #5C6A98", +"|@ c #677BB2", +"1@ c #6685C4", +"2@ c #6791E1", +"3@ c #7BA5EB", +"4@ c #4B5C7B", +"5@ c #1E2026", +"6@ c #444D55", +"7@ c #79868D", +"8@ c #4B5259", +"9@ c #6B7786", +"0@ c #B1C0D7", +"a@ c #788AAD", +"b@ c #EBEDF2", +"c@ c #66779C", +"d@ c #242C39", +"e@ c #7B8DAB", +"f@ c #D9DCE2", +"g@ c #C2CEE3", +"h@ c #464F63", +"i@ c #374458", +"j@ c #546173", +"k@ c #97ADC6", +"l@ c #8BA3C4", +"m@ c #323A4F", +"n@ c #383F4C", +"o@ c #515D77", +"p@ c #6E8CBE", +"q@ c #729BE0", +"r@ c #779FE7", +"s@ c #455981", +"t@ c #202530", +"u@ c #242832", +"v@ c #2D374D", +"w@ c #55729B", +"x@ c #A9CAD7", +"y@ c #677A89", +"z@ c #465159", +"A@ c #616D7B", +"B@ c #88909B", +"C@ c #2F3747", +"D@ c #CCD7DF", +"E@ c #4F638E", +"F@ c #B3B5BA", +"G@ c #BDC0C7", +"H@ c #506A96", +"I@ c #313D4E", +"J@ c #6C80A8", +"K@ c #DFEDF4", +"L@ c #A6BBCB", +"M@ c #374869", +"N@ c #232A39", +"O@ c #526286", +"P@ c #576478", +"Q@ c #5A6B87", +"R@ c #414954", +"S@ c #4F5E73", +"T@ c #B0BCC5", +"U@ c #363F4C", +"V@ c #BBCDE3", +"W@ c #2A3242", +"X@ c #51648B", +"Y@ c #DEE0E4", +"Z@ c #B7BEC8", +"`@ c #313E5E", +" # c #374871", +".# c #62728D", +"+# c #C5E2F2", +"@# c #A2BCD1", +"## c #596B91", +"$# c #272C38", +"%# c #484F64", +"&# c #89ADDB", +"*# c #8EBBEB", +"=# c #819FC2", +"-# c #77869D", +";# c #454F65", +"># c #2E3647", +",# c #354258", +"'# c #89AABE", +")# c #CCE9F5", +"!# c #92B3C9", +"~# c #4D5E76", +"{# c #242935", +"]# c #17181C", +"^# c #4B556B", +"/# c #515F72", +"(# c #89939D", +"_# c #6A7B8E", +":# c #6B7C8D", +"<# c #5A6682", +"[# c #2C3D64", +"}# c #778195", +"|# c #EAF0F8", +"1# c #8E9AB4", +"2# c #252B3F", +"3# c #42568E", +"4# c #56667D", +"5# c #D9F3FC", +"6# c #BED0D8", +"7# c #6F7586", +"8# c #30333F", +"9# c #6B7794", +"0# c #88A5B6", +"a# c #C5E7F6", +"b# c #A1B7C2", +"c# c #6E7D8C", +"d# c #5D6D8D", +"e# c #677BA9", +"f# c #6C82AE", +"g# c #97B5D5", +"h# c #A2C5E9", +"i# c #8DB5F4", +"j# c #6B87C8", +"k# c #3A4665", +"l# c #3F4862", +"m# c #545D78", +"n# c #4C5569", +"o# c #9DADC8", +"p# c #2B3A58", +"q# c #D4DEF0", +"r# c #454D5E", +"s# c #374D81", +"t# c #6D778D", +"u# c #E6EDF2", +"v# c #9FAFCF", +"w# c #29324C", +"x# c #435283", +"y# c #4D5566", +"z# c #B2C3D0", +"A# c #CAE4F1", +"B# c #A3B5CB", +"C# c #43454F", +"D# c #656975", +"E# c #69768D", +"F# c #85A2BF", +"G# c #9EC5F4", +"H# c #7694C8", +"I# c #3E4B6B", +"J# c #252A37", +"K# c #1E2028", +"L# c #16171C", +"M# c #1F2229", +"N# c #384564", +"O# c #343D54", +"P# c #3A4158", +"Q# c #616D94", +"R# c #333E5F", +"S# c #868EAA", +"T# c #49567A", +"U# c #A6AEBF", +"V# c #999EB2", +"W# c #435A8F", +"X# c #333D5B", +"Y# c #8690A5", +"Z# c #D0DFF5", +"`# c #7B88AC", +" $ c #353E5B", +".$ c #454F6E", +"+$ c #464E62", +"@$ c #A4B8D4", +"#$ c #A9C6F3", +"$$ c #676F88", +"%$ c #40424B", +"&$ c #4D5160", +"*$ c #7F89A4", +"=$ c #97ABD1", +"-$ c #7A98DC", +";$ c #7293E3", +">$ c #5F7ABB", +",$ c #627BB1", +"'$ c #586988", +")$ c #2B2F3B", +"!$ c #16171B", +"~$ c #18191C", +"{$ c #36405E", +"]$ c #5A6896", +"^$ c #2D3244", +"/$ c #909ACA", +"($ c #475070", +"_$ c #ADB5E0", +":$ c #7D87B1", +"<$ c #374D8F", +"[$ c #262F49", +"}$ c #6876A1", +"|$ c #ABB7E6", +"1$ c #8792BF", +"2$ c #545D7F", +"3$ c #3D4257", +"4$ c #404352", +"5$ c #67708B", +"6$ c #819AE3", +"7$ c #8796C2", +"8$ c #525970", +"9$ c #3D414C", +"0$ c #373C4D", +"a$ c #404C6D", +"b$ c #556BA5", +"c$ c #536DB0", +"d$ c #5874BB", +"e$ c #5770B2", +"f$ c #344164", +"g$ c #3C486C", +"h$ c #515878", +"i$ c #313545", +"j$ c #5E617B", +"k$ c #2B334C", +"l$ c #48506F", +"m$ c #A8ADDC", +"n$ c #8492D1", +"o$ c #252A3B", +"p$ c #2B3048", +"q$ c #636C93", +"r$ c #919AC9", +"s$ c #8792BE", +"t$ c #51576E", +"u$ c #575B6C", +"v$ c #5E5F69", +"w$ c #6F7BA2", +"x$ c #7187CC", +"y$ c #6377B4", +"z$ c #6F80AC", +"A$ c #5B6581", +"B$ c #4B5169", +"C$ c #535E7E", +"D$ c #6373A1", +"E$ c #566796", +"F$ c #3D4866", +"G$ c #38476D", +"H$ c #37476F", +"I$ c #323646", +"J$ c #394059", +"K$ c #545971", +"L$ c #202128", +"M$ c #656FA5", +"N$ c #2A3A6B", +"O$ c #565F84", +"P$ c #9297CD", +"Q$ c #7579A1", +"R$ c #414B72", +"S$ c #37405F", +"T$ c #525D80", +"U$ c #70779D", +"V$ c #8993C2", +"W$ c #686F8E", +"X$ c #525563", +"Y$ c #4D4E58", +"Z$ c #454A5E", +"`$ c #68759C", +" % c #52649C", +".% c #4F64A0", +"+% c #3A4872", +"@% c #2A324C", +"#% c #1D212D", +"$% c #21232C", +"%% c #3A3C47", +"&% c #303444", +"*% c #191B1E", +"=% c #34394B", +"-% c #404764", +";% c #484B5E", +">% c #8596DE", +",% c #6681CC", +"'% c #2D3855", +")% c #424E77", +"!% c #8388B9", +"~% c #7C83B8", +"{% c #383E58", +"]% c #404969", +"^% c #434A63", +"/% c #5C6485", +"(% c #717AA6", +"_% c #666E95", +":% c #4A4C56", +"<% c #656B7F", +"[% c #606A84", +"}% c #3B4159", +"|% c #323B56", +"1% c #3C4B76", +"2% c #44578F", +"3% c #3C4D7E", +"4% c #364570", +"5% c #303C61", +"6% c #2E364D", +"7% c #323546", +"8% c #444A66", +"9% c #404A66", +"0% c #8399CC", +"a% c #6E819E", +"b% c #3E507C", +"c% c #344169", +"d% c #6A79B5", +"e% c #7376A1", +"f% c #565C7B", +"g% c #434D69", +"h% c #4F597A", +"i% c #49506B", +"j% c #5B6381", +"k% c #5B678F", +"l% c #454B66", +"m% c #40465A", +"n% c #474E69", +"o% c #5A688F", +"p% c #4D5261", +"q% c #282A2F", +"r% c #24293C", +"s% c #333D59", +"t% c #303C5F", +"u% c #2D2F3B", +"v% c #373D54", +"w% c #3C4057", +"x% c #3F5083", +"y% c #849ABA", +"z% c #334373", +"A% c #344578", +"B% c #525D8F", +"C% c #686E9B", +"D% c #5B6282", +"E% c #424A67", +"F% c #4D5B81", +"G% c #444D65", +"H% c #5B668C", +"I% c #58638C", +"J% c #465074", +"K% c #414B6E", +"L% c #2F364B", +"M% c #252830", +"N% c #3F4046", +"O% c #343740", +"P% c #191A1E", +"Q% c #1A1B21", +"R% c #373E59", +"S% c #3F4154", +"T% c #3C3D50", +"U% c #262C3D", +"V% c #495672", +"W% c #6477A2", +"X% c #3D4D7A", +"Y% c #33426E", +"Z% c #363F5F", +"`% c #4B5171", +" & c #525875", +".& c #4F5774", +"+& c #444C68", +"@& c #353E5D", +"#& c #49506E", +"$& c #454A64", +"%& c #414864", +"&& c #383F57", +"*& c #495372", +"=& c #292D3B", +"-& c #3B3D49", +";& c #1F2128", +">& c #363C51", +",& c #222736", +"'& c #1D212F", +")& c #272A36", +"!& c #2B3146", +"~& c #2F364E", +"{& c #383B4E", +"]& c #3F496A", +"^& c #303751", +"/& c #3A3E55", +"(& c #3C3E52", +"_& c #3A4059", +":& c #394260", +"<& c #2C334A", +"[& c #383F56", +"}& c #383D51", +"|& c #353A4C", +"1& c #32384C", +"2& c #31374B", +"3& c #333950", +"4& c #282E41", +"5& c #202431", +"6& c #1A1B1F", +"7& c #262B37", +"8& c #282C3D", +"9& c #303547", +"0& c #393D53", +"a& c #32384E", +"b& c #343B54", +"c& c #292C38", +"d& c #2F3242", +"e& c #2C303F", +"f& c #2C2F3C", +"g& c #252832", +"h& c #2D313E", +"i& c #262935", +"j& c #2A2E3C", +"k& c #21242F", +"l& c #20242E", +"m& c #222429", +"n& c #262A3B", +"o& c #1A1C22", +"p& c #282C3B", +"q& c #30364C", +"r& c #333A54", +"s& c #2A3044", +"t& c #272A37", +"u& c #292E3F", +"v& c #2A2F42", +"w& c #272D3F", +"x& c #1E212A", +"y& c #1B1C1F", +"z& c #1C1E21", +"A& c #1D1F22", +"B& c #22242D", +"C& c #232631", +"D& c #222734", +"E& c #1C1D23", +"F& c #1E1F22", +"G& c #1C1D21", +" . + @ # $ % & * ", +" = - ; > , ' ) ! ~ { ] ^ / ( ", +" _ : < [ } | 1 2 3 4 5 6 7 8 9 0 ", +" a b c d e f g h i j k l m n o p q r s t ", +" u u v w x y z A B C D E F G H I J K u u u u u ", +" L u M N O P Q R S T U V W u u u u u X Y Z ` ... ", +" +.@.u #.$.%.&.*.=.-.;.>.,.'.u ).!.~.{.].^./.(._.:.<. ", +" [.}.u |.1.2.3.4.5.6.7.8.9.0.u a.b.c.d.e.f.g.h.i.j.k. ", +" l.m.n.u o.p.q.r.s.t.u.v.w.x.y.u z.A.B.6 C.D.E.F.G.H.I.0 ", +" J.K.L.M.u N.O.P.Q.R.S.T.U.V.W.X.u Y.Z.`. +.+++@+#+$+%+&+*+=+ ", +" -+;+>+,+u '+)+!+~+{+]+^+/+(+_+:+u <+[+}+|+1+2+3+4+5+6+7+8+9+ ", +" 0+a+b+c+u d+e+f+g+h+i+j+k+l+m+n+u o+p+q+r+s+t+u+v+w+x+y+z+A+ ", +"B+C+D+E+F+u G+H+I+J+K+L+M+N+O+P+Q+u R+S+T+U+V+W+X+Y+Z+`+ @.@+@@@", +"#@$@%@&@*@u =@-@;@>@,@'@)@!@~@{@]@u ^@/@(@_@:@<@[@}@|@1@2@3@4@5@", +"6@7@8@9@0@u a@b@c@d@e@f@g@h@i@j@k@u l@m@n@o@p@q@r@s@t@u@v@w@x@y@", +"z@A@B@C@D@u E@F@G@H@I@J@K@L@M@N@O@u u u u u u u u u u u u u P@Q@", +"R@S@T@U@V@u W@X@Y@Z@`@ #.#+#@###$#%#u &#*#=#-#;#>#,#'#)#!#~#{#]#", +"^#/#(#_#:#u <#[#}#|#1#2#3#4#5#6#7#8#u 9#0#a#b#c#d#e#f#g#h#i#j#k#", +"l#m#n#o#p#u q#r#s#t#u#v#w#x#y#z#A#B#u C#D#E#F#G#H#I#J#K#L#M#N#O#", +"P#Q#R#S#T#u U#V#W#X#Y#Z#`# $.$+$@$#$u $$%$&$*$=$-$;$>$,$'$)$!$~$", +" {$]$^$/$u ($_$:$<$[$}$|$1$2$3$4$5$u 6$7$8$M.9$0$a$b$c$d$e$f$ ", +" g$h$i$j$u k$l$m$n$o$p$q$r$s$t$u$v$u w$x$y$z$A$B$C$D$E$F$G$H$ ", +" I$J$K$L$u M$N$O$P$Q$R$S$T$U$V$W$X$u Y$Z$`$ %.%+%@%#%$%%%&%*% ", +" =%-%;%u >%,%'%)%!%~%{%]%^%/%(%_%u :%<%[%}%|%1%2%3%4%5%6% ", +" 7%8%u 9%0%a%b%c%d%e%f%g%h%i%j%u k%l%m%n%o%p%q%r%s%t% ", +" u%v%u w%x%y%A.z%A%B%C%D%E%F%G%u H%I%J%K%L%M%N%O%P%Q% ", +" u R%S%T%U%V%W%X%Y%Z%`% &.&+&u u u u u u u u u u ", +" u u u u u u u u u u u @&#&$&%&&&*&=&-&;&>&,&'& ", +" )&!&~&{&]&^&/&(&_&:&<&[&}&|&1&2&3&4&5&6& ", +" 7&8&9&0&a&b&c&d&e&f&g&h&i&j&k&l& ", +" m&n&o&p&c&q&r&s&t&u&v&w&x&y& ", +" z&A&B&C&D&E&F&G& "}; diff --git a/debian/rdlogin.desktop b/debian/rdlogin.desktop new file mode 100644 index 00000000..5d042562 --- /dev/null +++ b/debian/rdlogin.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=rdlogin +Comment=Rivendell Login Utility +Exec=rdlogin +Terminal=false +Type=Application +Icon=/usr/share/srlabs/rdlogin.xpm +Categories=Application;AudioVideo; diff --git a/debian/rdlogin.xpm b/debian/rdlogin.xpm new file mode 100644 index 00000000..f142fbc1 --- /dev/null +++ b/debian/rdlogin.xpm @@ -0,0 +1,715 @@ +/* XPM */ +static char * rdlogin_xpm[] = { +"32 32 680 2", +" c None", +". c #3D485E", +"+ c #3D485F", +"@ c #364156", +"# c #3B475D", +"$ c #414F69", +"% c #37435A", +"& c #36425B", +"* c #3B4A68", +"= c #2F3645", +"- c #4B5871", +"; c #505D74", +"> c #4D586E", +", c #454F62", +"' c #606E88", +") c #5B6985", +"! c #414D64", +"~ c #536280", +"{ c #4E5F81", +"] c #3F4E69", +"^ c #435478", +"/ c #384868", +"( c #2E384D", +"_ c #424D5E", +": c #576375", +"< c #57606E", +"[ c #525B6A", +"} c #778192", +"| c #3B414B", +"1 c #8A98A8", +"2 c #404753", +"3 c #758398", +"4 c #4B5669", +"5 c #58667F", +"6 c #51607E", +"7 c #404D68", +"8 c #47587A", +"9 c #394868", +"0 c #364566", +"a c #30353E", +"b c #485468", +"c c #677281", +"d c #484F5D", +"e c #8F96A5", +"f c #3D414E", +"g c #A1A6B3", +"h c #4D5363", +"i c #8992A1", +"j c #686E79", +"k c #545E70", +"l c #8494A9", +"m c #3C4454", +"n c #586581", +"o c #6478A1", +"p c #3D4964", +"q c #46587D", +"r c #4A5D87", +"s c #323E5C", +"t c #354464", +"u c #23262D", +"v c #636F7E", +"w c #404551", +"x c #E11313", +"y c #222531", +"z c #C7C8CD", +"A c #393C48", +"B c #A3A6B3", +"C c #7A7D86", +"D c #404557", +"E c #BEC3D0", +"F c #535768", +"G c #434B5E", +"H c #8FA0B8", +"I c #5E6983", +"J c #3D465C", +"K c #6A7EA7", +"L c #506285", +"M c #45567B", +"N c #445983", +"O c #3A4A70", +"P c #293246", +"Q c #404B5C", +"R c #48505C", +"S c #6F7A88", +"T c #636570", +"U c #20222B", +"V c #DBDDE2", +"W c #50535F", +"X c #6C6E76", +"Y c #D1D3DC", +"Z c #2A2E3F", +"` c #505564", +" . c #C4C9D3", +".. c #5C6374", +"+. c #353A44", +"@. c #8092AC", +"#. c #7283A0", +"$. c #3B4359", +"%. c #3F4C67", +"&. c #5B72A2", +"*. c #425379", +"=. c #3E4C6F", +"-. c #3C4F7A", +";. c #374668", +">. c #2A2E35", +",. c #54627A", +"'. c #9299A1", +"). c #3C404D", +"!. c #878996", +"~. c #373E55", +"{. c #CCCDD6", +"]. c #767989", +"^. c #3C435E", +"/. c #A8AAB4", +"(. c #A8AAB8", +"_. c #363B4E", +":. c #565A68", +"<. c #C2CEDA", +"[. c #76829B", +"}. c #353E56", +"|. c #54617C", +"1. c #86A2D2", +"2. c #5E6F96", +"3. c #4A557A", +"4. c #45567D", +"5. c #5975B2", +"6. c #3E4E75", +"7. c #3A4362", +"8. c #202023", +"9. c #627183", +"0. c #394152", +"a. c #B8BBC3", +"b. c #2A2D39", +"c. c #848591", +"d. c #1C202C", +"e. c #A2A8BE", +"f. c #C9CAD3", +"g. c #212431", +"h. c #4D5164", +"i. c #D7D7DB", +"j. c #8B8C95", +"k. c #36384A", +"l. c #4D5160", +"m. c #AEBFD0", +"n. c #8495AC", +"o. c #5572B5", +"p. c #2F3D5B", +"q. c #47566D", +"r. c #7D8C9E", +"s. c #33343A", +"t. c #C6C7CF", +"u. c #242A3A", +"v. c #6E7792", +"w. c #CFD1D8", +"x. c #494C57", +"y. c #DFE0E3", +"z. c #8C8E9C", +"A. c #22242C", +"B. c #616471", +"C. c #DDDEE2", +"D. c #838692", +"E. c #404357", +"F. c #4D6399", +"G. c #363F4B", +"H. c #4B596D", +"I. c #8492A4", +"J. c #363A46", +"K. c #CFD0D4", +"L. c #3F4C6D", +"M. c #3C4256", +"N. c #ECEEF5", +"O. c #555B77", +"P. c #8E909D", +"Q. c #DCDCE3", +"R. c #717385", +"S. c #24252D", +"T. c #616472", +"U. c #E8EBF3", +"V. c #A0A9BC", +"W. c #96B6E9", +"X. c #647AA9", +"Y. c #293044", +"Z. c #46506E", +"`. c #313A54", +" + c #1F242E", +".+ c #222326", +"++ c #657B92", +"@+ c #3C4558", +"#+ c #919FB2", +"$+ c #262C3C", +"%+ c #BEC1CA", +"&+ c #676C7D", +"*+ c #384467", +"=+ c #ADADB5", +"-+ c #2A2D3A", +";+ c #3D4253", +">+ c #C5C6CD", +",+ c #D6D6DF", +"'+ c #53586E", +")+ c #34384B", +"!+ c #4E5365", +"~+ c #C1D2E5", +"{+ c #212331", +"]+ c #3F486A", +"^+ c #7E9BD4", +"/+ c #84AAEF", +"(+ c #5A70A8", +"_+ c #273147", +":+ c #6F8398", +"<+ c #333841", +"[+ c #A0ABB5", +"}+ c #283454", +"|+ c #99A1B7", +"1+ c #A8AFBF", +"2+ c #21283B", +"3+ c #878EA8", +"4+ c #71778C", +"5+ c #2D344D", +"6+ c #4C4E5D", +"7+ c #D4D8E4", +"8+ c #BDC0CB", +"9+ c #41465B", +"0+ c #454E73", +"a+ c #6876A0", +"b+ c #353B57", +"c+ c #272C3C", +"d+ c #3E4C6D", +"e+ c #7DA2EA", +"f+ c #6487CB", +"g+ c #5170A4", +"h+ c #4C4E51", +"i+ c #8096AC", +"j+ c #2C323F", +"k+ c #B7C4D0", +"l+ c #3C4A6C", +"m+ c #4C5773", +"n+ c #DCDCE1", +"o+ c #5D6A8F", +"p+ c #242D47", +"q+ c #575D70", +"r+ c #3F4A70", +"s+ c #404456", +"t+ c #DFE5F3", +"u+ c #D5E0F0", +"v+ c #3D4453", +"w+ c #67799B", +"x+ c #9EC0F4", +"y+ c #6D87B6", +"z+ c #62709E", +"A+ c #555F8A", +"B+ c #343A4F", +"C+ c #445072", +"D+ c #333C52", +"E+ c #44494F", +"F+ c #7C95A3", +"G+ c #262E3D", +"H+ c #A0A9B1", +"I+ c #5E6980", +"J+ c #324576", +"K+ c #C8CAD2", +"L+ c #9BA3B7", +"M+ c #2E3445", +"N+ c #4F5978", +"O+ c #CAD0E2", +"P+ c #2B3142", +"Q+ c #455681", +"R+ c #565E72", +"S+ c #BFCFD9", +"T+ c #B6CCE5", +"U+ c #56638D", +"V+ c #6A7EAB", +"W+ c #7B9DD7", +"X+ c #7DA1E1", +"Y+ c #475A80", +"Z+ c #434C67", +"`+ c #7BA5EB", +" @ c #4B5C7B", +".@ c #1E2026", +"+@ c #444D55", +"@@ c #79868D", +"#@ c #4B5259", +"$@ c #6B7786", +"%@ c #B1C0D7", +"&@ c #2B334A", +"*@ c #788AAD", +"=@ c #EBEDF2", +"-@ c #66779C", +";@ c #242C39", +">@ c #D9DCE2", +",@ c #C2CEE3", +"'@ c #464F63", +")@ c #374458", +"!@ c #546173", +"~@ c #97ADC6", +"{@ c #323A4F", +"]@ c #383F4C", +"^@ c #515D77", +"/@ c #6E8CBE", +"(@ c #729BE0", +"_@ c #2D374D", +":@ c #55729B", +"<@ c #A9CAD7", +"[@ c #677A89", +"}@ c #465159", +"|@ c #616D7B", +"1@ c #88909B", +"2@ c #2F3747", +"3@ c #CCD7DF", +"4@ c #525C70", +"5@ c #4F638E", +"6@ c #B3B5BA", +"7@ c #BDC0C7", +"8@ c #506A96", +"9@ c #6C80A8", +"0@ c #DFEDF4", +"a@ c #A6BBCB", +"b@ c #374869", +"c@ c #232A39", +"d@ c #526286", +"e@ c #7199CA", +"f@ c #7D9DC6", +"g@ c #5C71A3", +"h@ c #424E66", +"i@ c #576478", +"j@ c #5A6B87", +"k@ c #414954", +"l@ c #4F5E73", +"m@ c #B0BCC5", +"n@ c #363F4C", +"o@ c #BBCDE3", +"p@ c #D3E3F0", +"q@ c #2A3242", +"r@ c #51648B", +"s@ c #DEE0E4", +"t@ c #B7BEC8", +"u@ c #374871", +"v@ c #62728D", +"w@ c #C5E2F2", +"x@ c #A2BCD1", +"y@ c #596B91", +"z@ c #272C38", +"A@ c #484F64", +"B@ c #354258", +"C@ c #89AABE", +"D@ c #CCE9F5", +"E@ c #92B3C9", +"F@ c #4D5E76", +"G@ c #242935", +"H@ c #17181C", +"I@ c #4B556B", +"J@ c #515F72", +"K@ c #89939D", +"L@ c #6A7B8E", +"M@ c #6B7C8D", +"N@ c #D8DBE0", +"O@ c #5A6682", +"P@ c #2C3D64", +"Q@ c #778195", +"R@ c #EAF0F8", +"S@ c #252B3F", +"T@ c #42568E", +"U@ c #56667D", +"V@ c #D9F3FC", +"W@ c #BED0D8", +"X@ c #6F7586", +"Y@ c #30333F", +"Z@ c #515667", +"`@ c #6B7794", +" # c #88A5B6", +".# c #C5E7F6", +"+# c #5D6D8D", +"@# c #677BA9", +"## c #6C82AE", +"$# c #97B5D5", +"%# c #A2C5E9", +"&# c #8DB5F4", +"*# c #6B87C8", +"=# c #3A4665", +"-# c #3F4862", +";# c #545D78", +"># c #4C5569", +",# c #9DADC8", +"'# c #2B3A58", +")# c #798AAF", +"!# c #D4DEF0", +"~# c #454D5E", +"{# c #374D81", +"]# c #6D778D", +"^# c #9FAFCF", +"/# c #29324C", +"(# c #435283", +"_# c #4D5566", +":# c #B2C3D0", +"<# c #CAE4F1", +"[# c #A3B5CB", +"}# c #4F5464", +"|# c #43454F", +"1# c #656975", +"2# c #69768D", +"3# c #85A2BF", +"4# c #9EC5F4", +"5# c #7694C8", +"6# c #3E4B6B", +"7# c #252A37", +"8# c #1E2028", +"9# c #16171C", +"0# c #1F2229", +"a# c #384564", +"b# c #343D54", +"c# c #3A4158", +"d# c #616D94", +"e# c #333E5F", +"f# c #868EAA", +"g# c #49567A", +"h# c #2A3F72", +"i# c #A6AEBF", +"j# c #999EB2", +"k# c #435A8F", +"l# c #333D5B", +"m# c #D0DFF5", +"n# c #7B88AC", +"o# c #353E5B", +"p# c #454F6E", +"q# c #464E62", +"r# c #A4B8D4", +"s# c #A9C6F3", +"t# c #8599C5", +"u# c #676F88", +"v# c #40424B", +"w# c #7F89A4", +"x# c #97ABD1", +"y# c #7A98DC", +"z# c #7293E3", +"A# c #5F7ABB", +"B# c #627BB1", +"C# c #586988", +"D# c #2B2F3B", +"E# c #16171B", +"F# c #18191C", +"G# c #36405E", +"H# c #5A6896", +"I# c #2D3244", +"J# c #909ACA", +"K# c #3D5189", +"L# c #475070", +"M# c #ADB5E0", +"N# c #7D87B1", +"O# c #374D8F", +"P# c #6876A1", +"Q# c #ABB7E6", +"R# c #8792BF", +"S# c #545D7F", +"T# c #3D4257", +"U# c #404352", +"V# c #67708B", +"W# c #879BDB", +"X# c #819AE3", +"Y# c #8796C2", +"Z# c #525970", +"`# c #3D414C", +" $ c #373C4D", +".$ c #404C6D", +"+$ c #556BA5", +"@$ c #536DB0", +"#$ c #5874BB", +"$$ c #5770B2", +"%$ c #344164", +"&$ c #3C486C", +"*$ c #515878", +"=$ c #313545", +"-$ c #5E617B", +";$ c #7E89B8", +">$ c #2B334C", +",$ c #48506F", +"'$ c #A8ADDC", +")$ c #8492D1", +"!$ c #2B3048", +"~$ c #636C93", +"{$ c #919AC9", +"]$ c #8792BE", +"^$ c #51576E", +"/$ c #575B6C", +"($ c #5E5F69", +"_$ c #565B6C", +":$ c #6F7BA2", +"<$ c #7187CC", +"[$ c #6377B4", +"}$ c #6F80AC", +"|$ c #5B6581", +"1$ c #4B5169", +"2$ c #535E7E", +"3$ c #6373A1", +"4$ c #566796", +"5$ c #3D4866", +"6$ c #38476D", +"7$ c #37476F", +"8$ c #323646", +"9$ c #394059", +"0$ c #545971", +"a$ c #202128", +"b$ c #696B8C", +"c$ c #656FA5", +"d$ c #2A3A6B", +"e$ c #565F84", +"f$ c #7579A1", +"g$ c #414B72", +"h$ c #37405F", +"i$ c #525D80", +"j$ c #70779D", +"k$ c #8993C2", +"l$ c #686F8E", +"m$ c #525563", +"n$ c #525462", +"o$ c #4D4E58", +"p$ c #454A5E", +"q$ c #68759C", +"r$ c #52649C", +"s$ c #4F64A0", +"t$ c #3A4872", +"u$ c #2A324C", +"v$ c #1D212D", +"w$ c #21232C", +"x$ c #3A3C47", +"y$ c #303444", +"z$ c #191B1E", +"A$ c #34394B", +"B$ c #404764", +"C$ c #484B5E", +"D$ c #242632", +"E$ c #8596DE", +"F$ c #6681CC", +"G$ c #2D3855", +"H$ c #8388B9", +"I$ c #7C83B8", +"J$ c #383E58", +"K$ c #404969", +"L$ c #434A63", +"M$ c #5C6485", +"N$ c #717AA6", +"O$ c #666E95", +"P$ c #5A5F76", +"Q$ c #4A4C56", +"R$ c #656B7F", +"S$ c #606A84", +"T$ c #3B4159", +"U$ c #323B56", +"V$ c #3C4B76", +"W$ c #44578F", +"X$ c #3C4D7E", +"Y$ c #364570", +"Z$ c #303C61", +"`$ c #2E364D", +" % c #323546", +".% c #444A66", +"+% c #3D3F4F", +"@% c #404A66", +"#% c #8399CC", +"$% c #6E819E", +"%% c #2D2F3B", +"&% c #373D54", +"*% c #474A5F", +"=% c #3C4057", +"-% c #3F5083", +";% c #849ABA", +">% c #5B6282", +",% c #424A67", +"'% c #4D5B81", +")% c #444D65", +"!% c #434B68", +"~% c #5B668C", +"{% c #58638C", +"]% c #465074", +"^% c #414B6E", +"/% c #2F364B", +"(% c #252830", +"_% c #3F4046", +":% c #343740", +"<% c #191A1E", +"[% c #1A1B21", +"}% c #2D303E", +"|% c #373E59", +"1% c #3F4154", +"2% c #3C3D50", +"3% c #262C3D", +"4% c #495672", +"5% c #6477A2", +"6% c #3D4D7A", +"7% c #33426E", +"8% c #363F5F", +"9% c #4B5171", +"0% c #525875", +"a% c #4F5774", +"b% c #444C68", +"c% c #485375", +"d% c #3E455E", +"e% c #454F70", +"f% c #56638A", +"g% c #383F57", +"h% c #313A57", +"i% c #3D496E", +"j% c #323D60", +"k% c #364265", +"l% c #222736", +"m% c #2C2F3D", +"n% c #31374C", +"o% c #33374A", +"p% c #3A3C4D", +"q% c #1D1F26", +"r% c #303850", +"s% c #4E5B8D", +"t% c #43496D", +"u% c #344068", +"v% c #3B466A", +"w% c #353E5D", +"x% c #49506E", +"y% c #454A64", +"z% c #414864", +"A% c #495372", +"B% c #292D3B", +"C% c #3B3D49", +"D% c #1F2128", +"E% c #363C51", +"F% c #1D212F", +"G% c #272A36", +"H% c #2B3146", +"I% c #2F364E", +"J% c #383B4E", +"K% c #3F496A", +"L% c #303751", +"M% c #3A3E55", +"N% c #3C3E52", +"O% c #3A4059", +"P% c #394260", +"Q% c #2C334A", +"R% c #383F56", +"S% c #383D51", +"T% c #353A4C", +"U% c #32384C", +"V% c #31374B", +"W% c #333950", +"X% c #282E41", +"Y% c #202431", +"Z% c #1A1B1F", +"`% c #262B37", +" & c #282C3D", +".& c #303547", +"+& c #393D53", +"@& c #32384E", +"#& c #343B54", +"$& c #292C38", +"%& c #2F3242", +"&& c #2C303F", +"*& c #2C2F3C", +"=& c #252832", +"-& c #2D313E", +";& c #262935", +">& c #2A2E3C", +",& c #21242F", +"'& c #20242E", +")& c #222429", +"!& c #262A3B", +"~& c #1A1C22", +"{& c #282C3B", +"]& c #30364C", +"^& c #333A54", +"/& c #2A3044", +"(& c #272A37", +"_& c #292E3F", +":& c #2A2F42", +"<& c #272D3F", +"[& c #1E212A", +"}& c #1B1C1F", +"|& c #1C1E21", +"1& c #1D1F22", +"2& c #22242D", +"3& c #232631", +"4& c #222734", +"5& c #1C1D23", +"6& c #1E1F22", +"7& c #1C1D21", +" . + @ # $ % & * ", +" = - ; > , ' ) ! ~ { ] ^ / ( ", +" _ : < [ } | 1 2 3 4 5 6 7 8 9 0 ", +" a b c d e f g h i j k l m n o p q r s t ", +" u v w x y z A B C D E F G H I J K L M N O P ", +" Q R S T x U V W X Y Z ` ...+.@.#.$.%.&.*.=.-.;. ", +" >.,.'.).!.x ~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.7.8. ", +" 9.0.a.b.c.x d.e.f.g.h.i.j.k.l.m.n.x x x x x x x o.p. ", +" q.r.s.t.u.v.w.x x.y.z.A.B.C.D.E.x x x x x x x x x x F.0 ", +" G.H.I.J.K.L.M.N.x O.P.Q.R.S.T.U.V.x x x W.X.Y.Z.x x x `. +.+ ", +" ++@+#+$+%+&+*+=+x -+;+>+,+'+)+!+~+x x {+]+^+/+(+x x x x x _+ ", +" :+<+[+}+|+1+2+3+x 4+5+6+7+8+9+0+x x x a+b+c+d+e+f+x x x x g+ ", +"h+i+j+k+l+m+n+o+p+x x q+r+s+t+u+v+x x w+x+y+z+A+B+x x x x x C+D+", +"E+F+G+H+I+J+K+L+M+N+x O+P+Q+R+S+T+x x U+V+W+X+Y+Z+x x x x `+ @.@", +"+@@@#@$@%@&@*@=@-@;@x >@,@'@)@!@~@x x {@]@^@/@(@x x x x _@:@<@[@", +"}@|@1@2@3@4@5@6@7@8@x 9@0@a@b@c@d@x x x x x x x x x e@f@g@h@i@j@", +"k@l@m@n@o@p@q@r@s@t@x u@v@w@x@y@z@A@x x x x x x x B@C@D@E@F@G@H@", +"I@J@K@L@M@N@O@P@Q@R@x S@T@U@V@W@X@Y@Z@`@ #.#x x +#@###$#%#&#*#=#", +"-#;#>#,#'#)#!#~#{#]#x ^#/#(#_#:#<#[#}#|#1#2#3#4#5#6#7#8#9#0#a#b#", +"c#d#e#f#g#h#i#j#k#l#x m#n#o#p#q#r#s#t#u#v#l.w#x#y#z#A#B#C#D#E#F#", +" G#H#I#J#K#L#M#N#O#x P#Q#R#S#T#U#V#W#X#Y#Z#J.`# $.$+$@$#$$$%$ ", +" &$*$=$-$;$>$,$'$)$x !$~${$]$^$/$($_$:$<$[$}$|$1$2$3$4$5$6$7$ ", +" 8$9$0$a$b$c$d$e$x f$g$h$i$j$k$l$m$n$o$p$q$r$s$t$u$v$w$x$y$z$ ", +" A$B$C$D$E$F$G$x H$I$J$K$L$M$N$O$P$Q$R$S$T$U$V$W$X$Y$Z$`$ ", +" %.%+%@%#%$%x x x x x x x x x x x x x x x x x x x x ", +" %%&%*%=%-%;%x x x x x >%,%'%)%!%~%{%]%^%/%(%_%:%<%[% ", +" }%|%1%2%3%4%5%6%7%8%9%0%a%b%c%d%e%f%g%h%i%j%k%l% ", +" m%n%o%p%q%r%s%t%u%v%w%x%y%z%g%A%B%C%D%E%l%F% ", +" G%H%I%J%K%L%M%N%O%P%Q%R%S%T%U%V%W%X%Y%Z% ", +" `% &.&+&@&#&$&%&&&*&=&-&;&>&,&'& ", +" )&!&~&{&$&]&^&/&(&_&:&<&[&}& ", +" |&1&2&3&4&5&6&7& "}; diff --git a/debian/rdlogmanager.desktop b/debian/rdlogmanager.desktop new file mode 100644 index 00000000..f1252615 --- /dev/null +++ b/debian/rdlogmanager.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=rdlogmanager +Comment=Rivendell Log Manager +Exec=rdlogmanager +Terminal=false +Type=Application +Icon=/usr/share/srlabs/rdlogmanager.xpm +Categories=Application;AudioVideo; diff --git a/debian/rdlogmanager.xpm b/debian/rdlogmanager.xpm new file mode 100644 index 00000000..2ac56328 --- /dev/null +++ b/debian/rdlogmanager.xpm @@ -0,0 +1,745 @@ +/* XPM */ +static char * rdlogmanager_xpm[] = { +"32 32 710 2", +" c None", +". c #3D485E", +"+ c #3D485F", +"@ c #364156", +"# c #3B475D", +"$ c #414F69", +"% c #37435A", +"& c #36425B", +"* c #3B4A68", +"= c #2F3645", +"- c #4B5871", +"; c #505D74", +"> c #4D586E", +", c #454F62", +"' c #606E88", +") c #5B6985", +"! c #414D64", +"~ c #536280", +"{ c #4E5F81", +"] c #3F4E69", +"^ c #435478", +"/ c #384868", +"( c #2E384D", +"_ c #424D5E", +": c #576375", +"< c #57606E", +"[ c #525B6A", +"} c #778192", +"| c #3B414B", +"1 c #8A98A8", +"2 c #404753", +"3 c #758398", +"4 c #4B5669", +"5 c #58667F", +"6 c #51607E", +"7 c #404D68", +"8 c #47587A", +"9 c #394868", +"0 c #364566", +"a c #30353E", +"b c #485468", +"c c #677281", +"d c #484F5D", +"e c #8F96A5", +"f c #3D414E", +"g c #A1A6B3", +"h c #4D5363", +"i c #8992A1", +"j c #686E79", +"k c #545E70", +"l c #8494A9", +"m c #3C4454", +"n c #586581", +"o c #6478A1", +"p c #3D4964", +"q c #46587D", +"r c #4A5D87", +"s c #323E5C", +"t c #354464", +"u c #23262D", +"v c #E11313", +"w c #404551", +"x c #9BA1A7", +"y c #222531", +"z c #C7C8CD", +"A c #393C48", +"B c #A3A6B3", +"C c #7A7D86", +"D c #404557", +"E c #BEC3D0", +"F c #535768", +"G c #434B5E", +"H c #8FA0B8", +"I c #5E6983", +"J c #3D465C", +"K c #6A7EA7", +"L c #506285", +"M c #45567B", +"N c #445983", +"O c #3A4A70", +"P c #293246", +"Q c #404B5C", +"R c #48505C", +"S c #636570", +"T c #888A94", +"U c #20222B", +"V c #DBDDE2", +"W c #50535F", +"X c #6C6E76", +"Y c #D1D3DC", +"Z c #2A2E3F", +"` c #505564", +" . c #C4C9D3", +".. c #5C6374", +"+. c #353A44", +"@. c #8092AC", +"#. c #7283A0", +"$. c #3B4359", +"%. c #3F4C67", +"&. c #5B72A2", +"*. c #425379", +"=. c #3E4C6F", +"-. c #3C4F7A", +";. c #374668", +">. c #2A2E35", +",. c #54627A", +"'. c #9299A1", +"). c #878996", +"!. c #878A99", +"~. c #373E55", +"{. c #CCCDD6", +"]. c #767989", +"^. c #3C435E", +"/. c #A8AAB4", +"(. c #A8AAB8", +"_. c #363B4E", +":. c #565A68", +"<. c #C2CEDA", +"[. c #76829B", +"}. c #353E56", +"|. c #54617C", +"1. c #86A2D2", +"2. c #5E6F96", +"3. c #4A557A", +"4. c #45567D", +"5. c #5975B2", +"6. c #3E4E75", +"7. c #3A4362", +"8. c #202023", +"9. c #627183", +"0. c #394152", +"a. c #B8BBC3", +"b. c #848591", +"c. c #A0A3B3", +"d. c #1C202C", +"e. c #A2A8BE", +"f. c #C9CAD3", +"g. c #212431", +"h. c #4D5164", +"i. c #D7D7DB", +"j. c #8B8C95", +"k. c #36384A", +"l. c #4D5160", +"m. c #424C72", +"n. c #3B4560", +"o. c #5F749D", +"p. c #6A86B9", +"q. c #526288", +"r. c #5F6D9F", +"s. c #415582", +"t. c #47566D", +"u. c #7D8C9E", +"v. c #33343A", +"w. c #C6C7CF", +"x. c #6E7792", +"y. c #CFD1D8", +"z. c #424A62", +"A. c #494C57", +"B. c #DFE0E3", +"C. c #8C8E9C", +"D. c #22242C", +"E. c #616471", +"F. c #DDDEE2", +"G. c #838692", +"H. c #404357", +"I. c #8293AB", +"J. c #444C73", +"K. c #4A5579", +"L. c #607DB6", +"M. c #5977B2", +"N. c #333E59", +"O. c #363F4B", +"P. c #4B596D", +"Q. c #8492A4", +"R. c #363A46", +"S. c #CFD0D4", +"T. c #3C4256", +"U. c #ECEEF5", +"V. c #5F6169", +"W. c #555B77", +"X. c #8E909D", +"Y. c #DCDCE3", +"Z. c #717385", +"`. c #24252D", +" + c #616472", +".+ c #E8EBF3", +"++ c #A0A9BC", +"@+ c #424C70", +"#+ c #96B6E9", +"$+ c #647AA9", +"%+ c #293044", +"&+ c #46506E", +"*+ c #667BB3", +"=+ c #7090DC", +"-+ c #1F242E", +";+ c #222326", +">+ c #657B92", +",+ c #3C4558", +"'+ c #919FB2", +")+ c #262C3C", +"!+ c #BEC1CA", +"~+ c #384467", +"{+ c #ADADB5", +"]+ c #C9CDDC", +"^+ c #2A2D3A", +"/+ c #3D4253", +"(+ c #C5C6CD", +"_+ c #D6D6DF", +":+ c #53586E", +"<+ c #34384B", +"[+ c #4E5365", +"}+ c #C1D2E5", +"|+ c #505A79", +"1+ c #212331", +"2+ c #7E9BD4", +"3+ c #84AAEF", +"4+ c #5A70A8", +"5+ c #4B5F90", +"6+ c #5D82D2", +"7+ c #273147", +"8+ c #6F8398", +"9+ c #333841", +"0+ c #A0ABB5", +"a+ c #283454", +"b+ c #99A1B7", +"c+ c #21283B", +"d+ c #878EA8", +"e+ c #EBECF2", +"f+ c #71778C", +"g+ c #2D344D", +"h+ c #4C4E5D", +"i+ c #D4D8E4", +"j+ c #BDC0CB", +"k+ c #41465B", +"l+ c #454E73", +"m+ c #464C60", +"n+ c #A3BEDE", +"o+ c #6876A0", +"p+ c #272C3C", +"q+ c #3E4C6D", +"r+ c #7DA2EA", +"s+ c #647CAB", +"t+ c #535E85", +"u+ c #2B3550", +"v+ c #5170A4", +"w+ c #4C4E51", +"x+ c #8096AC", +"y+ c #2C323F", +"z+ c #B7C4D0", +"A+ c #3C4A6C", +"B+ c #4C5773", +"C+ c #5D6A8F", +"D+ c #242D47", +"E+ c #9A9EAD", +"F+ c #DBDBDE", +"G+ c #575D70", +"H+ c #3F4A70", +"I+ c #404456", +"J+ c #DFE5F3", +"K+ c #D5E0F0", +"L+ c #3D4453", +"M+ c #3A4568", +"N+ c #67799B", +"O+ c #9EC0F4", +"P+ c #6D87B6", +"Q+ c #555F8A", +"R+ c #3F537E", +"S+ c #668EDD", +"T+ c #597DC5", +"U+ c #303E5C", +"V+ c #445072", +"W+ c #333C52", +"X+ c #44494F", +"Y+ c #7C95A3", +"Z+ c #262E3D", +"`+ c #A0A9B1", +" @ c #5E6980", +".@ c #324576", +"+@ c #9BA3B7", +"@@ c #2E3445", +"#@ c #4F5978", +"$@ c #D8D9DE", +"%@ c #CAD0E2", +"&@ c #2B3142", +"*@ c #455681", +"=@ c #565E72", +"-@ c #BFCFD9", +";@ c #B6CCE5", +">@ c #5B698A", +",@ c #56638D", +"'@ c #6A7EAB", +")@ c #7B9DD7", +"!@ c #475A80", +"~@ c #5C6A98", +"{@ c #677BB2", +"]@ c #6685C4", +"^@ c #6791E1", +"/@ c #4B5C7B", +"(@ c #1E2026", +"_@ c #444D55", +":@ c #79868D", +"<@ c #4B5259", +"[@ c #6B7786", +"}@ c #B1C0D7", +"|@ c #2B334A", +"1@ c #EBEDF2", +"2@ c #66779C", +"3@ c #242C39", +"4@ c #7B8DAB", +"5@ c #D9DCE2", +"6@ c #C2CEE3", +"7@ c #464F63", +"8@ c #374458", +"9@ c #546173", +"0@ c #97ADC6", +"a@ c #B5D5F7", +"b@ c #323A4F", +"c@ c #383F4C", +"d@ c #515D77", +"e@ c #6E8CBE", +"f@ c #455981", +"g@ c #202530", +"h@ c #242832", +"i@ c #2D374D", +"j@ c #A9CAD7", +"k@ c #677A89", +"l@ c #465159", +"m@ c #616D7B", +"n@ c #88909B", +"o@ c #2F3747", +"p@ c #CCD7DF", +"q@ c #525C70", +"r@ c #B3B5BA", +"s@ c #BDC0C7", +"t@ c #506A96", +"u@ c #313D4E", +"v@ c #6C80A8", +"w@ c #DFEDF4", +"x@ c #A6BBCB", +"y@ c #374869", +"z@ c #232A39", +"A@ c #526286", +"B@ c #7288A8", +"C@ c #87A7CE", +"D@ c #5E7091", +"E@ c #384150", +"F@ c #282C35", +"G@ c #8DB7F3", +"H@ c #7DADF3", +"I@ c #7199CA", +"J@ c #7D9DC6", +"K@ c #5C71A3", +"L@ c #576478", +"M@ c #5A6B87", +"N@ c #414954", +"O@ c #4F5E73", +"P@ c #B0BCC5", +"Q@ c #363F4C", +"R@ c #BBCDE3", +"S@ c #D3E3F0", +"T@ c #51648B", +"U@ c #DEE0E4", +"V@ c #B7BEC8", +"W@ c #313E5E", +"X@ c #374871", +"Y@ c #62728D", +"Z@ c #C5E2F2", +"`@ c #A2BCD1", +" # c #596B91", +".# c #272C38", +"+# c #484F64", +"@# c #89ADDB", +"## c #8EBBEB", +"$# c #819FC2", +"%# c #77869D", +"&# c #454F65", +"*# c #2E3647", +"=# c #354258", +"-# c #89AABE", +";# c #CCE9F5", +"># c #92B3C9", +",# c #242935", +"'# c #17181C", +")# c #4B556B", +"!# c #515F72", +"~# c #89939D", +"{# c #6A7B8E", +"]# c #6B7C8D", +"^# c #D8DBE0", +"/# c #2C3D64", +"(# c #778195", +"_# c #EAF0F8", +":# c #8E9AB4", +"<# c #252B3F", +"[# c #42568E", +"}# c #56667D", +"|# c #D9F3FC", +"1# c #BED0D8", +"2# c #6F7586", +"3# c #30333F", +"4# c #6B7794", +"5# c #88A5B6", +"6# c #C5E7F6", +"7# c #A1B7C2", +"8# c #6E7D8C", +"9# c #5D6D8D", +"0# c #677BA9", +"a# c #6C82AE", +"b# c #97B5D5", +"c# c #A2C5E9", +"d# c #6B87C8", +"e# c #3A4665", +"f# c #3F4862", +"g# c #545D78", +"h# c #4C5569", +"i# c #9DADC8", +"j# c #2B3A58", +"k# c #798AAF", +"l# c #454D5E", +"m# c #374D81", +"n# c #6D778D", +"o# c #E6EDF2", +"p# c #9FAFCF", +"q# c #29324C", +"r# c #435283", +"s# c #4D5566", +"t# c #B2C3D0", +"u# c #CAE4F1", +"v# c #A3B5CB", +"w# c #656975", +"x# c #69768D", +"y# c #85A2BF", +"z# c #9EC5F4", +"A# c #7694C8", +"B# c #3E4B6B", +"C# c #252A37", +"D# c #1E2028", +"E# c #16171C", +"F# c #384564", +"G# c #343D54", +"H# c #3A4158", +"I# c #616D94", +"J# c #333E5F", +"K# c #868EAA", +"L# c #49567A", +"M# c #2A3F72", +"N# c #999EB2", +"O# c #435A8F", +"P# c #333D5B", +"Q# c #8690A5", +"R# c #D0DFF5", +"S# c #7B88AC", +"T# c #353E5B", +"U# c #454F6E", +"V# c #464E62", +"W# c #A4B8D4", +"X# c #A9C6F3", +"Y# c #8599C5", +"Z# c #40424B", +"`# c #7F89A4", +" $ c #97ABD1", +".$ c #7A98DC", +"+$ c #7293E3", +"@$ c #5F7ABB", +"#$ c #627BB1", +"$$ c #586988", +"%$ c #16171B", +"&$ c #18191C", +"*$ c #36405E", +"=$ c #5A6896", +"-$ c #2D3244", +";$ c #909ACA", +">$ c #3D5189", +",$ c #ADB5E0", +"'$ c #7D87B1", +")$ c #374D8F", +"!$ c #262F49", +"~$ c #6876A1", +"{$ c #ABB7E6", +"]$ c #8792BF", +"^$ c #545D7F", +"/$ c #3D4257", +"($ c #404352", +"_$ c #67708B", +":$ c #879BDB", +"<$ c #8796C2", +"[$ c #525970", +"}$ c #3D414C", +"|$ c #373C4D", +"1$ c #404C6D", +"2$ c #556BA5", +"3$ c #536DB0", +"4$ c #5874BB", +"5$ c #344164", +"6$ c #3C486C", +"7$ c #515878", +"8$ c #313545", +"9$ c #5E617B", +"0$ c #7E89B8", +"a$ c #48506F", +"b$ c #A8ADDC", +"c$ c #8492D1", +"d$ c #252A3B", +"e$ c #2B3048", +"f$ c #636C93", +"g$ c #919AC9", +"h$ c #8792BE", +"i$ c #51576E", +"j$ c #575B6C", +"k$ c #5E5F69", +"l$ c #565B6C", +"m$ c #7187CC", +"n$ c #6377B4", +"o$ c #6F80AC", +"p$ c #5B6581", +"q$ c #4B5169", +"r$ c #535E7E", +"s$ c #6373A1", +"t$ c #566796", +"u$ c #3D4866", +"v$ c #37476F", +"w$ c #323646", +"x$ c #394059", +"y$ c #545971", +"z$ c #202128", +"A$ c #696B8C", +"B$ c #2A3A6B", +"C$ c #565F84", +"D$ c #9297CD", +"E$ c #7579A1", +"F$ c #414B72", +"G$ c #37405F", +"H$ c #525D80", +"I$ c #70779D", +"J$ c #8993C2", +"K$ c #686F8E", +"L$ c #525563", +"M$ c #525462", +"N$ c #454A5E", +"O$ c #68759C", +"P$ c #52649C", +"Q$ c #4F64A0", +"R$ c #3A4872", +"S$ c #2A324C", +"T$ c #1D212D", +"U$ c #21232C", +"V$ c #3A3C47", +"W$ c #34394B", +"X$ c #404764", +"Y$ c #484B5E", +"Z$ c #242632", +"`$ c #8596DE", +" % c #2D3855", +".% c #424E77", +"+% c #8388B9", +"@% c #7C83B8", +"#% c #383E58", +"$% c #404969", +"%% c #434A63", +"&% c #5C6485", +"*% c #717AA6", +"=% c #666E95", +"-% c #5A5F76", +";% c #656B7F", +">% c #606A84", +",% c #3B4159", +"'% c #323B56", +")% c #3C4B76", +"!% c #44578F", +"~% c #3C4D7E", +"{% c #364570", +"]% c #303C61", +"^% c #2E364D", +"/% c #323546", +"(% c #444A66", +"_% c #3D3F4F", +":% c #404A66", +"<% c #6E819E", +"[% c #3E507C", +"}% c #344169", +"|% c #6A79B5", +"1% c #7376A1", +"2% c #565C7B", +"3% c #434D69", +"4% c #4F597A", +"5% c #49506B", +"6% c #5B6381", +"7% c #535C81", +"8% c #454B66", +"9% c #40465A", +"0% c #474E69", +"a% c #5A688F", +"b% c #4D5261", +"c% c #282A2F", +"d% c #24293C", +"e% c #333D59", +"f% c #303C5F", +"g% c #2D2F3B", +"h% c #373D54", +"i% c #474A5F", +"j% c #3C4057", +"k% c #849ABA", +"l% c #334373", +"m% c #344578", +"n% c #525D8F", +"o% c #686E9B", +"p% c #5B6282", +"q% c #424A67", +"r% c #4D5B81", +"s% c #444D65", +"t% c #434B68", +"u% c #58638C", +"v% c #465074", +"w% c #414B6E", +"x% c #2F364B", +"y% c #252830", +"z% c #3F4046", +"A% c #343740", +"B% c #191A1E", +"C% c #1A1B21", +"D% c #2D303E", +"E% c #373E59", +"F% c #3F4154", +"G% c #262C3D", +"H% c #495672", +"I% c #6477A2", +"J% c #3D4D7A", +"K% c #33426E", +"L% c #363F5F", +"M% c #4B5171", +"N% c #525875", +"O% c #4F5774", +"P% c #444C68", +"Q% c #485375", +"R% c #3E455E", +"S% c #454F70", +"T% c #56638A", +"U% c #383F57", +"V% c #313A57", +"W% c #3D496E", +"X% c #323D60", +"Y% c #364265", +"Z% c #222736", +"`% c #2C2F3D", +" & c #31374C", +".& c #454A64", +"+& c #414864", +"@& c #495372", +"#& c #292D3B", +"$& c #3B3D49", +"%& c #1F2128", +"&& c #363C51", +"*& c #1D212F", +"=& c #272A36", +"-& c #2B3146", +";& c #2F364E", +">& c #383B4E", +",& c #3F496A", +"'& c #303751", +")& c #3A3E55", +"!& c #3C3E52", +"~& c #3A4059", +"{& c #394260", +"]& c #2C334A", +"^& c #383F56", +"/& c #383D51", +"(& c #353A4C", +"_& c #32384C", +":& c #31374B", +"<& c #333950", +"[& c #282E41", +"}& c #202431", +"|& c #1A1B1F", +"1& c #262B37", +"2& c #282C3D", +"3& c #303547", +"4& c #393D53", +"5& c #32384E", +"6& c #343B54", +"7& c #292C38", +"8& c #2F3242", +"9& c #2C303F", +"0& c #2C2F3C", +"a& c #252832", +"b& c #2D313E", +"c& c #262935", +"d& c #2A2E3C", +"e& c #21242F", +"f& c #20242E", +"g& c #222429", +"h& c #262A3B", +"i& c #1A1C22", +"j& c #282C3B", +"k& c #30364C", +"l& c #333A54", +"m& c #2A3044", +"n& c #272A37", +"o& c #292E3F", +"p& c #2A2F42", +"q& c #272D3F", +"r& c #1E212A", +"s& c #1B1C1F", +"t& c #1C1E21", +"u& c #1D1F22", +"v& c #22242D", +"w& c #232631", +"x& c #222734", +"y& c #1C1D23", +"z& c #1E1F22", +"A& c #1C1D21", +" . + @ # $ % & * ", +" = - ; > , ' ) ! ~ { ] ^ / ( ", +" _ : < [ } | 1 2 3 4 5 6 7 8 9 0 ", +" a b c d e f g h i j k l m n o p q r s t ", +" u v w x y z A B C D E F G H I J K L M N O P ", +" Q R v S T U V W X Y Z ` ...+.@.#.$.%.&.*.=.-.;. ", +" >.,.'.v ).!.~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.7.8. ", +" 9.0.a.v b.c.d.e.f.g.h.i.j.k.l.v v m.n.o.p.q.r.s.v v ", +" t.u.v.w.v x.y.z.A.B.C.D.E.F.G.H.v I.v 6 J.K.L.M.N.v v 0 ", +" O.P.Q.R.S.v T.U.V.W.X.Y.Z.`. +.+++v @+v #+$+%+&+*+v =+v -+;+ ", +" >+,+'+)+!+v ~+{+]+^+/+(+_+:+<+[+}+v |+1+v 2+3+4+v v 5+6+v 7+ ", +" 8+9+0+a+b+v c+d+e+f+g+h+i+j+k+l+m+v n+o+v p+q+r+v s+t+u+v v+ ", +"w+x+y+z+A+B+v C+D+E+F+G+H+I+J+K+L+M+v N+O+P+v Q+v R+S+T+U+v V+W+", +"X+Y+Z+`+ @.@v +@@@#@$@%@&@*@=@-@;@>@v ,@'@)@v !@v ~@{@]@^@v /@(@", +"_@:@<@[@}@|@v 1@2@3@4@5@6@7@8@9@0@a@v b@c@d@e@v v f@g@h@i@v j@k@", +"l@m@n@o@p@q@v r@s@t@u@v@w@x@y@z@A@B@v C@D@E@F@v G@H@I@J@K@v L@M@", +"N@O@P@Q@R@S@v T@U@V@W@X@Y@Z@`@ #.#+#v @###$#%#&#*#=#-#;#>#v ,#'#", +")#!#~#{#]#^#v /#(#_#:#<#[#}#|#1#2#3#v 4#5#6#7#8#9#0#a#b#c#v d#e#", +"f#g#h#i#j#k#v l#m#n#o#p#q#r#s#t#u#v#v v w#x#y#z#A#B#C#D#E#v F#G#", +"H#I#J#K#L#M#v N#O#P#Q#R#S#T#U#V#W#X#Y#v Z#l.`# $.$+$@$#$$$v %$&$", +" *$=$-$;$>$v ,$'$)$!$~${$]$^$/$($_$:$v <$[$R.}$|$1$2$3$4$v 5$ ", +" 6$7$8$9$0$v a$b$c$d$e$f$g$h$i$j$k$l$v m$n$o$p$q$r$s$t$u$v v$ ", +" w$x$y$z$A$v B$C$D$E$F$G$H$I$J$K$L$M$v N$O$P$Q$R$S$T$U$V$v v ", +" W$X$Y$Z$`$v %.%+%@%#%$%%%&%*%=%-%v ;%>%,%'%)%!%~%{%]%^%v ", +" /%(%_%:%v <%[%}%|%1%2%3%4%5%6%7%v 8%9%0%a%b%c%d%e%f% v ", +" g%h%i%j%v k%I.l%m%n%o%p%q%r%s%t%v u%v%w%x%y%z%A%B%C% v ", +" D%E%F%v G%H%I%J%K%L%M%N%O%P%Q%R%S%T%U%V%W%X%Y%Z% ", +" `% &v v v v v v v v v v .&+&U%@&#&$&%&&&Z%*& ", +" =&-&;&>&,&'&)&!&~&{&]&^&/&(&_&:&<&[&}&|& ", +" 1&2&3&4&5&6&7&8&9&0&a&b&c&d&e&f& ", +" g&h&i&j&7&k&l&m&n&o&p&q&r&s& ", +" t&u&v&w&x&y&z&A& "}; diff --git a/debian/rivendell.conffiles b/debian/rivendell.conffiles new file mode 100644 index 00000000..7c19b32d --- /dev/null +++ b/debian/rivendell.conffiles @@ -0,0 +1 @@ +/etc/logrotate.d/rivendell diff --git a/debian/rivendell.config b/debian/rivendell.config new file mode 100644 index 00000000..5681baf0 --- /dev/null +++ b/debian/rivendell.config @@ -0,0 +1,110 @@ +#!/bin/sh -e + +# if we do not have debconf, we just skip this +. /usr/share/debconf/confmodule || exit 0 + +db_version 2.0 +db_title "Rivendell configuration" + +# FIXME: initially, I am not going to even try to parse the config file and retreive the previous settings. ... for now, take values from user and generate the config file. The config file is windows style, and I do not know a decent parser for that (maybe make a python script ;-D). + + +# debconf enable or not +db_input high rivendell/debconfenable || true +db_go + +# If user doesn't want to use debconf then leave... +db_get rivendell/debconfenable || true +if [ "$RET" = "false" ]; then + exit 0 +fi + +# general Rivendell questions +db_input high rivendell/postrm_remove_data || true +db_go + +db_input high rivendell/run_mode || true +db_go + + +# Identify section +db_input high rivendell/identity/password || true +db_go + +db_input high rivendell/identity/audioowner || true +db_go + +db_input high rivendell/identity/audiogroup || true +db_go + +# Format section +db_input high rivendell/format/samplerate || true +db_go + +db_input medium rivendell/format/channels || true +db_go + +# MySQL section +db_input high rivendell/mysql/hostname || true +db_go + +db_input high rivendell/mysql/loginname || true +db_go + +# Populate the password with the value entered above. +db_get rivendell/identity/password +db_set rivendell/mysql/password $RET +db_input high rivendell/mysql/password || true +db_go + +db_input medium rivendell/mysql/database || true +db_go + +db_input low rivendell/mysql/driver || true +db_go + +# CAE section +db_input medium rivendell/cae/audioroot || true +db_go + +db_input medium rivendell/cae/audioextension || true +db_go + +db_input low rivendell/cae/allownonstandardrates || true +db_go + +# Tuning section +db_input low rivendell/tuning/userealtime || true +db_go + +# RDAirPlay section +db_input low rivendell/rdairplay/logfile || true +db_go + +# RDCatchd section +db_input low rivendell/rdcatchd/logfile || true +db_go + +# Ripcd section +db_input low rivendell/ripcd/logfile || true +db_go + +# Caed section +db_input low rivendell/caed/logfile || true +db_go + +# Audio adapters section +db_input high rivendell/audioadapters/selections || true +db_go + +db_get rivendell/audioadapters/selections || true +if echo "$RET" | grep -s ALSA > /dev/null 2> /dev/null ; then + db_input high rivendell/audioadapters/alsaintro || true + db_go +fi + +# Introduction +db_input high rivendell/intro || true +db_go + +# vim:tabstop=4:expandtab:shiftwidth=4 diff --git a/debian/rivendell.docs.in b/debian/rivendell.docs.in new file mode 100644 index 00000000..d6ec02d1 --- /dev/null +++ b/debian/rivendell.docs.in @@ -0,0 +1,9 @@ +AUTHORS +ChangeLog +COPYING +INSTALL +NEWS +README +SupportedCards +ToDo +CODINGSTYLE diff --git a/debian/rivendell.examples b/debian/rivendell.examples new file mode 100644 index 00000000..ebd3a298 --- /dev/null +++ b/debian/rivendell.examples @@ -0,0 +1,2 @@ +conf/rd.conf-complete-sample +conf/rd.conf-sample diff --git a/debian/rivendell.init b/debian/rivendell.init new file mode 100755 index 00000000..cda3a666 --- /dev/null +++ b/debian/rivendell.init @@ -0,0 +1,83 @@ +#!/bin/bash -e +# +# /etc/init.d/rivendell +# + +DAEMONS="caed ripcd rdcatchd" +PIDDIR=/var/run/rivendell +NAME=rivendell +LABEL="Rivendell daemons" + +# Defaults +RUN_MODE="init.d" + +# Read config file (will override defaults above) +[ -r /etc/default/rivendell ] && . /etc/default/rivendell + +if [ ! -f "/etc/rd.conf" ]; then + echo "No /etc/rd.conf found. See documentation and /usr/share/doc/rivendell/examples/." >&2 + exit 0 +fi + +DAEMON_USER=`sed -n 's/^AudioOwner=\(.*\)$/\1/p' /etc/rd.conf` + +# For Ubuntu, create run directory to store pid files. +AUDIOGROUP=`sed -n 's/^AudioGroup=\(.*\)$/\1/p' /etc/rd.conf` +if [ ! -d /var/run/rivendell ]; then + install --directory --mode 02775 --owner="$DAEMON_USER" --group="$AUDIOGROUP" /var/run/rivendell +fi + + +# Check if Rivendell daemons are started by init scripts or pam_rd. +if [ "$RUN_MODE" != "init.d" ]; then + exit 0 +fi + +for daemon in $DAEMONS; do + test -x /usr/bin/$daemon || exit 0 +done + +function start() { + echo -n "Starting $LABEL:" + for daemon in $DAEMONS; do + start-stop-daemon --start --oknodo --chuid $DAEMON_USER --exec "/usr/bin/$daemon" + echo -n " $daemon" + done + echo "." +} + +function stop() { + echo -n "Stopping $LABEL:" + for daemon in $DAEMONS; do + start-stop-daemon --stop --pidfile "$PIDDIR/$daemon.pid" --oknodo --user $DAEMON_USER --exec "/usr/bin/$daemon" + echo -n " $daemon" + done + echo "." + + # caed forgets sometimes the shared memory 0x5005 + ipcrm -M 0x5005 2> /dev/null || true +} + +case "$1" in + start) + if ! /usr/bin/rdadmin --check-db; then + echo "No database available, check that MySQL is running" >&2; + exit 0; + fi + + start + ;; + stop) + stop + ;; + restart) + stop + start + ;; + *) + echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload}" + exit 1 + ;; +esac + +exit 0 diff --git a/debian/rivendell.install b/debian/rivendell.install new file mode 100644 index 00000000..ac103e41 --- /dev/null +++ b/debian/rivendell.install @@ -0,0 +1,5 @@ +usr/bin +usr/sbin +usr/share/applications/rd*.desktop +usr/share/srlabs/rd*.qm +usr/share/srlabs/rd*.xpm diff --git a/debian/rivendell.logrotate b/debian/rivendell.logrotate new file mode 100644 index 00000000..f9cf3230 --- /dev/null +++ b/debian/rivendell.logrotate @@ -0,0 +1,27 @@ +/var/log/rivendell/rdairplay.log { + rotate 30 + daily + compress + missingok +} + +/var/log/rivendell/rdcatchd.log { + rotate 30 + daily + compress + missingok +} + +/var/log/rivendell/ripcd.log { + rotate 30 + daily + compress + missingok +} + +/var/log/rivendell/caed.log { + rotate 30 + daily + compress + missingok +} diff --git a/debian/rivendell.postinst b/debian/rivendell.postinst new file mode 100644 index 00000000..7112c0ab --- /dev/null +++ b/debian/rivendell.postinst @@ -0,0 +1,315 @@ +#!/bin/bash -e + +case "$1" in + configure) + + # Default values, in case debconf was not used to set them. These will + # be used for system configurations down below after debconf values are + # read. + # NOTE: make sure to match these defaults with the rivendell.postrm script + AUDIOUSER="rduser" + AUDIOGROUP="rivendell" + AUDIOROOT="/var/snd" + REMOVEDATA="false" + + + # create configuration file, based on debconf entries + . /usr/share/debconf/confmodule + + # Is the user configuring with debconf? + db_get rivendell/debconfenable + if [ "$RET" = "true" ]; then + + # generate the rd.conf file from debconf settings. + dc="/etc/rd.conf" + if [ -e "$dc" ]; then + cp -a "$dc" "${dc}.dpkg-save" + fi + + echo "; NOTE: this file was generated by the rivendell debian package" > "$dc" + echo ";" >> "$dc" + echo "; DO NOT EDIT THIS FILE! Your changes will be lost on the next upgrade." >> "$dc" + echo ";" >> "$dc" + echo "; To regenerate this file (or to select manual configuration) run the command:" >> "$dc" + echo "; dpkg-reconfigure rivendell" >> "$dc" + echo ";" + echo "" >> "$dc" + + echo "[Identity]" >> "$dc" + db_get rivendell/identity/password + echo "Password=$RET" >> "$dc" + db_get rivendell/identity/audioowner + echo "AudioOwner=$RET" >> "$dc" + AUDIOUSER="$RET" + db_get rivendell/identity/audiogroup + echo "AudioGroup=$RET" >> "$dc" + AUDIOGROUP="$RET" + echo "" >> "$dc" + + echo "[Format]" >> "$dc" + db_get rivendell/format/samplerate + echo "SampleRate=$RET" >> "$dc" + db_get rivendell/format/channels + echo "Channels=$RET" >> "$dc" + echo "" >> "$dc" + + echo "[mySQL]" >> "$dc" + db_get rivendell/mysql/hostname + echo "Hostname=$RET" >> "$dc" + db_get rivendell/mysql/loginname + echo "Loginname=$RET" >> "$dc" + db_get rivendell/mysql/password + echo "Password=$RET" >> "$dc" + db_get rivendell/mysql/database + echo "Database=$RET" >> "$dc" + db_get rivendell/mysql/driver + echo "Driver=$RET" >> "$dc" + echo "" >> "$dc" + + echo "[Cae]" >> "$dc" + db_get rivendell/cae/audioroot + echo "AudioRoot=$RET" >> "$dc" + AUDIOROOT="$RET" + db_get rivendell/cae/audioextension + echo "AudioExtension=$RET" >> "$dc" + db_get rivendell/cae/allownonstandardrates + echo "AllowNonstandardRates=$RET" >> "$dc" + echo "" >> "$dc" + + echo "[Tuning]" >> "$dc" + db_get rivendell/tuning/userealtime + echo "UseRealtime=$RET" >> "$dc" + echo "" >> "$dc" + + echo ";" >> "$dc" + echo "; Log Generation, mainly useful for debugging" >> "$dc" + echo ";" >> "$dc" + echo "" >> "$dc" + echo "[RDAirPlay]" >> "$dc" + db_get rivendell/rdairplay/logfile + echo "Logfile=$RET" >> "$dc" + echo "" >> "$dc" + echo "[RDCatchd]" >> "$dc" + db_get rivendell/rdcatchd/logfile + echo "Logfile=$RET" >> "$dc" + echo "" >> "$dc" + echo "[Ripcd]" >> "$dc" + db_get rivendell/ripcd/logfile + echo "Logfile=$RET" >> "$dc" + echo "" >> "$dc" + echo "[Caed]" >> "$dc" + db_get rivendell/caed/logfile + echo "Logfile=$RET" >> "$dc" + echo "" >> "$dc" + + db_get rivendell/audioadapters/selections + JACK_CARD=0 # initialize JACK card to 0 + + # no configuration needed for HPI, simply increment JACK card + if echo "$RET" | grep -s "Audioscience HPI" &> /dev/null ; then + let JACK_CARD=$JACK_CARD+1 + fi + + # no configuration needed for ALSA, simply increment JACK card + if echo "$RET" | grep -s "ALSA" &> /dev/null ; then + let JACK_CARD=$JACK_CARD+1 + fi + + # JACK configuration file portion + if echo "$RET" | grep -s "JACK" &> /dev/null ; then + cat >> "$dc" << EOF +; +; JACK Session Management +; +; See the 'JACK.txt' file for details on how this works! +; +[JackSession] +Source1=rivendell_${JACK_CARD}:playout_0L +Destination1=alsa_pcm:playback_1 + +Source2=rivendell_${JACK_CARD}:playout_0R +Destination2=alsa_pcm:playback_2 + +Source3=rivendell_${JACK_CARD}:playout_1L +Destination3=alsa_pcm:playback_1 + +Source4=rivendell_${JACK_CARD}:playout_1R +Destination4=alsa_pcm:playback_2 + +Source5=rivendell_${JACK_CARD}:playout_2L +Destination5=alsa_pcm:playback_1 + +Source6=rivendell_${JACK_CARD}:playout_2R +Destination6=alsa_pcm:playback_2 + +Source7=rivendell_${JACK_CARD}:playout_3L +Destination7=alsa_pcm:playback_1 + +Source8=rivendell_${JACK_CARD}:playout_3R +Destination8=alsa_pcm:playback_2 + +Source9=rivendell_${JACK_CARD}:playout_4L +Destination9=alsa_pcm:playback_1 + +Source10=rivendell_${JACK_CARD}:playout_4R +Destination10=alsa_pcm:playback_2 + +Source11=rivendell_${JACK_CARD}:playout_5L +Destination11=alsa_pcm:playback_1 + +Source12=rivendell_${JACK_CARD}:playout_5R +Destination12=alsa_pcm:playback_2 + +Source13=rivendell_${JACK_CARD}:playout_6L +Destination13=alsa_pcm:playback_1 + +Source14=rivendell_${JACK_CARD}:playout_6R +Destination14=alsa_pcm:playback_2 + +Source15=rivendell_${JACK_CARD}:playout_7L +Destination15=alsa_pcm:playback_1 + +Source16=rivendell_${JACK_CARD}:playout_7R +Destination16=alsa_pcm:playback_2 + +Source17=alsa_pcm:capture_1 +Destination17=rivendell_${JACK_CARD}:record_0L + +Source18=alsa_pcm:capture_2 +Destination18=rivendell_${JACK_CARD}:record_0R +EOF + + # generate global /etc/jackdrc configuration file + dc="/etc/jackdrc" + if [ -e "$dc" ]; then + cp -a "$dc" "${dc}.dpkg-save" + fi + db_get rivendell/format/samplerate + echo "/usr/bin/jackd --realtime --temporary --driver alsa --rate $RET" > "$dc" + # FIXME: unfortunately jackd cannot parse comments, so none can be added at this time to /etc/jackdrc + + # generate global X11 Xsession.d configuration file to set JACK_START_SERVER environment variable + dc="/etc/X11/Xsession.d/98jack-environment" + if [ -e "$dc" ]; then + cp -a "$dc" "${dc}.dpkg-save" + fi + echo "# NOTE: this file was generated by the rivendell debian package" > "$dc" + echo "#" >> "$dc" + echo "# DO NOT EDIT THIS FILE! Your changes will be lost on the next upgrade." >> "$dc" + echo "#" >> "$dc" + echo "# To regenerate this file (or to select manual configuration) run the command:" >> "$dc" + echo "# dpkg-reconfigure rivendell" >> "$dc" + echo "" >> "$dc" + echo "# set environment variable for JACK to start if not running" >> "$dc" + echo "# (NOTE: /etc/jackdrc is read for the jackd command line)." >> "$dc" + echo "export JACK_START_SERVER=1" >> "$dc" + fi # End of if rivendell/audioadapters/selections has JACK + # End of generate the rd.conf file from debconf settings. + + # generate init script configuration file from debconf settings. + dc="/etc/default/rivendell" + if [ -e "$dc" ]; then + cp -a "$dc" "${dc}.dpkg-save" + fi + echo "# Defaults for rivendell initscript." > "$dc" + echo "# Sourced by /etc/init.d/rivendell ." >> "$dc" + echo "# NOTE: this file was generated by the rivendell debian package." >> "$dc" + echo "#" >> "$dc" + echo "# To regenerate this file (or to select manual configuration) run the command:" >> "$dc" + echo "# dpkg-reconfigure rivendell" >> "$dc" + echo "#" >> "$dc" + echo "# This is a POSIX shell fragment." >> "$dc" + echo "#" >> "$dc" + echo "" >> "$dc" + echo "# How should Rivendell daemons (caed, ripcd, rdcatchd) run?" >> "$dc" + echo "# Possible values are 'init.d' or 'pam_rd'." >> "$dc" + db_get rivendell/run_mode || true + echo "RUN_MODE=\"$RET\" " >> "$dc" + + # populate PAM scripts with pam_rd hooks if requested by the user and it is not already in there + db_get rivendell/run_mode + if [ "$RET" = "pam_rd" ]; then + DISPLAY_MANAGER=`cat /etc/X11/default-display-manager` + DISPLAY_MANAGER=`basename "$DISPLAY_MANAGER"` + dc="/etc/pam.d/$DISPLAY_MANAGER" + + if [ `grep --count "pam_rd.so" "$dc"` -eq 0 ] ; then + cp -a "$dc" "${dc}.dpkg-save" + + # sed command to + # replace (substitute): + # @include common-auth + # with + # auth optional pam_rd.so debug kill_rd_daemons destroy_shm ignore_pass \\ + # @include common-auth + # note only 1 backslash after first line, as we don't want an extra blank line in the output file. + sed -e "s/^[[:space:]]*@include common-auth[[:space:]]*/\ +auth optional pam_rd.so debug kill_rd_daemons destroy_shm ignore_pass \\ +@include common-auth/" \ + < ${dc} >${dc}.dpkg-tmp + mv -f ${dc}.dpkg-tmp ${dc} + fi + fi # End of populate PAM scripts. + + fi # End of if rivendell/debconfenable = true + + db_stop # End of debconf section + + + # Do other system configurations, using debconf values if set, and + # falling back to defaults if not using debconf. + + # create Rivendell user and group + if ! getent group "$AUDIOGROUP" >/dev/null; then + # Adding system group: + addgroup --system "$AUDIOGROUP" 2> /dev/null || true + fi + if ! getent passwd "$AUDIOUSER" >/dev/null; then + # Adding system user: + adduser \ + --system \ + --group \ + --home $AUDIOROOT \ + --no-create-home \ + --shell /bin/bash \ + --gecos "Rivendell system account" \ + $AUDIOUSER >/dev/null + fi + if ! getent group "$AUDIOGROUP" | grep -q "$AUDIOUSER"; then + # Add the user to the group + adduser $AUDIOUSER $AUDIOGROUP + fi + + + # Create audio store directory and set permissions. + if [ ! -d "$AUDIOROOT" ]; then + install --directory --mode 02775 --owner="$AUDIOUSER" --group="$AUDIOGROUP" "$AUDIOROOT" + fi + + # Create run directory to store pid files . + if [ ! -d /var/run/rivendell ]; then + install --directory --mode 02775 --owner="$AUDIOUSER" --group="$AUDIOGROUP" /var/run/rivendell + fi + + # Create log directory to store log files . + #FIXME: better integrate with debconf (debconf currently only has various log file paths). + if [ ! -d /var/log/rivendell ]; then + install --directory --mode 02775 --owner="$AUDIOUSER" --group="$AUDIOGROUP" /var/log/rivendell + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "$0 called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_makeshlibs doesn't add it automaticaly (?!) +if [ "$1" = "configure" ]; then + ldconfig +fi + +#DEBHELPER# diff --git a/debian/rivendell.postrm b/debian/rivendell.postrm new file mode 100644 index 00000000..240af7ae --- /dev/null +++ b/debian/rivendell.postrm @@ -0,0 +1,77 @@ +#!/bin/sh -e + + +# dh_makeshlibs doesn't add it automaticaly (?!) +if [ "$1" = "remove" ]; then + ldconfig +fi + + +case "$1" in + purge) + # Default values, in case debconf was not used to set them. These will + # be used for system configurations down below after debconf values are + # read. + # NOTE: make sure to match these defaults with the rivendell.postinst script + AUDIOUSER="rduser" + AUDIOGROUP="rivendell" + AUDIOROOT="/var/snd" + REMOVEDATA="false" + + # get debconf entries if used. + . /usr/share/debconf/confmodule + + # Is the user configuring with debconf? + db_get rivendell/debconfenable || true + if [ "$RET" = "true" ]; then + db_get rivendell/identity/audioowner || true + [ -n ${RET} ] && AUDIOUSER="$RET" + db_get rivendell/identity/audiogroup || true + [ -n ${RET} ] && AUDIOGROUP="$RET" + db_get rivendell/cae/audioroot || true + [ -n ${RET} ] && AUDIOROOT="$RET" + db_get rivendell/postrm_remove_data || true + [ -n ${RET} ] && REMOVEDATA="$RET" + fi + + # Remove init.d configuration file + rm -f /etc/default/rivendell + + # Remove pam_rd hooks from PAM scripts + DISPLAY_MANAGER=`cat /etc/X11/default-display-manager` + DISPLAY_MANAGER=`basename "$DISPLAY_MANAGER"` + dc="/etc/pam.d/$DISPLAY_MANAGER" + grep -v "pam_rd.so" "$dc" > "${dc}.dpkg-tmp" + mv -f "${dc}.dpkg-tmp" "$dc" + + # Remove user and group + deluser $AUDIOUSER $AUDIOGROUP 2> /dev/null || true + deluser $AUDIOUSER 2> /dev/null || true + groupdel $AUDIOGROUP 2> /dev/null || true + if [ "$REMOVEDATA" = "true" ]; then + [ -d "$AUDIOROOT" ] && rm -rf "$AUDIOROOT" || true + mysqladmin --force drop Rivendell || true + fi + [ -d /var/run/rivendell ] && rm -rf /var/run/rivendell || true + [ -d /var/log/rivendell ] && rm -rf /var/log/rivendell || true + + # Clean out debconf stuff + if [ -e /usr/share/debconf/confmodule ]; then + . /usr/share/debconf/confmodule + db_purge + fi + ;; + + remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + # Nothing to do here + ;; + + *) + echo "$0 called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# NOTE: debhelper section is at the end, so the debconf values can be used during a purge + +#DEBHELPER# diff --git a/debian/rivendell.templates b/debian/rivendell.templates new file mode 100644 index 00000000..e77df9da --- /dev/null +++ b/debian/rivendell.templates @@ -0,0 +1,228 @@ +Template: rivendell/debconfenable +Type: boolean +Default: true +Description: Configure Rivendell and rd.conf through debconf? + The rest of the configuration of Rivendell deals with questions that + affect parameters in /etc/rd.conf, which is the file used to configure + the Rivendell programs. + . + If you don't use debconf to configure rd.conf, you will have to handle + any configuration changes yourself, and will not be able to take + advantage of periodic configuration enhancements. + +Template: rivendell/postrm_remove_data +Type: boolean +Default: false +Description: Remove Rivendell audio store and database if purging Rivendell? + Should the Rivendell audio store (the contents of /var/snd) and the Rivendell + database be removed when the Rivendell package is purged? + +Template: rivendell/run_mode +Type: select +Choices: init.d, pam_rd +Default: init.d +Description: How should the Rivendell daemons be started? + The Rivendell daemons can be started by the init.d scripts during system boot, + or the pam_rd PAM module can be used to start the Rivendell daemons as + needed by each user when they use a Rivendell app. + . + init.d - only a single UNIX user account should be used to run Rivendell apps + . + pam_rd - multiple UNIX user accounts can be used, with pam_rd clearing any old + daemons when a user logs in to an X session. + +Template: rivendell/identity/password +Type: string +Default: letmein +Description: Password for Rivendell: + The password used to identify Rivendell. + . + This is used within Rivendell by ripcd to authenticate. + +Template: rivendell/identity/audioowner +Type: string +Default: rduser +Description: UNIX user account for Rivendell: + The unix user account to use for Rivendell. + +Template: rivendell/identity/audiogroup +Type: string +Default: rivendell +Description: UNIX group account for Rivendell: + The unix group account to use for Rivendell. + +Template: rivendell/format/samplerate +Type: select +Choices: 32000, 44100, 48000 +Default: 44100 +Description: Select the samplerate to use for Rivendell: + Select the samplerate to use for Rivendell. The sample rate is in Hz. + +Template: rivendell/format/channels +Type: select +Choices: 1, 2 +Default: 2 +Description: Select the numer of system channels to use in Rivendell: + Select the number of system channels to use in Rivendell. One (1) + channel is for each input to be treated seperately, while two (2) + channels is for treating the inputs as stereo pairs. + . + NOTE: This is different from channels used to record files within + Rivendell, that is configured via rdadmin and the Rivendell + applications. + +Template: rivendell/mysql/hostname +Type: string +Default: localhost +Description: Enter the hostname of the Rivendell MySQL server: + The hostname of the MySQL server for Rivendell to connect to. If the + server is running locally, localhost should work. + +Template: rivendell/mysql/loginname +Type: string +Default: rduser +Description: Enter the MySQL account with which to connect to the MySQL server: + The MySQL user account which should be used to connect to the MySQL + server. + . + This account will be created during the initial database creation. + +Template: rivendell/mysql/password +Type: string +Default: letmein +Description: Enter the MySQL account password to use when connecting to the MySQL server: + This is the password used to authenticate when connecting to the MySQL + serer. + +Template: rivendell/mysql/database +Type: string +Default: Rivendell +Description: Enter the name of the database for Rivendell in the MySQL server: + This is the name of the database within the MySQL server. + . + It will be created during the initial database creation when running + rdadmin. + +Template: rivendell/mysql/driver +Type: select +Choices: QMYSQL3, FIXME +Description: Select the driver used to connect to the database: + This is the driver used to connect to the database, which may or may + not be a MySQL database. + +Template: rivendell/cae/audioroot +Type: string +Default: /var/snd +Description: Enter the path to the audio store directory: + Path to the directory for Rivendell to store audio. This may be a + local directory or an NFS mounted directory from a remote server. + . + The directory must be read/write by the UNIX user account specified + above. + +Template: rivendell/cae/audioextension +Type: string +Default: wav +Description: Enter the default extension to use for audio files: + This will be the extention used for audio files in the audio store. + +Template: rivendell/cae/allownonstandardrates +Type: boolean +Default: true +Description: Should non standard sample rates be permitted + If true, then non-standard rates can exist in the audio store. + . + FIXME: is this samplerate or bitrate or both. + +Template: rivendell/tuning/userealtime +Type: boolean +Default: true +Description: Use realtime scheduling for CAE? + Use realtime scheduling for the core audio engine (CAE), when talking + via JACK and or ALSA. + +Template: rivendell/rdairplay/logfile +Type: string +Default: /var/log/rivendell/rdairplay.log +Description: Enter the path to the rdairplay log file: + This is the path to the rdairplay log file. + . + NOTE: If a non-default value is used, the path may have to be created. + +Template: rivendell/rdcatchd/logfile +Type: string +Default: /var/log/rivendell/rdcatchd.log +Description: Enter the path to the rdcatchd log file: + This is the path to the rdcatchd log file. + . + NOTE: If a non-default value is used, the path may have to be created. + +Template: rivendell/ripcd/logfile +Type: string +Default: /var/log/rivendell/ripcd.log +Description: Enter the path to the ripcd log file: + This is the path to the ripcd log file. + . + NOTE: If a non-default value is used, the path may have to be created. + +Template: rivendell/caed/logfile +Type: string +Default: /var/log/rivendell/caed.log +Description: Enter the path to the caed log file: + This is the path to the caed log file. + . + NOTE: If a non-default value is used, the path may have to be created. + +Template: rivendell/audioadapters/selections +Type: multiselect +Choices: Audioscience HPI, ALSA, JACK +Default: JACK +Description: Select the audio adapters to use: + Rivendell can use several different types of audio adapters, both + independantly or simultaneously. + +Template: rivendell/audioadapters/alsaintro +Type: note +Description: ALSA Rivendell integration. + In order for Rivendell to recognize an ALSA sound adapter, there must + exist a standard ALSA configuration file with a card named "rd0" + defined. + . + The ALSA configuration file can be global (/etc/asound.conf) or per + user (~/.asoundrc). + . + Sample contents for the configuration file to define rd0 follow: + pcm.rd0 { + type hw + card 1 + } + ctl.rd0 { + type hw + card 1 + } + . + More information on ALSA configuration files can be found here: + http://www.alsa-project.org/alsa-doc/doc-php/asoundrc.php + . + More information on Rivendell and ALSA can also be found in + /usr/share/doc/rivendell/ALSA.txt . + . + This information is repeated in /usr/share/doc/rivendell/README.Debian + +Template: rivendell/intro +Type: note +Description: Rivendell introduction. + The Rivendell radio broadcast automation solution has been installed. + . + The next step is to run the "rdadmin" command with a user that has permissions + to the rivendell system. The first time it will prompt for a MySQL userid and + password that has permissions to connect and create the database. + . + Once the database has been created, run the "rdadmin" command again. + From this point on, rdadmin will allow for configuring of Rivendell. + . + The default user accounts within Rivendell are "admin" and "user", both + with no password. + . + This information is repeated in /usr/share/doc/rivendell/README.Debian + diff --git a/debian/rules b/debian/rules new file mode 100755 index 00000000..00eb413d --- /dev/null +++ b/debian/rules @@ -0,0 +1,117 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# This file is public domain software, originally written by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +export QTDIR=/usr/share/qt3 + +# Include dpatch stuff. +PACKAGE=rivendell +include /usr/share/dpatch/dpatch.make + +configure: configure-stamp +configure-stamp: patch-stamp + dh_testdir + + [ -x ./autogen.sh ] && ./autogen.sh + ./configure --libexecdir=/usr/lib/cgi-bin/rivendell/ + + touch configure-stamp + +build: build-stamp +build-stamp: configure + dh_testdir + + # Add here commands to compile the package. + $(MAKE) + + touch build-stamp + +clean: clean-patched unpatch +clean-patched: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + + # Add here commands to clean up after the build process. + -$(MAKE) clean + -$(MAKE) distclean + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/<packagename> + $(MAKE) DESTDIR=`pwd`/debian/tmp prefix=/usr install-debian +# rm -f `pwd`/debian/tmp/usr/bin/toolame + + install -m 644 $(CURDIR)/debian/rdadmin.xpm $(CURDIR)/debian/tmp/usr/share/srlabs + install -m 644 $(CURDIR)/debian/rdairplay.xpm $(CURDIR)/debian/tmp/usr/share/srlabs + install -m 644 $(CURDIR)/debian/rdcatch.xpm $(CURDIR)/debian/tmp/usr/share/srlabs + install -m 644 $(CURDIR)/debian/rdlibrary.xpm $(CURDIR)/debian/tmp/usr/share/srlabs + install -m 644 $(CURDIR)/debian/rdlogedit.xpm $(CURDIR)/debian/tmp/usr/share/srlabs + install -m 644 $(CURDIR)/debian/rdlogin.xpm $(CURDIR)/debian/tmp/usr/share/srlabs + install -m 644 $(CURDIR)/debian/rdlogmanager.xpm $(CURDIR)/debian/tmp/usr/share/srlabs + + # FIXME: there may be a better way to get this directory created... + install -d -m 755 $(CURDIR)/debian/tmp/usr/share/applications + install -m 644 $(CURDIR)/debian/rdadmin.desktop $(CURDIR)/debian/tmp/usr/share/applications + install -m 644 $(CURDIR)/debian/rdairplay.desktop $(CURDIR)/debian/tmp/usr/share/applications + install -m 644 $(CURDIR)/debian/rdcatch.desktop $(CURDIR)/debian/tmp/usr/share/applications + install -m 644 $(CURDIR)/debian/rdlibrary.desktop $(CURDIR)/debian/tmp/usr/share/applications + install -m 644 $(CURDIR)/debian/rdlogedit.desktop $(CURDIR)/debian/tmp/usr/share/applications + install -m 644 $(CURDIR)/debian/rdlogin.desktop $(CURDIR)/debian/tmp/usr/share/applications + install -m 644 $(CURDIR)/debian/rdlogmanager.desktop $(CURDIR)/debian/tmp/usr/share/applications + + dh_install --sourcedir=debian/tmp --autodest + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs ChangeLog + # + cat debian/rivendell.docs.in > debian/rivendell.docs + find docs -type f -and ! \( -regex ".*CVS.*" -or -regex ".*Makefile.*" \) >> debian/rivendell.docs + dh_installdocs + #dh_installdocs -X CVS -X Makefile + # + dh_installexamples +# dh_install + dh_installmenu + dh_installdebconf + dh_installlogrotate +# dh_installemacsen +# dh_installcatalogs +# dh_installpam +# dh_installmime + dh_installinit +# dh_installcron +# dh_installinfo +# dh_undocumented + dh_installman + dh_link + dh_strip + dh_compress + dh_fixperms +# dh_perl +# dh_python + dh_makeshlibs + dh_installdeb + dh_shlibdeps -ldebian/librivendell/usr/lib + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff --git a/docs/ALSA.txt b/docs/ALSA.txt new file mode 100644 index 00000000..2f0f7ceb --- /dev/null +++ b/docs/ALSA.txt @@ -0,0 +1,42 @@ + ALSA Support in Rivendell + +Rivendell can optionally be compiled to provide direct support for +soundcards using the Advanced Linux Sound Architecture (ALSA). +Instructions on enabling such support can be found in the INSTALL +file. Information about ALSA itself can be found at: + + http://www.alsa-project.org/ + + +STARTING UP RIVENDELL WITH ALSA +When Rivendell's audio daemon, caed(8) is started, and ALSA support is +enabled, caed(8) will look for PCM devices named rd<n>, where <n> is a +number between 0 and 7. If it finds one or more, it will attempt to +open the devices(s) for both playback and capture. If successful, the +devices will then be available as Rivendell virtual 'card' resources, +starting with the next available card number after any HPI or JACK +devices have been started. + + +CONFIGURING PCM DEVICE NAMES +PCM device names for ALSA can be configured by means of entries in the ALSA +configuration file. The ALSA configuration file can either be an '.asoundrc' +file in the home directory of the user running the Rivendell daemons (normally +'root') or an '/etc/asound.conf' file which will apply to all users. For the +simple case of a single ALSA soundcard to be made visible to Rivendell, one +would create an ALSA configuration file containing the following lines: + +pcm.rd0 { + type hw + card 0 +} +ctl.rd0 { + type hw + card 0 +} + +This would create an 'alias' for the first ALSA soundcard in the +system, called 'rd0'. + +More details regarding the syntax and uses of .asoundrc can be found +on the ALSA web site in the documentation section. diff --git a/docs/ENCODERS.txt b/docs/ENCODERS.txt new file mode 100644 index 00000000..e9a5e128 --- /dev/null +++ b/docs/ENCODERS.txt @@ -0,0 +1,93 @@ + File Exporting and Encoders in Rivendell + +Rivendell has the capability to export audio in many different formats using +several different modules (RDLibrary, RDCatch and RDCastManager). To +accomplish this, Rivendell uses audio *encoder* objects, each of which enable +one or more particular 'export formats'. A list of all +recognized export formats for each host can be found by looking in +RDAdmin->ManageHosts->AudioResources, under 'Supported Export Formats'. + +Encoders in Rivendell come in two different basic types, "built-in", and +"custom". Each type is discussed separately below. + + +BUILT-IN ENCODERS +Some built-in encoders are enabled automatically as part of the basic +Rivendell installation process, while others require one or more external +library packages in order to be recognized and used. The following chart +shows the dependencies: + +FORMAT REQUIRED PACKAGE(S) AVAILABLE AT +------------------------------------------------------------------------- +Linear PCM16 [included] +MPEG 1,2 Layer 2 [included] +MPEG 1,2 Layer 3 Lame http://lame.sourceforge.net +FLAC Flac http://flac.sourceforge.net +OggVorbis LibOgg, LibVorbis http://www.vorbis.com + + +CUSTOM ENCODERS +It is possible to configure a Rivendell host to export audio in a format not +supported by one of the built-in encoders by configuring a 'custom' encoder. +Generally, all that is needed is an encoder program that can be invoked from +the Linux command-line. The configuration is done in +RDAdmin->ManageHosts->CustomEncoders. Each encoder needs the following +information: + +NAME +A unique-per-host name for the encoder. + +DEFAULT EXTENSION +A typically two- or three-letter long file extension to associate with this +encoder. + +COMMAND LINE +The command line that Rivendell should invoke to encode a file. When invoked, +Rivendell will pipe the source audio data into standard input of the program +shown here, using sixteen-bit little-endian format with no headers (so-called +'raw' mode) and with channelization and sample rate as indicated in the +configuration for the specific export being executed. The following +wildcard characters can be used to pass parameters from the specfic export +configuration: + + %f - Full destination path/name. + %c - Number of channels + %r - Sample rate, in samples/sec + %b - Bitrate, in bits/sec + +ALLOWABLE PARAMETERS +Finally, each encoder can be provided with a list of zero or more 'allowed' +values for Channel, Sample Rate and Bit Rate. Rivendell will use these values +(along with the 'NAME' value, see above) to populate the approriate controls +in the Edit Export Settings dialog. If no values are configured for a +particular parameter, then the correponding control in the dialog will be +shown as disabled ("greyed-out"), in which case it is assumed that the encoder +being invoked either does not need the parameter or has had it hard-coded in +the configured command line. + + +EXAMPLE +As an example, let's set up a custom encoder to produce 'Flash' encoded audio +files using the FFmpeg multimedia transcoder (http://ffmpeg.mplayerhq.hu/) and +the Freeware Advanced Audio Coder (http://sourceforge.net/projects/faac/). +After installing these packages and verifying that Flash files can be +successfully generated from the command line, we go into +RDAdmin->ManageHosts->CustomEncoders, click the 'Add' button and fill out the +name: + + New Encoder Name: Flash AAC + +Click 'Ok', and the Edit Encoder dialog will open. Fill out the parameters +as follows: + + Default Extension: flv + Command Line: ffmpeg -y -vn -f s16le -ac %c -ar %r -i - -vn -f flv -acodec libfaac -ac %c -ar %r -ab %b %f + Allow Channels: 1,2 + Allow Sample Rates: 22050,44100 + Allow Bit Rates: 8,16 + +Note that the bit rates here are specified in kbps! + +Click 'OK' to save, then go to RDAdmin->ManageHosts->AudioResources. You +should now see a 'Flash AAC [Custom]' entry in the 'SUPPORTED EXPORT FORMATS' +list. diff --git a/docs/GPIO.txt b/docs/GPIO.txt new file mode 100644 index 00000000..e6af2134 --- /dev/null +++ b/docs/GPIO.txt @@ -0,0 +1,185 @@ + GPIO Notes for Rivendell + +Rivendell supports the following General Purpose Input/Output (GPIO) +devices: + +Gameport Joystick Buttons +USB Joystick Buttons +Measurement Computing PCI-PDIS08 Board +Measurement Computing PCI-PDIS16 Board +Measurement Computing PCI-DIO24 Board + +Several supported switcher devices feature GPIO capabiities as well, +see the file 'SWITCHERS.txt' for more info. + +JOYSTICK DEVICES +Joystick support utilizes the Linux Input Device subsystem. Inputs +are active-low, and should be wired as follows: + +02: Input 1 +04: Ground + +07: Input 2 +05: Ground + +10: Input 3 +12: Ground + +14: Input 4 +12: Ground + +In addition, you will need to connect 47 kohm resistors between the +following pins: 1-3, 6-8, 9-11 and 13-15. While not strictly needed +for the GPI portion of the interface to work, the kernel's analog +joystick driver will refuse to initialize the port if these resistors +(or a real joystick) are not present. + +The device name of the joystick will be one of the /dev/input/event<n> +devices. + +NOTE: There have been reports that some port models do not internally +connect pin 12 to ground. The symptom of this situation will be that +Inputs 1 and 2 work, but not Inputs 3 and 4. If this is the case, +connecting the ground for Inputs 3 and 4 to pins 04 or 05 should remedy +the problem. + + +MEASUREMENT COMPUTER GPIO BOARDS +To configure one of the supported MeasurementComputing GPIO boards, +proceed as follows: + +1) Install the card(s) in the computer. In the case of the PCI-DIO24, + two cards may be necessary, as each seperate card is entirely + utilized as either inputs or outputs. + + +2) Test it out. Two programs exist for this purpose: 'gpitest' tests + GPI inputs, and 'gpotest' tests GPO outputs. These programs come + with the 'libradio' package. + +3) Define a GPIO device in RDAdmin->Stations->Switcher/GPIO. Use + a device type of 'Local GPIO'. + +----------------------------------------------------------------------------- +GPIO BOARD-SPECIFIC NOTES + +The Measurement Computing PCI-PDIS08 and PCI-PDIS16 boards feature +floating, opto-isolated inputs. The inputs are not polarity sensitive +and may be driven by either AC or DC. The outputs are electro-mechanical +relays with dry contacts. Connector pinouts are as follows: + +PCI-PDIS08 -- DB37 Male Connector +PCI-PDIS16 -- DB37 Male Connector (using C50F-37F Cable) +Pin Signal +---------------- + 1 Input 8/16 + 20 Input 8/16 + + 2 Input 7/15 + 21 Input 7/15 + + 3 Input 6/14 + 22 Input 6/14 + + 4 Input 5/13 + 23 Input 5/13 + + 5 Input 4/12 + 24 Input 4/12 + + 6 Input 3/11 + 25 Input 3/11 + + 7 Input 2/10 + 26 Input 2/10 + + 8 Input 1/9 + 27 Input 1/9 + + 9 Output 8/16 C + 28 Output 8/16 N/O + + 10 Output 7/15 C + 29 Output 7/15 N/O + + 11 Output 6/14 C + 30 Output 6/14 N/O + + 12 Output 5/13 N/C + 13 Output 5/13 N/O + 31 Output 5/13 C + + 14 Output 4/12 C + 32 Output 4/12 N/C + 33 Output 4/12 N/O + + 15 Output 3/11 N/C + 16 Output 3/11 N/O + 34 Output 3/11 C + + 17 Output 2/10 C + 35 Output 2/10 N/C + 36 Output 2/10 N/O + + 18 Output 1/9 N/C + 19 Output 1/9 N/O + + 37 Output 1/9 C +---------------------- +C = Common +N/O = Normally Open +N/C = Normally Closed + +----------------------------------------------------------------------------- + +The Measurement Computing PCI-DIO24 board features TTL logic-level +connections, which can be configured to operate either as inputs or +outputs. Connector pinouts are as follows: + +PCI-DIO24 -- DB37 Male Connector +Pin Signal +--------------------- + 37 Input/Output 1 + 36 Input/Output 2 + 35 Input/Output 3 + 34 Input/Output 4 + 33 Input/Output 5 + 32 Input/Output 6 + 31 Input/Output 7 + 30 Input/Output 8 + 10 Input/Output 9 + 9 Input/Output 10 + 8 Input/Output 11 + 7 Input/Output 12 + 6 Input/Output 13 + 5 Input/Output 14 + 4 Input/Output 15 + 3 Input/Output 16 + 29 Input/Output 17 + 28 Input/Output 18 + 27 Input/Output 19 + 26 Input/Output 20 + 25 Input/Output 21 + 24 Input/Output 22 + 23 Input/Output 23 + 22 Input/Output 24 + + 11 Ground + 13 Ground + 15 Ground + 17 Ground + 19 Ground + 21 Ground + + 18 +5 VDC + 20 +5 VDC + + 16 +12 VDC + + 14 -12 VDC + +WARNING: The +5 VDC, +12 VDC and -12 VDC pins are connected directly to +the power supply buss of the host PC. Improper use of these pins can +cause serious damage to your computer! + +----------------------------------------------------------------------------- diff --git a/docs/JACK.txt b/docs/JACK.txt new file mode 100644 index 00000000..7d20fe05 --- /dev/null +++ b/docs/JACK.txt @@ -0,0 +1,110 @@ + JACK Support in Rivendell + +Rivendell can optionally be compiled to provide full support for the +JACK Audio Connection Kit. Instructions on enabling such support can +be found in the INSTALL file. Information about JACK itself can be +found at: + + http://jackit.sourceforge.net/ + + +STARTING UP RIVENDELL WITH JACK +When Rivendell's audio daemon, caed(8) is started, and JACK support is +enabled, caed(8) will look for a running jackd(1). If it finds one, +it will attempt to join the graph and create the following ports: + + rivendell_<N>:capture_<M>L + rivendell_<N>:capture_<M>R + ... + rivendell_<N>:playout_<M>L + rivendell_<N>:playout_<M>R + ... + +where <N> is the number of the virtual 'card' Rivendell will use to +access JACK, and <M> is the number of the virtual 'port' within that +'card'. The card number is selected automatically by caed(8), and +will be the first unused card number after any ASI adapters found in +the system are initialized. The 'L' and 'R' stand for 'left' and +'right' stereo channels, respectively. These card/port pairs can be +assigned within RDAdmin just like any other Rivendell audio resource. + + +JACK DAEMON MANAGEMENT +On distros that use a SysV-ish init system (such as SuSE), it's +possible to configure Rivendell to automatically start and stop the +jackd(8) daemon as needed. To do this, proceed as follows: + + On SuSE + Fire up Yast2, click 'System' and then select 'Editor for + /etc/sysconfig Files'. Under 'Configuration Options', select + 'Applications' and then 'Rivendell'. Configure the parameters there + as desired, then click 'Finish' to save them. + + Other Distros + Edit the file '/etc/sysconfig/rivendell' and set the variables to + the desired settings. + + +JACK SESSION MANAGEMENT +Simple session connection management is possible by placing entries +within the [JackSession] section of /etc/rd.conf. The format is as +follows: + +[JackSession] +Source<n>=<src-port> +Destination<n>=<dest-port> + +where: + <n> = Arbitrary connection number, must start at '1' and go up + consecutively. + + <src-port> = The name of the source JACK port to connect, in + standard CLIENTNAME:PORTNAME format. + + <dest-port> = The name of the destination JACK port to connect, in + standard CLIENTNAME:PORTNAME format. + +Here is an example [JackSession] section: + + [JackSession] + Source1=rivendell_1:playout_0L + Destination1=alsa_pcm:playback_1 + + Source2=rivendell_1:playout_0R + Destination2=alsa_pcm:playback_2 + + Source3=rivendell_1:playout_1L + Destination3=alsa_pcm:playback_3 + + Source4=rivendell_1:playout_1R + Destination4=alsa_pcm:playback_4 + + Source5=rivendell_1:playout_2L + Destination5=alsa_pcm:playback_9 + + Source6=rivendell_1:playout_2R + Destination6=alsa_pcm:playback_10 + + Source7=alsa_pcm:capture_1 + Destination7=rivendell_1:record_0L + + Source8=alsa_pcm:capture_2 + Destination8=rivendell_1:record_0R + + Source9=alsa_pcm:capture_3 + Destination9=rivendell_1:record_1L + + Source10=alsa_pcm:capture_4 + Destination10=rivendell_1:record_1R + + Source11=alsa_pcm:capture_9 + Destination11=rivendell_1:record_2L + + Source12=alsa_pcm:capture_10 + Destination12=rivendell_1:record_2R + +This example sets up an ICE1712-based soundcard (a Midiman Delta-66, +in this case) to use the first three playout and record ports of Card +1 in Rivendell. It is, of course, fully possible to dynamically +manage the port assignments through use of a JACK patchbay (such as +QJackConnect) as well. diff --git a/docs/MESSAGE_BOX.txt b/docs/MESSAGE_BOX.txt new file mode 100644 index 00000000..ef9495be --- /dev/null +++ b/docs/MESSAGE_BOX.txt @@ -0,0 +1,9 @@ + Message Box RML Notes + +When using the 'Message Box' ['MB'} RML, it may be necessary to configure +the X server to allow local connections from other processes. One way to +do this is to execute the following command as the local Rivendell user: + + xhost +local: + +For more information, see the xhost(1) man page. diff --git a/docs/Makefile.am b/docs/Makefile.am new file mode 100644 index 00000000..78604f0e --- /dev/null +++ b/docs/Makefile.am @@ -0,0 +1,62 @@ +## automake.am +## +## docs/automake.am for Rivendell +## +## (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +## +## $Id: Makefile.am,v 1.21.6.5 2012/11/29 01:37:35 cvs Exp $ +## $Date: 2012/11/29 01:37:35 $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +SUBDIRS = examples\ + tables + +EXTRA_DIST = ALSA.txt\ + ando_interface.odt\ + asound.conf-sample\ + cae.sxw\ + catchd.txt\ + colors\ + copy_split_format.odt\ + datetime_wildcards.txt\ + implemented_macros.txt\ + ENCODERS.txt\ + GPIO.txt\ + JACK.txt\ + MESSAGE_BOX.txt\ + NEXGEN_FILTER.txt\ + NOW+NEXT.txt\ + pam_rd.txt\ + PODCASTING.txt\ + RDMONITOR.txt\ + reports.txt\ + ripc.txt\ + RIVENDELL_FILTER.txt\ + rml.sxw\ + SAGE_ENDEC.txt\ + scheduler_formats.ods\ + SWITCHERS.txt\ + web_api.odt\ + WIN32.txt\ + WINGS_FILTER.txt + + +CLEANFILES = *~ +MAINTAINERCLEANFILES = *~\ + aclocal.m4\ + configure\ + Makefile.in diff --git a/docs/NEXGEN_FILTER.txt b/docs/NEXGEN_FILTER.txt new file mode 100644 index 00000000..e69de29b diff --git a/docs/NOW+NEXT.txt b/docs/NOW+NEXT.txt new file mode 100644 index 00000000..627b5aa2 --- /dev/null +++ b/docs/NOW+NEXT.txt @@ -0,0 +1,57 @@ + CONFIGURING NOW & NEXT IN RIVENDELL + +SCOPE +Rivendell has the ability to automatically send information regarding +the current and next-to-play events in RDAirPlay logs to external +systems (such as RDS/RDBS encoders or web servers) using TCP/IP UDP +datagrams. This capability is referred to in Rivendell as 'Now & +Next'. This document provides some pointers on setting up this +capability. + +CONFIGURATION +Now and Next is configured in RDAdmin->ManageHosts->RDAirPlay. +Pressing the 'Configure Now & Next Parameters' button here will open a +dialog. Each RDAirPlay log machine can be seperately configured, as +follows: + + IP ADDRESS: The IP address, in dotted-quad notation, to which + packets should be sent. + + UDP PORT: The UDP port number to which packets should be sent. + + UDP STRING: The contents of the update string. The following + placeholder macros can be used, which will be replaced + appropriately when a packet is sent: + + %n - The currently-playing CART NUMBER + %g - The currently-playing GROUP NAME + %t - The currently-playing TITLE field + %a - The currently-playing ARTIST field + %l - The currently-playing ALBUM field + %y - The currently-playing YEAR field + %b - The currently-playing LABEL field + %c - The currently-playing CLIENT field + %e - The currently-playing AGENCY field + %u - The currently-playing USER DEFINED field + %h - The length of the currently playing cut, in mS. + %r - A "Unix" style newline (naked ASCII 10) + %R - An "MS-DOS" style newsline (ASCII 13/10) + %% - A literal '%'. + + Additionally, with the exception of the '%r', '%R' and '%%' + placeholders, the corresponding field for the next-to-play + event can be specified by simply uppercasing the above + placeholders. Any other characters will be sent unchanged. + + +ENABLING AUDIO +Before any data is sent, RDAirPlay checks to see that the Group +to which the event's cart belongs has been enabled to send Now & Next +data. This can be set on a group-by-group basis in +RDAdmin->ManageGroups by setting the 'Transmit Now & Next data' box +appropriately. + + +OPERATION +Once properly configured, RDAirPlay will send a UDP packet as +specified every time the corresponding log changes status. diff --git a/docs/PODCASTING.txt b/docs/PODCASTING.txt new file mode 100644 index 00000000..e6d5fe54 --- /dev/null +++ b/docs/PODCASTING.txt @@ -0,0 +1,132 @@ +Rivendell has the ability to manage multiple RSS audio feeds, including +capabilities for posting and expiring audio automatically as well as updating +associated cast metadata. + + +CREATING AND POPULATING RSS FEEDS +-------------------------------- +Setting up a new RSS feed is a matter of accomplishing the following steps: + +1) Create and configure the feed in RDAdmin + +2) Schedule the audio posts by means of one or more Upload Events in RDCatch. + +3) Manage the metadata in RDCastManager. + +We'll cover each of these steps in turn. + + +1) Creating RSS Feeds +Base parameters for each RSS feed are configured in RDAdmin->ManageFeeds. The +'CHANNEL VALUES' section shows metadata values that will be common to the feed +as a whole (as opposed to specific podcasts within it). The other parameters +are used as follows: + + Key Name - A unique name, eight-characters or less in length, used to + identify the feed within Rivendell. + + Audio Upload URL - This is the URL of the directory to which the audio + files will be uploaded. It is also the URL that the + system will use when deleting expired audio from the + system (e.g. by means of an FTP 'DELETE' command); + hence the specified 'Username' and 'Password' should grant + sufficient rights to allow contents in the directory + to be deleted. Currently supported protocols are + 'file:', 'ftp:' and 'smb:'. + +Audio Download URL - This is the URL of the directory from which the audio + files will be downloaded. The URL listed should be + world-readable by 'anonymous' users. Often, this will + be the same as the 'Audio Upload URL' above. + + Enable AutoPost - If enabled, each new cast in the feed will become + 'visible' immediately following upload, using the + default metadata as configured in the channel values. + If not enabled, then all new casts are placed on hold + pending the customization of the metadata for the + particular cast in RDCastManager. + + Audio Extension - The file extension to use for files posted to the feed + (default: 'mp3'). NOTE: when using a non-default value, + it is necessary to manually create a corresponding + symbolic link on the web server running the 'rdfeed.xml' + script with the appropriate extension that points to the + script. For example, if using an extension of 'aac', one + would do: + + cd <rd-bin-dir> + ln -s rdfeed.xml rdfeed.aac + + Max. Shelf Life - Sets the maximum period (in days) that a piece of audio + can be set in RDCastManager to remain in the feed until + purged. If set to 'None', then no limit is enforced. + This value also establishes the default expiration date + for each cast (with 'Off' resulting in no expiration + date being set --i.e. the cast remains TFN). + + + +XML Data Fields - The various 'XML' fields contain customizable templates that +Rivendell uses to construct the actual XML code that goes into the RSS file. +The following variables are automatically substituted on-the-fly when the XML +is rendered by the 'rdfeed.xml' script: + +CHANNEL PARAMETERS (from CHANNEL PARAMETERS) +-- VARIABLE -- -- Meaning ------------------- +---------------------------------------------- +%TITLE% Channel Title +%CATEGORY% Channel Category +%LINK% Channel Link +%COPYRIGHT% Channel Copyright Notice +%WEBMASTER% Channel Webmaster Address +%DESCRIPTION% Channel Description +%BUILD_DATE% Last Build Date +%PUBLISH_DATE% Date of feed creation +%GENERATOR% Name and Version of RSS Generator + + +ITEM PARAMETERS (from individual cast record in RDCastManager) +-- VARIABLE ------- -- Meaning ----------------------------- +------------------------------------------------------------- +%ITEM_TITLE% Item Title +%ITEM_CATEGORY% ITem Category +%ITEM_DESCRIPTION% Item Description +%ITEM_LINK% Item Link +%ITEM_AUTHOR% Item Author +%ITEM_SOURCE_TEXT% Item Third-Party Source - Human Readable +%ITEM_SOURCE_URL% Item Third-Party Source - URL Link +%ITEM_COMMENTS% Item Comments +%ITEM_AUDIO_URL% Item Audio Download URL +%ITEM_AUDIO_LENGTH% Item Audio File Length in bytes +%ITEM_AUDIO_TIME% Item Audio Playout Time in MM:SS format +%ITEM_PUBLISH_DATE% Date of cast creation +%ITEM_GUID% Globally Unique ID String + + +2) Posting Audio +Once the RSS feed(s) are set up, individual podcasts can be added by +scheduling one or more Upload events in RDCatch. To associate a given upload +to a particular feed, simply select the desired feed in the 'RSS Feed' +control of the Edit Upload dialog, being sure that it gets uploaded to the +location specified in the 'Audio Base URL' for the feed. RDCatch will +automatically add the audio to the feed's XML file after the upload. + + +3) Editing Podcast Metadata +The metadata for individual podcasts (including the cast's expiration date and +posting status) can be edited by means of the RDCastManager module. Operation +of the module should be largely self-explanatory. + + +POSTING THE RSS FEED FILE +------------------------- +The RSS file for each feed is generated dynamically by the RDFeed +script. The specific location of the script is determined by the value +given in the '--libexecdir=' parameter to './configure' (see the +'INSTALL' file for more details) and will also be influenced by the specific +configuration used by the web server. A typical link would looks as +follows: + + http://www.example.com/rd-bin/rdfeed.xml?TEST + +This link would serve the RSS file for the feed with the Key Name 'TEST'. diff --git a/docs/RDMONITOR.txt b/docs/RDMONITOR.txt new file mode 100644 index 00000000..0e2ae8e3 --- /dev/null +++ b/docs/RDMONITOR.txt @@ -0,0 +1,58 @@ + RDMonitor / RDSelect Configuration + +The Rivendell RDMonitor module can be used to monitor the health state +(Database + Audio Store) of a system. Optionally, it can also be used +with RDSelect to allow a host to be switched between multiple Database + +AudioStore setups. This document describes the procedure for converting +an existing Rivendell setup to allow this functionality. + +1) OVERVIEW +Rivendell requires that a configuration file exist at '/etc/rd.conf' +that describes basic parameters (such as login information for the MySQL +database server). RDMonitor/RDSelect build on this foundation by +utilizing a set of one or more configuration files located in the +'/etc/rivendell/' directory, with the 'current' configuration indicated +by a symbolic link at '/etc/rd.conf' that points to the desired configuration +in '/etc/rivendell.d/'. Several new parameters have been added to +rd.conf(5) to support this mode of operation, including: + +[Identity] +Label=<label> + +[AudioStore] +MountSource=<mnt-src> +MountType=<mnt-type> +MountOptions=<mnt-opts> + +Where: +<label> - A text string that is displayed to indicate the overall name +of this configuration. + +<mnt-src> - The filesystem to be mounted at '/var/snd' when using this +configuration, such as would be provided in fstab(5). If the desired +audio store resides on the root filesystem, then this field should be +left blank. + +<mnt-type> - The type of audio store mount, such as would be specified in +fstab(5). + +<mnt-opts> - The mount point options for the audio store, such as would +be specified in fstab(5). + + +2) CONVERTING AN OLD-STYLE SETUP +An 'old-style' setup --i.e. one that consists of a single configuration +file at '/etc/rd.conf'-- can be converted to the new layout through the +following steps: + +A) Create the configuration directory: + + mkdir -p /etc/rivendell.d + +B) Move the original configuration file: + + mv /etc/rd.conf /etc/rivendell.d/rd-default.conf + +C) Create the symbolic link: + + ln -s /etc/rivendell.d/rd-default.conf /etc/rd.conf diff --git a/docs/RIVENDELL_FILTER.txt b/docs/RIVENDELL_FILTER.txt new file mode 100644 index 00000000..e0bfe3c9 --- /dev/null +++ b/docs/RIVENDELL_FILTER.txt @@ -0,0 +1,70 @@ + Usage Notes for the 'rivendell_filter' Import Script. + +Rivendell_filter is a script designed to be used to import existing audio +and meta-data from another Rivendell system. It is invoked as follows: + +USAGE + +rivendell_filter -h <hostname> -u <username> -p <password> -A <audio-dir> +-g <default-group> -s <start-cartnum> -e <end-cartnum> +Where: + <hostname> = The MySQL hostname of the source Rivendell database. + + <username> = The MySQL username of the source Rivendell database. + + <password> = The MySQL password of the source Rivendell database. + + <audio-dir> = The name of the directory containing the source + Rivendell audio files. + + <default-group> = The name of the group in which to place carts + belonging to a source Group for which there + is no corresponding destination Group. + + <start-cartnum> = The first cart in the range of those to be transferred. + + <end-cartnum> = The last cart in the range of those to be trasnferred. + +OVERVIEW +In order transfer carts from an external Rivendell system, proceed as +follows: + +1) CREATE RIVENDELL GROUPS +In RDAdmin->ManageGroups, create a Group to correspond to each Rivendell +Group that exists in the library to be imported, and an additional +group to catch any carts that may not have a corresponding Group. + +2) LOCATE THE EXTERNAL RIVENDELL DATABASE AND AUDIO FILES +The directory containing the audio files can be mounted from a remote +system if needs be. Read-only access is adequate (and in fact recommended), +as the script does not modify these items in any way. + +3) VERIFY AVAILABLE DISK SPACE +Verify that enough disk space is available in the '/var/snd/' +directory of the destination system to accomodate the audio to be +imported. You should have at least the amount of space currently occupied +by the source files, plus 5 percent additional. + +4) INVOKE SCRIPT +Start up the script, as described in the USAGE section above. The +script will print progress reports as it proceeds, or notify you of +error conditions as required. + +WARNING +If a cart from the source system has the same number as one one the +destination, the destination cart (data and *all* audio) will be overwritten! + +NOTE ON AUDIO PROCESSING +Rivendell_filter does not alter or reencode the audio sample data in any +way, and thus does *not* incurr any generation or transcoding loss of +quality. At the same time, this means that the incoming audio will be +brought into the new Rivendell system *exactly* as it exists in the +source system, with all parameters (e.g. sample rate, bit rate, level, +etc) unaltered. If you need to alter one or more of these parameters as +part of the import process, we suggest you use the RDImport script +instead. + +NOTE ON GROUP ASSIGNMENTS +WARNING: Rivendell_filter makes no attempt to enforce group numbering rules! +If a group to which a given source cart belongs exists on the destination +system, the cart will be placed in that group, regardless of numbering rules. diff --git a/docs/SAGE_ENDEC.txt b/docs/SAGE_ENDEC.txt new file mode 100644 index 00000000..9e4fa4ea --- /dev/null +++ b/docs/SAGE_ENDEC.txt @@ -0,0 +1,24 @@ + Automating Required Weekly Tests on a Sage Digital ENDEC + +Rivendell can be configured to allow Required Weekly Tests (RWTs) for the +Emergency Alert System (EAS) to be executed directly from a macro cart, +using the Digital ENDEC Emergency Alert (EAS) Unit Manufactured by Sage +Systems. + +PROCEDURES +Create a macro cart and populate it with the following RML: + + RN sage_endec_rwt.sh <ip-addr> <web-user> <web-password>! + +where: + + <ip-addr> - The IP address of the ENDEC system.. + <web-user> - The name used to log in to the ENDEC's web interface. +<web-password> - The password used to log into the ENDEC's web interface. + +For example, for an ENDEC at 192.168.0.1 with a login name of 'admin' +and a login password of 'letmein', you'd use: + + RN sage_endec_rwt.sh 192.168.0.1 admin letmein! + +Whenever this macro cart is executed, the ENDEC will run an RWT. diff --git a/docs/SWITCHERS.txt b/docs/SWITCHERS.txt new file mode 100644 index 00000000..5a62861e --- /dev/null +++ b/docs/SWITCHERS.txt @@ -0,0 +1,631 @@ + Switcher Application Notes for Rivendell + +The following devices are supported as switchers under Rivendell: + +360 Systems AM-16/B Audio Crosspoint Switcher +Broadcast Tools 10x1 Audio Switcher +Broadcast Tools 16x1 Audio Switcher +Broadcast Tools 16x2 Audio Switcher +Broadcast Tools 8x2 Audio Switcher +Broadcast Tools Sentinel 4 Web AES Switcher +Broadcast Tools SS 12.4 Audio Switcher +Broadcast Tools SS 16.4 Audio Switcher +Broadcast Tools SS 4.2 Audio Switcher +Broadcast Tools SS 4.4 Audio Switcher +Broadcast Tools ACS 8.2 Audio Control Switcher +Broadcast Tools SS 8.2 Audio Switcher +Harlond Virtual Mixer +LiveWire LWRP Audio +LiveWire LWRP GPIO +LiveWire Multicast GPIO +Local Audio Adapter +Logitek vGuest +Quartz Electronics Type 1 Routing Protocol +Sierra Automated Systems 32000 Audio Router +Sierra Automated Systems 64000 Audio Router +Sierra Automated Systems Universal Serial Interface (USI) +Sine Systems ACU-1 (Prophet version) +StarGuide III Satellite Receiver +Wegener Unity4000 DVB Satellite Receiver + +See the sections below for notes on each specific model. + +---------------------------------------------------------------------------- +360 SYSTEMS AM-16/B AUDIO CROSSPOINT SWITCHER + +Driver Name: 360 Systems AM-16/B + +Supported RML Commands: + Switch Take ('ST') + +GENERAL NOTES: +Control is done by means of MIDI connections to the 'MIDI IN' and +'MIDI OUT' ports on the back of the unit, with the appropriate MIDI device +specified in the 'Device:' field in RDAdmin->ManageHosts->Switchers/GPIO. +The following settings should be configured on the AM-16/B: + + Control Port Type: MIDI (jumper JMP1) + Program Send: OFF + Receive Channel: o (Omni mode) + Memory Protect: OFF + +The driver uses MIDI programs '0' and '1' on the AM-16/B when processing +crosspoint changes; anything previously saved in those programs will +be overwritten! + + +---------------------------------------------------------------------------- +BROADCAST TOOLS 10x1 + +Driver Name: BroadcastTools 10x1 + +Supported RML Commands: + Switch Take ('ST') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to a four pin RJ11 +modular jack on the back of the unit (an adapter to a standard DB9 +connector is supplied by Broadcast Tools with the unit). Serial port +parameters should be set to 2400 baud rate, no parity, 8 data bits, 1 +stop bit, CR/LF termination. + + +---------------------------------------------------------------------------- +BROADCAST TOOLS 16x1 + +Driver Name: BroadcastTools 16x1 + +Supported RML Commands: + Switch Take ('ST') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to a four pin RJ11 +modular jack on the back of the unit (an adapter to a standard DB9 +connector is supplied by Broadcast Tools with the unit). Serial port +parameters should be set to 9600 baud rate, no parity, 8 data bits, 1 +stop bit, CR/LF termination. + + +Driver Name: BroadcastTools 16x2 + +Supported RML Commands: + Switch Take ('ST') + GPO Set ('GO') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to a four pin RJ11 +modular jack on the back of the unit (an adapter to a standard DB9 +connector is supplied by Broadcast Tools with the unit). Serial port +parameters should be set to 9600 baud rate, no parity, 8 data bits, 1 +stop bit, CR/LF termination. + +Operation in 'multidrop' mode is not supported. + + +---------------------------------------------------------------------------- +BROADCAST TOOLS 8x2 + +Driver Name: BroadcastTools 8x2 + +Supported RML Commands: + Switch Take ('ST') + Switch Add ('SA') + Switch Remove ('SR') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to a four pin RJ11 +modular jack on the back of the unit (an adapter to a standard DB9 +connector is supplied by Broadcast Tools with the unit). Serial port +parameters should be set to 2400 baud rate, no parity, 8 data bits, 1 +stop bit, CR/LF termination. + +The 8x2 should be configured to use 'Mix' mode. This can be done by holding +down the F1 button on the switcher while powering up. + +Operation in 'multidrop' mode is not supported. + + +---------------------------------------------------------------------------- +BROADCAST TOOLS SENTINEL 4 WEB AES SWITCHER + +Driver Name: BroadcastTools Sentinel 4 Web + +Supported RML Commands: + Switch Take ('ST') + +GENERAL NOTES: +Control is done by means of a TCP/IP connection to the unit's integrated +Ethernet port. + +On the 'Email/Network Setup' page of the unit, be sure that the 'TCP Enabled' +box is checked and that 'TCP Listen Port' is set to the same number as is +used in the 'IP Port' setting in Rivendell's driver configuration +('56' by default). + + +---------------------------------------------------------------------------- +BROADCAST TOOLS SS 12.4 + +Driver Name: BroadcastTools SS 12.4 + +Supported RML Commands: + Switch Take ('ST') + Switch Add ('SA') + Switch Remove ('SR') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to a four pin RJ11 +modular jack on the back of the unit (an adapter to a standard DB9 +connector is supplied by Broadcast Tools with the unit). Serial port +parameters should be set to 9600 baud rate, no parity, 8 data bits, 1 +stop bit, CR/LF termination. + +The SS 12.4 should be configured to use 'Mix' mode. This can be done +by setting DIP switches SW1-7 and SW-1-3 to OFF. + +Operation in 'multidrop' mode is not supported. + + +Driver Name: BroadcastTools SS 16.4 + +Supported RML Commands: + GPO Set ('GO') + Switch Take ('ST') + Switch Add ('SA') + Switch Remove ('SR') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to a four pin RJ11 +modular jack on the back of the unit (an adapter to a standard DB9 +connector is supplied by Broadcast Tools with the unit). Serial port +parameters should be set to 9600 baud rate, no parity, 8 data bits, 1 +stop bit, CR/LF termination. + +A total of 24 GPO outputs are supported, with the relays appearing as +GPO lines 1-8 and the open collector outputs as lines 9-24. All 24 +'PIP' inputs are supported as GPI devices. + +The SS 16.4 should be configured to use 'Mix' mode and to have 'PIP' +mode enabled. This can be done by setting DIP switches SW24-5, SW24-6 +and SW24-8 to ON. + +Operation in 'multidrop' mode is not supported. + + +---------------------------------------------------------------------------- +BROADCAST TOOLS SS 4.2 + +Driver Name: BroadcastTools SS4.2 + +Supported RML Commands: + Switch Take ('ST') + Switch Add ('SA') + Switch Remove ('SR') + GPI Enable ('GE') + GPI Set ('GI') + GPO Set ('GO') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to a four pin RJ11 +modular jack on the back of the unit (an adapter to a standard DB9 +connector is supplied by Broadcast Tools with the unit). Serial port +speed on the SS 4.2 should be set to 9600 (DIP switches SW13-3 and +SW13-4 set to 'off'). Serial port parameters in RDAdmin should be set +to 9600 baud rate, no parity, 8 data bits, 1 stop bit, CR/LF termination. + +The SS 4.2 should be configured to use 'Mix' mode --i.e. DIP switches +SW13-5 and SW13-6 should both be 'on', and the unit ID should be set to +'0', with DIP switches SW13-1 and SW13-2 both 'off'. + +Operation in 'multidrop' mode is not supported. If you wish to use +GPI (referred to as 'PIP', for 'Parallel Input Port' in the Broadcast +Tools documentation), then you will also need to be sure that DIP +switch SW13-7 is ON. + + +---------------------------------------------------------------------------- +BROADCAST TOOLS SS 4.4 + +Driver Name: BroadcastTools SS4.4 + +Supported RML Commands: + Switch Take ('ST') + Switch Add ('SA') + Switch Remove ('SR') + GPI Enable ('GE') + GPI Set ('GI') + GPO Set ('GO') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to a four pin RJ11 +modular jack on the back of the unit (an adapter to a standard DB9 +connector is supplied by Broadcast Tools with the unit). Serial port +speed on the SS 4.4 should be set to 9600 (DIP switch SW3 set to 'off'). +Serial port parameters in RDAdmin should be set to 9600 baud rate, no parity, +8 data bits, 1 stop bit, CR/LF termination. + +The SS 4.4 should be configured to use 'Mix' mode --i.e. DIP switches +SW4 and SW5 should both be 'on', and the unit ID should be set to +'0', with DIP switches SW1 and SW2 both 'off'. + +Operation in 'multidrop' mode is not supported. If you wish to use +GPI (referred to as 'PIP', for 'Parallel Input Port' in the Broadcast +Tools documentation), then you will also need to be sure that DIP +switch SW8 is 'on'. If you wish to use the open collector and relay outputs +as GPO, then you will also need to be sure that DIP switch SW6 is 'off'. + + +---------------------------------------------------------------------------- +BROADCAST TOOLS ACS 8.2 + +Driver Name: BroadcastTools ACS8.2 + +Supported RML Commands: + Switch Take ('ST') + Switch Add ('SA') + Switch Remove ('SR') + Switch Level ('SL') [Output #1 only] + GPI Enable ('GE') + GPI Set ('GI') + GPO Set ('GO') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to a four pin RJ11 +modular jack on the back of the unit (an adapter to a standard DB9 +connector is supplied by Broadcast Tools with the unit). Serial port +speed on the ACS 8.2 should be set to 9600. Serial port parameters +should be set to 9600 baud rate, no parity, 8 data bits, 1 stop bit, +no termination. + +The ACS 8.2 should be configured to use 'Mix' mode --i.e. DIP switches +SW17-5 and SW17-6 should both be 'on', and the unit ID should be +'0', with DIP switches SW17-1 and SW17-2 both 'off'. + +Operation in 'multidrop' mode is not supported. If you wish to use +GPI (referred to as 'PIP', for 'Parallel Input Port' in the Broadcast +Tools documentation), then you will also need to be sure that DIP +switch SW17-10 is ON. + +The ACS 8.2 supports the Switch Level [SL] RML for connections to +Output 1. Six different gain levels are supported: 0 dB, -3 dB, +-6 dB, -10 dB, -15 dB and -20 dB. For for a specified gain level of +greater than or equal to -20, the applied gain will be rounded down +to the next supported level. For gain levels of less than -20 dB, the +minimum supported gain (-20 dB) will be applied. + + +---------------------------------------------------------------------------- +BROADCAST TOOLS SS 8.2 + +Driver Name: BroadcastTools SS8.2 + +Supported RML Commands: + Switch Take ('ST') + Switch Add ('SA') + Switch Remove ('SR') + GPI Enable ('GE') + GPI Set ('GI') + GPO Set ('GO') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to a four pin RJ11 +modular jack on the back of the unit (an adapter to a standard DB9 +connector is supplied by Broadcast Tools with the unit). Serial port +speed on the SS 8.2 should be set to 19200 (some have found 9600 to work +instead). Do *not* use 38400, as there are known bugs within the SS 8.2 +when used with this speed! Serial port parameters should be set to +19200 baud rate (or 9600 if that worked instead), No parity, 8 data +bits, 1 stop bit, CR/LF termination (or potentially no termination). + +The SS 8.2 should be configured to use 'Mix' mode --i.e. DIP switches +SW-14-4 and SW-14-5 should both be 'on', and the unit ID should be +'0', with DIP switches SW-14-1, SW-14-2 and SW-14-3 all 'off'. + +Operation in 'multidrop' mode is not supported. If you wish to use +GPI (referred to as 'PIP', for 'Parallel Input Port' in the Broadcast +Tools documentation), then you will also need to be sure that DIP +switch SW-14-10 is ON. + + +---------------------------------------------------------------------------- +Harlond Virtual Mixer + +Driver Name: Harlond Virtual Mixer + +Supported RML Commands: + Fire Salvo ('FS') + GPI Enable ('GE') + GPI Set ('GI') + GPO Set ('GO') + Switch Add ('SA') + Switch Level ('SL') + Switch Remove ('SR') + Switch Take ('ST') + +GENERAL NOTES: +Control is by means of a TCP/IP connection to port 5002. Output busses are +mapped as follows: + +OUTPUT BUSS +------ ---- + 1 PGM + 2 AUD + 3 UTL + 4 CUE + +Input channel ON/OFF is sensed/controlled by means of the respective GPIO +number using GE/GI/GO RMLs. + + +---------------------------------------------------------------------------- +LiveWire LWRP Audio + +Driver Name: LiveWire LWRP Audio + +Supported RML Commands: + Switch Take ('ST') + +GENERAL NOTES: +LiveWire is a distributed audio router and control system, with the +components (called 'nodes') configured and controled via TCP/IP. More +information can be found at http://www.axiaaudio.com/. + +This driver can be used to create and remove connections between audio +sources and destinations via LiveWire Routing Protocol (LWRP). + +Configuration is a matter of entering the IP address, password and base +output number for each node in +RDAdmin->ManageHosts->Switcher/GPIO->LiveWire Nodes. The driver +will autodetect all other parameters from the nodes themselves. The +resulting constellation of nodes can be controled with the 'Switch Take' +['ST'] RML by specifying the LiveWire source stream number as the <input> +parameter and the the base output number+the slot number-1 for the <output> +parameter. + + +---------------------------------------------------------------------------- +LiveWire LWRP GPIO + +Driver Name: LiveWire LWRP GPIO + +Supported RML Commands: + GPI Enable ('GE') + GPI Set ('GI') + GPO Set ('GO') + +GENERAL NOTES: +LiveWire is a distributed audio router and control system, with the +components (called 'nodes') configured and controled via TCP/IP. More +information can be found at http://www.axiaaudio.com/. + +This driver can be used to control LiveWire's GPIO subsystem by means of +the LiveWire Routing Protocol (LWRP) with both physical as well as 'virtual' +GPIO devices. + +Only two items need to be specified in the configuration: the IP address +of the device to control and the 'Layer', with 'V' specifying a virtual +GPIO device and 'D' specifying an actual physical one. The driver +will autodetect all other parameters (e.g. the number of input and output +lines) from the device itself. + + +---------------------------------------------------------------------------- +LiveWire Multicast GPIO + +Driver Name: LiveWire Multicast GPIO + +Supported RML Commands: + GPI Enable ('GE') + GPI Set ('GI') + GPO Set ('GO') + +GENERAL NOTES: +LiveWire is a distributed audio router and control system, with the +components (called 'nodes') configured and controled via TCP/IP. More +information can be found at http://www.axiaaudio.com/. + +This driver provides the ability to access GPIO functions from LiveWire- +enabled control surfaces for setups that lack a virtual GPIO device --e.g. +when interfacing audio directly to a LiveWire node without using a native +LiveWire software audio driver or audio adapter. + +When configuring it, the 'IP Address' field should contain the address +of the local interface to which the LiveWire network is attached, while +the 'LiveWire GPIOs' list should be populated with the stream number - GPIO +line associations to be used. + + +---------------------------------------------------------------------------- +Driver Name: Local Audio Adapter + +Supported RML Commands: + Switch Take ('ST') + Switch Add ('SA') + Switch Remove ('SR') + Switch Add with Gain ('SX') + +GENERAL NOTES: +It's possible to use one or more of the actual audio adapters as a +switcher device using this driver. Doing so makes it possible to +route audio directly from the adapter inputs to outputs, while at the +same time using it for audio capture/playout in the usual manner. + + +Driver Name: Logitek vGuest + +Supported RML Commands: + GPI Enable ('GE') + GPI Set ('GI') + GPO Set ('GO') + Set Display ('SD') + Switch Take ('ST') + +GENERAL NOTES: +Before using the driver, the resources within the Logitek Audio Engine +system that you wish to control must be made available in a 'vGuest' +account within the Logitek 'Supervisor' system. Then, those same +resources must be mapped within the Rivendell driver. For the 'ST' +RML, the Logitek Engine Numbers and Device Numbers are mapped to +logical Rivendell 'Inputs' and 'Outputs' within the 'Configure Inputs' +and 'Configure Outputs' dialogs. For the GPO RMLs, various Logitek +'switches' (by which we mean anything that can be turned on and off, +such as faders feeds, not just GPIO) are mapped to logical Rivendell +GPIO lines by means of their Logitek Engine, Device and Buss numbers. + + +---------------------------------------------------------------------------- +Quartz Electronics Type 1 Routing Protocol + +Driver Name: Quartz Type 1 + +Supported RML Commands: + Switch Take ('ST') + Fire Salvo ('FS') + +GENERAL NOTES: +Control can done either by means of an RS-232C connection or by means of +TCP/IP to TCP port 23. + + +SIERRA AUTOMATED SYSTEMS 32000 AUDIO ROUTER + +Driver Name: SAS 32000 + +Supported RML Commands: + Switch Take ('ST') + Switch Add ('SA') + Switch Remove ('SR') + Switch Level ('SL') [requires appropriate SAS hardware support] + +GENERAL NOTES: +Control is done by means of an RS-232C connection to the 'Computer +RS-232' port on the AXC-8 System Controller. Serial port parameters +should be set to 9600 baud rate, no parity, 8 data bits, 1 stop bit +and no terminator. The AXC-8 must be equipped with firmware built to +use the 'conventional' command protocol -- the 'enhanced' version will +not work! + + +---------------------------------------------------------------------------- +SIERRA AUTOMATED SYSTEMS 64000 AUDIO ROUTER + +Rivendell contains two drivers that support this switcher, depending +upon how the physical connection is made. If possible, use the 'SAS +64000-GPI' driver, as it is better tested and provides superior +performance. + +Driver Name: SAS 64000 + +Supported RML Commands: + Switch Take ('ST') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to the 'Computer +RS-232' port on the AXC-8 System Controller. Serial port parameters +should be set to 9600 baud rate, no parity, 8 data bits, 1 stop bit +and no terminator. The AXC-8 must be equipped with firmware built to +use the 'conventional' command protocol -- the 'enhanced' version will +not work! + +Driver Name: SAS 64000-GPI + +Supported RML Commands: + Switch Take ('ST') + GPO Set ('GO') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to the 'Computer +RS-232' port on a GPI-1600 GPIO interface. Serial port parameters +should be set to 19200 baud rate, no parity, 8 data bits, 1 stop bit +and no terminator. This driver allows control of the system's GPO +outputs as well as audio crosspoints. + + +---------------------------------------------------------------------------- +SIERRA AUTOMATED SYSTEMS Universal Serial Interface (USI) + +Driver Name: SAS User Serial Interface + +Supported RML Commands: + Switch Take ('ST') + Switch Take With Gain ('SG') + Switch Add ('SA') + Switch Remove ('SR') + Switch Level ('SL') + Switch Crosspoint Gain ('SX') + GPO Set ('GO') + Fire Salvo ('FS') + Console Label ('CL') + +GENERAL NOTES: +Control can done either by means of an RS-232C connection to one of +the serial ports on a DRC-16E card or by means of TCP/IP to a PC +running SAS's Server Module software. TCP connections are normally made +to port 1350 on the Server Module system. + + +---------------------------------------------------------------------------- +SINE SYSTEMS ACU-1 (PROPHET VERSION) + +Driver Name: Since ACU-1 (Prophet) + +Supported RML Commands: + Switch Add ('SA') + Switch Remove ('SR') + Switch Take ('ST') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to the RS-232 port on +the unit. Serial port parameters in RDAdmin should be set to 57600 baud +rate, even parity, 8 data bits, 1 stop bit and no terminator. + +The ACU-1 should be set to use factory default settings. This can be done +by simultaneously pressing buttons 1 and 8 on the front panel of the unit +for at least one second. + + +---------------------------------------------------------------------------- +STARGUIDE III Satellite Receiver + +Driver Name: StarGuide III + +Supported RML Commands: + Switch Take ('ST') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to the +RS-232 port on the unit. The port should be configured on the +receiver to use a speed of 9600. Serial port parameters in RDAdmin +should be set to 9600 baud rate, no parity, 8 data bits, 1 stop bit +and no terminator. Once configured, use RDAdmin to create inputs that +correspond to the StarGuide Provider and Source IDs available on the +selected DVB carrier. Provider and Source ID data is available from +the provider network. + + +---------------------------------------------------------------------------- +WEGENER UNITY4000 DVB SATELLITE RECEIVER + +Driver Name: Wegener Unity 4000 + +Supported RML Commands: + Switch Take ('ST') + +GENERAL NOTES: +Control is done by means of an RS-232C connection to one of the two +RS-232 ports on the unit. If possible, use serial port number one, +as the reciever uses a larger data buffer with that port. The +selected port should be configured in the reciever to be of type +"Terminal" with a speed of 19200. Serial port parameters should be +set to 19200 baud rate, no parity, 8 data bits, 1 stop bit +and no terminator. Once configured, use RDAdmin to create inputs that +correspond to the DVB stream names available on the selected DVB +carrier. + +Caution is needed when scheduling record events from the Unity4000, as +the unit is capable of outputting a given DVB stream to only a single +output at a time. Commanding a stream to an output will cause that +stream to be silently deselected from a previously selected output. + + +---------------------------------------------------------------------------- diff --git a/docs/WIN32.txt b/docs/WIN32.txt new file mode 100644 index 00000000..83c5fbf4 --- /dev/null +++ b/docs/WIN32.txt @@ -0,0 +1,25 @@ + WINDOWS SUPPORT FOR RIVENDELL + +A Windows port of Rivendell exists, consisting of just the RDLogEdit, +RDLogManager and RMLSend tools, primarily intended for use on systems +employing Windows-based traffic and music schedulers. Current binary +versions can be found at: + + ftp://ftp.salemradiolabs.com/pub/srlabs/rivendell/win32/ + +If you wish to build the Windows port from source, please see the +'INSTALL' file. + + +INSTALLING THE BIANRY VERSION +The binary version comes with a standard setup program that will do +most of the work of getting Rivendell installed. After the +installation is complete, you will need to edit the 'rd.ini' file, +located in the Rivendell installation directory (by default, +'C:\ProgramFiles\SalemRadioLabs\Rivendell\') and supply the hostname +and login password to the 'rduser' account on the site's mySQL server. +This file can contain all of the directives and arguments used in +Rivendell's standard '/etc/rd.conf' file (although only a few will +have any real effect in the Windows envrionment). The default +file provided should help get you started. + diff --git a/docs/WINGS_FILTER.txt b/docs/WINGS_FILTER.txt new file mode 100644 index 00000000..b67257c1 --- /dev/null +++ b/docs/WINGS_FILTER.txt @@ -0,0 +1,67 @@ + Usage Notes for the 'wings_filter' Import Script. + +Wings_filter is a script designed to be used to import existing audio +and meta-data from an AirForce 'Wings' automation system. It is +invoked as follows: + +USAGE + +wings_filter -g <default-group> -d <db-file> -A <audio-dir> [-e <audio-ext>] + +Where: + <default-group> = The name of the group in which to place carts + belonging to a source tab in Wings for which there + is no corresponding Rivendell Group. + + <db-file> = The name of the Wings database file. + + <audio-dir> = The name of the directory containing the Wings ATX + audio files. + + <audio-ext> = The filetype extension fo the Wings ATX files. By + default, this is 'ATX', but can be changed to + other values here if necessary. + + +OVERVIEW +In order import audio from an existing Wings system, proceed as +follows: + +1) CREATE RIVENDELL GROUPS +In RDAdmin->ManageGroups, create a Group to correspond to each Wings +Tab value that exists in the library to be imported, and an additional +group to catch any Wings entries that may not have a valid Group. +When creating these groups, it is essential that a default cart number +range be configured for each group that is large enough to accomodate +all anticipated imports. + +2) LOCATE THE 'WINGS' DATABASE AND AUDIO FILES +These can be mounted from a remote system if needs be. Read-only +access is adequate, as the script does not modify these items in any +way. + +3) VERIFY AVAILABLE DISK SPACE +Verify that enough disk space is available in the '/var/snd/' +directory to accomodate the audio to be imported. You should have at +least the amount of space currently occupied by the Wings ATX files, +plus 5 percent additional. + +4) INVOKE SCRIPT +Start up the script, as described in the USAGE section above. The +script will print progress reports as it proceeds, or notify you of +error conditions as required. + +5) CLEAN UP +If desired, use RDAdmin->ManageGroups to rename the single-letter +import groups to more intuitive names. + + +NOTE ON AUDIO PROCESSING +Wings_filter does not alter or reencode the audio sample data in any +way, and thus does *not* incurr any generation or transcoding loss of +quality. At the same time, this means that the incoming audio will be +brought into Rivendell *exactly* as it exists in the Wings system, +with all parameters (e.g. sample rate, bit rate, level, etc) +unaltered. If you need to alter one or more of these parameters as +part of the import process, we suggest you use the RDImport script +instead. diff --git a/docs/ando_interface.odt b/docs/ando_interface.odt new file mode 100644 index 0000000000000000000000000000000000000000..4b1b91319664c285e67dc051380fde640d5f13d8 GIT binary patch literal 21106 zcma%i18`<tvu<W$+qU1>#>Af3w(U%8CllMYZQHhOCwIQ@$NA5>_f*|gwRWxUej2Oy z+Eu;#-LIS^FbE3JUjw1Qlt+7z5r+KF`mYJ`XIhzA89BPy8tK{ETACT?Ihxs6(>Yrk z0&Mgg%p3qVwno;5HU>^sM%Io1M<Z89xxbA;{89bO*dP6W59mKD0~>3{zmTq0mKPct zHfyXX-dj}!%-Lc!qqP~V7VCrlO_mnEh0s_o$J$`iNJb7hVv+ght{9JNE@JAnp0Tt` zkx4M#;xxDGe7ETaVcs7bTD{ZBVn0B;uGJ$8gCXF52)|tSzAb-^_?&nxeVjIg7+}T8 zko3|JYQE)cV|@~DAC~SJ)3r<8Ms<gk!VN*n<Kj9COSn!hQ2ul&2e9SdCoC8@^&44B zUpi_T3$=BJgFmon>@vEL+~fo5assn|uNcTDy~r@|p&>kw45R|o?1m`1I<7_3i!un3 zrN|;j%!G#ZraAfe;Lk1fY*nWVQVf4nK>_!M$QSx4=b`S`L(Vi;dIdFFB2C48i)|3{ zXVDf=iVSX0>33B{OtlR#x@gb~Mc?6xJni$qN_0am7e!5OhpE(^{cLe((}89zDI1#x z1W+X~S6me40q&p)p?<>puVpW;JJ-E%+fI?5j)>fb=BExLxi!af_tVf20pgqlfLoP; zP<S!ZjMQm7ks*|Nrs38d1<G?JX0j?bHv)*`wmBF!WX^w9G9TUzivbH36w!SbS0Hpk zOm6n>1*u;R{7o?!h?T7fOWng3p{$}NsOxO3tJ(=r#v-NBSqzM2`q&4M#$kz!192eR zBMxj+08!1#h<EGb#gA-gBZY(V?9rm;H!e+-MQgNBQGn?e3wlQg?TV5ZmcFeT#p+|U zm>7%%KKT!mkRmmt9;cq#?h_7Ub65$k-1mC;{mjv(MQ)X+Tc-J(DAMtHyFN+t{u)|* zGMSokm)@|fl&|@18Gh`dCPrLNuTsH+bX2#tf4>ZLM|rCCury+4J!!Un$21?0!UUfP zQbb0DzKPKXL$YpVPB()8yacm>0bMr#+thexQ%H}J2)nN#IP6nQ3{Ou)Dxa!DJ$rPI zBh8N|XWD~N0AJYe1*<57!bgnVl0YnHcKX8TE_c+t4BlqdbK#<aKIuXMx%AP`jRRHj zDlIJEu4?h%n`&dRh;E@oykXj9Hr2%Bpk3iNS81WGQOet@k2c*Cr?P35I)(uxcv2bB z7Z8|aI<&_g7fm)fEn*sCI&@9?7fKX(B9_2FEa<g`x8xZ@MHq^a!a>d;KE?tw?gv!I zO#){k62(porh|9tl(wG7N1^(S8P&rdZfNC@Iem!C#5hoAvkJC9dFx@4ZHVY$S%_Ug z#Xnp#cspGwU(uJR%?k)BL|`IE+(4*LKhu|oCqpxWw5F>|p=eGisfWwvy?7g^@ZlRJ z1vJyfqo1!rzQTw6zmOU)Jcb&*R4u9hlACzwaS@BtJEG0X-q_OJ3-w-L_9{O^k41E@ zl*FG%o-Pgh>dt_zmllSzYxup&e?Hz^WPjDCxxOImDa}3J1)IM4ucKBR?m;dr4(=|i zoVSl@z~4geCiQ+Tdsq&9A$pBy_xK#>R=~YeW8Qam>r@?YW^b|F@a4|=RbYQTN8U0y ze-d*lu=}-9HxJ$UeOXOhR@GaQ<!;tk@Gd`|RxwLsBeDaoA9i4=bWA45z=%@O;K@o0 zpdlC;d=te(xzO|q!|o{AQVK0kMTG@QZ;=sW6<BLkW>H?4h&?}pteg;5azaWIc1q|N zCn(5yi4A%I+#%r^&S$%{1~FeG7{t%+uv`#lM>fDu@%m_ooq~W3RL*c+r+I}T1pvj8 ziS`pPE;1hCpxiI_D>@&6r4Gsa#dOA0wlpT+6EMt+-p_}+4GYR_G1B6q1PIDS62T-@ z1IO>FnYlEPx)8V95dN^h%Oi)MhBQC?4hzkE??c$%6seeVHB&aI+3l+=XLQ4m{8|Kw zMDXdVVq3U^6>v6@Dqz|$nVKS|n@oym9g&P@6I57#U=EGa@Kr+@V$j-nTzSZ5ac~i= zBZ=&UM`SRnb}N7PkIaNm;-RXVkYn%l6jKDA_yyC7U!f5QI@yMZ2Ta^FE}}_;fegmk zhFz_k(Xr=s>2$~X?ZYr|5#eS1?DI3=L}i*%t{@BMq0DDI56M%NTR3HneSjb06E-j% z4LBLLHlLZcBEQSxm~Z2F7P^WH6H)vW#H23&chXfo%H4un@%qL9J-c}%c#Gl_14V%4 z?<H1UvGA%EY-M#kFMhr*YHkgfx-%S^rjPUH-;ce1w-?_^PVC_xc5p9$P7L>a&{i4W zAMi+%hMJl(;u3oni?)nCW*#yPYcm~zE36}3it01A$?PjgYi>3>@%ZdGQBSA&aJRIc zuCH^`s=cv_XqK-^qV^g{rBK=*2QUZ0GUw1oAp+|Xu)$3%{1}dN2g!$Ps#pz2x$?AP z<(epbTYk15{yjIlqjEQ;V0hA_;t=ch<?m^vgulAe-mF;Bf{WvwMS6I-q#k_)8zLXF z?xE<IdyE@)9AmDuDK2M)&Khi=wuk3@bIZG`2hYN`G(<axP>KICta-uf>JUrZSvdEL z<i~Q&0(&FYkn$d31D4IEBc5iHoh5tJgNr1P`jf`5XxI();BYK&*WfL+1)a&AL$v6% zJBL=U@8Fr*0*4HIX8Zv?*7PmNwJluu@gzp<^<COpoN9HU3z-7q2@qyc#o6!>OhKer z2EP%F%!43hFS4s71Gs<=b3aE<6)7RjU`~DsSm@iPrsRX_3$Ck!lcTI-8gMxAQ<jES z1=@U8;dE1ma}=)AK;Cg-epBDy(X2ZJ{!ZlY1d3oPe*TRjC@e|ESk-uN?wi!c<RamL z96=3QZH<Ew;DdKSYAS2p%uDVj{Nb`oP7)k~VRY31^iQR6%L@ebzgG`Xf2s!uM>k6& zhkq0gXYp%|h+mssf_+kN1qH&VjxKSh4u`kqj0Q~^&$q`#Fv5aJ`eEBZ+v2x6Sz5mc z2oV!Z&+N@?QpfwzoNL;iFZ{zrwY@sm4E;r^NcLW|5a9E4`R@XXXmmC}`M5oiW&Edf zzD`he0BV9ql(M6+6G{{dym|IO@eUkp{cYJOFX_l5``qN%R7X@PcYcS?v+D<$7D~p# z&}Up)Ol@_j8zr6bu}``Hwfm*=l#P`Vg0(+1I=xd7o!iz3S4yBH9+~G)gn_8?Wg{9N zAN2A>s>8e)=QdpHsvymBksC`^Y%_B!TZKE+f?;Nr)Cf}%`4pUiK379GHpSS^N5U!# z1#N3I#rvQjirL#zPtAv@kRc^-=8@Ep&6=DP_zjQ5N0%$5)5#5lhRf>_$9uGpS3a99 z<{AQ4FDJsQZ;GM1Kdy|htX+7I+F4P_lR*{^qw-7{8M|;VFT@`!bi<&6c{oNgV`xec zkFfDgyV0Y65$8u^6#mxO&gCN2i3Xu<mTMp!`virW##~aLB`sM1D#9^`B$SzN)r2G- z4?vW8p}|lLoTRMW+is}HmxNPt6i31;WFFZ+Qy~LB-SK^iblwEjxmBR20<&X&X8Sq9 ziNQavu?ai&=+dJj)^o5GjX7aT&q@2amgVz4^~Cq}u(Naa9G*5Z;gz2|oYy<%EOMX5 zs7Dz~l2jwAFT_KB#H$hG$=B@jwjFQqd*wQL%LjWMTBKHY8v=lk*tQ)D1R6HL(V#P< zGZKBUjjO&~u((sQ-N~QhKP=u1kh`fqB$5>uK`fb6!nIZ7rbhB#$9#{s2H(1a9pMRQ z&Fw{<DAA4i{Qd%{eUUS2T9~p?M|MI7J*?5PAKU+7%?kkCaGR57_EtHg0UAPk05YaS z-AJF~Ii;#wXg<-Yh@{ktV=QY`r*5e=B^9eN7T0wv+tMS<zJ?wk*sN|!8)FfFVFh`K zE46h&7w%)v9E9;36WVGzfm)45Xl20~^&^?44vO(R2d4RD7{ryCzUwV)fdo(Indv@e zb@Q693}jTDPW$t0+HqSlPJHMJ6j9jVfXGN}7(Y(IPVswBx56ka^+*^?4OBfYv;d@I zlY;MEVu5bB@1T_{)EpCH>3{%#HFv?Y(qKkd8<s_W10tvUH3uDuh*Z-G3)kv~x-=za zcTAo`!)<^Gj=K)2#Bs{+byboT@M>l}bctvq5}iatP$A|eU`RR#QUWS(SC?v}bacTk zfoh+Sprs#?zNmU7_|9CCr2%RZlMbtBVYm(=E{ny)IV=mrjfG}Cu#Vtr^W+WY<^J&k zz}MwZ1F478+jrdKVyOy<<`&an*VjP{)W?__KT^m`nZGyj2f@Mrh9k7+eYTtqp!BC1 zmltPFA0J$jHpdw>`Sy#|?FLd{zqxYH!PP7|M->}zf%M)6lB28^tPng~1f{?hR9x|W z$d~jusG7UqD?75%F1&=|;5FpH4`x~v%9>-e7#sVrU#|xgj2jF&K`$gC0tHFvL17?g zdyV*j-af(oijr1vKt-{_PBOa0Nv5W38swZyEFmF;`M4Zt(F-#cY22TLLjy&s)WkB; zAPh+!e7LGW(Xs^|kwkS4?b^X>5){P`r(XE==(oV)Lf2;+Rpb@ZQ@zu^Ew!xx>PWGl zw9j*9n5K_O2b2{p`?`|TJf=>sj=B*itK3(3!J$;Im!$Y<zp6=R55HGB_NxQS5WfQ^ zp6+&%-Tjzf(VOhZ8Z08hm)uXN4aLp%V>%NdRojAV0tzgVIcmu{BQck>mP=OgMp6$q z0B*Xf%afU?FRvNS<|h^&4!2`}sY<t~2=3_dg?1KnHZCP&txGzy?MPBUH@U}Cgn>uZ z6KuVDR&5M&PHN6@=FHxm(fZaaowzULM?fZ!1L(`JutQu4)6D%x2uH^fHn|!)z4S~L zl}9ta6S>Y%aDT)O%(Hs$C9?B^*QgKEgaS`|+s1s=ESH42dqH7SR+m5S(IsTZczt`k zwl`5Qk5&5?9f>@?U>j9RIjBY}tolZvz5u2Z^y^8{^@yPt@pkl{I1ii)b5!+&zcQub zn;)M0y&cPzk`vrlXOmCWE1Tt049}QpM_WmIV836X9<6kvhSdHyo&B(+T<3Da6^E4S zZPgUF86t>vT4n)%eS%9G4F@no5)%GCjWo0dA*n0f=U`vOPsHgWkLnys6d#ydbfQiC z6Q7Qk*DnG-)L|?%Z7K)P<-t`sKjOg%-q~_}Hc$-kZOOfC<lPTiU$n+Ys79iNd4r*5 z5<to(IzQ<=c<Q`0%*gj)cj5?_7~UFDnnX*U=6$unrtOk}P39kAG~Y$tyw;5#47zNU zSdd=1dhZ3!v=CVLl>B373Tn?`dp8fhH$abMVnpj;493Gnkb6gvPx;;~K=(bj0`FPy z4KDqm_5<}i=X`G>@%Pe>x}RVFP;0(775IB=f2hMiJ?@Kc*V7@_R~(G3PWlKFT#TuA zjHyiEy_4`>_D3R|x9i9(;Ek0rL6>FUtLf<LYc=|)Jan+zX5jrA{Qa9i0{l45eTT~8 ze%kZ63W=O5D=-$q@~E5N>D2ER4uYB$3++d4Bx>Rh()oDx$OUz-AIaSr29Im5(jm9! zLW-I;KG0^F&X~jRVCpv^Vg|ml(nl-#Zjc34zl_-?_aO1P6BEF|9IbvBxDnmIIa!{a z0`q$?M7j#RU-WoP2$=KC^8)kS)EB4LBEcYKb4Hgx-#eMSDZlf-93P*kJs{h}=vB}_ z(&iW)^o;ba=_7-i{QgdvO{wvFm+9WDBWotlVpQ1zgzXZfBMweRi4Yy8n^fu9E(b)9 z%5;lvUB)K5v2fx;Fip8Bmo|)kktILcUdn0bLk(%Ci#Li2g<OSq*KZgs+mt<OW7rY% zN6Ru>gg2f+sR#K+91tl&)*ODiSBumtDEaY1!4@Q3M=ljY>YB2w@Da$C+cC6B90k?> z4Q(f-$WG8X9NH%LeK`gRZTVFBDn+Z4-vn>E--6Ki31sStIqL&`ENLgr^=%AFmV5F# z8){Dkbn!;w<;_D@+M7EvR_y1HxQY+jic<w;j|#!-(6ClH(=yupz6Vzib#KtHx=2L@ zmasUv&U7;?S749Zt2>GJ{+CX(_7~V+6_<r97ZxWZ5YTtle^p$6HEI6p*Vrw+elr6G z0{UzI-TX0f)cdR6;^zBvA#gUbclgu(;UQuG&=V0DSsU0GnpvCh5Gg5&(6STp@j`Li z7#o`z7;*lqBSibBb)-k|N7dSa^B*D}A}4!m&cAy{oYs0)Mh={g2Au!dMB@BUH0R%r z{=spzG_$tgAu@GzwB@9ub8&G2xG({1>`mwxI5;@y{+1H`)0LsYzj3xs_LhI63=Qav zERFtZQ#sHv02t{0h5akS|KFhg!v1GSHa0f@cJ$XC{;|cs-7(VBGt>QpCL;J}R{kS> zj6}Tu%GF;+dAa{KZD4QocYlr6P|wkb_m2q<T6#uW23AD|dQN6GP9{cfy8j1`+t7gX zp9&20v<wWi^z4cZ%$&^3oD3Y?bpI0m!-J8bnd6^ZMr+_^@TZdIW&WqZ|H1z6SVJfK zzoX)nQ)FRd7Gq$Qrf2^7KNSCs`G=~Bk+snuB^!HQ**|HK{rgb-ofaklJ&BUFnJdA6 z=j+(o+n5^}IMOlE(_1kzkO(@NSsK!EF#WZGzjyp!2LIvU-v`XW@lR|Hj%Ee~f8!kW z^ev5O4Q!mO9eIfUoYB9TW>$J8{}<Cn|1XFC6KeY(NQQr^+v?ftnb_;un*IyS$ofx- zi;cbEznL8D|Ku8&{!uV+G_wD<h@OFsh>n;0pXY(|ub}>m`uA4;X8-RmKp1}>QAJZH zD}8G{GfM|L$A2vWw$>&GDN34}Q+3<OexMLC1Y+0QXzR4iAWc0Re}+-@_T}Xz+Pae; z467I;2$;#sN7ea;$CKUGBlkQ9{DRWLN6BTSO$G(&j}mx_01BJU_7?);59xykp4Y>P zHMZf9DxD$ss~?-~dUZ)JWTl5Md)%VS$}TJyp!b7^TITmy13lT0D;~89W{BF|^qRHH zV4$Zs84UcK?lQtZ!lS5b5Uat4P@M&D9)ZvqFEJ|SeL_$mF)FLTue&qki*-Bl`kO*a zqC;W#A;&RbSe@v5dn0_E4r+9u_MIKMlA}F1#PX)h^@Hkk9=Y2s-R^rDHH`z{+wI*# z_df80&u`vbmh^GJaonoEwxIpC7k*LOd@%*ph@|$d+r0sqc>gML@oilr70P0B>c$=J z{sh^F_L}`=cD~%iViZ=lWP0i$4=prQgGP3K)@Z^U;8awSc?uHOm^FE>Qm%o857Rj7 zHH1HSM7cz*IEHmlIEy_8`_47*%dF8$2i_SID2YaYD(Rpvx%K<QIZ3j&uaCt066Mn& zSagb$KD=cE!Ah622M=Rg?`qZ5p@i?jEL5YI$4s677i0gCS$Eo*-h}f(33uBOUhc{6 z){|{5>_xTB7}?07&WYz{%O?Xrlq_g7c-cD4WeyqNpM)7hgW<S4b!R8hShdh0tBi=1 zCHwNiaj}E0%4VipRYPPIhSyxwMWSI_jVo^zC83t{Z>7CF)YYx5C};Z!nd@8;XC)2H zOAf&+@am|4o>?uB&WvCR-~@B<vA?U@SD-`HFV;*v`~;pL`z5`ma+h}o4sky?ZFgj+ zzB5-dWKN&Le;N?7y@2}m$_$3?_n_BP)K+&CXDP5OoAiJjeuY*x)hVU*#CFO^SEQ9H z&A#O@NcaA(*3Yx2fi&BG3!>HBn$6~_{pf=C)0;j-S3^YunN;l8_lR>jXJ@}G@cJ4^ zda)hlhjOgojpXH?BqnE6L`LKgE_dII43>NAEPt=S%Dc{=M=TFNOwVXsFK4SG=9nQ( z+SmCi3GCQ-@#?*78a7rgrjMB7de*jxdrhicUt#O(N0AypaEz5D5Q&d#HxWKP>*`Dk zhRenzaNxhT0$8*y7s4f1odshoc{(bW63_3@L;y3icK1tNHiUFmEp?sB1sl(6w(q^* z--d=jP4?On0;6Y=*!@1l)}{4<siD6g0b;nW(nv44)v})#E=i}{s@^U>YcGv;w>AWp z;_=CbIA%y8=A^n>F&PJ9QVoij%(A^_ycemiNL;z{cFN04hY0FrW}SHC9h|?lGP9i_ z&G&AJO!A4U|Msw@@*nAI$d0g1SmDoWZe|_oVtsmEd~NU!)j(WLR@>2LI2-f2g@`na zBZq;aQ>yd|*l~*SV~Ng0QFBH{tfMjSGoJP8cY-Pi@27iDSAD+8B-iBs2D<bF2c|%z zqC(SBHy-_@-w?o>)6-ejp}zap8m#O_R&0Hg#Og9fk8iUtuD0nG+P_j)Q@F2L=u+*8 zw(k-qsEkNTO4{#EC|R0@<_r}A@=Zm<pWYKU2p!xUi$}#%=S*{z@1WQCwTVl=VN?9# zXwM$IjdE!LUS!>f!vS>`cg81eN|$RRwIam>I({A}iS(sQT=<)dlNn#sDlmWmkW%4F zVGt$tKE?9peKf~I!`BYgD*^hGL&fISXV?dNpJM20T*-XSOI3}qpfD{x!-2h#t$;#z z{j{AHE7YA%1DS?1*QX1hQmi=a%zeIR$MDUbhkHWJ_&szvUb=M$8$T+pk5NO;{_~h1 zFoa%`?4s@0f!v%l&q#r#dR?TJUsc`111Ta(u%1sfiz6iR<=EUESFN^*MdSw-Ch<0@ z%eh~#DACP|#p)v3#~HUC$kwWgX52~ED+K@(8Hp9j0H#oaD+$UpQLHV+tal;y(T1<y z+AX0<BG)b>P6m+0>zqIQ4Wu4m^-Rto&~m~^<`bizT~p7d|D@JJf##y6d@gscWi2-% zOT52&5pSjNyxIx`*EW$+ko<J>B(Wv?dT5^JU>&Bs-#Lz&I~OOlA<7<K)j_CZyNEV1 z;3a)@e{>e7Su>YatQ&mU6Mu;qJ{p%ko^Umq>0IdIkM}&no5Ys6<6)6P21F4AyqWPe z5j)Tqxb3k1xg?AUq)_6%hrde$-7olh5RrOq#*(KDv7t#5D5#ybxR-^xbW3H-|32r7 z7BaVfT{6a5*E_+Tj(J-o@@4jQMZz2|+0bvelD8L_bJPP@y}3U7b7lww;X>Pb0$!KH zuJ|NRV`8o4=fkTuWtH4MNQN`3jMYs<Z62LH>B>#1B*)8r!P%f?M=@9KK#m@$X$}>^ zDx?4HG*+VMQ!jVPnCf>_7LA{fuUc9XDMT3p86##neV<NW)Nmweb|sKI9(r^&%r{U; ztyPHM^d}0^<z5-SNC*=M`RfP}%re_NR@l+G6w6c|#1d4&az`P#6U!m-t|#+F@Xou4 z37Nmi7D+d)?@nzsS+vj`dU%vA)f{<9fK_93hqx~$&S7!@@LJ#}WE5u(LGJN+Cp+Oo zZjrbqW#Q!AJL!*4?P5iW)4Jl$>YJMTGC)=>vo_uey(`eo{g>&=TkSf-uMRa1hBUd_ z4rG!gqB;&c^ST}1t9ueh9rIg%ohuKM?A>TO9TbIU(=Ggrq8bzwX6ePFkUM8fC|?mE zV!PK+oy*+Tb|;^nN_t7~5x9Ym8f??I<4-YRR=gCP8dBCX34~W&>69o?G*aENSS8eU zJl{zCCGRr~$uQ$!cDB}9OqtfXq>U>WE-k}$u~QBd4`}D<4vt2mtzlU5P-S-(7O3x7 z5P|{j0uQPV13v#TxC~Qrnt(z+V8+U|RCQ%K5z_&;-c&SZUe=C>h4CX+B}>DXWD`8J zM1G=cUrssdr$uG`*r4EOAZRi^s2+H0eyRZT!!=dgga&ej-UKV~(X1P<;+z=Il|r0F zk4}Ps@~365&Ck2^xW{ANB#o2o`=vCAE4v^1xGpa06tki`592}s$vGJFw`eJpF8BZk z_k^ZA!ZQ^PqZ+U1evCqF!{c*6ha~viWJ3d0h}hK-C6?nk-|uX?G&OHs*Q0{N`<g<V zl6@96HEy9zSN*PVO8Ia+NtV6jHUTkzO;Ky}wWKYx9E0A*yR^9&Ly!|5a;|F=a#qTi zNIE_Ukj~dG=co+os_qf|-tmw9rU_(Bq_YAeAKT3-RyCbI=0|DK3_8_>?B1$kjSDd~ zYk!4&f8k%+JSu~RbZ4^=2f^~iKlK^&q-YA1iR&~qJ4zt6V#|wLOBS>q{OV?95I>B{ zevuVY*{jf{<#Q&2u@AjTR)I?2Cm*MCu><xLn@d|)EYA1K7oOYf6A3L^Rxd-?v}a80 z(-;SsvkHVuN`dp5;T;9x!=?2l6Nmc?Z(W^D_{<{bA4h|(KJ`6a<SxJFE&!Buew>0a zLm^laKT>}r9aa&eV8>g8x+g3r!)U0=*>%w;OEZCbOAE6ZWLD!M^zW|}Yz~;6d*L`u zzI}K70+LC)HD5~?$?a?0YeFgIt?|2;Bt`DQmoxc^^32Kjy5RjK6!Xb!@L9XrI^1-L z-w+y{=}5I6WzHg*&eh}g;=~oJ*tEYYA4Tr>S@80HIMM;Owyt%VJ5&%g+L#(pLCnI< zDXpu55o1+C8HS#39)wEt(s^8j)SDG^n!1@ugLIYGFD%~Tajj+Ol*oWpA7q}9S$zOr zn9~UP>5Hcrk|#chljvt>6<JD&wXH|DXC!_PiYcE8W89)Vo1hHe0@V{~PMUImaJxyv zTSvPiD6+z{=uPdI2W@|2z#=&{Lg!htQBDy7J=+nhQL5xam6qO~sg+2L(Cz&x<QR1q zxEyw0|0~3)uY+0)Twon=`_qe5$m^K7u|kvLr=k;DsKgCpWA%EN1WBeD!l5((xDqlZ zEC`Y)%T1B(;ulZdl8CIlw3EYc`n6Jp@~6zMlYqw=kU2?*WC(B5y|LRJkzXt1U{d~6 zXAs0h3JDWwK6eI;D&5jn167@J5fn17<Y`hK$X-towE`P36?D7204MTH=$FFp-xOu; zMF@2avhj#I6oj!Iv%SmiKeR5+c)iWewbOK?FjJ3QJ3zR_$yk}8aygW5xw39ZYJ;$1 zw0}}IGIgqx#wIO;=ZqO{i&?r@ZQ02a``yy=uKJ)>#kT)6)i${6xK&K4Ugo8^!^cL% zG0?5}*v}k>2)aD~o!6;MvQ(`e-iEMoS{VIp1CuPs--RTGF8`=0KifpYD@qSk0E^W& z_fukS<ao5Ip)ml>tINSjduPY5ipeGFW(R=ektaC7uwO@9HXg>8beM6fBMT7qIpGoC zrMcCqO-gQMEvSR~1mXK&ZijRp>|lKSRQCS7jkI)iBO4mR1cnp)ZW*qI+@iVi!O2Q6 zdpGmMC0SPvoY`95oj4_KX7gq7=qF(B)tWeg1MrLep)7e1B7#+yiiLHb-nAOQS-df0 z=Keu3sLsau^Z4|gpbzVFP){UOVj!oW2@2Yv7rJ_Y(Jk;{(0MIa-=7(Fs_;$}F1BmM z0<;nijXA7kFADR4bUfiU&XVfrbGx(EUrpeVCCL9UH-jvZ<(8XHUU2&WYwRY?muz}u zI9Jzs`22w7Cx(6GnqEpE+tL~V`m=urHqDpe@_3-QU>80L*jNVV`9UtGQSXxrGU#_4 zhKy(4Mrv-xL!yXmtSxWdP|l=POBB++u*2J+4_9S4Rg;B{xA~}tz2|-+mxCrm-JV`M zqLj$k{M^cUD>hgs>H<g=*x!R<Bztzx8r}z!fnc`Y4ndd~`kXrz?$1sd+60X$(P>kv zV^&=u5NjO2m3>9=)TA1ikCO^|s@2Z>nxuJL!xoJ)`6cH7y6y7WKYxR5RmE8D;mGJ& z|K31b+$H!%0u`9I*r&~#nqK&JZ}dU@m1m<3uI?>mL#J<VUQ|>xQK;;zS5j<rwN>+K z(XZ~MePpUQ`BSU_nE*aXN@)>WWmn(g=we)0--a-obY%pIGxU_*!!D~m`cX{Kub94R zZ*tV}g*E+{l)JNNaT>EAQ`m;A$Gr|*uPsp^H$VDfFh5uwBOdbY_&XlOJSm$QD`1xo zSwANOS+fnjT=ku*hi%ywEi<VT`Pwfv^<*6)=aPaDnK>5kccp5@q7F~o(|MuNwE65? zgK0m^GSzy@6QpG$5883X%LQ9YFR6q{Jj6Xlj0tjiQe~L_B@pFY2Fx9Zf;jg<pC7WY z<avoMN{CrqMz<4K=AJ0~3%wAYeiLCpj@HTN7s`tz@PUvPhY;*9dx3iXt9in5AKjDV zM`YHg2LRt)$<OU7O?iF%xU=h~@~j?T>wL%_c`x0?_naVx14;Xu+{+%K4e_qa9I#m( z@U*Xm>n^n?d;)rF8+~^b!S724o`cCAe5K|h(3J^j_m$9Bif&<{bwO1u$77%;LJ0Fm zxUqsrIYn7I&FpfAvDIbR1~~)D4@*$)O}tA^N|S+^>V6^GfvL&Yh(DHcM6&Fh7S)UH zq6_eOwIoZe0>DX;XUEB{3>@7KP~XSJB2ZW)m>nVOZR-XO5c;$ms6XF@WEv8B3WpTT zq=Qi7=NhfAbcq5XY1=;mwGh6vSp;9B1Ze|Ngz9F~5#76#lL`f5ahm6~rb}5DL)skh z=)CQ3;!oyCwNQ4@v(qQP)`CVV;i+sgWvs8RKtt!l&aSA>pK@kL14tQTJmsUq@v2(0 z&;mxCvZO;0j4FJ(RlrMP43{TTgNf4Sr?|WvF4~*)zj;^6-U0wfml~0TN)hvYX8kHk zp?A2v#NIMl(e+kj;exV#9x6io&=~tQ!<!EYVd#AudYg?ap8{`Qu4rnO94j*lyG6i( zjsqiVoliB`^~s@h+q>N~38Vc*{4I_c*sroJ0FIh&lM#8Cz?nm}&_xionD)HJoZbqp zPI7L;UaugYl&q;0)T2tshhaR}I4gs*YqFL+_M3AGbiGckPupHo0!pbH)vAqfWz?Cx zXi<OxIRN{{t|LKHTFZUOTrEWyYc)P&-wJn^*dj1o2yXYPo<Dx5g{dq4+{jbmo=XAv z<wQN*lh}~P{BbLPGxj3l7J!Ln4;&h2B`O)^kv<U)y$X8;VdzEsd;^Ll`n&%-xq>wz zf<=pQODs$rz<pY_OSEX!?QEez>&?g`X{l6dpJoD?oc&JiS0e^}v}f=#L1N5khTLeW zEl~698uz3A<^@QhfOAK6r_|xqAfs^4q0Kno4vL8od1zRSUGj2uG+fUVp?-#|T_{{K zug@Dg>0C21=L!m(XM%eRPOGHC6>rSNwAqhrJ0&))aNV@y;d)GTyytm0ZKG`dDO$U| zIKYpT6{%}q5N>A~`Sy@pf_dOv;eOkT(YQsuZlaQt5%#u-Fga5u5&HP~#Ux?6-N)E? zc<H>Fv_z)`JvOdI6Uyr5cc~bqb1NBMw1j+%XQ1Hke?BF_rZu)NP50F8HHJIXNkIXB zuI%c%Z#a&hsi3cMY0{4>F7}Jha3{GcYnt09lpCNd0dR7rZpj`DaQNhTt<hL)Y<8&a z5j~}y`|^qwN$h~3Ess{tKe$0Os!4Yn&|=63X$gLJq;qJGeJi~-&3sM6Fj*?5-+LeI z5{1;E^TIV)(^!%)9N65bu`vKrs{iIu&ff1XJ<Fu)b>UWt*bWc8fK#w@{4j2rt|Nk~ zR*`L|RhMG-`nrgEK>lC@{V6r()eua!Sxj?G_Gxt=Y3i8~hG107WuI5UggR8pKi47u zVm_)w9GfELv8xpj=#ZYcOupLgOk@tOG=QVCL>5YUhm{G4kg;_g4im6pr6yBVz)50M zfmooC4^dFiO-j!bA<KeY70P7^5q5@3Xd04z`TlzHQP<Ji@WM20`?LE|%{ga)&G^v< zldeN4O;h$%PdV)@nl%i$TDRISGOl_iWPt?#tTFX*OKQdv2b9=dW_qeCa~Z6)wHeYQ zGY+l$<JQzCT={1ezf`N5(8wU5&H!r&|5glx6FyI01Q#N^krJ)IxQO?om4~wN5rip! zWsj_AYGUp{*l?iibAbcgGEFMY(4y4;i6?RD$E3fErCAR!6%@}m>2b4A8{}0y_h2b& zpT|e3;d;ppDv!Z}eifaHN-49VCWv{h=om)XFlI~8q;_QLc;s(!7+$)e*4)8^2?=sv zv5{XHQgbTXt<gciqF47y$Ng};@}^K-O(m<UY4kOfg(Aj%F53JS=CRcCONP0w3ScmD zv8#NL)JxMK50()vw(K-(3E`xIDfs9EWSpj$l`QYq?fF?$no-250ibL{o{XMpQ!bRa zTT2jqs;^iWE7t|xId6ma5LYxzSW3b-?=&PV6W;6wPe<WlAdORC^-Twb4l$ov*;-m~ z;Nz$?%ou@tIc3wl9|~(AdoD@CyXv7}KD{5WXD;N<T&<MVH~o9P@P0ejp8#pa1w=jd z_U=LOSaeZ+AeQ^LhM%T_MOi?*>TF7p7%fLeQB%5+5CUCcgUm>XH-4`Wpk2NO&)W*0 z-(CkJvnuTn$AO3(gU<4k2)XzR1E@wl;YQltRl9ketRV``Ee{<m?mz7BtO{4%8^SAS zYX+v+*UHWq*ozMVkz8v|U+c|Oai)%~D*y#+ghiu0y~WmYgw93^^szm;yUF?NohN72 zDpzi|sOgAQm+xs=%f=d8e!hLksTr4HS*b+u4kb`!`F9MqfRpAqX)D*V81FakEe=ta z8r{;3D7h7_*@ys6!r@BzM6yz;KveYOmYQVQrf&W`8B7j64*Qar#?9`DR5VT7YcId! zDcE$1K5$WyMl>v|+eC@f{*^@4=a@rY@(h;7qNNc^0kg%Z8j>N7f`soiN(DX;G6<(t zccT)-=&v^S8-d<wu+@H+mbD*saIwhw5AnG7^H@bqj5EHT1^MiFZs%AU2<6|rd@9oX zfAsk>(BRPVtA+xet)8^Kt<6@#uDsuHu5Q9?a2S5DybUz)O*J*>gG`f@1eHuJ+?I9< zhY6Te)#}pkm=v8}Pxfa7VzfMT6ee@g8ZY$}5(D$1kuXLG&f|zXmM6;6+oVR&6?aI4 zjrxP48m!D%d;c(kqvgQy!xlbr;U2H7*Xlq${-Q8=mrVImQY-dPi`AppY9w)K38_we z&J5S3fzcuX`@m=6v6n-K9LLW8c<ZCX#XKcK)__~lw(Vja-|)I3C|xZeFL;?YrneI5 z`b?V09&!`ao<xzXibuZCfS+CbATp8*S2g)*9r_t-*nb@1Uqx-SwAVL(jVM!#UtVG% zSrA4z6!zV5wE)rPGG`<z7?!8I!Fv0>8V+SStQxsq^H$f-z>D43k)MlDF2ccDDvC{w zK?DShqw!2u>C0k!XajN<n2Fi$`JA-~TO|_r)12_is*B~mMsG{WYwJ!>$MFaf^?jB? z2LeSj*Hm5g7$o}>(Rh9Upkse5WGiHU1dxqzsAzhjWdK%@Y>;3IbGqr14ab<5>a~+i z2X2B91LJ99Em|37`Z1<ae!d~GS=tx3n}HhmlL-Kb`h~Av!y3$anu@Su@0bLe7cng4 z?Z~JUuA(vYTf-p8PeEb&+<B_FLfNp&e{H9xMy^jF^=IwJhv9_yU?Ks`veos6kg7+- z(o5lXBHS-y1CAsh2v|NM4UMoKOzJ2oplbw>C9SgRGxt%R@g`$t7IoNS;ijKemOEF? zym((`{iZh?T<_l>YF0#WDJy8xT~oGzdC4CY?x{&1C=b`{afl_BGp*r}4UKTDiO7_z zCCBnyHLWw|go6X`nr#%4O#*$Hg<_M0MTd&d6k<man7+rg2*!znbR@?z)P-VU)LI9t z$zBU`uG(^cO0;QgkTyxCq;%&b-D+g^{<``h^b%HPs&K_xhe!66|8AX;*UrZSI~7|A zdf#B>S@?4SWrK)C7IEy3$`i_}i*IE-I^k*T@@w!LlrQ#?Ygtil5Gf(zMC&cx71hpf z#>F{51sUca<TB$@rcZq5_vhD5wzHSEOOIG%gKuO_%q<O<<W{gP4N4LgOaM{LUJs2G zUZxeE3!(nd2x7+a9KRcgZ1rx)qLX|X3}nQ|W0NnYnz~QYhjyrMy#=puAy}iPZ=yPH zad}HT64hAT8h1&miBa9sM{IPjNlWp<-8I9)DxK#ISZtW@d}jw=X|6wxAB}Zd+k<ED zGw~PtYpnQ!h&|P6w`q&3?E{v?ulq69fhw*Q)3YHY781(pYD+H$c@HkucQ7;)6B10% zcfCY|t+OskrXs;M-OCx+6=LbHHRX`>TZyw4yJN3Tnf%;JzstOg!9f&IVHpQ43qaGH zL^61FaKnBK-4K2`qJpG@DjWa$rWFya)MK~M-_&{UiRU>8?(eMuX`NCa<B`u>H~3+j zc`V|9naM%l85e6g1->{n-hbm+RjoNWX&zq%MHa6@G`!d$%|8+J(BR%7RdWydZe+i% zCE^8e(hPe7L+n<rnw^~uLxebU*{bGbPC6mF89|~sqi;T7=@xolLh<YmRZ>qxKQ*)} zJ&Wy^^{{Uak-5P-IrF|7x^gw&hwTR>p{Ys-ssrwcAKsu@kCib$!~Dhu?sLK>2%{~p zS3V-iuH)<-2LLq9uEKARJtrR+ziM{S2hgPXyN!ZBS3o5-kj-_-Q*h$3zme_gWDkf9 zhLd)01$;=00Zq}|BeD0sZr0*NnIX>}6(yyen3NGBkiXwM*m=FZ9VAi0hBqKI;Q1$+ zh3LwYzQ8n$mP3iPXwanYyL}&uK$v*bgqrc+ZWQv(VW*5}8<IB%FO_6EHOkDhXzO2l zAr+}z7$hOA_r>khXn7sE1dc+{;UKr<aQQr#=NFPW?Ra3aI&)oaN3eXmSzhPw+E8w5 zO0+}w{RLj}rTjKUEVY`Gd5)dRKoqn>aOOd|Kay>%VXy_H;tX?VBZK=bll94Z$8UB_ z_!#LnN#v^^%_l6026?e~F5eySF!%LgIw~)E6GBppN=^3?$0nYVmnOT4h71lW5CY_U z0&l<SNIFX1@Wubrd3CCMfrYI+%_Eeni+n)=bN1aKg5HviMq46kwR|C}+NOR3@rhRP zek8bd1NLQGk}nWX^UZ0_Ye47(l|``G*Wri{yPECPKeu)l^okSU^=w0%A^)5^61=FA z>M5O}W5XaB;yKB^1;w4AMp-F!Xz%~IE<DYj*hKmg($?GVVIPno^t6Tc=_Q%wo%{y8 z8+b&|14opfwW^ioz5%fyhf-*7V{1)arv5H29M<=Bj{n1}Zp|7(ou5u@ww@`YDq+&$ z&A330AD-4H?5vP=3r~M4A)nI(NVldS)(*MQ(4l-IiIMMdy{hz%3R=-;Qhnm6wrH9C zE-70POss~o<oxFiX>?MnIA@xXNeGxt-vl&UHMt0yw!14hqJE6NQw|anonB&o2d-QE zUG0tqC`Pqw^}Z~HMDL@5Xs-Y{$GL%|?$6JJdPS@{e-uZG0Oi3x^e)_1<IN7v8B|-| zlJh?G549$#YXcjNT_sT0&h|>Te6P*+bFXzat~f-*l;#9}nSxQ59E4Nda|BR*IA2_k zj-sx`1~!{DK;toD>Yka!wCTv_w^3lwIl2&OySRI05pLJ()Er+rO%znd6DxaqT<Zt~ zs~YsZdjk5Ak)`0)O}vb9%==LYuhc8-Ko!xO4flbCyu(3_-_qeZae);#gD-`4IZ=eA zXziKBstsi*uAn$mBqoZrtb8N}Zi=PJ24vAOotPyy<dgi8NaknK8iliwm1inX_&1NF zbq<{fl0u+LzYpD~ks*@Ix<Ve@n<tSBJ$+?__B<P|TyRaCO^2D9JAOphlU8J^AGFSC z-f_!zC4TCBo4w)#nw^14KNpwVZW|KXl-fulfjraeB#XWD26wue{dtUIuO<hhZt$FU zbwFh2lbB^nC*a1<{H`W<urNp<8rN4JtTiJqN+B$o$GR&<<ge`cRLDFQKR@|xm~2&C zWohCN)1NIJH`syjJqsv|P`BvNNlB*uxdI*1(t!mkW&)&RWen08o9+B&PCrMNTH3+r znP?3<{7|Nt0C+%h5_#Q=x7*l-EeuNiJvmd)@1;pJ|EVJJPh%~rL6hw$o`PPRAP|ZM z@WJ1B$ZZLp#PNuCZ4kV0XyP&PksoznG*KLb4#9C|O{uA{z&P&`k#YfW^xXGDg(gja ziiiZ}tBxW~9kL@=yJFRXjsT#MuWxX8{17vly8iNw0gJvHWHpBl+eGRBidvX#vazf~ z4(xu_{)QBvK=C1=IUl1Wr*dgrXGVW3?lntruHKARNPz*R9wl@0RRCLGJrIS1%1MDe zdDl3}Ezml=hnhV<q_s4fWi6Z4cTc-E(?aQ`mG8=9V2L9^-#R88(wO*;_C>+8mK7tR zyL~8j1M(CY1De#N@<Uwj1Yx&n!|^F$+0u76QxVRy6i-A>fCZJ^jkPwJB$*-Y`Gfh$ zvVpJX<U!ymC7+eG?&R*WX#B=rvCeag=WX5^RGaPi{a&>2{C5XajsXE;t4z0+)hN5E zx<b1^{pU(Jca5&{pQp~!stVfVv9H7W5NZLZX9KR4fd+3*`chJ3oZ2}JI@PA+=0taR zVa@9hDw}ua1h=MHheXC=lV&E#DFy6$0x0fNkPkk={`b+sm0fbI;j#+j=GS;u6qS+m zm_2=0R}9p59_`SHU035`|0JifAx3Ifb?_~ix|*7J-%p4M*YYi<)U>UfnlhK60G;m0 z$hKFe-5?BiLf@Elq~DdxfUzeOK5JMGpD`wPzFk_!kj?aqWB^|6Ymq8dj3uK<^t~Ml zLiPe7CJBW)thpON{g&FJf&qqFgb*_wHR4$_QVyJ85kMXv8R`>8ysoEWB^{ZQmwB}7 z?cC>Z+;*B;vYZv*Mxa7BQVZ`v62a)-Wn1EOt?S$SV6&pnGdi$ag+kAgH~%G-PG@<G z2)?1yaPsH#we+dnjCeS8(eTIH`UoR)8PwJq-mzj+``qqQb5+n-OpY6DYNcqcfc#z# ziZx1Z(@CC&pQRqdDZ9`mTKpdO5}DB(tO2U;4IoH_D4!>EkI-;tl~bcCX%s|aiJg_# z_6i&ZA2QMwh25r)Y2*^(0EyE)-E9lz<c?EfzrEC!EU=dX12Fpb@$bY1zdi^-GKZgA zcehpu(zA#VkrJG5kJbY=#-YsI1b+j$5K^GY+s#eTI{ThBFJ?t<s?vj)#?k>T!68d7 zxJkIhr54aPbS6Nb?9o0^j3!~||Ca2pL(IY>TyHwz0r@&y6NhsdL{*n%G^b_mS;z)H zZSPwqektz!@!|mPKG^C{s<iYh)+4sM_+9xp^=mmLtasBvE|$m~77>S#;gY2vS_t%H zrm!u}Chc(f5rn17)H<CT>DJA*2$Z@h)Pas`g~;kM4h8cQD^c@OhYKcRwY(>eqDX^= zucz7zQj|_Thnyle>(!4S*x8yT*difSA(X{()Q-+I<D>k_R&W-zz+X4lxUd7`xooG} zEt#c3j7<>S{Gp>}Mz<)^l!Ka*&v@7ezq2R*=SYuT+&eujC>)+Y4!jG--5ClRAS19C zL2H4Jo#P=aKK7-GUF`s$=z26>&>h5}W6Rucg$lc@LfHGNAwmACbWEA<Lwtl{$&+(j z_xILq+Khc^ykAlret+SJkT9zG1DNdIWkez2M-<%6<mf_6*cv+5D7dB_r|9BTeHHJy zK30L}Jx`kjl^c6Q2~%`vD5Wm~Ep@_`exzDbUMBrReGwz1lM%_U0aFmqOv%dhE&dVC zqjEU<Nc;3tZodjFpBz6s(h$?#uLP_!-%)5(RwJ}<_gUX=`J?YQ4;G+oQXK|xS3WPR zINQ^oJTnIQACNN<JFTyG!C=>#Yu(hp9)Z7e9|U~vDDfO@9bIZ5@P&W7<WD=mGF$2@ zAEnn0T!RWEXhQ2<oOXIMNO2<!TJ%ws8m1R)lhN|<!YwM<723CQ$RMEWYhf&e|J6q1 z<z;n=NR*x4F_X!lnZtB@@c@Qpu7qNpla{tr>Jldt!nb{>HMxtKy>~=NDlI?pg*(9J zy#_E8TN0)@T;oNn1{uVeJaN81ZpXzsIY_HosLloUNwz8m%om|1^z<CL7zVQaN=SIA zAXkU78J~ZAEp}j_{Be0hd&C&@h5+s1k`>D2dupei{<eZ+*Rva$(iJX3W~W}OjY$(I z+d<{OU8yvTcB{hTVVkzKr<Y5Q&T!e5$MmBvPZz>?x+~bv&Oc8n{vO`z=0iwF>k&4+ zbzwr0XRw_9spEMHd0Yx?8AGb^_5-+*a@Rend_PtKvGSBLp5RL4p^UiAkMX$x*0BV4 zgOk^YBf}$?(IUVlOtR>FEA5WnD#*~DYT-c0iy>Pi?Yfe26bb)^49$WA`HTJKA$m61 ze+|V_UB#4d)yNC%9D4$HqnN={iWOPV^rNN^goiOus@Pa`opmkiuwm&#_#L?bxLZY& zRePY6xOofXK&`S%rns*<oP?q9tFyE(byxX}p=F}C(Y_YAy}d>A^dxL@_fA6s6Vz7z z2cJ7Tn|m&r^C0UMC3La#b=8v2rQ&uDBB-3Qs3rqDhAxL3>MG+S+bof!dx>ZH4NqMD z$lcum)UW#s-87Ve`4fiQcm@gfBTvR=4ddsqRTA0tQgAis;c3j|HquiORfE%Kt-w~i z$Jxx{r+1LX4*AR}>}XNk__&6lcDZ2et|_OoL{<9pHXfhzu@uxU6SAMM-cIm2-5;Mf zj_wE&vl80Kz8yl<Z+e~KWjfXQ&j+`mYU<IAC`yUGKwc3;3Rc<Y+s3ZnMblb)C#U;D z3O<&9`+>h-(ZV;5vkDN0P<$jS&H!nxGI#}Ij@=cbG?~eCf4u4w3LN#dW_ks_ayAL3 zz>>?3R2-UBaPTY$%nL4HK_%xM>Z&B*5xrK$?yT=rnjXhT1>71~vRYmh3cEU<5fCeT zx+?)Ys<uSuj?Zu-pAT!oy_t|NY~ZPT`*6ilh3w@ajE2npR`&axNqg0fG<_<^qYcQ( zjr5gqYTA=G7V;zh;TE%Tn?^IqVdLoao$ULAKZomcwa2*RXU<$tWF6@aU&(+9KSf{U zn|Uc<PyElH9;5UK%rlD}u{Pk?xsO*(JK=iz!el_rbZFpSD4hkhEtr9h@>Kw*Zy~QQ zFnFX6siRkK{j-6TNsH4b6VVEijfGu>%>g8>)&SPS_UH}M#_%vKG>vrcK?K();jU2l znp~ifpxa53vA60x(R@vW%g?*A(<BIqX9R34rf;n%>tATJ6d_!OjiCl?Cuu;<yuU!Q zTRGLMylMGfWn~eqoVs=&r7VAYleSh34g&;2ujH!fRa8k=oa9Sq(slir$lblbJM9y9 zu+)01gea}6&01P56jjvI&GjDqvgd;PZ?rp2@rDgm+iCp5xN|*$Xu==;_$z8H0bc>m zjkqPc`JlLf#*)}^Tj=HcI0EHB?m6CC9;TEDx#V2o3eji`d4J@TL&f7ha~n=;dvudS zvYttIje3PcbKOXE>_JYfdf6cxmFiJKt<{zGHOTQGnpo9wgxliWxfDK7hLvxc^xe># zN=hi`Mmz_?>?fxU(81KMH!KPqWHPOPe#h0^ORycG=$PFt5il(_=!1<ss57%iG9)(t z@HyJ7Y8i_yC=*U8Qnv{tLD`zYk#^z=mBqlj_McLs<?Bg?TvI|j5b<7UBlSs4w`7CM zZ<W~R_k&k$r3;p{*D))oh=*9+Y9h>6crbx%T(&jN!q$7WhIB1}x?q&neX*=JImWGC zYVut0mlHGbU_!DsD-mzZCjLkSUSgJ>yhofr7W~X4Jz2_u(I6{P#4>t{A90zd;gRYu zFH24iYCQSnP8A#q*I{-oNI@D({Mdk3&yQO^{W^kofUqNPrd|(`gOad5egiOFG^77; zX|Z$`CHH4f+`O1sUk15t-psGZ^%mdUV;l~vwHY$YUg7A&h<+DQrc0LP*&SHk^%@?1 zm1`T{Bcpa7AvU+n6Y14YbXrLb_;H{%3|ge&TY0xtBa>o8m^(v0Scj*JJ0xBZ-gAxN zTNd&$5%Y-8GJ)pdWQ<q>^=qmQ!7^G!qkSatynQqe&2&m-jx^q4@y`EB-aN0kF?8}5 zfqyFP2KgZ!z#bGHzBGAK%y)6(@;2)z9h@(Jtz&S@bQ@S3G?>Mnq3HwC#EkAXL6#3= zM)<hYT70_08`$&g{Smw}Z_8%^g-Wou9$_*g^WttC)i&j{hNjFj3DaD=6kqb>|5S1% z&`_>_c<lQ!XzaTz&16c1>`PSE?0YmJJ2S>0RCcm&QBonh#+oH$OA!gzB>P@j3t5x@ zO!qpY;-3Hg%{g<vS)S+neee5z?>y(sc^;L<iMBzGv3Ff%_6&FGP3`L~^TB1c*-i-z zQi!GJN>$gnOfrh4TuM%6Dy^h5c&nKX3Gg>mL+H8L8YQfHWn<~;<B=kFBNg0REy%M- zm~=oHCJc{PZ-T3sOD4&}B&J&Qpv0mcyS+ok3Mi0_we)I?ljO#*`#l=40Y$QlA*b$B zbln^0Fr6KGQx@aq>(=v8%PoUZ0U(41eW3i)(a+Uu$Be6PiaXGz57jU|@eA(`t{vm! z2^GzU@sbF__qxtq=AmQp@Xc~ug}^8HOuA$)ijuNgW;Y^iMkZ0J{lgnZl<vy|;C7H^ z#hi&@r>P~Ki2E7h=x884TZ-9_rRcqiPRHV%r(%BQY?j02?I|-evi<!1>iyaS4b158 zO<y+I125Kie6The>4c8!7SwLfS<<qk36z#Y%mOOhs9CbPYS5X2CdR}0$FwR<dPkB@ zu@^suqAPD|obsH@T)S6p_7@^Cv23Y(Q{AR&kSbUz$7AQV4XHLoDp&EG1bJxB2n4!5 zXwD96k@iXezZ_J12+1mX{q_u0Hfv2pSi9iCkImO|4G-VHlI-uXqz$=F6Ro=Xk?U(Q zF)T9M43t3g`J0H0;K$F9E~oLG8xcP?1)J@wwlK-XaM5S8ul28!`7F%?BFyyCSZ8B$ zrov7Py?nu;9A1LbbXn(iST>@N=dE{9icj)!{+?bTg(w<4L4dCBZZUiNDcF<E3N%vB z4Xuo$Z&%<}{&IbnjhXWuoz_F&bS=`)igG@_Iyc$pU0O0S6;vbweUk*(R!Boar_`Jt zD;LbGIdzOF4OOGBbP*dHYZL<^9#rY_{Zt&AFjM9aVt;*CVog8i7sg0H>`W?8U07KP zqTt)>%em+S%P6+kl{BoS4u=W}p?VRF!(A)W7EPr+XCYGM;q@1~d2|iOn7UNuT%KQY zlTGMbm2-f1X1Hqy`3=_akJMO2SdrVqD=d{{%aP!afbf3S5=ihG?^_WJZEm-yLahve zTUVM4Lr3}~-^;CP%;_YiaJC<N$)9d2`98j+k1`KSs`v4~CcyNfKa!Pn4~p~b@L9)< zk3j)|+|&D>ox?I#aG@<KZmxC?_WzhR5Modp7!2!t`Dw?1!jN$IKlv*}ShF=5&f^0h z#64l_Z|?!_==bOr4(xls(_$?f_HbJS;;IcC+u*?j863lY;am&9Bki2su>O{RL$Mu# za(8n_x?}x2$p3gY9OS?E=;`L>{O>64Lwfw_G(kX>9XwrZ+!6oM=wTO#v$7x$4Ci6< zON~7#!qyY#;rZ!<uQVNkPfF4IkD)JYJ)noDvE~Jf@U%D!3S{5Xbo{6_K;z9{XqnJC zvz&YUzB6b6;#8E2b)qhR^sK7>Q5&<_&X7%cdDuI;@60lBaIBK>tmNow_LZGUf0sRv z=yKCfDquy02*pqL2#Y_5pL^UL;`jvZR;L;X5<6CqVhzkoSvO}18VJDn-mJAvexies zWkO4iD$iFNqR~c$ef=**I(+JToX^g$FRtgsUIo3SGfd71KvM$8n9}I<U`1uC<>haD zw_l(VShqyQKU&>j4=dhToYz#^&ILJ!YdUL}y=tpqk2QFf!do<&IXmOOvFsMmyA?xx zwrOCfq33?;s5=t^y}Pxt@CNCBrDGz2>{MS(W_L{D4g;xgJb3f_<U*ZC`WFS>bm&T# zt6xp6b4sGT)wm-uK{D$aNV8LE@p>vB+`8GxDNRwD6O{?}crs2vB%B}*v*3g@fJ&=D zkpK++0vY&4+k#{;ZH+W!8r2k&f9cIT;-REfpDhCr#%e0F=evcKE70sMJMm)KRYR#6 zT{*KN6Xq|^0@XvLc$v;#niNPJIbVFbgE^qTZreb66WV%RInxX5dRveC{3W7iO{yDl zLh%D6UWUET!_mpSHxxwuXPuI^p6NT>y(S<*O4|_n2>Mxxq7T8<V4s@#p4DN7`w^Fq zx3LztK!U?u&t7i5JTUsR5GZItBdYCDq9un>e64m|sF&3Jco*7xk;oR^K1M`uMbUR) zDlfU0xzaI$vK65ysh1I7^YZI<gi$pGlzn94iSn-q`g}P3sk-<xdsPU5aN~<4Y36I1 zO}TGeg;R&UzYz&v6V)X=u8UNCH=|j1f^ws=^K#S<MOC%ubW@cuhFu-`aJ!%GNpD-4 z3?Jn2ax08MtBF>z|2-p3MuG{~HM%U5KrwUmnZ<Xcu9~#&o45O#8#yP`C@EA57{jlg zxYgXCCoiK~sKZp`(dh@b4NOt=ZM3`<;^}X$Z$vyrWZgto14Z+j%ZW8)){V8yUa<C> zOm)jR_S!th^cyJl14BU0{ja)fQYV;$VwHlI1laoS!KYrLV)WbG%FT&X=0tUEJl+Ed zD{WgRV=gniC%V=Y-oZ#RR+xT5tf{3sYm}vc->(c5$b3=V_MzKC+!UYdF1`178L@9f zQW7eNf#~!qDk@@aqc?G>KCD6&spH&pnU_%~;tO)chECS58k>JX|1DagO(#!TvKRxO zCpX>zgfOneN7r>@Vt004O#p=$WxU9>hs0@ka%4J>-(jB9rdF<ePG$_;m65R4_vWW1 zV{`oqM8>{67w-=K;3&0gP7}iFZ2@F@owcI4*w#77BUFNcGW{6n$qrTyX;N?u4OCVk z&ufrv&*G&k8;}K@Z$@D_^L7eT2Va1<)|Fq++}j)hECm5LlS3;?Iw2Wa{;toEDjX?a z#ZGd{VZ?)_SisV+l4;nxCgcSD#{0pg)MA7rgPZ+5X7?7OQc~q>VMW{#y%Wwby(d=6 z_1@NeHg(|J_2+aQjJkoTatI1WP4-)NitWsAw~7b%xI9Pdhp~>a*mu&I*+D8%Q6$D+ zsR+HIL2A<xrTGcc;a=~;BY5oh1o|%N<cmD0wa9e&RGYqq&S`zHP<2%+dAtQ0cj3;& z&4plfNs`HVQJ*t+Q^T97syo`oAd63gZgG$z|8nkByoUBIe6bDGh^xJmAV_U5PtE9Z z_6Gsv_MWX52a@^(CAw$+hJx|?I{~lV{x-U%>p=wBNdN#!p8a39!#34p*iBXIyn)im zi`r^X7aLaxJ6puhh_cG$Cf61oYQ^Q<$nYD@m_8<n2Nf500+)z{J@f=lk>4-a-8tSr zXlG96bj+1LZG*bW?whasvjG)>sZwBff1)s;(v4<4dUMz>2|9_aH<1p>A)4Hl6%IvS zxa+{L*E$FmGsuD~O3V+EHDczc0X08Zuf*nj%d8HRfj#CRoGPvEcqCCU4ZEe5M_<$v z874c!H8eL}kP{g>(KuP_TUIzTjksHMGHBA0KRXUJbBc1hBz{PIG5(c!+b!vuR&^?I z84N)o*`q3(`<8HXgSLd})e_2qZkmT78%w2U{3CPUsA}X_kW#h$rJk=J6}#KIV`)mv zyDd-HV`R(Vi2;XNeAtO=*6kFb3lOlEVObxw3u4dp<=L_u$dAjXZQwK=XpQXSzq^7O z%MFHk7_}St&TU>{TRm%M%{AJt;bhgW&^^6Pg;N>UL}%>I6951<WVm@CAY=j@oi~S_ zj03fwKDUqBpTC2lF}Pqkd}(11VfdK2-+>3c&$vt(eBHr{A$-EjJ`VT!Va{kgZWo9R z$-`PYaX#sN)P9=>RU1wU;VTNe>W;E={?39!?Ta*=!oyeT`9I~=5qfW*6bC*`-{DEg z)&3;?Rqg#cgLotW@ash?AHsxJe@C<6<PpBS4`Df|29M_XwVRSdc<}1*|7Dpygaxk_ zk7mK?MSO9n|2f8gsK=wpejOmwL&y%Q$-jB_*W|%X5vM2d6_4dPs4n-H%s%qqZH(JA c@inV?#1^WnK|+fA8Xfkrg#A~>RU7x}e{Z|SR{#J2 literal 0 HcmV?d00001 diff --git a/docs/asound.conf-sample b/docs/asound.conf-sample new file mode 100644 index 00000000..769c0bf6 --- /dev/null +++ b/docs/asound.conf-sample @@ -0,0 +1,11 @@ +# *** Start of Rivendell configuration generated by rdalsaconfig(1) *** +pcm.rd0 { + type hw + card 0 + device 0 +} +ctl.rd0 { + type hw + card 0 +} +# *** End of Rivendell configuration generated by rdalsaconfig(1) *** diff --git a/docs/cae.sxw b/docs/cae.sxw new file mode 100644 index 0000000000000000000000000000000000000000..1bc7f55b8807d9217ab5ea5df97da46600a75d08 GIT binary patch literal 15896 zcmbum1y~%}@;(d%2yVeWSb*T}?j9t#>kt@h@Zb<2xH|+0?!n!Hy9Rf6C-@(BH=FF< z-TU3&^BtZZdiuO?bsgzCRcERdq@O{egMq<-fz6t`3od6dauR}pfju3Mm%uCmmc}4w zYh!(DYYTv(J_uk1q;~)s(b?Gp>6|Pr=p1bUAY)sFzsOK?XG({L0t0(Gev@Gg(tiT; z@IQVKI~d#AJxbvvVWeXqAvOjYS{VU=ro1F7%3`z}B>a4EJXR(q07GLgBP&CDOJg92 z_E7_U;zugbj_da-UJ^49$eN3u-pbk-`1>U~D_c`~CI$uu`rp5k{6TQC007_piFb5# zq;q8c4a>;M$w~iP?GLDt;h#8bds~a&P)3II#umm;TG-Ju(lOHiz&@$;C;FeXcmn(Y zTUlBC7c9%)G&Z$0GP3v+|BJ?ttz)J)r8m+C>C-v@j2%fyi2vxRU%HfugzrcHJ*mLQ z^YqDOY78{C)dyMG^2q=UY>nlA>tK3jIu<e&Ai#<Emy5dAwpQlGh9G)o76wa3G9i0_ zg%K?)0}~JZ-vs?G7ytx-0QwfRhPKAPi5IgqHX;_cFxI!T0{%hyJLGrbZ-mEbK>OGn zW4_0xG0`%x&@wVAGcs|pFmf@l{lWe#j>pK5>z{A+OT`oD52=hyk0NQA8I&0~xR{u@ zSXp@Je^maihP5pK2r@RJHE`zp2i1S6{RRH3${e(eoXU)BT&$d2Oq_qH{2S|c(C;i` zqsLAHn$j9N8(J9K@i8*7|AG8l#b41z_Kzd>*h72@jI1J$_mE(fW#Ul!8}m=l?_7I3 zV_RAyV-o=IaTtCZFrdDrF)xWE(8P+EfrS2#>F{4+jQ<;q>3@SU{|Wo^akc|Jw#yC# zF#KIZkiLP1F|DDMJrKl8@@Nr$QyXBZZ~7k>tqh)K=HH>#zaTmPpj+$P>YLi?Tbum= zGjXu|QRQf5YxLtPBPRpLAD0cy9w~;8rtHr;CI;pomB7b&>S*?8=<KZZ4IkC|4=e)% zJL^+J|9F(Sp4#y9+n+7}?eg!o5(Wn5H+%bNV*e}%k7stqpr^TF_hc^zG-hpAI8fXc zOC*l#Vp?Cu;bb#Se@TfCw+^Z$Z-A`_mpAGm@4?>Ktu~fmleVUS&ow_4vgn)N$!tmn z*4(~B9n0i|!Lhl>1f6tH6M(}zVV7-(DK>8sc)Y%|Kkp(>lgR*U^5>B-)Z0<>R;&>r zT;7#&*X6x`lSmcwo<7bQ!oq$R9&60D<4fVmPF;n&z98wvZ5?0V7y4;H)5T|vqS(_M zdg*6_6eDNPreCd3M8;upY!Vgnxz6{@WV3gwN~zMvHeoy2*P=BoblQ9-o}45qvSLQd zoIi#6qADXbyKr@R4PIOg6;3EGMK3?j)cPvA9I%~lYo4OH8Ml6E%ST@i{-RQ)rZR0# zA3a~awOF1S>jt*j&x~ufX+NqYXLHdZY9Zyg-yfwBZVpFZDI5>CGg*na5R@eXSHGRh zEPf;-6y>i#<|dSTTk(B0o~#QMULSnfwY17r{T`_^N6j7S#HFT8B~RpY>m-u)^c^L< zTZu;5paYgBK3$G(0k>;va3?wv5pAs+Gk9vy1w5%}*RuN;f@1WrYIy#e>wN?9Z`d}3 zmkN{FV*@n`uIpLQ>L<#z$=Qsv!TZ9JjvO9*YSztN9i(0>1~&`xg#?beaoV3yC}DWL z*d3;>W0S0+WJXr)7iOBk;MX^McXmiHMD)Gx>CY#S+L2H{ix0=u!@?f1YT9F<CV|@p zjP2_6D%Vm!GltrYQE<q2;)e~S=4s{KiM0r49NuLuXZDnj%1sa^+d6qSX4Z?a4akuy zFl)izQi5cOE@B}R))_`Z(sbXdGXn*naz#AzlbcZC*|x^nhGFoWX0@`hkCVcXjYWi% zM<Qi?hZc*rLrmbx2C0RNnJ+8}#w;g1)$iiZP)MIHD?ElYjH*QuuY0G{E@7|?=jW<r z5xXKR;i&YI0i`66#4uPcu8UD0>V4_0Bo98%m}wZZ3O1^%MGf8yDecH^qyR9-P%lRt zeTr2BT4=8TGKkMWBxE@a+X^j6DQk0L*R>U^Oa{no;ei(Y@pWDplfHmbxn77EG+`XL zXX?+vU@W^8!pRtk2D2sFWRr8V(!GyAD!Jaikafz#*=RWtl$X<EHpGXZDRdou{*jKg z3n@QT>q|Vt9#B+n`hDvBGYdAr^PZCA9?IJ;t62nj=&+7xyY;(IFE=$rpGyijd3R|m z<iUOouiUhha%B=Mwt~pT2%Ka)BbM8G?(4$O3_2}4;CA7;WX3YH$ymJHs?YUrBOpo| z_S~4GDaB_J!V_piM(b@d@f=Q16(Bq;$gbDp!4OmQ!9B=E2s}9LeNlCGN>6)9=r9#* z6Z5Uz;EMa?14fZ{<^-fKDFe#EuKISOM+U)V>D;(?^zll6AU0~B{FpFG(WO#A9CH!4 za6Tb^k?KJrh)VPWjC0lmV-D$v0v}`<D{2$e#*V4Ojp;PpHU}Y1PbugA;sUwh#+aV@ z1O3DG+pY85F@jt7?cu7VDi^25i@jL4(6n>DnaPlX2;I}doZ?371fQxj&CD*Bi4ug- zkyY)J3J{@pe73%2DQK0Nk7(&3RrJF|1+(=A_-UNHuz9V`JHl~FM0a&~cD@8CoA_Wu z53#8wRW<H(!wUt=I`zq#D&sLZ_t4it&M2f!)qIC%JD5B7ti_1bnfh-#Hm7shTnKqX zBXgvhuN~a5$I>!WV`|5pkE}H8+{CO`huUTa8a=qX6*|?Esv?gwNyWpI>UB@2%!Z|i z4|I9XuB-OP_n#Nc>?}IniT4qmSz#^=7gV{#9@Z*tnlM-=-s`b#t7p!H`nvYkfYGBV zZi~5ze%$HT^Vc+$IErqEij22sWRAIFwX`X<Pliiv+7(3Blj7TGnS7H4Q4G}+9@xV+ zrXh>oPnIq%GcHs;DP~rXBA@z}&hxYGW(^fne?noo7@2GZy<3%lD0r}dwb8TYmk{-M z-^lH-3!B0%nd58$E1tG-r`;Jf*ltyy0J^>6qyA|RjcIy#0vWB6TdV4}Vv88xg~7GQ zQUSi%PA=W=Y}tTHz2$Q-Ym;>P;0iD7XwR;2*9}j&e7`|XK*lU$Uu_T3$%`t8^bEtE zgY8LpoZGL7f)+=7>9m?{Hh6ngbcoNlT1?V~VTA%TDy8CviL<hym1j3|H7P!9iE*Fa zH+WuoT9ysMRVfPL`FH3dYa;dw0HUW(?9t52!Rj$#{2}7t!st%f-24ORZrMt24@}wD zGt%(2?+_KFpTmsXy7~n|gMn3$fr0(|5(fXcgc({rx>P{W(+ak)?Pj+kHu~^zg<kHS zuPE7p?bC=?5_OL8t{j$gR)P2sn5w*E9u7TR6b{1Gr_Z}NlD`brLEVCa4Dc<evkw<b zOm)AqzdY;T%JF!gg1eT$sa4(Y_$s9Q^hKM@#3;z__Fzr&N}-<Xs%zlk)+j`*uD6&~ zIz={Nds4X%v`p`nBkN9k*u<SsQ|zW)qRGa*p2ggU^DSv}bJPCn=Buk`y&Y*|quDaM z<FqP!B`X^Y?wEdOy(oNh?Z$B2_~aB=&2lx7y5MeHTwHk^{K%K%i~ZT_%~rQNpLH34 zK%c5Gdvl=${Q)#6SCHFv13M!odorOle7RwP<K6gOmD0wja$=d+;#9J%f4?LVi9H~A z`PR81*qkb1(-UjQmuuS_l~(Ajt{F~Y)37(AqT?5DJJs{&HB|S`HOT8LGD^Ckh~CF} zp}-s^x}@*OYOyh+*S3O<>Gp|o+LOBY^Tu+YYZGU*vOeH4j3gGL$YvtZn(yIEkShq_ zv+5oTl+#%~52>v>nMfl#c)sH+3z$+H0&0!P9w;)e1xNLsf3x?Wew)iMxi#O@&saj+ zYp-C$WvsWb!^*csI#RiKQfD)XV3t&)WLP=9tlhjlHByl!>y;dItrjn~uWm~JfY%-e za&yA-kB=Bc7{HSpp2S1CF=rO<icollk<PZ>!lHoG*A&X*MjOsKepYg&;}53~$n0Qm zgU_H>=4`f(I~LgfcC3TAjM37yOSM9q*eW{l3I9w6>^S6*?la<q&m!p&E^A00bn}(u zlB|<o_aetf$5+qdxO}caW?u1Pu@)>DO7rnuhoTE!0_`}#EAK-3>d(*kG(zPNPmFe! z_OP9?$y~2L%wRs)l%+J_?#@nXW0dYB2q~eviVZd2$`FE-Qq<OTh~%|ScJqs0AhI87 zg3mAY+&A<^yjoA0iBI?>?<p6`nq~5K=$zd4f^H-M-pbm(l0pZS((^mJm_Z3DX!VV$ zl7A?Hx%@4jHMkGTaVBPNaNZkn?qgjGpC;z637oEx44ui`^e{n76%)9lnEiX+)ndNH zZyev9oMwa8J@Z0yTh+U>u|C{-I6|0b1=@(2$>T`a^*sYO6D^#(=AfhI4b7G7#bdR` z8rO2utjw-zZNl7WH&#Js=I<#fpx`QgfaPVOW313X&j~Cmf1?MoqUNeQRTR5y2M+~S zG8O|-;tlnYv<V>m8?;pY17uXC6@sdtvzX~_;UU-A+<(J42U>nE+qcd~OMX2&!A^}; zFIw|f4?6~ae)PSBP{7nwT<LqGV-w=VjNoYp8dW|+ID}&AH@e`F1-QN17^>q1P@)3@ z`B1z%$7eGFZzm{iSq<S4iu1ws%4;TB#+HlJ5f<`s$%;*6yZ|xzo!-)-H5gZH1-Rn` zTv}|eu`c%k#RclM-8Loa%BP=JI>_-Q5VM%Cs>vql;u=)~)sU$rE#I=5E$k>Ol;@-F zf2dPz5h_nMh;_r9D9`^e{jR^fvxXw~+-Zkj)pL90*fXy{x0GTrMkIVw<y%~tUEt{Y zAtmY=`mPzdyy}APtP*8lsgdhv6W5L`L#i=G>cCRccQw1~%2I6)CSUABwk61yOW@AF zl&vbDxo7$=IO6(I!{RR(K|-;TF=m$9EONs~M;o1+5v)if8AU%vS+2_av>24sc`L<R z3_I3RU(m}*0jj*+RC_CvOMS)1CNCVXRguiTA%GRLq1vM#uqD2uam;@s`PKxE!LaDq zIKz1oCdg+Y5movauqGwxFrWrFee=p+g&0<gU4lA2JCh6^*ZD=tN)PY=#SrgU&~4qt z?67lqbOVyAF4gAk>STA(G^pQP*nfn+rfngiEUNpXi|I!mo9qboP#XJAQacK#v8oVf zSwk(Nq{_UkGKoMPQ0KIVNxyPJvjw;F8?>zLIkv3^lL0MZcJ%?hp?)Vvh&ocBG@&Dc zVW;-<fU^E|UUa8~l@hweJzC0DSzX&rODN&I;*CUFqKE|+wK4axZ)pj6jO|CMm19YZ z8c3u?3E7%!nCSgw2%~m1-xQ0I>7DraU0o-;M=qF_`o7ec$OG$$X79pME^_b>UF>X0 z9b0T5b_&u@P^qC?wfn$%DbPQhe<}#|%co^$u^v5q|D6~;rY`4e%53m^b2p1LRC%rQ zByiDs5~Om1P8&z~e9RF}K*LMndGZejb=E}K2+%HYDPEN_fm0U-4A%(J4Kmng2o7Ku z`&;A2rnMiUIuqF`v$mrXabFdS&cTwR=2Z?bQbuBz$Z|3na=cO!la(t(O&6)%j}W}P zNPEDgymQ#~%8dmuVRXfW4GohvL0n2leB0bCfn|V{j8~f@Pv#uz4`e8Pr56(4?^c#f zFYvK1VBO4mTa+Dv$yZnSI2>Aw6rC<FnpuY~ih>wcaJ8EW0bVvR0Fh#x_&t))or|`Z z<4Lx(KUh($cJo!IwTE(!1|s{>du9g@vgTEco#5jxqP5HN@^XHi^{wwaYhsjd2uT)A zqRO0_MFm*C>d|e{Q2OZMw07n|T5H;$y*z=h-L&j|scZ(HPZ)swISBe|#fe(Cr8&jn z>yWjn_Z+^@ffBy;fe!G^4`G~`xi1qkrdyZ|q=~w~@vfB}vj$o;RgOAi?WE2k^gIOx zJMK1erYOR0V{^qO53M*2TeOBJ4yDR`J1(1hNd&w`s-UY=kXjLe#MZ+hE!p&Ro}`{m z)SuFGaKStS=)R{l!Cmp?M}zYupcHu0e0sJix{0DOEi)m`H73`1548m=qhDiZDKSCM zXsZKqgxI>|{n!ZIK#;yw)>@!6Ze+!Cf|iz-zcu)hG#`)Itd@b}A|{Wy!kZ`4r-H}Q z3DGzIVAb&E?KX(0M|ijF-0mj*E_coOT;;j|oZF?SbxEn(qdG9VxU^f^=_bb)G2>h7 zj=EVu0g(rWTOESvw%{hQNgDJbzf|*@ACz?~$nRn!O4lWayu~ik@QqVwsBu6qEMsLT z3c0=0o&s~JFvdZ==Nlo9)8Ku}ohi=+K0DLUo)WC>9XFE2=8x*3rmVYV;5w>7&4c9) zJYvH#?B2n%Sg+U}?|@+<7S`NVwvL*0b&G;d<d9)6)v<d}z1|#o<lQ81islowcpqps zH(Jf#M}b`T-QlMhyN`{y!jfLGU(QczlhK@U_4uc5Cu>s#QYMY1LajC)t^*NyVSSbI zGAH_{m8ae<`0KhNuMP<z>sW$QG$O64^NH;us49D2J55J*8;PMjPX`!e;4a{9i@`QE z1~0KuhmhL@^8|doT#9tce}iX;i;b}sbmeIa*z{tF1M&FEe9(Iq;go>FvZY1L`UPn$ zC7h67x`X@upf(#VMuTvBUt4YsD_I3^cI%42jI-e-s=xUQPhy{aK4>t%>xy)t4*v?7 zFFL7*08CTp7CNUj&%RNmRhh3;&=Jw&xRh2hmhEDn(EDu)&8iAzK%wRENX*1s&KG!_ z^7swbuZq|B+_G}V72&lgjySqVnk3n@@GJQVh_kKqu#xa2Z@wNAp9BQxBr~lJp`#lk zr6C$Cu6UCn2+O3-Rm~)olWUXWwN&PGRo*S)dUcMWkuK!OuIweZlK{!XO_y{Xb|sk% zKXy7hCmy(_)}W<DMi|O=gv>>NnS2xq^Twuq$P9_XQ@$=&gi1nHH?^sCrfVMvaP8$L zl;N%SLHdvbB@VeQ0Ih=aLN)=kj!aorAbJ|ihhL*SyTX+}&St^R?N+z#Jl}ObRpooN zAw@HK!!dK<VBvUWAuJR}0;r)kvo6C9S`i^i@P0SR`E0{1OQzq{=wtUMxHZ4VMcZok zsEU;qTSSx4c}Z-#*<e7r`l|Zd$_T+O*C80!__;tyV34_*U^_m!f}Q=wl921l?%;^F z>e!kp<W@Qw1;PSRmc<vdgB*S86~C1xih#x!erNiymg>zzJ=~nT49wc|U}y*tcuTVV z1@U<kg>PiD$KqMv*hjJtsHa|CP1Z)rX885b7vVhjvw5YXJz;`G_!*<;9q#6Ler#{8 z=$C2po^?<aYG%tSyPR*6%VbvkXTGDnwdrSE{Q^hQ1$N6^L|Gd-sx<1^eEObzs<6Ur zeb2@eeI^baPq&a%@=~}5%#YycVYYC~6eXysN%)3vTWv`k{xV9226eqqje^X}XbsMJ zG{HxGSz!Butq=AEvy-S&hv2!Q=*uGkZXQdR9k;HzW4+`N3LD}?|50Z%WT56{N>>`` zYui+pMj*euB`75Dg>iVrhp&4lNV4gqgF^&{oO@LhoyIVMu<A6=HA3N!0!{P0<3V=G zUBpaqUCz-w$=ZWOlHOfVGs5(NsGA<Rk%5cN539}1-|i_B(b7x{W&83sFK4Ug@3qU& zG)S45KMuX@<!j-{XV|t`)HNJ6EGzZ=*icx!QA>WyA)sai=E;)K+TQ<BZa?u^HkuaB z4)9i}L9M(`1vbx~HD>03#^q8?L)xr8a<BtVBn+aYJX)%^GbRG@wyC71Z!~FPUwAbH zp^nI9Kdpy1<(Ynn(rB<QAT=^*Dn`g}GpO>FBvvO{SzX7C0Su-Iio`Y8_r5~Jx{uSR z2G6XtfkeEdWQJO|Yxdn5q+HfsM9LiGadF`R`gL~Be%tYz40dpCP&RMO)EnqU&U751 z>``s`z+h7=w8!O;a6WtWId!KktyL@d=$Nn^CxV)!Kpehu@rkJB0-fmt)luJr6gm0H zTRQYoj+pI^ZZPPW<w@beNokddbEBC|T`Z!Pvxk`VR+!Wgwa(T?w=MJ7rsNTA;>OP$ z4`^2_g%-IFsOAeYOlj%_^q(&<+Re9EmLg#VPoO3UH>q554_kX=xYHM?Aj!O7Hch6^ z|MdE!K4V_Vh4`hd1AhD#!-Orvr>Ly5)(x}qv#}01^hOAhNlk<V1I-bVcy1eP5&jQV zm-(u?5_V+=_Gb(jEK6-!MZ+dG<}$@pFGh7}09`AZ!5#8<v1MPz97wcp9etL&WT{@h zI?RT-fZAl;=&k&SzOoTmEN8@v_|DnJ=-oKuyU_)YfD==08nEI%#DvY0p*-<$z7!_J zY8l*9MK;tTYB9G&24;L-pjFbF_IP0_#!1;wR!U?FXzxO+8=vtnkyEbds`=-)Q8~Us zuG6ZT&-Jg*8Nxp8nXA!Y_6j;s`4xp=`E}f;$00&-#j_e^O{kv8qpe!3Rkz4}Af8|i zxpGV@`O-sDmZoDeC5g0A&!=yWYI&~qrrZ+)vU*>Mw2JmsMHK9MdQrePPc%2_+UAJ^ z!^?8r;uAK(pw0+(nLJY?U(JBw+$|6p{uEi{Q94l>;&)`<1F%l%DV$nUdS0V$NUfs= zVR?dWP(gXtcKuCxkjL?i(*c+>;yZk04>1uvJ~*<{6d%?5W|M$KKG;YV*7sZQftP)A zj&Xbu&fp&>-jaCr8Xi)eoEl!<Z>KjNen$Vic%|l`sFCYHQXXt-vd61Qz@TcjRc_qx zt!-Qf7}ApecIgXOyWxxUj0R%AM8IITU{28kGl!2@o`)Q*rl)@#ACpFYe8H-T`ZIPi zC@tE2Mbh!X39ZOdl|ZjBK@&m$o-IPuz9qxp9XZnTQLqZWii4Two*G2?!5Z-8x2{l( z9qA@U^)u!)FQnnV7Pd1caTzS=!k$j*6jaqEei6`7(D3R5>RAWwd%u~bTg@#zo5g|M zce^pXX@Zbgs9nVGQKgOHZLx5W5d=U=mIY&qJAGXz?cRrZjk(&C?<sl-gPEtdED92@ z;K=B37-=IlvdL$rU2@u5P<d&$$Fs+4mwfGytO_n19={`#stUtLt*)pkwGHafpUi_{ z!tmEnIv{v9_zhiYWU;1i^Gz~XY0|wl(cqHb%o2roF$e5;tCa|f$KfC_w}n^W(i`lh zYaf|#U&>xQ%pBtcmd~Q+$KcBPyf;RoJOb6YgrB(djlM#m(^=uWwTwLf?PIMzskVE= z?tBBEEA8@tE}wPRQxWd%41GcY4_BD59ieN24-A&f`kYi5cqwJ`c|MA>L-atpQRcSv zZN93p^;cc_FkM{kNiHP23nqnJk`^!IeX2bRuTJ&VdB2pRizV;5ZNuAOE7%|jY42Vr z5I!aCIzYk9aCS1nw)EBKxxuEHhkoo!fuXE}U@P!L5&pR<8J)paH-Bn@#R*9<E6odj ze7E5RHwBSVfQ~rZY}Dem`*g~Xb49lvFrS>`BMGYG?soAQ`FA(o^*Hy-?M>bMxSnb$ zHC|$3S4)M+u>uU8UAnjEUt1vgYo1RxvEs?E2^Iud)XJ4Y(YgT&{FYq@Adv8V?rR)q zx3$F(T>a;2h~rRqFwidKwqMFvvfw5py_`*pad;@Rmj@nl?~7;kTSkDb9aV{ss=BOI zO(>;atHe{+?jLZvCj%T1b;E5xQ_Ce<@wWB*9uyB8y@(TXk032?4{LHY?IajsRpr3L z2IAM9Bpi<dGZUjRL|tcD@YyPlNWZLfOOn0hNrC2v^USEqyY{QC<&!D>SUN5&iXr$x zLMve-g-WXQn1c5MX4H&kE|j}AwP{Ws0~|}Bq+^fr;TG>~d=M#@?Rq~B0sc!y^wPck zAkEe5G|e>IK@=I*YMVIQr5=s&w}qQ%`U9oPw<kd?0ueG2T0u(*71DhpU3IlDr;OT? z93hA3N(Xk$3tD3FL)CV}_r|!*1I(_?zJ9$7YM?h$<MD3ecUhG8-(Ws4aMdK7qif<K z3zK_6V20p=(S;uvm24Sg=a!3C$L*ogyY$6iRag3+?-EL===(KiYuLNBYmL^}^oMV= zb44BjvaGl8C2&0VRvd1qS~R?vjWNfs$fSfQmv7nf``hk)zY5MoES>w=wwdPlau5w1 ziO}W)zF+Be@mBzqG#)4*`nXyRR-N1<wzA~H<$UBXMbHI4e<Rg`#&pWXm}T~oOSs^x z@*dcnes2k8SaMq38HVp&N$*e=C?3#97sZ}lxn?>rt6jRWFIG4WHV+<n$mP@PWpi)n zbqUw$$fa8C*A@SXj|h`QRoGlygpcF|ob(GvJhG5S4qrGtPO1eWS_seX2k?HP8L4{t znXsbE%i4|jIJXb4L+InCM1gc{NzxmvlkqOyd*rI9pPXavGB`Na$jh#TL)ozgj?xZX zf^eE-ut=j~4T^0)&Ip+Z$u2$L1mU~Ov0kE#A}d(x^dhKDo_FZi>4-z}vvfujE^EDK zWpHt^TH9^R?Tzp2rNVu4zg%XEk>p=;Vy*%X-xk=HersM)iZaT!je>T(xX!tNY<YEw zd{nTqO5_||nV{pdxOcH**$_Z0f?JR~zxlCll5z4D>Z(QU4#R)?G)cz>r_+STf0HS& zi0D4XT=OQUvXFOo0IM&A_fTpO$yuCh3rk)S3#+R8D4jTBUDe;AqPK_X+b);pLP77h z^y`hP7;-dBys(BVezdpMc$=F#08Q5ieFf~8Z}`gnknA`r{B<Gk9NX)<O;^>_;<)vm zOEu5COu=Ssl%PTdBpxQQdN5-bp$lQmOM*o5(C`iLvykwdUFHR!2a(PSr7SooJYQKS zZBT~M@qTYM%TeA&#_QG%_eONsWSBFSWPK#3ENpCl9(Ub6$#UA@J_M`4k}*PzmT}N} z`fh~pb@-=f<0Su3)a`n~wRvV+I=)`ZX|_oQ>oF1JBa##H1X_KOdE5|Cj5ac@CE@)j zjXj%jwx$y8m|rvd1M<^O_T3&tZv-Y780ylGo$MdUFE9}rg~5+o*iQ%c<4(4+nZ2a} zP#<7nM-TdON@oo;4OEa5M})(LdxRiLN{A>v{_g|>0|$eFcsw)ZPsIWQgIAIi5ma_c z-cQ*LU86)0!vQQl#JGxU&QR{-kug?}bMlMfz`^9b7sa0)ez?88Mfc>nPv8Y}!jpiD z6jTgHi1aoJM<?_7OpHSY)k91r0WB%W^nb4EN#pn6d%gkJ)tu(u%Riw8l_#i3=U;`} zxBM)U={xr&eiRBs9b9DO`&8qu7a`)aDv!53b(d7x-)diB+pT5~+jlwDDp|XWq<&aj zJ*CCUj;u-^ltRN)3GzB0z?@Q**jYxrH*uR=x{G8YVo5zOdfhe9*!GQo9%6x>3L7CZ zpSUphgn;7WMR+tk#W-)c^4F{N1H1lPWhlv781_1K2;6^aoQq^WBgkq)o{*6ER)Bld zCKio~Jmc$lf&{&wJoo4uMIn5T`&A`dIptAxDH^`%M4iZdlfb1I_t){8kNu_*N+`A_ z(Oz+gr`u<otb5@7c7k5CM2aJa-FaZ31K!(7Z-K$vabZUTmeJ`AP$$UoYQ6f+tP_U( z7PmBOHh!S_F_Z403Zt2O)%C1@zE!GI0%h!>F#AJ89As*=`BkmAI;GSK`9-5?A*!73 z1-w}yV8Nm!>VnUwjkttI%|=Drm|E(qXh+Z9v3-JN7tf8@l%h*rsHt9&(8${$6({mD zb&Y7t)U1f;xVMjc;)iXdw~9LHm)#7riHJd?vNq^A2zgv4HDAq|m9LS@*2_qc&hP_s z_#&)8BwCfyOK6LfR9kR=PL6~G@C4#gy-rh^uxJO8tuSvrQR|&4<ZW$>WXNpzXC>Fp zN5}C6r1(8+p24|G^D*Xun|Vz9aGfR>N|q|`1GPTlD+^1;39*;2u@2JPXQpr3nIkN| z#e=?cA}ln2Q7&g#k>jGRS@TWzo%DPYuj($Ok?4Jw5sJ}>wxZ3XfP(C|V9S(@U|8k~ zd{vn1;G$S!xX<zgm(!G=L}^~hI-br|(8|2%-TnIdI8tWCtc<O#ziLHfb7AEyvL%|Y zI$y(yHg+zt{2PoWbrqR6SIAvZBqqGf+&Sj1c(YfhjZDeIcP&+Z?QqVj$KMY&7QnKR zUEy`!rMA=j{$wQFk=fs{nod_A#FdEz51k@I9rJ0|-n#c(Cc_LTsTjQP@(LJmE^8px zzz6BzdxUYY^61xM>z3Ve3HoP4iXyjFmS_7PvF@2lJ8ONsawO=9J0+BCCHeWVCD2gO zUwuxT7>@_|>YDQ~lar5zA@vK5l=4_-3agq(^`7yk@WW{ke1*M*0rJewDh8OaR>h$g ziglG9hiS}+F|6Tj;jPw}DI+>;4j}XKz$i@((W~sY-ke3Yt;D!&5ceJ4VewccsJ|S1 zHnwgP8}FFGXt5o~bVKD%H_mCZqqu1@;6#u{c{xbV6)3+}v;mKl|7@$v-97J<NgrI( zY>KXVF*97_NoT9_SVuA2URRQ3Uf|qYfnN0u?_Uguw&4`~Rg+xhRb<^h7Z*Fg3Y$CG zo6+f>?9S>YFYIKsW?duynfvz`J|kGw&Gr`Er5M--1sC#92c^fsA-j<FLtgMjYKjF& z-*ee)B9mzH%HQpzDh-}VJ7a*ZR9L%ME4$9C7Q6fI@{!cuC+P0S?bsYoB+aaT);3&2 z*3NvUCZTxAAPiWLch*gEB&~{5&f{h58OH6ui2S&pGdsdtGjI{<Jt6R`%}clnY#ZXf z!ru}|LQ?u#JH=J6b!LGyEAxy!(_KgCG$i<Y=dq0bjrtD$1Q(o732XOx=qxnO`b^)B z%Ef5U>dS-)5yHFg_;z7ewVT^_@p5?=#DNK@i>X!%3k)5mldRwE!uCz`?A1222ciD7 ztNj7|BK6r3WfC9SzAO$|idjITH^;t9lM0uijl}R_v9^KRZy4cK<>i$>nH#9OzCleG z%jTxNC`*{=-`x@EQqP}1TrpO8Ui|4q6Vt?azdE=>`<y4?xyn~wz6WYwrG2FpM0$>r z`>c-hdZq)b?g}TfiUNx7`YKTwXG1KEVfl@L+gl%RU>jsNx(D7RchqfMiOa}0ecIMN za2%bF%@-RJaW1=PI=09xFbM&0Laln?1(#+ubU9bf!Dqo{u0_^<qIH{xJ#lG+(cFo| z85!NQls0P(n7UE>7V9nhA4^K`k@Pl)nf2TWKw-dwGCBEr?9@}XWa7~-9XcqUou_&r zfyfpu3|y*tWg!W6>RlZkw^|Z?sCrRnzK=ML-nE*V=h~oAt5zw&DPjyFU6KyEIJCMR z6P2{bmV3|=G;X$%b`}zk^2i9{5BMN;u$Xir_8neHA}gl70Z~E|(=8{x$`37%#)@Lh zB(cF1fA25izrTrbeh3u-a{}YE>hq6_-!^tQXJ`TAix+b|Nla$3bp+Rb``9n3=ml($ z45Fi|hQ}slG%X8#UYWd}Lh84ZFu6~2;t3tFZxIxZjG8nGl+D+)Ju97d)DI-^^LbY8 zt^hHnJ`yWLsac-!S?}G?)%FY#Z;`p8vRcw9{VNk!W7E*yu!V6dQtGf{toa!kRKXEw zX-MmojBkR#rLXFY@x-OO27A$;*mp1HtBnBjTWka{7v`DR6}e`@M<xEcZj0R>vskqg zIFY;EDTV|p98owO)gr)*H!xwc@Lx9Yj@?Qko2;8d)K5_<uQ4X64{mIG3m93z?&a1# z&g3EHfeyri3q!F>@3Be|Xicg9(oBwvjHs@h1>$e|MRRtiW1VshZ$p;(BjWYskXyr7 zcmg`p-wu6&I<?IEYQ>QCnjXpRX1rc{jrx=vivHQ}Ghba!k-LelJ>ftzR%I~~X^^vZ z#`Sa9xkte|gXclHa;cK~n}xP=)r~;*T#KziXT(gqp#iSVUiJ(xN)xKs@~qUBQy>(@ zbEClrRwdp157D)~aF()0Cp7ERiu)g;DNT{{w`s6e>v56w*)&2_rxi;f{)-z!K#o!9 z0-xb}j7wAYxp;ADnN8R<kJwNS|NYTtVPY#|E-5MT-PARqvVt}`J!wIv(@T->_<Dqm z&?Zz8CV}WYZU{GRG=KA#`nPyd`(^2o^YQR2_6n%XUDj=^tdne9Nw!#Bgj5#XlRDIU zH#_1BW({2$S#@8C1W&zKZa87i-H2gH?Vz!kBYc5|qc3ek+6?zNoZ0ox?n{=`M4J*& zu~FaTOHJ#()v_y(yd1NHC$OZ7@K<+lJ^-M;zsD%?%?9>=<0@~rV;!j_)VwOX5lBQC zzHH4YT0NZ%+(_03E|Ab1EUh>17%*G{gXsky*oZ&f_|QAx2lRF<vPwzF%8<Eu<YkCB zr)D*nZ#+9Nb3Lv9&Q!;ZYQQcyQL8ZE?yOkOwH}`G{@KF!|8x>%#G9ixiTI^H#%LN) zC<mhL>-gJm@ks;t^-;FWdV)y2fHv0$bBZ)EPR@2N8C=z)0|{A^MjL75qZ9drN3Nz` z5qhb@PY!27vt5u}E*gf^zI@mYMf}l=1b%5}0O+}n{xBrPm$^Y&8=a5pg#E%YZ&n{` zTKoQD$N&HMu77)So;*|fva4*6cmd7Lqn8aPDJmyYETrfC@3|;X>68}w&Q|u1DWm#^ zX2ym_dPbB-#(H`%OGbKnBmRtNdclDVor2h_%)#lMFvh;^*hK=+kI601VMwuhy<a`j z-#i|F&24|Y@Mpn&JQKD8ngC4yNY%AtqPKob5wL#D7q_SXcOKC{@P12pwWAjTfGqW` z?fwh-pKc1Wva+z&2O3-aA9+uixb}7i`nLathyM@CKIVv<+8W#ae=wgSsK0m5lcxXu ze*eUJ>d*f>%f!O!F}M6j+x{ux_GyU!uA#o6;bX@CZ^`oXhW56$e`GQ}`)yu4;=!I` zyr=T-6YnW5v;#Rm=6XNnKuxI6hR(8~xE-ou!_Ba3#5N{X&T|NAvNY;pLDeN?lvIdl zT2LwyQ_Uuo9EPLYmyu7`;#d+U#@lf)<EPdtxSel=myLu<h(hT?jX0qN!-R<nT{&Ph zxVi*wv?hI9Y(Psw4C!G)wTVD2ju;&Z&PBD@FyHnqAfDjT{gB=b>nLsbvU(ZBl;C^d zr~oXje}0U)yqt)CMmz&X&7hMuVu?zaD$zhBf(HiKzRI2<ba;7l>~0b<Vo(P2;NF0| z2$!(j8}}^p){TBa>NWogTpU)Ux-y!-FX{^`46#+pv#DS+o~?3lCkFa2tP$<vUvaA; ziXCR@O6CXl^3}dl#kOM^qT1)0_9Q3_MeYQv<?u!%`6CloJUG{s9EzIw^df%Z(xn0L z?bZ5xM-&PGKN~=81n2#lmt;+!NAU$b?D;aIi4BHG#JQF%Is`;SN_voZU#rr>hsd>z zCgL)6D8DsnFAS)arC<TB4(aldSNEf&aU)I|BRms0yE(NHE?aLYBwwM=CHQGdi&kVB zJ!HfTwIAzNC~>_t&#t%Nxx>N5VOocX%qs+htgs{M+(=cUDy*ZSF`r+@41~BCuem3E zFZ31<SzooQ!nFPxV*LqmkkS>{hs!0SNC`nm7;ZaiJ=KXEX~5>vMKx~B<l@9rc}6hk zcYTk&`Bt;aF5j@bfB-rdb{eOz`JTz;6OUZSRw_`5_quWD4EE^MlK;)pVqT+dZP}RQ zaI7^6l~E)*&c-H<Kf$FIUG2g~igY(LR^gtL4q&_Q?Fvs;85|EsT#H;DRfX7*E3yHZ zt>ttF6jQTL1b|XHW<_KVRSlBjQ#*BhaHbhy0*V7kYCVboeaNRkl+U*K!cjtb;b+g1 zVVM2HfFF*zS1slOKO{fE%)i<K4$w(aJfP53FzD3)5>fPp0~z|1_VnK_YM>#|Dg$aX z_Q|u|aY=EG-eWKXp4HheM!))sPRpFf(x?H2*N<NI`6JYeVN6|_y|hHrkM3Y8Bje~E zYKHMv@C|<CZGCP~-_Q<L=MDR^r~N-!8yq;s<xpZcP5ZaE21%*tv_ZYfp*D<I55{+i zemja(8PiXFf$paWtA$z1Bx&70W1iP>Ev@*n3vHHrugC9<Qy#X90t=;GQi$w}`^;B8 zmdtC?=?E;INk1hsG<Y~Z$PPL4&8<~oPc%5r){uyv?^Qj+a^Cjg**5AaqPt2xM$yh1 zpz);=Y3_FoBtwAHD-8t8QC}9N${qqqCYjp($E4k{7YaJLXE12)T$S_IBZBW<s}=jP zSg<L3ndb!bKnkZ0u?2pfx-=Sd6|()@5xX_se-XcbT+U@$3dqIPaq>1sJEJIXX7~^T zQQgn|dhgpM<jIHz*^ntlo6vc%$owFSrGxm(b~H4?6|f$Dn{CaKV!ug~x2eIeP7|aL zxcE$0Y?1Bt&t9O+4UFpU(Kw(H^1zegS-wxDHF4~E6-jZI^r|u@a)wQnmU}+?eMan* z@mL3{(`(-ip{S9O+np=t4>0_g!Km6mzCgXjm{jGl;^mo`anWLW{(dX#h)5s)gI2c$ zX7LGkKEQbnL>slGKb0Wx3;V-Cr=YQCVhi62+<gX|PGC>&$^HFULt3@VL}kN6!Yiz! zuG>a*KL_ENz)1dNG7bnPr?oF=Kqv?B>oE5AAOy?3xOkOeR06vIK0mC)M4h4WJ(p}? zvFXl*OSaDAxA}9Kff7@58(yW6wV)|Dd3fpVmTU_PxL$(AVau2M-CM~4c@EEv%Hu98 z+Oj<qoc7!=+ZOcS#=jD+RnzQ;QU={H68rbmRCc*#vC1Q54tZD>NRio0oZ04t^_7U4 zs0qFn>~zALw5OPHqd1I!wb%#wYs#6WE#~8H%vVmy<6gA4tQhZ3PhgBG$`f!ilf*Dh zz23jHQIf|cvM;Q<_6be+An+<A0_%G#BE+)ys5v*XGv+yqO1-iCi&GnygT-KXUUHyN zP==SVa}hdMaX5N%7x^pSaWo|Y{IIGwi)OAQ)?<b&sS6kVp_SdWjNe~&j9@~5a^*HY z^k3I&!+ME_scs296TVz4#(;Vl7kdZMTB=E7Q5EmlcGRg*`CP@+{^sgqlm}cE!ApGE zxjNro1sAr)yDE3TD#FwGMd3LqsZ!_FX(Ij8?;#yWzRFlf7S}{8(?;*vo9nkd#O)>T zT(hJ%7GEPSs~XHdd_dN>5~YSR4g`M76PqV|-^4DHE=CSNw9UB#kz$@baP6{YJay;c zuloT1<n3s?H7%q*ruJ$-zV!F+s~X1RswOL{EJ!OUCq{3n4+NMP+x?d0TNKp_Y-2$9 zaOnDx=CZQ|AcX!IJc`27=NY~OLf)*HR1~!hj@yl&B!NUgp!wY1)RlXe14X&8@f4xk z@L=|PO6cTt6}qu1i7SWGNS@>AGyRhqwE_0DUGjp@6P(bvj?kJ`X^T3W!LPsyaQCT) zDutHcgO^UxOu5EkO@s9z4>~!LG4(q6>M|L=VY{uPq7U3*^bC6MxDp2K^AaS9`c>|; z7M{#-q?J6zW(cDsZJrG0QMtcfwy}_92vwZDWkn=<61Zzp;IJC%J5*hr7cNL{EYxJq z4ev!i9tl_@TzW&3eawV)eE!;$O6+iOK3cZ2Trml3JRzg10|QmN2VxofFw4Mb7gs7; znS6m^CZ%e$`i^X4aHG!b7Wrkc0JR@<<}Oce=S_3cC4W)s?2K9ZAS|zHu!c`H-4rC< zV_H1k(-_p>_BIKEKW;fgK8*o51UlHizmxgoef%sx-q8Fz>+f%2{$z+eo<6;b^yHoV zVEu59eoga!a-e?}>&Le_e|<aY@62Df)t}P9e-`FPLBAx0{~-R`uKQ2o9m&7%!T*r* zL-Ai-_P;9LO!wC~;0N=^{eRvM4D89f{#l6W|I<JG)xrPkF#Y6#fjznSKa1Kw$oUV4 z|KElERjHVN5cX>T@W09#_y;+^1_b{u=P4xkS)dsHp_Bd+ApE<eCujd>;r|CoKLdvU zRf_#TNckB+{I609{z1ymfZ}&4Kc?PO3w}fePa(z6viuKH{w2WpF)M!v{naQx1r$FE r2jj2d#ou|q8j>fI{j(r({EGoskcN7+{*OP1J^oog+Mh_yr*Hoc*B+s0 literal 0 HcmV?d00001 diff --git a/docs/catchd.txt b/docs/catchd.txt new file mode 100644 index 00000000..8662c38d --- /dev/null +++ b/docs/catchd.txt @@ -0,0 +1,117 @@ + Rivendell Netcatcher Communication Protocol + +This defines the IP protocol used for communication between different +modules of Rivendell and the 'rdcatchd' daemon. + +Connection to ripcd is by means of a TCP SOCK_STREAM connection to TCP +port 6006. The format of a message is as follows: + + <cmd>[<arg>][...]! + +where: + +<cmd> is a two-letter code indicating the nature of the message. +<arg> is zero or more arguments. +! is an ASCII character 0x21. + + +UNPRIVILEDGED COMMANDS -- no authentication is required to execute these. + +DC! -- DROP CONNECTION +End the session and drop the TCP connection. + +PW <passwd>! -- SEND PASSWORD +Send a password to authenticate the connection. Ripcd will respond +with 'PW +!' or 'PW -!', indicating the success or failure of the +authentication. + + +PRIVILEDGED - a connection must be authenticated before these can be +executed. + +RD! -- Reload Deck List +Reload the record/play deck configuration. Rdcatchd will respond with RD ++!. + +RS! -- Reload Event List +Reload the list of scheduled events. Rdcatchd will respond with +RS +!. + +RA <id>! -- Add Event +Add event number <id> to the event list. Rdcatchd will respond with +RA <id> +! + +RR <id>! -- Remove Event +Remove event number <id> from the event list. Rdcatchd will respond with +RR <id> +! + +RU <id>! -- Update Event +Refresh event number <id> in the event list. Rdcatchd will respond with +RU <id> +! + +RE <channel>! -- Request Status +<channel> = Channel number + +If <channel> is greater than zero, rdcatchd will respond with +RE <channel> <status> <id> <cutname>! +<channel> = Channel number + +<status> = 0 - Deck is offline + 1 - Deck is Idle + 2 - Deck is Ready + 3 - Deck is active (playing or recording) + 4 - Deck is waiting for GPI + +<id> = ID number of current event (from RECORDINGS table) + +<cutname> = The cutname of the event (present only for <status>==3). + +If <channel> is zero, rdcatchd will respond for every event whose +status is non-idle. + +An RE packet will also be sent automatically to all active connections +upon any change of deck status. + + +RM <state>! -- Enable/Disable Metering +<state> = 0 - Turn metering off + 1 - Turn metering on + +When metering is active, meter data packets will be periodically sent, +as follows: + +RM <deck> <chan> <level>! +<deck> = Deck number + +<chan> = Channel, 0 = Left, 1 = Right + +<level> = Left audio level, in 1/100 of dbFS + + +SR <deck>! -- Stop +<deck> = Deck Number + + +PE <id>! -- Purge Event +Received from the daemon upon completion of an event with the ONE_SHOT +flag set, meaning that the event has been removed from the database. + + +RO! -- Reload Time Offset + + +RH! -- Reload Heartbeat Configuration + + +HB! -- Heartbeat Pulse + + +MN <deck> <state>! -- Monitor State +Turn the input monitor for deck <deck> on or off. + + +RX! -- Restart dropbox instances + + +SC <id> <code> <msg>! +Set exit code of event <id> to <code>. diff --git a/docs/colors b/docs/colors new file mode 100644 index 00000000..687351dd --- /dev/null +++ b/docs/colors @@ -0,0 +1,44 @@ + System Color Table + +RDAirPlay +StartButton +--------------------------------------------------- +Playable green +OnAir red +Disabled darkGray +Add yellow +Delete blue +Move magenta + +FullLog / Log Source +--------------------------------------------------- +Playing pale green +Selected blue +Traffic pale cyan +Music pale yellow +Template pale magenta +Manual white +Error red + +Cart Label +--------------------------------------------------- +Playing pale green +Loaded white +Error red +Macro pale blue +LogNote lightGray +Empty darkGray + +Operation Mode +--------------------------------------------------- +Manual red +Automatic green + +RDLibrary +Marker Colors +--------------------------------------------------- +Start/End red +FadeUp/Down yellow +TalkStart/End blue +SegueStart/End cyan +HookStart/End magenta diff --git a/docs/copy_split_format.odt b/docs/copy_split_format.odt new file mode 100644 index 0000000000000000000000000000000000000000..4228db07f3e92cb79b97c183fd6a248141d841a3 GIT binary patch literal 20186 zcmb4r19T<b(spdywr$(igcI9#CQc@HGO=xQ;$&jmc24a4Gw*%x{qO&2eSfdjy}I{) zo~qi_`<&f%PE{+(f`Xv|{n^4Q!g%$ESl}pspa0pRe($!Hwx%wg4yJ|<4mOs?hAx)& zc8qRzCJgq5&X&#$_70|YCicdzwx)J23@)Y~E=qq1gZfSVBkVW-UmNW2Gh=%@mp@1k zTbl!I1N$`&B>$}vBDP$`6!bOeMV`7ahA#nMZ8hhym2!_k>6JM!Bj%-E400YUA9^38 z-6Un|GnZp*D0LdTmoYqh_BO6!h6^rk36CsAisdXB#HXy;WBK~Ts7M(k_^(=i(0&#@ z8h>^;V-NG0Y)FMBCPD9osbG0f24J+GnR#!DMN}7NoK@#i&*`DMnGT74JJl%aaHHqU zpCBoNZ|PHSG;~(QjH;*A;;HPZN3YH&6*qV7rGhQg*r}_8%|085C9lmko4@AO7)NEW z^WI!etHcFsSgGVbV=KY|uhOj12X|{`<DxsLkC3TULxZ3*Y)wPZp3qPlDITA0f5@|0 zAY+yelUpbb#qnY+_u?tfLY|v}u<B!0Z*uO3sR?aCT|l&_EH_fM8p1WYVex=Xd^ouH zVaib2c&Sa*A);RDp|K`UsW&J~Evt&W%~8tU;_Kpq*LoCrXH)Sc=h&|%&bLlOFiS>< zoqEDED^!gh5Ij|!R&2UUitGiNi{E;pq9uu|?(g$zh7|KfCbjR)&@czqwp5FyfC&nh zpC1}+tdNDA+3`IPdd4cXLX4R{6<B(s5yuB?wW%BjWIY{Nq??g7x}i|&Y<9%Qmt!hz z7pf3i41qdT87@Xd$aJxaN~_A4CX2AJPVN{_hdXXnzlY0L_wY0qFMJ2>#u$f1(8w_V z^{6^BsegdKfSmsdqH=m4|3^F`OHm)G5(mso66N>o$3QccoQ-(rAc8N-(KjFA&<^kk zItMQ)DA=6DHlNh$cvEnU%XX{QNV1DqYEkz3+EcBIkc=Cv_7@=>biNjVud0<djy%jl zIXijw_esKyHMGUu_Q}=<9A;`W@%byQX#v3J3g<yrN}$X6$m;Q$R1Cs?5ZEJ0J4lyW ztBXHNpb3Rnd%K6CPl0+A8+QPGOAbCktLbXBzD60xFl`u}<x@O-#y)JJ<wQjNSJNlO zKFb|yHmE-n=?!mHz__cF8bfLxZueww8NZ62ae>;pbL0IY(<X)rf&IWUA?-S=BX9aK zT@*05WZr#C&%9;Vtk_L)6PrW-eBruZQwB$SN66mN&;#AG-}4Ui$%~nt_$di?V{IwC zz4OiSQa}svh>$tw&uJHnvpVNb-$;!5fCI3o<KO6N%py=*;>dlhvKHi9)4P8|O#b2B zMcIDttK<59s4v>a3GHcl;6S^-Q;@nSaxs^@I6-?pb=g%6P;%=T45D53s2ZmXWzkMT zl(PC<_oJ>{Aw;D}S(<wd8bA=&HHX%Faxy|;NXx0Emi5|<KPuLvt4RbaFAlsf62e7P zaZ}YTLYxa6btz4deI#!#@@2J74^oRIKE{2)bPA+=@g5C<7PzKHMV3WzB5nu~96_-g zA!kq0H8hd07F^4(S8s3dYxZX~Bl}S*XC+}GH=fqtyi<E&)B*NQl2n>%Fo_-t(+-V9 z0u8q}9y$gj6nUJxtSt+eohK1u=%+=rM34-*s){Q@6N$r#aeQ=cudnqi-*Qj$(kJwT zj?{W;e8;p|1h#gq+jb^Wu81={L*5TMF>lu(CY%^Y6OO}cVE^Yl-EHr2Nz~Lm+VfsA zuUJs14pZ23>_BRH3M9l|$#w~R@IfC_rF;h8;a0+7<;~WkHegSM8}y#EsG($iUgSa} zLtDm=CHQNM)5)BMNLX~^80Dl%(4~uv&gg9DmZr?1@016mEg;0xa7rRzcDqT=+c@*{ zLdv<GAUF~!nhW}Z>#e4s*sQ?zzuuP$mo`uJ2S@4z{!k>$CfH^)0W)-t1aHuZ%~J#& zwm);`e>T8lugX3sYC<i&5W2_`!iPM?lT(Boo5^-PT6X@@Q3+g4A;hgrrz*EMNZwc4 z9yRB>Ea*3~&X>nB(&Bx~$>C-(`h6f1y$D;Zr64yre6_E3;CnpxYbS`uat%(3!OumH zBR{6~g*T+!?zF-VFTj(6Zhe{pigT4{cLOG#(DaJfd4=O%Lfe-1HD{V$S44^yA^3-P zNp87xCm16W&#^-28Q&38GJ!fsQ;)HM<3M$;UjNQ})^}%k#q;@x7kJ5`lAh1Eipjc{ z-29caGHpmN`0Sj{O*g#sLQTt1WoXAwB+IxIe;E>i-QsVePyM^3=BnoIjP6^<vYa)L zm`h-F@HaRD`l3fAxmOMHn_{9maqh#_Uk2_dQt5#0=KJ8;7v<w|ZCr&FH;s)LPX!Qa zZ<pii69ZX9!-VhmAT4cRYi>;i^btn3mzJ)ie~oKNG_B53h7WJvTVkis4yM`LlcAed z5PQARJnR=)oe=7RV^d!%W_!i<h%X%(lMkL1A0l`I^^->0!qUHnQ|D3{Id`_NUS=;} zb~_$D9MV~+KW&q!JrKH31%354ZQkb5p=cprv-r*sBbxB3YHyI}<iTG+<G=ay<RI}C zhJN`vXZk}>Nfr_+t=M*j01^mDjRpwlzh72ielM%eE}k}~&VN?b4Q-v+T@EzAs~Vv% zP4*PQ->`GXs>@~6X)l^p+#fwnQ9vbGw^9+n=LV^Bd665Hqy$NQxK+ybdrx;}ds zuf8b=Zo#m>ZcLHjC3^$*nPn}yzd#rWe10?QeRUV?GCgCD9wjk!Opn(kAx5M|22IQS z9zx6zlyC$a3Xc9A&s>bor1LBI=tW`3Sl4v<csRzQd%KyNxomx^FD30}L7T^dLBsEB zN<7Wq*ZM!_v%1ZEDX+vM7vTo!Xln~8HO^Ht{B<C7sK1M2X{fVTUWP{5_gM(!gk`K^ z;c@zikE%{24-iX7s8IA-V1=Y`lA=5|DFWIl4osU#Iyu?2b{k3~H;UaQ&N=X>2Xw~0 zk3!7^5U%uQ1v}j%cscu>){qmwJRyg_Yz-sYGF(^IFbsNwsgGOEtjYIZOqxfr7neg9 z3pKUv%~+sh*oSqrkLWwnK)WyReLrVb*n@CPc@_fgrUF9{bEA=`=hReim&p#zM2i|5 zigW#h06&hxr60xNv<gs#YXU2zu+pmzR#F!!E$)Pda4m4oIOFm#=RL^~#?;$O%MBhV z^LSiT6Jq6K+WIwVdYvBF6x1Wl{*-FUg$NOMlfqtbVu<|~2utC|zrz~TyDinYD~X$c zszA)tnX=@BrZyDU&O2Uq>MrcD(zq2se~)D{+@bzG5(Z$jFmvld7)-We{HwoOYhlj} zxlw|`Bzmk-AE#=6H6MO>FlFf5K~;}(FR^!PArgC&5ZwR<Wu*v_0aC=n*jKiw{4Zj} zVgxTcnGAVh#1_wB5g^00+qv|6cf4Eys{Q!#431Yx>~&$7PMt05tok|gIJs!+Wu@yR z4N*0YG?_m!(~P5&zb6q>`vuF6CZUW#WFVPoIcnR~spnp3IR+X=prHgZ(u?0yo9Ygs zq-8siX-Yy1-v*b?YOLWe;aV3qAvc2~Icq>AGjEu2p8vXJwU-eF3e^SIq>cUZ>nm__ zXYf#m*$|0vPf*cJYn&I|;B)Z+E*41}LHL(+S%fcu1Jyl&`01z_&OT?`cI0D^G7}OD z3oZ8283%2)CoMqAi*HX$p>}-HKHVdfx~!AT!{Rn-9{d7nbDm`{eWfJ&V##?17Z@fg zOzs*%B>ku%WUo`wE*bE6Bl|Cia6buLM6W|V<-<C<=$|knwZQ>rNI}D>a};PYRB9I0 zNl~GR&mOBO6ONY{Ko&ZzQ&LQnF8HvMv2wyiv&AZNbN&vYR$21du9m)4Xl|@g%O8#z zZkZ-&hf=npwwKXUX^|>6idy<ggfC)y9Q8@9>Bb0rv_tCLrD{PC2%d?%BBf$}Wkv&E zT=VfH6ku*~iNO<WME5nasML1&i<i|cW}i`$lmk6cTpl2CyU}2Q4~3zdz+D-x6a!I9 zl6VJug`Bk{{8XLPs~Gytv7UGceD&(~w^`5X6jBTkY$1qf@2tH2Yt|%WwV0_FIK0{L zCNAmZ3o280bQ$}(s;-6k7F9DtmF?RURtE~JGAK3M-7isTG$!m(58}Z9-w-xhqyW9p zV?W7z$d0FCj!5&)FRmc9zGUx>gzU>Dj}SaNq3r`y1Mhel)DV3JfdZ281ncrM%TFq) zd?!p8gzpxW+4v1q?`G|<q$D=f7we8Qn4Qff3_szIBEJI>BC}JmH(A%auQ(TT-f0V6 zL4AOCoV?Qx#aek{?mf!nd8mL`k5(of&O3zm35KF%G8LOh&Sq>Z7efe1HmD_GtGEkd z;kfKI(sX#8mMt+vK$kxv0u=}hBYB_q(h`ZHakjPhTu1O5mYJUQvfDstiK8^~q(J~x zcx+SIyVYy-&?I!Ud$A3u<<z7ATMeI;%ZzGkKVTTvbO>FD)Kd=a;r4sXegh1|0`_sR zwl=Va<`AMv{Gv*hetI|=V{N&A^|=~;`oO_bw1?XZLx>`L!xGd5-FyAbTKonWj|H6L zU<s~c4c#I{9r;Ba{bsqTVoB-;lM;5%uuo@gVYK%n_=NcdhiUe5;cQ@y>><Pr`^612 zf<340ljN{UgJl-ovTr2m8eAdZfRrn?S`QVzJb)9I`?61Y@Mfl*7UdE&qK52s`cXO@ zr3KY^Nh#f&lQ!S9^n{Qpw!;<rfmV5hNLhbVls~H5;0ri~oqX=PW!McWNtx}-715cq zAaH(P!)&T@*7s>@e8|(>;0cn$A(gG=M8JjO6cF-=Rd^!&P6xv$N14i-p)w=(u4b~B ziF<dPGCiTejqJ*!DGPZ`W|SF-+KRxsmtag2bURiNw$eX}T-(*jQ^Ky(%?iW0*hFSL zK1iva7)#avI>hUmv(gP%f(t~`$oyu;h8InMhj-q9rHvdQsyHp@ew!W!U9)hOm<mbx znJkiV{iBd+5ARpYB7gSBy1>OTW&<bbJ7#N5S2vJOPcvA>5$Zc~`y@}$QQ)c?-&9vd zoZ-xfMdLz{%<Ld0(vlgac@_#6GU1Cq@YALLpS5>9Y;R8N_u4B=_0P5UPaOLvq)mmg z&*cFF0{XN66(5_r82(v#`2>F-h}=w_oPS5i{3Of_Oe936cE<K5mUia+B<gAs^jsu@ z0x*2`W@eVgrab=)n(2Q>*M>yDsdmmh|LEc;adooe`76BUu`{$ab>?v~=K1$Ho9Exr zJbx+rM~jDzrJXfDiG_=c0}mskySqDsJ1c{|lQ|<ZH#axqU%e!Mt1>bE7tX=e$>uMV zi7}(8jp?6A-kFh^ftm52*gqEjZ;kqc{dbe>?d|`i=+7AbF~q;ru`n^QG5+J4gy?Ut z{G0n&NCf`rt3N^o`2G@Y>}2}aPZ0DbhAyT8zeRA<Gqcb$ajG#h^RRRAuru*7{uekt z6JwtLMBw0I;pAcC;A8w}=RY)<npnF0zGd_#u1<ex5>QfOVwGZHmS<sC{ag5dg8aWs zV^8DXPh$eVCI4m0Khb|T{{w4oYG?XezP*!x;%~1g{xv85@(L>h6Pdc5r3caf+iu|C zWN&3^?83;(#AM6DOeW%LX=6gq&C1OEx0e4a@E-~soGk5J{<D`@d6-yun7RHY{Tt{X ztbff)XP4iDcXqKfCi-g(E`~-nru4@4u68c`B)=#2UyYWwhUWjN(cb8fng0>$@NY=w zzv&K!PKM@Ah7K101ha7e-Q#ZWWb&^@rhlq4w)jmjb}@DOXBRUYCnpKx-xI^t`FDqj zshOpnsmVXg`}5i1Cy}-@vnOKy-@#b^cQDrf9gOV{?C%NA^T%QT_v&A6{;T=Ff40Z^ z{hgy`;c9DSXJ~2T%;@sZQw9e+^Nn_OHGJhIa+q&Ky~JRF9UWu6{H>_##I3w|ciVQv zT*2D}>xfR%L14eX2TGnl2z+0A9-kj%m-;Jl)V-Gy>K?V77fYqk$*~(1!E(NS{W`sG zLcXv$1<J%!%OnMLrTGdmlF!6Mx8syxgron3a^>7@z`2ZQk;pyGUPVlcfFcJ1nQ7tZ z*6f5_a3tbAJ_H+q^rO-0C1{+<VFfM54>+oep{f?R0E4}m>xrD%LBN3!?nPHONbMU5 zVQ6um2yzw@d_Yx*DdH>FeKcMLh1Cu<Z&1U=%$U{vdip-aFeA}4?Z>IhiaR3BK-*GN z%lV58W0>t=Xpcu;)C@!z5iv;U6?@F_$0v4Fw4fb)2@8U2Hy`~GXh_Qp@Z=DAI*2-i zp5>Tcw{_je&lxSlO9SUg%F$*~-+L~lyp193tssQwJYmI?10pDiTkvaIOKi}c;>CE3 zVdo;~tG!=a=S~+^IIi(@n6~kg{jVpqiiDs#x$$r3=QhSxjseP!#X!U3bXUedIGMPA zN<-f~H95dpP)<{oS5}^n!ox>Ez2MDlZP|ZN-A?Ur_oq`tOs`S6gbQ$kf2qaiGC0|) zU(2ki)!HKOOZ)!x5GM(xtJVy*So1T2=zF7`%n?c(ChY+kaqO*PhaG=DJ3rQ^_jdR= zvZHIF{(0wlZ&3u2OINfd?-o34RR^yQ0B-7F$|*4Whif*JTejM*{>DxAYK05&JFi5U z<mE5l)!i_2pEWxgUYc-x67_8*TVXCD@Yf3thwKM++EFtOX!oLGOq}W&qd}~$i%H@h zG|h{zg;ndHE}i|$I(`IgI2j(~VeZNJhNLHCJA|!evz!i>dZg0U$ztW^IYxx|ao*>@ zYOTj9Y<*Pn)PMG;UNC1Hd4+<ZR^Nbp=!-6JJ*|Y5qG_eUWhR(fbPno3JEvwL5g%7I zShtrDNJe|nNB?l~Zj+90Lv<YS0jf6E%k`D@O`VQc37fh`BqmeyCNabmh;NDTb)qYu zKF+JX{XVTDm7u}xT0dHrOdGZy>$3Ds6BfKw+58o7S;0T==LwwXv&L#Z)5W8$@Kn8e zfA<8(vtE1ivL4>ZGiAx4wq|s=y`6i9<=@><Fy-JM;&kv%AuLAJ`aUQ%6|KT;cU|Hd z`j)OdTk*Y5Tezq`yT7g`y(@h!ge4oiTwDXeuA4RB7Yn7k1z)#t+@;`-J_|Ez3*J7> zG)?AEGcri9n~XUDElw+ACk#O(Zp5X43uVdZ1@OTS)?c*jtk(+*3*@s)?e&!*^{br~ z25)#k(2cGheQeLB^OeT<Yl0{GVPMUc_ygddy9X}(3`x(9^8!eZg<kU!>z@3r{Th<u z0(Mn^tQd`+W8320Ot+psZak{7oT13ZL`r8SPrG+u3U6o1W{ys5iu3I$>guHBCi`{G zFK_FQ5tcqgUR=>s0Qm5kqr@2EVIh5Tsu|yp1kqJ0i+6&Nwi}#hHsz9=2G+r`ljwVw zL(W@%Mms>}w9)V9_?8PmT|tVs#pj1`0GDmRi32PV3zdAN$J6n{P<v6GvNHlHka0v_ zwD_|38D8O;vFzu&pClg63d6Ky$PXTs%ZmxZ7Ebq$;udk{M|LXP{_L-}FWWgSk4sH3 z2PktPxRz2YZ<g86E0WOTh3I$P6tOAEnxYdlkVFRvcL!1a3lrodvrutsCb|`Z)w>aq zLTG*AJrWqm_a*yBim&+d&0kHF5Y47PL5)Is`BUecW93)}?Dur)AZ-uY)Y+Z@pn9Ej z&6=4k8o4V9_|GS$FtAxo4uVCT&N(QIVe<o0?pJ5Db2d2-MFH18(i0tu9l$<4_t`Ww zwBO|Cx}5x#E@lYBVx4{Q+y;ROswxoT8rAfH><s!6f@kF->Ohns{3>pf**rQJBP`u^ zspmpehgFP&tGzcj9>}UlX5qe`=1kxtY5MaFZH-@unT%2CIUc0#m5q7dy|ox<3JKtU zW>%p`H@mCSeh!3;usTTwyY9Q!OknxMQo)N@GO+bwN2)x^@tom1OjqAN=DOdNs|L?g zEi|W=gmv|1B!?8;hq_MQL(l9vi)Lewb118~B|!Q4?6$(WnO2`Yihnm3z-F87%xG*J zSNrLErr8^ca3&X%i#hDI_y|AiPUHV({b>+SS<$eg5*G2{_iU9IBXyT0ax7=Z1$H=j zT#DpNbk_V35KRd&m~WN|-`G^_lh3AiwpZTvI^(a97A{0J$c1J*_?r6Ued7zZZKU+o zc`TZSp(Z&1#U(2fu2We!yp%5P5L^(`^?P89M0+)VI1(;!2Ov-0Hh<%)YbjK%kAQP- zIuQ|DA=KpUWN@rwC%ri8jHtw)+yngszCpV&PTvq6rPE=k?Ns=o-$Zj(7_Vv2($M;| z?9@1?;4JR@fRTAsb><C!vo@@ddHLn2WYiE1G4DO;a`ba8eI`eS(2W<P<k{2k&G6NQ zh5&cPPfSp$#VU7b?C$CVH_QAVB9J;!P?WOh^a69>s@c1iVSaqHC#Sd*CK1dlFkr{< z9uwy>V6C!J<MQ;Qk|<?cHQ%-#qMY!2>m&`{%6W=!$_e@i9u}zi?_#Hoq6rypk{01o zwe>MuzKz}WR<E5}_+5l;y2eQsP^e6BGpmeqeLk@+RR93RTA=1HcNCfUbKLCigO^QK zue{U7fXE*mP`}n4(@@l=mRjlyRNtgs6h*Ka9SQ=EwM=>_RTo73-|ly0xnWUYlSgu% zLCbVh(POVPf?@;=AG9yiAhX@j8s62-BXKVtIDh|=cCP#$A%B!Evvys{z6@5Y1%$`j z`Z#oY@nVLd+=I@B+@L&qYkvBo7e@NgO16X{+Bq;cjSWWQEb$>8YafFzli=a^dO__U z&7qOIirPxZXFV7NE_$Jo4<qEvB0a|d;b#&Dn;u%!8z{+G-Ba2Xz<9lN(3BvDI43mf zpG+OZ)c9r=Sd$=+6Y=D%@RWkT{Z7m;5zb1#GMn9~^_G&#Amx2faeS2Th|)cGK5XTB zHIAb7IMTDMS_aV0J5;y-fB;3fdUt6^4vB>Ai8!QV&IuOkC{^5_c$ml^OJQM9vcnRq z3`s?4H~tvU&VIwsmC=W(^@n~ho<Av(Agw3eQF#%pnj_mI3xP~{ve!cWV6u_roftOJ z(>+?#80A#75A258q^DO{(~x>okY5ICkm?Ti#nlU-zR5w;Vp45NkQ)D-91O4rt`S9; zk|_Jx<4BiLa_42ifLbY=Y(`w>2j;dk_W7><stf7SHYk#ExbR@=NWjf3uiVDUF{bMQ z9SL<P+%I(J>htxPZ1KRB*PH3`Iw^T0gtCoAm``Toam!PF(_Nbh6*<EvCMg%~wG?Eo z?ky5#X_t=CTf8x1Pb|U_UPA%8c)!-MXy@GYa@$#MK^x@W2lNcj4MW==o;E^zbxa6# zS{zBVT&cU<El?Wid1Uahur77YMI;~n6NA557als4ECewoFs26jyP}$r)dn`UZht!_ zP;d<JEabUsj@)o~4#sj;*^5zxR*6ex58PBfKKK^%AzE;p-2IYAHzP^1Na1~~rG3nn z@m=C4c`8JPb$S6#-_N3;H+9<z*Dym{LNt!EkFf{Hgjz5Rr7$tWYl+L_Sve<QI$9Ws z@H7#7^I#fO9E^h)l@eKe=Nynz4M)`|M~>EepRW#J8`2mx?(Cn{y6~97P#2cvY6h=h zgiTev!<z(;41BGnW!%ZKPX3~pWVK}E5`5L3B%i){l`{p|8Ed2+%>esFTmCx%7lml= z=B>Tm!YJXXF3}l7#>MQl-ub0(PacLE74iAy1;n;`fVHML%Z8%OqkK1yd>#G1RwB(^ zCvenVA1L3Yk&8GzSst9v!=XJJl@Jv~>gA$^uHNivqsM*RPnoQBoco{95EJOm^&te0 zp_Qo87%9!QhJ{l}6EbJ;Zk@pMWP(bGdmyOVgDWGM_284!00QjIV}iGp2Eh5fw_<r+ z>v{E}@;(G~SKWJDPfznJ(Tp*0<5THyDUTgAge^f7jJyGp9<n;U$UPq(V#(_k9o#3i zi2Tcz^Vi-Xa3do%J9U?~b{tSL0KmvYe*!qi$0b_L<RJ@F2QyUDY<*2e|MLywYoAX1 z<h32|{H%8R`yr#ljM2^IrMUU&nD7yGSiRlBtd2H_WUjR{gqw+E(Ce=}l#|)os~PHB zO;a<ef?1*Q!Mo&>gqLwtLS#}$FTIOkN&gX0<MtXTgwV-y9BSA|slkI!Cr1tERB!MD z{*DHE5Bc4jX#jIN1vlnWdVJ3WtE*!iVWWA4LNJD-0;xY9%}j>G+_{;6=9K2~lE!1p z;$jIK*2Em$2FwkP$OEN>+rA`y%KR8}L;)>mbE=$<1>!-9e-dw{L#r`8U9%3b?j+x& zpxvj>^K6-cL+J;N5^+jNdgOw2J_+Af6m-Yd>#SD(5{?_c37r|hR>X?#6h0_mDRhL` z=wvmak8~~E0PmwG(|tx@OM|2bD!*KH^vnA*Dbrd2YHBLC+ewdzujZv`fT5XbGr5Q0 z`2+m~n|6TpyQLw$4l;EU(N^TC{BCTv*PCCAd7_7bzTJlEIqPA;*Cqs!$bfkqo~M+F z0X$=(eXqwi#)~|Y(Y2A8hV?bQAr~(~!tv-T%oAD3sQAb{&gxOnM~;jy-LYr6X{`=Z z(bfw)J(lZBT+Er|gPxn|3<pQ@qubii<*A7z(u${|J`kq&atB5nWj-m@{*sjp*X4{j zgn6K|<{mF>V%2$ej0cyZoRd@50CzbU83X93^0d#H$LpsWv>jc$=AEi2Gbb<7cQs2V z4{9r_8}X6PnNB4)imRN&-Dw`2wHA&MvoK)Jl(nq23If$H+)hL7Er9ienrp+vZ2p<3 zaJYLo1)C%Ou&pk~)WIz#J2!b*DIU5RHCV#7xPV4~W9sY%Mr>!=jQ*&!<_pmx^X!NK zm~0o&lA9try{@atP$QUYrUULlM%bd^+pRcjxm$xMnS|+)#$yJ$HKW(&(Ap2+!>0=y z%58%)<Cp2m#MPGeADjo-Zma^Ps670YQFQXoRZ>M;$_!Q8$hnwZ;XFpyl&$+rE>QN? zX5VWLEiHA$vc0Vw42Ql5?{u?yeVv?KhYmarv;M%Zns6ftZp%(93lr&&5YS-Xy<p|g z8-!+PM!+dUq1s0dt!x+=Xp^nfclM^MEK|2!r~$LYh%mtM0XzkXRh<cV9OS~}y^?5E zYD>!0C^U^I)EV`dHK&Snx{-*5+161F=~XM7eXGC%u;*r=&J*(pEH@I4<!ep0PP8yZ zj=%GsR_>2|D9#YS*(M<#E1=~KA`4f}>?zAcO&;D0%uEiw>+1?A%($hLgcYwJ*F!vM z5Of|&Xmk51Quu}T9(&KO|7yXlgckagcaIczgRY|ZblJN7{sljgp}xHFtP0)J29V%S zSZJzKHkRK}X#MTbT}3o=N*a~LC#J)_!JSx9*_5TbM@l^h<~7{R2*e`Ff^&tIximu< zEO<T&K|4!yGZ@7@NFFS?1mPVnBXvSxe%=l|O5?Cy^frhqi9@{X5k|W2$)S+AU|hD% za`kH#7T3_XK39E62gSmn;8vVXp&^)6kp2F#d8jibdZAVyqJur!nVb57B867=O{9tj zzqN=fz7s5=DZRQ+W4S<F)6J~`hh4>>d!ijh^JJ)EC@?yg;a_R(Be?ah)rXS_77O%E z=bBj+Gtj%;TRf`3rdrU0H)LPkWE$)@CMzTGetB$@TX)44ukI}FE_K<bn<!GqTmTtL zR>r2@#xEkxU%g9OJ6U%%mFvJ+v&tk2ex)wcKsyA#0cG%oE+O_pyO3AOYe|9-!~H&Y zdmF8gXm%yvwT&8(s;ouyieqEnSA{?~a}SX3q7s~(1(sN`M$t_#55FKW*P<DiEGm(? zTk~Q0y5Jy-P-(8^O7j5ic7M(a(|z+3+H%(0Uo{le*cI`I98`3Tn_GVU&hie=1nri! zC|Sya`c9fJY~9b^W-`VF%vYM{CPHt6!eECG7RxzCM>Z{X54II?z}~!ZR`__v$jn9q zj7~=;RYjPn&e}5tVG{0qrQ84<Mn<fAe*P`D|4x3S?s!LbXPL4ex%tIx@90ooY0{cU zt+Q);pvU{FxJI4@F@v-7C`Yq@?$dTIPgV81wj==9n$!B-@0xrjwr`P$kX8X(-`A&L zL7o@!#BR{|fLBoaOA^p{-kyXrm6SF}TFGjGh>g_FC-yC&Klfqv@W<8uO>GPoE#=Qf zuSRIh$KW+0yk%<Io^q=ixM2sTHaSyFiPy;*_k}yS1w`78kHl@VJ!NQa05U0Mh_~Sl zHs6H#=g1_FpvZhGB3CK#{wHoA<n-I+iMf$DlsEjd1C&z37Iq9EgiS|1Ag5ST5er1~ zoSl1qC&qk+^guGpI|Ixb5-D9JCrFZ3$K{tt&Wk49gQ=+V;%0vl7hbPWNY9aNp)+}c z5$Ow`=omM3q%R38O{r)*K_2Vq)S4Jed1K?eAES+hMn}1mKBA8Rb3{v5p_}Y=cyTLa zJovZbCwOJv`ED&g-P^VhJw(pWF1B8)EVBo>vXQ`E^nK0oAu0g}4I8a!qM78Q%4f?- zznw71i(j!{US>)+m^t1g_v;iv&5ATA=OT*69LpOEa-!USQSff1e?MN7>IVdoUk63= zI8I2NFN@ZXC{mc=O-g#{+xyVb%zGGuY&vVjrW3do;;ta}%S6c8bns_N#r&d{%A27< z%t(w{65~rSP)3Jk^g!NjumDa(O92LQ9V)DqRa<C2YH4rBcFJKg$Aey!#^aiW##$ED zm)}$jr%4(bd~Jn7SwKB?uvSMwAn<A!x}67eSDz<0n$2pCJe+Wdc3ca!f~!AI9WR%J zQ*!f(jZ>&^qD}A0cZ+ik5u?06m8LN^&bbh{F|IYZ@j9NAaSJR!8u0ie70K9IpN>QS zq2m%G8}*Ze*ls_~C?X&HGlN=Ls-@|0(|g`XLV+2wF!E;ZXhos)ll_Ew8IF}_f=9~% zbc?du9OM88x!&)-U{qkEl&W;~<Q-wb*uI5hK=#KdoUj;(F^ZxhB0L(>&1d|RPOmUy zv31Rdbcy9~dIpA*>TbgxyPROY6~5?iv)}d51eq46Q(2B@7)(xTsmMb}#HB=M;9%6f zUGDDDmsgFqLN>o;$sq{u-Wy1R+>%1P^y0|N(LKe#MsZt!*@(z%0Htw+d?M^xMc(;* zP@Gd34{)A4aX3bB87b`6Kc1qQpI_(L8yB^iP_4msnbdEe%{xh`4#5jnYG~ZYiSWiL zip=2NX9;WDy)76d3=%TPl@izaH+PSEM%z9;%8cYNE1#+1c4gsZZC1Kwi5Mu-x@f-& zc5S}p$zbdN@bGbQt<z7+t)ku7RIn@$`}R^Uf1d3Am`C|Gh`+A^R~rHSZF^9>f(aMf z?}S>3>m^m9h{VZR%HW6bz!CN0b1bLyJlhWrD~r3xIdb#GDEhms8e<7`bY;Rl!_@G| zD<C%~N!oiDq#>S_nB1xFdh?-g`wd6pB;)j*HAlH_gFOXx>7Bk7Ya6e%*uFgSh(ALi zLVvsoT98<_Z-?3J16q#0H3=(XGj1Kmvyv9Q?8*jzN96a~k%!_iAmR*=ks1_$VtqiR za;b~m4Soj+e9JW{OP*hn&2BD#y^s}>4J@D@6gnXAN+{eJIjUOts!#z)V)5%-cmN|R zlL`ZW-_Q?!y>;~j#C)*nNC}M9bd=-bsvQ7vUiDU_aOT}XC9ul#;cORLp6Aam(Q!3I zbbmkTTGv$9x-nm6@b+wJVsd{kC~KiDUyD7XrCJqEM`dw@Mfi$6u-p}<UQ@>DkJG;@ zHBGSKK`PHpMh5@UE~3H!q+TdqgvTGVY-=5@#x1gS<~L0?n^rx>ONC^fHFoxe%uj4K zw;&`BPLyv~Q#qBUah)xJ!W6MeilyPUF951z(`M$>;q*~H;?UmbBr&ih(x5gH0gL=+ z)*zK{E1`7Jul|=v(jz?qF6&U+ab8?JOLH>?RP>>-n^FEzsoY{<+2^57!(jt-vS%K9 z1_-t?7*um+SAqGcSs4AWjRS3=%sH@*aAz_>znb0yfF6w#+jnby4-W9G(*-jzZ5QCG zgjX$7;uBf>MI69;Te%GPl_*n*0>+B0*}84+RKbL7E(L3+h-*=YdD}?dZe8sSSCdXz z#2nb<O8zgr{0Ph>d0azjU#g5uCV*ny{DgS=dQJFJB1CzkoCq^C;~Ya<nIuOdW^K-n zP^!@$9GNOz_ZBDtn~TzZ98>>`3bj``)HOC(Pkust(#5e}`Un5AUak?=*fP+rdfB&x z{cG9^))ss4h89bKe&P<2hCS8V``UN+<wuDtIw%#9rlB5?=^C~rN}L?Fk8V(Ksi=<3 zR327m`FR0J3c9T;QYmtHWs1+~Q4zIHaNH@_=faQy&IrXw5e#t%E^F?}-GGTAoycaJ zC9W$)JVcF1nc7{Hr*rwth8LK#MM>eT-H=`_5ZMec+?@9Qu~3jr+9WkYhpEa82>6+2 zAqMFeq?bT)$`r;|pS~mVmo}-M>*<(8Z~qVVg@hzqMNRQIQg~nnE8|rP87-c7`#?we z{P%#PgQsN3r7k8`YqgE<k(fFD7D77sJ8kOcF6KwK^gr1kk?HuwUKGzgl#|<*bS6BV zcF7hY!f0ueRu$er;}=w(g>b74S)4SS-+nv?2w+<E`-6QzK03J%5m@oZ3J{lY$@3u0 zYOAyY#Dz|pSAYdUl{MD(V*AreZ#woWULaAt$%H+2xnGxd=Yn>39Vq7?hKc3rXpU<1 z<SpHatDQ@Fwy?rHZdZznPQkB0ofMY92}8pkc3#bZdK_TL6$$|Iv-Tw`Q~l=pr*F){ zE8wsLe&(TDF6DN3psz_Sw^_5Sb8@@hEwAHe*_@{=@Aw{X1(gHpsX<6TDBfCbmY5AE zYDg&`p+VKbJ{w%wPFfs<=@K7j#bJ}~Q8a`Uv#;zqME1kN6G?6v2{2b?5IP1k@hJ8x zSF*Q0<hrke#Av@YIquUi9J<I4WiAKzA``+qwH-aaPKRtK>s{Qy+zjFd+mhNAw$*O2 zFbYUp=vdeBKYp1X1jfI=65Kb+AOT35sT~Gb0^eB*Cd;ZhDWOCO+XQxIRpF)#ey2D5 zX|aONi?|UMU%Gc7l7bHN?CfzajIPm3dG^G4IjOc^>(gf~D^@@R$8puwwIR|AKE`$I zwkE*EE5zx?vw+Q-QW*e=+lk*AV4l1ZgJTppW5}D(&{@y_GxQ48IPJLfy-Kw(9po&r zoU(PYFY8+-I=wP~98gR~X|P)Xhj83FE{QDU7CKKPCN5x{hlR*j?gcd0Q92U?BA{T? zhcV8ier|Ve9N0PSjhp#K5E?_YGKxA#W?ak*j|!sQSR`j(3%QWvQQ#iyWG72yL^OAP zPM8K=gf0<fxxe-@W?wnz_H#Vc?RTp2tUJ8kN5M}Pgl?x@SbMKz8(0?c9|ODqpR@ix zU2%Sv^85`t6gkVP;k<ySE8V`5FuRhcPLqdRGUfY{Oml%U!v-5cgGF|CDL4YL-#NF% zto>D^1>pByp&cwBV*V<iw?wIJjIs|)Ltsz8^XizcBrv)jwxW>&Pt~cDfW}a7I<d^S zh!;pwN|z2rVuIVo{RVmXO-JE8UrP;?PbWI7DQO(!W{J>xRDzicPOWA+FD_FrSPVlG zFmb@@AnOI7P=5Au*Db%jz=W9rHfvpI+XkfX@9LNa@7+0{CL{IHMW%>7w#eW(A4Pm$ z$mr!-n7S@8z2b{PLMN)dyO<TT+=Am$S)x`<GukvRs+7qM64Y2iPb2|VkAj_?1#{{R zJhWGn6t&Jm%|H+w#Ib?>ttFhKLMhE(gpZ<Y`3uRwK213ZwCSD}FU91Dl1QEaYsWrd z-XbRI7+e%k``6v{sAiRjknH6GU790MnLg8g7=(}=5LQZM0_)`#k9L6tn%0YWDY9%j zU(USYXgycOLM~`J3R@XUX*0|1cICL0J0BL~gzd{l%ZWZgxK>AL6@OG*3YK^HF7g3b z!WrMsbNEpFR%MlvvLeW|QlAhv5iXURv4XFUbBDQ&Z+is+k#i5`j39@A{$E7vFTmyu zc!(iR_nQIRzP+uZc|+OVj;<bRuUl_#`pt&~7By*kPmK}0V}o(~5^U(bJ)8Av1ooic z+Gt9S@Vinp^{*3!^7S7jyw8Sz)=vru?B61u=gc8MxZOhgOFrMP#SavG-V|~bKjD4_ zVAH)a-D58jRjo^`WP|NL9bl|Rr*dxiriyl$g;Q{tvFz*Hkaz?m%5HWDE!$2XPMlXu z3c9H1ib}RYv<~?K0gqmz%5{pE!xAz)HRg?=G1qS`M<dmD?AD^B;ZDwoR_Ra1gwovJ zD{z7X`pCRdUk@Mer0GOFhrV78lSQH6gZ8~TwRgfNnpA+G6itURw1k?O8-~v(D(IM` zQ;#}92aEhb@;5IBdW#~cEZVgZbquvuwLxyjmnKMjyViX_Dz$Df27y1R)r7XWoNU3g z&>k(&w_E}vcjPR`SejT7v3^-bCfl~W{xm@9XqkL^0(b`~F@EU<kKao0qc2Go3YYE^ zV+~4TCw978VNsOQK*Y^r2XeF(Y*UJO9C@oCaMp|&eG%i2-ztf>qV*Ylu21@$)cK_J z#1CU^l$|;;6s<o*#=e&43`0^BA)yE509YilJkU+FB#_y6=@uIs8~6CnBx%v=0#))G zvYmPIEQX$S&uYkj`_hxf%HrqXy2>{BMTcdx#cL_+F(J}ckO1Vtos1v}h$_kKNmp0N zt(LBiAIvmprjpEx=y)mM+SAst&CIrM*6T5M!J@F-tNl<Oz(n_ew`pvjOofHUeyeec zp>W8U!7q<@gBM1r?StEtlh4jUJmPBNAok<#C_Wz!7)6;BB32miYrIcHbUH->0@1VU znfjRpSr{#wc78HbWbc(z6ugq)8{?&__rMP|Yjz=a;z@!KlSJxhPER^onRsJ1g?P8E zNH!(s9xb4&)*?k@%#jCTl+790>>(>;y{LUffS}32MK`602l<ymW^N9F$VO<F&tM_A zTzc1(;BREC$rQp7(O!lzHl=8_H!UXF8;T<X!Hk;EEs)$Ys2cGaj$o(7))pwp7sMb6 zL(^r(@;Q=ca@I7ZYg4iDAhUC!%V-?zdb-5VZrSGz&RFD6P#OoRd2mf1QRuYVK*IXe zy8b+tTKP!w$gpq;W*b~z;T0Sy#u$1z;&j`8B1`0P&2TL_RlXF^+^423Oo>aK<7!eK zyz3?-oBqm<G%JqSY$}GOk$#Ak&933_6tw7##*xsZ(o8JQi~jOK!Pn!1Rx6}>-2-7{ z#UijWcUc!gtQ^k?=!vnB=g?QsA-hyv5|B7H<uFM+ym6eL6zau%se7r>WY~2}M)dyl zs7?*@q<Z&^4UuvREC($6dzR|pGa}YseQhJ0MU1NQP`ghhIMoa5W_*dB&oW6f2(Q%9 zDo?e*WOFs)-%|@almArPglppe9vvJ``$M9`6q<{~|1j84)|H45-k^``d>qlLaawGC zJ>_&eYaiUl^M-$&VIw;>REZdQO)2S%a?x1#X8EAy6xFSvzRN}!h7tcf0)O9TQBq;j z-Q&`iw1ciBWHvze<zQbTQtr>wFLgT8m!yKz+ws>1pcc%doF7kiv*vSAkx$nlapw<8 zH-3Cc;Q(CVnaI*^EJ@aR?pIk0rTUj9CN#Xeszkwq@hRz`joy9FsGnC61Z9ugSKAsi z*e4RoELWQh`We~x?=K84bPyI?@wS{(X)DyWdb|ud9Axu@(5gY-d>~huP>Yw^Xd5AE z+v_dB2iyItzF^*G;E9g!$FbVR>z4cw@YFup?}tI38}KbLm%KrHvMsWoqSq`bh*4T; z{ei>^;|%RVb<if9LH)d>j$GX4Xom~3#)z@~eR{kQ7a|H>4?j5%n3)j<pHPQ8b?Z?v ziOL7}$1K+s@zklex?F=H_yvVrXVaTWKhaLa60tBq!R&RDSXZ3kMP0)a{pidd+!ULK zAs@xY__UpDNk1M}V5h?0fZsi~=jNtiu4j5e<@=bKaoU(AcP`Cs_#0DAgD)i)JNKQ_ zfOLJw%u+mQx|KF+mdrRKI!{yVyV|piiEn_@^YA@8KA^W{HOk>M7M24Cc-j!kc=mKj zAXSP3tdBTOMB7-fUWy)*rhn|A2EJsH`L-B$X*mr*paF+N_(|4A<y~rs-n5@Ly#~@O z?R61)y&b|Fz*7Pt-Z@%-M)Wk-&i}k&11m%k8F@;<IYj1}^8_qoJlt*L2?%X-EG1h@ zKXoPNCPRLD3J(i&A2jUQps`By@=a?4pB(tHOXP??+C)!ixms3{_)4%%w>Ev^voU~i zl?BSlta+JTO9^bUVJd~0GX7)Ct}l}LE6sy+C3Nf%vC#B-`@u6qJ%ff%fL_7-b?}13 zfoFO~Cz`tuvYU<v$QRCaa?Xz#TtqsGe0x-0+`ID&Rnc2(SK5Wt;{oTcpL*-~ID#a$ z;WLLdZUh~9>H;QC<FEbMLR}Z3QQie?;$OHpL&62Ng>6A~Z8Y9aJQQM#dx8-B05iZh zDJE5qyo}H51|7gikP3G*Z!)E;W2M7~r~O4z^c=(tn3y=YoTQ^A8xam)wT^E$mZWnj zlyEc$Gk_)?e*YOgjwzt^a`0<-q1Y&5fwcEcFZmkHOkL9aS=j@<hoA_kUNx4aH1!Im zC4cq?f8{9<wP&*=Vnn|Ut^9ZTpdF&{m5Wv|<zV;c$OtiXj7Pq_-6MwoC>G6QT}a0M zh*y}wt{1U)f0Dj!?DR*!Y2~DAH0g5Q=$F!lIDWXOvIv9`8We3x78;4rpIEs4s@m0r z;^C3GZI^S_BNnb~Ov4Zn*ZPRec$4&Pww2!M$!h{Tfj}ris>V+uLnr50s2`~d0@7hT zDVv!f6$=n>L$ePX-%Y;v_9~4s&CQ+~zMT4(bfNmd*FAc8`a;CxgEhvZy4;LnxylbU ztgho=YfyHn>|Hdw!xi}@Qmtw}Qi!s7NEm$8@_>{lsjXmmq+_8#p?eZ|(Ls}TNt?JP zju&Rmk(`9%w*XzIZlz@KNi45?B^ASJvQ-oLfo<K?Qi|aCUN=70^!c#)bVtSmxgn}l zAXE|3SpnZI$j<ZF|EnwKl|)4Ws`NUFUcD!-#7bkjoKl^A*MW0)D3tAl9X(pG;icY( ziF5;jsiFAoVSQ`$kXXvwDzOMd1&P$GfGHAVu=h5&4xYj3vkv4mPU*6C@IvV;(<(ga zT^smCk%u5_c+Sc7ty4^BlS{%BVQR`Th$)2`QN1iyyhs}d%=J@_WQJ*#Ay@2-&(Cw+ z6TZ$&(9B{d-ayKVV8m%C$ly}hU@XKC%P?veX-4HHSFJX&0hD@|quhkLz-cT+P7E~< zj+UikeCXk_l#IM#(r!jj(0j*fiY?Z)fuv`l4%JY-`x1l?Nz0>BA1LzCo51L9tPB)_ zv$}z;@ObV=ASfsZh|(A`{Wy6tTkTD=5a3;BteqV?v=3l$IHM#&5Aw-h*>uH=IctS; zN^h2VhNC233Rdiu5mB>sraY?YhW$aFq?nd96#QUzzYK*?KOyzr^_$%6IZnI4cs?FJ zt^07iN^4dvs=wMI$|Xq3lI^^Z;_-W^Iw>Y|Z1i8o1V1)>`@B%`{bt-|t>B>g%Y{ME z!wjlwE{ZHqPR>;^6aQo3`;e++e`M^Bf^qgwHGl0VkM;xpuS0qfcdPwnkc)cno`aZk zKbc87HzhTpo}QF_6!~IUb4`4)jg<#$OUKC<7J^*^5k*>fi|*URLEM)s++U>MiAsME z_FJ<9dz9$*&CNVZJ3wL#mEM$C`)QJ4F_@z5I!-6X#HOWGq_^XpS+U6I*R(9%&n*N$ z4z+x93m@qH7*hX+RrDy$idK5F=J+V;nhrY#kPPJa*=k=~i1@juB*yupISHyW?b@xZ z;Do~V>>ve)G7lY?FZQf5@w-`LS{BE#B{|{{3szT_FbOO!Q1qj={YB_);TjxIM(7V- z?QSqXO_|cMhi8!Y*P$VdN-Nir1+iIOOn!_$-4(YPdhuaT8TE^-!_dL)5anubdX52g zJNFG(2d}<w1q1Gn4laT)G@5>muYlkA6NLKu%>f6cHclj8vMgJg2ny`-*l*nq{A1DU zy$SpABl(#sRT^;{le#}iLCOnhP{2n-ZPN=U_FqHRu!sW)Ity=DhbX*uzT+G@dQvW; z>47;uz@`>15S{V3M@UA*?<lYdUog>3>oxVP2Z@damJU<}f<3g?tT`Wr$O3&R2|MHT zPn=-YEr$!PEsKoFnDB%||C)Wt25toWFm0&0)LMdf*4ct}Q9Sn*o$!{|v&z>l<t0Xy zeVp4(^=$-7`N`k4K&E5o!51${QPvf7Mjy!&a_k0rQuOQDO+(cqVi^CbIX^?3Gbm5W z?ssln%Y>wzXy~0Za26>a>)6)MRc(NfkF7u;0n9bg=x%z#io7%deV_wu2Xd(SIB6RY zp$MQg0}O*vChTiekkxoFjg|cvwi*|T($CyZMULhA%6xV0qOIh86#PV7(Cz95BG6QD z-ES;87<aaJJpj7MwSZ~R&>rV#jI;B&b_Ua~0M$4sn0dm!Y=bMqE=Ll(#Q=9s@BM6L zD0I}Loqb2i#4@}uYUe40Zd^7g>~M~;QRg&I5E%<vy`B*wJ&H7obmOJ(F}0z-XBNpK zquuL2tDu~eE4eCtsG}17G)C<Rt%uUjB{?Y9@_>{z@~{2IgFv8LcT8NblTr)T%1E{5 zZ8U*&w;UFzUzmgu(eZ}f38=z2>qWeD=30a%T6VBHw37uXyfCgTM`{ie^_lE=(l}RQ z-W^&6-JbZ&PuRy@)(jq*?t>)d;&SX@wA9ZR1hlBWUNH?CH{)rW6hx4Z2!^eZw6GKk z7Cv<*Red{+St&lx1|NwsPLsSnF*UF)7=e3#j*7Q*>&8;RDc_e>sxbOgUn;jkWClPt z#8j!cY!df7$ZrC_y>d1P?%hE|6OO7TVrzA$OIYJ=H8hlko8)A=&$cb8QsYjmk>MdX z%+Owra8CECmoV-I(^RjI`0rkc;n%3nhHH<WlsPsHU5G>`b+Kj{+*iFsWoW8z#(F4z z4U_nUfy1EWQ>AU3=7l41?5!(t>8PyrWObAua}=q<I?n01*cc!ja-hEaI*p1b2lf0` z*xfUKyvJKeWtTQzo04WJpYbbAg{)0+g13zWm6oM~T!pNY5L>NF>}Y+vIa_|(ISnPJ zKG$MXxYrwr2H!Fa85M_-3ESLgyfJjz`pJKv^6>NZ>pOf(Byb8B4eJrk;d@-7N<t+H zC&CBepK6Y^?z}E4dLW>m4F9a=_^)12@aK&OqV{%Xmgaw_{yVcU8X6n_u8H_7Q=ie; z)ye7amluHkF35!ZQ~d!1^5^h-`$rP@pR@n?-UGbfZU0g1?`(c^CsSu<BSR;~|DO3L z{rf*M&1~#{S3dktES&#><zVmN>hQa=!}b4D+aJpRzl|>T_BQ`Bi}1g&@vm|MXGRfA z7h6LI=l{Xb|7w7L>J?o7&7J?%{e}Cj)Y;VKPj$y%wXzf1I;y)eNPdDneY^KbvO?~9 zRHn3IK~ywOdY-rm5cLXXDy*msuV*ckxo0Gf+{CJ`KEjFVm)YGu@Auo!Ev8bjheRen zSH$z~MrrVXZ(9j#PsH=KoMU@1x)(mUj}oP~g%^(W@jz6EQIh(|Z=hOOzv%UJQw;>F zbH{(HWI+k6q^bEu`jv65++I@?)%1)~7N_>;d!JlcsWu%0#&^Z<iHf>%--~35ROB|h z>F&9HfX(@;S84XB4|4mf7jjlcOD84MpEb6AbT~9J-$Yyg3R(S5s2^j%yG5ntj|T}O za`B^J!q|3I99UiB2$)X4OJlj|YKk9J*B+LLp8#Edvs69Up2~bq<l^?r$*m`#E9srQ z<!ioMWHUk{FPsni8g;9WQC1cn#T!oGiA~E&QH{BQ%u1oVxz7wR;T&8hwxMdA4$e@f zDp949DoLmfPevuflSm)_BeDETuu@yg(_Wm|Fz~G*^oO_k#blicqDGk3#nDZ1k7>CY z$@JvniS8u9ulaS}x=PT2VszOyAC+I39xPa@BRyIubrj{i$m`PdsCvQadYL2D&P5)r zI!`AjE0!EPq?7#wk*f-=*qEn8a#r!^vB~|Gc=Z?Uld@h}w@2$RuU!VZyVMMBYx?yp z+FMC_x!ctLXCGo4`Hg1md;BoE!Lxer!8LceH@LpLA99^P$x&q6i~pBmZ+9fE@>LR8 z_aIR`WKV2+Wy`s5*Vom~@VT(<%Dke6wkI-Dvu_>oxa{?$++ni9jXc(!H}5NRXu0(~ z=lXp6X_EAsPX>Ei=WLPx>GJl~3;nH?6~OhT#~a@>J0~d#uo(!kmwyurnj;~swsbr5 z>1TrN$D``IuGE<;pAZrh*mn1{Sx|TV{rL9G0|pVA%kMfL68&s{r(T2SU8oA5d*+;3 zs|p3I9VdAFD2n2jIJn_j+qbX#T~9B6T(Cju@b1k2ztp5Q^L<_R?f<9c`9JgeukCK$ zuP=M++uXBt^AB&m8z^r-|9JnlyS&<t%O6Jh$5y}GU^VaWX47By)|8xTuK4m-tt#rO z{N4%2>XJ7U9pc(2|KR;P*S4uUY*(DOy%uT9yYgwv_u}=AE5BckvP#T+)>>!6XKhiy zQ}?S^NOtq_Q*$>*Y|+cDOn0|G_Vno;?u+}c%ieous(a;c@g0dN?uT8UzOA-jV((^~ z{qVxC<ma#I)+IBA&z*UH$F8^LF=kSC+y%bv|02cgeY@lNt`i=T%X+vS_DnPT{CdiU z^v)kkx(_Q}>CU{=?z^>fwLy@!b8TL&fw@4?%gZJkO=f0o`fVZO9Q5qx{FkEVW#!zM zmh4MCG55b(-|I(=8h1Wy<Ye2F*Eq}dt3r<fb5Li>w-*ZiS&KLC68!i<!*-qk8~X}Q z6PMU<?;bAYEv!fWD}1|InzK&I><`Q1I_}%CpZTBMUF?1{&?UT<^U)-YN&An+8nqw% zrS_)La*DU`<i2$rsmHt47oR$#DK({^bMKuyLRmuTJ=1UZ6i#(WvT{BXab4H%58pEN z^e?f`o(OVExooR()tFtGq5H$R(Yw_<{A5V-q5M3CE9Ntq{B&53#fEq48UDTbbmNCj zn-4GB<GN*o>ZB`WXKX}gXEmAeF5_9aes#r_XGT9fe9PEXZ`^v=9nB!DTo@#w7kO|0 z{=ysgpJptc>$CT@U9X7C_V$$u7k$hozCQgnQ<4Al>`ku6K6J^jnZ$gmUMC~8GUC8e zh3@u`{67!ede6S~4ilr2E#Fo)gC}<PE~cfrRVg^0zpqfWA;h^SAf>~%P>uQj_F3$0 z_YP|r9;{HY38;TO)!HGy@>mo{5R0UuyMe0xPBpX2@+%iye>OI6>aIVl<9oyW%7rts z^Vp`dh?z&_Tn#-D!c*Yy^;4-(dQxe-0e{9nFQF+f8(5Z}Pt{ia!qYyv@ATP)w|sR% z4I*C#oJ?GhR^D>7<r?dRbY`uu4YwF=d(SOAe%<#_0+Z6EgwB0iQj9ZqG)mWs0n4dn z>rRRTS83WF-eq@e;iStEx2JH2AF?!6Idk7|@uJL`Gv7%0`tsfCeEn)l#d)j4y(KK$ zj`(~?U}<{%;m7oyA0NzXD2P3N*@v}1^3~FsJdsM_Z)Z|+*&C!@na(m+z5oA7z3q`_ z3L$g3QzV{6opoOGWvc`CGl%(K6jb;%yRYb9?|T2Qed&yE_ieYvgBk)XI|a<$*cce( zRbUMPZ1s;Qu>SFN4RO@<^mEhCP0Y(oODzT;g|v0*!Mwu?JPz;wc6C%Ax^`K_bnX_< z-%anBH41}N3^-=5`ukh;>aDbB{%p}aftlZV4yJvrD%f_zS>^FY!Sh!qYcOoh=l#|T z?EOvAe^k0R!m@Q4^P^uj8f~Q>(=(NWj@;5V3Rzs_VEXzN`+;k(pD^tFCmG+r?CYW( zP1eZ^Wtbjs+;M7w>8dBm4Q?w0)?Dmrw|Ode`_+?G%euNA9(c5?YSZecPl~6n(QSSd ztGr}F`BMX~CmSZ-HhDYoxXG~w%biEuxlOFEF|KA`usv~hY*BQ`u}M!pZ{WIdo_Buh z_jenOYrB@8cJW@hg^m0075A0FJ^g=={Em%eQT%1cbTKSdsN|Y<Tg=Vh6AlHO(d4gF zNw=2xb}y}2dU=(?&$JsWC#>Y#CmVU=NY`cM>7UB)FK<aM3_BT8_3B5w)MvA_1i5=B zy|d#^+Mj>&iyIUV3CzZ6u8a%}iNKw^0p5&EA`H0CwE{*45`dj@1=9tKKjbqwKnGYM zfG?1lj5y8;T_f@aV$cyC2(Sd`IK+V+Fnu6-Y}<<w`V{zqhj9V75rQ@w!*s!%iQK>i zwHgtiK^XTILUdC=x?t^DP-7SY-Z@~lL~%5YVTOV<V`~Z{40UzHG!(UAj2eRooeT`9 zo~*}W5~87u+Z0es5&^biF$KBdjN2Sk*Sy7I4x%AVtSQP)n4yDcSmQPY)U-x`NGzsc zG_-LWh8jTAuo#Bi@P?QJOOwcjBB<$&0Ox?_AUDKeNd~49IU9otO$6}s#8HF>c(Ve_ SUj_z#AbiKnz;MkA!~+1`aM&>b literal 0 HcmV?d00001 diff --git a/docs/datetime_wildcards.txt b/docs/datetime_wildcards.txt new file mode 100644 index 00000000..4a2b8a0a --- /dev/null +++ b/docs/datetime_wildcards.txt @@ -0,0 +1,122 @@ + Rivendell Date/Time Wildcards + +A date/time wildcard in Rivendell has the following form: + + %<meta-char><fmt-char> + +where: + + % -- A literal '%' + +<meta-char> -- Optional. One of the following meta-characters: + ^ -- Convert value indicated by <fmt-char> to all uppercase. + $ -- Convert the initial character of the value indicated by <fmt-char> + to uppercase. + +<fmt-char> -- One of the following letters: + + a -- Abbreviated weekday name --e.g. 'mon', 'tue' + + A -- Full weekday name --e.g. 'monday', 'tuesday' + + b -- Abbreviated month name --e.g. 'jan', 'feb' + + B -- Full month name --e.g. 'january', 'february' + + c -- [unassigned] + + C -- Century + + d -- Day of the month, zero padded (01 - 31) + + D -- Date (mm/dd/yy) + + e -- Day of the month, space padded ( 1 - 12) + + E -- Day of the month, unpadded (1 - 12) + + f -- [unassigned] + + F -- Date (yyyy-mm-dd) + + g -- Two digit year, as per ISO 8601 + + G -- Four digit year, as per ISO 8601 + + h -- Abbreviated month name --e.g. 'jan', 'feb' + + H -- Hour, 24 hour, zero padded (00 - 23) + + i -- Hour, 12 hour, space padded ( 0 - 12) + + I -- Hour, 12 hour, zero padded (00 - 12) + + j -- Day of year, zero padded (000 - 355) + + J -- Hour, 12 hour, unpadded (1 - 12) + + k -- Hour, 24 hour, space padded ( 0 - 23) + + K -- [unassigned] + + l -- [unassigned] + + L -- [unassigned] + + m -- Month, zero padded (01 - 12) + + M -- Minute, zero padded (00 - 59) + + n -- [unassigned] + + N -- [unassigned] + + o -- [unassigned] + + O -- [unassigned] + + p -- AM/PM string + + P -- [unassigned] + + q -- [unassigned] + + Q -- [unassigned] + + r -- [unassigned] + + R -- [unassigned] + + s -- [unassigned] + + S -- Seconds, zero padded (00 - 60) + + t -- [unassigned] + + T -- [unassigned] + + u -- Day of the week, numeric, 1=Monday, 7=Sunday + + U -- [unassigned] + + v -- [unassigned] + + V -- Week number, as per ISO 8601 + + w -- Day of the week, numeric, 0=Sunday,6=Saturday + + W -- Week number, as per ISO 8601 + + x -- [unassigned] + + X -- [unassigned] + + y -- Two digit year + + Y -- Four digit year + + z -- [unassigned] + + Z -- [unassigned] + + % -- A literal '%'. diff --git a/docs/examples/0320090805.cpi b/docs/examples/0320090805.cpi new file mode 100644 index 00000000..f9e13d90 --- /dev/null +++ b/docs/examples/0320090805.cpi @@ -0,0 +1,4 @@ +00:00:00 10001 Lonely Cowboy 00:02:53 ISCI4567890123456789012345678901 GUID4567890123456789012345678901 +00:02:53 10002 E Song 00:03:27 ISCI4567890123456789012345678901 GUID4567890123456789012345678901 +00:06:20 10003 Likeness 00:02:54 ISCI4567890123456789012345678901 GUID4567890123456789012345678901 +00:09:14 10004 Atchafalaya 00:28:02 ISCI4567890123456789012345678901 GUID4567890123456789012345678901 diff --git a/docs/examples/0320090805.elr b/docs/examples/0320090805.elr new file mode 100644 index 00000000..905d8c5f --- /dev/null +++ b/docs/examples/0320090805.elr @@ -0,0 +1,4 @@ +00:00:00 14:49:47 00:02:53 00:03:15 10001 Lonely Cowboy 01234567890123456789012345678901 +00:02:53 14:53:02 00:03:27 00:03:53 10002 E Song 01234567890123456789012345678901 +00:06:20 14:56:55 00:02:54 00:03:16 10003 Likeness 01234567890123456789012345678901 +00:09:14 15:00:11 00:28:02 00:03:54 10004 Atchafalaya 01234567890123456789012345678901 diff --git a/docs/examples/0320090805.tfc b/docs/examples/0320090805.tfc new file mode 100644 index 00000000..83c077f7 --- /dev/null +++ b/docs/examples/0320090805.tfc @@ -0,0 +1,4 @@ +00:00:00 10001 Lonely Cowboy 00:02:53 GUID4567890123456789012345678901 +00:02:53 10002 E Song 00:03:27 GUID4567890123456789012345678901 +00:06:20 10003 Likeness 00:02:54 GUID4567890123456789012345678901 +00:09:14 10004 Atchafalaya 00:28:02 GUID4567890123456789012345678901 diff --git a/docs/examples/0320090805.vti b/docs/examples/0320090805.vti new file mode 100644 index 00000000..32d0eddc --- /dev/null +++ b/docs/examples/0320090805.vti @@ -0,0 +1,4 @@ + 00:00:00 010001 Lonely Cowboy 00:02:50 Virginia Coalition 0253 + 00:02:53 010002 E Song 00:03:27 Virginia Coalition 0327 + 00:06:20 010003 Likeness 00:02:54 Virginia Coalition 0254 + 00:09:14 010004 Atchafalaya 00:02:02 Virginia Coalition 0202 diff --git a/docs/examples/080509T3.LOG b/docs/examples/080509T3.LOG new file mode 100644 index 00000000..90744a1e --- /dev/null +++ b/docs/examples/080509T3.LOG @@ -0,0 +1,5 @@ +00:00:01 123456 This is the title 00:01:00 +00:00:00 10001 Lonely Cowboy 00:02:53 +00:02:53 10002 E Song 00:03:27 +00:06:20 10003 Likeness 00:02:54 +00:09:14 10004 Atchafalaya 00:03:54 diff --git a/docs/examples/Makefile.am b/docs/examples/Makefile.am new file mode 100644 index 00000000..883ec522 --- /dev/null +++ b/docs/examples/Makefile.am @@ -0,0 +1,33 @@ +## automake.am +## +## docs/examples/automake.am for Rivendell +## +## (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +## +## $Id: Makefile.am,v 1.1.6.1 2013/12/10 21:25:49 cvs Exp $ +## $Date: 2013/12/10 21:25:49 $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +EXTRA_DIST = 0320090805.tfc\ + 0320090805.elr\ + 0320090805.cpi\ + 0320090805.vti\ + 080509T3.LOG\ + cart_report.asc + +CLEANFILES = *~ +MAINTAINERCLEANFILES = *~ Makefile.in configure aclocal.m4 diff --git a/docs/examples/cart_report.asc b/docs/examples/cart_report.asc new file mode 100644 index 00000000..2456fd10 --- /dev/null +++ b/docs/examples/cart_report.asc @@ -0,0 +1,13 @@ +CART |CUT|GROUP_NAME|TITLE |ARTIST |ALBUM |YEAR|ISRC |LABEL |CLIENT |AGENCY |PUBLISHER |COMPOSER |USER_DEFINED |LENGTH | +010001|001|MUSIC |Lonely Cowboy |Virginia Coalition |Townburg | | | | | | | | |0:03:15.0| +010002|001|MUSIC |E Song |Virginia Coalition |Townburg | | | | | | | | |0:03:53.1| +010003|001|MUSIC |Likeness |Virginia Coalition |Townburg | | | | | | | | |0:03:16.3| +010004|001|MUSIC |Atchafalaya |Virginia Coalition |Townburg | | | | | | | | |0:03:54.7| +010005|001|MUSIC |Luminiferous Ether |Virginia Coalition |Townburg | | | | | | | | |0:03:49.0| +010006|001|MUSIC |Witchita |Virginia Coalition |Townburg | | | | | | | | |0:01:02.8| +010007|001|MUSIC |Green and Grey |Virginia Coalition |Townburg | | | | | | | | |0:04:16.0| +010008|001|MUSIC |Mista Banks |Virginia Coalition |Townburg | | | | | | | | |0:04:43.9| +010009|001|MUSIC |A Song |Virginia Coalition |Townburg | | | | | | | | |0:03:02.7| +010010|001|MUSIC |Go-Go Song |Virginia Coalition |Townburg | | | | | | | | |0:04:47.4| +010011|001|MUSIC |Wichita Reprise |Virginia Coalition |Townburg | | | | | | | | |0:04:28.0| +999999|001|TEST |Test Tone |Rivendell Radio Automation | | | | | | | | | |0:00:10.0| diff --git a/docs/implemented_macros.txt b/docs/implemented_macros.txt new file mode 100644 index 00000000..434682ae --- /dev/null +++ b/docs/implemented_macros.txt @@ -0,0 +1,48 @@ +The following RMLs are currently implemented: + +Binary Serial Out [BO] +Clear Serial Trap [SC] +Console Label [CL] +Database Backup [DB] +Execute [EX] +Fire Salvo [FS] +GPI Enable [GE] +GPI Set [GI] +GPO Set [GO] +Insert Next [PX] +Insert Serial Trap [SI] +Load Log [LL] +Load Panel [PE] +Login [LO] +Macro Timer [MT] +Make Next [MN] +Pause Panel [PU] +Play Panel [PP] +Push Button [PB] +Record Start [RS] +Record Stop [RR] +Refresh Log [RL] +Run Shell Command [RN] +Select Widget [PW] +Send Command [CC] +Serial Output [SO] +Set Label [LB] +Set Color Label [LC] +Set Default Now & Next Cart [SN] +Set Mode [PM] +Sleep [SP] +Start [PL] +Start Next [PN] +Stop [PS] +Stop Panel [PT] +Switch Add [SA] +Switch Add With Gain [SG] +Switch Crosspoint Gain [SX] +Switch Level [SL] +Switch Reload [SZ] +Switch Remove [SR] +Switch Take [ST] +UDP Out [UO] + +For a full description of Rivendell Macro Langauge commands, see the +file 'rml.sxw'. diff --git a/docs/pam_rd.txt b/docs/pam_rd.txt new file mode 100644 index 00000000..fa779292 --- /dev/null +++ b/docs/pam_rd.txt @@ -0,0 +1,62 @@ + PAM and multi-user support in Rivendell + +In order to support a multi-user environment, the PAM (Pluggable +Authentication Module) infrastructure is used to activate a Rivendell +user. + +First of all, a distinction should be made between *nix user accounts +and Rivendell user accounts. The former are accounts used by the +operating system; they may be local accounts in the /etc/passwd file +or they may be centraly administered accounts such as in an LDAP +server. The Rivendell user accounts are used only within the +Rivendell system and are stored within the Rivendell SQL database. +Rivendell users can be used to distinguish what groups of audio a user +can create or delete within Rivendell. + +For the multi-user Rivendell environment, users should each have a +unique *nix system account and a matching Rivendell account. The *nix +user accounts should be members of a "rivendell" *nix system group and +also any group required to access audio hardware devices (ex: the +"audio" group on a debian system). The files in the Rivendell system +(/var/snd, PID files, log files) will be owned by "foouser.rivendell" +with appropiate group writable permissions. Commands to create the +*nix accounts are: + adduser foouser # create a new *nix user called foouser + adduser foouser rivendell # add foouser to the rivendll *nix group + adduser foouser audio # add foouser to the audio *nix group +Rivendell user accounts can be added with the "rdadmin" utility. + +Instead of requiring users to log in multiple times (once for their +*nix account and again for their Rivendell account), the pam_rd module +allows for the Rivendell user to be set during the authentication +process of PAM. + +Options the pam_rd module recognizes include: + + debug - to increase logging to syslog + use_first_pass - to use only the first password entered by the + try_first_pass - to try the first password, and if that is not + found succeed prompt the user to enter their + password. + kill_rd_daemons - kill any previously running rivendell daemons + (caed, ripcd, rdcatchd) + destroy_shm - destroy and release the rivendell shared memory + segment, id "0x5005 + ignore_pass - log a valid Rivendell user account into Rivendell, + ignoring any password check. the idea is to "trust" + the network logon credentials and ignore the + rivendell credentials + fail_default_user - if a corresponding Rivendell user account is not found + or if the entered password does not authenticate a + Rivendell user, the Rivendell user account is set to + the the user specified by this option (defaults to + "user"). + + +We have had success tying the pam_rd module into the "kdm" PAM module. +The following entry was added as the last "auth" entry for "kdm" in +/etc/pam.d/kdm: + + auth required pam_rd.so debug kill_rd_daemons destroy_shm ignore_pass fail_default_user=user + + diff --git a/docs/reports.txt b/docs/reports.txt new file mode 100644 index 00000000..61446725 --- /dev/null +++ b/docs/reports.txt @@ -0,0 +1,95 @@ + Configuring Reports in Rivendell + +Following are some filter-specific notes concerning configuring +reports in Rivendell: + + +CBSI DeltaFlex +Report files should be named according to the following scheme: + + <ii><yy><mm><dd>.201 + +where: + <ii> -- the two digit Station ID of the corresponding CBSI system. + This same value should be set in the 'Station ID' field of the + report configuration. + + <yy> -- The last two digits of the year. + + <mm> -- The two digit month, in the range 01 - 12. + + <dd> -- The two digit day, in the range 01 - 31. + +Thus, for example, for a system with a station ID of '01', the name +part of the export path would be: '01%y%m%d.201'. + + +ASCAP/BMI Electronic Music Reports +Sometimes also known as the "Paris" format, these reports can be +directly submitted to ASCAP/BMI as part of their EMR (Electronic Music +Reporting) initiatives. For more information, see: + + http://www.ascap.com/licensing/radio/ + http://emr.bmi.com/ + +When setting up generation of an ASCAP/BMI Music Report, output files +should be named in the scheme: + + <id><yy><mm>.emr + +where: + <id> -- Your identifier string (assigned by ASCAP/BMI). Normally, + this will be a station's call letters. + + <yy> -- The last two digits of the year for the data covered in the + report. + + <mm> -- The two digit month for the data covered in the report, in + the range 01 - 12. + +Thus, for a station called 'WAVA', the 'Station ID' box in the Edit +Report dialog would be set to 'WAVA', and the name part of the export +path would be: 'wava%y%m.emr'. + +You will also need to specify a 'Station Type' and 'Station Format' +for the report. 'Station Type' is self-explanatory, while 'Station +Format' is simply a phrase describing the programming format of the +station --e.g. "Jazz", "Top Country", etc. + +Another setting that will effect any Music Reports generated is the +'Usage' field on the Cart Label in RDLibrary. You should set the +value for each cart to best reflect the use that is made of the +material in it. + +Music Reports are customarily generated on a monthly basis, so when +generating one in RDLogManger, be sure to select the first and last +days of the month in question for the 'Start Date' and 'End Date' +respectively, otherwise the resulting report may not include all of +the relevant playout activity. + + +SoundExchange Statutory License Report +This report can be imported into a spreadsheet program (such as +OpenOffice.org or Excel) and then saved as an 'XLS' file, which can then be +directly submitted to SoundExchange to satisfy their reporting +requirements for streaming music on the Internet. When configuring +the report in RDAdmin->ManageReports, fill in the fields as follows: + +Station ID: The "Name of Service" as assigned by SoundExchange. + This will normally be the name of the entity operating + the service -- e.g. "SALEM COMMUNICATIONS". + +Service Name: The "Channel Name" of the service, as assigned by + SoundExchange. For radio staions, this will normally be + the station's call letters -- e.g. "WAVA-FM". + +Station Format: The "Transmission Category" of the service. This is + a single-letter code assigned by the U.S. Copyright + Office. For a list of possible values, see: + http://www.copyright.gov/fedreg/2004/69fr11515.pdf + +When generating a report in RDLogManager->ManageReports, the system +will prompt for an 'Aggreggate Tuning Hours (ATH)' value for the +report period. This is a measure of the total amount of listenership +to the audio stream, and can normally be obtained from your streaming +provider. diff --git a/docs/ripc.txt b/docs/ripc.txt new file mode 100644 index 00000000..28e80a0b --- /dev/null +++ b/docs/ripc.txt @@ -0,0 +1,86 @@ + Rivendell Interprocess Communication Protocol + +This defines the IP protocol used for communication between different +modules of Rivendell and the 'ripcd' daemon. + +Connection to ripcd is by means of a TCP SOCK_STREAM connection to TCP +port 5006. The format of a message is as follows: + + <cmd>[<arg>][...]! + +where: + +<cmd> is a two-letter code indicating the nature of the message. +<arg> is zero or more arguments. +! is an ASCII character 0x21. + + +UNPRIVILEDGED COMMANDS -- no authentication is required to execute these. + +DC! -- DROP CONNECTION +End the session and drop the TCP connection. + +PW <passwd>! -- SEND PASSWORD +Send a password to authenticate the connection. Ripcd will respond +with 'PW +!' or 'PW -!', indicating the success or failure of the +authentication. + + +PRIVILEDGED - a connection must be authenticated before these can be +executed. + +RU! -- Request User +Request the LOGIN_NAME of the user currently logged in. +Ripcd will respond with RU <user>!. + +SU <user>! -- SET USER +Log <user> in. Ripcd will respond with RU <user>! + +MS <ip-addr> <echo> <rml-cmd>! +Send an RML command to the specified destination. + +ME <ip-addr> <echo> <rml-echo>! +Send an RML echo to the specified destination. + +GC <matrix>! +Return the current GPI line cart numbers for matrix <matrix>. +Return for each line: + GC <matrix> <gpi-line> <off-cart-num> <on-cart-num>! + Indicates a change in a GPI line cart number (receive only). + +GD <matrix>! +Return the current GPO line cart numbers for matrix <matrix>. +Return for each line: + GD <matrix> <gpo-line> <off-cart-num> <on-cart-num>! + Indicates a change in a GPO line cart number (receive only). + +GI <matrix>! +Return the current GPI line states for matrix <matrix>. +Return for each line: + GI <matrix> <gpi-line> <gpi-state> <mask-state>! + Indicates a change in a GPI line status (receive only). + +GO <matrix>! +Return the current GPO line states for matrix <matrix>. +Return for each line: + GO <matrix> <gpo-line> <gpo-state> <mask-state>! + Indicates a change in a GPO line status (receive only). + +GM <matrix>! +Return the current GPI line mask states for matrix <matrix>. +Return for each line: + GM <matrix> <gpi-line> <state>! + Indicates a change in a GPI line mask status (receive only). + +GN <matrix>! +Return the current GPO line mask states for matrix <matrix>. +Return for each line: + GN <matrix> <gpo-line> <state>! + Indicates a change in a GPO line mask status (receive only). + +RG! +Reload the GPI table. + +TA! +Request the current state of the On Air flag. +Ripcd will respond with TA 0|1!, with 0 = Off and 1 = On. diff --git a/docs/rml.sxw b/docs/rml.sxw new file mode 100644 index 0000000000000000000000000000000000000000..77a8c0b56ec125fd6aa841b7016a468d73f6b70e GIT binary patch literal 26168 zcmb@sV{mO<^zIqkwr$%yv6B<qww;{VwrwXTwv!Xvwyoap|JJ?zp{x5-r)pJprRJV% z&AG;Sp5GXmiZY;JXh1+vKtMyG(qelh%-jS(KtTUpfIk7*TH2brcsiIGIyl%^8XLM; z+S@U@*_kjnyV@~$*xE3-J6XDzIw}6o98geD|1$^RYyaoxf95cCG5l|EOtQXx78Ba= z&I>it1??&Xr5sYhJezCQVntG_ly?-~#~%++Tx^v_d%*_{DJ?Zm;r-1WegPeZV#Kn> zTfM$T<*FD3kxTFVb`0es+@F<a=HG9KYhkK{2#KO3Z1&QM98~=*vn`c8*wVN^7Pcuw z#k7jSXjVx@P{z@Jy!~ys(3QV(-db%3Ij%Ju_3D)La}@i{YprDGRDwvU@@14rQBc?# zbc@|pT>8MQYjzCJ)b=-_l)6$@8<?FE(oOrLLY|9mVv=}pEf38XKL0{#uInb@p<$V| zjOQM1_c<dH;q1r%ncGTIowj`OZrP--aEG|0Df$6w3pdi)?^KAP6GJLFop9m`!Zlb9 zh0+li`&$hh0V2|Bl0fGWbkJ~<C<9K2cJg2$<e?8^(4tPwL+kSIRN5jShjtq!@t<kX zjkiPn`IYdmi)HHF9}i$xw_d!s?s-PTxpV=Q=iq;{8?P56-}2+LRWsN)URgM@M7u;O zGF!BfDR!*A6~WKpad!QM8}+Xo(KD-`M~lniwKa#JHfucr0T&W$F*gD|ddcLI`Vn3` z-LKXyJfu==QGbs9sEt;j)GZrVEJ?^(HRqcozs<EcTo9PvYgMOCHk5B#HA`9+)MB}p zbsHJ~Js*u?SjOvqS{VBVRg{5*;wH3ex&Q_OasmSa`hO1)I6$a4o4UAI+L=557bMeK z+Rp1-Xns5T345-T!|~c@Y-d=IQ1nPfeQaIOA3$~{<D}zQ_ZKf?Li6PDX7HJ7T_*KM zq&XKaImZ59t>LHRcp-4yoeaqWnxUu$0*E3U-3)N=PYbi5_MHB{M@dqrgJ}UDQed(< z(uy!?W2ipa<BU}sE1?<6cWFimqkZaW0*=h|sq~XHwSJh(h;$ZXxq8cGmhaU3lgp_z zDbmcHoto#)9MEMqV+`mTG8~8wGdr5T-%g1w^1amh44XD=TT~touH-(x(F=;g#VvxG z`etMz-6zDwj2zULUdKBZ{5tlqM7{)=9PW!OBfQB?mV2c>nmt|bpDnNIGoz+$28C`g zZ3s!caG>lPzUNM7=bub_?nv_HopHLYwKUvv^I3O`p+H42+1Q3E@!Gu6++{+)_aq{~ z?yu%d)cRGRZ3+4W&QL{;!iMuC$OPaufncGwaje~wO=k`KB9BI8x8Yi2X;PqC8eE0a z9y*=uFV$uk5uh%*&zxNSERSOOuw$w51hrWj%ux7HudZj&rUo}>CQURtl=;@_KOffK zmc#|lNN0)!Ce{)DVq>1?|6L@J$)yTgAT!$N@TEIbo5_n!-L$__rtH}_dRdcEpIP8E zMWlL#3HsXy%N^Tuuzw?NwsYmWwcZUBcyC<)_dNls5Gnr$w#Tg@vO=K$7l-26711e* zFw0$c`l|<p_7fWN#+pa;KcOy^33)WaAz&qMeh(nKaSUwGZe3PhP@3k5OtlCw_+Ae9 zvZ;RpwQy~Fa7FnJ&Yq5Dy4gobo_SQhml#ul0)K=+*Q5%WO^7^QG)$DL0?TEh6_cl4 zv0C|u4;a!4W@teD+K=#SdnlDdlT2Y_D8mXeTcBm2YDk8?d3uZx;195Z>`tr1F55PN zd1_!_=v32C2+gt~>UFE)8m5H?_~B*4erq^jlhU+*r6Q|1h7Mfl*r0|NEe?u7(Gj+Z zB``0eg-IeCdjGb$3w|yyRLDEerbbOr5nog3M@<bJ;djew3o6Er#rJRGITE9Wm&GSQ zW`^IXFEGBGkAf;eh%m(riJR%Oa`m(%szQE`M++3998F*TD<jC`Jq6MyyaOu_pS+1< z=JZcny33HJj|KjEfC#7*HaQSK^Bxk)Y%;#yZlHbyMRY9iNFfa#Nh_g%$kC<;D)asq zedN+SQas}7Z&1tB6WnShWG%+;cETSK6<e-g?y~m$GRJz|*|-AOdxA5N;eR>C8rwtP zCW6q@b>hot?R;Or^;@rm;9p##i65DSFL3<9cFgEQYtj9RNOg_zLqz96lKhGh&{2j> zsVzM(Nzl)65{YEiQ_Tpz;YRQBNp9&lnF7@t(*m>mQ^0=-n-E-m5nl>!bK>MK1I`yQ z!Y`x$VZ`s|1UZ%C5V=&2#vgrH#W$HBN_l!k(giPwt+apAmruSuV?eeQtV;0L?Awfj zS+SDw^ht9V>zJ1J==;eBg(g%=+4C9~jcAp&)NKUJJi?<@J#7TL+6TM615aM**5h~Z z)%}SMKMK=EM9OJ%?vN9k*=Mavc3wPpkWMHNl@N6)_;)m@hz!}#<n?10hx_a1n<3TQ z@?%ZUh2Zk%Ye#h48;fsrv)8ul>U+1lM0CS$<5R7yRG07!GIzwI22)L>O{tB*`+2}{ zi5y$+cTwInOh;4RMq5iFs@iR48d&=uI9jQdsu|y72EwpKr^1;{d&P4>ZCFa0=})Tg z(F9)7DQ^TEavn3pl-8uu8g1>?tJjtGuJn%tnJ?Zn_YXPP7jFX2u6v7g^;<t4tLR(_ zLCHH~Pen_?u3AKrck9JA<uG-^O)YZ)GltMiURazK!eEJ<m@av^x!uN{+v@y1dZo5p z-3ylwy_WMOTK3thR$Y6JGejEpm%t6XE$`EnuF*X8l0EslI%hY0l@ahoQR0+bk{T@S zBy7A`lj+O~j+*g$m`WPVUpvc8b}$cYhTizRcsufI0f-;|{5A`NaEJN#xo5i5w{9_n zs3GR4Vq~#rD8yo?fr$xjeKQn)t4@c_q|^4OSza=18r7-fn)5(g`(k{s0(Zw6zlG}W zX;(;{Z`BDEHd(`*EC;?cg;vIm1ZDlutbW+sc>9p7q=emG>1BV3$hEtS(o%wUHgiGi zL}SdH;yO9gX>hn);ucuAetC@?X0c=$!A~Uj)s7KQL0TELM`|wR`^f6)ja%N^gCw*{ zoW1+UQ4Z`#N-{$|p<x^b4wA(j`$O%6>Y1BW3nO~lV5m|HFYMKN$%H8i7L-b)b?(Sq zVriIn8_ej@fa+nAQR%|ll!T}wU?)(}QzRD}+DxW#cTM})fD>cE=+K<IWXP%Cha7L$ zfkfI1^wM5`Jl-A?{%4jMAHWI^5I{g(RR3RQ2@5bwV|zOnQ#+Ucyz)v{+j)bl(NC}! zWVFnTrlQ48KAS7IrOia@*+a5XHIYxsjiv=WDSn8ZQA>}`+nV55@bZG&-_CFR48mh6 zCSOde(OnNE3M^3K;6lQ^2>A1jG478%LHd<Ns;8SGtp*|#E4s|m)ZJSD)or7T({0+r z&wCR)jwKAQ8vQV9`dKR4q|2T^h<?^gg@?BrljGKzWr>ko1~owny|)f`rFs?m-ACU~ zpJU$R(~)OHe)}ZBR!d2P(C_r^lErBmuwk{VndQ_GkiMAw&oLO8S+l15OMFJnkH<5W zqse^Tj%J(SKh1pSnV!9keEzue1tCYJxit^UmCA-ZqJMZ(v^vzGCvc`ptSv`Cgbf#1 zuhYAGq83Y_|L`Inn5sr4ctUv=$d-5e8F)m5FWoGnsrRZ33Mjib202rvAaou6xUA2$ zua2xwGzhH<4lkEpP-BV*A<|81sl0#Tbrn4F$adFF*-V?dRkt^`wu`uun-rQ>V`XZA zODC^_4v>QpJ+Eut^(%>YA;9vUPgM50tb>{kz~P`T&%>s%EjU(SJC5j0J{?3(m#Twd zS-ZIHt{qp1<HHBY!b9xWWbcOsQt-e_=Ppl365FD#{L_fS?}3kuwN=yALL2kcz;>Ra z;<vDQ7KDU0Z6iR+I|k}!mtUuZwX(c|WG~1NQ34BhpdWuTjT2SlZ{$Pe0Y2X{C-Tl_ z(H_)LJ;}?Vu;My$4q#NlSy1bpsQ)ru0xBUN44i{d)m~UwU5PjcvWatAB2J`tWz#2B zMXFPD%yz$S?8kkkeXR|70I`tkEm>uAM-xzWIS&Z9#XjUqKMA?j7}z0Azm}#^aXI;% z)lrgA2!D;~=HkU_UnJnecE{MYHi-}+wX%3ux!0{mSd2#q*5gaXyK8OiiD@mfpm8lf zTg1SP&?{A2sOQrb#b?tOe<gWt@zB6wMTLNNNinRL;y@KI&8!L-Ah3*+O}QCZC!nkN z4qV5<OiISEV>_5}{<XtWE@fA(P~07&xwBAl^jZH~m2bA-4frvrSp^3p)XAE4Ij+Ww zPw<c<RlcaMQB3bsa?!Z}LPJHmD^fB3wKpR6(aMljU`@qpp+T-JX&0PNh&K6$Dzp&N zYepS0D6%Y{GyTeHN|+<xC#}3TM)(um>@RZP&mMOzhZhaE!J)7%>m)=9XW`#Ll5g(y z-u#GlZ#JkPbJo%rN}@KRMynvk-|b+m80^6cMvTK6{TD|&G^xx>YX|3bgCL*Yhu+a? z)>z)nb<zA<BfnAQEPdIn<CYuUmR69RHGBv$Zmr|ZZ#sk4U`vy)zDJ#2zGU{Vy-MnH z+bpGtW16s22JUk2TmC{@RcRNx4Zma+JrC0EUrW6m-1XeO9LVh7c-7PsbXsctH@0P9 zT;M@1HCX01*=(S~$5h}gwjVz9wp#!yz9#+T2C(v?0OJ|ANUORpIBBYD&?JZ18oJA~ z(q#33wfKj(c(k_OK@;)^>usw=nnG$D_OESRP8tpbS|hVMlg7HM82gsK`<B2ijU(#C zNQWVpX_JzO*+i|D_pN?bD2Ho-I4~N$JlW&xHJhnn^iQpQ1UplQ6{i<&r@`q-=jbq4 ziIm=f7Fn6<v;;KfRfLm4a8UA?nU&(lFxb`^j&6VMb=!6W2b+0&y;npHnvrF2)Iy-v zZ^~h`Kd_~;7=NT6ETS}>+YKnH3mptubZ*Vu*g)xIKde2fRh%#9n0-cM<=c%sORWbb z+k)Zb7>1rrC`aWM2cA{lL=0pQLMbySBa&>7!_f)tVWNiX6|L%$B58v$v}z?;{$*}O zA~#zxv>Q%XX=(HzT0Y6p{nOISaNp}~Z(5`bGRgHqpygg3qn8tIly>JRdPzq%^}ZxZ z1vbU~)onXug{K*LGE`{(>cq2@Cr#tr*Fk5PsW|0-7{h&;N5G1XQ5;4mfF@Rv$+~o= zGJdafJ#>B<cxDbs1oPQq@YzxuJZkmu*m^{7Qf`A~(qN+ji}2Z+!uFMIjJLF;lNG4| zMl`UQ@zC?!C!2D{bEY`l`fFn)!%uC2U7rv?TX1n=$w{r!#&mk)1@a_VqHQIy{M3Ve z{7|lU!B2)QOmUx&n}Ic)og~2bc1IOhQlX4NCBhond;-n(QLH@3!QplepOm57oT4Lm zv{c$GlXp&bUmhzW^HN2v>DQKIi|IRkN`&B_J)-K1p-wit$M-G6wmDmw#izU7uDL6h zb51#yS1;CT{{-WGBrn%Nc1&|Pr$~sdeH#alQOVR=?Qn+Eva|V7m5TM1CxmqjMqMvR zt&vRinckHxLNw7YzsqkSzkb3+0*$*B&U={-oo@^Qwl~qd1(n+g%t}aw=g(eH<^U9y zq6Fz1n*ke&m4_DJC?Xb(assDqrVR7nrKNqS3v+mwnux}ze&;iEB2Q-_sj{<uCcHu1 z1p!88yke|sas{7RZxr)>2L`a3x8lIZL|_mqoHy=FMioP!F@adx9L#jM<@KX{m>H8~ ziAN6<S>YuJ=Pgp@l~%%WTg7~MPVjvMz#=qMaCcPPWclgByv<V$wcMyda|(DsKGjS< zaqI&YfirG~4j7WFdzsSiLYST^vL@zMo)@vh&B9GfJ>MNmKQtAHulY@qr5@$PO5h{S zxr$C>XduoUSX8YLk!+VqtPOm+!!Y@5J|?jE-W!+5m+7Lh3b6_f0ee3RU?~(!i}lKg zpkvv(!FC5_y_|LLPYCzxCU|iMf4IQbUFe7BjfpJ4BKhYiS}8MGPf;5(26piuhs_ME z;(04KA&YF+)_=2xHtW0~!Ev;T>B_emQ@_Ajzbg(S`iuv03<!8ff*jG3R-WZfBaGV= zo)OC^;-I?R<<7G0l24@C?zPGCley>0$WBtu=F?1~gMO*k(L)DZ%-#1NO!1LL(<DI+ zMpg4i&(<y8Q6iXsyn$37J+$EbSd`3z8!MFOz53MGR=Pu;_$M;JU43Vk9M22P$OuFo z?-aT+-2+t<uj}F-9mbf^{0;l~B4PjHh$quURBG5OzAI~vDBOO9&U7fv4;S7CDR2QX zgj=*@GPaQrr;drtdUvAnQL9Hrw>);NTWat5^zwBU@1whXCO2Kri^Ur#7@+6FU#thg z0%s?)F_43z1Fw*<=D}JS<o>XS@d}LTgH{>`UE(iK5{bDjE1eL!B@>UdjyfQs*CA9w zV@oq_@w^V;e8CQFe6~wa+?8D}RkPZ8DH$@+3^vYUc21(GdkxEC_ks-Wk;=k+-7=G- zQE(};<GAgd&SdLL0F#s~O^MZaY5J3kC7mkEt1mt-S0IwdAqwNurkTVeaevsW&->P^ zpcGAQwV;7J?x1$`x&L0e{Ue?EWT+c7f@q+?ydiEa2uIOnc;twEsdi1V>9&&y4Xz!| ztK^<p+o7;I(Ohwcl?j`9FCR?EftAmsFyP;=gq9N;0to`|z3V6TtuwWX?_uCaUuPzq z5qxFGv`Go^faHwEGhFdYJTzyV?xQ}ngAil%i?^AY;<6#6#<7YdOrqE}d+KmTMdr`0 zR+YhcfbezavQHsw=|d;wtp}46m;iDtzE4#}pR)tDY3Zx#JA<K-SsWT^i_tawfQOh( zJ8mn4=v|s%WMEdQBJO4bGicV(lTDLRBQ^xA;XmIpI)Pct0co<UPOFE`%4{xM^7${b z;Pq>vw!WIjt?WRbF<OjSkQ)X90x@ff$I1AHhCkbj+jjQDzC2v^?iX?_7VcpznGIeJ z+sxRA=-CjF1|?UEHs&qHm19WL(Da|s7LafZ5nP1M2>tj&H4kI7_Er&GR3oRLo(=)5 zEIR$E@kzzweQ(zW@StbEjjp(c?R<Jew>-M~+LBYD&fzXOS1>n2gJOqOb5yf5zl2N- zHVP{pXyTLZQiajqfMdWMeOwCPiX`y~ObdEgD*j{+$uEzHqQN}jVIVXTB0b9Dha22+ z>3|3cJBZ?DVT>R(Ls4LzDf8hjH1tUhp~L5kL-6J;YeV*>!)DK&MGJIum~bP)`2SR& zI;DT*Q`-aramTy%FFOYR-WEX*G=9TFLUoh{e(eMz-T*~V^{CVR(Taz;v1M}d4td!g z@nFQ+=2zrOxQ|vO>67?m?{OU?fS_XK8$E(zlVU5|t8OPY0Ua`S$UYBHWtaSda=?e{ z><-%H@mO=fzogfJ{Fi|Vq=8Cs1iiGJrheeIN`m>N{#EvV@^|X5xWt&B=UV(%V~%(M z>jU@h28wm~T?VEugoW>={C>!;6$mqgy)kS+Iz1c8F)#xzO)B^NNG`p)0V;;Ho)Pj| zoU@T5zx1O)ho|E&HqKWQfw3WRDOR}BeJyGR0V9X-x`+F6Wb)l|)XAYsrU?!Iqv@xB zU}lxbOa&SE{NI>H%~0O7^08*}{Fo3x3)(gir_D#pMTTPw{Lk<8cg9V>-M7@y&uLJf zrlkaWyz*mlp8UR(%r8u>3)S7^9(7`!@_mPlmJ8c1Az55x3Oq<KX7?tH-`79srN><B zl$t#(R6-{uicRc<Q0FaTG<?vG3vX9Rx?J;0qr(#Ur>y=t{-s2<s$!+Wuew~0?t!Cy zd=ME>1x^}DlXq^w`BePQU+S%GlX`Lc<%GE$b$vXLNo`KezGOIV^n~ZgQW#zovSwUh z7#|*V5bV?u?Qc)yZ@HIQdvb3{@rw#b=gk`1C}O}&B>*xPZUneJmM2$o$Oir}{iI^b zo!<6$(=!8lq#=&kMQH{v6mE=>c{JOpEw}Mh0wbtO0I0@VZ}vW;LQblKi?|k*Km+`j zW*4*0^&WR$j@v24@VcZ5jl7*K<p|+JHuY5fLOug;f(~axAI>m_CsJQDc~Ph<^m=j= z=u}ayWQV3v;6&Ye=Dx|uf&)qh{=+4yy(&jxE`d*Mg{3k_QV7^4+}|q<%N0f~mX1l5 z@~DVk7+toF1dWpWiToZmivP;vlwMbxBvm7lOIZrc4x#6HpXmk`z#-!n*d_OgIe#lw zhHNC{BjGVCK%&A&ph?7>tz-PQE|h`YdH`p-T(q0!CWhdw8HxWyUs&?m`c@n%rj^I| zes3&`?KR8ep|dj;gF(!5%nyx=gz(#P&0s#d!11GK5(*CRwx}bEfQjdm^h40|n6U1% zdGM;YueTMzv^gQ=3@z+<Yn-dLnwbQ0DPzZ4tkXIyq-`Rt<ic`i&})9qA=QVd`z{?G zLo-C&E$x^C9mE!dw8{!XXh4RP9@;n_cL&<2;3Q|AR;7;~N@N@=^X(xF^I;{zImskx zd<v?*2_+c0{K;eH<{3+c5H$<LR%K|B8>q`A+{bzQYV%LBb{?`%2W}HeG=F%)yYmuI z*#NWm9pu?gK(Q3c3)J^wu+FR@4m^X=*mtK{3pUTnhe@~;e$KF%8BND@nc|7YLy$rI zDXr~AHJ{B!-27)ASk)kMj>#7#+Mqh9VdgOJEOu|#brW{iV_YsoXNSEzZ5&DAB+~id z(Do~v`E4qkkD{xXeDC-{O>e=`R$;tH(mF#&--6+7>`64=(h=G=YC-^y;NjeFS=CG& zf3-^@3=e-9p{i>>b~cT81`K`^A_;LexX1W??QB3^W3CmPCvRte=wh{Aa8j+yj0et! z@y%=Doitq^G2Q>~KhimJ$MaBzlmo`OjLOsLUu837bu`19rUxMxzk;aL`b2K&_GHkH zJ7#?dmF4k)N|VD68HlL~NJH;CrHU)XP)gj<$MZ9rl-xk$R6{|u?mJzT;gL2uos<Xz z?12gX*)pOQ(3Z9*jX_1sx}b2=Gj4QSn7K2SF6P{t&l-xd0Wg38R_(f9L$UfyB_1el zl$@{riPQy!x0Y<1Z|ASGBz|r%$|KFGs-_t{D|$)V$`=Oq;)b9*`3FremaC@2wSIqo z=Tz<oC!ucHdoVf!8%A`$4E)MbgE&d;i4GZX&PqvZtqz@!DUs~?LDe?9<<=tOI?Krm zS{Zbm)^L#1kq)WMJPVPboA|3S-xA8jeR}Rd<nM{&2o{Q5gHV~+-Md>srLw)>_tVDZ z2LY{Q33Jp~-|Ifv`zc7#B`un<MR%nh%FxGII(fRrW4G}xvto8a46q5vWaGFpm?v$D zY4(<l*f;$fg7ul`RUcrp)A8w;%@Fi!$$d4uq|6p8SqD_wR?1rXso6X6WOmM1X;Xw# zgw~ewJ1qwuAbwSeFvH)!Hm~SGM0x_D6weqmim|Zvxl%*zkRo9+8fj}H`&V=;7d04B z>y+VI!9QwQd1}43PL$uP9KUQV%d>X>W+|;`TMIF?MqWZ4e>XUZc#az2KD4A-x>(YU zzBs&glZ_CS&Rq1XW9u->UVewmX9h`AmWRB>VpU`B?48NtTwjmzaMDrF(4rqznQu)_ ziYoJ7Y~v*=U)f0GkLIkVa^{9a?2^D6*j2^k^Qdp${86YUMTi5LIaAnsCXmlGxVh>5 z(xz>43Ys=wNkph&toOG1>a~&bLmudqc6*VMJ<8v_*3;b?3%lhT$I|nLMVd&iEfKm| zz+mQ+_cME4R3GhtAy@tTNGZ5_%1x)mAo&#$Hfa{ghC!r@!n`J2U(L`;JfghWAQ>1A z-Ys+8!dA1|-`g)iraMTg>}oAbHw#|^B{yl{bb4@3pddSmGC!Odgy%t4maXXN*)ILH zfy?sRuw)0>`S%`k_j@`DW0(8h^l%^pC{_B~a=kMd+`wc96&IRYF2a`>n&yFf$S`Tz zwvh?vvWc1HH=6{8Tiu?tmQS0O0PkW5bAb1v)0%Z_AN6(t*V`wa;7^F7AI{JG;CH#G z859>yD;W7KESWuCY9m2})u+hfO7Wgm`z}Lw6G8f-ME>LD#sx0W71L@e_vMPI#&{Ev zdz6rZu<&EQkq2c$EB+tp#M^aoHpxTyIiO{r7HavTZ|K`IM}nRT_wzrVH5HACSv)q) z+E0G!7UQOYURlL~7+u|Fs8}4&;D16Ba(QdS%{R<;h97l0d2x7(+>}wL#GN)HrVFFE zheDb6Pm%8`7<!z-^Wbo=e$o{&*@nZ{_K6m_o<+Q=hjx6bSZPl<f@N@CpAe5J_$Nkl zt=qJ)k44wc>USRwIFOIGgP3p;RI&?`r_C!n40kDPBCwe1aXuSmm&QlCuzh+6IQ+<- z%vgU8C?KA`a7W+wxn{`4G;{GcZ1FC=b_}8ZWmwj-Ko|Np3{{x?i>vIPlf2ukEay}d zyVQ&7)o)z+Szc`UU_0o<Au<2`L!DqBNGUKHYY0mI7_jI55b^u7E1+VUfNj$Gkupe9 zG)C??DaO2UZ|2OAp^Uvo9z2Se;QKv6XQ>H{+_b=7jqWij_n?kt_Rh(OY+zN@JN9AY zS*ph&4c?7+?uVN;uorSJBDO1Fr$xGkrnXsy@w3}o%?Y9~i1Oh8vrfs$7i6O*?+9UM z?9>+1r*MQ~L7DfUd8lsIhx%b&@HSqAQ-~{oTRa*CA8hjkrc$Dp7whrw3g=)Dn}0v# zzHLw~BQ6eq9gvj|`e-Yjxs~NE0eIS7#=)v5y-bQn5aMv4@{r$qjawT-OQW*E<H^M& zhh~o%hbD^S&DJ`JZ)w;I$*bgW<WWCS4w*D+tT-8}BvGVp^f%dcp2irf@~y}3DUXL6 zkcz55W+MnX#m@AR8GL!S0g4^of!Dp=HZDK(tba+D+GT8HZplHP#q*9aIzW+sZ_I=R z4~U7Ss%e|q{TWz1`=;v@q>fVC+!5?7=`Gl5{7H?3KRyKYmb%Ln@$HF&zBeIB7+ve* zpW@mdts0cXwu_sMecj6?5_lTfj`nar^A)i8`D**Y7t!tgdG_DW_Ho33>LJezv{aXe z!3x0Ed2QE&Os<Qtinf{DMOAEvD0&w&Q~T1+1LnBY({0f%_7*)~@pW3O)t5Tol(=My zTe`)%)-M*2LaF%Hnxv+u7`wX2Ect78AdGJ;Mp*xxw$8a(y3*Z6)~ni!-m7+ir_g(~ zZN`<XufDT|k&V*X@3GB5A!NCLLV$=z(=;^Ka~EBRKXvk1e<-GoDrg>)ry-l-J;KU9 zSRD^`w3u_V^(i$`$EZZ38|-=><Cg|k$4j3<+snG&o#g7rNN|%gT(P+XXO<>QyDkNW zXdoh09D?S0>J2eX)mXyS66G?=Qk80=7Wx+btt{CU7BPIW8rmnT)558bXKWX-1@--G zDTx;x&Ngg4N1!`0#dSr5H;@`­pz@^PDLZn6Mbd1j>1Duo69LGJmdBU;GDGw*>y zV|=kvdy71Yebkj+M<BmJ>jtr((AMQcZr+C7FR|kJfTcq|t<>+>SxcS;`gJr&W$0+u z@(oQ7Cx4T&F&K4!n9yT<2g3K$dpWCtLy3&?A|Wt(v<aNKZocuYrqjdC#eu^s+CuD_ z<;d}rkUjhbqsW<<hGZ;3eAxg%!K;E+f6N{F5mC7JG^yM5Xd3n`$K<^9PS7ZngYPmH zMH4(xFYBFOpO%J78F&xx2$Ifbhz)D+Il8oFz;*jm^{+};{n&^pu~iEQm1&6S@vVY* z-$=``!+xH<x&1pe6v0oBytKxI{kAk5I!V02I*EJYV7ss#FVv>W8ZwG1j5<iAv<kQL zCHwFE7?S=<Q^CU!ep=(^NlBW-8eFBtp4yj?!eG3q?ICG$9LU9=+I>jIi2v<p5#`pW z*&W6$^WlJK%hV6oesqy#$3<Kl@?K?~9=-4#kNb|fysA~z$!|AJef~aDZ%#W>r!peE zWb{#6+2`)u8DjKfu%qSzd)Yvky1hlP-ekZcMN;Du5IGOV?-y3sU+9A>W%WxV>s?NG zp{z#mS#aQVY%KE-t{kb8INDgK8kdWioZu~Xalu-~lO_H}k6%UU!Lj6!)w~3DPI^PH zW_vBsGMG46szQzAtb7|0h^?@{kvy?amRi_3X#X{;S)op0v|$>g(ZE+Z*jFXo`ZgV+ z&71JN>RYdTeoQ5Y^-(kFXMKBcebmtFf4{0vAIFQ-Du5dp!3J&Eb;+^JE|NAnAqknr zXQ!oKydN+uT%vNzuqkIm#aX4siRq>fdC8=1G@z|tQ1H|XLvsoe8p%n-Tjo7SUgt`W zz}@|&!qUy2^j(`UNO_nd6fyhnt^@mnf4C!>adL+3mQM}#WH#ck<%qgT9f;h?kr&Uc z<emgpOts%!*gmK{3S4Z<v(`F;H%MtVSW`xkNm4e~VD+ncaiiC=qRmWeUmyf|>xSAV z(%V*xCH?o)TBuAyp)<<)@U!lp)hURZ;QXYk439whdERi%^@PqqI|c%`MiPg<Sw@uR zkVy;Tom4JDM+~P60Y0_RFVvNxfuo?z8v#Yu`@*2qUEcZ=p2Z=?{4(2U@kRU|pfC+T z2ZjE_K$vMTP8cu7Yd%NIh^7JP%YNSD8Ha9SKj~--theJNqIOKA0qluEyMj8foJ=F- zeo+@EnFMSTtf-9!w%*H!W$&!)HinSPmCAqMq%;fx-yC%`jsKLwBkN0P*}*hm$CtPW z+##_>1svN+2~;5X+E6;C3~wA#c1J&#$NjnzRh*#V4$3HoJ0xFoSF>k|u@jGN4=4xP zaL02pl5uilhDe#!Tuc-cXjbd2YP0)*O2=~$plfG^IZmSSmQ=2x?YXrE#$yEuO-N2j zmqp|K%pFljasM5iZyoL0)@$*H)tXwA79nqAWq{8n2Crfu^IlT#{AEOm8~m5qG)C4n z4(hEoEso$IdP$J(4Q`)D;}!JUcn6lihi1~26zE?%vmeO)O+&(I$^;B^0}E>(*R&im zaepTzq~`v28l-W@J0}gkQ{HV=6FTQQZegYdsdYpSxQ}=V`rbHKBqrN2Sa0<q>=4Rt zg@1*I>}HqI@R1T9RxgV}op>Z2SnLzrrwb&G?Q>%t@)wyqx7c!CdVrmr0DU-N;0_Zf zVZ;I9SKYpt{VW{=ylvOv`-AI)^t;dv9m(CBY1Gh34EtT(QjQETg(Z?UuEOR#*w<)A zX)JgwkbX(Ye8ZxM6W#0(9cI$mTlucr7fAG>-dAaO&Rh2vZ$Ne1AsXYM8Jn^8U-R@m zg^f&c;p5%brTl!;8;_QOILvqK3FNad$NB!}W8LfvIs#yNb*l#W0bb12GbIJ&>iyV` zhUtdUPW)t8Pa<oyIw*pt_(~O)@|4M=0~(PZ_0Km@%aBnD@nYQQOnDniM%kc5%xG2H z&5_Tj!b77U2F-JNy+$&6Ox~{d;1hK^R%^$&c{dOe*fahihFKpPn9dLPbZz@PCQj;0 zhPbOvwlOQ-VO{A?n7fyM=-$If2pAwn#-Pq}!}fHin7_}|i0E`ekj^CiXu@W(bAu1H zzl?TS;_KZiKxr^_bpI9-uZ%dL94SUjh`mw<VP_Q71-dhGp%#mxmSy90CY@saI@P1k zo7C`r+7PZ{I&$drpV;HTJgSF<7vc~5DgX(AL7EZ@<Aa)qDZK^fQxXR6S(Uvn>vAGM zT$Z?_x>cWNZ1dAdCd23ouC=iDr_$y5>&v@B?QiF5zk&>=<MJVj{<;iw%}*tPdOJMb zg)VFYahn~DZq}EI`s1VDs%Nofhbr+mX<)^o<9RZ^FjWbf<7F04Q>QW|PVmYP`K6^Y z58bf>POBoqN2I2?hGW99+nW@<onqX$1Y;^6%-92Fp;U~lOPXru9L2-HhucRYC*Asx z@#K|i$URU#l#?Sk(rN8(k5TS^)#F>MLf3)CroUA4BM8wC<AcsEVbpHAy!7~%+|KYR z^kv|+Y8S#856REpQ9|Bl8B_|vJjSkbBTZ5}u=5K>uZ|igBSzN!iX4N9<?al9U!U%R zOtZ1$w@ub+B(+b?<h!l+FT1~a<1dTp-+f6Lzl={hjUm7(>oI-rPvMzs*6R2UD65(; zjjdEH%HDaU?W?hIKso7t%^<WoPM75leJILjHKpw&Vm{>?#Ykih$luUCQNNdH!MyBC zfBxcK;Q#Ue?_5DxLtYOd5fD)M_y0au@V`%b);IY8v(W(o{dZvj&K0OyxY`=o8Cu#n zGrIimj|>iW<`IhWlJGD%Fn}TOQoqEM0l!CpfPjIZKmec21#>ZhfM`FY#DrBnvafPH zlhKFYzHh>Vpay_~Wdo2k;g}l1#Y~jugoT(;&^d>EBPN8&m>K585F(^wN6Q_dfzimJ zf-c~QI!OwJ!UGDKPV-T)@l0@$kX#J>@|^P+pJ+cAbn?Bgb27ZX+so|TZMVK$mQ>X2 zyIpN8EiK3T`vvi`E<w0d*|?;+U*ROFA@laAj&@n`O7MLC6eS1GIwU*YV#g{Y2n;Gs z^qc?xGN_0|<-8z_pi-%5WPdnnG!{QAEsfLTcDGWkN&*5`(9cIpYyD|O-@hLmv+M0R z3sc{Rx%cPuL=YARCfDbFJUcr(jL`43x@jgdWs?78bD>(ZX~V9QeoUKMp?oa4Ql)IB zEYDA?N}V3TV0^wrW~14X)qcAR7!>00_&C>b1Um+Y{e3qWQLEVk*b)Jci)f%<#BcB4 zKq&0VOpf<?MOn}H`^CR&M*p|Trda{Nw->-+F`8{RFb3{6iX`Lyx?Y%>m>_}gi|nvl zFY9>hg%)=i4M%=`y!75r&?@jhExzpd`(HMU`n~Rj@w#76O-*$@uUk{fXRj8BhFRBk z9Je3D%G?{@<DzFMYq!~jGO(J@=(Jd&`-j2fa(Lb!o-b7m0#%ahU2*RCs3<EdYiUi; zo*Z6pb-rA#745iQEN?lE;){!m4-XI9_kOwc`h9WOuB-n3?eV;3j*6)qOTeGmPS)xB z@f?H8+4DFrlSCm``1k#~^CsCzU0r=LmEQeoy~S|w&w7jX;7lgF^}xD-?|ZZLN~{5i z(Xgm^DcTcE@5`1uVedkz9IJVsIHs;im?~CINYJOA<1qSPF>#}yeq6tg=c`FZ*Eo5% z^F=Ah6<zn7911mL)jy;7yl#heS`zX-fHf}~F6#AcTf-EPsL*tzGZ~5mQPN`Jl^_Iu ze)^EjS(fEU@P};|j<Z6JGiXH)DA7<T%KY+J<o62i)o!&(I3RQ0MM95NW(LkvT(~_0 zyz}4PUanv7PZily!i_R%e;tw|p~tO)FE4Fo14UK;UqTZqQdvRp%cVxEMOs>#$K~{P zNkiZF<EqU(*YlY7rt9HulyD)*3-G#1<#W6?9Y+ECOP>$IMFuOZ1j8~7*q+&3e$Fiy zl`{Dp2skVzm(zcM2jOC6Wu>Ksr9ekRbD+-O#7_**r*a*DrgS-*FOg26aXy|36z%qU zdOt0SD=$~C{tcXGHkCdHh*S3+-<M72S@?1wgmDqY<o7Fkf9oIHt-r2gnay=@O=T$< zru4J^?`LIz00+)c8+n5W9PCcpz4pCWu6a6N;>`pSAfb|uA>ijBB@IrkbvzgmoV-~z zwgk4k`F_azxlL=msjRB?`uTdP>v=yP6U+7geiM6K1|(CA9cd?EZPYE@-Y+P3lZ?H^ zo?G>X!DVn9Js;PdN%B17&Q9B1p3Uo&xgJKJKGWSpkpukyWeWu+s(@7~NXhi<><gLr zE201AoHM2yiHp|^?+xF_q5sdv&VqvA78nQc1dy=Od0!wXAT18h==6KK)T-3^CIC_B zcC+ofQmd;{Dr>pZ!#|N@00?xQUO!(zBI@}*spUR3nodH^HtnihueVeQ&@l*SHqG!< z)z>?WCz1p5YNyNdq1ASyv8l-u*!TSrAPM%#IZ|>XJ%C&P<fEDXt~co4?GH`?KRkGi z;oK%F>ivGIYuoYrSZy%ohW@eZeo`+c&`jd8cR8NQ*l4r2UvH-7SFcSJ2&J6zzUeNz zzkNwJj?Lh5B!Nab8blP#X0t>&Qc^}sp`${~V9;rgr-3o0mXZHX6u`cNSG3RZI<I&P z?+ESj{ZQ6Q%;a@vaBs6(qTxriEB1Ui&hvf7R)Xpq^f}HjmnGq&a`HJ!(U6G286KaX zS2jvu2ghQwP_(mSs0;=I=<g=N_&pDZ*O^GbefFqoo1HF#2i~HD4?nNl<t{4?1B1YI z`$5mow|CIpKxAa(^VP;EV+!kG0GLn0D4{=}#@nR#e&Bt31Z|Wy0k*jZHa9nSl|~%} z^>$U`!4?&Jw?T&M&31Pd>!VPFI0jFxdJPUCKO|F@!M{+nF%eB#l8y&}2UmT(+-P8_ z5L_Q&_P&Oqkij@ocS%JiyI*fs$X4XNl7kccqSEQ6Cf!#~<Z(T(*6qXya{4o$sJc|C z=4s(#^eFo)>0y%s7)rM1&;o^6IQPoY&>@jhl&*&dY6yEk1q<ZXSD7pk{xk*`OuXWv zu2&DzCx;I~yJqt7d8PN;)ucL=UVGg?3;}<lZlv~Cn55^LX_^xH9r}L?(#1{geLqgw zX1l?mTqMNe7gMu&<NxEG1isTo=WdE&bNPpuytns#sqVF;bWZAvU6F@C$LDT1H;bf# zwyuli-1qC4vzM8=7og}@ga5EoQYRodR>3)lA`7#`RQ<MsxZnCf5k2lf-qT58Zx}(+ zPFi=NLR&!ch<5DE%u10VwHWgcxJaT|Z>30VcKZTh#(_^P*F8cbMZPo?75j?HU?M8D zxTIWBs`?y5<dNC|YD=n+>-)SWe2A{tNB|~IO&UPP1yGj1rjr;n5XC?{FzifApm6ya zVf^vI?-{pH34qyMC=_yKWeSc(iO0hsz)_IItw8@Oo}3&VIm(uz;LVF3It`<1C_)yO zm7%8N?2q8u7XzIVpYv7Fo)N4gOh}2Vr9M_-0d$U_zhKzKAxI+r{ZB7a=yD_w*dG$S ze7^G3gK(yKVmPz}1eISVs9@)7O=U{BW7NrD%|yk>c!^w4+j`wzj>>^jir_*ENWage z|Ax(@Bvgfn-GV<R(~t!fs;c%QHzvnyjr6|mM;)(*Gxf8Yzz`dSHX9a41lEK_^Dxh! zlxEo#Iw`MR265v7XOj>76xg^(m<Iem2?7uU!od)(m#cS#Kd+;JOY;5J<->F-BPWL+ zAd-87Vg3Lg<4H<L*lYMaoF7XdRp35K4wyJbq5?b!K*k#z8~?iB^q7pJKs}xa{%ES_ zyli{lBvY#Z^r)*W*Gt-5WKW>W_HC`*@!;|CF#zTmi7lvb5s*6o{o}CT<~y&fP$|Qy zngKW!8YU(omqTB6g>Gl-=)JQXR<VJZCEf&bP$8O{64fQvi~x1j%-KR&7=k=BF7K>j z$WfUnx42@m*WEDY#bQO1=YtsynafhW;h;n`)*V3DeF4VF(|-N;qC89@j({HkHEr8o zRpL<??pv-J0IUgtMz#3R126-F?%#hzPOf+R!zCpp8aj^Pd!sS9?tp1kyz!l<n1NF^ z_o$H3N(6pBA0!Dp4+9|yPB%Lq0BA4^ARYjZ{2R$}Tesw)qNCGkci4mH+`I+kMW^LL zDZrOEn#>gd()#b1ihk7@;B4nKz2xNNFo@&oHCjin$rFH3`DGKr-Q8NF-A0mVFa-cC z;odr_BnloX8k!(}fI&zM_ye+zUb{7!ngX8Ce@+`uqe?xd3T(UAUyvmFR=3mb3jk0= z7$LCbhX|4p`Fd0M?wkFLTH5}zFoSp(LeIzXBe5QySUlG_e>#e9ol?%?8_NTByu`Ia zR0sgeBJjR!04O?uqtab*;so9;04AHDo?x4*o;akHmbmMM4!V{=vM$eaMm8&w@Nbs> zm)t}n+L9Fp@yy>$7LE@(cfcChe%r1$k55h(&BS+@$;%_0TLJiOkq}@|%)KL1%2lQ$ zm>IXnW`L=!m+2PMHAM!a!l*_RRbVxeX8=&A)n-Tkp-_V^+*a^)GL<2k86WXoWGh^W zCk0a>2|N~cVBhm*2B4)!A;7dUqx*$X4231BYvyil99s%x_+rIOXc6k2fUN-LA9RY$ zry>t~>>@U<jTo|9tuL^l<Aw^IW-&FRrkx%Wr%;S!t;}m)40!=agZajvOs)1pmu4KX z=R7UiLUvi2fYioSjN*xe;@$Yj=>|AOYQEljNsa)P51Z{SZfGZK8d(5LjM3&p{`LcG zUOA|UU|W21Xsh{j#1tJVX2xmV%<81L%Sh5MDkJ8Iz~yd>l#2frQba*6B>alQWAO|P z?vE<*c}c@flh5~p3<`<BHac_3D*S(tDM2gQNmLpgNU9Xgm*2ZjN>my^&^(l9gLwdc z$Ypvso}L^V%ReFK#KP2Z2!uBKc_OnuVK*6zH_!8Jt-h{fA<0Odn4X@VnbB*un8P;D zX7+xzdAlB;n$l@75(j|GF!aE`q~51xZGG>nmiMQNI-QP2$v6T49<u?%xlZYm^8(&c zhdj}8G&bw6J%G27rSj*VA%P`IRRBCk(b=M0Dp>aI?Ts?W1%(oq!=}7}1RepvO)0GU z0Du5sZ7>8p3@q%MwyJ8eOApMT4NH{?yG!wJCL2I`0SJBy&9L2gS?T^_fC<|!8QpY@ zjW;*5#aN&o1Imbfd%$b1Z~}lm1pRuO{cHvx1O5ywDK9Vyd_Ags@n1DB$Tqsskyin; z0%kFxALfm9MKSXjNLM1s0c2bZ{?xZMB`$lasKc)sf;>_1|6BF?m1*X6#tQ~WsieoR zwxB7qiM*-3?p-EMZLc;v7U)T9SD_qQ9CLVF0fa<<P)s40IVMK!SDjC3LNgnpfO5k| zB|WU=vI{tJ$x57LAThFLO%ll8V{t$lTT{;<{^UT|co|oei8e{YBP?Z*Mr@TlMu#Tu zZl$yT$LRF{5u}2bc%j4jL=0uE$$S=|3$EGu4<CR$A4l>WiN>bYsP#E52%{Q&JX=r@ zcr)=_NYnleQm54t*@%sD$_G~(4~s#^_5FIVu&@9~fepa^3=D|q)xc>UMF^rjv-|G$ z0fPaFlaMjua-f=Bt~NwrGWHy$YP(20Pj@+WFqPPd^&V$hBO%gjH8Yux&CZrx6Hfq& z4glL*c3q;viVGWDyWj5igBATsE&~)oc&NSrxCaDh@`CopJ9qv{=3i76XbKYZI;V}y z{0DF2a9QAR5$9^Pijl0I%>h6`<PNA%lBa)DUVH*r?2&f%rBVJ^uFZbO55VmssQy$s z)Dv&~QjYoDB-gQBiXb#td4bCLa7<FBDit13#r6|Kob6&2>NT0nSrlDp;DJwgs>N>) zCwZR78Id!(lR3Q%*cT@O@&EG_Mjr(V|K9j#HP+@B#?D_Rm|Rkl2#k+#?b?BLjbu}c zKnjJx<G`Cnld5M_`V}{n*#983P|W#J94}u|wU#tO<4s1?K-*O3fr^~VkC8zM2n(#0 zlMIsLM_-1wNGen>=|)g7Z4|%8ho1}dPC5J*=LbptD3B)uk^7^$E*^TbHZl4-$@%eW z5l5gUJK(I=2}0b9#Gn;yx*Q_406^_cPs3k$N4d&QQ})YBYb1jQj63a1D+K(2{N>(D zU|&avax`8x$Y3{|XG4k=OY|)|f&h#rm_zDFi9;58HWT`^lA=^zQ8#u20=+770W0Sl zG~iI4ROFf&|DFHyb5@pTwNXhbgr{lToaT$9);2s~2p_D5Mdq(VlPYc>bf64Y`kuk( z**IdB$zdy9V~{#7${r&!S4*72rPAqUOWKiK(HgTDfYjkEg-dL^S|2#`10ePoC|WwY zX4efsk&X&D+4jy{ijyeFfIeBs*)LWOp(to(GeY-^Gw~NGe-@{`-9jn6Ig*5g6Sayh zt|dg(FKJStMP{uBJF#@hHgYbw(zj_MLK7=uwUH7MdM{MjLqz{q(bHXycrzObqhGzx zr?JRV5>6Sia#(<W?d>5OLWH$Inj8tk#K?Hkc}+qHBhIUeB!2+%x3d4gPDe6w37d$h zU~TlM<$fGoMin)0Kyo8^RB%2OyWM7c7Qh^S%uxvn&H$+ep!uzv-%a+pfqA6Q!>8k% z%VY5!RtP9A`xaB_sf_xy*P-yd$SDgU{(zcbhWjKNV11c=_FZ=)<Y_u6k%kDSX*<Tf zCCNo*@UV#1pHun(Mv9J(zB?Fgv)jtd<xns=nn)SNbDsKqdswN~6xA)+s(gFBe|Uf% z9E{|-bvEh25=G8(wO+KENTwb-U#wU-p3dUes8X#E35*zX1fYPdp0op?_8G|{1wY1L zfYkY41=DCW_8@Jv6(hUb<!@JlmIBVY41-Nx_cF>Ns`$j;WG!A#Rt)1cMVD1n5>XiR zRC_}as4>K7$Qm_Trpnu$?l-acyb$m>|5YsqA&H<L%vSDqETW3Z`z=d#`uf3afRtWh z!|vVj|LI<<(P|aL0sik{!FsSfa{w539}PzhxWl;;jZ+9}Zk0*#iJq30)kz7Mt$nN* zW$I-Kpj>~AF=Z@S8~h0se((J}Vl)jN&T1_}Lq``TN}P|G?9+Ny!x1kEnV4KPTcft$ zY;RC1l9-s|DtP1@3D9$-1MH%<U57ZN7Ly&t7T<$uE;9bC{+m&9?yrBCq=?LD%q+!n zt&F{&_kik{-$`P2JLn@6Q;%s_v8N#TKw$)9B3G@rXHK}dTXk_w)cdWgFdylWbADjl zdD5)xuG}5DF<X(see@=u3f&U5rd9u28F6y_!EidcB4yFB`1RM2;&}3B{e2AH4v&eR zBp+F-j&qeLpm_J3s;#iM*ixeL$z)?z1<Fjco-d9tnE;3|E}MmrZ$KYg(6}2<O$AS- z<KY#cS0Vn$1#$474+AI@iBOr($w3YniJWcJ!4A+i$esn92Qg48@B@%zIqEv5)1Iit zU3SJ|0`dR45it>}8k8D;nxaN#A}b5HE8P`|8rqr5`cx5i1k$JhA3eR?z9`KQmap{# zDGhPXN&4xb(IRx?6dEGFsFl){ApSlPl{EQ$cGeo_M)gLnQPd4MPfx$c7z$y6glZzS zSQt-uVo(rB1uAa>DMwP}Vfkgz$vioAt^5Qg4KJXD81{b(0P40jX5#-)9<bw${y*P< zrkBs>-6-<P=eFlbj+p0JNgC1<z@}<7>Ik}rt?Rm5WzrbzAm@@rCa!G%YZk;BLPsB_ zgMQ`uy`KSsuU5N_;pFTsEjjtW7Th`rcfPg*7fbQx_6WdV_B>RuhH?OHF+ipfDFQlV z>a{u*;@_VrEd2ccnGA5s&R)0@hBxkDG}sHrH$dJbV(~Nq9m6ZPvOwAxbW=04XLwQ* zc#8y8X-%|Y>gbMQ?I^<6_zH3mvM}tgwzy!4dfd54;07P0)qhi&8R}8dLFW@=V*y13 zh*A{Nhh~kE9mds;Bq<&wrA!0|loNk|ZZ|V^@BhH#N_hD-x-TweoaFiU0N_#ehYzOa zHlarCkiPeJ02T`Lo@5FjhgE7-%LSs42mg2#!8(y^THRWFksKsSWqjDubltGsX)h4g zc?G16+r*LqO+x3fcw#_C&BNjEXabz?;o%{TQGZ4%w?%ye(CLd>1TYOFEKLSR_uU9C z*a5LstKD+7=E&=Kx^lmKETE}MReAjSD?2eBr!vpj3l8Ao$J3T)gyM1zh&mHOmg8E^ ztB*=laHEx!;ja_4b<sHN($3*YlnTeb&P$tVjv^I6X6VF6#a^PCW~Qdd;LmLK+u2~I z>82D^Ezd~L`RYo|#pBF|&3Qz#c?OS8AYL~G`J9C@kHQABX@JVVw8Y_Gd2_QWtM!Oo z1eK4Tmq})UXre!$L#J~T@Nm=fQLDajXA%_^B_)lan%Q*_aZ#k<mPr_b%I9b-U6Skx zY!<7~s+lY|y6%v=_)4I<2=>xf0#_g3TOZlS2N`LIN2_Ra6<Ecp6U591=Bz&gT>^q- z+^E>Ty}xmw9rSytN+ZoT$~;I}A%Nw<ae#8bd9z3o5n;D*YVv>DGPra1$7I3n&OID& zMDb14lY>zBY~qn<@a5!-ZBwHp=BKheK@<m<XWV*;-Nm}=wDZZ4#%lx_+&zk`@${AK ziKA8%&g?TTWP#H<#V|$p<*ThN>W98-%Xi6nt<etzum;#>rsn2(&NJM{*wR3K#2@yj zCkqw8fb`91&6YR;RJJ7uCl}Fd3kad)GDQ+Ge5q1C*Nz;1|5t5a0aewy{YxW=NNg04 z?u{Vb-Q6f%!lpZ<k&s4eQ&Q3?4N8L|Al*nyHz+BB;`=z~_}6=`=f3+NZ@iDeU^B*^ zbM?38FV<WqgyNn|lU651e3tgZL=G({x7;xH)Ib$XvzzI?&(~@t>@|3_RFaXu(g4V5 zK9_ZUw~6~RsdU(anWZ^1{<8sgP;>MGSRvLySpikq3UzQY9Rqc+R{BE}0A*k^&JYB2 zz}~Hu)0CMxD0fmQ(2?E!IH9fG9Vh1L=_whia(rp~9PZ4<W%A|;F12*gJdIMT0axqs zUEF(>I(L;l$@O#gM7IwV@Ne;Neu69Pysvn#9pZE$XBF4MGv|nm7wUD}uy-r}Kpz!# zM1u7UK=*NG3jOt==PD4LF%6jCr`PBmAvYvKooqtX8PhW5NGdR8$x|c)L+>^-pjjP; zomG0ifxW!OeYKlNwgK&mT8Gk8gcjA(P-V7!(m`fwLMnsSla{X!n-QjmSu-1{ex<$c zN<e_Ix(Kb%sgZ^}=|+jg5!<2Y2@f{JAay;H<EXM4quZ;5eI<>>4Sy#ad7BB@bJm4` z$O+?R4<y6raLxQFmk>J5ARGEzu~S@DwNwO0j20@f@Teft(tT>I=}Ne+C<{NHm|BEG z-0ULl+Un{i1w<)KvhijZbx@wH;zf}bA-`oBjH&iKINOw%-H#H#O_MwJKC(HPWCZ=} z2Sn)X4vvy^T+S+BQZR!%2cBOZ)8o%SIo>4f?SiXKYu-&`M&0YClHxLMM_{nO&Y~P2 zh^rDeX#iPyjZTgg%=0-O*LONAsx|>l7LVw5_zZbfVpAOT_$uJIqvgi1P&;)Aik!4^ zJ8Z>nZB4n%)jNGk{Ah?QVov%{)5dkp@+Ps`UFsP{SLCMHu|gFd37N070@fP!uwDmw z+5Luwh7it7wq|XWQNn=4s<cw}QFUSpHtg;ZOa=lJUU~rKlsIUfiTBBtDH||n8w&)E zF5(;pk9$nII$o2o)+gq3UIiR4n1$tn)GG{I(8)Xy!X;YCp5{{$8Db3-*#=J#k9Gk( zR|lw)m%>4}!rX~(KaF_i7G~NNHG(iZ>(Dk}Cy$Mnkvc)fNoC|0e$P#6GG2p$jF-o9 zn4;JGCaF`rw_42GP0CcQ#8|XsI`uw`FA<!Y=3Srgj!(&kBcmmWte`hyQzjm1lA#P& z!XK2%6%4mqB}j?CeuP5XrmDY|Ha3eH-0k79?>rdp2kskpJ`y}iRU^?ewUQ0_q$?T< zftQRe!n^5tx9K7FI2!|L78MeCRB?~uY~x8*d5(|7sO{kq5u2I{`drQtMus9I7`8V_ zDZ_bHUU8azf#h?ucNlbuH4`y%n0jC|HehZ_$xw+h6JW+fX61{cqs!WUR`!YX8hiPj z-dj_;J5vn0g)C5>lZL<$1^9UJ8~Ktd-!H%A(?lg?KU~S~W6$_BZc$*8sN%TrL?@Kj z=gd*~;GJ6-O?feYuD4*2w7l4M1m;<~%ixlC7FuwYrnq$Mvux^Icur%DdTT<GnNW>i z@%lO=UlOHHlTVnBr;misWL1~jHR&>A^jP6A4l{z{J5(~RyZf~bi~(<Ghjs}OV_%s| zJ|&JmbQG;iJzFMf(ln1|xztu0Un+NA`pUr|pG|2UEOz6yyC+cXvfxFh#ib*+vMU9U z69now^G5tN{QO!`@J;#`Y_6e>`==8-3ggaaK}Bi`<-g*R=E_C|9`r{8oG9C;bDxGL z`5YEEIL0L<iwQI?pnT+(jLF_lWKD>qQcmN3${#;&{ORmq#VXtD^S%-cs?%eXC(a;f z9%+`>F71C<Z=CH(jM&nYE2)|wZf%JZoJ97FD&wujddiFd<dH=?e3@v3#Ijv3Fg*En z2fKHLnu;Z2mTse@Yf!=0{!GRL8P_N(Hq4Oa=^9f<*}A|8Ni{BK+%3WRdWWo7l6KP@ zF1zzh$*%8E2jiG<8=RDELf&92tl4wAsy-+vEVLO^j*nyN7dqq{*~y#IOiGMaAH|`x zA?%ryD-6Zu$_dHpSB7Su_=j(z^<YzvVDly3;-aQ@!phnIj5p!gXuy3$(qBgO&Ek+t zXQ$c8lcL8GDb4$MPN9Ty?S-wz+m!vv*hThs6o-MlTQckg?CL<6T_gP;bvAE~zZDRu zV{j^MQ1h4%rptW~TLEN>4=51qCkz`zd&^eFh=oq3wocuFBr}pDHT<q@<}QnDgPV_T zE_x{_m}*VCvAu-A^$wtQsZpDsn3$MozS}3<fQl7(zS;{nAAP&omwP~Ev7{3IvI<|< zmS9&AJa}^1%ir1l!OgnI;AV<?DQ*lN;<->^g!uXR3muL@Ypx-P-sXnFM0xXJZ_xu8 zGSgh%o$(xg{FsQhg+qc#ALA+uHy-k-^JFTRenGwe7U)M${91Y0PH?k6xHNoUA0e59 z=xLTx*JvtX4~OH~Wau*NHl;`1YdIc;^(C!sY-k_?BA31%Mdg+Oze*g?iSobJMmvD= z*p;g`$+0tnKq3?yaGm8?C1xXQ&oXmu5Bu#e?1uXL^H}gOy_tC;QDA)KdFBJDQpr-d zd>`s;w5ALDX!&V3l)vaBdpXI(AbiV=yc;Ued23=@_N7uYtEn8RTLv+I6o)P+JvC$5 ziGmMC<{orhv8qQ?fy137_PPl}W&x>P<h`L|lGVsLmS@KLfv-=g#DoA9rNAV$>OFie zsjiybnPQR8g!I|luU^A8mEuU7bQ*4Xij``SkxB<1AI+?D3vEJ)xeO5MG%vUfvvj-s zvawTPceMpU(yDW<721{0)tQp_*HG7TRrWv9=mzozLb->I^*du{Ln9BxprOtvS9(4m z_ex|tI1+CGc5j}@yT6M=F~4+1LX28*NcdtmmQo^K+c;F>R|XIFTOEM4kH4%XgL1O3 zzds#FW4`Nv4tBgkY~ak;87sV*(HhHjxF1_BOP3EIr)g55l_-OVh*2arS8T_9zlNC> zZ+Gir417Ar`!5@?p^;|lnB@scN!CJeyJ)-i`^*g2I=QsmWuY`W3O!;&aRzR(N_h`r zhO&{`fA|cdjG>A34e=7eVyX%3$~QpSUs%z0Ia8l7*WhBoID5`ZA{3aD;ABm~lH8SV zCOXZRhkYeg+(gQ*ygSHS70=b}ZuX_%U6fe_q$7)@|DaPvEN#Nf%#3ivyuXFoJuw_r zrIl>Qnb;mllAmAeg@%d{S1Ys;y;r<OWj)Wi_UNgRhk#iLUj`$(i%*7tdo(<ZyA;sP za7&5ut7~B1{X<>b3`&bms?XZ18X&C(2M6og8<Tj)4`vE^1GP@JEidnhHXtou!iNBk za|5;b6B??3LY3!!fLw>a2WY-->xS)AlRL|kMRS<uC6J=wE1>un`Lc@tq+l+z7f+Xa z_h9b>Xkc(QD^Iv)9L?fKb(lO98D}|m%H*t#ss^DGb4a2y`m(p$-0WqIE}EgHKAe0E zW8HT;gm$<{J&DuZEvfFoF`R9-eAu3n-xpMbQiS<HS67!gN@AuhZQe>9<<G1>P1(=A zL*pl2K9y`%m%2~msJp|mtAv~@t}LvS>WuCMBg7QFunbMU{uo04tVC0CYqBg&m~vi| zq1kaW_Vi;M*$^BYVfheMCnOs7?ruF628P8lONCoC28w}4K?lB(^sREzUS9ksNe8ul z@4`y7Y>6OT@}912iHh<{shnH=97B>Aq)JpXm$a^qS7A|K4Xtf%*Q7;Ew-x|J-Ps*V z3+a1RKTXtiM!LrMX8KVl^woNe`2bKvZlgmwium(l%9e^uH~CZC0>KHI3(GS<+;S?w zjF*G9uIH|5Y%ZR%sP~>eV$;<wEHmi0XEeVcMyXB@B#whj{775UO;9+OT57?lvLij= z$w{)Y=N7mcX}*!m-qfp!MFUqS<#**hm+U_m_HIfU9_oBHt<*WGu6s<chKFeb-5bM; z03PWB0c(_}4Q7HR<fAo3Wks6@8SV?7#T=Qdw|l?U9^}Rd&j64+m?1F6IFd6$88fb~ zmW;S<(Dh!OpBvf0*^7+tK^_96eW7|iR<`bdrcHGpnh1y2nDxY$8#Kvlj$qH|%BQt_ zs$NqU6WAmzPl}Ixv>+6)BxYzx#u&?}1m&e%6Jv)GJZ>965o1vybqFtsio()Uu&TLD zEbNItjO{h5t{+GhZV7F$3^khxxw-JJFK9Zo3j=zmCoh3T*uLnw>*BP=kR^0A+UfqH z6Pxh`(={DrK{93-T4U5_6z_^<YJ7E?H4GyY)%`oIk~n?&;+^oWVt;us-BdsMAG8mQ z09T;8c(|fK;R68S$wq!e&jbNj5ZJE|62{&Dr#Kw2H6s{TO4=0%v%I_vbT&{Lo?l*k zEDTk-Sqf^(uT)R3h!1R1ew;`$5(65qGoY?d14(czbjJbQnSdu_Q_tY>w-dzqXo+PY z2_3gs45Xr#0*P>@)~W-MCDYHNkTr=(=Zz;J@(^!5Ag336js}1~=R2sGNqFq%>|V`t zyR0jo8(qJBkBON%m>-3D(jO5y1e^5yQ^!s41ztcH09(ZQY>w1*JQ86a57E!dj@n>R z^y!Y`$@dJ5<p4)V%w=8cvM~s5Aot63-3HV79A!gfocRH~x7%~<mMbAIc}2uwz6!?1 z23XtoK==nf2DKMJcJ)0Tk$J0&-xVWrS=0tf9qI}oPR;~f`@<d*FEnG|KA+#l=}Bqh z&{}2Mof-@9YAD;O+{%UqvKFv7G+kO>MsLeMF77!_?p2w^BF8H>FW3`HUnYh1^c{8~ zAA9>94e+G39iaE#Y?x#5bFI;H)U*ZsD`re8o-`U~SpkNaDN{bYN^x<eUg=e&jB6s_ zq57sH9oedVW?rwYFq>%G#!7e0M)(V0pvmpJa+NH!cwe0C6e>jnWT9MkBEgs4TigZo z&(}ms{R7WMo?jTfw0-t9k;SOh2Z)jEV@adBpc(<bkhSW$1@o!?&7SIfhYzivtY%-@ zL5u;l*)_l)3}s@<!%Hl6iZDC9`GAtI;%S75|6J<(3M2B)$+pMefr$i<usrM3*~JBl zV8VdaJCwP?K{jMHxfQ+pq0K0|Pbg#$qH;myvcj18^4^1IJ#i03j)x`KSph$0Gf_ft zQ|z<C@>~H~!Jc2nCLlA}Db+~xZqE1d<kzb#ARfwITwbzZ8D8<RIZDw33lf6RFX72r z7E1j+$n^(WgWlCGp)Q$>0SKv?HLr-cIlOG%m(SPP+*Z5NZA|TE2l%&usU)18fturn z1*R1@Be(s)mh<7u&3g=$m@kl2gDs_}O_3@fS-4Qb?zQ1TZd-cNy~zHjr5<#R>*R@X zSpB#d18F=P5;=sLZo@NzinHJNm-b>+AG}8LdQXP3|9P&z;+aAhOG8UQ6<xF7#hJD8 zfMQNC_F(d}Esj}OgZ{H=4ljNOrX1T89YF!=i)LuJGmXF99ed;TEf0%RSCe<CL^Q!g z`+cyf{ps6$uEQ4%;pI%W$S&TPqnd)5cj9y!Evl<+an4jN0`K){h;*N=ugYZkBpOeP zJkMH^9wPnI3kYuYWWL905Zb_mOzc49;K<5%y}i0M<~QP#N?TVCn?8KQ{<ctMDsz~_ zA-fDF%VF#W2H13-z*(4?`Zl<(UwuE_pVvb_Uh?f<yOOJ8iup+J%9mU|5%uJaUzv8m zg#_r`5gIPLnd259>w^l!cL>&>!j_i~hfBcUgNx94uGR{lIV*$~Sg^=FSL1;4gBItu zCdm$6n@$`uB;TO6zd^0+pNF-eX<Q#N^rvMp%1qt*Z5XcWI^d);GBfW<CC0^7f!Yz! z*9i#;b3nCkUBy#S$j$)_#0M}xkL1dH2Gfz>xARsD1HL#j`9!gMPPGaB4pcn4k9diH z&D)#FI9&(KbEE>JqoY3Q5x5VnikFuk`k@1}nDuxONP+t2>fPtopbaHSX2%!9Zf)oC z`O8oV?kZQ)A0X@%6cp;Hj6snA`1(U%ZHA;IDwgp(4J?Muymzs9sMf9nEwr?vwGqpi zFE7ctFX3CT&DmcbO<Cf69JVXV9-cfSdU#NId=rXNZHC8k_*Z5|#^r6(7@<dRiKHgf zy-#<ifr<xq8Ia-JWeCO0z{YXP0|&x4U_`qc6op-!A2o!EZnQ`&4C+Qjd7*>1_|B=7 zpxkj864JufJ`-|W^cNIAx_Cz&1H2d~md@c^VZ(WH_)2|>&)C<1#}J!pr#Bo_0xh4l z^(N1QCAfWn-%TY8waC`-#`C}2q{R;z6dwzVh_nF{;@7?TrdKg(CuF0lgv=A*-1&lj z#Iw_jVZpGA73>@Ga}(+Efq;=)#n3P&sRa}mLTFHJZ*T8Ry;E*2_BK6l{@S7dxYwIz z-|5qQe=4`DYWT-C{D1ed{y)27&mJox^SpVC6Z;Xkff3}SlqJi>jRXI4yH8saPX{+w zW>XVWOPHydu^9t{v9a;BMKfdL5o9(GB0`!R|EN;d5oJPCo~Q$)E*#S*?CB;^KGH?F zNB&WQDUD;STi->|Ku=NhYumN2r3Ao&UBU043;khlzFM6hgBW~}aIiPGvT$?$qlK*t zJBy=(qno20%-)UVpX11X6K7>-VgYku5w~)+GjVkJ55d1%sH=m6t)q!O%=Uj7=i+MO z>gMv$#Q8tOk^E+59i1I4oMA5im&hyk_uqHV)tdh2<^3+|YJdLkqs(m`Oh6Oizqajn zU4-d>vxX+7rZ8I=IGzs9ET(SG&VTj9L;mBu0N+Qr@~2;oe?A$nJnb&7p0=<*I?qn% z&PLC2<M;wMA?6H^PJByR-Mj}fr;<NX8sr_FsF788^^|OmsCw(_4hN0YJj;TaX|3lq z<H4nVAWk~IU7gs`z#GC&aS|UZTN^O23DJ0tMl<hFHuQX9`tHujH<k)ZLOgN@r0oq1 z<=}x%zAhiMG>z7gH)RAEadsr3=DZUMF1@FNZ`=%IzQ2sPVf~rGkP=IO5l$$jAc`T~ zgfWk4vWO_rtyYU7%8DhNM|<ueI2fZ4d_1{RcQmvTbQE2UlGvL5Fy4>o?Om&_P^0DQ z^iE8IGwkT9C?5Cbh7Cg7Kvd!r9V9H?0XV7oii{)@7t-L(3*ibkb8HyX*K1V=Zy6*B zwqdNe+c4Ek+;B?@=erw1*CvcUl9x1BnrSwmBy1cJ^>hin$EgWW=MQYP8o4uUn%?LX z9d)hW+VL@DKX-~HNERM2?tx8V>l5qBX36c<s~5Ty^#CJhX|h+RF*^*O0$ZLn0p1pO zM`_6c%XwwsHthg)+}jS$WOd~E8j8)}Kmi4diXuz$Yr?IS!~-xv#GMC7n!ze|TeSfr zH!}B8Xiq3<OYRnXRQXO5Nu(A!UfV2?LO6hSM9JbtOuST*=#Z|Pdl-I{zj=MIFeW-- zx_U_LHbbgYnGMSe@39;S%ssw#zy6O##X02<%+FsP+t>(Uz9k##i59mPFA<}Zm-Vsl zwdObDa={|Yv@OpctbZChM~}G7ux9vPmNs4eC}chAotIT918Uv8uK7nNOq0+?(4bjo z#@|fxY*=61`OWJ!8A2hkm~-TZl4`bZ-k`_tItyRO;wKCW51;I2(`&b7M;(4>Qf;}! zS|?wE)P!Pm5Fgue+iaX=<G<1vr19z%DJ(RMpcR@+p+@1A^wf_Ml(t%0&CF(^5`Kln zYdXxALcx0HbwD)5ODj6f#9s1AMeev8F{+|5+$llM)hc>@8Qu%M)Wzf{RD-_PiquRx zt_9d-Qj$wU1ahK$@~cNIo8390MPyaJ8FIRQrQh7oy5QQu>7g^v)mOzpV~<79AdtD! zsq+L&ach<>%GiGy>5wr>av^gx?8R;w0f*i$aSxr9|5_sL#(1Na>H)+0l(9>+UCJ)- z!MW$M1@p;Ol4#kkuHK#cbjumyUq_gKL9%CpQE2@-^brf;>c)|22YSO$hz%s)+})`} zJRlA=Um%!{`s~O~>$wV?sjCq2X?|^K4J6<}hi3hy|0w55^{tsz=49g4wmd5Kx3RtJ zqH>ZOOmB)CDfS3ahturV)+XhlW_Kx<!v%W|$8R@0U{Ju?R|yMCohl476E{XjDWOi3 zp8GQ3<)l}*b8S|dNK;|Kb?m}0Rc;`JtxWn7zo+O$QaW)x>hqW?x0%K2Fg^W;yka!> zsUs-IbC7$T$?7NuKWiA=j1}V43LJ=L@3HT>vl&Fv*Bh&NZUX1d?GD&J4|FoW-q=kQ z|G|erIEUjoyEc#JU<m8m>ULr#dw4ma6SjTNM+Xb-5A?A^k2rZ%7@q_mdcNLwFR-r> z!Nhntj6i`sjHPeTH?bX!N!gY?*U+TP%{Y%f6F5rJxpyZQb5U}UEGy1uh)4jD5t~TC zS17bOi?F4y#V=?)>@cb)V1?CH?vb_JSruep)$3p?+unB}p-8X2Ik-M!aOYNrR>jr^ z6sZIIAXK1OuddcQE$-BoY;aum!!D0{?{$vbh371Uk;+3UmN~~KC+&s#E1nqNqSfQn z11!p7w8y0AXC}x!Nlevj*ISwjZK}Ut*Bi5&m$&{#On!D+&Qam+O;p8(N-JAZ&ztTr zwiswx(mbla8P}A%>cCv3+fGRCsNc@Tv5JKAAq6phD%<P+ysnT*awws?M|N@Ni6V1_ z#rC>afj#)McA_|MFf_jHRWSLUW36H6Vc!;a(wl%v%OjF=UE+A(!SR%ej899}ni7w{ z-MUjxxP9r_c_aUW0ye{7Rb#g9EsoxBzxO?h8U<A{MmC3OYTFtQ$H=Po^O6PT>{~FO zQQTY9O-xOzq)+empb66Dn_HRuL|RT>IF3Jb4l`BUsWI9tUcR-W3Spn>8*g*zF;w?X z)0io7=lep4z#r~#CxA$c0*9aB>D>+ABoAbXq8VqJfUhzI6V0ij6JAexgyYM-sYBUy zG3Lq=aKE$~eF|VF^b4<?=_u#n+<1h-&bh7A#z9>3rshj$3?!r)CriVV{o8#_q0w77 zXR=(FZkEPK?jMQOSXF3Gu_ai?Z=vdyYqhXK<V&!#N+ObmM67y@AYap5vN5u)a^4fU z2EVE4+^d+73GjO4xl|(Z;JbH{VK{62ht=&+4G}-Pk*(Nmq)g^Z2|<?)_tK`crI-@o zVsrhr7mNA^XK?M$ZA(EMQ*oGLBROflC6ljYp6gi`?CR3H6dc#u2N-fidOf!Dv`W(Z z-nVjj=c>p$+K%BSKu18JrTR}dQvz@^Rg%&aW0q5vX0bD|w=##h{L!Vh4F1~w4J%g2 zNAC!x&t2_S;*dN<IGtS(GRY&X;#p~VIHMDh??td2sccxd_1x~%7r*XDbTtyNDKg*T z!2%x!wDj!z_r_kzetC2hFL*G0Y;styJ;3vPhqg3tf)9<@9Zk>S`3J*|D0+la;yuQp zI`JhR#L6kADevUl(+GVx2R+<r*n2&m7_pnGaer-uvV?E5`A7P=FUOz-QM$_EzE#fC zzoR%D@1R1k@sv%Dxmc0!Q%$IG0ZiQPDKy#5t~MT$hUlFZKCF#vgKK1n?}hEl$w=eb z>?0NNNz@VRb08W`L@tIq`dtgC^vA*Z1f{wf^)!U>XE`rB32+U1kd_EP=07ysA(l_j zq+MX0$#^;X>Ko1a;CiFw*PE14qKv_4xjTYIT^DU>pGC?tXJ;(42Qh@SqI82^-J3$W zC;ajFk7LmEwYOCaG}G7oqnSP;5(MF&-`Q|g^!yw@-r%6B@MqMI`s&yA{8w*j_&FrO zNAT8%Ki=8!_o!d{6koOO|2bfw-uktX|KB5jeG>7ikMYkDkMS>Ejei9GsO10tpyJQK zZRkHgw)i8<kInrRDg5h-Yd%0g_!W};i2SkqpUXo)xGL&@jvf&C_rm#CT=B1m>1P}Q z!WFXkIS{q}J<q@4jDJq{uPY_|n`FP@j{i2#qu=ED6^HzDo+~8sbCmxk&%ff5f6jD; zF@BEC-(>oUQ~uj5WZM6}vwz~2|2B)}Z?gQvF@I+Haq3-d!4EKUg=Bt?h~H%S2VC>x zto)Jm*Gc&b$NU^iAn8w3^Y^%4Cz7iv`{%f4{0|ejssbwLOpbtn3w|8I{8Mdm_22&i Donf`j literal 0 HcmV?d00001 diff --git a/docs/scheduler_formats.ods b/docs/scheduler_formats.ods new file mode 100644 index 0000000000000000000000000000000000000000..8018b8c348d42f167feccdd242e823de4d38e71a GIT binary patch literal 19094 zcmb@t1#ld}k}WD`X0Vu<WihiXS<EzI$zo<^wwRfjnJi{zS<K9ANpHM+@7sMFclXCe z{Eq0E>Y1sUs_M*>=VWy$$bv&)fPlb&fS_kbhz476M=*kbfc!myAAwj~SerPx+nE6D z?5r$|08SRRHcT!y#*DTAM+-+rTRRgQV_PF<YZDtMMn^jb6M(U!xrvFB!oRf%0|WDK zZ33J5zsJ9|Y2pN6bhEaKPEfSXV8#gEdZLS4S2w~pm!Z#{V|UJ2C`(9|_KpnmPH=ZT zA4#Qrdt#$Bwnz%?{MEMAb);id9@?))RkO`wA{VV8qX;IUQ8rO5A&4E@Duz56I##_b z1CpY4ugy$o`>RFToP&T!mg6*Qr};u<Sgs>D#`D(&(!@gFv;|?b#6fP-i*kYf<`oyo z+q=NVQJFJ--{Bp1_#$l5?!bjd2^j?>C}N<fq{i6D01|8sB1i4f&&npM0#G7R$&RSG zfT%0<E_<a@S$GIeDiXk%_MdVC-@y32S2O7BJX4+x5((u&=04#waDP!YcEHS+d9?XA zNILGWJ?^Rz$m;k2B7BV)%@ADO+5l{d=_@)`OiAdtvC!D4LH)eEAGd$FZn8eGlDi^Z zCZGPy8$KRX{~20|b&aMnwc7CWC)QZzD@zJIYNe%7O2@Krc`N+ptI?g<a8M~V<##Z( zx<$-KL%lJ#9@{mCW+qwkNfsKshZ=Mw3C;RanRihcJ}w{3GJJCCA~0~)i6*_^-7)7E zd=Xuv=r5t@x0H}<l3=MWS}0u-_C@lEfQueb^-T&TX{UbixI%M1NH^4E8Svt)!D6sK z*+iP+vvWwKAPWt1cRwpQ4hp=}5FjA`y#XKqf8c21<YZxE=J?kLF0|JjcDYczw`!zb zoaqAXDOZExzTrZ{@cP4Ya>3fxR~c9vk5Y`{JijKjO&EX4M5!&IY?^`>PMNnZduwcG zVC<Oy_hJo<B9p<Bc}OVF6xvln{%IkK8_QGTOQ)ait1~w&x!>0=xk2qGmgztp^ri3n zzEj`X*<}bCi&BXnnI09fUnk>l9z>E=`3gZIU42;XmI)Tp?}&rgq?PKl_FsG>rUeu^ zt5kk8X_+i`5S%LAh84d>XvO+4Mku}NDzE~oCS+2J%X8??uEs_sM$KdkXeKXstcZHt z+fZvixWvJrM%OZ}($N?3A}};_NN{}hIZT#2bB<QR$e=~Dgqid6>Mt-N6<kP36N^1G z-C=JTxAC8;BZRv}v#(u+e=J5u?(Ni&q`&g2E>BG@blrRhN69AL{l$GhS8veinWE-c z=v_A`fY;x8RJ5=kAdRk&9xkl1Rb&B{KIaIrAJJKKJgtm?hYGsNpj)+^F>N3grOcg9 zMzXOjAnEvm`$8hQ|6^<>9u2e>(~$giA@D@*nufP;h6H_t0gk`u-NpabY2oM<+pner zY;qfJ1Hw4Hj&BXHt?lhdS;J77Hb^hIdnmiBy?})o0L2aVof=UBjY2(AUdY<7fc;cv z_VmLmOADMi7`DGV!pFR}&I`{KS0<rFlqSTFTJ9HVE55tr-Wdy7WGS?e7{WF_&tz!v z6B6fDu|?JXNqmWHHlzEi@92E-JxQ9VftMky5MOVn*Ym4T&w5}DaufuGZi<ucoU`;Y zQAV}(0GXd80(nwrJ%|#k^XLMFa>}>&@l>7)Pt}dh<t8=ftEj%$*!I!c`#si(I&h7{ zv#7i2qBH_)({Mkm!0nUdU;9;3$)o&W6KqyCL@ekd$1=VjJ{g<PzCz-PGojqO+9R;# z!Yn2<=HJl2mRn+*rMvk2?C-{^rCs)uT`cfRW$zB@4Xnf=Nk-0#vr-1}i1m$xkbuyN z?9EHnW+rfPL^VW3i7AC`^*f24>Tg);<?nXq)lP*#cWB#M9kjlv0mr3A?CCIcAn(NF zCQK*EcC`M0bjv=-Ce-gga~!CGwD*>P)#}rCC0*%E+v4{Vt@}KPbPnXhB**`gt&Jl- z9E}ghr#y#E;il+!7A1-dvjVuS1Pw$P{}fcim}N-@h!LI*2rjUI*pqzJV!W_W6TiuP z3uT3NCnOI+#<3Gevybf}b|g#KgXx@z{YvF7g+yOTuCAl8me*Wrbk>^>Y5)`G6t$VF zwwb*Zpe$x%+$o5YC)cTdL^R%D+ipZ&3R;Vg*-uU<nbM3Pp2&#F<<}oM%^>FYdx<it z=Cjh==ePdp-7kgDi_Z{MPcFTXg|5@#_u1#BJlFQk<&#*m(~~S|)}7Ix)@ll(rY!{m z8n3^Js~}r>)v2Dk@LHEr-YZ-dVJzz>WB9nCelO;0cW^j{x4E_Um!l$>+F%>GmQ6+H zo_6?S^Z1{D8!~m-VDcJkoZ;JhITqb@6MmeT-=*QFu5@vpT$Gl`xXYIO_>s`jO8K@Y z?Rv}JmJ@`$*1AOWfpZ1<yfrEnjrbcc{o>aI31x`&{8Rfy&7Mu@w{u~bz?;F+9~FAb zdLw2H_mA5y#w}VdB}>g0YFmx(!?UeRoS`aTc^~Z-nu#tKwU#qE@p^Q9miE*$=t`2w zhtBtAQ9%n=_>A{lz+Wf=S>CU|Rb>;o^$G7=cq5EfqvsH`-|CZ)@uXCG;iIaH8A#%O zO*sWk754N-e#U2EJ{T<G7N=D5z}X#46?K7x7}<&uaLIm@t-r~yARSzc=q7qazzagS z9l&;|(LYSFzx-7?oD$1AKQ|Vs535q|BRKm9`7cTjxFrTzL4ttzv;0pe4G%<VBU>A% zzj6I9Nb7Dm?6xO&=aeXzsLM^N41yZ@uw@A(ofdkQ6wi0i**#`@H_6sPx;5A7#KVlX zrMsqn&7{H|9g;xFfT@i}JdKpE{YYM}DSW8AJ+ZA}L+&IN(LLYNNmZYO_w&N%trl!+ zdwx5vnC*F9Kk|JE8a7&%SVn3-V%uly9}?IT1SPtdKP!DWG?f4I1EEZ|#+ys@K7DnW zOUQ@sRO`~4pc<1u?|f33kkBPrlI?y>1v;|(htW>M>lnbyy-{>q#JTo(JdGBa$Y}9b z%>vs{s-riS(4mdO&1u_*{#R_}p@1_9qdE;8hDy3`l!%VZIP85(K?b}h*c0K{j}GTh zw{aR#oD*~ns83lWP^u^B-X`&XUe0k*O_qe9wxl_T!)_V>I0qY+%aO-w&ex=b*SmCm zV_mWOPNKNfP<z*2t`YP1<a2>qWf$#!A0o3w`1JhKJx9l?tSfu3Ym_ASTj+(OVDr{3 z%3h=#2L;zt%BEt~>TCYA($(P7CHyX{SmEX4(k18pdC;C)@(}yxwAD2slm{wp4$e;l zh)J9oOR-65vr}XF_t@bpQO^idyT#S_)`p$eL}A}ST+*Ppm*OlaVNgnXz=X!ei-ScI z+FG&Ip-BhQES_r?%CPjs*k~Qz?`S(RPCcE*XOqbmo8?epvUBpc`6}=UQ_*|rZ}E|y z2Y*J%!@nExJ!Op`icJXBfRa|52k3E~dsv5X)SQztaV{FaH(GEN4MjPO+9MABYGU`; z7)@BMSaTAgt7F^DwC@+OmSISy44YLJZNw!VvS;enk&d{iik!A5jzvh}jE6QNoQY;> z{JBHCUXUXwj>PSbkUt%8nGvbID>B^)@>_F=-?aLv*{T)fhmm+Bi?D#NvQ4Mcj*`dh zioj>sT~Gj#IcWAZ!Yd8@I~@Y^du+7NY=3`B?3UqHOM)i^V?*1WkH1&tj8jsP_FL7v z1a3M({WHO<?ep6gguL%;nv4&MfTv&V(c2jC`mZsWg*!8g_?lR?UPwn#OanUWFh|ng z$o}|7tKnyi8p_g&J`H`v*z`KoA0RsjmFQ(4Ks|I2C)_(T3)t2lV%wFNroxaNW@GGN z(vh@+N>_guuGo9sftR|sBCA%#vcIUXDOuc#=BnVELevWUWi!wui*YtJ;5>#=(Nr+y zJWg8eY~rHTF(XkQm9#ww1^5&GO?82sQ2r-x8Y@Y&nwi1vVv90g$w)7#quC7G{!Y}y zEMt%v&aF?-*GU@-VClstNc&w4SmN^Qg8Ay1b<35#^W~AObDin?Fx!`5y&&ymO~Rcn zKIcx}S{bs=oC@`mi|HGd`(yb;<Xe?n;TC1W15-B1Io?UVw8A4?fpt?)-<($76L%<u z3hPH1a{g%)%ZDmfOv+{AwW~{_cULO@X=Y33u|mFOt~L1Y&L%&z&B!@C-;}$xiA|U{ zScZ_z;#kF^K;+|4qn}582_l*WdG`cEm4i~-ZUW}U#kr}6i~OOtk{cP!uv`zS1zAj2 zb{aee45mBcvMw=PNjg*oRyoJo9fb89bg_g;9g=sT$+}PR`rC#%zvp_*c*>=_+5TGS z9f($z9f~w>$s6XN(-YNc$D47a>K4Aq46{03@s8Gpg+uvPUtGrm<E(>%6Qo5|ZSHLq zHhn`qOfeFp#U~Npb{!9Q{9Wv_{-s+uj>Pm1opPSW{=EkwB)YCcOVBcMi;{5IuC_gC zuQL!`e%@(Mr`uyI1AZ)5O8mNnO^UMG*3F#0QeHzRJt`QjN)5(LD<_laf&~a|CVV!x zzCY-P91q(B*4%<?rTM<DByPVL<H34nLGM6ry+U&8(|O5k_}-S7el?hDaD!q+|5|gy zJ5S>zHYbzKZI$|lL`s7A<HztkL-OW6uICh<xS=(;680+#q=Qju!}wAvMj3xP$K|z+ z%}q0aXI`{suIYVfS2{H6AmPypES`}BmN(UQsi=^1>ovo+L9_a$ImV{DYA@aP^;SIH zcB!e0b4!_7KWvPB>v49n#ari2PQP2~Zc@g|;*Md`%X&W)ro^!C%1tNxoio;^XL4`t zZ^boRwM+GN+lLEv)geuqd!DgYFtF^l7_$DDu`NUK?}OHReGhG4*+tZA@7Hc8Q(ac6 zj_cWMntoVJ9UazJ*i640WjKD8E@gIm{2a>kPb)2AS)Pr5LYyeSofJwoe^JxvR&`zQ z*i-!&qJ#fY6s<{Act2EOieE#24`2XZ6_lGy^6(Im@L<D2tYY!AO$eo3lCo`k&ScqW zTL^{IFUnf$4C9>l<tWRrSTcEk^YVKfJMcVEmSMI$TRir=tKZyJ9&W=ol~)hxuqzvh z(y`%fJ+{D<mwc@*uwoM^qF3g)<cUvb<iR^L*Gb03&iSU&K5lNj#G%E>XLMw(N=;7; z!=vKWb#+&AtnHO=y7oKrJdTudf&U{Q2hrUxf28C$jGkIKK1am1_)HKo1(XM76P`GL zmDZbs{S^D7=L`DHcKG)p=c&8iIN>e-f$*b5ZcLv$R*x@s>T%B?Wka}WuoYx%CkMkT z*~+83;X}mNn+VW~JEx?g@?`d!wUoi}wI~a>kbN?#<JAjco#YNSj9T`{RA_eObL^uP zHCh9iaJF+6*tOLUJMCRIwp-4ydWH0~GGNv-R8EY+JU3PIt=)w8hre-qAf?Xv+cxC} zzT_7hT)%W}2Jns$yP*IEvTu(=dewI<aNZX*VqO+j$c26uPVpX^qHV3saU^V*HkgEL z8VCNg%(O0ZXf7I9)sA(X3GEyABLXlCD&d;bpuV6pp}Y+B4^X%T#6(I$L<p<%1?dC~ zb30obT#C8~lh&(<7d}32-58hs-v0bJ^8KZd7)glE2fmO^YIaEimJjCb2Z+;<DKoT6 zv4yr)rEEz`<@>TB5RG({wr03><?Dt2?(uB7tELEO>v-EqDGALf2;K78uQmPbcT<Wt znAi6?2aGIfbBWWLo*z&@>b3T0wdR0dEqc9nQI8<>z2W!%#s#ZJ&W8Pfe}NJVecsuO z;zjSbtC_(JE06tnJ$u;Od$7atE{|hl5F;@5rdB6u9j#8jOe{vLKulz4B#mDzdZwZ6 z)B`*11{=<5jS9f^>VgpaGAjf^0L^W%Q%{o%+BmD%QGrJzQPE+jS)pBSsBy74r`Ewf z_>9I4dzjaN>7jlLwb1~JOn6JB)5pVJDO<R#!&1IXzYN|;jyyxFNzncNzH<pDHf_Fl zXMU=L60;lQH~kp}B5Wn^b&1<LR$KOLWwhnO|FyFhY<5erwLH$l$weU+8D`aGO7J7e zub#lEg+`1gnh)%`o7nyiFC3k$Dg8D&0D2&c6Ecpt7bUH&+fDZR4^-}o4+^%tq4O@% z@ZIx?&noRuH0tNQZA(8BGIDPtp6T6|YU0=sQyB5^vmf|-k`snx>c%bPT2-P@e+K6z z(ttihM6~_@Y&Uzaz~{yT3d{h5SfVnVuj_WkzI^vBV}L0OB2m%=N^s)NHS)*R&CTWI z>BonFhYKv0G9zKqI<>ekk|l|UNy(zJi!^@|d>jA?Rnod_7ECfUTFi*>k`c6!R1U>G zVBfSNW{2E%6lRZFj#K|8lRo$^gjkR?ze2hb6~ou8)FGp{ApGFw1_p|)Um&9zwrDlh zCm;jgjyGq5X1;HS<?Ip$_-d=m9++hAl>#q+AGW7YJqj0I?n<wC6Q`eDSv-CL_emXp zwz9={H$#){8N+oYR&QkFNh8(`0F7fJI?$rd>5~ABoc})l4u>LaZ3MU5E!MMeYqv0d zXV)m_8uOVyRx`_Iu)d+R;o^Jn8lsm6GO80%fSMgdOYJ3D&mVCgLHSmyUs?Md16oKj z2oAOJ7wMAJ4V?UWHvR0<`Bz@`@Z=-6h4R+gX|akkpO&AFjPDljb22g&RLj}`OYbBm zz_V_)uIM*;WW!s?X~^Vbs>8QNSp~M<@F5X%`k*0^!n4~sS6&bcl>z7olA`Vj2W5Rp z#c1t}$-I(sY{OW)7#WthL_@n*nYt6E=Hk&d`OJz2bLlyY1LExRv%&NR6kku+=_Utb zQd|$T_&oJ;2Pu&1FW1`Kd1nJD>q~a3pJEU>JeB1PplfT~AZzT&mm1W8y4%WgE_v#g zE<4B9WwI##YJFD|;jsSv!4PW*sBpvw(>IZ4R^+WI>M}}ryMWFpR(R^(Rsm$*P5f9E z3{=K@*<P`9!*kN<@LWyK$1>Tp5xU@$aD_?BG|SRA-J&4?4Hb0Z8}Fi1A1Z{F+?ORv zlm=>gtXnBX4f^@Y;6EHVvVnE%I2A~Svj&xL@REUbmSnW3_p<0q3|nTm-Zb~gq*@nT zr!)~BqB3wGAcWx52Z7qJ^MSTrS7_c8Wn2p?`PFzFs>qmIodz(fmK^Ra^MvOP=;=gE zF%HeEW0AsJmRf;Urd9>zx?!}Jb@_jctvB7q>{M}I6ZDYi?8O&pLX(XAOGzW-o#9d& z-gYtp)~#N24w{giBNnRr@srR4Cyu(=XJotbFuX7N)qy@_(|=}~2Bg)@-}KZNsyXPm zN_cd<qxt!f9#yO-OWuapOFn;}@wjL7u|KJ&GGxd^Tk!Y1>IIhuR$r-pzUqlnhg4rV zhlngcbUB%G?Y-)4#W5Lzv_8#zqaNzN9tRh!=4#`HNYdr+CkLw(lX3Zsoy~db+4{tJ zf3d^%?b0J&qivLn?nX>_y3Dm0-Kwjb68<#yGX@h;l9Z|TWnq&w8fVgNDOuXuh_Rt7 zzcCA(SBas+E76Sga4)_+cpSx?kfn9a{PBy=#7Mv*s`v}VS!>`j^JD``WQc{D1{Yqj z=1L5=Ybqu3+i;-8n!h%8iVG(Wr!p=;!8+4aX-0mteLr~O8@mb_+gaYCnd6f}u!l=1 zA=YWou+pZSh1;0_b)pfxLcjP_1%wt!M4oK!Vh6Aw^S97Frb=Q!stYDZCuv%*n<7-9 z4%<kYC<H8U{hm<~h&jVEZ(9~hs3CEBZ$NKdXLSZ`M5psJr9G>z_G>O+KT`yiEBL|Q zE>ZBqk`ybtx~$fYy}h{B`_2MWxB*<}Z%4Txl-u@gn`SvqRA(am*S699*9w`n+BjEW zllosbiX4v_=-L)~2-Wa}4&t;lIwqg&2`U#HHvk+J5!A=dS{xNiPMxXws_W<T<p@6X z4cW6ip^uE_g>=~7l{9#G$w!*i&-4~I(jL0t=Fpr(O7=(8V-DsQ*&fAn<J7YSnUqPa zjY~1OYxA-JM28Z{)YZx)k{;!Y4rA1j1y;`S<r<+CV;zy~eGmxS3y3zvn*G~$j#9%6 z(zQh*h?hzlzvspXi9-9+dpY6SFJ_&kopjN3Q^b}jxJmX0);N@cGdn`$&5wgZ<QK%a z@OXaiZ8jMk55POdLT7D9s!tVVAv^6Zz$H{(=-vj%lGADdT7&T9x1sl;1&_Ul6O=(< zJI!_g#QwU6%3!ePta(tdh3TU)#QsSEXM#UevCf5d+djx-Xa+2(MWS<IPCQC07BXpa z^OTgzJo)|SLBzjMrzIygStn^%mohMHOaV^jE148Va@gX#_qHZ?ct0Ls5U4<AxH5P^ zcw(#WR+^@aA`u>me4|3tw|w7<8&)#tic#|%s3!@e*(aoUY8X*z_unzI482|+P+8Qf zoB_*DXKh8QPsV4};d6J=VTU98x;OZ|EH4D#`WtCmVkdv5@aidD{zNCtVtt$9D=a1` zecUfxIl-)sthg{9Oe?M31!X=`$rWNi0i~nkLO`0abx9BW*)$jWE}s}o^)8x^c#nrN z;0^j%hSRn$aDbdAS^`tI*l%{;StY=|k{v0?J#li4`}y+n3HmqRBA5E~{uLDjgn|zA zA6fB#F10XTTrb8Gfq?uyae(<26?126LmPmFl_QhWKZ}fZHfG@p@{)*fctFqsL6nvf zQv$y0fPjF4z<>cub<H7PK|qK!rNx9*+%hk8VRfR%--u{h$TdYq&@>(Fe{!rU{T|77 z7>(bMOU7SK!N2V4OVV|sk$o(R6QS0&F&^*UH`5=R6IZ$aoJ#ZP>M|QU$y9jXx;pZj zGBe#wGc)bJo0z!kG@E*}EGaHV!^O>e@4}D6CrRk@4@m5A4KF)6YU~Rh{Vw>^WIW6t zv`j7fTbhXJ^i&<(-mX-clJULy?!{!A$C;W|G&q!9xx753?}zkK71`6JB1xBLf@VWl zb#<}a>wWk{&Ud{|V&C^cG_mx#dJ21c5)DHI3R--D%r9I*Sd8Ry>E>EL<nwIx>rLS8 z9Y}3#$mydVAuwumE6P@aAXoulxSYU6il1O6_IA0A!uE%gWLH}WN7JJ#bxy6O6T~Io z6NY2U(5m#mzdn$yw<HkqkK7*Y#|oM^Lm`gDQxpP39WL-#zLxAui2ua@8dgNH+8m98 z`?E;)B$bL1&FpBJgBE)l44bi#rQV$_T4Z^K89kw~LNXQ&8QI~6ltwciiHcFTP2_YT zFP+2QP^*G@?l{-s&dRD3f{1ACCN3_j@cC^XS+q*a_+V^0MMrn^S70K{Or0qrje3mJ ziHLGsOm(w`Xt5kw7LOvP5tnlW1eB6^f1J&VP&!8esJ3=G;yJUiVkW#3xB-DdDjO98 z3cf6l6Y*k2f***(K1`ZGmbt|&mMN6<9rMpwD0Yx&;R-8j@xqn$1XMEWVb{yJp3h?b zUkKQYs^wxQwe_SsJB@1A*7at{UHb>(i>G^%JUfbUpok*q@K}XA&u&@}e(fB#@?*&q z+AVX`EnIYckhdT@;D*CU<$>l6O&lkiSrCwl&Qk#x(s!qe1)xz*8|}smrBQ{6G@>sd zF2ZNIrYtNuOnH1x4!6c*6n&y0UN#g^D42X6ViA}H3GfkcwS%#X5jF<DL9E4f=`%I$ z0XT{NG*CjQL2KHLxuQ)L^JZxXrFBA}ub@gw$4?!uxU5p?R3Z7QGTN+aSQDZsP>Wzs zU{HvpY-V$+h@y(!d~%?H8W_1RJ?|1Fm?5u+az4Jfcjlx^R@7dva5>St2+??o!H|&0 z2x>XrZ^!iJzf<)@UJIp-e{<0yMvlL~HNqFk&da8fU96iOhp{?29e)i$H<_jF&I%}t z8HIhY*?4s%Z5EQ0EKg1~L?Gau^I_BwI-+7n`JrGs7F(e)G_(8qa6$?lJ)&k0s)51J ze?kjlnR|f}7LFjaJfrpPkG>BHg^YspkWB!fS5;-UjctQ*<#r;tTR^wR^|BBhSEuBs zQkw%5Ljb2C3J!A=m;v!N*-$FWJ(<L0dX9Mbpa@X$fJb7PX#JizcSJon0Jn_YfFm+# z{2?ib_UD85o!P)PJ`D3K6PZc9__+T!IA~UyFJ6>`v$OWg)w;-peALRt6CsHB#qwDm zPnR3}`}?XDYHfxms_-KA!rR!9R$JX&X4Bav@>!N^jVE(OvWm>CtV&&LixPM=u&}V6 zkLN7R%)k|0oX92~0%)W!sjMauYlSd_yiUj0=$YS={5dnxu-<HA*p-+CFlkkew|YL? zozDgeqX_w5AI_FdO-&ERQ-;Huek|ME9ZsGt*W?KLeyq3H^7HY@B++sh4MhRpviLn+ z)*3C4kdSmcT)I3SEEmgFft?+XFq)8z`2s7)!op%PUp!f<*)SB1?|QMuAt=~G$nODT z_)y0|tI%jZdv`Q#+t;0eRGO-BK9$7_9C_rQ7Ml$R7Z+fgOLKE;?ap-N=!Lr7UTx|% zdQ5tq&o{$FESp!GU82xNMn-f-^NK$)%q?;Ryn&MxU98{kB;6V{g^a@tvgfta7ySI} z#>?B0M5mt5flMUO>2_lXoGHbv0?AnBa)mmR@#H4UMa$!vJmMCYi!~Awl1eu*u>rMU zi`d$fl$4T^qhtncEP9RWl)gChf%cA$2AN1~rkLb!nOw7oP=#RAIfB@cCPmB$BUl6k z-g`rcalz$hixpH-qMvkXm93snmuzNJeyC(*WbBx9f#vA|&g6W2f1YpleEU!eWAc3Y z50Mn+buth!Xq)Tm+#gOcsY}(W@J{=`jw@?{8X4^k3=D__!{vPn2nZ;|B_?91eF>+h zN@hSf+#QVE>U5uPb2N(z(x`0JOrZK6!sutRgcz<-DD>6Y**Q<y0L9YK+??8C|9YqY z7a31LrUDjq89##lq7Z(x@DPl_J<LOuOD>J`_6M~>t${Foa_QXf-(H^|?>KtLf{hZP zX+v-r26`c2@Ysy>+RauP8XD1f9C1?-f<Avzb;XH*rUGR$08=2#@nZ>sH$cO_Ap(Pj z6=-z70-@QI$PEXR;6VBL`R&OH^7C`w{Qdo#o10gJYV!$roJy_Nn@5V#XmD7f@YBPX zRWPCjV34&yYXcvJ!+Y6FEoO54BO~FZM!$Vo3L_B>X|!5JbKdIlCBn$%N(Kjz8bDe9 zZmlEABmgrr`Em<yNRb~Gu(K1vF!?7v%CC`3G6rUjneaKA-2x3uEHOGV@@%0@nR5xF z5=rDs7WUSb<o(HfNjz&mrUAeV66LrE1nhe@AF3HvM1z%rt+2qW%lQgRxE(Ykj5B9r ztzNCzy(B3X#x}kzN2DPjdBoooP=#4i`q2?=)oD)*45|O_wj+ghLekuXzMbM?k;+x_ z91OE6{4}B21oiv?I<YsE<A%JQkW32$9)ThsEmzwtYm4<;j|0`wbHcsukImPh#GrQZ zGsc>hPWzjo^5vw2bhHKbk<L<XFsL;sZt7%`Q<Fs5#&Ok*igIHlcf4Kiar_IG#jgZD zK5koV-Zkrb>RpTiG-c$@h7$uEpW1gH^KXO)9+jmnA~m_2Z?RWd(_B~H^~?2z2OBM} zq3K9j8s7P>D#3l26Zez#SoJTz4uxj}EwQWKuf~04v1nm8_)vZG-A4}v&EHW7v27G5 z3~d{_c(iz?1^KRg+TTu6N`BQya>T+eQr!!#6R}PrrwKNDT2=nYbgqfOqz$p{@$^AD zAXw6_WGYw2nEgs)3zbRW_n0!z0KM_jHZcw38h$>vUijp120eC~jM$7YRP;^SKcBI) zi+O={;TW3i%xEclneX$@&Ge$HI<z2S_sZk$cwtI1YVuf7`WI^@KZOF`HJ<ilVTNiH z9q*@`EJ^3sicj4v7n8NlwY%zfSHyQ@D?H%B21X<q)@)6FMxy!c^ZTAl(K>;-kHPLi zc%%&z7)=F!r48=vZNNh?6DycTa_xP~^;7r7232{i8YqJ++f!T9(Nquj=YC`Y@;RY_ z7QiXTDR+sO5|8q2E+-l9f^F^2ZJK!=kQVQ7xyU`=S8Oe#=v$~6ZfZ^q*0Q--uF|UX zK)Q&^No!oFV=24Gz!9mSpBLeiG!evXU;)x#Uft&ZGLO8lU!~lLbZ3YrNU@901F2f> z+bYmUQ?>xUKqJ&uC8A}~eK5Qb`zrjpyEdF2ZBhtcqMy0Mm`kuh`D$`I&b@r(wsG%J zwd?WHGj6NAxt7!TT}Ez>q4bTKWfC&j1Md{)^v4;M&o^V59BFr8hH^s!B>hjq&i8Sn z6e4#Yh(NE?L7E{VC|{FvnTd<%LbuWuR+=Pu^=b<R<uHd}W(-=Px1ogy;d50m->p~P zN8NMP^$O*hZx3B(k%<A2$H>G_XjiI>H4!ht$8U^RN$b6Kmk->_@YS}0-PS6dvkl18 zLKLr2ppjmvZPN}!-7F%M9+cSVjI`=m{)yS2j~G1QF?pLYpF9D4lIX)_9L1zvzJnhc zy_KYuxhsQC5f-Qn@f30Tnqd)k^jA3dT&1%=B{W=_*H*-G^KuKcjay``nONi|zyj%z zyFU(J_s0|TDSAZ8q7lD}Og*3O8KD`{hNuMTxutuGd}pJRm#(9=NLrISrFUO^?32s{ z^Bz));1n*kD7E13a_FPTnByEnQ>dtq)1&OV23!n5`!7jU1=ov!BwXfgh=%uSU$A~E zs?Jq_t-+ts4@hQesB|1x7k3QMJPtjIMAw|_doxxWatKxBHyKtBE+AG!Zi;BOr<_%L ztab)l#RUvL)GqGSEGPa3U!6D-qEM30q4a)@`)Ygq3yFxx17dfM;&um|g}qRc#?VN* zLXDg?J{vrPKZB5tS}Ev*unPdrA5S`^nHRt#7u4Iz<&g}JvJd|2*F8FpR7Q&%i~B=F zwk94|+=qmXfsi8-PF!A@x!28Z<MTw?eUJp!(X$FE1$!dlgK)#|jT4d-qha&Vr%Smv zO^-1Q4?a-ix_)~y$+-wBx%|nb{Rz}4+`BeG;)6a&kNiNuj>zpJgZpC?;SiTcVsRM0 zpAwF`YAza0f#kgYRaND&zxXI%V7Z3IWOnu*1EsI`ba6k&S86cAcuyipD^AzV6J6i3 zHSY60)(4qL9=U*v7oDHqW9s-Qhlb3Y_VsF)lz*eniRR|6AcZ`XfLtLQ!yL3+v(}F= z85Y?LT6@kfn~EF-9-c?+Y<WJBMARILs)U_l+CGc}666g?9b?Pg+-8gzX9y;UCrp%; zr!<j@2d!R>L6f9@ogc5KAP{~--Y`gx@E3-M%QyS;cvUh9hAn3QjB)2a5Z35uoo+M; z#{=)@^L}g$Nbl<o7x}sB*4j3E_j71SC5!62Jn#2nC>7e}R+hHx*}IVT`i7j7r}gkG zf_IqbyYCkAP5uXt`6KvGXt;rW)7pKLUPDMNWy<pmmgX``aV^G3#!6gq(mO(w!Qg2a zNDd*1VPRpw=*OU0PcB(l7P`^l8X6QtPC?Pu*0xxquaB<CEi_i8-IAZ5kA{xUfn5YU zmPmt+kN@`Z{uWOmYe`KDEycpd=IH85#OGFfn9uH?ld}aRYgZc`*eEE>_PYa2*dt$F z%;cn{rD@bES9l@WF_L_xa5=43a)krq6B3T5vMTaQzmN^8+lhCh<9)U1)LR`<hkub& zc0d8LPhc4PM@&nPC&hW*TAstU6!d<*FO*K8RjY(Cnj0IF;kUs1`H%0Gk(9>hKAtRW zY^s}uqNPv~{#^YyiTu&h+$^!Z*7PG1i{bYEUgf)ikG3+9+Nl>vL<4zCf1|3lln+@E zkl4&50y&wv;rS5=O@RNWH-opD=a0WV-eRYa{EygbE+zvcA3{PP$sWACypOJw*w`tQ zTYv1uOV_5SnJ6esfHaRnCNT^c>3_G~jV4enVwIxOTy6E}1NkVB!k#Tvo$c)0{CNS& zo{Ar&3jBUCKt5>bX0Y6ByR|t!E}Qf@U;-K~b+S@N7WKo{_KL^(w6(2`-~ARMI`Awn z{2Rwiv0TRW^))7)n$<?T^JF@Qyu3UNuq863-Mzg$Vj#!M1aj-VJb;o?{NdN=MImEj z;|jH^Kkx4><gS;$U!Jynzh`oRe%1o%`YG%}SfXNqM3>tQSUJGTiqGj-fq|ilyRW~X zn}nIOlt6ZUrOs$oupF>ZJ_$1$ml&;o0-?@1s|acz5z^e$N#Xb(GXuO`xu`TiiY<#d z9T4OkOK|f>s5r`Sq--G2XBy~?41dr;^l#VII&EN)AWQE+ZU*S{-Xf!IJMfYL65*Z# zXC`4A?wo+tH-aipScmbKM2Tp;@SM5_Z(E)5Bjs+!|FGX^Da~dpT&reY*UMhJx%v4( z#j}eG-Da!ROv}s&l&w|)*UK**DFQx!o~`(+ln|n&?46z8pKl5p8XCI01rYvZe6_Xt z-TIT?>RemIYYz|L!o<(T_52nma_kuQm6wa_e7yxZ-O$R4-W_kf#s7K8c`yQVwd-E9 z!L*D)L0M@#@E157Jbd6hs6=mM2-u?E^H5Vq2X9A;9&m6>DH9Os@$u>D<pl-c$`0GT z{y;s@SGlB+iwEo()@70F>B4CE`y|`jOkyHpgs;DrhK7O64{90fFk79YkuE29*~5SM zC~&|EIT$Y4*cnJJUrfh0+nr^-$Vs8K(>NR=#pyDSbek-bVq=jTOzNP+W5r6TG!gf) zBGtI2BUw<bH0w;tvNay!&givtb#;FwV`?Y++HF<cI{*Eojsc&5fI%Y}FJcnQAw_)L zW(=;m^7dz#E%<8wJJx@I#DB~<5HbG$xENt5<a4|39T*@_k&-2&ASKNQ>d2ozf6Aq^ zr*S({@<s&OKDNju2V4{R{_*d%?RigTv;IDOdoWJK@4?O+iLDlXJ;-THd2zYX@%Z=% zw6>sbSW{9Bd~OGFbrC$8?(S|NVm;p6jJ}4;0C7i4OKbZWs5!#J!+~7ie7*UiRI$Lx z$!R80Hic0bYy|-Z=C6eNDM(FiK36DBB;X}921Ey-X#8PeadLi6k72P;idtW#)daUu zs#G)vgbdBs7y@36!@gj6eV~E^()Yu|L*VbvfST9Ap}r8Y=kueZmDI#S>T13uHZ3i! zmFe@(U2IFs)Ap}GVTJKzhNFoz$GxHG($Z3(=PN1c_4p9r;o%Vw=mM4I@;QOJKG;Gz z&^P14ln%y{=9iX`;Nd%bKf8gG)YRl0eE+q0v04}3TDQS;G8~-><zlm|qol+PD7=G6 zqcCRffv^G;zpy7Fhb%@zPM5#iq<)eP#}J4<<r2p+S%6ESsu$8<06Tx|2o%Sm2)Lw9 zpoT1*25^N!Fe{zjZ=9Y`R1_w_?g2$R78aK6R=4U6az;o<NH84cD^RQq#}Wb6y9RLN z`Qnj=2sJ=oK2b=fQ7$INPmfGaOHZ$V3QcCz#oO8?{f5^;D<4{1I{|_tyoG>(a2<`8 zv`$<mrHQA4!=1;m%P4fFtgH-AyGaY>U^bDOS5vdqXfY2=0J!G*0QK41)78`U_3>;$ zC~YUR!LdXX4ye6$iw!?8TUCtg)FGF_d2R{R%ghQiG&H+L?z^P)MIH~Qfl!EGu{hTD z?WZW}3$6A>;q2<_>OhRvYO)NE6nfyaUSkLJK?FVA-=8kmOfPUoCm!Fs>a5b_>Kshm zW6QvTh5!L{`|WTtLu3n>?x37vRs{`b$H&Ldg8`>pXfT_G@qSx2PrhB&_pJjd=7&cB zYWpqVq@+k0S;wi6{|pJyoqqOV5*FxhwcleNtWB>qw^@zvVLGHE7Bl(J;kWyn%#;Vk zYWxdFxf*05hE=16Ct$O;6CMEp;}epfO;7}#N{W<?O;LoC9r;n)^b=IjZX4u$w$1VA z<93|Ml0AfuTu#|QuE68#*OtE~CmxA~CYUc4j&_Zq0r!n8{u1I>Wil7<ZXz)0@N0Or z#WrWV+|P9+XyaEVs);Y$A&s<aSgJc1xYfhy;<f&EuJj+uxL~Dg`56$6{rO_Kzyqjp zezxWCw6zo_eHSMuj9WI605#K80cM95+btwV<y}dqi#1G%ud;wb=1hK1wcYbD<r&sG zCbCxAZ^Z-rWVqhA@s}udR(8BunVAN-eSm~#x$R?M+%r$@=<ozuBw($tohq$EJ_-ZJ zcK6RWsmS}3Ra4@F-))X|M2YV(;qYW2qEz-S12l$L;OV5Tv}hz?1KkL~UgO9l(}&YM zDuRY@4aB8?;2GqpELA5s_^`}L`EwvTSE-btIc2=d>7Pp)<dTw+Q7|I(USfu25!lNl zP|A@DAc5aGF?+5?jU$L~+UM7A4S>84y9seHzq66)KK!wOuUaYFc|}Eod7+q^VulPV z-QI(FNvj}D9(^bY8zDh!O=#6Z=yP1C{RR`R@00~}H>xQncbp8XlD}+4Sda7|W7Q!s z(PpC^0F8)*<a2k3=;BbBSn@q*h=*LPt^zQf!wd*WN=mAzI0IUlYV2mKJ$S}4FvrCb zS|?`%q+^tn65Qfe{P_|lMoP5@iB%kpTfcsRB2HB%XlD3&Db=bQA@=+D7aKf<%wpo< z(Z;aK!mi_R_HA}~wpgtyJy7EX?eIGtqcmFrGLw`CmdH4<?VUC|-NlT@Sw!J~*Z~<s z_->nmxuEA;f*+7weBpCLVYs=yT?3ldVugC$AoHCq(9=;-Q3D`HF5`@h29udqf)X(j zgT%vT`&aV8bbu+dMlLuu!0rAh^Uz8}bap8r1zZIJhQYEq@PABc5GFh@KHR7B>FHM- zCT0SpA&oF_Ki;kcnQl5xF>4zd)`4z5p27sobc7Q?bCOg-n11+U)Y7+!B3ab>L1Zvn z%lQul1VF-Lv0JS$^YMLorH|>m583T?L*LYit1^FoeIS98Kyl(~z<@I4m&wPG_!Wf# zZZq8BdR04P;A`T(qH8Vzmv|3!(TAs}Q2&~elF*3M7fCnQ5eiNK9?dn)>*GaaTf|}C zT5uU-4BDh$GpG4XE->Y0Z*QMg6jmh(F`zg>b`QN2v639vZSaRAbVFm1oI$lb(M}nQ z46dgb2(Z^B%=sFi0~d<TAQUtfg}n}#TWd*T;k(#h9@n*83MM%F@kn$A^Gh>HId{m1 z3Q>|*{`w8pt$_e5gF)|UTwI(GM$7qNm%(Aq^HiI`VYqc)XCsA~zv*PUv}r!&2vy-e zF&X(*Tztd72jjp$LU8Bo`ubaih2%Jy-*W^o`}$sj&PfI1z>J_Np}sV-nvC^EVf9(U zPaqfe!Un+OVPHTcOwZ0L!t}2y0$DHd!OPtdo9TofJdfA2oxO&&|BHX(CR|tn9vra7 zKG%N@?jse2T)=~y`{eYrTDt{FZ4|qIz1dn>*G-SY1jvSf2+hO80|aTwqaK{8<m*lu znKGrn2&@Xs-vM)sVydteF`Y7SihK{M+S=L=wWlNfg<-bd6=-S%?x~42(EpiG1oC|! z8~I5lDk^Hb*=b>EIhO6j5L5p&Yl`ijjgikR@p!&!WMI%6UGD!!C?Yy~5{Rw2*ud~U zrpOUTBvsektOsO+-J&8Qi3OI#(+PcQh{YH{dO)v;HpzI)N23q^|HujV>_lK}6qAs! z{PDx}WX=Sb1C1~BV7=p`5xdd<0;KgT59hgUT;*fFzKK7Hq(B=R8^ex2^+fJJnP?mj zCvF}eT^t>abfohC{uk+=r$~HNWMG>$p#OPDe<ju}>|a7cNlAHgbMx`>0gPS@YL%&! zbHLAmI-o+OY_2~P+1be{ATSW<y7BSx^`1{QqYWD>Vge+Cb8|p}LrY0n>~JtfZ2oe4 z(B9tOrw`W<$@d-Z+X^rhoXn)ZIXzti=noOIZ(Uhj<lyG!W@c9S{{1^*8gSZNR`P`d zq3m3O#LUdh<cts9mAaw+>rMXeiQb5FVH7UgAuwABOiL4RI}}Do%f-N70fiK>=M7WI zXHuwkz(l<J-61BmLhtgj>)}M&bT)qmi&02$aBytw^iF?hBv7LiO8rbsOa$iDff~`S zKLil~006zrV18!i8mKImmX@%Y^!V(ydx0Dc9UYxW(5KVu#UbBKel-G<PT>n^9^<2d zDh4tlB1Kz5qI3c!fX~|6T6h@9{+=$@LkDj5h67O{fYN5Y>4)pV7$&o7kxUYh8T?&A z2qp4iW?=!vCN}By1I1?40cs``Ld<|fAo2vt1bwyLL~v02@(uRsAZV999bX!N!)3P} zhDs*j{n`k$;?h#;9V{mxahK2LgXKsQ@aAbhIyqTwwqC!!wgZ}Xsj7nmE3XfUfJ3eM zZ2t4}GjL@h03I3|`j|L^Nwa?cD90D*HH@rbkp=lWk`Z=R+t`pAIJ9KOcB(>Q^~<b4 zMj1h!O)`ZROUNH#yHjTgq+AX4^`yAd<mamm!z(MP!4!jz1T@@8J56M0PNxer4WutQ z7#wkDQWn6amZG8q;Mjq(E<$)H*?$sJRtQK3fo8<A!%|W^woSXFh$YlK7>NxO^eVt# z0dEt19S~Z8psqm)%qjoMW{wr3-_*#KlamV!2&gv~ttK1X*zg9@#TBMHP{8o}!?OO3 z_wE2J4mMD?_O;~X5Iw5sL`O%PfEusVn~dj)hE7aO)Q<a+kuO!KUjcRQ`RKQmS`B$` zZ|`%~zV%ozFt8Qda1EX7$!2SqQRhN~jzNboRMV2z+F1i+Fw|Os%*@Q%Smr$nRZx=k zAXs#R)Vfca+JW9)A!;cgn_m4<tFa3t%z2bRH$EpBskH&Nwlb2Lm9^TOg)a>XL~wY> zUt%*$OA?|$uB_YR^Im5(EW(j1cAi$=x>hWQPqLoH>zXa#z1HLFyTVG3I&ZyF3rJO{ zHH7d_O{&%JWqJ;ngYBW{Ye#Lij)yNn9&N=%RuqcQ)9>*Sk;lR*@FSlc91NyYh?~z9 z27lBht<)=Qum(Pfrqs<(zTW(Q6Yc+x{{62Pzdk`Zvl$&8rAOz0YwaM?;__nEA_f8f zzPs(8>-c}a`R4&#$_Ej(wK26Yb9VT*&619+OcvGvGZRN95ep}4fSn`Le_t8zUsSfU zwR5%uZm)FyU)FQ7wY9PX*qB)TFY7rv0i2v24FL}SL%lEms-F(FW)3Ef{~tB~KIZUW zr{`}^|L6bvSGE35$^X8Vsg*6j$>g77`&au@ss2R|0Y*k9RwlsvY3smb<m}+^k4-V) zz~?!j|L$i6`THQo-{aqJ?Z0aF@5398PVQDF|Gwu@N85If6U%2yA7I`*h@c>jy)Jh? zgoH(n^;WBl!DgWkFOhFzL!p>k%5_q+C90I@+)~LE&L)R9p|Zcz=5utdP~_o#hZ3CN zIiV!7m$aj^G6XS9_#pkIGHT1_(^?Pr>zS|4{A7rm+lew$q}{}1qF@MDR_`vCZuw}^ z&pJ10MVUF1DAG*Eww6NJn1_6mG!Gi_GSpG4V+Uy+y~!JJqIQiLwWa)yop=g+_onF? zn`1*^cmW2ct(m+?qPdyh3iAbu0bFGkHz@JX(@Av)e41KIHZ2`1a!l0l^k#J$8V=10 zD|E;4QNi(JPxN05N$8t0;fLoMQ4h^aeFB;*l`_R$QxRPdcS}(hgLW{adUgEA0a0T= zXrJ4Wp$g6fj_n#+#I2a8$n7y{m3_HXihbOzgPxnoy49D=QWJf>KCTGW>G5b~XVi2K zSmF^ll@(K#m1W>n2f>ogm2{Vz&5}JB6|X!-U8C$KWcKx#+CoKYuDPPuGNGJeATcPr zvE!B(zTs?)y4$d1Dh$DkbM{9PxD7KXIgc0A@~RG2QX-~awZsSTD8tWT#Se8-xjp46 zjlaJ4)RHT<`8+V%S;@{|(12WSU~6Mxtp5rzt*e=n=LQ!fPeo-37HPB6+))^<V9&bc z6t(TqFr32Rz%N(owoYuOUDi1Bwh#q;Un54&5P0l!@~%3SX5mwu7HLbmVUkcd#z7x( zmP7q{&62}Rnbc%BgkXno2=X{bAg$bgdgKcqQj(y5ZF3teL2ZM2&o5*CsvIqkD4^Tf zY*^`R5)ovFY&p#z&;-UMD%P=QELi+S@;mAW+XvAre}<R1{o2Vb+9Zmrpk|47WAIFK zsq!~I)%L|C(3e)rg~nuo&0PA4^{<oM>e9(j^ZfvG^V|2hH0DyID0HDp(}SNdzr<if z=96|Vy?+vifQ7_cJ7U^F?69+V$2(v|R?l{)Cb;!z6nZ*lvDXA#A?k)uBe7!i;=~;I zK|6=B)gH9eNO<SLHsK9YM2%TYicEhzT<4ZJn0inav)Hg=c8P=$@vLIqF+@djk7^Cn zQ%IftSp0UtuS(%CM%1$+5p5nXC{E5PJz)=W=7olW1aK(K#ma_6W->yE0g1KF|Kj;r zQFYN;LbBjBE9jUEC<y*#<RmFtCC8za-i%TAAP7HbNzZfsL!@@gfghhao#NJy43mkw z(DF?o1xI%!DGq_gsgH;gAKxdaGP5LCHzU~i<vE1E^b1N}A&C1q`eNr+0dqf*pf}NV zjvAz!LVQr0;3Qltl4M|i_bMK&SsgUVagIHV@JA{UizpuS0}lPVQJf(_1RJ~}ZyfNT z({WAY#_)(TOc^Z)$1q8W5q%96Y(W#-%x-kTY%)Eobz~AS3u$uXx4ZGMV879IS|*tr zNl}}U{$93sUp&>w3V*?p=(QpmqHdy}Th#Q2YbuGQQv`#=pTSDov3v2-i-;eI%xfTw zKxk$&N;sK8LSsp#rC>}3`<o0KF5DBOH3&H1%6wgBaeL4jzpRc8%WV2=e+tbw@|%F( zfmvBcf(sNiYl69PFyvkFk>O^k^})+Ko2T4o)Pnm*vC*25lfK2v&7YQ9P;-86C#`bb z?^|F#ou_=+1Xo)hKEs6GD#wn-w#ZJs_o$RIc|_}E_h^T{<>3OOG%|VH3Zko56N6jW zl9CUZWYh0kg!@?EgMTl$vy4Rhj^FUbWyDxi4(}ba9||JJki%t%kUd>R78J<yGHJF? z;W=D_j6C#!x)g8J48}t1UMyBQW8t5ae%;$nL04~9f0$(3v0c%=63x!;A*<bBs!>Pp z5wD&44z@JD41IQIvuX71KzMLl*>X0XKzyCZB-2d+LHK}mKtFb%8Te36RB36=h9Ou% zM?C1AV6X0kqv{Hf!-yx|++wpp)@CesnH}PGIvS+e(BU>%#Lj%gPnsqV!*rdPEEn}) zrox=qDnLV`^i0nopE4wBh#SzDFJve8fgX){-ko9?<GRQlL1hdc^Zg1(;F1cV-OUQp z|4}z(FX>)#s^QMj7&5Rba49$Y`Ah2elc1b|$2GMsb)9)JyV36LatOw9K8`#y+Efri zOj|eNtZx~DPPbV*E1yP~=GOuE#JC=z<~yUlXvTd$hSWC6EJen}9WKVfJ)zQ`+6)=3 zrV7880uWb-NPgw-=FwnQA;&*WI}PWL$Q`1v@{{pIG~oIJ#1{F(5T4@)H0=ZBb<Uyi zC&ONM1wEM)wl4acA)(K|Zzt6u7NP8DeG}i<I<&86`aSq3zVyux)ev+d*p1AzJdnPm zCT3G{YH-m0txr#9a-mDCLc2mIYk4MdzEE|tTt<yd2fXhb3H~l4JTJAQU;<mniODn) zf*xzo_x4w^U_7yK_v<li@@h(qUPz~)_#Vnz`>yY`)y?;vd^E^L3Q!x6V!-9P&_Wx} z1;leUVP8ulJ@uL&ox5lo&f=v@VHfumJ?mf#d)Rm~+tE}mJ_ili8*<u!IynOB=I+yY z#keMRT!y2&j<%_jU1XUT+cnBLX=Z>=^ZSM;fe*N|8)qd_j^HB{JH*vB-*-1o&-Lk+ z$!4tA^QnR~yh$ZRd83@miT5<=9(x)Fh}m7QqV><)L_XIW1}pquYAt66HLQsS>4(Ek zZynOOGDU&bd*D@TZN1jq*aM`$7R;!W<lDu&TN^eMa_y&7FdpuL4%L<9rIz(Gs0qdr zZv7OzBIh(JpC3_FVlO9c7c4z65(&~11@wSRDDrde%of>Vx8X2FkW!I%(gM`AYfn>! zI;`4A%(U-I%eRr&<e$77hLxquU%!4`R`X^ilC~VxlePGn^-3*22jOJ?#Z>hXbIupD zc^~<Ww9Tclb527Pa<V*rsf$(vQIOE#BIVE7GU0SP;`AZ3%9pUcGKFI)v+n}5Jo0WD zl#0_icrm3?<p`r=8VQUxOU~U)_R-S9#$(IgGvMn}3r;%o{)|h_3@<;{+pq%c-uuPq zz7Uu)TuB~QLXs(eZ1OZ5ICW?8iVP`zV5zn2)L3p;_&XRT!5;ALJ{T%esu<OP=>dk- zZ~hE>-3_bz*BE||t!6m)(W=sImO#@=2N+@=JKPU0x$BgndS&al=n1#T;4S$%E5HYL z*2e)nkSnt;JcwWizXIe4gO&HAc&W{PZ)T=-9Zh&nWp;2-O{AUVW~O!jz4U6}Hfka| zsC@j)TY3HbOVr9h!HDc(K|tcZ{h#4$sEGm_YQC-^j=G+HZu+^2d6{Xc#o#T_Yl9DF z9X8<E`(3-~{l@L{+A?n)PKduy+wfdt<-uvas?)!{pDuE%q^GCtt6JoxYJZ!`&DN~( zvWk<tZ*+wJRMK*gj&842w)-ysb@q+i@Yx9$N*&g$cQietc=wXqlpZUoq9qqu6wZbn zXSv}P&7|;p{@-7RN>0CHS#z{3)VF5t=K%iCKW$3OkN&ojv@>x!+vsziF)BUFPCcW= z^Q3ilMMkiD&QsS7d#-D0rW)wVGDNIU4Px3b@$fX`D?I99$(4c{jGq%&ZDnt`Jt@4K z{`eigYR$sJc_Q)7GdIjvEIjyS!LeUT)4q4ieeJ!^!ZSN{4J*I1)aFg9&-a`EmcQP- z+?CaxbCX5pdqJ^Z=hON7ckK_{zwhNYX;7$Uu(4(f0}uUp$P5ZqMkWyk+-J#vn#c$M zJ6Q&%3)XB#K1KxGx`t~B0kVLn(SXm6LDz-6tsQj42m*uxTj$6Jj-cyAUZ4%y_KpC* z*-<vZ!!*MBedz1A5gM~4aj)h^HwB>!xQrW_!(eQQ*;&HqOQME2vVKr+5&;UZ7>3-p zB-Wf2Sj<80YZ7bD11#ns_dRi&1L}PufP@uhAQhnWMRA)1>Q^E_5EhdVeN$ph>A+$N zqOVG<Df_UPg6O+KOo8PWkPl!TP*Cp`0lr`{1xH^NmMUR}A{UmRzAFNFTO;>m(e)u0 f2cV)90lv84C|Co$S=m6!1c1;Ccyy4L8;A!0aKEs! literal 0 HcmV?d00001 diff --git a/docs/tables/Makefile.am b/docs/tables/Makefile.am new file mode 100644 index 00000000..0e79576f --- /dev/null +++ b/docs/tables/Makefile.am @@ -0,0 +1,80 @@ +## automake.am +## +## docs/tables/automake.am for Rivendell +## +## (C) Copyright 2002-2006 Fred Gleason <fredg@salemradiolabs.com> +## +## $Id: Makefile.am,v 1.16.8.5.2.1 2014/06/03 18:23:34 cvs Exp $ +## $Date: 2014/06/03 18:23:34 $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +EXTRA_DIST = audio_perms.txt\ + audio_ports.txt\ + cart.txt\ + cartslots.txt\ + clipboard.txt\ + clock_perms.txt\ + copy_splits.txt\ + cuts.txt\ + decks.txt\ + dropboxes.txt\ + dropbox_paths.txt\ + dropbox_sched_codes.txt\ + encoder_bitrates.txt\ + encoder_channels.txt\ + encoder_samplerates.txt\ + encoders.txt\ + extended_panel_names.txt\ + feed_perms.txt\ + gpis.txt\ + gpos.txt\ + groups.txt\ + isci_xreference.txt\ + jack_clients.txt\ + livewire_gpio_slots.txt\ + log_format.txt\ + log_modes.txt\ + logs.txt\ + nownext_plugins.txt\ + panels.txt\ + panel_names.txt\ + rdairplay_channels.txt\ + rd_airplay.txt\ + rd_catch.txt\ + rd_library.txt\ + rd_logedit.txt\ + rdpanel_channels.txt\ + recordings.txt\ + repl_cart_state.txt\ + repl_cut_state.txt\ + replicator_map.txt\ + replicators.txt\ + services.txt\ + sources.txt\ + stations.txt\ + svc_rec_format.txt\ + triggers.txt\ + ttys.txt\ + user_perms.txt\ + users.txt\ + version.txt\ + vguest_resources.txt\ + web_connections.txt + +CLEANFILES = *~ +MAINTAINERCLEANFILES = *~ Makefile.in diff --git a/docs/tables/audio_perms.txt b/docs/tables/audio_perms.txt new file mode 100644 index 00000000..f632e113 --- /dev/null +++ b/docs/tables/audio_perms.txt @@ -0,0 +1,12 @@ + AUDIO_PERMS Table Layout for Rivendell + +The AUDIO_PERMS table holds data concerning which audio services are +are allowed to air which GROUPS. Following is the layout of a record +in the AUDIO_PERMS table: + + +FIELD NAME TYPE REMARKS +--------------------------------------------------------------- +ID int(10) unsigned Primary key, auto increment +GROUP_NAME char(10) Index +SERVICE_NAME char(10) Index diff --git a/docs/tables/audio_ports.txt b/docs/tables/audio_ports.txt new file mode 100644 index 00000000..d8a1c0b7 --- /dev/null +++ b/docs/tables/audio_ports.txt @@ -0,0 +1,62 @@ + AUDIO_PORTS Table Layout for Rivendell + +The AUDIO_PORTS table holds data concerning which configuration of the +physical audio interfaces. Following is the layout of a record +in the AUDIO_PERMS table: + + +FIELD NAME TYPE REMARKS +--------------------------------------------------------------- +ID int(10) unsigned Primary key, auto increment +STATION_NAME char(64) +CARD_NUMBER int(11) signed +CLOCK_SOURCE int(11) signed 0 = Internal, 1 = AES/EBU, + 2 = SP/DIFF, 3 = Word Clock +INPUT_0_TYPE int(11) signed 0 = Analog, 1 = AES/EBU, + 2 = SP/DIFF +INPUT_0_LEVEL int(11) signed Gain offset, in 1/100 dB +INPUT_0_MODE int(11) signed 0 = Normal, 1 = Swap, + 2 = Left Only, 3 = Right Only +INPUT_1_TYPE int(11) signed 0 = Analog, 1 = AES/EBU, + 2 = SP/DIFF +INPUT_1_LEVEL int(11) signed Gain offset, in 1/100 dB +INPUT_1_MODE int(11) signed 0 = Normal, 1 = Swap, + 2 = Left Only, 3 = Right Only +INPUT_2_TYPE int(11) signed 0 = Analog, 1 = AES/EBU, + 2 = SP/DIFF +INPUT_2_LEVEL int(11) signed Gain offset, in 1/100 dB +INPUT_2_MODE int(11) signed 0 = Normal, 1 = Swap, + 2 = Left Only, 3 = Right Only +INPUT_3_TYPE int(11) signed 0 = Analog, 1 = AES/EBU, + 2 = SP/DIFF +INPUT_3_LEVEL int(11) signed Gain offset, in 1/100 dB +INPUT_3_MODE int(11) signed 0 = Normal, 1 = Swap, + 2 = Left Only, 3 = Right Only +INPUT_4_TYPE int(11) signed 0 = Analog, 1 = AES/EBU, + 2 = SP/DIFF +INPUT_4_LEVEL int(11) signed Gain offset, in 1/100 dB +INPUT_4_MODE int(11) signed 0 = Normal, 1 = Swap, + 2 = Left Only, 3 = Right Only +INPUT_5_TYPE int(11) signed 0 = Analog, 1 = AES/EBU, + 2 = SP/DIFF +INPUT_5_LEVEL int(11) signed Gain offset, in 1/100 dB +INPUT_5_MODE int(11) signed 0 = Normal, 1 = Swap, + 2 = Left Only, 3 = Right Only +INPUT_6_TYPE int(11) signed 0 = Analog, 1 = AES/EBU, + 2 = SP/DIFF +INPUT_6_LEVEL int(11) signed Gain offset, in 1/100 dB +INPUT_6_MODE int(11) signed 0 = Normal, 1 = Swap, + 2 = Left Only, 3 = Right Only +INPUT_7_TYPE int(11) signed 0 = Analog, 1 = AES/EBU, + 2 = SP/DIFF +INPUT_7_LEVEL int(11) signed Gain offset, in 1/100 dB +INPUT_7_MODE int(11) signed 0 = Normal, 1 = Swap, + 2 = Left Only, 3 = Right Only +OUTPUT_0_LEVEL int(11) signed Gain offset, in 1/100 dB +OUTPUT_1_LEVEL int(11) signed Gain offset, in 1/100 dB +OUTPUT_2_LEVEL int(11) signed Gain offset, in 1/100 dB +OUTPUT_3_LEVEL int(11) signed Gain offset, in 1/100 dB +OUTPUT_4_LEVEL int(11) signed Gain offset, in 1/100 dB +OUTPUT_5_LEVEL int(11) signed Gain offset, in 1/100 dB +OUTPUT_6_LEVEL int(11) signed Gain offset, in 1/100 dB +OUTPUT_7_LEVEL int(11) signed Gain offset, in 1/100 dB diff --git a/docs/tables/cart.txt b/docs/tables/cart.txt new file mode 100644 index 00000000..093c6ad5 --- /dev/null +++ b/docs/tables/cart.txt @@ -0,0 +1,52 @@ + CART Table Layout for Rivendell + +The CARTS table holds data concerning all of the available events +in a Rivendell system that are capable of being individually +scheduled. Following is the layout of a record in the CARTS table: + +FIELD NAME TYPE REMARKS +-------------------------------------------------------------------------- +NUMBER int(10) unsigned Primary key +TYPE int(10) unsigned 1 = Audio, 2 = Command, 3 = Split +GROUP_NAME char(10) Index +TITLE char(255) Index +ARTIST char(255) Index +ALBUM char(255) Name of release album +YEAR date Year of release +ISRC char(12) RETIRED as of DB v100 +CONDUCTOR char(64) +LABEL char(64) Release Record Label +CLIENT char(64) Index +AGENCY char(64) Index +PUBLISHER char(64) Index +COMPOSER char(64) Index +USER_DEFINED char(255) For use by local user +SONG_ID char(32) +BPM int(10) unsigned Beats per minute +USAGE_CODE int(11) 0=Feature, 1=Theme Open, + 2=Theme Close, 3=Theme Open/Close, + 4=Background, 5=Comm/Promo +FORCED_LENGTH int(10) Playout this length, 0 = don't timeshift +AVERAGE_LENGTH int(10) +LENGTH_DEVIATION int(10) Maximum variation of underlying cuts +AVERAGE_SEGUE_LENGTH int(10) +AVERAGE_HOOK_LENGTH int(10) +CUT_QUANTITY int(10) > 1 for rotators +LAST_CUT_PLAYED int(10) Offset for rotators +PLAY_ORDER int(10) 0 = Sequence, 1 = Random +VALIDITY int(10) 0 = Always invalid, 1 = Conditionally + valid, 2 = Always valid, 3 = Evergreen +START_DATETIME datetime +END_DATETIME datetime +ENFORCE_LENGTH enum('N','Y') Timeshift? +PRESERVE_PITCH enum('N','Y') Preserve Pitch? +ASYNCRONOUS enum('N','Y') +OWNER char(64) From LOGS.NAME or STATIONS.NAME +MACROS text RML Macros +NOTES text User notes (freeform) +METADATA_DATETIME datetime Metadata last modified +USE_EVENT_LENGTH enum('N','Y') Use RDLogManager event lengths for + macro cart PAD updates. +PENDING_STATION char(64) +PENDING_DATETIME datetime +PENDING_PID int(11) diff --git a/docs/tables/cartslots.txt b/docs/tables/cartslots.txt new file mode 100644 index 00000000..f9e79eaf --- /dev/null +++ b/docs/tables/cartslots.txt @@ -0,0 +1,23 @@ + CARTSLOTS Table Layout for Rivendell + +The CARTSLOTS table holds data concerning configuration of RDCartSlot +decks in a Rivendell system. Following is the layout of a record in the +CARTS table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------------ +ID int(10) unsigned Primary key, Auto Increment +STATION_NAME char(64) From STATIONS.NAME +SLOT_NUMBER int(10) unsigned +MODE int(11) signed 0=Cart Deck, 1=Breakaway +DEFAULT_MODE int(11) signed -1=Previous, 0=Cart Deck, 1=Breakaway +STOP_ACTION int(11) signed 0=Unload, 1=Recue, 2=Loop +DEFAULT_STOP_ACTION int(11) signed -1=Previous, 0=Unload, 1=Recue, 2=Loop +CART_NUMBER int(11) signed +DEFAULT_CART_NUMBER int(11) signed -1=Previous, 0=None, >0=Cart +HOOK_MODE int(11) signed +DEFAULT_HOOK_MODE int(11) signed -1=Previous, 0=Off, 1=On +SERVICE_NAME char(10) From SERVICES.NAME +CARD int(11) signed +INPUT_PORT int(11) signed +OUTPUT_PORT int(11) signed diff --git a/docs/tables/clipboard.txt b/docs/tables/clipboard.txt new file mode 100644 index 00000000..0e33af53 --- /dev/null +++ b/docs/tables/clipboard.txt @@ -0,0 +1,34 @@ + CLIPBOARD Table Layout for Rivendell + +The CLIPBOARD table holds data concerning the audio cut in the clipboard. +The layout is a duplicate of the CUTS table. Following is the +layout of a record in the CLIPBOARD table: + +FIELD NAME TYPE REMARKS +--------------------------------------------------------------- +CUT_NAME char(12) * Primary key, Base name of WAV file +CART_NUMBER int(10) unsigned Parent Cart Entry, Indexed +DESCRIPTION char(64) Indexed +OUTCUE char(64) Indexed +LENGTH int(10) unsigned Overall length in ms. +ORIGIN_DATETIME datetime Date/Time when recorded +ORIGIN_NAME char(64) Workstation ID where recorded +WEIGHT int(10) unsigned Relative airplay frequency, 1 = normal +LAST_PLAY_DATETIME datetime +PLAY_COUNTER int(10) unsigned +CODING_FORMAT int(10) unsigned 0 = PCM16, 2 = Layer-2, 3 = Layer-3 +SAMPLE_RATE int(10) unsigned In samples/sec +BIT_RATE int(10) unsigned In bits/sec, PCM16 = 0 +CHANNELS int(10) unsigned 1 = mono, 2 = stereo +START_POINT int(10) unsigned Offset to Start point in ms +FADEUP_POINT int(10) unsigned Offset to FadeUp point in ms +FADEDOWN_POINT int(10) unsigned Offset to FadeDown point in ms +END_POINT int(10) unsigned Offset to End point in ms +HOOK_START_POINT int(10) unsigned Offset to Hook Start point in ms +HOOK_END_POINT int(10) unsigned Offset to Hook End point in ms +TALK_START_POINT int(10) unsigned Offset to Talk Start point in ms +TALK_END_POINT int(10) unsigned Offset to Talk End point in ms + + + +* Should always be 'clip.wav'. diff --git a/docs/tables/clock_perms.txt b/docs/tables/clock_perms.txt new file mode 100644 index 00000000..1ed682a7 --- /dev/null +++ b/docs/tables/clock_perms.txt @@ -0,0 +1,12 @@ + CLOCK_PERMS Table Layout for Rivendell + +The CLOCK_PERMS table holds data concerning which clocks in RDLogManager are +are associated with which services. Following is the layout of a record +in the CLOCK_PERMS table: + + +FIELD NAME TYPE REMARKS +--------------------------------------------------------------- +ID int(10) unsigned Primary key, auto increment +CLOCK_NAME char(64) Index +SERVICE_NAME char(10) Index diff --git a/docs/tables/copy_splits.txt b/docs/tables/copy_splits.txt new file mode 100644 index 00000000..098dd5cb --- /dev/null +++ b/docs/tables/copy_splits.txt @@ -0,0 +1,14 @@ + COPY_SPLITS Table Layout for Rivendell + +The COPY_SPLITS table holds data concerning the National=>Regional +copy mapping for the copy-split subsystem. + + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------- +ID int unsigned(10) Primary key +SLOT int unsigned(10) +CART_NUMBER int unsigned(10) From CART.NUMBER +ISCI_CODE char(32) +DESCRIPTION char(255) +FILENAME char(64) diff --git a/docs/tables/cuts.txt b/docs/tables/cuts.txt new file mode 100644 index 00000000..8beaa9b0 --- /dev/null +++ b/docs/tables/cuts.txt @@ -0,0 +1,63 @@ + CUTS Table Layout for Rivendell + +The CUTS table holds data concerning each individual audio cut on the +system, as opposed to CART (where individual entries may reference +more than one cut, as in the case of rotators). Following is the +layout of a record in the CUTS table: + +FIELD NAME TYPE REMARKS +--------------------------------------------------------------- +CUT_NAME char(12) * Primary key, Base name of WAV file +CART_NUMBER int(10) unsigned Parent Cart Entry, Indexed +EVERGREEN enum('N','Y') +DESCRIPTION char(64) Indexed +OUTCUE char(64) Indexed +ISRC char(12) International Standard Recording Code +ISCI char(32) ISCI Code +LENGTH int(10) unsigned Overall length in ms. +ORIGIN_DATETIME datetime Date/Time when recorded +START_DATETIME datetime +END_DATETIME datetime +START_DAYPART time +END_DAYPART time +SUN enum('N','Y') +MON enum('N','Y') +TUE enum('N','Y') +WED enum('N','Y') +THU enum('N','Y') +FRI enum('N','Y') +SAT enum('N','Y') +ORIGIN_NAME char(64) Workstation ID where recorded +WEIGHT int(10) unsigned Relative airplay frequency, 1 = normal +LAST_PLAY_DATETIME datetime +UPLOAD_DATETIME datetime Copy-split upload timestamp +PLAY_COUNTER int(10) unsigned +LOCAL_COUNTER int(10) Resets when cart structure changes +VALIDITY int(10) 0 = Invalid, 1 = Conditionally Valid, + 2 = Valid +CODING_FORMAT int(10) unsigned 0 = PCM16, 2 = Layer-2, 3 = Layer-3 +SAMPLE_RATE int(10) unsigned In samples/sec +BIT_RATE int(10) unsigned In bits/sec, PCM16 = 0 +CHANNELS int(10) unsigned 1 = mono, 2 = stereo +PLAY_GAIN int(11) signed In 1/100 dB +START_POINT int(10) unsigned Offset to Start point in ms +FADEUP_POINT int(10) unsigned Offset to FadeUp point in ms +FADEDOWN_POINT int(10) unsigned Offset to FadeDown point in ms +END_POINT int(10) unsigned Offset to End point in ms +HOOK_START_POINT int(10) unsigned Offset to Hook Start point in ms +HOOK_END_POINT int(10) unsigned Offset to Hook End point in ms +TALK_START_POINT int(10) unsigned Offset to Talk Start point in ms +TALK_END_POINT int(10) unsigned Offset to Talk End point in ms + + +* Names of WAV files are calculated as follows: + + CCCCCC_NNN.wav + + where: + CCCCCC = The cart number (000000 - 999999) + NNN = The rotator offset (000 - 999) + + Thus, we can accomodate up to 1000 cuts in a single rotator. The + base name is that part of the name prior to '.wav'. + diff --git a/docs/tables/decks.txt b/docs/tables/decks.txt new file mode 100644 index 00000000..ce30803d --- /dev/null +++ b/docs/tables/decks.txt @@ -0,0 +1,26 @@ + DECKS Table Layout for Rivendell + +The DECKS table holds data concerning each configured netcatcher +recording interface on the system. Following is the layout of a +record in the DECKS table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------ +ID int(10) unsigned Primary key, auto increment +STATION_NAME char(64) From STATIONS.NAME +CHANNEL int(10) unsigned 0 = Audition Channel +CARD_NUMBER int(11) signed -1 = None Assigned +STREAM_NUMBER int(11) signed -1 = None Assigned +PORT_NUMBER int(11) signed -1 = None Assigned +PORT_TYPE enum('A','D') A = Analog, D= Digital +MON_PORT_NUMBER int(11) signed +DEFAULT_MONITOR_ON enum('N','Y') +DEFAULT_FORMAT int(10) signed +DEFAULT_CHANNELS int(10) signed +DEFAULT_SAMPRATE int(10) signed RETIRED +DEFAULT_BITRATE int(10) signed +DEFAULT_THRESHOLD int(10) signed +SWITCH_STATION char(64) From OUTPUTS.STATION_NAME +SWITCH_MATRIX int(11) From OUTPUTS.MATRIX +SWITCH_OUTPUT int(11) From OUTPUTS.NUMBER +SWITCH_DELAY int(10) unsigned diff --git a/docs/tables/dropbox_paths.txt b/docs/tables/dropbox_paths.txt new file mode 100644 index 00000000..53a67924 --- /dev/null +++ b/docs/tables/dropbox_paths.txt @@ -0,0 +1,11 @@ + DROPBOXES_PATHS Table Layout for Rivendell + +The DROPBOXES_PATHS table holds timestamps for 'persistent' dropbox files. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------- +ID int(11) Primary Key, Not Null, Unique + Auto-Increment +DROPBOX_ID int(11) From DROPBOXES.ID +FILE_PATH char(255) +FILE_DATETIME datetime diff --git a/docs/tables/dropbox_sched_codes.txt b/docs/tables/dropbox_sched_codes.txt new file mode 100644 index 00000000..0e84faa7 --- /dev/null +++ b/docs/tables/dropbox_sched_codes.txt @@ -0,0 +1,11 @@ + DROPBOX_SCHED_CODES Table Layout for Rivendell + +The DROPBOX_SCHED_CODES table holds the scheduler codes to be applied for +each dropbox. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------- +ID int(11) Primary Key, Not Null, Unique + Auto-Increment +DROPBOX_ID int(11) From DROPBOXES.ID +SCHED_CODE char(11) diff --git a/docs/tables/dropboxes.txt b/docs/tables/dropboxes.txt new file mode 100644 index 00000000..40b4ffee --- /dev/null +++ b/docs/tables/dropboxes.txt @@ -0,0 +1,28 @@ + DROPBOXES Table Layout for Rivendell + +The DROPBOXES table holds data concerning dropbox 'services'. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------- +ID int(11) Primary Key, Not Null, Unique + Auto-Increment +STATION_NAME char(64) From STATIONS.NAME +GROUP_NAME char(10) From GROUPS.NAME +PATH char(255) +NORMALIZATION_LEVEL int(11) +AUTOTRIM_LEVEL int(11) +SINGLE_CART enum('N','Y') +TO_CART uint(10) +USE_CARTCHUNK_ID enum('N','Y') +TITLE_FROM_CARTCHUNK_ID enum('N','Y') Set Rivendell cart title from cartchunk cutid. +DELETE_CUTS enum('N','Y') +DELETE_SOURCE enum('N','Y') +METADATA_PATTERN char(64) +STARTDATE_OFFSET int(11) +ENDDATE_OFFSET int(11) +FIX_BROKEN_FORMATS enum('N','Y') +LOG_PATH char(255) +IMPORT_CREATE_DATES enum('N','Y') +CREATE_STARTDATE_OFFSET int(11) +CREATE_ENDDATE_OFFSET int(11) +SET_USER_DEFINED char(255) diff --git a/docs/tables/encoder_bitrates.txt b/docs/tables/encoder_bitrates.txt new file mode 100644 index 00000000..eb836f70 --- /dev/null +++ b/docs/tables/encoder_bitrates.txt @@ -0,0 +1,11 @@ + ENCODER_BITRATES Table Layout for Rivendell + +The ENCODER_BITRATES table holds data concerning the allowed bit rates +in bits/sec for each custom encoder format on the system. +Following is the layout of a record in the ENCODER_BITRATES table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------- +ID int(11) +ENCODER_ID int(11) From ENCODERS.ID +BITRATE int(11) diff --git a/docs/tables/encoder_channels.txt b/docs/tables/encoder_channels.txt new file mode 100644 index 00000000..215acf24 --- /dev/null +++ b/docs/tables/encoder_channels.txt @@ -0,0 +1,11 @@ + ENCODER_CHANNELS Table Layout for Rivendell + +The ENCODER_CHANNELS table holds data concerning the allowed channel +count for each custom encoder format on the system. +Following is the layout of a record in the ENCODER_CHANNELS table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------- +ID int(11) +ENCODER_ID int(11) From ENCODERS.ID +CHANNELS int(11) diff --git a/docs/tables/encoder_samplerates.txt b/docs/tables/encoder_samplerates.txt new file mode 100644 index 00000000..4594dd2b --- /dev/null +++ b/docs/tables/encoder_samplerates.txt @@ -0,0 +1,11 @@ + ENCODER_SAMPLERATES Table Layout for Rivendell + +The ENCODER_SAMPLERATES table holds data concerning the allowed +sample rates in samples/sec for each custom encoder format on the system. +Following is the layout of a record in the ENCODER_SAMPLERATES table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------- +ID int(11) +ENCODER_ID int(11) From ENCODERS.ID +SAMPLERATE int(11) diff --git a/docs/tables/encoders.txt b/docs/tables/encoders.txt new file mode 100644 index 00000000..4eda566b --- /dev/null +++ b/docs/tables/encoders.txt @@ -0,0 +1,13 @@ + ENCODERS Table Layout for Rivendell + +The EVENTS table holds data concerning each custom encoder format +on the system. Following is the layout of a record in the ENCODERS +table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------- +ID int(11) +NAME char(32) +STATION_NAME char(64) From STATIONS.NAME +COMMAND_LINE char(255) +DEFAULT_EXTENSION char(16) diff --git a/docs/tables/extended_panel_names.txt b/docs/tables/extended_panel_names.txt new file mode 100644 index 00000000..7880fcbb --- /dev/null +++ b/docs/tables/extended_panel_names.txt @@ -0,0 +1,13 @@ + EXTENDED_PANEL_NAMES Table Layout for Rivendell + +The EXTENDED_PANEL_NAMES table holds configuration data for the names of the +extended SoundPanels in Rivendell. Following is the layout of a record in the +EXTENDED_PANEL_NAMES table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------------ +ID int(10) unsigned * Primary key, Auto Increment +TYPE int(11) 0=Station Panel, 1=User Panel +OWNER char(64) +PANEL_NO int(11) +NAME char(64) diff --git a/docs/tables/feed_perms.txt b/docs/tables/feed_perms.txt new file mode 100644 index 00000000..c6ee3e7b --- /dev/null +++ b/docs/tables/feed_perms.txt @@ -0,0 +1,12 @@ + FEED_PERMS Table Layout for Rivendell + +The FEED_PERMS table holds data concerning which RSS feeds are +are allowed to be accessed by which users. Following is the layout +of a record in the FEED_PERMS table: + + +FIELD NAME TYPE REMARKS +--------------------------------------------------------------- +ID int(10) unsigned Primary key, auto increment +USER_NAME char(255) From USERS.LOGIN_NAME +KEY_NAME char(8) From FEEDS.KEYNAME diff --git a/docs/tables/gpis.txt b/docs/tables/gpis.txt new file mode 100644 index 00000000..91217c01 --- /dev/null +++ b/docs/tables/gpis.txt @@ -0,0 +1,14 @@ + GPIS Table Layout for Rivendell + +The GPIS table holds data concerning the gpi lines of each +configured switcher device on the system. Following is the layout +of a record in the GPIS table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------ +ID int(10) unsigned Primary key, auto increment +STATION_NAME char(64) From STATIONS.NAME +MATRIX int(10) unsigned +NUMBER int(11) +MACRO_CART int(10) unsigned +OFF_MACRO_CART int(10) unsigned diff --git a/docs/tables/gpos.txt b/docs/tables/gpos.txt new file mode 100644 index 00000000..c075d7ab --- /dev/null +++ b/docs/tables/gpos.txt @@ -0,0 +1,14 @@ + GPOS Table Layout for Rivendell + +The GPOS table holds data concerning the gpo lines of each +configured switcher device on the system. Following is the layout +of a record in the GPOS table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------ +ID int(10) unsigned Primary key, auto increment +STATION_NAME char(64) From STATIONS.NAME +MATRIX int(10) unsigned +NUMBER int(11) +MACRO_CART int(10) unsigned +OFF_MACRO_CART int(10) unsigned diff --git a/docs/tables/groups.txt b/docs/tables/groups.txt new file mode 100644 index 00000000..779a8017 --- /dev/null +++ b/docs/tables/groups.txt @@ -0,0 +1,21 @@ + GROUPS Layout for Rivendell + +The GROUPS table holds data concerning each Cart Group configured +on the system. Following is the layout of a record in the GROUPS +table: + +FIELD NAME TYPE REMARKS +--------------------------------------------------------------- +NAME char(10) Primary Key +DESCRIPTION char(255) +DEFAULT_CART_TYPE unsigned int(10) 1=Audio, 2=Macro +DEFAULT_LOW_CART unsigned int(10) +DEFAULT_HIGH_CART unsigned int(10) +CUT_SHELFLIFE int(11) -1=no autopurge +DELETE_EMPTY_CARTS enum('N','Y') After purging cuts +DEFAULT_TITLE char(255) +ENFORCE_CART_RANGE enum('N','Y') +REPORT_TFC enum('N','Y') +REPORT_MUS enum('N','Y') +ENABLE_NOW_NEXT enum('N','Y') +COLOR char(7) diff --git a/docs/tables/isci_xreference.txt b/docs/tables/isci_xreference.txt new file mode 100644 index 00000000..f456f4f2 --- /dev/null +++ b/docs/tables/isci_xreference.txt @@ -0,0 +1,19 @@ + ISCI_XREFERENCE Table Layout for Rivendell + +The ISCI_XREFERENCE table holds a representation of the 'ISCI Cross Reference' +data generated by the CounterPoint Traffic system and used in conjunction with +the Citadel XDS replicator. + + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------ +ID int(10) unsigned Primary key, auto increment +CART_NUMBER int(10) unsigned +ISCI char(32) +FILENAME char(64) +LATEST_DATE date +TYPE char(1) +ADVERTISER_NAME char(30) +PRODUCT_NAME char(35) +CREATIVE_TITLE char(30) +REGION_NAME char(80) diff --git a/docs/tables/jack_clients.txt b/docs/tables/jack_clients.txt new file mode 100644 index 00000000..035cff4e --- /dev/null +++ b/docs/tables/jack_clients.txt @@ -0,0 +1,11 @@ + JACK_CLIENTS Table Layout for Rivendell + +The JACK_CLIENTS table contains data about jackd(1) clients to start +when starting the rivendell daemons. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------- +ID int unsigned(10) Primary Key +STATION_NAME char(64) From STATIONS.NAME +DESCRIPTION char(64) +COMMAND_LINE char(255) diff --git a/docs/tables/livewire_gpio_slots.txt b/docs/tables/livewire_gpio_slots.txt new file mode 100644 index 00000000..6d52ec26 --- /dev/null +++ b/docs/tables/livewire_gpio_slots.txt @@ -0,0 +1,14 @@ + LIVEWIRE_GPIO_SLOTS Table Layout for Rivendell + +This table holds the 'mapping' between LiveWire source numbers and +the Rivendell GPIO 'slots' used by the LiveWire Virtual GPIO driver. +Each slot consist of five Rivendell GPIO lines. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------ +ID int(11) signed Primary key, auto-increment +STATION_NAME char(64) From STATIONS.NAME +MATRIX int(11) From MATRICES.MATRIX +SLOT int(11) +IP_ADDRESS char(15) +SOURCE_NUMBER int(11) diff --git a/docs/tables/log_format.txt b/docs/tables/log_format.txt new file mode 100644 index 00000000..a4c4d916 --- /dev/null +++ b/docs/tables/log_format.txt @@ -0,0 +1,47 @@ + Log Format Table Layout for Rivendell + +This is the generic layout of all log tables. Each of these tables +will be have a name ending in '_LOG' and be listed in the 'LOGS' +table. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------ +ID int(11) signed Primary key, auto-increment +COUNT int(11) signed Order of records +TYPE int(11) signed 0=Cart, 1=Marker, 2=OpenBracket, + 3=CloseBracket, 4=Link +SOURCE int(11) signed 0=Manual, 1=Traffic, 2=Music, + 3=Template +START_TIME int(11) Milliseconds after 00:00:00 +GRACE_TIME int(11) signed +CART_NUMBER int(10) unsigned From CART.NUMBER +TIME_TYPE int(11) signed +POST_POINT enum('N','Y') +TRANS_TYPE int(11) signed 0 = Play, 1 = Stop, 2 = Segue +START_POINT int(11) signed Overloads CUTS.START_POINT +END_POINT int(11) signed Overloads CUTS.END_POINT +FADEUP_POINT int(11) signed Overloads CUTS.FADEUP_POINT +FADEUP_GAIN int(11) signed +FADEDOWN_POINT int(11) signed Overloads CUTS.FADEDOWN_POINT +FADEDOWN_GAIN int(11) signed +SEGUE_START_POINT int(11) signed Overloads CUTS.SEGUE_START_POINT +SEGUE_END_POINT int(11) signed Overloads CUTS.SEGUE_END_POINT +SEGUE_GAIN int(11) signed +COMMENT char(255) +LABEL char(64) +ORIGIN_USER char(255) From USERS.LOGIN_NAME +ORIGIN_DATETIME datetime +EVENT_LENGTH int(11) Length of parent RDLogManager event +LINK_EVENT_NAME char(64) +LINK_START_TIME int(11) Milliseconds after 00:00:00 +LINK_LENGTH int(11) +LINK_START_SLOP int(11) +LINK_END_SLOP int(11) +LINK_ID int(11) +LINK_EMBEDDED enum('N','Y') +EXT_START_TIME time External Scheduler Start Time +EXT_LENGTH int(11) External Scheduler Event Length +EXT_CART_NAME char(32) External Scheduler Cart Name +EXT_DATA char(32) External Scheduler Data +EXT_EVENT_ID char(8) External Scheduler Event ID +EXT_ANNC_TYPE char(8) External Scheduler Announcement Type diff --git a/docs/tables/log_modes.txt b/docs/tables/log_modes.txt new file mode 100644 index 00000000..d5b60d26 --- /dev/null +++ b/docs/tables/log_modes.txt @@ -0,0 +1,14 @@ + LOG_MODES Table Layout for Rivendell + +The LOG_MODES table hold the default log mode for each instance of +RDAirPlay. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------------ +ID int(10) unsigned * Primary key, Auto Increment +STATION_NAME char(64) From STATIONS.NAME +MACHINE int(10) unsigned 0=Main Log, 1=AuxLog 1, 2=AuxLog +START_MODE int(11) 0=Previous, 1=LiveAssist, 2=Automatic, + 3=Manual +OP_MODE int(11) 0=Previous, 1=LiveAssist, 2=Automatic, + 3=Manual diff --git a/docs/tables/logs.txt b/docs/tables/logs.txt new file mode 100644 index 00000000..a4ec85d3 --- /dev/null +++ b/docs/tables/logs.txt @@ -0,0 +1,28 @@ + LOGS Table Layout for Rivendell + +The LOGS table holds data concerning each log object that exists +on the system. Following is the layout of a record in the LOGS +table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------- +NAME char(64) Table name, ends with '_LOG' +LOG_EXISTS enum('N','Y') +TYPE int(11) 0=Log, 1=Event, 2=Clock, 3=Grid +SERVICE char(10) From SERVICES.NAME +DESCRIPTION char(64) +ORIGIN_USER char(255) From USERS.LOGIN_NAME +ORIGIN_DATETIME datetime +LINK_DATETIME datetime +MODIFIED_DATETIME datetime +AUTO_REFRESH enum('N','Y') +START_DATE date +END_DATE date +PURGE_DATE date +IMPORT_DATE date +SCHEDULED_TRACKS int unsigned(10) +COMPLETED_TRACKS int unsigned(10) +MUSIC_LINKS int +MUSIC_LINKED enum('N','Y') +TRAFFIC_LINKS int +TRAFFIC_LINKED enum('N','Y') diff --git a/docs/tables/nownext_plugins.txt b/docs/tables/nownext_plugins.txt new file mode 100644 index 00000000..ae347b0b --- /dev/null +++ b/docs/tables/nownext_plugins.txt @@ -0,0 +1,13 @@ + NOWNEXT_PLUGINS Table Layout for Rivendell + +The NOWNEXT_PLUGINS table holds data concerning each Now & Next +plugins configured on the system. Following is the layout +of a record in the NOWNEXT_PLUGINS table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------ +ID int(10) unsigned Primary key, auto increment +STATION_NAME char(64) From STATIONS.NAME +LOG_MACHINE int(10) unsigned 0=Main, 1=Aux1, 2=Aux2 +PLUGIN_PATH char(255) +PLUGIN_ARG char(255) diff --git a/docs/tables/panel_names.txt b/docs/tables/panel_names.txt new file mode 100644 index 00000000..de584639 --- /dev/null +++ b/docs/tables/panel_names.txt @@ -0,0 +1,13 @@ + PANEL_NAMES Table Layout for Rivendell + +The PANEL_NAMES table holds configuration data for the names of the +SoundPanels in Rivendell. Following is the layout of a record in the +PANEL_NAMES table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------------ +ID int(10) unsigned * Primary key, Auto Increment +TYPE int(11) 0=Station Panel, 1=User Panel +OWNER char(64) +PANEL_NO int(11) +NAME char(64) diff --git a/docs/tables/panels.txt b/docs/tables/panels.txt new file mode 100644 index 00000000..9c0118e3 --- /dev/null +++ b/docs/tables/panels.txt @@ -0,0 +1,17 @@ + PANELS Table Layout for Rivendell + +The PANELS table holds configuration data for all the SoundPanels in +Rivendell. Following is the layout of a record in the PANELS table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------------ +ID int(10) unsigned * Primary key, Auto Increment +TYPE int(11) 0=Station Panel, 1=User Panel +OWNER char(64) +PANEL_NO int(11) +ROW_NO int(11) +COLUMN_NO int(11) +LABEL char(64) +CART int(11) +DEFAULT_COLOR char(7) Background color, in hex format + "#RRGGBB". diff --git a/docs/tables/rd_airplay.txt b/docs/tables/rd_airplay.txt new file mode 100644 index 00000000..2ad2075f --- /dev/null +++ b/docs/tables/rd_airplay.txt @@ -0,0 +1,81 @@ + RDAIRPLAY Table Layout for Rivendell + +The RDAIRPLAY table holds configuration data for the RDAirPlay widget. +Following is the layout of a record in the RDAIRPLAY table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------------ +ID int(10) unsigned * Primary key, Auto Increment +STATION char(40) Workstation, Indexed +SEGUE_LENGTH int(11) +TRANS_LENGTH int(11) +OP_MODE int(11) *** RETIRED @ DB v233 *** +START_MODE int(11) *** RETIRED @ DB v233 *** +LOG_MODE_STYLE int(11) 0=Unified, 1=Independent +PIE_COUNT_LENGTH int(11) +PIE_COUNT_ENDPOINT int(11) 0=EOF, 1=Segue Point +CHECK_TIMESYNC enum('N','Y') +STATION_PANELS int(11) +USER_PANELS int(11) +SHOW_AUX_1 enum('N','Y') +SHOW_AUX_2 enum('N','Y') +CLEAR_FILTER enum('N','Y') +DEFAULT_TRANS_TYPE int(11) +BAR_ACTION int(10) unsigned 0=None, 1=Start Next +FLASH_PANEL enum('N','Y') +PANEL_PAUSE_ENABLED enum('N','Y') +BUTTON_LABEL_TEMPLATE char(32) +PAUSE_ENABLED enum('N','Y') +DEFAULT_SERVICE char(10) From SERVICES.NAME +HOUR_SELECTOR_ENABLED enum('N','Y') +UDP_ADDR0 char(255) +UDP_PORT0 int(10) unsigned +UDP_STRING0 char(255) +LOG_RML0 char(255) +UDP_ADDR1 char(255) +UDP_PORT1 int(10) unsigned +UDP_STRING1 char(255) +LOG_RML1 char(255) +UDP_ADDR2 char(255) +UDP_PORT2 int(10) unsigned +UDP_STRING2 char(255) +LOG_RML2 char(255) +EXIT_CODE int(11) 0=clean, 1=dirty +EXIT_PASSWORD char(41) +SKIN_PATH char(255) +SHOW_COUNTERS enum('N','Y') +AUDITION_PREROLL int(11) +TITLE_TEMPLATE char(64) +ARTIST_TEMPLATE char(64) +OUTCUE_TEMPLATE char(64) +DESCRIPTION_TEMPLATE char(64) +LOG0_START_MODE int(11) 0=start empty, 1=load last, + 2=load specified +LOG0_AUTO_RESTART enum('N','Y') +LOG0_LOG_NAME char(64) From LOGS.NAME +LOG0_CURRENT_LOG char(64) From LOGS.NAME +LOG0_RUNNING enum('N','Y') +LOG0_LOG_ID int(11) +LOG0_LOG_LINE int(11) +LOG0_NOW_CART int(10) unsigned +LOG0_NEXT_CART int(10) unsigned +LOG1_START_MODE int(11) 0=start empty, 1=load last, + 2=load specified +LOG1_AUTO_RESTART enum('N','Y') +LOG1_LOG_NAME char(64) From LOGS.NAME +LOG1_CURRENT_LOG char(64) From LOGS.NAME +LOG1_RUNNING enum('N','Y') +LOG1_LOG_ID int(11) +LOG1_LOG_LINE int(11) +LOG1_NOW_CART int(10) unsigned +LOG1_NEXT_CART int(10) unsigned +LOG2_START_MODE int(11) 0=start empty, 1=load last, + 2=load specified +LOG2_AUTO_RESTART enum('N','Y') +LOG2_LOG_NAME char(64) From LOGS.NAME +LOG2_CURRENT_LOG char(64) From LOGS.NAME +LOG2_RUNNING enum('N','Y') +LOG2_LOG_ID int(11) +LOG2_LOG_LINE int(11) +LOG2_NOW_CART int(10) unsigned +LOG2_NEXT_CART int(10) unsigned diff --git a/docs/tables/rd_catch.txt b/docs/tables/rd_catch.txt new file mode 100644 index 00000000..fc560804 --- /dev/null +++ b/docs/tables/rd_catch.txt @@ -0,0 +1,10 @@ + RDCATCH Table Layout for Rivendell + +The RDCATCH table holds non-deck specific configuration data for the +RDCatch module. Following is the layout of a record in the RDAIRPLAY table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------------ +ID int(10) unsigned * Primary key, Auto Increment +STATION char(64) Workstation, Indexed +ERROR_RML char(255) diff --git a/docs/tables/rd_library.txt b/docs/tables/rd_library.txt new file mode 100644 index 00000000..4662182e --- /dev/null +++ b/docs/tables/rd_library.txt @@ -0,0 +1,38 @@ + RDLIBRARY Table Layout for Rivendell + +The RDLIBRARY table holds configuration data for the RDLibrary widget. +Following is the layout of a record in the RDLIBRARY table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------------ +ID int(10) unsigned * Primary key, Auto Increment +STATION char(40) Workstation, Indexed +INSTANCE int(10) unsigned +INPUT_CARD int(11) None=-1 +INPUT_STREAM int(11) RETIRED +INPUT_TYPE enum('A','D') +OUTPUT_CARD int(11) None=-1 +OUTPUT_STREAM int(11) RETIRED +OUTPUT_PORT int(11) None=-1 +VOX_THRESHOLD int(11) dBFS * 100 +TRIM_THRESHOLD int(11) dBFS * 100 +RECORD_GPI int(11) RETIRED +PLAY_GPI int(11) RETIRED +STOP_GPI int(11) RETIRED +DEFAULT_FORMAT int(10) unsigned 0 = PCM16, 1 = Layer-2, 2 = Layer-3 +DEFAULT_CHANNELS int(10) unsigned +DEFAULT_SAMPRATE int(10) unsigned RETIRED +DEFAULT_LAYER int(10) unsigned +DEFAULT_BITRATE int(10) unsigned +DEFAULT_RECORD_MODE int(10) unsigned 0 = Manual, 1 = VOX +DEFAULT_TRIM_STATE enum('Y','N') +MAXLENGTH int(11) Max record length, in sec +TAIL_PREROLL int(10) unsigned +RIPPER_DEVICE char(64) +PARANOIA_LEVEL int(11) +RIPPER_LEVEL int(11) +CDDB_SERVER char(64) +ENABLE_EDITOR enum('N','Y') +SRC_CONVERTER int(11) +LIMIT_SEARCH int(11) 0 = No, 1 = Yes, 2 = Previous +SEARCH_LIMITED enum('N','Y') diff --git a/docs/tables/rd_logedit.txt b/docs/tables/rd_logedit.txt new file mode 100644 index 00000000..55272e78 --- /dev/null +++ b/docs/tables/rd_logedit.txt @@ -0,0 +1,27 @@ + RDLOGEDIT Table Layout for Rivendell + +The RDLOGEDIT table holds configuration data for the RDLogEdit widget. +Following is the layout of a record in the RDLOGEDIT table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------------ +ID int(10) unsigned * Primary key, Auto Increment +STATION char(64) Workstation, Indexed +INPUT_CARD int(11) None=-1 +OUTPUT_CARD int(11) None=-1 +OUTPUT_PORT int(11) +FORMAT int(10) unsigned 0 = PCM16, 1 = Layer-2, 2 = Layer-3 +SAMPRATE int(10) unsigned RETIRED +LAYER int(10) unsigned +BITRATE int(10) unsigned +ENABLE_SECOND_START enum('N','Y') +DEFAULT_CHANNELS int(10) unsigned +MAXLENGTH int(11) Max record length, in sec +TAIL_PREROLL int(10) unsigned +START_CART int(10) unsigned +END_CART int(10) unsigned +REC_START_CART int(10) unsigned +REC_STOP_CART int(10) unsigned +TRIM_THRESHOLD int(11) +RIPPER_LEVEL int(11) +DEFAULT_TRANS_TYPE int(11) diff --git a/docs/tables/rdairplay_channels.txt b/docs/tables/rdairplay_channels.txt new file mode 100644 index 00000000..6badba84 --- /dev/null +++ b/docs/tables/rdairplay_channels.txt @@ -0,0 +1,32 @@ + RDAIRPLAY_CHANNELS Table Layout for Rivendell + +The RDAIRPLAY_CHANNELS table holds configuration data for the RDAirPlay +channels assignments and related information. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------------ +ID int(10) unsigned * Primary key, Auto Increment +STATION_NAME char(64) From STATIONS.NAME +INSTANCE int(10) unsigned 0 = Main Log Output 1 + 1 = Main Log Output 2 + 2 = Sound Panel Output 1 + 3 = Cue Output + 4 = Aux Log 1 Output + 5 = Aux Log 2 Output + 6 = Sound Panel Output 2 + 7 = Sound Panel Output 3 + 8 = Sound Panel Output 4 + 9 = Sound Panel Output 5 +CARD int(11) +PORT int(11) +START_RML char(255) +STOP_RML char(255) +GPIO_TYPE int unsigned 0 = Edge, 1 = Level +START_GPI_MATRIX int(11) +START_GPI_LINE int(11) +START_GPO_MATRIX int(11) +START_GPO_LINE int(11) +STOP_GPI_MATRIX int(11) +STOP_GPI_LINE int(11) +STOP_GPO_MATRIX int(11) +STOP_GPO_LINE int(11) diff --git a/docs/tables/rdpanel_channels.txt b/docs/tables/rdpanel_channels.txt new file mode 100644 index 00000000..b49fef8d --- /dev/null +++ b/docs/tables/rdpanel_channels.txt @@ -0,0 +1,32 @@ + RDPANEL_CHANNELS Table Layout for Rivendell + +The RDPANEL_CHANNELS table holds configuration data for the RDPanel +channels assignments and related information. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------------ +ID int(10) unsigned * Primary key, Auto Increment +STATION_NAME char(64) From STATIONS.NAME +INSTANCE int(10) unsigned 0 = Main Log Output 1 (Not Used) + 1 = Main Log Output 2 (Not Used) + 2 = Sound Panel Output 1 + 3 = Cue Output + 4 = Aux Log 1 Output (Not Used) + 5 = Aux Log 2 Output (Not Used) + 6 = Sound Panel Output 2 + 7 = Sound Panel Output 3 + 8 = Sound Panel Output 4 + 9 = Sound Panel Output 5 +CARD int(11) +PORT int(11) +START_RML char(255) +STOP_RML char(255) +GPIO_TYPE int unsigned 0 = Edge, 1 = Level +START_GPI_MATRIX int(11) +START_GPI_LINE int(11) +START_GPO_MATRIX int(11) +START_GPO_LINE int(11) +STOP_GPI_MATRIX int(11) +STOP_GPI_LINE int(11) +STOP_GPO_MATRIX int(11) +STOP_GPO_LINE int(11) diff --git a/docs/tables/recordings.txt b/docs/tables/recordings.txt new file mode 100644 index 00000000..0451345f --- /dev/null +++ b/docs/tables/recordings.txt @@ -0,0 +1,64 @@ + RECORDINGS Table Layout for Rivendell + +The RECORDINGS table holds data concerning each individual automatic +recording programmed on the system. Following is the layout of a +record in the RECORDINGS table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------ +ID int(10) unsigned Primary key, auto increment +IS_ACTIVE enum('N','Y') +TYPE int(11) 0=Recording,1=Macro Event, + 2=Switch Event,3=Playout, + 4=Download,5=Upload +STATION_NAME char(64) From STATIONS.NAME +CHANNEL int(10) unsigned +CUT_NAME char(12) From CUTS.CUT_NAME +SUN enum('N','Y') +MON enum('N','Y') +TUE enum('N','Y') +WED enum('N','Y') +THU enum('N','Y') +FRI enum('N','Y') +SAT enum('N','Y') +DESCRIPTION char(64) Remarks + +START_TYPE int(10) 0=Hard Timed,1=GPI +START_TIME time +START_LENGTH int(11) +START_MATRIX int(11) from MATRICES.MATRIX +START_LINE int(11) +START_OFFSET int(11) +END_TYPE int(10) 0=Hard Timed,1=GPI,2=Length +END_TIME time +END_LENGTH int(11) +END_MATRIX int(11) from MATRICES.MATRIX +END_LINE int(11) + +LENGTH int(10) unsigned in milliseconds +START_GPI int(11) signed -1 = None +END_GPI int(11) signed -1 = None +ALLOW_MULT_RECS enum('N','Y') +MAX_GPI_REC_LENGTH int(10) unsigned +TRIM_THRESHOLD int(11) in 1/100 dBFS +NORMALIZE_LEVEL int(11) in 1/100 dBFS +STARTDATE_OFFSET int(10) unsigned +ENDDATE_OFFSET int(10) unsigned +EVENTDATE_OFFSET int(11) +FORMAT int(11) signed 0 = PCM16, 2 = Layer 2, 3 = Layer 3 +CHANNELS int(11) signed +SAMPRATE int(11) signed RETIRED +BITRATE int(11) signed +QUALITY int(11) signed +MACRO_CART int(10) unsigned +SWITCH_INPUT int(11) +SWITCH_OUTPUT int(11) +EXIT_CODE int(11) 0 = Ok, 1 = Short Length, + 2 = Low Level, 3 = High Level +EXIT_TEXT text +ONE_SHOT enum ('N','Y') +URL char(255) +URL_USERNAME char(64) +URL_PASSWORD char(64) +ENABLE_METADATA enum('N','Y') +FEED_ID int From FEEDS.ID diff --git a/docs/tables/repl_cart_state.txt b/docs/tables/repl_cart_state.txt new file mode 100644 index 00000000..b2e45dff --- /dev/null +++ b/docs/tables/repl_cart_state.txt @@ -0,0 +1,14 @@ + REPL_CART_STATE Table Layout for Rivendell + +The REPL_CART_STATE table holds replication tracking data for cart +objects. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------ +ID int(10) unsigned auto_increment, not null + primary key +REPLICATOR_NAME char(32) from REPLICATORS.NAME +CART_NUMBER int(10) unsigned from CART.NUMBER +POSTED_FILENAME char(255) +ITEM_DATETIME datetime +REPOST enum('N','Y') diff --git a/docs/tables/repl_cut_state.txt b/docs/tables/repl_cut_state.txt new file mode 100644 index 00000000..a4332c20 --- /dev/null +++ b/docs/tables/repl_cut_state.txt @@ -0,0 +1,12 @@ + REPL_CUT_STATE Table Layout for Rivendell + +The REPL_CUT_STATE table holds replication tracking data for cut +objects. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------ +ID int(10) unsigned auto_increment, not null + primary key +REPLICATOR_NAME char(32) from REPLICATORS.NAME +CUT_NAME char(12) from CUTS.CUT_NAME +ITEM_DATETIME datetime diff --git a/docs/tables/replicator_map.txt b/docs/tables/replicator_map.txt new file mode 100644 index 00000000..5fce14a8 --- /dev/null +++ b/docs/tables/replicator_map.txt @@ -0,0 +1,11 @@ + REPLICATOR_MAP Table Layout for Rivendell + +The REPLICATOR_MAP table holds the mapping data between replicator +configurations and groups. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------ +ID int(10) unsigned auto_increment, not null, + primary key +REPLICATOR_NAME char(32) from REPLICATORS.NAME +GROUP_NAME char(10) from GROUPS.NAME diff --git a/docs/tables/replicators.txt b/docs/tables/replicators.txt new file mode 100644 index 00000000..afd74d91 --- /dev/null +++ b/docs/tables/replicators.txt @@ -0,0 +1,21 @@ + REPLICATORS Table Layout for Rivendell + +The REPLICATORS table holds data concerning each individual replicator +configuration on the system. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------ +NAME char(32) not null, primary key +DESCRIPTION char(64) +TYPE_ID int(10) unsigned not null +STATION_NAME char(64) from STATIONS.NAME +FORMAT int(10) unsigned +CHANNELS int(10) unsigned +SAMPRATE int(10) unsigned +BITRATE int(10) unsigned +QUALITY int(10) unsigned +URL char(255) +URL_USERNAME char(64) +URL_PASSWORD char(64) +ENABLE_METADATA enum('N','Y') +NORMALIZATION_LEVEL int(11) signed diff --git a/docs/tables/services.txt b/docs/tables/services.txt new file mode 100644 index 00000000..45d56b98 --- /dev/null +++ b/docs/tables/services.txt @@ -0,0 +1,265 @@ + SERVICES Table Layout for Rivendell + +The SERVICES table holds data concerning each audio service configured +on the system. Following is the layout of a record in the SERVICES +table: + +FIELD NAME TYPE REMARKS +--------------------------------------------------------------- +NAME char(10) unsigned Primary Key +DESCRIPTION char(255) +NAME_TEMPLATE char(255) +DESCRIPTION_TEMPLATE char(255) +PROGRAM_CODE char(255) +CHAIN_LOG enum('N','Y') +TRACK_GROUP char(10) From GROUPS.NAME +AUTOSPOT_GROUP char(10) From GROUPS.NAME +AUTO_REFRESH enum('N','Y') +DEFAULT_LOG_SHELFLIFE int(11) +ELR_SHELFLIFE int(11) +TFC_PATH char(255) +TFC_PREIMPORT_CMD text +TFC_WIN_PATH char(255) +TFC_WIN_PREIMPORT_CMD text +TFC_IMPORT_TEMPLATE char(64) From IMPORT_TEMPLATES.NAME +TFC_LABEL_CART char(32) +TFC_TRACK_CART char(32) +TFC_CART_OFFSET int(11) +TFC_CART_LENGTH int(11) +TFC_TITLE_OFFSET int(11) +TFC_TITLE_LENGTH int(11) +TFC_START_OFFSET int(11) RETIRED as of DB v119 +TFC_START_LENGTH int(11) RETIRED as of DB v119 +TFC_HOURS_OFFSET int(11) +TFC_HOURS_LENGTH int(11) +TFC_MINUTES_OFFSET int(11) +TFC_MINUTES_LENGTH int(11) +TFC_SECONDS_OFFSET int(11) +TFC_SECONDS_LENGTH int(11) +TFC_LENGTH_OFFSET int(11) +TFC_LENGTH_LENGTH int(11) +TFC_LEN_HOURS_OFFSET int(11) +TFC_LEN_HOURS_LENGTH int(11) +TFC_LEN_MINUTES_OFFSET int(11) +TFC_LEN_MINUTES_LENGTH int(11) +TFC_LEN_SECONDS_OFFSET int(11) +TFC_LEN_SECONDS_LENGTH int(11) +TFC_DATA_OFFSET int(11) +TFC_DATA_LENGTH int(11) +TFC_EVENT_ID_OFFSET int(11) +TFC_EVENT_ID_LENGTH int(11) +TFC_ANNC_TYPE_OFFSET int(11) +TFC_ANNC_TYPE_LENGTH int(11) +MUS_PATH char(255) +MUS_PREIMPORT_CMD text +MUS_WIN_PATH char(255) +MUS_WIN_PREIMPORT_CMD text +MUS_IMPORT_TEMPLATE char(64) From IMPORT_TEMPLATES.NAME +MUS_LABEL_CART char(32) +MUS_TRACK_CART char(32) +MUS_BREAK_STRING char(64) +MUS_TRACK_STRING char(64) +MUS_CART_OFFSET int(11) +MUS_CART_LENGTH int(11) +MUS_TITLE_OFFSET int(11) +MUS_TITLE_LENGTH int(11) +MUS_START_OFFSET int(11) RETIRED as of DB v119 +MUS_START_LENGTH int(11) RETIRED as of DB v119 +MUS_HOURS_OFFSET int(11) +MUS_HOURS_LENGTH int(11) +MUS_MINUTES_OFFSET int(11) +MUS_MINUTES_LENGTH int(11) +MUS_SECONDS_OFFSET int(11) +MUS_SECONDS_LENGTH int(11) +MUS_LEN_HOURS_OFFSET int(11) +MUS_LEN_HOURS_LENGTH int(11) +MUS_LEN_MINUTES_OFFSET int(11) +MUS_LEN_MINUTES_LENGTH int(11) +MUS_LEN_SECONDS_OFFSET int(11) +MUS_LEN_SECONDS_LENGTH int(11) +MUS_LENGTH_OFFSET int(11) +MUS_LENGTH_LENGTH int(11) +MUS_DATA_OFFSET int(11) +MUS_DATA_LENGTH int(11) +MUS_EVENT_ID_OFFSET int(11) +MUS_EVENT_ID_LENGTH int(11) +MUS_ANNC_TYPE_OFFSET int(11) +MUS_ANNC_TYPE_LENGTH int(11) +CLOCK0 char(64) RDLogManager Clock Name +CLOCK1 char(64) RDLogManager Clock Name +CLOCK2 char(64) RDLogManager Clock Name +CLOCK3 char(64) RDLogManager Clock Name +CLOCK4 char(64) RDLogManager Clock Name +CLOCK5 char(64) RDLogManager Clock Name +CLOCK6 char(64) RDLogManager Clock Name +CLOCK7 char(64) RDLogManager Clock Name +CLOCK8 char(64) RDLogManager Clock Name +CLOCK9 char(64) RDLogManager Clock Name +CLOCK10 char(64) RDLogManager Clock Name +CLOCK11 char(64) RDLogManager Clock Name +CLOCK12 char(64) RDLogManager Clock Name +CLOCK13 char(64) RDLogManager Clock Name +CLOCK14 char(64) RDLogManager Clock Name +CLOCK15 char(64) RDLogManager Clock Name +CLOCK16 char(64) RDLogManager Clock Name +CLOCK17 char(64) RDLogManager Clock Name +CLOCK18 char(64) RDLogManager Clock Name +CLOCK19 char(64) RDLogManager Clock Name +CLOCK20 char(64) RDLogManager Clock Name +CLOCK21 char(64) RDLogManager Clock Name +CLOCK22 char(64) RDLogManager Clock Name +CLOCK23 char(64) RDLogManager Clock Name +CLOCK24 char(64) RDLogManager Clock Name +CLOCK25 char(64) RDLogManager Clock Name +CLOCK26 char(64) RDLogManager Clock Name +CLOCK27 char(64) RDLogManager Clock Name +CLOCK28 char(64) RDLogManager Clock Name +CLOCK29 char(64) RDLogManager Clock Name +CLOCK30 char(64) RDLogManager Clock Name +CLOCK31 char(64) RDLogManager Clock Name +CLOCK32 char(64) RDLogManager Clock Name +CLOCK33 char(64) RDLogManager Clock Name +CLOCK34 char(64) RDLogManager Clock Name +CLOCK35 char(64) RDLogManager Clock Name +CLOCK36 char(64) RDLogManager Clock Name +CLOCK37 char(64) RDLogManager Clock Name +CLOCK38 char(64) RDLogManager Clock Name +CLOCK39 char(64) RDLogManager Clock Name +CLOCK40 char(64) RDLogManager Clock Name +CLOCK41 char(64) RDLogManager Clock Name +CLOCK42 char(64) RDLogManager Clock Name +CLOCK43 char(64) RDLogManager Clock Name +CLOCK44 char(64) RDLogManager Clock Name +CLOCK45 char(64) RDLogManager Clock Name +CLOCK46 char(64) RDLogManager Clock Name +CLOCK47 char(64) RDLogManager Clock Name +CLOCK48 char(64) RDLogManager Clock Name +CLOCK49 char(64) RDLogManager Clock Name +CLOCK50 char(64) RDLogManager Clock Name +CLOCK51 char(64) RDLogManager Clock Name +CLOCK52 char(64) RDLogManager Clock Name +CLOCK53 char(64) RDLogManager Clock Name +CLOCK54 char(64) RDLogManager Clock Name +CLOCK55 char(64) RDLogManager Clock Name +CLOCK56 char(64) RDLogManager Clock Name +CLOCK57 char(64) RDLogManager Clock Name +CLOCK58 char(64) RDLogManager Clock Name +CLOCK59 char(64) RDLogManager Clock Name +CLOCK60 char(64) RDLogManager Clock Name +CLOCK61 char(64) RDLogManager Clock Name +CLOCK62 char(64) RDLogManager Clock Name +CLOCK63 char(64) RDLogManager Clock Name +CLOCK64 char(64) RDLogManager Clock Name +CLOCK65 char(64) RDLogManager Clock Name +CLOCK66 char(64) RDLogManager Clock Name +CLOCK67 char(64) RDLogManager Clock Name +CLOCK68 char(64) RDLogManager Clock Name +CLOCK69 char(64) RDLogManager Clock Name +CLOCK60 char(64) RDLogManager Clock Name +CLOCK61 char(64) RDLogManager Clock Name +CLOCK62 char(64) RDLogManager Clock Name +CLOCK63 char(64) RDLogManager Clock Name +CLOCK64 char(64) RDLogManager Clock Name +CLOCK65 char(64) RDLogManager Clock Name +CLOCK66 char(64) RDLogManager Clock Name +CLOCK67 char(64) RDLogManager Clock Name +CLOCK68 char(64) RDLogManager Clock Name +CLOCK69 char(64) RDLogManager Clock Name +CLOCK70 char(64) RDLogManager Clock Name +CLOCK71 char(64) RDLogManager Clock Name +CLOCK72 char(64) RDLogManager Clock Name +CLOCK73 char(64) RDLogManager Clock Name +CLOCK74 char(64) RDLogManager Clock Name +CLOCK75 char(64) RDLogManager Clock Name +CLOCK76 char(64) RDLogManager Clock Name +CLOCK77 char(64) RDLogManager Clock Name +CLOCK78 char(64) RDLogManager Clock Name +CLOCK79 char(64) RDLogManager Clock Name +CLOCK80 char(64) RDLogManager Clock Name +CLOCK81 char(64) RDLogManager Clock Name +CLOCK82 char(64) RDLogManager Clock Name +CLOCK83 char(64) RDLogManager Clock Name +CLOCK84 char(64) RDLogManager Clock Name +CLOCK85 char(64) RDLogManager Clock Name +CLOCK86 char(64) RDLogManager Clock Name +CLOCK87 char(64) RDLogManager Clock Name +CLOCK88 char(64) RDLogManager Clock Name +CLOCK89 char(64) RDLogManager Clock Name +CLOCK90 char(64) RDLogManager Clock Name +CLOCK91 char(64) RDLogManager Clock Name +CLOCK92 char(64) RDLogManager Clock Name +CLOCK93 char(64) RDLogManager Clock Name +CLOCK94 char(64) RDLogManager Clock Name +CLOCK95 char(64) RDLogManager Clock Name +CLOCK96 char(64) RDLogManager Clock Name +CLOCK97 char(64) RDLogManager Clock Name +CLOCK98 char(64) RDLogManager Clock Name +CLOCK99 char(64) RDLogManager Clock Name +CLOCK100 char(64) RDLogManager Clock Name +CLOCK101 char(64) RDLogManager Clock Name +CLOCK102 char(64) RDLogManager Clock Name +CLOCK103 char(64) RDLogManager Clock Name +CLOCK104 char(64) RDLogManager Clock Name +CLOCK105 char(64) RDLogManager Clock Name +CLOCK106 char(64) RDLogManager Clock Name +CLOCK107 char(64) RDLogManager Clock Name +CLOCK108 char(64) RDLogManager Clock Name +CLOCK109 char(64) RDLogManager Clock Name +CLOCK110 char(64) RDLogManager Clock Name +CLOCK111 char(64) RDLogManager Clock Name +CLOCK112 char(64) RDLogManager Clock Name +CLOCK113 char(64) RDLogManager Clock Name +CLOCK114 char(64) RDLogManager Clock Name +CLOCK115 char(64) RDLogManager Clock Name +CLOCK116 char(64) RDLogManager Clock Name +CLOCK117 char(64) RDLogManager Clock Name +CLOCK118 char(64) RDLogManager Clock Name +CLOCK119 char(64) RDLogManager Clock Name +CLOCK120 char(64) RDLogManager Clock Name +CLOCK121 char(64) RDLogManager Clock Name +CLOCK122 char(64) RDLogManager Clock Name +CLOCK123 char(64) RDLogManager Clock Name +CLOCK124 char(64) RDLogManager Clock Name +CLOCK125 char(64) RDLogManager Clock Name +CLOCK126 char(64) RDLogManager Clock Name +CLOCK127 char(64) RDLogManager Clock Name +CLOCK128 char(64) RDLogManager Clock Name +CLOCK129 char(64) RDLogManager Clock Name +CLOCK130 char(64) RDLogManager Clock Name +CLOCK131 char(64) RDLogManager Clock Name +CLOCK132 char(64) RDLogManager Clock Name +CLOCK133 char(64) RDLogManager Clock Name +CLOCK134 char(64) RDLogManager Clock Name +CLOCK135 char(64) RDLogManager Clock Name +CLOCK136 char(64) RDLogManager Clock Name +CLOCK137 char(64) RDLogManager Clock Name +CLOCK138 char(64) RDLogManager Clock Name +CLOCK139 char(64) RDLogManager Clock Name +CLOCK140 char(64) RDLogManager Clock Name +CLOCK141 char(64) RDLogManager Clock Name +CLOCK142 char(64) RDLogManager Clock Name +CLOCK143 char(64) RDLogManager Clock Name +CLOCK144 char(64) RDLogManager Clock Name +CLOCK145 char(64) RDLogManager Clock Name +CLOCK146 char(64) RDLogManager Clock Name +CLOCK147 char(64) RDLogManager Clock Name +CLOCK148 char(64) RDLogManager Clock Name +CLOCK149 char(64) RDLogManager Clock Name +CLOCK150 char(64) RDLogManager Clock Name +CLOCK151 char(64) RDLogManager Clock Name +CLOCK152 char(64) RDLogManager Clock Name +CLOCK153 char(64) RDLogManager Clock Name +CLOCK154 char(64) RDLogManager Clock Name +CLOCK155 char(64) RDLogManager Clock Name +CLOCK156 char(64) RDLogManager Clock Name +CLOCK157 char(64) RDLogManager Clock Name +CLOCK158 char(64) RDLogManager Clock Name +CLOCK159 char(64) RDLogManager Clock Name +CLOCK160 char(64) RDLogManager Clock Name +CLOCK161 char(64) RDLogManager Clock Name +CLOCK162 char(64) RDLogManager Clock Name +CLOCK163 char(64) RDLogManager Clock Name +CLOCK164 char(64) RDLogManager Clock Name +CLOCK165 char(64) RDLogManager Clock Name +CLOCK166 char(64) RDLogManager Clock Name +CLOCK167 char(64) RDLogManager Clock Name diff --git a/docs/tables/sources.txt b/docs/tables/sources.txt new file mode 100644 index 00000000..143f421c --- /dev/null +++ b/docs/tables/sources.txt @@ -0,0 +1,15 @@ + SOURCES Table Layout for Rivendell + +The SOURCES table holds data concerning each configured netcatcher +feed source on the system. Following is the layout of a +record in the SOURCES table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------ +ID int(10) unsigned Primary key, auto increment +STATION_NAME char(64) From DECKS.STATION_NAME +CHANNEL int(10) unsigned From DECKS.CHANNEL +SOURCE_NAME char(64) +SERIAL_COMMAND char(64) +GPO_LINE int(10) unsigned + diff --git a/docs/tables/stations.txt b/docs/tables/stations.txt new file mode 100644 index 00000000..f2c7441f --- /dev/null +++ b/docs/tables/stations.txt @@ -0,0 +1,77 @@ + STATIONS Table Layout for Rivendell + +The STATIONS table contains data about each workstation in the system. +Following is the layout of a record in the SERVICES table: + +FIELD NAME TYPE REMARKS +--------------------------------------------------------------- +NAME char(64) Primary Key +DESCRIPTION char(64) Indexed +USER_NAME char(255) Current User +DEFAULT_NAME char(255) Default User +IPV4_ADDRESS char(15) +HTTP_STATION char(64) From STATIONS.NAME +CAE_STATION char(64) From STATIONS.NAME +TIME_OFFSET int(11) +BACKUP_DIR char(255) +BACKUP_LIFE int(11) +BROADCAST_SECURITY int(10) unsigned 0=HostSec, 1=UserSec +HEARTBEAT_CART int(10) unsigned +HEARTBEAT_INTERVAL int(10) unsigned +STARTUP_CART int(10) unsigned +EDITOR_PATH char(255) +FILTER_MODE int(11) 0=Synchronous, 1=Asynchronous +START_JACK enum('Y','N') +JACK_SERVER_NAME char(64) +JACK_COMMAND_LINE char(255) +CUE_CARD int(11) signed +CUE_PORT int(11) signed +CUE_START_CART int(10) unsigned +CUE_STOP_CART int(10) unsigned +CARTSLOT_COLUMNS int(11) signed +CARTSLOT_ROWS int(11) signed +ENABLE_DRAGDROP enum('N','Y') +ENFORCE_PANEL_SETUP enum('N','Y') +SYSTEM_MAINT enum('N','Y') +STATION_SCANNED enum('N','Y') +HAVE_OGGENC enum('N','Y') +HAVE_OGG123 enum('N','Y') +HAVE_FLAC enum('N','Y') +HAVE_TWOLAME enum('N','Y') +HAVE_LAME enum('N','Y') +HAVE_MPG321 enum('N','Y') +HPI_VERSION char(16) +JACK_VERSION char(16) +ALSA_VERSION char(16) +CARD0_DRIVER int(11) signed 0=None, 1=Hpi, 2=Jack, 3=ALSA +CARD0_NAME char(64) +CARD0_INPUTS int(11) signed +CARD0_OUTPUTS int(11) signed +CARD1_DRIVER int(11) signed 0=None, 1=Hpi, 2=Jack, 3=ALSA +CARD1_NAME char(64) +CARD1_INPUTS int(11) signed +CARD1_OUTPUTS int(11) signed +CARD2_DRIVER int(11) signed 0=None, 1=Hpi, 2=Jack, 3=ALSA +CARD2_NAME char(64) +CARD2_INPUTS int(11) signed +CARD2_OUTPUTS int(11) signed +CARD3_DRIVER int(11) signed 0=None, 1=Hpi, 2=Jack, 3=ALSA +CARD3_NAME char(64) +CARD3_INPUTS int(11) signed +CARD3_OUTPUTS int(11) signed +CARD4_DRIVER int(11) signed 0=None, 1=Hpi, 2=Jack, 3=ALSA +CARD4_NAME char(64) +CARD4_INPUTS int(11) signed +CARD4_OUTPUTS int(11) signed +CARD5_DRIVER int(11) signed 0=None, 1=Hpi, 2=Jack, 3=ALSA +CARD5_NAME char(64) +CARD5_INPUTS int(11) signed +CARD5_OUTPUTS int(11) signed +CARD6_DRIVER int(11) signed 0=None, 1=Hpi, 2=Jack, 3=ALSA +CARD6_NAME char(64) +CARD6_INPUTS int(11) signed +CARD6_OUTPUTS int(11) signed +CARD7_DRIVER int(11) signed 0=None, 1=Hpi, 2=Jack, 3=ALSA +CARD7_NAME char(64) +CARD7_INPUTS int(11) signed +CARD7_OUTPUTS int(11) signed diff --git a/docs/tables/svc_rec_format.txt b/docs/tables/svc_rec_format.txt new file mode 100644 index 00000000..214d63a0 --- /dev/null +++ b/docs/tables/svc_rec_format.txt @@ -0,0 +1,41 @@ + Reconciliation Format Table Layout for Rivendell + +This is the generic layout of all reconciliation tables. Each of +these tables will be have a name ending in '_SRT' and be listed in +the 'SERVICES' table. + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------ +ID int(10) unsigned Primary key, auto-increment +LENGTH int(11) signed +LOG_NAME char(64) From LOGS.NAME +LOG_ID int(11) signed From *_LOG.ID +CART_NUMBER int(10) unsigned From CART.NUMBER +CUT_NUMBER int(11) +TITLE char(255) From CART.TITLE +ARTIST char(255) From CART.ARTIST +PUBLISHER char(64) From CART.PUBLISHER +COMPOSER char(64) From CART.COMPOSER +ALBUM char(255) From CART.ALBUM +LABEL char(64) From CART.LABEL +CONDUCTOR char(64) From CART.CONDUCTOR +USER_DEFINED char(255) From CART.USER_DEFINED +SONG_ID char(32) From CART.SONG_ID +USAGE_CODE int From CART.USAGE_CODE +ISRC char(12) From CUTS.ISRC +ISCI char(32) From CUTS.ISCI +STATION_NAME char(64) From STATIONS.NAME +EVENT_DATETIME datetime +SCHEDULED_TIME time From *_LOG.START_TIME +EVENT_TYPE int(11) 1=Start, 2=Stop +EVENT_SOURCE int(11) 0=Manual,1=Traffic,2=Music,3=Template +PLAY_SOURCE int(11) 0=Unknown,1=MainLog, + 2=AuxLog1,3=AuxLog2,4=SoundPanel +START_SOURCE int(11) 0=Unknown +ONAIR_FLAG enum('N','Y') +EXT_START_TIME time Scheduler Start Time +EXT_LENGTH int(11) Scheduler Length +EXT_CART_NAME char(32) Scheduler Cart Name +EXT_DATA char(32) Scheduler Data +EXT_EVENT_ID char(8) Scheduler Event ID +EXT_ANNC_TYPE char(8) External Scheduler Announcement Type diff --git a/docs/tables/triggers.txt b/docs/tables/triggers.txt new file mode 100644 index 00000000..d681e744 --- /dev/null +++ b/docs/tables/triggers.txt @@ -0,0 +1,12 @@ + TRIGGERS Table Layout for Rivendell + +The TRIGGERS table holds data concerning all triggers on the system. +Following is the layout of a record in the SERVICES table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------------- +ID int(10) unsigned Primary Key, Autoincrement +CUT_NAME char(12) Indexed +TRIGGER_CODE int(10) unsigned +OFFSET int(10) Location + diff --git a/docs/tables/ttys.txt b/docs/tables/ttys.txt new file mode 100644 index 00000000..7341a96a --- /dev/null +++ b/docs/tables/ttys.txt @@ -0,0 +1,17 @@ + TTYS Table Layout for Rivendell + +The TTYS table holds data concerning each configured tty port on the +system. Following is the layout of a record in the TTYS table: + +FIELD NAME TYPE REMARKS +------------------------------------------------------------------ +ID int(10) unsigned Primary Key +PORT_ID int(10) unsigned +ACTIVE enum('N','Y') +STATION_NAME char(64) From STATIONS +PORT char(20) Unix device name +BAUD_RATE int(11) signed in bits/sec +DATA_BITS int(11) signed +STOP_BITS int(11) signed +PARITY int(11) signed 0 = None, 1 = Even, 2 = Odd +TERMINATION int(11) signed 0 = None, 1 = LF, 2 = CR/LF diff --git a/docs/tables/user_perms.txt b/docs/tables/user_perms.txt new file mode 100644 index 00000000..6e532821 --- /dev/null +++ b/docs/tables/user_perms.txt @@ -0,0 +1,12 @@ + USER_PERMS Table Layout for Rivendell + +The USER_PERMS table holds data concerning which audio groups are +are allowed to be accessed by which users. Following is the layout +of a record in the USER_PERMS table: + + +FIELD NAME TYPE REMARKS +--------------------------------------------------------------- +ID int(10) unsigned Primary key, auto increment +USER_NAME char(255) From USERS.LOGIN_NAME +GROUP_NAME char(10) From GROUPS.NAME diff --git a/docs/tables/users.txt b/docs/tables/users.txt new file mode 100644 index 00000000..7154b40a --- /dev/null +++ b/docs/tables/users.txt @@ -0,0 +1,35 @@ + USERS Table Layout for Rivendell + +The USERS table holds data concerning each individual user configured +on the system. Following is the layout of a record in the USERS +table: + +FIELD NAME TYPE REMARKS +-------------------------------------------------------------------------- +LOGIN_NAME char(255) Primary key +FULL_NAME char(255) Indexed +PHONE_NUMBER char(20) +DESCRIPTION char(255) +PASSWORD char(32) Not-NULL, Hashed +ENABLE_WEB enum('N','Y') +ADMIN_USERS_PRIV enum('N','Y') Retired +ADMIN_CONFIG_PRIV enum('N','Y') +CREATE_CARTS_PRIV enum('N','Y') +DELETE_CARTS_PRIV enum('N','Y') +MODIFY_CARTS_PRIV enum('N','Y') +EDIT_AUDIO_PRIV enum('N','Y') +ASSIGN_CART_PRIV enum('N','Y') Retired +CREATE_LOG_PRIV enum('N','Y') +DELETE_LOG_PRIV enum('N','Y') +DELETE_REC_PRIV enum('N','Y') +PLAYOUT_LOG_PRIV enum('N','Y') +ARRANGE_LOG_PRIV enum('N','Y') +MODIFY_TEMPLATE_PRIV enum('N','Y') +ADDTO_LOG_PRIV enum('N','Y') +REMOVEFROM_LOG_PRIV enum('N','Y') +CONFIG_PANELS_PRIV enum('N','Y') +VOICETRACK_LOG_PRIV enum('N','Y') +EDIT_CATCHES_PRIV enum('N','Y') +ADD_PODCAST_PRIV enum('N','Y') +EDIT_PODCAST_PRIV enum('N','Y') +DELETE_PODCAST_PRIV enum('N','Y') diff --git a/docs/tables/version.txt b/docs/tables/version.txt new file mode 100644 index 00000000..5da0982d --- /dev/null +++ b/docs/tables/version.txt @@ -0,0 +1,11 @@ + VERSION Table Layout for Rivendell + +The VERSION table holds data concerning the current version level +of various Rivendell components as well as other 'system-wide' parameters. +Following is the layout of a record in the VERSION table: + +FIELD NAME TYPE REMARKS +-------------------------------------------------------------------------- +DATABASE int(11) Primary key +LAST_MAINT_DATETIME datetime +LAST_ISCI_XREFERENCE datetime diff --git a/docs/tables/vguest_resources.txt b/docs/tables/vguest_resources.txt new file mode 100644 index 00000000..1895719e --- /dev/null +++ b/docs/tables/vguest_resources.txt @@ -0,0 +1,20 @@ + VGUEST_RESOURCES Table Layout for Rivendell + +The VGUEST_RESOURCES table holds data concerning the the mapping of +various Rivendell objects to resources in a Logitek Audio Engine +system. +Following is the layout of a record in the VGUEST_RESOURCES table: + +FIELD NAME TYPE REMARKS +-------------------------------------------------------------------------- +ID unsigned int(10) Primary key +STATION_NAME char(64) from STATIONS.NAME +MATRIX_NUM int(11) from MATRICES.MATRIX +VGUEST_TYPE int(11) +NUMBER int(11) +ENGINE_NUM int(11) +DEVICE_NUM int(11) +SURFACE_NUM int(11) +RELAY_NUM int(11) +BUSS_NUM int(11) + diff --git a/docs/tables/web_connections.txt b/docs/tables/web_connections.txt new file mode 100644 index 00000000..5da2cbdf --- /dev/null +++ b/docs/tables/web_connections.txt @@ -0,0 +1,11 @@ + WEB_CONNECTIONS Table Layout for Rivendell + +The WEB_CONNECTIONS table holds data concerning each authenticated web +browser connection. + +FIELD NAME TYPE REMARKS +-------------------------------------------------------------------------- +SESSION_ID unsigned int(10) Primary key +LOGIN_NAME char(255) From USERS.LOGIN_NAME +IP_ADDRESS char(16) +TIMESTAMP datetime diff --git a/docs/web_api.odt b/docs/web_api.odt new file mode 100644 index 0000000000000000000000000000000000000000..8ad687f506b7c0558fc3347d2b640de18f02f8d0 GIT binary patch literal 20514 zcmb5W1z26ZvOkPd++B+lch}->#oad!8+Rzh-QC@advSLyR$Pm_Q|#M)<(%_B_uTv4 zyPhYDtjSD%lgT72S!A}7EF=^r7}z^7u(GfaQT;(yL@F>au-^$p0<*QW1vq=y1B~qL zZ7fZUoGpQNOs;mOj6fqNOD9I4J;2TsXyRfEuybZ~2Dm#b{Xdm`^X0A!fdT{jo&Kl{ z;B3U`ZfnE;5p*MU1vol^suLh%VPqyF1=yJYO)c%r1<2G?B^bELJ_^F~1I^4VO#r-q zBQSteF(L(t+Bxz5StLN_;%LYFhc3K!Mz#PaUS|{De^rY2U%7ez0Q!^SZewX@EkI`B z>}=1=#N_7Y#^}bz2y`@OV&UQ8Vfv$#>@O%&lYj8pyExkX!DVW~1h4`8ZnhH>3nL5D z-@Lyy{NF0|oA+N;0s?{m0Q%jAKb!am94j+3JJX-fe<PVYnwr}Dga2O|0ODn1GG{V1 zayDXcwFJ14lac;q$A2+6E1BTm*8Q!9ApalAm^cFd=wSwsFhG!%nT45wnTvsiS(Sy0 zmz9T?gO#7@Kk)IJn(+QDz{bGB3X)M}VdZ6E<7MIIXZpMFPXvIer8B6L8BARq|3DH{ zVii+mVV2_HmS<yA`K$W>!u0>jns}Jl0GtFlxc-g(FZ!R%<^VeY2m<IRC}(Nx2vGdP zlbF~T*(ucQEZs@}g=k>!2($v2I5V-aGuyIIh`3nVm@;rM|J~MqR`k1_e^>}qse~iI zlvL6NVB`d}`=gD27yOC-507<n1~t>k+0umc55qYd8QTCDOn@$S&H`kttYm*uEp3g= z|3L)}g+Ew<#=n*NoA+<3{l9Rsu>HkqZ{%oX?r3Ch@i#XY>)%CgKu6QRsjMt)9Dhle zSb#)KoB@u1m$9&Ov9SMDXa}@oaI>&<1~}OpnSk{AFT8B5p!%8q@);K=P%WkaGfO*= zMgGwI_dpaNleRMhlCu2o*jWE}Z2wD8_TRPrHClLoYxK{jfAq^A<Uc2?ckkZ)G4p{Y zyMJ7WpqvxH`M0Y&{hqKov^SiVxlw()y2y6iASi5?nc;{;Wn@JmAPduuGiq?A#TPs& zc)CA-rXy$}+$7{!5MX&2s%lsUb^&qhI_b$B?%-vd5}Wm3+V`@)ATsYdx*iKe@g+^I zr|gk%ac5nD;lGEGhWf6`jw>2-z~-rUB;oqBAe(4II;+b?5h27SH{Ff9yVp3lQbJHx ze=@3U|LAx;5fw%-e`H+CZJ?W7kgj&TxVSifbGA1F_A_xR+9gTgWdV!Kj%W#|ZlG|I z(W((;{-n*VNq;wETGxF-o{)0|xL!eIN`hraT35@XW6&hqb~_B%N$N8u;5eW5dh^|< z5;&(bG>Pn(AgT{Pj27a#PH)UO>I~bNxHGiU{o%8hmqx<w?V#1w!aMQcwpstU1z7y3 z=liTX{>vgd;(cJE$#gaw4`j!Vkw3McbhV`_#DKRmKz2){4>CB`+-EdUaM_#E*db^P zH5v5`_SoLP=p2=O?x-c!tuL#{s-Oj_Y2s(Zwq#m{R}K@?@xa91`=52{bnTiGR1l*> zGFDB_rX}hj-%xA8p55b5vGD^wF}@07vArU&;3t%=nPwEQQq30->lhg?Q^!l48Mo3O zGxVo?7wRBMK}J9<@3XF6gs<xSDoIMpjOvQ1M_qFRiL-&7(!O%+>GA-+J-D;P-WE%3 z7Mk%nME!-Cka=J*^1BCSy`TQ|#4vMXL>hYdt6zDMv;dDGW<D+8xqnlIkTt<8lu9Z2 ztQIb`tufm%b`xcMTt_Ydpl@)I=Db^ygL|A0TTS}9ODgh`DuyBTt->34Sf(?I%S@$A z7KI6zA2#F{nqYt!y>|?WvGAo>zBnwG?3tZf9VbbZOSOnY_j15$VWFQ8ssY=h7Wq-> z4QTQBK8=%ijfhJ<$AY!A)w16YjnBF++$cK)&;(M+pkbb;8e#OB6BLAw5VB|ruo5%y z&ZQvBBp`%gVDpEkqS|5~gO~cLD-5@_I;uE@#R`8CGlpK~3@)NeVb`{WPZZh8^)B4& zx@Ly5tlisWZv91^c*9}t7(3ieangbAf*;QSCbSgAPlrA92AQq5^oBoR_A`{V>C2Jg zYd(XGW}i_*u;KoP8XdOL8pXMi5K`(g{j#8=_`-1<qyf?7(Wdu|XW*`F4a&6iG828D zS(}*-Ee>=uvqDbci2xcfDA)l<)R7W~=s0NPTiLF3FNcY{oe@F+k>xWZ#832@p+_!H zwP*Z;sl{3Zf%P&U$+#eVH~Yo=Ew~I)#6sf3h-)sgJRP?gg|sqP4jI1)ShqV#s5r^o zz<*-ncxmd#x|a68ryL80tb8ec5;WrLOter|A8$5L5->e-C2D}pErnuK@D*Uv8&g^y z7N~Gti*;=OHN72QHa|m)Hn;OCw(VZDB=KGfT12K8TOHeG((%f$>}f*J%^V%ex#jy{ zlNMf<OVQX}AzfI8JOb9`R4XbEhI~Ia!}k}qpb>q@PwFW$ts4~ZXP7#uVMm<}`g*Eu z+}L!zDRn+^7z0}+P670=QZ-AvS#jK{$5kf|ry`z$Ba}Swn>f^k%C979&xy!U9lcX0 zB@LZ62y=`I)Dz#3b+T1OmB~5NzK7-0L0`CnX>}$L*V#*%hbf;V{jA%5o-o_vJ5lz& zCE_b^;#s~4>K1Q>Lzl4q0EzmOuNLo3elyTkvQ%BYg>)y&A?k(DDBph@_XlTWa>A;E zn1pXr-ZkI{dStJtUF8%fhA^2f5;F2sGqRi`wJ1DYZDK~S&_wt^8!)migWR}Tlo=-j zo&WCERqW@OUm!)`R5-C3QLRi{3E5%FlZm{``4sAWdsi6y8;p`H?7IV)a7Z0!Ffa=; zFtGoAQbqtx$|gWN=ih5h(42g#x8k_N>*_P5k;|`E5})XjN1@X+Ra;^z?Mf$!BbnT) zNR{L`LqXw`PKKrL&7*jY;vw&A*GU29o>YNA<4^WO%!*Y2TiDU5THd}g3Td;stCLCf z0v<_artugfPgek3DZyE5W^a*dc0})Rd$*eF?IuGog9g1l-ep8zXo6O{)hzEbIIj*{ zb!NdLRa2hcVSZVvMtY0iUJ|9=p=_y#xn7WtL7W#)SL#9t{-g7EZto`OjmlE0ohG{d z@Tr+|IsA~RWTZ=mqmdQ{N2`aMG~(M`Hx-5n=iS=@<%UEKx^*@2CkLM^W392TGCxmG zE1%VwjtASxboKSshd*r?jsTk*kdhkWi{Mq?ccy8fjfxCdxA`UG&I_(`+QgeNW#^$S zapY6_ip+awNk)e*K4LFQG3BH2a7yi{xgR?^gVMulkVS`0&u%`e5bVfjq+i1HxDloI zy|x;<lz5}8S0=obef!6)XBpv&_WDZ3c9q(;s+nD)l^d>{pV=@G@bmV*PwvH+%5)Ch z4tyxda}|MZr0&rmEcV?rkxbQ5C{@es^EFXf_dNUv^CEc&&Dft?Ti4|vJtHSO2Qh_< z8(696sm`*g%tgP!Qhz}7LFDV+%AGO8+-WtR;1Nd_L0x+-4Qq+MaJ8W4rA#%v_tTin z=N3L<M!Lc{k`{Q?j^=*gu^_Uyfrx02B3U^%stf`K4-#}pXFGgW$1)Xu#JxpIA9&ta z{ViQp2VuPBLZ!T5Y9!r*CfsLqrIP)1nj4ymtX207f&DBNx>ppon-{tXF}P$?>ax8F zpu*eFH^j`Y+O<V0+ci#13$Q$RVoX_29`Mqkt7S&a+nry#I1XhQT~%Dpz5?KR5lolo zi&ShsiAJfC*6wXB>q<qKr#XC%8ANS4S0^lW(nXPYh&u)m^n!z3YlJbNvf+X+kRoq` zN^Lo;D)pfH5br&6PCT)Yf&z~P4f4#6U;^4Vnm3lcRpi(%D}(yZUW~NuYtQ$RY=w_s z8JDpgbBd%W9f>}sk9@99T^1%9+%<s<*mse4X@xo$yV9@>)0eT(g!ljc_$VKDDS6rM ztz``l?{8gPa9+rw(GU-Ben44S^=d(VjdNpNrY*6?!_#AAm|s3VLvYl<I)V|57;WhD zt#QUzj7-%luTmiRdS}1H;j<fw47EWf*Cf_Q7^KqV1#R{zg89z^{mVK>3)x9u_Z#c= z7C6&!Qp{nsR?wSL5!77PG;dUXs6xFcClZ~05vn$rTlI5aK$^RB|D;@%&A?!IR8AJq zr8@E!r1Q<F;1D12&E|0IWnb_(If!R?&^1ITC7tbH=|?#W;*Vc3bKu6iTlXBYGk6%! z&gRlyH}$(O^(IpASx%L@)%tU8E^ZuK`Di6=*K$97vW~+z>xr^pvB;Tzp?UG#kGQ!y zoT24Ijl9wG>?42u*sQV~87R8<;`>c+KighlW)pO)O+&_<!PsBLsG>?=#dtUjoG^$+ zEUi--L(v#)a;!V~=I_uH*<&0?LX?4*FS+mSVKU5$j=JRbmdO&L+e1@-4nLVjq@kL& zB{@%cSwOol`Grn%Uvhr?>UTavG&#<1xbtcMnR*v~GR9lO-gmdnp9+ge!^W4dE;l@i z@Y4WHNjONPBs^+c`FH*wBC0IA@CsNy8usM}ZT>3a8(7|8%WebEZbAFuvS;u)@IZwQ zoLQVmDT)u?J#glm2$S592KJ+P5B^S*-8h-fFrAwfY!}caSznmA&k?V*GTlIwb`WL% zPl|Vs$8RA%A_HbNNUh-+Ow%t@!pPtJZ)-QVCq=Ly*moJ;k4XucZoFLAZpPAa3t#E= zJjR{FXD46l_0&6d(zz>7x<OBkK&z(i??M<blf|W8KvQLc&~^~LduV>w%>z>CJ4m7W z-wL_@0Y7Z+unwYJ|EBym3W0?FWHG#m{SSN;oj>I2S*hFjrWEJbc$iwR1$x{k);x@4 z&n7(v)&|`H6ojnj_Z}U3n{boR{E8QdiTiNbpRf3P>J_u8+|Nd?p{DpBpHrx^y)~Hg z!!_-pOVT>&xTkLPdcul9eaW7sOTh-m{azA}`%B5DNR=T!EEOgf9MuK=YH}=qg0$}Z z)q|MvUplj7JCu%de~Z;HeBv2(;KP1cClzi<*hFt#{|Bltf}Nx|`{DMDeN2`MDD%*4 zDsJH${+`FYeK<kYV-J6ndC%-k(MG|ypQ4SObhw|ywc3p93F>ftMq-MwTZ-=ldRmIH z;lGwaSCw%M(vfe)dUQ>3xNO2zl?f=?%b$AqTU%|znYmI=&A|Nh{(RMq5qaIWeWozU zMYTa#{fDOu?uUG#;{Ny-=p>4O;sp!N6o&VBkUI#8bs7=paRw1bm+c|jP?t>?Q=LuM zexim&9}g~M{K=;Z4?@v?ViN=dGlikchN@`8I6UG<qQ4hHqVMQ?;N|b&>#n8g>pt?h z^|#%5J|h0vzDblYD$Xu^yqbJZU(HWh^<*0uk@fkWMp~eJe$?ft6u0U6xsy7kyMH~| z6h<Z%nxf4a1*@TW<8w_uzPUKai00yry>-9y|1e?&HOPqK(Nvs@29y4Xs!shd<(bG( zRfbt8su8m9%Aa@k<v*Gf`zsHBf-CB_rWUO-Y%jnF*Ab_=2p8VK8c&3P<0*$mcV|%= z#;S009$<h)cR!3chj(4j8l4r9^)4!krPDk=fNx(wH?Xmk{cD)>XAwC<PnkbeZT3A! z)1{XAVmhk6QeXTU0x|DP4pjPKy2I`M?HW8E;lKG`lW$;Uk~~&z)`t*jFxMlc#uoT= zLv^BQf?!n!w(X!lTy%6d1=5p)$NAh(l^G9XWzznt+Ekr!gDwg0q<c6@?8o9TgUPk# z!S}1W1V4zS!!@61+(s5!d{Clu9Ox@~&<zjf=IZ|$;Rf~s#$hea!>^tHAtLyMZ{(xp zge10ivy9!Mxpuyh2hK}|t@h|ifhieE{#a+8d8=SrSUFtnY1RJa$k)Y;!{K<YgO*b* z4Zy~)O(AJ^tWPVxn%{9`u{zt3^1Y5!YIcWI((UNQTtcdwxGp+=a)zB%D~6MEe3m|- zozC52R(Zt0d!NZvneeg|OyGs=tPn;Vv8%h$yfP`suKJON5L<*J|1^gJ4xvdhJYC|s zv@FTmJPe{ln9E);EO(W=t7+tsptTX}USq7SqwDm!`>j#nHD=A)_q+ZH8LFqvP-K%G z0X(~(5;RIUWrr99#S6+zNt)3~>l})e_suV{+UcMo3kP`{w~m7>9J-njXm2K9SO1of zclx(@0#g3Z1JK*C?go%#QC!>C#S5QeN$U>F)P1bT$)|<cOo}f&{J~Td(O&8slZb41 zTYjB}ZB+)`$g%=IQSC`OFA84;ebWe(rmP`2irnpp72S%XtW5Wwv>~HYOyzuZ>ST%@ z8A2K!*+*NU9;{*+!bNmo1CO*j-#41ay(1PX<h(9aytBI7#>3Z`{8%*Qnm`+xB+>n1 zoo7J_?Xu(KoLw=FH6~_&<`{sqDAsjUpGMY0H`8<zWI+?})ZP9#A#hPKM)FGXg9Pkt zG0C<!zHBPit)GWpfI#W_i=8PRC$S|NgWSUg=NyG*d|qLChOcuK1>K%9)<>CE+p=&N zSz7O)qgyyKuicvKb^$eUf#@%Ya~#jiVT=-;ZX?zHkd%kwyulB_txEn=uGI`#D!qCS zqA$B<740JO!R7FsJ?7JW6@U*is13xPXY<K?j7ry08_qW;yT#<%WU1ctd3de(c-Rzg zr^slnQ(u<ji`R#Z9*lc>k`P*UT-y|=n?vI+C%@@^9Gc!(VD$HCx^6mP+X{aETDn|g znwN7)HQjA^YEQ8Jl`G*KWv$yJ>6T!K9pqj#S!X6*t6r%$5`9_NYObxvU~lvBxD49% z`ShgXB*Zq+_KvfjoS(+EP=|*Z5tg7cuNA&nK;TVIw=qD9Lw-oKKZiQ{>8T~u47t<B zS(=5gkG3xEO`@5d(!;c^%=MY*V40?LzNc%6wp1;M7WGJDp7s|?3yECjhsQ71aSg^$ za;u;Zb^|JYo?3drj=qE=(|jz!w7)RB@_}G=hnSLYh!}WdQ5#GKRWJcxhlT<~IG)Fl z*(Tk5J6%Zx`V<Y9%b^GD%gC*8qNj*R#xt5aHAxRmA&#L1D!>_5ru|C6EpS`Gr$3t# zS+suc*A<Z#4!lvE6Wz>({4w<5!ThQ`qN(Cwa%$M)ARM(t*Ep=|;qXohX4QG4wvkvx zXu{5KSM!ExQ(o8)7W;+efZT+_>q`U4QIXt;Qud5V{0i=5eE}o<+fV&3xuI{_hvnra z%G<`CNvX2zigv!ADh-B+#8e2o-dLM`qwKZL#Vi<ICIW45I^)^gzQJ9R-FS~tJv)X7 z1Tm>TIu{LdI<xdDXkafvv8`T1OH>%p)*&$vve@c*iCYEgQiM~YTfK>GUnj`AW-r^H zX)SrrUZ|0+7=)34w?QIwpaYqv{XU7@kP+f|5feV|oWDVSIM91wP2+d3Mi6v($%qlW z%wzIab<?dFl*BaA-c23j=j@s)>2AOZN!xktPa<hSVpWBj)%T`bG@*(wD&_KSu3?N@ zvqQ^)Hw*409pqih-i5-9uY~z7Ih<v-bo@fgHGKU6YWJ%t#Ec&cQr8VusgqKxV3`Rt z;b0{O^6^(X^dBuM-LP5J$>sbSh-sR~_&UB0(G{BIsbEx7*r)=s5G&Jw8_MFCd~Jni zZNu-hW41GIs$x&&;3s}`yBQyeC3Z$syx4IYg0o80OJ?n&sMz%vki&GYGG{tzA9$2b ztS*qGK9QKmAem6qU_l1;%!$q1gGB`yrw@}}!#5y>QVVuRvyrFo!^jqByS;`GT<w}X zBd(pZM1M<rDkgIQY9GKpbK8x=kY2D@x~o*++!I8S*%go5+7!RHaynpx>ZLY=|K$^{ zpGnzW!{c^lRT{Oci8A;=u}J3Zf}w3UH^wax__Y3|G|b68hROIt3^$<|nddGaba@@# zpsQ@BU!mb7CndrvIhtD6EdC;1n}%Dwj)GUcX*XrCsswN;Pa6Cj8FtkEv&~NgOu+Y> zs>M^c?ivoMOp08)<=hqgyWso86DyT^>s6wL!LE<Q!sQ-}0-A(sGZ~xCnThQ!;w2NR zdJXC^n=`#WO>i9Ao17T#7JeZ)^lJ~paQQDYKEMaD>m+$&`Pe(koSM8;eg-8mB@*qJ zm<<UN?Q_dIu-W~Cr)Sdi55&?xEe4zKefiS`nXkjQ-O%?n-bs&fWbRsh-SLJCQ$_Fk zj;oz_6*fdckkgIXRHDg7=P1QPF8<mj*82)_w2;|^gQ*~DyoagG_C-xkL8Ov^m9tdn z&5&qg(dxVM_DSTIxC~D20S_89s`A*)dS}B7)WbbDgwX2z{B43t3k7=W#eP#>k6%8$ zEFxrm#mPgdW;ug343WshZ0;Iz{8#po;}RO`^g_z|4%hfmqF4BKBBBkIIBTQ@BsteO z;1P|r-w0+g9)#tt+z<ptbjc6lpAFNB=<NlLlJ9?@8EoO0n|~K6Ey`|0wK^$gC|#Cd z1HPZT%4h*Snlc7zx6g^Y0FUxzkT&Z1;R*_Kl@;_UIH)R5#JB8=(z~PxO>Z!8gCG-| z=A^9@;kBvg<YEfdn0wAF>q9BLVsz77Jqy+^>=L7lzfp+>D?p=GSz+e56zbO4%+T-j zeZ_Kwxt0%nSJ*r3CY733C5+$9?RT?7nbZWu&Wjmx!zW8tB=c)6DKeGfMb)-I`qvsq zj3ekiADc@0B5jMtSk{x)A6cLhQs`SSewmP-fIY-SSf$G2yG>d!b%_8=Z5y34myOBo zd&!(t2Va&26pJZXzLRUcFgH8P?D}b7=2O}Zsb<lGE6UWSW>m6ruFxt*U{-*TwGWPR zDh#-o?r__$uE2I95l3ka7GqkFH)1Yr^<gf>2QrtYzZxnf>FG($bCw4P&p#iDoT#ch zzpta5G*t4*v30RJ$lebtqX<g8Q&JLfQYL_>#jkP>@sEemf)^DQhfMqhB71$ug{LJf zb_S4%OVNz<SD*?+%k@(_Hx#S7@^whNI?;CF!J{i6ScHkSOEbCG<x0!kER3Ol$=Blj z<l1srZ&A#64AWXME{L2F;GtBx&8F&Ns~}@0?xswswfg=Ae^5m?E-F%actUK<KZ24I zK}RH=S4CL5j0b(b>1JCiRqNKoq;1o-AEQ0$1{xS()FV5~S?=E)XVSA`D0RWPt@e@g zE;^F4bW3MULrqOY)zW%BaIdh~0|Ay^Zzh9%R2j7+NHnqaNZvvbzr5K#_b&MKwPDsr z<jRc;gF9U~y>OY8f~__bOoXYb08K#{OP74%Gd$GIxupBrEdBcp?mpnX>AT>I5`GrG zGM<=e2r++_o5NeMNrb|L^};FSbc_LIo><tWh|cDYAviXvCPY~lyvNBs<k8nt=WgWq zqxz0bA!6h6d%Fmvy9kG8WO4Eh=J<#ioi2)61)DY3r}6F;oSZGY7}gk|x=_<o$60Ka zqPdP*?%>C)5Fg(2w!S+zvs{~rybq_z_k^RiJUxfDUH1<`anEQH*FC=KSl7^d&ur;h zTzvTak;Hht^_5J?ts`6f<Lfm3S7oyu$4G59yQeILrliF?^vIJ&0*LB2NIq6EyeFnX z#UHkx3ZH{TJwrRzw$?0G&jfGV`kqE`%nWbUdCo;`?K=D<WgBoIA21P5q1iDHF;%NW z-08P|J!Qv11shW3x@n5OAe%6@<<>*H>HFCV_>wdY6>M3I4pI|-;@u1RfY(~QG9K0N z^O1<yhk#WqRT7AAJ_fr$68S;Tb$ubvP8dUO+97&RSkUIPuz`B9)K$R^1VG2doz=w0 zUf+<YVcNVA{<U70@eK!~I~vw!dWg@eHmIbT`&(5RNnv6(y_mx2%8svA4EI*R<o8+A zPDyoZMair)BXj1Jo#A6;bFM}5dOU)a`yc4rwsn++U1Q1J7o0kvA<An)K15&(hj`jR z*}rOaY;ztN#b))eK=7>`*UY-PvT(1E)1<(@`+HVx&w8@XfN0{cNTj=_eHzlzL>$`O z5Sq#$cz9ULduuoEk7uqSa-=daSNeG@T%>c|S+tW}C%Wn#A21xM%H;c`;eX9wsK9ls z9tt)Mb%aO*`;m|GPM~3LNxe!E?h=vo<zU=wWb5$q`aA;a?z!#QAWaqPbMwNYVI8!f ze|6)r{!sq-F&KS&oZDKey1Ur@qS@=DJ0@~VllZI`Zb3L}p^)#8CBBig&kI|@(@hLP z0aHC5yT^X|p-Qi{bl$Ii2yqx;L9ZR2&05NhgNKTHA9}CHqJ@tl2JT!)GG_<H@AY%o z#sQwPTt!}c{zkqPSMWu)T-(W}fUv@@U&--4a1EKy?{h%i;CsavqBm9m%;iXgt$nwO z>&;p!QJ9N4HQ`y}+G;-g`;6c_bcU5pzmk&!8oshq$qc6(@*=Iyj};YJSsWL3$pbxW zBJj_Ns<09%9e9Bvg5uv2yo?Zhscw6F6xWtET05SYPB!fhlIz*-2vql&#*Hd?Fn(M? zRLwSijPz_+n9EzJMG@P9W$#wz!aC8p@?;{;VmR+NSJALVfJk7UH$Q`MZ}HBC72B@L zuC(ta5<m&IarXW?n<dDMjpCM%STdHwK%pQkEi?*7KWy@oMu@inC<-H5SkPt3FQxe| ze(3C_;i;cu*3XIHHPJah41U<Mv}Q<HD)%{1jAGHqapQ<3F}NSiktyGvbe}EUP1kQk zjizdQtPOTupb%vwW#+&QreHUs>TOfFS0+|Y`(-1Iq6p*DOAil?$(LSzpnqTB{Re9n zv{%4TRzj81b>|$7t(4qrq%-Bw@hrC@IPr48=w_bR`N@cQFAP)nHdMIfp~O+d45AB? z1RKv5EBnWDN49+(jSQZc#vkJzN7fUW^=)&A^0O9I>`vJmL1vRnTIPHF>#S^E8fkej zwpFf0a_^{rQktP_CoI6TiHjy3{bH3Sk9@si6%R<b+h&EEkT$YS>wPcd2Eg<5Q`Xij zws2pM8ibVLxQAmnw2D{2rm#21AXj=nlO!ecX^gcH?0oXhoy&?MBFO2Y^7a-}jQ?x! zB$-I70i?Tlh=%)7<&M&~F!!j|&rzPcPn^>{ZZGP5S8(PBfivE(YFyb^Y*$+Qc|)Rh zJj?Bug?bw)3-&)wXSF7?w1@UhH7?@2@l_8i>Qx&AFKRj558QGFE8#G-w?FC9tGz?i ze%i)Fnp{~A#G?mdMF^8Bet~0X4{S>KRndy4l-VmrLg)AT=-HOBQ5$gArKt0=9yqz4 zBQ0Mmu2w7P2X8=gIwFhauo8GS`Z7hbf*l0!GujLjYS$sOV{ttZ?^=`y3rI*89h^*V z%@2~8-dsjSCD^L-S&c#59ge=_frD%ntqOCA9v9s_c+cF=+r04<gRL)jUAFNeV~KKK zXl7LTmG(35_4IH^0Akx%vs(;c0RkdoDG#}!W`gHS7oW`<S@_2T1#Qq+9e}tIkXN?l zX{e0IXIVz$ZpncFe<Apc(GePi*_*8#CKZH<5;_=ovf?SyZxvn=Vn@f{`)$Y5a$c32 zB$U#VQC}@?rySnMODhPqx=KW<t474IrOv<HR+Z~=#KAVGTgf2^wZ3)R8|X2>!{I%3 zohU8~PkSohjaykmO<3jJd|^~Qm~Zc=ywMZVK^w7cB;x@|vUfyZCvwAW)zF-)wy;59 zs<Cj+KcKDE)zx!?27M5BpE?nMXzR`t`VF%YDPF|>F1rgN0Vm$ra|TdTBj5go(NjuI zJm#WUlS%&+x-;CX$6W92i}^S=jtgT6Ek2^Z?-K(N@N?(h9UFF&6^;APMtH_2nl038 zQm5lDqjV`_5}jPl<@aXvm+NwRZCp!9XYBF?WvdxW2yTu>o(Ve{C&Q0s^c)5&=GsyC z+pr?pNLe7i2GHb8r#B>e&nOkq?j}g!`Vbkgb6bu*fZqGL+Xx}ldT5F$N;3GJ_U_;5 z!AgS7;Gs9gAvr6za|_Li^a;g~4s0R<(0_g7$cp^1v+hT<tJ73e5FEiVjW?j{TsZ-^ zIx9IEWGLOE&p3}_c+~VhsJw?hi-LS9@OfIhrh>HV__nQLctb}VBMOCCMO6x@Z=!B+ z652=ev>+^VejsnaQmF=A&&Jj6#9X}LmD!-9g)|g7QVRVGn;XNFg$gytWd*|6LKos5 z@1wlH=I`Z@-FBxEloP+FzjoLoZZ1!ag1uLoVLNTlO$5{ukwva0{ycim2`oN(?!;)Q zKdQA@-nXfS4-6L9YB{}gej*~)%5+Hd*rm=0kZA;p)VS$$Um?;66sU1?JB->so;v3& z&%$MiDJgrcK3WfFW6Ark>x3-SgE`hvGb`v?*llk^rk4l>v(2c7rT*xEFp(*DJ74b3 zb}VAen@Fg_n=o4`(tDq#5(!O0v?MP6&8}<&ZwneT_J}>tq^3ZUC@UO5i&kc)3&5WV zVYxY`3d%~#wY9-&h|=_Lifhfat)a89OqWoZ=Deb_AUJuqEI}{a=GIA&b!hi)If6g# zYoNO_b^~0cwCprCqH4K6r={NvP6M>)^<O)gyCi7+<)|7uR-szI>~5q~Vxs_hL!#l_ z*dt+y3?=qL96!sf2U=R%E&K1~dxpH!r4ieOcZA}YDiJX0`P^SoTaIt35*>9Lo}eVj zWLnL_!h=&dkz0dFE&`HJdYUGMDO_mMqh+z^Edq;;Yl+c8pH*ypDKh=0&8_jkz2%$8 zz_Y#%Prep>Kt(!;-bv6_aicKcS|!2BH$9+Zd&3<sSh|51DwbRPEat7G|I%Z4J2bFh zx+Go!N=GAg2(AeLkUyu<w+#d9PW-d}EEy1-Wwa2^_!>71YP&)*Wy6O`Q>`AMqI7y$ ze8Zar0JLa=>#ZbcHD3Bkji2khAOF2C;k)kl$W8uoh$4+)7C?10q;Nz-$zeI?08I#L z*5f<Xo4Mq0#46Q#rScS=q$2=*k!M<~a)+r#*?0D+V&#tUYS4pZnf{=1dCHSqTOqV< zRTG44C>5Y6{r5Ps0)dySCcxnO6lpWFThh%3?m>+PFP}U`f<;l=Qp;6$8ZbCX7u!mu zp;&L5brgqW@!s|&MHHy`>W3+B(0)3qrH~PD2~#%L$e#w`iIweZ<j*a|QQvB!|Fp@m zG;heAz<QGg!G*<x;3#B3aI~M|L2zNp%<ME8*;EZMT?v{w({zke?<RMmI#5|<Y;S@B zAtQE}gyFi_kdla!{JHY%_aA@x_h-=_!(kyTot@CqOPA(2!p5#&Fpt`C)UmE4k6ZeA z#8Ed^q8DMy=FcgoP;<Ca!h_zBGKt#0lrm97VagGdpYWgLtfxVq3H|n7qo7${N+gwr zE+ufGut>MAmzP|rj5ehZT*Ba+Y2e;vDdQC$Lw3aaxtw$r$izaa?|jpli;kSkhHc>+ zYFe{!)OXPOtbUExj52c+S`w()X-=^4RIv6VV=OBd)aT#^vxVUeQNh8zNM!t?WT)ad z(_q&<tm`TiPKJ1)!_OUW&*z3L{g!4u{!<-K7x}$_jEDU8cfuRwPh(yM3OT10T;VjX zj_WihNHsp5EvP`>me^M)hc8=r+n@z(tFTb?ekcN>Ji4NlY^4m+q;72#Xm{Dc09L@( zhY&)ymIeMJgHWGah@@?&y2CXkOCzZw5fGd*+G{$QCLWfO^L@j9r2ATu8a7h@P{Wz+ z0|coi_n75*MW!0eS*#wk!}`UjRdB|p1WcuadQ+bnt6k$~;M(0%44&JBfZq>Z{ZgB} z0$k7e86SGlL|-tK`FnZ?kLO`6Eyqev`D8%*tDo5%wTx^RI?>}nyUkof;R^VtnFO7| z0hNR_yP<0p*@@HZwjg(m_MjVccLYSm%VH}6wX(Dw>2(Ov`u2on<&}<cJ3{X30mG&A zrL4Kkxk9rU`yx7yrHnN_ZXp`$;KESf?})@1PR@N15Aa_O92^Xo4W&aU2ISIKVBQDI z^+OPy)_j>{Rh{JwMtH&czT8cKmNc_ym#pKyQ{s>^0Kq0|5Zg1|d1Vv2rNN6OF!P1B zfi(1NEby!GOS{Tg5YdYB&}zxkI|7&bb``FA9hZHNYP)34<LG9cW~B}DOr?@wU{!I= z2k4|GePfrgv-~X?4JMWrYquG&qD~-J0D+r%;Nd4Mge)X;-JbZhWVUGi88C0R{cWix zI^F(8tnbP*^m<ygLI~%){gkq-BXvGJ^zYX_HAQZqYeP?O_P)X+G9`+GHtjMWhGYS7 zh?Pl{{W|nxBakPmtceo7M?5R<-qVyeBq0{inPDMow8{i`h}XlzQoB$lIB!*8CdzFw z7quZFfi~=?q6t{}Lo>w~qFVh*Ds7F2rmF-E#aZjrbhbxT=teXM??CGwEow~qtl`Eq z<5cXbXI1f=>io3iQfbqxym!e5ry3MGSTmm<;MM52#44<384q@hlao_z?QrTR+>M*k zULSN4jOJxPoAUC;G?V#dQ>jMIow9{J{rTm>U?7`DKh68n1~qHYe5O(<-j`HmC68}P zQ@W53E~D4@p@9l%UYlEv=Bv7A?04l#aZya`sS@9N>*gt_d>=(gc&t2a=quZ*Pf-aG zr7a6veLV(Kt<PxBl*jQMe(7qx^{g{pTyH49kHlPj@qf1rIu0{B5AoNLn7>bGKe{l! zUqb-{`<-w>M`BbhTx^Z)j4W-On4JI4GTPgjhbbvYBEjRsgIJKHrNop$e+R+9z`@=@ zfO6&^vvI({Pzt5RgjL-$PqR+rE6b6^m(=!O48EP0?J#g=#Yp$RD|LE4sKXMS`$j6H zdz=HhM5Kt{DqQ{Akz~RtM5W_QscGU7DaAqmd5~gF#FP$>CmT^xroj8(6zWr!ef<17 zXPc?=1{~4e<UZc`JTQ6I^t!l8zKU@x(e8s?9Y5Fe9{HtvSwLK1(=-1^)jm8WTzw_k zK=v=7%lOwDqIP-ZQ}Vg|8Gs*jwV#Jfq0rYFmAjmQuM{r)dA~CIAu((rf55nIhqU+p zT1|mFR*NU&6Z$VY@5LAPKg+wBrFnn(TA7%NwxANa9m{=hd}=CccmB}7tmTj_Ic(iR zQ8sMj@|6lWncf~IES+U#VrA4M7h|%S@Nr!RNwru-X7I$q+L|SV#@Iu1m)qTo^ILvE z?FYji3Xu*6v$`Qs%W83R(T0I>jIoIHi`#2urfHSh;MOE5)?B+E*<-5GhjVdm2O~CK z?NP>hPZ?)}ztqFqBORnqr)ADJA<^WBE`MG{xA>ah5nX!ZS%-fZ-)c60{D9RIp%9i* zHgV+UGOj@t&SCqh8J3@Cpion$i_!7qJi2x#bU^GPIMSoK5oOO@m4Bv*w_|#4nIxl) zwo`6`PpP8R0Jt$qA)V%luA9j>|CVlcxsSy^kUzIq$pQYftOz_4QnYh9&q&=yr!poF z8;`}*hmvddmZ>u=S>z;4NGlE+w((zI>iBqxG_^UNdmWVUZfyXm8Ub4%1<yZqHr_C~ zZY8KA##|PD*Rl~1jkG3?ToDKb$lEDDzp#;p6ZqoX1<yFEhud?S!yF{wK{u5=_vJvn zJ+!duF#Lsgw5JED>gQax#ubb-ku%8;$?OBi7E;l8tz>^UBK|r)oyEmL0NR~iY}sbd zU5yqnEnm~%7HaU#=34m&S#s+S+ED4!@MhfY`G_G;ieVe+B4_1nVP>t0l;;{~)^P&u zGWl{+Si;LV(^P*+U1H{KI<9f@M16@-tpGi8{j-c_wz1}tnh(h`<LwwQ9f_?{<yl;g z?6cVIM>k<Zw9{^?je`7&X~GYmHe8|^a<ZW3OCs2t(HEAEwb;U9Z#|-7-g<VSH9295 z$5*+O&Lz`J>qO}qW6$~b((KW{P_R+c_;!X3mGB8V!v41-XXF_P&q1n75bT3gn}MlN zwuk~9z?UPao4*hM72iKXKK!Vaf5wHDx<tC0wEGqunL@WsnV$-vZrhKK4MRQ5o`jL6 z(OdV4OKbABR$wkYQ)M~PN#2L6OkB!$C(?ZhCtSnwJO_^e+u&<%WQu1H*3%Ev$ONmk z%aH8RnOyFqrfC|8;t1i($G%2(K3C+`Frk@Z>mUi-D&oRLOy)l}E&Sf3gR)1q6KS-T z3MY_83pLobjcOF!86Hnt_mxR6%ctASgDHbEp8qV1RX6u+PSJ;(;73B-dMV%{3ZfCr zd>NuOW9+D!XZ|pr7+oAuA%p8%b-uJg5pXd6XKzs0JGe!c1umNs9q4!AA)=e1Ic8!U zN{ixlBLa&=Y@sOaU<(mCmwkhs9$%VxCc(gAFDg5zjl?n|$N~JFmzgu!DE)Cb-*~tC zQYy#1pvk~37o`?;YP$F^A>u;HhC`_?g{7xSsYxYf9d^vqh_aja!%yu9Pqp4<LzG8n zK1p`mxGhYn;NUut8c(nCtiDOK%v~}ZmTS~L8)FdtXh`DiW<h-<9U<?0+A|$d(ZrCA z!|5wi`1k2h*GF`34x(HummAJvH;-aGdq<q5miB}prD>tGT+#_hht;g|L#87ru=;yU z#Z0z#?nKbUx@nU|QD7sT8C79kBM^I6+ZQ&iHW5er3nHH_24R#Y>T9aB2ig;EIeg70 zI?C~I)lI4V;vXKz_?)-9aU`;7SvbSGeRtvvYUZ{j*dsF$+|tS|*5%j5k}i}lTb+xM zQe!94C|!)KW;M?WQj6GC{fCCr-4c@&RQxee0<gTNvj~|2D!;@W)IW(rIcalnLrhan z;Atz5SQfPc`5H?a2!2@}#;M+4He1~l?+I|V8iIdPO!q3`-AUbYZQGjAN@c|Q%EKOE z)E>WB@?L+Op>|H_<hu{06v~Uj5~0NX`8w*>_PA9cijUYwFOFo0h@s1=+IIsrOWG|2 z4VGN(()1@a3!{}9NcrC-$E!bhzZ_qPdv14!&wToZd~_+7guGAwuHMa{(c|&yxQyZz z;_2e$^eimXPT^~MD@$8tOK-cyIVMiErxSWHZ}ZE6E=u1B7#xwou7}~0cro3GiqyNQ z<E{Z|UJHZ<KH(N2HGz~&19K^GdY@R>IFjt0nS~z;SELW$vHtyaw$AURkQ{s6u^*?V zbA^V!SJdCmb9>`}&fB?qqj2Sn9k}m_rAU$Mg5e)Q((STX(vu#ue%QeRzFtV0*7cqo z-D;v>8A9RNHYPk?->N8ujtU*7!$whstX1*8X(ZABX}%5>TkNskC2gMQpnbOf5J>iU z5s?s2tjV<VJ^2~EzQ!FZgG2rYP0IzJg{jXL<i$ivOs+99=%$0pI%}(ynU9!s=2O+< zhDd??Ye(DF0*AHGO>Fi>+qP*c`&9sacl~D_@@;fBv<40c2-_(ZG`O^tTW2PWMvi<~ zaJ`Lf;r)7ciWWNldkbJkwDyg~WW}c(h<q=m!sA~tN%%HX{fE7ZK+IL`Vfn1AZoRE< zi&wA(z*(tAjF{C4m5VU7vz}rI-4ye;xu5)11L>IAG2-ZGeB2e_Y5^FxDj$EE7Tyhi zs&7pUy-<(;%&6l=sb67l#i$ziVcXeADYM8te*8?$3m{=QaF`+Yv@Snw?&0>mA5map zTIs(1ha-I2#}tNTD+i38Z`zDz=37Xg$Fs+raGw#FZ|BhO8T5&8&(b>TAGrhVsn`ui zK3*OKsq6_{*||0Q37Qh$=4YxnV3iK6EHRk0;;={P-4bRmVSSjAr3^;i&9h0TUJZW7 zO~Lfqnt=lt@&ad?o5vQCuBU@NgTAy8<mT@}Vb=K(JWeXsm*;$GUML3clT1_GWctb9 z+Qi!k3X#<w3|<iU)6EZDf@;|;oX{<CPMA3wEo3`qZgY;3*kkKLAp;#Bg7T8MQv4*F zW_!WLxUZ?8a58x7*Txqq!WFKmUNn{qX54tmV2I^r6%z5;UUApNIhy1U<P5gAy%TC0 zCR|$DbZ{S7t%2xx+AaPBcO%v)B1+2bu=-ETT4T}i=t`nf+u-qJQ~v*4e<j@2i|Okl zOFkHomn0pTeT+Yky_410p5~|?4j36ZiY(-akLkY1q)503mMfHJ4Y-$bG<#f&^5n4~ z#X)(Ve?8`~1m@vW_4uUW8Nd`O(#VUQ1E3F`Wimad1$XS2sZ{g%>=ZW&$L2vZN#HKg zm1F14T!7Tq0lbXUZk2t-aL?OGD+6HSMiey`jFj&ot*;FKhH~Pf2mBAbYO?w%4!U0C zT!dGO7?dd$V%ns*;T=kG*MNVj@8nXR@Pz?w*BcKt^_sqGKbg8`F(H8oFew)gjK4-W z@kCAl%J?LYtHW0`#Gc1qf6Xg`E9_2LKCp`$^&-)z=e?c0+xX%lbmh$2b-&7wzpAJY zS;8y*Z;Mo?r@C5S4nX(2J8;d-<!x_tee>>W0gsYUfG|G-yncd}_2SAY%ukMxz?3Tg zknSgjmZ(d)w1IJzK+VVSvC3U~0-U!X?)EP!$--N?XbKxsRM%sE@HXLoajd_5GbgL? z?7mF?@)j>%*T$~#_*ts4SG>Ucxxd8aLq27!3c%H9tvPKVcoC(^b)5Es;5hs1FO|X# z)dh(_wrv5m>;7RM=3~|XD4*)OVJ*%Du6O3UX;k5&16^}x3<q~5l_9@SInT6UNIdO3 zgm;QVdH_$g;lU$vJ&+;x%z;tPIT+M5CkT{jRQ}fBcB$CgkZ})<k`U_k%q_dRogDLz z{@gEfl=R=$y-a9cfX~h|wVo2~`lNI+(_iBD3*8vjSc~7LejbIM|6qocX7gX@36IWd z^Z~|LjMujJYZcu?Yb;0O1-liPoo2Yfj_X`<mjQeMc+rGy1yo4f&=JK91+bpm{j`b0 zhWRT;q1p{6{R|MTm<s+7Iu11aurmg2DwqpVfgW8o!n$&*dT!z7JJ1httl2BwYQpoi z8swcHR~#4p<q9vJ`5Ncz;i4%?hMFb3O(FidR7%T~hGNPf<v#iVBzyCkn()B6BDw<g zwN3I5C7+PpbAg<uRrw}>lJd!9XSZfVY_b>f^hkJ7*y`6t&Sad=ifUA}MBK7-rCBr+ zxrMKM>WfP%qvz8Qt5t@rP*v7`(h2WKRR-iVyRr8SB?3LY)b@$Ly+3t)VE;%ZJ*tb% z5%KaEQ(ph5s1Tz$Alc>8m|bVzQMXPV+rpB77tdO7%Ne`)c`RS?GuJFQ70s$V7eVjS z!DM?{rU2ClXb}KJ5YPoJ=7NT-_v~qk^!=({&hV$UD~*!`%z_sq9~#ubJUcgK=BxX4 zms<sOSkf|?%Bsj4UCkd~EUjT3*v`lHu5Ldl*<(LX7BUQPUJjHK9!=y3d)ooR`FQO6 zCF8e3fs{{P+})8Jos>4jB1xwLy3E_x>a@t?MHAa{T!>H8w>3hCkVEb9-_||NxHJep zyiZ1#y*IW!Gd%UI!41s#+LdiW7A2z7HZs*K4b?IFm84Mfup*@DX>*21*)m8?<Mt{o zm0J2TGvVE57AmxUavPoMO=nTExJI>lT>bUVK2e)zG@0^o+{;S*#gmWO%Nu>*+}k>X zd&E_EmqY}f6@@rq;)Oi>>aICjt7#d;A0@rfnIZ1CZ<;QW%BS)_I@!AKA`ylEeDksI z-}g=JxA7-Ft88T|7F@2i;+xJWpoo5WHIB|`e;>*9(28~Hr^H4)B!7`c-Z^w#VScUD zV$&Y~B0xyW_NnDLdiFTaxI@q5o;9ZwIz{)pCpd~5?j=L281-a%1hrCg3jMW5Pjz(9 zCF(8m20P*93kgdiA9ip1w}7U|rr78z1XV7l&fH$K4TJV1zS>&*G^RS{#a2~<G0STr z!po?O+?6~%pV;fCZnO=VyL)>-Vd={qS$@zElm75ucbos09r9m$>qioJ{?;P5#dqtV zZ9AB>xPn-fh@t;~A0_iUbkWAh1Ly*Z9W^qs0GOB>no_3@cXy-qj&*k%A(_@dIDk<> zLXH`vmg0~@LUKi#jP!SR2aU&tIMAlWC5qQFgUJV{_Yc7XDhz{U=xSM*nR^NqYlX$v ze&FH0zL^{Tj?saAC)`7fs0zYL0;RvBzW)rQY`C}h4h;?l761tb_FEfUBRfkofRi($ zqp8_M!h~G_Giu;De-L2uhY%Aqv?KNCH>;d(j$ln_rmJ-H_0H%7^-qQ6M>%slRT69) z(G3}=Mufu=b)`M3>?Smnqf!=)hjhGcjNgh@c$a@P(UGJRU0MYc<<Pde+0pVCBnL5Y zA=*sU=Tp0<U-K)rll9DVJ4hi8HblRJBaRZWyxsN2=a~eZme%;>e4HEWaZf4`vBq1L zTL*8{q}&nGL>l)+C<;z)G|)MKuvI~JfGzp@6Hiax>GqIe$8118zu^U4^wf{_P{iV& z`kNg!XSx9!-bogoXC|I5vjdkK<cWrvtY?ZxZG0YY`>%{sZ+P3)4X$D~LX!pNzhd_r zu1M4*tN%9FpAq*U3;pB52jxV8c4n65f5k^Tu`<~M?Op6ak>)N;|GgZ^e~|kls@RE1 z#M0T;$lmFH5dKe~&Oo4zy^$Tj=Km=7JKovF$=Jy8e~=^m56XgKu+1F-PX9lWzdv{V zyLo<V`ak3SC#m1|{J%??*#JR-@&9bwKLdw<e^dK?{r=g6f7j5+#02zP0e=LeGnu$J zI{p>E2KhgPy8ZrW=j7}G3UmJ*>9(dV8?(cS-g#cljA;sNplBm$a^vqY_8VY~T|$bV z<jJL6Hj_Yyj<;I6K5mu@M`uv6yCoNFK|xAYtDyD0HH@1p$wBtu^!T8wq+Su=jt`BY zOhI2XU`O=)dc)N4&iB`Iv!YE~5u8>LeVL=O6vZwJxiLfnLM>~*i_)d>KuxZ(+Gb{G zlAL-4MNn3Q<2McMB)pm4L50QfGaG4S#}m^5FIF7jp!LG|*-7G#C+Ha=wRN`H=43Zu zcse;R@F!(*gZaSwf`Mk2nv^=-AS1oSSx-TLH_qVLPu97)h0VgBbadI4RqSxm5{ay6 zgR|TX?L2Yr6+YpM9A%|fNLvMYJ?J?eYW(LClKt0qVCkkYj|V@d$4kz#N_N)x6xY7- zBtL=Y(Dzmg&AoNLt`0y<4IL@BQz=nqCKsewwyZry)-I@W^iY&?x?zjE<vpI-FXAj& zD^PABdpX7l^k{u2n{*_x=*9`@{xVz-uQE0<pASp95t5l0Ikpgc`TzlaFur`VJjPF; zz$D&S!IxdEug+{vEK)9<TVO78M51ss1$a)$GqV!a4*hm>=>CgCmAz1gkitO)kToiZ zAh^QX2~g^7=6+92Dg8n4Gwb0Zvf?-p`aADKFRcPxPXEj<4sC)D^OwN-cAkmo<IVFH z(`^zT2{wE=!mT2F16UnTQcG0*g{LX90lYMC05pN>;e~qxo_+&4^cH45vpLPyKn9X$ zJ}O(nTfFBL-IxQ5g=!2i(5OAm&1{ivPu1&<vciwy8rO6vL@gp6{?cy#a>bb>h~iOp zv@b8$c2J(qI7)5=TSIF$S92svoG*GzKptXj<ynF<q+uuCf3e9%t&iHcXwFiFxzHCD zqw#ZfKXFNgM6M=k81gY``rsv5aZrjce~Ii5W7Lyjs4#S@X_Q=nog2OiMDt+2&bI!S zig7vqcBOuaF@c?1Y1`N_LmrMKFVofvhRHw-G|D~AfCCW=sc@1l8P+1G-oWBOJoU^Z zFB>ciKF&<T1H-_;(%9tuCNw~%%(6?Y0|ggVoJd4s>2hW3CpV4-DQj|7#dk33@K`c^ zX3Zy~XZ7={{$Pkfj#cW}HIc%f$vvQh@Qfu;;C~U(N0}GRncy+HVy*X}(%cC3mWw!s zhHrefPEn*dNje}%q_k~CJE%||5vwsVQtK@^^jX?A8PGYp@9T-j7f)8M=_OZnk;CKB z4Db@sDVMa7o%QF_R8$7a2{!q@V}!vJYW|q)rEHj#K;1`^=ulWW1D8IN*+hqn=LS%t zsAGjt^Y4p>mxU#1CrstcRg!rxicmz6zRqBNueY2zXb0!#%5xnI=A_G2gYlB|zEpKt z$tvQ-fG|(noWNXE`y*}O+B@<l-<!VZ1j1Q}G8O-*jwL)5tuUXMpG1#F_#aDR0sT>g zPQ+`>Ro{h!@G<Q}GZ0fmps&2J$S04o9dQpS_qar4D3+p!J9sb3`n{xUzfK2U17js< z_AHq-Nh+RL>7i0#Y33;BzO{eG$mA{Kr$&ZZZbRJVDpFcHV&(7YCaFJ&L6VITtk*9$ z<=Im*1FKU$Z$d$7wQ&waN>I-7&$nzy)k&Ao0`>*12Ro?m6u6fab3+##4tN5#tH#nb z%v;^g=vdV!&LMsVfn9z<o^Kw%m~j~Er|cR!1m5i<R1tQp=NOrLjEOKpnHP&iho)dq zP3i9xGHKqAlN^B6#P4XBB_?nL;1vPECy0{lh{ScSImCf4ckp!hlXYL@7bDB?rhSCo zkYJ-Dz;aMIsF7SO>fBbGikojFx-C#%VOtOTV1LC}fdXRgg{vN7!F-jyGG%g@NQZRU zJ^sIW_a@E$Qn^m}-TJoIQ?=i}owKiXe{!)b%a72Xc~*aV-W@o|=@D4on|5se)Cnck zF01}BE;TK2TmGXa=G^s`ci%P$=SNJNw`76h4F(yd?V773-G09m_q*~`zpc+U)M8cD z`|ndvTNd85Q}Fvb^|||-?lf<i+lO{sZ`^xHIyNiCZ=E3ftCnzw>t|zxE`~ln5uQ_0 zve9dnc9(Jgzw-f2a>;J<Jg;q-{Ud~V!Q!{xt7RnF*Ee4i&+5-#_AR^3JE`f_VJ?gC z_*nwg$D7O@uFYJUcepmGTBkS1c1P=E_SK$UX6~1B4@^`nn6mwN+UoeXz*X`_TfVQ{ zcP5g3g>=4>nsRjJP3xAur&(VKOj0(ScUR(AIkUw5pN9K(vmN^^efUQm!{ciEW8beI z`0?(TL7l{b9|!wC9yT@Dx8JZwp537COY)xz-X8fpp2tTSj&a)`>&{O2Q;{s8&u$R+ z%P=mE`SDTTM44*AzS<wht~-=hM!)c5|1kHL;Ji52#}>N`C!{kgod2V6{vPKi&6BSC z5+-q2c!@>tTD_yrd)5|~D|2>l@A3S4`+3Wb$kjj79!RE7t(um@_SWU0P8@KTOYxbf z?NwVtKD|*7%-Z`{SH;yTMd7P-#!+n-EAE;sw)J^uu8aLLP5t@6=FqPPnM+CxG_ISO zM5)Bov#-2m^?bLm?%LmXTx<&)eP$_mZxC0sE-<%is`mH$5r5i-&&Fr(Zz126nXBxi zW41hJv)z^dZq}oUg2LVs27jevnmSD8d1*04KB)zD!T)wtypd(xJ^NE})a_4m19xm( zr!1MQSGPa$k>JxG7uNaRWh;%BGUaKS5;mt%ZI;``#m&vN&F<2r_m`??Ec;pXF!50I z*DG(Iz6|>G#ZqedtFVhLt(;=U=M>jU&rbVpU-tg=ubcncJ^ouBJ@md}_dVN#uXw}% zbHobFIaur%+cEEWit~w$8L3-t&2m(I`N()p_GaPJepz3RwEtUw#QwiLsJR{=lgsD; zJcB7!57u1AcJ7HNu-)P78sezy>F1^oZ?^-RAZtUs^A0Nr+<h)0cKg(Yw9thXkuI+| zFERUkxZ&7zut~8iKi)daE_CXtu+7PJ@AoFMh0UH^epE1dQ=`^LwRqRY6sO#kYmYpC zx41@p_SdARjXBMoU!Ml>lulWfrdp&Tt8jA(r;XZKw|2gjd}`Gy*X%!ko%u5BE@wp7 z*F`%%nqEt^ymI{Cw7V(KPx1W-;QY$*<k`1~XpNokHwaxQJty@*(N}imwDg0Y;+Ch_ zYz!zisYsdNT+MIc?qJ%M-l&!$mo{M@Uk=m98_zcvmbbt8&T>ul==8;JR@6Eq*=|{J z?1zpRd+muBDFgO729NiucKkh4Sob?+&1_B)=WD0moW8}Dl{5RXq>`?vL^B_|u}f-E zPd)#O`WWH)Zl_GVCfxKY?l&mz-C1r?+8O@py7}gROrY?daLDO{F0d1{5P0-efHxzP z2m|gjwt#_-1Yjp_q3c3FObemK7sv!1Xaj01!gRr67x`!fP-hGQegR#Ee8vsBPUIPA z(9sJB&<|{$CL<1FfN8`vL5<M3NEi2XHOv&4!;$-!s1Dz1i`v75>12Q&<b&S-MA+|a zhuRxO=)~R?L+C8B$86Ulcg#>D7@?1W0n{}^fK^z`!RV;rHVo8NLxAU43`6d?5o?aT z1E%MYJ94<q0d?gNAlw1d9Mp~-Zj(TrGz6IFfN2t<qerYM$FZ1#==c$9%3my|AUc9D zQ?Pdh5k4|@#Pku4jv*{n!g2y~(GBVtB0v?;P((KoT_1801S;4O;FBkgVm`o|l?|j! O2nbgJ%ZDUy5Dx&Wz@i!e literal 0 HcmV?d00001 diff --git a/get_distro.sh b/get_distro.sh new file mode 100755 index 00000000..674b3482 --- /dev/null +++ b/get_distro.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# get_distro.sh +# +# Try to determine the distribution name and version of the host machine. +# Used as part of the AR_GET_DISTRO() macro. +# +# (C) Copyright 2007 Fred Gleason <fredg@salemradiolabs.com> +# +# 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +case "$1" in + NAME) + if test -f /etc/SuSE-release ; then + echo -n "SuSE" + exit 0 + fi + if test -f /etc/debian_version ; then + echo -n "Debian" + exit 0 + fi + if test -f /etc/redhat-release ; then + echo -n "RedHat" + exit 0 + fi + echo -n "unknown" + ;; + VERSION) + if test -f /etc/SuSE-release ; then + cat /etc/SuSE-release | sed "/SE/ d;s/VERSION = //" + exit 0 + fi + if test -f /etc/debian_version ; then + cat /etc/debian_version + exit 0 + fi + if test -f /etc/redhat-release ; then + awk '/release/ {print $3}' /etc/redhat-release + fi + ;; + MAJOR) + if test -f /etc/SuSE-release ; then + cat /etc/SuSE-release | sed "/SE/ d;s/VERSION = //" | awk -F '.' '{print $1}' + exit 0 + fi + if test -f /etc/debian_version ; then + cat /etc/debian_version | awk -F '.' '{print $1}' + exit 0 + fi + if test -f /etc/redhat-release ; then + awk '/release/ {print $3}' /etc/redhat-release | awk -F '.' '{print $1}' + fi + ;; + MINOR) + if test -f /etc/SuSE-release ; then + cat /etc/SuSE-release | sed "/SE/ d;s/VERSION = //" | awk -F '.' '{print $2}' + exit 0 + fi + if test -f /etc/debian_version ; then + cat /etc/debian_version | awk -F '.' '{print $2}' + exit 0 + fi + if test -f /etc/redhat-release ; then + awk '/release/ {print $3}' /etc/redhat-release | awk -F '.' '{print $2}' + fi + ;; +esac + + +# End of get_distro.sh diff --git a/get_target.sh b/get_target.sh new file mode 100755 index 00000000..272538d1 --- /dev/null +++ b/get_target.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# get_target.sh +# +# Return machine target information from gcc(1) +# Used as part of the AR_GCC_TARGET() macro. +# +# (C) Copyright 2006 Fred Gleason <fredg@salemradiolabs.com> +# +# 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +$1 -dumpmachine > ./gcc_arch + +case "$3" in + arch) + $2 -F- "// {print \$1}" ./gcc_arch + ;; + distro) + $2 -F- "// {print \$2}" ./gcc_arch + ;; + os) + $2 -F- "// {print \$3}" ./gcc_arch + ;; +esac + +rm -f ./gcc_arch + + +# End of get_target.sh diff --git a/helpers/Makefile.am b/helpers/Makefile.am new file mode 100644 index 00000000..0d5ab5a3 --- /dev/null +++ b/helpers/Makefile.am @@ -0,0 +1,55 @@ +## automake.am +## +## helper/ Automake.am for Rivendell +## +## (C) Copyright 2003-2005 Fred Gleason <fredg@paravelsystems.com> +## +## $Id: Makefile.am,v 1.9.6.1 2012/11/29 01:37:35 cvs Exp $ +## $Date: 2012/11/29 01:37:35 $ +## +## Use automake to process this into a Makefile.in +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## + + +AM_CFLAGS = -Wall + +noinst_PROGRAMS = cwrap\ + jsmin + +noinst_SCRIPTS = rdpack.sh\ + rdtrans.sh + +dist_cwrap_SOURCES = cwrap.cpp cwrap.h + +dist_jsmin_SOURCES = jsmin.c + +EXTRA_DIST = rdpack.sh\ + rdtrans.sh\ + rdtransgui.sh\ + setenvvar.sh\ + win32_frag1.txt\ + win32_frag2.txt + +CLEANFILES = *~\ + *.tar.gz\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/helpers/cwrap.cpp b/helpers/cwrap.cpp new file mode 100644 index 00000000..abf05d29 --- /dev/null +++ b/helpers/cwrap.cpp @@ -0,0 +1,136 @@ +// cwrap.cpp +// +// A utility for wrapping arbitrary file data in C-compaibile source +// statements. +// +// (C) Copyright 2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: cwrap.cpp,v 1.3 2007/02/14 21:48:41 fredg Exp $ +// $Date: 2007/02/14 21:48:41 $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> + +#include <cwrap.h> + +int main(int argc,char *argv[]) +{ + int input_fd; + FILE *output_desc; + char *input_name; + char output_name[256]; + char var_name[256]; + bool found; + struct stat stat; + char line[LINE_LENGTH]; + int n; + int count=0; + + // + // Build Defaults + // + sprintf(output_name,"%s.c",argv[argc-1]); + + // + // Process Arguments + // + for(int i=1;i<argc;i++) { + found=false; + if((!strcmp(argv[i],"-o"))||(!strcmp(argv[i],"--output-file"))) { + found=true; + if(i<(argc-2)) { + strcpy(output_name,argv[++i]); + } + else { + printf(USAGE); + exit(1); + } + } + if(i==(argc-1)) { + input_name=argv[i]; + found=true; + } + if(!found) { + printf(USAGE); + exit(1); + } + } + + // + // Set Variable Name + // + for(int j=0;j<strlen(output_name);j++) { + if(output_name[j]!='.') { + var_name[j]=output_name[j]; + } + else { + var_name[j]=0; + j=strlen(output_name); + } + } + + // + // Open Files + // + if((input_fd=open(input_name,O_RDONLY))<0) { + perror("wrapdat"); + exit(1); + } + if((output_desc=fopen(output_name,"w"))==NULL) { + perror("wrapdat"); + exit(1); + } + + // + // Get Size of Source File and Write Header + // + memset(&stat,0,sizeof(struct stat)); + if(fstat(input_fd,&stat)) { + perror("wrapdat"); + exit(1); + } + fprintf(output_desc,"const unsigned char %s[%d] = {\n", + var_name,stat.st_size+1); + + // + // Write Body + // + for(int i=0;i<(stat.st_size/LINE_LENGTH+1);i++) { + n=read(input_fd,line,LINE_LENGTH); + for(int j=0;j<n;j++) { + fprintf(output_desc,"%d,",line[j]); + count++; + } + if(n>0) { + fprintf(output_desc,"\n"); + } + } + fprintf(output_desc,"0};\n"); + + // + // Finish Up + // + close(input_fd); + fclose(output_desc); + exit(0); +} diff --git a/helpers/cwrap.h b/helpers/cwrap.h new file mode 100644 index 00000000..399cc422 --- /dev/null +++ b/helpers/cwrap.h @@ -0,0 +1,37 @@ +// cwrap.h +// +// A utility for wrapping arbitrary file data in C-compaibile source +// statements. +// +// (C) Copyright 2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: cwrap.h,v 1.3 2007/02/14 21:48:41 fredg Exp $ +// $Date: 2007/02/14 21:48:41 $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef WRAPDAT_H +#define WRAPDAT_H + +#define USAGE "wrapdat [-o|--output-file <file>] <file>\n" + +// +// Data Values per Line +// +#define LINE_LENGTH 16 + + +#endif // WRAPDAT_H diff --git a/helpers/jsmin.c b/helpers/jsmin.c new file mode 100644 index 00000000..c07e920e --- /dev/null +++ b/helpers/jsmin.c @@ -0,0 +1,275 @@ +/* jsmin.c + 2008-08-03 + +Copyright (c) 2002 Douglas Crockford (www.crockford.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include <stdlib.h> +#include <stdio.h> + +static int theA; +static int theB; +static int theLookahead = EOF; + + +/* isAlphanum -- return true if the character is a letter, digit, underscore, + dollar sign, or non-ASCII character. +*/ + +static int +isAlphanum(int c) +{ + return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' || + c > 126); +} + + +/* get -- return the next character from stdin. Watch out for lookahead. If + the character is a control character, translate it to a space or + linefeed. +*/ + +static int +get() +{ + int c = theLookahead; + theLookahead = EOF; + if (c == EOF) { + c = getc(stdin); + } + if (c >= ' ' || c == '\n' || c == EOF) { + return c; + } + if (c == '\r') { + return '\n'; + } + return ' '; +} + + +/* peek -- get the next character without getting it. +*/ + +static int +peek() +{ + theLookahead = get(); + return theLookahead; +} + + +/* next -- get the next character, excluding comments. peek() is used to see + if a '/' is followed by a '/' or '*'. +*/ + +static int +next() +{ + int c = get(); + if (c == '/') { + switch (peek()) { + case '/': + for (;;) { + c = get(); + if (c <= '\n') { + return c; + } + } + case '*': + get(); + for (;;) { + switch (get()) { + case '*': + if (peek() == '/') { + get(); + return ' '; + } + break; + case EOF: + fprintf(stderr, "Error: JSMIN Unterminated comment.\n"); + exit(1); + } + } + default: + return c; + } + } + return c; +} + + +/* action -- do something! What you do is determined by the argument: + 1 Output A. Copy B to A. Get the next B. + 2 Copy B to A. Get the next B. (Delete A). + 3 Get the next B. (Delete B). + action treats a string as a single character. Wow! + action recognizes a regular expression if it is preceded by ( or , or =. +*/ + +static void +action(int d) +{ + switch (d) { + case 1: + putc(theA, stdout); + case 2: + theA = theB; + if (theA == '\'' || theA == '"') { + for (;;) { + putc(theA, stdout); + theA = get(); + if (theA == theB) { + break; + } + if (theA == '\\') { + putc(theA, stdout); + theA = get(); + } + if (theA == EOF) { + fprintf(stderr, "Error: JSMIN unterminated string literal."); + exit(1); + } + } + } + case 3: + theB = next(); + if (theB == '/' && (theA == '(' || theA == ',' || theA == '=' || + theA == ':' || theA == '[' || theA == '!' || + theA == '&' || theA == '|' || theA == '?' || + theA == '{' || theA == '}' || theA == ';' || + theA == '\n')) { + putc(theA, stdout); + putc(theB, stdout); + for (;;) { + theA = get(); + if (theA == '/') { + break; + } + if (theA =='\\') { + putc(theA, stdout); + theA = get(); + } + if (theA == EOF) { + fprintf(stderr, +"Error: JSMIN unterminated Regular Expression literal.\n"); + exit(1); + } + putc(theA, stdout); + } + theB = next(); + } + } +} + + +/* jsmin -- Copy the input to the output, deleting the characters which are + insignificant to JavaScript. Comments will be removed. Tabs will be + replaced with spaces. Carriage returns will be replaced with linefeeds. + Most spaces and linefeeds will be removed. +*/ + +static void +jsmin() +{ + theA = '\n'; + action(3); + while (theA != EOF) { + switch (theA) { + case ' ': + if (isAlphanum(theB)) { + action(1); + } else { + action(2); + } + break; + case '\n': + switch (theB) { + case '{': + case '[': + case '(': + case '+': + case '-': + action(1); + break; + case ' ': + action(3); + break; + default: + if (isAlphanum(theB)) { + action(1); + } else { + action(2); + } + } + break; + default: + switch (theB) { + case ' ': + if (isAlphanum(theA)) { + action(1); + break; + } + action(3); + break; + case '\n': + switch (theA) { + case '}': + case ']': + case ')': + case '+': + case '-': + case '"': + case '\'': + action(1); + break; + default: + if (isAlphanum(theA)) { + action(1); + } else { + action(3); + } + } + break; + default: + action(1); + break; + } + } + } +} + + +/* main -- Output any command line arguments as comments + and then minify the input. +*/ +extern int +main(int argc, char* argv[]) +{ + int i; + for (i = 1; i < argc; i += 1) { + fprintf(stdout, "// %s\n", argv[i]); + } + jsmin(); + return 0; +} diff --git a/helpers/rdpack.sh b/helpers/rdpack.sh new file mode 100755 index 00000000..912eb67c --- /dev/null +++ b/helpers/rdpack.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# rdpack.sh +# +# A shell utility for packaging Rivendell translation files. +# +# (C) Copyright 2005,2008 Fred Gleason <fredg@paravelsystems.com> +# +# $Id: rdpack.sh,v 1.6 2010/07/29 19:32:32 cvs Exp $ +# $Date: 2010/07/29 19:32:32 $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +MAIL_ADDR=translations@paravelsystems.com + + +echo -n "Packaging translation files..." + +# +# Get Language +# +LANG=`cat language` + +# +# Package it +# +tar zvcf rivendell_$LANG-done.tar.gz * > /dev/null + +echo "done." +echo +echo "Please e-mail the file 'rivendell_$LANG-done.tar.gz' to" +echo "'$MAIL_ADDR.'" +echo +echo "Thank you for supporting the Rivendell project!" +echo + + +# End of rdpack.sh diff --git a/helpers/rdtrans.sh b/helpers/rdtrans.sh new file mode 100755 index 00000000..c5650e79 --- /dev/null +++ b/helpers/rdtrans.sh @@ -0,0 +1,153 @@ +#!/bin/bash + +# rdtrans.sh +# +# A shell utility for managing Rivendell translation files. +# +# (C) Copyright 2005,2008 Fred Gleason <fredg@paravelsystems.com> +# +# $Id: rdtrans.sh,v 1.7 2010/07/29 19:32:32 cvs Exp $ +# $Date: 2010/07/29 19:32:32 $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# The following environmental variables are used by this utility: +# +# RD_SOURCE - The path to the top of the Rivendell source tree. +# RD_LANGUAGES - The path to the top of the langauges tree. + +# +# Some readable variable names +# +CMD=$1 +LANG=$2 + +# +# Usage +# +USAGE="USAGE: rdtrans.sh <cmd> <lang>" + + +function ReadLanguage +{ + echo -n "Reading language '$LANG' ... " + mkdir -p $RD_LANGUAGES/$LANG + cp $RD_SOURCE/lib/librd_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/rdhpi/rdhpi_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/rdadmin/rdadmin_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/rdairplay/rdairplay_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/rdpanel/rdpanel_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/rdcastmanager/rdcastmanager_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/rdcatch/rdcatch_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/rdlibrary/rdlibrary_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/rdlogedit/rdlogedit_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/rdlogin/rdlogin_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/rdlogmanager/rdlogmanager_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/utils/rdgpimon/rdgpimon_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/utils/rmlsend/rmlsend_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/utils/rdchunk/rdchunk_$LANG.ts $RD_LANGUAGES/$LANG/ + cp $RD_SOURCE/utils/rdgpimon/rdgpimon_$LANG.ts $RD_LANGUAGES/$LANG/ + echo "done." +} + + +function WriteLanguage +{ + echo -n "Writing language '$LANG' ... " + cp $RD_LANGUAGES/$LANG/librd_$LANG.ts $RD_SOURCE/lib/ + cp $RD_LANGUAGES/$LANG/rdhpi_$LANG.ts $RD_SOURCE/rdhpi/ + cp $RD_LANGUAGES/$LANG/rdadmin_$LANG.ts $RD_SOURCE/rdadmin/ + cp $RD_LANGUAGES/$LANG/rdairplay_$LANG.ts $RD_SOURCE/rdairplay/ + cp $RD_LANGUAGES/$LANG/rdpanel_$LANG.ts $RD_SOURCE/rdpanel/ + cp $RD_LANGUAGES/$LANG/rdcastmanager_$LANG.ts $RD_SOURCE/rdcastmanager/ + cp $RD_LANGUAGES/$LANG/rdcatch_$LANG.ts $RD_SOURCE/rdcatch/ + cp $RD_LANGUAGES/$LANG/rdlibrary_$LANG.ts $RD_SOURCE/rdlibrary/ + cp $RD_LANGUAGES/$LANG/rdlogedit_$LANG.ts $RD_SOURCE/rdlogedit/ + cp $RD_LANGUAGES/$LANG/rdlogin_$LANG.ts $RD_SOURCE/rdlogin/ + cp $RD_LANGUAGES/$LANG/rdlogmanager_$LANG.ts $RD_SOURCE/rdlogmanager/ + cp $RD_LANGUAGES/$LANG/rdgpimon_$LANG.ts $RD_SOURCE/utils/rdgpimon/ + cp $RD_LANGUAGES/$LANG/rmlsend_$LANG.ts $RD_SOURCE/utils/rmlsend/ + cp $RD_LANGUAGES/$LANG/rdchunk_$LANG.ts $RD_SOURCE/utils/rdchunk/ + cp $RD_LANGUAGES/$LANG/rdgpimon_$LANG.ts $RD_SOURCE/utils/rdgpimon/ + echo "done." +} + +function PackLanguage +{ + echo $LANG > $RD_LANGUAGES/$LANG/language + cp $RD_SOURCE/helpers/rdpack.sh $RD_LANGUAGES/$LANG + CURRENT_DIR=`pwd` + cd $RD_LANGUAGES/ + tar -zvcf $RD_LANGUAGES/rivendell_$LANG.tar.gz $LANG/* + cd $CURRENT_DIR +} + +function EnvironmentError +{ + echo + echo "You need to set up the following environmental variables before" + echo "before you can use this utility:" + echo " \$RD_LANGUAGES" + echo " \$RD_SOURCE" + echo +} + + +# +# Check for a valid environment +# +if [ -z $RD_LANGUAGES ] ; then + echo $RD_LANGUAGES + EnvironmentError + exit 1 +fi +if [ -z $RD_SOURCE ] ; then + echo RD_SOURCE + EnvironmentError + exit 1 +fi + +# +# Check for argument sanity +# +if [ -z $CMD ] ; then + echo $USAGE + exit 1 +fi +if [ -z $LANG ] ; then + echo $USAGE + exit 1 +fi + +# +# dispatch the command +# +case $CMD in + "read") + ReadLanguage + ;; + + "write") + WriteLanguage + ;; + + "pack") + PackLanguage + ;; + + *) + echo "Unknown command. Try 'write', 'read' or 'pack'." + exit 1 + ;; +esac diff --git a/helpers/rdtransgui.sh b/helpers/rdtransgui.sh new file mode 100644 index 00000000..ca3d3d3c --- /dev/null +++ b/helpers/rdtransgui.sh @@ -0,0 +1,187 @@ +#!/bin/bash +# +# rdtransgui.sh +# +# A GUi interface for rdtrans.sh script that is used to manage Rivendell +# translation files. +# +# (C) Copyright 2010 Frederick Henderson <frederickjh@henderson-meier.org> +# +# $Id: rdtransgui.sh,v 1.1 2011/03/01 21:00:07 cvs Exp $ +# $Date: 2011/03/01 21:00:07 $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +### Functions ### +function whichdialog() +{ +zenitypresent="$(type "zenity" 2> /dev/null )" +# Line below commented out. Used for testing kdialog +#zenitypresent= +kdialogpresent="$(type "kdialog" 2> /dev/null )" +if [ ${#zenitypresent} -gt 0 ] ; then + dialog=zenity +else + if [ ${#kdialogpresent} -gt 0 ] ; then + dialog=kdialog + else + echo "Sorry this script needs a script GUI to run correctly." + echo "Try installing 'zenity' or 'kdialog' from the 'kdebase-bin'\ + package." + exit + + fi +fi +} + +# Check for a valid environment +# +function checkenviroment() +{ +if [[ -z "$RD_LANGUAGES" || -z "$RD_SOURCE" || -z "$RD_SHAREDDIR" ]] ; then + text="First you need to set the Enviromental Variables for this script to\ + work. I will bring up the setenvvar.sh script so you can do so before\ + continuing to the menu." + title="Need to set Enviromental Variables first." + if [ "${dialog}" = "kdialog" ] ; then + ${dialog} --title "$title" --passivepopup "$text" 15 + elif [ "${dialog}" = "zenity" ] ; then + ${dialog} --info --title="$title" --text="$text"\ + --timeout=15 + fi + . ./setenvvar.sh +fi +} + +function setlanguagecode() +{ +title="Enter a Valid Language Code" +text="Enter a Valid i18n language code. These are two letter codes for\ + language. + ie. German=de + +These maybe followed by an underscore and a capitalize two letter country code. +ie. de__CH for German and Switzerland to create a country specific language\ + code. + +You can find a list in '''/usr/share/i18n/SUPPORTED''' on Ubuntu systems. + +Run 'man locale' and check near the bottom of the man page for the location on\ + your system +of the SUPPORTED locale codes file. Only the portion before .UTF-8 is needed. + +The locale code that your computer is set to now is filled in below for you." +computerlocale=$(echo $LANG | sed 's/.utf8$//') + if [ "${dialog}" = "kdialog" ] ; then + langcode=$(${dialog} --title "$title" --inputbox "$text"\ + "$computerlocale") + elif [ "${dialog}" = "zenity" ] ; then + langcode=$(${dialog} --entry --title="$title" --text="$text"\ + --entry-text="$computerlocale") + fi +checkforcode +} + +function checkforcode() +{ +until [ -n "$langcode" ] ; do +setlanguagecode +done +} + +function menu() +{ +while true; do +title="RD Translation Utility - $langcode" +text="Please choose from the menu." + if [ "${dialog}" = "kdialog" ] ; then + choice=$(${dialog} --title "$title" --menu "$text" "Add Language"\ + "Add Language" "Remove Language" "Remove Language" "Update Language"\ + "Update Language" "Read Language" "Read Language" "Write Language"\ + "Write Language" "Test Language" "Test Language" "Pack Language"\ + "Pack Language" "Set Environmental Variables" "Set Environmental Variables"\ + "Set Language Code" "Set Language Code" "Exit" "Exit" ) + elif [ "${dialog}" = "zenity" ] ; then + choice=$(zenity --width=350 --height=350 --list --column "" --title="$title"\ + --text="$text" "Add Language" "Remove Language" "Update Language"\ + "Read Language" "Write Language" "Test Language" "Pack Language"\ + "Set Environmental Variables" "Set Language Code" "Exit") + fi + + + case "${choice}" in + +"Add Language") +./rdtrans.sh add $langcode +;; +"Remove Language") +./rdtrans.sh remove $langcode +;; +"Update Language") +./rdtrans.sh update $langcode +;; +"Read Language") +./rdtrans.sh read $langcode +;; +"Write Language") +./rdtrans.sh write $langcode +;; +"Test Language") +title="Password needed!" +text="Please enter your sudo password + as the test command needs super user + privileges." +if [ "${dialog}" = "kdialog" ] ; then + password=$(${dialog} --title "$title" --password "$text") + echo $password | sudo -ES ./rdtrans.sh test $langcode + password= + elif [ "${dialog}" = "zenity" ] ; then + password=$(${dialog} --title="$title" --text="$text" --entry --hide-text) + echo $password | sudo -ES ./rdtrans.sh test $langcode + password= + sudo -k + fi + +;; +"Pack Language") +. ./rdtrans.sh pack $langcode +title="Archive is ready to email!" +text="All done. Archive for language $LANG can be found here: +$RD_LANGUAGES/rivendell_$LANG.tar.gz +Please email it to the developer - $MAIL_ADDR +and thanks for translating Rivendell!" +if [ "${dialog}" = "kdialog" ] ; then + ${dialog} --title "$title" --msgbox "$text" +elif [ "${dialog}" = "zenity" ] ; then + ${dialog} --info --title="$title" --text="$text" +fi +;; +"Set Environmental Variables") +. ./setenvvar.sh +;; +"Set Language Code") +setlanguagecode +;; +Exit|*) + break + ;; + esac +done +} + +### Main Program ### +whichdialog +checkenviroment +setlanguagecode +menu diff --git a/helpers/setenvvar.sh b/helpers/setenvvar.sh new file mode 100644 index 00000000..2c0933ff --- /dev/null +++ b/helpers/setenvvar.sh @@ -0,0 +1,197 @@ +#!/bin/bash +# +# setenvvar.sh +# +# A utility for setting environmental variables to be used by the +# rdtrans.sh script that is used to manage Rivendell translation files. +# +# (C) Copyright 2010 Frederick Henderson <frederickjh@henderson-meier.org> +# +# $Id: setenvvar.sh,v 1.1 2011/03/01 21:00:07 cvs Exp $ +# $Date: 2011/03/01 21:00:07 $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# The following environmental variables are set by this utility: +# +# RD_SOURCE - The path to the top of the Rivendell source tree. +# RD_LANGUAGES - The path to the top of the languages tree. +# This a working folder for your translation files. +# RD_SHAREDDIR - The path to Rivendell's shared data directory +# /usr/local/share/rivendell by default +# /usr/share/rivendell on Ubuntu +# +## IMPORTANT NOTE: This script must be run in a special way. The best +## is if you run it from the /helpers folder with the following command: +## . ./setenvvar.sh +## If the first .(period) and space are omitted the script will run but +## environmental variables will not be set. +# +# +## Functions + +function whichdialog() +{ +zenitypresent="$(type "zenity" 2> /dev/null )" +# Line below commented out. Used for testing kdialog +#zenitypresent= +kdialogpresent="$(type "kdialog" 2> /dev/null )" +# Line below commented out. Used for testing bash 4 +#kdialogpresent= +if [ ${#zenitypresent} -gt 0 ] ; then + dialog=zenity +else + if [ ${#kdialogpresent} -gt 0 ] ; then + dialog=kdialog + else + if [ $BASH_VERSINFO -lt 4 ] ; then + echo "Sorry this script need at least Bash version 4 to run correctly." + echo "Try installing 'zenity' or 'kdialog' from the 'kdebase-bin'\ + package." + exit + fi + dialog=read + fi +fi +} + +function getdir() +{ + if [ "${dialog}" = "kdialog" ] ; then + ${dialog} --title "$shorttitle" --passivepopup "$title" 15 + height=600 ; width=1050 + selecteddir=$(${dialog} --title "$title" --getexistingdirectory\ + "${dir}" --geometry ${width}x${height}+0-0 2> /dev/null ) + if [ $? -ne 0 ] ; then + kill -SIGINT $$ + fi + elif [ "${dialog}" = "zenity" ] ; then + ${dialog} --info --title "$shorttitle" --text "$title"\ + --timeout=15 + selecteddir=$(${dialog} --title "$title" --file-selection\ + --directory --filename="$dir/" 2> /dev/null ) + if [ $? -ne 0 ] ; then + kill -SIGINT $$ + fi + elif [ "${dialog}" = "read" ]; then + echo ======================================================\ +===================================== + echo + read -e -p "$title " -i "$dir" selecteddir + echo + echo =======================================================\ +=================================== + fi +} + +function setrdsource() +{ +dir=${PWD%\/*} +title="Enter the directory for the RD_SOURCE variable. If you ran this in the\ + /helpers directory then you can most likely just use the default of $dir ." +shorttitle="Enter the directory for the RD_SOURCE variable." +if [ -n "$RD_SOURCE" ] ; then + dir="$RD_SOURCE" +fi +getdir +export RD_SOURCE="$selecteddir" +} + +function setrdlanguages() +{ +dir="$HOME/rdlanguages" +title="Enter the directory for the RD_LANGUAGES variable. This will be your\ + working folder for your translation files. The default is $dir in your home\ + folder." +shorttitle="Enter the directory for the RD_LANGUAGES variable." +if [ -n "$RD_LANGUAGES" ] ; then + dir="$RD_LANGUAGES" +fi +getdir +export RD_LANGUAGES="$selecteddir" +} + +function setrdshareddir() +{ +title="Enter the directory for the RD_SHAREDDIR variable. For Ubuntu use\ + /usr/share/rivendell The default is /usr/local/share/rivendell" +shorttitle="Enter the directory for the RD_SHAREDDIR variable." +if [ -n "$RD_SHAREDDIR" ] ; then + dir="$RD_SHAREDDIR" +else + distro=$(cat /etc/*_ver* /etc/*-rel* | sed '/^DISTRIB_ID=*/!d; s///; q') + if [ $distro = "Ubuntu" ] ; then + dir="/usr/share/rivendell" + else + dir="/usr/local/share/rivendell" + fi +fi +getdir +export RD_SHAREDDIR="$selecteddir" +} + +function addtodotprofile() +{ +title="Would you like me to add these variables to your $HOME/.profile file,\ + so that they are loaded each time you login?" +shorttitle="Would you like me to add . . ." + if [ "${dialog}" = "kdialog" ] ; then + ${dialog} --title "$shorttitle" --yesno "$title" + if [ $? -ne 0 ] ; then + kill -SIGINT $$ + else + envtoprofile + fi + elif [ "${dialog}" = "zenity" ] + then + ${dialog} --question --title "$shorttitle" --text "$title" + if [ $? -eq 0 ] ; then + envtoprofile + fi + elif [ "${dialog}" = "read" ]; then + echo =====================================================\ +===================================== + echo + answer= + until [[ "$answer" = "Yes" || "$answer" = "yes" ||\ + "$answer" = "No" || "$answer" = "no" ]] ; do + read -e -p "$title " -i "Yes" answer + if [[ "$answer" = "Yes" || "$answer" = "yes" ]] ; then + envtoprofile + fi + done + echo + echo =====================================================\ +===================================== + fi +} + +function envtoprofile() +{ +echo >> $HOME/.profile +echo "### The lines below were added to set Environmental Variables for\ + Rivendell translation script rdtrans.sh" >> $HOME/.profile +echo 'export RD_SOURCE='"$RD_SOURCE" >> $HOME/.profile +echo 'export RD_LANGUAGES='"$RD_LANGUAGES" >> $HOME/.profile +echo 'export RD_SHAREDDIR='"$RD_SHAREDDIR" >> $HOME/.profile +echo "### End of environmental variables for rdtrans.sh" >> $HOME/.profile +echo >> $HOME/.profile +} + +## MAIN PROGRAM ### +whichdialog +setrdsource +setrdlanguages +setrdshareddir +addtodotprofile diff --git a/helpers/win32_frag1.txt b/helpers/win32_frag1.txt new file mode 100644 index 00000000..319a0848 --- /dev/null +++ b/helpers/win32_frag1.txt @@ -0,0 +1 @@ +qmake -set VERSION " \ No newline at end of file diff --git a/helpers/win32_frag2.txt b/helpers/win32_frag2.txt new file mode 100644 index 00000000..9d68933c --- /dev/null +++ b/helpers/win32_frag2.txt @@ -0,0 +1 @@ +" \ No newline at end of file diff --git a/icons/Makefile.am b/icons/Makefile.am new file mode 100644 index 00000000..07385fbc --- /dev/null +++ b/icons/Makefile.am @@ -0,0 +1,130 @@ +## automake.am +## +## icons/automake.am for Rivendell +## +## (C) Copyright 2002-2006 Fred Gleason <fredg@salemradiolabs.com> +## +## $Id: Makefile.am,v 1.19.2.3 2013/12/30 19:56:11 cvs Exp $ +## $Date: 2013/12/30 19:56:11 $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +install-exec-am: + mkdir -p $(DESTDIR)@libexecdir@ + cp greencheckmark.png $(DESTDIR)@libexecdir@ + cp redx.png $(DESTDIR)@libexecdir@ + cp greenball.png $(DESTDIR)@libexecdir@ + cp redball.png $(DESTDIR)@libexecdir@ + cp whiteball.png $(DESTDIR)@libexecdir@ + cp progressbar.gif $(DESTDIR)@libexecdir@ + mkdir -p @prefix@/share/icons/hicolor/16x16/apps + cp rivendell-16x16.png @prefix@/share/icons/hicolor/16x16/apps/rivendell.png + mkdir -p @prefix@/share/icons/hicolor/22x22/apps + cp rivendell-22x22.png @prefix@/share/icons/hicolor/22x22/apps/rivendell.png + mkdir -p @prefix@/share/icons/hicolor/32x32/apps + cp rivendell-32x32.png @prefix@/share/icons/hicolor/32x32/apps/rivendell.png + mkdir -p @prefix@/share/icons/hicolor/48x48/apps + cp rivendell-48x48.png @prefix@/share/icons/hicolor/48x48/apps/rivendell.png + mkdir -p @prefix@/share/icons/hicolor/64x64/apps + cp rivendell-64x64.png @prefix@/share/icons/hicolor/64x64/apps/rivendell.png + mkdir -p @prefix@/share/icons/hicolor/128x128/apps + cp rivendell-128x128.png @prefix@/share/icons/hicolor/128x128/apps/rivendell.png + +uninstall: + rm -f $(DESTDIR)@libexecdir@/greencheckmark.png + rm -f $(DESTDIR)@libexecdir@/redx.png + rm -f $(DESTDIR)@libexecdir@/greenball.png + rm -f $(DESTDIR)@libexecdir@/redball.png + rm -f $(DESTDIR)@libexecdir@/whiteball.png + rm -f $(DESTDIR)@libexecdir@/progressbar.gif + rm -f @prefix@/share/icons/hicolor/16x16/apps/rivendell.png + rm -f @prefix@/share/icons/hicolor/22x22/apps/rivendell.png + rm -f @prefix@/share/icons/hicolor/32x32/apps/rivendell.png + rm -f @prefix@/share/icons/hicolor/48x48/apps/rivendell.png + rm -f @prefix@/share/icons/hicolor/64x64/apps/rivendell.png + rm -f @prefix@/share/icons/hicolor/128x128/apps/rivendell-128x128.png + +EXTRA_DIST = admin.xpm\ + blueball.xpm\ + chain.xpm\ + checkmark.xpm\ + download.xpm\ + ex.xpm\ + fillstart.xpm\ + fillstop.xpm\ + greenball.png\ + greencheckmark.png\ + greenball.xpm\ + greencheckmark.xpm\ + marker.xpm\ + mic16.xpm\ + music.xpm\ + note.xpm\ + note2.xpm\ + notemarker.xpm\ + play.xpm macro.xpm\ + post.xpm\ + post2.xpm\ + post3.xpm\ + progressbar.gif\ + progressbar.xcf\ + record.xpm\ + record2.xpm\ + record3.xpm\ + redball.png\ + redball.xpm\ + redcheckmark.xpm\ + redx.png\ + redx.xpm\ + rivendell.ico\ + rivendell.res\ + rivendell-16x16.png\ + rivendell-16x16.xpm\ + rivendell-22x22.png\ + rivendell-22x22.xpm\ + rivendell-32x32.png\ + rivendell-32x32.xpm\ + rivendell-48x48.png\ + rivendell-48x48.xpm\ + rivendell-64x64.png\ + rivendell-64x64.xpm\ + rivendell-128x128.png\ + rivendell-128x128.xpm\ + rml.xpm\ + rml2.xpm\ + rml3.xpm\ + rml5.xpm\ + split.xpm\ + switch.xpm\ + switch2.xpm\ + switch3.xpm\ + track.xpm\ + track_cart.xpm\ + traffic.xpm\ + trashcan-16x16.xpm\ + trashcan-32x32.xpm\ + upload.xpm\ + user.xpm\ + whiteball.png\ + whiteball.xpm + +CLEANFILES = *~ + +MAINTAINERCLEANFILES = *~\ + aclocal.m4\ + configure\ + Makefile.in diff --git a/icons/admin.xpm b/icons/admin.xpm new file mode 100644 index 00000000..96d22de6 --- /dev/null +++ b/icons/admin.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static const char * admin_xpm[] = { +"16 16 7 1", +" c None", +". c #BABDB6", +"+ c #888A85", +"@ c #EEEEEC", +"# c #204A87", +"$ c #729FCF", +"% c #3465A4", +" ", +" . + ", +" .@. +@+ ", +" .@. +@+ ", +" . .@. +++ ", +".@..@@. ++ ", +" .@@@@@.++ ", +" ....@@.+ ", +" .@@. ", +" ##++.@@. ", +" #$$#+ .@@. ", +" #$$%$# .@@. ", +"#$$%%$# .@@. ", +"#$%%$# .@. ", +"#$$$# .. ", +" ### "}; diff --git a/icons/blueball.xpm b/icons/blueball.xpm new file mode 100644 index 00000000..39d94260 --- /dev/null +++ b/icons/blueball.xpm @@ -0,0 +1,58 @@ +/* XPM */ +static const char * blueball_xpm[] = { +"14 14 41 1", +" c None", +". c #8BA6FF", +"+ c #0500B4", +"@ c #05004A", +"# c #060062", +"$ c #0F07FF", +"% c #040094", +"& c #4642CE", +"* c #0500AC", +"= c #0000FD", +"- c #03005A", +"; c #6462CD", +"> c #0600DE", +", c #131084", +"' c #4A4A9C", +") c #170FFF", +"! c #1210CE", +"~ c #33308B", +"{ c #0700EE", +"] c #0300D6", +"^ c #01006A", +"/ c #010084", +"( c #807AC5", +"_ c #030072", +": c #3134FF", +"< c #0E08D6", +"[ c #2721FF", +"} c #0600CE", +"| c #0800BC", +"1 c #130FFF", +"2 c #0700E6", +"3 c #00004A", +"4 c #7A7AC5", +"5 c #0700FD", +"6 c #00015A", +"7 c #A5C6FF", +"8 c #6B62CD", +"9 c #0200BC", +"0 c #0F0F72", +"a c #07009C", +"b c #0600C6", +" ", +" ", +" (&!!&( ", +" 8]==5{b8 ", +" 4}=1:$2ba4 ", +" &=$.7)]9%, ", +" !5$:[<9a/- ", +" !>2>}+a/#- ", +" &99|*a/630 ", +" 4%a%/_#@3' ", +" ;^^-333~ ", +" 40--0' ", +" ", +" "}; diff --git a/icons/chain.xpm b/icons/chain.xpm new file mode 100644 index 00000000..93dba6b3 --- /dev/null +++ b/icons/chain.xpm @@ -0,0 +1,22 @@ +/* XPM */ +const static char * chain_xpm[] = { +"16 16 3 1", +" c #000000000000", +". c #FFFFFFFF0000", +"X c #00000000CDCD", +" ", +" ..... ", +" ......... ", +" ....XXX.... ", +" ...XX.XX... ", +" ...XX...X.... ", +" ...XX........ ", +" ...XX........ ", +" ...XX........ ", +" ...XX...X.... ", +" ...XX.XX... ", +" ....XXX.... ", +" ......... ", +" ..... ", +" ", +" "}; diff --git a/icons/checkmark.xpm b/icons/checkmark.xpm new file mode 100644 index 00000000..6fe124eb --- /dev/null +++ b/icons/checkmark.xpm @@ -0,0 +1,22 @@ +/* XPM */ +const static char *checkmark_xpm[]={ +"32 16 3 1", +"# c None", +". c None", +"a c #00c000", +"...........................#....", +"..........................###...", +"........................a###....", +".......................aaa#.....", +"......................aaa#......", +".....#...............aaa#.......", +".....##a............aaa#........", +"......#a...........aaa#.........", +".......aa.........aaa#..........", +".......#aa.......aaa#...........", +"........#aa.....aaa#............", +".........#aa...aaa#.............", +"..........aa..aaa#..............", +"..........#aaaaa#...............", +"...........#aaa#................", +"............###................."}; diff --git a/icons/download.xpm b/icons/download.xpm new file mode 100644 index 00000000..fd6b0a7d --- /dev/null +++ b/icons/download.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char *download_xpm[]={ +"16 16 3 1", +"# c None", +". c None", +"a c #0000c0", +"..###aaaaaa###..", +"..###aaaaaa###..", +"..###aaaaaa###..", +"..###aaaaaa###..", +"..###aaaaaa###..", +"..###aaaaaa###..", +"..###aaaaaa###..", +"..###aaaaaa###..", +"aaaaaaaaaaaaaaaa", +".aaaaaaaaaaaaaa.", +".#aaaaaaaaaaaa#.", +"..#aaaaaaaaaa#..", +"..##aaaaaaaa##..", +"..###aaaaaa###..", +"..####aaaa####..", +"..#####aa######."}; diff --git a/icons/ex.xpm b/icons/ex.xpm new file mode 100644 index 00000000..6fb87b20 --- /dev/null +++ b/icons/ex.xpm @@ -0,0 +1,22 @@ +/* XPM */ +const static char *ex_xpm[]={ +"32 16 3 1", +"# c None", +". c None", +"a c #ff0000", +"........##............#.........", +"........###..........###........", +".........##a........a##.........", +"..........aaa......aaa..........", +"...........aaa....aaa...........", +"............aaa..aaa............", +".............aaaaaa.............", +"..............aaaa..............", +"..............aaaa..............", +".............aaaaaa.............", +"............aaa..aaa............", +"...........aaa....aaa...........", +"..........aaa......aaa..........", +".........##a........a##.........", +"........###..........###........", +".........#............#........."}; diff --git a/icons/fillstart.xpm b/icons/fillstart.xpm new file mode 100644 index 00000000..48773c6d --- /dev/null +++ b/icons/fillstart.xpm @@ -0,0 +1,25 @@ +/* XPM */ +const static char *fillstart_xpm[]={ +"16 16 6 1", +"d c None", +". c None", +"# c #000000", +"b c #008000", +"c c #c0ffc0", +"a c #ffffff", +".....#####......", +"...##aabbb##....", +"..#aaaabbbbc#...", +".#aaaaabbbcaa#..", +".#aaaaabbbaaa#..", +"#aaaaaabbaaaaa#.", +"#aaaaaabcaaaaa#.", +"#aaaaaabaaaaaa#.", +"#aaaaaaaaaaaaa#.", +"#aaaaaaaaaaaaa#.", +".#aaaaaaaaaaa#..", +".#aaaaaaaaaaa#..", +"..#aaaaaaaaa#...", +"...##aaaaa##....", +".....#####ddddd.", +"..............dd"}; diff --git a/icons/fillstop.xpm b/icons/fillstop.xpm new file mode 100644 index 00000000..e7a66ee6 --- /dev/null +++ b/icons/fillstop.xpm @@ -0,0 +1,25 @@ +/* XPM */ +const static char *fillstop_xpm[]={ +"16 16 6 1", +"d c None", +". c None", +"# c #000000", +"b c #008000", +"c c #c0ffc0", +"a c #ffffff", +".....#####......", +"...##aaabb##....", +"..#caaaabbbb#...", +".#bccaaabbbbb#..", +".#bbccaabbbbb#..", +"#bbbbccabbbbbb#.", +"#bbbbbcabbbbbb#.", +"#bbbbbbcbbbbbb#.", +"#bbbbbbbbbbbbb#.", +"#bbbbbbbbbbbbb#.", +".#bbbbbbbbbbb#..", +".#bbbbbbbbbbb#..", +"..#bbbbbbbbb#...", +"...##bbbbb##....", +".....#####ddddd.", +"..............dd"}; diff --git a/icons/greenball.png b/icons/greenball.png new file mode 100644 index 0000000000000000000000000000000000000000..9bd5ba42fded4a7be1537da8f04426fdb6f79439 GIT binary patch literal 435 zcmV;k0ZjghP)<h;3K|Lk000e1NJLTq000gE000gM1^@s6A4o0H00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru*9r*^EH(&20wDkZ0YFJa zK~yNu#gQ>f0$~`(e@dYuc3UK75iJpd<q(onLrZ&$G=!fZ#Fm=`!H>|AHuN!Cg5bnO zD~QV$sYPyz8^Sw1@1BOsgVNS|;D!JHeV*U@JTDLYb%cIis9Igxu`XSn0LYOcZ{?^L z)X=Z5lsXkbUlrW+*Vz!>H-%PGN}Y<#g;cF3bk_wpEsA7iR}Lj2Tf$&XXeEWlvZz`u zfWuSKjy*!wBNC2N<%BAyM2Umx!BD`4i`&bf(ZW>tfAZ}$H<*kWJ%7Mp0<RvJ4yJC+ zf&jd^jG{yC?H4dZFmS-|z;K}NeJc${&5?or81ympU0)j$AJQ!_Mkp&wvtZuJLeKNZ z>N(J}LAU)*<{|)v?fv<CEOpN0s@e3737Afh+d0_d;r#CRU8-75lyXWaCWK-_lyXXr d8pp!F$0tnOjZI(jt&ji!002ovPDHLkV1lZxxM~0Z literal 0 HcmV?d00001 diff --git a/icons/greenball.xpm b/icons/greenball.xpm new file mode 100644 index 00000000..254ef638 --- /dev/null +++ b/icons/greenball.xpm @@ -0,0 +1,58 @@ +/* XPM */ +static const char * greenball_xpm[] = { +"14 14 41 1", +" c None", +". c #31FF45", +"+ c #10CE28", +"@ c #00620F", +"# c #308B3E", +"$ c #00BC18", +"% c #7AC583", +"& c #00BC1B", +"* c #00E61E", +"= c #00DE1E", +"- c #7AC586", +"; c #00FD1D", +"> c #0FFF2F", +", c #62CD74", +"' c #006A0D", +") c #005A0D", +"! c #004A0D", +"~ c #009C16", +"{ c #00C619", +"] c #009416", +"^ c #00AC19", +"/ c #4A9C55", +"( c #00D61C", +"_ c #08D627", +": c #8FFF8B", +"< c #00CE1F", +"[ c #21FF3F", +"} c #005A08", +"| c #004A08", +"1 c #10841E", +"2 c #B1FFA5", +"3 c #07FF28", +"4 c #00FD21", +"5 c #00720E", +"6 c #0FFF33", +"7 c #008411", +"8 c #00B41A", +"9 c #42CE54", +"0 c #00EE23", +"a c #0F721B", +"b c #62CD70", +" ", +" ", +" -9++9- ", +" ,(;;40{, ", +" %<;>.3*{~% ", +" 9;3:26($]1 ", +" +43.[_$~7) ", +" +=*=<8~7@) ", +" 9$$&^~7}|a ", +" %]~]75@!|/ ", +" b'')|||# ", +" %a))a/ ", +" ", +" "}; diff --git a/icons/greencheckmark.png b/icons/greencheckmark.png new file mode 100644 index 0000000000000000000000000000000000000000..1a81b017e052ac216274a4eb47297c2c2153ab79 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~q!3HGX7W?Z1DYhhUcNd2LAh=-f^2tCE&H|6f zVg?3oVGw3ym^DWND9B#o>FdgVor{xC)zZ^`$xonAnx~6nh{pN7lMV_VP~c$EpSyH( zgw))*{R<{*IG%8pkk{B<%-?udb<ggz?zaLiB<@t<=WbQ#ShW0TRqUFCCX3Sjhp(`D ze`1a9pM0cM{-f_nE;-fY_5^)TiL%KqiNTXvm&<>bz85KaLv`oRvRkva0c~XPboFyt I=akR{0LAl2v;Y7A literal 0 HcmV?d00001 diff --git a/icons/greencheckmark.xpm b/icons/greencheckmark.xpm new file mode 100644 index 00000000..fe954217 --- /dev/null +++ b/icons/greencheckmark.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static const char * greencheckmark_xpm[] = { +"16 15 5 1", +" c None", +". c #C0FFC0", +"+ c #008000", +"@ c #00FF00", +"# c #004000", +" ", +" .. ", +" +++.", +" +.@++", +" .++ +.@@#+", +".+@.+ +.@@#+ ", +"+.@@.+ +.@@#+ ", +".+.@@.++.@@#+ ", +" .+@@@@.@@#+ ", +" .+.@@@@#+ ", +" .+@@@#+ ", +" .+@#+ ", +" ++ ", +" ", +" "}; diff --git a/icons/macro.xpm b/icons/macro.xpm new file mode 100644 index 00000000..b9d3e90b --- /dev/null +++ b/icons/macro.xpm @@ -0,0 +1,174 @@ +/* XPM */ +static const char * macro_xpm[] = { +"16 16 155 2", +" c None", +". c #A39C3D", +"+ c #9F983D", +"@ c #9C953D", +"# c #98923D", +"$ c #948E3D", +"% c #918B3D", +"& c #8D883D", +"* c #8A843D", +"= c #86813D", +"- c #827E3D", +"; c #7F7A3D", +"> c #7B773D", +", c #9E983D", +"' c #EBE03A", +") c #DDD23A", +"! c #D1C63A", +"~ c #D4CB49", +"{ c #CEC449", +"] c #C7BF49", +"^ c #C1B949", +"/ c #C8BE3A", +"( c #BAB23A", +"_ c #ADA63A", +": c #77733D", +"< c #666666", +"[ c #9A943D", +"} c #23253B", +"| c #C2BA68", +"1 c #D0CB88", +"2 c #CDC789", +"3 c #C8C389", +"4 c #C2BE88", +"5 c #C7C068", +"6 c #2A2B3B", +"7 c #9F973A", +"8 c #736F3D", +"9 c #96903D", +"0 c #CEC43A", +"a c #C2BC6A", +"b c #8C8B45", +"c c #676703", +"d c #5C5B00", +"e c #676600", +"f c #85830B", +"g c #A4A141", +"h c #AEA96A", +"i c #908A3A", +"j c #6E6B3D", +"k c #928C3D", +"l c #D1C749", +"m c #8F8E47", +"n c #757309", +"o c #D3CA33", +"p c #F4E841", +"q c #D2C93F", +"r c #AAA42D", +"s c #6E6F00", +"t c #9C9B59", +"u c #979249", +"v c #6A673D", +"w c #8E883D", +"x c #C9C049", +"y c #696907", +"z c #746D1B", +"A c #3C380E", +"B c #9B9326", +"C c #A6A12C", +"D c #989612", +"E c #908B49", +"F c #66633D", +"G c #404100", +"H c #F5EA42", +"I c #000000", +"J c #3E3A0F", +"K c #C1B72E", +"L c #9F9E01", +"M c #898449", +"N c #625F3D", +"O c #85803D", +"P c #BAB249", +"Q c #4C4E00", +"R c #D5CA41", +"S c #3D390F", +"T c #3D3A0F", +"U c #BCB32C", +"V c #8C8C00", +"W c #807D49", +"X c #5E5B3D", +"Y c #817C3D", +"Z c #B3AB49", +"` c #767608", +" . c #B7B231", +".. c #6E671C", +"+. c #3F3B10", +"@. c #948D24", +"#. c #C2BA29", +"$. c #8D8B0B", +"%. c #797649", +"&. c #5A583D", +"*. c #7D783D", +"=. c #AAA449", +"-. c #838348", +";. c #707100", +">. c #AAA631", +",. c #C1B72D", +"'. c #BFB42D", +"). c #C4BD2A", +"!. c #9C9418", +"~. c #959254", +"{. c #726F49", +"]. c #55543D", +"^. c #79753D", +"/. c #B5AD3A", +"(. c #C0BA6B", +"_. c #7D7C34", +":. c #888708", +"<. c #6D6E00", +"[. c #757600", +"}. c #5D4E23", +"|. c #68CD41", +"1. c #4A4824", +"2. c #51503D", +"3. c #74713D", +"4. c #A79F3A", +"5. c #2E303B", +"6. c #A59F69", +"7. c #B7B37C", +"8. c #B5B07C", +"9. c #B2AE7D", +"0. c #68CC41", +"a. c #00FF00", +"b. c #429D24", +"c. c #4D4C3D", +"d. c #706D3D", +"e. c #98923A", +"f. c #8B853A", +"g. c #7D783A", +"h. c #817D49", +"i. c #7B7749", +"j. c #747249", +"k. c #494724", +"l. c #419C24", +"m. c #383724", +"n. c #49483D", +"o. c #6C693D", +"p. c #68663D", +"q. c #65623D", +"r. c #615F3D", +"s. c #56553D", +"t. c #53513D", +"u. c #4F4E3D", +"v. c #4C4B3D", +"w. c #48473D", +"x. c #44443D", +" ", +" . + @ # $ % & * = - ; > ", +" , ' ) ! ~ { ] ^ / ( _ : < ", +" [ ) } | 1 2 3 4 5 6 7 8 < ", +" 9 0 a b c d e f g h i j < ", +" k l m n o p q r s t u v < ", +" w x y o z A A B C D E F < ", +" * ^ G H A I I J K L M N < ", +" O P Q R S I I T U V W X < ", +" Y Z ` ...+.J @.#.$.%.&.< ", +" *.=.-.;.>.,.'.).!.~.{.].< ", +" ^./.(._.:.<.[.}.|.|.1.2.< ", +" 3.4.5.6.7.8.9.0.a.a.b.c.< ", +" d.e.f.g.h.i.j.k.l.l.m.n.< ", +" o.p.q.r.X &.s.t.u.v.w.x.< ", +" < < < < < < < < < < < < "}; diff --git a/icons/marker.xpm b/icons/marker.xpm new file mode 100644 index 00000000..373c6287 --- /dev/null +++ b/icons/marker.xpm @@ -0,0 +1,23 @@ +/* XPM */ +const static char *marker_xpm[]={ +"16 16 4 1", +". c None", +"# c #000000", +"b c #0000c0", +"a c #ffff00", +".....#####......", +"...##aaaaa##....", +"..#aaaaaaaaa#...", +".#aabaaaaabaa#..", +".#aabbaaabbaa#..", +"#aaabbbabbbaaa#.", +"#aaabbbbbbbaaa#.", +"#aaabbababbaaa#.", +"#aaabbaaabbaaa#.", +"#aaabbaaabbaaa#.", +".#aabbaaabbaa#..", +".#aabbaaabbaa#..", +"..#aaaaaaaaa#...", +"...##aaaaa##....", +".....#####......", +"................"}; diff --git a/icons/mic16.xpm b/icons/mic16.xpm new file mode 100644 index 00000000..ed5d1e54 --- /dev/null +++ b/icons/mic16.xpm @@ -0,0 +1,95 @@ +/* XPM */ +static const char * mic16_xpm[] = { +"16 16 76 1", +" c None", +". c #AFAFCF", +"+ c #737590", +"@ c #5D5B7C", +"# c #C4C2DD", +"$ c #A7AABD", +"% c #5F5C81", +"& c #363459", +"* c #2F325B", +"= c #D1D0DF", +"- c #9FA2B4", +"; c #5F5C7E", +"> c #38365D", +", c #1B1841", +"' c #CCCEE3", +") c #A8ABBE", +"! c #515074", +"~ c #363259", +"{ c #161640", +"] c #CBCDE0", +"^ c #ADB1C0", +"/ c #4D4A70", +"( c #353559", +"_ c #15113E", +": c #3D3D62", +"< c #A5A7BE", +"[ c #ABAEC0", +"} c #4D4D70", +"| c #323257", +"1 c #13133C", +"2 c #010130", +"3 c #494969", +"4 c #E9EAF5", +"5 c #D9E0F3", +"6 c #7B7C99", +"7 c #2B2E53", +"8 c #04042E", +"9 c #4B4B6A", +"0 c #F5F5FF", +"a c #DCE1F5", +"b c #848AA3", +"c c #3B3F5D", +"d c #05062E", +"e c #E0E4F9", +"f c #DDDFF5", +"g c #878AA3", +"h c #36375B", +"i c #050A34", +"j c #5D5D7E", +"k c #8991AE", +"l c #5A5976", +"m c #1E1D47", +"n c #17194C", +"o c #ABAEC5", +"p c #2D466E", +"q c #22335A", +"r c #1E2F60", +"s c #354368", +"t c #767DA0", +"u c #8590AC", +"v c #646790", +"w c #3F4D71", +"x c #41486B", +"y c #303762", +"z c #717FA1", +"A c #4F5275", +"B c #1E2958", +"C c #9196B6", +"D c #C9CBE2", +"E c #6A6D8A", +"F c #1E2042", +"G c #A5ABC9", +"H c #ABAFC7", +"I c #6A6B88", +"J c #2A2752", +"K c #575B7A", +" .+@ ", +" #$%&* ", +" =-;>, ", +" ')!~{ ", +" ]^/(_ ", +" :<[}|12 ", +" 345678 ", +" 90abcd ", +" 9efghi ", +" j klmn ", +" o pqr s ", +" t uv ", +" wxy ", +" zAB ", +" CDEF ", +" GHIJK "}; diff --git a/icons/music.xpm b/icons/music.xpm new file mode 100644 index 00000000..025a7946 --- /dev/null +++ b/icons/music.xpm @@ -0,0 +1,90 @@ +/* XPM */ +static const char * music_xpm[] = { +"16 16 71 1", +" c None", +". c #4A43C6", +"+ c #6A66DA", +"@ c #8078DA", +"# c #6A53C6", +"$ c #4D47CB", +"% c #4B5EDE", +"& c #616EE4", +"* c #717BE4", +"= c #9199F3", +"- c #B9C1FE", +"; c #AFBBFE", +"> c #B9C0FE", +", c #A2ACFE", +"' c #7380FE", +") c #4255D1", +"! c #9BA7FE", +"~ c #A2AEFE", +"{ c #6E7BFE", +"] c #6370FE", +"^ c #7888FE", +"/ c #8192FE", +"( c #8090FE", +"_ c #7685FE", +": c #6674FE", +"< c #5F60ED", +"[ c #6171FE", +"} c #5358DF", +"| c #4F4CD1", +"1 c #4D40C6", +"2 c #4C37BD", +"3 c #461FA2", +"4 c #606BF8", +"5 c #575CE5", +"6 c #4D43C8", +"7 c #565AE3", +"8 c #4D3EC5", +"9 c #473ECB", +"0 c #4D4EDA", +"a c #4938C2", +"b c #4F62C1", +"c c #8F94D5", +"d c #5A43AC", +"e c #4633BF", +"f c #6479D2", +"g c #D8DAFE", +"h c #7674E0", +"i c #908BCF", +"j c #4842CF", +"k c #472FBC", +"l c #354EC3", +"m c #9EA4FE", +"n c #99A1FE", +"o c #647DFE", +"p c #492DB9", +"q c #676FF8", +"r c #5B6EFE", +"s c #8294FE", +"t c #4B2EBA", +"u c #4C43C3", +"v c #767AFE", +"w c #491092", +"x c #3440B5", +"y c #6A74FE", +"z c #6673FE", +"A c #586DFE", +"B c #471398", +"C c #3A138D", +"D c #552EAB", +"E c #511B99", +"F c #7073F8", +" .+@#$", +" %&*=-;>,'$", +" )!;;;~{]]]$", +" ^/(_:]]<<$", +" [}|123 4$", +" 4$ 5$", +" 56 7$", +" 78 9$", +" 0a bccd9$", +" 9e fggggh$", +" bcidjklmmnmmo$", +" fgggghplqrrrrh$", +"lmmmnsot uvvvvw ", +"xqyzrAhB CDE ", +" uFvvvw ", +" CDE "}; diff --git a/icons/note.xpm b/icons/note.xpm new file mode 100644 index 00000000..531ec12c --- /dev/null +++ b/icons/note.xpm @@ -0,0 +1,21 @@ +/* XPM */ +const static char *note_xpm[]={ +"16 16 2 1", +". c None", +"# c #c00000", +"...........#####", +"......##########", +"......##########", +"......##########", +"......##########", +"......#####....#", +"......#........#", +"......#........#", +"......#....###.#", +"..###.#...######", +".######..#######", +"#######..#######", +"#######..#######", +"#######...#####.", +".#####.....###..", +"..###..........."}; diff --git a/icons/note2.xpm b/icons/note2.xpm new file mode 100644 index 00000000..8c8d80b9 --- /dev/null +++ b/icons/note2.xpm @@ -0,0 +1,39 @@ +/* XPM */ +static char *note2[]={ +"16 16 20 1", +". c None", +"a c #000000", +"c c #010101", +"j c #404000", +"m c #555540", +"b c #555555", +"# c #585858", +"q c #606000", +"p c #8f8f30", +"g c #8f8f3f", +"r c #a0a000", +"o c #bfbf60", +"e c #dfdf7f", +"i c #efef9f", +"f c #efefbf", +"k c #ffffc0", +"n c #ffffcf", +"l c #ffffdf", +"h c #ffffef", +"d c #ffffff", +"..#a............", +"...aa....b......", +"...#a...bbcbc...", +"....#a.bd...cbc.", +".....abddde...ca", +".....bad##fee..a", +"....bdafee#efd.g", +"...bdhiaffe#ddgj", +"..bkhlef##fddgj.", +".mkkn##helhdgj..", +"bokkkkn#lhhpj...", +".mookkknelgj....", +"..bqrokkkpj.....", +"....bqropj......", +"......bqj.......", +"................"}; diff --git a/icons/notemarker.xpm b/icons/notemarker.xpm new file mode 100644 index 00000000..8e35d2af --- /dev/null +++ b/icons/notemarker.xpm @@ -0,0 +1,120 @@ +/* XPM */ +static const char * notemarker_xpm[] = { +"16 16 101 2", +" c #000000", +". c #F0ECCB", +"+ c #FBE73B", +"@ c #F2B64D", +"# c #D2C26A", +"$ c #D3C36B", +"% c #D4C46C", +"& c #D6C66E", +"* c #D7C76F", +"= c #D9C971", +"- c #DACA70", +"; c #DBCB73", +"> c #DDCD73", +", c #FCEB3D", +"' c #F7B544", +") c #665931", +"! c #D8C870", +"~ c #D9C96F", +"{ c #FCE93B", +"] c #F7B545", +"^ c #6C5F34", +"/ c #D6C66C", +"( c #D7C76D", +"_ c #D8C86E", +": c #DBCB71", +"< c #DBCE73", +"[ c #F9DF39", +"} c #F4B244", +"| c #6A5F36", +"1 c #BAAF65", +"2 c #DCCE72", +"3 c #DDCD75", +"4 c #F6D236", +"5 c #EFB44D", +"6 c #5C4F2B", +"7 c #E3D67B", +"8 c #DACD77", +"9 c #DFCF75", +"0 c #D7AE74", +"a c #655930", +"b c #E4D77C", +"c c #DBCE77", +"d c #4F4115", +"e c #E5D87D", +"f c #E6D97E", +"g c #DCCF74", +"h c #DECE74", +"i c #E0D276", +"j c #E7D97F", +"k c #DBD079", +"l c #E1D377", +"m c #E2D478", +"n c #DED074", +"o c #DFD277", +"p c #E2D57A", +"q c #E3D579", +"r c #E7DA7F", +"s c #E8DB80", +"t c #DCD079", +"u c #DED176", +"v c #E1D479", +"w c #E6D87C", +"x c #E9DC81", +"y c #DCD17A", +"z c #F1EDCD", +"A c #EFE9C0", +"B c #F0EAC1", +"C c #ECE5B1", +"D c #ECE6B2", +"E c #E9E19E", +"F c #EAE2A0", +"G c #EBE3A8", +"H c #ECE3A9", +"I c #EDE4AA", +"J c #EDE6AB", +"K c #E5DEA0", +"L c #A69D59", +"M c #A79E5A", +"N c #A89F5A", +"O c #A9A05A", +"P c #A9A05B", +"Q c #AAA15C", +"R c #ACA25D", +"S c #ACA45E", +"T c #ADA35F", +"U c #AEA560", +"V c #B0A561", +"W c #B0A661", +"X c #BEB366", +"Y c #BFB466", +"Z c #C0B567", +"` c #C1B667", +" . c #C2B869", +".. c #C3B86A", +"+. c #C3BA6B", +"@. c #C4BB6C", +"#. c #C5BA6E", +"$. c #C5BC6E", +"%. c #C8BF6F", +"&. c #C7BE70", +"*. c #BBB168", +" ", +" . . . . . . . . . . . + @ ", +" . # $ % & * = - ; > , ' ) ", +" . $ % & ! ~ - ; > { ] ^ ", +" . / ( _ ~ : < > [ } | 1 ", +" . ( _ = : 2 3 4 5 6 7 8 ", +" . ! = : 2 3 9 0 a b b c ", +" . = : 2 3 9 d b e f c ", +" . ; g h 9 i 7 b e f j k ", +" . ; g h 9 i l m 7 b e f j k ", +" . g n o i l p q b e f r s t ", +" . u o i v p 7 b w f j s x y ", +" . z A B C D E F G G H I J K ", +" L M N O P Q R R S T U U V W ", +" X Y Z ` .....+.@.#.$.%.&.*. ", +" "}; diff --git a/icons/play.xpm b/icons/play.xpm new file mode 100644 index 00000000..ab2aa8b0 --- /dev/null +++ b/icons/play.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static const char * play_xpm[] = { +"16 16 7 1", +" c None", +". c #000000", +"+ c #808000", +"@ c #808080", +"# c #FFFF00", +"$ c #C0C0C0", +"% c #FFFFFF", +" .. ", +" +@.@ ", +" +#.$$ ", +" +#@@$%@ @ ", +" +#%.$%%@ @ ", +" ++#%#.$%%@ @ ", +"+%$%#%..%%@ ", +"+#$#%#.$.%@ ", +"+#$%#%.@.%@ @@@@", +".+@#%#..%%@ ", +" ..+#%.$%%@ ", +" .+#.$%%@ @ ", +" .+@@%%@ @ ", +" .+.$$@ @ ", +" .+.@ ", +" .. "}; diff --git a/icons/post.xpm b/icons/post.xpm new file mode 100644 index 00000000..6a82550a --- /dev/null +++ b/icons/post.xpm @@ -0,0 +1,25 @@ +/* XPM */ +const static char *post_xpm[]={ +"16 16 6 1", +". c None", +"d c #404000", +"a c #808000", +"# c #c0c000", +"b c #ff0000", +"c c #ffff00", +"........#######a", +"..######bbbcbbba", +"##ccbbbcbccccbca", +"bbbcbcbcbbbccbca", +"bcbcbcbcccbccbca", +"bbbcbcbcbbbccbca", +"bcccbbbcccccccca", +"bcccccccaaaaaaa.", +"ccaaaaaa....dcd.", +"aaacd.......dcd.", +"..dcd.......dcd.", +"..dcd.......dcd.", +"..dcd.......dcd.", +"..dcd.......dcd.", +"..dcd........ad.", +"...ad..........."}; diff --git a/icons/post2.xpm b/icons/post2.xpm new file mode 100644 index 00000000..09a16a3c --- /dev/null +++ b/icons/post2.xpm @@ -0,0 +1,27 @@ +/* XPM */ +const static char *post2_xpm[]={ +"16 16 8 1", +". c None", +"# c #000000", +"f c #585858", +"e c #808080", +"a c #dcdcdc", +"c c #ff0000", +"d c #ffc0c0", +"b c #ffffc0", +".....######.....", +"...##abbbba##...", +"..#bbbbbbbbbb#..", +".#bbbcccccddbb#.", +".#bbbccccccdbb#.", +"#abbbccbbbccbba#", +"#bbbbccbbbccbbb#", +"#bbbbccbbbccbbb#", +"#bbbbccccccdbbb#", +"#bbbbcccccddbba#", +".ebbbccbbbbbbbe.", +".#bbbccbbbbbba#.", +"..#bbccbbbbbb#..", +"...#bbbbbbbb#...", +"....#fabbaf#....", +"......####......"}; diff --git a/icons/post3.xpm b/icons/post3.xpm new file mode 100644 index 00000000..29df447b --- /dev/null +++ b/icons/post3.xpm @@ -0,0 +1,24 @@ +/* XPM */ +const static char *post3_xpm[]={ +"16 16 5 1", +". c None", +"# c #000000", +"b c #ff0000", +"c c #ffc0c0", +"a c #ffffff", +".....#####......", +"...##aaaaa##....", +"..#aaaaaaaaa#...", +".#aaabbbbbcaa#..", +".#aaabbccbbaa#..", +"#aaaabbaabbaaa#.", +"#aaaabbccbbaaa#.", +"#aaaabbbbbcaaa#.", +"#aaaabbaaaaaaa#.", +"#aaaabbaaaaaaa#.", +".#aaabbaaaaaa#..", +".#aaabbaaaaaa#..", +"..#aaaaaaaaa#...", +"...##aaaaa##....", +".....#####......", +"................"}; diff --git a/icons/progressbar.gif b/icons/progressbar.gif new file mode 100644 index 0000000000000000000000000000000000000000..f43367b711d2b285d8ab5690572711e9e701a668 GIT binary patch literal 3130 zcmcJRdsNbQ7{+mSLC~?T<I;}RDiPPtx?^tZbXCw=si{b()?Kk|Q%ljdxn&_>+R{R0 zc1%qL?5a7%vNkgeT5YqG#MPEg5v&znxLNG?{eo$QwM+f~JHPjHp6~NM@8eBdM)h2O zz+o&Z(E;T;z1?E5OtN5CEDa1;yl~~xneTt#=zv0@COsatIBN6yn9Z9e#)ij)P4uQM zUx}Jz9EKi_vY_5WK0tv#px)S&k|t8z!{vWh*2FKpea?*Ach~1|8@Es+FTanK>HHdd z_qUs_=^x{qF`P?z50m{Uf~$pHPW$OaH^e=>pIF~FpU`99<jY#m7*keA8avC)E@_JP zZt0`c>sozZwFQUAhafc156(+M2A_9$W-w#EMov-N1_$4}w!jDnZxC}@32^YuDMcm4 zV6gX%$c<p|@{^tm!Qd8SbE=|UrxzlFPwp~2#^E#Tw@wR-OZHi$KBQC|d`>He(-`4o z+GbHDjpJGCM5MQ6O<~2$y_@#Pn^*->4aF<LQL=<D<Zr0T*P5~Z_OTJY&_J)i6Hn>2 zzP3EF;IdV(UWNYfn^3P`T76BaP_M|0KtVUqt3WLH(S<MD)UJ1SN3iFPc8Nvw^89cu zqF19=HV#ilx5mzmOU?}OHyl$N(4vd#ag1;_m9ew(3PV7<NuY%Gie|_2c&oEBnl$lc z((d`b{4uHkp+pj;C^dUA?P3>zXU;(ZwV64Co>|N}d*AoC6<g}0|FRqlpSjND{zV;p zW><wc0zPv=54MvhYt_A#awHRZX0MD?$J^b~oavw3(f55kJFU%)>J#UP4$3U9K*xsF zq6zNdzZ<A*ZbvZV(5((*d1bdJoibh=m@OvmG?kh#zBlA!nGwucs^}_3!a;03sWW(J z@OytH0)KYx9qiAr`&eeD&7ZZ8FZ|&I{kaAuxL5%EnSYhC4S=sn>k)P!;8CMePW%_} zD-c|YfYWW@8X^GKLU2+&X~OCkfa5kg!o^~k1{P~_GgcPjYh5f?9j>!`A6Tp<BLqL# zz*+s^RW|VI{|k;O1BzS0%@Ew9o>XGr;m|6;;Z926@Ew?eMBt2+ooQ=;iJ<Dj^*skJ zhTzTI9+eIJ+N%fmswZt*X;<<5{wNFl27o85-TNfU?v9k{2Ed2)JgfK<aIFoz;dOv} zFkZ}E7CP(<*v<IH{s=xnxU6eFZ;fC#7iZpX7{R(EzoR-3!Lq`g%RmH2wqQoEkqBnL zy(0P=62b4RQaC)2K3Z`^^02SkRV3)0=M$nFjo(sSQAhq7-GFx|7~|%!xyImdxSO{S zi)+To;cjXWr)cYm$Zkf=!p2l7%<24_zCm`mpBSaANt*~W#dTT#=@4>tez6a%ry~%H z@xB00$GV!f&j5GekuJIfo{mHpPBn5moX1GEtC7>OuB1J&;!$e*uZ_lPi>0(^gilCV z=4A4&iaI4eJ?>AkXC<1ul$({cl_2UcvM+ZGqlZeTHf<71#Yv`17*bUWWlBVXY7r?( zq4LdRwnzeA2F`a=f=rp5dB}G2RH-_@udLwJL0HW8p~3k!@Q(oa)}g`G2k>nJ;Ot`^ zM(z;cq{YlV3YG9^mDc<chl4O24#N=7>Oa=ZR=>tiQ{b^adCG}1H5VRha$b5}3UaI| zo!sLL<X8)YE@=RK_c+O5@R9X5q2jWUh~mmAc%ZoYK(U(a$wp^E#kmmN2o={r#WA%& z@%d134@7a{(TIRhyMjO2Opt{Qxv*sLRQ)A`PHWsnhTM0moH)~-<34NSPPcI{7$o?s z;ZBIQe|(<ezCFPJGyGkStsIrm8p{W`-G<~A*ti$IdhYx{yLu1WOpt_bC>Y_4cw4DE zm)pBPy&IOgsHjUD=&;na)u89h2c<5X%lcf2l)9iuS<xw^)a|J2{MO`>R-=kZ>`T2K zpxu7nf~%;JjSmTnE1u!A5AjKHF143RW8f=SXNlZnMQ4pp#0J8+P?mHaWv5h5%n&yb zJxE=lvlI9df8Pw1HsZ8!<EnoG9`U-s4Kt`#@CpN!M))`2W9)AxXtRW8YV<(`w~!Lh zU!%*~r191oeJtl;*hE;Pvlh~$e+D(0SGXpl7iqIOzs-yQHJVw9tf`{?z8+D0opuYN zxS=K(C{CTJ+>0oloKNkc(%5)+MwW;j>y9X%-M}3i%Hqw5kCDoy8LS&b4^@|RRs!Gb OFG*Kv&Fhf}_xc-C1W8l? literal 0 HcmV?d00001 diff --git a/icons/progressbar.xcf b/icons/progressbar.xcf new file mode 100644 index 0000000000000000000000000000000000000000..0c19d51162ea2f176c42fd30b999a23fbc0f2fd2 GIT binary patch literal 13026 zcmd^_d1zck9LHx<lQd0}HtEJDY0}v?ZH^|>WTUke1*H{h@dO3M15DG+b~Q&$Qf)n` zig+N1c%TSMQ4|zKPy|5~6~&v1;;rC;JW*5>54<{le*5ym+n9w$e`Wu0;Pc*ZXMXSd zcIVA+-W;3FjqFJ68XQUu<%ToHn8eK-k|3!L5(y4VVE#sm1d=!$0>{9iQ?~du;J=x3 zO%_=<I5skp8J*;_k;3{-<C%fU%(m1exykLR&09`BO-dH$U2`J?*^JAM=e9{6-U-t= zF}Zs<lbRSC&TZ>j&^eSH92*`RPj%)`ZalknAl0|FFP~;H(o;oUT)K6ZOQZ5saYHWM zHL+u0FgKb_rK5Y1xqG(EsXVuHG&h;bjSg<lOvv?PLqijp$>}dBSN}6B%qhH7>R~D+ zzB8tL8BgFUV-~zg?f%81S;JE})0m~#7}NB&F|GKfoH1=@8`FNBF`f8z<JXH{dLmMy zUgZHs&$sIM@qv*{Dt&~MSAaZI5A&yNPNphmFNoRIF?(Umu8G-;uth6Ml^AjlNl_c> z4nNAV?AFkp{*v>^dz?#tr2??aMUNDfmwjZ+yw~78_yWF%Kk)xXyqfH4uZlxYlK?$M z_LLhx7uNeqtBgZWlK?$6_9TwA;2@xRybRKwB}uPSp0|wY=Uf)rQ9H|jih^aGd@5D2 zbcA0_j^)pW_VkyO0Qr=7I}dWOv#`8^K&&9>DpJq`8{jx&Di0UGxip-azRiA>RmP#G zNr0XjwRXR^H3#uve68E>UClu}aEoBS4{8qLA^#@%w^5dFl%<NY)nVkwv8p|^<55<1 zJUz$5@FcuYSY9>CHJ8G*a0}c658=00{ANbZTs~L%!)&!836G*fQH{J}fT9`+PiH+1 z75HzP(_vEkrD{%Xa`P}%&*+p5op$x@4Cy|AFX4yKFKTYpPgDL1yaS)Xx5g~|1iv@L zZ!XP8e7pS;tBgZWlK?$6thHVhhn^+@dWt9oi;RFu7Az~|=3%P6H#|qdAi+}mJaZoc zxvn0T7naw4P5CdzEMoY!s1}-;UNXd6{JZ$gHCXC>k5$H@r%8aG8WnbfSH+>HNr0Xr zO2LwrwpFS(i<O&)scv6*jt5H}^Wh|~z9j23$rB69>zA@3!<(tT7mi|yhk1CCMTTU4 zig6&pa-=V}$~g2i3D8r+**dR^Lr;?cJw*!IfX*<iPugIqf~7SK068ZA4DEQZG_<gq zc0LTluEO#L=E)7G!MU)VHP5r~IRVZPzk-S?vIvv%%dIjFJxv1i)JWPjUKNL)CINbi z6tn@AVCg$j+E%H8g*QQz8oNR(9xRPpSYLe<o`RPO%Ns8;rtu260hrq~-3WKUed1S8 zQAL8KQgNCqQ|5UdMYU<JOquhFYSUbqGS4f%cB|8zSnexbb83>ChpBl+-zuZ}<~xmP z`53-}pF+Q=xivpa`Rnk$G0T|$w>$}~y0oyvQM@^=^^2`C4n0i*^wd~sTf8a`Jxv1i z6e-$`=mg7pX<Mc0dl{KWsrCNQih@CcrS(O&`l_G-rl!kLc`NHft-l$wyc~Wu#<Hel zSyQrqiB7RfYw%rG8Hb)G0eWgw*>zqOhn^+@dWsZ#?mAQ8zLIVqv(6Kx)LWqy1%m`j z>PPm(`GRd5;grJi6|4`fXg6l%p_CEqZLBG^v8L3vM*QNHcC;_E$~g2i3D8rc&(?ZX z9D14r=qVC^)<tcdH_JL{TcvulRLjl7)F%J)AjN}a73)dugD?h{6_&5sY|N_Djaj{k zGS-yZSyO6fO{x7%@rzeln_p&?ap-9hpr^)C+u>Dl=xGw5r%3!+7qxYQrKG#S46&lr z!T%*B#e=2eB>rXfFfbqKoUsesF=<T4mE`Y$%i(&s4fcvkywYTPs*LJHSEi<##DDt% z**XoWr2D^>^3cQ7wKF`&8&cQp{8f+r-)_e0-81%oyPh^?%_HRB4G+Q-@Eqj#f78Ck zD&x@8BtTD%)wap2;?UD1Ku?ha3Xu33noh9vOB*fK5QT|rlzL{_|LtM_x0mnM%UHd4 z#{O>)`@il(W7fV3@51Ns9pv|a8-2S~#-XQ4fSwu)ZNFE=p{GfJo+2d*mXhxOGQo{f z@4nEAzgc>}=g;4#!a0yFEbn8LDb1THy#yHdr`i8av+R{-d~eMEYfw^MeC<8nyB4$m zTd!NaabWPm?D*Ku(QQ)mWpW_R*8e8Rmr>~<;y~iREz`D4?V|jJF}o&aFT$P=QIdg4 zbWL)~j_%LL{*|F)yh-(MB>x$pkL{<Al@yitUqIf)a5dZncfkYjn0U=OK9#EbZ+KT3 Ag#Z8m literal 0 HcmV?d00001 diff --git a/icons/record.xpm b/icons/record.xpm new file mode 100644 index 00000000..e68e0387 --- /dev/null +++ b/icons/record.xpm @@ -0,0 +1,29 @@ +/* XPM */ +const static char *record_xpm[]={ +"16 16 10 1", +". c None", +"# c #000000", +"f c #00ff00", +"c c #800000", +"e c #808000", +"b c #808080", +"g c #c3c3c3", +"d c #dcdcdc", +"h c #ff0000", +"a c #ffffff", +"..###......###..", +".#aba#....#aba#.", +"#aabaa#cc#aabaa#", +"#bbabb#dd#bbabb#", +"#aabaa#dd#aabaa#", +"e#aba#dddd#aba#e", +".e###dddddd###e.", +".ceddddddddddec.", +".cdebbbbbbbbedc.", +".cddeeeeeeeeddc.", +".cddddddddddddc.", +".cddddddddddddc.", +".cddffdggdhhddc.", +".cddffdggdhhddc.", +".cddddddddddddc.", +"..cccccccccccc.."}; diff --git a/icons/record2.xpm b/icons/record2.xpm new file mode 100644 index 00000000..5cecb04a --- /dev/null +++ b/icons/record2.xpm @@ -0,0 +1,26 @@ +/* XPM */ +const static char *record2[]={ +"16 16 7 1", +". c None", +"# c #000000", +"e c #404000", +"b c #585858", +"d c #808080", +"c c #c3c3c3", +"a c #ffffff", +".....#####......", +"...##aaaaa##....", +"..#aaabbbaaa#...", +".#aaaabbbaaaa#..", +".#aaaacbcaaaa#..", +"#aaaaaabaaaaaa#.", +"#abbcad#dacbba#.", +"#abbbb###bbbba#.", +"#abbccd#dacbba#.", +"#aaaaaabaaaaaa#.", +".#aaaacbcaaaa#..", +".#aaaabbbaaaa#..", +"..#aaabbbaaa#...", +"...##aaaaa##....", +".....#####eeeee.", +"..............ee"}; diff --git a/icons/record3.xpm b/icons/record3.xpm new file mode 100644 index 00000000..84d64263 --- /dev/null +++ b/icons/record3.xpm @@ -0,0 +1,26 @@ +/* XPM */ +const static char *record3[]={ +"16 16 7 1", +". c None", +"# c #000000", +"e c #404000", +"b c #585858", +"d c #808080", +"a c #ff0000", +"c c #ffc0c0", +".....#####......", +"...##aaaaa##....", +"..#aaabbbaaa#...", +".#aaaabbbaaaa#..", +".#aaaacbcaaaa#..", +"#aaaaaabaaaaaa#.", +"#abbcad#dacbba#.", +"#abbbb###bbbba#.", +"#abbcad#dacbba#.", +"#aaaaaabaaaaaa#.", +".#aaaacbcaaaa#..", +".#aaaabbbaaaa#..", +"..#aaabbbaaa#...", +"...##aaaaa##....", +".....#####eeeee.", +"..............ee"}; diff --git a/icons/redball.png b/icons/redball.png new file mode 100644 index 0000000000000000000000000000000000000000..5ba34b749c25fc10fe5dfc05d80360b48c900252 GIT binary patch literal 410 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xawj^(N7l!{JxM1({$v_d#0*}aI z1_o|n5N2eUHAey{$X?><>&kwei<3{=@Mb!rD+2?gx~Gd{h{pM&lMMY2Ifxvu&-Kv= zmP~x(k`VaX>5`{C*GJ_8PB(laWTfxj@->$&z1(?Vk;PO$R`EC2k{|Z1<XbE1D)Uvh z{OA7PPxt=b&t5Nkt32_Bwg2hIk~Zg!4sM&E%bkAVYFU&2+qkH2?pIbm=}PKUatX?s zU+{##>-(>CRr9NV*k6TQ@MZqHp)t-VptA1KeWN!!Uy4P@`QKdL7RU6f_C?772F5iE ztTu5~uI1H7-#+%2D5zysO4}u-GvSONhk`)9eZv85uH>}=lLeVhGP(9Bu_;Z`R})*C z6z$@{q$0?9kxk@D`qeeL&6}<&xEQz#EaC`c(NGd{iCg>f#_nT<)2iyy8XT0&ijK3J z-JM?jb~<ap<=Nc*6*DCRO|wm8XJ59Ce;of<_SchAjn1g>a$qPjc)I$ztaD0e0swLi BoXh|K literal 0 HcmV?d00001 diff --git a/icons/redball.xpm b/icons/redball.xpm new file mode 100644 index 00000000..ca12ffda --- /dev/null +++ b/icons/redball.xpm @@ -0,0 +1,58 @@ +/* XPM */ +static const char * redball_xpm[] = { +"14 14 41 1", +" c None", +". c #940028", +"+ c #4A0017", +"@ c #C57A93", +"# c #C60038", +"$ c #FF0F59", +"% c #720020", +"& c #CE1049", +"* c #EE0041", +"= c #FF2162", +"- c #9C0028", +"; c #FF8BD5", +"> c #720F30", +", c #4A000F", +"' c #C57A8B", +") c #CE0038", +"! c #FF0F51", +"~ c #FF0751", +"{ c #9C4A62", +"] c #AC0030", +"^ c #841030", +"/ c #5A0017", +"( c #FD0051", +"_ c #CD627A", +": c #FF317A", +"< c #5A0020", +"[ c #BC0038", +"} c #D60841", +"| c #B40030", +"1 c #D60041", +"2 c #620017", +"3 c #840028", +"4 c #CE426A", +"5 c #8B3049", +"6 c #CD6283", +"7 c #FD0049", +"8 c #BC0030", +"9 c #DE0041", +"0 c #FFA5EE", +"a c #E60041", +"b c #6A0020", +" ", +" ", +" '4&&4' ", +" _1((7*#_ ", +" @)($:~a#-@ ", +" 4(~;0!1[.^ ", +" &7~:=}[-3/ ", +" &9a9)|-32/ ", +" 4[[8]-3<+> ", +" @.-.3%2,+{ ", +" 6bb/+++5 ", +" @>//>{ ", +" ", +" "}; diff --git a/icons/redcheckmark.xpm b/icons/redcheckmark.xpm new file mode 100644 index 00000000..0f0a27d3 --- /dev/null +++ b/icons/redcheckmark.xpm @@ -0,0 +1,63 @@ +/* XPM */ +static const char * redcheckmark_xpm[] = { +"16 15 45 1", +" c None", +". c #990000", +"+ c #AC3030", +"@ c #C64A40", +"# c #9F0300", +"$ c #F97252", +"% c #FF3301", +"& c #DF2200", +"* c #F97152", +"= c #FF3300", +"- c #FF3200", +"; c #CC1900", +"> c #BF5854", +", c #F99F76", +"' c #D2431F", +") c #B34040", +"! c #F97151", +"~ c #D91F00", +"{ c #DF775A", +"] c #FF7838", +"^ c #FF6F30", +"/ c #D93F19", +"( c #BF6060", +"_ c #FF8161", +": c #D21C00", +"< c #AC160A", +"[ c #F9672D", +"} c #FF6528", +"| c #FF5C21", +"1 c #D93310", +"2 c #FF8061", +"3 c #BF1300", +"4 c #AC1308", +"5 c #F9551E", +"6 c #FF5219", +"7 c #FF4812", +"8 c #EC3308", +"9 c #FF4F22", +"0 c #AC0F05", +"a c #EC3A0E", +"b c #FF3E0A", +"c c #FF3503", +"d c #9F0401", +"e c #EC2B02", +"f c #B30D00", +" ", +" . ", +" .+@# ", +" .+$%&.", +" ... .+*=-;.", +".>,'. .)!--~. ", +".{]^/. .(_--:. ", +" <[}|1.(2--3. ", +" .456789--3. ", +" .0abc--3. ", +" de--3. ", +" #;f. ", +" . ", +" ", +" "}; diff --git a/icons/redx.png b/icons/redx.png new file mode 100644 index 0000000000000000000000000000000000000000..ddb633f05749f0914c4fc8b8cda657d291974555 GIT binary patch literal 691 zcmV;k0!;mhP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru*9r*^C?a<B6IcKM0zgSb zK~y-)t&=}YQ*jW-KfhO6T5QXoz6NWeQHVl<M8cv@1|8~RqA|gcI5KFWgNwmI<A4zs zCZZ;;#u($^Xp96kFi43)tZ1bO5eaSSpVt<6w6E{|9Eb&io%E)=<i6j#``#V=qlrJx z>4O2Omn_2Bb@KVVs02_HMcQmO48srr3P9&xpL~41mxpIM>8h*7<MGJ9f!iBZIeP6f z&$`-i*{fuk!0oWJJ~K^0-=MFfnNwcJE^tRcl`ndNh|eM7u>>wG0IC3{QdzWk3^S8N z0)3s$)YUlUli4K!u)o$VpLPdX2z?-u)p?W1kv1%`LxW@fIyrp&2u3Cez^W-3oY$C0 zuQGn6oAmS~6EThFOKHMuhS(({K%37iADwKam`P#+rUhnGEBkbf(A*;TBg-soly+d0 z?ZKB+PTZP|;;2_af=z&$PZ3*=@nAl|&!Sa%joa50RBO0*K1gO}8q=~60ty!N&87$^ zvz0pl2-p<{uJ)ou!W4vpDL1RQ6zFfRr_JY;6$wrRRQd8oFUhyB2x~eQCl~4ek)gU? zMF8F^g~1j-hZ}0;4gw*BymTlahkMSEe*c<CZk?fM0$ta|cswKSgudfw*d%ca$?eug zoOb)xAvL+|+`Mp>Y-o&my~I#-g@v_^@~oqAO$>aTqq@P50_-UjIpB6~b&!;Tv5^tJ z<_p~Y79*P1cZvHhS7cyn4u{XrsuX4Y%ZW$5E~yzMe(6TVNAh?)vc==XG)+Fm(}MqD ZzX2HN?stZ2RG0t&002ovPDHLkV1kCKG~@sP literal 0 HcmV?d00001 diff --git a/icons/redx.xpm b/icons/redx.xpm new file mode 100644 index 00000000..84ab63de --- /dev/null +++ b/icons/redx.xpm @@ -0,0 +1,121 @@ +/* XPM */ +static const char * redx_xpm[] = { +"16 16 102 2", +" c None", +". c #422019", +"+ c #391C17", +"@ c #0D0D0D", +"# c #020202", +"$ c #050505", +"% c #321813", +"& c #DD8D7D", +"* c #D05F49", +"= c #4E1D14", +"- c #2D1714", +"; c #C16E5E", +"> c #AD4632", +", c #090504", +"' c #3E1E18", +") c #D3634E", +"! c #C95641", +"~ c #C64D37", +"{ c #4C1B13", +"] c #301914", +"^ c #D9705B", +"/ c #C24129", +"( c #962E1C", +"_ c #120502", +": c #0E0B09", +"< c #C34C36", +"[ c #C03B22", +"} c #BF3B22", +"| c #C44D36", +"1 c #5C251B", +"2 c #1D0F0C", +"3 c #D66F5B", +"4 c #B93B24", +"5 c #922C1B", +"6 c #4E160D", +"7 c #2F1510", +"8 c #BE3B22", +"9 c #B23821", +"0 c #3B1711", +"a c #CA6D5B", +"b c #B83E27", +"c c #822617", +"d c #2C0B05", +"e c #2B130E", +"f c #BD3B22", +"g c #BA3B22", +"h c #B73922", +"i c #B45B4A", +"j c #CE523A", +"k c #992F1D", +"l c #200804", +"m c #3C1812", +"n c #BA3A22", +"o c #C84E37", +"p c #B63922", +"q c #2F0E07", +"r c #49160C", +"s c #CE6653", +"t c #BD3C24", +"u c #BB3B22", +"v c #B43922", +"w c #2C140F", +"x c #1B0704", +"y c #D17F70", +"z c #BE3F27", +"A c #B63D26", +"B c #BC3B22", +"C c #B03720", +"D c #381914", +"E c #CB7868", +"F c #BD3F28", +"G c #922F1E", +"H c #090909", +"I c #B43A23", +"J c #25120F", +"K c #010101", +"L c #572119", +"M c #CC7261", +"N c #B93A22", +"O c #96311E", +"P c #200B08", +"Q c #411710", +"R c #A23A26", +"S c #080505", +"T c #230A06", +"U c #CD7261", +"V c #BD3D25", +"W c #98311E", +"X c #240D09", +"Y c #C23B22", +"Z c #AD3620", +"` c #26110D", +" . c #0F0907", +".. c #912F1E", +"+. c #94301E", +"@. c #180906", +"#. c #A13521", +"$. c #26110E", +"%. c #2C0E09", +"&. c #1C0905", +"*. c #341A15", +"=. c #311712", +" ", +" . + @ # $ ", +" % & * = @ - ; > , ", +" ' ) ! ~ { ] ^ / ( _ ", +" : < [ } | 1 2 3 4 5 6 ", +" 7 < 8 8 9 0 $ a b c d ", +" e < f g h i j k l ", +" m < n n o p q # ", +" # r s t n u v w ", +" x y z A h B f C e ", +" D E F G H 0 < 8 8 I J ", +" K L M N O P Q | } [ R S ", +" T U V W X { ~ Y Z ` ", +" ...+.@. @ = o #.$. ", +" %.&. @ *.=. ", +" "}; diff --git a/icons/rivendell-128x128.png b/icons/rivendell-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..556d766395260ad69f1946b4c7f8f8b0e9053b3b GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSjKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPggqW+_ooR(B`qDh38-QBN1gkcwMx z??&e>b`WSytTOp+WbM7lc$3kyToXN`5Uaaw+kVz*@(Y>?yj<cJ`ZaeJ&>RMa1ECsw z^LO}NmXZr_`_+8ibWgnG>%V=^rvGouc4lB<U}9iwU~phiU=U#7KyWKUXB|KE_{V>9 zxr!G*s%8HB-+!O<nc0OwjDhJu>d(IoOBTJUDp-72?{rc5{>pi)-~ISl`2Y9q+Z)fH zFPgHrSU|9WwShr_J;QKggh##=Yq`As^m)_mZ|!1%N?3HgsEk~1S7&$a?%vm*uI<|Y z?Y$r)$Ps(I_%^J2ed~K&^7`lN=jJOgf!wwuOMbyt{SABV-d}tBu`2g&{qD2A^Xz{` zv~wI_a$uOi{N?kPO}AH{uX?@J@?b{Fy!~ebosM0q)Ny73dF_M!>8!nuZ~h*aQP@4N zGHK1>?4N&Pn%K`DES}zO_dcgz9Bl8GSIjxzm^D;&d%o|BU!=Zo|NZa0%WC~|zrG3o zULgny7l-wB4!hJZ9Gv_6%;e3x?046do%{IWCyNpTHv^*s--qjmq>tZ!EN7EGxw2}S z@f_c`a&B8KTc8g7vxR@cJMI<y3;4kS*kQ7s`^FQN!nk@Ps|j=EFW9ATIQMz;@0noP z2AKu?{c++KX1}R*i~g++4uBt-d=uXO7Qg;0_tmphPn)mX-tw3Ty#Dgy=Eu@UU*G(e zoO%4VJcAAcOGElw<}2&|_sh+%{eSc1H?wQ(AlE&JEN-|q=Rvo1$=ctGk6$|%xW;z! zin9FVbhbudEIBaTKWn&b(|6-rzXd@lpkehF#;osL_pbeY9dg;c;!EVgwY7~p{1R*R z6__>v6Uh^Xy*B^5y(+JNUhh_>cIl#JBg~VJFYJEKIOP=MpS8>1&X=F?*0JQ<oL%?M zUk5uP;fmdXH2DLkZ0oD)|J{6@2M*H%o1ZYuOi!<EF^avN><UhSi=Qzpt}MGIJ|VaR zoF>n`WVWf&VNe1)E&0^DTOYsQn^*hoGeoucQ~uLi)Ti3|1z%(U0#8>zmvv4FO#u8B BiroMJ literal 0 HcmV?d00001 diff --git a/icons/rivendell-128x128.xpm b/icons/rivendell-128x128.xpm new file mode 100644 index 00000000..ee3bb3d3 --- /dev/null +++ b/icons/rivendell-128x128.xpm @@ -0,0 +1,138 @@ +/* XPM */ +static const char *rivendell_128x128_xpm[]={ +"128 128 7 1", +". c None", +"e c #008080", +"c c #808000", +"b c #c0c0c0", +"# c #ff0000", +"a c #ffff00", +"d c #ffffff", +"................................................................................................................................", +"................................................................................................................................", +"................................................................................................................................", +"................................................................................................................................", +"................................................................................................................................", +"................................................................................................................................", +"................................................................................................................................", +"................................................................................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"....................####....................................aaaa................................................................", +"................############............................aaaaaaaaaaaa............................................................", +"................############............................aaaaaaaaaaaa............................................................", +"................############............................aaaaaaaaaaaa............................................................", +"................############............................aaaaaaaaaaaa............................................................", +"................####....aaaa................bbbb........aaaaccccaaaa........bbbb................aaaa............................", +"................####....aaaa................bbbb........aaaaccccaaaa........bbbb................aaaa............................", +"................####....aaaa................bbbb........aaaaccccaaaa........bbbb................aaaa............................", +"................####....aaaa................bbbb........aaaaccccaaaa........bbbb................aaaa............................", +"................dddd....ddddaaaa............bbbb........aaaaccccaaaa........bbbb............aaaa................................", +"................dddd....ddddaaaa............bbbb........aaaaccccaaaa........bbbb............aaaa................................", +"................dddd....ddddaaaa............bbbb........aaaaccccaaaa........bbbb............aaaa................................", +"................dddd....ddddaaaa............bbbb........aaaaccccaaaa........bbbb............aaaa................................", +"................dddd....dddd....aaaaaaaa........bbbb....aaaaccccaaaa....bbbb........aaaaaaaa....................................", +"................dddd....dddd....aaaaaaaa........bbbb....aaaaccccaaaa....bbbb........aaaaaaaa....................................", +"................dddd....dddd....aaaaaaaa........bbbb....aaaaccccaaaa....bbbb........aaaaaaaa....................................", +"................dddd....dddd....aaaaaaaa........bbbb....aaaaccccaaaa....bbbb........aaaaaaaa....................................", +"................dddddddddddd....aaaaaaaaaaaa....bbbb....aaaaccccaaaa....bbbb....aaaaaaaaaaaa....................................", +"................dddddddddddd....aaaaaaaaaaaa....bbbb....aaaaccccaaaa....bbbb....aaaaaaaaaaaa....................................", +"................dddddddddddd....aaaaaaaaaaaa....bbbb....aaaaccccaaaa....bbbb....aaaaaaaaaaaa....................................", +"................dddddddddddd....aaaaaaaaaaaa....bbbb....aaaaccccaaaa....bbbb....aaaaaaaaaaaa....................................", +"................dddddddddddd........aaaaaaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaaaaaa........................................", +"................dddddddddddd........aaaaaaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaaaaaa........................................", +"................dddddddddddd........aaaaaaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaaaaaa........................................", +"................dddddddddddd........aaaaaaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaaaaaa........................................", +"................dddd....bbbbbbbb........aaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaa........bbbbbbbb............................", +"................dddd....bbbbbbbb........aaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaa........bbbbbbbb............................", +"................dddd....bbbbbbbb........aaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaa........bbbbbbbb............................", +"................dddd....bbbbbbbb........aaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaa........bbbbbbbb............................", +"................dddd....dddd....bbbbbbbbaaaaaaaaaaaaaaaabbbbccccbbbbaaaaaaaaaaaaaaaabbbbbbbb....................................", +"................dddd....dddd....bbbbbbbbaaaaaaaaaaaaaaaabbbbccccbbbbaaaaaaaaaaaaaaaabbbbbbbb....................................", +"................dddd....dddd....bbbbbbbbaaaaaaaaaaaaaaaabbbbccccbbbbaaaaaaaaaaaaaaaabbbbbbbb....................................", +"................dddd....dddd....bbbbbbbbaaaaaaaaaaaaaaaabbbbccccbbbbaaaaaaaaaaaaaaaabbbbbbbb....................................", +"............########....########....eeeebbbbbbbbaaaaaaaabbbbccccbbbbaaaaaaaabbbbbbbb............................................", +"............########....########....eeeebbbbbbbbaaaaaaaabbbbccccbbbbaaaaaaaabbbbbbbb............................................", +"............########....########....eeeebbbbbbbbaaaaaaaabbbbccccbbbbaaaaaaaabbbbbbbb............................................", +"............########....########....eeeebbbbbbbbaaaaaaaabbbbccccbbbbaaaaaaaabbbbbbbb............................................", +"............########aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbccccbbbbccccbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaa........................", +"............########aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbccccbbbbccccbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaa........................", +"............########aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbccccbbbbccccbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaa........................", +"............########aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbccccbbbbccccbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaa........................", +"....aaaaaaaaaaaaaaaaccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccaaaaaaaaaaaaaaaa........", +"....aaaaaaaaaaaaaaaaccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccaaaaaaaaaaaaaaaa........", +"....aaaaaaaaaaaaaaaaccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccaaaaaaaaaaaaaaaa........", +"....aaaaaaaaaaaaaaaaccccccccccccccccccccccccccccccccccccbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccaaaaaaaaaaaaaaaa........", +"............####....aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbccccbbbbccccbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaa........................", +"............####....aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbccccbbbbccccbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaa........................", +"............####....aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbccccbbbbccccbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaa........................", +"............####....aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbccccbbbbccccbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaa........................", +"............########....########........bbbbbbbbaaaaaaaabbbbccccbbbbaaaaaaaabbbbbbbb............................................", +"............########....########........bbbbbbbbaaaaaaaabbbbccccbbbbaaaaaaaabbbbbbbb............................................", +"............########....########........bbbbbbbbaaaaaaaabbbbccccbbbbaaaaaaaabbbbbbbb............................................", +"............########....########........bbbbbbbbaaaaaaaabbbbccccbbbbaaaaaaaabbbbbbbb............................................", +"............########....########bbbbbbbbaaaaaaaaaaaaaaaabbbbccccbbbbaaaaaaaaaaaaaaaabbbbbbbb....................................", +"............########....########bbbbbbbbaaaaaaaaaaaaaaaabbbbccccbbbbaaaaaaaaaaaaaaaabbbbbbbb....................................", +"............########....########bbbbbbbbaaaaaaaaaaaaaaaabbbbccccbbbbaaaaaaaaaaaaaaaabbbbbbbb....................................", +"............########....########bbbbbbbbaaaaaaaaaaaaaaaabbbbccccbbbbaaaaaaaaaaaaaaaabbbbbbbb....................................", +"........dddddddd........bbbbbbbbddddaaaaaaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaa........bbbbbbbb............................", +"........dddddddd........bbbbbbbbddddaaaaaaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaa........bbbbbbbb............................", +"........dddddddd........bbbbbbbbddddaaaaaaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaa........bbbbbbbb............................", +"........dddddddd........bbbbbbbbddddaaaaaaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaa........bbbbbbbb............................", +"........dddd....dddd....dddd....ddddaaaaaaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaaaaaa........................................", +"........dddd....dddd....dddd....ddddaaaaaaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaaaaaa........................................", +"........dddd....dddd....dddd....ddddaaaaaaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaaaaaa........................................", +"........dddd....dddd....dddd....ddddaaaaaaaaaaaaaaaabbbbaaaaccccaaaabbbbaaaaaaaaaaaaaaaa........................................", +"........dddd........dddd........aaaaaaaaaaaaaaaabbbb....aaaaccccaaaa....bbbb....aaaaaaaaaaaa....................................", +"........dddd........dddd........aaaaaaaaaaaaaaaabbbb....aaaaccccaaaa....bbbb....aaaaaaaaaaaa....................................", +"........dddd........dddd........aaaaaaaaaaaaaaaabbbb....aaaaccccaaaa....bbbb....aaaaaaaaaaaa....................................", +"........dddd........dddd........aaaaaaaaaaaaaaaabbbb....aaaaccccaaaa....bbbb....aaaaaaaaaaaa....................................", +"........dddd........dddd........aaaaaaaa........bbbb....aaaaccccaaaa....bbbb........aaaaaaaa....................................", +"........dddd........dddd........aaaaaaaa........bbbb....aaaaccccaaaa....bbbb........aaaaaaaa....................................", +"........dddd........dddd........aaaaaaaa........bbbb....aaaaccccaaaa....bbbb........aaaaaaaa....................................", +"........dddd........dddd........aaaaaaaa........bbbb....aaaaccccaaaa....bbbb........aaaaaaaa....................................", +"........dddd....dddd....ddddaaaadddd........bbbb........aaaaccccaaaa........bbbb............aaaa................................", +"........dddd....dddd....ddddaaaadddd........bbbb........aaaaccccaaaa........bbbb............aaaa................................", +"........dddd....dddd....ddddaaaadddd........bbbb........aaaaccccaaaa........bbbb............aaaa................................", +"........dddd....dddd....ddddaaaadddd........bbbb........aaaaccccaaaa........bbbb............aaaa................................", +"........dddddddd........aaaadddddddd........bbbb........aaaaccccaaaa........bbbb................aaaa............................", +"........dddddddd........aaaadddddddd........bbbb........aaaaccccaaaa........bbbb................aaaa............................", +"........dddddddd........aaaadddddddd........bbbb........aaaaccccaaaa........bbbb................aaaa............................", +"........dddddddd........aaaadddddddd........bbbb........aaaaccccaaaa........bbbb................aaaa............................", +"....########....................########................aaaaccccaaaa............................................................", +"....########....................########................aaaaccccaaaa............................................................", +"....########....................########................aaaaccccaaaa............................................................", +"....########....................########................aaaaccccaaaa............................................................", +"....####....########....########....####....................aaaa................................................................", +"....####....########....########....####....................aaaa................................................................", +"....####....########....########....####....................aaaa................................................................", +"....####....########....########....####....................aaaa................................................................", +"....####............####............####....................aaaa................................................................", +"....####............####............####....................aaaa................................................................", +"....####............####............####....................aaaa................................................................", +"....####............####............####....................aaaa................................................................", +"####................####................####................aaaa................................................................", +"####................####................####................aaaa................................................................", +"####................####................####................aaaa................................................................", +"####................####................####................aaaa................................................................", +"####........########....########........####................aaaa................................................................", +"####........########....########........####................aaaa................................................................", +"####........########....########........####................aaaa................................................................", +"####........########....########........####................aaaa................................................................", +"############....................############....................................................................................", +"############....................############....................................................................................", +"############....................############....................................................................................", +"############....................############...................................................................................."}; diff --git a/icons/rivendell-16x16.png b/icons/rivendell-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..a1ddace9599c52e063d8b63866d73b2c83b3ec4c GIT binary patch literal 439 zcmV;o0Z9IdP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*f2 z6%#QqtVl@!00B2iL_t(I%dL|klEOd`MPILE1yL~w(5%6%&n57=2^<Bzn7u(JH$Y5u zf(!_vuzy9!1W1ait=%>=(=+w^|KC0EUm?&Sr(y0n-u_zn0YIC!qH|6FRn@ZS&Mhm` zIDiD(uRz;5r>eS_W0H`WY}|toNJ8Fkm1U@|6V-Kc%bQ+GD2jqScL2<0-!#pN>vcgK zJ5HyBJkPk717M*8YhVfc^#`Btp8(`J%;&IJz+_Sp$1S)SL54{t_M%wA`P?HPk10{K zqG=9Hrw5|w5blzMM<BHpO0<rbWhx2ncB#rT)#b91_gg*F9~kJpm$Z?D$}&}!5x}~3 zj)DaLZ`0R3&a!^r<zEkyHUg37jwDGQ`rYca!65be&4Lfzo%iFtAN@pOHIvNrtIs45 hX6@SX=*Q$``~cg419((6qa*+T002ovPDHLkV1hm-yB`1m literal 0 HcmV?d00001 diff --git a/icons/rivendell-16x16.xpm b/icons/rivendell-16x16.xpm new file mode 100644 index 00000000..df2f6f6f --- /dev/null +++ b/icons/rivendell-16x16.xpm @@ -0,0 +1,53 @@ +/* XPM */ +static char *rivendell[]={ +"16 16 34 1", +". c None", +"d c #c0c0c0", +"F c #ff0101", +"f c #ffff01", +"D c #ffffff", +"j c #c0c0c0", +"# c #ff0000", +"c c #ff7f00", +"a c #ffff00", +"g c #ffffff", +"v c #aad42b", +"z c #d4d400", +"m c #d4d480", +"p c #d4d4d4", +"n c #e9e940", +"b c #ff0000", +"t c #ff5500", +"y c #ffaa00", +"l c #ffff00", +"h c #ffffaa", +"C c #ffffff", +"w c #a0a060", +"r c #afaf30", +"A c #b0b090", +"i c #bfbf00", +"x c #bfbf60", +"e c #dfdf00", +"s c #dfdf60", +"q c #efef30", +"B c #ff0000", +"u c #ff7f00", +"o c #ffff00", +"E c #ffff7f", +"k c #ffffff", +"................", +"..#....a........", +"..#....a........", +"..bc.d.ead..f...", +"..ghaddiajfa....", +"..kgllminnof....", +"..gpjoqrsonjd...", +".#tuvsswxsnaa...", +"fyziiiwAwriiiaa.", +".##Bjsowsqmd....", +".CDpEosisoldd...", +".gg.oajiajla....", +".CDEgj.iaj.ff...", +"##F#b..zf.......", +"#.#.FF.a........", +"b#F###.f........"}; diff --git a/icons/rivendell-22x22.png b/icons/rivendell-22x22.png new file mode 100644 index 0000000000000000000000000000000000000000..092664c6fdc9ba46f6b38c7bb31ada8954427546 GIT binary patch literal 851 zcmV-Z1FZasP)<h;3K|Lk000e1NJLTq000&M000&U1^@s6#I$TX00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*f2 z6%++tSt>gK00PrVL_t(I%e|G)YZGZ0$3O2(s+Jke8e>(gZ7AI?E>RcRRq>z&^{C`x z{Tn<8-n=LkS=i&^#fujOLDYq1Zz8%o(_+yUw6qrm(b}|N)ea5KwAiHidPq8Hn?zR; zpUe9&&%EE~`}}<2dx(rtLz^1g>WQ`L_NUzP^}ydyB4AmT0JNt{&G&uv_4P?I3IdSI zHqY}^4RWodxEeFQZ~=OIVfbv6Pf3(YB>?W-tC#mC!3SWj#ukgTix(@(EN~eKy?l9_ zY_?~`1<&);+&ocnUI5l&%m>pLIFj{|*3oeVW9FEg%m9BAhAB30en3~(pHVUEfz~bF z$jAu3{~vR6?Evi9aff`q6DdX*rr5M;fLJU~vFI>3cmvP#v^?jvj58U?WZ0d{@$AhT zuFm#y>et&O5`)C!qXfYL-o8CbI(?q0sUu8JA7p;MmG18Dx{S@TE*0m1!@xG^|KUe= zx?2c>eT<LKGc^^%wkJua_tMgGAIBNPamK1Z22%qpA^Ks!hVk*0o^!cfG&TK9Yikeh z-g(T-JZ0m?M_5)d`e)s`a==TF#>lK>eAd9cpcBH=9b~gTxb6$yzhA?XCyTVTB}k`V zk<0DEbziW3`#;MVmrPBLC5ip};qnkOdwwC;a-8tBLs!@DSk?k?f<oarZEeR$BnC+) z`<a+HiSPeg?f}aI4mBv=<HrEZjE&*CF73%<K%QdJC7<sk9{-C(B2EzOW9!ztq*B)? zm72+BPoYLTMir^*DM@Q2q0!Mx%I7<D^Cl`391RTIQW&;NLQ5n5KbO!j@Eh<GzV9(T zeF(>SRSqu}vaqm)p`q(hLp55bmNsk<!^2Q4mUGP?5cI;;Gj*9P^{p{75U+sSs=M3; zl4VJ@T|O({s;RQ{@FDu5Wgh|AcKNg{DHba`OD30rf8nNIVq4?PwpX!6-{u8bTwFQ( dt48*7@)61>Y-l~L8U+9V002ovPDHLkV1fXaj|Bh# literal 0 HcmV?d00001 diff --git a/icons/rivendell-22x22.xpm b/icons/rivendell-22x22.xpm new file mode 100644 index 00000000..1a3139d5 --- /dev/null +++ b/icons/rivendell-22x22.xpm @@ -0,0 +1,119 @@ +/* XPM */ +const static char *rivendell_xpm[]={ +"22 22 94 2", +".a c None", +"Qt c None", +".K c #90b39e", +".N c #94943c", +".0 c #98982d", +".1 c #9d9d57", +".W c #a4a46d", +".3 c #a5a504", +".D c #a6a604", +".o c #a7a700", +".X c #a7a752", +".4 c #afaf00", +".2 c #b9b9ad", +".V c #bbbb69", +".j c #c0c0c0", +".g c #c1c1c1", +".h c #c2c2c2", +".S c #c2df25", +".Z c #c5c500", +"#o c #c6c6a9", +".t c #c9c9a4", +"## c #cfcf5a", +".z c #d1d1d1", +"#n c #d3d382", +".O c #d3d384", +".x c #d5d57d", +"#e c #d5d588", +".J c #d77878", +".9 c #d7d778", +".C c #d8d875", +".U c #d9d972", +"#k c #dddd69", +".s c #dddd6a", +".u c #dede60", +"#g c #dfdf60", +"#h c #dfdfdf", +"#d c #e07d7d", +"#. c #e3e354", +".v c #e4e451", +".L c #e7e748", +".F c #e8e843", +".E c #e9e940", +".T c #ebeb3c", +"#i c #ebebeb", +".i c #eded00", +"#c c #ef3030", +".w c #f4f420", +".8 c #f4f422", +".A c #f5f51f", +".M c #f9f912", +".B c #fbfb0b", +".y c #fbfb0c", +"#f c #fdfd06", +".c c #ff0000", +".# c #ff0101", +".e c #ff0202", +"#z c #ff0303", +"#A c #ff0404", +"#s c #ff0e0e", +"#B c #ff1414", +".f c #ff2f00", +"#b c #ff3636", +".G c #ff4f4f", +".6 c #ff6700", +".5 c #ff7001", +".P c #ff7700", +".m c #ff7f7f", +".7 c #ff8b00", +".I c #ff9090", +"#x c #ff9a9a", +".H c #ff9f9f", +".Q c #ffb600", +".Y c #ffc200", +".R c #ffcf00", +"#t c #ffcfcf", +"#w c #ffedd4", +"#u c #fffbfb", +".d c #ffff00", +".b c #ffff01", +"#a c #ffff02", +"#y c #ffff03", +".p c #ffff05", +"#m c #ffff06", +".k c #ffff07", +".l c #ffff0f", +"#l c #ffff20", +"#r c #ffff2d", +"#j c #ffff30", +"#q c #ffff55", +"#v c #ffff56", +".n c #ffff70", +"#p c #ffffcf", +".r c #fffff2", +".q c #ffffff", +"QtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQt.#.aQtQtQtQtQt.bQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQt.c.aQtQtQtQtQt.dQtQtQtQtQtQtQtQtQtQtQt", +"QtQtQt.c.aQtQtQtQtQt.dQtQtQtQtQtQtQtQtQtQtQt", +"QtQt.e.c.fQtQt.g.h.b.i.dQt.jQtQt.k.lQtQtQtQt", +"QtQt.m.m.n.bQt.j.j.b.o.dQt.jQt.p.d.pQtQtQtQt", +"QtQt.q.q.r.b.d.s.j.b.o.d.j.t.b.d.kQtQtQtQtQt", +"QtQt.q.q.q.b.d.d.u.v.o.w.x.y.d.dQtQtQtQtQtQt", +"QtQt.q.q.z.j.A.d.B.C.D.E.F.d.B.t.j.jQtQtQtQt", +"QtQt.G.H.I.J.K.L.M.L.N.O.d.F.x.jQtQtQtQtQtQt", +"QtQt.c.P.Q.R.S.T.U.V.W.X.O.E.w.d.d.dQtQtQtQt", +".a.d.Y.Z.o.o.o.o.0.1.2.W.N.3.o.o.o.4.d.d.bQt", +"QtQt.c.5.6.7.8.9#.##.1.V.L.C.v#a#a#aQtQtQtQt", +"Qt.q#b.##c#d#e.y#f#..0.U.M.B#g.j.j.hQtQtQtQt", +"Qt.q.q.q#h#i#j.d.y.9.o.T.L.d.d#k.j.gQtQtQtQt", +"Qt.q.q.a.q#l#m.d#n.8.o.B#o.A.d.dQtQtQtQtQtQt", +"Qt.q.q.a#p#q#r.j.j.b.o.d.j.j.b.d.bQtQtQtQtQt", +"#s#t#u.q#v#w#x.j.j.b.o.dQt.jQt.l.b#yQtQtQtQt", +".#.c.e#z.e.#.cQtQt#a.Z.bQtQtQtQtQtQtQtQtQtQt", +".e.##z.#.e#A.c#BQtQt.dQtQtQtQtQtQtQtQtQtQtQt", +".c.e.a.a.a.e#z.cQtQt.dQtQtQtQtQtQtQtQtQtQtQt", +".c.e.a.a.a.e.c.cQtQt.aQtQtQtQtQtQtQtQtQtQtQt"}; diff --git a/icons/rivendell-32x32.png b/icons/rivendell-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..bec0a5c40ce7bdb2d5ded1411cb51d890f2597a0 GIT binary patch literal 510 zcmV<a0RjGrP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*f2 z6%-cQ=WFEv00DkUL_t(o!|hjFlEfeg>`vug@n-AXjGT=9n8G*)jhdO=pP?$1heV*k zMuD$5qJVbkX`fz8mj4d+>i}E%r!(&5pRDUmAwYm$d5Or&*T<th-czWH7n)&lx5`za z!|13!Jvi>r+!2dX6&m9)mPcRyGn@i5KC|X;bAx75Mr4<WXpVrr=hwX=B)RW<f^{^H zrY|Du73NS4*d!hbF`_!wYj{0z0GYy2Kp6rNqY4B7ux+6_*}gw@LI|89qC`Rs-_3|f zKnRlVSI*VaNUw5Bg7L(Rnlo4O^W!^oLVy5URs3!QR<9S3pryn5ffdzZ<S=gEW@=!) zQaBr~i|N=uBaWaXpJVx{juKHhM>hf_sj5nn+qR|m*(NlMfd71szSWFI>3A8T*B(lq z-khA<u;pIW+i;W!cpH))6qeEnGI23*v$K+IPI+1TwX;BN%tPSzK_oX;K7Z<9vYs}h z872S8xuC}waZvNSW%W{#8~ij9ygG>V9#m%K7k9GKI~-K@761SM07*qoM6N<$f*&s3 A!~g&Q literal 0 HcmV?d00001 diff --git a/icons/rivendell-32x32.xpm b/icons/rivendell-32x32.xpm new file mode 100644 index 00000000..76e99034 --- /dev/null +++ b/icons/rivendell-32x32.xpm @@ -0,0 +1,42 @@ +/* XPM */ +static char *rivendell[]={ +"32 32 7 1", +". c None", +"e c #008080", +"c c #808000", +"b c #c0c0c0", +"# c #ff0000", +"a c #ffff00", +"d c #ffffff", +"................................", +"................................", +".....#.........a................", +".....#.........a................", +".....#.........a................", +".....#.........a................", +"....###.......aaa...............", +"....#.a....b..aca..b....a.......", +"....d.da...b..aca..b...a........", +"....d.d.aa..b.aca.b..aa.........", +"....ddd.aaa.b.aca.b.aaa.........", +"....ddd..aaaabacabaaaa..........", +"....d.bb..aaabacabaaa..bb.......", +"....d.d.bbaaaabcbaaaabb.........", +"...##.##.ebbaabcbaabb...........", +"...##aaaaaaabbcbcbbaaaaaaa......", +".aaaacccccccccbbbcccccccccaaaa..", +"...#.aaaaaaabbcbcbbaaaaaaa......", +"...##.##..bbaabcbaabb...........", +"...##.##bbaaaabcbaaaabb.........", +"..dd..bbdaaaabacabaaa..bb.......", +"..d.d.d.daaaabacabaaaa..........", +"..d..d..aaaab.aca.b.aaa.........", +"..d..d..aa..b.aca.b..aa.........", +"..d.d.dad..b..aca..b...a........", +"..dd..add..b..aca..b....a.......", +".##.....##....aca...............", +".#.##.##.#.....a................", +".#...#...#.....a................", +"#....#....#....a................", +"#..##.##..#....a................", +"###.....###....................."}; diff --git a/icons/rivendell-48x48.png b/icons/rivendell-48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..1ea11cb783f5f0780ca82a402bff511e0b7e8830 GIT binary patch literal 1024 zcmV+b1poVqP)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*f2 z6%-^AFgj%b00V$YL_t(&-tAdCR_ibjy%SP}f)qe&rG0zg#G9b^P6#_u{oW!X?;s6z zlonDz5!!i0EL)akTmA(&hdC!jtlxa@T#Y2)SAJzWVSpLnK4bU$gqiz|{T2pnxA@rx zFki-i*-wZ0uK`~z)P#ShBXz-lX)J}0ohAZL06+N?QYq#At~H>Pf4aIcMe-AmW&i<% z4S-G6vrP(V4Wwyz<@5LtHh?n{btasO8tr+zK(0d)|MhZw9LE&y*|V52zWt(WzH~6) zv9=||2w(dc$v$fjE!TQy$Zk6p6z83Jmq6~~%wVl0PA8FhIWCQPeT|{ihNDPgvCv-S z`%-PMjm)>05E9qd+S~v0Q{;W_?-j;UJ}3f2L<YM`DK>cbMPjHk%sN+BS9o}MpwS={ zMG;P?6OPBDlZa)gESEa~5?UvCf8PPvLF*)&LssTB&~m?rDj#fs5TX(dpDdR<ESEc^ zslvyH1hB*5kRXaAgpjq+a;bGNgcx8DmE!DM$TnuZj)NA|I>F(P3|73hm@5@=j{yAx z*>w;-pU0e;C-F||mJm?{2vO~~Sm->d`zCTTg#J|dnm5IN8y0D*EHB3pB7xSXJpoaX z3qCmYrPg`VrlJ&(K8N}ucJd~H5DAouv$^8V-gWg->OAjiC8-3V{XSu>C1Pidmlxpe zEo?Cx*T#TzG|Jw-x!GlG72uM%oqFd0N*0+MAavvTG)*i|#TJ}o9*qJ*VFm<4sGf;3 zL#)KMPiFNjq@cCLIjSmCI?h?h&X=Jq)VUV2mG*5;ZDKY%09NfZ@;(qMtCj3rPMFQk zMB{iY95XZ;U`t%Do1fig%4zf4?~|+#c)JB}Hr4O$&$q@X)u?Sq6h*kby`7|<cTaX9 z2cuR95fRy*wrioYSx*c+V{GXIp?OmoZK6O_DvZ2zXD6c@9U&xED_Prz8GO+L%_ui& zp5y7{2KWx)wjym1aNEbYv1?3X%A~-3vCX+BslF6wJE2b$W^FeSCLi)UMrVx>#&A9D zA49#MG;2!YDs(o3*`uy65f6$){u<NvA`{fd*~q3OgZd+7arHobo|*3Mfc5$UY*s0u zJ?{c;HEQ>7W2`CP2D}lll`?SY^0;wnne~AOIg$HP1ALzUNk+^YuT{`|B5ObVTrdJ& udL-&iw*ckm;7M7?rwDa;z3c<OG37rPUTOuB1Hiig0000<MNUMnLSTXxC&tqN literal 0 HcmV?d00001 diff --git a/icons/rivendell-48x48.xpm b/icons/rivendell-48x48.xpm new file mode 100644 index 00000000..adfff46a --- /dev/null +++ b/icons/rivendell-48x48.xpm @@ -0,0 +1,77 @@ +/* XPM */ +static char *rivendell[]={ +"48 48 26 1", +"d c None", +". c None", +"i c #808000", +"s c #a0a060", +"r c #afaf30", +"c c #bfbf00", +"u c #bfbf60", +"f c #c0c0c0", +"n c #c3c3c3", +"v c #d4d400", +"l c #d4d480", +"p c #d4d4d4", +"g c #dfdf00", +"a c #dfdf60", +"o c #dfdfdf", +"m c #e9e940", +"q c #efef30", +"# c #ff0000", +"x c #ff0101", +"t c #ff5500", +"e c #ff7f00", +"b c #ffff00", +"h c #ffff01", +"w c #ffff7f", +"k c #ffffaa", +"j c #ffffff", +"................................................", +"................................................", +"................................................", +".......##.............ab........................", +".......##.............cb........................", +".......##.............bb........................", +".......##.............bb........................", +".......##.............bb........................", +".......##.............bb........................", +"......####d..........bbbbd......................", +"......###ee.....fd...bgcbd..df......bh..........", +"......##.bbb....ff...bcibd..ff.....bbb.....d....", +"......jj.jbbb...ff...bcibd..ff....bbb...........", +"......jj.jkbbbb.dffd.bcibb.dfd.dbbbb............", +"......jj.jjbbbb...ff.bcibb.ff..bbbb.............", +"......jjjjj.bbbbb.ff.bcibb.ff.bbbbb.............", +"......jjjjj.dbbbbbalfbcibmfambbbbbd.............", +"......jjjjj..dbbbbbafbcibafbbbbbb...............", +"......jj.fff...bbbbafbcibafbbbbb..dffn..........", +"......jj.opffffbbbbqaariaaabbbbmfffffd..........", +"......jj.jj.fffbbbbbbfsifabbbbbaffd.............", +"....d###.##ddddfffbbbfsifabbafff................", +"....###tdeeeddbaaaaaassssuaaaaambbddddd.........", +"....###ebbbbbbbbbbfffisiisffabbbbbbbbbb.........", +".bbbbbbciiiiiiiiiiiiiiffisiiiiiiiiiiiiibbbbca...", +".acbbbbvccccccccccssssffssssrccccccccccbbbbbb...", +"....##.bbbbbbbbbbbfffissisffabbbbbbbbbb.........", +"....####.###...fffbbbfsifabbafff................", +"....####.###fffaaabbbfsifabbqaalffd.............", +"....####.###fffdbbbbbfsifabbbbbafff.............", +"...jjj...fffjddbbbbafbcibafbbbbb..fffd..........", +"...jjjjj.opfjdbbbbbafbcibafbbbbbb.dfff..........", +"...jj.jj.jj.jwbbbbbafbcibafbbbbbb...............", +"...jj..jj...bbbbbdff.bcibb.ff.bbbbd.............", +"...jj..jj...bbbbbdff.bcibb.ff.dbbbb.............", +"...jj..jj..bbbb...fd.bcibb.df..dbbb.............", +"...jj.jd.jwbbj..df...bcibb..fd....bb............", +"...jjjjd.dwwjj..ff...bcibd..ff....hbbd..........", +"...jjj...bwjjj..fd...bcibd..df......bb..........", +".d###.......##d......bcibd......................", +".d#####x.#####d......bvcbd......................", +".##.####.###.##.......bb........................", +".##....##....##.......bb........................", +"###....##....d##d.....bb........................", +"##.....##......##.....bb........................", +"##..####.###...##.....bc........................", +"#######x.########.....ha........................", +"#####.......#####..............................."}; diff --git a/icons/rivendell-64x64.png b/icons/rivendell-64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..ee8991d7d74f92b417c4ef44754097327c6c81a9 GIT binary patch literal 675 zcmV;U0$lxxP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*f2 z6%;b&<c~A}00JXPL_t(|+U;9Wvcez?Oy0bE$<5T8;mPtoY^sgs5hz8gn;Ac_md>!7 zWfLk90)apTLWo3&q}zN#BGPZZ*7*5$V6gyL04x9&01NQV!IAynxsh8Q=<WT?ZS#Qv zqZWXPn2DH#LVhskEIDWQm*?~K(|Ug|NBQ*(_>Cm3Ch4pSL?puU%G_1d*FGN%Xx=`i zmACn)-=~yVbNPN8(T-=o_nw1YU=#yHL`LRj$v40UyjlZFT5ubuMQ-cZ%l*S44RwrQ zKpbgasJc~aj|tt17K6NXiP2pK45+RKC-qkb*s(=IbJ&Z^B~J*Z3AtQ#-&(}MfT#w{ zeE{Z%WW2x5ip1%3)dpH3RYG<&;$T2j10Fg-joNOJw7GA`YnfB)6TpC|=l-vIQxg_x z%Z#;gJk~J;3@B-Uc7IzP9yDO@wZO~-_4;N%u;&A1XBcyW@Bw@22h`RA(XjLMs{X)$ z5(8}SPpiH;H?vjiL#VLSoK|FY8Xeo~kNzQ{A23t{y!u}ex7W80+iivhjM@b}CIrmn zBDWPW&ry0ONnW=ZCqwUQgqVr%KfUJL%>sO0E#P#8Z@Di|{X*@ja7ha+3-Erx)(j}C z{%c?KwkJ`oOaKFH-LHLr?>)fVN-xg`YzJwrQ;XgY4d|@_a}Utz{6xRsI(Oj%Hm?Sa z2G|^j75)?k^g`BZ!CsgG2DnbJau<LG>@;}oKSFx{qXY~X9DiA%GWr?2ehL5p002ov JPDHLkV1nRFDMSDO literal 0 HcmV?d00001 diff --git a/icons/rivendell-64x64.xpm b/icons/rivendell-64x64.xpm new file mode 100644 index 00000000..7bb1c4e7 --- /dev/null +++ b/icons/rivendell-64x64.xpm @@ -0,0 +1,74 @@ +/* XPM */ +static char *rivendell[]={ +"64 64 7 1", +". c None", +"e c #008080", +"c c #808000", +"b c #c0c0c0", +"# c #ff0000", +"a c #ffff00", +"d c #ffffff", +"................................................................", +"................................................................", +"................................................................", +"................................................................", +"..........##..................aa................................", +"..........##..................aa................................", +"..........##..................aa................................", +"..........##..................aa................................", +"..........##..................aa................................", +"..........##..................aa................................", +"..........##..................aa................................", +"..........##..................aa................................", +"........######..............aaaaaa..............................", +"........######..............aaaaaa..............................", +"........##..aa........bb....aaccaa....bb........aa..............", +"........##..aa........bb....aaccaa....bb........aa..............", +"........dd..ddaa......bb....aaccaa....bb......aa................", +"........dd..ddaa......bb....aaccaa....bb......aa................", +"........dd..dd..aaaa....bb..aaccaa..bb....aaaa..................", +"........dd..dd..aaaa....bb..aaccaa..bb....aaaa..................", +"........dddddd..aaaaaa..bb..aaccaa..bb..aaaaaa..................", +"........dddddd..aaaaaa..bb..aaccaa..bb..aaaaaa..................", +"........dddddd....aaaaaaaabbaaccaabbaaaaaaaa....................", +"........dddddd....aaaaaaaabbaaccaabbaaaaaaaa....................", +"........dd..bbbb....aaaaaabbaaccaabbaaaaaa....bbbb..............", +"........dd..bbbb....aaaaaabbaaccaabbaaaaaa....bbbb..............", +"........dd..dd..bbbbaaaaaaaabbccbbaaaaaaaabbbb..................", +"........dd..dd..bbbbaaaaaaaabbccbbaaaaaaaabbbb..................", +"......####..####..eebbbbaaaabbccbbaaaabbbb......................", +"......####..####..eebbbbaaaabbccbbaaaabbbb......................", +"......####aaaaaaaaaaaaaabbbbccbbccbbbbaaaaaaaaaaaaaa............", +"......####aaaaaaaaaaaaaabbbbccbbccbbbbaaaaaaaaaaaaaa............", +"..aaaaaaaaccccccccccccccccccbbbbbbccccccccccccccccccaaaaaaaa....", +"..aaaaaaaaccccccccccccccccccbbbbbbccccccccccccccccccaaaaaaaa....", +"......##..aaaaaaaaaaaaaabbbbccbbccbbbbaaaaaaaaaaaaaa............", +"......##..aaaaaaaaaaaaaabbbbccbbccbbbbaaaaaaaaaaaaaa............", +"......####..####....bbbbaaaabbccbbaaaabbbb......................", +"......####..####....bbbbaaaabbccbbaaaabbbb......................", +"......####..####bbbbaaaaaaaabbccbbaaaaaaaabbbb..................", +"......####..####bbbbaaaaaaaabbccbbaaaaaaaabbbb..................", +"....dddd....bbbbddaaaaaaaabbaaccaabbaaaaaa....bbbb..............", +"....dddd....bbbbddaaaaaaaabbaaccaabbaaaaaa....bbbb..............", +"....dd..dd..dd..ddaaaaaaaabbaaccaabbaaaaaaaa....................", +"....dd..dd..dd..ddaaaaaaaabbaaccaabbaaaaaaaa....................", +"....dd....dd....aaaaaaaabb..aaccaa..bb..aaaaaa..................", +"....dd....dd....aaaaaaaabb..aaccaa..bb..aaaaaa..................", +"....dd....dd....aaaa....bb..aaccaa..bb....aaaa..................", +"....dd....dd....aaaa....bb..aaccaa..bb....aaaa..................", +"....dd..dd..ddaadd....bb....aaccaa....bb......aa................", +"....dd..dd..ddaadd....bb....aaccaa....bb......aa................", +"....dddd....aadddd....bb....aaccaa....bb........aa..............", +"....dddd....aadddd....bb....aaccaa....bb........aa..............", +"..####..........####........aaccaa..............................", +"..####..........####........aaccaa..............................", +"..##..####..####..##..........aa................................", +"..##..####..####..##..........aa................................", +"..##......##......##..........aa................................", +"..##......##......##..........aa................................", +"##........##........##........aa................................", +"##........##........##........aa................................", +"##....####..####....##........aa................................", +"##....####..####....##........aa................................", +"######..........######..........................................", +"######..........######.........................................."}; diff --git a/icons/rivendell.ico b/icons/rivendell.ico new file mode 100644 index 0000000000000000000000000000000000000000..f04bf013a739cb78ea70aad744b887e343121765 GIT binary patch literal 766 zcmb7?F;Buk6vzJv0h$gv7*`nGbzm^jufXW;NZ<oF^b(dPEM19%iyxp#7m`b~AAnIO z663(Yz;GlmVSN7Yu97y<!PoxZ_4nSr*Sl+h8n15m1lCqZz!}GLs!QEaH8kh}#oX_v zm}EvNKhX1$Qpoe132`?>>=VVyhUlgVoEUbN1j!T$!UH2fnFBH-hkU^K6}J6=Ed6O9 zcrk5q8*njW_67SM<`^0(OI7GgENjcUU>4|EHq+X76vUp>wz3hvKh}CY(KCmZ5t9o< z5NfUCUT?yI(?gwI(BiT6HWEBk^0vNNu7@#|{xC7zdW!c$OjuqYS*NA-v%a!Fm_7V? z6la*E1^e^yU!&N(+n{xa^X7v8$#(kR*6E1cy^Gva`dQ?Odc2BcJ{U!>gP|-gZ)MTw z%Ny!4M>ATYCd<4fE8toI^$(6q)sh|K+q@ZVR9!Zwec7>YyB^AJJ&HD;k?g;uBK~{M Fz5z49<{1D0 literal 0 HcmV?d00001 diff --git a/icons/rivendell.res b/icons/rivendell.res new file mode 100644 index 0000000000000000000000000000000000000000..c9f9d447bc316a4358152ae83f3d869188414388 GIT binary patch literal 868 zcmb7Dze~eF6#inRZ3t+G?#<{bIyeZrI(Br{v9y1HLk_wGT(TAi7yp1jm%@SO4{+3} zAPyZmbhtu0ReXMzOG^Se_{ewfzV|EdUUC2s5+V-VR%E`n_175V<-S(S-`@ruaT5}k zga>C<%=ujuzz0e>#g$t^A<Hs4Y!g<AQ(RqNf>DAT^yZTI$p{I89fyxH_sMD5`F+M$ zxUC0_(`^C4i)oTKf!t=yrr@rIIfRB9rz&tMmTSv(!I_{Z<B8U;q9ArWZ7OTw`(v$# z_j;03%Mp_o6n>z!j?d2SsTdyU@d+g!+SOY8hl=0k*UR}Zrcxg!M&3{HeuxRm{gLam z)Iakp=Y!e6&7+uMk`~;}$9;|B@c9AlvYR&>{wKHLe@mw$a{D22N9bpfC*tuulGolK zdh7LNdU`F>{jR*DCa<VRGk7w~8Zrki6j1x5o~eecX<udaXsK$lY<FeNyw##F>%|~i qenqnRmI|bhHe0j*y2t^paDxH*I3~AJz7O^mcnHH*ejDuV@$ds=(({V| literal 0 HcmV?d00001 diff --git a/icons/rml.xpm b/icons/rml.xpm new file mode 100644 index 00000000..da0834bc --- /dev/null +++ b/icons/rml.xpm @@ -0,0 +1,23 @@ +/* XPM */ +const static char *rml_xpm[]={ +"16 16 4 1", +"b c #0000c0", +"a c #0080ff", +"# c #a8dcff", +". c #ffffff", +"......#abbbbbbbb", +".bbba...#abbbbbb", +".b..b.....#abbbb", +".b..b.......#abb", +".bbba.b...#...#a", +".bba..bb.bb.....", +".b.ba.babab.....", +".b..b.b.b.b.b...", +"....a.b...b.b...", +"......b...b.b...", +"#.....a...b.b...", +"ba#.......a.b...", +"bbba#.......b...", +"bbbbba#.....bbba", +"bbbbbbba#.......", +"bbbbbbbbba#....."}; diff --git a/icons/rml2.xpm b/icons/rml2.xpm new file mode 100644 index 00000000..9597e7be --- /dev/null +++ b/icons/rml2.xpm @@ -0,0 +1,23 @@ +/* XPM */ +const static char *rml2_xpm[]={ +"16 16 4 1", +". c None", +"# c #000000", +"b c #0000c0", +"a c #ffff00", +".....#####......", +"...##aaaaa##....", +"..#aaaaaaaaa#...", +".#aabaaaaabaa#..", +".#aabbaaabbaa#..", +"#aaabbbabbbaaa#.", +"#aaabbbbbbbaaa#.", +"#aaabbababbaaa#.", +"#aaabbaaabbaaa#.", +"#aaabbaaabbaaa#.", +".#aabbaaabbaa#..", +".#aabbaaabbaa#..", +"..#aaaaaaaaa#...", +"...##aaaaa##....", +".....#####......", +"................"}; diff --git a/icons/rml3.xpm b/icons/rml3.xpm new file mode 100644 index 00000000..d706fbe5 --- /dev/null +++ b/icons/rml3.xpm @@ -0,0 +1,23 @@ +/* XPM */ +const static char *rml3_xpm[]={ +"16 16 4 1", +"b c #0000c0", +"a c #0080ff", +"# c #a8dcff", +". c #ffff00", +"......#abbbbbbbb", +".bbba...#abbbbbb", +".b..b.....#abbbb", +".b..b.......#abb", +".bbba.b...#...#a", +".bba..bb.bb.....", +".b.ba.babab.....", +".b..b.b.b.b.b...", +"....a.b...b.b...", +"......b...b.b...", +"#.....a...b.b...", +"ba#.......a.b...", +"bbba#.......b...", +"bbbbba#.....bbba", +"bbbbbbba#.......", +"bbbbbbbbba#....."}; diff --git a/icons/rml5.xpm b/icons/rml5.xpm new file mode 100755 index 00000000..efaf3f83 --- /dev/null +++ b/icons/rml5.xpm @@ -0,0 +1,175 @@ +/* XPM */ +static const char *rml5_xpm[]={ +"16 16 156 2", +"Qt c None", +".f c None", +"#z c #000001", +".1 c #000007", +".T c #04040f", +"#J c #070714", +"#q c #0a0a1d", +"#c c #0c0c1e", +"#0 c #111125", +"ax c #16162e", +".8 c #1a1a36", +".U c #202045", +"at c #262636", +"am c #28285b", +".H c #28285d", +".0 c #29295a", +"as c #2a2a5d", +"#e c #2e2e4d", +".w c #2e2e62", +".n c #2f2f68", +"an c #313160", +"ar c #333364", +"#Q c #353570", +"ap c #363672", +"#K c #373758", +".2 c #38385a", +".m c #39396b", +"aw c #393975", +".v c #3a3a76", +".x c #3f3f84", +"ab c #40406e", +"az c #41417d", +".o c #414184", +"#w c #42427d", +"aq c #454576", +"#y c #454582", +".Z c #464681", +"#b c #474785", +".# c #4a4a8c", +".V c #4b4b8a", +".a c #50508b", +"#k c #52528e", +"ay c #52528f", +".I c #555591", +".9 c #555596", +"#l c #555597", +"#p c #565692", +"#I c #57578f", +".g c #595995", +"ac c #5b5b7f", +"#F c #5b5b99", +".h c #5d5d9b", +".l c #5e5e81", +".p c #63639a", +"al c #6666a5", +".M c #6868a4", +".i c #6969a6", +".e c #6a6a91", +"#m c #6a6aa3", +".G c #6c6c99", +"av c #7070a9", +"#v c #7171aa", +"#G c #7171ac", +".d c #7272a6", +"#. c #7272a7", +".S c #7676a1", +"#T c #7878a2", +".Y c #7878b1", +"#P c #7c7cb1", +".q c #7e7eb1", +".j c #7e7eb3", +".b c #8181b6", +"#Z c #8383b2", +"#a c #8383b8", +"#r c #8787af", +".r c #8787b9", +".L c #8989bb", +"#L c #8a8ab1", +"#E c #8a8abb", +".N c #8b8bb6", +"#u c #8b8bbb", +".s c #8c8cbc", +"#A c #8e8eb9", +"#x c #8e8ebc", +"#n c #9191be", +".C c #9595c2", +"ak c #9797c7", +".c c #9898c5", +"aa c #9898c7", +".k c #9898c8", +"au c #9999c4", +".D c #9a9ac6", +".y c #9e9ec5", +"#R c #9f9fc9", +"#H c #a0a0ca", +"#1 c #a1a1cf", +"#S c #a6a6cb", +".E c #a6a6cd", +".W c #a8a8cc", +".7 c #a8a8d3", +".B c #a9a9cf", +".F c #aaaad2", +"#j c #ababd1", +"aj c #ababd3", +".u c #acacd7", +".P c #adadd1", +".3 c #adadd7", +".O c #aeaed2", +"ad c #aeaed9", +".t c #afafd2", +"a# c #b1b1d4", +"ai c #b2b2d4", +"#f c #b2b2dc", +"#t c #b4b4d6", +"#3 c #b5b5d6", +"#o c #b5b5d7", +"ae c #b5b5d8", +"#2 c #b7b7d8", +".J c #b8b8d5", +".X c #bbbbda", +"#U c #bbbbe1", +"#4 c #bcbcda", +".4 c #bcbcdb", +".Q c #bdbddb", +".K c #bebedb", +".A c #c0c0dc", +"#i c #c3c3de", +".z c #c4c4df", +".5 c #c5c5df", +"## c #c6c6e0", +"#5 c #c8c8e5", +"#s c #cacae5", +"#g c #cccce4", +"#D c #cdcde4", +"af c #cfcfe8", +"#h c #d1d1e7", +"#V c #d1d1e9", +"#8 c #d2d2e7", +"#B c #d2d2ec", +"#d c #d3d3e7", +"#M c #d3d3ed", +"ag c #d4d4e8", +"#6 c #d5d5e9", +"#7 c #d7d7ea", +".R c #d7d7f0", +"ah c #d8d8ea", +"#C c #dadaeb", +".6 c #ddddee", +"#W c #dedeee", +"#N c #e6e6f2", +"#O c #e7e7f3", +"a. c #eeeef7", +"ao c #eeeefb", +"#9 c #efeff7", +"#Y c #f3f3fa", +"#X c #f6f6fb", +"QtQtQtQtQtQt.#.a.b.c.d.e.bQtQtQt", +"Qt.fQtQtQt.#.#.g.h.i.j.k.l.lQtQt", +"QtQt.k.m.n.o.p.d.q.r.s.t.u.vQtQt", +"QtQt.w.x.a.y.z.A.B.C.D.E.F.G.vQt", +"QtQt.H.I.J.K.L.M.a.N.O.P.Q.R.S.T", +"Qt.U.V.W.X.Y.Z.0.1.2.3.4.5.6.7.8", +".b.9#.###a#b#c#dQt#e#f#g#h#i#j#k", +"#l#m#n#o#p#q#dQt#d#r#s#h#t#u#v#w", +".b#v#x.E#y#z.f#d#A#B#C#D#E#F.v.v", +"Qt#G.c#H#I#J#K#L#M#d#N#O#P#Q.vQt", +".F.b#R.B#S#T#U#V#W#N#X#Y#Z#0QtQt", +".B#1#2#3#4#5#6#7#8#9a.a#aaabQtQt", +"Qtacadaeafagahai#u.sajakalamQtQt", +"QtQtan#I#Iao#i#E#FapaqarasQtQtQt", +"QtQtQtQtatau.FavawQtQtQtQtQtQtQt", +"QtQtQtQtQtaxayazQtQtQtQtQtQtQtQt"}; diff --git a/icons/split.xpm b/icons/split.xpm new file mode 100644 index 00000000..ccb43528 --- /dev/null +++ b/icons/split.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static const char * split_xpm[] = { +"16 16 7 1", +" c None", +". c #000000", +"+ c #35335F", +"@ c #808080", +"# c #1207F6", +"$ c #C0C0C0", +"% c #FFFFFF", +" .. ", +" +@.@ ", +" +#.$$ ", +" +#@@$%@ @ ", +" +#%.$%%@ @ ", +" ++#%#.$%%@ @ ", +"+%$%#%..%%@ ", +"+#$#%#.$.%@ ", +"+#$%#%.@.%@ @@@@", +".+@#%#..%%@ ", +" ..+#%.$%%@ ", +" .+#.$%%@ @ ", +" .+@@%%@ @ ", +" .+.$$@ @ ", +" .+.@ ", +" .. "}; diff --git a/icons/switch.xpm b/icons/switch.xpm new file mode 100644 index 00000000..be76744c --- /dev/null +++ b/icons/switch.xpm @@ -0,0 +1,24 @@ +/* XPM */ +const static char *switch_xpm[]={ +"16 16 5 1", +". c None", +"# c #000000", +"c c #800000", +"b c #a0a0a0", +"a c #c0ffc0", +"..############..", +"..#aaaaaaaaaa#..", +"..#aa##a#baaa#..", +"..#aa##a##aaa#..", +"..#aa##ab#aaa#..", +"..#aaaaaaaaaa#..", +"..#aaaa#ccaaa#..", +"..#aaaa#ccaaa#..", +"..#aaaa#caaaa#..", +"..#aaaa##aaaa#..", +"..#aaaaaaaaaa#..", +"..#a##a##a##a#..", +"..#a##a#ba#ba#..", +"..#a##a#aa#aa#..", +"..#aaaaaaaaaa#..", +"..############.."}; diff --git a/icons/switch2.xpm b/icons/switch2.xpm new file mode 100644 index 00000000..3dda4ae2 --- /dev/null +++ b/icons/switch2.xpm @@ -0,0 +1,29 @@ +/* XPM */ +const static char *switch2_xpm[]={ +"16 16 10 1", +"# c None", +". c None", +"b c #000000", +"a c #800000", +"e c #808080", +"f c #a0a0a0", +"c c #c00000", +"g c #c3c3c3", +"d c #ffff00", +"h c #ffffc0", +"...........#aaaa", +"...bbbbbbbacadda", +"...befghhahdadha", +"...befghahddaaaa", +"...befgahddadda.", +"...befgaddadha..", +"...befgadadhab..", +"...befgacdhaeb..", +"...befgcaaafeb..", +"...befgccccfeb..", +"...befghhhgfeb..", +"...befghhhgfeb..", +"...befghhhgfeb..", +"...befghhhgfeb..", +"...beffggggeeb..", +"...bbbbbbbbbbb.."}; diff --git a/icons/switch3.xpm b/icons/switch3.xpm new file mode 100644 index 00000000..86058b49 --- /dev/null +++ b/icons/switch3.xpm @@ -0,0 +1,100 @@ +/* XPM */ +static const char *switch3_xpm[]={ +"16 16 81 2", +".# c None", +"Qt c None", +".a c #000000", +".c c #010101", +".i c #020202", +".q c #040404", +"#j c #061528", +"#m c #07172d", +".8 c #072136", +"#o c #080c15", +"#k c #092843", +"#e c #092a46", +".V c #0a2f4f", +"#d c #0a3052", +".N c #0b3a5a", +".K c #0c2e51", +"#h c #0c3559", +"#i c #0e3758", +".M c #0e3f61", +".R c #0e4870", +".O c #0e74a6", +".G c #0f4f74", +"#n c #10365c", +".Q c #105074", +"#l c #105686", +".4 c #108ac1", +".L c #114366", +"## c #118dc7", +".w c #1191c9", +".E c #1198ca", +".A c #133354", +".b c #133755", +".9 c #168aba", +"#c c #1695c4", +".S c #1a5a84", +".W c #1c1c1c", +"#g c #1c95be", +"#. c #1ca8d6", +".C c #1f99c2", +".D c #229ec7", +"#a c #239ec9", +"#f c #2495bf", +".7 c #26445e", +".H c #292929", +".1 c #294a6b", +".v c #2a97c8", +"#b c #2aa0c6", +".I c #2b333e", +".P c #30b6da", +".r c #314d6b", +".z c #343434", +".2 c #38577a", +".T c #3b3a3b", +".F c #40b7da", +".0 c #425061", +".5 c #42a4d0", +".j c #4c637b", +".g c #4c7497", +".X c #4d9dc5", +".y c #50748c", +".h c #51758d", +".p c #59798e", +".u c #60b6da", +".k c #6a86a0", +".6 c #70afd2", +".f c #767676", +".3 c #77c4e0", +".J c #818181", +".n c #82a6c1", +".l c #8494a7", +".t c #89c7e1", +".Z c #8a959f", +".U c #979797", +".d c #a1a1a1", +".Y c #a5aeb8", +".s c #aecee2", +".B c #afd2e8", +".e c #b4b4b4", +".m c #b4bcc9", +".o c #b6d8e9", +".x c #badcec", +"QtQtQtQtQtQt.#.#.#.#.aQtQt.#.#Qt", +"QtQtQtQtQtQt.#.#.#Qt.b.cQtQtQt.#", +"QtQtQtQtQtQt.d.e.f.a.g.h.iQtQtQt", +"QtQtQtQtQtQt.j.k.l.m.n.o.p.qQtQt", +"QtQtQtQtQtQt.r.s.t.u.v.w.x.y.cQt", +"QtQt.#.#Qt.z.A.B.C.D.E.w.F.G.HQt", +"QtQtQtQt.I.J.K.L.M.N.O.P.Q.HQt.#", +".#QtQt.q.k.R.#.#Qt.#.S.G.T.#QtQt", +".#Qt.z.I.G.R.T.J.U.#.V.W.#.#QtQt", +".#.q.y.s.X.w.Y.Z.0Qt.1.#.#.#.#.#", +".H.2.s.3.4.5.u.6.7.#.#.#.#.#.#.#", +"Qt.8.9#.###a#b#c#d.#.#.#.#.#QtQt", +".#Qt#e#f#g.R#h#i#j.#.#.#.#.#QtQt", +"QtQtQt#k#l.R.#.#.#.#.#.#.#.#.#Qt", +"QtQtQt.##m#n.#.#.#QtQtQtQtQtQtQt", +"QtQtQtQtQt#oQtQt.#QtQtQtQtQtQtQt"}; diff --git a/icons/track.xpm b/icons/track.xpm new file mode 100644 index 00000000..5d1716fc --- /dev/null +++ b/icons/track.xpm @@ -0,0 +1,23 @@ +/* XPM */ +const static char * track_xpm[] = { +"16 16 4 1", +" c None", +". c #000000", +"+ c #2CD928", +"@ c #D94128", +" ..... ", +" ..+++++.. ", +" .+++++++++. ", +" .+@@@@@@@@@+. ", +" .+@@@@@@@@@+. ", +".+++++@@@+++++. ", +".+++++@@@+++++. ", +".+++++@@@+++++. ", +".+++++@@@+++++. ", +".+++++@@@+++++. ", +" .++++@@@++++. ", +" .++++@@@++++. ", +" .+++++++++. ", +" ..+++++.. ", +" ..... ", +" "}; diff --git a/icons/track_cart.xpm b/icons/track_cart.xpm new file mode 100644 index 00000000..584a9b30 --- /dev/null +++ b/icons/track_cart.xpm @@ -0,0 +1,26 @@ +/* XPM */ +const static char * track_cart_xpm[] = { +"16 16 7 1", +" c None", +". c #000000", +"+ c #808000", +"@ c #808080", +"# c #D94128", +"$ c #C0C0C0", +"% c #FFFFFF", +" .. ", +" +@.@ ", +" +#.$$ ", +" +#@@$%@ @ ", +" +##.$%%@ @ ", +" ++###.$%%@ @ ", +"+#$###..%%@ ", +"+#$###.$.%@ ", +"+#$###.@.%@ @@@@", +".+@###..%%@ ", +" ..+##.$%%@ ", +" .+#.$%%@ @ ", +" .+@@%%@ @ ", +" .+.$$@ @ ", +" .+.@ ", +" .. "}; diff --git a/icons/traffic.xpm b/icons/traffic.xpm new file mode 100644 index 00000000..8f2fc8bb --- /dev/null +++ b/icons/traffic.xpm @@ -0,0 +1,167 @@ +/* XPM */ +static const char * traffic_xpm[] = { +"16 16 148 2", +" c None", +". c #A42729", +"+ c #A22628", +"@ c #9D2526", +"# c #902223", +"$ c #7E1D1F", +"% c #681819", +"& c #AC292A", +"* c #B92B2D", +"= c #BC2D2F", +"- c #BA2B2D", +"; c #B5292B", +"> c #AB2628", +", c #9B2325", +"' c #861E1F", +") c #661617", +"! c #AF2A2C", +"~ c #C12D2F", +"{ c #CE6B6D", +"] c #C12E2F", +"^ c #C02D2E", +"/ c #BC2B2C", +"( c #B32729", +"_ c #A52426", +": c #9D3638", +"< c #73282C", +"[ c #571213", +"} c #BE2D2F", +"| c #D97476", +"1 c #C3C375", +"2 c #85856F", +"3 c #511010", +"4 c #3D0B0C", +"5 c #AD292A", +"6 c #C32E30", +"7 c #B44F57", +"8 c #BFBF7B", +"9 c #C2C273", +"0 c #B5B565", +"a c #F3F332", +"b c #DFDF50", +"c c #C2C27E", +"d c #9C9C7B", +"e c #300909", +"f c #3F0B0B", +"g c #B1292B", +"h c #C22E2F", +"i c #B73335", +"j c #6D4851", +"k c #654951", +"l c #4E496C", +"m c #F7F735", +"n c #BABA68", +"o c #55525F", +"p c #4B424C", +"q c #3B3035", +"r c #2A0708", +"s c #400B0B", +"t c #330809", +"u c #AD282A", +"v c #BF2C2E", +"w c #C22C2E", +"x c #A12426", +"y c #751A1B", +"z c #614762", +"A c #F5F54D", +"B c #B6B662", +"C c #332830", +"D c #34090A", +"E c #440D0D", +"F c #470C0D", +"G c #470B0C", +"H c #3A0A0A", +"I c #A32628", +"J c #B72A2C", +"K c #C02B2D", +"L c #BC292B", +"M c #B12628", +"N c #7E536D", +"O c #F4F44C", +"P c #B5B55D", +"Q c #34232B", +"R c #500F10", +"S c #6D1415", +"T c #611011", +"U c #4E0C0D", +"V c #3B0A0A", +"W c #932224", +"X c #AA2728", +"Y c #B6282A", +"Z c #BA292B", +"` c #B82729", +" . c #82556F", +".. c #F4F44A", +"+. c #B5B55C", +"@. c #36252C", +"#. c #520F10", +"$. c #6E1314", +"%. c #5E0F0F", +"&. c #330808", +"*. c #982224", +"=. c #A62526", +"-. c #AB2527", +";. c #AB2425", +">. c #A0768C", +",. c #F3F368", +"'. c #BDBD78", +"). c #392A32", +"!. c #470D0D", +"~. c #601011", +"{. c #540C0D", +"]. c #4D0C0D", +"^. c #1D0505", +"/. c #7D1C1D", +"(. c #911F20", +"_. c #992022", +":. c #991F21", +"<. c #80807E", +"[. c #C5C576", +"}. c #B3B370", +"|. c #433C44", +"1. c #3A090A", +"2. c #4F0C0D", +"3. c #3F090A", +"4. c #551314", +"5. c #721819", +"6. c #7F1A1B", +"7. c #80191A", +"8. c #662327", +"9. c #4A2C34", +"0. c #33242B", +"a. c #210E0E", +"b. c #300708", +"c. c #480B0C", +"d. c #100303", +"e. c #3C0D0D", +"f. c #571112", +"g. c #611313", +"h. c #5A1011", +"i. c #430B0C", +"j. c #310708", +"k. c #3D0909", +"l. c #3E0A0A", +"m. c #120303", +"n. c #3B0A0B", +"o. c #3D0B0B", +"p. c #350909", +"q. c #230606", +" ", +" . + @ # $ % ", +" & * = - ; > , ' ) ", +" ! ~ { ] ^ / ( _ : < [ ", +" } | 1 1 1 1 1 1 1 2 3 4 ", +" 5 6 7 8 9 0 a b c 1 d e f ", +" g h i j k l m n o p q r s t ", +" u v w x y z A B C D E F G H ", +" I J K L M N O P Q R S T U V ", +" W X Y Z ` ...+.@.#.$.%.U &. ", +" $ *.=.-.;.>.,.'.).!.~.{.].^. ", +" /.(._.:.<.[.}.|.1.2.2.3. ", +" 4.5.6.7.8.9.0.a.b.c.c.d. ", +" e.f.g.h.i.&.j.k.l.m. ", +" e n.f o.p.q. ", +" "}; diff --git a/icons/trashcan-16x16.xpm b/icons/trashcan-16x16.xpm new file mode 100644 index 00000000..fca86721 --- /dev/null +++ b/icons/trashcan-16x16.xpm @@ -0,0 +1,72 @@ +/* XPM */ +static const char * trashcan_xpm[] = { +"16 16 53 1", +" c None", +". c #204A87", +"+ c #81A7D7", +"@ c #82A7D7", +"# c #98B6DD", +"$ c #22426A", +"% c #244670", +"& c #264A76", +"* c #2B5487", +"= c #2D588D", +"- c #32619C", +"; c #3466A4", +"> c #366AAA", +", c #386FB2", +"' c #22436C", +") c #294F7F", +"! c #305E96", +"~ c #376BAB", +"{ c #284E7E", +"] c #2B5589", +"^ c #305F98", +"/ c #3567A5", +"( c #8DAFDA", +"_ c #5981B2", +": c #79A2D4", +"< c #376CAD", +"[ c #3465A2", +"} c #3364A1", +"| c #33639F", +"1 c #496F9F", +"2 c #4D84C7", +"3 c #4980C5", +"4 c #467EC4", +"5 c #376DAF", +"6 c #567BA9", +"7 c #3D77BF", +"8 c #3D78C1", +"9 c #3970B3", +"0 c #7CA3D5", +"a c #5488C8", +"b c #477FC5", +"c c #3E79C2", +"d c #5B86BA", +"e c #5287C8", +"f c #3C76BE", +"g c #4E7DB7", +"h c #78A1D3", +"i c #799ECC", +"j c #779AC6", +"k c #779BC7", +"l c #7197C4", +"m c #6A90BF", +"n c #577CAC", +" ", +" ", +" ........... ", +" ..+@@@@@@@@.. ", +" .#$%&*=-;>,@. ", +" .#''%)*!-;~@. ", +" .#{'%)]^-/~@. ", +" .,(((((((((_. ", +" .:<~/[}}[|}1. ", +" .:2345555556. ", +" .:2347887956. ", +" .0a3b7cc7c7d. ", +" .:eb4f88f8fd. ", +" .ghiijkkjlmn. ", +" ............. ", +" "}; diff --git a/icons/trashcan-32x32.xpm b/icons/trashcan-32x32.xpm new file mode 100644 index 00000000..e8e3e4e4 --- /dev/null +++ b/icons/trashcan-32x32.xpm @@ -0,0 +1,281 @@ +/* XPM */ +static const char * trashcan_xpm[] = { +"32 32 246 2", +" c None", +". c #5A5B5B", +"+ c #595959", +"@ c #565656", +"# c #555555", +"$ c #5D5E5E", +"% c #626262", +"& c #7F92AA", +"* c #758FB1", +"= c #748EB1", +"- c #738EB1", +"; c #738DB0", +"> c #738CB0", +", c #728CB0", +"' c #718BB0", +") c #708BAF", +"! c #6F8AAF", +"~ c #6E8AAF", +"{ c #6D89AE", +"] c #6E89AF", +"^ c #6D88AE", +"/ c #6C87AD", +"( c #6E8CB3", +"_ c #93A1B0", +": c #5C5D5D", +"< c #A1A4A5", +"[ c #1C3864", +"} c #204A87", +"| c #346099", +"1 c #6C95C3", +"2 c #6E6E6F", +"3 c #8898AD", +"4 c #14305A", +"5 c #37629B", +"6 c #719ECE", +"7 c #9EAAB7", +"8 c #5E5E5E", +"9 c #777878", +"0 c #3E587C", +"a c #142F58", +"b c #3A659E", +"c c #729FCF", +"d c #759AC4", +"e c #606060", +"f c #B4B7B8", +"g c #163159", +"h c #142E56", +"i c #3D68A0", +"j c #6E9ACB", +"k c #9EA4A9", +"l c #5D5D5D", +"m c #575757", +"n c #B3BEC9", +"o c #132C53", +"p c #132D54", +"q c #3F6BA2", +"r c #709ECE", +"s c #9AB2CD", +"t c #ECF0F1", +"u c #EFF3F4", +"v c #EEF2F3", +"w c #EEF1F2", +"x c #EDF1F2", +"y c #5F5F5F", +"z c #A9ABAC", +"A c #C1C4C5", +"B c #C0C3C4", +"C c #BFC2C3", +"D c #BEC1C2", +"E c #BDC0C1", +"F c #BCBFC0", +"G c #BBBEBF", +"H c #BABDBE", +"I c #B5B8B9", +"J c #5A5A5A", +"K c #53565B", +"L c #545454", +"M c #585858", +"N c #214D8B", +"O c #769CCD", +"P c #457CC2", +"Q c #3E76BE", +"R c #3D74BB", +"S c #3D73BA", +"T c #3C72B6", +"U c #3B70B4", +"V c #3A6EB1", +"W c #396DB0", +"X c #386CAD", +"Y c #376AAB", +"Z c #3768A8", +"` c #3567A7", +" . c #3565A3", +".. c #33639F", +"+. c #32609B", +"@. c #305E98", +"#. c #305D96", +"$. c #2F5C95", +"%. c #2F5B95", +"&. c #2E5B93", +"*. c #2E5A92", +"=. c #2D5A91", +"-. c #2D5990", +";. c #3E6496", +">. c #5576A0", +",. c #214C89", +"'. c #234D8B", +"). c #7096C9", +"!. c #497FC3", +"~. c #3F77BF", +"{. c #3E75BD", +"]. c #3E75BB", +"^. c #3D74BA", +"/. c #3D73B9", +"(. c #3C72B8", +"_. c #3C72B7", +":. c #3B71B6", +"<. c #3B70B5", +"[. c #3A6FB4", +"}. c #3A6FB2", +"|. c #396EB1", +"1. c #386CAF", +"2. c #376BAC", +"3. c #3669AA", +"4. c #3364A3", +"5. c #33629F", +"6. c #31619C", +"7. c #305E99", +"8. c #456DA0", +"9. c #5476A3", +"0. c #234E8D", +"a. c #6A91C4", +"b. c #4E82C4", +"c. c #386CAE", +"d. c #376BAD", +"e. c #376AAC", +"f. c #3668A9", +"g. c #3568A8", +"h. c #507AB1", +"i. c #5377AA", +"j. c #1F4C89", +"k. c #224D8A", +"l. c #658CBF", +"m. c #5285C6", +"n. c #567FB4", +"o. c #4E73A7", +"p. c #204986", +"q. c #224B8A", +"r. c #5E85BA", +"s. c #5788C7", +"t. c #5B82B6", +"u. c #486FA2", +"v. c #577EB4", +"w. c #5B8CC9", +"x. c #5F86B8", +"y. c #41689E", +"z. c #5079AF", +"A. c #5F8ECA", +"B. c #648ABA", +"C. c #3B6299", +"D. c #4B72A9", +"E. c #6391CC", +"F. c #698DBD", +"G. c #345A94", +"H. c #426AA2", +"I. c #6694CD", +"J. c #6E91BF", +"K. c #2D568F", +"L. c #3A639B", +"M. c #6895CD", +"N. c #7294C1", +"O. c #274F8B", +"P. c #335B94", +"Q. c #6995CD", +"R. c #7495C1", +"S. c #204988", +"T. c #2B548E", +"U. c #6996CE", +"V. c #3869A8", +"W. c #6D90BD", +"X. c #204B87", +"Y. c #264E8A", +"Z. c #6996CD", +"`. c #3C6CAA", +" + c #6488B8", +".+ c #204C89", +"++ c #224C89", +"@+ c #6793CA", +"#+ c #406FAB", +"$+ c #5B80B2", +"%+ c #214C88", +"&+ c #214C8A", +"*+ c #608DC5", +"=+ c #4279C0", +"-+ c #4371AD", +";+ c #5278AD", +">+ c #214A86", +",+ c #204A86", +"'+ c #4E7CB7", +")+ c #4E81C4", +"!+ c #3F77BE", +"~+ c #3F76BD", +"{+ c #3F76BB", +"]+ c #3E75BA", +"^+ c #3E74B9", +"/+ c #3D73B8", +"(+ c #3D73B7", +"_+ c #3C71B5", +":+ c #3B70B2", +"<+ c #3A6FB1", +"[+ c #3A6EB0", +"}+ c #396DAF", +"|+ c #396DAE", +"1+ c #386BAC", +"2+ c #376AAA", +"3+ c #3769A9", +"4+ c #396BAA", +"5+ c #537DB4", +"6+ c #446BA3", +"7+ c #1D427B", +"8+ c #2E5893", +"9+ c #5382BF", +"0+ c #5C8AC7", +"a+ c #5C8AC6", +"b+ c #5D8AC4", +"c+ c #5C89C3", +"d+ c #5C88C3", +"e+ c #5C88C2", +"f+ c #5C88C1", +"g+ c #5C87C0", +"h+ c #5C88BF", +"i+ c #5C88BE", +"j+ c #5C87BD", +"k+ c #5C87BC", +"l+ c #5C86BD", +"m+ c #5C86BC", +"n+ c #5C86BB", +"o+ c #5C85BB", +"p+ c #5C85B9", +"q+ c #5C84B9", +"r+ c #5B84B7", +"s+ c #4972A9", +"t+ c #26518B", +"u+ c #1C4278", +"v+ c #1F4680", +"w+ c #16335D", +" ", +" ", +" . + @ @ @ @ @ @ @ @ @ @ @ # # # # # # # # # # # $ ", +" % & * = = = - - ; > , , ' ) ! ! ~ { ] ] { ^ / ( _ : ", +" : < [ } } } } } } } } } } } } } } } } } } } } } | 1 2 ", +" + 3 4 } } } } } } } } } } } } } } } } } } } } } 5 6 7 8 ", +" 9 0 a } } } } } } } } } } } } } } } } } } } } } b c d e ", +" 8 f g h } } } } } } } } } } } } } } } } } } } } } i c j k l ", +" m n o p } } } } } } } } } } } } } } } } } } } } } q c r s m ", +" # t u u u u u u u u u u u u u u u u u u u u u u v v v w x y ", +" m z A A A A B B B C C C C D D D E E E E F F F F G G G H I J ", +" K # # # # # # # # # # # L L L L L L L L L L L L L L L # M ", +" N O P Q R S T U V W X Y Z ` ...+.@.#.$.%.&.*.=.-.;.>.,. ", +" '.).!.~.Q {.].^./.(._.:.<.[.}.|.W 1.2.3.` 4.5.6.7.8.9.,. ", +" 0.a.b.~.Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.` h.i.j. ", +" k.l.m.~.Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.` n.o.p. ", +" q.r.s.~.Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.` t.u. ", +" } v.w.~.Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.` x.y. ", +" z.A.~.Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.` B.C. ", +" D.E.~.Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.` F.G. ", +" H.I.~.Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.` J.K. ", +" L.M.~.Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.` N.O. ", +" P.Q.~.Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.` R.S. ", +" T.U.~.Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.V.W.X. ", +" Y.Z.~.Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.`. +.+ ", +" ++@+~.Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.#+$+%+ ", +" &+*+=+Q {.].^./.(._.:.<.[.}.|.W 1.c.d.e.3.f.g.-+;+>+ ", +" ,+'+)+!+~+{+]+^+/+(+T _+U :+<+[+}+|+X 1+2+3+4+5+6+7+ ", +" 8+9+0+a+b+c+d+e+f+f+g+h+i+j+k+l+m+n+o+p+q+r+s+t+ ", +" u+,+} } } } } } } } } } } } } } } } } } } } v+w+ ", +" ", +" "}; diff --git a/icons/upload.xpm b/icons/upload.xpm new file mode 100644 index 00000000..cb5087af --- /dev/null +++ b/icons/upload.xpm @@ -0,0 +1,22 @@ +/* XPM */ +static const char *upload_xpm[]={ +"16 16 3 1", +"# c None", +". c None", +"a c #0000c0", +"..#####aa#####..", +"..####aaaa####..", +"..###aaaaaa###..", +"..##aaaaaaaa##..", +"..#aaaaaaaaaa#..", +"..aaaaaaaaaaaa..", +".aaaaaaaaaaaaaa.", +"aaaaaaaaaaaaaaaa", +"#####aaaaaa#####", +".####aaaaaa#####", +".####aaaaaa####.", +"..###aaaaaa###..", +"..###aaaaaa###..", +"..###aaaaaa###..", +"..###aaaaaa###..", +"..###aaaaaa####."}; diff --git a/icons/user.xpm b/icons/user.xpm new file mode 100644 index 00000000..b626dd8d --- /dev/null +++ b/icons/user.xpm @@ -0,0 +1,76 @@ +/* XPM */ +static const char * user_xpm[] = { +"16 16 57 1", +" c None", +". c #888A85", +"+ c #AFB0AD", +"@ c #F3F3F2", +"# c #FEFEFE", +"$ c #F8F8F7", +"% c #F9F9F9", +"& c #FBFBFB", +"* c #F3F4F3", +"= c #F9FAF9", +"- c #FBFCFB", +"; c #F6F7F6", +"> c #F5F6F5", +", c #EBECEA", +"' c #F0F1EF", +") c #F5F4F3", +"! c #F2F3F2", +"~ c #EEEFEE", +"{ c #E8E9E6", +"] c #EEEFED", +"^ c #EFEFEE", +"/ c #EDEDEB", +"( c #E9EBE9", +"_ c #EEEEED", +": c #E5E7E4", +"< c #E7E9E6", +"[ c #E8E9E7", +"} c #E7E8E5", +"| c #898B86", +"1 c #ECEDEB", +"2 c #E3E4E1", +"3 c #E3E5E1", +"4 c #EDEDEC", +"5 c #92948F", +"6 c #BABBB8", +"7 c #8C8E89", +"8 c #EDEEED", +"9 c #E0E2DE", +"0 c #BABCB7", +"a c #9B9D98", +"b c #8B8D88", +"c c #9B9C98", +"d c #B8BAB6", +"e c #DFE0DD", +"f c #DCDDDA", +"g c #DDDEDA", +"h c #DBDDD9", +"i c #DBDCD9", +"j c #DADCD8", +"k c #DADBD7", +"l c #E9EAE7", +"m c #E9E9E7", +"n c #E3E4E0", +"o c #E3E3E0", +"p c #E2E3E0", +"q c #EFF0EE", +"r c #91938E", +" .... ", +" .+@##@+. ", +" +#$%&%#+ ", +" .@*@=-;>@. ", +" .#,')>!~#. ", +" .#{,]^/(#. ", +" .@_:<[}~@. ", +" |+#1234#+| ", +" 56+@##@+65 ", +" 7890abbcde87 ", +" 7#fgfhijjk#7 ", +" 7#llllmmmm#7 ", +" 7#222noppp#7 ", +" 7#fgfhijjk#7 ", +" 7q########q7 ", +" rrrrrrrrrrrr "}; diff --git a/icons/whiteball.png b/icons/whiteball.png new file mode 100644 index 0000000000000000000000000000000000000000..3846121bc5511a1bee8f62f7cf14e9b327f8ec84 GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xawj^(N7l!{JxM1({$v_d#0*}aI z1_o|n5N2eUHAey{$X?><>&kweTbf^3`trvWzkx!xJzX3_G|nHLq*&H!AmFNR8_(mN zz&TN2;+j^~4RiOiY-?~)5|)&VIi~vV`V^TTTc*A}F}*zf+#b$9rJ?T+?OLZVxHH2t z{nx(rbu8O+t2;T4%~-Tj>zt)a%evQH{~z0M?r=E1W&N_F#f+{k+j8@FACd6XoLHO| zDVF!3{OKI!mWJ<gp+}>l@5!Yv{yuNlI#11ot6Bs&6gRxLzW3YvvUCNX>ai31-bZ8y zUOoM<znH_l%JMnWDy>zgstdLk+sr>Nbc&II=kNg&->d886XvBmaWI(pHXF7T%4q-F aYR7oltJO~Rj<yESn+%?=elF{r5}E+RSAs$S literal 0 HcmV?d00001 diff --git a/icons/whiteball.xpm b/icons/whiteball.xpm new file mode 100644 index 00000000..42893eef --- /dev/null +++ b/icons/whiteball.xpm @@ -0,0 +1,37 @@ +/* XPM */ +static const char * whiteball_xpm[] = { +"14 14 20 1", +" g None", +". g #C6C6C6", +"+ g #CECECE", +"@ g #D6D6D6", +"# g #FFFFFF", +"$ g #EFEFEF", +"% g #E7E7E7", +"& g #9C9C9C", +"* g #BDBDBD", +"= g #949494", +"- g #848484", +"; g #5A5A5A", +"> g #DEDEDE", +", g #B5B5B5", +"' g #636363", +") g #ADADAD", +"! g #4A4A4A", +"~ g #737373", +"{ g #6B6B6B", +"] g #8C8C8C", +" ", +" ", +" .++++. ", +" +@###$.+ ", +" .+####%.&. ", +" +#####@*=- ", +" +####@*&-; ", +" +>%>+,&-'; ", +" +***)&-;!~ ", +" .=&=-~'!!& ", +" +{{;!!!] ", +" .~;;~& ", +" ", +" "}; diff --git a/importers/Makefile.am b/importers/Makefile.am new file mode 100644 index 00000000..0bf8738e --- /dev/null +++ b/importers/Makefile.am @@ -0,0 +1,76 @@ +## automake.am +## +## Automake.am for rivendell/importers +## +## (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +## +## $Id: Makefile.am,v 1.18.8.2 2012/11/29 01:37:35 cvs Exp $ +## $Date: 2012/11/29 01:37:35 $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = nexgen_filter\ + panel_copy\ + rdcatch_copy\ + rivendell_filter\ + sas_filter\ + wings_filter + +dist_nexgen_filter_SOURCES = nexgen_filter.cpp nexgen_filter.h +nodist_nexgen_filter_SOURCES = moc_nexgen_filter.cpp +nexgen_filter_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_panel_copy_SOURCES = panel_copy.cpp panel_copy.h +nodist_panel_copy_SOURCES = moc_panel_copy.cpp +panel_copy_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_rdcatch_copy_SOURCES = rdcatch_copy.cpp rdcatch_copy.h +nodist_rdcatch_copy_SOURCES = moc_rdcatch_copy.cpp +rdcatch_copy_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_rivendell_filter_SOURCES = rivendell_filter.cpp rivendell_filter.h +nodist_rivendell_filter_SOURCES = moc_rivendell_filter.cpp +rivendell_filter_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_sas_filter_SOURCES = sas_filter.cpp sas_filter.h +nodist_sas_filter_SOURCES = moc_sas_filter.cpp +sas_filter_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_wings_filter_SOURCES = wings_filter.cpp wings_filter.h +nodist_wings_filter_SOURCES = moc_wings_filter.cpp +wings_filter_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = export_slax + +CLEANFILES = *~\ + moc_* + +MAINTAINERCLEANFILES = *~\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_*\ + *.tar.gz diff --git a/importers/export_slax b/importers/export_slax new file mode 100755 index 00000000..023807c0 --- /dev/null +++ b/importers/export_slax @@ -0,0 +1,74 @@ +#!/bin/bash + +# export_slax +# +# Export the current Rivendell archive as a SLAX module. +# +# (C) Copyright 2006 Fred Gleason <fredg@paravelsystems.com> +# +# $Id: export_slax,v 1.4 2007/02/14 21:48:41 fredg Exp $ +# $Date: 2007/02/14 21:48:41 $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, +# Boston, MA 02111-1307 USA +# + +# +# Check arguments +# +if test -z $1 ; then + echo + echo " export_slax <module-name> [<audio-owner>]" + echo + exit 256 +fi +if test -z $2 ; then + AUDIO_OWNER=500 +else + AUDIO_OWNER=$2 +fi + +# +# Clean the build tree +# +BUILD_DIR=/var/tmp/export_slax +rm -rf $BUILD_DIR + +# +# Build the package tree +# +mkdir -p $BUILD_DIR/var/lib/mysql/mysql +mkdir -p $BUILD_DIR/var/lib/mysql/Rivendell +chown -R mysql:users $BUILD_DIR/var/lib/mysql +cp -a /var/lib/mysql/mysql $BUILD_DIR/var/lib/mysql/ +cp -a /var/lib/mysql/Rivendell $BUILD_DIR/var/lib/mysql/ +cp -a /var/snd $BUILD_DIR/var/ +chown -R $AUDIO_OWNER:root $BUILD_DIR/var/snd + +# +# Generate the package +# +SOURCE_DIR=`pwd` +cd $BUILD_DIR +makepkg --prepend --linkadd y --chown n export_slax.tgz +tgz2mo export_slax.tgz $SOURCE_DIR/$1 +cd $SOURCE_DIR + +# +# Clean up and exit +# +#rm -r $BUILD_DIR + + +# End of export_slax diff --git a/importers/nexgen_filter.cpp b/importers/nexgen_filter.cpp new file mode 100644 index 00000000..0b6060c5 --- /dev/null +++ b/importers/nexgen_filter.cpp @@ -0,0 +1,713 @@ +// nexgen_filter.cpp +// +// A Library import filter for the Prophet NexGen system +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: nexgen_filter.cpp,v 1.1.2.8 2013/06/20 20:24:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdint.h> +#include <errno.h> + +#include <qapplication.h> +#include <qstringlist.h> +#include <qfile.h> +#include <qregexp.h> + +#include <rddb.h> +#include <rd.h> +#include <rdconfig.h> +#include <rdconf.h> +#include <rdcmd_switch.h> +#include <rdcut.h> +#include <rdwavefile.h> +#include <rdcart.h> +#include <rdcut.h> +#include <rdweb.h> + +#include <nexgen_filter.h> + +// +// Global Variables +// +RDConfig *rdconfig; + + +MainObject::MainObject(QObject *parent,const char *name) + : QObject(parent,name) +{ + QString group_name; + QString audio_dir; + QString reject_dir="/dev/null"; + QStringList xml_files; + bool ok=false; + char tempdir[PATH_MAX]; + + filter_cart_offset=0; + filter_delete_cuts=false; + filter_normalization_level=0; + filter_verbose=false; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"nexgen_filter", + NEXGEN_FILTER_USAGE); + bool options=true; + for(unsigned i=0;i<cmd->keys();i++) { + if(!options) { + xml_files.push_back(cmd->key(i)); + } + else { + if(cmd->key(i)=="--verbose") { + filter_verbose=true; + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--group") { + group_name=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--audio-dir") { + audio_dir=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--reject-dir") { + reject_dir=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--cart-offset") { + filter_cart_offset=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"nexgen_filter: --cart-offset must be an integer\n"); + exit(256); + } + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--delete-cuts") { + filter_delete_cuts=true; + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--normalization-level") { + filter_normalization_level=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"nexgen_filter: --cart-offset must be an integer\n"); + exit(256); + } + if(filter_normalization_level>0) { + fprintf(stderr, + "nexgen_filter: positive --normalization-level is invalid\n"); + exit(256); + } + cmd->setProcessed(i,true); + } + if(!cmd->processed(i)) { + options=false; + xml_files.push_back(cmd->key(i)); + } + } + } + delete cmd; + + // + // Open Config + // + rdconfig=new RDConfig(RD_CONF_FILE); + rdconfig->load(); + + // + // Open Database + // + filter_db=QSqlDatabase::addDatabase(rdconfig->mysqlDriver()); + if(!filter_db) { + fprintf(stderr,"nexgen_filter: can't open mySQL database\n"); + exit(1); + } + filter_db->setDatabaseName(rdconfig->mysqlDbname()); + filter_db->setUserName(rdconfig->mysqlUsername()); + filter_db->setPassword(rdconfig->mysqlPassword()); + filter_db->setHostName(rdconfig->mysqlHostname()); + if(!filter_db->open()) { + fprintf(stderr,"nexgen_filter: unable to connect to mySQL Server\n"); + filter_db->removeDatabase(rdconfig->mysqlDbname()); + exit(1); + } + + // + // RIPCD Connection + // + filter_ripc=new RDRipc(""); + filter_ripc->connectHost("localhost",RIPCD_TCP_PORT,rdconfig->password()); + + // + // Station Configuration + // + filter_rdstation=new RDStation(rdconfig->stationName()); + + // + // Validate Arguments + // + if(group_name.isEmpty()) { + fprintf(stderr,"nexgen_filter: missing group name\n"); + exit(256); + } + filter_group=new RDGroup(group_name); + if(!filter_group->exists()) { + fprintf(stderr,"nexgen_filter: group \"%s\" does not exist\n", + (const char *)group_name); + exit(256); + } + filter_audio_dir=new QDir(audio_dir); + if(!audio_dir.isEmpty()) { + if(!filter_audio_dir->exists()) { + fprintf(stderr,"nexgen_filter: audio directory \"%s\" does not exist\n", + (const char *)audio_dir); + exit(256); + } + if(!filter_audio_dir->isReadable()) { + fprintf(stderr,"nexgen_filter: audio directory \"%s\" is not readable\n", + (const char *)audio_dir); + exit(256); + } + } + + // + // Configure Reject Directory + // + if(reject_dir=="/dev/null") { + filter_reject_dir=NULL; + } + else { + filter_reject_dir=new QDir(reject_dir); + if(!filter_reject_dir->exists()) { + fprintf(stderr,"nexgen_filter: reject directory \"%s\" does not exist\n", + (const char *)reject_dir); + exit(256); + } + } + + // + // Create Temp Directory + // + strncpy(tempdir,RDTempDir()+"/nexgen_filterXXXXXX",PATH_MAX); + filter_temp_dir=new QDir(mkdtemp(tempdir)); + filter_temp_audiofile=filter_temp_dir->canonicalPath()+"/audio.dat"; + + // + // Main Loop + // + for(unsigned i=0;i<xml_files.size();i++) { + if(IsXmlFile(xml_files[i])) { + if(audio_dir.isEmpty()) { + fprintf(stderr,"unable to process \"%s\" [no --audio-dir specified]\n", + (const char *)xml_files[i]); + } + else { + ProcessXmlFile(xml_files[i]); + } + } + else { + ProcessArchive(xml_files[i]); + } + } + + // + // Clean Up + // + rmdir(filter_temp_dir->canonicalPath()); + + exit(0); +} + + +void MainObject::ProcessArchive(const QString &filename) +{ + int fd_in=-1; + int fd_out=-1; + char tempdir[PATH_MAX]; + char *data=NULL; + QString dir; + char header[105]; + uint32_t len; + QString xmlfile; + QString wavfile; + QStringList files; + struct stat stat; + blksize_t blksize=1024; + ssize_t n=0; + + // + // Allocate Default Buffer + // + data=(char *)malloc(1024); + + // + // Create temporary directory + // + snprintf(tempdir,PATH_MAX,"%s/XXXXXX",(const char *)RDTempDir()); + if(mkdtemp(tempdir)==NULL) { + return; + } + dir=tempdir; + + // + // Open Archive + // + if((fd_in=open(filename,O_RDONLY))<0) { + return; + } + + // + // Write Out File Components + // + while((read(fd_in,header,104)==104)&&(strncmp(header,"FR:",3)==0)) { + files.push_back(dir+"/"+RDGetBasePart(QString(header+3).replace("\\","/"))); + if(files.back().right(4).lower()==".xml") { + xmlfile=files.back(); + } + if(files.back().right(4).lower()==".wav") { + wavfile=files.back(); + } + len=((0xFF&header[103])<<24)+((0xFF&header[102])<<16)+ + ((0xFF&header[101])<<8)+(0xFF&header[100]); + if((fd_out=open(files.back(),O_CREAT|O_WRONLY|O_TRUNC,S_IRUSR|S_IWUSR))<0) { + fprintf(stderr,"unable to write temporary file \"%s\" [%s].\n", + (const char *)files.back(),strerror(errno)); + return; + } + if(fstat(fd_out,&stat)==0) { + blksize=stat.st_blksize; + data=(char *)realloc(data,blksize); + } + for(uint32_t i=blksize;i<len;i+=blksize) { + n=read(fd_in,data,blksize); + write(fd_out,data,n); + } + n=read(fd_in,data,len%blksize); + write(fd_out,data,n); + close(fd_out); + } + close(fd_in); + + // + // Run Import + // + if((!xmlfile.isEmpty())&&(!wavfile.isEmpty())) { + ProcessXmlFile(xmlfile,wavfile,filename); + } + + // + // Clean Up + // + for(unsigned i=0;i<files.size();i++) { + unlink(files[i]); + } + rmdir(tempdir); + free(data); +} + + +void MainObject::ProcessXmlFile(const QString &xml,const QString &wavname, + const QString &arcname) +{ + RDCart *cart=NULL; + RDCut *cut=NULL; + RDWaveData data; + QString filename; + int cartnum; + QString sql; + RDSqlQuery *q; + QString delete_cuts_switch=""; + + // + // Read Metadata + // + if(!OpenXmlFile(xml,&data,&cartnum,&filename)) { + fprintf(stderr,"unable to parse XML file \"%s\"\n",(const char *)xml); + WriteReject(xml); + return; + } + if(!wavname.isEmpty()) { + filename=wavname; + } + + // + // Sanity Checks + // + if((cartnum<1)||(cartnum>999999)) { + fprintf(stderr,"calculated cart number [%d] is invalid\n",cartnum); + WriteReject(xml); + return; + } + if(filter_group->enforceCartRange()) { + if((cartnum<(int)filter_group->defaultLowCart())|| + (cartnum>(int)filter_group->defaultHighCart())) { + fprintf(stderr, + "calculated cart number [%d] is invalid for group \"%s\"\n", + cartnum,(const char *)filter_group->name()); + WriteReject(xml); + return; + } + } + + // + // Prepare Audio + // + if(!PreprocessAudio(filename)) { + WriteReject(xml); + return; + } + + // + // Import Audio + // + Print(QString().sprintf("Importing cart %06d",cartnum)); + if(!data.title().isEmpty()) { + Print(QString().sprintf(" [%s",(const char *)data.title())); + if(!data.artist().isEmpty()) { + Print(QString().sprintf("/%s",(const char *)data.artist())); + } + Print(QString().sprintf("]")); + } + if(arcname.isEmpty()) { + Print(QString().sprintf(" from %s ...",(const char *)filename)); + } + else { + Print(QString().sprintf(" from %s ...",(const char *)arcname)); + } + if(filter_delete_cuts) { + delete_cuts_switch="--delete-cuts "; + } + if(system(QString().sprintf("rdimport --autotrim-level=0 --normalization-level=%d --to-cart=%d ", + filter_normalization_level,cartnum)+ + +delete_cuts_switch+filter_group->name()+" "+ + filter_temp_audiofile)!=0) { + Print(QString().sprintf(" aborted.\n")); + fprintf(stderr,"import of \"%s\" failed\n",(const char *)filename); + WriteReject(xml); + return; + } + Print(QString().sprintf(" done.\n")); + unlink(filter_temp_audiofile); + + // + // Apply Metadata + // + cart=new RDCart(cartnum); + cart->setMetadata(&data); + delete cart; + sql= + QString().sprintf("select CUT_NAME from CUTS where CART_NUMBER=%d",cartnum)+ + " order by ORIGIN_DATETIME desc"; + q=new RDSqlQuery(sql); + if(q->first()) { + cut=new RDCut(q->value(0).toString()); + cut->setMetadata(&data); + delete cut; + } + delete q; +} + + +bool MainObject::OpenXmlFile(const QString &xml,RDWaveData *data, + int *cartnum,QString *filename) +{ + FILE *f=NULL; + char line[1024]; + int crossfade=-1; + int fadeup_start=-1; + int fadeup_len=-1; + + if((f=fopen(xml,"r"))==NULL) { + return false; + } + if(fgets(line,1024,f)==NULL) { + fclose(f); + return false; + } + if(!QString(line).contains("XMLDAT")) { + fclose(f); + return false; + } + while(fgets(line,1024,f)!=NULL) { + ProcessXmlLine(line,data,cartnum,filename,&crossfade,&fadeup_start, + &fadeup_len); + } + if((fadeup_start>=0)&&(fadeup_len>=0)) { // Calculate Start Marker + data->setStartPos(fadeup_start); + data->setEndPos(data->endPos()+fadeup_start); + data->setFadeUpPos(fadeup_start+fadeup_len); + } + if((crossfade!=-1)&&(data->endPos()>0)) { // Calculate Segue + data->setSegueStartPos(data->endPos()-crossfade); + data->setSegueEndPos(data->endPos()); + } + + fclose(f); + return true; +} + + +void MainObject::ProcessXmlLine(const QString &line,RDWaveData *data, + int *cartnum,QString *filename, + int *crossfade,int *fadeup_start, + int *fadeup_len) +{ + QString tag= + line.mid(line.find("<")+1,line.find(">")-line.find("<")-1).lower(); + QString value=line.mid(line.find(">")+1,line.findRev("<")-line.find(">")-1); + + // printf("%s: %s\n",(const char *)tag,(const char *)value); + + if(tag=="file_name") { + *filename=filter_audio_dir->canonicalPath()+"/"+ + value.right(value.length()-value.findRev('\\')-1); + } + if(tag=="cart") { + *cartnum=value.toUInt()+filter_cart_offset; + data->setMetadataFound(true); + } + if(tag=="title") { + data->setTitle(RDXmlUnescape(value)); + data->setMetadataFound(true); + } + if(tag=="artist") { + data->setArtist(RDXmlUnescape(value)); + data->setMetadataFound(true); + } + if(tag=="album") { + data->setAlbum(RDXmlUnescape(value)); + data->setMetadataFound(true); + } + if(tag=="label") { + data->setLabel(RDXmlUnescape(value)); + data->setMetadataFound(true); + } + if(tag=="composer") { + data->setComposer(RDXmlUnescape(value)); + data->setMetadataFound(true); + } + if(tag=="licensor") { + data->setLicensingOrganization(RDXmlUnescape(value)); + data->setMetadataFound(true); + } + if(tag=="user_define") { + data->setUserDefined(RDXmlUnescape(value)); + data->setMetadataFound(true); + } + if(tag=="isrc") { + data->setIsrc(value.replace("-","")); + data->setMetadataFound(true); + } + if(tag=="modified_time") { + QDateTime dt=GetDateTime(value); + data->setOriginationDate(dt.date()); + data->setOriginationTime(dt.time()); + data->setMetadataFound(true); + } + if(tag=="start_time") { + QDateTime dt=GetDateTime(value); + data->setStartDate(dt.date()); + data->setStartTime(dt.time()); + data->setMetadataFound(true); + } + if(tag=="end_time") { + QDateTime dt=GetDateTime(value); + data->setEndDate(dt.date()); + data->setEndTime(dt.time()); + data->setMetadataFound(true); + } + if(tag=="intro_start") { + data->setStartPos(value.toInt()); + data->setMetadataFound(true); + } + if(tag=="intro_3") { + if(value.toInt()>0) { + data->setIntroStartPos(0); + data->setIntroEndPos(value.toInt()); + } + } + if(tag=="hookstart") { + if(value.toInt()>0) { + data->setHookStartPos(value.toInt()); + } + } + if(tag=="hookend") { + if(value.toInt()>0) { + data->setHookEndPos(value.toInt()); + } + } + /* + if(tag=="length") { + data->setEndPos(value.toInt()); + data->setMetadataFound(true); + } + */ + if(tag=="runtime") { + data->setEndPos(value.toInt()); + data->setMetadataFound(true); + } + if(tag=="isci_code") { + data->setIsci(value); + data->setMetadataFound(true); + } + + // + // Used for calculating segue markers later + // + if(tag=="cross_fade") { + *crossfade=value.toInt(); + } + if(tag=="fade_up_start") { + *fadeup_start=value.toInt(); + } + if(tag=="fade_up_length") { + *fadeup_len=value.toInt(); + } +} + + +bool MainObject::PreprocessAudio(QString filename) +{ + int fd=-1; + char c; + + if((fd=open(filename,O_RDONLY))<0) { + filename=SwapCase(filename); + if((fd=open(filename,O_RDONLY))<0) { + fprintf(stderr,"unable to open audio file \"%s\"\n", + (const char *)filename); + return false; + } + + } + lseek(fd,20,SEEK_SET); + if(read(fd,&c,1)!=1) { + close(fd); + fprintf(stderr,"truncated audio file \"%s\"\n",(const char *)filename); + return false; + } + close(fd); + if(c==80) { // MPEG Audio + if(system(QString("madplay -Q -o wave:")+filter_temp_audiofile+" "+filename)!=0) { + fprintf(stderr,"MPEG converter error with file \"%s\"\n", + (const char *)filename); + return false; + } + } + else { // PCM Audio + if(symlink(filename,filter_temp_audiofile)!=0) { + fprintf(stderr,"unable to create symlink \"%s\"\n", + (const char *)filter_temp_audiofile); + return false; + } + } + return true; +} + + +void MainObject::WriteReject(const QString &filename) +{ + if(filter_reject_dir!=NULL) { + if(QFile::exists(filename)) { + if(!RDCopy(filename,filter_reject_dir->canonicalPath()+"/"+ + RDGetBasePart(filename))) { + fprintf(stderr,"Unable to write to \"%s\"\n", + (const char *)filter_reject_dir->path()); + } + } + } +} + + +QDateTime MainObject::GetDateTime(const QString &str) const +{ + QStringList fields; + QStringList dates; + QStringList times; + QDateTime ret; + + fields=fields.split(" ",str); + if(fields.size()==2) { + dates=dates.split("/",fields[0]); + if(dates.size()==3) { + times=times.split(":",fields[1]); + if(times.size()==3) { + ret= + QDateTime(QDate(dates[2].toInt(),dates[0].toInt(),dates[1].toInt()), + QTime(times[0].toInt(),times[1].toInt(),times[2].toInt())); + } + } + } + return ret; +} + + +QString MainObject::SwapCase(const QString &str) const +{ + QStringList parts=parts.split(".",str); + if(parts[parts.size()-1].contains(QRegExp("*[a-z]*",true,true))>0) { + parts[parts.size()-1]=parts[parts.size()-1].upper(); + } + else { + parts[parts.size()-1]=parts[parts.size()-1].lower(); + } + return parts.join("."); +} + + +bool MainObject::IsXmlFile(const QString &filename) +{ + int fd=-1; + char data[10]; + + if((fd=open(filename,O_RDONLY))<0) { + return false; + } + if(read(fd,data,8)!=8) { + close(fd); + return false; + } + close(fd); + data[8]=0; + return strncmp(data,"<XMLDAT>",8)==0; +} + + +void MainObject::Print(const QString &msg) const +{ + if(filter_verbose) { + printf("%s",(const char *)msg); + fflush(stdout); + } +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/importers/nexgen_filter.h b/importers/nexgen_filter.h new file mode 100644 index 00000000..ba26a6c4 --- /dev/null +++ b/importers/nexgen_filter.h @@ -0,0 +1,77 @@ +// nexgen_filter.h +// +// A Library import filter for the Prophet NexGen system +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: nexgen_filter.h,v 1.1.2.5 2013/06/20 20:24:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef NEXGEN_FILTER_H +#define NEXGEN_FILTER_H + +#include <stdio.h> + +#include <qobject.h> +#include <qapplication.h> +#include <qsqldatabase.h> +#include <qdatetime.h> +#include <qdir.h> + +#include <rdstation.h> +#include <rdripc.h> +#include <rdgroup.h> +#include <rdwavedata.h> + +#define NEXGEN_FILTER_USAGE "[options] <xml-file>|<pkt-file> [...]\n\nImport audio from a Prophet NexGen system, using metadata contained in\none or more XML files. Options are:\n\n--group=<group-name>\n The Rivendell group to use. This option is mandatory and has no default.\n\n--audio-dir=<path>\n The full path to the directory containing the audio files. This option\n is ignored when importing PKT files, but mandatory for importing\n using XML data. It has no default.\n\n--reject-dir=<path>\n The full path to the directory in which to place copies of XML files\n which were unable to be processed. Default is '/dev/null'.\n\n--cart-offset=<offset>\n Apply integer <offset> to the NexGen cart number before importing.\n Default is '0'.\n\n--delete-cuts\n If the destination cart already exists, delete any existing cuts\n within it before importing.\n\n--normalization-level=<level>\n The level to use for normalizing the audio, in dBFS. Specifying '0'\n will turn off normalization. Default is '0'.\n\n--verbose\n Print status messages as files are processed.\n\n<xml-file> [..]\n Filespec for XML file(s) containing import metadata.\n\n" + +class MainObject : public QObject +{ + Q_OBJECT + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + void ProcessArchive(const QString &filename); + void ProcessXmlFile(const QString &xml,const QString &wavname="", + const QString &arcname=""); + bool OpenXmlFile(const QString &xml,RDWaveData *data,int *cartnum, + QString *filename); + void ProcessXmlLine(const QString &line,RDWaveData *data,int *cartnum, + QString *filename,int *crossfade,int *fadeup_start, + int *fadeup_len); + bool PreprocessAudio(QString filename); + void WriteReject(const QString &filename); + QDateTime GetDateTime(const QString &str) const; + QString SwapCase(const QString &str) const; + bool IsXmlFile(const QString &filename); + void Print(const QString &msg) const; + RDGroup *filter_group; + QDir *filter_audio_dir; + QDir *filter_reject_dir; + QDir *filter_temp_dir; + QString filter_temp_audiofile; + int filter_cart_offset; + bool filter_delete_cuts; + int filter_normalization_level; + RDStation *filter_rdstation; + RDRipc *filter_ripc; + QSqlDatabase *filter_db; + bool filter_verbose; +}; + + +#endif diff --git a/importers/panel_copy.cpp b/importers/panel_copy.cpp new file mode 100644 index 00000000..98616b63 --- /dev/null +++ b/importers/panel_copy.cpp @@ -0,0 +1,219 @@ +// panel_copy.cpp +// +// An RDCatch event copier. +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: panel_copy.cpp,v 1.7 2010/07/29 19:32:32 cvs Exp $ +// $Date: 2010/07/29 19:32:32 $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +#include <qapplication.h> +#include <rddb.h> +#include <rd.h> +#include <dbversion.h> +#include <panel_copy.h> +#include <rdcmd_switch.h> + + +MainObject::MainObject(QObject *parent,const char *name) + : QObject(parent,name) +{ + bool found=false; + QString src_hostname; + QString dest_hostname; + QString src_station; + QString dest_station; + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"panel_copy", + PANEL_COPY_USAGE); + delete cmd; + + rd_config=new RDConfig(RD_CONF_FILE); + rd_config->load(); + + // + // Read Switches + // + for(int i=1;i<qApp->argc();i+=2) { + found=false; + if(QString(qApp->argv()[i])=="-h") { // Source mySQL Hostname + if((i+1)==qApp->argc()) { + fprintf(stderr,"panel_copy: invalid argument\n"); + exit(256); + } + src_hostname=qApp->argv()[i+1]; + found=true; + } + if(QString(qApp->argv()[i])=="-H") { // Source mySQL Hostname + if((i+1)==qApp->argc()) { + fprintf(stderr,"panel_copy: invalid argument\n"); + exit(256); + } + dest_hostname=qApp->argv()[i+1]; + found=true; + } + if(!found) { + fprintf(stderr,"panel_copy: invalid argument\n"); + exit(256); + } + } + + if(src_hostname.isEmpty()) { + fprintf(stderr,"panel_copy: invalid source mySQL hostname\n"); + exit(256); + } + if(dest_hostname.isEmpty()) { + fprintf(stderr,"panel_copy: invalid destination mySQL hostname\n"); + exit(256); + } + if(src_hostname==dest_hostname) { + fprintf(stderr,"panel_copy: cannot copy a database onto itself\n"); + exit(256); + } + + // + // Open Databases + // + src_db=QSqlDatabase::addDatabase("QMYSQL3","SRCDB"); + if(!src_db) { + fprintf(stderr,"panel_copy: can't open source mySQL database\n"); + exit(1); + } + src_db->setDatabaseName(rd_config->mysqlDbname()); + src_db->setUserName(rd_config->mysqlUsername()); + src_db->setPassword(rd_config->mysqlPassword()); + src_db->setHostName(src_hostname); + if(!src_db->open()) { + fprintf(stderr,"panel_copy: unable to connect to source mySQL server\n"); + src_db->removeDatabase(rd_config->mysqlDbname()); + exit(256); + } + + dest_db=QSqlDatabase::addDatabase("QMYSQL3","DESTDB"); + if(!dest_db) { + fprintf(stderr,"panel_copy: can't open destination mySQL database\n"); + exit(1); + } + dest_db->setDatabaseName(rd_config->mysqlDbname()); + dest_db->setUserName(rd_config->mysqlUsername()); + dest_db->setPassword(rd_config->mysqlPassword()); + dest_db->setHostName(dest_hostname); + if(!dest_db->open()) { + fprintf(stderr, + "panel_copy: unable to connect to destination mySQL server\n"); + dest_db->removeDatabase(rd_config->mysqlDbname()); + exit(256); + } + + // + // Check Database Versions + // + sql="select DB from VERSION"; + q=new RDSqlQuery(sql,src_db); + if(!q->first()) { + fprintf(stderr, + "panel_copy: unable to read source database version\n"); + exit(256); + } + if(q->value(0).toInt()!=RD_VERSION_DATABASE) { + fprintf(stderr,"panel_copy: source database version mismatch\n"); + exit(256); + } + delete q; + + q=new RDSqlQuery(sql,dest_db); + if(!q->first()) { + fprintf(stderr, + "panel_copy: unable to read destination database version\n"); + exit(256); + } + if(q->value(0).toInt()!=RD_VERSION_DATABASE) { + fprintf(stderr,"panel_copy: destination database version mismatch\n"); + exit(256); + } + delete q; + + // + // Confirmation Prompt + // + printf("\n"); + printf("****** WARNING ******\n"); + printf(" This operation will OVERWRITE ALL SOUNDPANEL BUTTON ASSIGNMENTS on the destination database!"); + printf(" Press RETURN to continue, or CNTL-C to abort."); + printf("\n"); + while(getchar()!=10); + printf("Copying button assignments..."); + fflush(stdout); + + // + // Delete current destination entries + // + sql="delete from PANELS"; + q=new RDSqlQuery(sql,dest_db); + delete q; + + // + // Copy Entries + // + sql="select TYPE,OWNER,PANEL_NO,ROW_NO,COLUMN_NO,LABEL,CART,DEFAULT_COLOR\ + from PANELS"; + q=new RDSqlQuery(sql,src_db); + while(q->next()) { + sql=QString().sprintf("insert into PANELS set \ + TYPE=%d,\ + OWNER=\"%s\",\ + PANEL_NO=%d,\ + ROW_NO=%d,\ + COLUMN_NO=%d,\ + LABEL=\"%s\",\ + CART=%d,\ + DEFAULT_COLOR=\"%s\"", + q->value(0).toInt(), + (const char *)q->value(1).toString(), + q->value(2).toInt(), + q->value(3).toInt(), + q->value(4).toInt(), + (const char *)q->value(5).toString(), + q->value(6).toInt(), + (const char *)q->value(7).toString()); + q1=new RDSqlQuery(sql,dest_db); + delete q1; + } + delete q; + + printf("done.\n"); + exit(0); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/importers/panel_copy.h b/importers/panel_copy.h new file mode 100644 index 00000000..2d6714a1 --- /dev/null +++ b/importers/panel_copy.h @@ -0,0 +1,48 @@ +// panel_copy.h +// +// A utility for copying SoundPanel assignments between databases. +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: panel_copy.h,v 1.5 2010/07/29 19:32:32 cvs Exp $ +// $Date: 2010/07/29 19:32:32 $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef PANEL_COPY_H +#define PANEL_COPY_H + +#include <qobject.h> +#include <qapplication.h> +#include <qsqldatabase.h> + +#include <rdconfig.h> + +#define PANEL_COPY_USAGE "-h <src-mysql-host> -H <dest-mysql-host>\n" + +class MainObject : public QObject +{ + Q_OBJECT + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + QSqlDatabase *src_db; + QSqlDatabase *dest_db; + RDConfig *rd_config; +}; + + +#endif diff --git a/importers/rdcatch_copy.cpp b/importers/rdcatch_copy.cpp new file mode 100644 index 00000000..602168dc --- /dev/null +++ b/importers/rdcatch_copy.cpp @@ -0,0 +1,335 @@ +// rdcatch_copy.cpp +// +// An RDCatch event copier. +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcatch_copy.cpp,v 1.8 2010/07/29 19:32:32 cvs Exp $ +// $Date: 2010/07/29 19:32:32 $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +#include <qapplication.h> + +#include <rd.h> +#include <dbversion.h> +#include <rdcatch_copy.h> +#include <rdcmd_switch.h> +#include <rddb.h> + +MainObject::MainObject(QObject *parent,const char *name) + : QObject(parent,name) +{ + bool found=false; + QString src_hostname; + QString dest_hostname; + QString src_station; + QString dest_station; + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdcatch_copy", + RDCATCH_COPY_USAGE); + delete cmd; + + rd_config=new RDConfig(RD_CONF_FILE); + rd_config->load(); + + // + // Read Switches + // + for(int i=1;i<qApp->argc();i+=2) { + found=false; + if(QString(qApp->argv()[i])=="-h") { // Source mySQL Hostname + if((i+1)==qApp->argc()) { + fprintf(stderr,"rdcatch_copy: invalid argument\n"); + exit(256); + } + src_hostname=qApp->argv()[i+1]; + found=true; + } + if(QString(qApp->argv()[i])=="-s") { // Source Rivendell Host + if((i+1)==qApp->argc()) { + fprintf(stderr,"rdcatch_copy: invalid argument\n"); + exit(256); + } + src_station=qApp->argv()[i+1]; + found=true; + } + if(QString(qApp->argv()[i])=="-H") { // Source mySQL Hostname + if((i+1)==qApp->argc()) { + fprintf(stderr,"rdcatch_copy: invalid argument\n"); + exit(256); + } + dest_hostname=qApp->argv()[i+1]; + found=true; + } + if(QString(qApp->argv()[i])=="-S") { // Source Rivendell Host + if((i+1)==qApp->argc()) { + fprintf(stderr,"rdcatch_copy: invalid argument\n"); + exit(256); + } + dest_station=qApp->argv()[i+1]; + found=true; + } + if(!found) { + fprintf(stderr,"rdcatch_copy: invalid argument\n"); + exit(256); + } + } + + if(src_hostname.isEmpty()) { + fprintf(stderr,"rdcatch_copy: invalid source mySQL hostname\n"); + exit(256); + } + if(src_station.isEmpty()) { + fprintf(stderr,"rdcatch_copy: invalid source Rivendell host\n"); + exit(256); + } + if(dest_hostname.isEmpty()) { + fprintf(stderr,"rdcatch_copy: invalid destination mySQL hostname\n"); + exit(256); + } + if(dest_station.isEmpty()) { + fprintf(stderr,"rdcatch_copy: invalid destination Rivendell host\n"); + exit(256); + } + + // + // Open Databases + // + src_db=QSqlDatabase::addDatabase("QMYSQL3"); + if(!src_db) { + fprintf(stderr,"rdcatch_copy: can't open source mySQL database\n"); + exit(1); + } + src_db->setDatabaseName(rd_config->mysqlDbname()); + src_db->setUserName(rd_config->mysqlUsername()); + src_db->setPassword(rd_config->mysqlPassword()); + src_db->setHostName(src_hostname); + if(!src_db->open()) { + fprintf(stderr,"rdcatch_copy: unable to connect to source mySQL server\n"); + src_db->removeDatabase(rd_config->mysqlDbname()); + exit(256); + } + + if(src_hostname==dest_hostname) { + if(src_station==dest_station) { + fprintf(stderr,"rdcatch_copy: cannot copy a host configuration onto itself\n"); + exit(256); + } + else { + dest_db=src_db; + } + } + else { + dest_db=QSqlDatabase::addDatabase("QMYSQL3"); + if(!dest_db) { + fprintf(stderr,"rdcatch_copy: can't open destination mySQL database\n"); + exit(1); + } + dest_db->setDatabaseName(rd_config->mysqlDbname()); + dest_db->setUserName(rd_config->mysqlUsername()); + dest_db->setPassword(rd_config->mysqlPassword()); + dest_db->setHostName(dest_hostname); + if(!dest_db->open()) { + fprintf(stderr, + "rdcatch_copy: unable to connect to destination mySQL server\n"); + dest_db->removeDatabase(rd_config->mysqlDbname()); + exit(256); + } + } + + // + // Check Database Versions + // + sql="select DB from VERSION"; + q=new RDSqlQuery(sql,src_db); + if(!q->first()) { + fprintf(stderr, + "rdcatch_copy: unable to read source database version\n"); + exit(256); + } + if(q->value(0).toInt()!=RD_VERSION_DATABASE) { + fprintf(stderr,"rdcatch_copy: source database version mismatch\n"); + exit(256); + } + delete q; + + q=new RDSqlQuery(sql,dest_db); + if(!q->first()) { + fprintf(stderr, + "rdcatch_copy: unable to read destination database version\n"); + exit(256); + } + if(q->value(0).toInt()!=RD_VERSION_DATABASE) { + fprintf(stderr,"rdcatch_copy: destination database version mismatch\n"); + exit(256); + } + delete q; + + // + // Check Rivendell Hosts + // + sql=QString().sprintf("select NAME from STATIONS where NAME=\"%s\"", + (const char *)src_station); + q=new RDSqlQuery(sql,src_db); + if(!q->first()) { + fprintf(stderr, + "rdcatch_copy: source Rivendell host doesn't exist\n"); + exit(256); + } + delete q; + + sql=QString().sprintf("select NAME from STATIONS where NAME=\"%s\"", + (const char *)dest_station); + q=new RDSqlQuery(sql,dest_db); + if(!q->first()) { + fprintf(stderr, + "rdcatch_copy: destination Rivendell host doesn't exist\n"); + exit(256); + } + delete q; + + // + // Confirmation Prompt + // + printf("\n"); + printf("****** WARNING ******\n"); + printf(" This operation will OVERWRITE ALL RDCATCH EVENTS on the destination Host!"); + printf(" Press RETURN to continue, or CNTL-C to abort."); + printf("\n"); + while(getchar()!=10); + printf("Copying events..."); + fflush(stdout); + + // + // Delete current destination entries + // + sql=QString().sprintf("delete from RECORDINGS where STATION_NAME\"%s\"", + (const char *)dest_station); + q=new RDSqlQuery(sql,dest_db); + delete q; + + // + // Copy Entries + // + sql=QString().sprintf("select IS_ACTIVE,TYPE,CHANNEL,CUT_NAME,SUN,MON,TUE,\ + WED,THU,FRI,SAT,DESCRIPTION,START_TYPE,START_TIME,\ + START_LENGTH,START_MATRIX,START_LINE,START_OFFSET,\ + END_TYPE,END_TIME,END_LENGTH,END_MATRIX,END_LINE,\ + LENGTH,TRIM_THRESHOLD,NORMALIZE_LEVEL,\ + STARTDATE_OFFSET,ENDDATE_OFFSET,FORMAT,CHANNELS,\ + SAMPRATE,BITRATE,QUALITY,MACRO_CART,SWITCH_INPUT,\ + SWITCH_OUTPUT,EXIT_CODE,ONE_SHOT,URL,URL_USERNAME,\ + URL_PASSWORD from RECORDINGS\ + where STATION_NAME=\"%s\"", + (const char *)src_station); + q=new RDSqlQuery(sql,src_db); + while(q->next()) { + sql=QString().sprintf("insert into RECORDINGS set IS_ACTIVE=\"%s\",\ + TYPE=%d,CHANNEL=%u,CUT_NAME=\"%s\",SUN=\"%s\",\ + MON=\"%s\",TUE=\"%s\",WED=\"%s\",THU=\"%s\",\ + FRI=\"%s\",SAT=\"%s\",DESCRIPTION=\"%s\",\ + START_TYPE=%d,START_TIME=\"%s\",START_LENGTH=%d,\ + START_MATRIX=%d,START_LINE=%d,START_OFFSET=%d,\ + END_TYPE=%d,END_TIME=\"%s\",END_LENGTH=%d,\ + END_MATRIX=%d,END_LINE=%d,LENGTH=%u,\ + TRIM_THRESHOLD=%d,NORMALIZE_LEVEL=%d,\ + STARTDATE_OFFSET=%u,ENDDATE_OFFSET=%u,FORMAT=%d,\ + CHANNELS=%d,SAMPRATE=%d,BITRATE=%d,QUALITY=%d,\ + MACRO_CART=%d,SWITCH_INPUT=%d,SWITCH_OUTPUT=%d,\ + EXIT_CODE=%d,ONE_SHOT=\"%s\",URL=\"%s\",\ + URL_USERNAME=\"%s\",URL_PASSWORD=\"%s\",\ + STATION_NAME=\"%s\"", + (const char *)q->value(0).toString(), + + q->value(1).toInt(),q->value(2).toUInt(), + (const char *)q->value(3).toString(), + (const char *)q->value(4).toString(), + + (const char *)q->value(5).toString(), + (const char *)q->value(6).toString(), + (const char *)q->value(7).toString(), + (const char *)q->value(8).toString(), + + (const char *)q->value(9).toString(), + (const char *)q->value(10).toString(), + (const char *)q->value(11).toString(), + + q->value(12).toInt(), + (const char *)q->value(13).toString(), + q->value(14).toInt(), + + q->value(15).toInt(), + q->value(16).toInt(), + q->value(17).toInt(), + + q->value(18).toInt(), + (const char *)q->value(19).toString(), + q->value(20).toInt(), + + q->value(21).toInt(), + q->value(22).toInt(), + q->value(23).toUInt(), + + q->value(24).toInt(), + q->value(25).toInt(), + + q->value(26).toUInt(), + q->value(27).toUInt(), + q->value(28).toInt(), + + q->value(29).toInt(), + q->value(30).toInt(), + q->value(31).toInt(), + q->value(32).toInt(), + + q->value(33).toInt(), + q->value(34).toInt(), + q->value(35).toInt(), + + q->value(36).toInt(), + (const char *)q->value(37).toString(), + (const char *)q->value(38).toString(), + + (const char *)q->value(39).toString(), + (const char *)q->value(40).toString(), + (const char *)dest_station); + q1=new RDSqlQuery(sql,dest_db); + delete q1; + } + delete q; + + printf("done.\n"); + exit(0); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/importers/rdcatch_copy.h b/importers/rdcatch_copy.h new file mode 100644 index 00000000..9a9bf78c --- /dev/null +++ b/importers/rdcatch_copy.h @@ -0,0 +1,52 @@ +// rdcatch_copy.h +// +// An RDCatch event copier. +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcatch_copy.h,v 1.6 2010/07/29 19:32:32 cvs Exp $ +// $Date: 2010/07/29 19:32:32 $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCATCH_COPY_H +#define RDCATCH_COPY_H + +#include <qobject.h> +#include <qapplication.h> +#include <qsqldatabase.h> + +#include <rdstation.h> +#include <rdripc.h> +#include <rdcatch_connect.h> +#include <rdstation.h> +#include <rdconfig.h> + +#define RDCATCH_COPY_USAGE "-h <src-mysql-host> -s <src-rd-host> -H <dest-mysql-host> -S <dest-rd-host>\n" + +class MainObject : public QObject +{ + Q_OBJECT + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + QSqlDatabase *src_db; + QSqlDatabase *dest_db; + RDConfig *rd_config; +}; + + +#endif diff --git a/importers/rivendell_filter.cpp b/importers/rivendell_filter.cpp new file mode 100644 index 00000000..0b37d7b5 --- /dev/null +++ b/importers/rivendell_filter.cpp @@ -0,0 +1,497 @@ +// rivendell_filter.cpp +// +// A Library import filter for an external Rivendell system +// +// (C) Copyright 2002-2005,2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rivendell_filter.cpp,v 1.3 2010/07/29 19:32:32 cvs Exp $ +// $Date: 2010/07/29 19:32:32 $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> + +#include <qapplication.h> +#include <qdir.h> + +#include <rddb.h> +#include <rd.h> +#include <rdconf.h> +#include <rdconfig.h> +#include <rdcmd_switch.h> +#include <rdescape_string.h> +#include <rdcut.h> +#include <rivendell_filter.h> + + +// +// Global Variables +// +RDConfig *rdconfig; + + +MainObject::MainObject(QObject *parent,const char *name) + : QObject(parent,name) +{ + QString ext_dbname; + QString ext_hostname; + QString ext_username; + QString ext_password; + QString ext_audiodir; + QString default_group; + unsigned start_cartnum=0; + unsigned end_cartnum=0; + QSqlDatabase *filter_db; + QSqlDatabase *ext_db; + bool ok=false; + bool found; + QString start_datetime; + QString end_datetime; + QString start_daypart; + QString end_daypart; + QString owner; + QString group; + QString sql; + QSqlQuery *q; + QSqlQuery *q1; + QSqlQuery *q2; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rivendell_filter", + RIVENDELL_FILTER_USAGE); + delete cmd; + + rdconfig=new RDConfig(RD_CONF_FILE); + rdconfig->load(); + + // + // Open Local Database + // + filter_db=QSqlDatabase::addDatabase(rdconfig->mysqlDriver(),"LOCAL_DB"); + if(!filter_db) { + fprintf(stderr,"rivendell_filter: can't open local mySQL database\n"); + exit(1); + } + filter_db->setDatabaseName(rdconfig->mysqlDbname()); + filter_db->setUserName(rdconfig->mysqlUsername()); + filter_db->setPassword(rdconfig->mysqlPassword()); + filter_db->setHostName(rdconfig->mysqlHostname()); + if(!filter_db->open()) { + fprintf(stderr, + "rivendell_filter: unable to connect to local mySQL Server\n"); + filter_db->removeDatabase(rdconfig->mysqlDbname()); + exit(1); + } + + // + // Read Arguments + // + for(int i=1;i<(qApp->argc()-1);i+=2) { + found=false; + if(!strcmp("-h",qApp->argv()[i])) { + ext_hostname=qApp->argv()[i+1]; + found=true; + } + if(!strcmp("-u",qApp->argv()[i])) { + ext_username=qApp->argv()[i+1]; + found=true; + } + if(!strcmp("-p",qApp->argv()[i])) { + ext_password=qApp->argv()[i+1]; + found=true; + } + if(!strcmp("-A",qApp->argv()[i])) { + ext_audiodir=qApp->argv()[i+1]; + found=true; + } + if(!strcmp("-g",qApp->argv()[i])) { + default_group=qApp->argv()[i+1]; + found=true; + } + if(!strcmp("-s",qApp->argv()[i])) { + start_cartnum=QString(qApp->argv()[i+1]).toUInt(&ok); + if(!ok) { + fprintf(stderr,"\nrivendell_filter: invalid group number\n"); + exit(256); + } + found=true; + } + if(!strcmp("-e",qApp->argv()[i])) { + end_cartnum=QString(qApp->argv()[i+1]).toUInt(&ok); + if(!ok) { + fprintf(stderr,"\nrivendell_filter: invalid group number\n"); + exit(256); + } + found=true; + } + if(!found) { + fprintf(stderr,"\nrivendell_filter %s\n",RIVENDELL_FILTER_USAGE); + exit(1); + } + } + if((start_cartnum==0)||(start_cartnum>999999)) { + fprintf(stderr,"\nrivendell_filter: invalid start cart value\n"); + exit(256); + } + if((end_cartnum==0)||(end_cartnum>999999)) { + fprintf(stderr,"\nrivendell_filter: invalid end cart value\n"); + exit(256); + } + if(start_cartnum>end_cartnum) { + fprintf(stderr,"\nrivendell_filter: invalid cart values\n"); + exit(256); + } + if(ext_audiodir.isEmpty()) { + fprintf(stderr,"rivendell_filter: invalid source audio directory\n"); + exit(256); + } + QDir dir=QDir(ext_audiodir); + if(!dir.exists()) { + fprintf(stderr,"rivendell_filter: invalid source audio directory\n"); + exit(256); + } + if(!dir.isReadable()) { + fprintf(stderr, + "rivendell_filter: source audio directory is not readable\n"); + exit(256); + } + if(ext_audiodir.right(1)!="/") { + ext_audiodir+="/"; + } + + // + // Open Remote Database + // + ext_db=QSqlDatabase::addDatabase(rdconfig->mysqlDriver(),"REMOTE_DB"); + if(!ext_db) { + fprintf(stderr,"rivendell_filter: can't open remote mySQL database\n"); + exit(1); + } + ext_db->setDatabaseName(rdconfig->mysqlDbname()); + ext_db->setUserName(ext_username); + ext_db->setPassword(ext_password); + ext_db->setHostName(ext_hostname); + if(!ext_db->open()) { + fprintf(stderr, + "rivendell_filter: unable to connect to remote mySQL Server\n"); + ext_db->removeDatabase(rdconfig->mysqlDbname()); + exit(1); + } + + // + // Verify that default group exists + // + sql=QString().sprintf("select NAME from GROUPS where NAME=\"%s\"", + (const char *)default_group); + q=new QSqlQuery(sql,filter_db); + if(!q->next()) { + fprintf(stderr,"rivendell_filter: default group does not exist\n"); + exit(256); + } + delete q; + + // + // Transfer Loop + // + sql=QString().sprintf("select NUMBER,TYPE,GROUP_NAME,TITLE,ARTIST,ALBUM,\ + YEAR,ISRC,LABEL,CLIENT,AGENCY,PUBLISHER,COMPOSER,\ + USER_DEFINED,USAGE_CODE,FORCED_LENGTH,AVERAGE_LENGTH,\ + LENGTH_DEVIATION,AVERAGE_SEGUE_LENGTH,\ + AVERAGE_HOOK_LENGTH,CUT_QUANTITY,LAST_CUT_PLAYED,\ + PLAY_ORDER,VALIDITY,\ + ENFORCE_LENGTH,PRESERVE_PITCH,ASYNCRONOUS,\ + OWNER,MACROS,SCHED_CODES from CART \ + where (NUMBER>=%u)&&(NUMBER<=%u)", + start_cartnum,end_cartnum); + q=new QSqlQuery(sql,ext_db); + while(q->next()) { + printf("Transferring cart %06u [%s]...",q->value(0).toUInt(), + (const char *)q->value(3).toString()); + fflush(stdout); + + // + // Validate Group + // + sql=QString().sprintf("select NAME from GROUPS where NAME=\"%s\"", + (const char *)RDEscapeString(q->value(2).toString())); + q1=new QSqlQuery(sql,filter_db); + if(q1->first()) { + group=q->value(2).toString(); + } + else { + group=default_group; + } + delete q1; + + // + // Purge old entries + // + sql=QString().sprintf("select CUT_NAME from CUTS where CART_NUMBER=%u", + q->value(0).toUInt()); + q1=new QSqlQuery(sql,filter_db); + while(q1->next()) { + unlink(RDCut::pathName(q1->value(0).toString())); + } + delete q1; + sql=QString().sprintf("delete from CUTS where CART_NUMBER=%u", + q->value(0).toUInt()); + q1=new QSqlQuery(sql,filter_db); + delete q1; + sql=QString().sprintf("delete from CART where NUMBER=%u", + q->value(0).toUInt()); + q1=new QSqlQuery(sql,filter_db); + delete q1; + + // + // Create new entries + // + if(q->value(27).isNull()) { + owner="null"; + } + else { + owner=QString().sprintf("\"%s\"", + (const char *)RDEscapeString(q->value(27).toString())); + } + sql=QString().sprintf("insert into CART set NUMBER=%u,\ + TYPE=%u,\ + GROUP_NAME=\"%s\",\ + TITLE=\"%s\",\ + ARTIST=\"%s\",\ + ALBUM=\"%s\",\ + YEAR=\"%s\",\ + ISRC=\"%s\",\ + LABEL=\"%s\",\ + CLIENT=\"%s\",\ + AGENCY=\"%s\",\ + PUBLISHER=\"%s\",\ + COMPOSER=\"%s\",\ + USER_DEFINED=\"%s\",\ + USAGE_CODE=\"%s\",\ + FORCED_LENGTH=%u,\ + AVERAGE_LENGTH=%u,\ + LENGTH_DEVIATION=%u,\ + AVERAGE_SEGUE_LENGTH=%u,\ + AVERAGE_HOOK_LENGTH=%u,\ + CUT_QUANTITY=%u,\ + LAST_CUT_PLAYED=%u,\ + PLAY_ORDER=%u,\ + VALIDITY=%u,\ + ENFORCE_LENGTH=\"%s\",\ + PRESERVE_PITCH=\"%s\",\ + ASYNCRONOUS=\"%s\",\ + OWNER=%s,\ + MACROS=\"%s\",\ + SCHED_CODES=\"%s\"", + q->value(0).toUInt(), + q->value(1).toUInt(), + (const char *)RDEscapeString(group), + (const char *)RDEscapeString(q->value(3).toString()), + (const char *)RDEscapeString(q->value(4).toString()), + (const char *)RDEscapeString(q->value(5).toString()), + (const char *)q->value(6).toDate(). + toString("yyyy-MM-dd"), + (const char *)RDEscapeString(q->value(7).toString()), + (const char *)RDEscapeString(q->value(8).toString()), + (const char *)RDEscapeString(q->value(9).toString()), + (const char *)RDEscapeString(q->value(10).toString()), + (const char *)RDEscapeString(q->value(11).toString()), + (const char *)RDEscapeString(q->value(12).toString()), + (const char *)RDEscapeString(q->value(13).toString()), + (const char *)RDEscapeString(q->value(14).toString()), + q->value(15).toUInt(), + q->value(16).toUInt(), + q->value(17).toUInt(), + q->value(18).toUInt(), + q->value(19).toUInt(), + q->value(20).toUInt(), + q->value(21).toUInt(), + q->value(22).toUInt(), + q->value(23).toUInt(), + (const char *)RDEscapeString(q->value(24).toString()), + (const char *)RDEscapeString(q->value(25).toString()), + (const char *)RDEscapeString(q->value(26).toString()), + (const char *)owner, + (const char *)RDEscapeString(q->value(28).toString()), + (const char *)RDEscapeString(q->value(29). + toString())); + q1=new QSqlQuery(sql,filter_db); + delete q1; + sql=QString().sprintf("select CUT_NAME,EVERGREEN,DESCRIPTION,OUTCUE,ISRC,\ + LENGTH,ORIGIN_DATETIME,START_DATETIME,END_DATETIME,\ + SUN,MON,TUE,WED,THU,FRI,SAT,START_DAYPART,\ + END_DAYPART,ORIGIN_NAME,WEIGHT,VALIDITY,\ + CODING_FORMAT,SAMPLE_RATE,BIT_RATE,CHANNELS,\ + PLAY_GAIN,START_POINT,END_POINT,FADEUP_POINT,\ + FADEDOWN_POINT,SEGUE_START_POINT,SEGUE_END_POINT,\ + SEGUE_GAIN,HOOK_START_POINT,HOOK_END_POINT,\ + TALK_START_POINT,TALK_END_POINT from CUTS \ + where CART_NUMBER=%u",q->value(0).toUInt()); + q1=new QSqlQuery(sql,ext_db); + while(q1->next()) { + if(q1->value(7).isNull()) { + start_datetime="null"; + } + else { + start_datetime=QString().sprintf("\"%s\"", + (const char *)q1->value(7). + toDateTime().toString("yyyy-MM-dd hh:mm:ss")); + } + if(q1->value(8).isNull()) { + end_datetime="null"; + } + else { + end_datetime=QString().sprintf("\"%s\"", + (const char *)q1->value(8). + toDateTime().toString("yyyy-MM-dd hh:mm:ss")); + } + if(q1->value(16).isNull()) { + start_daypart="null"; + } + else { + start_daypart=QString().sprintf("\"%s\"", + (const char *)q1->value(16). + toTime().toString("hh:mm:ss")); + } + if(q1->value(17).isNull()) { + end_daypart="null"; + } + else { + end_daypart=QString().sprintf("\"%s\"", + (const char *)q1->value(17). + toTime().toString("hh:mm:ss")); + } + sql=QString().sprintf("insert into CUTS set CART_NUMBER=%u,\ + CUT_NAME=\"%s\",\ + EVERGREEN=\"%s\",\ + DESCRIPTION=\"%s\",\ + OUTCUE=\"%s\",\ + ISRC=\"%s\",\ + LENGTH=%u,\ + ORIGIN_DATETIME=\"%s\",\ + START_DATETIME=%s,\ + END_DATETIME=%s,\ + SUN=\"%s\",\ + MON=\"%s\",\ + TUE=\"%s\",\ + WED=\"%s\",\ + THU=\"%s\",\ + FRI=\"%s\",\ + SAT=\"%s\",\ + START_DAYPART=%s,\ + END_DAYPART=%s,\ + ORIGIN_NAME=\"%s\",\ + WEIGHT=%u,\ + VALIDITY=%u,\ + CODING_FORMAT=%u,\ + SAMPLE_RATE=%u,\ + BIT_RATE=%u,\ + CHANNELS=%u,\ + PLAY_GAIN=%d,\ + START_POINT=%d,\ + END_POINT=%d,\ + FADEUP_POINT=%d,\ + FADEDOWN_POINT=%d,\ + SEGUE_START_POINT=%d,\ + SEGUE_END_POINT=%d,\ + SEGUE_GAIN=%d,\ + HOOK_START_POINT=%d,\ + HOOK_END_POINT=%d,\ + TALK_START_POINT=%d,\ + TALK_END_POINT=%d", + q->value(0).toUInt(), + (const char *)RDEscapeString(q1->value(0). + toString()), + (const char *)RDEscapeString(q1->value(1). + toString()), + (const char *)RDEscapeString(q1->value(2). + toString()), + (const char *)RDEscapeString(q1->value(3). + toString()), + (const char *)RDEscapeString(q1->value(4). + toString()), + q1->value(5).toUInt(), + (const char *)RDEscapeString(q1->value(6). + toString()), + (const char *)start_datetime, + (const char *)end_datetime, + (const char *)RDEscapeString(q1->value(9). + toString()), + (const char *)RDEscapeString(q1->value(10). + toString()), + (const char *)RDEscapeString(q1->value(11). + toString()), + (const char *)RDEscapeString(q1->value(12). + toString()), + (const char *)RDEscapeString(q1->value(13). + toString()), + (const char *)RDEscapeString(q1->value(14). + toString()), + (const char *)RDEscapeString(q1->value(15). + toString()), + (const char *)start_daypart, + (const char *)end_daypart, + (const char *)RDEscapeString(q1->value(18). + toString()), + q1->value(19).toUInt(), + q1->value(20).toUInt(), + q1->value(21).toUInt(), + q1->value(22).toUInt(), + q1->value(23).toUInt(), + q1->value(24).toUInt(), + q1->value(25).toInt(), + q1->value(26).toInt(), + q1->value(27).toInt(), + q1->value(28).toInt(), + q1->value(29).toInt(), + q1->value(30).toInt(), + q1->value(31).toInt(), + q1->value(32).toInt(), + q1->value(33).toInt(), + q1->value(34).toInt(), + q1->value(35).toInt(), + q1->value(36).toInt()); + q2=new QSqlQuery(sql,filter_db); + delete q2; + ok=RDCopy(QString().sprintf("%s%s.%s",(const char *)ext_audiodir, + (const char *)q1->value(0).toString(), + RD_AUDIO_EXTENSION), + RDCut::pathName(q1->value(0).toString())); + if(!ok) { + printf("[WARNING -- NO AUDIO FOUND]..."); + fflush(stdout); + } + } + delete q1; + printf("done.\n"); + } + delete q; + + exit(0); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/importers/rivendell_filter.h b/importers/rivendell_filter.h new file mode 100644 index 00000000..91fb528a --- /dev/null +++ b/importers/rivendell_filter.h @@ -0,0 +1,43 @@ +// rivendell_filter.h +// +// A Library import filter for an external Rivendell system +// +// (C) Copyright 2002-2005, 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rivendell_filter.h,v 1.3 2010/07/29 19:32:32 cvs Exp $ +// $Date: 2010/07/29 19:32:32 $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RIVENDELL_FILTER_H +#define RIVENDELL_FILTER_H + +#include <stdio.h> + +#include <qobject.h> +#include <qapplication.h> +#include <qsqldatabase.h> + +#define RIVENDELL_FILTER_USAGE " -h <hostname> -u <username> -p <password> -A <audio-dir> -g <default-group> -s <start-cartnum> -e <end-cartnum>" + +class MainObject : public QObject +{ + Q_OBJECT + public: + MainObject(QObject *parent=0,const char *name=0); +}; + + +#endif // RIVENDELL_FILTER_H diff --git a/importers/sas_filter.cpp b/importers/sas_filter.cpp new file mode 100644 index 00000000..1ef095e2 --- /dev/null +++ b/importers/sas_filter.cpp @@ -0,0 +1,283 @@ +// sas_filter.cpp +// +// An RDCatch event import filter for the SAS64000 +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: sas_filter.cpp,v 1.11 2011/06/21 22:20:43 cvs Exp $ +// $Date: 2011/06/21 22:20:43 $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// 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.// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +#include <qapplication.h> +#include <rddb.h> +#include <rd.h> +#include <rdcmd_switch.h> +#include <dbversion.h> + +#include <sas_filter.h> + +// +// Global Variables +// + + +MainObject::MainObject(QObject *parent,const char *name) + : QObject(parent,name) +{ + bool skip_db_check=false; + unsigned schema=0; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"sas_filter",SAS_FILTER_USAGE); + for(unsigned i=0;i<cmd->keys();i++) { + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + } + delete cmd; + + rd_config=new RDConfig(RD_CONF_FILE); + rd_config->load(); + filter_switch_count=0; + filter_macro_count=0; + + // + // Open Database + // + QString err(tr("sas_filter: ")); + filter_db=RDInitDb(&schema,&err); + if(!filter_db) { + fprintf(stderr,"%s\n",err.ascii()); + exit(1); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr, + "sas_filter: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + + // + // RIPCD Connection + // + filter_ripc=new RDRipc(""); + filter_ripc->connectHost("localhost",RIPCD_TCP_PORT,rd_config->password()); + + // + // Station Configuration + // + filter_rdstation=new RDStation(rd_config->stationName()); + + // + // RDCatchd Connection + // + filter_connect=new RDCatchConnect(0,this,"filter_connect"); + filter_connect->connectHost("localhost",RDCATCHD_TCP_PORT, + rd_config->password()); + + // + // Read Switches + // + if((qApp->argc()==2)&&(!strcmp(qApp->argv()[1],"-d"))) { // Delete List + DeleteList(); + filter_connect->reset(); + exit(0); + } + if((qApp->argc()==3)&&(!strcmp(qApp->argv()[1],"-i"))) { // Insert List + InsertList(); + filter_connect->reset(); + exit(0); + } + fprintf(stderr,"\nsas_filter %s\n",SAS_FILTER_USAGE); + exit(1); +} + + +void MainObject::InsertList() +{ + char line[256]; + int count=0; + + FILE *fh=fopen(qApp->argv()[2],"r"); + if(fh==NULL) { + perror("sas_filter"); + exit(1); + } + printf("Importing events from %s...",qApp->argv()[2]); + fflush(0); + while(fgets(line,256,fh)!=NULL) { + if(strlen(line)==79) { + InjectLine(line); + count++; + } + } + printf("done.\n"); + fclose(fh); + printf("Imported %d switch events, %d macro events, %d total.\n", + filter_switch_count,filter_macro_count, + filter_switch_count+filter_macro_count); +} + + +void MainObject::DeleteList() +{ + QString sql="delete from RECORDINGS"; + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + filter_connect->reset(); + printf("RDCatch events list deleted!\n"); +} + + +void MainObject::InjectLine(char *line) +{ + QString temp; + int input=0; + int output=0; + int gpo=0; + + // + // Initialize the SQL clause + // + QString base_sql=QString().sprintf("insert into RECORDINGS set\ + STATION_NAME=\"%s\",CHANNEL=%d,", + (const char *)rd_config->sasStation(), + rd_config->sasMatrix()); + + // + // Day of the week fields + // + if(line[0]=='X') { + base_sql+="MON=\"Y\","; + } + if(line[1]=='X') { + base_sql+="TUE=\"Y\","; + } + if(line[2]=='X') { + base_sql+="WED=\"Y\","; + } + if(line[3]=='X') { + base_sql+="THU=\"Y\","; + } + if(line[4]=='X') { + base_sql+="FRI=\"Y\","; + } + if(line[5]=='X') { + base_sql+="SAT=\"Y\","; + } + if(line[6]=='X') { + base_sql+="SUN=\"Y\","; + } + + // + // Time + // + line[17]=0; + base_sql+=QString().sprintf("START_TIME=\"%s\",",line+9); + + // + // Title + // + line[60]=0; + temp=QString(line+19).stripWhiteSpace(); + base_sql+=QString().sprintf("DESCRIPTION=\"%s\",",(const char *)temp); + + // + // Active Flag + // + if(line[77]=='I') { + base_sql+="IS_ACTIVE=\"N\","; + } + + // + // Output + // + line[65]=0; + sscanf(line+62,"%d",&output); + + // + // Input + // + line[70]=0; + sscanf(line+67,"%d",&input); + + // + // GPO + // + line[75]=0; + sscanf(line+73,"%d",&gpo); + + if((input>0)&&(output>0)) { + InjectSwitchEvent(base_sql,input,output); + } + if(gpo>0) { + InjectCartEvent(base_sql,gpo); + } +} + + +void MainObject::InjectSwitchEvent(QString sql,int input,int output) +{ + // + // Event Type + // + sql+="TYPE=2,"; + + // + // Input and Output + // + sql+=QString().sprintf("SWITCH_INPUT=%d,SWITCH_OUTPUT=%d",input,output); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + filter_switch_count++; +} + + +void MainObject::InjectCartEvent(QString sql,int gpo) +{ + // + // Event Type + // + sql+="TYPE=1,"; + + // + // Macro Cart + // + sql+=QString().sprintf("MACRO_CART=%d",gpo+rd_config->sasBaseCart()); + filter_macro_count++; + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; +// printf("SQL: %s\n",(const char *)sql); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/importers/sas_filter.h b/importers/sas_filter.h new file mode 100644 index 00000000..39595c7a --- /dev/null +++ b/importers/sas_filter.h @@ -0,0 +1,61 @@ +// sas_filter.h +// +// An RDCatch event import filter for the SAS64000 +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: sas_filter.h,v 1.7 2010/07/29 19:32:32 cvs Exp $ +// $Date: 2010/07/29 19:32:32 $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef SAS_FILTER_H +#define SAS_FILTER_H + +#include <qobject.h> +#include <qapplication.h> +#include <qsqldatabase.h> + +#include <rdstation.h> +#include <rdripc.h> +#include <rdcatch_connect.h> +#include <rdstation.h> +#include <rdconfig.h> + +#define SAS_FILTER_USAGE "-d|-i <insert-list>\n" + +class MainObject : public QObject +{ + Q_OBJECT + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + void InsertList(); + void DeleteList(); + void InjectLine(char *line); + void InjectSwitchEvent(QString sql,int input,int output); + void InjectCartEvent(QString sql,int gpo); + RDStation *filter_rdstation; + RDRipc *filter_ripc; + RDCatchConnect *filter_connect; + QSqlDatabase *filter_db; + int filter_switch_count; + int filter_macro_count; + RDConfig *rd_config; +}; + + +#endif diff --git a/importers/wings_filter.cpp b/importers/wings_filter.cpp new file mode 100644 index 00000000..0038df18 --- /dev/null +++ b/importers/wings_filter.cpp @@ -0,0 +1,329 @@ +// wings_filter.cpp +// +// A Library import filter for the Airforce Wings system +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: wings_filter.cpp,v 1.13 2010/07/29 19:32:33 cvs Exp $ +// $Date: 2010/07/29 19:32:33 $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> + +#include <qapplication.h> + +#include <rddb.h> +#include <rd.h> +#include <rdconfig.h> +#include <rdcmd_switch.h> +#include <rdcut.h> +#include <wings_filter.h> + + +// +// Global Variables +// +RDConfig *rdconfig; + + +MainObject::MainObject(QObject *parent,const char *name) + : QObject(parent,name) +{ + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"wings_filter", + WINGS_FILTER_USAGE); + delete cmd; + + WingsRecord wr; + QString audioname; + bool found; + QString dbname; + QString audiodir; + QString audio_extension=WINGS_DEFAULT_AUDIO_EXT; + QString groupname; + RDWaveFile *wavefile=NULL; + + rdconfig=new RDConfig(RD_CONF_FILE); + rdconfig->load(); + + // + // Open Database + // + + + filter_db=QSqlDatabase::addDatabase(rdconfig->mysqlDriver()); + if(!filter_db) { + fprintf(stderr,"wings_filter: can't open mySQL database\n"); + exit(1); + } + filter_db->setDatabaseName(rdconfig->mysqlDbname()); + filter_db->setUserName(rdconfig->mysqlUsername()); + filter_db->setPassword(rdconfig->mysqlPassword()); + filter_db->setHostName(rdconfig->mysqlHostname()); + if(!filter_db->open()) { + fprintf(stderr,"wings_filter: unable to connect to mySQL Server\n"); + filter_db->removeDatabase(rdconfig->mysqlDbname()); + exit(1); + } + + // + // RIPCD Connection + // + filter_ripc=new RDRipc(""); + filter_ripc->connectHost("localhost",RIPCD_TCP_PORT,rdconfig->password()); + + // + // Station Configuration + // + filter_rdstation=new RDStation(rdconfig->stationName()); + + // + // Read Arguments + // + for(int i=1;i<(qApp->argc()-1);i+=2) { + found=false; + if(!strcmp("-d",qApp->argv()[i])) { + dbname=qApp->argv()[i+1]; + found=true; + } + if(!strcmp("-A",qApp->argv()[i])) { + audiodir=qApp->argv()[i+1]; + found=true; + } + if(!strcmp("-g",qApp->argv()[i])) { + groupname=qApp->argv()[i+1]; + found=true; + } + if(!strcmp("-e",qApp->argv()[i])) { + audio_extension=qApp->argv()[i+1]; + found=true; + } + if(!found) { + fprintf(stderr,"\nwings_filter %s\n",WINGS_FILTER_USAGE); + exit(1); + } + } + + FILE *file=fopen((const char *)dbname,"r"); + if(file==NULL) { + perror("wings_filter"); + exit(1); + } + + RDGroup *default_group=new RDGroup(groupname); + if(!default_group->exists()) { + fprintf(stderr,"wings_filter: no such default group\n"); + delete default_group; + exit(256); + } + while(ReadLine(file,&wr)) { + strcpy(wr.extension,audio_extension); + audioname=QString().sprintf("%s/%s.%s",(const char *)audiodir, + wr.filename,(const char *)audio_extension); + wavefile=new RDWaveFile(audioname); + if(!wavefile->openWave()) { + fprintf(stderr,"Unable to open %s, skipping...\n", + (const char *)audioname); + } + else { + if(wavefile->type()!=RDWaveFile::Atx) { + fprintf(stderr,"ATX header in %s appears corrupt, skipping...\n", + (const char *)audioname); + } + else { + RDGroup *group=new RDGroup(wr.group); + if(group->exists()) { + ImportCut(group,&wr,wavefile); + } + else { + ImportCut(default_group,&wr,wavefile); + } + delete group; + } + wavefile->closeWave(); + } + delete wavefile; + } + + delete default_group; + fclose(file); + exit(0); +} + + +bool MainObject::ImportCut(RDGroup *group,struct WingsRecord *rec, + RDWaveFile *wavefile) +{ + unsigned cartnum=0; + QString sql; + RDSqlQuery *q; + int format=0; + RDWaveFile *destfile; + int n; + char buffer[WINGS_XFER_BUFFER_SIZE]; + + if((cartnum=group->nextFreeCart())==0) { + fprintf(stderr,"No more available carts in group %s, skipping %s...\n", + rec->group,rec->filename); + delete group; + return false; + } + destfile=new RDWaveFile(RDCut::pathName(QString().sprintf + ("%06u_001",cartnum))); + switch(wavefile->getFormatTag()) { + case WAVE_FORMAT_PCM: + format=0; + destfile->setBextChunk(true); + destfile->setFormatTag(WAVE_FORMAT_PCM); + break; + + case WAVE_FORMAT_MPEG: + if(wavefile->getHeadLayer()==2) { + format=1; + destfile->setFormatTag(WAVE_FORMAT_MPEG); + destfile->setHeadLayer(2); + destfile->setHeadBitRate(wavefile->getHeadBitRate()); + destfile->setHeadMode(wavefile->getHeadMode()); + destfile->setMextChunk(true); + destfile->setMextHomogenous(true); + destfile->setMextAncillaryLength(3); + destfile->setMextLeftEnergyPresent(true); + if(wavefile->getChannels()>1) { + destfile->setMextRightEnergyPresent(true); + } + } + else { + return false; + } + break; + + default: + return false; + break; + } + destfile->setSamplesPerSec(wavefile->getSamplesPerSec()); + destfile->setBitsPerSample(wavefile->getBitsPerSample()); + destfile->setChannels(wavefile->getChannels()); + destfile->setBextChunk(true); + destfile->setBextDescription(rec->title); + if(!destfile->createWave()) { + fprintf(stderr,"wings_filter: unable to write to audio directory\n"); + exit(256); + } + while((n=wavefile->readWave(buffer,WINGS_XFER_BUFFER_SIZE))>0) { + destfile->writeWave(buffer,n); + } + destfile->closeWave(); + + printf("Importing %s - %s to cart %u, group %s\n", + rec->filename,rec->title,cartnum,(const char *)group->name()); + + sql=QString().sprintf("insert into CART set NUMBER=%u,GROUP_NAME=\"%s\",\ + TITLE=\"%s\",ARTIST=\"%s\",ALBUM=\"%s\",\ + CUT_QUANTITY=1,TYPE=%d,FORCED_LENGTH=%u,\ + AVERAGE_LENGTH=%u,USER_DEFINED=\"%s.%s\"", + cartnum,(const char *)group->name(), + rec->title,rec->artist,rec->album, + RDCart::Audio,wavefile->getExtTimeLength(), + wavefile->getExtTimeLength(), + rec->filename,rec->extension); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("insert into CUTS set CUT_NAME=\"%06u_001\",\ + CART_NUMBER=%u,DESCRIPTION=\"%s\",\ + ORIGIN_DATETIME=\"%s\",ORIGIN_NAME=\"%s\",\ + CODING_FORMAT=%d,SAMPLE_RATE=%u,CHANNELS=%d,\ + BIT_RATE=%d,LENGTH=%u,START_POINT=0,\ + END_POINT=%d", + cartnum,cartnum,(const char *)rec->title, + (const char *)QDateTime::currentDateTime(). + toString("yyyy-MM-dd hh:mm:ss"), + (const char *)rdconfig->stationName(),format, + wavefile->getSamplesPerSec(), + wavefile->getChannels(),wavefile->getHeadBitRate(), + wavefile->getExtTimeLength(), + wavefile->getExtTimeLength()); + q=new RDSqlQuery(sql); + delete q; + + return true; +} + + +bool MainObject::ReadLine(FILE *fp,struct WingsRecord *rec) +{ + char buffer[WINGS_RECORD_LENGTH+1]; + + memset(rec,0,sizeof(struct WingsRecord)); + if(fgets(buffer,WINGS_RECORD_LENGTH+1,fp)==NULL) { + return false; + } + if(strlen(buffer)<WINGS_RECORD_LENGTH) { + return false; + } + buffer[8]=0; // Fielname + strcpy(rec->filename,buffer); + TrimSpaces(rec->filename); + + rec->group[0]=buffer[9]; // Group + rec->group[1]=0; + + buffer[17]=0; // Length + sscanf(buffer+14,"%d",&rec->length); + rec->length*=1000; + + buffer[47]=0; // Title + strcpy(rec->title,buffer+24); + TrimSpaces(rec->title); + + buffer[77]=0; // Artist + strcpy(rec->artist,buffer+55); + TrimSpaces(rec->artist); + + buffer[105]=0; + strcpy(rec->album,buffer+78); + TrimSpaces(rec->album); + + return true; +} + + +void MainObject::TrimSpaces(char *str) +{ + for(int i=strlen(str)-1;i>=0;i--) { + if(isspace(str[i])) { + str[i]=0; + } + else { + i=-1; + } + } +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/importers/wings_filter.h b/importers/wings_filter.h new file mode 100644 index 00000000..f7eaa2df --- /dev/null +++ b/importers/wings_filter.h @@ -0,0 +1,71 @@ +// wings_filter.h +// +// A Library import filter for the Crown Wings system +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: wings_filter.h,v 1.9 2010/07/29 19:32:33 cvs Exp $ +// $Date: 2010/07/29 19:32:33 $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WINGS_FILTER_H +#define WINGS_FILTER_H + +#include <stdio.h> + +#include <qobject.h> +#include <qapplication.h> +#include <qsqldatabase.h> + +#include <rdwavefile.h> +#include <rdstation.h> +#include <rdripc.h> +#include <rdcatch_connect.h> +#include <rdcae.h> +#include <rdgroup.h> + +#define WINGS_RECORD_LENGTH 613 +#define WINGS_FILTER_USAGE "-g <default-group> -d <db-file> -A <audio-dir> [-e <audio-ext>]\n" +#define WINGS_DEFAULT_AUDIO_EXT "ATX" +#define WINGS_XFER_BUFFER_SIZE 4096 + +struct WingsRecord { + char filename[9]; + char extension[4]; + char title[32]; + char artist[32]; + char album[32]; + char group[2]; + unsigned length; +}; + +class MainObject : public QObject +{ + Q_OBJECT + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + bool ImportCut(RDGroup *group,struct WingsRecord *rec,RDWaveFile *wavefile); + bool ReadLine(FILE *fp,struct WingsRecord *rec); + void TrimSpaces(char *str); + RDStation *filter_rdstation; + RDRipc *filter_ripc; + QSqlDatabase *filter_db; +}; + + +#endif diff --git a/install-init.sh b/install-init.sh new file mode 100755 index 00000000..816a37d3 --- /dev/null +++ b/install-init.sh @@ -0,0 +1,41 @@ +#! /bin/bash + +# install-init.sh +# +# Install the init scripts for Rivendell +# +# (C) Copyright 2005 Fred Gleason <fredg@paravelsystems.com> +# +# $Id: install-init.sh,v 1.7 2010/07/29 19:32:30 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +if test ! -f ./building-debian ; then + mkdir -p /etc/init.d + cp rivendell /etc/init.d/rivendell + cp rdrepld-suse /etc/init.d/rdrepld + mkdir -p /etc/sysconfig + cp rivendell.sys /etc/sysconfig/rivendell + mkdir -p /var/run/rivendell + chmod 777 /var/run/rivendell + ldconfig +fi + +chmod 4755 $1/bin/caed +chmod 4755 $1/bin/ripcd +chmod 4755 $1/bin/rdcatchd + + +# End of install-init.sh diff --git a/ios/Makefile.am b/ios/Makefile.am new file mode 100644 index 00000000..33b2b1a4 --- /dev/null +++ b/ios/Makefile.am @@ -0,0 +1,40 @@ +## automake.am +## +## Automake.am for rivendell/ios +## +## (C) Copyright 2011 Fred Gleason <fredg@paravelsystems.com> +## +## $Id: Makefile.am,v 1.1.6.1 2012/11/29 01:37:35 cvs Exp $ +## +## 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. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +SUBDIRS = rmlsend + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/ios/rmlsend/Classes/Makefile.am b/ios/rmlsend/Classes/Makefile.am new file mode 100644 index 00000000..8945707a --- /dev/null +++ b/ios/rmlsend/Classes/Makefile.am @@ -0,0 +1,33 @@ +## automake.am +## +## Automake.am for rivendell/ios/rmlsend/Classes +## +## (C) Copyright 2011 Fred Gleason <fredg@paravelsystems.com> +## +## $Id: Makefile.am,v 1.1 2011/05/27 16:53:00 cvs Exp $ +## +## 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. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +EXTRA_DIST = RMLSendAppDelegate.h\ + RMLSendAppDelegate.m\ + RMLSendViewController.h\ + RMLSendViewController.m\ + TextFieldDelegate.h\ + TextFieldDelegate.m + +CLEANFILES = *~ moc_* *.qm *.obj *.idb *.pdb *ilk +MAINTAINERCLEANFILES = *~ Makefile.in configure aclocal.m4 *.tar.gz moc_* diff --git a/ios/rmlsend/Classes/RMLSendAppDelegate.h b/ios/rmlsend/Classes/RMLSendAppDelegate.h new file mode 100644 index 00000000..20a26fe4 --- /dev/null +++ b/ios/rmlsend/Classes/RMLSendAppDelegate.h @@ -0,0 +1,35 @@ +// +// RMLSendAppDelegate.h +// RMLSend +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: RMLSendAppDelegate.h,v 1.2 2011/05/27 17:20:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// // You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#import <UIKit/UIKit.h> + +@class RMLSendViewController; + +@interface RMLSendAppDelegate : NSObject <UIApplicationDelegate> { + UIWindow *window; + RMLSendViewController *viewController; +} + +@property (nonatomic, retain) IBOutlet UIWindow *window; +@property (nonatomic, retain) IBOutlet RMLSendViewController *viewController; + +@end + diff --git a/ios/rmlsend/Classes/RMLSendAppDelegate.m b/ios/rmlsend/Classes/RMLSendAppDelegate.m new file mode 100644 index 00000000..b1525b9c --- /dev/null +++ b/ios/rmlsend/Classes/RMLSendAppDelegate.m @@ -0,0 +1,104 @@ +// +// RMLSendAppDelegate.m +// RMLSend +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: RMLSendAppDelegate.m,v 1.3 2011/05/31 22:47:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#import "RMLSendAppDelegate.h" +#import "RMLSendViewController.h" + +@implementation RMLSendAppDelegate + +@synthesize window; +@synthesize viewController; + + +#pragma mark - +#pragma mark Application lifecycle + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + + // Override point for customization after application launch. + + // Add the view controller's view to the window and display. + [window addSubview:viewController.view]; + [window makeKeyAndVisible]; + + [viewController RestoreFields]; + return YES; +} + + +- (void)applicationWillResignActive:(UIApplication *)application { + /* + Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. + */ +} + + +- (void)applicationDidEnterBackground:(UIApplication *)application { + /* + Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + If your application supports background execution, called instead of applicationWillTerminate: when the user quits. + */ + [viewController SaveFields]; +} + + +- (void)applicationWillEnterForeground:(UIApplication *)application { + /* + Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background. + */ +} + + +- (void)applicationDidBecomeActive:(UIApplication *)application { + /* + Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + */ +} + + +- (void)applicationWillTerminate:(UIApplication *)application { + /* + Called when the application is about to terminate. + See also applicationDidEnterBackground:. + */ +} + + +#pragma mark - +#pragma mark Memory management + +- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { + /* + Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later. + */ +} + + +- (void)dealloc { + [viewController release]; + [window release]; + [super dealloc]; +} + + +@end diff --git a/ios/rmlsend/Classes/RMLSendViewController.h b/ios/rmlsend/Classes/RMLSendViewController.h new file mode 100644 index 00000000..f8b212ff --- /dev/null +++ b/ios/rmlsend/Classes/RMLSendViewController.h @@ -0,0 +1,68 @@ +// +// RMLSendViewController.h +// RMLSend +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: RMLSendViewController.h,v 1.3 2011/05/31 22:47:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <netdb.h> +#include <netinet/ip.h> +#include <netinet/in.h> + +#import <UIKit/UIKit.h> + +#define RMLSEND_TAG_IPADDR 0 +#define RMLSEND_TAG_UDPPORT 1 +#define RMLSEND_TAG_CMDLINE 2 +#define RMLSEND_TAG_BUTTON 3 + +@interface RMLSendViewController : UIViewController <UITextFieldDelegate> { + UITextField *ipaddr; + UITextField *udpport; + UITextField *cmdline; + UIButton *button; + int sock; + struct sockaddr_in sa; + NSString *conf_filename; +} + +@property(nonatomic,retain) IBOutlet UITextField *ipaddr; +@property(nonatomic,retain) IBOutlet UITextField *udpport; +@property(nonatomic,retain) IBOutlet UITextField *cmdline; +@property(nonatomic,retain) IBOutlet UIButton *button; + +-(IBAction) processSend: (id) sender; + +-(BOOL) ValidateFields; +-(BOOL) SaveFields; +-(BOOL) RestoreFields; + +// +// UITextFieldDelegate methods +// +-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField; +-(void) textFieldDidBeginEditing:(UITextField *)textField; +-(BOOL) textFieldShouldEndEditing:(UITextField *)textField; +-(void) textFieldDidEndEditing:(UITextField *)textField; +-(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange: (NSRange) range + replacementString: (NSString *) string; +-(BOOL) textFieldShouldClear:(UITextField *)textField; +-(BOOL) textFieldShouldReturn: (UITextField *) textField; + +@end + diff --git a/ios/rmlsend/Classes/RMLSendViewController.m b/ios/rmlsend/Classes/RMLSendViewController.m new file mode 100644 index 00000000..9f67605d --- /dev/null +++ b/ios/rmlsend/Classes/RMLSendViewController.m @@ -0,0 +1,262 @@ +// +// RMLSendViewController.m +// RMLSend +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: RMLSendViewController.m,v 1.3 2011/05/31 22:47:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA +// + +#include <unistd.h> +#include <sys/socket.h> + +#import "RMLSendViewController.h" +#import "TextFieldDelegate.h" + +@implementation RMLSendViewController + +@synthesize ipaddr,udpport,cmdline,button; + +-(IBAction) processSend: (id) sender +{ + sendto(sock,[cmdline.text UTF8String],cmdline.text.length,0,(struct sockaddr *)(&sa),sizeof(sa)); +} + + +-(BOOL) ValidateFields +{ + struct hostent *host=NULL; + + // + // IP Address + // + if([ipaddr.text length]<1) { + return NO; + } + if((host=gethostbyname([ipaddr.text UTF8String]))==NULL) { + NSString *err=[[NSString alloc] initWithUTF8String: hstrerror(h_errno)]; + UIAlertView *alert=[[UIAlertView alloc] + initWithTitle: @"RMLSend" + message: err + delegate:nil + cancelButtonTitle:nil + otherButtonTitles:@"OK",nil]; + [alert show]; + [alert release]; + [err release]; + return NO; + } + sa.sin_addr.s_addr=*((uint32_t *)host->h_addr_list[0]); + + // + // Command-line + // + if([cmdline.text length]<1) { + return NO; + } + if([cmdline.text characterAtIndex:[cmdline.text length]-1]!='!') { + return NO; + } + + // + // UDP Port + // + if((udpport.text.intValue<1)||(udpport.text.intValue>0xFFFF)) { + UIAlertView *alert=[[UIAlertView alloc] + initWithTitle: @"RMLSend" + message: @"Invalid Port Number" + delegate:nil + cancelButtonTitle:nil + otherButtonTitles:@"OK",nil]; + [alert show]; + [alert release]; + return NO; + } + sa.sin_port=htons(udpport.text.intValue); + + return YES; +} + +-(BOOL) SaveFields +{ + NSMutableString *str=[[NSMutableString alloc] init]; + [str appendString: ipaddr.text]; + [str appendString: @"\n"]; + [str appendString: udpport.text]; + [str appendString: @"\n"]; + [str appendString: cmdline.text]; + [str writeToFile: conf_filename atomically: NO encoding: NSASCIIStringEncoding error: nil]; + return YES; + } + +-(BOOL) RestoreFields +{ + NSString *str=[NSString stringWithContentsOfFile: conf_filename encoding: NSASCIIStringEncoding error: nil]; + NSArray *fields=[NSArray arrayWithArray: [str componentsSeparatedByString: @"\n"]]; + if(fields.count==3) { + [ipaddr setText: [fields objectAtIndex: 0]]; + [udpport setText: [fields objectAtIndex: 1]]; + [cmdline setText: [fields objectAtIndex: 2]]; + } + return YES; +} + + +// The designated initializer. Override to perform setup that is required before the view is loaded. +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { + if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) { + NSLog(@"Started up!"); + // Custom initialization + } + return self; +} + + +/* +// Implement loadView to create a view hierarchy programmatically, without using a nib. +- (void)loadView { +} +*/ + + + +// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. +- (void)viewDidLoad { + [super viewDidLoad]; + ipaddr.delegate=self; + udpport.delegate=self; + cmdline.delegate=self; + + // + // Configure the UDP Socket + // + if((sock=socket(PF_INET,SOCK_DGRAM,0))<0) { + NSLog(@"socket: %s",strerror(errno)); + } + memset(&sa,0,sizeof(sa)); + sa.sin_family=AF_INET; + + // + // Initialize the configuration file + // + NSString *dir=[NSHomeDirectory() stringByAppendingPathComponent: @"Documents/.rivendell"]; + NSFileManager *fm=[[NSFileManager alloc] init]; + if([fm contentsOfDirectoryAtPath: dir error: nil]==nil) { + [fm createDirectoryAtPath: dir withIntermediateDirectories: YES attributes: nil error: nil]; + } + conf_filename=[[NSString alloc] initWithString: [dir stringByAppendingPathComponent: @"rmlsend"]]; + if(![fm fileExistsAtPath: conf_filename]) { + [fm createFileAtPath: conf_filename contents: [[NSData alloc] init] attributes: nil]; + } +/* + UIAlertView *alert=[[UIAlertView alloc] + initWithTitle: @"RMLSend" + message: conf_filename + delegate:nil + cancelButtonTitle:nil + otherButtonTitles:@"OK",nil]; + [alert show]; + [alert release]; + */ + } + + + +/* +// Override to allow orientations other than the default portrait orientation. +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { + // Return YES for supported orientations + return (interfaceOrientation == UIInterfaceOrientationPortrait); +} +*/ + +- (void)didReceiveMemoryWarning { + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + + // Release any cached data, images, etc that aren't in use. +} + +- (void)viewDidUnload { + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; +} + + +// +// UITextFieldDelegate methods +// +-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField +{ + return YES; +} + + +-(void) textFieldDidBeginEditing:(UITextField *)textField +{ +} + + +-(BOOL) textFieldShouldEndEditing:(UITextField *)textField +{ + return YES; +} + + +-(void) textFieldDidEndEditing:(UITextField *)textField +{ +} + + +-(BOOL) textField: (UITextField *) textField shouldChangeCharactersInRange: (NSRange) range +replacementString: (NSString *) string +{ + return YES; +} + + +-(BOOL) textFieldShouldClear:(UITextField *)textField +{ + return YES; +} + + +-(BOOL) textFieldShouldReturn: (UITextField *) textField +{ + switch(textField.tag) { + case RMLSEND_TAG_IPADDR: + break; + + case RMLSEND_TAG_UDPPORT: + break; + + case RMLSEND_TAG_CMDLINE: + break; + } + button.enabled=[self ValidateFields]; + [textField resignFirstResponder]; + return YES; +} + + +- (void)dealloc { + if(sock>=0) { + close(sock); + } + [super dealloc]; +} + +@end diff --git a/ios/rmlsend/Classes/TextFieldDelegate.h b/ios/rmlsend/Classes/TextFieldDelegate.h new file mode 100644 index 00000000..9317e8c9 --- /dev/null +++ b/ios/rmlsend/Classes/TextFieldDelegate.h @@ -0,0 +1,32 @@ +// +// TextFieldDelegate.h +// RMLSend +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: TextFieldDelegate.h,v 1.2 2011/05/27 17:20:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA +// + +#import <Foundation/Foundation.h> +#import <UIKit/UIKit.h> + +@interface TextFieldDelegate : NSObject { + +} + +-(BOOL) textFieldShouldReturn: (UITextField *) textField; + +@end diff --git a/ios/rmlsend/Classes/TextFieldDelegate.m b/ios/rmlsend/Classes/TextFieldDelegate.m new file mode 100644 index 00000000..768d9e14 --- /dev/null +++ b/ios/rmlsend/Classes/TextFieldDelegate.m @@ -0,0 +1,35 @@ +// +// TextFieldDelegate.m +// RMLSend +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: TextFieldDelegate.m,v 1.2 2011/05/27 17:20:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA +// + +#import "TextFieldDelegate.h" + + +@implementation TextFieldDelegate + +-(BOOL) textFieldShouldReturn: (UITextField *) textField +{ + [textField resignFirstResponder]; + return YES; +} + + +@end diff --git a/ios/rmlsend/Icon.png b/ios/rmlsend/Icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3be3a5d3d61611e5c71c452487b7354dc74e353b GIT binary patch literal 5931 zcmV+`7u4v9P)<h;3K|Lk000e1NJLTq001li001lq0ssI2k><@-000U@X+uL$Nkc;* zaB^>EX>4Tx0C?J+Q+HUC_ZB|i_hk=OLfG)Jmu!ImA|tE_$Pihg5Rw34gb)%y#f69p zRumNxoJdu~g4GI0orvO~D7a@qiilc^Ra`jkAKa(4eR}Wh?fcjJyyu+f{LXpL4}cL8 zCXwc%Y5+M>g*-agACFH+#L2yY0u@N$1RxOR%fe>`#Q*^C19^CUbg)1C0k3ZW0swH; zE+i7i;s1lWP$pLZAdvvzA`<5d0gzGv$SzdK6adH=0I*ZDWC{S3003-xd_p1ssto|_ z^hrJi0NAOM+!p}Yq8zCR0F40vnJ7mj0zkU}U{!%qECRs70HCZuA}$2Lt^t5qwlYTo zfV~9(c8*w(4?ti5fSE!p%m5%b0suoE6U_r4Oaq`W(!b!TUvP!ENC5!A%azTSOVTqG zxRuZvck=My;vwR~Y_URN7by^C3FIQ2mzyIKNaq7g&I|wm8u`(|{y0C7=jP<$=4R(? z@ASo@{%i1WB0eGU-~POe0t5gMPS5Y!U*+Z218~Oyuywy{sapWrRsd+<`CT*H37}dE z(0cicc{uz)9-g64$UGe!3JVMEC1RnyFyo6p|1;rl;ER6t{6HT5+j{T-ahgDxt-zy$ z{c&M#cCJ#6=gR~_F>d$gBmT#QfBlXr(c(0*Tr3re@mPttP$EsodAU-NL?OwQ;u7h9 zGVvdl{RxwI4FIf$Pry#L2er#=z<%xl0*ek<(slqqe)BDi8VivC5N9+pdG`PSlfU_o zKq~<N&6lL(006w`7+k277fi+o002awfhw>;2Moa!tiTSO!5zH77Xo1hL_iEAz&sE_ z2IPPo3ZWR5K^auQI@koYumc*P5t`u;w81er4d>tzT!HIw7Y1M$p28Tsh6w~g$Osc* zAv%Z=Vvg7%&IlKojszlMNHmgwq#)^t6j36@$a16tsX}UzT}UJHEpik&ja)$bklV;0 zGK&0)yhkyVfwEBp)B<%txu_o+ipHRG(R4HqU4WLNYtb6C9zB4zqNmYI=yh}eeTt4_ zfYC7yW{lZkT#ScBV2M~7CdU?I<ybXVk2PZ*ST}YR8^E4n?+7FUi+~gC2wsE`!fb+& zkVjZdSVO2K>?5=ix(HVZgM=}{CnA%mPqZa^68Xe<Vmh&qSVpWS?jar_o+Vx<4ijIK zNF)x)lH^VbAtjJ9NefA9NZUv)q*J6m(hzB!OeX7)ZOPu`2(o~zAeWK1kPnbglKaWS z<hK+$#faie38ExYq?8g$HDy2L1f`!cLYbhdQO&8I)Cj7GI-goeZJ>5gFH?u96Et<2 zCC!@_L(8Nsqt(!wX=iEoXfNq>x(VHb9z~bXm(pwK2kGbOgY<U{4TcSa$4Fu*8EYAP z8K)Sx884YkrUlcNnaETy*D@QKXP6I|Z&g?-_9}c8k;)R4I+a$HewF8{R8@0TKh=4v z3skFB5362QeWpfLvryxy3Dg#=)u|m-yQwy=&Qf<$k5JE1U!%TX{et>q4YG!XMxcgB zqf}$J#u<$v7REAV@mNCEa#jQDENhreVq3EL>`ZnA`x|yIdrVV9bE;;nW|3x{=5fsd z4#u(I@HyF>O3oq94bFQl11&!-vDRv>X03j$H`;pIzS?5#a_tuF>)P*iaGgM%ES>c_ zZ94aL3A#4AQM!e?+jY<CKGS3CdFcuD%JmNE-O)$&ZS<q{7wYfU@6jJOFf<4@kQr<- zIAie4kYng;m}$7t@Py&05zA=0k;G`D(Mh8xxF+t0XX7<^7d~dJZyaK*G~Q+0Ydm3M zX)@cS#H7XKzA4R=Yno=d(X`Wa%*@Cv+^pEF$?T3f)tqadVZPbC+x(4%rA3^@N{cp& z$Clcbe9HxvO_ukpm{vYkc~<pS*Q`m_T<a|BZPr(8P#ag944XQe%eJVko2|rln{D3| z;uMc5(kb;*ZrU;I{Ok(sn(PMcIrd@pCH8Ih&mGJh5*^k%bUS=<bal*jY;e5mq~SEf zsl=(n=~rhPXQ6YQ^EDTyOOVSFmv)yIQ*Eb;r*5Bm%a!FC?z+;o)Agg9yPMpt*=^L_ z%ss_@tNTqZn;Xep!#(do^zips;&II5ou`|p!t;>lFJ5+DSzi0S9#6BJCZ5(XZOGfi zTj0IRdtf>~J!SgN=>tB-J_4V5pNGDtz9Qc}z9W9tewls;{GR(e`pf-~_`l(K@)q$< z1z-We0p$U`ff|9c18V~x1epY-2Q>wa1-k|>3_cY?3<(WcA99m#z!&lx`C~KOXDpi0 z70L*m6<QnmFw7=Q9@Y_#hR+D!5Pol_`Aq4|wg`yeM{J0=A88qx7x{e@DJn9mF6vRV zQ*?23_bk?|<XQV?y^isZsf@Wh+iJFQc4w?=Y*K7v?3=iNxT?5;c!&5!@s|>G6C?@k ziR8rC#65}Qa{}jVnlqf_npBo_W3J`gqPZ95>CVfZcRX1&S&)1<g_shTvOnd6AVN?t z7*FM=ZcQB%@`Rg(Pes0>jiOPpx423?lIEROmG(H@JAFg?XogQlb;dIZPf{y+kr|S? zBlAsGMAqJ{&)IR=Ejg5&l$@hd4QZCNE7vf$D7Q~$D=U)?<ay?8${Ul1%J<|W`E&Ez z6>Nn}(WA6du22pZOfRS_cv~1-c(_QtNLti0-)8>m`6CO07JR*suu!<Lv)H(JS@GZ^ zzeT$iBa2fPcP=qqQo3Y#Y4Fm0%V^88mi<uTSW;E;YI)r9j#7itrKLkFf>$(^sg%jf zZm#rNxnmV!m1I@#YM0epR(~oNm0zrItf;Q|utvD%;#W>z)qM4NZQ9!2O1H}G>qzUQ z>u#*~S--DJy=p<#(1!30tsC);<r`mZO5Sv#dTRBK&9u$R%>y-IHSJr>wyfLop*ExT zdYyk=%U1oZtGB+{Cfe4&-FJKQ4uc&PJKpb<?7X!rcvow^MSb;d((Z!Yj~Zedy1(Xr z-MB}0PsN^(d!>5^_C@dOYIJXG+^@gCvI%WcHjN%gI&kHifN$EH?V5MBa9S!3!a?Q1 zC*P)gd*e{(q0YnH!_D8Bf4B7r>qvPk(mKC&tSzH$pgp0z@92!9ogH2sN4~fJe(y2k zV|B+hk5`_cohUu=`Q(C=<ELb&o}ErVJ=B@pdG}2GnQL89UA<>R&z?UQbnZ;IU-!xL z-sg{9@Vs#JBKKn3CAUkhJ+3`ResKNaNUvLO>t*-L?N>ambo5Q@JJIjcfBI^`)pOVQ z*DhV3dA;w(>>IakCfyvkCA#(acJ}QTcM9%I++BK)c(44v+WqPW`VZ=VwEnSWz-{38 zV8CF{!&wjS4he^z{*?dIhvCvk%tzHDMk9@nogW_?4H~`jWX_Y}r?RIL&&qyQ|9R_k ztLNYS;`>X_Sp3-V3;B!Bzpi<y^K$R2sjoW6BgY@S&UroYru?nW+kNl2@4DZ|y&st< z{6PLt^U?Za$EVOw_de%*{`@cZg!B7=IVBMQ000SaNLh0L01FcU01FcV0GgZ_00007 zbV*G`2ipY;5-k9fL}SbV01SIcL_t(o!?l=sd{kAI$A9;}_o^zjrz)u;`yL1(1Ohfu zngK*Z0MimdQ9y)lQRzYbI3LmebdRIh+D<Fe+R^S$H-aMTfU-ouVUbM;i!?+aD`X{W zWvNP4Dz&}k&L0I45ko68_mBF#dUb#Aee2$H&OPUlv{yUv-N7-LDvHGM3<N_Cj>?26 zk}TlP27l9c$`qM!GRK9l6+&+*BZM(VWQ7Ab0F)>SqdytqW~D-CW>-yN^&Yd|r4UNM zZYg7o02mwB@-OM9cuu?%f?GfUc)IL^_qRPcx~&`lr$|GHpU-=xWcFf%y8jNh;}#IN zHHE>UR+m%i#vPAaK!}_GK%v}i#lzw>S}hbt{=XoCoEiXOLy5zt5R%pZ_YevQ0TfCB zDD;|b67qxQiR&vdIOm27_ER7VtM<&fu#Ew4?tancb;yKcAcQdXy{A1l<(*_}1Ay0N z{pLCoZoCM)@lS!sYyC%r=##0CHvaNP(?ij;XYe2A+dai8-GehHryp@RP+5t)6Ax*G zK=|ggcvoSf^F{)#YGBVZQ#U*@_eVesn4_VyzCL5s{#El*m({OdJjbGQg?}=sLJuVO z<lC>gL+?OTV<S$UL_=q6K-2&j8R?y$;fU7-2Dw#yX#Ju`hTE$x+TI@l!9Ta0HB{Hn zeZ1TI5u#>iB-XB9IA?^t8bF&*0NBJ~p72Z+FNq=s24IeGX4)D6=mju_t6l*BN2L^N z{gx#U=Ej}7&^GSjwR?U91kveWi<T9p$YA&nz%U}FYWFi!OXfaR(QA71>oM8ZzBwr_ z0HRDe4k1xUu(Yn6^#XtdEj!<%InWYK2wO9M!NF%I=Ejv@Xd63!-A-RfH-w$u3?VZR z;O-PvhMgxETi)^u#y|*$+pF?Z${Gejo2qgP;s?@Aq{Wp42nr};yf<h_&`Z-|{g=Bl z0DQdg(MjpY7z1NivGaqFq#D{zZ$7|eg#mbes*W*q^(!xIe{XSq#NzxlY0-5X7R~*l z@)y+&i&QFY{xEfhtqGkXPkBJL=vcnJN3U<pOSv>-;?AF^9Sfr$ubX_;m2_KA;lJnl z2)iR8M5jV)pZvzYH-;HI3rFq&*sM{d_h%k$Z7V7i<_$M1)twyANeZKp^7!K67c(;7 znP9lgalvq?I8i_Omz(}O{O<54Az<vE*ba^oLdc$q;E9VZZOvEakLU%keA}9hUoQzG zs#I>XsajFgl!_cx2mwb~C=|u>KC`KU<AUM$m0p~?c*9o4NI^pPlUeOEl3X_ik{?_N z0>(fT1^}DR`cib>qRha(F&?YXSKXD>@0>=+$JaExH!|`}AYkwBH^{QLuWtm;yN$-C z!6+%qYDatVeRd%;`bu6@fDmk{)80O*2@_m9L;+I-&Cg01o2_|iYy0eB7e*RdqN1G& zqXdi)W;E97^>5eJz0%ee83^oXZhk5&>ypK?elV7M`ZKc)+LZLR6I~H&Ys{{IP}8Ry zVmq!wFvbX(*znbo9e-pAF#`!N3!fg1=sj`#o)7l5j*pUPetiBD<WHh#N=)2rw;!am zUzUx*U<@I~U@)1|a~vm1lB%g`smGHeN!q=QDJMHDtpof`26yW;(K6*l0F02V&Wg?J z=4c$P<jUnkQ-7YUD;ptvo|{;{!~d{PR^FQPf|0jtG$O}E$a1RRKd!dc<8-zN0?(L} z=LL->%je5elqf-<CR20H@V{oo9c^-^_IPa?LF746Qute#Bw-AMWUg$B)H-{-(MzuU z{kMBxB_fpy`G%LGRKtVjfCp~rDofEA0ydq4F~;#|x%yyB%TqkxU0JzG5TZh%UXQ0D zE$vC0ZH7wKl$^ZUY_66SLJ0%7uKp;e&qBbgy6&>3X{(O?CkRvX!BCJXicTbISpfi2 z@cx-?i;8&Kt<y7E;W$Zdsl=D(;q(C<Pa$at6dAsN!1FRCN+_fag`yOtpW|p=-UpNl zRaLL^ytTi-kui@()5mcNV+e_Y!iZiQ;y6$WuNRq_C@Q+P09UUf5E%33sgknBOrDeY zpcHwwdYWE)B*QLQdwZ%Qvz>8LHec(PAQ=cRLU2<ebD*Nas36de_RRM7xs-N?LRE_5 zkBAtiR>v}Cv{)vo)gAHiTMdSOS)l|XW5Qs1A&RhA(A1ks2%|*d^Z}i|Hz<3;hC&AG zj#-tZfBx+0E#n?nEe+-0Uq*UZY-hXQp!qVY(9s{0X{*bzN*w2RyK_CByEx8QUj9{I zUyzWHEcd6SjZR9+rPO0KpV4R>iXznX(JNia36aeLr-UTls_Xfxe(Il(thh~_5IGeC z9zC~#oWtVBw@$Cx``Eel0j=@#S65!t#ZI?2Y13=`{>0SOzhr0s3IJp8A3N62-Mub9 zza%g3u*I@WQ4E(auW-30P#WCdn0&g^R_DG=W)%+SJOCAwLWB?SY5)XafLaWM%N}j0 zZ+>#)oHSvei(T|KKbTXZ)n2`p1u9y`EQDw!$x29w5JqW#T--*xeOI45Ynr%Vk}Y_k zRkyt{atMfUc;zWU2z->D&Yzuuk#C;7<k~7_T#6f$Z*$crKEx*{+cFYY*G9K@<B^G# zR_oUQ{Qel1Ym(7;Ha7OO*Xv45{Lt@Db~x_0+YcIzwE*<`x*eB_ue2vF7<nPt=q>9s zo_3gqikKWFip<8v();F)XBcnpl%mT0az()VvxnN^W(o}Ih~&Mc&Xu$N_;B9lu*N%( zTwnjMxw*fIiM`m=q$DJkb~)a5xklS;Uxu?$mC8LLb;IAzPi*s#T9H>Z(lQXE4ee}< z{=uY%fdLqhDP!zlRiM`^zf!2rjTe$k<}uN>FDuNDv1i$u`Qz7p8{oKrO68K}2vG!M z5JgIeEC}wws);eo$}Y`MDXVdlcQ3|otBdOJssGu6xV~5ZuS4Dqi_C94U?@2{@a{3O z#icBrHqUOT4u}1HRYg?|^CsC@X<f#23sn(Cl6j6Ymr%C#((f26IqfhTEQc2U>|=nv zeBbNOe!8}zH@>3x+fv~6M|rfK0I2DbZ3g;HtJva_?S>u=f0&S(@Dd!TnR%+VsIPC# zS%<B~mB1J;$rOOYLr%9Rb#_j#xmx(z7jNyYc#tvV#9dgk;87JPg_{UNoE_hRaQPSj zor(Y?C5qRp1FMRkHbuAr<I&3ncfC`w`%>|!*!n}AT%$)$h-?NV5JHHY6I;>Y$AJ#m zObq~@|LpJks)`sxT2x(j>^A^pg&U#}qG38-5{W2ksq*SfgVQIczvf7_a)+Kfes@Y4 z5vNo(fAiFq^?km`;v~O@W7``n05}Q&0w*$tE8QajIQ;5i5sVTB;Mq?<oUp3W6EJQ2 z<pbdwi81nni7pQYz$NiarJ8@Y;qhGVe0>N&Roh`Jf0nV2nCgfZaSB6TWX}VsO|@?Q z^=uS`KpUYn^rXGG^F08rkeqJvKbGzYPjC)cKfg2wz}{t3C#4_xwru=9L{K3BCe|H6 zX=$jwX~7oX;YJZaOk~YxRXMvZJw^^!nNJ=C5aKkYP0`2OO@r02EJKnI5H<Y)9e^wD zh)-(ly@7ALM=QVhL+)GkmF+pRM{mE4cO<!*{;gy#fD^-~EBE|*hPUfN!uYDvQEh&= z*|&D~&gINL63-m2=+Rg7=m(V+U2jMYvl(%b9U37JF2cU*h`h-Qd?DQ<AMF{sGUfp+ zJ^9y8V@!)Vaa!&Edu#WDkOhl(Ed2W8nU$XdIG#2&$=O&~vv=Q!SvM*_D}QYHUEd5F z#&%Ra5hfUX_xHVE=*pOkd#U>D+gT@4CqMVdhf7YaCSWrwc6FNKj;BqD@4H%_aMzin zdyc<5w$Ykau)ORh@qy(NQ={rLR(6Dqj{Veb3IFoJ-xI*<bM~u^B~xAmpbHHwIrX>q zroOc1o?nM2ZOvOa@BGH1ik-Vh6@N!eWdKHv$L%+<JLuQ&bIUiko8nd!mki$0h<*TS zDL8oN--}lHg@|{zFXI$x*XW0DJct1hqTFexh5&8mgj!qH@UH5eA5P!3x?tY<O`l9y zdT;IiGpk0e-84Va=LGO+-U0vx)&KLI#u;_j*K@(Zoi@&R0HfM3Y+g4zzON<L-4-^f z-8sbz&aSf#^h~Zhyl&$>kH%#8bTFX96nmrC>5Hd|88F--1Q99ED-r_;uq|)F9|~Tx z4)nOR7C{z8PDpe$?_6DQy+Fbz6Q2Bi;TwbEgveHbYMWga`OY@ve*q)0+F-Ft6~6!g N002ovPDHLkV1jB0Z!!P? literal 0 HcmV?d00001 diff --git a/ios/rmlsend/MainWindow.xib b/ios/rmlsend/MainWindow.xib new file mode 100644 index 00000000..c3ded963 --- /dev/null +++ b/ios/rmlsend/MainWindow.xib @@ -0,0 +1,444 @@ +<?xml version="1.0" encoding="UTF-8"?> +<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10"> + <data> + <int key="IBDocument.SystemTarget">1024</int> + <string key="IBDocument.SystemVersion">10D571</string> + <string key="IBDocument.InterfaceBuilderVersion">786</string> + <string key="IBDocument.AppKitVersion">1038.29</string> + <string key="IBDocument.HIToolboxVersion">460.00</string> + <object class="NSMutableDictionary" key="IBDocument.PluginVersions"> + <string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + <string key="NS.object.0">112</string> + </object> + <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> + <bool key="EncodedWithXMLCoder">YES</bool> + <integer value="10"/> + </object> + <object class="NSArray" key="IBDocument.PluginDependencies"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + </object> + <object class="NSMutableDictionary" key="IBDocument.Metadata"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys" id="0"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBProxyObject" id="841351856"> + <string key="IBProxiedObjectIdentifier">IBFilesOwner</string> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + </object> + <object class="IBProxyObject" id="427554174"> + <string key="IBProxiedObjectIdentifier">IBFirstResponder</string> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + </object> + <object class="IBUICustomObject" id="664661524"> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + </object> + <object class="IBUIViewController" id="943309135"> + <string key="IBUINibName">RMLSendViewController</string> + <object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/> + <object class="IBUISimulatedOrientationMetrics" key="IBUISimulatedOrientationMetrics"> + <int key="interfaceOrientation">1</int> + </object> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + <bool key="IBUIHorizontal">NO</bool> + </object> + <object class="IBUIWindow" id="117978783"> + <nil key="NSNextResponder"/> + <int key="NSvFlags">292</int> + <string key="NSFrameSize">{320, 480}</string> + <object class="NSColor" key="IBUIBackgroundColor"> + <int key="NSColorSpace">1</int> + <bytes key="NSRGB">MSAxIDEAA</bytes> + </object> + <bool key="IBUIOpaque">NO</bool> + <bool key="IBUIClearsContextBeforeDrawing">NO</bool> + <object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + <bool key="IBUIResizesToFullScreen">YES</bool> + </object> + </object> + <object class="IBObjectContainer" key="IBDocument.Objects"> + <object class="NSMutableArray" key="connectionRecords"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBConnectionRecord"> + <object class="IBCocoaTouchOutletConnection" key="connection"> + <string key="label">delegate</string> + <reference key="source" ref="841351856"/> + <reference key="destination" ref="664661524"/> + </object> + <int key="connectionID">4</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBCocoaTouchOutletConnection" key="connection"> + <string key="label">viewController</string> + <reference key="source" ref="664661524"/> + <reference key="destination" ref="943309135"/> + </object> + <int key="connectionID">11</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBCocoaTouchOutletConnection" key="connection"> + <string key="label">window</string> + <reference key="source" ref="664661524"/> + <reference key="destination" ref="117978783"/> + </object> + <int key="connectionID">14</int> + </object> + </object> + <object class="IBMutableOrderedSet" key="objectRecords"> + <object class="NSArray" key="orderedObjects"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBObjectRecord"> + <int key="objectID">0</int> + <reference key="object" ref="0"/> + <reference key="children" ref="1000"/> + <nil key="parent"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-1</int> + <reference key="object" ref="841351856"/> + <reference key="parent" ref="0"/> + <string key="objectName">File's Owner</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">3</int> + <reference key="object" ref="664661524"/> + <reference key="parent" ref="0"/> + <string key="objectName">RMLSend App Delegate</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-2</int> + <reference key="object" ref="427554174"/> + <reference key="parent" ref="0"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">10</int> + <reference key="object" ref="943309135"/> + <reference key="parent" ref="0"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">12</int> + <reference key="object" ref="117978783"/> + <reference key="parent" ref="0"/> + </object> + </object> + </object> + <object class="NSMutableDictionary" key="flattenedProperties"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>-1.CustomClassName</string> + <string>-2.CustomClassName</string> + <string>10.CustomClassName</string> + <string>10.IBEditorWindowLastContentRect</string> + <string>10.IBPluginDependency</string> + <string>12.IBEditorWindowLastContentRect</string> + <string>12.IBPluginDependency</string> + <string>3.CustomClassName</string> + <string>3.IBPluginDependency</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>UIApplication</string> + <string>UIResponder</string> + <string>RMLSendViewController</string> + <string>{{234, 376}, {320, 480}}</string> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + <string>{{525, 346}, {320, 480}}</string> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + <string>RMLSendAppDelegate</string> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + </object> + </object> + <object class="NSMutableDictionary" key="unlocalizedProperties"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference key="dict.sortedKeys" ref="0"/> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <nil key="activeLocalization"/> + <object class="NSMutableDictionary" key="localizations"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference key="dict.sortedKeys" ref="0"/> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <nil key="sourceID"/> + <int key="maxID">15</int> + </object> + <object class="IBClassDescriber" key="IBDocument.Classes"> + <object class="NSMutableArray" key="referencedPartialClassDescriptions"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBPartialClassDescription"> + <string key="className">UIWindow</string> + <string key="superclassName">UIView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBUserSource</string> + <string key="minorKey"/> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">RMLSendAppDelegate</string> + <string key="superclassName">NSObject</string> + <object class="NSMutableDictionary" key="outlets"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>viewController</string> + <string>window</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>RMLSendViewController</string> + <string>UIWindow</string> + </object> + </object> + <object class="NSMutableDictionary" key="toOneOutletInfosByName"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>viewController</string> + <string>window</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBToOneOutletInfo"> + <string key="name">viewController</string> + <string key="candidateClassName">RMLSendViewController</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">window</string> + <string key="candidateClassName">UIWindow</string> + </object> + </object> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">Classes/RMLSendAppDelegate.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">RMLSendAppDelegate</string> + <string key="superclassName">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBUserSource</string> + <string key="minorKey"/> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">RMLSendViewController</string> + <string key="superclassName">UIViewController</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">Classes/RMLSendViewController.h</string> + </object> + </object> + </object> + <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSError.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSObject.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSThread.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSURL.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIAccessibility.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UINibLoading.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier" id="356479594"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIResponder.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIApplication</string> + <string key="superclassName">UIResponder</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIApplication.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIResponder</string> + <string key="superclassName">NSObject</string> + <reference key="sourceIdentifier" ref="356479594"/> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UISearchBar</string> + <string key="superclassName">UIView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UISearchBar.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UISearchDisplayController</string> + <string key="superclassName">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UISearchDisplayController.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UITextField.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIView</string> + <string key="superclassName">UIResponder</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIView.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIViewController</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UINavigationController.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIViewController</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIPopoverController.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIViewController</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UISplitViewController.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIViewController</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UITabBarController.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIViewController</string> + <string key="superclassName">UIResponder</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIViewController.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIWindow</string> + <string key="superclassName">UIView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIWindow.h</string> + </object> + </object> + </object> + </object> + <int key="IBDocument.localizationMode">0</int> + <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string> + <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults"> + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string> + <integer value="1024" key="NS.object.0"/> + </object> + <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies"> + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string> + <integer value="3100" key="NS.object.0"/> + </object> + <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool> + <string key="IBDocument.LastKnownRelativeProjectPath">RMLSend.xcodeproj</string> + <int key="IBDocument.defaultPropertyAccessControl">3</int> + <string key="IBCocoaTouchPluginVersion">112</string> + </data> +</archive> diff --git a/ios/rmlsend/Makefile.am b/ios/rmlsend/Makefile.am new file mode 100644 index 00000000..39a0c481 --- /dev/null +++ b/ios/rmlsend/Makefile.am @@ -0,0 +1,48 @@ +## automake.am +## +## Automake.am for rivendell/ios/rmlsend +## +## (C) Copyright 2011 Fred Gleason <fredg@paravelsystems.com> +## +## $Id: Makefile.am,v 1.1.6.1 2012/11/29 01:37:35 cvs Exp $ +## +## 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. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +SUBDIRS = Classes\ + RMLSend.xcodeproj + +EXTRA_DIST = Icon.png\ + main.m\ + MainWindow.xib\ + RMLSend-Info.plist\ + RMLSend_Prefix.pch\ + RMLSendViewController.xib + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/ios/rmlsend/RMLSend-Info.plist b/ios/rmlsend/RMLSend-Info.plist new file mode 100644 index 00000000..17d09c2c --- /dev/null +++ b/ios/rmlsend/RMLSend-Info.plist @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleDisplayName</key> + <string>${PRODUCT_NAME}</string> + <key>CFBundleExecutable</key> + <string>${EXECUTABLE_NAME}</string> + <key>CFBundleIconFile</key> + <string>Icon.png</string> + <key>CFBundleIdentifier</key> + <string>org.rivendellaudio.rmlsend</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>${PRODUCT_NAME}</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.0</string> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>NSMainNibFile</key> + <string>MainWindow</string> +</dict> +</plist> diff --git a/ios/rmlsend/RMLSend.xcodeproj/Makefile.am b/ios/rmlsend/RMLSend.xcodeproj/Makefile.am new file mode 100644 index 00000000..054d1db9 --- /dev/null +++ b/ios/rmlsend/RMLSend.xcodeproj/Makefile.am @@ -0,0 +1,40 @@ +## automake.am +## +## Automake.am for rivendell/ios/rmlsend/RMLSend.xcodeproj +## +## (C) Copyright 2011 Fred Gleason <fredg@paravelsystems.com> +## +## $Id: Makefile.am,v 1.1.6.1 2012/11/29 01:37:35 cvs Exp $ +## +## 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. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +EXTRA_DIST = project.pbxproj + +CLEANFILES = *~\ + *.idb\ + *.ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/ios/rmlsend/RMLSend.xcodeproj/project.pbxproj b/ios/rmlsend/RMLSend.xcodeproj/project.pbxproj new file mode 100755 index 00000000..5aff7b91 --- /dev/null +++ b/ios/rmlsend/RMLSend.xcodeproj/project.pbxproj @@ -0,0 +1,269 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 1D3623260D0F684500981E51 /* RMLSendAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* RMLSendAppDelegate.m */; }; + 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; + 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; + 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765A40DF7441C002DB57D /* CoreGraphics.framework */; }; + 2899E5220DE3E06400AC0155 /* RMLSendViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2899E5210DE3E06400AC0155 /* RMLSendViewController.xib */; }; + 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD733E0D9D9553002E5188 /* MainWindow.xib */; }; + 28D7ACF80DDB3853001CB0EB /* RMLSendViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28D7ACF70DDB3853001CB0EB /* RMLSendViewController.m */; }; + D600AA0E1289FAC100190B10 /* TextFieldDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D600AA0D1289FAC100190B10 /* TextFieldDelegate.m */; }; + D606CE90137B11CC001C17BA /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = D606CE8F137B11CC001C17BA /* Icon.png */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 1D3623240D0F684500981E51 /* RMLSendAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMLSendAppDelegate.h; sourceTree = "<group>"; }; + 1D3623250D0F684500981E51 /* RMLSendAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMLSendAppDelegate.m; sourceTree = "<group>"; }; + 1D6058910D05DD3D006BFB54 /* RMLSend.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RMLSend.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 288765A40DF7441C002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 2899E5210DE3E06400AC0155 /* RMLSendViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RMLSendViewController.xib; sourceTree = "<group>"; }; + 28AD733E0D9D9553002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = "<group>"; }; + 28D7ACF60DDB3853001CB0EB /* RMLSendViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMLSendViewController.h; sourceTree = "<group>"; }; + 28D7ACF70DDB3853001CB0EB /* RMLSendViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMLSendViewController.m; sourceTree = "<group>"; }; + 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; + 32CA4F630368D1EE00C91783 /* RMLSend_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMLSend_Prefix.pch; sourceTree = "<group>"; }; + 8D1107310486CEB800E47090 /* RMLSend-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "RMLSend-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = "<group>"; }; + D600AA0C1289FAC100190B10 /* TextFieldDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextFieldDelegate.h; sourceTree = "<group>"; }; + D600AA0D1289FAC100190B10 /* TextFieldDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TextFieldDelegate.m; sourceTree = "<group>"; }; + D606CE8F137B11CC001C17BA /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, + 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, + 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + 1D3623240D0F684500981E51 /* RMLSendAppDelegate.h */, + 1D3623250D0F684500981E51 /* RMLSendAppDelegate.m */, + 28D7ACF60DDB3853001CB0EB /* RMLSendViewController.h */, + 28D7ACF70DDB3853001CB0EB /* RMLSendViewController.m */, + D600AA0C1289FAC100190B10 /* TextFieldDelegate.h */, + D600AA0D1289FAC100190B10 /* TextFieldDelegate.m */, + ); + path = Classes; + sourceTree = "<group>"; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 1D6058910D05DD3D006BFB54 /* RMLSend.app */, + ); + name = Products; + sourceTree = "<group>"; + }; + 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + isa = PBXGroup; + children = ( + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = CustomTemplate; + sourceTree = "<group>"; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 32CA4F630368D1EE00C91783 /* RMLSend_Prefix.pch */, + 29B97316FDCFA39411CA2CEA /* main.m */, + ); + name = "Other Sources"; + sourceTree = "<group>"; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + D606CE8F137B11CC001C17BA /* Icon.png */, + 2899E5210DE3E06400AC0155 /* RMLSendViewController.xib */, + 28AD733E0D9D9553002E5188 /* MainWindow.xib */, + 8D1107310486CEB800E47090 /* RMLSend-Info.plist */, + ); + name = Resources; + sourceTree = "<group>"; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, + 1D30AB110D05D00D00671497 /* Foundation.framework */, + 288765A40DF7441C002DB57D /* CoreGraphics.framework */, + ); + name = Frameworks; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1D6058900D05DD3D006BFB54 /* RMLSend */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "RMLSend" */; + buildPhases = ( + 1D60588D0D05DD3D006BFB54 /* Resources */, + 1D60588E0D05DD3D006BFB54 /* Sources */, + 1D60588F0D05DD3D006BFB54 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RMLSend; + productName = RMLSend; + productReference = 1D6058910D05DD3D006BFB54 /* RMLSend.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "RMLSend" */; + compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 1D6058900D05DD3D006BFB54 /* RMLSend */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 1D60588D0D05DD3D006BFB54 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */, + 2899E5220DE3E06400AC0155 /* RMLSendViewController.xib in Resources */, + D606CE90137B11CC001C17BA /* Icon.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1D60588E0D05DD3D006BFB54 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D60589B0D05DD56006BFB54 /* main.m in Sources */, + 1D3623260D0F684500981E51 /* RMLSendAppDelegate.m in Sources */, + 28D7ACF80DDB3853001CB0EB /* RMLSendViewController.m in Sources */, + D600AA0E1289FAC100190B10 /* TextFieldDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1D6058940D05DD3E006BFB54 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = RMLSend_Prefix.pch; + INFOPLIST_FILE = "RMLSend-Info.plist"; + PRODUCT_NAME = RMLSend; + }; + name = Debug; + }; + 1D6058950D05DD3E006BFB54 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = RMLSend_Prefix.pch; + INFOPLIST_FILE = "RMLSend-Info.plist"; + PRODUCT_NAME = RMLSend; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Don't Code Sign"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; + SDKROOT = iphoneos; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + PREBINDING = NO; + SDKROOT = iphoneos4.2; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "RMLSend" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1D6058940D05DD3E006BFB54 /* Debug */, + 1D6058950D05DD3E006BFB54 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "RMLSend" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/ios/rmlsend/RMLSendViewController.xib b/ios/rmlsend/RMLSendViewController.xib new file mode 100644 index 00000000..ea89b3a8 --- /dev/null +++ b/ios/rmlsend/RMLSendViewController.xib @@ -0,0 +1,732 @@ +<?xml version="1.0" encoding="UTF-8"?> +<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.10"> + <data> + <int key="IBDocument.SystemTarget">1024</int> + <string key="IBDocument.SystemVersion">10F2025</string> + <string key="IBDocument.InterfaceBuilderVersion">788</string> + <string key="IBDocument.AppKitVersion">1038.29</string> + <string key="IBDocument.HIToolboxVersion">461.00</string> + <object class="NSMutableDictionary" key="IBDocument.PluginVersions"> + <string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + <string key="NS.object.0">117</string> + </object> + <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> + <bool key="EncodedWithXMLCoder">YES</bool> + <integer value="13"/> + </object> + <object class="NSArray" key="IBDocument.PluginDependencies"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + </object> + <object class="NSMutableDictionary" key="IBDocument.Metadata"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys" id="0"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBProxyObject" id="372490531"> + <string key="IBProxiedObjectIdentifier">IBFilesOwner</string> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + </object> + <object class="IBProxyObject" id="843779117"> + <string key="IBProxiedObjectIdentifier">IBFirstResponder</string> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + </object> + <object class="IBUIView" id="774585933"> + <reference key="NSNextResponder"/> + <int key="NSvFlags">274</int> + <object class="NSMutableArray" key="NSSubviews"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBUILabel" id="928075110"> + <reference key="NSNextResponder" ref="774585933"/> + <int key="NSvFlags">292</int> + <string key="NSFrame">{{28, 66}, {93, 21}}</string> + <reference key="NSSuperview" ref="774585933"/> + <bool key="IBUIOpaque">NO</bool> + <bool key="IBUIClipsSubviews">YES</bool> + <int key="IBUIContentMode">7</int> + <bool key="IBUIUserInteractionEnabled">NO</bool> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + <string key="IBUIText">Hostname</string> + <object class="NSColor" key="IBUITextColor" id="485806178"> + <int key="NSColorSpace">1</int> + <bytes key="NSRGB">MSAxIDEAA</bytes> + <object class="NSColorSpace" key="NSCustomColorSpace" id="1045472674"> + <int key="NSID">1</int> + </object> + </object> + <nil key="IBUIHighlightedColor"/> + <int key="IBUIBaselineAdjustment">0</int> + <float key="IBUIMinimumFontSize">10</float> + </object> + <object class="IBUILabel" id="579836596"> + <reference key="NSNextResponder" ref="774585933"/> + <int key="NSvFlags">292</int> + <string key="NSFrame">{{28, 194}, {42, 21}}</string> + <reference key="NSSuperview" ref="774585933"/> + <bool key="IBUIOpaque">NO</bool> + <bool key="IBUIClipsSubviews">YES</bool> + <int key="IBUIContentMode">7</int> + <bool key="IBUIUserInteractionEnabled">NO</bool> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + <string key="IBUIText">RML</string> + <reference key="IBUITextColor" ref="485806178"/> + <nil key="IBUIHighlightedColor"/> + <int key="IBUIBaselineAdjustment">1</int> + <float key="IBUIMinimumFontSize">10</float> + </object> + <object class="IBUITextField" id="609900879"> + <reference key="NSNextResponder" ref="774585933"/> + <int key="NSvFlags">292</int> + <string key="NSFrame">{{20, 85}, {280, 31}}</string> + <reference key="NSSuperview" ref="774585933"/> + <reference key="IBUIBackgroundColor" ref="485806178"/> + <bool key="IBUIOpaque">NO</bool> + <bool key="IBUIClipsSubviews">YES</bool> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + <int key="IBUIContentVerticalAlignment">0</int> + <string key="IBUIText"/> + <int key="IBUIBorderStyle">3</int> + <object class="NSColor" key="IBUITextColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MAA</bytes> + <object class="NSColorSpace" key="NSCustomColorSpace" id="125617915"> + <int key="NSID">2</int> + </object> + </object> + <bool key="IBUIAdjustsFontSizeToFit">YES</bool> + <float key="IBUIMinimumFontSize">17</float> + <object class="IBUITextInputTraits" key="IBUITextInputTraits"> + <int key="IBUIAutocorrectionType">1</int> + <int key="IBUIKeyboardType">1</int> + <int key="IBUIReturnKeyType">9</int> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + </object> + <int key="IBUIClearButtonMode">3</int> + </object> + <object class="IBUITextField" id="733629842"> + <reference key="NSNextResponder" ref="774585933"/> + <int key="NSvFlags">292</int> + <string key="NSFrame">{{20, 148}, {60, 31}}</string> + <reference key="NSSuperview" ref="774585933"/> + <reference key="IBUIBackgroundColor" ref="485806178"/> + <bool key="IBUIOpaque">NO</bool> + <bool key="IBUIClipsSubviews">YES</bool> + <int key="IBUITag">1</int> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + <int key="IBUIContentVerticalAlignment">0</int> + <string key="IBUIText">5859</string> + <int key="IBUIBorderStyle">3</int> + <object class="NSColor" key="IBUITextColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MAA</bytes> + <reference key="NSCustomColorSpace" ref="125617915"/> + </object> + <bool key="IBUIAdjustsFontSizeToFit">YES</bool> + <float key="IBUIMinimumFontSize">17</float> + <object class="IBUITextInputTraits" key="IBUITextInputTraits"> + <int key="IBUIAutocorrectionType">1</int> + <int key="IBUIKeyboardType">4</int> + <int key="IBUIReturnKeyType">9</int> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + </object> + </object> + <object class="IBUILabel" id="811337944"> + <reference key="NSNextResponder" ref="774585933"/> + <int key="NSvFlags">292</int> + <string key="NSFrame">{{25, 129}, {42, 21}}</string> + <reference key="NSSuperview" ref="774585933"/> + <bool key="IBUIOpaque">NO</bool> + <bool key="IBUIClipsSubviews">YES</bool> + <int key="IBUIContentMode">7</int> + <bool key="IBUIUserInteractionEnabled">NO</bool> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + <string key="IBUIText">Port</string> + <reference key="IBUITextColor" ref="485806178"/> + <nil key="IBUIHighlightedColor"/> + <int key="IBUIBaselineAdjustment">1</int> + <float key="IBUIMinimumFontSize">10</float> + </object> + <object class="IBUIButton" id="1051060136"> + <reference key="NSNextResponder" ref="774585933"/> + <int key="NSvFlags">292</int> + <string key="NSFrame">{{28, 381}, {272, 37}}</string> + <reference key="NSSuperview" ref="774585933"/> + <object class="NSColor" key="IBUIBackgroundColor"> + <int key="NSColorSpace">1</int> + <bytes key="NSRGB">MC4wMDU0MzQ3ODI2MDkgNi4xNjQ3MjkwNTJlLTA1IDAuMDAxNDg5NTkzNDU1AA</bytes> + </object> + <bool key="IBUIOpaque">NO</bool> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + <int key="IBUIContentHorizontalAlignment">0</int> + <int key="IBUIContentVerticalAlignment">0</int> + <object class="NSFont" key="IBUIFont"> + <string key="NSName">Helvetica-Bold</string> + <double key="NSSize">15</double> + <int key="NSfFlags">16</int> + </object> + <int key="IBUIButtonType">1</int> + <string key="IBUINormalTitle">Send</string> + <object class="NSColor" key="IBUIHighlightedTitleColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MQA</bytes> + </object> + <object class="NSColor" key="IBUINormalTitleColor"> + <int key="NSColorSpace">1</int> + <bytes key="NSRGB">MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA</bytes> + </object> + <object class="NSColor" key="IBUINormalTitleShadowColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MC41AA</bytes> + </object> + </object> + <object class="IBUITextField" id="80918079"> + <reference key="NSNextResponder" ref="774585933"/> + <int key="NSvFlags">292</int> + <string key="NSFrame">{{20, 214}, {280, 31}}</string> + <reference key="NSSuperview" ref="774585933"/> + <reference key="IBUIBackgroundColor" ref="485806178"/> + <bool key="IBUIOpaque">NO</bool> + <bool key="IBUIClipsSubviews">YES</bool> + <int key="IBUITag">2</int> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + <int key="IBUIContentVerticalAlignment">0</int> + <string key="IBUIText"/> + <int key="IBUIBorderStyle">3</int> + <object class="NSColor" key="IBUITextColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MAA</bytes> + <reference key="NSCustomColorSpace" ref="125617915"/> + </object> + <bool key="IBUIAdjustsFontSizeToFit">YES</bool> + <float key="IBUIMinimumFontSize">17</float> + <object class="IBUITextInputTraits" key="IBUITextInputTraits"> + <int key="IBUIAutocorrectionType">1</int> + <int key="IBUIKeyboardType">1</int> + <int key="IBUIReturnKeyType">9</int> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + </object> + <int key="IBUIClearButtonMode">3</int> + </object> + <object class="IBUILabel" id="838393156"> + <reference key="NSNextResponder" ref="774585933"/> + <int key="NSvFlags">292</int> + <string key="NSFrame">{{28, 20}, {272, 31}}</string> + <reference key="NSSuperview" ref="774585933"/> + <bool key="IBUIOpaque">NO</bool> + <bool key="IBUIClipsSubviews">YES</bool> + <int key="IBUIContentMode">7</int> + <bool key="IBUIUserInteractionEnabled">NO</bool> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + <string key="IBUIText">RMLSend</string> + <object class="NSFont" key="IBUIFont"> + <string key="NSName">Helvetica-Bold</string> + <double key="NSSize">24</double> + <int key="NSfFlags">16</int> + </object> + <object class="NSColor" key="IBUITextColor"> + <int key="NSColorSpace">1</int> + <bytes key="NSRGB">MSAxIDEAA</bytes> + <reference key="NSCustomColorSpace" ref="1045472674"/> + </object> + <nil key="IBUIHighlightedColor"/> + <int key="IBUIBaselineAdjustment">1</int> + <float key="IBUIMinimumFontSize">10</float> + <int key="IBUITextAlignment">1</int> + </object> + </object> + <string key="NSFrameSize">{320, 460}</string> + <reference key="NSSuperview"/> + <object class="NSColor" key="IBUIBackgroundColor"> + <int key="NSColorSpace">1</int> + <bytes key="NSRGB">MCAwIDAAA</bytes> + </object> + <bool key="IBUIClearsContextBeforeDrawing">NO</bool> + <object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/> + <string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string> + </object> + </object> + <object class="IBObjectContainer" key="IBDocument.Objects"> + <object class="NSMutableArray" key="connectionRecords"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBConnectionRecord"> + <object class="IBCocoaTouchEventConnection" key="connection"> + <string key="label">processSend:</string> + <reference key="source" ref="1051060136"/> + <reference key="destination" ref="372490531"/> + <int key="IBEventType">7</int> + </object> + <int key="connectionID">20</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBCocoaTouchOutletConnection" key="connection"> + <string key="label">cmdline</string> + <reference key="source" ref="372490531"/> + <reference key="destination" ref="80918079"/> + </object> + <int key="connectionID">21</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBCocoaTouchOutletConnection" key="connection"> + <string key="label">view</string> + <reference key="source" ref="372490531"/> + <reference key="destination" ref="774585933"/> + </object> + <int key="connectionID">22</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBCocoaTouchOutletConnection" key="connection"> + <string key="label">delegate</string> + <reference key="source" ref="609900879"/> + <reference key="destination" ref="372490531"/> + </object> + <int key="connectionID">23</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBCocoaTouchOutletConnection" key="connection"> + <string key="label">delegate</string> + <reference key="source" ref="733629842"/> + <reference key="destination" ref="372490531"/> + </object> + <int key="connectionID">24</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBCocoaTouchOutletConnection" key="connection"> + <string key="label">ipaddr</string> + <reference key="source" ref="372490531"/> + <reference key="destination" ref="609900879"/> + </object> + <int key="connectionID">25</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBCocoaTouchOutletConnection" key="connection"> + <string key="label">udpport</string> + <reference key="source" ref="372490531"/> + <reference key="destination" ref="733629842"/> + </object> + <int key="connectionID">26</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBCocoaTouchOutletConnection" key="connection"> + <string key="label">button</string> + <reference key="source" ref="372490531"/> + <reference key="destination" ref="1051060136"/> + </object> + <int key="connectionID">27</int> + </object> + </object> + <object class="IBMutableOrderedSet" key="objectRecords"> + <object class="NSArray" key="orderedObjects"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBObjectRecord"> + <int key="objectID">0</int> + <reference key="object" ref="0"/> + <reference key="children" ref="1000"/> + <nil key="parent"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-1</int> + <reference key="object" ref="372490531"/> + <reference key="parent" ref="0"/> + <string key="objectName">File's Owner</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-2</int> + <reference key="object" ref="843779117"/> + <reference key="parent" ref="0"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">6</int> + <reference key="object" ref="774585933"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="1051060136"/> + <reference ref="928075110"/> + <reference ref="838393156"/> + <reference ref="609900879"/> + <reference ref="733629842"/> + <reference ref="811337944"/> + <reference ref="579836596"/> + <reference ref="80918079"/> + </object> + <reference key="parent" ref="0"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">9</int> + <reference key="object" ref="928075110"/> + <reference key="parent" ref="774585933"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">10</int> + <reference key="object" ref="579836596"/> + <reference key="parent" ref="774585933"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">12</int> + <reference key="object" ref="609900879"/> + <reference key="parent" ref="774585933"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">13</int> + <reference key="object" ref="733629842"/> + <reference key="parent" ref="774585933"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">14</int> + <reference key="object" ref="811337944"/> + <reference key="parent" ref="774585933"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">15</int> + <reference key="object" ref="1051060136"/> + <reference key="parent" ref="774585933"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">16</int> + <reference key="object" ref="80918079"/> + <reference key="parent" ref="774585933"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">17</int> + <reference key="object" ref="838393156"/> + <reference key="parent" ref="774585933"/> + </object> + </object> + </object> + <object class="NSMutableDictionary" key="flattenedProperties"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>-1.CustomClassName</string> + <string>-2.CustomClassName</string> + <string>10.IBPluginDependency</string> + <string>12.IBPluginDependency</string> + <string>13.IBPluginDependency</string> + <string>14.IBPluginDependency</string> + <string>15.IBPluginDependency</string> + <string>16.IBPluginDependency</string> + <string>17.IBPluginDependency</string> + <string>6.IBEditorWindowLastContentRect</string> + <string>6.IBPluginDependency</string> + <string>9.IBPluginDependency</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>RMLSendViewController</string> + <string>UIResponder</string> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + <string>{{26, 152}, {320, 480}}</string> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + <string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string> + </object> + </object> + <object class="NSMutableDictionary" key="unlocalizedProperties"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference key="dict.sortedKeys" ref="0"/> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <nil key="activeLocalization"/> + <object class="NSMutableDictionary" key="localizations"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference key="dict.sortedKeys" ref="0"/> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <nil key="sourceID"/> + <int key="maxID">27</int> + </object> + <object class="IBClassDescriber" key="IBDocument.Classes"> + <object class="NSMutableArray" key="referencedPartialClassDescriptions"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBPartialClassDescription"> + <string key="className">RMLSendViewController</string> + <string key="superclassName">UIViewController</string> + <object class="NSMutableDictionary" key="actions"> + <string key="NS.key.0">processSend:</string> + <string key="NS.object.0">id</string> + </object> + <object class="NSMutableDictionary" key="actionInfosByName"> + <string key="NS.key.0">processSend:</string> + <object class="IBActionInfo" key="NS.object.0"> + <string key="name">processSend:</string> + <string key="candidateClassName">id</string> + </object> + </object> + <object class="NSMutableDictionary" key="outlets"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>button</string> + <string>cmdline</string> + <string>ipaddr</string> + <string>udpport</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>UIButton</string> + <string>UITextField</string> + <string>UITextField</string> + <string>UITextField</string> + </object> + </object> + <object class="NSMutableDictionary" key="toOneOutletInfosByName"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>button</string> + <string>cmdline</string> + <string>ipaddr</string> + <string>udpport</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBToOneOutletInfo"> + <string key="name">button</string> + <string key="candidateClassName">UIButton</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">cmdline</string> + <string key="candidateClassName">UITextField</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">ipaddr</string> + <string key="candidateClassName">UITextField</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">udpport</string> + <string key="candidateClassName">UITextField</string> + </object> + </object> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">Classes/RMLSendViewController.h</string> + </object> + </object> + </object> + <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSError.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSObject.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSThread.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSURL.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIAccessibility.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UINibLoading.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier" id="500413017"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIResponder.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIButton</string> + <string key="superclassName">UIControl</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIButton.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIControl</string> + <string key="superclassName">UIView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIControl.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UILabel</string> + <string key="superclassName">UIView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UILabel.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIResponder</string> + <string key="superclassName">NSObject</string> + <reference key="sourceIdentifier" ref="500413017"/> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UISearchBar</string> + <string key="superclassName">UIView</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UISearchBar.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UISearchDisplayController</string> + <string key="superclassName">NSObject</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UISearchDisplayController.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UITextField</string> + <string key="superclassName">UIControl</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier" id="201513681"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UITextField.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIView</string> + <reference key="sourceIdentifier" ref="201513681"/> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIView</string> + <string key="superclassName">UIResponder</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIView.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIViewController</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UINavigationController.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIViewController</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIPopoverController.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIViewController</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UISplitViewController.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIViewController</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UITabBarController.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">UIViewController</string> + <string key="superclassName">UIResponder</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBFrameworkSource</string> + <string key="minorKey">UIKit.framework/Headers/UIViewController.h</string> + </object> + </object> + </object> + </object> + <int key="IBDocument.localizationMode">0</int> + <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaTouchFramework</string> + <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults"> + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string> + <integer value="1024" key="NS.object.0"/> + </object> + <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies"> + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3</string> + <integer value="3100" key="NS.object.0"/> + </object> + <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool> + <string key="IBDocument.LastKnownRelativeProjectPath">RMLSend.xcodeproj</string> + <int key="IBDocument.defaultPropertyAccessControl">3</int> + <string key="IBCocoaTouchPluginVersion">117</string> + </data> +</archive> diff --git a/ios/rmlsend/RMLSend_Prefix.pch b/ios/rmlsend/RMLSend_Prefix.pch new file mode 100644 index 00000000..827e56dc --- /dev/null +++ b/ios/rmlsend/RMLSend_Prefix.pch @@ -0,0 +1,25 @@ +// +// Prefix header for all source files of the 'RMLSend' target in the 'RMLSend' project +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id:$ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifdef __OBJC__ + #import <Foundation/Foundation.h> + #import <UIKit/UIKit.h> +#endif diff --git a/ios/rmlsend/main.m b/ios/rmlsend/main.m new file mode 100644 index 00000000..62e6a42a --- /dev/null +++ b/ios/rmlsend/main.m @@ -0,0 +1,30 @@ +// +// main.m +// RMLSend +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id:$ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#import <UIKit/UIKit.h> + +int main(int argc, char *argv[]) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + int retVal = UIApplicationMain(argc, argv, nil, nil); + [pool release]; + return retVal; +} diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 00000000..e1d81202 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,352 @@ +## automake.am +## +## Automake.am for rivendell/lib +## +## (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +## +## $Id: Makefile.am,v 1.132.4.15.2.3 2014/05/28 21:21:39 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" @QT_CXXFLAGS@ +MOC = @QT_MOC@ +CWRAP = ../helpers/cwrap + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# The cwrap dependency +html_%.cpp: %.html + $(CWRAP) -o $@ $< + +instdir = @LOCAL_PREFIX@/lib + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp librd_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/librd_*.qm + +all: + @QT_BIN@/lupdate lib.pro + @QT_BIN@/lrelease lib.pro + +lib_LTLIBRARIES = librd.la +dist_librd_la_SOURCES = dbversion.h\ + gpio.h\ + export_bmiemr.cpp\ + export_deltaflex.cpp\ + export_musicclassical.cpp\ + export_musicplayout.cpp\ + export_musicsummary.cpp\ + export_nprsoundex.cpp\ + export_radiotraffic.cpp\ + export_soundex.cpp\ + export_technical.cpp\ + export_textlog.cpp\ + html_gpl2.cpp\ + rdadd_cart.cpp rdadd_cart.h\ + rdadd_log.cpp rdadd_log.h\ + rdairplay_conf.cpp rdairplay_conf.h\ + rdaudio_exists.cpp rdaudio_exists.h\ + rdaudio_port.cpp rdaudio_port.h\ + rdaudioconvert.cpp rdaudioconvert.h\ + rdaudioexport.cpp rdaudioexport.h\ + rdaudioimport.cpp rdaudioimport.h\ + rdaudioinfo.cpp rdaudioinfo.h\ + rdaudiosettings_dialog.cpp rdaudiosettings_dialog.h\ + rdaudiosettings.cpp rdaudiosettings.h\ + rdbusybar.cpp rdbusybar.h\ + rdbusydialog.cpp rdbusydialog.h\ + rdbutton_dialog.cpp rdbutton_dialog.h\ + rdbutton_panel.cpp rdbutton_panel.h\ + rdcae.cpp rdcae.h\ + rdcardselector.cpp rdcardselector.h\ + rdcart.cpp rdcart.h\ + rdcart_dialog.cpp rdcart_dialog.h\ + rdcart_search_text.cpp rdcart_search_text.h\ + rdcartdrag.cpp rdcartdrag.h\ + rdcartslot.cpp rdcartslot.h\ + rdcastsearch.cpp rdcastsearch.h\ + rdcatch_conf.cpp rdcatch_conf.h\ + rdcatch_connect.cpp rdcatch_connect.h\ + rdcddblookup.cpp rdcddblookup.h\ + rdcddbrecord.cpp rdcddbrecord.h\ + rdcdplayer.cpp rdcdplayer.h\ + rdcdripper.cpp rdcdripper.h\ + rdcheck_daemons.cpp rdcheck_daemons.h\ + rdcheck_version.cpp rdcheck_version.h\ + rdclock.cpp rdclock.h\ + rdcmd_cache.cpp rdcmd_cache.h\ + rdcmd_switch.cpp rdcmd_switch.h\ + rdcodetrap.cpp rdcodetrap.h\ + rdcombobox.cpp rdcombobox.h\ + rdconf.cpp rdconf.h\ + rdconfig.cpp rdconfig.h\ + rdcopyaudio.cpp rdcopyaudio.h\ + rdcreate_log.cpp rdcreate_log.h\ + rdcreateauxfieldstable.cpp rdcreateauxfieldstable.h\ + rdcueedit.cpp rdcueedit.h\ + rdcueeditdialog.cpp rdcueeditdialog.h\ + rdcut.cpp rdcut.h\ + rdcut_dialog.cpp rdcut_dialog.h\ + rdcut_path.cpp rdcut_path.h\ + rddatedecode.cpp rddatedecode.h\ + rddatedialog.cpp rddatedialog.h\ + rddatepicker.cpp rddatepicker.h\ + rddb.h rddb.cpp\ + rddbheartbeat.cpp rddbheartbeat.h\ + rddebug.cpp rddebug.h\ + rddeck.cpp rddeck.h\ + rddelete.cpp rddelete.h\ + rddownload.cpp rddownload.h\ + rddropbox.cpp rddropbox.h\ + rdedit_audio.cpp rdedit_audio.h\ + rdedit_panel_name.cpp rdedit_panel_name.h\ + rdemptycart.cpp rdemptycart.h\ + rdencoder.cpp rdencoder.h\ + rdencoderlist.cpp rdencoderlist.h\ + rdescape_string.cpp rdescape_string.h\ + rdevent.cpp rdevent.h\ + rdevent_line.cpp rdevent_line.h\ + rdevent_player.cpp rdevent_player.h\ + rdexception_dialog.cpp rdexception_dialog.h\ + rdexport_settings_dialog.cpp rdexport_settings_dialog.h\ + rdfeed.cpp rdfeed.h\ + rdfeedlog.cpp rdfeedlog.h\ + rdformpost.cpp rdformpost.h\ + rdflacdecode.cpp rdflacdecode.h\ + rdgain_envelope.cpp rdgain_envelope.h\ + rdget_ath.cpp rdget_ath.h\ + rdgetpasswd.cpp rdgetpasswd.h\ + rdgpio.cpp rdgpio.h\ + rdgpioselector.cpp rdgpioselector.h\ + rdgrid.cpp rdgrid.h\ + rdgroup.cpp rdgroup.h\ + rdgroup_list.cpp rdgroup_list.h\ + rdhotkeys.cpp rdhotkeys.h\ + rdhotkeylist.cpp rdhotkeylist.h\ + rdidvalidator.cpp rdidvalidator.h\ + rdimport_audio.cpp rdimport_audio.h\ + rdinstancelock.cpp rdinstancelock.h\ + rdintegeredit.cpp rdintegeredit.h\ + rdintegerdialog.cpp rdintegerdialog.h\ + rd.h\ + rdlabel.cpp rdlabel.h\ + rdlibrary_conf.cpp rdlibrary_conf.h\ + rdlicense.cpp rdlicense.h\ + rdlineedit.cpp rdlineedit.h\ + rdlistselector.cpp rdlistselector.h\ + rdlist_groups.cpp rdlist_groups.h\ + rdlist_logs.cpp rdlist_logs.h\ + rdlistsvcs.cpp rdlistsvcs.h\ + rdlistview.cpp rdlistview.h\ + rdlistviewitem.cpp rdlistviewitem.h\ + rdlivewire.cpp rdlivewire.h\ + rdlivewiredestination.cpp rdlivewiredestination.h\ + rdlivewiresource.cpp rdlivewiresource.h\ + rdlog.cpp rdlog.h\ + rdlogedit_conf.cpp rdlogedit_conf.h\ + rdlog_event.cpp rdlog_event.h\ + rdlog_line.cpp rdlog_line.h\ + rdmacro.cpp rdmacro.h\ + rdmacro_event.cpp rdmacro_event.h\ + rdmarker_bar.cpp rdmarker_bar.h\ + rdmarker_button.cpp rdmarker_button.h\ + rdmarker_edit.cpp rdmarker_edit.h\ + rdmatrix.cpp rdmatrix.h\ + rdmeteraverage.cpp rdmeteraverage.h\ + rdmixer.cpp rdmixer.h\ + rdmonitor_config.cpp rdmonitor_config.h\ + rdnownext.cpp rdnownext.h\ + rdoneshot.cpp rdoneshot.h\ + rdpam.cpp rdpam.h\ + rdpanel_button.cpp rdpanel_button.h\ + rdpasswd.cpp rdpasswd.h\ + rdpaths.h\ + rdplay_deck.cpp rdplay_deck.h\ + rdplaymeter.cpp rdplaymeter.h\ + rdpeaksexport.cpp rdpeaksexport.h\ + rdpodcast.cpp rdpodcast.h\ + rdprofile.cpp rdprofile.h\ + rdprofileline.cpp rdprofileline.h\ + rdprofilesection.cpp rdprofilesection.h\ + rdpushbutton.cpp rdpushbutton.h\ + rdrecording.cpp rdrecording.h\ + rdreplicator.cpp rdreplicator.h\ + rdreport.cpp rdreport.h\ + rdringbuffer.cpp rdringbuffer.h\ + rdripc.cpp rdripc.h\ + rdschedcodes_dialog.cpp rdschedcodes_dialog.h\ + rdsegmeter.cpp rdsegmeter.h\ + rdsettings.cpp rdsettings.h\ + rdsimpleplayer.cpp rdsimpleplayer.h\ + rdslider.cpp rdslider.h\ + rdslotbox.cpp rdslotbox.h\ + rdslotdialog.cpp rdslotdialog.h\ + rdslotoptions.cpp rdslotoptions.h\ + rdsocket.cpp rdsocket.h\ + rdsound_panel.cpp rdsound_panel.h\ + rdstation.cpp rdstation.h\ + rdstatus.cpp rdstatus.h\ + rdstereometer.cpp rdstereometer.h\ + rdstringlist.cpp rdstringlist.h\ + rdsvc.cpp rdsvc.h\ + rdsystem.cpp rdsystem.h\ + rdsystemuser.cpp rdsystemuser.h\ + rdtextfile.cpp rdtextfile.h\ + rdtextvalidator.cpp rdtextvalidator.h\ + rdtimeedit.cpp rdtimeedit.h\ + rdtimeengine.cpp rdtimeengine.h\ + rdtimeevent.cpp rdtimeevent.h\ + rdtransportbutton.cpp rdtransportbutton.h\ + rdtrimaudio.cpp rdtrimaudio.h\ + rdtty.cpp rdtty.h\ + rdttydevice.cpp rdttydevice.h\ + rdttyout.cpp rdttyout.h\ + rdurl.cpp rdurl.h\ + rduser.cpp rduser.h\ + rdupload.cpp rdupload.h\ + rdversion.cpp rdversion.h\ + rdwavedata.cpp rdwavedata.h\ + rdwavedata_dialog.cpp rdwavedata_dialog.h\ + rdwavefile.cpp rdwavefile.h\ + rdwavepainter.cpp rdwavepainter.h\ + rdweb.cpp rdweb.h\ + rdwebresult.cpp rdwebresult.h\ + rdxport_interface.h\ + schedruleslist.cpp schedruleslist.h\ + schedcartlist.cpp schedcartlist.h + + +nodist_librd_la_SOURCES = moc_rdadd_cart.cpp\ + moc_rdadd_log.cpp\ + moc_rdaudioconvert.cpp\ + moc_rdaudioexport.cpp\ + moc_rdaudioimport.cpp\ + moc_rdaudioinfo.cpp\ + moc_rdaudiosettings_dialog.cpp\ + moc_rdbusybar.cpp\ + moc_rdbusydialog.cpp\ + moc_rdbutton_dialog.cpp\ + moc_rdcae.cpp\ + moc_rdcardselector.cpp\ + moc_rdcart_dialog.cpp\ + moc_rdcartslot.cpp\ + moc_rdcatch_connect.cpp\ + moc_rdcddblookup.cpp\ + moc_rdcdplayer.cpp\ + moc_rdcdripper.cpp\ + moc_rdcodetrap.cpp\ + moc_rdcombobox.cpp\ + moc_rdcueedit.cpp\ + moc_rdcueeditdialog.cpp\ + moc_rdcut_dialog.cpp\ + moc_rddatedialog.cpp\ + moc_rddatepicker.cpp\ + moc_rddb.cpp\ + moc_rddbheartbeat.cpp\ + moc_rddelete.cpp\ + moc_rddownload.cpp\ + moc_rdedit_audio.cpp\ + moc_rdedit_panel_name.cpp\ + moc_rdemptycart.cpp\ + moc_rdevent_player.cpp\ + moc_rdexception_dialog.cpp\ + moc_rdexport_settings_dialog.cpp\ + moc_rdfeed.cpp\ + moc_rdget_ath.cpp\ + moc_rdgetpasswd.cpp\ + moc_rdgpio.cpp\ + moc_rdgpioselector.cpp\ + moc_rdhotkeys.cpp\ + moc_rdhotkeylist.cpp\ + moc_rdimport_audio.cpp\ + moc_rdintegeredit.cpp\ + moc_rdintegerdialog.cpp\ + moc_rdlabel.cpp\ + moc_rdlicense.cpp\ + moc_rdlineedit.cpp\ + moc_rdlist_groups.cpp\ + moc_rdlist_logs.cpp\ + moc_rdlistselector.cpp\ + moc_rdlistsvcs.cpp\ + moc_rdlistview.cpp\ + moc_rdlivewire.cpp\ + moc_rdmacro_event.cpp\ + moc_rdmarker_bar.cpp\ + moc_rdmarker_edit.cpp\ + moc_rdoneshot.cpp\ + moc_rdpanel_button.cpp\ + moc_rdpasswd.cpp\ + moc_rdplay_deck.cpp\ + moc_rdplaymeter.cpp\ + moc_rdpushbutton.cpp\ + moc_rdripc.cpp\ + moc_rdschedcodes_dialog.cpp\ + moc_rdsegmeter.cpp\ + moc_rdsimpleplayer.cpp\ + moc_rdslider.cpp\ + moc_rdsocket.cpp\ + moc_rdsound_panel.cpp\ + moc_rdslotbox.cpp\ + moc_rdslotdialog.cpp\ + moc_rdstereometer.cpp\ + moc_rdsvc.cpp\ + moc_rdtimeedit.cpp\ + moc_rdtimeengine.cpp\ + moc_rdtransportbutton.cpp\ + moc_rdtrimaudio.cpp\ + moc_rdupload.cpp\ + moc_rdwavedata_dialog.cpp\ + moc_schedcartlist.cpp\ + moc_schedruleslist.cpp + +librd_la_LDFLAGS = -release $(VERSION) + +EXTRA_DIST = gpl2.html\ + html_gpl2_win32.cpp\ + lib.pro\ + librd_cs.ts\ + librd_de.ts\ + librd_es.ts\ + librd_fr.ts\ + librd_nb.ts\ + librd_nn.ts\ + librd_pt_BR.ts\ + rdpaths.h.in\ + rdttydevice_win32.cpp\ + rdwin32.cpp\ + rdwin32.h + +CLEANFILES = *~\ + moc_*\ + *.lib\ + *.obj\ + *.qm + +DISTCLEANFILES = rdpaths.h + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/lib/dbversion.h b/lib/dbversion.h new file mode 100644 index 00000000..12cb5e9c --- /dev/null +++ b/lib/dbversion.h @@ -0,0 +1,32 @@ +// dbversion.h +// +// The Current Database Schema Version for Rivendell +// +// (C) Copyright 2002-2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: dbversion.h,v 1.34.4.29.2.4 2014/06/03 18:23:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef DBVERSION_H +#define DBVERSION_H + +/* + * Current Database Version + */ +#define RD_VERSION_DATABASE 239 + + +#endif // DBVERSION_H diff --git a/lib/export_bmiemr.cpp b/lib/export_bmiemr.cpp new file mode 100644 index 00000000..952b1cc6 --- /dev/null +++ b/lib/export_bmiemr.cpp @@ -0,0 +1,149 @@ +// export_bmiemr.cpp +// +// Export a Rivendell Report to BMI EMR Format +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: export_bmiemr.cpp,v 1.10.8.1.2.1 2014/03/19 23:50:20 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> +#include <rddb.h> +#include <rddatedecode.h> +#include <rdreport.h> +#include <rdcart.h> + + +bool RDReport::ExportBmiEmr(const QDate &startdate,const QDate &enddate, + const QString &mixtable) +{ + QString sql; + RDSqlQuery *q; + FILE *f; + int records=0; + QDateTime current_datetime= + QDateTime(QDate::currentDate(),QTime::currentTime()); + QString type_code; + QString usage_code; + QString station_format=stationFormat(); + +#ifdef WIN32 + QString filename=RDDateDecode(exportPath(RDReport::Windows),startdate); +#else + QString filename=RDDateDecode(exportPath(RDReport::Linux),startdate); +#endif + + // + // Station Type + // + switch(stationType()) { + case RDReport::TypeAm: + type_code="AM"; + break; + + case RDReport::TypeFm: + type_code="FM"; + break; + + default: + type_code="OT"; + break; + } + + if((f=fopen((const char *)filename,"wb"))==NULL) { + report_error_code=RDReport::ErrorCantOpen; + return false; + } + /* + sql=QString().sprintf("select EVENT_DATETIME,TITLE,ARTIST,COMPOSER,\ + LENGTH,ISRC,USAGE_CODE from `%s_SRT` \ + order by EVENT_DATETIME", + (const char *)mixtable); + */ + sql=QString("select EVENT_DATETIME,TITLE,ARTIST,COMPOSER,")+ + "LENGTH,ISRC,USAGE_CODE from `"+ + mixtable+"_SRT` order by EVENT_DATETIME"; + q=new RDSqlQuery(sql); + + // + // Write HEDR Record + // + fprintf(f,"HEDRSTA%-25s%22sFMDT \x0d\x0a", + (const char *)stationId().utf8(), + (const char *)current_datetime.toString("yyyyMMddhhmmssyyyyMMdd")); + records++; + + // + // Write FMDT Records + // + while(q->next()) { + switch((RDCart::UsageCode)q->value(6).toInt()) { + case RDCart::UsageFeature: + usage_code="F1"; + break; + + case RDCart::UsageOpen: + usage_code="TO"; + break; + + case RDCart::UsageClose: + usage_code="TC"; + break; + + case RDCart::UsageTheme: + usage_code="TT"; + break; + + case RDCart::UsageBackground: + usage_code="B "; + break; + + case RDCart::UsagePromo: + usage_code="JP"; + break; + + default: + usage_code="F1"; + break; + } + fprintf(f,"FMDT%-40s%2s%-25s%6s01%14s000000001%-40s%-40s%-40s%8s %12s%2s \x0d\x0a", + (const char *)stationId().utf8(), + (const char *)type_code.utf8(), + (const char *)station_format.utf8(), + (const char *)startdate.toString("yyyyMM"), + (const char *)q->value(0).toDateTime(). + toString("yyyyMMddhh:mm:ss"), + (const char *)q->value(1).toString().utf8(), + (const char *)q->value(2).toString().utf8(), + (const char *)q->value(3).toString().utf8(), + (const char *)QTime().addMSecs(q->value(4).toInt()). + toString("hh:mm:ss"), + (const char *)q->value(5).toString().utf8(), + (const char *)usage_code.utf8()); + records++; + } + delete q; + + // + // Write TRLR Record + // + fprintf(f,"TRLR%012d \x0d\x0a",++records); + + fclose(f); + report_error_code=RDReport::ErrorOk; + return true; +} + diff --git a/lib/export_deltaflex.cpp b/lib/export_deltaflex.cpp new file mode 100644 index 00000000..dc128834 --- /dev/null +++ b/lib/export_deltaflex.cpp @@ -0,0 +1,185 @@ +// export_deltaflex.cpp +// +// Export a Rivendell Report to CBSI DeltaFlex +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: export_deltaflex.cpp,v 1.12.6.1 2013/02/08 21:41:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +// +// CBSI Settings +// +#define CBSI_DELTAFLEX_VERSION 201 +#define CBSI_STATION_ID 1 +#define CBSI_SCHED_FLAG "C" + +#include <stdio.h> + +#include <qfile.h> +#include <qmessagebox.h> +#include <rddb.h> +#include <rddatedecode.h> +#include <rdreport.h> + + +bool RDReport::ExportDeltaflex(const QDate &startdate,const QDate &enddate, + const QString &mixtable) +{ + QString sql; + RDSqlQuery *q; + FILE *f; + QString air_fmt; + +#ifdef WIN32 + QString filename=RDDateDecode(exportPath(RDReport::Windows),startdate); +#else + QString filename=RDDateDecode(exportPath(RDReport::Linux),startdate); +#endif + + QFile file(filename); + if((f=fopen((const char *)filename,"wb"))==NULL) { + report_error_code=RDReport::ErrorCantOpen; + return false; + } + + if(useLeadingZeros()) { + air_fmt=QString().sprintf("%%0%uu",cartDigits()); + } + else { + air_fmt="%u"; + } + sql=QString().sprintf("select `%s_SRT`.LENGTH,`%s_SRT`.CART_NUMBER,\ + `%s_SRT`.EVENT_DATETIME,`%s_SRT`.EVENT_TYPE,\ + `%s_SRT`.EXT_START_TIME,`%s_SRT`.EXT_LENGTH,\ + `%s_SRT`.EXT_DATA,`%s_SRT`.EXT_EVENT_ID,\ + `%s_SRT`.EXT_ANNC_TYPE,`%s_SRT`.TITLE,\ + `%s_SRT`.EXT_CART_NAME from `%s_SRT` \ + left join CART on\ + `%s_SRT`.CART_NUMBER=CART.NUMBER\ + order by EVENT_DATETIME", + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable); + q=new RDSqlQuery(sql); + + // + // Write File Header + // + unsigned station_id=stationId().toUInt(); + if(station_id>99) { + station_id=0; + } + fprintf(f,"Air Log for CBSI %03d|%s|%02u|%05d|%s|\x0d\x0a", + CBSI_DELTAFLEX_VERSION, + (const char *)startdate.toString("yy/MM/dd"), + station_id, + q->size(), + CBSI_SCHED_FLAG); + + // + // Write Data Rows + // + QString cart_title; + QString play_length; + QString tfc_length; + QString tfc_time; + QString air_cartnum; + QString tfc_cartnum; + QString ext_data; + QString ext_annc_type; + + while(q->next()) { + if(q->value(9).toString().length()>29) { + cart_title=q->value(9).toString().left(29); + } + else { + cart_title=q->value(9).toString(); + } + if(q->value(8).toString().length()>3) { + ext_annc_type=q->value(8).toString().left(3); + } + else { + ext_annc_type=q->value(8).toString(); + } + ext_data=""; + if(q->value(6).toString().length()>0) { + if(q->value(6).toString().length()<=8) { + for(unsigned i=0;i<(8-q->value(6).toString().stripWhiteSpace().length()); + i++) { + ext_data+="0"; + } + ext_data+=q->value(6).toString().stripWhiteSpace(); + } + else { + ext_data+=q->value(6).toString().stripWhiteSpace().left(8); + } + } + if(q->value(0).toUInt()<=999000) { + play_length=QString().sprintf("%03u",q->value(0).toUInt()/1000); + } + else { + play_length=QString("999"); + } + if(q->value(5).toInt()<0) { + tfc_length="000"; + } + else { + if(q->value(5).toInt()<=999000) { + tfc_length=QString().sprintf("%03d",q->value(5).toInt()/1000); + } + else { + tfc_length=QString("999"); + } + } + if(!q->value(4).toTime().isNull()) { + tfc_time=q->value(4).toTime().toString("hhmm"); + } + else { + tfc_time=""; + } + air_cartnum=QString().sprintf(air_fmt,q->value(1).toUInt()); + tfc_cartnum=q->value(10).toString(); + + fprintf(f,"%s|%4s|%-29s|%-12s|%-12s|%s|%s|%8s|%-3s| | |%4s|\x0d\x0a", + (const char *)q->value(2).toDateTime().toString("hhmm"), + (const char *)tfc_time, + (const char *)cart_title, + (const char *)air_cartnum, + (const char *)tfc_cartnum, + (const char *)play_length, + (const char *)tfc_length, + (const char *)ext_data, + (const char *)q->value(8).toString(), + (const char *)q->value(7).toString()); + } + + delete q; + fclose(f); + report_error_code=RDReport::ErrorOk; + return true; +} + diff --git a/lib/export_musicclassical.cpp b/lib/export_musicclassical.cpp new file mode 100644 index 00000000..fd0c835d --- /dev/null +++ b/lib/export_musicclassical.cpp @@ -0,0 +1,135 @@ +// export_musicclassical.cpp +// +// Export a Rivendell Classical Music Playout report +// +// (C) Copyright 2014 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: export_musicclassical.cpp,v 1.1.2.1 2014/05/20 22:39:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> + +#include <qfile.h> +#include <qmessagebox.h> +#include <rddb.h> +#include <rdlog_line.h> +#include <rdairplay_conf.h> +#include <rdconf.h> +#include <rddatedecode.h> +#include <rdreport.h> + +bool RDReport::ExportMusicClassical(const QDate &startdate,const QDate &enddate, + const QString &mixtable) +{ + QString sql; + RDSqlQuery *q; + FILE *f; + QString cut; + QString str; + QString cart_fmt; + QString cart_num; + +#ifdef WIN32 + QString filename=RDDateDecode(exportPath(RDReport::Windows),startdate); +#else + QString filename=RDDateDecode(exportPath(RDReport::Linux),startdate); +#endif + + QFile file(filename); + if((f=fopen((const char *)filename,"w"))==NULL) { + report_error_code=RDReport::ErrorCantOpen; + return false; + } + if(useLeadingZeros()) { + cart_fmt=QString().sprintf("%%0%uu",cartDigits()); + } + else { + cart_fmt="%6u"; + } + sql=QString().sprintf("select `%s_SRT`.LENGTH,\ + `%s_SRT`.CART_NUMBER,\ + `%s_SRT`.EVENT_DATETIME,\ + `%s_SRT`.TITLE,\ + `%s_SRT`.ALBUM,\ + `%s_SRT`.COMPOSER,\ + `%s_SRT`.USER_DEFINED \ + from `%s_SRT` left join CART on\ + `%s_SRT`.CART_NUMBER=CART.NUMBER\ + order by EVENT_DATETIME", + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable); + q=new RDSqlQuery(sql); + + // + // Write File Header + // + if(startdate==enddate) { + fprintf(f," Rivendell RDAirPlay Classical Music Playout Report for %s\n", + (const char *)startdate.toString("MM/dd/yyyy")); + } + else { + fprintf(f," Rivendell RDAirPlay Music Playout Report for %s - %s\n", + (const char *)startdate.toString("MM/dd/yyyy"), + (const char *)enddate.toString("MM/dd/yyyy")); + } + str=QString().sprintf("%s -- %s\n",(const char *)name(), + (const char *)description()); + for(unsigned i=0;i<(120-str.length())/2;i++) { + fprintf(f," "); + } + fprintf(f,"%s\n",(const char *)str); + fprintf(f,"Time -Len- --Title----------------------- --Composer-------------------- --Label / Spine #-------- Lib # Cart #\n"); + + // + // Write Data Rows + // + while(q->next()) { + if(q->value(5).toInt()>0) { + cut=QString().sprintf("%03d",q->value(5).toInt()); + } + else { + if((RDAirPlayConf::TrafficAction)q->value(6).toInt()== + RDAirPlayConf::TrafficMacro) { + cut="rml"; + } + else { + cut=" "; + } + } + cart_num=QString().sprintf(cart_fmt,q->value(1).toUInt()); + fprintf(f,"%4s %5s %-30s %-30s %-25s %-5s %06u\n", + (const char *)q->value(2).toDateTime().time().toString("hhmm"), + (const char *)RDGetTimeLength(q->value(0).toInt(),true,false). + right(5), + (const char *)StringField(q->value(3).toString().left(30)), + (const char *)StringField(q->value(5).toString().left(30)), + (const char *)StringField(q->value(4).toString().left(25)), + (const char *)StringField(q->value(6).toString().left(5)), + q->value(1).toUInt()); + } + delete q; + fclose(f); + report_error_code=RDReport::ErrorOk; + + return true; +} diff --git a/lib/export_musicplayout.cpp b/lib/export_musicplayout.cpp new file mode 100644 index 00000000..abe2b883 --- /dev/null +++ b/lib/export_musicplayout.cpp @@ -0,0 +1,140 @@ +// export_musicplayout.cpp +// +// Export a Rivendell Report to an ASCII Text File. +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: export_musicplayout.cpp,v 1.1.2.2.2.1 2014/05/20 22:39:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> + +#include <qfile.h> +#include <qmessagebox.h> +#include <rddb.h> +#include <rdlog_line.h> +#include <rdairplay_conf.h> +#include <rdconf.h> +#include <rddatedecode.h> +#include <rdreport.h> + +bool RDReport::ExportMusicPlayout(const QDate &startdate,const QDate &enddate, + const QString &mixtable) +{ + QString sql; + RDSqlQuery *q; + FILE *f; + QString cut; + QString str; + QString cart_fmt; + QString cart_num; + +#ifdef WIN32 + QString filename=RDDateDecode(exportPath(RDReport::Windows),startdate); +#else + QString filename=RDDateDecode(exportPath(RDReport::Linux),startdate); +#endif + + QFile file(filename); + if((f=fopen((const char *)filename,"w"))==NULL) { + report_error_code=RDReport::ErrorCantOpen; + return false; + } + if(useLeadingZeros()) { + cart_fmt=QString().sprintf("%%0%uu",cartDigits()); + } + else { + cart_fmt="%6u"; + } + sql=QString().sprintf("select `%s_SRT`.LENGTH,\ + `%s_SRT`.CART_NUMBER,\ + `%s_SRT`.EVENT_DATETIME,\ + `%s_SRT`.EXT_EVENT_ID,\ + `%s_SRT`.TITLE,\ + `%s_SRT`.CUT_NUMBER,\ + `%s_SRT`.ARTIST,\ + `%s_SRT`.ALBUM,\ + `%s_SRT`.LABEL \ + from `%s_SRT` left join CART on\ + `%s_SRT`.CART_NUMBER=CART.NUMBER\ + order by EVENT_DATETIME", + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable); + q=new RDSqlQuery(sql); + + // + // Write File Header + // + if(startdate==enddate) { + fprintf(f," Rivendell RDAirPlay Music Playout Report for %s\n", + (const char *)startdate.toString("MM/dd/yyyy")); + } + else { + fprintf(f," Rivendell RDAirPlay Music Playout Report for %s - %s\n", + (const char *)startdate.toString("MM/dd/yyyy"), + (const char *)enddate.toString("MM/dd/yyyy")); + } + str=QString().sprintf("%s -- %s\n",(const char *)name(), + (const char *)description()); + for(unsigned i=0;i<(180-str.length())/2;i++) { + fprintf(f," "); + } + fprintf(f,"%s\n",(const char *)str); + fprintf(f,"--Time-- -Cart- Cut A-Len --Title----------------------- --Artist---------------------- --Album------------------ --Label-------------\n"); + + // + // Write Data Rows + // + while(q->next()) { + if(q->value(5).toInt()>0) { + cut=QString().sprintf("%03d",q->value(5).toInt()); + } + else { + if((RDAirPlayConf::TrafficAction)q->value(6).toInt()== + RDAirPlayConf::TrafficMacro) { + cut="rml"; + } + else { + cut=" "; + } + } + cart_num=QString().sprintf(cart_fmt,q->value(1).toUInt()); + fprintf(f,"%8s %6s %3s %5s %-30s %-30s %-25s %-20s\n", + (const char *)q->value(2).toDateTime().time().toString("hh:mm:ss"), + (const char *)cart_num, + (const char *)cut, + (const char *)RDGetTimeLength(q->value(0).toInt(),true,false). + right(5), + (const char *)StringField(q->value(4).toString().left(30)), + (const char *)StringField(q->value(6).toString().left(30)), + (const char *)StringField(q->value(7).toString().left(25)), + (const char *)StringField(q->value(8).toString().left(20))); + } + delete q; + fclose(f); + report_error_code=RDReport::ErrorOk; + + return true; +} diff --git a/lib/export_musicsummary.cpp b/lib/export_musicsummary.cpp new file mode 100644 index 00000000..d961c075 --- /dev/null +++ b/lib/export_musicsummary.cpp @@ -0,0 +1,104 @@ +// export_musicsummary.cpp +// +// Export a Rivendell Report to an ASCII Text File. +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: export_musicsummary.cpp,v 1.1.2.1 2012/08/13 20:08:27 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> + +#include <qfile.h> +#include <qmessagebox.h> +#include <rddb.h> +#include <rdlog_line.h> +#include <rdairplay_conf.h> +#include <rdconf.h> +#include <rddatedecode.h> +#include <rdreport.h> + + +bool RDReport::ExportMusicSummary(const QDate &startdate,const QDate &enddate, + const QString &mixtable) +{ + QString sql; + RDSqlQuery *q; + FILE *f; + QString cut; + QString str; + +#ifdef WIN32 + QString filename=RDDateDecode(exportPath(RDReport::Windows),startdate); +#else + QString filename=RDDateDecode(exportPath(RDReport::Linux),startdate); +#endif + + QFile file(filename); + if((f=fopen((const char *)filename,"w"))==NULL) { + report_error_code=RDReport::ErrorCantOpen; + return false; + } + sql=QString().sprintf("select `%s_SRT`.ARTIST,`%s_SRT`.TITLE,\ + `%s_SRT`.ALBUM \ + from `%s_SRT` left join CART on\ + `%s_SRT`.CART_NUMBER=CART.NUMBER\ + order by EVENT_DATETIME", + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable); + q=new RDSqlQuery(sql); + + // + // Write File Header + // + if(startdate==enddate) { + fprintf(f," Rivendell RDAirPlay Music Summary Report for %s\n", + (const char *)startdate.toString("MM/dd/yyyy")); + } + else { + fprintf(f," Rivendell RDAirPlay Music Summary Report for %s - %s\n", + (const char *)startdate.toString("MM/dd/yyyy"), + (const char *)enddate.toString("MM/dd/yyyy")); + } + str=QString().sprintf("%s -- %s\n",(const char *)name(), + (const char *)description()); + for(unsigned i=0;i<(80-str.length())/2;i++) { + fprintf(f," "); + } + fprintf(f,"%s\n",(const char *)str); + + // + // Write Data Rows + // + while(q->next()) { + if(!q->value(0).toString().isEmpty()) { + fprintf(f,"%s - ",(const char *)q->value(0).toString()); + } + fprintf(f,"%s",(const char *)q->value(1).toString()); + if(!q->value(2).toString().isEmpty()) { + fprintf(f," [%s]",(const char *)q->value(2).toString()); + } + fprintf(f,"\n"); + } + delete q; + fclose(f); + report_error_code=RDReport::ErrorOk; + return true; +} + diff --git a/lib/export_nprsoundex.cpp b/lib/export_nprsoundex.cpp new file mode 100644 index 00000000..475d74f4 --- /dev/null +++ b/lib/export_nprsoundex.cpp @@ -0,0 +1,91 @@ +// export_nprsoundex.cpp +// +// Export a Rivendell NPR SoundExchange Report to an ASCII Text File. +// +// (C) Copyright 2002-2006,2013 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: export_nprsoundex.cpp,v 1.1.2.2.2.1 2014/06/24 18:27:03 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> + +#include <qfile.h> +#include <qmessagebox.h> +#include <rddb.h> +#include <rdlog_line.h> +#include <rdairplay_conf.h> +#include <rddatedecode.h> +#include <rdreport.h> +#include <rdget_ath.h> +#include <rdescape_string.h> + +// +// This implements a National Public Radio (NPR) standard. +// See http://soundexchange.digitalservices.npr.org/playlist-log-file-guidelines/ +// for more information. +// + +bool RDReport::ExportNprSoundEx(const QDate &startdate,const QDate &enddate, + const QString &mixtable) +{ + QString sql; + RDSqlQuery *q; + FILE *f=NULL; + QString artist; + QString title; + QString album; + QString label; + QString service_name=serviceName(); + QString trans_category=stationFormat(); + QString channel_name=stationId(); + +#ifdef WIN32 + QString filename=RDDateDecode(exportPath(RDReport::Windows),startdate); +#else + QString filename=RDDateDecode(exportPath(RDReport::Linux),startdate); +#endif + if((f=fopen(filename,"wb"))==NULL) { + report_error_code=RDReport::ErrorCantOpen; + return false; + } + + // + // Generate Header + // + fprintf(f,"Start Time\tEnd Time\tTitle\tArtist\tAlbum\tLabel\x0d\x0a"); + + // + // Roll Up Records + // + sql=QString("select EVENT_DATETIME,LENGTH,TITLE,ARTIST,ALBUM,LABEL from `")+ + mixtable+"_SRT` order by EVENT_DATETIME"; + q=new RDSqlQuery(sql); + while(q->next()) { + fprintf(f,"%s\t",(const char *)q->value(0).toDateTime(). + toString("MM/dd/yyyy hh:mm:ss")); + fprintf(f,"%s\t",(const char *)q->value(0).toDateTime(). + addSecs(q->value(1).toInt()/1000). + toString("MM/dd/yyyy hh:mm:ss")); + fprintf(f,"%s\t",(const char *)StringField(q->value(2).toString())); + fprintf(f,"%s\t",(const char *)StringField(q->value(3).toString())); + fprintf(f,"%s\t",(const char *)StringField(q->value(4).toString())); + fprintf(f,"%s\x0d\x0a",(const char *)StringField(q->value(5).toString())); + } + fclose(f); + report_error_code=RDReport::ErrorOk; + return true; +} + diff --git a/lib/export_radiotraffic.cpp b/lib/export_radiotraffic.cpp new file mode 100644 index 00000000..7544b5f4 --- /dev/null +++ b/lib/export_radiotraffic.cpp @@ -0,0 +1,124 @@ +// export_radiotraffic.cpp +// +// Export a Rivendell Report to RadioTraffic.com +// +// (C) Copyright 2002-2005,2009 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: export_radiotraffic.cpp,v 1.2.8.1 2013/02/08 21:41:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> + +#include <qfile.h> +#include <qmessagebox.h> + +#include <rddb.h> +#include <rdconf.h> +#include <rddatedecode.h> +#include <rdreport.h> + + +bool RDReport::ExportRadioTraffic(const QDate &startdate,const QDate &enddate, + const QString &mixtable) +{ + QString sql; + RDSqlQuery *q; + FILE *f; + QString air_fmt; + +#ifdef WIN32 + QString filename=RDDateDecode(exportPath(RDReport::Windows),startdate); +#else + QString filename=RDDateDecode(exportPath(RDReport::Linux),startdate); +#endif + + QFile file(filename); + if((f=fopen((const char *)filename,"wb"))==NULL) { + report_error_code=RDReport::ErrorCantOpen; + return false; + } + + if(useLeadingZeros()) { + air_fmt=QString().sprintf("%%0%uu ",cartDigits()); + } + else { + air_fmt=QString().sprintf("%%%-uu ",cartDigits()); + } + sql=QString().sprintf("select `%s_SRT`.LENGTH,`%s_SRT`.CART_NUMBER,\ + `%s_SRT`.EVENT_DATETIME,`%s_SRT`.EVENT_TYPE,\ + `%s_SRT`.EXT_START_TIME,`%s_SRT`.EXT_LENGTH,\ + `%s_SRT`.EXT_DATA,`%s_SRT`.EXT_EVENT_ID,\ + `%s_SRT`.EXT_ANNC_TYPE,`%s_SRT`.TITLE,\ + `%s_SRT`.EXT_CART_NAME from `%s_SRT` \ + left join CART on\ + `%s_SRT`.CART_NUMBER=CART.NUMBER\ + order by EVENT_DATETIME", + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable); + + q=new RDSqlQuery(sql); + + // + // Write Data Rows + // + while(q->next()) { + fprintf(f,"%s ",(const char *)q->value(4).toTime().toString("hh:mm:ss")); + fprintf(f,"%s ",(const char *)q->value(2).toDateTime(). + toString("hh:mm:ss")); + if(q->value(5).toInt()>0) { + fprintf(f,"0%s ",(const char *)RDGetTimeLength(q->value(5).toInt(), + true,false)); + } + else { + fprintf(f,"00:00:00 "); + } + if(q->value(0).toInt()>0) { + fprintf(f,"0%s ",(const char *)RDGetTimeLength(q->value(0).toInt(), + true,false)); + } + else { + fprintf(f,"00:00:00 "); + } + fprintf(f,air_fmt,q->value(1).toUInt()); + fprintf(f,"%-34s ",(const char *)q->value(9).toString().left(34)); + if(q->value(6).toString().isEmpty()) { + fprintf(f," "); + } + else { + fprintf(f,"%-32s",(const char *)q->value(6).toString().left(32). + stripWhiteSpace()); + } + fprintf(f,"\x0d\x0a"); + } + + delete q; + fclose(f); + report_error_code=RDReport::ErrorOk; + + return true; +} + diff --git a/lib/export_soundex.cpp b/lib/export_soundex.cpp new file mode 100644 index 00000000..33b56f24 --- /dev/null +++ b/lib/export_soundex.cpp @@ -0,0 +1,152 @@ +// export_soundex.cpp +// +// Export a Rivendell SoundExchange Report to an ASCII Text File. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: export_soundex.cpp,v 1.9 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> + +#include <qfile.h> +#include <qmessagebox.h> +#include <rddb.h> +#include <rdlog_line.h> +#include <rdairplay_conf.h> +#include <rddatedecode.h> +#include <rdreport.h> +#include <rdget_ath.h> + + +bool RDReport::ExportSoundEx(const QDate &startdate,const QDate &enddate, + const QString &mixtable) +{ + QString sql; + RDSqlQuery *q; + FILE *f; + unsigned cartnum=0; + QString artist; + QString title; + QString isrc; + QString album; + QString label; + unsigned plays=0; + QString service_name=serviceName(); + QString trans_category=stationFormat(); + QString channel_name=stationId(); + +#ifdef WIN32 + QString filename=RDDateDecode(exportPath(RDReport::Windows),startdate); +#else + QString filename=RDDateDecode(exportPath(RDReport::Linux),startdate); +#endif + + // + // Get ATH Value + // + double ath=0.0; + RDGetAth *getath=new RDGetAth(&ath); + if(getath->exec()<0) { + report_error_code=RDReport::ErrorCanceled; + return false; + } + + if((f=fopen((const char *)filename,"w"))==NULL) { + report_error_code=RDReport::ErrorCantOpen; + return false; + } + + // + // Generate Header + // + fprintf(f,"\"NAME_OF_SERVICE\",\"TRANSMISSION_CATEGORY\",\"FEATURED_ARTIST\",\"SOUND_RECORDING_TITLE\",\"ISRC\",\"ALBUM_TITLE\",\"MARKETING_LABEL\",\"ACTUAL_TOTAL_PERFORMANCES\",\"AGGREGATE_TUNING_HOURS\",\"CHANNEL_OR_PROGRAM_NAME\",\"PLAY_FREQUENCY\"\r\n"); + + // + // Roll Up Records + // + sql=QString().sprintf("select CART_NUMBER,ARTIST,TITLE,ISRC,ALBUM,LABEL \ + from `%s_SRT` order by CART_NUMBER", + (const char *)mixtable); + q=new RDSqlQuery(sql); + while(q->next()) { + if(q->value(0).toUInt()==cartnum) { + plays++; + } + else { + if(cartnum!=0) { + fprintf(f, + "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",,%9.2lf,\"%s\",%d\n", + (const char *)service_name, + (const char *)trans_category, + (const char *)artist, + (const char *)title, + (const char *)isrc, + (const char *)album, + (const char *)label, + ath, + (const char *)channel_name, + plays); + } + plays=1; + if(q->value(1).isNull()) { + artist=""; + } + else { + artist=q->value(1).toString(); + } + title=q->value(2).toString(); + if(q->value(3).isNull()) { + isrc=""; + } + else { + isrc=q->value(3).toString(); + } + if(q->value(4).isNull()) { + album=""; + } + else { + album=q->value(4).toString(); + } + if(q->value(5).isNull()) { + label=""; + } + else { + label=q->value(5).toString(); + } + } + cartnum=q->value(0).toUInt(); + } + delete q; + if(cartnum!=0) { + fprintf(f, + "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",,%9.2lf,\"%s\",%d\n", + (const char *)service_name, + (const char *)trans_category, + (const char *)artist, + (const char *)title, + (const char *)isrc, + (const char *)album, + (const char *)label, + ath, + (const char *)channel_name, + plays); + } + fclose(f); + report_error_code=RDReport::ErrorOk; + return true; +} + diff --git a/lib/export_technical.cpp b/lib/export_technical.cpp new file mode 100644 index 00000000..caf73ef9 --- /dev/null +++ b/lib/export_technical.cpp @@ -0,0 +1,178 @@ +// export_technical.cpp +// +// Export a Rivendell Technical Report to an ASCII Text File. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: export_technical.cpp,v 1.9.8.1 2012/11/16 18:10:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> + +#include <qfile.h> +#include <qmessagebox.h> +#include <rddb.h> +#include <rdlog_line.h> +#include <rdairplay_conf.h> +#include <rdconf.h> +#include <rddatedecode.h> +#include <rdreport.h> + + +bool RDReport::ExportTechnical(const QDate &startdate,const QDate &enddate, + const QString &mixtable) +{ + QString sql; + RDSqlQuery *q; + FILE *f; + QString cut; + QString str; + QString cart_fmt; + QString cart_num; + +#ifdef WIN32 + QString filename=RDDateDecode(exportPath(RDReport::Windows),startdate); +#else + QString filename=RDDateDecode(exportPath(RDReport::Linux),startdate); +#endif + + QFile file(filename); + if((f=fopen((const char *)filename,"w"))==NULL) { + report_error_code=RDReport::ErrorCantOpen; + return false; + } + if(useLeadingZeros()) { + cart_fmt=QString().sprintf("%%0%uu",cartDigits()); + } + else { + cart_fmt="%6u"; + } + sql=QString().sprintf("select `%s_SRT`.LENGTH,`%s_SRT`.CART_NUMBER,\ + `%s_SRT`.EVENT_DATETIME,`%s_SRT`.EVENT_TYPE,\ + `%s_SRT`.EXT_START_TIME,`%s_SRT`.EXT_LENGTH,\ + `%s_SRT`.EXT_DATA,`%s_SRT`.EXT_EVENT_ID,\ + `%s_SRT`.TITLE,CART.FORCED_LENGTH,\ + `%s_SRT`.STATION_NAME,`%s_SRT`.PLAY_SOURCE,\ + `%s_SRT`.CUT_NUMBER,`%s_SRT`.START_SOURCE,\ + `%s_SRT`.ONAIR_FLAG from `%s_SRT` left join CART on\ + `%s_SRT`.CART_NUMBER=CART.NUMBER\ + order by EVENT_DATETIME", + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable); + q=new RDSqlQuery(sql); + + // + // Write File Header + // + if(startdate==enddate) { + fprintf(f," Rivendell RDAirPlay Technical Playout Report for %s\n", + (const char *)startdate.toString("MM/dd/yyyy")); + } + else { + fprintf(f," Rivendell RDAirPlay Technical Playout Report for %s - %s\n", + (const char *)startdate.toString("MM/dd/yyyy"), + (const char *)enddate.toString("MM/dd/yyyy")); + } + str=QString().sprintf("%s -- %s\n",(const char *)name(), + (const char *)description()); + for(unsigned i=0;i<(80-str.length())/2;i++) { + fprintf(f," "); + } + fprintf(f,"%s\n",(const char *)str); + fprintf(f,"--Time-- -Cart- Cut --Title---------------- A-Len N-Len --Host---- Srce StartedBy OnAir\n"); + + // + // Write Data Rows + // + while(q->next()) { + if(q->value(12).toInt()>0) { + cut=QString().sprintf("%03d",q->value(12).toInt()); + } + else { + if((RDAirPlayConf::TrafficAction)q->value(3).toInt()== + RDAirPlayConf::TrafficMacro) { + cut="rml"; + } + else { + cut=" "; + } + } + cart_num=QString().sprintf(cart_fmt,q->value(1).toUInt()); + fprintf(f,"%8s %6s %3s %-23s %5s %5s %-10s ", + (const char *)q->value(2).toTime().toString("hh:mm:ss"), + (const char *)cart_num, + (const char *)cut, + (const char *)q->value(8).toString().left(23), + (const char *)RDGetTimeLength(q->value(0).toInt(),true,false). + right(5), + (const char *)RDGetTimeLength(q->value(9).toInt(),true,false). + right(5), + (const char *)q->value(10).toString()); + switch((RDLogLine::PlaySource)q->value(11).toInt()) { + case RDLogLine::MainLog: + fprintf(f,"Main "); + break; + + case RDLogLine::AuxLog1: + fprintf(f,"Aux1 "); + break; + + case RDLogLine::AuxLog2: + fprintf(f,"Aux2 "); + break; + + case RDLogLine::SoundPanel: + fprintf(f,"SPnl "); + break; + + case RDLogLine::CartSlot: + fprintf(f,"Slot "); + break; + + default: + fprintf(f," "); + break; + } + fprintf(f,"%-7s ",(const char *)RDLogLine:: + startSourceText((RDLogLine::StartSource)q->value(13).toInt())); + if(q->value(14).toString()=="Y") { + fprintf(f," Yes "); + } + else { + fprintf(f," No "); + } + fprintf(f,"\n"); + } + delete q; + fclose(f); + report_error_code=RDReport::ErrorOk; + return true; +} + diff --git a/lib/export_textlog.cpp b/lib/export_textlog.cpp new file mode 100644 index 00000000..5ca10fc6 --- /dev/null +++ b/lib/export_textlog.cpp @@ -0,0 +1,167 @@ +// export_textlog.cpp +// +// Export a Rivendell Report to an ASCII Text File. +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: export_textlog.cpp,v 1.11.8.1 2012/11/16 18:10:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> + +#include <qfile.h> +#include <qmessagebox.h> +#include <rddb.h> +#include <rdlog_line.h> +#include <rdairplay_conf.h> +#include <rdconf.h> +#include <rddatedecode.h> +#include <rdreport.h> + + +bool RDReport::ExportTextLog(const QDate &startdate,const QDate &enddate, + const QString &mixtable) +{ + QString sql; + RDSqlQuery *q; + FILE *f; + QString cut; + QString str; + QString cart_fmt; + QString cart_num; + +#ifdef WIN32 + QString filename=RDDateDecode(exportPath(RDReport::Windows),startdate); +#else + QString filename=RDDateDecode(exportPath(RDReport::Linux),startdate); +#endif + + QFile file(filename); + if((f=fopen((const char *)filename,"w"))==NULL) { + report_error_code=RDReport::ErrorCantOpen; + return false; + } + if(useLeadingZeros()) { + cart_fmt=QString().sprintf("%%0%uu",cartDigits()); + } + else { + cart_fmt="%6u"; + } + sql=QString().sprintf("select `%s_SRT`.LENGTH,`%s_SRT`.CART_NUMBER,\ + `%s_SRT`.EVENT_DATETIME,`%s_SRT`.EVENT_TYPE,\ + `%s_SRT`.EXT_START_TIME,`%s_SRT`.EXT_LENGTH,\ + `%s_SRT`.EXT_DATA,`%s_SRT`.EXT_EVENT_ID,\ + `%s_SRT`.TITLE,CART.FORCED_LENGTH,\ + `%s_SRT`.STATION_NAME,`%s_SRT`.PLAY_SOURCE,\ + `%s_SRT`.CUT_NUMBER from `%s_SRT` left join CART on\ + `%s_SRT`.CART_NUMBER=CART.NUMBER\ + order by EVENT_DATETIME", + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable, + (const char *)mixtable); + q=new RDSqlQuery(sql); + + // + // Write File Header + // + if(startdate==enddate) { + fprintf(f," Rivendell RDAirPlay Playout Report for %s\n", + (const char *)startdate.toString("MM/dd/yyyy")); + } + else { + fprintf(f," Rivendell RDAirPlay Playout Report for %s - %s\n", + (const char *)startdate.toString("MM/dd/yyyy"), + (const char *)enddate.toString("MM/dd/yyyy")); + } + str=QString().sprintf("%s -- %s\n",(const char *)name(), + (const char *)description()); + for(unsigned i=0;i<(80-str.length())/2;i++) { + fprintf(f," "); + } + fprintf(f,"%s\n",(const char *)str); + fprintf(f,"--Time-- -Cart- Cut --Title---------------- A-Len N-Len --Host---- Srce\n"); + + // + // Write Data Rows + // + while(q->next()) { + if(q->value(12).toInt()>0) { + cut=QString().sprintf("%03d",q->value(12).toInt()); + } + else { + if((RDAirPlayConf::TrafficAction)q->value(3).toInt()== + RDAirPlayConf::TrafficMacro) { + cut="rml"; + } + else { + cut=" "; + } + } + cart_num=QString().sprintf(cart_fmt,q->value(1).toUInt()); + fprintf(f,"%8s %6s %3s %-23s %5s %5s %-10s ", + (const char *)q->value(2).toTime().toString("hh:mm:ss"), + (const char *)cart_num, + (const char *)cut, + (const char *)q->value(8).toString().left(23), + (const char *)RDGetTimeLength(q->value(0).toInt(),true,false). + right(5), + (const char *)RDGetTimeLength(q->value(9).toInt(),true,false). + right(5), + (const char *)q->value(10).toString()); + switch((RDLogLine::PlaySource)q->value(11).toInt()) { + case RDLogLine::MainLog: + fprintf(f,"Main"); + break; + + case RDLogLine::AuxLog1: + fprintf(f,"Aux1"); + break; + + case RDLogLine::AuxLog2: + fprintf(f,"Aux2"); + break; + + case RDLogLine::SoundPanel: + fprintf(f,"SPnl"); + break; + + case RDLogLine::CartSlot: + fprintf(f,"Slot"); + break; + + default: + fprintf(f," "); + break; + } + fprintf(f,"\n"); + } + delete q; + fclose(f); + report_error_code=RDReport::ErrorOk; + return true; +} + diff --git a/lib/gpio.h b/lib/gpio.h new file mode 100644 index 00000000..6c06aebe --- /dev/null +++ b/lib/gpio.h @@ -0,0 +1,125 @@ +// gpio.h +// +// A device driver for MeasurementComputing GPIO cards. +// +// Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: gpio.h,v 1.1 2007/09/18 11:20:00 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef GPIO_H +#define GPIO_H + +#include <linux/ioctl.h> + +/* + * For non-Automake only + */ +#define GPIO_DEV_MAJOR 125 + +/* + * Modes + */ +#define GPIO_MODE_AUTO 0 +#define GPIO_MODE_INPUT 1 +#define GPIO_MODE_OUTPUT 2 + +/* + * Device Capability Flags + */ +#define GPIO_CAP_FILTER 0x00000001 +#define GPIO_CAP_MODE 0x00000002 + + +struct gpio_info { + char name[48]; // Model/Description of board + int mode; // Board Mode (PCI-DIO24 only) + int inputs; // Number of input lines + int outputs; // Number of output lines + int samples; // Number of analog sample channels + int depth; // Number of sample bits per analog channel + unsigned caps; // Device capabilities +}; + +struct gpio_mask { + unsigned mask[4]; +}; + +struct gpio_line { + int line; // The number of the output line (0 - 127) + int state; // 0 = Off, 1 = On +}; + +struct gpio_sample { + int line; // The number of the input line (0 - 127) + int gain; // Channel gain, value 0 - 3 + unsigned sample; // The sample value +}; + +/* + * IOCTLS + */ +#define GPIO_IOCTL_MAGIC 0xfd +#ifdef KERNEL_2_4 +#define GPIO_GETINFO _IOR(GPIO_IOCTL_MAGIC,1,sizeof(struct gpio_info)) +#define GPIO_SETMODE _IOW(GPIO_IOCTL_MAGIC,2,sizeof(unsigned)) +#define GPIO_GET_INPUTS _IOR(GPIO_IOCTL_MAGIC,3,sizeof(struct gpio_mask)) +#define GPIO_GET_OUTPUTS _IOR(GPIO_IOCTL_MAGIC,4,sizeof(struct gpio_mask)) +#define GPIO_GET_FILTERS _IOR(GPIO_IOCTL_MAGIC,5,sizeof(struct gpio_mask)) +#define GPIO_SET_OUTPUT _IOW(GPIO_IOCTL_MAGIC,6,sizeof(struct gpio_line)) +#define GPIO_SET_FILTER _IOW(GPIO_IOCTL_MAGIC,7,sizeof(struct gpio_line)) +#define GPIO_SET_OUTPUTS _IOW(GPIO_IOCTL_MAGIC,8,sizeof(struct gpio_mask)) +#define GPIO_SET_FILTERS _IOW(GPIO_IOCTL_MAGIC,9,sizeof(struct gpio_mask)) +#define GPIO_GET_SAMPLE _IOWR(GPIO_IOCTL_MAGIC,10,sizeof(struct gpio_sample)) +#else +#define GPIO_GETINFO _IOR(GPIO_IOCTL_MAGIC,1,struct gpio_info) +#define GPIO_SETMODE _IOW(GPIO_IOCTL_MAGIC,2,unsigned) +#define GPIO_GET_INPUTS _IOR(GPIO_IOCTL_MAGIC,3,struct gpio_mask) +#define GPIO_GET_OUTPUTS _IOR(GPIO_IOCTL_MAGIC,4,struct gpio_mask) +#define GPIO_GET_FILTERS _IOR(GPIO_IOCTL_MAGIC,5,struct gpio_mask) +#define GPIO_SET_OUTPUT _IOW(GPIO_IOCTL_MAGIC,6,struct gpio_line) +#define GPIO_SET_FILTER _IOW(GPIO_IOCTL_MAGIC,7,struct gpio_line) +#define GPIO_SET_OUTPUTS _IOW(GPIO_IOCTL_MAGIC,8,struct gpio_mask) +#define GPIO_SET_FILTERS _IOW(GPIO_IOCTL_MAGIC,9,struct gpio_mask) +#define GPIO_GET_SAMPLE _IOWR(GPIO_IOCTL_MAGIC,10,struct gpio_sample) +#endif // KERNEL_2_4 + +#ifdef __KERNEL__ + +#include <linux/autoconf.h> +#include <linux/module.h> +#include <asm/io.h> +#include <linux/pci.h> +#include <linux/ioport.h> + +#ifndef CONFIG_PCI +#error "No PCI Support Present" +#endif + +/* + * Driver Defines + */ +#define GPIO_MAX_CARDS 8 +#define GPIO_CBOARDS_VENDOR_ID 0x1307 +#define GPIO_PCI_DIO24_DEVICE_ID 0x0028 +#define GPIO_PCI_PDISO8_DEVICE_ID 0x000C +#define GPIO_PCI_PDISO16_DEVICE_ID 0x000D +#define GPIO_PCI_DAS1000_DEVICE_ID 0x004C + + +#endif // __KERNEL__ + +#endif // GPIO_H diff --git a/lib/gpl2.html b/lib/gpl2.html new file mode 100644 index 00000000..f8004619 --- /dev/null +++ b/lib/gpl2.html @@ -0,0 +1,348 @@ +<center><big><big><strong>GNU GENERAL PUBLIC LICENSE</strong></big></big></center> +<center><big>Version 2, June 1991</big></center> + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple + Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted + to copy and distribute verbatim copies of this license document, but + changing it is not allowed.<br> + +<center><big><strong>PREAMBLE</strong></big></center> +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License +is intended to guarantee your freedom to share and change free +software -- to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors +commit to using it. (Some other Free Software Foundation +software is covered by the GNU Library General Public +License instead.) You can apply it to your programs, too. +<p> +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. +<p> +To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the software, or if you modify it. +<p> +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. +<p> +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. +<p> +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, +we want its recipients to know that what they have is not the +original, so that any problems introduced by others will not reflect +on the original authors' reputations. +<p> +Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at +all. + +<p> +The precise terms and conditions for copying, distribution and +modification follow. +<p> +<center><big><strong>GNU GENERAL PUBLIC LICENSE</strong></big></center> +<strong>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</strong><br> +0. This License applies to any program or other work which contains a +notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". +<p> +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the Program +(independent of having been made by running the Program). Whether +that is true depends on what the Program does. +<p> +1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy an appropriate copyright notice +and disclaimer of warranty; keep intact all the notices that refer to +this License and to the absence of any warranty; and give any other +recipients of the Program a copy of this License along with the +Program. +<p> +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a +fee. +<p> +2. You may modify your copy or copies of the Program or any portion of +it, thus forming a work based on the Program, and copy and distribute +such modifications or work under the terms of Section 1 above, +provided that you also meet all of these conditions: +<p> + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. +<p> + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. +<p> + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) +<p> +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. +<p> +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. +<p> +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. +<p> +3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: +<p> + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, +<p> + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, +<p> + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) +<p> +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. +<p> +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. +<p> +4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. +<p> +5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. +<p> +6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. +<p> +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. +<p> +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. +<p> +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. +<p> +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. +<p> +8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. +<p> +9. The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. +<p> +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a +version number of this License, you may choose any version ever +published by the Free Software Foundation. +<p> +10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the +author to ask for permission. For software which is copyrighted by +the Free Software Foundation, write to the Free Software Foundation; +we sometimes make exceptions for this. Our decision will be guided by +the two goals of preserving the free status of all derivatives of our +free software and of promoting the sharing and reuse of software +generally. +<p> +<strong>NO WARRANTY</strong> +<p> +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. +<p> +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. +<p> +<strong>END OF TERMS AND CONDITIONS</strong> +<p> +<strong>How to Apply These Terms to Your New Programs</strong><br> +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. +<p> +To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. +<p> + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> +<p> + 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. +<p> + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +<p> + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +<p> +Also add information on how to contact you by electronic and paper mail. +<p> +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: +<pre> + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. +</pre> +<p> +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. +<p> +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the program, +if necessary. Here is a sample; alter the names: +<p> +<pre> + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice +</pre> +<p> +This General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, +you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use +the GNU Library General Public License instead of this License. + diff --git a/lib/html_gpl2.cpp b/lib/html_gpl2.cpp new file mode 100644 index 00000000..6b8cf2f7 --- /dev/null +++ b/lib/html_gpl2.cpp @@ -0,0 +1,1149 @@ +const unsigned char html_gpl2[18343] = { +60,99,101,110,116,101,114,62,60,98,105,103,62,60,98,105, +103,62,60,115,116,114,111,110,103,62,71,78,85,32,71,69, +78,69,82,65,76,32,80,85,66,76,73,67,32,76,73,67, +69,78,83,69,60,47,115,116,114,111,110,103,62,60,47,98, +105,103,62,60,47,98,105,103,62,60,47,99,101,110,116,101, +114,62,10,60,99,101,110,116,101,114,62,60,98,105,103,62, +86,101,114,115,105,111,110,32,50,44,32,74,117,110,101,32, +49,57,57,49,60,47,98,105,103,62,60,47,99,101,110,116, +101,114,62,10,10,32,67,111,112,121,114,105,103,104,116,32, +40,67,41,32,49,57,56,57,44,32,49,57,57,49,32,70, +114,101,101,32,83,111,102,116,119,97,114,101,32,70,111,117, +110,100,97,116,105,111,110,44,32,73,110,99,46,32,32,53, +57,32,84,101,109,112,108,101,10,32,80,108,97,99,101,44, +32,83,117,105,116,101,32,51,51,48,44,32,66,111,115,116, +111,110,44,32,77,65,32,32,48,50,49,49,49,45,49,51, +48,55,32,32,85,83,65,32,32,69,118,101,114,121,111,110, +101,32,105,115,32,112,101,114,109,105,116,116,101,100,10,32, +116,111,32,99,111,112,121,32,97,110,100,32,100,105,115,116, +114,105,98,117,116,101,32,118,101,114,98,97,116,105,109,32, +99,111,112,105,101,115,32,111,102,32,116,104,105,115,32,108, +105,99,101,110,115,101,32,100,111,99,117,109,101,110,116,44, +32,98,117,116,10,32,99,104,97,110,103,105,110,103,32,105, +116,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100, +46,60,98,114,62,10,10,60,99,101,110,116,101,114,62,60, +98,105,103,62,60,115,116,114,111,110,103,62,80,82,69,65, +77,66,76,69,60,47,115,116,114,111,110,103,62,60,47,98, +105,103,62,60,47,99,101,110,116,101,114,62,10,84,104,101, +32,108,105,99,101,110,115,101,115,32,102,111,114,32,109,111, +115,116,32,115,111,102,116,119,97,114,101,32,97,114,101,32, +100,101,115,105,103,110,101,100,32,116,111,32,116,97,107,101, +32,97,119,97,121,32,121,111,117,114,32,102,114,101,101,100, +111,109,10,116,111,32,115,104,97,114,101,32,97,110,100,32, +99,104,97,110,103,101,32,105,116,46,32,32,66,121,32,99, +111,110,116,114,97,115,116,44,32,116,104,101,32,71,78,85, +32,71,101,110,101,114,97,108,32,80,117,98,108,105,99,32, +76,105,99,101,110,115,101,10,105,115,32,105,110,116,101,110, +100,101,100,32,116,111,32,103,117,97,114,97,110,116,101,101, +32,121,111,117,114,32,102,114,101,101,100,111,109,32,116,111, +32,115,104,97,114,101,32,97,110,100,32,99,104,97,110,103, +101,32,102,114,101,101,10,115,111,102,116,119,97,114,101,32, +45,45,32,116,111,32,109,97,107,101,32,115,117,114,101,32, +116,104,101,32,115,111,102,116,119,97,114,101,32,105,115,32, +102,114,101,101,32,102,111,114,32,97,108,108,32,105,116,115, +32,117,115,101,114,115,46,32,32,84,104,105,115,10,71,101, +110,101,114,97,108,32,80,117,98,108,105,99,32,76,105,99, +101,110,115,101,32,97,112,112,108,105,101,115,32,116,111,32, +109,111,115,116,32,111,102,32,116,104,101,32,70,114,101,101, +32,83,111,102,116,119,97,114,101,10,70,111,117,110,100,97, +116,105,111,110,39,115,32,115,111,102,116,119,97,114,101,32, +97,110,100,32,116,111,32,97,110,121,32,111,116,104,101,114, +32,112,114,111,103,114,97,109,32,119,104,111,115,101,32,97, +117,116,104,111,114,115,10,99,111,109,109,105,116,32,116,111, +32,117,115,105,110,103,32,105,116,46,32,32,40,83,111,109, +101,32,111,116,104,101,114,32,70,114,101,101,32,83,111,102, +116,119,97,114,101,32,70,111,117,110,100,97,116,105,111,110, +10,115,111,102,116,119,97,114,101,32,105,115,32,99,111,118, +101,114,101,100,32,98,121,32,116,104,101,32,71,78,85,32, +76,105,98,114,97,114,121,32,71,101,110,101,114,97,108,32, +80,117,98,108,105,99,10,76,105,99,101,110,115,101,32,105, +110,115,116,101,97,100,46,41,32,32,89,111,117,32,99,97, +110,32,97,112,112,108,121,32,105,116,32,116,111,32,121,111, +117,114,32,112,114,111,103,114,97,109,115,44,32,116,111,111, +46,10,60,112,62,10,87,104,101,110,32,119,101,32,115,112, +101,97,107,32,111,102,32,102,114,101,101,32,115,111,102,116, +119,97,114,101,44,32,119,101,32,97,114,101,32,114,101,102, +101,114,114,105,110,103,32,116,111,32,102,114,101,101,100,111, +109,44,32,110,111,116,10,112,114,105,99,101,46,32,32,79, +117,114,32,71,101,110,101,114,97,108,32,80,117,98,108,105, +99,32,76,105,99,101,110,115,101,115,32,97,114,101,32,100, +101,115,105,103,110,101,100,32,116,111,32,109,97,107,101,32, +115,117,114,101,32,116,104,97,116,32,121,111,117,10,104,97, +118,101,32,116,104,101,32,102,114,101,101,100,111,109,32,116, +111,32,100,105,115,116,114,105,98,117,116,101,32,99,111,112, +105,101,115,32,111,102,32,102,114,101,101,32,115,111,102,116, +119,97,114,101,32,40,97,110,100,32,99,104,97,114,103,101, +32,102,111,114,10,116,104,105,115,32,115,101,114,118,105,99, +101,32,105,102,32,121,111,117,32,119,105,115,104,41,44,32, +116,104,97,116,32,121,111,117,32,114,101,99,101,105,118,101, +32,115,111,117,114,99,101,32,99,111,100,101,32,111,114,32, +99,97,110,32,103,101,116,32,105,116,10,105,102,32,121,111, +117,32,119,97,110,116,32,105,116,44,32,116,104,97,116,32, +121,111,117,32,99,97,110,32,99,104,97,110,103,101,32,116, +104,101,32,115,111,102,116,119,97,114,101,32,111,114,32,117, +115,101,32,112,105,101,99,101,115,32,111,102,32,105,116,10, +105,110,32,110,101,119,32,102,114,101,101,32,112,114,111,103, +114,97,109,115,59,32,97,110,100,32,116,104,97,116,32,121, +111,117,32,107,110,111,119,32,121,111,117,32,99,97,110,32, +100,111,32,116,104,101,115,101,32,116,104,105,110,103,115,46, +10,60,112,62,10,84,111,32,112,114,111,116,101,99,116,32, +121,111,117,114,32,114,105,103,104,116,115,44,32,119,101,32, +110,101,101,100,32,116,111,32,109,97,107,101,32,114,101,115, +116,114,105,99,116,105,111,110,115,32,116,104,97,116,32,102, +111,114,98,105,100,10,97,110,121,111,110,101,32,116,111,32, +100,101,110,121,32,121,111,117,32,116,104,101,115,101,32,114, +105,103,104,116,115,32,111,114,32,116,111,32,97,115,107,32, +121,111,117,32,116,111,32,115,117,114,114,101,110,100,101,114, +32,116,104,101,32,114,105,103,104,116,115,46,10,84,104,101, +115,101,32,114,101,115,116,114,105,99,116,105,111,110,115,32, +116,114,97,110,115,108,97,116,101,32,116,111,32,99,101,114, +116,97,105,110,32,114,101,115,112,111,110,115,105,98,105,108, +105,116,105,101,115,32,102,111,114,32,121,111,117,32,105,102, +10,121,111,117,32,100,105,115,116,114,105,98,117,116,101,32, +99,111,112,105,101,115,32,111,102,32,116,104,101,32,115,111, +102,116,119,97,114,101,44,32,111,114,32,105,102,32,121,111, +117,32,109,111,100,105,102,121,32,105,116,46,10,60,112,62, +10,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102, +32,121,111,117,32,100,105,115,116,114,105,98,117,116,101,32, +99,111,112,105,101,115,32,111,102,32,115,117,99,104,32,97, +32,112,114,111,103,114,97,109,44,32,119,104,101,116,104,101, +114,10,103,114,97,116,105,115,32,111,114,32,102,111,114,32, +97,32,102,101,101,44,32,121,111,117,32,109,117,115,116,32, +103,105,118,101,32,116,104,101,32,114,101,99,105,112,105,101, +110,116,115,32,97,108,108,32,116,104,101,32,114,105,103,104, +116,115,32,116,104,97,116,10,121,111,117,32,104,97,118,101, +46,32,32,89,111,117,32,109,117,115,116,32,109,97,107,101, +32,115,117,114,101,32,116,104,97,116,32,116,104,101,121,44, +32,116,111,111,44,32,114,101,99,101,105,118,101,32,111,114, +32,99,97,110,32,103,101,116,32,116,104,101,10,115,111,117, +114,99,101,32,99,111,100,101,46,32,32,65,110,100,32,121, +111,117,32,109,117,115,116,32,115,104,111,119,32,116,104,101, +109,32,116,104,101,115,101,32,116,101,114,109,115,32,115,111, +32,116,104,101,121,32,107,110,111,119,32,116,104,101,105,114, +10,114,105,103,104,116,115,46,10,60,112,62,10,87,101,32, +112,114,111,116,101,99,116,32,121,111,117,114,32,114,105,103, +104,116,115,32,119,105,116,104,32,116,119,111,32,115,116,101, +112,115,58,32,40,49,41,32,99,111,112,121,114,105,103,104, +116,32,116,104,101,32,115,111,102,116,119,97,114,101,44,32, +97,110,100,10,40,50,41,32,111,102,102,101,114,32,121,111, +117,32,116,104,105,115,32,108,105,99,101,110,115,101,32,119, +104,105,99,104,32,103,105,118,101,115,32,121,111,117,32,108, +101,103,97,108,32,112,101,114,109,105,115,115,105,111,110,32, +116,111,32,99,111,112,121,44,10,100,105,115,116,114,105,98, +117,116,101,32,97,110,100,47,111,114,32,109,111,100,105,102, +121,32,116,104,101,32,115,111,102,116,119,97,114,101,46,10, +60,112,62,10,65,108,115,111,44,32,102,111,114,32,101,97, +99,104,32,97,117,116,104,111,114,39,115,32,112,114,111,116, +101,99,116,105,111,110,32,97,110,100,32,111,117,114,115,44, +32,119,101,32,119,97,110,116,32,116,111,32,109,97,107,101, +32,99,101,114,116,97,105,110,10,116,104,97,116,32,101,118, +101,114,121,111,110,101,32,117,110,100,101,114,115,116,97,110, +100,115,32,116,104,97,116,32,116,104,101,114,101,32,105,115, +32,110,111,32,119,97,114,114,97,110,116,121,32,102,111,114, +32,116,104,105,115,32,102,114,101,101,10,115,111,102,116,119, +97,114,101,46,32,32,73,102,32,116,104,101,32,115,111,102, +116,119,97,114,101,32,105,115,32,109,111,100,105,102,105,101, +100,32,98,121,32,115,111,109,101,111,110,101,32,101,108,115, +101,32,97,110,100,32,112,97,115,115,101,100,32,111,110,44, +10,119,101,32,119,97,110,116,32,105,116,115,32,114,101,99, +105,112,105,101,110,116,115,32,116,111,32,107,110,111,119,32, +116,104,97,116,32,119,104,97,116,32,116,104,101,121,32,104, +97,118,101,32,105,115,32,110,111,116,32,116,104,101,10,111, +114,105,103,105,110,97,108,44,32,115,111,32,116,104,97,116, +32,97,110,121,32,112,114,111,98,108,101,109,115,32,105,110, +116,114,111,100,117,99,101,100,32,98,121,32,111,116,104,101, +114,115,32,119,105,108,108,32,110,111,116,32,114,101,102,108, +101,99,116,10,111,110,32,116,104,101,32,111,114,105,103,105, +110,97,108,32,97,117,116,104,111,114,115,39,32,114,101,112, +117,116,97,116,105,111,110,115,46,10,60,112,62,10,70,105, +110,97,108,108,121,44,32,97,110,121,32,102,114,101,101,32, +112,114,111,103,114,97,109,32,105,115,32,116,104,114,101,97, +116,101,110,101,100,32,99,111,110,115,116,97,110,116,108,121, +32,98,121,32,115,111,102,116,119,97,114,101,10,112,97,116, +101,110,116,115,46,32,32,87,101,32,119,105,115,104,32,116, +111,32,97,118,111,105,100,32,116,104,101,32,100,97,110,103, +101,114,32,116,104,97,116,32,114,101,100,105,115,116,114,105, +98,117,116,111,114,115,32,111,102,32,97,32,102,114,101,101, +10,112,114,111,103,114,97,109,32,119,105,108,108,32,105,110, +100,105,118,105,100,117,97,108,108,121,32,111,98,116,97,105, +110,32,112,97,116,101,110,116,32,108,105,99,101,110,115,101, +115,44,32,105,110,32,101,102,102,101,99,116,32,109,97,107, +105,110,103,32,116,104,101,10,112,114,111,103,114,97,109,32, +112,114,111,112,114,105,101,116,97,114,121,46,32,32,84,111, +32,112,114,101,118,101,110,116,32,116,104,105,115,44,32,119, +101,32,104,97,118,101,32,109,97,100,101,32,105,116,32,99, +108,101,97,114,32,116,104,97,116,32,97,110,121,10,112,97, +116,101,110,116,32,109,117,115,116,32,98,101,32,108,105,99, +101,110,115,101,100,32,102,111,114,32,101,118,101,114,121,111, +110,101,39,115,32,102,114,101,101,32,117,115,101,32,111,114, +32,110,111,116,32,108,105,99,101,110,115,101,100,32,97,116, +10,97,108,108,46,10,10,60,112,62,10,84,104,101,32,112, +114,101,99,105,115,101,32,116,101,114,109,115,32,97,110,100, +32,99,111,110,100,105,116,105,111,110,115,32,102,111,114,32, +99,111,112,121,105,110,103,44,32,100,105,115,116,114,105,98, +117,116,105,111,110,32,97,110,100,10,109,111,100,105,102,105, +99,97,116,105,111,110,32,102,111,108,108,111,119,46,10,60, +112,62,10,60,99,101,110,116,101,114,62,60,98,105,103,62, +60,115,116,114,111,110,103,62,71,78,85,32,71,69,78,69, +82,65,76,32,80,85,66,76,73,67,32,76,73,67,69,78, +83,69,60,47,115,116,114,111,110,103,62,60,47,98,105,103, +62,60,47,99,101,110,116,101,114,62,10,60,115,116,114,111, +110,103,62,84,69,82,77,83,32,65,78,68,32,67,79,78, +68,73,84,73,79,78,83,32,70,79,82,32,67,79,80,89, +73,78,71,44,32,68,73,83,84,82,73,66,85,84,73,79, +78,32,65,78,68,32,77,79,68,73,70,73,67,65,84,73, +79,78,60,47,115,116,114,111,110,103,62,60,98,114,62,10, +48,46,32,84,104,105,115,32,76,105,99,101,110,115,101,32, +97,112,112,108,105,101,115,32,116,111,32,97,110,121,32,112, +114,111,103,114,97,109,32,111,114,32,111,116,104,101,114,32, +119,111,114,107,32,119,104,105,99,104,32,99,111,110,116,97, +105,110,115,32,97,10,110,111,116,105,99,101,32,112,108,97, +99,101,100,32,98,121,32,116,104,101,32,99,111,112,121,114, +105,103,104,116,32,104,111,108,100,101,114,32,115,97,121,105, +110,103,32,105,116,32,109,97,121,32,98,101,32,100,105,115, +116,114,105,98,117,116,101,100,10,117,110,100,101,114,32,116, +104,101,32,116,101,114,109,115,32,111,102,32,116,104,105,115, +32,71,101,110,101,114,97,108,32,80,117,98,108,105,99,32, +76,105,99,101,110,115,101,46,32,32,84,104,101,32,34,80, +114,111,103,114,97,109,34,44,32,98,101,108,111,119,44,10, +114,101,102,101,114,115,32,116,111,32,97,110,121,32,115,117, +99,104,32,112,114,111,103,114,97,109,32,111,114,32,119,111, +114,107,44,32,97,110,100,32,97,32,34,119,111,114,107,32, +98,97,115,101,100,32,111,110,32,116,104,101,32,80,114,111, +103,114,97,109,34,10,109,101,97,110,115,32,101,105,116,104, +101,114,32,116,104,101,32,80,114,111,103,114,97,109,32,111, +114,32,97,110,121,32,100,101,114,105,118,97,116,105,118,101, +32,119,111,114,107,32,117,110,100,101,114,32,99,111,112,121, +114,105,103,104,116,32,108,97,119,58,10,116,104,97,116,32, +105,115,32,116,111,32,115,97,121,44,32,97,32,119,111,114, +107,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101, +32,80,114,111,103,114,97,109,32,111,114,32,97,32,112,111, +114,116,105,111,110,32,111,102,32,105,116,44,10,101,105,116, +104,101,114,32,118,101,114,98,97,116,105,109,32,111,114,32, +119,105,116,104,32,109,111,100,105,102,105,99,97,116,105,111, +110,115,32,97,110,100,47,111,114,32,116,114,97,110,115,108, +97,116,101,100,32,105,110,116,111,32,97,110,111,116,104,101, +114,10,108,97,110,103,117,97,103,101,46,32,32,40,72,101, +114,101,105,110,97,102,116,101,114,44,32,116,114,97,110,115, +108,97,116,105,111,110,32,105,115,32,105,110,99,108,117,100, +101,100,32,119,105,116,104,111,117,116,32,108,105,109,105,116, +97,116,105,111,110,32,105,110,10,116,104,101,32,116,101,114, +109,32,34,109,111,100,105,102,105,99,97,116,105,111,110,34, +46,41,32,32,69,97,99,104,32,108,105,99,101,110,115,101, +101,32,105,115,32,97,100,100,114,101,115,115,101,100,32,97, +115,32,34,121,111,117,34,46,10,60,112,62,10,65,99,116, +105,118,105,116,105,101,115,32,111,116,104,101,114,32,116,104, +97,110,32,99,111,112,121,105,110,103,44,32,100,105,115,116, +114,105,98,117,116,105,111,110,32,97,110,100,32,109,111,100, +105,102,105,99,97,116,105,111,110,32,97,114,101,32,110,111, +116,10,99,111,118,101,114,101,100,32,98,121,32,116,104,105, +115,32,76,105,99,101,110,115,101,59,32,116,104,101,121,32, +97,114,101,32,111,117,116,115,105,100,101,32,105,116,115,32, +115,99,111,112,101,46,32,32,84,104,101,32,97,99,116,32, +111,102,10,114,117,110,110,105,110,103,32,116,104,101,32,80, +114,111,103,114,97,109,32,105,115,32,110,111,116,32,114,101, +115,116,114,105,99,116,101,100,44,32,97,110,100,32,116,104, +101,32,111,117,116,112,117,116,32,102,114,111,109,32,116,104, +101,32,80,114,111,103,114,97,109,10,105,115,32,99,111,118, +101,114,101,100,32,111,110,108,121,32,105,102,32,105,116,115, +32,99,111,110,116,101,110,116,115,32,99,111,110,115,116,105, +116,117,116,101,32,97,32,119,111,114,107,32,98,97,115,101, +100,32,111,110,32,116,104,101,32,80,114,111,103,114,97,109, +10,40,105,110,100,101,112,101,110,100,101,110,116,32,111,102, +32,104,97,118,105,110,103,32,98,101,101,110,32,109,97,100, +101,32,98,121,32,114,117,110,110,105,110,103,32,116,104,101, +32,80,114,111,103,114,97,109,41,46,32,32,87,104,101,116, +104,101,114,10,116,104,97,116,32,105,115,32,116,114,117,101, +32,100,101,112,101,110,100,115,32,111,110,32,119,104,97,116, +32,116,104,101,32,80,114,111,103,114,97,109,32,100,111,101, +115,46,10,60,112,62,10,49,46,32,89,111,117,32,109,97, +121,32,99,111,112,121,32,97,110,100,32,100,105,115,116,114, +105,98,117,116,101,32,118,101,114,98,97,116,105,109,32,99, +111,112,105,101,115,32,111,102,32,116,104,101,32,80,114,111, +103,114,97,109,39,115,32,115,111,117,114,99,101,10,99,111, +100,101,32,97,115,32,121,111,117,32,114,101,99,101,105,118, +101,32,105,116,44,32,105,110,32,97,110,121,32,109,101,100, +105,117,109,44,32,112,114,111,118,105,100,101,100,32,116,104, +97,116,32,121,111,117,32,99,111,110,115,112,105,99,117,111, +117,115,108,121,10,97,110,100,32,97,112,112,114,111,112,114, +105,97,116,101,108,121,32,112,117,98,108,105,115,104,32,111, +110,32,101,97,99,104,32,99,111,112,121,32,97,110,32,97, +112,112,114,111,112,114,105,97,116,101,32,99,111,112,121,114, +105,103,104,116,32,110,111,116,105,99,101,10,97,110,100,32, +100,105,115,99,108,97,105,109,101,114,32,111,102,32,119,97, +114,114,97,110,116,121,59,32,107,101,101,112,32,105,110,116, +97,99,116,32,97,108,108,32,116,104,101,32,110,111,116,105, +99,101,115,32,116,104,97,116,32,114,101,102,101,114,32,116, +111,10,116,104,105,115,32,76,105,99,101,110,115,101,32,97, +110,100,32,116,111,32,116,104,101,32,97,98,115,101,110,99, +101,32,111,102,32,97,110,121,32,119,97,114,114,97,110,116, +121,59,32,97,110,100,32,103,105,118,101,32,97,110,121,32, +111,116,104,101,114,10,114,101,99,105,112,105,101,110,116,115, +32,111,102,32,116,104,101,32,80,114,111,103,114,97,109,32, +97,32,99,111,112,121,32,111,102,32,116,104,105,115,32,76, +105,99,101,110,115,101,32,97,108,111,110,103,32,119,105,116, +104,32,116,104,101,10,80,114,111,103,114,97,109,46,10,60, +112,62,10,89,111,117,32,109,97,121,32,99,104,97,114,103, +101,32,97,32,102,101,101,32,102,111,114,32,116,104,101,32, +112,104,121,115,105,99,97,108,32,97,99,116,32,111,102,32, +116,114,97,110,115,102,101,114,114,105,110,103,32,97,32,99, +111,112,121,44,32,97,110,100,10,121,111,117,32,109,97,121, +32,97,116,32,121,111,117,114,32,111,112,116,105,111,110,32, +111,102,102,101,114,32,119,97,114,114,97,110,116,121,32,112, +114,111,116,101,99,116,105,111,110,32,105,110,32,101,120,99, +104,97,110,103,101,32,102,111,114,32,97,10,102,101,101,46, +10,60,112,62,10,50,46,32,89,111,117,32,109,97,121,32, +109,111,100,105,102,121,32,121,111,117,114,32,99,111,112,121, +32,111,114,32,99,111,112,105,101,115,32,111,102,32,116,104, +101,32,80,114,111,103,114,97,109,32,111,114,32,97,110,121, +32,112,111,114,116,105,111,110,32,111,102,10,105,116,44,32, +116,104,117,115,32,102,111,114,109,105,110,103,32,97,32,119, +111,114,107,32,98,97,115,101,100,32,111,110,32,116,104,101, +32,80,114,111,103,114,97,109,44,32,97,110,100,32,99,111, +112,121,32,97,110,100,32,100,105,115,116,114,105,98,117,116, +101,10,115,117,99,104,32,109,111,100,105,102,105,99,97,116, +105,111,110,115,32,111,114,32,119,111,114,107,32,117,110,100, +101,114,32,116,104,101,32,116,101,114,109,115,32,111,102,32, +83,101,99,116,105,111,110,32,49,32,97,98,111,118,101,44, +10,112,114,111,118,105,100,101,100,32,116,104,97,116,32,121, +111,117,32,97,108,115,111,32,109,101,101,116,32,97,108,108, +32,111,102,32,116,104,101,115,101,32,99,111,110,100,105,116, +105,111,110,115,58,10,60,112,62,10,32,32,32,32,97,41, +32,89,111,117,32,109,117,115,116,32,99,97,117,115,101,32, +116,104,101,32,109,111,100,105,102,105,101,100,32,102,105,108, +101,115,32,116,111,32,99,97,114,114,121,32,112,114,111,109, +105,110,101,110,116,32,110,111,116,105,99,101,115,10,32,32, +32,32,115,116,97,116,105,110,103,32,116,104,97,116,32,121, +111,117,32,99,104,97,110,103,101,100,32,116,104,101,32,102, +105,108,101,115,32,97,110,100,32,116,104,101,32,100,97,116, +101,32,111,102,32,97,110,121,32,99,104,97,110,103,101,46, +10,60,112,62,10,32,32,32,32,98,41,32,89,111,117,32, +109,117,115,116,32,99,97,117,115,101,32,97,110,121,32,119, +111,114,107,32,116,104,97,116,32,121,111,117,32,100,105,115, +116,114,105,98,117,116,101,32,111,114,32,112,117,98,108,105, +115,104,44,32,116,104,97,116,32,105,110,10,32,32,32,32, +119,104,111,108,101,32,111,114,32,105,110,32,112,97,114,116, +32,99,111,110,116,97,105,110,115,32,111,114,32,105,115,32, +100,101,114,105,118,101,100,32,102,114,111,109,32,116,104,101, +32,80,114,111,103,114,97,109,32,111,114,32,97,110,121,10, +32,32,32,32,112,97,114,116,32,116,104,101,114,101,111,102, +44,32,116,111,32,98,101,32,108,105,99,101,110,115,101,100, +32,97,115,32,97,32,119,104,111,108,101,32,97,116,32,110, +111,32,99,104,97,114,103,101,32,116,111,32,97,108,108,32, +116,104,105,114,100,10,32,32,32,32,112,97,114,116,105,101, +115,32,117,110,100,101,114,32,116,104,101,32,116,101,114,109, +115,32,111,102,32,116,104,105,115,32,76,105,99,101,110,115, +101,46,10,60,112,62,10,32,32,32,32,99,41,32,73,102, +32,116,104,101,32,109,111,100,105,102,105,101,100,32,112,114, +111,103,114,97,109,32,110,111,114,109,97,108,108,121,32,114, +101,97,100,115,32,99,111,109,109,97,110,100,115,32,105,110, +116,101,114,97,99,116,105,118,101,108,121,10,32,32,32,32, +119,104,101,110,32,114,117,110,44,32,121,111,117,32,109,117, +115,116,32,99,97,117,115,101,32,105,116,44,32,119,104,101, +110,32,115,116,97,114,116,101,100,32,114,117,110,110,105,110, +103,32,102,111,114,32,115,117,99,104,10,32,32,32,32,105, +110,116,101,114,97,99,116,105,118,101,32,117,115,101,32,105, +110,32,116,104,101,32,109,111,115,116,32,111,114,100,105,110, +97,114,121,32,119,97,121,44,32,116,111,32,112,114,105,110, +116,32,111,114,32,100,105,115,112,108,97,121,32,97,110,10, +32,32,32,32,97,110,110,111,117,110,99,101,109,101,110,116, +32,105,110,99,108,117,100,105,110,103,32,97,110,32,97,112, +112,114,111,112,114,105,97,116,101,32,99,111,112,121,114,105, +103,104,116,32,110,111,116,105,99,101,32,97,110,100,32,97, +10,32,32,32,32,110,111,116,105,99,101,32,116,104,97,116, +32,116,104,101,114,101,32,105,115,32,110,111,32,119,97,114, +114,97,110,116,121,32,40,111,114,32,101,108,115,101,44,32, +115,97,121,105,110,103,32,116,104,97,116,32,121,111,117,32, +112,114,111,118,105,100,101,10,32,32,32,32,97,32,119,97, +114,114,97,110,116,121,41,32,97,110,100,32,116,104,97,116, +32,117,115,101,114,115,32,109,97,121,32,114,101,100,105,115, +116,114,105,98,117,116,101,32,116,104,101,32,112,114,111,103, +114,97,109,32,117,110,100,101,114,10,32,32,32,32,116,104, +101,115,101,32,99,111,110,100,105,116,105,111,110,115,44,32, +97,110,100,32,116,101,108,108,105,110,103,32,116,104,101,32, +117,115,101,114,32,104,111,119,32,116,111,32,118,105,101,119, +32,97,32,99,111,112,121,32,111,102,32,116,104,105,115,10, +32,32,32,32,76,105,99,101,110,115,101,46,32,32,40,69, +120,99,101,112,116,105,111,110,58,32,105,102,32,116,104,101, +32,80,114,111,103,114,97,109,32,105,116,115,101,108,102,32, +105,115,32,105,110,116,101,114,97,99,116,105,118,101,32,98, +117,116,10,32,32,32,32,100,111,101,115,32,110,111,116,32, +110,111,114,109,97,108,108,121,32,112,114,105,110,116,32,115, +117,99,104,32,97,110,32,97,110,110,111,117,110,99,101,109, +101,110,116,44,32,121,111,117,114,32,119,111,114,107,32,98, +97,115,101,100,32,111,110,10,32,32,32,32,116,104,101,32, +80,114,111,103,114,97,109,32,105,115,32,110,111,116,32,114, +101,113,117,105,114,101,100,32,116,111,32,112,114,105,110,116, +32,97,110,32,97,110,110,111,117,110,99,101,109,101,110,116, +46,41,10,60,112,62,10,84,104,101,115,101,32,114,101,113, +117,105,114,101,109,101,110,116,115,32,97,112,112,108,121,32, +116,111,32,116,104,101,32,109,111,100,105,102,105,101,100,32, +119,111,114,107,32,97,115,32,97,32,119,104,111,108,101,46, +32,32,73,102,10,105,100,101,110,116,105,102,105,97,98,108, +101,32,115,101,99,116,105,111,110,115,32,111,102,32,116,104, +97,116,32,119,111,114,107,32,97,114,101,32,110,111,116,32, +100,101,114,105,118,101,100,32,102,114,111,109,32,116,104,101, +32,80,114,111,103,114,97,109,44,10,97,110,100,32,99,97, +110,32,98,101,32,114,101,97,115,111,110,97,98,108,121,32, +99,111,110,115,105,100,101,114,101,100,32,105,110,100,101,112, +101,110,100,101,110,116,32,97,110,100,32,115,101,112,97,114, +97,116,101,32,119,111,114,107,115,32,105,110,10,116,104,101, +109,115,101,108,118,101,115,44,32,116,104,101,110,32,116,104, +105,115,32,76,105,99,101,110,115,101,44,32,97,110,100,32, +105,116,115,32,116,101,114,109,115,44,32,100,111,32,110,111, +116,32,97,112,112,108,121,32,116,111,32,116,104,111,115,101, +10,115,101,99,116,105,111,110,115,32,32,119,104,101,110,32, +121,111,117,32,100,105,115,116,114,105,98,117,116,101,32,116, +104,101,109,32,97,115,32,115,101,112,97,114,97,116,101,32, +119,111,114,107,115,46,32,32,66,117,116,32,119,104,101,110, +32,121,111,117,10,100,105,115,116,114,105,98,117,116,101,32, +116,104,101,32,115,97,109,101,32,115,101,99,116,105,111,110, +115,32,97,115,32,112,97,114,116,32,111,102,32,97,32,119, +104,111,108,101,32,119,104,105,99,104,32,105,115,32,97,32, +119,111,114,107,32,98,97,115,101,100,10,111,110,32,116,104, +101,32,80,114,111,103,114,97,109,44,32,116,104,101,32,100, +105,115,116,114,105,98,117,116,105,111,110,32,111,102,32,116, +104,101,32,119,104,111,108,101,32,109,117,115,116,32,98,101, +32,111,110,32,116,104,101,32,116,101,114,109,115,32,111,102, +10,116,104,105,115,32,76,105,99,101,110,115,101,44,32,119, +104,111,115,101,32,112,101,114,109,105,115,115,105,111,110,115, +32,102,111,114,32,111,116,104,101,114,32,108,105,99,101,110, +115,101,101,115,32,101,120,116,101,110,100,32,116,111,32,116, +104,101,10,101,110,116,105,114,101,32,119,104,111,108,101,44, +32,97,110,100,32,116,104,117,115,32,116,111,32,101,97,99, +104,32,97,110,100,32,101,118,101,114,121,32,112,97,114,116, +32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119, +104,111,32,119,114,111,116,101,10,105,116,46,10,60,112,62, +10,84,104,117,115,44,32,105,116,32,105,115,32,110,111,116, +32,116,104,101,32,105,110,116,101,110,116,32,111,102,32,116, +104,105,115,32,115,101,99,116,105,111,110,32,116,111,32,99, +108,97,105,109,32,114,105,103,104,116,115,32,111,114,32,99, +111,110,116,101,115,116,10,121,111,117,114,32,114,105,103,104, +116,115,32,116,111,32,119,111,114,107,32,119,114,105,116,116, +101,110,32,101,110,116,105,114,101,108,121,32,98,121,32,121, +111,117,59,32,114,97,116,104,101,114,44,32,116,104,101,32, +105,110,116,101,110,116,32,105,115,32,116,111,10,101,120,101, +114,99,105,115,101,32,116,104,101,32,114,105,103,104,116,32, +116,111,32,99,111,110,116,114,111,108,32,116,104,101,32,100, +105,115,116,114,105,98,117,116,105,111,110,32,111,102,32,100, +101,114,105,118,97,116,105,118,101,32,111,114,10,99,111,108, +108,101,99,116,105,118,101,32,119,111,114,107,115,32,98,97, +115,101,100,32,111,110,32,116,104,101,32,80,114,111,103,114, +97,109,46,10,60,112,62,10,73,110,32,97,100,100,105,116, +105,111,110,44,32,109,101,114,101,32,97,103,103,114,101,103, +97,116,105,111,110,32,111,102,32,97,110,111,116,104,101,114, +32,119,111,114,107,32,110,111,116,32,98,97,115,101,100,32, +111,110,32,116,104,101,32,80,114,111,103,114,97,109,10,119, +105,116,104,32,116,104,101,32,80,114,111,103,114,97,109,32, +40,111,114,32,119,105,116,104,32,97,32,119,111,114,107,32, +98,97,115,101,100,32,111,110,32,116,104,101,32,80,114,111, +103,114,97,109,41,32,111,110,32,97,32,118,111,108,117,109, +101,32,111,102,10,97,32,115,116,111,114,97,103,101,32,111, +114,32,100,105,115,116,114,105,98,117,116,105,111,110,32,109, +101,100,105,117,109,32,100,111,101,115,32,110,111,116,32,98, +114,105,110,103,32,116,104,101,32,111,116,104,101,114,32,119, +111,114,107,32,117,110,100,101,114,10,116,104,101,32,115,99, +111,112,101,32,111,102,32,116,104,105,115,32,76,105,99,101, +110,115,101,46,10,60,112,62,10,51,46,32,89,111,117,32, +109,97,121,32,99,111,112,121,32,97,110,100,32,100,105,115, +116,114,105,98,117,116,101,32,116,104,101,32,80,114,111,103, +114,97,109,32,40,111,114,32,97,32,119,111,114,107,32,98, +97,115,101,100,32,111,110,32,105,116,44,10,117,110,100,101, +114,32,83,101,99,116,105,111,110,32,50,41,32,105,110,32, +111,98,106,101,99,116,32,99,111,100,101,32,111,114,32,101, +120,101,99,117,116,97,98,108,101,32,102,111,114,109,32,117, +110,100,101,114,32,116,104,101,32,116,101,114,109,115,32,111, +102,10,83,101,99,116,105,111,110,115,32,49,32,97,110,100, +32,50,32,97,98,111,118,101,32,112,114,111,118,105,100,101, +100,32,116,104,97,116,32,121,111,117,32,97,108,115,111,32, +100,111,32,111,110,101,32,111,102,32,116,104,101,32,102,111, +108,108,111,119,105,110,103,58,10,60,112,62,10,32,32,32, +32,97,41,32,65,99,99,111,109,112,97,110,121,32,105,116, +32,119,105,116,104,32,116,104,101,32,99,111,109,112,108,101, +116,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103, +32,109,97,99,104,105,110,101,45,114,101,97,100,97,98,108, +101,10,32,32,32,32,115,111,117,114,99,101,32,99,111,100, +101,44,32,119,104,105,99,104,32,109,117,115,116,32,98,101, +32,100,105,115,116,114,105,98,117,116,101,100,32,117,110,100, +101,114,32,116,104,101,32,116,101,114,109,115,32,111,102,32, +83,101,99,116,105,111,110,115,10,32,32,32,32,49,32,97, +110,100,32,50,32,97,98,111,118,101,32,111,110,32,97,32, +109,101,100,105,117,109,32,99,117,115,116,111,109,97,114,105, +108,121,32,117,115,101,100,32,102,111,114,32,115,111,102,116, +119,97,114,101,32,105,110,116,101,114,99,104,97,110,103,101, +59,32,111,114,44,10,60,112,62,10,32,32,32,32,98,41, +32,65,99,99,111,109,112,97,110,121,32,105,116,32,119,105, +116,104,32,97,32,119,114,105,116,116,101,110,32,111,102,102, +101,114,44,32,118,97,108,105,100,32,102,111,114,32,97,116, +32,108,101,97,115,116,32,116,104,114,101,101,10,32,32,32, +32,121,101,97,114,115,44,32,116,111,32,103,105,118,101,32, +97,110,121,32,116,104,105,114,100,32,112,97,114,116,121,44, +32,102,111,114,32,97,32,99,104,97,114,103,101,32,110,111, +32,109,111,114,101,32,116,104,97,110,32,121,111,117,114,10, +32,32,32,32,99,111,115,116,32,111,102,32,112,104,121,115, +105,99,97,108,108,121,32,112,101,114,102,111,114,109,105,110, +103,32,115,111,117,114,99,101,32,100,105,115,116,114,105,98, +117,116,105,111,110,44,32,97,32,99,111,109,112,108,101,116, +101,10,32,32,32,32,109,97,99,104,105,110,101,45,114,101, +97,100,97,98,108,101,32,99,111,112,121,32,111,102,32,116, +104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103, +32,115,111,117,114,99,101,32,99,111,100,101,44,32,116,111, +32,98,101,10,32,32,32,32,100,105,115,116,114,105,98,117, +116,101,100,32,117,110,100,101,114,32,116,104,101,32,116,101, +114,109,115,32,111,102,32,83,101,99,116,105,111,110,115,32, +49,32,97,110,100,32,50,32,97,98,111,118,101,32,111,110, +32,97,32,109,101,100,105,117,109,10,32,32,32,32,99,117, +115,116,111,109,97,114,105,108,121,32,117,115,101,100,32,102, +111,114,32,115,111,102,116,119,97,114,101,32,105,110,116,101, +114,99,104,97,110,103,101,59,32,111,114,44,10,60,112,62, +10,32,32,32,32,99,41,32,65,99,99,111,109,112,97,110, +121,32,105,116,32,119,105,116,104,32,116,104,101,32,105,110, +102,111,114,109,97,116,105,111,110,32,121,111,117,32,114,101, +99,101,105,118,101,100,32,97,115,32,116,111,32,116,104,101, +32,111,102,102,101,114,10,32,32,32,32,116,111,32,100,105, +115,116,114,105,98,117,116,101,32,99,111,114,114,101,115,112, +111,110,100,105,110,103,32,115,111,117,114,99,101,32,99,111, +100,101,46,32,32,40,84,104,105,115,32,97,108,116,101,114, +110,97,116,105,118,101,32,105,115,10,32,32,32,32,97,108, +108,111,119,101,100,32,111,110,108,121,32,102,111,114,32,110, +111,110,99,111,109,109,101,114,99,105,97,108,32,100,105,115, +116,114,105,98,117,116,105,111,110,32,97,110,100,32,111,110, +108,121,32,105,102,32,121,111,117,10,32,32,32,32,114,101, +99,101,105,118,101,100,32,116,104,101,32,112,114,111,103,114, +97,109,32,105,110,32,111,98,106,101,99,116,32,99,111,100, +101,32,111,114,32,101,120,101,99,117,116,97,98,108,101,32, +102,111,114,109,32,119,105,116,104,32,115,117,99,104,10,32, +32,32,32,97,110,32,111,102,102,101,114,44,32,105,110,32, +97,99,99,111,114,100,32,119,105,116,104,32,83,117,98,115, +101,99,116,105,111,110,32,98,32,97,98,111,118,101,46,41, +10,60,112,62,10,84,104,101,32,115,111,117,114,99,101,32, +99,111,100,101,32,102,111,114,32,97,32,119,111,114,107,32, +109,101,97,110,115,32,116,104,101,32,112,114,101,102,101,114, +114,101,100,32,102,111,114,109,32,111,102,32,116,104,101,32, +119,111,114,107,32,102,111,114,10,109,97,107,105,110,103,32, +109,111,100,105,102,105,99,97,116,105,111,110,115,32,116,111, +32,105,116,46,32,32,70,111,114,32,97,110,32,101,120,101, +99,117,116,97,98,108,101,32,119,111,114,107,44,32,99,111, +109,112,108,101,116,101,32,115,111,117,114,99,101,10,99,111, +100,101,32,109,101,97,110,115,32,97,108,108,32,116,104,101, +32,115,111,117,114,99,101,32,99,111,100,101,32,102,111,114, +32,97,108,108,32,109,111,100,117,108,101,115,32,105,116,32, +99,111,110,116,97,105,110,115,44,32,112,108,117,115,32,97, +110,121,10,97,115,115,111,99,105,97,116,101,100,32,105,110, +116,101,114,102,97,99,101,32,100,101,102,105,110,105,116,105, +111,110,32,102,105,108,101,115,44,32,112,108,117,115,32,116, +104,101,32,115,99,114,105,112,116,115,32,117,115,101,100,32, +116,111,10,99,111,110,116,114,111,108,32,99,111,109,112,105, +108,97,116,105,111,110,32,97,110,100,32,105,110,115,116,97, +108,108,97,116,105,111,110,32,111,102,32,116,104,101,32,101, +120,101,99,117,116,97,98,108,101,46,32,32,72,111,119,101, +118,101,114,44,32,97,115,32,97,10,115,112,101,99,105,97, +108,32,101,120,99,101,112,116,105,111,110,44,32,116,104,101, +32,115,111,117,114,99,101,32,99,111,100,101,32,100,105,115, +116,114,105,98,117,116,101,100,32,110,101,101,100,32,110,111, +116,32,105,110,99,108,117,100,101,10,97,110,121,116,104,105, +110,103,32,116,104,97,116,32,105,115,32,110,111,114,109,97, +108,108,121,32,100,105,115,116,114,105,98,117,116,101,100,32, +40,105,110,32,101,105,116,104,101,114,32,115,111,117,114,99, +101,32,111,114,32,98,105,110,97,114,121,10,102,111,114,109, +41,32,119,105,116,104,32,116,104,101,32,109,97,106,111,114, +32,99,111,109,112,111,110,101,110,116,115,32,40,99,111,109, +112,105,108,101,114,44,32,107,101,114,110,101,108,44,32,97, +110,100,32,115,111,32,111,110,41,32,111,102,32,116,104,101, +10,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101, +109,32,111,110,32,119,104,105,99,104,32,116,104,101,32,101, +120,101,99,117,116,97,98,108,101,32,114,117,110,115,44,32, +117,110,108,101,115,115,32,116,104,97,116,32,99,111,109,112, +111,110,101,110,116,10,105,116,115,101,108,102,32,97,99,99, +111,109,112,97,110,105,101,115,32,116,104,101,32,101,120,101, +99,117,116,97,98,108,101,46,10,60,112,62,10,73,102,32, +100,105,115,116,114,105,98,117,116,105,111,110,32,111,102,32, +101,120,101,99,117,116,97,98,108,101,32,111,114,32,111,98, +106,101,99,116,32,99,111,100,101,32,105,115,32,109,97,100, +101,32,98,121,32,111,102,102,101,114,105,110,103,10,97,99, +99,101,115,115,32,116,111,32,99,111,112,121,32,102,114,111, +109,32,97,32,100,101,115,105,103,110,97,116,101,100,32,112, +108,97,99,101,44,32,116,104,101,110,32,111,102,102,101,114, +105,110,103,32,101,113,117,105,118,97,108,101,110,116,10,97, +99,99,101,115,115,32,116,111,32,99,111,112,121,32,116,104, +101,32,115,111,117,114,99,101,32,99,111,100,101,32,102,114, +111,109,32,116,104,101,32,115,97,109,101,32,112,108,97,99, +101,32,99,111,117,110,116,115,32,97,115,10,100,105,115,116, +114,105,98,117,116,105,111,110,32,111,102,32,116,104,101,32, +115,111,117,114,99,101,32,99,111,100,101,44,32,101,118,101, +110,32,116,104,111,117,103,104,32,116,104,105,114,100,32,112, +97,114,116,105,101,115,32,97,114,101,32,110,111,116,10,99, +111,109,112,101,108,108,101,100,32,116,111,32,99,111,112,121, +32,116,104,101,32,115,111,117,114,99,101,32,97,108,111,110, +103,32,119,105,116,104,32,116,104,101,32,111,98,106,101,99, +116,32,99,111,100,101,46,10,60,112,62,10,52,46,32,89, +111,117,32,109,97,121,32,110,111,116,32,99,111,112,121,44, +32,109,111,100,105,102,121,44,32,115,117,98,108,105,99,101, +110,115,101,44,32,111,114,32,100,105,115,116,114,105,98,117, +116,101,32,116,104,101,32,80,114,111,103,114,97,109,10,101, +120,99,101,112,116,32,97,115,32,101,120,112,114,101,115,115, +108,121,32,112,114,111,118,105,100,101,100,32,117,110,100,101, +114,32,116,104,105,115,32,76,105,99,101,110,115,101,46,32, +32,65,110,121,32,97,116,116,101,109,112,116,10,111,116,104, +101,114,119,105,115,101,32,116,111,32,99,111,112,121,44,32, +109,111,100,105,102,121,44,32,115,117,98,108,105,99,101,110, +115,101,32,111,114,32,100,105,115,116,114,105,98,117,116,101, +32,116,104,101,32,80,114,111,103,114,97,109,32,105,115,10, +118,111,105,100,44,32,97,110,100,32,119,105,108,108,32,97, +117,116,111,109,97,116,105,99,97,108,108,121,32,116,101,114, +109,105,110,97,116,101,32,121,111,117,114,32,114,105,103,104, +116,115,32,117,110,100,101,114,32,116,104,105,115,32,76,105, +99,101,110,115,101,46,10,72,111,119,101,118,101,114,44,32, +112,97,114,116,105,101,115,32,119,104,111,32,104,97,118,101, +32,114,101,99,101,105,118,101,100,32,99,111,112,105,101,115, +44,32,111,114,32,114,105,103,104,116,115,44,32,102,114,111, +109,32,121,111,117,32,117,110,100,101,114,10,116,104,105,115, +32,76,105,99,101,110,115,101,32,119,105,108,108,32,110,111, +116,32,104,97,118,101,32,116,104,101,105,114,32,108,105,99, +101,110,115,101,115,32,116,101,114,109,105,110,97,116,101,100, +32,115,111,32,108,111,110,103,32,97,115,32,115,117,99,104, +10,112,97,114,116,105,101,115,32,114,101,109,97,105,110,32, +105,110,32,102,117,108,108,32,99,111,109,112,108,105,97,110, +99,101,46,10,60,112,62,10,53,46,32,89,111,117,32,97, +114,101,32,110,111,116,32,114,101,113,117,105,114,101,100,32, +116,111,32,97,99,99,101,112,116,32,116,104,105,115,32,76, +105,99,101,110,115,101,44,32,115,105,110,99,101,32,121,111, +117,32,104,97,118,101,32,110,111,116,10,115,105,103,110,101, +100,32,105,116,46,32,32,72,111,119,101,118,101,114,44,32, +110,111,116,104,105,110,103,32,101,108,115,101,32,103,114,97, +110,116,115,32,121,111,117,32,112,101,114,109,105,115,115,105, +111,110,32,116,111,32,109,111,100,105,102,121,32,111,114,10, +100,105,115,116,114,105,98,117,116,101,32,116,104,101,32,80, +114,111,103,114,97,109,32,111,114,32,105,116,115,32,100,101, +114,105,118,97,116,105,118,101,32,119,111,114,107,115,46,32, +32,84,104,101,115,101,32,97,99,116,105,111,110,115,32,97, +114,101,10,112,114,111,104,105,98,105,116,101,100,32,98,121, +32,108,97,119,32,105,102,32,121,111,117,32,100,111,32,110, +111,116,32,97,99,99,101,112,116,32,116,104,105,115,32,76, +105,99,101,110,115,101,46,32,32,84,104,101,114,101,102,111, +114,101,44,32,98,121,10,109,111,100,105,102,121,105,110,103, +32,111,114,32,100,105,115,116,114,105,98,117,116,105,110,103, +32,116,104,101,32,80,114,111,103,114,97,109,32,40,111,114, +32,97,110,121,32,119,111,114,107,32,98,97,115,101,100,32, +111,110,32,116,104,101,10,80,114,111,103,114,97,109,41,44, +32,121,111,117,32,105,110,100,105,99,97,116,101,32,121,111, +117,114,32,97,99,99,101,112,116,97,110,99,101,32,111,102, +32,116,104,105,115,32,76,105,99,101,110,115,101,32,116,111, +32,100,111,32,115,111,44,32,97,110,100,10,97,108,108,32, +105,116,115,32,116,101,114,109,115,32,97,110,100,32,99,111, +110,100,105,116,105,111,110,115,32,102,111,114,32,99,111,112, +121,105,110,103,44,32,100,105,115,116,114,105,98,117,116,105, +110,103,32,111,114,32,109,111,100,105,102,121,105,110,103,10, +116,104,101,32,80,114,111,103,114,97,109,32,111,114,32,119, +111,114,107,115,32,98,97,115,101,100,32,111,110,32,105,116, +46,10,60,112,62,10,54,46,32,69,97,99,104,32,116,105, +109,101,32,121,111,117,32,114,101,100,105,115,116,114,105,98, +117,116,101,32,116,104,101,32,80,114,111,103,114,97,109,32, +40,111,114,32,97,110,121,32,119,111,114,107,32,98,97,115, +101,100,32,111,110,32,116,104,101,10,80,114,111,103,114,97, +109,41,44,32,116,104,101,32,114,101,99,105,112,105,101,110, +116,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32, +114,101,99,101,105,118,101,115,32,97,32,108,105,99,101,110, +115,101,32,102,114,111,109,32,116,104,101,10,111,114,105,103, +105,110,97,108,32,108,105,99,101,110,115,111,114,32,116,111, +32,99,111,112,121,44,32,100,105,115,116,114,105,98,117,116, +101,32,111,114,32,109,111,100,105,102,121,32,116,104,101,32, +80,114,111,103,114,97,109,32,115,117,98,106,101,99,116,32, +116,111,10,116,104,101,115,101,32,116,101,114,109,115,32,97, +110,100,32,99,111,110,100,105,116,105,111,110,115,46,32,32, +89,111,117,32,109,97,121,32,110,111,116,32,105,109,112,111, +115,101,32,97,110,121,32,102,117,114,116,104,101,114,10,114, +101,115,116,114,105,99,116,105,111,110,115,32,111,110,32,116, +104,101,32,114,101,99,105,112,105,101,110,116,115,39,32,101, +120,101,114,99,105,115,101,32,111,102,32,116,104,101,32,114, +105,103,104,116,115,32,103,114,97,110,116,101,100,32,104,101, +114,101,105,110,46,10,89,111,117,32,97,114,101,32,110,111, +116,32,114,101,115,112,111,110,115,105,98,108,101,32,102,111, +114,32,101,110,102,111,114,99,105,110,103,32,99,111,109,112, +108,105,97,110,99,101,32,98,121,32,116,104,105,114,100,32, +112,97,114,116,105,101,115,32,116,111,10,116,104,105,115,32, +76,105,99,101,110,115,101,46,10,60,112,62,10,55,46,32, +73,102,44,32,97,115,32,97,32,99,111,110,115,101,113,117, +101,110,99,101,32,111,102,32,97,32,99,111,117,114,116,32, +106,117,100,103,109,101,110,116,32,111,114,32,97,108,108,101, +103,97,116,105,111,110,32,111,102,32,112,97,116,101,110,116, +10,105,110,102,114,105,110,103,101,109,101,110,116,32,111,114, +32,102,111,114,32,97,110,121,32,111,116,104,101,114,32,114, +101,97,115,111,110,32,40,110,111,116,32,108,105,109,105,116, +101,100,32,116,111,32,112,97,116,101,110,116,32,105,115,115, +117,101,115,41,44,10,99,111,110,100,105,116,105,111,110,115, +32,97,114,101,32,105,109,112,111,115,101,100,32,111,110,32, +121,111,117,32,40,119,104,101,116,104,101,114,32,98,121,32, +99,111,117,114,116,32,111,114,100,101,114,44,32,97,103,114, +101,101,109,101,110,116,32,111,114,32,10,111,116,104,101,114, +119,105,115,101,41,32,116,104,97,116,32,99,111,110,116,114, +97,100,105,99,116,32,116,104,101,32,99,111,110,100,105,116, +105,111,110,115,32,111,102,32,116,104,105,115,32,76,105,99, +101,110,115,101,44,32,116,104,101,121,32,100,111,32,110,111, +116,10,101,120,99,117,115,101,32,121,111,117,32,102,114,111, +109,32,116,104,101,32,99,111,110,100,105,116,105,111,110,115, +32,111,102,32,116,104,105,115,32,76,105,99,101,110,115,101, +46,32,32,73,102,32,121,111,117,32,99,97,110,110,111,116, +10,100,105,115,116,114,105,98,117,116,101,32,115,111,32,97, +115,32,116,111,32,115,97,116,105,115,102,121,32,115,105,109, +117,108,116,97,110,101,111,117,115,108,121,32,121,111,117,114, +32,111,98,108,105,103,97,116,105,111,110,115,32,117,110,100, +101,114,32,116,104,105,115,10,76,105,99,101,110,115,101,32, +97,110,100,32,97,110,121,32,111,116,104,101,114,32,112,101, +114,116,105,110,101,110,116,32,111,98,108,105,103,97,116,105, +111,110,115,44,32,116,104,101,110,32,97,115,32,97,32,99, +111,110,115,101,113,117,101,110,99,101,32,121,111,117,10,109, +97,121,32,110,111,116,32,100,105,115,116,114,105,98,117,116, +101,32,116,104,101,32,80,114,111,103,114,97,109,32,97,116, +32,97,108,108,46,32,32,70,111,114,32,101,120,97,109,112, +108,101,44,32,105,102,32,97,32,112,97,116,101,110,116,10, +108,105,99,101,110,115,101,32,119,111,117,108,100,32,110,111, +116,32,112,101,114,109,105,116,32,114,111,121,97,108,116,121, +45,102,114,101,101,32,114,101,100,105,115,116,114,105,98,117, +116,105,111,110,32,111,102,32,116,104,101,32,80,114,111,103, +114,97,109,32,98,121,10,97,108,108,32,116,104,111,115,101, +32,119,104,111,32,114,101,99,101,105,118,101,32,99,111,112, +105,101,115,32,100,105,114,101,99,116,108,121,32,111,114,32, +105,110,100,105,114,101,99,116,108,121,32,116,104,114,111,117, +103,104,32,121,111,117,44,32,116,104,101,110,10,116,104,101, +32,111,110,108,121,32,119,97,121,32,121,111,117,32,99,111, +117,108,100,32,115,97,116,105,115,102,121,32,98,111,116,104, +32,105,116,32,97,110,100,32,116,104,105,115,32,76,105,99, +101,110,115,101,32,119,111,117,108,100,32,98,101,32,116,111, +10,114,101,102,114,97,105,110,32,101,110,116,105,114,101,108, +121,32,102,114,111,109,32,100,105,115,116,114,105,98,117,116, +105,111,110,32,111,102,32,116,104,101,32,80,114,111,103,114, +97,109,46,10,60,112,62,10,73,102,32,97,110,121,32,112, +111,114,116,105,111,110,32,111,102,32,116,104,105,115,32,115, +101,99,116,105,111,110,32,105,115,32,104,101,108,100,32,105, +110,118,97,108,105,100,32,111,114,32,117,110,101,110,102,111, +114,99,101,97,98,108,101,32,117,110,100,101,114,10,97,110, +121,32,112,97,114,116,105,99,117,108,97,114,32,99,105,114, +99,117,109,115,116,97,110,99,101,44,32,116,104,101,32,98, +97,108,97,110,99,101,32,111,102,32,116,104,101,32,115,101, +99,116,105,111,110,32,105,115,32,105,110,116,101,110,100,101, +100,32,116,111,10,97,112,112,108,121,32,97,110,100,32,116, +104,101,32,115,101,99,116,105,111,110,32,97,115,32,97,32, +119,104,111,108,101,32,105,115,32,105,110,116,101,110,100,101, +100,32,116,111,32,97,112,112,108,121,32,105,110,32,111,116, +104,101,114,10,99,105,114,99,117,109,115,116,97,110,99,101, +115,46,10,60,112,62,10,73,116,32,105,115,32,110,111,116, +32,116,104,101,32,112,117,114,112,111,115,101,32,111,102,32, +116,104,105,115,32,115,101,99,116,105,111,110,32,116,111,32, +105,110,100,117,99,101,32,121,111,117,32,116,111,32,105,110, +102,114,105,110,103,101,32,97,110,121,10,112,97,116,101,110, +116,115,32,111,114,32,111,116,104,101,114,32,112,114,111,112, +101,114,116,121,32,114,105,103,104,116,32,99,108,97,105,109, +115,32,111,114,32,116,111,32,99,111,110,116,101,115,116,32, +118,97,108,105,100,105,116,121,32,111,102,32,97,110,121,10, +115,117,99,104,32,99,108,97,105,109,115,59,32,116,104,105, +115,32,115,101,99,116,105,111,110,32,104,97,115,32,116,104, +101,32,115,111,108,101,32,112,117,114,112,111,115,101,32,111, +102,32,112,114,111,116,101,99,116,105,110,103,32,116,104,101, +10,105,110,116,101,103,114,105,116,121,32,111,102,32,116,104, +101,32,102,114,101,101,32,115,111,102,116,119,97,114,101,32, +100,105,115,116,114,105,98,117,116,105,111,110,32,115,121,115, +116,101,109,44,32,119,104,105,99,104,32,105,115,10,105,109, +112,108,101,109,101,110,116,101,100,32,98,121,32,112,117,98, +108,105,99,32,108,105,99,101,110,115,101,32,112,114,97,99, +116,105,99,101,115,46,32,32,77,97,110,121,32,112,101,111, +112,108,101,32,104,97,118,101,32,109,97,100,101,10,103,101, +110,101,114,111,117,115,32,99,111,110,116,114,105,98,117,116, +105,111,110,115,32,116,111,32,116,104,101,32,119,105,100,101, +32,114,97,110,103,101,32,111,102,32,115,111,102,116,119,97, +114,101,32,100,105,115,116,114,105,98,117,116,101,100,10,116, +104,114,111,117,103,104,32,116,104,97,116,32,115,121,115,116, +101,109,32,105,110,32,114,101,108,105,97,110,99,101,32,111, +110,32,99,111,110,115,105,115,116,101,110,116,32,97,112,112, +108,105,99,97,116,105,111,110,32,111,102,32,116,104,97,116, +10,115,121,115,116,101,109,59,32,105,116,32,105,115,32,117, +112,32,116,111,32,116,104,101,32,97,117,116,104,111,114,47, +100,111,110,111,114,32,116,111,32,100,101,99,105,100,101,32, +105,102,32,104,101,32,111,114,32,115,104,101,32,105,115,32, +119,105,108,108,105,110,103,10,116,111,32,100,105,115,116,114, +105,98,117,116,101,32,115,111,102,116,119,97,114,101,32,116, +104,114,111,117,103,104,32,97,110,121,32,111,116,104,101,114, +32,115,121,115,116,101,109,32,97,110,100,32,97,32,108,105, +99,101,110,115,101,101,32,99,97,110,110,111,116,10,105,109, +112,111,115,101,32,116,104,97,116,32,99,104,111,105,99,101, +46,10,60,112,62,10,84,104,105,115,32,115,101,99,116,105, +111,110,32,105,115,32,105,110,116,101,110,100,101,100,32,116, +111,32,109,97,107,101,32,116,104,111,114,111,117,103,104,108, +121,32,99,108,101,97,114,32,119,104,97,116,32,105,115,32, +98,101,108,105,101,118,101,100,32,116,111,10,98,101,32,97, +32,99,111,110,115,101,113,117,101,110,99,101,32,111,102,32, +116,104,101,32,114,101,115,116,32,111,102,32,116,104,105,115, +32,76,105,99,101,110,115,101,46,10,60,112,62,10,56,46, +32,73,102,32,116,104,101,32,100,105,115,116,114,105,98,117, +116,105,111,110,32,97,110,100,47,111,114,32,117,115,101,32, +111,102,32,116,104,101,32,80,114,111,103,114,97,109,32,105, +115,32,114,101,115,116,114,105,99,116,101,100,32,105,110,10, +99,101,114,116,97,105,110,32,99,111,117,110,116,114,105,101, +115,32,101,105,116,104,101,114,32,98,121,32,112,97,116,101, +110,116,115,32,111,114,32,98,121,32,99,111,112,121,114,105, +103,104,116,101,100,32,105,110,116,101,114,102,97,99,101,115, +44,32,116,104,101,10,111,114,105,103,105,110,97,108,32,99, +111,112,121,114,105,103,104,116,32,104,111,108,100,101,114,32, +119,104,111,32,112,108,97,99,101,115,32,116,104,101,32,80, +114,111,103,114,97,109,32,117,110,100,101,114,32,116,104,105, +115,32,76,105,99,101,110,115,101,10,109,97,121,32,97,100, +100,32,97,110,32,101,120,112,108,105,99,105,116,32,103,101, +111,103,114,97,112,104,105,99,97,108,32,100,105,115,116,114, +105,98,117,116,105,111,110,32,108,105,109,105,116,97,116,105, +111,110,32,101,120,99,108,117,100,105,110,103,10,116,104,111, +115,101,32,99,111,117,110,116,114,105,101,115,44,32,115,111, +32,116,104,97,116,32,100,105,115,116,114,105,98,117,116,105, +111,110,32,105,115,32,112,101,114,109,105,116,116,101,100,32, +111,110,108,121,32,105,110,32,111,114,32,97,109,111,110,103, +10,99,111,117,110,116,114,105,101,115,32,110,111,116,32,116, +104,117,115,32,101,120,99,108,117,100,101,100,46,32,32,73, +110,32,115,117,99,104,32,99,97,115,101,44,32,116,104,105, +115,32,76,105,99,101,110,115,101,32,105,110,99,111,114,112, +111,114,97,116,101,115,10,116,104,101,32,108,105,109,105,116, +97,116,105,111,110,32,97,115,32,105,102,32,119,114,105,116, +116,101,110,32,105,110,32,116,104,101,32,98,111,100,121,32, +111,102,32,116,104,105,115,32,76,105,99,101,110,115,101,46, +10,60,112,62,10,57,46,32,84,104,101,32,70,114,101,101, +32,83,111,102,116,119,97,114,101,32,70,111,117,110,100,97, +116,105,111,110,32,109,97,121,32,112,117,98,108,105,115,104, +32,114,101,118,105,115,101,100,32,97,110,100,47,111,114,32, +110,101,119,10,118,101,114,115,105,111,110,115,32,111,102,32, +116,104,101,32,71,101,110,101,114,97,108,32,80,117,98,108, +105,99,32,76,105,99,101,110,115,101,32,102,114,111,109,32, +116,105,109,101,32,116,111,32,116,105,109,101,46,32,32,83, +117,99,104,32,110,101,119,10,118,101,114,115,105,111,110,115, +32,119,105,108,108,32,98,101,32,115,105,109,105,108,97,114, +32,105,110,32,115,112,105,114,105,116,32,116,111,32,116,104, +101,32,112,114,101,115,101,110,116,32,118,101,114,115,105,111, +110,44,32,98,117,116,32,109,97,121,10,100,105,102,102,101, +114,32,105,110,32,100,101,116,97,105,108,32,116,111,32,97, +100,100,114,101,115,115,32,110,101,119,32,112,114,111,98,108, +101,109,115,32,111,114,32,99,111,110,99,101,114,110,115,46, +10,60,112,62,10,69,97,99,104,32,118,101,114,115,105,111, +110,32,105,115,32,103,105,118,101,110,32,97,32,100,105,115, +116,105,110,103,117,105,115,104,105,110,103,32,118,101,114,115, +105,111,110,32,110,117,109,98,101,114,46,32,32,73,102,32, +116,104,101,32,80,114,111,103,114,97,109,10,115,112,101,99, +105,102,105,101,115,32,97,32,118,101,114,115,105,111,110,32, +110,117,109,98,101,114,32,111,102,32,116,104,105,115,32,76, +105,99,101,110,115,101,32,119,104,105,99,104,32,97,112,112, +108,105,101,115,32,116,111,32,105,116,32,97,110,100,10,34, +97,110,121,32,108,97,116,101,114,32,118,101,114,115,105,111, +110,34,44,32,121,111,117,32,104,97,118,101,32,116,104,101, +32,111,112,116,105,111,110,32,111,102,32,102,111,108,108,111, +119,105,110,103,32,116,104,101,32,116,101,114,109,115,32,97, +110,100,10,99,111,110,100,105,116,105,111,110,115,32,101,105, +116,104,101,114,32,111,102,32,116,104,97,116,32,118,101,114, +115,105,111,110,32,111,114,32,111,102,32,97,110,121,32,108, +97,116,101,114,32,118,101,114,115,105,111,110,32,112,117,98, +108,105,115,104,101,100,32,98,121,10,116,104,101,32,70,114, +101,101,32,83,111,102,116,119,97,114,101,32,70,111,117,110, +100,97,116,105,111,110,46,32,32,73,102,32,116,104,101,32, +80,114,111,103,114,97,109,32,100,111,101,115,32,110,111,116, +32,115,112,101,99,105,102,121,32,97,10,118,101,114,115,105, +111,110,32,110,117,109,98,101,114,32,111,102,32,116,104,105, +115,32,76,105,99,101,110,115,101,44,32,121,111,117,32,109, +97,121,32,99,104,111,111,115,101,32,97,110,121,32,118,101, +114,115,105,111,110,32,101,118,101,114,10,112,117,98,108,105, +115,104,101,100,32,98,121,32,116,104,101,32,70,114,101,101, +32,83,111,102,116,119,97,114,101,32,70,111,117,110,100,97, +116,105,111,110,46,10,60,112,62,10,49,48,46,32,73,102, +32,121,111,117,32,119,105,115,104,32,116,111,32,105,110,99, +111,114,112,111,114,97,116,101,32,112,97,114,116,115,32,111, +102,32,116,104,101,32,80,114,111,103,114,97,109,32,105,110, +116,111,32,111,116,104,101,114,32,102,114,101,101,10,112,114, +111,103,114,97,109,115,32,119,104,111,115,101,32,100,105,115, +116,114,105,98,117,116,105,111,110,32,99,111,110,100,105,116, +105,111,110,115,32,97,114,101,32,100,105,102,102,101,114,101, +110,116,44,32,119,114,105,116,101,32,116,111,32,116,104,101, +10,97,117,116,104,111,114,32,116,111,32,97,115,107,32,102, +111,114,32,112,101,114,109,105,115,115,105,111,110,46,32,32, +70,111,114,32,115,111,102,116,119,97,114,101,32,119,104,105, +99,104,32,105,115,32,99,111,112,121,114,105,103,104,116,101, +100,32,98,121,10,116,104,101,32,70,114,101,101,32,83,111, +102,116,119,97,114,101,32,70,111,117,110,100,97,116,105,111, +110,44,32,119,114,105,116,101,32,116,111,32,116,104,101,32, +70,114,101,101,32,83,111,102,116,119,97,114,101,32,70,111, +117,110,100,97,116,105,111,110,59,10,119,101,32,115,111,109, +101,116,105,109,101,115,32,109,97,107,101,32,101,120,99,101, +112,116,105,111,110,115,32,102,111,114,32,116,104,105,115,46, +32,32,79,117,114,32,100,101,99,105,115,105,111,110,32,119, +105,108,108,32,98,101,32,103,117,105,100,101,100,32,98,121, +10,116,104,101,32,116,119,111,32,103,111,97,108,115,32,111, +102,32,112,114,101,115,101,114,118,105,110,103,32,116,104,101, +32,102,114,101,101,32,115,116,97,116,117,115,32,111,102,32, +97,108,108,32,100,101,114,105,118,97,116,105,118,101,115,32, +111,102,32,111,117,114,10,102,114,101,101,32,115,111,102,116, +119,97,114,101,32,97,110,100,32,111,102,32,112,114,111,109, +111,116,105,110,103,32,116,104,101,32,115,104,97,114,105,110, +103,32,97,110,100,32,114,101,117,115,101,32,111,102,32,115, +111,102,116,119,97,114,101,10,103,101,110,101,114,97,108,108, +121,46,10,60,112,62,10,60,115,116,114,111,110,103,62,78, +79,32,87,65,82,82,65,78,84,89,60,47,115,116,114,111, +110,103,62,10,60,112,62,10,49,49,46,32,66,69,67,65, +85,83,69,32,84,72,69,32,80,82,79,71,82,65,77,32, +73,83,32,76,73,67,69,78,83,69,68,32,70,82,69,69, +32,79,70,32,67,72,65,82,71,69,44,32,84,72,69,82, +69,32,73,83,32,78,79,10,87,65,82,82,65,78,84,89, +32,70,79,82,32,84,72,69,32,80,82,79,71,82,65,77, +44,32,84,79,32,84,72,69,32,69,88,84,69,78,84,32, +80,69,82,77,73,84,84,69,68,32,66,89,32,65,80,80, +76,73,67,65,66,76,69,32,76,65,87,46,10,69,88,67, +69,80,84,32,87,72,69,78,32,79,84,72,69,82,87,73, +83,69,32,83,84,65,84,69,68,32,73,78,32,87,82,73, +84,73,78,71,32,84,72,69,32,67,79,80,89,82,73,71, +72,84,32,72,79,76,68,69,82,83,32,65,78,68,47,79, +82,10,79,84,72,69,82,32,80,65,82,84,73,69,83,32, +80,82,79,86,73,68,69,32,84,72,69,32,80,82,79,71, +82,65,77,32,34,65,83,32,73,83,34,32,87,73,84,72, +79,85,84,32,87,65,82,82,65,78,84,89,32,79,70,32, +65,78,89,10,75,73,78,68,44,32,69,73,84,72,69,82, +32,69,88,80,82,69,83,83,69,68,32,79,82,32,73,77, +80,76,73,69,68,44,32,73,78,67,76,85,68,73,78,71, +44,32,66,85,84,32,78,79,84,32,76,73,77,73,84,69, +68,32,84,79,44,32,84,72,69,10,73,77,80,76,73,69, +68,32,87,65,82,82,65,78,84,73,69,83,32,79,70,32, +77,69,82,67,72,65,78,84,65,66,73,76,73,84,89,32, +65,78,68,32,70,73,84,78,69,83,83,32,70,79,82,32, +65,32,80,65,82,84,73,67,85,76,65,82,10,80,85,82, +80,79,83,69,46,32,32,84,72,69,32,69,78,84,73,82, +69,32,82,73,83,75,32,65,83,32,84,79,32,84,72,69, +32,81,85,65,76,73,84,89,32,65,78,68,32,80,69,82, +70,79,82,77,65,78,67,69,32,79,70,32,84,72,69,10, +80,82,79,71,82,65,77,32,73,83,32,87,73,84,72,32, +89,79,85,46,32,32,83,72,79,85,76,68,32,84,72,69, +32,80,82,79,71,82,65,77,32,80,82,79,86,69,32,68, +69,70,69,67,84,73,86,69,44,32,89,79,85,32,65,83, +83,85,77,69,10,84,72,69,32,67,79,83,84,32,79,70, +32,65,76,76,32,78,69,67,69,83,83,65,82,89,32,83, +69,82,86,73,67,73,78,71,44,32,82,69,80,65,73,82, +32,79,82,32,67,79,82,82,69,67,84,73,79,78,46,10, +60,112,62,10,49,50,46,32,73,78,32,78,79,32,69,86, +69,78,84,32,85,78,76,69,83,83,32,82,69,81,85,73, +82,69,68,32,66,89,32,65,80,80,76,73,67,65,66,76, +69,32,76,65,87,32,79,82,32,65,71,82,69,69,68,32, +84,79,32,73,78,10,87,82,73,84,73,78,71,32,87,73, +76,76,32,65,78,89,32,67,79,80,89,82,73,71,72,84, +32,72,79,76,68,69,82,44,32,79,82,32,65,78,89,32, +79,84,72,69,82,32,80,65,82,84,89,32,87,72,79,32, +77,65,89,32,77,79,68,73,70,89,10,65,78,68,47,79, +82,32,82,69,68,73,83,84,82,73,66,85,84,69,32,84, +72,69,32,80,82,79,71,82,65,77,32,65,83,32,80,69, +82,77,73,84,84,69,68,32,65,66,79,86,69,44,32,66, +69,32,76,73,65,66,76,69,32,84,79,32,89,79,85,10, +70,79,82,32,68,65,77,65,71,69,83,44,32,73,78,67, +76,85,68,73,78,71,32,65,78,89,32,71,69,78,69,82, +65,76,44,32,83,80,69,67,73,65,76,44,32,73,78,67, +73,68,69,78,84,65,76,32,79,82,10,67,79,78,83,69, +81,85,69,78,84,73,65,76,32,68,65,77,65,71,69,83, +32,65,82,73,83,73,78,71,32,79,85,84,32,79,70,32, +84,72,69,32,85,83,69,32,79,82,32,73,78,65,66,73, +76,73,84,89,32,84,79,32,85,83,69,32,84,72,69,10, +80,82,79,71,82,65,77,32,40,73,78,67,76,85,68,73, +78,71,32,66,85,84,32,78,79,84,32,76,73,77,73,84, +69,68,32,84,79,32,76,79,83,83,32,79,70,32,68,65, +84,65,32,79,82,32,68,65,84,65,32,66,69,73,78,71, +10,82,69,78,68,69,82,69,68,32,73,78,65,67,67,85, +82,65,84,69,32,79,82,32,76,79,83,83,69,83,32,83, +85,83,84,65,73,78,69,68,32,66,89,32,89,79,85,32, +79,82,32,84,72,73,82,68,32,80,65,82,84,73,69,83, +32,79,82,32,65,10,70,65,73,76,85,82,69,32,79,70, +32,84,72,69,32,80,82,79,71,82,65,77,32,84,79,32, +79,80,69,82,65,84,69,32,87,73,84,72,32,65,78,89, +32,79,84,72,69,82,32,80,82,79,71,82,65,77,83,41, +44,32,69,86,69,78,32,73,70,10,83,85,67,72,32,72, +79,76,68,69,82,32,79,82,32,79,84,72,69,82,32,80, +65,82,84,89,32,72,65,83,32,66,69,69,78,32,65,68, +86,73,83,69,68,32,79,70,32,84,72,69,32,80,79,83, +83,73,66,73,76,73,84,89,32,79,70,32,83,85,67,72, +10,68,65,77,65,71,69,83,46,10,60,112,62,10,60,115, +116,114,111,110,103,62,69,78,68,32,79,70,32,84,69,82, +77,83,32,65,78,68,32,67,79,78,68,73,84,73,79,78, +83,60,47,115,116,114,111,110,103,62,10,60,112,62,10,60, +115,116,114,111,110,103,62,72,111,119,32,116,111,32,65,112, +112,108,121,32,84,104,101,115,101,32,84,101,114,109,115,32, +116,111,32,89,111,117,114,32,78,101,119,32,80,114,111,103, +114,97,109,115,60,47,115,116,114,111,110,103,62,60,98,114, +62,10,73,102,32,121,111,117,32,100,101,118,101,108,111,112, +32,97,32,110,101,119,32,112,114,111,103,114,97,109,44,32, +97,110,100,32,121,111,117,32,119,97,110,116,32,105,116,32, +116,111,32,98,101,32,111,102,32,116,104,101,32,103,114,101, +97,116,101,115,116,10,112,111,115,115,105,98,108,101,32,117, +115,101,32,116,111,32,116,104,101,32,112,117,98,108,105,99, +44,32,116,104,101,32,98,101,115,116,32,119,97,121,32,116, +111,32,97,99,104,105,101,118,101,32,116,104,105,115,32,105, +115,32,116,111,32,109,97,107,101,32,105,116,10,102,114,101, +101,32,115,111,102,116,119,97,114,101,32,119,104,105,99,104, +32,101,118,101,114,121,111,110,101,32,99,97,110,32,114,101, +100,105,115,116,114,105,98,117,116,101,32,97,110,100,32,99, +104,97,110,103,101,32,117,110,100,101,114,32,116,104,101,115, +101,10,116,101,114,109,115,46,10,60,112,62,10,84,111,32, +100,111,32,115,111,44,32,97,116,116,97,99,104,32,116,104, +101,32,102,111,108,108,111,119,105,110,103,32,110,111,116,105, +99,101,115,32,116,111,32,116,104,101,32,112,114,111,103,114, +97,109,46,32,32,73,116,32,105,115,32,115,97,102,101,115, +116,10,116,111,32,97,116,116,97,99,104,32,116,104,101,109, +32,116,111,32,116,104,101,32,115,116,97,114,116,32,111,102, +32,101,97,99,104,32,115,111,117,114,99,101,32,102,105,108, +101,32,116,111,32,109,111,115,116,32,101,102,102,101,99,116, +105,118,101,108,121,10,99,111,110,118,101,121,32,116,104,101, +32,101,120,99,108,117,115,105,111,110,32,111,102,32,119,97, +114,114,97,110,116,121,59,32,97,110,100,32,101,97,99,104, +32,102,105,108,101,32,115,104,111,117,108,100,32,104,97,118, +101,32,97,116,32,108,101,97,115,116,10,116,104,101,32,34, +99,111,112,121,114,105,103,104,116,34,32,108,105,110,101,32, +97,110,100,32,97,32,112,111,105,110,116,101,114,32,116,111, +32,119,104,101,114,101,32,116,104,101,32,102,117,108,108,32, +110,111,116,105,99,101,32,105,115,32,102,111,117,110,100,46, +10,60,112,62,10,32,32,32,32,60,111,110,101,32,108,105, +110,101,32,116,111,32,103,105,118,101,32,116,104,101,32,112, +114,111,103,114,97,109,39,115,32,110,97,109,101,32,97,110, +100,32,97,32,98,114,105,101,102,32,105,100,101,97,32,111, +102,32,119,104,97,116,32,105,116,32,100,111,101,115,46,62, +10,32,32,32,32,67,111,112,121,114,105,103,104,116,32,40, +67,41,32,38,108,116,59,121,101,97,114,38,103,116,59,32, +32,38,108,116,59,110,97,109,101,32,111,102,32,97,117,116, +104,111,114,38,103,116,59,10,60,112,62,10,32,32,32,32, +84,104,105,115,32,112,114,111,103,114,97,109,32,105,115,32, +102,114,101,101,32,115,111,102,116,119,97,114,101,59,32,121, +111,117,32,99,97,110,32,114,101,100,105,115,116,114,105,98, +117,116,101,32,105,116,32,97,110,100,47,111,114,32,109,111, +100,105,102,121,10,32,32,32,32,105,116,32,117,110,100,101, +114,32,116,104,101,32,116,101,114,109,115,32,111,102,32,116, +104,101,32,71,78,85,32,71,101,110,101,114,97,108,32,80, +117,98,108,105,99,32,76,105,99,101,110,115,101,32,97,115, +32,112,117,98,108,105,115,104,101,100,32,98,121,10,32,32, +32,32,116,104,101,32,70,114,101,101,32,83,111,102,116,119, +97,114,101,32,70,111,117,110,100,97,116,105,111,110,59,32, +101,105,116,104,101,114,32,118,101,114,115,105,111,110,32,50, +32,111,102,32,116,104,101,32,76,105,99,101,110,115,101,44, +32,111,114,10,32,32,32,32,40,97,116,32,121,111,117,114, +32,111,112,116,105,111,110,41,32,97,110,121,32,108,97,116, +101,114,32,118,101,114,115,105,111,110,46,10,60,112,62,10, +32,32,32,32,84,104,105,115,32,112,114,111,103,114,97,109, +32,105,115,32,100,105,115,116,114,105,98,117,116,101,100,32, +105,110,32,116,104,101,32,104,111,112,101,32,116,104,97,116, +32,105,116,32,119,105,108,108,32,98,101,32,117,115,101,102, +117,108,44,10,32,32,32,32,98,117,116,32,87,73,84,72, +79,85,84,32,65,78,89,32,87,65,82,82,65,78,84,89, +59,32,119,105,116,104,111,117,116,32,101,118,101,110,32,116, +104,101,32,105,109,112,108,105,101,100,32,119,97,114,114,97, +110,116,121,32,111,102,10,32,32,32,32,77,69,82,67,72, +65,78,84,65,66,73,76,73,84,89,32,111,114,32,70,73, +84,78,69,83,83,32,70,79,82,32,65,32,80,65,82,84, +73,67,85,76,65,82,32,80,85,82,80,79,83,69,46,32, +32,83,101,101,32,116,104,101,10,32,32,32,32,71,78,85, +32,71,101,110,101,114,97,108,32,80,117,98,108,105,99,32, +76,105,99,101,110,115,101,32,102,111,114,32,109,111,114,101, +32,100,101,116,97,105,108,115,46,10,60,112,62,10,32,32, +32,32,89,111,117,32,115,104,111,117,108,100,32,104,97,118, +101,32,114,101,99,101,105,118,101,100,32,97,32,99,111,112, +121,32,111,102,32,116,104,101,32,71,78,85,32,71,101,110, +101,114,97,108,32,80,117,98,108,105,99,32,76,105,99,101, +110,115,101,10,32,32,32,32,97,108,111,110,103,32,119,105, +116,104,32,116,104,105,115,32,112,114,111,103,114,97,109,59, +32,105,102,32,110,111,116,44,32,119,114,105,116,101,32,116, +111,32,116,104,101,32,70,114,101,101,32,83,111,102,116,119, +97,114,101,10,32,32,32,32,70,111,117,110,100,97,116,105, +111,110,44,32,73,110,99,46,44,32,53,57,32,84,101,109, +112,108,101,32,80,108,97,99,101,44,32,83,117,105,116,101, +32,51,51,48,44,32,66,111,115,116,111,110,44,32,77,65, +32,32,48,50,49,49,49,45,49,51,48,55,32,32,85,83, +65,10,60,112,62,10,65,108,115,111,32,97,100,100,32,105, +110,102,111,114,109,97,116,105,111,110,32,111,110,32,104,111, +119,32,116,111,32,99,111,110,116,97,99,116,32,121,111,117, +32,98,121,32,101,108,101,99,116,114,111,110,105,99,32,97, +110,100,32,112,97,112,101,114,32,109,97,105,108,46,10,60, +112,62,10,73,102,32,116,104,101,32,112,114,111,103,114,97, +109,32,105,115,32,105,110,116,101,114,97,99,116,105,118,101, +44,32,109,97,107,101,32,105,116,32,111,117,116,112,117,116, +32,97,32,115,104,111,114,116,32,110,111,116,105,99,101,32, +108,105,107,101,32,116,104,105,115,10,119,104,101,110,32,105, +116,32,115,116,97,114,116,115,32,105,110,32,97,110,32,105, +110,116,101,114,97,99,116,105,118,101,32,109,111,100,101,58, +10,60,112,114,101,62,10,32,32,32,32,71,110,111,109,111, +118,105,115,105,111,110,32,118,101,114,115,105,111,110,32,54, +57,44,32,67,111,112,121,114,105,103,104,116,32,40,67,41, +32,121,101,97,114,32,32,110,97,109,101,32,111,102,32,97, +117,116,104,111,114,10,32,32,32,32,71,110,111,109,111,118, +105,115,105,111,110,32,99,111,109,101,115,32,119,105,116,104, +32,65,66,83,79,76,85,84,69,76,89,32,78,79,32,87, +65,82,82,65,78,84,89,59,32,102,111,114,32,100,101,116, +97,105,108,115,32,116,121,112,101,32,96,115,104,111,119,32, +119,39,46,10,32,32,32,32,84,104,105,115,32,105,115,32, +102,114,101,101,32,115,111,102,116,119,97,114,101,44,32,97, +110,100,32,121,111,117,32,97,114,101,32,119,101,108,99,111, +109,101,32,116,111,32,114,101,100,105,115,116,114,105,98,117, +116,101,32,105,116,10,32,32,32,32,117,110,100,101,114,32, +99,101,114,116,97,105,110,32,99,111,110,100,105,116,105,111, +110,115,59,32,116,121,112,101,32,96,115,104,111,119,32,99, +39,32,102,111,114,32,100,101,116,97,105,108,115,46,10,60, +47,112,114,101,62,10,60,112,62,10,84,104,101,32,104,121, +112,111,116,104,101,116,105,99,97,108,32,99,111,109,109,97, +110,100,115,32,96,115,104,111,119,32,119,39,32,97,110,100, +32,96,115,104,111,119,32,99,39,32,115,104,111,117,108,100, +32,115,104,111,119,32,116,104,101,10,97,112,112,114,111,112, +114,105,97,116,101,32,112,97,114,116,115,32,111,102,32,116, +104,101,32,71,101,110,101,114,97,108,32,80,117,98,108,105, +99,32,76,105,99,101,110,115,101,46,32,32,79,102,32,99, +111,117,114,115,101,44,32,116,104,101,10,99,111,109,109,97, +110,100,115,32,121,111,117,32,117,115,101,32,109,97,121,32, +98,101,32,99,97,108,108,101,100,32,115,111,109,101,116,104, +105,110,103,32,111,116,104,101,114,32,116,104,97,110,32,96, +115,104,111,119,32,119,39,32,97,110,100,32,96,115,104,111, +119,10,99,39,59,32,116,104,101,121,32,99,111,117,108,100, +32,101,118,101,110,32,98,101,32,109,111,117,115,101,45,99, +108,105,99,107,115,32,111,114,32,109,101,110,117,32,105,116, +101,109,115,45,45,119,104,97,116,101,118,101,114,32,115,117, +105,116,115,32,121,111,117,114,32,10,112,114,111,103,114,97, +109,46,10,60,112,62,10,89,111,117,32,115,104,111,117,108, +100,32,97,108,115,111,32,103,101,116,32,121,111,117,114,32, +101,109,112,108,111,121,101,114,32,40,105,102,32,121,111,117, +32,119,111,114,107,32,97,115,32,97,32,112,114,111,103,114, +97,109,109,101,114,41,32,111,114,10,121,111,117,114,32,115, +99,104,111,111,108,44,32,105,102,32,97,110,121,44,32,116, +111,32,115,105,103,110,32,97,32,34,99,111,112,121,114,105, +103,104,116,32,100,105,115,99,108,97,105,109,101,114,34,32, +102,111,114,32,116,104,101,32,112,114,111,103,114,97,109,44, +10,105,102,32,110,101,99,101,115,115,97,114,121,46,32,32, +72,101,114,101,32,105,115,32,97,32,115,97,109,112,108,101, +59,32,97,108,116,101,114,32,116,104,101,32,110,97,109,101, +115,58,10,60,112,62,10,60,112,114,101,62,10,32,32,89, +111,121,111,100,121,110,101,44,32,73,110,99,46,44,32,104, +101,114,101,98,121,32,100,105,115,99,108,97,105,109,115,32, +97,108,108,32,99,111,112,121,114,105,103,104,116,32,105,110, +116,101,114,101,115,116,32,105,110,32,116,104,101,32,112,114, +111,103,114,97,109,10,32,32,96,71,110,111,109,111,118,105, +115,105,111,110,39,32,40,119,104,105,99,104,32,109,97,107, +101,115,32,112,97,115,115,101,115,32,97,116,32,99,111,109, +112,105,108,101,114,115,41,32,119,114,105,116,116,101,110,32, +98,121,32,74,97,109,101,115,32,72,97,99,107,101,114,46, +10,10,32,32,38,108,116,59,115,105,103,110,97,116,117,114, +101,32,111,102,32,84,121,32,67,111,111,110,38,103,116,59, +44,32,49,32,65,112,114,105,108,32,49,57,56,57,10,32, +32,84,121,32,67,111,111,110,44,32,80,114,101,115,105,100, +101,110,116,32,111,102,32,86,105,99,101,10,60,47,112,114, +101,62,10,60,112,62,10,84,104,105,115,32,71,101,110,101, +114,97,108,32,80,117,98,108,105,99,32,76,105,99,101,110, +115,101,32,100,111,101,115,32,110,111,116,32,112,101,114,109, +105,116,32,105,110,99,111,114,112,111,114,97,116,105,110,103, +32,121,111,117,114,32,112,114,111,103,114,97,109,10,105,110, +116,111,32,112,114,111,112,114,105,101,116,97,114,121,32,112, +114,111,103,114,97,109,115,46,32,32,73,102,32,121,111,117, +114,32,112,114,111,103,114,97,109,32,105,115,32,97,32,115, +117,98,114,111,117,116,105,110,101,32,108,105,98,114,97,114, +121,44,10,121,111,117,32,109,97,121,32,99,111,110,115,105, +100,101,114,32,105,116,32,109,111,114,101,32,117,115,101,102, +117,108,32,116,111,32,112,101,114,109,105,116,32,108,105,110, +107,105,110,103,32,112,114,111,112,114,105,101,116,97,114,121, +10,97,112,112,108,105,99,97,116,105,111,110,115,32,119,105, +116,104,32,116,104,101,32,108,105,98,114,97,114,121,46,32, +32,73,102,32,116,104,105,115,32,105,115,32,119,104,97,116, +32,121,111,117,32,119,97,110,116,32,116,111,32,100,111,44, +32,117,115,101,10,116,104,101,32,71,78,85,32,76,105,98, +114,97,114,121,32,71,101,110,101,114,97,108,32,80,117,98, +108,105,99,32,76,105,99,101,110,115,101,32,105,110,115,116, +101,97,100,32,111,102,32,116,104,105,115,32,76,105,99,101, +110,115,101,46,10,10, +0}; diff --git a/lib/html_gpl2_win32.cpp b/lib/html_gpl2_win32.cpp new file mode 100644 index 00000000..57739825 --- /dev/null +++ b/lib/html_gpl2_win32.cpp @@ -0,0 +1,1169 @@ +// html_gpl2_win32.cpp +// +// Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: html_gpl2_win32.cpp,v 1.1 2007/09/14 14:06:24 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +char html_gpl2[18343] = { +60,99,101,110,116,101,114,62,60,98,105,103,62,60,98,105, +103,62,60,115,116,114,111,110,103,62,71,78,85,32,71,69, +78,69,82,65,76,32,80,85,66,76,73,67,32,76,73,67, +69,78,83,69,60,47,115,116,114,111,110,103,62,60,47,98, +105,103,62,60,47,98,105,103,62,60,47,99,101,110,116,101, +114,62,10,60,99,101,110,116,101,114,62,60,98,105,103,62, +86,101,114,115,105,111,110,32,50,44,32,74,117,110,101,32, +49,57,57,49,60,47,98,105,103,62,60,47,99,101,110,116, +101,114,62,10,10,32,67,111,112,121,114,105,103,104,116,32, +40,67,41,32,49,57,56,57,44,32,49,57,57,49,32,70, +114,101,101,32,83,111,102,116,119,97,114,101,32,70,111,117, +110,100,97,116,105,111,110,44,32,73,110,99,46,32,32,53, +57,32,84,101,109,112,108,101,10,32,80,108,97,99,101,44, +32,83,117,105,116,101,32,51,51,48,44,32,66,111,115,116, +111,110,44,32,77,65,32,32,48,50,49,49,49,45,49,51, +48,55,32,32,85,83,65,32,32,69,118,101,114,121,111,110, +101,32,105,115,32,112,101,114,109,105,116,116,101,100,10,32, +116,111,32,99,111,112,121,32,97,110,100,32,100,105,115,116, +114,105,98,117,116,101,32,118,101,114,98,97,116,105,109,32, +99,111,112,105,101,115,32,111,102,32,116,104,105,115,32,108, +105,99,101,110,115,101,32,100,111,99,117,109,101,110,116,44, +32,98,117,116,10,32,99,104,97,110,103,105,110,103,32,105, +116,32,105,115,32,110,111,116,32,97,108,108,111,119,101,100, +46,60,98,114,62,10,10,60,99,101,110,116,101,114,62,60, +98,105,103,62,60,115,116,114,111,110,103,62,80,82,69,65, +77,66,76,69,60,47,115,116,114,111,110,103,62,60,47,98, +105,103,62,60,47,99,101,110,116,101,114,62,10,84,104,101, +32,108,105,99,101,110,115,101,115,32,102,111,114,32,109,111, +115,116,32,115,111,102,116,119,97,114,101,32,97,114,101,32, +100,101,115,105,103,110,101,100,32,116,111,32,116,97,107,101, +32,97,119,97,121,32,121,111,117,114,32,102,114,101,101,100, +111,109,10,116,111,32,115,104,97,114,101,32,97,110,100,32, +99,104,97,110,103,101,32,105,116,46,32,32,66,121,32,99, +111,110,116,114,97,115,116,44,32,116,104,101,32,71,78,85, +32,71,101,110,101,114,97,108,32,80,117,98,108,105,99,32, +76,105,99,101,110,115,101,10,105,115,32,105,110,116,101,110, +100,101,100,32,116,111,32,103,117,97,114,97,110,116,101,101, +32,121,111,117,114,32,102,114,101,101,100,111,109,32,116,111, +32,115,104,97,114,101,32,97,110,100,32,99,104,97,110,103, +101,32,102,114,101,101,10,115,111,102,116,119,97,114,101,32, +45,45,32,116,111,32,109,97,107,101,32,115,117,114,101,32, +116,104,101,32,115,111,102,116,119,97,114,101,32,105,115,32, +102,114,101,101,32,102,111,114,32,97,108,108,32,105,116,115, +32,117,115,101,114,115,46,32,32,84,104,105,115,10,71,101, +110,101,114,97,108,32,80,117,98,108,105,99,32,76,105,99, +101,110,115,101,32,97,112,112,108,105,101,115,32,116,111,32, +109,111,115,116,32,111,102,32,116,104,101,32,70,114,101,101, +32,83,111,102,116,119,97,114,101,10,70,111,117,110,100,97, +116,105,111,110,39,115,32,115,111,102,116,119,97,114,101,32, +97,110,100,32,116,111,32,97,110,121,32,111,116,104,101,114, +32,112,114,111,103,114,97,109,32,119,104,111,115,101,32,97, +117,116,104,111,114,115,10,99,111,109,109,105,116,32,116,111, +32,117,115,105,110,103,32,105,116,46,32,32,40,83,111,109, +101,32,111,116,104,101,114,32,70,114,101,101,32,83,111,102, +116,119,97,114,101,32,70,111,117,110,100,97,116,105,111,110, +10,115,111,102,116,119,97,114,101,32,105,115,32,99,111,118, +101,114,101,100,32,98,121,32,116,104,101,32,71,78,85,32, +76,105,98,114,97,114,121,32,71,101,110,101,114,97,108,32, +80,117,98,108,105,99,10,76,105,99,101,110,115,101,32,105, +110,115,116,101,97,100,46,41,32,32,89,111,117,32,99,97, +110,32,97,112,112,108,121,32,105,116,32,116,111,32,121,111, +117,114,32,112,114,111,103,114,97,109,115,44,32,116,111,111, +46,10,60,112,62,10,87,104,101,110,32,119,101,32,115,112, +101,97,107,32,111,102,32,102,114,101,101,32,115,111,102,116, +119,97,114,101,44,32,119,101,32,97,114,101,32,114,101,102, +101,114,114,105,110,103,32,116,111,32,102,114,101,101,100,111, +109,44,32,110,111,116,10,112,114,105,99,101,46,32,32,79, +117,114,32,71,101,110,101,114,97,108,32,80,117,98,108,105, +99,32,76,105,99,101,110,115,101,115,32,97,114,101,32,100, +101,115,105,103,110,101,100,32,116,111,32,109,97,107,101,32, +115,117,114,101,32,116,104,97,116,32,121,111,117,10,104,97, +118,101,32,116,104,101,32,102,114,101,101,100,111,109,32,116, +111,32,100,105,115,116,114,105,98,117,116,101,32,99,111,112, +105,101,115,32,111,102,32,102,114,101,101,32,115,111,102,116, +119,97,114,101,32,40,97,110,100,32,99,104,97,114,103,101, +32,102,111,114,10,116,104,105,115,32,115,101,114,118,105,99, +101,32,105,102,32,121,111,117,32,119,105,115,104,41,44,32, +116,104,97,116,32,121,111,117,32,114,101,99,101,105,118,101, +32,115,111,117,114,99,101,32,99,111,100,101,32,111,114,32, +99,97,110,32,103,101,116,32,105,116,10,105,102,32,121,111, +117,32,119,97,110,116,32,105,116,44,32,116,104,97,116,32, +121,111,117,32,99,97,110,32,99,104,97,110,103,101,32,116, +104,101,32,115,111,102,116,119,97,114,101,32,111,114,32,117, +115,101,32,112,105,101,99,101,115,32,111,102,32,105,116,10, +105,110,32,110,101,119,32,102,114,101,101,32,112,114,111,103, +114,97,109,115,59,32,97,110,100,32,116,104,97,116,32,121, +111,117,32,107,110,111,119,32,121,111,117,32,99,97,110,32, +100,111,32,116,104,101,115,101,32,116,104,105,110,103,115,46, +10,60,112,62,10,84,111,32,112,114,111,116,101,99,116,32, +121,111,117,114,32,114,105,103,104,116,115,44,32,119,101,32, +110,101,101,100,32,116,111,32,109,97,107,101,32,114,101,115, +116,114,105,99,116,105,111,110,115,32,116,104,97,116,32,102, +111,114,98,105,100,10,97,110,121,111,110,101,32,116,111,32, +100,101,110,121,32,121,111,117,32,116,104,101,115,101,32,114, +105,103,104,116,115,32,111,114,32,116,111,32,97,115,107,32, +121,111,117,32,116,111,32,115,117,114,114,101,110,100,101,114, +32,116,104,101,32,114,105,103,104,116,115,46,10,84,104,101, +115,101,32,114,101,115,116,114,105,99,116,105,111,110,115,32, +116,114,97,110,115,108,97,116,101,32,116,111,32,99,101,114, +116,97,105,110,32,114,101,115,112,111,110,115,105,98,105,108, +105,116,105,101,115,32,102,111,114,32,121,111,117,32,105,102, +10,121,111,117,32,100,105,115,116,114,105,98,117,116,101,32, +99,111,112,105,101,115,32,111,102,32,116,104,101,32,115,111, +102,116,119,97,114,101,44,32,111,114,32,105,102,32,121,111, +117,32,109,111,100,105,102,121,32,105,116,46,10,60,112,62, +10,70,111,114,32,101,120,97,109,112,108,101,44,32,105,102, +32,121,111,117,32,100,105,115,116,114,105,98,117,116,101,32, +99,111,112,105,101,115,32,111,102,32,115,117,99,104,32,97, +32,112,114,111,103,114,97,109,44,32,119,104,101,116,104,101, +114,10,103,114,97,116,105,115,32,111,114,32,102,111,114,32, +97,32,102,101,101,44,32,121,111,117,32,109,117,115,116,32, +103,105,118,101,32,116,104,101,32,114,101,99,105,112,105,101, +110,116,115,32,97,108,108,32,116,104,101,32,114,105,103,104, +116,115,32,116,104,97,116,10,121,111,117,32,104,97,118,101, +46,32,32,89,111,117,32,109,117,115,116,32,109,97,107,101, +32,115,117,114,101,32,116,104,97,116,32,116,104,101,121,44, +32,116,111,111,44,32,114,101,99,101,105,118,101,32,111,114, +32,99,97,110,32,103,101,116,32,116,104,101,10,115,111,117, +114,99,101,32,99,111,100,101,46,32,32,65,110,100,32,121, +111,117,32,109,117,115,116,32,115,104,111,119,32,116,104,101, +109,32,116,104,101,115,101,32,116,101,114,109,115,32,115,111, +32,116,104,101,121,32,107,110,111,119,32,116,104,101,105,114, +10,114,105,103,104,116,115,46,10,60,112,62,10,87,101,32, +112,114,111,116,101,99,116,32,121,111,117,114,32,114,105,103, +104,116,115,32,119,105,116,104,32,116,119,111,32,115,116,101, +112,115,58,32,40,49,41,32,99,111,112,121,114,105,103,104, +116,32,116,104,101,32,115,111,102,116,119,97,114,101,44,32, +97,110,100,10,40,50,41,32,111,102,102,101,114,32,121,111, +117,32,116,104,105,115,32,108,105,99,101,110,115,101,32,119, +104,105,99,104,32,103,105,118,101,115,32,121,111,117,32,108, +101,103,97,108,32,112,101,114,109,105,115,115,105,111,110,32, +116,111,32,99,111,112,121,44,10,100,105,115,116,114,105,98, +117,116,101,32,97,110,100,47,111,114,32,109,111,100,105,102, +121,32,116,104,101,32,115,111,102,116,119,97,114,101,46,10, +60,112,62,10,65,108,115,111,44,32,102,111,114,32,101,97, +99,104,32,97,117,116,104,111,114,39,115,32,112,114,111,116, +101,99,116,105,111,110,32,97,110,100,32,111,117,114,115,44, +32,119,101,32,119,97,110,116,32,116,111,32,109,97,107,101, +32,99,101,114,116,97,105,110,10,116,104,97,116,32,101,118, +101,114,121,111,110,101,32,117,110,100,101,114,115,116,97,110, +100,115,32,116,104,97,116,32,116,104,101,114,101,32,105,115, +32,110,111,32,119,97,114,114,97,110,116,121,32,102,111,114, +32,116,104,105,115,32,102,114,101,101,10,115,111,102,116,119, +97,114,101,46,32,32,73,102,32,116,104,101,32,115,111,102, +116,119,97,114,101,32,105,115,32,109,111,100,105,102,105,101, +100,32,98,121,32,115,111,109,101,111,110,101,32,101,108,115, +101,32,97,110,100,32,112,97,115,115,101,100,32,111,110,44, +10,119,101,32,119,97,110,116,32,105,116,115,32,114,101,99, +105,112,105,101,110,116,115,32,116,111,32,107,110,111,119,32, +116,104,97,116,32,119,104,97,116,32,116,104,101,121,32,104, +97,118,101,32,105,115,32,110,111,116,32,116,104,101,10,111, +114,105,103,105,110,97,108,44,32,115,111,32,116,104,97,116, +32,97,110,121,32,112,114,111,98,108,101,109,115,32,105,110, +116,114,111,100,117,99,101,100,32,98,121,32,111,116,104,101, +114,115,32,119,105,108,108,32,110,111,116,32,114,101,102,108, +101,99,116,10,111,110,32,116,104,101,32,111,114,105,103,105, +110,97,108,32,97,117,116,104,111,114,115,39,32,114,101,112, +117,116,97,116,105,111,110,115,46,10,60,112,62,10,70,105, +110,97,108,108,121,44,32,97,110,121,32,102,114,101,101,32, +112,114,111,103,114,97,109,32,105,115,32,116,104,114,101,97, +116,101,110,101,100,32,99,111,110,115,116,97,110,116,108,121, +32,98,121,32,115,111,102,116,119,97,114,101,10,112,97,116, +101,110,116,115,46,32,32,87,101,32,119,105,115,104,32,116, +111,32,97,118,111,105,100,32,116,104,101,32,100,97,110,103, +101,114,32,116,104,97,116,32,114,101,100,105,115,116,114,105, +98,117,116,111,114,115,32,111,102,32,97,32,102,114,101,101, +10,112,114,111,103,114,97,109,32,119,105,108,108,32,105,110, +100,105,118,105,100,117,97,108,108,121,32,111,98,116,97,105, +110,32,112,97,116,101,110,116,32,108,105,99,101,110,115,101, +115,44,32,105,110,32,101,102,102,101,99,116,32,109,97,107, +105,110,103,32,116,104,101,10,112,114,111,103,114,97,109,32, +112,114,111,112,114,105,101,116,97,114,121,46,32,32,84,111, +32,112,114,101,118,101,110,116,32,116,104,105,115,44,32,119, +101,32,104,97,118,101,32,109,97,100,101,32,105,116,32,99, +108,101,97,114,32,116,104,97,116,32,97,110,121,10,112,97, +116,101,110,116,32,109,117,115,116,32,98,101,32,108,105,99, +101,110,115,101,100,32,102,111,114,32,101,118,101,114,121,111, +110,101,39,115,32,102,114,101,101,32,117,115,101,32,111,114, +32,110,111,116,32,108,105,99,101,110,115,101,100,32,97,116, +10,97,108,108,46,10,10,60,112,62,10,84,104,101,32,112, +114,101,99,105,115,101,32,116,101,114,109,115,32,97,110,100, +32,99,111,110,100,105,116,105,111,110,115,32,102,111,114,32, +99,111,112,121,105,110,103,44,32,100,105,115,116,114,105,98, +117,116,105,111,110,32,97,110,100,10,109,111,100,105,102,105, +99,97,116,105,111,110,32,102,111,108,108,111,119,46,10,60, +112,62,10,60,99,101,110,116,101,114,62,60,98,105,103,62, +60,115,116,114,111,110,103,62,71,78,85,32,71,69,78,69, +82,65,76,32,80,85,66,76,73,67,32,76,73,67,69,78, +83,69,60,47,115,116,114,111,110,103,62,60,47,98,105,103, +62,60,47,99,101,110,116,101,114,62,10,60,115,116,114,111, +110,103,62,84,69,82,77,83,32,65,78,68,32,67,79,78, +68,73,84,73,79,78,83,32,70,79,82,32,67,79,80,89, +73,78,71,44,32,68,73,83,84,82,73,66,85,84,73,79, +78,32,65,78,68,32,77,79,68,73,70,73,67,65,84,73, +79,78,60,47,115,116,114,111,110,103,62,60,98,114,62,10, +48,46,32,84,104,105,115,32,76,105,99,101,110,115,101,32, +97,112,112,108,105,101,115,32,116,111,32,97,110,121,32,112, +114,111,103,114,97,109,32,111,114,32,111,116,104,101,114,32, +119,111,114,107,32,119,104,105,99,104,32,99,111,110,116,97, +105,110,115,32,97,10,110,111,116,105,99,101,32,112,108,97, +99,101,100,32,98,121,32,116,104,101,32,99,111,112,121,114, +105,103,104,116,32,104,111,108,100,101,114,32,115,97,121,105, +110,103,32,105,116,32,109,97,121,32,98,101,32,100,105,115, +116,114,105,98,117,116,101,100,10,117,110,100,101,114,32,116, +104,101,32,116,101,114,109,115,32,111,102,32,116,104,105,115, +32,71,101,110,101,114,97,108,32,80,117,98,108,105,99,32, +76,105,99,101,110,115,101,46,32,32,84,104,101,32,34,80, +114,111,103,114,97,109,34,44,32,98,101,108,111,119,44,10, +114,101,102,101,114,115,32,116,111,32,97,110,121,32,115,117, +99,104,32,112,114,111,103,114,97,109,32,111,114,32,119,111, +114,107,44,32,97,110,100,32,97,32,34,119,111,114,107,32, +98,97,115,101,100,32,111,110,32,116,104,101,32,80,114,111, +103,114,97,109,34,10,109,101,97,110,115,32,101,105,116,104, +101,114,32,116,104,101,32,80,114,111,103,114,97,109,32,111, +114,32,97,110,121,32,100,101,114,105,118,97,116,105,118,101, +32,119,111,114,107,32,117,110,100,101,114,32,99,111,112,121, +114,105,103,104,116,32,108,97,119,58,10,116,104,97,116,32, +105,115,32,116,111,32,115,97,121,44,32,97,32,119,111,114, +107,32,99,111,110,116,97,105,110,105,110,103,32,116,104,101, +32,80,114,111,103,114,97,109,32,111,114,32,97,32,112,111, +114,116,105,111,110,32,111,102,32,105,116,44,10,101,105,116, +104,101,114,32,118,101,114,98,97,116,105,109,32,111,114,32, +119,105,116,104,32,109,111,100,105,102,105,99,97,116,105,111, +110,115,32,97,110,100,47,111,114,32,116,114,97,110,115,108, +97,116,101,100,32,105,110,116,111,32,97,110,111,116,104,101, +114,10,108,97,110,103,117,97,103,101,46,32,32,40,72,101, +114,101,105,110,97,102,116,101,114,44,32,116,114,97,110,115, +108,97,116,105,111,110,32,105,115,32,105,110,99,108,117,100, +101,100,32,119,105,116,104,111,117,116,32,108,105,109,105,116, +97,116,105,111,110,32,105,110,10,116,104,101,32,116,101,114, +109,32,34,109,111,100,105,102,105,99,97,116,105,111,110,34, +46,41,32,32,69,97,99,104,32,108,105,99,101,110,115,101, +101,32,105,115,32,97,100,100,114,101,115,115,101,100,32,97, +115,32,34,121,111,117,34,46,10,60,112,62,10,65,99,116, +105,118,105,116,105,101,115,32,111,116,104,101,114,32,116,104, +97,110,32,99,111,112,121,105,110,103,44,32,100,105,115,116, +114,105,98,117,116,105,111,110,32,97,110,100,32,109,111,100, +105,102,105,99,97,116,105,111,110,32,97,114,101,32,110,111, +116,10,99,111,118,101,114,101,100,32,98,121,32,116,104,105, +115,32,76,105,99,101,110,115,101,59,32,116,104,101,121,32, +97,114,101,32,111,117,116,115,105,100,101,32,105,116,115,32, +115,99,111,112,101,46,32,32,84,104,101,32,97,99,116,32, +111,102,10,114,117,110,110,105,110,103,32,116,104,101,32,80, +114,111,103,114,97,109,32,105,115,32,110,111,116,32,114,101, +115,116,114,105,99,116,101,100,44,32,97,110,100,32,116,104, +101,32,111,117,116,112,117,116,32,102,114,111,109,32,116,104, +101,32,80,114,111,103,114,97,109,10,105,115,32,99,111,118, +101,114,101,100,32,111,110,108,121,32,105,102,32,105,116,115, +32,99,111,110,116,101,110,116,115,32,99,111,110,115,116,105, +116,117,116,101,32,97,32,119,111,114,107,32,98,97,115,101, +100,32,111,110,32,116,104,101,32,80,114,111,103,114,97,109, +10,40,105,110,100,101,112,101,110,100,101,110,116,32,111,102, +32,104,97,118,105,110,103,32,98,101,101,110,32,109,97,100, +101,32,98,121,32,114,117,110,110,105,110,103,32,116,104,101, +32,80,114,111,103,114,97,109,41,46,32,32,87,104,101,116, +104,101,114,10,116,104,97,116,32,105,115,32,116,114,117,101, +32,100,101,112,101,110,100,115,32,111,110,32,119,104,97,116, +32,116,104,101,32,80,114,111,103,114,97,109,32,100,111,101, +115,46,10,60,112,62,10,49,46,32,89,111,117,32,109,97, +121,32,99,111,112,121,32,97,110,100,32,100,105,115,116,114, +105,98,117,116,101,32,118,101,114,98,97,116,105,109,32,99, +111,112,105,101,115,32,111,102,32,116,104,101,32,80,114,111, +103,114,97,109,39,115,32,115,111,117,114,99,101,10,99,111, +100,101,32,97,115,32,121,111,117,32,114,101,99,101,105,118, +101,32,105,116,44,32,105,110,32,97,110,121,32,109,101,100, +105,117,109,44,32,112,114,111,118,105,100,101,100,32,116,104, +97,116,32,121,111,117,32,99,111,110,115,112,105,99,117,111, +117,115,108,121,10,97,110,100,32,97,112,112,114,111,112,114, +105,97,116,101,108,121,32,112,117,98,108,105,115,104,32,111, +110,32,101,97,99,104,32,99,111,112,121,32,97,110,32,97, +112,112,114,111,112,114,105,97,116,101,32,99,111,112,121,114, +105,103,104,116,32,110,111,116,105,99,101,10,97,110,100,32, +100,105,115,99,108,97,105,109,101,114,32,111,102,32,119,97, +114,114,97,110,116,121,59,32,107,101,101,112,32,105,110,116, +97,99,116,32,97,108,108,32,116,104,101,32,110,111,116,105, +99,101,115,32,116,104,97,116,32,114,101,102,101,114,32,116, +111,10,116,104,105,115,32,76,105,99,101,110,115,101,32,97, +110,100,32,116,111,32,116,104,101,32,97,98,115,101,110,99, +101,32,111,102,32,97,110,121,32,119,97,114,114,97,110,116, +121,59,32,97,110,100,32,103,105,118,101,32,97,110,121,32, +111,116,104,101,114,10,114,101,99,105,112,105,101,110,116,115, +32,111,102,32,116,104,101,32,80,114,111,103,114,97,109,32, +97,32,99,111,112,121,32,111,102,32,116,104,105,115,32,76, +105,99,101,110,115,101,32,97,108,111,110,103,32,119,105,116, +104,32,116,104,101,10,80,114,111,103,114,97,109,46,10,60, +112,62,10,89,111,117,32,109,97,121,32,99,104,97,114,103, +101,32,97,32,102,101,101,32,102,111,114,32,116,104,101,32, +112,104,121,115,105,99,97,108,32,97,99,116,32,111,102,32, +116,114,97,110,115,102,101,114,114,105,110,103,32,97,32,99, +111,112,121,44,32,97,110,100,10,121,111,117,32,109,97,121, +32,97,116,32,121,111,117,114,32,111,112,116,105,111,110,32, +111,102,102,101,114,32,119,97,114,114,97,110,116,121,32,112, +114,111,116,101,99,116,105,111,110,32,105,110,32,101,120,99, +104,97,110,103,101,32,102,111,114,32,97,10,102,101,101,46, +10,60,112,62,10,50,46,32,89,111,117,32,109,97,121,32, +109,111,100,105,102,121,32,121,111,117,114,32,99,111,112,121, +32,111,114,32,99,111,112,105,101,115,32,111,102,32,116,104, +101,32,80,114,111,103,114,97,109,32,111,114,32,97,110,121, +32,112,111,114,116,105,111,110,32,111,102,10,105,116,44,32, +116,104,117,115,32,102,111,114,109,105,110,103,32,97,32,119, +111,114,107,32,98,97,115,101,100,32,111,110,32,116,104,101, +32,80,114,111,103,114,97,109,44,32,97,110,100,32,99,111, +112,121,32,97,110,100,32,100,105,115,116,114,105,98,117,116, +101,10,115,117,99,104,32,109,111,100,105,102,105,99,97,116, +105,111,110,115,32,111,114,32,119,111,114,107,32,117,110,100, +101,114,32,116,104,101,32,116,101,114,109,115,32,111,102,32, +83,101,99,116,105,111,110,32,49,32,97,98,111,118,101,44, +10,112,114,111,118,105,100,101,100,32,116,104,97,116,32,121, +111,117,32,97,108,115,111,32,109,101,101,116,32,97,108,108, +32,111,102,32,116,104,101,115,101,32,99,111,110,100,105,116, +105,111,110,115,58,10,60,112,62,10,32,32,32,32,97,41, +32,89,111,117,32,109,117,115,116,32,99,97,117,115,101,32, +116,104,101,32,109,111,100,105,102,105,101,100,32,102,105,108, +101,115,32,116,111,32,99,97,114,114,121,32,112,114,111,109, +105,110,101,110,116,32,110,111,116,105,99,101,115,10,32,32, +32,32,115,116,97,116,105,110,103,32,116,104,97,116,32,121, +111,117,32,99,104,97,110,103,101,100,32,116,104,101,32,102, +105,108,101,115,32,97,110,100,32,116,104,101,32,100,97,116, +101,32,111,102,32,97,110,121,32,99,104,97,110,103,101,46, +10,60,112,62,10,32,32,32,32,98,41,32,89,111,117,32, +109,117,115,116,32,99,97,117,115,101,32,97,110,121,32,119, +111,114,107,32,116,104,97,116,32,121,111,117,32,100,105,115, +116,114,105,98,117,116,101,32,111,114,32,112,117,98,108,105, +115,104,44,32,116,104,97,116,32,105,110,10,32,32,32,32, +119,104,111,108,101,32,111,114,32,105,110,32,112,97,114,116, +32,99,111,110,116,97,105,110,115,32,111,114,32,105,115,32, +100,101,114,105,118,101,100,32,102,114,111,109,32,116,104,101, +32,80,114,111,103,114,97,109,32,111,114,32,97,110,121,10, +32,32,32,32,112,97,114,116,32,116,104,101,114,101,111,102, +44,32,116,111,32,98,101,32,108,105,99,101,110,115,101,100, +32,97,115,32,97,32,119,104,111,108,101,32,97,116,32,110, +111,32,99,104,97,114,103,101,32,116,111,32,97,108,108,32, +116,104,105,114,100,10,32,32,32,32,112,97,114,116,105,101, +115,32,117,110,100,101,114,32,116,104,101,32,116,101,114,109, +115,32,111,102,32,116,104,105,115,32,76,105,99,101,110,115, +101,46,10,60,112,62,10,32,32,32,32,99,41,32,73,102, +32,116,104,101,32,109,111,100,105,102,105,101,100,32,112,114, +111,103,114,97,109,32,110,111,114,109,97,108,108,121,32,114, +101,97,100,115,32,99,111,109,109,97,110,100,115,32,105,110, +116,101,114,97,99,116,105,118,101,108,121,10,32,32,32,32, +119,104,101,110,32,114,117,110,44,32,121,111,117,32,109,117, +115,116,32,99,97,117,115,101,32,105,116,44,32,119,104,101, +110,32,115,116,97,114,116,101,100,32,114,117,110,110,105,110, +103,32,102,111,114,32,115,117,99,104,10,32,32,32,32,105, +110,116,101,114,97,99,116,105,118,101,32,117,115,101,32,105, +110,32,116,104,101,32,109,111,115,116,32,111,114,100,105,110, +97,114,121,32,119,97,121,44,32,116,111,32,112,114,105,110, +116,32,111,114,32,100,105,115,112,108,97,121,32,97,110,10, +32,32,32,32,97,110,110,111,117,110,99,101,109,101,110,116, +32,105,110,99,108,117,100,105,110,103,32,97,110,32,97,112, +112,114,111,112,114,105,97,116,101,32,99,111,112,121,114,105, +103,104,116,32,110,111,116,105,99,101,32,97,110,100,32,97, +10,32,32,32,32,110,111,116,105,99,101,32,116,104,97,116, +32,116,104,101,114,101,32,105,115,32,110,111,32,119,97,114, +114,97,110,116,121,32,40,111,114,32,101,108,115,101,44,32, +115,97,121,105,110,103,32,116,104,97,116,32,121,111,117,32, +112,114,111,118,105,100,101,10,32,32,32,32,97,32,119,97, +114,114,97,110,116,121,41,32,97,110,100,32,116,104,97,116, +32,117,115,101,114,115,32,109,97,121,32,114,101,100,105,115, +116,114,105,98,117,116,101,32,116,104,101,32,112,114,111,103, +114,97,109,32,117,110,100,101,114,10,32,32,32,32,116,104, +101,115,101,32,99,111,110,100,105,116,105,111,110,115,44,32, +97,110,100,32,116,101,108,108,105,110,103,32,116,104,101,32, +117,115,101,114,32,104,111,119,32,116,111,32,118,105,101,119, +32,97,32,99,111,112,121,32,111,102,32,116,104,105,115,10, +32,32,32,32,76,105,99,101,110,115,101,46,32,32,40,69, +120,99,101,112,116,105,111,110,58,32,105,102,32,116,104,101, +32,80,114,111,103,114,97,109,32,105,116,115,101,108,102,32, +105,115,32,105,110,116,101,114,97,99,116,105,118,101,32,98, +117,116,10,32,32,32,32,100,111,101,115,32,110,111,116,32, +110,111,114,109,97,108,108,121,32,112,114,105,110,116,32,115, +117,99,104,32,97,110,32,97,110,110,111,117,110,99,101,109, +101,110,116,44,32,121,111,117,114,32,119,111,114,107,32,98, +97,115,101,100,32,111,110,10,32,32,32,32,116,104,101,32, +80,114,111,103,114,97,109,32,105,115,32,110,111,116,32,114, +101,113,117,105,114,101,100,32,116,111,32,112,114,105,110,116, +32,97,110,32,97,110,110,111,117,110,99,101,109,101,110,116, +46,41,10,60,112,62,10,84,104,101,115,101,32,114,101,113, +117,105,114,101,109,101,110,116,115,32,97,112,112,108,121,32, +116,111,32,116,104,101,32,109,111,100,105,102,105,101,100,32, +119,111,114,107,32,97,115,32,97,32,119,104,111,108,101,46, +32,32,73,102,10,105,100,101,110,116,105,102,105,97,98,108, +101,32,115,101,99,116,105,111,110,115,32,111,102,32,116,104, +97,116,32,119,111,114,107,32,97,114,101,32,110,111,116,32, +100,101,114,105,118,101,100,32,102,114,111,109,32,116,104,101, +32,80,114,111,103,114,97,109,44,10,97,110,100,32,99,97, +110,32,98,101,32,114,101,97,115,111,110,97,98,108,121,32, +99,111,110,115,105,100,101,114,101,100,32,105,110,100,101,112, +101,110,100,101,110,116,32,97,110,100,32,115,101,112,97,114, +97,116,101,32,119,111,114,107,115,32,105,110,10,116,104,101, +109,115,101,108,118,101,115,44,32,116,104,101,110,32,116,104, +105,115,32,76,105,99,101,110,115,101,44,32,97,110,100,32, +105,116,115,32,116,101,114,109,115,44,32,100,111,32,110,111, +116,32,97,112,112,108,121,32,116,111,32,116,104,111,115,101, +10,115,101,99,116,105,111,110,115,32,32,119,104,101,110,32, +121,111,117,32,100,105,115,116,114,105,98,117,116,101,32,116, +104,101,109,32,97,115,32,115,101,112,97,114,97,116,101,32, +119,111,114,107,115,46,32,32,66,117,116,32,119,104,101,110, +32,121,111,117,10,100,105,115,116,114,105,98,117,116,101,32, +116,104,101,32,115,97,109,101,32,115,101,99,116,105,111,110, +115,32,97,115,32,112,97,114,116,32,111,102,32,97,32,119, +104,111,108,101,32,119,104,105,99,104,32,105,115,32,97,32, +119,111,114,107,32,98,97,115,101,100,10,111,110,32,116,104, +101,32,80,114,111,103,114,97,109,44,32,116,104,101,32,100, +105,115,116,114,105,98,117,116,105,111,110,32,111,102,32,116, +104,101,32,119,104,111,108,101,32,109,117,115,116,32,98,101, +32,111,110,32,116,104,101,32,116,101,114,109,115,32,111,102, +10,116,104,105,115,32,76,105,99,101,110,115,101,44,32,119, +104,111,115,101,32,112,101,114,109,105,115,115,105,111,110,115, +32,102,111,114,32,111,116,104,101,114,32,108,105,99,101,110, +115,101,101,115,32,101,120,116,101,110,100,32,116,111,32,116, +104,101,10,101,110,116,105,114,101,32,119,104,111,108,101,44, +32,97,110,100,32,116,104,117,115,32,116,111,32,101,97,99, +104,32,97,110,100,32,101,118,101,114,121,32,112,97,114,116, +32,114,101,103,97,114,100,108,101,115,115,32,111,102,32,119, +104,111,32,119,114,111,116,101,10,105,116,46,10,60,112,62, +10,84,104,117,115,44,32,105,116,32,105,115,32,110,111,116, +32,116,104,101,32,105,110,116,101,110,116,32,111,102,32,116, +104,105,115,32,115,101,99,116,105,111,110,32,116,111,32,99, +108,97,105,109,32,114,105,103,104,116,115,32,111,114,32,99, +111,110,116,101,115,116,10,121,111,117,114,32,114,105,103,104, +116,115,32,116,111,32,119,111,114,107,32,119,114,105,116,116, +101,110,32,101,110,116,105,114,101,108,121,32,98,121,32,121, +111,117,59,32,114,97,116,104,101,114,44,32,116,104,101,32, +105,110,116,101,110,116,32,105,115,32,116,111,10,101,120,101, +114,99,105,115,101,32,116,104,101,32,114,105,103,104,116,32, +116,111,32,99,111,110,116,114,111,108,32,116,104,101,32,100, +105,115,116,114,105,98,117,116,105,111,110,32,111,102,32,100, +101,114,105,118,97,116,105,118,101,32,111,114,10,99,111,108, +108,101,99,116,105,118,101,32,119,111,114,107,115,32,98,97, +115,101,100,32,111,110,32,116,104,101,32,80,114,111,103,114, +97,109,46,10,60,112,62,10,73,110,32,97,100,100,105,116, +105,111,110,44,32,109,101,114,101,32,97,103,103,114,101,103, +97,116,105,111,110,32,111,102,32,97,110,111,116,104,101,114, +32,119,111,114,107,32,110,111,116,32,98,97,115,101,100,32, +111,110,32,116,104,101,32,80,114,111,103,114,97,109,10,119, +105,116,104,32,116,104,101,32,80,114,111,103,114,97,109,32, +40,111,114,32,119,105,116,104,32,97,32,119,111,114,107,32, +98,97,115,101,100,32,111,110,32,116,104,101,32,80,114,111, +103,114,97,109,41,32,111,110,32,97,32,118,111,108,117,109, +101,32,111,102,10,97,32,115,116,111,114,97,103,101,32,111, +114,32,100,105,115,116,114,105,98,117,116,105,111,110,32,109, +101,100,105,117,109,32,100,111,101,115,32,110,111,116,32,98, +114,105,110,103,32,116,104,101,32,111,116,104,101,114,32,119, +111,114,107,32,117,110,100,101,114,10,116,104,101,32,115,99, +111,112,101,32,111,102,32,116,104,105,115,32,76,105,99,101, +110,115,101,46,10,60,112,62,10,51,46,32,89,111,117,32, +109,97,121,32,99,111,112,121,32,97,110,100,32,100,105,115, +116,114,105,98,117,116,101,32,116,104,101,32,80,114,111,103, +114,97,109,32,40,111,114,32,97,32,119,111,114,107,32,98, +97,115,101,100,32,111,110,32,105,116,44,10,117,110,100,101, +114,32,83,101,99,116,105,111,110,32,50,41,32,105,110,32, +111,98,106,101,99,116,32,99,111,100,101,32,111,114,32,101, +120,101,99,117,116,97,98,108,101,32,102,111,114,109,32,117, +110,100,101,114,32,116,104,101,32,116,101,114,109,115,32,111, +102,10,83,101,99,116,105,111,110,115,32,49,32,97,110,100, +32,50,32,97,98,111,118,101,32,112,114,111,118,105,100,101, +100,32,116,104,97,116,32,121,111,117,32,97,108,115,111,32, +100,111,32,111,110,101,32,111,102,32,116,104,101,32,102,111, +108,108,111,119,105,110,103,58,10,60,112,62,10,32,32,32, +32,97,41,32,65,99,99,111,109,112,97,110,121,32,105,116, +32,119,105,116,104,32,116,104,101,32,99,111,109,112,108,101, +116,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103, +32,109,97,99,104,105,110,101,45,114,101,97,100,97,98,108, +101,10,32,32,32,32,115,111,117,114,99,101,32,99,111,100, +101,44,32,119,104,105,99,104,32,109,117,115,116,32,98,101, +32,100,105,115,116,114,105,98,117,116,101,100,32,117,110,100, +101,114,32,116,104,101,32,116,101,114,109,115,32,111,102,32, +83,101,99,116,105,111,110,115,10,32,32,32,32,49,32,97, +110,100,32,50,32,97,98,111,118,101,32,111,110,32,97,32, +109,101,100,105,117,109,32,99,117,115,116,111,109,97,114,105, +108,121,32,117,115,101,100,32,102,111,114,32,115,111,102,116, +119,97,114,101,32,105,110,116,101,114,99,104,97,110,103,101, +59,32,111,114,44,10,60,112,62,10,32,32,32,32,98,41, +32,65,99,99,111,109,112,97,110,121,32,105,116,32,119,105, +116,104,32,97,32,119,114,105,116,116,101,110,32,111,102,102, +101,114,44,32,118,97,108,105,100,32,102,111,114,32,97,116, +32,108,101,97,115,116,32,116,104,114,101,101,10,32,32,32, +32,121,101,97,114,115,44,32,116,111,32,103,105,118,101,32, +97,110,121,32,116,104,105,114,100,32,112,97,114,116,121,44, +32,102,111,114,32,97,32,99,104,97,114,103,101,32,110,111, +32,109,111,114,101,32,116,104,97,110,32,121,111,117,114,10, +32,32,32,32,99,111,115,116,32,111,102,32,112,104,121,115, +105,99,97,108,108,121,32,112,101,114,102,111,114,109,105,110, +103,32,115,111,117,114,99,101,32,100,105,115,116,114,105,98, +117,116,105,111,110,44,32,97,32,99,111,109,112,108,101,116, +101,10,32,32,32,32,109,97,99,104,105,110,101,45,114,101, +97,100,97,98,108,101,32,99,111,112,121,32,111,102,32,116, +104,101,32,99,111,114,114,101,115,112,111,110,100,105,110,103, +32,115,111,117,114,99,101,32,99,111,100,101,44,32,116,111, +32,98,101,10,32,32,32,32,100,105,115,116,114,105,98,117, +116,101,100,32,117,110,100,101,114,32,116,104,101,32,116,101, +114,109,115,32,111,102,32,83,101,99,116,105,111,110,115,32, +49,32,97,110,100,32,50,32,97,98,111,118,101,32,111,110, +32,97,32,109,101,100,105,117,109,10,32,32,32,32,99,117, +115,116,111,109,97,114,105,108,121,32,117,115,101,100,32,102, +111,114,32,115,111,102,116,119,97,114,101,32,105,110,116,101, +114,99,104,97,110,103,101,59,32,111,114,44,10,60,112,62, +10,32,32,32,32,99,41,32,65,99,99,111,109,112,97,110, +121,32,105,116,32,119,105,116,104,32,116,104,101,32,105,110, +102,111,114,109,97,116,105,111,110,32,121,111,117,32,114,101, +99,101,105,118,101,100,32,97,115,32,116,111,32,116,104,101, +32,111,102,102,101,114,10,32,32,32,32,116,111,32,100,105, +115,116,114,105,98,117,116,101,32,99,111,114,114,101,115,112, +111,110,100,105,110,103,32,115,111,117,114,99,101,32,99,111, +100,101,46,32,32,40,84,104,105,115,32,97,108,116,101,114, +110,97,116,105,118,101,32,105,115,10,32,32,32,32,97,108, +108,111,119,101,100,32,111,110,108,121,32,102,111,114,32,110, +111,110,99,111,109,109,101,114,99,105,97,108,32,100,105,115, +116,114,105,98,117,116,105,111,110,32,97,110,100,32,111,110, +108,121,32,105,102,32,121,111,117,10,32,32,32,32,114,101, +99,101,105,118,101,100,32,116,104,101,32,112,114,111,103,114, +97,109,32,105,110,32,111,98,106,101,99,116,32,99,111,100, +101,32,111,114,32,101,120,101,99,117,116,97,98,108,101,32, +102,111,114,109,32,119,105,116,104,32,115,117,99,104,10,32, +32,32,32,97,110,32,111,102,102,101,114,44,32,105,110,32, +97,99,99,111,114,100,32,119,105,116,104,32,83,117,98,115, +101,99,116,105,111,110,32,98,32,97,98,111,118,101,46,41, +10,60,112,62,10,84,104,101,32,115,111,117,114,99,101,32, +99,111,100,101,32,102,111,114,32,97,32,119,111,114,107,32, +109,101,97,110,115,32,116,104,101,32,112,114,101,102,101,114, +114,101,100,32,102,111,114,109,32,111,102,32,116,104,101,32, +119,111,114,107,32,102,111,114,10,109,97,107,105,110,103,32, +109,111,100,105,102,105,99,97,116,105,111,110,115,32,116,111, +32,105,116,46,32,32,70,111,114,32,97,110,32,101,120,101, +99,117,116,97,98,108,101,32,119,111,114,107,44,32,99,111, +109,112,108,101,116,101,32,115,111,117,114,99,101,10,99,111, +100,101,32,109,101,97,110,115,32,97,108,108,32,116,104,101, +32,115,111,117,114,99,101,32,99,111,100,101,32,102,111,114, +32,97,108,108,32,109,111,100,117,108,101,115,32,105,116,32, +99,111,110,116,97,105,110,115,44,32,112,108,117,115,32,97, +110,121,10,97,115,115,111,99,105,97,116,101,100,32,105,110, +116,101,114,102,97,99,101,32,100,101,102,105,110,105,116,105, +111,110,32,102,105,108,101,115,44,32,112,108,117,115,32,116, +104,101,32,115,99,114,105,112,116,115,32,117,115,101,100,32, +116,111,10,99,111,110,116,114,111,108,32,99,111,109,112,105, +108,97,116,105,111,110,32,97,110,100,32,105,110,115,116,97, +108,108,97,116,105,111,110,32,111,102,32,116,104,101,32,101, +120,101,99,117,116,97,98,108,101,46,32,32,72,111,119,101, +118,101,114,44,32,97,115,32,97,10,115,112,101,99,105,97, +108,32,101,120,99,101,112,116,105,111,110,44,32,116,104,101, +32,115,111,117,114,99,101,32,99,111,100,101,32,100,105,115, +116,114,105,98,117,116,101,100,32,110,101,101,100,32,110,111, +116,32,105,110,99,108,117,100,101,10,97,110,121,116,104,105, +110,103,32,116,104,97,116,32,105,115,32,110,111,114,109,97, +108,108,121,32,100,105,115,116,114,105,98,117,116,101,100,32, +40,105,110,32,101,105,116,104,101,114,32,115,111,117,114,99, +101,32,111,114,32,98,105,110,97,114,121,10,102,111,114,109, +41,32,119,105,116,104,32,116,104,101,32,109,97,106,111,114, +32,99,111,109,112,111,110,101,110,116,115,32,40,99,111,109, +112,105,108,101,114,44,32,107,101,114,110,101,108,44,32,97, +110,100,32,115,111,32,111,110,41,32,111,102,32,116,104,101, +10,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101, +109,32,111,110,32,119,104,105,99,104,32,116,104,101,32,101, +120,101,99,117,116,97,98,108,101,32,114,117,110,115,44,32, +117,110,108,101,115,115,32,116,104,97,116,32,99,111,109,112, +111,110,101,110,116,10,105,116,115,101,108,102,32,97,99,99, +111,109,112,97,110,105,101,115,32,116,104,101,32,101,120,101, +99,117,116,97,98,108,101,46,10,60,112,62,10,73,102,32, +100,105,115,116,114,105,98,117,116,105,111,110,32,111,102,32, +101,120,101,99,117,116,97,98,108,101,32,111,114,32,111,98, +106,101,99,116,32,99,111,100,101,32,105,115,32,109,97,100, +101,32,98,121,32,111,102,102,101,114,105,110,103,10,97,99, +99,101,115,115,32,116,111,32,99,111,112,121,32,102,114,111, +109,32,97,32,100,101,115,105,103,110,97,116,101,100,32,112, +108,97,99,101,44,32,116,104,101,110,32,111,102,102,101,114, +105,110,103,32,101,113,117,105,118,97,108,101,110,116,10,97, +99,99,101,115,115,32,116,111,32,99,111,112,121,32,116,104, +101,32,115,111,117,114,99,101,32,99,111,100,101,32,102,114, +111,109,32,116,104,101,32,115,97,109,101,32,112,108,97,99, +101,32,99,111,117,110,116,115,32,97,115,10,100,105,115,116, +114,105,98,117,116,105,111,110,32,111,102,32,116,104,101,32, +115,111,117,114,99,101,32,99,111,100,101,44,32,101,118,101, +110,32,116,104,111,117,103,104,32,116,104,105,114,100,32,112, +97,114,116,105,101,115,32,97,114,101,32,110,111,116,10,99, +111,109,112,101,108,108,101,100,32,116,111,32,99,111,112,121, +32,116,104,101,32,115,111,117,114,99,101,32,97,108,111,110, +103,32,119,105,116,104,32,116,104,101,32,111,98,106,101,99, +116,32,99,111,100,101,46,10,60,112,62,10,52,46,32,89, +111,117,32,109,97,121,32,110,111,116,32,99,111,112,121,44, +32,109,111,100,105,102,121,44,32,115,117,98,108,105,99,101, +110,115,101,44,32,111,114,32,100,105,115,116,114,105,98,117, +116,101,32,116,104,101,32,80,114,111,103,114,97,109,10,101, +120,99,101,112,116,32,97,115,32,101,120,112,114,101,115,115, +108,121,32,112,114,111,118,105,100,101,100,32,117,110,100,101, +114,32,116,104,105,115,32,76,105,99,101,110,115,101,46,32, +32,65,110,121,32,97,116,116,101,109,112,116,10,111,116,104, +101,114,119,105,115,101,32,116,111,32,99,111,112,121,44,32, +109,111,100,105,102,121,44,32,115,117,98,108,105,99,101,110, +115,101,32,111,114,32,100,105,115,116,114,105,98,117,116,101, +32,116,104,101,32,80,114,111,103,114,97,109,32,105,115,10, +118,111,105,100,44,32,97,110,100,32,119,105,108,108,32,97, +117,116,111,109,97,116,105,99,97,108,108,121,32,116,101,114, +109,105,110,97,116,101,32,121,111,117,114,32,114,105,103,104, +116,115,32,117,110,100,101,114,32,116,104,105,115,32,76,105, +99,101,110,115,101,46,10,72,111,119,101,118,101,114,44,32, +112,97,114,116,105,101,115,32,119,104,111,32,104,97,118,101, +32,114,101,99,101,105,118,101,100,32,99,111,112,105,101,115, +44,32,111,114,32,114,105,103,104,116,115,44,32,102,114,111, +109,32,121,111,117,32,117,110,100,101,114,10,116,104,105,115, +32,76,105,99,101,110,115,101,32,119,105,108,108,32,110,111, +116,32,104,97,118,101,32,116,104,101,105,114,32,108,105,99, +101,110,115,101,115,32,116,101,114,109,105,110,97,116,101,100, +32,115,111,32,108,111,110,103,32,97,115,32,115,117,99,104, +10,112,97,114,116,105,101,115,32,114,101,109,97,105,110,32, +105,110,32,102,117,108,108,32,99,111,109,112,108,105,97,110, +99,101,46,10,60,112,62,10,53,46,32,89,111,117,32,97, +114,101,32,110,111,116,32,114,101,113,117,105,114,101,100,32, +116,111,32,97,99,99,101,112,116,32,116,104,105,115,32,76, +105,99,101,110,115,101,44,32,115,105,110,99,101,32,121,111, +117,32,104,97,118,101,32,110,111,116,10,115,105,103,110,101, +100,32,105,116,46,32,32,72,111,119,101,118,101,114,44,32, +110,111,116,104,105,110,103,32,101,108,115,101,32,103,114,97, +110,116,115,32,121,111,117,32,112,101,114,109,105,115,115,105, +111,110,32,116,111,32,109,111,100,105,102,121,32,111,114,10, +100,105,115,116,114,105,98,117,116,101,32,116,104,101,32,80, +114,111,103,114,97,109,32,111,114,32,105,116,115,32,100,101, +114,105,118,97,116,105,118,101,32,119,111,114,107,115,46,32, +32,84,104,101,115,101,32,97,99,116,105,111,110,115,32,97, +114,101,10,112,114,111,104,105,98,105,116,101,100,32,98,121, +32,108,97,119,32,105,102,32,121,111,117,32,100,111,32,110, +111,116,32,97,99,99,101,112,116,32,116,104,105,115,32,76, +105,99,101,110,115,101,46,32,32,84,104,101,114,101,102,111, +114,101,44,32,98,121,10,109,111,100,105,102,121,105,110,103, +32,111,114,32,100,105,115,116,114,105,98,117,116,105,110,103, +32,116,104,101,32,80,114,111,103,114,97,109,32,40,111,114, +32,97,110,121,32,119,111,114,107,32,98,97,115,101,100,32, +111,110,32,116,104,101,10,80,114,111,103,114,97,109,41,44, +32,121,111,117,32,105,110,100,105,99,97,116,101,32,121,111, +117,114,32,97,99,99,101,112,116,97,110,99,101,32,111,102, +32,116,104,105,115,32,76,105,99,101,110,115,101,32,116,111, +32,100,111,32,115,111,44,32,97,110,100,10,97,108,108,32, +105,116,115,32,116,101,114,109,115,32,97,110,100,32,99,111, +110,100,105,116,105,111,110,115,32,102,111,114,32,99,111,112, +121,105,110,103,44,32,100,105,115,116,114,105,98,117,116,105, +110,103,32,111,114,32,109,111,100,105,102,121,105,110,103,10, +116,104,101,32,80,114,111,103,114,97,109,32,111,114,32,119, +111,114,107,115,32,98,97,115,101,100,32,111,110,32,105,116, +46,10,60,112,62,10,54,46,32,69,97,99,104,32,116,105, +109,101,32,121,111,117,32,114,101,100,105,115,116,114,105,98, +117,116,101,32,116,104,101,32,80,114,111,103,114,97,109,32, +40,111,114,32,97,110,121,32,119,111,114,107,32,98,97,115, +101,100,32,111,110,32,116,104,101,10,80,114,111,103,114,97, +109,41,44,32,116,104,101,32,114,101,99,105,112,105,101,110, +116,32,97,117,116,111,109,97,116,105,99,97,108,108,121,32, +114,101,99,101,105,118,101,115,32,97,32,108,105,99,101,110, +115,101,32,102,114,111,109,32,116,104,101,10,111,114,105,103, +105,110,97,108,32,108,105,99,101,110,115,111,114,32,116,111, +32,99,111,112,121,44,32,100,105,115,116,114,105,98,117,116, +101,32,111,114,32,109,111,100,105,102,121,32,116,104,101,32, +80,114,111,103,114,97,109,32,115,117,98,106,101,99,116,32, +116,111,10,116,104,101,115,101,32,116,101,114,109,115,32,97, +110,100,32,99,111,110,100,105,116,105,111,110,115,46,32,32, +89,111,117,32,109,97,121,32,110,111,116,32,105,109,112,111, +115,101,32,97,110,121,32,102,117,114,116,104,101,114,10,114, +101,115,116,114,105,99,116,105,111,110,115,32,111,110,32,116, +104,101,32,114,101,99,105,112,105,101,110,116,115,39,32,101, +120,101,114,99,105,115,101,32,111,102,32,116,104,101,32,114, +105,103,104,116,115,32,103,114,97,110,116,101,100,32,104,101, +114,101,105,110,46,10,89,111,117,32,97,114,101,32,110,111, +116,32,114,101,115,112,111,110,115,105,98,108,101,32,102,111, +114,32,101,110,102,111,114,99,105,110,103,32,99,111,109,112, +108,105,97,110,99,101,32,98,121,32,116,104,105,114,100,32, +112,97,114,116,105,101,115,32,116,111,10,116,104,105,115,32, +76,105,99,101,110,115,101,46,10,60,112,62,10,55,46,32, +73,102,44,32,97,115,32,97,32,99,111,110,115,101,113,117, +101,110,99,101,32,111,102,32,97,32,99,111,117,114,116,32, +106,117,100,103,109,101,110,116,32,111,114,32,97,108,108,101, +103,97,116,105,111,110,32,111,102,32,112,97,116,101,110,116, +10,105,110,102,114,105,110,103,101,109,101,110,116,32,111,114, +32,102,111,114,32,97,110,121,32,111,116,104,101,114,32,114, +101,97,115,111,110,32,40,110,111,116,32,108,105,109,105,116, +101,100,32,116,111,32,112,97,116,101,110,116,32,105,115,115, +117,101,115,41,44,10,99,111,110,100,105,116,105,111,110,115, +32,97,114,101,32,105,109,112,111,115,101,100,32,111,110,32, +121,111,117,32,40,119,104,101,116,104,101,114,32,98,121,32, +99,111,117,114,116,32,111,114,100,101,114,44,32,97,103,114, +101,101,109,101,110,116,32,111,114,32,10,111,116,104,101,114, +119,105,115,101,41,32,116,104,97,116,32,99,111,110,116,114, +97,100,105,99,116,32,116,104,101,32,99,111,110,100,105,116, +105,111,110,115,32,111,102,32,116,104,105,115,32,76,105,99, +101,110,115,101,44,32,116,104,101,121,32,100,111,32,110,111, +116,10,101,120,99,117,115,101,32,121,111,117,32,102,114,111, +109,32,116,104,101,32,99,111,110,100,105,116,105,111,110,115, +32,111,102,32,116,104,105,115,32,76,105,99,101,110,115,101, +46,32,32,73,102,32,121,111,117,32,99,97,110,110,111,116, +10,100,105,115,116,114,105,98,117,116,101,32,115,111,32,97, +115,32,116,111,32,115,97,116,105,115,102,121,32,115,105,109, +117,108,116,97,110,101,111,117,115,108,121,32,121,111,117,114, +32,111,98,108,105,103,97,116,105,111,110,115,32,117,110,100, +101,114,32,116,104,105,115,10,76,105,99,101,110,115,101,32, +97,110,100,32,97,110,121,32,111,116,104,101,114,32,112,101, +114,116,105,110,101,110,116,32,111,98,108,105,103,97,116,105, +111,110,115,44,32,116,104,101,110,32,97,115,32,97,32,99, +111,110,115,101,113,117,101,110,99,101,32,121,111,117,10,109, +97,121,32,110,111,116,32,100,105,115,116,114,105,98,117,116, +101,32,116,104,101,32,80,114,111,103,114,97,109,32,97,116, +32,97,108,108,46,32,32,70,111,114,32,101,120,97,109,112, +108,101,44,32,105,102,32,97,32,112,97,116,101,110,116,10, +108,105,99,101,110,115,101,32,119,111,117,108,100,32,110,111, +116,32,112,101,114,109,105,116,32,114,111,121,97,108,116,121, +45,102,114,101,101,32,114,101,100,105,115,116,114,105,98,117, +116,105,111,110,32,111,102,32,116,104,101,32,80,114,111,103, +114,97,109,32,98,121,10,97,108,108,32,116,104,111,115,101, +32,119,104,111,32,114,101,99,101,105,118,101,32,99,111,112, +105,101,115,32,100,105,114,101,99,116,108,121,32,111,114,32, +105,110,100,105,114,101,99,116,108,121,32,116,104,114,111,117, +103,104,32,121,111,117,44,32,116,104,101,110,10,116,104,101, +32,111,110,108,121,32,119,97,121,32,121,111,117,32,99,111, +117,108,100,32,115,97,116,105,115,102,121,32,98,111,116,104, +32,105,116,32,97,110,100,32,116,104,105,115,32,76,105,99, +101,110,115,101,32,119,111,117,108,100,32,98,101,32,116,111, +10,114,101,102,114,97,105,110,32,101,110,116,105,114,101,108, +121,32,102,114,111,109,32,100,105,115,116,114,105,98,117,116, +105,111,110,32,111,102,32,116,104,101,32,80,114,111,103,114, +97,109,46,10,60,112,62,10,73,102,32,97,110,121,32,112, +111,114,116,105,111,110,32,111,102,32,116,104,105,115,32,115, +101,99,116,105,111,110,32,105,115,32,104,101,108,100,32,105, +110,118,97,108,105,100,32,111,114,32,117,110,101,110,102,111, +114,99,101,97,98,108,101,32,117,110,100,101,114,10,97,110, +121,32,112,97,114,116,105,99,117,108,97,114,32,99,105,114, +99,117,109,115,116,97,110,99,101,44,32,116,104,101,32,98, +97,108,97,110,99,101,32,111,102,32,116,104,101,32,115,101, +99,116,105,111,110,32,105,115,32,105,110,116,101,110,100,101, +100,32,116,111,10,97,112,112,108,121,32,97,110,100,32,116, +104,101,32,115,101,99,116,105,111,110,32,97,115,32,97,32, +119,104,111,108,101,32,105,115,32,105,110,116,101,110,100,101, +100,32,116,111,32,97,112,112,108,121,32,105,110,32,111,116, +104,101,114,10,99,105,114,99,117,109,115,116,97,110,99,101, +115,46,10,60,112,62,10,73,116,32,105,115,32,110,111,116, +32,116,104,101,32,112,117,114,112,111,115,101,32,111,102,32, +116,104,105,115,32,115,101,99,116,105,111,110,32,116,111,32, +105,110,100,117,99,101,32,121,111,117,32,116,111,32,105,110, +102,114,105,110,103,101,32,97,110,121,10,112,97,116,101,110, +116,115,32,111,114,32,111,116,104,101,114,32,112,114,111,112, +101,114,116,121,32,114,105,103,104,116,32,99,108,97,105,109, +115,32,111,114,32,116,111,32,99,111,110,116,101,115,116,32, +118,97,108,105,100,105,116,121,32,111,102,32,97,110,121,10, +115,117,99,104,32,99,108,97,105,109,115,59,32,116,104,105, +115,32,115,101,99,116,105,111,110,32,104,97,115,32,116,104, +101,32,115,111,108,101,32,112,117,114,112,111,115,101,32,111, +102,32,112,114,111,116,101,99,116,105,110,103,32,116,104,101, +10,105,110,116,101,103,114,105,116,121,32,111,102,32,116,104, +101,32,102,114,101,101,32,115,111,102,116,119,97,114,101,32, +100,105,115,116,114,105,98,117,116,105,111,110,32,115,121,115, +116,101,109,44,32,119,104,105,99,104,32,105,115,10,105,109, +112,108,101,109,101,110,116,101,100,32,98,121,32,112,117,98, +108,105,99,32,108,105,99,101,110,115,101,32,112,114,97,99, +116,105,99,101,115,46,32,32,77,97,110,121,32,112,101,111, +112,108,101,32,104,97,118,101,32,109,97,100,101,10,103,101, +110,101,114,111,117,115,32,99,111,110,116,114,105,98,117,116, +105,111,110,115,32,116,111,32,116,104,101,32,119,105,100,101, +32,114,97,110,103,101,32,111,102,32,115,111,102,116,119,97, +114,101,32,100,105,115,116,114,105,98,117,116,101,100,10,116, +104,114,111,117,103,104,32,116,104,97,116,32,115,121,115,116, +101,109,32,105,110,32,114,101,108,105,97,110,99,101,32,111, +110,32,99,111,110,115,105,115,116,101,110,116,32,97,112,112, +108,105,99,97,116,105,111,110,32,111,102,32,116,104,97,116, +10,115,121,115,116,101,109,59,32,105,116,32,105,115,32,117, +112,32,116,111,32,116,104,101,32,97,117,116,104,111,114,47, +100,111,110,111,114,32,116,111,32,100,101,99,105,100,101,32, +105,102,32,104,101,32,111,114,32,115,104,101,32,105,115,32, +119,105,108,108,105,110,103,10,116,111,32,100,105,115,116,114, +105,98,117,116,101,32,115,111,102,116,119,97,114,101,32,116, +104,114,111,117,103,104,32,97,110,121,32,111,116,104,101,114, +32,115,121,115,116,101,109,32,97,110,100,32,97,32,108,105, +99,101,110,115,101,101,32,99,97,110,110,111,116,10,105,109, +112,111,115,101,32,116,104,97,116,32,99,104,111,105,99,101, +46,10,60,112,62,10,84,104,105,115,32,115,101,99,116,105, +111,110,32,105,115,32,105,110,116,101,110,100,101,100,32,116, +111,32,109,97,107,101,32,116,104,111,114,111,117,103,104,108, +121,32,99,108,101,97,114,32,119,104,97,116,32,105,115,32, +98,101,108,105,101,118,101,100,32,116,111,10,98,101,32,97, +32,99,111,110,115,101,113,117,101,110,99,101,32,111,102,32, +116,104,101,32,114,101,115,116,32,111,102,32,116,104,105,115, +32,76,105,99,101,110,115,101,46,10,60,112,62,10,56,46, +32,73,102,32,116,104,101,32,100,105,115,116,114,105,98,117, +116,105,111,110,32,97,110,100,47,111,114,32,117,115,101,32, +111,102,32,116,104,101,32,80,114,111,103,114,97,109,32,105, +115,32,114,101,115,116,114,105,99,116,101,100,32,105,110,10, +99,101,114,116,97,105,110,32,99,111,117,110,116,114,105,101, +115,32,101,105,116,104,101,114,32,98,121,32,112,97,116,101, +110,116,115,32,111,114,32,98,121,32,99,111,112,121,114,105, +103,104,116,101,100,32,105,110,116,101,114,102,97,99,101,115, +44,32,116,104,101,10,111,114,105,103,105,110,97,108,32,99, +111,112,121,114,105,103,104,116,32,104,111,108,100,101,114,32, +119,104,111,32,112,108,97,99,101,115,32,116,104,101,32,80, +114,111,103,114,97,109,32,117,110,100,101,114,32,116,104,105, +115,32,76,105,99,101,110,115,101,10,109,97,121,32,97,100, +100,32,97,110,32,101,120,112,108,105,99,105,116,32,103,101, +111,103,114,97,112,104,105,99,97,108,32,100,105,115,116,114, +105,98,117,116,105,111,110,32,108,105,109,105,116,97,116,105, +111,110,32,101,120,99,108,117,100,105,110,103,10,116,104,111, +115,101,32,99,111,117,110,116,114,105,101,115,44,32,115,111, +32,116,104,97,116,32,100,105,115,116,114,105,98,117,116,105, +111,110,32,105,115,32,112,101,114,109,105,116,116,101,100,32, +111,110,108,121,32,105,110,32,111,114,32,97,109,111,110,103, +10,99,111,117,110,116,114,105,101,115,32,110,111,116,32,116, +104,117,115,32,101,120,99,108,117,100,101,100,46,32,32,73, +110,32,115,117,99,104,32,99,97,115,101,44,32,116,104,105, +115,32,76,105,99,101,110,115,101,32,105,110,99,111,114,112, +111,114,97,116,101,115,10,116,104,101,32,108,105,109,105,116, +97,116,105,111,110,32,97,115,32,105,102,32,119,114,105,116, +116,101,110,32,105,110,32,116,104,101,32,98,111,100,121,32, +111,102,32,116,104,105,115,32,76,105,99,101,110,115,101,46, +10,60,112,62,10,57,46,32,84,104,101,32,70,114,101,101, +32,83,111,102,116,119,97,114,101,32,70,111,117,110,100,97, +116,105,111,110,32,109,97,121,32,112,117,98,108,105,115,104, +32,114,101,118,105,115,101,100,32,97,110,100,47,111,114,32, +110,101,119,10,118,101,114,115,105,111,110,115,32,111,102,32, +116,104,101,32,71,101,110,101,114,97,108,32,80,117,98,108, +105,99,32,76,105,99,101,110,115,101,32,102,114,111,109,32, +116,105,109,101,32,116,111,32,116,105,109,101,46,32,32,83, +117,99,104,32,110,101,119,10,118,101,114,115,105,111,110,115, +32,119,105,108,108,32,98,101,32,115,105,109,105,108,97,114, +32,105,110,32,115,112,105,114,105,116,32,116,111,32,116,104, +101,32,112,114,101,115,101,110,116,32,118,101,114,115,105,111, +110,44,32,98,117,116,32,109,97,121,10,100,105,102,102,101, +114,32,105,110,32,100,101,116,97,105,108,32,116,111,32,97, +100,100,114,101,115,115,32,110,101,119,32,112,114,111,98,108, +101,109,115,32,111,114,32,99,111,110,99,101,114,110,115,46, +10,60,112,62,10,69,97,99,104,32,118,101,114,115,105,111, +110,32,105,115,32,103,105,118,101,110,32,97,32,100,105,115, +116,105,110,103,117,105,115,104,105,110,103,32,118,101,114,115, +105,111,110,32,110,117,109,98,101,114,46,32,32,73,102,32, +116,104,101,32,80,114,111,103,114,97,109,10,115,112,101,99, +105,102,105,101,115,32,97,32,118,101,114,115,105,111,110,32, +110,117,109,98,101,114,32,111,102,32,116,104,105,115,32,76, +105,99,101,110,115,101,32,119,104,105,99,104,32,97,112,112, +108,105,101,115,32,116,111,32,105,116,32,97,110,100,10,34, +97,110,121,32,108,97,116,101,114,32,118,101,114,115,105,111, +110,34,44,32,121,111,117,32,104,97,118,101,32,116,104,101, +32,111,112,116,105,111,110,32,111,102,32,102,111,108,108,111, +119,105,110,103,32,116,104,101,32,116,101,114,109,115,32,97, +110,100,10,99,111,110,100,105,116,105,111,110,115,32,101,105, +116,104,101,114,32,111,102,32,116,104,97,116,32,118,101,114, +115,105,111,110,32,111,114,32,111,102,32,97,110,121,32,108, +97,116,101,114,32,118,101,114,115,105,111,110,32,112,117,98, +108,105,115,104,101,100,32,98,121,10,116,104,101,32,70,114, +101,101,32,83,111,102,116,119,97,114,101,32,70,111,117,110, +100,97,116,105,111,110,46,32,32,73,102,32,116,104,101,32, +80,114,111,103,114,97,109,32,100,111,101,115,32,110,111,116, +32,115,112,101,99,105,102,121,32,97,10,118,101,114,115,105, +111,110,32,110,117,109,98,101,114,32,111,102,32,116,104,105, +115,32,76,105,99,101,110,115,101,44,32,121,111,117,32,109, +97,121,32,99,104,111,111,115,101,32,97,110,121,32,118,101, +114,115,105,111,110,32,101,118,101,114,10,112,117,98,108,105, +115,104,101,100,32,98,121,32,116,104,101,32,70,114,101,101, +32,83,111,102,116,119,97,114,101,32,70,111,117,110,100,97, +116,105,111,110,46,10,60,112,62,10,49,48,46,32,73,102, +32,121,111,117,32,119,105,115,104,32,116,111,32,105,110,99, +111,114,112,111,114,97,116,101,32,112,97,114,116,115,32,111, +102,32,116,104,101,32,80,114,111,103,114,97,109,32,105,110, +116,111,32,111,116,104,101,114,32,102,114,101,101,10,112,114, +111,103,114,97,109,115,32,119,104,111,115,101,32,100,105,115, +116,114,105,98,117,116,105,111,110,32,99,111,110,100,105,116, +105,111,110,115,32,97,114,101,32,100,105,102,102,101,114,101, +110,116,44,32,119,114,105,116,101,32,116,111,32,116,104,101, +10,97,117,116,104,111,114,32,116,111,32,97,115,107,32,102, +111,114,32,112,101,114,109,105,115,115,105,111,110,46,32,32, +70,111,114,32,115,111,102,116,119,97,114,101,32,119,104,105, +99,104,32,105,115,32,99,111,112,121,114,105,103,104,116,101, +100,32,98,121,10,116,104,101,32,70,114,101,101,32,83,111, +102,116,119,97,114,101,32,70,111,117,110,100,97,116,105,111, +110,44,32,119,114,105,116,101,32,116,111,32,116,104,101,32, +70,114,101,101,32,83,111,102,116,119,97,114,101,32,70,111, +117,110,100,97,116,105,111,110,59,10,119,101,32,115,111,109, +101,116,105,109,101,115,32,109,97,107,101,32,101,120,99,101, +112,116,105,111,110,115,32,102,111,114,32,116,104,105,115,46, +32,32,79,117,114,32,100,101,99,105,115,105,111,110,32,119, +105,108,108,32,98,101,32,103,117,105,100,101,100,32,98,121, +10,116,104,101,32,116,119,111,32,103,111,97,108,115,32,111, +102,32,112,114,101,115,101,114,118,105,110,103,32,116,104,101, +32,102,114,101,101,32,115,116,97,116,117,115,32,111,102,32, +97,108,108,32,100,101,114,105,118,97,116,105,118,101,115,32, +111,102,32,111,117,114,10,102,114,101,101,32,115,111,102,116, +119,97,114,101,32,97,110,100,32,111,102,32,112,114,111,109, +111,116,105,110,103,32,116,104,101,32,115,104,97,114,105,110, +103,32,97,110,100,32,114,101,117,115,101,32,111,102,32,115, +111,102,116,119,97,114,101,10,103,101,110,101,114,97,108,108, +121,46,10,60,112,62,10,60,115,116,114,111,110,103,62,78, +79,32,87,65,82,82,65,78,84,89,60,47,115,116,114,111, +110,103,62,10,60,112,62,10,49,49,46,32,66,69,67,65, +85,83,69,32,84,72,69,32,80,82,79,71,82,65,77,32, +73,83,32,76,73,67,69,78,83,69,68,32,70,82,69,69, +32,79,70,32,67,72,65,82,71,69,44,32,84,72,69,82, +69,32,73,83,32,78,79,10,87,65,82,82,65,78,84,89, +32,70,79,82,32,84,72,69,32,80,82,79,71,82,65,77, +44,32,84,79,32,84,72,69,32,69,88,84,69,78,84,32, +80,69,82,77,73,84,84,69,68,32,66,89,32,65,80,80, +76,73,67,65,66,76,69,32,76,65,87,46,10,69,88,67, +69,80,84,32,87,72,69,78,32,79,84,72,69,82,87,73, +83,69,32,83,84,65,84,69,68,32,73,78,32,87,82,73, +84,73,78,71,32,84,72,69,32,67,79,80,89,82,73,71, +72,84,32,72,79,76,68,69,82,83,32,65,78,68,47,79, +82,10,79,84,72,69,82,32,80,65,82,84,73,69,83,32, +80,82,79,86,73,68,69,32,84,72,69,32,80,82,79,71, +82,65,77,32,34,65,83,32,73,83,34,32,87,73,84,72, +79,85,84,32,87,65,82,82,65,78,84,89,32,79,70,32, +65,78,89,10,75,73,78,68,44,32,69,73,84,72,69,82, +32,69,88,80,82,69,83,83,69,68,32,79,82,32,73,77, +80,76,73,69,68,44,32,73,78,67,76,85,68,73,78,71, +44,32,66,85,84,32,78,79,84,32,76,73,77,73,84,69, +68,32,84,79,44,32,84,72,69,10,73,77,80,76,73,69, +68,32,87,65,82,82,65,78,84,73,69,83,32,79,70,32, +77,69,82,67,72,65,78,84,65,66,73,76,73,84,89,32, +65,78,68,32,70,73,84,78,69,83,83,32,70,79,82,32, +65,32,80,65,82,84,73,67,85,76,65,82,10,80,85,82, +80,79,83,69,46,32,32,84,72,69,32,69,78,84,73,82, +69,32,82,73,83,75,32,65,83,32,84,79,32,84,72,69, +32,81,85,65,76,73,84,89,32,65,78,68,32,80,69,82, +70,79,82,77,65,78,67,69,32,79,70,32,84,72,69,10, +80,82,79,71,82,65,77,32,73,83,32,87,73,84,72,32, +89,79,85,46,32,32,83,72,79,85,76,68,32,84,72,69, +32,80,82,79,71,82,65,77,32,80,82,79,86,69,32,68, +69,70,69,67,84,73,86,69,44,32,89,79,85,32,65,83, +83,85,77,69,10,84,72,69,32,67,79,83,84,32,79,70, +32,65,76,76,32,78,69,67,69,83,83,65,82,89,32,83, +69,82,86,73,67,73,78,71,44,32,82,69,80,65,73,82, +32,79,82,32,67,79,82,82,69,67,84,73,79,78,46,10, +60,112,62,10,49,50,46,32,73,78,32,78,79,32,69,86, +69,78,84,32,85,78,76,69,83,83,32,82,69,81,85,73, +82,69,68,32,66,89,32,65,80,80,76,73,67,65,66,76, +69,32,76,65,87,32,79,82,32,65,71,82,69,69,68,32, +84,79,32,73,78,10,87,82,73,84,73,78,71,32,87,73, +76,76,32,65,78,89,32,67,79,80,89,82,73,71,72,84, +32,72,79,76,68,69,82,44,32,79,82,32,65,78,89,32, +79,84,72,69,82,32,80,65,82,84,89,32,87,72,79,32, +77,65,89,32,77,79,68,73,70,89,10,65,78,68,47,79, +82,32,82,69,68,73,83,84,82,73,66,85,84,69,32,84, +72,69,32,80,82,79,71,82,65,77,32,65,83,32,80,69, +82,77,73,84,84,69,68,32,65,66,79,86,69,44,32,66, +69,32,76,73,65,66,76,69,32,84,79,32,89,79,85,10, +70,79,82,32,68,65,77,65,71,69,83,44,32,73,78,67, +76,85,68,73,78,71,32,65,78,89,32,71,69,78,69,82, +65,76,44,32,83,80,69,67,73,65,76,44,32,73,78,67, +73,68,69,78,84,65,76,32,79,82,10,67,79,78,83,69, +81,85,69,78,84,73,65,76,32,68,65,77,65,71,69,83, +32,65,82,73,83,73,78,71,32,79,85,84,32,79,70,32, +84,72,69,32,85,83,69,32,79,82,32,73,78,65,66,73, +76,73,84,89,32,84,79,32,85,83,69,32,84,72,69,10, +80,82,79,71,82,65,77,32,40,73,78,67,76,85,68,73, +78,71,32,66,85,84,32,78,79,84,32,76,73,77,73,84, +69,68,32,84,79,32,76,79,83,83,32,79,70,32,68,65, +84,65,32,79,82,32,68,65,84,65,32,66,69,73,78,71, +10,82,69,78,68,69,82,69,68,32,73,78,65,67,67,85, +82,65,84,69,32,79,82,32,76,79,83,83,69,83,32,83, +85,83,84,65,73,78,69,68,32,66,89,32,89,79,85,32, +79,82,32,84,72,73,82,68,32,80,65,82,84,73,69,83, +32,79,82,32,65,10,70,65,73,76,85,82,69,32,79,70, +32,84,72,69,32,80,82,79,71,82,65,77,32,84,79,32, +79,80,69,82,65,84,69,32,87,73,84,72,32,65,78,89, +32,79,84,72,69,82,32,80,82,79,71,82,65,77,83,41, +44,32,69,86,69,78,32,73,70,10,83,85,67,72,32,72, +79,76,68,69,82,32,79,82,32,79,84,72,69,82,32,80, +65,82,84,89,32,72,65,83,32,66,69,69,78,32,65,68, +86,73,83,69,68,32,79,70,32,84,72,69,32,80,79,83, +83,73,66,73,76,73,84,89,32,79,70,32,83,85,67,72, +10,68,65,77,65,71,69,83,46,10,60,112,62,10,60,115, +116,114,111,110,103,62,69,78,68,32,79,70,32,84,69,82, +77,83,32,65,78,68,32,67,79,78,68,73,84,73,79,78, +83,60,47,115,116,114,111,110,103,62,10,60,112,62,10,60, +115,116,114,111,110,103,62,72,111,119,32,116,111,32,65,112, +112,108,121,32,84,104,101,115,101,32,84,101,114,109,115,32, +116,111,32,89,111,117,114,32,78,101,119,32,80,114,111,103, +114,97,109,115,60,47,115,116,114,111,110,103,62,60,98,114, +62,10,73,102,32,121,111,117,32,100,101,118,101,108,111,112, +32,97,32,110,101,119,32,112,114,111,103,114,97,109,44,32, +97,110,100,32,121,111,117,32,119,97,110,116,32,105,116,32, +116,111,32,98,101,32,111,102,32,116,104,101,32,103,114,101, +97,116,101,115,116,10,112,111,115,115,105,98,108,101,32,117, +115,101,32,116,111,32,116,104,101,32,112,117,98,108,105,99, +44,32,116,104,101,32,98,101,115,116,32,119,97,121,32,116, +111,32,97,99,104,105,101,118,101,32,116,104,105,115,32,105, +115,32,116,111,32,109,97,107,101,32,105,116,10,102,114,101, +101,32,115,111,102,116,119,97,114,101,32,119,104,105,99,104, +32,101,118,101,114,121,111,110,101,32,99,97,110,32,114,101, +100,105,115,116,114,105,98,117,116,101,32,97,110,100,32,99, +104,97,110,103,101,32,117,110,100,101,114,32,116,104,101,115, +101,10,116,101,114,109,115,46,10,60,112,62,10,84,111,32, +100,111,32,115,111,44,32,97,116,116,97,99,104,32,116,104, +101,32,102,111,108,108,111,119,105,110,103,32,110,111,116,105, +99,101,115,32,116,111,32,116,104,101,32,112,114,111,103,114, +97,109,46,32,32,73,116,32,105,115,32,115,97,102,101,115, +116,10,116,111,32,97,116,116,97,99,104,32,116,104,101,109, +32,116,111,32,116,104,101,32,115,116,97,114,116,32,111,102, +32,101,97,99,104,32,115,111,117,114,99,101,32,102,105,108, +101,32,116,111,32,109,111,115,116,32,101,102,102,101,99,116, +105,118,101,108,121,10,99,111,110,118,101,121,32,116,104,101, +32,101,120,99,108,117,115,105,111,110,32,111,102,32,119,97, +114,114,97,110,116,121,59,32,97,110,100,32,101,97,99,104, +32,102,105,108,101,32,115,104,111,117,108,100,32,104,97,118, +101,32,97,116,32,108,101,97,115,116,10,116,104,101,32,34, +99,111,112,121,114,105,103,104,116,34,32,108,105,110,101,32, +97,110,100,32,97,32,112,111,105,110,116,101,114,32,116,111, +32,119,104,101,114,101,32,116,104,101,32,102,117,108,108,32, +110,111,116,105,99,101,32,105,115,32,102,111,117,110,100,46, +10,60,112,62,10,32,32,32,32,60,111,110,101,32,108,105, +110,101,32,116,111,32,103,105,118,101,32,116,104,101,32,112, +114,111,103,114,97,109,39,115,32,110,97,109,101,32,97,110, +100,32,97,32,98,114,105,101,102,32,105,100,101,97,32,111, +102,32,119,104,97,116,32,105,116,32,100,111,101,115,46,62, +10,32,32,32,32,67,111,112,121,114,105,103,104,116,32,40, +67,41,32,38,108,116,59,121,101,97,114,38,103,116,59,32, +32,38,108,116,59,110,97,109,101,32,111,102,32,97,117,116, +104,111,114,38,103,116,59,10,60,112,62,10,32,32,32,32, +84,104,105,115,32,112,114,111,103,114,97,109,32,105,115,32, +102,114,101,101,32,115,111,102,116,119,97,114,101,59,32,121, +111,117,32,99,97,110,32,114,101,100,105,115,116,114,105,98, +117,116,101,32,105,116,32,97,110,100,47,111,114,32,109,111, +100,105,102,121,10,32,32,32,32,105,116,32,117,110,100,101, +114,32,116,104,101,32,116,101,114,109,115,32,111,102,32,116, +104,101,32,71,78,85,32,71,101,110,101,114,97,108,32,80, +117,98,108,105,99,32,76,105,99,101,110,115,101,32,97,115, +32,112,117,98,108,105,115,104,101,100,32,98,121,10,32,32, +32,32,116,104,101,32,70,114,101,101,32,83,111,102,116,119, +97,114,101,32,70,111,117,110,100,97,116,105,111,110,59,32, +101,105,116,104,101,114,32,118,101,114,115,105,111,110,32,50, +32,111,102,32,116,104,101,32,76,105,99,101,110,115,101,44, +32,111,114,10,32,32,32,32,40,97,116,32,121,111,117,114, +32,111,112,116,105,111,110,41,32,97,110,121,32,108,97,116, +101,114,32,118,101,114,115,105,111,110,46,10,60,112,62,10, +32,32,32,32,84,104,105,115,32,112,114,111,103,114,97,109, +32,105,115,32,100,105,115,116,114,105,98,117,116,101,100,32, +105,110,32,116,104,101,32,104,111,112,101,32,116,104,97,116, +32,105,116,32,119,105,108,108,32,98,101,32,117,115,101,102, +117,108,44,10,32,32,32,32,98,117,116,32,87,73,84,72, +79,85,84,32,65,78,89,32,87,65,82,82,65,78,84,89, +59,32,119,105,116,104,111,117,116,32,101,118,101,110,32,116, +104,101,32,105,109,112,108,105,101,100,32,119,97,114,114,97, +110,116,121,32,111,102,10,32,32,32,32,77,69,82,67,72, +65,78,84,65,66,73,76,73,84,89,32,111,114,32,70,73, +84,78,69,83,83,32,70,79,82,32,65,32,80,65,82,84, +73,67,85,76,65,82,32,80,85,82,80,79,83,69,46,32, +32,83,101,101,32,116,104,101,10,32,32,32,32,71,78,85, +32,71,101,110,101,114,97,108,32,80,117,98,108,105,99,32, +76,105,99,101,110,115,101,32,102,111,114,32,109,111,114,101, +32,100,101,116,97,105,108,115,46,10,60,112,62,10,32,32, +32,32,89,111,117,32,115,104,111,117,108,100,32,104,97,118, +101,32,114,101,99,101,105,118,101,100,32,97,32,99,111,112, +121,32,111,102,32,116,104,101,32,71,78,85,32,71,101,110, +101,114,97,108,32,80,117,98,108,105,99,32,76,105,99,101, +110,115,101,10,32,32,32,32,97,108,111,110,103,32,119,105, +116,104,32,116,104,105,115,32,112,114,111,103,114,97,109,59, +32,105,102,32,110,111,116,44,32,119,114,105,116,101,32,116, +111,32,116,104,101,32,70,114,101,101,32,83,111,102,116,119, +97,114,101,10,32,32,32,32,70,111,117,110,100,97,116,105, +111,110,44,32,73,110,99,46,44,32,53,57,32,84,101,109, +112,108,101,32,80,108,97,99,101,44,32,83,117,105,116,101, +32,51,51,48,44,32,66,111,115,116,111,110,44,32,77,65, +32,32,48,50,49,49,49,45,49,51,48,55,32,32,85,83, +65,10,60,112,62,10,65,108,115,111,32,97,100,100,32,105, +110,102,111,114,109,97,116,105,111,110,32,111,110,32,104,111, +119,32,116,111,32,99,111,110,116,97,99,116,32,121,111,117, +32,98,121,32,101,108,101,99,116,114,111,110,105,99,32,97, +110,100,32,112,97,112,101,114,32,109,97,105,108,46,10,60, +112,62,10,73,102,32,116,104,101,32,112,114,111,103,114,97, +109,32,105,115,32,105,110,116,101,114,97,99,116,105,118,101, +44,32,109,97,107,101,32,105,116,32,111,117,116,112,117,116, +32,97,32,115,104,111,114,116,32,110,111,116,105,99,101,32, +108,105,107,101,32,116,104,105,115,10,119,104,101,110,32,105, +116,32,115,116,97,114,116,115,32,105,110,32,97,110,32,105, +110,116,101,114,97,99,116,105,118,101,32,109,111,100,101,58, +10,60,112,114,101,62,10,32,32,32,32,71,110,111,109,111, +118,105,115,105,111,110,32,118,101,114,115,105,111,110,32,54, +57,44,32,67,111,112,121,114,105,103,104,116,32,40,67,41, +32,121,101,97,114,32,32,110,97,109,101,32,111,102,32,97, +117,116,104,111,114,10,32,32,32,32,71,110,111,109,111,118, +105,115,105,111,110,32,99,111,109,101,115,32,119,105,116,104, +32,65,66,83,79,76,85,84,69,76,89,32,78,79,32,87, +65,82,82,65,78,84,89,59,32,102,111,114,32,100,101,116, +97,105,108,115,32,116,121,112,101,32,96,115,104,111,119,32, +119,39,46,10,32,32,32,32,84,104,105,115,32,105,115,32, +102,114,101,101,32,115,111,102,116,119,97,114,101,44,32,97, +110,100,32,121,111,117,32,97,114,101,32,119,101,108,99,111, +109,101,32,116,111,32,114,101,100,105,115,116,114,105,98,117, +116,101,32,105,116,10,32,32,32,32,117,110,100,101,114,32, +99,101,114,116,97,105,110,32,99,111,110,100,105,116,105,111, +110,115,59,32,116,121,112,101,32,96,115,104,111,119,32,99, +39,32,102,111,114,32,100,101,116,97,105,108,115,46,10,60, +47,112,114,101,62,10,60,112,62,10,84,104,101,32,104,121, +112,111,116,104,101,116,105,99,97,108,32,99,111,109,109,97, +110,100,115,32,96,115,104,111,119,32,119,39,32,97,110,100, +32,96,115,104,111,119,32,99,39,32,115,104,111,117,108,100, +32,115,104,111,119,32,116,104,101,10,97,112,112,114,111,112, +114,105,97,116,101,32,112,97,114,116,115,32,111,102,32,116, +104,101,32,71,101,110,101,114,97,108,32,80,117,98,108,105, +99,32,76,105,99,101,110,115,101,46,32,32,79,102,32,99, +111,117,114,115,101,44,32,116,104,101,10,99,111,109,109,97, +110,100,115,32,121,111,117,32,117,115,101,32,109,97,121,32, +98,101,32,99,97,108,108,101,100,32,115,111,109,101,116,104, +105,110,103,32,111,116,104,101,114,32,116,104,97,110,32,96, +115,104,111,119,32,119,39,32,97,110,100,32,96,115,104,111, +119,10,99,39,59,32,116,104,101,121,32,99,111,117,108,100, +32,101,118,101,110,32,98,101,32,109,111,117,115,101,45,99, +108,105,99,107,115,32,111,114,32,109,101,110,117,32,105,116, +101,109,115,45,45,119,104,97,116,101,118,101,114,32,115,117, +105,116,115,32,121,111,117,114,32,10,112,114,111,103,114,97, +109,46,10,60,112,62,10,89,111,117,32,115,104,111,117,108, +100,32,97,108,115,111,32,103,101,116,32,121,111,117,114,32, +101,109,112,108,111,121,101,114,32,40,105,102,32,121,111,117, +32,119,111,114,107,32,97,115,32,97,32,112,114,111,103,114, +97,109,109,101,114,41,32,111,114,10,121,111,117,114,32,115, +99,104,111,111,108,44,32,105,102,32,97,110,121,44,32,116, +111,32,115,105,103,110,32,97,32,34,99,111,112,121,114,105, +103,104,116,32,100,105,115,99,108,97,105,109,101,114,34,32, +102,111,114,32,116,104,101,32,112,114,111,103,114,97,109,44, +10,105,102,32,110,101,99,101,115,115,97,114,121,46,32,32, +72,101,114,101,32,105,115,32,97,32,115,97,109,112,108,101, +59,32,97,108,116,101,114,32,116,104,101,32,110,97,109,101, +115,58,10,60,112,62,10,60,112,114,101,62,10,32,32,89, +111,121,111,100,121,110,101,44,32,73,110,99,46,44,32,104, +101,114,101,98,121,32,100,105,115,99,108,97,105,109,115,32, +97,108,108,32,99,111,112,121,114,105,103,104,116,32,105,110, +116,101,114,101,115,116,32,105,110,32,116,104,101,32,112,114, +111,103,114,97,109,10,32,32,96,71,110,111,109,111,118,105, +115,105,111,110,39,32,40,119,104,105,99,104,32,109,97,107, +101,115,32,112,97,115,115,101,115,32,97,116,32,99,111,109, +112,105,108,101,114,115,41,32,119,114,105,116,116,101,110,32, +98,121,32,74,97,109,101,115,32,72,97,99,107,101,114,46, +10,10,32,32,38,108,116,59,115,105,103,110,97,116,117,114, +101,32,111,102,32,84,121,32,67,111,111,110,38,103,116,59, +44,32,49,32,65,112,114,105,108,32,49,57,56,57,10,32, +32,84,121,32,67,111,111,110,44,32,80,114,101,115,105,100, +101,110,116,32,111,102,32,86,105,99,101,10,60,47,112,114, +101,62,10,60,112,62,10,84,104,105,115,32,71,101,110,101, +114,97,108,32,80,117,98,108,105,99,32,76,105,99,101,110, +115,101,32,100,111,101,115,32,110,111,116,32,112,101,114,109, +105,116,32,105,110,99,111,114,112,111,114,97,116,105,110,103, +32,121,111,117,114,32,112,114,111,103,114,97,109,10,105,110, +116,111,32,112,114,111,112,114,105,101,116,97,114,121,32,112, +114,111,103,114,97,109,115,46,32,32,73,102,32,121,111,117, +114,32,112,114,111,103,114,97,109,32,105,115,32,97,32,115, +117,98,114,111,117,116,105,110,101,32,108,105,98,114,97,114, +121,44,10,121,111,117,32,109,97,121,32,99,111,110,115,105, +100,101,114,32,105,116,32,109,111,114,101,32,117,115,101,102, +117,108,32,116,111,32,112,101,114,109,105,116,32,108,105,110, +107,105,110,103,32,112,114,111,112,114,105,101,116,97,114,121, +10,97,112,112,108,105,99,97,116,105,111,110,115,32,119,105, +116,104,32,116,104,101,32,108,105,98,114,97,114,121,46,32, +32,73,102,32,116,104,105,115,32,105,115,32,119,104,97,116, +32,121,111,117,32,119,97,110,116,32,116,111,32,100,111,44, +32,117,115,101,10,116,104,101,32,71,78,85,32,76,105,98, +114,97,114,121,32,71,101,110,101,114,97,108,32,80,117,98, +108,105,99,32,76,105,99,101,110,115,101,32,105,110,115,116, +101,97,100,32,111,102,32,116,104,105,115,32,76,105,99,101, +110,115,101,46,10,10, +0}; diff --git a/lib/lib.pro b/lib/lib.pro new file mode 100644 index 00000000..42e6398d --- /dev/null +++ b/lib/lib.pro @@ -0,0 +1,312 @@ +# lib.pro +# +# The lib/ QMake project file for Rivendell. +# +# (C) Copyright 2003-2007 Fred Gleason <fredg@paravelsystems.com> +# +# $Id: lib.pro,v 1.36.8.13.2.1 2014/06/02 22:52:24 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = lib + +win32 { + DEFINES += WIN32 + DEFINES += VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE=\"rivendell\" + DEFINES += PACKAGE_VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE_NAME=\"rivendell\" + DEFINES += PACKAGE_BUGREPORT=\"fredg@paravelsystems.com\" +} + +SOURCES += export_bmiemr.cpp +SOURCES += export_deltaflex.cpp +SOURCES += export_musicclassical.cpp +SOURCES += export_musicplayout.cpp +SOURCES += export_musicsummary.cpp +SOURCES += export_nprsoundex.cpp +SOURCES += export_radiotraffic.cpp +SOURCES += export_soundex.cpp +SOURCES += export_technical.cpp +SOURCES += export_textlog.cpp +SOURCES += rdadd_log.cpp +SOURCES += rdaudiosettings.cpp +SOURCES += rdaudiosettings_dialog.cpp +SOURCES += rdbusybar.cpp +SOURCES += rdbusydialog.cpp +SOURCES += rdcart.cpp +SOURCES += rdcart_dialog.cpp +SOURCES += rdcart_search_text.cpp +SOURCES += rdcartdrag.cpp +SOURCES += rdclock.cpp +SOURCES += rdcmd_switch.cpp +SOURCES += rdcombobox.cpp +SOURCES += rdconf.cpp +SOURCES += rdconfig.cpp +SOURCES += rdcreate_log.cpp +SOURCES += rdcut.cpp +SOURCES += rddatedialog.cpp +SOURCES += rddatedecode.cpp +SOURCES += rddatepicker.cpp +SOURCES += rddb.cpp +SOURCES += rddbheartbeat.cpp +SOURCES += rddebug.cpp +SOURCES += rddropbox.cpp +SOURCES += rdemptycart.cpp +SOURCES += rdencoder.cpp +SOURCES += rdencoderlist.cpp +SOURCES += rdescape_string.cpp +SOURCES += rdevent.cpp +SOURCES += rdevent_line.cpp +SOURCES += rdexception_dialog.cpp +SOURCES += rdget_ath.cpp +SOURCES += rdgetpasswd.cpp +SOURCES += rdgroup_list.cpp +SOURCES += rdidvalidator.cpp +SOURCES += rdintegeredit.cpp +SOURCES += rdintegerdialog.cpp +SOURCES += rdlabel.cpp +SOURCES += rdlibrary_conf.cpp +SOURCES += rdlicense.cpp +SOURCES += rdlineedit.cpp +SOURCES += rdlistselector.cpp +SOURCES += rdlistview.cpp +SOURCES += rdlistviewitem.cpp +SOURCES += rdlog.cpp +SOURCES += rdlog_event.cpp +SOURCES += rdlog_line.cpp +SOURCES += rdlogedit_conf.cpp +SOURCES += rdmacro.cpp +SOURCES += rdmacro_event.cpp +SOURCES += rdoneshot.cpp +SOURCES += rdplaymeter.cpp +SOURCES += rdprofile.cpp +SOURCES += rdprofileline.cpp +SOURCES += rdprofilesection.cpp +SOURCES += rdpushbutton.cpp +SOURCES += rdreport.cpp +SOURCES += rdripc.cpp +SOURCES += rdsegmeter.cpp +SOURCES += rdslider.cpp +SOURCES += rdsocket.cpp +SOURCES += rdstation.cpp +SOURCES += rdstereometer.cpp +SOURCES += rdsvc.cpp +SOURCES += rdsystem.cpp +SOURCES += rdtextfile.cpp +SOURCES += rdtextvalidator.cpp +SOURCES += rdtimeedit.cpp +SOURCES += rdtimeengine.cpp +SOURCES += rdtransportbutton.cpp +SOURCES += rduser.cpp +SOURCES += rdwavedata.cpp +SOURCES += schedcartlist.cpp +SOURCES += schedruleslist.cpp +win32 { + SOURCES += html_gpl2_win32.cpp + SOURCES += rdttydevice_win32.cpp + SOURCES += rdwin32.cpp +} +x11 { + SOURCES += html_gpl2.cpp + SOURCES += rdadd_cart.cpp + SOURCES += rdairplay_conf.cpp + SOURCES += rdaudio_exists.cpp + SOURCES += rdaudio_port.cpp + SOURCES += rdbutton_dialog.cpp + SOURCES += rdbutton_panel.cpp + SOURCES += rdcae.cpp + SOURCES += rdcardselector.cpp + SOURCES += rdcatch_connect.cpp + SOURCES += rdcddblookup.cpp + SOURCES += rdcdplayer.cpp + SOURCES += rdcddbrecord.cpp + SOURCES += rdcheck_daemons.cpp + SOURCES += rdcheck_version.cpp + SOURCES += rdcmd_cache.cpp + SOURCES += rdcueedit.cpp + SOURCES += rdcueeditdialog.cpp + SOURCES += rdcut_dialog.cpp + SOURCES += rdcut_path.cpp + SOURCES += rddeck.cpp + SOURCES += rdedit_audio.cpp + SOURCES += rdedit_panel_name.cpp + SOURCES += rdexport_settings_dialog.cpp + SOURCES += rdgpioselector.cpp + SOURCES += rdgrid.cpp + SOURCES += rdgroup.cpp + SOURCES += rdimport_audio.cpp + SOURCES += rdlist_groups.cpp + SOURCES += rdlist_logs.cpp + SOURCES += rdmarker_button.cpp + SOURCES += rdmarker_edit.cpp + SOURCES += rdmatrix.cpp + SOURCES += rdmonitor_config.cpp + SOURCES += rdpanel_button.cpp + SOURCES += rdpasswd.cpp + SOURCES += rdplay_deck.cpp + SOURCES += rdrecording.cpp + SOURCES += rdsettings.cpp + SOURCES += rdsimpleplayer.cpp + SOURCES += rdsound_panel.cpp + SOURCES += rdstatus.cpp + SOURCES += rdtimeedit.cpp + SOURCES += rdtty.cpp + SOURCES += rdttydevice.cpp + SOURCES += rdttyout.cpp + SOURCES += rdversion.cpp + SOURCES += rdwavefile.cpp +} + +HEADERS += schedcartlist.h +HEADERS += schedruleslist.h +HEADERS += rdadd_log.h +HEADERS += rdaudiosettings.h +HEADERS += rdaudiosettings_dialog.h +HEADERS += rdbusybar.h +HEADERS += rdbusydialog.h +HEADERS += rdcae.h +HEADERS += rdcart.h +HEADERS += rdcart_dialog.h +HEADERS += rdcart_search_text.h +HEADERS += rdcartdrag.h +HEADERS += rdclock.h +HEADERS += rdcmd_switch.h +HEADERS += rdcombobox.h +HEADERS += rdconf.h +HEADERS += rdconfig.h +HEADERS += rdcreate_log.h +HEADERS += rdcut.h +HEADERS += rddatedecode.h +HEADERS += rddatedialog.h +HEADERS += rddatepicker.h +HEADERS += rddb.h +HEADERS += rddbheartbeat.h +HEADERS += rddebug.h +HEADERS += rddropbox.h +HEADERS += rdemptycart.h +HEADERS += rdencoder.h +HEADERS += rdencoderlist.h +HEADERS += rdescape_string.h +HEADERS += rdevent.h +HEADERS += rdevent_line.h +HEADERS += rdexception_dialog.h +HEADERS += rdget_ath.h +HEADERS += rdgetpasswd.h +HEADERS += rdgroup_list.h +HEADERS += rd.h +HEADERS += rdidvalidator.h +HEADERS += rdintegeredit.h +HEADERS += rdintegerdialog.h +HEADERS += rdlabel.h +HEADERS += rdlibrary_conf.h +HEADERS += rdlicense.h +HEADERS += rdlineedit.h +HEADERS += rdlistselector.h +HEADERS += rdlistview.h +HEADERS += rdlistviewitem.h +HEADERS += rdlog.h +HEADERS += rdlog_event.h +HEADERS += rdlog_line.h +HEADERS += rdlogedit_conf.h +HEADERS += rdmacro.h +HEADERS += rdmacro_event.h +HEADERS += rdoneshot.h +HEADERS += rdplaymeter.h +HEADERS += rdprofile.h +HEADERS += rdprofileline.h +HEADERS += rdprofilesection.h +HEADERS += rdpushbutton.h +HEADERS += rdreport.h +HEADERS += rdripc.h +HEADERS += rdsegmeter.h +HEADERS += rdslider.h +HEADERS += rdsocket.h +HEADERS += rdstation.h +HEADERS += rdstereometer.h +HEADERS += rdsvc.h +HEADERS += rdsystem.h +HEADERS += rdtextfile.h +HEADERS += rdtextvalidator.h +HEADERS += rdtimeedit.h +HEADERS += rdtimeengine.h +HEADERS += rdtransportbutton.h +HEADERS += rdttydevice.h +HEADERS += rduser.h +HEADERS += rdwavedata.h + +win32 { + HEADERS += rdwin32.h +} +x11 { + HEADERS += rdadd_cart.h + HEADERS += rdairplay_conf.h + HEADERS += rdaudio_exists.h + HEADERS += rdaudio_port.h + HEADERS += rdbutton_dialog.h + HEADERS += rdbutton_panel.h + HEADERS += rdcae.h + HEADERS += rdcardselector.h + HEADERS += rdcatch_connect.h + HEADERS += rdcddblookup.h + HEADERS += rdcdplayer.h + HEADERS += rdcddbrecord.h + HEADERS += rdcheck_daemons.h + HEADERS += rdcheck_version.h + HEADERS += rdcmd_cache.h + HEADERS += rdcueedit.h + HEADERS += rdcueeditdialog.h + HEADERS += rdcut_dialog.h + HEADERS += rdcut_path.h + HEADERS += rddeck.h + HEADERS += rdedit_audio.h + HEADERS += rdedit_panel_name.h + HEADERS += rdexport_settings_dialog.h + HEADERS += rdgpioselector.h + HEADERS += rdgrid.h + HEADERS += rdgpio.h + HEADERS += rdgroup.h + HEADERS += rdimport_audio.h + HEADERS += rdlist_groups.h + HEADERS += rdlist_logs.h + HEADERS += rdmarker_button.h + HEADERS += rdmarker_edit.h + HEADERS += rdmatrix.h + HEADERS += rdmonitor_config.h + HEADERS += rdpanel_button.h + HEADERS += rdpaths.h + HEADERS += rdpasswd.h + HEADERS += rdplay_deck.h + HEADERS += rdrecording.h + HEADERS += rdsettings.h + HEADERS += rdsimpleplayer.h + HEADERS += rdsound_panel.h + HEADERS += rdstatus.h + HEADERS += rdtimeedit.h + HEADERS += rdtty.h + HEADERS += rdttyout.h + HEADERS += rdversion.h +} + +INCLUDEPATH += ..\..\libradio\radio + +CONFIG += qt staticlib + +TRANSLATIONS += librd_cs.ts +TRANSLATIONS += librd_de.ts +TRANSLATIONS += librd_es.ts +TRANSLATIONS += librd_fr.ts +TRANSLATIONS += librd_nb.ts +TRANSLATIONS += librd_nn.ts +TRANSLATIONS += librd_pt_BR.ts diff --git a/lib/librd_cs.ts b/lib/librd_cs.ts new file mode 100644 index 00000000..ac799201 --- /dev/null +++ b/lib/librd_cs.ts @@ -0,0 +1,2189 @@ +<!DOCTYPE TS><TS> +<context> + <name></name> + <message> + <source>UNKNOWN CUT</source> + <translation type="obsolete">Unbekannter Cut</translation> + </message> +</context> +<context> + <name>@default</name> + <message> + <source>ALL</source> + <translation type="obsolete">ALLE</translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <source>Couldn't initialize QSql driver!</source> + <translation>Nepodařilo se inicializovat ovladač QSql!</translation> + </message> + <message> + <source>Couldn't open mySQL connection!</source> + <translation>Nepodařilo se vytvořit žádné spojení se serverem mySQL-Server!</translation> + </message> + <message> + <source>Sequentially</source> + <translation>Postupně</translation> + </message> + <message> + <source>Randomly</source> + <translation>Náhodně</translation> + </message> + <message> + <source>Unknown</source> + <translation>Neznámý</translation> + </message> + <message> + <source>Feature</source> + <translation>Vlastnost</translation> + </message> + <message> + <source>Theme Open</source> + <translation>Začátek tématu</translation> + </message> + <message> + <source>Theme Close</source> + <translation>Konec tématu</translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation>Začátek/Konec tématu</translation> + </message> + <message> + <source>Background</source> + <translation>Pozadí</translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation>Komerční/Znělka/Reklama</translation> + </message> + <message> + <source>UNKNOWN CUT</source> + <translation>Neznámý záběr</translation> + </message> + <message> + <source>Manual</source> + <translation>Ruční</translation> + </message> + <message> + <source>Play</source> + <translation>Přehrát</translation> + </message> + <message> + <source>Segue</source> + <translation>Přechod</translation> + </message> + <message> + <source>Time</source> + <translation>Čas</translation> + </message> + <message> + <source>Panel</source> + <translation>Panel</translation> + </message> + <message> + <source>Macro</source> + <translation>Makro</translation> + </message> + <message> + <source>PLAY</source> + <translation>PŘEHRÁT</translation> + </message> + <message> + <source>SEGUE</source> + <translation>PŘECHOD</translation> + </message> + <message> + <source>STOP</source> + <translation>ZASTAVIT</translation> + </message> + <message> + <source>UNKNOWN</source> + <translation>NEZNÁMÝ</translation> + </message> + <message> + <source>Audio</source> + <translation>Poslech</translation> + </message> + <message> + <source>Marker</source> + <translation>Značka</translation> + </message> + <message> + <source>Open Bracket</source> + <translation>Otevřít závorku</translation> + </message> + <message> + <source>Close Bracket</source> + <translation>Zavřít závorku</translation> + </message> + <message> + <source>ChainTo</source> + <translation>ŘetězDo</translation> + </message> + <message> + <source>Track</source> + <translation>Stopa</translation> + </message> + <message> + <source>Link</source> + <translation>Propojení</translation> + </message> + <message> + <source>Traffic</source> + <translation>Přenos</translation> + </message> + <message> + <source>Music</source> + <translation>Hudba</translation> + </message> + <message> + <source>RDLogManager</source> + <translation>RDLogManager</translation> + </message> + <message> + <source>Tracker</source> + <translation>Tracker</translation> + </message> + <message> + <source>Recording</source> + <translation>Nahrávání</translation> + </message> + <message> + <source>Macro Event</source> + <translation>Událost Makro</translation> + </message> + <message> + <source>Switch Event</source> + <translation>Událost přepnutí</translation> + </message> + <message> + <source>Playout</source> + <translation>Přehrávat</translation> + </message> + <message> + <source>Download</source> + <translation>Stáhnout</translation> + </message> + <message> + <source>Upload</source> + <translation>Nahrát</translation> + </message> + <message> + <source>Ok</source> + <translation>OK</translation> + </message> + <message> + <source>Short Length</source> + <translation>Krátká délka</translation> + </message> + <message> + <source>Low Level</source> + <translation>Nízká úroveň</translation> + </message> + <message> + <source>High Level</source> + <translation>Vysoká úroveň</translation> + </message> + <message> + <source>Downloading</source> + <translation>Stahování</translation> + </message> + <message> + <source>Uploading</source> + <translation>Nahrávání</translation> + </message> + <message> + <source>Server Error</source> + <translation>Chyba serveru</translation> + </message> + <message> + <source>Internal Error</source> + <translation>Vnitřní chyba</translation> + </message> + <message> + <source>Interrupted</source> + <translation>Přerušeno</translation> + </message> + <message> + <source>Playing</source> + <translation>Přehrává se</translation> + </message> + <message> + <source>Waiting</source> + <translation>Čeká se</translation> + </message> + <message> + <source>Device Busy</source> + <translation>Zařízení zaneprázdněno</translation> + </message> + <message> + <source>No Such Cart/Cut</source> + <translation>Žádný takový vozík/záběr</translation> + </message> + <message> + <source>Unknown Audio Format</source> + <translation>Neznámý formát zvuku</translation> + </message> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation>CBSI DeltaFlex sladění přenosu v2.01</translation> + </message> + <message> + <source>Text Log</source> + <translation>Textový zápis</translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation>ASCAP/BMI elektronická zpráva o hudbě</translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation>Technická zpráva o přehrávání</translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation>SoundExchange Statutory License Report</translation> + </message> + <message> + <source>RadioTraffic.com Traffic Reconciliation</source> + <translation>RadioTraffic.com sladění přenosu</translation> + </message> + <message> + <source>VisualTraffic Reconciliation</source> + <translation>VisualTraffic sladění</translation> + </message> + <message> + <source>CounterPoint Traffic Reconciliation</source> + <translation>CounterPoint sladění přenosu</translation> + </message> + <message> + <source>Music1 Reconciliation</source> + <translation>Music1 sladění</translation> + </message> + <message> + <source>Other</source> + <translation>Jiné</translation> + </message> + <message> + <source>AM</source> + <translation>AM</translation> + </message> + <message> + <source>FM</source> + <translation>FM</translation> + </message> + <message> + <source>Report complete!</source> + <translation>Zpráva úplná!</translation> + </message> + <message> + <source>Report canceled!</source> + <translation>Zpráva zrušena!</translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation>Nelze otevřít soubor se zprávou!</translation> + </message> + <message> + <source>invalid SQL or failed DB connection:</source> + <translation type="obsolete">Neplatné SQL nebo nepodařilo připojit k DB:</translation> + </message> + <message> + <source>Music Summary</source> + <translation>Hudební shrnutí</translation> + </message> + <message> + <source>WideOrbit Traffic Reconciliation</source> + <translation>WideOrbit sladění přenosu</translation> + </message> + <message> + <source>Unknown Position</source> + <translation>Neznámá poloha</translation> + </message> + <message> + <source>Top Left</source> + <translation>Nahoře vlevo</translation> + </message> + <message> + <source>Top Center</source> + <translation>Nahoře ve středu</translation> + </message> + <message> + <source>Top Right</source> + <translation>Nahoře vpravo</translation> + </message> + <message> + <source>Bottom Left</source> + <translation>Dole vlevo</translation> + </message> + <message> + <source>Bottom Center</source> + <translation>Dole ve středu</translation> + </message> + <message> + <source>Bottom Right</source> + <translation>Dole vpravo</translation> + </message> + <message> + <source>NPR/DS SoundExchange Report</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 1</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel First Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 1 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 2 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Second Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Third Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fourth Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audition/Cue Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Channel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fifth and Later Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>invalid SQL or failed DB connection</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>All</source> + <translation type="unfinished">Vše</translation> + </message> + <message> + <source>Relative</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hard</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NaturalLog Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>LiveAssist</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Automatic</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Previous</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Classical Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>reserved</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAddCart</name> + <message> + <source>&Group:</source> + <translation>&Skupina:</translation> + </message> + <message> + <source>&New Cart Number:</source> + <translation>&Nové číslo vozíku:</translation> + </message> + <message> + <source>&New Cart Type:</source> + <translation>&Nový typ vozíku:</translation> + </message> + <message> + <source>Audio</source> + <translation>Poslech</translation> + </message> + <message> + <source>Macro</source> + <translation>Makro</translation> + </message> + <message> + <source>[new cart]</source> + <translation>[nový vozík]</translation> + </message> + <message> + <source>&New Cart Title:</source> + <translation>&Nový název vozíku:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> + <message> + <source>No Available Cart Numbers</source> + <translation>Není dostupné žádné číslo vozíku</translation> + </message> + <message> + <source>There are no more available cart numbers for the group!</source> + <translation>Ve skupině nejsou dostupná žádná další čísla vozíků!</translation> + </message> + <message> + <source>Invalid Number</source> + <translation>Neplatné číslo</translation> + </message> + <message> + <source>Invalid Cart Number!</source> + <translation>Neplatné číslo vozíku!</translation> + </message> + <message> + <source>Title Required</source> + <translation>Název vyžadován</translation> + </message> + <message> + <source>You must enter a cart title!</source> + <translation>Musíte zadat název vozíku!</translation> + </message> + <message> + <source>The cart number is outside of the permitted range for this group!</source> + <translation>Číslo vozíku se nachází mimo pro tuto skupinu povolený rozsah!</translation> + </message> + <message> + <source>Cart Exists</source> + <translation>Vozík existuje</translation> + </message> + <message> + <source>This cart already exists.</source> + <translation>Tento vozík již existuje.</translation> + </message> + <message> + <source>Duplicate Title</source> + <translation>Zdvojený název</translation> + </message> + <message> + <source>The cart title must be unique!</source> + <translation>Název vozíku musí být jedinečný!</translation> + </message> +</context> +<context> + <name>RDAddLog</name> + <message> + <source>Create Log</source> + <translation>Vytvořit zápis</translation> + </message> + <message> + <source>&New Log Name:</source> + <translation>&Název nového zápisu:</translation> + </message> + <message> + <source>&Service:</source> + <translation>&Služba: </translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> + <message> + <source>RDLogEdit</source> + <translation>RDLogedit</translation> + </message> + <message> + <source>The name is invalid!</source> + <translation type="obsolete">Název je neplatný!</translation> + </message> + <message> + <source>The service is invalid!</source> + <translation>Služba je neplatná!</translation> + </message> +</context> +<context> + <name>RDAudioSettingsDialog</name> + <message> + <source>Edit Settings</source> + <translation>Upravit nastavení</translation> + </message> + <message> + <source>Default &Format:</source> + <translation>Výchozí &formát:</translation> + </message> + <message> + <source>Default &Channels:</source> + <translation>Výchozí &kanály:</translation> + </message> + <message> + <source>Default &Sample Rate:</source> + <translation>Výchozí &vzorkovací kmitočet:</translation> + </message> + <message> + <source>Default &Bitrate:</source> + <translation>Výchozí &datový tok:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> + <message> + <source>PCM16</source> + <translation>PCM16</translation> + </message> + <message> + <source>OggVorbis</source> + <translation>OggVorbis</translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation>MPEG Layer 2</translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation>MPEG Layer 3</translation> + </message> +</context> +<context> + <name>RDButtonDialog</name> + <message> + <source>Edit Button</source> + <translation>Upravit tlačítko</translation> + </message> + <message> + <source>Label:</source> + <translation>Štítek:</translation> + </message> + <message> + <source>Cart:</source> + <translation>Vozík:</translation> + </message> + <message> + <source>Set +Cart</source> + <translation>Nastavit +vozík</translation> + </message> + <message> + <source>Clear</source> + <translation>Smazat</translation> + </message> + <message> + <source>Set +Color</source> + <translation>Nastavit +barvu</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> + <message> + <source>NOT FOUND</source> + <translation>NENALEZENO</translation> + </message> +</context> +<context> + <name>RDCardSelector</name> + <message> + <source>Card:</source> + <translation>Karta:</translation> + </message> + <message> + <source>Port:</source> + <translation>Přípojka:</translation> + </message> +</context> +<context> + <name>RDCart</name> + <message> + <source>Sequentially</source> + <translation type="obsolete">Sequentiell</translation> + </message> + <message> + <source>Randomly</source> + <translation type="obsolete">Zufällig</translation> + </message> + <message> + <source>Unknown</source> + <translation type="obsolete">Unbekannt</translation> + </message> + <message> + <source>Feature</source> + <translation type="obsolete">Feature</translation> + </message> + <message> + <source>Theme Open</source> + <translation type="obsolete">Thema Anfang</translation> + </message> + <message> + <source>Theme Close</source> + <translation type="obsolete">Thema Ende</translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation type="obsolete">Thema Anfang/Ende</translation> + </message> + <message> + <source>Background</source> + <translation type="obsolete">Hintergrund</translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation type="obsolete">Commercial/Jingle/Promo</translation> + </message> +</context> +<context> + <name>RDCartDialog</name> + <message> + <source>Select Cart</source> + <translation>Vybrat vozík</translation> + </message> + <message> + <source>Please Wait...</source> + <translation>Počkejte, prosím...</translation> + </message> + <message> + <source>Cart Filter:</source> + <translation>Filtr vozíku:</translation> + </message> + <message> + <source>&Search</source> + <translation>&Hledat</translation> + </message> + <message> + <source>C&lear</source> + <translation>S&mazat</translation> + </message> + <message> + <source>Group:</source> + <translation>Skupina:</translation> + </message> + <message> + <source>NUMBER</source> + <translation>ČÍSLO</translation> + </message> + <message> + <source>LENGTH</source> + <translation>DÉLKA</translation> + </message> + <message> + <source>TITLE</source> + <translation>NÁZEV</translation> + </message> + <message> + <source>ARTIST</source> + <translation>UMĚLEC</translation> + </message> + <message> + <source>GROUP</source> + <translation>SKUPINA</translation> + </message> + <message> + <source>CLIENT</source> + <translation>ZÁKAZNÍK</translation> + </message> + <message> + <source>AGENCY</source> + <translation>AGENTURA</translation> + </message> + <message> + <source>USER DEF</source> + <translation>DEF UŽIVATELE</translation> + </message> + <message> + <source>START</source> + <translation>ZAČÁTEK</translation> + </message> + <message> + <source>END</source> + <translation>KONEC</translation> + </message> + <message> + <source>Send to +&Editor</source> + <translation>Poslat do +&editoru</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> + <message> + <source>ALL</source> + <translation>VŠE</translation> + </message> + <message> + <source>Show Only First</source> + <translation>Ukázat pouze první </translation> + </message> + <message> + <source>Matches</source> + <translation>Shody</translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation>Kódy rozvrhovače:</translation> + </message> + <message> + <source>Load From +&File</source> + <translation>Nahrát +ze &souboru</translation> + </message> + <message> + <source>Cart Error</source> + <translation>Chyba vozíku</translation> + </message> + <message> + <source>Unable to create temporary cart for import!</source> + <translation>Nelze vytvořit dočasný vozík pro zavedení!</translation> + </message> + <message> + <source>Unable to get temporary cart number for import!</source> + <translation>Nelze získat číslo dočasného vozík pro zavedení!</translation> + </message> + <message> + <source>Import Error</source> + <translation>Chyba při zavedení</translation> + </message> + <message> + <source>Imported from</source> + <translation>Zavedeno z</translation> + </message> + <message> + <source>Importing...</source> + <translation>Zavádí se...</translation> + </message> + <message> + <source>Importing</source> + <translation>Zavádí se</translation> + </message> + <message> + <source>COMPOSER</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CONDUCTOR</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEdit</name> + <message> + <source>&Audition</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Stop</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>End</source> + <translation type="unfinished">Konec</translation> + </message> + <message> + <source>&Recue</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEditDialog</name> + <message> + <source>Set Cue Point</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished">&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished">&Zrušit</translation> + </message> +</context> +<context> + <name>RDCutDialog</name> + <message> + <source>Select Cut</source> + <translation>Vybrat záběr</translation> + </message> + <message> + <source>Please Wait...</source> + <translation>Počkejte, prosím...</translation> + </message> + <message> + <source>Cart Filter:</source> + <translation>Filtr vozíku:</translation> + </message> + <message> + <source>&Search</source> + <translation>&Hledat</translation> + </message> + <message> + <source>C&lear</source> + <translation>S&mazat</translation> + </message> + <message> + <source>Group:</source> + <translation>Skupina:</translation> + </message> + <message> + <source>Carts</source> + <translation>Vozíky</translation> + </message> + <message> + <source>NUMBER</source> + <translation>ČÍSLO</translation> + </message> + <message> + <source>TITLE</source> + <translation>NÁZEV</translation> + </message> + <message> + <source>GROUP</source> + <translation>SKUPINA</translation> + </message> + <message> + <source>Cuts</source> + <translation>Záběry</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>POPIS</translation> + </message> + <message> + <source>&Add New +Cart</source> + <translation>&Přidat nový +vozík</translation> + </message> + <message> + <source>&Clear</source> + <translation>&Smazat</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> + <message> + <source>ALL</source> + <translation>VŠE</translation> + </message> + <message> + <source>Show Only First</source> + <translation>Ukázat pouze první </translation> + </message> + <message> + <source>Matches</source> + <translation>Shody</translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation>Kódy rozvrhovače:</translation> + </message> +</context> +<context> + <name>RDDateDialog</name> + <message> + <source>Select Date</source> + <translation>Vybrat datum</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> +</context> +<context> + <name>RDDatePicker</name> + <message> + <source>Mo</source> + <translation>Po</translation> + </message> + <message> + <source>Tu</source> + <translation>Út</translation> + </message> + <message> + <source>We</source> + <translation>St</translation> + </message> + <message> + <source>Th</source> + <translation>Čt</translation> + </message> + <message> + <source>Fr</source> + <translation>Pá</translation> + </message> + <message> + <source>Sa</source> + <translation>So</translation> + </message> + <message> + <source>Su</source> + <translation>Ne</translation> + </message> +</context> +<context> + <name>RDEditAudio</name> + <message> + <source>&Save</source> + <translation>&Uložit</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> + <message> + <source>Amplitude</source> + <translation>Rozkmit</translation> + </message> + <message> + <source>Zoom +In</source> + <translation>Přiblížit</translation> + </message> + <message> + <source>Zoom +Out</source> + <translation>Oddálit</translation> + </message> + <message> + <source>Time</source> + <translation>Čas</translation> + </message> + <message> + <source>Full +In</source> + <translation>Plný +In</translation> + </message> + <message> + <source>Full +Out</source> + <translation>Plný +Out</translation> + </message> + <message> + <source>Goto</source> + <translation>Přejít na</translation> + </message> + <message> + <source>Cursor</source> + <translation>Ukazovátko</translation> + </message> + <message> + <source>Home</source> + <translation>Domov</translation> + </message> + <message> + <source>End</source> + <translation>Konec</translation> + </message> + <message> + <source>Cut +Start</source> + <translation>Začátek +záběru</translation> + </message> + <message> + <source>Cut +End</source> + <translation>Konec +záběru</translation> + </message> + <message> + <source>Talk +Start</source> + <translation>Začátek +hovoru</translation> + </message> + <message> + <source>Segue +Start</source> + <translation>Začátek +přechodu</translation> + </message> + <message> + <source>Segue +End</source> + <translation>Konec +přechodu</translation> + </message> + <message> + <source>Fade +Up</source> + <translation>Utichat</translation> + </message> + <message> + <source>Hook +Start</source> + <translation>Začátek +chytlavé melodie</translation> + </message> + <message> + <source>Hook +End</source> + <translation>Konec +chytlavé melodie</translation> + </message> + <message> + <source> dB</source> + <translation> dB</translation> + </message> + <message> + <source>Threshold</source> + <translation>Prahová hodnota</translation> + </message> + <message> + <source>Trim +Start</source> + <translation>Začátek +ustřižení</translation> + </message> + <message> + <source>Trim +End</source> + <translation>Konec +ustřižení</translation> + </message> + <message> + <source>Cut Gain</source> + <translation>Zesílení záběru</translation> + </message> + <message> + <source>Remove +Marker</source> + <translation>Odstranit +značku</translation> + </message> + <message> + <source>No Fade on Segue Out</source> + <translation>Žádné prolínání při přechodu ven</translation> + </message> + <message> + <source>Position</source> + <translation>Poloha</translation> + </message> + <message> + <source>Length</source> + <translation>Délka</translation> + </message> + <message> + <source>Delete Talk Markers</source> + <translation>Smazat značky hovoru</translation> + </message> + <message> + <source>Delete Segue Markers</source> + <translation>Smazat značky přechodu</translation> + </message> + <message> + <source>Delete Hook Markers</source> + <translation>Smazat značky háčku (hook)</translation> + </message> + <message> + <source>Delete Fade Up Marker</source> + <translation>Smazat značku zesílení</translation> + </message> + <message> + <source>Delete Fade Down Marker</source> + <translation>Smazat značku zeslabení</translation> + </message> + <message> + <source>dB</source> + <translation>dB</translation> + </message> + <message> + <source><none></source> + <translation><none></translation> + </message> + <message> + <source>Cut</source> + <translation>Záběr</translation> + </message> + <message> + <source>Talk</source> + <translation>Hovor</translation> + </message> + <message> + <source>Segue</source> + <translation>Přechod</translation> + </message> + <message> + <source>Hook</source> + <translation>Chytlavá melodie</translation> + </message> + <message> + <source>Fade Up</source> + <translation>Zesílit</translation> + </message> + <message> + <source>Fade Down</source> + <translation>Zeslabit</translation> + </message> + <message> + <source>L</source> + <translation>L</translation> + </message> + <message> + <source>R</source> + <translation>P</translation> + </message> + <message> + <source>Rivendell Web Service</source> + <translation>Internetová služba Rivendellu</translation> + </message> + <message> + <source>Unable to download peak data, error was: +"</source> + <translation>Nepodařilo se stáhnout data vrcholu. Chyba byla: +"</translation> + </message> + <message> + <source>Edit Audio</source> + <translation>Upravit zvuk</translation> + </message> + <message> + <source>Marker Warning</source> + <translation>Varování týkající se značek</translation> + </message> + <message> + <source>Less than half of the audio is playable with these marker settings. +Are you sure you want to save?</source> + <translation>Méně než polovina zvukového záznamu je přehratelná s těmito nastaveními pro značky. +Opravdu chcete uložit?</translation> + </message> + <message> + <source>More than half of the audio will be faded with these marker settings. +Are you sure you want to save?</source> + <translation>Více než polovina zvukového záznamu bude s těmito nastaveními pro značky vystřižena. +Opravdu chcete uložit?</translation> + </message> +</context> +<context> + <name>RDEditPanelName</name> + <message> + <source>Edit Panel Name</source> + <translation>Upravit název panelu</translation> + </message> + <message> + <source>Panel &Name:</source> + <translation>&Název panelu:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> +</context> +<context> + <name>RDExceptionDialog</name> + <message> + <source>Rivendell Exception Report</source> + <translation>Zpráva o chybě Rivendellu</translation> + </message> + <message> + <source>&Save</source> + <translation>&Uložit</translation> + </message> + <message> + <source>&Close</source> + <translation>&Zavřít</translation> + </message> + <message> + <source>Text (*.txt *.TXT) +All Files (*.*)</source> + <translation>Text (*.txt *.TXT) +Všechny soubory (*.*)</translation> + </message> + <message> + <source>Export File</source> + <translation>Vyvést soubor</translation> + </message> + <message> + <source>The file</source> + <translation>Soubor</translation> + </message> + <message> + <source>already exists! +Overwrite?</source> + <translation>Již existuje! +Přepsat?</translation> + </message> + <message> + <source>File Exists</source> + <translation>Soubor již existuje</translation> + </message> + <message> + <source>Unable to open file</source> + <translation>Nelze otevřít soubor</translation> + </message> + <message> + <source>for writing!</source> + <translation>pro zápis!</translation> + </message> + <message> + <source>File Error</source> + <translation>Chyba souboru</translation> + </message> +</context> +<context> + <name>RDExportSettingsDialog</name> + <message> + <source>Edit Export Settings</source> + <translation>Upravit nastavení uložení v jiném formátu</translation> + </message> + <message> + <source>&Channels:</source> + <translation>&Kanály:</translation> + </message> + <message> + <source>&Sample Rate:</source> + <translation>&Vzorkovací kmitočet:</translation> + </message> + <message> + <source>&Bitrate:</source> + <translation>&Datový tok:</translation> + </message> + <message> + <source>&Quality:</source> + <translation>&Kvalita:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> + <message> + <source>PCM16</source> + <translation>PCM16</translation> + </message> + <message> + <source>FLAC</source> + <translation>FLAC</translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation>MPEG Layer 2</translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation>MPEG Layer 3</translation> + </message> + <message> + <source>OggVorbis</source> + <translation>OggVorbis</translation> + </message> + <message> + <source>VBR</source> + <translation>VBR</translation> + </message> + <message> + <source>32 kbps</source> + <translation>32 kb/s</translation> + </message> + <message> + <source>64 kbps</source> + <translation>64 kb/s</translation> + </message> + <message> + <source>96 kbps</source> + <translation>96 kb/s</translation> + </message> + <message> + <source>128 kbps</source> + <translation>128 kb/s</translation> + </message> + <message> + <source>160 kbps</source> + <translation>160 kb/s</translation> + </message> + <message> + <source>192 kbps</source> + <translation>192 kb/s</translation> + </message> + <message> + <source>224 kbps</source> + <translation>224 kb/s</translation> + </message> + <message> + <source>256 kbps</source> + <translation>256 kb/s</translation> + </message> + <message> + <source>288 kbps</source> + <translation>288 kb/s</translation> + </message> + <message> + <source>320 kbps</source> + <translation>320 kb/s</translation> + </message> + <message> + <source>352 kbps</source> + <translation>352 kb/s</translation> + </message> + <message> + <source>384 kbps</source> + <translation>384 kb/s</translation> + </message> + <message> + <source>416 kbps</source> + <translation>416 kb/s</translation> + </message> + <message> + <source>448 kbps</source> + <translation>448 kb/s</translation> + </message> + <message> + <source>48 kbps</source> + <translation>48 kb/s</translation> + </message> + <message> + <source>56 kbps</source> + <translation>56 kb/s</translation> + </message> + <message> + <source>80 kbps</source> + <translation>80 kb/s</translation> + </message> + <message> + <source>112 kbps</source> + <translation>112 kb/s</translation> + </message> + <message> + <source>40 kbps</source> + <translation>40 kb/s</translation> + </message> + <message> + <source>8 kbps</source> + <translation>8 kb/s</translation> + </message> + <message> + <source>16 kbps</source> + <translation>16 kb/s</translation> + </message> + <message> + <source>24 kbps</source> + <translation>24 kb/s</translation> + </message> + <message> + <source>144 kbps</source> + <translation>144 kb/s</translation> + </message> +</context> +<context> + <name>RDGetAth</name> + <message> + <source>Enter ATH</source> + <translation>Zadat ATH</translation> + </message> + <message> + <source>Enter the agreggate tuning hours (ATH) +figure for the report period. +(Supplied by your streaming provider).</source> + <translation>Zadejte údaj agreggate tuning hours (ATH) +pro dobu zprávy. +(Zeptejte se na to svého poskytovatele proudu - stream).</translation> + </message> + <message> + <source>ATH:</source> + <translation>ATH:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> + <message> + <source>Invalid ATH</source> + <translation>Neplatný údaj ATH</translation> + </message> + <message> + <source>You must provide a valid ATH figure!</source> + <translation>Musíte zadat platný údaj ATH!</translation> + </message> +</context> +<context> + <name>RDGetPasswd</name> + <message> + <source>Enter Password</source> + <translation>Zadat heslo</translation> + </message> + <message> + <source>Enter password</source> + <translation>Zadat heslo</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> +</context> +<context> + <name>RDGpioSelector</name> + <message> + <source>Pin:</source> + <translation>PIN:</translation> + </message> +</context> +<context> + <name>RDImportAudio</name> + <message> + <source>Import/Export Audio File</source> + <translation>Zavést/Vyvést soubor se zvukem</translation> + </message> + <message> + <source>Import File</source> + <translation>Zavést soubor</translation> + </message> + <message> + <source>Filename:</source> + <translation>Název souboru:</translation> + </message> + <message> + <source>&Select</source> + <translation>&Vybrat</translation> + </message> + <message> + <source>Import file metadata</source> + <translation>Zavést popisná data souboru</translation> + </message> + <message> + <source>Channels:</source> + <translation>Kanály:</translation> + </message> + <message> + <source>Autotrim</source> + <translation>Automatické zastřižení</translation> + </message> + <message> + <source>Level:</source> + <translation>Úroveň:</translation> + </message> + <message> + <source>dBFS</source> + <translation>dbFS</translation> + </message> + <message> + <source>Export File</source> + <translation>Vyvést soubor</translation> + </message> + <message> + <source>Export file metadata</source> + <translation>Vyvést popisná data souboru</translation> + </message> + <message> + <source>Format:</source> + <translation>Formát:</translation> + </message> + <message> + <source>S&et</source> + <translation>&Nastavit</translation> + </message> + <message> + <source>Normalize</source> + <translation>Normalizovat</translation> + </message> + <message> + <source>&Import</source> + <translation>&Zavést</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> + <message> + <source>Export</source> + <translation>Vyvést</translation> + </message> + <message> + <source>Import</source> + <translation>Zavést</translation> + </message> + <message> + <source>Import Audio File</source> + <translation>Zavést zvukový soubor</translation> + </message> + <message> + <source>File does not exist!</source> + <translation>Soubor neexistuje!</translation> + </message> + <message> + <source>Cannot open file!</source> + <translation type="obsolete">Kann die Datei nicht öffnen!</translation> + </message> + <message> + <source>Unsupported file type!</source> + <translation type="obsolete">Dateityp nicht unterstützt!</translation> + </message> + <message> + <source>Audio Exists</source> + <translation type="obsolete">Audiomaterial existiert</translation> + </message> + <message> + <source>This will overwrite the existing recording. +Do you want to proceed?</source> + <translation type="obsolete">Das wird die existierende Aufnahme löschen. +Wollen sie fortfahren?</translation> + </message> + <message> + <source>Empty Clipboard</source> + <translation type="obsolete">Zwischenablage leeren</translation> + </message> + <message> + <source>Importing this cut will also empty the clipboard. +Do you still want to proceed?</source> + <translation type="obsolete">Diesen Cut zu importieren wird die Zwischen- +ablage löschen! Fortfahren?</translation> + </message> + <message> + <source>Import Complete</source> + <translation>Zavedení dokončeno</translation> + </message> + <message> + <source>Import complete!</source> + <translation>Zavedení dokončeno!</translation> + </message> + <message> + <source>Import Aborted</source> + <translation type="obsolete">Import abgebrochen</translation> + </message> + <message> + <source>The import has been aborted.</source> + <translation type="obsolete">Der Import wurde abgebrochen.</translation> + </message> + <message> + <source>Import Failed</source> + <translation type="obsolete">Import fehlgeschlagen</translation> + </message> + <message> + <source>The importer encountered an error. +Please check your importer configuration and try again.</source> + <translation type="obsolete">Der Importer ist auf einen Fehler gestoßen. +Bitte überprüfen sie die Importer-Einstellungen und versuchen sie es erneut.</translation> + </message> + <message> + <source>File Exists</source> + <translation>Soubor již existuje</translation> + </message> + <message> + <source>The selected file already exists! +Do you want to overwrite it?</source> + <translation>Vybraný soubor již existuje! +Chcete jej přepsat?</translation> + </message> + <message> + <source>File Error</source> + <translation type="obsolete">Dateifehler</translation> + </message> + <message> + <source>Cannot open file in archive!</source> + <translation type="obsolete">Kann die Datei im Archiv nicht öffnen!</translation> + </message> + <message> + <source>Unsupported file type in archive!</source> + <translation type="obsolete">Nicht unterstützter Dateityp im Archiv!</translation> + </message> + <message> + <source>No Access</source> + <translation type="obsolete">Kein Zugriff</translation> + </message> + <message> + <source>Unable to open the file for writing!</source> + <translation type="obsolete">Kann die Logdatei nicht zum schreiben öffnen!</translation> + </message> + <message> + <source>OK</source> + <translation type="obsolete">OK</translation> + </message> + <message> + <source>Export Complete</source> + <translation>Vyvedení dokončeno</translation> + </message> + <message> + <source>Export complete!</source> + <translation>Vyvedení dokončeno!</translation> + </message> + <message> + <source>Export Aborted</source> + <translation type="obsolete">Export abgebrochen</translation> + </message> + <message> + <source>The export has been aborted.</source> + <translation type="obsolete">Der Export wurde abgebrochen.</translation> + </message> + <message> + <source>Export Failed</source> + <translation type="obsolete">Export fehlgeschlagen</translation> + </message> + <message> + <source>The Exporter encountered an error. +Please check your configuration and try again.</source> + <translation type="obsolete">Der Exporter ist auf einen Fehler gestoßen. +Bitte Kofiguration prüfen und erneut versuchen.</translation> + </message> + <message> + <source>Export Error</source> + <translation>Chyba při vyvedení</translation> + </message> + <message> + <source>Import Error</source> + <translation>Chyba při zavedení</translation> + </message> + <message> + <source>Abort</source> + <translation>Zrušit</translation> + </message> +</context> +<context> + <name>RDIntegerDialog</name> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> + <message> + <source>Set Value</source> + <translation>Nastavit hodnotu</translation> + </message> +</context> +<context> + <name>RDIntegerEdit</name> + <message> + <source>Add</source> + <translation>Přidat</translation> + </message> + <message> + <source>Delete</source> + <translation>Smazat</translation> + </message> + <message> + <source>Set Value</source> + <translation>Nastavit hodnotu</translation> + </message> +</context> +<context> + <name>RDLicense</name> + <message> + <source>&Close</source> + <translation>&Zavřít</translation> + </message> + <message> + <source>GNU Public License v2</source> + <translation>GNU Public License v2</translation> + </message> +</context> +<context> + <name>RDListGroups</name> + <message> + <source>Select Group</source> + <translation>Vybrat skupinu</translation> + </message> + <message> + <source>NAME</source> + <translation>NÁZEV</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>POPIS</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> +</context> +<context> + <name>RDListLogs</name> + <message> + <source>Select Log - User: </source> + <translation>Vybrat zápis - uživatel:</translation> + </message> + <message> + <source>Select Log</source> + <translation>Vybrat zápis</translation> + </message> + <message> + <source>NAME</source> + <translation>NÁZEV</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>POPIS</translation> + </message> + <message> + <source>SERVICE</source> + <translation>SLUŽBA</translation> + </message> + <message> + <source>OK</source> + <translation>OK</translation> + </message> + <message> + <source>Cancel</source> + <translation>Zrušit</translation> + </message> +</context> +<context> + <name>RDListSelector</name> + <message> + <source>Available Services</source> + <translation>Dostupné služby</translation> + </message> + <message> + <source>Add >></source> + <translation>Přidat >></translation> + </message> + <message> + <source><< Remove</source> + <translation><< Odstranit</translation> + </message> + <message> + <source>Active Services</source> + <translation>Spuštěné služby</translation> + </message> +</context> +<context> + <name>RDLogLine</name> + <message> + <source>Unknown</source> + <translation type="obsolete">Unbekannt</translation> + </message> + <message> + <source>Manual</source> + <translation type="obsolete">Handbuch</translation> + </message> + <message> + <source>Play</source> + <translation type="obsolete">Play</translation> + </message> + <message> + <source>Segue</source> + <translation type="obsolete">Segue</translation> + </message> + <message> + <source>Time</source> + <translation type="obsolete">Zeit</translation> + </message> + <message> + <source>Panel</source> + <translation type="obsolete">Panel</translation> + </message> + <message> + <source>Macro</source> + <translation type="obsolete">Makro</translation> + </message> + <message> + <source>PLAY</source> + <translation type="obsolete">PLAY</translation> + </message> + <message> + <source>SEGUE</source> + <translation type="obsolete">SEGUE</translation> + </message> + <message> + <source>STOP</source> + <translation type="obsolete">STOP</translation> + </message> + <message> + <source>UNKNOWN</source> + <translation type="obsolete">UNBEKANNT</translation> + </message> + <message> + <source>Audio</source> + <translation type="obsolete">Audio</translation> + </message> + <message> + <source>Marker</source> + <translation type="obsolete">Marker</translation> + </message> + <message> + <source>Open Bracket</source> + <translation type="obsolete">Klammer öffnen</translation> + </message> + <message> + <source>Close Bracket</source> + <translation type="obsolete">Klammer schließen</translation> + </message> + <message> + <source>ChainTo</source> + <translation type="obsolete">ChainTo</translation> + </message> + <message> + <source>Track</source> + <translation type="obsolete">Track</translation> + </message> + <message> + <source>Link</source> + <translation type="obsolete">Link</translation> + </message> + <message> + <source>Traffic</source> + <translation type="obsolete">Traffic</translation> + </message> + <message> + <source>Music</source> + <translation type="obsolete">Musik</translation> + </message> + <message> + <source>RDLogManager</source> + <translation type="obsolete">RDLogManager</translation> + </message> + <message> + <source>Tracker</source> + <translation type="obsolete">Tracker</translation> + </message> +</context> +<context> + <name>RDPanelButton</name> + <message> + <source>No Audio</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDPasswd</name> + <message> + <source>Change Password</source> + <translation>Změnit heslo</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Zrušit</translation> + </message> + <message> + <source>&Password:</source> + <translation>He&slo:</translation> + </message> + <message> + <source>C&onfirm:</source> + <translation>&Potvrdit:</translation> + </message> + <message> + <source>Password Mismatch</source> + <translation>Dvojice hesel se neshodují</translation> + </message> + <message> + <source>The passwords don't match, +please try again!</source> + <translation>Hesla se neshodují. +Zkuste to, prosím, znovu!</translation> + </message> + <message> + <source>OK</source> + <translation>OK</translation> + </message> +</context> +<context> + <name>RDRecording</name> + <message> + <source>Recording</source> + <translation type="obsolete">Aufnahme</translation> + </message> + <message> + <source>Macro Event</source> + <translation type="obsolete">Makro Event</translation> + </message> + <message> + <source>Switch Event</source> + <translation type="obsolete">Schalt-Event</translation> + </message> + <message> + <source>Playout</source> + <translation type="obsolete">Playout</translation> + </message> + <message> + <source>Download</source> + <translation type="obsolete">Download</translation> + </message> + <message> + <source>Upload</source> + <translation type="obsolete">Upload</translation> + </message> + <message> + <source>Ok</source> + <translation type="obsolete">Ok</translation> + </message> + <message> + <source>Short Length</source> + <translation type="obsolete">Kurze Länge</translation> + </message> + <message> + <source>Low Level</source> + <translation type="obsolete">Niedriger Level</translation> + </message> + <message> + <source>High Level</source> + <translation type="obsolete">Hoher Level</translation> + </message> + <message> + <source>Downloading</source> + <translation type="obsolete">Herunterladen</translation> + </message> + <message> + <source>Uploading</source> + <translation type="obsolete">Hochladen</translation> + </message> + <message> + <source>Server Error</source> + <translation type="obsolete">Serverfehler</translation> + </message> + <message> + <source>Internal Error</source> + <translation type="obsolete">Interner Fehler</translation> + </message> + <message> + <source>Interrupted</source> + <translation type="obsolete">Unterbrochen</translation> + </message> + <message> + <source>Playing</source> + <translation type="obsolete">Abspielen</translation> + </message> + <message> + <source>Waiting</source> + <translation type="obsolete">Warten</translation> + </message> + <message> + <source>Device Busy</source> + <translation type="obsolete">Gerät beschäftigt</translation> + </message> + <message> + <source>No Such Cart/Cut</source> + <translation type="obsolete">Kein solcher Cart/Cut</translation> + </message> + <message> + <source>Unknown Audio Format</source> + <translation type="obsolete">Unbekanntes Audioformat</translation> + </message> +</context> +<context> + <name>RDReport</name> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation type="obsolete">CBSI DeltaFlex Traffic Reconciliation v2.01</translation> + </message> + <message> + <source>Text Log</source> + <translation type="obsolete">Text Log</translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation type="obsolete">ASCAP/BMI Electronic Music Report</translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation type="obsolete">Technical Playout Report</translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation type="obsolete">SoundExchange Statutory License Report</translation> + </message> + <message> + <source>Unknown</source> + <translation type="obsolete">Unbekannt</translation> + </message> + <message> + <source>Other</source> + <translation type="obsolete">Andere</translation> + </message> + <message> + <source>AM</source> + <translation type="obsolete">AM</translation> + </message> + <message> + <source>FM</source> + <translation type="obsolete">FM</translation> + </message> + <message> + <source>Report complete!</source> + <translation type="obsolete">Report vollständig!</translation> + </message> + <message> + <source>Report canceled!</source> + <translation type="obsolete">Report abgebrochen!</translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation type="obsolete">Kann Reportdatei nicht öffnen!</translation> + </message> + <message> + <source>RadioTraffic.com Traffic Reconciliation</source> + <translation type="obsolete">RadioTraffic.com Traffic Reconciliation</translation> + </message> + <message> + <source>VisualTraffic Reconciliation</source> + <translation type="obsolete">VisualTraffic Reconciliation</translation> + </message> + <message> + <source>CounterPoint Traffic Reconciliation</source> + <translation type="obsolete">CounterPoint Traffic Reconciliation</translation> + </message> + <message> + <source>Music1 Reconciliation</source> + <translation type="obsolete">Music1 Reconciliation</translation> + </message> +</context> +<context> + <name>RDSoundPanel</name> + <message> + <source>Play All</source> + <translation>Přehrát vše</translation> + </message> + <message> + <source>Play Hook</source> + <translation>Přehrát chytlavou melodii</translation> + </message> + <message> + <source>Reset</source> + <translation>Nastavit znovu</translation> + </message> + <message> + <source>All</source> + <translation>Vše</translation> + </message> + <message> + <source>Setup</source> + <translation>Nastavení</translation> + </message> + <message> + <source>Cart</source> + <translation>Vozík</translation> + </message> + <message> + <source>Panel</source> + <translation>Panel</translation> + </message> +</context> +<context> + <name>RDSqlDatabaseStatus</name> + <message> + <source>Database connection restored.</source> + <translation>Databázové spojení obnoveno.</translation> + </message> + <message> + <source>Database connection failed : </source> + <translation>Databázové spojení se nezdařilo:</translation> + </message> +</context> +<context> + <name>RDStereoMeter</name> + <message> + <source>L</source> + <translation>L</translation> + </message> + <message> + <source>R</source> + <translation>P</translation> + </message> + <message> + <source>CLIP</source> + <translation>CLIP</translation> + </message> +</context> +<context> + <name>RDSvc</name> + <message> + <source>The following events were not placed: +</source> + <translation>Následující události nebyly umístěny:</translation> + </message> + <message> + <source>[unknown cart]</source> + <translation>[neznámý vozík]</translation> + </message> + <message> + <source>Event Fill Errors +</source> + <translation>Chyba plnění události</translation> + </message> +</context> +</TS> diff --git a/lib/librd_de.ts b/lib/librd_de.ts new file mode 100644 index 00000000..ca4441ff --- /dev/null +++ b/lib/librd_de.ts @@ -0,0 +1,2180 @@ +<!DOCTYPE TS><TS> +<context> + <name></name> + <message> + <source>UNKNOWN CUT</source> + <translation type="obsolete">Unbekannter Cut</translation> + </message> +</context> +<context> + <name>@default</name> + <message> + <source>ALL</source> + <translation type="obsolete">ALLE</translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <source>Couldn't initialize QSql driver!</source> + <translation>Qsql-Treiber konnte nicht initialisiert werden!</translation> + </message> + <message> + <source>Couldn't open mySQL connection!</source> + <translation>Konnte keine Verbindung zum mySQL-Server herstellen!</translation> + </message> + <message> + <source>Sequentially</source> + <translation type="unfinished">Sequentiell</translation> + </message> + <message> + <source>Randomly</source> + <translation type="unfinished">Zufällig</translation> + </message> + <message> + <source>Unknown</source> + <translation type="unfinished">Unbekannt</translation> + </message> + <message> + <source>Feature</source> + <translation type="unfinished">Feature</translation> + </message> + <message> + <source>Theme Open</source> + <translation type="unfinished">Thema Anfang</translation> + </message> + <message> + <source>Theme Close</source> + <translation type="unfinished">Thema Ende</translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation type="unfinished">Thema Anfang/Ende</translation> + </message> + <message> + <source>Background</source> + <translation type="unfinished">Hintergrund</translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation type="unfinished">Commercial/Jingle/Promo</translation> + </message> + <message> + <source>UNKNOWN CUT</source> + <translation type="unfinished">Unbekannter Cut</translation> + </message> + <message> + <source>Manual</source> + <translation type="unfinished">Handbuch</translation> + </message> + <message> + <source>Play</source> + <translation type="unfinished">Play</translation> + </message> + <message> + <source>Segue</source> + <translation type="unfinished">Segue</translation> + </message> + <message> + <source>Time</source> + <translation type="unfinished">Zeit</translation> + </message> + <message> + <source>Panel</source> + <translation type="unfinished">Panel</translation> + </message> + <message> + <source>Macro</source> + <translation type="unfinished">Makro</translation> + </message> + <message> + <source>PLAY</source> + <translation type="unfinished">PLAY</translation> + </message> + <message> + <source>SEGUE</source> + <translation type="unfinished">SEGUE</translation> + </message> + <message> + <source>STOP</source> + <translation type="unfinished">STOP</translation> + </message> + <message> + <source>UNKNOWN</source> + <translation type="unfinished">UNBEKANNT</translation> + </message> + <message> + <source>Audio</source> + <translation type="unfinished">Audio</translation> + </message> + <message> + <source>Marker</source> + <translation type="unfinished">Marker</translation> + </message> + <message> + <source>Open Bracket</source> + <translation type="unfinished">Klammer öffnen</translation> + </message> + <message> + <source>Close Bracket</source> + <translation type="unfinished">Klammer schließen</translation> + </message> + <message> + <source>ChainTo</source> + <translation type="unfinished">ChainTo</translation> + </message> + <message> + <source>Track</source> + <translation type="unfinished">Track</translation> + </message> + <message> + <source>Link</source> + <translation type="unfinished">Link</translation> + </message> + <message> + <source>Traffic</source> + <translation type="unfinished">Traffic</translation> + </message> + <message> + <source>Music</source> + <translation type="unfinished">Musik</translation> + </message> + <message> + <source>RDLogManager</source> + <translation type="unfinished">RDLogManager</translation> + </message> + <message> + <source>Tracker</source> + <translation type="unfinished">Tracker</translation> + </message> + <message> + <source>Recording</source> + <translation type="unfinished">Aufnahme</translation> + </message> + <message> + <source>Macro Event</source> + <translation type="unfinished">Makro Event</translation> + </message> + <message> + <source>Switch Event</source> + <translation type="unfinished">Schalt-Event</translation> + </message> + <message> + <source>Playout</source> + <translation type="unfinished">Playout</translation> + </message> + <message> + <source>Download</source> + <translation type="unfinished">Download</translation> + </message> + <message> + <source>Upload</source> + <translation type="unfinished">Upload</translation> + </message> + <message> + <source>Ok</source> + <translation type="unfinished">Ok</translation> + </message> + <message> + <source>Short Length</source> + <translation type="unfinished">Kurze Länge</translation> + </message> + <message> + <source>Low Level</source> + <translation type="unfinished">Niedriger Level</translation> + </message> + <message> + <source>High Level</source> + <translation type="unfinished">Hoher Level</translation> + </message> + <message> + <source>Downloading</source> + <translation type="unfinished">Herunterladen</translation> + </message> + <message> + <source>Uploading</source> + <translation type="unfinished">Hochladen</translation> + </message> + <message> + <source>Server Error</source> + <translation type="unfinished">Serverfehler</translation> + </message> + <message> + <source>Internal Error</source> + <translation type="unfinished">Interner Fehler</translation> + </message> + <message> + <source>Interrupted</source> + <translation type="unfinished">Unterbrochen</translation> + </message> + <message> + <source>Playing</source> + <translation type="unfinished">Abspielen</translation> + </message> + <message> + <source>Waiting</source> + <translation type="unfinished">Warten</translation> + </message> + <message> + <source>Device Busy</source> + <translation type="unfinished">Gerät beschäftigt</translation> + </message> + <message> + <source>No Such Cart/Cut</source> + <translation type="unfinished">Kein solcher Cart/Cut</translation> + </message> + <message> + <source>Unknown Audio Format</source> + <translation type="unfinished">Unbekanntes Audioformat</translation> + </message> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation type="unfinished">CBSI DeltaFlex Traffic Reconciliation v2.01</translation> + </message> + <message> + <source>Text Log</source> + <translation type="unfinished">Text Log</translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation type="unfinished">ASCAP/BMI Electronic Music Report</translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation type="unfinished">Technical Playout Report</translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation type="unfinished">SoundExchange Statutory License Report</translation> + </message> + <message> + <source>RadioTraffic.com Traffic Reconciliation</source> + <translation type="unfinished">RadioTraffic.com Traffic Reconciliation</translation> + </message> + <message> + <source>VisualTraffic Reconciliation</source> + <translation type="unfinished">VisualTraffic Reconciliation</translation> + </message> + <message> + <source>CounterPoint Traffic Reconciliation</source> + <translation type="unfinished">CounterPoint Traffic Reconciliation</translation> + </message> + <message> + <source>Music1 Reconciliation</source> + <translation type="unfinished">Music1 Reconciliation</translation> + </message> + <message> + <source>Other</source> + <translation type="unfinished">Andere</translation> + </message> + <message> + <source>AM</source> + <translation type="unfinished">AM</translation> + </message> + <message> + <source>FM</source> + <translation type="unfinished">FM</translation> + </message> + <message> + <source>Report complete!</source> + <translation type="unfinished">Report vollständig!</translation> + </message> + <message> + <source>Report canceled!</source> + <translation type="unfinished">Report abgebrochen!</translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation type="unfinished">Kann Reportdatei nicht öffnen!</translation> + </message> + <message> + <source>Music Summary</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>WideOrbit Traffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown Position</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Left</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Center</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Right</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Left</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Center</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Right</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NPR/DS SoundExchange Report</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 1</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel First Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 1 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 2 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Second Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Third Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fourth Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audition/Cue Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Channel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fifth and Later Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>invalid SQL or failed DB connection</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>All</source> + <translation type="unfinished">Alles</translation> + </message> + <message> + <source>Relative</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hard</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NaturalLog Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>LiveAssist</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Automatic</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Previous</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Classical Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>reserved</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAddCart</name> + <message> + <source>&Group:</source> + <translation>&Gruppe:</translation> + </message> + <message> + <source>&New Cart Number:</source> + <translation>&Neue Cartnummer:</translation> + </message> + <message> + <source>&New Cart Type:</source> + <translation>&Neuer Cart-Typ:</translation> + </message> + <message> + <source>Audio</source> + <translation>Audio</translation> + </message> + <message> + <source>Macro</source> + <translation>Makro</translation> + </message> + <message> + <source>[new cart]</source> + <translation>[neuer Cart]</translation> + </message> + <message> + <source>&New Cart Title:</source> + <translation>&Neuer Cart-Titel:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>Abbre&chen</translation> + </message> + <message> + <source>No Available Cart Numbers</source> + <translation>Keine Cartnummern verfügbar</translation> + </message> + <message> + <source>There are no more available cart numbers for the group!</source> + <translation>Es gibt keine weiteren verfügbaren Cartnummern für die Gruppe!</translation> + </message> + <message> + <source>Invalid Number</source> + <translation>Ungültige Zahl</translation> + </message> + <message> + <source>Invalid Cart Number!</source> + <translation>Ungültige Cartnummer!</translation> + </message> + <message> + <source>Title Required</source> + <translation>Titel benötigt</translation> + </message> + <message> + <source>You must enter a cart title!</source> + <translation>Sie müssen einen Cart-Titel eingeben!</translation> + </message> + <message> + <source>The cart number is outside of the permitted range for this group!</source> + <translation>Die Cartnummer befindet sich außerhalb des für diese Gruppe erlaubten Bereichs!</translation> + </message> + <message> + <source>Cart Exists</source> + <translation>Cart existiert</translation> + </message> + <message> + <source>This cart already exists.</source> + <translation>Dieser Cart existiert bereits.</translation> + </message> + <message> + <source>Duplicate Title</source> + <translation>Doppelter Titel</translation> + </message> + <message> + <source>The cart title must be unique!</source> + <translation>Der Cart-Titel muss einzigartig sein!</translation> + </message> +</context> +<context> + <name>RDAddLog</name> + <message> + <source>Create Log</source> + <translation>Log erstellen</translation> + </message> + <message> + <source>&New Log Name:</source> + <translation>&Name des neuen Logs:</translation> + </message> + <message> + <source>&Service:</source> + <translation>&Service:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>Abbre&chen</translation> + </message> + <message> + <source>RDLogEdit</source> + <translation>RDLogEdit</translation> + </message> + <message> + <source>The name is invalid!</source> + <translation type="obsolete">Der Name ist ungültig!</translation> + </message> + <message> + <source>The service is invalid!</source> + <translation>Der Service ist ungültig!</translation> + </message> +</context> +<context> + <name>RDAudioSettingsDialog</name> + <message> + <source>Edit Settings</source> + <translation>Einstellungen editieren</translation> + </message> + <message> + <source>Default &Format:</source> + <translation>Standard &Format:</translation> + </message> + <message> + <source>Default &Channels:</source> + <translation>Standard &Kanäle:</translation> + </message> + <message> + <source>Default &Sample Rate:</source> + <translation>Standard &Sample Rate:</translation> + </message> + <message> + <source>Default &Bitrate:</source> + <translation>Standard &Bitrate:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>Abbre&chen</translation> + </message> + <message> + <source>PCM16</source> + <translation>PCM16</translation> + </message> + <message> + <source>OggVorbis</source> + <translation>OggVorbis</translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation>MPEG Layer 2</translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation>MPEG Layer 3</translation> + </message> +</context> +<context> + <name>RDButtonDialog</name> + <message> + <source>Edit Button</source> + <translation>Edit Schaltfläche</translation> + </message> + <message> + <source>Label:</source> + <translation>Label:</translation> + </message> + <message> + <source>Cart:</source> + <translation>Cart:</translation> + </message> + <message> + <source>Set +Cart</source> + <translation>Cart +einstellen</translation> + </message> + <message> + <source>Clear</source> + <translation>Löschen</translation> + </message> + <message> + <source>Set +Color</source> + <translation>Farbe +setzen</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>Abbre&chen</translation> + </message> + <message> + <source>NOT FOUND</source> + <translation>NICHT GEFUNDEN</translation> + </message> +</context> +<context> + <name>RDCardSelector</name> + <message> + <source>Card:</source> + <translation>Karte:</translation> + </message> + <message> + <source>Port:</source> + <translation>Port:</translation> + </message> +</context> +<context> + <name>RDCart</name> + <message> + <source>Sequentially</source> + <translation type="obsolete">Sequentiell</translation> + </message> + <message> + <source>Randomly</source> + <translation type="obsolete">Zufällig</translation> + </message> + <message> + <source>Unknown</source> + <translation type="obsolete">Unbekannt</translation> + </message> + <message> + <source>Feature</source> + <translation type="obsolete">Feature</translation> + </message> + <message> + <source>Theme Open</source> + <translation type="obsolete">Thema Anfang</translation> + </message> + <message> + <source>Theme Close</source> + <translation type="obsolete">Thema Ende</translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation type="obsolete">Thema Anfang/Ende</translation> + </message> + <message> + <source>Background</source> + <translation type="obsolete">Hintergrund</translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation type="obsolete">Commercial/Jingle/Promo</translation> + </message> +</context> +<context> + <name>RDCartDialog</name> + <message> + <source>Select Cart</source> + <translation>Cart auswählen</translation> + </message> + <message> + <source>Please Wait...</source> + <translation>Bitte warten...</translation> + </message> + <message> + <source>Cart Filter:</source> + <translation>Cart Filter:</translation> + </message> + <message> + <source>&Search</source> + <translation>&Suchen</translation> + </message> + <message> + <source>C&lear</source> + <translation>&Löschen</translation> + </message> + <message> + <source>Group:</source> + <translation>Gruppe:</translation> + </message> + <message> + <source>NUMBER</source> + <translation>NUMMER</translation> + </message> + <message> + <source>LENGTH</source> + <translation>LÄNGE</translation> + </message> + <message> + <source>TITLE</source> + <translation>TITEL</translation> + </message> + <message> + <source>ARTIST</source> + <translation>KÜNSTLER</translation> + </message> + <message> + <source>GROUP</source> + <translation>GRUPPE</translation> + </message> + <message> + <source>CLIENT</source> + <translation>KUNDE</translation> + </message> + <message> + <source>AGENCY</source> + <translation>AGENTUR</translation> + </message> + <message> + <source>USER DEF</source> + <translation>BENUTZER DEF</translation> + </message> + <message> + <source>START</source> + <translation>START</translation> + </message> + <message> + <source>END</source> + <translation>END</translation> + </message> + <message> + <source>Send to +&Editor</source> + <translation>An &Editor +senden</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>Abbre&chen</translation> + </message> + <message> + <source>ALL</source> + <translation>ALLE</translation> + </message> + <message> + <source>Show Only First</source> + <translation>Zeige nur erste</translation> + </message> + <message> + <source>Matches</source> + <translation>Treffer</translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Load From +&File</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cart Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to create temporary cart for import!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to get temporary cart number for import!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import Error</source> + <translation type="unfinished">Importfehler</translation> + </message> + <message> + <source>Imported from</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Importing...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Importing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>COMPOSER</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CONDUCTOR</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEdit</name> + <message> + <source>&Audition</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Stop</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>End</source> + <translation type="unfinished">Ende</translation> + </message> + <message> + <source>&Recue</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEditDialog</name> + <message> + <source>Set Cue Point</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished">&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCutDialog</name> + <message> + <source>Select Cut</source> + <translation>Cut auswählen</translation> + </message> + <message> + <source>Please Wait...</source> + <translation>Bitte warten...</translation> + </message> + <message> + <source>Cart Filter:</source> + <translation>Cart-Filter:</translation> + </message> + <message> + <source>&Search</source> + <translation>&Suchen</translation> + </message> + <message> + <source>C&lear</source> + <translation>&Löschen</translation> + </message> + <message> + <source>Group:</source> + <translation>Gruppe:</translation> + </message> + <message> + <source>Carts</source> + <translation>Carts</translation> + </message> + <message> + <source>NUMBER</source> + <translation>NUMMER</translation> + </message> + <message> + <source>TITLE</source> + <translation>TITEL</translation> + </message> + <message> + <source>GROUP</source> + <translation>GRUPPE</translation> + </message> + <message> + <source>Cuts</source> + <translation>Cuts</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>BESCHREIBUNG</translation> + </message> + <message> + <source>&Add New +Cart</source> + <translation>Neuen C&art hinzufügen</translation> + </message> + <message> + <source>&Clear</source> + <translation>&Löschen</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>Abbre&chen</translation> + </message> + <message> + <source>ALL</source> + <translation>ALLE</translation> + </message> + <message> + <source>Show Only First</source> + <translation>Zeige nur erste</translation> + </message> + <message> + <source>Matches</source> + <translation>Treffer</translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDDateDialog</name> + <message> + <source>Select Date</source> + <translation>Datum wählen</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>Abbre&chen</translation> + </message> +</context> +<context> + <name>RDDatePicker</name> + <message> + <source>Mo</source> + <translation>Mo</translation> + </message> + <message> + <source>Tu</source> + <translation>Di</translation> + </message> + <message> + <source>We</source> + <translation>Mi</translation> + </message> + <message> + <source>Th</source> + <translation>Do</translation> + </message> + <message> + <source>Fr</source> + <translation>Fr</translation> + </message> + <message> + <source>Sa</source> + <translation>Sa</translation> + </message> + <message> + <source>Su</source> + <translation>So</translation> + </message> +</context> +<context> + <name>RDEditAudio</name> + <message> + <source>&Save</source> + <translation>&Speichern</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Abbrechen</translation> + </message> + <message> + <source>Amplitude</source> + <translation>Amplitude</translation> + </message> + <message> + <source>Zoom +In</source> + <translation>hineinzoomen</translation> + </message> + <message> + <source>Zoom +Out</source> + <translation>herauszoomen</translation> + </message> + <message> + <source>Time</source> + <translation>Zeit</translation> + </message> + <message> + <source>Full +In</source> + <translation>Full +In</translation> + </message> + <message> + <source>Full +Out</source> + <translation>Full +Out</translation> + </message> + <message> + <source>Goto</source> + <translation>Gehe zu</translation> + </message> + <message> + <source>Cursor</source> + <translation>Cursor</translation> + </message> + <message> + <source>Home</source> + <translation>Home</translation> + </message> + <message> + <source>End</source> + <translation>Ende</translation> + </message> + <message> + <source>Cut +Start</source> + <translation>Cut +Start</translation> + </message> + <message> + <source>Cut +End</source> + <translation>Cut +Ende</translation> + </message> + <message> + <source>Talk +Start</source> + <translation>Mod +Start</translation> + </message> + <message> + <source>Segue +Start</source> + <translation>Segue +Start</translation> + </message> + <message> + <source>Segue +End</source> + <translation>Segue +Ende</translation> + </message> + <message> + <source>Fade +Up</source> + <translation>Einfaden</translation> + </message> + <message> + <source>Hook +Start</source> + <translation>Hook +Start</translation> + </message> + <message> + <source>Hook +End</source> + <translation>Hook +Ende</translation> + </message> + <message> + <source> dB</source> + <translation>dB</translation> + </message> + <message> + <source>Threshold</source> + <translation>Threshold</translation> + </message> + <message> + <source>Trim +Start</source> + <translation>Trim +Start</translation> + </message> + <message> + <source>Trim +End</source> + <translation>Trim +Ende</translation> + </message> + <message> + <source>Cut Gain</source> + <translation>Cut Gain</translation> + </message> + <message> + <source>Remove +Marker</source> + <translation>Marker +entfernen</translation> + </message> + <message> + <source>No Fade on Segue Out</source> + <translation>Kein Fade bei Seque Out</translation> + </message> + <message> + <source>Position</source> + <translation>Position</translation> + </message> + <message> + <source>Length</source> + <translation>Länge</translation> + </message> + <message> + <source>Delete Talk Markers</source> + <translation>Mod.-Marker entfernen</translation> + </message> + <message> + <source>Delete Segue Markers</source> + <translation>Segue-Marker entfernen</translation> + </message> + <message> + <source>Delete Hook Markers</source> + <translation>Hook-Marker entfernen</translation> + </message> + <message> + <source>Delete Fade Up Marker</source> + <translation>Ein-Fade Marker entfernen</translation> + </message> + <message> + <source>Delete Fade Down Marker</source> + <translation>Aus-Fade Marker entfernen</translation> + </message> + <message> + <source>dB</source> + <translation>dB</translation> + </message> + <message> + <source><none></source> + <translation><nichts></translation> + </message> + <message> + <source>Cut</source> + <translation>Cut</translation> + </message> + <message> + <source>Talk</source> + <translation>Mod</translation> + </message> + <message> + <source>Segue</source> + <translation>Segue</translation> + </message> + <message> + <source>Hook</source> + <translation>Hook</translation> + </message> + <message> + <source>Fade Up</source> + <translation>Einfaden</translation> + </message> + <message> + <source>Fade Down</source> + <translation>Ausfaden</translation> + </message> + <message> + <source>L</source> + <translation>L</translation> + </message> + <message> + <source>R</source> + <translation>R</translation> + </message> + <message> + <source>Rivendell Web Service</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to download peak data, error was: +"</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Edit Audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Marker Warning</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Less than half of the audio is playable with these marker settings. +Are you sure you want to save?</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>More than half of the audio will be faded with these marker settings. +Are you sure you want to save?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDEditPanelName</name> + <message> + <source>Edit Panel Name</source> + <translation>Namen editieren</translation> + </message> + <message> + <source>Panel &Name:</source> + <translation>Paneel &Name:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>Abbre&chen</translation> + </message> +</context> +<context> + <name>RDExceptionDialog</name> + <message> + <source>Rivendell Exception Report</source> + <translation>Rivendell Fehlerreport</translation> + </message> + <message> + <source>&Save</source> + <translation>&Speichern</translation> + </message> + <message> + <source>&Close</source> + <translation>&Schliessen</translation> + </message> + <message> + <source>Text (*.txt *.TXT) +All Files (*.*)</source> + <translation>Text (*.txt *.TXT) +Alle Dateien (*.*)</translation> + </message> + <message> + <source>Export File</source> + <translation>Datei Exportieren</translation> + </message> + <message> + <source>The file</source> + <translation>Die Datei</translation> + </message> + <message> + <source>already exists! +Overwrite?</source> + <translation>existiert bereits! +Überschreiben?</translation> + </message> + <message> + <source>File Exists</source> + <translation>Datei existiert</translation> + </message> + <message> + <source>Unable to open file</source> + <translation>Kann die Datei nicht öffnen</translation> + </message> + <message> + <source>for writing!</source> + <translation>zum schreiben!</translation> + </message> + <message> + <source>File Error</source> + <translation>Dateifehler</translation> + </message> +</context> +<context> + <name>RDExportSettingsDialog</name> + <message> + <source>Edit Export Settings</source> + <translation>Exporteinstellungen editieren</translation> + </message> + <message> + <source>&Channels:</source> + <translation>&Kanäle:</translation> + </message> + <message> + <source>&Sample Rate:</source> + <translation>&Sample Rate:</translation> + </message> + <message> + <source>&Bitrate:</source> + <translation>&Bitrate:</translation> + </message> + <message> + <source>&Quality:</source> + <translation>&Qualität:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Abbrechen</translation> + </message> + <message> + <source>PCM16</source> + <translation>PCM16</translation> + </message> + <message> + <source>FLAC</source> + <translation>FLAC</translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation>MPEG Layer 2</translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation>MPEG Layer 3</translation> + </message> + <message> + <source>OggVorbis</source> + <translation>OggVorbis</translation> + </message> + <message> + <source>VBR</source> + <translation>VBR</translation> + </message> + <message> + <source>32 kbps</source> + <translation>32 kbps</translation> + </message> + <message> + <source>64 kbps</source> + <translation>64 kbps</translation> + </message> + <message> + <source>96 kbps</source> + <translation>96 kbps</translation> + </message> + <message> + <source>128 kbps</source> + <translation>128 kbps</translation> + </message> + <message> + <source>160 kbps</source> + <translation>160 kbps</translation> + </message> + <message> + <source>192 kbps</source> + <translation>192 kbps</translation> + </message> + <message> + <source>224 kbps</source> + <translation>224 kbps</translation> + </message> + <message> + <source>256 kbps</source> + <translation>256 kbps</translation> + </message> + <message> + <source>288 kbps</source> + <translation>288 kbps</translation> + </message> + <message> + <source>320 kbps</source> + <translation>320 kbps</translation> + </message> + <message> + <source>352 kbps</source> + <translation>352 kbps</translation> + </message> + <message> + <source>384 kbps</source> + <translation>384 kbps</translation> + </message> + <message> + <source>416 kbps</source> + <translation>416 kbps</translation> + </message> + <message> + <source>448 kbps</source> + <translation>448 kbps</translation> + </message> + <message> + <source>48 kbps</source> + <translation>48 kbps</translation> + </message> + <message> + <source>56 kbps</source> + <translation>56 kbps</translation> + </message> + <message> + <source>80 kbps</source> + <translation>80 kbps</translation> + </message> + <message> + <source>112 kbps</source> + <translation>112 kbps</translation> + </message> + <message> + <source>40 kbps</source> + <translation>40 kbps</translation> + </message> + <message> + <source>8 kbps</source> + <translation>8 kbps</translation> + </message> + <message> + <source>16 kbps</source> + <translation>16 kbps</translation> + </message> + <message> + <source>24 kbps</source> + <translation>24 kbps</translation> + </message> + <message> + <source>144 kbps</source> + <translation>144 kbps</translation> + </message> +</context> +<context> + <name>RDGetAth</name> + <message> + <source>Enter ATH</source> + <translation>ATH eingeben</translation> + </message> + <message> + <source>Enter the agreggate tuning hours (ATH) +figure for the report period. +(Supplied by your streaming provider).</source> + <translation>Enter the agreggate tuning hours (ATH) +figure for the report period. +(Fragen sie ihren Streamanbieter).</translation> + </message> + <message> + <source>ATH:</source> + <translation>ATH:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Abbrechen</translation> + </message> + <message> + <source>Invalid ATH</source> + <translation>Ungültiger ATH</translation> + </message> + <message> + <source>You must provide a valid ATH figure!</source> + <translation>Sie müssen eine gültige ATH-figure angeben!</translation> + </message> +</context> +<context> + <name>RDGetPasswd</name> + <message> + <source>Enter Password</source> + <translation>Passwort eingeben</translation> + </message> + <message> + <source>Enter password</source> + <translation>Passwort eingeben</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Abbrechen</translation> + </message> +</context> +<context> + <name>RDGpioSelector</name> + <message> + <source>Pin:</source> + <translation>PIN:</translation> + </message> +</context> +<context> + <name>RDImportAudio</name> + <message> + <source>Import/Export Audio File</source> + <translation>Audiodatei importieren/exportieren</translation> + </message> + <message> + <source>Import File</source> + <translation>Datei importieren</translation> + </message> + <message> + <source>Filename:</source> + <translation>Dateiname:</translation> + </message> + <message> + <source>&Select</source> + <translation>au&swählen</translation> + </message> + <message> + <source>Import file metadata</source> + <translation>Dateimetadaten importieren</translation> + </message> + <message> + <source>Channels:</source> + <translation>Kanäle:</translation> + </message> + <message> + <source>Autotrim</source> + <translation>Autotrim</translation> + </message> + <message> + <source>Level:</source> + <translation>Level:</translation> + </message> + <message> + <source>dBFS</source> + <translation>dBFS</translation> + </message> + <message> + <source>Export File</source> + <translation>Datei Exportieren</translation> + </message> + <message> + <source>Export file metadata</source> + <translation>Datei-Metadaten exportieren</translation> + </message> + <message> + <source>Format:</source> + <translation>Format:</translation> + </message> + <message> + <source>S&et</source> + <translation>S&etzen</translation> + </message> + <message> + <source>Normalize</source> + <translation>Normalisieren</translation> + </message> + <message> + <source>&Import</source> + <translation>&Importieren</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Abbrechen</translation> + </message> + <message> + <source>Export</source> + <translation>Exportieren</translation> + </message> + <message> + <source>Import</source> + <translation>Importieren</translation> + </message> + <message> + <source>Import Audio File</source> + <translation>Audiodatei importieren</translation> + </message> + <message> + <source>File does not exist!</source> + <translation>Datei existiert nicht!</translation> + </message> + <message> + <source>Cannot open file!</source> + <translation type="obsolete">Kann die Datei nicht öffnen!</translation> + </message> + <message> + <source>Unsupported file type!</source> + <translation type="obsolete">Dateityp nicht unterstützt!</translation> + </message> + <message> + <source>Audio Exists</source> + <translation type="obsolete">Audiomaterial existiert</translation> + </message> + <message> + <source>This will overwrite the existing recording. +Do you want to proceed?</source> + <translation type="obsolete">Das wird die existierende Aufnahme löschen. +Wollen sie fortfahren?</translation> + </message> + <message> + <source>Empty Clipboard</source> + <translation type="obsolete">Zwischenablage leeren</translation> + </message> + <message> + <source>Importing this cut will also empty the clipboard. +Do you still want to proceed?</source> + <translation type="obsolete">Diesen Cut zu importieren wird die Zwischen- +ablage löschen! Fortfahren?</translation> + </message> + <message> + <source>Import Complete</source> + <translation>Import abgeschlossen</translation> + </message> + <message> + <source>Import complete!</source> + <translation>Import abgeschlossen!</translation> + </message> + <message> + <source>Import Aborted</source> + <translation type="obsolete">Import abgebrochen</translation> + </message> + <message> + <source>The import has been aborted.</source> + <translation type="obsolete">Der Import wurde abgebrochen.</translation> + </message> + <message> + <source>Import Failed</source> + <translation type="obsolete">Import fehlgeschlagen</translation> + </message> + <message> + <source>The importer encountered an error. +Please check your importer configuration and try again.</source> + <translation type="obsolete">Der Importer ist auf einen Fehler gestoßen. +Bitte überprüfen sie die Importer-Einstellungen und versuchen sie es erneut.</translation> + </message> + <message> + <source>File Exists</source> + <translation>Datei existiert</translation> + </message> + <message> + <source>The selected file already exists! +Do you want to overwrite it?</source> + <translation>Die ausgewählte Datei existiert +bereits! Überschreiben?</translation> + </message> + <message> + <source>File Error</source> + <translation type="obsolete">Dateifehler</translation> + </message> + <message> + <source>Cannot open file in archive!</source> + <translation type="obsolete">Kann die Datei im Archiv nicht öffnen!</translation> + </message> + <message> + <source>Unsupported file type in archive!</source> + <translation type="obsolete">Nicht unterstützter Dateityp im Archiv!</translation> + </message> + <message> + <source>No Access</source> + <translation type="obsolete">Kein Zugriff</translation> + </message> + <message> + <source>Unable to open the file for writing!</source> + <translation type="obsolete">Kann die Logdatei nicht zum schreiben öffnen!</translation> + </message> + <message> + <source>OK</source> + <translation type="obsolete">OK</translation> + </message> + <message> + <source>Export Complete</source> + <translation>Export vollständig</translation> + </message> + <message> + <source>Export complete!</source> + <translation>Export vollständig!</translation> + </message> + <message> + <source>Export Aborted</source> + <translation type="obsolete">Export abgebrochen</translation> + </message> + <message> + <source>The export has been aborted.</source> + <translation type="obsolete">Der Export wurde abgebrochen.</translation> + </message> + <message> + <source>Export Failed</source> + <translation type="obsolete">Export fehlgeschlagen</translation> + </message> + <message> + <source>The Exporter encountered an error. +Please check your configuration and try again.</source> + <translation type="obsolete">Der Exporter ist auf einen Fehler gestoßen. +Bitte Kofiguration prüfen und erneut versuchen.</translation> + </message> + <message> + <source>Export Error</source> + <translation>Exportfehler</translation> + </message> + <message> + <source>Import Error</source> + <translation>Importfehler</translation> + </message> + <message> + <source>Abort</source> + <translation>Abbrechen</translation> + </message> +</context> +<context> + <name>RDIntegerDialog</name> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Abbrechen</translation> + </message> + <message> + <source>Set Value</source> + <translation>Wert setzen</translation> + </message> +</context> +<context> + <name>RDIntegerEdit</name> + <message> + <source>Add</source> + <translation>Hinzufügen</translation> + </message> + <message> + <source>Delete</source> + <translation>Löschen</translation> + </message> + <message> + <source>Set Value</source> + <translation>Wert setzen</translation> + </message> +</context> +<context> + <name>RDLicense</name> + <message> + <source>&Close</source> + <translation>&Schliessen</translation> + </message> + <message> + <source>GNU Public License v2</source> + <translation>GNU Public License v2</translation> + </message> +</context> +<context> + <name>RDListGroups</name> + <message> + <source>Select Group</source> + <translation>Gruppe wählen</translation> + </message> + <message> + <source>NAME</source> + <translation>NAME</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>BESCHREIBUNG</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>Abbre&chen</translation> + </message> +</context> +<context> + <name>RDListLogs</name> + <message> + <source>Select Log - User: </source> + <translation>Logbenutzer auswählen:</translation> + </message> + <message> + <source>Select Log</source> + <translation>Log auswählen</translation> + </message> + <message> + <source>NAME</source> + <translation>NAME</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>BESCHREIBUNG</translation> + </message> + <message> + <source>SERVICE</source> + <translation>SERVICE</translation> + </message> + <message> + <source>OK</source> + <translation>OK</translation> + </message> + <message> + <source>Cancel</source> + <translation>Abbrechen</translation> + </message> +</context> +<context> + <name>RDListSelector</name> + <message> + <source>Available Services</source> + <translation>Verfügbare Services</translation> + </message> + <message> + <source>Add >></source> + <translation>Hinzufügen >></translation> + </message> + <message> + <source><< Remove</source> + <translation><< Entfernen</translation> + </message> + <message> + <source>Active Services</source> + <translation>Aktive Services</translation> + </message> +</context> +<context> + <name>RDLogLine</name> + <message> + <source>Unknown</source> + <translation type="obsolete">Unbekannt</translation> + </message> + <message> + <source>Manual</source> + <translation type="obsolete">Handbuch</translation> + </message> + <message> + <source>Play</source> + <translation type="obsolete">Play</translation> + </message> + <message> + <source>Segue</source> + <translation type="obsolete">Segue</translation> + </message> + <message> + <source>Time</source> + <translation type="obsolete">Zeit</translation> + </message> + <message> + <source>Panel</source> + <translation type="obsolete">Panel</translation> + </message> + <message> + <source>Macro</source> + <translation type="obsolete">Makro</translation> + </message> + <message> + <source>PLAY</source> + <translation type="obsolete">PLAY</translation> + </message> + <message> + <source>SEGUE</source> + <translation type="obsolete">SEGUE</translation> + </message> + <message> + <source>STOP</source> + <translation type="obsolete">STOP</translation> + </message> + <message> + <source>UNKNOWN</source> + <translation type="obsolete">UNBEKANNT</translation> + </message> + <message> + <source>Audio</source> + <translation type="obsolete">Audio</translation> + </message> + <message> + <source>Marker</source> + <translation type="obsolete">Marker</translation> + </message> + <message> + <source>Open Bracket</source> + <translation type="obsolete">Klammer öffnen</translation> + </message> + <message> + <source>Close Bracket</source> + <translation type="obsolete">Klammer schließen</translation> + </message> + <message> + <source>ChainTo</source> + <translation type="obsolete">ChainTo</translation> + </message> + <message> + <source>Track</source> + <translation type="obsolete">Track</translation> + </message> + <message> + <source>Link</source> + <translation type="obsolete">Link</translation> + </message> + <message> + <source>Traffic</source> + <translation type="obsolete">Traffic</translation> + </message> + <message> + <source>Music</source> + <translation type="obsolete">Musik</translation> + </message> + <message> + <source>RDLogManager</source> + <translation type="obsolete">RDLogManager</translation> + </message> + <message> + <source>Tracker</source> + <translation type="obsolete">Tracker</translation> + </message> +</context> +<context> + <name>RDPanelButton</name> + <message> + <source>No Audio</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDPasswd</name> + <message> + <source>Change Password</source> + <translation>Paßwort ändern</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Abbrechen</translation> + </message> + <message> + <source>&Password:</source> + <translation>&Paßwort:</translation> + </message> + <message> + <source>C&onfirm:</source> + <translation>&Bestätigen:</translation> + </message> + <message> + <source>Password Mismatch</source> + <translation>Paßworte stimmen nicht überein</translation> + </message> + <message> + <source>The passwords don't match, +please try again!</source> + <translation>Die Paßworte stimmen nicht überein, +bitte erneut versuchen!</translation> + </message> + <message> + <source>OK</source> + <translation>OK</translation> + </message> +</context> +<context> + <name>RDRecording</name> + <message> + <source>Recording</source> + <translation type="obsolete">Aufnahme</translation> + </message> + <message> + <source>Macro Event</source> + <translation type="obsolete">Makro Event</translation> + </message> + <message> + <source>Switch Event</source> + <translation type="obsolete">Schalt-Event</translation> + </message> + <message> + <source>Playout</source> + <translation type="obsolete">Playout</translation> + </message> + <message> + <source>Download</source> + <translation type="obsolete">Download</translation> + </message> + <message> + <source>Upload</source> + <translation type="obsolete">Upload</translation> + </message> + <message> + <source>Ok</source> + <translation type="obsolete">Ok</translation> + </message> + <message> + <source>Short Length</source> + <translation type="obsolete">Kurze Länge</translation> + </message> + <message> + <source>Low Level</source> + <translation type="obsolete">Niedriger Level</translation> + </message> + <message> + <source>High Level</source> + <translation type="obsolete">Hoher Level</translation> + </message> + <message> + <source>Downloading</source> + <translation type="obsolete">Herunterladen</translation> + </message> + <message> + <source>Uploading</source> + <translation type="obsolete">Hochladen</translation> + </message> + <message> + <source>Server Error</source> + <translation type="obsolete">Serverfehler</translation> + </message> + <message> + <source>Internal Error</source> + <translation type="obsolete">Interner Fehler</translation> + </message> + <message> + <source>Interrupted</source> + <translation type="obsolete">Unterbrochen</translation> + </message> + <message> + <source>Playing</source> + <translation type="obsolete">Abspielen</translation> + </message> + <message> + <source>Waiting</source> + <translation type="obsolete">Warten</translation> + </message> + <message> + <source>Device Busy</source> + <translation type="obsolete">Gerät beschäftigt</translation> + </message> + <message> + <source>No Such Cart/Cut</source> + <translation type="obsolete">Kein solcher Cart/Cut</translation> + </message> + <message> + <source>Unknown Audio Format</source> + <translation type="obsolete">Unbekanntes Audioformat</translation> + </message> +</context> +<context> + <name>RDReport</name> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation type="obsolete">CBSI DeltaFlex Traffic Reconciliation v2.01</translation> + </message> + <message> + <source>Text Log</source> + <translation type="obsolete">Text Log</translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation type="obsolete">ASCAP/BMI Electronic Music Report</translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation type="obsolete">Technical Playout Report</translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation type="obsolete">SoundExchange Statutory License Report</translation> + </message> + <message> + <source>Unknown</source> + <translation type="obsolete">Unbekannt</translation> + </message> + <message> + <source>Other</source> + <translation type="obsolete">Andere</translation> + </message> + <message> + <source>AM</source> + <translation type="obsolete">AM</translation> + </message> + <message> + <source>FM</source> + <translation type="obsolete">FM</translation> + </message> + <message> + <source>Report complete!</source> + <translation type="obsolete">Report vollständig!</translation> + </message> + <message> + <source>Report canceled!</source> + <translation type="obsolete">Report abgebrochen!</translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation type="obsolete">Kann Reportdatei nicht öffnen!</translation> + </message> + <message> + <source>RadioTraffic.com Traffic Reconciliation</source> + <translation type="obsolete">RadioTraffic.com Traffic Reconciliation</translation> + </message> + <message> + <source>VisualTraffic Reconciliation</source> + <translation type="obsolete">VisualTraffic Reconciliation</translation> + </message> + <message> + <source>CounterPoint Traffic Reconciliation</source> + <translation type="obsolete">CounterPoint Traffic Reconciliation</translation> + </message> + <message> + <source>Music1 Reconciliation</source> + <translation type="obsolete">Music1 Reconciliation</translation> + </message> +</context> +<context> + <name>RDSoundPanel</name> + <message> + <source>Play All</source> + <translation>alles spielen</translation> + </message> + <message> + <source>Play Hook</source> + <translation>Hook spielen</translation> + </message> + <message> + <source>Reset</source> + <translation>Zurücksetzen</translation> + </message> + <message> + <source>All</source> + <translation>Alles</translation> + </message> + <message> + <source>Setup</source> + <translation>setup</translation> + </message> + <message> + <source>Cart</source> + <translation>Cart</translation> + </message> + <message> + <source>Panel</source> + <translation>Panel</translation> + </message> +</context> +<context> + <name>RDSqlDatabaseStatus</name> + <message> + <source>Database connection restored.</source> + <translation>Datenbankverbindung wiederhergestellt.</translation> + </message> + <message> + <source>Database connection failed : </source> + <translation>Datenbankverbindung fehlgeschlagen:</translation> + </message> +</context> +<context> + <name>RDStereoMeter</name> + <message> + <source>L</source> + <translation>L</translation> + </message> + <message> + <source>R</source> + <translation>R</translation> + </message> + <message> + <source>CLIP</source> + <translation>CLIP</translation> + </message> +</context> +<context> + <name>RDSvc</name> + <message> + <source>The following events were not placed: +</source> + <translation>Die folgenen Events wurden nicht plaziert:</translation> + </message> + <message> + <source>[unknown cart]</source> + <translation>[unbekannter Cart]</translation> + </message> + <message> + <source>Event Fill Errors +</source> + <translation>Event-Füllfehler</translation> + </message> +</context> +</TS> diff --git a/lib/librd_es.ts b/lib/librd_es.ts new file mode 100644 index 00000000..e0b92a65 --- /dev/null +++ b/lib/librd_es.ts @@ -0,0 +1,2176 @@ +<!DOCTYPE TS><TS> +<context> + <name></name> + <message> + <source>UNKNOWN CUT</source> + <translation type="obsolete">AUDIO DESCONOCIDO</translation> + </message> +</context> +<context> + <name>@default</name> + <message> + <source>ALL</source> + <translation type="obsolete">TODO</translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <source>Couldn't initialize QSql driver!</source> + <translation>¡No pude inicializar el driver QSql!</translation> + </message> + <message> + <source>Couldn't open mySQL connection!</source> + <translation>¡No pude abrir la conexión mySQL!</translation> + </message> + <message> + <source>Sequentially</source> + <translation type="unfinished">Secuencialmente</translation> + </message> + <message> + <source>Randomly</source> + <translation type="unfinished">Aleatoriamente</translation> + </message> + <message> + <source>Unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Feature</source> + <translation type="unfinished">Característica</translation> + </message> + <message> + <source>Theme Open</source> + <translation type="unfinished">Entrada del tema</translation> + </message> + <message> + <source>Theme Close</source> + <translation type="unfinished">Salida del tema</translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation type="unfinished">Entrada/Salida</translation> + </message> + <message> + <source>Background</source> + <translation type="unfinished">Fondo</translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation type="unfinished">Comercial/Jingle/promo</translation> + </message> + <message> + <source>UNKNOWN CUT</source> + <translation type="unfinished">AUDIO DESCONOCIDO</translation> + </message> + <message> + <source>Manual</source> + <translation type="unfinished">Manual</translation> + </message> + <message> + <source>Play</source> + <translation type="unfinished">Reproducir</translation> + </message> + <message> + <source>Segue</source> + <translation type="unfinished">Segue</translation> + </message> + <message> + <source>Time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Panel</source> + <translation type="unfinished">Panel</translation> + </message> + <message> + <source>Macro</source> + <translation type="unfinished">Macro</translation> + </message> + <message> + <source>PLAY</source> + <translation type="unfinished">REPROD</translation> + </message> + <message> + <source>SEGUE</source> + <translation type="unfinished">SEGUE</translation> + </message> + <message> + <source>STOP</source> + <translation type="unfinished">DETENER</translation> + </message> + <message> + <source>UNKNOWN</source> + <translation type="unfinished">DESCONOCIDO</translation> + </message> + <message> + <source>Audio</source> + <translation type="unfinished">Audio</translation> + </message> + <message> + <source>Marker</source> + <translation>Marcador</translation> + </message> + <message> + <source>Open Bracket</source> + <translation>Abrir llave</translation> + </message> + <message> + <source>Close Bracket</source> + <translation>Cerrar llave</translation> + </message> + <message> + <source>ChainTo</source> + <translation type="unfinished">ChainTo</translation> + </message> + <message> + <source>Track</source> + <translation>Pista</translation> + </message> + <message> + <source>Link</source> + <translation>Enlace</translation> + </message> + <message> + <source>Traffic</source> + <translation>Tráfico</translation> + </message> + <message> + <source>Music</source> + <translation>Música</translation> + </message> + <message> + <source>RDLogManager</source> + <translation>RDLogManager</translation> + </message> + <message> + <source>Tracker</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Recording</source> + <translation type="unfinished">Grabación</translation> + </message> + <message> + <source>Macro Event</source> + <translation type="unfinished">Evento Macro</translation> + </message> + <message> + <source>Switch Event</source> + <translation type="unfinished">Suichear evento</translation> + </message> + <message> + <source>Playout</source> + <translation type="unfinished">Reproducción</translation> + </message> + <message> + <source>Download</source> + <translation type="unfinished">Descargar</translation> + </message> + <message> + <source>Upload</source> + <translation type="unfinished">Subir</translation> + </message> + <message> + <source>Ok</source> + <translation type="unfinished">Aceptar</translation> + </message> + <message> + <source>Short Length</source> + <translation type="unfinished">Mostrar longitud</translation> + </message> + <message> + <source>Low Level</source> + <translation type="unfinished">Bajo nivel</translation> + </message> + <message> + <source>High Level</source> + <translation type="unfinished">Alto nivel</translation> + </message> + <message> + <source>Downloading</source> + <translation type="unfinished">Descargando</translation> + </message> + <message> + <source>Uploading</source> + <translation type="unfinished">Subiendo</translation> + </message> + <message> + <source>Server Error</source> + <translation type="unfinished">Error de servidor</translation> + </message> + <message> + <source>Internal Error</source> + <translation type="unfinished">Error interno</translation> + </message> + <message> + <source>Interrupted</source> + <translation type="unfinished">Interrumpido</translation> + </message> + <message> + <source>Playing</source> + <translation type="unfinished">Sonando</translation> + </message> + <message> + <source>Waiting</source> + <translation type="unfinished">Esperando</translation> + </message> + <message> + <source>Device Busy</source> + <translation type="unfinished">Disposit. ocupado</translation> + </message> + <message> + <source>No Such Cart/Cut</source> + <translation type="unfinished">El audio no existe</translation> + </message> + <message> + <source>Unknown Audio Format</source> + <translation type="unfinished">Formado desconocido</translation> + </message> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation type="unfinished">Reconciliación de tráfico CBSI DeltaFlex v2.01</translation> + </message> + <message> + <source>Text Log</source> + <translation type="unfinished">Texto plano</translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation type="unfinished">Reporte musical electrónico ASCAP/BMI</translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation type="unfinished">Reporte técnico de reproducciones</translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation type="unfinished">Reporte de licencias SoundExchange</translation> + </message> + <message> + <source>RadioTraffic.com Traffic Reconciliation</source> + <translation type="unfinished">Reconciliación de tráfico RadioTraffic.com</translation> + </message> + <message> + <source>VisualTraffic Reconciliation</source> + <translation type="unfinished">Reconciliación VisualTraffic</translation> + </message> + <message> + <source>CounterPoint Traffic Reconciliation</source> + <translation type="unfinished">Reconciliación de tráfico CounterPoint</translation> + </message> + <message> + <source>Music1 Reconciliation</source> + <translation type="unfinished">Reconciliación Music1</translation> + </message> + <message> + <source>Other</source> + <translation>Otro</translation> + </message> + <message> + <source>AM</source> + <translation></translation> + </message> + <message> + <source>FM</source> + <translation></translation> + </message> + <message> + <source>Report complete!</source> + <translation>¡Reporte terminado!</translation> + </message> + <message> + <source>Report canceled!</source> + <translation>¡Reporte cancelado!</translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation>¡No es posible abrir el archivo de reporte!</translation> + </message> + <message> + <source>Music Summary</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>WideOrbit Traffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown Position</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Left</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Center</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Right</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Left</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Center</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Right</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NPR/DS SoundExchange Report</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 1</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel First Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 1 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 2 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Second Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Third Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fourth Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audition/Cue Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Channel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fifth and Later Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>invalid SQL or failed DB connection</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>All</source> + <translation type="unfinished">Todo</translation> + </message> + <message> + <source>Relative</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hard</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NaturalLog Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>LiveAssist</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Automatic</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Previous</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Classical Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>reserved</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAddCart</name> + <message> + <source>&Group:</source> + <translation>&Grupo:</translation> + </message> + <message> + <source>&New Cart Number:</source> + <translation>&Nro. de cartucho:</translation> + </message> + <message> + <source>&New Cart Type:</source> + <translation>&Tipo de cartucho:</translation> + </message> + <message> + <source>Audio</source> + <translation>Audio</translation> + </message> + <message> + <source>Macro</source> + <translation>Macro</translation> + </message> + <message> + <source>[new cart]</source> + <translation>[nuevo cartucho]</translation> + </message> + <message> + <source>&New Cart Title:</source> + <translation>&Título del cartucho:</translation> + </message> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>No Available Cart Numbers</source> + <translation>No hay números disponibles</translation> + </message> + <message> + <source>There are no more available cart numbers for the group!</source> + <translation>¡No hay más números de cartuchos disponibles en este grupo!</translation> + </message> + <message> + <source>Invalid Number</source> + <translation>Número inválido</translation> + </message> + <message> + <source>Invalid Cart Number!</source> + <translation>¡El número de cartucho es inválido!</translation> + </message> + <message> + <source>Title Required</source> + <translation>Título requerido</translation> + </message> + <message> + <source>You must enter a cart title!</source> + <translation>¡Debe suministrar un título para el cartucho!</translation> + </message> + <message> + <source>The cart number is outside of the permitted range for this group!</source> + <translation>¡Ha colocado un número del cartucho fuera del rango permitido para este grupo!</translation> + </message> + <message> + <source>Cart Exists</source> + <translation>El cartucho ya existe</translation> + </message> + <message> + <source>This cart already exists.</source> + <translation>Este cartucho ya existe.</translation> + </message> + <message> + <source>Duplicate Title</source> + <translation>Título duplicado</translation> + </message> + <message> + <source>The cart title must be unique!</source> + <translation>¡El título del cartucho debe ser único!</translation> + </message> +</context> +<context> + <name>RDAddLog</name> + <message> + <source>Create Log</source> + <translation>Crear playlist</translation> + </message> + <message> + <source>&New Log Name:</source> + <translation>&Nuevo nombre:</translation> + </message> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>RDLogEdit</source> + <translation>RDLogEdit</translation> + </message> + <message> + <source>The name is invalid!</source> + <translation type="obsolete">¡El nombre es inválido!</translation> + </message> + <message> + <source>&Service:</source> + <translation>&Servicio:</translation> + </message> + <message> + <source>The service is invalid!</source> + <translation>¡El servicio es inválido!</translation> + </message> +</context> +<context> + <name>RDAudioSettingsDialog</name> + <message> + <source>Edit Settings</source> + <translation>Editar parámetros</translation> + </message> + <message> + <source>Default &Format:</source> + <translation>Formato por &Omisión:</translation> + </message> + <message> + <source>Default &Channels:</source> + <translation>&Canales por omisión:</translation> + </message> + <message> + <source>Default &Sample Rate:</source> + <translation>&Sampleo por omisión:</translation> + </message> + <message> + <source>Default &Bitrate:</source> + <translation>&Tasa de bits por omisión:</translation> + </message> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>PCM16</source> + <translation>PCM16</translation> + </message> + <message> + <source>OggVorbis</source> + <translation>OggVorbis</translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation>MPEG Capa 2</translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation>MPEG Capa 3</translation> + </message> +</context> +<context> + <name>RDButtonDialog</name> + <message> + <source>Edit Button</source> + <translation>Editar botón</translation> + </message> + <message> + <source>Label:</source> + <translation>Etiq.:</translation> + </message> + <message> + <source>Cart:</source> + <translation>Cart.:</translation> + </message> + <message> + <source>Set +Cart</source> + <translation>Asignar +Cartucho</translation> + </message> + <message> + <source>Clear</source> + <translation>Limpiar</translation> + </message> + <message> + <source>Set +Color</source> + <translation>Asignar +Color</translation> + </message> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>NOT FOUND</source> + <translation>NO ENCONTRADO</translation> + </message> +</context> +<context> + <name>RDCardSelector</name> + <message> + <source>Card:</source> + <translation>Tarjeta:</translation> + </message> + <message> + <source>Port:</source> + <translation>Puerto:</translation> + </message> +</context> +<context> + <name>RDCart</name> + <message> + <source>Sequentially</source> + <translation type="obsolete">Secuencialmente</translation> + </message> + <message> + <source>Randomly</source> + <translation type="obsolete">Aleatoriamente</translation> + </message> + <message> + <source>Unknown</source> + <translation type="obsolete">Desconocida</translation> + </message> + <message> + <source>Feature</source> + <translation type="obsolete">Característica</translation> + </message> + <message> + <source>Theme Open</source> + <translation type="obsolete">Entrada del tema</translation> + </message> + <message> + <source>Theme Close</source> + <translation type="obsolete">Salida del tema</translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation type="obsolete">Entrada/Salida</translation> + </message> + <message> + <source>Background</source> + <translation type="obsolete">Fondo</translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation type="obsolete">Comercial/Jingle/promo</translation> + </message> +</context> +<context> + <name>RDCartDialog</name> + <message> + <source>Select Cart</source> + <translation>Elegir Cartucho</translation> + </message> + <message> + <source>Cart Filter:</source> + <translation>Filtrar:</translation> + </message> + <message> + <source>C&lear</source> + <translation>&Limpiar</translation> + </message> + <message> + <source>Group:</source> + <translation>Grupo:</translation> + </message> + <message> + <source>NUMBER</source> + <translation>NÚMERO</translation> + </message> + <message> + <source>LENGTH</source> + <translation>DURACIÓN</translation> + </message> + <message> + <source>TITLE</source> + <translation>TÍTULO</translation> + </message> + <message> + <source>ARTIST</source> + <translation>ARTISTA<byte value="x9"/></translation> + </message> + <message> + <source>CLIENT</source> + <translation>CLIENTE</translation> + </message> + <message> + <source>AGENCY</source> + <translation>AGENCIA</translation> + </message> + <message> + <source>USER DEF</source> + <translation>OTROS</translation> + </message> + <message> + <source>START</source> + <translation>INICIO</translation> + </message> + <message> + <source>END</source> + <translation>FIN</translation> + </message> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>ALL</source> + <translation>TODAS</translation> + </message> + <message> + <source>GROUP</source> + <translation>GRUPO</translation> + </message> + <message> + <source>Send to +&Editor</source> + <translation>Enviar al +&Editor</translation> + </message> + <message> + <source>&Search</source> + <translation>&Buscar</translation> + </message> + <message> + <source>Please Wait...</source> + <translation>Por favor, espere...</translation> + </message> + <message> + <source>Show Only First</source> + <translation>Mostrar los primeros</translation> + </message> + <message> + <source>Matches</source> + <translation>resultados</translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation>Cód. Programac.:</translation> + </message> + <message> + <source>Load From +&File</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cart Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to create temporary cart for import!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to get temporary cart number for import!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import Error</source> + <translation type="unfinished">Error importando</translation> + </message> + <message> + <source>Imported from</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Importing...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Importing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>COMPOSER</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CONDUCTOR</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEdit</name> + <message> + <source>&Audition</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Stop</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>End</source> + <translation type="unfinished">Final</translation> + </message> + <message> + <source>&Recue</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEditDialog</name> + <message> + <source>Set Cue Point</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished">&Cancelar</translation> + </message> +</context> +<context> + <name>RDCutDialog</name> + <message> + <source>Select Cut</source> + <translation>Seleccione audio</translation> + </message> + <message> + <source>Cart Filter:</source> + <translation>Filtro:</translation> + </message> + <message> + <source>C&lear</source> + <translation>&Limpiar</translation> + </message> + <message> + <source>Group:</source> + <translation>Grupo:</translation> + </message> + <message> + <source>Carts</source> + <translation>Cartuchos</translation> + </message> + <message> + <source>NUMBER</source> + <translation>NÚMERO</translation> + </message> + <message> + <source>TITLE</source> + <translation>TÍTULO</translation> + </message> + <message> + <source>Cuts</source> + <translation>Audios</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>DESCRIPCIÓN</translation> + </message> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>ALL</source> + <translation></translation> + </message> + <message> + <source>&Clear</source> + <translation>&Limpiar</translation> + </message> + <message> + <source>&Add New +Cart</source> + <translation>&Añadir +Cartucho</translation> + </message> + <message> + <source>GROUP</source> + <translation>GRUPO</translation> + </message> + <message> + <source>Please Wait...</source> + <translation>Espere...</translation> + </message> + <message> + <source>&Search</source> + <translation>&Buscar</translation> + </message> + <message> + <source>Show Only First</source> + <translation>Mostrar los primeros</translation> + </message> + <message> + <source>Matches</source> + <translation>resultados</translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation>Cód. Programac.:</translation> + </message> +</context> +<context> + <name>RDDateDialog</name> + <message> + <source>Select Date</source> + <translation>Seleccione la fecha</translation> + </message> + <message> + <source>&OK</source> + <translation>Acepta&r</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> +</context> +<context> + <name>RDDatePicker</name> + <message> + <source>Mo</source> + <translation>Lu</translation> + </message> + <message> + <source>Tu</source> + <translation>Ma</translation> + </message> + <message> + <source>We</source> + <translation>Mi</translation> + </message> + <message> + <source>Th</source> + <translation>Ju</translation> + </message> + <message> + <source>Fr</source> + <translation>Vi</translation> + </message> + <message> + <source>Sa</source> + <translation>Sá</translation> + </message> + <message> + <source>Su</source> + <translation>Do</translation> + </message> +</context> +<context> + <name>RDEditAudio</name> + <message> + <source>&Save</source> + <translation>&Guardar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>Amplitude</source> + <translation>Amplitud</translation> + </message> + <message> + <source>Zoom +In</source> + <translation>Acercar +Zoom</translation> + </message> + <message> + <source>Zoom +Out</source> + <translation>Alejar +Zoom</translation> + </message> + <message> + <source>Time</source> + <translation>Tiemp</translation> + </message> + <message> + <source>Full +In</source> + <translation>Acercar +Máximo</translation> + </message> + <message> + <source>Full +Out</source> + <translation>Ver +Todo</translation> + </message> + <message> + <source>Goto</source> + <translation>Ir a</translation> + </message> + <message> + <source>Cursor</source> + <translation>Cursor</translation> + </message> + <message> + <source>Home</source> + <translation>Principio</translation> + </message> + <message> + <source>End</source> + <translation>Final</translation> + </message> + <message> + <source>Cut +Start</source> + <translation>Inicio del +audio</translation> + </message> + <message> + <source>Cut +End</source> + <translation>Fin del +audio</translation> + </message> + <message> + <source>Talk +Start</source> + <translation>Inicio +Hablar</translation> + </message> + <message> + <source>Segue +Start</source> + <translation>Inicio +Segue</translation> + </message> + <message> + <source>Segue +End</source> + <translation>Fin +Segue</translation> + </message> + <message> + <source>Fade +Up</source> + <translation>Fade +entrada</translation> + </message> + <message> + <source>Hook +Start</source> + <translation>Inicio +Hook</translation> + </message> + <message> + <source>Hook +End</source> + <translation>Fin +Hook</translation> + </message> + <message> + <source> dB</source> + <translation> dB</translation> + </message> + <message> + <source>Threshold</source> + <translation>Nivel</translation> + </message> + <message> + <source>Trim +Start</source> + <translation>Inicio +Recorte</translation> + </message> + <message> + <source>Trim +End</source> + <translation>Fin del +recorte</translation> + </message> + <message> + <source>Cut Gain</source> + <translation>Ganancia +del audio</translation> + </message> + <message> + <source>Remove +Marker</source> + <translation>Eliminar +marcador</translation> + </message> + <message> + <source>Position</source> + <translation>Posición</translation> + </message> + <message> + <source>Length</source> + <translation>Longitud</translation> + </message> + <message> + <source>Delete Talk Markers</source> + <translation>Eliminar marcadores de hablar</translation> + </message> + <message> + <source>Delete Segue Markers</source> + <translation>Eliminar marcadores Segue</translation> + </message> + <message> + <source>Delete Hook Markers</source> + <translation>Eliminar marcadores Hook</translation> + </message> + <message> + <source>Delete Fade Up Marker</source> + <translation>Eliminar marcador Fade entrada</translation> + </message> + <message> + <source>Delete Fade Down Marker</source> + <translation>Eliminar marcador Fade salida</translation> + </message> + <message> + <source>dB</source> + <translation>dB</translation> + </message> + <message> + <source><none></source> + <translation><ninguno></translation> + </message> + <message> + <source>Cut</source> + <translation>Cortar</translation> + </message> + <message> + <source>Talk</source> + <translation>Hablar</translation> + </message> + <message> + <source>Segue</source> + <translation>Segue</translation> + </message> + <message> + <source>Hook</source> + <translation>Hook</translation> + </message> + <message> + <source>Fade Up</source> + <translation>Fade de entrada</translation> + </message> + <message> + <source>Fade Down</source> + <translation>Fade de salida</translation> + </message> + <message> + <source>L</source> + <translation>Iz</translation> + </message> + <message> + <source>R</source> + <translation>De</translation> + </message> + <message> + <source>No Fade on Segue Out</source> + <translation>Quitar fade en Segue</translation> + </message> + <message> + <source>Rivendell Web Service</source> + <translation>Servicio web Rivendell</translation> + </message> + <message> + <source>Unable to download peak data, error was: +"</source> + <translation>No fue posible descargar datos de picos, el error fue: +"</translation> + </message> + <message> + <source>Edit Audio</source> + <translation>Editar Audio</translation> + </message> + <message> + <source>Marker Warning</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Less than half of the audio is playable with these marker settings. +Are you sure you want to save?</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>More than half of the audio will be faded with these marker settings. +Are you sure you want to save?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDEditPanelName</name> + <message> + <source>Edit Panel Name</source> + <translation>Editar nombre del panel</translation> + </message> + <message> + <source>Panel &Name:</source> + <translation>&Nombre del panel:</translation> + </message> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> +</context> +<context> + <name>RDExceptionDialog</name> + <message> + <source>Rivendell Exception Report</source> + <translation>Reporte de excepciones</translation> + </message> + <message> + <source>&Save</source> + <translation>&Guardar</translation> + </message> + <message> + <source>&Close</source> + <translation>&Cerrar</translation> + </message> + <message> + <source>Text (*.txt *.TXT) +All Files (*.*)</source> + <translation>Texto (*.txt *.TXT) +Todos los archivos (*.*)</translation> + </message> + <message> + <source>Export File</source> + <translation>Exportar archivo</translation> + </message> + <message> + <source>The file</source> + <translation>El archivo </translation> + </message> + <message> + <source>already exists! +Overwrite?</source> + <translation>ya existe. +¿Sobreescribir?</translation> + </message> + <message> + <source>File Exists</source> + <translation>El archivo ya existe</translation> + </message> + <message> + <source>Unable to open file</source> + <translation>¡No es posible abrir el archivo</translation> + </message> + <message> + <source>for writing!</source> + <translation>para escritura!</translation> + </message> + <message> + <source>File Error</source> + <translation>Error de archivo</translation> + </message> +</context> +<context> + <name>RDExportSettingsDialog</name> + <message> + <source>Edit Export Settings</source> + <translation>Editar parám. exportación</translation> + </message> + <message> + <source>&Channels:</source> + <translation>&Canales:</translation> + </message> + <message> + <source>&Sample Rate:</source> + <translation>Tasa de &Muestreo:</translation> + </message> + <message> + <source>&Bitrate:</source> + <translation>&Tasa de bits:</translation> + </message> + <message> + <source>&Quality:</source> + <translation>&Calidad:</translation> + </message> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>PCM16</source> + <translation>PCM16</translation> + </message> + <message> + <source>FLAC</source> + <translation>FLAC</translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation>MPEG Capa 2</translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation>MPEG Capa 3</translation> + </message> + <message> + <source>OggVorbis</source> + <translation>OggVorbis</translation> + </message> + <message> + <source>VBR</source> + <translation>VBR</translation> + </message> + <message> + <source>32 kbps</source> + <translation></translation> + </message> + <message> + <source>64 kbps</source> + <translation></translation> + </message> + <message> + <source>96 kbps</source> + <translation></translation> + </message> + <message> + <source>128 kbps</source> + <translation></translation> + </message> + <message> + <source>160 kbps</source> + <translation></translation> + </message> + <message> + <source>192 kbps</source> + <translation></translation> + </message> + <message> + <source>224 kbps</source> + <translation></translation> + </message> + <message> + <source>256 kbps</source> + <translation></translation> + </message> + <message> + <source>288 kbps</source> + <translation></translation> + </message> + <message> + <source>320 kbps</source> + <translation></translation> + </message> + <message> + <source>352 kbps</source> + <translation></translation> + </message> + <message> + <source>384 kbps</source> + <translation></translation> + </message> + <message> + <source>416 kbps</source> + <translation></translation> + </message> + <message> + <source>448 kbps</source> + <translation></translation> + </message> + <message> + <source>48 kbps</source> + <translation></translation> + </message> + <message> + <source>56 kbps</source> + <translation></translation> + </message> + <message> + <source>80 kbps</source> + <translation></translation> + </message> + <message> + <source>112 kbps</source> + <translation></translation> + </message> + <message> + <source>40 kbps</source> + <translation></translation> + </message> + <message> + <source>8 kbps</source> + <translation></translation> + </message> + <message> + <source>16 kbps</source> + <translation></translation> + </message> + <message> + <source>24 kbps</source> + <translation></translation> + </message> + <message> + <source>144 kbps</source> + <translation></translation> + </message> +</context> +<context> + <name>RDGetAth</name> + <message> + <source>ATH:</source> + <translation>ATH:</translation> + </message> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>Enter ATH</source> + <translation>Introduzca ATH</translation> + </message> + <message> + <source>Enter the agreggate tuning hours (ATH) +figure for the report period. +(Supplied by your streaming provider).</source> + <translation>Introduzca las horas de sintonización (ATH) +para el período a reportar. +(Suministrado por su proveedor de streaming).</translation> + </message> + <message> + <source>Invalid ATH</source> + <translation>ATH inválido</translation> + </message> + <message> + <source>You must provide a valid ATH figure!</source> + <translation>¡Usted debe proveer una figura ATH válida!</translation> + </message> +</context> +<context> + <name>RDGetPasswd</name> + <message> + <source>Enter password</source> + <translation>Introduzca clave</translation> + </message> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>Enter Password</source> + <translation>Introduzca la clave</translation> + </message> +</context> +<context> + <name>RDGpioSelector</name> + <message> + <source>Pin:</source> + <translation>Pin:</translation> + </message> +</context> +<context> + <name>RDImportAudio</name> + <message> + <source>Import/Export Audio File</source> + <translation>Importar/Exportar audio</translation> + </message> + <message> + <source>Import File</source> + <translation>Importar Archivo</translation> + </message> + <message> + <source>Filename:</source> + <translation>Archivo:</translation> + </message> + <message> + <source>&Select</source> + <translation>&Seleccionar</translation> + </message> + <message> + <source>Import file metadata</source> + <translation>Importar metadatos</translation> + </message> + <message> + <source>Channels:</source> + <translation>Canales:</translation> + </message> + <message> + <source>Autotrim</source> + <translation>Autorecortar</translation> + </message> + <message> + <source>Level:</source> + <translation>Nivel:</translation> + </message> + <message> + <source>dBFS</source> + <translation>dBFS</translation> + </message> + <message> + <source>Export File</source> + <translation>Exportar archivo</translation> + </message> + <message> + <source>Export file metadata</source> + <translation>Exportar metadatos</translation> + </message> + <message> + <source>Format:</source> + <translation>Formato:</translation> + </message> + <message> + <source>S&et</source> + <translation>&Asignar</translation> + </message> + <message> + <source>Normalize</source> + <translation>Normalizar</translation> + </message> + <message> + <source>&Import</source> + <translation>&Importar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>Export</source> + <translation>Exportar</translation> + </message> + <message> + <source>Import</source> + <translation>Importar</translation> + </message> + <message> + <source>Unable to open the file for writing!</source> + <translation type="obsolete">¡No es posible escribir en el archivo!</translation> + </message> + <message> + <source>Import Complete</source> + <translation>Importación finalizada</translation> + </message> + <message> + <source>Import complete!</source> + <translation>¡Importación finalizada!</translation> + </message> + <message> + <source>Import Aborted</source> + <translation type="obsolete">Importación cancelada</translation> + </message> + <message> + <source>The import has been aborted.</source> + <translation type="obsolete">La importación ha sido abortada.</translation> + </message> + <message> + <source>Import Failed</source> + <translation type="obsolete">Falló la importación</translation> + </message> + <message> + <source>The importer encountered an error. +Please check your importer configuration and try again.</source> + <translation type="obsolete">El importador de audio encontró un error. +Revise la configuración e intente de nuevo.</translation> + </message> + <message> + <source>File Exists</source> + <translation>El archivo ya existe</translation> + </message> + <message> + <source>The selected file already exists! +Do you want to overwrite it?</source> + <translation>¡El archivo seleccionado ya existe! +¿Desea sobreescribirlo?</translation> + </message> + <message> + <source>File Error</source> + <translation type="obsolete">Error de archivo</translation> + </message> + <message> + <source>Cannot open file in archive!</source> + <translation type="obsolete">¡No puedo abrir el archivo!</translation> + </message> + <message> + <source>Unsupported file type in archive!</source> + <translation type="obsolete">¡Tipo de audio no soportado!</translation> + </message> + <message> + <source>Export Complete</source> + <translation>Exportación finalizada</translation> + </message> + <message> + <source>Export complete!</source> + <translation>¡Exportación finalizada!</translation> + </message> + <message> + <source>Export Aborted</source> + <translation type="obsolete">Exportación cancelada</translation> + </message> + <message> + <source>The export has been aborted.</source> + <translation type="obsolete">Se ha abortado la exportación.</translation> + </message> + <message> + <source>Export Failed</source> + <translation type="obsolete">Fallo en la exportación</translation> + </message> + <message> + <source>The Exporter encountered an error. +Please check your configuration and try again.</source> + <translation type="obsolete">El exportador de audio encontró un error. +Revise la configuración e inténtelo de nuevo.</translation> + </message> + <message> + <source>No Access</source> + <translation type="obsolete">Sin acceso</translation> + </message> + <message> + <source>OK</source> + <translation type="obsolete">Aceptar</translation> + </message> + <message> + <source>Import Audio File</source> + <translation>Importar archivo de audio</translation> + </message> + <message> + <source>File does not exist!</source> + <translation>¡El archivo no existe!</translation> + </message> + <message> + <source>Cannot open file!</source> + <translation type="obsolete">No puedo abrir el archivo!</translation> + </message> + <message> + <source>Unsupported file type!</source> + <translation type="obsolete">¡Tipo de audio no soportado!</translation> + </message> + <message> + <source>Audio Exists</source> + <translation type="obsolete">El audio existe</translation> + </message> + <message> + <source>This will overwrite the existing recording. +Do you want to proceed?</source> + <translation type="obsolete">Esta acción sobreescribirá la grabación existente. +¿Desea continuar?</translation> + </message> + <message> + <source>Empty Clipboard</source> + <translation type="obsolete">Vaciar portapapeles</translation> + </message> + <message> + <source>Importing this cut will also empty the clipboard. +Do you still want to proceed?</source> + <translation type="obsolete">Importar este audio vaciará el portapapeles. +¿Desea continuar?</translation> + </message> + <message> + <source>Export Error</source> + <translation>Error exportando</translation> + </message> + <message> + <source>Import Error</source> + <translation>Error importando</translation> + </message> + <message> + <source>Abort</source> + <translation>Abortar</translation> + </message> +</context> +<context> + <name>RDIntegerDialog</name> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>Set Value</source> + <translation>Asignar valor</translation> + </message> +</context> +<context> + <name>RDIntegerEdit</name> + <message> + <source>Add</source> + <translation>Añadir</translation> + </message> + <message> + <source>Delete</source> + <translation>Borrar</translation> + </message> + <message> + <source>Set Value</source> + <translation>Colocar valor</translation> + </message> +</context> +<context> + <name>RDLicense</name> + <message> + <source>&Close</source> + <translation>&Cerrar</translation> + </message> + <message> + <source>GNU Public License v2</source> + <translation>Licencia Pública GNU v2</translation> + </message> +</context> +<context> + <name>RDListGroups</name> + <message> + <source>Select Group</source> + <translation>Seleccionar grupo</translation> + </message> + <message> + <source>NAME</source> + <translation>NOMBRE</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>DESCRIPCIÓN</translation> + </message> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> +</context> +<context> + <name>RDListLogs</name> + <message> + <source>Select Log - User: </source> + <translation>Seleccionar Playlist - Usuario: </translation> + </message> + <message> + <source>Select Log</source> + <translation>Seleccionar Playlist</translation> + </message> + <message> + <source>NAME</source> + <translation>NOMBRE</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>DESCRIPCIÓN</translation> + </message> + <message> + <source>SERVICE</source> + <translation>SERVICIO</translation> + </message> + <message> + <source>OK</source> + <translation>ACEPTAR</translation> + </message> + <message> + <source>Cancel</source> + <translation>Cancelar</translation> + </message> +</context> +<context> + <name>RDListSelector</name> + <message> + <source>Available Services</source> + <translation>Servicios disponibles</translation> + </message> + <message> + <source>Add >></source> + <translation>Añadir >></translation> + </message> + <message> + <source><< Remove</source> + <translation><< Remover</translation> + </message> + <message> + <source>Active Services</source> + <translation>Servicios Activos</translation> + </message> +</context> +<context> + <name>RDLogLine</name> + <message> + <source>Unknown</source> + <translation type="obsolete">Desconocido</translation> + </message> + <message> + <source>Manual</source> + <translation type="obsolete">Manual</translation> + </message> + <message> + <source>Play</source> + <translation type="obsolete">Reproducir</translation> + </message> + <message> + <source>Segue</source> + <translation type="obsolete">Segue</translation> + </message> + <message> + <source>Time</source> + <translation type="obsolete">Tiempo</translation> + </message> + <message> + <source>Panel</source> + <translation type="obsolete">Panel</translation> + </message> + <message> + <source>Macro</source> + <translation type="obsolete">Macro</translation> + </message> + <message> + <source>PLAY</source> + <translation type="obsolete">REPROD</translation> + </message> + <message> + <source>SEGUE</source> + <translation type="obsolete">SEGUE</translation> + </message> + <message> + <source>STOP</source> + <translation type="obsolete">DETENER</translation> + </message> + <message> + <source>UNKNOWN</source> + <translation type="obsolete">DESCONOCIDO</translation> + </message> + <message> + <source>Audio</source> + <translation type="obsolete">Audio</translation> + </message> + <message> + <source>Marker</source> + <translation type="obsolete">Marcador</translation> + </message> + <message> + <source>Open Bracket</source> + <translation type="obsolete">Abrir llave</translation> + </message> + <message> + <source>Close Bracket</source> + <translation type="obsolete">Cerrar llave</translation> + </message> + <message> + <source>ChainTo</source> + <translation type="obsolete">ChainTo</translation> + </message> + <message> + <source>Track</source> + <translation type="obsolete">Pista</translation> + </message> + <message> + <source>Link</source> + <translation type="obsolete">Enlace</translation> + </message> + <message> + <source>Traffic</source> + <translation type="obsolete">Tráfico</translation> + </message> + <message> + <source>Music</source> + <translation type="obsolete">Música</translation> + </message> + <message> + <source>RDLogManager</source> + <translation type="obsolete">RDLogManager</translation> + </message> +</context> +<context> + <name>RDPanelButton</name> + <message> + <source>No Audio</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDPasswd</name> + <message> + <source>Change Password</source> + <translation>Cambiar contraseña</translation> + </message> + <message> + <source>&OK</source> + <translation>&Aceptar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>&Password:</source> + <translation>&Contraseña:</translation> + </message> + <message> + <source>C&onfirm:</source> + <translation>C&onfirmar:</translation> + </message> + <message> + <source>Password Mismatch</source> + <translation>Las claves no concuerdan</translation> + </message> + <message> + <source>The passwords don't match, +please try again!</source> + <translation>Las contraseñas difieren entre sí, +¡inténtelo de nuevo!</translation> + </message> + <message> + <source>OK</source> + <translation>Aceptar</translation> + </message> +</context> +<context> + <name>RDRecording</name> + <message> + <source>Recording</source> + <translation type="obsolete">Grabación</translation> + </message> + <message> + <source>Macro Event</source> + <translation type="obsolete">Evento Macro</translation> + </message> + <message> + <source>Switch Event</source> + <translation type="obsolete">Suichear evento</translation> + </message> + <message> + <source>Playout</source> + <translation type="obsolete">Reproducción</translation> + </message> + <message> + <source>Download</source> + <translation type="obsolete">Descargar</translation> + </message> + <message> + <source>Upload</source> + <translation type="obsolete">Subir</translation> + </message> + <message> + <source>Ok</source> + <translation type="obsolete">Aceptar</translation> + </message> + <message> + <source>Short Length</source> + <translation type="obsolete">Mostrar longitud</translation> + </message> + <message> + <source>Low Level</source> + <translation type="obsolete">Bajo nivel</translation> + </message> + <message> + <source>High Level</source> + <translation type="obsolete">Alto nivel</translation> + </message> + <message> + <source>Downloading</source> + <translation type="obsolete">Descargando</translation> + </message> + <message> + <source>Uploading</source> + <translation type="obsolete">Subiendo</translation> + </message> + <message> + <source>Server Error</source> + <translation type="obsolete">Error de servidor</translation> + </message> + <message> + <source>Internal Error</source> + <translation type="obsolete">Error interno</translation> + </message> + <message> + <source>Interrupted</source> + <translation type="obsolete">Interrumpido</translation> + </message> + <message> + <source>Playing</source> + <translation type="obsolete">Sonando</translation> + </message> + <message> + <source>Waiting</source> + <translation type="obsolete">Esperando</translation> + </message> + <message> + <source>Device Busy</source> + <translation type="obsolete">Disposit. ocupado</translation> + </message> + <message> + <source>No Such Cart/Cut</source> + <translation type="obsolete">El audio no existe</translation> + </message> + <message> + <source>Unknown Audio Format</source> + <translation type="obsolete">Formado desconocido</translation> + </message> +</context> +<context> + <name>RDReport</name> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation type="obsolete">Reconciliación de tráfico CBSI DeltaFlex v2.01</translation> + </message> + <message> + <source>Text Log</source> + <translation type="obsolete">Texto plano</translation> + </message> + <message> + <source>Unknown</source> + <translation type="obsolete">Desconocido</translation> + </message> + <message> + <source>Other</source> + <translation type="obsolete">Otro</translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation type="obsolete">Reporte musical electrónico ASCAP/BMI</translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation type="obsolete">Reporte técnico de reproducciones</translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation type="obsolete">Reporte de licencias SoundExchange</translation> + </message> + <message> + <source>Report complete!</source> + <translation type="obsolete">¡Reporte terminado!</translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation type="obsolete">¡No es posible abrir el archivo de reporte!</translation> + </message> + <message> + <source>Report canceled!</source> + <translation type="obsolete">¡Reporte cancelado!</translation> + </message> + <message> + <source>RadioTraffic.com Traffic Reconciliation</source> + <translation type="obsolete">Reconciliación de tráfico RadioTraffic.com</translation> + </message> + <message> + <source>VisualTraffic Reconciliation</source> + <translation type="obsolete">Reconciliación VisualTraffic</translation> + </message> + <message> + <source>CounterPoint Traffic Reconciliation</source> + <translation type="obsolete">Reconciliación de tráfico CounterPoint</translation> + </message> + <message> + <source>Music1 Reconciliation</source> + <translation type="obsolete">Reconciliación Music1</translation> + </message> +</context> +<context> + <name>RDSoundPanel</name> + <message> + <source>Setup</source> + <translation>Configurar</translation> + </message> + <message> + <source>Cart</source> + <translation>Cartucho</translation> + </message> + <message> + <source>Reset</source> + <translation>Reiniciar</translation> + </message> + <message> + <source>Panel</source> + <translation>Panel</translation> + </message> + <message> + <source>Play All</source> + <translation>Completa</translation> + </message> + <message> + <source>Play Hook</source> + <translation>Sólo "hook"</translation> + </message> + <message> + <source>All</source> + <translation>Todo</translation> + </message> +</context> +<context> + <name>RDSqlDatabaseStatus</name> + <message> + <source>Database connection restored.</source> + <translation>Se recuperó la conexión a la base de datos.</translation> + </message> + <message> + <source>Database connection failed : </source> + <translation>Falló la conexión a la base de datos : </translation> + </message> +</context> +<context> + <name>RDStereoMeter</name> + <message> + <source>L</source> + <translation>Iz</translation> + </message> + <message> + <source>R</source> + <translation>De</translation> + </message> + <message> + <source>CLIP</source> + <translation>CLIP</translation> + </message> +</context> +<context> + <name>RDSvc</name> + <message> + <source>The following events were not placed: +</source> + <translation>Los siguientes eventos no fueron colocados: +</translation> + </message> + <message> + <source>[unknown cart]</source> + <translation>[cartucho desconocido]</translation> + </message> + <message> + <source>Event Fill Errors +</source> + <translation>Errores al llenar eventos +</translation> + </message> +</context> +</TS> diff --git a/lib/librd_fr.ts b/lib/librd_fr.ts new file mode 100644 index 00000000..87735963 --- /dev/null +++ b/lib/librd_fr.ts @@ -0,0 +1,1773 @@ +<!DOCTYPE TS><TS> +<context> + <name>QObject</name> + <message> + <source>Couldn't initialize QSql driver!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Couldn't open mySQL connection!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sequentially</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Randomly</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Feature</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Theme Open</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Theme Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Background</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>UNKNOWN CUT</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Manual</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Play</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Segue</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Panel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Macro</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>PLAY</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>SEGUE</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>STOP</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>UNKNOWN</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Marker</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Open Bracket</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Close Bracket</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>ChainTo</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Track</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Link</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Traffic</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>RDLogManager</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Tracker</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Recording</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Macro Event</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Switch Event</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Download</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Upload</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Ok</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Short Length</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Low Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>High Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Downloading</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Uploading</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Server Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Internal Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Interrupted</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Playing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Waiting</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Device Busy</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>No Such Cart/Cut</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown Audio Format</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Text Log</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>RadioTraffic.com Traffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>VisualTraffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CounterPoint Traffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music1 Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Other</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>AM</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>FM</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Report complete!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Report canceled!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music Summary</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>WideOrbit Traffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown Position</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Left</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Center</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Right</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Left</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Center</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Right</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NPR/DS SoundExchange Report</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 1</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel First Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 1 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 2 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Second Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Third Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fourth Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audition/Cue Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Channel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fifth and Later Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>invalid SQL or failed DB connection</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>All</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Relative</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hard</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NaturalLog Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>LiveAssist</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Automatic</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Previous</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Classical Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>reserved</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAddCart</name> + <message> + <source>&Group:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&New Cart Number:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&New Cart Type:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Macro</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>[new cart]</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&New Cart Title:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>No Available Cart Numbers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>There are no more available cart numbers for the group!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Invalid Number</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Invalid Cart Number!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Title Required</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>You must enter a cart title!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>The cart number is outside of the permitted range for this group!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cart Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>This cart already exists.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Duplicate Title</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>The cart title must be unique!</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAddLog</name> + <message> + <source>Create Log</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&New Log Name:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Service:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>RDLogEdit</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>The service is invalid!</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAudioSettingsDialog</name> + <message> + <source>Edit Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Default &Format:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Default &Channels:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Default &Sample Rate:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Default &Bitrate:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>PCM16</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>OggVorbis</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDButtonDialog</name> + <message> + <source>Edit Button</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Label:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cart:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Set +Cart</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Clear</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Set +Color</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NOT FOUND</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCardSelector</name> + <message> + <source>Card:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Port:</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCartDialog</name> + <message> + <source>Select Cart</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Please Wait...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cart Filter:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Search</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>C&lear</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Group:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NUMBER</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>LENGTH</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>TITLE</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>ARTIST</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>GROUP</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CLIENT</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>AGENCY</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>USER DEF</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>START</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>END</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Send to +&Editor</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>ALL</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Show Only First</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Matches</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Load From +&File</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cart Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to create temporary cart for import!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to get temporary cart number for import!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Imported from</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Importing...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Importing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>COMPOSER</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CONDUCTOR</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEdit</name> + <message> + <source>&Audition</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Stop</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>End</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Recue</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEditDialog</name> + <message> + <source>Set Cue Point</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCutDialog</name> + <message> + <source>Select Cut</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Please Wait...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cart Filter:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Search</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>C&lear</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Group:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Carts</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NUMBER</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>TITLE</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>GROUP</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cuts</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Add New +Cart</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Clear</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>ALL</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Show Only First</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Matches</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDDateDialog</name> + <message> + <source>Select Date</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDDatePicker</name> + <message> + <source>Mo</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Tu</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>We</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Th</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Fr</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sa</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Su</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDEditAudio</name> + <message> + <source>&Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Amplitude</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Zoom +In</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Zoom +Out</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Full +In</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Full +Out</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Goto</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cursor</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Home</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>End</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cut +Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cut +End</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Talk +Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Segue +Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Segue +End</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Fade +Up</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hook +Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hook +End</source> + <translation type="unfinished"></translation> + </message> + <message> + <source> dB</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Threshold</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Trim +Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Trim +End</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cut Gain</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Remove +Marker</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>No Fade on Segue Out</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Position</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Length</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Delete Talk Markers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Delete Segue Markers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Delete Hook Markers</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Delete Fade Up Marker</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Delete Fade Down Marker</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>dB</source> + <translation type="unfinished"></translation> + </message> + <message> + <source><none></source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cut</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Talk</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Segue</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hook</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Fade Up</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Fade Down</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>L</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>R</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Rivendell Web Service</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to download peak data, error was: +"</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Edit Audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Marker Warning</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Less than half of the audio is playable with these marker settings. +Are you sure you want to save?</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>More than half of the audio will be faded with these marker settings. +Are you sure you want to save?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDEditPanelName</name> + <message> + <source>Edit Panel Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Panel &Name:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDExceptionDialog</name> + <message> + <source>Rivendell Exception Report</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Save</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Text (*.txt *.TXT) +All Files (*.*)</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Export File</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>The file</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>already exists! +Overwrite?</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>File Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to open file</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>for writing!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>File Error</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDExportSettingsDialog</name> + <message> + <source>Edit Export Settings</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Channels:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Sample Rate:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Bitrate:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Quality:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>PCM16</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>FLAC</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>OggVorbis</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>VBR</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>32 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>64 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>96 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>128 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>160 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>192 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>224 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>256 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>288 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>320 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>352 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>384 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>416 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>448 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>48 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>56 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>80 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>112 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>40 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>8 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>16 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>24 kbps</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>144 kbps</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDGetAth</name> + <message> + <source>Enter ATH</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enter the agreggate tuning hours (ATH) +figure for the report period. +(Supplied by your streaming provider).</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>ATH:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Invalid ATH</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>You must provide a valid ATH figure!</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDGetPasswd</name> + <message> + <source>Enter Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Enter password</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDGpioSelector</name> + <message> + <source>Pin:</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDImportAudio</name> + <message> + <source>Import/Export Audio File</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import File</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Filename:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Select</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import file metadata</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Channels:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Autotrim</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Level:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>dBFS</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Export File</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Export file metadata</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Format:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>S&et</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Normalize</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Import</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Export</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import Audio File</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>File does not exist!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import Complete</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import complete!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>File Exists</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>The selected file already exists! +Do you want to overwrite it?</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Export Complete</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Export complete!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Export Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Abort</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDIntegerDialog</name> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Set Value</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDIntegerEdit</name> + <message> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Set Value</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDLicense</name> + <message> + <source>&Close</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>GNU Public License v2</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDListGroups</name> + <message> + <source>Select Group</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NAME</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDListLogs</name> + <message> + <source>Select Log - User: </source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Select Log</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NAME</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>SERVICE</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDListSelector</name> + <message> + <source>Available Services</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Add >></source> + <translation type="unfinished"></translation> + </message> + <message> + <source><< Remove</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Active Services</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDPanelButton</name> + <message> + <source>No Audio</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDPasswd</name> + <message> + <source>Change Password</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Password:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>C&onfirm:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Password Mismatch</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>The passwords don't match, +please try again!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>OK</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDSoundPanel</name> + <message> + <source>Play All</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Play Hook</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Reset</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>All</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Setup</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cart</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Panel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDSqlDatabaseStatus</name> + <message> + <source>Database connection restored.</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Database connection failed : </source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDStereoMeter</name> + <message> + <source>L</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>R</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CLIP</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDSvc</name> + <message> + <source>The following events were not placed: +</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>[unknown cart]</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Event Fill Errors +</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/lib/librd_nb.ts b/lib/librd_nb.ts new file mode 100644 index 00000000..aaae0b4e --- /dev/null +++ b/lib/librd_nb.ts @@ -0,0 +1,2121 @@ +<!DOCTYPE TS><TS> +<context> + <name></name> + <message> + <source>UNKNOWN CUT</source> + <translation type="obsolete">UKJENT KLYPP</translation> + </message> +</context> +<context> + <name>@default</name> + <message> + <source>ALL</source> + <translation type="obsolete">ALLE</translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <source>Couldn't initialize QSql driver!</source> + <translation>Greidde ikkje setja opp QSql-drivaren!</translation> + </message> + <message> + <source>Couldn't open mySQL connection!</source> + <translation>Greidde ikkje kopla til mySQL-databasen!</translation> + </message> + <message> + <source>Sequentially</source> + <translation type="unfinished">I rekkjefylgje</translation> + </message> + <message> + <source>Randomly</source> + <translation type="unfinished">Tilfeldig</translation> + </message> + <message> + <source>Unknown</source> + <translation type="unfinished">Ukjent</translation> + </message> + <message> + <source>Feature</source> + <translation type="unfinished">Eigenskap</translation> + </message> + <message> + <source>Theme Open</source> + <translation type="unfinished">Opningsvignett</translation> + </message> + <message> + <source>Theme Close</source> + <translation type="unfinished">Sluttvignett</translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation type="unfinished">Opnings/sluttvignett</translation> + </message> + <message> + <source>Background</source> + <translation type="unfinished">Bakgrunnen</translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation type="unfinished">Reklame/vignett/promo</translation> + </message> + <message> + <source>UNKNOWN CUT</source> + <translation type="unfinished">UKJENT KLYPP</translation> + </message> + <message> + <source>Manual</source> + <translation type="unfinished">Manuell</translation> + </message> + <message> + <source>Play</source> + <translation type="unfinished">Spel</translation> + </message> + <message> + <source>Segue</source> + <translation type="unfinished">Overgang</translation> + </message> + <message> + <source>Time</source> + <translation type="unfinished">Tid</translation> + </message> + <message> + <source>Panel</source> + <translation type="unfinished">Rute</translation> + </message> + <message> + <source>Macro</source> + <translation type="unfinished">Makro</translation> + </message> + <message> + <source>PLAY</source> + <translation type="unfinished">SPEL</translation> + </message> + <message> + <source>SEGUE</source> + <translation type="unfinished">OVERGANG</translation> + </message> + <message> + <source>STOP</source> + <translation type="unfinished">STOPP</translation> + </message> + <message> + <source>UNKNOWN</source> + <translation type="unfinished">UKJENT</translation> + </message> + <message> + <source>Audio</source> + <translation type="unfinished">Lyd</translation> + </message> + <message> + <source>Marker</source> + <translation type="unfinished">Markør</translation> + </message> + <message> + <source>Open Bracket</source> + <translation type="unfinished">Startklamme</translation> + </message> + <message> + <source>Close Bracket</source> + <translation type="unfinished">Sluttklamme</translation> + </message> + <message> + <source>ChainTo</source> + <translation type="unfinished">LenkTil</translation> + </message> + <message> + <source>Track</source> + <translation type="unfinished">Spor</translation> + </message> + <message> + <source>Link</source> + <translation type="unfinished">Lenkje</translation> + </message> + <message> + <source>Traffic</source> + <translation type="unfinished">Trafikk</translation> + </message> + <message> + <source>Music</source> + <translation type="unfinished">Musikk</translation> + </message> + <message> + <source>RDLogManager</source> + <translation type="unfinished">RDLoggredigering</translation> + </message> + <message> + <source>Tracker</source> + <translation type="unfinished">Sporleggjar</translation> + </message> + <message> + <source>Recording</source> + <translation type="unfinished">Opptak</translation> + </message> + <message> + <source>Macro Event</source> + <translation type="unfinished">Makro-hending</translation> + </message> + <message> + <source>Switch Event</source> + <translation type="unfinished">Byte-hending</translation> + </message> + <message> + <source>Playout</source> + <translation type="unfinished">Spel ut</translation> + </message> + <message> + <source>Download</source> + <translation type="unfinished">Last ned</translation> + </message> + <message> + <source>Upload</source> + <translation type="unfinished">Last opp</translation> + </message> + <message> + <source>Ok</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Short Length</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Low Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>High Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Downloading</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Uploading</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Server Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Internal Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Interrupted</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Playing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Waiting</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Device Busy</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>No Such Cart/Cut</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown Audio Format</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation type="unfinished">CBSI DeltaFlex Traffic Reconciliation v2.01</translation> + </message> + <message> + <source>Text Log</source> + <translation type="unfinished">Tekstlogg</translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation type="unfinished">ASCAP/BMI elektronisk musikkrapport</translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation type="unfinished">Teknisk utspelingsrapport</translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation type="unfinished">SoundExchange Statutory License-rapport</translation> + </message> + <message> + <source>RadioTraffic.com Traffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>VisualTraffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CounterPoint Traffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music1 Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Other</source> + <translation type="unfinished">Annan</translation> + </message> + <message> + <source>AM</source> + <translation type="unfinished">AM</translation> + </message> + <message> + <source>FM</source> + <translation type="unfinished">FM</translation> + </message> + <message> + <source>Report complete!</source> + <translation type="unfinished">Rapport ferdig!</translation> + </message> + <message> + <source>Report canceled!</source> + <translation type="unfinished">Rapport avbroten!</translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation type="unfinished">Greidde ikkje opna rapportfil!</translation> + </message> + <message> + <source>Music Summary</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>WideOrbit Traffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown Position</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Left</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Center</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Right</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Left</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Center</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Right</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NPR/DS SoundExchange Report</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 1</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel First Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 1 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 2 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Second Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Third Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fourth Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audition/Cue Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Channel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fifth and Later Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>invalid SQL or failed DB connection</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>All</source> + <translation type="unfinished">Alle</translation> + </message> + <message> + <source>Relative</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hard</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NaturalLog Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>LiveAssist</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Automatic</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Previous</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Classical Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>reserved</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAddCart</name> + <message> + <source>&Group:</source> + <translation>&Gruppe:</translation> + </message> + <message> + <source>&New Cart Number:</source> + <translation>&Nytt korgnummer</translation> + </message> + <message> + <source>&New Cart Type:</source> + <translation>&Ny korgtype:</translation> + </message> + <message> + <source>Audio</source> + <translation>Lyd</translation> + </message> + <message> + <source>Macro</source> + <translation>Makro</translation> + </message> + <message> + <source>[new cart]</source> + <translation>[ny korg]</translation> + </message> + <message> + <source>&New Cart Title:</source> + <translation>&Nytt namn på korga:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>No Available Cart Numbers</source> + <translation>Ingen korgnummer tilgjengelege</translation> + </message> + <message> + <source>There are no more available cart numbers for the group!</source> + <translation>Det er ikkje fleire korgnummer i denne gruppa!</translation> + </message> + <message> + <source>Invalid Number</source> + <translation>Ugyldig nummer</translation> + </message> + <message> + <source>Invalid Cart Number!</source> + <translation>Ugyldig korgnummer</translation> + </message> + <message> + <source>Title Required</source> + <translation>Namn er kravd</translation> + </message> + <message> + <source>You must enter a cart title!</source> + <translation>Du må skriva inn eit namn på korga!</translation> + </message> + <message> + <source>The cart number is outside of the permitted range for this group!</source> + <translation>Korgnummeret er utanfor det lovlege omfanget for denne gruppa!</translation> + </message> + <message> + <source>Cart Exists</source> + <translation>Korga finst alt</translation> + </message> + <message> + <source>This cart already exists.</source> + <translation>Denne korga finst frå før.</translation> + </message> + <message> + <source>Duplicate Title</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>The cart title must be unique!</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAddLog</name> + <message> + <source>Create Log</source> + <translation>Opprett logg</translation> + </message> + <message> + <source>&New Log Name:</source> + <translation>&Nytt namn på loggen:</translation> + </message> + <message> + <source>&Service:</source> + <translation>&Tenest:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>RDLogEdit</source> + <translation>RDLogEdit</translation> + </message> + <message> + <source>The name is invalid!</source> + <translation type="obsolete">Namnet er ikkje gyldig!</translation> + </message> + <message> + <source>The service is invalid!</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAudioSettingsDialog</name> + <message> + <source>Edit Settings</source> + <translation>Rediger innstillingar</translation> + </message> + <message> + <source>Default &Format:</source> + <translation>Standard&format:</translation> + </message> + <message> + <source>Default &Channels:</source> + <translation>Standard tal på &kanalar:</translation> + </message> + <message> + <source>Default &Sample Rate:</source> + <translation>Standard &punktprøverate:</translation> + </message> + <message> + <source>Default &Bitrate:</source> + <translation>Standard &bitrate:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>PCM16</source> + <translation>PCM16</translation> + </message> + <message> + <source>OggVorbis</source> + <translation>Ogg Vorbis</translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation>MPEG lag 2</translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation>MPEG lag 3</translation> + </message> +</context> +<context> + <name>RDButtonDialog</name> + <message> + <source>Edit Button</source> + <translation>Rediger knapp</translation> + </message> + <message> + <source>Label:</source> + <translation>Merke:</translation> + </message> + <message> + <source>Cart:</source> + <translation>Korg:</translation> + </message> + <message> + <source>Set +Cart</source> + <translation>Set opp +korg</translation> + </message> + <message> + <source>Clear</source> + <translation>Tøm</translation> + </message> + <message> + <source>Set +Color</source> + <translation>Set opp +farge</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>NOT FOUND</source> + <translation>IKKJE FUNNE</translation> + </message> +</context> +<context> + <name>RDCardSelector</name> + <message> + <source>Card:</source> + <translation>Kort:</translation> + </message> + <message> + <source>Port:</source> + <translation>Port:</translation> + </message> +</context> +<context> + <name>RDCart</name> + <message> + <source>Sequentially</source> + <translation type="obsolete">I rekkjefylgje</translation> + </message> + <message> + <source>Randomly</source> + <translation type="obsolete">Tilfeldig</translation> + </message> + <message> + <source>Unknown</source> + <translation type="obsolete">Ukjent</translation> + </message> + <message> + <source>Feature</source> + <translation type="obsolete">Eigenskap</translation> + </message> + <message> + <source>Theme Open</source> + <translation type="obsolete">Opningsvignett</translation> + </message> + <message> + <source>Theme Close</source> + <translation type="obsolete">Sluttvignett</translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation type="obsolete">Opnings/sluttvignett</translation> + </message> + <message> + <source>Background</source> + <translation type="obsolete">Bakgrunnen</translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation type="obsolete">Reklame/vignett/promo</translation> + </message> +</context> +<context> + <name>RDCartDialog</name> + <message> + <source>Select Cart</source> + <translation>Vel korg</translation> + </message> + <message> + <source>Please Wait...</source> + <translation>Vent litt...</translation> + </message> + <message> + <source>Cart Filter:</source> + <translation>Korgfilter:</translation> + </message> + <message> + <source>&Search</source> + <translation>&Søk</translation> + </message> + <message> + <source>C&lear</source> + <translation>&Tøm</translation> + </message> + <message> + <source>Group:</source> + <translation>Gruppe:</translation> + </message> + <message> + <source>NUMBER</source> + <translation>NUMMER</translation> + </message> + <message> + <source>LENGTH</source> + <translation>LENGD</translation> + </message> + <message> + <source>TITLE</source> + <translation>TITTEL</translation> + </message> + <message> + <source>ARTIST</source> + <translation>ARTIST</translation> + </message> + <message> + <source>GROUP</source> + <translation>GRUPPE</translation> + </message> + <message> + <source>CLIENT</source> + <translation>KLIENT</translation> + </message> + <message> + <source>AGENCY</source> + <translation>AGENT</translation> + </message> + <message> + <source>USER DEF</source> + <translation>BRUKARDEFINERT</translation> + </message> + <message> + <source>START</source> + <translation>START</translation> + </message> + <message> + <source>END</source> + <translation>SLUTT</translation> + </message> + <message> + <source>Send to +&Editor</source> + <translation>Send til R&edigering</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>ALL</source> + <translation>ALLE</translation> + </message> + <message> + <source>Show Only First</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Matches</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Load From +&File</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cart Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to create temporary cart for import!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to get temporary cart number for import!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Imported from</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Importing...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Importing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>COMPOSER</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CONDUCTOR</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEdit</name> + <message> + <source>&Audition</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Stop</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>End</source> + <translation type="unfinished">Slutten</translation> + </message> + <message> + <source>&Recue</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEditDialog</name> + <message> + <source>Set Cue Point</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished">&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished">&Avbryt</translation> + </message> +</context> +<context> + <name>RDCutDialog</name> + <message> + <source>Select Cut</source> + <translation>Vel klypp</translation> + </message> + <message> + <source>Please Wait...</source> + <translation>Vent litt...</translation> + </message> + <message> + <source>Cart Filter:</source> + <translation>Korgfilter:</translation> + </message> + <message> + <source>&Search</source> + <translation>&Søk</translation> + </message> + <message> + <source>C&lear</source> + <translation>&Tøm</translation> + </message> + <message> + <source>Group:</source> + <translation>Gruppe:</translation> + </message> + <message> + <source>Carts</source> + <translation>Korger</translation> + </message> + <message> + <source>NUMBER</source> + <translation>NUMMER</translation> + </message> + <message> + <source>TITLE</source> + <translation>TITTEL</translation> + </message> + <message> + <source>GROUP</source> + <translation>GRUPPE</translation> + </message> + <message> + <source>Cuts</source> + <translation>Klypp</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>SKILDRING</translation> + </message> + <message> + <source>&Add New +Cart</source> + <translation>&Legg til ny korg</translation> + </message> + <message> + <source>&Clear</source> + <translation>&Tøm</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>ALL</source> + <translation>ALLE</translation> + </message> + <message> + <source>Show Only First</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Matches</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDDateDialog</name> + <message> + <source>Select Date</source> + <translation>Vel dato</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> +</context> +<context> + <name>RDDatePicker</name> + <message> + <source>Mo</source> + <translation>Må</translation> + </message> + <message> + <source>Tu</source> + <translation>Ty</translation> + </message> + <message> + <source>We</source> + <translation>On</translation> + </message> + <message> + <source>Th</source> + <translation>To</translation> + </message> + <message> + <source>Fr</source> + <translation>Fr</translation> + </message> + <message> + <source>Sa</source> + <translation>La</translation> + </message> + <message> + <source>Su</source> + <translation>Su</translation> + </message> +</context> +<context> + <name>RDEditAudio</name> + <message> + <source>&Save</source> + <translation>&Lagra</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>Amplitude</source> + <translation>Lydstyrke</translation> + </message> + <message> + <source>Zoom +In</source> + <translation>Zoom +inn</translation> + </message> + <message> + <source>Zoom +Out</source> + <translation>Zoom +ut</translation> + </message> + <message> + <source>Time</source> + <translation>Tid</translation> + </message> + <message> + <source>Full +In</source> + <translation>Heilt +inn</translation> + </message> + <message> + <source>Full +Out</source> + <translation>Heilt +ut</translation> + </message> + <message> + <source>Goto</source> + <translation>Gå til</translation> + </message> + <message> + <source>Cursor</source> + <translation>Markør</translation> + </message> + <message> + <source>Home</source> + <translation>Heim</translation> + </message> + <message> + <source>End</source> + <translation>Slutten</translation> + </message> + <message> + <source>Cut +Start</source> + <translation>Klypp- +start</translation> + </message> + <message> + <source>Cut +End</source> + <translation>Klypp- +slutt</translation> + </message> + <message> + <source>Talk +Start</source> + <translation>Tale- +start</translation> + </message> + <message> + <source>Segue +Start</source> + <translation>Overgang- +start</translation> + </message> + <message> + <source>Segue +End</source> + <translation>Overgang- +slutt</translation> + </message> + <message> + <source>Fade +Up</source> + <translation>Ton +inn</translation> + </message> + <message> + <source>Hook +Start</source> + <translation>Knagg- +start</translation> + </message> + <message> + <source>Hook +End</source> + <translation>Knagg- +slutt</translation> + </message> + <message> + <source> dB</source> + <translation>dB</translation> + </message> + <message> + <source>Threshold</source> + <translation>Terskel</translation> + </message> + <message> + <source>Trim +Start</source> + <translation>Skjere- +start</translation> + </message> + <message> + <source>Trim +End</source> + <translation>Skjere- +slutt</translation> + </message> + <message> + <source>Cut Gain</source> + <translation>Dempevolum</translation> + </message> + <message> + <source>Remove +Marker</source> + <translation>Fjern +markør</translation> + </message> + <message> + <source>No Fade on Segue Out</source> + <translation>Inga uttoning ved Overgang ut</translation> + </message> + <message> + <source>Position</source> + <translation>Posisjon</translation> + </message> + <message> + <source>Length</source> + <translation>Lengd</translation> + </message> + <message> + <source>Delete Talk Markers</source> + <translation>Slett talemarkørar</translation> + </message> + <message> + <source>Delete Segue Markers</source> + <translation>Slett overgangsmarkørar</translation> + </message> + <message> + <source>Delete Hook Markers</source> + <translation>Slett knaggmarkørar</translation> + </message> + <message> + <source>Delete Fade Up Marker</source> + <translation>Slett Ton inn-markør</translation> + </message> + <message> + <source>Delete Fade Down Marker</source> + <translation>Slett Ton ut-markør</translation> + </message> + <message> + <source>dB</source> + <translation>dB</translation> + </message> + <message> + <source><none></source> + <translation><ingen></translation> + </message> + <message> + <source>Cut</source> + <translation>Klypp</translation> + </message> + <message> + <source>Talk</source> + <translation>Tale</translation> + </message> + <message> + <source>Segue</source> + <translation>Overgang</translation> + </message> + <message> + <source>Hook</source> + <translation>Knagg</translation> + </message> + <message> + <source>Fade Up</source> + <translation>Ton inn</translation> + </message> + <message> + <source>Fade Down</source> + <translation>Ton ut</translation> + </message> + <message> + <source>L</source> + <translation>V</translation> + </message> + <message> + <source>R</source> + <translation>H</translation> + </message> + <message> + <source>Rivendell Web Service</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to download peak data, error was: +"</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Edit Audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Marker Warning</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Less than half of the audio is playable with these marker settings. +Are you sure you want to save?</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>More than half of the audio will be faded with these marker settings. +Are you sure you want to save?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDEditPanelName</name> + <message> + <source>Edit Panel Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Panel &Name:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished">&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished">&Avbryt</translation> + </message> +</context> +<context> + <name>RDExceptionDialog</name> + <message> + <source>Rivendell Exception Report</source> + <translation>Unntaksrapport frå Rivendell</translation> + </message> + <message> + <source>&Save</source> + <translation>&Lagre</translation> + </message> + <message> + <source>&Close</source> + <translation>Lu&kk</translation> + </message> + <message> + <source>Text (*.txt *.TXT) +All Files (*.*)</source> + <translation>Tekst (*.txt *.TXT) +Alle filer (*.*)</translation> + </message> + <message> + <source>Export File</source> + <translation>Eksporter fil</translation> + </message> + <message> + <source>The file</source> + <translation>Fila</translation> + </message> + <message> + <source>already exists! +Overwrite?</source> + <translation>finst frå før! +Skriv over?</translation> + </message> + <message> + <source>File Exists</source> + <translation>Fila finst</translation> + </message> + <message> + <source>Unable to open file</source> + <translation>Greier ikkje opna fila</translation> + </message> + <message> + <source>for writing!</source> + <translation>for skriving!</translation> + </message> + <message> + <source>File Error</source> + <translation>Filfeil</translation> + </message> +</context> +<context> + <name>RDExportSettingsDialog</name> + <message> + <source>Edit Export Settings</source> + <translation>Rediger eksportinnstillingar</translation> + </message> + <message> + <source>&Channels:</source> + <translation>&Kanalar:</translation> + </message> + <message> + <source>&Sample Rate:</source> + <translation>&Punktprøverate:</translation> + </message> + <message> + <source>&Bitrate:</source> + <translation>&Bitrate:</translation> + </message> + <message> + <source>&Quality:</source> + <translation>&Kvalitet:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>PCM16</source> + <translation>PCM16</translation> + </message> + <message> + <source>FLAC</source> + <translation>FLAC</translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation>MPEG lag 2</translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation>MPEG lag 3</translation> + </message> + <message> + <source>OggVorbis</source> + <translation>Ogg Vorbis</translation> + </message> + <message> + <source>VBR</source> + <translation>VBR</translation> + </message> + <message> + <source>32 kbps</source> + <translation>32 kbps</translation> + </message> + <message> + <source>64 kbps</source> + <translation>64 kbps</translation> + </message> + <message> + <source>96 kbps</source> + <translation>96 kbps</translation> + </message> + <message> + <source>128 kbps</source> + <translation>128 kbps</translation> + </message> + <message> + <source>160 kbps</source> + <translation>160 kbps</translation> + </message> + <message> + <source>192 kbps</source> + <translation>192 kbps</translation> + </message> + <message> + <source>224 kbps</source> + <translation>224 kbps</translation> + </message> + <message> + <source>256 kbps</source> + <translation>256 kbps</translation> + </message> + <message> + <source>288 kbps</source> + <translation>288 kbps</translation> + </message> + <message> + <source>320 kbps</source> + <translation>320 kbps</translation> + </message> + <message> + <source>352 kbps</source> + <translation>352 kbps</translation> + </message> + <message> + <source>384 kbps</source> + <translation>384 kbps</translation> + </message> + <message> + <source>416 kbps</source> + <translation>416 kbps</translation> + </message> + <message> + <source>448 kbps</source> + <translation>448 kbps</translation> + </message> + <message> + <source>48 kbps</source> + <translation>48 kbps</translation> + </message> + <message> + <source>56 kbps</source> + <translation>56 kbps</translation> + </message> + <message> + <source>80 kbps</source> + <translation>80 kbps</translation> + </message> + <message> + <source>112 kbps</source> + <translation>112 kbps</translation> + </message> + <message> + <source>40 kbps</source> + <translation>40 kbps</translation> + </message> + <message> + <source>8 kbps</source> + <translation>8 kbps</translation> + </message> + <message> + <source>16 kbps</source> + <translation>16 kbps</translation> + </message> + <message> + <source>24 kbps</source> + <translation>24 kbps</translation> + </message> + <message> + <source>144 kbps</source> + <translation>144 kbps</translation> + </message> +</context> +<context> + <name>RDGetAth</name> + <message> + <source>Enter ATH</source> + <translation>Skriv inn lyttetimar</translation> + </message> + <message> + <source>Enter the agreggate tuning hours (ATH) +figure for the report period. +(Supplied by your streaming provider).</source> + <translation>Skriv inn totalt lyttetimetal +for rapportperioden. +(Oppgjeve av strøymeleverandøren din).</translation> + </message> + <message> + <source>ATH:</source> + <translation>Lyttetimar:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>Invalid ATH</source> + <translation>Ugyldig lyttetimetal</translation> + </message> + <message> + <source>You must provide a valid ATH figure!</source> + <translation>Du må oppgje eit gyldig tal på lyttetimar!</translation> + </message> +</context> +<context> + <name>RDGetPasswd</name> + <message> + <source>Enter Password</source> + <translation>Skriv inn passord</translation> + </message> + <message> + <source>Enter password</source> + <translation>Skriv inn passord</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> +</context> +<context> + <name>RDGpioSelector</name> + <message> + <source>Pin:</source> + <translation>Pin-nummer:</translation> + </message> +</context> +<context> + <name>RDImportAudio</name> + <message> + <source>Import/Export Audio File</source> + <translation>Importer/eksporter lydfil</translation> + </message> + <message> + <source>Import File</source> + <translation>Importer fil</translation> + </message> + <message> + <source>Filename:</source> + <translation>Filnamn:</translation> + </message> + <message> + <source>&Select</source> + <translation>&Vel</translation> + </message> + <message> + <source>Import file metadata</source> + <translation>Importer metadata frå fil</translation> + </message> + <message> + <source>Channels:</source> + <translation>Kanalar:</translation> + </message> + <message> + <source>Autotrim</source> + <translation>Autoskjer</translation> + </message> + <message> + <source>Level:</source> + <translation>Nivå:</translation> + </message> + <message> + <source>dBFS</source> + <translation>dBFS</translation> + </message> + <message> + <source>Export File</source> + <translation>Eksporter fil</translation> + </message> + <message> + <source>Export file metadata</source> + <translation>Eksporter metadata frå fil</translation> + </message> + <message> + <source>Format:</source> + <translation>Format:</translation> + </message> + <message> + <source>S&et</source> + <translation>S&et</translation> + </message> + <message> + <source>Normalize</source> + <translation>Normaliser</translation> + </message> + <message> + <source>&Import</source> + <translation>&Importer</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>Export</source> + <translation>Eksporter</translation> + </message> + <message> + <source>Import</source> + <translation>Importer</translation> + </message> + <message> + <source>Import Audio File</source> + <translation>Importer lydfil</translation> + </message> + <message> + <source>File does not exist!</source> + <translation>Fila finst ikkje!</translation> + </message> + <message> + <source>Cannot open file!</source> + <translation type="obsolete">Greier ikkje opna fila!</translation> + </message> + <message> + <source>Unsupported file type!</source> + <translation type="obsolete">Filtypen er ikkje støtta!</translation> + </message> + <message> + <source>Audio Exists</source> + <translation type="obsolete">Lyd finst</translation> + </message> + <message> + <source>This will overwrite the existing recording. +Do you want to proceed?</source> + <translation type="obsolete">Dette skriv over opptaket ditt. +Vil du halda fram?</translation> + </message> + <message> + <source>Empty Clipboard</source> + <translation type="obsolete">Tom utklyppstavle</translation> + </message> + <message> + <source>Importing this cut will also empty the clipboard. +Do you still want to proceed?</source> + <translation type="obsolete">Viss du importerer dette klyppet, tømer du utklyppstavla. +Vil du halda fram?</translation> + </message> + <message> + <source>Import Complete</source> + <translation>Import ferdig</translation> + </message> + <message> + <source>Import complete!</source> + <translation>Importen er ferdig!</translation> + </message> + <message> + <source>Import Aborted</source> + <translation type="obsolete">Import avbroten</translation> + </message> + <message> + <source>The import has been aborted.</source> + <translation type="obsolete">Importen vart avbroten.</translation> + </message> + <message> + <source>Import Failed</source> + <translation type="obsolete">Importfeil</translation> + </message> + <message> + <source>The importer encountered an error. +Please check your importer configuration and try again.</source> + <translation type="obsolete">Det var ein feil med importen. +Sjå over importoppsettet ditt og prøv att.</translation> + </message> + <message> + <source>File Exists</source> + <translation>Fila finst</translation> + </message> + <message> + <source>The selected file already exists! +Do you want to overwrite it?</source> + <translation>Denne fila finst alt! +Vil du skriva over henne?</translation> + </message> + <message> + <source>File Error</source> + <translation type="obsolete">Filfeil</translation> + </message> + <message> + <source>Cannot open file in archive!</source> + <translation type="obsolete">Greier ikkje opna fila i arkivet!</translation> + </message> + <message> + <source>Unsupported file type in archive!</source> + <translation type="obsolete">Filtypen i arkivet er ikkje støtta!</translation> + </message> + <message> + <source>No Access</source> + <translation type="obsolete">Ingen tilgang</translation> + </message> + <message> + <source>Unable to open the file for writing!</source> + <translation type="obsolete">Greier ikkje opna fila for skriving!</translation> + </message> + <message> + <source>OK</source> + <translation type="obsolete">OK</translation> + </message> + <message> + <source>Export Complete</source> + <translation>Eksport ferdig</translation> + </message> + <message> + <source>Export complete!</source> + <translation>Eksporten er ferdig!</translation> + </message> + <message> + <source>Export Aborted</source> + <translation type="obsolete">Eksport avbroten</translation> + </message> + <message> + <source>The export has been aborted.</source> + <translation type="obsolete">Eksporten vart avbroten.</translation> + </message> + <message> + <source>Export Failed</source> + <translation type="obsolete">Eksportfeil</translation> + </message> + <message> + <source>The Exporter encountered an error. +Please check your configuration and try again.</source> + <translation type="obsolete">Det var ein feil med eksporten. +Sjekk eksportoppsettet ditt og prøv att.</translation> + </message> + <message> + <source>Export Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Abort</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDIntegerDialog</name> + <message> + <source>Set Value</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished">&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished">&Avbryt</translation> + </message> +</context> +<context> + <name>RDIntegerEdit</name> + <message> + <source>Set Value</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDLicense</name> + <message> + <source>&Close</source> + <translation>Lu&kk</translation> + </message> + <message> + <source>GNU Public License v2</source> + <translation>GNU Public-lisensen, versjon 2</translation> + </message> +</context> +<context> + <name>RDListGroups</name> + <message> + <source>Select Group</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NAME</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation type="unfinished">SKILDRING</translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished">&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished">&Avbryt</translation> + </message> +</context> +<context> + <name>RDListLogs</name> + <message> + <source>Select Log - User: </source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Select Log</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NAME</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation type="unfinished">SKILDRING</translation> + </message> + <message> + <source>SERVICE</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>OK</source> + <translation type="unfinished">OK</translation> + </message> + <message> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDListSelector</name> + <message> + <source>Available Services</source> + <translation>Tilgjengelege tenester</translation> + </message> + <message> + <source>Add >></source> + <translation>Legg til >></translation> + </message> + <message> + <source><< Remove</source> + <translation><< Fjern</translation> + </message> + <message> + <source>Active Services</source> + <translation>Aktive tenester</translation> + </message> +</context> +<context> + <name>RDLogLine</name> + <message> + <source>Unknown</source> + <translation type="obsolete">Ukjent</translation> + </message> + <message> + <source>Manual</source> + <translation type="obsolete">Manuell</translation> + </message> + <message> + <source>Play</source> + <translation type="obsolete">Spel</translation> + </message> + <message> + <source>Segue</source> + <translation type="obsolete">Overgang</translation> + </message> + <message> + <source>Time</source> + <translation type="obsolete">Tid</translation> + </message> + <message> + <source>Panel</source> + <translation type="obsolete">Rute</translation> + </message> + <message> + <source>Macro</source> + <translation type="obsolete">Makro</translation> + </message> + <message> + <source>PLAY</source> + <translation type="obsolete">SPEL</translation> + </message> + <message> + <source>SEGUE</source> + <translation type="obsolete">OVERGANG</translation> + </message> + <message> + <source>STOP</source> + <translation type="obsolete">STOPP</translation> + </message> + <message> + <source>OVERLAP</source> + <translation type="obsolete">OVERLAPP</translation> + </message> + <message> + <source>UNKNOWN</source> + <translation type="obsolete">UKJENT</translation> + </message> + <message> + <source>Audio</source> + <translation type="obsolete">Lyd</translation> + </message> + <message> + <source>Marker</source> + <translation type="obsolete">Markør</translation> + </message> + <message> + <source>Open Bracket</source> + <translation type="obsolete">Startklamme</translation> + </message> + <message> + <source>Close Bracket</source> + <translation type="obsolete">Sluttklamme</translation> + </message> + <message> + <source>ChainTo</source> + <translation type="obsolete">LenkTil</translation> + </message> + <message> + <source>Track</source> + <translation type="obsolete">Spor</translation> + </message> + <message> + <source>Link</source> + <translation type="obsolete">Lenkje</translation> + </message> + <message> + <source>Traffic</source> + <translation type="obsolete">Trafikk</translation> + </message> + <message> + <source>Music</source> + <translation type="obsolete">Musikk</translation> + </message> + <message> + <source>RDLogManager</source> + <translation type="obsolete">RDLoggredigering</translation> + </message> + <message> + <source>Tracker</source> + <translation type="obsolete">Sporleggjar</translation> + </message> +</context> +<context> + <name>RDPanelButton</name> + <message> + <source>No Audio</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDPasswd</name> + <message> + <source>Change Password</source> + <translation>Endre passord</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>&Password:</source> + <translation>&Passord:</translation> + </message> + <message> + <source>C&onfirm:</source> + <translation>&Stadfest:</translation> + </message> + <message> + <source>Password Mismatch</source> + <translation>Passorda er ikkje like</translation> + </message> + <message> + <source>The passwords don't match, +please try again!</source> + <translation>Passorda dine er ikkje like, +prøv ein gong til!</translation> + </message> + <message> + <source>OK</source> + <translation>OK</translation> + </message> +</context> +<context> + <name>RDRecording</name> + <message> + <source>Recording</source> + <translation type="obsolete">Opptak</translation> + </message> + <message> + <source>Macro Event</source> + <translation type="obsolete">Makro-hending</translation> + </message> + <message> + <source>Switch Event</source> + <translation type="obsolete">Byte-hending</translation> + </message> + <message> + <source>Playout</source> + <translation type="obsolete">Spel ut</translation> + </message> + <message> + <source>Download</source> + <translation type="obsolete">Last ned</translation> + </message> + <message> + <source>Upload</source> + <translation type="obsolete">Last opp</translation> + </message> +</context> +<context> + <name>RDReport</name> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation type="obsolete">CBSI DeltaFlex Traffic Reconciliation v2.01</translation> + </message> + <message> + <source>Text Log</source> + <translation type="obsolete">Tekstlogg</translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation type="obsolete">ASCAP/BMI elektronisk musikkrapport</translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation type="obsolete">Teknisk utspelingsrapport</translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation type="obsolete">SoundExchange Statutory License-rapport</translation> + </message> + <message> + <source>Unknown</source> + <translation type="obsolete">Ukjent</translation> + </message> + <message> + <source>Other</source> + <translation type="obsolete">Annan</translation> + </message> + <message> + <source>AM</source> + <translation type="obsolete">AM</translation> + </message> + <message> + <source>FM</source> + <translation type="obsolete">FM</translation> + </message> + <message> + <source>Report complete!</source> + <translation type="obsolete">Rapport ferdig!</translation> + </message> + <message> + <source>Report canceled!</source> + <translation type="obsolete">Rapport avbroten!</translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation type="obsolete">Greidde ikkje opna rapportfil!</translation> + </message> +</context> +<context> + <name>RDSoundPanel</name> + <message> + <source>Play All</source> + <translation>Spel alle</translation> + </message> + <message> + <source>Play Hook</source> + <translation>Spel knagg</translation> + </message> + <message> + <source>Reset</source> + <translation>Nullstill</translation> + </message> + <message> + <source>All</source> + <translation>Alle</translation> + </message> + <message> + <source>Setup</source> + <translation>Oppsett</translation> + </message> + <message> + <source>Cart</source> + <translation>Korg</translation> + </message> + <message> + <source>Panel</source> + <translation>Rute</translation> + </message> +</context> +<context> + <name>RDSqlDatabaseStatus</name> + <message> + <source>Database connection restored.</source> + <translation>Databasetilkoplinga er gjenoppretta.</translation> + </message> + <message> + <source>Database connection failed : </source> + <translation>Feil med databasetilkoplinga: </translation> + </message> +</context> +<context> + <name>RDStereoMeter</name> + <message> + <source>L</source> + <translation>V</translation> + </message> + <message> + <source>R</source> + <translation>H</translation> + </message> + <message> + <source>CLIP</source> + <translation>KLYPP</translation> + </message> +</context> +<context> + <name>RDSvc</name> + <message> + <source>The following events were not placed: +</source> + <translation>Desse hendingane vart ikkje plasserte: +</translation> + </message> + <message> + <source>[unknown cart]</source> + <translation>[ukjend korg]</translation> + </message> + <message> + <source>Autofill Errors +</source> + <translation type="obsolete">Autofyll-feil +</translation> + </message> + <message> + <source>Event Fill Errors +</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/lib/librd_nn.ts b/lib/librd_nn.ts new file mode 100644 index 00000000..aaae0b4e --- /dev/null +++ b/lib/librd_nn.ts @@ -0,0 +1,2121 @@ +<!DOCTYPE TS><TS> +<context> + <name></name> + <message> + <source>UNKNOWN CUT</source> + <translation type="obsolete">UKJENT KLYPP</translation> + </message> +</context> +<context> + <name>@default</name> + <message> + <source>ALL</source> + <translation type="obsolete">ALLE</translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <source>Couldn't initialize QSql driver!</source> + <translation>Greidde ikkje setja opp QSql-drivaren!</translation> + </message> + <message> + <source>Couldn't open mySQL connection!</source> + <translation>Greidde ikkje kopla til mySQL-databasen!</translation> + </message> + <message> + <source>Sequentially</source> + <translation type="unfinished">I rekkjefylgje</translation> + </message> + <message> + <source>Randomly</source> + <translation type="unfinished">Tilfeldig</translation> + </message> + <message> + <source>Unknown</source> + <translation type="unfinished">Ukjent</translation> + </message> + <message> + <source>Feature</source> + <translation type="unfinished">Eigenskap</translation> + </message> + <message> + <source>Theme Open</source> + <translation type="unfinished">Opningsvignett</translation> + </message> + <message> + <source>Theme Close</source> + <translation type="unfinished">Sluttvignett</translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation type="unfinished">Opnings/sluttvignett</translation> + </message> + <message> + <source>Background</source> + <translation type="unfinished">Bakgrunnen</translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation type="unfinished">Reklame/vignett/promo</translation> + </message> + <message> + <source>UNKNOWN CUT</source> + <translation type="unfinished">UKJENT KLYPP</translation> + </message> + <message> + <source>Manual</source> + <translation type="unfinished">Manuell</translation> + </message> + <message> + <source>Play</source> + <translation type="unfinished">Spel</translation> + </message> + <message> + <source>Segue</source> + <translation type="unfinished">Overgang</translation> + </message> + <message> + <source>Time</source> + <translation type="unfinished">Tid</translation> + </message> + <message> + <source>Panel</source> + <translation type="unfinished">Rute</translation> + </message> + <message> + <source>Macro</source> + <translation type="unfinished">Makro</translation> + </message> + <message> + <source>PLAY</source> + <translation type="unfinished">SPEL</translation> + </message> + <message> + <source>SEGUE</source> + <translation type="unfinished">OVERGANG</translation> + </message> + <message> + <source>STOP</source> + <translation type="unfinished">STOPP</translation> + </message> + <message> + <source>UNKNOWN</source> + <translation type="unfinished">UKJENT</translation> + </message> + <message> + <source>Audio</source> + <translation type="unfinished">Lyd</translation> + </message> + <message> + <source>Marker</source> + <translation type="unfinished">Markør</translation> + </message> + <message> + <source>Open Bracket</source> + <translation type="unfinished">Startklamme</translation> + </message> + <message> + <source>Close Bracket</source> + <translation type="unfinished">Sluttklamme</translation> + </message> + <message> + <source>ChainTo</source> + <translation type="unfinished">LenkTil</translation> + </message> + <message> + <source>Track</source> + <translation type="unfinished">Spor</translation> + </message> + <message> + <source>Link</source> + <translation type="unfinished">Lenkje</translation> + </message> + <message> + <source>Traffic</source> + <translation type="unfinished">Trafikk</translation> + </message> + <message> + <source>Music</source> + <translation type="unfinished">Musikk</translation> + </message> + <message> + <source>RDLogManager</source> + <translation type="unfinished">RDLoggredigering</translation> + </message> + <message> + <source>Tracker</source> + <translation type="unfinished">Sporleggjar</translation> + </message> + <message> + <source>Recording</source> + <translation type="unfinished">Opptak</translation> + </message> + <message> + <source>Macro Event</source> + <translation type="unfinished">Makro-hending</translation> + </message> + <message> + <source>Switch Event</source> + <translation type="unfinished">Byte-hending</translation> + </message> + <message> + <source>Playout</source> + <translation type="unfinished">Spel ut</translation> + </message> + <message> + <source>Download</source> + <translation type="unfinished">Last ned</translation> + </message> + <message> + <source>Upload</source> + <translation type="unfinished">Last opp</translation> + </message> + <message> + <source>Ok</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Short Length</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Low Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>High Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Downloading</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Uploading</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Server Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Internal Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Interrupted</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Playing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Waiting</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Device Busy</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>No Such Cart/Cut</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown Audio Format</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation type="unfinished">CBSI DeltaFlex Traffic Reconciliation v2.01</translation> + </message> + <message> + <source>Text Log</source> + <translation type="unfinished">Tekstlogg</translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation type="unfinished">ASCAP/BMI elektronisk musikkrapport</translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation type="unfinished">Teknisk utspelingsrapport</translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation type="unfinished">SoundExchange Statutory License-rapport</translation> + </message> + <message> + <source>RadioTraffic.com Traffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>VisualTraffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CounterPoint Traffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music1 Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Other</source> + <translation type="unfinished">Annan</translation> + </message> + <message> + <source>AM</source> + <translation type="unfinished">AM</translation> + </message> + <message> + <source>FM</source> + <translation type="unfinished">FM</translation> + </message> + <message> + <source>Report complete!</source> + <translation type="unfinished">Rapport ferdig!</translation> + </message> + <message> + <source>Report canceled!</source> + <translation type="unfinished">Rapport avbroten!</translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation type="unfinished">Greidde ikkje opna rapportfil!</translation> + </message> + <message> + <source>Music Summary</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>WideOrbit Traffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown Position</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Left</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Center</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Right</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Left</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Center</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Right</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NPR/DS SoundExchange Report</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 1</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel First Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 1 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 2 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Second Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Third Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fourth Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audition/Cue Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Channel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fifth and Later Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>invalid SQL or failed DB connection</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>All</source> + <translation type="unfinished">Alle</translation> + </message> + <message> + <source>Relative</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hard</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NaturalLog Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>LiveAssist</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Automatic</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Previous</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Classical Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>reserved</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAddCart</name> + <message> + <source>&Group:</source> + <translation>&Gruppe:</translation> + </message> + <message> + <source>&New Cart Number:</source> + <translation>&Nytt korgnummer</translation> + </message> + <message> + <source>&New Cart Type:</source> + <translation>&Ny korgtype:</translation> + </message> + <message> + <source>Audio</source> + <translation>Lyd</translation> + </message> + <message> + <source>Macro</source> + <translation>Makro</translation> + </message> + <message> + <source>[new cart]</source> + <translation>[ny korg]</translation> + </message> + <message> + <source>&New Cart Title:</source> + <translation>&Nytt namn på korga:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>No Available Cart Numbers</source> + <translation>Ingen korgnummer tilgjengelege</translation> + </message> + <message> + <source>There are no more available cart numbers for the group!</source> + <translation>Det er ikkje fleire korgnummer i denne gruppa!</translation> + </message> + <message> + <source>Invalid Number</source> + <translation>Ugyldig nummer</translation> + </message> + <message> + <source>Invalid Cart Number!</source> + <translation>Ugyldig korgnummer</translation> + </message> + <message> + <source>Title Required</source> + <translation>Namn er kravd</translation> + </message> + <message> + <source>You must enter a cart title!</source> + <translation>Du må skriva inn eit namn på korga!</translation> + </message> + <message> + <source>The cart number is outside of the permitted range for this group!</source> + <translation>Korgnummeret er utanfor det lovlege omfanget for denne gruppa!</translation> + </message> + <message> + <source>Cart Exists</source> + <translation>Korga finst alt</translation> + </message> + <message> + <source>This cart already exists.</source> + <translation>Denne korga finst frå før.</translation> + </message> + <message> + <source>Duplicate Title</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>The cart title must be unique!</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAddLog</name> + <message> + <source>Create Log</source> + <translation>Opprett logg</translation> + </message> + <message> + <source>&New Log Name:</source> + <translation>&Nytt namn på loggen:</translation> + </message> + <message> + <source>&Service:</source> + <translation>&Tenest:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>RDLogEdit</source> + <translation>RDLogEdit</translation> + </message> + <message> + <source>The name is invalid!</source> + <translation type="obsolete">Namnet er ikkje gyldig!</translation> + </message> + <message> + <source>The service is invalid!</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAudioSettingsDialog</name> + <message> + <source>Edit Settings</source> + <translation>Rediger innstillingar</translation> + </message> + <message> + <source>Default &Format:</source> + <translation>Standard&format:</translation> + </message> + <message> + <source>Default &Channels:</source> + <translation>Standard tal på &kanalar:</translation> + </message> + <message> + <source>Default &Sample Rate:</source> + <translation>Standard &punktprøverate:</translation> + </message> + <message> + <source>Default &Bitrate:</source> + <translation>Standard &bitrate:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>PCM16</source> + <translation>PCM16</translation> + </message> + <message> + <source>OggVorbis</source> + <translation>Ogg Vorbis</translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation>MPEG lag 2</translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation>MPEG lag 3</translation> + </message> +</context> +<context> + <name>RDButtonDialog</name> + <message> + <source>Edit Button</source> + <translation>Rediger knapp</translation> + </message> + <message> + <source>Label:</source> + <translation>Merke:</translation> + </message> + <message> + <source>Cart:</source> + <translation>Korg:</translation> + </message> + <message> + <source>Set +Cart</source> + <translation>Set opp +korg</translation> + </message> + <message> + <source>Clear</source> + <translation>Tøm</translation> + </message> + <message> + <source>Set +Color</source> + <translation>Set opp +farge</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>NOT FOUND</source> + <translation>IKKJE FUNNE</translation> + </message> +</context> +<context> + <name>RDCardSelector</name> + <message> + <source>Card:</source> + <translation>Kort:</translation> + </message> + <message> + <source>Port:</source> + <translation>Port:</translation> + </message> +</context> +<context> + <name>RDCart</name> + <message> + <source>Sequentially</source> + <translation type="obsolete">I rekkjefylgje</translation> + </message> + <message> + <source>Randomly</source> + <translation type="obsolete">Tilfeldig</translation> + </message> + <message> + <source>Unknown</source> + <translation type="obsolete">Ukjent</translation> + </message> + <message> + <source>Feature</source> + <translation type="obsolete">Eigenskap</translation> + </message> + <message> + <source>Theme Open</source> + <translation type="obsolete">Opningsvignett</translation> + </message> + <message> + <source>Theme Close</source> + <translation type="obsolete">Sluttvignett</translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation type="obsolete">Opnings/sluttvignett</translation> + </message> + <message> + <source>Background</source> + <translation type="obsolete">Bakgrunnen</translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation type="obsolete">Reklame/vignett/promo</translation> + </message> +</context> +<context> + <name>RDCartDialog</name> + <message> + <source>Select Cart</source> + <translation>Vel korg</translation> + </message> + <message> + <source>Please Wait...</source> + <translation>Vent litt...</translation> + </message> + <message> + <source>Cart Filter:</source> + <translation>Korgfilter:</translation> + </message> + <message> + <source>&Search</source> + <translation>&Søk</translation> + </message> + <message> + <source>C&lear</source> + <translation>&Tøm</translation> + </message> + <message> + <source>Group:</source> + <translation>Gruppe:</translation> + </message> + <message> + <source>NUMBER</source> + <translation>NUMMER</translation> + </message> + <message> + <source>LENGTH</source> + <translation>LENGD</translation> + </message> + <message> + <source>TITLE</source> + <translation>TITTEL</translation> + </message> + <message> + <source>ARTIST</source> + <translation>ARTIST</translation> + </message> + <message> + <source>GROUP</source> + <translation>GRUPPE</translation> + </message> + <message> + <source>CLIENT</source> + <translation>KLIENT</translation> + </message> + <message> + <source>AGENCY</source> + <translation>AGENT</translation> + </message> + <message> + <source>USER DEF</source> + <translation>BRUKARDEFINERT</translation> + </message> + <message> + <source>START</source> + <translation>START</translation> + </message> + <message> + <source>END</source> + <translation>SLUTT</translation> + </message> + <message> + <source>Send to +&Editor</source> + <translation>Send til R&edigering</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>ALL</source> + <translation>ALLE</translation> + </message> + <message> + <source>Show Only First</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Matches</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Load From +&File</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cart Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to create temporary cart for import!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to get temporary cart number for import!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Imported from</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Importing...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Importing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>COMPOSER</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CONDUCTOR</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEdit</name> + <message> + <source>&Audition</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Stop</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>End</source> + <translation type="unfinished">Slutten</translation> + </message> + <message> + <source>&Recue</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEditDialog</name> + <message> + <source>Set Cue Point</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished">&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished">&Avbryt</translation> + </message> +</context> +<context> + <name>RDCutDialog</name> + <message> + <source>Select Cut</source> + <translation>Vel klypp</translation> + </message> + <message> + <source>Please Wait...</source> + <translation>Vent litt...</translation> + </message> + <message> + <source>Cart Filter:</source> + <translation>Korgfilter:</translation> + </message> + <message> + <source>&Search</source> + <translation>&Søk</translation> + </message> + <message> + <source>C&lear</source> + <translation>&Tøm</translation> + </message> + <message> + <source>Group:</source> + <translation>Gruppe:</translation> + </message> + <message> + <source>Carts</source> + <translation>Korger</translation> + </message> + <message> + <source>NUMBER</source> + <translation>NUMMER</translation> + </message> + <message> + <source>TITLE</source> + <translation>TITTEL</translation> + </message> + <message> + <source>GROUP</source> + <translation>GRUPPE</translation> + </message> + <message> + <source>Cuts</source> + <translation>Klypp</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>SKILDRING</translation> + </message> + <message> + <source>&Add New +Cart</source> + <translation>&Legg til ny korg</translation> + </message> + <message> + <source>&Clear</source> + <translation>&Tøm</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>ALL</source> + <translation>ALLE</translation> + </message> + <message> + <source>Show Only First</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Matches</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDDateDialog</name> + <message> + <source>Select Date</source> + <translation>Vel dato</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> +</context> +<context> + <name>RDDatePicker</name> + <message> + <source>Mo</source> + <translation>Må</translation> + </message> + <message> + <source>Tu</source> + <translation>Ty</translation> + </message> + <message> + <source>We</source> + <translation>On</translation> + </message> + <message> + <source>Th</source> + <translation>To</translation> + </message> + <message> + <source>Fr</source> + <translation>Fr</translation> + </message> + <message> + <source>Sa</source> + <translation>La</translation> + </message> + <message> + <source>Su</source> + <translation>Su</translation> + </message> +</context> +<context> + <name>RDEditAudio</name> + <message> + <source>&Save</source> + <translation>&Lagra</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>Amplitude</source> + <translation>Lydstyrke</translation> + </message> + <message> + <source>Zoom +In</source> + <translation>Zoom +inn</translation> + </message> + <message> + <source>Zoom +Out</source> + <translation>Zoom +ut</translation> + </message> + <message> + <source>Time</source> + <translation>Tid</translation> + </message> + <message> + <source>Full +In</source> + <translation>Heilt +inn</translation> + </message> + <message> + <source>Full +Out</source> + <translation>Heilt +ut</translation> + </message> + <message> + <source>Goto</source> + <translation>Gå til</translation> + </message> + <message> + <source>Cursor</source> + <translation>Markør</translation> + </message> + <message> + <source>Home</source> + <translation>Heim</translation> + </message> + <message> + <source>End</source> + <translation>Slutten</translation> + </message> + <message> + <source>Cut +Start</source> + <translation>Klypp- +start</translation> + </message> + <message> + <source>Cut +End</source> + <translation>Klypp- +slutt</translation> + </message> + <message> + <source>Talk +Start</source> + <translation>Tale- +start</translation> + </message> + <message> + <source>Segue +Start</source> + <translation>Overgang- +start</translation> + </message> + <message> + <source>Segue +End</source> + <translation>Overgang- +slutt</translation> + </message> + <message> + <source>Fade +Up</source> + <translation>Ton +inn</translation> + </message> + <message> + <source>Hook +Start</source> + <translation>Knagg- +start</translation> + </message> + <message> + <source>Hook +End</source> + <translation>Knagg- +slutt</translation> + </message> + <message> + <source> dB</source> + <translation>dB</translation> + </message> + <message> + <source>Threshold</source> + <translation>Terskel</translation> + </message> + <message> + <source>Trim +Start</source> + <translation>Skjere- +start</translation> + </message> + <message> + <source>Trim +End</source> + <translation>Skjere- +slutt</translation> + </message> + <message> + <source>Cut Gain</source> + <translation>Dempevolum</translation> + </message> + <message> + <source>Remove +Marker</source> + <translation>Fjern +markør</translation> + </message> + <message> + <source>No Fade on Segue Out</source> + <translation>Inga uttoning ved Overgang ut</translation> + </message> + <message> + <source>Position</source> + <translation>Posisjon</translation> + </message> + <message> + <source>Length</source> + <translation>Lengd</translation> + </message> + <message> + <source>Delete Talk Markers</source> + <translation>Slett talemarkørar</translation> + </message> + <message> + <source>Delete Segue Markers</source> + <translation>Slett overgangsmarkørar</translation> + </message> + <message> + <source>Delete Hook Markers</source> + <translation>Slett knaggmarkørar</translation> + </message> + <message> + <source>Delete Fade Up Marker</source> + <translation>Slett Ton inn-markør</translation> + </message> + <message> + <source>Delete Fade Down Marker</source> + <translation>Slett Ton ut-markør</translation> + </message> + <message> + <source>dB</source> + <translation>dB</translation> + </message> + <message> + <source><none></source> + <translation><ingen></translation> + </message> + <message> + <source>Cut</source> + <translation>Klypp</translation> + </message> + <message> + <source>Talk</source> + <translation>Tale</translation> + </message> + <message> + <source>Segue</source> + <translation>Overgang</translation> + </message> + <message> + <source>Hook</source> + <translation>Knagg</translation> + </message> + <message> + <source>Fade Up</source> + <translation>Ton inn</translation> + </message> + <message> + <source>Fade Down</source> + <translation>Ton ut</translation> + </message> + <message> + <source>L</source> + <translation>V</translation> + </message> + <message> + <source>R</source> + <translation>H</translation> + </message> + <message> + <source>Rivendell Web Service</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to download peak data, error was: +"</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Edit Audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Marker Warning</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Less than half of the audio is playable with these marker settings. +Are you sure you want to save?</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>More than half of the audio will be faded with these marker settings. +Are you sure you want to save?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDEditPanelName</name> + <message> + <source>Edit Panel Name</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Panel &Name:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished">&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished">&Avbryt</translation> + </message> +</context> +<context> + <name>RDExceptionDialog</name> + <message> + <source>Rivendell Exception Report</source> + <translation>Unntaksrapport frå Rivendell</translation> + </message> + <message> + <source>&Save</source> + <translation>&Lagre</translation> + </message> + <message> + <source>&Close</source> + <translation>Lu&kk</translation> + </message> + <message> + <source>Text (*.txt *.TXT) +All Files (*.*)</source> + <translation>Tekst (*.txt *.TXT) +Alle filer (*.*)</translation> + </message> + <message> + <source>Export File</source> + <translation>Eksporter fil</translation> + </message> + <message> + <source>The file</source> + <translation>Fila</translation> + </message> + <message> + <source>already exists! +Overwrite?</source> + <translation>finst frå før! +Skriv over?</translation> + </message> + <message> + <source>File Exists</source> + <translation>Fila finst</translation> + </message> + <message> + <source>Unable to open file</source> + <translation>Greier ikkje opna fila</translation> + </message> + <message> + <source>for writing!</source> + <translation>for skriving!</translation> + </message> + <message> + <source>File Error</source> + <translation>Filfeil</translation> + </message> +</context> +<context> + <name>RDExportSettingsDialog</name> + <message> + <source>Edit Export Settings</source> + <translation>Rediger eksportinnstillingar</translation> + </message> + <message> + <source>&Channels:</source> + <translation>&Kanalar:</translation> + </message> + <message> + <source>&Sample Rate:</source> + <translation>&Punktprøverate:</translation> + </message> + <message> + <source>&Bitrate:</source> + <translation>&Bitrate:</translation> + </message> + <message> + <source>&Quality:</source> + <translation>&Kvalitet:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>PCM16</source> + <translation>PCM16</translation> + </message> + <message> + <source>FLAC</source> + <translation>FLAC</translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation>MPEG lag 2</translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation>MPEG lag 3</translation> + </message> + <message> + <source>OggVorbis</source> + <translation>Ogg Vorbis</translation> + </message> + <message> + <source>VBR</source> + <translation>VBR</translation> + </message> + <message> + <source>32 kbps</source> + <translation>32 kbps</translation> + </message> + <message> + <source>64 kbps</source> + <translation>64 kbps</translation> + </message> + <message> + <source>96 kbps</source> + <translation>96 kbps</translation> + </message> + <message> + <source>128 kbps</source> + <translation>128 kbps</translation> + </message> + <message> + <source>160 kbps</source> + <translation>160 kbps</translation> + </message> + <message> + <source>192 kbps</source> + <translation>192 kbps</translation> + </message> + <message> + <source>224 kbps</source> + <translation>224 kbps</translation> + </message> + <message> + <source>256 kbps</source> + <translation>256 kbps</translation> + </message> + <message> + <source>288 kbps</source> + <translation>288 kbps</translation> + </message> + <message> + <source>320 kbps</source> + <translation>320 kbps</translation> + </message> + <message> + <source>352 kbps</source> + <translation>352 kbps</translation> + </message> + <message> + <source>384 kbps</source> + <translation>384 kbps</translation> + </message> + <message> + <source>416 kbps</source> + <translation>416 kbps</translation> + </message> + <message> + <source>448 kbps</source> + <translation>448 kbps</translation> + </message> + <message> + <source>48 kbps</source> + <translation>48 kbps</translation> + </message> + <message> + <source>56 kbps</source> + <translation>56 kbps</translation> + </message> + <message> + <source>80 kbps</source> + <translation>80 kbps</translation> + </message> + <message> + <source>112 kbps</source> + <translation>112 kbps</translation> + </message> + <message> + <source>40 kbps</source> + <translation>40 kbps</translation> + </message> + <message> + <source>8 kbps</source> + <translation>8 kbps</translation> + </message> + <message> + <source>16 kbps</source> + <translation>16 kbps</translation> + </message> + <message> + <source>24 kbps</source> + <translation>24 kbps</translation> + </message> + <message> + <source>144 kbps</source> + <translation>144 kbps</translation> + </message> +</context> +<context> + <name>RDGetAth</name> + <message> + <source>Enter ATH</source> + <translation>Skriv inn lyttetimar</translation> + </message> + <message> + <source>Enter the agreggate tuning hours (ATH) +figure for the report period. +(Supplied by your streaming provider).</source> + <translation>Skriv inn totalt lyttetimetal +for rapportperioden. +(Oppgjeve av strøymeleverandøren din).</translation> + </message> + <message> + <source>ATH:</source> + <translation>Lyttetimar:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>Invalid ATH</source> + <translation>Ugyldig lyttetimetal</translation> + </message> + <message> + <source>You must provide a valid ATH figure!</source> + <translation>Du må oppgje eit gyldig tal på lyttetimar!</translation> + </message> +</context> +<context> + <name>RDGetPasswd</name> + <message> + <source>Enter Password</source> + <translation>Skriv inn passord</translation> + </message> + <message> + <source>Enter password</source> + <translation>Skriv inn passord</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> +</context> +<context> + <name>RDGpioSelector</name> + <message> + <source>Pin:</source> + <translation>Pin-nummer:</translation> + </message> +</context> +<context> + <name>RDImportAudio</name> + <message> + <source>Import/Export Audio File</source> + <translation>Importer/eksporter lydfil</translation> + </message> + <message> + <source>Import File</source> + <translation>Importer fil</translation> + </message> + <message> + <source>Filename:</source> + <translation>Filnamn:</translation> + </message> + <message> + <source>&Select</source> + <translation>&Vel</translation> + </message> + <message> + <source>Import file metadata</source> + <translation>Importer metadata frå fil</translation> + </message> + <message> + <source>Channels:</source> + <translation>Kanalar:</translation> + </message> + <message> + <source>Autotrim</source> + <translation>Autoskjer</translation> + </message> + <message> + <source>Level:</source> + <translation>Nivå:</translation> + </message> + <message> + <source>dBFS</source> + <translation>dBFS</translation> + </message> + <message> + <source>Export File</source> + <translation>Eksporter fil</translation> + </message> + <message> + <source>Export file metadata</source> + <translation>Eksporter metadata frå fil</translation> + </message> + <message> + <source>Format:</source> + <translation>Format:</translation> + </message> + <message> + <source>S&et</source> + <translation>S&et</translation> + </message> + <message> + <source>Normalize</source> + <translation>Normaliser</translation> + </message> + <message> + <source>&Import</source> + <translation>&Importer</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>Export</source> + <translation>Eksporter</translation> + </message> + <message> + <source>Import</source> + <translation>Importer</translation> + </message> + <message> + <source>Import Audio File</source> + <translation>Importer lydfil</translation> + </message> + <message> + <source>File does not exist!</source> + <translation>Fila finst ikkje!</translation> + </message> + <message> + <source>Cannot open file!</source> + <translation type="obsolete">Greier ikkje opna fila!</translation> + </message> + <message> + <source>Unsupported file type!</source> + <translation type="obsolete">Filtypen er ikkje støtta!</translation> + </message> + <message> + <source>Audio Exists</source> + <translation type="obsolete">Lyd finst</translation> + </message> + <message> + <source>This will overwrite the existing recording. +Do you want to proceed?</source> + <translation type="obsolete">Dette skriv over opptaket ditt. +Vil du halda fram?</translation> + </message> + <message> + <source>Empty Clipboard</source> + <translation type="obsolete">Tom utklyppstavle</translation> + </message> + <message> + <source>Importing this cut will also empty the clipboard. +Do you still want to proceed?</source> + <translation type="obsolete">Viss du importerer dette klyppet, tømer du utklyppstavla. +Vil du halda fram?</translation> + </message> + <message> + <source>Import Complete</source> + <translation>Import ferdig</translation> + </message> + <message> + <source>Import complete!</source> + <translation>Importen er ferdig!</translation> + </message> + <message> + <source>Import Aborted</source> + <translation type="obsolete">Import avbroten</translation> + </message> + <message> + <source>The import has been aborted.</source> + <translation type="obsolete">Importen vart avbroten.</translation> + </message> + <message> + <source>Import Failed</source> + <translation type="obsolete">Importfeil</translation> + </message> + <message> + <source>The importer encountered an error. +Please check your importer configuration and try again.</source> + <translation type="obsolete">Det var ein feil med importen. +Sjå over importoppsettet ditt og prøv att.</translation> + </message> + <message> + <source>File Exists</source> + <translation>Fila finst</translation> + </message> + <message> + <source>The selected file already exists! +Do you want to overwrite it?</source> + <translation>Denne fila finst alt! +Vil du skriva over henne?</translation> + </message> + <message> + <source>File Error</source> + <translation type="obsolete">Filfeil</translation> + </message> + <message> + <source>Cannot open file in archive!</source> + <translation type="obsolete">Greier ikkje opna fila i arkivet!</translation> + </message> + <message> + <source>Unsupported file type in archive!</source> + <translation type="obsolete">Filtypen i arkivet er ikkje støtta!</translation> + </message> + <message> + <source>No Access</source> + <translation type="obsolete">Ingen tilgang</translation> + </message> + <message> + <source>Unable to open the file for writing!</source> + <translation type="obsolete">Greier ikkje opna fila for skriving!</translation> + </message> + <message> + <source>OK</source> + <translation type="obsolete">OK</translation> + </message> + <message> + <source>Export Complete</source> + <translation>Eksport ferdig</translation> + </message> + <message> + <source>Export complete!</source> + <translation>Eksporten er ferdig!</translation> + </message> + <message> + <source>Export Aborted</source> + <translation type="obsolete">Eksport avbroten</translation> + </message> + <message> + <source>The export has been aborted.</source> + <translation type="obsolete">Eksporten vart avbroten.</translation> + </message> + <message> + <source>Export Failed</source> + <translation type="obsolete">Eksportfeil</translation> + </message> + <message> + <source>The Exporter encountered an error. +Please check your configuration and try again.</source> + <translation type="obsolete">Det var ein feil med eksporten. +Sjekk eksportoppsettet ditt og prøv att.</translation> + </message> + <message> + <source>Export Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Abort</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDIntegerDialog</name> + <message> + <source>Set Value</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished">&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished">&Avbryt</translation> + </message> +</context> +<context> + <name>RDIntegerEdit</name> + <message> + <source>Set Value</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Add</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Delete</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDLicense</name> + <message> + <source>&Close</source> + <translation>Lu&kk</translation> + </message> + <message> + <source>GNU Public License v2</source> + <translation>GNU Public-lisensen, versjon 2</translation> + </message> +</context> +<context> + <name>RDListGroups</name> + <message> + <source>Select Group</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NAME</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation type="unfinished">SKILDRING</translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished">&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished">&Avbryt</translation> + </message> +</context> +<context> + <name>RDListLogs</name> + <message> + <source>Select Log - User: </source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Select Log</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NAME</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation type="unfinished">SKILDRING</translation> + </message> + <message> + <source>SERVICE</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>OK</source> + <translation type="unfinished">OK</translation> + </message> + <message> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDListSelector</name> + <message> + <source>Available Services</source> + <translation>Tilgjengelege tenester</translation> + </message> + <message> + <source>Add >></source> + <translation>Legg til >></translation> + </message> + <message> + <source><< Remove</source> + <translation><< Fjern</translation> + </message> + <message> + <source>Active Services</source> + <translation>Aktive tenester</translation> + </message> +</context> +<context> + <name>RDLogLine</name> + <message> + <source>Unknown</source> + <translation type="obsolete">Ukjent</translation> + </message> + <message> + <source>Manual</source> + <translation type="obsolete">Manuell</translation> + </message> + <message> + <source>Play</source> + <translation type="obsolete">Spel</translation> + </message> + <message> + <source>Segue</source> + <translation type="obsolete">Overgang</translation> + </message> + <message> + <source>Time</source> + <translation type="obsolete">Tid</translation> + </message> + <message> + <source>Panel</source> + <translation type="obsolete">Rute</translation> + </message> + <message> + <source>Macro</source> + <translation type="obsolete">Makro</translation> + </message> + <message> + <source>PLAY</source> + <translation type="obsolete">SPEL</translation> + </message> + <message> + <source>SEGUE</source> + <translation type="obsolete">OVERGANG</translation> + </message> + <message> + <source>STOP</source> + <translation type="obsolete">STOPP</translation> + </message> + <message> + <source>OVERLAP</source> + <translation type="obsolete">OVERLAPP</translation> + </message> + <message> + <source>UNKNOWN</source> + <translation type="obsolete">UKJENT</translation> + </message> + <message> + <source>Audio</source> + <translation type="obsolete">Lyd</translation> + </message> + <message> + <source>Marker</source> + <translation type="obsolete">Markør</translation> + </message> + <message> + <source>Open Bracket</source> + <translation type="obsolete">Startklamme</translation> + </message> + <message> + <source>Close Bracket</source> + <translation type="obsolete">Sluttklamme</translation> + </message> + <message> + <source>ChainTo</source> + <translation type="obsolete">LenkTil</translation> + </message> + <message> + <source>Track</source> + <translation type="obsolete">Spor</translation> + </message> + <message> + <source>Link</source> + <translation type="obsolete">Lenkje</translation> + </message> + <message> + <source>Traffic</source> + <translation type="obsolete">Trafikk</translation> + </message> + <message> + <source>Music</source> + <translation type="obsolete">Musikk</translation> + </message> + <message> + <source>RDLogManager</source> + <translation type="obsolete">RDLoggredigering</translation> + </message> + <message> + <source>Tracker</source> + <translation type="obsolete">Sporleggjar</translation> + </message> +</context> +<context> + <name>RDPanelButton</name> + <message> + <source>No Audio</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDPasswd</name> + <message> + <source>Change Password</source> + <translation>Endre passord</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Avbryt</translation> + </message> + <message> + <source>&Password:</source> + <translation>&Passord:</translation> + </message> + <message> + <source>C&onfirm:</source> + <translation>&Stadfest:</translation> + </message> + <message> + <source>Password Mismatch</source> + <translation>Passorda er ikkje like</translation> + </message> + <message> + <source>The passwords don't match, +please try again!</source> + <translation>Passorda dine er ikkje like, +prøv ein gong til!</translation> + </message> + <message> + <source>OK</source> + <translation>OK</translation> + </message> +</context> +<context> + <name>RDRecording</name> + <message> + <source>Recording</source> + <translation type="obsolete">Opptak</translation> + </message> + <message> + <source>Macro Event</source> + <translation type="obsolete">Makro-hending</translation> + </message> + <message> + <source>Switch Event</source> + <translation type="obsolete">Byte-hending</translation> + </message> + <message> + <source>Playout</source> + <translation type="obsolete">Spel ut</translation> + </message> + <message> + <source>Download</source> + <translation type="obsolete">Last ned</translation> + </message> + <message> + <source>Upload</source> + <translation type="obsolete">Last opp</translation> + </message> +</context> +<context> + <name>RDReport</name> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation type="obsolete">CBSI DeltaFlex Traffic Reconciliation v2.01</translation> + </message> + <message> + <source>Text Log</source> + <translation type="obsolete">Tekstlogg</translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation type="obsolete">ASCAP/BMI elektronisk musikkrapport</translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation type="obsolete">Teknisk utspelingsrapport</translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation type="obsolete">SoundExchange Statutory License-rapport</translation> + </message> + <message> + <source>Unknown</source> + <translation type="obsolete">Ukjent</translation> + </message> + <message> + <source>Other</source> + <translation type="obsolete">Annan</translation> + </message> + <message> + <source>AM</source> + <translation type="obsolete">AM</translation> + </message> + <message> + <source>FM</source> + <translation type="obsolete">FM</translation> + </message> + <message> + <source>Report complete!</source> + <translation type="obsolete">Rapport ferdig!</translation> + </message> + <message> + <source>Report canceled!</source> + <translation type="obsolete">Rapport avbroten!</translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation type="obsolete">Greidde ikkje opna rapportfil!</translation> + </message> +</context> +<context> + <name>RDSoundPanel</name> + <message> + <source>Play All</source> + <translation>Spel alle</translation> + </message> + <message> + <source>Play Hook</source> + <translation>Spel knagg</translation> + </message> + <message> + <source>Reset</source> + <translation>Nullstill</translation> + </message> + <message> + <source>All</source> + <translation>Alle</translation> + </message> + <message> + <source>Setup</source> + <translation>Oppsett</translation> + </message> + <message> + <source>Cart</source> + <translation>Korg</translation> + </message> + <message> + <source>Panel</source> + <translation>Rute</translation> + </message> +</context> +<context> + <name>RDSqlDatabaseStatus</name> + <message> + <source>Database connection restored.</source> + <translation>Databasetilkoplinga er gjenoppretta.</translation> + </message> + <message> + <source>Database connection failed : </source> + <translation>Feil med databasetilkoplinga: </translation> + </message> +</context> +<context> + <name>RDStereoMeter</name> + <message> + <source>L</source> + <translation>V</translation> + </message> + <message> + <source>R</source> + <translation>H</translation> + </message> + <message> + <source>CLIP</source> + <translation>KLYPP</translation> + </message> +</context> +<context> + <name>RDSvc</name> + <message> + <source>The following events were not placed: +</source> + <translation>Desse hendingane vart ikkje plasserte: +</translation> + </message> + <message> + <source>[unknown cart]</source> + <translation>[ukjend korg]</translation> + </message> + <message> + <source>Autofill Errors +</source> + <translation type="obsolete">Autofyll-feil +</translation> + </message> + <message> + <source>Event Fill Errors +</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/lib/librd_pt_BR.ts b/lib/librd_pt_BR.ts new file mode 100644 index 00000000..a90bccd5 --- /dev/null +++ b/lib/librd_pt_BR.ts @@ -0,0 +1,2131 @@ +<!DOCTYPE TS><TS> +<context> + <name></name> + <message> + <source>UNKNOWN CUT</source> + <translation type="obsolete">CONTEÚDO DESCONHECIDO</translation> + </message> +</context> +<context> + <name>@default</name> + <message> + <source>ALL</source> + <translation type="obsolete">TODOS</translation> + </message> +</context> +<context> + <name>QObject</name> + <message> + <source>Couldn't initialize QSql driver!</source> + <translation>Não foi possível inicializar driver QSql !</translation> + </message> + <message> + <source>Couldn't open mySQL connection!</source> + <translation>Não foi possível conetar ao mySQL !</translation> + </message> + <message> + <source>Sequentially</source> + <translation type="unfinished">Sequencialmente</translation> + </message> + <message> + <source>Randomly</source> + <translation type="unfinished">Randomicamente</translation> + </message> + <message> + <source>Unknown</source> + <translation type="unfinished">Desconhecido</translation> + </message> + <message> + <source>Feature</source> + <translation type="unfinished">Vários</translation> + </message> + <message> + <source>Theme Open</source> + <translation type="unfinished">Tema de Abertura</translation> + </message> + <message> + <source>Theme Close</source> + <translation type="unfinished">Tema de Fechamento</translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation type="unfinished">Tema de Abertura/Fechamento</translation> + </message> + <message> + <source>Background</source> + <translation type="unfinished">BG</translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation type="unfinished">Comercial/Vinheta/Promo</translation> + </message> + <message> + <source>UNKNOWN CUT</source> + <translation type="unfinished">CONTEÚDO DESCONHECIDO</translation> + </message> + <message> + <source>Manual</source> + <translation type="unfinished">Manual</translation> + </message> + <message> + <source>Play</source> + <translation type="unfinished">Simples</translation> + </message> + <message> + <source>Segue</source> + <translation type="unfinished">Sobre</translation> + </message> + <message> + <source>Time</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Panel</source> + <translation type="unfinished">Painel</translation> + </message> + <message> + <source>Macro</source> + <translation type="unfinished">Macro</translation> + </message> + <message> + <source>PLAY</source> + <translation type="unfinished">SIMPLES<byte value="x9"/></translation> + </message> + <message> + <source>SEGUE</source> + <translation type="unfinished">SOBRE</translation> + </message> + <message> + <source>STOP</source> + <translation type="unfinished">PARE</translation> + </message> + <message> + <source>UNKNOWN</source> + <translation type="unfinished">DESCONHECIDO</translation> + </message> + <message> + <source>Audio</source> + <translation type="unfinished">Áudio</translation> + </message> + <message> + <source>Marker</source> + <translation type="unfinished">Marcador</translation> + </message> + <message> + <source>Open Bracket</source> + <translation type="unfinished">Abrir Colchetes</translation> + </message> + <message> + <source>Close Bracket</source> + <translation type="unfinished">FEchar Colchetes</translation> + </message> + <message> + <source>ChainTo</source> + <translation type="unfinished">Corrente para</translation> + </message> + <message> + <source>Track</source> + <translation type="unfinished">Pista</translation> + </message> + <message> + <source>Link</source> + <translation type="unfinished">Link</translation> + </message> + <message> + <source>Traffic</source> + <translation type="unfinished">Tráfego</translation> + </message> + <message> + <source>Music</source> + <translation type="unfinished">Música</translation> + </message> + <message> + <source>RDLogManager</source> + <translation type="unfinished">RDControle</translation> + </message> + <message> + <source>Tracker</source> + <translation type="unfinished">Busca</translation> + </message> + <message> + <source>Recording</source> + <translation type="unfinished">Gravação</translation> + </message> + <message> + <source>Macro Event</source> + <translation type="unfinished">Eventp Macro</translation> + </message> + <message> + <source>Switch Event</source> + <translation type="unfinished">Evento de Switch</translation> + </message> + <message> + <source>Playout</source> + <translation type="unfinished">Execução</translation> + </message> + <message> + <source>Download</source> + <translation type="unfinished">Download</translation> + </message> + <message> + <source>Upload</source> + <translation type="unfinished">Upload</translation> + </message> + <message> + <source>Ok</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Short Length</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Low Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>High Level</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Downloading</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Uploading</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Server Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Internal Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Interrupted</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Playing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Waiting</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Device Busy</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>No Such Cart/Cut</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown Audio Format</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation type="unfinished">CBSI DeltaFlex Traffic Reconciliation v2.01</translation> + </message> + <message> + <source>Text Log</source> + <translation type="unfinished">Texto</translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation type="unfinished">ASCAP/BMI Electronic Music Report</translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation type="unfinished">Relatório Técnico de Execução</translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation type="unfinished">SoundExchange Statutory License Report</translation> + </message> + <message> + <source>RadioTraffic.com Traffic Reconciliation</source> + <translation type="unfinished">RadioTraffic.com Traffic Reconciliation</translation> + </message> + <message> + <source>VisualTraffic Reconciliation</source> + <translation type="unfinished">VisualTraffic Reconciliation</translation> + </message> + <message> + <source>CounterPoint Traffic Reconciliation</source> + <translation type="unfinished">CounterPoint Traffic Reconciliation</translation> + </message> + <message> + <source>Music1 Reconciliation</source> + <translation type="unfinished">Music1 Reconciliation</translation> + </message> + <message> + <source>Other</source> + <translation type="unfinished">Outros</translation> + </message> + <message> + <source>AM</source> + <translation type="unfinished">AM</translation> + </message> + <message> + <source>FM</source> + <translation type="unfinished">FM</translation> + </message> + <message> + <source>Report complete!</source> + <translation type="unfinished">Relatório Completo</translation> + </message> + <message> + <source>Report canceled!</source> + <translation type="unfinished">Relatório Cancelado</translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation type="unfinished">Não foi possível abrir o Relatório!</translation> + </message> + <message> + <source>Music Summary</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>WideOrbit Traffic Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unknown Position</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Left</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Center</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Top Right</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Left</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Center</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Bottom Right</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NPR/DS SoundExchange Report</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 1</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Main Log Output 2</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel First Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 1 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Aux Log 2 Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Second Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Third Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fourth Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Audition/Cue Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Channel</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Sound Panel Fifth and Later Play Output</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>invalid SQL or failed DB connection</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>All</source> + <translation type="unfinished">Todos</translation> + </message> + <message> + <source>Relative</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Hard</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>NaturalLog Reconciliation</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>LiveAssist</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Automatic</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Previous</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Classical Music Playout</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>reserved</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDAddCart</name> + <message> + <source>&Group:</source> + <translation>&Grupo:</translation> + </message> + <message> + <source>&New Cart Number:</source> + <translation>&Número:</translation> + </message> + <message> + <source>&New Cart Type:</source> + <translation>&Tipo:</translation> + </message> + <message> + <source>Audio</source> + <translation>Áudio</translation> + </message> + <message> + <source>Macro</source> + <translation>Macro</translation> + </message> + <message> + <source>[new cart]</source> + <translation>[novo cartão]</translation> + </message> + <message> + <source>&New Cart Title:</source> + <translation>&Título:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>No Available Cart Numbers</source> + <translation>Não há Números de Cartões Disponíveis</translation> + </message> + <message> + <source>There are no more available cart numbers for the group!</source> + <translation>Não há mais números de Cartões disponíveis para este Grupo!</translation> + </message> + <message> + <source>Invalid Number</source> + <translation>Número Inválido</translation> + </message> + <message> + <source>Invalid Cart Number!</source> + <translation>Número de Cartão Inválido!</translation> + </message> + <message> + <source>Title Required</source> + <translation>O Título é necessário</translation> + </message> + <message> + <source>You must enter a cart title!</source> + <translation>Você deve dar um título ao cartão!</translation> + </message> + <message> + <source>Duplicate Title</source> + <translation>Título DUplicado</translation> + </message> + <message> + <source>The cart title must be unique!</source> + <translation>O Título do Cartão deve ser único!</translation> + </message> + <message> + <source>The cart number is outside of the permitted range for this group!</source> + <translation>O número do Cartão está fora da variação permitida para este Grupo!</translation> + </message> + <message> + <source>Cart Exists</source> + <translation>O Cartão Existe</translation> + </message> + <message> + <source>This cart already exists.</source> + <translation>Este Cartão já Existe.</translation> + </message> +</context> +<context> + <name>RDAddLog</name> + <message> + <source>Create Log</source> + <translation>Criar Lista</translation> + </message> + <message> + <source>&New Log Name:</source> + <translation>&Nome da &Lista:</translation> + </message> + <message> + <source>&Service:</source> + <translation>&Serviço</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>RDLogEdit</source> + <translation>RDListas</translation> + </message> + <message> + <source>The name is invalid!</source> + <translation type="obsolete">O Nome é Inválido!</translation> + </message> + <message> + <source>The service is invalid!</source> + <translation>O Serviço é Inválido!</translation> + </message> +</context> +<context> + <name>RDAudioSettingsDialog</name> + <message> + <source>Edit Settings</source> + <translation>Editar Configurações</translation> + </message> + <message> + <source>Default &Format:</source> + <translation>&Formato Padrão:</translation> + </message> + <message> + <source>Default &Channels:</source> + <translation>&Canais Padrão:</translation> + </message> + <message> + <source>Default &Sample Rate:</source> + <translation>&Taxa de Amostragem Padrão:</translation> + </message> + <message> + <source>Default &Bitrate:</source> + <translation>&Taxa de Bits Padrão:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>PCM16</source> + <translation>PCM16</translation> + </message> + <message> + <source>OggVorbis</source> + <translation>OggVorbis</translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation>MPEG Layer 2</translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation>MPEG Layer 3</translation> + </message> +</context> +<context> + <name>RDButtonDialog</name> + <message> + <source>Edit Button</source> + <translation>Editar Botão</translation> + </message> + <message> + <source>Label:</source> + <translation>Mostre:</translation> + </message> + <message> + <source>Cart:</source> + <translation>Cartão:</translation> + </message> + <message> + <source>Set +Cart</source> + <translation>Escolha +Cartão</translation> + </message> + <message> + <source>Clear</source> + <translation>Limpar</translation> + </message> + <message> + <source>Set +Color</source> + <translation>Escolha +Cor</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>NOT FOUND</source> + <translation>NÃO ENCONTRADO</translation> + </message> +</context> +<context> + <name>RDCardSelector</name> + <message> + <source>Card:</source> + <translation>Placa:</translation> + </message> + <message> + <source>Port:</source> + <translation>Porta:</translation> + </message> +</context> +<context> + <name>RDCart</name> + <message> + <source>Sequentially</source> + <translation type="obsolete">Sequencialmente</translation> + </message> + <message> + <source>Randomly</source> + <translation type="obsolete">Randomicamente</translation> + </message> + <message> + <source>Unknown</source> + <translation type="obsolete">Desconhecido</translation> + </message> + <message> + <source>Feature</source> + <translation type="obsolete">Vários</translation> + </message> + <message> + <source>Theme Open</source> + <translation type="obsolete">Tema de Abertura</translation> + </message> + <message> + <source>Theme Close</source> + <translation type="obsolete">Tema de Fechamento</translation> + </message> + <message> + <source>Theme Open/Close</source> + <translation type="obsolete">Tema de Abertura/Fechamento</translation> + </message> + <message> + <source>Background</source> + <translation type="obsolete">BG</translation> + </message> + <message> + <source>Commercial/Jingle/Promo</source> + <translation type="obsolete">Comercial/Vinheta/Promo</translation> + </message> +</context> +<context> + <name>RDCartDialog</name> + <message> + <source>Select Cart</source> + <translation>Selecionar Cartão</translation> + </message> + <message> + <source>Please Wait...</source> + <translation>Por Favor, Espere...</translation> + </message> + <message> + <source>Cart Filter:</source> + <translation>Filtro:</translation> + </message> + <message> + <source>&Search</source> + <translation>&Procurar</translation> + </message> + <message> + <source>C&lear</source> + <translation>&Limpar</translation> + </message> + <message> + <source>Group:</source> + <translation>Grupo:</translation> + </message> + <message> + <source>NUMBER</source> + <translation>NÚMERO</translation> + </message> + <message> + <source>LENGTH</source> + <translation>DURAÇÃO</translation> + </message> + <message> + <source>TITLE</source> + <translation>TÍTULO</translation> + </message> + <message> + <source>ARTIST</source> + <translation>ARTISTA</translation> + </message> + <message> + <source>GROUP</source> + <translation>GRUPO</translation> + </message> + <message> + <source>CLIENT</source> + <translation>CLIENTE</translation> + </message> + <message> + <source>AGENCY</source> + <translation>AGÊNCIA</translation> + </message> + <message> + <source>USER DEF</source> + <translation>USO GENERICO</translation> + </message> + <message> + <source>START</source> + <translation>INÍCIO</translation> + </message> + <message> + <source>END</source> + <translation>FINAL</translation> + </message> + <message> + <source>Send to +&Editor</source> + <translation>Mandar ao +&Editor</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>ALL</source> + <translation>TODOS</translation> + </message> + <message> + <source>Show Only First</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Matches</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Load From +&File</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Cart Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to create temporary cart for import!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to get temporary cart number for import!</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Imported from</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Importing...</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Importing</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>COMPOSER</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>CONDUCTOR</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEdit</name> + <message> + <source>&Audition</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Pause</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Stop</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Start</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>End</source> + <translation type="unfinished">Fim</translation> + </message> + <message> + <source>&Recue</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDCueEditDialog</name> + <message> + <source>Set Cue Point</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&OK</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>&Cancel</source> + <translation type="unfinished">&Cancelar</translation> + </message> +</context> +<context> + <name>RDCutDialog</name> + <message> + <source>Select Cut</source> + <translation>Selecionar Conteúdo</translation> + </message> + <message> + <source>Please Wait...</source> + <translation>Por Favor, Espere...</translation> + </message> + <message> + <source>Cart Filter:</source> + <translation>Filtro de Cartões:</translation> + </message> + <message> + <source>&Search</source> + <translation>&Procurar</translation> + </message> + <message> + <source>C&lear</source> + <translation>&Limpar</translation> + </message> + <message> + <source>Group:</source> + <translation>Grupo:</translation> + </message> + <message> + <source>Carts</source> + <translation>Cartão:</translation> + </message> + <message> + <source>NUMBER</source> + <translation>NÚMERO</translation> + </message> + <message> + <source>TITLE</source> + <translation>TÍTULO</translation> + </message> + <message> + <source>GROUP</source> + <translation>GRUPO</translation> + </message> + <message> + <source>Cuts</source> + <translation>Conteúdos</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>DESCRIÇÃO</translation> + </message> + <message> + <source>&Add New +Cart</source> + <translation>&Novo +Cartão</translation> + </message> + <message> + <source>&Clear</source> + <translation>&Limpar</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>ALL</source> + <translation>TODOS</translation> + </message> + <message> + <source>Show Only First</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Matches</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Scheduler Code:</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDDateDialog</name> + <message> + <source>Select Date</source> + <translation>Selecione Data</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> +</context> +<context> + <name>RDDatePicker</name> + <message> + <source>Mo</source> + <translation>Seg</translation> + </message> + <message> + <source>Tu</source> + <translation>Ter</translation> + </message> + <message> + <source>We</source> + <translation>Qua</translation> + </message> + <message> + <source>Th</source> + <translation>Qui</translation> + </message> + <message> + <source>Fr</source> + <translation>Sex</translation> + </message> + <message> + <source>Sa</source> + <translation>Sab</translation> + </message> + <message> + <source>Su</source> + <translation>Dom</translation> + </message> +</context> +<context> + <name>RDEditAudio</name> + <message> + <source>&Save</source> + <translation>&Salvar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>Amplitude</source> + <translation>Amplitude</translation> + </message> + <message> + <source>Zoom +In</source> + <translation>Zoom +In</translation> + </message> + <message> + <source>Zoom +Out</source> + <translation>Zoom +Out</translation> + </message> + <message> + <source>Time</source> + <translation>Tempo</translation> + </message> + <message> + <source>Full +In</source> + <translation>Zoom +Máximo</translation> + </message> + <message> + <source>Full +Out</source> + <translation>Zoom +Mínimo</translation> + </message> + <message> + <source>Goto</source> + <translation>Ir Até</translation> + </message> + <message> + <source>Cursor</source> + <translation>Cursor</translation> + </message> + <message> + <source>Home</source> + <translation>Casa</translation> + </message> + <message> + <source>End</source> + <translation>Fim</translation> + </message> + <message> + <source>Cut +Start</source> + <translation>Início</translation> + </message> + <message> + <source>Cut +End</source> + <translation>Fim</translation> + </message> + <message> + <source>Talk +Start</source> + <translation>Início +Locutor</translation> + </message> + <message> + <source>Segue +Start</source> + <translation>Sobre +Começa</translation> + </message> + <message> + <source>Segue +End</source> + <translation>Sobre +Termina</translation> + </message> + <message> + <source>Fade +Up</source> + <translation>Fade +Up</translation> + </message> + <message> + <source>Hook +Start</source> + <translation>Trecho +Começa</translation> + </message> + <message> + <source>Hook +End</source> + <translation>Trecho +Termina</translation> + </message> + <message> + <source> dB</source> + <translation> dB</translation> + </message> + <message> + <source>Threshold</source> + <translation>Valor Mínimo</translation> + </message> + <message> + <source>Trim +Start</source> + <translation>Corte +Começa</translation> + </message> + <message> + <source>Trim +End</source> + <translation>Corte +Termina</translation> + </message> + <message> + <source>Cut Gain</source> + <translation>Ganho</translation> + </message> + <message> + <source>Remove +Marker</source> + <translation>Remover +Marcador</translation> + </message> + <message> + <source>No Fade on Segue Out</source> + <translation>Sem Fade na Saída</translation> + </message> + <message> + <source>Position</source> + <translation>Posição</translation> + </message> + <message> + <source>Length</source> + <translation>Duração</translation> + </message> + <message> + <source>Delete Talk Markers</source> + <translation>Deletar Marcadores de Locução</translation> + </message> + <message> + <source>Delete Segue Markers</source> + <translation>Deletar Marcadores de Sobre</translation> + </message> + <message> + <source>Delete Hook Markers</source> + <translation>Deletar Marcadores de Trechos</translation> + </message> + <message> + <source>Delete Fade Up Marker</source> + <translation>Deletar Marcadores de Fade Up</translation> + </message> + <message> + <source>Delete Fade Down Marker</source> + <translation>Deletar Marcadores de Fade Down</translation> + </message> + <message> + <source>dB</source> + <translation>dB</translation> + </message> + <message> + <source><none></source> + <translation><nenhum></translation> + </message> + <message> + <source>Cut</source> + <translation>Conteúdo</translation> + </message> + <message> + <source>Talk</source> + <translation>Fim Locutor</translation> + </message> + <message> + <source>Segue</source> + <translation>Sobre</translation> + </message> + <message> + <source>Hook</source> + <translation>Trecho +</translation> + </message> + <message> + <source>Fade Up</source> + <translation>Fade Up</translation> + </message> + <message> + <source>Fade Down</source> + <translation>Fade Down</translation> + </message> + <message> + <source>L</source> + <translation>L</translation> + </message> + <message> + <source>R</source> + <translation>R</translation> + </message> + <message> + <source>Rivendell Web Service</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Unable to download peak data, error was: +"</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Edit Audio</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Marker Warning</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Less than half of the audio is playable with these marker settings. +Are you sure you want to save?</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>More than half of the audio will be faded with these marker settings. +Are you sure you want to save?</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDEditPanelName</name> + <message> + <source>Edit Panel Name</source> + <translation>Editar nome do Painel</translation> + </message> + <message> + <source>Panel &Name:</source> + <translation>&Nome do Painel:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK +</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> +</context> +<context> + <name>RDExceptionDialog</name> + <message> + <source>Rivendell Exception Report</source> + <translation>Relatório de Exceções do Rivendell</translation> + </message> + <message> + <source>&Save</source> + <translation>&Salvar</translation> + </message> + <message> + <source>&Close</source> + <translation>&Fechar</translation> + </message> + <message> + <source>Text (*.txt *.TXT) +All Files (*.*)</source> + <translation>Textos (*.txt *.TXT) +Todos os Arquivos (*.*)</translation> + </message> + <message> + <source>Export File</source> + <translation>Exportar Arquivo</translation> + </message> + <message> + <source>The file</source> + <translation>O Arquivo</translation> + </message> + <message> + <source>already exists! +Overwrite?</source> + <translation>já Existe! +Sobreescrever?</translation> + </message> + <message> + <source>File Exists</source> + <translation>Arquivo Existente</translation> + </message> + <message> + <source>Unable to open file</source> + <translation>Não foi Possível abrir o arquivo</translation> + </message> + <message> + <source>for writing!</source> + <translation>para escrita!</translation> + </message> + <message> + <source>File Error</source> + <translation>Erro no Arquivo</translation> + </message> +</context> +<context> + <name>RDExportSettingsDialog</name> + <message> + <source>Edit Export Settings</source> + <translation>Editar Configuração de Exportação</translation> + </message> + <message> + <source>&Channels:</source> + <translation>&Canais:</translation> + </message> + <message> + <source>&Sample Rate:</source> + <translation>&Taxa de Amostragem:</translation> + </message> + <message> + <source>&Bitrate:</source> + <translation>&Taxa de Bits:</translation> + </message> + <message> + <source>&Quality:</source> + <translation>&Qualidade:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>PCM16</source> + <translation>PCM16</translation> + </message> + <message> + <source>FLAC</source> + <translation>FLAC</translation> + </message> + <message> + <source>MPEG Layer 2</source> + <translation>MPEG Layer 2</translation> + </message> + <message> + <source>MPEG Layer 3</source> + <translation>MPEG Layer 3</translation> + </message> + <message> + <source>OggVorbis</source> + <translation>OggVorbis</translation> + </message> + <message> + <source>VBR</source> + <translation>VBR</translation> + </message> + <message> + <source>32 kbps</source> + <translation>32 kbps</translation> + </message> + <message> + <source>64 kbps</source> + <translation>64 kbps</translation> + </message> + <message> + <source>96 kbps</source> + <translation>96 kbps</translation> + </message> + <message> + <source>128 kbps</source> + <translation>128 kbps</translation> + </message> + <message> + <source>160 kbps</source> + <translation>160 kbps</translation> + </message> + <message> + <source>192 kbps</source> + <translation>192 kbps</translation> + </message> + <message> + <source>224 kbps</source> + <translation>224 kbps</translation> + </message> + <message> + <source>256 kbps</source> + <translation>256 kbps</translation> + </message> + <message> + <source>288 kbps</source> + <translation>288 kbps</translation> + </message> + <message> + <source>320 kbps</source> + <translation>320 kbps</translation> + </message> + <message> + <source>352 kbps</source> + <translation>352 kbps</translation> + </message> + <message> + <source>384 kbps</source> + <translation>384 kbps</translation> + </message> + <message> + <source>416 kbps</source> + <translation>416 kbps</translation> + </message> + <message> + <source>448 kbps</source> + <translation>448 kbps</translation> + </message> + <message> + <source>48 kbps</source> + <translation>48 kbps</translation> + </message> + <message> + <source>56 kbps</source> + <translation>56 kbps</translation> + </message> + <message> + <source>80 kbps</source> + <translation>80 kbps</translation> + </message> + <message> + <source>112 kbps</source> + <translation>112 kbps</translation> + </message> + <message> + <source>40 kbps</source> + <translation>40 kbps</translation> + </message> + <message> + <source>8 kbps</source> + <translation>8 kbps</translation> + </message> + <message> + <source>16 kbps</source> + <translation>16 kbps</translation> + </message> + <message> + <source>24 kbps</source> + <translation>24 kbps</translation> + </message> + <message> + <source>144 kbps</source> + <translation>144 kbps</translation> + </message> +</context> +<context> + <name>RDGetAth</name> + <message> + <source>Enter ATH</source> + <translation>Digitare ATH</translation> + </message> + <message> + <source>Enter the agreggate tuning hours (ATH) +figure for the report period. +(Supplied by your streaming provider).</source> + <translation>Digitar a figura de 'agreggate tuning hours (ATH)' +para o período do relatório +(Disponibilizado pelo Servidor de Streaming).</translation> + </message> + <message> + <source>ATH:</source> + <translation>ATH:</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>Invalid ATH</source> + <translation>ATH Inválido</translation> + </message> + <message> + <source>You must provide a valid ATH figure!</source> + <translation>Você deve dar uma figura de ATH válida!</translation> + </message> +</context> +<context> + <name>RDGetPasswd</name> + <message> + <source>Enter Password</source> + <translation>Digitar Senha</translation> + </message> + <message> + <source>Enter password</source> + <translation>Digitar Senha</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> +</context> +<context> + <name>RDGpioSelector</name> + <message> + <source>Pin:</source> + <translation>Pin:</translation> + </message> +</context> +<context> + <name>RDImportAudio</name> + <message> + <source>Import/Export Audio File</source> + <translation>Importar/Exportar Arquivo de Áudio</translation> + </message> + <message> + <source>Import File</source> + <translation>Importar Arquivo</translation> + </message> + <message> + <source>Filename:</source> + <translation>Arquivo:</translation> + </message> + <message> + <source>&Select</source> + <translation>&Selecionar</translation> + </message> + <message> + <source>Import file metadata</source> + <translation>Importar metadados do arquivo</translation> + </message> + <message> + <source>Channels:</source> + <translation>Canais:</translation> + </message> + <message> + <source>Autotrim</source> + <translation>AutoCorte</translation> + </message> + <message> + <source>Level:</source> + <translation>Nível:</translation> + </message> + <message> + <source>dBFS</source> + <translation>dBFS</translation> + </message> + <message> + <source>Export File</source> + <translation>Exportar Arquivo</translation> + </message> + <message> + <source>Export file metadata</source> + <translation>Exportar matadados do arquivo</translation> + </message> + <message> + <source>Format:</source> + <translation>Formato:</translation> + </message> + <message> + <source>S&et</source> + <translation>&Selecionar</translation> + </message> + <message> + <source>Normalize</source> + <translation>Normalizar</translation> + </message> + <message> + <source>&Import</source> + <translation>&Importar</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>Export</source> + <translation>Exportar</translation> + </message> + <message> + <source>Import</source> + <translation>Importar</translation> + </message> + <message> + <source>Import Audio File</source> + <translation>Importar Arquivo de Áudio</translation> + </message> + <message> + <source>File does not exist!</source> + <translation>Arquivo não existe!</translation> + </message> + <message> + <source>Cannot open file!</source> + <translation type="obsolete">Não foi possível abrir o arquivo!</translation> + </message> + <message> + <source>Unsupported file type!</source> + <translation type="obsolete">Tipo de Arquivo sem suporte!</translation> + </message> + <message> + <source>Audio Exists</source> + <translation type="obsolete">Áudio Existe</translation> + </message> + <message> + <source>This will overwrite the existing recording. +Do you want to proceed?</source> + <translation type="obsolete">Isto sobreescreverá a gravação existente. +Você quer continuar?</translation> + </message> + <message> + <source>Empty Clipboard</source> + <translation type="obsolete">Clipboard Vazio</translation> + </message> + <message> + <source>Importing this cut will also empty the clipboard. +Do you still want to proceed?</source> + <translation type="obsolete">Importar este Conteúdo também esvaziará o clipboard. +Você quer continuar?</translation> + </message> + <message> + <source>Import Complete</source> + <translation>Importação Completa</translation> + </message> + <message> + <source>Import complete!</source> + <translation>Importação Completa!</translation> + </message> + <message> + <source>Import Aborted</source> + <translation type="obsolete">Importação Abortada</translation> + </message> + <message> + <source>The import has been aborted.</source> + <translation type="obsolete">A Importação foi abortada.</translation> + </message> + <message> + <source>Import Failed</source> + <translation type="obsolete">Importação Falhou</translation> + </message> + <message> + <source>The importer encountered an error. +Please check your importer configuration and try again.</source> + <translation type="obsolete">O importador encontrou um erro. +Por Favor, cheque suas configurações e tenbte outra vez.</translation> + </message> + <message> + <source>File Exists</source> + <translation>Arquivo Existente</translation> + </message> + <message> + <source>The selected file already exists! +Do you want to overwrite it?</source> + <translation>O arquivo selecionado já existe! +Você quer sobreescrevê-lo?</translation> + </message> + <message> + <source>File Error</source> + <translation type="obsolete">Erro no Arquivo</translation> + </message> + <message> + <source>Cannot open file in archive!</source> + <translation type="obsolete">Não foi possível abrir arquivo no Acervo!</translation> + </message> + <message> + <source>Unsupported file type in archive!</source> + <translation type="obsolete">Arquivo sem Suporte no Acervo!</translation> + </message> + <message> + <source>No Access</source> + <translation type="obsolete">Sem Acesso</translation> + </message> + <message> + <source>Unable to open the file for writing!</source> + <translation type="obsolete">Não foi possível abrir o arquivo para escrita!</translation> + </message> + <message> + <source>OK</source> + <translation type="obsolete">OK</translation> + </message> + <message> + <source>Export Complete</source> + <translation>Exportação Completa</translation> + </message> + <message> + <source>Export complete!</source> + <translation>Exportação Completa!</translation> + </message> + <message> + <source>Export Aborted</source> + <translation type="obsolete">Exportação Abortada</translation> + </message> + <message> + <source>The export has been aborted.</source> + <translation type="obsolete">A Exportação foi abortada.</translation> + </message> + <message> + <source>Export Failed</source> + <translation type="obsolete">Exportação Falhou</translation> + </message> + <message> + <source>The Exporter encountered an error. +Please check your configuration and try again.</source> + <translation type="obsolete">O Exportador encontrou um erro. +Por Favor, cheque suas configurações e tenbte outra vez.</translation> + </message> + <message> + <source>Abort</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Import Error</source> + <translation type="unfinished"></translation> + </message> + <message> + <source>Export Error</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDIntegerDialog</name> + <message> + <source>Set Value</source> + <translation>Selecionar Valor</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> +</context> +<context> + <name>RDIntegerEdit</name> + <message> + <source>Set Value</source> + <translation>Selecionar Valor</translation> + </message> + <message> + <source>Add</source> + <translation>Adicionar</translation> + </message> + <message> + <source>Delete</source> + <translation>Deletar</translation> + </message> +</context> +<context> + <name>RDLicense</name> + <message> + <source>&Close</source> + <translation>&Fechar</translation> + </message> + <message> + <source>GNU Public License v2</source> + <translation>GNU Public License v2</translation> + </message> +</context> +<context> + <name>RDListGroups</name> + <message> + <source>Select Group</source> + <translation>Selecionar Grupo</translation> + </message> + <message> + <source>NAME</source> + <translation>NOME</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>DESCRIÇÃO</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> +</context> +<context> + <name>RDListLogs</name> + <message> + <source>Select Log - User: </source> + <translation>Selecionar Lista - Usuario: </translation> + </message> + <message> + <source>Select Log</source> + <translation>Selecione Lista</translation> + </message> + <message> + <source>NAME</source> + <translation>NOME</translation> + </message> + <message> + <source>DESCRIPTION</source> + <translation>DESCRIÇÃO</translation> + </message> + <message> + <source>SERVICE</source> + <translation>SERVIÇO</translation> + </message> + <message> + <source>OK</source> + <translation>OK</translation> + </message> + <message> + <source>Cancel</source> + <translation>Cancelar</translation> + </message> +</context> +<context> + <name>RDListSelector</name> + <message> + <source>Available Services</source> + <translation>Serviços Disponíveis</translation> + </message> + <message> + <source>Add >></source> + <translation>Add >></translation> + </message> + <message> + <source><< Remove</source> + <translation><< Remover +</translation> + </message> + <message> + <source>Active Services</source> + <translation>Serviços Ativos</translation> + </message> +</context> +<context> + <name>RDLogLine</name> + <message> + <source>Unknown</source> + <translation type="obsolete">Desconhecido</translation> + </message> + <message> + <source>Manual</source> + <translation type="obsolete">Manual</translation> + </message> + <message> + <source>Play</source> + <translation type="obsolete">Simples</translation> + </message> + <message> + <source>Segue</source> + <translation type="obsolete">Sobre</translation> + </message> + <message> + <source>Time</source> + <translation type="obsolete">Hora</translation> + </message> + <message> + <source>Panel</source> + <translation type="obsolete">Painel</translation> + </message> + <message> + <source>Macro</source> + <translation type="obsolete">Macro</translation> + </message> + <message> + <source>PLAY</source> + <translation type="obsolete">SIMPLES<byte value="x9"/></translation> + </message> + <message> + <source>SEGUE</source> + <translation type="obsolete">SOBRE</translation> + </message> + <message> + <source>STOP</source> + <translation type="obsolete">PARE</translation> + </message> + <message> + <source>UNKNOWN</source> + <translation type="obsolete">DESCONHECIDO</translation> + </message> + <message> + <source>Audio</source> + <translation type="obsolete">Áudio</translation> + </message> + <message> + <source>Marker</source> + <translation type="obsolete">Marcador</translation> + </message> + <message> + <source>Open Bracket</source> + <translation type="obsolete">Abrir Colchetes</translation> + </message> + <message> + <source>Close Bracket</source> + <translation type="obsolete">FEchar Colchetes</translation> + </message> + <message> + <source>ChainTo</source> + <translation type="obsolete">Corrente para</translation> + </message> + <message> + <source>Track</source> + <translation type="obsolete">Pista</translation> + </message> + <message> + <source>Link</source> + <translation type="obsolete">Link</translation> + </message> + <message> + <source>Traffic</source> + <translation type="obsolete">Tráfego</translation> + </message> + <message> + <source>Music</source> + <translation type="obsolete">Música</translation> + </message> + <message> + <source>RDLogManager</source> + <translation type="obsolete">RDControle</translation> + </message> + <message> + <source>Tracker</source> + <translation type="obsolete">Busca</translation> + </message> +</context> +<context> + <name>RDPanelButton</name> + <message> + <source>No Audio</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>RDPasswd</name> + <message> + <source>Change Password</source> + <translation>Alterar Senha</translation> + </message> + <message> + <source>&OK</source> + <translation>&OK</translation> + </message> + <message> + <source>&Cancel</source> + <translation>&Cancelar</translation> + </message> + <message> + <source>&Password:</source> + <translation>&Senha:</translation> + </message> + <message> + <source>C&onfirm:</source> + <translation>&Confirmar</translation> + </message> + <message> + <source>Password Mismatch</source> + <translation>Senha não bateu</translation> + </message> + <message> + <source>The passwords don't match, +please try again!</source> + <translation>As Senhas não batem, +por favor, tente novamente!</translation> + </message> + <message> + <source>OK</source> + <translation>OK</translation> + </message> +</context> +<context> + <name>RDRecording</name> + <message> + <source>Recording</source> + <translation type="obsolete">Gravação</translation> + </message> + <message> + <source>Macro Event</source> + <translation type="obsolete">Eventp Macro</translation> + </message> + <message> + <source>Switch Event</source> + <translation type="obsolete">Evento de Switch</translation> + </message> + <message> + <source>Playout</source> + <translation type="obsolete">Execução</translation> + </message> + <message> + <source>Download</source> + <translation type="obsolete">Download</translation> + </message> + <message> + <source>Upload</source> + <translation type="obsolete">Upload</translation> + </message> +</context> +<context> + <name>RDReport</name> + <message> + <source>CBSI DeltaFlex Traffic Reconciliation v2.01</source> + <translation type="obsolete">CBSI DeltaFlex Traffic Reconciliation v2.01</translation> + </message> + <message> + <source>Text Log</source> + <translation type="obsolete">Texto</translation> + </message> + <message> + <source>ASCAP/BMI Electronic Music Report</source> + <translation type="obsolete">ASCAP/BMI Electronic Music Report</translation> + </message> + <message> + <source>Technical Playout Report</source> + <translation type="obsolete">Relatório Técnico de Execução</translation> + </message> + <message> + <source>SoundExchange Statutory License Report</source> + <translation type="obsolete">SoundExchange Statutory License Report</translation> + </message> + <message> + <source>RadioTraffic.com Traffic Reconciliation</source> + <translation type="obsolete">RadioTraffic.com Traffic Reconciliation</translation> + </message> + <message> + <source>VisualTraffic Reconciliation</source> + <translation type="obsolete">VisualTraffic Reconciliation</translation> + </message> + <message> + <source>CounterPoint Traffic Reconciliation</source> + <translation type="obsolete">CounterPoint Traffic Reconciliation</translation> + </message> + <message> + <source>Music1 Reconciliation</source> + <translation type="obsolete">Music1 Reconciliation</translation> + </message> + <message> + <source>Unknown</source> + <translation type="obsolete">Desconhecido</translation> + </message> + <message> + <source>Other</source> + <translation type="obsolete">Outros</translation> + </message> + <message> + <source>AM</source> + <translation type="obsolete">AM</translation> + </message> + <message> + <source>FM</source> + <translation type="obsolete">FM</translation> + </message> + <message> + <source>Report complete!</source> + <translation type="obsolete">Relatório Completo</translation> + </message> + <message> + <source>Report canceled!</source> + <translation type="obsolete">Relatório Cancelado</translation> + </message> + <message> + <source>Unable to open report file!</source> + <translation type="obsolete">Não foi possível abrir o Relatório!</translation> + </message> +</context> +<context> + <name>RDSoundPanel</name> + <message> + <source>Play All</source> + <translation>Tocar Tudo</translation> + </message> + <message> + <source>Play Hook</source> + <translation>Tocar Trecho</translation> + </message> + <message> + <source>Reset</source> + <translation>Reiniciar</translation> + </message> + <message> + <source>All</source> + <translation>Todos</translation> + </message> + <message> + <source>Setup</source> + <translation>Editar</translation> + </message> + <message> + <source>Cart</source> + <translation>Cartão</translation> + </message> + <message> + <source>Panel</source> + <translation>Painel</translation> + </message> +</context> +<context> + <name>RDSqlDatabaseStatus</name> + <message> + <source>Database connection restored.</source> + <translation>Conexão à Base de Daods reestabelecido.</translation> + </message> + <message> + <source>Database connection failed : </source> + <translation>Conexão à Base de Daods falhou: </translation> + </message> +</context> +<context> + <name>RDStereoMeter</name> + <message> + <source>L</source> + <translation>L</translation> + </message> + <message> + <source>R</source> + <translation>R</translation> + </message> + <message> + <source>CLIP</source> + <translation>CLIP</translation> + </message> +</context> +<context> + <name>RDSvc</name> + <message> + <source>The following events were not placed: +</source> + <translation>Os seguintes Eventos não foram colocados: +</translation> + </message> + <message> + <source>[unknown cart]</source> + <translation>[cartão desconhecido]</translation> + </message> + <message> + <source>Event Fill Errors +</source> + <translation>Erros de Auto Preenchimento +</translation> + </message> +</context> +</TS> diff --git a/lib/rd.h b/lib/rd.h new file mode 100644 index 00000000..052f0c3c --- /dev/null +++ b/lib/rd.h @@ -0,0 +1,571 @@ +// rd.h +// +// System-Wide Values for Rivendell +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rd.h,v 1.194.6.14.2.1 2014/05/22 14:30:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RD_H +#define RD_H + +/* + * Default Configuration File + */ +#define RD_CONF_FILE "/etc/rd.conf" +#define RD_WIN_CONF_FILE "rd.ini" + +/* + * Default ALSA asoundrc file + */ +#define RD_ASOUNDRC_FILE "/etc/asound.conf" + +/* + * PID File Locations + */ +#define RD_PID_DIR "/var/run/rivendell" +#define RD_CAED_PID "/var/run/rivendell/caed.pid" +#define RD_RIPCD_PID "/var/run/rivendell/ripcd.pid" +#define RD_RDCATCHD_PID "/var/run/rivendell/rdcatchd.pid" + +/* + * Where audio gets stored + */ +#define RD_AUDIO_ROOT "/var/snd" + +/* + * Audio File Extension + */ +#define RD_AUDIO_EXTENSION "wav" + +/* + * Allow Nonstandard Bitrates? + */ +#define RD_ALLOW_NONSTANDARD_RATES false + +/* + * Default mySQL Settings + */ +#define DEFAULT_MYSQL_HOSTNAME "localhost" +#define DEFAULT_MYSQL_DATABASE "Rivendell" +#define DEFAULT_MYSQL_USERNAME "rduser" +#define DEFAULT_MYSQL_PASSWORD "letmein" +#define DEFAULT_MYSQL_DRIVER "QMYSQL3" +#define DEFAULT_MYSQL_HEARTBEAT_INTERVAL 360 +#define MYSQL_BUILTIN_DATABASE "mysql" +#define POSTGRESQL_BUILTIN_DATABASE "template1" + +/* + * Default Logging Settings + */ +#define DEFAULT_LOG_FACILITY "syslog" +#define DEFAULT_LOG_CORE_DUMP_DIRECTORY "/" +#define DEFAULT_LOG_PATTERN "%n-%Y%M%d.log" + +/* + * ALSA Settings + */ +#define RD_ALSA_DEFAULT_PERIOD_QUANTITY 4 +#define RD_ALSA_DEFAULT_PERIOD_SIZE 1024 +#define RD_ALSA_FADE_INTERVAL 100 +#define RD_ALSA_SAMPLE_RATE_TOLERANCE 100 + +/* + * Date Limits + */ +#define RD_MAX_YEAR 8000 + +/* + * JACK Settings + */ +#define RD_JACK_FADE_INTERVAL 100 + +/* + * RIPCD TCP Port + */ +#define RIPCD_TCP_PORT 5006 + +/* + * CAED TCP Port + */ +#define CAED_TCP_PORT 5005 + +/* + * RdCatchd TCP Port + */ +#define RDCATCHD_TCP_PORT 6006 + +/* + * Minimum event ID for dynamic (RML-controlled) recordings + */ +#define RDCATCHD_DYNAMIC_BASE_ID 1000000000 + +/* + * Default Local GPIO Device + */ +#define RD_DEFAULT_GPIO_DEVICE "/dev/gpio0" + +/* + * Max number of possible GPIO lines (GPI OR GPO) + */ +#define MAX_GPIO_PINS 32768 + +/* + * Max number of possible workstations + */ +#define RD_MAX_STATIONS 64 + +/* + * Max number of possible audio adapters + */ +#define RD_MAX_CARDS 8 + +/* + * Max number of possible audio streams/card/type + */ +#define RD_MAX_STREAMS 16 + +/* + * Max number of possible audio ports/card/type + */ +#define RD_MAX_PORTS 8 + +/* + * Max number of possible TTYs + */ +#define MAX_TTYS 8 + +/* + * Max number of netcatcher decks per workstation + */ +#define MAX_DECKS 8 + +/* + * Max number of inputs or outputs in a switcher + */ +#define MAX_ENDPOINTS 1024 + +/* + * Max number of attached switcher matrices per workstation + */ +#define MAX_MATRICES 8 + +/* + * Max number of macro timers + */ +#define RD_MAX_MACRO_TIMERS 16 + +/* + * Reference Analog Level at 0 dBFS (1/100 dB) + * (thus, -16 dBFS = +4 dBu) + */ +#define RD_BASE_ANALOG 1600 + +/* + * Maximum number of SoundPanels of a given type + */ +#define MAX_PANELS 50 + +/* + * Maximum Cart Number + */ +#define RD_MAX_CART_NUMBER 999999 + +/* + * Maximum Cut Number + */ +#define RD_MAX_CUT_NUMBER 999 + +/* + * In negative 1/100ths of a dB + */ +#define REFERENCE_LEVEL 1600 + +/* + * Typomatic Rate Interval, in mS + */ +#define TYPO_RATE_1 300 +#define TYPO_RATE_2 100 + +/* + * ALSA Values + */ +#define ALSA_PLAY_PCM_DEVICE "rdp" +#define ALSA_RECORD_PCM_DEVICE "rdr" + +/* + * Default Administrative User + */ +#define RDA_LOGIN_NAME "admin" +#define RDA_PASSWORD "" +#define RDA_FULLNAME "Rivendell Administrator" +#define RDA_DESCRIPTION "Default Administrator Account" + +/* + * Default System User + */ +#define RD_USER_LOGIN_NAME "user" +#define RD_USER_PASSWORD "" +#define RD_USER_FULL_NAME "Rivendell User" +#define RD_USER_DESCRIPTION "Default User Account" + +/* + * Default System Identities + */ +#define RD_DEFAULT_AUDIO_OWNER "user" +#define RD_DEFAULT_AUDIO_GROUP "users" +#define RD_DEFAULT_LABEL "Default Configuration" + +/* + * Default Audio Store Settings + */ +#define RD_DEFAULT_AUDIO_STORE_MOUNT_OPTIONS "defaults" + +/* + * Default RDSelect Configuration Directory + */ +#define RD_DEFAULT_RDSELECT_DIR "/etc/rivendell.d" + +/* + * Default Workstation + */ +#define RD_STATION_NAME "DEFAULT" +#define RD_STATION_DESCRIPTION "Default Workstation" + +/* + * Default Program Service + */ +#define RD_SERVICE_NAME "Production" +#define RD_SERVICE_DESCRIPTION "Default Audio Service" + +/* + * RDSelect Label + * (Used for the RDSelect entry in RDAdmin->ManageHosts) + */ +#define RD_RDSELECT_LABEL "[RDSelect]" + +/* + * Default Maximum POST Length (bytes) + */ +#define RD_DEFAULT_MAX_POST_LENGTH 10000000 + +/* + * Pause Time for Starting Daemons (secs) + */ +#define RD_DAEMON_PAUSE_TIME 1 + +/* + * Location of the proc filesystem + */ +#define RD_PROC_DIR "/proc" + +/* + * Location for Lock Files + */ +#define RD_LOCKFILE_DIR "/var/lock" + +/* + * Rivendell Macro Language (RML) + */ +#define RD_RML_ECHO_PORT 5858 +#define RD_RML_NOECHO_PORT 5859 +#define RD_RML_REPLY_PORT 5860 +#define RD_RML_MAX_ARGS 100 +#define RD_RML_MAX_LENGTH 2048 + +/* + * Maximum Permissible Time Offset (+/- mS) + */ +#define RD_MAX_TIME_OFFSET 10000 + +/* + * The file to save geometry state in + */ +#define RD_GEOMETRY_FILE ".rivendell" + +/* + * Meter Update Interval (msecs) + */ +#define RD_METER_UPDATE_INTERVAL 20 + +/* + * The metering block shared memory key + */ +#define RD_METER_SHM_KEY 0x00005005 + +/* + * Maximum length of import log file line + */ +#define RD_MAX_IMPORT_LINE_LENGTH 1024 + +/* + * The minimum fader gain at the end of a segue transition + * (in hundreths of a dB) + */ +#define RD_FADE_DEPTH -3000 + +/* + * The mixer 'off' level for full muting + */ +#define RD_MUTE_DEPTH -10000 + +/* + * The fade profile (for HPI adapters only) + */ +#define RD_FADE_TYPE RDHPISoundCard::Log + +/* + * This defines the maximum frequency (in Hz) of the broadcast audio + * channel being fed by Rivendell. It is used for things like calculating + * how expensive an algorithm is needed for sample rate conversion. + * + * For modern FM facilities running MPX stereo, 15000 Hz is a reasonable + * value. + */ +#define RD_MAX_BANDPASS 15000 + +/* + * The limits on timescaling + */ +#define RD_TIMESCALE_MIN 0.833 +#define RD_TIMESCALE_MAX 1.250 +#define RD_TIMESCALE_DIVISOR 100000.0 + +/* + * Max number of default services + */ +#define RD_MAX_DEFAULT_SERVICES 32 + +/* + * Ripper Settings + */ +#define RIPPER_BAR_INTERVAL 500 +#define RIPPER_TEMP_DIR "/tmp" +#define RIPPER_TEMP_WAV "rdlibrary_rip.wav" +#define RIPPER_TEMP_PEAK "rdlibrary_rip.dat" +#define RIPPER_CDDB_USER "rdlibrary" +#define RIPPER_MAX_SECTORS 20 + +/* + * CAE Values + */ +#define CAE_MAX_ARGS 10 +#define CAE_MAX_LENGTH 256 +#define CAE_POLL_INTERVAL 50 +#define CAE_MAX_CONNECTIONS 128 + +/* + * Default Sample Rate + */ +#define RD_DEFAULT_SAMPLE_RATE 48000 + +/* + * Default Channels + */ +#define RD_DEFAULT_CHANNELS 2 + +/* + * Marker Colors + */ +#define RD_SEGUE_MARKER_COLOR Qt::cyan +#define RD_TALK_MARKER_COLOR Qt::blue +#define RD_START_END_MARKER_COLOR Qt::red +#define RD_FADE_MARKER_COLOR Qt::yellow +#define RD_HOOK_MARKER_COLOR Qt::magenta + +/* + * Cart Status Colors + */ +#define RD_CART_ERROR_COLOR Qt::red +#define RD_CART_CONDITIONAL_COLOR Qt::yellow +#define RD_CART_FUTURE_COLOR "#00FFFF" +#define RD_CART_EVERGREEN_COLOR "#008000" +#define RD_CART_INVALID_SERVICE_COLOR Qt::magenta + +/* + * RDAirPlay Colors + */ +#define RDPANEL_SETUP_FLASH_COLOR Qt::blue +#define RDPANEL_RESET_FLASH_COLOR Qt::blue +#define RDPANEL_PLAY_BACKGROUND_COLOR Qt::red +#define RDPANEL_PAUSED_BACKGROUND_COLOR Qt::cyan +#define BUTTON_STOPPED_BACKGROUND_COLOR Qt::green +#define BUTTON_PLAY_BACKGROUND_COLOR Qt::red +#define BUTTON_PLAY_TEXT_COLOR Qt::black +#define BUTTON_PAUSE_BACKGROUND_COLOR Qt::cyan +#define BUTTON_PAUSE_TEXT_COLOR Qt::black +#define BUTTON_FROM_BACKGROUND_COLOR Qt::magenta +#define BUTTON_FROM_TEXT_COLOR Qt::black +#define BUTTON_TO_BACKGROUND_COLOR Qt::yellow +#define BUTTON_TO_TEXT_COLOR Qt::black +#define BUTTON_DISABLED_BACKGROUND_COLOR Qt::darkGray +#define BUTTON_DISABLED_TEXT_COLOR Qt::white +#define BUTTON_ERROR_BACKGROUND_COLOR Qt::red +#define BUTTON_ERROR_TEXT_COLOR Qt::black + +/* + * RDAirPlay Log Machines + */ +#define RDAIRPLAY_LOG_QUANTITY 3 + +/* + * Cue Editor Colors + */ +#define RD_CUEEDITOR_KNOB_COLOR blue +#define RD_CUEEDITOR_PLAY_MARKER black +#define RD_CUEEDITOR_START_MARKER red +#define RD_CUEEDITOR_BUTTON_FLASH_PERIOD 200 +#define RD_CUEEDITOR_AUDITION_PREROLL 5000 + +/* + * Log Colors + */ +#define RD_CUSTOM_TRANSITION_COLOR Qt::blue + +/* + * Default Text Editors + */ +#define RD_LINUX_EDITOR "xterm -e vi" +#define RD_WIN32_EDITOR "notepad" + +/* + * System-wide Maintenance Interval (mS) + */ +#define RD_MAINT_MIN_INTERVAL 900000 +#define RD_MAINT_MAX_INTERVAL 3600000 + +/* + * Audio File Filter for QFileDialog + */ +#define RD_AUDIO_FILE_FILTER "Sound Files (*.mp* *.MP* *.wav *.WAV *.ogg *.OGG *.flac *.FLAC *.atx *.ATX *.tmc *.TMC *.aif* *.AIF*)\nAIFF Files (*.aif* *.AIF*)\nATX Files (*.atx *.ATX)\nMPEG Files (*.mp* *.MP*)\nOggVorbis Files (*.ogg *.OGG)\nFLAC Files (*.flac *.FLAC)\nTM Century GoldDrive Files (*.tmc *.TMC)\nWAV Files (*.wav *.WAV)\nAll Files (*.*)" + +/* + * Image File Filter for QFileDialog + */ +#define RD_IMAGE_FILE_FILTER "Image Files (*.png *.bmp *.xbm *.xpm *.pbm *.pgm *.ppm *.jpg *.mng *.gif *.PNG *.BMP *.XBM *.XPM *.PBM *.PGM *.PPM *.JPG *.MNG *.GIF)\nAll Files (*.*)" + +/* + * Loadable Module Filter for QFileDialog + */ +#define RD_MODULE_FILE_FILTER "Rivendell Loadable Modules (*.rlm)\nAll Files (*.*)" + +/* + * Web Interface Settings + */ +#define RD_WEB_BACKGROUND_COLOR "#FFFFFF" +#define RD_WEB_LINE_COLOR1 "#E0E0E0" +#define RD_WEB_LINE_COLOR2 "#F0F0F0" + +/* + * LiveWire Values + */ +#define RD_LIVEWIRE_DEFAULT_TCP_PORT 93 +#define RD_LIVEWIRE_DEFAULT_STREAM_PORT 5004 +#define RD_LIVEWIRE_DEFAULT_CHANNELS 2 +#define RD_LIVEWIRE_MAX_CMD_LENGTH 1024 +#define RD_LIVEWIRE_GPIO_BUNDLE_SIZE 5 +#define RD_LIVEWIRE_DEFAULT_LOAD RDLiveWireDestination::LoadHighZ +#define RD_LIVEWIRE_MAX_SOURCE 0x7FFF +#define RD_LIVEWIRE_GPIO_MCAST_ADDR "239.192.255.4" +#define RD_LIVEWIRE_GPIO_SEND_PORT 2055 +#define RD_LIVEWIRE_GPIO_RECV_PORT 2060 +#define RD_LIVEWIRE_GPIO_PULSE_WIDTH 100 + +/* + * Number of Carts to Include in a 'Limited' Search + */ +#define RD_LIMITED_CART_SEARCH_QUANTITY 100 + +/* + * Default title for a new cart + */ +#define RD_DEFAULT_CART_TITLE "[new cart]" + +/* + * Timeout for libcurl (secs) + */ +#define RD_CURL_TIMEOUT 1200 + +/* + * Anonymous FTP Credentials + */ +#define RD_ANON_FTP_USERNAME "anonymous" +#define RD_ANON_FTP_PASSWORD "rivendell" + +/* + * Status Monitor Height + */ +#define RDMONITOR_HEIGHT 30 + +/* + * RDAirPlay Colors + */ +#define RDPANEL_SETUP_FLASH_COLOR Qt::blue +#define RDPANEL_RESET_FLASH_COLOR Qt::blue +#define RDPANEL_PLAY_BACKGROUND_COLOR Qt::red +#define RDPANEL_PAUSED_BACKGROUND_COLOR Qt::cyan +#define BUTTON_STOPPED_BACKGROUND_COLOR Qt::green +#define BUTTON_PLAY_BACKGROUND_COLOR Qt::red +#define BUTTON_PLAY_TEXT_COLOR Qt::black +#define BUTTON_PAUSE_BACKGROUND_COLOR Qt::cyan +#define BUTTON_PAUSE_TEXT_COLOR Qt::black +#define BUTTON_FROM_BACKGROUND_COLOR Qt::magenta +#define BUTTON_FROM_TEXT_COLOR Qt::black +#define BUTTON_TO_BACKGROUND_COLOR Qt::yellow +#define BUTTON_TO_TEXT_COLOR Qt::black +#define BUTTON_DISABLED_BACKGROUND_COLOR Qt::darkGray +#define BUTTON_DISABLED_TEXT_COLOR Qt::white +#define BUTTON_ERROR_BACKGROUND_COLOR Qt::red +#define BUTTON_ERROR_TEXT_COLOR Qt::black + +#define LOG_SCHEDULED_COLOR Qt::white +#define LOG_PLAYING_COLOR Qt::green +#define LOG_PAUSED_COLOR Qt::cyan +#define LOG_NEXT_COLOR "#CCFFCC" +#define LOG_FINISHED_COLOR Qt::gray +#define LOG_EVERGREEN_COLOR "#008000" +#define LOG_ERROR_COLOR Qt::red +#define LOG_RELATIVE_TEXT_COLOR Qt::black +#define LOG_HARDTIME_TEXT_COLOR Qt::blue + +/* + * Cart Label Box Colors + */ +#define BAR_UNCHANGED_TRANSITION_COLOR Qt::green +#define BAR_UNCHANGED_STOPPING_COLOR Qt::red +#define BAR_CHANGED_TRANSITION_COLOR Qt::yellow +#define BAR_CHANGED_STOPPING_COLOR Qt::blue +#define LABELBOX_BACKGROUND_COLOR Qt::white +#define LABELBOX_MISSING_COLOR Qt::red +#define LABELBOX_MARKER_COLOR Qt::cyan +#define LABELBOX_CHAIN_COLOR Qt::magenta +#define LABELBOX_EVERGREEN_COLOR "#008000" +#define LABELBOX_TIMESCALE_COLOR Qt::green + +/* + * RDCartSlots Settings + */ +#define RDCARTSLOTS_MAX_ROWS 16 +#define RDCARTSLOTS_MAX_COLUMNS 4 + +/* + * Custom MIME Types (for Drag and Drop) + */ +#define RDMIMETYPE_CART "application/rivendell-cart" + + +#endif // RD_H diff --git a/lib/rdadd_cart.cpp b/lib/rdadd_cart.cpp new file mode 100644 index 00000000..92636b77 --- /dev/null +++ b/lib/rdadd_cart.cpp @@ -0,0 +1,282 @@ +// rdadd_cart.cpp +// +// Add a Rivendell Cart +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdadd_cart.cpp,v 1.8.10.1 2014/05/19 19:31:15 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <math.h> + +#include <qdialog.h> +#include <qstring.h> +#include <qpushbutton.h> +#include <qlistbox.h> +#include <qtextedit.h> +#include <qlabel.h> +#include <qpainter.h> +#include <qevent.h> +#include <qmessagebox.h> +#include <qcheckbox.h> +#include <qbuttongroup.h> + +#include <rdsystem.h> +#include <rddb.h> +#include <rdpasswd.h> +#include <rdgroup.h> +#include <rdtextvalidator.h> +#include <rdadd_cart.h> +#include <rdescape_string.h> + +RDAddCart::RDAddCart(QString *group,RDCart::Type *type,QString *title, + const QString &username,RDSystem *system, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + cart_system=system; + cart_group=group; + cart_type=type; + cart_title=title; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption("Add Cart"); + + // + // Generate Fonts + // + QFont label_font("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + // + // Group + // + cart_group_box=new QComboBox(this,"cart_group_box"); + cart_group_box->setGeometry(145,11,160,19); + QLabel *cart_group_label= + new QLabel(cart_group_box,tr("&Group:"),this, + "cart_group_label"); + cart_group_label->setGeometry(10,11,130,19); + cart_group_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + cart_group_label->setFont(label_font); + sql=QString().sprintf("select GROUP_NAME from USER_PERMS \ + where USER_NAME=\"%s\" order by GROUP_NAME", + (const char *)username); + q=new RDSqlQuery(sql); + while(q->next()) { + cart_group_box->insertItem(q->value(0).toString()); + if(q->value(0).toString()==*cart_group) { + cart_group_box->setCurrentItem(cart_group_box->count()-1); + } + } + delete q; + connect(cart_group_box,SIGNAL(activated(const QString &)), + this,SLOT(groupActivatedData(const QString &))); + + // + // Cart Number + // + cart_number_edit=new QLineEdit(this,"cart_number_edit"); + cart_number_edit->setGeometry(145,32,60,19); + cart_number_edit->setMaxLength(6); + QIntValidator *validator=new QIntValidator(this,"validator"); + validator->setRange(1,999999); + cart_number_edit->setValidator(validator); + QLabel *cart_number_label= + new QLabel(cart_number_edit,tr("&New Cart Number:"),this, + "cart_number_label"); + cart_number_label->setGeometry(10,32,130,19); + cart_number_label->setFont(label_font); + cart_number_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Cart Type + // + cart_type_box=new QComboBox(this,"cart_type_box"); + cart_type_box->setGeometry(145,53,100,19); + QLabel *cart_type_label= + new QLabel(cart_type_box,tr("&New Cart Type:"),this, + "cart_type_label"); + cart_type_label->setGeometry(10,53,130,19); + cart_type_label->setFont(label_font); + cart_type_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + if((*cart_type==RDCart::All)||(*cart_type==RDCart::Audio)) { + cart_type_box->insertItem(tr("Audio")); + } + if((*cart_type==RDCart::All)||(*cart_type==RDCart::Macro)) { + cart_type_box->insertItem(tr("Macro")); + } + if(*cart_type==RDCart::All) { + sql= + QString().sprintf("select DEFAULT_CART_TYPE from GROUPS\ + where NAME=\"%s\"", + (const char *)*cart_group); + q=new RDSqlQuery(sql); + if(q->first()) { + cart_type_box->setCurrentItem(q->value(0).toUInt()-1); + } + delete q; + } + + // + // Cart Title + // + cart_title_edit=new QLineEdit(this,"cart_title_edit"); + cart_title_edit->setGeometry(145,73,sizeHint().width()-155,19); + cart_title_edit->setMaxLength(255); + // cart_title_edit->setValidator(text_validator); + cart_title_edit->setText(tr("[new cart]")); + QLabel *cart_title_label= + new QLabel(cart_title_edit,tr("&New Cart Title:"),this, + "cart_title_label"); + cart_title_label->setGeometry(10,73,130,19); + cart_title_label->setFont(label_font); + cart_title_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(label_font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(label_font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + groupActivatedData(cart_group_box->currentText()); +} + + +QSize RDAddCart::sizeHint() const +{ + return QSize(400,160); +} + + +QSizePolicy RDAddCart::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDAddCart::groupActivatedData(const QString &groupname) +{ + unsigned cartnum=0; + + RDGroup *group=new RDGroup(groupname); + if((cartnum=group->nextFreeCart())==0) { + cart_number_edit->clear(); + if(group->enforceCartRange()) { + QMessageBox::warning(this,tr("No Available Cart Numbers"), + tr("There are no more available cart numbers for the group!")); + } + } + else { + cart_number_edit->setText(QString().sprintf("%06u",cartnum)); + } + delete group; +} + + +void RDAddCart::okData() +{ + RDSqlQuery *q; + QString sql; + unsigned num; + RDGroup *group=new RDGroup(cart_group_box->currentText()); + + if((sscanf((const char *)cart_number_edit->text(),"%d",&num)!=1)|| + (num<=0)) { + QMessageBox::warning(this,tr("Invalid Number"),tr("Invalid Cart Number!")); + return; + } + if(cart_title_edit->text().isEmpty()) { + QMessageBox::warning(this,tr("Title Required"), + tr("You must enter a cart title!")); + return; + } + RDSystem *system=new RDSystem(); + if(!system->allowDuplicateCartTitles()) { + sql=QString().sprintf("select NUMBER from CART where TITLE=\"%s\"", + (const char *)RDEscapeString(cart_title_edit->text())); + q=new RDSqlQuery(sql); + if(q->first()) { + QMessageBox::warning(this,tr("Duplicate Title"), + tr("The cart title must be unique!")); + delete q; + return; + } + delete q; + } + delete system; + if(group->enforceCartRange()) { + if((num<group->defaultLowCart())||(num>group->defaultHighCart())) { + QMessageBox::warning(this,tr("Invalid Number"), + tr("The cart number is outside of the permitted range for this group!")); + delete group; + return; + } + } + sql=QString().sprintf("select NUMBER from CART where NUMBER=%u",num); + q=new RDSqlQuery(sql); + if(q->first()) { + QMessageBox::information(this,tr("Cart Exists"), + tr("This cart already exists."), + QMessageBox::Ok); + delete q; + delete group; + return; + } + delete q; + delete group; + *cart_group=cart_group_box->currentText(); + if(*cart_type==RDCart::All) { + *cart_type=(RDCart::Type)(cart_type_box->currentItem()+1); + } + *cart_title=cart_title_edit->text(); + done(num); +} + + +void RDAddCart::cancelData() +{ + done(-1); +} + + +void RDAddCart::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/lib/rdadd_cart.h b/lib/rdadd_cart.h new file mode 100644 index 00000000..269555d7 --- /dev/null +++ b/lib/rdadd_cart.h @@ -0,0 +1,64 @@ +// rdadd_cart.h +// +// Add a Rivendell Cart +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdadd_cart.h,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDADD_CART_H +#define RDADD_CART_H + +#include <qdialog.h> +#include <qcombobox.h> +#include <qlineedit.h> + +#include <rdcart.h> +#include <rduser.h> +#include <rdsystem.h> + +class RDAddCart : public QDialog +{ + Q_OBJECT + public: + RDAddCart(QString *group,RDCart::Type *type,QString *title, + const QString &username,RDSystem *system, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void groupActivatedData(const QString &); + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + QLineEdit *cart_number_edit; + QComboBox *cart_group_box; + QComboBox *cart_type_box; + QLineEdit *cart_title_edit; + QString *cart_group; + RDCart::Type *cart_type; + QString *cart_title; + RDSystem *cart_system; +}; + + +#endif // RDADD_CART_H diff --git a/lib/rdadd_log.cpp b/lib/rdadd_log.cpp new file mode 100644 index 00000000..1c80442b --- /dev/null +++ b/lib/rdadd_log.cpp @@ -0,0 +1,197 @@ +// rdadd_log.cpp +// +// Create a Rivendell Log +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdadd_log.cpp,v 1.15.10.2 2014/05/21 20:29:01 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <math.h> + +#include <qdialog.h> +#include <qstring.h> +#include <qlistbox.h> +#include <qtextedit.h> +#include <qlabel.h> +#include <qpainter.h> +#include <qevent.h> +#include <qmessagebox.h> +#include <qcheckbox.h> +#include <qbuttongroup.h> +#include <qsqldatabase.h> +#include <rddb.h> +#include <rdidvalidator.h> +#include <rdadd_log.h> + + +RDAddLog::RDAddLog(QString *logname,QString *svcname,RDStation *station, + QString caption,QWidget *parent,const char *name, + RDUser *rduser) + : QDialog(parent,name,true) +{ + QStringList services_list; + log_name=logname; + log_svc=svcname; + log_station=station; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Create Log")); + + // + // Create Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + + // + // Validator + // + RDIdValidator *v=new RDIdValidator(this); + v->addBannedChar(' '); + + // + // Log Name + // + add_name_edit=new QLineEdit(this); + add_name_edit->setGeometry(115,11,sizeHint().width()-125,19); + add_name_edit->setMaxLength(64); + add_name_edit->setValidator(v); + QLabel *label=new QLabel(add_name_edit,tr("&New Log Name:"),this); + label->setGeometry(10,13,100,19); + label->setFont(button_font); + label->setAlignment(AlignRight|ShowPrefix); + connect(add_name_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(nameChangedData(const QString &))); + + // + // Service selector + // + add_service_box=new QComboBox(this); + add_service_box->setGeometry(115,33,100,19); + label=new QLabel(add_name_edit,tr("&Service:"),this); + label->setGeometry(10,33,100,19); + label->setFont(button_font); + label->setAlignment(AlignRight|ShowPrefix); + + // + // Ok Button + // + add_ok_button=new QPushButton(this); + add_ok_button-> + setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + add_ok_button->setDefault(true); + add_ok_button->setFont(button_font); + add_ok_button->setText(tr("&OK")); + connect(add_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + add_cancel_button=new QPushButton(this); + add_cancel_button-> + setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + add_cancel_button->setFont(button_font); + add_cancel_button->setText(tr("&Cancel")); + connect(add_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + if (rduser != 0) { // RDStation::UserSec + services_list = rduser->services(); + } else { // RDStation::HostSec + QString sql; + if(station==NULL) { + sql="select NAME from SERVICES order by NAME"; + } + else { + sql=QString().sprintf("select SERVICE_NAME from SERVICE_PERMS \ + where STATION_NAME=\"%s\" order by SERVICE_NAME", + (const char *)station->name()); + } + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + services_list.append( q->value(0).toString() ); + } + delete q; + } + + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end(); + ++it ) { + add_service_box->insertItem(*it); + if(*svcname==*it) { + add_service_box->setCurrentItem(add_service_box->count()-1); + } + } +} + + +RDAddLog::~RDAddLog() +{ + delete add_name_edit; +} + + +QSize RDAddLog::sizeHint() const +{ + return QSize(400,132); +} + + +QSizePolicy RDAddLog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDAddLog::okData() +{ + if(add_service_box->currentText().isEmpty()){ + QMessageBox::warning(this,tr("RDLogEdit"),tr("The service is invalid!")); + return; + } + + *log_name=add_name_edit->text().stripWhiteSpace(); + *log_svc=add_service_box->currentText(); + done(0); +} + + +void RDAddLog::cancelData() +{ + done(-1); +} + + +void RDAddLog::nameChangedData(const QString &str) +{ + add_ok_button->setDisabled(str.isEmpty()); +} + + +void RDAddLog::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/lib/rdadd_log.h b/lib/rdadd_log.h new file mode 100644 index 00000000..c4069876 --- /dev/null +++ b/lib/rdadd_log.h @@ -0,0 +1,76 @@ +// rdadd_log.h +// +// Create a Rivendell Log +// +// This class creates a basic dialog requesting from the user a name and +// corresponding service that is later used to create a new log. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdadd_log.h,v 1.8.10.1 2014/05/21 18:19:42 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_LOG_H +#define ADD_LOG_H + +#include <qdialog.h> +#include <qcombobox.h> +#include <qlineedit.h> +#include <qpushbutton.h> + +#include <rdstation.h> +#include <rdlog.h> +#include <rduser.h> + + +class RDAddLog : public QDialog +{ + Q_OBJECT + public: + /** + * Constructor for the RDAddLog object. + * + * NOTE: the presence of the optional rduser parameter is used to flag if + * user security should be used instead of host based security. + */ + RDAddLog(QString *logname,QString *svcname,RDStation *station, + QString caption,QWidget *parent=0,const char *name=0, + RDUser *rduser=0); + ~RDAddLog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + void nameChangedData(const QString &str); + + protected: + void closeEvent(QCloseEvent *e); + + private: + QLineEdit *add_name_edit; + QComboBox *add_service_box; + QPushButton *add_ok_button; + QPushButton *add_cancel_button; + QString *log_name; + QString *log_svc; + RDStation *log_station; +}; + + +#endif + diff --git a/lib/rdairplay_conf.cpp b/lib/rdairplay_conf.cpp new file mode 100644 index 00000000..7a083de8 --- /dev/null +++ b/lib/rdairplay_conf.cpp @@ -0,0 +1,997 @@ +// rdairplay_conf.cpp +// +// Abstract an RDAirPlay Configuration. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdairplay_conf.cpp,v 1.35.8.6 2014/02/10 20:45:09 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qobject.h> + +#include <rddb.h> +#include <rdconf.h> +#include <rdairplay_conf.h> +#include <rdescape_string.h> + +RDAirPlayConf::RDAirPlayConf(const QString &station,const QString &tablename) +{ + RDSqlQuery *q; + QString sql; + + air_station=station; + air_tablename=tablename; + + sql=QString(). + sprintf("select ID from %s where STATION=\"%s\"", + (const char *)air_tablename, + (const char *)RDEscapeString(air_station)); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + sql=QString(). + sprintf("insert into %s set STATION=\"%s\"", + (const char *)air_tablename, + (const char *)RDEscapeString(air_station)); + q=new RDSqlQuery(sql); + delete q; + sql=QString(). + sprintf("select ID from %s where STATION=\"%s\"", + (const char *)air_tablename, + (const char *)RDEscapeString(air_station)); + q=new RDSqlQuery(sql); + q->first(); + } + air_id=q->value(0).toUInt(); + delete q; +} + + +QString RDAirPlayConf::station() const +{ + return air_station; +} + + +int RDAirPlayConf::card(RDAirPlayConf::Channel chan) const +{ + return GetChannelValue("CARD",chan).toInt(); +} + + +void RDAirPlayConf::setCard(RDAirPlayConf::Channel chan,int card) const +{ + SetChannelValue("CARD",chan,card); +} + + +int RDAirPlayConf::port(RDAirPlayConf::Channel chan) const +{ + return GetChannelValue("PORT",chan).toInt(); +} + + +void RDAirPlayConf::setPort(RDAirPlayConf::Channel chan,int port) const +{ + SetChannelValue("PORT",chan,port); +} + + +QString RDAirPlayConf::startRml(RDAirPlayConf::Channel chan) const +{ + return GetChannelValue("START_RML",chan).toString(); +} + + +void RDAirPlayConf::setStartRml(RDAirPlayConf::Channel chan,QString str) const +{ + SetChannelValue("START_RML",chan,str); +} + + +QString RDAirPlayConf::stopRml(RDAirPlayConf::Channel chan) const +{ + return GetChannelValue("STOP_RML",chan).toString(); +} + + +void RDAirPlayConf::setStopRml(RDAirPlayConf::Channel chan,QString str) const +{ + SetChannelValue("STOP_RML",chan,str); +} + + +RDAirPlayConf::GpioType RDAirPlayConf::gpioType(RDAirPlayConf::Channel chan) + const +{ + return (RDAirPlayConf::GpioType)GetChannelValue("GPIO_TYPE",chan).toUInt(); +} + + +void RDAirPlayConf::setGpioType(RDAirPlayConf::Channel chan,GpioType type) + const +{ + SetChannelValue("GPIO_TYPE",chan,(int)type); +} + + +int RDAirPlayConf::startGpiMatrix(RDAirPlayConf::Channel chan) const +{ + return GetChannelValue("START_GPI_MATRIX",chan).toInt(); +} + + +void RDAirPlayConf::setStartGpiMatrix(RDAirPlayConf::Channel chan,int matrix) const +{ + SetChannelValue("START_GPI_MATRIX",chan,matrix); +} + + +int RDAirPlayConf::startGpiLine(RDAirPlayConf::Channel chan) const +{ + return GetChannelValue("START_GPI_LINE",chan).toInt(); +} + + +void RDAirPlayConf::setStartGpiLine(RDAirPlayConf::Channel chan,int line) const +{ + SetChannelValue("START_GPI_LINE",chan,line); +} + + +int RDAirPlayConf::startGpoMatrix(RDAirPlayConf::Channel chan) const +{ + return GetChannelValue("START_GPO_MATRIX",chan).toInt(); +} + + +void RDAirPlayConf::setStartGpoMatrix(RDAirPlayConf::Channel chan,int matrix) const +{ + SetChannelValue("START_GPO_MATRIX",chan,matrix); +} + + +int RDAirPlayConf::startGpoLine(RDAirPlayConf::Channel chan) const +{ + return GetChannelValue("START_GPO_LINE",chan).toInt(); +} + + +void RDAirPlayConf::setStartGpoLine(RDAirPlayConf::Channel chan,int line) const +{ + SetChannelValue("START_GPO_LINE",chan,line); +} + + +int RDAirPlayConf::stopGpiMatrix(RDAirPlayConf::Channel chan) const +{ + return GetChannelValue("STOP_GPI_MATRIX",chan).toInt(); +} + + +void RDAirPlayConf::setStopGpiMatrix(RDAirPlayConf::Channel chan,int matrix) const +{ + SetChannelValue("STOP_GPI_MATRIX",chan,matrix); +} + + +int RDAirPlayConf::stopGpiLine(RDAirPlayConf::Channel chan) const +{ + return GetChannelValue("STOP_GPI_LINE",chan).toInt(); +} + + +void RDAirPlayConf::setStopGpiLine(RDAirPlayConf::Channel chan,int line) const +{ + SetChannelValue("STOP_GPI_LINE",chan,line); +} + + +int RDAirPlayConf::stopGpoMatrix(RDAirPlayConf::Channel chan) const +{ + return GetChannelValue("STOP_GPO_MATRIX",chan).toInt(); +} + + +void RDAirPlayConf::setStopGpoMatrix(RDAirPlayConf::Channel chan,int matrix) const +{ + SetChannelValue("STOP_GPO_MATRIX",chan,matrix); +} + + +int RDAirPlayConf::stopGpoLine(RDAirPlayConf::Channel chan) const +{ + return GetChannelValue("STOP_GPO_LINE",chan).toInt(); +} + + +void RDAirPlayConf::setStopGpoLine(RDAirPlayConf::Channel chan,int line) const +{ + SetChannelValue("STOP_GPO_LINE",chan,line); +} + + +int RDAirPlayConf::segueLength() const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,"SEGUE_LENGTH").toInt(); +} + + +void RDAirPlayConf::setSegueLength(int len) const +{ + SetRow("SEGUE_LENGTH",len); +} + + +int RDAirPlayConf::transLength() const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,"TRANS_LENGTH").toInt(); +} + + +void RDAirPlayConf::setTransLength(int len) const +{ + SetRow("TRANS_LENGTH",len); +} + + +RDAirPlayConf::OpModeStyle RDAirPlayConf::opModeStyle() const +{ + return (RDAirPlayConf::OpModeStyle) + RDGetSqlValue(air_tablename,"ID",air_id,"LOG_MODE_STYLE").toInt(); +} + + +void RDAirPlayConf::setOpModeStyle(RDAirPlayConf::OpModeStyle style) const +{ + SetRow("LOG_MODE_STYLE",(int)style); +} + + +RDAirPlayConf::OpMode RDAirPlayConf::opMode(int mach) const +{ + return GetLogMode("OP_MODE",mach); +} + + +void RDAirPlayConf::setOpMode(int mach,RDAirPlayConf::OpMode mode) const +{ + SetLogMode("OP_MODE",mach,mode); +} + + +RDAirPlayConf::OpMode RDAirPlayConf::logStartMode(int mach) const +{ + return GetLogMode("START_MODE",mach); +} + + +void RDAirPlayConf::setLogStartMode(int mach,RDAirPlayConf::OpMode mode) const +{ + SetLogMode("START_MODE",mach,mode); +} + + +int RDAirPlayConf::pieCountLength() const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,"PIE_COUNT_LENGTH").toInt(); +} + + +void RDAirPlayConf::setPieCountLength(int len) const +{ + SetRow("PIE_COUNT_LENGTH",len); +} + + +RDAirPlayConf::PieEndPoint RDAirPlayConf::pieEndPoint() const +{ + return (RDAirPlayConf::PieEndPoint) + RDGetSqlValue(air_tablename,"ID",air_id,"PIE_COUNT_ENDPOINT").toInt(); +} + + +void RDAirPlayConf::setPieEndPoint(RDAirPlayConf::PieEndPoint point) const +{ + SetRow("PIE_COUNT_ENDPOINT",(int)point); +} + + +bool RDAirPlayConf::checkTimesync() const +{ + return RDBool(RDGetSqlValue(air_tablename,"ID",air_id, + "CHECK_TIMESYNC").toString()); +} + + +void RDAirPlayConf::setCheckTimesync(bool state) const +{ + SetRow("CHECK_TIMESYNC",RDYesNo(state)); +} + + +int RDAirPlayConf::panels(RDAirPlayConf::PanelType type) const +{ + switch(type) { + case RDAirPlayConf::StationPanel: + return RDGetSqlValue(air_tablename,"ID",air_id,"STATION_PANELS").toInt(); + + case RDAirPlayConf::UserPanel: + return RDGetSqlValue(air_tablename,"ID",air_id,"USER_PANELS").toInt(); + } + return 0; +} + + +void RDAirPlayConf::setPanels(RDAirPlayConf::PanelType type,int quan) const +{ + switch(type) { + case RDAirPlayConf::StationPanel: + SetRow("STATION_PANELS",quan); + break; + + case RDAirPlayConf::UserPanel: + SetRow("USER_PANELS",quan); + break; + } +} + + +bool RDAirPlayConf::showAuxButton(int auxbutton) const +{ + return RDBool(RDGetSqlValue(air_tablename,"ID", + air_id,QString().sprintf("SHOW_AUX_%d",auxbutton+1)).toString()); +} + + +void RDAirPlayConf::setShowAuxButton(int auxbutton,bool state) const +{ + SetRow(QString().sprintf("SHOW_AUX_%d",auxbutton+1),RDYesNo(state)); +} + + +bool RDAirPlayConf::clearFilter() const +{ + return + RDBool(RDGetSqlValue(air_tablename,"ID",air_id,"CLEAR_FILTER").toString()); +} + + +void RDAirPlayConf::setClearFilter(bool state) const +{ + SetRow("CLEAR_FILTER",RDYesNo(state)); +} + + +RDLogLine::TransType RDAirPlayConf::defaultTransType() const +{ + return (RDLogLine::TransType) + RDGetSqlValue(air_tablename,"ID",air_id,"DEFAULT_TRANS_TYPE").toInt(); +} + + +void RDAirPlayConf::setDefaultTransType(RDLogLine::TransType type) const +{ + SetRow("DEFAULT_TRANS_TYPE",(int)type); +} + + +RDAirPlayConf::BarAction RDAirPlayConf::barAction() const +{ + return (RDAirPlayConf::BarAction) + RDGetSqlValue(air_tablename,"ID",air_id,"BAR_ACTION").toUInt(); +} + + +void RDAirPlayConf::setBarAction(RDAirPlayConf::BarAction action) const +{ + SetRow("BAR_ACTION",(int)action); +} + + +bool RDAirPlayConf::flashPanel() const +{ + return + RDBool(RDGetSqlValue(air_tablename,"ID",air_id,"FLASH_PANEL").toString()); +} + + +void RDAirPlayConf::setFlashPanel(bool state) const +{ + SetRow("FLASH_PANEL",RDYesNo(state)); +} + + +bool RDAirPlayConf::panelPauseEnabled() const +{ + return RDBool(RDGetSqlValue(air_tablename,"ID",air_id,"PANEL_PAUSE_ENABLED"). + toString()); +} + + +void RDAirPlayConf::setPanelPauseEnabled(bool state) const +{ + SetRow("PANEL_PAUSE_ENABLED",RDYesNo(state)); +} + + +QString RDAirPlayConf::buttonLabelTemplate() const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,"BUTTON_LABEL_TEMPLATE"). + toString(); +} + + +void RDAirPlayConf::setButtonLabelTemplate(const QString &str) const +{ + SetRow("BUTTON_LABEL_TEMPLATE",str); +} + + +bool RDAirPlayConf::pauseEnabled() const +{ + return + RDBool(RDGetSqlValue(air_tablename,"ID",air_id,"PAUSE_ENABLED").toString()); +} + + +void RDAirPlayConf::setPauseEnabled(bool state) const +{ + SetRow("PAUSE_ENABLED",RDYesNo(state)); +} + + +QString RDAirPlayConf::defaultSvc() const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,"DEFAULT_SERVICE").toString(); +} + + +void RDAirPlayConf::setDefaultSvc(const QString &svcname) const +{ + SetRow("DEFAULT_SERVICE",svcname); +} + + +bool RDAirPlayConf::hourSelectorEnabled() const +{ + return + RDBool(RDGetSqlValue(air_tablename,"ID",air_id,"HOUR_SELECTOR_ENABLED"). + toString()); +} + + +void RDAirPlayConf::setHourSelectorEnabled(bool state) const +{ + SetRow("HOUR_SELECTOR_ENABLED",RDYesNo(state)); +} + + +QString RDAirPlayConf::titleTemplate() const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,"TITLE_TEMPLATE"). + toString(); +} + + +void RDAirPlayConf::setTitleTemplate(const QString &str) +{ + SetRow("TITLE_TEMPLATE",str); +} + + +QString RDAirPlayConf::artistTemplate() const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,"ARTIST_TEMPLATE"). + toString(); +} + + +void RDAirPlayConf::setArtistTemplate(const QString &str) +{ + SetRow("ARTIST_TEMPLATE",str); +} + + +QString RDAirPlayConf::outcueTemplate() const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,"OUTCUE_TEMPLATE"). + toString(); +} + + +void RDAirPlayConf::setOutcueTemplate(const QString &str) +{ + SetRow("OUTCUE_TEMPLATE",str); +} + + +QString RDAirPlayConf::descriptionTemplate() const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,"DESCRIPTION_TEMPLATE"). + toString(); +} + + +void RDAirPlayConf::setDescriptionTemplate(const QString &str) +{ + SetRow("DESCRIPTION_TEMPLATE",str); +} + + +QHostAddress RDAirPlayConf::udpAddress(int logno) const +{ + QHostAddress addr; + QString str(RDGetSqlValue(air_tablename,"ID",air_id, + QString().sprintf("UDP_ADDR%d",logno)).toString()); + addr.setAddress(str); + return addr; +} + + +void RDAirPlayConf::setUdpAddress(int logno,QHostAddress addr) const +{ + SetRow(QString().sprintf("UDP_ADDR%d",logno),addr.toString()); +} + + +Q_UINT16 RDAirPlayConf::udpPort(int logno) const +{ + return (Q_UINT16)RDGetSqlValue(air_tablename,"ID",air_id,QString(). + sprintf("UDP_PORT%d",logno)).toInt(); +} + + +void RDAirPlayConf::setUdpPort(int logno,Q_UINT16 port) const +{ + SetRow(QString().sprintf("UDP_PORT%d",logno),(int)port); +} + + +QString RDAirPlayConf::udpString(int logno) const +{ + return RDGetSqlValue(air_tablename,"ID",air_id, + QString().sprintf("UDP_STRING%d",logno)).toString(); +} + + +void RDAirPlayConf::setUdpString(int logno,const QString &str) const +{ + SetRow(QString().sprintf("UDP_STRING%d",logno),str); +} + + +QString RDAirPlayConf::logRml(int logno) const +{ + return RDGetSqlValue(air_tablename,"ID",air_id, + QString().sprintf("LOG_RML%d",logno)).toString(); +} + + +void RDAirPlayConf::setLogRml(int logno,const QString &str) const +{ + SetRow(QString().sprintf("LOG_RML%d",logno),str); +} + + +RDAirPlayConf::ExitCode RDAirPlayConf::exitCode() const +{ + return (RDAirPlayConf::ExitCode) + RDGetSqlValue(air_tablename,"ID",air_id,"EXIT_CODE").toInt(); +} + + +void RDAirPlayConf::setExitCode(RDAirPlayConf::ExitCode code) const +{ + SetRow("EXIT_CODE",(int)code); +} + + +bool RDAirPlayConf::exitPasswordValid(const QString &passwd) const +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select EXIT_PASSWORD from %s where \ + STATION=\"%s\" && EXIT_PASSWORD=PASSWORD(\"%s\")", + (const char *)air_tablename, + (const char *)air_station, + (const char *)passwd); + q=new RDSqlQuery(sql); + if(q->size()>0) { + delete q; + return true; + } + delete q; + return false; +} + + +void RDAirPlayConf::setExitPassword(const QString &passwd) const +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf ("update %s set EXIT_PASSWORD=PASSWORD(\"%s\") \ + where STATION=\"%s\"",(const char *)air_tablename, + (const char *)passwd, + (const char *)air_station); + q=new RDSqlQuery(sql); + delete q; +} + + +QString RDAirPlayConf::skinPath() const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,"SKIN_PATH").toString(); +} + + +void RDAirPlayConf::setSkinPath(const QString &path) const +{ + SetRow("SKIN_PATH",path); +} + + +bool RDAirPlayConf::showCounters() const +{ + return RDBool(RDGetSqlValue(air_tablename,"ID",air_id,"SHOW_COUNTERS"). + toString()); +} + + +void RDAirPlayConf::setShowCounters(bool state) const +{ + SetRow("SHOW_COUNTERS",RDYesNo(state)); +} + + +int RDAirPlayConf::auditionPreroll() const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,"AUDITION_PREROLL").toInt(); +} + + +void RDAirPlayConf::setAuditionPreroll(int msecs) const +{ + SetRow("AUDITION_PREROLL",msecs); +} + + +RDAirPlayConf::StartMode RDAirPlayConf::startMode(int lognum) const +{ + return (RDAirPlayConf::StartMode) + RDGetSqlValue(air_tablename,"ID", + air_id,QString().sprintf("LOG%d_START_MODE",lognum)).toInt(); +} + + +void RDAirPlayConf::setStartMode(int lognum,RDAirPlayConf::StartMode mode) const +{ + SetRow(QString().sprintf("LOG%d_START_MODE",lognum),(int)mode); +} + + +bool RDAirPlayConf::autoRestart(int lognum) const +{ + return RDBool(RDGetSqlValue(air_tablename,"ID",air_id, + QString().sprintf("LOG%d_AUTO_RESTART",lognum)). + toString()); +} + + +void RDAirPlayConf::setAutoRestart(int lognum,bool state) const +{ + SetRow(QString().sprintf("LOG%d_AUTO_RESTART",lognum),RDYesNo(state)); +} + + +QString RDAirPlayConf::logName(int lognum) const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,QString(). + sprintf("LOG%d_LOG_NAME",lognum)).toString(); +} + + +void RDAirPlayConf::setLogName(int lognum,const QString &name) const +{ + SetRow(QString().sprintf("LOG%d_LOG_NAME",lognum),name); +} + + +QString RDAirPlayConf::currentLog(int lognum) const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,QString(). + sprintf("LOG%d_CURRENT_LOG",lognum)).toString(); +} + + +void RDAirPlayConf::setCurrentLog(int lognum,const QString &name) const +{ + SetRow(QString().sprintf("LOG%d_CURRENT_LOG",lognum),name); +} + + +bool RDAirPlayConf::logRunning(int lognum) const +{ + return RDBool(RDGetSqlValue(air_tablename,"ID",air_id, + QString().sprintf("LOG%d_RUNNING",lognum)). + toString()); +} + + +void RDAirPlayConf::setLogRunning(int lognum,bool state) const +{ + SetRow(QString().sprintf("LOG%d_RUNNING",lognum),RDYesNo(state)); +} + + +int RDAirPlayConf::logId(int lognum) const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,QString(). + sprintf("LOG%d_LOG_ID",lognum)).toInt(); +} + + +void RDAirPlayConf::setLogId(int lognum,int id) const +{ + SetRow(QString().sprintf("LOG%d_LOG_ID",lognum),id); +} + + +int RDAirPlayConf::logCurrentLine(int lognum) const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,QString(). + sprintf("LOG%d_LOG_LINE",lognum)).toInt(); +} + + +void RDAirPlayConf::setLogCurrentLine(int lognum,int line) const +{ + SetRow(QString().sprintf("LOG%d_LOG_LINE",lognum),line); +} + + +unsigned RDAirPlayConf::logNowCart(int lognum) const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,QString(). + sprintf("LOG%d_NOW_CART",lognum)).toUInt(); +} + + +void RDAirPlayConf::setLogNowCart(int lognum,unsigned cartnum) const +{ + SetRow(QString().sprintf("LOG%d_NOW_CART",lognum),cartnum); +} + + +unsigned RDAirPlayConf::logNextCart(int lognum) const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,QString(). + sprintf("LOG%d_NEXT_CART",lognum)).toUInt(); +} + + +void RDAirPlayConf::setLogNextCart(int lognum,unsigned cartnum) const +{ + SetRow(QString().sprintf("LOG%d_NEXT_CART",lognum),cartnum); +} + + +QString RDAirPlayConf::channelText(RDAirPlayConf::Channel chan) +{ + QString ret=QObject::tr("Unknown"); + + switch(chan) { + case RDAirPlayConf::MainLog1Channel: + ret=QObject::tr("Main Log Output 1"); + break; + + case RDAirPlayConf::MainLog2Channel: + ret=QObject::tr("Main Log Output 2"); + break; + + case RDAirPlayConf::SoundPanel1Channel: + ret=QObject::tr("Sound Panel First Play Output"); + break; + + case RDAirPlayConf::CueChannel: + ret=QObject::tr("Audition/Cue Output"); + break; + + case RDAirPlayConf::AuxLog1Channel: + ret=QObject::tr("Aux Log 1 Output"); + break; + + case RDAirPlayConf::AuxLog2Channel: + ret=QObject::tr("Aux Log 2 Output"); + break; + + case RDAirPlayConf::SoundPanel2Channel: + ret=QObject::tr("Sound Panel Second Play Output"); + break; + + case RDAirPlayConf::SoundPanel3Channel: + ret=QObject::tr("Sound Panel Third Play Output"); + break; + + case RDAirPlayConf::SoundPanel4Channel: + ret=QObject::tr("Sound Panel Fourth Play Output"); + break; + + case RDAirPlayConf::SoundPanel5Channel: + ret=QObject::tr("Sound Panel Fifth and Later Play Output"); + break; + + case RDAirPlayConf::LastChannel: + break; + } + + return ret; +} + + +QString RDAirPlayConf::logModeText(RDAirPlayConf::OpMode mode) +{ + QString ret=QObject::tr("Unknown"); + + switch(mode) { + case RDAirPlayConf::LiveAssist: + ret=QObject::tr("LiveAssist"); + break; + + case RDAirPlayConf::Auto: + ret=QObject::tr("Automatic"); + break; + + case RDAirPlayConf::Manual: + ret=QObject::tr("Manual"); + break; + + case RDAirPlayConf::Previous: + ret=QObject::tr("Previous"); + break; + } + + return ret; +} + + +QVariant RDAirPlayConf::GetChannelValue(const QString ¶m,RDAirPlayConf::Channel chan) const +{ + RDSqlQuery *q; + QString sql; + QVariant ret; + + sql=QString("select ")+param+" from "+air_tablename+"_CHANNELS where "+ + "(STATION_NAME=\""+RDEscapeString(air_station)+"\")&&"+ + QString().sprintf("(INSTANCE=%u)",chan); + q=new RDSqlQuery(sql); + if(q->first()) { + ret=q->value(0); + } + delete q; + + return ret; +} + + +void RDAirPlayConf::SetChannelValue(const QString ¶m,RDAirPlayConf::Channel chan,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString("update ")+air_tablename+"_CHANNELS set "+ + param+QString().sprintf("=%d ",value)+ + "where (STATION_NAME=\""+RDEscapeString(air_station)+"\")&&"+ + QString().sprintf("(INSTANCE=%d)",chan); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDAirPlayConf::SetChannelValue(const QString ¶m,RDAirPlayConf::Channel chan,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString("update ")+air_tablename+"_CHANNELS set "+ + param+"=\""+RDEscapeString(value)+"\" "+ + "where (STATION_NAME=\""+RDEscapeString(air_station)+"\")&&"+ + QString().sprintf("(INSTANCE=%d)",chan); + q=new RDSqlQuery(sql); + delete q; +} + + +RDAirPlayConf::OpMode RDAirPlayConf::GetLogMode(const QString ¶m,int mach) const +{ + RDAirPlayConf::OpMode mode=RDAirPlayConf::Auto; + QString sql; + RDSqlQuery *q; + + sql=QString("select ")+param+" from LOG_MODES where "+ + "(STATION_NAME=\""+RDEscapeString(air_station)+"\")&&"+ + QString().sprintf("MACHINE=%d",mach); + q=new RDSqlQuery(sql); + if(q->first()) { + mode=(RDAirPlayConf::OpMode)q->value(0).toInt(); + } + delete q; + return mode; +} + + +void RDAirPlayConf::SetLogMode(const QString ¶m,int mach, + RDAirPlayConf::OpMode mode) const +{ + QString sql; + RDSqlQuery *q; + + sql=QString("update LOG_MODES set ")+param+QString().sprintf("=%d ",mode)+ + "where (STATION_NAME=\""+RDEscapeString(air_station)+"\")&&"+ + QString().sprintf("(MACHINE=%d)",mach); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDAirPlayConf::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString(). + sprintf("UPDATE %s SET %s=%d WHERE STATION=\"%s\"", + (const char *)air_tablename, + (const char *)param, + value, + (const char *)RDEscapeString(air_station)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDAirPlayConf::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString(). + sprintf("UPDATE %s SET %s=%u WHERE STATION=\"%s\"", + (const char *)air_tablename, + (const char *)param, + value, + (const char *)RDEscapeString(air_station)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDAirPlayConf::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString(). + sprintf("UPDATE %s SET %s=\"%s\" WHERE STATION=\"%s\"", + (const char *)air_tablename, + (const char *)RDEscapeString(param), + (const char *)RDEscapeString(value), + (const char *)RDEscapeString(air_station)); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdairplay_conf.h b/lib/rdairplay_conf.h new file mode 100644 index 00000000..cbfc71f2 --- /dev/null +++ b/lib/rdairplay_conf.h @@ -0,0 +1,183 @@ +// rdairplay_conf.h +// +// Abstract RDAirPlay Configuration +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdairplay_conf.h,v 1.36.8.5 2014/02/10 20:45:09 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDAIRPLAY_CONF_H +#define RDAIRPLAY_CONF_H + +#include <qsqldatabase.h> +#include <qhostaddress.h> + +#include <rdlog_line.h> + + +class RDAirPlayConf +{ + public: + enum TimeMode {TwelveHour=0,TwentyFourHour=1}; + enum OpModeStyle {Unified=0,Independent=1}; + enum OpMode {Previous=0,LiveAssist=1,Auto=2,Manual=3}; + enum ActionMode {Normal=0,AddFrom=1,AddTo=2,DeleteFrom=3,MoveFrom=4,MoveTo=5, + CopyFrom=6,CopyTo=7,Audition=8}; + enum PieEndPoint {CartEnd=0,CartTransition=1}; + enum BarAction {NoAction=0,StartNext=1}; + enum TrafficAction {TrafficStart=1,TrafficStop=2,TrafficFinish=3, + TrafficPause=4,TrafficMacro=5}; + enum PanelType {StationPanel=0,UserPanel=1}; + enum ExitCode {ExitClean=0,ExitDirty=1}; + enum StartMode {StartEmpty=0,StartPrevious=1,StartSpecified=2}; + enum Channel {MainLog1Channel=0,MainLog2Channel=1,SoundPanel1Channel=2, + CueChannel=3,AuxLog1Channel=4,AuxLog2Channel=5, + SoundPanel2Channel=6,SoundPanel3Channel=7, + SoundPanel4Channel=8,SoundPanel5Channel=9,LastChannel=10}; + enum GpioType {EdgeGpio=0,LevelGpio=1}; + RDAirPlayConf(const QString &station,const QString &tablename); + QString station() const; + int card(Channel chan) const; + void setCard(Channel chan,int card) const; + int port(Channel chan) const; + void setPort(Channel chan,int port) const; + QString startRml(Channel chan) const; + void setStartRml(Channel chan,QString str) const; + QString stopRml(Channel chan) const; + void setStopRml(Channel chan,QString str) const; + RDAirPlayConf::GpioType gpioType(RDAirPlayConf::Channel chan) const; + void setGpioType(RDAirPlayConf::Channel chan,RDAirPlayConf::GpioType type) + const; + int startGpiMatrix(Channel chan) const; + void setStartGpiMatrix(Channel chan,int matrix) const; + int startGpiLine(Channel chan) const; + void setStartGpiLine(Channel chan,int line) const; + int startGpoMatrix(Channel chan) const; + void setStartGpoMatrix(Channel chan,int matrix) const; + int startGpoLine(Channel chan) const; + void setStartGpoLine(Channel chan,int line) const; + int stopGpiMatrix(Channel chan) const; + void setStopGpiMatrix(Channel chan,int matrix) const; + int stopGpiLine(Channel chan) const; + void setStopGpiLine(Channel chan,int line) const; + int stopGpoMatrix(Channel chan) const; + void setStopGpoMatrix(Channel chan,int matrix) const; + int stopGpoLine(Channel chan) const; + void setStopGpoLine(Channel chan,int line) const; + int segueLength() const; + void setSegueLength(int len) const; + int transLength() const; + void setTransLength(int len) const; + RDAirPlayConf::OpModeStyle opModeStyle() const; + void setOpModeStyle(RDAirPlayConf::OpModeStyle style) const; + RDAirPlayConf::OpMode opMode(int mach) const; + void setOpMode(int mach,RDAirPlayConf::OpMode mode) const; + RDAirPlayConf::OpMode logStartMode(int mach) const; + void setLogStartMode(int mach,RDAirPlayConf::OpMode mode) const; + int pieCountLength() const; + void setPieCountLength(int len) const; + RDAirPlayConf::PieEndPoint pieEndPoint() const; + void setPieEndPoint(RDAirPlayConf::PieEndPoint point) const; + bool checkTimesync() const; + void setCheckTimesync(bool state) const; + int panels(RDAirPlayConf::PanelType type) const; + void setPanels(RDAirPlayConf::PanelType type,int quan) const; + bool showAuxButton(int auxbutton) const; + void setShowAuxButton(int auxbutton,bool state) const; + bool clearFilter() const; + void setClearFilter(bool state) const; + RDLogLine::TransType defaultTransType() const; + void setDefaultTransType(RDLogLine::TransType type) const; + RDAirPlayConf::BarAction barAction() const; + void setBarAction(RDAirPlayConf::BarAction action) const; + bool flashPanel() const; + void setFlashPanel(bool state) const; + bool panelPauseEnabled() const; + void setPanelPauseEnabled(bool state) const; + QString buttonLabelTemplate() const; + void setButtonLabelTemplate(const QString &str) const; + bool pauseEnabled() const; + void setPauseEnabled(bool state) const; + QString defaultSvc() const; + void setDefaultSvc(const QString &svcname) const; + QString titleTemplate() const; + void setTitleTemplate(const QString &str); + QString artistTemplate() const; + void setArtistTemplate(const QString &str); + QString outcueTemplate() const; + void setOutcueTemplate(const QString &str); + QString descriptionTemplate() const; + void setDescriptionTemplate(const QString &str); + bool hourSelectorEnabled() const; + void setHourSelectorEnabled(bool state) const; + QHostAddress udpAddress(int logno) const; + void setUdpAddress(int logno,QHostAddress addr) const; + Q_UINT16 udpPort(int logno) const; + void setUdpPort(int logno,Q_UINT16 port) const; + QString udpString(int logno) const; + void setUdpString(int logno,const QString &str) const; + QString logRml(int logno) const; + void setLogRml(int logno,const QString &str) const; + RDAirPlayConf::ExitCode exitCode() const; + void setExitCode(RDAirPlayConf::ExitCode code) const; + bool exitPasswordValid(const QString &passwd) const; + void setExitPassword(const QString &passwd) const; + QString skinPath() const; + void setSkinPath(const QString &path) const; + bool showCounters() const; + void setShowCounters(bool state) const; + int auditionPreroll() const; + void setAuditionPreroll(int msecs) const; + RDAirPlayConf::StartMode startMode(int lognum) const; + void setStartMode(int lognum,RDAirPlayConf::StartMode mode) const; + bool autoRestart(int lognum) const; + void setAutoRestart(int lognum,bool state) const; + QString logName(int lognum) const; + void setLogName(int lognum,const QString &name) const; + QString currentLog(int lognum) const; + void setCurrentLog(int lognum,const QString &name) const; + bool logRunning(int lognum) const; + void setLogRunning(int lognum,bool state) const; + int logId(int lognum) const; + void setLogId(int lognum,int id) const; + int logCurrentLine(int lognum) const; + void setLogCurrentLine(int lognum,int line) const; + unsigned logNowCart(int lognum) const; + void setLogNowCart(int lognum,unsigned cartnum) const; + unsigned logNextCart(int lognum) const; + void setLogNextCart(int lognum,unsigned cartnum) const; + static QString channelText(RDAirPlayConf::Channel chan); + static QString logModeText(RDAirPlayConf::OpMode mode); + + private: + QVariant GetChannelValue(const QString ¶m,Channel chan) const; + void SetChannelValue(const QString ¶m,Channel chan,int value) const; + void SetChannelValue(const QString ¶m,Channel chan, + const QString &value) const; + RDAirPlayConf::OpMode GetLogMode(const QString ¶m,int mach) const; + void SetLogMode(const QString ¶m,int mach, + RDAirPlayConf::OpMode mode) const; + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,unsigned value) const; + void SetRow(const QString ¶m,const QString &value) const; + QString air_station; + unsigned air_id; + QString air_tablename; +}; + + +#endif // RDAIRPLAY_CONF_H diff --git a/lib/rdaudio_exists.cpp b/lib/rdaudio_exists.cpp new file mode 100644 index 00000000..7a076a1e --- /dev/null +++ b/lib/rdaudio_exists.cpp @@ -0,0 +1,35 @@ +// rdaudio_exists.cpp +// +// Test for the existence of audio in a Rivendell Audio Cut. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudio_exists.cpp,v 1.10 2010/09/13 23:14:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qstring.h> +#include <qfile.h> +#include <rd.h> +#include <rdcut.h> +#include <rdaudio_exists.h> + +bool RDAudioExists(QString cutname) +{ + RDCut *cut=new RDCut(cutname); + bool ret=cut->exists()&&(cut->length()>0); + delete cut; + return ret; +} diff --git a/lib/rdaudio_exists.h b/lib/rdaudio_exists.h new file mode 100644 index 00000000..fa0de0bd --- /dev/null +++ b/lib/rdaudio_exists.h @@ -0,0 +1,29 @@ +// rdaudio_exists.h +// +// Test for the existence of a Rivendell Audio Cut. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudio_exists.h,v 1.3 2007/02/14 21:48:41 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDAUDIO_EXISTS_H +#define RDAUDIO_EXISTS_H + +bool RDAudioExists(QString cutname); + + +#endif diff --git a/lib/rdaudio_port.cpp b/lib/rdaudio_port.cpp new file mode 100644 index 00000000..825f8e87 --- /dev/null +++ b/lib/rdaudio_port.cpp @@ -0,0 +1,189 @@ +// rdaudio_port.cpp +// +// Abstract a Rivendell Audio Port. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudio_port.cpp,v 1.12.8.1 2012/08/03 16:52:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +#include <rddb.h> +#include <rdaudio_port.h> + + +// +// Global Classes +// +RDAudioPort::RDAudioPort(QString station,int card,bool create) +{ + RDSqlQuery *q; + QString sql; + + port_station=station; + port_card=card; + + if(create) { + sql=QString().sprintf("select ID from AUDIO_PORTS where \ +(STATION_NAME=\"%s\")&&(CARD_NUMBER=%d)",(const char *)port_station,port_card); + q=new RDSqlQuery(sql); + if(q->size()!=1) { + delete q; + sql=QString().sprintf("INSERT INTO AUDIO_PORTS SET STATION_NAME=\"%s\",\ +CARD_NUMBER=%d", + (const char *)port_station,port_card); + q=new RDSqlQuery(sql); + delete q; + } + else { + delete q; + } + } +} + + +QString RDAudioPort::station() const +{ + return port_station; +} + + +int RDAudioPort::card() const +{ + return port_card; +} + + +RDCae::ClockSource RDAudioPort::clockSource() +{ + return (RDCae::ClockSource)GetIntValue("CLOCK_SOURCE"); +} + + +void RDAudioPort::setClockSource(RDCae::ClockSource src) +{ + SetRow("CLOCK_SOURCE",(int)src); +} + + +RDAudioPort::PortType RDAudioPort::inputPortType(int port) +{ + if(port<0) { + return RDAudioPort::Analog; + } + return + (RDAudioPort::PortType)GetIntValue(QString().sprintf("INPUT_%d_TYPE",port)); +} + + +void RDAudioPort::setInputPortType(int port,RDAudioPort::PortType type) +{ + if(port<0) { + return; + } + SetRow(QString().sprintf("INPUT_%d_TYPE",port),(int)type); +} + + +RDCae::ChannelMode RDAudioPort::inputPortMode(int port) +{ + if(port<0) { + return RDCae::Normal; + } + return + (RDCae::ChannelMode)GetIntValue(QString().sprintf("INPUT_%d_MODE",port)); +} + + +void RDAudioPort::setInputPortMode(int port,RDCae::ChannelMode mode) +{ + if(port<0) { + return; + } + SetRow(QString().sprintf("INPUT_%d_MODE",port),(int)mode); +} + + +int RDAudioPort::inputPortLevel(int port) +{ + if(port<0) { + return 400; + } + return GetIntValue(QString().sprintf("INPUT_%d_LEVEL",port)); +} + + +void RDAudioPort::setInputPortLevel(int port,int level) +{ + if(port<0) { + return; + } + SetRow(QString().sprintf("INPUT_%d_LEVEL",port),level); +} + + +int RDAudioPort::outputPortLevel(int port) +{ + if(port<0) { + return 400; + } + return GetIntValue(QString().sprintf("OUTPUT_%d_LEVEL",port)); +} + + +void RDAudioPort::setOutputPortLevel(int port,int level) +{ + if(port<0) { + return; + } + SetRow(QString().sprintf("OUTPUT_%d_LEVEL",port),level); +} + + +int RDAudioPort::GetIntValue(QString field) +{ + QString sql; + RDSqlQuery *q; + int accum; + + sql=QString().sprintf("select %s from AUDIO_PORTS where \ +(STATION_NAME=\"%s\")&&(CARD_NUMBER=%d)",(const char *)field, + (const char *)port_station,port_card); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toInt(); + delete q; + return accum; + } + delete q; + return 0; +} + + +void RDAudioPort::SetRow(QString param,int value) +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE AUDIO_PORTS SET %s=%d \ +WHERE (STATION_NAME=\"%s\")&&(CARD_NUMBER=%d)", + (const char *)param, + value, + (const char *)port_station, + port_card); + q=new RDSqlQuery(sql); + delete q; +} + + diff --git a/lib/rdaudio_port.h b/lib/rdaudio_port.h new file mode 100644 index 00000000..226111ba --- /dev/null +++ b/lib/rdaudio_port.h @@ -0,0 +1,55 @@ +// rdaudio_port.h +// +// Abstract a Rivendell Audio Port +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudio_port.h,v 1.9.8.1 2012/08/03 16:52:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDAUDIO_PORT_H +#define RDAUDIO_PORT_H + +#include <qsqldatabase.h> +#include <rdcae.h> + +class RDAudioPort +{ + public: + enum PortType {Analog=0,AesEbu=1,SpDiff=2}; + RDAudioPort(QString station,int card,bool create=false); + QString station() const; + int card() const; + RDCae::ClockSource clockSource(); + void setClockSource(RDCae::ClockSource src); + RDAudioPort::PortType inputPortType(int port); + void setInputPortType(int port,RDAudioPort::PortType type); + RDCae::ChannelMode inputPortMode(int port); + void setInputPortMode(int port,RDCae::ChannelMode mode); + int inputPortLevel(int port); + void setInputPortLevel(int port,int level); + int outputPortLevel(int port); + void setOutputPortLevel(int port,int level); + + private: + int GetIntValue(QString field); + void SetRow(QString param,int value); + QString port_station; + int port_card; +}; + + +#endif diff --git a/lib/rdaudioconvert.cpp b/lib/rdaudioconvert.cpp new file mode 100644 index 00000000..afdb9c1e --- /dev/null +++ b/lib/rdaudioconvert.cpp @@ -0,0 +1,1819 @@ +// rdaudioconvert.cpp +// +// Convert Audio File Formats +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudioconvert.cpp,v 1.14.2.3.2.1 2014/05/15 16:30:00 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> +#include <dlfcn.h> +#include <errno.h> + +#include <sndfile.h> +#include <samplerate.h> +#include <soundtouch/SoundTouch.h> +#ifdef HAVE_VORBIS +#include <ogg/ogg.h> +#include <vorbis/vorbisenc.h> +#endif // HAVE_VORBIS +#ifdef HAVE_FLAC +#include <FLAC++/encoder.h> +#include <rdflacdecode.h> +#endif // HAVE_FLAC +#include <id3/tag.h> +#include <qfile.h> + +#include <rd.h> +#include <rdaudioconvert.h> +#include <rdlibrary_conf.h> + +#define STAGE2_XFER_SIZE 2048 +#define STAGE2_BUFFER_SIZE 49152 + +RDAudioConvert::RDAudioConvert(const QString &station_name, + QObject *parent,const char *name) + : QObject(parent,name) +{ + conv_start_point=-1; + conv_end_point=-1; + conv_speed_ratio=1.0; + conv_peak_sample=0.0; + conv_settings=NULL; + conv_src_wavedata=new RDWaveData(); + conv_dst_wavedata=NULL; + RDLibraryConf *conf=new RDLibraryConf(station_name,0); + conv_src_converter=conf->srcConverter(); + delete conf; + + // + // Load MPEG Libraries + // + conv_mad_handle=dlopen("libmad.so",RTLD_LAZY); + conv_lame_handle=dlopen("libmp3lame.so",RTLD_LAZY); + conv_twolame_handle=dlopen("libtwolame.so",RTLD_LAZY); +} + + +RDAudioConvert::~RDAudioConvert() +{ + delete conv_src_wavedata; +} + + +void RDAudioConvert::setSourceFile(const QString &filename) +{ + conv_src_filename=filename; +} + + +void RDAudioConvert::setDestinationFile(const QString &filename) +{ + conv_dst_filename=filename; +} + + +void RDAudioConvert::setDestinationSettings(RDSettings *settings) +{ + conv_settings=settings; +} + + +RDWaveData *RDAudioConvert::sourceWaveData() const +{ + return conv_src_wavedata; +} + + +void RDAudioConvert::setDestinationWaveData(RDWaveData *wavedata) +{ + conv_dst_wavedata=wavedata; +} + + +void RDAudioConvert::setRange(int start_pt,int end_pt) +{ + conv_start_point=start_pt; + conv_end_point=end_pt; +} + + +void RDAudioConvert::setSpeedRatio(float ratio) +{ + conv_speed_ratio=ratio; +} + + +RDAudioConvert::ErrorCode RDAudioConvert::convert() +{ + char tmpdir[PATH_MAX]; + RDAudioConvert::ErrorCode err; + QString tmpfile1; + QString tmpfile2; + + // + // Make sure we're all set to go... + // + if(conv_settings==NULL) { + return RDAudioConvert::ErrorInvalidSettings; + } + if(!RDAudioConvert::settingsValid(conv_settings)) { + return RDAudioConvert::ErrorInvalidSettings; + } + if(!QFile::exists(conv_src_filename)) { + return RDAudioConvert::ErrorNoSource; + } + if(conv_dst_filename.isEmpty()) { + return RDAudioConvert::ErrorNoDestination; + } + if((conv_speed_ratio<RD_TIMESCALE_MIN)||(conv_speed_ratio>RD_TIMESCALE_MAX)) { + return RDAudioConvert::ErrorInvalidSpeed; + } + + // + // Generate Temporary Filenames + // + strcpy(tmpdir,"/tmp"); + if(getenv("TEMP")!=NULL) { + strncpy(tmpdir,getenv("TEMP"),PATH_MAX-20); + } + strcat(tmpdir,"/rdaudioconvertXXXXXX"); + if(mkdtemp(tmpdir)==NULL) { + return RDAudioConvert::ErrorInternal; + } + tmpfile1=QString(tmpdir)+"/signed32_1.wav"; + tmpfile2=QString(tmpdir)+"/signed32_2.wav"; + + // + // Stage One -- Convert Source Format to Signed 32 Bit Integer + // + if((err=Stage1Convert(conv_src_filename,tmpfile1))!= + RDAudioConvert::ErrorOk) { + unlink(tmpfile1); + rmdir(tmpdir); + return err; + } + + // + // Stage Two -- Convert Levels, Sample Rate, Channelization, Speed + // + if((err=Stage2Convert(tmpfile1,tmpfile2))!= + RDAudioConvert::ErrorOk) { + unlink(tmpfile1); + unlink(tmpfile2); + rmdir(tmpdir); + return err; + } + + // + // Stage Three -- Write Out Destination Format + // + if((err=Stage3Convert(tmpfile2,conv_dst_filename))!= + RDAudioConvert::ErrorOk) { + unlink(tmpfile1); + unlink(tmpfile2); + rmdir(tmpdir); + return err; + } + + // + // Clean Up + // + unlink(tmpfile1); + unlink(tmpfile2); + rmdir(tmpdir); + + return RDAudioConvert::ErrorOk; +} + + +bool RDAudioConvert::settingsValid(RDSettings *settings) +{ + return true; +} + + +QString RDAudioConvert::errorText(RDAudioConvert::ErrorCode err) +{ + QString ret=QString().sprintf("Unknown Error [%u]",err); + + switch(err) { + case RDAudioConvert::ErrorOk: + ret=tr("OK"); + break; + + case RDAudioConvert::ErrorInvalidSettings: + ret=tr("Invalid/Unsupported Settings"); + break; + + case RDAudioConvert::ErrorNoSource: + ret=tr("Unable to access source file"); + break; + + case RDAudioConvert::ErrorNoDestination: + ret=tr("Unable to create destination file"); + break; + + case RDAudioConvert::ErrorInvalidSource: + ret=tr("Unrecognized source format"); + break; + + case RDAudioConvert::ErrorInternal: + ret=tr("Internal Error"); + break; + + case RDAudioConvert::ErrorFormatNotSupported: + ret=tr("Unsupported Format"); + break; + + case RDAudioConvert::ErrorNoDisc: + ret=tr("No CD found in drive"); + break; + + case RDAudioConvert::ErrorNoTrack: + ret=tr("No such track on CD"); + break; + + case RDAudioConvert::ErrorInvalidSpeed: + ret=tr("Invalid speed ratio"); + break; + + case RDAudioConvert::ErrorFormatError: + ret=tr("Source format error"); + break; + + case RDAudioConvert::ErrorNoSpace: + ret=tr("No space left on device"); + break; + } + return ret; +} + + +RDAudioConvert::ErrorCode RDAudioConvert::Stage1Convert(const QString &srcfile, + const QString &dstfile) +{ + SNDFILE *sf_src=NULL; + SF_INFO sf_src_info; + RDWaveFile *wave=NULL; + RDAudioConvert::ErrorCode err=RDAudioConvert::ErrorInvalidSource; + + // + // Try RDWaveFile + // + wave=new RDWaveFile(srcfile); + if(wave->openWave(conv_src_wavedata)) { + switch(wave->type()) { + case RDWaveFile::Wave: + if(wave->getFormatTag()==WAVE_FORMAT_MPEG) { + err=Stage1Mpeg(dstfile,wave); + delete wave; + return err; + } + break; + + case RDWaveFile::Mpeg: + case RDWaveFile::Atx: + case RDWaveFile::Tmc: + case RDWaveFile::Ambos: + err=Stage1Mpeg(dstfile,wave); + delete wave; + return err; + + case RDWaveFile::Ogg: + err=Stage1Vorbis(dstfile,wave); + delete wave; + return err; + + case RDWaveFile::Flac: + err=Stage1Flac(dstfile,wave); + delete wave; + return err; + + case RDWaveFile::Unknown: + break; + } + } + delete wave; + + // + // Try Libsndfile + // + memset(&sf_src_info,0,sizeof(sf_src_info)); + if((sf_src=sf_open(srcfile,SFM_READ,&sf_src_info))!=NULL) { + err=Stage1SndFile(dstfile,sf_src,&sf_src_info); + sf_close(sf_src); + return RDAudioConvert::ErrorOk; + } + + return err; +} + + +RDAudioConvert::ErrorCode RDAudioConvert::Stage1Flac(const QString &dstfile, + RDWaveFile *wave) +{ +#ifdef HAVE_FLAC + SNDFILE *sf_dst=NULL; + SF_INFO sf_dst_info; + RDFlacDecode *flac=NULL; + + // + // Open Destination + // + memset(&sf_dst_info,0,sizeof(sf_dst_info)); + sf_dst_info.format=SF_FORMAT_WAV|SF_FORMAT_FLOAT; + sf_dst_info.channels=wave->getChannels(); + sf_dst_info.samplerate=wave->getSamplesPerSec(); + if((sf_dst=sf_open(dstfile,SFM_WRITE,&sf_dst_info))==NULL) { + return RDAudioConvert::ErrorNoDestination; + } + + // + // Decode + // + flac=new RDFlacDecode(sf_dst); + flac->setRange(conv_start_point,conv_end_point); + flac->decode(wave,&conv_peak_sample); + + // + // Clean Up + // + delete flac; + sf_close(sf_dst); + return RDAudioConvert::ErrorOk; +#else + return RDAudioConvert::ErrorFormatNotSupported; +#endif // HAVE_FLAC +} + + +RDAudioConvert::ErrorCode RDAudioConvert::Stage1Vorbis(const QString &dstfile, + RDWaveFile *wave) +{ +#ifdef HAVE_VORBIS + SNDFILE *sf_dst=NULL; + SF_INFO sf_dst_info; + ogg_sync_state ogg_sync; + ogg_stream_state ogg_stream; + ogg_packet ogg_packet; + ogg_page ogg_page; + vorbis_info vorbis_info; + vorbis_comment vorbis_comment; + vorbis_dsp_state vorbis_dsp; + vorbis_block vorbis_block; + int fd; + ssize_t n; + long serialno=-1; + bool vorbis_ready=false; + int frames; + float **pcm; + float pcmbuf[32768]; + sf_count_t start=0; + sf_count_t end=wave->getSampleLength(); + sf_count_t total_frames=0; + + // + // Open Destination + // + memset(&sf_dst_info,0,sizeof(sf_dst_info)); + sf_dst_info.format=SF_FORMAT_WAV|SF_FORMAT_FLOAT; + sf_dst_info.channels=wave->getChannels(); + sf_dst_info.samplerate=wave->getSamplesPerSec(); + if((sf_dst=sf_open(dstfile,SFM_WRITE,&sf_dst_info))==NULL) { + return RDAudioConvert::ErrorNoDestination; + } + + // + // Initialize Decoder + // + if((fd=open(wave->getName(),O_RDONLY))<0) { + sf_close(sf_dst); + return RDAudioConvert::ErrorNoSource; + } + ogg_sync_init(&ogg_sync); + vorbis_info_init(&vorbis_info); + vorbis_comment_init(&vorbis_comment); + + // + // Decode + // + if(conv_start_point>0) { + start=(double)conv_start_point*(double)wave->getSamplesPerSec()/1000.0; + } + if(conv_end_point>=0) { + end=(double)conv_end_point*(double)wave->getSamplesPerSec()/1000.0; + } + while((n=read(fd,ogg_sync_buffer(&ogg_sync,4096),4096))>0) { + ogg_sync_wrote(&ogg_sync,n); + while(ogg_sync_pageout(&ogg_sync,&ogg_page)==1) { + if(serialno<0) { + serialno=ogg_page_serialno(&ogg_page); + ogg_stream_init(&ogg_stream,serialno); + } + if(ogg_stream_pagein(&ogg_stream,&ogg_page)==0) { + if(ogg_stream_packetout(&ogg_stream,&ogg_packet)==1) { + switch(ogg_packet.packetno) { + case 0: // Start Packet + case 1: // Comment Packet + vorbis_synthesis_headerin(&vorbis_info,&vorbis_comment,&ogg_packet); + break; + + case 2: // Codebook Packet + vorbis_synthesis_headerin(&vorbis_info,&vorbis_comment,&ogg_packet); + vorbis_synthesis_init(&vorbis_dsp,&vorbis_info); + vorbis_block_init(&vorbis_dsp,&vorbis_block); + vorbis_ready=true; + break; + + default: // Audio Packets + if(vorbis_synthesis(&vorbis_block,&ogg_packet)==0) { + vorbis_synthesis_blockin(&vorbis_dsp,&vorbis_block); + } + while((frames=vorbis_synthesis_pcmout(&vorbis_dsp,&pcm))>0) { + for(int i=0;i<frames;i++) { + for(int j=0;j<wave->getChannels();j++) { + pcmbuf[wave->getChannels()*i+j]=pcm[j][i]; + } + } + if(total_frames>=start) { + if((total_frames+frames)<end) { // Write entire buffer + UpdatePeak(pcmbuf,frames*wave->getChannels()); + sf_writef_float(sf_dst,pcmbuf,frames); + } + else { + if(total_frames<(total_frames+frames)) { // Write start of buffer + UpdatePeak(pcmbuf, + (total_frames+frames-end)*wave->getChannels()); + sf_writef_float(sf_dst,pcmbuf,total_frames+frames-end); + // + // Done -- no need to decode the rest + // + if(vorbis_ready) { + vorbis_block_clear(&vorbis_block); + vorbis_dsp_clear(&vorbis_dsp); + } + vorbis_info_clear(&vorbis_info); + vorbis_comment_clear(&vorbis_comment); + ogg_stream_clear(&ogg_stream); + ogg_sync_clear(&ogg_sync); + ::close(fd); + sf_close(sf_dst); + + return RDAudioConvert::ErrorOk; + } + } + } + else { + int diff=total_frames+frames-start; + if(diff>0) { // Write end of buffer + UpdatePeak(pcmbuf+diff,(frames-diff)*wave->getChannels()); + sf_writef_float(sf_dst,pcmbuf+diff,frames-diff); + } + } + total_frames+=frames; + vorbis_synthesis_read(&vorbis_dsp,frames); + } + break; + } + } + } + } + } + + // + // Clean Up + // + if(vorbis_ready) { + vorbis_block_clear(&vorbis_block); + vorbis_dsp_clear(&vorbis_dsp); + } + vorbis_info_clear(&vorbis_info); + vorbis_comment_clear(&vorbis_comment); + ogg_stream_clear(&ogg_stream); + ogg_sync_clear(&ogg_sync); + ::close(fd); + sf_close(sf_dst); + + return RDAudioConvert::ErrorOk; +#else + return RDAudioConvert::ErrorFormatNotSupported; +#endif // HAVE_VORBIS +} + +#define STAGE1BUFSIZE 2500 + +RDAudioConvert::ErrorCode RDAudioConvert::Stage1Mpeg(const QString &dstfile, + RDWaveFile *wave) +{ +#ifdef HAVE_MAD + SNDFILE *sf_dst=NULL; + SF_INFO sf_dst_info; + struct mad_stream mad_stream; + struct mad_frame mad_frame; + struct mad_synth mad_synth; + int left_over=0; + int fsize; + int n; + unsigned char buffer[STAGE1BUFSIZE]; + float sf_buffer[1152*2]; + sf_count_t start=0; + sf_count_t end=wave->getSampleLength(); + sf_count_t frames=0; + + // + // Load MAD + // + if(!LoadMad()) { + return RDAudioConvert::ErrorFormatNotSupported; + } + + // + // Open Destination + // + memset(&sf_dst_info,0,sizeof(sf_dst_info)); + sf_dst_info.format=SF_FORMAT_WAV|SF_FORMAT_FLOAT; + sf_dst_info.channels=wave->getChannels(); + sf_dst_info.samplerate=wave->getSamplesPerSec(); + if((sf_dst=sf_open(dstfile,SFM_WRITE,&sf_dst_info))==NULL) { + return RDAudioConvert::ErrorNoDestination; + } + sf_command(sf_dst,SFC_SET_NORM_DOUBLE,NULL,SF_FALSE); + + // + // Initialize Decoder + // + mad_stream_init(&mad_stream); + mad_frame_init(&mad_frame); + mad_synth_init(&mad_synth); + fsize=144*wave->getHeadBitRate()/wave->getSamplesPerSec(); + + // + // Decode + // + if(conv_start_point>0) { + start=(double)conv_start_point*(double)wave->getSamplesPerSec()/1000.0; + } + if(conv_end_point>=0) { + end=(double)conv_end_point*(double)wave->getSamplesPerSec()/1000.0; + } + while((n=wave->readWave(buffer+left_over,fsize))>0) { + if((buffer[left_over]==0xff)&&(buffer[2+left_over]&0x02)!=0) { + n+=wave->readWave(buffer+left_over+n,1); // Padding slot + } + mad_stream_buffer(&mad_stream,buffer,n+left_over); + //printf("mad err: %d\n",mad_stream.error); + while(1) { + + int thiserr=mad_frame_decode(&mad_frame,&mad_stream); + if(thiserr!=0) { + if(!MAD_RECOVERABLE(mad_stream.error)) + break; + else + continue; + } + + //printf("decoding...\n"); + mad_synth_frame(&mad_synth,&mad_frame); + for(int i=0;i<mad_synth.pcm.length;i++) { + for(int j=0;j<mad_synth.pcm.channels;j++) { + sf_buffer[i*mad_synth.pcm.channels+j]= + (float)mad_f_todouble(mad_synth.pcm.samples[j][i]); + } + } + if(frames>=start) { + if((frames+mad_synth.pcm.length)<end) { // Write entire buffer + UpdatePeak(sf_buffer,mad_synth.pcm.length*wave->getChannels()); + sf_writef_float(sf_dst,sf_buffer,mad_synth.pcm.length); + } + else { + if(frames<(frames+mad_synth.pcm.length)) { // Write start of buffer + UpdatePeak(sf_buffer, + (frames+mad_synth.pcm.length-end)*wave->getChannels()); + sf_writef_float(sf_dst,sf_buffer,frames+mad_synth.pcm.length-end); + // + // Done -- no need to decode the rest + // + mad_synth_finish(&mad_synth); + mad_frame_finish(&mad_frame); + mad_stream_finish(&mad_stream); + wave->closeWave(); + sf_close(sf_dst); + return RDAudioConvert::ErrorOk; + } + } + } + else { + int diff=frames+mad_synth.pcm.length-start; + if(diff>0) { // Write end of buffer + UpdatePeak(sf_buffer+diff, + (mad_synth.pcm.length-diff)*wave->getChannels()); + sf_writef_float(sf_dst,sf_buffer+diff,mad_synth.pcm.length-diff); + } + } + frames+=mad_synth.pcm.length; + + } + left_over=mad_stream.bufend-mad_stream.next_frame; + + // Prevent buffer overflow on malformed files. + // The amount checked for should match the maximum amount that may be read + // by the next top-of-loop wave->readWave call. + if(left_over + fsize + 1 > STAGE1BUFSIZE) + return RDAudioConvert::ErrorFormatError; + + memmove(buffer,mad_stream.next_frame,left_over); + + } + memset(buffer+left_over,0,MAD_BUFFER_GUARD); + mad_stream_buffer(&mad_stream,buffer,MAD_BUFFER_GUARD+left_over); + if(mad_frame_decode(&mad_frame,&mad_stream)==0) { + mad_synth_frame(&mad_synth,&mad_frame); + for(int i=0;i<mad_synth.pcm.length;i++) { + for(int j=0;j<mad_synth.pcm.channels;j++) { + sf_buffer[i*mad_synth.pcm.channels+j]= + (float)mad_f_todouble(mad_synth.pcm.samples[j][i]); + } + } + UpdatePeak(sf_buffer,mad_synth.pcm.length*wave->getChannels()); + sf_writef_float(sf_dst,sf_buffer,mad_synth.pcm.length); + } + + // + // Clean Up + // + mad_synth_finish(&mad_synth); + mad_frame_finish(&mad_frame); + mad_stream_finish(&mad_stream); + wave->closeWave(); + + sf_close(sf_dst); + + return RDAudioConvert::ErrorOk; +#else + return RDAudioConvert::ErrorFormatNotSupported; +#endif // HAVE_MAD +} + + +RDAudioConvert::ErrorCode RDAudioConvert::Stage1SndFile(const QString &dstfile, + SNDFILE *sf_src, + SF_INFO *sf_src_info) +{ + SNDFILE *sf_dst=NULL; + SF_INFO sf_dst_info; + sf_count_t start=0; + sf_count_t end=sf_src_info->frames; + + // + // Open Destination + // + sf_dst_info=*sf_src_info; + sf_dst_info.format=SF_FORMAT_WAV|SF_FORMAT_FLOAT; + if((sf_dst=sf_open(dstfile,SFM_WRITE,&sf_dst_info))==NULL) { + return RDAudioConvert::ErrorNoDestination; + } + + // + // Transfer Data + // + sf_count_t buffer_size=2048/sf_src_info->channels; + float *buffer=new float[2048]; + sf_count_t n=0; + if(conv_start_point>0) { + start=sf_seek(sf_src,(double)conv_start_point* + (double)sf_src_info->samplerate/1000.0,SEEK_SET); + } + if(conv_end_point>=0) { + end=(double)conv_end_point*(double)sf_src_info->samplerate/1000.0; + } + while((n=sf_readf_float(sf_src,buffer,buffer_size))>0) { + UpdatePeak(buffer,n*sf_src_info->channels); + sf_writef_float(sf_dst,buffer,n); + start+=n; + if((end-start)<buffer_size) { + buffer_size=end-start; + } + } + delete buffer; + sf_close(sf_dst); + + return RDAudioConvert::ErrorOk; +} + + +RDAudioConvert::ErrorCode RDAudioConvert::Stage2Convert(const QString &srcfile, + const QString &dstfile) +{ + soundtouch::SoundTouch *st_conv=NULL; + SNDFILE *src_sf=NULL; + SNDFILE *dst_sf=NULL; + SF_INFO src_info; + SF_INFO dst_info; + SRC_STATE *src_state=NULL; + SRC_DATA src_data; + float *pcm[3]={NULL,NULL,NULL}; + bool free_pcm[3]={false,false,false}; + int err; + sf_count_t n; + float ratio=1.0; + + // + // Open Files + // + memset(&src_info,0,sizeof(src_info)); + if((src_sf=sf_open(srcfile,SFM_READ,&src_info))==NULL) { + return RDAudioConvert::ErrorInternal; + } + sf_command(src_sf,SFC_SET_NORM_FLOAT,NULL,SF_FALSE); + sf_command(dst_sf,SFC_SET_CLIPPING,NULL,SF_TRUE); + memset(&dst_info,0,sizeof(dst_info)); + dst_info.format=SF_FORMAT_WAV|SF_FORMAT_PCM_32; + dst_info.channels=conv_settings->channels(); + dst_info.samplerate=conv_settings->sampleRate(); + if((dst_sf=sf_open(dstfile,SFM_WRITE,&dst_info))==NULL) { + sf_close(src_sf); + return RDAudioConvert::ErrorInternal; + } + + // + // Allocate Buffers + // + pcm[0]=new float[STAGE2_BUFFER_SIZE]; + free_pcm[0]=true; + if(dst_info.samplerate!=src_info.samplerate) { + pcm[1]=new float[STAGE2_BUFFER_SIZE]; + free_pcm[1]=true; + if(dst_info.channels!=src_info.channels) { + pcm[2]=new float[STAGE2_BUFFER_SIZE]; + free_pcm[2]=true; + } + else { + pcm[2]=pcm[1]; + } + } + else { + pcm[1]=pcm[0]; + if(dst_info.channels!=src_info.channels) { + pcm[2]=new float[STAGE2_BUFFER_SIZE]; + free_pcm[2]=true; + } + else { + pcm[2]=pcm[0]; + } + } + + + // + // Initialize Rate Converter + // + if(dst_info.samplerate!=src_info.samplerate) { + if((src_state=src_new(conv_src_converter,src_info.channels,&err))==NULL) { + sf_close(src_sf); + sf_close(dst_sf); + return RDAudioConvert::ErrorInternal; + } + memset(&src_data,0,sizeof(src_data)); + src_data.src_ratio=(double)dst_info.samplerate/(double)src_info.samplerate; + src_data.data_in=pcm[0]; + src_data.data_out=pcm[1]; + src_data.output_frames=STAGE2_XFER_SIZE*dst_info.samplerate/ + src_info.samplerate+src_info.channels; + } + + // + // Initialize Speed Converter + // + if(conv_speed_ratio!=1.0) { + st_conv=new soundtouch::SoundTouch(); + st_conv->setTempo(conv_speed_ratio); + st_conv->setSampleRate(dst_info.samplerate); + st_conv->setChannels(dst_info.channels); + } + + // + // Calculate Gain Ratio + // + if(conv_settings->normalizationLevel()!=0) { + float gain= + (float)conv_settings->normalizationLevel()-20.0*log10f(conv_peak_sample); + ratio=exp10f(gain/20.0); + } + + // + // Convert + // + while((n=sf_readf_float(src_sf,pcm[0],STAGE2_XFER_SIZE))>0) { + + // + // Levels + // + if(ratio!=1.0) { + for(unsigned i=0;i<(n*src_info.channels);i++) { + pcm[0][i]=ratio*pcm[0][i]; + } + } + + // + // Sample Rate + // + if(src_state!=NULL) { + src_data.input_frames=n; + if((err=src_process(src_state,&src_data))!=0) { + fprintf(stderr,"SRC Error: %s\n",src_strerror(err)); + return RDAudioConvert::ErrorInternal; + } + n=src_data.output_frames_gen; + } + + // + // Channelization + // + switch(src_info.channels) { + case 1: + switch(dst_info.channels) { + case 1: // Nothing to do + break; + + case 2: + for(unsigned i=0;i<n;i++) { + pcm[2][2*i]=pcm[1][i]; + pcm[2][2*i+1]=pcm[1][i]; + } + break; + } + break; + + case 2: + switch(dst_info.channels) { + case 1: + for(unsigned i=0;i<n;i++) { + pcm[2][i]=(pcm[1][2*i]+pcm[1][2*i+1])/2; + } + break; + + case 2: // Nothing to do + break; + } + break; + } + + // + // Speed + // + if(st_conv!=NULL) { + st_conv->putSamples((soundtouch::SAMPLETYPE *)pcm[2],n); + n=st_conv->receiveSamples((soundtouch::SAMPLETYPE *)pcm[2],STAGE2_BUFFER_SIZE/dst_info.channels); + } + + // + // Write Output + // + if(sf_writef_float(dst_sf,pcm[2],n)!=n) { + for(unsigned i=0;i<3;i++) { + if(free_pcm[i]) { + delete pcm[i]; + } + } + if(src_state!=NULL) { + src_delete(src_state); + } + sf_close(src_sf); + sf_close(dst_sf); + return RDAudioConvert::ErrorNoSpace; + } + } + + // + // Finish Up Speed Conversion + // + if(st_conv!=NULL) { + st_conv->flush(); + while((n=st_conv-> + receiveSamples((soundtouch::SAMPLETYPE *)pcm[2], + STAGE2_BUFFER_SIZE/dst_info.channels))>0) { + if(sf_writef_float(dst_sf,pcm[2],n)!=n) { + for(unsigned i=0;i<3;i++) { + if(free_pcm[i]) { + delete pcm[i]; + } + } + if(src_state!=NULL) { + src_delete(src_state); + } + sf_close(src_sf); + sf_close(dst_sf); + return RDAudioConvert::ErrorNoSpace; + } + } + delete st_conv; + } + + // + // Clean Up + // + for(unsigned i=0;i<3;i++) { + if(free_pcm[i]) { + delete pcm[i]; + } + } + if(src_state!=NULL) { + src_delete(src_state); + } + sf_close(src_sf); + sf_close(dst_sf); + + return RDAudioConvert::ErrorOk; +} + + +RDAudioConvert::ErrorCode RDAudioConvert::Stage3Convert(const QString &srcfile, + const QString &dstfile) +{ + SNDFILE *src_sf=NULL; + SF_INFO src_sf_info; + RDAudioConvert::ErrorCode ret; + + // + // Open Source File + // + if((src_sf=sf_open(srcfile,SFM_READ,&src_sf_info))==NULL) { + return RDAudioConvert::ErrorInternal; + } + + switch(conv_settings->format()) { + case RDSettings::Pcm16: + ret=Stage3Pcm16(src_sf,&src_sf_info,dstfile); + break; + + case RDSettings::MpegL2: + ret=Stage3Layer2(src_sf,&src_sf_info,dstfile); + break; + + case RDSettings::MpegL2Wav: + ret=Stage3Layer2Wav(src_sf,&src_sf_info,dstfile); + break; + + case RDSettings::MpegL3: + ret=Stage3Layer3(src_sf,&src_sf_info,dstfile); + break; + + case RDSettings::Flac: + ret=Stage3Flac(src_sf,&src_sf_info,dstfile); + break; + + case RDSettings::OggVorbis: + ret=Stage3Vorbis(src_sf,&src_sf_info,dstfile); + break; + + case RDSettings::MpegL1: + default: + ret=RDAudioConvert::ErrorInvalidSettings; + } + + sf_close(src_sf); + return ret; +} + + +RDAudioConvert::ErrorCode RDAudioConvert::Stage3Flac(SNDFILE *src_sf, + SF_INFO *src_sf_info, + const QString &dstfile) +{ +#ifdef HAVE_FLAC + sf_count_t n; + int32_t *pcm; + + // + // Initialize Encoder + // + FLAC::Encoder::File *flac=new FLAC::Encoder::File(); + flac->set_channels(src_sf_info->channels); + flac->set_bits_per_sample(16); // FIXME: Should vary by input file + flac->set_sample_rate(src_sf_info->samplerate); + //flac->set_compression_level(8); + flac->set_blocksize(0); + unlink(dstfile); + /* + * FLAC <1.2.x + * + flac->set_filename(dstfile.ascii()); + switch(flac->init()) { + case 0: + break; + + default: + delete flac; + return RDAudioConvert::ErrorInternal; + } + */ + /* + * FLAC 1.2.x + */ + switch(flac->init(dstfile.ascii())) { + case FLAC__STREAM_ENCODER_INIT_STATUS_OK: + break; + + case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS: + case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE: + case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE: + delete flac; + return RDAudioConvert::ErrorInvalidSettings; + + case FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR: + case FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER: + case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER: + case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION: + case FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER: + case FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE: + case FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA: + default: + delete flac; + return RDAudioConvert::ErrorInternal; + } + + pcm=new int32_t[2048*src_sf_info->channels]; + + // + // Encode + // + while((n=sf_readf_int(src_sf,pcm,2048))>0) { + for(unsigned i=0;i<(n*src_sf_info->channels);i++) { + pcm[i]=pcm[i]>>16; + } + flac->process_interleaved(pcm,n); + } + flac->finish(); + + // + // Clean Up + // + delete pcm; + delete flac; + + return RDAudioConvert::ErrorOk; +#else + return RDAudioConvert::ErrorFormatNotSupported; +#endif // HAVE_FLAC +} + + +RDAudioConvert::ErrorCode RDAudioConvert::Stage3Vorbis(SNDFILE *src_sf, + SF_INFO *src_sf_info, + const QString &dstfile) +{ +#ifdef HAVE_VORBIS + ogg_stream_state ogg_stream; + ogg_page ogg_page; + ogg_packet header; + ogg_packet comment; + ogg_packet codebook; + ogg_packet ogg_packet; + vorbis_info vorbis_info; + vorbis_comment vorbis_comment; + vorbis_dsp_state vorbis_dsp; + vorbis_block vorbis_block; + float *pcm=NULL; + float **vorbis; + sf_count_t n; + int dst_fd=-1; + + // + // Open Destination File + // + unlink(dstfile); + if((dst_fd=open(dstfile,O_WRONLY|O_CREAT|O_TRUNC, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))<0) { + return RDAudioConvert::ErrorNoDestination; + } + + // + // Initialize the Encoder + // + vorbis_info_init(&vorbis_info); + switch(vorbis_encode_init_vbr(&vorbis_info,src_sf_info->channels, + src_sf_info->samplerate, + conv_settings->quality())) { + case OV_EFAULT: + default: + return RDAudioConvert::ErrorInternal; + + case OV_EINVAL: + case OV_EIMPL: + return RDAudioConvert::ErrorInvalidSettings; + + case 0: + break; + } + vorbis_comment_init(&vorbis_comment); + // Metadata stuff goes here... + vorbis_analysis_init(&vorbis_dsp,&vorbis_info); + vorbis_block_init(&vorbis_dsp,&vorbis_block); + vorbis_analysis_headerout(&vorbis_dsp,&vorbis_comment, + &header,&comment,&codebook); + ogg_stream_init(&ogg_stream,rand()); + ogg_stream_packetin(&ogg_stream,&header); + ogg_stream_packetin(&ogg_stream,&comment); + ogg_stream_packetin(&ogg_stream,&codebook); + pcm=new float[2048*src_sf_info->channels]; + + // + // Encode + // + while((n=sf_readf_float(src_sf,pcm,2048))>0) { + vorbis=vorbis_analysis_buffer(&vorbis_dsp,n); + for(unsigned i=0;i<n;i++) { + for(int j=0;j<src_sf_info->channels;j++) { + vorbis[j][i]=pcm[src_sf_info->channels*i+j]; + } + } + vorbis_analysis_wrote(&vorbis_dsp,n); + while(vorbis_analysis_blockout(&vorbis_dsp,&vorbis_block)>0) { + vorbis_analysis(&vorbis_block,&ogg_packet); + ogg_stream_packetin(&ogg_stream,&ogg_packet); + while(ogg_stream_pageout(&ogg_stream,&ogg_page)!=0) { + if(write(dst_fd,ogg_page.header,ogg_page.header_len)!= + ogg_page.header_len) { + ::close(dst_fd); + delete pcm; + ogg_stream_clear(&ogg_stream); + vorbis_comment_clear(&vorbis_comment); + vorbis_info_clear(&vorbis_info); + return RDAudioConvert::ErrorNoSpace; + } + if(write(dst_fd,ogg_page.body,ogg_page.body_len)!= + ogg_page.body_len) { + ::close(dst_fd); + delete pcm; + ogg_stream_clear(&ogg_stream); + vorbis_comment_clear(&vorbis_comment); + vorbis_info_clear(&vorbis_info); + return RDAudioConvert::ErrorNoSpace; + } + } + } + while(ogg_stream_flush(&ogg_stream,&ogg_page)!=0) { + if(write(dst_fd,ogg_page.header,ogg_page.header_len)!= + ogg_page.header_len) { + ::close(dst_fd); + delete pcm; + ogg_stream_clear(&ogg_stream); + vorbis_comment_clear(&vorbis_comment); + vorbis_info_clear(&vorbis_info); + return RDAudioConvert::ErrorNoSpace; + } + } + if(write(dst_fd,ogg_page.body,ogg_page.body_len)!= + ogg_page.body_len) { + ::close(dst_fd); + delete pcm; + ogg_stream_clear(&ogg_stream); + vorbis_comment_clear(&vorbis_comment); + vorbis_info_clear(&vorbis_info); + return RDAudioConvert::ErrorNoSpace; + } + } + vorbis=vorbis_analysis_buffer(&vorbis_dsp,0); + vorbis_analysis_wrote(&vorbis_dsp,0); + while(vorbis_analysis_blockout(&vorbis_dsp,&vorbis_block)>0) { + vorbis_analysis(&vorbis_block,&ogg_packet); + ogg_stream_packetin(&ogg_stream,&ogg_packet); + while(ogg_stream_pageout(&ogg_stream,&ogg_page)!=0) { + if(write(dst_fd,ogg_page.header,ogg_page.header_len)!= + ogg_page.header_len) { + ::close(dst_fd); + delete pcm; + ogg_stream_clear(&ogg_stream); + vorbis_comment_clear(&vorbis_comment); + vorbis_info_clear(&vorbis_info); + return RDAudioConvert::ErrorNoSpace; + } + if(write(dst_fd,ogg_page.body,ogg_page.body_len)!= + ogg_page.body_len) { + ::close(dst_fd); + delete pcm; + ogg_stream_clear(&ogg_stream); + vorbis_comment_clear(&vorbis_comment); + vorbis_info_clear(&vorbis_info); + return RDAudioConvert::ErrorNoSpace; + } + } + } + while(ogg_stream_flush(&ogg_stream,&ogg_page)!=0) { + if(write(dst_fd,ogg_page.header,ogg_page.header_len)!= + ogg_page.header_len) { + ::close(dst_fd); + delete pcm; + ogg_stream_clear(&ogg_stream); + vorbis_comment_clear(&vorbis_comment); + vorbis_info_clear(&vorbis_info); + return RDAudioConvert::ErrorNoSpace; + } + if(write(dst_fd,ogg_page.body,ogg_page.body_len)!= + ogg_page.body_len) { + ::close(dst_fd); + delete pcm; + ogg_stream_clear(&ogg_stream); + vorbis_comment_clear(&vorbis_comment); + vorbis_info_clear(&vorbis_info); + return RDAudioConvert::ErrorNoSpace; + } + } + + // + // Clean Up + // + ::close(dst_fd); + delete pcm; + ogg_stream_clear(&ogg_stream); + vorbis_comment_clear(&vorbis_comment); + vorbis_info_clear(&vorbis_info); + + return RDAudioConvert::ErrorOk; +#else + return RDAudioConvert::ErrorFormatNotSupported; +#endif // HAVE_VORBIS +} + + +RDAudioConvert::ErrorCode RDAudioConvert::Stage3Layer3(SNDFILE *src_sf, + SF_INFO *src_sf_info, + const QString &dstfile) +{ +#ifdef HAVE_LAME + MPEG_mode mpeg_mode=STEREO; + lame_global_flags *lameopts=NULL; + int dst_fd=-1; + int16_t pcm[2304]; + unsigned char mpeg[2048]; + sf_count_t n; + sf_count_t s; + + // + // Load LAME + // + if(!LoadLame()) { + return RDAudioConvert::ErrorFormatNotSupported; + } + + // + // Determine MPEG Mode + // + switch(src_sf_info->channels) { + case 1: + mpeg_mode=MONO; + break; + + case 2: + mpeg_mode=STEREO; + break; + + default: + return RDAudioConvert::ErrorInvalidSettings; + } + + // + // Open Destination File + // + unlink(dstfile); + if((dst_fd=open(dstfile,O_WRONLY|O_CREAT|O_TRUNC, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))<0) { + return RDAudioConvert::ErrorNoDestination; + } + + // + // Initialize Encoder + // + if((lameopts=lame_init())==NULL) { + lame_close(lameopts); + ::close(dst_fd); + return RDAudioConvert::ErrorInternal; + } + lame_set_mode(lameopts,mpeg_mode); + lame_set_num_channels(lameopts,src_sf_info->channels); + lame_set_in_samplerate(lameopts,src_sf_info->samplerate); + lame_set_out_samplerate(lameopts,src_sf_info->samplerate); + lame_set_brate(lameopts,conv_settings->bitRate()/1000); + lame_set_bWriteVbrTag(lameopts,0); + if(lame_init_params(lameopts)!=0) { + lame_close(lameopts); + ::close(dst_fd); + return RDAudioConvert::ErrorInvalidSettings; + } + + // + // Encode + // + if(src_sf_info->channels==2) { + while((n=sf_readf_short(src_sf,pcm,1152))>0) { + if((s=lame_encode_buffer_interleaved(lameopts,pcm,n,mpeg,2048))>=0) { + if(write(dst_fd,mpeg,s)!=s) { + lame_close(lameopts); + ::close(dst_fd); + return RDAudioConvert::ErrorNoSpace; + } + } + } + } + else { + while((n=sf_readf_short(src_sf,pcm,1152))>0) { + if((s=lame_encode_buffer(lameopts,pcm,NULL,n,mpeg,2048))>=0) { + if(write(dst_fd,mpeg,s)!=s) { + lame_close(lameopts); + ::close(dst_fd); + return RDAudioConvert::ErrorNoSpace; + } + } + } + } + if((s=lame_encode_flush(lameopts,mpeg,2048))>=0) { + if(write(dst_fd,mpeg,s)!=s) { + lame_close(lameopts); + ::close(dst_fd); + return RDAudioConvert::ErrorNoSpace; + } + } + + // + // Clean Up + // + lame_close(lameopts); + ::close(dst_fd); + + // + // Apply Metadata + // + if(conv_dst_wavedata!=NULL) { + ApplyId3Tag(dstfile,conv_dst_wavedata); + } + + return RDAudioConvert::ErrorOk; +#else + return RDAudioConvert::ErrorFormatNotSupported; +#endif // HAVE_LAME +} + + +RDAudioConvert::ErrorCode RDAudioConvert::Stage3Layer2Wav(SNDFILE *src_sf, + SF_INFO *src_sf_info, + const QString &dstfile) +{ +#ifdef HAVE_TWOLAME + short *sf_buffer=NULL; + sf_count_t n; + ssize_t s; + RDWaveFile *wave=NULL; + TWOLAME_MPEG_mode mpeg_mode=TWOLAME_STEREO; + twolame_options *lameopts=NULL; + float pcm[2304]; + unsigned char mpeg[2048]; + + // + // Load TwoLAME + // + if(!LoadTwoLame()) { + return RDAudioConvert::ErrorFormatNotSupported; + } + + // + // Determine MPEG Mode + // + switch(src_sf_info->channels) { + case 1: + mpeg_mode=TWOLAME_MONO; + break; + + case 2: + mpeg_mode=TWOLAME_STEREO; + break; + + default: + return RDAudioConvert::ErrorInvalidSettings; + } + + // + // Open Destination File + // + wave=new RDWaveFile(dstfile); + wave->setFormatTag(WAVE_FORMAT_MPEG); + wave->setChannels(src_sf_info->channels); + switch(src_sf_info->channels) { + case 1: + wave->setHeadMode(ACM_MPEG_SINGLECHANNEL); + break; + + case 2: + wave->setHeadMode(ACM_MPEG_STEREO); + break; + } + wave->setSamplesPerSec(src_sf_info->samplerate); + wave->setHeadLayer(2); + wave->setHeadBitRate(conv_settings->bitRate()); + wave->setBextChunk(true); + wave->setMextChunk(true); + wave->setCartChunk(conv_dst_wavedata!=NULL); + wave->setLevlChunk(true); + sf_buffer=new int16_t[2048*src_sf_info->channels]; + unlink(dstfile); + if(!wave->createWave(conv_dst_wavedata)) { + return RDAudioConvert::ErrorNoDestination; + } + + // + // Initialize Encoder + // + if((lameopts=twolame_init())==NULL) { + wave->closeWave(); + return RDAudioConvert::ErrorInternal; + } + twolame_set_mode(lameopts,mpeg_mode); + twolame_set_num_channels(lameopts,src_sf_info->channels); + twolame_set_in_samplerate(lameopts,src_sf_info->samplerate); + twolame_set_out_samplerate(lameopts,src_sf_info->samplerate); + twolame_set_bitrate(lameopts,conv_settings->bitRate()/1000); + twolame_set_energy_levels(lameopts,1); + if(twolame_init_params(lameopts)!=0) { + twolame_close(&lameopts); + wave->closeWave(); + return RDAudioConvert::ErrorInvalidSettings; + } + + // + // Encode + // + while((n=sf_readf_float(src_sf,pcm,1152))>0) { + if((s=twolame_encode_buffer_float32_interleaved(lameopts, + pcm,n,mpeg,2048))>=0) { + if(wave->writeWave(mpeg,s)!=s) { + twolame_close(&lameopts); + wave->closeWave(src_sf_info->frames); + return RDAudioConvert::ErrorNoSpace; + } + } + else { + fprintf(stderr,"TwoLAME encode error\n"); + } + } + if((s=twolame_encode_flush(lameopts,mpeg,2048))>=0) { + if(wave->writeWave(mpeg,s)!=s) { + twolame_close(&lameopts); + wave->closeWave(src_sf_info->frames); + return RDAudioConvert::ErrorNoSpace; + } + } + else { + fprintf(stderr,"TwoLAME encode error\n"); + } + + // + // Clean Up + // + twolame_close(&lameopts); + wave->closeWave(src_sf_info->frames); + return RDAudioConvert::ErrorOk; +#else + return RDAudioConvert::ErrorFormatNotSupported; +#endif // HAVE_TWOLAME +} + + +RDAudioConvert::ErrorCode RDAudioConvert::Stage3Layer2(SNDFILE *src_sf, + SF_INFO *src_sf_info, + const QString &dstfile) +{ +#ifdef HAVE_TWOLAME + sf_count_t n; + ssize_t s; + int dst_fd=-1; + TWOLAME_MPEG_mode mpeg_mode=TWOLAME_STEREO; + twolame_options *lameopts=NULL; + float pcm[2304]; + unsigned char mpeg[2048]; + + if(!LoadTwoLame()) { + return RDAudioConvert::ErrorFormatNotSupported; + } + if((conv_settings->bitRate()>192000)&&(src_sf_info->channels<2)) { + return RDAudioConvert::ErrorInvalidSettings; + } + + // + // Determine MPEG Mode + // + switch(src_sf_info->channels) { + case 1: + mpeg_mode=TWOLAME_MONO; + break; + + case 2: + mpeg_mode=TWOLAME_STEREO; + break; + + default: + return RDAudioConvert::ErrorInvalidSettings; + } + + // + // Open Destination File + // + unlink(dstfile); + if((dst_fd=open(dstfile,O_WRONLY|O_CREAT|O_TRUNC, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))<0) { + return RDAudioConvert::ErrorNoDestination; + } + + // + // Initialize Encoder + // + if((lameopts=twolame_init())==NULL) { + ::close(dst_fd); + return RDAudioConvert::ErrorInternal; + } + twolame_set_mode(lameopts,mpeg_mode); + twolame_set_num_channels(lameopts,src_sf_info->channels); + twolame_set_in_samplerate(lameopts,src_sf_info->samplerate); + twolame_set_out_samplerate(lameopts,src_sf_info->samplerate); + twolame_set_bitrate(lameopts,conv_settings->bitRate()/1000); + if(twolame_init_params(lameopts)!=0) { + twolame_close(&lameopts); + ::close(dst_fd); + return RDAudioConvert::ErrorInvalidSettings; + } + + // + // Encode + // + while((n=sf_readf_float(src_sf,pcm,1152))>0) { + if((s=twolame_encode_buffer_float32_interleaved(lameopts, + pcm,n,mpeg,2048))>=0) { + if(write(dst_fd,mpeg,s)!=s) { + twolame_close(&lameopts); + ::close(dst_fd); + return RDAudioConvert::ErrorNoSpace; + } + } + else { + fprintf(stderr,"TwoLAME encode error\n"); + } + } + if((s=twolame_encode_flush(lameopts,mpeg,2048))>=0) { + if(write(dst_fd,mpeg,s)!=s) { + twolame_close(&lameopts); + ::close(dst_fd); + return RDAudioConvert::ErrorNoSpace; + } + } + else { + fprintf(stderr,"TwoLAME encode error\n"); + } + + // + // Clean Up + // + twolame_close(&lameopts); + ::close(dst_fd); + + // + // Apply Metadata + // + if(conv_dst_wavedata!=NULL) { + ApplyId3Tag(dstfile,conv_dst_wavedata); + } + + return RDAudioConvert::ErrorOk; +#else + return RDAudioConvert::ErrorFormatNotSupported; +#endif // HAVE_TWOLAME +} + + +RDAudioConvert::ErrorCode RDAudioConvert::Stage3Pcm16(SNDFILE *src_sf, + SF_INFO *src_sf_info, + const QString &dstfile) +{ + short *sf_buffer=NULL; + ssize_t n; + + RDWaveFile *wave=new RDWaveFile(dstfile); + wave->setFormatTag(WAVE_FORMAT_PCM); + wave->setEncoding(RDWaveFile::Signed16Int); + wave->setChannels(src_sf_info->channels); + wave->setSamplesPerSec(src_sf_info->samplerate); + wave->setBitsPerSample(16); + wave->setBextChunk(true); + wave->setCartChunk(conv_dst_wavedata!=NULL); + if((conv_dst_wavedata!=NULL)&&(conv_settings->normalizationLevel()!=0)) { + wave->setCartLevelRef(32768* + exp10((double)conv_settings->normalizationLevel()/20.0)); + } + wave->setLevlChunk(true); + sf_buffer=new int16_t[2048*src_sf_info->channels]; + unlink(dstfile); + if(!wave->createWave(conv_dst_wavedata)) { + return RDAudioConvert::ErrorNoDestination; + } + while((n=sf_readf_short(src_sf,sf_buffer,2048))>0) { + if((unsigned)wave-> + writeWave(sf_buffer,n*sizeof(short)*src_sf_info->channels)!= + (n*sizeof(short)*src_sf_info->channels)) { + delete sf_buffer; + wave->closeWave(); + delete wave; + return RDAudioConvert::ErrorNoSpace; + } + } + delete sf_buffer; + wave->closeWave(); + delete wave; + return RDAudioConvert::ErrorOk; +} + + +void RDAudioConvert::ApplyId3Tag(const QString &filename,RDWaveData *wavedata) +{ + ID3_Tag *tag=new ID3_Tag(filename); + ID3_Frame *frame=new ID3_Frame(ID3FID_TITLE); + frame->GetField(ID3FN_TEXT)->Set(wavedata->title()); + tag->AddNewFrame(frame); + + if(wavedata->beatsPerMinute()>0) { + frame=new ID3_Frame(ID3FID_BPM); + frame->GetField(ID3FN_TEXT)-> + Set(QString().sprintf("%d",wavedata->beatsPerMinute())); + tag->AddNewFrame(frame); + } + if(!wavedata->album().isEmpty()) { + frame=new ID3_Frame(ID3FID_ALBUM); + frame->GetField(ID3FN_TEXT)->Set(wavedata->album()); + tag->AddNewFrame(frame); + } + if(!wavedata->composer().isEmpty()) { + frame=new ID3_Frame(ID3FID_COMPOSER); + frame->GetField(ID3FN_TEXT)->Set(wavedata->composer()); + tag->AddNewFrame(frame); + } + if(!wavedata->copyrightNotice().isEmpty()) { + frame=new ID3_Frame(ID3FID_COPYRIGHT); + frame->GetField(ID3FN_TEXT)->Set(wavedata->copyrightNotice()); + tag->AddNewFrame(frame); + } + if(!wavedata->artist().isEmpty()) { + frame=new ID3_Frame(ID3FID_LEADARTIST); + frame->GetField(ID3FN_TEXT)->Set(wavedata->artist()); + tag->AddNewFrame(frame); + } + if(!wavedata->publisher().isEmpty()) { + frame=new ID3_Frame(ID3FID_PUBLISHER); + frame->GetField(ID3FN_TEXT)->Set(wavedata->publisher()); + tag->AddNewFrame(frame); + } + if(!wavedata->isrc().isEmpty()) { + frame=new ID3_Frame(ID3FID_ISRC); + frame->GetField(ID3FN_TEXT)->Set(wavedata->isrc()); + tag->AddNewFrame(frame); + } + if(wavedata->releaseYear()>0) { + frame=new ID3_Frame(ID3FID_YEAR); + frame->GetField(ID3FN_TEXT)-> + Set(QString().sprintf("%d",wavedata->releaseYear())); + tag->AddNewFrame(frame); + } + tag->Update(); + delete tag; +} + + +void RDAudioConvert::UpdatePeak(const float data[],ssize_t len) +{ + float peak; + + for(ssize_t i=0;i<len;i++) { + if((peak=fabsf(data[i]))>conv_peak_sample) { + conv_peak_sample=peak; + } + } +} + + +void RDAudioConvert::UpdatePeak(const double data[],ssize_t len) +{ + float peak; + + for(ssize_t i=0;i<len;i++) { + if((peak=(float)fabsf(data[i]))>conv_peak_sample) { + conv_peak_sample=peak; + } + } +} + + +bool RDAudioConvert::LoadMad() +{ +#ifdef HAVE_MAD + if(conv_mad_handle==NULL) { + return false; + } + *(void **)(&mad_stream_init)= + dlsym(conv_mad_handle,"mad_stream_init"); + *(void **)(&mad_frame_init)= + dlsym(conv_mad_handle,"mad_frame_init"); + *(void **)(&mad_synth_init)= + dlsym(conv_mad_handle,"mad_synth_init"); + *(void **)(&mad_stream_buffer)= + dlsym(conv_mad_handle,"mad_stream_buffer"); + *(void **)(&mad_frame_decode)= + dlsym(conv_mad_handle,"mad_frame_decode"); + *(void **)(&mad_synth_frame)= + dlsym(conv_mad_handle,"mad_synth_frame"); + *(void **)(&mad_frame_finish)= + dlsym(conv_mad_handle,"mad_frame_finish"); + *(void **)(&mad_stream_finish)= + dlsym(conv_mad_handle,"mad_stream_finish"); + return true; +#else + return false; +#endif // HAVE_MAD +} + + +bool RDAudioConvert::LoadTwoLame() +{ +#ifdef HAVE_TWOLAME + if(conv_twolame_handle==NULL) { + return false; + } + *(void **)(&twolame_init)=dlsym(conv_twolame_handle,"twolame_init"); + *(void **)(&twolame_set_mode)=dlsym(conv_twolame_handle,"twolame_set_mode"); + *(void **)(&twolame_set_num_channels)= + dlsym(conv_twolame_handle,"twolame_set_num_channels"); + *(void **)(&twolame_set_in_samplerate)= + dlsym(conv_twolame_handle,"twolame_set_in_samplerate"); + *(void **)(&twolame_set_out_samplerate)= + dlsym(conv_twolame_handle,"twolame_set_out_samplerate"); + *(void **)(&twolame_set_bitrate)= + dlsym(conv_twolame_handle,"twolame_set_bitrate"); + *(void **)(&twolame_init_params)= + dlsym(conv_twolame_handle,"twolame_init_params"); + *(void **)(&twolame_close)=dlsym(conv_twolame_handle,"twolame_close"); + *(void **)(&twolame_encode_buffer_float32_interleaved)= + dlsym(conv_twolame_handle,"twolame_encode_buffer_float32_interleaved"); + *(void **)(&twolame_encode_flush)= + dlsym(conv_twolame_handle,"twolame_encode_flush"); + *(void **)(&twolame_set_energy_levels)= + dlsym(conv_twolame_handle,"twolame_set_energy_levels"); + return true; +#else + return false; +#endif // HAVE_TWOLAME +} + + +bool RDAudioConvert::LoadLame() +{ +#ifdef HAVE_LAME + if(conv_lame_handle==NULL) { + return false; + } + *(void **)(&lame_init)=dlsym(conv_lame_handle,"lame_init"); + *(void **)(&lame_set_mode)= + dlsym(conv_lame_handle,"lame_set_mode"); + *(void **)(&lame_set_num_channels)= + dlsym(conv_lame_handle,"lame_set_num_channels"); + *(void **)(&lame_set_in_samplerate)= + dlsym(conv_lame_handle,"lame_set_in_samplerate"); + *(void **)(&lame_set_out_samplerate)= + dlsym(conv_lame_handle,"lame_set_out_samplerate"); + *(void **)(&lame_set_brate)=dlsym(conv_lame_handle,"lame_set_brate"); + *(void **)(&lame_init_params)=dlsym(conv_lame_handle,"lame_init_params"); + *(void **)(&lame_close)=dlsym(conv_lame_handle,"lame_close"); + *(void **)(&lame_encode_buffer_interleaved)= + dlsym(conv_lame_handle,"lame_encode_buffer_interleaved"); + *(void **)(&lame_encode_buffer)= + dlsym(conv_lame_handle,"lame_encode_buffer"); + *(void **)(&lame_encode_flush)=dlsym(conv_lame_handle,"lame_encode_flush"); + *(void **)(&lame_set_bWriteVbrTag)= + dlsym(conv_lame_handle,"lame_set_bWriteVbrTag"); + return true; +#else + return false; +#endif // HAVE_LAME +} diff --git a/lib/rdaudioconvert.h b/lib/rdaudioconvert.h new file mode 100644 index 00000000..3b833c9a --- /dev/null +++ b/lib/rdaudioconvert.h @@ -0,0 +1,156 @@ +// rdaudioconvert.h +// +// Convert Audio File Formats +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudioconvert.h,v 1.4.4.1 2012/09/06 19:47:15 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDAUDIOCONVERT_H +#define RDAUDIOCONVERT_H + +#include <sndfile.h> +#ifdef HAVE_TWOLAME +#include <twolame.h> +#endif // HAVE_TWOLAME +#ifdef HAVE_LAME +#include <lame/lame.h> +#endif // HAVE_LAME +#ifdef HAVE_MAD +#include <mad.h> +#endif // HAVE_MAD +#include <qobject.h> + +#include <rdwavedata.h> +#include <rdsettings.h> +#include <rdwavefile.h> + +class RDAudioConvert : public QObject +{ + Q_OBJECT; + public: + enum ErrorCode {ErrorOk=0,ErrorInvalidSettings=1,ErrorNoSource=2, + ErrorNoDestination=3,ErrorInvalidSource=4,ErrorInternal=5, + ErrorFormatNotSupported=6,ErrorNoDisc=7,ErrorNoTrack=8, + ErrorInvalidSpeed=9,ErrorFormatError=10,ErrorNoSpace=11}; + RDAudioConvert(const QString &station_name, + QObject *parent=0,const char *name=0); + ~RDAudioConvert(); + void setSourceFile(const QString &filename); + void setDestinationFile(const QString &filename); + void setDestinationSettings(RDSettings *settings); + RDWaveData *sourceWaveData() const; + void setDestinationWaveData(RDWaveData *wavedata); + void setRange(int start_pt,int end_pt); + void setSpeedRatio(float ratio); + RDAudioConvert::ErrorCode convert(); + static bool settingsValid(RDSettings *settings); + static QString errorText(RDAudioConvert::ErrorCode err); + + private: + RDAudioConvert::ErrorCode Stage1Convert(const QString &srcfile, + const QString &dstfile); + RDAudioConvert::ErrorCode Stage1Flac(const QString &dstfile, + RDWaveFile *wave); + RDAudioConvert::ErrorCode Stage1Vorbis(const QString &dstfile, + RDWaveFile *wave); + RDAudioConvert::ErrorCode Stage1Mpeg(const QString &dstfile, + RDWaveFile *wave); + RDAudioConvert::ErrorCode Stage1SndFile(const QString &dstfile, + SNDFILE *sf_src, + SF_INFO *sf_src_info); + RDAudioConvert::ErrorCode Stage2Convert(const QString &srcfile, + const QString &dstfile); + RDAudioConvert::ErrorCode Stage3Convert(const QString &srcfile, + const QString &dstfile); + RDAudioConvert::ErrorCode Stage3Flac(SNDFILE *src_sf,SF_INFO *src_sf_info, + const QString &dstfile); + RDAudioConvert::ErrorCode Stage3Vorbis(SNDFILE *src_sf,SF_INFO *src_sf_info, + const QString &dstfile); + RDAudioConvert::ErrorCode Stage3Layer3(SNDFILE *src_sf,SF_INFO *src_sf_info, + const QString &dstfile); + RDAudioConvert::ErrorCode Stage3Layer2Wav(SNDFILE *src_sf, + SF_INFO *src_sf_info, + const QString &dstfile); + RDAudioConvert::ErrorCode Stage3Layer2(SNDFILE *src_sf,SF_INFO *src_sf_info, + const QString &dstfile); + RDAudioConvert::ErrorCode Stage3Pcm16(SNDFILE *src_sf,SF_INFO *src_sf_info, + const QString &dstfile); + void ApplyId3Tag(const QString &filename,RDWaveData *wavedata); + void UpdatePeak(const float data[],ssize_t len); + void UpdatePeak(const double data[],ssize_t len); + bool LoadMad(); + bool LoadTwoLame(); + bool LoadLame(); + QString conv_src_filename; + QString conv_dst_filename; + int conv_start_point; + int conv_end_point; + float conv_speed_ratio; + RDSettings *conv_settings; + RDWaveData *conv_src_wavedata; + RDWaveData *conv_dst_wavedata; + float conv_peak_sample; + int conv_src_converter; + void *conv_mad_handle; + void *conv_lame_handle; + void *conv_twolame_handle; +#ifdef HAVE_MAD + void (*mad_stream_init)(struct mad_stream *); + void (*mad_frame_init)(struct mad_frame *); + void (*mad_synth_init)(struct mad_synth *); + void (*mad_stream_buffer)(struct mad_stream *,unsigned char const *, + unsigned long); + int (*mad_frame_decode)(struct mad_frame *, struct mad_stream *); + void (*mad_synth_frame)(struct mad_synth *, struct mad_frame const *); + void (*mad_frame_finish)(struct mad_frame *); + void (*mad_stream_finish)(struct mad_stream *); +#endif // HAVE_MAD +#ifdef HAVE_TWOLAME + twolame_options *(*twolame_init)(void); + void (*twolame_set_mode)(twolame_options *,TWOLAME_MPEG_mode); + void (*twolame_set_num_channels)(twolame_options *,int); + void (*twolame_set_in_samplerate)(twolame_options *,int); + void (*twolame_set_out_samplerate)(twolame_options *,int); + void (*twolame_set_bitrate)(twolame_options *,int); + int (*twolame_init_params)(twolame_options *); + void (*twolame_close)(twolame_options **); + int (*twolame_encode_buffer_float32_interleaved) + (twolame_options *,const float[],int,unsigned char *,int); + int (*twolame_encode_flush)(twolame_options *,unsigned char *,int); + int (*twolame_set_energy_levels)(twolame_options *,int); +#endif // HAVE_TWOLAME +#ifdef HAVE_LAME + lame_global_flags *(*lame_init)(void); + void (*lame_set_mode)(lame_global_flags *,int); + void (*lame_set_num_channels)(lame_global_flags *,int); + void (*lame_set_in_samplerate)(lame_global_flags *,int); + void (*lame_set_out_samplerate)(lame_global_flags *,int); + void (*lame_set_brate)(lame_global_flags *,int); + int (*lame_init_params)(lame_global_flags *); + void (*lame_close)(lame_global_flags *); + int (*lame_encode_buffer_interleaved) + (lame_global_flags *,short int[],int,unsigned char *,int); + int (*lame_encode_buffer) + (lame_global_flags *,short int[],short int[],int,unsigned char *,int); + int (*lame_encode_flush)(lame_global_flags *,unsigned char *,int); + int (*lame_set_bWriteVbrTag)(lame_global_flags *, int); +#endif // HAVE_LAME +}; + + +#endif // RDAUDIOCONVERT_H diff --git a/lib/rdaudioexport.cpp b/lib/rdaudioexport.cpp new file mode 100644 index 00000000..41e59e6a --- /dev/null +++ b/lib/rdaudioexport.cpp @@ -0,0 +1,279 @@ +// rdaudioexport.cpp +// +// Export an Audio File using the RdXport Web Service +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudioexport.cpp,v 1.8.4.1 2013/11/13 23:36:30 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> + +#include <curl/curl.h> + +#include <qapplication.h> + +#include <rd.h> +#include <rdxport_interface.h> +#include <rdformpost.h> +#include <rdaudioexport.h> +#include <rdwebresult.h> + +// +// CURL Progress Callback +// +int ExportProgressCallback(void *clientp,double dltotal,double dlnow, + double ultotal,double ulnow) +{ + RDAudioExport *conv=(RDAudioExport *)clientp; + qApp->processEvents(); + if(conv->aborting()) { + return 1; + } + return 0; +} + + +RDAudioExport::RDAudioExport(RDStation *station,RDConfig *config, + QObject *parent,const char *name) + : QObject(parent,name) +{ + conv_station=station; + conv_config=config; + conv_cart_number=0; + conv_cut_number=0; + conv_start_point=-1; + conv_end_point=-1; + conv_enable_metadata=false; + conv_settings=NULL; + conv_aborting=false; +} + + +void RDAudioExport::setCartNumber(unsigned cartnum) +{ + conv_cart_number=cartnum; +} + + +void RDAudioExport::setCutNumber(unsigned cutnum) +{ + conv_cut_number=cutnum; +} + + +void RDAudioExport::setDestinationFile(const QString &filename) +{ + conv_dst_filename=filename; +} + + +void RDAudioExport::setDestinationSettings(RDSettings *settings) +{ + conv_settings=settings; +} + + +void RDAudioExport::setRange(int start_pt,int end_pt) +{ + conv_start_point=start_pt; + conv_end_point=end_pt; +} + + +void RDAudioExport::setEnableMetadata(bool state) +{ + conv_enable_metadata=state; +} + + +RDAudioExport::ErrorCode RDAudioExport::runExport(const QString &username, + const QString &password, + RDAudioConvert::ErrorCode *conv_err) +{ + long response_code; + CURL *curl=NULL; + FILE *f=NULL; + char url[1024]; + RDAudioExport::ErrorCode ret; + RDWebResult web_result; + + // + // Generate POST Data + // + QString post=QString().sprintf("COMMAND=%d&LOGIN_NAME=%s&PASSWORD=%s&CART_NUMBER=%u&CUT_NUMBER=%u&FORMAT=%d&CHANNELS=%d&SAMPLE_RATE=%d&BIT_RATE=%d&QUALITY=%d&START_POINT=%d&END_POINT=%d&NORMALIZATION_LEVEL=%d&ENABLE_METADATA=%d", + RDXPORT_COMMAND_EXPORT, + (const char *)RDFormPost::urlEncode(username), + (const char *)RDFormPost::urlEncode(password), + conv_cart_number, + conv_cut_number, + conv_settings->format(), + conv_settings->channels(), + conv_settings->sampleRate(), + conv_settings->bitRate(), + conv_settings->quality(), + conv_start_point, + conv_end_point, + conv_settings->normalizationLevel(), + conv_enable_metadata); + + if((curl=curl_easy_init())==NULL) { + return RDAudioExport::ErrorInternal; + } + if((f=fopen(conv_dst_filename,"w"))==NULL) { + curl_easy_cleanup(curl); + return RDAudioExport::ErrorNoDestination; + } + // + // Write out URL as a C string before passing to curl_easy_setopt(), + // otherwise some versions of LibCurl will throw a 'bad/illegal format' + // error. + // + strncpy(url,conv_station->webServiceUrl(conv_config),1024); + curl_easy_setopt(curl,CURLOPT_URL,url); + curl_easy_setopt(curl,CURLOPT_WRITEDATA,f); + curl_easy_setopt(curl,CURLOPT_POST,1); + curl_easy_setopt(curl,CURLOPT_POSTFIELDS,(const char *)post); + curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT); + curl_easy_setopt(curl,CURLOPT_PROGRESSFUNCTION,ExportProgressCallback); + curl_easy_setopt(curl,CURLOPT_PROGRESSDATA,this); + curl_easy_setopt(curl,CURLOPT_NOPROGRESS,0); + + switch(curl_easy_perform(curl)) { + case CURLE_OK: + break; + + case CURLE_ABORTED_BY_CALLBACK: + curl_easy_cleanup(curl); + unlink(conv_dst_filename); + return RDAudioExport::ErrorAborted; + + case CURLE_UNSUPPORTED_PROTOCOL: + case CURLE_FAILED_INIT: + case CURLE_COULDNT_RESOLVE_PROXY: + case CURLE_PARTIAL_FILE: + case CURLE_HTTP_RETURNED_ERROR: + case CURLE_WRITE_ERROR: + case CURLE_OUT_OF_MEMORY: + case CURLE_OPERATION_TIMEDOUT: + case CURLE_HTTP_POST_ERROR: + curl_easy_cleanup(curl); + return RDAudioExport::ErrorInternal; + + case CURLE_URL_MALFORMAT: + case CURLE_COULDNT_RESOLVE_HOST: + case CURLE_COULDNT_CONNECT: + case 9: // CURLE_REMOTE_ACCESS_DENIED: + curl_easy_cleanup(curl); + return RDAudioExport::ErrorUrlInvalid; + } + curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&response_code); + curl_easy_cleanup(curl); + fclose(f); + + if(response_code==200) { + *conv_err=RDAudioConvert::ErrorOk; + return RDAudioExport::ErrorOk; + } + + if(web_result.readXmlFromFile(conv_dst_filename)) { + *conv_err=web_result.converterErrorCode(); + } + switch(response_code) { + case 400: + ret=RDAudioExport::ErrorService; + + case 401: + ret=RDAudioExport::ErrorInvalidUser; + + case 404: + ret=RDAudioExport::ErrorNoSource; + + default: + ret=RDAudioExport::ErrorConverter; + } + unlink(conv_dst_filename); + + return ret; +} + + +bool RDAudioExport::aborting() const +{ + return conv_aborting; +} + + +QString RDAudioExport::errorText(RDAudioExport::ErrorCode err, + RDAudioConvert::ErrorCode conv_err) +{ + QString ret=QString().sprintf("Uknown Error [%u]",err); + + switch(err) { + case RDAudioExport::ErrorOk: + ret=tr("OK"); + break; + + case RDAudioExport::ErrorInvalidSettings: + ret=tr("Invalid/unsupported audio parameters"); + break; + + case RDAudioExport::ErrorNoSource: + ret=tr("No such cart/cut"); + break; + + case RDAudioExport::ErrorNoDestination: + ret=tr("Unable to create destination file"); + break; + + case RDAudioExport::ErrorInternal: + ret=tr("Internal Error"); + break; + + case RDAudioExport::ErrorUrlInvalid: + ret=tr("Invalid URL"); + break; + + case RDAudioExport::ErrorService: + ret=tr("RDXport service returned an error"); + break; + + case RDAudioExport::ErrorInvalidUser: + ret=tr("Invalid user or password"); + break; + + case RDAudioExport::ErrorAborted: + ret=tr("Aborted"); + break; + + case RDAudioExport::ErrorConverter: + ret=tr("Audio Converter Error: ")+RDAudioConvert::errorText(conv_err); + break; + } + return ret; +} + + +void RDAudioExport::abort() +{ + conv_aborting=true; +} diff --git a/lib/rdaudioexport.h b/lib/rdaudioexport.h new file mode 100644 index 00000000..9346275b --- /dev/null +++ b/lib/rdaudioexport.h @@ -0,0 +1,76 @@ +// rdaudioexport.h +// +// Export an Audio File using the RdXport Web Service +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudioexport.h,v 1.4.4.1 2013/11/13 23:36:30 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDAUDIOEXPORT_H +#define RDAUDIOEXPORT_H + +#include <qobject.h> + +#include <rdconfig.h> +#include <rdstation.h> +#include <rdsettings.h> +#include <rdaudioconvert.h> + +class RDAudioExport : public QObject +{ + Q_OBJECT; + public: + enum ErrorCode {ErrorOk=0,ErrorInvalidSettings=1,ErrorNoSource=2, + ErrorNoDestination=3,ErrorInternal=5,ErrorUrlInvalid=7, + ErrorService=8,ErrorInvalidUser=9,ErrorAborted=10, + ErrorConverter=11}; + RDAudioExport(RDStation *station,RDConfig *config,QObject *parent=0, + const char *name=0); + void setCartNumber(unsigned cartnum); + void setCutNumber(unsigned cutnum); + void setDestinationFile(const QString &filename); + void setDestinationSettings(RDSettings *settings); + void setRange(int start_pt,int end_pt); + void setEnableMetadata(bool state); + RDAudioExport::ErrorCode runExport(const QString &username, + const QString &password, + RDAudioConvert::ErrorCode *conv_err); + bool aborting() const; + static QString errorText(RDAudioExport::ErrorCode err, + RDAudioConvert::ErrorCode conv_err); + + public slots: + void abort(); + + signals: + void strobe(); + + private: + RDStation *conv_station; + RDConfig *conv_config; + unsigned conv_cart_number; + unsigned conv_cut_number; + QString conv_dst_filename; + int conv_start_point; + int conv_end_point; + bool conv_enable_metadata; + RDSettings *conv_settings; + bool conv_aborting; +}; + + +#endif // RDAUDIOEXPORT_H diff --git a/lib/rdaudioimport.cpp b/lib/rdaudioimport.cpp new file mode 100644 index 00000000..11911936 --- /dev/null +++ b/lib/rdaudioimport.cpp @@ -0,0 +1,319 @@ +// rdaudioimport.cpp +// +// Import an Audio File using the RdXport Web Service +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudioimport.cpp,v 1.12.4.4 2014/01/15 19:56:32 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <syslog.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> + +#include <curl/curl.h> + +#include <qapplication.h> + +#include <rd.h> +#include <rdxport_interface.h> +#include <rdformpost.h> +#include <rdaudioimport.h> +#include <rdwebresult.h> + +// +// CURL Callbacks +// +size_t ImportReadCallback(void *ptr,size_t size,size_t nmemb,void *userdata) +{ + QString *xml=(QString *)userdata; + for(unsigned i=0;i<(size*nmemb);i++) { + *xml+=((const char *)ptr)[i]; + } + return size*nmemb; +} + + +int ImportProgressCallback(void *clientp,double dltotal,double dlnow, + double ultotal,double ulnow) +{ + RDAudioImport *conv=(RDAudioImport *)clientp; + qApp->processEvents(); + if(conv->aborting()) { + return 1; + } + return 0; +} + + +RDAudioImport::RDAudioImport(RDStation *station,RDConfig *config, + QObject *parent,const char *name) + : QObject(parent,name) +{ + conv_station=station; + conv_config=config; + conv_cart_number=0; + conv_cut_number=0; + conv_settings=NULL; + conv_use_metadata=false; + conv_aborting=false; +} + + +void RDAudioImport::setCartNumber(unsigned cartnum) +{ + conv_cart_number=cartnum; +} + + +void RDAudioImport::setCutNumber(unsigned cutnum) +{ + conv_cut_number=cutnum; +} + + +void RDAudioImport::setSourceFile(const QString &filename) +{ + conv_src_filename=filename; +} + + +void RDAudioImport::setUseMetadata(bool state) +{ + conv_use_metadata=state; +} + + +void RDAudioImport::setDestinationSettings(RDSettings *settings) +{ + conv_settings=settings; +} + + +RDAudioImport::ErrorCode RDAudioImport::runImport(const QString &username, + const QString &password, + RDAudioConvert::ErrorCode *conv_err) +{ + long response_code; + CURL *curl=NULL; + CURLcode curl_err; + struct curl_httppost *first=NULL; + struct curl_httppost *last=NULL; + char url[1024]; + QString xml; + RDWebResult web_result; + + // + // Generate POST Data + // + // We have to use multipart here because we have a file to send. + // + curl_formadd(&first,&last,CURLFORM_PTRNAME,"COMMAND", + CURLFORM_COPYCONTENTS, + (const char *)QString().sprintf("%u",RDXPORT_COMMAND_IMPORT), + CURLFORM_END); + curl_formadd(&first,&last,CURLFORM_PTRNAME,"LOGIN_NAME", + CURLFORM_COPYCONTENTS,(const char *)username,CURLFORM_END); + curl_formadd(&first,&last,CURLFORM_PTRNAME,"PASSWORD", + CURLFORM_COPYCONTENTS,(const char *)password,CURLFORM_END); + curl_formadd(&first,&last,CURLFORM_PTRNAME,"CART_NUMBER", + CURLFORM_COPYCONTENTS, + (const char *)QString().sprintf("%u",conv_cart_number), + CURLFORM_END); + curl_formadd(&first,&last,CURLFORM_PTRNAME,"CUT_NUMBER", + CURLFORM_COPYCONTENTS, + (const char *)QString().sprintf("%u",conv_cut_number), + CURLFORM_END); + curl_formadd(&first,&last,CURLFORM_PTRNAME,"CHANNELS", + CURLFORM_COPYCONTENTS, + (const char *)QString().sprintf("%u",conv_settings->channels()), + CURLFORM_END); + curl_formadd(&first,&last,CURLFORM_PTRNAME,"NORMALIZATION_LEVEL", + CURLFORM_COPYCONTENTS, + (const char *)QString().sprintf("%d",conv_settings-> + normalizationLevel()), + CURLFORM_END); + curl_formadd(&first,&last,CURLFORM_PTRNAME,"AUTOTRIM_LEVEL", + CURLFORM_COPYCONTENTS, + (const char *)QString().sprintf("%d",conv_settings-> + autotrimLevel()),CURLFORM_END); + curl_formadd(&first,&last,CURLFORM_PTRNAME,"USE_METADATA", + CURLFORM_COPYCONTENTS, + (const char *)QString().sprintf("%u",conv_use_metadata), + CURLFORM_END); + curl_formadd(&first,&last,CURLFORM_PTRNAME,"FILENAME", + CURLFORM_FILE,(const char *)(conv_src_filename.utf8()), + CURLFORM_END); + + // + // Set up the transfer + // + if((curl=curl_easy_init())==NULL) { + return RDAudioImport::ErrorInternal; + } + curl_easy_setopt(curl,CURLOPT_WRITEDATA,stdout); + curl_easy_setopt(curl,CURLOPT_HTTPPOST,first); + curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT); + curl_easy_setopt(curl,CURLOPT_PROGRESSFUNCTION,ImportProgressCallback); + curl_easy_setopt(curl,CURLOPT_PROGRESSDATA,this); + curl_easy_setopt(curl,CURLOPT_NOPROGRESS,0); + curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,ImportReadCallback); + curl_easy_setopt(curl,CURLOPT_WRITEDATA,&xml); + // + // Write out URL as a C string before passing to curl_easy_setopt(), + // otherwise some versions of LibCurl will throw a 'bad/illegal format' + // error. + // + strncpy(url,conv_station->webServiceUrl(conv_config),1024); + curl_easy_setopt(curl,CURLOPT_URL,url); + + // + // Send it + // + switch(curl_err=curl_easy_perform(curl)) { + case CURLE_OK: + break; + + case CURLE_ABORTED_BY_CALLBACK: + curl_easy_cleanup(curl); + return RDAudioImport::ErrorAborted; + + case CURLE_UNSUPPORTED_PROTOCOL: + case CURLE_FAILED_INIT: + case CURLE_COULDNT_RESOLVE_PROXY: + case CURLE_PARTIAL_FILE: + case CURLE_HTTP_RETURNED_ERROR: + case CURLE_WRITE_ERROR: + case CURLE_OUT_OF_MEMORY: + case CURLE_OPERATION_TIMEDOUT: + case CURLE_HTTP_POST_ERROR: + curl_easy_cleanup(curl); + return RDAudioImport::ErrorInternal; + + case CURLE_URL_MALFORMAT: + case CURLE_COULDNT_RESOLVE_HOST: + case CURLE_COULDNT_CONNECT: + case 9: // CURLE_REMOTE_ACCESS_DENIED: + curl_easy_cleanup(curl); + return RDAudioImport::ErrorUrlInvalid; + } + /* + syslog(LOG_NOTICE,"CURL code: %d [%s]\n",curl_err, + curl_easy_strerror(curl_err)); + */ + + // + // Clean up + // + curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&response_code); + curl_easy_cleanup(curl); + curl_formfree(first); + + // + // Process the results + // + if(web_result.readXml(xml)) { + *conv_err=web_result.converterErrorCode(); + } + else { + *conv_err=RDAudioConvert::ErrorOk; + } + //printf("resp code: %d\n",response_code); + switch(response_code) { + case 200: + break; + + case 400: + return RDAudioImport::ErrorService; + + case 401: + return RDAudioImport::ErrorInvalidUser; + + case 404: + return RDAudioImport::ErrorNoDestination; + + default: + return RDAudioImport::ErrorConverter; + } + return RDAudioImport::ErrorOk; +} + + +bool RDAudioImport::aborting() const +{ + return conv_aborting; +} + + +QString RDAudioImport::errorText(RDAudioImport::ErrorCode err, + RDAudioConvert::ErrorCode conv_err) +{ + QString ret=QString().sprintf("Uknown Error [%u]",err); + + switch(err) { + case RDAudioImport::ErrorOk: + ret=tr("OK"); + break; + + case RDAudioImport::ErrorInvalidSettings: + ret=tr("Invalid/unsupported audio parameters"); + break; + + case RDAudioImport::ErrorNoSource: + ret=tr("No such cart/cut"); + break; + + case RDAudioImport::ErrorNoDestination: + ret=tr("Unable to create destination file"); + break; + + case RDAudioImport::ErrorInternal: + ret=tr("Internal Error"); + break; + + case RDAudioImport::ErrorUrlInvalid: + ret=tr("Invalid URL"); + break; + + case RDAudioImport::ErrorService: + ret=tr("RDXport service returned an error"); + break; + + case RDAudioImport::ErrorInvalidUser: + ret=tr("Invalid user or password"); + break; + + case RDAudioImport::ErrorAborted: + ret=tr("Aborted"); + break; + + case RDAudioImport::ErrorConverter: + ret=tr("Audio Converter Error: ")+RDAudioConvert::errorText(conv_err); + break; + } + return ret; +} + + +void RDAudioImport::abort() +{ + conv_aborting=true; +} diff --git a/lib/rdaudioimport.h b/lib/rdaudioimport.h new file mode 100644 index 00000000..ca288c00 --- /dev/null +++ b/lib/rdaudioimport.h @@ -0,0 +1,70 @@ +// rdaudioimport.h +// +// Import an Audio File using the RdXport Web Service +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudioimport.h,v 1.4.4.1 2013/11/13 23:36:30 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDAUDIOIMPORT_H +#define RDAUDIOIMPORT_H + +#include <qobject.h> + +#include <rdconfig.h> +#include <rdstation.h> +#include <rdsettings.h> +#include <rdaudioconvert.h> + +class RDAudioImport : public QObject +{ + Q_OBJECT; + public: + enum ErrorCode {ErrorOk=0,ErrorInvalidSettings=1,ErrorNoSource=2, + ErrorNoDestination=3,ErrorInternal=5,ErrorUrlInvalid=7, + ErrorService=8,ErrorInvalidUser=9,ErrorAborted=10, + ErrorConverter=11}; + RDAudioImport(RDStation *station,RDConfig *config,QObject *parent=0, + const char *name=0); + void setCartNumber(unsigned cartnum); + void setCutNumber(unsigned cutnum); + void setSourceFile(const QString &filename); + void setUseMetadata(bool state); + void setDestinationSettings(RDSettings *settings); + RDAudioImport::ErrorCode runImport(const QString &username, + const QString &password, + RDAudioConvert::ErrorCode *conv_err); + bool aborting() const; + static QString errorText(RDAudioImport::ErrorCode err, + RDAudioConvert::ErrorCode conv_err); + + public slots: + void abort(); + + private: + RDStation *conv_station; + RDConfig *conv_config; + unsigned conv_cart_number; + unsigned conv_cut_number; + QString conv_src_filename; + RDSettings *conv_settings; + bool conv_use_metadata; + bool conv_aborting; +}; + + +#endif // RDAUDIOIMPORT_H diff --git a/lib/rdaudioinfo.cpp b/lib/rdaudioinfo.cpp new file mode 100644 index 00000000..b7f1d163 --- /dev/null +++ b/lib/rdaudioinfo.cpp @@ -0,0 +1,245 @@ +// rdaudioinfo.cpp +// +// Get information about a cut in the audio store. +// +// (C) Copyright 2011 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudioinfo.cpp,v 1.3.4.3 2013/11/13 23:36:30 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> + +#include <curl/curl.h> + +#include <qstringlist.h> + +#include <rd.h> +#include <rdxport_interface.h> +#include <rdformpost.h> +#include <rdaudioinfo.h> + +size_t RDAudioInfoCallback(void *ptr,size_t size,size_t nmemb,void *userdata) +{ + QString *xml=(QString *)userdata; + for(unsigned i=0;i<(size*nmemb);i++) { + *xml+=((const char *)ptr)[i]; + } + return size*nmemb; +} + + +RDAudioInfo::RDAudioInfo(RDStation *station,RDConfig *config, + QObject *parent,const char *name) + : QObject(parent,name) +{ + conv_station=station; + conv_config=config; + conv_cart_number=0; + conv_cut_number=0; + conv_format=RDWaveFile::Pcm16; + conv_channels=0; + conv_sample_rate=0; + conv_frames=0; + conv_length=0; +} + + +RDWaveFile::Format RDAudioInfo::format() const +{ + return conv_format; +} + + +unsigned RDAudioInfo::channels() const +{ + return conv_channels; +} + + +unsigned RDAudioInfo::sampleRate() const +{ + return conv_sample_rate; +} + + +unsigned RDAudioInfo::frames() const +{ + return conv_frames; +} + + +unsigned RDAudioInfo::length() const +{ + return conv_length; +} + + +void RDAudioInfo::setCartNumber(unsigned cartnum) +{ + conv_cart_number=cartnum; +} + + +void RDAudioInfo::setCutNumber(unsigned cutnum) +{ + conv_cut_number=cutnum; +} + + +RDAudioInfo::ErrorCode RDAudioInfo::runInfo(const QString &username, + const QString &password) +{ + long response_code; + CURL *curl=NULL; + char url[1024]; + CURLcode curl_err; + + // + // Generate POST Data + // + QString post=QString().sprintf("COMMAND=%d&LOGIN_NAME=%s&PASSWORD=%s&CART_NUMBER=%u&CUT_NUMBER=%u", + RDXPORT_COMMAND_AUDIOINFO, + (const char *)RDFormPost::urlEncode(username), + (const char *)RDFormPost::urlEncode(password), + conv_cart_number, + conv_cut_number); + if((curl=curl_easy_init())==NULL) { + return RDAudioInfo::ErrorInternal; + } + + // + // Write out URL as a C string before passing to curl_easy_setopt(), + // otherwise some versions of LibCurl will throw a 'bad/illegal format' + // error. + // + strncpy(url,conv_station->webServiceUrl(conv_config),1024); + curl_easy_setopt(curl,CURLOPT_URL,url); + curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,RDAudioInfoCallback); + curl_easy_setopt(curl,CURLOPT_WRITEDATA,&conv_xml); + curl_easy_setopt(curl,CURLOPT_POST,1); + curl_easy_setopt(curl,CURLOPT_POSTFIELDS,(const char *)post); + curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT); + + switch(curl_err=curl_easy_perform(curl)) { + case CURLE_OK: + break; + + case CURLE_UNSUPPORTED_PROTOCOL: + case CURLE_FAILED_INIT: + case CURLE_COULDNT_RESOLVE_PROXY: + case CURLE_PARTIAL_FILE: + case CURLE_HTTP_RETURNED_ERROR: + case CURLE_WRITE_ERROR: + case CURLE_OUT_OF_MEMORY: + case CURLE_OPERATION_TIMEDOUT: + case CURLE_HTTP_POST_ERROR: + curl_easy_cleanup(curl); + fprintf(stderr,"curl error: %d\n",curl_err); + return RDAudioInfo::ErrorInternal; + + case CURLE_URL_MALFORMAT: + case CURLE_COULDNT_RESOLVE_HOST: + case CURLE_COULDNT_CONNECT: + case 9: // CURLE_REMOTE_ACCESS_DENIED + curl_easy_cleanup(curl); + return RDAudioInfo::ErrorUrlInvalid; + + default: + curl_easy_cleanup(curl); + return RDAudioInfo::ErrorService; + } + curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&response_code); + curl_easy_cleanup(curl); + + switch(response_code) { + case 200: + break; + + case 404: + return RDAudioInfo::ErrorNoAudio; + + default: + return RDAudioInfo::ErrorService; + } + conv_format=(RDWaveFile::Format)ParseInt("format",conv_xml); + conv_channels=ParseInt("channels",conv_xml); + conv_sample_rate=ParseInt("sampleRate",conv_xml); + conv_frames=ParseInt("frames",conv_xml); + conv_length=ParseInt("length",conv_xml); + + return RDAudioInfo::ErrorOk; +} + + +QString RDAudioInfo::errorText(RDAudioInfo::ErrorCode err) +{ + QString ret=QString().sprintf("Unknown Error [%u]",err); + + switch(err) { + case RDAudioInfo::ErrorOk: + ret=tr("OK"); + break; + + case RDAudioInfo::ErrorInternal: + ret=tr("Internal Error"); + break; + + case RDAudioInfo::ErrorUrlInvalid: + ret=tr("Invalid URL"); + break; + + case RDAudioInfo::ErrorService: + ret=tr("RDXport service returned an error"); + break; + + case RDAudioInfo::ErrorInvalidUser: + ret=tr("Invalid user or password"); + break; + + case RDAudioInfo::ErrorNoAudio: + ret=tr("Audio does not exist"); + break; + } + return ret; +} + + +int RDAudioInfo::ParseInt(const QString &tag,const QString &xml) +{ + // + // FIXME: This is totally ad-hoc, but should work until we settle on + // a proper XML parser. + // + QStringList list=list.split("\n",xml); + for(unsigned i=0;i<list.size();i++) { + if(list[i].contains(tag)) { + QStringList list2=list.split("<",list[i]); + if(list2.size()>=2) { + list2=list2.split(">",list2[1]); + if(list2.size()>=2) { + return list2[1].toInt(); + } + } + } + } + return -1; +} diff --git a/lib/rdaudioinfo.h b/lib/rdaudioinfo.h new file mode 100644 index 00000000..1d94005b --- /dev/null +++ b/lib/rdaudioinfo.h @@ -0,0 +1,66 @@ +// rdaudioinfo.h +// +// Get information about a cut in the audio store. +// +// (C) Copyright 2011 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudioinfo.h,v 1.1.6.2 2013/11/13 23:36:31 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDAUDIOINFO_H +#define RDAUDIOINFO_H + +#include <qobject.h> + +#include <rdconfig.h> +#include <rdwavefile.h> +#include <rdstation.h> + +class RDAudioInfo : public QObject +{ + Q_OBJECT; + public: + enum ErrorCode {ErrorOk=0,ErrorInternal=5,ErrorUrlInvalid=7, + ErrorService=8,ErrorInvalidUser=9,ErrorNoAudio=10}; + RDAudioInfo(RDStation *station,RDConfig *config,QObject *parent=0, + const char *name=0); + RDWaveFile::Format format() const; + unsigned channels() const; + unsigned sampleRate() const; + unsigned frames() const; + unsigned length() const; + void setCartNumber(unsigned cartnum); + void setCutNumber(unsigned cutnum); + RDAudioInfo::ErrorCode runInfo(const QString &username, + const QString &password); + static QString errorText(RDAudioInfo::ErrorCode err); + + private: + int ParseInt(const QString &tag,const QString &xml); + RDStation *conv_station; + RDConfig *conv_config; + unsigned conv_cart_number; + unsigned conv_cut_number; + RDWaveFile::Format conv_format; + unsigned conv_channels; + unsigned conv_sample_rate; + unsigned conv_frames; + unsigned conv_length; + QString conv_xml; +}; + + +#endif // RDAUDIOINFO_H diff --git a/lib/rdaudiosettings.cpp b/lib/rdaudiosettings.cpp new file mode 100644 index 00000000..834b17a4 --- /dev/null +++ b/lib/rdaudiosettings.cpp @@ -0,0 +1,76 @@ +// rdaudiosettings.cpp +// +// Common Audio Settings +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudiosettings.cpp,v 1.1 2007/09/14 14:06:24 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdaudiosettings.h> + + +RDAudioSettings::RDAudioSettings() +{ +} + + +RDAudioSettings::Format RDAudioSettings::format() const +{ + return set_format; +} + + +void RDAudioSettings::setFormat(RDAudioSettings::Format format) +{ + set_format=format; +} + + +unsigned RDAudioSettings::channels() const +{ + return set_channels; +} + + +void RDAudioSettings::setChannels(unsigned channels) +{ + set_channels=channels; +} + + +unsigned RDAudioSettings::sampleRate() const +{ + return set_sample_rate; +} + + +void RDAudioSettings::setSampleRate(unsigned rate) +{ + set_sample_rate=rate; +} + + +unsigned RDAudioSettings::bitRate() const +{ + return set_bit_rate; +} + + +void RDAudioSettings::setBitRate(unsigned rate) +{ + set_bit_rate=rate; +} diff --git a/lib/rdaudiosettings.h b/lib/rdaudiosettings.h new file mode 100644 index 00000000..b62c7a5b --- /dev/null +++ b/lib/rdaudiosettings.h @@ -0,0 +1,49 @@ +// rdaudiosettings.h +// +// A container class for audio settings. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudiosettings.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDAUDIOSETTINGS_H +#define RDAUDIOSETTINGS_H + + +class RDAudioSettings +{ + public: + enum Format {Pcm16=0,Layer1=1,Layer2=2,Layer3=3,OggVorbis=4}; + RDAudioSettings(); + RDAudioSettings::Format format() const; + void setFormat(RDAudioSettings::Format format); + unsigned channels() const; + void setChannels(unsigned channels); + unsigned sampleRate() const; + void setSampleRate(unsigned rate); + unsigned bitRate() const; + void setBitRate(unsigned rate); + + private: + RDAudioSettings::Format set_format; + unsigned set_channels; + unsigned set_sample_rate; + unsigned set_bit_rate; +}; + + +#endif // RDAUDIOSETTINGS_H diff --git a/lib/rdaudiosettings_dialog.cpp b/lib/rdaudiosettings_dialog.cpp new file mode 100644 index 00000000..ba825e92 --- /dev/null +++ b/lib/rdaudiosettings_dialog.cpp @@ -0,0 +1,507 @@ +// rdaudiosettings_dialog.cpp +// +// Edit an RDAudioSettings object. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudiosettings_dialog.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qdialog.h> +#include <qstring.h> +#include <qpushbutton.h> +#include <qlistbox.h> +#include <qtextedit.h> +#include <qlabel.h> +#include <qevent.h> +#include <qmessagebox.h> +#include <qcheckbox.h> +#include <qbuttongroup.h> +#include <rdconf.h> +#include <math.h> + +#include <rdaudiosettings_dialog.h> + + +RDAudioSettingsDialog::RDAudioSettingsDialog(RDAudioSettings *settings, + bool mpeg, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + lib_lib=settings; + + // + // Dialog Name + // + setCaption(tr("Edit Settings")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + QFont button_font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Default Format + // + lib_format_box=new QComboBox(this,"lib_name_edit"); + lib_format_box->setGeometry(150,10,150,20); + lib_format_box->setFont(font); + connect(lib_format_box,SIGNAL(activated(int)),this,SLOT(formatData(int))); + QLabel *lib_format_label=new QLabel(lib_format_box,tr("Default &Format:"), + this,"lib_format_label"); + lib_format_label->setGeometry(25,10,120,20); + lib_format_label->setFont(font); + lib_format_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Default Channels + // + lib_channels_box=new QComboBox(this,"lib_name_edit"); + lib_channels_box->setGeometry(150,32,60,20); + lib_channels_box->setFont(font); + QLabel *lib_channels_label=new QLabel(lib_channels_box, + tr("Default &Channels:"), + this,"lib_channels_label"); + lib_channels_label->setGeometry(25,32,120,20); + lib_channels_label->setFont(font); + lib_channels_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Default Sample Rate + // + lib_samprate_box=new QComboBox(this,"lib_name_edit"); + lib_samprate_box->setGeometry(150,54,100,20); + lib_samprate_box->setFont(font); + QLabel *lib_samprate_label= + new QLabel(lib_samprate_box,tr("Default &Sample Rate:"),this, + "lib_samprate_label"); + lib_samprate_label->setGeometry(20,54,125,20); + lib_samprate_label->setFont(font); + lib_samprate_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Default Bitrate + // + lib_bitrate_box=new QComboBox(this,"lib_name_edit"); + lib_bitrate_box->setGeometry(150,76,100,20); + lib_bitrate_box->setFont(font); + QLabel *lib_bitrate_label= + new QLabel(lib_bitrate_box,tr("Default &Bitrate:"),this, + "lib_bitrate_label"); + lib_bitrate_label->setGeometry(25,76,120,20); + lib_bitrate_label->setFont(font); + lib_bitrate_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(145,108,80,50); + ok_button->setDefault(true); + ok_button->setFont(button_font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(235,108,80,50); + cancel_button->setFont(button_font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + lib_format_box->insertItem(tr("PCM16")); +#ifdef HAVE_VORBIS + lib_format_box->insertItem(tr("OggVorbis")); +#endif // HAVE_VORBIS + if(mpeg) { + lib_format_box->insertItem(tr("MPEG Layer 2")); + lib_format_box->insertItem(tr("MPEG Layer 3")); + } + QString str; + switch(lib_lib->format()) { + case RDAudioSettings::Pcm16: + str="PCM16"; + break; + + case RDAudioSettings::OggVorbis: + str="OggVorbis"; + break; + + case RDAudioSettings::Layer1: + str="MPEG Layer 1"; + break; + + case RDAudioSettings::Layer2: + str="MPEG Layer 2"; + break; + + case RDAudioSettings::Layer3: + str="MPEG Layer 3"; + break; + } + for(int i=0;i<lib_format_box->count();i++) { + if(lib_format_box->text(i)==str) { + lib_format_box->setCurrentItem(i); + } + } + lib_channels_box->insertItem("1"); + lib_channels_box->insertItem("2"); + lib_channels_box->setCurrentItem(lib_lib->channels()-1); + lib_samprate_box->insertItem("32000"); + lib_samprate_box->insertItem("44100"); + lib_samprate_box->insertItem("48000"); + switch(lib_lib->sampleRate()) { + case 32000: + lib_samprate_box->setCurrentItem(0); + break; + + case 44100: + lib_samprate_box->setCurrentItem(1); + break; + + case 48000: + lib_samprate_box->setCurrentItem(2); + break; + } + ShowBitRates(lib_lib->format(),lib_lib->bitRate()); +} + + +RDAudioSettingsDialog::~RDAudioSettingsDialog() +{ + delete lib_channels_box; + delete lib_samprate_box; + delete lib_bitrate_box; +} + + +QSize RDAudioSettingsDialog::sizeHint() const +{ + return QSize(325,168); +} + + +QSizePolicy RDAudioSettingsDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDAudioSettingsDialog::formatData(int index) +{ + ShowBitRates(ReadFormat(),lib_lib->bitRate()); +} + + +void RDAudioSettingsDialog::okData() +{ + unsigned rate=0; + lib_lib->setFormat(ReadFormat()); + lib_lib->setChannels(lib_channels_box->currentItem()+1); + sscanf(lib_samprate_box->currentText(),"%d",&rate); + lib_lib->setSampleRate(rate); + rate=0; + switch(lib_lib->format()) { + case RDAudioSettings::Layer1: + case RDAudioSettings::Layer2: + case RDAudioSettings::Layer3: + sscanf(lib_bitrate_box->currentText(),"%d",&rate); + break; + + default: + break; + } + lib_lib->setBitRate(rate*1000); + done(0); +} + + +void RDAudioSettingsDialog::cancelData() +{ + done(1); +} + + +void RDAudioSettingsDialog::ShowBitRates(RDAudioSettings::Format fmt,int rate) +{ + lib_bitrate_box->clear(); + switch(fmt) { + case RDAudioSettings::Pcm16: + case RDAudioSettings::OggVorbis: + lib_bitrate_box->setDisabled(true); + break; + + case RDAudioSettings::Layer1: + lib_bitrate_box->setEnabled(true); + lib_bitrate_box->insertItem("32 kbps"); + lib_bitrate_box->insertItem("64 kbps"); + lib_bitrate_box->insertItem("96 kbps"); + lib_bitrate_box->insertItem("128 kbps"); + lib_bitrate_box->insertItem("160 kbps"); + lib_bitrate_box->insertItem("192 kbps"); + lib_bitrate_box->insertItem("224 kbps"); + lib_bitrate_box->insertItem("256 kbps"); + lib_bitrate_box->insertItem("288 kbps"); + lib_bitrate_box->insertItem("320 kbps"); + lib_bitrate_box->insertItem("352 kbps"); + lib_bitrate_box->insertItem("384 kbps"); + lib_bitrate_box->insertItem("416 kbps"); + lib_bitrate_box->insertItem("448 kbps"); + switch(lib_lib->bitRate()) { + case 32000: + lib_bitrate_box->setCurrentItem(0); + break; + + case 64000: + lib_bitrate_box->setCurrentItem(1); + break; + + case 96000: + lib_bitrate_box->setCurrentItem(2); + break; + + case 128000: + lib_bitrate_box->setCurrentItem(3); + break; + + case 160000: + lib_bitrate_box->setCurrentItem(4); + break; + + case 192000: + lib_bitrate_box->setCurrentItem(5); + break; + + case 224000: + lib_bitrate_box->setCurrentItem(6); + break; + + case 256000: + lib_bitrate_box->setCurrentItem(7); + break; + + case 288000: + lib_bitrate_box->setCurrentItem(8); + break; + + case 320000: + lib_bitrate_box->setCurrentItem(9); + break; + + case 352000: + lib_bitrate_box->setCurrentItem(10); + break; + + case 384000: + lib_bitrate_box->setCurrentItem(11); + break; + + case 416000: + lib_bitrate_box->setCurrentItem(12); + break; + + case 448000: + lib_bitrate_box->setCurrentItem(13); + break; + } + break; + + case RDAudioSettings::Layer2: + lib_bitrate_box->setEnabled(true); + lib_bitrate_box->insertItem("32 kbps"); + lib_bitrate_box->insertItem("48 kbps"); + lib_bitrate_box->insertItem("56 kbps"); + lib_bitrate_box->insertItem("64 kbps"); + lib_bitrate_box->insertItem("80 kbps"); + lib_bitrate_box->insertItem("96 kbps"); + lib_bitrate_box->insertItem("112 kbps"); + lib_bitrate_box->insertItem("128 kbps"); + lib_bitrate_box->insertItem("160 kbps"); + lib_bitrate_box->insertItem("192 kbps"); + lib_bitrate_box->insertItem("224 kbps"); + lib_bitrate_box->insertItem("256 kbps"); + lib_bitrate_box->insertItem("320 kbps"); + lib_bitrate_box->insertItem("384 kbps"); + switch(lib_lib->bitRate()) { + case 32000: + lib_bitrate_box->setCurrentItem(0); + break; + + case 48000: + lib_bitrate_box->setCurrentItem(1); + break; + + case 56000: + lib_bitrate_box->setCurrentItem(2); + break; + + case 64000: + lib_bitrate_box->setCurrentItem(3); + break; + + case 80000: + lib_bitrate_box->setCurrentItem(4); + break; + + case 96000: + lib_bitrate_box->setCurrentItem(5); + break; + + case 112000: + lib_bitrate_box->setCurrentItem(6); + break; + + case 128000: + lib_bitrate_box->setCurrentItem(7); + break; + + case 160000: + lib_bitrate_box->setCurrentItem(8); + break; + + case 192000: + lib_bitrate_box->setCurrentItem(9); + break; + + case 224000: + lib_bitrate_box->setCurrentItem(10); + break; + + case 256000: + lib_bitrate_box->setCurrentItem(11); + break; + + case 320000: + lib_bitrate_box->setCurrentItem(12); + break; + + case 384000: + lib_bitrate_box->setCurrentItem(13); + break; + } + break; + + case RDAudioSettings::Layer3: + lib_bitrate_box->setEnabled(true); + lib_bitrate_box->insertItem("32 kbps"); + lib_bitrate_box->insertItem("40 kbps"); + lib_bitrate_box->insertItem("48 kbps"); + lib_bitrate_box->insertItem("56 kbps"); + lib_bitrate_box->insertItem("64 kbps"); + lib_bitrate_box->insertItem("80 kbps"); + lib_bitrate_box->insertItem("96 kbps"); + lib_bitrate_box->insertItem("112 kbps"); + lib_bitrate_box->insertItem("128 kbps"); + lib_bitrate_box->insertItem("160 kbps"); + lib_bitrate_box->insertItem("192 kbps"); + lib_bitrate_box->insertItem("224 kbps"); + lib_bitrate_box->insertItem("256 kbps"); + lib_bitrate_box->insertItem("320 kbps"); + switch(lib_lib->bitRate()) { + case 32000: + lib_bitrate_box->setCurrentItem(0); + break; + + case 40000: + lib_bitrate_box->setCurrentItem(1); + break; + + case 48000: + lib_bitrate_box->setCurrentItem(2); + break; + + case 56000: + lib_bitrate_box->setCurrentItem(3); + break; + + case 64000: + lib_bitrate_box->setCurrentItem(4); + break; + + case 80000: + lib_bitrate_box->setCurrentItem(5); + break; + + case 96000: + lib_bitrate_box->setCurrentItem(6); + break; + + case 112000: + lib_bitrate_box->setCurrentItem(7); + break; + + case 128000: + lib_bitrate_box->setCurrentItem(8); + break; + + case 160000: + lib_bitrate_box->setCurrentItem(9); + break; + + case 192000: + lib_bitrate_box->setCurrentItem(10); + break; + + case 224000: + lib_bitrate_box->setCurrentItem(11); + break; + + case 256000: + lib_bitrate_box->setCurrentItem(12); + break; + + case 320000: + lib_bitrate_box->setCurrentItem(13); + break; + } + break; + + } +} + + +RDAudioSettings::Format RDAudioSettingsDialog::ReadFormat() +{ + if(lib_format_box->currentText()==tr("PCM16")) { + return RDAudioSettings::Pcm16; + } + if(lib_format_box->currentText()==tr("OggVorbis")) { + return RDAudioSettings::OggVorbis; + } + if(lib_format_box->currentText()==tr("MPEG Layer 2")) { + return RDAudioSettings::Layer2; + } + if(lib_format_box->currentText()==tr("MPEG Layer 3")) { + return RDAudioSettings::Layer3; + } + return RDAudioSettings::Pcm16; +} diff --git a/lib/rdaudiosettings_dialog.h b/lib/rdaudiosettings_dialog.h new file mode 100644 index 00000000..a2843f50 --- /dev/null +++ b/lib/rdaudiosettings_dialog.h @@ -0,0 +1,59 @@ +// rdaudiosettings_dialog.h +// +// Edit Rivendell Audio Settings +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdaudiosettings_dialog.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDAUDIOSETTINGS_DIALOG_H +#define RDAUDIOSETTINGS_DIALOG_H + +#include <qdialog.h> +#include <qsqldatabase.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <rdaudiosettings.h> + + +class RDAudioSettingsDialog : public QDialog +{ + Q_OBJECT + public: + RDAudioSettingsDialog(RDAudioSettings *settings,bool mpeg=true, + QWidget *parent=0,const char *name=0); + ~RDAudioSettingsDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void formatData(int); + void okData(); + void cancelData(); + + private: + void ShowBitRates(RDAudioSettings::Format fmt,int rate); + RDAudioSettings::Format ReadFormat(); + RDAudioSettings *lib_lib; + QComboBox *lib_format_box; + QComboBox *lib_channels_box; + QComboBox *lib_bitrate_box; + QComboBox *lib_samprate_box; +}; + + +#endif // RDAUDIOSETTINGS_DIALOG_H diff --git a/lib/rdbusybar.cpp b/lib/rdbusybar.cpp new file mode 100644 index 00000000..c8ca3827 --- /dev/null +++ b/lib/rdbusybar.cpp @@ -0,0 +1,76 @@ +// rdbusybar.cpp +// +// A 'progress bar' widget that shows busy state. +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdbusybar.cpp,v 1.2 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <rdbusybar.h> + +RDBusyBar::RDBusyBar(QWidget *parent,const char *name,WFlags f) + : QFrame(parent,name,f) +{ + bar_pos=0; + setFrameStyle(QFrame::StyledPanel|QFrame::Sunken); + QPalette p=palette(); + p.setColor(QPalette::Active,QColorGroup::Background, + p.color(QPalette::Active,QColorGroup::Base)); + setPalette(p); + + bar_label=new QLabel(this); + p.setColor(QPalette::Active,QColorGroup::Background, + p.color(QPalette::Active,QColorGroup::Highlight)); + bar_label->setPalette(p); + bar_label->hide(); + + bar_timer=new QTimer(this); + connect(bar_timer,SIGNAL(timeout()),this,SLOT(strobe())); +} + +void RDBusyBar::activate(bool state) +{ + if(state) { + Update(); + bar_label->show(); + bar_timer->start(500); + } + else { + bar_label->hide(); + bar_timer->stop(); + } +} + + +void RDBusyBar::strobe() +{ + bar_pos++; + bar_pos=bar_pos%5; + if(bar_label->isVisible()) { + Update(); + } +} + + +void RDBusyBar::Update() +{ + int w=rect().width(); + int h=rect().height(); + int fw=frameWidth(); + bar_label->setGeometry(bar_pos*w/5+fw,fw,(w-2*fw)/5,h-2*fw); +} diff --git a/lib/rdbusybar.h b/lib/rdbusybar.h new file mode 100644 index 00000000..c3712c5a --- /dev/null +++ b/lib/rdbusybar.h @@ -0,0 +1,51 @@ +// rdbusybar.h +// +// A 'progress bar' widget that shows busy state. +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdbusybar.h,v 1.2.8.1 2012/11/26 20:19:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDBUSYBAR_H +#define RDBUSYBAR_H + +#include <qwidget.h> +#include <qframe.h> +#include <qlabel.h> +#include <qtimer.h> + +class RDBusyBar : public QFrame +{ + Q_OBJECT + + public: + RDBusyBar(QWidget *parent=0,const char *name=0,WFlags f=0); + + public slots: + void activate(bool state); + void strobe(); + + private: + void Update(); + QLabel *bar_label; + int bar_pos; + QTimer *bar_timer; +}; + + +#endif // RDBUSYBAR_H diff --git a/lib/rdbusydialog.cpp b/lib/rdbusydialog.cpp new file mode 100644 index 00000000..f9b40e86 --- /dev/null +++ b/lib/rdbusydialog.cpp @@ -0,0 +1,74 @@ +// rdbusydialog.cpp +// +// A 'progress dialog' widget that shows busy state. +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdbusydialog.cpp,v 1.1.2.1 2012/11/26 20:19:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <rdbusydialog.h> + +RDBusyDialog::RDBusyDialog(QWidget *parent,const char *name,WFlags f) + : QDialog(parent,name,true,f) +{ + QFont font("helvetica",16,QFont::Bold); + font.setPixelSize(16); + + bar_label=new QLabel(this); + bar_label->setFont(font); + bar_label->setAlignment(Qt::AlignCenter); + + bar_bar=new RDBusyBar(this); +} + + +RDBusyDialog::~RDBusyDialog() +{ + delete bar_bar; + delete bar_label; +} + + +QSize RDBusyDialog::sizeHint() const +{ + return QSize(200,80); +} + + +void RDBusyDialog::show(const QString &caption,const QString &label) +{ + setCaption(caption); + bar_label->setText(label); + bar_bar->activate(true); + QDialog::show(); +} + + +void RDBusyDialog::hide() +{ + bar_bar->activate(false); + QDialog::hide(); +} + + +void RDBusyDialog::resizeEvent(QResizeEvent *e) +{ + bar_label->setGeometry(0,0,size().width(),size().height()/2); + bar_bar-> + setGeometry(10,size().height()/2,size().width()-20,size().height()/2-10); +} diff --git a/lib/rdbusydialog.h b/lib/rdbusydialog.h new file mode 100644 index 00000000..bc4fe452 --- /dev/null +++ b/lib/rdbusydialog.h @@ -0,0 +1,51 @@ +// rdbusydialog.h +// +// A 'progress dialog' widget that shows busy state. +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdbusydialog.h,v 1.1.2.1 2012/11/26 20:19:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDBUSYDIALOG_H +#define RDBUSYDIALOG_H + +#include <qdialog.h> +#include <qlabel.h> + +#include <rdbusybar.h> + +class RDBusyDialog : public QDialog +{ + Q_OBJECT; + public: + RDBusyDialog(QWidget *parent=0,const char *name=0,WFlags f=0); + ~RDBusyDialog(); + QSize sizeHint() const; + void show(const QString &caption,const QString &label); + void hide(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + QLabel *bar_label; + RDBusyBar *bar_bar; +}; + + +#endif // RDBUSYDIALOG_H diff --git a/lib/rdbutton_dialog.cpp b/lib/rdbutton_dialog.cpp new file mode 100644 index 00000000..21d4d47c --- /dev/null +++ b/lib/rdbutton_dialog.cpp @@ -0,0 +1,262 @@ +// rdbutton_dialog.cpp +// +// Event Editor for RDAirPlay +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdbutton_dialog.cpp,v 1.23.6.1.2.1 2014/03/21 15:41:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qpushbutton.h> +#include <qlabel.h> +#include <qcolordialog.h> +#include <rddb.h> +#include <rdcart.h> +#include <rdcart_dialog.h> +#include <rd.h> +#include <rdbutton_dialog.h> +#include <rdconf.h> + +RDButtonDialog::RDButtonDialog(QString station_name, + const QString &label_template, + RDCartDialog *cart_dialog,const QString &svcname, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Edit Button")); + edit_station_name=station_name; + edit_label_template=label_template; + edit_cart_dialog=cart_dialog; + edit_svcname=svcname; + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont button_font=QFont("Helvetica",14,QFont::Bold); + button_font.setPixelSize(14); + QFont counter_font=QFont("Helvetica",24,QFont::Bold); + counter_font.setPixelSize(24); + + // + // Button Label + // + edit_label_edit=new QLineEdit(this,"edit_label_edit"); + edit_label_edit->setGeometry(60,10,300,20); + edit_label_edit->setFont(font); + QLabel *label=new QLabel(edit_label_edit,tr("Label:"), + this,"edit_label_label"); + label->setGeometry(10,12,45,16); + label->setFont(label_font); + label->setAlignment(AlignRight); + + // + // Button Cart + // + edit_cart_edit=new QLineEdit(this,"edit_cart_edit"); + edit_cart_edit->setGeometry(60,34,300,20); + edit_cart_edit->setFont(font); + edit_cart_edit->setReadOnly(true); + label=new QLabel(edit_cart_edit,tr("Cart:"),this,"edit_cart_label"); + label->setGeometry(10,36,45,16); + label->setFont(label_font); + label->setAlignment(AlignRight); + + // + // Set Cart Button + // + QPushButton *button=new QPushButton(this,"cart_button"); + button->setGeometry(55,60,80,50); + button->setFont(label_font); + button->setText(tr("Set\nCart")); + connect(button,SIGNAL(clicked()),this,SLOT(setCartData())); + + // + // Clear Button + // + button=new QPushButton(this,"cart_button"); + button->setGeometry(145,60,80,50); + button->setFont(label_font); + button->setText(tr("Clear")); + connect(button,SIGNAL(clicked()),this,SLOT(clearCartData())); + + // + // Color Button + // + edit_color_button=new QPushButton(this,"edit_color_button"); + edit_color_button->setGeometry(sizeHint().width()-135,60,80,50); + edit_color_button->setFont(label_font); + edit_color_button->setText(tr("Set\nColor")); + connect(edit_color_button,SIGNAL(clicked()),this,SLOT(setColorData())); + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(label_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(label_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +RDButtonDialog::~RDButtonDialog() +{ +} + + +QSize RDButtonDialog::sizeHint() const +{ + return QSize(370,190); +} + + +QSizePolicy RDButtonDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int RDButtonDialog::exec(RDPanelButton *button,bool hookmode, + const QString &username,const QString &passwd) +{ + edit_button=button; + edit_hookmode=hookmode; + edit_user_name=username; + edit_user_password=passwd; + edit_cart=edit_button->cart(); + edit_color=edit_button->defaultColor(); + QPalette p=QPalette(edit_color,backgroundColor()); + p.setColor(QColorGroup::ButtonText,RDGetTextColor(edit_color)); + edit_color_button->setPalette(p); + edit_label_edit->setText(edit_button->text()); + DisplayCart(edit_cart); + return QDialog::exec(); +} + + +void RDButtonDialog::setCartData() +{ + if(edit_cart_dialog->exec(&edit_cart,RDCart::All,&edit_svcname,1, + edit_user_name,edit_user_password)==0) { + DisplayCart(edit_cart); + } +} + + +void RDButtonDialog::clearCartData() +{ + edit_cart=0; + edit_color=backgroundColor(); + edit_color_button->setPalette(QPalette(edit_color,backgroundColor())); + edit_label_edit->setText(""); + edit_cart_edit->setText(""); +} + + +void RDButtonDialog::setColorData() +{ + QColor new_color=QColorDialog::getColor(edit_color,this,"edit_color_dialog"); + if(new_color.isValid()) { + edit_color=new_color; + QPalette p=QPalette(edit_color,backgroundColor()); + p.setColor(QColorGroup::ButtonText,RDGetTextColor(edit_color)); + edit_color_button->setPalette(p); + } +} + + +void RDButtonDialog::okData() +{ + RDCart *cart=new RDCart((unsigned)edit_cart); + edit_button->setCart(edit_cart); + edit_button->setColor(edit_color); + edit_button->setDefaultColor(edit_color); + if((edit_cart>0)&&edit_label_edit->text().isEmpty()) { + edit_button-> + setText(RDLogLine::resolveWildcards(edit_cart,edit_label_template)); + } + else { + edit_button->setText(edit_label_edit->text()); + } + edit_button->setLength(false,cart->forcedLength()); + if(cart->averageHookLength()>0) { + edit_button->setLength(true,cart->averageHookLength()); + } + else { + edit_button->setLength(true,cart->forcedLength()); + } + edit_button->setActiveLength(edit_button->length(edit_hookmode)); + edit_button->setHookMode(edit_hookmode); + delete cart; + done(0); +} + + +void RDButtonDialog::cancelData() +{ + done(-1); +} + + +void RDButtonDialog::DisplayCart(int cartnum) +{ + if(cartnum==0) { + edit_cart_edit->setText(""); + return; + } + RDCart *cart=new RDCart((unsigned)cartnum); + if(cart->exists()) { + edit_cart_edit-> + setText(QString().sprintf("%06u - ",cart->number())+cart->title()); + /* + edit_cart_edit->setText(QString().sprintf("%06u - %s", + cart->number(), + (const char *)cart->title())); + */ + } + else { + edit_cart_edit->setText(QString().sprintf("%06u - [",cart->number())+"] "+ + tr("NOT FOUND")); + /* + edit_cart_edit-> + setText(QString().sprintf("%06u - [%s]",cart->number(), + (const char *)str)); + */ + } + delete cart; +} diff --git a/lib/rdbutton_dialog.h b/lib/rdbutton_dialog.h new file mode 100644 index 00000000..9a14b228 --- /dev/null +++ b/lib/rdbutton_dialog.h @@ -0,0 +1,84 @@ + +// rdbutton_dialog.h +// +// Button Editor for the SoundPanel in RDAirPlay. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdbutton_dialog.h,v 1.14.8.1 2012/11/26 20:19:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDBUTTON_DIALOG_H +#define RDBUTTON_DIALOG_H + +#include <qdialog.h> +#include <qcombobox.h> +#include <qlineedit.h> + +#include <rdpanel_button.h> +#include <rdcart_dialog.h> + +class RDButtonDialog : public QDialog +{ + Q_OBJECT + public: + RDButtonDialog(QString station_name,const QString &label_template, + RDCartDialog *cart_dialog,const QString &svcname, + QWidget *parent=0,const char *name=0); +/* + RDButtonDialog(QString station_name,const QString &label_template, + RDCae *cae,RDRipc *ripc,RDStation *station, + int audition_card,int audition_port, + const QString &editor_cmd, + QWidget *parent=0,const char *name=0); +*/ + ~RDButtonDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(RDPanelButton *button,bool hookmode,const QString &username, + const QString &passwd); + + private slots: + void setCartData(); + void clearCartData(); + void setColorData(); + void okData(); + void cancelData(); + + private: + void DisplayCart(int cartnum); + QLineEdit *edit_label_edit; + QLineEdit *edit_cart_edit; + RDPanelButton *edit_button; + QString edit_label_template; + QString edit_filter; + QString edit_group; + QString edit_user_name; + QString edit_user_password; + QPushButton *edit_color_button; + int edit_cart; + QColor edit_color; + QString edit_station_name; + bool edit_hookmode; + RDCartDialog *edit_cart_dialog; + QString edit_svcname; +}; + + +#endif + diff --git a/lib/rdbutton_panel.cpp b/lib/rdbutton_panel.cpp new file mode 100644 index 00000000..98e57a68 --- /dev/null +++ b/lib/rdbutton_panel.cpp @@ -0,0 +1,214 @@ +// rdbutton_panel.cpp +// +// The sound panel widget for RDAirPlay +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdbutton_panel.cpp,v 1.12.6.4 2014/02/06 20:43:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qcolor.h> + +#include <rdbutton_panel.h> +#include <rdbutton_dialog.h> + + +RDButtonPanel::RDButtonPanel(RDAirPlayConf::PanelType type,int panel,int cols, + int rows,RDStation *station,bool flash, + QWidget *parent) +{ + panel_button_columns=cols; + panel_button_rows=rows; + panel_station=station; + for(int i=0;i<panel_button_rows;i++) { + for(int j=0;j<panel_button_columns;j++) { + panel_button[i][j]= + new RDPanelButton(i,j,panel_station,flash,parent); + if(station->enableDragdrop()&&(!station->enforcePanelSetup())) { + panel_button[i][j]->setAcceptDrops(true); + } + panel_button[i][j]->setGeometry((15+PANEL_BUTTON_SIZE_X)*j, + (15+PANEL_BUTTON_SIZE_Y)*i, + PANEL_BUTTON_SIZE_X, + PANEL_BUTTON_SIZE_Y); + panel_button[i][j]->hide(); + parent->connect(parent,SIGNAL(buttonFlash(bool)), + panel_button[i][j],SLOT(flashButton(bool))); + QObject::connect(panel_button[i][j], + SIGNAL(cartDropped(int,int,unsigned,const QColor &,const QString &)), + parent, + SLOT(acceptCartDrop(int,int,unsigned,const QColor &,const QString &))); + } + } + clear(); +} + + +RDButtonPanel::~RDButtonPanel() +{ + for(int i=0;i<panel_button_rows;i++) { + for(int j=0;j<panel_button_columns;j++) { + delete panel_button[i][j]; + } + } +} + + +QSize RDButtonPanel::sizeHint() const +{ + return QSize(500,535); +} + + +QSizePolicy RDButtonPanel::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +RDPanelButton *RDButtonPanel::panelButton(int row,int col) const +{ + return panel_button[row][col]; +} + + +void RDButtonPanel::setActionMode(RDAirPlayConf::ActionMode mode) +{ + switch(mode) { + case RDAirPlayConf::CopyFrom: + for(int i=0;i<panel_button_rows;i++) { + for(int j=0;j<panel_button_columns;j++) { + if(panel_button[i][j]->cart()!=0) { + panel_button[i][j]->setColor(BUTTON_FROM_BACKGROUND_COLOR); + } + } + } + break; + + case RDAirPlayConf::CopyTo: + for(int i=0;i<panel_button_rows;i++) { + for(int j=0;j<panel_button_columns;j++) { + if(panel_button[i][j]->playDeck()!=NULL) { + if(panel_button[i][j]->playDeck()->state()==RDPlayDeck::Paused) { + panel_button[i][j]->setColor(RDPANEL_PAUSED_BACKGROUND_COLOR); + } + else { + panel_button[i][j]->setColor(RDPANEL_PLAY_BACKGROUND_COLOR); + } + } + else { + panel_button[i][j]->setColor(BUTTON_TO_BACKGROUND_COLOR); + } + } + } + break; + + case RDAirPlayConf::AddTo: + for(int i=0;i<panel_button_rows;i++) { + for(int j=0;j<panel_button_columns;j++) { + if(panel_button[i][j]->playDeck()==NULL) { + panel_button[i][j]->setColor(BUTTON_TO_BACKGROUND_COLOR); + } + } + } + break; + + case RDAirPlayConf::DeleteFrom: + for(int i=0;i<panel_button_rows;i++) { + for(int j=0;j<panel_button_columns;j++) { + if(panel_button[i][j]->playDeck()==NULL) { + panel_button[i][j]->setColor(BUTTON_FROM_BACKGROUND_COLOR); + } + } + } + break; + + default: + for(int i=0;i<panel_button_rows;i++) { + for(int j=0;j<panel_button_columns;j++) { +// if(panel_button[i][j]->cart()!=0) { + if(panel_button[i][j]->playDeck()!=NULL) { + if(panel_button[i][j]->playDeck()->state()==RDPlayDeck::Paused) { + panel_button[i][j]->setColor(RDPANEL_PAUSED_BACKGROUND_COLOR); + } + else { + panel_button[i][j]->setColor(RDPANEL_PLAY_BACKGROUND_COLOR); + } + } + else { + if(panel_button[i][j]->state()) { + panel_button[i][j]->setColor(RDPANEL_PAUSED_BACKGROUND_COLOR); + } + else { + panel_button[i][j]->reset(); + } + } +// } + } + } + break; + } +} + + +void RDButtonPanel::setAllowDrags(bool state) +{ + for(int i=0;i<panel_button_rows;i++) { + for(int j=0;j<panel_button_columns;j++) { + panel_button[i][j]->setAllowDrags(state); + } + } +} + + +void RDButtonPanel::setAcceptDrops(bool state) +{ + for(int i=0;i<panel_button_rows;i++) { + for(int j=0;j<panel_button_columns;j++) { + panel_button[i][j]->setAcceptDrops(state); + } + } +} + + +void RDButtonPanel::hide() +{ + for(int i=0;i<panel_button_rows;i++) { + for(int j=0;j<panel_button_columns;j++) { + panel_button[i][j]->hide(); + } + } +} + + +void RDButtonPanel::show() +{ + for(int i=0;i<panel_button_rows;i++) { + for(int j=0;j<panel_button_columns;j++) { + panel_button[i][j]->show(); + } + } +} + + +void RDButtonPanel::clear() +{ + for(int i=0;i<panel_button_rows;i++) { + for(int j=0;j<panel_button_columns;j++) { + panel_button[i][j]->clear(); + } + } +} diff --git a/lib/rdbutton_panel.h b/lib/rdbutton_panel.h new file mode 100644 index 00000000..445afed3 --- /dev/null +++ b/lib/rdbutton_panel.h @@ -0,0 +1,68 @@ +// rdbutton_panel.h +// +// The sound panel widget for RDAirPlay +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdbutton_panel.h,v 1.10.6.2 2014/02/06 20:43:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDBUTTON_PANEL_H +#define RDBUTTON_PANEL_H + +#include <qwidget.h> +#include <qdatetime.h> +#include <qlabel.h> + +#include <rdairplay_conf.h> +#include <rdstation.h> +#include <rduser.h> +#include <rdpanel_button.h> +#include <rdbutton_dialog.h> + +// +// Widget Settings +// +#define PANEL_MAX_BUTTON_COLUMNS 20 +#define PANEL_MAX_BUTTON_ROWS 20 +#define PANEL_BUTTON_SIZE_X 88 +#define PANEL_BUTTON_SIZE_Y 80 + + +class RDButtonPanel +{ + public: + RDButtonPanel(RDAirPlayConf::PanelType type,int panel,int cols,int rows, + RDStation *station,bool flash,QWidget *parent); + ~RDButtonPanel(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + RDPanelButton *panelButton(int row,int col) const; + void setActionMode(RDAirPlayConf::ActionMode mode); + void setAllowDrags(bool state); + void setAcceptDrops(bool state); + void hide(); + void show(); + void clear(); + + private: + RDPanelButton *panel_button[PANEL_MAX_BUTTON_ROWS][PANEL_MAX_BUTTON_COLUMNS]; + RDStation *panel_station; + int panel_button_columns; + int panel_button_rows; +}; + +#endif diff --git a/lib/rdcae.cpp b/lib/rdcae.cpp new file mode 100644 index 00000000..2e44e8fe --- /dev/null +++ b/lib/rdcae.cpp @@ -0,0 +1,664 @@ +// rdcae.cpp +// +// Connection to the Rivendell Core Audio Engine +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcae.cpp,v 1.59.4.5 2013/11/14 02:04:57 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <syslog.h> + +#include <qobject.h> +#include <ctype.h> + +#include <qsocketdevice.h> +#include <qtimer.h> +#include <qstringlist.h> + +#include <rddb.h> +#include <rdcae.h> +#include <rddebug.h> +#include <rdescape_string.h> + +RDCae::RDCae(RDStation *station,RDConfig *config, + QObject *parent,const char *name) + : QObject(parent,name) +{ + cae_station=station; + cae_config=config; + cae_connected=false; + argnum=0; + argptr=0; + + // + // TCP Connection + // + cae_socket=new QSocketDevice(QSocketDevice::Stream); + cae_socket->setBlocking(false); + + // + // Meter Connection + // + cae_meter_socket=new QSocketDevice(QSocketDevice::Datagram); + cae_meter_socket->setBlocking(false); + for(Q_INT16 i=30000;i<30100;i++) { + if(cae_meter_socket->bind(QHostAddress(),i)) { + i=31000; + } + } + + // + // Initialize Data Structures + // + for(int i=0;i<RD_MAX_CARDS;i++) { + for(int j=0;j<RD_MAX_PORTS;j++) { + input_status[i][j]=false; + for(unsigned k=0;k<2;k++) { + cae_input_levels[i][j][k]=-10000; + cae_output_levels[i][j][k]=-10000; + cae_stream_output_levels[i][j][k]=-10000; + } + for(int k=0;k<RD_MAX_STREAMS;k++) { + cae_output_status_flags[i][j][k]=false; + } + } + for(int j=0;j<RD_MAX_STREAMS;j++) { + cae_handle[i][j]=-1; + cae_output_positions[i][j]=0; + } + } + + // + // The Clock Timer + // + QTimer *timer=new QTimer(this,"clock_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(clockData())); + timer->start(RD_METER_UPDATE_INTERVAL); +} + + +RDCae::~RDCae() { + delete cae_socket; +} + + +void RDCae::connectHost() +{ + int count=10; + // QHostAddress addr; + QTimer *timer=new QTimer(this,"read_timer"); + + connect(timer,SIGNAL(timeout()),this,SLOT(readyData())); + timer->start(CAE_POLL_INTERVAL); + while((!cae_socket->connect(cae_station->caeAddress(cae_config), + CAED_TCP_PORT))&&(--count>0)) { + usleep(100000); + } + usleep(100000); + if(count>0) { + SendCommand(QString().sprintf("PW %s!", + (const char *)cae_config->password())); + for(int i=0;i<RD_MAX_CARDS;i++) { + SendCommand(QString().sprintf("TS %d!",i)); + for(int j=0;j<RD_MAX_PORTS;j++) { + SendCommand(QString().sprintf("IS %d %d!",i,j)); + } + } + SendCommand(QString().sprintf("ME %u!",cae_meter_socket->port())); + } +} + +bool RDCae::loadPlay(int card,QString name,int *stream,int *handle) +{ + int count=0; + + SendCommand(QString().sprintf("LP %d %s!", + card,(const char *)name)); + + // + // This is really warty, but needed to make the method 'synchronous' + // with respect to CAE. + // + *stream=-2; + *handle=-1; + while(*stream==-2) { + readyData(stream,handle,name); + usleep(1000); + count++; + } + if(count>1000) { + syslog(LOG_ERR,"*** LoadPlay: CAE took %d mS to return stream for %s ***", + count,(const char *)name); + } + cae_handle[card][*stream]=*handle; + cae_pos[card][*stream]=0xFFFFFFFF; + return true; +} + + +void RDCae::unloadPlay(int handle) +{ + SendCommand(QString().sprintf("UP %d!",handle)); +} + + +void RDCae::positionPlay(int handle,int pos) +{ + if(pos<0) { + return; + } + SendCommand(QString().sprintf("PP %d %u!",handle,pos)); +} + + +void RDCae::play(int handle,unsigned length,int speed,bool pitch) +{ + int pitch_state=0; + + if(pitch) { + pitch_state=1; + } + SendCommand(QString().sprintf("PY %d %u %d %d!", + handle,length,speed,pitch_state)); +} + + +void RDCae::stopPlay(int handle) +{ + SendCommand(QString().sprintf("SP %d!",handle)); +} + + +void RDCae::loadRecord(int card,int stream,QString name, + AudioCoding coding,int chan,int samp_rate, + int bit_rate) +{ + // printf("RDCae::loadRecord(%d,%d,%s,%d,%d,%d,%d)\n", + // card,stream,(const char *)name,coding,chan,samp_rate,bit_rate); + SendCommand(QString().sprintf("LR %d %d %d %d %d %d %s!", + card,stream,(int)coding,chan,samp_rate, + bit_rate,(const char *)name)); +} + + +void RDCae::unloadRecord(int card,int stream) +{ + SendCommand(QString().sprintf("UR %d %d!",card,stream)); +} + + +void RDCae::record(int card,int stream,unsigned length,int threshold) +{ + SendCommand(QString().sprintf("RD %d %d %u %d!", + card,stream,length,threshold)); +} + + +void RDCae::stopRecord(int card,int stream) +{ + SendCommand(QString().sprintf("SR %d %d!",card,stream)); +} + + +void RDCae::setClockSource(int card,RDCae::ClockSource src) +{ + SendCommand(QString().sprintf("CS %d %d!",card,src)); +} + + +void RDCae::setInputVolume(int card,int stream,int level) +{ + SendCommand(QString().sprintf("IV %d %d %d!",card,stream,level)); +} + + +void RDCae::setOutputVolume(int card,int stream,int port,int level) +{ + SendCommand(QString().sprintf("OV %d %d %d %d!",card,stream,port,level)); +} + + +void RDCae::fadeOutputVolume(int card,int stream,int port,int level,int length) +{ + SendCommand(QString().sprintf("FV %d %d %d %d %d!", + card,stream,port,level,length)); +} + + +void RDCae::setInputLevel(int card,int port,int level) +{ + SendCommand(QString().sprintf("IL %d %d %d!",card,port,level)); +} + + +void RDCae::setOutputLevel(int card,int port,int level) +{ + SendCommand(QString().sprintf("OL %d %d %d!",card,port,level)); +} + + +void RDCae::setInputMode(int card,int stream,RDCae::ChannelMode mode) +{ + SendCommand(QString().sprintf("IM %d %d %d!",card,stream,mode)); +} + + +void RDCae::setOutputMode(int card,int stream,RDCae::ChannelMode mode) +{ + SendCommand(QString().sprintf("OM %d %d %d!",card,stream,mode)); +} + + +void RDCae::setInputVOXLevel(int card,int stream,int level) +{ + SendCommand(QString().sprintf("IX %d %d %d!",card,stream,level)); +} + + +void RDCae::setInputType(int card,int port,RDCae::SourceType type) +{ + SendCommand(QString().sprintf("IT %d %d %d!",card,port,type)); +} + + +void RDCae::setPassthroughVolume(int card,int in_port,int out_port,int level) +{ + SendCommand(QString(). + sprintf("AL %d %d %d %d!",card,in_port,out_port,level)); +} + + +bool RDCae::inputStatus(int card,int port) const +{ + return input_status[card][port]; +} + + +void RDCae::inputMeterUpdate(int card,int port,short levels[2]) +{ + UpdateMeters(); + levels[0]=cae_input_levels[card][port][0]; + levels[1]=cae_input_levels[card][port][1]; +} + + +void RDCae::outputMeterUpdate(int card,int port,short levels[2]) +{ + UpdateMeters(); + levels[0]=cae_output_levels[card][port][0]; + levels[1]=cae_output_levels[card][port][1]; +} + + +void RDCae::outputStreamMeterUpdate(int card,int stream,short levels[2]) +{ + UpdateMeters(); + levels[0]=cae_stream_output_levels[card][stream][0]; + levels[1]=cae_stream_output_levels[card][stream][1]; +} + + +unsigned RDCae::playPosition(int handle) +{ + for(int i=0;i<RD_MAX_CARDS;i++) { + for(int j=0;j<RD_MAX_STREAMS;j++) { + if(cae_handle[i][j]==handle) { + return cae_pos[i][j]; + } + } + } + return 0; +} + + +void RDCae::requestTimescale(int card) +{ + SendCommand(QString().sprintf("TS %d!",card)); +} + + +bool RDCae::playPortActive(int card,int port,int except_stream) +{ + for(int i=0;i<RD_MAX_STREAMS;i++) { + if(cae_output_status_flags[card][port][i]&&(i!=except_stream)) { + return true; + } + } + return false; +} + + +void RDCae::setPlayPortActive(int card,int port,int stream) +{ + cae_output_status_flags[card][port][stream]=true; +} + + +void RDCae::connectJackPorts(const QString &out,const QString &in) +{ + SendCommand(QString("JC ")+out+" | "+in+"!"); +} + + +void RDCae::disconnectJackPorts(const QString &out,const QString &in) +{ + SendCommand(QString("JD ")+out+" | "+in+"!"); +} + + +void RDCae::readyData() +{ + readyData(0,0,""); +} + + +void RDCae::readyData(int *stream,int *handle,QString name) +{ + char buf[256]; + int c; + RDCmdCache cmd; + + if(stream==NULL) { + for(unsigned i=0;i<delayed_cmds.size();i++) { + DispatchCommand(&delayed_cmds[i]); + } + delayed_cmds.clear(); + } + + while((c=cae_socket->readBlock(buf,256))>0) { + buf[c]=0; + for(int i=0;i<c;i++) { + if(buf[i]==' ') { + if(argnum<CAE_MAX_ARGS) { + args[argnum][argptr]=0; + argnum++; + argptr=0; + } + else { + if(debug) { + printf("Argument list truncated!\n"); + } + } + } + if(buf[i]=='!') { + args[argnum++][argptr]=0; + if(stream==NULL) { + cmd.load(args,argnum,argptr); + /* + // ************************************ + printf("DISPATCHING: "); + for(int z=0;z<cmd.argNum();z++) { + printf(" %s",cmd.arg(z)); + } + printf("\n"); + // ************************************ + */ + DispatchCommand(&cmd); + } + else { + if(!strcmp(args[0],"LP")) { + if(QString(args[2])==name) { + sscanf(args[3],"%d",stream); + sscanf(args[4],"%d",handle); + } + } + else { + cmd.load(args,argnum,argptr); + delayed_cmds.push_back(cmd); + } + } + argnum=0; + argptr=0; + if(cae_socket==NULL) { + return; + } + } + if((isgraph(buf[i]))&&(buf[i]!='!')) { + if(argptr<CAE_MAX_LENGTH) { + args[argnum][argptr]=buf[i]; + argptr++; + } + else { + if(debug) { + printf("WARNING: argument truncated!\n"); + } + } + } + } + } +} + + +void RDCae::clockData() +{ + for(int i=0;i<RD_MAX_CARDS;i++) { + for(int j=0;j<RD_MAX_STREAMS;j++) { + if(cae_handle[i][j]>=0) { + if(cae_output_positions[i][j]!=cae_pos[i][j]) { + emit playPositionChanged(cae_handle[i][j], + cae_output_positions[i][j]); + cae_pos[i][j]=cae_output_positions[i][j]; + } + } + } + } +} + + +void RDCae::SendCommand(QString cmd) +{ + //printf("RDCae: SendCommand(%s)\n",(const char *)cmd); + cae_socket->writeBlock((const char *)cmd,cmd.length()); +} + + +void RDCae::DispatchCommand(RDCmdCache *cmd) +{ + int pos; + int card; + + if(!strcmp(cmd->arg(0),"PW")) { // Password Response + if(cmd->arg(1)[0]=='+') { + emit isConnected(true); + } + else { + emit isConnected(false); + } + } + + if(!strcmp(cmd->arg(0),"LP")) { // Load Play + int handle=GetHandle(cmd->arg(4)); + int card=CardNumber(cmd->arg(1)); + int stream=StreamNumber(cmd->arg(3)); + syslog(LOG_ERR,"*** RDCae::DispatchCommand: received unhandled play stream from CAE, handle=%d, card=%d, stream=%d, name=\"%s\" ***", + handle,card,stream,cmd->arg(2)); + + unloadPlay(handle); + } + + if(!strcmp(cmd->arg(0),"UP")) { // Unload Play + if(cmd->arg(2)[0]=='+') { + int handle=GetHandle(cmd->arg(1)); + for(int i=0;i<RD_MAX_CARDS;i++) { + for(int j=0;j<RD_MAX_STREAMS;j++) { + if(cae_handle[i][j]==handle) { + cae_handle[i][j]=-1; + for(unsigned k=0;k<RD_MAX_PORTS;k++) { + cae_output_status_flags[i][k][j]=false; + } + } + } + } + emit playUnloaded(handle); + } + } + + if(!strcmp(cmd->arg(0),"PP")) { // Position Play + if(cmd->arg(3)[0]=='+') { + int handle=GetHandle(cmd->arg(1)); + sscanf(cmd->arg(2),"%u",&pos); + for(int i=0;i<RD_MAX_CARDS;i++) { + for(int j=0;j<RD_MAX_STREAMS;j++) { + if(cae_handle[i][j]==handle) { + //emit playPositionChanged(handle,cae_output_positions[i][j]); + emit playPositionChanged(handle,pos); + } + } + } + emit playPositioned(handle,pos); + } + } + + if(!strcmp(cmd->arg(0),"PY")) { // Play + if(cmd->arg(4)[0]=='+') { + emit playing(GetHandle(cmd->arg(1))); + } + } + + if(!strcmp(cmd->arg(0),"SP")) { // Stop Play + if(cmd->arg(2)[0]=='+') { + emit playStopped(GetHandle(cmd->arg(1))); + } + } + + if(!strcmp(cmd->arg(0),"TS")) { // Timescale Supported + if(sscanf(cmd->arg(1),"%d",&card)==1) { + if(cmd->arg(2)[0]=='+') { + emit timescalingSupported(card,true); + } + else { + emit timescalingSupported(card,false); + } + } + } + + if(!strcmp(cmd->arg(0),"LR")) { // Load Record + if(cmd->arg(8)[0]=='+') { + emit recordLoaded(CardNumber(cmd->arg(1)),StreamNumber(cmd->arg(2))); + } + } + + if(!strcmp(cmd->arg(0),"UR")) { // Unload Record + if(cmd->arg(4)[0]=='+') { + emit recordUnloaded(CardNumber(cmd->arg(1)),StreamNumber(cmd->arg(2)), + QString(cmd->arg(3)).toUInt()); + } + } + + if(!strcmp(cmd->arg(0),"RD")) { // Record + } + + if(!strcmp(cmd->arg(0),"RS")) { // Record Start + if(cmd->arg(3)[0]=='+') { + emit recording(CardNumber(cmd->arg(1)),StreamNumber(cmd->arg(2))); + } + } + + if(!strcmp(cmd->arg(0),"SR")) { // Stop Record + if(cmd->arg(3)[0]=='+') { + emit recordStopped(CardNumber(cmd->arg(1)),StreamNumber(cmd->arg(2))); + } + } + + if(!strcmp(cmd->arg(0),"IS")) { // Input Status + switch(cmd->arg(3)[0]) { + case '0': + emit inputStatusChanged(CardNumber(cmd->arg(1)), + StreamNumber(cmd->arg(2)),true); + input_status[CardNumber(cmd->arg(1))][StreamNumber(cmd->arg(2))]= + true; + break; + + case '1': + emit inputStatusChanged(CardNumber(cmd->arg(1)), + StreamNumber(cmd->arg(2)),false); + input_status[CardNumber(cmd->arg(1))][StreamNumber(cmd->arg(2))]= + false; + break; + } + } +} + + +int RDCae::CardNumber(const char *arg) +{ + int n=-1; + + sscanf(arg,"%d",&n); + return n; +} + + +int RDCae::StreamNumber(const char *arg) +{ + int n=-1; + + sscanf(arg,"%d",&n); + return n; +} + + +int RDCae::GetHandle(const char *arg) +{ + int n=-1; + + sscanf(arg,"%d",&n); + return n; +} + + +void RDCae::UpdateMeters() +{ + char msg[1501]; + int n; + QStringList args; + + while((n=cae_meter_socket->readBlock(msg,1500))>0) { + msg[n]=0; + args=args.split(" ",msg); + if(args[0]=="ML") { + if(args.size()==6) { + if(args[1]=="I") { + cae_input_levels[args[2].toInt()][args[3].toInt()][0]=args[4].toInt(); + cae_input_levels[args[2].toInt()][args[3].toInt()][1]=args[5].toInt(); + } + if(args[1]=="O") { + cae_output_levels[args[2].toInt()][args[3].toInt()][0]= + args[4].toInt(); + cae_output_levels[args[2].toInt()][args[3].toInt()][1]= + args[5].toInt(); + } + } + } + if(args[0]=="MO") { + if(args.size()==5) { + cae_stream_output_levels[args[1].toInt()][args[2].toInt()][0]= + args[3].toInt(); + cae_stream_output_levels[args[1].toInt()][args[2].toInt()][1]= + args[4].toInt(); + } + } + if(args[0]=="MP") { + if(args.size()==4) { + cae_output_positions[args[1].toInt()][args[2].toInt()]=args[3].toUInt(); + } + } + } +} diff --git a/lib/rdcae.h b/lib/rdcae.h new file mode 100644 index 00000000..cbb0b32c --- /dev/null +++ b/lib/rdcae.h @@ -0,0 +1,133 @@ +// rdcae.h +// +// Connection to the Rivendell Core Audio Engine +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcae.h,v 1.32.4.2 2012/11/30 16:14:59 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCAE_H +#define RDCAE_H + +#include <vector> + +#include <qsqldatabase.h> +#include <qstring.h> +#include <qobject.h> +#include <qsocketdevice.h> +#include <qlabel.h> + +#include <rd.h> +#include <rdcmd_cache.h> +#include <rdstation.h> +#include <rdconfig.h> + +class RDCae : public QObject +{ + Q_OBJECT + public: + enum ClockSource {InternalClock=0,AesEbuClock=1,SpDiffClock=2,WordClock=4}; + enum ChannelMode {Normal=0,Swap=1,LeftOnly=2,RightOnly=3}; + enum SourceType {Analog=0,AesEbu=1}; + enum AudioCoding {Pcm16=0,MpegL1=1,MpegL2=2,MpegL3=3}; + RDCae(RDStation *station,RDConfig *config, + QObject *parent=0,const char *name=0); + ~RDCae(); + void connectHost(); + bool loadPlay(int card,QString name,int *stream,int *handle); + void unloadPlay(int handle); + void positionPlay(int handle,int pos); + void play(int handle,unsigned length,int speed,bool pitch); + void stopPlay(int handle); + void loadRecord(int card,int stream,QString name,AudioCoding coding, + int chan,int samp_rate,int bit_rate); + void unloadRecord(int card,int stream); + void record(int card,int stream,unsigned length,int threshold); + void stopRecord(int card,int stream); + void setClockSource(int card,RDCae::ClockSource src); + void setInputVolume(int card,int stream,int level); + void setOutputVolume(int card,int stream,int port,int level); + void fadeOutputVolume(int card,int stream,int port,int level,int length); + void setInputLevel(int card,int port,int level); + void setOutputLevel(int card,int port,int level); + void setInputMode(int card,int stream,RDCae::ChannelMode mode); + void setOutputMode(int card,int stream,RDCae::ChannelMode mode); + void setInputVOXLevel(int card,int stream,int level); + void setInputType(int card,int port,RDCae::SourceType type); + void setPassthroughVolume(int card,int in_port,int out_port,int level); + bool inputStatus(int card,int port) const; + void inputMeterUpdate(int card,int port,short levels[2]); + void outputMeterUpdate(int card,int port,short levels[2]); + void outputStreamMeterUpdate(int card,int stream,short levels[2]); + unsigned playPosition(int handle); + void requestTimescale(int card); + bool playPortActive(int card,int port,int except_stream=-1); + void setPlayPortActive(int card,int port,int stream); + void connectJackPorts(const QString &out,const QString &in); + void disconnectJackPorts(const QString &out,const QString &in); + + signals: + void isConnected(bool state); + void playLoaded(int handle); + void playPositioned(int handle,unsigned pos); + void playing(int handle); + void playStopped(int handle); + void playUnloaded(int handle); + void recordLoaded(int card,int stream); + void recording(int card,int stream); + void recordStopped(int card,int stream); + void recordUnloaded(int card,int stream,unsigned msecs); + void gpiInputChanged(int line,bool state); + void connected(bool state); + void inputStatusChanged(int card,int stream,bool state); + void playPositionChanged(int handle,unsigned sample); + void timescalingSupported(int card,bool state); + + private slots: + void readyData(); + void readyData(int *stream,int *handle,QString name); + void clockData(); + + private: + void SendCommand(QString cmd); + void DispatchCommand(RDCmdCache *cmd); + int CardNumber(const char *arg); + int StreamNumber(const char *arg); + int GetHandle(const char *arg); + void UpdateMeters(); + QSocketDevice *cae_socket; + bool debug; + char args[CAE_MAX_ARGS][CAE_MAX_LENGTH]; + int argnum; + int argptr; + bool cae_connected; + bool input_status[RD_MAX_CARDS][RD_MAX_PORTS]; + int cae_handle[RD_MAX_CARDS][RD_MAX_STREAMS]; + unsigned cae_pos[RD_MAX_CARDS][RD_MAX_STREAMS]; + QSocketDevice *cae_meter_socket; + short cae_input_levels[RD_MAX_CARDS][RD_MAX_PORTS][2]; + short cae_output_levels[RD_MAX_CARDS][RD_MAX_PORTS][2]; + short cae_stream_output_levels[RD_MAX_CARDS][RD_MAX_PORTS][2]; + unsigned cae_output_positions[RD_MAX_CARDS][RD_MAX_STREAMS]; + bool cae_output_status_flags[RD_MAX_CARDS][RD_MAX_PORTS][RD_MAX_STREAMS]; + std::vector<RDCmdCache> delayed_cmds; + RDStation *cae_station; + RDConfig *cae_config; +}; + + +#endif diff --git a/lib/rdcardselector.cpp b/lib/rdcardselector.cpp new file mode 100644 index 00000000..d1393aa7 --- /dev/null +++ b/lib/rdcardselector.cpp @@ -0,0 +1,250 @@ +// rdcardselector.cpp +// +// Audio card selector widget for Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcardselector.cpp,v 1.21.8.1 2013/03/22 15:11:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <math.h> + +#include <qdialog.h> +#include <qstring.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qlineedit.h> +#include <qtextedit.h> +#include <qlabel.h> +#include <qpainter.h> +#include <qevent.h> +#include <qmessagebox.h> +#include <qbuttongroup.h> + + +#include <rdcardselector.h> + + +RDCardSelector::RDCardSelector(QWidget *parent,const char *name) + : QWidget(parent,name) +{ + card_id=-1; + yoffset=0; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + yoffset=0; + + // + // Title + // + card_title=new QLabel(this,"card_title"); + card_title->setGeometry(0,0,geometry().width(),19); + card_title->setFont(QFont("Helvetica",12,QFont::Bold)); + card_title->setAlignment(AlignHCenter); + card_title->hide(); + + // + // Card + // + card_card_box=new QSpinBox(this,"card_card_box"); + card_card_box->setGeometry(60,yoffset,50,19); + card_card_box->setSpecialValueText("None"); + card_card_box->setMinValue(-1); + card_card_box->setMaxValue(RD_MAX_CARDS-1); + card_card_box->setValue(-1); + connect(card_card_box,SIGNAL(valueChanged(int)),this,SLOT(cardData(int))); + card_card_label=new QLabel(card_card_box,tr("Card:"),this, + "card_card_label"); + card_card_label->setGeometry(0,yoffset+2,55,19); + card_card_label->setAlignment(AlignRight|ShowPrefix); + + // + // Port + // + card_port_box=new QSpinBox(this,"card_port_box"); + card_port_box->setGeometry(60,yoffset+22,50,19); + card_port_box->setSpecialValueText("None"); + card_port_box->setMinValue(-1); + card_port_box->setMaxValue(RD_MAX_PORTS-1); + card_port_box->setValue(-1); + connect(card_port_box,SIGNAL(valueChanged(int)),this,SLOT(portData(int))); + card_port_label=new QLabel(card_port_box,tr("Port:"),this, + "card_port_label"); + card_port_label->setGeometry(0,yoffset+24,55,19); + card_port_label->setAlignment(AlignRight|ShowPrefix); + for(int i=0;i<RD_MAX_CARDS;i++) { + card_max_ports[i] = 0; + cardData(i); + } + card_port_box->setDisabled(true); +} + + +RDCardSelector::~RDCardSelector() +{ + delete card_title; + delete card_card_box; + delete card_port_box; +} + + +QSize RDCardSelector::sizeHint() const +{ + return QSize(110,41+yoffset); +} + + +QSizePolicy RDCardSelector::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +bool RDCardSelector::isDisabled() const +{ + return (card_card_box->value()<0)||(card_port_box->value()<0); +} + + +int RDCardSelector::id() const +{ + return card_id; +} + + +void RDCardSelector::setId(int id) +{ + card_id=id; +} + + +QString RDCardSelector::title() const +{ + return card_title->text(); +} + + +void RDCardSelector::setTitle(QString title) +{ + card_title->setText(title); + if(title.isEmpty()) { + yoffset=0; + card_title->hide(); + } + else { + yoffset=22; + card_title->show(); + } + card_card_box->setGeometry(60,yoffset,50,19); + card_card_label->setGeometry(0,yoffset+2,55,19); + card_port_box->setGeometry(60,yoffset+44,50,19); + card_port_label->setGeometry(0,yoffset+46,55,19); +} + + +int RDCardSelector::card() const +{ + return card_card_box->value(); +} + + +void RDCardSelector::setCard(int card) +{ + card_card_box->setValue(card); +} + + +int RDCardSelector::port() const +{ + return card_port_box->value(); +} + + +void RDCardSelector::setPort(int port) +{ + card_port_box->setValue(port); +} + + +int RDCardSelector::maxCards() const +{ + return card_card_box->maxValue()+1; +} + + +void RDCardSelector::setMaxCards(int num) +{ + card_card_box->setMaxValue(num-1); +} + + +int RDCardSelector::maxPorts(int card) const +{ + if(card>=0) { + return card_max_ports[card]; + } + return 0; +} + + +void RDCardSelector::setMaxPorts(int card,int num) +{ + if(card>=0) { + card_max_ports[card]=num; + if (card == this->card()){ + card_port_box->setMaxValue(num-1); + if (num == 0){ + card_port_box->setValue(-1); + card_port_box->setDisabled(true); + } else { + card_port_box->setDisabled(false); + } + } + } +} + +void RDCardSelector::cardData(int card) +{ + int c; + if(card>=0) { + c = card_max_ports[card]-1; + card_port_box->setMaxValue(c); + if (c <0){ + card_port_box->setValue(-1); + } + card_port_box->setDisabled((c>=0) ? false : true); + } + else { + card_port_box->setValue(-1); + card_port_box->setDisabled(true); + } + emit cardChanged(card); + emit settingsChanged(card_id,card,card_port_box->value()); +} + + +void RDCardSelector::portData(int port) +{ + emit portChanged(port); + emit settingsChanged(card_id,card_card_box->value(),port); +} diff --git a/lib/rdcardselector.h b/lib/rdcardselector.h new file mode 100644 index 00000000..7f52d953 --- /dev/null +++ b/lib/rdcardselector.h @@ -0,0 +1,77 @@ +// rdcardselector.h +// +// Audio Card Selector Widget for Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcardselector.h,v 1.9.8.1 2013/03/22 15:11:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCARDSELECTOR_H +#define RDCARDSELECTOR_H + +#include <qwidget.h> +#include <qspinbox.h> +#include <qlabel.h> + +#include <rd.h> + + +class RDCardSelector : public QWidget +{ + Q_OBJECT + public: + RDCardSelector(QWidget *parent=0,const char *name=0); + ~RDCardSelector(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + bool isDisabled() const; + int id() const; + void setId(int id); + QString title() const; + void setTitle(QString title); + int card() const; + void setCard(int card); + int port() const; + void setPort(int port); + int maxCards() const; + void setMaxCards(int num); + int maxPorts(int card) const; + void setMaxPorts(int card,int num); + + signals: + void settingsChanged(int id,int card,int port); + void cardChanged(int card); + void portChanged(int port); + + private slots: + void cardData(int); + void portData(int); + + private: + QLabel *card_card_label; + QSpinBox *card_card_box; + QLabel *card_port_label; + QSpinBox *card_port_box; + QLabel *card_title; + int yoffset; + int card_max_ports[RD_MAX_CARDS]; + int card_id; +}; + + +#endif + diff --git a/lib/rdcart.cpp b/lib/rdcart.cpp new file mode 100644 index 00000000..7cb1fa08 --- /dev/null +++ b/lib/rdcart.cpp @@ -0,0 +1,1701 @@ +// rdcart.cpp +// +// Abstract a Rivendell Cart. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcart.cpp,v 1.72.4.7.2.9 2014/06/02 22:52:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WIN32 +#include <sys/types.h> +#include <unistd.h> +#include <syslog.h> +#include <curl/curl.h> +#endif // WIN32 + +#include <vector> + +#include <qstringlist.h> +#include <qobject.h> + +#include <rd.h> +#include <rdconf.h> +#include <rdcart.h> +#include <rdcut.h> +#include <rdtextvalidator.h> +#include <rdescape_string.h> +#include <rdsystem.h> +#include <rdxport_interface.h> +#include <rdformpost.h> +#include <rdweb.h> +#include <rdstation.h> + +// +// CURL Callbacks +// +size_t CartWriteCallback(void *ptr,size_t size,size_t nmemb,void *userdata) +{ + QString *xml=(QString *)userdata; + for(unsigned i=0;i<(size*nmemb);i++) { + *xml+=((const char *)ptr)[i]; + } + return size*nmemb; +} + + +RDCart::RDCart(unsigned number) +{ + cart_number=number; + metadata_changed=false; +} + + +RDCart::~RDCart() +{ + if(metadata_changed) { + writeTimestamp(); + } +} + + +bool RDCart::exists() const +{ + return RDDoesRowExist("CART","NUMBER",cart_number); +} + + +bool RDCart::selectCut(QString *cut) const +{ + return selectCut(cut,QTime::currentTime()); +} + + +bool RDCart::selectCut(QString *cut,const QTime &time) const +{ + bool ret; + + if(!exists()) { + ret=(*cut==""); + *cut=""; +#ifndef WIN32 + syslog(LOG_USER|LOG_WARNING, + "RDCart::selectCut(): cart doesn't exist, CUT=%s", + (const char *)cut); +#endif // WIN32 + return ret; + } + + if(!cut->isEmpty()) { + RDCut *rdcut=new RDCut(*cut); + delete rdcut; + } + + QString sql; + RDSqlQuery *q; + QString cutname; + QDate current_date=QDate::currentDate(); + QString datetime_str=QDateTime(current_date,time). + toString("yyyy-MM-dd hh:mm:ss"); + QString time_str=QDateTime(current_date,time).toString("hh:mm:ss"); + + // if(type()==RDCart::Audio) { + switch(type()) { + case RDCart::Audio: + sql=QString().sprintf("select CUT_NAME,WEIGHT,LOCAL_COUNTER\ + from CUTS where (((START_DATETIME<=\"%s\")&&\ + (END_DATETIME>=\"%s\"))||\ + (START_DATETIME is null))&&\ + (((START_DAYPART<=\"%s\")&&(END_DAYPART>=\"%s\")||\ + START_DAYPART is null))&&\ + (%s=\"Y\")&&(CART_NUMBER=%u)&&(EVERGREEN=\"N\")&&\ + (LENGTH>0) order by LOCAL_COUNTER", + (const char *)datetime_str, + (const char *)datetime_str, + (const char *)time_str, + (const char *)time_str, + (const char *)RDGetShortDayNameEN(current_date.dayOfWeek()).upper(), + cart_number); + q=new RDSqlQuery(sql); + cutname=GetNextCut(q); + delete q; + break; + + case RDCart::Macro: + case RDCart::All: + break; + } + if(cutname.isEmpty()) { // No valid cuts, try the evergreen +#ifndef WIN32 + // syslog(LOG_USER|LOG_WARNING,"RDCart::selectCut(): no valid cuts, trying evergreen, SQL=%s",(const char *)sql); +#endif // WIN32 + sql=QString().sprintf("select CUT_NAME,WEIGHT,LOCAL_COUNTER\ + from CUTS where (CART_NUMBER=%u)&&\ + (EVERGREEN=\"Y\")&&(LENGTH>0) \ + order by LOCAL_COUNTER", + cart_number); + q=new RDSqlQuery(sql); + cutname=GetNextCut(q); + delete q; + } + if(cutname.isEmpty()) { +#ifndef WIN32 + // syslog(LOG_USER|LOG_WARNING,"RDCart::selectCut(): no valid evergreen cuts, SQL=%s",(const char *)sql); +#endif // WIN32 + } + *cut=cutname; + return true; +} + + +unsigned RDCart::number() const +{ + return cart_number; +} + + +QString RDCart::groupName() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"GROUP_NAME"). + toString(); +} + + +void RDCart::setGroupName(const QString &name) +{ + SetRow("GROUP_NAME",name); + metadata_changed=true; +} + + +RDCart::Type RDCart::type() const +{ + return (RDCart::Type)RDGetSqlValue("CART","NUMBER",cart_number, + "TYPE").toUInt(); +} + + +void RDCart::setType(RDCart::Type type) +{ + SetRow("TYPE",(unsigned)type); + metadata_changed=true; +} + + +QString RDCart::title() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"TITLE").toString(); +} + + +void RDCart::setTitle(const QString &title) +{ + SetRow("TITLE",VerifyTitle(title)); + metadata_changed=true; +} + + +QString RDCart::artist() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"ARTIST").toString(); +} + + +void RDCart::setArtist(const QString &artist) +{ + SetRow("ARTIST",artist); + metadata_changed=true; +} + + +QString RDCart::album() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"ALBUM").toString(); +} + + +void RDCart::setAlbum(const QString &album) +{ + SetRow("ALBUM",album); + metadata_changed=true; +} + + +int RDCart::year() const +{ + QString value; + value=RDGetSqlValue("CART","NUMBER",cart_number,"YEAR").toString(); + QStringList f0=f0.split("-",value); + return f0[0].toInt(); +} + + +void RDCart::setYear(int year) +{ + SetRow("YEAR",QString().sprintf("%04d-01-01",year)); + metadata_changed=true; +} + + +QString RDCart::schedCodes() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"SCHED_CODES").toString(); +} + + +void RDCart::setSchedCodes(const QString &sched_codes) const +{ + SetRow("SCHED_CODES",sched_codes); +} + + +QStringList RDCart::schedCodesList() const +{ + QStringList list; + QString sched_codes= + RDGetSqlValue("CART","NUMBER",cart_number,"SCHED_CODES").toString(); + + for(int i=0;i<255;i+=11) { + QString code=sched_codes.mid(i,11); + if((!code.isEmpty())&&(code.stripWhiteSpace()!=".")) { + list.push_back(code.stripWhiteSpace()); + } + } + + return list; +} + + +void RDCart::setSchedCodesList(const QStringList &codes) +{ + QString sched_codes=""; + + for(unsigned i=0;i<codes.size();i++) { + sched_codes+=QString().sprintf("%-11s",(const char *)codes[i].left(11)); + } + sched_codes+="."; + SetRow("SCHED_CODES",sched_codes); +} + + +void RDCart::addSchedCode(const QString &code) +{ + QStringList codes=schedCodesList(); + codes.push_back(code); + setSchedCodesList(codes); +} + + +void RDCart::updateSchedCodes(const QString &add_codes,const QString &remove_codes) const +{ + QString sched_codes; + QString save_codes=""; + QString sql; + RDSqlQuery *q; + QString str; + + sched_codes=schedCodes(); + + sql=QString().sprintf("select CODE from SCHED_CODES"); + q=new RDSqlQuery(sql); + while(q->next()) { + QString wstr=q->value(0).toString(); + wstr+=" "; + wstr=wstr.left(11); + if((sched_codes.contains(wstr)>0||add_codes.contains(wstr)>0)&&remove_codes.contains(wstr)==0) { + save_codes+=wstr; + } + } + delete q; + + save_codes+="."; + SetRow("SCHED_CODES",save_codes); +} + + +QString RDCart::label() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"LABEL").toString(); +} + + +void RDCart::setLabel(const QString &label) +{ + SetRow("LABEL",label); + metadata_changed=true; +} + + +QString RDCart::conductor() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"CONDUCTOR").toString(); +} + + +void RDCart::setConductor(const QString &cond) +{ + SetRow("CONDUCTOR",cond); + metadata_changed=true; +} + + +QString RDCart::client() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"CLIENT").toString(); +} + + +void RDCart::setClient(const QString &client) +{ + SetRow("CLIENT",client); + metadata_changed=true; +} + + +QString RDCart::agency() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"AGENCY").toString(); +} + + +void RDCart::setAgency(const QString &agency) +{ + SetRow("AGENCY",agency); + metadata_changed=true; +} + + +QString RDCart::publisher() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number, + "PUBLISHER").toString(); +} + + +void RDCart::setPublisher(const QString &publisher) +{ + SetRow("PUBLISHER",publisher); + metadata_changed=true; +} + + +QString RDCart::composer() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number, + "COMPOSER").toString(); +} + + +void RDCart::setComposer(const QString &composer) +{ + SetRow("COMPOSER",composer); + metadata_changed=true; +} + + +QString RDCart::userDefined() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number, + "USER_DEFINED").toString(); +} + + +void RDCart::setUserDefined(const QString &string) +{ + SetRow("USER_DEFINED",string); + metadata_changed=true; +} + + +QString RDCart::songId() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"SONG_ID").toString(); +} + + +void RDCart::setSongId(const QString &id) +{ + SetRow("SONG_ID",id); + metadata_changed=true; +} + + +unsigned RDCart::beatsPerMinute() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"BPM").toUInt(); +} + + +void RDCart::setBeatsPerMinute(unsigned bpm) +{ + SetRow("BPM",bpm); + metadata_changed=true; +} + + +RDCart::UsageCode RDCart::usageCode() const +{ + return (RDCart::UsageCode) RDGetSqlValue("CART","NUMBER",cart_number, + "USAGE_CODE").toInt(); +} + + +void RDCart::setUsageCode(RDCart::UsageCode code) +{ + SetRow("USAGE_CODE",(int)code); + metadata_changed=true; +} + + +QString RDCart::notes() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"NOTES").toString(); +} + + +void RDCart::setNotes(const QString ¬es) +{ + SetRow("NOTES",notes); + metadata_changed=true; +} + + +unsigned RDCart::forcedLength() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number, + "FORCED_LENGTH").toUInt(); +} + + +void RDCart::setForcedLength(unsigned length) +{ + SetRow("FORCED_LENGTH",length); + metadata_changed=true; +} + + +unsigned RDCart::lengthDeviation() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number, + "LENGTH_DEVIATION").toUInt(); +} + + +void RDCart::setLengthDeviation(unsigned length) const +{ + SetRow("LENGTH_DEVIATION",length); +} + + +unsigned RDCart::calculateAverageLength(unsigned *max_dev) const +{ + unsigned total=0; + unsigned count=0; + unsigned high=0; + unsigned low=0xFFFFFFFF; + unsigned avg=0; + unsigned weight; + QDateTime end_datetime; + QString sql; + RDSqlQuery *q; + + switch(type()) { + case RDCart::Audio: + sql=QString().sprintf("select LENGTH, WEIGHT,END_DATETIME from CUTS\ + where (CART_NUMBER=%u)&&(LENGTH>0)", + cart_number); + q=new RDSqlQuery(sql); + while(q->next()) { + weight = q->value(1).toUInt(); + end_datetime = q->value(2).toDateTime(); + if (end_datetime.isValid() && (end_datetime <QDateTime::currentDateTime ())){ + // This cut has expired, it is no more, set its weight to zero. + weight = 0; + } + total+=(q->value(0).toUInt() * weight); + if((weight) && (q->value(0).toUInt()>high)) { + high=q->value(0).toUInt(); + } + if((weight) && (q->value(0).toUInt()<low)) { + low=q->value(0).toUInt(); + } + count += weight; + } + delete q; + if(count==0) { + avg=0; + low=0; + high=0; + } + else { + avg=total/count; + } + if(max_dev!=NULL) { + if((high-avg)>(avg-low)) { + *max_dev=high-avg; + } + else { + *max_dev=avg-low; + } + } + break; + + case RDCart::Macro: + case RDCart::All: + break; + } + return avg; +} + + +unsigned RDCart::averageLength() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number, + "AVERAGE_LENGTH").toUInt(); +} + + +void RDCart::setAverageLength(unsigned length) const +{ + SetRow("AVERAGE_LENGTH",length); +} + + +unsigned RDCart::averageSegueLength() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number, + "AVERAGE_SEGUE_LENGTH").toUInt(); +} + + +void RDCart::setAverageSegueLength(unsigned length) const +{ + SetRow("AVERAGE_SEGUE_LENGTH",length); +} + + +unsigned RDCart::averageHookLength() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number, + "AVERAGE_HOOK_LENGTH").toUInt(); +} + + +void RDCart::setAverageHookLength(unsigned length) const +{ + SetRow("AVERAGE_HOOK_LENGTH",length); +} + + +unsigned RDCart::cutQuantity() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number, + "CUT_QUANTITY").toUInt(); +} + + +void RDCart::setCutQuantity(unsigned quan) const +{ + SetRow("CUT_QUANTITY",quan); +} + + +unsigned RDCart::lastCutPlayed() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number, + "LAST_CUT_PLAYED").toUInt(); +} + + +void RDCart::setLastCutPlayed(unsigned cut) const +{ + SetRow("LAST_CUT_PLAYED",cut); +} + + +RDCart::PlayOrder RDCart::playOrder() const +{ + return (RDCart::PlayOrder)RDGetSqlValue("CART","NUMBER",cart_number, + "PLAY_ORDER").toUInt(); +} + + +void RDCart::setPlayOrder(RDCart::PlayOrder order) const +{ + SetRow("PLAY_ORDER",(unsigned)order); +} + + +RDCart::Validity RDCart::validity() const +{ + return (RDCart::Validity)RDGetSqlValue("CART","NUMBER",cart_number, + "VALIDITY").toUInt(); +} + + +void RDCart::setValidity(RDCart::Validity state) +{ + SetRow("VALIDITY",(unsigned)state); +} + + +QDateTime RDCart::startDateTime() const +{ + QDateTime value; + value=RDGetSqlValue("CART","NUMBER",cart_number, + "START_DATETIME").toDateTime(); + if(value.isValid()) { + return value; + } + return QDateTime(QDate(),QTime()); +} + + +void RDCart::setStartDateTime(const QDateTime &time) +{ + SetRow("START_DATETIME",time); + metadata_changed=true; +} + + +void RDCart::setStartDateTime() +{ + SetRow("START_DATETIME"); + metadata_changed=true; +} + + +QDateTime RDCart::endDateTime() const +{ + QDateTime value; + value=RDGetSqlValue("CART","NUMBER",cart_number, + "END_DATETIME").toDateTime(); + if(value.isValid()) { + return value; + } + return QDateTime(QDate(),QTime()); +} + + +void RDCart::setEndDateTime(const QDateTime &time) +{ + SetRow("END_DATETIME",time); + metadata_changed=true; +} + + +void RDCart::setEndDateTime() +{ + SetRow("END_DATETIME"); + metadata_changed=true; +} + + +bool RDCart::enforceLength() const +{ + return RDBool(RDGetSqlValue("CART","NUMBER",cart_number, + "ENFORCE_LENGTH").toString()); +} + + +void RDCart::setEnforceLength(bool state) +{ + SetRow("ENFORCE_LENGTH",RDYesNo(state)); + metadata_changed=true; +} + + +bool RDCart::preservePitch() const +{ + return RDBool(RDGetSqlValue("CART","NUMBER",cart_number, + "PRESERVE_PITCH").toString()); +} + + +void RDCart::setPreservePitch(bool state) const +{ + SetRow("PRESERVE_PITCH",RDYesNo(state)); +} + + +bool RDCart::asyncronous() const +{ + return RDBool(RDGetSqlValue("CART","NUMBER",cart_number, + "ASYNCRONOUS").toString()); +} + + +void RDCart::setAsyncronous(bool state) const +{ + SetRow("ASYNCRONOUS",RDYesNo(state)); +} + + +QString RDCart::owner() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"OWNER").toString(); +} + + +void RDCart::setOwner(const QString &owner) const +{ + SetRow("OWNER",owner); +} + + +bool RDCart::useEventLength() const +{ + return RDBool(RDGetSqlValue("CART","NUMBER",cart_number, + "USE_EVENT_LENGTH").toString()); +} + + +void RDCart::setUseEventLength(bool state) const +{ + SetRow("USE_EVENT_LENGTH",RDYesNo(state)); +} + + +void RDCart::setPending(const QString &station_name) +{ +#ifndef WIN32 + QString sql; + RDSqlQuery *q; + + sql=QString("update CART set PENDING_STATION=\"")+ + RDEscapeString(station_name)+"\","+ + "PENDING_DATETIME=now(),"+ + "PENDING_PID="+QString().sprintf("%d ",getpid())+ + QString().sprintf("where NUMBER=%u",cart_number); + q=new RDSqlQuery(sql); + delete q; +#endif // WIN32 +} + + +void RDCart::clearPending() const +{ + QString sql; + RDSqlQuery *q; + + sql=QString("update CART set PENDING_STATION=NULL,")+ + "PENDING_DATETIME=NULL "+ + QString().sprintf("where NUMBER=%u",cart_number); + q=new RDSqlQuery(sql); + delete q; +} + + +QString RDCart::macros() const +{ + return RDGetSqlValue("CART","NUMBER",cart_number,"MACROS").toString(); +} + + +void RDCart::setMacros(const QString &cmds) const +{ + SetRow("MACROS",cmds); +} + + +void RDCart::getMetadata(RDWaveData *data) const +{ + QString sql; + RDSqlQuery *q; + + sql=QString("select TITLE,ARTIST,ALBUM,YEAR,LABEL,CLIENT,")+ + "AGENCY,PUBLISHER,COMPOSER,USER_DEFINED,CONDUCTOR,SONG_ID,BPM,USAGE_CODE"+ + QString().sprintf(" from CART where NUMBER=%u",cart_number); + q=new RDSqlQuery(sql); + if(q->first()) { + data->setTitle(q->value(0).toString()); + data->setArtist(q->value(1).toString()); + data->setAlbum(q->value(2).toString()); + data->setReleaseYear(q->value(3).toInt()); + data->setLabel(q->value(4).toString()); + data->setClient(q->value(5).toString()); + data->setAgency(q->value(6).toString()); + data->setPublisher(q->value(7).toString()); + data->setComposer(q->value(8).toString()); + data->setUserDefined(q->value(9).toString()); + data->setConductor(q->value(10).toString()); + data->setTmciSongId(q->value(11).toString()); + data->setBeatsPerMinute(q->value(12).toUInt()); + data->setUsageCode(q->value(13).toUInt()); + data->setSchedCodes(schedCodesList()); + data->setMetadataFound(true); + } + delete q; +} + + +void RDCart::setMetadata(const RDWaveData *data) +{ + QString sql="update CART set "; + if(!data->title().isEmpty()) { + sql+=QString().sprintf("TITLE=\"%s\",",(const char *) + RDEscapeString(VerifyTitle(data->title())).utf8()); + } + if(!data->artist().isEmpty()) { + sql+=QString().sprintf("ARTIST=\"%s\",",(const char *) + RDEscapeString(data->artist()).utf8()); + } + if(!data->album().isEmpty()) { + sql+=QString().sprintf("ALBUM=\"%s\",",(const char *) + RDEscapeString(data->album()).utf8()); + } + if(data->releaseYear()>0) { + sql+=QString().sprintf("YEAR=\"%04d-01-01\",",data->releaseYear()); + } + if(!data->label().isEmpty()) { + sql+=QString().sprintf("LABEL=\"%s\",",(const char *) + RDEscapeString(data->label()).utf8()); + } + if(!data->conductor().isEmpty()) { + sql+=QString().sprintf("CONDUCTOR=\"%s\",",(const char *) + RDEscapeString(data->conductor()).utf8()); + } + if(!data->client().isEmpty()) { + sql+=QString().sprintf("CLIENT=\"%s\",",(const char *) + RDEscapeString(data->client()).utf8()); + } + if(!data->agency().isEmpty()) { + sql+=QString().sprintf("AGENCY=\"%s\",",(const char *) + RDEscapeString(data->agency()).utf8()); + } + if(!data->publisher().isEmpty()) { + sql+=QString().sprintf("PUBLISHER=\"%s\",",(const char *) + RDEscapeString(data->publisher()).utf8()); + } + if(!data->composer().isEmpty()) { + sql+=QString().sprintf("COMPOSER=\"%s\",",(const char *) + RDEscapeString(data->composer()).utf8()); + } + if(!data->userDefined().isEmpty()) { + sql+=QString().sprintf("USER_DEFINED=\"%s\",",(const char *) + RDEscapeString(data->userDefined()).utf8()); + } + if(!data->tmciSongId().isEmpty()) { + sql+=QString().sprintf("SONG_ID=\"%s\",",(const char *) + RDEscapeString(data->tmciSongId()).utf8()); + } + if(data->beatsPerMinute()>0) { + sql+=QString().sprintf("BPM=%u,",data->beatsPerMinute()); + } + sql+=QString().sprintf("USAGE_CODE=%u,",data->usageCode()); + if(sql.right(1)==",") { + sql=sql.left(sql.length()-1); + sql+=QString().sprintf(" where NUMBER=%u",cart_number); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + } + setSchedCodesList(data->schedCodes()); + metadata_changed=true; +} + + +bool RDCart::validateLengths(int len) const +{ + int maxlen=(int)(RD_TIMESCALE_MAX*(double)len); + int minlen=(int)(RD_TIMESCALE_MIN*(double)len); + QString sql=QString().sprintf("select LENGTH from CUTS where CART_NUMBER=%u", + cart_number); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + if((q->value(0).toInt()>maxlen)||(q->value(0).toInt()<minlen)) { + delete q; + return false; + } + } + delete q; + + return true; +} + + +QString RDCart::xml(bool include_cuts) const +{ +#ifdef WIN32 + return QString(); +#else + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + QString ret=""; + RDCut *cut; + QStringList mlist; + + sql=QString().sprintf("select TYPE,GROUP_NAME,TITLE,ARTIST,ALBUM,YEAR,\ + LABEL,CLIENT,AGENCY,PUBLISHER,COMPOSER,USER_DEFINED,\ + USAGE_CODE,FORCED_LENGTH,AVERAGE_LENGTH,\ + LENGTH_DEVIATION,AVERAGE_SEGUE_LENGTH,\ + AVERAGE_HOOK_LENGTH,CUT_QUANTITY,LAST_CUT_PLAYED,\ + VALIDITY,\ + ENFORCE_LENGTH,ASYNCRONOUS,OWNER,METADATA_DATETIME \ + from CART where NUMBER=%u",cart_number); + q=new RDSqlQuery(sql); + if(q->first()) { + ret+="<cart>\n"; + ret+=" "+RDXmlField("number",cart_number); + switch((RDCart::Type)q->value(0).toUInt()) { + case RDCart::Audio: + ret+=" "+RDXmlField("type","audio"); + break; + + case RDCart::Macro: + ret+=" "+RDXmlField("type","macro"); + break; + + case RDCart::All: + break; + } + ret+=" "+RDXmlField("groupName",q->value(1).toString()); + ret+=" "+RDXmlField("title",q->value(2).toString()); + ret+=" "+RDXmlField("artist",q->value(3).toString()); + ret+=" "+RDXmlField("album",q->value(4).toString()); + ret+=" "+RDXmlField("year",q->value(5).toDate().toString("yyyy")); + ret+=" "+RDXmlField("label",q->value(6).toString()); + ret+=" "+RDXmlField("client",q->value(7).toString()); + ret+=" "+RDXmlField("agency",q->value(8).toString()); + ret+=" "+RDXmlField("publisher",q->value(9).toString()); + ret+=" "+RDXmlField("composer",q->value(10).toString()); + ret+=" "+RDXmlField("userDefined",q->value(11).toString()); + ret+=" "+RDXmlField("usageCode",q->value(12).toInt()); + ret+=" "+RDXmlField("forcedLength", + RDGetTimeLength(q->value(13).toUInt(),true)); + ret+=" "+RDXmlField("averageLength", + RDGetTimeLength(q->value(14).toUInt(),true)); + ret+=" "+RDXmlField("lengthDeviation", + RDGetTimeLength(q->value(15).toUInt(),true)); + ret+=" "+RDXmlField("averageSegueLenth", + RDGetTimeLength(q->value(16).toUInt(),true)); + ret+=" "+RDXmlField("averageHookLength", + RDGetTimeLength(q->value(17).toUInt(),true)); + ret+=" "+RDXmlField("cutQuantity",q->value(18).toUInt()); + ret+=" "+RDXmlField("lastCutPlayed",q->value(19).toUInt()); + ret+=" "+RDXmlField("validity",q->value(20).toUInt()); + ret+=" "+RDXmlField("enforceLength",RDBool(q->value(21).toString())); + ret+=" "+RDXmlField("asyncronous",RDBool(q->value(22).toString())); + ret+=" "+RDXmlField("owner",q->value(23).toString()); + ret+=" "+RDXmlField("metadataDatetime",q->value(24).toDateTime()); + switch(type()) { + case RDCart::Audio: + if(include_cuts) { + ret+="<cutList>\n"; + sql=QString().sprintf("select CUT_NAME from CUTS where CART_NUMBER=%u", + cart_number); + q1=new RDSqlQuery(sql); + while(q1->next()) { + cut=new RDCut(q1->value(0).toString()); + ret+=cut->xml(); + delete cut; + } + delete q1; + ret+="</cutList>\n"; + } + break; + + case RDCart::Macro: + mlist=mlist.split("!",macros()); + ret+=" <macroList>\n"; + for(unsigned i=0;i<mlist.size();i++) { + ret+=QString().sprintf(" <macro%d>",i)+mlist[i]+ + QString().sprintf("!</macro%d>\n",i); + } + ret+=" </macroList>\n"; + break; + + case RDCart::All: + break; + } + ret+="</cart>\n"; + } + delete q; + return ret; +#endif // WIN32 +} + + +void RDCart::updateLength() +{ + updateLength(enforceLength(),forcedLength()); +} + + +void RDCart::updateLength(bool enforce_length,unsigned length) +{ + // + // Update Length + // + long long total=0; + long long segue_total=0; + long long hook_total=0; + unsigned weight_total=0; + unsigned weight = 0; + QDateTime end_date; + + bool dow_active[7]={false,false,false,false,false,false,false}; + bool time_ok=true; + QString sql=QString(). + sprintf("select LENGTH,SEGUE_START_POINT,SEGUE_END_POINT,START_POINT,\ + SUN,MON,TUE,WED,THU,FRI,SAT,START_DAYPART,END_DAYPART,\ + HOOK_START_POINT,HOOK_END_POINT,WEIGHT,END_DATETIME \ + from CUTS where (CUT_NAME like \"%06d%%\")&&(LENGTH>0)", + cart_number); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + for(unsigned i=0;i<7;i++) { + dow_active[i]|=RDBool(q->value(4+i).toString()); + } + weight = q->value(15).toUInt(); + end_date = q->value(16).toDateTime(); + if (end_date.isValid() && (end_date <QDateTime::currentDateTime ())){ + // This cut has expired, it is no more, set its weight to zero. + weight = 0; + } + total+=q->value(0).toUInt() * weight; + if((q->value(1).toInt()<0)||(q->value(2).toInt()<0)) { + segue_total+=q->value(0).toUInt() * weight; + } + else { + segue_total+=(q->value(1).toInt()-q->value(3).toInt()) * weight; + } + hook_total+=(q->value(14).toUInt()-q->value(13).toUInt()) * weight; + weight_total += weight; + } + if(weight_total>0) { + setAverageLength(total/weight_total); + setAverageSegueLength(segue_total/weight_total); + setAverageHookLength(hook_total/weight_total); + if(!enforce_length) { + setForcedLength(total/weight_total); + } + } + else { + setAverageLength(0); + setAverageSegueLength(0); + setAverageHookLength(0); + if(!enforce_length) { + setForcedLength(0); + } + } + setCutQuantity(q->size()); + delete q; + + // + // Update Validity + // + RDCut::Validity cut_validity=RDCut::NeverValid; + RDCart::Validity cart_validity=RDCart::NeverValid; + bool evergreen=true; + QDateTime start_datetime; + QDateTime end_datetime; + RDSqlQuery *q1; + QDateTime valid_until; + bool dates_valid=true; + + sql=QString().sprintf("select CUT_NAME,START_DAYPART,END_DAYPART,LENGTH,\ + SUN,MON,TUE,WED,THU,FRI,SAT,EVERGREEN,\ + START_DATETIME,END_DATETIME from CUTS\ + where CART_NUMBER=%u", + cart_number); + q=new RDSqlQuery(sql); + while(q->next()) { + cut_validity=ValidateCut(q,enforce_length,length,&time_ok); + sql=QString().sprintf("update CUTS set VALIDITY=%u where CUT_NAME=\"%s\"", + cut_validity,(const char *)q->value(0).toString()); + q1=new RDSqlQuery(sql); + delete q1; + evergreen&=RDBool(q->value(11).toString()); + if((int)cut_validity>(int)cart_validity) { + cart_validity=(RDCart::Validity)cut_validity; + } + if((cut_validity!=RDCut::NeverValid)&&(q->value(13).isNull())) { + dates_valid=false; + } + if(!q->value(12).isNull()) { + if((start_datetime>q->value(12).toDateTime())|| + start_datetime.isNull()) { + start_datetime=q->value(12).toDateTime(); + } + } + if(!q->value(13).isNull()) { + if((end_datetime<q->value(13).toDateTime())|| + (end_datetime.isNull())) { + end_datetime=q->value(13).toDateTime(); + } + } + } + delete q; + if(cart_validity==RDCart::ConditionallyValid) { // Promote to Always? + bool all_dow=true; + for(unsigned i=0;i<7;i++) { + all_dow&=dow_active[i]; + } + if(all_dow&&time_ok) { + cart_validity=RDCart::AlwaysValid; + } + } + if(evergreen) { // Promote to Evergreen? + cart_validity=RDCart::EvergreenValid; + } + + // + // Set start/end datetimes + // + sql="update CART set "; + if(start_datetime.isNull()||(!dates_valid)) { + sql+="START_DATETIME=NULL,"; + } + else { + sql+=QString().sprintf("START_DATETIME=\"%s\",", + (const char *)start_datetime.toString("yyyy-MM-dd hh:mm:ss")); + } + if(end_datetime.isNull()||(!dates_valid)) { + sql+="END_DATETIME=NULL,"; + } + else { + sql+=QString().sprintf("END_DATETIME=\"%s\",", + (const char *)end_datetime.toString("yyyy-MM-dd hh:mm:ss")); + } + sql+=QString().sprintf("VALIDITY=%u where NUMBER=%u", + cart_validity,cart_number); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDCart::resetRotation() const +{ + QString sql= + QString().sprintf("update CUTS set LOCAL_COUNTER=0 where CART_NUMBER=%d", + cart_number); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; +} + + +void RDCart::writeTimestamp() +{ + QString sql; + RDSqlQuery *q; + sql=QString().sprintf("update CART set METADATA_DATETIME=now() \ + where NUMBER=%u",cart_number); + q=new RDSqlQuery(sql); + delete q; + metadata_changed=false; +} + + +int RDCart::addCut(unsigned format,unsigned bitrate,unsigned chans, + const QString &isci,QString desc) +{ + RDSqlQuery *q; + QString sql; + int next; + + if((next=GetNextFreeCut())<0) { + return -1; + } + QString next_name=QString().sprintf("%06d_%03d",cart_number,next); + if(desc.isEmpty()) { + desc=QString().sprintf("Cut %03d",next); + } + sql=QString().sprintf("insert into CUTS set CUT_NAME=\"%s\",\ + CART_NUMBER=%d,ISCI=\"%s\",DESCRIPTION=\"%s\",\ + LENGTH=0,CODING_FORMAT=%d,BIT_RATE=%d,CHANNELS=%d", + (const char *)next_name, + cart_number, + (const char *)RDEscapeString(isci), + (const char *)RDEscapeString(desc), + format, + bitrate, + chans); + q=new RDSqlQuery(sql); + delete q; + + setCutQuantity(cutQuantity()+1); + updateLength(); + resetRotation(); + metadata_changed=true; + return next; +} + + +bool RDCart::removeAllCuts(RDStation *station,RDUser *user,RDConfig *config) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select CUT_NAME from CUTS where CART_NUMBER=%u", + cart_number); + q=new RDSqlQuery(sql); + while(q->next()) { + if(!removeCut(station,user,q->value(0).toString(),config)) { + delete q; + return false; + } + } + delete q; + metadata_changed=true; + return true; +} + + +bool RDCart::removeCut(RDStation *station,RDUser *user,const QString &cutname, + RDConfig *config) +{ + if(!exists()) { + return true; + } + + QString sql; + RDSqlQuery *q; + QString filename; + + filename = RDCut::pathName(cutname); + if(!RDCart::removeCutAudio(station,user,cart_number,cutname,config)) { + return false; + } + sql=QString().sprintf("delete from REPL_CUT_STATE where CUT_NAME=\"%s\"", + (const char *)cutname); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from CUTS where CUT_NAME=\"%s\"", + (const char *)cutname); + q=new RDSqlQuery(sql); + delete q; + setCutQuantity(cutQuantity()-1); + metadata_changed=true; + + return true; +} + + +bool RDCart::removeCutAudio(RDStation *station,RDUser *user, + const QString &cutname,RDConfig *config) +{ + return RDCart::removeCutAudio(station,user,cart_number,cutname,config); +} + + +bool RDCart::create(const QString &groupname,RDCart::Type type) +{ + QString sql=QString().sprintf("insert into CART set NUMBER=%d,TYPE=%d,\ + GROUP_NAME=\"%s\",TITLE=\"%s\"", + cart_number,type, + (const char *)RDEscapeString(groupname), + (const char *) + RDEscapeString(RD_DEFAULT_CART_TITLE)); + RDSqlQuery *q=new RDSqlQuery(sql); + bool ret=q->isActive(); + delete q; + metadata_changed=true; + + return ret; +} + + +bool RDCart::remove(RDStation *station,RDUser *user,RDConfig *config) const +{ + return RDCart::removeCart(cart_number,station,user,config); +} + + +bool RDCart::exists(unsigned cartnum) +{ + RDSqlQuery *q=new RDSqlQuery(QString().sprintf("select NUMBER from CART\ + where NUMBER=%u",cartnum)); + bool ret=q->first(); + delete q; + return ret; +} + + +QString RDCart::playOrderText(RDCart::PlayOrder order) +{ + switch(order) { + case RDCart::Sequence: + return QObject::tr("Sequentially"); + + case RDCart::Random: + return QObject::tr("Randomly"); + } + return QObject::tr("Unknown"); +} + + +QString RDCart::usageText(RDCart::UsageCode usage) +{ + switch(usage) { + case RDCart::UsageFeature: + return QObject::tr("Feature"); + + case RDCart::UsageOpen: + return QObject::tr("Theme Open"); + + case RDCart::UsageClose: + return QObject::tr("Theme Close"); + + case RDCart::UsageTheme: + return QObject::tr("Theme Open/Close"); + + case RDCart::UsageBackground: + return QObject::tr("Background"); + + case RDCart::UsagePromo: + return QObject::tr("Commercial/Jingle/Promo"); + + case RDCart::UsageLast: + return QObject::tr("Unknown"); + break; + } + return QObject::tr("Unknown"); +} + + +QString RDCart::typeText(RDCart::Type type) +{ + QString ret=QObject::tr("Unknown"); + + switch(type) { + case RDCart::All: + ret=QObject::tr("All"); + break; + + case RDCart::Audio: + ret=QObject::tr("Audio"); + break; + + case RDCart::Macro: + ret=QObject::tr("Macro"); + break; + + } + + return ret; +} + + +bool RDCart::removeCart(unsigned cart_num,RDStation *station,RDUser *user, + RDConfig *config) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select CUT_NAME from CUTS where CART_NUMBER=%u", + cart_num); + q=new RDSqlQuery(sql); + while(q->next()) { + if(!RDCart::removeCutAudio(station,user,cart_num,q->value(0).toString(), + config)) { + delete q; + return false; + } + } + delete q; + sql=QString().sprintf("delete from CUTS where CART_NUMBER=%u",cart_num); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from REPL_CART_STATE where CART_NUMBER=%u", + cart_num); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from CART where NUMBER=%u",cart_num); + q=new RDSqlQuery(sql); + delete q; + + return true; +} + + +bool RDCart::removeCutAudio(RDStation *station,RDUser *user,unsigned cart_num, + const QString &cutname,RDConfig *config) +{ + bool ret=true; +#ifndef WIN32 + CURL *curl=NULL; + long response_code=0; + char url[1024]; + QString xml=""; + + if(user==NULL) { + unlink(RDCut::pathName(cutname)); + unlink(RDCut::pathName(cutname)+".energy"); + } + else { + // + // Generate POST Data + // + QString post=QString(). + sprintf("COMMAND=%d&LOGIN_NAME=%s&PASSWORD=%s&CART_NUMBER=%u&CUT_NUMBER=%u", + RDXPORT_COMMAND_DELETEAUDIO, + (const char *)RDFormPost::urlEncode(user->name()), + (const char *)RDFormPost::urlEncode(user->password()), + cart_num, + cutname.right(3).toUInt()); + if((curl=curl_easy_init())==NULL) { + return false; + } + // + // Write out URL as a C string before passing to curl_easy_setopt(), + // otherwise some versions of LibCurl will throw a 'bad/illegal format' + // error. + // + strncpy(url,station->webServiceUrl(config),1024); + curl_easy_setopt(curl,CURLOPT_URL,url); + curl_easy_setopt(curl,CURLOPT_POST,1); + curl_easy_setopt(curl,CURLOPT_POSTFIELDS,(const char *)post); + curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT); + curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,CartWriteCallback); + curl_easy_setopt(curl,CURLOPT_WRITEDATA,&xml); + ret&=curl_easy_perform(curl)==0; + curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&response_code); + ret&=response_code==200; + curl_easy_cleanup(curl); + } +#endif // WIN32 + return ret; +} + + +void RDCart::removePending(RDStation *station,RDUser *user,RDConfig *config) +{ +#ifndef WIN32 + QString sql; + RDSqlQuery *q; + + sql=QString("delete from CART where ")+ + "(PENDING_STATION=\""+RDEscapeString(station->name())+"\")&&"+ + "(PENDING_PID="+QString().sprintf("%d)",getpid()); + q=new RDSqlQuery(sql); + while(q->next()) { + + } + delete q; +#endif // WIN32 +} + + +QString RDCart::GetNextCut(RDSqlQuery *q) const +{ + QString cutname; + double ratio; + double play_ratio=100000000.0; + std::vector<int> eligibles; + + + while(q->next()) { + if((ratio=q->value(2).toDouble()/q->value(1).toDouble())<play_ratio) { + play_ratio=ratio; + cutname=q->value(0).toString(); + } + } + return cutname; +} + + +int RDCart::GetNextFreeCut() const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("select CUT_NAME from CUTS where CART_NUMBER=%d\ + order by CUT_NAME", + cart_number); + q=new RDSqlQuery(sql); + for(int i=1;i<=RD_MAX_CUT_NUMBER;i++) { + if(q->next()) { + if(q->value(0).toString()!=RDCut::cutName(cart_number,i)) { + delete q; + return i; + } + } + else { + delete q; + return i; + } + } + return -1; +} + + +RDCut::Validity RDCart::ValidateCut(RDSqlQuery *q,bool enforce_length, + unsigned length,bool *time_ok) const +{ + RDCut::Validity ret=RDCut::AlwaysValid; + QDateTime current_datetime= + QDateTime(QDate::currentDate(),QTime::currentTime()); + + if(q->value(3).toUInt()==0) { + return RDCut::NeverValid; + } + if(q->value(11).toString()=="N") { // Not an Evergreen Cut! + // + // Dayparts + // + if((!q->value(1).isNull())||(!q->value(2).isNull())) { + *time_ok=false; + ret=RDCut::ConditionallyValid; + } + + // + // Days of the Week + // + bool dow_found=false; + bool all_dow_found=true; + for(int i=4;i<11;i++) { + if(q->value(i).toString()=="Y") { + dow_found=true; + } + else { + all_dow_found=false; + } + } + if(!dow_found) { + return RDCut::NeverValid; + } + if(!all_dow_found) { + ret=RDCut::ConditionallyValid; + } + + // + // Start/End DayTimes + // + if(!q->value(13).isNull()) { + *time_ok=false; + if(q->value(13).toDateTime()<current_datetime) { + return RDCut::NeverValid; + } + if(q->value(12).toDateTime()>current_datetime) { + ret=RDCut::FutureValid; + } + else { + ret=RDCut::ConditionallyValid; + } + } + } + + // + // Timescaling + // + if(enforce_length) { + double len=(double)length; + if(((q->value(3).toDouble()*RD_TIMESCALE_MAX)<len)|| + ((q->value(3).toDouble()*RD_TIMESCALE_MIN)>len)) { + *time_ok=false; + return RDCut::NeverValid; + } + } + + return ret; +} + + +QString RDCart::VerifyTitle(const QString &title) const +{ + QString ret=title; + QString sql; + RDSqlQuery *q; + RDSystem *system=new RDSystem(); + + if(!system->allowDuplicateCartTitles()) { + int n=1; + while(1==1) { + sql=QString().sprintf("select NUMBER from CART \ + where (TITLE=\"%s\")&&(NUMBER!=%u)", + (const char *)RDEscapeString(ret),cart_number); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return ret; + } + delete q; + ret=title+QString().sprintf(" [%d]",n++); + } + } + delete system; + return ret; +} + + +void RDCart::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE CART SET %s=\"%s\" WHERE NUMBER=%u", + (const char *)param, + (const char *)RDEscapeString(value.utf8()), + cart_number); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDCart::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE CART SET %s=%d WHERE NUMBER=%u", + (const char *)param, + value, + cart_number); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDCart::SetRow(const QString ¶m,const QDateTime &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE CART SET %s=\"%s\" WHERE NUMBER=%u", + (const char *)param, + (const char *)value.toString("yyyy-MM-dd hh:mm:ss"), + cart_number); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDCart::SetRow(const QString ¶m,const QDate &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE CART SET %s=\"%s\" WHERE NUMBER=%u", + (const char *)param, + (const char *)value.toString("yyyy-MM-dd"), + cart_number); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDCart::SetRow(const QString ¶m) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE CART SET %s=NULL WHERE NUMBER=%u", + (const char *)param, + cart_number); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdcart.h b/lib/rdcart.h new file mode 100644 index 00000000..dcdcc9ff --- /dev/null +++ b/lib/rdcart.h @@ -0,0 +1,178 @@ +// rdcart.h +// +// Abstract a Rivendell Cart +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcart.h,v 1.39.6.5.2.5 2014/05/30 00:26:28 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qdatetime.h> +#include <qstringlist.h> + +#include <rdconfig.h> +#include <rdwavedata.h> + +#include <rdcut.h> +#include <rddb.h> +#include <rduser.h> +#include <rdstation.h> + +#ifndef RDCART_H +#define RDCART_H + +#define MAX_SERVICES 16 + +class RDCart +{ + public: + enum Type {All=0,Audio=1,Macro=2}; + enum PlayOrder {Sequence=0,Random=1}; + enum UsageCode {UsageFeature=0,UsageOpen=1,UsageClose=2,UsageTheme=3, + UsageBackground=4,UsagePromo=5,UsageLast=6}; + enum Validity {NeverValid=0,ConditionallyValid=1,AlwaysValid=2, + EvergreenValid=3,FutureValid=4}; + RDCart(unsigned number); + ~RDCart(); + bool exists() const; + bool selectCut(QString *cut) const; + bool selectCut(QString *cut,const QTime &time) const; + RDCart::Type type() const; + void setType(RDCart::Type type); + unsigned number() const; + QString groupName() const; + void setGroupName(const QString &name); + QString title() const; + void setTitle(const QString &title); + QString artist() const; + void setArtist(const QString &name); + QString album() const; + void setAlbum(const QString &album); + int year() const; + void setYear(int year=-1); + QString schedCodes() const; + void setSchedCodes(const QString &sched_codes) const; + QStringList schedCodesList() const; + void setSchedCodesList(const QStringList &codes); + void addSchedCode(const QString &code); + void updateSchedCodes(const QString &add_codes, + const QString &remove_codes) const; + QString conductor() const; + void setConductor(const QString &cond); + QString label() const; + void setLabel(const QString &label); + QString client() const; + void setClient(const QString &client); + QString agency() const; + void setAgency(const QString &agency); + QString publisher() const; + void setPublisher(const QString &publisher); + QString composer() const; + void setComposer(const QString &composer); + QString userDefined() const; + void setUserDefined(const QString &string); + QString songId() const; + void setSongId(const QString &id); + unsigned beatsPerMinute() const; + void setBeatsPerMinute(unsigned bpm); + RDCart::UsageCode usageCode() const; + void setUsageCode(RDCart::UsageCode code); + QString notes() const; + void setNotes(const QString ¬es); + unsigned forcedLength() const; + void setForcedLength(unsigned length); + unsigned lengthDeviation() const; + void setLengthDeviation(unsigned length) const; + unsigned calculateAverageLength(unsigned *max_dev=0) const; + unsigned averageLength() const; + void setAverageLength(unsigned length) const; + unsigned averageSegueLength() const; + void setAverageSegueLength(unsigned length) const; + unsigned averageHookLength() const; + void setAverageHookLength(unsigned length) const; + unsigned cutQuantity() const; + void setCutQuantity(unsigned quan) const; + unsigned lastCutPlayed() const; + void setLastCutPlayed(unsigned cut) const; + RDCart::PlayOrder playOrder() const; + void setPlayOrder(RDCart::PlayOrder order) const; + RDCart::Validity validity() const; + void setValidity(RDCart::Validity state); + QDateTime startDateTime() const; + void setStartDateTime(const QDateTime &time); + void setStartDateTime(); + QDateTime endDateTime() const; + void setEndDateTime(const QDateTime &time); + void setEndDateTime(); + bool enforceLength() const; + void setEnforceLength(bool state); + bool preservePitch() const; + void setPreservePitch(bool state) const; + bool asyncronous() const; + void setAsyncronous(bool state) const; + QString owner() const; + void setOwner(const QString &owner) const; + bool useEventLength() const; + void setUseEventLength(bool state) const; + void setPending(const QString &station_name); + void clearPending() const; + QString macros() const; + void setMacros(const QString &cmds) const; + bool validateLengths(int len) const; + void getMetadata(RDWaveData *data) const; + void setMetadata(const RDWaveData *data); + QString xml(bool include_cuts) const; + void updateLength(); + void updateLength(bool enforce_length,unsigned length); + void resetRotation() const; + void writeTimestamp(); + int addCut(unsigned format,unsigned bitrate,unsigned chans, + const QString &isci="",QString desc=""); + bool removeAllCuts(RDStation *station,RDUser *user,RDConfig *config); + bool removeCut(RDStation *station,RDUser *user,const QString &cutname, + RDConfig *config); + bool removeCutAudio(RDStation *station,RDUser *user, + const QString &cutname,RDConfig *config); + bool create(const QString &groupname,RDCart::Type type); + bool remove(RDStation *station,RDUser *user,RDConfig *config) const; + static bool exists(unsigned cartnum); + static QString playOrderText(RDCart::PlayOrder order); + static QString usageText(RDCart::UsageCode usage); + static QString typeText(RDCart::Type type); + static bool removeCart(unsigned cart_num,RDStation *station,RDUser *user, + RDConfig *config); + static bool removeCutAudio(RDStation *station,RDUser *user,unsigned cart_num, + const QString &cutname,RDConfig *config); + static void removePending(RDStation *station,RDUser *user,RDConfig *config); + + private: + QString GetNextCut(RDSqlQuery *q) const; + int GetNextFreeCut() const; + RDCut::Validity ValidateCut(RDSqlQuery *q,bool enforce_length, + unsigned length,bool *time_ok) const; + QString VerifyTitle(const QString &title) const; + + void SetRow(const QString ¶m,const QString &value) const; + void SetRow(const QString ¶m,unsigned value) const; + void SetRow(const QString ¶m,const QDateTime &value) const; + void SetRow(const QString ¶m,const QDate &value) const; + void SetRow(const QString ¶m) const; + unsigned cart_number; + bool metadata_changed; +}; + + +#endif // RDCART_H diff --git a/lib/rdcart_dialog.cpp b/lib/rdcart_dialog.cpp new file mode 100644 index 00000000..ba74e465 --- /dev/null +++ b/lib/rdcart_dialog.cpp @@ -0,0 +1,943 @@ +// rdcart_dialog.cpp +// +// A widget to select a Rivendell Cart. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcart_dialog.cpp,v 1.48.4.8 2014/02/11 23:46:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> + +#include <qpushbutton.h> +#include <qlabel.h> +#include <qsqlquery.h> +#include <qdatetime.h> +#include <qapplication.h> +#include <qeventloop.h> +#include <qfiledialog.h> +#include <qmessagebox.h> + +#include <rdconf.h> +#include <rdcart_dialog.h> +#include <rdcart_search_text.h> +#include <rdtextvalidator.h> +#include <rdprofile.h> +#include <rddb.h> +#include <rdgroup.h> +#ifndef WIN32 +#include <rdaudioimport.h> +#endif // WIN32 +#include <rdsettings.h> +#include <rdwavefile.h> + +// +// Icons +// +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" + +RDCartDialog::RDCartDialog(QString *filter,QString *group,QString *schedcode, + RDCae *cae,RDRipc *ripc,RDStation *station, + RDSystem *system,RDConfig *config,QWidget *parent) + : QDialog(parent,"",true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + cart_station=station; + cart_system=system; + cart_config=config; + cart_cartnum=NULL; + cart_type=RDCart::All; + cart_group=group; + cart_schedcode=schedcode; + cart_temp_allowed=NULL; +#ifdef WIN32 + cart_filter_mode=RDStation::FilterSynchronous; +#else + cart_filter_mode=station->filterMode(); +#endif // WIN32 + + if(filter==NULL) { + cart_filter=new QString(); + local_filter=true; + } + else { + cart_filter=filter; + local_filter=false; + } + cart_import_path=RDGetHomeDir(); + cart_import_file_filter=RD_AUDIO_FILE_FILTER; + + setCaption(tr("Select Cart")); + + // + // Create Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont progress_font=QFont("Helvetica",16,QFont::Bold); + progress_font.setPixelSize(16); + + // + // Create Icons + // + cart_playout_map=new QPixmap(play_xpm); + cart_macro_map=new QPixmap(rml5_xpm); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator",true); + + // + // Progress Dialog + // + cart_progress_dialog= + new QProgressDialog(tr("Please Wait..."),"Cancel",10,this, + "cart_progress_dialog",false, + Qt::WStyle_Customize|Qt::WStyle_NormalBorder); + cart_progress_dialog->setCaption(" "); + QLabel *label=new QLabel(tr("Please Wait..."),cart_progress_dialog); + label->setAlignment(AlignCenter); + label->setFont(progress_font); + cart_progress_dialog->setLabel(label); + cart_progress_dialog->setCancelButton(NULL); + cart_progress_dialog->setMinimumDuration(2000); + + cart_busy_dialog=new RDBusyDialog(this); + + // + // Filter Selector + // + cart_filter_edit=new QLineEdit(this); + cart_filter_edit->setValidator(validator); + cart_filter_label=new QLabel(cart_filter_edit,tr("Cart Filter:"), + this,"cart_filter_label"); + cart_filter_label->setAlignment(AlignRight|AlignVCenter); + cart_filter_label->setFont(button_font); + connect(cart_filter_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(filterChangedData(const QString &))); + + // + // Filter Search Button + // + cart_search_button=new QPushButton(this); + cart_search_button->setText(tr("&Search")); + cart_search_button->setFont(button_font); + connect(cart_search_button,SIGNAL(clicked()),this,SLOT(filterSearchedData())); + + // + // Filter Clear Button + // + cart_clear_button=new QPushButton(this); + cart_clear_button->setText(tr("C&lear")); + cart_clear_button->setFont(button_font); + connect(cart_clear_button,SIGNAL(clicked()),this,SLOT(filterClearedData())); + + // + // Group Code Selector + // + cart_group_box=new RDComboBox(this); + cart_group_label=new QLabel(cart_group_box,tr("Group:"),this); + cart_group_label->setAlignment(AlignRight|AlignVCenter); + cart_group_label->setFont(button_font); + connect(cart_group_box,SIGNAL(activated(const QString &)), + this,SLOT(groupActivatedData(const QString &))); + + // + // Scheduler Code Selector + // + cart_schedcode_box=new RDComboBox(this); + cart_schedcode_label= + new QLabel(cart_schedcode_box,tr("Scheduler Code:"),this); + cart_schedcode_label->setAlignment(AlignRight|AlignVCenter); + cart_schedcode_label->setFont(button_font); + connect(cart_schedcode_box,SIGNAL(activated(const QString &)), + this,SLOT(schedcodeActivatedData(const QString &))); + + // + // Search Limit Checkbox + // + cart_limit_box=new QCheckBox(this); + cart_limit_box->setChecked(true); + cart_limit_label= + new QLabel(cart_limit_box,tr("Show Only First")+ + QString().sprintf(" %d ", + RD_LIMITED_CART_SEARCH_QUANTITY)+tr("Matches"),this); + cart_limit_label->setAlignment(AlignLeft|AlignVCenter); + cart_limit_label->setFont(button_font); + connect(cart_limit_box,SIGNAL(stateChanged(int)), + this,SLOT(limitChangedData(int))); + + // + // Cart List + // + cart_cart_list=new RDListView(this); + cart_cart_list->setSelectionMode(QListView::Single); + cart_cart_list->setAllColumnsShowFocus(true); + cart_cart_list->setItemMargin(5); + connect(cart_cart_list,SIGNAL(clicked(QListViewItem *)), + this,SLOT(clickedData(QListViewItem *))); + connect(cart_cart_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + cart_cart_label=new QLabel(cart_cart_list,"Carts",this); + cart_cart_label->setFont(button_font); + cart_cart_list->addColumn(""); + cart_cart_list->setColumnAlignment(0,Qt::AlignHCenter); + + cart_cart_list->addColumn(tr("NUMBER")); + cart_cart_list->setColumnAlignment(1,Qt::AlignHCenter); + + cart_cart_list->addColumn(tr("LENGTH")); + cart_cart_list->setColumnAlignment(2,Qt::AlignRight); + cart_cart_list->setColumnSortType(2,RDListView::TimeSort); + + cart_cart_list->addColumn(tr("TITLE"),200); + cart_cart_list->setColumnAlignment(3,Qt::AlignLeft); + cart_cart_list->setColumnWidthMode(3,QListView::Manual); + + cart_cart_list->addColumn(tr("ARTIST")); + cart_cart_list->setColumnAlignment(4,Qt::AlignLeft); + + cart_cart_list->addColumn(tr("GROUP")); + cart_cart_list->setColumnAlignment(5,Qt::AlignLeft); + + cart_cart_list->addColumn(tr("COMPOSER")); + cart_cart_list->setColumnAlignment(6,Qt::AlignLeft); + + cart_cart_list->addColumn(tr("CONDUCTOR")); + cart_cart_list->setColumnAlignment(7,Qt::AlignLeft); + + cart_cart_list->addColumn(tr("CLIENT")); + cart_cart_list->setColumnAlignment(8,Qt::AlignLeft); + + cart_cart_list->addColumn(tr("AGENCY")); + cart_cart_list->setColumnAlignment(9,Qt::AlignLeft); + + cart_cart_list->addColumn(tr("USER DEF")); + cart_cart_list->setColumnAlignment(10,Qt::AlignLeft); + + cart_cart_list->addColumn(tr("START")); + cart_cart_list->setColumnAlignment(11,Qt::AlignLeft); + + cart_cart_list->addColumn(tr("END")); + cart_cart_list->setColumnAlignment(12,Qt::AlignLeft); + + // + // Audition Player + // +#ifndef WIN32 + if((cae==NULL)||(station->cueCard()<0)||(station->cuePort()<0)) { + cart_player=NULL; + } + else { + cart_player= + new RDSimplePlayer(cae,ripc,station->cueCard(),station->cuePort(), + station->cueStartCart(),station->cueStopCart(),this); + cart_player->playButton()->setDisabled(true); + cart_player->stopButton()->setDisabled(true); + cart_player->stopButton()->setOnColor(red); + } +#endif // WIN32 + + // + // Send to Editor Button + // + cart_editor_button=new QPushButton(tr("Send to\n&Editor"),this); + cart_editor_button->setFont(button_font); + connect(cart_editor_button,SIGNAL(clicked()),this,SLOT(editorData())); + if(station->editorPath().isEmpty()) { + cart_editor_button->hide(); + } + + // + // Load From File Button + // + cart_file_button=new QPushButton(tr("Load From\n&File"),this); + cart_file_button->setFont(button_font); + connect(cart_file_button,SIGNAL(clicked()),this,SLOT(loadFileData())); + if(station->editorPath().isEmpty()) { + cart_file_button->hide(); + } +#ifdef WIN32 + cart_file_button->hide(); +#endif // WIN32 + + // + // OK Button + // + cart_ok_button=new QPushButton(tr("&OK"),this); + cart_ok_button->setFont(button_font); + connect(cart_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + cart_cancel_button=new QPushButton(tr("&Cancel"),this); + cart_cancel_button->setFont(button_font); + connect(cart_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +RDCartDialog::~RDCartDialog() +{ + if(local_filter) { + delete cart_filter; + } +#ifndef WIN32 + if(cart_player!=NULL) { + delete cart_player; + } +#endif // WIN32 + delete cart_playout_map; + delete cart_macro_map; +} + + +QSize RDCartDialog::sizeHint() const +{ + return QSize(640,400); +} + +int RDCartDialog::exec(int *cartnum,RDCart::Type type,QString *svcname, + int svc_quan,const QString &username, + const QString &passwd,bool *temp_allowed) +{ + LoadState(); + cart_cartnum=cartnum; + cart_type=type; + cart_service=svcname; + cart_service_quan=svc_quan; + cart_user_name=username; + cart_user_password=passwd; + cart_temp_allowed=temp_allowed; + switch(cart_type) { + case RDCart::All: + case RDCart::Audio: + if(cart_station->editorPath().isEmpty()) { + cart_editor_button->hide(); + } + else { + cart_editor_button->show(); + } + if(temp_allowed==NULL) { + cart_file_button->hide(); + } + else { + cart_file_button->show(); + } +#ifndef WIN32 + if(cart_player!=NULL) { + cart_player->playButton()->show(); + cart_player->stopButton()->show(); + } +#endif // WIN32 + break; + + case RDCart::Macro: + cart_editor_button->hide(); +#ifndef WIN32 + if(cart_player!=NULL) { + cart_player->playButton()->hide(); + cart_player->stopButton()->hide(); + } +#endif // WIN32 + break; + } + if(*cart_cartnum==0) { + cart_ok_button->setDisabled(true); + } + switch(cart_filter_mode) { + case RDStation::FilterAsynchronous: + cart_search_button->setDefault(true); + break; + + case RDStation::FilterSynchronous: + cart_ok_button->setDefault(true); + cart_search_button->hide(); + } + BuildGroupList(); + cart_filter_edit->setText(*cart_filter); + RefreshCarts(); + RDListViewItem *item=(RDListViewItem *)cart_cart_list->firstChild(); + while(item!=NULL) { + if(item->text(1).toInt()==*cartnum) { + cart_cart_list->setSelected(item,true); + cart_cart_list->ensureItemVisible(item); + clickedData(item); + return QDialog::exec(); + } + item=(RDListViewItem *)item->nextSibling(); + } + return QDialog::exec(); +} + + +QSizePolicy RDCartDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDCartDialog::filterChangedData(const QString &str) +{ + cart_search_button->setEnabled(true); + switch(cart_filter_mode) { + case RDStation::FilterSynchronous: + filterSearchedData(); + break; + + case RDStation::FilterAsynchronous: + break; + } +} + + +void RDCartDialog::filterSearchedData() +{ + if(cart_filter_edit->text().isEmpty()) { + cart_clear_button->setDisabled(true); + } + else { + cart_clear_button->setEnabled(true); + } + RefreshCarts(); +} + + +void RDCartDialog::filterClearedData() +{ + cart_filter_edit->clear(); + filterChangedData(""); +} + + +void RDCartDialog::groupActivatedData(const QString &group) +{ + filterChangedData(""); + if(cart_group!=NULL) { + *cart_group=group; + } + if(cart_group!=NULL) { + *cart_group=group; + } +} + + +void RDCartDialog::schedcodeActivatedData(const QString &schedcode) +{ + filterChangedData(""); + if(cart_schedcode!=NULL) { + *cart_schedcode=schedcode; + } + if(cart_schedcode!=NULL) { + *cart_schedcode=schedcode; + } +} + + +void RDCartDialog::limitChangedData(int state) +{ + filterChangedData(""); +} + + +void RDCartDialog::clickedData(QListViewItem *item) +{ + RDListViewItem *i=(RDListViewItem *)item; + if (i==NULL) { + return; + } + cart_ok_button->setEnabled(true); + bool audio=((RDCart::Type)i->id())==RDCart::Audio; +#ifndef WIN32 + if(cart_player!=NULL) { + cart_player->playButton()->setEnabled(audio); + cart_player->stopButton()->setEnabled(audio); + cart_player->setCart(i->text(1).toUInt()); + } +#endif // WIN32 + cart_editor_button->setEnabled(audio); +} + + +void RDCartDialog::doubleClickedData(QListViewItem *,const QPoint &,int) +{ + okData(); +} + + +void RDCartDialog::editorData() +{ +#ifndef WIN32 + RDListViewItem *item=(RDListViewItem *)cart_cart_list->currentItem(); + if(item==NULL) { + return; + } + + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select CUTS.CUT_NAME,CUTS.LENGTH,CART.GROUP_NAME,\ + CART.TITLE,CART.ARTIST,CART.ALBUM,CART.YEAR,\ + CART.LABEL,CART.CLIENT,CART.AGENCY,CART.COMPOSER,\ + CART.PUBLISHER,CART.USER_DEFINED \ + from CUTS left join CART \ + on CUTS.CART_NUMBER=CART.NUMBER \ + where (CUTS.CART_NUMBER=%u)&&(CUTS.LENGTH>0)", + item->text(1).toUInt()); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return; + } + QString cmd=cart_station->editorPath(); + cmd.replace("%f",RDCut::pathName(q->value(0).toString())); + cmd.replace("%n",QString().sprintf("%06u",item->text(1).toUInt())); + cmd.replace("%h",QString().sprintf("%d",q->value(1).toInt())); + cmd.replace("%g",q->value(2).toString()); + cmd.replace("%t",q->value(3).toString()); + cmd.replace("%a",q->value(4).toString()); + cmd.replace("%l",q->value(5).toString()); + cmd.replace("%y",q->value(6).toString()); + cmd.replace("%b",q->value(7).toString()); + cmd.replace("%c",q->value(8).toString()); + cmd.replace("%e",q->value(9).toString()); + cmd.replace("%m",q->value(10).toString()); + cmd.replace("%p",q->value(11).toString()); + cmd.replace("%u",q->value(12).toString()); + delete q; + + if(fork()==0) { + system(cmd+" &"); + exit(0); + } +#endif +} + + +void RDCartDialog::loadFileData() +{ +#ifndef WIN32 + QString filename; + RDGroup *group=NULL; + RDCart *cart=NULL; + RDCut *cut=NULL; + RDAudioImport *conv; + RDAudioImport::ErrorCode err; + RDAudioConvert::ErrorCode conv_err; + RDSettings settings; + unsigned cartnum=0; + QString file_title=""; + RDWaveFile *wavefile=NULL; + RDWaveData wavedata; + + filename=QFileDialog::getOpenFileName(cart_import_path, + cart_import_file_filter,this); + if(!filename.isEmpty()) { + + // + // Get Cart Number + // + cart_import_path=RDGetPathPart(filename); + group=new RDGroup(cart_system->tempCartGroup()); + if((!group->exists())||((cartnum=group->nextFreeCart())==0)) { + delete group; + QMessageBox::warning(this,tr("Cart Error"), + tr("Unable to get temporary cart number for import!")); + return; + } + delete group; + + // + // Create Cart + // + cart=new RDCart(cartnum); + if(!cart->create(cart_system->tempCartGroup(),RDCart::Audio)) { + delete cart; + QMessageBox::warning(this,tr("Cart Error"), + tr("Unable to create temporary cart for import!")); + return; + } + cart->setOwner(cart_station->name()); + cut=new RDCut(cartnum,1,true); + + // + // Import Audio + // + cart_busy_dialog->show(tr("Importing"),tr("Importing...")); + conv=new RDAudioImport(cart_station,cart_config,this); + conv->setCartNumber(cartnum); + conv->setCutNumber(1); + conv->setSourceFile(filename); + settings.setChannels(2); + settings.setNormalizationLevel(-11); + conv->setDestinationSettings(&settings); + conv->setUseMetadata(true); + err=conv->runImport(cart_user_name,cart_user_password,&conv_err); + cart_busy_dialog->hide(); + switch(conv_err) { + case RDAudioImport::ErrorOk: + break; + + default: + QMessageBox::warning(this,tr("Import Error"), + RDAudioImport::errorText(err,conv_err)); + delete conv; + delete cart; + delete cut; + return; + } + + // + // Check Metadata + // + wavefile=new RDWaveFile(filename); + if(wavefile->openWave(&wavedata)) { + if((!wavedata.metadataFound())||(wavedata.title().isEmpty())) { + cart->setTitle(tr("Imported from")+" "+RDGetBasePart(filename)); + } + } + + *cart_cartnum=cartnum; + *cart_temp_allowed=true; + delete conv; + delete cart; + delete cut; + done(0); + } +#endif // WIN32 +} + + +void RDCartDialog::okData() +{ + RDListViewItem *item=(RDListViewItem *)cart_cart_list->currentItem(); + if(item==NULL) { + return; + } + +#ifndef WIN32 + SaveState(); + if(cart_player!=NULL) { + cart_player->stop(); + } +#endif // WIN32 + if(!local_filter) { + *cart_filter=cart_filter_edit->text(); + } + *cart_cartnum=item->text(1).toInt(); + if(cart_temp_allowed!=NULL) { + *cart_temp_allowed=false; + } + done(0); +} + + +void RDCartDialog::cancelData() +{ +#ifndef WIN32 + SaveState(); + if(cart_player!=NULL) { + cart_player->stop(); + } +#endif // WIN32 + done(-1); +} + + +void RDCartDialog::resizeEvent(QResizeEvent *e) +{ + cart_filter_label->setGeometry(10,10,85,20); + + cart_search_button->setGeometry(size().width()-160,5,70,30); + cart_clear_button->setGeometry(size().width()-80,5,70,30); + cart_group_box->setGeometry(100,40,150,20); + cart_group_label->setGeometry(10,40,85,20); + cart_schedcode_box->setGeometry(390,40,150,20); + cart_schedcode_label->setGeometry(280,40,105,20); + cart_limit_box->setGeometry(100,72,15,15); + cart_limit_label->setGeometry(120,70,300,20); + cart_cart_label->setGeometry(15,90,100,20); + cart_cart_list->setGeometry(10,110,size().width()-20,size().height()-180); + cart_editor_button->setGeometry(235,size().height()-60,80,50); + cart_file_button->setGeometry(325,size().height()-60,80,50); + cart_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + cart_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); + switch(cart_filter_mode) { + case RDStation::FilterAsynchronous: + cart_filter_edit->setGeometry(100,10,size().width()-280,20); + break; + + case RDStation::FilterSynchronous: + cart_filter_edit->setGeometry(100,10,size().width()-200,20); + break; + } +#ifndef WIN32 + if(cart_player!=NULL) { + cart_player->playButton()->setGeometry(10,size().height()-60,80,50); + cart_player->stopButton()->setGeometry(100,size().height()-60,80,50); + } +#endif // WIN32 +} + + +void RDCartDialog::closeEvent(QCloseEvent *e) +{ +#ifndef WIN32 + if(cart_player!=NULL) { + cart_player->stop(); + } +#endif // WIN32 + cancelData(); +} + + +void RDCartDialog::RefreshCarts() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *l; + RDListViewItem *active_item=NULL; + + cart_cart_list->clear(); + QString group=cart_group_box->currentText(); + if(group==QString(tr("ALL"))) { + group=""; + } + QString schedcode=cart_schedcode_box->currentText(); + if(group==QString(tr("ALL"))) { + schedcode=""; + } + if(cart_type==RDCart::All) { + sql=QString().sprintf("select CART.NUMBER,CART.TITLE,CART.ARTIST,\ + CART.CLIENT,CART.AGENCY,CART.USER_DEFINED,\ + CART.COMPOSER,CART.CONDUCTOR,\ + CART.START_DATETIME,CART.END_DATETIME,CART.TYPE,\ + CART.FORCED_LENGTH,CART.GROUP_NAME,GROUPS.COLOR \ + from CART left join GROUPS \ + on CART.GROUP_NAME=GROUPS.NAME where %s", + (const char *)GetSearchFilter(cart_filter_edit->text(), + group,schedcode)); + } + else { + sql=QString().sprintf("select CART.NUMBER,CART.TITLE,CART.ARTIST,\ + CART.CLIENT,CART.AGENCY,CART.USER_DEFINED,\ + CART.COMPOSER,CART.CONDUCTOR,\ + CART.START_DATETIME,CART.END_DATETIME,CART.TYPE,\ + CART.FORCED_LENGTH,CART.GROUP_NAME,GROUPS.COLOR \ + from CART left join GROUPS \ + on CART.GROUP_NAME=GROUPS.NAME \ + where (%s)&&(TYPE=%d)", + (const char *)GetSearchFilter(cart_filter_edit->text(), + group,schedcode), + cart_type); + } + if(cart_limit_box->isChecked()) { + sql+=QString().sprintf(" limit %d",RD_LIMITED_CART_SEARCH_QUANTITY); + } + q=new RDSqlQuery(sql); + int step=0; + int count=0; + cart_progress_dialog->setTotalSteps(q->size()/RDCART_DIALOG_STEP_SIZE); + cart_progress_dialog->setProgress(0); + while(q->next()) { + l=new RDListViewItem(cart_cart_list); + l->setId(q->value(10).toUInt()); + switch((RDCart::Type)q->value(10).toUInt()) { + case RDCart::Audio: + l->setPixmap(0,*cart_playout_map); + break; + + case RDCart::Macro: + l->setPixmap(0,*cart_macro_map); + break; + + default: + break; + } + l->setText(1,QString().sprintf("%06d",q->value(0).toUInt())); // Number + l->setText(2,RDGetTimeLength(q->value(11).toInt(),false,true)); // Length + l->setText(3,q->value(1).toString()); // Title + l->setText(4,q->value(2).toString()); // Artist + l->setText(5,q->value(12).toString()); // Group + l->setText(6,q->value(6).toString()); // Composer + l->setText(7,q->value(7).toString()); // Conductor + l->setTextColor(5,q->value(13).toString(),QFont::Bold); + l->setText(8,q->value(3).toString()); // Client + l->setText(9,q->value(4).toString()); // Agency + l->setText(10,q->value(5).toString()); // User Defined + if(!q->value(8).toDate().isNull()) { + l->setText(11,q->value(8).toDate().toString("MM/dd/yyyy")); // Start Date + } + if(!q->value(10).toDate().isNull()) { + l->setText(12,q->value(9).toDate().toString("MM/dd/yyyy")); // End Date + } + else { + l->setText(12,"TFN"); + } + if(*cart_cartnum==q->value(0).toInt()) { + active_item=l; + } + if(count++>RDCART_DIALOG_STEP_SIZE) { + cart_progress_dialog->setProgress(++step); + count=0; + qApp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput); + } + } + cart_progress_dialog->reset(); + delete q; + cart_search_button->setDisabled(true); +} + + +void RDCartDialog::BuildGroupList() +{ + QString sql; + RDSqlQuery *q; + + // + // Groups + // + cart_group_box->clear(); + cart_group_box->insertItem(tr("ALL")); + sql="select GROUP_NAME from AUDIO_PERMS"; + if(cart_service_quan>0) { + sql+=" where "; + for(int i=0;i<cart_service_quan;i++) { + if(!cart_service[i].isEmpty()) { + sql+=QString().sprintf("(SERVICE_NAME=\"%s\")||", + (const char *)cart_service[i]); + } + } + sql=sql.left(sql.length()-2); + } + sql+=" order by GROUP_NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + cart_group_box->insertItem(q->value(0).toString(),true); + } + delete q; + + // + // Preselect Group + // + if(cart_group!=NULL) { + for(int i=0;i<cart_group_box->count();i++) { + if(*cart_group==cart_group_box->text(i)) { + cart_group_box->setCurrentItem(i); + return; + } + } + } + + // + // Scheduler Codes + // + cart_schedcode_box->clear(); + cart_schedcode_box->insertItem(tr("ALL")); + sql="select CODE from SCHED_CODES"; + q=new RDSqlQuery(sql); + while(q->next()) { + cart_schedcode_box->insertItem(q->value(0).toString()); + } + delete q; + + // + // Preselect Scheduler Code + // + if(cart_schedcode!=NULL) { + for(int i=0;i<cart_schedcode_box->count();i++) { + if(*cart_schedcode==cart_schedcode_box->text(i)) { + cart_schedcode_box->setCurrentItem(i); + return; + } + } + } +} + + +QString RDCartDialog::GetSearchFilter(const QString &filter, + const QString &group, + const QString &schedcode) +{ + QString sql; + RDSqlQuery *q; + QString sched=""; + + if(schedcode!=tr("ALL")) { + sched=schedcode; + } + QString search=RDCartSearchText(filter,group,sched,false).utf8(); + + // + // Excluded Groups + // + sql=QString().sprintf("select NAME from GROUPS where "); + for(int i=1;i<cart_group_box->count();i++) { + sql+=QString().sprintf("(NAME!=\"%s\")&&", + (const char *)cart_group_box->text(i)); + } + sql=sql.left(sql.length()-2); + q=new RDSqlQuery(sql); + while(q->next()) { + search+=QString().sprintf("&&(GROUP_NAME!=\"%s\")", + (const char *)q->value(0).toString()); + } + delete q; + return search; +} + + +void RDCartDialog::LoadState() +{ + if(getenv("HOME")==NULL) { + return; + } + RDProfile *p=new RDProfile(); + p->setSource(QString().sprintf("%s/.rdcartdialog",getenv("HOME"))); + delete p; +} + + +void RDCartDialog::SaveState() +{ + FILE *f=NULL; + + if(getenv("HOME")==NULL) { + return; + } + if((f=fopen(QString().sprintf("%s/.rdcartdialog",getenv("HOME")),"w"))== + NULL) { + return; + } + fprintf(f,"[RDCartDialog]\n"); + if(cart_limit_box->isChecked()) { + fprintf(f,"LimitSearch=Yes\n"); + } + else { + fprintf(f,"LimitSearch=No\n"); + } + fclose(f); +} diff --git a/lib/rdcart_dialog.h b/lib/rdcart_dialog.h new file mode 100644 index 00000000..3a01e9f9 --- /dev/null +++ b/lib/rdcart_dialog.h @@ -0,0 +1,132 @@ +// rdcart_dialog.h +// +// A widget to select a Rivendell Cart. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcart_dialog.h,v 1.21.4.3 2014/02/11 23:46:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCART_DIALOG_H +#define RDCART_DIALOG_H + +#include <qdialog.h> +#include <qlineedit.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qprogressdialog.h> +#include <qcheckbox.h> + +#include <rdcae.h> +#include <rdconfig.h> +#include <rdripc.h> +#include <rdsystem.h> +#include <rdsimpleplayer.h> +#include <rdlistviewitem.h> +#include <rdcart.h> +#include <rdstation.h> +#include <rdcombobox.h> +#include <rduser.h> +#include <rdbusydialog.h> + +#define RDCART_DIALOG_STEP_SIZE 1000 + +class RDCartDialog : public QDialog +{ + Q_OBJECT + public: + RDCartDialog(QString *filter,QString *group,QString *schedcode, + RDCae *cae,RDRipc *ripc,RDStation *station,RDSystem *system, + RDConfig *config,QWidget *parent=0); + + ~RDCartDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(int *cartnum,RDCart::Type type,QString *svcname,int svc_quan, + const QString &username,const QString &passwd, + bool *temp_allowed=NULL); + + private slots: + void filterChangedData(const QString &); + void filterSearchedData(); + void filterClearedData(); + void groupActivatedData(const QString &group); + void schedcodeActivatedData(const QString &schedcode); + void limitChangedData(int state); + void clickedData(QListViewItem *item); + void doubleClickedData(QListViewItem *,const QPoint &,int); + void editorData(); + void loadFileData(); + void okData(); + void cancelData(); + + protected: + void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e); + + private: + void RefreshCarts(); + void BuildGroupList(); + QString GetSearchFilter(const QString &filter,const QString &group, + const QString &schedcode); + void LoadState(); + void SaveState(); + int *cart_cartnum; + QLabel *cart_cart_label; + RDListView *cart_cart_list; + QLabel *cart_filter_label; + QLineEdit *cart_filter_edit; + QLabel *cart_limit_label; + QCheckBox *cart_limit_box; + QPushButton *cart_ok_button; + QPushButton *cart_cancel_button; + QPushButton *cart_search_button; + QPushButton *cart_clear_button; + QPushButton *cart_editor_button; + QPushButton *cart_file_button; + QLabel *cart_group_label; + RDComboBox *cart_group_box; + QLabel *cart_schedcode_label; + RDComboBox *cart_schedcode_box; + QString *cart_filter; + QString *cart_group; + QString *cart_schedcode; + bool local_filter; + RDCart::Type cart_type; + QPixmap *cart_playout_map; + QPixmap *cart_macro_map; + QString *cart_service; + int cart_service_quan; + RDStation::FilterMode cart_filter_mode; + QProgressDialog *cart_progress_dialog; + QString cart_import_path; + QString cart_import_file_filter; + bool *cart_temp_allowed; + RDStation *cart_station; + RDSystem *cart_system; + RDConfig *cart_config; + QString cart_user_name; + QString cart_user_password; + RDBusyDialog *cart_busy_dialog; +#ifndef WIN32 + RDSimplePlayer *cart_player; +#endif // WIN32 +}; + + +#endif diff --git a/lib/rdcart_search_text.cpp b/lib/rdcart_search_text.cpp new file mode 100644 index 00000000..89a5efb6 --- /dev/null +++ b/lib/rdcart_search_text.cpp @@ -0,0 +1,176 @@ +// rdcart_search_text.cpp +// +// Generates a standardized SQL 'WHERE' clause for filtering Rivendell carts. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcart_search_text.cpp,v 1.21.4.2 2013/12/11 20:54:15 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdescape_string.h> +#include <rdcart_search_text.h> +#include <rddb.h> + +QString RDBaseSearchText(QString filter,bool incl_cuts) +{ +QString edit_filter=filter; +QString return_string=""; +QString search_string=""; +int pos=0; +char find; + +edit_filter=edit_filter.stripWhiteSpace(); +if(edit_filter.isEmpty()) { + return_string=QString().sprintf(" ((CART.TITLE like \"%%%s%%\")||\ + (CART.ARTIST like \"%%%s%%\")||(CART.CLIENT like \"%%%s%%\")||\ + (CART.AGENCY like \"%%%s%%\")||(CART.ALBUM like \"%%%s%%\")||\ + (CART.LABEL like \"%%%s%%\")||(CART.NUMBER like \"%%%s%%\")||\ + (CART.PUBLISHER like \"%%%s%%\")||(CART.COMPOSER like \"%%%s%%\")||\ + (CART.CONDUCTOR like \"%%%s%%\")||(CART.SONG_ID like \"%%%s%%\")||\ + (CART.USER_DEFINED like \"%%%s%%\")", + (const char *)search_string.utf8(), + (const char *)search_string.utf8(), + (const char *)search_string.utf8(), + (const char *)search_string.utf8(), + (const char *)search_string.utf8(), + (const char *)search_string.utf8(), + (const char *)search_string.utf8(), + (const char *)search_string.utf8(), + (const char *)search_string.utf8(), + (const char *)search_string.utf8(), + (const char *)search_string.utf8(), + (const char *)search_string.utf8()); + if(incl_cuts) { + return_string+=QString().sprintf("||(CUTS.ISCI like \"%%%s%%\")\ + ||(CUTS.ISRC like \"%%%s%%\")\ + ||(CUTS.DESCRIPTION like \"%%%s%%\")\ + ||(CUTS.OUTCUE like \"%%%s%%\")", + (const char *)search_string.utf8(), + (const char *)search_string.utf8(), + (const char *)search_string.utf8(), + (const char *)search_string.utf8()); + } + return_string+=")"; + } +else { + while(!edit_filter.isEmpty()) { + if(edit_filter.startsWith("\"") && edit_filter.length()>1) { + edit_filter=edit_filter.remove(0,1); + find='\"'; + } + else { + find=' '; + } + pos=edit_filter.find(find); + if(pos>=0) { + search_string=edit_filter.left(pos); + edit_filter=edit_filter.remove(0,pos); + if(find=='\"') { + edit_filter=edit_filter.remove(0,1); + } + edit_filter=edit_filter.stripWhiteSpace(); + } + else { + search_string=edit_filter; + edit_filter=edit_filter.remove(0,edit_filter.length()); + } + if(!return_string.isEmpty()) { + return_string=return_string+" AND "; + } + QString search=RDEscapeString(search_string); + return_string=return_string+QString().sprintf(" ((CART.TITLE like \"%%%s%%\")||\ + (CART.ARTIST like \"%%%s%%\")||(CART.CLIENT like \"%%%s%%\")|| \ + (CART.AGENCY like \"%%%s%%\")||(CART.ALBUM like \"%%%s%%\")|| \ + (CART.LABEL like \"%%%s%%\")||(CART.NUMBER like \"%%%s%%\")|| \ + (CART.PUBLISHER like \"%%%s%%\")||(CART.COMPOSER like \"%%%s%%\")|| \ + (CART.CONDUCTOR like \"%%%s%%\")||(CART.SONG_ID like \"%%%s%%\")|| \ + (CART.USER_DEFINED like \"%%%s%%\")", + (const char *)search.utf8(), + (const char *)search.utf8(), + (const char *)search.utf8(), + (const char *)search.utf8(), + (const char *)search.utf8(), + (const char *)search.utf8(), + (const char *)search.utf8(), + (const char *)search.utf8(), + (const char *)search.utf8(), + (const char *)search.utf8(), + (const char *)search.utf8(), + (const char *)search.utf8()); + if(incl_cuts) { + return_string+=QString().sprintf("||(CUTS.ISCI like \"%%%s%%\")\ + ||(CUTS.ISRC like \"%%%s%%\")\ + ||(CUTS.DESCRIPTION like \"%%%s%%\")\ + ||(CUTS.OUTCUE like \"%%%s%%\")", + (const char *)search.utf8(), + (const char *)search.utf8(), + (const char *)search.utf8(), + (const char *)search.utf8()); + } + return_string+=")"; + } + + } + return return_string; +} + + +QString RDCartSearchText(QString filter,const QString &group, + const QString &schedcode,bool incl_cuts) +{ + QString ret=QString(" ")+RDBaseSearchText(filter,incl_cuts); + if(!group.isEmpty()) { + ret+=QString("&&(CART.GROUP_NAME=\"")+RDEscapeString(group)+"\")"; + } + + if(!schedcode.isEmpty()) { + QString code=schedcode+" "; + code=code.left(11); + ret+=QString().sprintf("&&(SCHED_CODES like \"%%%s%%\")", + (const char *)code); + } + return ret.utf8(); +} + + +QString RDAllCartSearchText(const QString &filter,const QString &schedcode, + const QString &user,bool incl_cuts) +{ + QString sql; + RDSqlQuery *q; + QString search="("; + + sql=QString().sprintf("select GROUP_NAME from USER_PERMS\ + where USER_NAME=\"%s\"", + (const char *)user); + q=new RDSqlQuery(sql); + while(q->next()) { + search+=QString().sprintf("(CART.GROUP_NAME=\"%s\")||", + (const char *)q->value(0).toString()); + } + delete q; + search=search.left(search.length()-2)+QString(")"); + search+=QString("&&")+RDBaseSearchText(filter,incl_cuts); + + if(!schedcode.isEmpty()) { + QString code=schedcode+" "; + code=code.left(11); + search+=QString().sprintf("&&(SCHED_CODES like \"%%%s%%\")", + (const char *)code); + } + + return search; +} diff --git a/lib/rdcart_search_text.h b/lib/rdcart_search_text.h new file mode 100644 index 00000000..026439c6 --- /dev/null +++ b/lib/rdcart_search_text.h @@ -0,0 +1,37 @@ +// rdcart_search_text.h +// +// Generates a standardized SQL 'WHERE' clause for filtering Rivendell carts. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcart_search_text.h,v 1.10.4.1 2012/10/09 00:12:29 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCART_SEARCH_TEXT_H +#define RDCART_SEARCH_TEXT_H + +#include <qstring.h> + +#include <rdstation.h> + + +QString RDCartSearchText(QString filter,const QString &group, + const QString &schedcode,bool incl_cuts); +QString RDAllCartSearchText(const QString &filter,const QString &schedcode, + const QString &user,bool incl_cuts); + + +#endif diff --git a/lib/rdcartdrag.cpp b/lib/rdcartdrag.cpp new file mode 100644 index 00000000..9f8ad643 --- /dev/null +++ b/lib/rdcartdrag.cpp @@ -0,0 +1,141 @@ +// rdcartdrag.cpp +// +// Stored value drag object for Rivendell carts. +// +// (C) Copyright 2013 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcartdrag.cpp,v 1.1.2.7 2014/01/20 19:13:29 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <string.h> + +#include <qstringlist.h> + +#include <rd.h> +#include <rdcart.h> +#include <rdcartdrag.h> +#include <rdprofile.h> + +// +// Icons +// +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" +#include "../icons/trashcan-16x16.xpm" + +RDCartDrag::RDCartDrag(unsigned cartnum,const QPixmap *icon,QWidget *src) + : QStoredDrag(RDMIMETYPE_CART,src) +{ + SetData(cartnum,QColor(),QString()); + if(icon==NULL) { + RDCart *cart=new RDCart(cartnum); + switch(cart->type()) { + case RDCart::Audio: + setPixmap(QPixmap(play_xpm)); + break; + + case RDCart::Macro: + setPixmap(QPixmap(rml5_xpm)); + break; + + case RDCart::All: + break; + } + delete cart; + } + else { + setPixmap(*icon); + } +} + + +RDCartDrag::RDCartDrag(unsigned cartnum,const QString &title, + const QColor &color,QWidget *src) + : QStoredDrag(RDMIMETYPE_CART,src) +{ + SetData(cartnum,color,title); + if(cartnum==0) { + setPixmap(QPixmap(trashcan_xpm)); + } + else { + RDCart *cart=new RDCart(cartnum); + switch(cart->type()) { + case RDCart::Audio: + setPixmap(QPixmap(play_xpm)); + break; + + case RDCart::Macro: + setPixmap(QPixmap(rml5_xpm)); + break; + + case RDCart::All: + break; + } + delete cart; + } +} + + +bool RDCartDrag::canDecode(QMimeSource *e) +{ + return e->provides(RDMIMETYPE_CART); +} + + +bool RDCartDrag::decode(QMimeSource *e,unsigned *cartnum,QColor *color, + QString *title) +{ + RDProfile *p=new RDProfile(); + p->setSourceString(e->encodedData(RDMIMETYPE_CART)); + *cartnum=p->intValue("Rivendell-Cart","Number"); + if(color!=NULL) { + color->setNamedColor(p->stringValue("Rivendell-Cart","Color")); + } + if(title!=NULL) { + *title=p->stringValue("Rivendell-Cart","ButtonText"); + } + + return true; +} + + +bool RDCartDrag::decode(QMimeSource *e,RDLogLine *ll, + RDLogLine::TransType next_trans,int log_mach, + bool timescale,RDLogLine::TransType trans) +{ + unsigned cartnum; + + RDCartDrag::decode(e,&cartnum); + ll->loadCart(cartnum,next_trans,log_mach,timescale,trans); + + return true; +} + + +void RDCartDrag::SetData(unsigned cartnum,const QColor &color,const QString &title) +{ + QString str="[Rivendell-Cart]\n"; + str+="Number="+QString().sprintf("%06u",cartnum)+"\n"; + if(color.isValid()) { + str+="Color="+color.name()+"\n"; + } + if(!title.isEmpty()) { + str+="ButtonText="+title+"\n"; + } + QByteArray data(str.length()); + data.duplicate(str,str.length()); + setEncodedData(data); +} diff --git a/lib/rdcartdrag.h b/lib/rdcartdrag.h new file mode 100644 index 00000000..f8dce839 --- /dev/null +++ b/lib/rdcartdrag.h @@ -0,0 +1,52 @@ +// rdcartdrag.h +// +// Stored value drag object for Rivendell carts. +// +// (C) Copyright 2013 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcartdrag.h,v 1.1.2.4 2014/01/20 19:13:29 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCARTDRAG_H +#define RDCARTDRAG_H + +#include <qcolor.h> +#include <qdragobject.h> +#include <qpixmap.h> + +#include <rdcart.h> +#include <rdlog_line.h> + +class RDCartDrag : public QStoredDrag +{ + public: + RDCartDrag(unsigned cartnum,const QPixmap *icon,QWidget *src=0); + RDCartDrag(unsigned cartnum,const QString &title,const QColor &color, + QWidget *src=0); + static bool canDecode(QMimeSource *e); + static bool decode(QMimeSource *e,unsigned *cartnum,QColor *color=NULL, + QString *title=NULL); + static bool decode(QMimeSource *e,RDLogLine *ll, + RDLogLine::TransType next_trans=RDLogLine::Segue, + int log_mach=0,bool timescale=false, + RDLogLine::TransType trans=RDLogLine::NoTrans); + + private: + void SetData(unsigned cartnum,const QColor &color,const QString &title); +}; + + +#endif // RDCARTDRAG_H diff --git a/lib/rdcartslot.cpp b/lib/rdcartslot.cpp new file mode 100644 index 00000000..19b9944d --- /dev/null +++ b/lib/rdcartslot.cpp @@ -0,0 +1,727 @@ +// rdcartslot.cpp +// +// The cart slot widget. +// +// (C) Copyright 2012-2014 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcartslot.cpp,v 1.13.2.19.2.2 2014/06/24 18:27:03 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qpainter.h> +#include <qbitmap.h> + +#include "rdconfig.h" +#include "rdconf.h" +#include "rdescape_string.h" +#include "rdcart.h" +#include "rdcartslot.h" + +RDCartSlot::RDCartSlot(int slotnum,RDRipc *ripc,RDCae *cae,RDStation *station, + RDConfig *config,RDListSvcs *svcs_dialog, + RDSlotDialog *slot_dialog,RDCartDialog *cart_dialog, + RDCueEditDialog *cue_dialog, + const QString &caption,RDAirPlayConf *conf, + QWidget *parent) + : QWidget(parent) +{ + slot_number=slotnum; + slot_ripc=ripc; + slot_cae=cae; + slot_station=station; + slot_config=config; + slot_svcs_dialog=svcs_dialog; + slot_slot_dialog=slot_dialog; + slot_cart_dialog=cart_dialog; + slot_cue_dialog=cue_dialog; + slot_caption=caption; + slot_airplay_conf=conf; + + slot_svc_names=NULL; + slot_stop_requested=false; + slot_logline=new RDLogLine(); + slot_pause_enabled=false; + slot_user=NULL; + slot_svcname=""; + slot_breakaway_cart=0; + slot_breakaway_length=0; + slot_timescaling_active=false; + slot_temp_cart=false; + + // + // Fonts + // + QFont big_font("helvetica",36,QFont::Bold); + big_font.setPixelSize(36); + QFont mid_font("helvetica",14,QFont::Bold); + mid_font.setPixelSize(14); + + // + // Palettes + // + slot_ready_color= + QPalette(QColor(BUTTON_STOPPED_BACKGROUND_COLOR),backgroundColor()); + slot_playing_color= + QPalette(QColor(BUTTON_PLAY_BACKGROUND_COLOR),backgroundColor()); + + // + // Slot Options + // + slot_options=new RDSlotOptions(station->name(),slotnum); + slot_options->load(); + + // + // Play Deck + // + slot_deck=new RDPlayDeck(slot_cae,0,this); + connect(slot_deck,SIGNAL(stateChanged(int,RDPlayDeck::State)), + this,SLOT(stateChangedData(int,RDPlayDeck::State))); + connect(slot_deck,SIGNAL(position(int,int)), + this,SLOT(positionData(int,int))); + connect(slot_deck,SIGNAL(hookEnd(int)),this,SLOT(hookEndData(int))); + connect(slot_cae,SIGNAL(timescalingSupported(int,bool)), + this,SLOT(timescalingSupportedData(int,bool))); + + // + // Start Button + // + slot_start_button=new QPushButton(QString().sprintf("%d",slotnum+1),this); + slot_start_button->setGeometry(0,0,sizeHint().height(),sizeHint().height()); + slot_start_button->setFont(big_font); + slot_start_button->setDisabled(true); + connect(slot_start_button,SIGNAL(clicked()),this,SLOT(startData())); + + // + // Slot Box + // + slot_box=new RDSlotBox(slot_deck,conf,this); + slot_box->setBarMode(false); + slot_box->setAllowDrags(station->enableDragdrop()); + slot_box->setAcceptDrops(station->enableDragdrop()); + slot_box->setGeometry(5+sizeHint().height(),0, + slot_box->sizeHint().width(), + slot_box->sizeHint().height()); + connect(slot_box,SIGNAL(doubleClicked()),this,SLOT(doubleClickedData())); + connect(slot_box,SIGNAL(cartDropped(unsigned)), + this,SLOT(cartDroppedData(unsigned))); + + // + // Load Button + // + slot_load_button=new QPushButton(tr("Load"),this); + slot_load_button-> + setGeometry(sizeHint().height()+5+slot_box->sizeHint().width()+5,0, + sizeHint().height(),sizeHint().height()); + slot_load_button->setFont(mid_font); + connect(slot_load_button,SIGNAL(clicked()),this,SLOT(loadData())); + + // + // Options Button + // + slot_options_button=new QPushButton(this); + slot_options_button-> + setGeometry(2*sizeHint().height()+10+slot_box->sizeHint().width()+5,0, + sizeHint().height(),sizeHint().height()); + slot_options_button->setFont(mid_font); + connect(slot_options_button,SIGNAL(clicked()),this,SLOT(optionsData())); + + updateOptions(); + InitializeOptions(); +} + + +RDCartSlot::~RDCartSlot() +{ + stop(); + ClearTempCart(); + delete slot_logline; + delete slot_options; +} + + +QSize RDCartSlot::sizeHint() const +{ + return QSize(670,86); +} + + +QSizePolicy RDCartSlot::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDCartSlot::setUser(RDUser *user) +{ + slot_user=user; +} + + +RDSlotOptions *RDCartSlot::slotOptions() const +{ + return slot_options; +} + + +void RDCartSlot::updateOptions() +{ + slot_deck->setCard(slot_options->card()); + slot_deck->setPort(slot_options->outputPort()); + switch(slot_options->mode()) { + case RDSlotOptions::CartDeckMode: + SetInput(false); + slot_logline->setHookMode(slot_options->hookMode()); + if(slot_options->hookMode()) { + slot_options_button->setText(tr("Options")+"\n"+tr("[Hook]")); + } + else { + slot_options_button->setText(tr("Options")+"\n"+tr("[Full]")); + } + + break; + + case RDSlotOptions::BreakawayMode: + SetInput(true); + slot_start_button->setDisabled(true); + slot_box->setService(slot_svcname); + slot_box->setStatusLine(tr("Waiting for break...")); + slot_load_button->setText(tr("Load")); + slot_logline->setHookMode(false); + slot_options_button->setText(tr("Options")+"\n"+tr("[Breakaway]")); + break; + + case RDSlotOptions::LastMode: + break; + } + slot_box->setMode(slot_options->mode()); + slot_options->save(); + if(slot_logline->cartNumber()!=0) { + load(slot_logline->cartNumber()); + } +} + + +void RDCartSlot::setSvcNames(std::vector<QString> *svcnames) +{ + slot_svc_names=svcnames; +} + + +void RDCartSlot::setCart(RDCart *cart,int break_len) +{ + if(cart==NULL) { + slot_logline->clear(); + if(slot_options->mode()!=RDSlotOptions::BreakawayMode) { + slot_logline->setHookMode(slot_options->hookMode()); + } + slot_box->clear(); + } + else { + slot_logline->loadCart(cart->number(),RDLogLine::Play,0,true, + RDLogLine::NoTrans,break_len); + slot_logline-> + setEvent(0,RDLogLine::Play,slot_logline->timescalingActive(),break_len); + slot_box->setCart(slot_logline); + slot_box->setBarMode(false); + } +} + + +bool RDCartSlot::load(int cartnum,int break_len) +{ + bool ret=false; + RDCart *cart=new RDCart(cartnum); + if(cart->exists()) { + if(slot_deck->state()!=RDPlayDeck::Stopped) { + stop(); + } + setCart(cart,break_len); + slot_start_button-> + setEnabled(slot_options->mode()==RDSlotOptions::CartDeckMode); + slot_start_button->setPalette(slot_ready_color); + slot_load_button->setText(tr("Unload")); + slot_options->setCartNumber(cartnum); + slot_options->save(); + ret=true; + } + delete cart; + return ret; +} + + +void RDCartSlot::unload() +{ + if(slot_deck->state()==RDPlayDeck::Stopped) { + ClearTempCart(); + setCart(NULL); + slot_start_button->setDisabled(true); + slot_start_button->setPalette(palette()); + slot_load_button->setText(tr("Load")); + slot_options->setCartNumber(0); + slot_options->save(); + } +} + + +bool RDCartSlot::play() +{ + bool ret=false; + if(slot_logline->cartNumber()!=0) { + if(slot_deck->setCart(slot_logline,true)) { + if(slot_options->hookMode()&&(slot_logline->hookStartPoint()>=0)) { + slot_deck->playHook(); + } + else { + slot_deck->play(slot_logline->playPosition()); + } + slot_logline->setStartTime(RDLogLine::Actual,QTime::currentTime()); + // LogPlayout(RDAirPlayConf::TrafficStart); + ret=true; + } + } + return ret; +} + + +bool RDCartSlot::pause() +{ + return false; +} + + +bool RDCartSlot::stop() +{ + bool ret=false; + if(slot_logline->cartNumber()!=0) { + slot_stop_requested=true; + slot_deck->stop(); + // LogPlayout(RDAirPlayConf::TrafficStop); + ret=true; + } + return ret; +} + + +bool RDCartSlot::breakAway(unsigned msecs) +{ + bool ret=false; + unsigned cartnum=0; + + if(slot_options->mode()==RDSlotOptions::BreakawayMode) { + if(msecs==0) { + stop(); + SetInput(true); + unload(); + slot_box->setService(slot_svcname); + slot_box->setStatusLine(tr("Waiting for break...")); + } + else { + cartnum=SelectCart(slot_svcname,msecs); + if(cartnum!=0) { + switch(slot_deck->state()) { + case RDPlayDeck::Playing: + case RDPlayDeck::Paused: + case RDPlayDeck::Stopping: + slot_breakaway_cart=cartnum; + slot_breakaway_length=msecs; + stop(); + break; + + case RDPlayDeck::Stopped: + case RDPlayDeck::Finished: + SetInput(false); + if(slot_timescaling_active) { + load(cartnum,msecs); + } + else { + load(cartnum); + } + play(); + syslog(LOG_INFO,"started breakaway, len: %u cart: %u cut: %d", + msecs,cartnum,slot_logline->cutNumber()); + break; + } + } + else { + slot_box->setStatusLine(tr("No cart found for length")+" "+ + RDGetTimeLength(msecs,false,false)); + } + } + } + return ret; +} + + +bool RDCartSlot::pauseEnabled() const +{ + return slot_pause_enabled; +} + + +void RDCartSlot::setPauseEnabled(bool state) +{ + slot_pause_enabled=state; +} + + +void RDCartSlot::updateMeters() +{ + short lvls[2]; + + switch(slot_deck->state()) { + case RDPlayDeck::Playing: + case RDPlayDeck::Stopping: + slot_cae-> + outputStreamMeterUpdate(slot_deck->card(),slot_deck->stream(),lvls); + slot_box->updateMeters(lvls); + break; + + case RDPlayDeck::Paused: + case RDPlayDeck::Stopped: + case RDPlayDeck::Finished: + break; + } +} + + +void RDCartSlot::startData() +{ + switch(slot_deck->state()) { + case RDPlayDeck::Playing: + case RDPlayDeck::Stopping: + case RDPlayDeck::Paused: + stop(); + break; + + case RDPlayDeck::Stopped: + case RDPlayDeck::Finished: + play(); + break; + } +} + + +void RDCartSlot::doubleClickedData() +{ + if(slot_logline->cartNumber()==0) { + loadData(); + } + else { + if(slot_cue_dialog->exec(slot_logline)==0) { + slot_box->setBarMode(true); + slot_box->setCart(slot_logline); + } + } +} + + +void RDCartSlot::loadData() +{ + int cartnum; + QString svcname; + + switch(slot_options->mode()) { + case RDSlotOptions::CartDeckMode: + cartnum=slot_logline->cartNumber(); + if(cartnum==0) { + if(slot_cart_dialog->exec(&cartnum,RDCart::All,&svcname,0, + slot_user->name(),slot_user->password(), + &slot_temp_cart)==0) { + load(cartnum); + } + } + else { + unload(); + } + break; + + case RDSlotOptions::BreakawayMode: + if(slot_svcs_dialog->exec(&slot_svcname)==0) { + slot_box->setService(slot_svcname); + slot_box->setStatusLine(tr("Waiting for break...")); + } + break; + + case RDSlotOptions::LastMode: + break; + } +} + + +void RDCartSlot::optionsData() +{ + RDSlotOptions::Mode old_mode=slot_options->mode(); + if(slot_slot_dialog->exec(slot_options)==0) { + if(old_mode!=slot_options->mode()) { + slot_box->clear(); + } + updateOptions(); + } +} + + +void RDCartSlot::stateChangedData(int id,RDPlayDeck::State state) +{ + //printf("stateChangedData(%d,%d)\n",id,state); + short lvls[2]={-10000,-10000}; + + switch(state) { + case RDPlayDeck::Playing: + LogPlayout(state); + slot_start_button-> + setEnabled(slot_options->mode()==RDSlotOptions::CartDeckMode); + slot_start_button->setPalette(slot_playing_color); + slot_load_button->setDisabled(true); + slot_options_button->setDisabled(true); + break; + + case RDPlayDeck::Stopped: + case RDPlayDeck::Finished: + LogPlayout(state); + slot_start_button-> + setEnabled(slot_options->mode()==RDSlotOptions::CartDeckMode); + slot_start_button->setPalette(slot_ready_color); + slot_load_button->setEnabled(true); + slot_options_button->setEnabled(true); + slot_box->setTimer(0); + slot_box->updateMeters(lvls); + slot_box->setCart(slot_logline); + switch(slot_options->mode()) { + case RDSlotOptions::CartDeckMode: + if(!slot_stop_requested) { + switch(slot_options->stopAction()) { + case RDSlotOptions::RecueOnStop: + break; + + case RDSlotOptions::UnloadOnStop: + unload(); + break; + + case RDSlotOptions::LoopOnStop: + play(); + break; + + case RDSlotOptions::LastStop: + break; + } + } + break; + + case RDSlotOptions::BreakawayMode: + if(slot_breakaway_cart>0) { + SetInput(false); + load(slot_breakaway_cart); + play(); + syslog(LOG_INFO,"started breakaway, len: %u cart: %u cut: %d", + slot_breakaway_length,slot_breakaway_cart, + slot_logline->cutNumber()); + slot_breakaway_cart=0; + slot_breakaway_length=0; + } + else { + SetInput(true); + unload(); + slot_box->setService(slot_svcname); + slot_box->setStatusLine(tr("Waiting for break...")); + // LogPlayout(RDAirPlayConf::TrafficFinish); + } + break; + + case RDSlotOptions::LastMode: + break; + } + slot_stop_requested=false; + break; + + case RDPlayDeck::Stopping: + case RDPlayDeck::Paused: + break; + } + +} + + +void RDCartSlot::positionData(int id,int msecs) +{ + slot_box->setTimer(msecs); +} + + +void RDCartSlot::hookEndData(int id) +{ + if(slot_options->hookMode()) { + stop(); + } +} + + +void RDCartSlot::timescalingSupportedData(int card,bool state) +{ + if(card==slot_options->card()) { + slot_timescaling_active=state; + } +} + + +void RDCartSlot::cartDroppedData(unsigned cartnum) +{ + if(cartnum==0) { + unload(); + } + else { + load(cartnum); + } +} + + +void RDCartSlot::InitializeOptions() +{ + slot_svcname=slot_options->service(); + + switch(slot_options->mode()) { + case RDSlotOptions::CartDeckMode: + if(slot_options->cartNumber()>0) { + load(slot_options->cartNumber()); + } + break; + + case RDSlotOptions::BreakawayMode: + slot_box->setService(slot_svcname); + slot_box->setStatusLine(tr("Waiting for break...")); + break; + + case RDSlotOptions::LastMode: + break; + } + slot_cae->requestTimescale(slot_options->card()); +} + + +unsigned RDCartSlot::SelectCart(const QString &svcname,unsigned msecs) +{ + QString sql; + RDSqlQuery *q; + unsigned cartnum=0; + int diff=1000000; + + sql=QString("select AUTOFILLS.CART_NUMBER,CART.FORCED_LENGTH from ")+ + "AUTOFILLS left join CART on AUTOFILLS.CART_NUMBER=CART.NUMBER"+ + QString(). + sprintf(" where (CART.FORCED_LENGTH>%u)&&(CART.FORCED_LENGTH<%u)&&", + (unsigned)((double)msecs*RD_TIMESCALE_MIN), + (unsigned)((double)msecs*RD_TIMESCALE_MAX))+ + "(SERVICE=\""+RDEscapeString(svcname)+"\")"; + q=new RDSqlQuery(sql); + while(q->next()) { + if(::abs(msecs-q->value(1).toInt())<diff) { + cartnum=q->value(0).toUInt(); + diff=::abs(msecs-q->value(1).toInt()); + } + } + delete q; + return cartnum; +} + + +void RDCartSlot::SetInput(bool state) +{ + int level=-10000; + if(state) { + level=0; + } + slot_cae-> + setPassthroughVolume(slot_options->card(),slot_options->inputPort(), + slot_options->outputPort(),level); +} + + +void RDCartSlot::LogPlayout(RDPlayDeck::State state) +{ + if(state==RDPlayDeck::Playing) { + RDCut *cut=new RDCut(slot_logline->cutName()); + cut->logPlayout(); + delete cut; + } + if((state!=RDPlayDeck::Stopped)&&(state!=RDPlayDeck::Finished)) { + return; + } + RDAirPlayConf::TrafficAction action=RDAirPlayConf::TrafficFinish; + if(state==RDPlayDeck::Stopped) { + action=RDAirPlayConf::TrafficStop; + } + QString sql; + RDSqlQuery *q; + QDateTime datetime=QDateTime(QDate::currentDate(),QTime::currentTime()); + int length= + slot_logline->startTime(RDLogLine::Actual).msecsTo(datetime.time()); + if(length<0) { // Event crossed midnight! + length+=86400000; + datetime.setDate(datetime.date().addDays(-1)); + } + QString svctablename=slot_svcname; + svctablename.replace(" ","_"); + sql=QString("insert into `")+svctablename+"_SRT` set "+ + QString().sprintf("LENGTH=%d,LOG_ID=%d,CART_NUMBER=%u,EVENT_TYPE=%d,\ + EVENT_SOURCE=%d,EXT_LENGTH=%d,PLAY_SOURCE=%d,\ + CUT_NUMBER=%d,USAGE_CODE=%d,START_SOURCE=%d,", + length, + slot_number+1, + slot_logline->cartNumber(), + action, + slot_logline->source(), + slot_logline->extLength(), + RDLogLine::CartSlot, + slot_logline->cutNumber(), + slot_logline->usageCode(), + slot_logline->startSource())+ + "STATION_NAME=\""+RDEscapeString(slot_station->name())+"\","+ + "EVENT_DATETIME=\""+datetime.toString("yyyy-MM-dd")+ + " "+slot_logline->startTime(RDLogLine::Actual).toString("hh:mm:ss")+"\","+ + "EXT_START_TIME=\""+slot_logline->extStartTime().toString("hh:mm:ss")+"\","+ + "EXT_DATA=\""+RDEscapeString(slot_logline->extData())+"\","+ + "EXT_EVENT_ID=\""+RDEscapeString(slot_logline->extEventId())+"\","+ + "EXT_ANNC_TYPE=\""+RDEscapeString(slot_logline->extAnncType())+"\","+ + "EXT_CART_NAME=\""+RDEscapeString(slot_logline->extCartName())+"\","+ + "TITLE=\""+RDEscapeString(slot_logline->title())+"\","+ + "ARTIST=\""+RDEscapeString(slot_logline->artist())+"\","+ + "SCHEDULED_TIME=\""+slot_logline->startTime(RDLogLine::Logged). + toString("hh:mm:ss")+"\","+ + "ISRC=\""+RDEscapeString(slot_logline->isrc())+"\","+ + "PUBLISHER=\""+RDEscapeString(slot_logline->publisher())+"\","+ + "COMPOSER=\""+RDEscapeString(slot_logline->composer())+"\","+ + "ONAIR_FLAG=\""+RDYesNo(slot_ripc->onairFlag())+"\","+ + "ALBUM=\""+RDEscapeString(slot_logline->album())+"\","+ + "LABEL=\""+RDEscapeString(slot_logline->label())+"\","+ + "CONDUCTOR=\""+RDEscapeString(slot_logline->conductor())+"\","+ + "USER_DEFINED=\""+RDEscapeString(slot_logline->userDefined())+"\","+ + "SONG_ID=\""+RDEscapeString(slot_logline->songId())+"\","+ + "ISCI=\""+RDEscapeString(slot_logline->isci())+"\""; + q=new RDSqlQuery(sql); + delete q; +} + +void RDCartSlot::ClearTempCart() +{ + RDCart *cart=NULL; + + if(slot_temp_cart) { + cart=new RDCart(slot_logline->cartNumber()); + if(cart->exists()) { + cart->remove(slot_station,slot_user,slot_config); + } + slot_temp_cart=false; + delete cart; + } +} diff --git a/lib/rdcartslot.h b/lib/rdcartslot.h new file mode 100644 index 00000000..2190967c --- /dev/null +++ b/lib/rdcartslot.h @@ -0,0 +1,135 @@ +// rdcartslot.h +// +// The cart slot widget. +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcartslot.h,v 1.8.2.11 2014/01/07 23:23:17 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCARTSLOT_H +#define RDCARTSLOT_H + +#include <vector> + +#include <qwidget.h> +#include <qdatetime.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qsignalmapper.h> + +#include <rdpushbutton.h> + +#include <rdcart_dialog.h> +#include <rdcart.h> +#include <rduser.h> +#include <rdlog_line.h> +#include <rdplay_deck.h> +#include <rdpanel_button.h> +#include <rdbutton_dialog.h> +#include <rdbutton_panel.h> +#include <rdripc.h> +#include <rdcombobox.h> +#include <rdsvc.h> +#include <rdslotbox.h> +#include <rdslotdialog.h> +#include <rdslotoptions.h> +#include <rdcueeditdialog.h> +#include <rdlistsvcs.h> +#include <rdairplay_conf.h> + +class RDCartSlot : public QWidget +{ + Q_OBJECT + public: + RDCartSlot(int slotnum,RDRipc *ripc,RDCae *cae,RDStation *station, + RDConfig *config,RDListSvcs *svcs_dialog,RDSlotDialog *slot_dialog, + RDCartDialog *cart_dialog,RDCueEditDialog *cue_dialog, + const QString &caption,RDAirPlayConf *conf,QWidget *parent=0); + ~RDCartSlot(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void setUser(RDUser *user); + RDSlotOptions *slotOptions() const; + void updateOptions(); + void setSvcNames(std::vector<QString> *svcnames); + void setCart(RDCart *cart,int break_len=-1); + bool load(int cartnum,int break_len=-1); + void unload(); + bool play(); + bool pause(); + bool stop(); + bool breakAway(unsigned msecs); + bool pauseEnabled() const; + void setPauseEnabled(bool state); + + public slots: + void updateMeters(); + + signals: + void tick(); + void buttonFlash(bool state); + void selectClicked(unsigned cartnum,int row,int col); + + private slots: + void startData(); + void doubleClickedData(); + void loadData(); + void optionsData(); + void stateChangedData(int id,RDPlayDeck::State state); + void positionData(int id,int msecs); + void hookEndData(int id); + void timescalingSupportedData(int card,bool state); + void cartDroppedData(unsigned cartnum); + + private: + void InitializeOptions(); + unsigned SelectCart(const QString &svcname,unsigned msecs); + void SetInput(bool state); + void LogPlayout(RDPlayDeck::State state); + void ClearTempCart(); + QPushButton *slot_start_button; + QPushButton *slot_load_button; + QPushButton *slot_options_button; + std::vector<QString> *slot_svc_names; + QString slot_svcname; + RDLogLine *slot_logline; + RDSlotOptions *slot_options; + RDPlayDeck *slot_deck; + bool slot_pause_enabled; + bool slot_stop_requested; + RDUser *slot_user; + RDSlotBox *slot_box; + RDRipc *slot_ripc; + RDCae *slot_cae; + RDStation *slot_station; + RDConfig *slot_config; + RDListSvcs *slot_svcs_dialog; + RDSlotDialog *slot_slot_dialog; + RDCartDialog *slot_cart_dialog; + RDCueEditDialog *slot_cue_dialog; + QString slot_caption; + QPalette slot_ready_color; + QPalette slot_playing_color; + int slot_number; + unsigned slot_breakaway_cart; + int slot_breakaway_length; + bool slot_timescaling_active; + bool slot_temp_cart; + RDAirPlayConf *slot_airplay_conf; +}; + +#endif // RDCARTSLOT_H diff --git a/lib/rdcastsearch.cpp b/lib/rdcastsearch.cpp new file mode 100644 index 00000000..cbeb08f3 --- /dev/null +++ b/lib/rdcastsearch.cpp @@ -0,0 +1,78 @@ +// rdcastsearch.cpp +// +// SQL search clause for RDCastManager +// +// (C) Copyright 2009 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcastsearch.cpp,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qstring.h> + +#include <rdescape_string.h> +#include <rdpodcast.h> +#include <rdcastsearch.h> + +QString RDCastSearchString(const QString &filter,bool unexp_only, + bool active_only) +{ + QString ret; + if(!filter.isEmpty()) { + ret+=QString().sprintf("&&((PODCASTS.ITEM_TITLE like \"%%%s%%\")||\ + (PODCASTS.ITEM_DESCRIPTION like \"%%%s%%\")||\ + (PODCASTS.ITEM_CATEGORY like \"%%%s%%\")||\ + (PODCASTS.ITEM_LINK like \"%%%s%%\")||\ + (PODCASTS.ITEM_COMMENTS like \"%%%s%%\")||\ + (PODCASTS.ITEM_AUTHOR like \"%%%s%%\")||\ + (PODCASTS.ITEM_SOURCE_TEXT like \"%%%s%%\")||\ + (PODCASTS.ITEM_SOURCE_URL like \"%%%s%%\"))", + (const char *)filter, + (const char *)filter, + (const char *)filter, + (const char *)filter, + (const char *)filter, + (const char *)filter, + (const char *)filter, + (const char *)filter); + } + if(unexp_only) { + ret+=QString().sprintf("&&(STATUS!=%d)",RDPodcast::StatusExpired); + } + if(active_only) { + ret+=QString().sprintf("&&(STATUS=%d)",RDPodcast::StatusActive); + } + return ret; +} + +QString RDCastSearch(int feed_id,const QString &filter,bool unexp_only, + bool active_only) +{ + QString ret=QString().sprintf("where (FEED_ID=%d)",feed_id); + ret+=RDCastSearchString(filter,unexp_only,active_only); + + return ret; +} + + +QString RDCastSearch(const QString &keyname,const QString &filter, + bool unexp_only,bool active_only) +{ + QString ret=QString().sprintf("where (KEY_NAME=\"%s\")", + (const char *)RDEscapeString(keyname)); + ret+=RDCastSearchString(filter,unexp_only,active_only); + + return ret; +} diff --git a/lib/rdcastsearch.h b/lib/rdcastsearch.h new file mode 100644 index 00000000..e1ebf177 --- /dev/null +++ b/lib/rdcastsearch.h @@ -0,0 +1,32 @@ +// rdcastsearch.h +// +// SQL search clause for RDCastManager +// +// (C) Copyright 2009 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcastsearch.h,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCASTSEARCH_H +#define RDCASTSEARCH_H + +QString RDCastSearch(int feed_id,const QString &filter,bool unexp_only, + bool active_only); +QString RDCastSearch(const QString &keyname,const QString &filter, + bool unexp_only,bool active_only); + + +#endif // RDCASTSEARCH_H diff --git a/lib/rdcatch_conf.cpp b/lib/rdcatch_conf.cpp new file mode 100644 index 00000000..a3a82cd8 --- /dev/null +++ b/lib/rdcatch_conf.cpp @@ -0,0 +1,86 @@ +// rdcatch_conf.cpp +// +// Abstract an RDCatch Configuration. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcatch_conf.cpp,v 1.8 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rddb.h> +#include <rdconf.h> +#include <rdcatch_conf.h> +#include <rdescape_string.h> + + +// +// Global Classes +// +RDCatchConf::RDCatchConf(const QString &station) +{ + RDSqlQuery *q; + QString sql; + + air_station=station; + + sql=QString(). + sprintf("select ID from RDCATCH where STATION=\"%s\"", + (const char *)air_station); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + sql=QString(). + sprintf("insert into RDCATCH set STATION=\"%s\"", + (const char *)air_station); + q=new RDSqlQuery(sql); + delete q; + } else { + delete q; + } +} + + +QString RDCatchConf::station() const +{ + return air_station; +} + + +QString RDCatchConf::errorRml() const +{ + return RDGetSqlValue("RDCATCH","STATION",air_station,"ERROR_RML").toString(); +} + + +void RDCatchConf::setErrorRml(const QString &str) const +{ + SetRow("ERROR_RML",str); +} + + +void RDCatchConf::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString(). + sprintf("UPDATE RDCATCH SET %s=\"%s\" WHERE STATION=\"%s\"", + (const char *)param, + (const char *)RDEscapeString(value), + (const char *)RDEscapeString(air_station)); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdcatch_conf.h b/lib/rdcatch_conf.h new file mode 100644 index 00000000..22306f05 --- /dev/null +++ b/lib/rdcatch_conf.h @@ -0,0 +1,43 @@ +// rdcatch_conf.h +// +// Abstract RDCatch Configuration +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcatch_conf.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCATCH_CONF_H +#define RDCATCH_CONF_H + +#include <qsqldatabase.h> + + +class RDCatchConf +{ + public: + RDCatchConf(const QString &station); + QString station() const; + QString errorRml() const; + void setErrorRml(const QString &str) const; + + private: + void SetRow(const QString ¶m,const QString &value) const; + QString air_station; +}; + + +#endif // RDCATCH_CONF_H diff --git a/lib/rdcatch_connect.cpp b/lib/rdcatch_connect.cpp new file mode 100644 index 00000000..10b92c10 --- /dev/null +++ b/lib/rdcatch_connect.cpp @@ -0,0 +1,364 @@ +// catch_connect.cpp +// +// Connect to the Rivendell Netcatcher Daemon. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcatch_connect.cpp,v 1.26 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <ctype.h> + +#include <qobject.h> + +#include <rdcatch_connect.h> + + +RDCatchConnect::RDCatchConnect(int serial,QObject *parent,const char *name) + : QObject(parent,name) +{ + cc_serial=serial; + + cc_connected=false; + argnum=0; + argptr=0; + for(int i=0;i<MAX_DECKS;i++) { + cc_monitor_state[i]=false; + } + + // + // TCP Connection + // + cc_socket=new QSocket(this,"cc_socket"); + connect(cc_socket,SIGNAL(connected()),this,SLOT(connectedData())); + connect(cc_socket,SIGNAL(error(int)),this,SLOT(errorData(int))); + connect(cc_socket,SIGNAL(readyRead()),this,SLOT(readyData())); + + // + // Start the heartbeat timer + // + cc_heartbeat_timer=new QTimer(this,"cc_heartbeat_timer"); + connect(cc_heartbeat_timer,SIGNAL(timeout()), + this,SLOT(heartbeatTimeoutData())); + cc_heartbeat_timer->start(CC_HEARTBEAT_INTERVAL,true); + cc_heartbeat_valid=true; +} + + +RDCatchConnect::~RDCatchConnect() +{ +// printf("Destroying RDCatchConnect\n"); +} + + +void RDCatchConnect::connectHost(QString hostname,Q_UINT16 hostport, + QString password) +{ + cc_password=password; + cc_socket->connectToHost(hostname,hostport); +} + + +RDDeck::Status RDCatchConnect::status(unsigned chan) const +{ + if(chan<=MAX_DECKS) { + return cc_record_deck_status[chan-1]; + } + return cc_play_deck_status[chan-128]; +} + + +int RDCatchConnect::currentId(unsigned chan) const +{ + if(chan<=MAX_DECKS) { + return cc_record_id[chan-1]; + } + return cc_play_id[chan-129]; +} + + +void RDCatchConnect::enableMetering(bool state) +{ + SendCommand(QString().sprintf("RM %d!",state)); +} + + +void RDCatchConnect::reloadHeartbeat() +{ + SendCommand("RH!"); +} + + +void RDCatchConnect::reloadDropboxes() +{ + SendCommand("RX!"); +} + + +void RDCatchConnect::addEvent(int id) +{ + SendCommand(QString().sprintf("RA %d!",id)); +} + + +void RDCatchConnect::removeEvent(int id) +{ + SendCommand(QString().sprintf("RR %d!",id)); +} + + +void RDCatchConnect::updateEvent(int id) +{ + SendCommand(QString().sprintf("RU %d!",id)); +} + + +void RDCatchConnect::reset() +{ + SendCommand("RS!"); +} + + +void RDCatchConnect::reload() +{ + SendCommand("RD!"); +} + + +void RDCatchConnect::refresh() +{ + SendCommand("RE 0!"); +} + + +void RDCatchConnect::reloadOffset() +{ + SendCommand("RO!"); +} + + +void RDCatchConnect::stop(int deck) +{ + SendCommand(QString().sprintf("SR %d!",deck)); +} + + +void RDCatchConnect::monitor(int deck,bool state) +{ + SendCommand(QString().sprintf("MN %d %d!",deck,state)); +} + + +void RDCatchConnect::toggleMonitor(int deck) +{ + if(cc_monitor_state[deck-1]) { + SendCommand(QString().sprintf("MN %d 0!",deck)); + } + else { + SendCommand(QString().sprintf("MN %d 1!",deck)); + } +} + + +void RDCatchConnect::setExitCode(int id,RDRecording::ExitCode code, + const QString &msg) +{ + SendCommand(QString().sprintf("SC %d %d %s!",id,code, + (const char *)msg.simplifyWhiteSpace())); +} + + +void RDCatchConnect::connectedData() +{ + SendCommand(QString().sprintf("PW %s!",(const char *)cc_password)); +} + + +void RDCatchConnect::errorData(int errorcode) +{ + fprintf(stderr,"RDCatchConnect: socket error %d\n",errorcode); +} + + +void RDCatchConnect::readyData() +{ + char buf[1024]; + int c; + + while((c=cc_socket->readBlock(buf,254))>0) { + buf[c]=0; + // printf("readyData: %s\n",buf); + for(int i=0;i<c;i++) { + if(buf[i]==' ') { + if(argnum<CC_MAX_ARGS) { + args[argnum][argptr]=0; + argnum++; + argptr=0; + } + else { + if(debug) { + printf("Argument list truncated!\n"); + } + } + } + if(buf[i]=='!') { + args[argnum++][argptr]=0; + DispatchCommand(); + argnum=0; + argptr=0; + if(cc_socket==NULL) { + return; + } + } + if((isgraph(buf[i]))&&(buf[i]!='!')) { + if(argptr<CC_MAX_LENGTH) { + args[argnum][argptr]=buf[i]; + argptr++; + } + else { + if(debug) { + printf("WARNING: argument truncated!\n"); + } + } + } + } + } +} + + +void RDCatchConnect::heartbeatTimeoutData() +{ + if(cc_heartbeat_valid) { + emit heartbeatFailed(cc_serial); + cc_heartbeat_valid=false; + } +} + + +void RDCatchConnect::SendCommand(QString cmd) +{ + // printf("SendCommand(%s)\n",(const char *)cmd); + cc_socket->writeBlock((const char *)cmd,cmd.length()); +} + + +void RDCatchConnect::DispatchCommand() +{ + int deck; + int channel; + int level; + unsigned chan; + int status; + int id; + + if(!strcmp(args[0],"PW")) { // Password Response + if(args[1][0]=='+') { + emit connected(cc_serial,true); + SendCommand("RE 0!"); + } + else { + emit connected(cc_serial,false); + } + } + + if(!strcmp(args[0],"RE")) { // Channel Status + if(sscanf(args[1],"%u",&chan)!=1){ + return; + } + if((chan<0)||((chan>(MAX_DECKS+1))&&(chan<(129)))|| + (chan>(MAX_DECKS+129))) { + return; + } + + if(sscanf(args[2],"%d",&status)!=1) { + return; + } + if(sscanf(args[3],"%d",&id)!=1) { + return; + } + if(chan==0) { + emit statusChanged(cc_serial,chan,(RDDeck::Status)status,id,""); + return; + } + chan--; + if(chan<=MAX_DECKS) { + if((status!=cc_record_deck_status[chan])||(id!=cc_record_id[chan])) { + cc_record_deck_status[chan]=(RDDeck::Status)status; + cc_record_id[chan]=id; + emit statusChanged(cc_serial,chan+1,cc_record_deck_status[chan], + cc_record_id[chan],args[4]); + } + } + if((chan>=128)&&(chan<MAX_DECKS+128)) { + if((status!=cc_play_deck_status[chan-128])||(id!=cc_play_id[chan-128])) { + cc_play_deck_status[chan-128]=(RDDeck::Status)status; + cc_play_id[chan-128]=id; + emit statusChanged(cc_serial,chan+1,cc_play_deck_status[chan-128], + cc_play_id[chan-128],args[4]); + } + } + return; + } + + if(!strcmp(args[0],"RM")) { // Meter Level + if(sscanf(args[1],"%d",&deck)!=1) { + return; + } + if(sscanf(args[2],"%d",&channel)!=1) { + return; + } + if(sscanf(args[3],"%d",&level)!=1) { + return; + } + emit meterLevel(cc_serial,deck,channel,level); + return; + } + + if(!strcmp(args[0],"RU")) { // Update Event + if(sscanf(args[1],"%d",&id)!=1) { + return; + } + emit eventUpdated(id); + } + + if(!strcmp(args[0],"PE")) { // Purge Event + if(sscanf(args[1],"%d",&id)!=1) { + return; + } + emit eventPurged(id); + } + + if(!strcmp(args[0],"HB")) { // Heartbeat + cc_heartbeat_timer->stop(); + cc_heartbeat_timer->start(CC_HEARTBEAT_INTERVAL,true); + } + + if(!strcmp(args[0],"MN")) { // Monitor State + if(sscanf(args[1],"%d",&deck)!=1) { + return; + } + if(args[2][0]=='1') { + cc_monitor_state[deck-1]=true; + emit monitorChanged(cc_serial,deck,true); + } + else { + cc_monitor_state[deck-1]=false; + emit monitorChanged(cc_serial,deck,false); + } + } +} + + diff --git a/lib/rdcatch_connect.h b/lib/rdcatch_connect.h new file mode 100644 index 00000000..730c921f --- /dev/null +++ b/lib/rdcatch_connect.h @@ -0,0 +1,104 @@ +// rdcatch_connect.h +// +// Connect to the Rivendell Netcatcher Daemon. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcatch_connect.h,v 1.19 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> +#include <qstring.h> +#include <qobject.h> +#include <qsocket.h> +#include <qlabel.h> + +#include <rd.h> +#include <rddeck.h> +#include <rdrecording.h> + +#ifndef RDCATCH_CONNECT_H +#define RDCATCH_CONNECT_H + +#define CC_MAX_ARGS 10 +#define CC_MAX_LENGTH 256 +#define CC_HEARTBEAT_INTERVAL 15000 + + +class RDCatchConnect : public QObject +{ + Q_OBJECT; + public: + RDCatchConnect(int serial,QObject *parent=0,const char *name=0); + ~RDCatchConnect(); + void connectHost(QString hostname,Q_UINT16 hostport,QString password); + RDDeck::Status status(unsigned chan) const; + int currentId(unsigned chan) const; + void enableMetering(bool state); + void reloadHeartbeat(); + void reloadDropboxes(); + + public slots: + void addEvent(int id); + void removeEvent(int id); + void updateEvent(int id); + void reset(); + void reload(); + void refresh(); + void reloadOffset(); + void stop(int deck); + void monitor(int deck,bool state); + void toggleMonitor(int deck); + void setExitCode(int id,RDRecording::ExitCode code,const QString &msg); + + signals: + void connected(int serial,bool state); + void statusChanged(int serial,unsigned channel,RDDeck::Status status, + int id,const QString &cutname); + void monitorChanged(int serial,unsigned channel,bool state); + void meterLevel(int serial,int deck,int chan,int level); + void eventUpdated(int id); + void eventPurged(int id); + void heartbeatFailed(int id); + + private slots: + void connectedData(); + void errorData(int errorcode); + void readyData(); + void heartbeatTimeoutData(); + + private: + void SendCommand(QString cmd); + void DispatchCommand(); + QSocket *cc_socket; + QString cc_password; + bool debug; + char args[CC_MAX_ARGS][CC_MAX_LENGTH]; + int argnum; + int argptr; + bool cc_connected; + RDDeck::Status cc_record_deck_status[MAX_DECKS]; + RDDeck::Status cc_play_deck_status[MAX_DECKS]; + int cc_record_id[MAX_DECKS]; + int cc_play_id[MAX_DECKS]; + int cc_serial; + QTimer *cc_heartbeat_timer; + bool cc_heartbeat_valid; + bool cc_monitor_state[MAX_DECKS]; +}; + + +#endif diff --git a/lib/rdcddblookup.cpp b/lib/rdcddblookup.cpp new file mode 100644 index 00000000..56c414b0 --- /dev/null +++ b/lib/rdcddblookup.cpp @@ -0,0 +1,433 @@ +// rdcddblookup.cpp +// +// A Qt class for accessing the FreeDB CD Database. +// +// (C) Copyright 2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcddblookup.cpp,v 1.5.8.3 2014/01/14 17:35:31 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <stdlib.h> +#include <string.h> +#include <qtimer.h> +#include <qregexp.h> +#include <qdatetime.h> + +#include <rdcddblookup.h> +#include <rdprofile.h> + +RDCddbLookup::RDCddbLookup(FILE *profile_msgs,QObject *parent,const char *name) + : QObject(parent,name) +{ + lookup_state=0; + lookup_profile_msgs=profile_msgs; + + // + // Get the Hostname + // + if(getenv("HOSTNAME")==NULL) { + lookup_hostname=RDCDDBLOOKUP_DEFAULT_HOSTNAME; + } + else { + lookup_hostname=getenv("HOSTNAME"); + } + + // + // Socket + // + lookup_socket=new QSocket(this,"lookup_socket"); + connect(lookup_socket,SIGNAL(readyRead()),this,SLOT(readyReadData())); + connect(lookup_socket,SIGNAL(error(int)),this,SLOT(errorData(int))); +} + + +RDCddbLookup::~RDCddbLookup() +{ + delete lookup_socket; +} + + +void RDCddbLookup::setCddbRecord(RDCddbRecord *rec) +{ + lookup_record=rec; +} + + +void RDCddbLookup::lookupRecord(const QString &cdda_dir,const QString &cdda_dev, + const QString &hostname,Q_UINT16 port, + const QString &username,const QString &appname, + const QString &appver) +{ + lookup_username=username; + lookup_appname=appname; + lookup_appver=appver; + + Profile("starting CD-TEXT lookup"); + if(!cdda_dir.isEmpty()) { + if(ReadCdText(cdda_dir,cdda_dev)) { + emit done(RDCddbLookup::ExactMatch); + Profile("CD-TEXT lookup success"); + return; + } + } + Profile("CD-TEXT lookup failure"); + + Profile("starting CDDB lookup"); + if(!hostname.isEmpty()) { + // + // Set Up Default User + // + if(lookup_username.isEmpty()) { + if(getenv("USER")==NULL) { + lookup_username=RDCDDBLOOKUP_DEFAULT_USER; + } + else { + lookup_username=getenv("USER"); + } + } + + // + // Get the Hostname + // + if(getenv("HOSTNAME")==NULL) { + lookup_hostname=RDCDDBLOOKUP_DEFAULT_HOSTNAME; + } + else { + lookup_hostname=getenv("HOSTNAME"); + } + lookup_socket->connectToHost(hostname,port); + } +} + + +bool RDCddbLookup::readIsrc(const QString &cdda_dir,const QString &cdda_dev) +{ + return ReadIsrcs(cdda_dir,cdda_dev); +} + + +void RDCddbLookup::readyReadData() +{ + QString line; + QString tag; + QString value; + int index; + int code; + char buffer[2048]; + char offset[256]; + int hex; + int start; + + while(lookup_socket->canReadLine()) { + line=lookup_socket->readLine(); + Profile("recevied from server: \""+line+"\""); + sscanf((const char *)line,"%d",&code); + switch(lookup_state) { + case 0: // Login Banner + if((code==200)||(code==201)) { + sprintf(buffer,"cddb hello %s %s %s %s", + (const char *)lookup_username, + (const char *)lookup_hostname, + (const char *)lookup_appname, + (const char *)lookup_appver); + SendToServer(buffer); + lookup_state=1; + } + else { + FinishCddbLookup(RDCddbLookup::ProtocolError); + } + break; + + case 1: // Handshake Response + if((code==200)||(code==402)) { + sprintf(buffer,"cddb query %08x %d", + lookup_record->discId(),lookup_record->tracks()); + for(int i=0;i<lookup_record->tracks();i++) { + sprintf(offset," %d",lookup_record->trackOffset(i)); + strcat(buffer,offset); + } + sprintf(offset," %d",lookup_record->discLength()/75); + strcat(buffer,offset); + SendToServer(buffer); + lookup_state=2; + } + else { + FinishCddbLookup(RDCddbLookup::ProtocolError); + } + break; + + case 2: // Query Response + switch(code) { + case 200: // Exact Match + start=4; + if(sscanf((const char *)line+start,"%s",offset)==1) { + lookup_record->setDiscGenre(offset); + start+=lookup_record->discGenre().length()+1; + } + if(sscanf((const char *)line+start,"%x",&hex)==1) { + lookup_record->setDiscId(hex); + start+=9; + } + lookup_record->setDiscTitle((const char *)line+start); + sprintf(buffer,"cddb read %s %08x\n", + (const char *)lookup_record->discGenre(), + lookup_record->discId()); + SendToServer(buffer); + lookup_state=3; + break; + + case 211: // Inexact Match + FinishCddbLookup(RDCddbLookup::PartialMatch); + break; + + default: + FinishCddbLookup(RDCddbLookup::ProtocolError); + break; + } + break; + + case 3: // Read Response + if((code==210)) { + lookup_state=4; + } + else { + FinishCddbLookup(RDCddbLookup::ProtocolError); + } + break; + + case 4: // Record Lines + if(line[0]!='#') { // Ignore Comments + if(line[0]=='.') { // Done + FinishCddbLookup(RDCddbLookup::ExactMatch); + } + ParsePair(&line,&tag,&value,&index); + if(tag=="DTITLE") { + lookup_record->setDiscTitle(value.left(value.length()-1)); + } + if(tag=="DYEAR") { + lookup_record->setDiscYear(value.toUInt()); + } + if(tag=="EXTD") { + lookup_record-> + setDiscExtended(lookup_record->discExtended()+ + DecodeString(value)); + } + if(tag=="PLAYORDER") { + lookup_record->setDiscPlayOrder(value); + } + if((tag=="TTITLE")&&(index!=-1)) { + lookup_record->setTrackTitle(index,value.left(value.length()-1)); + } + if((tag=="EXTT")&&(index!=-1)) { + lookup_record-> + setTrackExtended(index, + lookup_record->trackExtended(index)+value); + } + } + break; + } + } +} + + +void RDCddbLookup::errorData(int err) +{ + switch(err) { + case QSocket::ErrConnectionRefused: + printf("CDDB: Connection Refused!\n"); + break; + case QSocket::ErrHostNotFound: + printf("CDDB: Host Not Found!\n"); + break; + case QSocket::ErrSocketRead: + printf("CDDB: Socket Read Error!\n"); + break; + } + lookup_state=0; + emit done(RDCddbLookup::NetworkError); +} + + +void RDCddbLookup::FinishCddbLookup(RDCddbLookup::Result res) +{ + SendToServer("quit"); + lookup_socket->close(); + lookup_state=0; + emit done(res); + Profile("CDDB lookup finished"); +} + + +QString RDCddbLookup::DecodeString(QString &str) +{ + QString outstr; + QChar ch; + + for(unsigned i=0;i<str.length();i++) { + if((ch=str.at(i).latin1())=='\\') { + outstr+=QString("\n"); + i++; + } + else { + outstr+=QString(ch); + } + } + return outstr; +} + + +void RDCddbLookup::ParsePair(QString *line,QString *tag,QString *value, + int *index) +{ + for(unsigned i=0;i<line->length();i++) { + if(line->at(i)=='=') { + *tag=line->left(i); + *value=line->right(line->length()-i-1); + *value=value->left(value->length()-1); // Lose the silly linefeed + *index=GetIndex(tag); + return; + } + } +} + + +int RDCddbLookup::GetIndex(QString *tag) +{ + int index; + + for(unsigned i=0;i<tag->length();i++) { + if(tag->at(i).isDigit()) { + index=tag->right(tag->length()-i).toInt(); + *tag=tag->left(i); + return index; + } + } + return -1; +} + + +bool RDCddbLookup::ReadCdText(const QString &cdda_dir,const QString &cdda_dev) +{ + int err=0; + RDProfile *title_profile=new RDProfile(); + bool ret=false; + QString str; + QString cmd; + + // + // Write the Track Title Data to a Temp File + // + cmd=QString().sprintf("CURDIR=`pwd`;cd %s;cdda2wav -D %s --info-only -v titles 2> /dev/null;cd $CURDIR", + (const char *)cdda_dir, + (const char *)cdda_dev); + if((err=system(cmd))!=0) { + return false; + } + + // + // Read the Track Title Data File + // + for(int i=0;i<lookup_record->tracks();i++) { + title_profile->setSource(QString().sprintf("%s/audio_%02d.inf", + (const char *)cdda_dir,i+1)); + str=title_profile->stringValue("","Albumtitle",""); + str.remove("'"); + if((!str.isEmpty())&&(str!="''")) { + lookup_record->setDiscTitle(str); + ret=true; + } + + str=title_profile->stringValue("","Albumperformer",""); + str.remove("'"); + if((!str.isEmpty())&&(str!="''")) { + lookup_record->setDiscArtist(str); + ret=true; + } + + str=title_profile->stringValue("","Tracktitle",""); + str.remove("'"); + if((!str.isEmpty())&&(str!="''")) { + lookup_record->setTrackTitle(i,str); + ret=true; + } + + str=title_profile->stringValue("","Performer",""); + str.remove("'"); + if((!str.isEmpty())&&(str!="''")) { + lookup_record->setTrackArtist(i,str); + ret=true; + } + } + return ret; +} + + +bool RDCddbLookup::ReadIsrcs(const QString &cdda_dir,const QString &cdda_dev) +{ + int err=0; + RDProfile *title_profile=new RDProfile(); + RDProfile *isrc_profile=new RDProfile(); + bool ret=false; + QString str; + QString cmd; + + // + // Write the ISRC Data to a Temp File + // + cmd=QString().sprintf("CURDIR=`pwd`;cd %s;cdda2wav -D %s --info-only -v trackid 2> /dev/null;cd $CURDIR", + (const char *)cdda_dir, + (const char *)cdda_dev); + if((err=system(cmd))!=0) { + return false; + } + + // + // Read the ISRC Data File + // + for(int i=0;i<lookup_record->tracks();i++) { + isrc_profile->setSource(QString().sprintf("%s/audio_%02d.inf", + (const char *)cdda_dir,i+1)); + str=isrc_profile->stringValue("","ISRC",""); + str.remove("'"); + str.remove("-"); + if((!str.isEmpty())&&(str!="''")) { + lookup_record->setIsrc(i,str); + ret=true; + } + } + delete title_profile; + delete isrc_profile; + + return ret; +} + + +void RDCddbLookup::SendToServer(const QString &msg) +{ + lookup_socket->writeBlock(msg+"\n",msg.length()+1); + Profile("sent to server: \""+msg+"\""); +} + + +void RDCddbLookup::Profile(const QString &msg) +{ + if(lookup_profile_msgs!=NULL) { + printf("%s | RDCddbLookup::%s\n", + (const char *)QTime::currentTime().toString("hh:mm:ss.zzz"), + (const char *)msg); + } +} diff --git a/lib/rdcddblookup.h b/lib/rdcddblookup.h new file mode 100644 index 00000000..d5dbbced --- /dev/null +++ b/lib/rdcddblookup.h @@ -0,0 +1,91 @@ +// rdcddblookup.h +// +// A Qt class for accessing the FreeDB CD Database. +// +// (C) Copyright 2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcddblookup.h,v 1.3.8.2 2014/01/14 17:35:31 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDCDDBLOOKUP_H +#define RDCDDBLOOKUP_H + +#include <stdio.h> + +#include <qobject.h> +#include <qsocket.h> +#include <rdcddbrecord.h> + +// +// Default Settings +// +#define RDCDDBLOOKUP_DEFAULT_PORT 8880 +#define RDCDDBLOOKUP_DEFAULT_USER "libradio" +#define RDCDDBLOOKUP_DEFAULT_HOSTNAME "linux" + +/** + * @short Lookup CD Data from the FreeDB CD Database + * @author Fred Gleason <fredg@paravelsystems.com> + * + * This class implements an object for accessing a remote FreeDB CD + * database server. + **/ + +class RDCddbLookup : public QObject +{ + Q_OBJECT + public: + enum Result {ExactMatch=0,PartialMatch=1,NoMatch=2, + ProtocolError=3,NetworkError=4}; + RDCddbLookup(FILE *profile_msgs,QObject *parent=0,const char *name=0); + ~RDCddbLookup(); + void setCddbRecord(RDCddbRecord *); + void lookupRecord(const QString &cdda_dir,const QString &cdda_dev, + const QString &hostname, + Q_UINT16 port=RDCDDBLOOKUP_DEFAULT_PORT, + const QString &username="", + const QString &appname=PACKAGE_NAME, + const QString &ver=VERSION); + bool readIsrc(const QString &cdda_dir,const QString &cdda_dev); + + private slots: + void readyReadData(); + void errorData(int); + + signals: + void done(RDCddbLookup::Result); + + private: + void FinishCddbLookup(RDCddbLookup::Result res); + QString DecodeString(QString &str); + void ParsePair(QString *line,QString *tag,QString *value,int *index); + int GetIndex(QString *tag); + bool ReadCdText(const QString &cdda_dir,const QString &cdda_dev); + bool ReadIsrcs(const QString &cdda_dir,const QString &cdda_dev); + void SendToServer(const QString &msg); + void Profile(const QString &msg); + RDCddbRecord *lookup_record; + QSocket *lookup_socket; + int lookup_state; + QString lookup_username; + QString lookup_appname; + QString lookup_appver; + QString lookup_hostname; + FILE *lookup_profile_msgs; +}; + +#endif // RDCDDBLOOKUP_H diff --git a/lib/rdcddbrecord.cpp b/lib/rdcddbrecord.cpp new file mode 100644 index 00000000..405cbc60 --- /dev/null +++ b/lib/rdcddbrecord.cpp @@ -0,0 +1,281 @@ +// rdcddbrecord.cpp +// +// A Container Class for CDDB Data. +// +// (C) Copyright 2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcddbrecord.cpp,v 1.1 2007/09/14 14:06:24 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <rdcddbrecord.h> + +RDCddbRecord::RDCddbRecord() +{ + clear(); +} + + +void RDCddbRecord::clear() +{ + cddb_tracks=0; + cddb_disc_id=0; + cddb_disc_length=0; + cddb_disc_title=""; + cddb_disc_artist=""; + cddb_disc_album=""; + cddb_disc_author=""; + cddb_disc_year=0; + cddb_disc_genre=""; + cddb_disc_extended=""; + cddb_disc_playorder=""; + for(int i=0;i<CDROM_LEADOUT;i++) { + cddb_track_title[i]=""; + cddb_track_extended[i]=""; + cddb_track_artist[i]=""; + cddb_track_isrc[i]=""; + cddb_track_offset[i]=0; + } +} + + +int RDCddbRecord::tracks() const +{ + return cddb_tracks; +} + + +void RDCddbRecord::setTracks(int num) +{ + cddb_tracks=num; +} + + +unsigned RDCddbRecord::discLength() const +{ + return cddb_disc_length; +} + + +void RDCddbRecord::setDiscLength(unsigned len) +{ + cddb_disc_length=len; +} + + +unsigned RDCddbRecord::discId() const +{ + return cddb_disc_id; +} + + +void RDCddbRecord::setDiscId(unsigned id) +{ + cddb_disc_id=id; +} + + +QString RDCddbRecord::discTitle() const +{ + return cddb_disc_title; +} + + +void RDCddbRecord::setDiscTitle(QString title) +{ + int n; + + cddb_disc_title=title; + if((n=title.find(" / "))!=-1) { + cddb_disc_artist=title.left(n); + cddb_disc_album=title.right(title.length()-n-3); + cddb_disc_author=""; + } + else { + cddb_disc_album=title; + cddb_disc_artist=title; + cddb_disc_author=""; + } +} + + +QString RDCddbRecord::discArtist() const +{ + return cddb_disc_artist; +} + + +void RDCddbRecord::setDiscArtist(QString artist) +{ + cddb_disc_artist=artist; +} + + +QString RDCddbRecord::discAlbum() const +{ + return cddb_disc_album; +} + + +void RDCddbRecord::setDiscAlbum(QString album) +{ + cddb_disc_album=album; +} + + +QString RDCddbRecord::discAuthor() const +{ + return cddb_disc_author; +} + + +void RDCddbRecord::setDiscAuthor(QString author) +{ + cddb_disc_author=author; +} + + +unsigned RDCddbRecord::discYear() const +{ + return cddb_disc_year; +} + + +void RDCddbRecord::setDiscYear(unsigned year) +{ + cddb_disc_year=year; +} + + +QString RDCddbRecord::discGenre() const +{ + return cddb_disc_genre; +} + + +void RDCddbRecord::setDiscGenre(QString genre) +{ + cddb_disc_genre=genre; +} + + +QString RDCddbRecord::discExtended() const +{ + return cddb_disc_extended; +} + + +void RDCddbRecord::setDiscExtended(QString text) +{ + cddb_disc_extended=text; +} + + +QString RDCddbRecord::discPlayOrder() const +{ + return cddb_disc_playorder; +} + + +void RDCddbRecord::setDiscPlayOrder(QString order) +{ + cddb_disc_playorder=order; +} + + +unsigned RDCddbRecord::trackOffset(int track) const +{ + if(track<CDROM_LEADOUT) { + return cddb_track_offset[track]; + } + return 0; +} + + +void RDCddbRecord::setTrackOffset(int track,unsigned frames) +{ + if(track<CDROM_LEADOUT) { + cddb_track_offset[track]=frames; + } +} + + +QString RDCddbRecord::trackTitle(int track) const +{ + if(track<CDROM_LEADOUT) { + return cddb_track_title[track]; + } + return QString(); +} + + +void RDCddbRecord::setTrackTitle(int track,QString title) +{ + if(track<CDROM_LEADOUT) { + cddb_track_title[track]=title; + } +} + + +QString RDCddbRecord::trackExtended(int track) const +{ + if(track<CDROM_LEADOUT) { + return cddb_track_extended[track]; + } + return QString(); +} + + +void RDCddbRecord::setTrackExtended(int track,QString text) +{ + if(track<CDROM_LEADOUT) { + cddb_track_extended[track]=text; + } +} + + +QString RDCddbRecord::trackArtist(int track) const +{ + if(track<CDROM_LEADOUT) { + return cddb_track_artist[track]; + } + return QString(); +} + + +void RDCddbRecord::setTrackArtist(int track,QString artist) +{ + if(track<CDROM_LEADOUT) { + cddb_track_artist[track]=artist; + } +} + + +QString RDCddbRecord::isrc(int track) const +{ + if(track<CDROM_LEADOUT) { + return cddb_track_isrc[track]; + } + return QString(); +} + + +void RDCddbRecord::setIsrc(int track,QString isrc) +{ + if(track<CDROM_LEADOUT) { + cddb_track_isrc[track]=isrc; + } +} diff --git a/lib/rdcddbrecord.h b/lib/rdcddbrecord.h new file mode 100644 index 00000000..9bd4fdf6 --- /dev/null +++ b/lib/rdcddbrecord.h @@ -0,0 +1,99 @@ +// rdcddbrecord.h +// +// A Container Class for CDDB Data. +// +// (C) Copyright 2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcddbrecord.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDCDDBRECORD_H +#define RDCDDBRECORD_H + +#include <qstring.h> +#include <linux/cdrom.h> + + +/** + * @short A container class for CDDB data. + * @author Fred Gleason <fredg@paravelsystems.com> + **/ + +class RDCddbRecord +{ + public: + /** + * Create an RDCddbRecord object + **/ + RDCddbRecord(); + void clear(); + int tracks() const; + void setTracks(int num); + unsigned discLength() const; + void setDiscLength(unsigned len); + unsigned discId() const; + void setDiscId(unsigned id); + QString discTitle() const; + void setDiscTitle(QString title); + QString discArtist() const; + void setDiscArtist(QString artist); + QString discAlbum() const; + void setDiscAlbum(QString album); + QString discAuthor() const; + void setDiscAuthor(QString author); + unsigned discYear() const; + void setDiscYear(unsigned year); + QString discGenre() const; + void setDiscGenre(QString genre); + QString discExtended() const; + void setDiscExtended(QString text); + QString discPlayOrder() const; + void setDiscPlayOrder(QString order); + unsigned trackOffset(int track) const; + void setTrackOffset(int track,unsigned frames); + QString trackTitle(int track) const; + void setTrackTitle(int track,QString title); + QString trackExtended(int track) const; + void setTrackExtended(int track,QString text); + QString trackArtist(int track) const; + void setTrackArtist(int track,QString artist); + QString isrc(int track) const; + void setIsrc(int track,QString isrc); + QString mcn(int track) const; + void setMcn(int track,QString mcn); + + private: + int cddb_tracks; + unsigned cddb_disc_id; + unsigned cddb_disc_length; + QString cddb_disc_title; + QString cddb_disc_artist; + QString cddb_disc_album; + QString cddb_disc_author; + unsigned cddb_disc_year; + QString cddb_disc_genre; + QString cddb_disc_extended; + QString cddb_disc_playorder; + QString cddb_track_title[CDROM_LEADOUT]; + QString cddb_track_extended[CDROM_LEADOUT]; + QString cddb_track_artist[CDROM_LEADOUT]; + QString cddb_track_isrc[CDROM_LEADOUT]; + unsigned cddb_track_offset[CDROM_LEADOUT]; +}; + + +#endif // RDCDDBRECORD_H diff --git a/lib/rdcdplayer.cpp b/lib/rdcdplayer.cpp new file mode 100644 index 00000000..be97848c --- /dev/null +++ b/lib/rdcdplayer.cpp @@ -0,0 +1,555 @@ +// rdcdplayer.cpp +// +// Abstract a Linux CDROM Device. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcdplayer.cpp,v 1.5.2.2 2014/01/10 18:52:24 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <errno.h> +#include <linux/cdrom.h> + +#include <qdatetime.h> + +#include <rdcdplayer.h> + + +RDCdPlayer::RDCdPlayer(FILE *profile_msgs,QWidget *parent,const char *name) + : QObject(parent,name) +{ + cdrom_profile_msgs=profile_msgs; + cdrom_fd=-1; + cdrom_track_count=0; + cdrom_track_start=NULL; + cdrom_audio_track=NULL; + cdrom_play_mode=RDCdPlayer::Single; + cdrom_old_state=false; + cdrom_audiostatus=0; + + // + // The Button Timer + // + cdrom_button_timer=new QTimer(this,"cdrom_button_timer"); + connect(cdrom_button_timer,SIGNAL(timeout()),this,SLOT(buttonTimerData())); + + // + // The Clock + // + cdrom_clock=new QTimer(this,"cdrom_clock"); + connect(cdrom_clock,SIGNAL(timeout()),this,SLOT(clockData())); + cdrom_clock->start(RDCDPLAYER_CLOCK_INTERVAL,true); +} + + +RDCdPlayer::~RDCdPlayer() +{ + if(cdrom_fd>0) { + close(); + } + if(cdrom_track_start!=NULL) { + delete cdrom_track_start; + } + if(cdrom_audio_track!=NULL) { + delete cdrom_audio_track; + } + delete cdrom_clock; + delete cdrom_button_timer; +} + + +QString RDCdPlayer::device() const +{ + return cdrom_device; +} + + +void RDCdPlayer::setDevice(QString device) +{ + if(cdrom_fd<0) { + cdrom_device=device; + } +} + + +bool RDCdPlayer::open() +{ + if((cdrom_fd=::open((const char *)cdrom_device,O_RDONLY|O_NONBLOCK))<0) { + return false; + } + return true; +} + + +void RDCdPlayer::close() +{ + ::close(cdrom_fd); + cdrom_fd=-1; +} + + +RDCdPlayer::Status RDCdPlayer::status() +{ + return (RDCdPlayer::Status)ioctl(cdrom_fd,CDROM_DRIVE_STATUS,NULL); +} + + +RDCdPlayer::Medium RDCdPlayer::medium() +{ + return (RDCdPlayer::Medium)ioctl(cdrom_fd,CDROM_DISC_STATUS,NULL); +} + + +int RDCdPlayer::tracks() const +{ + return cdrom_track_count; +} + + +bool RDCdPlayer::isAudio(int track) const +{ + if(cdrom_audio_track==NULL) { + return false; + } + if(track>cdrom_track_count) { + return false; + } + return cdrom_audio_track[track-1]; +} + + +/* + * TODO: + * Right now, we return length based just on the MSF minute and second data. + * Frames should be taken into account too. + */ +int RDCdPlayer::trackLength(int track) const +{ + if(cdrom_track_start==NULL) { + return 0; + } + if(track>cdrom_track_count) { + return 0; + } + return 1000*(60*cdrom_track_start[track].msf.minute+ + cdrom_track_start[track].msf.second- + (60*cdrom_track_start[track-1].msf.minute+ + cdrom_track_start[track-1].msf.second)); +} + + +unsigned RDCdPlayer::trackOffset(int track) const +{ + if(cdrom_track_start==NULL) { + return 0; + } + if(track>cdrom_track_count) { + return 0; + } + return ((75*(60*cdrom_track_start[track].msf.minute+ + cdrom_track_start[track].msf.second))+ + cdrom_track_start[track].msf.frame); +} + + +RDCdPlayer::State RDCdPlayer::state() const +{ + return cdrom_state; +} + + +int RDCdPlayer::leftVolume() +{ + struct cdrom_volctrl volctrl; + + if(ioctl(cdrom_fd,CDROMVOLREAD,&volctrl)<0) { + return -1; + } + return (int)volctrl.channel0; +} + + +int RDCdPlayer::rightVolume() +{ + struct cdrom_volctrl volctrl; + + if(ioctl(cdrom_fd,CDROMVOLREAD,&volctrl)<0) { + return -1; + } + return (int)volctrl.channel1; +} + + +void RDCdPlayer::setCddbRecord(RDCddbRecord *rec) +{ + rec->setTracks(cdrom_track_count); + rec->setDiscId(cdrom_disc_id); + rec->setDiscLength(75*(60*cdrom_track_start[cdrom_track_count].msf.minute+ + cdrom_track_start[cdrom_track_count].msf.second)+ + cdrom_track_start[cdrom_track_count].msf.frame); + for(int i=0;i<cdrom_track_count;i++) { + rec->setTrackOffset(i,trackOffset(i)); + } +} + + +void RDCdPlayer::lock() +{ + PushButton(RDCdPlayer::Lock); +} + + +void RDCdPlayer::unlock() +{ + system("eject -i off "+cdrom_device); +} + + +void RDCdPlayer::eject() +{ + system("eject "+cdrom_device); +} + + +void RDCdPlayer::play(int track) +{ + if((cdrom_state!=RDCdPlayer::Paused)||(cdrom_track!=track)) { + PushButton(RDCdPlayer::Play,track); + } + else { + PushButton(RDCdPlayer::Resume); + } +} + + +void RDCdPlayer::pause() +{ + PushButton(RDCdPlayer::Pause); +} + + +void RDCdPlayer::stop() +{ + PushButton(RDCdPlayer::Stop); +} + + +void RDCdPlayer::setLeftVolume(int vol) +{ + struct cdrom_volctrl volctrl; + + if(ioctl(cdrom_fd,CDROMVOLREAD,&volctrl)<0) { + return; + } + if(volctrl.channel0!=vol) { + volctrl.channel0=vol; + ioctl(cdrom_fd,CDROMVOLCTRL,&volctrl); + emit leftVolumeChanged(vol); + } +} + + +void RDCdPlayer::setRightVolume(int vol) +{ + struct cdrom_volctrl volctrl; + + if(ioctl(cdrom_fd,CDROMVOLREAD,&volctrl)<0) { + return; + } + if(volctrl.channel1!=vol) { + volctrl.channel1=vol; + ioctl(cdrom_fd,CDROMVOLCTRL,&volctrl); + emit rightVolumeChanged(vol); + } +} + + +RDCdPlayer::PlayMode RDCdPlayer::playMode() const +{ + return cdrom_play_mode; +} + + +void RDCdPlayer::setPlayMode(RDCdPlayer::PlayMode mode) +{ + cdrom_play_mode=mode; +} + + +void RDCdPlayer::buttonTimerData() +{ + struct cdrom_msf msf; + + if(cdrom_fd>0) { + switch(cdrom_button_queue.front()) { + case RDCdPlayer::Play: + memset(&msf,0,sizeof(struct cdrom_msf)); + msf.cdmsf_min0= + cdrom_track_start[cdrom_track_queue.front()-1].msf.minute; + msf.cdmsf_sec0= + cdrom_track_start[cdrom_track_queue.front()-1].msf.second; + msf.cdmsf_frame0= + cdrom_track_start[cdrom_track_queue.front()-1].msf.frame; + if(cdrom_play_mode==Single) { + msf.cdmsf_min1= + cdrom_track_start[cdrom_track_queue.front()].msf.minute; + msf.cdmsf_sec1= + cdrom_track_start[cdrom_track_queue.front()].msf.second; + msf.cdmsf_frame1= + cdrom_track_start[cdrom_track_queue.front()].msf.frame; + } + else { + msf.cdmsf_min1=cdrom_track_start[cdrom_track_count].msf.minute; + msf.cdmsf_sec1=cdrom_track_start[cdrom_track_count].msf.second; + msf.cdmsf_frame1=cdrom_track_start[cdrom_track_count].msf.frame; + } + ioctl(cdrom_fd,CDROMPLAYMSF,&msf); + cdrom_state=RDCdPlayer::Playing; + break; + + case RDCdPlayer::Pause: + ioctl(cdrom_fd,CDROMPAUSE,NULL); + cdrom_state=RDCdPlayer::Paused; + break; + + case RDCdPlayer::Resume: + ioctl(cdrom_fd,CDROMRESUME,NULL); + cdrom_state=RDCdPlayer::Playing; + break; + + case RDCdPlayer::Stop: + ioctl(cdrom_fd,CDROMSTOP,NULL); + cdrom_state=RDCdPlayer::Stopped; + break; + + case RDCdPlayer::Eject: + if(ioctl(cdrom_fd,CDROM_LOCKDOOR,0)<0) { + fprintf(stderr,"RDCdPlayer::Unlock failed: %s\n",strerror(errno)); + } + if(ioctl(cdrom_fd,CDROMEJECT,NULL)<0) { + fprintf(stderr,"RDCdPlayer::Eject failed: %s\n",strerror(errno)); + } + break; + + case RDCdPlayer::Lock: + if(ioctl(cdrom_fd,CDROM_LOCKDOOR,1)<0) { + fprintf(stderr,"RDCdPlayer::Lock failed: %s\n",strerror(errno)); + } + break; + + case RDCdPlayer::Unlock: + if(ioctl(cdrom_fd,CDROM_LOCKDOOR,0)<0) { + fprintf(stderr,"RDCdPlayer::Unlock failed: %s\n",strerror(errno)); + } + break; + } + } + cdrom_button_queue.pop(); + cdrom_track_queue.pop(); + if(cdrom_button_queue.size()>0) { + cdrom_button_timer->start(RDCDPLAYER_BUTTON_DELAY,true); + } +} + + +void RDCdPlayer::clockData() +{ + bool new_state; + struct cdrom_subchnl subchnl; + + // + // Media Status + // + if(ioctl(cdrom_fd,CDROM_MEDIA_CHANGED,NULL)==0) { + new_state=true; + if(cdrom_old_state==false) { + Profile("ReadToc() started"); + ReadToc(); + Profile("ReadToc() finished"); + Profile("emitting mediaChanged()"); + emit mediaChanged(); + Profile("mediaChanged() emitted"); + } + } + else { + new_state=false; + if(cdrom_old_state==true) { + Profile("emitting ejected()"); + emit ejected(); + Profile("ejected() emitted"); + } + } + cdrom_old_state=new_state; + + // + // Audio State + // + memset(&subchnl,0,sizeof(struct cdrom_subchnl)); + subchnl.cdsc_format=CDROM_MSF; + Profile("calling ioctl(CDROMSUBCHNL)"); + if(ioctl(cdrom_fd,CDROMSUBCHNL,&subchnl)>=0) { + Profile("ioctl(CDROMSUBCHNL) success"); + if(cdrom_audiostatus!=subchnl.cdsc_audiostatus) { + cdrom_audiostatus=subchnl.cdsc_audiostatus; + cdrom_track=subchnl.cdsc_trk; + switch(cdrom_audiostatus) { + case CDROM_AUDIO_INVALID: + cdrom_state=NoStateInfo; + break; + case CDROM_AUDIO_PLAY: + cdrom_state=RDCdPlayer::Playing; + emit played(cdrom_track); + break; + case CDROM_AUDIO_PAUSED: + cdrom_state=RDCdPlayer::Paused; + emit paused(); + break; + case CDROM_AUDIO_COMPLETED: + cdrom_state=RDCdPlayer::Stopped; + emit stopped(); + break; + case CDROM_AUDIO_ERROR: + cdrom_state=RDCdPlayer::Stopped; + emit stopped(); + break; + case CDROM_AUDIO_NO_STATUS: + cdrom_state=RDCdPlayer::Stopped; + emit stopped(); + break; + } + } + } + else { + Profile("ioctl(CDROMSUBCHNL) failure"); + if(cdrom_audiostatus!=CDROM_AUDIO_NO_STATUS) { + cdrom_audiostatus=CDROM_AUDIO_NO_STATUS; + cdrom_state=RDCdPlayer::Stopped; + emit stopped(); + } + } + cdrom_clock->start(RDCDPLAYER_CLOCK_INTERVAL,true); +} + + +void RDCdPlayer::ReadToc() +{ + struct cdrom_tochdr tochdr; + struct cdrom_tocentry tocentry; + + // + // TOC Header + // + if(ioctl(cdrom_fd,CDROMREADTOCHDR,&tochdr)<0) { + cdrom_track_count=0; + } + cdrom_track_count=tochdr.cdth_trk1-tochdr.cdth_trk0+1; + + // + // TOC Entries + // + if(cdrom_track_start!=NULL) { + delete cdrom_track_start; + } + if(cdrom_audio_track!=NULL) { + delete cdrom_audio_track; + } + cdrom_track_start=new union cdrom_addr[cdrom_track_count+1]; + cdrom_audio_track=new bool[cdrom_track_count]; + for(int i=1;i<=cdrom_track_count;i++) { + memset(&tocentry,0,sizeof(struct cdrom_tocentry)); + tocentry.cdte_track=i; + tocentry.cdte_format=CDROM_MSF; + ioctl(cdrom_fd,CDROMREADTOCENTRY,&tocentry); + cdrom_track_start[i-1]=tocentry.cdte_addr; + if((tocentry.cdte_ctrl&CDROM_DATA_TRACK)==0) { + cdrom_audio_track[i-1]=true; + } + else { + cdrom_audio_track[i-1]=false; + } + } + memset(&tocentry,0,sizeof(struct cdrom_tocentry)); + tocentry.cdte_track=CDROM_LEADOUT; + tocentry.cdte_format=CDROM_MSF; + ioctl(cdrom_fd,CDROMREADTOCENTRY,&tocentry); + cdrom_track_start[cdrom_track_count]=tocentry.cdte_addr; + cdrom_disc_id=GetCddbDiscId(); +} + + +// +// Methods for calculating the CDDB Disc ID are derived from code in +// the 'discid-1.3' package, from http://www.freedb.org/, by: +// Jeremy D. Zawodny <Jeremy@Zawodny.com> +// Byron Ellacott <rodent@route-qn.uqnga.org.au> +// +unsigned RDCdPlayer::GetCddbSum(int n) +{ + unsigned ret; + + ret=0; + while(n>0) { + ret+=(n%10); + n/=10; + } + return ret; +} + + +unsigned RDCdPlayer::GetCddbDiscId() +{ + int i; + unsigned t=0; + unsigned n=0; + + i=0; + while(i<cdrom_track_count) { + n=n+GetCddbSum((cdrom_track_start[i].msf.minute*60)+ + cdrom_track_start[i].msf.second); + i++; + } + t=((cdrom_track_start[cdrom_track_count].msf.minute*60)+ + cdrom_track_start[cdrom_track_count].msf.second)- + ((cdrom_track_start[0].msf.minute*60)+cdrom_track_start[0].msf.second); + return ((n%0xff)<<24|t<<8|cdrom_track_count); +} + + +void RDCdPlayer::PushButton(RDCdPlayer::ButtonOp op,int track) +{ + cdrom_button_queue.push(op); + cdrom_track_queue.push(track); + if(!cdrom_button_timer->isActive()) { + cdrom_button_timer->start(RDCDPLAYER_BUTTON_DELAY,true); + } +} + + +void RDCdPlayer::Profile(const QString &msg) +{ + if(cdrom_profile_msgs!=NULL) { + fprintf(cdrom_profile_msgs,"%s | RDCdPlayer::%s\n", + (const char *)QTime::currentTime().toString("hh:mm:ss.zzz"), + (const char *)msg); + } +} + diff --git a/lib/rdcdplayer.h b/lib/rdcdplayer.h new file mode 100644 index 00000000..b30a3df7 --- /dev/null +++ b/lib/rdcdplayer.h @@ -0,0 +1,123 @@ +// rdcdplayer.h +// +// Abstract a Linux CDROM Device. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcdplayer.h,v 1.4.8.2 2014/01/10 18:52:24 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCDPLAYER_H +#define RDCDPLAYER_H + +#include <stdio.h> +#include <linux/cdrom.h> + +#include <queue> + +#include <qdialog.h> +#include <qtimer.h> +#include <rdcddbrecord.h> + +// +// Driver Settings +// +#define RDCDPLAYER_CLOCK_INTERVAL 100 +#define RDCDPLAYER_BUTTON_DELAY 100 + +class RDCdPlayer : public QObject +{ + Q_OBJECT + public: + enum Status {NoStatusInfo=CDS_NO_INFO,NoDriveDisc=CDS_NO_DISC, + TrayOpen=CDS_TRAY_OPEN,NotReady=CDS_DRIVE_NOT_READY, + Ok=CDS_DISC_OK}; + enum Medium {NoMediumInfo=CDS_NO_INFO,NoMediumLoaded=CDS_NO_DISC, + AudioDisc=CDS_AUDIO,Data1=CDS_DATA_1,Data2=CDS_DATA_2, + Xa21=CDS_XA_2_1,Xa22=CDS_XA_2_2,Mixed=CDS_MIXED}; + enum State {NoStateInfo=0,Stopped=1,Playing=2,Paused=3}; + enum PlayMode {Single=0,Continuous=1}; + RDCdPlayer(FILE *profile_msgs,QWidget *parent=0,const char *name=0); + ~RDCdPlayer(); + QString device() const; + void setDevice(QString device); + bool open(); + void close(); + RDCdPlayer::Status status(); + RDCdPlayer::Medium medium(); + int tracks() const; + bool isAudio(int track) const; + int trackLength(int track) const; + unsigned trackOffset(int track) const; + RDCdPlayer::State state() const; + int leftVolume(); + int rightVolume(); + RDCdPlayer::PlayMode playMode() const; + void setPlayMode(RDCdPlayer::PlayMode mode); + void setCddbRecord(RDCddbRecord *); + + public slots: + void lock(); + void unlock(); + void eject(); + void play(int track); + void pause(); + void stop(); + void setLeftVolume(int vol); + void setRightVolume(int vol); + + signals: + void ejected(); + void mediaChanged(); + void played(int track); + void paused(); + void stopped(); + void leftVolumeChanged(int vol); + void rightVolumeChanged(int vol); + + private slots: + void buttonTimerData(); + void clockData(); + + private: + enum ButtonOp {Play=0,Pause=1,Resume=2,Stop=3,Eject=4,Lock=5,Unlock=6}; + void PushButton(RDCdPlayer::ButtonOp op,int track=-1); + void Profile(const QString &msg); + void ReadToc(); + unsigned GetCddbSum(int); + unsigned GetCddbDiscId(); + QString cdrom_device; + int cdrom_fd; + QTimer *cdrom_clock; + QTimer *cdrom_button_timer; + RDCdPlayer::State cdrom_state; + int cdrom_track; + int cdrom_track_count; + union cdrom_addr *cdrom_track_start; + bool *cdrom_audio_track; + RDCdPlayer::PlayMode cdrom_play_mode; + union cdrom_addr cdrom_rip_ptr; + union cdrom_addr cdrom_rip_end; + bool cdrom_old_state; + int cdrom_audiostatus; + unsigned cdrom_disc_id; + FILE *cdrom_profile_msgs; + std::queue<int> cdrom_button_queue; + std::queue<int> cdrom_track_queue; +}; + + +#endif // RDCDPLAYER_H diff --git a/lib/rdcdripper.cpp b/lib/rdcdripper.cpp new file mode 100644 index 00000000..2c424bbc --- /dev/null +++ b/lib/rdcdripper.cpp @@ -0,0 +1,205 @@ +// rdcdripper.cpp +// +// Rip an audio from from CD +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcdripper.cpp,v 1.4.6.3 2014/01/10 02:25:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +/* +extern "C" { +#include <cdda_interface.h> +} +*/ + +#include <qapplication.h> +#include <qdatetime.h> + +#include <rdpaths.h> +#include <rdcdripper.h> +#include <rd.h> + +RDCdRipper::RDCdRipper(FILE *profile_msgs,QObject *parent) + : QObject(parent) +{ + conv_profile_msgs=profile_msgs; + conv_aborting=false; +} + + +RDCdRipper::~RDCdRipper() +{ +} + + +void RDCdRipper::setDevice(const QString &device) +{ + conv_device=device; + Profile("using device \""+device+"\""); +} + + +void RDCdRipper::setDestinationFile(const QString &filename) +{ + conv_dst_filename=filename; +} + + +int RDCdRipper::totalSteps() const +{ + return 4; +} + + +RDCdRipper::ErrorCode RDCdRipper::rip(int track) +{ + return rip(track,track); +} + + +RDCdRipper::ErrorCode RDCdRipper::rip(int first_track,int last_track) +{ + SNDFILE *sf_dst=NULL; + SF_INFO sf_dst_info; + cdrom_drive *drive; + int err; + char *msg; + long sect=0; + long n; + short buffer[63504]; + long start; + long end; + long size=RIPPER_MAX_SECTORS; + int step; + int step_size; + + // + // Open the CD + // + if((drive=cdda_identify(conv_device,1,&msg))==NULL) { + return RDCdRipper::ErrorNoDevice; + } + if((err=cdda_open(drive))!=0) { + return RDCdRipper::ErrorNoDisc; + } + if((first_track>=cdda_tracks(drive))||(last_track>=cdda_tracks(drive))|| + (last_track<first_track)) { + cdda_close(drive); + return RDCdRipper::ErrorNoTrack; + } + start=cdda_track_firstsector(drive,first_track+1); + end=cdda_track_lastsector(drive,last_track+1); + step_size=(end-start)/4; + step=0; + + // + // Open Destination + // + memset(&sf_dst_info,0,sizeof(sf_dst_info)); + sf_dst_info.format=SF_FORMAT_WAV|SF_FORMAT_PCM_32; + sf_dst_info.channels=cdda_track_channels(drive,first_track+1); + sf_dst_info.samplerate=44100; + if((sf_dst=sf_open(conv_dst_filename,SFM_WRITE,&sf_dst_info))==NULL) { + cdda_close(drive); + return RDCdRipper::ErrorNoDestination; + } + + // + // Rip Track + // + emit progressChanged(step); + qApp->processEvents(); + for(long i=start;i<end;i+=RIPPER_MAX_SECTORS) { + if((end-i)<RIPPER_MAX_SECTORS) { + size=end-i; + } + n=cdda_read(drive,buffer,i,size); + sf_writef_short(sf_dst,buffer,CD_FRAMESIZE_RAW*n/(2*sf_dst_info.channels)); + sect+=n; + if(sect>((step+1)*step_size)) { + emit progressChanged(++step); + qApp->processEvents(); + if(conv_aborting) { + sf_close(sf_dst); + unlink(conv_dst_filename); + cdda_close(drive); + return RDCdRipper::ErrorAborted; + } + } + } + + // + // Clean Up + // + sf_close(sf_dst); + cdda_close(drive); + + return RDCdRipper::ErrorOk; +} + + +QString RDCdRipper::errorText(RDCdRipper::ErrorCode err) +{ + QString ret="Unknown Error"; + + switch(err) { + case RDCdRipper::ErrorOk: + ret="OK"; + break; + + case RDCdRipper::ErrorNoDevice: + ret="No such device"; + break; + + case RDCdRipper::ErrorNoDestination: + ret="Unable to create output file"; + break; + + case RDCdRipper::ErrorInternal: + ret="Internal error"; + break; + + case RDCdRipper::ErrorNoDisc: + ret="No disc found"; + break; + + case RDCdRipper::ErrorNoTrack: + ret="No such track"; + break; + + case RDCdRipper::ErrorAborted: + ret="Rip Aborted"; + break; + } + return ret; +} + + +void RDCdRipper::abort() +{ + conv_aborting=true; +} + + +void RDCdRipper::Profile(const QString &msg) +{ + if(conv_profile_msgs!=NULL) { + fprintf(conv_profile_msgs,"%s | RDCdPlayer::%s\n", + (const char *)QTime::currentTime().toString("hh:mm:ss.zzz"), + (const char *)msg); + } +} diff --git a/lib/rdcdripper.h b/lib/rdcdripper.h new file mode 100644 index 00000000..f39ecb2a --- /dev/null +++ b/lib/rdcdripper.h @@ -0,0 +1,62 @@ +// rdcdripper.h +// +// Rip an audio from from CD +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcdripper.h,v 1.2.8.3 2014/01/10 02:25:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCDRIPPER_H +#define RDCDRIPPER_H + +#include <sndfile.h> +#include <stdio.h> +#include <qobject.h> +#include <unistd.h> + +class RDCdRipper : public QObject +{ + Q_OBJECT; + public: + enum ErrorCode {ErrorOk=0,ErrorNoDevice=1,ErrorNoDestination=2, + ErrorInternal=3,ErrorNoDisc=4,ErrorNoTrack=5, + ErrorAborted=6}; + RDCdRipper(FILE *profile_msgs,QObject *parent=0); + ~RDCdRipper(); + void setDevice(const QString &device); + void setDestinationFile(const QString &filename); + int totalSteps() const; + RDCdRipper::ErrorCode rip(int track); + RDCdRipper::ErrorCode rip(int first_track,int last_track); + static QString errorText(RDCdRipper::ErrorCode err); + + public slots: + void abort(); + + signals: + void progressChanged(int step); + + private: + void Profile(const QString &msg); + QString conv_device; + QString conv_dst_filename; + bool conv_aborting; + FILE *conv_profile_msgs; +}; + + +#endif // RDCDRIPPER_H diff --git a/lib/rdcheck_daemons.cpp b/lib/rdcheck_daemons.cpp new file mode 100644 index 00000000..68556ab3 --- /dev/null +++ b/lib/rdcheck_daemons.cpp @@ -0,0 +1,133 @@ +// rdcheck_daemons.cpp +// +// Get the status of the Rivendell system daemons. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcheck_daemons.cpp,v 1.12 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <signal.h> + +#include <qstring.h> +#include <qdir.h> +#include <qmessagebox.h> + +#include <rd.h> +#include <rdcheck_daemons.h> + + +pid_t GetPid(QString pidfile) +{ + FILE *handle; + pid_t ret; + + if((handle=fopen((const char *)pidfile,"r"))==NULL) { + return -1; + } + if(fscanf(handle,"%d",&ret)!=1) { + ret=-1; + } + fclose(handle); + return ret; +} + + +void RDInitializeDaemons() +{ + if(!RDStartDaemons()) { + QMessageBox::warning(NULL,"Missing Daemons", + "Unable to start Rivendell daemons!"); + exit(1); + } +} + + +bool RDCheckDaemon(QString name) +{ + QString cmd; + + pid_t daemonPid = GetPid(name); + if(daemonPid == -1) return false; + + cmd=QString().sprintf("ps -p %d | grep %d > /dev/null", daemonPid, daemonPid); + int grepResult = system(cmd); + + // Grep returns 0 if any lines were found + return (grepResult == 0); +} + + +bool RDCheckDaemons() +{ + return RDCheckDaemon(RD_CAED_PID)&& + RDCheckDaemon(RD_RIPCD_PID)&& + RDCheckDaemon(RD_RDCATCHD_PID); +} + + +bool RDStartDaemon(QString cmd) +{ + system(cmd); + return true; +} + + +bool RDStartDaemons() +{ + if(!RDCheckDaemon(RD_CAED_PID)) { + RDKillDaemons(); + RDStartDaemon("caed"); + sleep(RD_DAEMON_PAUSE_TIME); + if(!RDCheckDaemon(RD_CAED_PID)) { + return false; + } + } + if(!RDCheckDaemon(RD_RIPCD_PID)) { + RDStartDaemon("ripcd"); + sleep(RD_DAEMON_PAUSE_TIME); + if(!RDCheckDaemon(RD_RIPCD_PID)) { + return false; + } + } + if(!RDCheckDaemon(RD_RDCATCHD_PID)) { + RDStartDaemon("rdcatchd"); + sleep(RD_DAEMON_PAUSE_TIME); + if(!RDCheckDaemon(RD_RDCATCHD_PID)) { + return false; + } + } + return true; +} + + +bool RDKillDaemons() +{ + if(RDCheckDaemon(RD_CAED_PID)) { + kill(GetPid(RD_CAED_PID),SIGTERM); + } + if(RDCheckDaemon(RD_RIPCD_PID)) { + kill(GetPid(RD_RIPCD_PID),SIGTERM); + } + if(RDCheckDaemon(RD_RDCATCHD_PID)) { + kill(GetPid(RD_RDCATCHD_PID),SIGTERM); + } + return true; +} diff --git a/lib/rdcheck_daemons.h b/lib/rdcheck_daemons.h new file mode 100644 index 00000000..5a8885aa --- /dev/null +++ b/lib/rdcheck_daemons.h @@ -0,0 +1,37 @@ +// rdcheck_daemons.h +// +// Get the status of the Rivendell system daemons. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcheck_daemons.h,v 1.7 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCHECK_DAEMONS_H +#define RDCHECK_DAEMONS_H + +#include <qstring.h> + + +void RDInitializeDaemons(); +bool RDCheckDaemon(QString name); +bool RDCheckDaemons(); +bool RDStartDaemons(); +bool RDKillDaemons(); + + +#endif + diff --git a/lib/rdcheck_version.cpp b/lib/rdcheck_version.cpp new file mode 100644 index 00000000..ab34bc82 --- /dev/null +++ b/lib/rdcheck_version.cpp @@ -0,0 +1,37 @@ +// rdcheck_version.cpp +// +// Get the current Rivendell Database Version,. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcheck_version.cpp,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rd.h> +#include <rdversion.h> + +#include <rdcheck_version.h> + + +int RDCheckVersion() +{ + int ver; + + RDVersion *version=new RDVersion(); + ver=version->database(); + delete version; + return ver; +} diff --git a/lib/rdcheck_version.h b/lib/rdcheck_version.h new file mode 100644 index 00000000..dd19f873 --- /dev/null +++ b/lib/rdcheck_version.h @@ -0,0 +1,30 @@ +// rdcheck_version.h +// +// Get the current Rivendell Database Version. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcheck_version.h,v 1.3 2007/02/14 21:48:41 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCHECK_VERSION_H +#define RDCHECK_VERSION_H + +int RDCheckVersion(); + + +#endif + diff --git a/lib/rdclock.cpp b/lib/rdclock.cpp new file mode 100644 index 00000000..909175ef --- /dev/null +++ b/lib/rdclock.cpp @@ -0,0 +1,337 @@ +// rdclock.cpp +// +// Abstract a Rivendell Log Manager Clock. +// +// (C) Copyright 2002-2004,2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdclock.cpp,v 1.23.10.1 2014/06/24 18:27:03 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +#include <rddb.h> +#include <rdclock.h> +#include <rdevent_line.h> +#include <rdescape_string.h> + +// +// Global Classes +// +RDClock::RDClock() +{ + clear(); +} + + +QString RDClock::name() const +{ + return clock_name; +} + + +void RDClock::setName(const QString &name) +{ + clock_name=name; + clock_name_esc=name; + clock_name_esc.replace(" ","_"); +} + + +QString RDClock::shortName() const +{ + return clock_short_name; +} + + +void RDClock::setShortName(const QString &name) +{ + clock_short_name=name; +} + + +QColor RDClock::color() const +{ + return clock_color; +} + + +void RDClock::setColor(const QColor &color) +{ + clock_color=color; +} + + +QString RDClock::remarks() const +{ + return clock_remarks; +} + + +void RDClock::setRemarks(const QString &str) +{ + clock_remarks=str; +} + + +unsigned RDClock::getArtistSep() +{ + return artistsep; +} + +void RDClock::setArtistSep(unsigned artist_sep) +{ + artistsep=artist_sep; +} + +bool RDClock::getRulesModified() +{ + return rules_modified; +} + + +void RDClock::setRulesModified(bool modified) +{ + rules_modified=modified; +} + + +void RDClock::clear() +{ + clock_name=""; + clock_short_name=""; + clock_color=QColor(); + clock_remarks=""; + clock_events.clear(); + artistsep=15; + rules_modified=false; +} + + +RDEventLine *RDClock::eventLine(int line) +{ + if((line<0)||((unsigned)line>=clock_events.size())) { + return NULL; + } + return &clock_events[line]; +} + + +int RDClock::size() const +{ + return clock_events.size(); +} + + +bool RDClock::load() +{ + QString sql=QString().sprintf("select SHORT_NAME,COLOR,ARTISTSEP,REMARKS from\ + CLOCKS where NAME=\"%s\"", + (const char *)clock_name); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return false; + } + clock_short_name=q->value(0).toString(); + if(q->value(1).isNull()) { + clock_color=QColor(); + } + else { + clock_color=QColor(q->value(1).toString()); + } + artistsep=q->value(2).toUInt(); + clock_remarks=q->value(3).toString(); + delete q; + + sql=QString().sprintf("select EVENT_NAME,START_TIME,LENGTH from %s_CLK\ + order by ID", + (const char *)clock_name_esc); + q=new RDSqlQuery(sql); + while(q->next()) { + clock_events.push_back(RDEventLine()); + clock_events.back().setName(q->value(0).toString()); + clock_events.back().setStartTime(QTime().addMSecs(q->value(1).toInt())); + clock_events.back().setLength(q->value(2).toInt()); + clock_events.back().load(); + } + delete q; + return true; +} + + +bool RDClock::save() +{ + if(clock_short_name.isEmpty()) { + clock_short_name=clock_name.left(3); + } + QString sql=QString().sprintf("select NAME from CLOCKS where NAME=\"%s\"", + (const char *)clock_name); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + delete q; + sql=QString().sprintf("update CLOCKS set SHORT_NAME=\"%s\",COLOR=\"%s\",\ + ARTISTSEP=%d,REMARKS=\"%s\" where NAME=\"%s\"", + (const char *)clock_short_name, + (const char *)clock_color.name(), + artistsep, + (const char *)RDEscapeString(clock_remarks), + (const char *)clock_name); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from %s_CLK",(const char *)clock_name_esc); + q=new RDSqlQuery(sql); + delete q; + } + else { + delete q; + sql=QString().sprintf("insert into CLOCKS set NAME=\"%s\",\ + SHORT_NAME=\"%s\",COLOR=\"%s\",ARTISTSEP=%d,\ + REMARKS=\"%s\"", + (const char *)clock_name, + (const char *)clock_short_name, + (const char *)clock_color.name(), + artistsep, + (const char *)RDEscapeString(clock_remarks)); + + q=new RDSqlQuery(sql); + delete q; + } + sql=QString().sprintf("delete from %s_CLK", + (const char *)clock_name_esc); + q=new RDSqlQuery(sql); + delete q; + for(unsigned i=0;i<clock_events.size();i++) { + sql=QString().sprintf("insert into %s_CLK set EVENT_NAME=\"%s\",\ + START_TIME=%d,LENGTH=%d", + (const char *)clock_name_esc, + (const char *)clock_events[i].name(), + QTime().msecsTo(clock_events[i].startTime()), + clock_events[i].length()); + q=new RDSqlQuery(sql); + delete q; + } + return true; +} + + +bool RDClock::insert(const QString &event_name,int line) +{ + QString sql=QString().sprintf("select NAME from EVENTS where NAME=\"%s\"", + (const char *)event_name); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return false; + } + delete q; + if(line>=size()) { + clock_events.push_back(RDEventLine()); + } + else { + vector<RDEventLine>::iterator it=clock_events.begin()+line; + clock_events.insert(it,1,RDEventLine()); + } + clock_events[line].setName(event_name); + clock_events[line].load(); + return true; +} + + +void RDClock::remove(int line) +{ + vector<RDEventLine>::iterator it=clock_events.begin()+line; + clock_events.erase(it,it+1); +} + + +void RDClock::move(int from_line,int to_line) +{ + int src_offset=0; + int dest_offset=1; + RDEventLine *srcline; + RDEventLine *destline; + + if(to_line<from_line) { + src_offset=1; + dest_offset=0; + } + insert(clock_events[from_line].name(),to_line+dest_offset); + if((to_line+1)>=size()) { + to_line=clock_events.size()-1; + dest_offset=0; + } + + if(((destline=eventLine(to_line+dest_offset))==NULL)|| + (srcline=eventLine(from_line+src_offset))==NULL) { + remove(to_line+dest_offset); + return; + } + *destline=*srcline; + remove(from_line+src_offset); +} + + +bool RDClock::validate(const QTime &start_time,int length,int except_line) +{ + QTime end_time=start_time.addMSecs(length); + QTime end; + for(unsigned i=0;i<clock_events.size();i++) { + if(i!=(unsigned)except_line) { + end=clock_events[i].startTime().addMSecs(clock_events[i].length()); + if((start_time>=clock_events[i].startTime())&&(start_time<end)) { + return false; + } + if(((end_time>clock_events[i].startTime())&& + (end_time<end))|| + ((start_time<end)&&(end_time>end))) { + return false; + } + } + } + return true; +} + + +bool RDClock::generateLog(int hour,const QString &logname, + const QString &svc_name,QString *errors) +{ + QString sql; + RDSqlQuery *q; + RDEventLine eventline; + + sql=QString().sprintf("select EVENT_NAME,START_TIME,LENGTH from %s_CLK\ + order by START_TIME", + (const char *)clock_name_esc); + q=new RDSqlQuery(sql); + while(q->next()) { + eventline.setName(q->value(0).toString()); + eventline.load(); + // eventline.setStartTime(q->value(1).toTime().addSecs(3600*hour)); + eventline.setStartTime(QTime().addMSecs(q->value(1).toInt()). + addSecs(3600*hour)); + eventline.setLength(q->value(2).toInt()); + eventline.generateLog(logname,svc_name,errors,artistsep,clock_name_esc); + eventline.clear(); + } + delete q; + return true; +} + + +QString RDClock::tableName(const QString &name) +{ + QString ret=name; + ret.replace(" ","_"); + + return ret+"_CLK"; +} diff --git a/lib/rdclock.h b/lib/rdclock.h new file mode 100644 index 00000000..bbef6815 --- /dev/null +++ b/lib/rdclock.h @@ -0,0 +1,77 @@ +// rdclock.h +// +// Abstract a Rivendell Log Manager Clock +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdclock.h,v 1.17.10.1 2014/06/24 18:27:03 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDCLOCK_H +#define RDCLOCK_H + +#include <vector> + +#include <qsqldatabase.h> + +#include <rdevent_line.h> + +using namespace std; + + +class RDClock +{ + public: + RDClock(); + QString name() const; + void setName(const QString &name); + QString shortName() const; + void setShortName(const QString &name); + QColor color() const; + void setColor(const QColor &color); + QString remarks() const; + void setRemarks(const QString &str); + unsigned getArtistSep(); + void setArtistSep(unsigned artist_sep); + bool getRulesModified(); + void setRulesModified(bool modified); + + RDEventLine *eventLine(int line); + void clear(); + int size() const; + bool load(); + bool save(); + bool insert(const QString &event_name,int line); + void remove(int line); + void move(int from_line,int to_line); + bool validate(const QTime &start_time,int length,int except_line=-1); + bool generateLog(int hour,const QString &logname,const QString &svc_name, + QString *errors); + static QString tableName(const QString &name); + + private: + QString clock_name; + QString clock_name_esc; + QString clock_short_name; + QColor clock_color; + QString clock_remarks; + vector<RDEventLine> clock_events; + unsigned artistsep; + bool rules_modified; +}; + +#endif diff --git a/lib/rdcmd_cache.cpp b/lib/rdcmd_cache.cpp new file mode 100644 index 00000000..00cc5f4b --- /dev/null +++ b/lib/rdcmd_cache.cpp @@ -0,0 +1,105 @@ +// rdcmd_cache.cpp +// +// A low-level container class for a CAE command. +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcmd_cache.cpp,v 1.6 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> +#include <string.h> + +#include <rdcmd_cache.h> + + +RDCmdCache::RDCmdCache() +{ + clear(); +} + + +RDCmdCache::RDCmdCache(const RDCmdCache &cmd) +{ + clear(); + cache_argnum=cmd.argNum(); + cache_argptr=cmd.argPtr(); + for(int i=0;i<cache_argnum;i++) { + strcpy(cache_args[i],cmd.arg(i)); + } +} + + +void RDCmdCache::clear() +{ + for(int i=0;i<CAE_MAX_ARGS;i++) { + cache_args[i][0]=0; + } + cache_argnum=0; + cache_argptr=0; +} + + +const char *RDCmdCache::arg(int n) const +{ + return cache_args[n]; +} + + +void RDCmdCache::setArg(int n,char *arg) +{ + strcpy(cache_args[n],arg); +} + + +int RDCmdCache::argNum() const +{ + return cache_argnum; +} + + +void RDCmdCache::setArgNum(int num) +{ + cache_argnum=num; +} + + +int RDCmdCache::argPtr() const +{ + return cache_argptr; +} + + +void RDCmdCache::setArgPtr(int ptr) +{ + cache_argptr=ptr; +} + + +void RDCmdCache::load(char args[CAE_MAX_ARGS][CAE_MAX_LENGTH], + int argnum,int argptr) +{ + for(int i=0;i<argnum;i++) { + int j=0; + while(args[i][j]!=0) { + cache_args[i][j]=args[i][j]; + j++; + } + cache_args[i][j]=0; + } + cache_argnum=argnum; + cache_argptr=argptr; +} diff --git a/lib/rdcmd_cache.h b/lib/rdcmd_cache.h new file mode 100644 index 00000000..39ffbe59 --- /dev/null +++ b/lib/rdcmd_cache.h @@ -0,0 +1,50 @@ +// rdcmd_cache.h +// +// A low-level container class for a CAE command. +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcmd_cache.h,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCMD_CACHE_H +#define RDCMD_CACHE_H + +#include <rd.h> + + +class RDCmdCache +{ + public: + RDCmdCache(); + RDCmdCache(const RDCmdCache &cmd); + void clear(); + const char *arg(int n) const; + void setArg(int n,char *arg); + int argNum() const; + void setArgNum(int num); + int argPtr() const; + void setArgPtr(int ptr); + void load(char args[CAE_MAX_ARGS][CAE_MAX_LENGTH],int argnum,int argptr); + + private: + char cache_args[CAE_MAX_ARGS][CAE_MAX_LENGTH]; + int cache_argnum; + int cache_argptr; +}; + + +#endif // RDCMD_CACHE_H diff --git a/lib/rdcmd_switch.cpp b/lib/rdcmd_switch.cpp new file mode 100644 index 00000000..abe84441 --- /dev/null +++ b/lib/rdcmd_switch.cpp @@ -0,0 +1,122 @@ +// rdcmd_switch.cpp +// +// Process Rivendell Command-Line Switches +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcmd_switch.cpp,v 1.13.8.1 2012/05/10 23:12:42 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WIN32 +#include <syslog.h> +#endif // WIN32 + +#include <stdlib.h> +#include <rdcmd_switch.h> +#include <qmessagebox.h> + +RDCmdSwitch::RDCmdSwitch(int argc,char *argv[],const char *modname, + const char *usage) +{ + unsigned l=0; + bool handled=false; + bool debug=false; + + for(int i=1;i<argc;i++) { +#ifndef WIN32 + if(!strcmp(argv[i],"--version")) { + printf("Rivendell v%s [%s]\n",VERSION,modname); + exit(0); + } +#endif // WIN32 + if(!strcmp(argv[i],"--help")) { + printf("\n%s %s\n",modname,usage); + exit(0); + } + if(!strcmp(argv[i],"-d")) { + debug=true; + } + l=strlen(argv[i]); + handled=false; + for(unsigned j=0;j<l;j++) { + if(argv[i][j]=='=') { + switch_keys.push_back(QString(argv[i]).left(j)); + switch_values.push_back(QString(argv[i]).right(l-(j+1))); + switch_processed.push_back(false); + j=l; + handled=true; + } + } + if(!handled) { + switch_keys.push_back(QString(argv[i])); + switch_values.push_back(QString("")); + switch_processed.push_back(false); + } + } + + // + // Initialize Logging + // +#ifndef WIN32 + if(debug) { + openlog(modname,LOG_PERROR,LOG_USER); + } + else { + openlog(modname,0,LOG_USER); + } +#endif // WIN32 +} + + +unsigned RDCmdSwitch::keys() const +{ + return switch_keys.size(); +} + + +QString RDCmdSwitch::key(unsigned n) const +{ + return switch_keys[n]; +} + + +QString RDCmdSwitch::value(unsigned n) const +{ + return switch_values[n]; +} + + +bool RDCmdSwitch::processed(unsigned n) const +{ + return switch_processed[n]; +} + + +void RDCmdSwitch::setProcessed(unsigned n,bool state) +{ + switch_processed[n]=state; +} + + +bool RDCmdSwitch::allProcessed() const +{ + for(unsigned i=0;i<switch_processed.size();i++) { + if(!switch_processed[i]) { + return false; + } + } + return true; +} diff --git a/lib/rdcmd_switch.h b/lib/rdcmd_switch.h new file mode 100644 index 00000000..f60ae1a5 --- /dev/null +++ b/lib/rdcmd_switch.h @@ -0,0 +1,48 @@ +// rdcmd_switch.h +// +// Process Rivendell Command-Line Switches +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcmd_switch.h,v 1.8.8.1 2012/05/10 23:12:42 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCMD_SWITCH_H +#define RDCMD_SWITCH_H + +#include <vector> +#include <qstring.h> + + +class RDCmdSwitch +{ + public: + RDCmdSwitch(int argc,char *argv[],const char *modname,const char *usage); + unsigned keys() const; + QString key(unsigned n) const; + QString value(unsigned n) const; + bool processed(unsigned n) const; + void setProcessed(unsigned n,bool state); + bool allProcessed() const; + + private: + std::vector<QString> switch_keys; + std::vector<QString> switch_values; + std::vector<bool> switch_processed; +}; + + +#endif // RDCMD_SWITCH_H diff --git a/lib/rdcodetrap.cpp b/lib/rdcodetrap.cpp new file mode 100644 index 00000000..a7679d77 --- /dev/null +++ b/lib/rdcodetrap.cpp @@ -0,0 +1,125 @@ +// rdcodetrap.cpp +// +// A class for trapping arbitrary character sequences. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcodetrap.cpp,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <string.h> + +#include <rdcodetrap.h> + + +RDCodeTrap::RDCodeTrap(QObject *parent,const char *name) + : QObject(parent,name) +{ +} + + +RDCodeTrap::~RDCodeTrap() +{ +} + + +void RDCodeTrap::addTrap(int id,const char *code,int length) +{ + for(unsigned i=0;i<trap_events.size();i++) { + if(length==trap_events[i].length) { + if((trap_events[i].id==id)&& + (!strncmp(code,trap_events[i].code,length))) { + return; + } + } + } + trap_events.push_back(RTrapEvent()); + trap_events.back().id=id; + trap_events.back().code=new char[length]; + memcpy(trap_events.back().code,code,length); + trap_events.back().length=length; + trap_events.back().istate=0; +} + + +void RDCodeTrap::removeTrap(int id) +{ + for(unsigned i=0;i<trap_events.size();i++) { + if(trap_events[i].id==id) { + delete trap_events[i].code; + vector<RTrapEvent>::iterator it=trap_events.begin()+i; + trap_events.erase(it,it+1); + i--; + } + } +} + + +void RDCodeTrap::removeTrap(const char *code,int length) +{ + for(unsigned i=0;i<trap_events.size();i++) { + if(length==trap_events[i].length) { + if(!strncmp(code,trap_events[i].code,length)) { + delete trap_events[i].code; + vector<RTrapEvent>::iterator it=trap_events.begin()+i; + trap_events.erase(it,it+1); + i--; + } + } + } +} + + +void RDCodeTrap::removeTrap(int id,const char *code,int length) +{ + for(unsigned i=0;i<trap_events.size();i++) { + if(length==trap_events[i].length) { + if((trap_events[i].id==id)&& + (!strncmp(code,trap_events[i].code,length))) { + delete trap_events[i].code; + vector<RTrapEvent>::iterator it=trap_events.begin()+i; + trap_events.erase(it,it+1); + i--; + } + } + } +} + + +void RDCodeTrap::scan(const char *buf,int length) +{ + for(unsigned i=0;i<trap_events.size();i++) { + for(int j=0;j<length;j++) { + if(buf[j]==trap_events[i].code[trap_events[i].istate]) { + trap_events[i].istate++; + } + else { + trap_events[i].istate=0; + } + if(trap_events[i].istate==trap_events[i].length) { + emit trapped(trap_events[i].id); + trap_events[i].istate=0; + } + } + } +} + + +void RDCodeTrap::clear() +{ + trap_events.clear(); +} diff --git a/lib/rdcodetrap.h b/lib/rdcodetrap.h new file mode 100644 index 00000000..2b9f19fe --- /dev/null +++ b/lib/rdcodetrap.h @@ -0,0 +1,64 @@ +// rdcodetrap.h +// +// A class for trapping arbitrary character sequences. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcodetrap.h,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDCODETRAP_H +#define RDCODETRAP_H + + +#include <vector> + +#include <qobject.h> + +using namespace std; + + +struct RTrapEvent { + int id; + char *code; + int length; + int istate; +}; + + +class RDCodeTrap : public QObject +{ + Q_OBJECT + public: + RDCodeTrap(QObject *parent=0,const char *name=0); + ~RDCodeTrap(); + void addTrap(int id,const char *code,int length); + void removeTrap(int id); + void removeTrap(const char *code,int length); + void removeTrap(int id,const char *code,int length); + void scan(const char *buf,int length); + void clear(); + + signals: + void trapped(int id); + + private: + vector<struct RTrapEvent> trap_events; +}; + + +#endif // RDCODETRAP_H diff --git a/lib/rdcombobox.cpp b/lib/rdcombobox.cpp new file mode 100644 index 00000000..656d75b6 --- /dev/null +++ b/lib/rdcombobox.cpp @@ -0,0 +1,87 @@ +// rdcombobox.cpp +// +// A Combo Box widget for Rivendell. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcombobox.cpp,v 1.8 2011/05/18 18:57:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdcombobox.h> + + +RDComboBox::RDComboBox(QWidget *parent,const char *name) + : QComboBox(parent,name) +{ + combo_setup_mode=false; +} + + +void RDComboBox::insertItem(const QString &str,bool unique) +{ + if(unique) { + if(!IsItemUnique(str)) { + return; + } + } + QComboBox::insertItem(str); +} + + +void RDComboBox::setSetupMode(bool state) +{ + combo_setup_mode=state; +} + + +void RDComboBox::addIgnoredKey(int key) +{ + ignored_keys.push_back(key); +} + + +void RDComboBox::mousePressEvent(QMouseEvent *e) +{ + if(combo_setup_mode) { + emit setupClicked(); + } + else { + QComboBox::mousePressEvent(e); + } +} + + +void RDComboBox::keyPressEvent(QKeyEvent *e) +{ + for(unsigned i=0;i<ignored_keys.size();i++) { + if(e->key()==ignored_keys[i]) { + e->ignore(); + return; + } + } + QComboBox::keyPressEvent(e); +} + + +bool RDComboBox::IsItemUnique(const QString &str) +{ + for(int i=0;i<count();i++) { + if(str==text(i)) { + return false; + } + } + return true; +} diff --git a/lib/rdcombobox.h b/lib/rdcombobox.h new file mode 100644 index 00000000..82e5cd40 --- /dev/null +++ b/lib/rdcombobox.h @@ -0,0 +1,53 @@ +// rdcombobox.h +// +// A Combo Box widget for Rivendell. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcombobox.h,v 1.7 2011/05/18 18:57:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCOMBOBOX_H +#define RDCOMBOBOX_H + +#include <vector> + +#include <qcombobox.h> + +class RDComboBox : public QComboBox +{ + Q_OBJECT + public: + RDComboBox(QWidget *parent=0,const char *name=0); + void insertItem(const QString &str,bool unique=false); + void setSetupMode(bool state); + void addIgnoredKey(int key); + + signals: + void setupClicked(); + + protected: + void mousePressEvent(QMouseEvent *e); + void keyPressEvent(QKeyEvent *e); + + private: + bool IsItemUnique(const QString &str); + bool combo_setup_mode; + std::vector<int> ignored_keys; +}; + + +#endif // RDCOMBOBOX_H diff --git a/lib/rdconf.cpp b/lib/rdconf.cpp new file mode 100644 index 00000000..80f6030a --- /dev/null +++ b/lib/rdconf.cpp @@ -0,0 +1,1215 @@ +// rconf.c +// A small library for handling common configuration file tasks +// +// Adopted from conflib +// +// (C) Copyright 1996-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdconf.cpp,v 1.15.4.7.2.1 2014/06/24 18:27:04 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> + +#include <qhostaddress.h> +#include <qvariant.h> +#include <qmessagebox.h> +#include <qdir.h> +#ifdef WIN32 +#define RDCONF_FILE_SEPARATOR '\\' +#else +#define RDCONF_FILE_SEPARATOR '/' +#include <unistd.h> +#include <netdb.h> +#include <sys/timex.h> +#include <time.h> +#endif +#include <rddb.h> +#include <rdconf.h> +#include <rdescape_string.h> + +#define BUFFER_SIZE 1024 + +int GetPrivateProfileBool(const char *sFilename,const char *cHeader, + const char *cLabel,bool bDefault=false) +{ + char temp[255]; + + if(GetPrivateProfileString(sFilename,cHeader,cLabel,temp,"",254)<0) { + return bDefault; + } + if(temp[0]==0) { + return bDefault; + } +#ifdef WIN32 + if((!stricmp(temp,"yes"))||(!stricmp(temp,"on"))) { + return true; + } + if((!stricmp(temp,"no"))||(!stricmp(temp,"off"))) { + return false; + } +#else + if((!strcasecmp(temp,"yes"))||(!strcasecmp(temp,"on"))) { + return true; + } + if((!strcasecmp(temp,"no"))||(!strcasecmp(temp,"off"))) { + return false; + } +#endif + return bDefault; +} + + +int GetPrivateProfileString(const char *sFilename,const char *cHeader, + const char *cLabel,char *cValue, + const char *cDefault,int dValueLength) +{ + int i; + + i=GetIni(sFilename,cHeader,cLabel,cValue,dValueLength); + if(i==0) { + return 0; + } + else { + strcpy(cValue,cDefault); + return -1; + } +} + + +int GetPrivateProfileInt(const char *sFilename,const char *cHeader, + const char *cLabel,int dDefault) +{ + int c; + char sNum[12]; + + if(GetIni(sFilename,cHeader,cLabel,sNum,11)==0) { + if(sscanf(sNum,"%d",&c)==1) { + return c; + } + else { + return dDefault; + } + } + else { + return dDefault; + } +} + + +int GetPrivateProfileHex(const char *sFilename,const char *cHeader, + const char *cLabel,int dDefault) +{ + char temp[256]; + int n=dDefault; + + GetPrivateProfileString(sFilename,cHeader,cLabel,temp,"",255); + sscanf(temp,"0x%x",&n); + return n; +} + + +double GetPrivateProfileDouble(const char *sFilename,const char *cHeader, + const char *cLabel,double dfDefault) +{ + char temp[256]; + double n=dfDefault; + + GetPrivateProfileString(sFilename,cHeader,cLabel,temp,"",255); + sscanf(temp,"%lf",&n); + return n; +} + + +int GetIni(const char *sFileName,const char *cHeader,const char *cLabel, + char *cValue,int dValueLength) + /* get a value from the ini file */ + +{ + FILE *cIniName; + char sName[BUFFER_SIZE]; + char cIniBuffer[BUFFER_SIZE],cIniHeader[80],cIniLabel[80]; + int i,j; + /* int iFileStat=NULL; */ + int iFileStat; + + strcpy(sName,sFileName); +#ifdef WIN32 + for(int i=0;i<strlen(sName);i++) { + if(sName[i]=='/') { + sName[i]='\\'; + } + } +#endif // WIN32 + cIniName=fopen(sName,"r"); + if(cIniName==NULL) { + return 2; /* ini file doesn't exist! */ + } + while(GetIniLine(cIniName,cIniBuffer)!=EOF) { + if(cIniBuffer[0]=='[') { /* start of section */ + i=1; + while(cIniBuffer[i]!=']' && cIniBuffer!=0) { + cIniHeader[i-1]=cIniBuffer[i]; + i++; + } + cIniHeader[i-1]=0; + if(strcmp(cIniHeader,cHeader)==0) { /* this is the right section! */ + iFileStat=EOF+1; /* Make this anything other than EOF! */ + while(iFileStat!=EOF) { + iFileStat=GetIniLine(cIniName,cIniBuffer); + if(cIniBuffer[0]=='[') return 1; + i=0; + while(cIniBuffer[i]!='=' && cIniBuffer[i]!=0) { + cIniLabel[i]=cIniBuffer[i]; + i++; + } + cIniLabel[i++]=0; + if(strcmp(cIniLabel,cLabel)==0) { /* this is the right label! */ + j=0; + while(j<dValueLength && cIniBuffer[i]!=0) { + cValue[j++]=cIniBuffer[i++]; + } + cValue[j]=0; + fclose(cIniName); + return 0; /* value found! */ + } + } + } + } + } + fclose(cIniName); + return 1; /* section or label not found! */ +} + + + + +int GetIniLine(FILE *cIniName,char *cIniBuffer) /* read a line from the ini file */ + +{ + int i; + + for(i=0;i<BUFFER_SIZE-1;i++) { + cIniBuffer[i]=getc(cIniName); + switch(cIniBuffer[i]) { + + case 10: + cIniBuffer[i]=0; + return 0; + } + } + return 0; +} + + +void Prepend(char *sPathname,char *sFilename) +{ + char sTemp[256]; + + if(sPathname[strlen(sPathname)-1]!='/' && sFilename[0]!='/') { + strcat(sPathname,"/"); + } + strcpy(sTemp,sPathname); + strcat(sTemp,sFilename); + strcpy(sFilename,sTemp); +} + + +#ifndef WIN32 +int IncrementIndex(char *sPathname,int dMaxIndex) +{ + int dLockname=-1; + FILE *hPathname; + int i; + char sLockname[256]; + char sAccum[256]; + int dIndex,dNewIndex; + + /* Lock the index */ + strcpy(sLockname,sPathname); + strcat(sLockname,".LCK"); + i=0; + while(dLockname<0 && i<MAX_RETRIES) { + dLockname=open(sLockname,O_WRONLY|O_EXCL|O_CREAT,S_IRUSR|S_IWUSR); + i++; + } + if(dLockname<0) { + return -1; + } + sprintf(sAccum,"%d",getpid()); + write(dLockname,sAccum,strlen(sAccum)); + close(dLockname); + + /* We've got the lock, so read the index */ + hPathname=fopen(sPathname,"r"); + if(hPathname==NULL) { + unlink(sLockname); + return -1; + } + if(fscanf(hPathname,"%d",&dIndex)!=1) { + fclose(hPathname); + unlink(sLockname); + return -1; + } + fclose(hPathname); + + /* Update the index */ + if((dIndex<dMaxIndex) || (dMaxIndex==0)) { + dNewIndex=dIndex+1; + } + else { + dNewIndex=1; + } + + /* Write it back */ + hPathname=fopen(sPathname,"w"); + if(hPathname==NULL) { + unlink(sLockname); + return -1; + } + fprintf(hPathname,"%d",dNewIndex); + fclose(hPathname); + + /* Release the lock */ + unlink(sLockname); + + /* Ensure a sane value to return and then exit */ + if((dIndex>dMaxIndex)&&(dMaxIndex!=0)) { + dIndex=1; + } + + return dIndex; +} +#endif + + +/* + * int StripLevel(char *sString) + * + * This strips the lower-most level from the pathname pointed to by 'sString' + */ + +void StripLevel(char *sString) +{ + int i; /* General Purpose Pointer */ + int dString; /* Initial Length of 'sString' */ + + dString=strlen(sString)-1; + for(i=dString;i>=0;i--) { + if(sString[i]=='/') { + sString[i]=0; + return; + } + } + sString[0]=0; +} + + + + +#ifndef WIN32 +bool GetLock(const char *sLockname) +{ + int fd; + char sAccum[256]; + + if((fd=open(sLockname,O_WRONLY|O_EXCL|O_CREAT,S_IRUSR|S_IWUSR))<0) { + printf("failed!\n"); + if(RDCheckPid(RDGetPathPart(sLockname),RDGetBasePart(sLockname))) { + return false; + } + ClearLock(sLockname); + if((fd=open(sLockname,O_WRONLY|O_EXCL|O_CREAT,S_IRUSR|S_IWUSR))<0) { + return false; + } + } + sprintf(sAccum,"%d",getpid()); + write(fd,sAccum,strlen(sAccum)); + close(fd); + return true; +} +#endif + + + + +#ifndef WIN32 +void ClearLock(const char *sLockname) +{ + unlink(sLockname); +} +#endif // WIN32 + + +QString RDGetPathPart(QString path) +{ + int c; + + // c=path.findRev('/'); + c=path.findRev(RDCONF_FILE_SEPARATOR); + if(c<0) { + return QString(""); + } + path.truncate(c+1); + return path; +} + + +QString RDGetBasePart(QString path) +{ + int c; + + // c=path.findRev('/'); + c=path.findRev(RDCONF_FILE_SEPARATOR); + if(c<0) { + return path; + } + path.remove(0,c+1); + return path; +} + + +QString RDGetShortDate(QDate date) +{ + return QString().sprintf("%02d/%02d/%04d", + date.month(),date.day(),date.year()); +} + +QString RDGetShortDayNameEN(int weekday) +{ + QString day_name; + if ( weekday < 1 || weekday > 7 ) + weekday = 1; + + if (weekday == 1) + day_name = "Mon"; + else if (weekday == 2) + day_name = "Tue"; + else if (weekday == 3) + day_name = "Wed"; + else if (weekday == 4) + day_name = "Thu"; + else if (weekday == 5) + day_name = "Fri"; + else if (weekday == 6) + day_name = "Sat"; + else if (weekday == 7) + day_name = "Sun"; + return day_name; +} + +QFont::Weight RDGetFontWeight(QString string) +{ + if(string.contains("Light",false)) { + return QFont::Light; + } + if(string.contains("Normal",false)) { + return QFont::Normal; + } + if(string.contains("DemiBold",false)) { + return QFont::DemiBold; + } + if(string.contains("Bold",false)) { + return QFont::Bold; + } + if(string.contains("Black",false)) { + return QFont::Black; + } + return QFont::Normal; +} + + +#ifndef WIN32 +bool RDDetach(const QString &coredir) +{ + if(!coredir.isEmpty()) { + chdir(coredir); + } + if(daemon(coredir.isEmpty(),0)) { + return false; + } + return true; +} +#endif + + +bool RDBool(QString string) +{ + if(string.contains("Y",false)) { + return true; + } + return false; +} + + +QString RDYesNo(bool state) +{ + if(state) { + return QString("Y"); + } + return QString("N"); +} + + +#ifndef WIN32 +QHostAddress RDGetHostAddr() +{ + FILE *file; + char host_name[256]; + struct hostent *host_ent; + int host_address; + + if((file=fopen("/etc/HOSTNAME","r"))==NULL) { + return QHostAddress(); + } + if(fscanf(file,"%s",host_name)!=1) { + return QHostAddress(); + } + if((host_ent=gethostbyname(host_name))==NULL) { + return QHostAddress(); + } + host_address=16777216*(host_ent->h_addr_list[0][0]&0xff)+ + 65536*(host_ent->h_addr_list[0][1]&0xff)+ + 256*(host_ent->h_addr_list[0][2]&0xff)+ + (host_ent->h_addr_list[0][3]&0xff); + return QHostAddress((Q_UINT32)host_address); +} +#endif // WIN32 + + +QString RDGetDisplay(bool strip_point) +{ +#ifdef WIN32 + return QString("win32"); +#else + QString display; + int l; + + if(getenv("DISPLAY")[0]==':') { + display=QString().sprintf("%s%s",(const char *)RDGetHostAddr().toString(), + getenv("DISPLAY")); + } + else { + display=QString(getenv("DISPLAY")); + } + if(strip_point) { + l=display.length(); + while(display.at(l)!=':') { + if(display.at(l--)=='.') { + return display.left(l+1); + } + } + } + return display; +#endif // WIN32 +} + + +bool RDDoesRowExist(const QString &table,const QString &name, + const QString &test,QSqlDatabase *db) +{ + RDSqlQuery *q; + QString sql; + + sql="select `"+name+"` from `"+table+"` where `"+name+"`="+ + "\""+RDEscapeString(test)+"\""; + q=new RDSqlQuery(sql,db); + if(q->first()) { + delete q; + return true; + } + delete q; + return false; +} + + +bool RDDoesRowExist(const QString &table,const QString &name,unsigned test, + QSqlDatabase *db) +{ + RDSqlQuery *q; + QString sql; + + sql="select `"+name+"` from `"+table+"` where `"+name+"`="+ + QString().sprintf("%d",test); + q=new RDSqlQuery(sql,db); + if(q->size()>0) { + delete q; + return true; + } + delete q; + return false; +} + + +QVariant RDGetSqlValue(const QString &table,const QString &name, + const QString &test,const QString ¶m, + QSqlDatabase *db,bool *valid) +{ + RDSqlQuery *q; + QString sql; + QVariant v; + + sql="select `"+param+"` from `"+table+"` where `"+name+"`="+ + "\""+RDEscapeString(test)+"\""; + q=new RDSqlQuery(sql,db); + if(q->isActive()) { + q->first(); + v=q->value(0); + if(valid!=NULL) { + *valid=!q->isNull(0); + } + delete q; + return v; + } + delete q; + return QVariant(); +} + + +QVariant RDGetSqlValue(const QString &table, + const QString &name1,const QString &test1, + const QString &name2,const QString &test2, + const QString &name3,const QString &test3, + const QString ¶m,QSqlDatabase *db,bool *valid) +{ + RDSqlQuery *q; + QString sql; + QVariant v; + + sql="select `"+param+"` from `"+table+"` where "+ + "(`"+name1+"`=\""+RDEscapeString(test1)+"\")&&"+ + "(`"+name2+"`=\""+RDEscapeString(test1)+"\")&&"+ + "(`"+name3+"`=\""+RDEscapeString(test1)+"\")"; + q=new RDSqlQuery(sql,db); + if(q->isActive()) { + q->first(); + v=q->value(0); + if(valid!=NULL) { + *valid=!q->isNull(0); + } + delete q; + return v; + } + delete q; + return QVariant(); +} + + +bool RDIsSqlNull(const QString &table,const QString &name,const QString &test, + const QString ¶m,QSqlDatabase *db) +{ + RDSqlQuery *q; + QString sql; + + sql="select `"+param+"` from `"+table+"` where `"+name+"`="+ + "\""+RDEscapeString(test)+"\""; + q=new RDSqlQuery(sql,db); + if(q->isActive()) { + q->first(); + if(q->isNull(0)) { + delete q; + return true; + } + else { + delete q; + return false; + } + } + delete q; + return true; +} + + +bool RDIsSqlNull(const QString &table,const QString &name,unsigned test, + const QString ¶m,QSqlDatabase *db) +{ + RDSqlQuery *q; + QString sql; + + sql="select `"+param+"` from `"+table+"` where `"+name+"`="+ + QString().sprintf("%d",test); + q=new RDSqlQuery(sql,db); + if(q->isActive()) { + q->first(); + if(q->isNull(0)) { + delete q; + return true; + } + else { + delete q; + return false; + } + } + delete q; + return true; +} + + +QVariant RDGetSqlValue(const QString &table,const QString &name,unsigned test, + const QString ¶m,QSqlDatabase *db,bool *valid) +{ + RDSqlQuery *q; + QString sql; + QVariant v; + + sql="select `"+param+"` from `"+table+"` where `"+name+"`="+ + QString().sprintf("%u",test); + q=new RDSqlQuery(sql,db); + if(q->first()) { + v=q->value(0); + if(valid!=NULL) { + *valid=!q->isNull(0); + } + delete q; + return v; + } + delete q; + return QVariant(); +} + + +QString RDGetTimeLength(int mseconds,bool leadzero,bool tenths) +{ + int hour,min,seconds,tenthsecs; + char negative[2]; + + if(mseconds<0) { + mseconds=-mseconds; + strcpy(negative,"-"); + } + else { + negative[0]=0; + } + QTime time_length(QTime(0,0,0).addMSecs(mseconds)); + hour = time_length.hour(); + min = time_length.minute(); + seconds = time_length.second(); + mseconds = time_length.msec(); + tenthsecs=mseconds/100; + if(leadzero) { + if(tenths) { + return QString().sprintf("%s%d:%02d:%02d.%d",negative,hour,min,seconds, + tenthsecs); + } + return QString().sprintf("%s%d:%02d:%02d",negative,hour,min,seconds); + } + if((hour==0)&&(min==0)) { + if(tenths) { + return QString().sprintf("%s:%02d.%d",negative,seconds,tenthsecs); + } + return QString().sprintf("%s:%02d",negative,seconds); + } + if(hour==0) { + if(tenths) { + return QString().sprintf("%s%2d:%02d.%d",negative,min,seconds, + tenthsecs); + } + return QString().sprintf("%s%2d:%02d",negative,min,seconds); + } + if(tenths) { + return QString().sprintf("%s%2d:%02d:%02d.%d",negative,hour,min,seconds, + tenthsecs); + } + return QString().sprintf("%s%2d:%02d:%02d",negative,hour,min,seconds); +} + + +int RDSetTimeLength(const QString &str) +{ + int istate=2; + QString field; + int res=0; + bool decimalpt=false; + + if(str.isEmpty()) { + return -1; + } + for(unsigned i=0;i<str.length();i++) { + if(str.at(i)==':') { + istate--; + } + } + if(istate<0) { + return -1; + } + for(unsigned i=0;i<str.length();i++) { + if(str.at(i).isNumber()) { + field+=str.at(i); + } + else { + if((str.at(i)==':')||(str.at(i)=='.')) { + if(field.length()>2) { + return -1; + } + switch(istate) { + case 0: + res+=3600000*field.toInt(); + break; + + case 1: + res+=60000*field.toInt(); + break; + + case 2: + res+=1000*field.toInt(); + break; + } + if(str.at(i)=='.') { + decimalpt=true; + } + istate++; + field=""; + } + else { + if(!str.at(i).isSpace()) { + return -2; + } + } + } + } + switch(istate) { + case 2: + res+=1000*field.toInt(); + break; + + case 3: + switch(field.length()) { + case 1: + res+=100*field.toInt(); + break; + + case 2: + res+=10*field.toInt(); + break; + + case 3: + res+=field.toInt(); + break; + } + } + + return res; +} + + +#ifndef WIN32 +bool RDCopy(const QString &srcfile,const QString &destfile) +{ + int src_fd; + int dest_fd; + struct stat src_stat; + struct stat dest_stat; + char *buf=NULL; + int n; + + if((src_fd=open((const char *)srcfile,O_RDONLY))<0) { + return false; + } + if(fstat(src_fd,&src_stat)<0) { + close(src_fd); + return false; + } + if((dest_fd=open((const char *)destfile,O_RDWR|O_CREAT,src_stat.st_mode)) + <0) { + close(src_fd); + return false; + } + if(fstat(dest_fd,&dest_stat)<0) { + close(src_fd); + close(dest_fd); + return false; + } + buf=(char *)malloc(dest_stat.st_blksize); + while((n=read(src_fd,buf,dest_stat.st_blksize))==dest_stat.st_blksize) { + write(dest_fd,buf,dest_stat.st_blksize); + } + write(dest_fd,buf,n); + free(buf); + close(src_fd); + close(dest_fd); + return true; +} +#endif // WIN32 + + +#ifndef WIN32 +bool RDWritePid(const QString &dirname,const QString &filename,int owner, + int group) +{ + FILE *file; + mode_t prev_mask; + QString pathname=QString().sprintf("%s/%s", + (const char *)dirname, + (const char *)filename); + + prev_mask = umask(0113); // Set umask so pid files are user and group writable. + file=fopen((const char *)pathname,"w"); + umask(prev_mask); + if(file==NULL) { + return false; + } + fprintf(file,"%d",getpid()); + fclose(file); + chown((const char *)pathname,owner,group); + + return true; +} + + +void RDDeletePid(const QString &dirname,const QString &filename) +{ + QString pid=QString().sprintf("%s/%s", + (const char *)dirname, + (const char *)filename); + unlink((const char *)pid); +} + + +bool RDCheckPid(const QString &dirname,const QString &filename) +{ + QDir dir; + QString path; + path=QString("/proc/")+ + QString().sprintf("%d",RDGetPid(dirname+QString("/")+filename)); + dir.setPath(path); + return dir.exists(); +} + + +pid_t RDGetPid(const QString &pidfile) +{ + FILE *handle; + pid_t ret; + + if((handle=fopen((const char *)pidfile,"r"))==NULL) { + return -1; + } + if(fscanf(handle,"%d",&ret)!=1) { + ret=-1; + } + fclose(handle); + return ret; +} + + +bool RDTimeSynced() +{ + struct timex timex; + + memset(&timex,0,sizeof(struct timex)); + if(adjtimex(&timex)==TIME_OK) { + return true; + } + return false; +} +#endif // WIN32 + + +QString RDGetHomeDir(bool *found) +{ + if(getenv("HOME")==NULL) { + if(found!=NULL) { + *found=false; + } + return QString("/"); + } + if(found!=NULL) { + *found=true; + } + return QString(getenv("HOME")); +} + + +QString RDTruncateAfterWord(QString str,int word,bool add_dots) +{ + QString simple=str.simplifyWhiteSpace(); + int quan=0; + int point; + + for(unsigned i=0;i<simple.length();i++) { + if(simple.at(i).isSpace()) { + quan++; + point=i; + if(quan==word) { + if(add_dots) { + return simple.left(point)+QString("..."); + } + else { + return simple.left(point); + } + } + } + } + return simple; +} + + +QString RDHomeDir() +{ + if(getenv("HOME")==NULL) { + return QString("/"); + } + return QString(getenv("HOME")); +} + + +QString RDTempDir() +{ +#ifdef WIN32 + if(getenv("TEMP")!=NULL) { + return QString(getenv("TEMP")); + } + if(getenv("TMP")!=NULL) { + return QString(getenv("TMP")); + } + return QString("C:\\"); +#else + if(getenv("TMPDIR")!=NULL) { + return QString(getenv("TMPDIR")); + } + return QString("/tmp"); +#endif // WIN32 +} + + +QString RDTempFile() +{ +#ifndef WIN32 + return QString(tmpnam(NULL)); +#endif // WIN32 + return QString(); +} + + +#ifndef WIN32 +QString RDTimeZoneName(const QDateTime &datetime) +{ + char name[20]; + time_t time=datetime.toTime_t(); + strftime(name,20,"%Z",localtime(&time)); + return QString(name); +} +#endif // WIN32 + + +QString RDDowCode(int dow) +{ + QString ret; + switch(dow) { + case 1: + ret=QString("MON"); + break; + + case 2: + ret=QString("TUE"); + break; + + case 3: + ret=QString("WED"); + break; + + case 4: + ret=QString("THU"); + break; + + case 5: + ret=QString("FRI"); + break; + + case 6: + ret=QString("SAT"); + break; + + case 7: + ret=QString("SUN"); + break; + } + return ret; +} + + +QDateTime RDLocalToUtc(const QDateTime &localdatetime) +{ + return localdatetime.addSecs(RDTimeZoneOffset()); +} + + +QTime RDLocalToUtc(const QTime &localtime) +{ + return localtime.addSecs(RDTimeZoneOffset()); +} + + +QDateTime RDUtcToLocal(const QDateTime &gmtdatetime) +{ + return gmtdatetime.addSecs(-RDTimeZoneOffset()); +} + + +QTime RDUtcToLocal(const QTime &gmttime) +{ + return gmttime.addSecs(-RDTimeZoneOffset()); +} + + +int RDTimeZoneOffset() +{ +#ifdef WIN32 + return 0; +#else + time_t t=time(&t); + struct tm *tm=localtime(&t); + time_t local_time=3600*tm->tm_hour+60*tm->tm_min+tm->tm_sec; + tm=gmtime(&t); + time_t gmt_time=3600*tm->tm_hour+60*tm->tm_min+tm->tm_sec; + + return gmt_time-local_time; +#endif // WIN32 +} + + +QColor RDGetTextColor(const QColor &background_color) +{ + int h,s,v; + QColor color=background_color; + + background_color.getHsv(&h,&s,&v); + if(v<128) { + color=Qt::white; + } + else { + if((h>210)&&(h<270)&&(s>128)) { // Special case for blue + color=Qt::white; + } + else { + color=Qt::black; + } + } + + return color; +} + + +bool RDProcessActive(const QString &cmd) +{ + QStringList cmds; + + cmds.push_back(cmd); + return RDProcessActive(cmds); +} + + +bool RDProcessActive(const QStringList &cmds) +{ +#ifndef WIN32 + QStringList dirs; + QDir *proc_dir=new QDir("/proc"); + bool ok=false; + FILE *f=NULL; + char line[1024]; + QString cmdline; + + proc_dir->setFilter(QDir::Dirs); + dirs=proc_dir->entryList(); + for(unsigned i=0;i<dirs.size();i++) { + dirs[i].toInt(&ok); + if(ok) { + if((f=fopen(QString("/proc/")+dirs[i]+"/cmdline","r"))!=NULL) { + if(fgets(line,1024,f)!=NULL) { + QStringList f1=f1.split(" ",QString(line)); + QStringList f2=f2.split("/",f1[0]); + cmdline=f2[f2.size()-1]; + for(unsigned j=0;j<cmds.size();j++) { + if(cmdline==cmds[j]) { + fclose(f); + return true; + } + } + } + fclose(f); + } + } + } + + delete proc_dir; +#endif // WIN32 + return false; +} + + +bool RDModulesActive() +{ + QStringList cmds; + + cmds.push_back("rdadmin"); + cmds.push_back("rdairplay"); + cmds.push_back("rdcastmanager"); + cmds.push_back("rdcatch"); + cmds.push_back("rdlibrary"); + cmds.push_back("rdlogedit"); + cmds.push_back("rdlogin"); + cmds.push_back("rdlogmanager"); + cmds.push_back("rdpanel"); + cmds.push_back("rddbcheck"); + cmds.push_back("rdgpimon"); + return RDProcessActive(cmds); +} + + +QByteArray RDStringToData(const QString &str) +{ + QByteArray ret; +#ifndef WIN32 + int istate=0; + QString hexcode=""; + + for(unsigned i=0;i<str.length();i++) { + switch(istate) { + case 0: + if((str.at(i)=='%')&&(i<(str.length()-2))) { + hexcode=""; + istate=1; + } + else { + ret.resize(ret.size()+1); + ret[ret.size()-1]=str.at(i); + } + break; + + case 1: + hexcode=str.at(i); + istate=2; + break; + + case 2: + hexcode+=str.at(i); + ret.resize(ret.size()+1); + ret[ret.size()-1]=0xFF&hexcode.toUInt(NULL,16); + istate=0; + break; + + default: + istate=0; + break; + } + } +#endif // WIN32 + return ret; +} diff --git a/lib/rdconf.h b/lib/rdconf.h new file mode 100644 index 00000000..1d50ea99 --- /dev/null +++ b/lib/rdconf.h @@ -0,0 +1,118 @@ +// rdconf.h +// +// The header file for the rconf package +// +// (C) Copyright 1996-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdconf.h,v 1.10.6.3 2013/12/03 23:34:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCONF_H +#define RDCONF_H + +#define MAX_RETRIES 10 +#include <stdlib.h> +#include <stdio.h> + +#include <qstring.h> +#include <qdatetime.h> +#include <qfont.h> +#include <qhostaddress.h> +#include <qsqldatabase.h> +#include <qvariant.h> +#include <qdatetime.h> +#include <qcolor.h> +#include <qstringlist.h> +#include <qcstring.h> + +/* Function Prototypes */ +int GetPrivateProfileBool(const char *,const char *,const char *,bool); +int GetPrivateProfileString(const char *,const char *,const char *,char *, + const char *,int); +int GetPrivateProfileInt(const char *,const char *,const char *,int); +int GetPrivateProfileHex(const char *,const char *,const char *,int); +double GetPrivateProfileDouble(const char *,const char *,const char *,double); +int GetIni(const char *,const char *,const char *,char *,int); +int GetIniLine(FILE *,char *); +void Prepend(char *,char *); +int IncrementIndex(char *,int); +void StripLevel(char *); +bool GetLock(const char *); +void ClearLock(const char *); +QString RDGetPathPart(QString path); +QString RDGetBasePart(QString path); +QString RDGetShortDate(QDate); +/** + * Returns the name of the weekday in english regardless of the locale + * configured. + * @param weekday Integer value for the weekday; 1 = "Mon", 2 = "Tue", + * ... 7 = "Sun". If the value is out of range 1 is defaulted to. + **/ +QString RDGetShortDayNameEN(int weekday); +QFont::Weight RDGetFontWeight(QString); +bool RDDetach(const QString &coredir); +bool RDBool(QString); +QString RDYesNo(bool); +QHostAddress RDGetHostAddr(); +QString RDGetDisplay(bool strip_point=false); +bool RDDoesRowExist(const QString &table,const QString &name, + const QString &test,QSqlDatabase *db=0); +bool RDDoesRowExist(const QString &table,const QString &name,unsigned test, + QSqlDatabase *db=0); +QVariant RDGetSqlValue(const QString &table,const QString &name, + const QString &test,const QString ¶m, + QSqlDatabase *db=0,bool *valid=0); +QVariant RDGetSqlValue(const QString &table,const QString &name,unsigned test, + const QString ¶m,QSqlDatabase *db=0,bool *valid=0); +QVariant RDGetSqlValue(const QString &table, + const QString &name1,const QString &test1, + const QString &name2,const QString &test2, + const QString &name3,const QString &test3, + const QString ¶m,QSqlDatabase *db=0,bool *valid=0); +bool RDIsSqlNull(const QString &table,const QString &name, + const QString &test,const QString ¶m,QSqlDatabase *db=0); +bool RDIsSqlNull(const QString &table,const QString &name,unsigned test, + const QString ¶m,QSqlDatabase *db=0); +QString RDGetTimeLength(int mseconds,bool leadzero=false,bool tenths=true); +int RDSetTimeLength(const QString &string); +bool RDCopy(const QString &srcfile,const QString &destfile); +#ifndef WIN32 +bool RDWritePid(const QString &dirname,const QString &filename,int owner=-1, + int group=-1); +void RDDeletePid(const QString &dirname,const QString &filename); +bool RDCheckPid(const QString &dirname,const QString &filename); +pid_t RDGetPid(const QString &pidfile); +#endif // WIN32 +QString RDGetHomeDir(bool *found=0); +bool RDTimeSynced(); +QString RDTruncateAfterWord(QString str,int word,bool add_dots=false); +QString RDHomeDir(); +QString RDTempDir(); +QString RDTempFile(); +QString RDTimeZoneName(const QDateTime &datetime); +QString RDDowCode(int dow); +QDateTime RDLocalToUtc(const QDateTime &localdatetime); +QTime RDLocalToUtc(const QTime &localtime); +QDateTime RDUtcToLocal(const QDateTime &gmtdatetime); +QTime RDUtcToLocal(const QTime &gmttime); +int RDTimeZoneOffset(); +QColor RDGetTextColor(const QColor &background_color); +bool RDProcessActive(const QString &cmd); +bool RDProcessActive(const QStringList &cmds); +bool RDModulesActive(); +QByteArray RDStringToData(const QString &str); + +#endif // RDCONF_H diff --git a/lib/rdconfig.cpp b/lib/rdconfig.cpp new file mode 100644 index 00000000..ac0cd76b --- /dev/null +++ b/lib/rdconfig.cpp @@ -0,0 +1,562 @@ +// rdconfig.cpp +// +// A container class for a Rivendell Base Configuration +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdconfig.cpp,v 1.24.6.7 2013/11/13 23:36:32 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WIN32 +#include <sys/types.h> +#include <sys/stat.h> +#include <pwd.h> +#include <grp.h> +#endif + +#include <qmessagebox.h> +#include <qsettings.h> +#include <qstringlist.h> + +#include <rdprofile.h> +#include <rdconfig.h> + + +RDConfig *RDConfiguration(void) +{ + static RDConfig *config = NULL; + if (!config){ + config = new RDConfig(); + config->load(); + } + return config; +} + + +RDConfig::RDConfig() +{ + clear(); +} + + +RDConfig::RDConfig(QString filename) +{ + clear(); + conf_filename=filename; +} + + +QString RDConfig::filename() const +{ + return conf_filename; +} + + +void RDConfig::setFilename(QString filename) +{ + conf_filename=filename; +} + +QString RDConfig::audioRoot() const +{ + return conf_audio_root; +} + +QString RDConfig::audioExtension() const +{ + return conf_audio_extension; +} + +QString RDConfig::audioFileName (QString cutname) +{ + return audioRoot() + QString("/") + cutname + QString(".") + + audioExtension(); +}; + +QString RDConfig::label() const +{ + return conf_label; +} + +QString RDConfig::audioStoreMountSource() const +{ + return conf_audio_store_mount_source; +} + +QString RDConfig::audioStoreMountType() const +{ + return conf_audio_store_mount_type; +} + +QString RDConfig::audioStoreMountOptions() const +{ + return conf_audio_store_mount_options; +} + + +QString RDConfig::audioStoreCaeHostname() const +{ + return conf_audio_store_cae_hostname; +} + + +QString RDConfig::audioStoreXportHostname() const +{ + return conf_audio_store_xport_hostname; +} + + +QString RDConfig::mysqlHostname() const +{ + return conf_mysql_hostname; +} + +QString RDConfig::mysqlUsername() const +{ + return conf_mysql_username; +} + + +QString RDConfig::mysqlDbname() const +{ + return conf_mysql_dbname; +} + + +QString RDConfig::mysqlPassword() const +{ + return conf_mysql_password; +} + + +QString RDConfig::mysqlDriver() const +{ + return conf_mysql_driver; +} + + +int RDConfig::mysqlHeartbeatInterval() const +{ + return conf_mysql_heartbeat_interval; +} + + +RDConfig::LogFacility RDConfig::logFacility() const +{ + return conf_log_facility; +} + + +QString RDConfig::logDirectory() const +{ + return conf_log_directory; +} + + +QString RDConfig::logCoreDumpDirectory() const +{ + return conf_log_core_dump_directory; +} + + +QString RDConfig::logPattern() const +{ + return conf_log_pattern; +} + + +bool RDConfig::logXloadDebugData() const +{ + return conf_log_xload_debug_data; +} + + +void RDConfig::log(const QString &module,LogPriority prio,const QString &msg) +{ +#ifndef WIN32 + QDateTime dt; + QString filename; + FILE *f=NULL; + + switch(conf_log_facility) { + case RDConfig::LogSyslog: + syslog((int)prio,"%s",(const char *)msg); + break; + + case RDConfig::LogFile: + if(conf_log_directory.isEmpty()||conf_log_pattern.isEmpty()) { + return; + } + filename=QString().sprintf("%s/%s",(const char *)conf_log_directory, + (const char *)conf_log_pattern); + dt=QDateTime(QDate::currentDate(),QTime::currentTime()); + filename.replace("%n",module); + filename.replace("%d",dt.date().toString("dd")); + filename.replace("%M",dt.date().toString("MM")); + filename.replace("%Y",dt.date().toString("yyyy")); + filename.replace("%h",dt.time().toString("hh")); + filename.replace("%m",dt.time().toString("mm")); + filename.replace("%s",dt.time().toString("ss")); + if((f=fopen(filename,"a"))!=NULL) { + fprintf(f,"%s: %s\n",(const char *)dt. + toString("dd/MM/yyyy - hh:mm:ss.zzz "), + (const char *)msg); + fclose(f); + } + chmod(filename,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); + chown(filename,uid(),gid()); + break; + + case RDConfig::LogNone: + break; + } +#endif // WIN32 +} + + +int RDConfig::alsaPeriodQuantity() const +{ + return conf_alsa_period_quantity; +} + + +int RDConfig::alsaPeriodSize() const +{ + return conf_alsa_period_size; +} + + +int RDConfig::alsaChannelsPerPcm() const +{ + return conf_alsa_channels_per_pcm; +} + + +QString RDConfig::stationName() const +{ + return conf_station_name; +} + + +QString RDConfig::password() const +{ + return conf_password; +} + + +QString RDConfig::audioOwner() const +{ + return conf_audio_owner; +} + + +QString RDConfig::audioGroup() const +{ + return conf_audio_group; +} + + +QString RDConfig::ripcdLogname() const +{ + return conf_ripcd_logname; +} + + +QString RDConfig::airplayLogname() const +{ + return conf_airplay_logname; +} + + +QString RDConfig::catchdLogname() const +{ + return conf_catchd_logname; +} + + +int RDConfig::jackConnections() const +{ + return conf_jack_ports[0].size(); +} + + +QString RDConfig::jackPort(int num,int endpt) const +{ + return conf_jack_ports[num][endpt]; +} + + +bool RDConfig::useStreamMeters() const +{ + return conf_use_stream_meters; +} + + +bool RDConfig::disableMaintChecks() const +{ + return conf_disable_maint_checks; +} + + +unsigned RDConfig::channels() const +{ + return conf_channels; +} + + +#ifndef WIN32 +uid_t RDConfig::uid() const +{ + return conf_uid; +} + + +gid_t RDConfig::gid() const +{ + return conf_gid; +} +#endif + + +QString RDConfig::caeLogfile() const +{ + return conf_cae_logfile; +} + + +bool RDConfig::enableMixerLogging() const +{ + return conf_enable_mixer_logging; +} + + +bool RDConfig::useRealtime() +{ + return conf_use_realtime; +} + + +int RDConfig::realtimePriority() +{ + return conf_realtime_priority; +} + + +QString RDConfig::sasStation() const +{ + return conf_sas_station; +} + + +int RDConfig::sasMatrix() const +{ + return conf_sas_matrix; +} + + +unsigned RDConfig::sasBaseCart() const +{ + return conf_sas_base_cart; +} + + +QString RDConfig::sasTtyDevice() const +{ + return conf_sas_tty_device; +} + + +QString RDConfig::destination(unsigned n) +{ + if(n>=conf_destinations.size()) { + return QString(); + } + return conf_destinations[n]; +} + + +void RDConfig::load() +{ + char sname[256]; + QString client; + QString facility; +#ifndef WIN32 + struct passwd *user; + struct group *groups; +#endif + + RDProfile *profile=new RDProfile(); + profile->setSource(conf_filename); +#ifdef WIN32 + strcpy(sname,"windows"); +#else + gethostname(sname,255); + QStringList list=list.split(".",sname); // Strip domain name parts + strncpy(sname,list[0],256); +#endif + conf_station_name= + profile->stringValue("Identity","StationName",sname); + conf_password=profile->stringValue("Identity","Password",""); + conf_audio_owner= + profile->stringValue("Identity","AudioOwner",RD_DEFAULT_AUDIO_OWNER); + conf_audio_group= + profile->stringValue("Identity","AudioGroup",RD_DEFAULT_AUDIO_GROUP); + conf_label=profile->stringValue("Identity","Label",RD_DEFAULT_LABEL); + + conf_audio_store_mount_source= + profile->stringValue("AudioStore","MountSource"); + conf_audio_store_mount_type= + profile->stringValue("AudioStore","MountType"); + conf_audio_store_mount_options= + profile->stringValue("AudioStore","MountOptions", + RD_DEFAULT_AUDIO_STORE_MOUNT_OPTIONS); + conf_audio_store_cae_hostname= + profile->stringValue("AudioStore","CaeHostname","localhost"); + conf_audio_store_xport_hostname= + profile->stringValue("AudioStore","XportHostname","localhost"); + + conf_audio_root= + profile->stringValue("Cae","AudioRoot",RD_AUDIO_ROOT); + conf_audio_extension= + profile->stringValue("Cae","AudioExtension",RD_AUDIO_EXTENSION); + conf_mysql_hostname= + profile->stringValue("mySQL","Hostname",DEFAULT_MYSQL_HOSTNAME); + conf_mysql_username= + profile->stringValue("mySQL","Loginname",DEFAULT_MYSQL_USERNAME); + conf_mysql_dbname= + profile->stringValue("mySQL","Database",DEFAULT_MYSQL_DATABASE); + conf_mysql_password=profile->stringValue("mySQL","Password",conf_password); + conf_mysql_driver= + profile->stringValue("mySQL","Driver",DEFAULT_MYSQL_DRIVER); + conf_mysql_heartbeat_interval= + profile->intValue("mySQL","HeartbeatInterval", + DEFAULT_MYSQL_HEARTBEAT_INTERVAL); + + facility=profile->stringValue("Logs","Facility",DEFAULT_LOG_FACILITY).lower(); + if(facility=="syslog") { + conf_log_facility=RDConfig::LogSyslog; + } + if(facility=="file") { + conf_log_facility=RDConfig::LogFile; + } + conf_log_directory=profile->stringValue("Logs","LogDirectory",""); + conf_log_pattern=profile->stringValue("Logs","LogPattern", + DEFAULT_LOG_PATTERN); + conf_log_xload_debug_data=profile-> + boolValue("Logs","LogXloadDebugData",false); + conf_log_core_dump_directory= + profile->stringValue("Logs","CoreDumpDirectory", + DEFAULT_LOG_CORE_DUMP_DIRECTORY); + + conf_alsa_period_quantity= + profile->intValue("Alsa","PeriodQuantity",RD_ALSA_DEFAULT_PERIOD_QUANTITY); + conf_alsa_period_size= + profile->intValue("Alsa","PeriodSize",RD_ALSA_DEFAULT_PERIOD_SIZE); + conf_alsa_channels_per_pcm=profile->intValue("Alsa","ChannelsPerPcm",-1); + conf_ripcd_logname=profile->stringValue("Ripcd","Logfile",""); + conf_airplay_logname=profile->stringValue("RDAirPlay","Logfile",""); + conf_catchd_logname=profile->stringValue("RDCatchd","Logfile",""); + conf_use_stream_meters=profile->boolValue("Hacks","UseStreamMeters",false); + conf_disable_maint_checks= + profile->boolValue("Hacks","DisableMaintChecks",false); + conf_channels=profile->intValue("Format","Channels",RD_DEFAULT_CHANNELS); +#ifndef WIN32 + if((user=getpwnam(profile->stringValue("Identity","AudioOwner")))!=NULL) { + conf_uid=user->pw_uid; + } + if((groups=getgrnam(profile->stringValue("Identity","AudioGroup")))!=NULL) { + conf_gid=groups->gr_gid; + } +#endif + conf_cae_logfile=profile->stringValue("Caed","Logfile",""); + conf_enable_mixer_logging=profile->boolValue("Caed","EnableMixerLogging"); + conf_use_realtime=profile->boolValue("Tuning","UseRealtime",false); + conf_realtime_priority=profile->intValue("Tuning","RealtimePriority",9); + conf_sas_station=profile->stringValue("SASFilter","Station",""); + conf_sas_matrix=profile->intValue("SASFilter","Matrix",0); + conf_sas_base_cart=profile->intValue("SASFilter","BaseCart",0); + conf_sas_tty_device=profile->stringValue("SASFilter","TtyDevice",""); + int c=1; + QString dest; + while(!(dest=profile-> + stringValue("RDBackup",QString(). + sprintf("Destination%d",c++),"")).isEmpty()) { + conf_destinations.push_back(dest); + } + delete profile; +} + + +void RDConfig::clear() +{ +#ifdef WIN32 + QSettings settings; + settings.insertSearchPath(QSettings::Windows,"/SalemRadioLabs"); + conf_filename=QString().sprintf("%s\\%s", + (const char *)settings. + readEntry("/Rivendell/InstallDir"), + (const char *)RD_WIN_CONF_FILE); +#else + conf_filename=RD_CONF_FILE; +#endif + conf_mysql_hostname=""; + conf_mysql_username=""; + conf_mysql_dbname=""; + conf_mysql_password=""; + conf_mysql_driver=""; + conf_mysql_heartbeat_interval=DEFAULT_MYSQL_HEARTBEAT_INTERVAL; + conf_log_facility=RDConfig::LogSyslog; + conf_log_directory=""; + conf_log_core_dump_directory=DEFAULT_LOG_CORE_DUMP_DIRECTORY; + conf_log_pattern=DEFAULT_LOG_PATTERN; + conf_log_xload_debug_data=false; + conf_alsa_period_quantity=RD_ALSA_DEFAULT_PERIOD_QUANTITY; + conf_alsa_period_size=RD_ALSA_DEFAULT_PERIOD_SIZE; + conf_alsa_channels_per_pcm=-1; + conf_station_name=""; + conf_password=""; + conf_audio_owner=""; + conf_audio_group=""; + conf_audio_root=RD_AUDIO_ROOT; + conf_audio_extension=RD_AUDIO_EXTENSION; + conf_label=RD_DEFAULT_LABEL; + conf_audio_store_mount_source=""; + conf_audio_store_mount_type=""; + conf_audio_store_mount_options=RD_DEFAULT_AUDIO_STORE_MOUNT_OPTIONS; + conf_audio_store_xport_hostname=""; + conf_audio_store_cae_hostname=""; + conf_ripcd_logname=""; + conf_airplay_logname=""; + conf_catchd_logname=""; + conf_jack_ports[0].clear(); + conf_jack_ports[1].clear(); + conf_use_stream_meters=false; + conf_disable_maint_checks=false; + conf_channels=RD_DEFAULT_CHANNELS; +#ifndef WIN32 + conf_uid=65535; + conf_gid=65535; +#endif + conf_cae_logfile=""; + conf_enable_mixer_logging=false; + conf_use_realtime=false; + conf_realtime_priority=9; + conf_sas_station=""; + conf_sas_matrix=-1; + conf_sas_base_cart=1; + conf_sas_tty_device=""; + conf_destinations.clear(); +} diff --git a/lib/rdconfig.h b/lib/rdconfig.h new file mode 100644 index 00000000..9b2ff5df --- /dev/null +++ b/lib/rdconfig.h @@ -0,0 +1,160 @@ +// rdconfig.h +// +// A container class for a Rivendell Base Configuration +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdconfig.h,v 1.18.8.7 2013/11/13 23:36:32 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCONFIG_H +#define RDCONFIG_H + +#ifndef WIN32 +#include <syslog.h> +#include <unistd.h> +#endif // WIN32 + +#include <vector> + +#include <qstring.h> + +#include <rd.h> + + +class RDConfig +{ + public: + enum LogFacility {LogNone=0,LogSyslog=1,LogFile=2}; +#ifdef WIN32 + enum LogPriority {LogEmerg=0,LogAlert=1,LogCrit=2, + LogErr=3,LogWarning=4,LogNotice=5, + LogInfo=6,LogDebug=7}; +#else + enum LogPriority {LogEmerg=LOG_EMERG,LogAlert=LOG_ALERT,LogCrit=LOG_CRIT, + LogErr=LOG_ERR,LogWarning=LOG_WARNING,LogNotice=LOG_NOTICE, + LogInfo=LOG_INFO,LogDebug=LOG_DEBUG}; + +#endif // WIN32 + RDConfig(); + RDConfig(QString filename); + QString filename() const; + void setFilename(QString filename); + QString mysqlHostname() const; + QString mysqlUsername() const; + QString mysqlDbname() const; + QString mysqlPassword() const; + QString mysqlDriver() const; + int mysqlHeartbeatInterval() const; + RDConfig::LogFacility logFacility() const; + QString logDirectory() const; + QString logCoreDumpDirectory() const; + QString logPattern() const; + bool logXloadDebugData() const; + void log(const QString &module,LogPriority prio,const QString &msg); + int alsaPeriodQuantity() const; + int alsaPeriodSize() const; + int alsaChannelsPerPcm() const; + QString stationName() const; + QString password() const; + QString audioOwner() const; + QString audioGroup() const; + QString audioRoot() const; + QString audioExtension() const; + QString audioFileName (QString cutname); + QString label() const; + QString audioStoreMountSource() const; + QString audioStoreMountType() const; + QString audioStoreMountOptions() const; + QString audioStoreCaeHostname() const; + QString audioStoreXportHostname() const; + QString ripcdLogname() const; + QString airplayLogname() const; + QString catchdLogname() const; + int jackConnections() const; + QString jackPort(int num,int endpt) const; + bool useStreamMeters() const; + bool disableMaintChecks() const; + QString caeLogfile() const; + bool enableMixerLogging() const; + unsigned channels() const; +#ifndef WIN32 + uid_t uid() const; + gid_t gid() const; +#endif + bool useRealtime(); + int realtimePriority(); + QString sasStation() const; + int sasMatrix() const; + unsigned sasBaseCart() const; + QString sasTtyDevice() const; + QString destination(unsigned n); + void load(); + void clear(); + + private: + QString conf_filename; + QString conf_mysql_hostname; + QString conf_mysql_username; + QString conf_mysql_dbname; + QString conf_mysql_password; + QString conf_mysql_driver; + int conf_mysql_heartbeat_interval; + RDConfig::LogFacility conf_log_facility; + QString conf_log_directory; + QString conf_log_core_dump_directory; + QString conf_log_pattern; + bool conf_log_xload_debug_data; + int conf_alsa_period_quantity; + int conf_alsa_period_size; + int conf_alsa_channels_per_pcm; + QString conf_station_name; + QString conf_password; + QString conf_audio_owner; + QString conf_audio_group; + QString conf_audio_root; + QString conf_audio_extension; + QString conf_label; + QString conf_audio_store_mount_source; + QString conf_audio_store_mount_type; + QString conf_audio_store_mount_options; + QString conf_audio_store_xport_hostname; + QString conf_audio_store_cae_hostname; + QString conf_ripcd_logname; + QString conf_airplay_logname; + QString conf_catchd_logname; + bool conf_use_stream_meters; + bool conf_disable_maint_checks; + std::vector<QString> conf_jack_ports[2]; + unsigned conf_channels; +#ifndef WIN32 + uid_t conf_uid; + gid_t conf_gid; +#endif + QString conf_cae_logfile; + bool conf_enable_mixer_logging; + bool conf_use_realtime; + int conf_realtime_priority; + QString conf_sas_station; + int conf_sas_matrix; + unsigned conf_sas_base_cart; + QString conf_sas_tty_device; + std::vector<QString> conf_destinations; +}; + +RDConfig *RDConfiguration(void); + +#endif // RDCONFIG_H diff --git a/lib/rdcopyaudio.cpp b/lib/rdcopyaudio.cpp new file mode 100644 index 00000000..9f0ce7c2 --- /dev/null +++ b/lib/rdcopyaudio.cpp @@ -0,0 +1,183 @@ +// rdcopyaudio.cpp +// +// Get the trim points for an audio cut. +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcopyaudio.cpp,v 1.3.4.1 2013/11/13 23:36:32 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> + +#include <curl/curl.h> + +#include <qstringlist.h> +#include <qobject.h> + +#include <rd.h> +#include <rdxport_interface.h> +#include <rdformpost.h> +#include <rdcopyaudio.h> + +RDCopyAudio::RDCopyAudio(RDStation *station,RDConfig *config) +{ + conv_station=station; + conv_config=config; + conv_source_cart_number=0; + conv_source_cut_number=0; + conv_destination_cart_number=0; + conv_destination_cut_number=0; +} + + +void RDCopyAudio::setSourceCartNumber(unsigned cartnum) +{ + conv_source_cart_number=cartnum; +} + + +void RDCopyAudio::setSourceCutNumber(unsigned cutnum) +{ + conv_source_cut_number=cutnum; +} + + +void RDCopyAudio::setDestinationCartNumber(unsigned cartnum) +{ + conv_destination_cart_number=cartnum; +} + + +void RDCopyAudio::setDestinationCutNumber(unsigned cutnum) +{ + conv_destination_cut_number=cutnum; +} + + +RDCopyAudio::ErrorCode RDCopyAudio::runCopy(const QString &username, + const QString &password) +{ + long response_code; + CURL *curl=NULL; + char url[1024]; + + // + // Generate POST Data + // + QString post=QString().sprintf("COMMAND=%d&LOGIN_NAME=%s&PASSWORD=%s&SOURCE_CART_NUMBER=%u&SOURCE_CUT_NUMBER=%u&DESTINATION_CART_NUMBER=%u&DESTINATION_CUT_NUMBER=%u", + RDXPORT_COMMAND_COPYAUDIO, + (const char *)RDFormPost::urlEncode(username), + (const char *)RDFormPost::urlEncode(password), + conv_source_cart_number, + conv_source_cut_number, + conv_destination_cart_number, + conv_destination_cut_number); + if((curl=curl_easy_init())==NULL) { + return RDCopyAudio::ErrorInternal; + } + + // + // Write out URL as a C string before passing to curl_easy_setopt(), + // otherwise some versions of LibCurl will throw a 'bad/illegal format' + // error. + // + strncpy(url,conv_station->webServiceUrl(conv_config),1024); + curl_easy_setopt(curl,CURLOPT_URL,url); + curl_easy_setopt(curl,CURLOPT_POST,1); + curl_easy_setopt(curl,CURLOPT_POSTFIELDS,(const char *)post); + curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT); + + switch(curl_easy_perform(curl)) { + case CURLE_OK: + break; + + case CURLE_UNSUPPORTED_PROTOCOL: + case CURLE_FAILED_INIT: + case CURLE_COULDNT_RESOLVE_PROXY: + case CURLE_PARTIAL_FILE: + case CURLE_HTTP_RETURNED_ERROR: + case CURLE_WRITE_ERROR: + case CURLE_OUT_OF_MEMORY: + case CURLE_OPERATION_TIMEDOUT: + case CURLE_HTTP_POST_ERROR: + curl_easy_cleanup(curl); + return RDCopyAudio::ErrorInternal; + + case CURLE_URL_MALFORMAT: + case CURLE_COULDNT_RESOLVE_HOST: + case CURLE_COULDNT_CONNECT: + case 9: // CURLE_REMOTE_ACCESS_DENIED: + curl_easy_cleanup(curl); + return RDCopyAudio::ErrorUrlInvalid; + } + curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&response_code); + curl_easy_cleanup(curl); + + switch(response_code) { + case 200: + break; + + case 400: + return RDCopyAudio::ErrorInternal; + + case 404: + return RDCopyAudio::ErrorNoCart; + + default: + return RDCopyAudio::ErrorService; + } + + return RDCopyAudio::ErrorOk; +} + + +QString RDCopyAudio::errorText(RDCopyAudio::ErrorCode err) +{ + QString ret=QString().sprintf("Uknown Error [%u]",err); + + switch(err) { + case RDCopyAudio::ErrorOk: + ret=QObject::tr("OK"); + break; + + case RDCopyAudio::ErrorNoCart: + ret=QObject::tr("No such cart"); + break; + + case RDCopyAudio::ErrorInternal: + ret=QObject::tr("Internal Error"); + break; + + case RDCopyAudio::ErrorUrlInvalid: + ret=QObject::tr("Invalid URL"); + break; + + case RDCopyAudio::ErrorService: + ret=QObject::tr("RDXport service returned an error"); + break; + + case RDCopyAudio::ErrorInvalidUser: + ret=QObject::tr("Invalid user or password"); + break; + } + return ret; +} diff --git a/lib/rdcopyaudio.h b/lib/rdcopyaudio.h new file mode 100644 index 00000000..f38e76f7 --- /dev/null +++ b/lib/rdcopyaudio.h @@ -0,0 +1,53 @@ +// rdcopyaudio.h +// +// Copy an audio file in the audio store. +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcopyaudio.h,v 1.1.6.1 2013/11/13 23:36:32 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCOPYAUDIO_H +#define RDCOPYAUDIO_H + +#include <rdconfig.h> +#include <rdstation.h> + +class RDCopyAudio +{ + public: + enum ErrorCode {ErrorOk=0,ErrorNoCart=1,ErrorInternal=5,ErrorUrlInvalid=7, + ErrorService=8,ErrorInvalidUser=9}; + RDCopyAudio(RDStation *station,RDConfig *config); + void setSourceCartNumber(unsigned cartnum); + void setSourceCutNumber(unsigned cutnum); + void setDestinationCartNumber(unsigned cartnum); + void setDestinationCutNumber(unsigned cutnum); + RDCopyAudio::ErrorCode runCopy(const QString &username, + const QString &password); + static QString errorText(RDCopyAudio::ErrorCode err); + + private: + RDStation *conv_station; + RDConfig *conv_config; + unsigned conv_source_cart_number; + unsigned conv_source_cut_number; + unsigned conv_destination_cart_number; + unsigned conv_destination_cut_number; +}; + + +#endif // RDCOPYAUDIO_H diff --git a/lib/rdcreate_log.cpp b/lib/rdcreate_log.cpp new file mode 100644 index 00000000..8421afdf --- /dev/null +++ b/lib/rdcreate_log.cpp @@ -0,0 +1,150 @@ +// rdcreate_log.cpp +// +// Create a new, empty Rivendell log table. +// +// (C) Copyright 2002-2014 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcreate_log.cpp,v 1.38.8.1.2.2 2014/06/24 18:27:04 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +#include <rddb.h> +#include <rdclock.h> +#include <rdcreate_log.h> +#include <rdescape_string.h> +#include <rdlog.h> +#include <rdsvc.h> +#include <rd.h> + + +void RDCreateLogTable(const QString &name) +{ + QString sql=RDCreateLogTableSql(name); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; +} + + +QString RDCreateLogTableSql(QString name) +{ + return QString("create table if not exits `")+RDLog::tableName(name)+"`"+ + "(ID INT NOT NULL PRIMARY KEY,"+ + "COUNT INT NOT NULL,"+ + "TYPE INT DEFAULT 0,"+ + "SOURCE INT NOT NULL,"+ + "START_TIME int,"+ + "GRACE_TIME int default 0,"+ + "CART_NUMBER INT UNSIGNED NOT NULL,"+ + "TIME_TYPE INT NOT NULL,"+ + "POST_POINT enum('N','Y') default 'N',"+ + "TRANS_TYPE INT NOT NULL,"+ + "START_POINT INT NOT NULL DEFAULT -1,"+ + "END_POINT INT NOT NULL DEFAULT -1,"+ + "FADEUP_POINT int default -1,"+ + QString().sprintf("FADEUP_GAIN int default %d,",RD_FADE_DEPTH)+ + "FADEDOWN_POINT int default -1,"+ + QString().sprintf("FADEDOWN_GAIN int default %d,",RD_FADE_DEPTH)+ + "SEGUE_START_POINT INT NOT NULL DEFAULT -1,"+ + "SEGUE_END_POINT INT NOT NULL DEFAULT -1,"+ + QString().sprintf("SEGUE_GAIN int default %d,",RD_FADE_DEPTH)+ + "DUCK_UP_GAIN int default 0,"+ + "DUCK_DOWN_GAIN int default 0,"+ + "COMMENT CHAR(255),"+ + "LABEL CHAR(64),"+ + "ORIGIN_USER char(255),"+ + "ORIGIN_DATETIME datetime,"+ + "EVENT_LENGTH int default -1,"+ + "LINK_EVENT_NAME char(64),"+ + "LINK_START_TIME int,"+ + "LINK_LENGTH int default 0,"+ + "LINK_START_SLOP int default 0,"+ + "LINK_END_SLOP int default 0,"+ + "LINK_ID int default -1,"+ + "LINK_EMBEDDED enum('N','Y') default 'N',"+ + "EXT_START_TIME time,"+ + "EXT_LENGTH int,"+ + "EXT_CART_NAME char(32),"+ + "EXT_DATA char(32),"+ + "EXT_EVENT_ID char(32),"+ + "EXT_ANNC_TYPE char(8),"+ + "index COUNT_IDX (COUNT),"+ + "index CART_NUMBER_IDX (CART_NUMBER),"+ + "index LABEL_IDX (LABEL))"; +} + + +QString RDCreateClockTableSql(QString name) +{ + return QString("create table `")+RDClock::tableName(name)+"` ("+ + "ID int unsigned auto_increment not null primary key,"+ + "EVENT_NAME char(64) not null,"+ + "START_TIME int not null,"+ + "LENGTH int not null,"+ + "INDEX EVENT_NAME_IDX (EVENT_NAME))"; +} + + +QString RDCreateReconciliationTableSql(QString name) +{ + QString sql=QString("create table `")+RDSvc::svcTableName(name)+"` ("+ + "ID int unsigned auto_increment primary key,"+ + "LENGTH int,"+ + "LOG_NAME char(64),"+ + "LOG_ID int,"+ + "CART_NUMBER int unsigned,"+ + "CUT_NUMBER int,"+ + "TITLE char(255),"+ + "ARTIST char(255),"+ + "PUBLISHER char(64),"+ + "COMPOSER char(64),"+ + "USER_DEFINED char(255),"+ + "SONG_ID char(32),"+ + "ALBUM char(255),"+ + "LABEL char(64),"+ + "CONDUCTOR char(64),"+ + "USAGE_CODE int,"+ + "ISRC char(12),"+ + "ISCI char(32),"+ + "STATION_NAME char(64),"+ + "EVENT_DATETIME datetime,"+ + "SCHEDULED_TIME time,"+ + "EVENT_TYPE int,"+ + "EVENT_SOURCE int,"+ + "PLAY_SOURCE int,"+ + "START_SOURCE int default 0,"+ + "ONAIR_FLAG enum('N','Y') default 'N',"+ + "EXT_START_TIME time,"+ + "EXT_LENGTH int,"+ + "EXT_CART_NAME char(32),"+ + "EXT_DATA char(32),"+ + "EXT_EVENT_ID char(8),"+ + "EXT_ANNC_TYPE char(8),"+ + "index EVENT_DATETIME_IDX(EVENT_DATETIME))"; + + return sql; +} + + +QString RDCreateStackTableSql(QString name) +{ + QString sql; + sql=QString().sprintf("create table if not exists `%s_STACK` (\ + SCHED_STACK_ID int unsigned not null primary key,\ + CART int unsigned not null,\ + ARTIST varchar(255),\ + SCHED_CODES varchar(255),\ + SCHEDULED_AT datetime default '1000-01-01 00:00:00')", + (const char *)name.replace(" ","_")); + return sql; +} diff --git a/lib/rdcreate_log.h b/lib/rdcreate_log.h new file mode 100644 index 00000000..237d74f2 --- /dev/null +++ b/lib/rdcreate_log.h @@ -0,0 +1,34 @@ +// rdcreate_log.h +// +// Create a new, empty Rivendell log table. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcreate_log.h,v 1.10 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> + +#ifndef RDCREATE_LOG_H +#define RDCREATE_LOG_H + +void RDCreateLogTable(const QString &name); +QString RDCreateLogTableSql(QString name); +QString RDCreateClockTableSql(QString name); +QString RDCreateReconciliationTableSql(QString name); +QString RDCreateStackTableSql(QString name); + +#endif diff --git a/lib/rdcreateauxfieldstable.cpp b/lib/rdcreateauxfieldstable.cpp new file mode 100644 index 00000000..dc83bce1 --- /dev/null +++ b/lib/rdcreateauxfieldstable.cpp @@ -0,0 +1,33 @@ +// rdrdcreateauxfieldstable.cpp +// +// Create a new, empty Rivendell log table. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcreateauxfieldstable.cpp,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rddb.h> + +void RDCreateAuxFieldsTable(QString keyname) +{ + keyname.replace(" ","_"); + QString sql=QString().sprintf("create table if not exists %s_FIELDS (\ + CAST_ID int unsigned not null primary key)", + (const char *)keyname); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdcreateauxfieldstable.h b/lib/rdcreateauxfieldstable.h new file mode 100644 index 00000000..37b30a76 --- /dev/null +++ b/lib/rdcreateauxfieldstable.h @@ -0,0 +1,31 @@ +// rdrdcreateauxfieldstable.h +// +// Create a new, empty Rivendell log table. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcreateauxfieldstable.h,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qstring.h> + +#ifndef RDRDCREATEAUXFIELDSTABLE_H +#define RDRDCREATEAUXFIELDSTABLE_H + +void RDCreateAuxFieldsTable(QString keyname); + + +#endif // RDRDCREATEAUXFIELDSTABLE_H diff --git a/lib/rdcueedit.cpp b/lib/rdcueedit.cpp new file mode 100644 index 00000000..73f3615d --- /dev/null +++ b/lib/rdcueedit.cpp @@ -0,0 +1,727 @@ +// rdcueedit.cpp +// +// Cueing Editor for RDLogLine-based Events +// +// (C) Copyright 2013 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcueedit.cpp,v 1.1.2.3.2.1 2014/05/20 01:45:16 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qpainter.h> +#include <qmessagebox.h> + +#include <rdconf.h> +#include <rdcueedit.h> + +RDCueEdit::RDCueEdit(RDCae *cae,int card,int port, + QWidget *parent,const char *name) + : QWidget(parent,name) +{ + edit_cae=cae; + edit_play_card=card; + edit_play_port=port; + edit_height=325; + edit_slider_pressed=false; + edit_shift_pressed=false; + edit_right_click_stop=false; + edit_event_player=NULL; + edit_start_rml=""; + edit_stop_rml=""; + + // + // Create Fonts + // + QFont radio_font=QFont("Helvetica",10,QFont::Normal); + radio_font.setPixelSize(10); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont counter_font=QFont("Helvetica",20,QFont::Bold); + counter_font.setPixelSize(20); + + // + // Create Palettes + // + edit_play_color= + QPalette(QColor(BUTTON_PLAY_BACKGROUND_COLOR),backgroundColor()); + edit_start_color=palette(); + edit_start_color.setColor(QColorGroup::Foreground,RD_CUEEDITOR_START_MARKER); + + edit_position_label=new QLabel(this,"edit_position_label"); + edit_position_label->setGeometry(0,0,sizeHint().width()-30,30); + edit_position_label->setBackgroundColor(QColor(white)); + edit_position_label->setLineWidth(1); + edit_position_label->setMidLineWidth(0); + edit_position_label->setFrameStyle(QFrame::Box|QFrame::Plain); + + edit_position_bar=new RDMarkerBar(this,"edit_position_bar"); + edit_position_bar->setGeometry(85,8,sizeHint().width()-200,14); + + edit_up_label=new QLabel("00:00:00",this,"edit_up_label"); + edit_up_label->setGeometry(5,8,70,14); + edit_up_label->setBackgroundColor(white); + edit_up_label->setFont(label_font); + edit_up_label->setAlignment(AlignRight|AlignVCenter); + + edit_down_label=new QLabel("00:00:00",this,"edit_down_label"); + edit_down_label->setGeometry(sizeHint().width()-110,8,70,14); + edit_down_label->setBackgroundColor(white); + edit_down_label->setFont(label_font); + edit_down_label->setAlignment(AlignRight|AlignVCenter); + + // + // Position Slider + // + edit_slider=new RDSlider(RDSlider::Right,this,"edit_slider"); + edit_slider->setGeometry(60,30,sizeHint().width()-150,50); + edit_slider->setKnobSize(50,50); + edit_slider->setKnobColor(QColor(RD_CUEEDITOR_KNOB_COLOR)); + connect(edit_slider,SIGNAL(sliderMoved(int)), + this,SLOT(sliderChangedData(int))); + connect(edit_slider,SIGNAL(sliderPressed()),this,SLOT(sliderPressedData())); + connect(edit_slider,SIGNAL(sliderReleased()), + this,SLOT(sliderReleasedData())); + + // + // Button Area + // + QLabel *label=new QLabel(this,"button_area"); + label->setGeometry(0,85,sizeHint().width()-30,60); + label->setBackgroundColor(QColor(gray)); + label->setLineWidth(1); + label->setMidLineWidth(0); + label->setFrameStyle(QFrame::Box|QFrame::Plain); + + // + // Audition Button + // + edit_audition_button=new RDTransportButton(RDTransportButton::PlayBetween, + this,"edit_audition_button"); + edit_audition_button->setGeometry(sizeHint().width()/2-130,90,80,50); + edit_audition_button-> + setPalette(QPalette(backgroundColor(),QColor(gray))); + edit_audition_button->setFont(button_font); + edit_audition_button->setText(tr("&Audition")); + connect(edit_audition_button,SIGNAL(clicked()), + this,SLOT(auditionButtonData())); + + // + // Pause Button + // + edit_pause_button=new RDTransportButton(RDTransportButton::Pause, + this,"edit_pause_button"); + edit_pause_button->setGeometry(sizeHint().width()/2-40,90,80,50); + edit_pause_button-> + setPalette(QPalette(backgroundColor(),QColor(gray))); + edit_pause_button->setFont(button_font); + edit_pause_button->setText(tr("&Pause")); + connect(edit_pause_button,SIGNAL(clicked()),this,SLOT(pauseButtonData())); + + // + // Stop Button + // + edit_stop_button=new RDTransportButton(RDTransportButton::Stop, + this,"edit_stop_button"); + edit_stop_button->setGeometry(sizeHint().width()/2+50,90,80,50); + edit_stop_button->setOnColor(QColor(red)); + edit_stop_button-> + setPalette(QPalette(backgroundColor(),QColor(gray))); + edit_stop_button->setFont(button_font); + edit_stop_button->setText(tr("&Stop")); + connect(edit_stop_button,SIGNAL(clicked()),this,SLOT(stopButtonData())); + + // + // Start Marker Control + // + edit_start_button=new RDPushButton(this,"button"); + edit_start_button->setToggleButton(true); + edit_start_button->setGeometry(0,155,66,45); + edit_start_button->setFlashColor(backgroundColor()); + edit_start_button->setFlashPeriod(RD_CUEEDITOR_BUTTON_FLASH_PERIOD); + edit_start_button->setPalette(QPalette(QColor(RD_CUEEDITOR_START_MARKER), + backgroundColor())); + edit_start_button->setFont(button_font); + edit_start_button->setText(tr("Start")); + connect(edit_start_button,SIGNAL(clicked()),this,SLOT(startClickedData())); + + // + // End Marker Control + // + edit_end_button=new RDPushButton(this); + edit_end_button->setToggleButton(true); + edit_end_button->setGeometry(90,155,66,45); + edit_end_button->setFlashColor(backgroundColor()); + edit_end_button->setFlashPeriod(RD_CUEEDITOR_BUTTON_FLASH_PERIOD); + edit_end_button->setPalette(QPalette(QColor(RD_CUEEDITOR_START_MARKER), + backgroundColor())); + edit_end_button->setFont(button_font); + edit_end_button->setText(tr("End")); + connect(edit_end_button,SIGNAL(clicked()),this,SLOT(endClickedData())); + + // + // Recue Marker Control + // + edit_recue_button=new RDPushButton(this); + edit_recue_button->setToggleButton(true); + edit_recue_button->setGeometry(180,155,66,45); + edit_recue_button->setFlashColor(backgroundColor()); + edit_recue_button->setFlashPeriod(RD_CUEEDITOR_BUTTON_FLASH_PERIOD); + edit_recue_button->setPalette(QPalette(QColor(RD_CUEEDITOR_START_MARKER), + backgroundColor())); + edit_recue_button->setFont(button_font); + edit_recue_button->setText(tr("&Recue")); + connect(edit_recue_button,SIGNAL(clicked()),this,SLOT(recue())); + + // + // Audition Stop Timer + // + edit_audition_timer=new QTimer(this,"edit_audition_timer"); + connect(edit_audition_timer,SIGNAL(timeout()),this,SLOT(auditionTimerData())); + + // + // Play Deck + // + edit_play_deck=new RDPlayDeck(edit_cae,RDPLAYDECK_AUDITION_ID, + this,"edit_play_deck"); + connect(edit_play_deck,SIGNAL(stateChanged(int,RDPlayDeck::State)),this, + SLOT(stateChangedData(int,RDPlayDeck::State))); + connect(edit_play_deck,SIGNAL(position(int,int)), + this,SLOT(positionData(int,int))); +} + + +RDCueEdit::~RDCueEdit() +{ +} + + +QSize RDCueEdit::sizeHint() const +{ + return QSize(610,215); +} + + +QSizePolicy RDCueEdit::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDCueEdit::setRml(RDEventPlayer *player,const QString &start_rml, + const QString &stop_rml) +{ + edit_event_player=player; + edit_start_rml=start_rml; + edit_stop_rml=stop_rml; +} + + +bool RDCueEdit::initialize(RDLogLine *logline) +{ + edit_logline=logline; + edit_position_bar->setLength(edit_logline->forcedLength()); + edit_start_button->setOn(false); + if(!(edit_logline->status()==RDLogLine::Scheduled) && + !(edit_logline->status()==RDLogLine::Paused)) { + edit_start_button->hide(); + edit_end_button->hide(); + } + else { + edit_start_button->show(); + edit_end_button->show(); + } + edit_slider->setRange(0,edit_logline->forcedLength()); + edit_slider->setValue(edit_logline->playPosition()); + sliderChangedData(edit_logline->playPosition()); + startClickedData(); + edit_stop_button->on(); + edit_position_bar-> + setMarker(RDMarkerBar::Play,edit_logline->playPosition()); + edit_position_bar-> + setMarker(RDMarkerBar::Start,edit_logline->playPosition()); + edit_position_bar-> + setMarker(RDMarkerBar::End,edit_logline->endPoint()); + edit_slider->setValue(edit_logline->playPosition()); + UpdateCounters(); + return true; +} + + +unsigned RDCueEdit::playPosition(RDMarkerBar::Marker marker) const +{ + return edit_position_bar->marker(marker); +} + + +void RDCueEdit::stop() +{ + if(edit_play_deck->state()==RDPlayDeck::Playing) { + edit_play_deck->stop(); + } +} + + +void RDCueEdit::recue() +{ + edit_position_bar->setMarker(RDMarkerBar::Start,0); + if(edit_start_button->isOn()) { + edit_slider->setValue(0); + } + UpdateCounters(); +} + + +void RDCueEdit::sliderChangedData(int pos) +{ + if(edit_start_button->isOn()) { + edit_position_bar->setMarker(RDMarkerBar::Start,pos); + } + else { + if(edit_end_button->isOn()) { + edit_position_bar->setMarker(RDMarkerBar::End,pos); + } + else { + edit_position_bar->setMarker(RDMarkerBar::Play,pos); + } + } + UpdateCounters(); +} + + +void RDCueEdit::sliderPressedData() +{ + if(edit_play_deck->state()==RDPlayDeck::Playing) { + edit_play_deck->stop(); + edit_slider_pressed=true; + } +} + + +void RDCueEdit::sliderReleasedData() +{ + if(edit_slider_pressed) { + auditionButtonData(); + edit_slider_pressed=false; + } +} + + +void RDCueEdit::auditionButtonData() +{ + int start_pos=edit_slider->value(); + int play_len=-1; + + if(edit_play_deck->state()==RDPlayDeck::Playing) { + return; + } + edit_play_deck->setCard(edit_play_card); + edit_play_deck->setPort(edit_play_port); + if(!edit_play_deck->setCart(edit_logline,false)) { + return; + } + if(edit_start_button->isOn()) { + if(edit_play_deck->state()==RDPlayDeck::Stopped) { + start_pos=edit_position_bar->marker(RDMarkerBar::Start); + } + if(edit_play_deck->state()==RDPlayDeck::Paused) { + start_pos=edit_play_deck->currentPosition(); + } + play_len=edit_position_bar->marker(RDMarkerBar::End)-start_pos; + } + else { + if(edit_end_button->isOn()) { + if(edit_play_deck->state()==RDPlayDeck::Stopped) { + play_len=RD_CUEEDITOR_AUDITION_PREROLL; + if(play_len>(edit_position_bar->marker(RDMarkerBar::End)- + edit_position_bar->marker(RDMarkerBar::Start))) { + play_len=edit_position_bar->marker(RDMarkerBar::End)- + edit_position_bar->marker(RDMarkerBar::Start); + } + start_pos=edit_position_bar->marker(RDMarkerBar::End)-play_len; + } + } + else { + if((edit_play_deck->state()==RDPlayDeck::Stopped)&& + (!edit_slider_pressed)) { + edit_start_pos=edit_slider->value(); + } + } + } + edit_play_deck->play(start_pos); + if(play_len>=0) { + edit_audition_timer->start(play_len,true); + } + if((!edit_start_rml.isEmpty())&&(edit_event_player!=NULL)) { + edit_event_player->exec(edit_logline->resolveWildcards(edit_start_rml)); + } +} + + +void RDCueEdit::pauseButtonData() +{ + if(edit_play_deck->state()==RDPlayDeck::Playing) { + edit_play_deck->pause(); + } +} + + +void RDCueEdit::stopButtonData() +{ + switch(edit_play_deck->state()) { + case RDPlayDeck::Playing: + case RDPlayDeck::Paused: + edit_play_deck->stop(); + break; + + default: + break; + } +} + + +void RDCueEdit::stateChangedData(int id,RDPlayDeck::State state) +{ + if(id!=RDPLAYDECK_AUDITION_ID) { + return; + } + switch(state) { + case RDPlayDeck::Playing: + Playing(id); + break; + + case RDPlayDeck::Stopping: + break; + + case RDPlayDeck::Paused: + Paused(id); + break; + + case RDPlayDeck::Stopped: + Stopped(id); + break; + + case RDPlayDeck::Finished: + Stopped(id); + break; + } +} + + +void RDCueEdit::positionData(int id,int msecs) +{ + if(id!=RDPLAYDECK_AUDITION_ID) { + return; + } + edit_position_bar->setMarker(RDMarkerBar::Play,msecs); + if((!edit_start_button->isOn())&&(!edit_end_button->isOn())) { + edit_slider->setValue(msecs); + } + UpdateCounters(); +} + + +void RDCueEdit::auditionTimerData() +{ + edit_play_deck->stop(); +} + + +void RDCueEdit::startClickedData() +{ + if(edit_end_button->isOn()) { + edit_end_button->toggle(); + SetEndMode(false); + } + SetStartMode(edit_start_button->isOn()); +} + + +void RDCueEdit::endClickedData() +{ + if(edit_start_button->isOn()) { + edit_start_button->toggle(); + SetStartMode(false); + } + SetEndMode(edit_end_button->isOn()); +} + + +void RDCueEdit::SetStartMode(bool state) +{ + if(state) { + edit_slider->setRange(0,edit_position_bar->marker(RDMarkerBar::End)); + edit_slider->setGeometry(60,30, + (int)(50.0+((double)(sizeHint().width()-200)* + (double)edit_position_bar-> + marker(RDMarkerBar::End)/ + (double)edit_logline-> + forcedLength())),50); + edit_slider->setValue(edit_position_bar->marker(RDMarkerBar::Start)); + edit_slider->setKnobColor(RD_CUEEDITOR_START_MARKER); + edit_audition_button->setAccentColor(RD_CUEEDITOR_START_MARKER); + edit_start_button->setFlashingEnabled(true); + edit_up_label->setPalette(edit_start_color); + edit_down_label->setPalette(edit_start_color); + UpdateCounters(); + } + else { + edit_slider->setRange(0,edit_logline->forcedLength()); + edit_slider->setGeometry(60,30,sizeHint().width()-150,50); + edit_slider->setValue(edit_position_bar->marker(RDMarkerBar::Play)); + edit_slider->setKnobColor(RD_CUEEDITOR_PLAY_MARKER); + edit_audition_button->setAccentColor(RD_CUEEDITOR_PLAY_MARKER); + edit_start_button->setFlashingEnabled(false); + edit_up_label->setPalette(palette()); + edit_down_label->setPalette(palette()); + UpdateCounters(); + } +} + + +void RDCueEdit::SetEndMode(bool state) +{ + if(state) { + edit_slider->setRange(edit_position_bar->marker(RDMarkerBar::Start), + edit_logline->forcedLength()); + edit_slider->setGeometry((int)(60.0+(double)(sizeHint().width()-200)* + (double)edit_position_bar-> + marker(RDMarkerBar::Start)/ + (double)edit_logline->forcedLength()), + 30,(int)(50.0+((double)(sizeHint().width()-200)* + ((double)edit_logline-> + forcedLength()- + (double)edit_position_bar-> + marker(RDMarkerBar::Start))/ + (double)edit_logline-> + forcedLength())),50); + edit_slider->setValue(edit_position_bar->marker(RDMarkerBar::End)); + edit_slider->setKnobColor(RD_CUEEDITOR_START_MARKER); + edit_audition_button->setAccentColor(RD_CUEEDITOR_START_MARKER); + edit_end_button->setFlashingEnabled(true); + edit_up_label->setPalette(edit_start_color); + edit_down_label->setPalette(edit_start_color); + UpdateCounters(); + } + else { + edit_slider->setRange(0,edit_logline->forcedLength()); + edit_slider->setGeometry(60,30,sizeHint().width()-150,50); + edit_slider->setValue(edit_position_bar->marker(RDMarkerBar::Play)); + edit_slider->setKnobColor(RD_CUEEDITOR_PLAY_MARKER); + edit_audition_button->setAccentColor(RD_CUEEDITOR_PLAY_MARKER); + edit_end_button->setFlashingEnabled(false); + edit_up_label->setPalette(palette()); + edit_down_label->setPalette(palette()); + UpdateCounters(); + } +} + +/* +void RDCueEdit::ShowAudioControls(bool state) +{ + if(state) { + edit_height=325; + edit_slider->show(); + edit_up_label->show(); + edit_down_label->show(); + edit_audition_button->show(); + edit_pause_button->show(); + edit_position_bar->show(); + edit_position_label->show(); + } + else { + edit_height=170; + edit_slider->hide(); + edit_up_label->hide(); + edit_down_label->hide(); + edit_audition_button->hide(); + edit_pause_button->hide(); + edit_position_bar->hide(); + edit_position_label->hide(); + } +} +*/ + +void RDCueEdit::Playing(int id) +{ + edit_audition_button->on(); + edit_pause_button->off(); + edit_stop_button->off(); + edit_right_click_stop=true; +} + + +void RDCueEdit::Paused(int id) +{ + if(!edit_slider_pressed) { + edit_audition_button->off(); + edit_pause_button->on(); + edit_stop_button->off(); + ClearChannel(); + edit_right_click_stop=false; + } +} + + +void RDCueEdit::Stopped(int id) +{ + if(!edit_slider_pressed) { + edit_audition_button->off(); + edit_pause_button->off(); + edit_stop_button->on(); + ClearChannel(); + edit_right_click_stop=false; + } + if(edit_start_button->isOn()) { + edit_position_bar-> + setMarker(RDMarkerBar::Play,edit_position_bar->marker(RDMarkerBar::Start)); + edit_slider->setValue(edit_position_bar->marker(RDMarkerBar::Start)); + } + else { + if(edit_end_button->isOn()) { + edit_slider->setValue(edit_position_bar->marker(RDMarkerBar::End)); + } + else { + edit_position_bar->setMarker(RDMarkerBar::Play,edit_start_pos); + edit_slider->setValue(edit_start_pos); + } + } +} + + +void RDCueEdit::UpdateCounters() +{ + if(edit_start_button->isOn()) { + edit_up_label-> + setText(RDGetTimeLength(edit_position_bar->marker(RDMarkerBar::Start),true)); + edit_down_label-> + setText(RDGetTimeLength(edit_logline-> + forcedLength()-edit_position_bar-> + marker(RDMarkerBar::Start),true)); + } + else { + if(edit_end_button->isOn()) { + edit_up_label-> + setText(RDGetTimeLength(edit_position_bar->marker(RDMarkerBar::End), + true)); + edit_down_label-> + setText(RDGetTimeLength(edit_logline-> + forcedLength()-edit_position_bar-> + marker(RDMarkerBar::End),true)); + } + else { + edit_up_label-> + setText(RDGetTimeLength(edit_position_bar->marker(RDMarkerBar::Play), + true)); + edit_down_label-> + setText(RDGetTimeLength(edit_logline-> + forcedLength()-edit_position_bar-> + marker(RDMarkerBar::Play),true)); + } + } +} + + +void RDCueEdit::ClearChannel() +{ + if(edit_cae->playPortActive(edit_play_deck->card(),edit_play_deck->port(), + edit_play_deck->stream())) { + return; + } + if((!edit_stop_rml.isEmpty())&&(edit_event_player!=NULL)) { + edit_event_player->exec(edit_stop_rml); + } +} + + +void RDCueEdit::wheelEvent(QWheelEvent *e) +{ + if(edit_audition_button->isShown()) { + if(edit_play_deck->state()==RDPlayDeck::Playing) { + edit_play_deck->pause(); + } + if(edit_shift_pressed) { + edit_slider->setValue(edit_slider->value()+(e->delta()*10)/12); + } + else { + edit_slider->setValue(edit_slider->value()+(e->delta()*100)/12); + } + sliderChangedData(edit_slider->value()); + } +} + + +void RDCueEdit::mousePressEvent(QMouseEvent *e) +{ + switch(e->button()) { + case QMouseEvent::RightButton: + if(edit_audition_button->isShown()) { + if(edit_right_click_stop) { + stopButtonData(); + } + else { + auditionButtonData(); + } + } + break; + + case QMouseEvent::MidButton: + if(edit_audition_button->isShown()) { + if(edit_logline->forcedLength()>10000) { + if(edit_play_deck->state()==RDPlayDeck::Playing) { + edit_play_deck->pause(); + } + edit_slider->setValue((edit_logline->forcedLength())-10000); + sliderChangedData(edit_slider->value()); + } + auditionButtonData(); + } + break; + + default: + QWidget::mousePressEvent(e); + break; + } +} + + +void RDCueEdit::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Shift: + edit_shift_pressed=true; + break; + + default: + e->ignore(); + break; + } +} + + +void RDCueEdit::keyReleaseEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Shift: + edit_shift_pressed=false; + QWidget::keyPressEvent(e); + break; + + default: + QWidget::keyPressEvent(e); + break; + } +} diff --git a/lib/rdcueedit.h b/lib/rdcueedit.h new file mode 100644 index 00000000..1f2b136c --- /dev/null +++ b/lib/rdcueedit.h @@ -0,0 +1,116 @@ +// rdcueedit.h +// +// Cueing Editor for RDLogLine-based Events +// +// (C) Copyright 2002-2013 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcueedit.h,v 1.1.2.2.2.1 2014/05/20 01:45:16 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCUEEDIT_H +#define RDCUEEDIT_H + +#include <qwidget.h> +#include <qlabel.h> +#include <qbuttongroup.h> +#include <qtimer.h> + +#include <rdtransportbutton.h> +#include <rdslider.h> +#include <rdcae.h> +#include <rdplay_deck.h> +#include <rdmarker_edit.h> +#include <rdpushbutton.h> +#include <rdtimeedit.h> +#include <rdmarker_bar.h> +#include <rdevent_player.h> +#include <rdcueedit.h> + +class RDCueEdit : public QWidget +{ + Q_OBJECT + public: + RDCueEdit(RDCae *cae,int card,int port,QWidget *parent=0,const char *name=0); + ~RDCueEdit(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void setRml(RDEventPlayer *player,const QString &start_rml, + const QString &stop_rml); + bool initialize(RDLogLine *logline); + unsigned playPosition(RDMarkerBar::Marker marker) const; + void stop(); + + public slots: + void recue(); + + private slots: + void sliderPressedData(); + void sliderReleasedData(); + void sliderChangedData(int pos); + void auditionButtonData(); + void pauseButtonData(); + void stopButtonData(); + void stateChangedData(int id,RDPlayDeck::State state); + void positionData(int id,int msecs); + void startClickedData(); + void endClickedData(); + void auditionTimerData(); + virtual void wheelEvent(QWheelEvent *e); + virtual void mousePressEvent(QMouseEvent *e); + void keyPressEvent(QKeyEvent *e); + void keyReleaseEvent(QKeyEvent *e); + + private: + void SetStartMode(bool state); + void SetEndMode(bool state); + void Playing(int id); + void Paused(int id); + void Stopped(int id); + void UpdateCounters(); + void ClearChannel(); + RDLogLine *edit_logline; + RDPlayDeck *edit_play_deck; + RDEventPlayer *edit_event_player; + QString edit_start_rml; + QString edit_stop_rml; + RDCae *edit_cae; + int edit_play_card; + int edit_play_port; + RDSlider *edit_slider; + QLabel *edit_up_label; + QLabel *edit_down_label; + QFont normal_font; + RDTransportButton *edit_audition_button; + RDTransportButton *edit_pause_button; + RDTransportButton *edit_stop_button; + int edit_height; + bool edit_slider_pressed; + QPalette edit_play_color; + QPalette edit_start_color; + int edit_start_pos; + QLabel *edit_position_label; + RDMarkerBar *edit_position_bar; + RDPushButton *edit_start_button; + RDPushButton *edit_end_button; + RDPushButton *edit_recue_button; + bool edit_shift_pressed; + bool edit_right_click_stop; + QTimer *edit_audition_timer; +}; + + +#endif // RDCUEEDIT_H + diff --git a/lib/rdcueeditdialog.cpp b/lib/rdcueeditdialog.cpp new file mode 100644 index 00000000..103aedd1 --- /dev/null +++ b/lib/rdcueeditdialog.cpp @@ -0,0 +1,116 @@ +// rdcueeditdialog.cpp +// +// A Dialog Box for using an RDCueEdit widget. +// +// (C) Copyright 2002-2013 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcueeditdialog.cpp,v 1.1.2.1 2013/07/05 22:44:17 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include <qapplication.h> +#include <qpushbutton.h> + +#include <rdcueeditdialog.h> + +RDCueEditDialog::RDCueEditDialog(RDCae *cae,int play_card,int play_port, + const QString &caption,QWidget *parent) + :QDialog(parent,"",true) +{ + QFont font; + + font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + setCaption(caption+" - "+tr("Set Cue Point")); + + // + // Cue Editor + // + cue_edit=new RDCueEdit(cae,play_card,play_port,this); + cue_edit->setGeometry(15,10, + cue_edit->sizeHint().width(), + cue_edit->sizeHint().height()); + + // + // OK Button + // + QPushButton *button=new QPushButton(this); + button->setGeometry(sizeHint().width()-170,sizeHint().height()-60,80,50); + button->setFont(font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +RDCueEditDialog::~RDCueEditDialog() +{ + delete cue_edit; +} + + +QSize RDCueEditDialog::sizeHint() const +{ + return QSize(cue_edit->sizeHint().width(), + cue_edit->sizeHint().height()+10); +} + + +QSizePolicy RDCueEditDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int RDCueEditDialog::exec(RDLogLine *logline) +{ + edit_logline=logline; + cue_edit->initialize(logline); + return QDialog::exec(); +} + + +void RDCueEditDialog::okData() +{ + if(cue_edit->playPosition(RDMarkerBar::Start)!= + edit_logline->playPosition()) { + edit_logline-> + setPlayPosition(cue_edit->playPosition(RDMarkerBar::Start)); + edit_logline->setPlayPositionChanged(true); + } + if(cue_edit->playPosition(RDMarkerBar::End)!= + (unsigned)edit_logline->endPoint()) { + edit_logline->setEndPoint(cue_edit->playPosition(RDMarkerBar::End), + RDLogLine::LogPointer); + edit_logline->setPlayPositionChanged(true); + } + done(0); +} + + +void RDCueEditDialog::cancelData() +{ + done(-1); +} diff --git a/lib/rdcueeditdialog.h b/lib/rdcueeditdialog.h new file mode 100644 index 00000000..aa4ef5dc --- /dev/null +++ b/lib/rdcueeditdialog.h @@ -0,0 +1,56 @@ +// rdcueeditdialog.h +// +// A Dialog Box for using an RDCueEdit widget. +// +// (C) Copyright 2002-2013 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcueeditdialog.h,v 1.1.2.1 2013/07/05 22:44:17 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDCUEEDITDIALOG_H +#define RDCUEEDITDIALOG_H + +#include <qdialog.h> + +#include <rdlog_line.h> + +#include <rdcueedit.h> + +class RDCueEditDialog : public QDialog +{ + Q_OBJECT + public: + RDCueEditDialog(RDCae *cae,int play_card,int play_port,const QString &caption, + QWidget *parent=0); + ~RDCueEditDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(RDLogLine *logline); + + private slots: + void okData(); + void cancelData(); + + private: + RDLogLine *edit_logline; + RDCueEdit *cue_edit; +}; + + +#endif // RDCUEEDITDIALOG_H diff --git a/lib/rdcut.cpp b/lib/rdcut.cpp new file mode 100644 index 00000000..8de8be26 --- /dev/null +++ b/lib/rdcut.cpp @@ -0,0 +1,1614 @@ +// rdcut.cpp +// +// Abstract a Rivendell Cut. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcut.cpp,v 1.76.6.10.2.2 2014/07/15 20:02:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WIN32 +#include <unistd.h> +#endif // WIN32 +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> + +#include <rd.h> +#include <rdconf.h> +#ifndef WIN32 +#include <rdwavefile.h> +#endif + +#include <rdcut.h> +#include <rdtextvalidator.h> +#include <rdconfig.h> +#include <rddb.h> +#include <rdescape_string.h> +#include <rdweb.h> +#include <rdcopyaudio.h> + +// +// Global Classes +// +RDCut::RDCut(const QString &name,bool create,QSqlDatabase *db) +{ + RDSqlQuery *q; + QString sql; + + cut_db=db; + cut_name=name; + + cut_signal=new QSignal(); + + if(name.isEmpty()) { + cut_number=0; + cart_number=0; + return; + } + + sscanf((const char *)name+7,"%u",&cut_number); + sscanf((const char *)name.left(6),"%u",&cart_number); + if(create) { + sql=QString().sprintf("insert into CUTS set CUT_NAME=\"%s\",CART_NUMBER=%u", + (const char *)cut_name,cart_number); + q=new RDSqlQuery(sql,cut_db); + delete q; + } +} + + +RDCut::RDCut(unsigned cartnum,int cutnum,bool create,QSqlDatabase *db) +{ + RDSqlQuery *q; + QString sql; + + cut_db=db; + cut_name=RDCut::cutName(cartnum,cutnum); + + cut_signal=new QSignal(); + + if(create) { + sql=QString().sprintf("insert into CUTS set CUT_NAME=\"%s\",CART_NUMBER=%u", + (const char *)cut_name,cartnum); + q=new RDSqlQuery(sql,cut_db); + delete q; + } + cut_number=cutnum; + cart_number=cartnum; +} + + +RDCut::~RDCut() +{ + delete cut_signal; +} + + +bool RDCut::exists() const +{ + return RDDoesRowExist("CUTS","CUT_NAME",cut_name,cut_db); +} + + +bool RDCut::isValid() const +{ + return isValid(QDateTime(QDate::currentDate(),QTime::currentTime())); +} + + +bool RDCut::isValid(const QTime &time) const +{ + return isValid(QDateTime(QDate::currentDate(),time)); +} + + +bool RDCut::isValid(const QDateTime &datetime) const +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select MON,TUE,WED,THU,FRI,SAT,SUN,EVERGREEN,\ + START_DATETIME,END_DATETIME,START_DAYPART,END_DAYPART\ + from CUTS where CUT_NAME=\"%s\"", + (const char *)cut_name); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return false; + } + if(q->value(7).toString()=="Y") { // Evergreen + delete q; + return true; + } + if(q->value(datetime.date().dayOfWeek()-1).toString()!="Y") { // Day of Week + delete q; + return false; + } + if((!q->value(8).isNull())&&(q->value(8).toDateTime()>datetime)) { + delete q; + return false; + } + if((!q->value(9).isNull())&&(q->value(9).toDateTime()<datetime)) { + delete q; + return false; + } + if((!q->value(10).isNull())&&(q->value(10).toTime()>datetime.time())) { + delete q; + return false; + } + if((!q->value(11).isNull())&&(q->value(11).toTime()<datetime.time())) { + delete q; + return false; + } + delete q; + return true; +} + + +QString RDCut::cutName() const +{ + return cut_name; +} + + +unsigned RDCut::cutNumber() const +{ + return cut_number; +} + + +unsigned RDCut::cartNumber() const +{ + return cart_number; +} + + +void RDCut::setCartNumber(unsigned num) const +{ + SetRow("CART_NUMBER",num); +} + + +bool RDCut::evergreen() const +{ + return RDBool(RDGetSqlValue("CUTS","CUT_NAME",cut_name,"EVERGREEN"). + toString()); +} + + +void RDCut::setEvergreen(bool state) const +{ + SetRow("EVERGREEN",RDYesNo(state)); +} + + +QString RDCut::description() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"DESCRIPTION",cut_db). + toString(); +} + + +void RDCut::setDescription(const QString &string) const +{ + SetRow("DESCRIPTION",string); +} + + +QString RDCut::outcue() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"OUTCUE",cut_db).toString(); +} + + +void RDCut::setOutcue(const QString &string) const +{ + SetRow("OUTCUE",string); +} + + +QString RDCut::isrc(IsrcFormat fmt) const +{ + QString str= RDGetSqlValue("CUTS","CUT_NAME",cut_name,"ISRC",cut_db). + toString(); + if((fmt==RDCut::RawIsrc)||(str.length()!=12)) { + return str; + } + str.insert(2,"-"); + str.insert(6,"-"); + str.insert(9,"-"); + return str; +} + + +void RDCut::setIsrc(const QString &isrc) const +{ + SetRow("ISRC",isrc); +} + + +QString RDCut::isci() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"ISCI",cut_db).toString(); +} + + +void RDCut::setIsci(const QString &isci) const +{ + SetRow("ISCI",isci); +} + + +unsigned RDCut::length() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"LENGTH",cut_db). + toUInt(); +} + + +void RDCut::setLength(int length) const +{ + SetRow("LENGTH",length); +} + + +QDateTime RDCut::originDatetime(bool *valid) const +{ + return + RDGetSqlValue("CUTS","CUT_NAME",cut_name,"ORIGIN_DATETIME",cut_db,valid). + toDateTime(); +} + + +void RDCut::setOriginDatetime(const QDateTime &datetime) const +{ + SetRow("ORIGIN_DATETIME",datetime); +} + + +QDateTime RDCut::startDatetime(bool *valid) const +{ + return + RDGetSqlValue("CUTS","CUT_NAME",cut_name,"START_DATETIME",cut_db,valid). + toDateTime(); +} + + +void RDCut::setStartDatetime(const QDateTime &datetime,bool valid) const +{ + if(valid) { + SetRow("START_DATETIME",datetime); + } + else { + SetRow("START_DATETIME"); + } +} + + +QDateTime RDCut::endDatetime(bool *valid) const +{ + return + RDGetSqlValue("CUTS","CUT_NAME",cut_name,"END_DATETIME",cut_db,valid). + toDateTime(); +} + + +void RDCut::setEndDatetime(const QDateTime &datetime,bool valid) const +{ + if(valid) { + SetRow("END_DATETIME",datetime); + } + else { + SetRow("END_DATETIME"); + } +} + + +QTime RDCut::startDaypart(bool *valid) const +{ + return + RDGetSqlValue("CUTS","CUT_NAME",cut_name,"START_DAYPART",cut_db,valid). + toTime(); +} + + +void RDCut::setStartDaypart(const QTime &time,bool valid) const +{ + if(valid) { + SetRow("START_DAYPART",time); + } + else { + SetRow("START_DAYPART"); + } +} + + +bool RDCut::weekPart(int dayofweek) const +{ + return RDBool(RDGetSqlValue("CUTS","CUT_NAME",cut_name, + RDGetShortDayNameEN(dayofweek).upper(),cut_db). + toString()); +} + + +void RDCut::setWeekPart(int dayofweek,bool state) const +{ + SetRow(RDGetShortDayNameEN(dayofweek).upper(),RDYesNo(state)); +} + + +QTime RDCut::endDaypart(bool *valid) const +{ + return + RDGetSqlValue("CUTS","CUT_NAME",cut_name,"END_DAYPART",cut_db,valid). + toTime(); +} + + +void RDCut::setEndDaypart(const QTime &time,bool valid) const +{ + if(valid) { + SetRow("END_DAYPART",time); + } + else { + SetRow("END_DAYPART"); + } +} + + +QString RDCut::originName() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"ORIGIN_NAME",cut_db). + toString(); +} + + +void RDCut::setOriginName(const QString &name) const +{ + SetRow("ORIGIN_NAME",name); +} + + +unsigned RDCut::weight() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"WEIGHT",cut_db). + toUInt(); +} + + +void RDCut::setWeight(int value) const +{ + SetRow("WEIGHT",value); +} + + +QDateTime RDCut::lastPlayDatetime(bool *valid) const +{ + return + RDGetSqlValue("CUTS","CUT_NAME",cut_name,"LAST_PLAY_DATETIME",cut_db,valid). + toDateTime(); +} + + +void RDCut::setLastPlayDatetime(const QDateTime &datetime,bool valid) const +{ + if(valid) { + SetRow("LAST_PLAY_DATETIME",datetime); + } + else { + SetRow("LAST_PLAY_DATETIME"); + } +} + + +QDateTime RDCut::uploadDatetime(bool *valid) const +{ + return + RDGetSqlValue("CUTS","CUT_NAME",cut_name,"UPLOAD_DATETIME",cut_db,valid). + toDateTime(); +} + + +void RDCut::setUploadDatetime(const QDateTime &datetime,bool valid) const +{ + if(valid) { + SetRow("UPLOAD_DATETIME",datetime); + } + else { + SetRow("UPLOAD_DATETIME"); + } +} + + +unsigned RDCut::playCounter() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"PLAY_COUNTER",cut_db). + toUInt(); +} + + +void RDCut::setPlayCounter(unsigned count) const +{ + SetRow("PLAY_COUNTER",count); +} + + +RDCut::Validity RDCut::validity() const +{ + return (RDCut::Validity) + RDGetSqlValue("CUTS","CUT_NAME",cut_name,"VALIDITY").toUInt(); +} + + +void RDCut::setValidity(RDCut::Validity state) +{ + SetRow("VALIDITY",(int)state); +} + + +unsigned RDCut::localCounter() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"LOCAL_COUNTER",cut_db). + toUInt(); +} + + +void RDCut::setLocalCounter(unsigned count) const +{ + SetRow("LOCAL_COUNTER",count); +} + + +unsigned RDCut::codingFormat() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"CODING_FORMAT",cut_db). + toUInt(); +} + + +void RDCut::setCodingFormat(unsigned format) const +{ + SetRow("CODING_FORMAT",format); +} + + +unsigned RDCut::sampleRate() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"SAMPLE_RATE",cut_db). + toUInt(); +} + + +void RDCut::setSampleRate(unsigned rate) const +{ + SetRow("SAMPLE_RATE",rate); +} + + +unsigned RDCut::bitRate() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"BIT_RATE",cut_db). + toUInt(); +} + + +void RDCut::setBitRate(unsigned rate) const +{ + SetRow("BIT_RATE",rate); +} + + +unsigned RDCut::channels() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"CHANNELS",cut_db). + toUInt(); +} + + +void RDCut::setChannels(unsigned chan) const +{ + SetRow("CHANNELS",chan); +} + + +int RDCut::playGain() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"PLAY_GAIN",cut_db). + toInt(); +} + + +void RDCut::setPlayGain(int gain) const +{ + SetRow("PLAY_GAIN",gain); +} + + +int RDCut::startPoint(bool calc) const +{ + int n; + + if(!calc) { + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"START_POINT",cut_db). + toInt(); + } + if((n=RDGetSqlValue("CUTS","CUT_NAME",cut_name,"START_POINT",cut_db). + toInt())!=-1) { + return n; + } + return 0; +} + + +void RDCut::setStartPoint(int point) const +{ + SetRow("START_POINT",point); +} + + +int RDCut::endPoint(bool calc) const +{ + int n; + + if(!calc) { + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"END_POINT",cut_db). + toInt(); + } + if((n=RDGetSqlValue("CUTS","CUT_NAME",cut_name,"END_POINT",cut_db). + toInt())!=-1) { + return n; + } + return (int)length(); +} + + +void RDCut::setEndPoint(int point) const +{ + SetRow("END_POINT",point); +} + + +int RDCut::fadeupPoint(bool calc) const +{ + int n; + + if(!calc) { + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"FADEUP_POINT",cut_db). + toInt(); + } + if((n=RDGetSqlValue("CUTS","CUT_NAME",cut_name,"FADEUP_POINT",cut_db). + toInt())!=-1) { + return n; + } + return 0; +} + + +void RDCut::setFadeupPoint(int point) const +{ + SetRow("FADEUP_POINT",point); +} + + +int RDCut::fadedownPoint(bool calc) const +{ + int n; + + if(!calc) { + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"FADEDOWN_POINT",cut_db). + toInt(); + } + if((n=RDGetSqlValue("CUTS","CUT_NAME",cut_name,"FADEDOWN_POINT",cut_db). + toInt())!=-1) { + return n; + } + return effectiveEnd(); +} + + +void RDCut::setFadedownPoint(int point) const +{ + SetRow("FADEDOWN_POINT",point); +} + + +int RDCut::segueStartPoint(bool calc) const +{ + int n; + + if(!calc) { + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"SEGUE_START_POINT",cut_db). + toInt(); + } + if((n=RDGetSqlValue("CUTS","CUT_NAME",cut_name,"SEGUE_START_POINT",cut_db). + toInt())!=-1) { + return n; + } + return 0; +} + + +void RDCut::setSegueStartPoint(int point) const +{ + SetRow("SEGUE_START_POINT",point); +} + + +int RDCut::segueEndPoint(bool calc) const +{ + int n; + + if(!calc) { + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"SEGUE_END_POINT",cut_db). + toInt(); + } + if((n=RDGetSqlValue("CUTS","CUT_NAME",cut_name,"SEGUE_END_POINT",cut_db). + toInt())!=-1) { + return n; + } + return effectiveEnd(); +} + + +void RDCut::setSegueEndPoint(int point) const +{ + SetRow("SEGUE_END_POINT",point); +} + + +int RDCut::segueGain() const +{ + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"SEGUE_GAIN",cut_db).toInt(); +} + + +void RDCut::setSegueGain(int gain) const +{ + SetRow("SEGUE_GAIN",gain); +} + + +int RDCut::hookStartPoint(bool calc) const +{ + int n; + + if(!calc) { + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"HOOK_START_POINT",cut_db). + toInt(); + } + if((n=RDGetSqlValue("CUTS","CUT_NAME",cut_name,"HOOK_START_POINT",cut_db). + toInt())!=-1) { + return n; + } + return 0; +} + + +void RDCut::setHookStartPoint(int point) const +{ + SetRow("HOOK_START_POINT",point); +} + + +int RDCut::hookEndPoint(bool calc) const +{ + int n; + + if(!calc) { + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"HOOK_END_POINT",cut_db). + toInt(); + } + if((n=RDGetSqlValue("CUTS","CUT_NAME",cut_name,"HOOK_END_POINT",cut_db). + toInt())!=-1) { + return n; + } + return effectiveEnd(); +} + + +void RDCut::setHookEndPoint(int point) const +{ + SetRow("HOOK_END_POINT",point); +} + + +int RDCut::talkStartPoint(bool calc) const +{ + int n; + + if(!calc) { + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"TALK_START_POINT",cut_db). + toInt(); + } + if((n=RDGetSqlValue("CUTS","CUT_NAME",cut_name,"TALK_START_POINT",cut_db). + toInt())!=-1) { + return n; + } + return 0; +} + + +void RDCut::setTalkStartPoint(int point) const +{ + SetRow("TALK_START_POINT",point); +} + + +int RDCut::talkEndPoint(bool calc) const +{ + int n; + + if(!calc) { + return RDGetSqlValue("CUTS","CUT_NAME",cut_name,"TALK_END_POINT",cut_db). + toInt(); + } + if((n=RDGetSqlValue("CUTS","CUT_NAME",cut_name,"TALK_END_POINT",cut_db). + toInt())!=-1) { + return n; + } + return effectiveEnd(); +} + + +void RDCut::setTalkEndPoint(int point) const +{ + SetRow("TALK_END_POINT",point); +} + + +int RDCut::effectiveStart() const +{ + int n; + + if((n=RDGetSqlValue("CUTS","CUT_NAME",cut_name,"START_POINT",cut_db). + toInt())!=-1) { + return n; + } + return 0; +} + + +int RDCut::effectiveEnd() const +{ + int n; + + if((n=RDGetSqlValue("CUTS","CUT_NAME",cut_name,"END_POINT",cut_db). + toInt())!=-1) { + return n; + } + return (int)length(); +} + + +void RDCut::logPlayout() const +{ + QString sql= + QString().sprintf("update CUTS set LAST_PLAY_DATETIME=\"%s\",\ + PLAY_COUNTER=%d,LOCAL_COUNTER=%d where CUT_NAME=\"%s\"", + (const char *)QDateTime(QDate::currentDate(), + QTime::currentTime()).toString("yyyy-MM-dd hh:mm:ss"), + playCounter()+1,localCounter()+1,(const char *)cut_name); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; +} + + +bool RDCut::copyTo(RDStation *station,RDUser *user, + const QString &cutname,RDConfig *config) const +{ +#ifdef WIN32 + return false; +#else + QString sql; + RDSqlQuery *q; + bool ret=true; + + // + // Copy the Database Record + // + sql= + QString().sprintf("select DESCRIPTION,OUTCUE,LENGTH,\ + CODING_FORMAT,SAMPLE_RATE,\ + BIT_RATE,CHANNELS,PLAY_GAIN,START_POINT,END_POINT,\ + FADEUP_POINT,FADEDOWN_POINT,SEGUE_START_POINT,\ + SEGUE_END_POINT,HOOK_START_POINT,HOOK_END_POINT,\ + TALK_START_POINT,TALK_END_POINT from CUTS\ + where CUT_NAME=\"%s\"",(const char *)cut_name); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("update CUTS set\ + PLAY_COUNTER=0,\ + DESCRIPTION=\"%s\",\ + OUTCUE=\"%s\",\ + LENGTH=%u,\ + ORIGIN_DATETIME=now(),\ + ORIGIN_NAME=\"%s\",\ + CODING_FORMAT=%u,\ + SAMPLE_RATE=%u,\ + BIT_RATE=%u,\ + CHANNELS=%u,\ + PLAY_GAIN=%d,\ + START_POINT=%d,\ + END_POINT=%d,\ + FADEUP_POINT=%d,\ + FADEDOWN_POINT=%d,\ + SEGUE_START_POINT=%d,\ + SEGUE_END_POINT=%d,\ + HOOK_START_POINT=%d,\ + HOOK_END_POINT=%d,\ + TALK_START_POINT=%d,\ + TALK_END_POINT=%d where CUT_NAME=\"%s\"", + (const char *)q->value(0).toString().utf8(), + (const char *)q->value(1).toString().utf8(), + q->value(2).toUInt(), + (const char *)RDEscapeString(station->name()), + q->value(3).toUInt(), + q->value(4).toUInt(), + q->value(5).toUInt(), + q->value(6).toUInt(), + q->value(7).toInt(), + q->value(8).toInt(), + q->value(9).toInt(), + q->value(10).toInt(), + q->value(11).toInt(), + q->value(12).toInt(), + q->value(13).toInt(), + q->value(14).toInt(), + q->value(15).toInt(), + q->value(16).toInt(), + q->value(17).toInt(), + (const char *)cutname); + } + delete q; + q=new RDSqlQuery(sql); + delete q; + + // + // Copy the Audio + // + RDCopyAudio *conv=new RDCopyAudio(station,config); + conv->setSourceCartNumber(cart_number); + conv->setSourceCutNumber(cut_number); + conv->setDestinationCartNumber(RDCut::cartNumber(cutname)); + conv->setDestinationCutNumber(RDCut::cutNumber(cutname)); + ret=conv->runCopy(user->name(),user->password())==RDCopyAudio::ErrorOk; + delete conv; + + return ret; +#endif +} + + +void RDCut::getMetadata(RDWaveData *data) const +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select DESCRIPTION,OUTCUE,ISRC,ISCI,ORIGIN_DATETIME,\ + START_DATETIME,END_DATETIME,START_DAYPART,END_DAYPART,\ + SEGUE_START_POINT,\ + SEGUE_END_POINT,TALK_START_POINT,TALK_END_POINT,\ + START_POINT,END_POINT,HOOK_START_POINT,\ + HOOK_END_POINT,FADEUP_POINT,FADEDOWN_POINT \ + from CUTS where CUT_NAME=\"%s\"", + (const char *)cut_name); + q=new RDSqlQuery(sql); + if(q->first()) { + data->setTitle(q->value(0).toString()); + data->setOutCue(q->value(1).toString()); + data->setIsrc(q->value(2).toString()); + data->setIsci(q->value(3).toString()); + data->setOriginationDate(q->value(4).toDate()); + data->setOriginationTime(q->value(4).toTime()); + data->setStartDate(q->value(5).toDate()); + data->setStartTime(q->value(5).toTime()); + data->setEndDate(q->value(6).toDate()); + data->setEndTime(q->value(6).toTime()); + data->setDaypartStartTime(q->value(7).toTime()); + data->setDaypartEndTime(q->value(8).toTime()); + data->setSegueStartPos(q->value(9).toInt()); + data->setSegueEndPos(q->value(10).toInt()); + data->setIntroStartPos(q->value(11).toInt()); + data->setIntroEndPos(q->value(12).toInt()); + data->setStartPos(q->value(13).toInt()); + data->setEndPos(q->value(14).toInt()); + data->setHookStartPos(q->value(15).toInt()); + data->setHookEndPos(q->value(16).toInt()); + data->setFadeUpPos(q->value(17).toInt()); + data->setFadeDownPos(q->value(18).toInt()); + data->setMetadataFound(true); + } + delete q; +} + + +void RDCut::setMetadata(RDWaveData *data) const +{ + QString sql="update CUTS set "; + if(!data->title().isEmpty()) { + sql+=QString().sprintf("DESCRIPTION=\"%s\",", + (const char *)RDTextValidator::stripString(data->title()).utf8()); + } + if(!data->outCue().isEmpty()) { + sql+=QString().sprintf("OUTCUE=\"%s\",", + (const char *)RDTextValidator::stripString(data->outCue()).utf8()); + } + else { + switch(data->endType()) { + case RDWaveData::FadeEnd: + sql+="OUTCUE=\"[music fades]\","; + break; + + case RDWaveData::ColdEnd: + sql+="OUTCUE=\"[music ends cold]\","; + break; + + case RDWaveData::UnknownEnd: + break; + } + } + if(!data->isrc().isEmpty()) { + sql+=QString().sprintf("ISRC=\"%s\",", + (const char *)RDTextValidator::stripString(data->isrc()).utf8()); + } + if(!data->isci().isEmpty()) { + sql+=QString().sprintf("ISCI=\"%s\",", + (const char *)RDTextValidator::stripString(data->isci()).utf8()); + } + if(data->startPos()>=0) { + sql+=QString().sprintf("START_POINT=%d,",data->startPos()); + } + if(data->endPos()>=0) { + sql+=QString().sprintf("END_POINT=%d,",data->endPos()); + } + if((data->introStartPos()==data->startPos())&& + (data->introEndPos()==data->endPos())) { + sql+="TALK_START_POINT=-1,TALK_END_POINT=-1,"; + } + else { + if(data->introStartPos()>=0) { + if(data->introStartPos()<data->startPos()) { + sql+=QString().sprintf("TALK_START_POINT=%d,",data->startPos()); + } + else { + sql+=QString().sprintf("TALK_START_POINT=%d,",data->introStartPos()); + } + } + if(data->introEndPos()>=0) { + if((data->introEndPos()>data->endPos())&&(data->endPos()!=-1)) { + sql+=QString().sprintf("TALK_END_POINT=%d,",data->endPos()); + } + else { + sql+=QString().sprintf("TALK_END_POINT=%d,",data->introEndPos()); + } + } + } + if(((data->segueStartPos()==data->startPos())&& + (data->segueEndPos()==data->endPos()))||(data->segueStartPos()==0)) { + sql+="SEGUE_START_POINT=-1,SEGUE_END_POINT=-1,"; + } + else { + if(data->segueStartPos()>=0) { + if(data->segueStartPos()<data->startPos()) { + sql+=QString().sprintf("SEGUE_START_POINT=%d,",data->startPos()); + } + else { + sql+=QString().sprintf("SEGUE_START_POINT=%d,",data->segueStartPos()); + } + } + if(data->segueEndPos()>=0) { + if(data->segueEndPos()>data->endPos()) { + if(data->endPos()<0) { + sql+=QString().sprintf("SEGUE_END_POINT=%d,",data->segueStartPos()+1); + } + else { + sql+=QString().sprintf("SEGUE_END_POINT=%d,",data->endPos()); + } + } + else { + sql+=QString().sprintf("SEGUE_END_POINT=%d,",data->segueEndPos()); + } + } + } + if(data->startDate().isValid()&&data->endDate().isValid()&& + (data->startTime().isNull())&&(data->endTime().isNull())) { + data->setEndTime(QTime(23,59,59)); + } + if(data->daypartStartTime().isValid()&&data->daypartEndTime().isValid()&& + (data->daypartStartTime()<data->daypartEndTime())) { + sql+="START_DAYPART=\""+data->daypartStartTime().toString("hh:mm:ss")+"\","+ + "END_DAYPART=\""+data->daypartEndTime().toString("hh:mm:ss")+"\","; + } + if((data->hookStartPos()>=data->startPos())&& + (data->hookStartPos()<=data->endPos())&& + (data->hookEndPos()>=data->startPos())&& + (data->hookEndPos()<=data->endPos())&& + (data->hookEndPos()>data->hookStartPos())) { + sql+=QString().sprintf("HOOK_START_POINT=%d,HOOK_END_POINT=%d,", + data->hookStartPos(),data->hookEndPos()); + } + if((data->fadeUpPos()>data->startPos())&& + (data->fadeUpPos()<=data->endPos())) { + sql+=QString().sprintf("FADEUP_POINT=%d,",data->fadeUpPos()); + } + if((data->fadeDownPos()>data->startPos())&& + (data->fadeDownPos()<=data->endPos())) { + sql+=QString().sprintf("FADEDOWN_POINT=%d,",data->fadeDownPos()); + } + if((data->startDate()>QDate(1900,1,1))&&(data->endDate().year()<8000)) { + if(data->startTime().isValid()) { + sql+=QString().sprintf("START_DATETIME=\"%s %s\",", + (const char *)data->startDate(). + toString("yyyy-MM-dd"), + (const char *)data->startTime(). + toString("hh:mm:ss")); + } + else { + sql+=QString().sprintf("START_DATETIME=\"%s 00:00:00\",", + (const char *)data->startDate(). + toString("yyyy-MM-dd")); + } + if(data->endDate().isValid()&&(data->endDate().year()<8000)) { + if(data->endTime().isValid()) { + sql+=QString().sprintf("END_DATETIME=\"%s %s\",", + (const char *)data->endDate(). + toString("yyyy-MM-dd"), + (const char *)data->endTime(). + toString("hh:mm:ss")); + } + else { + sql+=QString().sprintf("END_DATETIME=\"%s 23:59:59\",", + (const char *)data->endDate(). + toString("yyyy-MM-dd")); + } + } + } + if(sql.right(1)==",") { + sql=sql.left(sql.length()-1); + sql+=QString(). + sprintf(" where CUT_NAME=\"%s\"",(const char *)cut_name.utf8()); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + } +} + + +QString RDCut::xml() const +{ +#ifdef WIN32 + return QString(); +#else + QString sql; + RDSqlQuery *q; + QString ret=""; + + sql=QString().sprintf("select EVERGREEN,DESCRIPTION,OUTCUE,ISRC,ISCI,\ + LENGTH,ORIGIN_DATETIME,START_DATETIME,END_DATETIME,\ + SUN,MON,TUE,WED,THU,FRI,SAT,START_DAYPART,END_DAYPART,\ + ORIGIN_NAME,WEIGHT,LAST_PLAY_DATETIME,\ + PLAY_COUNTER,LOCAL_COUNTER,VALIDITY,CODING_FORMAT,\ + SAMPLE_RATE,BIT_RATE,CHANNELS,PLAY_GAIN,START_POINT,\ + END_POINT,FADEUP_POINT,FADEDOWN_POINT,\ + SEGUE_START_POINT,SEGUE_END_POINT,SEGUE_GAIN\ + HOOK_START_POINT,HOOK_END_POINT,\ + TALK_START_POINT,TALK_END_POINT \ + from CUTS where CUT_NAME=\"%s\"", + (const char *)cut_name); + q=new RDSqlQuery(sql); + if(q->first()) { + ret+="<cut>\n"; + ret+=" "+RDXmlField("cutName",cut_name); + ret+=" "+RDXmlField("cartNumber",cart_number); + ret+=" "+RDXmlField("cutNumber",cut_number); + ret+=" "+RDXmlField("evergreen",RDBool(q->value(0).toString())); + ret+=" "+RDXmlField("description",q->value(1).toString()); + ret+=" "+RDXmlField("outcue",q->value(2).toString()); + ret+=" "+RDXmlField("isrc",q->value(3).toString()); + ret+=" "+RDXmlField("isci",q->value(4).toString()); + ret+=" "+RDXmlField("length",q->value(5).toUInt()); + if(q->value(6).isNull()) { + ret+=" "+RDXmlField("originDatetime",""); + } + else { + ret+=" "+RDXmlField("originDatetime",q->value(6).toDateTime()); + } + if(q->value(7).isNull()) { + ret+=" "+RDXmlField("startDatetime",""); + } + else { + ret+=" "+RDXmlField("startDatetime",q->value(7).toDateTime()); + } + if(q->value(8).isNull()) { + ret+=" "+RDXmlField("endDatetime",""); + } + else { + ret+=" "+RDXmlField("endDatetime",q->value(8).toDateTime()); + } + ret+=" "+RDXmlField("sun",RDBool(q->value(9).toString())); + ret+=" "+RDXmlField("mon",RDBool(q->value(10).toString())); + ret+=" "+RDXmlField("tue",RDBool(q->value(11).toString())); + ret+=" "+RDXmlField("wed",RDBool(q->value(12).toString())); + ret+=" "+RDXmlField("thu",RDBool(q->value(13).toString())); + ret+=" "+RDXmlField("fri",RDBool(q->value(14).toString())); + ret+=" "+RDXmlField("sat",RDBool(q->value(15).toString())); + if(q->value(16).isNull()) { + ret+=" "+RDXmlField("startDaypart",""); + } + else { + ret+=" "+RDXmlField("startDaypart",q->value(16).toTime()); + } + if(q->value(17).isNull()) { + ret+=" "+RDXmlField("endDaypart",""); + } + else { + ret+=" "+RDXmlField("endDaypart",q->value(17).toTime()); + } + ret+=" "+RDXmlField("originName",q->value(18).toString()); + ret+=" "+RDXmlField("weight",q->value(19).toUInt()); + ret+=" "+RDXmlField("lastPlayDatetime",q->value(20).toDateTime()); + ret+=" "+RDXmlField("playCounter",q->value(21).toUInt()); + ret+=" "+RDXmlField("localCounter",q->value(22).toUInt()); + ret+=" "+RDXmlField("validity",q->value(23).toUInt()); + ret+=" "+RDXmlField("codingFormat",q->value(24).toUInt()); + ret+=" "+RDXmlField("sampleRate",q->value(25).toUInt()); + ret+=" "+RDXmlField("bitRate",q->value(26).toUInt()); + ret+=" "+RDXmlField("channels",q->value(27).toUInt()); + ret+=" "+RDXmlField("playGain",q->value(28).toUInt()); + ret+=" "+RDXmlField("startPoint",q->value(29).toInt()); + ret+=" "+RDXmlField("endPoint",q->value(30).toInt()); + ret+=" "+RDXmlField("fadeupPoint",q->value(31).toInt()); + ret+=" "+RDXmlField("fadedownPoint",q->value(32).toInt()); + ret+=" "+RDXmlField("segueStartPoint",q->value(33).toInt()); + ret+=" "+RDXmlField("segueEndPoint",q->value(34).toInt()); + ret+=" "+RDXmlField("segueGain",q->value(35).toInt()); + ret+=" "+RDXmlField("hookStartPoint",q->value(36).toInt()); + ret+=" "+RDXmlField("hookEndPoint",q->value(37).toInt()); + ret+=" "+RDXmlField("talkStartPoint",q->value(38).toInt()); + ret+=" "+RDXmlField("talkEndPoint",q->value(39).toInt()); + ret+="</cut>\n"; + } + delete q; + return ret; +#endif // WIN32 +} + + +bool RDCut::checkInRecording(const QString &stationname,RDSettings *settings, + unsigned msecs) const +{ +#ifdef WIN32 + return false; +#else + QString sql; + RDSqlQuery *q; + int format; + + switch(settings->format()) { + case RDSettings::MpegL2: + format=1; + break; + + default: + format=0; + break; + } + sql=QString().sprintf("update CUTS set START_POINT=0,END_POINT=%d,\ + FADEUP_POINT=-1,FADEDOWN_POINT=-1,\ + SEGUE_START_POINT=-1,SEGUE_END_POINT=-1,\ + TALK_START_POINT=-1,TALK_END_POINT=-1,\ + HOOK_START_POINT=-1,HOOK_END_POINT=-1,\ + PLAY_GAIN=0,PLAY_COUNTER=0,LOCAL_COUNTER=0,\ + CODING_FORMAT=%d,SAMPLE_RATE=%d,\ + BIT_RATE=%d,CHANNELS=%d,LENGTH=%d,\ + ORIGIN_DATETIME=\"%s %s\",ORIGIN_NAME=\"%s\",\ + UPLOAD_DATETIME=null \ + where CUT_NAME=\"%s\"", + msecs, + format, + settings->sampleRate(), + settings->bitRate(), + settings->channels(), + msecs, + (const char *)QDate::currentDate(). + toString("yyyy-MM-dd"), + (const char *)QTime::currentTime(). + toString("hh:mm:ss"), + (const char *)stationname, + (const char *)cut_name); + q=new RDSqlQuery(sql); + delete q; + return true; +#endif // WIN32 +} + + +void RDCut::autoTrim(RDCut::AudioEnd end,int level) +{ +#ifndef WIN32 + int point; + int start_point=0; + int end_point=-1; + + if(!exists()) { + return; + } + QString wavename=RDCut::pathName(cut_name); + RDWaveFile *wave=new RDWaveFile(wavename); + if(!wave->openWave()) { + delete wave; + return; + } + if(level>=0) { + if((end==RDCut::AudioHead)||(end==RDCut::AudioBoth)) { + setStartPoint(0); + } + if((end==RDCut::AudioTail)||(end==RDCut::AudioBoth)) { + setEndPoint(wave->getExtTimeLength()); + } + setLength(endPoint()-startPoint()); + delete wave; + return; + } + if((end==RDCut::AudioHead)||(end==RDCut::AudioBoth)) { + if((point=wave->startTrim(REFERENCE_LEVEL-level))>-1) { + start_point=(int)(1000.0*(double)point/(double)wave->getSamplesPerSec()); + } + } + if((end==RDCut::AudioTail)||(end==RDCut::AudioBoth)) { + if((point=wave->endTrim(+REFERENCE_LEVEL-level))>-1) { + end_point=(int)(1000.0*(double)point/(double)wave->getSamplesPerSec()); + } + else { + end_point=wave->getExtTimeLength(); + } + } + else { + end_point=wave->getExtTimeLength(); + } + setStartPoint(start_point); + setEndPoint(end_point); + if(segueEndPoint()>end_point) { + setSegueEndPoint(end_point); + } + if(segueStartPoint()>end_point) { + setSegueStartPoint(-1); + setSegueEndPoint(-1); + } + setLength(end_point-start_point); + delete wave; +#endif // WIN32 +} + + +void RDCut::autoSegue(int level,int length) +{ +#ifndef WIN32 + int point; + int start_point; + + if(!exists()) { + return; + } + QString wavename=RDCut::pathName(cut_name); + RDWaveFile *wave=new RDWaveFile(wavename); + if(!wave->openWave()) { + delete wave; + return; + } + if(level<0) { + if((point=wave->endTrim(+REFERENCE_LEVEL-level))>-1) { + start_point=(int)(1000.0*(double)point/(double)wave->getSamplesPerSec()); + setSegueStartPoint(start_point); + if(length>0 && (start_point+length)<endPoint()){ + setSegueEndPoint(start_point+length); + } + else { + setSegueEndPoint(endPoint()); + } + } + } + else { + if(length>0) { + if((endPoint()-length)>startPoint()){ + setSegueStartPoint(endPoint()-length); + setSegueEndPoint(endPoint()); + } + else { + setSegueStartPoint(startPoint()); + setSegueEndPoint(endPoint()); + } + } + } + delete wave; +#endif // WIN32 +} + + +void RDCut::reset() const +{ +#ifndef WIN32 + QString sql; + RDSqlQuery *q; + int format; + + if(!exists()) { + return; + } + RDWaveFile *wave=new RDWaveFile(RDCut::pathName(cut_name)); + if(wave->openWave()) { + switch(wave->getFormatTag()) { + case WAVE_FORMAT_MPEG: + format=wave->getHeadLayer()-1; + break; + default: + format=0; + break; + } + sql=QString().sprintf("update CUTS set LENGTH=%u,\ + ORIGIN_DATETIME=NOW(),\ + ORIGIN_NAME=\"\",\ + LAST_PLAY_DATETIME=NULL,PLAY_COUNTER=0,\ + CODING_FORMAT=%d,SAMPLE_RATE=%u,BIT_RATE=%u,\ + CHANNELS=%u,PLAY_GAIN=0,\ + START_POINT=0,END_POINT=%u,FADEUP_POINT=-1,\ + FADEDOWN_POINT=-1,\ + SEGUE_START_POINT=-1,SEGUE_END_POINT=-1,\ + SEGUE_GAIN=%d,\ + HOOK_START_POINT=-1,HOOK_END_POINT=-1,\ + TALK_START_POINT=-1,TALK_END_POINT=-1 \ + where CUT_NAME=\"%s\"", + wave->getExtTimeLength(), + format, + wave->getSamplesPerSec(), + wave->getHeadBitRate(), + wave->getChannels(), + wave->getExtTimeLength(), + RD_FADE_DEPTH, + (const char *)cut_name); + } + else { + sql=QString().sprintf("update CUTS set LENGTH=0,\ + ORIGIN_DATETIME=NULL,\ + ORIGIN_NAME=\"\",\ + LAST_PLAY_DATETIME=NULL,PLAY_COUNTER=0,\ + CODING_FORMAT=0,SAMPLE_RATE=0,BIT_RATE=0,\ + CHANNELS=0,PLAY_GAIN=0,\ + START_POINT=-1,END_POINT=-1,FADEUP_POINT=-1,\ + FADEDOWN_POINT=-1,\ + SEGUE_START_POINT=-1,SEGUE_END_POINT=-1,\ + SEGUE_GAIN= %d,\ + HOOK_START_POINT=-1,HOOK_END_POINT=-1,\ + TALK_START_POINT=-1,TALK_END_POINT=-1 \ + where CUT_NAME=\"%s\"", + RD_FADE_DEPTH, + (const char *)cut_name); + } + q=new RDSqlQuery(sql,cut_db); + delete q; + wave->closeWave(); + delete wave; +#endif // WIN32 +} + + +void RDCut::connect(QObject *receiver,const char *member) const +{ + cut_signal->connect(receiver,member); +} + + +void RDCut::disconnect(QObject *receiver,const char *member) const +{ + cut_signal->disconnect(receiver,member); +} + + +QString RDCut::cutName(unsigned cartnum,unsigned cutnum) +{ + if((cartnum<1)||(cartnum>RD_MAX_CART_NUMBER)|| + (cutnum<1)||(cutnum>RD_MAX_CUT_NUMBER)) { + return QString(); + } + return QString().sprintf("%06u_%03u",cartnum,cutnum); +} + + +unsigned RDCut::cartNumber(const QString &cutname) +{ + return cutname.left(6).toUInt(); +} + + +unsigned RDCut::cutNumber(const QString &cutname) +{ + return cutname.right(3).toUInt(); +} + + +bool RDCut::exists(unsigned cartnum,unsigned cutnum) +{ + return RDCut::exists(RDCut::cutName(cartnum,cutnum)); +} + + +bool RDCut::exists(const QString &cutname) +{ + RDSqlQuery *q=new RDSqlQuery(QString().sprintf("select CUT_NAME from CUTS\ + where CUT_NAME=\"%s\"", + (const char *)cutname)); + bool ret=q->first(); + delete q; + return ret; +} + + +QString RDCut::pathName(unsigned cartnum,unsigned cutnum) +{ + return RDCut::pathName(RDCut::cutName(cartnum,cutnum)); +} + + +QString RDCut::pathName(const QString &cutname) +{ + return RDConfiguration()->audioFileName(cutname); +} + + +bool RDCut::FileCopy(const QString &srcfile,const QString &destfile) const +{ +#ifndef WIN32 + int src_fd; + int dest_fd; + struct stat src_stat; + struct stat dest_stat; + char *buf=NULL; + int n; + unsigned bytes=0; + int previous_step=0; + int step=0; + + if((src_fd=open((const char *)srcfile.utf8(),O_RDONLY))<0) { + return false; + } + if(fstat(src_fd,&src_stat)<0) { + close(src_fd); + return false; + } + if((dest_fd=open((const char *)destfile.utf8(),O_RDWR|O_CREAT,src_stat.st_mode)) + <0) { + close(src_fd); + return false; + } + if(fstat(dest_fd,&dest_stat)<0) { + close(src_fd); + close(dest_fd); + return false; + } + buf=(char *)malloc(dest_stat.st_blksize); + while((n=read(src_fd,buf,dest_stat.st_blksize))==dest_stat.st_blksize) { + write(dest_fd,buf,dest_stat.st_blksize); + bytes+=dest_stat.st_blksize; + if((step=10*bytes/src_stat.st_size)!=previous_step) { + cut_signal->setValue(step); + cut_signal->activate(); + previous_step=step; + } + } + write(dest_fd,buf,n); + cut_signal->setValue(10); + cut_signal->activate(); + free(buf); + close(src_fd); + close(dest_fd); +#endif + return true; +} + + +void RDCut::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE CUTS SET %s=\"%s\" WHERE CUT_NAME=\"%s\"", + (const char *)param, + (const char *)RDEscapeString(value.utf8()), + (const char *)cut_name); + q=new RDSqlQuery(sql,cut_db); + delete q; +} + + +void RDCut::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE CUTS SET %s=%u WHERE CUT_NAME=\"%s\"", + (const char *)param, + value, + (const char *)cut_name); + q=new RDSqlQuery(sql,cut_db); + delete q; +} + + +void RDCut::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE CUTS SET %s=%d WHERE CUT_NAME=\"%s\"", + (const char *)param, + value, + (const char *)cut_name); + q=new RDSqlQuery(sql,cut_db); + delete q; +} + + +void RDCut::SetRow(const QString ¶m,const QDateTime &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE CUTS SET %s=\"%s\" WHERE CUT_NAME=\"%s\"", + (const char *)param, + (const char *)value.toString("yyyy-MM-dd hh:mm:ss"), + (const char *)cut_name); + q=new RDSqlQuery(sql,cut_db); + delete q; +} + + +void RDCut::SetRow(const QString ¶m,const QDate &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE CUTS SET %s=\"%s\" WHERE CUT_NAME=\"%s\"", + (const char *)param, + (const char *)value.toString("yyyy-MM-dd"), + (const char *)cut_name); + q=new RDSqlQuery(sql,cut_db); + delete q; +} + + +void RDCut::SetRow(const QString ¶m,const QTime &value) const +{ + RDSqlQuery *q; + QString sql; + sql=QString().sprintf("UPDATE CUTS SET %s=\"%s\" WHERE CUT_NAME=\"%s\"", + (const char *)param, + (const char *)value.toString("hh:mm:ss"), + (const char *)cut_name); + q=new RDSqlQuery(sql,cut_db); + delete q; +} + + +void RDCut::SetRow(const QString ¶m) const +{ + RDSqlQuery *q; + QString sql; + sql=QString().sprintf("UPDATE CUTS SET %s=NULL WHERE CUT_NAME=\"%s\"", + (const char *)param, + (const char *)cut_name); + q=new RDSqlQuery(sql,cut_db); + delete q; +} diff --git a/lib/rdcut.h b/lib/rdcut.h new file mode 100644 index 00000000..95eb23dc --- /dev/null +++ b/lib/rdcut.h @@ -0,0 +1,163 @@ +// rdcut.h +// +// Abstract a Rivendell Cut +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcut.h,v 1.44.6.2.2.1 2014/05/22 14:30:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> +#include <qsignal.h> +#include <qobject.h> + +#include <rdconfig.h> +#include <rdwavedata.h> +#include <rdsettings.h> +#include <rdstation.h> +#include <rduser.h> + +#ifndef RDCUT_H +#define RDCUT_H + +class RDCut +{ + public: + enum AudioEnd {AudioBoth=0,AudioHead=1,AudioTail=2}; + enum IsrcFormat {RawIsrc=0,FormattedIsrc=1}; + enum Validity {NeverValid=0,ConditionallyValid=1,AlwaysValid=2,FutureValid=3}; + RDCut(const QString &name,bool create=false,QSqlDatabase *db=0); + RDCut(unsigned cartnum,int cutnum,bool create=false,QSqlDatabase *db=0); + ~RDCut(); + bool exists() const; + bool isValid() const; + bool isValid(const QTime &time) const; + bool isValid(const QDateTime &datetime) const; + QString cutName() const; + unsigned cutNumber() const; + unsigned cartNumber() const; + void setCartNumber(unsigned num) const; + bool evergreen() const; + void setEvergreen(bool state) const; + QString description() const; + void setDescription(const QString &string) const; + QString outcue() const; + void setOutcue(const QString &string) const; + QString isrc(IsrcFormat fmt=RawIsrc) const; + void setIsrc(const QString &isrc) const; + QString isci() const; + void setIsci(const QString &isci) const; + unsigned length() const; + void setLength(int length) const; + QDateTime originDatetime(bool *valid) const; + void setOriginDatetime(const QDateTime &datetime) const; + QDateTime startDatetime(bool *valid) const; + void setStartDatetime(const QDateTime &datetime,bool valid) const; + QDateTime endDatetime(bool *valid) const; + void setEndDatetime(const QDateTime &datetime,bool valid) const; + QTime startDaypart(bool *valid) const; + void setStartDaypart(const QTime &time,bool valid) const; + QTime endDaypart(bool *valid) const; + void setEndDaypart(const QTime &time,bool valid) const; + bool weekPart(int dayofweek) const; + void setWeekPart(int dayofweek,bool state) const; + QString originName() const; + void setOriginName(const QString &name) const; + unsigned weight() const; + void setWeight(int value) const; + QDateTime lastPlayDatetime(bool *valid) const; + void setLastPlayDatetime(const QDateTime &datetime,bool valid) const; + QDateTime uploadDatetime(bool *valid) const; + void setUploadDatetime(const QDateTime &datetime,bool valid) const; + unsigned playCounter() const; + void setPlayCounter(unsigned count) const; + RDCut::Validity validity() const; + void setValidity(RDCut::Validity state); + unsigned localCounter() const; + void setLocalCounter(unsigned count) const; + unsigned codingFormat() const; + void setCodingFormat(unsigned format) const; + unsigned sampleRate() const; + void setSampleRate(unsigned rate) const; + unsigned bitRate() const; + void setBitRate(unsigned rate) const; + unsigned channels() const; + void setChannels(unsigned chan) const; + int playGain() const; + void setPlayGain(int gain) const; + int startPoint(bool calc=false) const; + void setStartPoint(int point) const; + int endPoint(bool calc=false) const; + void setEndPoint(int point) const; + int fadeupPoint(bool calc=false) const; + void setFadeupPoint(int point) const; + int fadedownPoint(bool calc=false) const; + void setFadedownPoint(int point) const; + int segueStartPoint(bool calc=false) const; + void setSegueStartPoint(int point) const; + int segueEndPoint(bool calc=false) const; + void setSegueEndPoint(int point) const; + int segueGain() const; + void setSegueGain(int gain) const; + int hookStartPoint(bool calc=false) const; + void setHookStartPoint(int point) const; + int hookEndPoint(bool calc=false) const; + void setHookEndPoint(int point) const; + int talkStartPoint(bool calc=false) const; + void setTalkStartPoint(int point) const; + int talkEndPoint(bool calc=false) const; + void setTalkEndPoint(int point) const; + int effectiveStart() const; + int effectiveEnd() const; + void logPlayout() const; + bool copyTo(RDStation *station,RDUser *user,const QString &cutname, + RDConfig *config) const; + void getMetadata(RDWaveData *data) const; + void setMetadata(RDWaveData *data) const; + QString xml() const; + bool checkInRecording(const QString &stationname,RDSettings *settings, + unsigned msecs) const; + void autoTrim(RDCut::AudioEnd end,int level); + void autoSegue(int level,int length); + void reset() const; + void connect(QObject *receiver,const char *member) const; + void disconnect(QObject *receiver,const char *member) const; + static QString cutName(unsigned cartnum,unsigned cutnum); + static unsigned cartNumber(const QString &cutname); + static unsigned cutNumber(const QString &cutname); + static bool exists(unsigned cartnum,unsigned cutnum); + static bool exists(const QString &cutname); + static QString pathName(unsigned cartnum,unsigned cutnum); + static QString pathName(const QString &cutname); + + private: + bool FileCopy(const QString &srcfile,const QString &destfile) const; + void SetRow(const QString ¶m,const QString &value) const; + void SetRow(const QString ¶m,unsigned value) const; + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,const QDateTime &value) const; + void SetRow(const QString ¶m,const QDate &value) const; + void SetRow(const QString ¶m,const QTime &value) const; + void SetRow(const QString ¶m) const; + QSignal *cut_signal; + QSqlDatabase *cut_db; + QString cut_name; + unsigned cart_number; + unsigned cut_number; +}; + + +#endif diff --git a/lib/rdcut_dialog.cpp b/lib/rdcut_dialog.cpp new file mode 100644 index 00000000..27e57a9d --- /dev/null +++ b/lib/rdcut_dialog.cpp @@ -0,0 +1,675 @@ +// rdcut_dialog.cpp +// +// A widget to select a Rivendell Cut. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcut_dialog.cpp,v 1.31.4.2 2013/11/15 18:24:08 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> + +#include <qpushbutton.h> +#include <qlabel.h> +#include <qsqlquery.h> +#include <qapplication.h> +#include <qeventloop.h> + +#include <rdcut_dialog.h> +#include <rdcart_search_text.h> +#include <rdtextvalidator.h> +#include <rdadd_cart.h> +#include <rdprofile.h> +#include <rddb.h> + +// +// Icons +// +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" + + +RDCutDialog::RDCutDialog(QString *cutname,RDStation *station,RDSystem *system, + QString *filter,QString *group,QString *schedcode, + QString username,bool show_clear,bool allow_add, + bool exclude_tracks,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + cut_cutname=cutname; + cut_exclude_tracks=exclude_tracks; + cut_group=group; + cut_schedcode=schedcode; + cut_username=username; + cut_allow_clear=show_clear; + cut_filter_mode=station->filterMode(); + cut_system=system; + + if(filter==NULL) { + cut_filter=new QString(); + local_filter=true; + } + else { + cut_filter=filter; + local_filter=false; + } + + setCaption(tr("Select Cut")); + + // + // Create Icons + // + cut_playout_map=new QPixmap(play_xpm); + cut_macro_map=new QPixmap(rml5_xpm); + + // + // Generate Fonts + // + QFont label_font("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont progress_font("Helvetica",16,QFont::Bold); + progress_font.setPixelSize(16); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Progress Dialog + // + cut_progress_dialog= + new QProgressDialog(tr("Please Wait..."),"Cancel",10,this, + "cut_progress_dialog",false, + Qt::WStyle_Customize|Qt::WStyle_NormalBorder); + cut_progress_dialog->setCaption(" "); + QLabel *label=new QLabel(tr("Please Wait..."),cut_progress_dialog); + label->setAlignment(AlignCenter); + label->setFont(progress_font); + cut_progress_dialog->setLabel(label); + cut_progress_dialog->setCancelButton(NULL); + cut_progress_dialog->setMinimumDuration(2000); + + // + // Filter Selector + // + cut_filter_edit=new QLineEdit(this,"cut_filter_edit"); + label=new QLabel(cut_filter_edit,tr("Cart Filter:"),this,"cut_filter_label"); + label->setGeometry(10,10,85,20); + label->setAlignment(AlignRight|AlignVCenter); + label->setFont(label_font); + connect(cut_filter_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(filterChangedData(const QString &))); + + // + // Filter Search Button + // + cut_search_button=new QPushButton(this,"cut_search_button"); + cut_search_button->setGeometry(sizeHint().width()-140,8,60,24); + cut_search_button->setText(tr("&Search")); + cut_search_button->setFont(label_font); + connect(cut_search_button,SIGNAL(clicked()),this,SLOT(searchButtonData())); + + // + // Filter Clear Button + // + cut_clear_button=new QPushButton(this,"cut_clear_button"); + cut_clear_button->setGeometry(sizeHint().width()-70,8,60,24); + cut_clear_button->setFont(label_font); + cut_clear_button->setText(tr("C&lear")); + connect(cut_clear_button,SIGNAL(clicked()),this,SLOT(clearData())); + + // + // Group Selector + // + cut_group_box=new QComboBox(this,"cut_clear_box"); + cut_group_box->setGeometry(100,40,140,20); + label=new QLabel(cut_filter_edit,tr("Group:"),this,"cut_group_label"); + label->setGeometry(10,40,85,20); + label->setAlignment(AlignRight|AlignVCenter); + label->setFont(label_font); + connect(cut_group_box,SIGNAL(activated(const QString &)), + this,SLOT(groupActivatedData(const QString &))); + + // + // Scheduler Code Selector + // + cut_schedcode_box=new QComboBox(this,"cut_schedcode_box"); + cut_schedcode_box->setGeometry(380,40,sizeHint().width()-390,20); + cut_schedcode_label=new QLabel(cut_schedcode_box,tr("Scheduler Code:"), + this,"cut_schedcode_label"); + cut_schedcode_label->setGeometry(260,40,115,20); + cut_schedcode_label->setAlignment(AlignRight|AlignVCenter); + cut_schedcode_label->setFont(label_font); + connect(cut_schedcode_box,SIGNAL(activated(const QString &)), + this,SLOT(groupActivatedData(const QString &))); + + // + // Search Limit Checkbox + // + cart_limit_box=new QCheckBox(this,"cart_limit_box"); + cart_limit_box->setGeometry(100,72,15,15); + cart_limit_box->setChecked(true); + label=new QLabel(cart_limit_box,tr("Show Only First")+ + QString().sprintf(" %d ", + RD_LIMITED_CART_SEARCH_QUANTITY)+tr("Matches"), + this,"cart_limit_label"); + label->setGeometry(120,70,300,20); + label->setAlignment(AlignLeft|AlignVCenter); + label->setFont(label_font); + connect(cart_limit_box,SIGNAL(stateChanged(int)), + this,SLOT(limitChangedData(int))); + + // + // Cart List + // + cut_cart_list=new RDListView(this,"cut_cart_list"); + cut_cart_list->setGeometry(10,120,300,200); + cut_cart_list->setAllColumnsShowFocus(true); + cut_cart_list->setItemMargin(5); + connect(cut_cart_list,SIGNAL(selectionChanged()), + this,SLOT(selectionChangedData())); + connect(cut_cart_list,SIGNAL(clicked(QListViewItem *)), + this,SLOT(cartClickedData(QListViewItem *))); + label=new QLabel(cut_cart_list,tr("Carts"),this,"cut_cart_label"); + label->setGeometry(15,100,100,20); + label->setFont(label_font); + cut_cart_list->addColumn(""); + cut_cart_list->setColumnAlignment(0,Qt::AlignHCenter); + cut_cart_list->addColumn(tr("NUMBER")); + + cut_cart_list->setColumnAlignment(1,Qt::AlignHCenter); + cut_cart_list->addColumn(tr("TITLE")); + cut_cart_list->setColumnAlignment(2,Qt::AlignLeft); + + cut_cart_list->addColumn(tr("GROUP")); + cut_cart_list->setColumnAlignment(3,Qt::AlignCenter); + + // + // Cut List + // + cut_cut_list=new QListView(this,"cut_cut_list"); + cut_cut_list->setGeometry(320,120,sizeHint().width()-330,200); + cut_cut_list->setAllColumnsShowFocus(true); + cut_cut_list->setItemMargin(5); + label=new QLabel(cut_cut_list,tr("Cuts"),this,"cut_cut_label"); + label->setGeometry(325,100,100,20); + label->setFont(label_font); + cut_cut_list->addColumn(tr("DESCRIPTION")); + cut_cut_list->setColumnAlignment(0,Qt::AlignLeft); + + cut_cut_list->addColumn(tr("NUMBER")); + cut_cut_list->setColumnAlignment(1,Qt::AlignLeft); + + + QPushButton *button=NULL; + + // + // Add Button + // + button=new QPushButton(tr("&Add New\nCart"),this,"add_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(label_font); + connect(button,SIGNAL(clicked()),this,SLOT(addButtonData())); + if(!allow_add) { + button->hide(); + } + + // + // Clear Button + // + button=new QPushButton(tr("&Clear"),this,"clear_button"); + button->setFont(label_font); + connect(button,SIGNAL(clicked()),this,SLOT(clearButtonData())); + if(!show_clear) { + button->hide(); + } + if(allow_add) { + button->setGeometry(100,sizeHint().height()-60,80,50); + } + else { + button->setGeometry(10,sizeHint().height()-60,80,50); + } + + // + // OK Button + // + cut_ok_button=new QPushButton(tr("&OK"),this,"ok_button"); + cut_ok_button-> + setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + cut_ok_button->setFont(label_font); + cut_ok_button->setDefault(true); + connect(cut_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + cut_cancel_button=new QPushButton(tr("&Cancel"),this,"cancel_button"); + cut_cancel_button-> + setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + cut_cancel_button->setFont(label_font); + connect(cut_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + if(cut_cutname->isEmpty()) { + cut_ok_button->setDisabled(true); + } + switch(cut_filter_mode) { + case RDStation::FilterAsynchronous: + cut_search_button->setDefault(true); + cut_filter_edit->setGeometry(100,10,sizeHint().width()-250,20); + break; + + case RDStation::FilterSynchronous: + cut_ok_button->setDefault(true); + cut_search_button->hide(); + cut_filter_edit->setGeometry(100,10,sizeHint().width()-180,20); + } + BuildGroupList(); + cut_filter_edit->setText(*cut_filter); + RefreshCarts(); + RefreshCuts(); + SelectCut(*cut_cutname); +} + + +RDCutDialog::~RDCutDialog() +{ + if(local_filter) { + delete cut_filter; + } +} + + +QSize RDCutDialog::sizeHint() const +{ + return QSize(550,400); +} + + +QSizePolicy RDCutDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int RDCutDialog::exec() +{ + LoadState(); + return QDialog::exec(); +} + + +void RDCutDialog::filterChangedData(const QString &str) +{ + cut_search_button->setEnabled(true); + switch(cut_filter_mode) { + case RDStation::FilterSynchronous: + searchButtonData(); + break; + + case RDStation::FilterAsynchronous: + break; + } +} + + +void RDCutDialog::clearData() +{ + cut_filter_edit->clear(); + filterChangedData(""); +} + + +void RDCutDialog::groupActivatedData(const QString &str) +{ + filterChangedData(""); +} + + +void RDCutDialog::limitChangedData(int state) +{ + filterChangedData(""); +} + + +void RDCutDialog::cartClickedData(QListViewItem *) +{ + cut_ok_button->setEnabled(true); +} + + +void RDCutDialog::selectionChangedData() +{ + RefreshCuts(); + if(cut_cut_list->firstChild()!=NULL) { + cut_cut_list->setSelected(cut_cut_list->firstChild(),true); + } +} + + +void RDCutDialog::searchButtonData() +{ + if(cut_filter_edit->text().isEmpty()) { + cut_clear_button->setDisabled(true); + } + else { + cut_clear_button->setEnabled(true); + } + RefreshCarts(); + RefreshCuts(); +} + + +void RDCutDialog::clearButtonData() +{ + RDListViewItem *item=(RDListViewItem *)cut_cart_list->selectedItem(); + if(item!=NULL) { + cut_cart_list->setSelected(item,false); + } + cut_cut_list->clear(); +} + + +void RDCutDialog::addButtonData() +{ + QString cart_group=cut_group_box->currentText(); + RDCart::Type cart_type=RDCart::Audio; + QString cart_title; + QString sql; + RDSqlQuery *q; + int cart_num=-1; + + RDAddCart *add_cart=new RDAddCart(&cart_group,&cart_type,&cart_title, + cut_username,cut_system,this); + if((cart_num=add_cart->exec())<0) { + delete add_cart; + return; + } + sql=QString().sprintf("insert into CART set \ + NUMBER=%d,TYPE=%d,GROUP_NAME=\"%s\",TITLE=\"%s\"", + cart_num,cart_type, + (const char *)cart_group, + (const char *)cart_title); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("insert into CUTS set CUT_NAME=\"%06d_001\",\ + CART_NUMBER=%d,DESCRIPTION=\"Cut 001\"", + cart_num,cart_num); + q=new RDSqlQuery(sql); + delete q; + + RDListViewItem *item=new RDListViewItem(cut_cart_list); + item->setPixmap(0,*cut_playout_map); + item->setText(1,QString().sprintf("%06d",cart_num)); + item->setText(2,cart_title); + cut_cart_list->setSelected(item,true); + cut_cart_list->ensureItemVisible(item); + cut_ok_button->setEnabled(true); + + delete add_cart; +} + + +void RDCutDialog::okData() +{ + RDListViewItem *cart_item=(RDListViewItem *)cut_cart_list->selectedItem(); + QListViewItem *cut_item=cut_cut_list->selectedItem(); + if((cart_item==NULL)||(cut_item==NULL)) { + if(cut_allow_clear) { + *cut_cutname=""; + if(!local_filter) { + *cut_filter=cut_filter_edit->text(); + } + if(cut_group!=NULL) { + *cut_group=cut_group_box->currentText(); + } + if(cut_schedcode!=NULL) { + *cut_schedcode=cut_schedcode_box->currentText(); + } + SaveState(); + done(0); + } + return; + } + + *cut_cutname=cart_item->text(1)+QString("_")+cut_item->text(1); + if(!local_filter) { + *cut_filter=cut_filter_edit->text(); + } + if(cut_group!=NULL) { + *cut_group=cut_group_box->currentText(); + } + SaveState(); + done(0); +} + + +void RDCutDialog::cancelData() +{ + SaveState(); + done(1); +} + + +void RDCutDialog::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void RDCutDialog::RefreshCarts() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *l; + QString group=cut_group_box->currentText(); + + if(!cut_cutname->isEmpty()) { + } + cut_cart_list->clear(); + if(group==QString(tr("ALL"))) { + group=""; + } + QString schedcode=""; + if(cut_schedcode_box->currentText()!=tr("ALL")) { + schedcode=cut_schedcode_box->currentText(); + } + sql=QString().sprintf("select CART.NUMBER,CART.TITLE,CART.GROUP_NAME,\ + GROUPS.COLOR,CART.TYPE from CART left join GROUPS \ + on CART.GROUP_NAME=GROUPS.NAME \ + where (%s)&&((CART.TYPE=%u))", + (const char *)RDCartSearchText(cut_filter_edit->text(), + group,schedcode.utf8(), + false), + RDCart::Audio); + if(cut_exclude_tracks) { + sql+="&&(CART.OWNER is null)"; + } + if(cart_limit_box->isChecked()) { + sql+=QString().sprintf(" limit %d",RD_LIMITED_CART_SEARCH_QUANTITY); + } + q=new RDSqlQuery(sql); + int step=0; + int count=0; + cut_progress_dialog->setTotalSteps(q->size()/RDCUT_DIALOG_STEP_SIZE); + cut_progress_dialog->setProgress(0); + while(q->next()) { + l=new RDListViewItem(cut_cart_list); + switch((RDCart::Type)q->value(4).toUInt()) { + case RDCart::Audio: + l->setPixmap(0,*cut_playout_map); + break; + + case RDCart::All: + case RDCart::Macro: + break; + } + l->setText(1,QString().sprintf("%06u",q->value(0).toUInt())); // Number + + l->setText(2,q->value(1).toString()); // Title + l->setText(3,q->value(2).toString()); // Group + l->setTextColor(3,q->value(3).toString(),QFont::Bold); + if(count++>RDCUT_DIALOG_STEP_SIZE) { + cut_progress_dialog->setProgress(++step); + count=0; + qApp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput); + } + } + cut_progress_dialog->reset(); + delete q; + cut_search_button->setDisabled(true); +} + + + +void RDCutDialog::RefreshCuts() + +{ + QString sql; + RDSqlQuery *q; + QListViewItem *l; + QListViewItem *cart_item=cut_cart_list->selectedItem(); + + cut_cut_list->clear(); + if(cart_item==NULL) { + return; + } + sql=QString().sprintf("select DESCRIPTION,CUT_NAME from CUTS where \ + CART_NUMBER=%s",(const char *)cart_item->text(1)); + q=new RDSqlQuery(sql); + while(q->next()) { + l=new QListViewItem(cut_cut_list); + l->setText(0,q->value(0).toString()); // Description + l->setText(1,QString().sprintf("%03u", // Cut Number + q->value(1).toString().right(3).toUInt())); + } + delete q; +} + + +void RDCutDialog::SelectCut(QString cutname) +{ + QString cart=cutname.left(6); + QString cut=cutname.right(3); + QListViewItem *item=cut_cart_list->findItem(cart,1); + if(item!=NULL) { + cut_cart_list->setSelected(item,true); + cut_cart_list->ensureItemVisible(item); + } + RefreshCuts(); + item=cut_cut_list->findItem(cut,1); + if(item!=NULL) { + cut_cut_list->setSelected(item,true); + } +} + + +void RDCutDialog::BuildGroupList() +{ + QString sql; + RDSqlQuery *q; + + cut_group_box->clear(); + cut_group_box->insertItem(tr("ALL")); + if(cut_username.isEmpty()) { + sql="select NAME from GROUPS order by NAME desc"; + } + else { + sql=QString().sprintf("select GROUP_NAME from USER_PERMS\ + where USER_NAME=\"%s\" order by GROUP_NAME desc", + (const char *)cut_username); + } + q=new RDSqlQuery(sql); + while(q->next()) { + cut_group_box->insertItem(q->value(0).toString(),true); + } + delete q; + + // + // Preselect Group + // + if(cut_group!=NULL) { + for(int i=0;i<cut_group_box->count();i++) { + if(*cut_group==cut_group_box->text(i)) { + cut_group_box->setCurrentItem(i); + return; + } + } + } + + // + // Scheduler Codes + // + cut_schedcode_box->clear(); + cut_schedcode_box->insertItem(tr("ALL")); + sql="select CODE from SCHED_CODES"; + q=new RDSqlQuery(sql); + while(q->next()) { + cut_schedcode_box->insertItem(q->value(0).toString()); + } + delete q; + + // + // Preselect Scheduler Code + // + if(cut_schedcode!=NULL) { + for(int i=0;i<cut_schedcode_box->count();i++) { + if(*cut_schedcode==cut_schedcode_box->text(i)) { + cut_schedcode_box->setCurrentItem(i); + return; + } + } + } +} + + +void RDCutDialog::LoadState() +{ + if(getenv("HOME")==NULL) { + return; + } + RDProfile *p=new RDProfile(); + p->setSource(QString().sprintf("%s/.rdcartdialog",getenv("HOME"))); + delete p; +} + + +void RDCutDialog::SaveState() +{ + FILE *f=NULL; + + if(getenv("HOME")==NULL) { + return; + } + if((f=fopen(QString().sprintf("%s/.rdcartdialog",getenv("HOME")),"w"))== + NULL) { + return; + } + fprintf(f,"[RDCartDialog]\n"); + if(cart_limit_box->isChecked()) { + fprintf(f,"LimitSearch=Yes\n"); + } + else { + fprintf(f,"LimitSearch=No\n"); + } + fclose(f); +} diff --git a/lib/rdcut_dialog.h b/lib/rdcut_dialog.h new file mode 100644 index 00000000..d909cff9 --- /dev/null +++ b/lib/rdcut_dialog.h @@ -0,0 +1,106 @@ +// rdcut_dialog.h +// +// A widget to select a Rivendell Cut. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcut_dialog.h,v 1.14 2011/08/30 23:35:43 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCUT_DIALOG_H +#define RDCUT_DIALOG_H + +#include <qdialog.h> +#include <qlistview.h> +#include <qlineedit.h> +#include <qpushbutton.h> +#include <qcombobox.h> +#include <qprogressdialog.h> +#include <qcheckbox.h> + +#include <rdlistviewitem.h> +#include <rdstation.h> +#include <rdsystem.h> + +#define RDCUT_DIALOG_STEP_SIZE 1000 + +class RDCutDialog : public QDialog +{ + Q_OBJECT + public: + RDCutDialog(QString *cutname,RDStation *station,RDSystem *system, + QString *filter=0,QString *group=0,QString *schedcode=NULL, + QString username="",bool show_clear=false,bool allow_add=false, + bool exclude_tracks=false, + QWidget *parent=0,const char *name=0); + ~RDCutDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(); + + private slots: + void filterChangedData(const QString &); + void clearData(); + void groupActivatedData(const QString &); + void limitChangedData(int state); + void cartClickedData(QListViewItem *); + void selectionChangedData(); + void searchButtonData(); + void clearButtonData(); + void addButtonData(); + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + void RefreshCarts(); + void RefreshCuts(); + void SelectCut(QString cutname); + void BuildGroupList(); + void LoadState(); + void SaveState(); + RDListView *cut_cart_list; + QListView *cut_cut_list; + QLineEdit *cut_filter_edit; + QCheckBox *cart_limit_box; + QPushButton *cut_search_button; + QPushButton *cut_clear_button; + QPushButton *cut_ok_button; + QPushButton *cut_cancel_button; + QComboBox *cut_group_box; + QLabel *cut_schedcode_label; + QComboBox *cut_schedcode_box; + QString *cut_cutname; + QString *cut_filter; + QString *cut_group; + QString *cut_schedcode; + bool local_filter; + QPixmap *cut_playout_map; + QPixmap *cut_macro_map; + QString cut_username; + bool cut_allow_clear; + bool cut_exclude_tracks; + RDStation::FilterMode cut_filter_mode; + RDSystem *cut_system; + QProgressDialog *cut_progress_dialog; +}; + + +#endif // RDCUT_DIALOG_H diff --git a/lib/rdcut_path.cpp b/lib/rdcut_path.cpp new file mode 100644 index 00000000..6f5748b9 --- /dev/null +++ b/lib/rdcut_path.cpp @@ -0,0 +1,55 @@ +// rdcut_path.cpp +// +// Get the full Cut Path for a given Cut Name. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcut_path.cpp,v 1.9 2012/01/12 16:24:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qobject.h> + +#include <rdcut.h> +#include <rdcart.h> +#include <rdcut_path.h> + +QString RDCutPath(QString cutname) +{ + QString path; + + RDCut *cut=new RDCut(cutname); + if(!cut->exists()) { + delete cut; + return QString(QObject::tr("UNKNOWN CUT")); + } + RDCart *cart=new RDCart(cut->cartNumber()); + + if(!cart->exists()) { + delete cart; + delete cut; + return QString("UNKNOWN CUT"); + } + if((cart->title().isEmpty())&&(cut->description().isEmpty())) { + path=QString(); + } + else { + path=QString().sprintf("%s->%s",(const char *)cart->title(), + (const char *)cut->description()); + } + delete cart; + delete cut; + return path; +} diff --git a/lib/rdcut_path.h b/lib/rdcut_path.h new file mode 100644 index 00000000..d3f78615 --- /dev/null +++ b/lib/rdcut_path.h @@ -0,0 +1,32 @@ +// rdcut_path.h +// +// Get the full Cut Path for a given Cut Name. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdcut_path.h,v 1.6 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qstring.h> + +#ifndef RDCUT_PATH_H +#define RDCUT_PATH_H + +QString RDCutPath(QString cutname); + + +#endif + diff --git a/lib/rddatedecode.cpp b/lib/rddatedecode.cpp new file mode 100644 index 00000000..a2134b1e --- /dev/null +++ b/lib/rddatedecode.cpp @@ -0,0 +1,340 @@ +// rddatedecode.cpp +// +// Decode Rivendell Date Macros +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddatedecode.cpp,v 1.10.8.4 2012/05/10 23:40:16 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> + +#include <rddatedecode.h> + +QString RDDateDecode(QString str,QDate date) +{ + QString string; + int yearnum; + int dow; + bool upper_case=false; + bool initial_case=false; + QString field; + int offset=0; + + for(unsigned i=0;i<str.length();i++) { + field=""; + offset=0; + if(str.at(i)!='%') { + string+=str.at(i); + } + else { + i++; + offset++; + if(((const char *)str)[i]=='^') { + upper_case=true; + i++; + offset++; + } + else { + upper_case=false; + } + if(((const char *)str)[i]=='$') { + initial_case=true; + i++; + offset++; + } + else { + initial_case=false; + } + switch(((const char *)str)[i]) { + case 'a': // Abbreviated weekday name + field=QDate::shortDayName(date.dayOfWeek()).lower(); + break; + + case 'A': // Full weekday name + field=QDate::longDayName(date.dayOfWeek()).lower(); + break; + + case 'b': // Abbreviated month name + case 'h': + field=QDate::shortMonthName(date.month()).lower(); + break; + + case 'B': // Full month name + field=QDate::longMonthName(date.month()).lower(); + break; + + case 'C': // Century + field=QString().sprintf("%02d",date.year()/100); + break; + + case 'd': // Day (01 - 31) + field=QString().sprintf("%02d",date.day()); + break; + + case 'D': // Date (mm-dd-yy) + field=date.toString("dd-MM-yy"); + break; + + case 'e': // Day ( 1 - 31) + field=QString().sprintf("%2d",date.day()); + break; + + case 'E': // Day (1 - 31) + field=QString().sprintf("%d",date.day()); + break; + + case 'F': // Date (yyyy-mm-dd) + field=date.toString("yyyy-MM-dd"); + break; + + case 'g': // Two digit year number (as per ISO 8601) + date.weekNumber(&yearnum); + field=QString().sprintf("%02d",yearnum-2000); + break; + + case 'G': // Four digit year number (as per ISO 8601) + date.weekNumber(&yearnum); + field=QString().sprintf("%04d",yearnum); + break; + + case 'j': // Day of year + field=QString().sprintf("%03d",date.dayOfYear()); + break; + + case 'm': // Month (01 - 12) + field=QString().sprintf("%02d",date.month()); + break; + + case 'u': // Day of week (numeric, 1..7, 1=Monday) + field=QString().sprintf("%d",date.dayOfWeek()); + break; + + case 'V': // Week number (as per ISO 8601) + case 'W': + field=QString().sprintf("%d",date.weekNumber()); + break; + + case 'w': // Day of week (numeric, 0..6, 0=Sunday) + dow=date.dayOfWeek(); + if(dow==7) { + dow=0; + } + field=QString().sprintf("%d",dow); + break; + + case 'y': // Year (yy) + field=QString().sprintf("%02d",date.year()-2000); + break; + + case 'Y': // Year (yyyy) + field=QString().sprintf("%04d",date.year()); + break; + + case '%': // Literal '%' + field=QString("%"); + break; + + default: // No recognized wildcard, rollback! + i-=offset; + field=str.at(i); + break; + } + if(upper_case) { + field=field.upper(); + } + if(initial_case) { + field=field.left(1).upper()+field.right(field.length()-1); + } + string+=field; + } + } + return string; +} + + +QString RDDateTimeDecode(QString str,QDateTime datetime) +{ + QString string; + int yearnum; + int dow; + bool upper_case=false; + bool initial_case=false; + QString field; + int offset=0; + + for(unsigned i=0;i<str.length();i++) { + field=""; + offset=0; + if(str.at(i)!='%') { + string+=str.at(i); + } + else { + i++; + offset++; + if(((const char *)str)[i]=='^') { + upper_case=true; + i++; + offset++; + } + else { + upper_case=false; + } + if(((const char *)str)[i]=='$') { + initial_case=true; + i++; + offset++; + } + else { + initial_case=false; + } + switch(((const char *)str)[i]) { + case 'a': // Abbreviated weekday name + field=QDate::shortDayName(datetime.date().dayOfWeek()).lower(); + break; + + case 'A': // Full weekday name + field=QDate::longDayName(datetime.date().dayOfWeek()).lower(); + break; + + case 'b': // Abbreviated month name + case 'h': + field=QDate::shortMonthName(datetime.date().month()).lower(); + break; + + case 'B': // Full month name + field=QDate::longMonthName(datetime.date().month()).lower(); + break; + + case 'C': // Century + field=QString().sprintf("%02d",datetime.date().year()/100); + break; + + case 'd': // Day (01 - 31) + field=QString().sprintf("%02d",datetime.date().day()); + break; + + case 'D': // Date (mm-dd-yy) + field=datetime.date().toString("MM-dd-yy"); + break; + + case 'e': // Day ( 1 - 31) + field=QString().sprintf("%2d",datetime.date().day()); + break; + + case 'E': // Day (1 - 31) + field=QString().sprintf("%d",datetime.date().day()); + break; + + case 'F': // Date (yyyy-mm-dd) + field=datetime.date().toString("yyyy-MM-dd"); + break; + + case 'g': // Two digit year number (as per ISO 8601) + datetime.date().weekNumber(&yearnum); + field=QString().sprintf("%02d",yearnum-2000); + break; + + case 'G': // Four digit year number (as per ISO 8601) + datetime.date().weekNumber(&yearnum); + field=QString().sprintf("%04d",yearnum); + break; + + case 'H': // Hour, zero padded, 24 hour + field=QString().sprintf("%02d",datetime.time().hour()); + break; + + case 'I': // Hour, zero padded, 12 hour + field=QString().sprintf("%02d",datetime.time().hour()%12); + break; + + case 'i': // Hour, space padded, 12 hour + field=QString().sprintf("%2d",datetime.time().hour()%12); + break; + + case 'J': // Hour, unpadded, 12 hour + field=QString().sprintf("%d",datetime.time().hour()%12); + break; + + case 'j': // Day of year + field=QString().sprintf("%03d",datetime.date().dayOfYear()); + break; + + case 'k': // Hour, space padded, 24 hour + field=QString().sprintf("%2d",datetime.time().hour()); + break; + + case 'M': // Minute, zero padded + field=QString().sprintf("%02d",datetime.time().minute()); + break; + + case 'm': // Month (01 - 12) + field=QString().sprintf("%02d",datetime.date().month()); + break; + + case 'p': // AM/PM string + field=datetime.time().toString("ap"); + break; + + case 'S': // Second (SS) + field=QString().sprintf("%02d",datetime.time().second()); + break; + + case 'u': // Day of week (numeric, 1..7, 1=Monday) + field=QString().sprintf("%d",datetime.date().dayOfWeek()); + break; + + case 'V': // Week number (as per ISO 8601) + case 'W': + field=QString().sprintf("%d",datetime.date().weekNumber()); + break; + + case 'w': // Day of week (numeric, 0..6, 0=Sunday) + dow=datetime.date().dayOfWeek(); + if(dow==7) { + dow=0; + } + field=QString().sprintf("%d",dow); + break; + + case 'y': // Year (yy) + field=QString().sprintf("%02d",datetime.date().year()-2000); + break; + + case 'Y': // Year (yyyy) + field=QString().sprintf("%04d",datetime.date().year()); + break; + + case '%': // Literal '%' + field=QString("%"); + break; + + default: // No recognized wildcard, rollback! + i-=offset; + field=str.at(i); + break; + } + if(upper_case) { + field=field.upper(); + } + if(initial_case) { + field=field.left(1).upper()+field.right(field.length()-1); + } + string+=field; + } + } + return string; +} diff --git a/lib/rddatedecode.h b/lib/rddatedecode.h new file mode 100644 index 00000000..74e39abb --- /dev/null +++ b/lib/rddatedecode.h @@ -0,0 +1,34 @@ +// rddatedecode.h +// +// Decode Rivendell Date Macros +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddatedecode.h,v 1.7 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qdatetime.h> + + +#ifndef RDDATEDECODE_H +#define RDDATEDECODE_H + + +QString RDDateDecode(QString str,QDate date); +QString RDDateTimeDecode(QString str,QDateTime datetime); + + +#endif // RDDATEDECODE diff --git a/lib/rddatedialog.cpp b/lib/rddatedialog.cpp new file mode 100644 index 00000000..a7d2ec45 --- /dev/null +++ b/lib/rddatedialog.cpp @@ -0,0 +1,117 @@ +// rddatedialog.cpp +// +// A Qt-based application for testing General Purpose Outputs (GPO). +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddatedialog.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include <qapplication.h> +#include <qwidget.h> +#include <qpushbutton.h> +#include <qrect.h> +#include <qpoint.h> +#include <qpainter.h> +#include <qstring.h> +#include <qmessagebox.h> +#include <qlineedit.h> +#include <qlabel.h> +#include <qsignalmapper.h> + +#include <rdconf.h> +#include <rddatedialog.h> + +// +// Global Classes +// +RDDateDialog::RDDateDialog(int low_year,int high_year, + QWidget *parent,const char *name) + :QDialog(parent,name,true) +{ + QFont font; + + font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + setCaption(tr("Select Date")); + + // + // Datepicker + // + date_picker=new RDDatePicker(low_year,high_year,this,"date_picker"); + date_picker->setGeometry(10,10, + date_picker->sizeHint().width(), + date_picker->sizeHint().height()); + + // + // OK Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-130,sizeHint().height()-40,50,30); + button->setFont(font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-65,sizeHint().height()-40,55,30); + button->setFont(font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +RDDateDialog::~RDDateDialog() +{ +} + + +QSize RDDateDialog::sizeHint() const +{ + return QSize(date_picker->sizeHint().width()+20, + date_picker->sizeHint().height()+60); +} + + +QSizePolicy RDDateDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int RDDateDialog::exec(QDate *date) +{ + date_date=date; + date_picker->setDate(*date_date); + return QDialog::exec(); +} + + +void RDDateDialog::okData() +{ + *date_date=date_picker->date(); + done(0); +} + + +void RDDateDialog::cancelData() +{ + done(-1); +} diff --git a/lib/rddatedialog.h b/lib/rddatedialog.h new file mode 100644 index 00000000..329eeadd --- /dev/null +++ b/lib/rddatedialog.h @@ -0,0 +1,62 @@ +// rddatedialog.h +// +// A Dialog Box for using an RDatePicker widget. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddatedialog.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDDATEDIALOG_H +#define RDDATEDIALOG_H + +#include <qdialog.h> +#include <qsize.h> +#include <qsizepolicy.h> +#include <qpushbutton.h> +#include <qcolor.h> +#include <qstring.h> +#include <qdatetime.h> +#include <qlabel.h> + +#include <rddatepicker.h> + + +class RDDateDialog : public QDialog +{ + Q_OBJECT + public: + RDDateDialog(int low_year,int high_year,QWidget *parent=0, + const char *name=0); + ~RDDateDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(QDate *date); + + private slots: + void okData(); + void cancelData(); + + private: + RDDatePicker *date_picker; + QDate *date_date; +}; + + +#endif // RDDATEDIALOG_H diff --git a/lib/rddatepicker.cpp b/lib/rddatepicker.cpp new file mode 100644 index 00000000..4166a52f --- /dev/null +++ b/lib/rddatepicker.cpp @@ -0,0 +1,351 @@ +// rddatepicker.cpp +// +// A Qt-based application for testing General Purpose Outputs (GPO). +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddatepicker.cpp,v 1.3.8.1 2013/01/22 18:33:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include <qwidget.h> +#include <qstring.h> +#include <qlabel.h> +#include <qpalette.h> + +#include <rddatepicker.h> + +// +// Global Classes +// +RDDatePicker::RDDatePicker(int low_year,int high_year, + QWidget *parent,const char *name) + :QWidget(parent,name) +{ + pick_low_year=low_year; + pick_high_year=high_year; + + // + // Generate Fonts + // + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + QFont header_font=QFont("Helvetica",12,QFont::Bold); + header_font.setPixelSize(12); + + // + // Month + // + pick_month_box=new QComboBox(this,"pick_month_box"); + pick_month_box->setGeometry(0,0,120,26); + for(int i=1;i<13;i++) { + pick_month_box->insertItem(QDate::longMonthName(i)); + } + connect(pick_month_box,SIGNAL(activated(int)), + this,SLOT(monthActivatedData(int))); + + // + // Year + // + if((high_year-low_year)<=10) { + pick_year_box=new QComboBox(this,"pick_year_box"); + pick_year_box->setGeometry(130,0,90,26); + for(int i=low_year;i<(high_year+1);i++) { + pick_year_box->insertItem(QString().sprintf("%04d",i)); + } + connect(pick_year_box,SIGNAL(activated(int)), + this,SLOT(yearActivatedData(int))); + pick_year_spin=NULL; + } + else { + pick_year_spin=new QSpinBox(this,"pick_year_spin"); + pick_year_spin->setGeometry(160,0,60,26); + pick_year_spin->setRange(low_year,high_year); + pick_year_box=NULL; + connect(pick_year_spin,SIGNAL(valueChanged(int)), + this,SLOT(yearChangedData(int))); + } + + // + // Date Labels + // + QPalette weekend_palette=palette(); + weekend_palette.setColor(QPalette::Active,QColorGroup::Background, + palette().color(QPalette::Active, + QColorGroup::Mid)); + weekend_palette.setColor(QPalette::Inactive,QColorGroup::Background, + palette().color(QPalette::Active, + QColorGroup::Mid)); + + QLabel *label=new QLabel(tr("Mo"),this,"monday_label"); + label->setGeometry(RDDATEPICKER_X_ORIGIN,30,30,30); + label->setFont(header_font); + label->setAlignment(AlignCenter); + + label=new QLabel(tr("Tu"),this,"tuesday_label"); + label->setGeometry(RDDATEPICKER_X_ORIGIN+RDDATEPICKER_X_INTERVAL, + RDDATEPICKER_Y_ORIGIN,30,30); + label->setFont(header_font); + label->setAlignment(AlignCenter); + + label=new QLabel(tr("We"),this,"wednesday_label"); + label->setGeometry(RDDATEPICKER_X_ORIGIN+RDDATEPICKER_X_INTERVAL*2, + RDDATEPICKER_Y_ORIGIN,30,30); + label->setFont(header_font); + label->setAlignment(AlignCenter); + + label=new QLabel(tr("Th"),this,"thursday_label"); + label->setGeometry(RDDATEPICKER_X_ORIGIN+RDDATEPICKER_X_INTERVAL*3, + RDDATEPICKER_Y_ORIGIN,30,30); + label->setFont(header_font); + label->setAlignment(AlignCenter); + + label=new QLabel(tr("Fr"),this,"friday_label"); + label->setGeometry(RDDATEPICKER_X_ORIGIN+RDDATEPICKER_X_INTERVAL*4, + RDDATEPICKER_Y_ORIGIN,30,30); + label->setFont(header_font); + label->setAlignment(AlignCenter); + + label=new QLabel(tr("Sa"),this,"saturday_label"); + label->setGeometry(RDDATEPICKER_X_ORIGIN+RDDATEPICKER_X_INTERVAL*5, + RDDATEPICKER_Y_ORIGIN,30,30); + label->setFont(header_font); + label->setAlignment(AlignCenter); + label->setPalette(weekend_palette); + + label=new QLabel(tr("Su"),this,"sunday_label"); + label->setGeometry(RDDATEPICKER_X_ORIGIN+RDDATEPICKER_X_INTERVAL*6, + RDDATEPICKER_Y_ORIGIN,30,30); + label->setFont(header_font); + label->setAlignment(AlignCenter); + label->setPalette(weekend_palette); + + + for(int i=0;i<6;i++) { + for(int j=0;j<7;j++) { + pick_date_label[i][j]=new QLabel(this,"date_label"); + pick_date_label[i][j]-> + setGeometry(RDDATEPICKER_X_ORIGIN+RDDATEPICKER_X_INTERVAL*j, + RDDATEPICKER_Y_ORIGIN+20+RDDATEPICKER_Y_INTERVAL*i,30,30); + pick_date_label[i][j]->setAlignment(Qt::AlignTop|Qt::AlignHCenter); + } + } + PrintDays(); +} + + +RDDatePicker::~RDDatePicker() +{ +} + + +QSize RDDatePicker::sizeHint() const +{ + return QSize(220,175); +} + + +QSizePolicy RDDatePicker::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +QDate RDDatePicker::date() const +{ + return pick_date; +} + + +bool RDDatePicker::setDate(QDate date) +{ + if(!date.isValid()) { + date=QDate::currentDate(); + } + if((date.year()<pick_low_year)||(date.year()>pick_high_year)) { + return false; + } + pick_date=date; + pick_month_box->setCurrentItem(date.month()-1); + if(pick_year_box!=NULL) { + pick_year_box->setCurrentItem(date.year()-pick_low_year); + } + else { + pick_year_spin->setValue(date.year()); + } + PrintDays(); + return true; +} + + +void RDDatePicker::monthActivatedData(int id) +{ + QDate date=QDate(pick_date.year(),id+1,1); + if(pick_date.day()<=date.daysInMonth()) { + pick_date=QDate(pick_date.year(),id+1,pick_date.day()); + } + else { + pick_date=QDate(pick_date.year(),id+1,date.daysInMonth()); + } + PrintDays(); +} + + +void RDDatePicker::yearActivatedData(int id) +{ + QDate date=QDate(pick_low_year+pick_year_box->currentItem(), + pick_date.month(),1); + if(pick_date.day()<=date.daysInMonth()) { + pick_date=QDate(pick_low_year+pick_year_box->currentItem(), + pick_date.month(),pick_date.day()); + } + else { + pick_date=QDate(pick_low_year+pick_year_box->currentItem(), + pick_date.month(),date.daysInMonth()); + } + PrintDays(); +} + + +void RDDatePicker::yearChangedData(int year) +{ + QDate date=QDate(pick_year_spin->value(),pick_date.month(),1); + if(pick_date.day()<=date.daysInMonth()) { + pick_date=QDate(pick_year_spin->value(), + pick_date.month(),pick_date.day()); + } + else { + pick_date=QDate(pick_year_spin->value(), + pick_date.month(),date.daysInMonth()); + } + PrintDays(); +} + + +void RDDatePicker::mousePressEvent(QMouseEvent *e) +{ + if((e->pos().x()<RDDATEPICKER_X_ORIGIN)|| + (e->pos().x()>(RDDATEPICKER_X_ORIGIN+RDDATEPICKER_X_INTERVAL*7))|| + (e->pos().y()<RDDATEPICKER_Y_ORIGIN)|| + (e->pos().y()>(RDDATEPICKER_Y_ORIGIN+RDDATEPICKER_Y_INTERVAL*7))) { + QWidget::mousePressEvent(e); + return; + } + int dow=(e->pos().x()-RDDATEPICKER_X_ORIGIN)/RDDATEPICKER_X_INTERVAL; + int week=(e->pos().y()-RDDATEPICKER_Y_ORIGIN)/RDDATEPICKER_Y_INTERVAL-1; + if((dow<0)||(dow>6)||(week<0)||(week>6)) { + return; + } + if(pick_date_label[week][dow]->text().isEmpty()) { + return; + } + pick_date=QDate(pick_date.year(),pick_date.month(), + pick_date_label[week][dow]->text().toInt()); + PrintDays(); +} + + +void RDDatePicker::PrintDays() +{ + QDate top_date; + + // + // Clear Days + // + QPalette weekend_palette=palette(); + weekend_palette.setColor(QPalette::Active,QColorGroup::Background, + palette().color(QPalette::Active, + QColorGroup::Mid)); + weekend_palette.setColor(QPalette::Inactive,QColorGroup::Background, + palette().color(QPalette::Active, + QColorGroup::Mid)); + for(int i=0;i<6;i++) { + for(int j=0;j<5;j++) { + pick_date_label[i][j]->clear(); + pick_date_label[i][j]->setPalette(palette()); + } + } + for(int i=0;i<6;i++) { + for(int j=5;j<7;j++) { + pick_date_label[i][j]->clear(); + pick_date_label[i][j]->setPalette(weekend_palette); + } + } + + // + // Get Top of Month + // + if(pick_year_box!=NULL) { + top_date=QDate(pick_low_year+pick_year_box->currentItem(), + pick_month_box->currentItem()+1,1); + } + else { + top_date=QDate(pick_year_spin->value(),pick_month_box->currentItem()+1,1); + } + + // + // Print Days + // + int dow_offset=top_date.dayOfWeek()-1; + for(int i=1;i<(top_date.daysInMonth()+1);i++) { + PrintDay(i,dow_offset); + if(pick_date.day()==i) { + SelectDay(i,dow_offset,true); + } + } +} + + +void RDDatePicker::PrintDay(int day,int dow_offset) +{ + int slot=day+dow_offset-1; + int week=slot/7; + int dow=slot-7*week; + pick_date_label[week][dow]->setText(QString().sprintf("%d",day)); +} + + +void RDDatePicker::SelectDay(int day,int dow_offset,bool state) +{ + int slot=day+dow_offset-1; + int week=slot/7; + int dow=slot-7*week; + QPalette pal=palette(); + if(state) { + pal.setColor(QPalette::Active,QColorGroup::Foreground, + palette(). + color(QPalette::Active,QColorGroup::HighlightedText)); + pal.setColor(QPalette::Active,QColorGroup::Background, + palette().color(QPalette::Active,QColorGroup::Highlight)); + pal.setColor(QPalette::Inactive,QColorGroup::Foreground, + palette(). + color(QPalette::Active,QColorGroup::HighlightedText)); + pal.setColor(QPalette::Inactive,QColorGroup::Background, + palette().color(QPalette::Active,QColorGroup::Highlight)); + } + else { + pal.setColor(QPalette::Active,QColorGroup::Foreground, + palette().color(QPalette::Active,QColorGroup::Text)); + pal.setColor(QPalette::Active,QColorGroup::Background, + palette().color(QPalette::Active,QColorGroup::Background)); + pal.setColor(QPalette::Inactive,QColorGroup::Foreground, + palette().color(QPalette::Active,QColorGroup::Text)); + pal.setColor(QPalette::Inactive,QColorGroup::Background, + palette().color(QPalette::Active,QColorGroup::Background)); + } + pick_date_label[week][dow]->setPalette(pal); +} + diff --git a/lib/rddatepicker.h b/lib/rddatepicker.h new file mode 100644 index 00000000..49fd7d08 --- /dev/null +++ b/lib/rddatepicker.h @@ -0,0 +1,80 @@ +// rddatepicker.h +// +// A Calendar Widget. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddatepicker.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDDATEPICKER_H +#define RDDATEPICKER_H + +#include <qwidget.h> +#include <qsize.h> +#include <qsizepolicy.h> +#include <qpushbutton.h> +#include <qcolor.h> +#include <qstring.h> +#include <qdatetime.h> +#include <qlabel.h> +#include <qcombobox.h> +#include <qspinbox.h> + +// +// Display Settings +// +#define RDDATEPICKER_X_ORIGIN 20 +#define RDDATEPICKER_X_INTERVAL 25 +#define RDDATEPICKER_Y_ORIGIN 30 +#define RDDATEPICKER_Y_INTERVAL 20 + +class RDDatePicker : public QWidget +{ + Q_OBJECT + public: + RDDatePicker(int low_year,int high_year,QWidget *parent=0, + const char *name=0); + ~RDDatePicker(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + QDate date() const; + bool setDate(QDate date); + + private slots: + void monthActivatedData(int id); + void yearActivatedData(int id); + void yearChangedData(int year); + + protected: + void mousePressEvent(QMouseEvent *e); + + private: + void PrintDays(); + void PrintDay(int day,int dow_offset); + void SelectDay(int day,int dow_offset,bool state); + QComboBox *pick_month_box; + QComboBox *pick_year_box; + QSpinBox *pick_year_spin; + QLabel *pick_date_label[6][7]; + QDate pick_date; + int pick_low_year; + int pick_high_year; +}; + + +#endif // RDDATEPICKER_H diff --git a/lib/rddb.cpp b/lib/rddb.cpp new file mode 100644 index 00000000..5fed964c --- /dev/null +++ b/lib/rddb.cpp @@ -0,0 +1,149 @@ +// rddb.cpp +// +// Database driver with automatic reconnect +// +// (C) Copyright 2007 Dan Mills <dmills@exponent.myzen.co.uk> +// +// $Id: rddb.cpp,v 1.13.4.2.2.2 2014/03/21 15:41:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qobject.h> +#include <qstring.h> +#include <qtextcodec.h> +#include <qtranslator.h> +#include <qserversocket.h> +#include <qsqldatabase.h> +#include <qsqlerror.h> +#include <assert.h> + +#include "rddb.h" +#include "rddbheartbeat.h" + +static QSqlDatabase *db = NULL; +static RDSqlDatabaseStatus * dbStatus = NULL; + +QSqlDatabase *RDInitDb (unsigned *schema,QString *error) +{ + static bool firsttime = true; + + *schema=0; + RDConfig *cf = RDConfiguration(); + cf->load(); + assert (cf); + if (!db){ + db=QSqlDatabase::addDatabase(cf->mysqlDriver()); + if(!db) { + if (error){ + (*error) += QString(QObject::tr("Couldn't initialize QSql driver!")); + } + return NULL; + } + db->setDatabaseName(cf->mysqlDbname()); + db->setUserName(cf->mysqlUsername()); + db->setPassword(cf->mysqlPassword()); + db->setHostName(cf->mysqlHostname()); + if(!db->open()) { + if (error){ + (*error) += QString(QObject::tr("Couldn't open mySQL connection!")); + } + db->removeDatabase(cf->mysqlDbname()); + db->close(); + return NULL; + } + } + if (firsttime){ + new RDDbHeartbeat(cf->mysqlHeartbeatInterval()); + firsttime = false; + } + // QSqlQuery *q=new QSqlQuery("set character_set_results='utf8'"); + // delete q; + + QSqlQuery *q=new QSqlQuery("select DB from VERSION"); + if(q->first()) { + *schema=q->value(0).toUInt(); + } + delete q; + + return db; +} + +RDSqlQuery::RDSqlQuery (const QString &query, QSqlDatabase *dbase): + QSqlQuery (query,dbase) +{ + //printf("lastQuery: %s\n",(const char *)lastQuery()); + + // With any luck, by the time we get here, we have already done the biz... + unsigned schema; + if (!isActive()){ //DB Offline? + QString err=QObject::tr("invalid SQL or failed DB connection")+ + +"["+lastError().text()+"]: "+query; + + fprintf(stderr,"%s\n",(const char *)err); +#ifndef WIN32 + syslog(LOG_ERR,(const char *)err); +#endif // WIN32 + QSqlDatabase *ldb = QSqlDatabase::database(); + // Something went wrong with the DB, trying a reconnect + ldb->removeDatabase(RDConfiguration()->mysqlDbname()); + ldb->close(); + db = NULL; + RDInitDb (&schema); + QSqlQuery::prepare (query); + QSqlQuery::exec (); + if (RDDbStatus()){ + if (isActive()){ + RDDbStatus()->sendRecon(); + } else { + RDDbStatus()->sendDiscon(query); + } + } + } else { + RDDbStatus()->sendRecon(); + } +} +void RDSqlDatabaseStatus::sendRecon() +{ + if (discon){ + discon = false; + emit reconnected(); + fprintf (stderr,"Database connection restored.\n"); + emit logText(RDConfig::LogErr,QString(tr("Database connection restored."))); + } +} + +void RDSqlDatabaseStatus::sendDiscon(QString query) +{ + if (!discon){ + emit connectionFailed(); + fprintf (stderr,"Database connection failed: %s\n",(const char *)query); + emit logText(RDConfig::LogErr, + QString(tr("Database connection failed : ")) + query); + discon = true; + } +} + +RDSqlDatabaseStatus::RDSqlDatabaseStatus() +{ + discon = false; +} + +RDSqlDatabaseStatus * RDDbStatus() +{ + if (!dbStatus){ + dbStatus = new RDSqlDatabaseStatus; + } + return dbStatus; +} diff --git a/lib/rddb.h b/lib/rddb.h new file mode 100644 index 00000000..240de1ce --- /dev/null +++ b/lib/rddb.h @@ -0,0 +1,64 @@ +// rddb.h +// +// Database driver with automatic reconnect +// +// (C) Copyright 2007 Dan Mills <dmills@exponent.myzen.co.uk> +// +// $Id: rddb.h,v 1.9 2011/06/21 22:20:43 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDDB_INC +#define RDDB_INC + +#include <qobject.h> +#include <qsqldatabase.h> +#include <qstring.h> + +#include <rdconfig.h> + + +class RDSqlDatabaseStatus : public QObject +{ + Q_OBJECT + signals: + void logText(RDConfig::LogPriority prio,const QString &msg); + void reconnected(); + void connectionFailed (); + private: + RDSqlDatabaseStatus (); + bool discon; + friend RDSqlDatabaseStatus * RDDbStatus(); + public: + void sendRecon(); + void sendDiscon(QString query); +}; + + +class RDSqlQuery : public QSqlQuery +{ + public: + RDSqlQuery ( const QString & query = QString::null, QSqlDatabase * db = 0 ); +}; + +// Setup the default database, returns true on success. +// if error is non NULL, an error string will be appended to it +// if there is a problem. +QSqlDatabase * RDInitDb(unsigned *schema,QString *error=NULL); + +// Return a handle to the database status object. +RDSqlDatabaseStatus * RDDbStatus(); + +#endif diff --git a/lib/rddbheartbeat.cpp b/lib/rddbheartbeat.cpp new file mode 100644 index 00000000..0ad1696f --- /dev/null +++ b/lib/rddbheartbeat.cpp @@ -0,0 +1,41 @@ +// rddbheartbeat.cpp +// +// Abstract a Rivendell Cart +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddbheartbeat.cpp,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rddbheartbeat.h> +#include <rddb.h> + +RDDbHeartbeat::RDDbHeartbeat(int interval,QObject *parent,const char *name) + : QObject(parent,name) +{ + QTimer *timer=new QTimer(this); + connect(timer,SIGNAL(timeout()),this,SLOT(intervalTimeoutData())); + intervalTimeoutData(); + timer->start(interval*1000); +} + + +void RDDbHeartbeat::intervalTimeoutData() +{ + RDSqlQuery *q=new RDSqlQuery("select DB from VERSION"); + q->first(); + delete q; +} diff --git a/lib/rddbheartbeat.h b/lib/rddbheartbeat.h new file mode 100644 index 00000000..61c064b3 --- /dev/null +++ b/lib/rddbheartbeat.h @@ -0,0 +1,42 @@ +// rddbheartbeat.h +// +// Abstract a Rivendell Cart +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddbheartbeat.h,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qobject.h> +#include <qsqldatabase.h> +#include <qtimer.h> + + +#ifndef RDDBHEARTBEAT_H +#define RDDBHEARTBEAT_H + +class RDDbHeartbeat : public QObject +{ + Q_OBJECT; + public: + RDDbHeartbeat(int interval,QObject *parent=0,const char *name=0); + + private slots: + void intervalTimeoutData(); +}; + + +#endif // RDDBHEARTBEAT_H diff --git a/lib/rddebug.cpp b/lib/rddebug.cpp new file mode 100644 index 00000000..315a40df --- /dev/null +++ b/lib/rddebug.cpp @@ -0,0 +1,32 @@ +// rddebug.cpp +// +// Debugging Utility Functions for Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddebug.cpp,v 1.8 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> + +#include <rddebug.h> + + +void RDTimePoint(QString label) +{ + printf("RDTimePoint - %s: %s\n",(const char *)label, + (const char *)QTime::currentTime().toString("hh:mm:ss.zzz")); +} diff --git a/lib/rddebug.h b/lib/rddebug.h new file mode 100644 index 00000000..b02dd603 --- /dev/null +++ b/lib/rddebug.h @@ -0,0 +1,33 @@ +// rddebug.h +// +// Debugging Utility Functions for Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddebug.h,v 1.7 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qdatetime.h> + + +#ifndef RDDEBUG_H +#define RDDEBUG_H + + +void RDTimePoint(QString label); + + +#endif // RDDEBUG_H diff --git a/lib/rddeck.cpp b/lib/rddeck.cpp new file mode 100644 index 00000000..83d96d72 --- /dev/null +++ b/lib/rddeck.cpp @@ -0,0 +1,363 @@ +// rddeck.cpp +// +// Abstract a Rivendell Deck. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddeck.cpp,v 1.17 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rddb.h> +#include <rdconf.h> +#include <rddeck.h> +#include <rdescape_string.h> + +// +// Global Classes +// +RDDeck::RDDeck(QString station,unsigned channel,bool create) +{ + RDSqlQuery *q; + QString sql; + + deck_station=station; + deck_channel=channel; + + if(create) { + sql=QString().sprintf("select ID from DECKS where \ +(STATION_NAME=\"%s\")&&(CHANNEL=%d)",(const char *)deck_station,deck_channel); + q=new RDSqlQuery(sql); + if(q->size()!=1) { + delete q; + sql=QString(). + sprintf("INSERT INTO DECKS SET STATION_NAME=\"%s\",CHANNEL=%d", + (const char *)deck_station,deck_channel); + q=new RDSqlQuery(sql); + delete q; + } + else { + delete q; + } + } +} + + +bool RDDeck::isActive() const +{ + QString sql; + RDSqlQuery *q; + bool ret=false; + + sql=QString().sprintf("select ID from DECKS where (STATION_NAME=\"%s\")&&\ + (CHANNEL=%u)&&(CARD_NUMBER>=0)&&(PORT_NUMBER>=0)", + (const char *)RDEscapeString(deck_station), + deck_channel); + q=new RDSqlQuery(sql); + ret=q->first(); + delete q; + + return ret; +} + + +QString RDDeck::station() const +{ + return deck_station; +} + + +int RDDeck::channel() const +{ + return deck_channel; +} + + +int RDDeck::cardNumber() const +{ + return GetIntValue("CARD_NUMBER"); +} + + +void RDDeck::setCardNumber(int card) const +{ + SetRow("CARD_NUMBER",card); +} + + +int RDDeck::streamNumber() const +{ + return GetIntValue("STREAM_NUMBER"); +} + + +void RDDeck::setStreamNumber(int stream) const +{ + SetRow("STREAM_NUMBER",stream); +} + + +int RDDeck::portNumber() const +{ + return GetIntValue("PORT_NUMBER"); +} + + +void RDDeck::setPortNumber(int port) const +{ + SetRow("PORT_NUMBER",port); +} + + +int RDDeck::monitorPortNumber() const +{ + return GetIntValue("MON_PORT_NUMBER"); +} + + +void RDDeck::setMonitorPortNumber(int port) const +{ + SetRow("MON_PORT_NUMBER",port); +} + + +bool RDDeck::defaultMonitorOn() const +{ + return RDBool(GetStringValue("DEFAULT_MONITOR_ON")); +} + + +void RDDeck::setDefaultMonitorOn(bool state) const +{ + SetRow("DEFAULT_MONITOR_ON",state); +} + + +RDSettings::Format RDDeck::defaultFormat() const +{ + return (RDSettings::Format)GetIntValue("DEFAULT_FORMAT"); +} + + +void RDDeck::setDefaultFormat(RDSettings::Format format) const +{ + SetRow("DEFAULT_FORMAT",(int)format); +} + + +int RDDeck::defaultChannels() const +{ + return GetIntValue("DEFAULT_CHANNELS"); +} + + +void RDDeck::setDefaultChannels(int chan) const +{ + SetRow("DEFAULT_CHANNELS",chan); +} + + +int RDDeck::defaultBitrate() const +{ + return GetIntValue("DEFAULT_BITRATE"); +} + + +void RDDeck::setDefaultBitrate(int rate) const +{ + SetRow("DEFAULT_BITRATE",rate); +} + + +int RDDeck::defaultThreshold() const +{ + return GetIntValue("DEFAULT_THRESHOLD"); +} + + +void RDDeck::setDefaultThreshold(int level) const +{ + SetRow("DEFAULT_THRESHOLD",level); +} + + +QString RDDeck::switchStation() const +{ + return GetStringValue("SWITCH_STATION"); +} + + +void RDDeck::setSwitchStation(QString str) const +{ + SetRow("SWITCH_STATION",str); +} + + +int RDDeck::switchMatrix() const +{ + return GetIntValue("SWITCH_MATRIX"); +} + + +QString RDDeck::switchMatrixName() const +{ + QString matrix_name; + + RDSqlQuery *q=new RDSqlQuery(QString().sprintf("select NAME from MATRICES \ + where (STATION_NAME=\"%s\")&&(MATRIX=%d)", + (const char *)switchStation(), + switchMatrix())); + if(q->first()) { + matrix_name=q->value(0).toString(); + } + delete q; + return matrix_name; +} + + +void RDDeck::setSwitchMatrix(int matrix) const +{ + SetRow("SWITCH_MATRIX",matrix); +} + + +int RDDeck::switchOutput() const +{ + return GetIntValue("SWITCH_OUTPUT"); +} + + +QString RDDeck::switchOutputName() const +{ + QString output_name; + + RDSqlQuery *q=new RDSqlQuery(QString().sprintf("select NAME from OUTPUTS \ + where (STATION_NAME=\"%s\")&&(MATRIX=%d)&&\ + (NUMBER=%d)", + (const char *)switchStation(), + switchMatrix(), + switchOutput())); + if(q->first()) { + output_name=q->value(0).toString(); + } + delete q; + return output_name; +} + + +void RDDeck::setSwitchOutput(int output) const +{ + SetRow("SWITCH_OUTPUT",output); +} + + +int RDDeck::switchDelay() const +{ + return GetIntValue("SWITCH_DELAY"); +} + + +void RDDeck::setSwitchDelay(int delay) const +{ + SetRow("SWITCH_DELAY",delay); +} + + +int RDDeck::GetIntValue(const QString &field) const +{ + QString sql; + RDSqlQuery *q; + int accum; + + sql=QString().sprintf("select %s from DECKS where \ +(STATION_NAME=\"%s\")&&(CHANNEL=%d)",(const char *)field, + (const char *)deck_station,deck_channel); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toInt(); + delete q; + return accum; + } + delete q; + return 0; +} + + +QString RDDeck::GetStringValue(const QString &field) const +{ + QString sql; + RDSqlQuery *q; + QString accum; + + sql=QString().sprintf("select %s from DECKS where \ +(STATION_NAME=\"%s\")&&(CHANNEL=%d)",(const char *)field, + (const char *)deck_station,deck_channel); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toString(); + delete q; + return accum; + } + delete q; + return 0; +} + + +void RDDeck::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE DECKS SET %s=%d \ +WHERE (STATION_NAME=\"%s\")&&(CHANNEL=%d)", + (const char *)param, + value, + (const char *)deck_station, + deck_channel); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDDeck::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE DECKS SET %s=\"%s\" \ +WHERE (STATION_NAME=\"%s\")&&(CHANNEL=%d)", + (const char *)param, + (const char *)RDEscapeString(value), + (const char *)deck_station, + deck_channel); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDDeck::SetRow(const QString ¶m,bool value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE DECKS SET %s=\"%s\" \ +WHERE (STATION_NAME=\"%s\")&&(CHANNEL=%d)", + (const char *)param, + (const char *)RDYesNo(value), + (const char *)deck_station, + deck_channel); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rddeck.h b/lib/rddeck.h new file mode 100644 index 00000000..19a5f27e --- /dev/null +++ b/lib/rddeck.h @@ -0,0 +1,79 @@ +// rddeck.h +// +// Abstract a Rivendell Record/Play Deck +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddeck.h,v 1.20 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> +#include <qtimer.h> + +#include <rdsettings.h> + +#ifndef RDDECK_H +#define RDDECK_H + +class RDDeck +{ + public: + enum Status {Offline=0,Idle=1,Ready=2,Recording=3,Waiting=4}; + RDDeck(QString station,unsigned channel,bool create=false); + bool isActive() const; + QString station() const; + int channel() const; + int cardNumber() const;; + void setCardNumber(int card) const; + int streamNumber() const; + void setStreamNumber(int stream) const; + int portNumber() const; + void setPortNumber(int port) const; + int monitorPortNumber() const; + void setMonitorPortNumber(int port) const; + bool defaultMonitorOn() const; + void setDefaultMonitorOn(bool state) const; + RDSettings::Format defaultFormat() const; + void setDefaultFormat(RDSettings::Format format) const; + int defaultChannels() const; + void setDefaultChannels(int chan) const; + int defaultBitrate() const; + void setDefaultBitrate(int rate) const; + int defaultThreshold() const; + void setDefaultThreshold(int level) const; + QString switchStation() const; + void setSwitchStation(QString str) const; + int switchMatrix() const; + QString switchMatrixName() const; + void setSwitchMatrix(int matrix) const; + int switchOutput() const; + QString switchOutputName() const; + void setSwitchOutput(int output) const; + int switchDelay() const; + void setSwitchDelay(int delay) const; + + private: + int GetIntValue(const QString &field) const; + QString GetStringValue(const QString &field) const; + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,const QString &value) const; + void SetRow(const QString ¶m,bool value) const; + int deck_channel; + QString deck_station; +}; + + +#endif diff --git a/lib/rddelete.cpp b/lib/rddelete.cpp new file mode 100644 index 00000000..8821540b --- /dev/null +++ b/lib/rddelete.cpp @@ -0,0 +1,228 @@ +// rddelete.cpp +// +// Delete a file from the audio store via the Rivendell Web Service +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddelete.cpp,v 1.3 2011/12/23 23:07:00 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#define _XOPEN_SOURCE +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <syslog.h> +#include <pwd.h> + +#include <curl/curl.h> + +#include <qapplication.h> +#include <qfileinfo.h> + +#include <rd.h> +#include <rdsystemuser.h> +#include <rddelete.h> + +// +// CURL Callbackd +// +size_t DeleteWriteCallback(void *ptr,size_t size,size_t nmemb,void *userdata) +{ + QString *xml=(QString *)userdata; + for(unsigned i=0;i<(size*nmemb);i++) { + *xml+=((const char *)ptr)[i]; + } + return size*nmemb; +} + + +int DeleteErrorCallback(CURL *curl,curl_infotype type,char *msg,size_t size, + void *clientp) +{ + char str[1000]; + + if(type!=CURLINFO_TEXT) { + return 0; + } + if(size>999) { + size=999; + } + memset(&str,0,size+1); + memcpy(str,msg,size); + syslog(LOG_DEBUG,"CURL MSG: %s",str); + return 0; +} + + +RDDelete::RDDelete(QObject *parent,const char *name) + : QObject(parent,name) +{ +} + + +void RDDelete::setTargetUrl(const QString &url) +{ + conv_target_url=url; +} + + +RDDelete::ErrorCode RDDelete::runDelete(const QString &username, + const QString &password, + bool log_debug) +{ + CURL *curl=NULL; + struct curl_slist *cmds=NULL; + CURLcode err; + RDDelete::ErrorCode ret=RDDelete::ErrorOk; + QString currentdir; + char urlstr[1024]; + char userpwd[256]; + QString xml=""; + + if((curl=curl_easy_init())==NULL) { + syslog(LOG_ERR,"unable to initialize curl library\n"); + return RDDelete::ErrorInternal; + } + strncpy(urlstr,(const char *)(conv_target_url.protocol()+"://"+ + conv_target_url.host()+"/"),1024); + curl_easy_setopt(curl,CURLOPT_URL,urlstr); + strncpy(userpwd,(const char *)QString(). + sprintf("%s:%s",(const char *)username, + (const char *)password),256); + curl_easy_setopt(curl,CURLOPT_USERPWD,userpwd); + curl_easy_setopt(curl,CURLOPT_HTTPAUTH,CURLAUTH_ANY); + printf("HERE\n"); + curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,DeleteWriteCallback); + curl_easy_setopt(curl,CURLOPT_WRITEDATA,&xml); + if(log_debug) { + curl_easy_setopt(curl,CURLOPT_VERBOSE,1); + curl_easy_setopt(curl,CURLOPT_DEBUGFUNCTION,DeleteErrorCallback); + } + currentdir=""; + if(!conv_target_url.dirPath().right(conv_target_url.dirPath().length()-1). + isEmpty()) { + currentdir=conv_target_url.dirPath(). + right(conv_target_url.dirPath().length()-1)+"/"; + } + if(!currentdir.isEmpty()) { + cmds=curl_slist_append(cmds,QString().sprintf("cwd %s", + (const char *)currentdir)); + } + cmds=curl_slist_append(cmds, QString().sprintf("dele %s", + (const char *)conv_target_url.fileName())); + curl_easy_setopt(curl,CURLOPT_QUOTE,cmds); + switch((err=curl_easy_perform(curl))) { + case CURLE_OK: + case 21: // CURLE_QUOTE_ERROR -- In case the file is already gone + ret=RDDelete::ErrorOk; + break; + + case CURLE_UNSUPPORTED_PROTOCOL: + ret=RDDelete::ErrorUnsupportedProtocol; + break; + + case CURLE_URL_MALFORMAT: + ret=RDDelete::ErrorUrlInvalid; + break; + + case CURLE_COULDNT_RESOLVE_HOST: + ret=RDDelete::ErrorInvalidHostname; + break; + + case CURLE_LOGIN_DENIED: + ret=RDDelete::ErrorInvalidLogin; + break; + + case CURLE_COULDNT_CONNECT: + ret=RDDelete::ErrorRemoteConnection; + break; + + case 9: // CURLE_REMOTE_ACCESS_DENIED: + ret=RDDelete::ErrorRemoteAccess; + break; + + default: + ret=RDDelete::ErrorUnknown; + printf("CURL error: %d\n",err); + break; + } + if(log_debug) { + syslog(LOG_NOTICE,curl_easy_strerror(err)); + } + curl_slist_free_all(cmds); + curl_easy_cleanup(curl); + + return ret; +} + + +QString RDDelete::errorText(RDDelete::ErrorCode err) +{ + QString ret=QString().sprintf("Unknown Error [%u]",err); + + switch(err) { + case RDDelete::ErrorOk: + ret=tr("OK"); + break; + + case RDDelete::ErrorUnsupportedProtocol: + ret=tr("Unsupported protocol"); + break; + + case RDDelete::ErrorInvalidHostname: + ret=tr("Unable to resolve hostname"); + break; + + case RDDelete::ErrorRemoteServer: + ret=tr("Remote server error"); + break; + + case RDDelete::ErrorUrlInvalid: + ret=tr("Invalid URL"); + break; + + case RDDelete::ErrorUnspecified: + ret=tr("Unspecified error"); + break; + + case RDDelete::ErrorInvalidUser: + ret=tr("Invalid User"); + break; + + case RDDelete::ErrorInvalidLogin: + ret=tr("Invalid Login"); + break; + + case RDDelete::ErrorRemoteAccess: + ret=tr("Remote Access Denied"); + break; + + case RDDelete::ErrorRemoteConnection: + ret=tr("Counldn't Connect"); + break; + + case RDDelete::ErrorInternal: + ret=tr("Internal Error"); + break; + + case RDDelete::ErrorUnknown: + ret=tr("Unknown Error"); + break; + } + return ret; +} diff --git a/lib/rddelete.h b/lib/rddelete.h new file mode 100644 index 00000000..05889c53 --- /dev/null +++ b/lib/rddelete.h @@ -0,0 +1,51 @@ +// rddelete.h +// +// Delete a Remote File +// +// (C) Copyright 2011 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddelete.h,v 1.1 2011/10/17 18:48:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDDELETE_H +#define RDDELETE_H + +#include <qobject.h> +#include <qurl.h> + +class RDDelete : public QObject +{ + Q_OBJECT; + public: + enum ErrorCode {ErrorOk=0,ErrorUnsupportedProtocol=1, + ErrorInvalidHostname=4, + ErrorInternal=5,ErrorRemoteServer=6,ErrorUrlInvalid=7, + ErrorUnspecified=8,ErrorInvalidUser=9, + ErrorInvalidLogin=11,ErrorRemoteAccess=12, + ErrorRemoteConnection=13,ErrorUnknown=14}; + RDDelete(QObject *parent=0,const char *name=0); + void setTargetUrl(const QString &url); + RDDelete::ErrorCode runDelete(const QString &username, + const QString &password, + bool log_debug); + static QString errorText(RDDelete::ErrorCode err); + + private: + QUrl conv_target_url; +}; + + +#endif // RDUPLOAD_H diff --git a/lib/rddownload.cpp b/lib/rddownload.cpp new file mode 100644 index 00000000..7ed12d50 --- /dev/null +++ b/lib/rddownload.cpp @@ -0,0 +1,293 @@ +// rddownload.cpp +// +// Download a File +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddownload.cpp,v 1.5.4.2 2013/01/30 15:03:53 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <syslog.h> + +#include <curl/curl.h> + +#include <qapplication.h> +#include <qfileinfo.h> + +#include <rd.h> +#include <rdsystemuser.h> +#include <rddownload.h> + +// +// CURL Progress Callback +// +int DownloadProgressCallback(void *clientp,double dltotal,double dlnow, + double ultotal,double ulnow) +{ + RDDownload *conv=(RDDownload *)clientp; + conv->UpdateProgress(ulnow); + qApp->processEvents(); + if(conv->aborting()) { + return 1; + } + return 0; +} + + +int DownloadErrorCallback(CURL *curl,curl_infotype type,char *msg,size_t size, + void *clientp) +{ + char str[1000]; + + if(type!=CURLINFO_TEXT) { + return 0; + } + if(size>999) { + size=999; + } + memset(&str,0,size+1); + memcpy(str,msg,size); + syslog(LOG_DEBUG,"CURL MSG: %s",str); + return 0; +} + + +RDDownload::RDDownload(const QString &station_name, + QObject *parent,const char *name) + : QObject(parent,name) +{ + conv_aborting=false; +} + + +void RDDownload::setSourceUrl(const QString &url) +{ + conv_src_url=url; +} + + +void RDDownload::setDestinationFile(const QString &filename) +{ + conv_dst_filename=filename; + QFileInfo fi(filename); + conv_dst_size=fi.size(); +} + + +int RDDownload::totalSteps() const +{ + return conv_dst_size; +} + + +RDDownload::ErrorCode RDDownload::runDownload(const QString &username, + const QString &password, + bool log_debug) +{ + CURL *curl=NULL; + CURLcode curl_err; + FILE *f; + long response_code=0; + RDDownload::ErrorCode ret=RDDownload::ErrorOk; + RDSystemUser *user=NULL; + char url[1024]; + char userpwd[256]; + + // + // Validate User for file: transfers + // + if((getuid()==0)&&(conv_src_url.protocol().lower()=="file")) { + user=new RDSystemUser(username); + if(!user->validatePassword(password)) { + delete user; + return RDDownload::ErrorInvalidUser; + } + } + + if((curl=curl_easy_init())==NULL) { + return RDDownload::ErrorInternal; + } + if((f=fopen(conv_dst_filename,"w"))==NULL) { + curl_easy_cleanup(curl); + return RDDownload::ErrorNoDestination; + } + // + // Write out URL as a C string before passing to curl_easy_setopt(), + // otherwise some versions of LibCurl will throw a 'bad/illegal format' + // error. + // + strncpy(url,conv_src_url.toString(conv_src_url.protocol().lower()=="http"), + 1024); + curl_easy_setopt(curl,CURLOPT_URL,url); + curl_easy_setopt(curl,CURLOPT_WRITEDATA,f); + strncpy(userpwd,username+":"+password,256); + curl_easy_setopt(curl,CURLOPT_USERPWD,userpwd); + curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT); + curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1); + curl_easy_setopt(curl,CURLOPT_PROGRESSFUNCTION,DownloadProgressCallback); + curl_easy_setopt(curl,CURLOPT_PROGRESSDATA,this); + curl_easy_setopt(curl,CURLOPT_NOPROGRESS,0); + if(log_debug) { + curl_easy_setopt(curl,CURLOPT_VERBOSE,1); + curl_easy_setopt(curl,CURLOPT_DEBUGFUNCTION,DownloadErrorCallback); + } + + if(user!=NULL) { + setegid(user->gid()); + seteuid(user->uid()); + } + switch((curl_err=curl_easy_perform(curl))) { + case CURLE_OK: + if(conv_src_url.protocol().lower()=="http") { + curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&response_code); + if(response_code!=200) { + ret=RDDownload::ErrorUrlInvalid; + } + } + break; + + case CURLE_UNSUPPORTED_PROTOCOL: + ret=RDDownload::ErrorUnsupportedProtocol; + break; + + case CURLE_URL_MALFORMAT: + ret=RDDownload::ErrorUrlInvalid; + break; + + case CURLE_COULDNT_RESOLVE_HOST: + ret=RDDownload::ErrorInvalidHostname; + break; + + case CURLE_LOGIN_DENIED: + ret=RDDownload::ErrorInvalidLogin; + break; + + case CURLE_COULDNT_CONNECT: + ret=RDDownload::ErrorRemoteConnection; + break; + + case 9: // CURLE_REMOTE_ACCESS_DENIED + ret=RDDownload::ErrorRemoteAccess; + break; + + default: + syslog(LOG_ERR,"Unknown CURL Error [%d]: %s", + curl_err,curl_easy_strerror(curl_err)); + ret=RDDownload::ErrorUnspecified; + } + if(user!=NULL) { + seteuid(getuid()); + setegid(getgid()); + delete user; + } + if((curl_err!=CURLE_OK)&&log_debug) { + syslog(LOG_WARNING,"CURL download failed: url: %s username: %s", + (const char *)conv_src_url.toString(), + (const char *)username); + } + curl_easy_cleanup(curl); + fclose(f); + + return ret; +} + + +bool RDDownload::aborting() const +{ + return conv_aborting; +} + + +QString RDDownload::errorText(RDDownload::ErrorCode err) +{ + QString ret=QString().sprintf("Unknown Error [%u]",err); + + switch(err) { + case RDDownload::ErrorOk: + ret=tr("OK"); + break; + + case RDDownload::ErrorUnsupportedProtocol: + ret=tr("Unsupported protocol"); + break; + + case RDDownload::ErrorNoSource: + ret=tr("Unable to access source file"); + break; + + case RDDownload::ErrorNoDestination: + ret=tr("Unable to create destination file"); + break; + + case RDDownload::ErrorInvalidHostname: + ret=tr("Unable to resolve hostname"); + break; + + case RDDownload::ErrorRemoteServer: + ret=tr("Remote server error"); + break; + + case RDDownload::ErrorUrlInvalid: + ret=tr("Invalid URL"); + break; + + case RDDownload::ErrorUnspecified: + ret=tr("Unspecified error"); + break; + + case RDDownload::ErrorInvalidUser: + ret=tr("Invalid User"); + break; + + case RDDownload::ErrorInternal: + ret=tr("Internal Error"); + break; + + case RDDownload::ErrorAborted: + ret=tr("Download aborted"); + break; + + case RDDownload::ErrorInvalidLogin: + ret=tr("Invalid username or password"); + break; + + case RDDownload::ErrorRemoteAccess: + ret=tr("Remote access denied"); + break; + + case RDDownload::ErrorRemoteConnection: + ret=tr("Couldn't connect to server"); + break; + } + return ret; +} + + +void RDDownload::abort() +{ + conv_aborting=true; +} + + +void RDDownload::UpdateProgress(int step) +{ + emit progressChanged(step); +} diff --git a/lib/rddownload.h b/lib/rddownload.h new file mode 100644 index 00000000..ca6336d7 --- /dev/null +++ b/lib/rddownload.h @@ -0,0 +1,67 @@ +// rddownload.h +// +// Download a File +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddownload.h,v 1.2 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDDOWNLOAD_H +#define RDDOWNLOAD_H + +#include <qobject.h> +#include <qurl.h> + +class RDDownload : public QObject +{ + Q_OBJECT; + public: + enum ErrorCode {ErrorOk=0,ErrorUnsupportedProtocol=1,ErrorNoSource=2, + ErrorNoDestination=3,ErrorInvalidHostname=4, + ErrorInternal=5,ErrorRemoteServer=6,ErrorUrlInvalid=7, + ErrorUnspecified=8,ErrorInvalidUser=9,ErrorAborted=10, + ErrorInvalidLogin=11,ErrorRemoteAccess=12, + ErrorRemoteConnection=13}; + RDDownload(const QString &station_name, + QObject *parent=0,const char *name=0); + void setSourceUrl(const QString &url); + void setDestinationFile(const QString &filename); + int totalSteps() const; + RDDownload::ErrorCode runDownload(const QString &username, + const QString &password, + bool log_debug); + bool aborting() const; + static QString errorText(RDDownload::ErrorCode err); + + public slots: + void abort(); + + signals: + void progressChanged(int step); + + private: + void UpdateProgress(int step); + friend int DownloadProgressCallback(void *clientp,double dltotal,double dlnow, + double ultotal,double ulnow); + QUrl conv_src_url; + QString conv_dst_filename; + bool conv_aborting; + uint conv_dst_size; +}; + + +#endif // RDDOWNLOAD_H diff --git a/lib/rddropbox.cpp b/lib/rddropbox.cpp new file mode 100644 index 00000000..fd9b0be6 --- /dev/null +++ b/lib/rddropbox.cpp @@ -0,0 +1,353 @@ +// rddropbox.cpp +// +// Abstract a Rivendell dropbox configuration. +// +// (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddropbox.cpp,v 1.9.8.1 2013/12/11 20:17:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rddb.h> +#include <rdconf.h> +#include <rddropbox.h> +#include <rdescape_string.h> + + +// +// Global Classes +// +RDDropbox::RDDropbox(int id,const QString &stationname) +{ + RDSqlQuery *q; + QString sql; + + box_id=id; + + if(id<0) { + sql=QString().sprintf("insert into DROPBOXES set STATION_NAME=\"%s\"", + (const char *)stationname); + q=new RDSqlQuery(sql); + delete q; + sql="select ID from DROPBOXES order by ID desc"; + q=new RDSqlQuery(sql); + if(q->first()) { + box_id=q->value(0).toInt(); + } + delete q; + } +} + + +int RDDropbox::id() const +{ + return box_id; +} + + +QString RDDropbox::stationName() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"STATION_NAME").toString(); +} + + +void RDDropbox::setStationName(const QString &name) const +{ + SetRow("STATION_NAME",name); +} + + +QString RDDropbox::groupName() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"GROUP_NAME").toString(); +} + + +void RDDropbox::setGroupName(const QString &name) const +{ + SetRow("GROUP_NAME",name); +} + + +QString RDDropbox::path() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"PATH").toString(); +} + + +void RDDropbox::setPath(const QString &path) const +{ + SetRow("PATH",path); +} + + +int RDDropbox::normalizationLevel() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"NORMALIZATION_LEVEL").toInt(); +} + + +void RDDropbox::setNormalizationLevel(int lvl) const +{ + SetRow("NORMALIZATION_LEVEL",lvl); +} + + +int RDDropbox::autotrimLevel() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"AUTOTRIM_LEVEL").toInt(); +} + + +void RDDropbox::setAutotrimLevel(int lvl) const +{ + SetRow("AUTOTRIM_LEVEL",lvl); +} + + +bool RDDropbox::singleCart() const +{ + return RDBool(RDGetSqlValue("DROPBOXES","ID",box_id,"SINGLE_CART").toString()); +} + + +void RDDropbox::setSingleCart(bool state) const +{ + SetRow("SINGLE_CART",state); +} + + +unsigned RDDropbox::toCart() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"TO_CART").toUInt(); +} + + +void RDDropbox::setToCart(unsigned cart) const +{ + SetRow("TO_CART",cart); +} + + +bool RDDropbox::useCartchunkId() const +{ + return + RDBool(RDGetSqlValue("DROPBOXES","ID",box_id,"USE_CARTCHUNK_ID").toString()); +} + + +void RDDropbox::setUseCartchunkId(bool state) const +{ + SetRow("USE_CARTCHUNK_ID",state); +} + + +bool RDDropbox::titleFromCartchunkId() const +{ + return + RDBool(RDGetSqlValue("DROPBOXES","ID",box_id,"TITLE_FROM_CARTCHUNK_ID").toString()); +} + + +void RDDropbox::setTitleFromCartchunkId(bool state) const +{ + SetRow("TITLE_FROM_CARTCHUNK_ID",state); +} + + +bool RDDropbox::deleteCuts() const +{ + return RDBool(RDGetSqlValue("DROPBOXES","ID",box_id,"DELETE_CUTS").toString()); +} + + +void RDDropbox::setDeleteCuts(bool state) const +{ + SetRow("DELETE_CUTS",state); +} + + +bool RDDropbox::deleteSource() const +{ + return RDBool(RDGetSqlValue("DROPBOXES","ID",box_id,"DELETE_SOURCE"). + toString()); +} + + +void RDDropbox::setDeleteSource(bool state) const +{ + SetRow("DELETE_SOURCE",state); +} + + +QString RDDropbox::metadataPattern() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"METADATA_PATTERN").toString(); +} + + +void RDDropbox::setMetadataPattern(const QString &str) const +{ + SetRow("METADATA_PATTERN",str); +} + + +QString RDDropbox::userDefined() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"SET_USER_DEFINED").toString(); +} + + +void RDDropbox::setUserDefined(const QString &str) const +{ + SetRow("SET_USER_DEFINED",str); +} + + +int RDDropbox::startdateOffset() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"STARTDATE_OFFSET").toInt(); +} + + +void RDDropbox::setStartdateOffset(int offset) const +{ + SetRow("STARTDATE_OFFSET",offset); +} + + +int RDDropbox::enddateOffset() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"ENDDATE_OFFSET").toInt(); +} + + +void RDDropbox::setEnddateOffset(int offset) const +{ + SetRow("ENDDATE_OFFSET",offset); +} + + +bool RDDropbox::fixBrokenFormats() const +{ + return RDBool(RDGetSqlValue("DROPBOXES","ID",box_id,"FIX_BROKEN_FORMATS"). + toString()); +} + + +void RDDropbox::setFixBrokenFormats(bool state) const +{ + SetRow("FIX_BROKEN_FORMATS",state); +} + + +QString RDDropbox::logPath() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"LOG_PATH").toString(); +} + + +void RDDropbox::setLogPath(const QString &path) const +{ + SetRow("LOG_PATH",path); +} + + +bool RDDropbox::createDates() const +{ + return RDBool(RDGetSqlValue("DROPBOXES","ID",box_id,"IMPORT_CREATE_DATES"). + toString()); +} + + +void RDDropbox::setCreateDates(bool state) const +{ + SetRow("IMPORT_CREATE_DATES",state); +} + + +int RDDropbox::createStartdateOffset() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"CREATE_STARTDATE_OFFSET").toInt(); +} + + +void RDDropbox::setCreateStartdateOffset(int offset) const +{ + SetRow("CREATE_STARTDATE_OFFSET",offset); +} + + +int RDDropbox::createEnddateOffset() const +{ + return RDGetSqlValue("DROPBOXES","ID",box_id,"CREATE_ENDDATE_OFFSET").toInt(); +} + + +void RDDropbox::setCreateEnddateOffset(int offset) const +{ + SetRow("CREATE_ENDDATE_OFFSET",offset); +} + + +void RDDropbox::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update DROPBOXES set %s=%d where ID=%d", + (const char *)param,value,box_id); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDDropbox::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update DROPBOXES set %s=%u where ID=%d", + (const char *)param,value,box_id); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDDropbox::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update DROPBOXES set %s=\"%s\" where ID=%d", + (const char *)param, + (const char *)RDEscapeString(value), + box_id); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDDropbox::SetRow(const QString ¶m,bool value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update DROPBOXES set %s=\"%s\" where ID=%d", + (const char *)param,(const char *)RDYesNo(value), + box_id); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rddropbox.h b/lib/rddropbox.h new file mode 100644 index 00000000..93bcde55 --- /dev/null +++ b/lib/rddropbox.h @@ -0,0 +1,84 @@ +// rddropbox.h +// +// Abstract a Rivendell Dropbox Configuration +// +// (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rddropbox.h,v 1.6.8.1 2013/12/11 20:17:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> + + +#ifndef RDDROPBOX_H +#define RDDROPBOX_H + +class RDDropbox +{ + public: + RDDropbox(int id,const QString &stationname=""); + int id() const; + QString stationName() const; + void setStationName(const QString &name) const; + QString groupName() const; + void setGroupName(const QString &name) const; + QString path() const; + void setPath(const QString &path) const; + int normalizationLevel() const; + void setNormalizationLevel(int lvl) const; + int autotrimLevel() const; + void setAutotrimLevel(int lvl) const; + bool singleCart() const; + void setSingleCart(bool state) const; + unsigned toCart() const; + void setToCart(unsigned cart) const; + bool useCartchunkId() const; + void setUseCartchunkId(bool state) const; + bool titleFromCartchunkId() const; + void setTitleFromCartchunkId(bool state) const; + bool deleteCuts() const; + void setDeleteCuts(bool state) const; + bool deleteSource() const; + void setDeleteSource(bool state) const; + QString metadataPattern() const; + void setMetadataPattern(const QString &str) const; + QString userDefined() const; + void setUserDefined(const QString &str) const; + int startdateOffset() const; + void setStartdateOffset(int offset) const; + int enddateOffset() const; + void setEnddateOffset(int offset) const; + bool fixBrokenFormats() const; + void setFixBrokenFormats(bool state) const; + QString logPath() const; + void setLogPath(const QString &path) const; + bool createDates() const; + void setCreateDates(bool state) const; + int createStartdateOffset() const; + void setCreateStartdateOffset(int offset) const; + int createEnddateOffset() const; + void setCreateEnddateOffset(int offset) const; + + private: + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,unsigned value) const; + void SetRow(const QString ¶m,const QString &value) const; + void SetRow(const QString ¶m,bool value) const; + int box_id; +}; + + +#endif // RDDROPBOX_H diff --git a/lib/rdedit_audio.cpp b/lib/rdedit_audio.cpp new file mode 100644 index 00000000..e6e68509 --- /dev/null +++ b/lib/rdedit_audio.cpp @@ -0,0 +1,2940 @@ +// rdedit_audio.cpp +// +// Edit Rivendell Audio +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdedit_audio.cpp,v 1.26.6.3 2014/01/16 02:44:59 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <math.h> +#include <qpainter.h> +#include <qsignalmapper.h> +#include <qmessagebox.h> + +#include <rdconf.h> +#include <rd.h> +#include <rdmixer.h> +#include <rdcut.h> +#include <rdedit_audio.h> +#include <rdaudioinfo.h> +#include <rdtrimaudio.h> + +RDEditAudio::RDEditAudio(RDCart *cart,QString cut_name,RDCae *cae,RDUser *user, + RDStation *station,RDConfig *config,int card, + int port,int preroll, + int trim_level,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_cae=cae; + edit_station=station; + edit_user=user; + edit_config=config; + edit_card=card; + edit_port=port; + edit_stream=-1; + + bool editing_allowed=user->editAudio()&&cart->owner().isEmpty(); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Hevetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Hevetica",12,QFont::Normal); + label_font.setPixelSize(12); + QFont small_font("Helvetica",10,QFont::Bold); + small_font.setPixelSize(10); + + edit_cursors[RDEditAudio::Play]=-1; + edit_cursors[RDEditAudio::SegueStart]=-1; + edit_cursors[RDEditAudio::SegueEnd]=-1; + edit_cursors[RDEditAudio::TalkStart]=-1; + edit_cursors[RDEditAudio::TalkEnd]=-1; + edit_cursors[RDEditAudio::Start]=-1; + edit_cursors[RDEditAudio::End]=-1; + edit_cursors[RDEditAudio::FadeUp]=-1; + edit_cursors[RDEditAudio::FadeDown]=-1; + edit_cursors[RDEditAudio::HookStart]=-1; + edit_cursors[RDEditAudio::HookEnd]=-1; + is_playing=false; + is_paused=false; + is_stopped=false; + is_looping=false; + edit_cue_point=RDEditAudio::Play; + edit_play_mode=RDEditAudio::FromStart; + left_button_pressed=false; + center_button_pressed=false; + energy_data=NULL; + energy_size=0; + edit_gain_mode=RDEditAudio::GainNone; + edit_gain_count=0; + use_looping=false; + ignore_pause=false; + delete_marker=false; + pause_mode=false; + played_cursor=0; + + // + // The Cut + // + edit_cut=new RDCut(cut_name); + setCaption(QString().sprintf("Edit Markers - %s\n", + (const char *)edit_cut->description())); + + // + // The Audio + // + connect(edit_cae,SIGNAL(playing(int)),this,SLOT(playedData(int))); + connect(edit_cae,SIGNAL(playStopped(int)),this,SLOT(pausedData(int))); + connect(edit_cae,SIGNAL(playPositionChanged(int,unsigned)), + this,SLOT(positionData(int,unsigned))); + edit_cae->loadPlay(edit_card,edit_cut->cutName(),&edit_stream,&edit_handle); + RDSetMixerOutputPort(edit_cae,edit_card,edit_stream,edit_port); + RDAudioInfo *info=new RDAudioInfo(station,edit_config,this); + RDAudioInfo::ErrorCode audio_err; + info->setCartNumber(RDCut::cartNumber(cut_name)); + info->setCutNumber(RDCut::cutNumber(cut_name)); + + if((audio_err=info->runInfo(user->name(),user->password()))== + RDAudioInfo::ErrorOk) { + edit_sample_rate=info->sampleRate(); + edit_sample_length=info->frames(); + edit_channels=info->channels(); + } + else { + fprintf(stderr,"unable to download cut data, error was: \"%s\".\n", + (const char *)RDAudioInfo::errorText(audio_err)); + edit_sample_rate=RD_DEFAULT_SAMPLE_RATE; + edit_sample_length=info->frames(); + edit_channels=2; + } + delete info; + edit_gain=EDITAUDIO_DEFAULT_GAIN; + edit_preroll=edit_sample_rate*preroll/1000; + for(unsigned i=0;i<(8*sizeof(unsigned));i++) { + if((edit_sample_length/(1<<i))<896256) { + edit_max_factor_x=1<<i; + i=8*sizeof(unsigned); + } + } + edit_factor_x=edit_max_factor_x; + + // + // Save Button + // + QPushButton *button=new QPushButton(this,"save_button"); + button->setGeometry(EDITAUDIO_WIDGET_WIDTH-90,EDITAUDIO_WIDGET_HEIGHT-120, + 80,50); + button->setDefault(true); + button->setFont(button_font); + button->setText(tr("&Save")); + connect(button,SIGNAL(clicked()),this,SLOT(saveData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(EDITAUDIO_WIDGET_WIDTH-90, + EDITAUDIO_WIDGET_HEIGHT-60,80,50); + cancel_button->setDefault(true); + cancel_button->setFont(button_font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Transport Buttons + // + edit_play_cursor_button=new RDTransportButton(RDTransportButton::PlayBetween, + this,"edit_play_cursor_button"); + edit_play_cursor_button->setGeometry(20,425,65,45); + edit_play_cursor_button-> + setPalette(QPalette(backgroundColor(),QColor(EDITAUDIO_HIGHLIGHT_COLOR))); + edit_play_cursor_button->setEnabled((edit_card>=0)&&(edit_port>=0)); + connect(edit_play_cursor_button,SIGNAL(clicked()), + this,SLOT(playCursorData())); + + edit_play_start_button=new RDTransportButton(RDTransportButton::Play, + this,"edit_play_start_button"); + edit_play_start_button->setGeometry(90,425,65,45); + edit_play_start_button-> + setPalette(QPalette(backgroundColor(),QColor(EDITAUDIO_HIGHLIGHT_COLOR))); + edit_play_start_button->setEnabled((edit_card>=0)&&(edit_port>=0)); + connect(edit_play_start_button,SIGNAL(clicked()), + this,SLOT(playStartData())); + + edit_pause_button=new RDTransportButton(RDTransportButton::Pause, + this,"edit_pause_button"); + edit_pause_button->setGeometry(160,425,65,45); + edit_pause_button->setOnColor(QColor(red)); + edit_pause_button-> + setPalette(QPalette(backgroundColor(),QColor(EDITAUDIO_HIGHLIGHT_COLOR))); + edit_pause_button->setEnabled((edit_card>=0)&&(edit_port>=0)); + connect(edit_pause_button,SIGNAL(clicked()),this,SLOT(pauseData())); + + edit_stop_button=new RDTransportButton(RDTransportButton::Stop, + this,"edit_stop_button"); + edit_stop_button->setGeometry(230,425,65,45); + edit_stop_button->on(); + edit_stop_button->setOnColor(QColor(red)); + edit_stop_button-> + setPalette(QPalette(backgroundColor(),QColor(EDITAUDIO_HIGHLIGHT_COLOR))); + edit_stop_button->setEnabled((edit_card>=0)&&(edit_port>=0)); + connect(edit_stop_button,SIGNAL(clicked()),this,SLOT(stopData())); + + edit_loop_button=new RDTransportButton(RDTransportButton::Loop, + this,"edit_loop_button"); + edit_loop_button->setGeometry(300,425,65,45); + edit_loop_button->off(); + edit_loop_button-> + setPalette(QPalette(backgroundColor(),QColor(EDITAUDIO_HIGHLIGHT_COLOR))); + edit_loop_button->setEnabled((edit_card>=0)&&(edit_port>=0)); + connect(edit_loop_button,SIGNAL(clicked()),this,SLOT(loopData())); + + // + // Time Origin Scroll Bar + // + edit_hscroll=new QScrollBar(0,0,EDITAUDIO_PAN_SIZE/10, + EDITAUDIO_PAN_SIZE,0,Qt::Horizontal, + this,"edit_hscroll"); + edit_hscroll->setGeometry(10,10+EDITAUDIO_WAVEFORM_HEIGHT, + EDITAUDIO_WAVEFORM_WIDTH,20); + connect(edit_hscroll,SIGNAL(valueChanged(int)),this,SLOT(hscrollData(int))); + + // + // Amplitude Buttons + // + QLabel *amp_label=new QLabel(this,"amp_label"); + amp_label->setGeometry(742,5,80,16); + amp_label->setAlignment(AlignHCenter|AlignVCenter); + amp_label->setFont(button_font); + amp_label->setText(tr("Amplitude")); + + RDTransportButton *y_up_button=new RDTransportButton(RDTransportButton::Up, + this,"y_up_button"); + y_up_button->setGeometry(747,22,70,50); + y_up_button->setFont(QFont("Helvetica",12,QFont::Bold)); + y_up_button->setText(tr("Zoom\nIn")); + connect(y_up_button,SIGNAL(clicked()),this,SLOT(yUp())); + + RDTransportButton *y_down_button=new RDTransportButton(RDTransportButton::Down, + this,"y_down_button"); + y_down_button->setGeometry(747,72,70,50); + y_down_button->setFont(QFont("Helvetica",12,QFont::Bold)); + y_down_button->setText(tr("Zoom\nOut")); + connect(y_down_button,SIGNAL(clicked()),this,SLOT(yDown())); + + // + // Time Buttons + // + QLabel *time_label=new QLabel(this,"time_label"); + time_label->setGeometry(760,143,40,16); + time_label->setAlignment(AlignHCenter|AlignVCenter); + time_label->setFont(button_font); + time_label->setText(tr("Time")); + + QPushButton *x_full_in_button=new QPushButton(this,"x_full_in_button"); + x_full_in_button->setGeometry(747,160,70,50); + x_full_in_button->setFont(button_font); + x_full_in_button->setText(tr("Full\nIn")); + connect(x_full_in_button,SIGNAL(clicked()),this,SLOT(xFullIn())); + + RDTransportButton *x_up_button=new RDTransportButton(RDTransportButton::Up, + this,"x_up_button"); + x_up_button->setGeometry(747,212,70,50); + x_up_button->setFont(button_font); + x_up_button->setText(tr("Zoom\nIn")); + connect(x_up_button,SIGNAL(clicked()),this,SLOT(xUp())); + + RDTransportButton *x_down_button=new RDTransportButton(RDTransportButton::Down, + this,"x_down_button"); + x_down_button->setGeometry(747,262,70,50); + x_down_button->setFont(button_font); + x_down_button->setText(tr("Zoom\nOut")); + connect(x_down_button,SIGNAL(clicked()),this,SLOT(xDown())); + + QPushButton *x_full_button=new QPushButton(this,"x_full_button"); + x_full_button->setGeometry(747,312,70,50); + x_full_button->setFont(button_font); + x_full_button->setText(tr("Full\nOut")); + connect(x_full_button,SIGNAL(clicked()),this,SLOT(xFullOut())); + + // + // GoTo Buttons + // + QLabel *goto_label=new QLabel(this,"goto_label"); + goto_label->setGeometry(760,378,40,16); + goto_label->setAlignment(AlignHCenter|AlignVCenter); + goto_label->setFont(button_font); + goto_label->setText(tr("Goto")); + + QPushButton *goto_cursor_button=new QPushButton(this,"goto_cursor_button"); + goto_cursor_button->setGeometry(747,393,70,50); + goto_cursor_button->setFont(button_font); + goto_cursor_button->setText(tr("Cursor")); + connect(goto_cursor_button,SIGNAL(clicked()),this,SLOT(gotoCursorData())); + + QPushButton *goto_home_button=new QPushButton(this,"goto_home_button"); + goto_home_button->setGeometry(747,443,70,50); + goto_home_button->setFont(button_font); + goto_home_button->setText(tr("Home")); + connect(goto_home_button,SIGNAL(clicked()),this,SLOT(gotoHomeData())); + + QPushButton *goto_end_button=new QPushButton(this,"goto_end_button"); + goto_end_button->setGeometry(747,493,70,50); + goto_end_button->setFont(button_font); + goto_end_button->setText(tr("End")); + connect(goto_end_button,SIGNAL(clicked()),this,SLOT(gotoEndData())); + + // + // Cursor Readouts + // + QSignalMapper *button_mapper=new QSignalMapper(this,"button_mapper"); + connect(button_mapper,SIGNAL(mapped(int)),this,SLOT(cuePointData(int))); + QSignalMapper *edit_mapper=new QSignalMapper(this,"edit_mapper"); + connect(edit_mapper,SIGNAL(mapped(int)),this,SLOT(cueEditData(int))); + QSignalMapper *esc_mapper=new QSignalMapper(this,"esc_mapper"); + connect(esc_mapper,SIGNAL(mapped(int)),this,SLOT(cueEscData(int))); + + edit_cursor_edit[RDEditAudio::Start]=new RDMarkerEdit(this,"edit_start_edit"); + edit_cursor_edit[RDEditAudio::Start]->setGeometry(88,496,70,21); + edit_cursor_edit[RDEditAudio::Start]->setReadOnly(true); + edit_cursor_edit[RDEditAudio::Start]->setDragEnabled(false); + edit_cursor_edit[RDEditAudio::Start]-> + setFont(label_font); + edit_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::Start],(int)RDEditAudio::Start); + esc_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::Start],(int)RDEditAudio::Start); + connect(edit_cursor_edit[RDEditAudio::Start],SIGNAL(returnPressed()), + edit_mapper,SLOT(map())); + connect(edit_cursor_edit[RDEditAudio::Start],SIGNAL(escapePressed()), + esc_mapper,SLOT(map())); + + edit_cue_button[RDEditAudio::Start]=new RDMarkerButton(this,"StartButton"); + edit_cue_button[RDEditAudio::Start]->setToggleButton(true); + edit_cue_button[RDEditAudio::Start]->setGeometry(20,485,66,45); + edit_cue_button[RDEditAudio::Start]->setFlashColor(backgroundColor()); + edit_cue_button[RDEditAudio::Start]-> + setFlashPeriod(EDITAUDIO_BUTTON_FLASH_PERIOD); + edit_cue_button[RDEditAudio::Start]-> + setPalette(QPalette(QColor(RD_START_END_MARKER_COLOR),backgroundColor())); + edit_cue_button[RDEditAudio::Start]-> + setFont(button_font); + edit_cue_button[RDEditAudio::Start]->setText(tr("Cut\nStart")); + button_mapper-> + setMapping(edit_cue_button[RDEditAudio::Start],(int)RDEditAudio::Start); + connect(edit_cue_button[RDEditAudio::Start],SIGNAL(clicked()), + button_mapper,SLOT(map())); + + edit_cursor_edit[RDEditAudio::End]=new RDMarkerEdit(this,"edit_end_edit"); + edit_cursor_edit[RDEditAudio::End]->setGeometry(88,541,70,21); + edit_cursor_edit[RDEditAudio::End]->setReadOnly(true); + edit_cursor_edit[RDEditAudio::End]->setDragEnabled(false); + edit_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::End],(int)RDEditAudio::End); + esc_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::End],(int)RDEditAudio::End); + connect(edit_cursor_edit[RDEditAudio::End],SIGNAL(returnPressed()), + edit_mapper,SLOT(map())); + connect(edit_cursor_edit[RDEditAudio::End],SIGNAL(escapePressed()), + esc_mapper,SLOT(map())); + edit_cursor_edit[RDEditAudio::End]-> + setFont(label_font); + edit_cue_button[RDEditAudio::End]=new RDMarkerButton(this,"button"); + edit_cue_button[RDEditAudio::End]->setToggleButton(true); + edit_cue_button[RDEditAudio::End]->setGeometry(20,530,66,45); + edit_cue_button[RDEditAudio::End]->setFlashColor(backgroundColor()); + edit_cue_button[RDEditAudio::End]-> + setFlashPeriod(EDITAUDIO_BUTTON_FLASH_PERIOD); + edit_cue_button[RDEditAudio::End]-> + setPalette(QPalette(QColor(RD_START_END_MARKER_COLOR), + backgroundColor())); + edit_cue_button[RDEditAudio::End]-> + setFont(button_font); + edit_cue_button[RDEditAudio::End]->setText(tr("Cut\nEnd")); + button_mapper-> + setMapping(edit_cue_button[RDEditAudio::End],(int)RDEditAudio::End); + connect(edit_cue_button[RDEditAudio::End],SIGNAL(clicked()), + button_mapper,SLOT(map())); + + edit_cursor_edit[RDEditAudio::TalkStart]= + new RDMarkerEdit(this,"edit_talk_start_edit"); + edit_cursor_edit[RDEditAudio::TalkStart]->setGeometry(243,596,70,21); + edit_cursor_edit[RDEditAudio::TalkStart]->setReadOnly(true); + edit_cursor_edit[RDEditAudio::TalkStart]->setDragEnabled(false); + edit_cursor_edit[RDEditAudio::TalkStart]-> + setFont(label_font); + edit_mapper->setMapping(edit_cursor_edit[RDEditAudio::TalkStart], + (int)RDEditAudio::TalkStart); + esc_mapper->setMapping(edit_cursor_edit[RDEditAudio::TalkStart], + (int)RDEditAudio::TalkStart); + connect(edit_cursor_edit[RDEditAudio::TalkStart],SIGNAL(returnPressed()), + edit_mapper,SLOT(map())); + connect(edit_cursor_edit[RDEditAudio::TalkStart],SIGNAL(escapePressed()), + esc_mapper,SLOT(map())); + edit_cue_button[RDEditAudio::TalkStart]=new RDMarkerButton(this,"button"); + edit_cue_button[RDEditAudio::TalkStart]->setToggleButton(true); + edit_cue_button[RDEditAudio::TalkStart]->setGeometry(175,585,66,45); + edit_cue_button[RDEditAudio::TalkStart]->setFlashColor(backgroundColor()); + edit_cue_button[RDEditAudio::TalkStart]-> + setFlashPeriod(EDITAUDIO_BUTTON_FLASH_PERIOD); + edit_cue_button[RDEditAudio::TalkStart]-> + setPalette(QPalette(QColor(RD_TALK_MARKER_COLOR), + backgroundColor())); + edit_cue_button[RDEditAudio::TalkStart]-> + setFont(button_font); + edit_cue_button[RDEditAudio::TalkStart]->setText(tr("Talk\nStart")); + button_mapper-> + setMapping(edit_cue_button[RDEditAudio::TalkStart],(int)RDEditAudio::TalkStart); + connect(edit_cue_button[RDEditAudio::TalkStart],SIGNAL(clicked()), + button_mapper,SLOT(map())); + + edit_cursor_edit[RDEditAudio::TalkEnd]= + new RDMarkerEdit(this,"edit_talk_end_edit"); + edit_cursor_edit[RDEditAudio::TalkEnd]->setGeometry(243,641,70,21); + edit_cursor_edit[RDEditAudio::TalkEnd]->setReadOnly(true); + edit_cursor_edit[RDEditAudio::TalkEnd]->setDragEnabled(false); + edit_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::TalkEnd],(int)RDEditAudio::TalkEnd); + esc_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::TalkEnd],(int)RDEditAudio::TalkEnd); + connect(edit_cursor_edit[RDEditAudio::TalkEnd],SIGNAL(returnPressed()), + edit_mapper,SLOT(map())); + connect(edit_cursor_edit[RDEditAudio::TalkEnd],SIGNAL(escapePressed()), + esc_mapper,SLOT(map())); + edit_cursor_edit[RDEditAudio::TalkEnd]-> + setFont(label_font); + edit_cue_button[RDEditAudio::TalkEnd]=new RDMarkerButton(this,"button"); + edit_cue_button[RDEditAudio::TalkEnd]->setToggleButton(true); + edit_cue_button[RDEditAudio::TalkEnd]->setGeometry(175,630,66,45); + edit_cue_button[RDEditAudio::TalkEnd]->setFlashColor(backgroundColor()); + edit_cue_button[RDEditAudio::TalkEnd]-> + setFlashPeriod(EDITAUDIO_BUTTON_FLASH_PERIOD); + edit_cue_button[RDEditAudio::TalkEnd]-> + setPalette(QPalette(QColor(RD_TALK_MARKER_COLOR), + backgroundColor())); + edit_cue_button[RDEditAudio::TalkEnd]-> + setFont(button_font); + edit_cue_button[RDEditAudio::TalkEnd]->setText("Talk\nEnd"); + button_mapper-> + setMapping(edit_cue_button[RDEditAudio::TalkEnd],(int)RDEditAudio::TalkEnd); + connect(edit_cue_button[RDEditAudio::TalkEnd],SIGNAL(clicked()), + button_mapper,SLOT(map())); + + edit_cursor_edit[RDEditAudio::SegueStart]= + new RDMarkerEdit(this,"edit_segue_start_edit"); + edit_cursor_edit[RDEditAudio::SegueStart]->setGeometry(398,596,70,21); + edit_cursor_edit[RDEditAudio::SegueStart]->setReadOnly(true); + edit_cursor_edit[RDEditAudio::SegueStart]->setDragEnabled(false); + edit_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::SegueStart], + (int)RDEditAudio::SegueStart); + esc_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::SegueStart], + (int)RDEditAudio::SegueStart); + connect(edit_cursor_edit[RDEditAudio::SegueStart],SIGNAL(returnPressed()), + edit_mapper,SLOT(map())); + connect(edit_cursor_edit[RDEditAudio::SegueStart],SIGNAL(escapePressed()), + esc_mapper,SLOT(map())); + edit_cursor_edit[RDEditAudio::SegueStart]-> + setFont(label_font); + edit_cue_button[RDEditAudio::SegueStart]=new RDMarkerButton(this,"button"); + edit_cue_button[RDEditAudio::SegueStart]->setToggleButton(true); + edit_cue_button[RDEditAudio::SegueStart]->setGeometry(330,585,66,45); + edit_cue_button[RDEditAudio::SegueStart]->setFlashColor(backgroundColor()); + edit_cue_button[RDEditAudio::SegueStart]-> + setFlashPeriod(EDITAUDIO_BUTTON_FLASH_PERIOD); + edit_cue_button[RDEditAudio::SegueStart]-> + setPalette(QPalette(QColor(RD_SEGUE_MARKER_COLOR), + backgroundColor())); + edit_cue_button[RDEditAudio::SegueStart]-> + setFont(button_font); + edit_cue_button[RDEditAudio::SegueStart]->setText(tr("Segue\nStart")); + button_mapper-> + setMapping(edit_cue_button[RDEditAudio::SegueStart], + (int)RDEditAudio::SegueStart); + connect(edit_cue_button[RDEditAudio::SegueStart],SIGNAL(clicked()), + button_mapper,SLOT(map())); + + edit_cursor_edit[RDEditAudio::SegueEnd]= + new RDMarkerEdit(this,"edit_segue_end_edit"); + edit_cursor_edit[RDEditAudio::SegueEnd]->setGeometry(398,641,70,21); + edit_cursor_edit[RDEditAudio::SegueEnd]->setReadOnly(true); + edit_cursor_edit[RDEditAudio::SegueEnd]->setDragEnabled(false); + edit_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::SegueEnd],(int)RDEditAudio::SegueEnd); + esc_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::SegueEnd],(int)RDEditAudio::SegueEnd); + connect(edit_cursor_edit[RDEditAudio::SegueEnd],SIGNAL(returnPressed()), + edit_mapper,SLOT(map())); + connect(edit_cursor_edit[RDEditAudio::SegueEnd],SIGNAL(escapePressed()), + esc_mapper,SLOT(map())); + edit_cursor_edit[RDEditAudio::SegueEnd]-> + setFont(label_font); + edit_cue_button[RDEditAudio::SegueEnd]=new RDMarkerButton(this,"button"); + edit_cue_button[RDEditAudio::SegueEnd]->setToggleButton(true); + edit_cue_button[RDEditAudio::SegueEnd]->setGeometry(330,630,66,45); + edit_cue_button[RDEditAudio::SegueEnd]->setFlashColor(backgroundColor()); + edit_cue_button[RDEditAudio::SegueEnd]-> + setFlashPeriod(EDITAUDIO_BUTTON_FLASH_PERIOD); + edit_cue_button[RDEditAudio::SegueEnd]-> + setPalette(QPalette(QColor(RD_SEGUE_MARKER_COLOR),backgroundColor())); + edit_cue_button[RDEditAudio::SegueEnd]-> + setFont(button_font); + edit_cue_button[RDEditAudio::SegueEnd]->setText(tr("Segue\nEnd")); + button_mapper-> + setMapping(edit_cue_button[RDEditAudio::SegueEnd],(int)RDEditAudio::SegueEnd); + connect(edit_cue_button[RDEditAudio::SegueEnd],SIGNAL(clicked()), + button_mapper,SLOT(map())); + + edit_cursor_edit[RDEditAudio::FadeUp]=new RDMarkerEdit(this,"edit_fadeup_edit"); + edit_cursor_edit[RDEditAudio::FadeUp]->setGeometry(88,596,70,21); + edit_cursor_edit[RDEditAudio::FadeUp]->setReadOnly(true); + edit_cursor_edit[RDEditAudio::FadeUp]->setDragEnabled(false); + edit_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::FadeUp],(int)RDEditAudio::FadeUp); + esc_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::FadeUp],(int)RDEditAudio::FadeUp); + connect(edit_cursor_edit[RDEditAudio::FadeUp],SIGNAL(returnPressed()), + edit_mapper,SLOT(map())); + connect(edit_cursor_edit[RDEditAudio::FadeUp],SIGNAL(escapePressed()), + esc_mapper,SLOT(map())); + edit_cursor_edit[RDEditAudio::FadeUp]-> + setFont(label_font); + edit_cue_button[RDEditAudio::FadeUp]=new RDMarkerButton(this,"button"); + edit_cue_button[RDEditAudio::FadeUp]->setToggleButton(true); + edit_cue_button[RDEditAudio::FadeUp]->setGeometry(20,585,66,45); + edit_cue_button[RDEditAudio::FadeUp]->setFlashColor(backgroundColor()); + edit_cue_button[RDEditAudio::FadeUp]-> + setFlashPeriod(EDITAUDIO_BUTTON_FLASH_PERIOD); + edit_cue_button[RDEditAudio::FadeUp]-> + setPalette(QPalette(QColor(RD_FADE_MARKER_COLOR),backgroundColor())); + edit_cue_button[RDEditAudio::FadeUp]-> + setFont(button_font); + edit_cue_button[RDEditAudio::FadeUp]->setText(tr("Fade\nUp")); + button_mapper-> + setMapping(edit_cue_button[RDEditAudio::FadeUp],(int)RDEditAudio::FadeUp); + connect(edit_cue_button[RDEditAudio::FadeUp],SIGNAL(clicked()), + button_mapper,SLOT(map())); + + edit_cursor_edit[RDEditAudio::FadeDown]= + new RDMarkerEdit(this,"edit_fadedown_edit"); + edit_cursor_edit[RDEditAudio::FadeDown]->setGeometry(88,641,70,21); + edit_cursor_edit[RDEditAudio::FadeDown]->setReadOnly(true); + edit_cursor_edit[RDEditAudio::FadeDown]->setDragEnabled(false); + edit_mapper->setMapping(edit_cursor_edit[RDEditAudio::FadeDown], + (int)RDEditAudio::FadeDown); + esc_mapper->setMapping(edit_cursor_edit[RDEditAudio::FadeDown], + (int)RDEditAudio::FadeDown); + connect(edit_cursor_edit[RDEditAudio::FadeDown],SIGNAL(returnPressed()), + edit_mapper,SLOT(map())); + connect(edit_cursor_edit[RDEditAudio::FadeDown],SIGNAL(escapePressed()), + esc_mapper,SLOT(map())); + edit_cursor_edit[RDEditAudio::FadeDown]-> + setFont(label_font); + edit_cue_button[RDEditAudio::FadeDown]=new RDMarkerButton(this,"button"); + edit_cue_button[RDEditAudio::FadeDown]->setToggleButton(true); + edit_cue_button[RDEditAudio::FadeDown]->setGeometry(20,630,66,45); + edit_cue_button[RDEditAudio::FadeDown]->setFlashColor(backgroundColor()); + edit_cue_button[RDEditAudio::FadeDown]-> + setFlashPeriod(EDITAUDIO_BUTTON_FLASH_PERIOD); + edit_cue_button[RDEditAudio::FadeDown]-> + setPalette(QPalette(QColor(RD_FADE_MARKER_COLOR),backgroundColor())); + edit_cue_button[RDEditAudio::FadeDown]-> + setFont(button_font); + edit_cue_button[RDEditAudio::FadeDown]->setText("Fade\nDown"); + button_mapper-> + setMapping(edit_cue_button[RDEditAudio::FadeDown],(int)RDEditAudio::FadeDown); + connect(edit_cue_button[RDEditAudio::FadeDown],SIGNAL(clicked()), + button_mapper,SLOT(map())); + + edit_cursor_edit[RDEditAudio::HookStart]=new RDMarkerEdit(this,"edit_hook_start_edit"); + edit_cursor_edit[RDEditAudio::HookStart]->setGeometry(553,596,70,21); + edit_cursor_edit[RDEditAudio::HookStart]->setReadOnly(true); + edit_cursor_edit[RDEditAudio::HookStart]->setDragEnabled(false); + edit_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::HookStart], + (int)RDEditAudio::HookStart); + esc_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::HookStart], + (int)RDEditAudio::HookStart); + connect(edit_cursor_edit[RDEditAudio::HookStart],SIGNAL(returnPressed()), + edit_mapper,SLOT(map())); + connect(edit_cursor_edit[RDEditAudio::HookStart],SIGNAL(escapePressed()), + esc_mapper,SLOT(map())); + edit_cursor_edit[RDEditAudio::HookStart]-> + setFont(label_font); + edit_cursor_edit[RDEditAudio::HookStart]->setReadOnly(true); + edit_cue_button[RDEditAudio::HookStart]=new RDMarkerButton(this,"button"); + edit_cue_button[RDEditAudio::HookStart]->setToggleButton(true); + edit_cue_button[RDEditAudio::HookStart]->setGeometry(485,585,66,45); + edit_cue_button[RDEditAudio::HookStart]->setFlashColor(backgroundColor()); + edit_cue_button[RDEditAudio::HookStart]-> + setFlashPeriod(EDITAUDIO_BUTTON_FLASH_PERIOD); + edit_cue_button[RDEditAudio::HookStart]-> + setPalette(QPalette(QColor(RD_HOOK_MARKER_COLOR), + backgroundColor())); + edit_cue_button[RDEditAudio::HookStart]-> + setFont(button_font); + edit_cue_button[RDEditAudio::HookStart]->setText(tr("Hook\nStart")); + button_mapper-> + setMapping(edit_cue_button[RDEditAudio::HookStart], + (int)RDEditAudio::HookStart); + connect(edit_cue_button[RDEditAudio::HookStart],SIGNAL(clicked()), + button_mapper,SLOT(map())); + + edit_cursor_edit[RDEditAudio::HookEnd]= + new RDMarkerEdit(this,"edit_hook_end_edit"); + edit_cursor_edit[RDEditAudio::HookEnd]->setGeometry(553,641,70,21); + edit_cursor_edit[RDEditAudio::HookEnd]->setReadOnly(true); + edit_cursor_edit[RDEditAudio::HookEnd]->setDragEnabled(false); + edit_cursor_edit[RDEditAudio::HookEnd]-> + setFont(label_font); + edit_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::HookEnd],(int)RDEditAudio::HookEnd); + esc_mapper-> + setMapping(edit_cursor_edit[RDEditAudio::HookEnd],(int)RDEditAudio::HookEnd); + connect(edit_cursor_edit[RDEditAudio::HookEnd],SIGNAL(returnPressed()), + edit_mapper,SLOT(map())); + connect(edit_cursor_edit[RDEditAudio::HookEnd],SIGNAL(escapePressed()), + esc_mapper,SLOT(map())); + edit_cue_button[RDEditAudio::HookEnd]=new RDMarkerButton(this,"button"); + edit_cue_button[RDEditAudio::HookEnd]->setToggleButton(true); + edit_cue_button[RDEditAudio::HookEnd]->setGeometry(485,630,66,45); + edit_cue_button[RDEditAudio::HookEnd]->setFlashColor(backgroundColor()); + edit_cue_button[RDEditAudio::HookEnd]-> + setFlashPeriod(EDITAUDIO_BUTTON_FLASH_PERIOD); + edit_cue_button[RDEditAudio::HookEnd]-> + setPalette(QPalette(QColor(RD_HOOK_MARKER_COLOR), + backgroundColor())); + edit_cue_button[RDEditAudio::HookEnd]-> + setFont(button_font); + edit_cue_button[RDEditAudio::HookEnd]->setText(tr("Hook\nEnd")); + button_mapper-> + setMapping(edit_cue_button[RDEditAudio::HookEnd],(int)RDEditAudio::HookEnd); + connect(edit_cue_button[RDEditAudio::HookEnd],SIGNAL(clicked()), + button_mapper,SLOT(map())); + + // + // AutoTrim Buttons + // + edit_trim_box=new QSpinBox(this,"edit_head_trim_box"); + edit_trim_box->setGeometry(243,529,70,21); + edit_trim_box->setAcceptDrops(false); + edit_trim_box->setValidator(0); + edit_trim_box->setSuffix(tr(" dB")); + edit_trim_box->setRange(-99,0); + edit_trim_box-> + setValue((trim_level+REFERENCE_LEVEL)/100); + QLabel *label=new QLabel(tr("Threshold"),this,"label"); + label->setGeometry(238,513,70,15); + label->setAlignment(AlignHCenter); + label->setFont(QFont(small_font)); + QPushButton *trim_start_button=new QPushButton(this,"trim_start_button"); + trim_start_button->setGeometry(175,485,66,45); + trim_start_button-> + setPalette(QPalette(QColor(RD_START_END_MARKER_COLOR),backgroundColor())); + trim_start_button->setFont(button_font); + trim_start_button->setText(tr("Trim\nStart")); + connect(trim_start_button,SIGNAL(clicked()),this,SLOT(trimHeadData())); + + QPushButton *trim_end_button=new QPushButton(this,"trim_end_button"); + trim_end_button->setGeometry(175,530,66,45); + trim_end_button-> + setPalette(QPalette(QColor(RD_START_END_MARKER_COLOR),backgroundColor())); + trim_end_button->setFont(button_font); + trim_end_button->setText(tr("Trim\nEnd")); + connect(trim_end_button,SIGNAL(clicked()),this,SLOT(trimTailData())); + + // + // Cut Gain Control + // + edit_gain_control=new QRangeControl(); + edit_gain_control->setRange(-1000,1000); + edit_gain_control->setSteps(10,10); + edit_gain_edit=new RDMarkerEdit(this,"edit_gain_edit"); + edit_gain_edit->setGeometry(398,529,70,21); + edit_gain_edit->setAcceptDrops(false); + connect(edit_gain_edit,SIGNAL(returnPressed()),this,SLOT(gainChangedData())); + label=new QLabel(tr("Cut Gain"),this,"label"); + label->setGeometry(388,513,70,15); + label->setAlignment(AlignHCenter); + label->setFont(QFont(small_font)); + RDTransportButton *gain_up_button=new + RDTransportButton(RDTransportButton::Up,this,"button"); + gain_up_button->setGeometry(330,485,66,45); + gain_up_button->off(); + connect(gain_up_button,SIGNAL(pressed()),this,SLOT(gainUpPressedData())); + connect(gain_up_button,SIGNAL(released()),this,SLOT(gainReleasedData())); + + RDTransportButton *gain_down_button= + new RDTransportButton(RDTransportButton::Down,this,"button"); + gain_down_button->setGeometry(330,530,66,45); + gain_down_button->off(); + connect(gain_down_button,SIGNAL(pressed()),this,SLOT(gainDownPressedData())); + connect(gain_down_button,SIGNAL(released()),this,SLOT(gainReleasedData())); + edit_gain_timer=new QTimer(this,"edit_gain_timer"); + connect(edit_gain_timer,SIGNAL(timeout()),this,SLOT(gainTimerData())); + + // + // Marker Remove Button + // + edit_remove_button=new RDPushButton(this,"edit_remove_button"); + edit_remove_button->setFlashPeriod(EDITAUDIO_BUTTON_FLASH_PERIOD); + edit_remove_button->setGeometry(485,510,66,45); + edit_remove_button->setFont(button_font); + edit_remove_button->setText(tr("Remove\nMarker")); + edit_remove_button->setToggleButton(true); + edit_remove_button->setFlashColor(QColor(EDITAUDIO_REMOVE_FLASH_COLOR)); + connect(edit_remove_button,SIGNAL(clicked()),this,SLOT(removeButtonData())); + + // + // Segue Fade Box + // + edit_overlap_box=new QCheckBox(this,"edit_overlap_box"); + edit_overlap_box->setGeometry(570,510,15,15); + label=new QLabel(edit_overlap_box,tr("No Fade on Segue Out"), + this,"label"); + label->setGeometry(590,508,130,20); + label->setFont(button_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Time Counters + // + label=new QLabel(tr("Position"),this,"label"); + label->setGeometry(60,385,70,20); + label->setFont(QFont(small_font)); + label->setAlignment(Qt::AlignHCenter); + label-> + setPalette(QPalette(backgroundColor(),QColor(EDITAUDIO_HIGHLIGHT_COLOR))); + edit_overall_edit=new QLineEdit(this,"edit_overall_edit"); + edit_overall_edit->setAcceptDrops(false); + edit_overall_edit->setGeometry(60,400,70,21); + edit_overall_edit->setFont(label_font); + edit_overall_edit->setReadOnly(true); + + edit_region_edit_label=new QLabel("Region",this,"label"); + edit_region_edit_label->setGeometry(158,385,70,20); + edit_region_edit_label->setFont(QFont(small_font)); + edit_region_edit_label->setAlignment(Qt::AlignHCenter); + edit_region_edit_label-> + setPalette(QPalette(backgroundColor(),QColor(EDITAUDIO_HIGHLIGHT_COLOR))); + edit_region_edit=new QLineEdit(this,"edit_region_edit"); + edit_region_edit->setAcceptDrops(false); + edit_region_edit->setGeometry(158,400,70,21); + edit_region_edit->setFont(label_font); + edit_region_edit->setReadOnly(true); + + label=new QLabel(tr("Length"),this,"label"); + label->setGeometry(256,385,70,20); + label->setFont(QFont(small_font)); + label->setAlignment(Qt::AlignHCenter); + label-> + setPalette(QPalette(backgroundColor(),QColor(EDITAUDIO_HIGHLIGHT_COLOR))); + edit_size_edit=new QLineEdit(this,"edit_size_edit"); + edit_size_edit->setAcceptDrops(false); + edit_size_edit->setGeometry(256,400,70,21); + edit_size_edit->setFont(label_font); + edit_size_edit->setReadOnly(true); + + // + // The Audio Meter + // + edit_meter=new RDStereoMeter(this,"edit_meter"); + edit_meter->setGeometry(380,398,edit_meter->geometry().width(), + edit_meter->geometry().height()); + edit_meter->setSegmentSize(5); + edit_meter->setMode(RDSegMeter::Peak); + edit_meter_timer=new QTimer(this,"meter_timer"); + connect(edit_meter_timer,SIGNAL(timeout()),this,SLOT(meterData())); + + // + // The Wave Forms + // + edit_peaks=new RDPeaksExport(station,config,this); + RDPeaksExport::ErrorCode conv_err; + edit_peaks->setCartNumber(RDCut::cartNumber(cut_name)); + edit_peaks->setCutNumber(RDCut::cutNumber(cut_name)); + if((conv_err=edit_peaks->runExport(user->name(),user->password()))!= + RDPeaksExport::ErrorOk) { + QMessageBox::warning(this,tr("Rivendell Web Service"), + tr("Unable to download peak data, error was:\n\"")+ + RDPeaksExport::errorText(conv_err)+"\"."); + } + edit_wave_array=new QPointArray(EDITAUDIO_WAVEFORM_WIDTH-2); + DrawMaps(); + + // + // The Edit Menu + // + edit_menu=new QPopupMenu(this,"edit_menu"); + connect(edit_menu,SIGNAL(aboutToShow()),this,SLOT(updateMenuData())); + edit_menu->insertItem(tr("Delete Talk Markers"),this, + SLOT(deleteTalkData()),0,RDEditAudio::TalkStart); + edit_menu->insertItem(tr("Delete Segue Markers"),this, + SLOT(deleteSegueData()),0,RDEditAudio::SegueStart); + edit_menu->insertItem(tr("Delete Hook Markers"),this, + SLOT(deleteHookData()),0,RDEditAudio::HookStart); + edit_menu->insertItem(tr("Delete Fade Up Marker"),this, + SLOT(deleteFadeupData()),0,RDEditAudio::FadeUp); + edit_menu->insertItem(tr("Delete Fade Down Marker"),this, + SLOT(deleteFadedownData()),0,RDEditAudio::FadeDown); + + // + // Populate Counter Fields + // + edit_cursor_edit[RDEditAudio::Start]-> + setText(RDGetTimeLength(edit_cut->startPoint(true),true)); + edit_cursors[RDEditAudio::Start]=(int)(((double)edit_cut->startPoint(true)* + (double)edit_sample_rate) + /1152000.0); + edit_cursors[RDEditAudio::Play]=edit_cursors[RDEditAudio::Start]; + baseline=edit_cursors[RDEditAudio::Start]; + edit_cursor_edit[RDEditAudio::End]-> + setText(RDGetTimeLength(edit_cut->endPoint(true),true)); + edit_cursors[RDEditAudio::End]=(int)(((double)edit_cut->endPoint(true)* + (double)edit_sample_rate) + /1152000.0); + if(edit_cut->talkStartPoint()!=-1) { + edit_cursor_edit[RDEditAudio::TalkStart]-> + setText(RDGetTimeLength(edit_cut->talkStartPoint(),true)); + edit_cursors[RDEditAudio::TalkStart]= + (int)(((double)edit_cut->talkStartPoint()* + (double)edit_sample_rate)/1152000.0); + } + else { + edit_cursors[RDEditAudio::TalkStart]=-1; + } + if(edit_cut->talkEndPoint()!=-1) { + edit_cursor_edit[RDEditAudio::TalkEnd]-> + setText(RDGetTimeLength(edit_cut->talkEndPoint(),true)); + edit_cursors[RDEditAudio::TalkEnd]=(int)(((double)edit_cut->talkEndPoint()* + (double)edit_sample_rate)/1152000.0); + } + else { + edit_cursors[RDEditAudio::TalkEnd]=-1; + } + if(edit_cut->segueStartPoint()!=-1) { + edit_cursor_edit[RDEditAudio::SegueStart]-> + setText(RDGetTimeLength(edit_cut->segueStartPoint(),true)); + edit_cursors[RDEditAudio::SegueStart]= + (int)(((double)edit_cut->segueStartPoint()* + (double)edit_sample_rate)/1152000.0); + } + else { + edit_cursors[RDEditAudio::SegueStart]=-1; + } + if(edit_cut->segueEndPoint()!=-1) { + edit_cursor_edit[RDEditAudio::SegueEnd]-> + setText(RDGetTimeLength(edit_cut->segueEndPoint(),true)); + edit_cursors[RDEditAudio::SegueEnd]=(int)(((double)edit_cut->segueEndPoint()* + (double)edit_sample_rate)/1152000.0); + } + else { + edit_cursors[RDEditAudio::SegueEnd]=-1; + } + if(edit_cut->fadeupPoint()!=-1) { + edit_cursor_edit[RDEditAudio::FadeUp]->setText(RDGetTimeLength(edit_cut->fadeupPoint(),true)); + edit_cursors[RDEditAudio::FadeUp]=(int)(((double)edit_cut->fadeupPoint()* + (double)edit_sample_rate)/1152000.0); + } + else { + edit_cursors[RDEditAudio::FadeUp]=-1; + } + if(edit_cut->fadedownPoint()!=-1) { + edit_cursor_edit[RDEditAudio::FadeDown]-> + setText(RDGetTimeLength(edit_cut->fadedownPoint(),true)); + edit_cursors[RDEditAudio::FadeDown]=(int)(((double)edit_cut->fadedownPoint()* + (double)edit_sample_rate)/1152000.0); + } + else { + edit_cursors[RDEditAudio::FadeDown]=-1; + } + if(edit_cut->hookStartPoint()!=-1) { + edit_cursor_edit[RDEditAudio::HookStart]-> + setText(RDGetTimeLength(edit_cut->hookStartPoint(),true)); + edit_cursors[RDEditAudio::HookStart]=(int)(((double)edit_cut->hookStartPoint()* + (double)edit_sample_rate)/1152000.0); + } + else { + edit_cursors[RDEditAudio::HookStart]=-1; + } + if(edit_cut->hookEndPoint()!=-1) { + edit_cursor_edit[RDEditAudio::HookEnd]-> + setText(RDGetTimeLength(edit_cut->hookEndPoint(),true)); + edit_cursors[RDEditAudio::HookEnd]=(int)(((double)edit_cut->hookEndPoint()* + (double)edit_sample_rate)/1152000.0); + } + else { + edit_cursors[RDEditAudio::HookEnd]=-1; + } + edit_gain_control->setValue(edit_cut->playGain()); + edit_gain_edit->setText(QString().sprintf("%4.1f dB", + (double)edit_gain_control->value()/100.0)); + edit_trim_box->setValue(trim_level/100); + if(edit_cut->segueGain()==0) { + edit_overlap_box->setChecked(true); + } + else { + edit_overlap_box->setChecked(false); + } + + // + // The Mouse Pointers + // + DrawPointers(); + setCursor(*edit_arrow_cursor); + setMouseTracking(true); + setFocusPolicy(StrongFocus); + + UpdateCursors(); + UpdateCounters(); + gainChangedData(); + // + // Set Control Perms + // + for(int i=1;i<RDEditAudio::LastMarker;i++) { + edit_cursor_edit[i]->setReadOnly(!editing_allowed); + edit_cue_button[i]->setEnabled(editing_allowed); + } + edit_remove_button->setEnabled(editing_allowed); + gain_up_button->setEnabled(editing_allowed); + gain_down_button->setEnabled(editing_allowed); + edit_gain_edit->setReadOnly(!editing_allowed); + trim_start_button->setEnabled(editing_allowed); + trim_end_button->setEnabled(editing_allowed); + edit_overlap_box->setEnabled(editing_allowed); +} + + +RDEditAudio::~RDEditAudio() +{ + delete edit_peaks; +} + + +QSize RDEditAudio::sizeHint() const +{ + return QSize(EDITAUDIO_WIDGET_WIDTH,EDITAUDIO_WIDGET_HEIGHT); +} + + +QSizePolicy RDEditAudio::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDEditAudio::saveData() +{ + edit_cae->stopPlay(edit_handle); + edit_cae->unloadPlay(edit_handle); + if(!SaveMarkers()) { + return; + } + done(0); +} + + +void RDEditAudio::cancelData() +{ + edit_cae->stopPlay(edit_handle); + edit_cae->unloadPlay(edit_handle); + done(1); +} + + +void RDEditAudio::xFullIn() +{ + if(edit_factor_x!=0.125) { + edit_factor_x=0.125; + edit_hscroll->setRange(0,(int)((double)edit_peaks->energySize()/ + (double)edit_channels* + (1.0-edit_factor_x/edit_max_factor_x))); + CenterDisplay(); + DrawMaps(); + repaint(false); + } +} + + +void RDEditAudio::xUp() +{ + if(edit_factor_x>(1.0/8.0)) { + edit_factor_x/=2.0; + if(edit_factor_x==edit_max_factor_x) { + edit_hscroll->setRange(0,0); + } + else { + edit_hscroll->setRange(0,(int)((double)edit_peaks->energySize()/ + (double)edit_channels* + (1.0-edit_factor_x/edit_max_factor_x))); + } + CenterDisplay(); + DrawMaps(); + repaint(false); + } +} + + +void RDEditAudio::xDown() +{ + if(edit_factor_x<edit_max_factor_x) { + edit_factor_x*=2; + if(edit_factor_x==edit_max_factor_x) { + edit_hscroll->setRange(0,0); + } + else { + edit_hscroll->setRange(0,(int)((double)edit_peaks->energySize()/ + (double)edit_channels* + (1.0-edit_factor_x/edit_max_factor_x))); + } + CenterDisplay(); + DrawMaps(); + repaint(false); + } +} + + +void RDEditAudio::xFullOut() +{ + if(edit_factor_x!=edit_max_factor_x) { + edit_factor_x=edit_max_factor_x; + edit_hscroll->setRange(0,0); + CenterDisplay(); + DrawMaps(); + repaint(false); + } +} + + +void RDEditAudio::yUp() +{ + if(edit_gain>-21) { + edit_gain-=3; + DrawMaps(); + repaint(false); + } +} + + +void RDEditAudio::yDown() +{ + if(edit_gain<0) { + edit_gain+=3; + DrawMaps(); + repaint(false); + } + +} + + +void RDEditAudio::gotoCursorData() +{ + edit_hscroll->setValue(edit_cursors[RDEditAudio::Play]- + (int)(edit_factor_x*(double)EDITAUDIO_WAVEFORM_WIDTH/2.0)); +} + + +void RDEditAudio::gotoHomeData() +{ + edit_hscroll->setValue(edit_hscroll->minValue()); +} + + +void RDEditAudio::gotoEndData() +{ + edit_hscroll->setValue(edit_hscroll->maxValue()); +} + + +void RDEditAudio::hscrollData(int value) +{ + DrawMaps(); + repaint(false); +} + + +void RDEditAudio::playStartData() +{ + if(is_playing) { + return; + } + edit_cae-> + positionPlay(edit_handle,GetTime(edit_cursors[RDEditAudio::Start]*1152)); + switch(edit_cue_point) { + case RDEditAudio::End: + case RDEditAudio::SegueEnd: + case RDEditAudio::TalkEnd: + case RDEditAudio::HookEnd: + played_cursor=edit_cursors[edit_cue_point]-edit_preroll/1152; + break; + + default: + played_cursor=edit_cursors[edit_cue_point]; + break; + } + if(!is_playing) { + edit_cae->setPlayPortActive(edit_card,edit_port,edit_stream); + edit_cae-> + setOutputVolume(edit_card,edit_stream,edit_port,0+edit_gain_control->value()); + edit_cae->play(edit_handle,(int)(1000.0*(double) + ((edit_cursors[RDEditAudio::End]- + edit_cursors[RDEditAudio::Start])*1152)/ + (double)edit_sample_rate), + RD_TIMESCALE_DIVISOR,0); + } + if(use_looping) { + is_looping=true; + } + edit_play_mode=RDEditAudio::FromStart; + edit_play_start_button->on(); + edit_play_cursor_button->off(); + edit_pause_button->off(); +} + + +void RDEditAudio::playCursorData() +{ + int length=0; + + if(is_playing) { + return; + } + switch(edit_cue_point) { + case RDEditAudio::Play: + case RDEditAudio::Start: + case RDEditAudio::End: + case RDEditAudio::FadeDown: + length=(int)(1000.0*(double)((edit_cursors[RDEditAudio::End]- + edit_cursors[RDEditAudio::Play])*1152)/ + (double)edit_sample_rate); + break; + + case RDEditAudio::SegueStart: + case RDEditAudio::SegueEnd: + length=(int)(1000.0*(double)((edit_cursors[RDEditAudio::SegueEnd]- + edit_cursors[RDEditAudio::Play])*1152)/ + (double)edit_sample_rate); + break; + + case RDEditAudio::TalkStart: + case RDEditAudio::TalkEnd: + length=(int)(1000.0*(double)((edit_cursors[RDEditAudio::TalkEnd]- + edit_cursors[RDEditAudio::Play])*1152)/ + (double)edit_sample_rate); + break; + + case RDEditAudio::HookStart: + case RDEditAudio::HookEnd: + length=(int)(1000.0*(double)((edit_cursors[RDEditAudio::HookEnd]- + edit_cursors[RDEditAudio::Play])*1152)/ + (double)edit_sample_rate); + break; + + case RDEditAudio::FadeUp: + length=(int)(1000.0*(double)((edit_cursors[RDEditAudio::FadeUp]- + edit_cursors[RDEditAudio::Play])*1152)/ + (double)edit_sample_rate); + break; + + default: + break; + } + played_cursor=edit_cursors[RDEditAudio::Play]; + + pause_mode=false; + if(!is_playing) { + edit_cae->setPlayPortActive(edit_card,edit_port,edit_stream); + edit_cae-> + setOutputVolume(edit_card,edit_stream,edit_port,0+edit_gain_control->value()); + edit_cae->play(edit_handle,length,RD_TIMESCALE_DIVISOR,0); + } + if(use_looping) { + is_looping=true; + } + edit_play_mode=RDEditAudio::FromCursor; + edit_play_start_button->off(); + edit_play_cursor_button->on(); + edit_pause_button->off(); +} + + +void RDEditAudio::pauseData() +{ + if(!is_paused) { + is_looping=false; + pause_mode=true; + edit_cae->stopPlay(edit_handle); + } +} + + +void RDEditAudio::stopData() +{ + if(!is_paused) { + is_looping=false; + pause_mode=false; + edit_cae->stopPlay(edit_handle); + } +} + + +void RDEditAudio::loopData() +{ + if(use_looping) { + use_looping=false; + is_looping=false; + edit_loop_button->off(); + } + else { + use_looping=true; + if(is_playing) { + is_looping=true; + } + edit_loop_button->flash(); + } +} + + +void RDEditAudio::playedData(int handle) +{ + edit_pause_button->off(); + edit_stop_button->off(); + is_playing=true; + is_paused=false; + is_stopped=false; + edit_meter_timer->start(RD_METER_UPDATE_INTERVAL); +} + + +void RDEditAudio::pausedData(int handle) +{ + if(ignore_pause) { + return; + } + if(is_looping) { + switch(edit_play_mode) { + case RDEditAudio::FromStart: + LoopRegion(edit_cursors[RDEditAudio::Start], + edit_cursors[RDEditAudio::End]); + break; + + case RDEditAudio::FromCursor: + case RDEditAudio::Region: + switch(edit_cue_point) { + case RDEditAudio::Start: + case RDEditAudio::End: + LoopRegion(edit_cursors[RDEditAudio::Start], + edit_cursors[RDEditAudio::End]); + break; + + case RDEditAudio::SegueStart: + case RDEditAudio::SegueEnd: + LoopRegion(edit_cursors[RDEditAudio::SegueStart], + edit_cursors[RDEditAudio::SegueEnd]); + break; + + case RDEditAudio::TalkStart: + case RDEditAudio::TalkEnd: + LoopRegion(edit_cursors[RDEditAudio::TalkStart], + edit_cursors[RDEditAudio::TalkEnd]); + break; + + case RDEditAudio::HookStart: + case RDEditAudio::HookEnd: + LoopRegion(edit_cursors[RDEditAudio::HookStart], + edit_cursors[RDEditAudio::HookEnd]); + break; + + case RDEditAudio::FadeUp: + LoopRegion(edit_cursors[RDEditAudio::Start], + edit_cursors[RDEditAudio::FadeUp]); + break; + + case RDEditAudio::FadeDown: + LoopRegion(edit_cursors[RDEditAudio::FadeDown], + edit_cursors[RDEditAudio::End]); + break; + + default: + break; + } + break; + } + return; + } + else { + edit_play_start_button->off(); + edit_play_cursor_button->off(); + if(pause_mode) { + edit_pause_button->on(); + } + else { + edit_stop_button->on(); + edit_cae->positionPlay(edit_handle,GetTime(played_cursor*1152)); + } + is_playing=false; + is_paused=true; + is_stopped=false; + } + if(edit_meter_timer->isActive()) { + edit_meter_timer->stop(); + edit_meter->setLeftPeakBar(-10000); + edit_meter->setRightPeakBar(-10000); + } +} + + +void RDEditAudio::positionData(int handle,unsigned int pos) +{ //pos is in miliseconds + edit_cursors[RDEditAudio::Play]= + (unsigned int)((double)pos*edit_sample_rate/1152000.0); + if((edit_sample_rate%8000)!=0) { //Account for the MPEG padding! + edit_cursors[RDEditAudio::Play]++; + } + UpdateCursors(); + UpdateCounters(); +} + + +void RDEditAudio::cuePointData(int id) +{ + if(is_playing) { + edit_cue_button[id]->toggle(); + return; + } + if(delete_marker) { + switch(id) { + case RDEditAudio::SegueStart: + case RDEditAudio::SegueEnd: + deleteSegueData(); + break; + + case RDEditAudio::TalkStart: + case RDEditAudio::TalkEnd: + deleteTalkData(); + break; + + case RDEditAudio::HookStart: + case RDEditAudio::HookEnd: + deleteHookData(); + break; + + case RDEditAudio::FadeUp: + deleteFadeupData(); + break; + + case RDEditAudio::FadeDown: + deleteFadedownData(); + break; + } + for(int i=1;i<11;i++) { + edit_cue_button[i]->setToggleButton(true); + } + edit_remove_button->setFlashingEnabled(false); + edit_remove_button->setOn(false); + delete_marker=false; + } + else { + if(edit_cue_button[id]->isOn()) { + edit_cue_button[id]->setFlashingEnabled(true); + if(edit_cue_point!=RDEditAudio::Play) { + cueEditData(edit_cue_point); + edit_cue_button[edit_cue_point]->setOn(false); + edit_cue_button[edit_cue_point]->setFlashingEnabled(false); + edit_cursor_edit[edit_cue_point]->setReadOnly(true); + } + edit_cue_point=(RDEditAudio::CuePoints)id; + edit_cue_string=edit_cursor_edit[edit_cue_point]->text(); + edit_cursor_edit[edit_cue_point]->setReadOnly(false); + switch(id) { + case RDEditAudio::Start: + case RDEditAudio::SegueStart: + case RDEditAudio::TalkStart: + case RDEditAudio::HookStart: + case RDEditAudio::FadeDown: + edit_cae->positionPlay(edit_handle,GetTime(edit_cursors[id]*1152)); + break; + + case RDEditAudio::End: + case RDEditAudio::SegueEnd: + case RDEditAudio::TalkEnd: + case RDEditAudio::HookEnd: + case RDEditAudio::FadeUp: + PreRoll(edit_cursors[id]*1152,(RDEditAudio::CuePoints)id); + break; + } + } + else { + edit_cue_button[id]->setFlashingEnabled(false); + edit_cue_point=RDEditAudio::Play; + edit_cae->positionPlay(edit_handle,0); + } + } + UpdateCounters(); +} + + +void RDEditAudio::cueEditData(int id) +{ + int cursor; + int old_cursor; + + old_cursor=1152*edit_cursors[id]; + if((cursor=(int)((double)(RDSetTimeLength(edit_cursor_edit[id]->text())* + (double)edit_sample_rate/1000.0)))<0) { + cursor=1152*edit_cursors[id]; + edit_cursor_edit[id]->setText(edit_cue_string); + return; + } + ignore_pause=true; + if(!PositionCursor(cursor)) { + PositionCursor(old_cursor); + } + ignore_pause=false; + edit_cursor_edit[id]->setFocus(); + edit_cursor_edit[id]->selectAll(); + return; +} + + +void RDEditAudio::cueEscData(int id) +{ + edit_cursor_edit[id]->setText(edit_cue_string); + edit_cursor_edit[id]->selectAll(); +} + + +void RDEditAudio::updateMenuData() +{ + if(edit_cursors[RDEditAudio::Start]!=-1) { + edit_menu->setItemEnabled(RDEditAudio::Start,true); + } + else { + edit_menu->setItemEnabled(RDEditAudio::Start,false); + } + if(edit_cursors[RDEditAudio::End]!=-1) { + edit_menu->setItemEnabled(RDEditAudio::End,true); + } + else { + edit_menu->setItemEnabled(RDEditAudio::End,false); + } + if(edit_cursors[RDEditAudio::SegueStart]!=-1) { + edit_menu->setItemEnabled(RDEditAudio::SegueStart,true); + } + else { + edit_menu->setItemEnabled(RDEditAudio::SegueStart,false); + } + if(edit_cursors[RDEditAudio::SegueEnd]!=-1) { + edit_menu->setItemEnabled(RDEditAudio::SegueEnd,true); + } + else { + edit_menu->setItemEnabled(RDEditAudio::SegueEnd,false); + } + if(edit_cursors[RDEditAudio::TalkStart]!=-1) { + edit_menu->setItemEnabled(RDEditAudio::TalkStart,true); + } + else { + edit_menu->setItemEnabled(RDEditAudio::TalkStart,false); + } + if(edit_cursors[RDEditAudio::TalkEnd]!=-1) { + edit_menu->setItemEnabled(RDEditAudio::TalkEnd,true); + } + else { + edit_menu->setItemEnabled(RDEditAudio::TalkEnd,false); + } + if(edit_cursors[RDEditAudio::FadeUp]!=-1) { + edit_menu->setItemEnabled(RDEditAudio::FadeUp,true); + } + else { + edit_menu->setItemEnabled(RDEditAudio::FadeUp,false); + } + if(edit_cursors[RDEditAudio::FadeDown]!=-1) { + edit_menu->setItemEnabled(RDEditAudio::FadeDown,true); + } + else { + edit_menu->setItemEnabled(RDEditAudio::FadeDown,false); + } + if(edit_cursors[RDEditAudio::HookStart]!=-1) { + edit_menu->setItemEnabled(RDEditAudio::HookStart,true); + } + else { + edit_menu->setItemEnabled(RDEditAudio::HookStart,false); + } + if(edit_cursors[RDEditAudio::HookEnd]!=-1) { + edit_menu->setItemEnabled(RDEditAudio::HookEnd,true); + } + else { + edit_menu->setItemEnabled(RDEditAudio::HookEnd,false); + } +} + + +void RDEditAudio::deleteSegueData() +{ + DeleteMarkerData(RDEditAudio::SegueStart); +} + + +void RDEditAudio::deleteFadeupData() +{ + DeleteMarkerData(RDEditAudio::FadeUp); +} + + +void RDEditAudio::deleteFadedownData() +{ + DeleteMarkerData(RDEditAudio::FadeDown); +} + + +void RDEditAudio::deleteTalkData() +{ + DeleteMarkerData(RDEditAudio::TalkStart); +} + + +void RDEditAudio::deleteHookData() +{ + DeleteMarkerData(RDEditAudio::HookStart); +} + + +void RDEditAudio::trimHeadData() +{ + RDEditAudio::CuePoints point; + RDTrimAudio::ErrorCode conv_err; + RDTrimAudio *conv=new RDTrimAudio(edit_station,edit_config,this); + conv->setCartNumber(edit_cut->cartNumber()); + conv->setCutNumber(edit_cut->cutNumber()); + conv->setTrimLevel(100*edit_trim_box->value()); + switch(conv_err=conv->runTrim(edit_user->name(),edit_user->password())) { + case RDTrimAudio::ErrorOk: + if(conv->startPoint()>=0) { + point=edit_cue_point; + edit_cue_point=RDEditAudio::Start; + PositionCursor((double)conv->startPoint()* + (double)edit_sample_rate/1000.0); + UpdateCounters(); + edit_cue_point=point; + } + break; + + default: + QMessageBox::warning(this,tr("Edit Audio"), + RDTrimAudio::errorText(conv_err)); + break; + } + delete conv; +} + + +void RDEditAudio::trimTailData() +{ + RDEditAudio::CuePoints point; + RDTrimAudio::ErrorCode conv_err; + RDTrimAudio *conv=new RDTrimAudio(edit_station,edit_config,this); + conv->setCartNumber(edit_cut->cartNumber()); + conv->setCutNumber(edit_cut->cutNumber()); + conv->setTrimLevel(100*edit_trim_box->value()); + switch(conv_err=conv->runTrim(edit_user->name(),edit_user->password())) { + case RDTrimAudio::ErrorOk: + if(conv->endPoint()>=0) { + point=edit_cue_point; + edit_cue_point=RDEditAudio::End; + PositionCursor((double)conv->endPoint()*(double)edit_sample_rate/1000.0); + UpdateCounters(); + edit_cue_point=point; + } + break; + + default: + QMessageBox::warning(this,tr("Edit Audio"), + RDTrimAudio::errorText(conv_err)); + break; + } + delete conv; +} + + +void RDEditAudio::gainUpPressedData() +{ + edit_gain_mode=RDEditAudio::GainUp; + gainTimerData(); + edit_gain_timer->start(TYPO_RATE_1); +} + + +void RDEditAudio::gainDownPressedData() +{ + edit_gain_mode=RDEditAudio::GainDown; + gainTimerData(); + edit_gain_timer->start(TYPO_RATE_1); +} + + +void RDEditAudio::gainChangedData() +{ + int gain; + QString str; + + if(sscanf((const char *)edit_gain_edit->text(),"%d",&gain)==1) { + edit_gain_control->setValue(gain*100); + } + str=QString(tr("dB")); + edit_gain_edit->setText(QString().sprintf("%4.1f %s", + (double)edit_gain_control->value()/100.0, + (const char *)str)); + DrawMaps(); + repaint(false); +} + + +void RDEditAudio::gainReleasedData() +{ + edit_gain_timer->stop(); + edit_gain_mode=RDEditAudio::GainNone; + edit_gain_count=0; +} + + +void RDEditAudio::gainTimerData() +{ + QString str; + + switch(edit_gain_mode) { + case RDEditAudio::GainUp: + edit_gain_control->addLine(); + if(edit_gain_count++==1) { + edit_gain_timer->changeInterval(TYPO_RATE_2); + } + break; + + case RDEditAudio::GainDown: + edit_gain_control->subtractLine(); + if(edit_gain_count++==1) { + edit_gain_timer->changeInterval(TYPO_RATE_2); + } + break; + + default: + break; + } + str=QString(tr("dB")); + edit_gain_edit->setText(QString().sprintf("%4.1f %s", + (double)edit_gain_control->value()/100.0, + (const char *)str)); + DrawMaps(); + repaint(false); +} + + +void RDEditAudio::removeButtonData() +{ + if(edit_remove_button->isOn()) { + if(edit_cue_point!=RDEditAudio::Play) { + edit_cue_button[edit_cue_point]->setOn(false); + edit_cue_button[edit_cue_point]->setFlashingEnabled(false); + edit_cue_point=RDEditAudio::Play; + } + for(int i=1;i<11;i++) { + edit_cue_button[i]->setToggleButton(false); + } + edit_remove_button->setFlashingEnabled(true); + delete_marker=true; + } + else { + for(int i=1;i<11;i++) { + edit_cue_button[i]->setToggleButton(true); + } + edit_remove_button->setFlashingEnabled(false); + delete_marker=false; + } + UpdateCounters(); +} + + +void RDEditAudio::meterData() +{ + short levels[2]; + + edit_cae->outputMeterUpdate(edit_card,edit_port,levels); + edit_meter->setLeftPeakBar(levels[0]); + edit_meter->setRightPeakBar(levels[1]); +} + + +void RDEditAudio::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + + // + // Waveforms + // + p->setPen(QColor(black)); + if(edit_channels==1) { + p->drawImage(11,11,edit_left_image); + } + if(edit_channels==2) { + p->drawImage(11,11,edit_left_image); + p->drawImage(11,11+EDITAUDIO_WAVEFORM_HEIGHT/2,edit_right_image); + } + + // + // Highlights + // + p->drawRect(739,12,85,120); // Amplitude Buttons + p->drawRect(739,150,85,220); // Time Buttons + p->drawRect(739,385,85,165); // Goto Buttons + + // + // Transport Control Area + // + p->setPen(QColor(colorGroup().shadow())); + p->fillRect(11,30+EDITAUDIO_WAVEFORM_HEIGHT,EDITAUDIO_WAVEFORM_WIDTH,92, + QColor(EDITAUDIO_HIGHLIGHT_COLOR)); + p->drawRect(11,30+EDITAUDIO_WAVEFORM_HEIGHT,EDITAUDIO_WAVEFORM_WIDTH,92); + + // + // Marker Control Area + // + p->drawRect(11,130+EDITAUDIO_WAVEFORM_HEIGHT,717,197); + + p->end(); + delete p; + UpdateCursors(); +} + + +void RDEditAudio::mouseMoveEvent(QMouseEvent *e) +{ + int cursor; + + if((e->x()>10)&&(e->x()<(10+EDITAUDIO_WAVEFORM_WIDTH))&& + (e->y()>10)&&(e->y()<(EDITAUDIO_WAVEFORM_HEIGHT+6))) { + setCursor(*edit_cross_cursor); + if(left_button_pressed) { + cursor=(int)((((double)e->x()-10.0)*edit_factor_x+ + (double)edit_hscroll->value())*1152.0); + if(edit_cue_point!=RDEditAudio::Play) { + ignore_pause=true; + PositionCursor(cursor); + ignore_pause=false; + } + else { + ignore_pause=true; + edit_cae->positionPlay(edit_handle,GetTime(cursor)); + ignore_pause=false; + } + } + if(center_button_pressed) { + cursor=(int)((((double)e->x()-10.0)*edit_factor_x+ + (double)edit_hscroll->value())*1152.0); + ignore_pause=true; + edit_cae->positionPlay(edit_handle,GetTime(cursor)); + ignore_pause=false; + } + } + else { + setCursor(*edit_arrow_cursor); + } +} + + +void RDEditAudio::mousePressEvent(QMouseEvent *e) +{ + int cursor; + + if((e->x()>10)&&(e->x()<788)&&(e->y()>10)&&(e->y()<400)) { + cursor=(int)((((double)e->x()-10.0)*edit_factor_x+ + (double)edit_hscroll->value())*1152.0); + switch(e->button()) { + case QMouseEvent::LeftButton: + left_button_pressed=true; + if(edit_cue_point!=RDEditAudio::Play) { + ignore_pause=true; + PositionCursor(cursor); + ignore_pause=false; + } + else { + ignore_pause=true; + edit_cae->positionPlay(edit_handle,GetTime(cursor)); + ignore_pause=false; + } + break; + + case QMouseEvent::MidButton: + center_button_pressed=true; + ignore_pause=true; + edit_cae->positionPlay(edit_handle,GetTime(cursor)); + ignore_pause=false; + break; + + case QMouseEvent::RightButton: + edit_menu->setGeometry(e->x(),e->y()+53, + edit_menu->sizeHint().width(), + edit_menu->sizeHint().height()); + edit_menu->exec(); + break; + + default: + break; + } + } +} + + +void RDEditAudio::mouseReleaseEvent(QMouseEvent *e) +{ + switch(e->button()) { + case QMouseEvent::LeftButton: + left_button_pressed=false; + break; + + case QMouseEvent::MidButton: + center_button_pressed=false; + break; + + default: + break; + } +} + + +void RDEditAudio::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Key_Space: + if(is_playing) { + stopData(); + } + else { + if(e->state()==0) { + playCursorData(); + } + if((e->state()&ControlButton)!=0) { + playStartData(); + } + } + e->accept(); + break; + + case Key_Left: + PositionCursor(-(edit_sample_rate/10),true); + e->accept(); + break; + + case Key_Right: + PositionCursor(edit_sample_rate/10,true); + e->accept(); + break; + + case Key_Plus: + xUp(); + break; + + case Key_Minus: + xDown(); + break; + + case Key_Home: + gotoHomeData(); + break; + + case Key_End: + gotoEndData(); + break; + + case Key_Delete: + DeleteMarkerData(edit_cue_point); + break; + + default: + e->ignore(); + break; + } +} + + +void RDEditAudio::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void RDEditAudio::DeleteMarkerData(int id) +{ + if((id==RDEditAudio::Play)||(id==RDEditAudio::Start)||(id==RDEditAudio::End)) { + return; + } + switch(id) { + case RDEditAudio::Start: + case RDEditAudio::TalkStart: + case RDEditAudio::SegueStart: + case RDEditAudio::HookStart: + edit_cursors[id]=-1; + edit_cursors[id+1]=-1; + edit_cursor_edit[id]->clear(); + edit_cursor_edit[id+1]->clear(); + break; + + case RDEditAudio::End: + case RDEditAudio::TalkEnd: + case RDEditAudio::SegueEnd: + case RDEditAudio::HookEnd: + edit_cursors[id]=-1; + edit_cursors[id-1]=-1; + edit_cursor_edit[id]->clear(); + edit_cursor_edit[id-1]->clear(); + break; + + case RDEditAudio::FadeUp: + case RDEditAudio::FadeDown: + edit_cursors[id]=-1; + edit_cursor_edit[id]->clear(); + break; + } + UpdateCursors(); + UpdateCounters(); +} + + +void RDEditAudio::PreRoll(int cursor,RDEditAudio::CuePoints point) +{ + int prepoint=cursor-edit_preroll; + switch(point) { + case RDEditAudio::SegueEnd: + if(prepoint>1152*edit_cursors[RDEditAudio::SegueStart]) { + edit_cae->positionPlay(edit_handle,GetTime(prepoint)); + } + else { + edit_cae->positionPlay(edit_handle, + GetTime(1152*edit_cursors[RDEditAudio::SegueStart])); + } + break; + case RDEditAudio::End: + if(prepoint>1152*edit_cursors[RDEditAudio::Start]) { + edit_cae->positionPlay(edit_handle,GetTime(prepoint)); + } + else { + edit_cae->positionPlay(edit_handle, + GetTime(1152*edit_cursors[RDEditAudio::Start])); + } + break; + case RDEditAudio::TalkEnd: + if(prepoint>1152*edit_cursors[RDEditAudio::TalkStart]) { + edit_cae->positionPlay(edit_handle,GetTime(prepoint)); + } + else { + edit_cae->positionPlay(edit_handle, + GetTime(1152*edit_cursors[RDEditAudio::TalkStart])); + } + break; + case RDEditAudio::HookEnd: + if(prepoint>1152*edit_cursors[RDEditAudio::HookStart]) { + edit_cae->positionPlay(edit_handle,GetTime(prepoint)); + } + else { + edit_cae->positionPlay(edit_handle, + GetTime(1152*edit_cursors[RDEditAudio::HookStart])); + } + break; + + default: + break; + } +} + + +bool RDEditAudio::PositionCursor(int cursor,bool relative) +{ + switch(edit_cue_point) { + case RDEditAudio::Start: + case RDEditAudio::TalkStart: + case RDEditAudio::HookStart: + case RDEditAudio::SegueStart: + if((edit_cursors[edit_cue_point+1]==-1)&&(cursor!=-1)) { + edit_cursors[edit_cue_point+1]=edit_cursors[RDEditAudio::End]; + edit_cursor_edit[edit_cue_point+1]-> + setText(RDGetTimeLength( + (int)(1152000.0*(double)edit_cursors[edit_cue_point+1]/ + (double)edit_sample_rate),true)); + } + if(relative) { + if((edit_cursors[edit_cue_point]+cursor/1152)> + edit_cursors[edit_cue_point+1]) { + return false; + } + if(((edit_cursors[edit_cue_point]+cursor/1152)< + edit_cursors[RDEditAudio::Start])&& + (edit_cue_point!=RDEditAudio::Start)) { + return false; + } + edit_cursors[edit_cue_point]+=cursor/1152; + cursor=edit_cursors[edit_cue_point]*1152; + } + else { + if((cursor/1152)>edit_cursors[edit_cue_point+1]) { + return false; + } + if(((cursor/1152)<edit_cursors[RDEditAudio::Start])&& + (edit_cue_point!=RDEditAudio::Start)) { + return false; + } + edit_cursors[edit_cue_point]=cursor/1152; + } + edit_cursor_edit[edit_cue_point]-> + setText(RDGetTimeLength((int)(1000.0*(double)cursor/ + (double)edit_sample_rate),true)); + edit_cae->positionPlay(edit_handle,GetTime(cursor)); + break; + + case RDEditAudio::End: + case RDEditAudio::TalkEnd: + case RDEditAudio::HookEnd: + case RDEditAudio::SegueEnd: + if((edit_cursors[edit_cue_point-1]==-1)&&(cursor!=-1)) { + edit_cursors[edit_cue_point-1]=edit_cursors[RDEditAudio::Start]; + edit_cursor_edit[edit_cue_point-1]-> + setText(RDGetTimeLength( + (int)(1152000.0*(double)edit_cursors[edit_cue_point-1]/ + (double)edit_sample_rate),true)); + } + if(relative) { + if((edit_cursors[edit_cue_point]+cursor/1152)< + edit_cursors[edit_cue_point-1]) { + return false; + } + if(((edit_cursors[edit_cue_point]+cursor/1152)> + edit_cursors[RDEditAudio::End])&& + (edit_cue_point!=RDEditAudio::End)) { + return false; + } + if((edit_cue_point==RDEditAudio::End)&& + ((1152*edit_cursors[edit_cue_point]+cursor) + >(int)edit_sample_length)) { + cursor=edit_sample_length- + 1152*edit_cursors[edit_cue_point];; + } + edit_cursors[edit_cue_point]+=cursor/1152; + cursor=edit_cursors[edit_cue_point]*1152; + } + else { + if((cursor/1152)<edit_cursors[edit_cue_point-1]) { + return false; + } + if(((cursor/1152)>edit_cursors[RDEditAudio::End])&& + (edit_cue_point!=RDEditAudio::End)) { + return false; + } + if((edit_cue_point==RDEditAudio::End)&& + (cursor>(int)edit_sample_length)) { + cursor=edit_sample_length; + } + edit_cursors[edit_cue_point]=cursor/1152; + } + if(((edit_play_mode==RDEditAudio::Region)&& + ((edit_cue_point==edit_cue_point-1)|| + (edit_cue_point==edit_cue_point)))) { + } + edit_cursor_edit[edit_cue_point]-> + setText(RDGetTimeLength((int)(1000.0*(double)cursor/ + (double)edit_sample_rate),true)); + PreRoll(cursor,edit_cue_point); + break; + + case RDEditAudio::FadeUp: + if(relative) { + if(((edit_cursors[RDEditAudio::FadeUp]+cursor/1152)> + edit_cursors[RDEditAudio::FadeDown])&& + edit_cursors[RDEditAudio::FadeDown]==-1) { + return false; + } + if((edit_cursors[edit_cue_point]+cursor/1152)< + edit_cursors[RDEditAudio::Start]) { + return false; + } + edit_cursors[RDEditAudio::FadeUp]+=cursor/1152; + cursor=edit_cursors[RDEditAudio::FadeUp]*1152; + } + else { + if(((cursor/1152)>edit_cursors[RDEditAudio::FadeDown])&& + (edit_cursors[RDEditAudio::FadeDown]!=-1)) { + return false; + } + if(((cursor/1152)<edit_cursors[RDEditAudio::Start])|| + ((cursor/1152)>edit_cursors[RDEditAudio::End])) { + return false; + } + edit_cursors[RDEditAudio::FadeUp]=cursor/1152; + } + if(((edit_play_mode==RDEditAudio::Region)&& + ((edit_cue_point==RDEditAudio::FadeUp)))) { + } + edit_cursor_edit[RDEditAudio::FadeUp]-> + setText(RDGetTimeLength((int)(1000.0*(double)cursor/ + (double)edit_sample_rate),true)); + edit_cae->positionPlay(edit_handle, + GetTime(edit_cursors[RDEditAudio::Start]*1152)); + break; + + case RDEditAudio::FadeDown: + if(relative) { + if((edit_cursors[RDEditAudio::FadeDown]+cursor/1152)< + edit_cursors[RDEditAudio::FadeUp]) { + return false; + } + if(((edit_cursors[RDEditAudio::FadeDown]+cursor/1152)< + edit_cursors[RDEditAudio::Start])|| + ((edit_cursors[RDEditAudio::FadeDown]+cursor/1152)> + edit_cursors[RDEditAudio::End])) { + return false; + } + edit_cursors[RDEditAudio::FadeDown]+=cursor/1152; + cursor=edit_cursors[RDEditAudio::FadeDown]*1152; + } + else { + if(((cursor/1152)<edit_cursors[RDEditAudio::FadeUp])) { + return false; + } + if(((cursor/1152)<edit_cursors[RDEditAudio::Start])|| + ((cursor/1152)>edit_cursors[RDEditAudio::End])) { + return false; + } + edit_cursors[RDEditAudio::FadeDown]=cursor/1152; + } + edit_cursor_edit[RDEditAudio::FadeDown]-> + setText(RDGetTimeLength((int)(1000.0*(double)cursor/ + (double)edit_sample_rate),true)); + edit_cae->positionPlay(edit_handle,GetTime(cursor)); + break; + + default: + break; + } + ValidateMarkers(); + UpdateCursors(); + UpdateCounters(); + update(0,0,11,399); + update(11+EDITAUDIO_WAVEFORM_WIDTH,0,11,399); + return true; +} + + +void RDEditAudio::ValidateMarkers() +{ + for(int i=RDEditAudio::SegueStart;i<RDEditAudio::FadeUp;i+=2) { + if(edit_cursors[i]!=-1) { + if(edit_cursors[i]<edit_cursors[RDEditAudio::Start]) { + if((edit_cursors[i+1]>=edit_cursors[RDEditAudio::Start])&& + (edit_cursors[i+1]<=edit_cursors[RDEditAudio::End])) { + edit_cursors[i]=edit_cursors[RDEditAudio::Start]; + edit_cursor_edit[i]->setText( + RDGetTimeLength((int)((double)edit_cursors[i]* + 1152000.0/(double)edit_sample_rate),true)); + } + else { + edit_cursors[i]=-1; + edit_cursors[i+1]=-1; + edit_cursor_edit[i]->clear(); + edit_cursor_edit[i+1]->clear(); + } + } + } + if(edit_cursors[i+1]!=-1) { + if(edit_cursors[i+1]>edit_cursors[RDEditAudio::End]) { + if((edit_cursors[i]>=edit_cursors[RDEditAudio::Start])&& + (edit_cursors[i]<=edit_cursors[RDEditAudio::End])) { + edit_cursors[i+1]=edit_cursors[RDEditAudio::End]; + edit_cursor_edit[i+1]->setText( + RDGetTimeLength((int)((double)edit_cursors[i+1]* + 1152000.0/(double)edit_sample_rate),true)); + } + else { + edit_cursors[i]=-1; + edit_cursors[i+1]=-1; + edit_cursor_edit[i]->clear(); + edit_cursor_edit[i+1]->clear(); + } + } + } + } + for(int i=RDEditAudio::FadeUp;i<RDEditAudio::LastMarker;i++) { + if(edit_cursors[i]!=-1) { + if(edit_cursors[i]<edit_cursors[RDEditAudio::Start]) { + edit_cursors[i]=-1; + edit_cursor_edit[i]->clear(); + } + if(edit_cursors[i]>edit_cursors[RDEditAudio::End]) { + edit_cursors[i]=-1; + edit_cursor_edit[i]->clear(); + } + } + } +} + + +bool RDEditAudio::SaveMarkers() +{ + // + // Sanity Checks + // + int start_point=(int)((double)(edit_cursors[RDEditAudio::Start])* + 1152000.0/(double)edit_sample_rate); + int end_point=(int)((double)(edit_cursors[RDEditAudio::End])* + 1152000.0/(double)edit_sample_rate)+26; + int len=(int)(1000.0*(double)edit_sample_length/(double)edit_sample_rate); + if((2*(end_point-start_point))<len) { + if(QMessageBox::question(this,tr("Marker Warning"), + tr("Less than half of the audio is playable with these marker settings.\nAre you sure you want to save?"),QMessageBox::Yes,QMessageBox::No)!=QMessageBox::Yes) { + return false; + } + } + + if(edit_cursors[RDEditAudio::SegueStart]!=-1) { + len=end_point-start_point; + start_point=(int)((double)(edit_cursors[RDEditAudio::SegueStart])* + 1152000.0/(double)edit_sample_rate); + end_point=(int)((double)(edit_cursors[RDEditAudio::SegueEnd])* + 1152000.0/(double)edit_sample_rate); + if((2*(end_point-start_point))>len) { + if(QMessageBox::question(this,tr("Marker Warning"), + tr("More than half of the audio will be faded with these marker settings.\nAre you sure you want to save?"),QMessageBox::Yes,QMessageBox::No)!=QMessageBox::Yes) { + return false; + } + } + } + + // + // Save Settings + // + edit_cut->setPlayGain(10*edit_gain_control->value()); + edit_cut->setStartPoint((int)((double)(edit_cursors[RDEditAudio::Start])* + 1152000.0/ + (double)edit_sample_rate)); + edit_cut->setEndPoint((int)((double)(edit_cursors[RDEditAudio::End])* + 1152000.0/ + (double)edit_sample_rate)+26); + if(edit_cursors[RDEditAudio::TalkStart]!=-1) { + edit_cut-> + setTalkStartPoint((int)((double)(edit_cursors[RDEditAudio::TalkStart])* + 1152000.0/ + (double)edit_sample_rate)); + } + else { + edit_cut->setTalkStartPoint(-1); + } + if(edit_cursors[RDEditAudio::TalkEnd]!=-1) { + edit_cut->setTalkEndPoint((int)((double)(edit_cursors[RDEditAudio::TalkEnd])* + 1152000.0/ + (double)edit_sample_rate)); + } + else { + edit_cut->setTalkEndPoint(-1); + } + if(edit_cursors[RDEditAudio::SegueStart]!=-1) { + edit_cut->setSegueStartPoint((int)((double)(edit_cursors[RDEditAudio::SegueStart])*1152000.0/ + (double)edit_sample_rate)); + } + else { + edit_cut->setSegueStartPoint(-1); + } + if(edit_cursors[RDEditAudio::SegueEnd]!=-1) { + edit_cut-> + setSegueEndPoint((int)((double)(edit_cursors[RDEditAudio::SegueEnd])* + 1152000.0/(double)edit_sample_rate)); + } + else { + edit_cut->setSegueEndPoint(-1); + } + if(edit_cursors[RDEditAudio::FadeUp]!=-1) { + edit_cut->setFadeupPoint((int)((double)(edit_cursors[RDEditAudio::FadeUp])*1152000.0/ + (double)edit_sample_rate)); + } + else { + edit_cut->setFadeupPoint(-1); + } + if(edit_cursors[RDEditAudio::FadeDown]!=-1) { + edit_cut-> + setFadedownPoint((int)((double)(edit_cursors[RDEditAudio::FadeDown])* + 1152000.0/(double)edit_sample_rate)); + } + else { + edit_cut->setFadedownPoint(-1); + } + if(edit_cursors[RDEditAudio::HookStart]!=-1) { + edit_cut->setHookStartPoint((int)((double)(edit_cursors[RDEditAudio::HookStart])*1152000.0/ + (double)edit_sample_rate)); + } + else { + edit_cut->setHookStartPoint(-1); + } + if(edit_cursors[RDEditAudio::HookEnd]!=-1) { + edit_cut->setHookEndPoint((int)((double)(edit_cursors[RDEditAudio::HookEnd])* + 1152000.0/ + (double)edit_sample_rate)); + } + else { + edit_cut->setHookEndPoint(-1); + } + edit_cut->setLength(edit_cut->endPoint(true)-edit_cut->startPoint(true)); + edit_cut->setPlayGain(edit_gain_control->value()); + if(edit_overlap_box->isChecked()) { + edit_cut->setSegueGain(0); + } + else { + edit_cut->setSegueGain(RD_FADE_DEPTH); + } + return true; +} + + +void RDEditAudio::LoopRegion(int cursor0,int cursor1) +{ + int length=0; + + if(cursor1!=-1) { + length=(int)(1000.0*(double)((cursor1-cursor0)* + 1152)/(double)edit_sample_rate); + } + if(cursor0==-1) { + edit_cae->positionPlay(edit_handle,0); + edit_cae-> + setOutputVolume(edit_card,edit_stream,edit_port,0+edit_gain_control->value()); + edit_cae->play(edit_handle,length,RD_TIMESCALE_DIVISOR,0); + } + else { + edit_cae->positionPlay(edit_handle,GetTime(cursor0*1152)); + edit_cae-> + setOutputVolume(edit_card,edit_stream,edit_port,0+edit_gain_control->value()); + edit_cae->play(edit_handle,length,RD_TIMESCALE_DIVISOR,0); + } +} + + +void RDEditAudio::UpdateCounters() +{ + int cursor0=0; + int cursor1=0; + bool null_region=false; + static RDEditAudio::CuePoints prev_cue_point=RDEditAudio::Play; + + edit_overall_edit->setText(RDGetTimeLength( + (int)(1000.0*(double)((edit_cursors[RDEditAudio::Play]-baseline)*1152)/ + (double)edit_sample_rate),true,true)); + if(prev_cue_point!=RDEditAudio::Play) { + edit_cursor_edit[prev_cue_point]->clearFocus(); + edit_cursor_edit[prev_cue_point]->deselect(); + } + + switch(edit_cue_point) { + case RDEditAudio::Play: + edit_play_cursor_button-> + setAccentColor(EDITAUDIO_WAVEFORM_COLOR); + edit_region_edit_label->setText(tr("<none>")); + edit_region_edit_label-> + setPalette(QPalette(backgroundColor(), + QColor(EDITAUDIO_HIGHLIGHT_COLOR))); + break; + + case RDEditAudio::Start: + cursor0=edit_cursors[RDEditAudio::Start]; + cursor1=edit_cursors[RDEditAudio::End]; + edit_play_cursor_button-> + setAccentColor(QColor(RD_START_END_MARKER_COLOR)); + edit_region_edit_label->setText(tr("Cut")); + edit_region_edit_label->setPalette(RD_START_END_MARKER_COLOR); + edit_cursor_edit[RDEditAudio::Start]->setFocus(); + edit_cursor_edit[RDEditAudio::Start]->selectAll(); + break; + + case RDEditAudio::End: + cursor0=edit_cursors[RDEditAudio::Start]; + cursor1=edit_cursors[RDEditAudio::End]; + edit_play_cursor_button-> + setAccentColor(QColor(RD_START_END_MARKER_COLOR)); + edit_region_edit_label->setText(tr("Cut")); + edit_region_edit_label->setPalette(RD_START_END_MARKER_COLOR); + edit_cursor_edit[RDEditAudio::End]->setFocus(); + edit_cursor_edit[RDEditAudio::End]->selectAll(); + break; + + case RDEditAudio::TalkStart: + cursor0=edit_cursors[RDEditAudio::TalkStart]; + cursor1=edit_cursors[RDEditAudio::TalkEnd]; + edit_play_cursor_button->setAccentColor(QColor(RD_TALK_MARKER_COLOR)); + edit_region_edit_label->setText(tr("Talk")); + edit_region_edit_label->setPalette(RD_TALK_MARKER_COLOR); + edit_cursor_edit[RDEditAudio::TalkStart]->setFocus(); + edit_cursor_edit[RDEditAudio::TalkStart]->selectAll(); + break; + + case RDEditAudio::TalkEnd: + cursor0=edit_cursors[RDEditAudio::TalkStart]; + cursor1=edit_cursors[RDEditAudio::TalkEnd]; + edit_play_cursor_button->setAccentColor(QColor(RD_TALK_MARKER_COLOR)); + edit_region_edit_label->setText(tr("Talk")); + edit_region_edit_label->setPalette(RD_TALK_MARKER_COLOR); + edit_cursor_edit[RDEditAudio::TalkEnd]->setFocus(); + edit_cursor_edit[RDEditAudio::TalkEnd]->selectAll(); + break; + + case RDEditAudio::SegueStart: + cursor0=edit_cursors[RDEditAudio::SegueStart]; + cursor1=edit_cursors[RDEditAudio::SegueEnd]; + edit_play_cursor_button->setAccentColor(QColor(RD_SEGUE_MARKER_COLOR)); + edit_region_edit_label->setText(tr("Segue")); + edit_region_edit_label->setPalette(RD_SEGUE_MARKER_COLOR); + edit_cursor_edit[RDEditAudio::SegueStart]->setFocus(); + edit_cursor_edit[RDEditAudio::SegueStart]->selectAll(); + break; + + case RDEditAudio::SegueEnd: + cursor0=edit_cursors[RDEditAudio::SegueStart]; + cursor1=edit_cursors[RDEditAudio::SegueEnd]; + edit_play_cursor_button->setAccentColor(QColor(RD_SEGUE_MARKER_COLOR)); + edit_region_edit_label->setText(tr("Segue")); + edit_region_edit_label->setPalette(RD_SEGUE_MARKER_COLOR); + edit_cursor_edit[RDEditAudio::SegueEnd]->setFocus(); + edit_cursor_edit[RDEditAudio::SegueEnd]->selectAll(); + break; + + case RDEditAudio::HookStart: + cursor0=edit_cursors[RDEditAudio::HookStart]; + cursor1=edit_cursors[RDEditAudio::HookEnd]; + edit_play_cursor_button->setAccentColor(QColor(RD_HOOK_MARKER_COLOR)); + edit_region_edit_label->setText(tr("Hook")); + edit_region_edit_label->setPalette(RD_HOOK_MARKER_COLOR); + edit_cursor_edit[RDEditAudio::HookStart]->setFocus(); + edit_cursor_edit[RDEditAudio::HookStart]->selectAll(); + break; + + case RDEditAudio::HookEnd: + cursor0=edit_cursors[RDEditAudio::HookStart]; + cursor1=edit_cursors[RDEditAudio::HookEnd]; + edit_play_cursor_button->setAccentColor(QColor(RD_HOOK_MARKER_COLOR)); + edit_region_edit_label->setText(tr("Hook")); + edit_region_edit_label->setPalette(RD_HOOK_MARKER_COLOR); + edit_cursor_edit[RDEditAudio::HookEnd]->setFocus(); + edit_cursor_edit[RDEditAudio::HookEnd]->selectAll(); + break; + + case RDEditAudio::FadeUp: + cursor0=edit_cursors[RDEditAudio::Start]; + cursor1=edit_cursors[RDEditAudio::FadeUp]; + edit_play_cursor_button->setAccentColor(QColor(RD_FADE_MARKER_COLOR)); + edit_region_edit_label->setText(tr("Fade Up")); + edit_region_edit_label->setPalette(RD_FADE_MARKER_COLOR); + edit_cursor_edit[RDEditAudio::FadeUp]->setFocus(); + edit_cursor_edit[RDEditAudio::FadeUp]->selectAll(); + break; + + case RDEditAudio::FadeDown: + cursor0=edit_cursors[RDEditAudio::FadeDown]; + cursor1=edit_cursors[RDEditAudio::End]; + edit_play_cursor_button->setAccentColor(QColor(RD_FADE_MARKER_COLOR)); + edit_region_edit_label->setText(tr("Fade Down")); + edit_region_edit_label->setPalette(RD_FADE_MARKER_COLOR); + edit_cursor_edit[RDEditAudio::FadeDown]->setFocus(); + edit_cursor_edit[RDEditAudio::FadeDown]->selectAll(); + break; + + case RDEditAudio::LastMarker: + break; + } + if(cursor0==-1) { + cursor0=0; + null_region=true; + } + if(cursor1==-1) { + cursor1=edit_sample_length/1152; + null_region=true; + } + if(null_region||(edit_cue_point==RDEditAudio::Play)) { + edit_region_edit->setText("0:00:00.0"); + edit_region_edit->setDisabled(true); + } + else { + edit_region_edit->setText(RDGetTimeLength( + (int)(1000.0*(double)((cursor1-cursor0)*1152)/ + (double)edit_sample_rate),true,true)); + edit_region_edit->setEnabled(true); + } + edit_size_edit->setText(RDGetTimeLength( + (int)(1000.0*(double)((edit_cursors[RDEditAudio::End]- + edit_cursors[RDEditAudio::Start])*1152)/ + (double)edit_sample_rate),true,true)); + prev_cue_point=edit_cue_point; +} + + +void RDEditAudio::DrawMaps() +{ + QPixmap *pix=NULL; + + if(edit_channels==1) { + pix=new QPixmap(EDITAUDIO_WAVEFORM_WIDTH,EDITAUDIO_WAVEFORM_HEIGHT); + DrawWave(EDITAUDIO_WAVEFORM_WIDTH,EDITAUDIO_WAVEFORM_HEIGHT,0,"",pix); + edit_left_image=pix->convertToImage(); + delete pix; + } + if(edit_channels==2) { + pix=new QPixmap(EDITAUDIO_WAVEFORM_WIDTH,EDITAUDIO_WAVEFORM_HEIGHT/2); + DrawWave(EDITAUDIO_WAVEFORM_WIDTH,EDITAUDIO_WAVEFORM_HEIGHT/2,0,tr("L"), + pix); + edit_left_image=pix->convertToImage(); + DrawWave(EDITAUDIO_WAVEFORM_WIDTH,EDITAUDIO_WAVEFORM_HEIGHT/2,1,tr("R"), + pix); + edit_right_image=pix->convertToImage(); + delete pix; + } +} + + +void RDEditAudio::UpdateCursors() +{ + if(edit_channels==1) { + DrawCursors(11,11,EDITAUDIO_WAVEFORM_WIDTH,EDITAUDIO_WAVEFORM_HEIGHT,0); + } + if(edit_channels==2) { + DrawCursors(11,11,EDITAUDIO_WAVEFORM_WIDTH,EDITAUDIO_WAVEFORM_HEIGHT/2,0); + DrawCursors(11,11+EDITAUDIO_WAVEFORM_HEIGHT/2,EDITAUDIO_WAVEFORM_WIDTH, + EDITAUDIO_WAVEFORM_HEIGHT/2,1); + } + +} + + +void RDEditAudio::DrawCursors(int xpos,int ypos,int xsize,int ysize,int chan) +{ + static int prev_x[2][12]={{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}, + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}}; + + EraseCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::Play],prev_x[chan][RDEditAudio::Play], + QColor(EDITAUDIO_PLAY_COLOR),RDEditAudio::None,20); + + EraseCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::SegueStart], + prev_x[chan][RDEditAudio::SegueStart], + QColor(RD_SEGUE_MARKER_COLOR), + RDEditAudio::Right,30); + + EraseCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::SegueEnd], + prev_x[chan][RDEditAudio::SegueEnd], + QColor(RD_SEGUE_MARKER_COLOR), + RDEditAudio::Left,30); + + EraseCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::Start], + prev_x[chan][RDEditAudio::Start], + QColor(RD_START_END_MARKER_COLOR), + RDEditAudio::Right,10); + + EraseCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::End], + prev_x[chan][RDEditAudio::End], + QColor(RD_START_END_MARKER_COLOR), + RDEditAudio::Left,10); + + EraseCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::TalkStart], + prev_x[chan][RDEditAudio::TalkStart], + QColor(RD_TALK_MARKER_COLOR), + RDEditAudio::Right,20); + + EraseCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::TalkEnd], + prev_x[chan][RDEditAudio::TalkEnd], + QColor(RD_TALK_MARKER_COLOR), + RDEditAudio::Left,20); + + EraseCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::FadeUp], + prev_x[chan][RDEditAudio::FadeUp], + QColor(RD_FADE_MARKER_COLOR), + RDEditAudio::Left,40); + + EraseCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::FadeDown], + prev_x[chan][RDEditAudio::FadeDown], + QColor(RD_FADE_MARKER_COLOR), + RDEditAudio::Right,40); + + EraseCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::HookStart], + prev_x[chan][RDEditAudio::HookStart], + QColor(RD_HOOK_MARKER_COLOR), + RDEditAudio::Right,50); + + EraseCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::HookEnd], + prev_x[chan][RDEditAudio::HookEnd], + QColor(RD_HOOK_MARKER_COLOR), + RDEditAudio::Left,50); + + + prev_x[chan][RDEditAudio::Play]=DrawCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::Play], + prev_x[chan][RDEditAudio::Play], + QColor(EDITAUDIO_PLAY_COLOR), + RDEditAudio::None,20,RDEditAudio::Play, + Qt::XorROP); + + prev_x[chan][RDEditAudio::SegueStart]=DrawCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::SegueStart], + prev_x[chan][RDEditAudio::SegueStart], + QColor(RD_SEGUE_MARKER_COLOR), + RDEditAudio::Right,30, + RDEditAudio::SegueStart); + + prev_x[chan][RDEditAudio::SegueEnd]=DrawCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::SegueEnd], + prev_x[chan][RDEditAudio::SegueEnd], + QColor(RD_SEGUE_MARKER_COLOR), + RDEditAudio::Left,30, + RDEditAudio::SegueEnd); + + prev_x[chan][RDEditAudio::Start]=DrawCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::Start], + prev_x[chan][RDEditAudio::Start], + QColor(RD_START_END_MARKER_COLOR), + RDEditAudio::Right,10, + RDEditAudio::Start); + + prev_x[chan][RDEditAudio::End]=DrawCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::End], + prev_x[chan][RDEditAudio::End], + QColor(RD_START_END_MARKER_COLOR), + RDEditAudio::Left,10, + RDEditAudio::End); + + prev_x[chan][RDEditAudio::TalkStart]=DrawCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::TalkStart], + prev_x[chan][RDEditAudio::TalkStart], + QColor(RD_TALK_MARKER_COLOR), + RDEditAudio::Right,20, + RDEditAudio::TalkStart); + + prev_x[chan][RDEditAudio::TalkEnd]=DrawCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::TalkEnd], + prev_x[chan][RDEditAudio::TalkEnd], + QColor(RD_TALK_MARKER_COLOR), + RDEditAudio::Left,20, + RDEditAudio::TalkEnd); + + prev_x[chan][RDEditAudio::FadeUp]=DrawCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::FadeUp], + prev_x[chan][RDEditAudio::FadeUp], + QColor(RD_FADE_MARKER_COLOR), + RDEditAudio::Left,40, + RDEditAudio::FadeUp); + + prev_x[chan][RDEditAudio::FadeDown]=DrawCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::FadeDown], + prev_x[chan][RDEditAudio::FadeDown], + QColor(RD_FADE_MARKER_COLOR), + RDEditAudio::Right,40, + RDEditAudio::FadeDown); + + prev_x[chan][RDEditAudio::HookStart]=DrawCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::HookStart], + prev_x[chan][RDEditAudio::HookStart], + QColor(RD_HOOK_MARKER_COLOR), + RDEditAudio::Right,50, + RDEditAudio::HookStart); + + prev_x[chan][RDEditAudio::HookEnd]=DrawCursor(xpos,ypos,xsize,ysize,chan, + edit_cursors[RDEditAudio::HookEnd], + prev_x[chan][RDEditAudio::HookEnd], + QColor(RD_HOOK_MARKER_COLOR), + RDEditAudio::Left,50, + RDEditAudio::HookEnd); +} + + +int RDEditAudio::DrawCursor(int xpos,int ypos,int xsize,int ysize,int chan, + int samp,int prev,QColor color,Arrow arrow,int apos, + RDEditAudio::CuePoints pt,Qt::RasterOp op) +{ + int x; + QPointArray *point; + + if(samp<0) { + return 0; + } + x=(int)((double)(samp-edit_hscroll->value())/edit_factor_x); + if((x!=prev)||(pt!=RDEditAudio::Play)) { + QPainter *p=new QPainter(this); + p->setClipRect(xpos,ypos,xsize,ysize); + p->setRasterOp(op); + p->translate(xpos,ypos); + if((x>=0)&(x<EDITAUDIO_WAVEFORM_WIDTH)) { + p->setPen(color); + p->moveTo(x,0); + p->lineTo(x,ysize); + if(arrow==RDEditAudio::Left) { + p->setClipRect(0,0,xsize+xpos+10,ysize+ypos); + p->setBrush(color); + point=new QPointArray(3); + point->setPoint(0,x,apos); + point->setPoint(1,x+10,apos-5); + point->setPoint(2,x+10,apos+5); + p->drawPolygon(*point); + point->setPoint(0,x,ysize-apos); + point->setPoint(1,x+10,ysize-apos-5); + point->setPoint(2,x+10,ysize-apos+5); + p->drawPolygon(*point); + delete point; + } + if(arrow==RDEditAudio::Right) { + p->setClipRect(-10,0,xsize+10,ysize+ypos); + p->setBrush(color); + point=new QPointArray(3); + point->setPoint(0,x,apos); + point->setPoint(1,x-10,apos-5); + point->setPoint(2,x-10,apos+5); + p->drawPolygon(*point); + point->setPoint(0,x,ysize-apos); + point->setPoint(1,x-10,ysize-apos-5); + point->setPoint(2,x-10,ysize-apos+5); + p->drawPolygon(*point); + delete point; + } + } + p->end(); + delete p; + } + return x; +} + + +void RDEditAudio::EraseCursor(int xpos,int ypos,int xsize,int ysize,int chan, + int samp,int prev,QColor color,Arrow arrow,int apos) +{ + int x; + + if(edit_hscroll==NULL) { + return; + } + x=(int)((double)(samp-edit_hscroll->value())/edit_factor_x); + if(x!=prev) { + QPainter *p=new QPainter(this); + p->translate(xpos,ypos); + if((prev>=0)&&(prev<EDITAUDIO_WAVEFORM_WIDTH)&&(prev!=x)) { + if(chan==0) { + p->drawImage(prev,0,edit_left_image,prev,0,1,ysize); + if(arrow==RDEditAudio::Left) { + p->drawImage(prev,apos-5,edit_left_image,prev,apos-5,11,25); + p->drawImage(prev,ysize-apos-5,edit_left_image,prev,ysize-apos-5, + 11,25); + p->fillRect(xsize,0,10,ysize,QBrush(backgroundColor())); + } + if(arrow==RDEditAudio::Right) { + p->drawImage(prev-11,apos-5,edit_left_image,prev-11,apos-5,11,25); + p->drawImage(prev-11,ysize-apos-5,edit_left_image,prev-11,ysize-apos-5, + 11,25); + p->fillRect(-10,0,10,ysize,QBrush(backgroundColor())); + } + } + if(chan==1) { + p->drawImage(prev,0,edit_right_image,prev,0,1,ysize); + if(arrow==RDEditAudio::Left) { + p->drawImage(prev,apos-5,edit_right_image,prev,apos-5,11,25); + p->drawImage(prev,ysize-apos-5,edit_right_image,prev, + ysize-apos-5,11,25); + p->fillRect(xsize,0,10,ysize,QBrush(backgroundColor())); + } + if(arrow==RDEditAudio::Right) { + p->drawImage(prev-11,apos-5,edit_right_image,prev-11,apos-5,11,25); + p->drawImage(prev-11,ysize-apos-5,edit_right_image,prev-11, + ysize-apos-5,11,25); + p->fillRect(-10,0,10,ysize,QBrush(backgroundColor())); + } + } + } + p->end(); + delete p; + } +} + + +void RDEditAudio::DrawWave(int xsize,int ysize,int chan,QString label, + QPixmap *pix) +{ + unsigned offset; + unsigned origin_x; + int ref_line; + + if(edit_factor_x>1) { + origin_x=(edit_hscroll->value()/(unsigned)edit_factor_x)* + (unsigned)edit_factor_x; + } + else { + origin_x=edit_hscroll->value();; + } + QPainter *p=new QPainter(pix); + p->eraseRect(0,0,xsize,ysize); + p->drawRect(0,0,xsize,ysize); + + int vert=ysize/2; + double size_y=pow(10,(-((double)edit_gain)/20.0)); + ref_line=int(size_y*ysize*pow(10.0,-(double)REFERENCE_LEVEL/2000.0- + (double)edit_gain_control->value()/2000.0)/2.0); + + // + // Grayed-Out Area + // + for(int i=1;i<(xsize-3);i++) { + offset=(unsigned)((double)i*edit_factor_x* + (double)edit_channels+ + (double)edit_channels* + (double)origin_x); + if(offset>=edit_peaks->energySize()) { + // if(offset>=edit_wave->energySize()) { + p->fillRect(i,1,xsize-i,ysize-2, + QBrush(QColor(EDITAUDIO_HIGHLIGHT_COLOR))); + continue; + } + } + + // + // Reference Level Lines + // + p->setPen(QColor(red)); + p->moveTo(0,vert+ref_line); + p->lineTo(xsize,vert+ref_line); + p->moveTo(0,vert-ref_line); + p->lineTo(xsize,vert-ref_line); + + p->translate(1,ysize/2); + if(edit_peaks->energySize()>0) { + // if(edit_wave->energySize()>0) { + + // + // Time Tick Marks + // + p->setFont(QFont("Helvetica",8,QFont::Normal)); + for(unsigned i=0;i<2*edit_peaks->energySize(); + i+=(int)(edit_factor_x*(double)edit_sample_rate/576.0)) { + offset=(int)((double)(i-origin_x)/edit_factor_x); + if((offset>0)&&(offset<(EDITAUDIO_WAVEFORM_WIDTH-2))) { + p->setPen(QColor(green)); + p->moveTo(offset,-ysize/2); + p->lineTo(offset,ysize/2); + p->setPen(QColor(red)); + p->drawText(offset+3,ysize/2-4, + RDGetTimeLength((int)((1152000.0*(double)i)/ + (double)edit_sample_rate+1000.0), + false,edit_factor_x<0.5)); + } + } + + double size_y=pow(10,(-((double)edit_gain)/20.0)); + + // + // Waveform + // + p->setPen(QColor(EDITAUDIO_WAVEFORM_COLOR)); + p->setBrush(QColor(EDITAUDIO_WAVEFORM_COLOR)); + edit_wave_array->setPoint(0,0,0); + for(int i=1;i<(xsize-3);i++) { + offset=(unsigned)((double)i*edit_factor_x* + (double)edit_channels+ + (double)edit_channels* + (double)origin_x+(double)chan); + if(offset<edit_peaks->energySize()) { + edit_wave_array->setPoint(i,i+(int)((double)chan/(2.0*edit_factor_x)), + (int)(edit_peaks->energy(offset)*ysize* + size_y/65534)); + } + else { + edit_wave_array->setPoint(i,i,0); + } + } + edit_wave_array->setPoint(xsize-3,xsize-3,0); + p->drawPolygon(*edit_wave_array); + + edit_wave_array->setPoint(0,0,0); + for(int i=1;i<(xsize-3);i++) { + offset=(unsigned)((double)i*edit_factor_x* + (double)edit_channels+ + (double)edit_channels* + (double)origin_x+(double)chan); + if(offset<edit_peaks->energySize()) { + edit_wave_array->setPoint(i,i+(int)((double)chan/(2.0*edit_factor_x)), + (int)(-edit_peaks->energy(offset)* + ysize*size_y/65534)); + } + else { + edit_wave_array->setPoint(i,i,0); + } + } + edit_wave_array->setPoint(xsize-3,xsize-3,0); + p->drawPolygon(*edit_wave_array); + + p->setPen(QColor(red)); + if(!label.isEmpty()) { + p->setFont(QFont("Helvetica",24,QFont::Normal)); + p->drawText(10,28-ysize/2,label); + } + p->setPen(QColor(black)); + p->moveTo(0,0); + p->lineTo(xsize-3,0); + } + else { + p->setFont(QFont("Helvetica",24,QFont::Bold)); + p->drawText(270,0,"No Energy Data"); + } + p->end(); + delete p; +} + + +void RDEditAudio::DrawPointers() +{ + edit_arrow_cursor=new QCursor(Qt::ArrowCursor); + edit_cross_cursor=new QCursor(Qt::CrossCursor); +} + + +void RDEditAudio::CenterDisplay() +{ + edit_hscroll-> + setValue((int)(edit_cursors[RDEditAudio::Play]-EDITAUDIO_WAVEFORM_WIDTH/2*edit_factor_x)); +} + + +int RDEditAudio::GetTime(int samples) +{ + if(samples>(int)edit_sample_length) { + return -1; + } + return (int)(1000.0f*(double)samples/(double)edit_sample_rate); +} diff --git a/lib/rdedit_audio.h b/lib/rdedit_audio.h new file mode 100644 index 00000000..5e079de1 --- /dev/null +++ b/lib/rdedit_audio.h @@ -0,0 +1,231 @@ +// rdedit_audio.h +// +// Edit Rivendell Audio +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdedit_audio.h,v 1.9.6.2 2013/11/13 23:36:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDEDIT_AUDIO_H +#define RDEDIT_AUDIO_H + +#include <qdialog.h> +#include <qscrollbar.h> +#include <qpixmap.h> +#include <qimage.h> +#include <qlineedit.h> +#include <qpointarray.h> +#include <qcursor.h> +#include <qpopupmenu.h> +#include <qlabel.h> +#include <qspinbox.h> +#include <qtimer.h> +#include <qnamespace.h> +#include <qcheckbox.h> + +#include <rdconfig.h> +#include <rdmarker_edit.h> +#include <rdtransportbutton.h> +#include <rdstereometer.h> +#include <rdwavefile.h> +#include <rdpushbutton.h> +#include <rdmarker_button.h> +#include <rdcart.h> +#include <rdcut.h> +#include <rdcae.h> +#include <rduser.h> +#include <rdstation.h> +#include <rdpeaksexport.h> + +// +// Widget Settings +// +#define EDITAUDIO_WIDGET_WIDTH 834 +#define EDITAUDIO_WIDGET_HEIGHT 680 +#define EDITAUDIO_WAVEFORM_WIDTH 717 +#define EDITAUDIO_WAVEFORM_HEIGHT 352 +#define EDITAUDIO_PAN_SIZE 300 +#define EDITAUDIO_TAIL_PREROLL 1500 +#define EDITAUDIO_DEFAULT_GAIN -12 +#define EDITAUDIO_BUTTON_FLASH_PERIOD 200 +#define EDITAUDIO_START_GAP 10 + +// +// Widget Colors +// +#define EDITAUDIO_PLAY_COLOR white +#define EDITAUDIO_REMOVE_FLASH_COLOR blue +#define EDITAUDIO_WAVEFORM_COLOR black +#define EDITAUDIO_HIGHLIGHT_COLOR colorGroup().mid() + +class RDEditAudio : public QDialog +{ + Q_OBJECT + public: + RDEditAudio(RDCart *cart,QString cut_name,RDCae *cae,RDUser *user, + RDStation *station,RDConfig *config,int card,int port, + int preroll,int trim_level, + QWidget *parent=0,const char *name=0); + ~RDEditAudio(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void saveData(); + void cancelData(); + void xFullIn(); + void xUp(); + void xDown(); + void xFullOut(); + void yUp(); + void yDown(); + void gotoCursorData(); + void gotoHomeData(); + void gotoEndData(); + void hscrollData(int); + void playStartData(); + void playCursorData(); + void pauseData(); + void stopData(); + void loopData(); + void playedData(int handle); + void pausedData(int handle); + void positionData(int handle,unsigned pos); + void cuePointData(int); + void cueEditData(int); + void cueEscData(int); + void updateMenuData(); + void deleteSegueData(); + void deleteFadeupData(); + void deleteFadedownData(); + void deleteTalkData(); + void deleteHookData(); + void trimHeadData(); + void trimTailData(); + void gainUpPressedData(); + void gainDownPressedData(); + void gainChangedData(); + void gainReleasedData(); + void gainTimerData(); + void removeButtonData(); + void meterData(); + + protected: + void paintEvent(QPaintEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void keyPressEvent(QKeyEvent *e); + void closeEvent(QCloseEvent *e); + + private: + enum CuePoints {Play=0,Start=1,End=2,SegueStart=3,SegueEnd=4, + TalkStart=5,TalkEnd=6,HookStart=7,HookEnd=8, + FadeUp=9,FadeDown=10,LastMarker=11}; + enum Arrow {None=0,Left=1,Right=2}; + enum PlayMode {FromStart=1,FromCursor=2,Region=3}; + enum GainChange {GainNone=0,GainUp=1,GainDown=2}; + void DeleteMarkerData(int id); + void PreRoll(int cursor,RDEditAudio::CuePoints); + bool PositionCursor(int cursor=0,bool relative=false); + void ValidateMarkers(); + bool SaveMarkers(); + void LoopRegion(int cursor0,int cursor1); + void UpdateCounters(); + void DrawMaps(); + void UpdateCursors(); + void DrawCursors(int xpos,int ypos,int xsize,int ysize,int chan); + int DrawCursor(int xpos,int ypos,int xsize,int ysize,int chan, + int samp,int prev,QColor color,Arrow arrow,int apos, + RDEditAudio::CuePoints pt,Qt::RasterOp op=Qt::CopyROP); + void EraseCursor(int xpos,int ypos,int xsize,int ysize,int chan, + int samp,int prev,QColor color,Arrow arrow,int apos); + void DrawWave(int xsize,int ysize,int chan,QString label,QPixmap *pix); + void DrawPointers(); + void CenterDisplay(); + int GetTime(int samples); + RDCut *edit_cut; + RDPeaksExport *edit_peaks; + unsigned edit_sample_rate; + unsigned edit_sample_length; + unsigned edit_channels; + QPopupMenu *edit_menu; + QScrollBar *edit_hscroll; + QImage edit_left_ref_image; + QImage edit_right_ref_image; + QImage edit_left_image; + QImage edit_right_image; + QLineEdit *edit_overall_edit; + QLineEdit *edit_region_edit; + QLabel *edit_region_edit_label; + QLineEdit *edit_size_edit; + RDMarkerEdit *edit_cursor_edit[RDEditAudio::LastMarker]; + QCursor *edit_arrow_cursor; + QCursor *edit_cross_cursor; + QPointArray *edit_wave_array; + QSpinBox *edit_trim_box; + RDMarkerButton *edit_cue_button[RDEditAudio::LastMarker]; + QString edit_cue_string; + RDPushButton *edit_remove_button; + QCheckBox *edit_overlap_box; + RDTransportButton *edit_loop_button; + RDTransportButton *edit_play_start_button; + RDTransportButton *edit_play_cursor_button; + RDTransportButton *edit_pause_button; + RDTransportButton *edit_stop_button; + RDStereoMeter *edit_meter; + QRangeControl *edit_gain_control; + RDMarkerEdit *edit_gain_edit; + QTimer *edit_gain_timer; + QTimer *edit_meter_timer; + GainChange edit_gain_mode; + int edit_gain_count; + CuePoints edit_cue_point; + PlayMode edit_play_mode; + unsigned short *edit_energy; + int edit_energy_size; + double edit_factor_x; + double edit_max_factor_x; + int edit_gain; + bool is_playing; + bool is_paused; + bool is_stopped; + bool use_looping; + bool is_looping; + bool left_button_pressed; + bool center_button_pressed; + bool delete_marker; + bool pause_mode; + int baseline; + int played_cursor; + int edit_cursors[RDEditAudio::LastMarker]; + short *energy_data; + int energy_size; + bool ignore_pause; + int edit_handle; + int edit_card; + int edit_stream; + int edit_port; + int edit_preroll; + RDCae *edit_cae; + RDStation *edit_station; + RDUser *edit_user; + RDConfig *edit_config; +}; + + +#endif // RDEDIT_AUDIO_H diff --git a/lib/rdedit_panel_name.cpp b/lib/rdedit_panel_name.cpp new file mode 100644 index 00000000..8732f991 --- /dev/null +++ b/lib/rdedit_panel_name.cpp @@ -0,0 +1,108 @@ +// rdedit_panel_name.cpp +// +// Edit a SoundPanel Panel Name +// +// (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdedit_panel_name.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qlabel.h> +#include <qpushbutton.h> + +#include <rdedit_panel_name.h> + + +RDEditPanelName::RDEditPanelName(QString *panelname, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + panel_name=panelname; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Edit Panel Name")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Panel Name + // + panel_name_edit=new QLineEdit(this,"panel_name_edit"); + panel_name_edit->setGeometry(95,11,sizeHint().width()-105,19); + panel_name_edit->setMaxLength(64); + panel_name_edit->setText(*panel_name); + panel_name_edit->selectAll(); + QLabel *panel_name_label=new QLabel(panel_name_edit,tr("Panel &Name:"),this, + "panel_name_label"); + panel_name_label->setGeometry(10,13,80,19); + panel_name_label->setFont(font); + panel_name_label->setAlignment(AlignRight|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,45,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,45,80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +QSize RDEditPanelName::sizeHint() const +{ + return QSize(400,110); +} + + +QSizePolicy RDEditPanelName::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDEditPanelName::okData() +{ + *panel_name=panel_name_edit->text(); + done(0); +} + + +void RDEditPanelName::cancelData() +{ + done(-1); +} diff --git a/lib/rdedit_panel_name.h b/lib/rdedit_panel_name.h new file mode 100644 index 00000000..003ebaaf --- /dev/null +++ b/lib/rdedit_panel_name.h @@ -0,0 +1,48 @@ +// rdedit_panel_name.h +// +// Edit a SoundPanel Panel Name +// +// (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdedit_panel_name.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDEDIT_PANEL_NAME_H +#define RDEDIT_PANEL_NAME_H + +#include <qdialog.h> +#include <qlineedit.h> + + +class RDEditPanelName : public QDialog +{ + Q_OBJECT + public: + RDEditPanelName(QString *panelname,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *panel_name_edit; + QString *panel_name; +}; + + +#endif // RDEDIT_PANEL_NAME diff --git a/lib/rdemptycart.cpp b/lib/rdemptycart.cpp new file mode 100644 index 00000000..6ac30586 --- /dev/null +++ b/lib/rdemptycart.cpp @@ -0,0 +1,63 @@ +// rdemptycart.cpp +// +// A drag source for an empty cart. +// +// (C) Copyright 2013 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdemptycart.cpp,v 1.1.2.2 2014/01/20 19:13:29 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include <rdemptycart.h> + +// +// Icons +// +#include "../icons/trashcan-32x32.xpm" + +RDEmptyCart::RDEmptyCart(QWidget *parent,const char *name) + : QWidget(parent,name) +{ + empty_label=new QLabel(this); + empty_label->setPixmap(QPixmap(trashcan_xpm)); + empty_label->setGeometry(0,0,32,32); +} + + +RDEmptyCart::~RDEmptyCart() +{ + delete empty_label; +} + + +QSize RDEmptyCart::sizeHint() const +{ + return QSize(32,32); +} + + +QSizePolicy RDEmptyCart::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDEmptyCart::mousePressEvent(QMouseEvent *e) +{ + QWidget::mousePressEvent(e); + RDCartDrag *d=new RDCartDrag(0,"",QColor(),this); + d->dragCopy(); +} diff --git a/lib/rdemptycart.h b/lib/rdemptycart.h new file mode 100644 index 00000000..d28138ce --- /dev/null +++ b/lib/rdemptycart.h @@ -0,0 +1,49 @@ +// rdemptycart.h +// +// A drag source for an empty cart. +// +// (C) Copyright 2013 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdemptycart.h,v 1.1.2.1 2013/12/30 20:37:01 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDEMPTYCART_H +#define RDEMPTYCART_H + +#include <qlabel.h> +#include <qwidget.h> + +#include <rdcartdrag.h> + +class RDEmptyCart : public QWidget +{ + Q_OBJECT + public: + RDEmptyCart(QWidget *parent=0,const char *name=0); + ~RDEmptyCart(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + void mousePressEvent(QMouseEvent *e); + + private: + QLabel *empty_label; +}; + + +#endif // RDEMPTYCART_H diff --git a/lib/rdencoder.cpp b/lib/rdencoder.cpp new file mode 100644 index 00000000..c4b360bd --- /dev/null +++ b/lib/rdencoder.cpp @@ -0,0 +1,142 @@ +// rdencoder.cpp +// +// Abstract a Rivendell Custom Encoder +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdencoder.cpp,v 1.1 2008/09/18 19:02:07 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdencoder.h> + +RDEncoder::RDEncoder() +{ + clear(); +} + + +QString RDEncoder::name() const +{ + return encoder_name; +} + + +void RDEncoder::setName(const QString &str) +{ + encoder_name=str; +} + + +int RDEncoder::id() const +{ + return encoder_id; +} + + +void RDEncoder::setId(int id) +{ + encoder_id=id; +} + + +QString RDEncoder::commandLine() const +{ + return encoder_command_line; +} + + +void RDEncoder::setCommandLine(const QString &str) +{ + encoder_command_line=str; +} + + +QString RDEncoder::defaultExtension() const +{ + return encoder_default_extension; +} + + +void RDEncoder::setDefaultExtension(const QString &str) +{ + encoder_default_extension=str; +} + + +int RDEncoder::allowedChannelsQuantity() const +{ + return encoder_channels.size(); +} + + +int RDEncoder::allowedChannel(unsigned n) +{ + return encoder_channels[n]; +} + + +void RDEncoder::addAllowedChannel(int val) +{ + encoder_channels.push_back(val); +} + + +int RDEncoder::allowedSampleratesQuantity() const +{ + return encoder_samplerates.size(); +} + + +int RDEncoder::allowedSamplerate(unsigned n) +{ + return encoder_samplerates[n]; +} + + +void RDEncoder::addAllowedSamplerate(int val) +{ + encoder_samplerates.push_back(val); +} + + +int RDEncoder::allowedBitratesQuantity() const +{ + return encoder_bitrates.size(); +} + + +int RDEncoder::allowedBitrate(unsigned n) +{ + return encoder_bitrates[n]; +} + + +void RDEncoder::addAllowedBitrate(int val) +{ + encoder_bitrates.push_back(val); +} + + +void RDEncoder::clear() +{ + encoder_name=""; + encoder_id=-1; + encoder_command_line=""; + encoder_default_extension=""; + encoder_channels.clear(); + encoder_samplerates.clear(); + encoder_bitrates.clear(); +} diff --git a/lib/rdencoder.h b/lib/rdencoder.h new file mode 100644 index 00000000..95b450b0 --- /dev/null +++ b/lib/rdencoder.h @@ -0,0 +1,64 @@ +// rdencoder.h +// +// Abstract a Rivendell Custom Encoder +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdencoder.h,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDENCODER_H +#define RDENCODER_H + +#include <vector> + +#include <qstring.h> + +class RDEncoder +{ + public: + RDEncoder(); + QString name() const; + void setName(const QString &str); + int id() const; + void setId(int id); + QString commandLine() const; + void setCommandLine(const QString &str); + QString defaultExtension() const; + void setDefaultExtension(const QString &str); + int allowedChannelsQuantity() const; + int allowedChannel(unsigned n); + void addAllowedChannel(int val); + int allowedSampleratesQuantity() const; + int allowedSamplerate(unsigned n); + void addAllowedSamplerate(int val); + int allowedBitratesQuantity() const; + int allowedBitrate(unsigned n); + void addAllowedBitrate(int val); + void clear(); + + private: + QString encoder_name; + int encoder_id; + QString encoder_command_line; + QString encoder_default_extension; + std::vector<int> encoder_channels; + std::vector<int> encoder_samplerates; + std::vector<int> encoder_bitrates; +}; + + +#endif // RDENCODER_H diff --git a/lib/rdencoderlist.cpp b/lib/rdencoderlist.cpp new file mode 100644 index 00000000..41fe2f74 --- /dev/null +++ b/lib/rdencoderlist.cpp @@ -0,0 +1,90 @@ +// rdencoderlist.cpp +// +// Abstract a Rivendell Custom Encoder +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdencoderlist.cpp,v 1.1 2008/09/18 19:02:07 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdescape_string.h> +#include <rddb.h> +#include <rdencoderlist.h> + +RDEncoderList::RDEncoderList(const QString &stationname) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + sql=QString().sprintf("select ID,NAME,DEFAULT_EXTENSION,COMMAND_LINE \ + from ENCODERS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(stationname)); + q=new RDSqlQuery(sql); + while(q->next()) { + list_encoders.push_back(new RDEncoder()); + list_encoders.back()->setId(q->value(0).toInt()); + list_encoders.back()->setName(q->value(1).toString()); + list_encoders.back()->setDefaultExtension(q->value(2).toString()); + list_encoders.back()->setCommandLine(q->value(3).toString()); + sql=QString().sprintf("select CHANNELS from ENCODER_CHANNELS \ + where ENCODER_ID=%d order by CHANNELS", + q->value(0).toInt()); + q1=new RDSqlQuery(sql); + while(q1->next()) { + list_encoders.back()->addAllowedChannel(q1->value(0).toInt()); + } + delete q1; + sql=QString().sprintf("select SAMPLERATES from ENCODER_SAMPLERATES \ + where ENCODER_ID=%d order by SAMPLERATES", + q->value(0).toInt()); + q1=new RDSqlQuery(sql); + while(q1->next()) { + list_encoders.back()->addAllowedSamplerate(q1->value(0).toInt()); + } + delete q1; + sql=QString().sprintf("select BITRATES from ENCODER_BITRATES \ + where ENCODER_ID=%d order by BITRATES", + q->value(0).toInt()); + q1=new RDSqlQuery(sql); + while(q1->next()) { + list_encoders.back()->addAllowedBitrate(q1->value(0).toInt()); + } + delete q1; + } + delete q; +} + + +RDEncoderList::~RDEncoderList() +{ + for(unsigned i=0;i<list_encoders.size();i++) { + delete list_encoders[i]; + } + list_encoders.clear(); +} + + +unsigned RDEncoderList::encoderQuantity() const +{ + return list_encoders.size(); +} + + +RDEncoder *RDEncoderList::encoder(unsigned n) +{ + return list_encoders[n]; +} diff --git a/lib/rdencoderlist.h b/lib/rdencoderlist.h new file mode 100644 index 00000000..9bf37796 --- /dev/null +++ b/lib/rdencoderlist.h @@ -0,0 +1,45 @@ +// rdencoderlist.h +// +// Abstract a Rivendell Custom Encoder +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdencoderlist.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDENCODERLIST_H +#define RDENCODERLIST_H + +#include <vector> + +#include <qstring.h> + +#include <rdencoder.h> + +class RDEncoderList +{ + public: + RDEncoderList(const QString &stationname); + ~RDEncoderList(); + unsigned encoderQuantity() const; + RDEncoder *encoder(unsigned n); + + private: + std::vector<RDEncoder *> list_encoders; +}; + + +#endif // RDENCODERLIST_H diff --git a/lib/rdescape_string.cpp b/lib/rdescape_string.cpp new file mode 100644 index 00000000..2262bf04 --- /dev/null +++ b/lib/rdescape_string.cpp @@ -0,0 +1,180 @@ +// rdescape_string.cpp +// +// Escape non-valid characters in a string. +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdescape_string.cpp,v 1.17.10.2 2014/06/24 18:27:04 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <vector> + +#include <rdescape_string.h> + +QString RDEscapeString(QString const &str) +{ + QString res; + + for(unsigned i=0;i<str.length();i++) { + switch(((const char *)str)[i]) { + case '(': + res+=QString("\\\("); + break; + + case ')': + res+=QString("\\)"); + break; + + case '{': + res+=QString("\\\{"); + break; + + case '"': + res+=QString("\\\""); + break; + + case '´': + res+=QString("\\´"); + break; + + case '`': + res+=QString("\\`"); + break; + + case '[': + res+=QString("\\\["); + break; + + case '\'': + res+=QString("\\\'"); + break; + + case '\\': + res+=QString("\\"); + res+=QString("\\"); + break; + + case '?': + res+=QString("\\\?"); + break; + + case ' ': + res+=QString("\\ "); + break; + + case '&': + res+=QString("\\&"); + break; + + case ';': + res+=QString("\\;"); + break; + + case '<': + res+=QString("\\<"); + break; + + case '>': + res+=QString("\\>"); + break; + + case '|': + res+=QString("\\|"); + break; + + default: + res+=((const char *)str)[i]; + break; + } + } + + /* + for(unsigned i=0;i<str.length();i++) { + switch(((const char *)str)[i]) { + case '(': + res+=QString("\\\("); + break; + + case ')': + res+=QString("\\)"); + break; + + case '{': + res+=QString("\\\{"); + break; + + case '"': + res+=QString("\\\""); + break; + + case '´': + res+=QString("\\´"); + break; + + case '`': + res+=QString("\\`"); + break; + + case '[': + res+=QString("\\\["); + break; + + case '\'': + res+=QString("\\\'"); + break; + + case '\\': + res+=QString("\\"); + res+=QString("\\"); + break; + + case '?': + res+=QString("\\\?"); + break; + + case ' ': + res+=QString("\\ "); + break; + + case '&': + res+=QString("\\&"); + break; + + case ';': + res+=QString("\\;"); + break; + + case '<': + res+=QString("\\<"); + break; + + case '>': + res+=QString("\\>"); + break; + + case '|': + res+=QString("\\|"); + break; + + default: + res+=((const char *)str)[i]; + break; + } + } + */ + + return res; +} diff --git a/lib/rdescape_string.h b/lib/rdescape_string.h new file mode 100644 index 00000000..3974a946 --- /dev/null +++ b/lib/rdescape_string.h @@ -0,0 +1,31 @@ +// rdescape_string.h +// +// Escape non-valid characters in a string. +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdescape_string.h,v 1.7.10.1 2014/06/24 18:27:04 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qstring.h> + +#ifndef RDESCAPE_STRING_H +#define RDESCAPE_STRING_H + +QString RDEscapeString(const QString &str); + + +#endif // RDESCAPE_STRING_H diff --git a/lib/rdevent.cpp b/lib/rdevent.cpp new file mode 100644 index 00000000..0ba217b1 --- /dev/null +++ b/lib/rdevent.cpp @@ -0,0 +1,421 @@ +// rdevent.cpp +// +// Abstract a Rivendell Log Manager Event. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdevent.cpp,v 1.14.8.1 2014/01/13 18:36:57 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +#include <rddb.h> +#include <rdconf.h> +#include <rdevent.h> +#include <rdescape_string.h> + +// +// Global Classes +// +RDEvent::RDEvent(const QString &name,bool create) +{ + RDSqlQuery *q; + QString sql; + + event_name=name; + + if(create) { + sql=QString().sprintf("select NAME from EVENTS where \ +(NAME=\"%s\")",(const char *)event_name); + q=new RDSqlQuery(sql); + if(q->size()!=1) { + delete q; + sql=QString(). + sprintf("INSERT INTO EVENTS SET NAME=\"%s\",TITLE_SEP=100", + (const char *)event_name); + q=new RDSqlQuery(sql); + delete q; + } + else { + delete q; + } + } +} + + +QString RDEvent::name() const +{ + return event_name; +} + + +QString RDEvent::properties() const +{ + bool ok; + return GetStringValue("PROPERTIES",&ok); +} + + +void RDEvent::setProperties(const QString &str) const +{ + SetRow("PROPERTIES",str,true); +} + + +QString RDEvent::displayText(bool *ok) const +{ + return GetStringValue("DISPLAY_TEXT",ok); +} + + +void RDEvent::setDisplayText(bool ok,const QString &text) const +{ + SetRow("DISPLAY_TEXT",text,ok); +} + + +QString RDEvent::noteText(bool *ok) const +{ + return GetStringValue("NOTE_TEXT",ok); +} + + +void RDEvent::setNoteText(bool ok,const QString &text) const +{ + SetRow("NOTE_TEXT",text,ok); +} + + +int RDEvent::preposition() const +{ + return GetIntValue("PREPOSITION"); +} + + +void RDEvent::setPreposition(int offset) const +{ + SetRow("PREPOSITION",offset); +} + + +RDLogLine::TimeType RDEvent::timeType() const +{ + return (RDLogLine::TimeType)GetIntValue("TIME_TYPE"); +} + + +void RDEvent::setTimeType(RDLogLine::TimeType type) const +{ + SetRow("TIME_TYPE",(int)type); +} + + +int RDEvent::graceTime() const +{ + return GetIntValue("GRACE_TIME"); +} + + +void RDEvent::setGraceTime(int offset) const +{ + SetRow("GRACE_TIME",offset); +} + + +bool RDEvent::postPoint() const +{ + bool ok; + return RDBool(GetStringValue("POST_POINT",&ok)); +} + + +void RDEvent::setPostPoint(bool state) const +{ + SetRow("POST_POINT",RDYesNo(state),true); +} + + +bool RDEvent::useAutofill() const +{ + bool ok; + return RDBool(GetStringValue("USE_AUTOFILL",&ok)); +} + + +void RDEvent::setUseAutofill(bool state) const +{ + SetRow("USE_AUTOFILL",RDYesNo(state),true); +} + + +int RDEvent::autofillSlop() const +{ + return GetIntValue("AUTOFILL_SLOP"); +} + + +void RDEvent::setAutofillSlop(int slop) const +{ + SetRow("AUTOFILL_SLOP",slop); +} + + +bool RDEvent::useTimescale() const +{ + bool ok; + return RDBool(GetStringValue("USE_TIMESCALE",&ok)); +} + + +void RDEvent::setUseTimescale(bool state) const +{ + SetRow("USE_TIMESCALE",RDYesNo(state),true); +} + + +RDEventLine::ImportSource RDEvent::importSource() const +{ + return (RDEventLine::ImportSource)GetIntValue("IMPORT_SOURCE"); +} + + +void RDEvent::setImportSource(RDEventLine::ImportSource src) const +{ + SetRow("IMPORT_SOURCE",(int)src); +} + + +int RDEvent::startSlop() const +{ + return GetIntValue("START_SLOP"); +} + + +void RDEvent::setStartSlop(int slop) const +{ + SetRow("START_SLOP",slop); +} + + +int RDEvent::endSlop() const +{ + return GetIntValue("END_SLOP"); +} + + +void RDEvent::setEndSlop(int slop) const +{ + SetRow("END_SLOP",slop); +} + + +RDLogLine::TransType RDEvent::firstTransType() const +{ + return (RDLogLine::TransType)GetIntValue("FIRST_TRANS_TYPE"); +} + + +void RDEvent::setFirstTransType(RDLogLine::TransType trans) const +{ + SetRow("FIRST_TRANS_TYPE",(int)trans); +} + + +RDLogLine::TransType RDEvent::defaultTransType() const +{ + return (RDLogLine::TransType)GetIntValue("DEFAULT_TRANS_TYPE"); +} + + +void RDEvent::setDefaultTransType(RDLogLine::TransType trans) const +{ + SetRow("DEFAULT_TRANS_TYPE",(int)trans); +} + + +QColor RDEvent::color() const +{ + bool ok; + QColor color; + color=QColor(GetStringValue("COLOR",&ok)); + if(!ok) { + color=QColor(); + } + return color; +} + + +void RDEvent::setColor(const QColor &color) const +{ + SetRow("COLOR",color.name(),color.isValid()); +} + + +QString RDEvent::nestedEvent() const +{ + bool ok; + return GetStringValue("NESTED_EVENT",&ok); +} + + +void RDEvent::setNestedEvent(const QString &eventname) +{ + SetRow("NESTED_EVENT",eventname,true); +} + + +QString RDEvent::remarks() const +{ + bool ok; + return GetStringValue("REMARKS",&ok); +} + + +void RDEvent::setRemarks(const QString &str) const +{ + SetRow("REMARKS",str,true); +} + + +QString RDEvent::preimportTableName(const QString event_name) +{ + QString ret=event_name; + ret.replace(" ","_"); + return ret+"_PRE"; +} + + +QString RDEvent::postimportTableName(const QString event_name) +{ + QString ret=event_name; + ret.replace(" ","_"); + return ret+"_POST"; +} + + +int RDEvent::GetIntValue(const QString &field) const +{ + QString sql; + RDSqlQuery *q; + int accum; + + sql=QString().sprintf("select %s from EVENTS where NAME=\"%s\"", + (const char *)field, + (const char *)event_name); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toInt(); + delete q; + return accum; + } + delete q; + return 0; +} + + +QString RDEvent::GetStringValue(const QString &field,bool *ok) const +{ + QString sql; + RDSqlQuery *q; + QString accum; + + sql=QString().sprintf("select %s from EVENTS where NAME=\"%s\"", + (const char *)field, + (const char *)event_name); + q=new RDSqlQuery(sql); + if(q->first()) { + if(q->value(0).isNull()) { + *ok=false; + } + else { + accum=q->value(0).toString(); + *ok=true; + } + delete q; + return accum; + } + delete q; + return 0; +} + + +void RDEvent::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE EVENTS SET %s=%d WHERE NAME=\"%s\"", + (const char *)param, + value, + (const char *)event_name); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDEvent::SetRow(const QString ¶m,const QString &value,bool ok) const +{ + RDSqlQuery *q; + QString sql; + + if(ok) { + sql=QString().sprintf("UPDATE EVENTS SET %s=\"%s\" WHERE NAME=\"%s\"", + (const char *)param, + (const char *)RDEscapeString(value), + (const char *)event_name); + } + else { + sql=QString().sprintf("UPDATE EVENTS SET %s=NULL WHERE NAME=\"%s\"", + (const char *)param, + (const char *)event_name); + } + q=new RDSqlQuery(sql); + delete q; +} + + +QString RDEvent::SchedGroup() +{ + bool ok; + return GetStringValue("SCHED_GROUP",&ok); +} + + +void RDEvent::setSchedGroup(QString str) +{ + SetRow("SCHED_GROUP",str,true); +} + +QString RDEvent::HaveCode() +{ + bool ok; + return GetStringValue("HAVE_CODE",&ok); +} + + +void RDEvent::setHaveCode(QString str) +{ + SetRow("HAVE_CODE",str,true); +} + + +unsigned RDEvent::titleSep() +{ + return GetIntValue("TITLE_SEP"); +} + + +void RDEvent::setTitleSep(unsigned titlesep) +{ + SetRow("TITLE_SEP",titlesep); +} diff --git a/lib/rdevent.h b/lib/rdevent.h new file mode 100644 index 00000000..e8251f87 --- /dev/null +++ b/lib/rdevent.h @@ -0,0 +1,90 @@ +// rdevent.h +// +// Abstract a Rivendell Log Manager Event +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdevent.h,v 1.11.8.1 2014/01/13 18:36:57 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> + +#include <rdlog_line.h> +#include <rdevent_line.h> + +#ifndef RDEVENT_H +#define RDEVENT_H + +class RDEvent +{ + public: + RDEvent(const QString &name,bool create=false); + QString name() const; + QString properties() const; + void setProperties(const QString &str) const; + QString displayText(bool *ok) const; + void setDisplayText(bool ok,const QString &text) const; + QString noteText(bool *ok) const; + void setNoteText(bool ok,const QString &text) const; + int preposition() const; + void setPreposition(int offset) const; + RDLogLine::TimeType timeType() const; + void setTimeType(RDLogLine::TimeType type) const; + int graceTime() const; + void setGraceTime(int offset) const; + bool postPoint() const; + void setPostPoint(bool state) const; + bool useAutofill() const; + void setUseAutofill(bool state) const; + int autofillSlop() const; + void setAutofillSlop(int slop) const; + bool useTimescale() const; + void setUseTimescale(bool state) const; + RDEventLine::ImportSource importSource() const; + void setImportSource(RDEventLine::ImportSource src) const; + int startSlop() const; + void setStartSlop(int slop) const; + int endSlop() const; + void setEndSlop(int slop) const; + RDLogLine::TransType firstTransType() const; + void setFirstTransType(RDLogLine::TransType trans) const; + RDLogLine::TransType defaultTransType() const; + void setDefaultTransType(RDLogLine::TransType trans) const; + QColor color() const; + void setColor(const QColor &color) const; + QString nestedEvent() const; + void setNestedEvent(const QString &eventname); + QString remarks() const; + void setRemarks(const QString &str) const; + QString SchedGroup(); + void setSchedGroup(QString str); + QString HaveCode(); + void setHaveCode(QString str); + unsigned titleSep(); + void setTitleSep(unsigned titlesep); + static QString preimportTableName(const QString event_name); + static QString postimportTableName(const QString event_name); + + private: + int GetIntValue(const QString &field) const; + QString GetStringValue(const QString &field,bool *ok) const; + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,const QString &value,bool ok) const; + QString event_name; +}; + + +#endif diff --git a/lib/rdevent_line.cpp b/lib/rdevent_line.cpp new file mode 100644 index 00000000..9ad29e6f --- /dev/null +++ b/lib/rdevent_line.cpp @@ -0,0 +1,1162 @@ +// rdevent_line.cpp +// +// Abstract a Rivendell Log Manager Event +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdevent_line.cpp,v 1.60.2.4.2.2 2014/06/24 18:27:04 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qtextstream.h> + +#include <rdconf.h> +#include <rdcart.h> +#include <rdevent.h> +#include <rdevent_line.h> +#include <schedcartlist.h> +#include <rddb.h> +#include <rdescape_string.h> + + +RDEventLine::RDEventLine() +{ + event_preimport_log=new RDLogEvent(); + event_postimport_log=new RDLogEvent(); + clear(); +} + + +QString RDEventLine::name() const +{ + return event_name; +} + + +void RDEventLine::setName(const QString &name) +{ + event_name=name; + event_preimport_log->setLogName(RDEvent::preimportTableName(event_name)); + event_postimport_log->setLogName(RDEvent::postimportTableName(event_name)); +} + + +QString RDEventLine::properties() const +{ + return event_properties; +} + + +void RDEventLine::setProperties(const QString &str) +{ + event_properties=str; +} + + +int RDEventLine::preposition() const +{ + return event_preposition; +} + + +void RDEventLine::setPreposition(int offset) +{ + event_preposition=offset; +} + + +RDLogLine::TimeType RDEventLine::timeType() const +{ + return event_time_type; +} + + +void RDEventLine::setTimeType(RDLogLine::TimeType type) +{ + event_time_type=type; +} + + +int RDEventLine::graceTime() const +{ + return event_grace_time; +} + + +void RDEventLine::setGraceTime(int offset) +{ + event_grace_time=offset; +} + + +bool RDEventLine::postPoint() const +{ + return event_post_point; +} + + +void RDEventLine::setPostPoint(bool state) +{ + event_post_point=state; +} + + +bool RDEventLine::useAutofill() const +{ + return event_use_autofill; +} + + +void RDEventLine::setUseAutofill(bool state) +{ + event_use_autofill=state; +} + + +int RDEventLine::autofillSlop() const +{ + return event_autofill_slop; +} + + +void RDEventLine::setAutofillSlop(int slop) +{ + event_autofill_slop=slop; +} + + +bool RDEventLine::useTimescale() const +{ + return event_use_timescale; +} + + +void RDEventLine::setUseTimescale(bool state) +{ + event_use_timescale=state; +} + + +RDEventLine::ImportSource RDEventLine::importSource() const +{ + return event_import_source; +} + + +void RDEventLine::setImportSource(RDEventLine::ImportSource src) +{ + event_import_source=src; +} + + +int RDEventLine::startSlop() const +{ + return event_start_slop; +} + + +void RDEventLine::setStartSlop(int slop) +{ + event_start_slop=slop; +} + + +int RDEventLine::endSlop() const +{ + return event_end_slop; +} + + +void RDEventLine::setEndSlop(int slop) +{ + event_end_slop=slop; +} + + +RDLogLine::TransType RDEventLine::firstTransType() const +{ + return event_first_transtype; +} + + +void RDEventLine::setFirstTransType(RDLogLine::TransType trans) +{ + event_first_transtype=trans; +} + + +RDLogLine::TransType RDEventLine::defaultTransType() const +{ + return event_default_transtype; +} + + +void RDEventLine::setDefaultTransType(RDLogLine::TransType trans) +{ + event_default_transtype=trans; +} + + +QColor RDEventLine::color() const +{ + return event_color; +} + + +void RDEventLine::setColor(const QColor &color) +{ + event_color=color; +} + + +QString RDEventLine::SchedGroup() const +{ + return event_sched_group; +} + + +void RDEventLine::setSchedGroup(QString str) +{ + event_sched_group=str; +} + + +QString RDEventLine::HaveCode() const +{ + return event_have_code; +} + + +void RDEventLine::setHaveCode(QString str) +{ + event_have_code=str; +} + + +unsigned RDEventLine::titleSep() const +{ + return event_title_sep; +} + + +void RDEventLine::setTitleSep(unsigned titlesep) +{ + event_title_sep=titlesep; +} + + + +RDLogEvent *RDEventLine::preimportCarts() +{ + return event_preimport_log; +} + + +RDLogEvent *RDEventLine::postimportCarts() +{ + return event_postimport_log; +} + + +QTime RDEventLine::startTime() const +{ + return event_start_time; +} + + +void RDEventLine::setStartTime(const QTime &time) +{ + event_start_time=time; +} + + +int RDEventLine::length() const +{ + return event_length; +} + + +void RDEventLine::setLength(int msecs) +{ + event_length=msecs; +} + + +void RDEventLine::clear() +{ + event_name=""; + event_properties=""; + event_preposition=0; + event_time_type=RDLogLine::Relative; + event_grace_time=0; + event_post_point=false; + event_use_autofill=false; + event_use_timescale=false; + event_import_source=RDEventLine::None; + event_start_slop=0; + event_end_slop=0; + event_first_transtype=RDLogLine::Segue; + event_default_transtype=RDLogLine::Segue; + event_color=QColor(); + event_preimport_log->clear(); + event_postimport_log->clear(); + event_start_time=QTime(); + event_length=0; + event_autofill_slop=-1; + event_sched_group=""; + event_have_code=""; + event_title_sep=100; + event_nested_event=""; +} + + +bool RDEventLine::load() +{ + QString sql=QString().sprintf("select PROPERTIES,PREPOSITION,TIME_TYPE,\ + GRACE_TIME,POST_POINT,USE_AUTOFILL,\ + USE_TIMESCALE,IMPORT_SOURCE,START_SLOP,\ + END_SLOP,FIRST_TRANS_TYPE,DEFAULT_TRANS_TYPE,\ + COLOR,AUTOFILL_SLOP,NESTED_EVENT,SCHED_GROUP,TITLE_SEP,HAVE_CODE \ + from EVENTS where NAME=\"%s\"", + (const char *)event_name); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + fprintf(stderr,"RDEventLine::load() EVENT NOT FOUND: %s\n", + (const char *)event_name); + delete q; + return false; + } + event_properties=q->value(0).toString(); + event_preposition=q->value(1).toInt(); + event_time_type=(RDLogLine::TimeType)q->value(2).toInt(); + event_grace_time=q->value(3).toInt(); + event_post_point=RDBool(q->value(4).toString()); + event_use_autofill=RDBool(q->value(5).toString()); + event_use_timescale=RDBool(q->value(6).toString()); + event_import_source=(RDEventLine::ImportSource)q->value(7).toInt(); + event_start_slop=q->value(8).toInt(); + event_end_slop=q->value(9).toInt(); + event_first_transtype=(RDLogLine::TransType)q->value(10).toInt(); + event_default_transtype=(RDLogLine::TransType)q->value(11).toInt(); + if(q->value(12).isNull()) { + event_color=QColor(); + } + else { + event_color=QColor(q->value(12).toString()); + } + event_autofill_slop=q->value(13).toInt(); + event_nested_event=q->value(14).toString(); + event_sched_group=q->value(15).toString(); + event_title_sep=q->value(16).toUInt(); + event_have_code=q->value(17).toString(); + + delete q; + event_preimport_log->load(); + event_postimport_log->load(); + return true; +} + + +bool RDEventLine::save() +{ + QString sql=QString().sprintf("select NAME from EVENTS where NAME=\"%s\"", + (const char *)event_name); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("update EVENTS set PROPERTIES=\"%s\",\ + PREPOSITION=%d,TIME_TYPE=%d,\ + GRACE_TIME=%d,POST_POINT=\"%s\",\ + USE_AUTOFILL=\"%s\",USE_TIMESCALE=\"%s\",\ + IMPORT_SOURCE=%d,START_SLOP=%d,\ + END_SLOP=%d,FIRST_TRANS_TYPE=%d,\ + DEFAULT_TRANS_TYPE=%d,COLOR=\"%s\"\ + AUTOFILL_SLOP=%d,NESTED_EVENT=\"%s\",\ + SCHED_GROUP=\"%s\",TITLE_SEP=%d,HAVE_CODE=\"%s\" \ + where NAME=\"%s\"", + (const char *)RDEscapeString(event_properties), + event_preposition,event_time_type, + event_grace_time, + (const char *)RDYesNo(event_post_point), + (const char *)RDYesNo(event_use_autofill), + (const char *)RDYesNo(event_use_timescale), + event_import_source,event_start_slop, + event_end_slop,event_first_transtype, + event_default_transtype, + (const char *)event_color.name(), + event_autofill_slop, + (const char *)RDEscapeString(event_nested_event), + (const char *)RDEscapeString(event_sched_group), + event_title_sep, + (const char*)event_have_code, + (const char *)RDEscapeString(event_name)); + } + else { + sql=QString().sprintf("insert into EVENTS set NAME=\"%s\",\ + PROPERTIES=\"%s\",\ + PREPOSITION=%d,TIME_TYPE=%d,\ + GRACE_TIME=%d,POST_POINT=\"%s\",\ + USE_AUTOFILL=\"%s\",USE_TIMESCALE=\"%s\",\ + IMPORT_SOURCE=%d,START_SLOP=%d,\ + END_SLOP=%d,FIRST_TRANS_TYPE=%d,\ + DEFAULT_TRANS_TYPE=%d,COLOR=\"%s\"\ + AUTOFILL_SLOP=%d,SCHED_GROUP=\"%s\" where NAME=\"%s\"", + (const char *)RDEscapeString(event_name), + (const char *)RDEscapeString(event_properties), + event_preposition,event_time_type, + event_grace_time, + (const char *)RDYesNo(event_post_point), + (const char *)RDYesNo(event_use_autofill), + (const char *)RDYesNo(event_use_timescale), + event_import_source,event_start_slop, + event_end_slop,event_first_transtype, + event_default_transtype, + (const char *)event_color.name(), + event_autofill_slop, + (const char *)RDEscapeString(event_sched_group), + (const char *)RDEscapeString(event_name)); + } + delete q; + q=new RDSqlQuery(sql); + if(!q->isActive()) { + delete q; + return false; + } + delete q; + event_preimport_log->save(); + event_postimport_log->save(); + return true; +} + + +bool RDEventLine::generateLog(QString logname,const QString &svcname, + QString *errors, unsigned artistsep, + QString clockname) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + QTime time=event_start_time; + QTime end_time=event_start_time.addMSecs(event_length); + QTime fill_start_time; + int count=0; + logname.replace(" ","_"); + RDLogLine *logline; + QString import_table; + int postimport_length=0; + RDLogLine::TransType trans_type=event_first_transtype; + RDLogLine::TimeType time_type=event_time_type; + RDLogLine::Type link_type=RDLogLine::MusicLink; + bool post_point=event_post_point; + int grace_time=event_grace_time; + int link_id=0; + + // + // Get Current Count and Link ID + // + sql=QString().sprintf("select COUNT from `%s_LOG` order by COUNT desc", + (const char *)logname); + q=new RDSqlQuery(sql); + if(q->first()) { + count=q->value(0).toInt()+1; + } + delete q; + + sql=QString().sprintf("select LINK_ID from `%s_LOG` where LINK_ID>=0 \ + order by LINK_ID desc", + (const char *)logname); + q=new RDSqlQuery(sql); + if(q->first()) { + link_id=q->value(0).toInt()+1; + } + delete q; + + // + // Override Default Parameters if Preposition Set + // + if(event_preposition>=0) { + time_type=RDLogLine::Hard; + grace_time=-1; + if(QTime().msecsTo(time)>event_preposition) { + time=time.addMSecs(-event_preposition); + } + else { + time=QTime(); + } + } + + // + // Pre-Import Carts + // + for(int i=0;i<event_preimport_log->size();i++) { + if((logline=event_preimport_log->logLine(i))!=NULL) { + sql=QString().sprintf("insert into `%s_LOG` set ID=%d,COUNT=%d,TYPE=%d,\ + SOURCE=%d,START_TIME=%d,GRACE_TIME=%d,\ + CART_NUMBER=%u,TIME_TYPE=%d,POST_POINT=\"%s\",\ + TRANS_TYPE=%d,COMMENT=\"%s\",EVENT_LENGTH=%d", + (const char *)logname,count,count, + logline->type(), + RDLogLine::Template, + QTime().msecsTo(time), + grace_time,logline->cartNumber(), + time_type, + (const char *)RDYesNo(post_point), + logline->transType(), + (const char *) + RDEscapeString(logline->markerComment()), + event_length); + q=new RDSqlQuery(sql); + delete q; + count++; + time=time.addMSecs(GetLength(logline->cartNumber())); + trans_type=event_default_transtype; + time_type=RDLogLine::Relative; + post_point=false; + grace_time=-1; + } + } + + // + // Calculate Post Import Length + // + for(int i=0;i<event_postimport_log->size();i++) { + postimport_length+= + GetLength(event_postimport_log->logLine(i)->cartNumber()); + } + + // + // Import Links + // + if(event_import_source==RDEventLine::Traffic || event_import_source==RDEventLine::Music) { + switch(event_import_source) { + case RDEventLine::Traffic: + link_type=RDLogLine::TrafficLink; + break; + + case RDEventLine::Music: + link_type=RDLogLine::MusicLink; + break; + + default: + break; + } + QTime end_start_time=event_start_time.addMSecs(event_length); + + sql=QString().sprintf("insert into `%s_LOG` set ID=%d,COUNT=%d,TYPE=%d,\ + SOURCE=%d,START_TIME=%d,GRACE_TIME=%d,\ + TIME_TYPE=%d,POST_POINT=\"%s\",TRANS_TYPE=%d,\ + LINK_EVENT_NAME=\"%s\",LINK_START_TIME=%d,\ + LINK_LENGTH=%d,LINK_ID=%d,LINK_START_SLOP=%d,\ + LINK_END_SLOP=%d,EVENT_LENGTH=%d", + (const char *)logname,count,count, + link_type,RDLogLine::Template, + QTime().msecsTo(time), + grace_time, + time_type, + (const char *)RDYesNo(post_point), + trans_type, + (const char *)RDEscapeString(event_name), + QTime().msecsTo(event_start_time), + event_start_time.msecsTo(end_start_time), + link_id, + event_start_slop, + event_end_slop, + event_length); + q=new RDSqlQuery(sql); + delete q; + count++; + time=time.addMSecs(event_length); + trans_type=event_default_transtype; + time_type=RDLogLine::Relative; + post_point=false; + grace_time=-1; + } + +// Scheduler + + if(event_import_source == RDEventLine::Scheduler ) { + int titlesep; + int stackid; + int counter; + RDLogLine::Source source=RDLogLine::Music; + + QString svcname_rp = svcname; + svcname_rp.replace(" ","_"); + + time.addMSecs(postimport_length); + + sql=QString().sprintf("select NUMBER,ARTIST,SCHED_CODES from CART where GROUP_NAME='%s'",(const char *)SchedGroup()); + + q=new RDSqlQuery(sql); + if(q->size()>0) + { + if(event_title_sep>=0 && event_title_sep<=50000) + { + titlesep = (int)event_title_sep; + } + else + { + titlesep = 100; + } + + int querysize=(int)q->size(); + SchedCartList *schedCL; + schedCL=new SchedCartList(querysize); + + for(counter=0;counter<querysize;counter++) + { + q->seek(counter); + schedCL->insertItem(q->value(0).toUInt(),0,0,q->value(1).toString(),q->value(2).toString()); + } + delete q; + + sql=QString().sprintf("SELECT SCHED_STACK_ID from %s_STACK order by SCHED_STACK_ID",(const char*)svcname_rp); + q=new RDSqlQuery(sql); + if (q->last()) + { + stackid=q->value(0).toUInt(); + } + else + { + stackid=0; + } + stackid++; + delete q; + + + // Add deconflicting rules here + // Title separation + schedCL->save(); + sql=QString().sprintf("select CART from %s_STACK \ + where SCHED_STACK_ID >= %d",(const char*)svcname_rp,(stackid-titlesep)); + q=new RDSqlQuery(sql); + + while (q->next()) + { + for(counter=0;counter<schedCL->getNumberOfItems();counter++) + { + if(q->value(0).toUInt()==schedCL->getItemCartnumber(counter)) + { + schedCL->removeItem(counter); + counter--; + } + } + } + delete q; + if(schedCL->getNumberOfItems()==0) + *errors+=QString().sprintf("%s Rule broken: Title Separation\n",(const char *)time.toString("hh:mm:ss")); + schedCL->restore(); + + // Artist separation + schedCL->save(); + sql=QString().sprintf("select ARTIST from %s_STACK \ + where SCHED_STACK_ID >= %d",(const char*)svcname_rp,(stackid-artistsep)); + q=new RDSqlQuery(sql); + + while (q->next()) + { + for(counter=0;counter<schedCL->getNumberOfItems();counter++) + { + if(q->value(0).toString()==schedCL->getItemArtist(counter)) + { + schedCL->removeItem(counter); + counter--; + } + } + } + + delete q; + if(schedCL->getNumberOfItems()==0) + *errors+=QString().sprintf("%s Rule broken: Artist Separation\n",(const char *)time.toString("hh:mm:ss")); + schedCL->restore(); + + // Must have scheduler code + if(event_have_code!="") + { + schedCL->save(); + for(counter=0;counter<schedCL->getNumberOfItems();counter++) + { + if(!schedCL->itemHasCode(counter,event_have_code)) + { + schedCL->removeItem(counter); + counter--; + } + } + if(schedCL->getNumberOfItems()==0) + *errors+=QString().sprintf("%s Rule broken: Must have code %s\n",(const char *)time.toString("hh:mm:ss"),(const char*)event_have_code); + schedCL->restore(); + } + + // Scheduler Codes + sql=QString().sprintf("select CODE,MAX_ROW,MIN_WAIT,NOT_AFTER, OR_AFTER,OR_AFTER_II from %s_RULES",(const char *)clockname); + q=new RDSqlQuery(sql); + while (q->next()) + { + // max in a row, min wait + schedCL->save(); + int range=q->value(1).toInt()+q->value(2).toInt(); + int allowed=q->value(1).toInt(); + QString wstr=q->value(0).toString(); + wstr+=" "; + wstr=wstr.left(11); + sql=QString().sprintf("select CART from %s_STACK \ + where SCHED_STACK_ID > %d and SCHED_CODES like \"%%%s%%\"",(const char*)svcname_rp,(stackid-range),(const char *)wstr); + q1=new RDSqlQuery(sql); + if (q1->size()>=allowed || allowed==0) + for(counter=0;counter<schedCL->getNumberOfItems();counter++) + if ( schedCL->removeIfCode(counter,q->value(0).toString())) + counter--; + delete q1; + if(schedCL->getNumberOfItems()==0) + *errors+=QString().sprintf("%s Rule broken: Max. in a Row/Min. Wait for %s\n",(const char *)time.toString("hh:mm:ss"),(const char *)q->value(0).toString()); + schedCL->restore(); + // do not play after + if (q->value(3).toString()!="") + { + schedCL->save(); + QString wstr=q->value(3).toString(); + wstr+=" "; + wstr=wstr.left(11); + sql=QString().sprintf("select CART from %s_STACK \ + where SCHED_STACK_ID = %d and SCHED_CODES like \"%%%s%%\"",(const char*)svcname_rp,(stackid-1),(const char *)wstr); + q1=new RDSqlQuery(sql); + if (q1->size()>0) + for(counter=0;counter<schedCL->getNumberOfItems();counter++) + if ( schedCL->removeIfCode(counter,q->value(0).toString())) + counter--; + delete q1; + if(schedCL->getNumberOfItems()==0) + *errors+=QString().sprintf("%s Rule broken: Do not schedule %s after %s\n",(const char *)time.toString("hh:mm:ss"),(const char *)q->value(0).toString(),(const char *)q->value(3).toString()); + schedCL->restore(); + } + // or after + if (q->value(4).toString()!="") + { + schedCL->save(); + QString wstr=q->value(4).toString(); + wstr+=" "; + wstr=wstr.left(11); + sql=QString().sprintf("select CART from %s_STACK \ + where SCHED_STACK_ID = %d and SCHED_CODES like \"%%%s%%\"",(const char*)svcname_rp,(stackid-1),(const char *)wstr); + q1=new RDSqlQuery(sql); + if (q1->size()>0) + for(counter=0;counter<schedCL->getNumberOfItems();counter++) + if ( schedCL->removeIfCode(counter,q->value(0).toString())) + counter--; + delete q1; + if(schedCL->getNumberOfItems()==0) + *errors+=QString().sprintf("%s Rule broken: Do not schedule %s after %s\n",(const char *)time.toString("hh:mm:ss"),(const char *)q->value(0).toString(),(const char *)q->value(4).toString()); + schedCL->restore(); + } + // or after II + if (q->value(5).toString()!="") + { + schedCL->save(); + QString wstr=q->value(5).toString(); + wstr+=" "; + wstr=wstr.left(11); + sql=QString().sprintf("select CART from %s_STACK \ + where SCHED_STACK_ID = %d and SCHED_CODES like \"%%%s%%\"",(const char*)svcname_rp,(stackid-1),(const char *)wstr); + q1=new RDSqlQuery(sql); + if (q1->size()>0) + for(counter=0;counter<schedCL->getNumberOfItems();counter++) + if ( schedCL->removeIfCode(counter,q->value(0).toString())) + counter--; + delete q1; + if(schedCL->getNumberOfItems()==0) + *errors+=QString().sprintf("%s Rule broken: Do not schedule %s after %s\n",(const char *)time.toString("hh:mm:ss"),(const char *)q->value(0).toString(),(const char *)q->value(5).toString()); + schedCL->restore(); + } + } + delete q; + + +// end of deconflicting rules + + int schedpos = rand()%schedCL->getNumberOfItems(); + sql=QString().sprintf("insert into `%s_LOG` set ID=%d,COUNT=%d,TYPE=%d,\ + SOURCE=%d,START_TIME=%d,GRACE_TIME=%d, \ + CART_NUMBER=%u,TIME_TYPE=%d,POST_POINT=\"%s\", \ + TRANS_TYPE=%d,EXT_START_TIME=\"%s\",\ + EVENT_LENGTH=%d", + (const char *)logname,count,count, + RDLogLine::Cart,source, + QTime().msecsTo(time), + grace_time, + schedCL->getItemCartnumber(schedpos), + time_type, + (const char *)RDYesNo(post_point), + trans_type, + (const char *)time.toString("hh:mm:ss"), + event_length); + q=new RDSqlQuery(sql); + delete q; + + + + count++; + + + + sql=QString().sprintf("insert into `%s_STACK` set SCHED_STACK_ID=%u,CART=%u,ARTIST=\"%s\",SCHED_CODES=\"%s\"",(const char*)svcname_rp, + stackid,schedCL->getItemCartnumber(schedpos), + (const char *)RDEscapeString(schedCL->getItemArtist(schedpos)),(const char *)schedCL->getItemSchedCodes(schedpos)); + q=new RDSqlQuery(sql); + delete q; + delete schedCL; + } + else + { + delete q; + } + } + + + // + // Post-Import Carts + // + for(int i=0;i<event_postimport_log->size();i++) { + if((logline=event_postimport_log->logLine(i))!=NULL) { + sql=QString().sprintf("insert into `%s_LOG` set ID=%d,COUNT=%d,TYPE=%d,\ + SOURCE=%d,START_TIME=%d,GRACE_TIME=%d,\ + CART_NUMBER=%u,TIME_TYPE=%d,POST_POINT=\"%s\",\ + TRANS_TYPE=%d,COMMENT=\"%s\",EVENT_LENGTH=%d", + (const char *)logname,count,count, + logline->type(), + RDLogLine::Template, + QTime().msecsTo(time), + grace_time,logline->cartNumber(), + time_type, + (const char *)RDYesNo(post_point), + logline->transType(), + (const char *) + RDEscapeString(logline->markerComment()), + event_length); + q=new RDSqlQuery(sql); + delete q; + count++; + time=time.addMSecs(GetLength(logline->cartNumber())); + time_type=RDLogLine::Relative; + trans_type=event_default_transtype; + post_point=false; + grace_time=-1; + } + } + + return true; +} + + +bool RDEventLine::linkLog(RDLogEvent *e,int next_id,const QString &svcname, + RDLogLine *link_logline,const QString &track_str, + const QString &label_cart,const QString &track_cart, + const QString &import_table,QString *errors) +{ + QString sql; + RDSqlQuery *q; + RDLogLine *logline=NULL; + + // + // Initial Import Parameters + // + RDLogLine::Source event_src=RDLogLine::Manual; + switch(event_import_source) { + case RDEventLine::Music: + event_src=RDLogLine::Music; + break; + + case RDEventLine::Traffic: + event_src=RDLogLine::Traffic; + break; + + case RDEventLine::Scheduler: + case RDEventLine::None: + break; + } + RDLogLine::TimeType time_type=link_logline->timeType(); + RDLogLine::TransType trans_type=link_logline->transType(); + int grace_time=link_logline->graceTime(); + QTime time=link_logline->startTime(RDLogLine::Logged); + + // + // Calculate Event Time Boundaries + // + int start_start_hour=link_logline->linkStartTime().hour(); + int start_start_secs=60000*link_logline->linkStartTime().minute()+ + 1000*link_logline->linkStartTime().second(); + int end_start_secs=start_start_secs+link_logline->linkLength(); + + // + // Apply Slop Factors + // + if(start_start_hour==link_logline->linkStartTime(). + addMSecs(-link_logline->linkStartSlop()).hour()) { + start_start_secs-=link_logline->linkStartSlop(); + } + else { + start_start_secs=0; // So we don't slop over into the previous hour + } + end_start_secs+=link_logline->linkEndSlop(); + + // + // Load Matching Events and Insert into Log + // + int id=-1; + sql=QString().sprintf("select CART_NUMBER,START_SECS,LENGTH,EXT_DATA,\ + EXT_EVENT_ID,EXT_ANNC_TYPE,EXT_CART_NAME,\ + INSERT_BREAK,INSERT_TRACK,INSERT_FIRST,TITLE,\ + TRACK_STRING from `%s` where (START_HOUR=%d)&&\ + (START_SECS>=%d)&&(START_SECS<=%d)&&\ + (EVENT_USED=\"N\") order by ID", + (const char *)import_table, + start_start_hour,start_start_secs/1000, + end_start_secs/1000); + q=new RDSqlQuery(sql); + while(q->next()) { + if((id=e->nextId())>next_id) { + next_id=id; + } + int length=GetLength(q->value(0).toUInt(),q->value(2).toInt()); + if(q->value(9).toUInt()==RDEventLine::InsertBreak) { + if(q->value(7).toString()=="Y") { // Insert Break + if((!event_nested_event.isEmpty()&&(event_nested_event!=event_name))) { + e->insert(e->size(),1); + logline=e->logLine(e->size()-1); + logline->setId(next_id++); + logline->setStartTime(RDLogLine::Logged,time); + logline->setType(RDLogLine::TrafficLink); + logline->setSource(event_src); + logline->setTransType(trans_type); + logline->setEventLength(event_length); + logline->setLinkEventName(event_nested_event); + logline->setLinkStartTime(link_logline->linkStartTime()); + logline->setLinkLength(link_logline->linkLength()); + logline->setLinkStartSlop(link_logline->linkStartSlop()); + logline->setLinkEndSlop(link_logline->linkEndSlop()); + logline->setLinkId(link_logline->linkId()); + logline->setLinkEmbedded(true); + } + } + if(q->value(8).toString()=="Y") { // Insert Track + e->insert(e->size(),1); + logline=e->logLine(e->size()-1); + logline->setId(next_id++); + logline->setStartTime(RDLogLine::Logged,time); + logline->setType(RDLogLine::Track); + logline->setSource(event_src); + logline->setTransType(RDLogLine::Segue); + logline->setMarkerComment(q->value(11).toString()); + logline->setEventLength(event_length); + logline->setLinkEventName(event_name); + logline->setLinkStartTime(link_logline->linkStartTime()); + logline->setLinkLength(link_logline->linkLength()); + logline->setLinkStartSlop(link_logline->linkStartSlop()); + logline->setLinkEndSlop(link_logline->linkEndSlop()); + logline->setLinkId(link_logline->linkId()); + logline->setLinkEmbedded(true); + } + } + else { + if(q->value(8).toString()=="Y") { // Insert Track + e->insert(e->size(),1); + logline=e->logLine(e->size()-1); + logline->setId(next_id++); + logline->setStartTime(RDLogLine::Logged,time); + logline->setType(RDLogLine::Track); + logline->setSource(event_src); + logline->setTransType(RDLogLine::Segue); + logline->setMarkerComment(q->value(11).toString()); + logline->setEventLength(event_length); + logline->setLinkEventName(event_name); + logline->setLinkStartTime(link_logline->linkStartTime()); + logline->setLinkLength(link_logline->linkLength()); + logline->setLinkStartSlop(link_logline->linkStartSlop()); + logline->setLinkEndSlop(link_logline->linkEndSlop()); + logline->setLinkId(link_logline->linkId()); + logline->setLinkEmbedded(true); + } + if(q->value(7).toString()=="Y") { // Insert Break + if((!event_nested_event.isEmpty()&&(event_nested_event!=event_name))) { + e->insert(e->size(),1); + logline=e->logLine(e->size()-1); + logline->setId(next_id++); + logline->setStartTime(RDLogLine::Logged,time); + logline->setType(RDLogLine::TrafficLink); + logline->setSource(event_src); + logline->setTransType(trans_type); + logline->setEventLength(event_length); + logline->setLinkEventName(event_nested_event); + logline->setLinkStartTime(link_logline->linkStartTime()); + logline->setLinkLength(link_logline->linkLength()); + logline->setLinkStartSlop(link_logline->linkStartSlop()); + logline->setLinkEndSlop(link_logline->linkEndSlop()); + logline->setLinkId(link_logline->linkId()); + logline->setLinkEmbedded(true); + } + } + } + + e->insert(e->size(),1); + logline=e->logLine(e->size()-1); + logline->setId(next_id++); + logline->setSource(event_src); + logline->setStartTime(RDLogLine::Logged,time); + logline->setGraceTime(grace_time); + logline->setTimeType(time_type); + logline->setTransType(trans_type); + logline->setExtStartTime(QTime().addSecs(3600*start_start_hour+ + q->value(1).toInt())); + logline->setExtLength(q->value(2).toInt()); + logline->setExtData(q->value(3).toString()); + logline->setExtEventId(q->value(4).toString()); + logline->setExtAnncType(q->value(5).toString()); + logline->setExtCartName(q->value(6).toString()); + logline->setEventLength(event_length); + logline->setLinkEventName(event_name); + logline->setLinkStartTime(link_logline->linkStartTime()); + logline->setLinkLength(link_logline->linkLength()); + logline->setLinkStartSlop(link_logline->linkStartSlop()); + logline->setLinkEndSlop(link_logline->linkEndSlop()); + logline->setLinkId(link_logline->linkId()); + logline->setLinkEmbedded(link_logline->linkEmbedded()); + if((q->value(6).toString()==label_cart)&&(!label_cart.isEmpty())) { + logline->setType(RDLogLine::Marker); + logline->setMarkerComment(q->value(10).toString()); + logline->setCartNumber(0); + } + else { + if((q->value(6).toString()==track_cart)&&(!track_cart.isEmpty())) { + logline->setType(RDLogLine::Track); + logline->setMarkerComment(q->value(10).toString()); + logline->setCartNumber(0); + } + else { + logline->setType(RDLogLine::Cart); + logline->setCartNumber(q->value(0).toUInt()); + } + } + + // + // Clear Leading Event Values + // + time_type=RDLogLine::Relative; + trans_type=event_default_transtype; + time=time.addMSecs(length); + grace_time=-1; + + } + delete q; + + // + // Mark Events as Used + // + sql=QString().sprintf("update `%s` set EVENT_USED=\"Y\"\ + where (START_HOUR=%d)&&(START_SECS>=%d)&&\ + (START_SECS<=%d)&&(EVENT_USED=\"N\")", + (const char *)import_table, + start_start_hour,start_start_secs/1000, + end_start_secs/1000); + q=new RDSqlQuery(sql); + delete q; + + // + // Autofill + // + QTime end_time=link_logline->startTime(RDLogLine::Logged). + addMSecs(link_logline->linkLength()); + if(event_use_autofill&&(event_start_time<=time)) { + QTime fill_start_time=time; + sql=QString(). + sprintf("select AUTOFILLS.CART_NUMBER,CART.FORCED_LENGTH from\ + AUTOFILLS left join CART on AUTOFILLS.CART_NUMBER=CART.NUMBER\ + where (AUTOFILLS.SERVICE=\"%s\")&&(CART.FORCED_LENGTH<=%d)&&\ + (CART.FORCED_LENGTH>0) order by CART.FORCED_LENGTH desc", + (const char *)svcname,time.msecsTo(end_time)); + q=new RDSqlQuery(sql); + bool fit=true; + while(fit) { + fit=false; + while(q->next()&&(fill_start_time<=time)) { + if((time.addMSecs(q->value(1).toInt())<=end_time)&& + (time.addMSecs(q->value(1).toInt())>time)) { + e->insert(e->size(),1); + logline=e->logLine(e->size()-1); + logline->setId(next_id++); + logline->setStartTime(RDLogLine::Logged,time); + logline->setType(RDLogLine::Cart); + logline->setSource(event_src); + logline->setTransType(trans_type); + logline->setGraceTime(grace_time); + logline->setCartNumber(q->value(0).toUInt()); + logline->setTimeType(time_type); + logline->setEventLength(event_length); + logline->setLinkEventName(event_name); + logline->setLinkStartTime(link_logline->linkStartTime()); + logline->setLinkLength(link_logline->linkLength()); + logline->setLinkStartSlop(link_logline->linkStartSlop()); + logline->setLinkEndSlop(link_logline->linkEndSlop()); + logline->setLinkId(link_logline->linkId()); + logline->setLinkEmbedded(false); + time=time.addMSecs(q->value(1).toInt()); + time_type=RDLogLine::Relative; + trans_type=event_default_transtype; + grace_time=-1; + q->seek(-1); + fit=true; + } + } + } + delete q; + } + + // + // Fill Check + // + if(event_autofill_slop>=0) { + int slop=QTime().msecsTo(end_time)-QTime().msecsTo(time); + if(abs(slop)>=event_autofill_slop) { + if(slop>0) { + *errors+=QString(). + sprintf(" %s -- \"%s\" is underscheduled by %s.\n", + (const char *)time.toString("hh:mm:ss"), + (const char *)event_name, + (const char *)QTime().addMSecs(slop). + toString("hh:mm:ss")); + } + else { + *errors+=QString(). + sprintf(" %s -- \"%s\" is overscheduled by %s.\n", + (const char *)time.toString("hh:mm:ss"), + (const char *)event_name, + (const char *)QTime().addMSecs(-slop). + toString("hh:mm:ss")); + } + } + } + + return false; +} + + +int RDEventLine::GetLength(unsigned cartnum,int def_length) +{ + RDCart *cart=new RDCart(cartnum); + if(!cart->exists()) { + delete cart; + return def_length; + } + int length=cart->forcedLength(); + delete cart; + return length; +} diff --git a/lib/rdevent_line.h b/lib/rdevent_line.h new file mode 100644 index 00000000..b34e783b --- /dev/null +++ b/lib/rdevent_line.h @@ -0,0 +1,118 @@ +// rdevent_line.h +// +// Abstract a Rivendell Log Manager Event +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdevent_line.h,v 1.18 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> +#include <qdatetime.h> + +#include <rdlog_event.h> +#include <rdlog_line.h> + + +#ifndef RDEVENT_LINE_H +#define RDEVENT_LINE_H + +class RDEventLine +{ + public: + enum ImportSource {None=0,Traffic=1,Music=2,Scheduler=3}; + enum InsertFirst {InsertNone=0,InsertBreak=1,InsertTrack=2}; + RDEventLine(); + QString name() const; + void setName(const QString &name); + QString properties() const; + void setProperties(const QString &str); + int preposition() const; + void setPreposition(int offset); + RDLogLine::TimeType timeType() const; + void setTimeType(RDLogLine::TimeType type); + int graceTime() const; + void setGraceTime(int offset); + bool postPoint() const; + void setPostPoint(bool state); + bool useAutofill() const; + void setUseAutofill(bool state); + int autofillSlop() const; + void setAutofillSlop(int slop); + bool useTimescale() const; + void setUseTimescale(bool state); + RDEventLine::ImportSource importSource() const; + void setImportSource(RDEventLine::ImportSource src); + int startSlop() const; + void setStartSlop(int slop); + int endSlop() const; + void setEndSlop(int slop); + RDLogLine::TransType firstTransType() const; + void setFirstTransType(RDLogLine::TransType trans); + RDLogLine::TransType defaultTransType() const; + void setDefaultTransType(RDLogLine::TransType trans); + QColor color() const; + void setColor(const QColor &color); + QString SchedGroup() const; + void setSchedGroup(QString str); + QString HaveCode() const; + void setHaveCode(QString str); + unsigned titleSep() const; + void setTitleSep(unsigned titlesep); + RDLogEvent *preimportCarts(); + RDLogEvent *postimportCarts(); + QTime startTime() const; + void setStartTime(const QTime &time); + int length() const; + void setLength(int msecs); + void clear(); + bool load(); + bool save(); + bool generateLog(QString logname,const QString &svcname, + QString *errors, unsigned artistsep,QString clockname); + bool linkLog(RDLogEvent *e,int next_id,const QString &svcname, + RDLogLine *link_logline,const QString &track_str, + const QString &label_cart,const QString &track_cart, + const QString &import_table,QString *errors); + + private: + int GetLength(unsigned cartnum,int def_length=0); + QString event_name; + QString event_properties; + int event_preposition; + RDLogLine::TimeType event_time_type; + int event_grace_time; + bool event_post_point; + bool event_use_autofill; + bool event_use_timescale; + RDEventLine::ImportSource event_import_source; + int event_start_slop; + int event_end_slop; + RDLogLine::TransType event_first_transtype; + RDLogLine::TransType event_default_transtype; + QColor event_color; + RDLogEvent *event_preimport_log; + RDLogEvent *event_postimport_log; + QTime event_start_time; + int event_length; + int event_autofill_slop; + QString event_nested_event; + QString event_sched_group; + QString event_have_code; + unsigned event_title_sep; +}; + +#endif diff --git a/lib/rdevent_player.cpp b/lib/rdevent_player.cpp new file mode 100644 index 00000000..f0efd964 --- /dev/null +++ b/lib/rdevent_player.cpp @@ -0,0 +1,94 @@ +// rdevent_player.cpp +// +// Execute a list of RML commands asynchronously. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdevent_player.cpp,v 1.6.8.1 2012/12/13 22:33:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdevent_player.h> + + +RDEventPlayer::RDEventPlayer(RDRipc *ripc,QObject *parent,const char *name) + : QObject(parent,name) +{ + player_ripc=ripc; + + for(unsigned i=0;i<RDEVENT_PLAYER_MAX_EVENTS;i++) { + player_events[i]=NULL; + player_state[i]=false; + } + player_mapper=new QSignalMapper(this,"player_mapper"); + connect(player_mapper,SIGNAL(mapped(int)), + this,SLOT(macroFinishedData(int))); + player_timer=new QTimer(this,"player_timer"); + connect(player_timer,SIGNAL(timeout()),this,SLOT(macroTimerData())); +} + + +RDEventPlayer::~RDEventPlayer() +{ +} + + +bool RDEventPlayer::exec(const QString &rml) +{ + bool ret=false; + + for(int i=0;i<RDEVENT_PLAYER_MAX_EVENTS;i++) { + if(player_events[i]==NULL) { + player_events[i]=new RDMacroEvent(player_ripc,this); + player_state[i]=true; + player_mapper->setMapping(player_events[i],i); + connect(player_events[i],SIGNAL(finished()), + player_mapper,SLOT(map())); + if(player_events[i]->load(rml)) { + player_events[i]->exec(); + ret=true; + } + i=RDEVENT_PLAYER_MAX_EVENTS; + } + } + return ret; +} + + +bool RDEventPlayer::exec(unsigned cartnum) +{ + if(cartnum==0) { + return false; + } + return exec(QString().sprintf("EX %u!",cartnum)); +} + + +void RDEventPlayer::macroFinishedData(int id) +{ + player_state[id]=false; + player_timer->start(1,true); +} + + +void RDEventPlayer::macroTimerData() +{ + for(int i=0;i<RDEVENT_PLAYER_MAX_EVENTS;i++) { + if((!player_state[i])&&(player_events[i]!=NULL)) { + delete player_events[i]; + player_events[i]=NULL; + } + } +} diff --git a/lib/rdevent_player.h b/lib/rdevent_player.h new file mode 100644 index 00000000..87975ef5 --- /dev/null +++ b/lib/rdevent_player.h @@ -0,0 +1,59 @@ +// rdevent_player.h +// +// Execute a list of RML commands asynchronously. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdevent_player.h,v 1.6 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qobject.h> +#include <qsignalmapper.h> +#include <qtimer.h> + +#include <rdmacro_event.h> +#include <rdmacro.h> +#include <rdripc.h> + + +#ifndef RDEVENT_PLAYER_H +#define RDEVENT_PLAYER_H + +#define RDEVENT_PLAYER_MAX_EVENTS 10 + +class RDEventPlayer : public QObject +{ + Q_OBJECT + public: + RDEventPlayer(RDRipc *ripc,QObject *parent=0,const char *name=0); + ~RDEventPlayer(); + bool exec(const QString &rml); + bool exec(unsigned cartnum); + + private slots: + void macroFinishedData(int id); + void macroTimerData(); + + private: + RDMacroEvent *player_events[RDEVENT_PLAYER_MAX_EVENTS]; + bool player_state[RDEVENT_PLAYER_MAX_EVENTS]; + RDRipc *player_ripc; + QSignalMapper *player_mapper; + QTimer *player_timer; +}; + + +#endif // RDEVENT_PLAYER_H diff --git a/lib/rdexception_dialog.cpp b/lib/rdexception_dialog.cpp new file mode 100644 index 00000000..d58d146c --- /dev/null +++ b/lib/rdexception_dialog.cpp @@ -0,0 +1,134 @@ +// rdexception_dialog.cpp +// +// A dialog for displaying exception reports. +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdexception_dialog.cpp,v 1.8 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qpushbutton.h> +#include <qfiledialog.h> +#include <qmessagebox.h> + +#include <rdconf.h> +#include <rdexception_dialog.h> + + +RDExceptionDialog::RDExceptionDialog(QString report, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + setCaption(tr("Rivendell Exception Report")); + + // + // Generate Fonts + // + QFont button_font("helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + + // + // Report Viewer + // + report_view=new QTextView(this,"report_view"); + report_view->setGeometry(10,10,sizeHint().width()-20,sizeHint().height()-80); + report_view->setText(report); + + // + // Save Button + // + QPushButton *button=new QPushButton(this,"save_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setText(tr("&Save")); + button->setFont(button_font); + connect(button,SIGNAL(clicked()),this,SLOT(saveData())); + + // + // Close Button + // + button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setText(tr("&Close")); + button->setFont(button_font); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +RDExceptionDialog::~RDExceptionDialog() +{ +} + + +QSize RDExceptionDialog::sizeHint() const +{ + return QSize(400,300); +} + + +QSizePolicy RDExceptionDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDExceptionDialog::saveData() +{ + QString str1; + QString str2; + QString filename=QFileDialog::getSaveFileName(RDGetHomeDir(), + tr("Text (*.txt *.TXT)\nAll Files (*.*)"), + this,tr("Export File")); + if(filename.isEmpty()) { + return; + } + if(filename.find(".")<0) { + filename+=".txt"; + } + QFile file(filename); + if(file.exists()) { + str1=QString(tr("The file")); + str2=QString(tr("already exists!\nOverwrite?")); + if(QMessageBox::question(this,tr("File Exists"), + QString().sprintf("%s \'%s\' %s", + (const char *)str1, + (const char *)filename, + (const char *)str2), + QMessageBox::Yes,QMessageBox::No)== + QMessageBox::No) { + return; + } + } + FILE *fh=fopen((const char *)filename,"w"); + if(fh==NULL) { + str1=QString(tr("Unable to open file")); + str2=QString(tr("for writing!")); + QMessageBox:: + warning(this,tr("File Error"),QString(). + sprintf("%s \'%s\' %s!",(const char *)str1, + (const char *)filename,(const char *)str2)); + return; + } + fprintf(fh,(const char *)report_view->text()); + fclose(fh); +} + + +void RDExceptionDialog::closeData() +{ + done(0); +} diff --git a/lib/rdexception_dialog.h b/lib/rdexception_dialog.h new file mode 100644 index 00000000..eab8ed38 --- /dev/null +++ b/lib/rdexception_dialog.h @@ -0,0 +1,48 @@ +// rdexception_dialog.h +// +// A dialog for displaying exception reports. +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdexception_dialog.h,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDEXCEPTION_DIALOG_H +#define RDEXCEPTION_DIALOG_H + +#include <qdialog.h> +#include <qtextview.h> + + +class RDExceptionDialog : public QDialog +{ + Q_OBJECT + public: + RDExceptionDialog(QString report,QWidget *parent=0,const char *name=0); + ~RDExceptionDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void saveData(); + void closeData(); + + private: + QTextView *report_view; +}; + + +#endif diff --git a/lib/rdexport_settings_dialog.cpp b/lib/rdexport_settings_dialog.cpp new file mode 100644 index 00000000..e753b1c5 --- /dev/null +++ b/lib/rdexport_settings_dialog.cpp @@ -0,0 +1,936 @@ +// rdexport_settings_dialog.cpp +// +// Edit RDLibrary Settings +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdexport_settings_dialog.cpp,v 1.12.8.1 2012/12/13 22:33:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qdialog.h> +#include <qstring.h> +#include <qpushbutton.h> +#include <qlistbox.h> +#include <qtextedit.h> +#include <qevent.h> +#include <qmessagebox.h> +#include <qcheckbox.h> +#include <qbuttongroup.h> +#include <math.h> + +#include <rdexport_settings_dialog.h> + + +RDExportSettingsDialog::RDExportSettingsDialog(RDSettings *settings, + RDStation *station, + QWidget *parent, + const char *name) + : QDialog(parent,name,true) +{ + lib_settings=settings; + lib_station=station; + + // + // Generate Fonts + // + QFont button_font("helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + + // + // Dialog Name + // + setCaption(tr("Edit Export Settings")); + + // + // Custom Encoders + // + lib_encoders=new RDEncoderList(station->name()); + + // + // Default Format + // + lib_format_box=new QComboBox(this,"lib_format_box"); + lib_format_box->setGeometry(100,10,150,19); + connect(lib_format_box,SIGNAL(activated(const QString &)), + this,SLOT(formatData(const QString &))); + QLabel *lib_format_label=new QLabel(lib_format_box,"Format:",this, + "lib_format_label"); + lib_format_label->setGeometry(25,10,70,19); + lib_format_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Default Channels + // + lib_channels_box=new QComboBox(this,"lib_channels_box"); + lib_channels_box->setGeometry(100,32,60,19); + QLabel *lib_channels_label= + new QLabel(lib_channels_box,tr("&Channels:"),this, + "lib_channels_label"); + lib_channels_label->setGeometry(25,32,70,19); + lib_channels_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Default Sample Rate + // + lib_samprate_box=new QComboBox(this,"lib_samprate_box"); + lib_samprate_box->setGeometry(100,54,100,19); + connect(lib_samprate_box,SIGNAL(activated(const QString &)), + this,SLOT(samprateData(const QString &))); + QLabel *lib_samprate_label= + new QLabel(lib_samprate_box,tr("&Sample Rate:"),this, + "lib_samprate_label"); + lib_samprate_label->setGeometry(25,54,75,19); + lib_samprate_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Default Bitrate + // + lib_bitrate_box=new QComboBox(this,"lib_bitrate_box"); + lib_bitrate_box->setGeometry(100,76,100,19); + connect(lib_bitrate_box,SIGNAL(activated(const QString &)), + this,SLOT(bitrateData(const QString &))); + lib_bitrate_label=new QLabel(lib_bitrate_box,tr("&Bitrate:"),this, + "lib_bitrate_label"); + lib_bitrate_label->setGeometry(25,76,70,19); + lib_bitrate_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Quality + // + lib_quality_spin=new QSpinBox(this,"lib_quality_box"); + lib_quality_spin->setGeometry(100,98,50,19); + lib_quality_spin->setRange(0,10); + lib_quality_label=new QLabel(lib_quality_spin,tr("&Quality:"),this, + "lib_quality_label"); + lib_quality_label->setGeometry(25,98,70,19); + lib_quality_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(button_font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(button_font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + lib_format_box->insertItem(tr("PCM16")); + if(settings->format()==RDSettings::Pcm16) { + lib_format_box->setCurrentItem(lib_format_box->count()-1); + } + if(station->haveCapability(RDStation::HaveFlac)) { + lib_format_box->insertItem(tr("FLAC")); + if(settings->format()==RDSettings::Flac) { + lib_format_box->setCurrentItem(lib_format_box->count()-1); + } + } + lib_format_box->insertItem(tr("MPEG Layer 2")); + if(settings->format()==RDSettings::MpegL2) { + lib_format_box->setCurrentItem(lib_format_box->count()-1); + } + if(station->haveCapability(RDStation::HaveLame)) { + lib_format_box->insertItem(tr("MPEG Layer 3")); + if(settings->format()==RDSettings::MpegL3) { + lib_format_box->setCurrentItem(lib_format_box->count()-1); + } + } + if(station->haveCapability(RDStation::HaveOggenc)) { + lib_format_box->insertItem(tr("OggVorbis")); + if(settings->format()==RDSettings::OggVorbis) { + lib_format_box->setCurrentItem(lib_format_box->count()-1); + } + } + for(unsigned i=0;i<lib_encoders->encoderQuantity();i++) { + lib_format_box->insertItem(lib_encoders->encoder(i)->name()); + if(settings->format()==lib_encoders->encoder(i)->id()) { + lib_format_box->setCurrentItem(lib_format_box->count()-1); + } + } + lib_channels_box->insertItem("1"); + lib_channels_box->insertItem("2"); + lib_channels_box->setCurrentItem(lib_settings->channels()-1); + lib_samprate_box->insertItem("16000"); + lib_samprate_box->insertItem("22050"); + lib_samprate_box->insertItem("24000"); + lib_samprate_box->insertItem("32000"); + lib_samprate_box->insertItem("44100"); + lib_samprate_box->insertItem("48000"); + for(int i=0;i<lib_samprate_box->count();i++) { + if(lib_samprate_box->text(i).toUInt()==lib_settings->sampleRate()) { + lib_samprate_box->setCurrentItem(i); + } + } + ShowBitRates(lib_settings->format(),lib_settings->sampleRate(), + lib_settings->bitRate(),lib_settings->quality()); +} + + +RDExportSettingsDialog::~RDExportSettingsDialog() +{ + delete lib_encoders; + delete lib_channels_box; + delete lib_samprate_box; + delete lib_bitrate_box; +} + + +QSize RDExportSettingsDialog::sizeHint() const +{ + return QSize(275,190); +} + + +QSizePolicy RDExportSettingsDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDExportSettingsDialog::formatData(const QString &str) +{ + RDSettings::Format fmt=RDSettings::Pcm16; + + fmt=GetFormat(str); + bool ok; + unsigned bitrate=lib_bitrate_box->currentText().toUInt(&ok); + if(!ok) { + bitrate=0; + } + ShowBitRates(fmt,lib_samprate_box->currentText().toInt(), + bitrate,lib_quality_spin->value()); +} + + +void RDExportSettingsDialog::samprateData(const QString &str) +{ + ShowBitRates(GetFormat(lib_format_box->currentText()),str.toInt(), + lib_bitrate_box->currentText().replace("kbps","").toInt(), + lib_quality_spin->value()); +} + +void RDExportSettingsDialog::bitrateData(const QString &str) +{ + lib_quality_label->setEnabled(str==tr("VBR")); + lib_quality_spin->setEnabled(str==tr("VBR")); +} + + +void RDExportSettingsDialog::okData() +{ + unsigned rate=0; + + lib_settings->setFormat(GetFormat(lib_format_box->currentText())); + lib_settings->setChannels(lib_channels_box->currentItem()+1); + lib_settings->setSampleRate(lib_samprate_box->currentText().toInt()); + switch(lib_settings->format()) { + case RDSettings::Pcm16: + lib_settings->setBitRate(0); + lib_settings->setQuality(0); + break; + + case RDSettings::MpegL1: + case RDSettings::MpegL2: + case RDSettings::MpegL3: + if (lib_bitrate_box && lib_bitrate_box->currentText()){ + sscanf(lib_bitrate_box->currentText(),"%d",&rate); + } + if(rate!=0) { + lib_settings->setBitRate(1000*rate); + lib_settings->setQuality(0); + } + else { + lib_settings->setBitRate(0); + lib_quality_spin->setRange(0,9); + lib_settings->setQuality(lib_quality_spin->value()); + } + break; + + case RDSettings::Flac: + lib_settings->setBitRate(0); + lib_settings->setQuality(0); + break; + + case RDSettings::OggVorbis: + lib_settings->setBitRate(0); + lib_quality_spin->setRange(-1,10); + lib_settings->setQuality(lib_quality_spin->value()); + break; + + default: // Custom format + for(unsigned i=0;i<lib_encoders->encoderQuantity();i++) { + if(lib_encoders->encoder(i)->id()==lib_settings->format()) { + lib_settings->setFormatName(lib_encoders->encoder(i)->name()); + lib_settings-> + setCustomCommandLine(lib_encoders->encoder(i)->commandLine()); + } + } + if(lib_channels_box->isEnabled()) { + lib_settings->setChannels(lib_channels_box->currentText().toUInt()); + } + else { + lib_settings->setChannels(0); + } + if(lib_samprate_box->isEnabled()) { + lib_settings->setSampleRate(lib_samprate_box->currentText().toUInt()); + } + else { + lib_settings->setSampleRate(0); + } + if(lib_bitrate_box->isEnabled()) { + sscanf(lib_bitrate_box->currentText(),"%d",&rate); + } + if(rate!=0) { + lib_settings->setBitRate(1000*rate); + lib_settings->setQuality(0); + } + else { + lib_settings->setBitRate(0); + } + + break; + } + done(0); +} + + +void RDExportSettingsDialog::cancelData() +{ + done(1); +} + + +void RDExportSettingsDialog::ShowBitRates(RDSettings::Format fmt, + int new_samprate, + int bitrate,int qual) +{ + RDEncoder *encoder; + + int samprate=lib_samprate_box->currentText().toInt(); + int channels=lib_channels_box->currentText().toInt(); + lib_channels_box->clear(); + lib_samprate_box->clear(); + lib_bitrate_box->clear(); + switch(fmt) { + case RDSettings::Pcm16: // PCM16 + lib_channels_box->insertItem("1"); + lib_channels_box->insertItem("2"); + lib_samprate_box->insertItem("32000"); + lib_samprate_box->insertItem("44100"); + lib_samprate_box->insertItem("48000"); + lib_bitrate_box->setDisabled(true); + lib_bitrate_label->setDisabled(true); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case RDSettings::MpegL1: // MPEG-1 Layer 1 + lib_channels_box->insertItem("1"); + lib_channels_box->insertItem("2"); + lib_samprate_box->insertItem("16000"); + lib_samprate_box->insertItem("22050"); + lib_samprate_box->insertItem("32000"); + lib_samprate_box->insertItem("44100"); + lib_samprate_box->insertItem("48000"); + lib_bitrate_box->setEnabled(true); + lib_bitrate_label->setEnabled(true); + lib_bitrate_box->insertItem(tr("32 kbps")); + lib_bitrate_box->insertItem(tr("64 kbps")); + lib_bitrate_box->insertItem(tr("96 kbps")); + lib_bitrate_box->insertItem(tr("128 kbps")); + lib_bitrate_box->insertItem(tr("160 kbps")); + lib_bitrate_box->insertItem(tr("192 kbps")); + lib_bitrate_box->insertItem(tr("224 kbps")); + lib_bitrate_box->insertItem(tr("256 kbps")); + lib_bitrate_box->insertItem(tr("288 kbps")); + lib_bitrate_box->insertItem(tr("320 kbps")); + lib_bitrate_box->insertItem(tr("352 kbps")); + lib_bitrate_box->insertItem(tr("384 kbps")); + lib_bitrate_box->insertItem(tr("416 kbps")); + lib_bitrate_box->insertItem(tr("448 kbps")); + lib_bitrate_box->insertItem(tr("VBR")); + switch(bitrate) { + case 0: + lib_bitrate_box->setCurrentItem(14); + lib_quality_spin->setEnabled(true); + lib_quality_label->setEnabled(true); + lib_quality_spin->setValue(qual); + lib_quality_spin->setRange(0,9); + break; + + case 32000: + lib_bitrate_box->setCurrentItem(0); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 64000: + lib_bitrate_box->setCurrentItem(1); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 96000: + lib_bitrate_box->setCurrentItem(2); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 128000: + lib_bitrate_box->setCurrentItem(3); + lib_quality_label->setDisabled(true); + lib_quality_spin->setDisabled(true); + break; + + case 160000: + lib_bitrate_box->setCurrentItem(4); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 192000: + lib_bitrate_box->setCurrentItem(5); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 224000: + lib_bitrate_box->setCurrentItem(6); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 256000: + lib_bitrate_box->setCurrentItem(7); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 288000: + lib_bitrate_box->setCurrentItem(8); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 320000: + lib_bitrate_box->setCurrentItem(9); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 352000: + lib_bitrate_box->setCurrentItem(10); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 384000: + lib_bitrate_box->setCurrentItem(11); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 416000: + lib_bitrate_box->setCurrentItem(12); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 448000: + lib_bitrate_box->setCurrentItem(13); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + } + break; + + case RDSettings::MpegL2: // MPEG-1 Layer 2 + lib_channels_box->insertItem("1"); + lib_channels_box->insertItem("2"); + lib_samprate_box->insertItem("16000"); + lib_samprate_box->insertItem("22050"); + lib_samprate_box->insertItem("32000"); + lib_samprate_box->insertItem("44100"); + lib_samprate_box->insertItem("48000"); + lib_bitrate_box->setEnabled(true); + lib_bitrate_label->setEnabled(true); + lib_bitrate_box->insertItem(tr("32 kbps")); + lib_bitrate_box->insertItem(tr("48 kbps")); + lib_bitrate_box->insertItem(tr("56 kbps")); + lib_bitrate_box->insertItem(tr("64 kbps")); + lib_bitrate_box->insertItem(tr("80 kbps")); + lib_bitrate_box->insertItem(tr("96 kbps")); + lib_bitrate_box->insertItem(tr("112 kbps")); + lib_bitrate_box->insertItem(tr("128 kbps")); + lib_bitrate_box->insertItem(tr("160 kbps")); + lib_bitrate_box->insertItem(tr("192 kbps")); + lib_bitrate_box->insertItem(tr("224 kbps")); + lib_bitrate_box->insertItem(tr("256 kbps")); + lib_bitrate_box->insertItem(tr("320 kbps")); + lib_bitrate_box->insertItem(tr("384 kbps")); + switch(bitrate) { + case 0: + lib_bitrate_box->setCurrentItem(11); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 32000: + lib_bitrate_box->setCurrentItem(0); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 48000: + lib_bitrate_box->setCurrentItem(1); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 56000: + lib_bitrate_box->setCurrentItem(2); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 64000: + lib_bitrate_box->setCurrentItem(3); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 80000: + lib_bitrate_box->setCurrentItem(4); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 96000: + lib_bitrate_box->setCurrentItem(5); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 112000: + lib_bitrate_box->setCurrentItem(6); + lib_quality_label->setDisabled(true); + lib_quality_spin->setDisabled(true); + break; + + case 128000: + lib_bitrate_box->setCurrentItem(7); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 160000: + lib_bitrate_box->setCurrentItem(8); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 192000: + lib_bitrate_box->setCurrentItem(9); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 224000: + lib_bitrate_box->setCurrentItem(10); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 256000: + lib_bitrate_box->setCurrentItem(11); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 320000: + lib_bitrate_box->setCurrentItem(12); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 384000: + lib_bitrate_box->setCurrentItem(13); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + } + break; + + case RDSettings::MpegL3: // MPEG-1 Layer 3 + lib_channels_box->insertItem("1"); + lib_channels_box->insertItem("2"); + lib_samprate_box->insertItem("32000"); + lib_samprate_box->insertItem("44100"); + lib_samprate_box->insertItem("48000"); + lib_bitrate_box->setEnabled(true); + lib_bitrate_label->setEnabled(true); + switch(samprate) { + case 32000: + case 44100: + case 48000: + default: + lib_bitrate_box->insertItem(tr("32 kbps")); + lib_bitrate_box->insertItem(tr("40 kbps")); + lib_bitrate_box->insertItem(tr("48 kbps")); + lib_bitrate_box->insertItem(tr("56 kbps")); + lib_bitrate_box->insertItem(tr("64 kbps")); + lib_bitrate_box->insertItem(tr("80 kbps")); + lib_bitrate_box->insertItem(tr("96 kbps")); + lib_bitrate_box->insertItem(tr("112 kbps")); + lib_bitrate_box->insertItem(tr("128 kbps")); + lib_bitrate_box->insertItem(tr("160 kbps")); + lib_bitrate_box->insertItem(tr("192 kbps")); + lib_bitrate_box->insertItem(tr("224 kbps")); + lib_bitrate_box->insertItem(tr("256 kbps")); + lib_bitrate_box->insertItem(tr("320 kbps")); + lib_bitrate_box->insertItem(tr("VBR")); + switch(bitrate) { + case 0: + lib_bitrate_box->setCurrentItem(14); + lib_quality_spin->setEnabled(true); + lib_quality_label->setEnabled(true); + lib_quality_spin->setRange(0,9); + lib_quality_spin->setValue(qual); + break; + + case 32000: + lib_bitrate_box->setCurrentItem(0); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 40000: + lib_bitrate_box->setCurrentItem(1); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 48000: + lib_bitrate_box->setCurrentItem(2); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 56000: + lib_bitrate_box->setCurrentItem(3); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 64000: + lib_bitrate_box->setCurrentItem(4); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 80000: + lib_bitrate_box->setCurrentItem(5); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 96000: + lib_bitrate_box->setCurrentItem(6); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 112000: + lib_bitrate_box->setCurrentItem(7); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 128000: + lib_bitrate_box->setCurrentItem(8); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 160000: + lib_bitrate_box->setCurrentItem(9); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 192000: + lib_bitrate_box->setCurrentItem(10); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 224000: + lib_bitrate_box->setCurrentItem(11); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 256000: + lib_bitrate_box->setCurrentItem(12); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 320000: + lib_bitrate_box->setCurrentItem(13); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + } + break; + + case 16000: + case 22050: + case 24000: + lib_bitrate_box->insertItem(tr("8 kbps")); + lib_bitrate_box->insertItem(tr("16 kbps")); + lib_bitrate_box->insertItem(tr("24 kbps")); + lib_bitrate_box->insertItem(tr("32 kbps")); + lib_bitrate_box->insertItem(tr("40 kbps")); + lib_bitrate_box->insertItem(tr("48 kbps")); + lib_bitrate_box->insertItem(tr("56 kbps")); + lib_bitrate_box->insertItem(tr("64 kbps")); + lib_bitrate_box->insertItem(tr("80 kbps")); + lib_bitrate_box->insertItem(tr("96 kbps")); + lib_bitrate_box->insertItem(tr("112 kbps")); + lib_bitrate_box->insertItem(tr("128 kbps")); + lib_bitrate_box->insertItem(tr("144 kbps")); + lib_bitrate_box->insertItem(tr("160 kbps")); + lib_bitrate_box->insertItem(tr("VBR")); + switch(bitrate) { + case 0: + lib_bitrate_box->setCurrentItem(14); + lib_quality_spin->setEnabled(true); + lib_quality_label->setEnabled(true); + lib_quality_spin->setRange(0,9); + lib_quality_spin->setValue(qual); + break; + + case 8000: + lib_bitrate_box->setCurrentItem(0); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 16000: + lib_bitrate_box->setCurrentItem(1); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 24000: + lib_bitrate_box->setCurrentItem(2); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 32000: + lib_bitrate_box->setCurrentItem(3); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 40000: + lib_bitrate_box->setCurrentItem(4); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 48000: + lib_bitrate_box->setCurrentItem(5); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 56000: + lib_bitrate_box->setCurrentItem(6); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 64000: + lib_bitrate_box->setCurrentItem(7); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 80000: + lib_bitrate_box->setCurrentItem(8); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 96000: + lib_bitrate_box->setCurrentItem(9); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 112000: + lib_bitrate_box->setCurrentItem(10); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 128000: + lib_bitrate_box->setCurrentItem(11); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 144000: + lib_bitrate_box->setCurrentItem(12); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case 160000: + lib_bitrate_box->setCurrentItem(13); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + } + break; + } + break; + + case RDSettings::Flac: + lib_channels_box->insertItem("1"); + lib_channels_box->insertItem("2"); + lib_samprate_box->insertItem("32000"); + lib_samprate_box->insertItem("44100"); + lib_samprate_box->insertItem("48000"); + lib_bitrate_box->setDisabled(true); + lib_bitrate_label->setDisabled(true); + lib_quality_spin->setDisabled(true); + lib_quality_label->setDisabled(true); + break; + + case RDSettings::OggVorbis: + lib_channels_box->insertItem("1"); + lib_channels_box->insertItem("2"); + lib_samprate_box->insertItem("32000"); + lib_samprate_box->insertItem("44100"); + lib_samprate_box->insertItem("48000"); + lib_bitrate_box->setDisabled(true); + lib_bitrate_label->setDisabled(true); + lib_quality_spin->setEnabled(true); + lib_quality_label->setEnabled(true); + lib_quality_spin->setRange(-1,10); + lib_quality_spin->setValue(qual); + break; + + default: // Custom format + lib_channels_box->clear(); + lib_samprate_box->clear(); + lib_bitrate_box->clear(); + for(unsigned i=0;i<lib_encoders->encoderQuantity();i++) { + encoder=lib_encoders->encoder(i); + if(encoder->id()==fmt) { + if(encoder->allowedChannelsQuantity()==0) { + lib_channels_box->setDisabled(true); + } + else { + lib_channels_box->setEnabled(true); + for(int j=0;j<encoder->allowedChannelsQuantity();j++) { + lib_channels_box-> + insertItem(QString().sprintf("%d",encoder->allowedChannel(j))); + } + } + if(encoder->allowedSampleratesQuantity()==0) { + lib_samprate_box->setDisabled(true); + } + else { + lib_samprate_box->setEnabled(true); + for(int j=0;j<encoder->allowedSampleratesQuantity();j++) { + lib_samprate_box-> + insertItem(QString().sprintf("%d", + encoder->allowedSamplerate(j))); + } + } + if(encoder->allowedBitratesQuantity()==0) { + lib_bitrate_box->setDisabled(true); + } + else { + lib_bitrate_box->setEnabled(true); + for(int j=0;j<encoder->allowedBitratesQuantity();j++) { + lib_bitrate_box-> + insertItem(QString().sprintf("%d kbps", + encoder->allowedBitrate(j))); + } + } + } + } + break; + } + SetCurrentItem(lib_channels_box,channels); + SetCurrentItem(lib_samprate_box,samprate); +} + + +void RDExportSettingsDialog::SetCurrentItem(QComboBox *box,int value) +{ + for(int i=0;i<box->count();i++) { + if(box->text(i).toInt()==value) { + box->setCurrentItem(i); + } + } +} + + +RDSettings::Format RDExportSettingsDialog::GetFormat(QString str) +{ + if(str==tr("PCM16")) { + return RDSettings::Pcm16; + } + if(str==tr("FLAC")) { + return RDSettings::Flac; + } + if(str==tr("MPEG Layer 2")) { + return RDSettings::MpegL2; + } + if(str==tr("MPEG Layer 3")) { + return RDSettings::MpegL3; + } + if(str==tr("OggVorbis")) { + return RDSettings::OggVorbis; + } + for(unsigned i=0;i<lib_encoders->encoderQuantity();i++) { + if(str==lib_encoders->encoder(i)->name()) { + return (RDSettings::Format)lib_encoders->encoder(i)->id(); + } + } + return RDSettings::Pcm16; +} + diff --git a/lib/rdexport_settings_dialog.h b/lib/rdexport_settings_dialog.h new file mode 100644 index 00000000..1538215c --- /dev/null +++ b/lib/rdexport_settings_dialog.h @@ -0,0 +1,72 @@ +// rdexport_settings_dialog.h +// +// Edit Rivendell Audio Settings +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdexport_settings_dialog.h,v 1.8 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDEXPORT_SETTINGS_DIALOG_H +#define RDEXPORT_SETTINGS_DIALOG_H + +#include <qdialog.h> +#include <qsqldatabase.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qspinbox.h> +#include <qlabel.h> + +#include <rdsettings.h> +#include <rdstation.h> +#include <rdencoderlist.h> + +class RDExportSettingsDialog : public QDialog +{ + Q_OBJECT + public: + RDExportSettingsDialog(RDSettings *settings,RDStation *station, + QWidget *parent=0,const char *name=0); + ~RDExportSettingsDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void formatData(const QString &); + void samprateData(const QString &); + void bitrateData(const QString &); + void okData(); + void cancelData(); + + private: + void ShowBitRates(RDSettings::Format fmt,int samprate,int bitrate,int qual); + void SetCurrentItem(QComboBox *box,int value); + RDSettings::Format GetFormat(QString str); + RDEncoderList *lib_encoders; + RDSettings *lib_settings; + RDStation *lib_station; + QComboBox *lib_format_box; + QComboBox *lib_channels_box; + QLabel *lib_bitrate_label; + QComboBox *lib_bitrate_box; + QComboBox *lib_samprate_box; + QLabel *lib_quality_label; + QSpinBox *lib_quality_spin; +}; + + +#endif + diff --git a/lib/rdfeed.cpp b/lib/rdfeed.cpp new file mode 100644 index 00000000..86f5b727 --- /dev/null +++ b/lib/rdfeed.cpp @@ -0,0 +1,902 @@ +// rdfeed.cpp +// +// Abstract a Rivendell RSS Feed +// +// (C) Copyright 2002-2007,2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdfeed.cpp,v 1.17.2.2 2013/11/13 23:36:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <math.h> + +#include <qfile.h> +#include <qurl.h> +#include <qapplication.h> + +#include <rddb.h> +#include <rdfeed.h> +#include <rdconf.h> +#include <rdlibrary_conf.h> +#include <rdescape_string.h> +#include <rdwavefile.h> +#include <rdpodcast.h> +#include <rdcart.h> +#include <rdcut.h> +#include <rdaudioexport.h> +#include <rdaudioconvert.h> +#include <rdupload.h> + +RDFeed::RDFeed(const QString &keyname,QObject *parent,const char *name) + : QObject(parent,name) +{ + RDSqlQuery *q; + QString sql; + + feed_keyname=keyname; + + sql=QString().sprintf("select ID from FEEDS where KEY_NAME=\"%s\"", + (const char *)RDEscapeString(keyname)); + q=new RDSqlQuery(sql); + if(q->first()) { + feed_id=q->value(0).toUInt(); + } + delete q; +} + + +RDFeed::RDFeed(unsigned id,QObject *parent,const char *name) + : QObject(parent,name) +{ + RDSqlQuery *q; + QString sql; + + feed_id=id; + + sql=QString().sprintf("select KEY_NAME from FEEDS where ID=%u",id); + q=new RDSqlQuery(sql); + if(q->first()) { + feed_keyname=q->value(0).toString(); + } + delete q; +} + + +bool RDFeed::exists() const +{ + return RDDoesRowExist("FEEDS","NAME",feed_keyname); +} + + +QString RDFeed::keyName() const +{ + return feed_keyname; +} + + +unsigned RDFeed::id() const +{ + return feed_id; +} + + +QString RDFeed::channelTitle() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"CHANNEL_TITLE"). + toString(); +} + + +void RDFeed::setChannelTitle(const QString &str) const +{ + SetRow("CHANNEL_TITLE",str); +} + + +QString RDFeed::channelDescription() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"CHANNEL_DESCRIPTION"). + toString(); +} + + +void RDFeed::setChannelDescription(const QString &str) const +{ + SetRow("CHANNEL_DESCRIPTION",str); +} + + +QString RDFeed::channelCategory() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"CHANNEL_CATEGORY"). + toString(); +} + + +void RDFeed::setChannelCategory(const QString &str) const +{ + SetRow("CHANNEL_CATEGORY",str); +} + + +QString RDFeed::channelLink() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"CHANNEL_LINK"). + toString(); +} + + +void RDFeed::setChannelLink(const QString &str) const +{ + SetRow("CHANNEL_LINK",str); +} + + +QString RDFeed::channelCopyright() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"CHANNEL_COPYRIGHT"). + toString(); +} + + +void RDFeed::setChannelCopyright(const QString &str) const +{ + SetRow("CHANNEL_COPYRIGHT",str); +} + + +QString RDFeed::channelWebmaster() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"CHANNEL_WEBMASTER"). + toString(); +} + + + +void RDFeed::setChannelWebmaster(const QString &str) const +{ + SetRow("CHANNEL_WEBMASTER",str); +} + + +QString RDFeed::channelLanguage() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"CHANNEL_LANGUAGE"). + toString(); +} + + +void RDFeed::setChannelLanguage(const QString &str) +{ + SetRow("CHANNEL_LANGUAGE",str); +} + + +QString RDFeed::baseUrl() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"BASE_URL"). + toString(); +} + + +void RDFeed::setBaseUrl(const QString &str) const +{ + SetRow("BASE_URL",str); +} + + +QString RDFeed::basePreamble() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"BASE_PREAMBLE"). + toString(); +} + + +void RDFeed::setBasePreamble(const QString &str) const +{ + SetRow("BASE_PREAMBLE",str); +} + + +QString RDFeed::purgeUrl() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"PURGE_URL"). + toString(); +} + + +void RDFeed::setPurgeUrl(const QString &str) const +{ + SetRow("PURGE_URL",str); +} + + +QString RDFeed::purgeUsername() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"PURGE_USERNAME"). + toString(); +} + + +void RDFeed::setPurgeUsername(const QString &str) const +{ + SetRow("PURGE_USERNAME",str); +} + + +QString RDFeed::purgePassword() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"PURGE_PASSWORD"). + toString(); +} + + +void RDFeed::setPurgePassword(const QString &str) const +{ + SetRow("PURGE_PASSWORD",str); +} + + +QString RDFeed::headerXml() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"HEADER_XML"). + toString(); +} + + +void RDFeed::setHeaderXml(const QString &str) +{ + SetRow("HEADER_XML",str); +} + + +QString RDFeed::channelXml() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"CHANNEL_XML"). + toString(); +} + + +void RDFeed::setChannelXml(const QString &str) +{ + SetRow("CHANNEL_XML",str); +} + + +QString RDFeed::itemXml() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"ITEM_XML"). + toString(); +} + + +void RDFeed::setItemXml(const QString &str) +{ + SetRow("ITEM_XML",str); +} + + +bool RDFeed::castOrder() const +{ + return RDBool(RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname, + "CAST_ORDER").toString()); +} + + +void RDFeed::setCastOrder(bool state) const +{ + SetRow("CAST_ORDER",RDYesNo(state)); +} + + +int RDFeed::maxShelfLife() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"MAX_SHELF_LIFE").toInt(); +} + + +void RDFeed::setMaxShelfLife(int days) +{ + SetRow("MAX_SHELF_LIFE",days); +} + + +QDateTime RDFeed::lastBuildDateTime() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"LAST_BUILD_DATETIME"). + toDateTime(); +} + + +void RDFeed::setLastBuildDateTime(const QDateTime &datetime) const +{ + SetRow("LAST_BUILD_DATETIME",datetime.toString("yyyy-MM-dd hh:mm:ss")); +} + + +QDateTime RDFeed::originDateTime() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"ORIGIN_DATETIME"). + toDateTime(); +} + + +void RDFeed::setOriginDateTime(const QDateTime &datetime) const +{ + SetRow("ORIGIN_DATETIME",datetime.toString("yyyy-MM-dd hh:mm:ss")); +} + + +bool RDFeed::enableAutopost() const +{ + return RDBool(RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname, + "ENABLE_AUTOPOST").toString()); +} + + +void RDFeed::setEnableAutopost(bool state) const +{ + SetRow("ENABLE_AUTOPOST",RDYesNo(state)); +} + + +bool RDFeed::keepMetadata() const +{ + return RDBool(RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname, + "KEEP_METADATA").toString()); +} + + +void RDFeed::setKeepMetadata(bool state) +{ + SetRow("KEEP_METADATA",RDYesNo(state)); +} + + +RDSettings::Format RDFeed::uploadFormat() const +{ + return (RDSettings::Format)RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname, + "UPLOAD_FORMAT").toInt(); +} + + +void RDFeed::setUploadFormat(RDSettings::Format fmt) const +{ + SetRow("UPLOAD_FORMAT",(int)fmt); +} + + +int RDFeed::uploadChannels() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"UPLOAD_CHANNELS"). + toInt(); +} + + +void RDFeed::setUploadChannels(int chans) const +{ + SetRow("UPLOAD_CHANNELS",chans); +} + + +int RDFeed::uploadQuality() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"UPLOAD_QUALITY"). + toInt(); +} + + +void RDFeed::setUploadQuality(int qual) const +{ + SetRow("UPLOAD_QUALITY",qual); +} + + +int RDFeed::uploadBitRate() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"UPLOAD_BITRATE"). + toInt(); +} + + +void RDFeed::setUploadBitRate(int rate) const +{ + SetRow("UPLOAD_BITRATE",rate); +} + + +int RDFeed::uploadSampleRate() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"UPLOAD_SAMPRATE"). + toInt(); +} + + +void RDFeed::setUploadSampleRate(int rate) const +{ + SetRow("UPLOAD_SAMPRATE",rate); +} + + +QString RDFeed::uploadExtension() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"UPLOAD_EXTENSION"). + toString(); +} + + +void RDFeed::setUploadExtension(const QString &str) +{ + SetRow("UPLOAD_EXTENSION",str); +} + + +QString RDFeed::uploadMimetype() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"UPLOAD_MIMETYPE"). + toString(); +} + + +void RDFeed::setUploadMimetype(const QString &str) +{ + SetRow("UPLOAD_MIMETYPE",str); +} + + +int RDFeed::normalizeLevel() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"NORMALIZE_LEVEL"). + toInt(); +} + + +void RDFeed::setNormalizeLevel(int lvl) const +{ + SetRow("NORMALIZE_LEVEL",lvl); +} + + +QString RDFeed::redirectPath() const +{ + return RDGetSqlValue("FEEDS","KEY_NAME",feed_keyname,"REDIRECT_PATH"). + toString(); +} + + +void RDFeed::setRedirectPath(const QString &str) +{ + SetRow("REDIRECT_PATH",str); +} + + +RDFeed::MediaLinkMode RDFeed::mediaLinkMode() const +{ + return (RDFeed::MediaLinkMode)RDGetSqlValue("FEEDS","KEY_NAME", + feed_keyname,"MEDIA_LINK_MODE"). + toUInt(); +} + + +void RDFeed::setMediaLinkMode(RDFeed::MediaLinkMode mode) const +{ + SetRow("MEDIA_LINK_MODE",(unsigned)mode); +} + + +QString RDFeed::audioUrl(RDFeed::MediaLinkMode mode, + const QString &cgi_hostname,unsigned cast_id) +{ + QUrl url(baseUrl()); + QString ret; + RDPodcast *cast; + + switch(mode) { + case RDFeed::LinkNone: + ret=""; + break; + + case RDFeed::LinkDirect: + cast=new RDPodcast(cast_id); + ret=QString().sprintf("%s/%s", + (const char *)baseUrl(), + (const char *)cast->audioFilename()); + delete cast; + break; + + case RDFeed::LinkCounted: + ret=QString().sprintf("http://%s%s/rd-bin/rdfeed.%s?%s&cast_id=%d", + (const char *)basePreamble(), + (const char *)cgi_hostname, + (const char *)uploadExtension(), + (const char *)keyName(), + cast_id); + break; + } + return ret; +} + + +unsigned RDFeed::postCut(RDUser *user,RDStation *station, + const QString &cutname,Error *err,bool log_debug, + RDConfig *config) +{ + QString tmpfile; + QString destfile; + QString sql; + RDSqlQuery *q; + RDPodcast *cast=NULL; + RDUpload *upload=NULL; + RDUpload::ErrorCode upload_err; + RDAudioConvert::ErrorCode audio_conv_err; + + emit postProgressChanged(0); + emit postProgressChanged(1); + + // + // Export Cut + // + tmpfile=GetTempFilename(); + RDCut *cut=new RDCut(cutname); + if(!cut->exists()) { + delete cut; + *err=RDFeed::ErrorCannotOpenFile; + return 0; + } + RDAudioExport *conv=new RDAudioExport(station,config,this); + conv->setCartNumber(cut->cartNumber()); + conv->setCutNumber(cut->cutNumber()); + conv->setDestinationFile(tmpfile); + conv->setRange(cut->startPoint(),cut->endPoint()); + RDSettings *settings=new RDSettings(); + settings->setFormat(uploadFormat()); + settings->setChannels(uploadChannels()); + settings->setSampleRate(uploadSampleRate()); + settings->setBitRate(uploadBitRate()); + settings->setNormalizationLevel(normalizeLevel()/100); + conv->setDestinationSettings(settings); + switch(conv->runExport(user->name(),user->password(),&audio_conv_err)) { + case RDAudioExport::ErrorOk: + break; + + case RDAudioExport::ErrorInvalidSettings: + delete settings; + delete conv; + *err=RDFeed::ErrorUnsupportedType; + unlink(tmpfile); + return 0; + + case RDAudioExport::ErrorNoSource: + case RDAudioExport::ErrorNoDestination: + case RDAudioExport::ErrorInternal: + case RDAudioExport::ErrorUrlInvalid: + case RDAudioExport::ErrorService: + case RDAudioExport::ErrorInvalidUser: + case RDAudioExport::ErrorAborted: + case RDAudioExport::ErrorConverter: + delete settings; + delete conv; + *err=RDFeed::ErrorGeneral; + unlink(tmpfile); + return 0; + } + delete settings; + delete conv; + + // + // Upload + // + emit postProgressChanged(2); + QFile file(tmpfile); + int length=file.size(); + unsigned cast_id=CreateCast(&destfile,length,cut->length()); + delete cut; + cast=new RDPodcast(cast_id); + upload=new RDUpload(station->name(),this); + upload->setSourceFile(tmpfile); + upload->setDestinationUrl(purgeUrl()+"/"+cast->audioFilename()); + switch((upload_err=upload->runUpload(purgeUsername(),purgePassword(), + log_debug))) { + case RDUpload::ErrorOk: + *err=RDFeed::ErrorOk; + break; + + default: + emit postProgressChanged(totalPostSteps()); + *err=RDFeed::ErrorUploadFailed; + sql=QString().sprintf("delete from PODCASTS where ID=%u",cast_id); + q=new RDSqlQuery(sql); + delete q; + delete upload; + delete cast; + *err=RDFeed::ErrorUploadFailed; + unlink(tmpfile); + return 0; + } + emit postProgressChanged(3); + unlink(tmpfile); + delete upload; + delete cast; + + emit postProgressChanged(totalPostSteps()); + + return cast_id; +} + + +unsigned RDFeed::postFile(RDStation *station,const QString &srcfile,Error *err, + bool log_debug,RDConfig *config) +{ + QString sql; + RDSqlQuery *q; + QString cmd; + QString tmpfile; + QString tmpfile2; + QString destfile; + int time_length=0; + RDUpload *upload=NULL; + RDUpload::ErrorCode upload_err; + RDWaveFile *wave=NULL; + unsigned audio_time=0; + + emit postProgressChanged(0); + emit postProgressChanged(1); + qApp->processEvents(); + + // + // Convert Cut + // + tmpfile=GetTempFilename(); + RDAudioConvert *conv=new RDAudioConvert(station->name(),this); + conv->setSourceFile(srcfile); + conv->setDestinationFile(tmpfile); + RDSettings *settings=new RDSettings(); + settings->setFormat(uploadFormat()); + settings->setChannels(uploadChannels()); + settings->setSampleRate(uploadSampleRate()); + settings->setBitRate(uploadBitRate()); + settings->setNormalizationLevel(normalizeLevel()/100); + conv->setDestinationSettings(settings); + switch(conv->convert()) { + case RDAudioConvert::ErrorOk: + wave=new RDWaveFile(tmpfile); + if(wave->openWave()) { + audio_time=wave->getExtTimeLength(); + } + delete wave; + break; + + case RDAudioConvert::ErrorInvalidSettings: + case RDAudioConvert::ErrorFormatNotSupported: + emit postProgressChanged(totalPostSteps()); + delete settings; + delete conv; + *err=RDFeed::ErrorUnsupportedType; + unlink(tmpfile); + return 0; + + case RDAudioConvert::ErrorNoSource: + case RDAudioConvert::ErrorNoDestination: + case RDAudioConvert::ErrorInternal: + case RDAudioConvert::ErrorInvalidSource: + case RDAudioConvert::ErrorNoDisc: + case RDAudioConvert::ErrorNoTrack: + case RDAudioConvert::ErrorInvalidSpeed: + case RDAudioConvert::ErrorFormatError: + case RDAudioConvert::ErrorNoSpace: + emit postProgressChanged(totalPostSteps()); + delete settings; + delete conv; + *err=RDFeed::ErrorGeneral; + unlink(tmpfile); + return 0; + } + delete settings; + delete conv; + + // + // Upload + // + emit postProgressChanged(2); + emit postProgressChanged(3); + qApp->processEvents(); + QFile file(tmpfile); + int length=file.size(); + + unsigned cast_id=CreateCast(&destfile,length,time_length); + RDPodcast *cast=new RDPodcast(cast_id); + upload=new RDUpload(station->name(),this); + upload->setSourceFile(tmpfile); + upload->setDestinationUrl(purgeUrl()+"/"+cast->audioFilename()); + switch((upload_err=upload->runUpload(purgeUsername(),purgePassword(), + log_debug))) { + case RDUpload::ErrorOk: + sql=QString().sprintf("update PODCASTS set AUDIO_TIME=%u where ID=%u", + audio_time,cast_id); + q=new RDSqlQuery(sql); + delete q; + break; + + default: + emit postProgressChanged(totalPostSteps()); + *err=RDFeed::ErrorUploadFailed; + printf("Upload Error: %s\n",(const char *)RDUpload::errorText(upload_err)); + sql=QString().sprintf("delete from PODCASTS where ID=%u",cast_id); + q=new RDSqlQuery(sql); + delete q; + delete upload; + delete cast; + *err=RDFeed::ErrorUploadFailed; + unlink(tmpfile); + return 0; + } + delete upload; + delete cast; + unlink(QString().sprintf("%s.wav",(const char *)tmpfile)); + unlink(tmpfile); + emit postProgressChanged(totalPostSteps()); + + *err=RDFeed::ErrorOk; + return cast_id; +} + + +int RDFeed::totalPostSteps() const +{ + return RDFEED_TOTAL_POST_STEPS; +} + + +QString RDFeed::errorString(RDFeed::Error err) +{ + QString ret="Unknown Error"; + + switch(err) { + case RDFeed::ErrorOk: + ret="Ok"; + break; + + case RDFeed::ErrorNoFile: + ret="No such file or directory"; + break; + + case RDFeed::ErrorCannotOpenFile: + ret="Cannot open file"; + break; + + case RDFeed::ErrorUnsupportedType: + ret="Unsupported file format"; + break; + + case RDFeed::ErrorUploadFailed: + ret="Upload failed"; + break; + + case RDFeed::ErrorGeneral: + ret="General Error"; + break; + } + return ret; +} + + +unsigned RDFeed::CreateCast(QString *filename,int bytes,int msecs) const +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + unsigned cast_id=0; + QDateTime current_datetime= + QDateTime(QDate::currentDate(),QTime::currentTime()); + + sql=QString().sprintf("select CHANNEL_TITLE,CHANNEL_DESCRIPTION,\ + CHANNEL_CATEGORY,CHANNEL_LINK,MAX_SHELF_LIFE,\ + UPLOAD_FORMAT,UPLOAD_EXTENSION from FEEDS \ + where ID=%u",feed_id); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return 0; + } + + // + // Create Entry + // + sql=QString().sprintf("insert into PODCASTS set \ + FEED_ID=%u,\ + ITEM_TITLE=\"%s\",\ + ITEM_DESCRIPTION=\"%s\",\ + ITEM_CATEGORY=\"%s\",\ + ITEM_LINK=\"%s\",\ + SHELF_LIFE=%d,\ + EFFECTIVE_DATETIME=UTC_TIMESTAMP(),\ + ORIGIN_DATETIME=UTC_TIMESTAMP()", + feed_id, + (const char *)RDEscapeString(q->value(0).toString()), + (const char *)RDEscapeString(q->value(1).toString()), + (const char *)RDEscapeString(q->value(2).toString()), + (const char *)RDEscapeString(q->value(3).toString()), + q->value(4).toInt()); + q1=new RDSqlQuery(sql); + delete q1; + + // + // Get The Cast ID + // + sql="select LAST_INSERT_ID() from PODCASTS"; + q1=new RDSqlQuery(sql); + if(q1->first()) { + cast_id=q1->value(0).toUInt(); + } + delete q1; + + // + // Generate the Filename + // + *filename=QString(). + sprintf("%s.%s", + (const char *)QString().sprintf("%06u_%06u",feed_id,cast_id), + (const char *)q->value(6).toString()); + sql=QString().sprintf("update PODCASTS set AUDIO_FILENAME=\"%s\",\ + AUDIO_LENGTH=%d,\ + AUDIO_TIME=%d where ID=%u", + (const char *)(*filename), + bytes,msecs,cast_id); + q1=new RDSqlQuery(sql); + delete q1; + delete q; + return cast_id; +} + + +QString RDFeed::GetTempFilename() const +{ + char tempname[PATH_MAX]; + + sprintf(tempname,"%s/podcastXXXXXX",(const char *)RDTempDir()); + if(mkstemp(tempname)<0) { + return QString(); + } + + return QString(tempname); +} + + +void RDFeed::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE FEEDS SET %s=%d WHERE KEY_NAME=\"%s\"", + (const char *)param, + value, + (const char *)feed_keyname); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDFeed::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE FEEDS SET %s=\"%s\" WHERE KEY_NAME=\"%s\"", + (const char *)param, + (const char *)RDEscapeString(value), + (const char *)feed_keyname); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdfeed.h b/lib/rdfeed.h new file mode 100644 index 00000000..cdffe507 --- /dev/null +++ b/lib/rdfeed.h @@ -0,0 +1,133 @@ +// rdfeed.h +// +// Abstract a Rivendell RSS Feed +// +// (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdfeed.h,v 1.9.4.1 2013/11/13 23:36:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> +#include <qobject.h> + +#include <rdconfig.h> +#include <rduser.h> +#include <rdstation.h> +#include <rdsettings.h> + +#ifndef RDFEED_H +#define RDFEED_H + +#define RDFEED_TOTAL_POST_STEPS 4 + +class RDFeed : public QObject +{ + Q_OBJECT; + public: + enum Error {ErrorOk=0,ErrorNoFile=1,ErrorCannotOpenFile=2, + ErrorUnsupportedType=3,ErrorUploadFailed=4,ErrorGeneral=5}; + enum MediaLinkMode {LinkNone=0,LinkDirect=1,LinkCounted=2}; + RDFeed(const QString &keyname,QObject *parent=0,const char *name=0); + RDFeed(unsigned id,QObject *parent=0,const char *name=0); + QString keyName() const; + unsigned id() const; + bool exists() const; + QString channelTitle() const; + void setChannelTitle(const QString &str) const; + QString channelDescription() const; + void setChannelDescription(const QString &str) const; + QString channelCategory() const; + void setChannelCategory(const QString &str) const; + QString channelLink() const; + void setChannelLink(const QString &str) const; + QString channelCopyright() const; + void setChannelCopyright(const QString &str) const; + QString channelWebmaster() const; + void setChannelWebmaster(const QString &str) const; + QString channelLanguage() const; + void setChannelLanguage(const QString &str); + QString baseUrl() const; + void setBaseUrl(const QString &str) const; + QString basePreamble() const; + void setBasePreamble(const QString &str) const; + QString purgeUrl() const; + void setPurgeUrl(const QString &str) const; + QString purgeUsername() const; + void setPurgeUsername(const QString &str) const; + QString purgePassword() const; + void setPurgePassword(const QString &str) const; + QString headerXml() const; + void setHeaderXml(const QString &str); + QString channelXml() const; + void setChannelXml(const QString &str); + QString itemXml() const; + void setItemXml(const QString &str); + bool castOrder() const; + void setCastOrder(bool state) const; + int maxShelfLife() const; + void setMaxShelfLife(int days); + QDateTime lastBuildDateTime() const; + void setLastBuildDateTime(const QDateTime &datetime) const; + QDateTime originDateTime() const; + void setOriginDateTime(const QDateTime &datetime) const; + bool enableAutopost() const; + void setEnableAutopost(bool state) const; + bool keepMetadata() const; + void setKeepMetadata(bool state); + RDSettings::Format uploadFormat() const; + void setUploadFormat(RDSettings::Format fmt) const; + int uploadChannels() const; + void setUploadChannels(int chans) const; + int uploadQuality() const; + void setUploadQuality(int qual) const; + int uploadBitRate() const; + void setUploadBitRate(int rate) const; + int uploadSampleRate() const; + void setUploadSampleRate(int rate) const; + QString uploadExtension() const; + void setUploadExtension(const QString &str); + QString uploadMimetype() const; + void setUploadMimetype(const QString &str); + int normalizeLevel() const; + void setNormalizeLevel(int lvl) const; + QString redirectPath() const; + void setRedirectPath(const QString &str); + RDFeed::MediaLinkMode mediaLinkMode() const; + void setMediaLinkMode(RDFeed::MediaLinkMode mode) const; + QString audioUrl(RDFeed::MediaLinkMode mode,const QString &cgi_hostname, + unsigned cast_id); + unsigned postCut(RDUser *user,RDStation *station, + const QString &cutname,Error *err,bool log_debug, + RDConfig *config); + unsigned postFile(RDStation *station,const QString &srcfile,Error *err, + bool log_debug,RDConfig *config); + int totalPostSteps() const; + static QString errorString(RDFeed::Error err); + + signals: + void postProgressChanged(int step); + + private: + unsigned CreateCast(QString *filename,int bytes,int msecs) const; + QString GetTempFilename() const; + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,const QString &value) const; + QString feed_keyname; + unsigned feed_id; +}; + + +#endif diff --git a/lib/rdfeedlog.cpp b/lib/rdfeedlog.cpp new file mode 100644 index 00000000..d06db5b8 --- /dev/null +++ b/lib/rdfeedlog.cpp @@ -0,0 +1,138 @@ +// rdfeedlog.cpp +// +// Functions for manipulating RSS feed log tables. +// +// (C) Copyright 2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdfeedlog.cpp,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qdatetime.h> + +#include <rdweb.h> +#include <rddb.h> +#include <rdfeedlog.h> + + +void RDCreateFeedLog(QString keyname) +{ + QString sql; + RDSqlQuery *q; + + keyname.replace(" ","_"); + sql=QString().sprintf("create table if not exists %s_FLG (\ + ID int unsigned primary key auto_increment,\ + CAST_ID int unsigned,\ + ACCESS_DATE date,\ + ACCESS_COUNT int unsigned default 0,\ + index CAST_ID_IDX(CAST_ID,ACCESS_DATE))", + (const char *)keyname); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDDeleteFeedLog(QString keyname) +{ + QString sql; + RDSqlQuery *q; + + keyname.replace(" ","_"); + sql=QString().sprintf("drop table %s_FLG",(const char *)keyname); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDDeleteCastCount(QString keyname,unsigned cast_id) +{ + QString sql; + RDSqlQuery *q; + + keyname.replace(" ","_"); + sql=QString().sprintf("delete from %s_FLG where CAST_ID=%u", + (const char *)keyname,cast_id); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDDeleteCastCount(unsigned feed_id,unsigned cast_id) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select KEY_NAME from FEEDS where ID=%u",feed_id); + q=new RDSqlQuery(sql); + if(q->first()) { + RDDeleteCastCount(q->value(0).toString(),cast_id); + } + delete q; +} + + +void RDIncrementFeedCount(QString keyname) +{ + RDIncrementCastCount(keyname,0); +} + + +void RDIncrementCastCount(QString keyname,unsigned cast_id) +{ + QString sql; + RDSqlQuery *q; + QDate current_date=QDate::currentDate(); + + keyname.replace(" ","_"); +/* + FIXME: Table locking kills updates. Why? + + sql=QString().sprintf("lock tables %s_FLG read",(const char *)keyname); + q=new RDSqlQuery(sql); + delete q; +*/ + sql=QString().sprintf("select ACCESS_COUNT from %s_FLG where \ + (CAST_ID=%u)&&(ACCESS_DATE=\"%s\")", + (const char *)keyname, + cast_id, + (const char *)current_date.toString("yyyy-MM-dd")); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("update %s_FLG set ACCESS_COUNT=%u where \ + (CAST_ID=%u)&&(ACCESS_DATE=\"%s\")", + (const char *)keyname, + q->value(0).toUInt()+1,cast_id, + (const char *)current_date.toString("yyyy-MM-dd")); + } + else { + sql=QString().sprintf("insert into %s_FLG set \ + CAST_ID=%u,\ + ACCESS_DATE=\"%s\",\ + ACCESS_COUNT=1", + (const char *)keyname, + cast_id, + (const char *)current_date.toString("yyyy-MM-dd")); + } + delete q; + q=new RDSqlQuery(sql); + delete q; + +/* + sql="unlock tables"; + q=new RDSqlQuery(sql); + delete q; +*/ +} diff --git a/lib/rdfeedlog.h b/lib/rdfeedlog.h new file mode 100644 index 00000000..f84928e4 --- /dev/null +++ b/lib/rdfeedlog.h @@ -0,0 +1,36 @@ +// rdfeedlog.h +// +// Functions for manipulating RSS feed log tables. +// +// (C) Copyright 2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdfeedlog.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDFEEDLOG_H +#define RDFEEDLOG_H + +#include <qstring.h> + +void RDCreateFeedLog(QString keyname); +void RDDeleteFeedLog(QString keyname); +void RDDeleteCastCount(QString keyname,unsigned cast_id); +void RDDeleteCastCount(unsigned feed_id,unsigned cast_id); +void RDIncrementFeedCount(QString keyname); +void RDIncrementCastCount(QString keyname,unsigned cast_id); + + +#endif // RDFEEDLOG_H diff --git a/lib/rdflacdecode.cpp b/lib/rdflacdecode.cpp new file mode 100644 index 00000000..c0e4780e --- /dev/null +++ b/lib/rdflacdecode.cpp @@ -0,0 +1,144 @@ +// rdflacdecode.cpp +// +// Decode FLAC Files using libFLAC++ +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdflacdecode.cpp,v 1.5.6.1 2012/12/13 22:33:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdio.h> +#include <math.h> + +#include <rdflacdecode.h> + + +#ifdef HAVE_FLAC +RDFlacDecode::RDFlacDecode(SNDFILE *dst_sf) + : FLAC::Decoder::File() +{ + flac_sf_dst=dst_sf; + flac_start_point=-1; + flac_end_point=-1; +} + + +void RDFlacDecode::setRange(int start_pt,int end_pt) +{ + flac_start_point=start_pt; + flac_end_point=end_pt; +} + + +void RDFlacDecode::decode(RDWaveFile *wave,float *peak) +{ + flac_active=true; + flac_wavefile=wave; + flac_peak_sample=peak; + if(flac_start_point<0) { + flac_start_sample=0; + } + else { + flac_start_sample= + (double)flac_start_point*(double)wave->getSamplesPerSec()/1000.0; + } + if(flac_end_point<0) { + flac_end_sample=wave->getSampleLength(); + } + else { + flac_end_sample= + (double)flac_end_point*(double)wave->getSamplesPerSec()/1000.0; + } + flac_total_frames=0; + init(wave->getName().ascii()); + //set_filename(wave->getName().ascii()); + //init(); + + while(flac_active&&process_single()); +} + + +FLAC__StreamDecoderWriteStatus +RDFlacDecode::write_callback(const ::FLAC__Frame *frame, + const FLAC__int32 *const buffer[]) +{ + float *pcm=new float[frame->header.blocksize*frame->header.channels]; + float divider=(float)((1<<frame->header.bits_per_sample)/2.0); + + for(unsigned i=0;i<frame->header.channels;i++) { + for(unsigned j=0;j<frame->header.blocksize;j++) { + pcm[j*frame->header.channels+i]=(float)(buffer[i][j])/divider; + } + } + if(flac_total_frames>=flac_start_sample) { + if((flac_total_frames+frame->header.blocksize)<(unsigned)flac_end_sample) { // Write entire buffer + UpdatePeak(pcm,frame->header.blocksize*flac_wavefile->getChannels()); + sf_writef_float(flac_sf_dst,pcm,frame->header.blocksize); + } + else { + if((unsigned)flac_total_frames<(flac_total_frames+frame->header.blocksize)) { // Write start of buffer + UpdatePeak(pcm, + (flac_total_frames+frame->header.blocksize-flac_end_sample)*flac_wavefile->getChannels()); + sf_writef_float(flac_sf_dst,pcm,flac_total_frames+frame->header.blocksize-flac_end_sample); + // + // Done + // + sf_close(flac_sf_dst); + flac_active=false; + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + } + } + } + else { + int diff=flac_total_frames+frame->header.blocksize-flac_start_sample; + if(diff>0) { // Write end of buffer + UpdatePeak(pcm+diff,(frame->header.blocksize-diff)*flac_wavefile->getChannels()); + sf_writef_float(flac_sf_dst,pcm+diff,frame->header.blocksize-diff); + } + } + flac_total_frames+=frame->header.blocksize; + + delete pcm; + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + + +void RDFlacDecode::error_callback(::FLAC__StreamDecoderErrorStatus status) +{ + printf("FLAC error: %d\n",status); +} + + +void RDFlacDecode::metadata_callback(const FLAC__StreamMetadata*) +{ +} + + +void RDFlacDecode::UpdatePeak(const float data[],ssize_t len) +{ + float peak; + + if(!flac_active) { + return; + } + for(ssize_t i=0;i<len;i++) { + if((peak=fabsf(data[i]))>*flac_peak_sample) { + *flac_peak_sample=peak; + } + } +} + +#endif // HAVE_FLAC diff --git a/lib/rdflacdecode.h b/lib/rdflacdecode.h new file mode 100644 index 00000000..24079083 --- /dev/null +++ b/lib/rdflacdecode.h @@ -0,0 +1,61 @@ +// rdflacdecode.h +// +// Decode FLAC Files using libFLAC++ +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdflacdecode.h,v 1.4 2010/11/24 18:03:30 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDFLACDECODE_H +#define RDFLACDECODE_H + +#include <sndfile.h> +#ifdef HAVE_FLAC +#include <FLAC++/decoder.h> + +#include <rdwavefile.h> + +class RDFlacDecode : public FLAC::Decoder::File +{ + public: + RDFlacDecode(SNDFILE *dst_sf); + void setRange(int start_pt,int end_pt); + void decode(RDWaveFile *src_wave,float *peak); + + protected: + FLAC__StreamDecoderWriteStatus + write_callback(const ::FLAC__Frame *frame, + const FLAC__int32 *const buffer[]); + void error_callback(::FLAC__StreamDecoderErrorStatus status); + void metadata_callback(const FLAC__StreamMetadata*); + + private: + void UpdatePeak(const float data[],ssize_t len); + SNDFILE *flac_sf_dst; + int flac_start_point; + int flac_end_point; + int flac_start_sample; + int flac_end_sample; + float *flac_peak_sample; + int flac_total_frames; + RDWaveFile *flac_wavefile; + bool flac_active; +}; +#endif // HAVE_FLAC + + +#endif // RDFLACDECODER_H diff --git a/lib/rdformpost.cpp b/lib/rdformpost.cpp new file mode 100644 index 00000000..fd88e9c2 --- /dev/null +++ b/lib/rdformpost.cpp @@ -0,0 +1,532 @@ +// rdformpost.cpp +// +// Handle data from an HTML form. +// +// (C) Copyright 2009 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdformpost.cpp,v 1.3.2.1 2012/12/13 22:33:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <syslog.h> + +#include <rdconf.h> +#include <rdweb.h> + +#include <rdformpost.h> + +RDFormPost::RDFormPost(RDFormPost::Encoding encoding,unsigned maxsize, + bool auto_delete) +{ + char tempdir[PATH_MAX]; + bool ok=false; + + post_encoding=encoding; + post_error=RDFormPost::ErrorNotInitialized; + post_auto_delete=auto_delete; + + // + // Verify Transfer Type + // + if(getenv("REQUEST_METHOD")==NULL) { + post_error=RDFormPost::ErrorNotPost; + return; + } + if(QString(getenv("REQUEST_METHOD")).lower()!="post") { + post_error=RDFormPost::ErrorNotPost; + return; + } + + // + // Verify Size + // + if(getenv("CONTENT_LENGTH")==NULL) { + post_error=RDFormPost::ErrorPostTooLarge; + return; + } + post_content_length=QString(getenv("CONTENT_LENGTH")).toUInt(&ok); + if((!ok)||((maxsize>0)&&(post_content_length>maxsize))) { + post_error=RDFormPost::ErrorPostTooLarge; + return; + } + + // + // Initialize Temp Directory Path + // + if(getenv("TMPDIR")!=NULL) { + strcpy(tempdir,getenv("TMPDIR")); + } + else { + strcpy(tempdir,"/tmp"); + } + strcat(tempdir,"/rivendellXXXXXX"); + post_tempdir=mkdtemp(tempdir); + if(post_tempdir.isNull()) { + post_error=RDFormPost::ErrorNoTempDir; + return; + } + + // + // (Perhaps) autodetect the encoding type + // + char first[2]; + read(0,first,1); + if(post_encoding==RDFormPost::AutoEncoded) { + if(first[0]=='-') { + post_encoding=RDFormPost::MultipartEncoded; + } + else { + post_encoding=RDFormPost::UrlEncoded; + } + } + + switch(post_encoding) { + case RDFormPost::UrlEncoded: + LoadUrlEncoding(first[0]); + break; + + case RDFormPost::MultipartEncoded: + LoadMultipartEncoding(first[0]); + break; + + case RDFormPost::AutoEncoded: + break; + } +} + + +RDFormPost::~RDFormPost() +{ + if(post_auto_delete) { + for(std::map<QString,bool>::const_iterator ci=post_filenames.begin(); + ci!=post_filenames.end();ci++) { + if(ci->second) { + unlink(post_values[ci->first].toString()); + } + } + if(!post_tempdir.isNull()) { + rmdir(post_tempdir); + } + } +} + + +RDFormPost::Error RDFormPost::error() const +{ + return post_error; +} + + +QStringList RDFormPost::names() const +{ + QStringList list; + for(std::map<QString,QVariant>::const_iterator ci=post_values.begin(); + ci!=post_values.end();ci++) { + list.push_back(ci->first); + } + return list; +} + + +QVariant RDFormPost::value(const QString &name,bool *ok) +{ + QVariant v; + if(post_values.count(name)>0) { + v=post_values[name]; + } + if(ok!=NULL) { + *ok=(post_values.count(name)>0); + } + return v; +} + + +bool RDFormPost::getValue(const QString &name,QHostAddress *addr) +{ + QString str; + bool ok=getValue(name,&str); + if(!ok) { + return false; + } + addr->setAddress(str); + return true; +} + + +bool RDFormPost::getValue(const QString &name,QString *str) +{ + if(post_values.count(name)>0) { + *str=post_values[name].toString(); + return true; + } + return false; +} + + +bool RDFormPost::getValue(const QString &name,int *n) +{ + if(post_values.count(name)>0) { + *n=post_values[name].toInt(); + return true; + } + return false; +} + + +bool RDFormPost::getValue(const QString &name,long *n) +{ + if(post_values.count(name)>0) { + *n=post_values[name].toLongLong(); + return true; + } + *n=0; + return false; +} + + +bool RDFormPost::getValue(const QString &name,QDateTime *datetime) +{ + QString str; + if(!getValue(name,&str)) { + return false; + } + *datetime=RDGetWebDateTime(str); + return true; +} + + +bool RDFormPost::getValue(const QString &name,QTime *time) +{ + QString str; + if(!getValue(name,&str)) { + return false; + } + if(str.length()==0) { + *time=QTime(); + } + else { + *time=QTime().addMSecs(RDSetTimeLength(str)); + } + return true; +} + + +bool RDFormPost::isFile(const QString &name) +{ + return post_filenames[name]; +} + + +QString RDFormPost::tempDir() const +{ + return post_tempdir; +} + + +void RDFormPost::dump() +{ + printf("Content-type: text/html\n\n"); + printf("<table cellpadding=\"5\" cellspacing=\"0\" border=\"1\">\n"); + printf("<tr>\n"); + printf("<td colspan=\"3\" align=\"center\"><strong>RDFormPost Data Dump</strong></td>\n"); + printf("</tr>\n"); + + printf("<tr>\n"); + printf("<th align=\"center\">NAME</th>\n"); + printf("<th align=\"center\">VALUE</th>\n"); + printf("<th align=\"center\">FILE</th>\n"); + printf("</tr>\n"); + + for(std::map<QString,QVariant>::const_iterator ci=post_values.begin(); + ci!=post_values.end();ci++) { + printf("<tr>\n"); + printf("<td align=\"left\">|%s|</td>\n",(const char *)ci->first); + printf("<td align=\"left\">|%s|</td>\n", + (const char *)ci->second.toString()); + if(post_filenames[ci->first]) { + printf("<td align=\"center\">Yes</td>\n"); + } + else { + printf("<td align=\"center\">No</td>\n"); + } + printf("</tr>\n"); + } + + printf("</table>\n"); +} + + +QString RDFormPost::errorString(RDFormPost::Error err) +{ + QString str="Unknown error"; + + switch(err) { + case RDFormPost::ErrorOk: + str="OK"; + break; + + case RDFormPost::ErrorNotPost: + str="Request is not POST"; + break; + + case RDFormPost::ErrorNoTempDir: + str="Unable to create temporary directory"; + break; + + case RDFormPost::ErrorMalformedData: + str="The data is malformed"; + break; + + case RDFormPost::ErrorPostTooLarge: + str="POST is too large"; + break; + + case RDFormPost::ErrorInternal: + str="Internal error"; + break; + + case RDFormPost::ErrorNotInitialized: + str="POST class not initialized"; + break; + } + return str; +} + + +QString RDFormPost::urlEncode(const QString &str) +{ + QString ret; + + for(unsigned i=0;i<str.length();i++) { + if(str.at(i).isLetterOrNumber()) { + ret+=str.mid(i,1); + } + else { + ret+=QString().sprintf("%%%02X",str.at(i).latin1()); + } + } + + return ret; +} + + +QString RDFormPost::urlDecode(const QString &str) +{ + int istate=0; + unsigned n; + QString code; + QString ret; + bool ok=false; + + for(unsigned i=0;i<str.length();i++) { + switch(istate) { + case 0: + if(str.at(i)==QChar('+')) { + ret+=" "; + } + else { + if(str.at(i)==QChar('%')) { + istate=1; + } + else { + ret+=str.at(i); + } + } + break; + + case 1: + n=str.mid(i,1).toUInt(&ok); + if((!ok)||(n>9)) { + istate=0; + } + code=str.mid(i,1); + istate=2; + break; + + case 2: + n=str.mid(i,1).toUInt(&ok); + if((!ok)||(n>9)) { + istate=0; + } + code+=str.mid(i,1); + ret+=QChar(code.toInt(&ok,16)); + istate=0; + break; + } + } + + return ret; +} + + +void RDFormPost::LoadUrlEncoding(char first) +{ + char *data=new char[post_content_length+1]; + int n; + QStringList lines; + QStringList line; + + data[0]=first; + if((n=read(0,data+1,post_content_length-1))<0) { + post_error=RDFormPost::ErrorMalformedData; + return; + } + data[post_content_length]=0; + + /* + * Uncomment this to dump the raw post data to "/tmp/output.dat". + */ + /* + int out=open("/tmp/output.dat",O_WRONLY|O_CREAT); + write(out,data,post_content_length); + ::close(out); + printf("Content-type: text/html\n\n"); + printf("POST DUMPED TO \"/tmp/output.dat\"!\n"); + exit(0); + */ + lines=lines.split("&",data); + for(unsigned i=0;i<lines.size();i++) { + line=line.split("=",lines[i]); + switch(line.size()) { + case 1: + post_values[line[0]]=""; + post_filenames[line[0]]=false; + break; + + case 2: + post_values[line[0]]=RDFormPost::urlDecode(line[1]); + post_filenames[line[0]]=false; + break; + } + } + + post_error=RDFormPost::ErrorOk; + delete data; +} + + +void RDFormPost::LoadMultipartEncoding(char first) +{ + std::map<QString,QString> headers; + bool header=true; + char *data=NULL; + FILE *f=NULL; + ssize_t n=0; + QString sep; + QString name; + QString filename; + QString tempdir; + int fd=-1; + + if((f=fdopen(0,"r"))==NULL) { + post_error=RDFormPost::ErrorInternal; + return; + } + + /* + * Uncomment this to dump the raw post data to "/tmp/output.dat". + */ + /* + int out=open("/tmp/output.dat",O_WRONLY|O_CREAT); + while((n=getline(&data,(size_t *)&n,f))>0) { + write(out,data,n); + } + ::close(out); + printf("Content-type: text/html\n\n"); + printf("POST DUMPED TO \"/tmp/output.dat\"!\n"); + exit(0); + */ + + if((n=getline(&data,(size_t *)&n,f))<=0) { + post_error=RDFormPost::ErrorMalformedData; + return; + } + sep=QString(data).simplifyWhiteSpace(); + + // + // Get message parts + // + while((n=getline(&data,(size_t *)&n,f))>0) { + if(QString(data).simplifyWhiteSpace().contains(sep)>0) { // End of part + if(fd>=0) { + ftruncate(fd,lseek(fd,0,SEEK_CUR)-2); // Remove extraneous final CR/LF + ::close(fd); + fd=-1; + } + name=""; + filename=""; + headers.clear(); + header=true; + continue; + } + if(header) { // Read header + if(QString(data).simplifyWhiteSpace().isEmpty()) { + if(!headers["content-disposition"].isNull()) { + QStringList fields; + fields=fields.split(";",headers["content-disposition"]); + if(fields.size()>0) { + if(fields[0].lower().simplifyWhiteSpace()=="form-data") { + for(unsigned i=1;i<fields.size();i++) { + QStringList pairs; + pairs=pairs.split("=",fields[i]); + if(pairs[0].lower().simplifyWhiteSpace()=="name") { + name=pairs[1].simplifyWhiteSpace(); + name.replace("\"",""); + } + if(pairs[0].lower().simplifyWhiteSpace()=="filename") { + filename=post_tempdir+"/"+pairs[1].simplifyWhiteSpace(); + filename.replace("\"",""); + fd=open(filename,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR); + } + } + } + } + } + header=false; + } + else { + QStringList hdr; + hdr=hdr.split(":",QString(data).simplifyWhiteSpace()); + // Reconcaternate trailing sections so we don't split on the + // useless M$ drive letter supplied by IE + for(unsigned i=2;i<hdr.size();i++) { + hdr[1]+=hdr[i]; + } + headers[hdr[0].lower()]=hdr[1]; + } + } + else { // Read data + if(filename.isEmpty()) { + QString str=post_values[name].toString(); + str+=QString(data); + post_filenames[name]=false; + post_values[name]=str.simplifyWhiteSpace(); + } + else { + post_filenames[name]=true; + post_values[name]=filename; + write(fd,data,n); + } + } + } + free(data); + post_error=RDFormPost::ErrorOk; +} diff --git a/lib/rdformpost.h b/lib/rdformpost.h new file mode 100644 index 00000000..90de4879 --- /dev/null +++ b/lib/rdformpost.h @@ -0,0 +1,71 @@ +// rdformpost.h +// +// Handle POST data from an HTML form. +// +// (C) Copyright 2009 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdformpost.h,v 1.2 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDFORMPOST_H +#define RDFORMPOST_H + +#include <map> + +#include <qstring.h> +#include <qstringlist.h> +#include <qvariant.h> +#include <qhostaddress.h> + +class RDFormPost +{ + public: + enum Encoding {UrlEncoded=0,MultipartEncoded=1,AutoEncoded=2}; + enum Error {ErrorOk=0,ErrorNotPost=1,ErrorNoTempDir=2,ErrorMalformedData=3, + ErrorPostTooLarge=4,ErrorInternal=5,ErrorNotInitialized=6}; + RDFormPost(RDFormPost::Encoding encoding,unsigned maxsize=0, + bool auto_delete=true); + ~RDFormPost(); + RDFormPost::Error error() const; + QStringList names() const; + QVariant value(const QString &name,bool *ok=NULL); + bool getValue(const QString &name,QHostAddress *addr); + bool getValue(const QString &name,QString *str); + bool getValue(const QString &name,int *n); + bool getValue(const QString &name,long *n); + bool getValue(const QString &name,QDateTime *datetime); + bool getValue(const QString &name,QTime *time); + bool isFile(const QString &name); + QString tempDir() const; + void dump(); + static QString errorString(RDFormPost::Error err); + static QString urlEncode(const QString &str); + static QString urlDecode(const QString &str); + + private: + void LoadUrlEncoding(char first); + void LoadMultipartEncoding(char first); + RDFormPost::Encoding post_encoding; + RDFormPost::Error post_error; + std::map<QString,QVariant> post_values; + std::map<QString,bool> post_filenames; + QString post_tempdir; + bool post_auto_delete; + unsigned post_content_length; +}; + + +#endif // RDFORMPOST_H diff --git a/lib/rdgain_envelope.cpp b/lib/rdgain_envelope.cpp new file mode 100644 index 00000000..9da33150 --- /dev/null +++ b/lib/rdgain_envelope.cpp @@ -0,0 +1,113 @@ +// rdgain_envelope.cpp +// +// A Container Class for Rivendell Event Segue Parameters +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdgain_envelope.cpp,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rd.h> +#include <rdgain_envelope.h> + + +RDGainEnvelope::RDGainEnvelope() +{ + clear(); +} + + +int RDGainEnvelope::startPoint() const +{ + return env_start_point; +} + + +void RDGainEnvelope::setStartPoint(int point) +{ + env_start_point=point; +} + + +int RDGainEnvelope::fadeupPoint() const +{ + return env_fadeup_point; +} + + +void RDGainEnvelope::setFadeupPoint(int point) +{ + env_fadeup_point=point; +} + + +int RDGainEnvelope::fadeupGain() const +{ + return env_fadeup_gain; +} + + +void RDGainEnvelope::setFadeupGain(int gain) +{ + env_fadeup_gain=gain; +} + + +int RDGainEnvelope::segueStartPoint() const +{ + return env_segue_start_point; +} + + +void RDGainEnvelope::setSegueStartPoint(int point) +{ + env_segue_start_point=point; +} + + +int RDGainEnvelope::segueEndPoint() const +{ + return env_segue_end_point; +} + + +void RDGainEnvelope::setSegueEndPoint(int point) +{ + env_segue_end_point=point; +} + + +int RDGainEnvelope::segueGain() const +{ + return env_segue_gain; +} + + +void RDGainEnvelope::setSegueGain(int gain) +{ + env_segue_gain=gain; +} + + +void RDGainEnvelope::clear() +{ + env_start_point=-1; + env_fadeup_point=-1; + env_fadeup_gain=RD_MUTE_DEPTH; + env_segue_start_point=-1; + env_segue_end_point=-1; + env_segue_gain=RD_MUTE_DEPTH; +} diff --git a/lib/rdgain_envelope.h b/lib/rdgain_envelope.h new file mode 100644 index 00000000..3830fda4 --- /dev/null +++ b/lib/rdgain_envelope.h @@ -0,0 +1,56 @@ +// rdgain_envelope.h +// +// A Container Class for Rivendell Event Segue Parameters +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdgain_envelope.h,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDGAIN_ENVELOPE_H +#define RDGAIN_ENVELOPE_H + +#include <qstring.h> + +class RDGainEnvelope +{ + public: + RDGainEnvelope(); + int startPoint() const; + void setStartPoint(int point); + int fadeupPoint() const; + void setFadeupPoint(int point); + int fadeupGain() const; + void setFadeupGain(int gain); + int segueStartPoint() const; + void setSegueStartPoint(int point); + int segueEndPoint() const; + void setSegueEndPoint(int point); + int segueGain() const; + void setSegueGain(int gain); + void clear(); + + private: + int env_start_point; + int env_fadeup_point; + int env_fadeup_gain; + int env_segue_start_point; + int env_segue_end_point; + int env_segue_gain; +}; + + +#endif // RDGAIN_ENVELOPE_H diff --git a/lib/rdget_ath.cpp b/lib/rdget_ath.cpp new file mode 100644 index 00000000..f4b9bb30 --- /dev/null +++ b/lib/rdget_ath.cpp @@ -0,0 +1,130 @@ +// rdget_ath.cpp +// +// Get an Aggreggate Tuning Hours (ATH) Figure. +// +// (C) Copyright 2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdget_ath.cpp,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qpushbutton.h> +#include <qlabel.h> +#include <qmessagebox.h> +#include <qvalidator.h> + +#include <rdget_ath.h> + + +RDGetAth::RDGetAth(double *ath,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + ath_ath=ath; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Enter ATH")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Validator + // + QDoubleValidator *validator=new QDoubleValidator(this,"validator"); + validator->setBottom(0.0); + + // + // Label + // + QLabel *label=new QLabel(tr("Enter the agreggate tuning hours (ATH)\nfigure for the report period.\n(Supplied by your streaming provider)."),this); + label->setGeometry(10,5,sizeHint().width()-20,65); + + // + // ATH + // + ath_ath_edit=new QLineEdit(this,"ath_ath_edit"); + ath_ath_edit->setGeometry(55,70,50,19); + ath_ath_edit->setValidator(validator); + QLabel *ath_ath_label=new QLabel(ath_ath_edit,tr("ATH:"),this, + "ath_ath_label"); + ath_ath_label->setGeometry(10,70,40,19); + ath_ath_label->setFont(font); + ath_ath_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button-> + setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +RDGetAth::~RDGetAth() +{ +} + + +QSize RDGetAth::sizeHint() const +{ + return QSize(250,160); +} + + +QSizePolicy RDGetAth::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDGetAth::okData() +{ + if(ath_ath_edit->text().isEmpty()) { + QMessageBox::warning(NULL,tr("Invalid ATH"), + tr("You must provide a valid ATH figure!")); + return; + } + *ath_ath=ath_ath_edit->text().toDouble(); + done(0); +} + + +void RDGetAth::cancelData() +{ + done(-1); +} diff --git a/lib/rdget_ath.h b/lib/rdget_ath.h new file mode 100644 index 00000000..510ab078 --- /dev/null +++ b/lib/rdget_ath.h @@ -0,0 +1,50 @@ +// get_ath.h +// +// Get an Agreggate Tuning Hours (ATH) Figure. +// +// (C) Copyright 2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdget_ath.h,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef GET_ATH_H +#define GET_ATH_H + +#include <qdialog.h> +#include <qlineedit.h> + + +class RDGetAth : public QDialog +{ + Q_OBJECT + public: + RDGetAth(double *ath,QWidget *parent=0,const char *name=0); + ~RDGetAth(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *ath_ath_edit; + double *ath_ath; +}; + + +#endif + diff --git a/lib/rdgetpasswd.cpp b/lib/rdgetpasswd.cpp new file mode 100644 index 00000000..06aaa5b7 --- /dev/null +++ b/lib/rdgetpasswd.cpp @@ -0,0 +1,115 @@ +// rdgetpasswd.cpp +// +// Prompt for a password. +// +// (C) Copyright 2006-2007 Fred Gleason <fredg@salemradiolabs.com> +// +// $Id: rdgetpasswd.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qpushbutton.h> +#include <qlabel.h> +#include <qmessagebox.h> +#include <qvalidator.h> + +#include <rdgetpasswd.h> + + +RDGetPasswd::RDGetPasswd(QString *passwd,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + pw_password=passwd; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Enter Password")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Label + // + QLabel *label=new QLabel(tr("Enter password"),this); + label->setGeometry(0,5,sizeHint().width(),20); + label->setAlignment(AlignCenter); + + // + // Password + // + pw_password_edit=new QLineEdit(this,"pw_password_edit"); + pw_password_edit->setGeometry(10,30,sizeHint().width()-20,20); + pw_password_edit->setEchoMode(QLineEdit::Password); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button-> + setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +RDGetPasswd::~RDGetPasswd() +{ +} + + +QSize RDGetPasswd::sizeHint() const +{ + return QSize(190,120); +} + + +QSizePolicy RDGetPasswd::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDGetPasswd::okData() +{ + *pw_password=pw_password_edit->text(); + done(0); +} + + +void RDGetPasswd::cancelData() +{ + done(-1); +} diff --git a/lib/rdgetpasswd.h b/lib/rdgetpasswd.h new file mode 100644 index 00000000..c47fa702 --- /dev/null +++ b/lib/rdgetpasswd.h @@ -0,0 +1,50 @@ +// rdgetpasswd.h +// +// Prompt for a password. +// +// (C) Copyright 2007 Fred Gleason <fredg@salemradiolabs.com> +// +// $Id: rdgetpasswd.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef GETPASSWD_H +#define GETPASSWD_H + +#include <qdialog.h> +#include <qlineedit.h> + + +class RDGetPasswd : public QDialog +{ + Q_OBJECT + public: + RDGetPasswd(QString *passwd,QWidget *parent=0,const char *name=0); + ~RDGetPasswd(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *pw_password_edit; + QString *pw_password; +}; + + +#endif // RDGETPASSWD_H + diff --git a/lib/rdgpio.cpp b/lib/rdgpio.cpp new file mode 100644 index 00000000..35ea10d6 --- /dev/null +++ b/lib/rdgpio.cpp @@ -0,0 +1,434 @@ +// rdgpio.cpp +// +// A driver for General-Purpose I/O devices. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdgpio.cpp,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#include <qobject.h> + +#include <rdgpio.h> + + +RDGpio::RDGpio(QObject *parent,const char *name) + : QObject(parent,name) +{ + Clear(); + + // + // Input Timer + // + gpio_input_timer=new QTimer(this,"input_timer"); + connect(gpio_input_timer,SIGNAL(timeout()),this,SLOT(inputTimerData())); + gpio_revert_mapper=NULL; + for(int i=0;i<GPIO_MAX_LINES;i++) { + gpio_revert_timer[i]=NULL; + } + for(int i=0;i<KEY_MAX;i++) { + gpio_key_map[i]=-1; + } +} + + +QString RDGpio::device() const +{ + return gpio_device; +} + + +void RDGpio::setDevice(QString dev) +{ + gpio_device=dev; +} + + +QString RDGpio::description() const +{ + return gpio_description; +} + + +RDGpio::Mode RDGpio::mode() +{ + struct gpio_info info; + + switch(gpio_api) { + case RDGpio::ApiGpio: + ioctl(gpio_fd,GPIO_GETINFO,&info); + return (RDGpio::Mode)info.mode; + + case RDGpio::ApiInput: + return RDGpio::Auto; + } + return RDGpio::Auto; +} + + +void RDGpio::setMode(RDGpio::Mode mode) +{ + unsigned umode=(unsigned)mode; + + switch(gpio_api) { + case RDGpio::ApiGpio: + ioctl(gpio_fd,GPIO_SETMODE,&umode); + RemapTimers(); + break; + + default: + break; + } +} + + +bool RDGpio::open() +{ + int ver; + + if(gpio_open) { + return false; + } + if((gpio_fd=::open((const char *)gpio_device,O_RDONLY|O_NONBLOCK))<0) { + return false; + } + if(ioctl(gpio_fd,GPIO_GETINFO,&gpio_info)==0) { + gpio_api=RDGpio::ApiGpio; + InitGpio(); + RemapTimers(); + } + else { + if(ioctl(gpio_fd,EVIOCGVERSION,&ver)==0) { + gpio_api=RDGpio::ApiInput; + InitInput(); + } + else { + ::close(gpio_fd); + return false; + } + } + gpio_open=true; + gpio_input_timer->start(GPIO_CLOCK_INTERVAL); + return true; +} + + +void RDGpio::close() +{ + if(!gpio_open) { + return; + } + gpio_input_timer->stop(); + ::close(gpio_fd); + gpio_open=false; + if(gpio_revert_mapper!=NULL) { + delete gpio_revert_mapper; + gpio_revert_mapper=NULL; + } + for(int i=0;i<outputs();i++) { + if(gpio_revert_timer[i]!=NULL) { + delete gpio_revert_timer[i]; + gpio_revert_timer[i]=NULL; + } + } +} + + +int RDGpio::inputs() const +{ + if(!gpio_open) { + return 0; + } + return gpio_info.inputs; +} + + +int RDGpio::outputs() const +{ + if(!gpio_open) { + return 0; + } + return gpio_info.outputs; +} + + +unsigned RDGpio::inputMask() +{ + struct gpio_mask mask; + struct input_event input; + static unsigned input_mask=0; + + if(!gpio_open) { + return 0; + } + switch(gpio_api) { + case RDGpio::ApiGpio: + memset(&mask,0,sizeof(struct gpio_mask)); + ioctl(gpio_fd,GPIO_GET_INPUTS,&mask); + return mask.mask[0]; + + case RDGpio::Input: + while(read(gpio_fd,&input,sizeof(input))>0) { + if((input.type==EV_KEY)&&(gpio_key_map[input.code]>=0)) { + if(input.value==0) { + input_mask&=~(1<<gpio_key_map[input.code]); + } + else { + input_mask|=(1<<gpio_key_map[input.code]); + } + } + } + return input_mask; + } + return 0; +} + + +bool RDGpio::inputState(int line) +{ + if(!gpio_open) { + return false; + } + if((inputMask()&(1<<line))==0) { + return false; + } + return true; +} + + +unsigned RDGpio::outputMask() const +{ + struct gpio_mask mask; + + if(!gpio_open) { + return 0; + } + switch(gpio_api) { + case RDGpio::ApiGpio: + memset(&mask,0,sizeof(struct gpio_mask)); + ioctl(gpio_fd,GPIO_GET_OUTPUTS,&mask); + return mask.mask[0]; + + case RDGpio::ApiInput: + return 0; + } + return 0; +} + + +void RDGpio::gpoSet(int line,unsigned interval) +{ + struct gpio_line out; + + if(!gpio_open) { + return; + } + switch(gpio_api) { + case RDGpio::ApiGpio: + out.line=line; + out.state=1; + ioctl(gpio_fd,GPIO_SET_OUTPUT,&out); + SetReversion(line,interval); + break; + + case RDGpio::ApiInput: + break; + } +} + + +void RDGpio::gpoReset(int line,unsigned interval) +{ + struct gpio_line out; + + if(!gpio_open) { + return; + } + switch(gpio_api) { + case RDGpio::ApiGpio: + out.line=line; + out.state=0; + ioctl(gpio_fd,GPIO_SET_OUTPUT,&out); + SetReversion(line,interval); + break; + + case RDGpio::ApiInput: + break; + } +} + + +void RDGpio::inputTimerData() +{ + unsigned input_mask; + unsigned output_mask; + unsigned mask; + + if((input_mask=inputMask())!=gpio_input_mask) { + for(int i=0;i<inputs();i++) { + mask=1<<i; + if((gpio_input_mask&mask)!=(input_mask&mask)) { + if((input_mask&mask)==0) { + emit inputChanged(i,false); + } + else { + emit inputChanged(i,true); + } + } + } + gpio_input_mask=input_mask; + } + if((output_mask=outputMask())!=gpio_output_mask) { + for(int i=0;i<outputs();i++) { + mask=1<<i; + if((gpio_output_mask&mask)!=(output_mask&mask)) { + if((output_mask&mask)==0) { + emit outputChanged(i,false); + } + else { + emit outputChanged(i,true); + } + } + } + gpio_output_mask=output_mask; + } +} + + void RDGpio::revertData(int id) +{ + if((outputMask()&(1<<id))==0) { + gpoSet(id); + } + else { + gpoReset(id); + } +} + + +void RDGpio::RemapTimers() +{ + struct gpio_info info; + + // + // Free Old Timers + // + if(gpio_revert_mapper!=NULL) { + delete gpio_revert_mapper; + gpio_revert_mapper=NULL; + } + for(int i=0;i<gpio_info.outputs;i++) { + if(gpio_revert_timer[i]!=NULL) { + delete gpio_revert_timer[i]; + gpio_revert_timer[i]=NULL; + } + } + + // + // Create New Timers + // + ioctl(gpio_fd,GPIO_GETINFO,&info); + gpio_revert_mapper=new QSignalMapper(this,"gpio_revert_mapper"); + connect(gpio_revert_mapper,SIGNAL(mapped(int)),this,SLOT(revertData(int))); + for(int i=0;i<info.outputs;i++) { + gpio_revert_timer[i]=new QTimer(this); + gpio_revert_mapper->setMapping(gpio_revert_timer[i],i); + connect(gpio_revert_timer[i],SIGNAL(timeout()), + gpio_revert_mapper,SLOT(map())); + } +} + + +void RDGpio::SetReversion(int line,unsigned interval) +{ + if(interval==0) { + if(gpio_revert_timer[line]->isActive()) { + gpio_revert_timer[line]->stop(); + } + return; + } + if(gpio_revert_timer[line]->isActive()) { + gpio_revert_timer[line]->changeInterval(interval); + } + else { + gpio_revert_timer[line]->start(interval,true); + } +} + + +void RDGpio::Clear() +{ + gpio_open=false; + gpio_description="Unknown Device"; + memset(&gpio_info,0,sizeof(struct gpio_info)); + gpio_input_mask=0; + gpio_api=RDGpio::ApiGpio; + for(int i=0;i<KEY_MAX;i++) { + gpio_key_map[i]=-1; + } +} + + +void RDGpio::InitGpio() +{ + gpio_description=gpio_info.name; + + // + // Enable Input Filters + // + if((gpio_info.caps&GPIO_CAP_FILTER)!=0) { + gpio_mask mask; + memset(&mask,0xFF,sizeof(struct gpio_mask)); + ioctl(gpio_fd,GPIO_SET_FILTERS,&mask); + } +} + + +void RDGpio::InitInput() +{ + unsigned char bitmask[EV_MAX/8+1]; + unsigned char keymask[KEY_MAX/8+1]; + int i=0; + char desc[256]; + + memset(&gpio_info,0,sizeof(struct gpio_info)); + + if(ioctl(gpio_fd,EVIOCGNAME(256),desc)>=0) { + gpio_description=desc; + } + if(ioctl(gpio_fd,EVIOCGBIT(0,EV_MAX),bitmask)<0) { + return; + } + if((bitmask[0]&(1<<EV_KEY))==0) { + return; + } + ioctl(gpio_fd,EVIOCGBIT(EV_KEY,KEY_MAX),keymask); + while((i<KEY_MAX)&&(gpio_info.inputs<GPIO_MAX_LINES)) { + if((keymask[i/8]&(1<<(i%8)))!=0) { + gpio_key_map[i]=gpio_info.inputs++; + } + i++; + } + gpio_info.mode=RDGpio::Auto; + gpio_info.outputs=0; +} + diff --git a/lib/rdgpio.h b/lib/rdgpio.h new file mode 100644 index 00000000..a66cb399 --- /dev/null +++ b/lib/rdgpio.h @@ -0,0 +1,91 @@ +// rdgpio.h +// +// A driver for General-Purpose I/O devices. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdgpio.h,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDGPIO_H +#define RDGPIO_H + +#include <linux/input.h> + +#include <qobject.h> +#include <qtimer.h> +#include <qsignalmapper.h> + +#include <gpio.h> + +#define GPIO_CLOCK_INTERVAL 100 +#define GPIO_MAX_LINES 24 + +class RDGpio : public QObject +{ + Q_OBJECT + public: + enum Mode {Auto=GPIO_MODE_AUTO,Input=GPIO_MODE_INPUT,Output=GPIO_MODE_OUTPUT}; + RDGpio(QObject *parent=0,const char *name=0); + QString device() const; + void setDevice(QString dev); + QString description() const; + RDGpio::Mode mode(); + void setMode(RDGpio::Mode mode); + bool open(); + void close(); + int inputs() const; + int outputs() const; + unsigned inputMask(); + bool inputState(int line); + unsigned outputMask() const; + + signals: + void inputChanged(int line,bool state); + void outputChanged(int line,bool state); + + public slots: + void gpoSet(int line,unsigned interval=0); + void gpoReset(int line,unsigned interval=0); + + private slots: + void inputTimerData(); + void revertData(int); + + private: + enum Api {ApiGpio=0,ApiInput=1}; + void RemapTimers(); + void SetReversion(int,unsigned); + void Clear(); + void InitGpio(); + void InitInput(); + Api gpio_api; + int gpio_fd; + QString gpio_device; + bool gpio_open; + struct gpio_info gpio_info; + QTimer *gpio_input_timer; + unsigned gpio_input_mask; + unsigned gpio_output_mask; + QSignalMapper *gpio_revert_mapper; + QTimer *gpio_revert_timer[GPIO_MAX_LINES]; + int gpio_key_map[KEY_MAX]; + QString gpio_description; +}; + + +#endif // RDGPIO_H diff --git a/lib/rdgpioselector.cpp b/lib/rdgpioselector.cpp new file mode 100644 index 00000000..c000888d --- /dev/null +++ b/lib/rdgpioselector.cpp @@ -0,0 +1,95 @@ +// rdgpioselector.cpp +// +// GPIO Pin selector widget for Rivendell +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdgpioselector.cpp,v 1.8 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <math.h> + +#include <qdialog.h> +#include <qstring.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qlineedit.h> +#include <qtextedit.h> +#include <qlabel.h> +#include <qpainter.h> +#include <qevent.h> +#include <qmessagebox.h> +#include <qbuttongroup.h> + + +#include <rd.h> +#include <rdgpioselector.h> + + +RDGpioSelector::RDGpioSelector(QWidget *parent,const char *name) + : QWidget(parent,name) +{ + // + // Pin + // + gpio_pin_box=new QSpinBox(this,"gpio_pin_box"); + gpio_pin_box->setGeometry(60,22,50,19); + gpio_pin_box->setSpecialValueText("None"); + gpio_pin_box->setMinValue(-1); + gpio_pin_box->setMaxValue(MAX_GPIO_PINS-1); + gpio_pin_box->setValue(-1); + connect(gpio_pin_box,SIGNAL(valueChanged(int)),this,SLOT(pinData(int))); + QLabel *gpio_pin_label=new QLabel(gpio_pin_box,tr("Pin:"),this, + "gpio_pin_label"); + gpio_pin_label->setGeometry(0,24,55,19); + gpio_pin_label->setAlignment(AlignRight|ShowPrefix); +} + + +RDGpioSelector::~RDGpioSelector() +{ + delete gpio_pin_box; +} + + +QSize RDGpioSelector::sizeHint() const +{ + return QSize(110,87); +} + + +QSizePolicy RDGpioSelector::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int RDGpioSelector::pin() const +{ + return gpio_pin_box->value(); +} + + +void RDGpioSelector::setPin(int pinno) +{ + gpio_pin_box->setValue(pinno); +} + + +void RDGpioSelector::pinData(int pinno) +{ + emit pinChanged(pinno); +} diff --git a/lib/rdgpioselector.h b/lib/rdgpioselector.h new file mode 100644 index 00000000..d59a02ec --- /dev/null +++ b/lib/rdgpioselector.h @@ -0,0 +1,54 @@ +// rdgpioselector.h +// +// GPIO Pin Selector Widget for Rivendell +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdgpioselector.h,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDGPIOSELECTOR_H +#define RDGPIOSELECTOR_H + +#include <qwidget.h> +#include <qspinbox.h> +#include <qlabel.h> + + +class RDGpioSelector : public QWidget +{ + Q_OBJECT + public: + RDGpioSelector(QWidget *parent=0,const char *name=0); + ~RDGpioSelector(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + int pin() const; + void setPin(int pinno); + + signals: + void pinChanged(int card); + + private slots: + void pinData(int); + + private: + QSpinBox *gpio_pin_box; +}; + + +#endif + diff --git a/lib/rdgrid.cpp b/lib/rdgrid.cpp new file mode 100644 index 00000000..1b6a5829 --- /dev/null +++ b/lib/rdgrid.cpp @@ -0,0 +1,87 @@ +// rdgrid.cpp +// +// Abstract a Rivendell Log Manager Grid. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdgrid.cpp,v 1.6 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdgrid.h> + + +RDGrid::RDGrid(QString svc_name) +{ + grid_name=svc_name; + for(int i=0;i<7;i++) { + for(int j=0;j<24;j++) { + grid_clocks[i][j]=new RDClock(); + } + } +} + + +QString RDGrid::serviceName() const +{ + return grid_name; +} + + +void RDGrid::setServiceName(QString svc_name) +{ + grid_name=svc_name; +} + + +RDClock *RDGrid::clock(int dayofweek,int hour) +{ + if((dayofweek<1)||(dayofweek>1)||(hour<0)||(hour>23)) { + return NULL; + } + return grid_clocks[dayofweek][hour]; +} + + +void RDGrid::setClock(int dayofweek,int hour,RDClock *clock) +{ + if((dayofweek<1)||(dayofweek>1)||(hour<0)||(hour>23)) { + return; + } + *grid_clocks[dayofweek][hour]=*clock; +} + + +bool RDGrid::load() +{ + return false; +} + + +void RDGrid::save() +{ +} + + +void RDGrid::clear() +{ + grid_name=""; + for(int i=0;i<7;i++) { + for(int j=0;j<24;j++) { + grid_clocks[i][j]->clear(); + } + } +} + diff --git a/lib/rdgrid.h b/lib/rdgrid.h new file mode 100644 index 00000000..0fec9105 --- /dev/null +++ b/lib/rdgrid.h @@ -0,0 +1,49 @@ +// rdgrid.h +// +// Abstract a Rivendell Log Manager Grid +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdgrid.h,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDGRID_H +#define RDGRID_H + +#include <qsqldatabase.h> + +#include <rdclock.h> + +class RDGrid +{ + public: + RDGrid(QString svc_name); + QString serviceName() const; + void setServiceName(QString name); + RDClock *clock(int dayofweek,int hour); + void setClock(int dayofweek,int hour,RDClock *clock); + bool load(); + void save(); + void clear(); + + private: + QString grid_name; + RDClock *grid_clocks[7][24]; +}; + + +#endif diff --git a/lib/rdgroup.cpp b/lib/rdgroup.cpp new file mode 100644 index 00000000..56fa9373 --- /dev/null +++ b/lib/rdgroup.cpp @@ -0,0 +1,487 @@ +// rdgroup.cpp +// +// Abstract a Rivendell Group. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdgroup.cpp,v 1.23.8.1.2.3 2014/06/02 18:52:21 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <sys/types.h> +#include <unistd.h> + +#include <qobject.h> + +#include <rdconf.h> +#include <rdgroup.h> +#include <rddb.h> +#include <rdescape_string.h> +#include <rdweb.h> + +// +// Global Classes +// +RDGroup::RDGroup(QString name,bool create,QSqlDatabase *db) +{ + RDSqlQuery *q; + QString sql; + + group_db=db; + group_name=name; + + if(create) { + sql=QString().sprintf("INSERT INTO GROUPS SET NAME=\"%s\"", + (const char *)RDEscapeString(group_name)); + q=new RDSqlQuery(sql,group_db); + delete q; + } +} + + +bool RDGroup::exists() const +{ + return RDDoesRowExist("GROUPS","NAME",group_name,group_db); +} + + +QString RDGroup::name() const +{ + return group_name; +} + + +QString RDGroup::description() const +{ + return RDGetSqlValue("GROUPS","NAME",group_name,"DESCRIPTION",group_db). + toString(); +} + + +void RDGroup::setDescription(const QString &desc) const +{ + SetRow("DESCRIPTION",desc); +} + + +RDCart::Type RDGroup::defaultCartType() const +{ + return (RDCart::Type)RDGetSqlValue("GROUPS","NAME",group_name, + "DEFAULT_CART_TYPE",group_db).toUInt(); +} + + +void RDGroup::setDefaultCartType(RDCart::Type type) const +{ + SetRow("DEFAULT_CART_TYPE",(unsigned)type); +} + + +unsigned RDGroup::defaultLowCart() const +{ + return RDGetSqlValue("GROUPS","NAME",group_name,"DEFAULT_LOW_CART",group_db). + toUInt(); +} + + +void RDGroup::setDefaultLowCart(unsigned cartnum) const +{ + SetRow("DEFAULT_LOW_CART",cartnum); +} + + +unsigned RDGroup::defaultHighCart() const +{ + return RDGetSqlValue("GROUPS","NAME",group_name,"DEFAULT_HIGH_CART",group_db). + toUInt(); +} + + +void RDGroup::setDefaultHighCart(unsigned cartnum) const +{ + SetRow("DEFAULT_HIGH_CART",cartnum); +} + + +int RDGroup::cutShelflife() const +{ + return RDGetSqlValue("GROUPS","NAME",group_name,"CUT_SHELFLIFE",group_db). + toInt(); +} + + +void RDGroup::setCutShelflife(int days) const +{ + SetRow("CUT_SHELFLIFE",days); +} + + +bool RDGroup::deleteEmptyCarts() const +{ + return RDBool(RDGetSqlValue("GROUPS","NAME",group_name,"DELETE_EMPTY_CARTS", + group_db).toString()); +} + + +void RDGroup::setDeleteEmptyCarts(bool state) const +{ + SetRow("DELETE_EMPTY_CARTS",RDYesNo(state)); +} + + +QString RDGroup::defaultTitle() const +{ + return RDGetSqlValue("GROUPS","NAME",group_name,"DEFAULT_TITLE",group_db). + toString(); +} + + +void RDGroup::setDefaultTitle(const QString &str) +{ + SetRow("DEFAULT_TITLE",str); +} + + +bool RDGroup::enforceCartRange() const +{ + return RDBool(RDGetSqlValue("GROUPS","NAME",group_name,"ENFORCE_CART_RANGE", + group_db).toString()); +} + + +void RDGroup::setEnforceCartRange(bool state) const +{ + SetRow("ENFORCE_CART_RANGE",RDYesNo(state)); +} + + +bool RDGroup::exportReport(ExportType type) const +{ + return RDBool(RDGetSqlValue("GROUPS","NAME",group_name,ReportField(type), + group_db).toString()); +} + + +void RDGroup::setExportReport(ExportType type,bool state) const +{ + SetRow(ReportField(type),RDYesNo(state)); +} + + +bool RDGroup::enableNowNext() const +{ + return RDBool(RDGetSqlValue("GROUPS","NAME",group_name,"ENABLE_NOW_NEXT", + group_db).toString()); +} + + +void RDGroup::setEnableNowNext(bool state) const +{ + SetRow("ENABLE_NOW_NEXT",RDYesNo(state)); +} + + +QColor RDGroup::color() const +{ + return QColor(RDGetSqlValue("GROUPS","NAME",group_name,"COLOR",group_db). + toString()); +} + + +void RDGroup::setColor(const QColor &color) +{ + SetRow("COLOR",color.name()); +} + + +unsigned RDGroup::RDGroup::nextFreeCart(unsigned startcart) const +{ + return GetNextFreeCart(startcart); +} + + +int RDGroup::freeCartQuantity() const +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select DEFAULT_LOW_CART,DEFAULT_HIGH_CART\ + from GROUPS where NAME=\"%s\"", + (const char *)group_name); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return -1; + } + if((q->value(0).toInt()<0)||(q->value(1).toInt()<0)) { + delete q; + return -1; + } + int low=q->value(0).toInt(); + int high=q->value(1).toInt(); + sql=QString().sprintf("select NUMBER from CART\ + where (NUMBER>=%d)&&(NUMBER<=%d)", + q->value(0).toInt(),q->value(1).toInt()); + delete q; + q=new RDSqlQuery(sql); + int free=high-low-q->size(); + delete q; + + return free; +} + + +bool RDGroup::reserveCarts(std::vector<unsigned> *cart_nums, + const QString &station_name,RDCart::Type type, + unsigned quan) const +{ + unsigned next; + QString sql; + RDSqlQuery *q; + + cart_nums->clear(); + if((next=GetNextFreeCart(0))==0) { + return false; + } + while(next!=0) { + if(ReserveCart(station_name,type,next)) { + cart_nums->push_back(next); + next++; + } + else { + for(unsigned i=0;i<cart_nums->size();i++) { + sql=QString().sprintf("delete from CART where NUMBER=%u", + cart_nums->at(i)); + q=new RDSqlQuery(sql); + delete q; + } + cart_nums->clear(); + next=GetNextFreeCart(next+1); + } + if(cart_nums->size()==quan) { + return true; + } + } + + return false; +} + + +bool RDGroup::cartNumberValid(unsigned cartnum) const +{ + if((cartnum<1)||(cartnum>999999)) { + return false; + } + bool ret=false; + QString sql=QString().sprintf("select DEFAULT_LOW_CART,DEFAULT_HIGH_CART,\ + ENFORCE_CART_RANGE from GROUPS \ + where NAME=\"%s\"",(const char *)group_name); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + if(!RDBool(q->value(2).toString())) { + ret=true; + } + else { + if((cartnum>=q->value(0).toUInt())&&(cartnum<=q->value(1).toUInt())) { + ret=true; + } + } + } + delete q; + return ret; +} + + +QString RDGroup::xml() const +{ + QString sql; + RDSqlQuery *q; + QString ret=""; + + sql=QString().sprintf("select DESCRIPTION,DEFAULT_CART_TYPE,DEFAULT_LOW_CART,\ + DEFAULT_HIGH_CART,CUT_SHELFLIFE,DEFAULT_TITLE,\ + ENFORCE_CART_RANGE,REPORT_TFC,REPORT_MUS,\ + ENABLE_NOW_NEXT,COLOR \ + from GROUPS where NAME=\"%s\"", + (const char *)RDEscapeString(group_name)); + q=new RDSqlQuery(sql); + if(q->first()) { + ret+="<group>\n"; + ret+=" "+RDXmlField("name",group_name); + ret+=" "+RDXmlField("description",q->value(0).toString()); + switch(q->value(1).toUInt()) { + case RDCart::Audio: + ret+=" "+RDXmlField("defaultCartType","audio"); + break; + + case RDCart::Macro: + ret+=" "+RDXmlField("defaultCartType","macro"); + break; + + case RDCart::All: + break; + } + ret+=" "+RDXmlField("defaultLowCart",q->value(2).toUInt()); + ret+=" "+RDXmlField("defaultHighCart",q->value(3).toUInt()); + ret+=" "+RDXmlField("cutShelfLife",q->value(4).toInt()); + ret+=" "+RDXmlField("defaultTitle",q->value(5).toString()); + ret+=" "+RDXmlField("enforceCartRange",RDBool(q->value(6).toString())); + ret+=" "+RDXmlField("reportTfc",RDBool(q->value(7).toString())); + ret+=" "+RDXmlField("reportMus",RDBool(q->value(8).toString())); + ret+=" "+RDXmlField("enableNowNext",RDBool(q->value(9).toString())); + ret+=" "+RDXmlField("color",q->value(10).toString()); + ret+="</group>\n"; + } + delete q; + return ret; +} + + +unsigned RDGroup::GetNextFreeCart(unsigned startcart) const +{ + QString sql; + RDSqlQuery *q; + unsigned cart_low_limit; + unsigned cart_high_limit; + + sql=QString().sprintf("select DEFAULT_LOW_CART,DEFAULT_HIGH_CART\ + from GROUPS where NAME=\"%s\"", + (const char *)group_name); + q=new RDSqlQuery(sql); + if(q->first()) { + if(startcart>q->value(0).toUInt()) { + cart_low_limit=startcart; + } + else { + cart_low_limit=q->value(0).toUInt(); + } + cart_high_limit=q->value(1).toUInt(); + delete q; + if((cart_low_limit<1)||(startcart>cart_high_limit)) { + return 0; + } + sql=QString().sprintf("select NUMBER from CART where \ + (NUMBER>=%u)&&(NUMBER<=%u) order by NUMBER", + cart_low_limit,cart_high_limit); + q=new RDSqlQuery(sql); + if(q->size()<1) { + delete q; + return cart_low_limit; + } + for(unsigned i=cart_low_limit;i<=cart_high_limit;i++) { + if(!q->next()) { + delete q; + return i; + } + if(i!=q->value(0).toUInt()) { + delete q; + return i; + } + } + delete q; + } + else { + delete q; + } + return 0; +} + + +bool RDGroup::ReserveCart(const QString &station_name,RDCart::Type type, + unsigned cart_num) const +{ + // + // We use QSqlQuery here, not RDSqlQuery because the insert could + // fail and we don't want to reset the DB connection when that happens. + // + QString sql; + QSqlQuery *q; + bool ret=false; + + if((cart_num>=defaultLowCart())&&(cart_num<=defaultHighCart())) { + sql=QString().sprintf("insert into CART set NUMBER=%u,",cart_num)+ + "GROUP_NAME=\""+RDEscapeString(group_name)+"\","+ + QString().sprintf("TYPE=%d,",type)+ + "TITLE=\"["+RDEscapeString(QObject::tr("reserved"))+"]\","+ + "PENDING_STATION=\""+RDEscapeString(station_name)+"\","+ + QString().sprintf("PENDING_PID=%d,",getpid())+ + "PENDING_DATETIME=now()"; + q=new QSqlQuery(sql); + ret=q->isActive(); + delete q; + } + return ret; +} + + +void RDGroup::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE GROUPS SET %s=%d WHERE NAME=\"%s\"", + (const char *)param, + value, + (const char *)group_name); + q=new RDSqlQuery(sql,group_db); + delete q; +} + + +void RDGroup::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE GROUPS SET %s=%u WHERE NAME=\"%s\"", + (const char *)param, + value, + (const char *)group_name); + q=new RDSqlQuery(sql,group_db); + delete q; +} + + +void RDGroup::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE GROUPS SET %s=\"%s\" WHERE NAME=\"%s\"", + (const char *)param, + (const char *)RDEscapeString(value), + (const char *)group_name); + q=new RDSqlQuery(sql,group_db); + delete q; +} + + +QString RDGroup::ReportField(ExportType type) const +{ + switch(type) { + case RDGroup::Traffic: + return QString("REPORT_TFC"); + break; + + case RDGroup::Music: + return QString("REPORT_MUS"); + break; + + default: + break; + } + return QString(); +} + diff --git a/lib/rdgroup.h b/lib/rdgroup.h new file mode 100644 index 00000000..70c72136 --- /dev/null +++ b/lib/rdgroup.h @@ -0,0 +1,81 @@ +// rdgroup.h +// +// Abstract a Rivendell Service +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdgroup.h,v 1.17.8.1.2.1 2014/05/30 00:26:28 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> +#include <qcolor.h> + +#include <rdcart.h> + +#ifndef RDGROUP_H +#define RDGROUP_H + +class RDGroup +{ + public: + enum ExportType {None=0,Traffic=1,Music=2}; + RDGroup(QString name,bool create=false,QSqlDatabase *db=0); + QString name() const; + bool exists() const; + QString description() const; + void setDescription(const QString &desc) const; + RDCart::Type defaultCartType() const; + void setDefaultCartType(RDCart::Type type) const; + unsigned defaultLowCart() const; + void setDefaultLowCart(unsigned cartnum) const; + unsigned defaultHighCart() const; + void setDefaultHighCart(unsigned cartnum) const; + int cutShelflife() const; + void setCutShelflife(int days) const; + bool deleteEmptyCarts() const; + void setDeleteEmptyCarts(bool state) const; + QString defaultTitle() const; + void setDefaultTitle(const QString &str); + bool enforceCartRange() const; + void setEnforceCartRange(bool state) const; + bool exportReport(ExportType type) const; + void setExportReport(ExportType type,bool state) const; + bool enableNowNext() const; + void setEnableNowNext(bool state) const; + QColor color() const; + void setColor(const QColor &color); + unsigned nextFreeCart(unsigned startcart=0) const; + int freeCartQuantity() const; + bool reserveCarts(std::vector<unsigned> *cart_nums, + const QString &station_name,RDCart::Type type, + unsigned quan) const; + bool cartNumberValid(unsigned cartnum) const; + QString xml() const; + + private: + unsigned GetNextFreeCart(unsigned startcart) const; + bool ReserveCart(const QString &station_name,RDCart::Type type, + unsigned cart_num) const; + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,unsigned value) const; + void SetRow(const QString ¶m,const QString &value) const; + QString ReportField(ExportType type) const; + QSqlDatabase *group_db; + QString group_name; +}; + + +#endif diff --git a/lib/rdgroup_list.cpp b/lib/rdgroup_list.cpp new file mode 100644 index 00000000..ddceedbd --- /dev/null +++ b/lib/rdgroup_list.cpp @@ -0,0 +1,79 @@ +// rdgroup_list.cpp +// +// A container class for Rivendell Groups +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdgroup_list.cpp,v 1.9 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rddb.h> +#include <rdgroup_list.h> + + +RDGroupList::RDGroupList() +{ + clear(); +} + + +void RDGroupList::loadSvc(QString svcname) +{ + QString sql; + RDSqlQuery *q; + + clear(); + sql=QString().sprintf("select GROUP_NAME from AUDIO_PERMS where\ + SERVICE_NAME=\"%s\"", + (const char *)svcname); + q=new RDSqlQuery(sql); + while(q->next()) { + list_groups.push_back(QString(q->value(0).toString())); + } + delete q; +} + + +void RDGroupList::clear() +{ + list_groups.clear(); +} + + +int RDGroupList::size() const +{ + return list_groups.size(); +} + + +QString RDGroupList::group(unsigned n) const +{ + if(n<list_groups.size()) { + return list_groups[n]; + } + return QString(); +} + + +bool RDGroupList::isGroupValid(QString group) +{ + for(unsigned i=0;i<list_groups.size();i++) { + if(list_groups[i].upper()==group.upper()) { + return true; + } + } + return false; +} diff --git a/lib/rdgroup_list.h b/lib/rdgroup_list.h new file mode 100644 index 00000000..23cb8081 --- /dev/null +++ b/lib/rdgroup_list.h @@ -0,0 +1,46 @@ +// rdgroup_list.h +// +// A container class for Rivendell Groups +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdgroup_list.h,v 1.7 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDGROUP_LIST_H +#define RDGROUP_LIST_H + +#include <vector> +#include <qsqldatabase.h> + +using namespace std; + +class RDGroupList +{ + public: + RDGroupList(); + void loadSvc(QString svcname); + void clear(); + int size() const; + QString group(unsigned n) const; + bool isGroupValid(QString group); + + private: + vector<QString> list_groups; +}; + + +#endif diff --git a/lib/rdhotkeylist.cpp b/lib/rdhotkeylist.cpp new file mode 100644 index 00000000..c755667e --- /dev/null +++ b/lib/rdhotkeylist.cpp @@ -0,0 +1,137 @@ +// rdhotkeylist.cpp +// +// An Abstract of the rdhotkeylist +// +// (C) Copyright 2002-2004,2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdhotkeylist.cpp,v 1.2.6.1 2012/12/13 22:33:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include<vector> + +#include <stdlib.h> + +#include<rdhotkeylist.h> + +RDHotKeyList::RDHotKeyList( ) +{ + + hotkeylist.resize(0); + BuildKeyList(); +} + +RDHotKeyList::~RDHotKeyList() +{ + hotkeylist.clear(); +} + +void RDHotKeyList::BuildKeyList( ) +{ + char qtpath[256]; + char keyfile[256]; + char line[256]; + FILE *hkeyfile; + + char enumstring[11] = "enum Key {"; + QString KeyString; + QString KeyHex; + QString Filestring; + keyList CurKey; + char *p = {0}; + + if(getenv("QTDIR")==NULL) { + return; + } + strcpy(qtpath, (const char *) getenv("QTDIR")); + strcpy(keyfile,qtpath); + strcat(keyfile,"/include/qnamespace.h"); + hkeyfile = fopen(keyfile,"r"); + if (hkeyfile==NULL) { + return; + } + if (fgets(line,256,hkeyfile) !=NULL) { + while ((p = strstr(line,enumstring))== NULL ) { + if (fgets(line,256,hkeyfile) == NULL) { + break; + } + } + if (p != NULL) { + while ( ( fgets(line,256,hkeyfile) != NULL) && (!(strstr(line,"}")) ) ) { + QString buf = cleanStrings(QString().sprintf("%s",line)); + int acomment = buf.find("//"); + int eqsign = buf.find("="); + if ((eqsign != -1) && (acomment != 0) ) { + KeyString = buf.left((eqsign )); + KeyString = KeyString.mid(4); // Remove 'Key_' + int comma = buf.find(","); + if (comma != -1) { + KeyHex = buf.mid((eqsign + 1), + (comma - eqsign)-1 ); + } + else { + int comment = buf.find("//"); + if (comment != -1) { + KeyHex = buf.mid( (eqsign+1), + (comment - eqsign) ); + } + else { + KeyHex = buf.mid( (eqsign+1), + (buf.length() - eqsign) ); + } + } + bool ok; + int hotkey_int = KeyHex.toInt(&ok,16); //Convert to decimal + if (ok) { + CurKey.decvalue = hotkey_int; + CurKey.stringvalue = KeyString; + hotkeylist.push_back(CurKey) ; + } + } + } + } + } + fclose(hkeyfile); +} + +QString RDHotKeyList::cleanStrings( const QString sent) +{ + QString cleanstring; + for (unsigned i=0 ; i<sent.length(); i++) { + switch(((const char *)sent)[i]) { + case '\n': + break; + case '\t': + break; + case ' ': + break; + default: + cleanstring+=((const char *)sent)[i]; + break; + } + } + return cleanstring; +} + +QString RDHotKeyList::GetKeyCode(int number) +{ + for (unsigned i = 0; i < hotkeylist.size(); i++) { + if ((hotkeylist.at(i).decvalue) == number){ + return hotkeylist.at(i).stringvalue; + } + } + return (QString("")); +} + diff --git a/lib/rdhotkeylist.h b/lib/rdhotkeylist.h new file mode 100644 index 00000000..e2ac7727 --- /dev/null +++ b/lib/rdhotkeylist.h @@ -0,0 +1,50 @@ +// rdhotkeylist.h +// +// Abstract a Rivendell HotKey List from QT Key Library entries +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdhotkeylist.h,v 1.2 2010/10/04 18:11:46 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// written by Todd Baker bakert@rfa.org + +#include <vector> +#include <qstring.h> +#include <qfile.h> +#ifndef RDHOTKEYLIST_H +#define RDHOTKEYLIST_H + + +struct keyList { + int decvalue ; + QString stringvalue; +}; + +class RDHotKeyList +{ + +public: + RDHotKeyList( ); + ~RDHotKeyList( ) ; + void BuildKeyList( ); + QString GetKeyCode(int); +private: + std::vector<keyList> hotkeylist; + QString cleanStrings(const QString cleanstring); +}; + +#endif + diff --git a/lib/rdhotkeys.cpp b/lib/rdhotkeys.cpp new file mode 100644 index 00000000..a2ca5708 --- /dev/null +++ b/lib/rdhotkeys.cpp @@ -0,0 +1,321 @@ +// rdhotkeys.cpp +// +// Abstract an RDHotKeys Configuration. +// +// (C) Copyright 2002-2004,2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdhotkeys.cpp,v 1.2.6.1 2012/12/13 22:33:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rddb.h> +#include <rdconf.h> +#include <rdhotkeys.h> +#include <rdescape_string.h> + +// +// Global Classes +// +RDHotkeys::RDHotkeys(const QString &station,const QString &module) +{ + QString sql; + RDSqlQuery *q; + + station_hotkeys=station; + module_name=module; + + sql=QString().sprintf( + "select STATION_NAME from RDHOTKEYS \ + where STATION_NAME=\"%s\" AND \ + MODULE_NAME=\"%s\"", + (const char *)RDEscapeString(station_hotkeys), + (const char *)RDEscapeString(module_name)); + + q=new RDSqlQuery(sql); + + if(!q->first()) + { + // Do any RDHOTKEY Module initializations for new objects here! + + if (strcmp((const char *)module_name,"airplay") ==0 ) + { + delete q; + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=1,\ + KEY_LABEL=\"Start Line 1\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=2,\ + KEY_LABEL=\"Stop Line 1\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=3,\ + KEY_LABEL=\"Pause Line 1\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=4,\ + KEY_LABEL=\"Start Line 2\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=5,\ + KEY_LABEL=\"Stop Line 2\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=6,\ + KEY_LABEL=\"Pause Line 2\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=7,\ + KEY_LABEL=\"Start Line 3\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=8,\ + KEY_LABEL=\"Stop Line 3\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=9,\ + KEY_LABEL=\"Pause Line 3\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=10,\ + KEY_LABEL=\"Start Line 4\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=11,\ + KEY_LABEL=\"Stop Line 4\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=12,\ + KEY_LABEL=\"Pause Line 4\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=13,\ + KEY_LABEL=\"Start Line 5\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=14,\ + KEY_LABEL=\"Stop Line 5\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=15,\ + KEY_LABEL=\"Pause Line 5\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=16,\ + KEY_LABEL=\"Start Line 6\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=17,\ + KEY_LABEL=\"Stop Line 6\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=18,\ + KEY_LABEL=\"Pause Line 6\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=19,\ + KEY_LABEL=\"Start Line 7\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=20,\ + KEY_LABEL=\"Stop Line 7\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=21,\ + KEY_LABEL=\"Pause Line 7\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=22,\ + KEY_LABEL=\"Add\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=23,\ + KEY_LABEL=\"Delete\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=24,\ + KEY_LABEL=\"Copy\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=25,\ + KEY_LABEL=\"Move\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=26,\ + KEY_LABEL=\"Sound Panel\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=27,\ + KEY_LABEL=\"Main Log\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=28,\ + KEY_LABEL=\"Aux Log 1\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=29,\ + KEY_LABEL=\"Aux Log 2\" ", + (const char *)RDEscapeString(station_hotkeys)); + q=new RDSqlQuery(sql); + } + } + delete q; +} + + +QString RDHotkeys::station() const +{ + return station_hotkeys; +} + + +QString RDHotkeys::GetRowLabel(const QString &station,const QString &module,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + QString hotkey_label; + + sql=QString().sprintf("SELECT KEY_LABEL FROM RDHOTKEYS WHERE STATION_NAME=\"%s\" \ + AND MODULE_NAME=\"%s\" and KEY_VALUE = \"%s\"", + (const char *)station, + (const char *)module, + (const char *)value); + q=new RDSqlQuery(sql); + + if(!q->first()) { + hotkey_label = QString(""); + } + else { + hotkey_label = QString().sprintf("%s",(const char *)q->value(0).toString()); + } + + delete q; + return hotkey_label; +} + diff --git a/lib/rdhotkeys.h b/lib/rdhotkeys.h new file mode 100644 index 00000000..cb687490 --- /dev/null +++ b/lib/rdhotkeys.h @@ -0,0 +1,26 @@ +// rdlogedit_conf.h +// +// Abstract RDHotkeys Configuration +// + +#ifndef RDHOTKEYS_H +#define RDHOTKEYS_H + +#include <qsqldatabase.h> + + +class RDHotkeys +{ + public: + RDHotkeys(const QString &station,const QString &module); + QString station() const; + int inputCard() const; + QString GetRowLabel(const QString &station,const QString &value,const QString &module) const; + + private: + QString station_hotkeys; + QString module_name; +}; + + +#endif diff --git a/lib/rdidvalidator.cpp b/lib/rdidvalidator.cpp new file mode 100644 index 00000000..699a4d63 --- /dev/null +++ b/lib/rdidvalidator.cpp @@ -0,0 +1,52 @@ +// rdidvalidator.cpp +// +// Validate a string as being valid for a MySQL identifier. +// See http://dev.mysql.com/doc/refman/5.0/en/identifiers.html +// +// (C) Copyright 2014 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdidvalidator.cpp,v 1.1.2.1 2014/05/21 18:19:42 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdidvalidator.h> + +RDIdValidator::RDIdValidator(QObject *parent) + : QValidator(parent) +{ + banned_chars.push_back('/'); + banned_chars.push_back('\\'); + banned_chars.push_back('.'); + banned_chars.push_back(96); // Apostrophe Quote + banned_chars.push_back(0); // NULL +} + + +QValidator::State RDIdValidator::validate(QString &input,int &pos) const +{ + char c=input.at(pos-1).latin1(); + for(unsigned i=0;i<banned_chars.size();i++) { + if(banned_chars[i]==c) { + return QValidator::Invalid; + } + } + return QValidator::Acceptable; +} + + +void RDIdValidator::addBannedChar(char c) +{ + banned_chars.push_back(c); +} diff --git a/lib/rdidvalidator.h b/lib/rdidvalidator.h new file mode 100644 index 00000000..2c1c94bd --- /dev/null +++ b/lib/rdidvalidator.h @@ -0,0 +1,43 @@ +// rdidvalidator.h +// +// Validate a string as being valid for a MySQL identifier. +// See http://dev.mysql.com/doc/refman/5.0/en/identifiers.html +// +// (C) Copyright 2014 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdidvalidator.h,v 1.1.2.1 2014/05/21 18:19:42 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDIDVALIDATOR_H +#define RDIDVALIDATOR_H + +#include <vector> + +#include <qvalidator.h> + +class RDIdValidator : public QValidator +{ + public: + RDIdValidator(QObject *parent=0); + QValidator::State validate(QString &input,int &pos) const; + void addBannedChar(char c); + + private: + std::vector<char> banned_chars; +}; + + +#endif // RDIDVALIDATOR_H diff --git a/lib/rdimport_audio.cpp b/lib/rdimport_audio.cpp new file mode 100644 index 00000000..1b01287f --- /dev/null +++ b/lib/rdimport_audio.cpp @@ -0,0 +1,700 @@ +// rdimport_audio.cpp +// +// Audio File Importation Dialog for Rivendell. +// +// (C) Copyright 2002-2004,2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdimport_audio.cpp,v 1.27.4.3 2013/11/13 23:36:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> + +#include <qpushbutton.h> +#include <qfiledialog.h> +#include <qmessagebox.h> +#include <qcheckbox.h> +#include <qpainter.h> + +#include <rd.h> +#include <rdconf.h> +#include <rdwavefile.h> +#include <rdcart.h> +#include <rdcut.h> +#include <rdescape_string.h> +#include <rdstation.h> +#include <rdimport_audio.h> +#include <rdlibrary_conf.h> + +RDImportAudio::RDImportAudio(QString cutname,QString *path, + RDSettings *settings,bool *import_metadata, + RDWaveData *wavedata,RDCut *clipboard, + RDStation *station,RDUser *user, + bool *running,RDConfig *config, + QWidget *parent,const char *name) + : QDialog(parent,name) +{ + import_config=config; + import_default_settings=settings; + import_path=path; + import_settings=settings; + import_cutname=cutname; + import_import_metadata=import_metadata; + import_wavedata=wavedata; + import_clipboard=clipboard; + import_running=running; + import_station=station; + import_user=user; + import_file_filter=RD_AUDIO_FILE_FILTER; + import_import_conv=NULL; + import_export_conv=NULL; + + setCaption(tr("Import/Export Audio File")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont mode_font=QFont("Helvetica",14,QFont::Bold); + mode_font.setPixelSize(14); + + // + // Mode Group + // + import_mode_group=new QButtonGroup(this,"import_mode_group"); + import_mode_group->hide(); + connect(import_mode_group,SIGNAL(clicked(int)), + this,SLOT(modeClickedData(int))); + + // + // Input Mode Button + // + import_importmode_button=new QRadioButton(tr("Import File"), this,"import_importmode_button"); + import_mode_group->insert(import_importmode_button); + import_importmode_button->setGeometry(10,10,sizeHint().width()-40,15); + import_importmode_button->setFont(mode_font); + import_importmode_button->setChecked(true); + + // + // Input Filename + // + import_in_filename_edit=new QLineEdit(this,"import_in_filename_edit"); + import_in_filename_edit->setGeometry(85,30,sizeHint().width()-180,20); + connect(import_in_filename_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(filenameChangedData(const QString &))); + import_in_filename_label= + new QLabel(import_in_filename_edit,tr("Filename:"), + this,"import_in_filename_label"); + import_in_filename_label->setGeometry(10,30,70,20); + import_in_filename_label->setFont(label_font); + import_in_filename_label->setAlignment(AlignVCenter|AlignRight); + + // + // Input File Selector Button + // + import_in_selector_button= + new QPushButton(tr("&Select"),this,"import_in_selector_button"); + import_in_selector_button->setGeometry(sizeHint().width()-85,27,70,26); + connect(import_in_selector_button,SIGNAL(clicked()), + this,SLOT(selectInputFileData())); + + // + // Input Metadata + // + import_in_metadata_box=new QCheckBox(tr("Import file metadata"),this,"import_in_metadata_box"); + import_in_metadata_box->setGeometry(95,56,160,15); + import_in_metadata_box->setChecked(*import_import_metadata); + import_in_metadata_box->setFont(label_font); + + // + // Input Channels + // + import_channels_box=new QComboBox(this,"import_channels_box"); + import_channels_box->setGeometry(310,54,50,20); + import_channels_label= + new QLabel(import_channels_box,tr("Channels:"), + this,"import_channels_label"); + import_channels_label->setGeometry(230,54,75,20); + import_channels_label->setFont(label_font); + import_channels_label->setAlignment(AlignRight|AlignVCenter); + + // + // Autotrim Check Box + // + import_autotrim_box=new QCheckBox(tr("Autotrim"),this,"import_autotrim_box"); + import_autotrim_box->setGeometry(95,82,80,15); + import_autotrim_box->setChecked(true); + import_autotrim_box->setFont(label_font); + connect(import_autotrim_box,SIGNAL(toggled(bool)), + this,SLOT(autotrimCheckData(bool))); + + // + // Autotrim Level + // + import_autotrim_spin=new QSpinBox(this,"import_autotrim_spin"); + import_autotrim_spin->setGeometry(235,80,40,20); + import_autotrim_spin->setRange(-99,0); + import_autotrim_label=new QLabel(import_autotrim_spin,tr("Level:"), + this,"autotrim_spin_label"); + import_autotrim_label->setGeometry(185,80,45,20); + import_autotrim_label->setFont(label_font); + import_autotrim_label->setAlignment(AlignRight|AlignVCenter); + import_autotrim_unit=new QLabel(tr("dBFS"),this,"autotrim_unit_label"); + import_autotrim_unit->setGeometry(280,80,40,20); + import_autotrim_unit->setFont(label_font); + import_autotrim_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Output Mode Button + // + import_exportmode_button=new QRadioButton(tr("Export File"),this,"import_exportmode_button"); + import_mode_group->insert(import_exportmode_button); + import_exportmode_button->setGeometry(10,120,sizeHint().width()-40,15); + import_exportmode_button->setFont(mode_font); + + // + // Output Filename + // + import_out_filename_edit=new QLineEdit(this,"import_out_filename_edit"); + import_out_filename_edit->setGeometry(85,140,sizeHint().width()-180,20); + connect(import_out_filename_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(filenameChangedData(const QString &))); + import_out_filename_edit->setReadOnly(true); + import_out_filename_label= + new QLabel(import_out_filename_edit,tr("Filename:"), + this,"import_out_filename_label"); + import_out_filename_label->setGeometry(10,140,70,20); + import_out_filename_label->setFont(label_font); + import_out_filename_label->setAlignment(AlignVCenter|AlignRight); + + // + // Output File Selector Button + // + import_out_selector_button= + new QPushButton(tr("&Select"),this,"import_out_selector_button"); + import_out_selector_button->setGeometry(sizeHint().width()-85,137,70,26); + connect(import_out_selector_button,SIGNAL(clicked()), + this,SLOT(selectOutputFileData())); + + // + // Output Metadata + // + import_out_metadata_box=new QCheckBox(tr("Export file metadata"),this,"import_out_metadata_box"); + import_out_metadata_box->setGeometry(95,161,sizeHint().width()-210,15); + import_out_metadata_box->setChecked(*import_import_metadata); + import_out_metadata_box->setFont(label_font); + + // + // Output Format + // + import_format_edit=new QLineEdit(this,"import_format_edit"); + import_format_edit->setGeometry(85,181,sizeHint().width()-180,20); + import_format_edit->setReadOnly(true); + import_format_edit->setText(import_settings->description()); + import_format_label=new QLabel(import_out_filename_edit,tr("Format:"), + this,"import_out_filename_label"); + import_format_label->setGeometry(10,181,70,20); + import_format_label->setFont(label_font); + import_format_label->setAlignment(AlignVCenter|AlignRight); + + // + // Output Format Selector Button + // + import_out_format_button= + new QPushButton(tr("S&et"),this,"import_out_format_button"); + import_out_format_button->setGeometry(sizeHint().width()-85,178,70,26); + connect(import_out_format_button,SIGNAL(clicked()), + this,SLOT(selectOutputFormatData())); + + // + // Progress Bar + // + import_bar=new RDBusyBar(this,"import_bar"); + import_bar->setGeometry(10,230,sizeHint().width()-20,20); + + // + // Normalize Check Box + // + import_normalize_box=new QCheckBox(tr("Normalize"),this,"import_normalize_box"); + import_normalize_box->setGeometry(10,262,113,15); + import_normalize_box->setChecked(true); + import_normalize_box->setFont(label_font); + connect(import_normalize_box,SIGNAL(toggled(bool)), + this,SLOT(normalizeCheckData(bool))); + + // + // Normalize Level + // + import_normalize_spin=new QSpinBox(this,"import_normalize_spin"); + import_normalize_spin->setGeometry(160,260,40,20); + import_normalize_spin->setRange(-30,0); + import_normalize_label=new QLabel(import_normalize_spin,tr("Level:"), + this,"normalize_spin_label"); + import_normalize_label->setGeometry(110,260,45,20); + import_normalize_label->setFont(label_font); + import_normalize_label->setAlignment(AlignRight|AlignVCenter); + import_normalize_unit=new QLabel(tr("dBFS"),this,"normalize_unit_label"); + import_normalize_unit->setGeometry(205,260,40,20); + import_normalize_unit->setFont(label_font); + import_normalize_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Import Button + // + import_import_button=new QPushButton(tr("&Import"),this,"import_button"); + import_import_button-> + setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + import_import_button->setFont(button_font); + connect(import_import_button,SIGNAL(clicked()),this,SLOT(importData())); + + // + // Cancel Button + // + import_cancel_button=new QPushButton(tr("&Cancel"),this,"cancel_button"); + import_cancel_button-> + setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + import_cancel_button->setFont(button_font); + import_cancel_button->setDefault(true); + connect(import_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + import_normalize_spin->setValue(settings->normalizationLevel()/100); + import_autotrim_spin->setValue(settings->autotrimLevel()/100); + import_channels_box->insertItem("1"); + import_channels_box->insertItem("2"); + import_channels_box->setCurrentItem(settings->channels()-1); + + filenameChangedData(""); + modeClickedData(import_mode_group->selectedId()); +} + + +RDImportAudio::~RDImportAudio() +{ +} + + +QSize RDImportAudio::sizeHint() const +{ + return QSize(470,332); +} + + +QSizePolicy RDImportAudio::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDImportAudio::enableAutotrim(bool state) +{ + import_autotrim_box->setChecked(state); + autotrimCheckData(state); +} + + +void RDImportAudio::setAutotrimLevel(int lvl) +{ + import_autotrim_spin->setValue(lvl/100); +} + + +void RDImportAudio::enableNormalization(bool state) +{ + import_normalize_box->setChecked(state); + normalizeCheckData(state); +} + + +void RDImportAudio::setNormalizationLevel(int lvl) +{ + import_normalize_spin->setValue(lvl/100); +} + + +void RDImportAudio::setChannels(int chans) +{ + import_channels_box->setCurrentItem(chans-1); +} + + +int RDImportAudio::exec(bool enable_import,bool enable_export) +{ + import_importmode_button->setEnabled(enable_import); + import_in_filename_label->setEnabled(enable_import); + import_in_filename_edit->setEnabled(enable_import); + import_in_metadata_box->setEnabled(enable_import&&(import_wavedata!=NULL)); + import_in_selector_button->setEnabled(enable_import); + import_channels_label->setEnabled(enable_import); + import_autotrim_box->setEnabled(enable_import); + import_autotrim_spin-> + setEnabled(enable_import&&import_autotrim_box->isChecked()); + import_autotrim_label-> + setEnabled(enable_import&&import_autotrim_box->isChecked()); + import_autotrim_unit-> + setEnabled(enable_import&&import_autotrim_box->isChecked()); + import_channels_box->setEnabled(enable_import); + + import_exportmode_button->setEnabled(enable_export); + + if(enable_export&&(!enable_import)) { + import_exportmode_button->setChecked(true); + modeClickedData(import_mode_group->id(import_exportmode_button)); + } + return QDialog::exec(); +} + + +void RDImportAudio::modeClickedData(int id) +{ + import_in_filename_label->setDisabled(id); + import_in_filename_edit->setDisabled(id); + import_in_metadata_box->setDisabled(id||(import_wavedata==NULL)); + import_in_selector_button->setDisabled(id); + import_autotrim_box->setDisabled(id); + import_autotrim_spin->setDisabled(id); + import_autotrim_label->setDisabled(id); + import_autotrim_unit->setDisabled(id); + import_channels_box->setDisabled(id); + import_channels_label->setDisabled(id); + import_out_filename_label->setEnabled(id); + import_out_filename_edit->setEnabled(id); + import_out_metadata_box->setEnabled(id); + import_out_selector_button->setEnabled(id); + import_format_edit->setEnabled(id); + import_format_label->setEnabled(id); + import_out_format_button->setEnabled(id); + if(id) { + import_import_button->setText(tr("Export")); + } + else { + import_import_button->setText(tr("Import")); + } +} + + +void RDImportAudio::filenameChangedData(const QString &str) +{ + import_import_button->setDisabled(str.isEmpty()); +} + + +void RDImportAudio::normalizeCheckData(bool state) +{ + import_normalize_spin->setEnabled(state); + import_normalize_label->setEnabled(state); + import_normalize_unit->setEnabled(state); +} + + +void RDImportAudio::autotrimCheckData(bool state) +{ + import_autotrim_spin->setEnabled(state); + import_autotrim_label->setEnabled(state); + import_autotrim_unit->setEnabled(state); +} + + +void RDImportAudio::selectInputFileData() +{ + QString filename; + + if(import_in_filename_edit->text().isEmpty()) { + filename= + QFileDialog::getOpenFileName(*import_path, + import_file_filter,this); + } + else { + filename= + QFileDialog::getOpenFileName(import_in_filename_edit->text(), + import_file_filter,this); + } + if(!filename.isEmpty()) { + import_in_filename_edit->setText(filename); + *import_path=RDGetPathPart(import_in_filename_edit->text()); + } +} + + +void RDImportAudio::selectOutputFileData() +{ + QString filename; + QString filter=import_settings->formatName()+" (*."+ + RDSettings::defaultExtension(import_station->name(), + import_settings->format())+")"; + + if(import_out_filename_edit->text().isEmpty()) { + filename= + QFileDialog::getSaveFileName(*import_path,filter,this); + } + else { + filename=QFileDialog::getSaveFileName(import_out_filename_edit->text(), + filter,this); + } + if(!filename.isEmpty()) { + import_out_filename_edit-> + setText(RDSettings::pathName(import_station->name(),filename, + import_settings->format())); + *import_path=RDGetPathPart(import_out_filename_edit->text()); + } +} + + +void RDImportAudio::selectOutputFormatData() +{ + RDExportSettingsDialog *dialog= + new RDExportSettingsDialog(import_settings,import_station,this,"dialog"); + dialog->exec(); + delete dialog; + import_format_edit->setText(import_settings->description()); + import_out_filename_edit-> + setText(RDSettings::pathName(import_station->name(), + import_out_filename_edit->text(), + import_settings->format())); +} + + +void RDImportAudio::importData() +{ + if(import_import_conv!=NULL) { + import_import_conv->abort(); + return; + } + if(import_export_conv!=NULL) { + import_export_conv->abort(); + return; + } + if(import_mode_group->selectedId()==0) { + Import(); + } + else { + Export(); + } +} + + +void RDImportAudio::cancelData() +{ + done(-1); +} + + +void RDImportAudio::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->moveTo(10,110); + p->lineTo(sizeHint().width()-10,110); + p->moveTo(0,215); + p->lineTo(sizeHint().width(),215); + p->moveTo(0,216); + p->lineTo(sizeHint().width(),216); + p->end(); + delete p; +} + + +void RDImportAudio::closeEvent(QCloseEvent *e) +{ + if(!(*import_running)) { + cancelData(); + } +} + + +void RDImportAudio::Import() +{ + RDSettings settings; + RDAudioImport::ErrorCode conv_err; + RDAudioConvert::ErrorCode audio_conv_err; + + if(*import_running) { + return; + } + + import_import_button->setText(tr("Abort")); + if(!QFile::exists(import_in_filename_edit->text())) { + QMessageBox::warning(this,tr("Import Audio File"), + tr("File does not exist!")); + return; + } + + // + // Import + // + StartBar(); + RDCut *cut=new RDCut(import_cutname); + import_import_conv=new RDAudioImport(import_station,import_config,this); + import_import_conv->setCartNumber(cut->cartNumber()); + import_import_conv->setCutNumber(cut->cutNumber()); + import_import_conv->setSourceFile(import_in_filename_edit->text()); + settings.setChannels(import_channels_box->currentItem()+1); + if(import_normalize_box->isChecked()) { + settings.setNormalizationLevel(import_normalize_spin->value()); + } + if(import_autotrim_box->isChecked()) { + settings.setAutotrimLevel(import_autotrim_spin->value()); + } + import_import_conv->setDestinationSettings(&settings); + import_import_conv->setUseMetadata(false); + *import_running=true; + import_import_aborted=false; + conv_err=import_import_conv->runImport(import_user->name(),import_user->password(),&audio_conv_err); + *import_running=false; + StopBar(); + switch(conv_err) { + case RDAudioImport::ErrorOk: + if(import_in_metadata_box->isChecked()) { + RDWaveFile *wave=new RDWaveFile(import_in_filename_edit->text()); + wave->openWave(import_wavedata); + wave->closeWave(); + delete wave; + } + cut->setOriginName(import_station->name()); + cut-> + setOriginDatetime(QDateTime(QDate::currentDate(),QTime::currentTime())); + QMessageBox::information(this,tr("Import Complete"), + tr("Import complete!")); + break; + + default: + QMessageBox::warning(this,tr("Import Error"), + RDAudioImport::errorText(conv_err,audio_conv_err)); + } + delete import_import_conv; + import_import_conv=NULL; + delete cut; + import_import_button->setText(tr("Import")); + done(0); +} + + +void RDImportAudio::Export() +{ + QString custom_cmd; + RDAudioExport::ErrorCode conv_err; + RDAudioConvert::ErrorCode audio_conv_err; + + if(*import_running) { + return; + } + import_import_button->setText(tr("Abort")); + + // + // Check Before Overwriting + // + import_dest_filename=import_out_filename_edit->text(); + if(QFile::exists(import_dest_filename)) { + if(QMessageBox::warning(this,tr("File Exists"), + tr("The selected file already exists!\nDo you want to overwrite it?"), + QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) { + return; + } + } + + // + // Export + // + StartBar(); + RDCut *cut=new RDCut(import_cutname); + import_settings->setNormalizationLevel(import_normalize_spin->value()); + import_export_conv=new RDAudioExport(import_station,import_config,this); + import_export_conv->setCartNumber(cut->cartNumber()); + import_export_conv->setCutNumber(cut->cutNumber()); + import_export_conv->setDestinationFile(import_dest_filename); + import_export_conv->setDestinationSettings(import_settings); + import_export_conv->setRange(cut->startPoint(),cut->endPoint()); + import_export_conv->setEnableMetadata(import_out_metadata_box->isChecked()); + *import_running=true; + import_import_aborted=false; + conv_err=import_export_conv->runExport(import_user->name(), + import_user->password(), + &audio_conv_err); + *import_running=false; + StopBar(); + switch(conv_err) { + case RDAudioExport::ErrorOk: + QMessageBox::information(this,tr("Export Complete"), + tr("Export complete!")); + break; + + default: + QMessageBox::warning(this,tr("Export Error"), + RDAudioExport::errorText(conv_err,audio_conv_err)); + } + delete import_export_conv; + import_export_conv=NULL; + delete cut; + import_import_button->setText(tr("Export")); + done(0); +} + + +void RDImportAudio::StartBar() +{ + import_bar->setEnabled(true); + import_bar->activate(true); + import_importmode_button->setDisabled(true); + import_exportmode_button->setDisabled(true); + import_in_filename_label->setDisabled(true); + import_in_filename_edit->setDisabled(true); + import_in_metadata_box->setDisabled(true); + import_in_selector_button->setDisabled(true); + import_channels_label->setDisabled(true); + import_out_filename_label->setDisabled(true); + import_out_filename_edit->setDisabled(true); + import_out_metadata_box->setDisabled(true); + import_out_selector_button->setDisabled(true); + import_format_label->setDisabled(true); + import_format_edit->setDisabled(true); + import_out_format_button->setDisabled(true); + import_normalize_box->setDisabled(true); + import_normalize_spin->setDisabled(true); + import_normalize_label->setDisabled(true); + import_normalize_unit->setDisabled(true); + import_autotrim_box->setDisabled(true); + import_autotrim_spin->setDisabled(true); + import_autotrim_label->setDisabled(true); + import_autotrim_unit->setDisabled(true); + import_channels_box->setDisabled(true); + import_cancel_button->setDisabled(true); + // import_import_button->setDisabled(true); +} + + +void RDImportAudio::StopBar() +{ + import_bar->activate(false); + import_bar->setDisabled(true); +} diff --git a/lib/rdimport_audio.h b/lib/rdimport_audio.h new file mode 100644 index 00000000..0b3f8e9e --- /dev/null +++ b/lib/rdimport_audio.h @@ -0,0 +1,145 @@ +// import_audio.h +// +// Audio File Importation Dialog for Rivendell. +// +// (C) Copyright 2002-2003,2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdimport_audio.h,v 1.10 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef IMPORT_AUDIO_H +#define IMPORT_AUDIO_H + +#include <sys/types.h> +#include <unistd.h> +#include <qdialog.h> +#include <qlistview.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qprogressbar.h> +#include <qtimer.h> +#include <qfile.h> +#include <qspinbox.h> +#include <qcombobox.h> +#include <qcheckbox.h> +#include <qtextedit.h> +#include <qbuttongroup.h> +#include <qradiobutton.h> + +#include <rdbusybar.h> +#include <rdwavedata.h> +#include <rdconfig.h> +#include <rdsettings.h> +#include <rdexport_settings_dialog.h> +#include <rdcut.h> +#include <rduser.h> +#include <rdaudioexport.h> +#include <rdaudioimport.h> + +// +// Widget Settings +// +#define IMPORT_BAR_INTERVAL 500 +#define IMPORT_TEMP_BASENAME "rdlib" + + +class RDImportAudio : public QDialog +{ + Q_OBJECT + public: + RDImportAudio(QString cutname,QString *path,RDSettings *settings, + bool *import_metadata,RDWaveData *wavedata, + RDCut *clipboard,RDStation *station,RDUser *user,bool *running, + RDConfig *config,QWidget *parent=0,const char *name=0); + ~RDImportAudio(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void enableAutotrim(bool state); + void setAutotrimLevel(int lvl); + void enableNormalization(bool state); + void setNormalizationLevel(int lvl); + void setChannels(int chans); + + public slots: + int exec(bool enable_import,bool enable_export); + + private slots: + void modeClickedData(int id); + void filenameChangedData(const QString &str); + void normalizeCheckData(bool state); + void autotrimCheckData(bool state); + void selectInputFileData(); + void selectOutputFileData(); + void selectOutputFormatData(); + void importData(); + void cancelData(); + + protected: + void paintEvent(QPaintEvent *e); + void closeEvent(QCloseEvent *e); + + private: + void Import(); + void Export(); + void StartBar(); + void StopBar(); + RDConfig *import_config; + RDSettings *import_default_settings; + RDStation *import_station; + RDUser *import_user; + RDCut *import_clipboard; + bool *import_running; + QButtonGroup *import_mode_group; + QRadioButton *import_importmode_button; + QRadioButton *import_exportmode_button; + QLabel *import_in_filename_label; + QLineEdit *import_in_filename_edit; + QCheckBox *import_in_metadata_box; + QPushButton *import_in_selector_button; + QLabel *import_channels_label; + QLabel *import_out_filename_label; + QLineEdit *import_out_filename_edit; + QCheckBox *import_out_metadata_box; + QPushButton *import_out_selector_button; + QLabel *import_format_label; + QLineEdit *import_format_edit; + QPushButton *import_out_format_button; + RDBusyBar *import_bar; + QCheckBox *import_normalize_box; + QSpinBox *import_normalize_spin; + QLabel *import_normalize_label; + QLabel *import_normalize_unit; + QCheckBox *import_autotrim_box; + QSpinBox *import_autotrim_spin; + QLabel *import_autotrim_label; + QLabel *import_autotrim_unit; + QComboBox *import_channels_box; + QPushButton *import_cancel_button; + QPushButton *import_import_button; + QString *import_path; + QString import_file_filter; + QString import_cutname; + QString import_dest_filename; + bool import_import_aborted; + bool *import_import_metadata; + RDSettings *import_settings; + RDWaveData *import_wavedata; + RDAudioImport *import_import_conv; + RDAudioExport *import_export_conv; +}; + + +#endif // RDIMPORT_AUDIO_H diff --git a/lib/rdinstancelock.cpp b/lib/rdinstancelock.cpp new file mode 100644 index 00000000..655a5b00 --- /dev/null +++ b/lib/rdinstancelock.cpp @@ -0,0 +1,105 @@ +// rdinstancelock.cpp +// +// An abstract instance-locking class. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdinstancelock.cpp,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <qstring.h> +#include <qdir.h> + +#include <rdinstancelock.h> + + +RDInstanceLock::RDInstanceLock(QString path) +{ + lock_path=path; + lock_locked=false; +} + + +RDInstanceLock::~RDInstanceLock() +{ + unlock(); +} + + +bool RDInstanceLock::lock() +{ + FILE *file; + pid_t pid; + QDir dir; + + if(MakeLock()) { + lock_locked=true; + return true; + } + if((file=fopen((const char *)lock_path,"r"))==NULL) { + lock_locked=false; + return false; + } + fscanf(file,"%d",&pid); + fclose(file); + dir.setPath(QString().sprintf("/proc/%u",pid)); + if(!dir.exists()) { + unlink((const char *)lock_path); + if(MakeLock()) { + lock_locked=true; + return true; + } + } + lock_locked=false; + return false; +} + + +void RDInstanceLock::unlock() +{ + if(lock_locked) { + unlink((const char *)lock_path); + } + lock_locked=false; +} + + +bool RDInstanceLock::locked() +{ + return lock_locked; +} + + +bool RDInstanceLock::MakeLock() +{ + FILE *file; + int fd=open((const char *)lock_path,O_WRONLY|O_CREAT|O_EXCL,S_IRUSR|S_IWUSR); + if(fd<0) { + return false; + } + file=fdopen(fd,"w"); + fprintf(file,"%u",getpid()); + fclose(file); + return true; +} diff --git a/lib/rdinstancelock.h b/lib/rdinstancelock.h new file mode 100644 index 00000000..ebecfc9a --- /dev/null +++ b/lib/rdinstancelock.h @@ -0,0 +1,45 @@ +// rdinstancelock.h +// +// An abstract instance-locking class. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdinstancelock.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDINSTANCELOCK_H +#define RDINSTANCELOCK_H + + +class RDInstanceLock +{ + public: + RDInstanceLock(QString path); + ~RDInstanceLock(); + bool lock(); + void unlock(); + bool locked(); + + private: + bool MakeLock(); + QString lock_path; + bool lock_locked; +}; + + + +#endif // RDINSTANCELOCK_H diff --git a/lib/rdintegerdialog.cpp b/lib/rdintegerdialog.cpp new file mode 100644 index 00000000..c9ddd7c5 --- /dev/null +++ b/lib/rdintegerdialog.cpp @@ -0,0 +1,112 @@ +// rdintegerdialog.cpp +// +// A widget to set an integer value. +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdintegerdialog.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qpushbutton.h> +#include <qlabel.h> + +#include <rdintegerdialog.h> + +RDIntegerDialog::RDIntegerDialog(int *value,const QString &lbl,int low,int high, + QWidget *parent,const char *name) + : QDialog(parent,name,false) +{ + int_value=value; + + // + // Fix the Window Size + // + setCaption(tr("Set Value")); + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont font=QFont("helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Value Control + // + int_value_box=new QSpinBox(this); + int_value_box->setGeometry(125,10,80,20); + int_value_box->setRange(low,high); + int_value_box->setValue(*value); + QLabel *label=new QLabel(int_value_box,lbl,this); + label->setGeometry(10,10,110,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // OK Button + // + QPushButton *button=new QPushButton(tr("&OK"),this); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setFont(font); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(tr("&Cancel"),this); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(font); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +RDIntegerDialog::~RDIntegerDialog() +{ +} + + +QSize RDIntegerDialog::sizeHint() const +{ + return QSize(240,100); +} + + +QSizePolicy RDIntegerDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDIntegerDialog::okData() +{ + *int_value=int_value_box->value(); + done(0); +} + + +void RDIntegerDialog::cancelData() +{ + done(-1); +} + + +void RDIntegerDialog::closeEvent(QCloseEvent *e) +{ + done(-1); +} diff --git a/lib/rdintegerdialog.h b/lib/rdintegerdialog.h new file mode 100644 index 00000000..f37a97c3 --- /dev/null +++ b/lib/rdintegerdialog.h @@ -0,0 +1,52 @@ +// rdintegerdialog.h +// +// A widget to set an integer value. +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdintegerdialog.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDINTEGERDIALOG_H +#define RDINTEGERDIALOG_H + +#include <qdialog.h> +#include <qspinbox.h> + +class RDIntegerDialog : public QDialog +{ + Q_OBJECT + public: + RDIntegerDialog(int *value,const QString &lbl,int low,int high, + QWidget *parent=0,const char *name=0); + ~RDIntegerDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + QSpinBox *int_value_box; + int *int_value; +}; + + +#endif diff --git a/lib/rdintegeredit.cpp b/lib/rdintegeredit.cpp new file mode 100644 index 00000000..af56285f --- /dev/null +++ b/lib/rdintegeredit.cpp @@ -0,0 +1,154 @@ +// rdintegeredit.cpp +// +// A widget for editing a list of integer values. +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdintegeredit.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <rdintegerdialog.h> +#include <rdintegeredit.h> + +RDIntegerEdit::RDIntegerEdit(const QString &lbl,int low,int high, + QWidget *parent,const char *name) + : QWidget(parent,name) +{ + edit_low=low; + edit_high=high; + + setCaption(tr("Set Value")); + + // + // Generate Fonts + // + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont button_font=QFont("Helvetica",10,QFont::Bold); + button_font.setPixelSize(10); + + // + // Values List + // + edit_values_box=new QListBox(this); + + // + // Title Label + // + edit_label=new QLabel(edit_values_box,lbl,this); + edit_label->setAlignment(AlignCenter); + edit_label->setFont(label_font); + + // + // Add Button + // + edit_add_button=new QPushButton(tr("Add"),this); + edit_add_button->setFont(button_font); + connect(edit_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Delete Button + // + edit_delete_button=new QPushButton(tr("Delete"),this); + edit_delete_button->setFont(button_font); + connect(edit_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); +} + + +QSize RDIntegerEdit::sizeHint() const +{ + return QSize(300,100); +} + + +QSizePolicy RDIntegerEdit::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +unsigned RDIntegerEdit::values(std::vector<int> *v) const +{ + v->clear(); + for(int i=0;i<edit_values_box->numRows();i++) { + v->push_back(edit_values_box->text(i).toInt()); + } + return v->size(); +} + + +void RDIntegerEdit::setValues(std::vector<int> *v) +{ + for(unsigned i=0;i<v->size();i++) { + edit_values_box->insertItem(QString().sprintf("%d",v->at(i))); + } +} + + +void RDIntegerEdit::setGeometry(int x,int y,int w,int h) +{ + QWidget::setGeometry(x,y,w,h); + edit_label->setGeometry(0,0,width(),20); + edit_values_box->setGeometry(0,20,width(),height()-60); + edit_add_button->setGeometry(0,height()-35,width()/2-5,30); + edit_delete_button->setGeometry(width()/2+5,height()-35,width()/2-5,30); +} + + +void RDIntegerEdit::addData() +{ + int value=edit_low; + int index=-1; + + RDIntegerDialog *ie= + new RDIntegerDialog(&value,edit_label->text(),edit_low,edit_high,this); + if(ie->exec()==0) { + for(unsigned i=0;i<edit_values_box->count();i++) { + if(edit_values_box->item(i)->text().toInt()<value) { + index=i; + } + if(edit_values_box->item(i)->text().toInt()==value) { + delete ie; + return; + } + } + edit_values_box->insertItem(QString().sprintf("%d",value),index+1); + } + delete ie; +} + + +void RDIntegerEdit::deleteData() +{ + QListBoxItem *item=edit_values_box->selectedItem(); + if(item==NULL) { + return; + } + delete item; +} + + +QListBoxItem *RDIntegerEdit::GetItem(int value) +{ + for(unsigned i=0;i<edit_values_box->count();i++) { + if(edit_values_box->item(i)->text().toInt()==value) { + return edit_values_box->item(i); + } + } + + return NULL; +} diff --git a/lib/rdintegeredit.h b/lib/rdintegeredit.h new file mode 100644 index 00000000..e5bca571 --- /dev/null +++ b/lib/rdintegeredit.h @@ -0,0 +1,63 @@ +// rdintegeredit.h +// +// A widget for editing a list of integer values. +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdintegeredit.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDINTEGEREDIT_H +#define RDINTEGEREDIT_H + +#include <vector> + +#include <qwidget.h> +#include <qlabel.h> +#include <qlistbox.h> +#include <qpushbutton.h> + +class RDIntegerEdit : public QWidget +{ + Q_OBJECT + public: + RDIntegerEdit(const QString &lbl,int low,int high, + QWidget *parent,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + unsigned values(std::vector<int> *v) const; + void setValues(std::vector<int> *v); + + public slots: + void setGeometry(int x,int y,int w,int h); + + private slots: + void addData(); + void deleteData(); + + private: + QListBoxItem *GetItem(int value); + QLabel *edit_label; + QListBox *edit_values_box; + QPushButton *edit_add_button; + QPushButton *edit_delete_button; + int edit_low; + int edit_high; +}; + + +#endif // RDINTEGEREDIT_H diff --git a/lib/rdlabel.cpp b/lib/rdlabel.cpp new file mode 100644 index 00000000..5a781c6d --- /dev/null +++ b/lib/rdlabel.cpp @@ -0,0 +1,141 @@ +// rdlabel.cpp +// +// Multiline button labelling that is smart about spaces and the like +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlabel.cpp,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <stdlib.h> +#include <stdio.h> +#include <qwidget.h> +#include <qlabel.h> +#include <qpainter.h> +#include <qcolor.h> +#include <qpalette.h> +#include <qsize.h> +#include <qrect.h> +#include <qpixmap.h> + +#include <rdlabel.h> + + +RDLabel::RDLabel(QWidget *parent,const char *name,WFlags f) + : QLabel(parent,name,f) +{ + label_wrap=false; +} + + +RDLabel::RDLabel(const QString &text,QWidget *parent=0,const char *name=0, + WFlags f) : QLabel(text,parent,name,f) +{ + label_wrap=false; + label_text=text; + QLabel::setText(WrapText()); +} + + +RDLabel::RDLabel(QWidget *buddy,const QString &text,QWidget *parent, + const char *name,WFlags f): QLabel(buddy,text,parent,name,f) +{ + label_wrap=false; + label_text=text; + QLabel::setText(WrapText()); +} + + +QString RDLabel::text() const +{ + return label_text; +} + + +void RDLabel::setFont(const QFont &font) +{ + label_font=font; + QLabel::setFont(font); + QLabel::setText(WrapText()); +} + + +bool RDLabel::wordWrapEnabled() const +{ + return label_wrap; +} + + +void RDLabel::setWordWrapEnabled(bool state) +{ + label_wrap=state; + QLabel::setText(WrapText()); +} + + +void RDLabel::setText(const QString &string) +{ + label_text=string; + QLabel::setText(WrapText()); +} + + +QString RDLabel::WrapText() +{ + QFontMetrics fm(label_font); + QString str; + QString residue=label_text; + bool space_found=false; + int l; + + if(label_wrap&&!label_text.isEmpty()) { + while(!residue.isEmpty()) { + space_found=false; + for(int i=residue.length();i>=0;i--) { + if((i==((int)residue.length()))||(residue.at(i).isSpace())) { + if(fm.boundingRect(residue.left(i)).width()<=width()) { + space_found=true; + if(!str.isEmpty()) { + str+="\n"; + } + str+=residue.left(i); + if(i==(int)residue.length()) { + return str; + } + residue=residue.right(residue.length()-i-1); + } + } + } + if(!space_found) { + l=residue.length(); + for(int i=l;i>=0;i--) { + if(fm.boundingRect(residue.left(i)).width()<=width()) { + if(!str.isEmpty()) { + str+="\n"; + } + str+=residue.left(i); + if(i==(int)residue.length()) { + return str; + } + residue=residue.right(residue.length()-i-1); + } + } + } + } + } + return label_text; +} diff --git a/lib/rdlabel.h b/lib/rdlabel.h new file mode 100644 index 00000000..fa5d86f2 --- /dev/null +++ b/lib/rdlabel.h @@ -0,0 +1,61 @@ +// rdlabel.h +// +// An label widget with word wrap. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlabel.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDLABEL_H +#define RDLABEL_H + +#include <qwidget.h> +#include <qlabel.h> +#include <qrangecontrol.h> +#include <qcolor.h> +#include <qpalette.h> +#include <qsize.h> +#include <qpixmap.h> + + +class RDLabel : public QLabel +{ + Q_OBJECT + + public: + RDLabel(QWidget *parent,const char *name,WFlags f=0); + RDLabel(const QString &text,QWidget *parent,const char *name,WFlags f=0); + RDLabel(QWidget *buddy,const QString &text,QWidget *parent,const char *name, + WFlags f=0); + QString text() const; + void setFont(const QFont &font); + bool wordWrapEnabled() const; + void setWordWrapEnabled(bool state); + + public slots: + void setText(const QString &string); + + private: + QString WrapText(); + QString label_text; + QFont label_font; + bool label_wrap; +}; + + +#endif // RDLABEL_H diff --git a/lib/rdlibrary_conf.cpp b/lib/rdlibrary_conf.cpp new file mode 100644 index 00000000..ee77f749 --- /dev/null +++ b/lib/rdlibrary_conf.cpp @@ -0,0 +1,422 @@ +// rdlibrary_conf.cpp +// +// Abstract an RDLibrary Configuration. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlibrary_conf.cpp,v 1.25.8.1 2014/01/09 01:03:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +#include <rddb.h> +#include <rdconf.h> +#include <rdlibrary_conf.h> +#include <rdescape_string.h> + + +// +// Global Classes +// +RDLibraryConf::RDLibraryConf(const QString &station,unsigned instance) +{ + RDSqlQuery *q; + QString sql; + + lib_station=station; + lib_instance=instance; + + sql=QString().sprintf("select ID from RDLIBRARY where STATION=\"%s\" && INSTANCE=%d", + (const char *)lib_station, + lib_instance); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + sql=QString().sprintf("insert into RDLIBRARY set STATION=\"%s\",INSTANCE=%d", + (const char *)lib_station, + lib_instance); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("select ID from RDLIBRARY where STATION=\"%s\" && INSTANCE=%d", + (const char *)lib_station, + lib_instance); + q=new RDSqlQuery(sql); + q->first(); + } + lib_id=q->value(0).toUInt(); + delete q; +} + + +QString RDLibraryConf::station() const +{ + return lib_station; +} + + +unsigned RDLibraryConf::instance() const +{ + return lib_instance; +} + + +int RDLibraryConf::inputCard() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"INPUT_CARD").toInt(); +} + + +int RDLibraryConf::inputPort() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"INPUT_PORT").toInt(); +} + + +void RDLibraryConf::setInputCard(int input) const +{ + SetRow("INPUT_CARD",input); +} + + +void RDLibraryConf::setInputPort(int input) const +{ + SetRow("INPUT_PORT",input); +} + + +int RDLibraryConf::outputCard() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"OUTPUT_CARD").toInt(); +} + + +int RDLibraryConf::outputPort() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"OUTPUT_PORT").toInt(); +} + + +void RDLibraryConf::setOutputCard(int output) const +{ + SetRow("OUTPUT_CARD",output); +} + + +void RDLibraryConf::setOutputPort(int output) const +{ + SetRow("OUTPUT_PORT",output); +} + + +int RDLibraryConf::voxThreshold() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"VOX_THRESHOLD").toInt(); +} + + +void RDLibraryConf::setVoxThreshold(int level) const +{ + SetRow("VOX_THRESHOLD",level); +} + + +int RDLibraryConf::trimThreshold() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"TRIM_THRESHOLD").toInt(); +} + + +void RDLibraryConf::setTrimThreshold(int level) const +{ + SetRow("TRIM_THRESHOLD",level); +} + + +unsigned RDLibraryConf::defaultFormat() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"DEFAULT_FORMAT").toUInt(); +} + + +void RDLibraryConf::setDefaultFormat(unsigned format) const +{ + SetRow("DEFAULT_FORMAT",format); +} + + +unsigned RDLibraryConf::defaultChannels() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"DEFAULT_CHANNELS").toUInt(); +} + + +void RDLibraryConf::setDefaultChannels(unsigned chans) const +{ + SetRow("DEFAULT_CHANNELS",chans); +} + + +unsigned RDLibraryConf::defaultLayer() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"DEFAULT_LAYER").toUInt(); +} + + +void RDLibraryConf::setDefaultLayer(unsigned layer) const +{ + SetRow("DEFAULT_LAYER",layer); +} + + +unsigned RDLibraryConf::defaultBitrate() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"DEFAULT_BITRATE").toUInt(); +} + + +void RDLibraryConf::setDefaultBitrate(unsigned rate) const +{ + SetRow("DEFAULT_BITRATE",rate); +} + + +RDLibraryConf::RecordMode RDLibraryConf::defaultRecordMode() const +{ + return (RDLibraryConf::RecordMode) + RDGetSqlValue("RDLIBRARY","ID",lib_id,"DEFAULT_RECORD_MODE").toUInt(); +} + + +void RDLibraryConf::setDefaultRecordMode(RecordMode mode) const +{ + SetRow("DEFAULT_RECORD_MODE",(unsigned)mode); +} + + +bool RDLibraryConf::defaultTrimState() const +{ + return RDBool(RDGetSqlValue("RDLIBRARY","ID",lib_id,"DEFAULT_TRIM_STATE"). + toString()); +} + + +void RDLibraryConf::setDefaultTrimState(bool state) const +{ + SetRow("DEFAULT_TRIM_STATE",state); +} + + +unsigned RDLibraryConf::maxLength() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"MAXLENGTH").toUInt(); +} + + +void RDLibraryConf::setMaxLength(unsigned length) const +{ + SetRow("MAXLENGTH",length); +} + + +unsigned RDLibraryConf::tailPreroll() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"TAIL_PREROLL").toUInt(); +} + + +void RDLibraryConf::setTailPreroll(unsigned length) const +{ + SetRow("TAIL_PREROLL",length); +} + + +QString RDLibraryConf::ripperDevice() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"RIPPER_DEVICE").toString(); +} + + +void RDLibraryConf::setRipperDevice(QString dev) const +{ + SetRow("RIPPER_DEVICE",dev); +} + + +int RDLibraryConf::paranoiaLevel() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"PARANOIA_LEVEL").toInt(); +} + + +void RDLibraryConf::setParanoiaLevel(int level) const +{ + SetRow("PARANOIA_LEVEL",level); +} + + +int RDLibraryConf::ripperLevel() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"RIPPER_LEVEL").toInt(); +} + + +void RDLibraryConf::setRipperLevel(int level) const +{ + SetRow("RIPPER_LEVEL",level); +} + + +QString RDLibraryConf::cddbServer() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"CDDB_SERVER").toString(); +} + + +void RDLibraryConf::setCddbServer(QString server) const +{ + SetRow("CDDB_SERVER",server); +} + + +bool RDLibraryConf::enableEditor() const +{ + return RDBool(RDGetSqlValue("RDLIBRARY","ID",lib_id,"ENABLE_EDITOR"). + toString()); +} + + +void RDLibraryConf::setEnableEditor(bool state) const +{ + SetRow("ENABLE_EDITOR",RDYesNo(state)); +} + + +int RDLibraryConf::srcConverter() const +{ + return RDGetSqlValue("RDLIBRARY","ID",lib_id,"SRC_CONVERTER").toInt(); +} + + +void RDLibraryConf::setSrcConverter(int conv) const +{ + SetRow("SRC_CONVERTER",conv); +} + + +RDLibraryConf::SearchLimit RDLibraryConf::limitSearch() const +{ + return (RDLibraryConf::SearchLimit) + RDGetSqlValue("RDLIBRARY","ID",lib_id,"LIMIT_SEARCH").toInt(); +} + + +void RDLibraryConf::setLimitSearch(RDLibraryConf::SearchLimit lmt) const +{ + SetRow("LIMIT_SEARCH",(int)lmt); +} + + +bool RDLibraryConf::searchLimited() const +{ + return RDBool(RDGetSqlValue("RDLIBRARY","ID",lib_id,"SEARCH_LIMITED"). + toString()); +} + + +void RDLibraryConf::setSearchLimited(bool state) const +{ + SetRow("SEARCH_LIMITED",RDYesNo(state)); +} + + +void RDLibraryConf::getSettings(RDSettings *s) const +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select DEFAULT_CHANNELS,DEFAULT_SAMPRATE,\ + DEFAULT_FORMAT,DEFAULT_BITRATE,RIPPER_LEVEL,\ + TRIM_THRESHOLD from RDLIBRARY \ + where STATION=\"%s\" && INSTANCE=%d", + (const char *)lib_station,lib_instance); + q=new RDSqlQuery(sql); + s->clear(); + if(q->first()) { + s->setChannels(q->value(0).toUInt()); + s->setSampleRate(q->value(1).toUInt()); + switch(q->value(2).toInt()) { + case 0: + s->setFormat(RDSettings::Pcm16); + break; + + case 1: + s->setFormat(RDSettings::MpegL2); + break; + } + s->setBitRate(q->value(3).toUInt()); + s->setNormalizationLevel(q->value(4).toUInt()); + s->setAutotrimLevel(q->value(5).toUInt()); + } + delete q; +} + + +void RDLibraryConf::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE RDLIBRARY SET %s=%d WHERE STATION=\"%s\" && INSTANCE=%d", + (const char *)param, + value, + (const char *)lib_station, + lib_instance); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDLibraryConf::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE RDLIBRARY SET %s=%d WHERE STATION=\"%s\" && INSTANCE=%d", + (const char *)param, + value, + (const char *)lib_station, + lib_instance); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDLibraryConf::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE RDLIBRARY SET %s=\"%s\" WHERE STATION=\"%s\" && INSTANCE=%d", + (const char *)param, + (const char *)RDEscapeString(value), + (const char *)lib_station, + lib_instance); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDLibraryConf::SetRow(const QString ¶m,bool value) const +{ + SetRow(param,RDYesNo(value)); +} diff --git a/lib/rdlibrary_conf.h b/lib/rdlibrary_conf.h new file mode 100644 index 00000000..01d5891f --- /dev/null +++ b/lib/rdlibrary_conf.h @@ -0,0 +1,95 @@ +// rdlibrary_conf.h +// +// Abstract RDLibrary Configuration +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlibrary_conf.h,v 1.22.8.1 2014/01/09 01:03:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDLIBRARY_CONF_H +#define RDLIBRARY_CONF_H + +#include <qsqldatabase.h> + +#include <rdsettings.h> + +class RDLibraryConf +{ + public: + enum RecordMode {Manual=0,Vox=1}; + enum SearchLimit {LimitNo=0,LimitYes=1,LimitPrevious=2}; + RDLibraryConf(const QString &station,unsigned instance); + QString station() const; + unsigned instance() const; + int inputCard() const; + void setInputCard(int input) const; + int inputPort() const; + void setInputPort(int input) const; + int outputCard() const; + void setOutputCard(int output) const; + int outputPort() const; + void setOutputPort(int input) const; + int voxThreshold() const; + void setVoxThreshold(int level) const; + int trimThreshold() const; + void setTrimThreshold(int level) const; + unsigned defaultFormat() const; + void setDefaultFormat(unsigned format) const; + unsigned defaultChannels() const; + void setDefaultChannels(unsigned chans) const; + unsigned defaultLayer() const; + void setDefaultLayer(unsigned layer) const; + unsigned defaultBitrate() const; + void setDefaultBitrate(unsigned rate) const; + RDLibraryConf::RecordMode defaultRecordMode() const; + void setDefaultRecordMode(RecordMode mode) const; + bool defaultTrimState() const; + void setDefaultTrimState(bool state) const; + unsigned maxLength() const; + void setMaxLength(unsigned length) const; + unsigned tailPreroll() const; + void setTailPreroll(unsigned length) const; + QString ripperDevice() const; + void setRipperDevice(QString dev) const; + int paranoiaLevel() const; + void setParanoiaLevel(int level) const; + int ripperLevel() const; + void setRipperLevel(int level) const; + QString cddbServer() const; + void setCddbServer(QString server) const; + bool enableEditor() const; + void setEnableEditor(bool state) const; + void getSettings(RDSettings *s) const; + int srcConverter() const; + void setSrcConverter(int conv) const; + RDLibraryConf::SearchLimit limitSearch() const; + void setLimitSearch(RDLibraryConf::SearchLimit lmt) const; + bool searchLimited() const; + void setSearchLimited(bool state) const; + + private: + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,unsigned value) const; + void SetRow(const QString ¶m,const QString &value) const; + void SetRow(const QString ¶m,bool value) const; + QString lib_station; + unsigned lib_instance; + unsigned lib_id; +}; + + +#endif diff --git a/lib/rdlicense.cpp b/lib/rdlicense.cpp new file mode 100644 index 00000000..728591f5 --- /dev/null +++ b/lib/rdlicense.cpp @@ -0,0 +1,91 @@ +// rdlicense.cpp +// +// Display License Text. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlicense.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <qpushbutton.h> + +#include <rdlicense.h> + +#include <html_gpl2.cpp> + +RDLicense::RDLicense(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont button_font=QFont("Helvetica",14,QFont::Bold); + button_font.setPixelSize(14); + + license_edit=new QTextEdit(this,"license_edit"); + license_edit-> + setGeometry(10,10,sizeHint().width()-20,sizeHint().height()-70); + license_edit->setTextFormat(RichText); + license_edit->setReadOnly(true); + + // + // Close Button + // + QPushButton *button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Close")); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +QSize RDLicense::sizeHint() const +{ + return QSize(600,400); +} + + +QSizePolicy RDLicense::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDLicense::exec(RDLicense::License lic) +{ + switch(lic) { + case RDLicense::GplV2: + license_edit->setText((const char *)html_gpl2); + setCaption(tr("GNU Public License v2")); + break; + } + QDialog::exec(); +} + + +void RDLicense::closeData() +{ + done(0); +} diff --git a/lib/rdlicense.h b/lib/rdlicense.h new file mode 100644 index 00000000..94aaf5d1 --- /dev/null +++ b/lib/rdlicense.h @@ -0,0 +1,51 @@ +// rdlicense.h +// +// Display License Text. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlicense.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDLICENSE_H +#define RDLICENSE_H4 + +#include <qdialog.h> +#include <qtextedit.h> + + +class RDLicense : public QDialog +{ + Q_OBJECT + public: + enum License {GplV2=0}; + RDLicense(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + void exec(RDLicense::License lic); + + private slots: + void closeData(); + + private: + QTextEdit *license_edit; +}; + + +#endif // RDLICENSE_H diff --git a/lib/rdlineedit.cpp b/lib/rdlineedit.cpp new file mode 100644 index 00000000..b1319591 --- /dev/null +++ b/lib/rdlineedit.cpp @@ -0,0 +1,49 @@ +// rdlineedit.cpp +// +// An flashing button widget. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlineedit.cpp,v 1.1 2007/09/14 14:06:24 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <rdlineedit.h> + +RDLineEdit::RDLineEdit(QWidget *parent,const char *name) + : QLineEdit(parent,name) +{ +} + + +RDLineEdit::RDLineEdit(const QString &contents,QWidget *parent,const char *name) + : QLineEdit(contents,parent,name) +{ +} + + +void RDLineEdit::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Escape: + emit escapePressed(); + break; + + default: + break; + } + QLineEdit::keyPressEvent(e); +} diff --git a/lib/rdlineedit.h b/lib/rdlineedit.h new file mode 100644 index 00000000..f3699dc3 --- /dev/null +++ b/lib/rdlineedit.h @@ -0,0 +1,49 @@ +// rdlineedit.h +// +// An flashing button widget. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlineedit.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDLINEEDIT_H +#define RDLINEEDIT_H + +#include <qwidget.h> +#include <qlineedit.h> +#include <qpixmap.h> +#include <qcolor.h> + +class RDLineEdit : public QLineEdit +{ + Q_OBJECT + + public: + RDLineEdit(QWidget *parent,const char *name); + RDLineEdit(const QString &contents,QWidget *parent,const char *name); + + signals: + void escapePressed(); + + protected: + void keyPressEvent(QKeyEvent *e); +}; + + + +#endif diff --git a/lib/rdlist_groups.cpp b/lib/rdlist_groups.cpp new file mode 100644 index 00000000..e7c0c9c8 --- /dev/null +++ b/lib/rdlist_groups.cpp @@ -0,0 +1,171 @@ +// rdlist_groups.cpp +// +// A widget to select a Rivendell Group. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlist_groups.cpp,v 1.7 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qpushbutton.h> +#include <qlabel.h> +#include <rddb.h> +#include <qdatetime.h> + +#include <rdlist_groups.h> + + +RDListGroups::RDListGroups(QString *groupname,const QString &username, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + group_name=groupname; + + setCaption(tr("Select Group")); + + // + // Create Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + // + // Cart List + // + group_group_list=new QListView(this,"group_group_list"); + group_group_list->setSelectionMode(QListView::Single); + group_group_list->setGeometry(10,10, + sizeHint().width()-20,sizeHint().height()-80); + group_group_list->setAllColumnsShowFocus(true); + group_group_list->setItemMargin(5); + connect(group_group_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + group_group_list->addColumn(tr("NAME")); + group_group_list->setColumnAlignment(0,Qt::AlignHCenter); + group_group_list->addColumn(tr("DESCRIPTION")); + group_group_list->setColumnAlignment(1,Qt::AlignLeft); + + // + // OK Button + // + QPushButton *button=new QPushButton(tr("&OK"),this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setDefault(true); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(tr("&Cancel"),this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(button_font); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + BuildGroupList(username); +} + + +RDListGroups::~RDListGroups() +{ +} + + +QSize RDListGroups::sizeHint() const +{ + return QSize(400,370); +} + + +QSizePolicy RDListGroups::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDListGroups::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + okData(); +} + + +void RDListGroups::okData() +{ + QListViewItem *item=group_group_list->selectedItem(); + if(item==NULL) { + return; + } + *group_name=item->text(0); + done(0); +} + + +void RDListGroups::cancelData() +{ + done(-1); +} + + +void RDListGroups::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void RDListGroups::BuildGroupList(const QString &username) +{ + QString sql; + RDSqlQuery *q; + QListViewItem *item=NULL; + QListViewItem *cur_item=NULL; + + group_group_list->clear(); + sql=QString().sprintf("select USER_PERMS.GROUP_NAME,GROUPS.DESCRIPTION\ + from USER_PERMS left join GROUPS\ + on USER_PERMS.GROUP_NAME=GROUPS.NAME\ + where USER_NAME=\"%s\"", + (const char *)username); + q=new RDSqlQuery(sql); + while(q->next()) { + item=new QListViewItem(group_group_list); + item->setText(0,q->value(0).toString()); + item->setText(1,q->value(1).toString()); + if(q->value(0).toString()==*group_name) { + cur_item=item; + } + } + delete q; + if(cur_item!=NULL) { + group_group_list->setSelected(cur_item,true); + group_group_list->ensureItemVisible(item); + } +} diff --git a/lib/rdlist_groups.h b/lib/rdlist_groups.h new file mode 100644 index 00000000..8259cad4 --- /dev/null +++ b/lib/rdlist_groups.h @@ -0,0 +1,57 @@ +// rdlist_groups.h +// +// A widget to select a Rivendell Group. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlist_groups.h,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDLIST_GROUPS_H +#define RDLIST_GROUPS_H + +#include <qdialog.h> +#include <qlistview.h> +#include <qpushbutton.h> + + +class RDListGroups : public QDialog +{ + Q_OBJECT + public: + RDListGroups(QString *groupname,const QString &username, + QWidget *parent=0,const char *name=0); + ~RDListGroups(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + void BuildGroupList(const QString &username); + QString *group_name; + QListView *group_group_list; +}; + + +#endif // RDLIST_GROUPS_H + diff --git a/lib/rdlist_logs.cpp b/lib/rdlist_logs.cpp new file mode 100644 index 00000000..7b683fa7 --- /dev/null +++ b/lib/rdlist_logs.cpp @@ -0,0 +1,196 @@ +// rdlist_logs.cpp +// +// Select a Rivendell Log +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlist_logs.cpp,v 1.12 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qpushbutton.h> +#include <qdatetime.h> +#include <rddb.h> +#include <rdlist_logs.h> + +RDListLogs::RDListLogs(QString *logname,const QString &stationname, + QWidget *parent,const char *name,RDUser *rduser) + : QDialog(parent,name,true) +{ + list_stationname=stationname; + list_logname=logname; + list_user=rduser; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + + if (list_user != 0) { // RDStation::UserSec + setCaption(QString().sprintf("%s%s",(const char *)tr("Select Log - User: "), + (const char *)list_user->name() )); + } else { // RDStation::HostSec + setCaption(tr("Select Log")); + } + + // + // Log List + // + list_log_list=new QListView(this,"list_log_list"); + list_log_list->setGeometry(10,10, + sizeHint().width()-20,sizeHint().height()-80); + list_log_list->setAllColumnsShowFocus(true); + list_log_list->setItemMargin(5); + list_log_list->setSelectionMode(QListView::Single); + connect(list_log_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + list_log_list->addColumn(tr("NAME")); + list_log_list->setColumnAlignment(0,Qt::AlignLeft); + list_log_list->addColumn(tr("DESCRIPTION")); + list_log_list->setColumnAlignment(1,Qt::AlignLeft); + list_log_list->addColumn(tr("SERVICE")); + list_log_list->setColumnAlignment(2,Qt::AlignLeft); + + // + // OK Button + // + QPushButton *button=new QPushButton(this,"load_button"); + button->setGeometry(sizeHint().width()-190,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okButtonData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("Cancel")); + button->setDefault(true); + connect(button,SIGNAL(clicked()),this,SLOT(cancelButtonData())); + + RefreshList(); +} + + +QSize RDListLogs::sizeHint() const +{ + return QSize(500,300); +} + + +QSizePolicy RDListLogs::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDListLogs::closeEvent(QCloseEvent *e) +{ + done(1); +} + + +void RDListLogs::doubleClickedData(QListViewItem *,const QPoint &,int) +{ + okButtonData(); +} + + +void RDListLogs::okButtonData() +{ + QListViewItem *item=list_log_list->selectedItem(); + if(item==NULL) { + return; + } + *list_logname=item->text(0); + done(0); +} + + +void RDListLogs::cancelButtonData() +{ + done(1); +} + + +void RDListLogs::RefreshList() +{ + RDSqlQuery *q; + QString sql; + QListViewItem *l; + QListViewItem *view_item=NULL; + QDate current_date=QDate::currentDate(); + QStringList services_list; + + list_log_list->clear(); + + if (list_user != 0) { // RDStation::UserSec + services_list = list_user->services(); + } else { // RDStation::HostSec + sql=QString().sprintf("select SERVICE_NAME from SERVICE_PERMS \ + where STATION_NAME=\"%s\"", + (const char *)list_stationname); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + services_list.append( q->value(0).toString() ); + } + delete q; + } + + if(services_list.size()==0) { + return; + } + sql=QString().sprintf("select NAME,DESCRIPTION,SERVICE from LOGS \ + where (TYPE=0)&&(LOG_EXISTS=\"Y\")&&\ + ((START_DATE<=\"%s\")||(START_DATE=\"0000-00-00\"))&&\ + ((END_DATE>=\"%s\")||(END_DATE=\"0000-00-00\"))&&(", + (const char *)current_date.toString("yyyy-MM-dd"), + (const char *)current_date.toString("yyyy-MM-dd")); + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end(); ++it ) { + sql+=QString().sprintf("SERVICE=\"%s\"||", + (const char *)*it); + } + sql=sql.left(sql.length()-2); + sql+=")"; + q=new RDSqlQuery(sql); + while(q->next()) { + l=new QListViewItem(list_log_list); + l->setText(0,q->value(0).toString()); + l->setText(1,q->value(1).toString()); + l->setText(2,q->value(2).toString()); + if(l->text(0)==*list_logname) { + view_item=l; + } + } + delete q; + if(view_item!=NULL) { + list_log_list->setCurrentItem(view_item); + list_log_list->ensureItemVisible(view_item); + } +} diff --git a/lib/rdlist_logs.h b/lib/rdlist_logs.h new file mode 100644 index 00000000..df04ccab --- /dev/null +++ b/lib/rdlist_logs.h @@ -0,0 +1,69 @@ +// rdlist_logs.h +// +// Select a Rivendell Log +// +// The RDListLogs class creates a basic dialog that displays a list of logs +// (log name, description, and service) and allows the user to select one. If +// user security is enabled (by passing a an RDUser object to the constructor) +// then the list of logs is filtered based on the users permissions. +// +// (C) Copyright 2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlist_logs.h,v 1.8 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDLIST_LOGS_H +#define RDLIST_LOGS_H + +#include <qsqldatabase.h> +#include <qdialog.h> +#include <qlistview.h> +#include <qpushbutton.h> +#include <rduser.h> + + +class RDListLogs : public QDialog +{ + Q_OBJECT + + public: + /** + * Constructor for the RDListLogs object. + * + * NOTE: the presence of the optional rduser parameter is used to flag if + * user security should be used instead of host based security. + */ + RDListLogs(QString *logname,const QString &stationname, + QWidget *parent=0,const char *name=0,RDUser *rduser=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void doubleClickedData(QListViewItem *,const QPoint &,int); + void closeEvent(QCloseEvent *); + void okButtonData(); + void cancelButtonData(); + + private: + void RefreshList(); + QListView *list_log_list; + QString *list_logname; + QString list_stationname; + RDUser *list_user; +}; + + +#endif // RDLIST_LOGS_H diff --git a/lib/rdlistselector.cpp b/lib/rdlistselector.cpp new file mode 100644 index 00000000..ed0456ed --- /dev/null +++ b/lib/rdlistselector.cpp @@ -0,0 +1,270 @@ +// rdlistselector.cpp +// +// A List Selector Widget. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlistselector.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <stdlib.h> +#include <stdio.h> +#include <qwidget.h> +#include <qhbox.h> +#include <qvbox.h> +#include <qstring.h> +#include <qpixmap.h> +#include <qpixmap.h> + +#include <rdlistselector.h> + + +RDListSelector::RDListSelector(QWidget *parent,const char *name) + : QHBox(parent,name) +{ + QFont font; + + // + // Generate Font + // + font=QFont("Helvetica",10,QFont::Bold); + font.setPixelSize(10); + + setSpacing(10); + + QVBox *source_box=new QVBox(this,"source_box"); + list_source_label=new QLabel(source_box,"list_source_label"); + list_source_label->setFont(font); + list_source_label->setText(tr("Available Services")); + list_source_label->setAlignment(AlignCenter); + list_source_box=new QListBox(source_box,"list_source_box"); + + QVBox *button_box=new QVBox(this,"button_box"); + list_add_button=new QPushButton(button_box,"list_add_button"); + list_add_button->setText(tr("Add >>")); + list_add_button->setDisabled(true); + connect(list_add_button,SIGNAL(clicked()),this,SLOT(addData())); + list_remove_button=new QPushButton(button_box,"list_add_button"); + list_remove_button->setText(tr("<< Remove")); + list_remove_button->setDisabled(true); + connect(list_remove_button,SIGNAL(clicked()),this,SLOT(removeData())); + + QVBox *dest_box=new QVBox(this,"dest_box"); + list_dest_label=new QLabel(dest_box,"list_dest_label"); + list_dest_label->setFont(font); + list_dest_label->setText(tr("Active Services")); + list_dest_label->setAlignment(AlignCenter); + list_dest_box=new QListBox(dest_box,"list_dest_box"); +} + + +uint RDListSelector::sourceCount() const +{ + return list_source_box->count(); +} + + +uint RDListSelector::destCount() const +{ + return list_dest_box->count(); +} + + +void RDListSelector::sourceSetLabel(QString label) +{ + list_source_label->setText(label); +} + + +void RDListSelector::destSetLabel(QString label) +{ + list_dest_label->setText(label); +} + + +void RDListSelector::sourceInsertItem(const QString &text,int index) +{ + list_source_box->insertItem(text,index); + list_source_box->sort(); + CheckButtons(); +} + + +void RDListSelector::destInsertItem(const QString &text,int index) +{ + list_dest_box->insertItem(text,index); + list_dest_box->sort(); + CheckButtons(); +} + + +void RDListSelector::sourceRemoveItem(int index) +{ + list_source_box->removeItem(index); + CheckButtons(); +} + + +void RDListSelector::destRemoveItem(int index) +{ + list_dest_box->removeItem(index); + CheckButtons(); +} + + +QString RDListSelector::sourceText(int index) const +{ + return list_source_box->text(index); +} + + +QString RDListSelector::destText(int index) const +{ + return list_dest_box->text(index); +} + + +void RDListSelector::sourceChangeItem(const QString &text,int index) +{ + list_source_box->changeItem(text,index); + list_source_box->sort(); +} + + +void RDListSelector::destChangeItem(const QString &text,int index) +{ + list_dest_box->changeItem(text,index); + list_dest_box->sort(); +} + + +int RDListSelector::sourceNumItemsVisible() const +{ + return list_source_box->numItemsVisible(); +} + + +int RDListSelector::destNumItemsVisible() const +{ + return list_dest_box->numItemsVisible(); +} + + +int RDListSelector::sourceCurrentItem() const +{ + return list_source_box->currentItem(); +} + + +int RDListSelector::destCurrentItem() const +{ + return list_dest_box->currentItem(); +} + + +QString RDListSelector::sourceCurrentText() const +{ + return list_source_box->currentText(); +} + + +QString RDListSelector::destCurrentText() const +{ + return list_dest_box->currentText(); +} + + +void RDListSelector::sourceSetCurrentItem(int item) +{ + list_source_box->setCurrentItem(item); +} + + +void RDListSelector::destSetCurrentItem(int item) +{ + list_dest_box->setCurrentItem(item); +} + + +QListBoxItem *RDListSelector::sourceFindItem(const QString &text, + ComparisonFlags compare) const +{ + return list_source_box->findItem(text,compare); +} + + +QListBoxItem *RDListSelector::destFindItem(const QString &text, + ComparisonFlags compare) const +{ + return list_dest_box->findItem(text,compare); +} + + +void RDListSelector::clear() +{ + list_source_box->clear(); + list_dest_box->clear(); +} + + +void RDListSelector::addData() +{ + if(list_source_box->currentItem()>=0) { + list_dest_box-> + insertItem(list_source_box->currentText()); + list_source_box->removeItem(list_source_box->currentItem()); + list_dest_box->sort(); + if(list_source_box->count()==0) { + list_add_button->setDisabled(true); + } + list_remove_button->setEnabled(true); + list_source_box->setCurrentItem(-1); + } +} + + +void RDListSelector::removeData() +{ + if(list_dest_box->currentItem()>=0) { + list_source_box-> + insertItem(list_dest_box->currentText()); + list_dest_box->removeItem(list_dest_box->currentItem()); + list_source_box->sort(); + if(list_dest_box->count()==0) { + list_remove_button->setDisabled(true); + } + list_add_button->setEnabled(true); + list_dest_box->setCurrentItem(-1); + } +} + + +void RDListSelector::CheckButtons() +{ + if(list_source_box->count()==0) { + list_add_button->setDisabled(true); + } + else { + list_add_button->setEnabled(true); + } + if(list_dest_box->count()==0) { + list_remove_button->setDisabled(true); + } + else { + list_remove_button->setEnabled(true); + } +} diff --git a/lib/rdlistselector.h b/lib/rdlistselector.h new file mode 100644 index 00000000..461d9345 --- /dev/null +++ b/lib/rdlistselector.h @@ -0,0 +1,82 @@ +// rdlistselector.h +// +// An listselector widget with word wrap. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlistselector.h,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDLISTSELECTOR_H +#define RDLISTSELECTOR_H + +#include <qwidget.h> +#include <qlabel.h> +#include <qhbox.h> +#include <qcolor.h> +#include <qlistbox.h> +#include <qpushbutton.h> + + +class RDListSelector : public QHBox +{ + Q_OBJECT + + public: + RDListSelector(QWidget *parent=0,const char *name=0); + uint sourceCount() const; + uint destCount() const; + void sourceSetLabel(QString label); + void destSetLabel(QString label); + void sourceInsertItem(const QString &text,int index=-1); + void destInsertItem(const QString &text,int index=-1); + void sourceRemoveItem(int index); + void destRemoveItem(int index); + QString sourceText(int index) const; + QString destText(int index) const; + void sourceChangeItem(const QString &text,int index); + void destChangeItem(const QString &text,int index); + int sourceNumItemsVisible() const; + int destNumItemsVisible() const; + int sourceCurrentItem() const; + int destCurrentItem() const; + QString sourceCurrentText() const; + QString destCurrentText() const; + void sourceSetCurrentItem(int item); + void destSetCurrentItem(int item); + QListBoxItem *sourceFindItem(const QString &text, + ComparisonFlags compare=ExactMatch) const; + QListBoxItem *destFindItem(const QString &text, + ComparisonFlags compare=ExactMatch) const; + void clear(); + + private slots: + void addData(); + void removeData(); + + private: + void CheckButtons(); + QListBox *list_source_box; + QLabel *list_source_label; + QListBox *list_dest_box; + QLabel *list_dest_label; + QPushButton *list_add_button; + QPushButton *list_remove_button; +}; + + +#endif // RDLISTSELECTOR_H diff --git a/lib/rdlistsvcs.cpp b/lib/rdlistsvcs.cpp new file mode 100644 index 00000000..706a4a72 --- /dev/null +++ b/lib/rdlistsvcs.cpp @@ -0,0 +1,142 @@ +// rdlistsvcs.cpp +// +// Service Picker dialog +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlistsvcs.cpp,v 1.1.2.2 2012/11/16 18:10:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qcolordialog.h> + +#include <rddb.h> +#include <rdcart.h> +#include <rdcart_dialog.h> +#include <rd.h> +#include <rdconf.h> + +#include "rdlistsvcs.h" + +RDListSvcs::RDListSvcs(const QString &caption,QWidget *parent) + : QDialog(parent) +{ + edit_caption=caption; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + setCaption(caption+" - "+tr("Rivendell Services")); + + // + // Fonts + // + QFont label_font("helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + // + // Services + // + edit_svc_list=new QListBox(this); + connect(edit_svc_list,SIGNAL(doubleClicked(QListBoxItem *)), + this,SLOT(doubleClickedData(QListBoxItem *))); + + // + // Ok Button + // + edit_ok_button=new QPushButton(this); + edit_ok_button->setDefault(true); + edit_ok_button->setFont(label_font); + edit_ok_button->setText(tr("&OK")); + connect(edit_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + edit_cancel_button=new QPushButton(this); + edit_cancel_button->setFont(label_font); + edit_cancel_button->setText(tr("&Cancel")); + connect(edit_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +RDListSvcs::~RDListSvcs() +{ +} + + +QSize RDListSvcs::sizeHint() const +{ + return QSize(300,240); +} + + +QSizePolicy RDListSvcs::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int RDListSvcs::exec(QString *svcname) +{ + QString sql; + RDSqlQuery *q; + + edit_svcname=svcname; + edit_svc_list->clear(); + sql="select NAME from SERVICES order by NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + edit_svc_list->insertItem(q->value(0).toString()); + if(q->value(0).toString()==*edit_svcname) { + edit_svc_list->setCurrentItem(edit_svc_list->count()-1); + } + } + delete q; + + return QDialog::exec(); +} + + +void RDListSvcs::doubleClickedData(QListBoxItem *item) +{ + okData(); +} + + +void RDListSvcs::okData() +{ + if(edit_svc_list->currentItem()>=0) { + *edit_svcname=edit_svc_list->currentText(); + } + done(0); +} + + +void RDListSvcs::cancelData() +{ + done(-1); +} + + +void RDListSvcs::resizeEvent(QResizeEvent *e) +{ + edit_svc_list->setGeometry(10,10,size().width()-20,size().height()-80); + edit_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + edit_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} diff --git a/lib/rdlistsvcs.h b/lib/rdlistsvcs.h new file mode 100644 index 00000000..b331c6a5 --- /dev/null +++ b/lib/rdlistsvcs.h @@ -0,0 +1,59 @@ +// rdlistsvcs.h +// +// Service Picker dialog +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlistsvcs.h,v 1.1.2.2 2012/11/16 18:10:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDLISTSVCS_H +#define RDLISTSVCS_H + +#include <qdialog.h> +#include <qlistbox.h> +#include <qpushbutton.h> + +class RDListSvcs : public QDialog +{ + Q_OBJECT + public: + RDListSvcs(const QString &caption,QWidget *parent=0); + ~RDListSvcs(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(QString *svcname); + + private slots: + void doubleClickedData(QListBoxItem *item); + void okData(); + void cancelData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + QListBox *edit_svc_list; + QString *edit_svcname; + QPushButton *edit_ok_button; + QPushButton *edit_cancel_button; + QString edit_caption; +}; + + +#endif // RDLISTSVCS_H diff --git a/lib/rdlistview.cpp b/lib/rdlistview.cpp new file mode 100644 index 00000000..69a08380 --- /dev/null +++ b/lib/rdlistview.cpp @@ -0,0 +1,126 @@ +// rdlistview.cpp +// +// A contiguous-selection only QListView widget for Rivendell +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlistview.cpp,v 1.12 2011/09/06 17:35:07 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <vector> + +#include <rdlistview.h> +#include <rdlistviewitem.h> + + +RDListView::RDListView(QWidget *parent,const char *name) + : QListView(parent,name) +{ + list_hard_sort_column=-1; + connect(this, + SIGNAL(mouseButtonClicked(int,QListViewItem *,const QPoint &,int)), + this, + SLOT(mouseButtonClickedData(int,QListViewItem *,const QPoint &,int))); +} + + +int RDListView::hardSortColumn() const +{ + return list_hard_sort_column; +} + + +void RDListView::setHardSortColumn(int col) +{ + list_hard_sort_column=col; +} + + +RDListView::SortType RDListView::columnSortType(int column) const +{ + return sort_type[column]; +} + + +void RDListView::setColumnSortType(int column,SortType type) +{ + sort_type[column]=type; +} + + +int RDListView::addColumn(const QString &label,int width) +{ + sort_type.push_back(RDListView::NormalSort); + return QListView::addColumn(label,width); +} + + +int RDListView::addColumn(const QIconSet &iconset,const QString &label, + int width) +{ + sort_type.push_back(RDListView::NormalSort); + return QListView::addColumn(iconset,label,width); +} + + +void RDListView::selectLine(int line) +{ + RDListViewItem *item=(RDListViewItem *)firstChild(); + while(item!=NULL) { + if(item->line()==line) { + setSelected(item,true); + return; + } + item=(RDListViewItem *)item->nextSibling(); + } +} + + +void RDListView::mouseButtonClickedData(int button,QListViewItem *item, + const QPoint &pt,int col) +{ + QListViewItem *l; + bool contiguous; + + if((selectionMode()!=QListView::Extended)||(item==NULL)||(button!=1)) { + return; + } + + // + // Get Selected Range + // + l=item; + contiguous=true; + while((l=l->itemAbove())!=NULL) { + if(!l->isSelected()) { + contiguous=false; + } + if(!contiguous) { + setSelected(l,false); + } + } + l=item; + contiguous=true; + while((l=l->itemBelow())!=NULL) { + if(!l->isSelected()) { + contiguous=false; + } + if(!contiguous) { + setSelected(l,false); + } + } +} diff --git a/lib/rdlistview.h b/lib/rdlistview.h new file mode 100644 index 00000000..5c0e1b95 --- /dev/null +++ b/lib/rdlistview.h @@ -0,0 +1,58 @@ +// rdlistview.h +// +// A contiguous-selection only QListView widget for Rivendell +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlistview.h,v 1.12.4.1 2013/02/21 02:46:23 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDLISTVIEW_H +#define RDLISTVIEW_H + +#include <vector> + +#include <qlistview.h> +#include <qpixmap.h> + + +class RDListView : public QListView +{ + Q_OBJECT + + public: + enum SortType {NormalSort=0,TimeSort=1,LineSort=2,GpioSort=3}; + RDListView(QWidget *parent,const char *name=0); + int hardSortColumn() const; + void setHardSortColumn(int col); + RDListView::SortType columnSortType(int column) const; + void setColumnSortType(int column,SortType type); + int addColumn(const QString &label,int width=-1); + int addColumn(const QIconSet &iconset,const QString &label,int width=-1); + void selectLine(int line); + + private slots: + void mouseButtonClickedData(int button,QListViewItem *item,const QPoint &pt, + int col); + + private: + int list_hard_sort_column; + std::vector<RDListView::SortType> sort_type; +}; + + +#endif // RDLISTVIEW_H diff --git a/lib/rdlistviewitem.cpp b/lib/rdlistviewitem.cpp new file mode 100644 index 00000000..e6614353 --- /dev/null +++ b/lib/rdlistviewitem.cpp @@ -0,0 +1,239 @@ +// rdlistviewitem.cpp +// +// A color-selectable QListViewItem class for Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlistviewitem.cpp,v 1.20.6.1 2013/02/21 02:46:23 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <qpainter.h> +#include <qstringlist.h> + +#include <rdconf.h> +#include <rdlistviewitem.h> + + +RDListViewItem::RDListViewItem(QListView *parent) + : QListViewItem(parent) +{ + item_line=-1; + item_id=-1; + list_parent=(RDListView *)parent; + item_background_color= + listView()->palette().color(QPalette::Active,QColorGroup::Base); + for(int i=0;i<parent->columns();i++) { + item_text_color. + push_back(parent->palette().color(QPalette::Active,QColorGroup::Text)); + item_text_weight.push_back(parent->font().weight()); + } +} + + +int RDListViewItem::line() const +{ + return item_line; +} + + +void RDListViewItem::setLine(int line) +{ + item_line=line; +} + + +int RDListViewItem::id() const +{ + return item_id; +} + + +void RDListViewItem::setId(int id) +{ + item_id=id; +} + + +QColor RDListViewItem::backgroundColor() const +{ + return item_background_color; +} + + +void RDListViewItem::setBackgroundColor(QColor color) +{ + item_background_color=color; + listView()->repaintItem(this); +} + + +void RDListViewItem::setTextColor(QColor color) +{ + for(unsigned i=0;i<item_text_color.size();i++) { + item_text_color[i]=color; + } + listView()->repaintItem(this); +} + + +QColor RDListViewItem::textColor(int column) const +{ + return item_text_color[column]; +} + + +void RDListViewItem::setTextColor(int column,QColor color,int weight) +{ + item_text_color[column]=color; + item_text_weight[column]=weight; + listView()->repaintItem(this); +} + + +void RDListViewItem::paintCell(QPainter *p,const QColorGroup &cg,int column, + int width,int align) +{ + QColor text_color=item_text_color[column]; + QColor back_color=item_background_color; + int x=0; + int y=0; + + if(item_text_weight[column]!=p->font().weight()) { + int pt_size=0; + if((pt_size=p->font().pointSize())<0) { + pt_size=p->font().pixelSize(); + } + QFont f(p->font().family(),pt_size,item_text_weight[column]); + f.setPixelSize(pt_size); + p->setFont(f); + } + if(isSelected()&&((column==0)||listView()->allColumnsShowFocus())) { + text_color=cg.highlightedText(); + back_color=cg.highlight(); + } + p->fillRect(0,0,width,height(),back_color); + if(pixmap(column)==NULL) { + for(int i=0;i<listView()->columns();i++) { + if(!text(i).isEmpty()) { + y=(height()+p->fontMetrics().boundingRect(text(i)).height())/2; + i=listView()->columns(); + } + } + x=listView()->itemMargin(); + if(((align&AlignHCenter)!=0)||((align&AlignCenter)!=0)) { + x=(width-p->fontMetrics().width(text(column)))/2; + } + if((align&AlignRight)!=0) { + x=width-p->fontMetrics().width(text(column))-listView()->itemMargin(); + } + p->setPen(text_color); + p->drawText(x,y,text(column)); + } + else { + x=listView()->itemMargin(); + y=(height()-pixmap(column)->height())/2; + if((align&AlignRight)!=0) { + x=width-pixmap(column)->width()-listView()->itemMargin(); + } + if(((align&AlignHCenter)!=0)||((align&AlignCenter)!=0)) { + x=(width-pixmap(column)->width())/2; + } + p->drawPixmap(x,y,*pixmap(column)); + } +} + + +int RDListViewItem::compare(QListViewItem *i,int col,bool ascending) const +{ + int hard_column; + int prev_length; + int length; + QStringList fields; + QStringList prev_fields; + + if((hard_column=list_parent->hardSortColumn())<0) { + switch(list_parent->columnSortType(col)) { + case RDListView::TimeSort: + prev_length=RDSetTimeLength(i->text(col)); + length=RDSetTimeLength(text(col)); + if(length<prev_length) { + return -1; + } + if(length>prev_length) { + return 1; + } + return 0; + + case RDListView::LineSort: + if(line()<((RDListViewItem *)i)->line()) { + return -1; + } + if(line()>((RDListViewItem *)i)->line()) { + return 1; + } + return 0; + + case RDListView::GpioSort: + fields=fields.split("-",text(col)); + prev_fields=fields.split("-",i->text(col)); + if(fields[0].toInt()>prev_fields[0].toInt()) { + return 1; + } + if(fields[0].toInt()<prev_fields[0].toInt()) { + return -1; + } + return 0; + + case RDListView::NormalSort: + return QListViewItem::compare(i,col,ascending); + } + } + if(ascending) { + int this_count=text(hard_column).toInt(); + if(this_count<0) { + return 1; + } + int that_count=i->text(hard_column).toInt(); + if(that_count<0) { + return -1; + } + if(this_count>that_count) { + return 1; + } + if(this_count<that_count) { + return -1; + } + return 0; + } + else { + int this_count=text(hard_column).toInt(); + if(this_count<0) { + return -1; + } + int that_count=i->text(hard_column).toInt(); + if(that_count<0) { + return 1; + } + if(this_count>that_count) { + return -1; + } + if(this_count<that_count) { + return 1; + } + return 0; + } +} diff --git a/lib/rdlistviewitem.h b/lib/rdlistviewitem.h new file mode 100644 index 00000000..6d377005 --- /dev/null +++ b/lib/rdlistviewitem.h @@ -0,0 +1,63 @@ +// rdlistviewitem.h +// +// A color-selectable QListViewItem class for Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlistviewitem.h,v 1.10 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDLISTVIEWITEM_H +#define RDLISTVIEWITEM_H + +#include <vector> + +#include <qlistview.h> +#include <qpixmap.h> + +#include <rdlistview.h> + +using namespace std; + +class RDListViewItem : public QListViewItem +{ + public: + RDListViewItem(QListView *parent); + int line() const; + void setLine(int line); + int id() const; + void setId(int id); + QColor backgroundColor() const; + void setBackgroundColor(QColor color); + QColor textColor(int column) const; + void setTextColor(QColor color); + void setTextColor(int column,QColor color,int weight); + void paintCell(QPainter *p,const QColorGroup &cg,int column, + int width,int align); + int compare(QListViewItem *i,int col,bool ascending) const; + + private: + int item_line; + int item_id; + vector<QColor> item_text_color; + vector<int> item_text_weight; + QColor item_background_color; + RDListView *list_parent; +}; + + +#endif // RDLISTVIEWITEM_H diff --git a/lib/rdlivewire.cpp b/lib/rdlivewire.cpp new file mode 100644 index 00000000..cb1a52fc --- /dev/null +++ b/lib/rdlivewire.cpp @@ -0,0 +1,836 @@ +// rdlivewire.cpp +// +// A LiveWire Node Driver for Rivendell +// +// (C) Copyright 2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlivewire.cpp,v 1.7.8.2 2013/11/17 02:03:19 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <syslog.h> + +#include <qsignalmapper.h> + +#include <rd.h> +#include <rdlivewire.h> + + +RDLiveWire::RDLiveWire(unsigned id,QObject *parent,const char *name) + : QObject(parent,name) +{ + live_id=id; + live_sources=0; + live_destinations=0; + live_channels=RD_LIVEWIRE_DEFAULT_CHANNELS; + live_gpis=0; + live_gpos=0; + live_tcp_port=0; + live_base_output=0; + live_ptr=0; + live_connected=false; + + // + // Connection Socket + // + live_socket=new QSocket(this,"live_socket"); + connect(live_socket,SIGNAL(connected()),this,SLOT(connectedData())); + connect(live_socket,SIGNAL(connectionClosed()), + this,SLOT(connectionClosedData())); + connect(live_socket,SIGNAL(readyRead()),this,SLOT(readyReadData())); + connect(live_socket,SIGNAL(error(int)),this,SLOT(errorData(int))); + + // + // Watchdog Timers + // + live_watchdog_timer=new QTimer(this,",live_watchdog_timer"); + connect(live_watchdog_timer,SIGNAL(timeout()),this,SLOT(watchdogData())); + + live_watchdog_timeout_timer=new QTimer(this,",live_watchdog_timeout_timer"); + connect(live_watchdog_timeout_timer,SIGNAL(timeout()), + this,SLOT(watchdogTimeoutData())); + + live_holdoff_timer=new QTimer(this,",live_holdoff_timer"); + connect(live_holdoff_timer,SIGNAL(timeout()),this,SLOT(holdoffData())); +} + + +unsigned RDLiveWire::id() const +{ + return live_id; +} + + +QString RDLiveWire::hostname() const +{ + return live_hostname; +} + + +Q_UINT16 RDLiveWire::tcpPort() const +{ + return live_tcp_port; +} + + +unsigned RDLiveWire::baseOutput() +{ + return live_base_output; +} + + +void RDLiveWire::connectToHost(const QString &hostname,Q_UINT16 port, + const QString &passwd,unsigned base_output) +{ + live_hostname=hostname; + live_tcp_port=port; + live_password=passwd; + live_base_output=base_output; + live_socket->connectToHost(hostname,port); +} + + +QString RDLiveWire::deviceName() const +{ + return live_device_name; +} + + +QString RDLiveWire::protocolVersion() const +{ + return live_protocol_version; +} + + +QString RDLiveWire::systemVersion() const +{ + return live_system_version; +} + + +int RDLiveWire::sources() const +{ + return live_sources; +} + + +int RDLiveWire::destinations() const +{ + return live_destinations; +} + + +int RDLiveWire::channels() const +{ + return live_channels; +} + + +int RDLiveWire::gpis() const +{ + return live_gpis; +} + + +int RDLiveWire::gpos() const +{ + return live_gpos; +} + + +unsigned RDLiveWire::gpiChannel(int slot,int line) const +{ + return live_gpi_channels[slot][line]; +} + + +unsigned RDLiveWire::gpoChannel(int slot,int line) const +{ + return live_gpo_channels[slot][line]; +} + + +bool RDLiveWire::gpiState(int slot,int line) const +{ + return live_gpi_states[slot][line]; +} + + +bool RDLiveWire::gpoState(int slot,int line) const +{ + return live_gpo_states[slot][line]; +} + + +void RDLiveWire::gpiSet(int slot,int line,unsigned interval) +{ + QString cmd=QString().sprintf("GPI %d ",slot+1); + for(int i=0;i<RD_LIVEWIRE_GPIO_BUNDLE_SIZE;i++) { + if(i==line) { + cmd+="l"; + } + else { + if(live_gpi_states[slot][i]) { + cmd+="l"; + } + else { + cmd+="h"; + } + } + } + cmd+="\"\r\n"; + live_socket->writeBlock(cmd,cmd.length()); + live_gpi_states[slot][line]=true; + if(interval>0) { + live_gpi_timers[slot*RD_LIVEWIRE_GPIO_BUNDLE_SIZE+line]-> + start(interval,true); + } + emit gpiChanged(live_id,slot,line,true); +} + + +void RDLiveWire::gpiReset(int slot,int line,unsigned interval) +{ + QString cmd=QString().sprintf("GPI %d ",slot+1); + for(int i=0;i<RD_LIVEWIRE_GPIO_BUNDLE_SIZE;i++) { + if(i==line) { + cmd+="h"; + } + else { + if(live_gpi_states[slot][i]) { + cmd+="l"; + } + else { + cmd+="h"; + } + } + } + cmd+="\"\r\n"; + live_socket->writeBlock(cmd,cmd.length()); + live_gpi_states[slot][line]=false; + if(interval>0) { + live_gpi_timers[slot*RD_LIVEWIRE_GPIO_BUNDLE_SIZE+line]-> + start(interval,true); + } + emit gpiChanged(live_id,slot,line,false); +} + + +void RDLiveWire::gpoSet(int slot,int line,unsigned interval) +{ + QString cmd=QString().sprintf("GPO %d ",slot+1); + for(int i=0;i<RD_LIVEWIRE_GPIO_BUNDLE_SIZE;i++) { + if(i==line) { + cmd+="l"; + } + else { + if(live_gpo_states[slot][i]) { + cmd+="l"; + } + else { + cmd+="h"; + } + } + } + cmd+="\r\n"; + live_socket->writeBlock(cmd,cmd.length()); + live_gpo_states[slot][line]=true; + if(interval>0) { + live_gpo_timers[slot*RD_LIVEWIRE_GPIO_BUNDLE_SIZE+line]-> + start(interval,true); + } + emit gpoChanged(live_id,slot,line,true); +} + + +void RDLiveWire::gpoReset(int slot,int line,unsigned interval) +{ + QString cmd=QString().sprintf("GPO %d ",slot+1); + for(int i=0;i<RD_LIVEWIRE_GPIO_BUNDLE_SIZE;i++) { + if(i==line) { + cmd+="h"; + } + else { + if(live_gpo_states[slot][i]) { + cmd+="l"; + } + else { + cmd+="h"; + } + } + } + cmd+="\r\n"; + live_socket->writeBlock(cmd,cmd.length()); + live_gpo_states[slot][line]=false; + if(interval>0) { + live_gpo_timers[slot*RD_LIVEWIRE_GPIO_BUNDLE_SIZE+line]-> + start(interval,true); + } + emit gpoChanged(live_id,slot,line,false); +} + + +void RDLiveWire::setRoute(int src_num,int dest_slot) const +{ + QString str; + str=QString().sprintf("DST %d ADDR:\"239.192.%d.%d\"\r\n", + dest_slot+1,src_num/256,src_num%256); + live_socket->writeBlock(str,str.length()); +} + + +void RDLiveWire::connectedData() +{ + QString str="LOGIN"; + if(!live_password.isEmpty()) { + str+=(" "+live_password); + } + str+="\r\n"; + live_socket->writeBlock(str,str.length()); + live_socket->writeBlock("VER\r\n",5); +} + + +void RDLiveWire::connectionClosedData() +{ + if(!live_watchdog_state) { + live_watchdog_state=true; + int holdoff=GetHoldoff(); + emit watchdogStateChanged(live_id,QString().sprintf( + "Connection to LiveWire node at %s:%d closed, attempting reconnect, holdoff = %d mS", + (const char *)live_hostname,live_tcp_port,holdoff)); + live_holdoff_timer->start(holdoff,true); + } +} + + +void RDLiveWire::readyReadData() +{ + char buf[RD_LIVEWIRE_MAX_CMD_LENGTH]; + + int n=live_socket->readBlock(buf,RD_LIVEWIRE_MAX_CMD_LENGTH); + buf[n]=0; + for(int i=0;i<n;i++) { + if(buf[i]=='\n') { + live_buf[live_ptr]=0; + DespatchCommand(live_buf); + live_ptr=0; + } + else { + if(buf[i]!='\r') { + live_buf[live_ptr++]=buf[i]; + } + } + if(live_ptr>=RD_LIVEWIRE_MAX_CMD_LENGTH) { + fprintf(stderr,"LiveWire: status string truncated"); + live_ptr=0; + } + } +} + + +void RDLiveWire::errorData(int err) +{ + int interval=RDLIVEWIRE_RECONNECT_MIN_INTERVAL; + + switch((QSocket::Error)err) { + case QSocket::ErrConnectionRefused: + live_watchdog_state=true; + interval=GetHoldoff(); + emit watchdogStateChanged(live_id,QString().sprintf( + "Connection to LiveWire node at %s:%d refused, attempting reconnect, holdoff = %d mS", + (const char *)live_hostname, + live_tcp_port,interval)); + live_holdoff_timer->start(interval,true); + break; + + case QSocket::ErrHostNotFound: + emit watchdogStateChanged(live_id,QString().sprintf( + "Error on connection to LiveWire node at %s:%d: Host Not Found", + (const char *)live_hostname, + live_tcp_port)); + break; + + case QSocket::ErrSocketRead: + emit watchdogStateChanged(live_id,QString().sprintf( + "Error on connection to LiveWire node at %s:%d: Socket Read Error", + (const char *)live_hostname, + live_tcp_port)); + break; + } +} + + +void RDLiveWire::gpiTimeoutData(int id) +{ + int chan=id/RD_LIVEWIRE_GPIO_BUNDLE_SIZE; + int line=id%RD_LIVEWIRE_GPIO_BUNDLE_SIZE; + + QString cmd=QString().sprintf("GPI %d ",chan+1); + for(int i=0;i<RD_LIVEWIRE_GPIO_BUNDLE_SIZE;i++) { + if(i==line) { + if(live_gpi_states[chan][i]) { + cmd+="h"; + } + else { + cmd+="l"; + } + } + else { + if(live_gpi_states[chan][i]) { + cmd+="l"; + } + else { + cmd+="h"; + } + } + } + cmd+="\"\r\n"; + live_socket->writeBlock(cmd,cmd.length()); + live_gpi_states[chan][line]=!live_gpi_states[chan][line]; + emit gpiChanged(live_id,chan,line,live_gpi_states[chan][line]); +} + + +void RDLiveWire::gpoTimeoutData(int id) +{ + int chan=id/RD_LIVEWIRE_GPIO_BUNDLE_SIZE; + int line=id%RD_LIVEWIRE_GPIO_BUNDLE_SIZE; + + QString cmd=QString().sprintf("GPO %d ",chan+1); + for(int i=0;i<RD_LIVEWIRE_GPIO_BUNDLE_SIZE;i++) { + if(i==line) { + if(live_gpo_states[chan][i]) { + cmd+="h"; + } + else { + cmd+="l"; + } + } + else { + if(live_gpo_states[chan][i]) { + cmd+="l"; + } + else { + cmd+="h"; + } + } + } + cmd+="\r\n"; + live_socket->writeBlock(cmd,cmd.length()); + live_gpo_states[chan][line]=!live_gpo_states[chan][line]; + emit gpoChanged(live_id,chan,line,live_gpo_states[chan][line]); +} + + +void RDLiveWire::watchdogData() +{ + live_socket->writeBlock("VER\r\n",4); +} + + +void RDLiveWire::watchdogTimeoutData() +{ + live_watchdog_state=true; + int holdoff=GetHoldoff(); + emit watchdogStateChanged(live_id,QString().sprintf( + "Connection to LiveWire node at %s:%d lost, attempting reconnect, holdoff = %d mS", + (const char *)live_hostname,live_tcp_port,holdoff)); + live_holdoff_timer->start(holdoff,true); +} + + +void RDLiveWire::holdoffData() +{ + ResetConnection(); +} + + +void RDLiveWire::resetConnectionData() +{ + live_socket->close(); + connectToHost(live_hostname,live_tcp_port,live_password,live_base_output); +} + + +void RDLiveWire::DespatchCommand(const QString &cmd) +{ + int offset=cmd.find(" "); + QString opcode=cmd.left(offset); + QString str; + if(opcode=="VER") { + ReadVersion(cmd.right(cmd.length()-offset-1)); + } + + if(opcode=="SET") { + } + + if(opcode=="SRC") { + ReadSources(cmd.right(cmd.length()-offset-1)); + } + + if(opcode=="DST") { + ReadDestinations(cmd.right(cmd.length()-offset-1)); + } + + if(opcode=="GPO") { + ReadGpos(cmd.right(cmd.length()-offset-1)); + } + + if(opcode=="GPI") { + ReadGpis(cmd.right(cmd.length()-offset-1)); + } + + if(opcode=="CFG") { + str=cmd.right(cmd.length()-offset-1); + offset=str.find(" "); + if(str.left(offset)=="GPO") { + ReadGpioConfig(str.right(str.length()-offset-1)); + } + } +} + + +void RDLiveWire::ReadVersion(const QString &cmd) +{ + int ptr=0; + QString tag; + QString value; + if(!live_connected) { + while((ptr=ParseString(cmd,ptr,&tag,&value))>=0) { + if(tag=="LWRP") { + live_protocol_version=value; + } + if(tag=="DEVN") { + live_device_name=value; + } + if(tag=="SYSV") { + live_system_version=value; + } + if(tag=="NSRC") { + int delimiter=value.find("/"); + if(delimiter<0) { + live_sources=value.toInt(); + } + else { + live_sources=value.left(delimiter).toInt(); + live_channels=value.right(value.length()-delimiter-1).toInt(); + } + if(live_sources>0) { + live_socket->writeBlock("SRC\r\n",5); + } + } + if(tag=="NDST") { + int delimiter=value.find("/"); + if(delimiter<0) { + live_destinations=value.toInt(); + } + else { + live_destinations=value.left(delimiter).toInt(); + live_channels=value.right(value.length()-delimiter-1).toInt(); + } + if(live_destinations>0) { + live_socket->writeBlock("DST\r\n",5); + } + } + if(tag=="NGPI") { + live_gpis=value.toInt(); + QSignalMapper *mapper=new QSignalMapper(this,"gpi_mapper"); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(gpiTimeoutData(int))); + for(int i=0;i<live_gpis;i++) { + live_gpi_states.push_back(new bool[RD_LIVEWIRE_GPIO_BUNDLE_SIZE]); + live_gpi_channels. + push_back(new unsigned[RD_LIVEWIRE_GPIO_BUNDLE_SIZE]); + for(int j=0;j<RD_LIVEWIRE_GPIO_BUNDLE_SIZE;j++) { + live_gpi_states.back()[j]=false; + live_gpi_channels.back()[j]=i*RD_LIVEWIRE_GPIO_BUNDLE_SIZE+j; + live_gpi_timers.push_back(new QTimer(this)); + mapper->setMapping(live_gpi_timers.back(), + i*RD_LIVEWIRE_GPIO_BUNDLE_SIZE+j); + connect(live_gpi_timers.back(),SIGNAL(timeout()),mapper,SLOT(map())); + } + } + if(live_gpis>0) { + live_socket->writeBlock("ADD GPI\r\n",9); + } + } + if(tag=="NGPO") { + live_gpos=value.toInt(); + QSignalMapper *mapper=new QSignalMapper(this,"gpo_mapper"); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(gpoTimeoutData(int))); + for(int i=0;i<live_gpos;i++) { + live_gpo_states.push_back(new bool[RD_LIVEWIRE_GPIO_BUNDLE_SIZE]); + live_gpo_channels. + push_back(new unsigned[RD_LIVEWIRE_GPIO_BUNDLE_SIZE]); + for(int j=0;j<RD_LIVEWIRE_GPIO_BUNDLE_SIZE;j++) { + live_gpo_states.back()[j]=false; + live_gpo_channels.back()[j]=i*RD_LIVEWIRE_GPIO_BUNDLE_SIZE+j; + live_gpo_timers.push_back(new QTimer(this)); + mapper->setMapping(live_gpo_timers.back(), + i*RD_LIVEWIRE_GPIO_BUNDLE_SIZE+j); + connect(live_gpo_timers.back(),SIGNAL(timeout()),mapper,SLOT(map())); + } + } + if(live_gpos>0) { + live_socket->writeBlock("CFG GPO\r\n",9); + live_socket->writeBlock("ADD GPO\r\n",9); + } + } + } + live_connected=true; + emit connected(live_id); + } + if(live_watchdog_state) { + live_watchdog_state=false; + emit watchdogStateChanged(live_id,QString().sprintf( + "Connection to LiveWire node at %s:%d restored", + (const char *)live_hostname,live_tcp_port)); + } + live_watchdog_timer->start(RDLIVEWIRE_WATCHDOG_INTERVAL,true); + live_watchdog_timeout_timer->stop(); + live_watchdog_timeout_timer->start(RDLIVEWIRE_WATCHDOG_TIMEOUT,true); +} + + +void RDLiveWire::ReadSources(const QString &cmd) +{ +// printf("SOURCES: %s\n",(const char *)cmd); + int ptr=0; + QString tag; + QString value; + RDLiveWireSource *src=new RDLiveWireSource(); + QHostAddress addr; + + int offset=cmd.find(" "); + src->setSlotNumber(cmd.left(offset).toInt()); + ptr=offset+1; + while((ptr=ParseString(cmd,ptr,&tag,&value))>=0) { + if(tag=="PSNM") { + src->setPrimaryName(value); + } + if(tag=="LABL") { + src->setLabelName(value); + } + if(tag=="FASM") { + // ???? + } + if(tag=="RTPE") { + src->setRtpEnabled(value.toInt()); + } + if(tag=="RTPA") { + addr.setAddress(value); + src->setStreamAddress(addr); + } + if(tag=="INGN") { + src->setInputGain(value.toInt()); + } + if(tag=="SHAB") { + src->setShareable(value.toInt()); + } + if(tag=="NCHN") { + src->setChannels(value.toInt()); + } + if(tag=="RTPP") { + // ???? + } + } + emit sourceChanged(live_id,src); + delete src; +} + + +void RDLiveWire::ReadDestinations(const QString &cmd) +{ + int ptr=0; + QString tag; + QString value; + RDLiveWireDestination *dst=new RDLiveWireDestination(); + QHostAddress addr; + + int offset=cmd.find(" "); + dst->setSlotNumber(cmd.left(offset).toInt()); + ptr=offset+1; + while((ptr=ParseString(cmd,ptr,&tag,&value))>=0) { + if(tag=="NAME") { + dst->setPrimaryName(value); + } + if(tag=="ADDR") { + addr.setAddress(value); + dst->setStreamAddress(addr); + } + if(tag=="NCHN") { + dst->setChannels(value.toInt()); + } + if(tag=="LOAD") { + dst->setLoad((RDLiveWireDestination::Load)value.toInt()); + } + if(tag=="OUGN") { + dst->setOutputGain(value.toInt()); + } + } + emit destinationChanged(live_id,dst); + delete dst; +} + + +void RDLiveWire::ReadGpis(const QString &cmd) +{ + // + // FIXME: This is currently emitting the relative slot number, which is + // wrong. How do we get the associated source number? + // + +// printf("GPI: %s\n",(const char *)cmd); + + int offset=cmd.find(" "); + int slot=cmd.left(offset).toInt()-1; + QString str=cmd.right(cmd.length()-offset-1).lower(); + for(int i=0;i<RD_LIVEWIRE_GPIO_BUNDLE_SIZE;i++) { + if((str[i]=='h')&&live_gpi_states[slot][i]) { + live_gpi_states[slot][i]=false; + emit gpiChanged(live_id,slot,i,false); + } + if((str[i]=='l')&&(!live_gpi_states[slot][i])) { + live_gpi_states[slot][i]=true; + emit gpiChanged(live_id,slot,i,true); + } + } +} + + +void RDLiveWire::ReadGpos(const QString &cmd) +{ + // + // FIXME: This is currently emitting the relative slot number, which is + // wrong. How do we get the associated source number? + // + +// printf("GPO: %s\n",(const char *)cmd); + + int offset=cmd.find(" "); + int slot=cmd.left(offset).toInt()-1; + QString str=cmd.right(cmd.length()-offset-1).lower(); + for(int i=0;i<RD_LIVEWIRE_GPIO_BUNDLE_SIZE;i++) { + if((str.mid(i,1)=="h")&&live_gpo_states[slot][i]) { + live_gpo_states[slot][i]=false; + emit gpoChanged(live_id,slot,i,false); + } + if((str.mid(i,1)=="l")&&(!live_gpo_states[slot][i])) { + live_gpo_states[slot][i]=true; + emit gpoChanged(live_id,slot,i,true); + } + } +} + + +void RDLiveWire::ReadGpioConfig(const QString &cmd) +{ + // printf("GpioConfig: %s\n",(const char *)cmd); + int ptr=0; + QString tag; + QString value; + int offset=cmd.find(" "); + int slot=cmd.left(offset).toInt()-1; + QString str=cmd.right(cmd.length()-offset-1).lower(); + ptr=offset+1; + while((ptr=ParseString(cmd,ptr,&tag,&value))>=0) { + if(tag=="SRCA") { + int chan=PruneUrl(value).toInt(); + for(unsigned i=0;i<RD_LIVEWIRE_GPIO_BUNDLE_SIZE;i++) { + live_gpi_channels[slot][i]=chan*RD_LIVEWIRE_GPIO_BUNDLE_SIZE+i; + live_gpo_channels[slot][i]=chan*RD_LIVEWIRE_GPIO_BUNDLE_SIZE+i; + emit gpoConfigChanged(live_id,slot,live_gpo_channels[slot][i]); + } + } + } +} + + +int RDLiveWire::ParseString(const QString &str,int ptr, + QString *tag,QString *value) const +{ + int len=(int)str.length(); + bool quote_mode=false; + + if(ptr>=len) { + return -1; + } + *tag=""; + *value=""; + // + // Get Tag + // + for(int i=ptr;i<len;i++) { + if(str[i]==':') { + ptr=i+1; + i=len; + } + else { + (*tag)+=str[i]; + } + } + + // + // Get Value + // + for(int i=ptr;i<len;i++) { + if(str[i]=='\"') { + quote_mode=!quote_mode; + } + else { + if((str[i]==' ')&&(!quote_mode)) { + ptr=i+1; + return ptr; + } + else { + (*value)+=str[i]; + } + } + if(i==(len-1)) { + ptr=i+1; + return ptr; + } + } + + return ptr; +} + + +QString RDLiveWire::PruneUrl(const QString &str) +{ + QString ret=str; + int offset=str.find("<"); + if(offset>=0) { + ret=str.left(offset); + } + return ret; +} + + +void RDLiveWire::ResetConnection() +{ + live_socket->close(); + connectToHost(live_hostname,live_tcp_port,live_password,live_base_output); +} + + +int RDLiveWire::GetHoldoff() +{ + return (int)(RDLIVEWIRE_RECONNECT_MIN_INTERVAL+ + (RDLIVEWIRE_RECONNECT_MAX_INTERVAL- + RDLIVEWIRE_RECONNECT_MIN_INTERVAL)* + (double)random()/(double)RAND_MAX); +} diff --git a/lib/rdlivewire.h b/lib/rdlivewire.h new file mode 100644 index 00000000..a98a5b54 --- /dev/null +++ b/lib/rdlivewire.h @@ -0,0 +1,134 @@ +// rdlivewire.h +// +// A LiveWire Node Driver for Rivendell +// +// (C) Copyright 2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlivewire.h,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDLIVEWIRE_H +#define RDLIVEWIRE_H + +#include <vector> + +#include <qobject.h> +#include <qsocket.h> +#include <qtimer.h> + +#include <rd.h> +#include <rdlivewiresource.h> +#include <rdlivewiredestination.h> + +#define RDLIVEWIRE_WATCHDOG_INTERVAL 10000 +#define RDLIVEWIRE_WATCHDOG_TIMEOUT 30000 +#define RDLIVEWIRE_RECONNECT_MIN_INTERVAL 5000 +#define RDLIVEWIRE_RECONNECT_MAX_INTERVAL 30000 + +class RDLiveWire : public QObject +{ + Q_OBJECT + public: + RDLiveWire(unsigned id,QObject *parent=0,const char *name=0); + unsigned id() const; + QString hostname() const; + Q_UINT16 tcpPort() const; + unsigned baseOutput(); + void connectToHost(const QString &hostname,Q_UINT16 port, + const QString &passwd,unsigned base_output); + QString deviceName() const; + QString protocolVersion() const; + QString systemVersion() const; + int sources() const; + int destinations() const; + int channels() const; + int gpis() const; + int gpos() const; + unsigned gpiChannel(int slot,int line) const; + unsigned gpoChannel(int slot,int line) const; + bool gpiState(int slot,int line) const; + bool gpoState(int slot,int line) const; + void gpiSet(int slot,int line,unsigned interval=0); + void gpiReset(int slot,int line,unsigned interval=0); + void gpoSet(int slot,int line,unsigned interval=0); + void gpoReset(int slot,int line,unsigned interval=0); + void setRoute(int src_num,int dest_slot) const; + + signals: + void connected(unsigned id); + void sourceChanged(unsigned id,RDLiveWireSource *src); + void destinationChanged(unsigned id,RDLiveWireDestination *dst); + void gpoConfigChanged(unsigned id,unsigned slot,unsigned chan); + void gpiChanged(unsigned id,unsigned slot,unsigned line,bool state); + void gpoChanged(unsigned id,unsigned slot,unsigned line,bool state); + void watchdogStateChanged(unsigned id,const QString &msg); + + private slots: + void connectedData(); + void connectionClosedData(); + void readyReadData(); + void errorData(int err); + void gpiTimeoutData(int id); + void gpoTimeoutData(int id); + void watchdogData(); + void watchdogTimeoutData(); + void holdoffData(); + void resetConnectionData(); + + private: + void DespatchCommand(const QString &cmd); + void ReadVersion(const QString &cmd); + void ReadSources(const QString &cmd); + void ReadDestinations(const QString &cmd); + void ReadGpis(const QString &cmd); + void ReadGpos(const QString &cmd); + void ReadGpioConfig(const QString &cmd); + int ParseString(const QString &str,int ptr,QString *tag, + QString *value) const; + QString PruneUrl(const QString &str); + void ResetConnection(); + int GetHoldoff(); + unsigned live_id; + unsigned live_base_output; + QString live_hostname; + Q_UINT16 live_tcp_port; + QString live_password; + QString live_device_name; + QString live_protocol_version; + QString live_system_version; + int live_sources; + int live_destinations; + int live_channels; + int live_gpis; + std::vector<unsigned *> live_gpi_channels; + std::vector<unsigned *> live_gpo_channels; + std::vector<bool *> live_gpi_states; + std::vector<bool *> live_gpo_states; + std::vector<QTimer *>live_gpi_timers; + std::vector<QTimer *>live_gpo_timers; + int live_gpos; + QSocket *live_socket; + char live_buf[RD_LIVEWIRE_MAX_CMD_LENGTH]; + int live_ptr; + bool live_connected; + bool live_watchdog_state; + QTimer *live_watchdog_timer; + QTimer *live_watchdog_timeout_timer; + QTimer *live_holdoff_timer; +}; + + +#endif // RDLIVEWIRE_H diff --git a/lib/rdlivewiredestination.cpp b/lib/rdlivewiredestination.cpp new file mode 100644 index 00000000..b9b09ee8 --- /dev/null +++ b/lib/rdlivewiredestination.cpp @@ -0,0 +1,142 @@ +// rdlivewiredestination.cpp +// +// Accessor Methods for LiveWire Destination Parameters +// +// (C) Copyright 2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlivewiredestination.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rd.h> +#include <rdlivewiredestination.h> + + +RDLiveWireDestination::RDLiveWireDestination() +{ + clear(); +} + + +int RDLiveWireDestination::slotNumber() const +{ + return live_slot_number; +} + + +void RDLiveWireDestination::setSlotNumber(int chan) +{ + live_slot_number=chan; +} + + +QString RDLiveWireDestination::primaryName() const +{ + return live_primary_name; +} + + +void RDLiveWireDestination::setPrimaryName(const QString &name) +{ + live_primary_name=name; +} + + +QHostAddress RDLiveWireDestination::streamAddress() const +{ + return live_stream_address; +} + + +void RDLiveWireDestination::setStreamAddress(const QHostAddress &addr) +{ + live_stream_address=addr; +} + + +Q_UINT16 RDLiveWireDestination::streamUdpPort() const +{ + return live_stream_udp_port; +} + + +void RDLiveWireDestination::setStreamUdpPort(Q_UINT16 port) +{ + live_stream_udp_port=port; +} + + +int RDLiveWireDestination::channels() const +{ + return live_channels; +} + + +void RDLiveWireDestination::setChannels(int chans) +{ + live_channels=chans; +} + + +RDLiveWireDestination::Load RDLiveWireDestination::load() const +{ + return live_load; +} + + +void RDLiveWireDestination::setLoad(RDLiveWireDestination::Load load) +{ + live_load=load; +} + + +int RDLiveWireDestination::outputGain() const +{ + return live_output_gain; +} + + +void RDLiveWireDestination::setOutputGain(int lvl) +{ + live_output_gain=lvl; +} + + +void RDLiveWireDestination::clear() +{ + live_slot_number=-1; + live_primary_name=""; + live_stream_address=QHostAddress(); + live_stream_udp_port=RD_LIVEWIRE_DEFAULT_STREAM_PORT; + live_channels=RD_LIVEWIRE_DEFAULT_CHANNELS; + live_load=RD_LIVEWIRE_DEFAULT_LOAD; + live_output_gain=0; +}; + + +QString RDLiveWireDestination::loadString(RDLiveWireDestination::Load load) +{ + switch(load) { + case RDLiveWireDestination::LoadHighZ: + return QString("hi-Z"); + + case RDLiveWireDestination::Load600Ohm: + return QString("600 ohm"); + + case RDLiveWireDestination::LoadMinus10: + return QString("-10 dBv"); + } + return QString("Unknown"); +} diff --git a/lib/rdlivewiredestination.h b/lib/rdlivewiredestination.h new file mode 100644 index 00000000..83760134 --- /dev/null +++ b/lib/rdlivewiredestination.h @@ -0,0 +1,62 @@ +// rdlivewiredestination.h +// +// Accessor Methods for LiveWire Destination Parameters +// +// (C) Copyright 2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlivewiredestination.h,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDLIVEWIREDESTINATION_H +#define RDLIVEWIREDESTINATION_H + +#include <qhostaddress.h> + + +class RDLiveWireDestination +{ + public: + enum Load {LoadHighZ=0,Load600Ohm=600,LoadMinus10=-125}; + RDLiveWireDestination(); + int slotNumber() const; + void setSlotNumber(int chan); + QString primaryName() const; + void setPrimaryName(const QString &name); + QHostAddress streamAddress() const; + void setStreamAddress(const QHostAddress &addr); + Q_UINT16 streamUdpPort() const; + void setStreamUdpPort(Q_UINT16 port); + int channels() const; + void setChannels(int chans); + RDLiveWireDestination::Load load() const; + void setLoad(RDLiveWireDestination::Load load); + int outputGain() const; + void setOutputGain(int lvl); + void clear(); + static QString loadString(RDLiveWireDestination::Load load); + + private: + int live_slot_number; + QString live_primary_name; + QHostAddress live_stream_address; + Q_UINT16 live_stream_udp_port; + int live_channels; + RDLiveWireDestination::Load live_load; + int live_output_gain; +}; + + +#endif // RDLIVEWIREDESTINATION_H diff --git a/lib/rdlivewiresource.cpp b/lib/rdlivewiresource.cpp new file mode 100644 index 00000000..5b11ec27 --- /dev/null +++ b/lib/rdlivewiresource.cpp @@ -0,0 +1,167 @@ +// rdlivewiresource.cpp +// +// Accessor Methods for LiveWire Source Parameters +// +// (C) Copyright 2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlivewiresource.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rd.h> +#include <rdlivewiresource.h> + + +RDLiveWireSource::RDLiveWireSource() +{ + clear(); +} + + +int RDLiveWireSource::slotNumber() const +{ + return live_slot_number; +} + + +void RDLiveWireSource::setSlotNumber(int slot) +{ + live_slot_number=slot; +} + + +int RDLiveWireSource::channelNumber() const +{ + return live_channel_number; +} + + +void RDLiveWireSource::setChannelNumber(int chan) +{ + live_channel_number=chan; + live_stream_address.setAddress(0xEFC00000|chan); +} + + +QString RDLiveWireSource::primaryName() const +{ + return live_primary_name; +} + + +void RDLiveWireSource::setPrimaryName(const QString &name) +{ + live_primary_name=name; +} + + +QString RDLiveWireSource::labelName() const +{ + return live_label_name; +} + + +void RDLiveWireSource::setLabelName(const QString &name) +{ + live_label_name=name; +} + + +bool RDLiveWireSource::rtpEnabled() const +{ + return live_rtp_enabled; +} + + +void RDLiveWireSource::setRtpEnabled(bool state) +{ + live_rtp_enabled=state; +} + + +QHostAddress RDLiveWireSource::streamAddress() const +{ + return live_stream_address; +} + + +void RDLiveWireSource::setStreamAddress(const QHostAddress &addr) +{ + live_stream_address=addr; + live_channel_number=addr.toIPv4Address()&0xFFFF; +} + + +Q_UINT16 RDLiveWireSource::streamUdpPort() const +{ + return live_stream_udp_port; +} + + +void RDLiveWireSource::setStreamUdpPort(Q_UINT16 port) +{ + live_stream_udp_port=port; +} + + +bool RDLiveWireSource::shareable() const +{ + return live_shareable; +} + + +void RDLiveWireSource::setShareable(bool state) +{ + live_shareable=state; +} + + +int RDLiveWireSource::inputGain() const +{ + return live_input_gain; +} + + +void RDLiveWireSource::setInputGain(int lvl) +{ + live_input_gain=lvl; +} + + +int RDLiveWireSource::channels() const +{ + return live_channels; +} + + +void RDLiveWireSource::setChannels(int chans) +{ + live_channels=chans; +} + + +void RDLiveWireSource::clear() +{ + live_slot_number=-1; + live_channel_number=-1; + live_primary_name=""; + live_label_name=""; + live_rtp_enabled=false; + live_stream_address=QHostAddress(); + live_stream_udp_port=RD_LIVEWIRE_DEFAULT_STREAM_PORT; + live_shareable=false; + live_input_gain=0; + live_channels=RD_LIVEWIRE_DEFAULT_CHANNELS; +} diff --git a/lib/rdlivewiresource.h b/lib/rdlivewiresource.h new file mode 100644 index 00000000..dc123036 --- /dev/null +++ b/lib/rdlivewiresource.h @@ -0,0 +1,69 @@ +// rdlivewiresource.h +// +// Accessor Methods for LiveWire Source Parameters +// +// (C) Copyright 2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlivewiresource.h,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDLIVEWIRESOURCE_H +#define RDLIVEWIRESOURCE_H + +#include <qhostaddress.h> + + +class RDLiveWireSource +{ + public: + RDLiveWireSource(); + int slotNumber() const; + void setSlotNumber(int slot); + int channelNumber() const; + void setChannelNumber(int chan); + QString primaryName() const; + void setPrimaryName(const QString &name); + QString labelName() const; + void setLabelName(const QString &); + bool rtpEnabled() const; + void setRtpEnabled(bool state); + QHostAddress streamAddress() const; + void setStreamAddress(const QHostAddress &addr); + Q_UINT16 streamUdpPort() const; + void setStreamUdpPort(Q_UINT16 port); + bool shareable() const; + void setShareable(bool state); + int inputGain() const; + void setInputGain(int lvl); + int channels() const; + void setChannels(int chans); + void clear(); + + private: + int live_slot_number; + int live_channel_number; + QString live_primary_name; + QString live_label_name; + bool live_rtp_enabled; + QHostAddress live_stream_address; + Q_UINT16 live_stream_udp_port; + bool live_shareable; + int live_input_gain; + int live_channels; +}; + + +#endif // RDLIVEWIRESOURCE_H diff --git a/lib/rdlog.cpp b/lib/rdlog.cpp new file mode 100644 index 00000000..b53b0e58 --- /dev/null +++ b/lib/rdlog.cpp @@ -0,0 +1,685 @@ +// rdlog.cpp +// +// Abstract a Rivendell Log. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlog.cpp,v 1.23.4.7.2.3 2014/06/24 18:27:04 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +#include <rddb.h> +#include <rdconf.h> +#include <rdlog.h> +#include <rdlog_line.h> +#include <rdescape_string.h> +#include <rdweb.h> + +// +// Global Classes +// +RDLog::RDLog(const QString &name,bool create) +{ + RDSqlQuery *q; + QString sql; + + log_name=name; + + if(create) { + sql=QString().sprintf("select NAME from LOGS where \ +(NAME=\"%s\")",(const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + if(q->size()!=1) { + delete q; + sql=QString(). + sprintf("INSERT INTO LOGS SET NAME=\"%s\",ORIGIN_DATETIME=NOW(),\ + LINK_DATETIME=NOW(),MODIFIED_DATETIME=now()", + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + delete q; + } + else { + delete q; + } + } +} + + +QString RDLog::name() const +{ + return log_name; +} + + +bool RDLog::exists() const +{ + QString sql=QString().sprintf("select NAME from LOGS where NAME=\"%s\"", + (const char *)RDEscapeString(log_name)); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + delete q; + return true; + } + delete q; + return false; +} + + +bool RDLog::logExists() const +{ + return RDBool(GetStringValue("LOG_EXISTS")); +} + + +void RDLog::setLogExists(bool state) const +{ + SetRow("LOG_EXISTS",RDYesNo(state)); +} + + +RDLog::Type RDLog::type() const +{ + return(RDLog::Type)GetIntValue("TYPE"); +} + + +void RDLog::setType(RDLog::Type type) const +{ + SetRow("TYPE",(int)type); +} + + +QString RDLog::description() const +{ + return GetStringValue("DESCRIPTION"); +} + + +void RDLog::setDescription(const QString &desc) const +{ + SetRow("DESCRIPTION",desc); +} + + +QString RDLog::service() const +{ + return GetStringValue("SERVICE"); +} + + +void RDLog::setService(const QString &svc) const +{ + SetRow("SERVICE",svc); +} + + +QDate RDLog::startDate() const +{ + return GetDateValue("START_DATE"); +} + + +void RDLog::setStartDate(const QDate &date) const +{ + SetRow("START_DATE",date); +} + + +QDate RDLog::endDate() const +{ + return GetDateValue("END_DATE"); +} + + +void RDLog::setEndDate(const QDate &date) const +{ + SetRow("END_DATE",date); +} + + +QDate RDLog::purgeDate() const +{ + return GetDateValue("PURGE_DATE"); +} + + +void RDLog::setPurgeDate(const QDate &date) const +{ + SetRow("PURGE_DATE",date); +} + + +QString RDLog::originUser() const +{ + return GetStringValue("ORIGIN_USER"); +} + + +void RDLog::setOriginUser(const QString &user) const +{ + SetRow("ORIGIN_USER",user); +} + + +QDateTime RDLog::originDatetime() const +{ + return GetDatetimeValue("ORIGIN_DATETIME"); +} + + +void RDLog::setOriginDatetime(const QDateTime &datetime) const +{ + SetRow("ORIGIN_DATETIME",datetime); +} + + +QDateTime RDLog::linkDatetime() const +{ + return GetDatetimeValue("LINK_DATETIME"); +} + + +void RDLog::setLinkDatetime(const QDateTime &datetime) const +{ + SetRow("LINK_DATETIME",datetime); +} + + +QDateTime RDLog::modifiedDatetime() const +{ + return GetDatetimeValue("MODIFIED_DATETIME"); +} + + +void RDLog::setModifiedDatetime(const QDateTime &datetime) const +{ + SetRow("MODIFIED_DATETIME",datetime); +} + + +bool RDLog::autoRefresh() const +{ + return RDBool(GetStringValue("AUTO_REFRESH")); +} + + +void RDLog::setAutoRefresh(bool state) const +{ + SetRow("AUTO_REFRESH",RDYesNo(state)); +} + + +unsigned RDLog::scheduledTracks() const +{ + return GetUnsignedValue("SCHEDULED_TRACKS"); +} + + +void RDLog::setScheduledTracks(unsigned tracks) const +{ + SetRow("SCHEDULED_TRACKS",tracks); +} + + +unsigned RDLog::completedTracks() const +{ + return GetUnsignedValue("COMPLETED_TRACKS"); +} + + +void RDLog::setCompletedTracks(unsigned tracks) const +{ + SetRow("COMPLETED_TRACKS",tracks); +} + + +int RDLog::linkQuantity(RDLog::Source src) const +{ + switch(src) { + case RDLog::SourceMusic: + return GetIntValue("MUSIC_LINKS"); + + case RDLog::SourceTraffic: + return GetIntValue("TRAFFIC_LINKS"); + } + return 0; +} + + +void RDLog::setLinkQuantity(RDLog::Source src,int quan) const +{ + switch(src) { + case RDLog::SourceMusic: + SetRow("MUSIC_LINKS",quan); + break; + + case RDLog::SourceTraffic: + SetRow("TRAFFIC_LINKS",quan); + break; + } +} + + +void RDLog::updateLinkQuantity(RDLog::Source src) const +{ + QString sql; + RDSqlQuery *q; + switch(src) { + case RDLog::SourceMusic: + sql=QString("select ID from `")+RDLog::tableName(log_name)+ + "` where "+QString().sprintf("TYPE=%d",RDLogLine::MusicLink); + q=new RDSqlQuery(sql); + sql=QString("update LOGS set ")+ + QString().sprintf("MUSIC_LINKS=%d ",q->size())+ + "where NAME=\""+RDEscapeString(log_name)+"\""; + break; + + case RDLog::SourceTraffic: + sql=QString("select ID from `")+RDLog::tableName(log_name)+ + "` where "+QString().sprintf("TYPE=%d",RDLogLine::TrafficLink); + q=new RDSqlQuery(sql); + + sql=QString("update LOGS set ")+ + QString().sprintf("TRAFFIC_LINKS=%d ",q->size())+ + "where NAME=\""+RDEscapeString(log_name)+"\""; + break; + + default: + return; + } + delete q; + q=new RDSqlQuery(sql); + delete q; +} + + +RDLog::LinkState RDLog::linkState(RDLog::Source src) const +{ + if(linkQuantity(src)==0) { + return RDLog::LinkNotPresent; + } + switch(src) { + case RDLog::SourceMusic: + return (RDLog::LinkState)RDBool(GetStringValue("MUSIC_LINKED")); + + case RDLog::SourceTraffic: + return (RDLog::LinkState)RDBool(GetStringValue("TRAFFIC_LINKED")); + } + return RDLog::LinkNotPresent; +} + + +void RDLog::setLinkState(RDLog::Source src,bool state) const +{ + switch(src) { + case RDLog::SourceMusic: + SetRow("MUSIC_LINKED",RDYesNo(state)); + break; + + case RDLog::SourceTraffic: + SetRow("TRAFFIC_LINKED",RDYesNo(state)); + break; + } +} + + +int RDLog::nextId() const +{ + return GetIntValue("NEXT_ID"); +} + + +void RDLog::setNextId(int id) const +{ + SetRow("NEXT_ID",id); +} + + +bool RDLog::isReady() const +{ + QString sql; + RDSqlQuery *q; + bool ret=false; + + sql=QString().sprintf("select MUSIC_LINKS,MUSIC_LINKED,TRAFFIC_LINKS,\ + TRAFFIC_LINKED,SCHEDULED_TRACKS,COMPLETED_TRACKS \ + from LOGS where NAME=\"%s\"", + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + if(q->first()) { + ret=((q->value(0).toInt()==0)||(q->value(1).toString()=="Y"))&& + ((q->value(2).toInt()==0)||(q->value(3).toString()=="Y"))&& + ((q->value(4).toInt()==0)||(q->value(4).toInt()==q->value(5).toInt())); + } + delete q; + return ret; +} + + +bool RDLog::remove(RDStation *station,RDUser *user,RDConfig *config) const +{ + QString sql; + RDSqlQuery *q; + QString name=log_name; + + name.replace(" ","_"); + if(removeTracks(station,user,config)<0) { + return false; + } + sql=QString().sprintf("drop table `%s_LOG`",(const char *)name); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from LOGS where (NAME=\"%s\" && TYPE=0)", + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + delete q; + return true; +} + + +void RDLog::updateTracks() +{ + QString sql; + RDSqlQuery *q; + unsigned scheduled=0; + unsigned completed=0; + + sql=QString().sprintf("select NUMBER from CART where OWNER=\"%s\"", + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + completed=q->size(); + delete q; + + sql=QString("select ID from `")+RDLog::tableName(log_name)+ + "` where "+QString().sprintf("TYPE=%d",RDLogLine::Track); + q=new RDSqlQuery(sql); + scheduled=q->size()+completed; + delete q; + + sql=QString().sprintf("update LOGS set SCHEDULED_TRACKS=%d,\ + COMPLETED_TRACKS=%u where NAME=\"%s\"", + scheduled,completed, + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +int RDLog::removeTracks(RDStation *station,RDUser *user,RDConfig *config) const +{ + QString sql; + RDSqlQuery *q; + int count=0; + RDCart *cart; + + QString owner=log_name; + owner.replace(" ","_"); + sql=QString().sprintf("select NUMBER from CART where OWNER=\"%s\"", + (const char *)owner); + q=new RDSqlQuery(sql); + while(q->next()) { + cart=new RDCart(q->value(0).toUInt()); + if(!cart->remove(station,user,config)) { + delete cart; + return -1; + } + delete cart; + count++; + } + delete q; + + return count; +} + + +RDLogEvent *RDLog::createLogEvent() const +{ + QString logname=name()+"_LOG"; + logname.replace(" ","_"); + return new RDLogEvent(logname); +} + + + +QString RDLog::xml() const +{ + QString sql; + RDSqlQuery *q; + QString ret; +#ifndef WIN32 + sql=QString("select NAME,SERVICE,DESCRIPTION,ORIGIN_USER,")+ + "ORIGIN_DATETIME,LINK_DATETIME,MODIFIED_DATETIME,"+ + "AUTO_REFRESH,START_DATE,END_DATE,SCHEDULED_TRACKS,COMPLETED_TRACKS,"+ + "MUSIC_LINKS,MUSIC_LINKED,TRAFFIC_LINKS,TRAFFIC_LINKED,NEXT_ID "+ + "from LOGS where NAME=\""+RDEscapeString(log_name)+"\""; + + q=new RDSqlQuery(sql); + if(q->first()) { + ret+=" <log>\n"; + ret+=" "+RDXmlField("name",log_name); + ret+=" "+RDXmlField("serviceName",q->value(1).toString()); + ret+=" "+RDXmlField("description",q->value(2).toString()); + ret+=" "+RDXmlField("originUserName",q->value(3).toString()); + ret+=" "+RDXmlField("originDatetime",q->value(4).toDateTime()); + ret+=" "+RDXmlField("linkDatetime",q->value(5).toDateTime()); + ret+=" "+RDXmlField("modifiedDatetime",q->value(6).toDateTime()); + ret+=" "+RDXmlField("autoRefresh",RDBool(q->value(7).toString())); + ret+=" "+RDXmlField("startDate",q->value(8).toDate()); + ret+=" "+RDXmlField("endDate",q->value(9).toDate()); + ret+=" "+RDXmlField("scheduledTracks",q->value(10).toInt()); + ret+=" "+RDXmlField("completedTracks",q->value(11).toInt()); + ret+=" "+RDXmlField("musicLinks",q->value(12).toInt()); + ret+=" "+RDXmlField("musicLinked",RDBool(q->value(13).toString())); + ret+=" "+RDXmlField("trafficLinks",q->value(14).toInt()); + ret+=" "+RDXmlField("trafficLinked",RDBool(q->value(15).toString())); + ret+=" </log>\n"; + } + delete q; +#endif // WIN32 + return ret; +} + + +bool RDLog::exists(const QString &name) +{ + QString sql; + RDSqlQuery *q; + bool ret=false; + + sql=QString("select NAME from LOGS where NAME=\"")+ + RDEscapeString(name)+"\""; + q=new RDSqlQuery(sql); + ret=q->first(); + delete q; + + return ret; +} + + +QString RDLog::tableName(const QString &log_name) +{ + QString ret=log_name; + ret.replace(" ","_"); + return ret+"_LOG"; +} + + +int RDLog::GetIntValue(const QString &field) const +{ + QString sql; + RDSqlQuery *q; + int accum; + + sql=QString().sprintf("select %s from LOGS where NAME=\"%s\"", + (const char *)field, + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toInt(); + delete q; + return accum; + } + delete q; + return 0; +} + + +unsigned RDLog::GetUnsignedValue(const QString &field) const +{ + QString sql; + RDSqlQuery *q; + unsigned accum; + + sql=QString().sprintf("select %s from LOGS where NAME=\"%s\"", + (const char *)field, + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toUInt(); + delete q; + return accum; + } + delete q; + return 0; +} + + +QString RDLog::GetStringValue(const QString &field) const +{ + QString sql; + RDSqlQuery *q; + QString accum; + + sql=QString().sprintf("select %s from LOGS where NAME=\"%s\"", + (const char *)field, + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toString(); + delete q; + return accum; + } + delete q; + return 0; +} + + +QDate RDLog::GetDateValue(const QString &field) const +{ + QString sql; + RDSqlQuery *q; + QDate accum; + + sql=QString().sprintf("select %s from LOGS where NAME=\"%s\"", + (const char *)field, + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toDate(); + delete q; + return accum; + } + delete q; + return QDate(); +} + + +QDateTime RDLog::GetDatetimeValue(const QString &field) const +{ + QString sql; + RDSqlQuery *q; + QDateTime accum; + + sql=QString().sprintf("select %s from LOGS where NAME=\"%s\"", + (const char *)field, + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toDateTime(); + delete q; + return accum; + } + delete q; + return QDateTime(); +} + + +void RDLog::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE LOGS SET %s=%d WHERE NAME=\"%s\"", + (const char *)param, + value, + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDLog::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE LOGS SET %s=%u WHERE NAME=\"%s\"", + (const char *)param, + value, + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDLog::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE LOGS SET %s=\"%s\" WHERE NAME=\"%s\"", + (const char *)param, + (const char *)RDEscapeString(value), + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDLog::SetRow(const QString ¶m,const QDate &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE LOGS SET %s=\"%s\" WHERE NAME=\"%s\"", + (const char *)param, + (const char *)value.toString("yyyy/MM/dd"), + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDLog::SetRow(const QString ¶m,const QDateTime &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE LOGS SET %s=\"%s\" WHERE NAME=\"%s\"", + (const char *)param, + (const char *)value.toString("yyyy-MM-dd hh:mm:ss"), + (const char *)RDEscapeString(log_name)); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdlog.h b/lib/rdlog.h new file mode 100644 index 00000000..55df9cda --- /dev/null +++ b/lib/rdlog.h @@ -0,0 +1,101 @@ +// rdlog.h +// +// Abstract a Rivendell Log +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlog.h,v 1.16.6.5.2.1 2014/05/20 14:01:49 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> + +#include <rdconfig.h> +#include <rdlog_event.h> +#include <rduser.h> +#include <rdstation.h> + +#ifndef RDLOG_H +#define RDLOG_H + +class RDLog +{ + public: + enum Type {Log=0,Event=1,Clock=2,Grid=3}; + enum Source {SourceTraffic=0,SourceMusic=1}; + enum LinkState {LinkMissing=0,LinkDone=1,LinkNotPresent=2}; + RDLog(const QString &name,bool create=false); + QString name() const; + bool exists() const; + bool logExists() const; + void setLogExists(bool state) const; + RDLog::Type type() const; + void setType(RDLog::Type type) const; + QString description() const; + void setDescription(const QString &desc) const; + QString service() const; + void setService(const QString &svc) const; + QDate startDate() const; + void setStartDate(const QDate &date) const; + QDate endDate() const; + void setEndDate(const QDate &date) const; + QDate purgeDate() const; + void setPurgeDate(const QDate &date) const; + QString originUser() const; + void setOriginUser(const QString &user) const; + QDateTime originDatetime() const; + void setOriginDatetime(const QDateTime &datetime) const; + QDateTime linkDatetime() const; + void setLinkDatetime(const QDateTime &datetime) const; + QDateTime modifiedDatetime() const; + void setModifiedDatetime(const QDateTime &datetime) const; + bool autoRefresh() const; + void setAutoRefresh(bool state) const; + unsigned scheduledTracks() const; + void setScheduledTracks(unsigned tracks) const; + unsigned completedTracks() const; + void setCompletedTracks(unsigned tracks) const; + int linkQuantity(RDLog::Source src) const; + void setLinkQuantity(RDLog::Source src,int quan) const; + void updateLinkQuantity(RDLog::Source src) const; + RDLog::LinkState linkState(RDLog::Source src) const; + void setLinkState(RDLog::Source src,bool state) const; + int nextId() const; + void setNextId(int id) const; + bool isReady() const; + bool remove(RDStation *station,RDUser *user,RDConfig *config) const; + void updateTracks(); + int removeTracks(RDStation *station,RDUser *user,RDConfig *config) const; + RDLogEvent *createLogEvent() const; + QString xml() const; + static bool exists(const QString &name); + static QString tableName(const QString &log_name); + + private: + int GetIntValue(const QString &field) const; + unsigned GetUnsignedValue(const QString &field) const; + QString GetStringValue(const QString &field) const; + QDate GetDateValue(const QString &field) const; + QDateTime GetDatetimeValue(const QString &field) const; + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,unsigned value) const; + void SetRow(const QString ¶m,const QString &value) const; + void SetRow(const QString ¶m,const QDate &value) const; + void SetRow(const QString ¶m,const QDateTime &value) const; + QString log_name; +}; + + +#endif diff --git a/lib/rdlog_event.cpp b/lib/rdlog_event.cpp new file mode 100644 index 00000000..d02b6cd0 --- /dev/null +++ b/lib/rdlog_event.cpp @@ -0,0 +1,1245 @@ +// rdlog_event.cpp +// +// Abstract Rivendell Log Events. +// +// (C) Copyright 2002-2014 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlog_event.cpp,v 1.101.4.13.2.2 2014/05/22 19:37:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <map> +#include <rddb.h> +#include <rdconf.h> +#include <rdlog.h> +#include <rdlog_event.h> +#include <rdcreate_log.h> +#include <rddebug.h> +#include <rd.h> +#include <rdescape_string.h> + +// +// Global Classes +// +RDLogEvent::RDLogEvent(QString name) +{ + log_name=name; + log_max_id=0; +} + + +RDLogEvent::~RDLogEvent() +{ + for(unsigned i=0;i<log_line.size();i++) { + delete log_line[i]; + } +} + + +bool RDLogEvent::exists() +{ + if(log_name.isEmpty()) { + return false; + } + QString sql="show tables"; + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + if(q->value(0).toString()==log_name) { + delete q; + return true; + } + } + delete q; + + return false; +} + + +bool RDLogEvent::exists(int line) +{ + if((int)log_line.size()>line) { + return true; + } + return false; +} + + +bool RDLogEvent::exists(const QTime &hard_time,int except_line) +{ + for(int i=0;i<size();i++) { + if((logLine(i)->timeType()==RDLogLine::Hard)&& + (logLine(i)->startTime(RDLogLine::Logged)==hard_time)&& + (i!=except_line)) { + return true; + } + } + return false; +} + + +QString RDLogEvent::logName() const +{ + return log_name; +} + + +void RDLogEvent::setLogName(QString logname) +{ + log_name=logname; +} + + +QString RDLogEvent::serviceName() const +{ + return log_service_name; +} + + +int RDLogEvent::load(bool track_ptrs) +{ + RDLogLine line; + QString sql; + RDSqlQuery *q; + + // + // Get the service name + // + sql=QString().sprintf("select SERVICE from LOGS where NAME=\"%s\"", + (const char *)RDEscapeString(log_name.left(log_name.length()-4))); + q=new RDSqlQuery(sql); + if(q->next()) { + log_service_name=q->value(0).toString(); + } + delete q; + + RDLog *log=new RDLog(log_name.left(log_name.length()-4)); + log_max_id=log->nextId(); + delete log; + + LoadLines(log_name,0,track_ptrs); + + return log_line.size(); +} + + +void RDLogEvent::save(bool update_tracks,int line) +{ + QString sql; + RDSqlQuery *q; + + if(log_name.isEmpty()) { + return; + } + if(line<0) { + if(exists()) { + sql=QString().sprintf("drop table `%s`",(const char *)log_name); + q=new RDSqlQuery(sql); + delete q; + } + RDCreateLogTable(log_name); + for(unsigned i=0;i<log_line.size();i++) { + SaveLine(i); + } + } + else { + sql=QString().sprintf("delete from `%s` where COUNT=%d", + (const char *)log_name,line); + q=new RDSqlQuery(sql); + delete q; + SaveLine(line); + } + RDLog *log=new RDLog(log_name.left(log_name.length()-4)); + if(log->nextId()<nextId()) { + log->setNextId(nextId()); + } + if(update_tracks) { + log->updateTracks(); + } + delete log; +} + + +int RDLogEvent::append(const QString &logname,bool track_ptrs) +{ + return LoadLines(RDLog::tableName(logname),log_max_id,track_ptrs); +} + + +void RDLogEvent::clear() +{ + log_name=""; + log_line.resize(0); + log_max_id=0; +} + + +int RDLogEvent::validate(QString *report,const QDate &date) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + int errs=0; + + // + // Report Header + // + *report="Rivendell Log Exception Report\n"; + *report+= + QString(). + sprintf("Generated at: %s - %s\n", + (const char *)QDate::currentDate().toString("MM/dd/yyyy"), + (const char *)QTime::currentTime().toString("hh:mm:ss")); + *report+=QString().sprintf("Log: %s\n", + (const char *)log_name.left(log_name.length()-4)); + *report+=QString().sprintf("Effective Airdate: %s\n", + (const char *)date.toString("MM/dd/yyyy")); + *report+="\n"; + + // + // Line Scan + // + for(int i=0;i<size();i++) { + if(logLine(i)->cartNumber()>0) { + sql=QString().sprintf("select TYPE,TITLE from CART where NUMBER=%d", + logLine(i)->cartNumber()); + q=new RDSqlQuery(sql); + if(!q->first()) { + *report+=QString(). + sprintf(" %s - missing cart %06d\n", + (const char *)logLine(i)->startTime(RDLogLine::Logged). + toString("hh:mm:ss"), + logLine(i)->cartNumber()); + errs++; + } + else { + if((RDCart::Type)q->value(0).toInt()==RDCart::Audio) { + if(logLine(i)->startTime(RDLogLine::Logged).isNull()) { + // + // Handle events with no logged start time (e.g. manual inserts) + // + sql=QString(). + sprintf("select CUT_NAME from CUTS where \ + (CART_NUMBER=%u)&& \ + ((START_DATETIME is null)|| \ + (START_DATETIME<=\"%s 23:59:59\"))&& \ + ((END_DATETIME is null)|| \ + (END_DATETIME>=\"%s 00:00:00\"))&& \ + (%s=\"Y\")&&(LENGTH>0)", + logLine(i)->cartNumber(), + (const char *)date.toString("yyyy-MM-dd"), + (const char *)date.toString("yyyy-MM-dd"), + (const char *)RDDowCode(date.dayOfWeek())); + } + else { + sql=QString(). + sprintf("select CUT_NAME from CUTS where \ + (CART_NUMBER=%u)&& \ + ((START_DATETIME is null)||(START_DATETIME<=\"%s %s\"))&& \ + ((END_DATETIME is null)||(END_DATETIME>=\"%s %s\"))&& \ + ((START_DAYPART is null)||(START_DAYPART<=\"%s\"))&& \ + ((END_DAYPART is null)||(END_DAYPART>=\"%s\"))&& \ + (%s=\"Y\")&&(LENGTH>0)", + logLine(i)->cartNumber(), + (const char *)date.toString("yyyy-MM-dd"), + (const char *)logLine(i)->startTime(RDLogLine::Logged). + toString("hh:mm:ss"), + (const char *)date.toString("yyyy-MM-dd"), + (const char *)logLine(i)->startTime(RDLogLine::Logged). + toString("hh:mm:ss"), + (const char *)logLine(i)->startTime(RDLogLine::Logged). + toString("hh:mm:ss"), + (const char *)logLine(i)->startTime(RDLogLine::Logged). + toString("hh:mm:ss"), + (const char *)RDDowCode(date.dayOfWeek())); + } + q1=new RDSqlQuery(sql); + if(!q1->first()) { + *report+=QString(). + sprintf(" %s - cart %06d [%s] is not playable\n", + (const char *)logLine(i)->startTime(RDLogLine::Logged). + toString("hh:mm:ss"),logLine(i)->cartNumber(), + (const char *)q->value(1).toString()); + errs++; + } + delete q1; + } + } + delete q; + } + } + *report+="\n"; + if(errs==1) { + *report+=QString().sprintf("%d exception found.\n\n",errs); + } + else { + *report+=QString().sprintf("%d exceptions found.\n\n",errs); + } + return errs; +} + + +void RDLogEvent::refresh(int line) +{ + if(log_name.isEmpty()||log_line[line]->cartNumber()==0) { + return; + } + QString sql=QString().sprintf("select CART.TYPE,CART.GROUP_NAME,CART.TITLE,\ + CART.ARTIST,CART.ALBUM,CART.YEAR,CART.LABEL,\ + CART.CLIENT,CART.AGENCY,CART.USER_DEFINED,\ + CART.FORCED_LENGTH,CART.CUT_QUANTITY,\ + CART.LAST_CUT_PLAYED,CART.PLAY_ORDER,\ + CART.ENFORCE_LENGTH,CART.PRESERVE_PITCH,\ + CART.PUBLISHER,CART.COMPOSER,CART.USAGE_CODE,\ + CART.AVERAGE_SEGUE_LENGTH,CART.VALIDITY,\ + CART.NOTES,GROUPS.COLOR from CART \ + left join GROUPS \ + on CART.GROUP_NAME=GROUPS.NAME \ + where CART.NUMBER=%u", + log_line[line]->cartNumber()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + switch((RDCart::Type)q->value(0).toInt()) { + case RDCart::Audio: + log_line[line]->setType(RDLogLine::Cart); + break; + + case RDCart::Macro: + log_line[line]->setType(RDLogLine::Macro); + break; + + default: + break; + } + log_line[line]-> + setCartType((RDCart::Type)q->value(0).toInt()); // Cart Type + log_line[line]->setGroupName(q->value(1).toString()); // Group Name + log_line[line]->setTitle(q->value(2).toString()); // Title + log_line[line]->setArtist(q->value(3).toString()); // Artist + log_line[line]->setPublisher(q->value(16).toString()); // Publisher + log_line[line]->setComposer(q->value(17).toString()); // Composer + log_line[line]->setAlbum(q->value(4).toString()); // Album + log_line[line]->setYear(q->value(5).toDate()); // Year + log_line[line]->setLabel(q->value(6).toString()); // Label + log_line[line]->setClient(q->value(7).toString()); // Client + log_line[line]->setAgency(q->value(8).toString()); // Agency + log_line[line]->setUserDefined(q->value(9).toString()); // User Defined + log_line[line]->setUsageCode((RDCart::UsageCode)q->value(16).toInt()); + log_line[line]->setForcedLength(q->value(10).toUInt()); // Forced Length + log_line[line]->setAverageSegueLength(q->value(19).toUInt()); + log_line[line]->setCutQuantity(q->value(11).toUInt()); // Cut Quantity + log_line[line]->setLastCutPlayed(q->value(12).toUInt()); // Last Cut Played + log_line[line]-> + setPlayOrder((RDCart::PlayOrder)q->value(13).toUInt()); // Play Order + log_line[line]-> + setEnforceLength(RDBool(q->value(14).toString())); // Enforce Length + log_line[line]-> + setPreservePitch(RDBool(q->value(15).toString())); // Preserve Pitch + log_line[line]->setValidity((RDCart::Validity)q->value(20).toInt()); + log_line[line]->setCartNotes(q->value(21).toString()); // Cart Notes + log_line[line]->setGroupColor(q->value(22).toString()); // Group Color + } + else { + log_line[line]->setValidity(RDCart::NeverValid); + } + delete q; +} + + +int RDLogEvent::size() const +{ + return log_line.size(); +} + + +void RDLogEvent::insert(int line,int num_lines,bool preserve_trans) +{ + if(!preserve_trans) { + if(line>0) { + log_line[line-1]->setEndPoint(-1,RDLogLine::LogPointer); + log_line[line-1]->setSegueStartPoint(-1,RDLogLine::LogPointer); + log_line[line-1]->setSegueEndPoint(-1,RDLogLine::LogPointer); + } + if(line<(size()-1)) { + log_line[line]->setStartPoint(-1,RDLogLine::LogPointer); + log_line[line]->setHasCustomTransition(false); + } + } + if(line<size()) { + for(int i=0;i<num_lines;i++) { + log_line.insert(log_line.begin()+line+i,1,new RDLogLine()); + log_line[line+i]->setId(++log_max_id); + } + return; + } + if(line>=size()) { + for(int i=0;i<num_lines;i++) { + log_line.push_back(new RDLogLine()); + log_line.back()->setId(++log_max_id); + } + return; + } +} + + +void RDLogEvent::remove(int line,int num_lines,bool preserve_trans) +{ + if(!preserve_trans) { + if(line>0) { + log_line[line-1]->setEndPoint(-1,RDLogLine::LogPointer); + log_line[line-1]->setSegueStartPoint(-1,RDLogLine::LogPointer); + log_line[line-1]->setSegueEndPoint(-1,RDLogLine::LogPointer); + } + if(line<((int)log_line.size()-num_lines)) { + log_line[line+num_lines]->setStartPoint(-1,RDLogLine::LogPointer); + log_line[line+num_lines]->setHasCustomTransition(false); + } + } + for(int i=line;i<(line+num_lines);i++) { + delete log_line[i]; + } + std::vector<RDLogLine *>::iterator it=log_line.begin()+line; + log_line.erase(it,it+num_lines); +} + + +void RDLogEvent::move(int from_line,int to_line) +{ + int src_offset=0; + int dest_offset=1; + RDLogLine *srcline; + RDLogLine *destline; + + if(to_line<from_line) { + src_offset=1; + dest_offset=0; + } + insert(to_line+dest_offset,1); + if((to_line+1)>=size()) { + to_line=size()-1; + dest_offset=0; + } + + if(((destline=logLine(to_line+dest_offset))==NULL)|| + (srcline=logLine(from_line+src_offset))==NULL) { + remove(to_line+dest_offset,1); + return; + } + *destline=*srcline; + destline->clearTrackData(RDLogLine::AllTrans); + remove(from_line+src_offset,1); +} + + +void RDLogEvent::copy(int from_line,int to_line) +{ + RDLogLine *srcline; + RDLogLine *destline; + + insert(to_line,1); + if(((destline=logLine(to_line))==NULL)|| + (srcline=logLine(from_line))==NULL) { + remove(to_line,1); + return; + } + *destline=*srcline; + destline->clearExternalData(); + destline->clearTrackData(RDLogLine::AllTrans); + destline->setSource(RDLogLine::Manual); +} + + +int RDLogEvent::length(int from_line,int to_line,QTime *sched_time) +{ + if(sched_time!=NULL) { + *sched_time=QTime(); + } + if(to_line<0) { + to_line=size(); + for(int i=from_line;i<size();i++) { + if(logLine(i)->timeType()==RDLogLine::Hard) { + to_line=i; + i=size(); + if(sched_time!=NULL) { + *sched_time=logLine(i)->startTime(RDLogLine::Logged); + } + } + } + } + int len=0; + for(int i=from_line;i<to_line;i++) { + if(((i+1)>=size())||(logLine(i+1)->transType()!=RDLogLine::Segue)|| + (logLine(i)->segueStartPoint()<0)) { + len+=logLine(i)->forcedLength(); + } + else { + len+=logLine(i)->segueStartPoint()-logLine(i)->startPoint(); + } + } + + return len; +} + + +int RDLogEvent::lengthToStop(int from_line,QTime *sched_time) +{ + int to_line=-1; + + for(int i=from_line;i<size();i++) { + if(logLine(i)->transType()==RDLogLine::Stop) { + to_line=i; + } + } + if(to_line<0) { + return -1; + } + return length(from_line,to_line,sched_time); +} + + +bool RDLogEvent::blockLength(int *nominal_length,int *actual_length,int line) +{ + *nominal_length=0; + *actual_length=0; + QTime start_time; + int start_line=-1; + QTime end_time; + int end_line=-1; + + if((line<0)||(line>(size()-1))) { + *nominal_length=0; + *actual_length=0; + return false; + } + + // + // Find Block Start + // + for(int i=line;i>=0;i--) { + if(logLine(i)->timeType()==RDLogLine::Hard) { + start_time=logLine(i)->startTime(RDLogLine::Logged); + start_line=i; + i=-1; + } + } + if(start_line<0) { + return false; + } + + // + // Find Block End + // + for(int i=line+1;i<size();i++) { + if(logLine(i)->timeType()==RDLogLine::Hard) { + end_time=logLine(i)->startTime(RDLogLine::Logged); + end_line=i; + i=size(); + } + } + if(end_line<0) { + return false; + } + + // + // Calculate Lengths + // + *nominal_length=start_time.msecsTo(end_time); + for(int i=start_line;i<end_line;i++) { + if((i<(size()+1))&&((logLine(i+1)->transType()==RDLogLine::Segue))) { + *actual_length+=logLine(i)->averageSegueLength(); + } + else { + *actual_length+=logLine(i)->forcedLength(); + } + } + + return true; +} + +QTime RDLogEvent::blockStartTime(int line) +{ + int actual_length=0; + QTime start_time(0,0,0); + QTime return_time(0,0,0); + int start_line=0; + + if((line<0)||(line>(size()-1))) { + actual_length=0; + return return_time; + } + + // + // Find Block Start + // + for(int i=line;i>=0;i--) { + if(logLine(i)->timeType()==RDLogLine::Hard) { + start_time=logLine(i)->startTime(RDLogLine::Logged); + start_line=i; + i=-1; + } + } + if(start_line == line) { + return start_time; + } + + // + // Calculate Lengths + // + for(int i=start_line;i<line;i++) { + if((i<(size()+1))&&((logLine(i+1)->transType()==RDLogLine::Segue))) { + actual_length+=logLine(i)->averageSegueLength(); + } + else { + actual_length+=logLine(i)->forcedLength(); + } + } + return_time=start_time.addMSecs(actual_length); + return return_time; +} + + +RDLogLine *RDLogEvent::logLine(int line) const +{ + if((line<0)||((unsigned)line>=log_line.size())) { + return NULL; + } + return log_line[line]; +} + + +void RDLogEvent::setLogLine(int line,RDLogLine *ll) +{ + int id=log_line[line]->id(); + *log_line[line]=*ll; + log_line[line]->setId(id); +} + + +RDLogLine *RDLogEvent::loglineById(int id) const +{ + for(int i=0;i<size();i++) { + if(log_line[i]->id()==id) { + return log_line[i]; + } + } + return NULL; +} + + +int RDLogEvent::lineById(int id) const +{ + for(int i=0;i<size();i++) { + if(log_line[i]->id()==id) { + return i; + } + } + return -1; +} + + +int RDLogEvent::lineByStartHour(int hour,RDLogLine::StartTimeType type) const +{ + for(int i=0;i<size();i++) { + if(!log_line[i]->startTime(type).isNull()&& + (log_line[i]->startTime(type).hour()==hour)) { + return i; + } + } + return -1; +} + + +int RDLogEvent::lineByStartHour(int hour) const +{ + int line=-1; + + if((line=lineByStartHour(hour,RDLogLine::Initial))<0) { + if((line=lineByStartHour(hour,RDLogLine::Predicted))<0) { + line=lineByStartHour(hour,RDLogLine::Imported); + } + } + return line; +} + + +int RDLogEvent::nextTimeStart(QTime after) +{ + for(unsigned i=0;i<log_line.size();i++) { + if((log_line[i]->timeType()==RDLogLine::Hard)&& + (log_line[i]->startTime(RDLogLine::Logged)>after)) { + return i; + } + } + return -1; +} + + +RDLogLine::TransType RDLogEvent::nextTransType(int line) +{ + if(line<(size()-1)) { + return logLine(line+1)->transType(); + } + return RDLogLine::Stop; +} + + +void RDLogEvent::removeCustomTransition(int line) +{ + if((line<0)||(line>(size()-1))) { + return; + } + logLine(line)->setStartPoint(-1,RDLogLine::LogPointer); + logLine(line)->setFadeupPoint(-1,RDLogLine::LogPointer); + logLine(line)->setFadeupGain(0); + logLine(line)->setDuckUpGain(0); + logLine(line)->setHasCustomTransition(false); + if(line<1) { + return; + } + if(logLine(line-1)->type()!=RDLogLine::Track) { + logLine(line-1)->setEndPoint(-1,RDLogLine::LogPointer); + logLine(line-1)->setSegueStartPoint(-1,RDLogLine::LogPointer); + logLine(line-1)->setSegueEndPoint(-1,RDLogLine::LogPointer); + logLine(line-1)->setSegueGain(RD_FADE_DEPTH); + logLine(line-1)->setFadedownPoint(-1,RDLogLine::LogPointer); + logLine(line-1)->setFadedownGain(0); + logLine(line-1)->setDuckDownGain(0); + return; + } + if(line<2) { + return; + } + logLine(line-2)->setEndPoint(-1,RDLogLine::LogPointer); + logLine(line-2)->setSegueStartPoint(-1,RDLogLine::LogPointer); + logLine(line-2)->setSegueEndPoint(-1,RDLogLine::LogPointer); + logLine(line-2)->setSegueGain(RD_FADE_DEPTH); + logLine(line-2)->setFadedownPoint(-1,RDLogLine::LogPointer); + logLine(line-2)->setFadedownGain(0); + logLine(line-2)->setDuckDownGain(0); +} + + +int RDLogEvent::nextId() const +{ + int id=-1; + for(int i=0;i<size();i++) { + if(log_line[i]->id()>id) { + id=log_line[i]->id(); + } + } + return id+1; +} + + +int RDLogEvent::nextLinkId() const +{ + int id=-1; + for(int i=0;i<size();i++) { + if(log_line[i]->linkId()>id) { + id=log_line[i]->linkId(); + } + } + return id+1; +} + + +QString RDLogEvent::xml() const +{ + QString ret; + + ret+="<logList>\n"; + for(int i=0;i<size();i++) { + ret+=logLine(i)->xml(i); + } + ret+="</logList>\n"; + + return ret; +} + + +int RDLogEvent::LoadLines(const QString &log_table,int id_offset, + bool track_ptrs) +{ + RDLogLine line; + RDSqlQuery *q1; + QString sql; + RDSqlQuery *q; + bool prev_custom=false; + unsigned lines=0; + unsigned start_line=log_line.size(); + + // + // Load the group color table + // + std::map<QString,QColor> group_colors; + sql="select NAME,COLOR from GROUPS"; + q=new RDSqlQuery(sql); + while(q->next()) { + group_colors[q->value(0).toString()]=QColor(q->value(1).toString()); + } + delete q; + + // + // Field Offsets: + // 0 - LOG.ID 1 - LOG.CART_NUMBER + // 2 - LOG.START_TIME 3 - LOG.TIME_TYPE + // 4 - LOG.TRANS_TYPE 5 - LOG.START_POINT + // 6 - LOG.END_POINT 7 - LOG.SEGUE_START_POINT + // 8 - LOG.SEGUE_END_POINT 9 - CART.TYPE + // 10 - CART.GROUP_NAME 11 - CART.TITLE + // 12 - CART.ARTIST 13 - CART.ALBUM + // 14 - CART.YEAR + // 15 - CART.LABEL 16 - CART.CLIENT + // 17 - CART.AGENCY 18 - CART.USER_DEFINED + // 19 - CART.CONDUCTOR 20 - CART.SONG_ID + // 21 - CART.FORCED_LENGTH 22 - CART.CUT_QUANTITY + // 23 - CART.LAST_CUT_PLAYED 24 - CART.PLAY_ORDER + // 25 - CART.ENFORCE_LENGTH 26 - CART.PRESERVE_PITCH + // 27 - LOG.TYPE 28 - LOG.COMMENT + // 29 - LOG.LABEL 30 - LOG.GRACE_TIME + // 31 - LOG.POST_POINT 32 - LOG.SOURCE + // 33 - LOG.EXT_START_TIME 34 - LOG.EXT_LENGTH + // 35 - LOG.EXT_DATA 36 - LOG.EXT_EVENT_ID + // 37 - LOG.EXT_ANNC_TYPE 38 - LOG.EXT_CART_NAME + // 39 - CART.ASYNCRONOUS 40 - LOG.FADEUP_POINT + // 41 - LOG.FADEUP_GAIN 42 - LOG.FADEDOWN_POINT + // 43 - LOG.FADEDOWN_GAIN 44 - LOG.SEGUE_GAIN + // 45 - CART.PUBLISHER 46 - CART.COMPOSER + // 47 - CART.USAGE_CODE 48 - CART.AVERAGE_SEGUE_LENGTH + // 49 - LOG.LINK_EVENT_NAME 50 - LOG.LINK_START_TIME + // 51 - LOG.LINK_LENGTH 52 - LOG.LINK_ID + // 53 - LOG.LINK_EMBEDDED 54 - LOG.ORIGIN_USER + // 55 - LOG.ORIGIN_DATETIME 56 - CART.VALIDITY + // 57 - LOG.LINK_START_SLOP 58 - LOG.LINK_END_SLOP + // 59 - LOG.DUCK_UP_GAIN 60 - LOG.DUCK_DOWN_GAIN + // 61 - CART.START_DATETIME 62 - CART.END_DATETIME + // 63 - LOG.EVENT_LENGTH 64 - CART.USE_EVENT_LENGTH + // 65 - CART.NOTES + // + sql=QString().sprintf("select `%s`.ID,`%s`.CART_NUMBER,\ +`%s`.START_TIME,`%s`.TIME_TYPE,`%s`.TRANS_TYPE,`%s`.START_POINT,\ +`%s`.END_POINT,`%s`.SEGUE_START_POINT,`%s`.SEGUE_END_POINT,\ +CART.TYPE,CART.GROUP_NAME,CART.TITLE,CART.ARTIST,CART.ALBUM,CART.YEAR,\ +CART.LABEL,CART.CLIENT,CART.AGENCY,CART.USER_DEFINED,\ +CART.CONDUCTOR,CART.SONG_ID,\ +CART.FORCED_LENGTH,CART.CUT_QUANTITY,CART.LAST_CUT_PLAYED,CART.PLAY_ORDER,\ +CART.ENFORCE_LENGTH,CART.PRESERVE_PITCH ,`%s`.TYPE,`%s`.COMMENT,\ +`%s`.LABEL,`%s`.GRACE_TIME,`%s`.POST_POINT,`%s`.SOURCE,\ +`%s`.EXT_START_TIME,`%s`.EXT_LENGTH,`%s`.EXT_DATA,`%s`.EXT_EVENT_ID,\ +`%s`.EXT_ANNC_TYPE,`%s`.EXT_CART_NAME,CART.ASYNCRONOUS,`%s`.FADEUP_POINT,\ +`%s`.FADEUP_GAIN,`%s`.FADEDOWN_POINT,`%s`.FADEDOWN_GAIN,`%s`.SEGUE_GAIN,\ +CART.PUBLISHER,CART.COMPOSER,CART.USAGE_CODE,CART.AVERAGE_SEGUE_LENGTH,\ +`%s`.LINK_EVENT_NAME,`%s`.LINK_START_TIME,`%s`.LINK_LENGTH,`%s`.LINK_ID, \ +`%s`.LINK_EMBEDDED,`%s`.ORIGIN_USER,`%s`.ORIGIN_DATETIME,CART.VALIDITY, \ +`%s`.LINK_START_SLOP,`%s`.LINK_END_SLOP, \ +`%s`.DUCK_UP_GAIN,`%s`.DUCK_DOWN_GAIN,CART.START_DATETIME,CART.END_DATETIME,\ +`%s`.EVENT_LENGTH,CART.USE_EVENT_LENGTH,CART.NOTES \ +from `%s` left join CART on `%s`.CART_NUMBER=CART.NUMBER order by COUNT", + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table, + (const char *)log_table); + q=new RDSqlQuery(sql); + if(q->size()<=0) { + delete q; + return 0; + } + for(int i=0;i<q->size();i++) { + lines++; + line.clear(); + q->next(); + line.setType((RDLogLine::Type)q->value(27).toInt()); // Type + line.setId(q->value(0).toInt()+id_offset); // Log Line ID + if((q->value(0).toInt()+id_offset)>log_max_id) { + log_max_id=q->value(0).toInt()+id_offset; + } + line.setStartTime(RDLogLine::Imported, + QTime().addMSecs(q->value(2).toInt())); // Start Time + line.setStartTime(RDLogLine::Logged, + QTime().addMSecs(q->value(2).toInt())); + line. + setTimeType((RDLogLine::TimeType)q->value(3).toInt()); // Time Type + if((line.timeType()==RDLogLine::Hard)&& + (q->value(31).toString()==QString("Y"))) { // Post Point + } + line. + setTransType((RDLogLine::TransType)q->value(4).toInt()); // Trans Type + line.setMarkerComment(q->value(28).toString()); // Comment + line.setMarkerLabel(q->value(29).toString()); // Label + line.setGraceTime(q->value(30).toInt()); // Grace Time + line.setUseEventLength(RDBool(q->value(64).toString())); // Use Event Length + line.setEventLength(q->value(63).toInt()); // Event Length + line.setSource((RDLogLine::Source)q->value(32).toUInt()); + line.setLinkEventName(q->value(49).toString()); // Link Event Name + line.setLinkStartTime(QTime().addMSecs(q->value(50).toInt())); // Link Start Time + line.setLinkLength(q->value(51).toInt()); // Link Length + line.setLinkStartSlop(q->value(57).toInt()); // Link Start Slop + line.setLinkEndSlop(q->value(58).toInt()); // Link End Slop + line.setLinkId(q->value(52).toInt()); // Link ID + line.setLinkEmbedded(RDBool(q->value(53).toString())); // Link Embedded + line.setOriginUser(q->value(54).toString()); // Origin User + line.setOriginDateTime(q->value(55).toDateTime()); // Origin DateTime + switch(line.type()) { + case RDLogLine::Cart: + line.setCartNumber(q->value(1).toUInt()); // Cart Number + line.setStartPoint(q->value(5).toInt(),RDLogLine::LogPointer); + line.setEndPoint(q->value(6).toInt(),RDLogLine::LogPointer); + line.setSegueStartPoint(q->value(7).toInt(),RDLogLine::LogPointer); + line.setSegueEndPoint(q->value(8).toInt(),RDLogLine::LogPointer); + line.setCartType((RDCart::Type)q->value(9).toInt()); // Cart Type + line.setGroupName(q->value(10).toString()); // Group Name + line.setGroupColor(group_colors[q->value(10).toString()]); + line.setTitle(q->value(11).toString()); // Title + line.setArtist(q->value(12).toString()); // Artist + line.setPublisher(q->value(45).toString()); // Publisher + line.setComposer(q->value(46).toString()); // Composer + line.setAlbum(q->value(13).toString()); // Album + line.setYear(q->value(14).toDate()); // Year + line.setLabel(q->value(15).toString()); // Label + line.setClient(q->value(16).toString()); // Client + line.setAgency(q->value(17).toString()); // Agency + line.setUserDefined(q->value(18).toString()); // User Defined + line.setCartNotes(q->value(65).toString()); // Cart Notes + line.setConductor(q->value(19).toString()); // Conductor + line.setSongId(q->value(20).toString()); // Song ID + line.setUsageCode((RDCart::UsageCode)q->value(47).toInt()); + line.setForcedLength(q->value(21).toUInt()); // Forced Length + if((q->value(7).toInt()<0)||(q->value(8).toInt()<0)) { + line.setAverageSegueLength(q->value(48).toInt()); + } + else { + line. + setAverageSegueLength(q->value(7).toInt()-q->value(5).toInt()); + } + line.setCutQuantity(q->value(22).toUInt()); // Cut Quantity + line.setLastCutPlayed(q->value(23).toUInt()); // Last Cut Played + line. + setPlayOrder((RDCart::PlayOrder)q->value(24).toUInt()); // Play Ord + line. + setEnforceLength(RDBool(q->value(25).toString())); // Enforce Length + line. + setPreservePitch(RDBool(q->value(26).toString())); // Preserve Pitch + if(!q->value(33).isNull()) { // Ext Start Time + line.setExtStartTime(q->value(33).toTime()); + } + if(!q->value(34).isNull()) { // Ext Length + line.setExtLength(q->value(34).toInt()); + } + if(!q->value(35).isNull()) { // Ext Data + line.setExtData(q->value(35).toString()); + } + if(!q->value(36).isNull()) { // Ext Event ID + line.setExtEventId(q->value(36).toString()); + } + if(!q->value(37).isNull()) { // Ext Annc. Type + line.setExtAnncType(q->value(37).toString()); + } + if(!q->value(38).isNull()) { // Ext Cart Name + line.setExtCartName(q->value(38).toString()); + } + if(!q->value(40).isNull()) { // FadeUp Point + line.setFadeupPoint(q->value(40).toInt(),RDLogLine::LogPointer); + } + if(!q->value(41).isNull()) { // FadeUp Gain + line.setFadeupGain(q->value(41).toInt()); + } + if(!q->value(42).isNull()) { // FadeDown Point + line.setFadedownPoint(q->value(42).toInt(),RDLogLine::LogPointer); + } + if(!q->value(43).isNull()) { // FadeDown Gain + line.setFadedownGain(q->value(43).toInt()); + } + if(!q->value(44).isNull()) { // Segue Gain + line.setSegueGain(q->value(44).toInt()); + } + if(!q->value(59).isNull()) { // Duck Up Gain + line.setDuckUpGain(q->value(59).toInt()); + } + if(!q->value(60).isNull()) { // Duck Down Gain + line.setDuckDownGain(q->value(60).toInt()); + } + if(!q->value(61).isNull()) { // Start Datetime + line.setStartDatetime(q->value(61).toDateTime()); + } + if(!q->value(62).isNull()) { // End Datetime + line.setEndDatetime(q->value(62).toDateTime()); + } + line.setValidity((RDCart::Validity)q->value(56).toInt()); // Validity + break; + + case RDLogLine::Macro: + line.setCartNumber(q->value(1).toUInt()); // Cart Number + line.setCartType((RDCart::Type)q->value(9).toInt()); // Cart Type + line.setGroupName(q->value(10).toString()); // Group Name + line.setGroupColor(group_colors[q->value(10).toString()]); + line.setTitle(q->value(11).toString()); // Title + line.setArtist(q->value(12).toString()); // Artist + line.setPublisher(q->value(45).toString()); // Publisher + line.setComposer(q->value(46).toString()); // Composer + line.setAlbum(q->value(13).toString()); // Album + line.setYear(q->value(14).toDate()); // Year + line.setLabel(q->value(15).toString()); // Label + line.setClient(q->value(16).toString()); // Client + line.setAgency(q->value(17).toString()); // Agency + line.setUserDefined(q->value(18).toString()); // User Defined + line.setCartNotes(q->value(65).toString()); // Cart Notes + line.setForcedLength(q->value(21).toUInt()); // Forced Length + line.setAverageSegueLength(q->value(21).toInt()); + if(!q->value(33).isNull()) { // Ext Start Time + line.setExtStartTime(q->value(33).toTime()); + } + if(!q->value(34).isNull()) { // Ext Length + line.setExtLength(q->value(34).toInt()); + } + if(!q->value(35).isNull()) { // Ext Data + line.setExtData(q->value(35).toString()); + } + if(!q->value(36).isNull()) { // Ext Event ID + line.setExtEventId(q->value(36).toString()); + } + if(!q->value(37).isNull()) { // Ext Annc. Type + line.setExtAnncType(q->value(37).toString()); + } + if(!q->value(38).isNull()) { // Ext Cart Name + line.setExtCartName(q->value(38).toString()); + } + if(!q->value(39).isNull()) { // Asyncronous + line.setAsyncronous(RDBool(q->value(39).toString())); + } + break; + + case RDLogLine::Marker: + break; + + case RDLogLine::Track: + break; + + case RDLogLine::Chain: + sql= + QString().sprintf("select DESCRIPTION from LOGS where NAME=\"%s\"", + (const char *)line.markerLabel()); + q1=new RDSqlQuery(sql); + if(q1->first()) { + line.setMarkerComment(q1->value(0).toString()); + } + delete q1; + break; + + default: + break; + } + + line.setHasCustomTransition(prev_custom||(q->value(5).toInt()>=0)||\ + (q->value(40).toInt()>=0)); + if(line.type()==RDLogLine::Cart) { + prev_custom=(q->value(6).toInt()>=0)||(q->value(7).toInt()>=0)|| + (q->value(8).toInt()>=0)||(q->value(42).toInt()>=0); + } + else { + prev_custom=false; + } +/* + printf("LINE: %u START: %d END: %d S_START: %d S_END: %d FD_UP: %d FD_DN: %d\n", + log_line.size(), + q->value(5).toInt(), + q->value(6).toInt(), + q->value(7).toInt(), + q->value(8).toInt(), + q->value(38).toInt(), + q->value(40).toInt()); +*/ + + log_line.push_back(new RDLogLine(line)); + } + delete q; + + LoadNowNext(start_line); + + if(track_ptrs) { + // + // Load default cart pointers for "representative" cuts. This is + // really only useful when setting up a voice tracker. + // + for(int i=start_line;i<size();i++) { + RDLogLine *ll=logLine(i); + if(ll->cartType()==RDCart::Audio) { + sql=QString("select START_POINT,END_POINT,")+ + "SEGUE_START_POINT,SEGUE_END_POINT,"+ + "TALK_START_POINT,TALK_END_POINT," + "HOOK_START_POINT,HOOK_END_POINT,"+ + "FADEUP_POINT,FADEDOWN_POINT,CUT_NAME,"+ + "ORIGIN_NAME,ORIGIN_DATETIME from CUTS "+ + QString().sprintf("where CART_NUMBER=%u ",ll->cartNumber())+ + "order by CUT_NAME"; + q=new RDSqlQuery(sql); + if(q->first()) { + ll->setStartPoint(q->value(0).toInt(),RDLogLine::CartPointer); + ll->setEndPoint(q->value(1).toInt(),RDLogLine::CartPointer); + ll->setSegueStartPoint(q->value(2).toInt(),RDLogLine::CartPointer); + ll->setSegueEndPoint(q->value(3).toInt(),RDLogLine::CartPointer); + ll->setTalkStartPoint(q->value(4).toInt()); + ll->setTalkEndPoint(q->value(5).toInt()); + ll->setHookStartPoint(q->value(6).toInt()); + ll->setHookEndPoint(q->value(7).toInt()); + ll->setFadeupPoint(q->value(8).toInt(),RDLogLine::CartPointer); + ll->setFadedownPoint(q->value(9).toInt(),RDLogLine::CartPointer); + ll->setCutNumber(RDCut::cutNumber(q->value(10).toString())); + ll->setOriginUser(q->value(11).toString()); + ll->setOriginDateTime(q->value(12).toDateTime()); + } + delete q; + } + } + } + + return lines; +} + + +void RDLogEvent::SaveLine(int line) +{ + QString sql; + RDSqlQuery *q; + sql=QString().sprintf("insert into `%s` set ID=%d,COUNT=%d,\ + CART_NUMBER=%u,START_TIME=%d,TIME_TYPE=%d,\ + TRANS_TYPE=%d,START_POINT=%d,END_POINT=%d,\ + SEGUE_START_POINT=%d,SEGUE_END_POINT=%d,TYPE=%d,\ + COMMENT=\"%s\",LABEL=\"%s\",GRACE_TIME=%d,\ + SOURCE=%d,EXT_START_TIME=\"%s\",\ + EXT_LENGTH=%d,EXT_DATA=\"%s\",EXT_EVENT_ID=\"%s\",\ + EXT_ANNC_TYPE=\"%s\",EXT_CART_NAME=\"%s\",\ + FADEUP_POINT=%d,FADEUP_GAIN=%d,FADEDOWN_POINT=%d,\ + FADEDOWN_GAIN=%d,SEGUE_GAIN=%d,\ + LINK_EVENT_NAME=\"%s\",LINK_START_TIME=%d,\ + LINK_LENGTH=%d,LINK_ID=%d,LINK_EMBEDDED=\"%s\",\ + ORIGIN_USER=\"%s\",ORIGIN_DATETIME=\"%s\",\ + LINK_START_SLOP=%d,LINK_END_SLOP=%d,\ + DUCK_UP_GAIN=%d,DUCK_DOWN_GAIN=%d,\ + EVENT_LENGTH=%d", + (const char *)log_name, + log_line[line]->id(), + line, + log_line[line]->cartNumber(), + QTime().msecsTo(log_line[line]-> + startTime(RDLogLine::Logged)), + (int)log_line[line]->timeType(), + (int)log_line[line]->transType(), + log_line[line]->startPoint(RDLogLine::LogPointer), + log_line[line]->endPoint(RDLogLine::LogPointer), + log_line[line]->segueStartPoint(RDLogLine::LogPointer), + log_line[line]->segueEndPoint(RDLogLine::LogPointer), + log_line[line]->type(), + (const char *) + RDEscapeString(log_line[line]->markerComment()), + (const char *) + RDEscapeString(log_line[line]->markerLabel()), + log_line[line]->graceTime(), + log_line[line]->source(), + (const char *)log_line[line]->extStartTime(). + toString("hh:mm:ss"), + log_line[line]->extLength(), + (const char *)RDEscapeString(log_line[line]->extData()), + (const char *) + RDEscapeString(log_line[line]->extEventId()), + (const char *) + RDEscapeString(log_line[line]->extAnncType()), + (const char *) + RDEscapeString(log_line[line]->extCartName()), + log_line[line]->fadeupPoint(RDLogLine::LogPointer), + log_line[line]->fadeupGain(), + log_line[line]->fadedownPoint(RDLogLine::LogPointer), + log_line[line]->fadedownGain(), + log_line[line]->segueGain(), + (const char *) + RDEscapeString(log_line[line]->linkEventName()), + QTime().msecsTo(log_line[line]->linkStartTime()), + log_line[line]->linkLength(), + log_line[line]->linkId(), + (const char *)RDYesNo(log_line[line]->linkEmbedded()), + (const char *) + RDEscapeString(log_line[line]->originUser()), + (const char *)log_line[line]->originDateTime(). + toString("yyyy-MM-dd hh:mm:ss"), + log_line[line]->linkStartSlop(), + log_line[line]->linkEndSlop(), + log_line[line]->duckUpGain(), + log_line[line]->duckDownGain(), + log_line[line]->eventLength()); + + // printf("SQL: %s\n",(const char *)sql); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDLogEvent::LoadNowNext(unsigned from_line) +{ + std::vector<QString> groups; + std::vector<bool> now_nexts; + + // + // Load the Lookup Table + // + RDSqlQuery *q=new RDSqlQuery("select NAME,ENABLE_NOW_NEXT from GROUPS"); + while(q->next()) { + groups.push_back(QString(q->value(0).toString())); + now_nexts.push_back(RDBool(q->value(1).toString())); + } + delete q; + + for(unsigned i=from_line;i<log_line.size();i++) { + for(unsigned j=0;j<groups.size();j++) { + if(log_line[i]->groupName()==groups[j]) { + log_line[i]->setNowNextEnabled(now_nexts[j]); + } + } + } +} + diff --git a/lib/rdlog_event.h b/lib/rdlog_event.h new file mode 100644 index 00000000..c44ac061 --- /dev/null +++ b/lib/rdlog_event.h @@ -0,0 +1,86 @@ +// rdlog_event.h +// +// Abstract Rivendell Log Events +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlog_event.h,v 1.36.6.4.2.1 2014/05/22 19:37:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <vector> + +#include <qdatetime.h> +#include <qsqldatabase.h> + +#include <rdlog_line.h> + + +#ifndef RDLOG_EVENT_H +#define RDLOG_EVENT_H + +#define INSERT_STEP_SIZE 500 + +class RDLogEvent +{ + public: + RDLogEvent(QString logname=""); + ~RDLogEvent(); + bool exists(); + bool exists(int line); + bool exists(const QTime &hard_time,int except_line=-1); + QString logName() const; + void setLogName(QString logname); + QString serviceName() const; + int load(bool track_ptrs=false); + void save(bool update_tracks=true,int line=-1); + int append(const QString &logname,bool track_ptrs=false); + int validate(QString *report,const QDate &date); + void clear(); + void refresh(int line); + int size() const; + void insert(int line,int num_lines,bool preserve_trans=false); + void remove(int line,int num_lines,bool preserve_trans=false); + void move(int from_line,int to_line); + void copy(int from_line,int to_line); + int length(int from_line,int to_line,QTime *sched_time=NULL); + int lengthToStop(int from_line,QTime *sched_time=NULL); + bool blockLength(int *nominal_length,int *actual_length,int line); + QTime blockStartTime(int line); + RDLogLine *logLine(int line) const; + void setLogLine(int line,RDLogLine *ll); + RDLogLine *loglineById(int id) const; + int lineById(int id) const; + int lineByStartHour(int hour,RDLogLine::StartTimeType type) const; + int lineByStartHour(int hour) const; + int nextTimeStart(QTime after); + RDLogLine::TransType nextTransType(int); + void removeCustomTransition(int line); + int nextId() const; + int nextLinkId() const; + QString xml() const; + + private: + int LoadLines(const QString &log_table,int id_offset,bool track_ptrs); + void SaveLine(int line); + void LoadNowNext(unsigned from_line); + QString log_name; + QString log_service_name; + int log_max_id; + std::vector<RDLogLine *> log_line; +}; + + +#endif diff --git a/lib/rdlog_line.cpp b/lib/rdlog_line.cpp new file mode 100644 index 00000000..4972d136 --- /dev/null +++ b/lib/rdlog_line.cpp @@ -0,0 +1,2095 @@ +// rdlog_line.cpp +// +// A container class for a Rivendell Log Line. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlog_line.cpp,v 1.113.4.13.2.2 2014/05/22 16:12:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WIN32 +#include <syslog.h> +#endif // WIN32 + +#include <qobject.h> + +#include <rddb.h> +#include <rdconf.h> +#include <rd.h> +#include <rdlog_line.h> +#include <rdcut.h> +#include <rdmacro_event.h> +#include <rdweb.h> + +RDLogLine::RDLogLine() +{ + clear(); +} + + +RDLogLine::RDLogLine(unsigned cartnum) +{ + QString sql; + RDSqlQuery *q; + + clear(); + log_cart_number=cartnum; + sql=QString().sprintf("select GROUP_NAME,TITLE,ARTIST,ALBUM,YEAR,LABEL,\ + CLIENT,AGENCY,COMPOSER,PUBLISHER,USER_DEFINED,NOTES \ + from CART where NUMBER=%u",log_cart_number); + q=new RDSqlQuery(sql); + if(q->first()) { + log_group_name=q->value(0).toString(); + log_title=q->value(1).toString(); + log_artist=q->value(2).toString(); + log_album=q->value(3).toString(); + log_year=QDate(q->value(4).toInt(),1,1); + log_label=q->value(5).toString(); + log_client=q->value(6).toString(); + log_agency=q->value(7).toString(); + log_composer=q->value(8).toString(); + log_publisher=q->value(9).toString(); + log_user_defined=q->value(10).toString(); + log_cart_notes=q->value(11).toString(); + } + delete q; +} + + +void RDLogLine::clear() +{ + log_id=-1; + log_status=RDLogLine::Scheduled; + log_state=RDLogLine::Ok; + log_validity=RDCart::AlwaysValid; + log_pass=0; + log_source=RDLogLine::Manual; + log_cart_number=0; + for(int i=0;i<5;i++) { + log_start_time[i]=QTime(); + } + log_time_type=RDLogLine::Relative; + log_origin_user=""; + log_origin_datetime=QDateTime(); + log_trans_type=RDLogLine::Play; + for(unsigned i=0;i<2;i++) { + log_start_point[i]=-1; + log_end_point[i]=-1; + log_segue_start_point[i]=-1; + log_segue_end_point[i]=-1; + log_fadeup_point[i]=-1; + log_fadedown_point[i]=-1; + } + log_segue_gain=RD_FADE_DEPTH; + log_segue_gain_cut=RD_FADE_DEPTH; + log_fadedown_gain=0; + log_fadeup_gain=0; + log_duck_up_gain=0; + log_duck_down_gain=0; + log_hook_mode=false; + log_hook_start=-1; + log_hook_end=-1; + log_cart_type=RDCart::Audio; + log_group_name=""; + log_group_color=QColor(); + log_title=""; + log_artist=""; + log_publisher=""; + log_composer=""; + log_isrc=""; + log_album=""; + log_year=QDate(); + log_isci=""; + log_label=""; + log_conductor=""; + log_song_id=""; + log_client=""; + log_agency=""; + log_outcue=""; + log_description=""; + log_user_defined=""; + log_usage_code=RDCart::UsageFeature; + log_forced_length=0; + log_cut_quantity=0; + log_last_cut_played=0; + log_play_order=RDCart::Sequence; + log_enforce_length=false; + log_preserve_pitch=false; + log_start_datetime=QDateTime(); + log_end_datetime=QDateTime(); + log_deck=-1; + log_port_name=""; + log_play_time=QTime(); + log_cut_number=-1; + log_effective_length=-1; + log_talk_start=-1; + log_talk_end=-1; + log_talk_length=-1; + log_play_position=0; + log_type=RDLogLine::Cart; + log_marker_comment=""; + log_marker_label=""; + log_marker_post_time=QTime(); + log_listview=NULL; + log_grace_time=0; + log_forced_stop=false; + log_play_position_changed=false; + log_evergreen=false; + log_ext_start_time=QTime(); + log_ext_length=-1; + log_ext_cart_name=""; + log_ext_data=""; + log_ext_event_id=""; + log_ext_annc_type=""; + log_pause_card=-1; + log_pause_port=-1; + log_now_next_enabled=false; + log_zombified=false; + log_timescaling_active=false; + log_play_deck=NULL; + log_asyncronous=false; + log_cut_name=""; + log_average_segue_length=0; + log_has_custom_transition=false; + log_use_event_length=false; + log_event_length=-1; + log_link_event_name=""; + log_link_start_time=QTime(); + log_link_length=0; + log_link_start_slop=0; + log_link_end_slop=0; + log_link_id=-1; + log_link_embedded=false; + log_start_source=RDLogLine::StartUnknown; +} + + +void RDLogLine::clearExternalData() +{ + log_ext_start_time=QTime(); + log_ext_length=-1; + log_ext_data=""; + log_ext_event_id=""; + log_ext_annc_type=""; +} + + +void RDLogLine::clearTrackData(RDLogLine::TransEdge edge) +{ + if((edge==RDLogLine::LeadingTrans)||(edge==RDLogLine::AllTrans)) { + log_start_point[RDLogLine::LogPointer]=-1; + log_fadeup_point[RDLogLine::LogPointer]=-1; + log_fadeup_gain=RD_FADE_DEPTH; + log_has_custom_transition=false; + } + if((edge==RDLogLine::TrailingTrans)||(edge==RDLogLine::AllTrans)) { + log_end_point[RDLogLine::LogPointer]=-1; + log_fadedown_point[RDLogLine::LogPointer]=-1; + log_fadedown_gain=RD_FADE_DEPTH; + log_segue_start_point[RDLogLine::LogPointer]=-1; + log_segue_end_point[RDLogLine::LogPointer]=-1; + log_segue_gain=RD_FADE_DEPTH; + } +} + + +int RDLogLine::id() const +{ + return log_id; +} + + +void RDLogLine::setId(int id) +{ + log_id=id; +} + + +RDLogLine::Status RDLogLine::status() const +{ + return log_status; +} + + +void RDLogLine::setStatus(RDLogLine::Status stat) +{ + log_status=stat; +} + + +RDLogLine::State RDLogLine::state() const +{ + return log_state; +} + + +void RDLogLine::setState(RDLogLine::State state) +{ + log_state=state; +} + + +RDCart::Validity RDLogLine::validity() const +{ + return log_validity; +} + + +RDCart::Validity RDLogLine::validity(const QDateTime &datetime) const +{ + if(datetime.isNull()||log_end_datetime.isNull()) { + return log_validity; + } + if(datetime>log_end_datetime) { + return RDCart::NeverValid; + } + if(datetime<log_start_datetime) { + return RDCart::FutureValid; + } + return log_validity; +} + + +void RDLogLine::setValidity(RDCart::Validity valid) +{ + log_validity=valid; +} + + +unsigned RDLogLine::pass() const +{ + return log_pass; +} + + +void RDLogLine::incrementPass() +{ + log_pass++; +} + + +void RDLogLine::clearPass() +{ + log_pass=0; +} + + +bool RDLogLine::zombified() const +{ + return log_zombified; +} + + +void RDLogLine::setZombified(bool state) +{ + log_zombified=state; +} + + +bool RDLogLine::evergreen() const +{ + return log_evergreen; +} + + +void RDLogLine::setEvergreen(bool state) +{ + log_evergreen=state; +} + + +RDLogLine::Source RDLogLine::source() const +{ + return log_source; +} + + +void RDLogLine::setSource(RDLogLine::Source src) +{ + log_source=src; +} + + +unsigned RDLogLine::cartNumber() const +{ + return log_cart_number; +} + + +void RDLogLine::setCartNumber(unsigned cart) +{ + log_cart_number=cart; +} + + +QTime RDLogLine::startTime(RDLogLine::StartTimeType type) const +{ + return log_start_time[type]; +} + + +void RDLogLine::setStartTime(RDLogLine::StartTimeType type,QTime time) +{ + if(type==RDLogLine::Initial) { + log_start_time[RDLogLine::Actual]=time; + } + log_start_time[type]=time; +} + + +int RDLogLine::graceTime() const +{ + return log_grace_time; +} + + +void RDLogLine::setGraceTime(int time) +{ + log_grace_time=time; +} + + +RDLogLine::TimeType RDLogLine::timeType() const +{ + return log_time_type; +} + + +void RDLogLine::setTimeType(RDLogLine::TimeType type) +{ + log_time_type=type; +} + + +QString RDLogLine::originUser() const +{ + return log_origin_user; +} + + +void RDLogLine::setOriginUser(const QString &username) +{ + log_origin_user=username; +} + + +QDateTime RDLogLine::originDateTime() const +{ + return log_origin_datetime; +} + + +void RDLogLine::setOriginDateTime(const QDateTime &datetime) +{ + log_origin_datetime=datetime; +} + + +RDLogLine::TransType RDLogLine::transType() const +{ + return log_trans_type; +} + + +void RDLogLine::setTransType(RDLogLine::TransType type) +{ + log_trans_type=type; +} + + +int RDLogLine::startPoint(PointerSource ptr) const +{ + if(ptr==RDLogLine::AutoPointer) { + if(log_start_point[RDLogLine::LogPointer]>=0) { + return log_start_point[RDLogLine::LogPointer]; + } + return log_start_point[RDLogLine::CartPointer]; + } + return log_start_point[ptr]; +} + + +void RDLogLine::setStartPoint(int point,PointerSource ptr) +{ + log_start_point[ptr]=point; +} + + +int RDLogLine::endPoint(PointerSource ptr) const +{ + if(ptr==RDLogLine::AutoPointer) { + if(log_end_point[RDLogLine::LogPointer]>=0) { + return log_end_point[RDLogLine::LogPointer]; + } + return log_end_point[RDLogLine::CartPointer]; + } + return log_end_point[ptr]; +} + + +void RDLogLine::setEndPoint(int point,PointerSource ptr) +{ + log_end_point[ptr]=point; +} + + +int RDLogLine::segueStartPoint(PointerSource ptr) const +{ + if(ptr==RDLogLine::AutoPointer) { + if(log_segue_start_point[RDLogLine::LogPointer]>=0) { + return log_segue_start_point[RDLogLine::LogPointer]; + } + if(log_segue_start_point[RDLogLine::CartPointer]>=0) { + return log_segue_start_point[RDLogLine::CartPointer]; + } + if(log_end_point[RDLogLine::LogPointer]>=0) { + return log_end_point[RDLogLine::LogPointer]; + } + return log_end_point[RDLogLine::CartPointer]; + } + return log_segue_start_point[ptr]; +} + + +void RDLogLine::setSegueStartPoint(int point,PointerSource ptr) +{ + log_segue_start_point[ptr]=point; +} + + +int RDLogLine::segueEndPoint(PointerSource ptr) const +{ + if(ptr==RDLogLine::AutoPointer) { + if(log_segue_end_point[RDLogLine::LogPointer]>=0) { + return log_segue_end_point[RDLogLine::LogPointer]; + } + if(log_segue_end_point[RDLogLine::CartPointer]>=0) { + return log_segue_end_point[RDLogLine::CartPointer]; + } + if(log_end_point[RDLogLine::LogPointer]>=0) { + return log_end_point[RDLogLine::LogPointer]; + } + return log_end_point[RDLogLine::CartPointer]; + } + return log_segue_end_point[ptr]; +} + + +void RDLogLine::setSegueEndPoint(int point,PointerSource ptr) +{ + log_segue_end_point[ptr]=point; +} + + +int RDLogLine::segueGain() const +{ + if(log_segue_gain>log_segue_gain_cut) { + return log_segue_gain; + } + else { + return log_segue_gain_cut; + } +} + + +void RDLogLine::setSegueGain(int gain) +{ + log_segue_gain=gain; +} + + +int RDLogLine::fadeupPoint(RDLogLine::PointerSource ptr) const +{ + if(ptr==RDLogLine::AutoPointer) { + if(log_fadeup_point[RDLogLine::LogPointer]>=0) { + return log_fadeup_point[RDLogLine::LogPointer]; + } + if(log_fadeup_point[RDLogLine::CartPointer]>=0) { + return log_fadeup_point[RDLogLine::CartPointer]; + } + if(log_start_point[RDLogLine::LogPointer]>=0) { + return log_start_point[RDLogLine::LogPointer]; + } + return log_start_point[RDLogLine::CartPointer]; + } + return log_fadeup_point[ptr]; +} + + +void RDLogLine::setFadeupPoint(int point,RDLogLine::PointerSource ptr) +{ + log_fadeup_point[ptr]=point; +} + + +int RDLogLine::fadeupGain() const +{ + return log_fadeup_gain; +} + + +void RDLogLine::setFadeupGain(int gain) +{ + log_fadeup_gain=gain; +} + + +int RDLogLine::fadedownPoint(RDLogLine::PointerSource ptr) const +{ + if(ptr==RDLogLine::AutoPointer) { + if(log_fadedown_point[RDLogLine::LogPointer]>=0) { + return log_fadedown_point[RDLogLine::LogPointer]; + } + if(log_fadedown_point[RDLogLine::CartPointer]>=0) { + return log_fadedown_point[RDLogLine::CartPointer]; + } + if(log_start_point[RDLogLine::LogPointer]>=0) { + return log_end_point[RDLogLine::LogPointer]; + } + return log_end_point[RDLogLine::CartPointer]; + } + return log_fadedown_point[ptr]; +} + + +void RDLogLine::setFadedownPoint(int point,RDLogLine::PointerSource ptr) +{ + log_fadedown_point[ptr]=point; +} + + +int RDLogLine::fadedownGain() const +{ + return log_fadedown_gain; +} + + +void RDLogLine::setFadedownGain(int gain) +{ + log_fadedown_gain=gain; +} + + +int RDLogLine::duckUpGain() const +{ + return log_duck_up_gain; +} + + +void RDLogLine::setDuckUpGain(int gain) +{ + log_duck_up_gain=gain; +} + +int RDLogLine::duckDownGain() const +{ + return log_duck_down_gain; +} + + +void RDLogLine::setDuckDownGain(int gain) +{ + log_duck_down_gain=gain; +} + + +int RDLogLine::talkStartPoint() const +{ + return log_talk_start; +} + + +void RDLogLine::setTalkStartPoint(int point) +{ + log_talk_start=point; +} + + +int RDLogLine::talkEndPoint() const +{ + return log_talk_end; +} + + +void RDLogLine::setTalkEndPoint(int point) +{ + log_talk_end=point; +} + + +bool RDLogLine::hookMode() const +{ + return log_hook_mode; +} + + +void RDLogLine::setHookMode(bool state) +{ + log_hook_mode=state; +} + + +int RDLogLine::hookStartPoint() const +{ + return log_hook_start; +} + + +void RDLogLine::setHookStartPoint(int point) +{ + log_hook_start=point; +} + + +int RDLogLine::hookEndPoint() const +{ + return log_hook_end; +} + + +void RDLogLine::setHookEndPoint(int point) +{ + log_hook_end=point; +} + + +RDCart::Type RDLogLine::cartType() const +{ + return log_cart_type; +} + + +void RDLogLine::setCartType(RDCart::Type type) +{ + log_cart_type=type; +} + + +bool RDLogLine::asyncronous() const +{ + return log_asyncronous; +} + + +void RDLogLine::setAsyncronous(bool state) +{ + log_asyncronous=state; +} + + +QString RDLogLine::groupName() const +{ + return log_group_name; +} + + +void RDLogLine::setGroupName(const QString &name) +{ + log_group_name=name; +} + + +QColor RDLogLine::groupColor() const +{ + return log_group_color; +} + + +void RDLogLine::setGroupColor(const QColor &color) +{ + log_group_color=color; +} + + +QString RDLogLine::title() const +{ + return log_title; +} + + +void RDLogLine::setTitle(const QString &title) +{ + log_title=title; +} + + +QString RDLogLine::artist() const +{ + return log_artist; +} + + +QString RDLogLine::publisher() const +{ + return log_publisher; +} + + +void RDLogLine::setPublisher(const QString &pub) +{ + log_publisher=pub; +} + + +QString RDLogLine::composer() const +{ + return log_composer; +} + + +void RDLogLine::setComposer(const QString &composer) +{ + log_composer=composer; +} + + +void RDLogLine::setArtist(const QString &artist) +{ + log_artist=artist; +} + + +QString RDLogLine::album() const +{ + return log_album; +} + + +void RDLogLine::setAlbum(const QString &album) +{ + log_album=album; +} + + +QDate RDLogLine::year() const +{ + return log_year; +} + + +void RDLogLine::setYear(QDate year) +{ + log_year=year; +} + + +QString RDLogLine::isrc() const +{ + return log_isrc; +} + + +void RDLogLine::setIsrc(const QString &string) +{ + log_isrc=string; +} + + +QString RDLogLine::isci() const +{ + return log_isci; +} + + +void RDLogLine::setIsci(const QString &string) +{ + log_isci=string; +} + + +QString RDLogLine::label() const +{ + return log_label; +} + + +void RDLogLine::setLabel(const QString &label) +{ + log_label=label; +} + + +QString RDLogLine::conductor() const +{ + return log_conductor; +} + + +void RDLogLine::setConductor(const QString &cond) +{ + log_conductor=cond; +} + + +QString RDLogLine::songId() const +{ + return log_song_id; +} + + +void RDLogLine::setSongId(const QString &id) +{ + log_song_id=id; +} + + +QString RDLogLine::client() const +{ + return log_client; +} + + +void RDLogLine::setClient(const QString &client) +{ + log_client=client; +} + + +QString RDLogLine::agency() const +{ + return log_agency; +} + + +void RDLogLine::setAgency(const QString &agency) +{ + log_agency=agency; +} + + +QString RDLogLine::outcue() const +{ + return log_outcue; +} + + +void RDLogLine::setOutcue(const QString &outcue) +{ + log_outcue=outcue; +} + + +QString RDLogLine::description() const +{ + return log_description; +} + + +void RDLogLine::setDescription(const QString &desc) +{ + log_description=desc; +} + + +QString RDLogLine::userDefined() const +{ + return log_user_defined; +} + + +void RDLogLine::setUserDefined(const QString &string) +{ + log_user_defined=string; +} + + +QString RDLogLine::cartNotes() const +{ + return log_cart_notes; +} + + +void RDLogLine::setCartNotes(const QString &str) +{ + log_cart_notes=str; +} + + +RDCart::UsageCode RDLogLine::usageCode() const +{ + return log_usage_code; +} + + +void RDLogLine::setUsageCode(RDCart::UsageCode code) +{ + log_usage_code=code; +} + + +unsigned RDLogLine::forcedLength() const +{ + return log_forced_length; +} + + +void RDLogLine::setForcedLength(unsigned len) +{ + log_forced_length=len; +} + + +unsigned RDLogLine::averageSegueLength() const +{ + return log_average_segue_length; +} + + +void RDLogLine::setAverageSegueLength(unsigned len) +{ + log_average_segue_length=len; +} + + +unsigned RDLogLine::cutQuantity() const +{ + return log_cut_quantity; +} + + +void RDLogLine::setCutQuantity(unsigned quan) +{ + log_cut_quantity=quan; +} + + +unsigned RDLogLine::lastCutPlayed() const +{ + return log_last_cut_played; +} + + +void RDLogLine::setLastCutPlayed(unsigned cut) +{ + log_last_cut_played=cut; +} + + +RDCart::PlayOrder RDLogLine::playOrder() const +{ + return log_play_order; +} + + +void RDLogLine::setPlayOrder(RDCart::PlayOrder order) +{ + log_play_order=order; +} + + +bool RDLogLine::enforceLength() const +{ + return log_enforce_length; +} + + +void RDLogLine::setEnforceLength(bool state) +{ + log_enforce_length=state; +} + + +bool RDLogLine::preservePitch() const +{ + return log_preserve_pitch; +} + + +void RDLogLine::setPreservePitch(bool state) +{ + log_preserve_pitch=state; +} + + +QDateTime RDLogLine::startDatetime() const +{ + return log_start_datetime; +} + + +void RDLogLine::setStartDatetime(const QDateTime &datetime) +{ + log_start_datetime=datetime; +} + + +QDateTime RDLogLine::endDatetime() const +{ + return log_end_datetime; +} + + +void RDLogLine::setEndDatetime(const QDateTime &datetime) +{ + log_end_datetime=datetime; +} + + +RDListViewItem *RDLogLine::listViewItem() const +{ + return log_listview; +} + + +void RDLogLine::setListViewItem(RDListViewItem *listview) +{ + log_listview=listview; +} + + +RDLogLine::Type RDLogLine::type() const +{ + return log_type; +} + + +void RDLogLine::setType(RDLogLine::Type type) +{ + log_type=type; +} + + +QString RDLogLine::markerComment() const +{ + return log_marker_comment; +} + + +void RDLogLine::setMarkerComment(const QString &str) +{ + log_marker_comment=str; +} + + +QString RDLogLine::markerLabel() const +{ + return log_marker_label; +} + + +void RDLogLine::setMarkerLabel(const QString &str) +{ + log_marker_label=str; +} + + +int RDLogLine::deck() const +{ + return log_deck; +} + + +void RDLogLine::setDeck(int deck) +{ + log_deck=deck; +} + + +QObject *RDLogLine::playDeck() +{ + return log_play_deck; +} + + +void RDLogLine::setPlayDeck(QObject *deck) +{ + log_play_deck=deck; +} + + +QString RDLogLine::portName() const +{ + return log_port_name; +} + + +void RDLogLine::setPortName(const QString &name) +{ + log_port_name=name; +} + + +QTime RDLogLine::playTime() const +{ + return log_play_time; +} + + +void RDLogLine::setPlayTime(QTime time) +{ + log_play_time=time; +} + + +QTime RDLogLine::extStartTime() const +{ + return log_ext_start_time; +} + + +void RDLogLine::setExtStartTime(QTime time) +{ + log_ext_start_time=time; +} + + +int RDLogLine::extLength() const +{ + return log_ext_length; +} + + +void RDLogLine::setExtLength(int length) +{ + log_ext_length=length; +} + + +QString RDLogLine::extCartName() const +{ + return log_ext_cart_name; +} + + +void RDLogLine::setExtCartName(const QString &name) +{ + log_ext_cart_name=name; +} + + +QString RDLogLine::extData() const +{ + return log_ext_data; +} + + +void RDLogLine::setExtData(const QString &data) +{ + log_ext_data=data; +} + + +QString RDLogLine::extEventId() const +{ + return log_ext_event_id; +} + + +void RDLogLine::setExtEventId(const QString &id) +{ + log_ext_event_id=id; +} + + +QString RDLogLine::extAnncType() const +{ + return log_ext_annc_type; +} + + +void RDLogLine::setExtAnncType(const QString &type) +{ + log_ext_annc_type=type; +} + + +int RDLogLine::cutNumber() const +{ + return log_cut_number; +} + + +void RDLogLine::setCutNumber(int cutnum) +{ + log_cut_number=cutnum; +} + + +QString RDLogLine::cutName() const +{ + return log_cut_name; +} + + +void RDLogLine::setCutName(const QString &cutname) +{ + log_cut_name=cutname; +} + + +int RDLogLine::pauseCard() const +{ + return log_pause_card; +} + + +void RDLogLine::setPauseCard(int card) +{ + log_pause_card=card; +} + + +int RDLogLine::pausePort() const +{ + return log_pause_port; +} + + +void RDLogLine::setPausePort(int port) +{ + log_pause_port=port; +} + + +bool RDLogLine::timescalingActive() const +{ + return log_timescaling_active; +} + + +void RDLogLine::setTimescalingActive(bool state) +{ + log_timescaling_active=state; +} + + +int RDLogLine::effectiveLength() const +{ + if(log_cut_number<0) { + return log_forced_length; + } + return log_effective_length; +} + + +int RDLogLine::talkLength() const +{ + return log_talk_length; +} + + +int RDLogLine::segueLength(RDLogLine::TransType next_trans) +{ + switch(type()) { + case RDLogLine::Cart: + switch(next_trans) { + case RDLogLine::Stop: + case RDLogLine::Play: + return log_effective_length; + + case RDLogLine::Segue: + if(segueStartPoint(RDLogLine::AutoPointer)<0) { + return log_effective_length; + } + return segueStartPoint(RDLogLine::AutoPointer)- + startPoint(RDLogLine::AutoPointer); + + default: + break; + } + break; + + case RDLogLine::Macro: + return log_effective_length; + + case RDLogLine::Marker: + return 0; + + default: + break; + } + return 0; +} + + +int RDLogLine::segueTail(RDLogLine::TransType next_trans) +{ + switch(type()) { + case RDLogLine::Cart: + switch(next_trans) { + case RDLogLine::Stop: + case RDLogLine::Play: + return 0; + + case RDLogLine::Segue: + return segueEndPoint(RDLogLine::AutoPointer)- + segueStartPoint(RDLogLine::AutoPointer); + + default: + break; + } + break; + + default: + return 0; + } + return 0; +} + + +int RDLogLine::forcedStop() const +{ + return log_forced_stop; +} + + +bool RDLogLine::hasCustomTransition() const +{ + return log_has_custom_transition; +} + + +void RDLogLine::setHasCustomTransition(bool state) +{ + log_has_custom_transition=state; +} + + +unsigned RDLogLine::playPosition() const +{ + return log_play_position; +} + + +void RDLogLine::setPlayPosition(unsigned pos) +{ + log_play_position=pos; +} + + +bool RDLogLine::playPositionChanged() const +{ + return log_play_position_changed; +} + + +void RDLogLine::setPlayPositionChanged(bool state) +{ + log_play_position_changed=state; +} + + +bool RDLogLine::nowNextEnabled() const +{ + return log_now_next_enabled; +} + + +void RDLogLine::setNowNextEnabled(bool state) +{ + log_now_next_enabled=state; +} + + +bool RDLogLine::useEventLength() const +{ + return log_use_event_length; +} + + +void RDLogLine::setUseEventLength(bool state) +{ + log_use_event_length=state; +} + + +int RDLogLine::eventLength() const +{ + return log_event_length; +} + + +void RDLogLine::setEventLength(int msec) +{ + log_event_length=msec; +} + + +QString RDLogLine::linkEventName() const +{ + return log_link_event_name; +} + + +void RDLogLine::setLinkEventName(const QString &name) +{ + log_link_event_name=name; +} + + +QTime RDLogLine::linkStartTime() const +{ + return log_link_start_time; +} + + +void RDLogLine::setLinkStartTime(const QTime &time) +{ + log_link_start_time=time; +} + + +int RDLogLine::linkLength() const +{ + return log_link_length; +} + + +void RDLogLine::setLinkLength(int msecs) +{ + log_link_length=msecs; +} + + +int RDLogLine::linkStartSlop() const +{ + return log_link_start_slop; +} + + +void RDLogLine::setLinkStartSlop(int msecs) +{ + log_link_start_slop=msecs; +} + + +int RDLogLine::linkEndSlop() const +{ + return log_link_end_slop; +} + + +void RDLogLine::setLinkEndSlop(int msecs) +{ + log_link_end_slop=msecs; +} + + +int RDLogLine::linkId() const +{ + return log_link_id; +} + + +void RDLogLine::setLinkId(int id) +{ + log_link_id=id; +} + + +bool RDLogLine::linkEmbedded() const +{ + return log_link_embedded; +} + + +void RDLogLine::setLinkEmbedded(bool state) +{ + log_link_embedded=state; +} + + +RDLogLine::StartSource RDLogLine::startSource() const +{ + return log_start_source; +} + + +void RDLogLine::setStartSource(RDLogLine::StartSource src) +{ + log_start_source=src; +} + + +QString RDLogLine::resolveWildcards(QString pattern) +{ + pattern.replace("%n",QString().sprintf("%06u",cartNumber())); + pattern.replace("%h",QString().sprintf("%d",effectiveLength())); + pattern.replace("%g",groupName()); + pattern.replace("%t",title()); + pattern.replace("%a",artist()); + pattern.replace("%l",album()); + pattern.replace("%y",year().toString("yyyy")); + pattern.replace("%b",label()); + pattern.replace("%r",conductor()); + pattern.replace("%s",songId()); + pattern.replace("%c",client()); + pattern.replace("%e",agency()); + pattern.replace("%m",composer()); + pattern.replace("%p",publisher()); + pattern.replace("%u",userDefined()); + + return pattern; +} + + +RDLogLine::State RDLogLine::setEvent(int mach,RDLogLine::TransType next_type, + bool timescale,int len) +{ + RDCart *cart; + RDMacroEvent *rml_event; + QString sql; + RDSqlQuery *q; + double time_ratio=1.0; + + switch(log_type) { + case RDLogLine::Cart: + cart=new RDCart(log_cart_number); + if(!cart->exists()) { + delete cart; +#ifndef WIN32 + syslog(LOG_USER|LOG_WARNING,"RDLogLine::setEvent(): no such cart, CART=%06u",log_cart_number); +#endif // WIN32 + log_state=RDLogLine::NoCart; + return RDLogLine::NoCart; + } + cart->selectCut(&log_cut_name); + if(log_cut_name.isEmpty()) { + delete cart; +#ifndef WIN32 + // syslog(LOG_USER|LOG_WARNING,"RDLogLine::setEvent(): RDCut::selectCut() failed, CART=%06u",log_cart_number); +#endif // WIN32 + log_state=RDLogLine::NoCut; + return RDLogLine::NoCut; + } + log_cut_number=log_cut_name.right(3).toInt(); + sql=QString().sprintf("select LENGTH,START_POINT,END_POINT,\ + SEGUE_START_POINT,SEGUE_END_POINT,\ + SEGUE_GAIN,\ + TALK_START_POINT,TALK_END_POINT,\ + HOOK_START_POINT,HOOK_END_POINT,\ + OUTCUE,ISRC,ISCI,DESCRIPTION from CUTS\ + where CUT_NAME=\"%s\"", + (const char *)log_cut_name); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + delete cart; +#ifndef WIN32 + syslog(LOG_USER|LOG_WARNING,"RDLogLine::setEvent(): no cut record found, SQL=%s",(const char *)sql); +#endif // WIN32 + log_state=RDLogLine::NoCut; + return RDLogLine::NoCut; + } + if(q->value(0).toInt()==0) { + delete q; + delete cart; +#ifndef WIN32 + syslog(LOG_USER|LOG_WARNING,"RDLogLine::setEvent(): zero length cut audio, SQL=%s",(const char *)sql); +#endif // WIN32 + log_state=RDLogLine::NoCut; + return RDLogLine::NoCut; + } + if(timescale) { + if(len>0) { + log_effective_length=len; + log_forced_length=len; + } + else { + if(log_hook_mode&& + (q->value(8).toInt()>=0)&&(q->value(9).toInt()>=0)) { + log_effective_length=q->value(9).toInt()-q->value(8).toInt(); + log_forced_length=log_effective_length; + time_ratio=1.0; + timescale=false; + } + else { + log_effective_length=cart->forcedLength(); + time_ratio=(double)log_forced_length/ + (q->value(2).toDouble()-q->value(1).toDouble()); + if(((1.0/time_ratio)<RD_TIMESCALE_MIN)|| + ((1.0/time_ratio)>RD_TIMESCALE_MAX)) { + timescale=false; + } + } + } + } + if(timescale) { + log_start_point[0]=(int)(q->value(1).toDouble()*time_ratio); + log_end_point[0]=(int)(q->value(2).toDouble()*time_ratio); + if(q->value(3).toInt()>=0) { + log_segue_start_point[0]=(int)(q->value(3).toDouble()*time_ratio); + log_segue_end_point[0]=(int)(q->value(4).toDouble()*time_ratio); + } + else { + log_segue_start_point[0]=-1; + log_segue_end_point[0]=-1; + } + if(log_talk_start>=0) { + log_talk_start=(int)((double)log_talk_start*time_ratio); + log_talk_end=(int)(q->value(7).toDouble()*time_ratio); + } + else { + log_talk_start=-1; + log_talk_end=-1; + } + log_talk_length=log_talk_end-log_talk_start; + } + else { + if(log_hook_mode&& + (q->value(8).toInt()>=0)&&(q->value(9).toInt()>=0)) { + log_start_point[0]=q->value(8).toInt(); + log_end_point[0]=q->value(9).toInt(); + log_segue_start_point[0]=-1; + log_segue_end_point[0]=-1; + log_talk_start=-1; + log_talk_end=-1; + } + else { + log_start_point[0]=q->value(1).toInt(); + log_end_point[0]=q->value(2).toInt(); + if(log_start_point[RDLogLine::LogPointer]>=0 || + log_end_point[RDLogLine::LogPointer]>=0) { + log_effective_length=log_end_point[RDLogLine::LogPointer]- + log_start_point[RDLogLine::LogPointer]; + } + else { + log_effective_length=q->value(0).toUInt(); + } + log_segue_start_point[0]=q->value(3).toInt(); + log_segue_end_point[0]=q->value(4).toInt(); + log_talk_start=q->value(6).toInt(); + log_talk_end=q->value(7).toInt(); + } + log_hook_start=q->value(8).toInt(); + log_hook_end=q->value(9).toInt(); + if(log_talk_end>log_end_point[RDLogLine::LogPointer] && + log_end_point[RDLogLine::LogPointer]>=0) { + log_talk_end=log_end_point[RDLogLine::LogPointer]; + } + if(log_talk_end<log_start_point[RDLogLine::LogPointer]) { + log_talk_end=0; + log_talk_start=0; + } + else { + if(log_talk_start<log_start_point[RDLogLine::LogPointer]) { + log_talk_start=0; + log_talk_end-=log_start_point[RDLogLine::LogPointer]; + } + if(log_talk_start>log_end_point[RDLogLine::LogPointer] && + log_end_point[RDLogLine::LogPointer]>=0) { + log_talk_start=0; + log_talk_end=0; + } + } + log_talk_length=log_talk_end-log_talk_start; + } + if(segueStartPoint(RDLogLine::AutoPointer)<0) { + log_average_segue_length=cart->averageSegueLength(); + } + else { + log_average_segue_length=segueStartPoint(RDLogLine::AutoPointer)- + startPoint(RDLogLine::AutoPointer); + } + log_outcue=q->value(10).toString(); + log_isrc=q->value(11).toString(); + log_isci=q->value(12).toString(); + log_description=q->value(13).toString(); + log_segue_gain_cut=q->value(5).toInt(); + delete q; + delete cart; + break; + + case RDLogLine::Macro: + cart=new RDCart(log_cart_number); + log_effective_length=cart->forcedLength(); + log_average_segue_length=log_effective_length; + log_forced_stop=false; + rml_event=new RDMacroEvent(); + rml_event->load(cart->number()); + for(int i=0;i<rml_event->size();i++) { + if(rml_event->command(i)->command()==RDMacro::LL) { + if(rml_event->command(i)->arg(0).toInt()==mach) { + log_forced_stop=true; + } + } + } + log_start_point[0]=-1; + log_end_point[0]=-1; + log_segue_start_point[0]=-1; + log_segue_end_point[0]=-1; + log_talk_length=0; + log_talk_start=-1; + log_talk_end=-1; + log_segue_gain_cut=0; + delete rml_event; + delete cart; + break; + + case RDLogLine::Marker: + case RDLogLine::Track: + log_cut_number=0; + log_cut_name=""; + log_effective_length=0; + log_average_segue_length=0; + log_forced_stop=false; + log_start_point[0]=-1; + log_end_point[0]=-1; + log_segue_start_point[0]=-1; + log_segue_end_point[0]=-1; + log_talk_length=0; + log_talk_start=-1; + log_talk_end=-1; + log_segue_gain_cut=0; + break; + + default: + break; + } + return RDLogLine::Ok; +} + + +void RDLogLine::loadCart(int cartnum,RDLogLine::TransType next_type,int mach, + bool timescale,RDLogLine::TransType type,int len) +{ + QString sql=QString().sprintf("select CART.TYPE,CART.GROUP_NAME,CART.TITLE,\ + CART.ARTIST,CART.ALBUM,CART.YEAR,CART.ISRC,\ + CART.LABEL,CART.CLIENT,CART.AGENCY,\ + CART.USER_DEFINED,CART.CONDUCTOR,CART.SONG_ID,\ + CART.FORCED_LENGTH,\ + CART.CUT_QUANTITY,CART.LAST_CUT_PLAYED,\ + CART.PLAY_ORDER,CART.START_DATETIME,\ + CART.END_DATETIME,CART.ENFORCE_LENGTH,\ + CART.PRESERVE_PITCH,GROUPS.ENABLE_NOW_NEXT,\ + CART.ASYNCRONOUS,CART.PUBLISHER,\ + CART.COMPOSER,CART.USAGE_CODE,\ + CART.AVERAGE_SEGUE_LENGTH,CART.NOTES,\ + GROUPS.COLOR \ + from CART left join GROUPS on\ + CART.GROUP_NAME=GROUPS.NAME\ + where (CART.NUMBER=%d)", + cartnum); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + log_state=RDLogLine::NoCart; + return; + } + log_cart_number=cartnum; + log_cart_type=(RDCart::Type)q->value(0).toInt(); + switch((RDCart::Type)q->value(0).toInt()) { + case RDCart::Audio: + log_type=RDLogLine::Cart; + break; + + case RDCart::Macro: + log_type=RDLogLine::Macro; + break; + + default: + break; + } + log_group_name=q->value(1).toString(); + log_title=q->value(2).toString(); + log_artist=q->value(3).toString(); + log_album=q->value(4).toString(); + log_year=q->value(5).toDate(); + log_isrc=q->value(6).toString(); + log_label=q->value(7).toString(); + log_client=q->value(8).toString(); + log_agency=q->value(9).toString(); + log_user_defined=q->value(10).toString(); + log_conductor=q->value(11).toString(); + log_song_id=q->value(12).toString(); + log_cut_quantity=q->value(14).toUInt(); + log_last_cut_played=q->value(15).toUInt(); + log_play_order=(RDCart::PlayOrder)q->value(16).toInt(); + log_start_datetime=q->value(17).toDateTime(); + log_end_datetime=q->value(18).toDateTime(); + log_preserve_pitch=RDBool(q->value(20).toString()); + if(len<0) { + log_forced_length=q->value(13).toUInt(); + log_enforce_length=RDBool(q->value(19).toString()); + } + else { + log_forced_length=len; + log_enforce_length=true; + } + log_now_next_enabled=RDBool(q->value(21).toString()); + log_asyncronous=RDBool(q->value(22).toString()); + log_publisher=q->value(23).toString(); + log_composer=q->value(24).toString(); + log_usage_code=(RDCart::UsageCode)q->value(25).toInt(); + log_average_segue_length=q->value(26).toInt(); + log_cart_notes=q->value(27).toString(); + log_group_color=QColor(q->value(28).toString()); + log_play_source=RDLogLine::UnknownSource; + if(type!=RDLogLine::NoTrans) { + log_trans_type=type; + } + delete q; + log_state=setEvent(mach,next_type,timescale); + log_timescaling_active=log_enforce_length&×cale; +} + + +void RDLogLine::refreshPointers() +{ + if(log_cut_name.isEmpty()) { + return; + } + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select START_POINT,END_POINT,\ + SEGUE_START_POINT,SEGUE_END_POINT,\ + TALK_START_POINT,TALK_END_POINT,\ + FADEUP_POINT,FADEDOWN_POINT,\ + HOOK_START_POINT,HOOK_END_POINT from CUTS\ + where CUT_NAME=\"%s\"", + (const char *)log_cut_name); + q=new RDSqlQuery(sql); + if(q->first()) { + log_start_point[RDLogLine::CartPointer]=q->value(0).toInt(); + log_end_point[RDLogLine::CartPointer]=q->value(1).toInt(); + log_segue_start_point[RDLogLine::CartPointer]=q->value(2).toInt(); + log_segue_end_point[RDLogLine::CartPointer]=q->value(3).toInt(); + log_talk_start=q->value(4).toInt(); + log_talk_end=q->value(5).toInt(); + log_talk_length=log_talk_end-log_talk_start; + log_fadeup_point[RDLogLine::CartPointer]=q->value(6).toInt(); + log_fadedown_point[RDLogLine::CartPointer]=q->value(7).toInt(); + log_hook_start=q->value(8).toInt(); + log_hook_end=q->value(9).toInt(); + } + delete q; +} + + +QString RDLogLine::xml(int line) const +{ + QString ret; +#ifndef WIN32 + ret+=" <logLine>\n"; + ret+=" "+RDXmlField("line",line); + ret+=" "+RDXmlField("id",id()); + ret+=" "+RDXmlField("type",RDLogLine::typeText(type())); + ret+=" "+RDXmlField("cartType",RDCart::typeText(cartType())); + ret+=" "+RDXmlField("cartNumber",cartNumber()); + ret+=" "+RDXmlField("cutNumber",cutNumber()); + ret+=" "+RDXmlField("groupName",groupName()); + ret+=" "+RDXmlField("groupColor",groupColor().name()); + ret+=" "+RDXmlField("title",title()); + ret+=" "+RDXmlField("artist",artist()); + ret+=" "+RDXmlField("publisher",publisher()); + ret+=" "+RDXmlField("composer",composer()); + ret+=" "+RDXmlField("album",album()); + ret+=" "+RDXmlField("label",label()); + if(year().isValid()) { + ret+=" "+RDXmlField("year",year().year()); + } + else { + ret+=" "+RDXmlField("year"); + } + ret+=" "+RDXmlField("client",client()); + ret+=" "+RDXmlField("agency",agency()); + ret+=" "+RDXmlField("userDefined",userDefined()); + ret+=" "+RDXmlField("usageCode",usageCode()); + ret+=" "+RDXmlField("enforceLength",enforceLength()); + ret+=" "+RDXmlField("forcedLength",RDGetTimeLength(forcedLength(),true)); + ret+=" "+RDXmlField("evergreen",evergreen()); + ret+=" "+RDXmlField("source",RDLogLine::sourceText(source())); + ret+=" "+RDXmlField("timeType",RDLogLine::timeTypeText(timeType())); + if(startTime(RDLogLine::Logged).isValid()&& + (!startTime(RDLogLine::Logged).isNull())) { + ret+=" "+RDXmlField("startTime",startTime(RDLogLine::Logged). + toString("hh:mm:ss.zzz")); + } + else { + ret+=" "+RDXmlField("startTime"); + } + ret+=" "+RDXmlField("transitionType",RDLogLine::transText(transType())); + ret+=" "+RDXmlField("cutQuantity",cutQuantity()); + ret+=" "+RDXmlField("lastCutPlayed",lastCutPlayed()); + ret+=" "+RDXmlField("markerComment",markerComment()); + ret+=" "+RDXmlField("markerLabel",markerLabel()); + + ret+=" "+RDXmlField("originUser",originUser()); + ret+=" "+RDXmlField("originDateTime",originDateTime()); + ret+=" "+RDXmlField("startPoint",startPoint(RDLogLine::CartPointer), + "src=\"cart\""); + ret+=" "+RDXmlField("startPoint",startPoint(RDLogLine::LogPointer), + "src=\"log\""); + ret+=" "+RDXmlField("endPoint",endPoint(RDLogLine::CartPointer), + "src=\"cart\""); + ret+=" "+RDXmlField("endPoint",endPoint(RDLogLine::LogPointer), + "src=\"log\""); + ret+=" "+RDXmlField("segueStartPoint", + segueStartPoint(RDLogLine::CartPointer), + "src=\"cart\""); + ret+=" "+RDXmlField("segueStartPoint", + segueStartPoint(RDLogLine::LogPointer),"src=\"log\""); + ret+=" "+RDXmlField("segueEndPoint", + segueEndPoint(RDLogLine::CartPointer), + "src=\"cart\""); + ret+=" "+RDXmlField("segueEndPoint", + segueEndPoint(RDLogLine::LogPointer),"src=\"log\""); + ret+=" "+RDXmlField("segueGain",segueGain()); + ret+=" "+RDXmlField("fadeupPoint", + fadeupPoint(RDLogLine::CartPointer),"src=\"cart\""); + ret+=" "+RDXmlField("fadeupPoint", + fadeupPoint(RDLogLine::LogPointer),"src=\"log\""); + ret+=" "+RDXmlField("fadeupGain",fadeupGain()); + ret+=" "+RDXmlField("fadedownPoint", + fadedownPoint(RDLogLine::CartPointer),"src=\"cart\""); + ret+=" "+RDXmlField("fadedownPoint", + fadedownPoint(RDLogLine::LogPointer),"src=\"log\""); + ret+=" "+RDXmlField("duckUpGain",duckUpGain()); + ret+=" "+RDXmlField("duckDownGain",duckDownGain()); + ret+=" "+RDXmlField("talkStartPoint",talkStartPoint()); + ret+=" "+RDXmlField("talkEndPoint",talkEndPoint()); + ret+=" "+RDXmlField("hookMode",hookMode()); + ret+=" "+RDXmlField("hookStartPoint",hookStartPoint()); + ret+=" "+RDXmlField("hookEndPoint",hookEndPoint()); + + ret+=" </logLine>\n"; +#endif // WIN32 + return ret; +} + + +QString RDLogLine::resolveWildcards(unsigned cartnum,const QString &pattern) +{ + RDLogLine logline; + logline.loadCart(cartnum,RDLogLine::Play,0,false); + return logline.resolveWildcards(pattern); +} + + +QString RDLogLine::startSourceText(RDLogLine::StartSource src) +{ + switch(src) { + case RDLogLine::StartUnknown: + return QObject::tr("Unknown"); + + case RDLogLine::StartManual: + return QObject::tr("Manual"); + + case RDLogLine::StartPlay: + return QObject::tr("Play"); + + case RDLogLine::StartSegue: + return QObject::tr("Segue"); + + case RDLogLine::StartTime: + return QObject::tr("Time"); + + case RDLogLine::StartPanel: + return QObject::tr("Panel"); + + case RDLogLine::StartMacro: + return QObject::tr("Macro"); + + case RDLogLine::StartChannel: + return QObject::tr("Channel"); + } + return QObject::tr("Unknown"); +} + + +QString RDLogLine::transText(RDLogLine::TransType trans) +{ + switch(trans) { + case RDLogLine::Play: + return QObject::tr("PLAY"); + + case RDLogLine::Segue: + return QObject::tr("SEGUE"); + + case RDLogLine::Stop: + return QObject::tr("STOP"); + + case RDLogLine::NoTrans: + return QObject::tr("UNKNOWN"); + } + return QObject::tr("UNKNOWN"); +} + + +QString RDLogLine::typeText(RDLogLine::Type type) +{ + switch(type) { + case RDLogLine::Cart: + return QObject::tr("Audio"); + + case RDLogLine::Marker: + return QObject::tr("Marker"); + + case RDLogLine::Macro: + return QObject::tr("Macro"); + + case RDLogLine::OpenBracket: + return QObject::tr("Open Bracket"); + + case RDLogLine::CloseBracket: + return QObject::tr("Close Bracket"); + + case RDLogLine::Chain: + return QObject::tr("ChainTo"); + + case RDLogLine::Track: + return QObject::tr("Track"); + + case RDLogLine::MusicLink: + case RDLogLine::TrafficLink: + return QObject::tr("Link"); + + case RDLogLine::UnknownType: + return QObject::tr("Unknown"); + } + return QObject::tr("Unknown"); +} + + +QString RDLogLine::timeTypeText(RDLogLine::TimeType type) +{ + QString ret=QObject::tr("Unknown"); + + switch(type) { + case RDLogLine::Relative: + ret=QObject::tr("Relative"); + break; + + case RDLogLine::Hard: + ret=QObject::tr("Hard"); + break; + } + + return ret; +} + + +QString RDLogLine::sourceText(RDLogLine::Source src) +{ + switch(src) { + case RDLogLine::Manual: + return QObject::tr("Manual"); + + case RDLogLine::Traffic: + return QObject::tr("Traffic"); + + case RDLogLine::Music: + return QObject::tr("Music"); + + case RDLogLine::Template: + return QObject::tr("RDLogManager"); + + case RDLogLine::Tracker: + return QObject::tr("Tracker"); + } + return QObject::tr("Unknown"); +} diff --git a/lib/rdlog_line.h b/lib/rdlog_line.h new file mode 100644 index 00000000..037fccfe --- /dev/null +++ b/lib/rdlog_line.h @@ -0,0 +1,374 @@ +// rdlog_line.h +// +// A container class for a Rivendell Log Line. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlog_line.h,v 1.85.8.10.2.1 2014/05/20 01:45:16 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDLOG_LINE_H +#define RDLOG_LINE_H + +#include <qdatetime.h> +#include <qobject.h> +#include <qcolor.h> + +#include <rdcart.h> +#include <rdlistviewitem.h> + + +class RDLogLine +{ + public: + enum StartTimeType {Imported=0,Logged=1,Predicted=2,Actual=3,Initial=4}; + enum TimeType {Relative=0,Hard=1}; + enum TransType {Play=0,Segue=1,Stop=2,NoTrans=255}; + enum TransEdge {AllTrans=0,LeadingTrans=1,TrailingTrans=2}; + enum Source {Manual=0,Traffic=1,Music=2,Template=3,Tracker=4}; + enum Status {Scheduled=1,Playing=2,Auditioning=3,Finished=4, + Finishing=5,Paused=6}; + enum State {Ok=0,NoCart=1,NoCut=2}; + enum Type {Cart=0,Marker=1,Macro=2,OpenBracket=3,CloseBracket=4,Chain=5, + Track=6,MusicLink=7,TrafficLink=8,UnknownType=9}; + enum StartSource {StartUnknown=0,StartManual=1,StartPlay=2,StartSegue=3, + StartTime=4,StartPanel=5,StartMacro=6,StartChannel=7}; + enum PlaySource {UnknownSource=0,MainLog=1,AuxLog1=2,AuxLog2=3,SoundPanel=4, + CartSlot=5}; + enum PointerSource {CartPointer=0,LogPointer=1,AutoPointer=2}; + RDLogLine(); + RDLogLine(unsigned cartnum); + void clear(); + void clearExternalData(); + void clearTrackData(RDLogLine::TransEdge edge); + int id() const; + void setId(int id); + RDLogLine::Status status() const; + void setStatus(RDLogLine::Status stat); + RDLogLine::State state() const; + void setState(RDLogLine::State state); + RDCart::Validity validity() const; + RDCart::Validity validity(const QDateTime &datetime) const; + void setValidity(RDCart::Validity valid); + unsigned pass() const; + void incrementPass(); + void clearPass(); + bool zombified() const; + void setZombified(bool state); + bool evergreen() const; + void setEvergreen(bool state); + RDLogLine::Source source() const; + void setSource(RDLogLine::Source src); + unsigned cartNumber() const; + void setCartNumber(unsigned cart); + QTime startTime(RDLogLine::StartTimeType type) const; + void setStartTime(RDLogLine::StartTimeType type,QTime time); + int graceTime() const; + void setGraceTime(int time); + RDLogLine::TimeType timeType() const; + void setTimeType(RDLogLine::TimeType type); + QString originUser() const; + void setOriginUser(const QString &username); + QDateTime originDateTime() const; + void setOriginDateTime(const QDateTime &datetime); + RDLogLine::TransType transType() const; + void setTransType(RDLogLine::TransType type); + int startPoint(PointerSource ptr=RDLogLine::AutoPointer) const; + void setStartPoint(int point,PointerSource ptr); + int endPoint(PointerSource ptr=RDLogLine::AutoPointer) const; + void setEndPoint(int point,PointerSource ptr); + int segueStartPoint(PointerSource ptr=RDLogLine::AutoPointer) const; + void setSegueStartPoint(int point,PointerSource ptr); + int segueEndPoint(PointerSource ptr=RDLogLine::AutoPointer) const; + void setSegueEndPoint(int point,PointerSource ptr); + int segueGain() const; + void setSegueGain(int gain); + int fadeupPoint(PointerSource ptr=RDLogLine::AutoPointer) const; + void setFadeupPoint(int point,PointerSource ptr); + int fadeupGain() const; + void setFadeupGain(int gain); + int fadedownPoint(PointerSource ptr=RDLogLine::AutoPointer) const; + void setFadedownPoint(int point,PointerSource ptr); + int fadedownGain() const; + void setFadedownGain(int gain); + int duckUpGain() const; + void setDuckUpGain(int gain); + int duckDownGain() const; + void setDuckDownGain(int gain); + int talkStartPoint() const; + void setTalkStartPoint(int point); + int talkEndPoint() const; + void setTalkEndPoint(int point); + bool hookMode() const; + void setHookMode(bool state); + int hookStartPoint() const; + void setHookStartPoint(int point); + int hookEndPoint() const; + void setHookEndPoint(int point); + RDCart::Type cartType() const; + void setCartType(RDCart::Type type); + bool asyncronous() const; + void setAsyncronous(bool state); + QString groupName() const; + void setGroupName(const QString &name); + QColor groupColor() const; + void setGroupColor(const QColor &color); + QString title() const; + void setTitle(const QString &title); + QString artist() const; + void setArtist(const QString &artist); + QString publisher() const; + void setPublisher(const QString &pub); + QString composer() const; + void setComposer(const QString &composer); + QString album() const; + void setAlbum(const QString &album); + QDate year() const; + void setYear(QDate year); + QString isrc() const; + void setIsrc(const QString &string); + QString isci() const; + void setIsci(const QString &string); + QString label() const; + void setLabel(const QString &label); + QString conductor() const; + void setConductor(const QString &cond); + QString songId() const; + void setSongId(const QString &id); + QString client() const; + void setClient(const QString &client); + QString agency() const; + void setAgency(const QString &agency); + QString outcue() const; + void setOutcue(const QString &outcue); + QString description() const; + void setDescription(const QString &desc); + QString userDefined() const; + void setUserDefined(const QString &string); + QString cartNotes() const; + void setCartNotes(const QString &str); + RDCart::UsageCode usageCode() const; + void setUsageCode(RDCart::UsageCode code); + unsigned forcedLength() const; + void setForcedLength(unsigned len); + unsigned averageSegueLength() const; + void setAverageSegueLength(unsigned len); + unsigned cutQuantity() const; + void setCutQuantity(unsigned quan); + unsigned lastCutPlayed() const; + void setLastCutPlayed(unsigned cut); + RDCart::PlayOrder playOrder() const; + void setPlayOrder(RDCart::PlayOrder order); + bool enforceLength() const; + void setEnforceLength(bool state); + bool preservePitch() const; + void setPreservePitch(bool state); + QDateTime startDatetime() const; + void setStartDatetime(const QDateTime &datetime); + QDateTime endDatetime() const; + void setEndDatetime(const QDateTime &datetime); + RDListViewItem *listViewItem() const; + void setListViewItem(RDListViewItem *); + RDLogLine::Type type() const; + void setType(RDLogLine::Type type); + QString markerComment() const; + void setMarkerComment(const QString &str); + QString markerLabel() const; + void setMarkerLabel(const QString &str); + int deck() const; + void setDeck(int deck); + QObject *playDeck(); + void setPlayDeck(QObject *deck); + QString portName() const; + void setPortName(const QString &name); + QTime playTime() const; + void setPlayTime(QTime time); + QTime extStartTime() const; + void setExtStartTime(QTime time); + int extLength() const; + void setExtLength(int length); + QString extCartName() const; + void setExtCartName(const QString &name); + QString extData() const; + void setExtData(const QString &data); + QString extEventId() const; + void setExtEventId(const QString &id); + QString extAnncType() const; + void setExtAnncType(const QString &type); + int cutNumber() const; + void setCutNumber(int cutnum); + QString cutName() const; + void setCutName(const QString &cutname); + int pauseCard() const; + void setPauseCard(int card); + int pausePort() const; + void setPausePort(int port); + bool timescalingActive() const; + void setTimescalingActive(bool state); + int effectiveLength() const; + int talkLength() const; + int segueLength(RDLogLine::TransType next_trans); + int segueTail(RDLogLine::TransType next_trans); + int forcedStop() const; + bool hasCustomTransition() const; + void setHasCustomTransition(bool state); + unsigned playPosition() const; + void setPlayPosition(unsigned pos); + bool playPositionChanged() const; + void setPlayPositionChanged(bool state); + bool nowNextEnabled() const; + void setNowNextEnabled(bool state); + bool useEventLength() const; + void setUseEventLength(bool state); + int eventLength() const; + void setEventLength(int msec); + QString linkEventName() const; + void setLinkEventName(const QString &name); + QTime linkStartTime() const; + void setLinkStartTime(const QTime &time); + int linkLength() const; + void setLinkLength(int msecs); + int linkStartSlop() const; + void setLinkStartSlop(int msecs); + int linkEndSlop() const; + void setLinkEndSlop(int msecs); + int linkId() const; + void setLinkId(int id); + bool linkEmbedded() const; + void setLinkEmbedded(bool state); + RDLogLine::StartSource startSource() const; + void setStartSource(RDLogLine::StartSource src); + QString resolveWildcards(QString pattern); + RDLogLine::State setEvent(int mach,RDLogLine::TransType next_type, + bool timescale,int len=-1); + void loadCart(int cartnum,RDLogLine::TransType next_type,int mach, + bool timescale,RDLogLine::TransType type=RDLogLine::NoTrans, + int len=-1); + void refreshPointers(); + QString xml(int line) const; + static QString resolveWildcards(unsigned cartnum,const QString &pattern); + static QString startSourceText(RDLogLine::StartSource src); + static QString transText(RDLogLine::TransType trans); + static QString typeText(RDLogLine::Type type); + static QString timeTypeText(RDLogLine::TimeType type); + static QString sourceText(RDLogLine::Source src); + + private: + int log_id; + RDLogLine::Status log_status; + RDLogLine::State log_state; + RDLogLine::Source log_source; + RDCart::Validity log_validity; + unsigned log_pass; + unsigned log_cart_number; + QTime log_start_time[5]; + RDLogLine::TimeType log_time_type; + QString log_origin_user; + QDateTime log_origin_datetime; + RDLogLine::TransType log_trans_type; + int log_start_point[2]; + int log_end_point[2]; + int log_segue_start_point[2]; + int log_segue_end_point[2]; + int log_segue_gain; + int log_segue_gain_cut; + int log_fadeup_point[2]; + int log_fadeup_gain; + int log_fadedown_point[2]; + int log_fadedown_gain; + int log_duck_up_gain; + int log_duck_down_gain; + bool log_hook_mode; + int log_hook_start; + int log_hook_end; + RDCart::Type log_cart_type; + QString log_group_name; + QColor log_group_color; + QString log_title; + QString log_artist; + QString log_album; + QString log_publisher; + QString log_composer; + QString log_isrc; + QString log_isci; + QDate log_year; + QString log_label; + QString log_conductor; + QString log_song_id; + QString log_client; + QString log_agency; + QString log_outcue; + QString log_description; + QString log_user_defined; + QString log_cart_notes; + RDCart::UsageCode log_usage_code; + unsigned log_forced_length; + unsigned log_cut_quantity; + unsigned log_last_cut_played; + RDCart::PlayOrder log_play_order; + bool log_enforce_length; + bool log_preserve_pitch; + QDateTime log_start_datetime; + QDateTime log_end_datetime; + int log_deck; + QTime log_play_time; + int log_cut_number; + int log_effective_length; + int log_talk_start; + int log_talk_end; + int log_talk_length; + unsigned log_play_position; + RDLogLine::Type log_type; + QString log_marker_comment; + QString log_marker_label; + QTime log_marker_post_time; + RDListViewItem *log_listview; + QString log_port_name; + int log_grace_time; + bool log_forced_stop; + QObject *log_play_deck; + bool log_play_position_changed; + bool log_evergreen; + QTime log_ext_start_time; + int log_ext_length; + int log_average_segue_length; + QString log_ext_cart_name; + QString log_ext_data; + QString log_ext_event_id; + QString log_ext_annc_type; + int log_pause_card; + int log_pause_port; + bool log_now_next_enabled; + PlaySource log_play_source; + StartSource log_start_source; + bool log_zombified; + bool log_timescaling_active; + bool log_asyncronous; + QString log_cut_name; + bool log_has_custom_transition; + bool log_use_event_length; + int log_event_length; + QString log_link_event_name; + QTime log_link_start_time; + int log_link_length; + int log_link_start_slop; + int log_link_end_slop; + int log_link_id; + bool log_link_embedded; +}; + + +#endif diff --git a/lib/rdlogedit_conf.cpp b/lib/rdlogedit_conf.cpp new file mode 100644 index 00000000..b47e33d2 --- /dev/null +++ b/lib/rdlogedit_conf.cpp @@ -0,0 +1,352 @@ +// rdlogedit_conf.cpp +// +// Abstract an RDLogedit Configuration. +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlogedit_conf.cpp,v 1.12.8.1 2014/01/08 18:14:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +#include <rddb.h> +#include <rdconf.h> +#include <rdlogedit_conf.h> +#include <rdescape_string.h> + +// +// Global Classes +// +RDLogeditConf::RDLogeditConf(const QString &station) +{ + QString sql; + RDSqlQuery *q; + + lib_station=station; + + sql=QString().sprintf("select ID from RDLOGEDIT where STATION=\"%s\"", + (const char *)RDEscapeString(lib_station)); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + sql=QString().sprintf("insert into RDLOGEDIT set STATION=\"%s\"", + (const char *)RDEscapeString(lib_station)); + q=new RDSqlQuery(sql); + } + delete q; +} + + +QString RDLogeditConf::station() const +{ + return lib_station; +} + + +int RDLogeditConf::inputCard() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"INPUT_CARD").toInt(); +} + + +int RDLogeditConf::inputPort() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"INPUT_PORT").toInt(); +} + + +void RDLogeditConf::setInputCard(int input) const +{ + SetRow("INPUT_CARD",input); +} + + +void RDLogeditConf::setInputPort(int input) const +{ + SetRow("INPUT_PORT",input); +} + + +int RDLogeditConf::outputCard() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"OUTPUT_CARD").toInt(); +} + + +int RDLogeditConf::outputPort() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"OUTPUT_PORT").toInt(); +} + + +void RDLogeditConf::setOutputCard(int output) const +{ + SetRow("OUTPUT_CARD",output); +} + + +void RDLogeditConf::setOutputPort(int output) const +{ + SetRow("OUTPUT_PORT",output); +} + + +unsigned RDLogeditConf::format() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"FORMAT").toUInt(); +} + + +void RDLogeditConf::setFormat(unsigned format) const +{ + SetRow("FORMAT",format); +} + + +unsigned RDLogeditConf::layer() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"LAYER").toUInt(); +} + + +void RDLogeditConf::setLayer(unsigned layer) const +{ + SetRow("LAYER",layer); +} + + +unsigned RDLogeditConf::bitrate() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"BITRATE").toUInt(); +} + + +void RDLogeditConf::setBitrate(unsigned rate) const +{ + SetRow("BITRATE",rate); +} + + +bool RDLogeditConf::enableSecondStart() const +{ + return RDBool(RDGetSqlValue("RDLOGEDIT","STATION",lib_station, + "ENABLE_SECOND_START").toString()); +} + + +void RDLogeditConf::setEnableSecondStart(bool state) const +{ + SetRow("ENABLE_SECOND_START",state); +} + + +unsigned RDLogeditConf::defaultChannels() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"DEFAULT_CHANNELS").toUInt(); +} + + +void RDLogeditConf::setDefaultChannels(unsigned chans) const +{ + SetRow("DEFAULT_CHANNELS",chans); +} + + +unsigned RDLogeditConf::maxLength() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"MAXLENGTH").toUInt(); +} + + +void RDLogeditConf::setMaxLength(unsigned length) const +{ + SetRow("MAXLENGTH",length); +} + + +unsigned RDLogeditConf::tailPreroll() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"TAIL_PREROLL"). + toUInt(); +} + + +void RDLogeditConf::setTailPreroll(unsigned length) const +{ + SetRow("TAIL_PREROLL",length); +} + + +unsigned RDLogeditConf::startCart() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"START_CART").toUInt(); +} + + +void RDLogeditConf::setStartCart(unsigned cartnum) const +{ + SetRow("START_CART",cartnum); +} + + +unsigned RDLogeditConf::endCart() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"END_CART").toUInt(); +} + + +void RDLogeditConf::setEndCart(unsigned cartnum) const +{ + SetRow("END_CART",cartnum); +} + + +unsigned RDLogeditConf::recStartCart() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"REC_START_CART"). + toUInt(); +} + + +void RDLogeditConf::setRecStartCart(unsigned cartnum) const +{ + SetRow("REC_START_CART",cartnum); +} + + +unsigned RDLogeditConf::recEndCart() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"REC_END_CART"). + toUInt(); +} + + +void RDLogeditConf::setRecEndCart(unsigned cartnum) const +{ + SetRow("REC_END_CART",cartnum); +} + + +int RDLogeditConf::trimThreshold() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"TRIM_THRESHOLD"). + toInt(); +} + + +void RDLogeditConf::setTrimThreshold(int level) +{ + SetRow("TRIM_THRESHOLD",level); +} + + +int RDLogeditConf::ripperLevel() const +{ + return RDGetSqlValue("RDLOGEDIT","STATION",lib_station,"RIPPER_LEVEL"). + toInt(); +} + + +void RDLogeditConf::setRipperLevel(int level) +{ + SetRow("RIPPER_LEVEL",level); +} + + +RDLogLine::TransType RDLogeditConf::defaultTransType() const +{ + return (RDLogLine::TransType)RDGetSqlValue("RDLOGEDIT","STATION",lib_station, + "DEFAULT_TRANS_TYPE").toInt(); +} + + +void RDLogeditConf::setDefaultTransType(RDLogLine::TransType type) +{ + SetRow("DEFAULT_TRANS_TYPE",(int)type); +} + + +#ifndef WIN32 +void RDLogeditConf::getSettings(RDSettings *s) const +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select DEFAULT_CHANNELS,SAMPRATE,\ + FORMAT,BITRATE,RIPPER_LEVEL,\ + TRIM_THRESHOLD from RDLOGEDIT \ + where STATION=\"%s\"", + (const char *)RDEscapeString(lib_station)); + q=new RDSqlQuery(sql); + s->clear(); + if(q->first()) { + s->setChannels(q->value(0).toUInt()); + s->setSampleRate(q->value(1).toUInt()); + switch(q->value(2).toInt()) { + case 0: + s->setFormat(RDSettings::Pcm16); + break; + + case 1: + s->setFormat(RDSettings::MpegL2); + break; + } + s->setBitRate(q->value(3).toUInt()); + s->setNormalizationLevel(q->value(4).toUInt()); + s->setAutotrimLevel(q->value(5).toUInt()); + } + delete q; +} +#endif // WIN32 + + +void RDLogeditConf::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE RDLOGEDIT SET %s=%d WHERE STATION=\"%s\"", + (const char *)param, + value, + (const char *)RDEscapeString(lib_station)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDLogeditConf::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE RDLOGEDIT SET %s=%d WHERE STATION=\"%s\"", + (const char *)param, + value, + (const char *)RDEscapeString(lib_station)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDLogeditConf::SetRow(const QString ¶m,bool value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update RDLOGEDIT set %s=\"%s\" where STATION=\"%s\"", + (const char *)param, + (const char *)RDYesNo(value), + (const char *)RDEscapeString(lib_station)); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdlogedit_conf.h b/lib/rdlogedit_conf.h new file mode 100644 index 00000000..3c0e5a05 --- /dev/null +++ b/lib/rdlogedit_conf.h @@ -0,0 +1,87 @@ +// rdlogedit_conf.h +// +// Abstract RDLogedit Configuration +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdlogedit_conf.h,v 1.10.8.1 2014/01/08 18:14:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDLOGEDIT_CONF_H +#define RDLOGEDIT_CONF_H + +#include <qsqldatabase.h> + +#ifndef WIN32 +#include <rdsettings.h> +#endif // WIN32 +#include <rdlog_line.h> + + +class RDLogeditConf +{ + public: + RDLogeditConf(const QString &station); + QString station() const; + int inputCard() const; + void setInputCard(int input) const; + int inputPort() const; + void setInputPort(int input) const; + int outputCard() const; + void setOutputCard(int output) const; + int outputPort() const; + void setOutputPort(int input) const; + unsigned format() const; + void setFormat(unsigned format) const; + unsigned layer() const; + void setLayer(unsigned layer) const; + unsigned bitrate() const; + void setBitrate(unsigned rate) const; + bool enableSecondStart() const; + void setEnableSecondStart(bool state) const; + unsigned defaultChannels() const; + void setDefaultChannels(unsigned chans) const; + unsigned maxLength() const; + void setMaxLength(unsigned length) const; + unsigned tailPreroll() const; + void setTailPreroll(unsigned length) const; + unsigned startCart() const; + void setStartCart(unsigned cartnum) const; + unsigned endCart() const; + void setEndCart(unsigned cartnum) const; + unsigned recStartCart() const; + void setRecStartCart(unsigned cartnum) const; + unsigned recEndCart() const; + void setRecEndCart(unsigned cartnum) const; + int trimThreshold() const; + void setTrimThreshold(int level); + int ripperLevel() const; + void setRipperLevel(int level); + RDLogLine::TransType defaultTransType() const; + void setDefaultTransType(RDLogLine::TransType type); +#ifndef WIN32 + void getSettings(RDSettings *s) const; +#endif // WIN32 + + private: + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,unsigned value) const; + void SetRow(const QString ¶m,bool value) const; + QString lib_station; +}; + + +#endif diff --git a/lib/rdmacro.cpp b/lib/rdmacro.cpp new file mode 100644 index 00000000..ce19f420 --- /dev/null +++ b/lib/rdmacro.cpp @@ -0,0 +1,345 @@ +// rdmacro.cpp +// +// A container class for a Rivendell Macro Language Command +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmacro.cpp,v 1.37.4.2.2.1 2014/05/22 19:37:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <ctype.h> + +#include <rdmacro.h> + +RDMacro::RDMacro() +{ + clear(); +} + + +RDMacro::Role RDMacro::role() const +{ + return rml_role; +} + + +void RDMacro::setRole(RDMacro::Role role) +{ + rml_role=role; +} + + +RDMacro::Command RDMacro::command() const +{ + return rml_cmd; +} + + +void RDMacro::setCommand(RDMacro::Command cmd) +{ + rml_cmd=cmd; +} + + +QHostAddress RDMacro::address() const +{ + return rml_addr; +} + + +void RDMacro::setAddress(QHostAddress addr) +{ + rml_addr=addr; +} + + +Q_UINT16 RDMacro::port() const +{ + return rml_port; +} + + +void RDMacro::setPort(Q_UINT16 port) +{ + rml_port=port; +} + + +bool RDMacro::echoRequested() const +{ + return rml_echo_requested; +} + + +void RDMacro::setEchoRequested(bool state) +{ + rml_echo_requested=state; +} + + +QVariant RDMacro::arg(int n) const +{ + if(n>=RD_RML_MAX_ARGS) { + return QVariant(); + } + return rml_arg[n]; +} + + +void RDMacro::setArg(int n,QVariant arg) +{ + if(n>=RD_RML_MAX_ARGS) { + return; + } + rml_arg[n]=arg; +} + + +int RDMacro::argQuantity() const +{ + return rml_arg_quantity; +} + + +void RDMacro::acknowledge(bool state) +{ + rml_role=RDMacro::Reply; + if(rml_arg_quantity<RD_RML_MAX_ARGS) { + if(state) { + rml_arg[rml_arg_quantity]=QString("+"); + rml_arg_quantity++; + } + else { + rml_arg[rml_arg_quantity]=QString("-"); + rml_arg_quantity++; + } + } +} + + +void RDMacro::setArgQuantity(int n) +{ + rml_arg_quantity=n; +} + + +QString RDMacro::rollupArgs(int n) +{ + QString str; + for(int i=n;i<rml_arg_quantity;i++) { + str=(str+" "+rml_arg[i].toString()); + } + return str.right(str.length()-1); +} + + +bool RDMacro::parseString(const char *str,int n) +{ + int argnum=0; + int argptr=0; + char arg[RD_RML_MAX_LENGTH]; + bool quoted=false; + bool escaped=false; + + if(n<3) { + return false; + } + + // + // Command Mneumonic + // + rml_cmd=(RDMacro::Command)((str[0]<<8)+str[1]); + switch(rml_cmd) { + case RDMacro::AL: + case RDMacro::BO: + case RDMacro::CC: + case RDMacro::CL: + case RDMacro::DB: + case RDMacro::DL: + case RDMacro::DP: + case RDMacro::DS: + case RDMacro::DX: + case RDMacro::EX: + case RDMacro::FS: + case RDMacro::GE: + case RDMacro::GI: + case RDMacro::GO: + case RDMacro::JC: + case RDMacro::JD: + case RDMacro::LB: + case RDMacro::LC: + case RDMacro::LL: + case RDMacro::LO: + case RDMacro::MB: + case RDMacro::MD: + case RDMacro::MN: + case RDMacro::MT: + case RDMacro::NN: + case RDMacro::PB: + case RDMacro::PC: + case RDMacro::PE: + case RDMacro::PL: + case RDMacro::PM: + case RDMacro::PN: + case RDMacro::PP: + case RDMacro::PS: + case RDMacro::PT: + case RDMacro::PU: + case RDMacro::PW: + case RDMacro::PX: + case RDMacro::RL: + case RDMacro::RS: + case RDMacro::RR: + case RDMacro::RN: + case RDMacro::SN: + case RDMacro::ST: + case RDMacro::SA: + case RDMacro::SC: + case RDMacro::SD: + case RDMacro::SG: + case RDMacro::SI: + case RDMacro::SO: + case RDMacro::SP: + case RDMacro::SR: + case RDMacro::SL: + case RDMacro::SX: + case RDMacro::SY: + case RDMacro::SZ: + case RDMacro::TA: + case RDMacro::UO: + case RDMacro::PD: + break; + + default: + return false; + } + if(str[2]=='!') { + rml_arg_quantity=0; + return true; + } + if(!isblank(str[2])) { + rml_arg_quantity=0; + rml_cmd=RDMacro::NN; + return false; + } + + // + // Arguments + // + for(int i=3;i<n;i++) { + if(quoted||escaped) { + arg[argptr]=str[i]; + if(quoted&&((arg[argptr]==0x22)||(arg[argptr]==0x27))) { + quoted=false; + } + if(escaped) { + escaped=false; + } + argptr++; + } + else { + switch(str[i]) { + case ' ': + arg[argptr]=0; + rml_arg[argnum++]=QVariant(QString(arg)); + argptr=0; + break; + + case '!': + arg[argptr]=0; + rml_arg[argnum++]=QVariant(QString(arg)); + rml_arg_quantity=argnum; + return true; + + case '\\': + escaped=true; + break; + + default: + arg[argptr]=str[i]; + if((arg[argptr]==0x22)||(arg[argptr]==0x27)) { + quoted=true; + } + argptr++; + break; + } + } + if((argnum>=RD_RML_MAX_ARGS)||(argptr>=RD_RML_MAX_LENGTH)) { + rml_arg_quantity=0; + rml_cmd=RDMacro::NN; + for(int j=0;j<RD_RML_MAX_ARGS;j++) { + rml_arg[j].clear(); + } + return false; + } + } + rml_arg_quantity=0; + rml_cmd=RDMacro::NN; + for(int i=0;i<RD_RML_MAX_ARGS;i++) { + rml_arg[i].clear(); + } + return false; +} + + +int RDMacro::generateString(char *str,int n) const +{ + int len=3; + + for(int i=0;i<rml_arg_quantity;i++) { + len+=(rml_arg[i].toString().length()+1); + } + if(len>=n) { + return -1; + } + sprintf(str,"%c%c",rml_cmd>>8,rml_cmd&0xFF); + for(int i=0;i<rml_arg_quantity;i++) { + strcat(str," "); + strcat(str,(const char *)rml_arg[i].toString()); + } + strcat(str,"!"); + return len; +} + + +unsigned RDMacro::length() const +{ + switch(rml_cmd) { + case RDMacro::SP: + if(rml_arg_quantity==1) { + return rml_arg[0].toUInt(); + } + return 0; + + default: + return 0; + } + return 0; +} + + +void RDMacro::clear() +{ + rml_role=RDMacro::Invalid; + rml_cmd=RDMacro::NN; + rml_addr=QHostAddress(); + rml_port=RD_RML_NOECHO_PORT; + rml_echo_requested=false; + for(int i=0;i<RD_RML_MAX_ARGS;i++) { + rml_arg[i].clear(); + } + rml_arg_quantity=0; +} diff --git a/lib/rdmacro.h b/lib/rdmacro.h new file mode 100644 index 00000000..e40ab14c --- /dev/null +++ b/lib/rdmacro.h @@ -0,0 +1,84 @@ +// rdmacro.h +// +// A container class for a Rivendell Macro Language Command +// +// (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmacro.h,v 1.37.4.2.2.1 2014/05/22 19:37:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDMACRO_H +#define RDMACRO_H + +#include <qstring.h> +#include <qhostaddress.h> +#include <qvariant.h> + +#include <rd.h> + +#ifdef WIN32 +#include <rdwin32.h> +#endif // WIN32 + + +class RDMacro +{ + public: + enum Command {AL=0x414C,BO=0x424F,CC=0x4343,CL=0x434C,DB=0x4442,DL=0x444C, + DP=0x4450,DS=0x4453,DX=0x4458,EX=0x4558,FS=0x4653,GE=0x4745, + GI=0x4749,GO=0x474F,JC=0x4A43,JD=0x4A44,LB=0x4C42,LC=0x4C43, + LL=0x4C4C,LO=0x4C4F,MB=0x4D42,MD=0x4D44,MN=0x4D4E,MT=0x4D54, + NN=0x4E4E,PB=0x5042,PC=0x5043,PD=0x5044,PE=0x5045,PL=0x504C, + PM=0x504D,PN=0x504E,PP=0x5050,PS=0x5053,PT=0x5054,PU=0x5055, + PW=0x5057,PX=0x5058,RL=0x524C,RN=0x524E,RS=0x5253,RR=0x5252, + SA=0x5341,SC=0x5343,SD=0x5344,SG=0x5347,SI=0x5349,SL=0x534C, + SN=0x534e,SO=0x534F,SP=0x5350,SR=0x5352,ST=0x5354,SX=0x5358, + SY=0x5359,SZ=0x535A,TA=0x5441,UO=0x554F}; + enum Role {Invalid=0,Cmd=1,Reply=2}; + RDMacro(); + RDMacro::Role role() const; + void setRole(RDMacro::Role role); + RDMacro::Command command() const; + void setCommand(RDMacro::Command cmd); + QHostAddress address() const; + void setAddress(QHostAddress addr); + Q_UINT16 port() const; + void setPort(Q_UINT16 port); + bool echoRequested() const; + void setEchoRequested(bool state); + QVariant arg(int n) const; + void setArg(int n,QVariant arg); + int argQuantity() const; + void setArgQuantity(int n); + void acknowledge(bool state); + QString rollupArgs(int n); + bool parseString(const char *str,int n); + int generateString(char *str,int n) const; + unsigned length() const; + void clear(); + + private: + RDMacro::Role rml_role; + RDMacro::Command rml_cmd; + QHostAddress rml_addr; + Q_UINT16 rml_port; + bool rml_echo_requested; + QVariant rml_arg[RD_RML_MAX_ARGS]; + int rml_arg_quantity; +}; + + +#endif // RDMACRO_H diff --git a/lib/rdmacro_event.cpp b/lib/rdmacro_event.cpp new file mode 100644 index 00000000..7126a941 --- /dev/null +++ b/lib/rdmacro_event.cpp @@ -0,0 +1,342 @@ +// rdmacro_event.cpp +// +// A container class for a list of RML macros. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmacro_event.cpp,v 1.22 2011/03/01 20:35:52 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qstringlist.h> + +#include <rddb.h> +#include <rdmacro_event.h> +#include <rdstation.h> + + +RDMacroEvent::RDMacroEvent(RDRipc *ripc,QObject *parent,const char *name) + : QObject(parent,name) +{ + QHostAddress addr; + addr.setAddress("127.0.0.1"); + event_ripc=ripc; + event_address=addr; + event_whole_list=false; + event_line=-1; + + event_sleep_timer=new QTimer(this,"event_sleep_timer"); + connect(event_sleep_timer,SIGNAL(timeout()),this,SLOT(sleepTimerData())); +} + + +RDMacroEvent::RDMacroEvent(QHostAddress addr,RDRipc *ripc, + QObject *parent,const char *name) + : QObject(parent,name) +{ + event_ripc=ripc; + event_address=addr; + event_whole_list=false; + event_line=-1; + + event_sleep_timer=new QTimer(this,"event_sleep_timer"); + connect(event_sleep_timer,SIGNAL(timeout()),this,SLOT(sleepTimerData())); +} + + +RDMacroEvent::~RDMacroEvent() +{ + for(unsigned i=0;i<event_cmds.size();i++) { + delete event_cmds[i]; + } +} + + +int RDMacroEvent::line() const +{ + return event_line; +} + + +void RDMacroEvent::setLine(int line) +{ + event_line=line; +} + + +QTime RDMacroEvent::startTime() const +{ + return event_start_time; +} + + +void RDMacroEvent::setStartTime(QTime time) +{ + event_start_time=time; +} + + +RDMacro *RDMacroEvent::command(int line) +{ + return event_cmds.at(line); +} + + +int RDMacroEvent::size() const +{ + return event_cmds.size(); +} + + +unsigned RDMacroEvent::length() const +{ + unsigned length=0; + for(unsigned i=0;i<event_cmds.size();i++) { + length+=event_cmds[i]->length(); + } + return length; +} + + +bool RDMacroEvent::load(QString str) +{ + char buffer[RD_RML_MAX_LENGTH]; + RDMacro cmd; + int ptr=0; + char c; + + for(unsigned i=0;i<str.length();i++) { + if((c=str.ascii()[i])=='!') { + buffer[ptr++]=c; + if(!cmd.parseString(buffer,ptr)) { + clear(); + return false; + } + cmd.setRole(RDMacro::Cmd); + cmd.setAddress(event_address); + cmd.setEchoRequested(false); + event_cmds.push_back(new RDMacro(cmd)); + ptr=0; + cmd.clear(); + } + else { + buffer[ptr++]=c; + } + } + return true; +} + + +bool RDMacroEvent::load(unsigned cartnum) +{ + QString sql=QString(). + sprintf("select MACROS from CART where (NUMBER=%d)&&(TYPE=2)",cartnum); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + clear(); + return false; + } + bool ret=load(q->value(0).toString()); + delete q; + return ret; +} + + +QString RDMacroEvent::save() +{ + QString str; + char buffer[RD_RML_MAX_LENGTH]; + + for(unsigned i=0;i<event_cmds.size();i++) { + event_cmds[i]->generateString(buffer,RD_RML_MAX_LENGTH-1); + str+=QString(buffer); + } + return str; +} + + +void RDMacroEvent::insert(int line,const RDMacro *cmd) +{ + std::vector<RDMacro *>::iterator it=event_cmds.begin()+line; + + event_cmds.insert(it,1,new RDMacro(*cmd)); +} + + +void RDMacroEvent::remove(int line) +{ + std::vector<RDMacro *>::iterator it=event_cmds.begin()+line; + + delete event_cmds[line]; + event_cmds.erase(it,it+1); +} + + +void RDMacroEvent::move(int from_line,int to_line) +{ + int src_offset=0; + + if(to_line<from_line) { + src_offset=1; + } + insert(to_line,command(from_line)); + remove(from_line+src_offset); +} + + +void RDMacroEvent::copy(int from_line,int to_line) +{ + insert(to_line,command(from_line)); +} + + +void RDMacroEvent::clear() +{ + event_cmds.clear(); + event_line=-1; + event_start_time=QTime(); +} + + +void RDMacroEvent::exec() +{ + if(event_ripc==NULL) { + return; + } + ExecList(0); +} + + +void RDMacroEvent::exec(int line) +{ + QString sql; + RDSqlQuery *q; + QString stationname; + QStringList args; + Q_UINT16 port=0; + + if(event_ripc==NULL) { + return; + } + RDMacro rml; + RDStation *station; + QHostAddress addr; + RDMacro::Command cmd; + emit started(line); + switch(event_cmds[line]->command()) { + case RDMacro::SP: // Sleep + event_sleeping_line=line; + event_sleep_timer->start(event_cmds[line]->arg(0).toInt(),true); + break; + + case RDMacro::CC: // Send Command + args=args.split(":",event_cmds[line]->arg(0).toString()); + stationname=args[0]; + if(args.size()==2) { + port=args[1].toUInt(); + } + //stationname=event_cmds[line]->arg(0).toString(); + sql= + QString().sprintf("select VARVALUE from HOSTVARS \ + where (STATION_NAME=\"%s\")&&(NAME=\"%s\")", + (const char *)event_ripc->station(), + (const char *)stationname); + q=new RDSqlQuery(sql); + if(q->first()) { + stationname=q->value(0).toString(); + } + delete q; + station=new RDStation(stationname); + if(station->exists()) { + rml.setAddress(station->address()); + } + else { + addr.setAddress(stationname); + if(addr.isNull()) { + emit finished(line); + delete station; + return; + } + rml.setAddress(addr); + } + delete station; + rml.setArgQuantity(event_cmds[line]->argQuantity()-2); + cmd= + (RDMacro::Command)(256*event_cmds[line]->arg(1).toString().ascii()[0]+ + event_cmds[line]->arg(1).toString().ascii()[1]); + rml.setCommand(cmd); + for(int i=0;i<rml.argQuantity();i++) { + rml.setArg(i,event_cmds[line]->arg(i+2)); + } + rml.setRole(RDMacro::Cmd); + rml.setPort(port); + rml.setEchoRequested(event_cmds[line]->echoRequested()); + event_ripc->sendRml(&rml); + emit finished(line); + break; + + default: + event_ripc->sendRml(event_cmds[line]); + emit finished(line); + break; + } +} + + +void RDMacroEvent::stop() +{ + // + // This will work only for 'Sleep' [SP] macros -- all others are + // assumed to execute 'instaneously', and hence trying to 'stop' + // them would make no sense. + // + if(event_sleep_timer->isActive()) { + event_sleep_timer->stop(); + emit stopped(); + } +} + + +void RDMacroEvent::sleepTimerData() +{ + emit finished(event_sleeping_line); + if(event_whole_list) { + ExecList(event_sleeping_line+1); + } +} + + +void RDMacroEvent::ExecList(int line) +{ + if(line==0) { + event_whole_list=true; + emit started(); + } + for(unsigned i=line;i<event_cmds.size();i++) { + switch(event_cmds[i]->command()) { + case RDMacro::SP: // Sleep + exec(i); + return; + break; + + default: + exec(i); + break; + } + } + event_whole_list=false; + emit finished(); +} diff --git a/lib/rdmacro_event.h b/lib/rdmacro_event.h new file mode 100644 index 00000000..1c2eadc3 --- /dev/null +++ b/lib/rdmacro_event.h @@ -0,0 +1,88 @@ +// rdmacro_event.h +// +// A container class for a list of RML macros. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmacro_event.h,v 1.14 2011/01/04 22:50:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDMACRO_EVENT_H +#define RDMACRO_EVENT_H + +#include <vector> + +#include <qobject.h> +#include <qtimer.h> +#include <qhostaddress.h> +#include <qdatetime.h> + +#include <rdmacro.h> +#include <rdripc.h> + +class RDMacroEvent : public QObject +{ + Q_OBJECT + public: + RDMacroEvent(RDRipc *ripc=0,QObject *parent=0,const char *name=0); + RDMacroEvent(QHostAddress addr,RDRipc *ripc=0, + QObject *parent=0,const char *name=0); + ~RDMacroEvent(); + int line() const; + void setLine(int line); + QTime startTime() const; + void setStartTime(QTime time); + RDMacro *command(int line); + int size() const; + unsigned length() const; + bool load(QString str); + bool load(unsigned cartnum); + QString save(); + void insert(int line,const RDMacro *cmd); + void remove(int line); + void move(int from_line,int to_line); + void copy(int from_line,int to_line); + void clear(); + + public slots: + void exec(); + void exec(int line); + void stop(); + + signals: + void started(); + void started(int line); + void finished(); + void finished(int line); + void stopped(); + + private slots: + void sleepTimerData(); + + private: + void ExecList(int line); + std::vector<RDMacro *> event_cmds; + RDRipc *event_ripc; + QTimer *event_sleep_timer; + bool event_whole_list; + unsigned event_sleeping_line; + QHostAddress event_address; + int event_line; + QTime event_start_time; +}; + + +#endif // RDMACRO_EVENT_H diff --git a/lib/rdmarker_bar.cpp b/lib/rdmarker_bar.cpp new file mode 100644 index 00000000..9fd22b79 --- /dev/null +++ b/lib/rdmarker_bar.cpp @@ -0,0 +1,125 @@ +// rdmarker_bar.cpp +// +// A marker widget for the RDCueEdit widget. +// +// (C) Copyright 2002-2013 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmarker_bar.cpp,v 1.1.2.1 2013/07/05 21:07:28 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qpainter.h> +#include <qpointarray.h> + +#include <rdmarker_bar.h> + +RDMarkerBar::RDMarkerBar(QWidget *parent,const char *name) + : QLabel(parent,name) +{ + for(int i=0;i<RDMarkerBar::MaxSize;i++) { + marker_pos[i]=0; + } + setLineWidth(1); + setMidLineWidth(0); + setFrameStyle(QFrame::Box|QFrame::Plain); +} + + +QSize RDMarkerBar::sizeHint() const +{ + return QSize(425,14); +} + + +QSizePolicy RDMarkerBar::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int RDMarkerBar::length() const +{ + return marker_length; +} + + +void RDMarkerBar::setLength(int msecs) +{ + marker_length=msecs; + DrawMap(); +} + + +int RDMarkerBar::marker(Marker marker) const +{ + if(marker>=RDMarkerBar::MaxSize) { + return 0; + } + return marker_pos[marker]; +} + + +void RDMarkerBar::setMarker(Marker marker,int msecs) +{ + if(marker>=RDMarkerBar::MaxSize) { + return; + } + marker_pos[marker]=msecs; + DrawMap(); +} + + +void RDMarkerBar::DrawMap() +{ + QPixmap *pix=new QPixmap(size()); + QPainter *p=new QPainter(pix); + QPointArray *pt; + p->fillRect(0,0,size().width(),size().height(),backgroundColor()); + if(marker_length>0) { + p->setPen(RD_CUEEDITOR_START_MARKER); + p->setBrush(RD_CUEEDITOR_START_MARKER); + p->fillRect(size().width()*marker_pos[RDMarkerBar::Start]/marker_length-2,0, + 4,size().height(),RD_CUEEDITOR_START_MARKER); + pt=new QPointArray(3); + pt->setPoint(0,size().width()*marker_pos[RDMarkerBar::Start]/marker_length-2, + size().height()/2-1); + pt->setPoint(1,size().width()*marker_pos[RDMarkerBar::Start]/marker_length-12, + size().height()-2); + pt->setPoint(2,size().width()*marker_pos[RDMarkerBar::Start]/marker_length-12, + 1); + p->drawPolygon(*pt); + + p->fillRect(size().width()*marker_pos[RDMarkerBar::End]/marker_length-2,0, + 4,size().height(),RD_CUEEDITOR_START_MARKER); + pt->setPoint(0,size().width()*marker_pos[RDMarkerBar::End]/marker_length+2, + size().height()/2-1); + pt->setPoint(1,size().width()*marker_pos[RDMarkerBar::End]/marker_length+12, + size().height()-2); + pt->setPoint(2,size().width()*marker_pos[RDMarkerBar::End]/marker_length+12, + 1); + p->drawPolygon(*pt); + delete pt; + + p->setPen(RD_CUEEDITOR_PLAY_MARKER); + p->setBrush(RD_CUEEDITOR_PLAY_MARKER); + p->fillRect(size().width()*marker_pos[RDMarkerBar::Play]/marker_length-1,0, + 2,size().height(),RD_CUEEDITOR_PLAY_MARKER); + } + p->end(); + setPixmap(*pix); + delete p; + delete pix; +} + diff --git a/lib/rdmarker_bar.h b/lib/rdmarker_bar.h new file mode 100644 index 00000000..e072fda7 --- /dev/null +++ b/lib/rdmarker_bar.h @@ -0,0 +1,54 @@ +// rdmarker_bar.h +// +// A marker widget for the RDCueEdit widget. +// +// (C) Copyright 2002-2013 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmarker_bar.h,v 1.1.2.1 2013/07/05 21:07:28 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDMARKER_BAR_H +#define RDMARKER_BAR_H + +#include <qlabel.h> +#include <qpixmap.h> + +#include <rd.h> + +class RDMarkerBar : public QLabel +{ + Q_OBJECT + public: + enum Marker {Play=0,Start=1,End=2,MaxSize=3}; + RDMarkerBar(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int length() const; + void setLength(int msecs); + int marker(Marker marker) const; + void setMarker(Marker marker,int msecs); + + private: + void DrawMap(); + int marker_pos[RDMarkerBar::MaxSize]; + int marker_length; +}; + + +#endif diff --git a/lib/rdmarker_button.cpp b/lib/rdmarker_button.cpp new file mode 100644 index 00000000..a653f1dd --- /dev/null +++ b/lib/rdmarker_button.cpp @@ -0,0 +1,49 @@ +// rdmarker_button.cpp +// +// Marker Button for RDLibrary +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmarker_button.cpp,v 1.6 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdmarker_button.h> + +RDMarkerButton::RDMarkerButton(QWidget *parent,const char *name) + : RDPushButton(parent,name) +{ +} + + +RDMarkerButton::RDMarkerButton(const QString &text,QWidget *parent, + const char *name) + : RDPushButton(text,parent,name) +{ +} + + +RDMarkerButton::RDMarkerButton(const QIconSet &icon,const QString &text, + QWidget *parent,const char *name) + : RDPushButton(icon,text,parent,name) +{ +} + + +void RDMarkerButton::keyPressEvent(QKeyEvent *e) +{ + e->ignore(); +} + diff --git a/lib/rdmarker_button.h b/lib/rdmarker_button.h new file mode 100644 index 00000000..73edce4d --- /dev/null +++ b/lib/rdmarker_button.h @@ -0,0 +1,43 @@ +// rdmarker_button.h +// +// Marker Button for RDLibrary +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmarker_button.h,v 1.6 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDMARKER_BUTTON_H +#define RDMARKER_BUTTON_H + +#include <rdpushbutton.h> +#include <qevent.h> + +class RDMarkerButton : public RDPushButton +{ + public: + RDMarkerButton(QWidget *parent,const char *name=0); + RDMarkerButton(const QString &text,QWidget *parent,const char *name=0); + RDMarkerButton(const QIconSet &icon,const QString &text,QWidget *parent, + const char *name=0); + + protected: + void keyPressEvent(QKeyEvent *e); +}; + + +#endif + diff --git a/lib/rdmarker_edit.cpp b/lib/rdmarker_edit.cpp new file mode 100644 index 00000000..6a2f9f53 --- /dev/null +++ b/lib/rdmarker_edit.cpp @@ -0,0 +1,69 @@ +// rdmarkeredit.cpp +// +// An flashing button widget. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmarker_edit.cpp,v 1.3 2007/02/14 21:48:41 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <rdmarker_edit.h> + +RDMarkerEdit::RDMarkerEdit(QWidget *parent,const char *name) + : QLineEdit(parent,name) +{ +} + + +RDMarkerEdit::RDMarkerEdit(const QString &contents,QWidget *parent,const char *name) + : QLineEdit(contents,parent,name) +{ +} + + +void RDMarkerEdit::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Escape: + emit escapePressed(); + break; + + case Qt::Key_Delete: + e->ignore(); + return; + break; + + case Qt::Key_Space: + e->ignore(); + return; + break; + + case Qt::Key_Home: + e->ignore(); + return; + break; + + case Qt::Key_End: + e->ignore(); + return; + break; + + default: + break; + } + QLineEdit::keyPressEvent(e); +} diff --git a/lib/rdmarker_edit.h b/lib/rdmarker_edit.h new file mode 100644 index 00000000..e39d3fc5 --- /dev/null +++ b/lib/rdmarker_edit.h @@ -0,0 +1,49 @@ +// rdmarkeredit.h +// +// An flashing button widget. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmarker_edit.h,v 1.7 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDMARKEREDIT_H +#define RDMARKEREDIT_H + +#include <qwidget.h> +#include <qlineedit.h> +#include <qpixmap.h> +#include <qcolor.h> + + +class RDMarkerEdit : public QLineEdit +{ + Q_OBJECT + + public: + RDMarkerEdit(QWidget *parent,const char *name); + RDMarkerEdit(const QString &contents,QWidget *parent,const char *name); + + signals: + void escapePressed(); + + protected: + void keyPressEvent(QKeyEvent *e); +}; + + +#endif // RDMARKEREDIT_H diff --git a/lib/rdmatrix.cpp b/lib/rdmatrix.cpp new file mode 100644 index 00000000..26ae7617 --- /dev/null +++ b/lib/rdmatrix.cpp @@ -0,0 +1,794 @@ +// rdmatrix.cpp +// +// Abstract a Rivendell Switcher Matrix +// +// (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmatrix.cpp,v 1.28.8.11 2014/02/17 02:19:01 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rddb.h> +#include <rdmatrix.h> +#include <rdescape_string.h> + +// +// Control Grids +// +bool __mx_primary_controls[RDMatrix::LastType][RDMatrix::LastControl]= + { + // 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 + {0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0}, // Local GPIO + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // Generic GPIO + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // Generic Serial + {0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0}, // SAS 32000 + {0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0}, // SAS 64000 + {0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0}, // Unity4k + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, // BT SS 8.2 + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0}, // BT 10x1 + {0,1,0,0,0,0,0,0,0,0,0,1,1,0,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0}, // SAS 64000 GPI + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0}, // BT 16x1 + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0}, // BT 8x2 + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, // BT ACS 8.2 + {1,1,1,1,0,0,1,1,0,0,0,1,1,1,1,0,1,1,1,1,0,0,0,1,1,0,0,0,0}, // SAS USI + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, // BT 16x2 + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0}, // BT SS 12.4 + {0,0,0,0,0,0,0,0,1,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0}, // Local Adapter + {1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,0,0,0}, // vGuest + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, // BT SS 16.4 + {0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0}, // StarGuide 3 + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, // BT SS 4.2 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,0,0}, // Livewire LWRP Audio + {1,1,1,1,0,0,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0}, // Quartz 1 + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, // BT SS 4.4 + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0}, // BT SRC8 III + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0}, // BT SRC16 + {0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0}, // Harlond + {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0}, // ACU-1 Prophet + {0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,1,0,0,0,1}, // LiveWire Multicast GPIO + {0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0}, // 360 AM16 + {0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0}, // LiveWire LWRP GPIO + {0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0} // BT Sentinel 4 Web + }; +bool __mx_backup_controls[RDMatrix::LastType][RDMatrix::LastControl]= + { + // 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // Local GPIO + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // Generic GPIO + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // Generic Serial + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // SAS 32000 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // SAS 64000 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // Unity4k + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT SS 8.2 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT 10x1 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // SAS 64000 GPI + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT 16x1 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT 8x2 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT ACS 8.2 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // SAS USI + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT 16x2 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT SS 12.4 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // Local Adapter + {1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,0,0,0}, // vGuest + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT SS16.4 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // StarGuide 3 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT SS 4.2 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // Livewire LWRP Audio + {1,1,1,1,0,0,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0}, // Quartz 1 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT SS 4.4 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT SRC8 III + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // BT SRC16 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // Harlond + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // ACU-1 Prophet + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // LiveWire Multicast GPIO + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // 360 AM16 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, // LiveWire LWRP GPIO + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} // BT Sentinel 4 Web + }; + +int __mx_default_values[RDMatrix::LastType][RDMatrix::LastControl]= + { + // 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // Local GPIO + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // Generic GPIO + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // Generic Serial + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // SAS 32000 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // SAS 64000 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // Unity4k + {0,0,0,0,0,0,0,0,0,0,0,8,2,16,8,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT SS 8.2 + {0,0,0,0,0,0,0,0,0,0,0,10,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT 10x1 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // SAS 64000 GPI + {0,0,0,0,0,0,0,0,0,0,0,16,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT 16x1 + {0,0,0,0,0,0,0,0,0,0,0,8,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT 8x2 + {0,0,0,0,0,0,0,0,0,0,0,8,2,16,16,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT ACS 8.2 + {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // SAS USI + {0,0,0,0,0,0,0,0,0,0,0,16,2,16,16,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT 16x2 + {0,0,0,0,0,0,0,0,0,0,0,12,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT SS 12.4 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // Local Adapter + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // vGuest + {0,0,0,0,0,0,0,0,0,0,0,16,4,24,24,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT SS16.4 + {0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // StarGuide 3 + {0,0,0,0,0,0,0,0,0,0,0,4,2,16,8,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT SS 4.2 + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // Livewire LWRP Audio + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // Quartz 1 + {0,0,0,0,0,0,0,0,0,0,0,4,4,16,8,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT SS 4.4 + {0,0,0,0,0,0,0,0,0,0,0,0,0,8,8,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT SRC8 III + {0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // BT SRC16 + {1,0,0,0,0,0,0,0,0,0,0,8,4,8,8,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // Harlond + {0,0,0,0,0,0,0,0,0,0,0,10,1,16,8,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // ACU-1 Prophet + {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0}, // LiveWire Multicast GPIO + {0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, // 360 AM16 + {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0}, // LiveWire LWRP GPIO + {1,0,0,0,0,0,0,0,0,0,0,4,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0} // BT Sentinel 4 Web + }; + +RDMatrix::RDMatrix(const QString &station,int matrix) +{ + mx_station=station; + mx_number=matrix; +} + + +QString RDMatrix::station() const +{ + return mx_station; +} + + +int RDMatrix::matrix() const +{ + return mx_number; +} + + +bool RDMatrix::exists() const +{ + QString sql=QString().sprintf("select TYPE from MATRICES where MATRIX=%d", + mx_number); + RDSqlQuery *q=new RDSqlQuery(sql); + bool result=q->first(); + delete q; + return result; +} + + +RDMatrix::Type RDMatrix::type() const +{ + return (RDMatrix::Type)GetRow("TYPE").toInt(); +} + + +void RDMatrix::setType(RDMatrix::Type type) const +{ + SetRow("TYPE",type); +} + + +int RDMatrix::layer() const +{ + return GetRow("LAYER").toInt(); +} + + +void RDMatrix::setLayer(int layer) +{ + SetRow("LAYER",layer); +} + + +QString RDMatrix::name() const +{ + return GetRow("NAME").toString(); +} + + +void RDMatrix::setName(const QString &name) const +{ + SetRow("NAME",name); +} + + +RDMatrix::PortType RDMatrix::portType(RDMatrix::Role role) const +{ + switch(role) { + case RDMatrix::Primary: + return (RDMatrix::PortType)GetRow("PORT_TYPE").toInt(); + + case RDMatrix::Backup: + return (RDMatrix::PortType)GetRow("PORT_TYPE_2").toInt(); + } + return RDMatrix::TtyPort; +} + + +void RDMatrix::setPortType(RDMatrix::Role role,PortType type) const +{ + switch(role) { + case RDMatrix::Primary: + SetRow("PORT_TYPE",(int)type); + break; + + case RDMatrix::Backup: + SetRow("PORT_TYPE_2",(int)type); + break; + } +} + + +QHostAddress RDMatrix::ipAddress(RDMatrix::Role role) const +{ + QHostAddress addr; + switch(role) { + case RDMatrix::Primary: + addr.setAddress(GetRow("IP_ADDRESS").toString()); + break; + + case RDMatrix::Backup: + addr.setAddress(GetRow("IP_ADDRESS_2").toString()); + break; + } + + return addr; +} + + +void RDMatrix::setIpAddress(RDMatrix::Role role,QHostAddress addr) const +{ + switch(role) { + case RDMatrix::Primary: + SetRow("IP_ADDRESS",addr.toString()); + break; + + case RDMatrix::Backup: + SetRow("IP_ADDRESS_2",addr.toString()); + break; + } +} + + +int RDMatrix::card() const +{ + return GetRow("CARD").toInt(); +} + + +void RDMatrix::setCard(int card) const +{ + SetRow("CARD",card); +} + + +int RDMatrix::ipPort(RDMatrix::Role role) const +{ + switch(role) { + case RDMatrix::Primary: + return GetRow("IP_PORT").toInt(); + + case RDMatrix::Backup: + return GetRow("IP_PORT_2").toInt(); + } + return 0; +} + + +void RDMatrix::setIpPort(RDMatrix::Role role,int port) const +{ + switch(role) { + case RDMatrix::Primary: + SetRow("IP_PORT",port); + + case RDMatrix::Backup: + SetRow("IP_PORT_2",port); + } +} + + +QString RDMatrix::username(RDMatrix::Role role) const +{ + switch(role) { + case RDMatrix::Primary: + return GetRow("USERNAME").toString(); + + case RDMatrix::Backup: + return GetRow("USERNAME_2").toString(); + } + return QString(); +} + + +void RDMatrix::setUsername(RDMatrix::Role role,const QString &name) const +{ + switch(role) { + case RDMatrix::Primary: + SetRow("USERNAME",name); + + case RDMatrix::Backup: + SetRow("USERNAME_2",name); + } +} + + +QString RDMatrix::password(RDMatrix::Role role) const +{ + switch(role) { + case RDMatrix::Primary: + return GetRow("PASSWORD").toString(); + + case RDMatrix::Backup: + return GetRow("PASSWORD_2").toString(); + } + return QString(); +} + + +void RDMatrix::setPassword(RDMatrix::Role role,const QString &passwd) const +{ + switch(role) { + case RDMatrix::Primary: + SetRow("PASSWORD",passwd); + + case RDMatrix::Backup: + SetRow("PASSWORD_2",passwd); + + } +} + + +unsigned RDMatrix::startCart(RDMatrix::Role role) const +{ + switch(role) { + case RDMatrix::Primary: + return GetRow("START_CART").toUInt(); + + case RDMatrix::Backup: + return GetRow("START_CART_2").toUInt(); + } + return 0; +} + + +void RDMatrix::setStartCart(RDMatrix::Role role,unsigned cartnum) const +{ + switch(role) { + case RDMatrix::Primary: + SetRow("START_CART",cartnum); + + case RDMatrix::Backup: + SetRow("START_CART_2",cartnum); + + } +} + + +unsigned RDMatrix::stopCart(RDMatrix::Role role) const +{ + switch(role) { + case RDMatrix::Primary: + return GetRow("STOP_CART").toUInt(); + + case RDMatrix::Backup: + return GetRow("STOP_CART_2").toUInt(); + } + return 0; +} + + +void RDMatrix::setStopCart(RDMatrix::Role role,unsigned cartnum) const +{ + switch(role) { + case RDMatrix::Primary: + SetRow("STOP_CART",cartnum); + + case RDMatrix::Backup: + SetRow("STOP_CART_2",cartnum); + + } +} + + +int RDMatrix::port(RDMatrix::Role role) const +{ + switch(role) { + case RDMatrix::Primary: + return GetRow("PORT").toInt(); + + case RDMatrix::Backup: + return GetRow("PORT_2").toInt(); + } + return -1; +} + + +void RDMatrix::setPort(RDMatrix::Role role,int port) const +{ + switch(role) { + case RDMatrix::Primary: + SetRow("PORT",port); + break; + + case RDMatrix::Backup: + SetRow("PORT_2",port); + break; + } +} + + +int RDMatrix::inputs() const +{ + return GetRow("INPUTS").toInt(); +} + + +void RDMatrix::setInputs(int inputs) const +{ + SetRow("INPUTS",inputs); +} + + +QString RDMatrix::inputName(int input) const +{ + return GetEndpointName(input,"INPUTS"); +} + + +RDMatrix::Mode RDMatrix::inputMode(int input) const +{ + QString sql=QString().sprintf("select CHANNEL_MODE from INPUTS where \ + STATION_NAME=\"%s\" && \ + MATRIX=%d && NUMBER=%d", + (const char *)mx_station, + mx_number, + input); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return RDMatrix::Stereo; + } + RDMatrix::Mode mode=(RDMatrix::Mode)q->value(0).toInt(); + delete q; + return mode; +} + + +int RDMatrix::outputs() const +{ + return GetRow("OUTPUTS").toInt(); +} + + +void RDMatrix::setOutputs(int outputs) const +{ + SetRow("OUTPUTS",outputs); +} + + +QString RDMatrix::outputName(int output) const +{ + return GetEndpointName(output,"OUTPUTS"); +} + + +int RDMatrix::gpis() const +{ + return GetRow("GPIS").toInt(); +} + + +void RDMatrix::setGpis(int gpis) const +{ + SetRow("GPIS",gpis); +} + + +int RDMatrix::gpos() const +{ + return GetRow("GPOS").toInt(); +} + + +void RDMatrix::setGpos(int gpos) const +{ + SetRow("GPOS",gpos); +} + + +QString RDMatrix::gpioDevice() const +{ + return GetRow("GPIO_DEVICE").toString(); +} + + +void RDMatrix::setGpioDevice(const QString &dev) const +{ + SetRow("GPIO_DEVICE",dev); +} + + +int RDMatrix::faders() const +{ + return GetRow("FADERS").toInt(); +} + + +void RDMatrix::setFaders(int quan) const +{ + SetRow("FADERS",quan); +} + + +int RDMatrix::displays() const +{ + return GetRow("DISPLAYS").toInt(); +} + + +void RDMatrix::setDisplays(int quan) const +{ + SetRow("DISPLAYS",quan); +} + + +QString RDMatrix::typeString(RDMatrix::Type type) +{ + switch(type) { + case RDMatrix::LocalGpio: + return QString("Local GPIO"); + break; + + case RDMatrix::GenericGpo: + return QString("Generic GPO"); + break; + + case RDMatrix::GenericSerial: + return QString("Generic Serial"); + break; + + case RDMatrix::Sas32000: + return QString("SAS 32000"); + break; + + case RDMatrix::Sas64000: + return QString("SAS 64000"); + break; + + case RDMatrix::Unity4000: + return QString("Wegener Unity 4000"); + break; + + case RDMatrix::BtSs82: + return QString("BroadcastTools SS8.2"); + break; + + case RDMatrix::Bt10x1: + return QString("BroadcastTools 10x1"); + break; + + case RDMatrix::Sas64000Gpi: + return QString("SAS 64000-GPI"); + break; + + case RDMatrix::Bt16x1: + return QString("BroadcastTools 16x1"); + break; + + case RDMatrix::Bt8x2: + return QString("BroadcastTools 8x2"); + break; + + case RDMatrix::BtAcs82: + return QString("BroadcastTools ACS 8.2"); + break; + + case RDMatrix::SasUsi: + return QString("SAS User Serial Interface"); + break; + + case RDMatrix::Bt16x2: + return QString("BroadcastTools 16x2"); + break; + + case RDMatrix::BtSs124: + return QString("BroadcastTools SS12.4"); + break; + + case RDMatrix::LocalAudioAdapter: + return QString("Local Audio Adapter"); + break; + + case RDMatrix::LogitekVguest: + return QString("Logitek vGuest"); + break; + + case RDMatrix::BtSs164: + return QString("BroadcastTools SS16.4"); + break; + + case RDMatrix::StarGuideIII: + return QString("StarGuide III"); + break; + + case RDMatrix::BtSs42: + return QString("BroadcastTools SS4.2"); + break; + + case RDMatrix::LiveWireLwrpAudio: + return QString("LiveWire LWRP Audio"); + break; + + case RDMatrix::Quartz1: + return QString("Quartz Type 1"); + break; + + case RDMatrix::BtSs44: + return QString("BroadcastTools SS4.4"); + break; + + case RDMatrix::BtSrc8III: + return QString("BroadcastTools SRC-8 III"); + break; + + case RDMatrix::BtSrc16: + return QString("BroadcastTools SRC-16"); + break; + + case RDMatrix::Harlond: + return QString("Harlond Virtual Mixer"); + break; + + case RDMatrix::Acu1p: + return QString("Sine ACU-1 (Prophet)"); + break; + + case RDMatrix::LiveWireMcastGpio: + return QString("LiveWire Multicast GPIO"); + break; + + case RDMatrix::Am16: + return QString("360 Systems AM-16/B"); + break; + + case RDMatrix::LiveWireLwrpGpio: + return QString("LiveWire LWRP GPIO"); + break; + + case RDMatrix::BtSentinel4Web: + return QString("BroadcastTools Sentinel 4 Web"); + break; + + default: + return QString("Unknown Type"); + break; + } + return QString("Unknown Type"); +} + + +bool RDMatrix::controlActive(RDMatrix::Type type,RDMatrix::Role role, + RDMatrix::Control control) +{ + bool ret=false; + + switch(role) { + case RDMatrix::Primary: + ret=__mx_primary_controls[type][control]; + break; + + case RDMatrix::Backup: + ret=__mx_backup_controls[type][control]; + break; + } + return ret; +} + + +bool RDMatrix::controlActive(RDMatrix::Type type,RDMatrix::Control control) +{ + return __mx_primary_controls[type][control]; +} + + +int RDMatrix::defaultControlValue(RDMatrix::Type type, + RDMatrix::Control control) +{ + return __mx_default_values[type][control]; +} + + +QString RDMatrix::GetEndpointName(int pointnum,const QString &table) const +{ + QString sql=QString().sprintf("select NAME from %s where \ + STATION_NAME=\"%s\" && \ + MATRIX=%d && NUMBER=%d", + (const char *)table, + (const char *)mx_station, + mx_number, + pointnum); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return QString("NULL"); + } + QString str=q->value(0).toString(); + delete q; + return str; +} + + +QVariant RDMatrix::GetRow(const QString ¶m) const +{ + QVariant var; + QString sql=QString().sprintf("select %s from MATRICES where \ + STATION_NAME=\"%s\" && MATRIX=%d", + (const char *)RDEscapeString(param), + (const char *)mx_station, + mx_number); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + var=q->value(0); + } + delete q; + return var; +} + + +void RDMatrix::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE MATRICES SET %s=\"%s\" \ + WHERE STATION_NAME=\"%s\" && MATRIX=%d", + (const char *)RDEscapeString(param), + (const char *)RDEscapeString(value), + (const char *)mx_station, + mx_number); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDMatrix::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE MATRICES SET %s=%d \ + WHERE STATION_NAME=\"%s\" && MATRIX=%d", + (const char *)RDEscapeString(param), + value, + (const char *)mx_station, + mx_number); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDMatrix::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE MATRICES SET %s=%u \ + WHERE STATION_NAME=\"%s\" && MATRIX=%d", + (const char *)RDEscapeString(param), + value, + (const char *)mx_station, + mx_number); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdmatrix.h b/lib/rdmatrix.h new file mode 100644 index 00000000..e3cdd44a --- /dev/null +++ b/lib/rdmatrix.h @@ -0,0 +1,127 @@ +// rdmatrix.h +// +// Abstract a Rivendell Switcher Matrix +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmatrix.h,v 1.28.8.9 2014/02/17 02:19:02 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> +#include <qdatetime.h> +#include <qhostaddress.h> + +#ifndef RDMATRIX_H +#define RDMATRIX_H + + +class RDMatrix +{ + public: + enum Role {Primary=0,Backup=2}; + enum PortType {TtyPort=0,TcpPort=1,NoPort=2}; + enum Type {LocalGpio=0,GenericGpo=1,GenericSerial=2,Sas32000=3,Sas64000=4, + Unity4000=5,BtSs82=6,Bt10x1=7,Sas64000Gpi=8,Bt16x1=9,Bt8x2=10, + BtAcs82=11,SasUsi=12,Bt16x2=13,BtSs124=14,LocalAudioAdapter=15, + LogitekVguest=16,BtSs164=17,StarGuideIII=18,BtSs42=19, + LiveWireLwrpAudio=20,Quartz1=21,BtSs44=22,BtSrc8III=23,BtSrc16=24, + Harlond=25,Acu1p=26,LiveWireMcastGpio=27,Am16=28, + LiveWireLwrpGpio=29,BtSentinel4Web=30,LastType=31}; + enum Endpoint {Input=0,Output=1}; + enum Mode {Stereo=0,Left=1,Right=2}; + enum VguestAttribute {VguestEngine=0,VguestDevice=1,VguestSurface=2, + VguestRelay=3,VguestBuss=4}; + enum VguestType {VguestTypeRelay=0,VguestTypeDisplay=2}; + enum GpioType {GpioInput=0,GpioOutput=1}; + enum Control {PortTypeControl=0,SerialPortControl=1, + IpAddressControl=2,IpPortControl=3, + UsernameControl=4,PasswordControl=5, + StartupCartControl=6,ShutdownCartControl=7, + CardControl=8,GpioDeviceControl=9, + LayerControl=10,InputsControl=11, + OutputsControl=12,GpisControl=13, + GposControl=14,DisplaysControl=15, + InputsButtonControl=16,OutputsButtonControl=17, + GpisButtonControl=18,GposButtonControl=19, + NodesButtonControl=20,VguestSwitchesButtonControl=21, + VguestDisplaysButtonControl=22,SasSwitchesButtonControl=23, + GpiGpoLinkedControl=24,GpioInputsLinkedControl=25, + DynamicGpioControl=26,GpioStepSize=27, + LivewireGpioButtonControl=28,LastControl=29}; + RDMatrix(const QString &station,int matrix); + QString station() const; + int matrix() const; + bool exists() const; + RDMatrix::Type type() const; + void setType(RDMatrix::Type type) const; + int layer() const; + void setLayer(int layer); + QString name() const; + void setName(const QString &name) const; + PortType portType(RDMatrix::Role role) const; + void setPortType(RDMatrix::Role role,PortType type) const; + int card() const; + void setCard(int card) const; + QHostAddress ipAddress(RDMatrix::Role role) const; + void setIpAddress(RDMatrix::Role role,QHostAddress addr) const; + int ipPort(RDMatrix::Role role) const; + void setIpPort(RDMatrix::Role role,int port) const; + QString username(RDMatrix::Role role) const; + void setUsername(RDMatrix::Role role,const QString &name) const; + QString password(RDMatrix::Role role) const; + void setPassword(RDMatrix::Role role,const QString &passwd) const; + unsigned startCart(RDMatrix::Role role) const; + void setStartCart(RDMatrix::Role role,unsigned cartnum) const; + unsigned stopCart(RDMatrix::Role role) const; + void setStopCart(RDMatrix::Role role,unsigned cartnum) const; + int port(RDMatrix::Role role) const; + void setPort(RDMatrix::Role role,int port) const; + int inputs() const; + void setInputs(int inputs) const; + QString inputName(int input) const; + RDMatrix::Mode inputMode(int input) const; + int outputs() const; + void setOutputs(int outputs) const; + QString outputName(int output) const; + int gpis() const; + void setGpis(int gpis) const; + int gpos() const; + void setGpos(int gpos) const; + QString gpioDevice() const; + void setGpioDevice(const QString &gpos) const; + int faders() const; + void setFaders(int quan) const; + int displays() const; + void setDisplays(int quan) const; + static QString typeString(RDMatrix::Type type); + static bool controlActive(RDMatrix::Type type,RDMatrix::Role role, + RDMatrix::Control control); + static bool controlActive(RDMatrix::Type type,RDMatrix::Control control); + static int defaultControlValue(RDMatrix::Type type, + RDMatrix::Control control); + + private: + QString GetEndpointName(int pointnum,const QString &table) const; + QVariant GetRow(const QString ¶m) const; + void SetRow(const QString ¶m,const QString &value) const; + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,unsigned value) const; + QString mx_station; + int mx_number; +}; + + +#endif diff --git a/lib/rdmeteraverage.cpp b/lib/rdmeteraverage.cpp new file mode 100644 index 00000000..3fd71b3e --- /dev/null +++ b/lib/rdmeteraverage.cpp @@ -0,0 +1,51 @@ +// rdmeteraverage.cpp +// +// Average sucessive levels for a meter. +// +// (C) Copyright 2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmeteraverage.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdmeteraverage.h> + + +RDMeterAverage::RDMeterAverage(int maxsize) +{ + avg_maxsize=maxsize; + avg_total=0.0; +} + + +double RDMeterAverage::average() const +{ + if(avg_values.size()==0) { + return 0.0; + } + return avg_total/((double)avg_values.size()); +} + + +void RDMeterAverage::addValue(double value) +{ + avg_total+=value; + avg_values.push(value); + int size=avg_values.size()-avg_maxsize; + for(int i=0;i<size;i++) { + avg_total-=avg_values.front(); + avg_values.pop(); + } +} diff --git a/lib/rdmeteraverage.h b/lib/rdmeteraverage.h new file mode 100644 index 00000000..ec2d5ebf --- /dev/null +++ b/lib/rdmeteraverage.h @@ -0,0 +1,42 @@ +// rdmeteraverage.h +// +// Average sucessive levels for a meter. +// +// (C) Copyright 2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmeteraverage.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +#ifndef RDMETERAVERAGE_H +#define RDMETERAVERAGE_H + +#include <queue> + + +class RDMeterAverage +{ + public: + RDMeterAverage(int maxsize); + double average() const; + void addValue(double value); + + private: + int avg_maxsize; + double avg_total; + std::queue<double> avg_values; +}; + + +#endif // RDMETERAVERAGE_H diff --git a/lib/rdmixer.cpp b/lib/rdmixer.cpp new file mode 100644 index 00000000..c6ad4bda --- /dev/null +++ b/lib/rdmixer.cpp @@ -0,0 +1,58 @@ +// rdmixer.cpp +// +// Mixer Functions for Rivendell. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmixer.cpp,v 1.13.8.2 2012/08/03 16:52:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdaudio_port.h> +#include <rd.h> + +#include <rdmixer.h> + + +void RDSetMixerPorts(QString station,RDCae *cae) +{ + for(int i=0;i<RD_MAX_CARDS;i++) { + RDAudioPort *port=new RDAudioPort(station,i); + cae->setClockSource(i,port->clockSource()); + for(int j=0;j<RD_MAX_PORTS;j++) { + if(port->inputPortType(j)==RDAudioPort::Analog) { + cae->setInputType(i,j,RDCae::Analog); + } + else { + cae->setInputType(i,j,RDCae::AesEbu); + } + cae->setInputLevel(i,j,RD_BASE_ANALOG+port->inputPortLevel(j)); + cae->setOutputLevel(i,j,RD_BASE_ANALOG+port->outputPortLevel(j)); + cae->setInputMode(i,j,port->inputPortMode(j)); + } + delete port; + } +} + + +void RDSetMixerOutputPort(RDCae *cae,int card,int stream,int port) +{ + for(int i=0;i<RD_MAX_PORTS;i++) { + if(i!=port) { + cae->setOutputVolume(card,stream,i,-10000); + } + } + cae->setOutputVolume(card,stream,port,0); +} diff --git a/lib/rdmixer.h b/lib/rdmixer.h new file mode 100644 index 00000000..60b40389 --- /dev/null +++ b/lib/rdmixer.h @@ -0,0 +1,33 @@ +// rdmixer.h +// +// Mixer Functions for Rivendell. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmixer.h,v 1.7 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> +#include <rdcae.h> + +#ifndef RDMIXER_H +#define RDMIXER_H + +void RDSetMixerPorts(QString station,RDCae *cae); +void RDSetMixerOutputPort(RDCae *cae,int card,int stream,int port); + + +#endif diff --git a/lib/rdmonitor_config.cpp b/lib/rdmonitor_config.cpp new file mode 100644 index 00000000..2dfbc7f4 --- /dev/null +++ b/lib/rdmonitor_config.cpp @@ -0,0 +1,166 @@ +// rdmonitor_config.cpp +// +// A container class for a Rivendell RDMonitor Configuration +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmonitor_config.cpp,v 1.1.2.2 2013/11/08 03:57:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> + +#include <qobject.h> + +#include <rdprofile.h> + +#include <rdmonitor_config.h> + +RDMonitorConfig::RDMonitorConfig() +{ + clear(); + mon_filename="/.rdmonitorrc"; + if(getenv("HOME")!=NULL) { + mon_filename=QString(getenv("HOME"))+mon_filename; + } +} + + +int RDMonitorConfig::screenNumber() const +{ + return mon_screen_number; +} + + +void RDMonitorConfig::setScreenNumber(int screen) +{ + mon_screen_number=screen; +} + + +RDMonitorConfig::Position RDMonitorConfig::position() const +{ + return mon_position; +} + + +void RDMonitorConfig::setPosition(RDMonitorConfig::Position pos) +{ + mon_position=pos; +} + + +int RDMonitorConfig::xOffset() const +{ + return mon_x_offset; +} + + +void RDMonitorConfig::setXOffset(int offset) +{ + mon_x_offset=offset; +} + + +int RDMonitorConfig::yOffset() const +{ + return mon_y_offset; +} + + +void RDMonitorConfig::setYOffset(int offset) +{ + mon_y_offset=offset; +} + + +bool RDMonitorConfig::load() +{ + RDProfile *p=new RDProfile(); + if(!p->setSource(mon_filename)) { + return false; + } + mon_screen_number=p->intValue("Monitor","ScreenNumber",0); + mon_position=(RDMonitorConfig::Position) + p->intValue("Monitor","Position",(int)RDMonitorConfig::UpperLeft); + mon_x_offset=p->intValue("Monitor","XOffset",0); + mon_y_offset=p->intValue("Monitor","YOffset",0); + delete p; + return true; +} + + +bool RDMonitorConfig::save() +{ + FILE *f=NULL; + + if((f=fopen(mon_filename,"w"))==NULL) { + return false; + } + fprintf(f,"[Monitor]\n"); + fprintf(f,"ScreenNumber=%d\n",mon_screen_number); + fprintf(f,"Position=%u\n",mon_position); + fprintf(f,"XOffset=%d\n",mon_x_offset); + fprintf(f,"YOffset=%d\n",mon_y_offset); + fprintf(f,"\n"); + + fclose(f); + return true; +} + + +void RDMonitorConfig::clear() +{ + mon_screen_number=0; + mon_position=RDMonitorConfig::UpperLeft; + mon_x_offset=0; + mon_y_offset=0; +} + + +QString RDMonitorConfig::positionText(RDMonitorConfig::Position pos) +{ + QString ret=QObject::tr("Unknown Position"); + switch(pos) { + case RDMonitorConfig::UpperLeft: + ret=QObject::tr("Top Left"); + break; + + case RDMonitorConfig::UpperCenter: + ret=QObject::tr("Top Center"); + break; + + case RDMonitorConfig::UpperRight: + ret=QObject::tr("Top Right"); + break; + + case RDMonitorConfig::LowerLeft: + ret=QObject::tr("Bottom Left"); + break; + + case RDMonitorConfig::LowerCenter: + ret=QObject::tr("Bottom Center"); + break; + + case RDMonitorConfig::LowerRight: + ret=QObject::tr("Bottom Right"); + break; + + case RDMonitorConfig::LastPosition: + break; + } + return ret; +} diff --git a/lib/rdmonitor_config.h b/lib/rdmonitor_config.h new file mode 100644 index 00000000..ba88c3db --- /dev/null +++ b/lib/rdmonitor_config.h @@ -0,0 +1,57 @@ +// rdmonitor_config.h +// +// A container class for a Rivendell RDMonitor Configuration +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdmonitor_config.h,v 1.1.2.2 2013/11/08 03:57:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDMONITOR_CONFIG_H +#define RDMONITOR_CONFIG_H + +#include <qstring.h> + +class RDMonitorConfig +{ + public: + enum Position {UpperLeft=0,UpperCenter=1,UpperRight=2, + LowerLeft=3,LowerCenter=4,LowerRight=5, + LastPosition=6}; + RDMonitorConfig(); + int screenNumber() const; + void setScreenNumber(int screen); + Position position() const; + void setPosition(RDMonitorConfig::Position pos); + int xOffset() const; + void setXOffset(int offset); + int yOffset() const; + void setYOffset(int offset); + bool load(); + bool save(); + void clear(); + static QString positionText(Position pos); + + private: + int mon_screen_number; + int mon_x_offset; + int mon_y_offset; + Position mon_position; + QString mon_filename; +}; + + +#endif // RDMONITOR_CONFIG_H diff --git a/lib/rdnownext.cpp b/lib/rdnownext.cpp new file mode 100644 index 00000000..7d0f2432 --- /dev/null +++ b/lib/rdnownext.cpp @@ -0,0 +1,209 @@ +// rdnownext.cpp +// +// Rivendell Now & Next Implementation +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdnownext.cpp,v 1.3.8.5 2014/01/07 18:18:29 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <vector> + +#include <qdatetime.h> + +#include <rdnownext.h> +#include <rdweb.h> + +void RDResolveNowNextDateTime(QString *str,const QString &code, + const QDateTime &dt) +{ + int ptr=0; + std::vector<QString> dts; + + while((ptr=str->find(code,ptr))>=0) { + for(unsigned i=ptr+3;i<str->length();i++) { + if(str->at(i)==')') { + dts.push_back(str->mid(ptr+3,i-ptr-3)); + ptr+=(i-ptr-3); + break; + } + } + } + if(dt.isValid()&&(!dt.time().isNull())) { + for(unsigned i=0;i<dts.size();i++) { + str->replace(code+dts[i]+")",dt.toString(dts[i])); + } + } + else { + for(unsigned i=0;i<dts.size();i++) { + str->replace(code+dts[i]+")",""); + } + } +} + + +QString RDResolveNowNextEncode(const QString &str,int encoding) +{ + QString ret=str; + + switch(encoding) { + case RLM_ENCODE_NONE: + break; + + case RLM_ENCODE_XML: + ret=RDXmlEscape(str); + break; + + case RLM_ENCODE_URL: + ret=RDUrlEscape(str); + break; + } + + return ret; +} + +void RDResolveNowNext(QString *str,RDLogLine **loglines,int encoding) +{ + // + // NOW PLAYING Event + // + if(loglines[0]!=NULL) { + str->replace("%n",QString().sprintf("%06u",loglines[0]->cartNumber())); + str->replace("%h",QString().sprintf("%d",loglines[0]->effectiveLength())); + str->replace("%g",RDResolveNowNextEncode(loglines[0]->groupName(), + encoding)); + str->replace("%t", + RDResolveNowNextEncode(loglines[0]->title(),encoding)); + str->replace("%a",RDResolveNowNextEncode(loglines[0]->artist(),encoding)); + str->replace("%l",RDResolveNowNextEncode(loglines[0]->album(),encoding)); + str->replace("%r",RDResolveNowNextEncode(loglines[0]->conductor(), + encoding)); + str->replace("%s",RDResolveNowNextEncode(loglines[0]->songId(),encoding)); + str->replace("%y",loglines[0]->year().toString("yyyy")); + str->replace("%b",RDResolveNowNextEncode(loglines[0]->label(),encoding)); + str->replace("%c",RDResolveNowNextEncode(loglines[0]->client(),encoding)); + str->replace("%e",RDResolveNowNextEncode(loglines[0]->agency(),encoding)); + str->replace("%m",RDResolveNowNextEncode(loglines[0]->composer(),encoding)); + str->replace("%p",RDResolveNowNextEncode(loglines[0]->publisher(), + encoding)); + str->replace("%u",RDResolveNowNextEncode(loglines[0]->userDefined(), + encoding)); + str->replace("%o",RDResolveNowNextEncode(loglines[0]->outcue(),encoding)); + str->replace("%i",RDResolveNowNextEncode(loglines[0]->description(), + encoding)); + RDResolveNowNextDateTime(str,"%d(",loglines[0]->startDatetime()); + } + else { // No NOW PLAYING Event + str->replace("%n",""); + str->replace("%h",""); + str->replace("%g",""); + str->replace("%t",""); + str->replace("%a",""); + str->replace("%l",""); + str->replace("%r",""); + str->replace("%s",""); + str->replace("%y",""); + str->replace("%b",""); + str->replace("%c",""); + str->replace("%e",""); + str->replace("%m",""); + str->replace("%p",""); + str->replace("%u",""); + str->replace("%o",""); + str->replace("%i",""); + RDResolveNowNextDateTime(str,"%d(",QDateTime()); + } + + // + // NEXT Event + // + if(loglines[1]!=NULL) { + str->replace("%N",QString().sprintf("%06u",loglines[1]->cartNumber())); + str->replace("%H",QString().sprintf("%d",loglines[1]->effectiveLength())); + str->replace("%G",RDResolveNowNextEncode(loglines[1]->groupName(), + encoding)); + str->replace("%T",RDResolveNowNextEncode(loglines[1]->title(),encoding)); + str->replace("%A",RDResolveNowNextEncode(loglines[1]->artist(),encoding)); + str->replace("%L",RDResolveNowNextEncode(loglines[1]->album(),encoding)); + str->replace("%R",RDResolveNowNextEncode(loglines[1]->conductor(), + encoding)); + str->replace("%S",RDResolveNowNextEncode(loglines[1]->songId(),encoding)); + str->replace("%Y",loglines[1]->year().toString("yyyy")); + str->replace("%B",RDResolveNowNextEncode(loglines[1]->label(),encoding)); + str->replace("%C",RDResolveNowNextEncode(loglines[1]->client(),encoding)); + str->replace("%E",RDResolveNowNextEncode(loglines[1]->agency(),encoding)); + str->replace("%M",RDResolveNowNextEncode(loglines[1]->composer(),encoding)); + str->replace("%P",RDResolveNowNextEncode(loglines[1]->publisher(), + encoding)); + str->replace("%U",RDResolveNowNextEncode(loglines[1]->userDefined(), + encoding)); + str->replace("%O",RDResolveNowNextEncode(loglines[1]->outcue(),encoding)); + str->replace("%I",RDResolveNowNextEncode(loglines[1]->description(), + encoding)); + RDResolveNowNextDateTime(str,"%D(",loglines[1]->startDatetime()); + } + else { // No NEXT Event + str->replace("%N",""); + str->replace("%H",""); + str->replace("%G",""); + str->replace("%T",""); + str->replace("%A",""); + str->replace("%L",""); + str->replace("%R",""); + str->replace("%S",""); + str->replace("%Y",""); + str->replace("%B",""); + str->replace("%C",""); + str->replace("%E",""); + str->replace("%M",""); + str->replace("%P",""); + str->replace("%U",""); + str->replace("%O",""); + str->replace("%I",""); + RDResolveNowNextDateTime(str,"%D(",QDateTime()); + } + str->replace("%%","%"); + str->replace("\\r","\n"); + str->replace("\\n","\r\n"); +} + + +QString RDResolveNowNext(const QString &pattern,RDLogLine *ll) +{ + QString ret=pattern; + + ret.replace("%n",QString().sprintf("%06u",ll->cartNumber())); + ret.replace("%h",QString().sprintf("%d",ll->effectiveLength())); + ret.replace("%g",ll->groupName()); + ret.replace("%t",ll->title()); + ret.replace("%a",ll->artist()); + ret.replace("%l",ll->album()); + ret.replace("%r",ll->conductor()); + ret.replace("%s",ll->songId()); + ret.replace("%y",ll->year().toString("yyyy")); + ret.replace("%b",ll->label()); + ret.replace("%c",ll->client()); + ret.replace("%e",ll->agency()); + ret.replace("%m",ll->composer()); + ret.replace("%p",ll->publisher()); + ret.replace("%u",ll->userDefined()); + ret.replace("%o",ll->outcue()); + ret.replace("%i",ll->description()); + RDResolveNowNextDateTime(&ret,"%d(",ll->startDatetime()); + + return ret; +} + diff --git a/lib/rdnownext.h b/lib/rdnownext.h new file mode 100644 index 00000000..519b2ad8 --- /dev/null +++ b/lib/rdnownext.h @@ -0,0 +1,33 @@ +// rdnownext.h +// +// Rivendell Now & Next Implementation +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdnownext.h,v 1.3.8.2 2014/01/07 18:18:29 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDNOWNEXT_H +#define RDNOWNEXT_H + +#include <rdlog_line.h> +#include "../rlm/rlm.h" + +void RDResolveNowNext(QString *str,RDLogLine **loglines,int encoding); +QString RDResolveNowNext(const QString &pattern,RDLogLine *ll); + + +#endif // RDNOWNEXT_H diff --git a/lib/rdoneshot.cpp b/lib/rdoneshot.cpp new file mode 100644 index 00000000..601a0a9f --- /dev/null +++ b/lib/rdoneshot.cpp @@ -0,0 +1,72 @@ +// rdoneshot.cpp +// +// A class for providing one-shot single use timers. +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdoneshot.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdoneshot.h> + +RDOneShot::RDOneShot(QObject *parent,const char *name) + : QObject(parent,name) +{ + // + // Timeout Mapper + // + shot_count=0; + shot_mapper=new QSignalMapper(this); + connect(shot_mapper,SIGNAL(mapped(int)),this,SLOT(timeoutData(int))); + + // + // Zombie Timer + // + shot_zombie_timer=new QTimer(this); + connect(shot_zombie_timer,SIGNAL(timeout()),this,SLOT(zombieData())); +} + + +void RDOneShot::start(void *data,int msecs) +{ + shot_pointers[shot_count]=data; + shot_timers[shot_count]=new QTimer(this); + shot_mapper->setMapping(shot_timers[shot_count],shot_count); + connect(shot_timers[shot_count],SIGNAL(timeout()), + shot_mapper,SLOT(map())); + shot_timers[shot_count]->start(msecs,true); + shot_count++; +} + + +void RDOneShot::timeoutData(int id) +{ + emit timeout(shot_pointers[id]); + shot_zombie_timer->start(10,true); +} + + +void RDOneShot::zombieData() +{ + for(std::map<int,QTimer *>::iterator it=shot_timers.begin(); + it!=shot_timers.end();it++) { + if(!it->second->isActive()) { + shot_pointers.erase(it->first); + delete it->second; + shot_timers.erase(it); + } + } +} diff --git a/lib/rdoneshot.h b/lib/rdoneshot.h new file mode 100644 index 00000000..ff258daa --- /dev/null +++ b/lib/rdoneshot.h @@ -0,0 +1,55 @@ +// rdoneshot.h +// +// A class for providing one-shot single use timers. +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdoneshot.h,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDONESHOT_H +#define RDONESHOT_H + +#include <map> + +#include <qobject.h> +#include <qsignalmapper.h> +#include <qtimer.h> + +class RDOneShot : public QObject +{ + Q_OBJECT + public: + RDOneShot(QObject *parent=0,const char *name=0); + void start(void *data,int msecs); + + signals: + void timeout(void *data); + + private slots: + void timeoutData(int id); + void zombieData(); + + private: + std::map<int,QTimer *> shot_timers; + std::map<int,void *> shot_pointers; + QSignalMapper *shot_mapper; + QTimer *shot_zombie_timer; + int shot_count; +}; + + +#endif // RDONESHOT_H diff --git a/lib/rdpam.cpp b/lib/rdpam.cpp new file mode 100644 index 00000000..a65ca8f6 --- /dev/null +++ b/lib/rdpam.cpp @@ -0,0 +1,110 @@ +// rdpam.cpp +// +// Authenticate a PAM name. +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpam.cpp,v 1.2.8.1 2012/12/13 22:33:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <syslog.h> + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <pwd.h> + +#include <security/pam_appl.h> + +#include <qstringlist.h> + +#include <rdpam.h> + +int RDPamCallback(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr) +{ + RDPam *pam=(RDPam *)appdata_ptr; + + pam->CleanupPam(); + *resp=new struct pam_response[num_msg]; + for(int i=0;i<num_msg;i++) { + resp[i]->resp=new char[256]; + memset(resp[i]->resp,0,256); + switch(msg[i]->msg_style) { + case PAM_PROMPT_ECHO_OFF: + strncpy(resp[i]->resp,pam->system_token,255); + break; + + case PAM_PROMPT_ECHO_ON: + syslog(LOG_ERR,"unhandled PAM request: %s",msg[i]->msg); + break; + + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + syslog(LOG_NOTICE,"PAM message: %s",msg[i]->msg); + break; + } + } + return 0; +} + + +RDPam::RDPam(const QString &pam_service) +{ + system_pam_response=NULL; + system_pam_response_count=0; + system_pam_service=pam_service; +} + + +bool RDPam::authenticate(const QString &username,const QString &token) +{ + pam_handle_t *pamh=NULL; + struct pam_conv conv; + int err; + + system_token=token; + memset(&conv,0,sizeof(conv)); + conv.conv=RDPamCallback; + conv.appdata_ptr=(RDPam *)this; + if((err=pam_start(system_pam_service,username,&conv,&pamh))!=PAM_SUCCESS) { + syslog(LOG_NOTICE,"PAM Error: %s",pam_strerror(pamh,err)); + pam_end(pamh,err); + CleanupPam(); + return false; + } + if((err=pam_authenticate(pamh,0))!=PAM_SUCCESS) { + pam_end(pamh,err); + CleanupPam(); + return false; + } + pam_end(pamh,err); + CleanupPam(); + return true; +} + + +void RDPam::CleanupPam() +{ + if(system_pam_response==NULL) { + return; + } + for(int i=0;i<system_pam_response_count;i++) { + delete system_pam_response[i].resp; + } + delete system_pam_response; + system_pam_response=NULL; +} diff --git a/lib/rdpam.h b/lib/rdpam.h new file mode 100644 index 00000000..82f845de --- /dev/null +++ b/lib/rdpam.h @@ -0,0 +1,45 @@ +// rdpam.h +// +// Authenticate a PAM name. +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpam.h,v 1.2 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDPAM_H +#define RDPAM_H + +#include <qstring.h> + +class RDPam +{ + public: + RDPam(const QString &pam_service); + bool authenticate(const QString &username,const QString &token); + + private: + void CleanupPam(); + QString system_pam_service; + QString system_token; + struct pam_response *system_pam_response; + int system_pam_response_count; + friend int RDPamCallback(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr); +}; + + +#endif // RDPAM_H diff --git a/lib/rdpanel_button.cpp b/lib/rdpanel_button.cpp new file mode 100644 index 00000000..92c08c02 --- /dev/null +++ b/lib/rdpanel_button.cpp @@ -0,0 +1,567 @@ +// rdpanel_button.cpp +// +// The SoundPanel Button for RDAirPlay. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpanel_button.cpp,v 1.26.6.9 2014/02/06 20:43:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdconf.h> +#include <rdpanel_button.h> + +#include <qpixmap.h> +#include <qpainter.h> + +#include <rdcartdrag.h> + +RDPanelButton::RDPanelButton(int row,int col,RDStation *station,bool flash, + QWidget *parent,const char *name) + : QPushButton(parent,name) +{ + button_row=row; + button_col=col; + button_station=station; + button_parent=parent; + button_flash=flash; + button_flash_state=false; + button_hook_mode=false; + button_move_count=-1; + button_allow_drags=false; + clear(); +} + + +void RDPanelButton::clear() +{ + setText(""); + setOutputText(""); + setDefaultColor(button_parent->backgroundColor()); + setColor(button_parent->backgroundColor()); + setCart(0); + button_deck=-1; + button_output=-1; + button_play_deck=NULL; + button_start_time=QTime(); + button_end_time=QTime(); + button_active_length=0; + button_length[0]=0; + button_length[1]=0; + button_secs=-1; + button_flashing=false; + button_flash_state=false; + button_state=false; + button_start_source=RDLogLine::StartUnknown; + button_pause_when_finished=false; + button_duck_volume=0; +} + + +QString RDPanelButton::text() const +{ + return button_text; +} + + +void RDPanelButton::setText(const QString &text) +{ + button_text=text; + WriteKeycap(-1); +} + + +QString RDPanelButton::outputText() const +{ + return button_output_text; +} + + +void RDPanelButton::setOutputText(const QString &text) +{ + button_output_text=text; +} + + +bool RDPanelButton::state() const +{ + return button_state; +} + + +void RDPanelButton::setState(bool state) +{ + button_state=state; +} + + +QColor RDPanelButton::defaultColor() const +{ + return button_default_color; +} + + +void RDPanelButton::setDefaultColor(QColor color) +{ + if(color==button_default_color) { + return; + } + button_default_color=color; + if(playDeck()==NULL) { + setColor(color); + } +} + + +RDLogLine::StartSource RDPanelButton::startSource() const +{ + return button_start_source; +} + + +void RDPanelButton::setStartSource(RDLogLine::StartSource src) +{ + button_start_source=src; +} + + +void RDPanelButton::setColor(QColor color) +{ + if(color==button_color) { + return; + } + button_color=color; + if(button_flash) { + if(color==button_parent->backgroundColor()) { + button_flashing=false; + } + else { + button_flashing=true; + } + } + WriteKeycap(button_secs); +} + + +unsigned RDPanelButton::cart() const +{ + return button_cart; +} + + +void RDPanelButton::setCart(unsigned cart) +{ + button_cart=cart; +} + + +QString RDPanelButton::cutName() const +{ + return button_cutname; +} + + +void RDPanelButton::setCutName(const QString &name) +{ + button_cutname=name; +} + + +int RDPanelButton::deck() const +{ + return button_deck; +} + + +void RDPanelButton::setDeck(int deck) +{ + button_deck=deck; +} + + +RDPlayDeck *RDPanelButton::playDeck() const +{ + return button_play_deck; +} + + +void RDPanelButton::setPlayDeck(RDPlayDeck *deck) +{ + button_play_deck=deck; +} + + +QTime RDPanelButton::startTime() const +{ + return button_start_time; +} + + +void RDPanelButton::setStartTime(QTime time) +{ + button_start_time=time; + button_end_time=button_start_time.addMSecs(button_active_length); +} + + +bool RDPanelButton::hookMode() const +{ + return button_hook_mode; +} + + +void RDPanelButton::setHookMode(bool state) +{ + button_hook_mode=state; +} + + +int RDPanelButton::output() const +{ + return button_output; +} + + +void RDPanelButton::setOutput(int outnum) +{ + button_output=outnum; +} + + +int RDPanelButton::length(bool hookmode) const +{ + return button_length[hookmode]; +} + + +void RDPanelButton::setLength(bool hookmode, int msecs) +{ + button_length[hookmode]=msecs; +} + + +void RDPanelButton::setActiveLength(int msecs) +{ + button_active_length=msecs; + button_end_time=button_start_time.addMSecs(button_active_length); + if((button_start_time.isNull())&&(button_cart!=0)) { + WriteKeycap(-1); + } +} + + +void RDPanelButton::reset() +{ + if(button_length[button_hook_mode]>0) { + setActiveLength(button_length[button_hook_mode]); + } + else { + setActiveLength(button_length[0]); + } + button_start_time=QTime(); + button_end_time=QTime(); + setColor(button_default_color); + if(button_cart!=0) { + WriteKeycap(-1); + } + setDeck(-1); + button_play_deck=NULL; +} + + +bool RDPanelButton::pauseWhenFinished() const +{ +return button_pause_when_finished; +} + + +void RDPanelButton::setPauseWhenFinished(bool pause_when_finished) +{ + button_pause_when_finished=pause_when_finished; +} + + +void RDPanelButton::resetCounter() +{ + WriteKeycap(-1); +} + + +void RDPanelButton::setAllowDrags(bool state) +{ + button_allow_drags=state; +} + + +void RDPanelButton::setDuckVolume(int level) +{ + button_duck_volume=level; +} + + +int RDPanelButton::duckVolume() const +{ + return button_duck_volume; +} + + +void RDPanelButton::tickClock() +{ + int secs; + QTime current_time= + QTime::currentTime().addMSecs(button_station->timeOffset()); + if((button_start_time.isNull())||(current_time>button_end_time)|| + ((secs=current_time.secsTo(button_end_time))==button_secs)) { + return; + } + button_secs=secs; + WriteKeycap(secs); +} + + +void RDPanelButton::flashButton(bool state) +{ + if(state==button_flash_state) { + return; + } + button_flash_state=state; + if(button_flashing&&button_state) { + WriteKeycap(button_secs); + } +} + + +void RDPanelButton::keyPressEvent(QKeyEvent *e) +{ + QWidget::keyPressEvent(e); +} + + +void RDPanelButton::keyReleaseEvent(QKeyEvent *e) +{ + QWidget::keyReleaseEvent(e); +} + + +void RDPanelButton::mousePressEvent(QMouseEvent *e) +{ + button_move_count=3; + QPushButton::mousePressEvent(e); +} + + +void RDPanelButton::mouseMoveEvent(QMouseEvent *e) +{ + button_move_count--; + if(button_move_count==0) { + QPushButton::mouseReleaseEvent(e); + if(button_allow_drags) { + RDCartDrag *d=new RDCartDrag(button_cart,button_text,button_color,this); + d->dragCopy(); + } + } +} + + +void RDPanelButton::mouseReleaseEvent(QMouseEvent *e) +{ + button_move_count=-1; + QPushButton::mouseReleaseEvent(e); +} + + +void RDPanelButton::dragEnterEvent(QDragEnterEvent *e) +{ + e->accept(RDCartDrag::canDecode(e)&&button_allow_drags&& + ((button_play_deck==NULL)||(button_play_deck->state()==RDPlayDeck::Stopped))); +} + + +void RDPanelButton::dropEvent(QDropEvent *e) +{ + unsigned cartnum; + QColor color; + QString title; + + if(RDCartDrag::decode(e,&cartnum,&color,&title)) { + emit cartDropped(button_row,button_col,cartnum,color,title); + } +} + + +void RDPanelButton::WriteKeycap(int secs) +{ + QString text=button_text; + QPixmap *pix=new QPixmap(size().width(),size().height()); + QPainter *p=new QPainter(pix); + if(button_state) { + if(button_flash) { + if(button_flash_state) { + p->fillRect(0,0,size().width(),size().height(),button_color); + p->setPen(RDGetTextColor(button_color)); + } + else { + p->fillRect(0,0,size().width(),size().height(),button_default_color); + p->setPen(RDGetTextColor(button_default_color)); + } + } + else { + p->fillRect(0,0,size().width(),size().height(),button_color); + p->setPen(RDGetTextColor(button_color)); + } + } + else { + p->fillRect(0,0,size().width(),size().height(),button_color); + p->setPen(RDGetTextColor(button_color)); + } + + // + // Button Title + // + QFont font("helvetica",13,QFont::Normal); + font.setPixelSize(13); + QFontMetrics m(font); + p->setFont(font); + p->drawText(RDPANEL_BUTTON_MARGIN,m.lineSpacing(), + GetNextLine(&text,m,size().width()-3*RDPANEL_BUTTON_MARGIN)); + p->drawText(RDPANEL_BUTTON_MARGIN,2*m.lineSpacing(), + GetNextLine(&text,m,size().width()-3*RDPANEL_BUTTON_MARGIN)); + p->drawText(RDPANEL_BUTTON_MARGIN,3*m.lineSpacing(), + GetNextLine(&text,m,size().width()-3*RDPANEL_BUTTON_MARGIN)); + + // + // Time Field & Output Text + // + if(!button_text.isEmpty()) { + if(secs<0) { + QFont out_font("helvetica",13,QFont::Normal); + out_font.setPixelSize(13); + p->setFont(out_font); + if(button_pause_when_finished) { + p->drawText(RDPANEL_BUTTON_MARGIN,size().height()-RDPANEL_BUTTON_MARGIN,"Finished"); + } + else { + if(button_active_length>=0) { + p->drawText(RDPANEL_BUTTON_MARGIN,size().height()- + RDPANEL_BUTTON_MARGIN, + RDGetTimeLength(button_active_length+1000,true,false)); + } + else { + p->drawText(RDPANEL_BUTTON_MARGIN,size().height()- + RDPANEL_BUTTON_MARGIN,tr("No Audio")); + } + } + } + else { + if(secs>8) { + p->drawText(RDPANEL_BUTTON_MARGIN,size().height()-RDPANEL_BUTTON_MARGIN, + RDGetTimeLength(1000*(secs+1),true,false)); + } + else { + QFont out_font("helvetica",18,QFont::Bold); + out_font.setPixelSize(18); + p->setFont(out_font); + QString secstr=QString().sprintf(":%d",secs+1); + p->drawText(RDPANEL_BUTTON_MARGIN,size().height()-RDPANEL_BUTTON_MARGIN,secstr); + } + QFont out_font("helvetica",18,QFont::Bold); + out_font.setPixelSize(18); + p->setFont(out_font); + QFontMetrics om(out_font); + p->drawText(size().width()-om.width(button_output_text)- + RDPANEL_BUTTON_MARGIN, + size().height()-RDPANEL_BUTTON_MARGIN,button_output_text); + } + } + p->end(); + setPixmap(*pix); + delete p; + delete pix; +} + + +QString RDPanelButton::WrapText(QString text,int *lines) +{ + QFontMetrics fm(font()); + QString str; + QString residue = text; + bool space_found=false; + int l; + + *lines=0; + if(!text.isEmpty()) { + while(!residue.isEmpty()) { + space_found=false; + for(int i=(int)residue.length();i>=0;i--) { + if((i==((int)residue.length()))||(residue.at(i).isSpace())) { + if(fm.boundingRect(residue.left(i)).width()<=width()-6) { + space_found=true; + if(!str.isEmpty()) { + str+="\n"; + if(++*lines==3) { + return str; + } + } + str+=residue.left(i); + if(i==(int)residue.length()) { + return str; + } + residue=residue.right(residue.length()-i-1); + } + } + } + if(!space_found) { + l=residue.length(); + for(int i=l;i>=0;i--) { + if(fm.boundingRect(residue.left(i)).width()<=(width()-6)) { + if(!str.isEmpty()) { + str+="\n"; + if(++*lines==3) { + return str; + } + } + str+=residue.left(i); + if(i==(int)residue.length()) { + return str; + } + residue=residue.right(residue.length()-i-1); + } + } + } + } + } + return text; +} + + +QString RDPanelButton::GetNextLine(QString *str,const QFontMetrics &m,int len) +{ + QString ret; + + for(unsigned i=0;i<str->length();i++) { + if(m.width(str->left(i))>len) { + int l=i; + while((!str->at(l--).isSpace())&&(l>=0)); + if(l>0) { + ret=str->left(l+1); + *str=str->right(str->length()-l-1).stripWhiteSpace(); + return ret; + } + } + } + ret=*str; + *str=""; + return ret; +} diff --git a/lib/rdpanel_button.h b/lib/rdpanel_button.h new file mode 100644 index 00000000..58af4360 --- /dev/null +++ b/lib/rdpanel_button.h @@ -0,0 +1,136 @@ +// rdpanel_button.h +// +// The SoundPanel Button for RDAirPlay. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpanel_button.h,v 1.18.6.5 2014/02/06 20:43:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDPANEL_BUTTON_H +#define RDPANEL_BUTTON_H + +#include <qdatetime.h> +#include <qpushbutton.h> +#include <qstring.h> +#include <qpalette.h> +#include <qtimer.h> + +#include <rdstation.h> +#include <rdairplay_conf.h> +#include <rdplay_deck.h> +#include <rdlog_line.h> +#include <rdcartdrag.h> + +#define RDPANEL_BUTTON_MARGIN 5 + +class RDPanelButton : public QPushButton +{ + Q_OBJECT + public: + RDPanelButton(int row,int col,RDStation *station,bool flash,QWidget *parent=0, + const char *name=0); + void clear(); + QString text() const; + void setText(const QString &text); + QString outputText() const; + void setOutputText(const QString &text); + bool state() const; + void setState(bool state); + QColor defaultColor() const; + void setDefaultColor(QColor color); + RDLogLine::StartSource startSource() const; + void setStartSource(RDLogLine::StartSource src); + void setColor(QColor color); + unsigned cart() const; + void setCart(unsigned cart); + QString cutName() const; + void setCutName(const QString &name); + int deck() const; + void setDeck(int deck); + QTime startTime() const; + void setStartTime(QTime time); + bool hookMode() const; + void setHookMode(bool state); + RDPlayDeck *playDeck() const; + void setPlayDeck(RDPlayDeck *deck); + int output() const; + void setOutput(int outnum); + int length(bool hookmode) const; + void setLength(bool hookmode, int msecs); + void setActiveLength(int msecs); + void reset(); + bool pauseWhenFinished() const; + void setPauseWhenFinished(bool pause_when_finished); + int duckVolume() const; + void setDuckVolume(int lvel); + void setAllowDrags(bool state); + void resetCounter(); + + signals: + void cartDropped(int row,int col,unsigned cartnum,const QColor &color, + const QString &title); + + public slots: + void tickClock(); + void flashButton(bool state); + + private slots: + void keyPressEvent(QKeyEvent *e); + void keyReleaseEvent(QKeyEvent *e); + + protected: + void mousePressEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void dragEnterEvent(QDragEnterEvent *e); + void dropEvent(QDropEvent *e); + + private: + void WriteKeycap(int secs); + QString WrapText(QString text,int *lines); + QString GetNextLine(QString *str,const QFontMetrics &m,int len); + QColor button_default_color; + QWidget *button_parent; + QString button_text; + QString button_formatted_text; + QString button_output_text; + QColor button_color; + unsigned button_cart; + QString button_cutname; + int button_deck; + QTime button_start_time; + bool button_hook_mode; + QTime button_end_time; + int button_length[2]; + int button_active_length; + int button_secs; + RDStation *button_station; + RDPlayDeck *button_play_deck; + int button_output; + bool button_flash; + bool button_flashing; + bool button_flash_state; + bool button_state; + bool button_pause_when_finished; + int button_duck_volume; + RDLogLine::StartSource button_start_source; + int button_row; + int button_col; + int button_move_count; + bool button_allow_drags; +}; +#endif diff --git a/lib/rdpasswd.cpp b/lib/rdpasswd.cpp new file mode 100644 index 00000000..fce1ad5b --- /dev/null +++ b/lib/rdpasswd.cpp @@ -0,0 +1,156 @@ +// rdpasswd.cpp +// +// Set Password widget for Rivendell. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpasswd.cpp,v 1.12 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qdialog.h> +#include <qstring.h> +#include <qpushbutton.h> +#include <qradiobutton.h> +#include <qlineedit.h> +#include <qtextedit.h> +#include <qlabel.h> +#include <qpainter.h> +#include <qevent.h> +#include <qmessagebox.h> +#include <qbuttongroup.h> +#include <math.h> + +#include <rdpasswd.h> +#include <rdtextvalidator.h> + + +RDPasswd::RDPasswd(QString *password,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont button_font=QFont("Helvetica",14,QFont::Bold); + button_font.setPixelSize(14); + + passwd_password=password; + setCaption(tr("Change Password")); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // OK Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(10,60,100,55); + ok_button->setFont(button_font); + ok_button->setText(tr("&OK")); + ok_button->setDefault(true); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(120,60,100,55); + cancel_button->setFont(button_font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Password + // + passwd_password_1_edit=new QLineEdit(this,"passwd_password_1_edit"); + passwd_password_1_edit->setGeometry(90,11,100,19); + passwd_password_1_edit->setMaxLength(16); + passwd_password_1_edit->setEchoMode(QLineEdit::Password); + passwd_password_1_edit->setFocus(); + passwd_password_1_edit->setValidator(validator); + QLabel *passwd_password_1_label=new QLabel(passwd_password_1_edit, + tr("&Password:"),this, + "passwd_password_1_label"); + passwd_password_1_label->setFont(label_font); + passwd_password_1_label->setGeometry(10,13,75,19); + passwd_password_1_label->setAlignment(AlignRight|ShowPrefix); + + // + // Confirm Password + // + passwd_password_2_edit=new QLineEdit(this,"passwd_password_2_edit"); + passwd_password_2_edit->setGeometry(90,32,100,19); + passwd_password_2_edit->setMaxLength(16); + passwd_password_2_edit->setEchoMode(QLineEdit::Password); + passwd_password_2_edit->setValidator(validator); + QLabel *passwd_password_2_label= + new QLabel(passwd_password_2_edit,tr("C&onfirm:"),this, + "passwd_password_2_label"); + passwd_password_2_label->setFont(label_font); + passwd_password_2_label->setGeometry(10,34,75,19); + passwd_password_2_label->setAlignment(AlignRight|ShowPrefix); + +} + + +RDPasswd::~RDPasswd() +{ + delete passwd_password_1_edit; + delete passwd_password_2_edit; +} + + +QSize RDPasswd::sizeHint() const +{ + return QSize(230,125); +} + + +QSizePolicy RDPasswd::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDPasswd::okData() +{ + if(passwd_password_1_edit->text()==passwd_password_2_edit->text()) { + *passwd_password=passwd_password_1_edit->text(); + done(0); + } + else { + QMessageBox::warning(this,tr("Password Mismatch"), + tr("The passwords don't match,\nplease try again!"), + tr("OK"),0); + } +} + + +void RDPasswd::cancelData() +{ + done(1); +} diff --git a/lib/rdpasswd.h b/lib/rdpasswd.h new file mode 100644 index 00000000..5a0d4c37 --- /dev/null +++ b/lib/rdpasswd.h @@ -0,0 +1,56 @@ +// rdpasswd.h +// +// Set Password Widget for Rivendell. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpasswd.h,v 1.6 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDPASSWD_H +#define RDPASSWD_H + +#include <qdialog.h> +#include <qlineedit.h> +#include <qtextedit.h> +#include <qpixmap.h> +#include <qradiobutton.h> + + +class RDPasswd : public QDialog +{ + Q_OBJECT + public: + RDPasswd(QString *password,QWidget *parent=0,const char *name=0); + ~RDPasswd(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *passwd_password_1_edit; + QLineEdit *passwd_password_2_edit; + QString *passwd_password; +}; + + +#endif + diff --git a/lib/rdpaths.h.in b/lib/rdpaths.h.in new file mode 100644 index 00000000..7f988f3f --- /dev/null +++ b/lib/rdpaths.h.in @@ -0,0 +1,50 @@ +// rdpaths.h +// +// Install-Dependent Path Values for Rivendell +// +// (C) Copyright 2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpaths.h.in,v 1.6 2011/03/26 01:37:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDPATHS_H +#define RDPATHS_H + +/* + * Rivendell Loadable Modules Directory + */ +#define RD_MODULES_DIR "@prefix@/@RD_LIB_PATH@/rivendell" + +/* + * Default Skins + */ +#define RD_DEFAULT_RDAIRPLAY_SKIN "@prefix@/share/pixmaps/rivendell/rdairplay_skin.png" +#define RD_DEFAULT_RDPANEL_SKIN "@prefix@/share/pixmaps/rivendell/rdpanel_skin.png" + +/* + * CD Paranoia Includes + */ +extern "C" { +#include @PARANOIA_INCLUDES@ +} + +/* + * Installation Prefix + */ +#define RD_PREFIX "@prefix@" + + +#endif // RDPATHS_H diff --git a/lib/rdpeaksexport.cpp b/lib/rdpeaksexport.cpp new file mode 100644 index 00000000..91e26acb --- /dev/null +++ b/lib/rdpeaksexport.cpp @@ -0,0 +1,229 @@ +// rdpeaksexport.cpp +// +// Export peak data using the RdXport Web Service +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpeaksexport.cpp,v 1.6.4.5 2013/11/13 23:36:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> + +#include <curl/curl.h> + +#include <qapplication.h> +#include <qobject.h> + +#include <rd.h> +#include <rdxport_interface.h> +#include <rdformpost.h> +#include <rdpeaksexport.h> + +// +// LibCURL Write Callback +// +size_t RDPeaksExportWrite(void *ptr, size_t size, size_t nmemb, void *userdata) +{ + RDPeaksExport *peaks=(RDPeaksExport *)userdata; + int bytes=size*nmemb; + peaks->conv_energy_data= + (unsigned short *)realloc(peaks->conv_energy_data,peaks->conv_write_ptr+bytes); + for(int i=0;i<bytes;i++) { + ((uint8_t *)peaks->conv_energy_data)[i+peaks->conv_write_ptr]= + ((uint8_t *)ptr)[i]; + } + peaks->conv_write_ptr+=bytes; + return size*nmemb; +} + + +RDPeaksExport::~RDPeaksExport() +{ + if(conv_energy_data!=NULL) { + free(conv_energy_data); + } +} + + +RDPeaksExport::RDPeaksExport(RDStation *station,RDConfig *config, + QObject *parent,const char *name) +{ + conv_station=station; + conv_config=config; + conv_cart_number=0; + conv_cut_number=0; + conv_energy_data=NULL; + conv_write_ptr=0; +} + + +void RDPeaksExport::setCartNumber(unsigned cartnum) +{ + conv_cart_number=cartnum; +} + + +void RDPeaksExport::setCutNumber(unsigned cutnum) +{ + conv_cut_number=cutnum; +} + + +RDPeaksExport::ErrorCode RDPeaksExport::runExport(const QString &username, + const QString &password) +{ + long response_code; + CURL *curl=NULL; + CURLcode curl_err; + char url[1024]; + + // + // Generate POST Data + // + QString post=QString(). + sprintf("COMMAND=%d&LOGIN_NAME=%s&PASSWORD=%s&CART_NUMBER=%u&CUT_NUMBER=%u", + RDXPORT_COMMAND_EXPORT_PEAKS, + (const char *)RDFormPost::urlEncode(username), + (const char *)RDFormPost::urlEncode(password), + conv_cart_number, + conv_cut_number); + + if((curl=curl_easy_init())==NULL) { + return RDPeaksExport::ErrorInternal; + } + curl_easy_setopt(curl,CURLOPT_WRITEDATA,this); + curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,RDPeaksExportWrite); + + // + // Write out URL as a C string before passing to curl_easy_setopt(), + // otherwise some versions of LibCurl will throw a 'bad/illegal format' + // error. + // + strncpy(url,conv_station->webServiceUrl(conv_config),1024); + curl_easy_setopt(curl,CURLOPT_URL,url); + curl_easy_setopt(curl,CURLOPT_POST,1); + curl_easy_setopt(curl,CURLOPT_POSTFIELDS,(const char *)post); + curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT); + curl_easy_setopt(curl,CURLOPT_NOPROGRESS,1); + //curl_easy_setopt(curl,CURLOPT_VERBOSE,1); + + switch((curl_err=curl_easy_perform(curl))) { + case CURLE_OK: + break; + + case CURLE_ABORTED_BY_CALLBACK: + curl_easy_cleanup(curl); + return RDPeaksExport::ErrorAborted; + + case CURLE_UNSUPPORTED_PROTOCOL: + case CURLE_FAILED_INIT: + case CURLE_COULDNT_RESOLVE_PROXY: + case CURLE_PARTIAL_FILE: + case CURLE_HTTP_RETURNED_ERROR: + case CURLE_WRITE_ERROR: + case CURLE_OUT_OF_MEMORY: + case CURLE_OPERATION_TIMEDOUT: + case CURLE_HTTP_POST_ERROR: + curl_easy_cleanup(curl); + return RDPeaksExport::ErrorInternal; + + case CURLE_URL_MALFORMAT: + case CURLE_COULDNT_RESOLVE_HOST: + case CURLE_COULDNT_CONNECT: + case 9: // CURLE_REMOTE_ACCESS_DENIED + curl_easy_cleanup(curl); + return RDPeaksExport::ErrorUrlInvalid; + } + curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&response_code); + curl_easy_cleanup(curl); + + switch(response_code) { + case 200: + break; + + case 403: + return RDPeaksExport::ErrorInvalidUser; + + default: + return RDPeaksExport::ErrorService; + } + return RDPeaksExport::ErrorOk; +} + + +QString RDPeaksExport::errorText(RDPeaksExport::ErrorCode err) +{ + QString ret=QString().sprintf("Unknown Error [%u]",err); + + switch(err) { + case RDPeaksExport::ErrorOk: + ret=QObject::tr("OK"); + break; + + case RDPeaksExport::ErrorNoSource: + ret=QObject::tr("No such cart/cut"); + break; + + case RDPeaksExport::ErrorInternal: + ret=QObject::tr("Internal Error"); + break; + + case RDPeaksExport::ErrorUrlInvalid: + ret=QObject::tr("Invalid URL"); + break; + + case RDPeaksExport::ErrorService: + ret=QObject::tr("RDXport service returned an error"); + break; + + case RDPeaksExport::ErrorInvalidUser: + ret=QObject::tr("Invalid user or password"); + break; + + case RDPeaksExport::ErrorAborted: + ret=QObject::tr("Aborted"); + break; + } + return ret; +} + + +unsigned RDPeaksExport::energySize() +{ + return conv_write_ptr/sizeof(unsigned short); +} + + +unsigned short RDPeaksExport::energy(unsigned frame) +{ + return conv_energy_data[frame]; +} + + +int RDPeaksExport::readEnergy(unsigned short buf[],int count) +{ + for(int i=0;i<count;i++) { + buf[i]=conv_energy_data[i]; + } + return count; +} diff --git a/lib/rdpeaksexport.h b/lib/rdpeaksexport.h new file mode 100644 index 00000000..bc30bb13 --- /dev/null +++ b/lib/rdpeaksexport.h @@ -0,0 +1,62 @@ +// rdpeaksexport.h +// +// Export peak data using the RdXport Web Service +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpeaksexport.h,v 1.1.6.1 2013/11/13 23:36:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDPEAKSEXPORT_H +#define RDPEAKSEXPORT_H + +#include <qobject.h> + +#include <rdconfig.h> +#include <rdstation.h> +#include <rdsettings.h> + +class RDPeaksExport +{ + public: + enum ErrorCode {ErrorOk=0,ErrorNoSource=2, + ErrorInternal=5,ErrorUrlInvalid=7, + ErrorService=8,ErrorInvalidUser=9,ErrorAborted=10}; + RDPeaksExport(RDStation *station,RDConfig *config,QObject *parent=0, + const char *name=0); + ~RDPeaksExport(); + void setCartNumber(unsigned cartnum); + void setCutNumber(unsigned cutnum); + RDPeaksExport::ErrorCode runExport(const QString &username, + const QString &password); + unsigned energySize(); + unsigned short energy(unsigned frame); + int readEnergy(unsigned short buf[],int count); + static QString errorText(RDPeaksExport::ErrorCode err); + + private: + RDStation *conv_station; + RDConfig *conv_config; + unsigned conv_cart_number; + unsigned conv_cut_number; + unsigned short *conv_energy_data; + unsigned conv_write_ptr; + friend size_t RDPeaksExportWrite(void *ptr, size_t size, size_t nmemb, + void *userdata); +}; + + +#endif // RDPEAKSEXPORT_H diff --git a/lib/rdplay_deck.cpp b/lib/rdplay_deck.cpp new file mode 100644 index 00000000..a0f53aaa --- /dev/null +++ b/lib/rdplay_deck.cpp @@ -0,0 +1,777 @@ +// rdplay_deck.cpp +// +// Abstract a Rivendell Playback Deck +// +// (C) Copyright 2003-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdplay_deck.cpp,v 1.85.8.5 2013/05/21 19:04:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsignalmapper.h> + +#include <rdplay_deck.h> +#include <rdmixer.h> + +RDPlayDeck::RDPlayDeck(RDCae *cae,int id,QObject *parent,const char *name) + : QObject(parent,name) +{ + play_id=id; + play_state=RDPlayDeck::Stopped; + play_start_time=QTime(); + play_owner=-1; + play_last_start_position=0; + play_handle=-1; + play_audio_length=0; + play_channel=-1; + play_hook_mode=false; + + play_cut_gain=0; + play_duck_level=0; + play_duck_gain[0]=0; + play_duck_gain[1]=0; + play_duck_up=RDPLAYDECK_DUCKUP_LENGTH; + play_duck_down=RDPLAYDECK_DUCKDOWN_LENGTH; + play_duck_up_point=0; + play_duck_down_state=false; + play_fade_down_state=false; + + // + // CAE Connection + // + play_cae=cae; + connect(play_cae,SIGNAL(playing(int)),this,SLOT(playingData(int))); + connect(play_cae,SIGNAL(playStopped(int)),this,SLOT(playStoppedData(int))); + play_cart=NULL; + play_cut=NULL; + play_card=-1; + play_stream=-1; + + // + // Timers + // + QSignalMapper *mapper=new QSignalMapper(this,"timer_mapper"); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(pointTimerData(int))); + for(int i=0;i<3;i++) { + play_point_timer[i]=new QTimer(this,"point_timer"); + connect(play_point_timer[i],SIGNAL(timeout()),mapper,SLOT(map())); + mapper->setMapping(play_point_timer[i],i); + } + play_position_timer=new QTimer(this,"play_position_timer"); + connect(play_position_timer,SIGNAL(timeout()), + this,SLOT(positionTimerData())); + play_fade_timer=new QTimer(this,"play_fade_timer"); + connect(play_fade_timer,SIGNAL(timeout()),this,SLOT(fadeTimerData())); + play_stop_timer=new QTimer(this,"play_stop_timer"); + connect(play_stop_timer,SIGNAL(timeout()),this,SLOT(stop())); + play_duck_timer=new QTimer(this,"play_duck_timer"); + connect(play_duck_timer,SIGNAL(timeout()),this,SLOT(duckTimerData())); +} + + +RDPlayDeck::~RDPlayDeck() +{ + if(play_state!=RDPlayDeck::Stopped) { + play_cae->stopPlay(play_handle); + play_cae->unloadPlay(play_handle); + } +} + + +int RDPlayDeck::id() const +{ + return play_id; +} + + +void RDPlayDeck::setId(int id) +{ + play_id=id; +} + + +int RDPlayDeck::owner() const +{ + return play_owner; +} + + +void RDPlayDeck::setOwner(int owner) +{ + play_owner=owner; +} + + +RDCart *RDPlayDeck::cart() const +{ + return play_cart; +} + + +bool RDPlayDeck::setCart(RDLogLine *logline,bool rotate) +{ + play_timescale_active=logline->timescalingActive(); + if((play_cart!=NULL)&&(rotate||play_cart->number()!=logline->cartNumber())) { + delete play_cart; + delete play_cut; + play_cart=NULL; + play_cut=NULL; + } + if(play_cart==NULL) { + StopTimers(); + play_cart=new RDCart(logline->cartNumber()); + if(!play_cart->exists()) { + delete play_cart; + play_cart=NULL; + return false; + } + + QString cutname=logline->cutName(); + // + // FIXME: We need to handle the 'cut no longer valid' case better! + // + //if(play_cart->selectCut(&cutname)) { This fixes problems with cuts of different length in one cart. + // logline->setCutName(cutname); We do not need to select a cut, because it is done immediatly before + //} this method is called. + if(cutname.isEmpty()) { + return false; + } + play_cut=new RDCut(cutname); + if(!play_cut->exists()) { + delete play_cut; + play_cut=NULL; + return false; + } + } + if(logline->startPoint(RDLogLine::LogPointer)<0) { + play_forced_length=logline->forcedLength(); + /* + play_audio_point[0]=logline->startPoint(); + play_audio_point[1]=logline->endPoint(); + */ + play_audio_point[0]=play_cut->startPoint(RDLogLine::CartPointer); + play_audio_point[1]=play_cut->endPoint(); + } + else { + play_forced_length=logline->effectiveLength(); + play_audio_point[0]=logline->startPoint(RDLogLine::LogPointer); + play_audio_point[1]=logline->endPoint(); + } + if(logline->endPoint(RDLogLine::LogPointer)>=0) { + play_forced_length=logline->effectiveLength(); + play_audio_point[0]=logline->startPoint(); + play_audio_point[1]=logline->endPoint(RDLogLine::LogPointer); + } + if(play_timescale_active) { + play_timescale_speed= + (int)(RD_TIMESCALE_DIVISOR*(double)(play_audio_point[1]- + play_audio_point[0])/ + (double)play_forced_length); + if((((double)play_timescale_speed)< + (RD_TIMESCALE_DIVISOR*RD_TIMESCALE_MIN))|| + (((double)play_timescale_speed)> + (RD_TIMESCALE_DIVISOR*RD_TIMESCALE_MAX))) { + play_timescale_speed=(int)RD_TIMESCALE_DIVISOR; + play_timescale_active=false; + } + } + else { + play_timescale_speed=(int)RD_TIMESCALE_DIVISOR; + } + play_audio_length=play_audio_point[1]-play_audio_point[0]; + if(logline->segueStartPoint(RDLogLine::AutoPointer)<0) { + play_point_value[RDPlayDeck::Segue][0]= + (int)((double)play_cut->segueStartPoint()); + play_point_value[RDPlayDeck::Segue][1]= + (int)((double)play_cut->segueEndPoint()); + } + else { + play_point_value[RDPlayDeck::Segue][0]= + (int)((double)logline->segueStartPoint(RDLogLine::AutoPointer)); + play_point_value[RDPlayDeck::Segue][1]= + (int)((double)logline->segueEndPoint(RDLogLine::AutoPointer)); + } + play_point_gain=logline->segueGain(); + play_point_value[RDPlayDeck::Hook][0]= + (int)((double)play_cut->hookStartPoint()); + play_point_value[RDPlayDeck::Hook][1]= + (int)((double)play_cut->hookEndPoint()); + logline->setHookStartPoint(play_point_value[RDPlayDeck::Hook][0]); + logline->setHookEndPoint(play_point_value[RDPlayDeck::Hook][1]); + play_point_value[RDPlayDeck::Talk][0]= + (int)((double)play_cut->talkStartPoint()* + (RD_TIMESCALE_DIVISOR/(double)play_timescale_speed)); + play_point_value[RDPlayDeck::Talk][1]= + (int)((double)play_cut->talkEndPoint()* + (RD_TIMESCALE_DIVISOR/(double)play_timescale_speed)); + logline->setTalkStartPoint(play_point_value[RDPlayDeck::Talk][0]); + logline->setTalkEndPoint(play_point_value[RDPlayDeck::Talk][1]); + if(logline->fadeupPoint(RDLogLine::LogPointer)<0) { + play_fade_point[0]=play_cut->fadeupPoint(); + play_fade_gain[0]=RD_FADE_DEPTH; + } + else { + play_fade_point[0]=logline->fadeupPoint(RDLogLine::LogPointer); + play_fade_gain[0]=logline->fadeupGain(); + } + if(logline->fadedownPoint(RDLogLine::LogPointer)<0) { + play_fade_point[1]=play_cut->fadedownPoint(); + play_fade_gain[1]=RD_FADE_DEPTH; + } + else { + play_fade_point[1]=logline->fadedownPoint(RDLogLine::LogPointer); + play_fade_gain[1]=logline->fadedownGain(); + } + play_duck_gain[0]=logline->duckUpGain(); + play_duck_gain[1]=logline->duckDownGain(); + +/* + if(play_timescale_active) { + play_timescale_speed= + (int)(1000*(double)(play_audio_point[1]-play_audio_point[0])/ + (double)play_forced_length); + } + else { + play_timescale_speed=1000; + } +*/ + + if(play_state!=RDPlayDeck::Paused) { + if(!play_cae->loadPlay(play_card,play_cut->cutName(), + &play_stream,&play_handle)) { + return false; + } + } + play_state=RDPlayDeck::Stopped; + return true; +} + + +RDCut *RDPlayDeck::cut() const +{ + return play_cut; +} + + +bool RDPlayDeck::playable() const +{ + if(play_handle<0) { + return false; + } + return true; +} + + +int RDPlayDeck::card() const +{ + return play_card; +} + + +void RDPlayDeck::setCard(int card_num) +{ + play_card=card_num; +} + + +int RDPlayDeck::stream() const +{ + return play_stream; +} + + +int RDPlayDeck::port() const +{ + return play_port; +} + + +void RDPlayDeck::setPort(int port_num) +{ + play_port=port_num; +} + + +int RDPlayDeck::channel() const +{ + return play_channel; +} + + +void RDPlayDeck::setChannel(int chan) +{ + play_channel=chan; +} + + +RDPlayDeck::State RDPlayDeck::state() const +{ + return play_state; +} + + +QTime RDPlayDeck::startTime() const +{ + return play_start_time; +} + + +int RDPlayDeck::currentPosition() const +{ + switch(play_state) { + case RDPlayDeck::Playing: + return play_start_position+ + play_start_time.msecsTo(QTime::currentTime()); + + case RDPlayDeck::Paused: + return play_current_position+POSITION_INTERVAL; + + default: + return play_start_position; + } + return 0; +} + + +int RDPlayDeck::lastStartPosition() const +{ + return play_last_start_position; +} + + +void RDPlayDeck::clear() +{ + StopTimers(); + switch(play_state) { + case RDPlayDeck::Playing: + case RDPlayDeck::Stopping: + stop(); + break; + + case RDPlayDeck::Paused: + play_cae->unloadPlay(play_handle); + emit stateChanged(play_id,RDPlayDeck::Stopped); + break; + + default: + emit stateChanged(play_id,RDPlayDeck::Stopped); + break; + } +} + + +void RDPlayDeck::reset() +{ + StopTimers(); + switch(play_state) { + case RDPlayDeck::Playing: + case RDPlayDeck::Stopping: + play_cae->stopPlay(play_handle); + + case RDPlayDeck::Paused: + play_cae->unloadPlay(play_handle); + break; + + default: + break; + } + play_state=RDPlayDeck::Stopped; +} + + +void RDPlayDeck::play(unsigned pos,int segue_start,int segue_end, + int duck_up_end) +{ + int fadeup; + play_hook_mode=false; + play_cut_gain=play_cut->playGain(); + + play_ducked=0; + if(duck_up_end==-1) { //ducked until stop (for recording in voice tracker) + play_ducked=play_duck_gain[0]; + play_duck_up_point=0; + } + else { + play_duck_up_point=duck_up_end-play_duck_up; + } + if(play_duck_up_point<0) + play_duck_up_point=0; + else + play_ducked=play_duck_gain[0]; + + if(play_handle<0) { + return; + } + if(segue_start>=0) { + play_point_value[RDPlayDeck::Segue][0]=segue_start; + } + if(segue_end>=0) { + play_point_value[RDPlayDeck::Segue][1]=segue_end; + } + play_start_position=pos; + play_current_position=pos; + play_last_start_position=play_start_position; + stop_called=false; + pause_called=false; + play_cae->positionPlay(play_handle,play_audio_point[0]+pos); + play_cae->setPlayPortActive(play_card,play_port,play_stream); + for(int i=0;i<RD_MAX_PORTS;i++) { + play_cae->setOutputVolume(play_card,play_stream,i,RD_MUTE_DEPTH); + } + if((play_fade_point[0]==-1)||(play_fade_point[0]==play_audio_point[0])|| + ((fadeup=play_fade_point[0]-play_audio_point[0]-pos)<=0)|| + (play_state==RDPlayDeck::Paused)) { + if((play_fade_point[1]==-1)||((fadeup=pos-play_fade_point[1])<=0)|| + (play_state==RDPlayDeck::Paused)) { + play_cae->setOutputVolume(play_card,play_stream,play_port, + play_ducked+play_cut_gain+play_duck_level); + play_cae->fadeOutputVolume(play_card,play_stream,play_port, + play_ducked+play_cut_gain+play_duck_level,10); + } + else { // Fadedown event in progress, interpolate the gain accordingly + int level=play_fade_gain[1]*((int)pos-play_fade_point[1])/ + (play_audio_point[1]-play_fade_point[1]); + play_cae-> + setOutputVolume(play_card,play_stream,play_port, + level+play_cut_gain+play_duck_level); + play_cae->fadeOutputVolume(play_card,play_stream,play_port, + play_fade_gain[1]+play_cut_gain+ + play_duck_level, + play_audio_point[1]-(int)pos); + } + } + else { // FadeUp event in progress, interpolate the gain accordingly + int level=(play_fade_gain[0]*fadeup/ + (play_fade_point[0]-play_audio_point[0])); + if (level>play_ducked) { + play_cae-> + setOutputVolume(play_card,play_stream,play_port, + play_ducked+play_cut_gain+play_duck_level); + play_cae->fadeOutputVolume(play_card,play_stream,play_port, + play_ducked+play_cut_gain+play_duck_level, + fadeup); + } + else { + play_cae-> + setOutputVolume(play_card,play_stream,play_port, + level+play_cut_gain+play_duck_level); + play_cae->fadeOutputVolume(play_card,play_stream,play_port, + play_ducked+play_cut_gain+play_duck_level, + fadeup); + } + } + play_cae-> + play(play_handle, + (int)(100000.0*(double)(play_audio_point[1]-play_audio_point[0]-pos)/ + (double)play_timescale_speed), + play_timescale_speed,false); + play_start_time=QTime::currentTime(); + StartTimers(pos); + play_state=RDPlayDeck::Playing; +} + + +void RDPlayDeck::playHook() +{ + play(play_point_value[RDPlayDeck::Hook][0]-play_audio_point[0]); + play_hook_mode=true; +} + + +void RDPlayDeck::pause() +{ + pause_called=true; + play_state=RDPlayDeck::Paused; + play_cae->stopPlay(play_handle); +} + + +void RDPlayDeck::stop() +{ + if((play_state!=RDPlayDeck::Playing)&&(play_state!=RDPlayDeck::Stopping)) { + return; + } + if(pause_called) { + play_state=RDPlayDeck::Stopped; + } + else { + stop_called=true; + play_state=RDPlayDeck::Stopping; + play_cae->stopPlay(play_handle); + } +} + + +void RDPlayDeck::stop(int interval,int gain) +{ + int level; + + if(gain>play_point_gain) { + play_point_gain=gain; + } + + + if((play_state!=RDPlayDeck::Playing)&&(play_state!=RDPlayDeck::Stopping)) { + return; + } + if((interval<=0)||pause_called) { + stop(); + } + else { + if(play_duck_gain[1]<0 && play_duck_down<interval && + (play_audio_point[1]-play_audio_point[0]- + currentPosition())>play_duck_down) { // duck + if(play_audio_point[0]+currentPosition()>play_fade_point[1]) { + level=play_fade_gain[1]*((currentPosition()+play_audio_point[0])- + play_fade_point[1])/(play_audio_point[1]-play_fade_point[1]); + } + else { + level=0; + } + if(level>play_duck_gain[1]){ + play_cae->fadeOutputVolume(play_card,play_stream,play_port, + play_duck_gain[1]+play_cut_gain+play_duck_level,play_duck_down); + play_duck_timer->start(play_duck_down,true); + play_duck_down_state=true; + play_segue_interval=interval; + } + } + else { + if(play_point_gain!=0) { + play_cae->fadeOutputVolume(play_card,play_stream,play_port, + play_point_gain+play_cut_gain+play_duck_level,interval); + } + } + play_stop_timer->start(interval,true); + stop_called=true; + play_state=RDPlayDeck::Stopping; + } +} + + + + +void RDPlayDeck::duckDown(int interval) +{ + if(play_duck_gain[1]<0) { + play_cae->fadeOutputVolume(play_card,play_stream,play_port, + play_duck_gain[1]+play_cut_gain+play_duck_level,play_duck_down); + play_duck_timer->start(play_duck_down,true); + play_duck_down_state=true; + play_segue_interval=interval; + + } +} + + +void RDPlayDeck::duckVolume(int level,int fade) +{ + play_duck_level=level; + if((state()==RDPlayDeck::Playing || state()==RDPlayDeck::Stopping) && fade>0) { + play_cae->fadeOutputVolume(play_card,play_stream,play_port,play_cut_gain+play_duck_level, + fade); + } +} + + +void RDPlayDeck::playingData(int handle) +{ + if(handle!=play_handle) { + return; + } + play_position_timer->start(POSITION_INTERVAL); + emit stateChanged(play_id,RDPlayDeck::Playing); +} + + +void RDPlayDeck::playStoppedData(int handle) +{ + if(handle!=play_handle) { + return; + } + play_position_timer->stop(); + play_start_time=QTime(); + StopTimers(); + if(pause_called) { + play_state=RDPlayDeck::Paused; + emit stateChanged(play_id,RDPlayDeck::Paused); + } + else { + play_cae->unloadPlay(play_handle); + + play_handle=-1; + play_state=RDPlayDeck::Stopped; + play_current_position=0; + play_duck_down_state=false; + play_fade_down_state=false; + if(stop_called) { + emit stateChanged(play_id,RDPlayDeck::Stopped); + } + else { + emit stateChanged(play_id,RDPlayDeck::Finished); + } + } +} + + +void RDPlayDeck::pointTimerData(int point) +{ + switch(point) { + case RDPlayDeck::Segue: + if(play_point_state[point]) { + play_point_state[point]=false; + emit segueEnd(play_id); + } + else { + play_point_state[point]=true; + play_point_timer[point]-> + start(play_point_value[point][1]-play_point_value[point][0],true); + emit segueStart(play_id); + } + break; + + case RDPlayDeck::Hook: + if(play_point_state[point]) { + play_point_state[point]=false; + emit hookEnd(play_id); + } + else { + play_point_state[point]=true; + play_point_timer[point]-> + start(play_point_value[point][1]-play_point_value[point][0],true); + emit hookStart(play_id); + } + break; + + case RDPlayDeck::Talk: + if(play_point_state[point]) { + play_point_state[point]=false; + emit talkEnd(play_id); + } + else { + play_point_state[point]=true; + play_point_timer[point]-> + start(play_point_value[point][1]-play_point_value[point][0],true); + emit talkStart(play_id); + } + break; + } +} + + +void RDPlayDeck::positionTimerData() +{ + play_current_position= + play_start_position+play_start_time.msecsTo(QTime::currentTime()); + if(play_current_position<0) { // Handle crossing midnight! + play_current_position+=86400000; + } + if(play_hook_mode) { + emit position(play_id,play_current_position-(play_point_value[RDPlayDeck::Hook][0]-play_audio_point[0])); + } + else { + emit position(play_id,play_current_position); + } +} + + +void RDPlayDeck::fadeTimerData() +{ + if(!play_duck_down_state) { + play_cae-> + fadeOutputVolume(play_card,play_stream,play_port,play_fade_gain[1]+play_cut_gain+play_duck_level, + play_fade_down); + } + play_fade_down_state=true; +} + + +void RDPlayDeck::duckTimerData() +{ + if (!play_duck_down_state) { //duck up + play_cae-> + fadeOutputVolume(play_card,play_stream,play_port,0+play_cut_gain+play_duck_level,play_duck_up); + play_ducked=0; + } + else { //duck down + if(play_point_gain!=0) { + play_cae->fadeOutputVolume(play_card,play_stream,play_port, + play_point_gain+play_cut_gain+play_duck_level, + play_segue_interval-play_duck_down); + } + else { + if(play_fade_down_state && + play_fade_gain[1]<play_duck_gain[1]) { //fade down in progress + play_cae->fadeOutputVolume(play_card,play_stream,play_port, + play_fade_gain[1]+play_cut_gain+play_duck_level, + play_segue_interval-play_duck_down); + } + } + play_duck_down_state=false; + } +} + + +void RDPlayDeck::StartTimers(int offset) +{ + int audio_point; + + for(int i=0;i<RDPlayDeck::SizeOf;i++) { + play_point_state[i]=false; + if(play_point_value[i][0]!=-1) { + audio_point=(int) + (RD_TIMESCALE_DIVISOR*(double)play_audio_point[0]/ + (double)play_timescale_speed); + if((play_point_value[i][0]-audio_point-offset)>=0) { + play_point_timer[i]-> + start(play_point_value[i][0]-audio_point-offset,true); + } + else { + if((play_point_value[i][1]-audio_point-offset)>=0) { + play_point_state[i]=true; + play_point_timer[i]-> + start(play_point_value[i][1]-audio_point-offset,true); + } + } + } + } + if((play_fade_point[1]!=-1)&&(offset<play_fade_point[1])&& + ((play_fade_down=play_audio_point[1]-play_fade_point[1])>0)) { + play_fade_timer->start(play_fade_point[1]-play_audio_point[0]-offset,true); + } + if(offset<play_duck_up_point){ + play_duck_timer-> + start(play_duck_up_point-offset,true); + } +} + + +void RDPlayDeck::StopTimers() +{ + for(int i=0;i<RDPlayDeck::SizeOf;i++) { + if(play_point_timer[i]->isActive()) { + play_point_timer[i]->stop(); + } + } + if(play_fade_timer->isActive()) { + play_fade_timer->stop(); + } + if(play_stop_timer->isActive()) { + play_stop_timer->stop(); + } + if(play_duck_timer->isActive()) { + play_duck_timer->stop(); + } +} diff --git a/lib/rdplay_deck.h b/lib/rdplay_deck.h new file mode 100644 index 00000000..4b955d0f --- /dev/null +++ b/lib/rdplay_deck.h @@ -0,0 +1,150 @@ +// rdplay_deck.h +// +// Abstract a Rivendell Playback Deck +// +// (C) Copyright 2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdplay_deck.h,v 1.36.8.1 2013/05/21 19:04:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qdatetime.h> +#include <qsqldatabase.h> +#include <qobject.h> +#include <qtimer.h> + +#include <rdcae.h> +#include <rdcart.h> +#include <rdcut.h> +#include <rdlog_line.h> + +#ifndef RDPLAY_DECK_H +#define RDPLAY_DECK_H + +#define POSITION_INTERVAL 100 +#define RDPLAYDECK_AUDITION_ID 2147483647 +#define RDPLAYDECK_DUCKDOWN_LENGTH 750 +#define RDPLAYDECK_DUCKUP_LENGTH 1500 + +class RDPlayDeck : public QObject +{ + Q_OBJECT + + public: + enum State {Stopped=0,Stopping=1,Playing=2,Paused=3,Finished=4}; + RDPlayDeck(RDCae *cae,int id,QObject *parent=0,const char *name=0); + ~RDPlayDeck(); + int id() const; + void setId(int id); + int owner() const; + void setOwner(int owner); + RDCart *cart() const; + bool setCart(RDLogLine *logline,bool rotate); + RDCut *cut() const; + bool playable() const; + int card() const; + void setCard(int card_num); + int stream() const; + int port() const; + void setPort(int port_num); + int channel() const; + void setChannel(int chan); + RDPlayDeck::State state() const; + QTime startTime() const; + int currentPosition() const; + int lastStartPosition() const; + void clear(); + void reset(); + + public slots: + void play(unsigned pos,int segue_start=-1,int segue_end=-1,int duck_up_end=0); + void playHook(); + void pause(); + void stop(); + // void stop(int interval); + void stop(int interval,int gain=-10000); + void duckDown(int interval); + void duckVolume(int level,int fade); + + signals: + void stateChanged(int id,RDPlayDeck::State); + void position(int id,int msecs); + void segueStart(int id); + void segueEnd(int id); + void hookStart(int id); + void hookEnd(int id); + void talkStart(int id); + void talkEnd(int id); + + private slots: + void playingData(int handle); + void playStoppedData(int handle); + void pointTimerData(int); + void positionTimerData(); + void fadeTimerData(); + void duckTimerData(); + + private: + enum Point {Segue=0,Hook=1,Talk=2,SizeOf=3}; + void StartTimers(int offset); + void StopTimers(); + QTimer *play_position_timer; + RDCart *play_cart; + RDCut *play_cut; + RDCae *play_cae; + QTimer *play_point_timer[3]; + QTimer *play_stop_timer; + QTimer *play_fade_timer; + QTimer *play_duck_timer; + bool play_duck_down_state; + bool play_fade_down_state; + int play_segue_interval; + bool play_point_state[3]; + int play_point_value[3][2]; + int play_point_gain; + int play_audio_point[2]; + int play_audio_length; + int play_fade_point[2]; + int play_fade_gain[2]; + int play_fade_down; + int play_cut_gain; + int play_duck_level; + int play_duck_gain[2]; + int play_duck_up; + int play_duck_down; + int play_ducked; + int play_duck_up_point; + int play_card; + int play_stream; + int play_port; + int play_channel; + int play_handle; + unsigned play_forced_length; + bool play_hook_mode; + QTime play_start_time; + RDPlayDeck::State play_state; + bool stop_called; + bool pause_called; + int play_id; + int play_owner; + unsigned play_start_position; + int play_last_start_position; + int play_current_position; + bool play_timescale_active; + int play_timescale_speed; +}; + + +#endif diff --git a/lib/rdplaymeter.cpp b/lib/rdplaymeter.cpp new file mode 100644 index 00000000..0eb1a80a --- /dev/null +++ b/lib/rdplaymeter.cpp @@ -0,0 +1,272 @@ +// rdplaymeter.cpp +// +// This implements a widget that represents a stereo audio level meter, +// complete with labels and scale. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdplaymeter.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qwidget.h> +#include <qstring.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qcolor.h> +#include <qpainter.h> +#include <qpushbutton.h> +#include <qsize.h> +#include <stdio.h> +#include <qslider.h> +#include <qbuttongroup.h> +#include <qsizepolicy.h> +#include <qmessagebox.h> + +#include <rdplaymeter.h> + +RDPlayMeter::RDPlayMeter(RDSegMeter::Orientation orient,QWidget *parent,const char *name) + : QWidget(parent,name) +{ + meter_label=QString(""); + setBackgroundColor(black); + orientation=orient; + makeFont(); + meter=new RDSegMeter(orientation,this,"meter"); + meter->setSegmentSize(5); + meter->setSegmentGap(1); +} + + +QSize RDPlayMeter::sizeHint() const +{ + if(meter_label==QString("")) { + return QSize(335,60); + } + else { + return QSize(335,80); + } +} + + +QSizePolicy RDPlayMeter::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); +} + + +void RDPlayMeter::setRange(int min,int max) +{ + meter->setRange(min,max); +} + + +void RDPlayMeter::setDarkLowColor(QColor color) +{ + meter->setDarkLowColor(color); +} + + +void RDPlayMeter::setDarkHighColor(QColor color) +{ + meter->setDarkHighColor(color); +} + + +void RDPlayMeter::setDarkClipColor(QColor color) +{ + meter->setDarkClipColor(color); +} + + +void RDPlayMeter::setLowColor(QColor color) +{ + meter->setLowColor(color); +} + + +void RDPlayMeter::setHighColor(QColor color) +{ + meter->setHighColor(color); +} + + +void RDPlayMeter::setClipColor(QColor color) +{ + meter->setClipColor(color); +} + + +void RDPlayMeter::setHighThreshold(int level) +{ + meter->setHighThreshold(level); +} + + +void RDPlayMeter::setClipThreshold(int level) +{ + meter->setClipThreshold(level); +} + + +void RDPlayMeter::setLabel(QString label) +{ + meter_label=label; + makeFont(); + setGeometry(geometry().left(),geometry().top(), + geometry().width(),geometry().height()); +} + + +void RDPlayMeter::setGeometry(int x,int y,int w,int h) +{ + QWidget::setGeometry(x,y,w,h); + if(meter_label.isEmpty()) { + meter->setGeometry(2,2,w-4,h-4); + } + else { + switch(orientation) { + case RDSegMeter::Left: + meter->setGeometry(2,2,w-4-h,h-4); + label_font=QFont("helvetica",height()-2,QFont::Bold); + label_font.setPixelSize(height()-2); + break; + case RDSegMeter::Right: + meter->setGeometry(2+h,2,w-4-h,h-4); + label_font=QFont("helvetica",height()-2,QFont::Bold); + label_font.setPixelSize(height()-2); + break; + case RDSegMeter::Up: + meter->setGeometry(2,2,w-4,h-4-w); + label_font=QFont("helvetica",width()-2,QFont::Bold); + label_font.setPixelSize(width()-2); + break; + case RDSegMeter::Down: + meter->setGeometry(2,2+width(),w-4,h-4-w); + label_font=QFont("helvetica",width()-2,QFont::Bold); + label_font.setPixelSize(width()-2); + break; + } + makeFont(); + } +} + + +void RDPlayMeter::setGeometry(QRect &rect) +{ + setGeometry(rect.left(),rect.top(),rect.width(),rect.height()); +} + + +void RDPlayMeter::setSolidBar(int level) +{ + meter->setSolidBar(level); +} + + +void RDPlayMeter::setPeakBar(int level) +{ + meter->setPeakBar(level); +} + + +void RDPlayMeter::setFloatingBar(int level) +{ + meter->setFloatingBar(level); +} + + +void RDPlayMeter::setSegmentSize(int size) +{ + meter->setSegmentSize(size); +} + + +void RDPlayMeter::setSegmentGap(int gap) +{ + meter->setSegmentGap(gap); +} + + +RDSegMeter::Mode RDPlayMeter::mode() const +{ + return meter->mode(); +} + + +void RDPlayMeter::setMode(RDSegMeter::Mode mode) +{ + meter->setMode(mode); +} + + +void RDPlayMeter::paintEvent(QPaintEvent *paintEvent) +{ + // + // Setup + // + QPainter *p=new QPainter(this); + p->setFont(label_font); + p->setPen(white); + if(!meter_label.isEmpty()) { + switch(orientation) { + case RDSegMeter::Left: + p->drawText(width()-height()+meter_label_x,height()-2,meter_label); + break; + case RDSegMeter::Right: + p->drawText(meter_label_x,height()-2,meter_label); + break; + case RDSegMeter::Up: + p->drawText(meter_label_x,height()-3,meter_label); + break; + case RDSegMeter::Down: + p->drawText(meter_label_x,width()-1,meter_label); + break; + } + } + p->end(); +} + + + +void RDPlayMeter::makeFont() +{ + switch(orientation) { + case RDSegMeter::Left: + label_font=QFont("helvetica",height()-2,QFont::Bold); + label_font.setPixelSize(height()-2); + meter_label_x=(height()-QFontMetrics(label_font). + width(meter_label))/2; + break; + case RDSegMeter::Right: + label_font=QFont("helvetica",height()-2,QFont::Bold); + label_font.setPixelSize(height()-2); + meter_label_x=(height()-QFontMetrics(label_font). + width(meter_label))/2; + break; + case RDSegMeter::Up: + label_font=QFont("helvetica",width()-2,QFont::Bold); + label_font.setPixelSize(width()-2); + meter_label_x=(width()-QFontMetrics(label_font). + width(meter_label))/2; + break; + case RDSegMeter::Down: + label_font=QFont("helvetica",width()-2,QFont::Bold); + label_font.setPixelSize(width()-2); + meter_label_x=(width()-QFontMetrics(label_font). + width(meter_label))/2; + break; + } +} diff --git a/lib/rdplaymeter.h b/lib/rdplaymeter.h new file mode 100644 index 00000000..72d3d0c1 --- /dev/null +++ b/lib/rdplaymeter.h @@ -0,0 +1,81 @@ +// rdplaymeter.h +// +// A playback audio meter widget. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdplaymeter.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDPLAYMETER_H +#define RDPLAYMETER_H + +#include <qwidget.h> +#include <qcolor.h> +#include <qpainter.h> +#include <qsize.h> +#include <qsizepolicy.h> +#include <qstring.h> +#include <qrect.h> +#include <qfont.h> + +#include <rdsegmeter.h> + + +class RDPlayMeter : public QWidget +{ + Q_OBJECT + public: + RDPlayMeter(RDSegMeter::Orientation orient,QWidget *parent=0, + const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void setRange(int min,int max); + void setDarkLowColor(QColor color); + void setDarkHighColor(QColor color); + void setDarkClipColor(QColor color); + void setLowColor(QColor color); + void setHighColor(QColor color); + void setClipColor(QColor color); + void setHighThreshold(int level); + void setClipThreshold(int level); + void setSegmentSize(int size); + void setSegmentGap(int gap); + RDSegMeter::Mode mode() const; + void setMode(RDSegMeter::Mode mode); + void setLabel(QString label); + + public slots: + void setGeometry(int x,int y,int w,int h); + void setGeometry(QRect &rect); + void setSolidBar(int level); + void setFloatingBar(int level); + void setPeakBar(int level); + + protected: + void paintEvent(QPaintEvent *); + + private: + void makeFont(); + RDSegMeter *meter; + QString meter_label; + QFont label_font; + RDSegMeter::Orientation orientation; + int meter_label_x; +}; + + +#endif // RDPLAYMETER_H diff --git a/lib/rdpodcast.cpp b/lib/rdpodcast.cpp new file mode 100644 index 00000000..3e39ba85 --- /dev/null +++ b/lib/rdpodcast.cpp @@ -0,0 +1,402 @@ +// rdpodcast.cpp +// +// Abstract a Rivendell Podcast +// +// (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpodcast.cpp,v 1.11 2010/11/24 16:57:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <curl/curl.h> + +#include <rddb.h> +#include <rdpodcast.h> +#include <rdconf.h> +#include <rdescape_string.h> +#include <rdurl.h> + +// +// CURL Callbacks +// +int PodcastErrorCallback(CURL *curl,curl_infotype type,char *msg,size_t size, + void *clientp) +{ + char str[1000]; + + if(type!=CURLINFO_TEXT) { + return 0; + } + if(size>999) { + size=999; + } + memset(&str,0,size+1); + memcpy(str,msg,size); + syslog(LOG_DEBUG,"CURL MSG: %s",str); + return 0; +} + + +RDPodcast::RDPodcast(unsigned id) +{ + RDSqlQuery *q; + QString sql; + + podcast_id=id; + sql=QString().sprintf("select FEEDS.KEY_NAME from \ + PODCASTS left join FEEDS \ + on (PODCASTS.FEED_ID=FEEDS.ID) \ + where PODCASTS.ID=%u",id); + q=new RDSqlQuery(sql); + if(q->first()) { + podcast_keyname=q->value(0).toString(); + } + delete q; +} + + +unsigned RDPodcast::id() const +{ + return podcast_id; +} + + +QString RDPodcast::keyName() const +{ + return podcast_keyname; +} + + +bool RDPodcast::exists() const +{ + return RDDoesRowExist("PODCASTS","ID",podcast_id); +} + + +unsigned RDPodcast::feedId() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id,"FEED_ID"). + toUInt(); +} + + +void RDPodcast::setFeedId(unsigned id) const +{ + SetRow("FEED_ID",id); +} + + +QString RDPodcast::itemTitle() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id,"ITEM_TITLE"). + toString(); +} + + +void RDPodcast::setItemTitle(const QString &str) const +{ + SetRow("ITEM_TITLE",str); +} + + +QString RDPodcast::itemDescription() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id, + "ITEM_DESCRIPTION").toString(); +} + + +void RDPodcast::setItemDescription(const QString &str) const +{ + SetRow("ITEM_DESCRIPTION",str); +} + + +QString RDPodcast::itemCategory() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id,"ITEM_CATEGORY"). + toString(); +} + + +void RDPodcast::setItemCategory(const QString &str) const +{ + SetRow("ITEM_CATEGORY",str); +} + + +QString RDPodcast::itemLink() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id,"ITEM_LINK"). + toString(); +} + + +void RDPodcast::setItemLink(const QString &str) const +{ + SetRow("ITEM_LINK",str); +} + + +QString RDPodcast::itemAuthor() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id,"ITEM_AUTHOR"). + toString(); +} + + +void RDPodcast::setItemAuthor(const QString &str) const +{ + SetRow("ITEM_AUTHOR",str); +} + + +QString RDPodcast::itemComments() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id,"ITEM_COMMENTS"). + toString(); +} + + +void RDPodcast::setItemComments(const QString &str) const +{ + SetRow("ITEM_COMMENTS",str); +} + + +QString RDPodcast::itemSourceText() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id,"ITEM_SOURCE_TEXT"). + toString(); +} + + +void RDPodcast::setItemSourceText(const QString &str) const +{ + SetRow("ITEM_SOURCE_TEXT",str); +} + + +QString RDPodcast::itemSourceUrl() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id,"ITEM_SOURCE_URL"). + toString(); +} + + +void RDPodcast::setItemSourceUrl(const QString &str) const +{ + SetRow("ITEM_SOURCE_URL",str); +} + + +QDateTime RDPodcast::originDateTime() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id, + "ORIGIN_DATETIME").toDateTime(); +} + + +void RDPodcast::setOriginDateTime(const QDateTime &datetime) const +{ + SetRow("ORIGIN_DATETIME",datetime.toString("yyyy-MM-dd hh:mm:ss")); +} + + +QDateTime RDPodcast::effectiveDateTime() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id, + "EFFECTIVE_DATETIME").toDateTime(); +} + + +void RDPodcast::setEffectiveDateTime(const QDateTime &datetime) const +{ + SetRow("EFFECTIVE_DATETIME",datetime.toString("yyyy-MM-dd hh:mm:ss")); +} + + +QString RDPodcast::audioFilename() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id, + "AUDIO_FILENAME").toString(); +} + + +void RDPodcast::setAudioFilename(const QString &str) const +{ + SetRow("AUDIO_FILENAME",str); +} + + +int RDPodcast::audioLength() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id,"AUDIO_LENGTH"). + toUInt(); +} + + +void RDPodcast::setAudioLength(int len) const +{ + SetRow("AUDIO_LENGTH",len); +} + + +int RDPodcast::audioTime() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id,"AUDIO_TIME"). + toUInt(); +} + + +void RDPodcast::setAudioTime(int msecs) const +{ + SetRow("AUDIO_TIME",msecs); +} + + +unsigned RDPodcast::shelfLife() const +{ + return RDGetSqlValue("PODCASTS","ID",podcast_id,"SHELF_LIFE"). + toUInt(); +} + + +void RDPodcast::setShelfLife(unsigned days) const +{ + SetRow("SHELF_LIFE",days); +} + + +RDPodcast::Status RDPodcast::status() const +{ + return (RDPodcast::Status)RDGetSqlValue("PODCASTS","ID", + podcast_id,"STATUS").toUInt(); +} + + +void RDPodcast::setStatus(RDPodcast::Status status) +{ + SetRow("STATUS",(unsigned)status); +} + + +bool RDPodcast::removeAudio(RDFeed *feed,QString *err_text,bool log_debug) const +{ + CURL *curl=NULL; + struct curl_slist *cmds=NULL; + CURLcode err; + QUrl *url; + bool ret=true; + QString currentdir; + char urlstr[1024]; + char userpwd[256]; + + if((curl=curl_easy_init())==NULL) { + syslog(LOG_ERR,"unable to initialize curl library\n"); + return false; + } + url=new QUrl(feed->purgeUrl()); + strncpy(urlstr,(const char *)(url->protocol()+"://"+url->host()+"/"),1024); + curl_easy_setopt(curl,CURLOPT_URL,urlstr); + strncpy(userpwd,(const char *)QString(). + sprintf("%s:%s",(const char *)feed->purgeUsername(), + (const char *)feed->purgePassword()),256); + curl_easy_setopt(curl,CURLOPT_USERPWD,userpwd); + curl_easy_setopt(curl,CURLOPT_HTTPAUTH,CURLAUTH_ANY); + if(log_debug) { + curl_easy_setopt(curl,CURLOPT_VERBOSE,1); + curl_easy_setopt(curl,CURLOPT_DEBUGFUNCTION,PodcastErrorCallback); + } + currentdir=""; + if(!url->dirPath().right(url->dirPath().length()-1).isEmpty()) { + currentdir=url->dirPath().right(url->dirPath().length()-1)+"/"; + } + if(!url->fileName().isEmpty()) { + currentdir+=url->fileName()+"/"; + } + if(!currentdir.isEmpty()) { + cmds=curl_slist_append(cmds,QString().sprintf("cwd %s", + (const char *)currentdir)); + } + cmds=curl_slist_append(cmds, QString().sprintf("dele %s", + (const char *)audioFilename())); + curl_easy_setopt(curl,CURLOPT_QUOTE,cmds); + switch((err=curl_easy_perform(curl))) { + case CURLE_OK: +#ifdef CURLE_QUOTE_ERROR + case CURLE_QUOTE_ERROR: // In case the file is already gone +#endif // CURLE_QUOTE_ERROR + ret=true; + break; + + default: + ret=false; + break; + } + if(err_text!=NULL) { + *err_text=curl_easy_strerror(err); + } + curl_slist_free_all(cmds); + curl_easy_cleanup(curl); + delete url; + + return ret; +} + + +QString RDPodcast::guid(const QString &url,const QString &filename, + unsigned feed_id,unsigned cast_id) +{ + return QString().sprintf("%s/%s_%06u_%06u", + (const char *)url,(const char *)filename, + feed_id,cast_id); +} + + +QString RDPodcast::guid(const QString &full_url,unsigned feed_id, + unsigned cast_id) +{ + return QString().sprintf("%s_%06u_%06u", + (const char *)full_url,feed_id,cast_id); +} + + +void RDPodcast::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE PODCASTS SET %s=%d WHERE ID=%u", + (const char *)param, + value, + podcast_id); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDPodcast::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE PODCASTS SET %s=\"%s\" WHERE ID=%u", + (const char *)param, + (const char *)RDEscapeString(value), + podcast_id); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdpodcast.h b/lib/rdpodcast.h new file mode 100644 index 00000000..368cd859 --- /dev/null +++ b/lib/rdpodcast.h @@ -0,0 +1,86 @@ +// rdpodcast.h +// +// Abstract a Rivendell Podcast Entry +// +// (C) Copyright 2002-2007 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpodcast.h,v 1.7 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> + +#include <rdfeed.h> + +#ifndef RDPODCAST_H +#define RDPODCAST_H + +class RDPodcast +{ + public: + enum Status {StatusPending=1,StatusActive=2,StatusExpired=3}; + RDPodcast(unsigned id); + unsigned id() const; + QString keyName() const; + bool exists() const; + unsigned feedId() const; + void setFeedId(unsigned id) const; + QString itemTitle() const; + void setItemTitle(const QString &str) const; + QString itemDescription() const; + void setItemDescription(const QString &str) const; + QString itemCategory() const; + void setItemCategory(const QString &str) const; + QString itemLink() const; + void setItemLink(const QString &str) const; + QString itemAuthor() const; + void setItemAuthor(const QString &str) const; + QString itemComments() const; + void setItemComments(const QString &str) const; + QString itemSourceText() const; + void setItemSourceText(const QString &str) const; + QString itemSourceUrl() const; + void setItemSourceUrl(const QString &str) const; + QDateTime originDateTime() const; + void setOriginDateTime(const QDateTime &datetime) const; + QDateTime effectiveDateTime() const; + void setEffectiveDateTime(const QDateTime &datetime) const; + QString audioFilename() const; + void setAudioFilename(const QString &str) const; + int audioLength() const; + void setAudioLength(int len) const; + int audioTime() const; + void setAudioTime(int msecs) const; + unsigned shelfLife() const; + void setShelfLife(unsigned days) const; + RDPodcast::Status status() const; + void setStatus(RDPodcast::Status status); + //QString audioUploadCommand(const QString &srcfile) const; + //QString audioPurgeCommand() const; + bool removeAudio(RDFeed *feed,QString *err_text,bool log_debug) const; + static QString guid(const QString &url,const QString &filename, + unsigned feed_id,unsigned cast_id); + static QString guid(const QString &full_url, + unsigned feed_id,unsigned cast_id); + + private: + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,const QString &value) const; + QString podcast_keyname; + unsigned podcast_id; +}; + + +#endif diff --git a/lib/rdprofile.cpp b/lib/rdprofile.cpp new file mode 100644 index 00000000..65b5c431 --- /dev/null +++ b/lib/rdprofile.cpp @@ -0,0 +1,249 @@ +// rdprofile.cpp +// +// A class to read an ini formatted configuration file. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdprofile.cpp,v 1.4.8.1 2014/01/20 19:13:30 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <qfile.h> +#include <qstringlist.h> +#include <qtextstream.h> + +#include <rdprofile.h> + + +RDProfile::RDProfile() +{ +} + + +QString RDProfile::source() const +{ + return profile_source; +} + + +bool RDProfile::setSource(const QString &filename) +{ + QString section; + int offset; + + profile_source=filename; + profile_section.resize(0); + profile_section.push_back(RDProfileSection()); + profile_section.back().setName(""); + QFile *file=new QFile(filename); + if(!file->open(IO_ReadOnly)) { + delete file; + return false; + } + QTextStream *text=new QTextStream(file); + QString line=text->readLine().stripWhiteSpace(); + while(!line.isNull()) { + if((line.left(1)!=";")&&(line.left(1)!="#")) { + if((line.left(1)=="[")&&(line.right(1)=="]")) { + section=line.mid(1,line.length()-2); + profile_section.push_back(RDProfileSection()); + profile_section.back().setName(section); + } + else if(((offset=line.find('='))!=-1)) { + profile_section.back(). + addValue(line.left(offset), + line.right(line.length()-offset-1).stripWhiteSpace()); + } + } + line=text->readLine().stripWhiteSpace(); + } + delete text; + delete file; + return true; +} + + +void RDProfile::setSourceString(const QString &str) +{ + QStringList lines; + QString section; + int offset; + + profile_source=""; + profile_section.resize(0); + profile_section.push_back(RDProfileSection()); + profile_section.back().setName(""); + lines=lines.split("\n",str); + for(unsigned i=0;i<lines.size();i++) { + QString line=lines[i]; + if((line.left(1)!=";")&&(line.left(1)!="#")) { + if((line.left(1)=="[")&&(line.right(1)=="]")) { + section=line.mid(1,line.length()-2); + profile_section.push_back(RDProfileSection()); + profile_section.back().setName(section); + } + else if(((offset=line.find('='))!=-1)) { + profile_section.back(). + addValue(line.left(offset), + line.right(line.length()-offset-1).stripWhiteSpace()); + } + } + } +} + + +QString RDProfile::stringValue(QString section,QString tag, + QString default_str,bool *ok) const +{ + QString result; + + for(unsigned i=0;i<profile_section.size();i++) { + if(profile_section[i].name()==section) { + if(profile_section[i].getValue(tag,&result)) { + if(ok!=NULL) { + *ok=true; + } + return result; + } + if(ok!=NULL) { + *ok=false; + } + return default_str; + } + } + if(ok!=NULL) { + *ok=false; + } + return default_str; +} + + +int RDProfile::intValue(QString section,QString tag, + int default_value,bool *ok) const +{ + bool valid; + + int result=stringValue(section,tag).toInt(&valid,10); + if(!valid) { + if(ok!=NULL) { + *ok=false; + } + return default_value; + } + if(ok!=NULL) { + *ok=true; + } + return result; +} + + +int RDProfile::hexValue(QString section,QString tag, + int default_value,bool *ok) const +{ + bool valid; + + QString str=stringValue(section,tag); + if(str.left(2).lower()=="0x") { + str=str.right(str.length()-2); + } + int result=str.toInt(&valid,16); + if(!valid) { + if(ok!=NULL) { + *ok=false; + } + return default_value; + } + if(ok!=NULL) { + *ok=true; + } + return result; +} + + +float RDProfile::floatValue(QString section,QString tag, + float default_value,bool *ok) const +{ + bool valid; + + float result=stringValue(section,tag).toDouble(&valid); + if(!valid) { + if(ok!=NULL) { + *ok=false; + } + return default_value; + } + if(ok!=NULL) { + *ok=true; + } + return result; +} + + +double RDProfile::doubleValue(QString section,QString tag, + double default_value,bool *ok) const +{ + bool valid; + + double result=stringValue(section,tag).toDouble(&valid); + if(!valid) { + if(ok!=NULL) { + *ok=false; + } + return default_value; + } + if(ok!=NULL) { + *ok=true; + } + return result; +} + + +bool RDProfile::boolValue(QString section,QString tag, + bool default_value,bool *ok) const +{ + bool valid; + + QString str=stringValue(section,tag,"",&valid).lower(); + if(!valid) { + if(ok!=NULL) { + *ok=false; + } + return default_value; + } + if((str=="yes")||(str=="true")||(str=="on")) { + if(ok!=NULL) { + *ok=true; + } + return true; + } + if((str=="no")||(str=="false")||(str=="off")) { + if(ok!=NULL) { + *ok=true; + } + return false; + } + if(ok!=NULL) { + *ok=false; + } + return default_value; +} + + +void RDProfile::clear() +{ + profile_source=""; + profile_section.resize(0); +} diff --git a/lib/rdprofile.h b/lib/rdprofile.h new file mode 100644 index 00000000..4702239a --- /dev/null +++ b/lib/rdprofile.h @@ -0,0 +1,72 @@ +// rdprofile.h +// +// A class to read an ini formatted configuration file. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdprofile.h,v 1.4.8.1 2014/01/20 19:13:30 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + + +#ifndef RDPROFILE_H +#define RDPROFILE_H + + +#include <vector> + +#include <qstring.h> + +#include <rdprofilesection.h> + +/** + * @short Implements an ini configuration file parser. + * @author Fred Gleason <fredg@paravelsystems.com> + * + * This class implements an ini configuration file parser. Methods + * exist for extracting data as strings, ints, bools or floats. + **/ +class RDProfile +{ + public: + /** + * Instantiates the class. + **/ + RDProfile(); + QString source() const; + bool setSource(const QString &filename); + void setSourceString(const QString &str); + QString stringValue(QString section,QString tag, + QString default_value="",bool *ok=0) const; + int intValue(QString section,QString tag, + int default_value=0,bool *ok=0) const; + int hexValue(QString section,QString tag, + int default_value=0,bool *ok=0) const; + float floatValue(QString section,QString tag, + float default_value=0.0,bool *ok=0) const; + double doubleValue(QString section,QString tag, + double default_value=0.0,bool *ok=0) const; + bool boolValue(QString section,QString tag, + bool default_value=false,bool *ok=0) const; + void clear(); + + private: + QString profile_source; + std::vector<RDProfileSection> profile_section; +}; + + +#endif // RDPROFILE_H diff --git a/lib/rdprofileline.cpp b/lib/rdprofileline.cpp new file mode 100644 index 00000000..47f742ab --- /dev/null +++ b/lib/rdprofileline.cpp @@ -0,0 +1,61 @@ +// rdprofileline.cpp +// +// A container class for profile lines. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdprofileline.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + + +#include <rdprofileline.h> + +RDProfileLine::RDProfileLine() +{ + clear(); +} + + +QString RDProfileLine::tag() const +{ + return line_tag; +} + + +void RDProfileLine::setTag(QString tag) +{ + line_tag=tag; +} + + +QString RDProfileLine::value() const +{ + return line_value; +} + + +void RDProfileLine::setValue(QString value) +{ + line_value=value; +} + + +void RDProfileLine::clear() +{ + line_tag=""; + line_value=""; +} diff --git a/lib/rdprofileline.h b/lib/rdprofileline.h new file mode 100644 index 00000000..255fb3c3 --- /dev/null +++ b/lib/rdprofileline.h @@ -0,0 +1,47 @@ +// rdprofileline.h +// +// A container class for profile lines. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdprofileline.h,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + + +#ifndef RDPROFILELINE_H +#define RDPROFILELINE_H + +#include <qstring.h> + + +class RDProfileLine +{ + public: + RDProfileLine(); + QString tag() const; + void setTag(QString tag); + QString value() const; + void setValue(QString value); + void clear(); + + private: + QString line_tag; + QString line_value; +}; + + +#endif // RDPROFILELINE_H diff --git a/lib/rdprofilesection.cpp b/lib/rdprofilesection.cpp new file mode 100644 index 00000000..3361d1ce --- /dev/null +++ b/lib/rdprofilesection.cpp @@ -0,0 +1,68 @@ +// rdprofilesection.cpp +// +// A container class for profile sections. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdprofilesection.cpp,v 1.1 2007/09/14 14:06:24 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <rdprofilesection.h> + +RDProfileSection::RDProfileSection() +{ + clear(); +} + + +QString RDProfileSection::name() const +{ + return section_name; +} + + +void RDProfileSection::setName(QString name) +{ + section_name=name; +} + + +bool RDProfileSection::getValue(QString tag,QString *value) const +{ + for(unsigned i=0;i<section_line.size();i++) { + if(section_line[i].tag()==tag) { + *value=section_line[i].value(); + return true; + } + } + return false; +} + + +void RDProfileSection::addValue(QString tag,QString value) +{ + section_line.push_back(RDProfileLine()); + section_line.back().setTag(tag); + section_line.back().setValue(value); +} + + +void RDProfileSection::clear() +{ + section_name=""; + section_line.resize(0); +} diff --git a/lib/rdprofilesection.h b/lib/rdprofilesection.h new file mode 100644 index 00000000..65bd85d2 --- /dev/null +++ b/lib/rdprofilesection.h @@ -0,0 +1,50 @@ +// rdprofilesection.h +// +// A container class for profile sections. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdprofilesection.h,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + + +#ifndef RDPROFILESECTION_H +#define RDPROFILESECTION_H + +#include <vector> + +#include <qstring.h> + +#include <rdprofileline.h> + +class RDProfileSection +{ + public: + RDProfileSection(); + QString name() const; + void setName(QString name); + bool getValue(QString tag,QString *value) const; + void addValue(QString tag,QString value); + void clear(); + + private: + QString section_name; + std::vector<RDProfileLine> section_line; +}; + + +#endif // RDPROFILESECTION_H diff --git a/lib/rdpushbutton.cpp b/lib/rdpushbutton.cpp new file mode 100644 index 00000000..b9fd6345 --- /dev/null +++ b/lib/rdpushbutton.cpp @@ -0,0 +1,284 @@ +// rdpushbutton.cpp +// +// An flashing button widget. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpushbutton.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// +#include <qpushbutton.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qpointarray.h> +#include <qtimer.h> +#include <qpalette.h> + +#include <rdpushbutton.h> + + +RDPushButton::RDPushButton(QWidget *parent=0,const char *name) : + QPushButton(parent,name) +{ + Init(); +} + + +RDPushButton::RDPushButton(const QString &text,QWidget *parent, + const char *name) + : QPushButton(text,parent,name) +{ + Init(); +} + +RDPushButton::RDPushButton(const QIconSet &icon,const QString &text, + QWidget *parent,const char *name) + : QPushButton(text,parent,name) +{ + Init(); +} + + +QColor RDPushButton::flashColor() const +{ + return flash_color; +} + + +void RDPushButton::setFlashColor(QColor color) +{ + int h=0; + int s=0; + int v=0; + + flash_color=color; + flash_palette=QPalette(QColor(flash_color),backgroundColor()); + + color.getHsv(&h,&s,&v); + if((h>180)&&(h<300)) { + v=255; + } + else { + if(v<168) { + v=255; + } + else { + v=0; + } + } + s=0; + color.setHsv(h,s,v); + flash_palette.setColor(QPalette::Active,QColorGroup::ButtonText,color); + flash_palette.setColor(QPalette::Inactive,QColorGroup::ButtonText,color); +} + + +bool RDPushButton::flashingEnabled() const +{ + return flashing_enabled; +} + + +void RDPushButton::setFlashingEnabled(bool state) +{ + flashing_enabled=state; + if(flashing_enabled) { + flashOn(); + } + else { + flashOff(); + } +} + + +int RDPushButton::id() const +{ + return button_id; +} + + +void RDPushButton::setId(int id) +{ + button_id=id; +} + + +void RDPushButton::setPalette(const QPalette &pal) +{ + off_palette=pal; + QPushButton::setPalette(pal); +} + + +void RDPushButton::mousePressEvent(QMouseEvent *e) +{ + switch(e->button()) { + case QMouseEvent::LeftButton: + QPushButton::mousePressEvent(e); + break; + + case QMouseEvent::MidButton: + emit centerPressed(); + break; + + case QMouseEvent::RightButton: + emit rightPressed(); + break; + + default: + break; + } +} + + +void RDPushButton::mouseReleaseEvent(QMouseEvent *e) +{ + switch(e->button()) { + case QMouseEvent::LeftButton: + QPushButton::mouseReleaseEvent(e); + break; + + case QMouseEvent::MidButton: + e->accept(); + emit centerReleased(); + if((e->x()>=0)&&(e->x()<geometry().width())&& + (e->y()>=0)&&(e->y()<geometry().height())) { + emit centerClicked(); + emit centerClicked(button_id,QPoint(e->x(),e->y())); + } + break; + + case QMouseEvent::RightButton: + e->accept(); + emit rightReleased(); + if((e->x()>=0)&&(e->x()<geometry().width())&& + (e->y()>=0)&&(e->y()<geometry().height())) { + emit rightClicked(); + emit rightClicked(button_id,QPoint(e->x(),e->y())); + } + break; + + default: + break; + } +} + + +int RDPushButton::flashPeriod() const +{ + return flash_period; +} + + +void RDPushButton::setFlashPeriod(int period) +{ + flash_period=period; + if(flash_timer->isActive()) { + flash_timer->changeInterval(flash_period); + } +} + + +RDPushButton::ClockSource RDPushButton::clockSource() const +{ + return flash_clock_source; +} + + +void RDPushButton::setClockSource(ClockSource src) +{ + if(src==flash_clock_source) { + return; + } + flash_clock_source=src; + if((src==RDPushButton::ExternalClock)&&(flash_timer->isActive())) { + flash_timer->stop(); + } + if((src==RDPushButton::InternalClock)&&flashing_enabled) { + flashOn(); + } +} + + +void RDPushButton::tickClock() +{ + if(!flashing_enabled) { + return; + } + QKeySequence a=accel(); + if(flash_state) { + flash_state=false; + QPushButton::setPalette(flash_palette); + } + else { + flash_state=true; + QPushButton::setPalette(off_palette); + } + setAccel(a); +} + + +void RDPushButton::tickClock(bool state) +{ + if(!flashing_enabled) { + return; + } + QKeySequence a=accel(); + if(state) { + flash_state=false; + QPushButton::setPalette(flash_palette); + } + else { + flash_state=true; + QPushButton::setPalette(off_palette); + } + setAccel(a); +} + + +void RDPushButton::flashOn() +{ + if((!flash_timer->isActive())&& + (flash_clock_source==RDPushButton::InternalClock)) { + flash_timer->start(flash_period); + } +} + + +void RDPushButton::flashOff() +{ + if(flash_timer->isActive()&& + (flash_clock_source==RDPushButton::InternalClock)) { + flash_timer->stop(); + } + setPalette(off_palette); +} + + +void RDPushButton::Init() +{ + flash_timer=new QTimer(); + connect(flash_timer,SIGNAL(timeout()),this,SLOT(tickClock())); + flash_state=true; + flashing_enabled=false; + off_palette=palette(); + flash_clock_source=RDPushButton::InternalClock; + flash_period=RDPUSHBUTTON_DEFAULT_FLASH_PERIOD; + setFlashColor(RDPUSHBUTTON_DEFAULT_FLASH_COLOR); + button_id=-1; +} + + diff --git a/lib/rdpushbutton.h b/lib/rdpushbutton.h new file mode 100644 index 00000000..28393e0f --- /dev/null +++ b/lib/rdpushbutton.h @@ -0,0 +1,95 @@ +// rdpushbutton.h +// +// An flashing button widget. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdpushbutton.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDPUSHBUTTON_H +#define RDPUSHBUTTON_H + +#include <qwidget.h> +#include <qpushbutton.h> +#include <qpixmap.h> +#include <qcolor.h> + +/* + * Widget Defaults + */ +#define RDPUSHBUTTON_DEFAULT_FLASH_PERIOD 300 +#define RDPUSHBUTTON_DEFAULT_FLASH_COLOR blue + + +class RDPushButton : public QPushButton +{ + Q_OBJECT + public: + enum ClockSource {InternalClock=0,ExternalClock=1}; + RDPushButton(QWidget *parent,const char *name=0); + RDPushButton(const QString &text,QWidget *parent,const char *name=0); + RDPushButton(const QIconSet &icon,const QString &text, + QWidget *parent,const char *name=0); + QColor flashColor() const; + void setFlashColor(QColor color); + int flashPeriod() const; + void setFlashPeriod(int period); + ClockSource clockSource() const; + void setClockSource(ClockSource src); + int id() const; + void setId(int id); + bool flashingEnabled() const; + + public slots: + void setFlashingEnabled(bool state); + void setPalette(const QPalette &); + void tickClock(); + void tickClock(bool state); + + signals: + void centerClicked(); + void centerClicked(int id,const QPoint &pt); + void centerPressed(); + void centerReleased(); + void rightClicked(); + void rightClicked(int id,const QPoint &pt); + void rightPressed(); + void rightReleased(); + + protected: + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + + private: + void flashOn(); + void flashOff(); + void Init(); + bool flash_state; + int flash_period; + bool flashing_enabled; + QColor flash_color; + QPalette flash_palette; + QPalette off_palette; + QTimer *flash_timer; + int button_id; + ClockSource flash_clock_source; +}; + + + +#endif // RDPUSHBUTTON_H diff --git a/lib/rdrecording.cpp b/lib/rdrecording.cpp new file mode 100644 index 00000000..e32b7385 --- /dev/null +++ b/lib/rdrecording.cpp @@ -0,0 +1,955 @@ +// rdrecording.cpp +// +// Abstract a Rivendell Netcatch Recording. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdrecording.cpp,v 1.30 2012/01/12 16:24:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <unistd.h> + +#include <qobject.h> + +#include <rd.h> +#include <rdconf.h> +#include <rddb.h> +#include <rdrecording.h> +#include <rddeck.h> +#include <rdescape_string.h> + +// +// Global Classes +// +RDRecording::RDRecording(int id,bool create) +{ + RDSqlQuery *q; + QString sql; + + if(id<0) { + rec_id=AddRecord(); + create=false; + } + else { + rec_id=id; + } + + if(create) { + sql=QString().sprintf("select ID from RECORDINGS where ID=%d",rec_id); + q=new RDSqlQuery(sql); + if(q->size()!=1) { + delete q; + sql=QString().sprintf("insert into RECORDINGS set ID=%d",rec_id); + q=new RDSqlQuery(sql); + } + delete q; + } +} + + +int RDRecording::id() const +{ + return rec_id; +} + + +bool RDRecording::isActive() const +{ + return RDBool(GetStringValue("IS_ACTIVE")); +} + + +void RDRecording::setIsActive(bool state) const +{ + SetRow("IS_ACTIVE",RDYesNo(state)); +} + + +QString RDRecording::station() const +{ + return GetStringValue("STATION_NAME"); +} + + +void RDRecording::setStation(QString name) const +{ + SetRow("STATION_NAME",name); +} + + +RDRecording::Type RDRecording::type() const +{ + return (RDRecording::Type)GetIntValue("TYPE"); +} + + +void RDRecording::setType(RDRecording::Type type) const +{ + SetRow("TYPE",(int)type); +} + + +unsigned RDRecording::channel() const +{ + return GetUIntValue("CHANNEL"); +} + + +void RDRecording::setChannel(unsigned chan) const +{ + SetRow("CHANNEL",chan); +} + + +QTime RDRecording::startTime() const +{ + return GetTimeValue("START_TIME"); +} + + +void RDRecording::setStartTime(QTime time) const +{ + SetRow("START_TIME",time); +} + + +QTime RDRecording::endTime() const +{ + return GetTimeValue("END_TIME"); +} + + +void RDRecording::setEndTime(QTime time) const +{ + SetRow("END_TIME",time); +} + + +QString RDRecording::cutName() const +{ + return GetStringValue("CUT_NAME"); +} + + +void RDRecording::setCutName(QString name) const +{ + SetRow("CUT_NAME",name); +} + + +bool RDRecording::sun() const +{ + return GetBoolValue("SUN"); +} + + +void RDRecording::setSun(bool state) const +{ + SetRow("SUN",state); +} + + +bool RDRecording::mon() const +{ + return GetBoolValue("MON"); +} + + +void RDRecording::setMon(bool state) const +{ + SetRow("MON",state); +} + + +bool RDRecording::tue() const +{ + return GetBoolValue("TUE"); +} + + +void RDRecording::setTue(bool state) const +{ + SetRow("TUE",state); +} + + +bool RDRecording::wed() const +{ + return GetBoolValue("WED"); +} + + +void RDRecording::setWed(bool state) const +{ + SetRow("WED",state); +} + + +bool RDRecording::thu() const +{ + return GetBoolValue("THU"); +} + + +void RDRecording::setThu(bool state) const +{ + SetRow("THU",state); +} + + +bool RDRecording::fri() const +{ + return GetBoolValue("FRI"); +} + + +void RDRecording::setFri(bool state) const +{ + SetRow("FRI",state); +} + + +bool RDRecording::sat() const +{ + return GetBoolValue("SAT"); +} + + +void RDRecording::setSat(bool state) const +{ + SetRow("SAT",state); +} + + +int RDRecording::switchSource() const +{ + return GetIntValue("SWITCH_INPUT"); +} + + +void RDRecording::setSwitchSource(int input) const +{ + SetRow("SWITCH_INPUT",input); +} + + +int RDRecording::switchDestination() const +{ + return GetIntValue("SWITCH_OUTPUT"); +} + + +void RDRecording::setSwitchDestination(int output) const +{ + SetRow("SWITCH_OUTPUT",output); +} + + +QString RDRecording::description() const +{ + return GetStringValue("DESCRIPTION"); +} + + +void RDRecording::setDescription(QString string) const +{ + SetRow("DESCRIPTION",string); +} + + +unsigned RDRecording::length() const +{ + return GetUIntValue("LENGTH"); +} + + +void RDRecording::setLength(unsigned length) const +{ + SetRow("LENGTH",length); +} + + +int RDRecording::startGpi() const +{ + return GetIntValue("START_GPI"); +} + + +void RDRecording::setStartGpi(int line) const +{ + SetRow("START_GPI",line); +} + + +int RDRecording::endGpi() const +{ + return GetIntValue("END_GPI"); +} + + +void RDRecording::setEndGpi(int line) const +{ + SetRow("END_GPI",line); +} + + +bool RDRecording::allowMultipleRecordings() const +{ + return RDBool(GetStringValue("ALLOW_MULT_RECS")); +} + + +void RDRecording::setAllowMultipleRecordings(bool state) const +{ + SetRow("ALLOW_MULT_RECS",state); +} + + +unsigned RDRecording::maxGpiRecordingLength() const +{ + return GetUIntValue("MAX_GPI_REC_LENGTH"); +} + + +void RDRecording::setMaxGpiRecordingLength(unsigned len) const +{ + SetRow("MAX_GPI_REC_LENGTH",len); +} + + +unsigned RDRecording::trimThreshold() const +{ + return GetUIntValue("TRIM_THRESHOLD"); +} + + +void RDRecording::setTrimThreshold(unsigned level) const +{ + SetRow("TRIM_THRESHOLD",level); +} + + +unsigned RDRecording::startdateOffset() const +{ + return GetUIntValue("STARTDATE_OFFSET"); +} + + +void RDRecording::setStartdateOffset(unsigned offset) const +{ + SetRow("STARTDATE_OFFSET",offset); +} + + +unsigned RDRecording::enddateOffset() const +{ + return GetUIntValue("ENDDATE_OFFSET"); +} + + +void RDRecording::setEnddateOffset(unsigned offset) const +{ + SetRow("ENDDATE_OFFSET",offset); +} + + +int RDRecording::eventdateOffset() const +{ + return GetIntValue("EVENTDATE_OFFSET"); +} + + +void RDRecording::setEventdateOffset(int offset) const +{ + SetRow("EVENTDATE_OFFSET",offset); +} + + +RDSettings::Format RDRecording::format() const +{ + return (RDSettings::Format)GetIntValue("FORMAT"); +} + + +void RDRecording::setFormat(RDSettings::Format fmt) const +{ + SetRow("FORMAT",(int)fmt); +} + + +int RDRecording::channels() const +{ + return GetIntValue("CHANNELS"); +} + + +void RDRecording::setChannels(int chan) const +{ + SetRow("CHANNELS",chan); +} + + +int RDRecording::sampleRate() const +{ + return GetIntValue("SAMPRATE"); +} + + +void RDRecording::setSampleRate(int rate) +{ + SetRow("SAMPRATE",rate); +} + + +int RDRecording::bitrate() const +{ + return GetIntValue("BITRATE"); +} + + +int RDRecording::quality() const +{ + return GetIntValue("QUALITY"); +} + + +void RDRecording::setQuality(int qual) const +{ + SetRow("QUALITY",qual); +} + + +void RDRecording::setBitrate(int rate) const +{ + SetRow("BITRATE",rate); +} + + +int RDRecording::normalizationLevel() const +{ + return GetIntValue("NORMALIZE_LEVEL"); +} + + +void RDRecording::setNormalizationLevel(int level) const +{ + SetRow("NORMALIZE_LEVEL",level); +} + + +int RDRecording::macroCart() const +{ + return GetIntValue("MACRO_CART"); +} + + +void RDRecording::setMacroCart(int cart) const +{ + SetRow("MACRO_CART",cart); +} + + +bool RDRecording::oneShot() const +{ + return GetBoolValue("ONE_SHOT"); +} + + +void RDRecording::setOneShot(bool state) const +{ + SetRow("ONE_SHOT",state); +} + + +RDRecording::StartType RDRecording::startType() const +{ + return (RDRecording::StartType)GetUIntValue("START_TYPE"); +} + + +void RDRecording::setStartType(StartType type) const +{ + SetRow("START_TYPE",(unsigned)type); +} + + +RDRecording::EndType RDRecording::endType() const +{ + return (RDRecording::EndType)GetUIntValue("END_TYPE"); +} + + +void RDRecording::setEndType(EndType type) const +{ + SetRow("END_TYPE",(unsigned)type); +} + + +int RDRecording::startMatrix() const +{ + return GetIntValue("START_MATRIX"); +} + + +void RDRecording::setStartMatrix(int matrix) const +{ + SetRow("START_MATRIX",matrix); +} + + +int RDRecording::startLine() const +{ + return GetIntValue("START_LINE"); +} + + +void RDRecording::setStartLine(int line) const +{ + SetRow("START_LINE",line); +} + + +int RDRecording::endMatrix() const +{ + return GetIntValue("END_MATRIX"); +} + + +void RDRecording::setEndMatrix(int matrix) const +{ + SetRow("END_MATRIX",matrix); +} + + +int RDRecording::endLine() const +{ + return GetIntValue("END_LINE"); +} + + +void RDRecording::setEndLine(int line) const +{ + SetRow("END_LINE",line); +} + + +int RDRecording::startLength() const +{ + return GetIntValue("START_LENGTH"); +} + + +void RDRecording::setStartLength(int len) const +{ + SetRow("START_LENGTH",len); +} + + +int RDRecording::endLength() const +{ + return GetIntValue("END_LENGTH"); +} + + +void RDRecording::setEndLength(int len) const +{ + SetRow("END_LENGTH",len); +} + + +int RDRecording::startOffset() const +{ + return GetIntValue("START_OFFSET"); +} + + +void RDRecording::setStartOffset(int offset) const +{ + SetRow("START_OFFSET",offset); +} + + +QString RDRecording::url() const +{ + return GetStringValue("URL"); +} + + +void RDRecording::setUrl(QString url) const +{ + SetRow("URL",url); +} + + +QString RDRecording::urlUsername() const +{ + return GetStringValue("URL_USERNAME"); +} + + +void RDRecording::setUrlUsername(QString name) const +{ + SetRow("URL_USERNAME",name); +} + + +QString RDRecording::urlPassword() const +{ + return GetStringValue("URL_PASSWORD"); +} + + +void RDRecording::setUrlPassword(QString passwd) const +{ + SetRow("URL_PASSWORD",passwd); +} + + +bool RDRecording::enableMetadata() const +{ + return GetBoolValue("ENABLE_METADATA"); +} + + +void RDRecording::setEnableMetadata(bool state) const +{ + SetRow("ENABLE_METADATA",state); +} + + +int RDRecording::feedId() const +{ + return GetIntValue("FEED_ID"); +} + + +void RDRecording::setFeedId(int id) const +{ + SetRow("FEED_ID",id); +} + + +void RDRecording::setFeedId(const QString &keyname) const +{ + QString sql=QString().sprintf("select ID from FEEDS where KEY_NAME=\"%s\"", + (const char *)keyname); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + setFeedId(q->value(0).toInt()); + } + else { + setFeedId(-1); + } + delete q; +} + + +QString RDRecording::feedKeyName() const +{ + QString ret; + QString sql=QString().sprintf("select KEY_NAME from FEEDS where ID=%d", + feedId()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + QString ret=q->value(0).toString(); + } + delete q; + return ret; +} + + +QString RDRecording::typeString(RDRecording::Type type) +{ + QString str; + + switch(type) { + case RDRecording::Recording: + str=QObject::tr("Recording"); + break; + + case RDRecording::MacroEvent: + str=QObject::tr("Macro Event"); + break; + + case RDRecording::SwitchEvent: + str=QObject::tr("Switch Event"); + break; + + case RDRecording::Playout: + str=QObject::tr("Playout"); + break; + + case RDRecording::Download: + str=QObject::tr("Download"); + break; + + case RDRecording::Upload: + str=QObject::tr("Upload"); + break; + } + + return str; +} + + +QString RDRecording::exitString(RDRecording::ExitCode code) +{ + QString ret; + + switch(code) { + case RDRecording::Ok: + ret=QObject::tr("Ok"); + break; + + case RDRecording::Short: + ret=QObject::tr("Short Length"); + break; + + case RDRecording::LowLevel: + ret=QObject::tr("Low Level"); + break; + + case RDRecording::HighLevel: + ret=QObject::tr("High Level"); + break; + + case RDRecording::Downloading: + ret=QObject::tr("Downloading"); + break; + + case RDRecording::Uploading: + ret=QObject::tr("Uploading"); + break; + + case RDRecording::ServerError: + ret=QObject::tr("Server Error"); + break; + + case RDRecording::InternalError: + ret=QObject::tr("Internal Error"); + break; + + case RDRecording::Interrupted: + ret=QObject::tr("Interrupted"); + break; + + case RDRecording::RecordActive: + ret=QObject::tr("Recording"); + break; + + case RDRecording::PlayActive: + ret=QObject::tr("Playing"); + break; + + case RDRecording::Waiting: + ret=QObject::tr("Waiting"); + break; + + case RDRecording::DeviceBusy: + ret=QObject::tr("Device Busy"); + break; + + case RDRecording::NoCut: + ret=QObject::tr("No Such Cart/Cut"); + break; + + case RDRecording::UnknownFormat: + ret=QObject::tr("Unknown Audio Format"); + break; + } + return ret; +} + + +int RDRecording::GetIntValue(QString field) const +{ + QString sql; + RDSqlQuery *q; + int accum; + + sql=QString().sprintf("select %s from RECORDINGS where ID=%d", + (const char *)field,rec_id); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toInt(); + delete q; + return accum; + } + delete q; + return 0; +} + + +unsigned RDRecording::GetUIntValue(QString field) const +{ + QString sql; + RDSqlQuery *q; + int accum; + + sql=QString().sprintf("select %s from RECORDINGS where ID=%d", + (const char *)field,rec_id); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toUInt(); + delete q; + return accum; + } + delete q; + return 0; +} + + +bool RDRecording::GetBoolValue(QString field) const +{ + QString sql; + RDSqlQuery *q; + bool state; + + sql=QString().sprintf("select %s from RECORDINGS where ID=%d", + (const char *)field,rec_id); + q=new RDSqlQuery(sql); + if(q->first()) { + state=RDBool(q->value(0).toString()); + delete q; + return state; + } + delete q; + return false; +} + + +QString RDRecording::GetStringValue(QString field) const +{ + QString sql; + RDSqlQuery *q; + QString accum; + + sql=QString().sprintf("select %s from RECORDINGS where ID=%d", + (const char *)field,rec_id); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toString(); + delete q; + return accum; + } + delete q; + return QString(); +} + + +QTime RDRecording::GetTimeValue(QString field) const +{ + QString sql; + RDSqlQuery *q; + QTime accum; + + sql=QString().sprintf("select %s from RECORDINGS where ID=%d", + (const char *)field,rec_id); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toTime(); + delete q; + return accum; + } + delete q; + return QTime(); +} + + +int RDRecording::AddRecord() const +{ + QString sql; + RDSqlQuery *q; + int n; + + sql=QString("select ID from RECORDINGS order by ID desc limit 1"); + q=new RDSqlQuery(sql); + if(q->first()) { + n=q->value(0).toInt()+1; + } + else { + n=1; + } + delete q; + sql=QString().sprintf("insert into RECORDINGS set ID=%d",n); + q=new RDSqlQuery(sql); + delete q; + return n; +} + + +void RDRecording::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update RECORDINGS set %s=%d where ID=%d", + (const char *)param,value,rec_id); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDRecording::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update RECORDINGS set %s=%u where ID=%d", + (const char *)param,value,rec_id); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDRecording::SetRow(const QString ¶m,bool value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update RECORDINGS set %s=\'%s\' where ID=%d", + (const char *)param,(const char *)RDYesNo(value), + rec_id); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDRecording::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update RECORDINGS set %s=\"%s\" where ID=%d", + (const char *)param, + (const char *)RDEscapeString(value), + rec_id); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDRecording::SetRow(const QString ¶m,const QTime &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update RECORDINGS set %s=\"%s\" where ID=%d", + (const char *)param, + (const char *)value.toString("hh:mm:ss"),rec_id); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdrecording.h b/lib/rdrecording.h new file mode 100644 index 00000000..4116bcbe --- /dev/null +++ b/lib/rdrecording.h @@ -0,0 +1,161 @@ +// rdrecording.h +// +// Abstract a Rivendell RDCatch Event +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdrecording.h,v 1.29 2011/06/21 18:31:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> +#include <qdatetime.h> + +#include <rdsettings.h> + +#ifndef RDRECORDING_H +#define RDRECORDING_H + +class RDRecording +{ + public: + enum StartType {HardStart=0,GpiStart=1}; + enum EndType {HardEnd=0,GpiEnd=1,LengthEnd=2}; + enum Type {Recording=0,MacroEvent=1,SwitchEvent=2,Playout=3, + Download=4,Upload=5}; + enum ExitCode {Ok=0,Short=1,LowLevel=2,HighLevel=3, + Downloading=4,Uploading=5,ServerError=6,InternalError=7, + Interrupted=8,RecordActive=9,PlayActive=10,Waiting=11, + DeviceBusy=12,NoCut=13,UnknownFormat=14}; + RDRecording(int id,bool create=false); + int id() const; + bool isActive() const; + void setIsActive(bool state) const; + QString station() const; + void setStation(QString name) const; + RDRecording::Type type() const; + void setType(RDRecording::Type type) const; + unsigned channel() const; + void setChannel(unsigned chan) const; + QTime startTime() const; + void setStartTime(QTime time) const; + QTime endTime() const; + void setEndTime(QTime time) const; + QString cutName() const; + void setCutName(QString name) const; + bool sun() const; + void setSun(bool state) const; + bool mon() const; + void setMon(bool state) const; + bool tue() const; + void setTue(bool state) const; + bool wed() const; + void setWed(bool state) const; + bool thu() const; + void setThu(bool state) const; + bool fri() const; + void setFri(bool state) const; + bool sat() const; + void setSat(bool state) const; + int switchSource() const; + void setSwitchSource(int input) const; + int switchDestination() const; + void setSwitchDestination(int output) const; + QString description() const; + void setDescription(QString string) const; + unsigned length() const; + void setLength(unsigned length) const; + int startGpi() const; + void setStartGpi(int line) const; + int endGpi() const; + void setEndGpi(int line) const; + bool allowMultipleRecordings() const; + void setAllowMultipleRecordings(bool state) const; + unsigned maxGpiRecordingLength() const; + void setMaxGpiRecordingLength(unsigned len) const; + unsigned trimThreshold() const; + void setTrimThreshold(unsigned level) const; + unsigned startdateOffset() const; + void setStartdateOffset(unsigned offset) const; + unsigned enddateOffset() const; + void setEnddateOffset(unsigned offset) const; + int eventdateOffset() const; + void setEventdateOffset(int offset) const; + RDSettings::Format format() const; + void setFormat(RDSettings::Format fmt) const; + int channels() const; + void setChannels(int chan) const; + int sampleRate() const; + void setSampleRate(int rate); + int bitrate() const; + void setBitrate(int rate) const; + int quality() const; + void setQuality(int qual) const; + int normalizationLevel() const; + void setNormalizationLevel(int level) const; + int macroCart() const; + void setMacroCart(int cart) const; + bool oneShot() const; + void setOneShot(bool state) const; + StartType startType() const; + void setStartType(StartType type) const; + EndType endType() const; + void setEndType(EndType type) const; + int startMatrix() const; + void setStartMatrix(int matrix) const; + int startLine() const; + void setStartLine(int line) const; + int endMatrix() const; + void setEndMatrix(int matrix) const; + int endLine() const; + void setEndLine(int line) const; + int startLength() const; + void setStartLength(int len) const; + int endLength() const; + void setEndLength(int len) const; + int startOffset() const; + void setStartOffset(int offset) const; + QString url() const; + void setUrl(QString url) const; + QString urlUsername() const; + void setUrlUsername(QString name) const; + QString urlPassword() const; + void setUrlPassword(QString passwd) const; + bool enableMetadata() const; + void setEnableMetadata(bool state) const; + int feedId() const; + void setFeedId(int id) const; + void setFeedId(const QString &keyname) const; + QString feedKeyName() const; + static QString typeString(RDRecording::Type type); + static QString exitString(RDRecording::ExitCode code); + + private: + int GetIntValue(QString field) const; + unsigned GetUIntValue(QString field) const; + bool GetBoolValue(QString field) const; + QString GetStringValue(QString field) const; + QTime GetTimeValue(QString field) const; + int AddRecord() const; + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,unsigned value) const; + void SetRow(const QString ¶m,bool value) const; + void SetRow(const QString ¶m,const QString &value) const; + void SetRow(const QString ¶m,const QTime &value) const; + int rec_id; +}; + + +#endif diff --git a/lib/rdreplicator.cpp b/lib/rdreplicator.cpp new file mode 100644 index 00000000..51f2be8e --- /dev/null +++ b/lib/rdreplicator.cpp @@ -0,0 +1,273 @@ +// rdreplicator.cpp +// +// Abstract a Rivendell replicator configuration +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdreplicator.cpp,v 1.3 2010/08/03 17:52:18 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdconf.h> +#include <rdescape_string.h> +#include <rddb.h> + +#include <rdreplicator.h> + +RDReplicator::RDReplicator(const QString &name) +{ + replicator_name=name; +} + + +QString RDReplicator::name() const +{ + return replicator_name; +} + + +RDReplicator::Type RDReplicator::type() const +{ + return (RDReplicator::Type)GetValue("TYPE_ID").toUInt(); +} + + +void RDReplicator::setType(RDReplicator::Type type) const +{ + SetRow("TYPE_ID",(unsigned)type); +} + + +QString RDReplicator::stationName() const +{ + return GetValue("STATION_NAME").toString(); +} + + +void RDReplicator::setStationName(const QString &str) +{ + SetRow("STATION_NAME",str); +} + + +QString RDReplicator::description() const +{ + return GetValue("DESCRIPTION").toString(); +} + + +void RDReplicator::setDescription(const QString &str) const +{ + SetRow("DESCRIPTION",str); +} + + +RDSettings::Format RDReplicator::format() const +{ + return (RDSettings::Format)GetValue("FORMAT").toUInt(); +} + + +void RDReplicator::setFormat(RDSettings::Format fmt) const +{ + SetRow("FORMAT",(unsigned)fmt); +} + + +unsigned RDReplicator::channels() const +{ + return GetValue("CHANNELS").toUInt(); +} + + +void RDReplicator::setChannels(unsigned chans) const +{ + SetRow("CHANNELS",chans); +} + + +unsigned RDReplicator::sampleRate() const +{ + return GetValue("SAMPRATE").toUInt(); +} + + +void RDReplicator::setSampleRate(unsigned rate) const +{ + SetRow("SAMPRATE",rate); +} + + +unsigned RDReplicator::bitRate() const +{ + return GetValue("BITRATE").toUInt(); +} + + +void RDReplicator::setBitRate(unsigned rate) const +{ + SetRow("BITRATE",rate); +} + + +unsigned RDReplicator::quality() const +{ + return GetValue("QUALITY").toUInt(); +} + + +void RDReplicator::setQuality(unsigned qual) const +{ + SetRow("QUALITY",qual); +} + + +QString RDReplicator::url() const +{ + return GetValue("URL").toString(); +} + + +void RDReplicator::setUrl(const QString &str) +{ + SetRow("URL",str); +} + + +QString RDReplicator::urlUsername() const +{ + return GetValue("URL_USERNAME").toString(); +} + + +void RDReplicator::setUrlUsername(const QString &str) const +{ + SetRow("URL_USERNAME",str); +} + + +QString RDReplicator::urlPassword() const +{ + return GetValue("URL_PASSWORD").toString(); +} + + +void RDReplicator::setUrlPassword(const QString &str) const +{ + SetRow("URL_PASSWORD",str); +} + + +bool RDReplicator::enableMetadate() const +{ + return RDBool(GetValue("ENABLE_PASSWORD").toString()); +} + + +void RDReplicator::setEnableMetadata(bool state) const +{ + SetRow("ENABLE_METADATA",RDYesNo(state)); +} + + +QString RDReplicator::typeString() const +{ + return RDReplicator::typeString(type()); +} + + +int RDReplicator::normalizeLevel() const +{ + return GetValue("NORMALIZATION_LEVEL").toInt(); +} + + +void RDReplicator::setNormalizeLevel(int lvl) const +{ + SetRow("NORMALIZATION_LEVEL",lvl); +} + + +QString RDReplicator::typeString(RDReplicator::Type type) +{ + QString ret="Unknown type"; + switch(type) { + case RDReplicator::TypeCitadelXds: + ret="Citadel X-Digital Portal"; + break; + + case RDReplicator::TypeLast: + break; + } + return ret; +} + + +QVariant RDReplicator::GetValue(const QString &field) const +{ + QVariant ret; + QString sql=QString().sprintf("select %s from REPLICATORS where NAME=\"%s\"", + (const char *)field, + (const char *)RDEscapeString(replicator_name)); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + ret=q->value(0); + } + delete q; + return ret; +} + + +void RDReplicator::SetRow(const QString ¶m,QString value) const +{ + RDSqlQuery *q; + QString sql; + + value.replace("\\","\\\\"); // Needed to preserve Windows pathnames + sql=QString().sprintf("update REPLICATORS set %s=\"%s\" where NAME=\"%s\"", + (const char *)param, + (const char *)RDEscapeString(value), + (const char *)RDEscapeString(replicator_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDReplicator::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update REPLICATORS set %s=%d where NAME=\"%s\"", + (const char *)param, + value, + (const char *)RDEscapeString(replicator_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDReplicator::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update REPLICATORS set %s=%u where NAME=\"%s\"", + (const char *)param, + value, + (const char *)RDEscapeString(replicator_name)); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdreplicator.h b/lib/rdreplicator.h new file mode 100644 index 00000000..da6e341d --- /dev/null +++ b/lib/rdreplicator.h @@ -0,0 +1,74 @@ +// rdreplicator.h +// +// Abstract a Rivendell replicator configuration +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdreplicator.h,v 1.3 2010/08/03 17:52:18 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDREPLICATOR_H +#define RDREPLICATOR_H + +#include <qvariant.h> + +#include <rdsettings.h> + +class RDReplicator +{ + public: + enum Type {TypeCitadelXds=0,TypeLast=1}; + RDReplicator(const QString &name); + QString name() const; + RDReplicator::Type type() const; + void setType(RDReplicator::Type type) const; + QString stationName() const; + void setStationName(const QString &str); + QString description() const; + void setDescription(const QString &str) const; + RDSettings::Format format() const; + void setFormat(RDSettings::Format fmt) const; + unsigned channels() const; + void setChannels(unsigned chans) const; + unsigned sampleRate() const; + void setSampleRate(unsigned rate) const; + unsigned bitRate() const; + void setBitRate(unsigned rate) const; + unsigned quality() const; + void setQuality(unsigned qual) const; + QString url() const; + void setUrl(const QString &str); + QString urlUsername() const; + void setUrlUsername(const QString &str) const; + QString urlPassword() const; + void setUrlPassword(const QString &str) const; + bool enableMetadate() const; + void setEnableMetadata(bool state) const; + int normalizeLevel() const; + void setNormalizeLevel(int lvl) const; + QString typeString() const; + static QString typeString(RDReplicator::Type type); + + private: + QVariant GetValue(const QString &field) const; + void SetRow(const QString ¶m,QString value) const; + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,unsigned value) const; + QString replicator_name; +}; + + +#endif // RDREPLICATOR_H diff --git a/lib/rdreport.cpp b/lib/rdreport.cpp new file mode 100644 index 00000000..e9c2be3e --- /dev/null +++ b/lib/rdreport.cpp @@ -0,0 +1,905 @@ +// rdreport.cpp +// +// Abstract a Rivendell Report Descriptor +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdreport.cpp,v 1.27.4.8.2.4 2014/06/24 18:27:05 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qfile.h> +#include <qobject.h> + +#include <rdconf.h> +#include <rdreport.h> +#include <rdcreate_log.h> +#include <rdlog_line.h> +#include <rdescape_string.h> +#include <rddb.h> +#include <rdescape_string.h> +#include <rddatedecode.h> + +RDReport::RDReport(const QString &rptname,QObject *parent,const char *name) +{ + report_name=rptname; + report_error_code=RDReport::ErrorOk; +} + + +QString RDReport::name() const +{ + return report_name; +} + + +bool RDReport::exists() const +{ + RDSqlQuery *q=new RDSqlQuery(QString().sprintf("select NAME from REPORTS\ + where NAME=\"%s\"", + (const char *) + RDEscapeString(report_name))); + if(!q->first()) { + delete q; + return false; + } + delete q; + return true; +} + + +QString RDReport::description() const +{ + return RDGetSqlValue("REPORTS","NAME",report_name,"DESCRIPTION").toString(); +} + + +void RDReport::setDescription(const QString &desc) const +{ + SetRow("DESCRIPTION",desc); +} + + +RDReport::ExportFilter RDReport::filter() const +{ + return (RDReport::ExportFilter)RDGetSqlValue("REPORTS","NAME",report_name, + "EXPORT_FILTER").toInt(); +} + + +void RDReport::setFilter(ExportFilter filter) const +{ + SetRow("EXPORT_FILTER",(int)filter); +} + + +QString RDReport::exportPath(ExportOs ostype) const +{ + return RDGetSqlValue("REPORTS","NAME",report_name,OsFieldName(ostype)). + toString(); +} + + +void RDReport::setExportPath(ExportOs ostype,const QString &path) const +{ + SetRow(OsFieldName(ostype),path); +} + + +bool RDReport::exportTypeEnabled(ExportType type) const +{ + return RDBool(RDGetSqlValue("REPORTS","NAME",report_name, + TypeFieldName(type,false)).toString()); +} + + +void RDReport::setExportTypeEnabled(ExportType type,bool state) const +{ + SetRow(TypeFieldName(type,false),RDYesNo(state)); +} + + +bool RDReport::exportTypeForced(ExportType type) const +{ + return RDBool(RDGetSqlValue("REPORTS","NAME",report_name, + TypeFieldName(type,true)).toString()); +} + + +void RDReport::setExportTypeForced(ExportType type,bool state) const +{ + SetRow(TypeFieldName(type,true),RDYesNo(state)); +} + + +QString RDReport::stationId() const +{ + return RDGetSqlValue("REPORTS","NAME",report_name,"STATION_ID").toString(); +} + + +void RDReport::setStationId(const QString &id) const +{ + SetRow("STATION_ID",id); +} + + +unsigned RDReport::cartDigits() const +{ + return RDGetSqlValue("REPORTS","NAME",report_name,"CART_DIGITS").toUInt(); +} + + +void RDReport::setCartDigits(unsigned num) const +{ + SetRow("CART_DIGITS",num); +} + + +bool RDReport::useLeadingZeros() const +{ + return RDBool(RDGetSqlValue("REPORTS","NAME",report_name,"USE_LEADING_ZEROS"). + toString()); +} + + +void RDReport::setUseLeadingZeros(bool state) const +{ + SetRow("USE_LEADING_ZEROS",state); +} + + +int RDReport::linesPerPage() const +{ + return RDGetSqlValue("REPORTS","NAME",report_name,"LINES_PER_PAGE").toInt(); +} + + +void RDReport::setLinesPerPage(int lines) const +{ + SetRow("LINES_PER_PAGE",lines); +} + + +QString RDReport::serviceName() const +{ + return RDGetSqlValue("REPORTS","NAME",report_name,"SERVICE_NAME").toString(); +} + + +void RDReport::setServiceName(const QString &name) const +{ + SetRow("SERVICE_NAME",name); +} + + +RDReport::StationType RDReport::stationType() const +{ + return (RDReport::StationType) + RDGetSqlValue("REPORTS","NAME",report_name,"STATION_TYPE").toInt(); +} + + +void RDReport::setStationType(RDReport::StationType type) const +{ + SetRow("STATION_TYPE",(int)type); +} + + +QString RDReport::stationFormat() const +{ + return RDGetSqlValue("REPORTS","NAME",report_name,"STATION_FORMAT"). + toString(); +} + + +void RDReport::setStationFormat(const QString &fmt) const +{ + SetRow("STATION_FORMAT",fmt); +} + + +bool RDReport::filterOnairFlag() const +{ + return RDBool(RDGetSqlValue("REPORTS","NAME",report_name,"FILTER_ONAIR_FLAG"). + toString()); +} + + +void RDReport::setFilterOnairFlag(bool state) const +{ + SetRow("FILTER_ONAIR_FLAG",RDYesNo(state)); +} + + +bool RDReport::filterGroups() const +{ + return RDBool(RDGetSqlValue("REPORTS","NAME",report_name,"FILTER_GROUPS"). + toString()); +} + + +void RDReport::setFilterGroups(bool state) const +{ + SetRow("FILTER_GROUPS",RDYesNo(state)); +} + + +QTime RDReport::startTime(bool *is_null) const +{ + if(is_null!=NULL) { + if(RDIsSqlNull("REPORTS","NAME",report_name,"START_TIME")) { + *is_null=true; + return QTime(); + } + *is_null=false; + } + return RDGetSqlValue("REPORTS","NAME",report_name,"START_TIME").toTime(); +} + + +void RDReport::setStartTime(const QTime &time) const +{ + SetRow("START_TIME",time); +} + + +void RDReport::setStartTime() const +{ + SetRowNull("START_TIME"); +} + + +QTime RDReport::endTime(bool *is_null) const +{ + if(is_null!=NULL) { + if(RDIsSqlNull("REPORTS","NAME",report_name,"END_TIME")) { + *is_null=true; + return QTime(); + } + *is_null=false; + } + return RDGetSqlValue("REPORTS","NAME",report_name,"END_TIME").toTime(); +} + + + +void RDReport::setEndTime(const QTime &time) const +{ + SetRow("END_TIME",time); +} + + +void RDReport::setEndTime() const +{ + SetRowNull("END_TIME"); +} + + +RDReport::ErrorCode RDReport::errorCode() const +{ + return report_error_code; +} + + +bool RDReport::outputExists(const QDate &startdate) +{ + QString out_path; +#ifdef WIN32 + out_path=RDDateDecode(exportPath(RDReport::Windows),startdate); +#else + out_path=RDDateDecode(exportPath(RDReport::Linux),startdate); +#endif + return QFile::exists(out_path); +} + + +bool RDReport::generateReport(const QDate &startdate,const QDate &enddate, + RDStation *station,QString *out_path) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + RDSqlQuery *q2; + RDSvc *svc; + QString rec_name; + QString daypart_sql; + QString station_sql; + QString group_sql; + QString force_sql; + bool is_null=false; + + if(!exists()) { + return false; + } + + // + // Generate the daypart filter + // + startTime(&is_null); + if(!is_null) { + for(int i=0;i<(startdate.daysTo(enddate)+1);i++) { + QDate date=startdate.addDays(i); + if(startTime()<endTime()) { + daypart_sql+=QString("((EVENT_DATETIME>=\"")+ + date.toString("yyyy-MM-dd")+ + " "+startTime().toString("hh:mm:ss")+"\")&&"+ + "(EVENT_DATETIME<\""+date.toString("yyyy-MM-dd")+ + " "+endTime().toString("hh:mm:ss")+"\"))||"; + } + else { + daypart_sql+=QString("((EVENT_DATETIME<=\"")+ + date.toString("yyyy-MM-dd")+ + " "+endTime().toString("hh:mm:ss")+"\")&&"+ + "(EVENT_DATETIME>\""+date.toString("yyyy-MM-dd")+" 00:00:00))||"+ + "((EVENT_DATETIME>=\""+ + date.toString("yyyy-MM-dd")+ + " "+startTime().toString("hh:mm:ss")+"\")&&"+ + "(EVENT_DATETIME<\""+date.toString("yyyy-MM-dd")+" 23:59:59))||"; + + } + } + daypart_sql=daypart_sql.left(daypart_sql.length()-2); + } + + // + // Generate the Station List + // + sql=QString().sprintf("select STATION_NAME from REPORT_STATIONS \ + where REPORT_NAME=\"%s\"", + (const char *)name()); + q=new RDSqlQuery(sql); + while(q->next()) { + station_sql+=QString().sprintf("(STATION_NAME=\"%s\")||", + (const char *)q->value(0).toString()); + } + delete q; + station_sql=station_sql.left(station_sql.length()-2); + + // + // Next, the group list + // + bool where=false; + if(exportTypeEnabled(RDReport::Generic)) { + sql="select NAME from GROUPS "; + } + else { + where=true; + sql="select NAME from GROUPS where "; + if(exportTypeEnabled(RDReport::Traffic)) { + sql+="(REPORT_TFC=\"Y\")||"; + } + if(exportTypeEnabled(RDReport::Music)) { + sql+="(REPORT_MUS=\"Y\")||"; + } + } + if(filterGroups()) { + QString sql2=QString().sprintf("select GROUP_NAME from REPORT_GROUPS \ + where REPORT_NAME=\"%s\"", + (const char *)RDEscapeString(name())); + q=new RDSqlQuery(sql2); + while(q->next()) { + if(!where) { + sql+="where "; + where=true; + } + sql+=QString().sprintf("(NAME=\"%s\")||", + (const char *)RDEscapeString(q->value(0).toString())); + } + delete q; + } + sql=sql.left(sql.length()-2); + q=new RDSqlQuery(sql); + while(q->next()) { + group_sql+=QString().sprintf("(CART.GROUP_NAME=\"%s\")||", + (const char *)q->value(0).toString()); + } + delete q; + group_sql=group_sql.left(group_sql.length()-2); + if(group_sql.length()==2) { + group_sql=""; + } + + // + // Generate Mixdown Table + // + QString mixname="MIXDOWN"+station->name(); + sql=QString().sprintf("drop table `%s_SRT`",(const char *)mixname); + QSqlQuery *p; + p=new QSqlQuery(sql); + delete p; + sql=RDCreateReconciliationTableSql(mixname); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("select SERVICE_NAME from REPORT_SERVICES \ + where REPORT_NAME=\"%s\"", + (const char *)name()); + q=new RDSqlQuery(sql); + while(q->next()) { + svc=new RDSvc(q->value(0).toString()); + if(svc->exists()) { + rec_name=q->value(0).toString(); + rec_name.replace(" ","_"); + force_sql=""; + if(exportTypeForced(RDReport::Traffic)) { + force_sql+=QString().sprintf("(`%s_SRT`.EVENT_SOURCE=%d)||", + (const char *)rec_name, + RDLogLine::Traffic); + } + if(exportTypeForced(RDReport::Music)) { + force_sql+=QString().sprintf("(`%s_SRT`.EVENT_SOURCE=%d)||", + (const char *)rec_name, + RDLogLine::Music); + } + force_sql=force_sql.left(force_sql.length()-2); + + sql=QString().sprintf("select LENGTH,LOG_ID,CART_NUMBER,STATION_NAME,\ + EVENT_DATETIME,EVENT_TYPE,EXT_START_TIME,\ + EXT_LENGTH,EXT_DATA,EXT_EVENT_ID,EXT_ANNC_TYPE,\ + PLAY_SOURCE,CUT_NUMBER,EVENT_SOURCE,EXT_CART_NAME,\ + LOG_NAME,`%s_SRT`.TITLE,`%s_SRT`.ARTIST,\ + SCHEDULED_TIME,\ + START_SOURCE,`%s_SRT`.PUBLISHER,`%s_SRT`.COMPOSER,\ + `%s_SRT`.ALBUM,`%s_SRT`.LABEL,\ + `%s_SRT`.ISRC,`%s_SRT`.USAGE_CODE,\ + `%s_SRT`.ONAIR_FLAG,`%s_SRT`.ISCI,\ + `%s_SRT`.CONDUCTOR,`%s_SRT`.USER_DEFINED,\ + `%s_SRT`.SONG_ID from `%s_SRT`\ + left join CART on `%s_SRT`.CART_NUMBER=CART.NUMBER \ + where ", + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name, + (const char *)rec_name); + if(filterOnairFlag()) { + sql+="(ONAIR_FLAG=\"Y\")&&"; + } + sql+="("; + if(!group_sql.isEmpty()) { + sql+=QString("(")+group_sql+")&&"; + } + if(!force_sql.isEmpty()) { + sql+=QString("(")+force_sql+")&&"; + } + if(daypart_sql.isEmpty()) { + sql+=QString("(EVENT_DATETIME>=\"")+startdate.toString("yyyy-MM-dd")+ + " 00:00:00\")&&"+ + "(EVENT_DATETIME<=\""+enddate.toString("yyyy-MM-dd")+ + " 23:59:59\")&&"; + } + else { + sql+=(QString("(")+daypart_sql+")&&"); + } + if(!station_sql.isEmpty()) { + sql+=QString("(")+station_sql+")||"; + } + sql=sql.left(sql.length()-2); + sql+=")"; + //printf("SQL: %s\n",(const char *)sql); + q1=new RDSqlQuery(sql); + while(q1->next()) { + sql=QString("insert into `")+mixname+"_SRT` "+ + "set "+QString().sprintf("LENGTH=%d,LOG_ID=%u,CART_NUMBER=%u,", + q1->value(0).toInt(), + q1->value(1).toUInt(), + q1->value(2).toInt())+ + "STATION_NAME=\""+RDEscapeString(q1->value(3).toString())+"\","+ + "EVENT_DATETIME=\""+RDEscapeString(q1->value(4).toDateTime(). + toString("yyyy-MM-dd hh:mm:ss"))+"\","+ + QString().sprintf("EVENT_TYPE=%d,",q1->value(5).toInt())+ + "EXT_START_TIME=\""+RDEscapeString(q1->value(6).toString())+"\","+ + QString().sprintf("EXT_LENGTH=%d,",q1->value(7).toInt())+ + "EXT_DATA=\""+RDEscapeString(q1->value(8).toString())+"\","+ + "EXT_EVENT_ID=\""+RDEscapeString(q1->value(9).toString())+"\","+ + "EXT_ANNC_TYPE=\""+RDEscapeString(q1->value(10).toString())+"\","+ + QString().sprintf("PLAY_SOURCE=%d,CUT_NUMBER=%d,EVENT_SOURCE=%d,", + q1->value(11).toInt(), + q1->value(12).toInt(), + q1->value(13).toInt())+ + "EXT_CART_NAME=\""+RDEscapeString(q1->value(14).toString())+"\","+ + "LOG_NAME=\""+RDEscapeString(q1->value(15).toString())+"\","+ + "TITLE=\""+RDEscapeString(q1->value(16).toString())+"\","+ + "ARTIST=\""+RDEscapeString(q1->value(17).toString())+"\","+ + "SCHEDULED_TIME=\""+ + q1->value(18).toDate().toString("yyyy-MM-dd hh:mm:ss")+"\","+ + QString().sprintf("START_SOURCE=%d,",q1->value(19).toInt())+ + "PUBLISHER=\""+RDEscapeString(q1->value(20).toString())+"\","+ + "COMPOSER=\""+RDEscapeString(q1->value(21).toString())+"\","+ + "ALBUM=\""+RDEscapeString(q1->value(22).toString())+"\","+ + "LABEL=\""+RDEscapeString(q1->value(23).toString())+"\","+ + "ISRC=\""+RDEscapeString(q1->value(24).toString())+"\","+ + QString().sprintf("USAGE_CODE=%d,",q1->value(25).toInt())+ + "ONAIR_FLAG=\""+RDEscapeString(q1->value(26).toString())+"\","+ + "ISCI=\""+RDEscapeString(q1->value(27).toString())+"\","+ + "CONDUCTOR=\""+RDEscapeString(q1->value(28).toString())+"\","+ + "USER_DEFINED=\""+RDEscapeString(q1->value(29).toString())+"\","+ + "SONG_ID=\""+RDEscapeString(q1->value(30).toString())+"\""; + q2=new RDSqlQuery(sql); + delete q2; + } + delete q1; + } + delete svc; + } + delete q; + + bool ret=false; + switch(filter()) { + case RDReport::CbsiDeltaFlex: + ret=ExportDeltaflex(startdate,enddate,mixname); + break; + + case RDReport::TextLog: + ret=ExportTextLog(startdate,enddate,mixname); + break; + + case RDReport::BmiEmr: + ret=ExportBmiEmr(startdate,enddate,mixname); + break; + + case RDReport::NaturalLog: + case RDReport::Technical: + ret=ExportTechnical(startdate,enddate,mixname); + break; + + case RDReport::SoundExchange: + ret=ExportSoundEx(startdate,enddate,mixname); + break; + + case RDReport::NprSoundExchange: + ret=ExportNprSoundEx(startdate,enddate,mixname); + break; + + case RDReport::RadioTraffic: + ret=ExportRadioTraffic(startdate,enddate,mixname); + break; + + case RDReport::VisualTraffic: + ret=ExportDeltaflex(startdate,enddate,mixname); + break; + + case RDReport::CounterPoint: + case RDReport::WideOrbit: + ret=ExportRadioTraffic(startdate,enddate,mixname); + break; + + case RDReport::Music1: + ret=ExportRadioTraffic(startdate,enddate,mixname); + break; + + case RDReport::MusicClassical: + ret=ExportMusicClassical(startdate,enddate,mixname); + break; + + case RDReport::MusicPlayout: + ret=ExportMusicPlayout(startdate,enddate,mixname); + break; + + case RDReport::MusicSummary: + ret=ExportMusicSummary(startdate,enddate,mixname); + break; + + default: + return false; + break; + } +#ifdef WIN32 + *out_path=RDDateDecode(exportPath(RDReport::Windows),startdate); +#else + *out_path=RDDateDecode(exportPath(RDReport::Linux),startdate); +#endif + // printf("MIXDOWN TABLE: %s_SRT\n",(const char *)mixname); + sql=QString().sprintf("drop table `%s_SRT`",(const char *)mixname); + q=new RDSqlQuery(sql); + delete q; + return ret; +} + + +QString RDReport::filterText(RDReport::ExportFilter filter) +{ + switch(filter) { + case RDReport::CbsiDeltaFlex: + return QObject::tr("CBSI DeltaFlex Traffic Reconciliation v2.01"); + + case RDReport::TextLog: + return QObject::tr("Text Log"); + + case RDReport::BmiEmr: + return QObject::tr("ASCAP/BMI Electronic Music Report"); + + case RDReport::Technical: + return QObject::tr("Technical Playout Report"); + + case RDReport::SoundExchange: + return QObject::tr("SoundExchange Statutory License Report"); + + case RDReport::NprSoundExchange: + return QObject::tr("NPR/DS SoundExchange Report"); + + case RDReport::RadioTraffic: + return QObject::tr("RadioTraffic.com Traffic Reconciliation"); + + case RDReport::VisualTraffic: + return QObject::tr("VisualTraffic Reconciliation"); + + case RDReport::CounterPoint: + return QObject::tr("CounterPoint Traffic Reconciliation"); + + case RDReport::Music1: + return QObject::tr("Music1 Reconciliation"); + + case RDReport::MusicClassical: + return QObject::tr("Classical Music Playout"); + + case RDReport::MusicPlayout: + return QObject::tr("Music Playout"); + + case RDReport::MusicSummary: + return QObject::tr("Music Summary"); + + case RDReport::NaturalLog: + return QObject::tr("NaturalLog Reconciliation"); + + case RDReport::WideOrbit: + return QObject::tr("WideOrbit Traffic Reconciliation"); + + default: + return QObject::tr("Unknown"); + } + return QObject::tr("Unknown"); +} + + +QString RDReport::stationTypeText(RDReport::StationType type) +{ + switch(type) { + case RDReport::TypeOther: + return QObject::tr("Other"); + + case RDReport::TypeAm: + return QObject::tr("AM"); + + case RDReport::TypeFm: + return QObject::tr("FM"); + + default: + break; + } + return QObject::tr("Unknown"); +} + + +bool RDReport::multipleDaysAllowed(RDReport::ExportFilter filter) +{ + switch(filter) { + case RDReport::CbsiDeltaFlex: + case RDReport::TextLog: + case RDReport::RadioTraffic: + case RDReport::VisualTraffic: + case RDReport::CounterPoint: + case RDReport::LastFilter: + case RDReport::Music1: + case RDReport::MusicClassical: + case RDReport::MusicPlayout: + case RDReport::NaturalLog: + case RDReport::WideOrbit: + return false; + + case RDReport::BmiEmr: + case RDReport::MusicSummary: + case RDReport::NprSoundExchange: + case RDReport::SoundExchange: + case RDReport::Technical: + return true; + } + return true; +} + + +bool RDReport::multipleMonthsAllowed(RDReport::ExportFilter filter) +{ + switch(filter) { + case RDReport::CbsiDeltaFlex: + case RDReport::TextLog: + case RDReport::BmiEmr: + case RDReport::RadioTraffic: + case RDReport::VisualTraffic: + case RDReport::CounterPoint: + case RDReport::LastFilter: + case RDReport::Music1: + case RDReport::MusicClassical: + case RDReport::MusicPlayout: + case RDReport::NaturalLog: + case RDReport::WideOrbit: + return false; + + case RDReport::MusicSummary: + case RDReport::NprSoundExchange: + case RDReport::SoundExchange: + case RDReport::Technical: + return true; + } + return true; +} + + +QString RDReport::errorText(RDReport::ErrorCode code) +{ + QString ret; + switch(code) { + case RDReport::ErrorOk: + ret=QObject::tr("Report complete!"); + break; + + case RDReport::ErrorCanceled: + ret=QObject::tr("Report canceled!"); + break; + + case RDReport::ErrorCantOpen: + ret=QObject::tr("Unable to open report file!"); + break; + } + return ret; +} + + +QString RDReport::StringField(const QString &str,const QString &null_text) const +{ + QString ret=null_text; + + if(!str.isEmpty()) { + ret=str; + } + + return ret; +} + + +void RDReport::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE REPORTS SET %s=\"%s\" WHERE NAME=\"%s\"", + (const char *)param, + (const char *)RDEscapeString(value), + (const char *)report_name); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDReport::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE REPORTS SET %s=%d WHERE NAME=\"%s\"", + (const char *)param, + value, + (const char *)report_name); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDReport::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE REPORTS SET %s=%u WHERE NAME=\"%s\"", + (const char *)param, + value, + (const char *)report_name); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDReport::SetRow(const QString ¶m,bool value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE REPORTS SET %s=\"%s\" WHERE NAME=\"%s\"", + (const char *)param, + (const char *)RDYesNo(value), + (const char *)report_name); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDReport::SetRow(const QString ¶m,const QTime &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE REPORTS SET %s=\"%s\" WHERE NAME=\"%s\"", + (const char *)param, + (const char *)value.toString("hh:mm:ss"), + (const char *)report_name); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDReport::SetRowNull(const QString ¶m) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString("update REPORTS set ")+param+"=NULL where NAME=\""+ + RDEscapeString(report_name)+"\""; + q=new RDSqlQuery(sql); + delete q; +} + + +QString RDReport::OsFieldName(ExportOs os) const +{ + switch(os) { + case RDReport::Linux: + return QString("EXPORT_PATH"); + + case RDReport::Windows: + return QString("WIN_EXPORT_PATH"); + } + return QString(); +} + + +QString RDReport::TypeFieldName(ExportType type,bool forced) const +{ + if(forced) { + switch(type) { + case RDReport::Traffic: + return QString("FORCE_TFC"); + + case RDReport::Music: + return QString("FORCE_MUS"); + + default: + return QString(); + } + } + else { + switch(type) { + case RDReport::Generic: + return QString("EXPORT_GEN"); + + case RDReport::Traffic: + return QString("EXPORT_TFC"); + + case RDReport::Music: + return QString("EXPORT_MUS"); + } + return QString(); + } + return QString(); +} diff --git a/lib/rdreport.h b/lib/rdreport.h new file mode 100644 index 00000000..e569f08b --- /dev/null +++ b/lib/rdreport.h @@ -0,0 +1,129 @@ +// rdreport.h +// +// Abstract a Rivendell Report Descriptor +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdreport.h,v 1.17.8.7.2.4 2014/05/22 01:21:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDREPORT_H +#define RDREPORT_H + +#include <qobject.h> +#include <qsqldatabase.h> + +#include <rdstation.h> +#include <rdsvc.h> +#include <rdlog_line.h> + +class RDReport +{ + public: + enum ExportFilter {CbsiDeltaFlex=0,TextLog=1,BmiEmr=2,Technical=3, + SoundExchange=4,RadioTraffic=5,VisualTraffic=6, + CounterPoint=7,Music1=8,MusicSummary=9,WideOrbit=10, + NprSoundExchange=11,MusicPlayout=12,NaturalLog=13, + MusicClassical=14,LastFilter=15}; + enum ExportOs {Linux=0,Windows=1}; + enum ExportType {Generic=0,Traffic=1,Music=2}; + enum StationType {TypeOther=0,TypeAm=1,TypeFm=2,TypeLast=3}; + enum ErrorCode {ErrorOk=0,ErrorCanceled=1,ErrorCantOpen=2}; + RDReport(const QString &rptname,QObject *parent=0,const char *name=0); + QString name() const; + bool exists() const; + QString description() const; + void setDescription(const QString &desc) const; + ExportFilter filter() const; + void setFilter(ExportFilter filter) const; + QString exportPath(ExportOs ostype) const; + void setExportPath(ExportOs ostype,const QString &path) const; + bool exportTypeEnabled(ExportType type) const; + void setExportTypeEnabled(ExportType type,bool state) const; + bool exportTypeForced(ExportType type) const; + void setExportTypeForced(ExportType type,bool state) const; + QString stationId() const; + void setStationId(const QString &id) const; + unsigned cartDigits() const; + void setCartDigits(unsigned num) const; + bool useLeadingZeros() const; + void setUseLeadingZeros(bool state) const; + int linesPerPage() const; + void setLinesPerPage(int lines) const; + QString serviceName() const; + void setServiceName(const QString &name) const; + RDReport::StationType stationType() const; + void setStationType(RDReport::StationType type) const; + QString stationFormat() const; + void setStationFormat(const QString &fmt) const; + RDLogLine::StartSource startSource() const; + void setStartSource(RDLogLine::StartSource src) const; + bool filterOnairFlag() const; + void setFilterOnairFlag(bool state) const; + bool filterGroups() const; + void setFilterGroups(bool state) const; + QTime startTime(bool *is_null=NULL) const; + void setStartTime(const QTime &time) const; + void setStartTime() const; + QTime endTime(bool *is_null=NULL) const; + void setEndTime(const QTime &time) const; + void setEndTime() const; + RDReport::ErrorCode errorCode() const; + bool outputExists(const QDate &startdate); + bool generateReport(const QDate &startdate,const QDate &enddate, + RDStation *station,QString *out_path); + static QString filterText(RDReport::ExportFilter filter); + static QString stationTypeText(RDReport::StationType type); + static bool multipleDaysAllowed(RDReport::ExportFilter filter); + static bool multipleMonthsAllowed(RDReport::ExportFilter filter); + static QString errorText(RDReport::ErrorCode code); + + private: + bool ExportDeltaflex(const QDate &startdate,const QDate &enddate, + const QString &mixtable); + bool ExportTextLog(const QDate &startdate,const QDate &enddate, + const QString &mixtable); + bool ExportBmiEmr(const QDate &startdate,const QDate &enddate, + const QString &mixtable); + bool ExportTechnical(const QDate &startdate,const QDate &enddate, + const QString &mixtable); + bool ExportSoundEx(const QDate &startdate,const QDate &enddate, + const QString &mixtable); + bool ExportNprSoundEx(const QDate &startdate,const QDate &enddate, + const QString &mixtable); + bool ExportRadioTraffic(const QDate &startdate,const QDate &enddate, + const QString &mixtable); + bool ExportMusicClassical(const QDate &startdate,const QDate &enddate, + const QString &mixtable); + bool ExportMusicPlayout(const QDate &startdate,const QDate &enddate, + const QString &mixtable); + bool ExportMusicSummary(const QDate &startdate,const QDate &enddate, + const QString &mixtable); + QString StringField(const QString &str,const QString &null_text="") const; + void SetRow(const QString ¶m,const QString &value) const; + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,unsigned value) const; + void SetRow(const QString ¶m,bool value) const; + void SetRow(const QString ¶m,const QTime &value) const; + void SetRowNull(const QString ¶m) const; + QString OsFieldName(ExportOs os) const; + QString TypeFieldName(ExportType type,bool forced) const; + QString report_name; + RDReport::ErrorCode report_error_code; +}; + + +#endif // RDREPORT_H diff --git a/lib/rdringbuffer.cpp b/lib/rdringbuffer.cpp new file mode 100644 index 00000000..1da428c1 --- /dev/null +++ b/lib/rdringbuffer.cpp @@ -0,0 +1,269 @@ +// rdringbuffer.cpp +// +// A lock-free ring buffer. +// +// (C) Copyright 2000 Paul Davis +// (C) Copyright 2003 Rohan Drape +// (C) Copyright 2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdringbuffer.cpp,v 1.4 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Adapted from code by Paul Davis and Rohan Drape in +// 'example-clients/ringbuffer.ch' in the Jack Audio Connection Kit. +// + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/mman.h> + +#include <rdringbuffer.h> + +RDRingBuffer::RDRingBuffer(int sz) +{ + int power_of_two; + + rb = (ringbuffer_t *)malloc(sizeof (ringbuffer_t)); + + for (power_of_two = 1; 1 << power_of_two < sz; power_of_two++); + + rb->size = 1 << power_of_two; + rb->size_mask = rb->size; + rb->size_mask -= 1; + rb->write_ptr = 0; + rb->read_ptr = 0; + rb->buf = (char *)malloc (rb->size); + rb->mlocked = 0; +} + + +RDRingBuffer::~RDRingBuffer() +{ + if (rb->mlocked) { + munlock (rb->buf, rb->size); + } + free (rb->buf); + free (rb); +} + + +bool RDRingBuffer::mlock() +{ + if (::mlock (rb->buf, rb->size)) { + return false; + } + rb->mlocked = 1; + return true; +} + + +void RDRingBuffer::reset() +{ + rb->read_ptr = 0; + rb->write_ptr = 0; +} + + +void RDRingBuffer::writeAdvance(size_t cnt) +{ + rb->write_ptr += cnt; + rb->write_ptr &= rb->size_mask; +} + + +void RDRingBuffer::readAdvance(size_t cnt) +{ + rb->read_ptr += cnt; + rb->read_ptr &= rb->size_mask; +} + + +size_t RDRingBuffer::writeSpace() const +{ + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) { + return ((r - w + rb->size) & rb->size_mask) - 1; + } else if (w < r) { + return (r - w) - 1; + } + return rb->size - 1; +} + + +size_t RDRingBuffer::readSpace() const +{ + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) { + return w - r; + } + return (w - r + rb->size) & rb->size_mask; +} + + +size_t RDRingBuffer::read(char *dest,size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_read; + size_t n1, n2; + + if ((free_cnt = readSpace()) == 0) { + return 0; + } + + to_read = cnt > free_cnt ? free_cnt : cnt; + + cnt2 = rb->read_ptr + to_read; + + if (cnt2 > rb->size) { + n1 = rb->size - rb->read_ptr; + n2 = cnt2 & rb->size_mask; + } else { + n1 = to_read; + n2 = 0; + } + + memcpy (dest, &(rb->buf[rb->read_ptr]), n1); + rb->read_ptr += n1; + rb->read_ptr &= rb->size_mask; + + if (n2) { + memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2); + rb->read_ptr += n2; + rb->read_ptr &= rb->size_mask; + } + + return to_read; +} + + +size_t RDRingBuffer::write(char *src,size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_write; + size_t n1, n2; + + if ((free_cnt = writeSpace()) == 0) { + return 0; + } + + to_write = cnt > free_cnt ? free_cnt : cnt; + + cnt2 = rb->write_ptr + to_write; + + if (cnt2 > rb->size) { + n1 = rb->size - rb->write_ptr; + n2 = cnt2 & rb->size_mask; + } else { + n1 = to_write; + n2 = 0; + } + + memcpy (&(rb->buf[rb->write_ptr]), src, n1); + rb->write_ptr += n1; + rb->write_ptr &= rb->size_mask; + + if (n2) { + memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2); + rb->write_ptr += n2; + rb->write_ptr &= rb->size_mask; + } + + return to_write; +} + + +void RDRingBuffer::getReadVector(ringbuffer_data_t *vec) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) { + free_cnt = w - r; + } else { + free_cnt = (w - r + rb->size) & rb->size_mask; + } + + cnt2 = r + free_cnt; + + if (cnt2 > rb->size) { + + /* Two part vector: the rest of the buffer after the current write + ptr, plus some from the start of the buffer. */ + + vec[0].buf = &(rb->buf[r]); + vec[0].len = rb->size - r; + vec[1].buf = rb->buf; + vec[1].len = cnt2 & rb->size_mask; + + } else { + + /* Single part vector: just the rest of the buffer */ + + vec[0].buf = &(rb->buf[r]); + vec[0].len = free_cnt; + vec[1].len = 0; + } +} + + +void RDRingBuffer::getWriteVector(ringbuffer_data_t *vec) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + + if (w > r) { + free_cnt = ((r - w + rb->size) & rb->size_mask) - 1; + } else if (w < r) { + free_cnt = (r - w) - 1; + } else { + free_cnt = rb->size - 1; + } + + cnt2 = w + free_cnt; + + if (cnt2 > rb->size) { + + /* Two part vector: the rest of the buffer after the current write + ptr, plus some from the start of the buffer. */ + + vec[0].buf = &(rb->buf[w]); + vec[0].len = rb->size - w; + vec[1].buf = rb->buf; + vec[1].len = cnt2 & rb->size_mask; + } else { + vec[0].buf = &(rb->buf[w]); + vec[0].len = free_cnt; + vec[1].len = 0; + } +} diff --git a/lib/rdringbuffer.h b/lib/rdringbuffer.h new file mode 100644 index 00000000..33624f3f --- /dev/null +++ b/lib/rdringbuffer.h @@ -0,0 +1,73 @@ +// rdringbuffer.h +// +// A lock-free ring buffer. +// +// (C) Copyright 2000 Paul Davis +// (C) Copyright 2003 Rohan Drape +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdringbuffer.h,v 1.5 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Adapted from code by Paul Davis and Rohan Drape in +// 'example-clients/ringbuffer.ch' in the Jack Audio Connection Kit. +// + +#ifndef RDRINGBUFFER_H +#define RDRINGBUFFER_H + +#include <sys/types.h> + +typedef struct +{ + char *buf; + size_t len; +} +ringbuffer_data_t ; + +typedef struct +{ + char *buf; + volatile size_t write_ptr; + volatile size_t read_ptr; + size_t size; + size_t size_mask; + int mlocked; +} +ringbuffer_t ; + +class RDRingBuffer +{ + public: + RDRingBuffer(int sz); + ~RDRingBuffer(); + bool mlock(); + void reset(); + void writeAdvance(size_t cnt); + void readAdvance(size_t cnt); + size_t writeSpace() const; + size_t readSpace() const; + size_t read(char *dest,size_t cnt); + size_t write(char *src,size_t cnt); + void getReadVector(ringbuffer_data_t *vec); + void getWriteVector(ringbuffer_data_t *vec); + + private: + ringbuffer_t *rb; +}; + + +#endif // RDRINGBUFFER_H + diff --git a/lib/rdripc.cpp b/lib/rdripc.cpp new file mode 100644 index 00000000..b99f5b34 --- /dev/null +++ b/lib/rdripc.cpp @@ -0,0 +1,432 @@ +// rdripc.cpp +// +// Connection to the Rivendell Interprocess Communication Daemon +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdripc.cpp,v 1.36.6.2 2013/03/09 00:21:11 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <ctype.h> + +#include <qobject.h> +#include <qapplication.h> + +#include <rddb.h> +#include <rdripc.h> + + +RDRipc::RDRipc(QString stationname,QObject *parent,const char *name) + : QObject(parent,name) +{ + ripc_stationname=stationname; + ripc_onair_flag=false; + ripc_ignore_mask=false; + debug=false; + argnum=0; + argptr=0; + + ripc_connected=false; + + // + // TCP Connection + // + ripc_socket=new QSocket(this,"ripc_socket"); + connect(ripc_socket,SIGNAL(connected()),this,SLOT(connectedData())); + connect(ripc_socket,SIGNAL(error(int)),this,SLOT(errorData(int))); + connect(ripc_socket,SIGNAL(readyRead()),this,SLOT(readyData())); +} + + +RDRipc::~RDRipc() +{ + delete ripc_socket; +} + + +QString RDRipc::user() const +{ + return ripc_user; +} + + +QString RDRipc::station() const +{ + return ripc_stationname; +} + + +bool RDRipc::onairFlag() const +{ + return ripc_onair_flag; +} + + +void RDRipc::setUser(QString user) +{ + SendCommand(QString().sprintf("SU %s!",(const char *)user)); +} + + +void RDRipc::setIgnoreMask(bool state) +{ + ripc_ignore_mask=state; +} + + +void RDRipc::connectHost(QString hostname,Q_UINT16 hostport,QString password) +{ + ripc_password=password; + ripc_socket->connectToHost(hostname,hostport); +} + + +void RDRipc::connectedData() +{ + SendCommand(QString().sprintf("PW %s!",(const char *)ripc_password)); +} + + +void RDRipc::sendGpiStatus(int matrix) +{ + SendCommand(QString().sprintf("GI %d!",matrix)); +} + + +void RDRipc::sendGpoStatus(int matrix) +{ + SendCommand(QString().sprintf("GO %d!",matrix)); +} + + +void RDRipc::sendGpiMask(int matrix) +{ + SendCommand(QString().sprintf("GM %d!",matrix)); +} + + +void RDRipc::sendGpoMask(int matrix) +{ + SendCommand(QString().sprintf("GN %d!",matrix)); +} + + +void RDRipc::sendGpiCart(int matrix) +{ + SendCommand(QString().sprintf("GC %d!",matrix)); +} + + +void RDRipc::sendGpoCart(int matrix) +{ + SendCommand(QString().sprintf("GD %d!",matrix)); +} + + +void RDRipc::sendOnairFlag() +{ + SendCommand("TA!"); +} + + +void RDRipc::sendRml(RDMacro *macro) +{ + char buffer[RD_RML_MAX_LENGTH]; + char cmd[RD_RML_MAX_LENGTH+4]; + /* + int echo=0; + + if(macro->echoRequested()) { + echo=1; + } + */ + Q_UINT16 port=RD_RML_NOECHO_PORT; + + if(macro->echoRequested()) { + port=RD_RML_ECHO_PORT; + } + if(macro->port()>0) { + port=macro->port(); + } + macro->generateString(buffer,RD_RML_MAX_LENGTH-1); + QString rmlline(buffer); + QString sql=QString().sprintf("select NAME,VARVALUE from HOSTVARS \ + where STATION_NAME=\"%s\"", + (const char *)ripc_stationname); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + rmlline.replace(q->value(0).toString(),q->value(1).toString()); + } + delete q; + switch(macro->role()) { + case RDMacro::Cmd: + sprintf(cmd,"MS %s %d %s",(const char *)macro->address().toString(), + port,(const char *)rmlline); + break; + + case RDMacro::Reply: + sprintf(cmd,"ME %s %d %s",(const char *)macro->address().toString(), + port,(const char *)rmlline); + break; + + default: + break; + } + SendCommand(cmd); +} + + +void RDRipc::reloadHeartbeat() +{ + SendCommand("RH!"); +} + + +void RDRipc::errorData(int errorcode) +{ +} + + +void RDRipc::readyData() +{ + char buf[255]; + int c; + + while((c=ripc_socket->readBlock(buf,256))>0) { + buf[c]=0; + for(int i=0;i<c;i++) { + if(buf[i]==' ') { + if(argnum<RIPC_MAX_ARGS) { + args[argnum][argptr]=0; + argptr=0; + argnum++; + } + else { + if(debug) { + printf("Argument list truncated!\n"); + } + } + } + if(buf[i]=='!') { + args[argnum++][argptr]=0; + DispatchCommand(); + argnum=0; + argptr=0; + if(ripc_socket==NULL) { + return; + } + } + if((isgraph(buf[i]))&&(buf[i]!='!')) { + if(argptr<RIPC_MAX_LENGTH) { + args[argnum][argptr]=buf[i]; + argptr++; + } + else { + if(debug) { + printf("WARNING: argument truncated!\n"); + } + } + } + } + } +} + + +void RDRipc::SendCommand(QString cmd) +{ + // printf("RDRipc::SendCommand(%s)\n",(const char *)cmd); + ripc_socket->writeBlock((const char *)cmd,cmd.length()); +} + + +void RDRipc::DispatchCommand() +{ + RDMacro macro; + char str[RD_RML_MAX_LENGTH]; + + if(!strcmp(args[0],"PW")) { // Password Response + SendCommand(QString("RU!")); + } + + if(!strcmp(args[0],"RU")) { // User Identity + if(QString(args[1])!=ripc_user) { + ripc_user=QString(args[1]); + if(!ripc_connected) { + ripc_connected=true; + emit connected(true); + } + emit userChanged(); + } + } + + if(!strcmp(args[0],"MS")) { // Macro Sent + if(argnum<4) { + return; + } + strcpy(str,args[3]); + for(int i=4;i<argnum;i++) { + strcat(str," "); + strcat(str,args[i]); + } + strcat(str,"!"); + if(macro.parseString(str,strlen(str))) { + QHostAddress addr; + addr.setAddress(args[1]); + if(args[2][0]=='1') { + macro.setEchoRequested(true); + } + macro.setAddress(addr); + macro.setRole(RDMacro::Cmd); + emit rmlReceived(¯o); + } + return; + } + + if(!strcmp(args[0],"ME")) { // Macro Echoed + if(argnum<4) { + return; + } + strcpy(str,args[3]); + for(int i=4;i<argnum;i++) { + strcat(str," "); + strcat(str,args[i]); + } + strcat(str,"!"); + if(macro.parseString(str,strlen(str))) { + macro.setAddress(QHostAddress().setAddress(args[1])); + macro.setRole(RDMacro::Reply); + emit rmlReceived(¯o); + } + return; + } + + if(!strcmp(args[0],"GI")) { // GPI State Changed + if(argnum<4) { + return; + } + int matrix; + int line; + int mask; + sscanf(args[1],"%d",&matrix); + sscanf(args[2],"%d",&line); + sscanf(args[4],"%d",&mask); + if((mask>0)||ripc_ignore_mask) { + if(args[3][0]=='0') { + emit gpiStateChanged(matrix,line,false); + } + else { + emit gpiStateChanged(matrix,line,true); + } + } + } + + if(!strcmp(args[0],"GO")) { // GPO State Changed + if(argnum<4) { + return; + } + int matrix; + int line; + int mask; + sscanf(args[1],"%d",&matrix); + sscanf(args[2],"%d",&line); + sscanf(args[4],"%d",&mask); + if((mask>0)||ripc_ignore_mask) { + if(args[3][0]=='0') { + emit gpoStateChanged(matrix,line,false); + } + else { + emit gpoStateChanged(matrix,line,true); + } + } + } + + if(!strcmp(args[0],"GM")) { // GPI Mask Changed + if(argnum<4) { + return; + } + int matrix; + int line; + sscanf(args[1],"%d",&matrix); + sscanf(args[2],"%d",&line); + if(args[3][0]=='0') { + emit gpiMaskChanged(matrix,line,false); + } + else { + emit gpiMaskChanged(matrix,line,true); + } + } + + if(!strcmp(args[0],"GN")) { // GPO Mask Changed + if(argnum<4) { + return; + } + int matrix; + int line; + sscanf(args[1],"%d",&matrix); + sscanf(args[2],"%d",&line); + if(args[3][0]=='0') { + emit gpoMaskChanged(matrix,line,false); + } + else { + emit gpoMaskChanged(matrix,line,true); + } + } + + if(!strcmp(args[0],"GC")) { // GPI Cart Changed + if(argnum<5) { + return; + } + int matrix; + int line; + unsigned off_cartnum; + unsigned on_cartnum; + sscanf(args[1],"%d",&matrix); + sscanf(args[2],"%d",&line); + sscanf(args[3],"%d",&off_cartnum); + sscanf(args[4],"%d",&on_cartnum); + emit gpiCartChanged(matrix,line,off_cartnum,on_cartnum); + } + + if(!strcmp(args[0],"GD")) { // GPO Cart Changed + if(argnum<5) { + return; + } + int matrix; + int line; + unsigned off_cartnum; + unsigned on_cartnum; + sscanf(args[1],"%d",&matrix); + sscanf(args[2],"%d",&line); + sscanf(args[3],"%d",&off_cartnum); + sscanf(args[4],"%d",&on_cartnum); + emit gpoCartChanged(matrix,line,off_cartnum,on_cartnum); + } + + if(!strcmp(args[0],"TA")) { // On Air Flag Changed + if(argnum!=2) { + return; + } + emit onairFlagChanged(args[1][0]=='1'); + } + + if(!strcmp(args[0],"TA")) { // On Air Flag Changed + if(argnum!=2) { + return; + } + ripc_onair_flag=args[1][0]=='1'; + emit onairFlagChanged(ripc_onair_flag); + } +} diff --git a/lib/rdripc.h b/lib/rdripc.h new file mode 100644 index 00000000..29c9aaec --- /dev/null +++ b/lib/rdripc.h @@ -0,0 +1,95 @@ +// rdripc.h +// +// Connection to the Rivendell Interprocess Communication Daemon +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdripc.h,v 1.24.8.1 2012/11/16 18:10:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> +#include <qstring.h> +#include <qobject.h> +#include <qsocket.h> +#include <qlabel.h> +#include <qtimer.h> + +#include <rdmacro.h> + +#ifndef RDRIPC_H +#define RDRIPC_H + +#define RIPC_MAX_ARGS 100 +#define RIPC_MAX_LENGTH 256 +#define RIPC_START_DELAY 2000 + +class RDRipc : public QObject +{ + Q_OBJECT + public: + RDRipc(QString stationname,QObject *parent=0,const char *name=0); + ~RDRipc(); + QString user() const; + QString station() const; + bool onairFlag() const; + void setUser(QString user); + void setIgnoreMask(bool state); + void connectHost(QString hostname,Q_UINT16 hostport,QString password); + void sendGpiStatus(int matrix); + void sendGpoStatus(int matrix); + void sendGpiMask(int matrix); + void sendGpoMask(int matrix); + void sendGpiCart(int matrix); + void sendGpoCart(int matrix); + void sendOnairFlag(); + void sendRml(RDMacro *macro); + void reloadHeartbeat(); + + signals: + void connected(bool state); + void userChanged(); + void gpiStateChanged(int matrix,int line,bool state); + void gpoStateChanged(int matrix,int line,bool state); + void gpiMaskChanged(int matrix,int line,bool state); + void gpoMaskChanged(int matrix,int line,bool state); + void gpiCartChanged(int matrix,int line,int off_cartnum,int on_cartnum); + void gpoCartChanged(int matrix,int line,int off_cartnum,int on_cartnum); + void onairFlagChanged(bool state); + void rmlReceived(RDMacro *rml); + + private slots: + void connectedData(); + void errorData(int errorcode); + void readyData(); + + private: + void SendCommand(QString cmd); + void DispatchCommand(); + QSocket *ripc_socket; + QString ripc_user; + QString ripc_password; + QString ripc_stationname; + bool ripc_onair_flag; + bool ripc_ignore_mask; + bool debug; + char args[RIPC_MAX_ARGS][RIPC_MAX_LENGTH]; + int argnum; + int argptr; + bool ripc_connected; +}; + + +#endif diff --git a/lib/rdschedcodes_dialog.cpp b/lib/rdschedcodes_dialog.cpp new file mode 100644 index 00000000..1c4782c4 --- /dev/null +++ b/lib/rdschedcodes_dialog.cpp @@ -0,0 +1,209 @@ +// rdschedcode_dialog.cpp +// +// Scheduler code editor dialog +// +// (C) Copyright 2014 Fred Gleason <fredg@paravelsystems.com> +// +// Based on original code by Stefan Gabriel <stg@st-gabriel.de> +// +// $Id: rdschedcodes_dialog.cpp,v 1.1.2.1 2014/05/28 21:21:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qpainter.h> +#include <qmessagebox.h> + +#include <rddb.h> +#include "rdschedcodes_dialog.h" + +RDSchedCodesDialog::RDSchedCodesDialog(QWidget *parent) + : QDialog(parent,"",true) +{ + setCaption(tr("Select Scheduler Codes")); + + // + // Create Fonts + // + QFont font("Helvetica",11,QFont::Bold); + font.setPixelSize(11); + + QFont listfont("Helvetica",11); + font.setPixelSize(11); + + + // + // Services Selector + // + codes_sel=new RDListSelector(this); + codes_sel->setFont(listfont); + codes_sel->sourceSetLabel(tr("Available Codes")); + + remove_codes_sel=new RDListSelector(this); + remove_codes_sel->setFont(listfont); + remove_codes_sel->sourceSetLabel(tr("Available Codes")); + remove_codes_sel->destSetLabel(tr("REMOVE from Carts")); + + // + // Ok Button + // + edit_ok_button=new QPushButton(tr("&OK"),this); + edit_ok_button->setDefault(true); + edit_ok_button->setFont(font); + connect(edit_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + edit_cancel_button=new QPushButton(tr("&Cancel"),this); + edit_cancel_button->setFont(font); + connect(edit_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +RDSchedCodesDialog::~RDSchedCodesDialog() +{ +} + + +QSize RDSchedCodesDialog::sizeHint() const +{ + return QSize(400,292); +} + + +QSizePolicy RDSchedCodesDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int RDSchedCodesDialog::exec(QStringList *sched_codes,QStringList *remove_codes) +{ + QString sql; + RDSqlQuery *q; + + edit_sched_codes=sched_codes; + edit_remove_codes=remove_codes; + + // + // Fix the Window Size + // + if(edit_remove_codes==NULL) { + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + } + else { + setMinimumWidth(2*sizeHint().width()); + setMaximumWidth(2*sizeHint().width()); + } + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + codes_sel->clear(); + remove_codes_sel->clear(); + if(edit_remove_codes==NULL) { + codes_sel->destSetLabel(tr("Assigned Codes")); + codes_sel->show(); + remove_codes_sel->hide(); + } + else { + codes_sel->destSetLabel(tr("ASSIGN to Carts")); + codes_sel->hide(); + remove_codes_sel->show(); + } + + for(unsigned i=0;i<edit_sched_codes->size();i++) { + codes_sel->destInsertItem((*edit_sched_codes)[i]); + } + if(edit_remove_codes!=NULL) { + for(unsigned i=0;i<edit_remove_codes->size();i++) { + remove_codes_sel->destInsertItem((*remove_codes)[i]); + } + } + + sql=QString().sprintf("select CODE from SCHED_CODES"); + q=new RDSqlQuery(sql); + while(q->next()) { + if(codes_sel->destFindItem(q->value(0).toString())==0) { + codes_sel->sourceInsertItem(q->value(0).toString()); + } + if(edit_remove_codes!=NULL) { + if(remove_codes_sel->destFindItem(q->value(0).toString())==0) { + remove_codes_sel->sourceInsertItem(q->value(0).toString()); + } + } + } + delete q; + + return QDialog::exec(); +} + + +void RDSchedCodesDialog::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->moveTo(sizeHint().width(),10); + p->lineTo(sizeHint().width(),210); + p->end(); +} + + +void RDSchedCodesDialog::resizeEvent(QResizeEvent *e) +{ + codes_sel->setGeometry(10,10,380,200); + remove_codes_sel->setGeometry(sizeHint().width()+10,10,380,200); + edit_ok_button-> + setGeometry(size().width()-180,size().height()-60,80,50); + edit_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void RDSchedCodesDialog::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void RDSchedCodesDialog::okData() +{ + edit_sched_codes->clear(); + + // + // Add New Objects + // + for(unsigned i=0;i<codes_sel->destCount();i++) { + edit_sched_codes->push_back(codes_sel->destText(i)); + } + + if(edit_remove_codes!=NULL) { + edit_remove_codes->clear(); + for(unsigned i=0;i<remove_codes_sel->destCount();i++) { + edit_remove_codes->push_back(remove_codes_sel->destText(i)); + } + } + + done(0); +} + + +void RDSchedCodesDialog::cancelData() +{ + done(-1); +} + + + + diff --git a/lib/rdschedcodes_dialog.h b/lib/rdschedcodes_dialog.h new file mode 100644 index 00000000..c402ddc6 --- /dev/null +++ b/lib/rdschedcodes_dialog.h @@ -0,0 +1,66 @@ +// rdschedcode_dialog.h +// +// Scheduler code editor dialog +// +// (C) Copyright 2014 Fred Gleason <fredg@paravelsystems.com> +// +// Based on original code by Stefan Gabriel <stg@st-gabriel.de> +// +// $Id: rdschedcodes_dialog.h,v 1.1.2.1 2014/05/28 21:21:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDSCHEDCODE_DIALOG_H +#define RDSCHEDCODE_DIALOG_H + +#include <qdialog.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qstringlist.h> + +#include <rdlistselector.h> + +class RDSchedCodesDialog : public QDialog +{ + Q_OBJECT + public: + RDSchedCodesDialog(QWidget *parent=0); + ~RDSchedCodesDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(QStringList *sched_codes,QStringList *remove_codes); + + protected: + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e); + + private slots: + void okData(); + void cancelData(); + + private: + RDListSelector *codes_sel; + RDListSelector *remove_codes_sel; + QStringList *edit_sched_codes; + QStringList *edit_remove_codes; + QPushButton *edit_ok_button; + QPushButton *edit_cancel_button; +}; + + +#endif // RDSCHEDCODE_DIALOG_H diff --git a/lib/rdsegmeter.cpp b/lib/rdsegmeter.cpp new file mode 100644 index 00000000..345cc3a2 --- /dev/null +++ b/lib/rdsegmeter.cpp @@ -0,0 +1,506 @@ +// rdsegmeter.cpp +// +// An audio meter display widget. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsegmeter.cpp,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <qwidget.h> +#include <qstring.h> +#include <qcolor.h> +#include <qpainter.h> +#include <qpushbutton.h> +#include <qsize.h> +#include <stdio.h> +#include <qslider.h> +#include <qbuttongroup.h> +#include <qsizepolicy.h> +#include <qmessagebox.h> + +#include <rdsegmeter.h> + +RDSegMeter::RDSegMeter(RDSegMeter::Orientation o,QWidget *parent,const char *name) + : QWidget(parent,name) +{ + orient=o; + setBackgroundColor(black); + dark_low_color=QColor(DEFAULT_DARK_LOW_COLOR); + dark_high_color=QColor(DEFAULT_DARK_HIGH_COLOR); + dark_clip_color=QColor(DEFAULT_DARK_CLIP_COLOR); + low_color=QColor(DEFAULT_LOW_COLOR); + high_color=QColor(DEFAULT_HIGH_COLOR); + clip_color=QColor(DEFAULT_CLIP_COLOR); + high_threshold=-14; + clip_threshold=0; + seg_size=2; + seg_gap=1; + range_min=-3000; + range_max=0; + solid_bar=-10000; + floating_bar=-10000; + seg_mode=RDSegMeter::Independent; + + peak_timer=new QTimer(this,"peak_timer"); + connect(peak_timer,SIGNAL(timeout()),this,SLOT(peakData())); +} + + +QSize RDSegMeter::sizeHint() const +{ + return QSize(0,0); +} + + +QSizePolicy RDSegMeter::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDSegMeter::setRange(int min,int max) +{ + range_min=min; + range_max=max; + repaint(false); +} + + +void RDSegMeter::setDarkLowColor(QColor color) +{ + if(dark_low_color!=color) { + dark_low_color=color; + repaint(false); + } +} + + +void RDSegMeter::setDarkHighColor(QColor color) +{ + if(dark_high_color!=color) { + dark_high_color=color; + repaint(false); + } +} + + +void RDSegMeter::setDarkClipColor(QColor color) +{ + if(dark_clip_color!=color) { + dark_clip_color=color; + repaint(false); + } +} + + +void RDSegMeter::setLowColor(QColor color) +{ + if(low_color!=color) { + low_color=color; + repaint(false); + } +} + + +void RDSegMeter::setHighColor(QColor color) +{ + if(high_color!=color) { + high_color=color; + repaint(false); + } +} + + +void RDSegMeter::setClipColor(QColor color) +{ + if(clip_color!=color) { + clip_color=color; + repaint(false); + } +} + + +void RDSegMeter::setHighThreshold(int level) +{ + if(high_threshold!=level) { + high_threshold=level; + repaint(false); + } +} + + +void RDSegMeter::setClipThreshold(int level) +{ + if(clip_threshold!=level) { + clip_threshold=level; + repaint(false); + } +} + + +RDSegMeter::Mode RDSegMeter::mode() const +{ + return seg_mode; +} + + +void RDSegMeter::setMode(RDSegMeter::Mode mode) +{ + seg_mode=mode; + switch(seg_mode) { + case RDSegMeter::Independent: + if(peak_timer->isActive()) { + peak_timer->stop(); + } + break; + case RDSegMeter::Peak: + if(!peak_timer->isActive()) { + peak_timer->start(PEAK_HOLD_TIME); + } + break; + } +} + + +void RDSegMeter::setSolidBar(int level) +{ + if((seg_mode==RDSegMeter::Independent)&&(solid_bar!=level)) { + solid_bar=level; + repaint(false); + } +} + + +void RDSegMeter::setFloatingBar(int level) +{ + if((seg_mode==RDSegMeter::Independent)&&(solid_bar!=level)) { + floating_bar=level; + repaint(false); + } +} + + +void RDSegMeter::setPeakBar(int level) +{ + if((seg_mode==RDSegMeter::Peak)&&(solid_bar!=level)) { + solid_bar=level; + if(solid_bar>floating_bar) { + floating_bar=solid_bar; + } + + if(solid_bar<range_min) { + floating_bar=solid_bar; + } + repaint(false); + } +} + + +void RDSegMeter::setSegmentSize(int size) +{ + if(seg_size!=size) { + seg_size=size; + repaint(false); + } +} + + +void RDSegMeter::setSegmentGap(int gap) +{ + if(seg_gap!=gap) { + seg_gap=gap; + repaint(false); + } +} + + +void RDSegMeter::paintEvent(QPaintEvent *paintEvent) +{ + int op_pt; + int low_region,high_region,clip_region,float_region; + int dark_low_region=0; + int dark_high_region=0; + int dark_clip_region=0; + QColor float_color; + + // + // Setup + // + QPixmap pix(this->size()); + pix.fill(this,0,0); + + int seg_total=seg_size+seg_gap; + QPainter *p=new QPainter(&pix); + low_region=0; + high_region=0; + clip_region=0; + p->setBrush(low_color); + p->setPen(low_color); + + // + // Set Orientation + // + switch(orient) { + case RDSegMeter::Left: + case RDSegMeter::Up: + p->translate(width(),height()); + p->rotate(180); + break; + + default: + break; + } + + // + // The low range + // + if(solid_bar>high_threshold) { + op_pt=high_threshold; + } + else { + op_pt=solid_bar; + } + switch(orient) { + case RDSegMeter::Left: + case RDSegMeter::Right: + low_region=(int)((double)(op_pt-range_min)/ + (double)(range_max-range_min)*width()/seg_total); + if(op_pt>range_min) { + for(int i=0;i<low_region;i++) { + p->fillRect(i*seg_total,0,seg_size,height(),low_color); + } + } + break; + case RDSegMeter::Down: + case RDSegMeter::Up: + low_region=(int)((double)(op_pt-range_min)/ + (double)(range_max-range_min)*height()/seg_total); + if(op_pt>range_min) { + for(int i=0;i<low_region;i++) { + p->fillRect(0,i*seg_total,width(),seg_size,low_color); + } + } + break; + } + + // + // The high range + // + if(solid_bar>clip_threshold) { + op_pt=clip_threshold; + } + else { + op_pt=solid_bar; + } + switch(orient) { + case RDSegMeter::Left: + case RDSegMeter::Right: + high_region=(int)((double)(op_pt-high_threshold)/ + (double)(range_max-range_min)*width()/seg_total); + if(op_pt>high_threshold) { + for(int i=low_region;i<low_region+high_region;i++) { + p->fillRect(i*seg_total,0,seg_size,height(),high_color); + } + } + break; + case RDSegMeter::Down: + case RDSegMeter::Up: + high_region=(int)((double)(op_pt-high_threshold)/ + (double)(range_max-range_min)*height()/seg_total); + if(op_pt>high_threshold) { + for(int i=low_region;i<low_region+high_region;i++) { + p->fillRect(0,i*seg_total,width(),seg_size,high_color); + } + } + break; + } + + // + // The clip range + // + if(solid_bar>range_max) { + op_pt=range_max; + } + else { + op_pt=solid_bar; + } + switch(orient) { + case RDSegMeter::Left: + case RDSegMeter::Right: + clip_region=(int)((double)(op_pt-clip_threshold)/ + (double)(range_max-range_min)*width()/seg_total); + if(op_pt>clip_threshold) { + for(int i=low_region+high_region; + i<low_region+high_region+clip_region;i++) { + p->fillRect(i*seg_total,0,seg_size,height(),clip_color); + } + } + break; + case RDSegMeter::Down: + case RDSegMeter::Up: + clip_region=(int)((double)(op_pt-range_min)/ + (double)(range_max-range_min)*height()/seg_total); + if(op_pt>clip_threshold) { + for(int i=low_region+high_region; + i<low_region+high_region+clip_region;i++) { + p->fillRect(0,i*seg_total,width(),seg_size,clip_color); + } + } + break; + } + + // + // The dark low range + // + switch(orient) { + case RDSegMeter::Left: + case RDSegMeter::Right: + dark_low_region=(int)((double)(high_threshold-range_min)/ + (double)(range_max-range_min)*width()/seg_total); + if(op_pt<high_threshold) { + for(int i=low_region;i<dark_low_region;i++) { + p->fillRect(i*seg_total,0,seg_size,height(),dark_low_color); + } + } + break; + case RDSegMeter::Down: + case RDSegMeter::Up: + dark_low_region=(int)((double)(high_threshold-range_min)/ + (double)(range_max-range_min)*height()/seg_total); + if(op_pt<high_threshold) { + for(int i=low_region;i<dark_low_region;i++) { + p->fillRect(0,i*seg_total,width(),seg_size,dark_low_color); + } + } + break; + } + + // + // The dark high range + // + if(solid_bar>=high_threshold) { + op_pt=low_region+high_region; + } + else { + op_pt=dark_low_region; + } + switch(orient) { + case RDSegMeter::Left: + case RDSegMeter::Right: + dark_high_region=(int)((double)(clip_threshold-range_min)/ + (double)(range_max-range_min)*width()/seg_total); + if(solid_bar<clip_threshold) { + for(int i=op_pt; + i<dark_high_region;i++) { + p->fillRect(i*seg_total,0,seg_size,height(),dark_high_color); + } + } + break; + case RDSegMeter::Down: + case RDSegMeter::Up: + dark_high_region=(int)((double)(clip_threshold-range_min)/ + (double)(range_max-range_min)*height()/seg_total); + if(solid_bar<clip_threshold) { + for(int i=op_pt;i<dark_high_region;i++) { + p->fillRect(0,i*seg_total,width(),seg_size,dark_high_color); + } + } + break; + } + + // + // The dark clip range + // + if(solid_bar>clip_threshold) { + op_pt=low_region+high_region+clip_region; + } + else { + op_pt=dark_high_region; + } + switch(orient) { + case RDSegMeter::Left: + case RDSegMeter::Right: + dark_clip_region=(int)((double)(range_max-range_min)/ + (double)(range_max-range_min)*width()/seg_total); + if(solid_bar<range_max) { + for(int i=op_pt;i<dark_clip_region;i++) { + p->fillRect(i*seg_total,0,seg_size,height(),dark_clip_color); + } + } + break; + case RDSegMeter::Down: + case RDSegMeter::Up: + dark_clip_region=(int)((double)(range_max-range_min)/ + (double)(range_max-range_min)*height()/seg_total); + if(solid_bar<range_max) { + for(int i=op_pt; + i<dark_clip_region;i++) { + p->fillRect(0,i*seg_total,width(),seg_size,dark_clip_color); + } + } + break; + } + + // + // The floating segment + // + if(floating_bar>solid_bar) { + if(floating_bar<=high_threshold) { + float_color=low_color; + } + if((floating_bar>high_threshold)&&(floating_bar<=clip_threshold)) { + float_color=high_color; + } + if(floating_bar>clip_threshold) { + float_color=clip_color; + } + switch(orient) { + case RDSegMeter::Left: + case RDSegMeter::Right: + float_region=(int)((double)(floating_bar-range_min)/ + (double)(range_max-range_min)*width()); + float_region=seg_total*(float_region/seg_total); + p->fillRect(float_region,0,seg_size,height(),float_color); + break; + + case RDSegMeter::Down: + case RDSegMeter::Up: + float_region=(int)((double)(floating_bar-range_min)/ + (double)(range_max-range_min)*height()); + float_region=seg_total*(float_region/seg_total); + p->fillRect(0,float_region,width(),seg_size,float_color); + break; + } + } + + p->end(); + p->begin(this); + p->drawPixmap(0,0,pix); + p->end(); + delete p; +} + + +void RDSegMeter::peakData() +{ + floating_bar=solid_bar; + repaint(false); +} + + + diff --git a/lib/rdsegmeter.h b/lib/rdsegmeter.h new file mode 100644 index 00000000..dd8073ad --- /dev/null +++ b/lib/rdsegmeter.h @@ -0,0 +1,101 @@ +// rdsegmeter.h +// +// An audio meter display widget. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsegmeter.h,v 1.3 2010/07/29 19:32:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDSEGMETER_H +#define RDSEGMETER_H + +#include <qwidget.h> +#include <qcolor.h> +#include <qpainter.h> +#include <qsize.h> +#include <qsizepolicy.h> +#include <qtimer.h> + +/* + * Default Colors + */ +#define DEFAULT_LOW_COLOR green +#define DEFAULT_DARK_LOW_COLOR 0,80,0 +#define DEFAULT_HIGH_COLOR yellow +#define DEFAULT_DARK_HIGH_COLOR 75,75,0 +#define DEFAULT_CLIP_COLOR red +#define DEFAULT_DARK_CLIP_COLOR 85,0,0 + +/* + * Global Settings + */ +#define PEAK_HOLD_TIME 750 + + +class RDSegMeter : public QWidget +{ + Q_OBJECT + public: + enum Mode {Independent=0,Peak=1}; + enum Orientation {Left=0,Right=1,Up=2,Down=3}; + RDSegMeter(RDSegMeter::Orientation o,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void setRange(int min,int max); + void setDarkLowColor(QColor color); + void setDarkHighColor(QColor color); + void setDarkClipColor(QColor color); + void setLowColor(QColor color); + void setHighColor(QColor color); + void setClipColor(QColor color); + void setHighThreshold(int level); + void setClipThreshold(int level); + void setSegmentSize(int size); + void setSegmentGap(int gap); + RDSegMeter::Mode mode() const; + void setMode(RDSegMeter::Mode mode); + + public slots: + void setSolidBar(int level); + void setFloatingBar(int level); + void setPeakBar(int level); + + protected: + void paintEvent(QPaintEvent *); + + private slots: + void peakData(); + + private: + RDSegMeter::Orientation orient; + RDSegMeter::Mode seg_mode; + QTimer *peak_timer; + int range_min,range_max; + QColor dark_low_color; + QColor dark_high_color; + QColor dark_clip_color; + QColor low_color; + QColor high_color; + QColor clip_color; + int high_threshold,clip_threshold; + int solid_bar,floating_bar; + int seg_size,seg_gap; +}; + + +#endif // RDSEGMETER_H diff --git a/lib/rdsettings.cpp b/lib/rdsettings.cpp new file mode 100644 index 00000000..30566aa9 --- /dev/null +++ b/lib/rdsettings.cpp @@ -0,0 +1,364 @@ +// rdsettings.cpp +// +// RDLibrary Settings +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsettings.cpp,v 1.11.8.1 2012/12/13 22:33:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdsettings.h> +#include <rddb.h> +#include <rdescape_string.h> + +RDSettings::RDSettings() +{ + clear(); +} + + +RDSettings::Format RDSettings::format() const +{ + return set_format; +} + + +void RDSettings::setFormat(Format format) +{ + set_format=format; +} + + +QString RDSettings::formatName() const +{ + return set_format_name; +} + + +void RDSettings::setFormatName(const QString &str) +{ + set_format_name=str; +} + + +unsigned RDSettings::channels() const +{ + return set_channels; +} + + +void RDSettings::setChannels(unsigned channels) +{ + set_channels=channels; +} + + +unsigned RDSettings::sampleRate() const +{ + return set_sample_rate; +} + + +void RDSettings::setSampleRate(unsigned rate) +{ + set_sample_rate=rate; +} + + +unsigned RDSettings::layer() const +{ + return set_layer; +} + + +void RDSettings::setLayer(unsigned layer) +{ + set_layer=layer; +} + + +unsigned RDSettings::bitRate() const +{ + return set_bit_rate; +} + + +void RDSettings::setBitRate(unsigned rate) +{ + set_bit_rate=rate; +} + + +unsigned RDSettings::quality() const +{ + return set_quality; +} + + +void RDSettings::setQuality(unsigned qual) +{ + set_quality=qual; +} + + +int RDSettings::normalizationLevel() const +{ + return set_normalization_level; +} + + +void RDSettings::setNormalizationLevel(int level) +{ + set_normalization_level=level; +} + + +int RDSettings::autotrimLevel() const +{ + return set_autotrim_level; +} + + +void RDSettings::setAutotrimLevel(int level) +{ + set_autotrim_level=level; +} + + +QString RDSettings::description() +{ + QString sql; + RDSqlQuery *q; + QString desc; + QString sr=QString().sprintf("%d S/sec",set_sample_rate); + switch(set_format) { + case RDSettings::Pcm16: + desc="PCM16, "; + break; + + case RDSettings::MpegL1: + desc="MPEG L1, "; + if(set_bit_rate==0) { + desc+=QString().sprintf("Qual %d, ",set_quality); + } + else { + desc+=QString().sprintf("%d kbit/sec, ",set_bit_rate/1000); + } + break; + + case RDSettings::MpegL2: + desc="MPEG L2, "; + if(set_bit_rate==0) { + desc+=QString().sprintf("Qual %d, ",set_quality); + } + else { + desc+=QString().sprintf("%d kbit/sec, ",set_bit_rate/1000); + } + break; + + case RDSettings::MpegL3: + desc="MPEG L3, "; + if(set_bit_rate==0) { + desc+=QString().sprintf("Qual %d, ",set_quality); + } + else { + desc+=QString().sprintf("%d kbit/sec, ",set_bit_rate/1000); + } + break; + + case RDSettings::Flac: + desc="FLAC, "; + break; + + case RDSettings::OggVorbis: + desc=QString().sprintf("OggVorbis, Qual %d, ",set_quality); + break; + + default: // Custom format + if(set_format_name.isEmpty()) { + sql=QString().sprintf("select NAME from ENCODERS where ID=%d", + set_format); + q=new RDSqlQuery(sql); + if(q->first()) { + set_format_name=q->value(0).toString(); + } + else { + set_format_name="Unknown"; + } + delete q; + } + desc=set_format_name+" "; + if(set_bit_rate>0) { + desc+=" "+QString().sprintf("%d kbit/sec, ",set_bit_rate/1000); + } + } + if(set_sample_rate>0) { + desc+=QString().sprintf("%d samp/sec, ",set_sample_rate); + } + switch(set_channels) { + case 1: + desc+="Mono"; + break; + + case 2: + desc+="Stereo"; + break; + + default: + desc+=QString().sprintf("%d chans",set_channels); + break; + } + return desc; +} + + +QString RDSettings::customCommandLine() const +{ + return set_custom_command_line; +} + + +void RDSettings::setCustomCommandLine(const QString &str) +{ + set_custom_command_line=str; +} + + +QString RDSettings::resolvedCustomCommandLine(const QString &destfile) +{ + if(set_custom_command_line.isEmpty()) { + QString sql; + RDSqlQuery *q; + sql=QString().sprintf("select COMMAND_LINE from ENCODERS where ID=%d", + set_format); + q=new RDSqlQuery(sql); + if(q->first()) { + set_custom_command_line=q->value(0).toString(); + } + delete q; + } + QString ret=set_custom_command_line; + + ret.replace("%f",destfile); + ret.replace("%c",QString().sprintf("%u",set_channels)); + ret.replace("%r",QString().sprintf("%u",set_sample_rate)); + ret.replace("%b",QString().sprintf("%u",set_bit_rate)); + + return ret; +} + + +QString RDSettings::pathName(const QString &stationname,QString pathname, + RDSettings::Format fmt) +{ + QString ext; + int index=pathname.findRev("."); + if(index<0) { + return pathname+"."+defaultExtension(stationname,fmt); + } + ext=pathname.right(pathname.length()-index); + if(ext.lower()==defaultExtension(stationname,fmt)) { + return pathname; + } + return pathname.replace(index,ext.length(),"."+ + defaultExtension(stationname,fmt)); +} + + +QString RDSettings::defaultExtension(const QString &stationname, + RDSettings::Format fmt) +{ + switch(fmt) { + case RDSettings::Pcm16: + case RDSettings::MpegL2Wav: + return QString("wav"); + + case RDSettings::MpegL1: + return QString("mp1"); + + case RDSettings::MpegL2: + return QString("mp2"); + + case RDSettings::MpegL3: + return QString("mp3"); + + case RDSettings::Flac: + return QString("flac"); + + case RDSettings::OggVorbis: + return QString("ogg"); + } + + // + // Custom Format + // + QString sql; + RDSqlQuery *q; + QString ret; + + sql=QString().sprintf("select DEFAULT_EXTENSION from ENCODERS \ + where (ID=%d)&&(STATION_NAME=\"%s\")", + fmt,(const char *)RDEscapeString(stationname)); + q=new RDSqlQuery(sql); + if(q->first()) { + ret=q->value(0).toString(); + } + delete q; + + return ret; +} + + +unsigned RDSettings::bytesPerSec(const QString &stationname, + RDSettings::Format fmt,unsigned quality) +{ + // + // Guesstimate the bit rate for a VBR encoding. This is *not* exact, + // but is intended merely to provide a half-way sane value for use with + // progress bars and such. + // + switch(fmt) { + case RDSettings::MpegL3: + return 16000; + break; + + case RDSettings::OggVorbis: + return 4173*quality+7977; + break; + + case RDSettings::Flac: + return 72500; + break; + + default: + break; + } + return 0; +} + + +void RDSettings::clear() +{ + set_format=RDSettings::Pcm16; + set_format_name=""; + set_channels=2; + set_sample_rate=48000; + set_bit_rate=0; + set_quality=0; + set_normalization_level=0; + set_autotrim_level=0; + set_custom_command_line=""; +} diff --git a/lib/rdsettings.h b/lib/rdsettings.h new file mode 100644 index 00000000..a6ec603e --- /dev/null +++ b/lib/rdsettings.h @@ -0,0 +1,79 @@ +// rdsettings.h +// +// Rivendell Audio Settings +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsettings.h,v 1.11 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDSETTINGS_H +#define RDSETTINGS_H + +#include <qstring.h> + +class RDSettings +{ + public: + enum Format {Pcm16=0,MpegL1=1,MpegL2=2,MpegL3=3,Flac=4,OggVorbis=5, + MpegL2Wav=6}; + RDSettings(); + RDSettings::Format format() const; + void setFormat(Format format); + QString formatName() const; + void setFormatName(const QString &str); + unsigned channels() const; + void setChannels(unsigned channels); + unsigned sampleRate() const; + void setSampleRate(unsigned rate); + unsigned layer() const; + void setLayer(unsigned layer); + unsigned bitRate() const; + void setBitRate(unsigned rate); + unsigned quality() const; + void setQuality(unsigned qual); + int normalizationLevel() const; + void setNormalizationLevel(int level); + int autotrimLevel() const; + void setAutotrimLevel(int level); + QString description(); + QString customCommandLine() const; + void setCustomCommandLine(const QString &str); + QString resolvedCustomCommandLine(const QString &destfile); + static QString pathName(const QString &stationname,QString pathname, + RDSettings::Format fmt); + static QString defaultExtension(const QString &stationname, + RDSettings::Format fmt); + static unsigned bytesPerSec(const QString &stationname, + RDSettings::Format fmt,unsigned quality); + void clear(); + + private: + Format set_format; + QString set_format_name; + unsigned set_channels; + unsigned set_sample_rate; + unsigned set_layer; + unsigned set_bit_rate; + unsigned set_quality; + int set_normalization_level; + int set_autotrim_level; + QString set_custom_command_line; +}; + + +#endif + diff --git a/lib/rdsimpleplayer.cpp b/lib/rdsimpleplayer.cpp new file mode 100644 index 00000000..900491a6 --- /dev/null +++ b/lib/rdsimpleplayer.cpp @@ -0,0 +1,184 @@ +// rdsimpleplayer.cpp +// +// A naively simple player for Rivendell Carts. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsimpleplayer.cpp,v 1.14 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rddb.h> +#include <rdsimpleplayer.h> + + +RDSimplePlayer::RDSimplePlayer(RDCae *cae,RDRipc *ripc,int card,int port, + unsigned start_cart,unsigned end_cart, + QWidget *parent,const char *name) + : QWidget(parent,name) +{ + play_cae=cae; + play_ripc=ripc; + play_card=card; + play_port=port; + play_start_cart=start_cart; + play_end_cart=end_cart; + play_stream=-1; + play_cart=0; + play_is_playing=false; + + // + // RDCae Connections + // + connect(play_cae,SIGNAL(playing(int)),this,SLOT(playingData(int))); + connect(play_cae,SIGNAL(playStopped(int)),this,SLOT(playStoppedData(int))); + + // + // Event Player + // + play_event_player=new RDEventPlayer(play_ripc,this,"play_event_player"); + + // + // Start Button + // + play_start_button= + new RDTransportButton(RDTransportButton::Play,parent,"play_start_button"); + play_start_button->setEnabled((play_card>=0)&&(play_port>=0)); + connect(play_start_button,SIGNAL(clicked()),this,SLOT(play())); + + // + // Stop Button + // + play_stop_button= + new RDTransportButton(RDTransportButton::Stop,parent,"play_stop_button"); + play_stop_button->on(); + play_stop_button->setEnabled((play_card>=0)&&(play_port>=0)); + connect(play_stop_button,SIGNAL(clicked()),this,SLOT(stop())); + + hide(); +} + + +RDSimplePlayer::~RDSimplePlayer() +{ + stop(); +} + + +void RDSimplePlayer::setCart(unsigned cart) +{ + play_cart=cart; +} + + +RDTransportButton *RDSimplePlayer::playButton() const +{ + return play_start_button; +} + + +RDTransportButton *RDSimplePlayer::stopButton() const +{ + return play_stop_button; +} + + +void RDSimplePlayer::play() +{ + play(0); +} + + +void RDSimplePlayer::play(int start_pos) +{ + int handle=0; + int play_cut_gain=0; + QString sql; + RDSqlQuery *q; + + if(play_cart==0) { + return; + } + if(play_is_playing) { + stop(); + } + sql=QString().sprintf("select CUT_NAME,START_POINT,END_POINT,PLAY_GAIN\ + from CUTS where (CART_NUMBER=%u)&&(LENGTH>0)", + play_cart); + q=new RDSqlQuery(sql); + if(q->first()) { + play_cae-> + loadPlay(play_card,q->value(0).toString(),&play_stream,&handle); + play_cut_gain=q->value(3).toInt(); + if(play_stream<0) { + delete q; + return; + } + play_handles.push(handle); + for(int i=0;i<RD_MAX_PORTS;i++) { + play_cae->setOutputVolume(play_card,play_stream,i,RD_MUTE_DEPTH); + } + play_cae->setOutputVolume(play_card,play_stream,play_port,0+play_cut_gain); + play_cae->positionPlay(play_handles.back(),q->value(1).toUInt()+start_pos); + play_cae->play(play_handles.back(), + q->value(2).toUInt()-(q->value(1).toUInt()+start_pos), + RD_TIMESCALE_DIVISOR,false); + play_cae->setPlayPortActive(play_card,play_port,play_stream); + } + delete q; +} + + +void RDSimplePlayer::stop() +{ + if(!play_is_playing) { + return; + } + play_cae->stopPlay(play_handles.back()); +} + + +void RDSimplePlayer::playingData(int handle) +{ + if(play_handles.empty()) { + return; + } + if(handle!=play_handles.back()) { + return; + } + play_event_player->exec(play_start_cart); + play_start_button->on(); + play_stop_button->off(); + play_is_playing=true; + emit played(); +} + + +void RDSimplePlayer::playStoppedData(int handle) +{ + if(play_handles.empty()) { + return; + } + if(handle!=play_handles.front()) { + return; + } + play_cae->unloadPlay(play_handles.front()); + play_event_player->exec(play_end_cart); + play_start_button->off(); + play_stop_button->on(); + play_handles.pop(); + play_is_playing=false; + emit stopped(); +} diff --git a/lib/rdsimpleplayer.h b/lib/rdsimpleplayer.h new file mode 100644 index 00000000..916003e7 --- /dev/null +++ b/lib/rdsimpleplayer.h @@ -0,0 +1,78 @@ +// rdsimpleplayer.h +// +// A naively simple player for Rivendell Carts. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsimpleplayer.h,v 1.7 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <queue> + +#include <qwidget.h> + +#include <rdtransportbutton.h> +#include <rdcae.h> +#include <rdripc.h> +#include <rdevent_player.h> + +#ifndef RDSIMPLEPLAYER_H +#define RDSIMPLEPLAYER_H + + +class RDSimplePlayer : public QWidget +{ + Q_OBJECT + public: + RDSimplePlayer(RDCae *cae,RDRipc *ripc,int card,int port, + unsigned start_cart,unsigned end_cart, + QWidget *parent=0,const char *name=0); + ~RDSimplePlayer(); + void setCart(unsigned cart); + RDTransportButton *playButton() const; + RDTransportButton *stopButton() const; + + public slots: + void play(); + void play(int start_pos); + void stop(); + + signals: + void played(); + void stopped(); + + private slots: + void playingData(int handle); + void playStoppedData(int handle); + + private: + RDCae *play_cae; + RDRipc *play_ripc; + int play_card; + int play_stream; + int play_port; + std::queue<int> play_handles; + unsigned play_cart; + unsigned play_start_cart; + unsigned play_end_cart; + bool play_is_playing; + RDEventPlayer *play_event_player; + RDTransportButton *play_start_button; + RDTransportButton *play_stop_button; +}; + + +#endif // RDSIMPLEPLAYER_H diff --git a/lib/rdslider.cpp b/lib/rdslider.cpp new file mode 100644 index 00000000..f6700684 --- /dev/null +++ b/lib/rdslider.cpp @@ -0,0 +1,853 @@ +// rdslider.cpp +// +// An audio- and touchscreen-friendly slider widget. +// +// (C) Copyright 2009 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdslider.cpp,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <stdlib.h> +#include <stdio.h> +#include <qwidget.h> +#include <qslider.h> +#include <qpainter.h> +#include <qcolor.h> +#include <qpalette.h> +#include <qsize.h> +#include <qrect.h> +#include <rdslider.h> +#include <qpixmap.h> + + +RDSlider::RDSlider(QWidget *parent=0,const char *name=0) + : QWidget(parent,name),QRangeControl() +{ + init(RDSlider::Right); + update(); +} + + +RDSlider::RDSlider(RDSlider::Orientation orient,QWidget *parent,const char *name) + : QWidget(parent,name),QRangeControl() +{ + init(orient); + setOrientation(orient); +} + + +RDSlider::RDSlider(int minValue,int maxValue,int pageStep,int value, + RDSlider::Orientation orient,QWidget *parent,const char *name) + : QWidget(parent,name),QRangeControl() +{ + init(orient); + setOrientation(orient); + setRange(minValue,maxValue); + setPageStep(pageStep); + setValue(value); +} + + +RDSlider::Orientation RDSlider::orientation() const +{ + return rdslider_orient; +} + + +void RDSlider::setOrientation(RDSlider::Orientation orient) +{ + rdslider_orient=orient; + update(); +} + + +void RDSlider::setTracking(bool enable) +{ + tracking_enabled=enable; +} + + +bool RDSlider::tracking() const +{ + return tracking_enabled; +} + + +void RDSlider::setTickInterval(int i) +{ + tick_interval=i; + update(); +} + + +void RDSlider::setTickmarks(QSlider::TickSetting s) +{ + tick_setting=s; + update(); +} + + +void RDSlider::setMinValue(int min_value) +{ + setRange(min_value,maxValue()); +} + + +void RDSlider::setMaxValue(int max_value) +{ + setRange(minValue(),max_value); +} + + +void RDSlider::setRange(int min_value,int max_value) +{ + QRangeControl::setRange(min_value,max_value); + calcKnob(); + update(prev_knob); + update(curr_knob); +} + + +void RDSlider::setLineStep(int step) +{ + line_step=step; +} + + +void RDSlider::setPageStep(int step) +{ + page_step=step; +} + + +void RDSlider::setKnobColor(QColorGroup group) +{ + knob_color=group; + calcKnob(); + update(); +} + + +void RDSlider::setKnobColor(QColor color) +{ + knob_color.setColor(QColorGroup::Background,color); + calcKnob(); + update(); +} + + +void RDSlider::setKnobSize(QSize size) +{ + if(size!=curr_knob.size()) { + knob_size=size; + calcKnob(); + } +} + + +void RDSlider::setKnobSize(int w,int h) +{ + setKnobSize(QSize(w,h)); +} + + +void RDSlider::setGeometry(int x,int y,int w,int h) +{ + calcKnob(x,y,w,h); + QWidget::setGeometry(x,y,w,h); +} + + +void RDSlider::setGeometry(QRect &rect) +{ + setGeometry(rect.left(),rect.top(),rect.width(),rect.height()); +} + + +void RDSlider::setValue(int setting) +{ + if(!rdslider_moving) { + if(setting!=value()) { + QRangeControl::setValue(setting); + calcKnob(); + update(prev_knob); + update(curr_knob); + } + } +} + + +void RDSlider::addStep() +{ + setValue(value()+page_step); +} + + +void RDSlider::subtractStep() +{ + setValue(value()-page_step); +} + + +void RDSlider::paintEvent(QPaintEvent *paintEvent) +{ + QPainter *p=new QPainter(this); + int tick_x,tick_y; + + if((rdslider_orient==RDSlider::Up)||(rdslider_orient==RDSlider::Down)) { + // + // The groove + // + p->setPen(QColor(colorGroup().dark())); + p->moveTo(width()/2,knob_size.height()/2); + p->lineTo(width()/2,height()-knob_size.height()/2); + p->setPen(QColor(colorGroup().shadow())); + p->moveTo(width()/2-1,height()-knob_size.height()/2+1); + p->lineTo(width()/2-1,knob_size.height()/2-1); + p->lineTo(width()/2+1,knob_size.height()/2-1); + + // + // The ticks + // + switch(rdslider_orient) { + case RDSlider::Up: + if((tick_setting==QSlider::Left)||(tick_setting==QSlider::Both)) { + p->setPen(colorGroup().shadow()); + for(int i=minValue();i<=maxValue();i+=tick_interval) { + tick_y=(geometry().height()-curr_knob.height())- + ((geometry().height()-curr_knob.height())*(i-minValue()))/ + (maxValue()-minValue())+curr_knob.height()/2; + p->moveTo(0,tick_y); + p->lineTo(width()/2-2,tick_y); + } + } + if((tick_setting==QSlider::Right)||(tick_setting==QSlider::Both)) { + p->setPen(colorGroup().shadow()); + for(int i=minValue();i<=maxValue();i+=tick_interval) { + tick_y=(geometry().height()-curr_knob.height())- + ((geometry().height()-curr_knob.height())*(i-minValue()))/ + (maxValue()-minValue())+curr_knob.height()/2; + p->moveTo(width()/2+2,tick_y); + p->lineTo(width(),tick_y); + } + } + break; + case RDSlider::Down: + if((tick_setting==QSlider::Left)||(tick_setting==QSlider::Both)) { + p->setPen(colorGroup().shadow()); + for(int i=minValue();i<=maxValue();i+=tick_interval) { + tick_y=(geometry().height()-curr_knob.height()/2)- + abs((geometry().height()-curr_knob.height())*i)/ + (maxValue()-minValue()); + p->moveTo(0,tick_y); + p->lineTo(width()/2-2,tick_y); + } + } + if((tick_setting==QSlider::Right)||(tick_setting==QSlider::Both)) { + p->setPen(colorGroup().shadow()); + for(int i=minValue();i<=maxValue();i+=tick_interval) { + tick_y=(geometry().height()-curr_knob.height()/2)- + abs((geometry().height()-curr_knob.height())*i)/ + (maxValue()-minValue()); + p->moveTo(width()/2+2,tick_y); + p->lineTo(width(),tick_y); + } + } + break; + + default: + break; + } + } + if((rdslider_orient==RDSlider::Left)||(rdslider_orient==RDSlider::Right)) { + // + // The groove + // + p->setPen(QColor(colorGroup().light())); + p->moveTo(knob_size.width()/2,height()/2+1); + p->lineTo(width()-knob_size.width()/2,height()/2+1); + p->setPen(QColor(colorGroup().dark())); + p->moveTo(knob_size.width()/2,height()/2); + p->lineTo(width()-knob_size.width()/2,height()/2); + p->setPen(QColor(colorGroup().shadow())); + p->moveTo(width()-knob_size.width()/2+1,height()/2-1); + p->lineTo(knob_size.width()/2-1,height()/2-1); + + // + // The ticks + // + switch(rdslider_orient) { + case RDSlider::Left: + if((tick_setting==QSlider::Above)||(tick_setting==QSlider::Both)) { + p->setPen(colorGroup().shadow()); + for(int i=minValue();i<=maxValue();i+=tick_interval) { + tick_x=(geometry().width()-curr_knob.width())- + ((geometry().width()-curr_knob.width())*(i-minValue()))/ + (maxValue()-minValue())+curr_knob.width()/2; + p->moveTo(tick_x,0); + p->lineTo(tick_x,height()/2-2); + } + } + if((tick_setting==QSlider::Below)||(tick_setting==QSlider::Both)) { + p->setPen(colorGroup().shadow()); + for(int i=minValue();i<=maxValue();i+=tick_interval) { + tick_x=(geometry().width()-curr_knob.width())- + ((geometry().width()-curr_knob.width())*(i-minValue()))/ + (maxValue()-minValue())+curr_knob.width()/2; + p->moveTo(tick_x,height()/2+2); + p->lineTo(tick_x,height()); + } + } + break; + case RDSlider::Right: + if((tick_setting==QSlider::Above)||(tick_setting==QSlider::Both)) { + p->setPen(colorGroup().shadow()); + for(int i=minValue();i<=maxValue();i+=tick_interval) { + tick_x=(geometry().width()-curr_knob.width()/2)- + abs((geometry().width()-curr_knob.width())*i)/ + (maxValue()-minValue()); + p->moveTo(tick_x,0); + p->lineTo(tick_x,height()/2-2); + } + } + if((tick_setting==QSlider::Below)||(tick_setting==QSlider::Both)) { + p->setPen(colorGroup().shadow()); + for(int i=minValue();i<=maxValue();i+=tick_interval) { + tick_x=(geometry().width()-curr_knob.width()/2)- + abs((geometry().width()-curr_knob.width())*i)/ + (maxValue()-minValue()); + p->moveTo(tick_x,height()/2+2); + p->lineTo(tick_x,height()); + } + } + break; + + default: + break; + } + } + + // + // The knob + // + p->drawPixmap(curr_knob.x(),curr_knob.y(),*knob_map); + + p->end(); +} + + +void RDSlider::mouseMoveEvent(QMouseEvent *mouse) +{ + int curr_x,curr_y; + int knob_value; + + if(rdslider_moving) { + prev_knob=curr_knob; + if((rdslider_orient==RDSlider::Up)||(rdslider_orient==RDSlider::Down)) { + if(mouse->y()<0) { + curr_knob=QRect(curr_knob.x(),0,curr_knob.width(),curr_knob.height()); + if(prev_knob!=curr_knob) { + switch(rdslider_orient) { + case RDSlider::Up: + if(value()!=maxValue()) { + QRangeControl::setValue(maxValue()); + if(tracking_enabled) { + emit valueChanged(value()); + } + else { + deferred_change=true; + } + } + break; + case RDSlider::Down: + if(value()!=minValue()) { + QRangeControl::setValue(minValue()); + if(tracking_enabled) { + emit valueChanged(value()); + } + else { + deferred_change=true; + } + } + break; + + default: + break; + } + emit sliderMoved(value()); + update(prev_knob); + update(curr_knob); + } + return; + } + if(mouse->y()>geometry().height()) { + curr_knob=QRect(curr_knob.x(),height()-curr_knob.height(), + curr_knob.width(),curr_knob.height()); + if(prev_knob!=curr_knob) { + switch(rdslider_orient) { + case RDSlider::Up: + if(value()!=minValue()) { + QRangeControl::setValue(minValue()); + if(tracking_enabled) { + emit valueChanged(value()); + } + else { + deferred_change=true; + } + } + break; + case RDSlider::Down: + if(value()!=maxValue()) { + QRangeControl::setValue(maxValue()); + if(tracking_enabled) { + emit valueChanged(value()); + } + else { + deferred_change=true; + } + } + break; + + default: + break; + } + emit sliderMoved(value()); + update(prev_knob); + update(curr_knob); + } + return; + } + curr_y=curr_knob.y()-base_y+mouse->y(); + if(curr_y<0) { + curr_y=0; + } + if(curr_y>(height()-curr_knob.height())) { + curr_y=height()-curr_knob.height(); + } + curr_knob=QRect(curr_knob.x(),curr_y, + curr_knob.width(),curr_knob.height()); + base_y=mouse->y(); + switch(rdslider_orient) { + case RDSlider::Up: + knob_value=(maxValue()-minValue())* + (geometry().height()-curr_knob.y() + -curr_knob.height())/ + (geometry().height()-curr_knob.height()) + +minValue(); + if(value()!=knob_value) { + QRangeControl::setValue(knob_value); + if(tracking_enabled) { + emit valueChanged(value()); + } + else { + deferred_change=true; + } + } + break; + case RDSlider::Down: + knob_value=((minValue()-maxValue())* + curr_knob.y() + +curr_knob.height()-geometry().height())/ + (curr_knob.height()-geometry().height()) + +minValue(); + if(value()!=knob_value) { + QRangeControl::setValue(knob_value); + if(tracking_enabled) { + emit valueChanged(value()); + } + else { + deferred_change=true; + } + } + break; + + default: + break; + } + emit sliderMoved(value()); + update(prev_knob); + update(curr_knob); + } + + if((rdslider_orient==RDSlider::Left)||(rdslider_orient==RDSlider::Right)) { + if(mouse->x()<0) { + curr_knob=QRect(0,curr_knob.y(),curr_knob.width(),curr_knob.height()); + if(prev_knob!=curr_knob) { + switch(rdslider_orient) { + case RDSlider::Left: + if(value()!=maxValue()) { + QRangeControl::setValue(maxValue()); + if(tracking_enabled) { + emit valueChanged(value()); + } + else { + deferred_change=true; + } + } + break; + case RDSlider::Right: + if(value()!=minValue()) { + QRangeControl::setValue(minValue()); + if(tracking_enabled) { + emit valueChanged(value()); + } + else { + deferred_change=true; + } + } + break; + + default: + break; + } + emit sliderMoved(value()); + update(prev_knob); + update(curr_knob); + } + return; + } + if(mouse->x()>geometry().width()) { + curr_knob=QRect(width()-curr_knob.width(),curr_knob.y(), + curr_knob.width(),curr_knob.height()); + if(prev_knob!=curr_knob) { + switch(rdslider_orient) { + case RDSlider::Left: + if(value()!=minValue()) { + QRangeControl::setValue(minValue()); + if(tracking_enabled) { + emit valueChanged(value()); + } + else { + deferred_change=true; + } + } + break; + case RDSlider::Right: + if(value()!=maxValue()) { + QRangeControl::setValue(maxValue()); + if(tracking_enabled) { + emit valueChanged(value()); + } + else { + deferred_change=true; + } + } + break; + + default: + break; + } + emit sliderMoved(value()); + update(prev_knob); + update(curr_knob); + } + return; + } + curr_x=curr_knob.x()-base_x+mouse->x(); + if(curr_x<0) { + curr_x=0; + } + if(curr_x>(width()-curr_knob.width())) { + curr_x=width()-curr_knob.width(); + } + curr_knob=QRect(curr_x,curr_knob.y(), + curr_knob.width(),curr_knob.height()); + base_x=mouse->x(); + switch(rdslider_orient) { + case RDSlider::Left: + knob_value=(maxValue()-minValue())* + (geometry().width()-curr_knob.x() + -curr_knob.width())/ + (geometry().width()-curr_knob.width()) + +minValue(); + if(value()!=knob_value) { + QRangeControl::setValue(knob_value); + if(tracking_enabled) { + emit valueChanged(value()); + } + else { + deferred_change=true; + } + } + break; + case RDSlider::Right: + knob_value=((minValue()-maxValue())*curr_knob.x() + +curr_knob.width()-geometry().width())/ + (curr_knob.width()-geometry().width()) + +minValue(); + if(value()!=knob_value) { + QRangeControl::setValue(knob_value); + if(tracking_enabled) { + emit valueChanged(value()); + } + else { + deferred_change=true; + } + } + break; + + default: + break; + } + emit sliderMoved(value()); + update(prev_knob); + update(curr_knob); + } + } +} + + +void RDSlider::mousePressEvent(QMouseEvent *mouse) +{ + if(mouse->button()==QMouseEvent::LeftButton) { + if(curr_knob.contains(mouse->x(),mouse->y())) { + base_x=mouse->x(); + base_y=mouse->y(); + rdslider_moving=true; + emit sliderPressed(); + return; + } + if(page_up.contains(mouse->x(),mouse->y())) { + addStep(); + return; + } + if(page_down.contains(mouse->x(),mouse->y())) { + subtractStep(); + } + } + else { + QWidget::mousePressEvent(mouse); + } +} + + +void RDSlider::mouseReleaseEvent(QMouseEvent *mouse) +{ + if(mouse->button()==QMouseEvent::LeftButton) { + rdslider_moving=false; + if(deferred_change) { + emit valueChanged(value()); + deferred_change=false; + } + emit sliderReleased(); + } +} + + +void RDSlider::init(RDSlider::Orientation orient) +{ + rdslider_orient=orient; + knob_map=NULL; + knob_color=colorGroup(); + rdslider_moving=false; + page_step=10; + line_step=1; + tracking_enabled=true; + deferred_change=false; + tick_interval=10; + tick_setting=QSlider::NoMarks; + setRange(0,100); + knob_size=QSize(geometry().width(),10); +} + + +void RDSlider::calcKnob() +{ + calcKnob(geometry().x(),geometry().y(), + geometry().width(),geometry().height()); +} + + +void RDSlider::calcKnob(int x,int y,int w,int h) +{ + int knob_x=0; + int knob_y=0; + int knob_w=0; + int knob_h=0; + QPainter p; + + if((rdslider_orient==RDSlider::Up)||(rdslider_orient==RDSlider::Down)) { + // + // The knob itself + // + knob_w=knob_size.width(); + knob_h=knob_size.height(); + knob_x=w/2-knob_w/2; + switch(rdslider_orient) { + case RDSlider::Up: + knob_y=(h-knob_h)-((h-knob_h)*(value()-minValue()))/ + (maxValue()-minValue()); + break; + case RDSlider::Down: + knob_y=-(h-knob_h-((h-knob_h)*(value()-minValue())))/ + (maxValue()-minValue()); + break; + + default: + break; + } + prev_knob=curr_knob; + if((knob_w>0)&&(knob_h>0)) { + curr_knob=QRect(knob_x,knob_y,knob_w,knob_h); + } + else { + curr_knob=QRect(knob_x,knob_y,1,1); + } + if(prev_knob!=curr_knob) { + emit sliderMoved(value()); + } + + // + // The PageUp/PageDown areas + // + if(rdslider_orient==RDSlider::Up) { + page_up=QRect(knob_x,0,knob_w,knob_y); + page_down=QRect(knob_x,knob_y+knob_h,knob_w,height()-(knob_y+knob_h)); + } + if(rdslider_orient==RDSlider::Down) { + page_down=QRect(knob_x,0,knob_w,knob_y); + page_up=QRect(knob_x,knob_y+knob_h,knob_w,height()-(knob_y+knob_h)); + } + + // + // The knob cap + // + if(knob_map!=NULL) { + delete knob_map; + } + knob_map=new QPixmap(curr_knob.size()); + knob_map->fill(knob_color.background()); + p.begin(knob_map); + + // + // The outline + // + p.setPen(knob_color.light()); + p.moveTo(0,curr_knob.height()-1); + p.lineTo(0,0); + p.lineTo(curr_knob.width()-1,0); + p.moveTo(1,curr_knob.height()-1); + p.lineTo(1,1); + p.lineTo(curr_knob.width()-1,1); + p.setPen(knob_color.dark()); + p.lineTo(curr_knob.width()-1,curr_knob.height()-1); + p.lineTo(0,curr_knob.height()-1); + p.moveTo(curr_knob.width()-2,1); + p.lineTo(curr_knob.width()-2,curr_knob.height()-2); + p.lineTo(0,curr_knob.height()-2); + + // + // The centerline + // + if(curr_knob.height()>=40) { + p.setPen(knob_color.dark()); + p.moveTo(2,curr_knob.height()/2); + p.lineTo(curr_knob.width()-2,curr_knob.height()/2); + p.setPen(knob_color.shadow()); + p.moveTo(2,curr_knob.height()/2-1); + p.lineTo(curr_knob.width()-2,curr_knob.height()/2-1); + p.setPen(knob_color.light()); + p.moveTo(2,curr_knob.height()/2+1); + p.lineTo(curr_knob.width()-2,curr_knob.height()/2+1); + } + p.end(); + } + if((rdslider_orient==RDSlider::Left)||(rdslider_orient==RDSlider::Right)) { + // + // The knob itself + // + knob_w=knob_size.width(); + knob_h=knob_size.height(); + knob_y=h/2-knob_h/2; + switch(rdslider_orient) { + case RDSlider::Left: + knob_x=(w-knob_w)-((w-knob_w)*(value()-minValue()))/ + (maxValue()-minValue()); + break; + case RDSlider::Right: + knob_x=-(w-knob_w-((w-knob_w)*(value()-minValue())))/ + (maxValue()-minValue()); + break; + + default: + break; + } + prev_knob=curr_knob; + if((knob_w>0)&&(knob_h>0)) { + curr_knob=QRect(knob_x,knob_y,knob_w,knob_h); + } + else { + curr_knob=QRect(knob_x,knob_y,1,1); + } + + // + // The PageUp/PageDown areas + // + if(rdslider_orient==RDSlider::Right) { + page_up=QRect(knob_x+knob_w,knob_y,x+w,knob_h); + page_down=QRect(0,knob_y,knob_x,knob_y+knob_h); + } + if(rdslider_orient==RDSlider::Left) { + page_down=QRect(knob_x+knob_w,knob_y,x+w,knob_h); + page_up=QRect(0,knob_y,knob_x,knob_y+knob_h); + } + + // + // The knob cap + // + if(knob_map!=NULL) { + delete knob_map; + } + knob_map=new QPixmap(curr_knob.size()); + knob_map->fill(knob_color.background()); + p.begin(knob_map); + + // + // The outline + // + p.setPen(knob_color.light()); + p.moveTo(0,curr_knob.height()-1); + p.lineTo(0,0); + p.lineTo(curr_knob.width()-1,0); + p.moveTo(1,curr_knob.height()-1); + p.lineTo(1,1); + p.lineTo(curr_knob.width()-1,1); + p.setPen(knob_color.dark()); + p.lineTo(curr_knob.width()-1,curr_knob.height()-1); + p.lineTo(0,curr_knob.height()-1); + p.moveTo(curr_knob.width()-2,1); + p.lineTo(curr_knob.width()-2,curr_knob.height()-2); + p.lineTo(0,curr_knob.height()-2); + + // + // The centerline + // + if(curr_knob.width()>=40) { + p.setPen(knob_color.dark()); + p.moveTo(curr_knob.width()/2,2); + p.lineTo(curr_knob.width()/2,curr_knob.height()-2); + p.setPen(knob_color.shadow()); + p.moveTo(curr_knob.width()/2-1,2); + p.lineTo(curr_knob.width()/2-1,curr_knob.height()-2); + p.setPen(knob_color.light()); + p.moveTo(curr_knob.width()/2+1,2); + p.lineTo(curr_knob.width()/2+1,curr_knob.height()-2); + } + p.end(); + } +} + diff --git a/lib/rdslider.h b/lib/rdslider.h new file mode 100644 index 00000000..9342c889 --- /dev/null +++ b/lib/rdslider.h @@ -0,0 +1,101 @@ +// rdslider.h +// +// An audio- and touchscreen-friendly slider widget. +// +// (C) Copyright 2009 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdslider.h,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDSLIDER_H +#define RDSLIDER_H + +#include <qwidget.h> +#include <qslider.h> +#include <qrangecontrol.h> +#include <qcolor.h> +#include <qpalette.h> +#include <qsize.h> +#include <qpixmap.h> + +class RDSlider : public QWidget,public QRangeControl +{ + Q_OBJECT + public: + enum Orientation {Left=0,Right=1,Up=2,Down=3}; + RDSlider(QWidget *parent,const char *name); + RDSlider(RDSlider::Orientation orient,QWidget *parent,const char *name); + RDSlider(int minValue,int maxValue,int pageStep,int value, + RDSlider::Orientation orient,QWidget *parent,const char *name); + RDSlider::Orientation orientation() const; + void setOrientation(RDSlider::Orientation orient); + void setTracking(bool enable); + bool tracking() const; + void setTickInterval(int i); + void setTickmarks(QSlider::TickSetting s); + void setMinValue(int min_value); + void setMaxValue(int max_value); + void setRange(int min_value,int max_value); + void setLineStep(int step); + void setPageStep(int step); + void setKnobColor(QColorGroup group); + void setKnobColor(QColor color); + void setKnobSize(QSize size); + void setKnobSize(int w,int h); + + signals: + void valueChanged(int value); + void sliderPressed(); + void sliderMoved(int value); + void sliderReleased(); + + public slots: + void setGeometry(int x,int y,int w, int h); + void setGeometry(QRect &rect); + void setValue(int setting); + void addStep(); + void subtractStep(); + + private: + void paintEvent(QPaintEvent *); + void mouseMoveEvent(QMouseEvent *); + void mousePressEvent(QMouseEvent *); + void mouseReleaseEvent(QMouseEvent *); + void init(RDSlider::Orientation orient); + void calcKnob(); + void calcKnob(int x,int y,int w,int h); + RDSlider::Orientation rdslider_orient; + QColorGroup knob_color; + QRect curr_knob; + QRect prev_knob; + QRect page_up; + QRect page_down; + QSize knob_size; + QPixmap *knob_map; + int base_x; + int base_y; + bool rdslider_moving; + int page_step; + int line_step; + bool tracking_enabled; + bool deferred_change; + int tick_interval; + QSlider::TickSetting tick_setting; +}; + + +#endif // RDSLIDER_H diff --git a/lib/rdslotbox.cpp b/lib/rdslotbox.cpp new file mode 100644 index 00000000..a92ae43e --- /dev/null +++ b/lib/rdslotbox.cpp @@ -0,0 +1,572 @@ +// rdslotbox.cpp +// +// Cart slot label widget for RDCartSlot +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdslotbox.cpp,v 1.5.2.8 2014/02/06 20:43:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qpainter.h> + +#include "rdconf.h" +#include "rdplay_deck.h" + +#include "rdnownext.h" +#include "rdslotbox.h" + +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" + +RDSlotBox::RDSlotBox(RDPlayDeck *deck,RDAirPlayConf *conf,QWidget *parent) + : QWidget(parent) +{ + line_deck=deck; + line_airplay_conf=conf; + line_type=RDLogLine::UnknownType; + line_logline=NULL; + line_mode=RDSlotOptions::LastMode; + log_id=-1; + + // + // Create Font + // + line_bold_font=QFont("Helvetica",12,QFont::Bold); + line_bold_font.setPixelSize(12); + line_font=QFont("Helvetica",12,QFont::Normal); + line_font.setPixelSize(12); + talk_font=QFont("Helvetica",12,QFont::Bold); + talk_font.setPixelSize(12); + QFont outcue_font=QFont("Helvetica",12,QFont::Normal); + outcue_font.setPixelSize(12); + outcue_font.setItalic(true); + + // + // Create Icons + // + line_playout_map=new QPixmap(play_xpm); + line_macro_map=new QPixmap(rml5_xpm); + + // + // Create Palettes + // + line_unchanged_stop_palette=palette(); + line_unchanged_stop_palette.setColor(QPalette::Active,QColorGroup::Highlight, + QColor(BAR_UNCHANGED_STOPPING_COLOR)); + line_unchanged_stop_palette.setColor(QPalette::Inactive, + QColorGroup::Highlight, + QColor(BAR_UNCHANGED_STOPPING_COLOR)); + line_unchanged_play_palette=palette(); + line_unchanged_play_palette.setColor(QPalette::Active,QColorGroup::Highlight, + QColor(BAR_UNCHANGED_TRANSITION_COLOR)); + line_unchanged_play_palette.setColor(QPalette::Inactive, + QColorGroup::Highlight, + QColor(BAR_UNCHANGED_TRANSITION_COLOR)); + line_changed_stop_palette=palette(); + line_changed_stop_palette.setColor(QPalette::Active,QColorGroup::Highlight, + QColor(BAR_CHANGED_STOPPING_COLOR)); + line_changed_stop_palette.setColor(QPalette::Inactive,QColorGroup::Highlight, + QColor(BAR_CHANGED_STOPPING_COLOR)); + line_changed_play_palette=palette(); + line_changed_play_palette.setColor(QPalette::Active,QColorGroup::Highlight, + QColor(BAR_CHANGED_TRANSITION_COLOR)); + line_changed_play_palette.setColor(QPalette::Inactive,QColorGroup::Highlight, + QColor(BAR_CHANGED_TRANSITION_COLOR)); + line_time_palette=palette(); + line_hard_palette=palette(); + line_hard_palette.setColor(QPalette::Active,QColorGroup::Foreground, + QColor(LOG_HARDTIME_TEXT_COLOR)); + line_hard_palette.setColor(QPalette::Inactive,QColorGroup::Foreground, + QColor(LOG_HARDTIME_TEXT_COLOR)); + + line_timescale_palette=palette(); + line_timescale_palette.setColor(QPalette::Active,QColorGroup::Foreground, + QColor(LABELBOX_TIMESCALE_COLOR)); + line_timescale_palette.setColor(QPalette::Inactive,QColorGroup::Foreground, + QColor(LABELBOX_TIMESCALE_COLOR)); + + // + // Audio Meter + // + for(int i=0;i<2;i++) { + line_meter[i]=new RDPlayMeter(RDSegMeter::Up,this); + line_meter[i]->setGeometry(5+15*i,5,15,sizeHint().height()-10); + line_meter[i]->setRange(-4600,0); + line_meter[i]->setHighThreshold(-1600); + line_meter[i]->setClipThreshold(-1100); + line_meter[i]->setSegmentSize(2); + line_meter[i]->setSegmentGap(1); + line_meter[i]->setMode(RDSegMeter::Peak); + } + line_meter[0]->setLabel(tr("L")); + line_meter[1]->setLabel(tr("R")); + + // + // Count Up + // + line_up_label=new QLabel(this); + line_up_label->setGeometry(45,65,65,16); + line_up_label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + line_up_label->setFont(line_font); + line_up_label->hide(); + + // + // Position Slider + // + line_position_bar=new QProgressBar(this); + line_position_bar->setGeometry(115,69,sizeHint().width()-190,13); + line_position_bar->setPercentageVisible(false); + line_position_bar->hide(); + + // + // Count Down + // + line_down_label=new QLabel(this); + line_down_label->setGeometry(sizeHint().width()-72,65,65,16); + line_down_label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + line_down_label->setFont(line_font); + line_down_label->hide(); + + // + // Cut Description + // + line_description_label=new QLabel(this); + line_description_label->setGeometry((sizeHint().width()/2),49,(sizeHint().width()/2 -10),16); + line_description_label->setFont(line_font); + + // + // Outcue + // + line_outcue_label=new QLabel(this); + line_outcue_label->setGeometry(45,49, (sizeHint().width()/2 -50),16); + line_outcue_label->setFont(outcue_font); + + // + // Artist + // + line_artist_label=new QLabel(this); + line_artist_label->setGeometry(45,36,sizeHint().width()-50,16); + line_artist_label->setFont(line_font); + line_artist_label->hide(); + + // + // Title + // + line_title_label=new QLabel(this); + line_title_label->setGeometry(45,18,sizeHint().width()-50,18); + line_title_label->setFont(line_bold_font); + + // + // Icon + // + line_icon_label=new QLabel(this); + line_icon_label->setGeometry(45,3,45,16); + + // + // Cart + // + line_cart_label=new QLabel(this); + line_cart_label->setGeometry(65,3,53,16); + line_cart_label->setFont(line_font); + + // + // Cut + // + line_cut_label=new QLabel(this); + line_cut_label->setGeometry(120,3,24,16); + line_cut_label->setFont(line_font); + + // + // Group + // + line_group_label=new QLabel(this); + line_group_label->setGeometry(147,3,75,16); + line_group_label->setFont(line_bold_font); + + // + // Talk Time + // + line_talktime_label=new QLabel(this); + line_talktime_label->setGeometry(313,3,21,16); + line_talktime_label->setFont(talk_font); + line_talktime_label->setAlignment(Qt::AlignRight); + + // + // Length + // + line_length_label=new QLabel(this); + line_length_label->setGeometry(337,3,40,16); + line_length_label->setFont(line_font); + line_length_label->setAlignment(Qt::AlignRight); + + SetColor(QColor(LABELBOX_BACKGROUND_COLOR)); +} + + +QSize RDSlotBox::sizeHint() const +{ + return QSize(393,RDSLOTBOX_FULL_HEIGHT); +} + + +QSizePolicy RDSlotBox::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +RDLogLine *RDSlotBox::logLine() +{ + return line_logline; +} + + +void RDSlotBox::updateMeters(short levels[2]) +{ + line_meter[0]->setPeakBar(levels[0]); + line_meter[1]->setPeakBar(levels[1]); +} + + +void RDSlotBox::setCart(RDLogLine *logline) +{ + QString cutname; + QPalette p; + + line_logline=logline; + + RDCart *cart; + RDCut *cut; + + line_type=logline->type(); + switch(line_type) { + case RDLogLine::Cart: + cart=new RDCart(logline->cartNumber()); + cut=new RDCut(QString().sprintf("%06u_%03u",logline->cartNumber(), + logline->cutNumber())); + if(!cart->exists()) { + line_cart_label-> + setText(QString().sprintf("%06u",logline->cartNumber())); + line_description_label->clear(); + line_artist_label->clear(); + line_cut_label->clear(); + line_group_label->clear(); + line_outcue_label->clear(); + line_length_label->setText("00:00"); + line_talktime_label->setText(":00"); + line_up_label->setText("0:00:00"); + line_down_label->setText("0:00:00"); + line_title_label->setText(tr("[CART NOT FOUND]")); + switch(cart->type()) { + case RDCart::Audio: + case RDCart::Macro: + case RDCart::All: + line_icon_label->setPixmap(*line_playout_map); + break; + } + SetColor(QColor(LABELBOX_MISSING_COLOR)); + } + else { + if(((cart->forcedLength()==0)&&(cart->type()==RDCart::Audio))|| + (line_logline->state()==RDLogLine::NoCut)) { + line_cart_label-> + setText(QString().sprintf("%06u",logline->cartNumber())); + line_description_label->setText(cut->description()); + line_artist_label->setText(tr("[NO AUDIO AVAILABLE]")); + line_cut_label->clear(); + line_group_label->clear(); + line_outcue_label->clear(); + line_length_label->setText("00:00"); + line_talktime_label->setText(":00"); + line_up_label->setText("0:00:00"); + line_down_label->setText("0:00:00"); + line_icon_label->setPixmap(*line_playout_map); + line_title_label->setText(logline->title()); + SetColor(QColor(LABELBOX_MISSING_COLOR)); + } + else { + line_cart_label-> + setText(QString().sprintf("%06u",logline->cartNumber())); + if(line_logline->evergreen()) { + SetColor(QColor(LABELBOX_EVERGREEN_COLOR)); + } + else { + SetColor(QColor(LABELBOX_BACKGROUND_COLOR)); + } + switch(cart->type()) { + case RDCart::Audio: + case RDCart::All: + line_icon_label->setPixmap(*line_playout_map); + break; + + case RDCart::Macro: + line_icon_label->setPixmap(*line_macro_map); + break; + } + line_group_label->setText(cart->groupName()); + p=line_group_label->palette(); + p.setColor(QColorGroup::Foreground,line_logline->groupColor()); + line_group_label->setPalette(p); + if(line_logline->talkLength()<=0) { + line_talktime_label->setText(":00"); + } + else { + line_talktime_label-> + setText(RDGetTimeLength(line_logline->talkLength(), + false,false)); + } + line_length_label-> + setText(RDGetTimeLength(line_logline->effectiveLength(), + false,false)); + if(line_logline->timescalingActive()) { + line_length_label->setPalette(line_hard_palette); + } + else { + line_length_label->setPalette(line_time_palette); + } + if(line_logline->originUser().isEmpty()|| + (!line_logline->originDateTime().isValid())) { + line_title_label-> + setText(RDResolveNowNext(line_airplay_conf->titleTemplate(), + logline)); + } + else { + line_title_label->setText(line_logline->title()+" -- "+ + line_logline->originUser()+" "+ + line_logline->originDateTime(). + toString("M/d hh:mm")); + } + line_description_label-> + setText(RDResolveNowNext(line_airplay_conf->descriptionTemplate(), + logline)); + line_artist_label-> + setText(RDResolveNowNext(line_airplay_conf->artistTemplate(), + logline)); + line_up_label-> + setText(RDGetTimeLength(line_logline->playPosition(),true,true)); + line_down_label-> + setText(RDGetTimeLength(line_logline->effectiveLength()- + line_logline->playPosition(),true,true)); + line_position_bar->setTotalSteps(line_logline->effectiveLength()); + line_position_bar->setProgress(line_logline->playPosition()); + if(logline->cutNumber()>=0) { + line_cut_label-> + setText(QString().sprintf("%03u",logline->cutNumber())); + line_outcue_label-> + setText(RDResolveNowNext(line_airplay_conf->outcueTemplate(), + logline)); + line_position_bar->show(); + line_up_label->show(); + line_down_label->show(); + } + else { + SetColor(QColor(LABELBOX_MISSING_COLOR)); + line_cut_label->clear(); + line_outcue_label->setText(tr("[NO VALID CUT AVAILABLE]")); + } + line_title_label->show(); + line_artist_label->show(); + } + } + delete cart; + delete cut; + break; + + case RDLogLine::Macro: + line_icon_label->setPixmap(*line_macro_map); + line_position_bar->hide(); + line_up_label->hide(); + line_down_label->hide(); + cart=new RDCart(logline->cartNumber()); + cut=new RDCut(QString().sprintf("%06u_%03u",logline->cartNumber(), + logline->cutNumber())); + if(!cart->exists()) { + SetColor(QColor(LABELBOX_MISSING_COLOR)); + } + else { + SetColor(QColor(LABELBOX_BACKGROUND_COLOR)); + } + line_cart_label->setText(QString().sprintf("%06u",cart->number())); + line_cut_label->setText(""); + line_group_label->setText(cart->groupName()); + p=line_group_label->palette(); + p.setColor(QColorGroup::Foreground,line_logline->groupColor()); + line_group_label->setPalette(p); + line_length_label-> + setText(RDGetTimeLength(line_logline->effectiveLength(), + false,false)); + line_title_label->setText(cart->title()); + line_description_label->setText(""); + line_artist_label->setText(cart->artist()); + line_outcue_label->setText(""); + delete cart; + delete cut; + line_title_label->show(); + line_artist_label->show(); + break; + + default: + break; + } +} + + +void RDSlotBox::setMode(RDSlotOptions::Mode mode) +{ + line_mode=mode; +} + + +void RDSlotBox::setService(const QString &svcname) +{ + clear(); + line_title_label->setText("Service: "+svcname); +} + + +void RDSlotBox::setStatusLine(const QString &str) +{ + line_artist_label->setText(str); +} + + +void RDSlotBox::setTimer(int msecs) +{ + if(line_logline==NULL) { + line_up_label->setText(RDGetTimeLength(0,true,true)); + line_down_label->setText(RDGetTimeLength(0,true,true)); + line_position_bar->setProgress(0); + } + else { + line_up_label->setText(RDGetTimeLength(msecs,true,true)); + line_down_label-> + setText(RDGetTimeLength(line_logline->effectiveLength()-msecs,true,true)); + line_position_bar->setProgress(msecs); + } +} + + +void RDSlotBox::clear() +{ + SetColor(QColor(LABELBOX_BACKGROUND_COLOR)); + line_cart_label->setText(""); + line_cut_label->setText(""); + line_group_label->setText(""); + line_title_label->setText(""); + line_description_label->setText(""); + line_artist_label->setText(""); + line_outcue_label->setText(""); + line_talktime_label->setText(""); + line_length_label->setText(""); + line_up_label->setText(""); + line_down_label->setText(""); + line_position_bar->reset(); + line_end_time=QTime(); + log_id=-1; + line_logline=NULL; + line_type=RDLogLine::Cart; + line_up_label->hide(); + line_position_bar->hide(); + line_down_label->hide(); + line_icon_label->clear(); + line_allow_drags=false; + setBarMode(RDSlotBox::Stopping); +} + + +void RDSlotBox::setBarMode(bool changed) +{ + if(changed) { + line_position_bar->setPalette(line_changed_stop_palette); + } + else { + line_position_bar->setPalette(line_unchanged_stop_palette); + } +} + + +void RDSlotBox::setAllowDrags(bool state) +{ + line_allow_drags=state; +} + + +void RDSlotBox::mousePressEvent(QMouseEvent *e) +{ + QWidget::mousePressEvent(e); + + if((line_logline!=NULL)&&(line_mode==RDSlotOptions::CartDeckMode)&& + line_allow_drags) { + RDCartDrag *d=new RDCartDrag(line_logline->cartNumber(), + line_icon_label->pixmap(),this); + d->dragCopy(); + } +} + + +void RDSlotBox::mouseDoubleClickEvent(QMouseEvent *e) +{ + emit doubleClicked(); + QWidget::mouseDoubleClickEvent(e); +} + + +void RDSlotBox::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->drawRect(0,0,sizeHint().width()-1,sizeHint().height()-1); + p->fillRect(1,1,sizeHint().width()-3,sizeHint().height()-3, + backgroundColor()); + p->end(); + delete p; +} + + +void RDSlotBox::dragEnterEvent(QDragEnterEvent *e) +{ + e->accept(RDCartDrag::canDecode(e)&& + (line_mode==RDSlotOptions::CartDeckMode)&& + (line_deck->state()==RDPlayDeck::Stopped)); +} + + +void RDSlotBox::dropEvent(QDropEvent *e) +{ + unsigned cartnum; + + if(RDCartDrag::decode(e,&cartnum)) { + emit cartDropped(cartnum); + } +} + + +void RDSlotBox::SetColor(QColor color) +{ + setBackgroundColor(color); + line_cart_label->setBackgroundColor(color); + line_cut_label->setBackgroundColor(color); + line_group_label->setBackgroundColor(color); + line_title_label->setBackgroundColor(color); + line_description_label->setBackgroundColor(color); + line_artist_label->setBackgroundColor(color); + line_outcue_label->setBackgroundColor(color); + line_length_label->setBackgroundColor(color); + line_talktime_label->setBackgroundColor(color); + line_up_label->setBackgroundColor(color); + line_position_bar->setBackgroundColor(QColor(Qt::lightGray)); + line_down_label->setBackgroundColor(color); + line_icon_label->setBackgroundColor(color); +} diff --git a/lib/rdslotbox.h b/lib/rdslotbox.h new file mode 100644 index 00000000..8230fa14 --- /dev/null +++ b/lib/rdslotbox.h @@ -0,0 +1,119 @@ +// rdslotbox.h +// +// Cart slot label widget for RDCartSlot +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdslotbox.h,v 1.3.2.7 2014/02/06 20:43:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDSLOTBOX_H +#define RDSLOTBOX_H + +#include <qwidget.h> +#include <qtimer.h> +#include <qdatetime.h> +#include <qpushbutton.h> +#include <qprogressbar.h> +#include <qpalette.h> +#include <qpixmap.h> +#include <qlabel.h> + +#include <rdlabel.h> +#include <rdlog_line.h> +#include <rdlog_event.h> +#include <rdplaymeter.h> +#include <rdplay_deck.h> +#include <rdcartdrag.h> +#include <rdslotoptions.h> +#include <rdairplay_conf.h> + +// +// Widget Settings +// +#define RDSLOTBOX_FULL_HEIGHT 85 +#define RDSLOTBOX_HALF_HEIGHT 50 + +class RDSlotBox : public QWidget +{ + Q_OBJECT + public: + enum BarMode {Transitioning=0,Stopping=1}; + RDSlotBox(RDPlayDeck *deck,RDAirPlayConf *conf,QWidget *parent=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + RDLogLine *logLine(); + void setCart(RDLogLine *logline); + void setMode(RDSlotOptions::Mode mode); + void setService(const QString &svcname); + void setStatusLine(const QString &str); + void setTimer(int msecs); + void clear(); + void setBarMode(bool changed); + void setAllowDrags(bool state); + void updateMeters(short levels[2]); + + signals: + void doubleClicked(); + void cartDropped(unsigned cartnum); + + protected: + void mousePressEvent(QMouseEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); + void paintEvent(QPaintEvent *); + void dragEnterEvent(QDragEnterEvent *e); + void dropEvent(QDropEvent *e); + + private: + void SetColor(QColor); + QLabel *line_icon_label; + QLabel *line_cart_label; + QLabel *line_cut_label; + QLabel *line_group_label; + QLabel *line_title_label; + QLabel *line_description_label; + QLabel *line_artist_label; + QLabel *line_outcue_label; + QLabel *line_length_label; + QLabel *line_talktime_label; + QLabel *line_up_label; + QLabel *line_down_label; + QProgressBar *line_position_bar; + QTime line_end_time; + int log_id; + RDLogLine *line_logline; + RDSlotOptions::Mode line_mode; + QFont line_font; + QFont talk_font; + QFont line_bold_font; + QPalette line_unchanged_stop_palette; + QPalette line_unchanged_play_palette; + QPalette line_changed_stop_palette; + QPalette line_changed_play_palette; + QPalette line_time_palette; + QPalette line_hard_palette; + QPalette line_timescale_palette; + RDLogLine::Type line_type; + QPixmap *line_playout_map; + QPixmap *line_macro_map; + RDPlayMeter *line_meter[2]; + RDPlayDeck *line_deck; + RDAirPlayConf *line_airplay_conf; + bool line_allow_drags; +}; + + +#endif diff --git a/lib/rdslotdialog.cpp b/lib/rdslotdialog.cpp new file mode 100644 index 00000000..427bd859 --- /dev/null +++ b/lib/rdslotdialog.cpp @@ -0,0 +1,175 @@ +// rdslotdialog.cpp +// +// Slot Editor for RDCartSlots. +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdslotdialog.cpp,v 1.3.2.4 2012/11/28 01:57:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qcolordialog.h> + +#include <rddb.h> +#include <rdcart.h> +#include <rdcart_dialog.h> +#include <rd.h> +#include <rdconf.h> + +#include "rdslotdialog.h" + +RDSlotDialog::RDSlotDialog(const QString &caption,QWidget *parent) + : QDialog(parent) +{ + edit_caption=caption; + edit_options=NULL; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + setCaption(caption+" - "+tr("Edit Slot Options")); + + // + // Create Fonts + // + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont button_font=QFont("Helvetica",14,QFont::Bold); + button_font.setPixelSize(14); + QFont counter_font=QFont("Helvetica",24,QFont::Bold); + counter_font.setPixelSize(24); + + // + // Slot Mode + // + edit_mode_box=new QComboBox(this); + connect(edit_mode_box,SIGNAL(activated(int)), + this,SLOT(modeActivatedData(int))); + for(int i=0;i<RDSlotOptions::LastMode;i++) { + edit_mode_box->insertItem(RDSlotOptions::modeText((RDSlotOptions::Mode)i)); + } + edit_mode_label=new QLabel(tr("Slot Mode:"),this); + edit_mode_label->setFont(label_font); + edit_mode_label->setAlignment(Qt::AlignRight); + + // + // Hook Mode + // + edit_hook_box=new QComboBox(this); + edit_hook_box->insertItem(tr("Full Cart")); + edit_hook_box->insertItem(tr("Hook")); + edit_hook_label=new QLabel(tr("Play Mode:"),this); + edit_hook_label->setFont(label_font); + edit_hook_label->setAlignment(Qt::AlignRight); + + // + // Stop Action + // + edit_stop_action_box=new QComboBox(this); + for(int i=0;i<RDSlotOptions::LastStop;i++) { + edit_stop_action_box-> + insertItem(RDSlotOptions::stopActionText((RDSlotOptions::StopAction)i)); + } + edit_stop_action_label=new QLabel(tr("At Playout End:"),this); + edit_stop_action_label->setFont(label_font); + edit_stop_action_label->setAlignment(Qt::AlignRight); + + // + // Ok Button + // + edit_ok_button=new QPushButton(this); + edit_ok_button->setDefault(true); + edit_ok_button->setFont(label_font); + edit_ok_button->setText(tr("&OK")); + connect(edit_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + edit_cancel_button=new QPushButton(this); + edit_cancel_button->setFont(label_font); + edit_cancel_button->setText(tr("&Cancel")); + connect(edit_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +RDSlotDialog::~RDSlotDialog() +{ +} + + +QSize RDSlotDialog::sizeHint() const +{ + return QSize(350,142); +} + + +QSizePolicy RDSlotDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int RDSlotDialog::exec(RDSlotOptions *opt) +{ + edit_options=opt; + edit_mode_box->setCurrentItem(edit_options->mode()); + edit_hook_box->setCurrentItem(edit_options->hookMode()); + edit_stop_action_box->setCurrentItem(edit_options->stopAction()); + modeActivatedData(edit_mode_box->currentItem()); + return QDialog::exec(); +} + + +void RDSlotDialog::modeActivatedData(int index) +{ + RDSlotOptions::Mode mode=(RDSlotOptions::Mode)index; + edit_hook_label->setEnabled(mode==RDSlotOptions::CartDeckMode); + edit_hook_box->setEnabled(mode==RDSlotOptions::CartDeckMode); + edit_stop_action_label->setEnabled(mode==RDSlotOptions::CartDeckMode); + edit_stop_action_box->setEnabled(mode==RDSlotOptions::CartDeckMode); +} + + +void RDSlotDialog::okData() +{ + edit_options->setMode((RDSlotOptions::Mode)edit_mode_box->currentItem()); + edit_options->setHookMode(edit_hook_box->currentItem()); + edit_options->setStopAction((RDSlotOptions::StopAction)edit_stop_action_box-> + currentItem()); + done(0); +} + + +void RDSlotDialog::cancelData() +{ + done(-1); +} + + +void RDSlotDialog::resizeEvent(QResizeEvent *e) +{ + edit_mode_box->setGeometry(130,10,150,20); + edit_mode_label->setGeometry(10,10,115,20); + edit_hook_box->setGeometry(130,32,150,20); + edit_hook_label->setGeometry(10,32,115,20); + edit_stop_action_box->setGeometry(130,54,size().width()-140,20); + edit_stop_action_label->setGeometry(10,54,115,20); + edit_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + edit_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} diff --git a/lib/rdslotdialog.h b/lib/rdslotdialog.h new file mode 100644 index 00000000..109d8a81 --- /dev/null +++ b/lib/rdslotdialog.h @@ -0,0 +1,67 @@ +// rdslotdialog.h +// +// Slot Editor for RDCartSlots. +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdslotdialog.h,v 1.3.2.3 2012/11/28 01:57:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDSLOTDIALOG_H +#define RDSLOTDIALOG_H + +#include <qdialog.h> +#include <qlabel.h> +#include <qcombobox.h> +#include <qpushbutton.h> + +#include <rdslotoptions.h> + +class RDSlotDialog : public QDialog +{ + Q_OBJECT + public: + RDSlotDialog(const QString &caption,QWidget *parent=0); + ~RDSlotDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(RDSlotOptions *opts); + + private slots: + void modeActivatedData(int index); + void okData(); + void cancelData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + QLabel *edit_mode_label; + QComboBox *edit_mode_box; + QLabel *edit_hook_label; + QComboBox *edit_hook_box; + QLabel *edit_stop_action_label; + QComboBox *edit_stop_action_box; + QPushButton *edit_ok_button; + QPushButton *edit_cancel_button; + RDSlotOptions *edit_options; + QString edit_caption; +}; + + +#endif // RDSLOTDIALOG_H diff --git a/lib/rdslotoptions.cpp b/lib/rdslotoptions.cpp new file mode 100644 index 00000000..3927f2e9 --- /dev/null +++ b/lib/rdslotoptions.cpp @@ -0,0 +1,299 @@ +// rdslotoptions.cpp +// +// Container class for RDCartSlot options +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdslotoptions.cpp,v 1.2.2.5 2012/11/28 18:49:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qobject.h> + +#include <rddb.h> +#include <rdescape_string.h> + +#include "rdslotoptions.h" + +RDSlotOptions::RDSlotOptions(const QString &stationname,unsigned slotno) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + set_stationname=stationname; + set_slotno=slotno; + + // + // Ensure that the DB record exists + // + sql=QString("select ID from CARTSLOTS where (STATION_NAME=\"")+ + RDEscapeString(stationname)+"\")&&"+ + QString().sprintf("(SLOT_NUMBER=%u)",slotno); + q=new RDSqlQuery(sql); + if(!q->first()) { + sql=QString("insert into CARTSLOTS set ")+ + "STATION_NAME=\""+RDEscapeString(stationname)+"\","+ + QString().sprintf("SLOT_NUMBER=%u",slotno); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + clear(); +} + + +RDSlotOptions::Mode RDSlotOptions::mode() const +{ + return set_mode; +} + + +void RDSlotOptions::setMode(RDSlotOptions::Mode mode) +{ + set_mode=mode; +} + + +bool RDSlotOptions::hookMode() const +{ + return set_hook_mode; +} + + +void RDSlotOptions::setHookMode(bool state) +{ + set_hook_mode=state; +} + + +RDSlotOptions::StopAction RDSlotOptions::stopAction() const +{ + return set_stop_action; +} + + +void RDSlotOptions::setStopAction(RDSlotOptions::StopAction action) +{ + set_stop_action=action; +} + + +int RDSlotOptions::cartNumber() const +{ + return set_cart_number; +} + + +void RDSlotOptions::setCartNumber(int cart) +{ + set_cart_number=cart; +} + + +QString RDSlotOptions::service() const +{ + return set_service; +} + + +void RDSlotOptions::setService(const QString &str) +{ + set_service=str; +} + + +int RDSlotOptions::card() const +{ + return set_card; +} + + +int RDSlotOptions::inputPort() const +{ + return set_input_port; +} + + +int RDSlotOptions::outputPort() const +{ + return set_output_port; +} + + +bool RDSlotOptions::load() +{ + bool ret=false; + QString sql; + RDSqlQuery *q; + + sql=QString("select CARD,INPUT_PORT,OUTPUT_PORT,")+ + "MODE,DEFAULT_MODE,HOOK_MODE,DEFAULT_HOOK_MODE,"+ + "STOP_ACTION,DEFAULT_STOP_ACTION,"+ + "CART_NUMBER,DEFAULT_CART_NUMBER,SERVICE_NAME from CARTSLOTS "+ + "where (STATION_NAME=\""+RDEscapeString(set_stationname)+"\")&&"+ + QString().sprintf("(SLOT_NUMBER=%u)",set_slotno); + q=new RDSqlQuery(sql); + if(q->first()) { + ret=true; + + // + // Channel Assignments + // + set_card=q->value(0).toInt(); + set_input_port=q->value(1).toInt(); + set_output_port=q->value(2).toInt(); + + // + // Mode + // + switch(q->value(4).toInt()) { + case -1: + set_mode=(RDSlotOptions::Mode)q->value(3).toInt(); + break; + + case 1: + set_mode=RDSlotOptions::BreakawayMode; + break; + + default: + set_mode=RDSlotOptions::CartDeckMode; + break; + } + + // + // Play Mode + // + switch(q->value(6).toInt()) { + case -1: + set_hook_mode=q->value(5).toInt()==1; + break; + + case 1: + set_hook_mode=true; + break; + + default: + set_hook_mode=false; + break; + } + + // + // Stop Action + // + if(q->value(8).toInt()<0) { + set_stop_action=(RDSlotOptions::StopAction)q->value(7).toInt(); + } + else { + set_stop_action=(RDSlotOptions::StopAction)q->value(8).toInt(); + } + + // + // Cart + // + switch(q->value(10).toInt()) { + case -1: + set_cart_number=q->value(9).toInt(); + break; + + case 0: + set_cart_number=0; + break; + + default: + set_cart_number=q->value(10).toInt(); + break; + } + + // + // Breakaway Service + // + set_service=q->value(11).toString(); + } + + return ret; +} + + +void RDSlotOptions::save() const +{ + QString sql; + RDSqlQuery *q; + + sql=QString("update CARTSLOTS set ")+ + QString().sprintf("MODE=%d,HOOK_MODE=%d,STOP_ACTION=%d,CART_NUMBER=%d,", + set_mode,set_hook_mode,set_stop_action,set_cart_number)+ + "SERVICE_NAME=\""+RDEscapeString(set_service)+"\" "+ + "where (STATION_NAME=\""+RDEscapeString(set_stationname)+"\")&&"+ + QString().sprintf("(SLOT_NUMBER=%u)",set_slotno); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDSlotOptions::clear() +{ + set_mode=RDSlotOptions::CartDeckMode; + set_hook_mode=false; + set_stop_action=RDSlotOptions::UnloadOnStop; + set_cart_number=0; + set_service=""; + set_card=0; + set_input_port=0; + set_output_port=0; +} + + +QString RDSlotOptions::modeText(RDSlotOptions::Mode mode) +{ + QString ret=QObject::tr("Unknown Mode"); + switch(mode) { + case RDSlotOptions::CartDeckMode: + ret=QObject::tr("Cart Deck"); + break; + + case RDSlotOptions::BreakawayMode: + ret=QObject::tr("Breakaway"); + break; + + case RDSlotOptions::LastMode: + break; + } + return ret; +} + + +QString RDSlotOptions::stopActionText(RDSlotOptions::StopAction action) +{ + QString ret=QObject::tr("Unknown Stop Action"); + switch(action) { + case RDSlotOptions::UnloadOnStop: + ret=QObject::tr("Unload Slot"); + break; + + case RDSlotOptions::RecueOnStop: + ret=QObject::tr("Recue to Start"); + break; + + case RDSlotOptions::LoopOnStop: + ret=QObject::tr("Restart Playout (Loop)"); + break; + + case RDSlotOptions::LastStop: + break; + } + return ret; +} diff --git a/lib/rdslotoptions.h b/lib/rdslotoptions.h new file mode 100644 index 00000000..f25275c7 --- /dev/null +++ b/lib/rdslotoptions.h @@ -0,0 +1,67 @@ +// rdslotoptions.h +// +// Container class for RDCartSlot options +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdslotoptions.h,v 1.2.2.4 2012/11/28 01:57:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDSLOTOPTIONS_H +#define RDSLOTOPTIONS_H + +#include <qstring.h> + +class RDSlotOptions +{ + public: + enum Mode {CartDeckMode=0,BreakawayMode=1,LastMode=2}; + enum StopAction {UnloadOnStop=0,RecueOnStop=1,LoopOnStop=2,LastStop=3}; + RDSlotOptions(const QString &stationname,unsigned slotno); + RDSlotOptions::Mode mode() const; + void setMode(RDSlotOptions::Mode mode); + bool hookMode() const; + void setHookMode(bool state); + RDSlotOptions::StopAction stopAction() const; + void setStopAction(RDSlotOptions::StopAction action); + int cartNumber() const; + void setCartNumber(int cart); + QString service() const; + void setService(const QString &str); + int card() const; + int inputPort() const; + int outputPort() const; + bool load(); + void save() const; + void clear(); + static QString modeText(RDSlotOptions::Mode mode); + static QString stopActionText(RDSlotOptions::StopAction action); + + private: + Mode set_mode; + bool set_hook_mode; + StopAction set_stop_action; + int set_cart_number; + QString set_service; + int set_card; + int set_input_port; + int set_output_port; + QString set_stationname; + unsigned set_slotno; +}; + + +#endif // RDSLOTOPTIONS_H diff --git a/lib/rdsocket.cpp b/lib/rdsocket.cpp new file mode 100644 index 00000000..afeed057 --- /dev/null +++ b/lib/rdsocket.cpp @@ -0,0 +1,86 @@ +// rdsocket.cpp +// +// A QSocket object with connection-ID. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsocket.cpp,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <stdlib.h> +#include <stdio.h> +#include <qwidget.h> +#include <qsocket.h> + +#include <rdsocket.h> + + +RDSocket::RDSocket(int id,QObject *parent,const char *name) + : QSocket(parent,name) +{ + id_num=id; + connect(this,SIGNAL(hostFound()),this,SLOT(hostFoundData())); + connect(this,SIGNAL(connected()),this,SLOT(connectedData())); + connect(this,SIGNAL(connectionClosed()),this,SLOT(connectionClosedData())); + connect(this,SIGNAL(delayedCloseFinished()), + this,SLOT(delayedCloseFinishedData())); + connect(this,SIGNAL(readyRead()),this,SLOT(readyReadData())); + connect(this,SIGNAL(bytesWritten(int)),this,SLOT(bytesWrittenData(int))); + connect(this,SIGNAL(error(int)),this,SLOT(errorData(int))); +} + + +void RDSocket::hostFoundData() +{ + emit hostFoundID(id_num); +} + + +void RDSocket::connectedData() +{ + emit connectedID(id_num); +} + + +void RDSocket::connectionClosedData() +{ + emit connectionClosedID(id_num); +} + + +void RDSocket::delayedCloseFinishedData() +{ + emit delayedCloseFinishedID(id_num); +} + + +void RDSocket::readyReadData() +{ + emit readyReadID(id_num); +} + + +void RDSocket::bytesWrittenData(int nbytes) +{ + emit bytesWrittenID(nbytes,id_num); +} + + +void RDSocket::errorData(int error) +{ + emit errorID(error,id_num); +} diff --git a/lib/rdsocket.h b/lib/rdsocket.h new file mode 100644 index 00000000..0cad24f1 --- /dev/null +++ b/lib/rdsocket.h @@ -0,0 +1,61 @@ +// rdsocket.h +// +// A QSocket object with connection-ID. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsocket.h,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDSOCKET_H +#define RDSOCKET_H + +#include <qobject.h> +#include <qsocket.h> + + +class RDSocket : public QSocket +{ + Q_OBJECT + + public: + RDSocket(int id,QObject *parent=0,const char *name=0); + + signals: + void hostFoundID(int id); + void connectedID(int id); + void connectionClosedID(int id); + void delayedCloseFinishedID(int id); + void readyReadID(int id); + void bytesWrittenID(int nbytes,int id); + void errorID(int error,int id); + + private slots: + void hostFoundData(); + void connectedData(); + void connectionClosedData(); + void delayedCloseFinishedData(); + void readyReadData(); + void bytesWrittenData(int nbytes); + void errorData(int error); + + private: + int id_num; +}; + + +#endif // RDSOCKET_H diff --git a/lib/rdsound_panel.cpp b/lib/rdsound_panel.cpp new file mode 100644 index 00000000..a74bdb36 --- /dev/null +++ b/lib/rdsound_panel.cpp @@ -0,0 +1,1676 @@ +// rdsound_panel.cpp +// +// The sound panel widget for RDAirPlay +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsound_panel.cpp,v 1.62.6.13.2.3 2014/05/20 22:39:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsignalmapper.h> +#include <rddb.h> +#include <rdlog_line.h> +#include <rdsound_panel.h> +#include <rdbutton_dialog.h> +#include <rdmacro.h> +#include <rdcut.h> +#include <rdedit_panel_name.h> +#include <rdescape_string.h> +#include <rdconf.h> + +RDSoundPanel::RDSoundPanel(int cols,int rows,int station_panels, + int user_panels,bool flash, + const QString &label_template,bool extended, + RDEventPlayer *player,RDRipc *ripc,RDCae *cae, + RDStation *station,RDCartDialog *cart_dialog, + QWidget *parent,const char *name) + : QWidget(parent,name) +{ + panel_playmode_box=NULL; + panel_button_columns=cols; + panel_button_rows=rows; + panel_cue_port=-1; + if(extended) { + panel_tablename="EXTENDED_PANELS"; + panel_name_tablename="EXTENDED_PANEL_NAMES"; + } + else { + panel_tablename="PANELS"; + panel_name_tablename="PANEL_NAMES"; + } + panel_label_template=label_template; + + panel_type=RDAirPlayConf::StationPanel; + panel_number=0; + panel_setup_mode=false; + panel_reset_mode=false; + panel_parent=parent; + panel_cae=cae; + panel_user=NULL; + panel_ripc=ripc; + panel_station=station; + panel_station_panels=station_panels; + panel_user_panels=user_panels; + panel_event_player=player; + panel_action_mode=RDAirPlayConf::Normal; + for(int i=0;i<RD_MAX_STREAMS;i++) { + panel_active_buttons[i]=NULL; + } + panel_flash=flash; + panel_flash_count=0; + panel_flash_state=false; + panel_config_panels=false; + panel_pause_enabled=false; + for(unsigned i=0;i<PANEL_MAX_OUTPUTS;i++) { + panel_card[i]=-1; + panel_port[i]=-1; + } + panel_cart_dialog=cart_dialog; + for(int i=0;i<PANEL_MAX_OUTPUTS;i++) { + panel_timescaling_supported[i]=false; + } + panel_onair_flag=false; + + // + // Create Fonts + // + QFont button_font=QFont("Helvetica",14,QFont::Bold); + button_font.setPixelSize(14); + + // + // Load Buttons + // + panel_mapper=new QSignalMapper(this,"panel_mapper"); + connect(panel_mapper,SIGNAL(mapped(int)),this,SLOT(buttonMapperData(int))); + + LoadPanels(); + + // + // Panel Selector + // + panel_selector_box=new RDComboBox(this,"panel_selector_box"); + panel_selector_box->setFont(button_font); + panel_selector_box->addIgnoredKey(Qt::Key_Space); + panel_selector_box-> + setGeometry((15+PANEL_BUTTON_SIZE_X)*(panel_button_columns-5), + (15+PANEL_BUTTON_SIZE_Y)*panel_button_rows, + 2*PANEL_BUTTON_SIZE_X+15,50); + connect(panel_selector_box,SIGNAL(activated(int)), + this,SLOT(panelActivatedData(int))); + connect(panel_selector_box,SIGNAL(setupClicked()), + this,SLOT(panelSetupData())); + + if(panel_station_panels>0) { + panel_number=0; + panel_type=RDAirPlayConf::StationPanel; + panel_buttons[0]->show(); + } + else { + if(panel_user_panels>0) { + panel_number=0; + panel_type=RDAirPlayConf::UserPanel; + panel_buttons[0]->show(); + } + else { + setDisabled(true); + } + } + + // + // Play Mode Box + // + panel_playmode_box=new QComboBox(this,"panel_playmode_box"); + panel_playmode_box->setFont(button_font); + panel_playmode_box-> + setGeometry((15+PANEL_BUTTON_SIZE_X)*(panel_button_columns-3)-5, + (15+PANEL_BUTTON_SIZE_Y)*panel_button_rows, + PANEL_BUTTON_SIZE_X+10,50); + connect(panel_playmode_box,SIGNAL(activated(int)), + this,SLOT(playmodeActivatedData(int))); + panel_playmode_box->insertItem(tr("Play All")); + panel_playmode_box->insertItem(tr("Play Hook")); + + // + // Reset Button + // + panel_reset_button=new RDPushButton(this,"reset_button"); + panel_reset_button-> + setGeometry((15+PANEL_BUTTON_SIZE_X)*(panel_button_columns-2), + (15+PANEL_BUTTON_SIZE_Y)*panel_button_rows, + PANEL_BUTTON_SIZE_X,50); + panel_reset_button->setFont(button_font); + panel_reset_button->setText(tr("Reset")); + panel_reset_button->setFlashColor(QColor(RDPANEL_RESET_FLASH_COLOR)); + panel_reset_button->setFocusPolicy(QWidget::NoFocus); + connect(panel_reset_button,SIGNAL(clicked()),this,SLOT(resetClickedData())); + + // + // All Button + // + panel_all_button=new RDPushButton(this,"all_button"); + panel_all_button-> + setGeometry((15+PANEL_BUTTON_SIZE_X)*(panel_button_columns-1), + (15+PANEL_BUTTON_SIZE_Y)*panel_button_rows, + PANEL_BUTTON_SIZE_X,50); + panel_all_button->setFont(button_font); + panel_all_button->setText(tr("All")); + panel_all_button->setFlashColor(QColor(RDPANEL_RESET_FLASH_COLOR)); + panel_all_button->setFocusPolicy(QWidget::NoFocus); + panel_all_button->hide(); + connect(panel_all_button,SIGNAL(clicked()),this,SLOT(allClickedData())); + + // + // Setup Button + // + panel_setup_button=new RDPushButton(this,"setup_button"); + panel_setup_button-> + setGeometry((15+PANEL_BUTTON_SIZE_X)*(panel_button_columns-1), + (15+PANEL_BUTTON_SIZE_Y)*panel_button_rows, + PANEL_BUTTON_SIZE_X,50); + panel_setup_button->setFont(button_font); + panel_setup_button->setText(tr("Setup")); + panel_setup_button->setFlashColor(QColor(RDPANEL_SETUP_FLASH_COLOR)); + panel_setup_button->setFocusPolicy(QWidget::NoFocus); + connect(panel_setup_button,SIGNAL(clicked()),this,SLOT(setupClickedData())); + + // + // Button Dialog Box + // + panel_button_dialog= + new RDButtonDialog(panel_station->name(),panel_label_template, + panel_cart_dialog,panel_svcname,this, + "panel_button_dialog"); + + // + // CAE Setup + // + connect(panel_cae,SIGNAL(timescalingSupported(int,bool)), + this,SLOT(timescalingSupportedData(int,bool))); + + // + // RIPC Setup + // + connect(panel_ripc,SIGNAL(onairFlagChanged(bool)), + this,SLOT(onairFlagChangedData(bool))); + + // + // Load Panel Names + // + + QString sql; + sql=QString("select PANEL_NO,NAME from ")+panel_name_tablename+" where "+ + QString().sprintf("(TYPE=%d)&&",RDAirPlayConf::StationPanel)+ + "(OWNER=\""+RDEscapeString(panel_station->name())+"\") "+ + "order by PANEL_NO"; + RDSqlQuery *q=new RDSqlQuery(sql); + q->first(); + for(int i=0;i<panel_station_panels;i++) { + if(q->isValid()&&(q->value(0).toInt()==i)) { + panel_selector_box-> + insertItem(QString().sprintf("[S:%d] ",i+1)+q->value(1).toString()); + q->next(); + } + else { + panel_selector_box->insertItem(QString().sprintf("[S:%d] Panel S:%d", + i+1,i+1)); + } + } + delete q; + for(int i=0;i<panel_user_panels;i++) { + panel_selector_box->insertItem(QString().sprintf("[U:%d] Panel U:%d", + i+1,i+1)); + } + panel_selector_box->setFocus(); + + panel_scan_timer=new QTimer(this); + connect(panel_scan_timer,SIGNAL(timeout()),this,SLOT(scanPanelData())); + panel_scan_timer->start(PANEL_SCAN_INTERVAL); +} + + +RDSoundPanel::~RDSoundPanel() +{ + for(unsigned i=0;i<panel_buttons.size();i++) { + delete panel_buttons[i]; + } +} + + +QSize RDSoundPanel::sizeHint() const +{ + return QSize(panel_button_columns*(PANEL_BUTTON_SIZE_X+15), + panel_button_rows*(PANEL_BUTTON_SIZE_Y+15)+50); +} + + +QSizePolicy RDSoundPanel::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int RDSoundPanel::card(int outnum) const +{ + return panel_card[outnum]; +} + + +void RDSoundPanel::setCard(int outnum,int card) +{ + panel_card[outnum]=card; + panel_cae->requestTimescale(card); +} + + +int RDSoundPanel::port(int outnum) const +{ + return panel_port[outnum]; +} + + +void RDSoundPanel::setPort(int outnum,int port) +{ + panel_port[outnum]=port; +} + + +QString RDSoundPanel::outputText(int outnum) const +{ + return panel_output_text[outnum]; +} + + +void RDSoundPanel::setOutputText(int outnum,const QString &text) +{ + panel_output_text[outnum]=text; +} + + +void RDSoundPanel::setRmls(int outnum,const QString &start_rml, + const QString &stop_rml) +{ + panel_start_rml[outnum]=start_rml; + panel_stop_rml[outnum]=stop_rml; +} + + +void RDSoundPanel::setLogName(const QString &logname) +{ + panel_logname=logname; +} + + +void RDSoundPanel::setSvcName(const QString &svcname) +{ + panel_svcname=svcname; + panel_svcname.replace(" ","_"); +} + + +void RDSoundPanel::setLogfile(QString filename) +{ + panel_logfile=filename; +} + + +void RDSoundPanel::play(RDAirPlayConf::PanelType type,int panel, + int row, int col,RDLogLine::StartSource src,int mport, + bool pause_when_finished) +{ + PlayButton(type,panel,row,col,src,panel_playmode_box->currentItem()==1, + mport,pause_when_finished); +} + + +bool RDSoundPanel::pause(RDAirPlayConf::PanelType type,int panel, + int row,int col,int mport) +{ + if(panel_pause_enabled) { + PauseButton(type,panel,row,col,mport); + return true; + } + return false; +} + + +void RDSoundPanel::stop(RDAirPlayConf::PanelType type,int panel, + int row,int col, + int mport,bool pause_when_finished,int fade_out) +{ + StopButton(type,panel,row,col,mport,pause_when_finished,fade_out); +} + + +void RDSoundPanel::channelStop(int mport) +{ + RDPanelButton *button=NULL; + RDPlayDeck *deck=NULL; + for(unsigned i=0;i<RD_MAX_STREAMS;i++) { + if((button=panel_active_buttons[i])!=NULL) { + if(button->outputText().toInt()==(mport+1)) { + if((deck=button->playDeck())!=NULL) { + if(deck->state()==RDPlayDeck::Playing) { + deck->stop(); + } + } + } + } + } +} + + +void RDSoundPanel::setText(RDAirPlayConf::PanelType type,int panel,int row, + int col,const QString &str) +{ + RDPanelButton *button= + panel_buttons[PanelOffset(type,panel)]->panelButton(row,col); + button->setText(str); + SaveButton(type,panel,row,col); +} + + +void RDSoundPanel::setColor(RDAirPlayConf::PanelType type,int panel,int row, + int col,const QColor &color) +{ + RDPanelButton *button= + panel_buttons[PanelOffset(type,panel)]->panelButton(row,col); + button->setDefaultColor(color); + SaveButton(type,panel,row,col); +} + + +void RDSoundPanel::duckVolume(RDAirPlayConf::PanelType type,int panel,int row,int col, + int level,int fade,int mport) +{ + int edit_mport=mport; + if (edit_mport==0) { + edit_mport=-1; + } + for(int i=0;i<panel_button_columns;i++) { + for(int j=0;j<panel_button_rows;j++) { + RDPlayDeck *deck= + panel_buttons[PanelOffset(type,panel)]->panelButton(j,i)->playDeck(); + if((row==j || row==-1) && (col==i || col==-1)) { + if(mport==-1) { + panel_buttons[PanelOffset(type,panel)]->panelButton(j,i)->setDuckVolume(level); + } + if(deck!=NULL) { + if(edit_mport==-1 || + edit_mport==panel_buttons[PanelOffset(type,panel)]->panelButton(j,i)-> + outputText().toInt()) { + deck->duckVolume(level,fade); + } + } + } + } + } +} + + +RDAirPlayConf::ActionMode RDSoundPanel::actionMode() const +{ + return panel_action_mode; +} + + +void RDSoundPanel::setActionMode(RDAirPlayConf::ActionMode mode) +{ + if(panel_setup_mode) { + return; + } + switch(mode) { + case RDAirPlayConf::CopyFrom: + mode=RDAirPlayConf::CopyFrom; + break; + + case RDAirPlayConf::CopyTo: + mode=RDAirPlayConf::CopyTo; + break; + + case RDAirPlayConf::AddTo: + mode=RDAirPlayConf::AddTo; + break; + + case RDAirPlayConf::DeleteFrom: + mode=RDAirPlayConf::DeleteFrom; + break; + + default: + mode=RDAirPlayConf::Normal; + break; + } + if(mode!=panel_action_mode) { + panel_action_mode=mode; + panel_setup_button->setEnabled(panel_action_mode==RDAirPlayConf::Normal); + for(unsigned i=0;i<panel_buttons.size();i++) { + if(i<(unsigned)panel_station_panels && + (!panel_config_panels) && + (mode==RDAirPlayConf::AddTo || mode==RDAirPlayConf::CopyTo || mode==RDAirPlayConf::DeleteFrom)) { + panel_buttons[i]->setActionMode(RDAirPlayConf::Normal); + } + else { + panel_buttons[i]->setActionMode(panel_action_mode); + } + } + } +} + + +bool RDSoundPanel::pauseEnabled() const +{ + return panel_pause_enabled; +} + + +void RDSoundPanel::setPauseEnabled(bool state) +{ + if(state) { + panel_reset_button->show(); + } + else { + panel_reset_button->hide(); + } + panel_pause_enabled=state; +} + + +int RDSoundPanel::currentNumber() const +{ + return panel_number; +} + + +RDAirPlayConf::PanelType RDSoundPanel::currentType() const +{ + return panel_type; +} + + +void RDSoundPanel::setButton(RDAirPlayConf::PanelType type,int panel, + int row,int col,unsigned cartnum, + const QString &title) +{ + QString str; + + RDPanelButton *button= + panel_buttons[PanelOffset(type,panel)]->panelButton(row,col); + if(button->playDeck()!=NULL) { + return; + } + button->clear(); + if(cartnum>0) { + button->setCart(cartnum); + RDCart *cart=new RDCart(cartnum); + if(cart->exists()) { + if(title.isEmpty()) { + button-> + setText(RDLogLine::resolveWildcards(cartnum,panel_label_template)); + } + else { + button->setText(title); + } + button->setLength(false,cart->forcedLength()); + if(cart->averageHookLength()>0) { + button->setLength(true,cart->averageHookLength()); + } + else { + button->setLength(true,cart->forcedLength()); + } + button->setHookMode(panel_playmode_box->currentItem()==1); + switch(cart->type()) { + case RDCart::Audio: + if(button->length(button->hookMode())==0) { + button->setActiveLength(-1); + } + else { + button->setActiveLength(button->length(button->hookMode())); + } + break; + + case RDCart::Macro: + button->setActiveLength(cart->forcedLength()); + break; + + case RDCart::All: + break; + } + } + else { + if(title.isEmpty()) { + str=QString(tr("Cart")); + button->setText(str+QString().sprintf(" %06u",cartnum)); + } + else { + button->setText(title); + } + } + delete cart; + } + SaveButton(type,panel,row,col); +} + + +void RDSoundPanel::acceptCartDrop(int row,int col,unsigned cartnum, + const QColor &color,const QString &title) +{ + setButton(panel_type,panel_number,row,col,cartnum,title); + if(color.isValid()&&(color.name()!="#000000")) { + setColor(panel_type,panel_number,row,col,color); + } +} + + +void RDSoundPanel::changeUser() +{ + if(panel_user!=NULL) { + delete panel_user; + } + panel_user=new RDUser(panel_ripc->user()); + panel_config_panels=panel_user->configPanels(); + LoadPanels(); + panel_buttons[PanelOffset(panel_type,panel_number)]->show(); + + // + // Remove Old Panel Names + // + int current_item=panel_selector_box->currentItem(); + for(int i=0;i<panel_user_panels;i++) { + panel_selector_box->removeItem(panel_station_panels); + } + + // + // Load New Panel Names + // + QString sql; + sql=QString("select PANEL_NO,NAME from ")+panel_name_tablename+" where "+ + QString().sprintf("(TYPE=%d)&&",RDAirPlayConf::UserPanel)+ + "(OWNER=\""+RDEscapeString(panel_user->name())+"\") "+ + "order by PANEL_NO"; + RDSqlQuery *q=new RDSqlQuery(sql); + q->first(); + for(int i=0;i<panel_user_panels;i++) { + if(q->isValid()&&(q->value(0).toInt()==i)) { + panel_selector_box-> + insertItem(QString().sprintf("[U:%d] ",i+1)+q->value(1).toString()); + q->next(); + } + else { + panel_selector_box->insertItem(QString().sprintf("[U:%d] Panel U:%d", + i+1,i+1)); + } + } + delete q; + panel_selector_box->setCurrentItem(current_item); +} + + +void RDSoundPanel::tickClock() +{ + emit tick(); + if(panel_flash) { + if(panel_flash_count++>1) { + emit buttonFlash(panel_flash_state); + panel_flash_state=!panel_flash_state; + panel_flash_count=0; + } + } +} + + +void RDSoundPanel::panelActivatedData(int n) +{ + panel_buttons[PanelOffset(panel_type,panel_number)]->hide(); + if(n<panel_station_panels) { + panel_type=RDAirPlayConf::StationPanel; + panel_number=n; + } + else { + panel_type=RDAirPlayConf::UserPanel; + panel_number=n-panel_station_panels; + } + panel_buttons[PanelOffset(panel_type,panel_number)]->show(); +} + + +void RDSoundPanel::resetClickedData() +{ + if(panel_reset_mode) { + panel_reset_mode=false; + panel_reset_button->setFlashingEnabled(false); + panel_all_button->hide(); + panel_setup_button->show(); + } + else { + panel_reset_mode=true; + panel_reset_button->setFlashingEnabled(true); + panel_setup_button->hide(); + panel_all_button->show(); + } +} + + +void RDSoundPanel::allClickedData() +{ + StopButton(panel_type,panel_number,-1,-1); +} + + +void RDSoundPanel::playmodeActivatedData(int n) +{ + LoadPanel(panel_type,panel_number); +} + + +void RDSoundPanel::setupClickedData() +{ + if(panel_setup_mode) { + panel_setup_mode=false; + panel_setup_button->setFlashingEnabled(false); + panel_reset_button->setEnabled(true); + panel_playmode_box->setEnabled(true); + } + else { + panel_setup_mode=true; + panel_setup_button->setFlashingEnabled(true); + panel_reset_button->setDisabled(true); + panel_playmode_box->setDisabled(true); + } + if(panel_station->enableDragdrop()&&(panel_station->enforcePanelSetup())) { + for(unsigned i=0;i<panel_buttons.size();i++) { + if(panel_buttons[i]!=NULL) { + panel_buttons[i]->setAcceptDrops(panel_setup_mode); + } + } + } + panel_selector_box->setSetupMode(panel_setup_mode); +} + + +void RDSoundPanel::buttonMapperData(int id) +{ + int row=id/panel_button_columns; + int col=id-row*panel_button_columns; + unsigned cartnum; + + switch(panel_action_mode) { + case RDAirPlayConf::CopyFrom: + if((cartnum=panel_buttons[PanelOffset(panel_type,panel_number)]-> + panelButton(row,col)->cart())>0) { + emit selectClicked(cartnum,0,0); + } + break; + + case RDAirPlayConf::CopyTo: + if(panel_buttons[PanelOffset(panel_type,panel_number)]-> + panelButton(row,col)->playDeck()==NULL + && ((panel_type==RDAirPlayConf::UserPanel) || + panel_config_panels)) { + emit selectClicked(0,row,col); + } + break; + + case RDAirPlayConf::AddTo: + if(panel_buttons[PanelOffset(panel_type,panel_number)]-> + panelButton(row,col)->playDeck()==NULL + && ((panel_type==RDAirPlayConf::UserPanel) || + panel_config_panels)) { + emit selectClicked(0,row,col); + } + break; + + case RDAirPlayConf::DeleteFrom: + if(panel_buttons[PanelOffset(panel_type,panel_number)]-> + panelButton(row,col)->playDeck()==NULL + && ((panel_type==RDAirPlayConf::UserPanel) || + panel_config_panels)) { + emit selectClicked(0,row,col); + } + break; + + default: + if(panel_setup_mode) { + if((panel_type==RDAirPlayConf::StationPanel)&& + (!panel_config_panels)) { + ClearReset(); + return; + } + if(panel_button_dialog-> + exec(panel_buttons[PanelOffset(panel_type,panel_number)]-> + panelButton(row,col),panel_playmode_box->currentItem()==1, + panel_user->name(),panel_user->password()) + ==0) { + SaveButton(panel_type,panel_number,row,col); + } + } + else { + RDPanelButton *button= + panel_buttons[PanelOffset(panel_type,panel_number)]-> + panelButton(row,col); + RDPlayDeck *deck=button->playDeck(); + if(panel_reset_mode) { + StopButton(panel_type,panel_number,row,col); + } + else { + if(deck==NULL) { + PlayButton(panel_type,panel_number,row,col, + RDLogLine::StartManual, + panel_playmode_box->currentItem()==1); + } + else { + if(panel_pause_enabled) { + if(deck->state()!=RDPlayDeck::Paused) { + PauseButton(panel_type,panel_number,row,col); + } + else { + PlayButton(panel_type,panel_number,row,col, + RDLogLine::StartManual,button->hookMode()); + } + } + else { + StopButton(panel_type,panel_number,row,col); + } + } + } + } + } + ClearReset(); +} + + +void RDSoundPanel::stateChangedData(int id,RDPlayDeck::State state) +{ + switch(state) { + case RDPlayDeck::Playing: + Playing(id); + break; + + case RDPlayDeck::Stopped: + case RDPlayDeck::Finished: + Stopped(id); + break; + + case RDPlayDeck::Paused: + Paused(id); + break; + + default: + break; + } +} + + +void RDSoundPanel::hookEndData(int id) +{ + RDPanelButton *button=panel_active_buttons[id]; + if(!button->hookMode()) { + return; + } + RDPlayDeck *deck=button->playDeck(); + if(deck!=NULL) { + switch(deck->state()) { + case RDPlayDeck::Playing: + case RDPlayDeck::Paused: + StopButton(id); + break; + + default: + break; + } + } +} + + +void RDSoundPanel::timescalingSupportedData(int card,bool state) +{ + for(unsigned i=0;i<PANEL_MAX_OUTPUTS;i++) { + if(card==panel_card[i]) { + panel_timescaling_supported[i]=state; + } + } +} + + +void RDSoundPanel::panelSetupData() +{ + if(panel_user->configPanels()||(panel_type==RDAirPlayConf::UserPanel)) { + QString sql; + RDSqlQuery *q; + int cutpt=panel_selector_box->currentText().find(" "); + if(panel_selector_box->currentText().left(5)==tr("Panel")) { + cutpt=-1; + } + QString panel_name=panel_selector_box->currentText(). + right(panel_selector_box->currentText().length()-cutpt-1); + RDEditPanelName *edn=new RDEditPanelName(&panel_name); + if(edn->exec()==0) { + panel_selector_box-> + setCurrentText("["+PanelTag(panel_selector_box->currentItem())+"] "+ + panel_name); + sql=QString("delete from ")+panel_name_tablename+" where "+ + QString().sprintf("(TYPE=%d)&&",panel_type)+ + "(OWNER=\""+RDEscapeString(PanelOwner(panel_type))+"\")&&"+ + QString().sprintf("(PANEL_NO=%d)",panel_number); + q=new RDSqlQuery(sql); + delete q; + sql=QString("insert into ")+panel_name_tablename+" set "+ + QString().sprintf("TYPE=%d,",panel_type)+ + "OWNER=\""+RDEscapeString(PanelOwner(panel_type))+"\","+ + QString().sprintf("PANEL_NO=%d,",panel_number)+ + "NAME=\""+RDEscapeString(panel_name)+"\""; + q=new RDSqlQuery(sql); + delete q; + } + delete edn; + } +} + + +void RDSoundPanel::onairFlagChangedData(bool state) +{ + panel_onair_flag=state; +} + + +void RDSoundPanel::scanPanelData() +{ + LoadPanel(panel_type,panel_number); +} + + +void RDSoundPanel::PlayButton(RDAirPlayConf::PanelType type,int panel, + int row,int col,RDLogLine::StartSource src,bool hookmode, + int mport,bool pause_when_finished) +{ + int edit_row=row; + int edit_col=col; + + for(int i=0;i<panel_button_columns;i++) { + for(int j=0;j<panel_button_rows;j++) { + if(panel_buttons[PanelOffset(type,panel)]-> + panelButton(j,i)->cart()>0 && + panel_buttons[PanelOffset(type,panel)]-> + panelButton(j,i)->state()==false) { + if(edit_col==-1 || col==i) { + edit_col=i; + if(edit_row==-1) { + edit_row=j; + } + } + } + } + } + if(edit_row==-1 || edit_col==-1) { + return; + } + + RDPanelButton *button= + panel_buttons[PanelOffset(type,panel)]->panelButton(edit_row,edit_col); + RDPlayDeck *deck=button->playDeck(); + if(deck!=NULL) { + deck->play(deck->currentPosition()); + if(button->hookMode()) { + button->setStartTime(QTime::currentTime(). + addMSecs(panel_station->timeOffset()). + addMSecs(-deck->currentPosition()+ + deck->cut()->hookStartPoint())); + } + else { + button->setStartTime(QTime::currentTime(). + addMSecs(panel_station->timeOffset()). + addMSecs(-deck->currentPosition())); + } + return; + } + + int cartnum=0; + + if((cartnum=button->cart())==0) { + LogLine(QString().sprintf("Tried to start empty button. Row=%d, Col=%d", + edit_row,edit_col)); + return; + } + RDCart *cart=new RDCart(cartnum); + if(!cart->exists()) { + delete cart; + LogLine(QString().sprintf("Tried to start non-existent cart: %u",cartnum)); + return; + } + button->setStartSource(src); + if(panel_pause_enabled) { + button->setPauseWhenFinished(pause_when_finished); + } + else { + button->setPauseWhenFinished(false); + } + switch(cart->type()) { + case RDCart::Audio: + PlayAudio(button,cart,hookmode,mport); + break; + + case RDCart::Macro: + PlayMacro(button,cart); + break; + + default: + break; + } + delete cart; +} + + +bool RDSoundPanel::PlayAudio(RDPanelButton *button,RDCart *cart,bool hookmode,int mport) +{ + RDLogLine logline; + + bool timescale=false; + int button_deck=GetFreeButtonDeck(); + if(button_deck<0) { + LogLine(QString(). + sprintf("No button deck available, playout aborted. Cart=%u", + cart->number())); + return false; + } + if(mport<=0 || mport>PANEL_MAX_OUTPUTS) { + button->setOutput(GetFreeOutput()); + } + else { + button->setOutput(mport-1); + } + button->setOutputText(panel_output_text[button->output()]); + button->setHookMode(hookmode); + button->setPlayDeck(new RDPlayDeck(panel_cae,button_deck,this)); + button->playDeck()->setCard(panel_card[button->output()]); + button->playDeck()->setPort(panel_port[button->output()]); + button->playDeck()->duckVolume(button->duckVolume(),0); + if(panel_timescaling_supported[panel_card[button->output()]]&& + cart->enforceLength()) { + timescale=true; + } + logline.loadCart(cart->number(),RDLogLine::Play,0,timescale); + if(!button->playDeck()->setCart(&logline,true)) { + delete button->playDeck(); + button->setPlayDeck(NULL); + LogLine(QString(). + sprintf("No CAE stream available, playout aborted. Cart=%u", + cart->number())); + return false; + } + button->setCutName(logline.cutName()); + panel_active_buttons[button_deck]=button; + + // + // Set Mappings + // + connect(button->playDeck(),SIGNAL(stateChanged(int,RDPlayDeck::State)), + this,SLOT(stateChangedData(int,RDPlayDeck::State))); + connect(button->playDeck(),SIGNAL(hookEnd(int)), + this,SLOT(hookEndData(int))); + connect(this,SIGNAL(tick()),button,SLOT(tickClock())); + + // + // Calculate Start Parameters for Hook Playout + // + int start_pos=0; + int segue_start=-1; + int segue_end=-1; + if(hookmode&&(logline.hookStartPoint()>=0)&&(logline.hookEndPoint()>=0)) { + start_pos=logline.hookStartPoint()-logline.startPoint(); + segue_start=logline.hookEndPoint()-logline.startPoint(); + segue_end=logline.hookEndPoint()-logline.startPoint(); + } + + // + // Start Playout + // + button-> + setStartTime(QTime::currentTime().addMSecs(panel_station->timeOffset())); + if(hookmode&&(button->playDeck()->cut()->hookStartPoint()>=0)) { + button->setActiveLength(button->playDeck()->cut()->hookEndPoint()- + button->playDeck()->cut()->hookStartPoint()); + } + else { + if(timescale) { + button->setActiveLength(cart->forcedLength()); + } + else { + button->setActiveLength(button->playDeck()->cut()->length()); + } + } + button->playDeck()->play(start_pos,segue_start,segue_end); + panel_event_player-> + exec(logline.resolveWildcards(panel_start_rml[button->output()])); + emit channelStarted(button->output(),button->playDeck()->card(), + button->playDeck()->port()); + return true; +} + + +void RDSoundPanel::PlayMacro(RDPanelButton *button,RDCart *cart) +{ + RDMacro rml; + rml.setRole(RDMacro::Cmd); + rml.setAddress(panel_station->address()); + rml.setEchoRequested(false); + rml.setCommand(RDMacro::EX); + rml.setArgQuantity(1); + rml.setArg(0,cart->number()); + panel_ripc->sendRml(&rml); + if(!panel_svcname.isEmpty()) { + LogTrafficMacro(button); + } + if(button->pauseWhenFinished() && panel_pause_enabled) { + button->setState(true); + button->resetCounter(); + button->setColor(RDPANEL_PAUSED_BACKGROUND_COLOR); + } +} + + +void RDSoundPanel::PauseButton(RDAirPlayConf::PanelType type,int panel, + int row,int col,int mport) +{ + for(int i=0;i<panel_button_columns;i++) { + for(int j=0;j<panel_button_rows;j++) { + RDPlayDeck *deck= + panel_buttons[PanelOffset(type,panel)]->panelButton(j,i)->playDeck(); + if(deck!=NULL && (row==j || row==-1) && (col==i || col==-1)) { + if(mport==-1 || + mport==panel_buttons[PanelOffset(type,panel)]-> + panelButton(j,i)->outputText().toInt()) { + deck->pause(); + + panel_buttons[PanelOffset(type,panel)]->panelButton(j,i)-> + setStartTime(QTime()); + } + } + } + } +} + + +void RDSoundPanel::StopButton(RDAirPlayConf::PanelType type,int panel, + int row,int col,int mport, + bool pause_when_finished,int fade_out) +{ + int edit_mport=mport; + if (edit_mport==0) { + edit_mport=-1; + } + for(int i=0;i<panel_button_columns;i++) { + for(int j=0;j<panel_button_rows;j++) { + RDPlayDeck *deck= + panel_buttons[PanelOffset(type,panel)]->panelButton(j,i)->playDeck(); + if((row==j || row==-1) && (col==i || col==-1)) { + if(deck!=NULL) { + if(edit_mport==-1 || + edit_mport==panel_buttons[PanelOffset(type,panel)]->panelButton(j,i)-> + outputText().toInt()) { + if(panel_pause_enabled) { + panel_buttons[PanelOffset(type,panel)]->panelButton(j,i)-> + setPauseWhenFinished(pause_when_finished); + } + else { + panel_buttons[PanelOffset(type,panel)]->panelButton(j,i)-> + setPauseWhenFinished(false); + } + switch(deck->state()) { + case RDPlayDeck::Playing: + deck->stop(fade_out,RD_FADE_DEPTH); + break; + + case RDPlayDeck::Paused: + deck->clear(); + break; + + default: + deck->clear(); + break; + } + } + } + else { + if(!pause_when_finished && panel_pause_enabled) { + panel_buttons[PanelOffset(type,panel)]->panelButton(j,i)->setState(false); + panel_buttons[PanelOffset(type,panel)]->panelButton(j,i)-> + setPauseWhenFinished(false); + panel_buttons[PanelOffset(type,panel)]->panelButton(j,i)->reset(); + } + } + } + } + } + panel_reset_mode=false; + panel_reset_button->setFlashingEnabled(false); + panel_all_button->hide(); + panel_setup_button->show(); +} + + +void RDSoundPanel::StopButton(int id) +{ + RDPlayDeck *deck=panel_active_buttons[id]->playDeck(); + StopButton(deck); +} + + +void RDSoundPanel::StopButton(RDPlayDeck *deck) +{ + if(deck!=NULL) { + switch(deck->state()) { + case RDPlayDeck::Playing: + deck->stop(); + break; + + case RDPlayDeck::Paused: + deck->clear(); + break; + + default: + break; + } + } +} + + +void RDSoundPanel::LoadPanels() +{ + for(unsigned i=0;i<panel_buttons.size();i++) { + delete panel_buttons[i]; + } + panel_buttons.clear(); + + // + // Load Buttons + // + for(int i=0;i<panel_station_panels;i++) { + panel_buttons.push_back(new RDButtonPanel(panel_type,i,panel_button_columns, + panel_button_rows, + panel_station,panel_flash,this)); + for(int j=0;j<panel_button_rows;j++) { + for(int k=0;k<panel_button_columns;k++) { + connect(panel_buttons.back()->panelButton(j,k),SIGNAL(clicked()), + panel_mapper,SLOT(map())); + panel_mapper->setMapping(panel_buttons.back()->panelButton(j,k), + j*panel_button_columns+k); + } + } + LoadPanel(RDAirPlayConf::StationPanel,i); + panel_buttons.back()->setAllowDrags(panel_station->enableDragdrop()); + } + for(int i=0;i<panel_user_panels;i++) { + panel_buttons.push_back(new RDButtonPanel(panel_type,i,panel_button_columns, + panel_button_rows, + panel_station,panel_flash,this)); + for(int j=0;j<panel_button_rows;j++) { + for(int k=0;k<panel_button_columns;k++) { + connect(panel_buttons.back()->panelButton(j,k),SIGNAL(clicked()), + panel_mapper,SLOT(map())); + panel_mapper->setMapping(panel_buttons.back()->panelButton(j,k), + j*panel_button_columns+k); + } + } + panel_buttons.back()->setAllowDrags(panel_station->enableDragdrop()); + LoadPanel(RDAirPlayConf::UserPanel,i); + } +} + + +void RDSoundPanel::LoadPanel(RDAirPlayConf::PanelType type,int panel) +{ + QString owner; + int offset=0; + + switch(type) { + case RDAirPlayConf::UserPanel: + if(panel_user==NULL) { + return; + } + owner=panel_user->name(); + offset=panel_station_panels+panel; + break; + + case RDAirPlayConf::StationPanel: + owner=panel_station->name(); + offset=panel; + break; + } + + QString sql=QString("select ")+panel_tablename+".ROW_NO,"+ + panel_tablename+".COLUMN_NO,"+ + panel_tablename+".LABEL,"+ + panel_tablename+".CART,"+ + panel_tablename+".DEFAULT_COLOR,"+ + "CART.FORCED_LENGTH,CART.AVERAGE_HOOK_LENGTH,CART.TYPE from "+ + panel_tablename+" left join CART on "+panel_tablename+".CART=CART.NUMBER "+ + "where "+panel_tablename+QString().sprintf(".TYPE=%d && ",type)+ + panel_tablename+".OWNER=\""+RDEscapeString(owner)+"\" && "+ + panel_tablename+QString().sprintf(".PANEL_NO=%d ",panel)+ + "order by "+panel_tablename+".COLUMN_NO,"+panel_tablename+".ROW_NO"; + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + if(panel_buttons[offset]->panelButton(q->value(0).toInt(), + q->value(1).toInt())->playDeck()==NULL) { + panel_buttons[offset]-> + panelButton(q->value(0).toInt(),q->value(1).toInt())-> + setText(q->value(2).toString()); + panel_buttons[offset]-> + panelButton(q->value(0).toInt(),q->value(1).toInt())-> + setCart(q->value(3).toInt()); + panel_buttons[offset]-> + panelButton(q->value(0).toInt(),q->value(1).toInt())-> + setLength(false,q->value(5).toInt()); + panel_buttons[offset]-> + panelButton(q->value(0).toInt(),q->value(1).toInt())-> + setLength(true,q->value(6).toInt()); + if((panel_playmode_box!=NULL)&&(panel_playmode_box->currentItem()==1)&& + (q->value(6).toUInt()>0)) { + panel_buttons[offset]-> + panelButton(q->value(0).toInt(),q->value(1).toInt())-> + setActiveLength(q->value(6).toInt()); + } + else { + if(q->value(7).toInt()==RDCart::Macro) { + panel_buttons[offset]-> + panelButton(q->value(0).toInt(),q->value(1).toInt())-> + setActiveLength(q->value(5).toInt()); + } + else { + if(q->value(5).toInt()>0) { + panel_buttons[offset]-> + panelButton(q->value(0).toInt(),q->value(1).toInt())-> + setActiveLength(q->value(5).toInt()); + } + else { + panel_buttons[offset]-> + panelButton(q->value(0).toInt(),q->value(1).toInt())-> + setActiveLength(-1); + } + } + } + if(q->value(4).toString().isEmpty()) { + panel_buttons[offset]-> + panelButton(q->value(0).toInt(),q->value(1).toInt())-> + setColor(palette().active().background()); + panel_buttons[offset]-> + panelButton(q->value(0).toInt(),q->value(1).toInt())-> + setDefaultColor(palette().active().background()); + } + else { + panel_buttons[offset]-> + panelButton(q->value(0).toInt(),q->value(1).toInt())-> + setColor(QColor(q->value(4).toString())); + panel_buttons[offset]-> + panelButton(q->value(0).toInt(),q->value(1).toInt())-> + setDefaultColor(QColor(q->value(4).toString())); + } + } + } + delete q; +} + + +void RDSoundPanel::SaveButton(RDAirPlayConf::PanelType type, + int panel,int row,int col) +{ + QString sql; + QString sql1; + RDSqlQuery *q; + QString owner; + int offset=0; + + switch(type) { + case RDAirPlayConf::UserPanel: + owner=panel_user->name(); + offset=panel_station_panels+panel; + break; + + case RDAirPlayConf::StationPanel: + owner=panel_station->name(); + offset=panel; + break; + } + + // + // Determine if the button exists + // + sql=QString("select LABEL from ")+panel_tablename+" where "+ + QString().sprintf("TYPE=%d && ",type)+ + "OWNER=\""+RDEscapeString(owner)+"\" && "+ + QString().sprintf("PANEL_NO=%d && ",panel)+ + QString().sprintf("ROW_NO=%d && ",row)+ + QString().sprintf("COLUMN_NO=%d",col); + q=new RDSqlQuery(sql); + if(q->size()>0) { + // + // If so, update the record + // + delete q; + sql1=QString("update ")+panel_tablename+" set "+ + "LABEL=\""+RDEscapeString(panel_buttons[offset]->panelButton(row,col)-> + text())+"\","+ + QString().sprintf("CART=%d,", + panel_buttons[PanelOffset(panel_type,panel_number)]-> + panelButton(row,col)->cart())+ + "DEFAULT_COLOR=\""+panel_buttons[offset]->panelButton(row,col)-> + defaultColor().name()+"\" where "+ + QString().sprintf("(TYPE=%d)&&",type)+ + "(OWNER=\""+RDEscapeString(owner)+"\")&&"+ + QString().sprintf("(PANEL_NO=%d)&&",panel)+ + QString().sprintf("(ROW_NO=%d)&&",row)+ + QString().sprintf("(COLUMN_NO=%d)",col); + q=new RDSqlQuery(sql1); + if(q->isActive()) { + delete q; + return; + } + delete q; + } + else { + delete q; + + // + // Otherwise, insert a new one + // + sql1=QString("insert into ")+panel_tablename+ + " (TYPE,OWNER,PANEL_NO,ROW_NO,COLUMN_NO,LABEL,CART,DEFAULT_COLOR) "+ + QString().sprintf("values (%d,",type)+ + "\""+RDEscapeString(owner)+"\","+ + QString().sprintf("%d,%d,%d,",panel,row,col)+ + "\""+RDEscapeString(panel_buttons[offset]-> + panelButton(row,col)->text())+"\","+ + QString().sprintf("%d,", + panel_buttons[PanelOffset(panel_type,panel_number)]-> + panelButton(row,col)->cart())+ + "\""+RDEscapeString(panel_buttons[offset]-> + panelButton(row,col)->defaultColor().name())+"\")"; + q=new RDSqlQuery(sql1); + delete q; + } +} + + +int RDSoundPanel::PanelOffset(RDAirPlayConf::PanelType type,int panel) +{ + switch(type) { + case RDAirPlayConf::StationPanel: + return panel; + break; + + case RDAirPlayConf::UserPanel: + return panel_station_panels+panel; + break; + } + return 0; +} + + +int RDSoundPanel::GetFreeButtonDeck() +{ + for(int i=0;i<RD_MAX_STREAMS;i++) { + if(panel_active_buttons[i]==NULL) { + return i; + } + } + return -1; +} + + +int RDSoundPanel::GetFreeOutput() +{ + bool active=false; + + for(int i=0;i<PANEL_MAX_OUTPUTS;i++) { + active=false; + for(int j=0;j<RD_MAX_STREAMS;j++) { + if((panel_active_buttons[j]!=NULL)&& + (panel_active_buttons[j]->output()==i)) { + active=true; + } + } + if(!active) { + return i; + } + } + return PANEL_MAX_OUTPUTS-1; +} + + +void RDSoundPanel::LogPlayEvent(unsigned cartnum,int cutnum) +{ + RDCut *cut=new RDCut(QString().sprintf("%06u_%03d",cartnum,cutnum)); + cut->logPlayout(); + delete cut; +} + + +void RDSoundPanel::LogTraffic(RDPanelButton *button) +{ + if(panel_svcname.isEmpty()) { + return; + } + + QString sql; + RDSqlQuery *q; + QDateTime datetime(QDate::currentDate(),QTime::currentTime()); + + sql=QString("select CART.TITLE,CART.ARTIST,CART.PUBLISHER,")+ + "CART.COMPOSER,CART.USAGE_CODE,CUTS.ISRC,"+ + "CART.ALBUM,CART.LABEL,CUTS.ISCI,CART.CONDUCTOR,CART.USER_DEFINED," + "CART.SONG_ID from CART left join CUTS "+ + "on CART.NUMBER=CUTS.CART_NUMBER where "+ + "CUTS.CUT_NAME=\""+RDEscapeString(button->cutName())+"\""; + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString("insert into `")+panel_svcname+"_SRT` set "+ + QString().sprintf("LENGTH=%d,",button->startTime(). + msecsTo(datetime.time()))+ + QString().sprintf("CART_NUMBER=%u,",button->cart())+ + "STATION_NAME=\""+RDEscapeString(panel_station->name().utf8())+"\","+ + "EVENT_DATETIME=\""+datetime.toString("yyyy-MM-dd")+" "+ + button->startTime().toString("hh:mm:ss")+"\","+ + QString().sprintf("EVENT_TYPE=%d,",RDAirPlayConf::TrafficStop)+ + QString().sprintf("EVENT_SOURCE=%d,",RDLogLine::SoundPanel)+ + QString().sprintf("PLAY_SOURCE=%d,",RDLogLine::SoundPanel)+ + QString().sprintf("CUT_NUMBER=%d,",button->cutName().right(3).toInt())+ + "TITLE=\""+RDEscapeString(q->value(0).toString().utf8())+"\","+ + "ARTIST=\""+RDEscapeString(q->value(1).toString().utf8())+"\","+ + "PUBLISHER=\""+RDEscapeString(q->value(2).toString().utf8())+"\","+ + "COMPOSER=\""+RDEscapeString(q->value(3).toString().utf8())+"\","+ + QString().sprintf("USAGE_CODE=%d,",q->value(4).toInt())+ + "ISRC=\""+RDEscapeString(q->value(5).toString().utf8())+"\","+ + QString().sprintf("START_SOURCE=%d,",button->startSource())+ + "ALBUM=\""+RDEscapeString(q->value(6).toString().utf8())+"\","+ + "LABEL=\""+RDEscapeString(q->value(7).toString().utf8())+"\","+ + "ISCI=\""+RDEscapeString(q->value(8).toString().utf8())+"\","+ + "CONDUCTOR=\""+RDEscapeString(q->value(9).toString().utf8())+"\","+ + "USER_DEFINED=\""+RDEscapeString(q->value(10).toString().utf8())+"\","+ + "SONG_ID=\""+RDEscapeString(q->value(11).toString().utf8())+"\","+ + "ONAIR_FLAG=\""+RDYesNo(panel_onair_flag)+"\""; + delete q; + q=new RDSqlQuery(sql); + } + delete q; +} + + +void RDSoundPanel::LogTrafficMacro(RDPanelButton *button) +{ + QString sql; + RDSqlQuery *q; + QDateTime datetime(QDate::currentDate(),QTime::currentTime()); + + sql=QString("select TITLE,ARTIST,PUBLISHER,COMPOSER,USAGE_CODE,")+ + "FORCED_LENGTH,ALBUM,LABEL from CART where "+ + QString().sprintf("NUMBER=%u",button->cart()); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString("insert into `")+panel_svcname+"_SRT` set "+ + QString().sprintf("LENGTH=%d,",q->value(5).toUInt())+ + QString().sprintf("CART_NUMBER=%u,",button->cart())+ + "STATION_NAME=\""+RDEscapeString(panel_station->name().utf8())+"\","+ + "EVENT_DATETIME=\""+datetime.toString("yyyy-MM-dd hh:mm:ss")+"\","+ + QString().sprintf("EVENT_TYPE=%d,",RDAirPlayConf::TrafficMacro)+ + QString().sprintf("EVENT_SOURCE=%d,",RDLogLine::SoundPanel)+ + QString().sprintf("PLAY_SOURCE=%d,",RDLogLine::SoundPanel)+ + "TITLE=\""+RDEscapeString(q->value(0).toString().utf8())+"\","+ + "ARTIST=\""+RDEscapeString(q->value(1).toString().utf8())+"\","+ + "PUBLISHER=\""+RDEscapeString(q->value(2).toString().utf8())+"\","+ + "COMPOSER=\""+RDEscapeString(q->value(3).toString().utf8())+"\","+ + QString().sprintf("USAGE_CODE=%d,",q->value(4).toInt())+ + QString().sprintf("START_SOURCE=%d,",button->startSource())+ + "ALBUM=\""+RDEscapeString(q->value(6).toString().utf8())+"\","+ + "LABEL=\""+RDEscapeString(q->value(7).toString().utf8())+"\","+ + "ONAIR_FLAG=\""+RDYesNo(panel_onair_flag)+"\""; + delete q; + q=new RDSqlQuery(sql); + delete q; + } +} + + +void RDSoundPanel::LogLine(QString str) +{ + FILE *file; + + if(panel_logfile.isEmpty()) { + return; + } + + QDateTime current=QDateTime::currentDateTime(); + if((file=fopen(panel_logfile,"a"))==NULL) { + return; + } + fprintf(file,"%02d/%02d/%4d - %02d:%02d:%02d.%03d : RDSoundPanel: %s\n", + current.date().month(), + current.date().day(), + current.date().year(), + current.time().hour(), + current.time().minute(), + current.time().second(), + current.time().msec(), + (const char *)str); + fclose(file); +} + + +void RDSoundPanel::Playing(int id) +{ + if(panel_active_buttons[id]==NULL) { + LogLine(QString().sprintf("Invalid ID=%d in RDSoundPanel::Playing()", + id)); + return; + } + panel_active_buttons[id]->setState(true); + panel_active_buttons[id]->setColor(RDPANEL_PLAY_BACKGROUND_COLOR); + LogPlayEvent(panel_active_buttons[id]->playDeck()->cart()->number(), + panel_active_buttons[id]->playDeck()->cut()->cutNumber()); + LogLine(QString(). + sprintf("Playout started: id=%d cart=%u cut=%d", + id,panel_active_buttons[id]->playDeck()->cart()->number(), + panel_active_buttons[id]->playDeck()->cut()->cutNumber())); +} + + +void RDSoundPanel::Paused(int id) +{ + if(panel_active_buttons[id]==NULL) { + LogLine(QString().sprintf("Invalid ID=%d in RDSoundPanel::Paused()", + id)); + return; + } + panel_active_buttons[id]->setState(true); + panel_active_buttons[id]->setColor(RDPANEL_PAUSED_BACKGROUND_COLOR); + LogLine(QString(). + sprintf("Playout paused: id=%d cart=%u cut=%d", + id,panel_active_buttons[id]->playDeck()->cart()->number(), + panel_active_buttons[id]->playDeck()->cut()->cutNumber())); +} + + +void RDSoundPanel::Stopped(int id) +{ + if(panel_active_buttons[id]==NULL) { + LogLine(QString().sprintf("Invalid ID=%d in RDSoundPanel::Stopped()", + id)); + return; + } + LogTraffic(panel_active_buttons[id]); + ClearChannel(id); + if(panel_active_buttons[id]->pauseWhenFinished()) { + panel_active_buttons[id]->setState(true); + panel_active_buttons[id]->setColor(RDPANEL_PAUSED_BACKGROUND_COLOR); + panel_active_buttons[id]->resetCounter(); + } + else { + panel_active_buttons[id]->setState(false); + panel_active_buttons[id]->setHookMode(panel_playmode_box->currentItem()==1); + } + disconnect(this,SIGNAL(tick()),panel_active_buttons[id],SLOT(tickClock())); + panel_active_buttons[id]->playDeck()->disconnect(); + delete panel_active_buttons[id]->playDeck(); + panel_active_buttons[id]->setPlayDeck(NULL); + if(!panel_active_buttons[id]->pauseWhenFinished()) { + panel_active_buttons[id]->reset(); + } + panel_active_buttons[id]->setDuckVolume(0); + panel_active_buttons[id]=NULL; + LogLine(QString().sprintf("Playout stopped: id=%d",id)); +} + + +void RDSoundPanel::ClearChannel(int id) +{ + RDPlayDeck *playdeck=panel_active_buttons[id]->playDeck(); + if(panel_cae-> + playPortActive(playdeck->card(),playdeck->port(),playdeck->stream())) { + return; + } + panel_event_player->exec(panel_stop_rml[panel_active_buttons[id]->output()]); + emit channelStopped(panel_active_buttons[id]->output(), + playdeck->card(),playdeck->port()); +} + + +void RDSoundPanel::ClearReset() +{ + panel_reset_mode=false; + panel_reset_button->setFlashingEnabled(false); + panel_setup_button->setEnabled(true); +} + + +QString RDSoundPanel::PanelTag(int index) +{ + if(index<panel_station_panels) { + return QString().sprintf("S:%d",index+1); + } + return QString().sprintf("U:%d",index-panel_station_panels+1); +} + + +QString RDSoundPanel::PanelOwner(RDAirPlayConf::PanelType type) +{ + switch(type) { + case RDAirPlayConf::StationPanel: + return panel_station->name(); + + case RDAirPlayConf::UserPanel: + if(panel_user!=NULL) { + return panel_user->name(); + } + } + return QString(); +} diff --git a/lib/rdsound_panel.h b/lib/rdsound_panel.h new file mode 100644 index 00000000..6d8e4d0a --- /dev/null +++ b/lib/rdsound_panel.h @@ -0,0 +1,200 @@ +// rdsound_panel.h +// +// The sound panel widget for RDAirPlay +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsound_panel.h,v 1.32.6.8 2014/02/20 17:29:32 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDSOUND_PANEL_H +#define RDSOUND_PANEL_H + +#include <vector> + +#include <qwidget.h> +#include <qdatetime.h> +#include <qlabel.h> +#include <qsignalmapper.h> + +#include <rdpushbutton.h> + +#include <rdcart_dialog.h> +#include <rdcart.h> +#include <rduser.h> +#include <rdairplay_conf.h> +#include <rdpanel_button.h> +#include <rdbutton_dialog.h> +#include <rdbutton_panel.h> +#include <rdripc.h> +#include <rdevent_player.h> +#include <rdcombobox.h> + +// +// Widget Settings +// +#define PANEL_BUTTON_SIZE_X 88 +#define PANEL_BUTTON_SIZE_Y 80 +#define PANEL_MAX_OUTPUTS 5 +#define PANEL_SCAN_INTERVAL 10000 + +class RDSoundPanel : public QWidget +{ + Q_OBJECT + public: + RDSoundPanel(int cols,int rows,int station_panels,int user_panels,bool flash, + const QString &label_template,bool extended, + RDEventPlayer *player,RDRipc *ripc,RDCae *cae, + RDStation *station,RDCartDialog *cart_dialog, + QWidget *parent=0,const char *name=0); + ~RDSoundPanel(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + int card(int outnum) const; + void setCard(int outnum,int card); + int port(int outnum) const; + void setPort(int outnum,int port); + QString outputText(int outnum) const; + void setOutputText(int outnum,const QString &text); + void setRmls(int outnum,const QString &start_rml,const QString &stop_rml); + void setLogName(const QString &logname); + void setSvcName(const QString &svcname); + void setLogfile(QString filename); + void play(RDAirPlayConf::PanelType type,int panel,int row,int col, + RDLogLine::StartSource src,int mport=-1,bool pause_when_finished=false); + bool pause(RDAirPlayConf::PanelType type,int panel,int row,int col,int mport=-1); + void stop(RDAirPlayConf::PanelType type,int panel,int row,int col, + int mport=-1,bool pause_when_finished=false,int fade_out=0); + void channelStop(int mport); + void setText(RDAirPlayConf::PanelType type,int panel,int row,int col, + const QString &str); + void setColor(RDAirPlayConf::PanelType type,int panel,int row,int col, + const QColor &color); + void duckVolume(RDAirPlayConf::PanelType type,int panel,int row,int col, + int level,int fade,int mport=-1); + RDAirPlayConf::ActionMode actionMode() const; + void setActionMode(RDAirPlayConf::ActionMode mode); + bool pauseEnabled() const; + void setPauseEnabled(bool state); + int currentNumber() const; + RDAirPlayConf::PanelType currentType() const; + + public slots: + void setButton(RDAirPlayConf::PanelType type,int panel,int row,int col, + unsigned cartnum,const QString &title=""); + void acceptCartDrop(int row,int col,unsigned cartnum,const QColor &color, + const QString &); + void changeUser(); + void tickClock(); + + signals: + void tick(); + void buttonFlash(bool state); + void selectClicked(unsigned cartnum,int row,int col); + void channelStarted(int mport,int card,int port); + void channelStopped(int mport,int card,int port); + + private slots: + void panelActivatedData(int n); + void playmodeActivatedData(int n); + void resetClickedData(); + void allClickedData(); + void setupClickedData(); + void buttonMapperData(int id); + void stateChangedData(int id,RDPlayDeck::State state); + void hookEndData(int id); + void timescalingSupportedData(int card,bool state); + void panelSetupData(); + void onairFlagChangedData(bool state); + void scanPanelData(); + + private: + void PlayButton(RDAirPlayConf::PanelType type,int panel,int row,int col, + RDLogLine::StartSource src,bool hookmode,int mport=-1, + bool pause_when_finished=false); + bool PlayAudio(RDPanelButton *button,RDCart *cart,bool hookmode,int mport=-1); + void PlayMacro(RDPanelButton *button,RDCart *cart); + void PauseButton(RDAirPlayConf::PanelType type,int panel,int row,int col,int mport=-1); + void StopButton(RDAirPlayConf::PanelType type,int panel,int row,int col, + int mport=-1,bool pause_when_finished=false,int fade_out=0); + void StopButton(int id); + void StopButton(RDPlayDeck *deck); + void LoadPanels(); + void LoadPanel(RDAirPlayConf::PanelType type,int panel); + void SaveButton(RDAirPlayConf::PanelType type,int panel,int row,int col); + int PanelOffset(RDAirPlayConf::PanelType type,int panel); + int GetFreeButtonDeck(); + int GetFreeOutput(); + void LogPlayEvent(unsigned cartnum,int cutnum); + void LogTraffic(RDPanelButton *button); + void LogTrafficMacro(RDPanelButton *button); + void LogLine(QString str); + void Playing(int id); + void Paused(int id); + void Stopped(int id); + void ClearChannel(int id); + void ClearReset(); + QString PanelTag(int index); + QString PanelOwner(RDAirPlayConf::PanelType type); + std::vector<RDButtonPanel *> panel_buttons; + RDCae *panel_cae; + RDUser *panel_user; + RDComboBox *panel_selector_box; + QComboBox *panel_playmode_box; + RDPushButton *panel_setup_button; + RDPushButton *panel_reset_button; + RDPushButton *panel_all_button; + RDAirPlayConf::PanelType panel_type; + RDButtonDialog *panel_button_dialog; + QSignalMapper *panel_mapper; + QString panel_tablename; + QString panel_name_tablename; + int panel_number; + int panel_station_panels; + int panel_user_panels; + QString panel_label_template; + bool panel_setup_mode; + bool panel_reset_mode; + QWidget *panel_parent; + RDRipc *panel_ripc; + RDStation *panel_station; + int panel_card[PANEL_MAX_OUTPUTS]; + int panel_port[PANEL_MAX_OUTPUTS]; + int panel_cue_card; + int panel_cue_port; + QString panel_output_text[PANEL_MAX_OUTPUTS]; + QString panel_start_rml[PANEL_MAX_OUTPUTS]; + QString panel_stop_rml[PANEL_MAX_OUTPUTS]; + RDPanelButton *panel_active_buttons[RD_MAX_STREAMS]; + bool panel_flash; + int panel_flash_count; + bool panel_flash_state; + QString panel_logname; + QString panel_logfile; + bool panel_timescaling_supported[PANEL_MAX_OUTPUTS]; + bool panel_config_panels; + RDEventPlayer *panel_event_player; + QString panel_svcname; + RDAirPlayConf::ActionMode panel_action_mode; + bool panel_pause_enabled; + int panel_button_columns; + int panel_button_rows; + RDCartDialog *panel_cart_dialog; + bool panel_onair_flag; + QTimer *panel_scan_timer; +}; + +#endif // RDSOUND_PANEL_H diff --git a/lib/rdstation.cpp b/lib/rdstation.cpp new file mode 100644 index 00000000..4a1396f6 --- /dev/null +++ b/lib/rdstation.cpp @@ -0,0 +1,710 @@ +// rdstation.cpp +// +// Abstract a Rivendell Workstation. +// +// (C) Copyright 2002-2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdstation.cpp,v 1.30.4.8 2014/02/11 23:46:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdconf.h> +#include <rdstation.h> +#include <rd.h> +#include <rddb.h> +#include <rdescape_string.h> + +// +// Global Classes +// +RDStation::RDStation(const QString &name,bool create) +{ + QString sql; + time_offset_valid = false; + station_name=name; +} + + +RDStation::~RDStation() +{ +// printf("Destroying RDStation\n"); +} + + +bool RDStation::exists() const +{ + return RDDoesRowExist("STATIONS","NAME",RDEscapeString(station_name)); +} + + +QString RDStation::name() const +{ + return station_name; +} + + +QString RDStation::description() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"DESCRIPTION").toString(); +} + + +void RDStation::setDescription(QString desc) const +{ + SetRow("DESCRIPTION",desc); +} + + +QString RDStation::userName() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"USER_NAME").toString(); +} + + +void RDStation::setUserName(QString name) const +{ + SetRow("USER_NAME",name); +} + + +QString RDStation::defaultName() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"DEFAULT_NAME"). + toString(); +} + + +void RDStation::setDefaultName(QString name) const +{ + SetRow("DEFAULT_NAME",name); +} + + +QHostAddress RDStation::address() const +{ + QHostAddress addr; + addr.setAddress(RDGetSqlValue("STATIONS","NAME",station_name,"IPV4_ADDRESS"). + toString()); + return addr; +} + + +void RDStation::setAddress(QHostAddress addr) const +{ + SetRow("IPV4_ADDRESS",addr.toString()); +} + + +QHostAddress RDStation::httpAddress(RDConfig *config) const +{ + QHostAddress addr; + + addr.setAddress("127.0.0.1"); + if(httpStation()!="localhost") { + if(httpStation()==RD_RDSELECT_LABEL) { + addr.setAddress(config->audioStoreXportHostname()); + } + else { + addr.setAddress(RDGetSqlValue("STATIONS","NAME",httpStation(), + "IPV4_ADDRESS").toString()); + } + } + + return addr; +} + + +QString RDStation::httpStation() const +{ + return + RDGetSqlValue("STATIONS","NAME",station_name,"HTTP_STATION").toString(); +} + + +void RDStation::setHttpStation(const QString &str) +{ + SetRow("HTTP_STATION",str); +} + + +QString RDStation::caeStation() const +{ + return + RDGetSqlValue("STATIONS","NAME",station_name,"CAE_STATION").toString(); +} + + +QHostAddress RDStation::caeAddress(RDConfig *config) const +{ + QHostAddress addr; + + addr.setAddress("127.0.0.1"); + if(caeStation()!="localhost") { + if(caeStation()==RD_RDSELECT_LABEL) { + addr.setAddress(config->audioStoreCaeHostname()); + } + else { + addr.setAddress(RDGetSqlValue("STATIONS","NAME",caeStation(), + "IPV4_ADDRESS").toString()); + } + } + + return addr; +} + + +void RDStation::setCaeStation(const QString &str) +{ + SetRow("CAE_STATION",str); +} + + +QString RDStation::webServiceUrl(RDConfig *config) const +{ + return QString("http://")+httpAddress(config).toString()+ + "/rd-bin/rdxport.cgi"; +} + + +int RDStation::timeOffset() +{ + if (!time_offset_valid){ + time_offset = RDGetSqlValue("STATIONS","NAME",station_name,"TIME_OFFSET").toInt(); + time_offset_valid = true; + } + return time_offset; +} + + +void RDStation::setTimeOffset(int msecs) +{ + SetRow("TIME_OFFSET",msecs); + time_offset = msecs; +} + + +QString RDStation::backupPath() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"BACKUP_DIR").toString(); +} + + +void RDStation::setBackupPath(QString path) const +{ + SetRow("BACKUP_DIR",path); +} + + +int RDStation::backupLife() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"BACKUP_LIFE").toInt(); +} + + +void RDStation::setBackupLife(int days) const +{ + SetRow("BACKUP_LIFE",days); +} + + +void RDStation::setBroadcastSecurity(BroadcastSecurityMode mode) +{ + SetRow("BROADCAST_SECURITY",mode); +} + + +RDStation::BroadcastSecurityMode RDStation::broadcastSecurity() const +{ + return (RDStation::BroadcastSecurityMode)RDGetSqlValue("STATIONS","NAME", + station_name, + "BROADCAST_SECURITY"). + toUInt(); +} + + +unsigned RDStation::heartbeatCart() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"HEARTBEAT_CART"). + toUInt(); +} + + +void RDStation::setHeartbeatCart(unsigned cartnum) const +{ + SetRow("HEARTBEAT_CART",cartnum); +} + + +unsigned RDStation::heartbeatInterval() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"HEARTBEAT_INTERVAL"). + toUInt(); +} + + +void RDStation::setHeartbeatInterval(unsigned interval) const +{ + SetRow("HEARTBEAT_INTERVAL",interval); +} + + +unsigned RDStation::startupCart() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"STARTUP_CART"). + toUInt(); +} + + +void RDStation::setStartupCart(unsigned cartnum) const +{ + SetRow("STARTUP_CART",cartnum); +} + + +QString RDStation::editorPath() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"EDITOR_PATH"). + toString(); +} + + +void RDStation::setEditorPath(const QString &cmd) +{ + SetRow("EDITOR_PATH",cmd); +} + + +RDStation::FilterMode RDStation::filterMode() const +{ + return (RDStation::FilterMode)RDGetSqlValue("STATIONS","NAME",station_name, + "FILTER_MODE").toInt(); +} + + +void RDStation::setFilterMode(RDStation::FilterMode mode) const +{ + SetRow("FILTER_MODE",(int)mode); +} + + +bool RDStation::startJack() const +{ + return RDBool(RDGetSqlValue("STATIONS","NAME",station_name,"START_JACK"). + toString()); +} + + +void RDStation::setStartJack(bool state) const +{ + SetRow("START_JACK",RDYesNo(state)); +} + + +QString RDStation::jackServerName() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"JACK_SERVER_NAME"). + toString(); +} + + +void RDStation::setJackServerName(const QString &str) const +{ + SetRow("JACK_SERVER_NAME",str); +} + + +QString RDStation::jackCommandLine() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"JACK_COMMAND_LINE"). + toString(); +} + + +void RDStation::setJackCommandLine(const QString &str) const +{ + SetRow("JACK_COMMAND_LINE",str); +} + + +int RDStation::cueCard() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"CUE_CARD").toInt(); +} + + +void RDStation::setCueCard(int card) +{ + SetRow("CUE_CARD",card); +} + + +int RDStation::cuePort() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"CUE_PORT").toInt(); +} + + +void RDStation::setCuePort(int port) +{ + SetRow("CUE_PORT",port); +} + + +unsigned RDStation::cueStartCart() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"CUE_START_CART"). + toUInt(); +} + + +void RDStation::setCueStartCart(unsigned cartnum) const +{ + SetRow("CUE_START_CART",cartnum); +} + + +unsigned RDStation::cueStopCart() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"CUE_STOP_CART").toUInt(); +} + + +void RDStation::setCueStopCart(unsigned cartnum) const +{ + SetRow("CUE_STOP_CART",cartnum); +} + + +int RDStation::cartSlotColumns() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"CARTSLOT_COLUMNS"). + toInt(); +} + + +void RDStation::setCartSlotColumns(int cols) +{ + SetRow("CARTSLOT_COLUMNS",cols); +} + + +int RDStation::cartSlotRows() const +{ + return RDGetSqlValue("STATIONS","NAME",station_name,"CARTSLOT_ROWS").toInt(); +} + + +void RDStation::setCartSlotRows(int rows) +{ + SetRow("CARTSLOT_ROWS",rows); +} + + +bool RDStation::enableDragdrop() const +{ + return RDBool(RDGetSqlValue("STATIONS","NAME",station_name, + "ENABLE_DRAGDROP").toString()); +} + + +void RDStation::setEnableDragdrop(bool state) +{ + SetRow("ENABLE_DRAGDROP",state); +} + + +bool RDStation::enforcePanelSetup() const +{ + return RDBool(RDGetSqlValue("STATIONS","NAME",station_name, + "ENFORCE_PANEL_SETUP").toString()); +} + + +void RDStation::setEnforcePanelSetup(bool state) +{ + SetRow("ENFORCE_PANEL_SETUP",state); +} + + +bool RDStation::systemMaint() const +{ + return RDBool(RDGetSqlValue("STATIONS","NAME",station_name,"SYSTEM_MAINT"). + toString()); +} + + +void RDStation::setSystemMaint(bool state) const +{ + SetRow("SYSTEM_MAINT",state); +} + + +bool RDStation::scanned() const +{ + return RDBool(RDGetSqlValue("STATIONS","NAME",station_name,"STATION_SCANNED"). + toString()); +} + + +void RDStation::setScanned(bool state) const +{ + SetRow("STATION_SCANNED",state); +} + + +bool RDStation::haveCapability(Capability cap) const +{ + switch(cap) { + case RDStation::HaveOggenc: + return RDBool(RDGetSqlValue("STATIONS","NAME",station_name, + "HAVE_OGGENC").toString()); + break; + + case RDStation::HaveOgg123: + return RDBool(RDGetSqlValue("STATIONS","NAME",station_name, + "HAVE_OGG123").toString()); + break; + + case RDStation::HaveFlac: + return RDBool(RDGetSqlValue("STATIONS","NAME",station_name, + "HAVE_FLAC").toString()); + break; + + case RDStation::HaveLame: + return RDBool(RDGetSqlValue("STATIONS","NAME",station_name, + "HAVE_LAME").toString()); + break; + + case RDStation::HaveMpg321: + return RDBool(RDGetSqlValue("STATIONS","NAME",station_name, + "HAVE_MPG321").toString()); + + case RDStation::HaveTwoLame: + return RDBool(RDGetSqlValue("STATIONS","NAME",station_name, + "HAVE_TWOLAME").toString()); + break; + } + return false; +} + + +void RDStation::setHaveCapability(Capability cap,bool state) const +{ + switch(cap) { + case RDStation::HaveOggenc: + SetRow("HAVE_OGGENC",state); + break; + + case RDStation::HaveOgg123: + SetRow("HAVE_OGG123",state); + break; + + case RDStation::HaveFlac: + SetRow("HAVE_FLAC",state); + break; + + case RDStation::HaveLame: + SetRow("HAVE_LAME",state); + break; + + case RDStation::HaveMpg321: + SetRow("HAVE_MPG321",state); + break; + + case RDStation::HaveTwoLame: + SetRow("HAVE_TWOLAME",state); + break; + } +} + + +int RDStation::cards() const +{ + int n=0; + + QString sql=QString().sprintf("select CARD0_DRIVER,CARD1_DRIVER,\ + CARD2_DRIVER,CARD3_DRIVER,CARD4_DRIVER,\ + CARD5_DRIVER,CARD6_DRIVER,CARD7_DRIVER\ + from STATIONS where NAME=\"%s\"", + (const char *)station_name); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + for(int i=0;i<RD_MAX_CARDS;i++) { + if((RDStation::AudioDriver)q->value(i).toInt()!=RDStation::None) { + n++; + } + else { + delete q; + return n; + } + } + } + delete q; + + return n; +} + + +RDStation::AudioDriver RDStation::cardDriver(int cardnum) const +{ + return (RDStation::AudioDriver) + RDGetSqlValue("STATIONS","NAME",station_name, + QString().sprintf("CARD%d_DRIVER",cardnum)). + toInt(); +} + + +void RDStation::setCardDriver(int cardnum,AudioDriver driver) const +{ + SetRow(QString().sprintf("CARD%d_DRIVER",cardnum),(int)driver); +} + + +QString RDStation::driverVersion(AudioDriver driver) const +{ + switch(driver) { + case RDStation::None: + return QString(); + + case RDStation::Hpi: + return RDGetSqlValue("STATIONS","NAME",station_name,"HPI_VERSION"). + toString(); + + case RDStation::Jack: + return RDGetSqlValue("STATIONS","NAME",station_name,"JACK_VERSION"). + toString(); + + case RDStation::Alsa: + return RDGetSqlValue("STATIONS","NAME",station_name,"ALSA_VERSION"). + toString(); + } + return QString(); +} + + +void RDStation::setDriverVersion(AudioDriver driver,QString ver) const +{ + switch(driver) { + case RDStation::None: + break; + + case RDStation::Hpi: + SetRow("HPI_VERSION",ver); + break; + + case RDStation::Jack: + SetRow("JACK_VERSION",ver); + break; + + case RDStation::Alsa: + SetRow("ALSA_VERSION",ver); + break; + } +} + + +QString RDStation::cardName(int cardnum) const +{ + return RDGetSqlValue("STATIONS","NAME",station_name, + QString().sprintf("CARD%d_NAME",cardnum)).toString(); +} + + +void RDStation::setCardName(int cardnum,QString name) const +{ + SetRow(QString().sprintf("CARD%d_NAME",cardnum),name); +} + + +int RDStation::cardInputs(int cardnum) const +{ + return RDGetSqlValue("STATIONS","NAME",station_name, + QString().sprintf("CARD%d_INPUTS",cardnum)).toInt(); +} + + +void RDStation::setCardInputs(int cardnum,int inputs) const +{ + SetRow(QString().sprintf("CARD%d_INPUTS",cardnum),inputs); +} + + +int RDStation::cardOutputs(int cardnum) const +{ + return RDGetSqlValue("STATIONS","NAME",station_name, + QString().sprintf("CARD%d_OUTPUTS",cardnum)).toInt(); +} + + +void RDStation::setCardOutputs(int cardnum,int outputs) const +{ + SetRow(QString().sprintf("CARD%d_OUTPUTS",cardnum),outputs); +} + + +void RDStation::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE STATIONS SET %s=\"%s\" WHERE NAME=\"%s\"", + (const char *)param, + (const char *)RDEscapeString(value), + (const char *)RDEscapeString(station_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDStation::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE STATIONS SET %s=%d WHERE NAME=\"%s\"", + (const char *)param, + value, + (const char *)RDEscapeString(station_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDStation::SetRow(const QString ¶m,unsigned value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE STATIONS SET %s=%u WHERE NAME=\"%s\"", + (const char *)param, + value, + (const char *)RDEscapeString(station_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDStation::SetRow(const QString ¶m,bool value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE STATIONS SET %s=\"%s\" WHERE NAME=\"%s\"", + (const char *)param, + (const char *)RDYesNo(value), + (const char *)RDEscapeString(station_name)); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdstation.h b/lib/rdstation.h new file mode 100644 index 00000000..321f921f --- /dev/null +++ b/lib/rdstation.h @@ -0,0 +1,148 @@ +// rdstation.h +// +// Abstract a Rivendell Workstation +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdstation.h,v 1.24.4.7 2014/02/11 23:46:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDSTATION_H +#define RDSTATION_H + +#include <qsqldatabase.h> +#include <qhostaddress.h> + +#include <rdconfig.h> + +class RDStation +{ + public: + enum AudioDriver {None=0,Hpi=1,Jack=2,Alsa=3}; + /** + * Enum to track the state of the broadcast applications security model. + * @see setBroadcastSecurity() + * @see broadcastSecurity() + */ + enum BroadcastSecurityMode { + HostSec=0, /**< HostSec - original host (or no) security. */ + UserSec=1 /**< UserSec - user based security. */ + }; + enum Capability {HaveOggenc=0,HaveOgg123=1,HaveFlac=2, + HaveLame=3,HaveMpg321=4,HaveTwoLame=5}; + enum FilterMode {FilterSynchronous=0,FilterAsynchronous=1}; + RDStation(const QString &name,bool create=false); + ~RDStation(); + QString name() const; + bool exists() const; + QString description() const; + void setDescription(QString path) const; + QString userName() const; + void setUserName(QString name) const; + QString defaultName() const; + void setDefaultName(QString name) const; + QHostAddress address() const; + void setAddress(QHostAddress addr) const; + QHostAddress httpAddress(RDConfig *config) const; + QString httpStation() const; + void setHttpStation(const QString &str); + QHostAddress caeAddress(RDConfig *config) const; + QString caeStation() const; + void setCaeStation(const QString &str); + QString webServiceUrl(RDConfig *config) const; + int timeOffset(); + void setTimeOffset(int msecs); + QString backupPath() const; + void setBackupPath(QString path) const; + int backupLife() const; + void setBackupLife(int days) const; + + /** + * Set the Broadcast applications (rdairplay, rdlogedit, rdlogmanager) + * security mode. + * + * @param mode An enum with the desired mode. + */ + void setBroadcastSecurity(BroadcastSecurityMode mode); + + /** + * Get the Broadcast applicaitons security mode. + * + * @return An enum with the current mode. + */ + BroadcastSecurityMode broadcastSecurity() const; + unsigned heartbeatCart() const; + void setHeartbeatCart(unsigned cartnum) const; + unsigned heartbeatInterval() const; + void setHeartbeatInterval(unsigned interval) const; + unsigned startupCart() const; + void setStartupCart(unsigned cartnum) const; + QString editorPath() const; + void setEditorPath(const QString &cmd); + RDStation::FilterMode filterMode() const; + void setFilterMode(RDStation::FilterMode mode) const; + bool startJack() const; + void setStartJack(bool state) const; + QString jackServerName() const; + void setJackServerName(const QString &str) const; + QString jackCommandLine() const; + void setJackCommandLine(const QString &str) const; + int cueCard() const; + void setCueCard(int card); + int cuePort() const; + void setCuePort(int port); + unsigned cueStartCart() const; + void setCueStartCart(unsigned cartnum) const; + unsigned cueStopCart() const; + void setCueStopCart(unsigned cartnum) const; + int cartSlotColumns() const; + void setCartSlotColumns(int cols); + int cartSlotRows() const; + void setCartSlotRows(int rows); + bool enableDragdrop() const; + void setEnableDragdrop(bool state); + bool enforcePanelSetup() const; + void setEnforcePanelSetup(bool state); + bool systemMaint() const; + void setSystemMaint(bool state) const; + bool scanned() const; + void setScanned(bool state) const; + bool haveCapability(Capability cap) const; + void setHaveCapability(Capability cap,bool state) const; + int cards() const; + RDStation::AudioDriver cardDriver(int cardnum) const; + void setCardDriver(int cardnum,AudioDriver driver) const; + QString driverVersion(AudioDriver driver) const; + void setDriverVersion(AudioDriver driver,QString ver) const; + QString cardName(int cardnum) const; + void setCardName(int cardnum,QString name) const; + int cardInputs(int cardnum) const; + void setCardInputs(int cardnum,int inputs) const; + int cardOutputs(int cardnum) const; + void setCardOutputs(int cardnum,int outputs) const; + + private: + void SetRow(const QString ¶m,const QString &value) const; + void SetRow(const QString ¶m,int value) const; + void SetRow(const QString ¶m,unsigned value) const; + void SetRow(const QString ¶m,bool value) const; + QString station_name; + int time_offset; + bool time_offset_valid; +}; + + +#endif diff --git a/lib/rdstatus.cpp b/lib/rdstatus.cpp new file mode 100644 index 00000000..8f4eba2d --- /dev/null +++ b/lib/rdstatus.cpp @@ -0,0 +1,91 @@ +// rdstatus.cpp +// +// Functions for getting system status. +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdstatus.cpp,v 1.1.2.2 2012/10/22 23:09:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <syslog.h> +#include <errno.h> + +#include <qstringlist.h> +#include <qsqldatabase.h> + +#include "rdstatus.h" + +bool RDAudioStoreValid(RDConfig *config) +{ + FILE *f=NULL; + char line[1024]; + bool ret=false; + + if((f=fopen("/etc/mtab","r"))==NULL) { + syslog(LOG_CRIT,"unable to read mtab(5) [%s]",strerror(errno)); + return false; + } + if(config->audioStoreMountSource().isEmpty()) { // Audio store is local + ret=true; + while(fgets(line,1024,f)!=NULL) { + QStringList fields=fields.split(" ",QString(line)); + if(fields.size()>=2) { + ret=ret&&(fields[1]!=RD_AUDIO_ROOT); + } + } + } + else { // Audio store is remote + ret=false; + while(fgets(line,1024,f)!=NULL) { + QStringList fields=fields.split(" ",QString(line)); + if(fields.size()>=2) { + ret=ret||fields[0]==config->audioStoreMountSource(); + } + } + } + fclose(f); + return ret; +} + + +bool RDDbValid(RDConfig *config,int *schema) +{ + QString sql; + QSqlQuery *q; + bool ret=false; + + QSqlDatabase *db=QSqlDatabase::addDatabase(config->mysqlDriver()); + if(db) { + db->setDatabaseName(config->mysqlDbname()); + db->setUserName(config->mysqlUsername()); + db->setPassword(config->mysqlPassword()); + db->setHostName(config->mysqlHostname()); + if(db->open()) { + ret=true; + sql="select DB from VERSION"; + q=new QSqlQuery(sql); + if(q->first()) { + *schema=q->value(0).toInt(); + } + delete q; + db->close(); + } + QSqlDatabase::removeDatabase(db); + } + return ret; +} diff --git a/lib/rdstatus.h b/lib/rdstatus.h new file mode 100644 index 00000000..6d4321b0 --- /dev/null +++ b/lib/rdstatus.h @@ -0,0 +1,31 @@ +// rdstatus.h +// +// Functions for getting system status. +// +// (C) Copyright 2012 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdstatus.h,v 1.1.2.2 2012/10/22 23:09:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDSTATUS_H +#define RDSTATUS_H + +#include <rdconfig.h> + +bool RDAudioStoreValid(RDConfig *config); +bool RDDbValid(RDConfig *config,int *schema); + +#endif // RDCONF_H diff --git a/lib/rdstereometer.cpp b/lib/rdstereometer.cpp new file mode 100644 index 00000000..f9cbcced --- /dev/null +++ b/lib/rdstereometer.cpp @@ -0,0 +1,316 @@ +// rdstereometer.cpp +// +// This implements a widget that represents a stereo audio level meter, +// complete with labels and scale. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdstereometer.cpp,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qwidget.h> +#include <qstring.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qcolor.h> +#include <qpainter.h> +#include <qpushbutton.h> +#include <qsize.h> +#include <stdio.h> +#include <qslider.h> +#include <qbuttongroup.h> +#include <qsizepolicy.h> +#include <qmessagebox.h> + +#include <rdsegmeter.h> +#include <rdstereometer.h> + +RDStereoMeter::RDStereoMeter(QWidget *parent,const char *name) + : QWidget(parent,name) +{ + ref_level=0; + clip_light_level=1600; + clip_light_on=false; + label_x=0; + meter_label=QString(""); + setBackgroundColor(black); + left_meter=new RDSegMeter(RDSegMeter::Right,this,"left_meter"); + left_meter->setGeometry(25,10,300,10); + left_meter->setRange(-4600,-800); + left_meter->setHighThreshold(-1600); + left_meter->setClipThreshold(-1100); + left_meter->setSegmentSize(5); + left_meter->setSegmentGap(1); + left_meter->setSolidBar(-10000); + left_meter->setFloatingBar(-10000); + right_meter=new RDSegMeter(RDSegMeter::Right,this,"right_meter"); + right_meter->setGeometry(25,40,300,10); + right_meter->setRange(-4600,-800); + right_meter->setHighThreshold(-1600); + right_meter->setClipThreshold(-1100); + right_meter->setSegmentSize(5); + right_meter->setSegmentGap(1); + right_meter->setSolidBar(-10000); + right_meter->setFloatingBar(-10000); + setFixedSize(335,60); + + // + // Generate Fonts + // + meter_label_font=QFont("System",18,QFont::Bold); + meter_label_font.setPixelSize(18); + meter_scale_font=QFont("System",12,QFont::Bold); + meter_scale_font.setPixelSize(12); +} + + +QSize RDStereoMeter::sizeHint() const +{ + if(meter_label==QString("")) { + return QSize(335,60); + } + else { + return QSize(335,80); + } +} + + +QSizePolicy RDStereoMeter::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RDStereoMeter::setReference(int level) +{ + ref_level=level; +} + + +void RDStereoMeter::setClipLight(int level) +{ + clip_light_level=level-1600+ref_level; +} + + +void RDStereoMeter::setDarkLowColor(QColor color) +{ + left_meter->setDarkLowColor(color); + right_meter->setDarkLowColor(color); +} + + +void RDStereoMeter::setDarkHighColor(QColor color) +{ + left_meter->setDarkHighColor(color); + right_meter->setDarkHighColor(color); +} + + +void RDStereoMeter::setDarkClipColor(QColor color) +{ + left_meter->setDarkClipColor(color); + right_meter->setDarkClipColor(color); +} + + +void RDStereoMeter::setLowColor(QColor color) +{ + left_meter->setLowColor(color); + right_meter->setLowColor(color); +} + + +void RDStereoMeter::setHighColor(QColor color) +{ + left_meter->setHighColor(color); + right_meter->setHighColor(color); +} + + +void RDStereoMeter::setClipColor(QColor color) +{ + left_meter->setClipColor(color); + right_meter->setClipColor(color); +} + + +void RDStereoMeter::setHighThreshold(int level) +{ + left_meter->setHighThreshold(level); + right_meter->setHighThreshold(level); +} + + +void RDStereoMeter::setClipThreshold(int level) +{ + left_meter->setClipThreshold(level); + right_meter->setClipThreshold(level); +} + + +void RDStereoMeter::setLabel(QString label) +{ + meter_label=label; + if(meter_label!=QString("")) { + QFont meter_font=QFont("System",18,QFont::Normal); + meter_font.setPixelSize(18); + QFontMetrics meter_metrics=QFontMetrics(meter_font); + label_x=(335-meter_metrics.width(meter_label))/2; + setFixedSize(335,80); + } + else { + setFixedSize(335,60); + } +} + + +RDSegMeter::Mode RDStereoMeter::mode() const +{ + return left_meter->mode(); +} + + +void RDStereoMeter::setMode(RDSegMeter::Mode mode) +{ + left_meter->setMode(mode); + right_meter->setMode(mode); +} + + +void RDStereoMeter::setLeftSolidBar(int level) +{ + left_meter->setSolidBar(level-ref_level); + if((level>=0)&&(!clip_light_on)) { + clip_light_on=true; + emit clip(); + update(); + } +} + + +void RDStereoMeter::setRightSolidBar(int level) +{ + right_meter->setSolidBar(level-ref_level); + if((level>=clip_light_level)&&(!clip_light_on)) { + clip_light_on=true; + emit clip(); + update(); + } +} + + +void RDStereoMeter::setLeftFloatingBar(int level) +{ + left_meter->setFloatingBar(level-ref_level); + if((level>=clip_light_level)&&(!clip_light_on)) { + clip_light_on=true; + emit clip(); + update(); + } +} + + +void RDStereoMeter::setRightFloatingBar(int level) +{ + right_meter->setFloatingBar(level-ref_level); + if((level>=clip_light_level)&&(!clip_light_on)) { + clip_light_on=true; + emit clip(); + update(); + } +} + + +void RDStereoMeter::setLeftPeakBar(int level) +{ + left_meter->setPeakBar(level-ref_level); + if((level>=clip_light_level)&&(!clip_light_on)) { + clip_light_on=true; + emit clip(); + update(); + } +} + + +void RDStereoMeter::setRightPeakBar(int level) +{ + right_meter->setPeakBar(level-ref_level); + if((level>=clip_light_level)&&(!clip_light_on)) { + clip_light_on=true; + emit clip(); + update(); + } +} + + +void RDStereoMeter::resetClipLight() +{ + clip_light_on=false; + update(); +} + + +void RDStereoMeter::setSegmentSize(int size) +{ + left_meter->setSegmentSize(size); + right_meter->setSegmentSize(size); +} + + +void RDStereoMeter::setSegmentGap(int gap) +{ + left_meter->setSegmentGap(gap); + right_meter->setSegmentGap(gap); +} + + +void RDStereoMeter::paintEvent(QPaintEvent *paintEvent) +{ + // + // Setup + // + QPixmap pix(this->size()); + pix.fill(this,0,0); + QPainter *p=new QPainter(&pix); + p->setBrush(QColor(white)); + p->setPen(QColor(white)); + p->setFont(meter_scale_font); + p->drawText(10,20,tr("L")); + p->drawText(10,50,tr("R")); + p->drawText(12,35,"-30"); + p->drawText(48,35,"-25"); + p->drawText(88,35,"-20"); + p->drawText(126,35,"-15"); + p->drawText(167,35,"-10"); + p->drawText(207,35,"-5"); + p->drawText(255,35,"0"); + p->drawText(314,35,"+8"); + if(meter_label!=QString("")) { + p->setFont(meter_label_font); + p->drawText(label_x,72,meter_label); + } + if(clip_light_on) { + p->setFont(meter_scale_font); + p->setPen(QColor(CLIP_LIGHT_COLOR)); + p->drawText(274,35,tr("CLIP")); + } + p->end(); + p->begin(this); + p->drawPixmap(0,0,pix); + p->end(); + delete p; +} diff --git a/lib/rdstereometer.h b/lib/rdstereometer.h new file mode 100644 index 00000000..ca3cac69 --- /dev/null +++ b/lib/rdstereometer.h @@ -0,0 +1,88 @@ +// rdstereometer.h +// +// A Stereo Audio Meter Widget +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdstereometer.h,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDSTEREOMETER_H +#define RDSTEREOMETER_H + +#include <qwidget.h> +#include <qcolor.h> +#include <qpainter.h> +#include <qsize.h> +#include <qsizepolicy.h> +#include <qstring.h> +#include <rdsegmeter.h> + +#define CLIP_LIGHT_COLOR red + + +class RDStereoMeter : public QWidget +{ + Q_OBJECT + public: + RDStereoMeter(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void setReference(int level); + void setClipLight(int level); + void setDarkLowColor(QColor color); + void setDarkHighColor(QColor color); + void setDarkClipColor(QColor color); + void setLowColor(QColor color); + void setHighColor(QColor color); + void setClipColor(QColor color); + void setHighThreshold(int level); + void setClipThreshold(int level); + void setSegmentSize(int size); + void setSegmentGap(int gap); + void setLabel(QString label); + RDSegMeter::Mode mode() const; + void setMode(RDSegMeter::Mode mode); + + public slots: + void setLeftSolidBar(int level); + void setRightSolidBar(int level); + void setLeftFloatingBar(int level); + void setRightFloatingBar(int level); + void setLeftPeakBar(int level); + void setRightPeakBar(int level); + void resetClipLight(); + + signals: + void clip(); + + protected: + void paintEvent(QPaintEvent *); + + private: + RDSegMeter *left_meter,*right_meter; + int ref_level; + int clip_light_level; + bool clip_light_on; + int label_x; + QString meter_label; + QFont meter_label_font; + QFont meter_scale_font; +}; + + +#endif // RDSTEREOMETER_H diff --git a/lib/rdstringlist.cpp b/lib/rdstringlist.cpp new file mode 100644 index 00000000..d30fd7b8 --- /dev/null +++ b/lib/rdstringlist.cpp @@ -0,0 +1,69 @@ +// rdstringlist.cpp +// +// A StringList with quote mode +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdstringlist.cpp,v 1.2.8.1 2012/12/13 22:33:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <rdstringlist.h> + + +RDStringList::RDStringList() + : QStringList() +{ +} + + +RDStringList::RDStringList(const RDStringList &lhs) + : QStringList(lhs) +{ +} + + +RDStringList::RDStringList(const QStringList &lhs) + : QStringList(lhs) +{ +} + + +RDStringList RDStringList::split(const QString &sep,const QString &str, + const QString &esc) +{ + if(esc.isEmpty()) { + return (RDStringList)QStringList::split(sep,str); + } + RDStringList list; + bool escape=false; + QChar e=esc.at(0); + list.push_back(QString()); + for(unsigned i=0;i<str.length();i++) { + if(str.at(i)==e) { + escape=!escape; + } + else { + if((!escape)&&(str.at(i)==sep)) { + list.push_back(QString()); + } + else { + list.back()+=str.at(i); + } + } + } + return list; +} diff --git a/lib/rdstringlist.h b/lib/rdstringlist.h new file mode 100644 index 00000000..4bf7816d --- /dev/null +++ b/lib/rdstringlist.h @@ -0,0 +1,41 @@ +// rdstringlist.h +// +// A StringList with quote mode +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdstringlist.h,v 1.2 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDSTRINGLIST_H +#define RDSTRINGLIST_H + +#include <qstringlist.h> + + +class RDStringList : public QStringList +{ + public: + RDStringList(); + RDStringList(const RDStringList &lhs); + RDStringList(const QStringList &lhs); + RDStringList split(const QString &sep,const QString &str, + const QString &esc=""); +}; + + +#endif // RDSTRINGLIST_H diff --git a/lib/rdsvc.cpp b/lib/rdsvc.cpp new file mode 100644 index 00000000..fad746af --- /dev/null +++ b/lib/rdsvc.cpp @@ -0,0 +1,1602 @@ +// rdsvc.cpp +// +// Abstract a Rivendell Service. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsvc.cpp,v 1.71.8.10.2.5 2014/06/24 18:27:05 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qmessagebox.h> + +#include <rdconf.h> +#include <rd.h> +#include <rdsvc.h> +#include <rddatedecode.h> +#include <rdcreate_log.h> +#include <rdclock.h> +#include <rdlog.h> +#include <rddb.h> +#include <rdescape_string.h> +#include <rdweb.h> + +// +// Global Classes +// +RDSvc::RDSvc(QString svcname,QObject *parent,const char *name) + : QObject(parent,name) +{ + svc_name=svcname; +} + + +bool RDSvc::exists() const +{ + return RDDoesRowExist("SERVICES","NAME",svc_name); +} + + +QString RDSvc::name() const +{ + return svc_name; +} + + +QString RDSvc::description() const +{ + return RDGetSqlValue("SERVICES","NAME",svc_name,"DESCRIPTION"). + toString(); +} + + +void RDSvc::setDescription(const QString &desc) const +{ + SetRow("DESCRIPTION",desc); +} + + +QString RDSvc::programCode() const +{ + return RDGetSqlValue("SERVICES","NAME",svc_name,"PROGRAM_CODE"). + toString(); +} + + +void RDSvc::setProgramCode(const QString &str) const +{ + SetRow("PROGRAM_CODE",str); +} + + +QString RDSvc::nameTemplate() const +{ + return RDGetSqlValue("SERVICES","NAME",svc_name,"NAME_TEMPLATE"). + toString(); +} + + +void RDSvc::setNameTemplate(const QString &str) const +{ + SetRow("NAME_TEMPLATE",str); +} + + +QString RDSvc::descriptionTemplate() const +{ + return RDGetSqlValue("SERVICES","NAME",svc_name,"DESCRIPTION_TEMPLATE"). + toString(); +} + + +void RDSvc::setDescriptionTemplate(const QString &str) const +{ + SetRow("DESCRIPTION_TEMPLATE",str); +} + + +QString RDSvc::trackGroup() const +{ + return RDGetSqlValue("SERVICES","NAME",svc_name,"TRACK_GROUP"). + toString(); +} + + +void RDSvc::setTrackGroup(const QString &group) const +{ + SetRow("TRACK_GROUP",group); +} + + +QString RDSvc::autospotGroup() const +{ + return RDGetSqlValue("SERVICES","NAME",svc_name,"AUTOSPOT_GROUP"). + toString(); +} + + +void RDSvc::setAutospotGroup(const QString &group) const +{ + SetRow("AUTOSPOT_GROUP",group); +} + + +bool RDSvc::autoRefresh() const +{ + return RDBool(RDGetSqlValue("SERVICES","NAME",svc_name,"AUTO_REFRESH"). + toString()); +} + + +void RDSvc::setAutoRefresh(bool state) +{ + SetRow("AUTO_REFRESH",RDYesNo(state)); +} + + +int RDSvc::defaultLogShelflife() const +{ + return RDGetSqlValue("SERVICES","NAME",svc_name,"DEFAULT_LOG_SHELFLIFE").toInt(); +} + + +void RDSvc::setDefaultLogShelflife(int days) const +{ + SetRow("DEFAULT_LOG_SHELFLIFE",days); +} + + +int RDSvc::elrShelflife() const +{ + return RDGetSqlValue("SERVICES","NAME",svc_name,"ELR_SHELFLIFE").toInt(); +} + + +void RDSvc::setElrShelflife(int days) const +{ + SetRow("ELR_SHELFLIFE",days); +} + + +bool RDSvc::chainto() const +{ + return + RDBool(RDGetSqlValue("SERVICES","NAME",svc_name,"CHAIN_LOG").toString()); +} + + +void RDSvc::setChainto(bool state) const +{ + SetRow("CHAIN_LOG",RDYesNo(state)); +} + + +QString RDSvc::importTemplate(ImportSource src) const +{ + QString fieldname=SourceString(src)+"IMPORT_TEMPLATE"; + return RDGetSqlValue("SERVICES","NAME",svc_name,fieldname). + toString(); +} + + +void RDSvc::setImportTemplate(ImportSource src,const QString &str) const +{ + QString fieldname=SourceString(src)+"IMPORT_TEMPLATE"; + SetRow(fieldname,str); +} + + +QString RDSvc::breakString() const +{ + return RDGetSqlValue("SERVICES","NAME",svc_name,"MUS_BREAK_STRING"). + toString(); +} + + +void RDSvc::setBreakString(const QString &str) +{ + SetRow("MUS_BREAK_STRING",str); +} + + +QString RDSvc::trackString(ImportSource src) const +{ + QString fieldname=SourceString(src)+"TRACK_STRING"; + return RDGetSqlValue("SERVICES","NAME",svc_name,fieldname). + toString(); +} + + +void RDSvc::setTrackString(ImportSource src,const QString &str) +{ + QString fieldname=SourceString(src)+"TRACK_STRING"; + SetRow(fieldname,str); +} + + +QString RDSvc::labelCart(ImportSource src) const +{ + QString fieldname=SourceString(src)+"LABEL_CART"; + return RDGetSqlValue("SERVICES","NAME",svc_name,fieldname).toString(); +} + + +void RDSvc::setLabelCart(ImportSource src,const QString &str) +{ + QString fieldname=SourceString(src)+"LABEL_CART"; + SetRow(fieldname,str); +} + + +QString RDSvc::trackCart(ImportSource src) const +{ + QString fieldname=SourceString(src)+"TRACK_CART"; + return RDGetSqlValue("SERVICES","NAME",svc_name,fieldname).toString(); +} + + +void RDSvc::setTrackCart(ImportSource src,const QString &str) +{ + QString fieldname=SourceString(src)+"TRACK_CART"; + SetRow(fieldname,str); +} + + +QString RDSvc::importPath(ImportSource src,ImportOs os) const +{ + QString fieldname=SourceString(src)+OsString(os)+"PATH"; + return RDGetSqlValue("SERVICES","NAME",svc_name,fieldname). + toString(); +} + + +void RDSvc::setImportPath(ImportSource src,ImportOs os,const QString &path) + const +{ + QString fieldname=SourceString(src)+OsString(os)+"PATH"; + SetRow(fieldname,path); +} + + +QString RDSvc::preimportCommand(ImportSource src,ImportOs os) const +{ + QString fieldname=SourceString(src)+OsString(os)+"PREIMPORT_CMD"; + return RDGetSqlValue("SERVICES","NAME",svc_name,fieldname). + toString(); +} + + +void RDSvc::setPreimportCommand(ImportSource src,ImportOs os, + const QString &path) const +{ + QString fieldname=SourceString(src)+OsString(os)+"PREIMPORT_CMD"; + SetRow(fieldname,path); +} + + +int RDSvc::importOffset(ImportSource src,ImportField field) const +{ + QString fieldname=SourceString(src)+FieldString(field)+"OFFSET"; + return RDGetSqlValue("SERVICES","NAME",svc_name,fieldname).toInt(); +} + + +void RDSvc::setImportOffset(ImportSource src,ImportField field,int offset) + const +{ + QString fieldname=SourceString(src)+FieldString(field)+"OFFSET"; + SetRow(fieldname,offset); +} + + +int RDSvc::importLength(ImportSource src,ImportField field) const +{ + QString fieldname=SourceString(src)+FieldString(field)+"LENGTH"; + return RDGetSqlValue("SERVICES","NAME",svc_name,fieldname).toInt(); +} + + +void RDSvc::setImportLength(ImportSource src,ImportField field,int len) const +{ + QString fieldname=SourceString(src)+FieldString(field)+"LENGTH"; + SetRow(fieldname,len); +} + + +QString RDSvc::importFilename(ImportSource src,const QDate &date) const +{ + QString src_str; + switch(src) { + case RDSvc::Traffic: + src_str="TFC"; + break; + + case RDSvc::Music: + src_str="MUS"; + break; + } + QString os_flag; +#ifdef WIN32 + os_flag="_WIN"; +#endif + QString sql=QString().sprintf("select %s%s_PATH from SERVICES \ + where NAME=\"%s\"", + (const char *)src_str, + (const char *)os_flag, + (const char *)svc_name); + QString ret; + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + ret=RDDateDecode(q->value(0).toString(),date); + } + delete q; + return ret; +} + + +bool RDSvc::import(ImportSource src,const QDate &date,const QString &break_str, + const QString &track_str,const QString &dest_table) const +{ + FILE *infile; + QString src_str; + char buf[RD_MAX_IMPORT_LINE_LENGTH]; + QString str_buf; + char var_buf[RD_MAX_IMPORT_LINE_LENGTH]; + int start_hour; + int start_minutes; + int start_seconds; + QString hours_len_buf; + QString minutes_len_buf; + QString seconds_len_buf; + unsigned cartnum; + QString cartname; + QString title; + char data_buf[RD_MAX_IMPORT_LINE_LENGTH]; + char eventid_buf[RD_MAX_IMPORT_LINE_LENGTH]; + char annctype_buf[RD_MAX_IMPORT_LINE_LENGTH]; + QString os_flag; + int cartlen; + QString sql; + bool ok=false; + + // + // Set Import Source + // + switch(src) { + case RDSvc::Traffic: + src_str="TFC"; + break; + + case RDSvc::Music: + src_str="MUS"; + break; + } + + // + // Set OS Type + // +#ifdef WIN32 + os_flag="_WIN"; +#endif + + // + // Load Parser Parameters + // + sql=QString().sprintf("select %s%s_PATH,\ + %s_LABEL_CART,\ + %s_TRACK_CART,\ + %s%s_PREIMPORT_CMD \ + from SERVICES where NAME=\"%s\"", + (const char *)src_str, + (const char *)os_flag, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)os_flag, + (const char *)RDEscapeString(svc_name)); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return false; + } + QString infilename=q->value(0).toString(); + QString label_cart=q->value(1).toString().stripWhiteSpace(); + QString track_cart=q->value(2).toString().stripWhiteSpace(); + QString preimport_cmd=q->value(3).toString(); + delete q; + + // + // Open Source File + // + if((infile=fopen(RDDateDecode(infilename,date),"r"))==NULL) { + return false; + } + + // + // Run Preimport Command + // + if(!preimport_cmd.isEmpty()) { + system(RDDateDecode(preimport_cmd,date)); + } + + QString parser_table; + QString parser_name; + if(importTemplate(src).isEmpty()) { + src_str+="_"; + parser_table="SERVICES"; + parser_name=svc_name; + } + else { + src_str=""; + parser_table="IMPORT_TEMPLATES"; + parser_name=importTemplate(src); + } + sql=QString().sprintf("select %sCART_OFFSET,%sCART_LENGTH,\ + %sDATA_OFFSET,%sDATA_LENGTH, \ + %sEVENT_ID_OFFSET,%sEVENT_ID_LENGTH, \ + %sANNC_TYPE_OFFSET,%sANNC_TYPE_LENGTH, \ + %sTITLE_OFFSET,%sTITLE_LENGTH,\ + %sHOURS_OFFSET,%sHOURS_LENGTH,\ + %sMINUTES_OFFSET,%sMINUTES_LENGTH,\ + %sSECONDS_OFFSET,%sSECONDS_LENGTH,\ + %sLEN_HOURS_OFFSET,%sLEN_HOURS_LENGTH,\ + %sLEN_MINUTES_OFFSET,%sLEN_MINUTES_LENGTH,\ + %sLEN_SECONDS_OFFSET,%sLEN_SECONDS_LENGTH \ + from %s where NAME=\"%s\"", + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)parser_table, + (const char *)RDEscapeString(parser_name)); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return false; + } + int cart_offset=q->value(0).toInt(); + int cart_length=q->value(1).toInt(); + unsigned cart_size=cart_offset+cart_length; + int data_offset=q->value(2).toInt(); + int data_length=q->value(3).toInt(); + unsigned data_size=data_offset+data_length; + int eventid_offset=q->value(4).toInt(); + int eventid_length=q->value(5).toInt(); + unsigned eventid_size=eventid_offset+eventid_length; + int annctype_offset=q->value(6).toInt(); + int annctype_length=q->value(7).toInt(); + unsigned annctype_size=annctype_offset+annctype_length; + int title_offset=q->value(8).toInt(); + int title_length=q->value(9).toInt(); + unsigned title_size=title_offset+title_length; + int hours_offset=q->value(10).toInt(); + int hours_length=q->value(11).toInt(); + unsigned hours_size=hours_offset+hours_length; + int minutes_offset=q->value(12).toInt(); + int minutes_length=q->value(13).toInt(); + unsigned minutes_size=minutes_offset+minutes_length; + int seconds_offset=q->value(14).toInt(); + int seconds_length=q->value(15).toInt(); + unsigned seconds_size=seconds_offset+seconds_length; + int hours_len_offset=q->value(16).toInt(); + int hours_len_length=q->value(17).toInt(); + unsigned hours_len_size=hours_len_offset+hours_len_length; + int minutes_len_offset=q->value(18).toInt(); + int minutes_len_length=q->value(19).toInt(); + unsigned minutes_len_size=minutes_len_offset+minutes_len_length; + int seconds_len_offset=q->value(20).toInt(); + int seconds_len_length=q->value(21).toInt(); + unsigned seconds_len_size=seconds_len_offset+seconds_len_length; + + delete q; + + // + // Setup Data Source and Destination + // + /* + if((infile=fopen(RDDateDecode(infilename,date),"r"))==NULL) { + return false; + } + */ + sql=QString().sprintf("drop table `%s`",(const char *)dest_table); + QSqlQuery *qq; // Use QSqlQuery so we don't generate a + qq=new QSqlQuery(sql); // spurious error message. + delete qq; + sql=QString().sprintf("create table `%s` (\ + ID int primary key,\ + START_HOUR int not null,\ + START_SECS int not null,\ + CART_NUMBER int unsigned,\ + TITLE char(255),\ + LENGTH int,\ + INSERT_BREAK enum('N','Y') default 'N',\ + INSERT_TRACK enum('N','Y') default 'N',\ + INSERT_FIRST int unsigned default 0,\ + TRACK_STRING char(255),\ + EXT_DATA char(32),\ + EXT_EVENT_ID char(32),\ + EXT_ANNC_TYPE char(8),\ + EXT_CART_NAME char(32),\ + EVENT_USED enum('N','Y') default 'N',\ + INDEX START_TIME_IDX (START_HOUR,START_SECS))", + (const char *)dest_table); + q=new RDSqlQuery(sql); + delete q; + + // + // Parse and Save + // + int line_id=0; + bool insert_found=false; + bool cart_ok=false; + bool line_used=false; + bool insert_break=false; + bool insert_track=false; + bool break_first=false; + bool track_first=false; + QString track_label; + while(fgets(buf,RD_MAX_IMPORT_LINE_LENGTH,infile)!=NULL) { + line_used=false; + str_buf=buf; + cartnum=0; // Get Cart Number + if(strlen(buf)>=cart_size) { + for(int i=cart_offset;i<(cart_offset+cart_length);i++) { + var_buf[i-cart_offset]=buf[i]; + } + var_buf[cart_length]=0; + cartname=QString(var_buf).stripWhiteSpace(); + if(strlen(buf)>=hours_size) { // Get Start Hours + start_hour=QString(buf).mid(hours_offset,hours_length).toInt(&ok); + if(ok&&(strlen(buf)>=minutes_size)) { // Get Start Minutes + start_minutes= + QString(buf).mid(minutes_offset,minutes_length).toInt(&ok); + if(ok&&(strlen(buf)>=seconds_size)) { // Get Start Seconds + start_seconds= + QString(buf).mid(seconds_offset,seconds_length).toInt(&ok); + if(ok&&(strlen(buf)>=hours_len_size)) { // Get Length Hours + hours_len_buf= + QString(buf).mid(hours_len_offset,hours_len_length); + if(strlen(buf)>=minutes_len_size) { // Get Length Minutes + minutes_len_buf= + QString(buf).mid(minutes_len_offset,minutes_len_length); + if(strlen(buf)>=seconds_len_size) { // Get Length Seconds + seconds_len_buf= + QString(buf).mid(seconds_len_offset,seconds_len_length); + cartlen=3600000*hours_len_buf.toInt()+ + 60000*minutes_len_buf.toInt()+ + 1000*seconds_len_buf.toInt(); + if(strlen(buf)>=data_size) { // Get Ext Data + for(int i=data_offset;i<(data_offset+data_length);i++) { + data_buf[i-data_offset]=buf[i]; + } + data_buf[data_length]=0; + if(strlen(buf)>=eventid_size) { // Get Ext Event ID + for(int i=eventid_offset; + i<(eventid_offset+eventid_length);i++) { + eventid_buf[i-eventid_offset]=buf[i]; + } + eventid_buf[eventid_length]=0; + if(strlen(buf)>=annctype_size) { // Get Ext Annc Type + for(int i=annctype_offset; + i<(annctype_offset+annctype_length); + i++) { + annctype_buf[i-annctype_offset]=buf[i]; + } + annctype_buf[annctype_length]=0; + if(strlen(buf)>=title_size) { // Get Title + title=QString(buf).mid(title_offset,title_length); + cartnum=cartname.toUInt(&cart_ok); + if(cart_ok|| + ((!label_cart.isEmpty())&& + (cartname==label_cart))|| + ((!track_cart.isEmpty())&& + (cartname==track_cart))) { + sql=QString().sprintf("insert into `%s` \ + set ID=%d,START_HOUR=%d,START_SECS=%d,\ + CART_NUMBER=%u,TITLE=\"%s\",LENGTH=%d,\ + EXT_DATA=\"%s\",EXT_EVENT_ID=\"%s\",\ + EXT_ANNC_TYPE=\"%s\",EXT_CART_NAME=\"%s\"", + (const char *)dest_table, + line_id++, + start_hour, + 60*start_minutes+ + start_seconds, + cartnum, + (const char *) + RDEscapeString(title), + cartlen, + (const char *)data_buf, + (const char *)eventid_buf, + (const char *)annctype_buf, + (const char *)cartname); + q=new RDSqlQuery(sql); + delete q; + // + // Insert Break + // + if(insert_break) { + if(break_first) { + sql=QString(). + sprintf("update `%s` set INSERT_BREAK=\"Y\",\ + INSERT_FIRST=%d where ID=%d", + (const char *)dest_table, + RDEventLine::InsertBreak,line_id-1); + } + else { + sql=QString(). + sprintf("update `%s` set INSERT_BREAK=\"Y\" \ + where ID=%d", + (const char *)dest_table,line_id-1); + + } + q=new RDSqlQuery(sql); + delete q; + } + // + // Insert Track + // + if(insert_track) { + if(track_first) { + sql=QString(). + sprintf("update `%s` set INSERT_TRACK=\"Y\",\ + TRACK_STRING=\"%s\",\ + INSERT_FIRST=%d where ID=%d", + (const char *)dest_table, + (const char *)track_label, + RDEventLine::InsertTrack,line_id-1); + } + else { + sql=QString(). + sprintf("update `%s` set INSERT_TRACK=\"Y\",\ + TRACK_STRING=\"%s\" where ID=%d", + (const char *)dest_table, + (const char *)track_label, + line_id-1); + } + q=new RDSqlQuery(sql); + delete q; + } + insert_break=false; + break_first=false; + insert_track=false; + track_first=false; + insert_found=false; + line_used=true; + } + } + } + } + } + } + } + } + } + } + } + } + if(!line_used) { + // + // Look for Break and Track Strings + // + str_buf=str_buf.stripWhiteSpace(); + if(!break_str.isEmpty()) { + if(str_buf.contains(break_str)) { + insert_break=true; + if(!insert_found) { + break_first=true; + insert_found=true; + } + // q=new RDSqlQuery(sql); + } + } + if(!track_str.isEmpty()) { + if(str_buf.contains(track_str)) { + insert_track=true; + track_label=str_buf; + if(!insert_found) { + track_first=true; + insert_found=true; + } + } + } + } + } + + // + // Cleanup + // + fclose(infile); + return true; +} + + +bool RDSvc::generateLog(const QDate &date,const QString &logname, + const QString &nextname,QString *report) +{ + QString sql; + RDSqlQuery *q; + RDClock clock; + + if((!date.isValid()||logname.isEmpty())) { + return false; + } + + emit generationProgress(0); + + // + // Generate Log Structure + // + QString purge_date; + if(defaultLogShelflife()>=0) { + purge_date=date.addDays(defaultLogShelflife()).toString("yyyy-MM-dd"); + } + sql=QString().sprintf("select NAME from LOGS where NAME=\"%s\"", + (const char *)RDEscapeString(logname)); + q=new RDSqlQuery(sql); + if(q->first()) { // Already Exists + delete q; + sql=QString().sprintf("update LOGS set SERVICE=\"%s\",\ + DESCRIPTION=\"%s\",ORIGIN_USER=\"%s\",\ + ORIGIN_DATETIME=now(),LINK_DATETIME=now(),\ + MODIFIED_DATETIME=now(),START_DATE=null,\ + END_DATE=null,NEXT_ID=0", + (const char *)RDEscapeString(svc_name), + (const char *)RDEscapeString(RDDateDecode(descriptionTemplate(),date)), + "RDLogManager"); + if(!purge_date.isEmpty()) { + sql+=(",PURGE_DATE=\""+purge_date+"\""); + } + sql+=(" where NAME=\""+RDEscapeString(logname)+"\""); + + q=new RDSqlQuery(sql); + delete q; + sql=QString("drop table `")+RDLog::tableName(logname)+"`"; + q=new RDSqlQuery(sql); + delete q; + } + else { // Doesn't exist + delete q; + sql=QString().sprintf("insert into LOGS set NAME=\"%s\",\ + SERVICE=\"%s\",DESCRIPTION=\"%s\",\ + ORIGIN_USER=\"%s\",ORIGIN_DATETIME=now(),\ + LINK_DATETIME=now(),MODIFIED_DATETIME=now(),\ + PURGE_DATE=\"%s\"", + (const char *)RDEscapeString(logname), + (const char *)RDEscapeString(svc_name), + (const char *)RDEscapeString(RDDateDecode(descriptionTemplate(),date)), + "RDLogManager", + (const char *)purge_date); + q=new RDSqlQuery(sql); + delete q; + } + RDCreateLogTable(RDLog::tableName(logname)); + // RDCreateLogTable(QString().sprintf("%s_LOG",(const char *)logname_esc)); + emit generationProgress(1); + + // + // Generate Events + // + for(int i=0;i<24;i++) { + sql=QString().sprintf("select CLOCK%d from SERVICES where NAME=\"%s\"", + 24*(date.dayOfWeek()-1)+i, + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + if(q->first()) { + if((!q->value(0).isNull())&&(!q->value(0).toString().isEmpty())) { + clock.setName(q->value(0).toString()); + clock.load(); + clock.generateLog(i,logname,svc_name,report); + clock.clear(); + } + } + delete q; + emit generationProgress(1+i); + } + + // + // Get Current Count + // + int count; + sql=QString("select COUNT from `")+RDLog::tableName(logname)+"` order by COUNT desc"; + q=new RDSqlQuery(sql); + if(q->first()) { + count=q->value(0).toInt()+1; + } + else { + count=0; + } + delete q; + + // + // Log Chain To + // + if(chainto()) { + sql=QString("insert into `")+RDLog::tableName(logname)+"` set "+ + QString().sprintf("ID=%d,COUNT=%d,TYPE=%d,",count,count,RDLogLine::Chain)+ + QString().sprintf("SOURCE=%d,TRANS_TYPE=%d,",RDLogLine::Template, + RDLogLine::Segue)+ + "LABEL=\""+RDEscapeString(nextname)+"\""; + q=new RDSqlQuery(sql); + delete q; + count ++; + } + + RDLog *log=new RDLog(logname); + log->updateLinkQuantity(RDLog::SourceMusic); + log->setLinkState(RDLog::SourceMusic,false); + log->updateLinkQuantity(RDLog::SourceTraffic); + log->setLinkState(RDLog::SourceTraffic,false); + log->setNextId(count); + log->setAutoRefresh(autoRefresh()); + delete log; + + return true; +} + + +bool RDSvc::linkLog(RDSvc::ImportSource src,const QDate &date, + const QString &logname,QString *report) +{ + QString sql; + RDSqlQuery *q; + QString autofill_errors; + + emit generationProgress(0); + + // + // Load ParserStrings + // + QString break_str; + QString track_str; + QString label_cart; + QString track_cart; + GetParserStrings(src,&break_str,&track_str,&label_cart,&track_cart); + + // + // Import File + // + QString import_name=QString("IMPORT_")+svc_name+"_"+date.toString("yyyyMMdd"); + + import_name.replace(" ","_"); + if(!import(src,date,breakString(),trackString(src),import_name)) { + return false; + } + + // + // Calculate Source + // + RDLogLine::Type src_type=RDLogLine::UnknownType; + RDLog::Source link_src=RDLog::SourceMusic; + switch(src) { + case RDSvc::Music: + src_type=RDLogLine::MusicLink; + link_src=RDLog::SourceMusic; + break; + + case RDSvc::Traffic: + src_type=RDLogLine::TrafficLink; + link_src=RDLog::SourceTraffic; + break; + } + RDLog *log=new RDLog(logname); + int current_link=0; + int total_links=log->linkQuantity(link_src); + + // + // Iterate Through the Log + // + RDLogEvent *src_event=new RDLogEvent(RDLog::tableName(logname)); + RDLogEvent *dest_event=new RDLogEvent(RDLog::tableName(logname)); + src_event->load(); + RDLogLine *logline=NULL; + for(int i=0;i<src_event->size();i++) { + logline=src_event->logLine(i); + if(logline->type()==src_type) { + RDEventLine *e=new RDEventLine(); + e->setName(logline->linkEventName()); + e->load(); + e->linkLog(dest_event,dest_event->nextId(),svc_name,logline,track_str, + label_cart,track_cart,import_name,&autofill_errors); + delete e; + emit generationProgress(1+(24*current_link++)/total_links); + } + else { + dest_event->insert(dest_event->size(),1,true); + *(dest_event->logLine(dest_event->size()-1))=*logline; + dest_event->logLine(dest_event->size()-1)->setId(dest_event->nextId()); + } + } + dest_event->save(); + + // + // Update the Log Link Status + // + log->setLinkState(link_src,true); + if(link_src==RDLog::SourceMusic) { + log->updateLinkQuantity(RDLog::SourceTraffic); + } + QDateTime current_datetime= + QDateTime(QDate::currentDate(),QTime::currentTime()); + log->setLinkDatetime(current_datetime); + log->setModifiedDatetime(current_datetime); + delete log; + + // + // Generate Missing Event and Skipped Events Report + // + QString cartname; + QString missing_report; + dest_event->validate(&missing_report,date); + bool event=false; + QString link_report=tr("The following events were not placed:\n"); + sql=QString().sprintf("select `%s`.START_HOUR,`%s`.START_SECS,\ + `%s`.CART_NUMBER,CART.TITLE from `%s` LEFT JOIN CART\ + ON `%s`.CART_NUMBER=CART.NUMBER \ + where `%s`.EVENT_USED=\"N\"", + (const char *)import_name,(const char *)import_name, + (const char *)import_name,(const char *)import_name, + (const char *)import_name,(const char *)import_name); + q=new RDSqlQuery(sql); + while(q->next()) { + event=true; + if(q->value(3).toString().isEmpty()) { + cartname=tr("[unknown cart]"); + } + else { + cartname=q->value(3).toString(); + } + link_report+= + QString().sprintf(" %s - %06u - %s\n", + (const char *)RDSvc::timeString(q->value(0).toInt(), + q->value(1).toInt()), + q->value(2).toUInt(), + (const char *)cartname); + } + delete q; + link_report+="\n"; + + // + // Assemble Exception Report + // + *report=""; + if(!autofill_errors.isEmpty()) { + *report+=tr("Event Fill Errors\n"); + *report+=autofill_errors; + *report+="\n"; + } + *report+=missing_report; + if(event) { + *report+=link_report; + } + + // + // Clean Up + // + emit generationProgress(24); + delete src_event; + delete dest_event; + // printf("Import Table: %s\n",(const char *)import_name); + sql=QString().sprintf("drop table `%s`",(const char *)import_name); + q=new RDSqlQuery(sql); + delete q; + + return true; +} + + +void RDSvc::clearLogLinks(RDSvc::ImportSource src,const QDate &date, + const QString &logname) +{ + std::vector<int> cleared_ids; + RDLogLine::Type event_type=RDLogLine::UnknownType; + RDLogLine::Source event_source=RDLogLine::Manual; + switch(src) { + case RDSvc::Music: + event_type=RDLogLine::MusicLink; + event_source=RDLogLine::Music; + break; + + case RDSvc::Traffic: + event_type=RDLogLine::TrafficLink; + event_source=RDLogLine::Traffic; + break; + } + + RDLogEvent *src_event=new RDLogEvent(RDLog::tableName(logname)); + RDLogEvent *dest_event=new RDLogEvent(RDLog::tableName(logname)); + src_event->load(); + RDLogLine *logline=NULL; + for(int i=0;i<src_event->size();i++) { + logline=src_event->logLine(i); + if((logline->linkId()>=0)&&(logline->source()==event_source)) { + if(CheckId(&cleared_ids,logline->linkId())) { + dest_event->insert(dest_event->size(),1); + RDLogLine *lline=dest_event->logLine(dest_event->size()-1); + lline->setId(dest_event->nextId()); + lline->setStartTime(RDLogLine::Logged,logline->linkStartTime()); + lline->setType(event_type); + if(logline->linkEmbedded()) { + lline->setSource(RDLogLine::Music); + } + else { + lline->setSource(RDLogLine::Template); + } + lline->setTransType(logline->transType()); + lline->setLinkEventName(logline->linkEventName()); + lline->setLinkStartTime(logline->linkStartTime()); + lline->setLinkLength(logline->linkLength()); + lline->setLinkStartSlop(logline->linkStartSlop()); + lline->setLinkEndSlop(logline->linkEndSlop()); + lline->setLinkId(logline->linkId()); + lline->setLinkEmbedded(logline->linkEmbedded()); + } + } + else { + dest_event->insert(dest_event->size(),1); + *(dest_event->logLine(dest_event->size()-1))=*logline; + dest_event->logLine(dest_event->size()-1)->setId(dest_event->nextId()); + } + } + dest_event->save(); + delete src_event; + delete dest_event; +} + + +void RDSvc::create(const QString exemplar) const +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + if(exemplar.isEmpty()) { // Create Empty Service + sql=QString("insert into SERVICES set NAME=\"")+ + RDEscapeString(svc_name)+"\","+ + "NAME_TEMPLATE=\""+RDEscapeString(svc_name)+"-%m%d\","+ + "DESCRIPTION_TEMPLATE=\""+RDEscapeString(svc_name)+" log for %d/%m/%Y\""; + q=new RDSqlQuery(sql); + delete q; + + // + // Create Group Audio Perms + // + sql="select NAME from GROUPS"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into AUDIO_PERMS set\ + GROUP_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *) + RDEscapeString(q->value(0).toString()), + (const char *)RDEscapeString(svc_name)); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Create Station Perms + // + sql="select NAME from STATIONS"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into SERVICE_PERMS set\ + STATION_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *) + RDEscapeString(q->value(0).toString()), + (const char *)RDEscapeString(svc_name)); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + } + else { // Base on Existing Service + sql=QString().sprintf("select NAME_TEMPLATE,DESCRIPTION_TEMPLATE,\ + CHAIN_LOG,AUTO_REFRESH,\ + ELR_SHELFLIFE,TFC_PATH,TFC_WIN_PATH,\ + TFC_CART_OFFSET,TFC_CART_LENGTH,\ + TFC_START_OFFSET,TFC_START_LENGTH,\ + TFC_LENGTH_OFFSET,TFC_LENGTH_LENGTH,\ + TFC_HOURS_OFFSET,TFC_HOURS_LENGTH,\ + TFC_MINUTES_OFFSET,TFC_MINUTES_LENGTH,\ + TFC_SECONDS_OFFSET,TFC_SECONDS_LENGTH,\ + TFC_DATA_OFFSET,TFC_DATA_LENGTH,\ + TFC_EVENT_ID_OFFSET,TFC_EVENT_ID_LENGTH,\ + TFC_ANNC_TYPE_OFFSET,TFC_ANNC_TYPE_LENGTH,\ + MUS_PATH,MUS_WIN_PATH,\ + MUS_CART_OFFSET,MUS_CART_LENGTH,\ + MUS_START_OFFSET,MUS_START_LENGTH,\ + MUS_LENGTH_OFFSET,MUS_LENGTH_LENGTH,\ + MUS_HOURS_OFFSET,MUS_HOURS_LENGTH,\ + MUS_MINUTES_OFFSET,MUS_MINUTES_LENGTH,\ + MUS_SECONDS_OFFSET,MUS_SECONDS_LENGTH,\ + MUS_DATA_OFFSET,MUS_DATA_LENGTH,\ + MUS_EVENT_ID_OFFSET,MUS_EVENT_ID_LENGTH,\ + MUS_ANNC_TYPE_OFFSET,MUS_ANNC_TYPE_LENGTH,"); + for(int i=0;i<168;i++) { + sql+=QString().sprintf("CLOCK%d,",i); + } + sql=sql.left(sql.length()-1); + sql+=QString().sprintf(" from SERVICES where NAME=\"%s\"", + (const char *)exemplar); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("insert into SERVICES set\ + NAME_TEMPLATE=\"%s\",\ + DESCRIPTION_TEMPLATE=\"%s\",\ + CHAIN_LOG=\"%s\",\ + AUTO_REFRESH=\"%s\",ELR_SHELFLIFE=%d,\ + TFC_PATH=\"%s\",TFC_WIN_PATH=\"%s\",\ + TFC_CART_OFFSET=%d,TFC_CART_LENGTH=%d,\ + TFC_START_OFFSET=%d,TFC_START_LENGTH=%d,\ + TFC_LENGTH_OFFSET=%d,TFC_LENGTH_LENGTH=%d,\ + TFC_HOURS_OFFSET=%d,TFC_HOURS_LENGTH=%d,\ + TFC_MINUTES_OFFSET=%d,TFC_MINUTES_LENGTH=%d,\ + TFC_SECONDS_OFFSET=%d,TFC_SECONDS_LENGTH=%d,\ + TFC_DATA_OFFSET=%d,TFC_DATA_LENGTH=%d,\ + TFC_EVENT_ID_OFFSET=%d,TFC_EVENT_ID_LENGTH=%d,\ + TFC_ANNC_TYPE_OFFSET=%d,TFC_ANNC_TYPE_LENGTH=%d,\ + MUS_PATH=\"%s\",MUS_WIN_PATH=\"%s\",\ + MUS_CART_OFFSET=%d,MUS_CART_LENGTH=%d,\ + MUS_START_OFFSET=%d,MUS_START_LENGTH=%d,\ + MUS_LENGTH_OFFSET=%d,MUS_LENGTH_LENGTH=%d,\ + MUS_HOURS_OFFSET=%d,MUS_HOURS_LENGTH=%d,\ + MUS_MINUTES_OFFSET=%d,MUS_MINUTES_LENGTH=%d,\ + MUS_SECONDS_OFFSET=%d,MUS_SECONDS_LENGTH=%d,\ + MUS_DATA_OFFSET=%d,MUS_DATA_LENGTH=%d,\ + MUS_EVENT_ID_OFFSET=%d,MUS_EVENT_ID_LENGTH=%d,\ + MUS_ANNC_TYPE_OFFSET=%d,MUS_ANNC_TYPE_LENGTH=%d,\ + NAME=\"%s\",", + (const char *) + RDEscapeString(q->value(0).toString()), + (const char *) + RDEscapeString(q->value(1).toString()), + (const char *)q->value(2).toString(), + (const char *)q->value(3).toString(), + q->value(4).toInt(), + (const char *)q->value(5).toString(), + (const char *)q->value(6).toString(), + q->value(7).toInt(), + q->value(8).toInt(), + q->value(9).toInt(), + q->value(10).toInt(), + q->value(11).toInt(), + q->value(12).toInt(), + q->value(13).toInt(), + q->value(14).toInt(), + q->value(15).toInt(), + q->value(16).toInt(), + q->value(17).toInt(), + q->value(18).toInt(), + q->value(19).toInt(), + q->value(20).toInt(), + q->value(21).toInt(), + q->value(22).toInt(), + q->value(23).toInt(), + q->value(24).toInt(), + (const char *)q->value(25).toString(), + (const char *)q->value(26).toString(), + q->value(27).toInt(), + q->value(28).toInt(), + q->value(29).toInt(), + q->value(30).toInt(), + q->value(31).toInt(), + q->value(32).toInt(), + q->value(33).toInt(), + q->value(34).toInt(), + q->value(35).toInt(), + q->value(36).toInt(), + q->value(37).toInt(), + q->value(38).toInt(), + q->value(39).toInt(), + q->value(40).toInt(), + q->value(41).toInt(), + q->value(42).toInt(), + q->value(43).toInt(), + q->value(44).toInt(), + (const char *)RDEscapeString(svc_name)); + for(int i=0;i<168;i++) { + sql+=QString().sprintf("CLOCK%d=\"%s\",", + i,(const char *)q->value(45+i).toString()); + } + sql=sql.left(sql.length()-1); + q=new RDSqlQuery(sql); + delete q; + } + + // + // Clone Audio Perms + // + sql=QString().sprintf("select GROUP_NAME from AUDIO_PERMS\ + where SERVICE_NAME=\"%s\"", + (const char *)RDEscapeString(exemplar)); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into AUDIO_PERMS set\ + GROUP_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *) + RDEscapeString(q->value(0).toString()), + (const char *)RDEscapeString(svc_name)); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone Service Perms + // + sql=QString().sprintf("select STATION_NAME from SERVICE_PERMS\ + where SERVICE_NAME=\"%s\"", + (const char *)RDEscapeString(exemplar)); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into SERVICE_PERMS set\ + STATION_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *) + RDEscapeString(q->value(0).toString()), + (const char *)RDEscapeString(svc_name)); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone Autofill List + // + sql=QString().sprintf("select CART_NUMBER from AUTOFILLS\ + where SERVICE=\"%s\"", + (const char *)RDEscapeString(exemplar)); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into AUTOFILLS set\ + CART_NUMBER=%u,SERVICE=\"%s\"", + q->value(0).toUInt(), + (const char *)RDEscapeString(svc_name)); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone Clock Perms + // + sql=QString().sprintf("select CLOCK_NAME from CLOCK_PERMS\ + where SERVICE_NAME=\"%s\"", + (const char *)RDEscapeString(exemplar)); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into CLOCK_PERMS set\ + CLOCK_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *) + RDEscapeString(q->value(0).toString()), + (const char *)RDEscapeString(svc_name)); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone Event Perms + // + sql=QString().sprintf("select EVENT_NAME from EVENT_PERMS\ + where SERVICE_NAME=\"%s\"", + (const char *)RDEscapeString(exemplar)); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into EVENT_PERMS set\ + EVENT_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *) + RDEscapeString(q->value(0).toString()), + (const char *)RDEscapeString(svc_name)); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + } + + // + // Create Service Reconciliation Table + // + sql=RDCreateReconciliationTableSql(svc_name); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDSvc::remove() const +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + QString logname; + + sql=QString().sprintf("delete from AUDIO_PERMS where SERVICE_NAME=\"%s\"", + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + delete q; + sql= + QString().sprintf("delete from SERVICE_PERMS where SERVICE_NAME=\"%s\"", + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("update RDAIRPLAY set DEFAULT_SERVICE=\"\" \ + where DEFAULT_SERVICE=\"%s\"", + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + delete q; + sql= + QString().sprintf("delete from EVENT_PERMS where SERVICE_NAME=\"%s\"", + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + delete q; + sql= + QString().sprintf("delete from CLOCK_PERMS where SERVICE_NAME=\"%s\"", + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + delete q; + sql= + QString().sprintf("delete from AUTOFILLS where SERVICE=\"%s\"", + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + delete q; + sql= + QString().sprintf("delete from REPORT_SERVICES where SERVICE_NAME=\"%s\"", + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from SERVICES where NAME=\"%s\"", + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("select NAME from LOGS where SERVICE=\"%s\"", + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + while(q->next()) { + logname=q->value(0).toString(); + logname.replace(" ","_"); + sql=QString("drop table `")+RDLog::tableName(logname)+"`"; + q1=new RDSqlQuery(sql); + delete q1; + sql=QString().sprintf("drop table `%s_REC`",(const char *)logname); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + QString tablename=svc_name; + tablename.replace(" ","_"); + sql=QString().sprintf("drop table `%s_SRT`",(const char *)tablename); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("drop table `%s_STACK`",(const char *)tablename); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("delete from LOGS where SERVICE=\"%s\"", + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +QString RDSvc::xml() const +{ + QString sql; + RDSqlQuery *q; + QString ret; +#ifndef WIN32 + sql="select DESCRIPTION from SERVICES where NAME=\""+ + RDEscapeString(svc_name)+"\""; + + q=new RDSqlQuery(sql); + if(q->first()) { + ret+=" <service>\n"; + ret+=" "+RDXmlField("name",svc_name); + ret+=" "+RDXmlField("description",q->value(0).toString()); + ret+=" </service>\n"; + } + delete q; +#endif // WIN32 + return ret; +} + + +QString RDSvc::svcTableName(const QString &svc_name) +{ + QString ret=svc_name; + ret.replace(" ","_"); + + return ret+"_SRT"; +} + + +QString RDSvc::timeString(int hour,int secs) +{ + return QString().sprintf("%02d:%02d:%02d",hour,secs/60,secs%60); +} + + +QString RDSvc::SourceString(ImportSource src) const +{ + QString fieldname; + switch(src) { + case RDSvc::Traffic: + fieldname="TFC_"; + break; + + case RDSvc::Music: + fieldname="MUS_"; + break; + } + return fieldname; +} + + +QString RDSvc::OsString(ImportOs os) const +{ + QString fieldname; + switch(os) { + case RDSvc::Linux: + fieldname=""; + break; + + case RDSvc::Windows: + fieldname="WIN_"; + break; + } + return fieldname; +} + + +QString RDSvc::FieldString(ImportField field) const +{ + QString fieldname; + switch(field) { + case RDSvc::CartNumber: + fieldname="CART_"; + break; + + case RDSvc::Title: + fieldname="TITLE_"; + break; + + case RDSvc::StartHours: + fieldname="HOURS_"; + break; + + case RDSvc::StartMinutes: + fieldname="MINUTES_"; + break; + + case RDSvc::StartSeconds: + fieldname="SECONDS_"; + break; + + case RDSvc::LengthHours: + fieldname="LEN_HOURS_"; + break; + + case RDSvc::LengthMinutes: + fieldname="LEN_MINUTES_"; + break; + + case RDSvc::LengthSeconds: + fieldname="LEN_SECONDS_"; + break; + + case RDSvc::ExtData: + fieldname="DATA_"; + break; + + case RDSvc::ExtEventId: + fieldname="EVENT_ID_"; + break; + + case RDSvc::ExtAnncType: + fieldname="ANNC_TYPE_"; + break; + } + return fieldname; +} + + +void RDSvc::SetRow(const QString ¶m,QString value) const +{ + RDSqlQuery *q; + QString sql; + + value.replace("\\","\\\\"); // Needed to preserve Windows pathnames + sql=QString().sprintf("UPDATE SERVICES SET %s=\"%s\" WHERE NAME=\"%s\"", + (const char *)param, + (const char *)value, + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDSvc::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE SERVICES SET %s=%d WHERE NAME=\"%s\"", + (const char *)param, + value, + (const char *)RDEscapeString(svc_name)); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDSvc::GetParserStrings(ImportSource src,QString *break_str, + QString *track_str,QString *label_cart, + QString *track_cart) +{ + QString src_str=SourceString(src); + QString sql=QString().sprintf("select %sBREAK_STRING,%sTRACK_STRING,\ + %sLABEL_CART,%sTRACK_CART \ + from SERVICES where NAME=\"%s\"", + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)src_str, + (const char *)RDEscapeString(svc_name)); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + *break_str=q->value(0).toString(); + *track_str=q->value(1).toString(); + *label_cart=q->value(2).toString(); + *track_cart=q->value(3).toString(); + } + else { + *break_str=""; + *track_str=""; + *label_cart=""; + *track_cart=""; + } + delete q; +} + + +bool RDSvc::CheckId(std::vector<int> *v,int value) +{ + for(unsigned i=0;i<v->size();i++) { + if(v->at(i)==value) { + return false; + } + } + v->push_back(value); + return true; +} diff --git a/lib/rdsvc.h b/lib/rdsvc.h new file mode 100644 index 00000000..909ec1eb --- /dev/null +++ b/lib/rdsvc.h @@ -0,0 +1,114 @@ +// rdsvc.h +// +// Abstract a Rivendell Service +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsvc.h,v 1.26.8.3.2.1 2014/05/20 22:39:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <vector> + +#include <qobject.h> +#include <qsqldatabase.h> + +#ifndef RDSVC_H +#define RDSVC_H + +class RDSvc : public QObject +{ + Q_OBJECT + public: + enum ImportOs {Linux=0,Windows=1}; + enum ImportSource {Traffic=0,Music=1}; + enum ImportField {CartNumber=0,ExtData=3,ExtEventId=4,ExtAnncType=5, + Title=6,StartHours=7,StartMinutes=8,StartSeconds=9, + LengthHours=10,LengthMinutes=11,LengthSeconds=12}; + RDSvc(QString svcname,QObject *parent=0,const char *name=0); + QString name() const; + bool exists() const; + QString description() const; + void setDescription(const QString &desc) const; + QString programCode() const; + void setProgramCode(const QString &str) const; + QString nameTemplate() const; + void setNameTemplate(const QString &str) const; + QString descriptionTemplate() const; + void setDescriptionTemplate(const QString &str) const; + QString trackGroup() const; + void setTrackGroup(const QString &group) const; + QString autospotGroup() const; + void setAutospotGroup(const QString &group) const; + bool autoRefresh() const; + void setAutoRefresh(bool state); + int defaultLogShelflife() const; + void setDefaultLogShelflife(int days) const; + int elrShelflife() const; + void setElrShelflife(int days) const; + bool chainto() const; + void setChainto(bool state) const; + QString importTemplate(ImportSource src) const; + void setImportTemplate(ImportSource src,const QString &str) const; + QString breakString() const; + void setBreakString(const QString &str); + QString trackString(ImportSource src) const; + void setTrackString(ImportSource src,const QString &str); + QString labelCart(ImportSource src) const; + void setLabelCart(ImportSource src,const QString &str); + QString trackCart(ImportSource src) const; + void setTrackCart(ImportSource src,const QString &str); + QString importPath(ImportSource src,ImportOs os) const; + void setImportPath(ImportSource src,ImportOs os,const QString &path) const; + QString preimportCommand(ImportSource src,ImportOs os) const; + void setPreimportCommand(ImportSource src,ImportOs os, + const QString &path) const; + int importOffset(ImportSource src,ImportField field) const; + void setImportOffset(ImportSource src,ImportField field,int offset) const; + int importLength(ImportSource src,ImportField field) const; + void setImportLength(ImportSource src,ImportField field,int len) const; + QString importFilename(ImportSource src,const QDate &date) const; + bool import(ImportSource src,const QDate &date,const QString &break_str, + const QString &track_str,const QString &dest_table) + const; + bool generateLog(const QDate &date,const QString &logname, + const QString &nextname,QString *report); + bool linkLog(RDSvc::ImportSource src,const QDate &date, + const QString &logname,QString *report); + void clearLogLinks(RDSvc::ImportSource src,const QDate &date, + const QString &logname); + void create(const QString exemplar) const; + void remove() const; + QString xml() const; + static QString timeString(int hour,int secs); + static QString svcTableName(const QString &svc_name); + + signals: + void generationProgress(int step); + + private: + QString SourceString(ImportSource src) const; + QString OsString(ImportOs os) const; + QString FieldString(ImportField field) const; + void SetRow(const QString ¶m,QString value) const; + void SetRow(const QString ¶m,int value) const; + void GetParserStrings(ImportSource src,QString *break_str,QString *track_str, + QString *label_cart,QString *track_cart); + bool CheckId(std::vector<int> *v,int value); + QString svc_name; +}; + + +#endif diff --git a/lib/rdsystem.cpp b/lib/rdsystem.cpp new file mode 100644 index 00000000..98b75e84 --- /dev/null +++ b/lib/rdsystem.cpp @@ -0,0 +1,160 @@ +// rdsystem.cpp +// +// System-wide Rivendell settings +// +// (C) Copyright 2009 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsystem.cpp,v 1.4.8.1 2012/11/26 20:19:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rd.h> +#include <rddb.h> +#include <rdconf.h> +#include <rdsystem.h> + +RDSystem::RDSystem() +{ +} + + +unsigned RDSystem::sampleRate() const +{ + return GetValue("SAMPLE_RATE").toUInt(); +} + + +void RDSystem::setSampleRate(unsigned rate) const +{ + SetRow("SAMPLE_RATE",rate); +} + + +bool RDSystem::allowDuplicateCartTitles() const +{ + bool ret=false; + QString sql; + RDSqlQuery *q; + + sql="select DUP_CART_TITLES from SYSTEM"; + q=new RDSqlQuery(sql); + if(q->first()) { + ret=RDBool(q->value(0).toString()); + } + delete q; + return ret; +} + + +void RDSystem::setAllowDuplicateCartTitles(bool state) const +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("update SYSTEM set DUP_CART_TITLES=\"%s\"", + (const char *)RDYesNo(state)); + q=new RDSqlQuery(sql); + delete q; +} + + +unsigned RDSystem::maxPostLength() const +{ + unsigned ret; + + QString sql="select MAX_POST_LENGTH from SYSTEM"; + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + ret=q->value(0).toUInt(); + } + else { + ret=RD_DEFAULT_MAX_POST_LENGTH; + } + delete q; + return ret; +} + + +void RDSystem::setMaxPostLength(unsigned bytes) const +{ + QString sql=QString().sprintf("update SYSTEM set MAX_POST_LENGTH=%u",bytes); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; +} + + +QString RDSystem::isciXreferencePath() const +{ + return GetValue("ISCI_XREFERENCE_PATH").toString(); +} + + +void RDSystem::setIsciXreferencePath(const QString &str) const +{ + SetRow("ISCI_XREFERENCE_PATH",str); +} + + +QString RDSystem::tempCartGroup() const +{ + return GetValue("TEMP_CART_GROUP").toString(); +} + + +void RDSystem::setTempCartGroup(const QString &str) const +{ + SetRow("TEMP_CART_GROUP",str); +} + + +QVariant RDSystem::GetValue(const QString &field) const +{ + QVariant ret; + QString sql=QString().sprintf("select %s from SYSTEM", + (const char *)field); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + ret=q->value(0); + } + delete q; + return ret; +} + + +void RDSystem::SetRow(const QString ¶m,QString value) const +{ + RDSqlQuery *q; + QString sql; + + value.replace("\\","\\\\"); // Needed to preserve Windows pathnames + sql=QString().sprintf("update SYSTEM set %s=\"%s\"", + (const char *)param, + (const char *)value); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDSystem::SetRow(const QString ¶m,int value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update SYSTEM set %s=%d", + (const char *)param, + value); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdsystem.h b/lib/rdsystem.h new file mode 100644 index 00000000..23009563 --- /dev/null +++ b/lib/rdsystem.h @@ -0,0 +1,50 @@ +// rdsystem.h +// +// System-wide Rivendell settings +// +// (C) Copyright 2009 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsystem.h,v 1.3.8.1 2012/11/26 20:19:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDSYSTEM_H +#define RDSYSTEM_H + +#include <qvariant.h> + +class RDSystem +{ + public: + RDSystem(); + unsigned sampleRate() const; + void setSampleRate(unsigned rate) const; + bool allowDuplicateCartTitles() const; + void setAllowDuplicateCartTitles(bool state) const; + unsigned maxPostLength() const; + void setMaxPostLength(unsigned bytes) const; + QString isciXreferencePath() const; + void setIsciXreferencePath(const QString &str) const; + QString tempCartGroup() const; + void setTempCartGroup(const QString &str) const; + + private: + QVariant GetValue(const QString &field) const; + void SetRow(const QString ¶m,QString value) const; + void SetRow(const QString ¶m,int value) const; +}; + + +#endif // RDSYSTEM_H diff --git a/lib/rdsystemuser.cpp b/lib/rdsystemuser.cpp new file mode 100644 index 00000000..31dbc733 --- /dev/null +++ b/lib/rdsystemuser.cpp @@ -0,0 +1,104 @@ +// rdsystemuser.cpp +// +// Abstracts a system (non-Rivendell) user. +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsystemuser.cpp,v 1.2.8.1 2012/12/13 22:33:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <syslog.h> + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <pwd.h> + +#include <security/pam_appl.h> + +#include <qstringlist.h> + +#include <rdpam.h> +#include <rdsystemuser.h> + +RDSystemUser::RDSystemUser(const QString &username) +{ + struct passwd *user=NULL; + QStringList fields; + + system_username=username; + system_exists=false; + + if((user=getpwnam(username))==NULL) { + return; + } + system_uid=user->pw_uid; + system_gid=user->pw_gid; + system_full_name=user->pw_gecos; + system_home_directory=user->pw_dir; + system_shell=user->pw_shell; +} + + +QString RDSystemUser::username() const +{ + return system_username; +} + + +bool RDSystemUser::exists() const +{ + return system_exists; +} + + +uid_t RDSystemUser::uid() const +{ + return system_uid; +} + + +gid_t RDSystemUser::gid() const +{ + return system_gid; +} + + +QString RDSystemUser::fullName() const +{ + return system_full_name; +} + + +QString RDSystemUser::homeDirectory() const +{ + return system_home_directory; +} + + +QString RDSystemUser::shell() const +{ + return system_shell; +} + + +bool RDSystemUser::validatePassword(const QString &pwd) +{ + RDPam *pam=new RDPam("login"); + bool ret=pam->authenticate(system_username,pwd); + delete pam; + return ret; +} diff --git a/lib/rdsystemuser.h b/lib/rdsystemuser.h new file mode 100644 index 00000000..380611aa --- /dev/null +++ b/lib/rdsystemuser.h @@ -0,0 +1,53 @@ +// rdsystemuser.h +// +// Abstracts a system (non-Rivendell) user. +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdsystemuser.h,v 1.2 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDSYSTEMUSER_H +#define RDSYSTEMUSER_H + +#include <qstring.h> + +class RDSystemUser +{ + public: + RDSystemUser(const QString &username); + QString username() const; + bool exists() const; + uid_t uid() const; + gid_t gid() const; + QString fullName() const; + QString homeDirectory() const; + QString shell() const; + bool validatePassword(const QString &pwd); + + private: + QString system_username; + bool system_exists; + uid_t system_uid; + gid_t system_gid; + QString system_full_name; + QString system_home_directory; + QString system_shell; + QString system_password; +}; + + +#endif // RDSYSTEMUSER_H diff --git a/lib/rdtextfile.cpp b/lib/rdtextfile.cpp new file mode 100644 index 00000000..3315f7e7 --- /dev/null +++ b/lib/rdtextfile.cpp @@ -0,0 +1,85 @@ +// rdtextfile.cpp +// +// Spawn an external text file viewer. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtextfile.cpp,v 1.7 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WIN32 +#include <unistd.h> +#endif // WIN32 +#include <stdlib.h> +#include <stdio.h> + +#include <qmessagebox.h> +#include <qprocess.h> + +#include <rdconf.h> +#include <rd.h> +#include <rdtextfile.h> + +bool RDTextFile(const QString &data) +{ + char tmpfile[256]; + QString editor; + + if(getenv("VISUAL")==NULL) { +#ifdef WIN32 + editor=RD_WIN32_EDITOR; +#else + editor=RD_LINUX_EDITOR; +#endif // WIN32 + } + else { + editor=getenv("VISUAL"); + } +#ifdef WIN32 + QString tempfile=QString().sprintf("%s\\rd-%s",(const char *)RDTempDir(), + (const char *)QTime::currentTime().toString("hhmmsszzz")); + FILE *f=fopen(tempfile,"w"); + if(f==NULL) { + QMessageBox::warning(NULL,"File Error","Unable to create temporary file"); + return false; + } + fprintf(f,"%s",(const char *)data); + fclose(f); + QStringList args; + args+=editor; + args+=tempfile; + QProcess *proc=new QProcess(args); + proc->launch(""); + delete proc; +#else + strcpy(tmpfile,"/tmp/rdreportXXXXXX"); + int fd=mkstemp(tmpfile); + if(fd<0) { + QMessageBox::warning(NULL,"File Error","Unable to create temporary file"); + return false; + } + else { + write(fd,data,data.length()); + ::close(fd); + if(fork()==0) { + system(QString().sprintf("%s %s",(const char *)editor,tmpfile)); + unlink(tmpfile); + exit(0); + } + } +#endif // WIN32 + return true; +} diff --git a/lib/rdtextfile.h b/lib/rdtextfile.h new file mode 100644 index 00000000..94e0f229 --- /dev/null +++ b/lib/rdtextfile.h @@ -0,0 +1,31 @@ +// rdtextfile.h +// +// Spawn an external text file viewer. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtextfile.h,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDTEXTFILE_H +#define RDTEXTFILE_H + +#include <qstring.h> + +bool RDTextFile(const QString &data); + + +#endif // RDTEXTFILE_H diff --git a/lib/rdtextvalidator.cpp b/lib/rdtextvalidator.cpp new file mode 100644 index 00000000..69450060 --- /dev/null +++ b/lib/rdtextvalidator.cpp @@ -0,0 +1,64 @@ +// rdtextvalidator.cpp +// +// Validate a string as being valid for a SQL text datatype. +// +// (C) Copyright 2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtextvalidator.cpp,v 1.11 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdtextvalidator.h> + + +RDTextValidator::RDTextValidator(QObject *parent,const char *name,bool allow_quote) + : QValidator(parent,name) +{ + if(!allow_quote) { + banned_chars.push_back(34); // Double Quote + } + banned_chars.push_back(39); // Single Quote + banned_chars.push_back(92); // Backslash Quote + banned_chars.push_back(96); // Apostrophe Quote +} + + +QValidator::State RDTextValidator::validate(QString &input,int &pos) const +{ + char c=input.at(pos-1).latin1(); + for(unsigned i=0;i<banned_chars.size();i++) { + if(banned_chars[i]==c) { + return QValidator::Invalid; + } + } + return QValidator::Acceptable; +} + + +void RDTextValidator::addBannedChar(char c) +{ + banned_chars.push_back(c); +} + + +QString RDTextValidator::stripString(QString str) +{ + str.replace(34,""); // Double Quote + str.replace(39,""); // Single Quote + str.replace(92,""); // Backslash Quote + str.replace(96,""); // Apostrophe Quote + + return str; +} diff --git a/lib/rdtextvalidator.h b/lib/rdtextvalidator.h new file mode 100644 index 00000000..40dae202 --- /dev/null +++ b/lib/rdtextvalidator.h @@ -0,0 +1,45 @@ +// rdtextvalidator.h +// +// Validate a string as being valid for a SQL text datatype. +// +// (C) Copyright 2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtextvalidator.h,v 1.9 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDTEXTVALIDATOR_H +#define RDTEXTVALIDATOR_H + +#include <vector> + +#include <qvalidator.h> + +using namespace std; + +class RDTextValidator : public QValidator +{ + public: + RDTextValidator(QObject *parent=0,const char *name=0,bool allow_quote=false); + QValidator::State validate(QString &input,int &pos) const; + void addBannedChar(char c); + static QString stripString(QString str); + + private: + vector<char> banned_chars; +}; + + +#endif // RDTEXTVALIDATOR_H diff --git a/lib/rdtimeedit.cpp b/lib/rdtimeedit.cpp new file mode 100644 index 00000000..45e5ec6a --- /dev/null +++ b/lib/rdtimeedit.cpp @@ -0,0 +1,506 @@ +// rdtimeedit.cpp +// +// A QTimeEdit with tenth-second precision. +// +// (C) Copyright 2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtimeedit.cpp,v 1.6 2010/10/06 19:24:02 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qfontmetrics.h> + +#include <rdtimeedit.h> + + +RDTimeEdit::RDTimeEdit(QWidget *parent,const char *name) + : QFrame(parent,name) +{ + edit_display=0; + edit_section=0; + edit_read_only=false; + edit_digit=0; + GetSizeHint(); + setFrameStyle(QFrame::StyledPanel|QFrame::Sunken); + setLineWidth(1); + setMidLineWidth(3); + setFocusPolicy(QWidget::StrongFocus); + QPalette p=palette(); + p.setColor(QPalette::Active,QColorGroup::Background, + p.color(QPalette::Active,QColorGroup::Base)); + setPalette(p); + edit_labels[0]=new QLabel("00",this); + edit_labels[0]->setAlignment(Qt::AlignCenter); + edit_labels[1]=new QLabel("00",this); + edit_labels[1]->setAlignment(Qt::AlignCenter); + edit_labels[2]=new QLabel("00",this); + edit_labels[2]->setAlignment(Qt::AlignCenter); + edit_labels[3]=new QLabel("0",this); + edit_labels[3]->setAlignment(Qt::AlignCenter); + edit_sep_labels[0]=new QLabel(":",this); + edit_sep_labels[0]->setAlignment(Qt::AlignCenter); + edit_sep_labels[1]=new QLabel(":",this); + edit_sep_labels[1]->setAlignment(Qt::AlignCenter); + edit_sep_labels[2]=new QLabel(".",this); + edit_sep_labels[2]->setAlignment(Qt::AlignCenter); + edit_up_button= + new RDTransportButton(RDTransportButton::Up,this,"edit_up_button"); + edit_up_button->setFocusPolicy(QWidget::NoFocus); + connect(edit_up_button,SIGNAL(clicked()),this,SLOT(upClickedData())); + edit_down_button= + new RDTransportButton(RDTransportButton::Down,this,"edit_down_button"); + edit_down_button->setFocusPolicy(QWidget::NoFocus); + connect(edit_down_button,SIGNAL(clicked()),this,SLOT(downClickedData())); + setDisplay(RDTimeEdit::Hours|RDTimeEdit::Minutes|RDTimeEdit::Seconds); +} + + +RDTimeEdit::~RDTimeEdit() +{ + for(unsigned i=0;i<4;i++) { + delete edit_labels[i]; + } + for(unsigned i=0;i<3;i++) { + delete edit_sep_labels[i]; + } + delete edit_up_button; + delete edit_down_button; +} + + +QSize RDTimeEdit::sizeHint() const +{ + return QSize(edit_widths[0]+edit_widths[1]+edit_widths[2]+ + edit_sep_widths[0]+edit_sep_widths[1], + edit_height); +} + + +QSizePolicy RDTimeEdit::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +QTime RDTimeEdit::time() const +{ + return QTime(edit_labels[0]->text().toInt(), + edit_labels[1]->text().toInt(), + edit_labels[2]->text().toInt(), + 100*edit_labels[3]->text().toInt()); +} + + +bool RDTimeEdit::isReadOnly() const +{ + return edit_read_only; +} + + +void RDTimeEdit::setFont(const QFont &f) +{ + QFrame::setFont(f); + GetSizeHint(); +} + + +uint RDTimeEdit::display() const +{ + return edit_display; +} + + +void RDTimeEdit::setDisplay(uint disp) +{ + edit_section=-1; + for(unsigned i=0;i<4;i++) { + if((disp&(1<<i))==0) { + edit_labels[i]->hide(); + } + else { + edit_labels[i]->show(); + if(edit_section<0) { + edit_section=i; + } + } + } + for(unsigned i=1;i<4;i++) { + if(((disp&(1<<(i-1)))==0)||((disp&(1<<i))==0)) { + edit_sep_labels[i-1]->hide(); + } + else { + edit_sep_labels[i-1]->show(); + } + } + edit_display=disp; + GetSizeHint(); + setGeometry(geometry()); +} + + +void RDTimeEdit::setGeometry(int x,int y,int w,int h) +{ + QFrame::setGeometry(x,y,w,h); + QFontMetrics fm(font()); + int fy=h-fm.height(); + int fx=contentsRect().x()+fy; + + edit_labels[0]->setGeometry(fx,fy,edit_widths[0],edit_height); + edit_section_x[0]=fx+edit_widths[0]+edit_sep_widths[0]/2; + edit_sep_labels[0]-> + setGeometry(fx+edit_widths[0],fy,edit_sep_widths[0],edit_height); + edit_labels[1]-> + setGeometry(fx+edit_widths[0]+edit_sep_widths[0],fy,edit_widths[1], + edit_height); + edit_section_x[1]= + fx+edit_widths[0]+edit_sep_widths[0]+edit_widths[1]+edit_sep_widths[0]/2; + edit_sep_labels[1]-> + setGeometry(fx+edit_widths[0]+edit_sep_widths[0]+edit_widths[1],fy, + edit_sep_widths[1],edit_height); + edit_labels[2]-> + setGeometry(fx+edit_widths[0]+edit_widths[1]+ + edit_sep_widths[0]+edit_sep_widths[1],fy, + edit_widths[2],edit_height); + + edit_section_x[2]= + fx+edit_widths[0]+edit_sep_widths[0]+edit_sep_widths[1]+ + edit_widths[1]+edit_widths[2]+edit_sep_widths[2]/2; + edit_sep_labels[2]-> + setGeometry(fx+edit_widths[0]+edit_sep_widths[0]+edit_sep_widths[1]+edit_widths[1]+ + edit_widths[2],fy,edit_sep_widths[2],edit_height); + edit_labels[3]-> + setGeometry(fx+edit_widths[0]+edit_widths[1]+ + edit_sep_widths[0]+edit_sep_widths[1]+ + edit_widths[2]+edit_sep_widths[2],fy, + edit_widths[3],edit_height); + int button_x=fx+edit_widths[0]+edit_widths[1]+edit_widths[2]+ + edit_sep_widths[0]+edit_sep_widths[1]+edit_widths[3]+edit_sep_widths[2]+fy; + edit_up_button->setGeometry(button_x,0,w-button_x,h/2); + edit_down_button->setGeometry(button_x,h/2,w-button_x,h/2); +} + + +void RDTimeEdit::setTime(const QTime &time) +{ + edit_labels[0]->setText(time.toString("hh")); + edit_labels[1]->setText(time.toString("mm")); + edit_labels[2]->setText(time.toString("ss")); + edit_labels[3]->setText(QString().sprintf("%d",time.msec()/100)); +} + + +void RDTimeEdit::setReadOnly(bool state) +{ + if(state) { + setFocusPolicy(QWidget::NoFocus); + } + else { + setFocusPolicy(QWidget::StrongFocus); + } + edit_read_only=state; +} + + +void RDTimeEdit::setFocus() +{ + QPalette p=palette(); + for(int i=0;i<4;i++) { + edit_labels[i]->setPalette(p); + } + p.setColor(QPalette::Active,QColorGroup::Background, + p.color(QPalette::Active,QColorGroup::Highlight)); + p.setColor(QPalette::Active,QColorGroup::Foreground, + p.color(QPalette::Active,QColorGroup::HighlightedText)); + edit_labels[edit_section]->setPalette(p); + QFrame::setFocus(); +} + + +void RDTimeEdit::setGeometry(const QRect &r) +{ + setGeometry(r.x(),r.y(),r.width(),r.height()); +} + + +void RDTimeEdit::upClickedData() +{ + int value; + + if(edit_read_only) { + return; + } + setFocus(); + switch(edit_section) { + case 0: + if((value=edit_labels[edit_section]->text().toInt())<23) { + value++; + } + else { + value=0; + } + edit_labels[edit_section]->setText(QString().sprintf("%02d",value)); + emit valueChanged(time()); + break; + + case 1: + case 2: + if((value=edit_labels[edit_section]->text().toInt())<59) { + value++; + } + else { + value=0; + } + edit_labels[edit_section]->setText(QString().sprintf("%02d",value)); + emit valueChanged(time()); + break; + + case 3: + if((value=edit_labels[edit_section]->text().toInt())<9) { + value++; + } + else { + value=0; + } + edit_labels[edit_section]->setText(QString().sprintf("%d",value)); + emit valueChanged(time()); + break; + } +} + + +void RDTimeEdit::downClickedData() +{ + int value; + + if(edit_read_only) { + return; + } + setFocus(); + switch(edit_section) { + case 0: + if((value=edit_labels[edit_section]->text().toInt())>0) { + value--; + } + else { + value=23; + } + edit_labels[edit_section]->setText(QString().sprintf("%02d",value)); + emit valueChanged(time()); + break; + + case 1: + case 2: + if((value=edit_labels[edit_section]->text().toInt())>0) { + value--; + } + else { + value=59; + } + edit_labels[edit_section]->setText(QString().sprintf("%02d",value)); + emit valueChanged(time()); + break; + + case 3: + if((value=edit_labels[edit_section]->text().toInt())>0) { + value--; + } + else { + value=9; + } + edit_labels[edit_section]->setText(QString().sprintf("%d",value)); + emit valueChanged(time()); + break; + } +} + + +void RDTimeEdit::mousePressEvent(QMouseEvent *e) +{ + int section=0; + + if(edit_read_only) { + return; + } + if(e->x()<edit_section_x[0]) { + section=0; + } + else { + if(e->x()<edit_section_x[1]) { + section=1; + } + else { + if(e->x()<edit_section_x[2]) { + section=2; + } + else { + section=3; + } + } + } + if(edit_section!=section) { + edit_section=section; + edit_digit=0; + } + setFocus(); +} + + +void RDTimeEdit::wheelEvent(QWheelEvent *e) +{ + if(e->delta()>=0) { + upClickedData(); + } + else { + downClickedData(); + } + e->accept(); +} + + +void RDTimeEdit::keyPressEvent(QKeyEvent *e) +{ + if(edit_read_only) { + e->ignore(); + return; + } + switch(e->key()) { + case Qt::Key_0: + case Qt::Key_1: + case Qt::Key_2: + case Qt::Key_3: + case Qt::Key_4: + case Qt::Key_5: + case Qt::Key_6: + case Qt::Key_7: + case Qt::Key_8: + case Qt::Key_9: + ProcessKey(e->ascii()); + e->accept(); + break; + + case Qt::Key_Left: + if((edit_section>0)&&(((1<<(edit_section-1))&edit_display)!=0)) { + edit_section--; + edit_digit=0; + setFocus(); + } + e->accept(); + break; + + case Qt::Key_Right: + if(((1<<(edit_section+1))&edit_display)!=0) { + edit_section++; + edit_digit=0; + setFocus(); + } + e->accept(); + break; + + case Qt::Key_Up: + upClickedData(); + break; + + case Qt::Key_Down: + downClickedData(); + break; + + default: + e->ignore(); + break; + } +} + + +void RDTimeEdit::focusInEvent(QFocusEvent *e) +{ + QFrame::focusInEvent(e); +} + + +void RDTimeEdit::focusOutEvent(QFocusEvent *e) +{ + QFrame::focusOutEvent(e); + QPalette p=palette(); + for(int i=0;i<4;i++) { + edit_labels[i]->setPalette(p); + } + QFrame::focusOutEvent(e); +} + + +void RDTimeEdit::GetSizeHint() +{ + QFontMetrics fm(font()); + if((edit_display&RDTimeEdit::Hours)==0) { + edit_widths[0]=0; + edit_sep_widths[0]=0; + } + else { + edit_widths[0]=fm.width("00"); + edit_sep_widths[0]=fm.width(":"); + } + if((edit_display&RDTimeEdit::Minutes)==0) { + edit_widths[1]=0; + edit_sep_widths[1]=0; + } + else { + edit_widths[1]=fm.width("00"); + edit_sep_widths[1]=fm.width(":"); + } + if((edit_display&RDTimeEdit::Seconds)==0) { + edit_widths[2]=0; + edit_sep_widths[2]=0; + } + else { + edit_widths[2]=fm.width("00"); + edit_sep_widths[2]=fm.width("."); + } + if((edit_display&RDTimeEdit::Tenths)==0) { + edit_widths[3]=0; + } + else { + edit_widths[3]=fm.width("0"); + } + edit_height=fm.ascent(); +} + + +void RDTimeEdit::ProcessKey(int key) +{ + int ten; + + switch(edit_section) { + case 0: + case 1: + case 2: + if(edit_digit==0) { + edit_labels[edit_section]->setText(QString().sprintf("0%c",key)); + edit_digit=1; + } + else { + ten=edit_labels[edit_section]->text().toInt(); + if(ten>5) { + ten=0; + } + edit_labels[edit_section]->setText(QString().sprintf("%d%c",ten,key)); + } + break; + + case 3: + edit_labels[3]->setText(QString().sprintf("%c",key)); + break; + } + emit valueChanged(time()); +} diff --git a/lib/rdtimeedit.h b/lib/rdtimeedit.h new file mode 100644 index 00000000..7894aa4d --- /dev/null +++ b/lib/rdtimeedit.h @@ -0,0 +1,86 @@ +// rdtimeedit.h +// +// A QTimeEdit with tenth-second precision. +// +// (C) Copyright 2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtimeedit.h,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDTIMEEDIT_H +#define RDTIMEEDIT_H + +#include <qframe.h> +#include <qdatetime.h> +#include <qlabel.h> + +#include <rdtransportbutton.h> + +class RDTimeEdit : public QFrame +{ + Q_OBJECT + public: + enum Display {Hours=0x01,Minutes=0x02,Seconds=0x04,Tenths=0x08}; + RDTimeEdit(QWidget *parent=0,const char *name=0); + ~RDTimeEdit(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + QTime time() const; + bool isReadOnly() const; + void setFont(const QFont &f); + uint display() const; + void setDisplay(uint disp); + + public slots: + void setTime(const QTime &time); + void setReadOnly(bool state); + void setFocus(); + void setGeometry(int x,int y,int w,int h); + void setGeometry(const QRect &r); + + signals: + void valueChanged(const QTime &time); + + private slots: + void upClickedData(); + void downClickedData(); + + protected: + void mousePressEvent(QMouseEvent *e); + void wheelEvent(QWheelEvent *e); + void keyPressEvent(QKeyEvent *e); + void focusInEvent(QFocusEvent *e); + void focusOutEvent(QFocusEvent *e); + + private: + void GetSizeHint(); + void ProcessKey(int key); + QLabel *edit_labels[4]; + QLabel *edit_sep_labels[3]; + RDTransportButton *edit_up_button; + RDTransportButton *edit_down_button; + int edit_widths[4]; + int edit_section_x[3]; + int edit_sep_widths[3]; + int edit_height; + int edit_section; + int edit_digit; + uint edit_display; + bool edit_read_only; +}; + + +#endif // RDTimeEdit diff --git a/lib/rdtimeengine.cpp b/lib/rdtimeengine.cpp new file mode 100644 index 00000000..822db018 --- /dev/null +++ b/lib/rdtimeengine.cpp @@ -0,0 +1,179 @@ +// rdtimeengine.cpp +// +// An event timer engine. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtimeengine.cpp,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + + +#include <stdlib.h> + +#include <rdtimeengine.h> + +RDTimeEngine::RDTimeEngine(QObject *parent,const char *name) + : QObject(parent,name) +{ + engine_pending_id=-1; + engine_timer=new QTimer(this,"engine_timer"); + engine_time_offset=0; + connect(engine_timer,SIGNAL(timeout()),this,SLOT(timerData())); +} + + +RDTimeEngine::~RDTimeEngine() +{ + clear(); + delete engine_timer; +} + + +void RDTimeEngine::clear() +{ + engine_time_offset=0; + engine_events.clear(); + SetTimer(); +} + + +QTime RDTimeEngine::event(int id) const +{ + for(unsigned i=0;i<engine_events.size();i++) { + for(int j=0;j<engine_events[i].size();j++) { + if(id==engine_events[i].id(j)) { + return engine_events[i].time(); + } + } + } + return QTime(); +} + + +int RDTimeEngine::timeOffset() const +{ + return engine_time_offset; +} + + +void RDTimeEngine::setTimeOffset(int msecs) +{ + engine_time_offset=msecs; + SetTimer(); +} + + +void RDTimeEngine::addEvent(int id,QTime time) +{ + for(unsigned i=0;i<engine_events.size();i++) { + if(time==engine_events[i].time()) { + engine_events[i].addId(id); + SetTimer(); + return; + } + } + engine_events.push_back(RDTimeEvent()); + engine_events.back().setTime(time); + engine_events.back().addId(id); + SetTimer(); +} + + +void RDTimeEngine::removeEvent(int id) +{ + for(unsigned i=0;i<engine_events.size();i++) { + for(int j=0;j<engine_events[i].size();j++) { + if(id==engine_events[i].id(j)) { + if(engine_events[i].size()==1) { + std::vector<RDTimeEvent>::iterator it=engine_events.begin()+i; + engine_events.erase(it,it+1); + } + else { + engine_events[i].removeId(j); + } + SetTimer(); + return; + } + } + } +} + + +int RDTimeEngine::next() const +{ + return engine_pending_id; +} + + +void RDTimeEngine::timerData() +{ + for(unsigned i=0;i<engine_events.size();i++) { + for(int j=0;j<engine_events[i].size();j++) { + if(engine_pending_id==engine_events[i].id(j)) { + EmitEvents(i); + SetTimer(); + return; + } + } + } +} + + +void RDTimeEngine::EmitEvents(int offset) +{ +// for(int i=0;i<engine_events[offset].size();i++) { + for(int i=engine_events[offset].size()-1;i>=0;i--) { + emit timeout(engine_events[offset].id(i)); + } +} + + +void RDTimeEngine::SetTimer() +{ + engine_timer->stop(); + if(engine_events.size()==0) { + return; + } + QTime current_time=QTime::currentTime().addMSecs(engine_time_offset); + int diff=GetNextDiff(current_time,&engine_pending_id); + if(diff!=86400001) { + engine_timer->start(diff,true); + return; + } + diff=GetNextDiff(QTime(),&engine_pending_id); + if(diff!=86400001) { + diff+=(current_time.msecsTo(QTime(23,59,59))+1000); + engine_timer->start(diff,true); + return; + } +} + + +int RDTimeEngine::GetNextDiff(QTime time,int *pending_id) +{ + int diff=86400001; + *pending_id=-1; + + for(unsigned i=0;i<engine_events.size();i++) { + if(((time.msecsTo(engine_events[i].time()))>=0)&& + (time.msecsTo(engine_events[i].time())<diff)) { + diff=time.msecsTo(engine_events[i].time()); + *pending_id=engine_events[i].id(0); + } + } + return diff; +} diff --git a/lib/rdtimeengine.h b/lib/rdtimeengine.h new file mode 100644 index 00000000..f8609ab7 --- /dev/null +++ b/lib/rdtimeengine.h @@ -0,0 +1,68 @@ +// rdtimeengine.h +// +// An event timer engine. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtimeengine.h,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDTIMEENGINE_H +#define RDTIMEENGINE_H + + +#include <vector> + +#include <qwidget.h> +#include <qdatetime.h> +#include <qtimer.h> + +#include <rdtimeevent.h> + + +class RDTimeEngine : public QObject +{ + Q_OBJECT + public: + RDTimeEngine(QObject *parent=0,const char *name=0); + ~RDTimeEngine(); + void clear(); + QTime event(int id) const; + int timeOffset() const; + void setTimeOffset(int msecs); + void addEvent(int id,QTime time); + void removeEvent(int id); + int next() const; + + signals: + void timeout(int id); + + private slots: + void timerData(); + + private: + void EmitEvents(int offset); + void SetTimer(); + int GetNextDiff(QTime time,int *pending_id); + QTimer *engine_timer; + std::vector<RDTimeEvent> engine_events; + int engine_pending_id; + int engine_time_offset; +}; + + +#endif // RDTIMEENGINE_H diff --git a/lib/rdtimeevent.cpp b/lib/rdtimeevent.cpp new file mode 100644 index 00000000..8fd440fa --- /dev/null +++ b/lib/rdtimeevent.cpp @@ -0,0 +1,80 @@ +// rdtimeevent.cpp +// +// A Container Class for RTimeEngine events. +// +// (C) Copyright 2003-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtimeevent.cpp,v 1.3 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +/// + +#include <rdtimeevent.h> + + +RDTimeEvent::RDTimeEvent() +{ + clear(); +} + + +QTime RDTimeEvent::time() const +{ + return event_time; +} + + +void RDTimeEvent::setTime(QTime time) +{ + event_time=time; +} + + +int RDTimeEvent::id(int num) const +{ + return event_id[num]; +} + + +void RDTimeEvent::setId(int num,int id) +{ + event_id[num]=id; +} + + +void RDTimeEvent::addId(int id) +{ + event_id.push_back(id); +} + + +void RDTimeEvent::removeId(int num) +{ + std::vector<int>::iterator it=event_id.begin()+num; + event_id.erase(it,it+1); +} + + +int RDTimeEvent::size() const +{ + return event_id.size(); +} + + +void RDTimeEvent::clear() +{ + event_time=QTime(); + event_id.clear(); +} diff --git a/lib/rdtimeevent.h b/lib/rdtimeevent.h new file mode 100644 index 00000000..378e1ccf --- /dev/null +++ b/lib/rdtimeevent.h @@ -0,0 +1,50 @@ +// rdtimeevent.h +// +// A Container Class for RTimeEngine events. +// +// (C) Copyright 2003-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtimeevent.h,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDTIMEEVENT_H +#define RDTIMEEVENT_H + +#include <vector> + +#include <qdatetime.h> + +class RDTimeEvent +{ + public: + RDTimeEvent(); + QTime time() const; + void setTime(QTime time); + int id(int num) const; + void setId(int num,int id); + void addId(int id); + void removeId(int num); + int size() const; + void clear(); + + private: + QTime event_time; + std::vector<int> event_id; +}; + + +#endif // RDTIMEEVENTy_H diff --git a/lib/rdtransportbutton.cpp b/lib/rdtransportbutton.cpp new file mode 100644 index 00000000..22cd9b32 --- /dev/null +++ b/lib/rdtransportbutton.cpp @@ -0,0 +1,793 @@ +// rdtransportbutton.cpp +// +// An audio transport button widget. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtransportbutton.cpp,v 1.4.10.1 2014/05/27 22:49:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <qpushbutton.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qbitmap.h> +#include <qpointarray.h> +#include <qtimer.h> +#include <qpalette.h> + +#include <rdtransportbutton.h> + + +RDTransportButton::RDTransportButton(RDTransportButton::TransType type, + QWidget *parent,const char *name) + : QPushButton(parent,name) +{ + button_type=type; + button_state=RDTransportButton::Off; + on_color=QColor(RDTRANSPORTBUTTON_DEFAULT_ON_COLOR); + accent_color=QColor(colorGroup().shadow()); + on_cap=new QPixmap(); + drawOnCap(); + off_cap=new QPixmap(); + drawOffCap(); + setPixmap(*off_cap); + + flash_timer=new QTimer(this,"flash_timer"); + connect(flash_timer,SIGNAL(timeout()),this,SLOT(flashClock())); + flash_state=false; +} + + +RDTransportButton::TransType RDTransportButton::getType() const +{ + return button_type; +} + + +void RDTransportButton::setType(RDTransportButton::TransType type) +{ + button_type=type; +} + + +QColor RDTransportButton::onColor() const +{ + return on_color; +} + + +void RDTransportButton::setOnColor(QColor color) +{ + if(color!=on_color) { + on_color=color; + drawOnCap(); + drawOffCap(); + updateCaps(); + } +} + +QColor RDTransportButton::accentColor() const +{ + return accent_color; +} + + +void RDTransportButton::setAccentColor(QColor color) +{ + if(color!=accent_color) { + accent_color=color; + drawOnCap(); + drawOffCap(); + updateCaps(); + } +} + +void RDTransportButton::setState(RDTransportButton::TransState state) +{ + QKeySequence a=accel(); + button_state=state; + switch(button_state) { + case RDTransportButton::On: + flashOff(); + if(isEnabled()) { + setPixmap(*on_cap); + } + break; + case RDTransportButton::Off: + flashOff(); + if(isEnabled()) { + setPixmap(*off_cap); + } + break; + case RDTransportButton::Flashing: + if(isEnabled()) { + flashOn(); + } + break; + } + setAccel(a); +} + + +void RDTransportButton::on() +{ + setState(RDTransportButton::On); +} + + +void RDTransportButton::off() +{ + setState(RDTransportButton::Off); +} + + +void RDTransportButton::flash() +{ + setState(RDTransportButton::Flashing); +} + + +void RDTransportButton::resizeEvent(QResizeEvent *event) +{ + QKeySequence a=accel(); + drawOnCap(); + drawOffCap(); + switch(button_state) { + case RDTransportButton::Off: + setPixmap(*off_cap); + break; + case RDTransportButton::On: + setPixmap(*on_cap); + break; + default: + setPixmap(*off_cap); + break; + } + setAccel(a); +} + + +void RDTransportButton::enabledChange(bool oldEnabled) +{ + QKeySequence a=accel(); + if(isEnabled()&&!oldEnabled) { + setState(button_state); + update(); + } + if(!isEnabled()&&oldEnabled) { +// setPixmap(*grey_cap); + update(); + setAccel(a); + } +} + + +void RDTransportButton::flashClock() +{ + QKeySequence a=accel(); + if(flash_state) { + flash_state=false; + setPixmap(*off_cap); + } + else { + flash_state=true; + setPixmap(*on_cap); + } + setAccel(a); +} + + +void RDTransportButton::updateCaps() +{ + switch(button_state) { + case RDTransportButton::On: + setPixmap(*on_cap); + break; + + case RDTransportButton::Flashing: + if(flash_state) { + setPixmap(*on_cap); + } + else { + setPixmap(*off_cap); + } + break; + + case RDTransportButton::Off: + setPixmap(*off_cap); + break; + } +} + + +void RDTransportButton::drawMask(QPixmap *cap) +{ + QPointArray triangle=QPointArray(3); + QPainter b; + QBitmap *bitmap=new QBitmap(size()); + int edge; + + if(height()<width()) { + edge=height(); + } + else { + edge=width(); + } + cap->resize(size()); + b.begin(bitmap); + b.fillRect(0,0,size().width(),size().height(),QColor(color0)); + b.setPen(QColor(color1)); + b.setBrush(QColor(color1)); + + switch(button_type) { + case RDTransportButton::Play: + triangle.setPoint(0,width()/2-(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,height()/2); + triangle.setPoint(2,width()/2-(3*edge)/10,height()/2+(3*edge)/10); + b.drawPolygon(triangle); + break; + case RDTransportButton::Stop: + b.fillRect(width()/2-edge*3/10,height()/2-edge*3/10, + edge*3/5,edge*3/5,QColor(color1)); + break; + case RDTransportButton::Record: + b.drawEllipse(width()/2-(3*edge)/10,height()/2-(3*edge)/10, + (3*edge)/5,(3*edge)/5); + break; + case RDTransportButton::FastForward: + triangle.setPoint(0,width()/2-(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2,height()/2); + triangle.setPoint(2,width()/2-(3*edge)/10,height()/2+(3*edge)/10); + b.drawPolygon(triangle); + triangle.setPoint(0,width()/2,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,height()/2); + triangle.setPoint(2,width()/2,height()/2+(3*edge)/10); + b.drawPolygon(triangle); + break; + case RDTransportButton::Rewind: + triangle.setPoint(0,width()/2+(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2,height()/2); + triangle.setPoint(2,width()/2+(3*edge)/10,height()/2+(3*edge)/10); + b.drawPolygon(triangle); + triangle.setPoint(0,width()/2,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2-(3*edge)/10,height()/2); + triangle.setPoint(2,width()/2,height()/2+(3*edge)/10); + b.drawPolygon(triangle); + break; + case RDTransportButton::Eject: + triangle.setPoint(0,width()/2,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,height()/2); + triangle.setPoint(2,width()/2-(3*edge)/10,height()/2); + b.drawPolygon(triangle); + b.fillRect(width()/2-(3*edge)/10,height()/2+edge/10, + (3*edge)/5,edge/5,QColor(color1)); + break; + case RDTransportButton::Pause: + b.fillRect(width()/2-(3*edge)/10,height()/2-(3*edge)/10, + (3*edge)/15,(3*edge)/5,QColor(color1)); + b.fillRect(width()/2+(3*edge)/30,height()/2-(3*edge)/10, + (3*edge)/15,(3*edge)/5,QColor(color1)); + break; + case RDTransportButton::PlayFrom: + b.fillRect(width()/2-(3*edge)/10,height()/2-(3*edge)/10, + 3,(3*edge)/5,QBrush(color1)); + triangle.setPoint(0,width()/2-(2*edge)/10+1,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10+1,height()/2); + triangle.setPoint(2,width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + b.drawPolygon(triangle); + break; + case RDTransportButton::PlayBetween: + b.fillRect(width()/2-(3*edge)/10,height()/2-(3*edge)/10, + 3,(3*edge)/5,QBrush(color1)); + b.fillRect(width()/2+(3*edge)/10,height()/2-(3*edge)/10, + 3,(3*edge)/5,QBrush(color1)); + triangle.setPoint(0,width()/2-(2*edge)/10+1,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(2*edge)/10+1,height()/2); + triangle.setPoint(2,width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + b.drawPolygon(triangle); + break; + case RDTransportButton::Loop: + b.moveTo(width()/2-(2*edge)/10+1,height()/2+(edge)/4); + b.moveTo(width()/2+(edge)/10+1,height()/2-edge/10); + b.moveTo(width()/2-(2*edge)/10+1,height()/2+(edge)/4); + b.drawArc(width()/6,height()/2-edge/9,2*width()/3, + height()/3+edge/10,1440,5760); + triangle.setPoint(0,width()/2-(2*edge)/10+1,height()/2-(edge)/4); + triangle.setPoint(1,width()/2+(edge)/10+1,height()/2-edge/10); + triangle.setPoint(2,width()/2-(2*edge)/10+1,height()/2+edge/20); + b.drawPolygon(triangle); + break; + case RDTransportButton::Up: + triangle.setPoint(0,width()/2,(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,height()-(3*edge)/10); + triangle.setPoint(2,width()/2-(3*edge)/10,height()-(3*edge)/10); + b.drawPolygon(triangle); + break; + case RDTransportButton::Down: + triangle.setPoint(0,width()/2,height()-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,(3*edge)/10); + triangle.setPoint(2,width()/2-(3*edge)/10,(3*edge)/10); + b.drawPolygon(triangle); + break; + case RDTransportButton::PlayTo: + b.fillRect(width()/2+(3*edge)/10,height()/2-(3*edge)/10, + 3,(3*edge)/5,QBrush(color1)); + triangle.setPoint(0,width()/2-(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(2*edge)/10+1,height()/2); + triangle.setPoint(2,width()/2-(3*edge)/10,height()/2+(3*edge)/10); + b.drawPolygon(triangle); + break; + default: + b.fillRect(0,0,width(),height(),QColor(color1)); + } + b.end(); + cap->setMask(*bitmap); + + delete bitmap; +} + + +void RDTransportButton::drawOnCap() +{ + QPainter p; + QPointArray triangle=QPointArray(3); + int edge; + + if(height()<width()) { + edge=height(); + } + else { + edge=width(); + } + drawMask(on_cap); + p.begin(on_cap); + p.setPen(on_color); + p.setBrush(on_color); + switch(button_type) { + case RDTransportButton::Play: + triangle.setPoint(0,width()/2-(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,height()/2); + triangle.setPoint(2,width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(3*edge)/10,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + break; + case RDTransportButton::Stop: + p.fillRect(width()/2-edge*3/10,height()/2-edge*3/10, + edge*3/5,edge*3/5,QColor(on_color)); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-edge*3/10,height()/2+edge*3/10); + p.lineTo(width()/2-edge*3/10,height()/2-edge*3/10); + p.lineTo(width()/2+edge*3/10,height()/2-edge*3/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2+edge*3/10,height()/2+edge*3/10); + p.lineTo(width()/2-edge*3/10,height()/2+edge*3/10); + break; + case RDTransportButton::Record: + p.setPen(QColor(red)); + p.setBrush(QColor(red)); + p.drawEllipse(width()/2-(3*edge)/10,height()/2-(3*edge)/10, + (3*edge)/5,(3*edge)/5); + break; + case RDTransportButton::FastForward: + triangle.setPoint(0,width()/2-(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2,height()/2); + triangle.setPoint(2,width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + triangle.setPoint(0,width()/2,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,height()/2); + triangle.setPoint(2,width()/2,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2,height()/2+(3*edge)/10); + p.lineTo(width()/2,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(3*edge)/10,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2,height()/2+(3*edge)/10); + break; + case RDTransportButton::Rewind: + triangle.setPoint(0,width()/2+(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2,height()/2); + triangle.setPoint(2,width()/2+(3*edge)/10,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2+(3*edge)/10,height()/2-(3*edge)/10); + p.lineTo(width()/2,height()/2); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(3*edge)/10,height()/2+(3*edge)/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2+(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(0,width()/2,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2-(3*edge)/10,height()/2); + triangle.setPoint(2,width()/2,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2,height()/2-(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10,height()/2); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2,height()/2+(3*edge)/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2,height()/2-(3*edge)/10); + break; + case RDTransportButton::Eject: + triangle.setPoint(0,width()/2,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,height()/2); + triangle.setPoint(2,width()/2-(3*edge)/10,height()/2); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(3*edge)/10,height()/2); + p.lineTo(width()/2,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(3*edge)/10,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(3*edge)/10,height()/2); + p.fillRect(width()/2-(3*edge)/10,height()/2+edge/10, + (3*edge)/5,edge/5,on_color); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(3*edge)/10,height()/2+edge/10+edge/5); + p.lineTo(width()/2-(3*edge)/10,height()/2+edge/10); + p.lineTo(width()/2+(3*edge)/10,height()/2+edge/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2+(3*edge)/10,height()/2+edge/10+edge/5); + p.lineTo(width()/2-(3*edge)/10,height()/2+edge/10+edge/5); + break; + case RDTransportButton::Pause: + p.fillRect(width()/2-(3*edge)/10,height()/2-(3*edge)/10, + (3*edge)/15,(3*edge)/5,on_color); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10,height()/2-(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10+(3*edge)/15,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(3*edge)/10+(3*edge)/15,height()/2+(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.fillRect(width()/2+(3*edge)/30,height()/2-(3*edge)/10, + (3*edge)/15,(3*edge)/5,on_color); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2+(3*edge)/30,height()/2+(3*edge)/10); + p.lineTo(width()/2+(3*edge)/30,height()/2-(3*edge)/10); + p.lineTo(width()/2+(3*edge)/10,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2+(3*edge)/10,height()/2+(3*edge)/10); + p.lineTo(width()/2+(3*edge)/30,height()/2+(3*edge)/10); + break; + case RDTransportButton::PlayFrom: + p.fillRect(width()/2-(3*edge)/10,height()/2-(3*edge)/10, + 3,(3*edge)/5,QBrush(accent_color)); + triangle.setPoint(0,width()/2-(2*edge)/10+1,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10+1,height()/2); + triangle.setPoint(2,width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + p.lineTo(width()/2-(2*edge)/10+1,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(3*edge)/10+1,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + break; + case RDTransportButton::PlayBetween: + p.fillRect(width()/2-(3*edge)/10,height()/2-(3*edge)/10, + 3,(3*edge)/5,QBrush(accent_color)); + p.fillRect(width()/2+(3*edge)/10,height()/2-(3*edge)/10, + 3,(3*edge)/5,QBrush(accent_color)); + triangle.setPoint(0,width()/2-(2*edge)/10+1,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(2*edge)/10+1,height()/2); + triangle.setPoint(2,width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + p.lineTo(width()/2-(2*edge)/10+1,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(2*edge)/10+1,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + break; + case RDTransportButton::Loop: + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(2*edge)/10+1,height()/2+(edge)/4); + p.lineTo(width()/2+(edge)/10+1,height()/2-edge/10); + p.setPen(QColor(colorGroup().dark())); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(2*edge)/10+1,height()/2+(edge)/4); + p.setPen(QColor(colorGroup().shadow())); + p.drawArc(width()/6,height()/2-edge/9,2*width()/3, + height()/3+edge/10,1440,5760); + triangle.setPoint(0,width()/2-(2*edge)/10+1,height()/2-(edge)/4); + triangle.setPoint(1,width()/2+(edge)/10+1,height()/2-edge/10); + triangle.setPoint(2,width()/2-(2*edge)/10+1,height()/2+edge/20); + p.drawPolygon(triangle); + break; + case RDTransportButton::Up: + triangle.setPoint(0,width()/2,(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,height()-(3*edge)/10); + triangle.setPoint(2,width()/2-(3*edge)/10,height()-(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(3*edge)/10,height()-(3*edge)/10); + p.lineTo(width()/2,(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(3*edge)/10,height()-(3*edge)/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(3*edge)/10,height()-(3*edge)/10); + break; + case RDTransportButton::Down: + triangle.setPoint(0,width()/2,height()-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,(3*edge)/10); + triangle.setPoint(2,width()/2-(3*edge)/10,(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().dark())); + p.moveTo(width()/2-(3*edge)/10,(3*edge)/10); + p.lineTo(width()/2,height()-(3*edge)/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2+(3*edge)/10,(3*edge)/10); + p.setPen(QColor(colorGroup().shadow())); + p.lineTo(width()/2-(3*edge)/10,(3*edge)/10); + break; + case RDTransportButton::PlayTo: + p.fillRect(width()/2+(3*edge)/10,height()/2-(3*edge)/10, + 3,(3*edge)/5,QBrush(accent_color)); + triangle.setPoint(0,width()/2-(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(2*edge)/10+1,height()/2); + triangle.setPoint(2,width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(2*edge)/10+1,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + break; + } + p.end(); +} + + +void RDTransportButton::drawOffCap() +{ + QPainter p; + QPointArray triangle=QPointArray(3); + int edge; + + if(height()<width()) { + edge=height(); + } + else { + edge=width(); + } + drawMask(off_cap); + p.begin(off_cap); + p.setPen(QColor(black)); + p.setBrush(QColor(black)); + switch(button_type) { + case RDTransportButton::Play: + triangle.setPoint(0,width()/2-(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,height()/2); + triangle.setPoint(2,width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(3*edge)/10,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + break; + case RDTransportButton::Stop: + p.fillRect(width()/2-edge*3/10,height()/2-edge*3/10, + edge*3/5,edge*3/5,QColor(colorGroup().shadow())); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-edge*3/10,height()/2+edge*3/10); + p.lineTo(width()/2-edge*3/10,height()/2-edge*3/10); + p.lineTo(width()/2+edge*3/10,height()/2-edge*3/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2+edge*3/10,height()/2+edge*3/10); + p.lineTo(width()/2-edge*3/10,height()/2+edge*3/10); + break; + case RDTransportButton::Record: + p.setPen(QColor(darkRed)); + p.setBrush(QColor(darkRed)); + p.drawEllipse(width()/2-(3*edge)/10,height()/2-(3*edge)/10, + (3*edge)/5,(3*edge)/5); + break; + case RDTransportButton::FastForward: + triangle.setPoint(0,width()/2-(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2,height()/2); + triangle.setPoint(2,width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + triangle.setPoint(0,width()/2,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,height()/2); + triangle.setPoint(2,width()/2,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2,height()/2+(3*edge)/10); + p.lineTo(width()/2,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(3*edge)/10,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2,height()/2+(3*edge)/10); + break; + case RDTransportButton::Rewind: + triangle.setPoint(0,width()/2+(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2,height()/2); + triangle.setPoint(2,width()/2+(3*edge)/10,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2+(3*edge)/10,height()/2-(3*edge)/10); + p.lineTo(width()/2,height()/2); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(3*edge)/10,height()/2+(3*edge)/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2+(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(0,width()/2,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2-(3*edge)/10,height()/2); + triangle.setPoint(2,width()/2,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2,height()/2-(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10,height()/2); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2,height()/2+(3*edge)/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2,height()/2-(3*edge)/10); + break; + case RDTransportButton::Eject: + triangle.setPoint(0,width()/2,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,height()/2); + triangle.setPoint(2,width()/2-(3*edge)/10,height()/2); + p.drawPolygon(triangle); + p.fillRect(width()/2-(3*edge)/10,height()/2+edge/10, + (3*edge)/5,edge/5,QColor(black)); + break; + case RDTransportButton::Pause: + p.fillRect(width()/2-(3*edge)/10,height()/2-(3*edge)/10, + (3*edge)/15,(3*edge)/5,QColor(black)); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10,height()/2-(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10+(3*edge)/15,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(3*edge)/10+(3*edge)/15,height()/2+(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.fillRect(width()/2+(3*edge)/30,height()/2-(3*edge)/10, + (3*edge)/15,(3*edge)/5,QColor(black)); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2+(3*edge)/30,height()/2+(3*edge)/10); + p.lineTo(width()/2+(3*edge)/30,height()/2-(3*edge)/10); + p.lineTo(width()/2+(3*edge)/10,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2+(3*edge)/10,height()/2+(3*edge)/10); + p.lineTo(width()/2+(3*edge)/30,height()/2+(3*edge)/10); + break; + case RDTransportButton::PlayFrom: + p.fillRect(width()/2-(3*edge)/10,height()/2-(3*edge)/10, + 3,(3*edge)/5,QBrush(accent_color)); + triangle.setPoint(0,width()/2-(2*edge)/10+1,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10+1,height()/2); + triangle.setPoint(2,width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + p.lineTo(width()/2-(2*edge)/10+1,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(3*edge)/10+1,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + break; + case RDTransportButton::PlayBetween: + p.fillRect(width()/2-(3*edge)/10,height()/2-(3*edge)/10, + 3,(3*edge)/5,QBrush(accent_color)); + p.fillRect(width()/2+(3*edge)/10,height()/2-(3*edge)/10, + 3,(3*edge)/5,QBrush(accent_color)); + triangle.setPoint(0,width()/2-(2*edge)/10+1,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(2*edge)/10+1,height()/2); + triangle.setPoint(2,width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + p.lineTo(width()/2-(2*edge)/10+1,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(2*edge)/10+1,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(2*edge)/10+1,height()/2+(3*edge)/10); + break; + case RDTransportButton::Loop: + triangle.setPoint(0,width()/2-(2*edge)/10+1,height()/2-(edge)/4); + triangle.setPoint(1,width()/2+(edge)/10+1,height()/2-edge/10); + triangle.setPoint(2,width()/2-(2*edge)/10+1,height()/2+edge/20); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(2*edge)/10+1,height()/2+(edge)/4); + p.lineTo(width()/2+(edge)/10+1,height()/2-edge/10); + p.setPen(QColor(colorGroup().dark())); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(2*edge)/10+1,height()/2+(edge)/4); + p.setPen(QColor(colorGroup().shadow())); + p.drawArc(width()/6,height()/2-edge/9,2*width()/3, + height()/3+edge/10,1440,5760); + break; + case RDTransportButton::Up: + triangle.setPoint(0,width()/2,(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,height()-(3*edge)/10); + triangle.setPoint(2,width()/2-(3*edge)/10,height()-(3*edge)/10); + p.drawPolygon(triangle); + break; + case RDTransportButton::Down: + triangle.setPoint(0,width()/2,height()-(3*edge)/10); + triangle.setPoint(1,width()/2+(3*edge)/10,(3*edge)/10); + triangle.setPoint(2,width()/2-(3*edge)/10,(3*edge)/10); + p.drawPolygon(triangle); + break; + case RDTransportButton::PlayTo: + p.fillRect(width()/2+(3*edge)/10,height()/2-(3*edge)/10, + 3,(3*edge)/5,QBrush(accent_color)); + triangle.setPoint(0,width()/2-(3*edge)/10,height()/2-(3*edge)/10); + triangle.setPoint(1,width()/2+(2*edge)/10+1,height()/2); + triangle.setPoint(2,width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.drawPolygon(triangle); + p.setPen(QColor(colorGroup().shadow())); + p.moveTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + p.lineTo(width()/2-(3*edge)/10,height()/2-(3*edge)/10); + p.setPen(QColor(colorGroup().dark())); + p.lineTo(width()/2+(2*edge)/10+1,height()/2); + p.setPen(QColor(colorGroup().light())); + p.lineTo(width()/2-(3*edge)/10,height()/2+(3*edge)/10); + break; + } + p.end(); +} + +void RDTransportButton::flashOn() +{ + if(!flash_timer->isActive()) { + flash_timer->start(500); + } +} + + +void RDTransportButton::flashOff() +{ + if(flash_timer->isActive()) { + flash_timer->stop(); + } +} + + + diff --git a/lib/rdtransportbutton.h b/lib/rdtransportbutton.h new file mode 100644 index 00000000..a19200ed --- /dev/null +++ b/lib/rdtransportbutton.h @@ -0,0 +1,84 @@ +// rdtransportbutton.h +// +// An audio transport button widget. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtransportbutton.h,v 1.3.10.1 2014/05/27 22:49:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDTRANSPORTBUTTON_H +#define RDTRANSPORTBUTTON_H + +#include <qwidget.h> +#include <qpushbutton.h> +#include <qpixmap.h> +#include <qcolor.h> + + +#define RDTRANSPORTBUTTON_DEFAULT_ON_COLOR green + + +class RDTransportButton : public QPushButton +{ + Q_OBJECT + public: + enum TransType {Play=0,Stop=1,Record=2,FastForward=3,Rewind=4,Eject=5, + Pause=6,PlayFrom=7,PlayBetween=8,Loop=9,Up=10,Down=11, + PlayTo=12}; + enum TransState {On=0,Off=1,Flashing=2}; + RDTransportButton(RDTransportButton::TransType type,QWidget *parent=0, + const char *name=0); + RDTransportButton::TransType getType() const; + void setType(RDTransportButton::TransType type); + QColor onColor() const; + void setOnColor(QColor color); + QColor accentColor() const; + void setAccentColor(QColor color); + void setState(RDTransportButton::TransState state); + + public slots: + void on(); + void off(); + void flash(); + + protected: + virtual void resizeEvent(QResizeEvent *); + virtual void enabledChange(bool oldEnabled); + + private slots: + void flashClock(); + + private: + void updateCaps(); + void drawMask(QPixmap *cap); + void drawOnCap(); + void drawOffCap(); + void flashOn(); + void flashOff(); + bool flash_state; + RDTransportButton::TransType button_type; + RDTransportButton::TransState button_state; + QColor on_color; + QColor accent_color; + QPixmap *on_cap; + QPixmap *off_cap; + QTimer *flash_timer; +}; + + +#endif // RDTRANSPORTBUTTON_H diff --git a/lib/rdtrimaudio.cpp b/lib/rdtrimaudio.cpp new file mode 100644 index 00000000..4c4a9e40 --- /dev/null +++ b/lib/rdtrimaudio.cpp @@ -0,0 +1,252 @@ +// rdtrimaudio.cpp +// +// Get the trim points for an audio cut. +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtrimaudio.cpp,v 1.6.4.3 2014/01/16 02:44:59 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> + +#include <curl/curl.h> + +#include <qstringlist.h> + +#include <rd.h> +#include <rdxport_interface.h> +#include <rdformpost.h> +#include <rdtrimaudio.h> + +size_t RDTrimAudioCallback(void *ptr,size_t size,size_t nmemb,void *userdata) +{ + QString *xml=(QString *)userdata; + for(unsigned i=0;i<(size*nmemb);i++) { + *xml+=((const char *)ptr)[i]; + } + return size*nmemb; +} + + +RDTrimAudio::RDTrimAudio(RDStation *station,RDConfig *config, + QObject *parent,const char *name) + : QObject(parent,name) +{ + conv_station=station; + conv_config=config; + conv_cart_number=0; + conv_cut_number=0; + conv_start_point=-1; + conv_end_point=-1; +} + + +int RDTrimAudio::startPoint() const +{ + return conv_start_point; +} + + +int RDTrimAudio::endPoint() const +{ + return conv_end_point; +} + + +void RDTrimAudio::setCartNumber(unsigned cartnum) +{ + conv_cart_number=cartnum; +} + + +void RDTrimAudio::setCutNumber(unsigned cutnum) +{ + conv_cut_number=cutnum; +} + + +void RDTrimAudio::setTrimLevel(int lvl) +{ + conv_trim_level=lvl; +} + + +RDTrimAudio::ErrorCode RDTrimAudio::runTrim(const QString &username, + const QString &password) +{ + long response_code; + CURL *curl=NULL; + char url[1024]; + CURLcode curl_err; + + // + // Generate POST Data + // + QString post=QString().sprintf("COMMAND=%d&LOGIN_NAME=%s&PASSWORD=%s&CART_NUMBER=%u&CUT_NUMBER=%u&TRIM_LEVEL=%d", + RDXPORT_COMMAND_TRIMAUDIO, + (const char *)RDFormPost::urlEncode(username), + (const char *)RDFormPost::urlEncode(password), + conv_cart_number, + conv_cut_number, + conv_trim_level); + if((curl=curl_easy_init())==NULL) { + return RDTrimAudio::ErrorInternal; + } + + // + // Write out URL as a C string before passing to curl_easy_setopt(), + // otherwise some versions of LibCurl will throw a 'bad/illegal format' + // error. + // + strncpy(url,conv_station->webServiceUrl(conv_config),1024); + curl_easy_setopt(curl,CURLOPT_URL,url); + curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,RDTrimAudioCallback); + curl_easy_setopt(curl,CURLOPT_WRITEDATA,&conv_xml); + curl_easy_setopt(curl,CURLOPT_POST,1); + curl_easy_setopt(curl,CURLOPT_POSTFIELDS,(const char *)post); + curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT); + + switch(curl_err=curl_easy_perform(curl)) { + case CURLE_OK: + break; + + case CURLE_UNSUPPORTED_PROTOCOL: + case CURLE_FAILED_INIT: + case CURLE_COULDNT_RESOLVE_PROXY: + case CURLE_PARTIAL_FILE: + case CURLE_HTTP_RETURNED_ERROR: + case CURLE_WRITE_ERROR: + case CURLE_OUT_OF_MEMORY: + case CURLE_OPERATION_TIMEDOUT: + case CURLE_HTTP_POST_ERROR: + //fprintf(stderr,"CURL Error: %s [%d]\n",curl_easy_strerror(curl_err), + //curl_err); + curl_easy_cleanup(curl); + return RDTrimAudio::ErrorInternal; + + case CURLE_URL_MALFORMAT: + case CURLE_COULDNT_RESOLVE_HOST: + case CURLE_COULDNT_CONNECT: + case 9: // CURLE_REMOTE_ACCESS_DENIED + curl_easy_cleanup(curl); + return RDTrimAudio::ErrorUrlInvalid; + } + curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&response_code); + curl_easy_cleanup(curl); + + switch(response_code) { + case 200: + //printf("XML: %s\n",(const char *)conv_xml); + break; + + case 404: + return RDTrimAudio::ErrorNoAudio; + + default: + return RDTrimAudio::ErrorService; + } + conv_start_point=ParsePoint("startTrimPoint",conv_xml); + conv_end_point=ParsePoint("endTrimPoint",conv_xml); + + return RDTrimAudio::ErrorOk; +} + + +QString RDTrimAudio::errorText(RDTrimAudio::ErrorCode err) +{ + QString ret=QString().sprintf("Unknown Error [%u]",err); + + switch(err) { + case RDTrimAudio::ErrorOk: + ret=tr("OK"); + break; + + case RDTrimAudio::ErrorInternal: + ret=tr("Internal Error"); + break; + + case RDTrimAudio::ErrorUrlInvalid: + ret=tr("Invalid URL"); + break; + + case RDTrimAudio::ErrorService: + ret=tr("RDXport service returned an error"); + break; + + case RDTrimAudio::ErrorInvalidUser: + ret=tr("Invalid user or password"); + break; + + case RDTrimAudio::ErrorNoAudio: + ret=tr("No audio data"); + break; + } + return ret; +} + + +bool RDTrimAudio::ParseXml(const QString &xml) +{ + // + // FIXME: This is totally ad-hoc, but should work until we settle on + // a proper XML parser. + // + bool ret=false; + + QStringList list=list.split("\n",xml); + for(unsigned i=0;i<list.size();i++) { + if(list[i].contains("startTrimPoint")) { + QStringList list2=list.split("<",list[i]); + if(list2.size()>=2) { + list2=list2.split(">",list2[1]); + if(list2.size()>=2) { + conv_start_point=list2[1].toInt(); + ret=true; + } + } + } + } + + return ret; +} + + +int RDTrimAudio::ParsePoint(const QString &tag,const QString &xml) +{ + // + // FIXME: This is totally ad-hoc, but should work until we settle on + // a proper XML parser. + // + QStringList list=list.split("\n",xml); + for(unsigned i=0;i<list.size();i++) { + if(list[i].contains(tag)) { + QStringList list2=list.split("<",list[i]); + if(list2.size()>=2) { + list2=list2.split(">",list2[1]); + if(list2.size()>=2) { + return list2[1].toInt(); + } + } + } + } + return -1; +} diff --git a/lib/rdtrimaudio.h b/lib/rdtrimaudio.h new file mode 100644 index 00000000..da6540bb --- /dev/null +++ b/lib/rdtrimaudio.h @@ -0,0 +1,62 @@ +// rdtrimaudio.h +// +// Get the trim points for an audio cut. +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtrimaudio.h,v 1.1.6.2 2014/01/16 02:44:59 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDTRIMAUDIO_H +#define RDTRIMAUDIO_H + +#include <qobject.h> + +#include <rdconfig.h> +#include <rdstation.h> + +class RDTrimAudio : public QObject +{ + Q_OBJECT; + public: + enum ErrorCode {ErrorOk=0,ErrorInternal=5,ErrorUrlInvalid=7, + ErrorService=8,ErrorInvalidUser=9,ErrorNoAudio=10}; + RDTrimAudio(RDStation *station,RDConfig *config,QObject *parent=0, + const char *name=0); + int startPoint() const; + int endPoint() const; + void setCartNumber(unsigned cartnum); + void setCutNumber(unsigned cutnum); + void setTrimLevel(int lvl); + RDTrimAudio::ErrorCode runTrim(const QString &username, + const QString &password); + static QString errorText(RDTrimAudio::ErrorCode err); + + private: + bool ParseXml(const QString &xml); + int ParsePoint(const QString &tag,const QString &xml); + RDStation *conv_station; + RDConfig *conv_config; + unsigned conv_cart_number; + unsigned conv_cut_number; + int conv_trim_level; + int conv_start_point; + int conv_end_point; + QString conv_xml; +}; + + +#endif // RDAUDIOIMPORT_H diff --git a/lib/rdtty.cpp b/lib/rdtty.cpp new file mode 100644 index 00000000..d226af08 --- /dev/null +++ b/lib/rdtty.cpp @@ -0,0 +1,258 @@ +// rdtty.cpp +// +// Abstract a Rivendell TTY. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtty.cpp,v 1.10 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rddb.h> +#include <rdconf.h> +#include <rdtty.h> + + +// +// Global Classes +// +RDTty::RDTty(const QString &station,unsigned port_id,bool create) +{ + RDSqlQuery *q; + QString sql; + + tty_station=station; + tty_id=port_id; + + if(create) { + sql=QString().sprintf("select ID from TTYS where \ +(STATION_NAME=\"%s\")&&(PORT_ID=%d)",(const char *)tty_station,tty_id); + q=new RDSqlQuery(sql); + if(q->size()!=1) { + delete q; + sql=QString().sprintf("INSERT INTO TTYS SET STATION_NAME=\"%s\",PORT_ID=%d", + (const char *)tty_station,tty_id); + q=new RDSqlQuery(sql); + delete q; + } + else { + delete q; + } + } +} + + +QString RDTty::station() const +{ + return tty_station; +} + + +int RDTty::portId() const +{ + return tty_id; +} + + +bool RDTty::active() +{ + return GetBoolValue("ACTIVE"); +} + + +void RDTty::setActive(bool state) +{ + SetRow("ACTIVE",state); +} + + +QString RDTty::port() +{ + return GetStringValue("PORT"); +} + + +void RDTty::setPort(QString port) +{ + SetRow("PORT",port); +} + + +int RDTty::baudRate() +{ + return GetIntValue("BAUD_RATE"); +} + + +void RDTty::setBaudRate(int rate) +{ + SetRow("BAUD_RATE",rate); +} + + +int RDTty::dataBits() +{ + return GetIntValue("DATA_BITS"); +} + + +void RDTty::setDataBits(int bits) +{ + SetRow("DATA_BITS",bits); +} + + +int RDTty::stopBits() +{ + return GetIntValue("STOP_BITS"); +} + + +void RDTty::setStopBits(int bits) +{ + SetRow("STOP_BITS",bits); +} + + +RDTTYDevice::Parity RDTty::parity() +{ + return (RDTTYDevice::Parity)GetIntValue("PARITY"); +} + + +void RDTty::setParity(RDTTYDevice::Parity parity) +{ + SetRow("PARITY",(int)parity); +} + + +RDTty::Termination RDTty::termination() +{ + return (RDTty::Termination)GetIntValue("TERMINATION"); +} + + +void RDTty::setTermination(RDTty::Termination term) +{ + SetRow("TERMINATION",(int)term); +} + + +bool RDTty::GetBoolValue(const QString &field) +{ + QString sql; + RDSqlQuery *q; + bool state; + + sql=QString().sprintf("select %s from TTYS where \ +(STATION_NAME=\"%s\")&&(PORT_ID=%d)",(const char *)field, + (const char *)tty_station,tty_id); + q=new RDSqlQuery(sql); + if(q->first()) { + state=RDBool(q->value(0).toString()); + delete q; + return state; + } + delete q; + return false; +} + + +QString RDTty::GetStringValue(const QString &field) +{ + QString sql; + RDSqlQuery *q; + QString accum; + + sql=QString().sprintf("select %s from TTYS where \ +(STATION_NAME=\"%s\")&&(PORT_ID=%d)",(const char *)field, + (const char *)tty_station,tty_id); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toString(); + delete q; + return accum; + } + delete q; + return QString(); +} + + +int RDTty::GetIntValue(const QString &field) +{ + QString sql; + RDSqlQuery *q; + int accum; + + sql=QString().sprintf("select %s from TTYS where \ +(STATION_NAME=\"%s\")&&(PORT_ID=%d)",(const char *)field, + (const char *)tty_station,tty_id); + q=new RDSqlQuery(sql); + if(q->first()) { + accum=q->value(0).toInt(); + delete q; + return accum; + } + delete q; + return 0; +} + + +void RDTty::SetRow(const QString ¶m,bool value) +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE TTYS SET %s=\"%s\" \ +WHERE (STATION_NAME=\"%s\")&&(PORT_ID=%d)", + (const char *)param, + (const char *)RDYesNo(value), + (const char *)tty_station, + tty_id); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDTty::SetRow(const QString ¶m,const QString &value) +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE TTYS SET %s=\"%s\" \ +WHERE (STATION_NAME=\"%s\")&&(PORT_ID=%d)", + (const char *)param, + (const char *)value, + (const char *)tty_station, + tty_id); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDTty::SetRow(const QString ¶m,int value) +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE TTYS SET %s=%d \ +WHERE (STATION_NAME=\"%s\")&&(PORT_ID=%d)", + (const char *)param, + value, + (const char *)tty_station, + tty_id); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdtty.h b/lib/rdtty.h new file mode 100644 index 00000000..705426d4 --- /dev/null +++ b/lib/rdtty.h @@ -0,0 +1,64 @@ +// rdtty.h +// +// Abstract a Rivendell TTY +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdtty.h,v 1.8 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> + +#include <rdttydevice.h> + +#ifndef RDTTY_H +#define RDTTY_H + +class RDTty +{ + public: + enum Termination {NoTerm=0,CrTerm=1,LfTerm=2,CrLfTerm=3}; + RDTty(const QString &station,unsigned port_id,bool create=false); + QString station() const; + int portId() const; + bool active(); + void setActive(bool state); + QString port(); + void setPort(QString port); + int baudRate(); + void setBaudRate(int rate); + int dataBits(); + void setDataBits(int bits); + int stopBits(); + void setStopBits(int bits); + RDTTYDevice::Parity parity(); + void setParity(RDTTYDevice::Parity); + RDTty::Termination termination(); + void setTermination(RDTty::Termination term); + + private: + bool GetBoolValue(const QString &field); + QString GetStringValue(const QString &field); + int GetIntValue(const QString &field); + void SetRow(const QString ¶m,bool value); + void SetRow(const QString ¶m,const QString &value); + void SetRow(const QString ¶m,int value); + QString tty_station; + int tty_id; +}; + + +#endif diff --git a/lib/rdttydevice.cpp b/lib/rdttydevice.cpp new file mode 100644 index 00000000..15dd5660 --- /dev/null +++ b/lib/rdttydevice.cpp @@ -0,0 +1,561 @@ +// rdttydevice.cpp +// +// A Qt driver for tty ports on Linux. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdttydevice.cpp,v 1.5 2011/05/04 18:09:06 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <qiodevice.h> + +#include <rdttydevice.h> + + +RDTTYDevice::RDTTYDevice() : QIODevice() +{ + Init(); +} + +RDTTYDevice::~RDTTYDevice() +{ + if(tty_open) { + close(); + } +} + +bool RDTTYDevice::open(int mode) +{ + int flags=O_NONBLOCK|O_NOCTTY; + struct termios term; + + tty_mode=mode; + if((mode&IO_ReadWrite)==IO_ReadWrite) { + flags|=O_RDWR; + } + else { + if(((mode&IO_WriteOnly)!=0)) { + flags|=O_WRONLY; + } + if(((mode&IO_ReadOnly)!=0)) { + flags|=O_RDONLY; + } + } + if((mode&IO_Append)!=0) { + flags|=O_APPEND; + } + if((mode&IO_Truncate)!=0) { + flags|=O_TRUNC; + } + + if((tty_fd=::open((const char *)tty_name,flags))<0) { + tty_status=IO_OpenError; + return false; + } + tty_open=true; + tty_status=IO_Ok; + + tcgetattr(tty_fd,&term); + cfsetispeed(&term,B0); + cfsetospeed(&term,tty_speed); + cfmakeraw(&term); + term.c_iflag |= IGNBRK; + switch(tty_parity) { + case RDTTYDevice::None: + term.c_iflag |= IGNPAR; + break; + + case RDTTYDevice::Even: + term.c_cflag |= PARENB; + break; + + case RDTTYDevice::Odd: + term.c_cflag |= PARENB|PARODD; + break; + } + tcsetattr(tty_fd,TCSADRAIN,&term); + + return true; +} + + +void RDTTYDevice::close() +{ + if(tty_open) { + ::close(tty_fd); + } + tty_open=false; +} + + +int RDTTYDevice::socket() +{ + return tty_fd; +} + + +void RDTTYDevice::flush() +{ +} + + +Q_LONG RDTTYDevice::readBlock(char *data,Q_ULONG maxlen) +{ + Q_LONG n; + + if((n=read(tty_fd,data,(size_t)maxlen))<0) { + if(errno!=EAGAIN) { + tty_status=IO_ReadError; + return -1; + } + return 0; + } + tty_status=IO_Ok; + return n; +} + + +Q_LONG RDTTYDevice::writeBlock(const char *data,Q_ULONG len) +{ + Q_LONG n; + + if((n=write(tty_fd,data,(size_t)len))<0) { + tty_status=IO_WriteError; + return n; + } + tty_status=IO_Ok; + return n; +} + + +int RDTTYDevice::getch() +{ + char c; + int n; + + if((n=readBlock(&c,1))<0) { + tty_status=IO_ReadError; + return -1; + } + return (int)c; +} + + +int RDTTYDevice::putch(int ch) +{ + char c; + int n; + + c=(char)ch; + if((n=writeBlock(&c,1))<0) { + tty_status=IO_WriteError; + return -1; + } + return ch; +} + + +int RDTTYDevice::ungetch(int ch) +{ + tty_status=IO_WriteError; + return -1; +} + + +QIODevice::Offset RDTTYDevice::size() const +{ + return 0; +} + + +int RDTTYDevice::flags() const +{ + return tty_mode|state(); +} + + +int RDTTYDevice::mode() const +{ + return tty_mode; +} + + +int RDTTYDevice::state() const +{ + if(tty_open) { + return IO_Open; + } + return 0; +} + + +bool RDTTYDevice::isDirectAccess() const +{ + return false; +} + + +bool RDTTYDevice::isSequentialAccess() const +{ + return true; +} + + +bool RDTTYDevice::isCombinedAccess() const +{ + return false; +} + + +bool RDTTYDevice::isBuffered() const +{ + return false; +} + + +bool RDTTYDevice::isRaw() const +{ + return true; +} + + +bool RDTTYDevice::isSynchronous() const +{ + return true; +} + + +bool RDTTYDevice::isAsynchronous() const +{ + return false; +} + + +bool RDTTYDevice::isTranslated() const +{ + return false; +} + + +bool RDTTYDevice::isReadable() const +{ + if(((tty_mode&IO_ReadOnly)!=0)||((tty_mode&IO_ReadWrite)!=0)) { + return true; + } + return false; +} + + +bool RDTTYDevice::isWritable() const +{ + if(((tty_mode&IO_WriteOnly)!=0)||((tty_mode&IO_ReadWrite)!=0)) { + return true; + } + return false; +} + + +bool RDTTYDevice::isReadWrite() const +{ + if((tty_mode&IO_ReadWrite)!=0) { + return true; + } + return false; + +} + + +bool RDTTYDevice::isInactive() const +{ + if(!tty_open) { + return true; + } + return false; +} + + +bool RDTTYDevice::isOpen() const +{ + if(tty_open) { + return true; + } + return false; +} + + +int RDTTYDevice::status() const +{ + return tty_status; +} + + +void RDTTYDevice::resetStatus() +{ + tty_status=IO_Ok; +} + + +void RDTTYDevice::setName(QString name) +{ + tty_name=name; +} + + +int RDTTYDevice::speed() const +{ + switch(tty_speed) { + case B0: + return 0; + break; + + case B50: + return 50; + break; + + case B75: + return 75; + break; + + case B110: + return 110; + break; + + case B134: + return 134; + break; + + case B150: + return 150; + break; + + case B200: + return 200; + break; + + case B300: + return 300; + break; + + case B600: + return 600; + break; + + case B1200: + return 1200; + break; + + case B1800: + return 1800; + break; + + case B2400: + return 2400; + break; + + case B4800: + return 4800; + break; + + case B9600: + return 9600; + break; + + case B19200: + return 19200; + break; + + case B38400: + return 38400; + break; + + case B57600: + return 57600; + break; + + case B115200: + return 115200; + break; + + case B230400: + return 230400; + break; + } + return 0; +} + + +void RDTTYDevice::setSpeed(int speed) +{ + switch(speed) { + case 0: + tty_speed=B0; + break; + + case 50: + tty_speed=B50; + break; + + case 75: + tty_speed=B75; + break; + + case 110: + tty_speed=B110; + break; + + case 134: + tty_speed=B134; + break; + + case 150: + tty_speed=B150; + break; + + case 200: + tty_speed=B200; + break; + + case 300: + tty_speed=B300; + break; + + case 600: + tty_speed=B600; + break; + + case 1200: + tty_speed=B1200; + break; + + case 1800: + tty_speed=B1800; + break; + + case 2400: + tty_speed=B2400; + break; + + case 4800: + tty_speed=B4800; + break; + + case 9600: + tty_speed=B9600; + break; + + case 19200: + tty_speed=B19200; + break; + + case 38400: + tty_speed=B38400; + break; + + case 57600: + tty_speed=B57600; + break; + + case 115200: + tty_speed=B115200; + break; + + case 230400: + tty_speed=B230400; + break; + + default: + tty_speed=B9600; + break; + } + + +} + + +int RDTTYDevice::wordLength() const +{ + switch(tty_length) { + case CS5: + return 5; + break; + + case CS6: + return 6; + break; + + case CS7: + return 7; + break; + + case CS8: + return 8; + break; + } + return 0; +} + + +void RDTTYDevice::setWordLength(int length) +{ + switch(length) { + case 5: + tty_length=CS5; + break; + + case 6: + tty_length=CS6; + break; + + case 7: + tty_length=CS7; + break; + + case 8: + tty_length=CS8; + break; + + default: + tty_length=CS8; + break; + } +} + + +RDTTYDevice::Parity RDTTYDevice::parity() const +{ + return tty_parity; +} + + +void RDTTYDevice::setParity(Parity parity) +{ + tty_parity=parity; +} + + +void RDTTYDevice::Init() +{ + tty_speed=9600; + tty_length=8; + tty_parity=RDTTYDevice::None; + tty_open=false; +} diff --git a/lib/rdttydevice.h b/lib/rdttydevice.h new file mode 100644 index 00000000..e4faa4b9 --- /dev/null +++ b/lib/rdttydevice.h @@ -0,0 +1,288 @@ +// rdttydevice.h +// +// A Qt driver for serial ports. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdttydevice.h,v 1.5 2011/05/04 18:09:06 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDTTYDEVICE_H +#define RDTTYDEVICE_H + +#define WIN32_BUFFER_SIZE 130 + +#ifdef WIN32 +#include <windows.h> +#else +#include <termios.h> +#include <unistd.h> +#endif // WIN32 +#include <qiodevice.h> +#include <qstring.h> + + +/** + * @short A QIODevice-compatible class for serial ports. + * @author Fred Gleason <fredg@paravelsystems.com> + * + * This class implements an QIODevice-compatible class for dealing + * with serial ports. + **/ + +class RDTTYDevice : public QIODevice +{ + public: + enum Parity {None=0,Even=1,Odd=2}; + + /** + * Create an RDTTYDevice object + **/ + RDTTYDevice(); + + /** + * Destroy an RDTTYDevice object + **/ + ~RDTTYDevice(); + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool open(int mode); + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + void close(); + +#ifndef WIN32 + int socket(); +#endif // WIN32 + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + void flush(); + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + Q_LONG readBlock(char *data,Q_ULONG maxlen); + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + Q_LONG writeBlock(const char *data,Q_ULONG len); + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + int getch(); + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + int putch(int ch); + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + int ungetch(int ch); + + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + QIODevice::Offset size() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + int flags() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + int mode() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + int state() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isDirectAccess() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isSequentialAccess() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isCombinedAccess() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isBuffered() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isRaw() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isSynchronous() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isAsynchronous() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isTranslated() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isReadable() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isWritable() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isReadWrite() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isInactive() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + bool isOpen() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + int status() const; + + /** + * This method is reimplemented from the QIODevice class, the API is + * unaffected. + **/ + void resetStatus(); + + /** + * Set the name of the tty device to use. + * @param name Name of tty device to use. + **/ + void setName(QString name); + + /** + * Returns the speed of the tty device, in bits per second. + **/ + int speed() const; + + /** + * Set the speed of the tty device. + * @param speed Speed of the tty device, in bits per second. + **/ + void setSpeed(int speed); + + /** + * Returns the word length of the tty device. + **/ + int wordLength() const; + + /** + * Set the word length of the tty device. + * @param length Word length in bits. Legal values are 5, 6, 7 or 8. + **/ + void setWordLength(int length); + + /** + * Returns the parity coding of the tty device. + **/ + RDTTYDevice::Parity parity() const; + + /** + * Set the parity coding of the tty device. + * @param parity Parity coding. + **/ + void setParity(Parity); + + private: + void Init(); + Parity tty_parity; + QString tty_name; + bool tty_open; + int tty_flags; + int tty_mode; + int tty_status; +#ifdef WIN32 + HANDLE tty_fd; + int tty_speed; + int tty_length; +#else + int tty_fd; + speed_t tty_speed; + tcflag_t tty_length; +#endif // WIN32 +}; + + +#endif // RDTTYDEVICE_H diff --git a/lib/rdttydevice_win32.cpp b/lib/rdttydevice_win32.cpp new file mode 100644 index 00000000..4b456cec --- /dev/null +++ b/lib/rdttydevice_win32.cpp @@ -0,0 +1,368 @@ +// rdttydevice_win32.cpp +// +// The Win32 version of a Qt driver for serial ports. +// +// (C) Copyright 2002 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdttydevice_win32.cpp,v 1.3 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <qiodevice.h> + +#include <rdttydevice.h> + + + +RDTTYDevice::RDTTYDevice() : QIODevice() +{ + Init(); +} + +RDTTYDevice::~RDTTYDevice() +{ + if(tty_open) { + close(); + } +} + +bool RDTTYDevice::open(int mode) +{ + DWORD flags=0; + WCHAR name[255]; + DCB dcb; + COMMTIMEOUTS timeouts; + + tty_mode=mode; + if((mode&IO_ReadWrite)==IO_ReadWrite) { + flags|=GENERIC_WRITE|GENERIC_READ; + } + else { + if(((mode&IO_WriteOnly)!=0)) { + flags|=GENERIC_WRITE; + } + if(((mode&IO_ReadOnly)!=0)) { + flags|=GENERIC_READ; + } + } + wcscpy(name,(TCHAR*)qt_winTchar(tty_name,true)); + tty_fd=CreateFile(name,flags,0,NULL,OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL,NULL); + if(tty_fd==INVALID_HANDLE_VALUE) { + tty_status=IO_OpenError; + return false; + } + tty_open=true; + tty_status=IO_Ok; + + SetupComm(tty_fd,WIN32_BUFFER_SIZE,WIN32_BUFFER_SIZE); + switch(tty_parity) { + case RDTTYDevice::None: + BuildCommDCB((TCHAR*)qt_winTchar(QString(). + sprintf("%d,N,%d,1", + tty_speed,tty_length), + true),&dcb); + break; + + case RDTTYDevice::Even: + BuildCommDCB((TCHAR*)qt_winTchar(QString(). + sprintf("%d,E,%d,1", + tty_speed,tty_length), + true),&dcb); + break; + + case RDTTYDevice::Odd: + BuildCommDCB((TCHAR*)qt_winTchar(QString(). + sprintf("%d,O,%d,1", + tty_speed,tty_length), + true),&dcb); + break; + } + SetCommState(tty_fd,&dcb); + timeouts.ReadIntervalTimeout=MAXDWORD; + timeouts.ReadTotalTimeoutMultiplier=0; + timeouts.ReadTotalTimeoutConstant=0; + timeouts.WriteTotalTimeoutMultiplier=0; + timeouts.WriteTotalTimeoutConstant=0; + SetCommTimeouts(tty_fd,&timeouts); + + return true; +} + + +void RDTTYDevice::close() +{ + if(tty_open) { + CloseHandle(tty_fd); + } + tty_open=false; +} + + +void RDTTYDevice::flush() +{ +} + + +Q_LONG RDTTYDevice::readBlock(char *data,Q_ULONG maxlen) +{ + Q_ULONG n; + + if(!ReadFile(tty_fd,data,maxlen,&n,NULL)) { + if(GetLastError()!=ERROR_TIMEOUT) { + tty_status=IO_ReadError; + return -1; + } + } + tty_status=IO_Ok; + return n; +} + + +Q_LONG RDTTYDevice::writeBlock(const char *data,Q_ULONG len) +{ + Q_ULONG n; + + if(!WriteFile(tty_fd,data,len,&n,NULL)) { + tty_status=IO_WriteError; + return n; + } + tty_status=IO_Ok; + return n; +} + + +int RDTTYDevice::getch() +{ + char c; + int n; + + if((n=readBlock(&c,1))<0) { + tty_status=IO_ReadError; + return -1; + } + return (int)c; +} + + +int RDTTYDevice::putch(int ch) +{ + char c; + int n; + + c=(char)ch; + if((n=writeBlock(&c,1))<0) { + tty_status=IO_WriteError; + return -1; + } + return ch; +} + + +int RDTTYDevice::ungetch(int ch) +{ + tty_status=IO_WriteError; + return -1; +} + + +QIODevice::Offset RDTTYDevice::size() const +{ + return 0; +} + + +int RDTTYDevice::flags() const +{ + return tty_mode|state(); +} + + +int RDTTYDevice::mode() const +{ + return tty_mode; +} + + +int RDTTYDevice::state() const +{ + if(tty_open) { + return IO_Open; + } + return 0; +} + + +bool RDTTYDevice::isDirectAccess() const +{ + return false; +} + + +bool RDTTYDevice::isSequentialAccess() const +{ + return true; +} + + +bool RDTTYDevice::isCombinedAccess() const +{ + return false; +} + + +bool RDTTYDevice::isBuffered() const +{ + return false; +} + + +bool RDTTYDevice::isRaw() const +{ + return true; +} + + +bool RDTTYDevice::isSynchronous() const +{ + return true; +} + + +bool RDTTYDevice::isAsynchronous() const +{ + return false; +} + + +bool RDTTYDevice::isTranslated() const +{ + return false; +} + + +bool RDTTYDevice::isReadable() const +{ + if(((tty_mode&IO_ReadOnly)!=0)||((tty_mode&IO_ReadWrite)!=0)) { + return true; + } + return false; +} + + +bool RDTTYDevice::isWritable() const +{ + if(((tty_mode&IO_WriteOnly)!=0)||((tty_mode&IO_ReadWrite)!=0)) { + return true; + } + return false; +} + + +bool RDTTYDevice::isReadWrite() const +{ + if((tty_mode&IO_ReadWrite)!=0) { + return true; + } + return false; + +} + + +bool RDTTYDevice::isInactive() const +{ + if(!tty_open) { + return true; + } + return false; +} + + +bool RDTTYDevice::isOpen() const +{ + if(tty_open) { + return true; + } + return false; +} + + +int RDTTYDevice::status() const +{ + return tty_status; +} + + +void RDTTYDevice::resetStatus() +{ + tty_status=IO_Ok; +} + + +void RDTTYDevice::setName(QString name) +{ + tty_name=name; +} + + +int RDTTYDevice::speed() const +{ + return tty_speed; +} + + +void RDTTYDevice::setSpeed(int speed) +{ + tty_speed=speed; +} + + +int RDTTYDevice::wordLength() const +{ + return tty_length; +} + + +void RDTTYDevice::setWordLength(int length) +{ + tty_length=length; +} + + +RDTTYDevice::Parity RDTTYDevice::parity() const +{ + return tty_parity; +} + + +void RDTTYDevice::setParity(Parity parity) +{ + tty_parity=parity; +} + + +void RDTTYDevice::Init() +{ + tty_speed=9600; + tty_length=8; + tty_parity=RDTTYDevice::None; + tty_open=false; +} diff --git a/lib/rdttyout.cpp b/lib/rdttyout.cpp new file mode 100644 index 00000000..f68b94f7 --- /dev/null +++ b/lib/rdttyout.cpp @@ -0,0 +1,66 @@ +// rdttyout.cpp +// +// Output a string on a Rivendell TTY +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdttyout.cpp,v 1.10 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdtty.h> +#include <rdttyout.h> + + +bool RDTtyOut(const QString &station,unsigned port_id,const QString &str) +{ + RDTty *tty_entry=new RDTty(station,port_id); + if(!tty_entry->active()) { + delete tty_entry; + return false; + } + RDTTYDevice *tty_device=new RDTTYDevice(); + tty_device->setName(tty_entry->port()); + tty_device->setSpeed(tty_entry->baudRate()); + tty_device->setWordLength(tty_entry->dataBits()); + tty_device->setParity(tty_entry->parity()); + if(!tty_device->open(IO_Raw|IO_WriteOnly)) { + delete tty_device; + delete tty_entry; + return false; + } + tty_device->writeBlock((const char *)str,strlen((const char *)str)); + switch(tty_entry->termination()) { + case RDTty::CrTerm: + tty_device->putch(13); + break; + + case RDTty::LfTerm: + tty_device->putch(10); + break; + + case RDTty::CrLfTerm: + tty_device->putch(13); + tty_device->putch(10); + break; + + default: + break; + } + tty_device->close(); + delete tty_device; + delete tty_entry; + return true; +} diff --git a/lib/rdttyout.h b/lib/rdttyout.h new file mode 100644 index 00000000..56fbceb6 --- /dev/null +++ b/lib/rdttyout.h @@ -0,0 +1,34 @@ +// rdttyout.h +// +// Output a string on a Rivendell TTY +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdttyout.h,v 1.7 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qstring.h> +#include <qsqldatabase.h> + +#include <rdttydevice.h> + +#ifndef RDTTYOUT_H +#define RDTTYOUT_H + +bool RDTtyOut(const QString &station,unsigned port_id,const QString &string); + + +#endif diff --git a/lib/rdupload.cpp b/lib/rdupload.cpp new file mode 100644 index 00000000..5d1a999c --- /dev/null +++ b/lib/rdupload.cpp @@ -0,0 +1,291 @@ +// rdupload.cpp +// +// Upload a File +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdupload.cpp,v 1.5.4.2 2012/05/10 23:12:42 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#define _XOPEN_SOURCE +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <syslog.h> +#include <pwd.h> + +#include <curl/curl.h> + +#include <qapplication.h> +#include <qfileinfo.h> + +#include <rd.h> +#include <rdsystemuser.h> +#include <rdupload.h> + +// +// CURL Progress Callback +// +int UploadProgressCallback(void *clientp,double dltotal,double dlnow, + double ultotal,double ulnow) +{ + RDUpload *conv=(RDUpload *)clientp; + conv->UpdateProgress(ulnow); + qApp->processEvents(); + if(conv->aborting()) { + return 1; + } + return 0; +} + + +int UploadErrorCallback(CURL *curl,curl_infotype type,char *msg,size_t size, + void *clientp) +{ + char str[1000]; + + if(type!=CURLINFO_TEXT) { + return 0; + } + if(size>999) { + size=999; + } + memset(&str,0,size+1); + memcpy(str,msg,size); + syslog(LOG_DEBUG,"CURL MSG: %s",str); + return 0; +} + + +RDUpload::RDUpload(const QString &station_name, + QObject *parent,const char *name) + : QObject(parent,name) +{ + conv_aborting=false; +} + + +void RDUpload::setSourceFile(const QString &filename) +{ + conv_src_filename=filename; + QFileInfo fi(filename); + conv_src_size=fi.size(); +} + + +void RDUpload::setDestinationUrl(const QString &url) +{ + conv_dst_url=url; +} + + +int RDUpload::totalSteps() const +{ + return conv_src_size; +} + + +RDUpload::ErrorCode RDUpload::runUpload(const QString &username, + const QString &password, + bool log_debug) +{ + CURL *curl=NULL; + CURLcode curl_err; + FILE *f; + RDUpload::ErrorCode ret=RDUpload::ErrorOk; + RDSystemUser *user=NULL; + char url[1024]; + char userpwd[256]; + + // + // Validate User for file: transfers + // + if((getuid()==0)&&(conv_dst_url.protocol().lower()=="file")) { + user=new RDSystemUser(username); + if(!user->validatePassword(password)) { + delete user; + return RDUpload::ErrorInvalidUser; + } + } + + if((curl=curl_easy_init())==NULL) { + return RDUpload::ErrorInternal; + } + if((f=fopen(conv_src_filename,"r"))==NULL) { + curl_easy_cleanup(curl); + return RDUpload::ErrorNoSource; + } + + // + // Write out URL as a C string before passing to curl_easy_setopt(), + // otherwise some versions of LibCurl will throw a 'bad/illegal format' + // error. + // + strncpy(url,conv_dst_url.toString(conv_dst_url.protocol().lower()=="http"), + 1024); + curl_easy_setopt(curl,CURLOPT_URL,url); + curl_easy_setopt(curl,CURLOPT_UPLOAD,1); + curl_easy_setopt(curl,CURLOPT_READDATA,f); + curl_easy_setopt(curl,CURLOPT_INFILESIZE,(long)conv_src_size); + strncpy(userpwd,(username+":"+password),256); + curl_easy_setopt(curl,CURLOPT_USERPWD,userpwd); + curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT); + curl_easy_setopt(curl,CURLOPT_PROGRESSFUNCTION,UploadProgressCallback); + curl_easy_setopt(curl,CURLOPT_PROGRESSDATA,this); + curl_easy_setopt(curl,CURLOPT_NOPROGRESS,0); + if(log_debug) { + curl_easy_setopt(curl,CURLOPT_VERBOSE,1); + curl_easy_setopt(curl,CURLOPT_DEBUGFUNCTION,UploadErrorCallback); + } + if(user!=NULL) { + setegid(user->gid()); + seteuid(user->uid()); + } + switch((curl_err=curl_easy_perform(curl))) { + case CURLE_OK: + case CURLE_PARTIAL_FILE: + break; + + case CURLE_UNSUPPORTED_PROTOCOL: + ret=RDUpload::ErrorUnsupportedProtocol; + break; + + case CURLE_URL_MALFORMAT: + ret=RDUpload::ErrorUrlInvalid; + break; + + case CURLE_COULDNT_RESOLVE_HOST: + ret=RDUpload::ErrorInvalidHostname; + break; + + case CURLE_LOGIN_DENIED: + ret=RDUpload::ErrorInvalidLogin; + break; + + case CURLE_COULDNT_CONNECT: + ret=RDUpload::ErrorRemoteConnection; + break; + + case 9: // CURLE_REMOTE_ACCESS_DENIED + ret=RDUpload::ErrorRemoteAccess; + break; + + default: + syslog(LOG_ERR,"Unknown CURL Error [%d]: %s", + curl_err,curl_easy_strerror(curl_err)); + ret=RDUpload::ErrorUnspecified; + break; + } + if(user!=NULL) { + seteuid(getuid()); + setegid(getgid()); + delete user; + } + if((curl_err!=CURLE_OK)&&log_debug) { + syslog(LOG_WARNING,"CURL upload failed: url: %s username: %s", + (const char *)conv_dst_url.toString(), + (const char *)username); + } + curl_easy_cleanup(curl); + fclose(f); + + return ret; +} + + +bool RDUpload::aborting() const +{ + return conv_aborting; +} + + +QString RDUpload::errorText(RDUpload::ErrorCode err) +{ + QString ret=QString().sprintf("Unknown Error [%u]",err); + + switch(err) { + case RDUpload::ErrorOk: + ret=tr("OK"); + break; + + case RDUpload::ErrorUnsupportedProtocol: + ret=tr("Unsupported protocol"); + break; + + case RDUpload::ErrorNoSource: + ret=tr("Unable to access source file"); + break; + + case RDUpload::ErrorNoDestination: + ret=tr("Unable to create destination file"); + break; + + case RDUpload::ErrorInvalidHostname: + ret=tr("Unable to resolve hostname"); + break; + + case RDUpload::ErrorRemoteServer: + ret=tr("Remote server error"); + break; + + case RDUpload::ErrorUrlInvalid: + ret=tr("Invalid URL"); + break; + + case RDUpload::ErrorUnspecified: + ret=tr("Unspecified error"); + break; + + case RDUpload::ErrorInvalidUser: + ret=tr("Invalid User"); + break; + + case RDUpload::ErrorInternal: + ret=tr("Internal Error"); + break; + + case RDUpload::ErrorAborted: + ret=tr("Upload aborted"); + break; + + case RDUpload::ErrorInvalidLogin: + ret=tr("Invalid username or password"); + break; + + case RDUpload::ErrorRemoteAccess: + ret=tr("Remote access denied"); + break; + + case RDUpload::ErrorRemoteConnection: + ret=tr("Couldn't connect to server"); + break; + } + return ret; +} + + +void RDUpload::abort() +{ + conv_aborting=true; +} + + +void RDUpload::UpdateProgress(int step) +{ + emit progressChanged(step); +} diff --git a/lib/rdupload.h b/lib/rdupload.h new file mode 100644 index 00000000..9a1bf393 --- /dev/null +++ b/lib/rdupload.h @@ -0,0 +1,67 @@ +// rdupload.h +// +// Upload a File +// +// (C) Copyright 2010 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdupload.h,v 1.2 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDUPLOAD_H +#define RDUPLOAD_H + +#include <qobject.h> +#include <qurl.h> + +class RDUpload : public QObject +{ + Q_OBJECT; + public: + enum ErrorCode {ErrorOk=0,ErrorUnsupportedProtocol=1,ErrorNoSource=2, + ErrorNoDestination=3,ErrorInvalidHostname=4, + ErrorInternal=5,ErrorRemoteServer=6,ErrorUrlInvalid=7, + ErrorUnspecified=8,ErrorInvalidUser=9,ErrorAborted=10, + ErrorInvalidLogin=11,ErrorRemoteAccess=12, + ErrorRemoteConnection=13}; + RDUpload(const QString &station_name, + QObject *parent=0,const char *name=0); + void setSourceFile(const QString &filename); + void setDestinationUrl(const QString &url); + int totalSteps() const; + RDUpload::ErrorCode runUpload(const QString &username, + const QString &password, + bool log_debug); + bool aborting() const; + static QString errorText(RDUpload::ErrorCode err); + + public slots: + void abort(); + + signals: + void progressChanged(int step); + + private: + void UpdateProgress(int step); + friend int UploadProgressCallback(void *clientp,double dltotal,double dlnow, + double ultotal,double ulnow); + QString conv_src_filename; + QUrl conv_dst_url; + bool conv_aborting; + uint conv_src_size; +}; + + +#endif // RDUPLOAD_H diff --git a/lib/rdurl.cpp b/lib/rdurl.cpp new file mode 100644 index 00000000..3cda2a6c --- /dev/null +++ b/lib/rdurl.cpp @@ -0,0 +1,64 @@ +// rdurl.cpp +// +// A URL Handling Class with Support for SMB URLs. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdurl.cpp,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <rdurl.h> + + +RDUrl::RDUrl() + : QUrl() +{ +} + + +RDUrl::RDUrl(const QString &url) + : QUrl(url) +{ +} + + +bool RDUrl::validSmbShare() const +{ + return (protocol()=="smb")&&(!host().isEmpty())&&(path()!="/"); +} + + +QString RDUrl::smbShare() const +{ + int offset=0; + if((offset=path().right(path().length()-1).find("/"))<0) { + offset=path().length(); + } + return QString().sprintf("//%s%s", + (const char *)host(), + (const char *)path().left(offset+1)); +} + + +QString RDUrl::smbPath() const +{ + int offset=0; + if((offset=path().right(path().length()-1).find("/"))<0) { + return QString("/"); + } + return path().right(path().length()-offset-1); +} diff --git a/lib/rdurl.h b/lib/rdurl.h new file mode 100644 index 00000000..b258601a --- /dev/null +++ b/lib/rdurl.h @@ -0,0 +1,41 @@ +// rdurl.h +// +// A URL Handling Class with Support for SMB URLs. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdurl.h,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDURL_H +#define RDURL_H + +#include <qurl.h> + + +class RDUrl : public QUrl +{ + public: + RDUrl(); + RDUrl(const QString &url); + bool validSmbShare() const; + QString smbShare() const; + QString smbPath() const; +}; + + +#endif // RDURL_H diff --git a/lib/rduser.cpp b/lib/rduser.cpp new file mode 100644 index 00000000..47d9ad8d --- /dev/null +++ b/lib/rduser.cpp @@ -0,0 +1,506 @@ +// rduser.cpp +// +// Abstract a Rivendell User. +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rduser.cpp,v 1.26.8.1 2013/12/03 23:34:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rdconf.h> +#include <rduser.h> +#include <rddb.h> +#include <rdescape_string.h> + +// +// Global Classes +// +RDUser::RDUser(const QString &name) +{ + user_name=name; +} + + +QString RDUser::name() const +{ + return user_name; +} + + +bool RDUser::exists() const +{ + return RDDoesRowExist("USERS","LOGIN_NAME",user_name); +} + + +bool RDUser::authenticated(bool webuser) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("select LOGIN_NAME,ENABLE_WEB from USERS \ + where LOGIN_NAME=\"%s\" \ + && PASSWORD=\"%s\"", + (const char *)RDEscapeString(user_name), + (const char *)RDEscapeString(user_password)); + q=new RDSqlQuery(sql); + if(q->first()) { + bool ret=RDBool(q->value(1).toString())|| + ((!RDBool(q->value(1).toString()))&&(!webuser)); + delete q; + return ret; + } + delete q; + + return false; +} + + +bool RDUser::checkPassword(const QString &password,bool webuser) +{ + user_password=password; + return authenticated(webuser); +} + + +QString RDUser::password() const +{ + return RDGetSqlValue("USERS","LOGIN_NAME",user_name,"PASSWORD").toString(); +} + + +void RDUser::setPassword(const QString &password) +{ + user_password=password; + SetRow("PASSWORD",password); +} + + +bool RDUser::enableWeb() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name,"ENABLE_WEB"). + toString()); +} + + +void RDUser::setEnableWeb(bool state) const +{ + SetRow("ENABLE_WEB",RDYesNo(state)); +} + + +QString RDUser::fullName() const +{ + return RDGetSqlValue("USERS","LOGIN_NAME",user_name,"FULL_NAME").toString(); +} + + +void RDUser::setFullName(const QString &name) const +{ + SetRow("FULL_NAME",name); +} + + +QString RDUser::description() const +{ + return RDGetSqlValue("USERS","LOGIN_NAME",user_name,"DESCRIPTION").toString(); +} + + +void RDUser::setDescription(const QString &desc) const +{ + SetRow("DESCRIPTION",desc); +} + + +QString RDUser::phone() const +{ + return RDGetSqlValue("USERS","LOGIN_NAME",user_name,"PHONE_NUMBER"). + toString(); +} + + +void RDUser::setPhone(const QString &phone) const +{ + SetRow("PHONE_NUMBER",phone); +} + + +bool RDUser::adminConfig() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "ADMIN_CONFIG_PRIV").toString()); +} + + +void RDUser::setAdminConfig(bool priv) const +{ + SetRow("ADMIN_CONFIG_PRIV",priv); +} + + +bool RDUser::createCarts() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "CREATE_CARTS_PRIV").toString()); +} + + +void RDUser::setCreateCarts(bool priv) const +{ + SetRow("CREATE_CARTS_PRIV",priv); +} + + +bool RDUser::deleteCarts() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "DELETE_CARTS_PRIV").toString()); +} + + +void RDUser::setDeleteCarts(bool priv) const +{ + SetRow("DELETE_CARTS_PRIV",priv); +} + + +bool RDUser::modifyCarts() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "MODIFY_CARTS_PRIV").toString()); +} + + +void RDUser::setModifyCarts(bool priv) const +{ + SetRow("MODIFY_CARTS_PRIV",priv); +} + + +bool RDUser::editAudio() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "EDIT_AUDIO_PRIV").toString()); +} + + +void RDUser::setEditAudio(bool priv) const +{ + SetRow("EDIT_AUDIO_PRIV",priv); +} + + +bool RDUser::createLog() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "CREATE_LOG_PRIV").toString()); +} + + +void RDUser::setCreateLog(bool priv) const +{ + SetRow("CREATE_LOG_PRIV",priv); +} + + +bool RDUser::deleteLog() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "DELETE_LOG_PRIV").toString()); +} + + +void RDUser::setDeleteLog(bool priv) const +{ + SetRow("DELETE_LOG_PRIV",priv); +} + + +bool RDUser::deleteRec() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "DELETE_REC_PRIV").toString()); +} + + +void RDUser::setDeleteRec(bool priv) const +{ + SetRow("DELETE_REC_PRIV",priv); +} + + +bool RDUser::playoutLog() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "PLAYOUT_LOG_PRIV").toString()); +} + + +void RDUser::setPlayoutLog(bool priv) const +{ + SetRow("PLAYOUT_LOG_PRIV",priv); +} + + +bool RDUser::arrangeLog() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "ARRANGE_LOG_PRIV").toString()); +} + + +void RDUser::setArrangeLog(bool priv) const +{ + SetRow("ARRANGE_LOG_PRIV",priv); +} + + +bool RDUser::addtoLog() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "ADDTO_LOG_PRIV").toString()); +} + + +void RDUser::setAddtoLog(bool priv) const +{ + SetRow("ADDTO_LOG_PRIV",priv); +} + + +bool RDUser::removefromLog() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "REMOVEFROM_LOG_PRIV").toString()); +} + + +bool RDUser::configPanels() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "CONFIG_PANELS_PRIV").toString()); +} + + +void RDUser::setConfigPanels(bool priv) const +{ + SetRow("CONFIG_PANELS_PRIV",priv); +} + + +void RDUser::setRemovefromLog(bool priv) const +{ + SetRow("REMOVEFROM_LOG_PRIV",priv); +} + + +bool RDUser::voicetrackLog() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "VOICETRACK_LOG_PRIV").toString()); +} + + +void RDUser::setVoicetrackLog(bool priv) const +{ + SetRow("VOICETRACK_LOG_PRIV",priv); +} + + +bool RDUser::modifyTemplate() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "MODIFY_TEMPLATE_PRIV").toString()); +} + + +void RDUser::setModifyTemplate(bool priv) const +{ + SetRow("MODIFY_TEMPLATE_PRIV",priv); +} + + +bool RDUser::editCatches() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "EDIT_CATCHES_PRIV").toString()); +} + + +void RDUser::setEditCatches(bool priv) const +{ + SetRow("EDIT_CATCHES_PRIV",priv); +} + + +bool RDUser::addPodcast() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "ADD_PODCAST_PRIV").toString()); +} + + +void RDUser::setAddPodcast(bool priv) const +{ + SetRow("ADD_PODCAST_PRIV",priv); +} + + +bool RDUser::editPodcast() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "EDIT_PODCAST_PRIV").toString()); +} + + +void RDUser::setEditPodcast(bool priv) const +{ + SetRow("EDIT_PODCAST_PRIV",priv); +} + + +bool RDUser::deletePodcast() const +{ + return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, + "DELETE_PODCAST_PRIV").toString()); +} + + +void RDUser::setDeletePodcast(bool priv) const +{ + SetRow("DELETE_PODCAST_PRIV",priv); +} + + +bool RDUser::groupAuthorized(const QString &group_name) +{ + QString sql; + RDSqlQuery *q; + bool ret=false; + + sql=QString(). + sprintf("select GROUP_NAME from USER_PERMS where USER_NAME=\"%s\"", + (const char *)RDEscapeString(user_name)); + q=new RDSqlQuery(sql); + ret=q->first(); + delete q; + return ret; +} + + +QStringList RDUser::groups() const +{ + QString sql; + RDSqlQuery *q; + QStringList ret; + + sql=QString("select GROUP_NAME from USER_PERMS where ")+ + "USER_NAME=\""+RDEscapeString(user_name)+"\" order by GROUP_NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + ret.push_back(q->value(0).toString()); + } + delete q; + + return ret; +} + + +bool RDUser::cartAuthorized(unsigned cartnum) const +{ + QString sql; + RDSqlQuery *q; + bool ret=false; + + sql=QString(). + sprintf("select CART.NUMBER from CART \ + left join USER_PERMS \ + on CART.GROUP_NAME=USER_PERMS.GROUP_NAME \ + where (USER_PERMS.USER_NAME=\"%s\")&&(CART.NUMBER=%u)", + (const char *)RDEscapeString(user_name),cartnum); + q=new RDSqlQuery(sql); + ret=q->first(); + delete q; + return ret; +} + + +QString RDUser::serviceCheckDefault(QString serv) const +{ + bool match_flag = false; + QStringList services_list = services(); + + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end(); ++it ) { + if (serv.compare(*it) == 0) { + match_flag = true; + break; + } + } + + if (match_flag) + return serv; + else + return QString(""); +} + + +QStringList RDUser::services() const +{ + RDSqlQuery *q; + QString sql; + QStringList services_list; + + if (adminConfig()) { + sql=QString().sprintf("SELECT NAME FROM SERVICES" ); + } + else { + sql=QString().sprintf("select distinct AUDIO_PERMS.SERVICE_NAME \ + from USER_PERMS left join AUDIO_PERMS \ + on USER_PERMS.GROUP_NAME=AUDIO_PERMS.GROUP_NAME \ + where USER_PERMS.USER_NAME=\"%s\"", + (const char *)RDEscapeString(user_name)); + } + + q=new RDSqlQuery(sql); + while (q->next() ) { + services_list.append( q->value(0).toString() ); + } + delete q; + + return services_list; +} + + +void RDUser::SetRow(const QString ¶m,const QString &value) const +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("UPDATE USERS SET %s=\"%s\" WHERE LOGIN_NAME=\"%s\"", + (const char *)param, + (const char *)RDEscapeString(value), + (const char *)user_name); + q=new RDSqlQuery(sql); + delete q; +} + + +void RDUser::SetRow(const QString ¶m,bool value) const +{ + SetRow(param,RDYesNo(value)); +} diff --git a/lib/rduser.h b/lib/rduser.h new file mode 100644 index 00000000..2bf76ebd --- /dev/null +++ b/lib/rduser.h @@ -0,0 +1,113 @@ +// rduser.h +// +// Abstract a Rivendell User +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rduser.h,v 1.22.8.1 2013/12/03 23:34:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> + +#ifndef RDUSER_H +#define RDUSER_H + +class RDUser +{ + public: + RDUser(const QString &name); + QString name() const; + bool exists() const; + bool authenticated(bool webuser) const; + bool checkPassword(const QString &password,bool webuser); + QString password() const; + void setPassword(const QString &password); + bool enableWeb() const; + void setEnableWeb(bool state) const; + QString fullName() const; + void setFullName(const QString &name) const; + QString description() const; + void setDescription(const QString &desc) const; + QString phone() const; + void setPhone(const QString &phone) const; + bool adminConfig() const; + void setAdminConfig(bool priv) const; + bool createCarts() const; + void setCreateCarts(bool priv) const; + bool deleteCarts() const; + void setDeleteCarts(bool priv) const; + bool modifyCarts() const; + void setModifyCarts(bool priv) const; + bool editAudio() const; + void setEditAudio(bool priv) const; + bool createLog() const; + void setCreateLog(bool priv) const; + bool deleteLog() const; + void setDeleteLog(bool priv) const; + bool deleteRec() const; + void setDeleteRec(bool priv) const; + bool playoutLog() const; + void setPlayoutLog(bool priv) const; + bool arrangeLog() const; + void setArrangeLog(bool priv) const; + bool addtoLog() const; + void setAddtoLog(bool priv) const; + bool removefromLog() const; + void setRemovefromLog(bool priv) const; + bool configPanels() const; + void setConfigPanels(bool priv) const; + bool voicetrackLog() const; + void setVoicetrackLog(bool priv) const; + bool modifyTemplate() const; + void setModifyTemplate(bool priv) const; + bool editCatches() const; + void setEditCatches(bool priv) const; + bool addPodcast() const; + void setAddPodcast(bool priv) const; + bool editPodcast() const; + void setEditPodcast(bool priv) const; + bool deletePodcast() const; + void setDeletePodcast(bool priv) const; + bool groupAuthorized(const QString &group_name); + QStringList groups() const; + bool cartAuthorized(unsigned cartnum) const; + + /** Check a default service to ensure it is valid for the current user. + * + * @param serv QString with the proposed default service, presumably gotten + * from RDAirPlayConf::defaultSvc() + * @return QString with serv if it was valid, otherwise an empty QString. + */ + QString serviceCheckDefault(QString serv) const; + + /** Calculate the services associated with a user, based on the user's group + * membership and the relationship of groups to services. + * + * Note: admin users, those who pass adminConfig(), can see all services. + * + * @return QStringList with all the services associated with the user. + */ + QStringList services() const; + + private: + void SetRow(const QString ¶m,const QString &value) const; + void SetRow(const QString ¶m,bool value) const; + QString user_name; + QString user_password; +}; + + +#endif // RDUSER_H diff --git a/lib/rdversion.cpp b/lib/rdversion.cpp new file mode 100644 index 00000000..c09517f9 --- /dev/null +++ b/lib/rdversion.cpp @@ -0,0 +1,59 @@ +// rdversion.cpp +// +// Get / Set Version Numbers of Rivendell Components +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdversion.cpp,v 1.8 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <rd.h> +#include <rddb.h> +#include <rdversion.h> + + +// +// Global Classes +// +RDVersion::RDVersion() +{ +} + + +int RDVersion::database() +{ + int ver; + + RDSqlQuery *q=new RDSqlQuery("select DB from VERSION"); + if(!q->first()) { + delete q; + return 0; + } + ver=q->value(0).toInt(); + delete q; + return ver; +} + + +void RDVersion::setDatabase(int ver) +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update VERSION set DB=%d",ver); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/lib/rdversion.h b/lib/rdversion.h new file mode 100644 index 00000000..e2d48eaa --- /dev/null +++ b/lib/rdversion.h @@ -0,0 +1,37 @@ +// rdversion.h +// +// Get / Set Version Numbers of Rivendell Components +// +// (C) Copyright 2002-2003 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdversion.h,v 1.6 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qsqldatabase.h> + +#ifndef RDVERSION_H +#define RDVERSION_H + +class RDVersion +{ + public: + RDVersion(); + int database(); + void setDatabase(int); +}; + + +#endif // RDVERSION_H diff --git a/lib/rdwavedata.cpp b/lib/rdwavedata.cpp new file mode 100644 index 00000000..1c876923 --- /dev/null +++ b/lib/rdwavedata.cpp @@ -0,0 +1,684 @@ +// rdwavedata.cpp +// +// A Container Class for Audio Meta Data. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdwavedata.cpp,v 1.4.8.3.2.2 2014/07/15 20:02:23 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <rdwavedata.h> + + +RDWaveData::RDWaveData() +{ + clear(); +} + + +bool RDWaveData::metadataFound() const +{ + return data_metadata_found; +} + + +void RDWaveData::setMetadataFound(bool state) +{ + data_metadata_found=state; +} + + +QString RDWaveData::title() const +{ + return data_title; +} + + +void RDWaveData::setTitle(const QString &str) +{ + data_title=str; +} + + +QString RDWaveData::artist() const +{ + return data_artist; +} + + +void RDWaveData::setArtist(const QString &str) +{ + data_artist=str; +} + + +QString RDWaveData::album() const +{ + return data_album; +} + + +void RDWaveData::setAlbum(const QString &str) +{ + data_album=str; +} + + +QString RDWaveData::conductor() const +{ + return data_conductor; +} + + +void RDWaveData::setConductor(const QString &str) +{ + data_conductor=str; +} + + +QString RDWaveData::label() const +{ + return data_label; +} + + +void RDWaveData::setLabel(const QString &str) +{ + data_label=str; +} + + +int RDWaveData::releaseYear() const +{ + return data_release_year; +} + + +void RDWaveData::setReleaseYear(int year) +{ + data_release_year=year; +} + + +QString RDWaveData::client() const +{ + return data_client; +} + + +void RDWaveData::setClient(const QString &str) +{ + data_client=str; +} + + +QString RDWaveData::agency() const +{ + return data_agency; +} + + +void RDWaveData::setAgency(const QString &str) +{ + data_agency=str; +} + + +QString RDWaveData::composer() const +{ + return data_composer; +} + + +void RDWaveData::setComposer(const QString &str) +{ + data_composer=str; +} + + +QString RDWaveData::publisher() const +{ + return data_publisher; +} + + +void RDWaveData::setPublisher(const QString &str) +{ + data_publisher=str; +} + + +int RDWaveData::usageCode() const +{ + return data_usage_code; +} + + +void RDWaveData::setUsageCode(int code) +{ + data_usage_code=code; +} + + +QStringList RDWaveData::schedCodes() const +{ + return data_sched_codes; +} + + +void RDWaveData::setSchedCodes(const QStringList &codes) +{ + data_sched_codes=codes; +} + + +QString RDWaveData::licensingOrganization() const +{ + return data_licensing_organization; +} + + +void RDWaveData::setLicensingOrganization(const QString &str) +{ + data_licensing_organization=str; +} + + +QString RDWaveData::copyrightNotice() const +{ + return data_copyright_notice; +} + + +void RDWaveData::setCopyrightNotice(const QString &str) +{ + data_copyright_notice=str; +} + + +QString RDWaveData::cutId() const +{ + return data_cut_id; +} + + +void RDWaveData::setCutId(const QString &str) +{ + data_cut_id=str; +} + + +QString RDWaveData::classification() const +{ + return data_classification; +} + + +void RDWaveData::setClassification(const QString &str) +{ + data_classification=str; +} + + +QString RDWaveData::category() const +{ + return data_category; +} + + +void RDWaveData::setCategory(const QString &str) +{ + data_category=str; +} + + +QString RDWaveData::url() const +{ + return data_url; +} + + +void RDWaveData::setUrl(const QString &str) +{ + data_url=str; +} + + +QString RDWaveData::tagText() const +{ + return data_tag_text; +} + + +void RDWaveData::setTagText(const QString &str) +{ + data_tag_text=str; +} + + +QString RDWaveData::description() const +{ + return data_description; +} + + +void RDWaveData::setDescription(const QString &str) +{ + data_description=str; +} + + +QString RDWaveData::originator() const +{ + return data_originator; +} + + +void RDWaveData::setOriginator(const QString &str) +{ + data_originator=str; +} + + +QString RDWaveData::originatorReference() const +{ + return data_originator_reference; +} + + +void RDWaveData::setOriginatorReference(const QString &str) +{ + data_originator_reference=str; +} + + +QString RDWaveData::codingHistory() const +{ + return data_coding_history; +} + + +void RDWaveData::setCodingHistory(const QString &str) +{ + data_coding_history=str; +} + + +QString RDWaveData::userDefined() const +{ + return data_user_defined; +} + + +void RDWaveData::setUserDefined(const QString &str) +{ + data_user_defined=str; +} + + +QString RDWaveData::isrc() const +{ + return data_isrc; +} + + +void RDWaveData::setIsrc(const QString &str) +{ + data_isrc=str; +} + + +QString RDWaveData::isci() const +{ + return data_isci; +} + + +void RDWaveData::setIsci(const QString &str) +{ + data_isci=str; +} + + +QString RDWaveData::mcn() const +{ + return data_mcn; +} + + +void RDWaveData::setMcn(const QString &str) +{ + data_mcn=str; +} + + +QString RDWaveData::outCue() const +{ + return data_out_cue; +} + + +void RDWaveData::setOutCue(const QString &str) +{ + data_out_cue=str; +} + + +RDWaveData::EndType RDWaveData::endType() const +{ + return data_end_type; +} + + +void RDWaveData::setEndType(RDWaveData::EndType type) +{ + data_end_type=type; +} + + +int RDWaveData::introStartPos() const +{ + return data_intro_start_pos; +} + + +void RDWaveData::setIntroStartPos(int msec) +{ + data_intro_start_pos=msec; +} + + +int RDWaveData::introEndPos() const +{ + return data_intro_end_pos; +} + + +void RDWaveData::setIntroEndPos(int msec) +{ + data_intro_end_pos=msec; +} + + +int RDWaveData::segueStartPos() const +{ + return data_segue_start_pos; +} + + +void RDWaveData::setSegueStartPos(int msec) +{ + data_segue_start_pos=msec; +} + + +int RDWaveData::segueEndPos() const +{ + return data_segue_end_pos; +} + + +void RDWaveData::setSegueEndPos(int msec) +{ + data_segue_end_pos=msec; +} + + +int RDWaveData::startPos() const +{ + return data_start_pos; +} + + +void RDWaveData::setStartPos(int msec) +{ + data_start_pos=msec; +} + + +int RDWaveData::endPos() const +{ + return data_end_pos; +} + + +void RDWaveData::setEndPos(int msec) +{ + data_end_pos=msec; +} + + +int RDWaveData::hookStartPos() const +{ + return data_hook_start_pos; +} + + +void RDWaveData::setHookStartPos(int msec) +{ + data_hook_start_pos=msec; +} + + +int RDWaveData::hookEndPos() const +{ + return data_hook_end_pos; +} + + +void RDWaveData::setHookEndPos(int msec) +{ + data_hook_end_pos=msec; +} + + +int RDWaveData::fadeUpPos() const +{ + return data_fade_up_pos; +} + + +void RDWaveData::setFadeUpPos(int msec) +{ + data_fade_up_pos=msec; +} + + +int RDWaveData::fadeDownPos() const +{ + return data_fade_down_pos; +} + + +void RDWaveData::setFadeDownPos(int msec) +{ + data_fade_down_pos=msec; +} + + +int RDWaveData::beatsPerMinute() const +{ + return data_beats_per_minute; +} + + +void RDWaveData::setBeatsPerMinute(int bpm) +{ + data_beats_per_minute=bpm; +} + + +QString RDWaveData::tmciSongId() const +{ + return data_tmci_song_id; +} + + +void RDWaveData::setTmciSongId(const QString &str) +{ + data_tmci_song_id=str; +} + + +QDate RDWaveData::startDate() const +{ + return data_start_date; +} + + +void RDWaveData::setStartDate(const QDate &date) +{ + data_start_date=date; +} + + +QTime RDWaveData::startTime() const +{ + return data_start_time; +} + + +void RDWaveData::setStartTime(const QTime &time) +{ + data_start_time=time; +} + + +QDate RDWaveData::originationDate() const +{ + return data_origination_date; +} + + +void RDWaveData::setOriginationDate(const QDate &date) +{ + data_origination_date=date; +} + + +QTime RDWaveData::originationTime() const +{ + return data_origination_time; +} + + +void RDWaveData::setOriginationTime(const QTime &time) +{ + data_origination_time=time; +} + + +QDate RDWaveData::endDate() const +{ + return data_end_date; +} + + +void RDWaveData::setEndDate(const QDate &date) +{ + data_end_date=date; +} + + +QTime RDWaveData::endTime() const +{ + return data_end_time; +} + + +void RDWaveData::setEndTime(const QTime &time) +{ + data_end_time=time; +} + + +QTime RDWaveData::daypartStartTime() const +{ + return data_daypart_start_time; +} + + +void RDWaveData::setDaypartStartTime(const QTime &time) +{ + data_daypart_start_time=time; +} + + +QTime RDWaveData::daypartEndTime() const +{ + return data_daypart_end_time; +} + + +void RDWaveData::setDaypartEndTime(const QTime &time) +{ + data_daypart_end_time=time; +} + + +void RDWaveData::clear() +{ + data_metadata_found=false; + data_title=""; + data_artist=""; + data_album=""; + data_conductor=""; + data_label=""; + data_release_year=0; + data_client=""; + data_agency=""; + data_composer=""; + data_publisher=""; + data_usage_code=0; + data_sched_codes.clear(); + data_licensing_organization=""; + data_copyright_notice=""; + data_user_defined=""; + data_cut_id=""; + data_classification=""; + data_category=""; + data_url=""; + data_tag_text=""; + data_description=""; + data_originator=""; + data_originator_reference=""; + data_isrc=""; + data_isci=""; + data_mcn=""; + data_out_cue=""; + data_end_type=RDWaveData::UnknownEnd; + data_intro_start_pos=-1; + data_intro_end_pos=-1; + data_segue_start_pos=-1; + data_segue_end_pos=-1; + data_start_pos=-1; + data_end_pos=-1; + data_hook_start_pos=-1; + data_hook_end_pos=-1; + data_fade_up_pos=-1; + data_fade_down_pos=-1; + data_beats_per_minute=0; + data_tmci_song_id=""; + data_origination_date=QDate(); + data_origination_time=QTime(); + data_start_date=QDate(); + data_start_time=QTime(); + data_end_date=QDate(); + data_end_time=QTime(); + data_daypart_start_time=QTime(); + data_daypart_end_time=QTime(); +} diff --git a/lib/rdwavedata.h b/lib/rdwavedata.h new file mode 100644 index 00000000..02e68efe --- /dev/null +++ b/lib/rdwavedata.h @@ -0,0 +1,197 @@ +// rdwavedata.h +// +// A Container Class for Audio Meta Data. +// +// (C) Copyright 2002-2006 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdwavedata.h,v 1.5.8.3.2.2 2014/07/15 20:02:23 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDWAVEDATA_H +#define RDWAVEDATA_H + +#include <qstring.h> +#include <qstringlist.h> +#include <qdatetime.h> + +class RDWaveData +{ + public: + enum EndType {UnknownEnd='N',ColdEnd='C',FadeEnd='F'}; + RDWaveData(); + bool metadataFound() const; + void setMetadataFound(bool state); + QString title() const; + void setTitle(const QString &str); + QString artist() const; + void setArtist(const QString &str); + QString album() const; + void setAlbum(const QString &str); + QString conductor() const; + void setConductor(const QString &str); + QString label() const; + void setLabel(const QString &str); + int releaseYear() const; + void setReleaseYear(int year); + QString client() const; + void setClient(const QString &str); + QString agency() const; + void setAgency(const QString &str); + QString composer() const; + void setComposer(const QString &str); + QString publisher() const; + void setPublisher(const QString &str); + int usageCode() const; + void setUsageCode(int code); + QStringList schedCodes() const; + void setSchedCodes(const QStringList &codes); + QString licensingOrganization() const; + void setLicensingOrganization(const QString &str); + QString copyrightNotice() const; + void setCopyrightNotice(const QString &str); + QString cutId() const; + void setCutId(const QString &str); + QString classification() const; + void setClassification(const QString &str); + QString category() const; + void setCategory(const QString &str); + QString url() const; + void setUrl(const QString &str); + QString tagText() const; + void setTagText(const QString &str); + QString description() const; + void setDescription(const QString &str); + QString originator() const; + void setOriginator(const QString &str); + QString originatorReference() const; + void setOriginatorReference(const QString &str); + QString codingHistory() const; + void setCodingHistory(const QString &str); + QString userDefined() const; + void setUserDefined(const QString &str); + QString isrc() const; + void setIsrc(const QString &str); + QString isci() const; + void setIsci(const QString &str); + QString mcn() const; + void setMcn(const QString &str); + QString outCue() const; + void setOutCue(const QString &str); + RDWaveData::EndType endType() const; + void setEndType(RDWaveData::EndType type); + int introStartPos() const; + void setIntroStartPos(int msec); + int introEndPos() const; + void setIntroEndPos(int msec); + int segueStartPos() const; + void setSegueStartPos(int msec); + int segueEndPos() const; + void setSegueEndPos(int msec); + int startPos() const; + void setStartPos(int msec); + int endPos() const; + void setEndPos(int msec); + int hookStartPos() const; + void setHookStartPos(int msec); + int hookEndPos() const; + void setHookEndPos(int msec); + int fadeUpPos() const; + void setFadeUpPos(int msec); + int fadeDownPos() const; + void setFadeDownPos(int msec); + int beatsPerMinute() const; + void setBeatsPerMinute(int bpm); + QString tmciSongId() const; + void setTmciSongId(const QString &str); + QDate originationDate() const; + void setOriginationDate(const QDate &date); + QTime originationTime() const; + void setOriginationTime(const QTime &time); + QDate startDate() const; + void setStartDate(const QDate &date); + QTime startTime() const; + void setStartTime(const QTime &time); + QDate endDate() const; + void setEndDate(const QDate &date); + QTime endTime() const; + void setEndTime(const QTime &time); + QTime daypartStartTime() const; + void setDaypartStartTime(const QTime &time); + QTime daypartEndTime() const; + void setDaypartEndTime(const QTime &time); + void clear(); + + private: + bool data_metadata_found; + QString data_title; + QString data_artist; + QString data_album; + QString data_conductor; + QString data_label; + int data_release_year; + QString data_client; + QString data_agency; + QString data_composer; + QString data_publisher; + int data_usage_code; + QStringList data_sched_codes; + QString data_licensing_organization; + QString data_copyright_notice; + QString data_user_defined; + QString data_cut_id; + QString data_classification; + QString data_category; + QString data_url; + QString data_tag_text; + QString data_description; + QString data_originator; + QString data_originator_reference; + QString data_coding_history; + QString data_isrc; + QString data_isci; + QString data_mcn; + QString data_out_cue; + RDWaveData::EndType data_end_type; + int data_intro_start_pos; + int data_intro_end_pos; + int data_segue_start_pos; + int data_segue_end_pos; + int data_start_pos; + int data_end_pos; + int data_hook_start_pos; + int data_hook_end_pos; + int data_fade_up_pos; + int data_fade_down_pos; +/* + int data_intro_length; + int data_segue_length; + int data_full_length; +*/ + int data_beats_per_minute; + QString data_tmci_song_id; + QDate data_origination_date; + QTime data_origination_time; + QDate data_start_date; + QTime data_start_time; + QDate data_end_date; + QTime data_end_time; + QTime data_daypart_start_time; + QTime data_daypart_end_time; +}; + + +#endif // RDWAVEDATA_H diff --git a/lib/rdwavedata_dialog.cpp b/lib/rdwavedata_dialog.cpp new file mode 100644 index 00000000..08d3e2ba --- /dev/null +++ b/lib/rdwavedata_dialog.cpp @@ -0,0 +1,320 @@ +// rdwavedata_dialog.cpp +// +// A dialog to edit the contents of an RDWaveData. +// +// (C) Copyright 2014 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdwavedata_dialog.cpp,v 1.1.2.1 2014/05/28 21:21:41 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <qvalidator.h> + +#include "rdwavedata_dialog.h" + +RDWaveDataDialog::RDWaveDataDialog(const QString &caption,QWidget *parent) + : QDialog(parent,"",true) +{ + wave_caption=caption; + setCaption(caption+" - "+tr("Edit Cart Label")); + + // + // Fonts + // + QFont label_font("helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + // + // Dialogs + // + wave_schedcodes_dialog=new RDSchedCodesDialog(this); + + // + // Title + // + wave_title_label=new QLabel(tr("Title")+":",this); + wave_title_label->setFont(label_font); + wave_title_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_title_edit=new QLineEdit(this); + wave_title_edit->setMaxLength(255); + + // + // Artist + // + wave_artist_label=new QLabel(tr("Artist")+":",this); + wave_artist_label->setFont(label_font); + wave_artist_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_artist_edit=new QLineEdit(this); + wave_artist_edit->setMaxLength(255); + + // + // Year + // + wave_year_label=new QLabel(tr("Year")+":",this); + wave_year_label->setFont(label_font); + wave_year_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_year_edit=new QLineEdit(this); + wave_year_edit->setMaxLength(4); + wave_year_edit->setValidator(new QIntValidator(1980,8000,this)); + + // + // Usage + // + wave_usage_label=new QLabel(tr("Usage")+":",this); + wave_usage_label->setFont(label_font); + wave_usage_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_usage_box=new QComboBox(this); + for(int i=0;i<(int)RDCart::UsageLast;i++) { + wave_usage_box->insertItem(RDCart::usageText((RDCart::UsageCode)i)); + } + + // + // Scheduler Codes + // + wave_sched_button=new QPushButton(tr("Scheduler Codes"),this); + wave_sched_button->setFont(label_font); + connect(wave_sched_button,SIGNAL(clicked()),this,SLOT(schedClickedData())); + + // + // Song ID + // + wave_songid_label=new QLabel(tr("Song ID")+":",this); + wave_songid_label->setFont(label_font); + wave_songid_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_songid_edit=new QLineEdit(this); + wave_songid_edit->setMaxLength(32); + + // + // Beats Per Minute + // + wave_bpm_label=new QLabel(tr("Beats per Minute")+":",this); + wave_bpm_label->setFont(label_font); + wave_bpm_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_bpm_spin=new QSpinBox(this); + wave_bpm_spin->setRange(0,300); + wave_bpm_spin->setSpecialValueText(tr("Unknown")); + + // + // Album + // + wave_album_label=new QLabel(tr("Album")+":",this); + wave_album_label->setFont(label_font); + wave_album_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_album_edit=new QLineEdit(this); + wave_album_edit->setMaxLength(255); + + // + // Label + // + wave_label_label=new QLabel(tr("Label")+":",this); + wave_label_label->setFont(label_font); + wave_label_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_label_edit=new QLineEdit(this); + wave_label_edit->setMaxLength(64); + + // + // Client + // + wave_client_label=new QLabel(tr("Client")+":",this); + wave_client_label->setFont(label_font); + wave_client_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_client_edit=new QLineEdit(this); + wave_client_edit->setMaxLength(64); + + // + // Agency + // + wave_agency_label=new QLabel(tr("Agency")+":",this); + wave_agency_label->setFont(label_font); + wave_agency_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_agency_edit=new QLineEdit(this); + wave_agency_edit->setMaxLength(64); + + // + // Publisher + // + wave_publisher_label=new QLabel(tr("Publisher")+":",this); + wave_publisher_label->setFont(label_font); + wave_publisher_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_publisher_edit=new QLineEdit(this); + wave_publisher_edit->setMaxLength(64); + + // + // Composer + // + wave_composer_label=new QLabel(tr("Composer")+":",this); + wave_composer_label->setFont(label_font); + wave_composer_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_composer_edit=new QLineEdit(this); + wave_composer_edit->setMaxLength(64); + + // + // Conductor + // + wave_conductor_label=new QLabel(tr("Conductor")+":",this); + wave_conductor_label->setFont(label_font); + wave_conductor_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_conductor_edit=new QLineEdit(this); + wave_conductor_edit->setMaxLength(64); + + // + // User Defined + // + wave_userdef_label=new QLabel(tr("User Defined")+":",this); + wave_userdef_label->setFont(label_font); + wave_userdef_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + wave_userdef_edit=new QLineEdit(this); + wave_userdef_edit->setMaxLength(255); + + // + // OK Button + // + wave_ok_button=new QPushButton(tr("OK"),this); + wave_ok_button->setFont(label_font); + connect(wave_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + wave_cancel_button=new QPushButton(tr("Cancel"),this); + wave_cancel_button->setFont(label_font); + connect(wave_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +RDWaveDataDialog::~RDWaveDataDialog() +{ + delete wave_schedcodes_dialog; +} + + +QSize RDWaveDataDialog::sizeHint() const +{ + return QSize(600,344); +} + + +QSizePolicy RDWaveDataDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int RDWaveDataDialog::exec(RDWaveData *data) +{ + wave_data=data; + + wave_title_edit->setText(wave_data->title()); + wave_artist_edit->setText(wave_data->artist()); + if(wave_data->releaseYear()>0) { + wave_year_edit->setText(QString().sprintf("%d",wave_data->releaseYear())); + } + wave_usage_box->setCurrentItem(wave_data->usageCode()); + wave_songid_edit->setText(wave_data->tmciSongId()); + wave_bpm_spin->setValue(wave_data->beatsPerMinute()); + wave_album_edit->setText(wave_data->album()); + wave_label_edit->setText(wave_data->label()); + wave_client_edit->setText(wave_data->client()); + wave_agency_edit->setText(wave_data->agency()); + wave_publisher_edit->setText(wave_data->publisher()); + wave_composer_edit->setText(wave_data->composer()); + wave_conductor_edit->setText(wave_data->conductor()); + wave_userdef_edit->setText(wave_data->userDefined()); + + return QDialog::exec(); +} + + +void RDWaveDataDialog::schedClickedData() +{ + QStringList codes=wave_data->schedCodes(); + if(wave_schedcodes_dialog->exec(&codes,NULL)==0) { + wave_data->setSchedCodes(codes); + } +} + + +void RDWaveDataDialog::okData() +{ + wave_data->setTitle(wave_title_edit->text()); + wave_data->setArtist(wave_artist_edit->text()); + if(wave_year_edit->text().isEmpty()) { + wave_data->setReleaseYear(0); + } + else { + wave_data->setReleaseYear(wave_year_edit->text().toInt()); + } + wave_data->setUsageCode(wave_usage_box->currentItem()); + wave_data->setTmciSongId(wave_songid_edit->text()); + wave_data->setBeatsPerMinute(wave_bpm_spin->value()); + wave_data->setAlbum(wave_album_edit->text()); + wave_data->setLabel(wave_label_edit->text()); + wave_data->setClient(wave_client_edit->text()); + wave_data->setAgency(wave_agency_edit->text()); + wave_data->setPublisher(wave_publisher_edit->text()); + wave_data->setComposer(wave_composer_edit->text()); + wave_data->setConductor(wave_conductor_edit->text()); + wave_data->setUserDefined(wave_userdef_edit->text()); + + done(0); +} + + +void RDWaveDataDialog::cancelData() +{ + done(-1); +} + + +void RDWaveDataDialog::resizeEvent(QResizeEvent *e) +{ + wave_title_label->setGeometry(10,10,100,20); + wave_title_edit->setGeometry(115,10,size().width()-125,20); + wave_artist_label->setGeometry(10,32,100,20); + wave_artist_edit->setGeometry(115,32,size().width()-125,20); + wave_year_label->setGeometry(10,54,100,20); + wave_year_edit->setGeometry(115,54,50,20); + wave_usage_label->setGeometry(178,54,60,20); + wave_usage_box->setGeometry(245,54,170,20); + wave_sched_button->setGeometry(440,53,150,22); + wave_songid_label->setGeometry(10,76,100,20); + wave_songid_edit->setGeometry(115,76,240,20); + wave_bpm_label->setGeometry(375,76,120,20); + wave_bpm_spin->setGeometry(500,76,90,20); + wave_album_label->setGeometry(10,98,100,20); + wave_album_edit->setGeometry(115,98,size().width()-125,20); + wave_label_label->setGeometry(10,120,100,20); + wave_label_edit->setGeometry(115,120,size().width()-125,20); + wave_client_label->setGeometry(10,142,100,20); + wave_client_edit->setGeometry(115,142,size().width()-125,20); + wave_agency_label->setGeometry(10,164,100,20); + wave_agency_edit->setGeometry(115,164,size().width()-125,20); + wave_publisher_label->setGeometry(10,186,100,20); + wave_publisher_edit->setGeometry(115,186,size().width()-125,20); + wave_composer_label->setGeometry(10,208,100,20); + wave_composer_edit->setGeometry(115,208,size().width()-125,20); + wave_conductor_label->setGeometry(10,230,100,20); + wave_conductor_edit->setGeometry(115,230,size().width()-125,20); + wave_userdef_label->setGeometry(10,252,100,20); + wave_userdef_edit->setGeometry(115,252,size().width()-125,20); + wave_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + wave_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void RDWaveDataDialog::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/lib/rdwavedata_dialog.h b/lib/rdwavedata_dialog.h new file mode 100644 index 00000000..f807c98b --- /dev/null +++ b/lib/rdwavedata_dialog.h @@ -0,0 +1,96 @@ +// rdwavedata_dialog.h +// +// A dialog to edit the contents of an RDWaveData. +// +// (C) Copyright 2014 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdwavedata_dialog.h,v 1.1.2.1 2014/05/28 21:21:41 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDWAVEDATA_DIALOG_H +#define RDWAVEDATA_DIALOG_H + +#include <qdialog.h> +#include <qlineedit.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qcombobox.h> +#include <qspinbox.h> + +#include <rdcombobox.h> +#include <rdcart.h> +#include <rdschedcodes_dialog.h> + +class RDWaveDataDialog : public QDialog +{ + Q_OBJECT + public: + RDWaveDataDialog(const QString &caption,QWidget *parent=0); + ~RDWaveDataDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(RDWaveData *data); + + private slots: + void schedClickedData(); + void okData(); + void cancelData(); + + protected: + void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e); + + private: + QLabel *wave_title_label; + QLineEdit *wave_title_edit; + QLabel *wave_artist_label; + QLineEdit *wave_artist_edit; + QLabel *wave_year_label; + QLineEdit *wave_year_edit; + QLabel *wave_usage_label; + QComboBox *wave_usage_box; + QPushButton *wave_sched_button; + QLabel *wave_songid_label; + QLineEdit *wave_songid_edit; + QLabel *wave_bpm_label; + QSpinBox *wave_bpm_spin; + QLabel *wave_album_label; + QLineEdit *wave_album_edit; + QLabel *wave_label_label; + QLineEdit *wave_label_edit; + QLabel *wave_client_label; + QLineEdit *wave_client_edit; + QLabel *wave_agency_label; + QLineEdit *wave_agency_edit; + QLabel *wave_publisher_label; + QLineEdit *wave_publisher_edit; + QLabel *wave_composer_label; + QLineEdit *wave_composer_edit; + QLabel *wave_conductor_label; + QLineEdit *wave_conductor_edit; + QLabel *wave_userdef_label; + QLineEdit *wave_userdef_edit; + QPushButton *wave_ok_button; + QPushButton *wave_cancel_button; + QString wave_caption; + RDSchedCodesDialog *wave_schedcodes_dialog; + RDWaveData *wave_data; +}; + + +#endif // RDWAVEDATA_DIALOG_H diff --git a/lib/rdwavefile.cpp b/lib/rdwavefile.cpp new file mode 100644 index 00000000..fc6414ea --- /dev/null +++ b/lib/rdwavefile.cpp @@ -0,0 +1,4434 @@ +// rdwavefile.cpp +// +// A class for handling Microsoft WAV files. +// +// (C) Copyright 2002-2008 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdwavefile.cpp,v 1.24.6.5.2.3 2014/07/15 20:02:23 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <syslog.h> +#include <math.h> +#include <fcntl.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <errno.h> + +#include <id3/tag.h> +#include <id3/misc_support.h> +#ifdef HAVE_FLAC +#include <FLAC/metadata.h> +#endif // HAVE_FLAC + +#include <qobject.h> +#include <qstring.h> +#include <qdatetime.h> + +#include <rd.h> +#include <rdwavefile.h> +#include <rdconf.h> + +RDWaveFile::RDWaveFile(QString file_name) +{ + // + // Initialize Class Structures + // + wave_file.setName(file_name); + wave_data=NULL; + recordable=false; + format_chunk=false; + comm_chunk=false; + format_tag=0; + channels=0; + normalize_level=1.0; + samples_per_sec=0; + avg_bytes_per_sec=0; + block_align=0; + bits_per_sample=0; + cb_size=0; + head_layer=0; + head_bit_rate=0; + head_mode=0; + head_mode_ext=0; + head_emphasis=1; + head_flags=0; + pts=0; + mpeg_id=RDWaveFile::NonMpeg; + mpeg_frame_size=0; + id3v1_tag=false; + id3v2_tag[0]=false; + id3v2_tag[1]=false; + id3v2_offset[0]=0; + id3v2_offset[1]=0; + has_energy=false; + energy_loaded=false; + energy_ptr=0; + for(int i=0;i<FMT_CHUNK_SIZE;i++) { + fmt_chunk_data[i]=0; + } + fmt_size=0; + fact_chunk=false; + sample_length=0; + for(int i=0;i<FACT_CHUNK_SIZE;i++) { + fact_chunk_data[i]=0; + } + data_chunk=false; + data_length=0; + cart_chunk=false; + cart_version=0; + cart_title=""; + cart_title=""; + cart_artist=""; + cart_cut_id=""; + cart_client_id=""; + cart_category=""; + cart_classification=""; + cart_out_cue=""; + cart_start_date=QDate::currentDate(); + cart_start_time=QTime::currentTime(); + cart_end_date=QDate(CART_DEFAULT_END_YEAR, + CART_DEFAULT_END_MONTH, + CART_DEFAULT_END_DAY); + cart_end_time=QTime(CART_DEFAULT_END_HOUR, + CART_DEFAULT_END_MINUTE, + CART_DEFAULT_END_SECOND); + cart_producer_app_id=""; + cart_producer_app_ver=""; + cart_user_def=""; + cart_url=""; + cart_tag_text=""; + cart_level_ref=CART_DEFAULT_LEVEL_REF; + for(int i=0;i<MAX_TIMERS;i++) { + cart_timer_label[i]=QString(""); + cart_timer_sample[i]=0; + } + for(int i=0;i<CART_CHUNK_SIZE;i++) { + cart_chunk_data[i]=0; + } + bext_chunk=false; + bext_description=""; + bext_originator=""; + bext_originator_ref=""; + bext_origination_date=QDate::currentDate(); + bext_origination_time=QTime::currentTime(); + bext_time_reference_low=0; + bext_time_reference_high=0; + bext_version=0; + for(int i=0;i<64;i++) { + bext_umid[i]=0; + } + bext_coding_history=""; + for(int i=0;i<BEXT_CHUNK_SIZE;i++) { + bext_chunk_data[i]=0; + } + bext_coding_data=NULL; + bext_coding_size=0; + mext_chunk=false; + mext_homogenous=true; + mext_padding_used=false; + mext_rate_hacked=false; + mext_free_format=false; + mext_frame_size=0; + mext_anc_length=0; + mext_left_energy=false; + mext_ancillary_private=false; + mext_right_energy=false; + for(int i=0;i<MEXT_CHUNK_SIZE;i++) { + mext_chunk_data[i]=0; + } + levl_chunk=false; + levl_format=DEFAULT_LEVL_FORMAT; + levl_points=DEFAULT_LEVL_POINTS; + levl_block_size=DEFAULT_LEVL_BLOCK_SIZE; + cook_buffer=NULL; + cook_buffer_size=0; + cook_encoding=RDWaveFile::Raw; + wave_type=RDWaveFile::Unknown; + encode_quality=5.0f; + serial_number=-1; + atx_offset=0; + scot_chunk=false; + av10_chunk=false; +} + + +RDWaveFile::~RDWaveFile() +{ + if(bext_coding_data!=NULL) { + free(bext_coding_data); + } + if(cook_buffer!=NULL) { + free(cook_buffer); + } +} + + +RDWaveFile::Type RDWaveFile::type() const +{ + return wave_type; +} + + +void RDWaveFile::nameWave(QString file_name) +{ + if(wave_file.isOpen()) { + return; + } + wave_file.setName(file_name); +} + + + +bool RDWaveFile::openWave(RDWaveData *data) +{ +#ifdef HAVE_VORBIS + vorbis_info *vorbis_info; +#endif // HAVE_VORBIS + unsigned char tmc_buffer[4]; + + wave_data=data; + if(!wave_file.open(IO_ReadOnly)) { + return false; + } + + switch(GetType(wave_file.handle())) { + case RDWaveFile::Wave: + if(GetFmt(wave_file.handle())) { + wave_type=RDWaveFile::Wave; + } + else { + wave_type=RDWaveFile::Ambos; + format_tag=WAVE_FORMAT_MPEG; + } + if(!GetChunk(wave_file.handle(),"data",&data_length,NULL,0)) { // Set fileptr to start of data block + return false; + } + data_chunk=true; + data_start=lseek(wave_file.handle(),0,SEEK_CUR); + if((!GetFact(wave_file.handle()))||(sample_length==0)) { + if((format_tag!=WAVE_FORMAT_PCM)&& + (format_tag!=WAVE_FORMAT_IEEE_FLOAT)&&format_chunk) { +#ifdef MPEG_FACT_FUDGE + // Guesstimate the overall sample size + sample_length=1152.0*((double)data_length/(144.0*(double)head_bit_rate/ + (double)samples_per_sec)); + ext_time_length=1000.0*(double)sample_length/(double)samples_per_sec; + time_length=ext_time_length/1000; +#else + time_length=0; + sample_length=0; + ext_time_length=0; +#endif + } + else { + if(format_chunk) { + ext_time_length=(unsigned)(1000.0*(double)data_length/ + (double)(block_align*samples_per_sec)); + time_length=ext_time_length/1000; + sample_length=data_length/block_align; + } + else { + if(!GetMpegHeader(wave_file.handle(),data_start)) { + wave_file.close(); + return false; + } + data_length=wave_file.size()-data_start; + sample_length=1152*(data_length/mpeg_frame_size); + ext_time_length=(unsigned)(1000.0*(double)sample_length/ + (double)samples_per_sec); + time_length=ext_time_length/1000; + lseek(wave_file.handle(),data_start,SEEK_SET); + format_chunk=true; + } + } + } + else { + if(format_chunk) { + time_length=sample_length/samples_per_sec; + ext_time_length=(unsigned)(1000.0*(double)sample_length/ + (double)samples_per_sec); + } + else { + time_length=0; + ext_time_length=0; + } + } + GetCart(wave_file.handle()); + GetBext(wave_file.handle()); + GetMext(wave_file.handle()); + GetList(wave_file.handle()); + GetScot(wave_file.handle()); + GetAv10(wave_file.handle()); + GetAir1(wave_file.handle()); + break; + + case RDWaveFile::Aiff: + if(GetComm(wave_file.handle())) { + wave_type=RDWaveFile::Aiff; + } + if(!GetChunk(wave_file.handle(),"SSND",&data_length,NULL,0,true)) { + return false; + } + data_length-=8; // SSND chunk has eight data bytes at the beginning! + data_chunk=true; + data_start=lseek(wave_file.handle(),8,SEEK_CUR); + ext_time_length=(unsigned)(1000.0*(double)sample_length/ + (double)samples_per_sec); + time_length=ext_time_length/1000; + break; + + case RDWaveFile::Mpeg: + format_tag=WAVE_FORMAT_MPEG; + if(!GetMpegHeader(wave_file.handle(),id3v2_offset[0])) { + wave_file.close(); + return false; + } + data_length=wave_file.size(); + if(id3v1_tag) { + data_length-=128; + } + if(id3v2_tag[1]) { + data_length-=id3v2_offset[1]; + } + data_start=id3v2_offset[0]; + sample_length=1152*(data_length/mpeg_frame_size); + ext_time_length= + (unsigned)(1000.0*(double)sample_length/(double)samples_per_sec); + time_length=ext_time_length/1000; + data_chunk=true; + lseek(wave_file.handle(),data_start,SEEK_SET); + format_chunk=true; + wave_type=RDWaveFile::Mpeg; + ReadId3Metadata(); + break; + + case RDWaveFile::Ogg: +#ifdef HAVE_VORBIS + format_tag=WAVE_FORMAT_VORBIS; + avg_bytes_per_sec=ov_bitrate(&vorbis_file,-1)/8; + vorbis_info=ov_info(&vorbis_file,-1); + channels=vorbis_info->channels; + block_align=2*channels; + samples_per_sec=vorbis_info->rate; + avg_bytes_per_sec=block_align*samples_per_sec; + bits_per_sample=16; + data_start=0; + sample_length=ov_pcm_total(&vorbis_file,-1); + data_length=sample_length*2*channels; + ext_time_length=(unsigned)(ov_time_total(&vorbis_file,-1)*1000.0); + time_length=(unsigned)ov_time_total(&vorbis_file,-1); + data_chunk=true; + format_chunk=true; + wave_type=RDWaveFile::Ogg; + ReadNormalizeLevel(wave_file.name()); + ValidateMetadata(); + return true; +#else + return false; +#endif // HAVE_VORBIS + break; + + case RDWaveFile::Atx: + format_tag=WAVE_FORMAT_MPEG; + atx_offset=GetAtxOffset(wave_file.handle()); + if(!GetMpegHeader(wave_file.handle(),atx_offset)) { + wave_file.close(); + return false; + } + data_length=wave_file.size()-atx_offset; + data_start=atx_offset; + sample_length=1152*(data_length/mpeg_frame_size); + ext_time_length= + (unsigned)(1000.0*(double)sample_length/(double)samples_per_sec); + time_length=ext_time_length/1000; + data_chunk=true; + lseek(wave_file.handle(),data_start,SEEK_SET); + format_chunk=true; + wave_type=RDWaveFile::Atx; + break; + + case RDWaveFile::Tmc: + format_tag=WAVE_FORMAT_MPEG; + atx_offset=4; + if(!GetMpegHeader(wave_file.handle(),atx_offset)) { + wave_file.close(); + return false; + } + lseek(wave_file.handle(),0,SEEK_SET); + read(wave_file.handle(),tmc_buffer,4); + data_length=(0xFF&tmc_buffer[0])+(0xFF&tmc_buffer[1])*256+ + (0xFF&tmc_buffer[2])*65536+(0xFF&tmc_buffer[3])*16777216; + data_start=atx_offset; + sample_length=1152*(data_length/mpeg_frame_size); + ext_time_length= + (unsigned)(1000.0*(double)sample_length/(double)samples_per_sec); + time_length=ext_time_length/1000; + data_chunk=true; + lseek(wave_file.handle(),data_start,SEEK_SET); + format_chunk=true; + wave_type=RDWaveFile::Tmc; + ReadTmcMetadata(wave_file.handle()); + break; +#ifdef HAVE_FLAC + case RDWaveFile::Flac: + format_tag=WAVE_FORMAT_FLAC; + if(!GetFlacStreamInfo()) { + wave_file.close(); + return false; + } + wave_type=RDWaveFile::Flac; + format_chunk=true; + if(wave_data!=NULL) { + ReadId3Metadata(); + ReadFlacMetadata(); + } + break; +#endif // HAVE_FLAC + + default: + close(wave_file.handle()); + return false; + break; + } + lseek(wave_file.handle(),data_start,SEEK_SET); + ValidateMetadata(); + + // lseek(wave_file.handle(),SEEK_SET,0x845); + // printf("PTR: 0x%04X\n",lseek(wave_file.handle(),SEEK_CUR,0)); + + return true; +} + + +bool RDWaveFile::createWave(RDWaveData *data) +{ + mode_t prev_mask; + bool rc; + wave_data=data; + if(wave_data!=NULL) { + cart_title=wave_data->title(); + cart_artist=wave_data->artist(); + cart_cut_id=wave_data->cutId(); + cart_client_id=wave_data->client(); + cart_category=wave_data->category(); + cart_classification=wave_data->classification(); + cart_out_cue=wave_data->outCue(); + cart_start_date=wave_data->startDate(); + cart_start_time=wave_data->startTime(); + cart_end_date=wave_data->endDate(); + cart_end_time=wave_data->endTime(); + cart_user_def=wave_data->userDefined(); + cart_url=wave_data->url(); + cart_tag_text=wave_data->tagText(); + bext_description=wave_data->description(); + bext_originator=wave_data->originator(); + bext_originator_ref=wave_data->originatorReference(); + bext_coding_history=wave_data->codingHistory(); + } + + switch(format_tag) { + case WAVE_FORMAT_PCM: + case WAVE_FORMAT_MPEG: + levl_block_ptr=0; + levl_istate=0; + levl_accum=0; + energy_data.clear(); + for(int i=0;i<channels;i++) { + energy_data.push_back(0); + } + if(!MakeFmt()) { + return false; + } + prev_mask = umask(0113); // Set umask so files are user and group writable. + rc=wave_file.open(IO_ReadWrite|IO_Truncate); + unlink((wave_file.name()+".energy").ascii()); + umask(prev_mask); + if(rc==false) { + return false; + } + recordable=true; + write(wave_file.handle(),"RIFF\0\0\0\0WAVE",12); + WriteChunk(wave_file.handle(),"fmt ",fmt_chunk_data,fmt_size); + if(format_tag==WAVE_FORMAT_MPEG) { + write(wave_file.handle(),"fact\4\0\0\0\0\0\0\0",12); + } + if(cart_chunk) { + MakeCart(); + WriteChunk(wave_file.handle(),"cart",cart_chunk_data, + CART_CHUNK_SIZE); + } + if(bext_chunk) { + MakeBext(); + WriteChunk(wave_file.handle(),"bext",bext_coding_data, + bext_coding_size); + } + if(mext_chunk) { + MakeMext(); + WriteChunk(wave_file.handle(),"mext",mext_chunk_data, + MEXT_CHUNK_SIZE); + } + wave_type=RDWaveFile::Wave; + write(wave_file.handle(),"data\0\0\0\0",8); + data_start=lseek(wave_file.handle(),0,SEEK_CUR); + break; + + case WAVE_FORMAT_VORBIS: +#ifdef HAVE_VORBIS + avg_bytes_per_sec=2*channels*samples_per_sec; + vorbis_info_init(&vorbis_inf); + if(vorbis_encode_init_vbr(&vorbis_inf,channels,samples_per_sec, + encode_quality)<0) { + vorbis_info_clear(&vorbis_inf); + return false; + } + vorbis_encode_ctl(&vorbis_inf,OV_ECTL_RATEMANAGE_SET,NULL); + + prev_mask = umask(0113); // Set umask so files are user and group writable. + rc=wave_file.open(IO_ReadWrite|IO_Truncate); + umask(prev_mask); + if(rc==false) { + vorbis_info_clear(&vorbis_inf); + return false; + } + wave_type=RDWaveFile::Ogg; + recordable=true; + vorbis_encode_setup_init(&vorbis_inf); + vorbis_analysis_init(&vorbis_dsp,&vorbis_inf); + vorbis_block_init(&vorbis_dsp,&vorbis_blk); + if(serial_number<0) { // Generate random serial number + srand(time(NULL)); + serial_number=abs(rand()); + } + ogg_stream_init(&ogg_stream,serial_number); + { + ogg_packet header_main; + ogg_packet header_comments; + ogg_packet header_codebooks; + vorbis_comment vorbis_comm; + vorbis_comment_init(&vorbis_comm); + + vorbis_analysis_headerout(&vorbis_dsp,&vorbis_comm,&header_main, + &header_comments,&header_codebooks); + ogg_stream_packetin(&ogg_stream,&header_main); + ogg_stream_packetin(&ogg_stream,&header_comments); + ogg_stream_packetin(&ogg_stream,&header_codebooks); + while(ogg_stream_flush(&ogg_stream,&ogg_pg)) { + WriteOggPage(&ogg_pg); + } + } + return true; +#endif // HAVE_VORBIS + return false; + break; + } + levl_timestamp=QDateTime(QDate::currentDate(),QTime::currentTime()); + data_length=0; + return true; +} + + +void RDWaveFile::closeWave(int samples) +{ + unsigned char size_buf[4]; + unsigned csize; + unsigned lsize=0; + unsigned cptr; + + if(recordable) { + switch(wave_type) { + case RDWaveFile::Wave: + // + // Write levl chunk + // + if(levl_chunk&&((format_tag==WAVE_FORMAT_PCM)|| + ((format_tag==WAVE_FORMAT_MPEG)&&(head_layer==2)))) { + levl_version=0; + levl_format=2; + levl_points=1; + levl_block_size=1152; + levl_channels=channels; + levl_frames=energy_data.size()/channels; + levl_peak_offset=0xFFFFFFFF; + levl_peak_value=0; + MakeLevl(); + lseek(wave_file.handle(),0,SEEK_END); + write(wave_file.handle(),"levl",4); + lsize=LEVL_CHUNK_SIZE+energy_data.size()*2; + size_buf[0]=lsize&0xff; + size_buf[1]=(lsize>>8)&0xff; + size_buf[2]=(lsize>>16)&0xff; + size_buf[3]=(lsize>>24)&0xff; + write(wave_file.handle(),size_buf,4); + write(wave_file.handle(),levl_chunk_data,LEVL_CHUNK_SIZE-4); + // Fixup the endianness + unsigned char * sbuf = new unsigned char [2 * energy_data.size()]; + for (unsigned int i=0; i < energy_data.size(); i++){ + WriteSword (sbuf,2*i,(unsigned short) energy_data[i]); + } + write(wave_file.handle(),sbuf,2*energy_data.size()); + delete [] sbuf; + ftruncate(wave_file.handle(),lseek(wave_file.handle(),0,SEEK_CUR)); + } + + // + // Update file size + // + cptr=lseek(wave_file.handle(),0,SEEK_END)-12; + size_buf[0]=cptr&0xff; + size_buf[1]=(cptr>>8)&0xff; + size_buf[2]=(cptr>>16)&0xff; + size_buf[3]=(cptr>>24)&0xff; + lseek(wave_file.handle(),4,SEEK_SET); + write(wave_file.handle(),size_buf,4); + + // + // Update data chunk size + // + size_buf[0]=data_length&0xff; + size_buf[1]=(data_length>>8)&0xff; + size_buf[2]=(data_length>>16)&0xff; + size_buf[3]=(data_length>>24)&0xff; + lseek(wave_file.handle(), + FindChunk(wave_file.handle(),"data",&csize)-4,SEEK_SET); + write(wave_file.handle(),size_buf,4); + + // + // Update fact chunk + // + if(FindChunk(wave_file.handle(),"fact",&csize)>0) { + if(samples<0) { + if(format_tag==WAVE_FORMAT_PCM) { + samples=data_length/block_align; + } + if(format_tag==WAVE_FORMAT_MPEG) { + samples=(unsigned)(1152.0*((double)data_length/ + (144.0*(double)head_bit_rate/ + (double)samples_per_sec))); + } + } + size_buf[0]=samples&0xff; + size_buf[1]=(samples>>8)&0xff; + size_buf[2]=(samples>>16)&0xff; + size_buf[3]=(samples>>24)&0xff; + WriteChunk(wave_file.handle(),"fact",size_buf,4); + } + + // + // Update Cart Chunk + // + if(cart_chunk) { + MakeCart(); + WriteChunk(wave_file.handle(),"cart",cart_chunk_data,CART_CHUNK_SIZE); + } + + // + // Update Bext Chunk + // + if(bext_chunk) { + MakeBext(); + WriteChunk(wave_file.handle(),"bext",bext_coding_data,bext_coding_size); + } + + // + // Update Mext Chunk + // + if(mext_chunk) { + MakeMext(); + WriteChunk(wave_file.handle(),"mext",mext_chunk_data,MEXT_CHUNK_SIZE); + } + + // + // Truncate + // + if(!levl_chunk) { + ftruncate(wave_file.handle(),FindChunk(wave_file.handle(), + "data",&csize)+data_length); + } + else { + if((format_tag==WAVE_FORMAT_MPEG)&&(head_layer!=2)) { + ftruncate(wave_file.handle(), + FindChunk(wave_file.handle(), + "data",&csize)+data_length); + } + } + break; + + case RDWaveFile::Ogg: +#ifdef HAVE_VORBIS + WriteOggBuffer(NULL,0); + ogg_stream_clear(&ogg_stream); + vorbis_block_clear(&vorbis_blk); + vorbis_dsp_clear(&vorbis_dsp); + vorbis_info_clear(&vorbis_inf); + wave_file.close(); +#endif // HAVE_VORBIS + break; + + default: + break; + } + } + if(wave_type==RDWaveFile::Ogg) { +#ifdef HAVE_VORBIS + if(!recordable) { + ov_clear(&vorbis_file); + } +#endif // HAVE_VORBIS + } + wave_file.close(); + recordable=false; + time_length=0; + format_chunk=false; + format_tag=0; + channels=0; + normalize_level=1.0; + samples_per_sec=0; + avg_bytes_per_sec=0; + block_align=0; + bits_per_sample=0; + cb_size=0; + head_layer=0; + head_bit_rate=0; + head_mode=0; + head_mode_ext=0; + head_emphasis=1; + head_flags=0; + pts=0; + mpeg_id=RDWaveFile::NonMpeg; + mpeg_frame_size=0; + id3v1_tag=false; + id3v2_tag[0]=false; + id3v2_tag[1]=false; + id3v2_offset[0]=0; + id3v2_offset[1]=0; + for(int i=0;i<FMT_CHUNK_SIZE;i++) { + fmt_chunk_data[i]=0; + } + fmt_size=0; + fact_chunk=false; + for(int i=0;i<FACT_CHUNK_SIZE;i++) { + fact_chunk_data[i]=0; + } + sample_length=0; + data_chunk=false; + data_length=0; + cart_chunk=false; + cart_version=0; + cart_title=""; + cart_title=""; + cart_artist=""; + cart_cut_id=""; + cart_client_id=""; + cart_category=""; + cart_classification=""; + cart_out_cue=""; + cart_start_date=QDate::currentDate(); + cart_start_time=QTime::currentTime(); + cart_end_date=QDate(CART_DEFAULT_END_YEAR, + CART_DEFAULT_END_MONTH, + CART_DEFAULT_END_DAY); + cart_end_time=QTime(CART_DEFAULT_END_HOUR, + CART_DEFAULT_END_MINUTE, + CART_DEFAULT_END_SECOND); + cart_producer_app_id=""; + cart_producer_app_ver=""; + cart_user_def=""; + cart_url=""; + cart_tag_text=""; + cart_level_ref=CART_DEFAULT_LEVEL_REF; + for(int i=0;i<CART_CHUNK_SIZE;i++) { + cart_chunk_data[i]=0; + } + bext_chunk=false; + bext_description=""; + bext_originator=""; + bext_originator_ref=""; + bext_origination_date=QDate::currentDate(); + bext_origination_time=QTime::currentTime(); + bext_time_reference_low=0; + bext_time_reference_high=0; + bext_version=0; + for(int i=0;i<64;i++) { + bext_umid[i]=0; + } + bext_coding_history=""; + for(int i=0;i<BEXT_CHUNK_SIZE;i++) { + bext_chunk_data[i]=0; + } + free(bext_coding_data); + bext_coding_data=NULL; + bext_coding_size=0; + mext_chunk=false; + mext_homogenous=true; + mext_padding_used=false; + mext_rate_hacked=false; + mext_free_format=false; + mext_frame_size=0; + mext_anc_length=0; + mext_left_energy=false; + mext_ancillary_private=false; + mext_right_energy=false; + for(int i=0;i<MEXT_CHUNK_SIZE;i++) { + mext_chunk_data[i]=0; + } + levl_chunk=false; + levl_format=DEFAULT_LEVL_FORMAT; + levl_points=DEFAULT_LEVL_POINTS; + levl_block_size=DEFAULT_LEVL_BLOCK_SIZE; + energy_loaded=false; + energy_data.clear(); + free(cook_buffer); + cook_buffer=NULL; + cook_buffer_size=0; + cook_encoding=RDWaveFile::Raw; + encode_quality=5.0f; + serial_number=-1; + atx_offset=0; + av10_chunk=false; +} + + +void RDWaveFile::resetWave() +{ + if(wave_type!=RDWaveFile::Ogg) { + lseek(wave_file.handle(),data_start,SEEK_SET); + ftruncate(wave_file.handle(),data_start); + } +} + + +QString RDWaveFile::getName() const +{ + return wave_file.name(); +} + + +bool RDWaveFile::getFormatChunk() const +{ + return format_chunk; +} + + + +bool RDWaveFile::getFactChunk() const +{ + return fact_chunk; +} + + + +unsigned RDWaveFile::getSampleLength() const +{ + return sample_length; +} + + + +unsigned RDWaveFile::getTimeLength() const +{ + return time_length; +} + + +unsigned RDWaveFile::getExtTimeLength() const +{ + return ext_time_length; +} + + +bool RDWaveFile::getDataChunk() const +{ + return data_chunk; +} + + + +unsigned RDWaveFile::getDataLength() const +{ + return data_length; +} + + +RDWaveFile::Encoding RDWaveFile::encoding() const +{ + return cook_encoding; +} + + +void RDWaveFile::setEncoding(RDWaveFile::Encoding code) +{ + cook_encoding=code; +} + + +int RDWaveFile::readWave(void *buf,int count) +{ + int stream; + int n; + unsigned int pos; + int c = 0; + int16_t *sample; + + switch(wave_type) { + case RDWaveFile::Ogg: +#ifdef HAVE_VORBIS + n = 0; + while(n!=count){ + int ret = ov_read(&vorbis_file,(char *)buf+n,count-n,0,2,1,&stream); + if (!ret) break; + n+=ret; + } + if(normalize_level != 1.0f){ + for (int i=0;i<n/2;i++) { + sample=(int16_t *)buf+i; + *sample=(int16_t)(normalize_level*(double)*sample); + } + } + return n; +#endif // HAVE_VORBIS + return 0; + + case RDWaveFile::Wave: + pos = lseek(wave_file.handle(),0,SEEK_CUR); + // + // FIXME: how fix comparing singed (data_start, count) vs. + // unsigned (pos, data_length) ... WAVE standard is 32 bit, + // but not sure if signed or not... + // grauf@rfa.org Tue, 04 Apr 2006 21:02:51 -0400 + // + if (((pos+count)>(data_start+data_length))&&(data_length>0)) { + count=count - ( (pos+count) - (data_start+data_length) ); + } + c = read(wave_file.handle(),buf,count); + break; + default: + c = read(wave_file.handle(),buf,count); + } + if ( c <0 ) return 0; // read error + // Fixup the buffer for big endian hosts (Wav is defined as LE). + if (htonl (1l) == 1){ // Big endian host + for (unsigned int i = 0; i < c/2; i++){ + ((short*)buf)[i] = ReadSword((unsigned char *)buf,2*i); + } + } + + // printf("RDWaveFile: 0x%02X\n",((char *)buf)[0]&0xff); + + return c; +} + + +int RDWaveFile::writeWave(void *buf,int count) +{ + if(!recordable) { + return -1; + } + switch(format_tag) { + case WAVE_FORMAT_PCM: + if(levl_chunk) { + for(int i=0;i<count;i++) { + switch(levl_istate) { + case 0: // Left Channel, LSB + levl_accum=((char *)buf)[i]&0xff; + levl_istate=1; + break; + + case 1: // Left Channel, MSB + levl_accum|=((((char *)buf)[i]&0xff)<<8); + switch(channels) { + case 1: + if(levl_accum>energy_data[energy_data.size()-1]) { + energy_data[energy_data.size()-1]=levl_accum; + } + if(++levl_block_ptr==1152) { + energy_data.push_back(0); + levl_block_ptr=0; + } + levl_istate=0; + break; + + case 2: + if(levl_accum>energy_data[energy_data.size()-2]) { + energy_data[energy_data.size()-2]=levl_accum; + } + levl_istate=2; + break; + } + break; + + case 2: // Right Channel, LSB + levl_accum=((char *)buf)[i]&0xff; + levl_istate=3; + break; + + case 3: // Right Channel, MSB + levl_accum|=((((char *)buf)[i]&0xff)<<8); + if(levl_accum>energy_data[energy_data.size()-1]) { + energy_data[energy_data.size()-1]=levl_accum; + } + if(++levl_block_ptr==1152) { + energy_data.push_back(0); + energy_data.push_back(0); + levl_block_ptr=0; + } + levl_istate=0; + break; + } + } + } + lseek(wave_file.handle(),0,SEEK_END); + data_length+=count; + // Fixup the buffer for big endian hosts (Wav is defined as LE). + if (htonl (1l) == 1l){ // Big endian host + for (unsigned int i = 0; i < count/2; i++){ + unsigned short s = ((unsigned short*)buf)[i]; + WriteSword((unsigned char *)buf,2*i,s); + } + } + return write(wave_file.handle(),buf,count); + + case WAVE_FORMAT_MPEG: + if(levl_chunk&&(head_layer==2)) { + for(int i=0;i<count;i++) { + if(levl_block_ptr==(block_align-5)) { // Right Channel, MSB + if(channels==2) { + levl_accum=((((char *)buf)[i]&0xff)<<8); + } + levl_block_ptr++; + } + else { + if(levl_block_ptr==(block_align-4)) { // Right Channel, LSB + if(channels==2) { + levl_accum|=((char *)buf)[i]&0xff; + energy_data[energy_data.size()-1]=levl_accum; + } + levl_block_ptr++; + } + else { + if(levl_block_ptr==(block_align-2)) { // Left Channel, MSB + levl_accum=((((char *)buf)[i]&0xff)<<8); + levl_block_ptr++; + } + else { + if(levl_block_ptr==(block_align-1)) { // Left Channel, LSB + levl_accum|=((char *)buf)[i]&0xff; + energy_data[energy_data.size()-channels]=levl_accum; + for(unsigned j=0;j<channels;j++) { + energy_data.push_back(0); + } + levl_block_ptr=0; + } + else { + levl_block_ptr++; + } + } + } + } + } + } + lseek(wave_file.handle(),0,SEEK_END); + data_length+=count; + return write(wave_file.handle(),buf,count); + + case WAVE_FORMAT_VORBIS: + WriteOggBuffer((char *)buf,count); + break; + } + return 0; +} + + +bool RDWaveFile::hasEnergy() +{ + GetEnergy(); + return has_energy; +} + + +unsigned RDWaveFile::energySize() +{ + GetEnergy(); + if(!has_energy) { + return 0; + } + return energy_data.size(); +} + + +unsigned short RDWaveFile::energy(unsigned frame) +{ + if(!has_energy) { + return 0; + } + GetEnergy(); + return energy_data[frame]; +} + + +int RDWaveFile::readEnergy(unsigned short buf[],int count) +{ + if(!has_energy) { + return 0; + } + GetEnergy(); + for(int i=0;i<count;i++) { + if((i+energy_ptr)<energy_data.size()) { + buf[i]=energy_data[i+energy_ptr]; + } + else { + energy_ptr+=i; + return i; + } + } + return 0; +} + + +int RDWaveFile::startTrim(int level) +{ + double ratio=pow(10,-(double)level/2000.0)*32768.0; + GetEnergy(); + for(unsigned i=0;i<energy_data.size();i++) { + if((double)energy_data[i]>=ratio) { + return i*1152/getChannels(); + } + } + return -1; +} + + +int RDWaveFile::endTrim(int level) +{ + double ratio=pow(10,-(double)level/2000.0)*32768.0; + GetEnergy(); + for(int i=energy_data.size()-1;i>=0;i--) { + if((double)energy_data[i]>=ratio) { + return i*1152/getChannels(); + } + } + return -1; +} + + +void RDWaveFile::getSettings(RDSettings *settings) +{ + switch(type()) { + case RDWaveFile::Pcm8: + // FIXME + break; + + case RDWaveFile::Wave: + switch(getFormatTag()) { + case WAVE_FORMAT_PCM: + settings->setFormat(RDSettings::Pcm16); + break; + + case WAVE_FORMAT_MPEG: + settings->setFormat((RDSettings::Format)getHeadLayer()); + break; + } + break; + + case RDWaveFile::Mpeg: + case RDWaveFile::Atx: + case RDWaveFile::Tmc: + case RDWaveFile::Ambos: + settings->setFormat((RDSettings::Format)getHeadLayer()); + break; + + case RDWaveFile::Ogg: + settings->setFormat(RDSettings::OggVorbis); + break; +#ifdef HAVE_FLAC + case RDWaveFile::Flac: + settings->setFormat(RDSettings::Flac); + break; +#endif // HAVE_FLAC + } + settings->setChannels(getChannels()); + settings->setSampleRate(getSamplesPerSec()); + settings->setLayer(getHeadLayer()); + settings->setBitRate(getHeadBitRate()); +} + + +void RDWaveFile::setSettings(const RDSettings *settings) +{ +} + + +int RDWaveFile::seekWave(int offset,int whence) +{ + int pos; + + switch(wave_type) { + case RDWaveFile::Ogg: +#ifdef HAVE_VORBIS + switch(whence) { + case SEEK_SET: + if(ov_pcm_seek(&vorbis_file,offset/(2*channels))==0) { + //printf("RDWaveFile::seekWave() = %d\n",offset); + return offset; + } + //printf("RDWaveFile::seekWave() = -1\n"); + return -1; + break; + + case SEEK_CUR: + pos=ov_pcm_tell(&vorbis_file)*2*channels; + if(offset==0) { + return pos; + } + return seekWave(pos+offset,SEEK_SET); + break; + + case SEEK_END: + break; + } +#endif // HAVE_VORBIS + return -1; + break; + + case RDWaveFile::Wave:// FIXME: how fix comparing singed (data_start, offset, pos) vs. unsigned (data_length) ... WAVE standard is 32 bit, but not sure if signed or not... grauf@rfa.org Tue, 04 Apr 2006 21:02:51 -0400 + switch(whence) { + case SEEK_SET: + if (offset<0) { + offset=0; + } + if (offset>data_length) { + offset=data_length; + } + return lseek(wave_file.handle(), + offset+data_start,SEEK_SET)-data_start; + break; + case SEEK_CUR: + pos = lseek(wave_file.handle(),0,SEEK_CUR); + if ((pos+offset)<data_start) { + offset=offset + (data_start - (pos+offset)); + } + if ((pos+offset)>(data_start+data_length)) { + offset=offset - ((pos+offset) - (data_start+data_length)); + } + return lseek(wave_file.handle(),offset,SEEK_CUR)-data_start; + break; + case SEEK_END: + pos = lseek(wave_file.handle(),0,SEEK_END); + if ((pos+offset)<data_start) { + offset=offset + (data_start - (pos+offset)); + } + if ((pos+offset)>(data_start+data_length)) { + offset=offset - ((pos+offset) - (data_start+data_length)); + } + return lseek(wave_file.handle(),offset,SEEK_END)-data_start; + break; + } + break; + + default: + switch(whence) { + case SEEK_SET: + return lseek(wave_file.handle(), + offset+data_start,SEEK_SET)-data_start; + break; + case SEEK_CUR: + return lseek(wave_file.handle(),offset,SEEK_CUR)-data_start; + break; + case SEEK_END: + return lseek(wave_file.handle(),offset,SEEK_END)-data_start; + break; + } + } + return 0; +} + + +unsigned short RDWaveFile::getFormatTag() const +{ + return format_tag; +} + + +void RDWaveFile::setFormatTag(unsigned short format) +{ + if(!recordable) { + format_tag=format; + } +} + + +unsigned short RDWaveFile::getChannels() const +{ + return channels; +} + + +void RDWaveFile::setChannels(unsigned short chan) +{ + if(!recordable) { + channels=chan; + } +} + + +unsigned RDWaveFile::getSamplesPerSec() const +{ + return samples_per_sec; +} + + +void RDWaveFile::setSamplesPerSec(unsigned rate) +{ + if(!recordable) { + samples_per_sec=rate; + } +} + + +unsigned RDWaveFile::getAvgBytesPerSec() const +{ + return avg_bytes_per_sec; +} + + + +unsigned short RDWaveFile::getBlockAlign() const +{ + return block_align; +} + + +unsigned short RDWaveFile::getBitsPerSample() const +{ + return bits_per_sample; +} + + +void RDWaveFile::setBitsPerSample(unsigned short bits) +{ + if(!recordable) { + bits_per_sample=bits; + } +} + + +unsigned short RDWaveFile::getHeadLayer() const +{ + return head_layer; +} + + +void RDWaveFile::setHeadLayer(unsigned short layer) +{ + if(!recordable) { + head_layer=layer; + } +} + + +unsigned RDWaveFile::getHeadBitRate() const +{ + return head_bit_rate; +} + + +void RDWaveFile::setHeadBitRate(unsigned rate) +{ + if(!recordable) { + head_bit_rate=rate; + } +} + + +unsigned short RDWaveFile::getHeadMode() const +{ + return head_mode; +} + + +void RDWaveFile::setHeadMode(unsigned short mode) +{ + if(!recordable) { + head_mode=mode; + } +} + + +void RDWaveFile::setHeadFlags(unsigned short flags) +{ + if(!recordable) { + head_flags=flags; + } +} + + +unsigned RDWaveFile::getHeadModeExt() const +{ + return head_mode_ext; +} + + + +unsigned RDWaveFile::getHeadEmphasis() const +{ + return head_emphasis; +} + + + +unsigned short RDWaveFile::getHeadFlags() const +{ + return head_flags; +} + + + +unsigned long RDWaveFile::getPTS() const +{ + return pts; +} + + +bool RDWaveFile::getCartChunk() const +{ + return cart_chunk; +} + + +void RDWaveFile::setCartChunk(bool state) +{ + if(!recordable) { + cart_chunk=state; + } +} + + +unsigned RDWaveFile::getCartVersion() const +{ + return cart_version; +} + + +QString RDWaveFile::getCartTitle() const +{ + return cart_title; +} + + +void RDWaveFile::setCartTitle(QString string) +{ + cart_title=string; +} + + +QString RDWaveFile::getCartArtist() const +{ + return cart_artist; +} + + +void RDWaveFile::setCartArtist(QString string) +{ + cart_artist=string; +} + + +QString RDWaveFile::getCartCutID() const +{ + return cart_cut_id; +} + + +void RDWaveFile::setCartCutID(QString string) +{ + cart_cut_id=string; +} + + +QString RDWaveFile::getCartClientID() const +{ + return cart_client_id; +} + + +void RDWaveFile::setCartClientID(QString string) +{ + cart_client_id=string; +} + + +QString RDWaveFile::getCartCategory() const +{ + return cart_category; +} + + +void RDWaveFile::setCartCategory(QString string) +{ + cart_category=string; +} + + +QString RDWaveFile::getCartClassification() const +{ + return cart_classification; +} + + +void RDWaveFile::setCartClassification(QString string) +{ + cart_classification=string; +} + + +QString RDWaveFile::getCartOutCue() const +{ + return cart_out_cue; +} + + +void RDWaveFile::setCartOutCue(QString string) +{ + cart_out_cue=string; +} + + +QDate RDWaveFile::getCartStartDate() const +{ + return cart_start_date; +} + + +void RDWaveFile::setCartStartDate(QDate date) +{ + cart_start_date=date; +} + + +QTime RDWaveFile::getCartStartTime() const +{ + return cart_start_time; +} + + +void RDWaveFile::setCartStartTime(QTime time) +{ + cart_start_time=time; +} + + +QDate RDWaveFile::getCartEndDate() const +{ + return cart_end_date; +} + + +void RDWaveFile::setCartEndDate(QDate date) +{ + cart_end_date=date; +} + + +QTime RDWaveFile::getCartEndTime() const +{ + return cart_end_time; +} + + +void RDWaveFile::setCartEndTime(QTime time) +{ + cart_end_time=time; +} + + +QString RDWaveFile::getCartProducerAppID() const +{ + return cart_producer_app_id; +} + + +QString RDWaveFile::getCartProducerAppVer() const +{ + return cart_producer_app_ver; +} + + +QString RDWaveFile::getCartUserDef() const +{ + return cart_user_def; +} + + +void RDWaveFile::setCartUserDef(QString string) +{ + cart_user_def=string; +} + + +unsigned RDWaveFile::getCartLevelRef() const +{ + return cart_level_ref; +} + + +void RDWaveFile::setCartLevelRef(unsigned level) +{ + cart_level_ref=level; +} + + +QString RDWaveFile::getCartTimerLabel(int index) const +{ + if(index<MAX_TIMERS) { + return cart_timer_label[index]; + } + return QString(""); +} + + +void RDWaveFile::setCartTimerLabel(int index,QString label) +{ + if(index<MAX_TIMERS) { + cart_timer_label[index]=label; + } +} + + +unsigned RDWaveFile::getCartTimerSample(int index) const +{ + if(index<MAX_TIMERS) { + return cart_timer_sample[index]; + } + return 0; +} + + +void RDWaveFile::setCartTimerSample(int index,unsigned sample) +{ + if(index<MAX_TIMERS) { + cart_timer_sample[index]=sample; + } +} + + +QString RDWaveFile::getCartURL() const +{ + return cart_url; +} + + +void RDWaveFile::setCartURL(QString string) +{ + cart_url=string; +} + + +QString RDWaveFile::getCartTagText() const +{ + return cart_tag_text; +} + + +bool RDWaveFile::getBextChunk() const +{ + return bext_chunk; +} + + +void RDWaveFile::setBextChunk(bool state) +{ + if(!recordable) { + bext_chunk=state; + } +} + + +QString RDWaveFile::getBextDescription() const +{ + return bext_description; +} + + +void RDWaveFile::setBextDescription(QString string) +{ + bext_description=string; +} + + +QString RDWaveFile::getBextOriginator() const +{ + return bext_originator; +} + + +void RDWaveFile::setBextOriginator(QString string) +{ + bext_originator=string; +} + + +QString RDWaveFile::getBextOriginatorRef() const +{ + return bext_originator_ref; +} + + +void RDWaveFile::setBextOriginatorRef(QString string) +{ + bext_originator_ref=string; +} + + +QDate RDWaveFile::getBextOriginationDate() const +{ + return bext_origination_date; +} + + +void RDWaveFile::setBextOriginationDate(QDate date) +{ + bext_origination_date=date; +} + + +QTime RDWaveFile::getBextOriginationTime() const +{ + return bext_origination_time; +} + + +void RDWaveFile::setBextOriginationTime(QTime time) +{ + bext_origination_time=time; +} + + +unsigned RDWaveFile::getBextTimeReferenceLow() const +{ + return bext_time_reference_low; +} + + +void RDWaveFile::setBextTimeReferenceLow(unsigned sample) +{ + bext_time_reference_low=sample; +} + + +unsigned RDWaveFile::getBextTimeReferenceHigh() const +{ + return bext_time_reference_low; +} + + +void RDWaveFile::setBextTimeReferenceHigh(unsigned sample) +{ + bext_time_reference_high=sample; +} + + +unsigned short RDWaveFile::getBextVersion() const +{ + return bext_version; +} + + +void RDWaveFile::getBextUMD(unsigned char *buf) const +{ + for(int i=0;i<64;i++) { + buf[i]=bext_umid[i]; + } +} + + +void RDWaveFile::setBextUMD(unsigned char *buf) +{ + for(int i=0;i<64;i++) { + bext_umid[i]=buf[i]; + } +} + + +QString RDWaveFile::getBextCodingHistory() const +{ + return bext_coding_history; +} + + +void RDWaveFile::setBextCodingHistory(QString string) +{ + if(!recordable) { + bext_coding_history=string; + } +} + + +bool RDWaveFile::getMextChunk() const +{ + return mext_chunk; +} + + +void RDWaveFile::setMextChunk(bool state) +{ + if(!recordable) { + mext_chunk=state; + } +} + + +bool RDWaveFile::getMextHomogenous() const +{ + return mext_homogenous; +} + + +void RDWaveFile::setMextHomogenous(bool state) +{ + mext_homogenous=state; +} + + +bool RDWaveFile::getMextPaddingUsed() const +{ + return mext_padding_used; +} + + +void RDWaveFile::setMextPaddingUsed(bool state) +{ + mext_padding_used=state; +} + + +bool RDWaveFile::getMextHackedBitRate() const +{ + return mext_rate_hacked; +} + + +void RDWaveFile::setMextHackedBitRate(bool state) +{ + mext_rate_hacked=state; +} + + +bool RDWaveFile::getMextFreeFormat() const +{ + return mext_free_format; +} + + +void RDWaveFile::setMextFreeFormat(bool state) +{ + mext_free_format=state; +} + + +int RDWaveFile::getMextFrameSize() const +{ + return mext_frame_size; +} + + +void RDWaveFile::setMextFrameSize(int size) +{ + mext_frame_size=size; +} + + +int RDWaveFile::getMextAncillaryLength() const +{ + return mext_anc_length; +} + + +void RDWaveFile::setMextAncillaryLength(int length) +{ + mext_anc_length=length; +} + + +bool RDWaveFile::getMextLeftEnergyPresent() const +{ + return mext_left_energy; +} + + +void RDWaveFile::setMextLeftEnergyPresent(bool state) +{ + mext_left_energy=state; +} + + +bool RDWaveFile::getMextPrivateDataPresent() const +{ + return mext_ancillary_private; +} + + +void RDWaveFile::setMextPrivateDataPresent(bool state) +{ + mext_ancillary_private=state; +} + + +bool RDWaveFile::getMextRightEnergyPresent() const +{ + return mext_right_energy; +} + + +void RDWaveFile::setMextRightEnergyPresent(bool state) +{ + mext_right_energy=state; +} + + +bool RDWaveFile::getLevlChunk() const +{ + return levl_chunk; +} + + +void RDWaveFile::setLevlChunk(bool state) +{ + levl_chunk=state; +} + + +int RDWaveFile::getLevlVersion() const +{ + return levl_version; +} + + +void RDWaveFile::setLevlVersion(unsigned ver) +{ + levl_version=ver; +} + + +int RDWaveFile::getLevlBlockSize() const +{ + return levl_block_size; +} + + +void RDWaveFile::setLevlBlockSize(unsigned size) +{ + levl_block_size=size; +} + + +int RDWaveFile::getLevlChannels() const +{ + return levl_channels; +} + + +unsigned short RDWaveFile::getLevlPeak() const +{ + return levl_peak_value; +} + + +QDateTime RDWaveFile::getLevlTimestamp() const +{ + return levl_timestamp; +} + + +void RDWaveFile::setEncodeQuality(float qual) +{ + encode_quality=qual; +} + + +int RDWaveFile::getSerialNumber() const +{ + return serial_number; +} + + +void RDWaveFile::setSerialNumber(int serial) +{ + serial_number=serial; +} + + +bool RDWaveFile::getScotChunk() const +{ + return scot_chunk; +} + + +bool RDWaveFile::getAIR1Chunk() const +{ + return AIR1_chunk; +} + + + +RDWaveFile::Type RDWaveFile::GetType(int fd) +{ + if(IsWav(fd)) { + return RDWaveFile::Wave; + } + if(IsAiff(fd)) { + return RDWaveFile::Aiff; + } + if(IsFlac(fd)) { + return RDWaveFile::Flac; + } + if(IsAtx(fd)) { + return RDWaveFile::Atx; + } + if(IsTmc(fd)) { + return RDWaveFile::Tmc; + } + if(IsOgg(fd)) { + return RDWaveFile::Ogg; + } + if(IsMpeg(fd)) { + return RDWaveFile::Mpeg; + } + return RDWaveFile::Unknown; +} + + +bool RDWaveFile::IsWav(int fd) +{ + int i; + char buffer[5]; + + /* + * Is this a riff file? + */ + lseek(fd,0,SEEK_SET); + i=read(fd,buffer,4); + if(i==4) { + buffer[4]=0; + if(strcmp("RIFF",buffer)!=0) { + return false; + } + } + else { + return false; + } + + /* + * Is this a WAVE file? + */ + if(lseek(fd,8,SEEK_SET)!=8) { + return false; + } + i=read(fd,buffer,4); + if(i==4) { + buffer[4]=0; + if(strcmp("WAVE",buffer)!=0) { + return false; + } + } + else { + return false; + } + + return true; +} + + +bool RDWaveFile::IsMpeg(int fd) +{ + int i; + unsigned char buffer[11]; + + id3v1_tag=false; + id3v2_tag[0]=false; + id3v2_tag[1]=false; + id3v2_offset[0]=0; + id3v2_offset[1]=0; + + lseek(fd,0,SEEK_SET); + if((i=read(fd,buffer,10))!=10) { + return false; + } + buffer[3]=0; + if(!strcasecmp((char *)buffer,"ID3")) { + id3v2_tag[0]=true; + id3v2_offset[0]= + (buffer[9]|(buffer[8]<<7)|(buffer[7]<<14)|(buffer[6]<<21))+10; + } + lseek(fd,id3v2_offset[0],SEEK_SET); + if((i=read(fd,buffer,2))!=2) { + return false; + } + if((buffer[0]==0xFF)&&((buffer[1]&0xE0)==0xE0)) { + return true; + } + while(read(fd,buffer,1)==1) { + if(buffer[0]==0xFF) { // Could be it -- check the next byte + if(read(fd,buffer,1)==1) { + if((buffer[0]&0xF0)==0xF0) { // Got it -- fix things up + id3v2_tag[0]=true; + id3v2_offset[0]=lseek(fd,0,SEEK_CUR)-2; + return true; + } + } + } + } + return false; +} + + +bool RDWaveFile::IsOgg(int fd) +{ +#ifdef HAVE_VORBIS + lseek(fd,0,SEEK_SET); + if(ov_open(fdopen(fd,"r"),&vorbis_file,NULL,0)==0) { + return true; + } +#endif // HAVE_VORBIS + return false; +} + + +bool RDWaveFile::IsAtx(int fd) +{ + char buffer[6]; + + lseek(fd,0,SEEK_SET); + if(read(fd,buffer,5)!=5) { + return false; + } + buffer[5]=0; + if(strcmp("FILE:",buffer)) { + return false; + } + + return true; +} + + +bool RDWaveFile::IsTmc(int fd) +{ + unsigned char buffer[7]; + + lseek(fd,0,SEEK_SET); + if(read(fd,buffer,6)!=6) { + return false; + } + buffer[6]=0; + if((buffer[4]!=0xFF)||((buffer[5]&0xF0)!=0xF0)) { + return false; + } + return true; +} + + +bool RDWaveFile::IsFlac(int fd) +{ +#ifdef HAVE_FLAC + char buffer[5]; + + ID3_Tag id3_tag(QCString().sprintf("%s",(const char *)wave_file.name().utf8())); + lseek(fd,id3_tag.GetPrependedBytes(),SEEK_SET); + if(read(fd,buffer,4)!=4) { + return false; + } + buffer[4]=0; + if(strcmp(buffer,"fLaC")) { + return false; + } + return true; +#else + return false; +#endif // HAVE_FLAC +} + + +bool RDWaveFile::IsAiff(int fd) +{ + int i; + char buffer[5]; + + lseek(fd,0,SEEK_SET); + i=read(fd,buffer,4); + if(i==4) { + buffer[4]=0; + if(strcmp("FORM",buffer)!=0) { + return false; + } + } + else { + return false; + } + + if(lseek(fd,8,SEEK_SET)!=8) { + return false; + } + i=read(fd,buffer,4); + if(i==4) { + buffer[4]=0; + if(strcmp("AIFF",buffer)!=0) { + return false; + } + } + else { + return false; + } + + return true; +} + + +off_t RDWaveFile::FindChunk(int fd,char *chunk_name,unsigned *chunk_size, + bool big_end) +{ + int i; + char name[5]={0,0,0,0,0}; + unsigned char buffer[4]; + off_t offset; + + offset=lseek(fd,12,SEEK_SET); + i=read(fd,name,4); + i=read(fd,buffer,4); + if(big_end) { + *chunk_size= + buffer[3]+(256*buffer[2])+(65536*buffer[1])+(16777216*buffer[0]); + } + else { + *chunk_size= + buffer[0]+(256*buffer[1])+(65536*buffer[2])+(16777216*buffer[3]); + } + while(i==4) { + if(strcasecmp(chunk_name,name)==0) { + return lseek(fd,0,SEEK_CUR); + } + lseek(fd,*chunk_size,SEEK_CUR); + i=read(fd,name,4); + i=read(fd,buffer,4); + if(big_end) { + *chunk_size=buffer[3]+(256*buffer[2])+(65536*buffer[1])+ + (16777216*buffer[0]); + } + else { + *chunk_size=buffer[0]+(256*buffer[1])+(65536*buffer[2])+ + (16777216*buffer[3]); + } + } + return -1; +} + + +bool RDWaveFile::GetChunk(int fd,char *chunk_name,unsigned *chunk_size, + unsigned char *chunk,size_t size,bool big_end) +{ + off_t pos; + if((pos=FindChunk(fd,chunk_name,chunk_size,big_end))<0) { + return false; + } + lseek(fd,SEEK_SET,pos); + read(fd,chunk,size); + return true; +} + + +void RDWaveFile::WriteChunk(int fd,char *cname,unsigned char *buf,unsigned size, + bool big_end) +{ + unsigned char size_buf[4]; + unsigned csize; + + if(FindChunk(fd,cname,&csize)<0) { + if(big_end) { + size_buf[3]=size&0xff; + size_buf[2]=(size>>8)&0xff; + size_buf[1]=(size>>16)&0xff; + size_buf[0]=(size>>24)&0xff; + } + else { + size_buf[0]=size&0xff; + size_buf[1]=(size>>8)&0xff; + size_buf[2]=(size>>16)&0xff; + size_buf[3]=(size>>24)&0xff; + } + lseek(fd,0,SEEK_END); + write(fd,cname,4); + write(fd,size_buf,4); + write(fd,buf,size); + + return; + } + if(csize==size) { + write(fd,buf,size); + return; + } + //printf("WARNING: Updated chunk size mismatch! Update not written.\n"); +} + + +bool RDWaveFile::GetFmt(int fd) +{ + unsigned chunk_size; + + /* + * Load the chunk + */ + if(!GetChunk(fd,"fmt ",&chunk_size,fmt_chunk_data,FMT_CHUNK_SIZE)) { + format_chunk=false; + return false; + } + format_chunk=true; + + /* + * Generic data -- present in ALL valid WAV files + */ + format_tag=fmt_chunk_data[0]+256*fmt_chunk_data[1]; + channels=fmt_chunk_data[2]+256*fmt_chunk_data[3]; + samples_per_sec=fmt_chunk_data[4]+256*fmt_chunk_data[5]+65536* + fmt_chunk_data[6]+16777216*fmt_chunk_data[7]; + avg_bytes_per_sec=fmt_chunk_data[8]+256*fmt_chunk_data[9]+65536* + fmt_chunk_data[10]+16777216*fmt_chunk_data[11]; + block_align=fmt_chunk_data[12]+256*fmt_chunk_data[13]; + + /* + * PCM Linear specific fields + */ + if(format_tag==WAVE_FORMAT_PCM) { + bits_per_sample=fmt_chunk_data[14]+256*fmt_chunk_data[15]; + } + + /* + * MPEG-1 specific fields + */ + if(format_tag==WAVE_FORMAT_MPEG) { + head_layer=fmt_chunk_data[18]+256*fmt_chunk_data[19]; + head_bit_rate=fmt_chunk_data[20]+256*fmt_chunk_data[21]+65536* + fmt_chunk_data[22]+16777216*fmt_chunk_data[23]; + head_mode=fmt_chunk_data[24]+256*fmt_chunk_data[25]; + head_mode_ext=fmt_chunk_data[26]+256*fmt_chunk_data[27]; + head_emphasis=fmt_chunk_data[28]+256*fmt_chunk_data[29]; + head_flags=fmt_chunk_data[30]+256*fmt_chunk_data[31]; + pts=fmt_chunk_data[32]+256*fmt_chunk_data[33]+65536* + fmt_chunk_data[34]+16777216*fmt_chunk_data[35]; + } + + return true; +} + + + +bool RDWaveFile::GetFact(int fd) +{ + unsigned chunk_size; + + /* + * Load the chunk + */ + if(!GetChunk(fd,"fact",&chunk_size,fact_chunk_data,FACT_CHUNK_SIZE)) { + return false; + } + fact_chunk=true; + + sample_length=fact_chunk_data[0]+256*fact_chunk_data[1]+ + 65536*fact_chunk_data[2]+16777216*fact_chunk_data[3]; + return true; +} + + + +bool RDWaveFile::GetCart(int fd) +{ + unsigned chunk_size; + char *tag_buffer=NULL; + int i,j; + + /* + * Load the chunk + */ + if(!GetChunk(fd,"cart",&chunk_size,cart_chunk_data,CART_CHUNK_SIZE)) { + return false; + } + cart_chunk=true; + + cart_version=cart_chunk_data[0]+256*cart_chunk_data[1]+ + 65536*cart_chunk_data[2]+16777216*cart_chunk_data[3]; + cart_title=cutString((char *)cart_chunk_data,4,64); + cart_artist=cutString((char *)cart_chunk_data,68,64); + cart_cut_id=cutString((char *)cart_chunk_data,132,64); + cart_client_id=cutString((char *)cart_chunk_data,196,64); + cart_category=cutString((char *)cart_chunk_data,260,64); + cart_classification=cutString((char *)cart_chunk_data,324,64); + cart_out_cue=cutString((char *)cart_chunk_data,388,64); + cart_start_date=cutDate((char *)cart_chunk_data,452); + cart_start_time=cutTime((char *)cart_chunk_data,462); + cart_end_date=cutDate((char *)cart_chunk_data,470); + cart_end_time=cutTime((char *)cart_chunk_data,480); + cart_producer_app_id=cutString((char *)cart_chunk_data,488,64); + cart_producer_app_ver=cutString((char *)cart_chunk_data,552,64); + cart_user_def=cutString((char *)cart_chunk_data,616,64); + cart_level_ref=cart_chunk_data[680]+256*cart_chunk_data[681]+ + 65536*cart_chunk_data[682]+16777216*cart_chunk_data[683]; + + j=0; + for(i=0;i<MAX_TIMERS;i++) { + if(cart_chunk_data[684+i*8]!=0) { + cart_timer_label[j]=cutString((char *)cart_chunk_data,684+i*8,4); + cart_timer_sample[j]=cart_chunk_data[688+i*8]+ + 256*cart_chunk_data[689+i*8]+ + 65536*cart_chunk_data[690+i*8]+ + 16777216*cart_chunk_data[691+i*8]; + j++; + } + } + if(wave_type==RDWaveFile::Wave) { + cart_url=cutString((char *)cart_chunk_data,1024,1024); + + // + // Get the Tag Text + // + if(chunk_size>2048) { + tag_buffer=(char *)malloc(chunk_size-2048+1); + read(wave_file.handle(),tag_buffer,chunk_size-2048); + tag_buffer[chunk_size-2048]=0; + cart_tag_text=tag_buffer; + free(tag_buffer); + tag_buffer=NULL; + } + } + else { + cart_url=""; + cart_tag_text=""; + } + + + if(wave_data!=NULL) { + wave_data->setMetadataFound(true); + wave_data->setTitle(cart_title); + wave_data->setArtist(cart_artist); + wave_data->setCutId(cart_cut_id); + wave_data->setClient(cart_client_id); + wave_data->setCategory(cart_category); + wave_data->setClassification(cart_classification); + wave_data->setOutCue(cart_out_cue); + wave_data->setStartDate(cart_start_date); + wave_data->setStartTime(cart_start_time); + wave_data->setEndDate(cart_end_date); + wave_data->setEndTime(cart_end_time); + wave_data->setUserDefined(cart_user_def); + wave_data->setUrl(cart_url); + wave_data->setTagText(cart_tag_text); + for(int i=0;i<MAX_TIMERS;i++) { + if((cart_timer_label[i]=="SEGs")||(cart_timer_label[i]=="SEC1")) { + wave_data->setSegueStartPos((int)(1000.0*((double)cart_timer_sample[i])/ + ((double)getSamplesPerSec()))); + } + if((cart_timer_label[i]=="SEGe")||(cart_timer_label[i]=="EOD ")) { + wave_data->setSegueEndPos((int)(1000.0*((double)cart_timer_sample[i])/ + ((double)getSamplesPerSec()))); + } + if(cart_timer_label[i]=="INTs") { + wave_data->setIntroStartPos((int)(1000.0*((double)cart_timer_sample[i])/ + ((double)getSamplesPerSec()))); + } + if(cart_timer_label[i]=="INTe") { + wave_data->setIntroEndPos((int)(1000.0*((double)cart_timer_sample[i])/ + ((double)getSamplesPerSec()))); + } + if((cart_timer_label[i]=="INT ")||(cart_timer_label[i]=="INT1")) { + wave_data->setIntroStartPos(0); + wave_data->setIntroEndPos((int)(1000.0*((double)cart_timer_sample[i])/ + ((double)getSamplesPerSec()))); + } + if(cart_timer_label[i]=="AUDs") { + wave_data->setStartPos((int)(1000.0*((double)cart_timer_sample[i])/ + ((double)getSamplesPerSec()))); + } + if(cart_timer_label[i]=="AUDe") { + wave_data->setEndPos((int)(1000.0*((double)cart_timer_sample[i])/ + ((double)getSamplesPerSec()))); + } + } + } + return true; +} + + +bool RDWaveFile::GetBext(int fd) +{ + unsigned chunk_size; + char *tag_buffer=NULL; + + /* + * Load the chunk + */ + if(!GetChunk(fd,"bext",&chunk_size,bext_chunk_data,BEXT_CHUNK_SIZE)) { + return false; + } + bext_chunk=true; + + bext_description=cutString((char *)bext_chunk_data,0,256); + bext_originator=cutString((char *)bext_chunk_data,256,32); + bext_originator_ref=cutString((char *)bext_chunk_data,288,32); + bext_origination_date=cutDate((char *)bext_chunk_data,320); + bext_origination_time=cutTime((char *)bext_chunk_data,330); + bext_time_reference_low=bext_chunk_data[338]+256*bext_chunk_data[339]+ + 65536*bext_chunk_data[340]+16777216*bext_chunk_data[341]; + bext_time_reference_high=bext_chunk_data[342]+256*bext_chunk_data[343]+ + 65536*bext_chunk_data[344]+16777216*bext_chunk_data[345]; + bext_version=bext_chunk_data[346]+256*bext_chunk_data[347]; + for(int i=0;i<64;i++) { + bext_umid[i]=bext_chunk_data[348+i]; + } + + // + // Get the Coding History + // + if(chunk_size>602) { + tag_buffer=(char *)malloc(chunk_size-602+1); + read(wave_file.handle(),tag_buffer,chunk_size-602); + tag_buffer[chunk_size-602]=0; + bext_coding_history=tag_buffer; + free(tag_buffer); + tag_buffer=NULL; + } + + if(wave_data!=NULL) { + wave_data->setMetadataFound(true); + wave_data->setDescription(bext_description); + wave_data->setOriginator(bext_originator); + wave_data->setOriginatorReference(bext_originator_ref); + wave_data->setOriginationDate(bext_origination_date); + wave_data->setOriginationTime(bext_origination_time); + wave_data->setCodingHistory(bext_coding_history); + } + return true; +} + + +bool RDWaveFile::GetMext(int fd) +{ + unsigned chunk_size; + + /* + * Load the chunk + */ + if(!GetChunk(fd,"mext",&chunk_size,mext_chunk_data,MEXT_CHUNK_SIZE)) { + return false; + } + mext_chunk=true; + + if((mext_chunk_data[0]&1)!=0) { + mext_homogenous=true; + } + if((mext_chunk_data[0]&2)==0) { + mext_padding_used=true; + } + if((mext_chunk_data[0]&4)!=0) { + mext_rate_hacked=true; + } + if((mext_chunk_data[0]&8)!=0) { + mext_free_format=true; + } + mext_frame_size=mext_chunk_data[2]+256*mext_chunk_data[3]; + mext_anc_length=mext_chunk_data[4]+256*mext_chunk_data[5]; + if((mext_chunk_data[6]&1)!=0) { + mext_left_energy=true; + } + if((mext_chunk_data[6]&2)!=0) { + mext_ancillary_private=true; + } + if((mext_chunk_data[6]&4)!=0) { + mext_right_energy=true; + } + + return true; +} + + +bool RDWaveFile::GetLevl(int fd) +{ + unsigned size=LEVL_CHUNK_SIZE; + unsigned chunk_size; + unsigned char frame[2]; + QDate date; + QTime time; + + /* + * Load the chunk + */ + if(!GetChunk(fd,"levl",&chunk_size,levl_chunk_data,LEVL_CHUNK_SIZE)) { + return false; + } + levl_chunk=true; + + levl_version=ReadDword(levl_chunk_data,0); + levl_format=ReadDword(levl_chunk_data,4); + levl_points=ReadDword(levl_chunk_data,8); + levl_block_size=ReadDword(levl_chunk_data,12); + levl_channels=ReadDword(levl_chunk_data,16); + levl_frames=ReadDword(levl_chunk_data,20); + levl_peak_offset=ReadDword(levl_chunk_data,24); + levl_block_offset=ReadDword(levl_chunk_data,28); + levl_timestamp=QDateTime(cutDate((char *)levl_chunk_data,32), + cutTime((char *)levl_chunk_data,43)); + if(levl_block_size!=1152) { + return true; + } + lseek(wave_file.handle(),FindChunk(wave_file.handle(),"levl",&size)+ + levl_block_offset-8,SEEK_SET); + for(unsigned i=1;i<levl_frames;i++) { + for(int j=0;j<levl_channels;j++) { + read(wave_file.handle(),frame,2); + energy_data.push_back(frame[0]+256*frame[1]); + } + } + if(levl_peak_offset==0xFFFFFFFF) { + levl_peak_value=0; + } + else { + levl_peak_value=energy_data[levl_peak_offset]; + } + energy_loaded=true; + has_energy=true; + return true; +} + + +bool RDWaveFile::GetScot(int fd) +{ + unsigned chunk_size; + int start_day; + int start_month; + int start_year; + int start_hour; + int end_day; + int end_month; + int end_year; + int end_hour; + unsigned cartnum; + unsigned segue_start; + + /* + * Load the chunk + */ + if(!GetChunk(fd,"scot",&chunk_size,scot_chunk_data,SCOT_CHUNK_SIZE)) { + return false; + } + scot_chunk=true; + scot_title=cutString((char *)scot_chunk_data,4,42); + scot_artist=cutString((char *)scot_chunk_data,267,33); + scot_etc=cutString((char *)scot_chunk_data,301,33); + scot_year=cutString((char *)scot_chunk_data,338,4).toInt(); + scot_intro_length=cutString((char *)scot_chunk_data,335,2).toInt()*1000; + start_year=cutString((char *)scot_chunk_data,69,2).toInt()+2000; + start_month=cutString((char *)scot_chunk_data,65,2).toInt(); + start_day=cutString((char *)scot_chunk_data,67,2).toInt(); + cartnum=cutString((char *)scot_chunk_data,47,4).toUInt(); + segue_start=(0xFF&scot_chunk_data[88])+((0xFF&scot_chunk_data[89])<<8); + if((start_month>0)&&(start_month<13)&&(start_month>0)&&(start_day<32)) { + scot_start_date=QDate(start_day,start_month,start_day); + } + start_hour=cutString((char *)scot_chunk_data,77,2).toInt(); + if((start_hour>=129)&&(start_hour<=151)) { + scot_start_time=QTime(start_hour-128,0,0); + } + end_year=cutString((char *)scot_chunk_data,75,2).toInt()+2000; + end_month=cutString((char *)scot_chunk_data,71,2).toInt(); + end_day=cutString((char *)scot_chunk_data,73,2).toInt(); + if((end_month>0)&&(end_month<13)&&(end_day>0)&&(end_day<32)&& + scot_start_date.isValid()) { + scot_end_date=QDate(end_day,end_month,end_day); + } + else { + scot_start_date=QDate(); + scot_end_date=QDate(); + } + end_hour=cutString((char *)scot_chunk_data,78,2).toInt(); + if((end_hour>=129)&&(end_hour<=151)) { + scot_end_time=QTime(end_hour-128,0,0); + } + if(wave_data!=NULL) { + wave_data->setMetadataFound(true); + wave_data->setTitle(scot_title.stripWhiteSpace()); + wave_data->setArtist(scot_artist.stripWhiteSpace()); + wave_data->setUserDefined(scot_etc.stripWhiteSpace()); + wave_data->setReleaseYear(scot_year); + wave_data->setCutId(QString().sprintf("%u",cartnum)); + wave_data->setIntroStartPos(0); + wave_data->setIntroEndPos(scot_intro_length); + if(segue_start>0) { + wave_data->setSegueStartPos(getExtTimeLength()-10*segue_start); + wave_data->setSegueEndPos(getExtTimeLength()); + } + if(scot_start_date.isValid()) { + wave_data->setStartDate(scot_start_date); + } + if(scot_start_time.isValid()) { + wave_data->setStartTime(scot_start_time); + } + if(scot_end_date.isValid()) { + wave_data->setEndDate(scot_end_date); + } + if(scot_end_time.isValid()) { + wave_data->setEndTime(scot_end_time); + } + } + return true; +} + + +bool RDWaveFile::GetAv10(int fd) +{ + // + // The 'av10' chunk is used by BE AudioVault systems for metadata storage + // + unsigned chunk_size; + QString str; + int n; + int pos; + int offset; + bool ok=false; + int istate=0; + QString label; + QString arg; + QString userdef; + + /* + * Load the chunk + */ + if(!GetChunk(fd,"av10",&chunk_size,av10_chunk_data,AV10_CHUNK_SIZE)) { + return false; + } + av10_chunk=true; + + // + // Walk through the fields + // + for(int i=2;i<chunk_size;i++) { + switch(istate) { + case 0: // Label + if(av10_chunk_data[i]==0) { + i++; + istate=1; + } + else { + label+=av10_chunk_data[i]; + } + break; + + case 1: // Argument + if(av10_chunk_data[i]==0) { // Found a label/value pair, see if we can + // use it + if(label=="1") { // Start/end markers + if((n=arg.find(","))>0) { + pos=arg.left(n).toInt(&ok); + if(ok) { + offset=arg.right(arg.length()-n-1).toInt(&ok); + if(ok) { + if(wave_data!=NULL) { + wave_data->setStartPos(pos); + wave_data->setEndPos(pos+offset); + wave_data->setMetadataFound(true); + } + } + } + } + } + if(label=="2") { // Segue markers + if((n=arg.find(","))>0) { + pos=arg.left(n).toInt(&ok); + if(ok) { + offset=arg.right(arg.length()-n-1).toInt(&ok); + if(ok) { + if(wave_data!=NULL) { + wave_data->setSegueStartPos(pos); + wave_data->setSegueEndPos(pos+offset); + wave_data->setMetadataFound(true); + } + } + } + } + } + if(label=="C") { // AV Category + userdef+=("av_category="+arg+", "); + } + if(label=="CI") { // AV Artist/Client + if(wave_data!=NULL) { + wave_data->setArtist(arg); + } + } + if(label=="CL") { // AV Class + userdef+=("av_class="+arg+", "); + } + if(label=="CO") { // AV Codes + userdef+=("av_codes="+arg+", "); + } + if(label=="D") { // AV Description + if(wave_data!=NULL) { + wave_data->setTitle(arg); + wave_data->setMetadataFound(true); + } + } + if(label=="G") { // AV ??? + } + if(label=="IN") { // AV Intro + if(ok) { + if(wave_data!=NULL) { + wave_data->setIntroStartPos(wave_data->startPos()); + wave_data->setIntroEndPos(1000*arg.toInt()); + wave_data->setMetadataFound(true); + } + } + } + if(label=="K") { // AV Kill Date + } + if(label=="N") { // AV Name + } + if(label=="Q") { // AV Outcue + if(wave_data!=NULL) { + wave_data->setOutCue(arg); + wave_data->setMetadataFound(true); + } + } + if(label=="S") { // AV Start Date + } + if(label=="SR") { // AV ??? + } + // printf("Label: %s Arg: %s\n",(const char *)label,(const char *)arg); + label=""; + arg=""; + istate=0; + } + else { + arg+=av10_chunk_data[i]; + } + break; + } + if(!userdef.isEmpty()) { + if(wave_data!=NULL) { + wave_data->setUserDefined(userdef.left(userdef.length()-2)); + } + } + } + + return true; +} + + +bool RDWaveFile::GetAir1(int fd) +{ + // + // The 'AIR1' chunk is used by AirForce systems for metadata storage + // + unsigned chunk_size; + + /* + * Load the chunk + */ + if(!GetChunk(fd,"AIR1",&chunk_size,AIR1_chunk_data,AIR1_CHUNK_SIZE)) { + return false; + } + AIR1_chunk_data[2047]=0; + if(wave_data!=NULL) { + wave_data->setTitle(cutString((char *)AIR1_chunk_data,0x102,27). + stripWhiteSpace()); + wave_data->setArtist(cutString((char *)AIR1_chunk_data,0x147,27). + stripWhiteSpace()); + wave_data->setAlbum(cutString((char *)AIR1_chunk_data,0x163,27). + stripWhiteSpace()); + wave_data->setReleaseYear(cutString((char *)AIR1_chunk_data,0x17F,4). + toInt()); + wave_data->setMetadataFound(true); + } + AIR1_chunk=true; + return true; +} + + +bool RDWaveFile::GetComm(int fd) +{ + unsigned chunk_size; + float samprate; + + /* + * Load the chunk + */ + if(!GetChunk(fd,"COMM",&chunk_size,comm_chunk_data,COMM_CHUNK_SIZE,true)) { + comm_chunk=false; + return false; + } + comm_chunk=true; + + + format_tag=WAVE_FORMAT_PCM; // We support only PCM AIFFs at the moment + channels=comm_chunk_data[1]+256*fmt_chunk_data[0]; + sample_length=comm_chunk_data[5]+256*comm_chunk_data[4]+ + 65536*comm_chunk_data[3]+16777216*comm_chunk_data[2]; + bits_per_sample=comm_chunk_data[6]+256*comm_chunk_data[7]; + samples_per_sec=256*(0xFF&comm_chunk_data[10])+(0xFF&comm_chunk_data[11]); + + return true; +} + + +bool RDWaveFile::GetList(int fd) +{ + unsigned chunk_size=0; + if((wave_data==NULL)||(FindChunk(fd,"list",&chunk_size)<0)) { + return false; + } + unsigned char *chunk_data=new unsigned char[chunk_size]; + read(fd,chunk_data,chunk_size); +/* + if(strncmp("INFO",chunk_data,4)) { + delete chunk_data; + return false; + } +*/ + unsigned offset=4; + while(ReadListElement(chunk_data,&offset,chunk_size)); + if((wave_data->segueStartPos()>=0)&&(wave_data->segueEndPos()<0)) { + wave_data->setSegueEndPos(ext_time_length); + } + return true; +} + + +bool RDWaveFile::ReadListElement(unsigned char *buffer,unsigned *offset, + unsigned size) +{ + if(*offset>=size) { + return false; + } + char tag[5]; + for(int i=0;i<4;i++) { + tag[i]=buffer[*offset+i]; + } + tag[4]=0; + *offset+=4; + unsigned len=ReadDword(buffer,*offset); + *offset+=4; + if(!strcmp(tag,"tref")) { + wave_data->setTmciSongId(((char *)buffer)+(*offset)); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"tttl")) { + wave_data->setTitle(((char *)buffer)+(*offset)); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"tart")) { + wave_data->setArtist(((char *)buffer)+(*offset)); + wave_data->setMetadataFound(true); + } + + if(!strcmp(tag,"tcom")) { + wave_data->setComposer(((char *)buffer)+(*offset)); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"tpub")) { + wave_data->setPublisher(((char *)buffer)+(*offset)); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"tlic")) { + wave_data->setLicensingOrganization(((char *)buffer)+(*offset)); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"tlab")) { + wave_data->setLabel(((char *)buffer)+(*offset)); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"tint")) { + wave_data->setIntroStartPos(0); + wave_data->setIntroEndPos(RDSetTimeLength(((char *)buffer)+(*offset))); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"ttim")) { + wave_data->setStartPos(0); + wave_data->setEndPos(RDSetTimeLength(((char *)buffer)+(*offset))); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"tend")) { + wave_data->setEndType((RDWaveData::EndType)(((char *)buffer)+(*offset))[0]); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"tyr ")) { + wave_data->setReleaseYear(QString(((char *)buffer)+(*offset)).toInt()); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"taux")) { + wave_data->setSegueStartPos(RDSetTimeLength(((char *)buffer)+(*offset))); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"tbpm")) { + wave_data->setBeatsPerMinute(QString(((char *)buffer)+(*offset)).toInt()); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"talb")) { + wave_data->setAlbum(((char *)buffer)+(*offset)); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"tpli")) { + wave_data->setCopyrightNotice(((char *)buffer)+(*offset)); + wave_data->setMetadataFound(true); + } + if(!strcmp(tag,"tisr")) { + wave_data->setIsrc(QString(((char *)buffer)+(*offset)).remove(" ")); + wave_data->setMetadataFound(true); + } + + *offset+=len; + while(((*offset)<size) && (buffer[*offset]==0)) { + (*offset)++; + } + return true; +} + + +bool RDWaveFile::ReadTmcMetadata(int fd) +{ + char buffer[256]; + QString current_tag; + + lseek(fd,data_length+4,SEEK_SET); + while(GetLine(fd,buffer,255)) { + if(buffer[0]=='#') { + current_tag=QString(buffer+1); + } + else { + if(!current_tag.isEmpty()) { + ReadTmcTag(current_tag,QString(buffer)); + } + } + } + return false; +} + + +void RDWaveFile::ReadTmcTag(const QString tag,const QString value) +{ + if(tag=="TITLE") { + wave_data->setTitle(value.stripWhiteSpace()); + wave_data->setMetadataFound(true); + } + if(tag=="ARTIST") { + wave_data->setArtist(value.stripWhiteSpace()); + wave_data->setMetadataFound(true); + } + if(tag=="COMPOSER") { + wave_data->setComposer(value.stripWhiteSpace()); + wave_data->setMetadataFound(true); + } + if(tag=="PUBLISHER") { + wave_data->setPublisher(value.stripWhiteSpace()); + wave_data->setMetadataFound(true); + } + if(tag=="LICENSE") { + wave_data->setLicensingOrganization(value.stripWhiteSpace()); + wave_data->setMetadataFound(true); + } + if(tag=="LABEL") { + wave_data->setLabel(value.stripWhiteSpace()); + wave_data->setMetadataFound(true); + } + if(tag=="ALBUM") { + wave_data->setAlbum(value.stripWhiteSpace()); + wave_data->setMetadataFound(true); + } + if(tag=="YEAR") { + wave_data->setReleaseYear(value.stripWhiteSpace().toInt()); + wave_data->setMetadataFound(true); + } + if(tag=="INTRO") { + wave_data->setIntroStartPos(0); + wave_data->setIntroEndPos(RDSetTimeLength(value.stripWhiteSpace())); + wave_data->setMetadataFound(true); + } + if(tag=="AUX") { + wave_data->setSegueStartPos(RDSetTimeLength(value.stripWhiteSpace())); + wave_data->setMetadataFound(true); + } + if(tag=="END") { + wave_data->setEndType((RDWaveData::EndType)((char)value[0])); + wave_data->setMetadataFound(true); + } + if(tag=="TMCIREF") { + wave_data->setTmciSongId(value.stripWhiteSpace()); + wave_data->setMetadataFound(true); + } + if(tag=="BPM") { + wave_data->setBeatsPerMinute(value.toInt()); + wave_data->setMetadataFound(true); + } + if(tag=="ISRC") { + QString str=value; + wave_data->setIsrc(str.remove(" ").stripWhiteSpace()); + wave_data->setMetadataFound(true); + } + if(tag=="PLINE") { + wave_data->setCopyrightNotice(value.stripWhiteSpace()); + wave_data->setMetadataFound(true); + } +} + + +bool RDWaveFile::GetLine(int fd,char *buffer,int max_len) +{ + for(int i=0;i<max_len;i++) { + if(read(fd,buffer+i,1)==0) { + return false; + } + if(buffer[i]==10) { + if(buffer[i-1]==13) { + buffer[i-1]=0; + } + else { + buffer[i]=0; + } + return true; + } + } + buffer[max_len-1]=0; + return true; +} + + +void RDWaveFile::ReadId3Metadata() +{ + if(wave_data==NULL) { + return; + } + ID3_Frame *frame=NULL; + ID3_Tag id3_tag(QCString().sprintf("%s",(const char *)wave_file.name().utf8())); + if((frame=id3_tag.Find(ID3FID_TITLE))!=NULL) { + wave_data->setTitle(ID3_GetString(frame,ID3FN_TEXT)); + wave_data->setMetadataFound(true); + } + if((frame=id3_tag.Find(ID3FID_BPM))!=NULL) { + wave_data-> + setBeatsPerMinute(QString(ID3_GetString(frame,ID3FN_TEXT)).toInt()); + wave_data->setMetadataFound(true); + } + if((frame=id3_tag.Find(ID3FID_ALBUM))!=NULL) { + wave_data->setAlbum(ID3_GetString(frame,ID3FN_TEXT)); + wave_data->setMetadataFound(true); + } + if((frame=id3_tag.Find(ID3FID_COMPOSER))!=NULL) { + wave_data->setComposer(ID3_GetString(frame,ID3FN_TEXT)); + wave_data->setMetadataFound(true); + } + if((frame=id3_tag.Find(ID3FID_COPYRIGHT))!=NULL) { + wave_data->setCopyrightNotice(ID3_GetString(frame,ID3FN_TEXT)); + wave_data->setMetadataFound(true); + } + if((frame=id3_tag.Find(ID3FID_ORIGARTIST))!=NULL) { + wave_data->setArtist(ID3_GetString(frame,ID3FN_TEXT)); + wave_data->setMetadataFound(true); + } + if((frame=id3_tag.Find(ID3FID_LEADARTIST))!=NULL) { + wave_data->setArtist(ID3_GetString(frame,ID3FN_TEXT)); + wave_data->setMetadataFound(true); + } + if((frame=id3_tag.Find(ID3FID_PUBLISHER))!=NULL) { + wave_data->setPublisher(ID3_GetString(frame,ID3FN_TEXT)); + wave_data->setMetadataFound(true); + } + if((frame=id3_tag.Find(ID3FID_ISRC))!=NULL) { + wave_data->setIsrc(ID3_GetString(frame,ID3FN_TEXT)); + wave_data->setMetadataFound(true); + } + if((frame=id3_tag.Find(ID3FID_YEAR))!=NULL) { + wave_data-> + setReleaseYear(QString(ID3_GetString(frame,ID3FN_TEXT)).toInt()); + wave_data->setMetadataFound(true); + } +} + + +bool RDWaveFile::GetMpegHeader(int fd,int offset) +{ + unsigned char buffer[4]; + int n; + + lseek(fd,offset,SEEK_SET); + if((n=read(fd,buffer,4))!=4) { + return false; + } + + // + // Sync + // + if((buffer[0]!=0xFF)||((buffer[1]&0xE0)!=0xE0)) { + return false; + } + + // + // MPEG Id + // + if((buffer[1]&0x08)==0) { + mpeg_id=RDWaveFile::Mpeg2; + } + else { + mpeg_id=RDWaveFile::Mpeg1; + } + + // + // Layer + // + switch((buffer[1]&0x06)>>1) { + case 1: + head_layer=3; + break; + + case 2: + head_layer=2; + break; + + case 3: + head_layer=1; + break; + + default: + return false; + } + + // + // Bitrate + // + switch(mpeg_id) { + case RDWaveFile::Mpeg1: + switch(head_layer) { + case 1: + switch(buffer[2]>>4) { + case 1: + head_bit_rate=32000; + break; + + case 2: + head_bit_rate=64000; + break; + + case 3: + head_bit_rate=96000; + break; + + case 4: + head_bit_rate=128000; + break; + + case 5: + head_bit_rate=160000; + break; + + case 6: + head_bit_rate=192000; + break; + + case 7: + head_bit_rate=224000; + break; + + case 8: + head_bit_rate=256000; + break; + + case 9: + head_bit_rate=288000; + break; + + case 10: + head_bit_rate=320000; + break; + + case 11: + head_bit_rate=352000; + break; + + case 12: + head_bit_rate=384000; + break; + + case 13: + head_bit_rate=416000; + break; + + case 14: + head_bit_rate=448000; + break; + + default: + return false; + } + break; + + case 2: + switch(buffer[2]>>4) { + case 1: + head_bit_rate=32000; + break; + + case 2: + head_bit_rate=48000; + break; + + case 3: + head_bit_rate=56000; + break; + + case 4: + head_bit_rate=64000; + break; + + case 5: + head_bit_rate=80000; + break; + + case 6: + head_bit_rate=96000; + break; + + case 7: + head_bit_rate=112000; + break; + + case 8: + head_bit_rate=128000; + break; + + case 9: + head_bit_rate=160000; + break; + + case 10: + head_bit_rate=192000; + break; + + case 11: + head_bit_rate=224000; + break; + + case 12: + head_bit_rate=256000; + break; + + case 13: + head_bit_rate=320000; + break; + + case 14: + head_bit_rate=384000; + break; + + default: + return false; + break; + } + break; + + case 3: + switch(buffer[2]>>4) { + case 1: + head_bit_rate=32000; + break; + + case 2: + head_bit_rate=40000; + break; + + case 3: + head_bit_rate=48000; + break; + + case 4: + head_bit_rate=56000; + break; + + case 5: + head_bit_rate=64000; + break; + + case 6: + head_bit_rate=80000; + break; + + case 7: + head_bit_rate=96000; + break; + + case 8: + head_bit_rate=112000; + break; + + case 9: + head_bit_rate=128000; + break; + + case 10: + head_bit_rate=160000; + break; + + case 11: + head_bit_rate=192000; + break; + + case 12: + head_bit_rate=224000; + break; + + case 13: + head_bit_rate=256000; + break; + + case 14: + head_bit_rate=320000; + break; + + default: + return false; + break; + } + break; + } + break; + + case RDWaveFile::Mpeg2: + switch(head_layer) { + case 1: + switch(buffer[2]>>4) { + case 1: + head_bit_rate=32000; + break; + + case 2: + head_bit_rate=48000; + break; + + case 3: + head_bit_rate=56000; + break; + + case 4: + head_bit_rate=64000; + break; + + case 5: + head_bit_rate=80000; + break; + + case 6: + head_bit_rate=96000; + break; + + case 7: + head_bit_rate=112000; + break; + + case 8: + head_bit_rate=128000; + break; + + case 9: + head_bit_rate=144000; + break; + + case 10: + head_bit_rate=160000; + break; + + case 11: + head_bit_rate=176000; + break; + + case 12: + head_bit_rate=192000; + break; + + case 13: + head_bit_rate=224000; + break; + + case 14: + head_bit_rate=256000; + break; + + default: + return false; + } + break; + + case 2: + switch(buffer[2]>>4) { + case 1: + head_bit_rate=8000; + break; + + case 2: + head_bit_rate=16000; + break; + + case 3: + head_bit_rate=24000; + break; + + case 4: + head_bit_rate=32000; + break; + + case 5: + head_bit_rate=40000; + break; + + case 6: + head_bit_rate=48000; + break; + + case 7: + head_bit_rate=56000; + break; + + case 8: + head_bit_rate=64000; + break; + + case 9: + head_bit_rate=80000; + break; + + case 10: + head_bit_rate=96000; + break; + + case 11: + head_bit_rate=112000; + break; + + case 12: + head_bit_rate=128000; + break; + + case 13: + head_bit_rate=144000; + break; + + case 14: + head_bit_rate=160000; + break; + + default: + return false; + break; + } + break; + + case 3: + switch(buffer[2]>>4) { + case 1: + head_bit_rate=8000; + break; + + case 2: + head_bit_rate=16000; + break; + + case 3: + head_bit_rate=24000; + break; + + case 4: + head_bit_rate=32000; + break; + + case 5: + head_bit_rate=40000; + break; + + case 6: + head_bit_rate=48000; + break; + + case 7: + head_bit_rate=56000; + break; + + case 8: + head_bit_rate=64000; + break; + + case 9: + head_bit_rate=80000; + break; + + case 10: + head_bit_rate=96000; + break; + + case 11: + head_bit_rate=112000; + break; + + case 12: + head_bit_rate=128000; + break; + + case 13: + head_bit_rate=144000; + break; + + case 14: + head_bit_rate=160000; + break; + + default: + return false; + break; + } + break; + } + break; + + default: + return false; + } + + // + // Sample Rate + // + switch((buffer[2]>>2)&0x03) { + case 0: + switch(mpeg_id) { + case RDWaveFile::Mpeg1: + samples_per_sec=44100; + break; + + case RDWaveFile::Mpeg2: + samples_per_sec=22050; + break; + + default: + break; + } + break; + + case 1: + switch(mpeg_id) { + case RDWaveFile::Mpeg1: + samples_per_sec=48000; + break; + + case RDWaveFile::Mpeg2: + samples_per_sec=24000; + break; + + default: + break; + } + break; + + case 2: + switch(mpeg_id) { + case RDWaveFile::Mpeg1: + samples_per_sec=32000; + break; + + case RDWaveFile::Mpeg2: + samples_per_sec=16000; + break; + + default: + break; + } + break; + + default: + return false; + break; + } + + // + // Mode + // + switch(buffer[3]>>6) { + case 0: + head_mode=ACM_MPEG_STEREO; + channels=2; + break; + + case 1: + head_mode=ACM_MPEG_JOINTSTEREO; + channels=2; + break; + + case 2: + head_mode=ACM_MPEG_DUALCHANNEL; + channels=2; + break; + + case 3: + head_mode=ACM_MPEG_SINGLECHANNEL; + channels=1; + break; + } + + // + // Flags + // + if((buffer[2]&0x01)!=0) { + head_flags|=ACM_MPEG_PRIVATEBIT; + } + if((buffer[3]&0x08)!=0) { + head_flags|=ACM_MPEG_COPYRIGHT; + } + if((buffer[3]&0x04)!=0) { + head_flags|=ACM_MPEG_ORIGINALHOME; + } + if((buffer[1]&0x01)!=0) { + head_flags|=ACM_MPEG_PROTECTIONBIT; + } + if(mpeg_id==RDWaveFile::Mpeg1) { + head_flags|=ACM_MPEG_ID_MPEG1; + } + + // + // Frame Size (without padding) + // + mpeg_frame_size=144*head_bit_rate/samples_per_sec; + + return true; +} + + +int RDWaveFile::GetAtxOffset(int fd) +{ + unsigned char buffer[MAX_ATX_HEADER_SIZE]; + lseek(fd,0,SEEK_SET); + + int n=read(fd,buffer,MAX_ATX_HEADER_SIZE-1); + for(int i=0;i<n;i++) { + if(buffer[i]==0xFF) { + return i; + } + } + return -1; +} + + +bool RDWaveFile::GetFlacStreamInfo() +{ +#if HAVE_FLAC + FLAC__StreamMetadata sinfo; + if(!FLAC__metadata_get_streaminfo(QCString().sprintf("%s",(const char *)wave_file.name().utf8()),&sinfo)) { + return false; + } + samples_per_sec=sinfo.data.stream_info.sample_rate; + bits_per_sample=sinfo.data.stream_info.bits_per_sample; + sample_length=sinfo.data.stream_info.total_samples; + channels=sinfo.data.stream_info.channels; + return true; +#else + return false; +#endif // HAVE_FLAC +} + + +void RDWaveFile::ReadFlacMetadata() +{ +#ifdef HAVE_FLAC_METADATA + QString artist; + QString composer; + FLAC__StreamMetadata* tags; + if(!FLAC__metadata_get_tags(QCString(). + sprintf("%s",(const char *)wave_file.name().utf8()),&tags)) { + return; + } + for(int iCommentIndex=0;iCommentIndex<tags->data.vorbis_comment.num_comments; + ++iCommentIndex) + { + FLAC__StreamMetadata_VorbisComment_Entry& + comment(tags->data.vorbis_comment.comments[iCommentIndex]); + + // comment.entry is a UTF-8 string of comment.length octets + // (http://www.xiph.org/vorbis/doc/v-comment.html) + QString entry= + QString::fromUtf8((const char *)comment.entry, comment.length); + + // every entry is a name=value pair. Name is not allowed to contain a '=' + // so we just scan to the first instance of it. + int nameLength = entry.find('='); + if(nameLength < 0) continue; // malformed comment, it would seem + QString name = entry.left(nameLength), value = entry.mid(nameLength + 1); + + if(name=="TITLE") { + wave_data->setTitle(value); + wave_data->setMetadataFound(true); + continue; + } + if(name=="ARTIST") { + composer=value; + wave_data->setMetadataFound(true); + continue; + } + if(name=="PERFORMER") { + artist=value; + wave_data->setMetadataFound(true); + } + if(name=="ALBUM") { + wave_data->setAlbum(value); + wave_data->setMetadataFound(true); + continue; + } + if(name=="ORGANIZATION") { + wave_data->setLabel(value); + wave_data->setMetadataFound(true); + continue; + } + // TODO: Parse the date field to get the year out + //if(name == "DATE") { wave_data->setReleaseYear(value); + //wave_data->setMetadataFound(true); continue; } + if(name=="ISRC") { + wave_data->setIsrc(value); + wave_data->setMetadataFound(true); + continue; + } + } + if((!artist.isEmpty())&&(!composer.isEmpty())) { + wave_data->setArtist(artist); + wave_data->setComposer(composer); + } + else { + if(!artist.isEmpty()) { + wave_data->setArtist(artist); + } + else { + wave_data->setArtist(composer); + } + } + FLAC__metadata_object_delete(tags); +#endif // HAVE_FLAC_METADATA +} + + +bool RDWaveFile::MakeFmt() +{ + if((format_tag!=WAVE_FORMAT_PCM)&&(format_tag!=WAVE_FORMAT_MPEG)) { + return false; + } + if((channels!=1)&&(channels!=2)) { + return false; + } + if(samples_per_sec==0) { + return false; + } + if(format_tag==WAVE_FORMAT_PCM) { + switch(bits_per_sample) { + case 8: + block_align=channels; + break; + case 16: + block_align=2*channels; + break; + case 24: + block_align=3*channels; + break; + case 32: + block_align=4*channels; + break; + default: + return false; + break; + } + avg_bytes_per_sec=block_align*samples_per_sec; + cb_size=0; + WriteSword(fmt_chunk_data,0,format_tag); + WriteSword(fmt_chunk_data,2,channels); + WriteDword(fmt_chunk_data,4,samples_per_sec); + WriteDword(fmt_chunk_data,8,avg_bytes_per_sec); + WriteSword(fmt_chunk_data,12,block_align); + WriteSword(fmt_chunk_data,14,bits_per_sample); + WriteSword(fmt_chunk_data,16,cb_size); + fmt_size=18; + return true; + } + if(format_tag==WAVE_FORMAT_MPEG) { + bits_per_sample=0; + block_align=144*head_bit_rate/samples_per_sec; + cb_size=40; + if(head_layer==0) { + return false; + } + if(head_bit_rate==0) { + return false; + } + if((!mext_padding_used)&&((samples_per_sec==11025)|| + (samples_per_sec==22050)|| + (samples_per_sec==44100))) { + avg_bytes_per_sec=samples_per_sec*block_align/1152; + } + else { + avg_bytes_per_sec=head_bit_rate/8; + } + if(head_mode==0) { + return false; + } + head_flags|=ACM_MPEG_ID_MPEG1; + + WriteSword(fmt_chunk_data,0,format_tag); + WriteSword(fmt_chunk_data,2,channels); + WriteDword(fmt_chunk_data,4,samples_per_sec); + WriteDword(fmt_chunk_data,8,avg_bytes_per_sec); + WriteSword(fmt_chunk_data,12,block_align); + WriteSword(fmt_chunk_data,14,bits_per_sample); + WriteSword(fmt_chunk_data,16,cb_size); + WriteSword(fmt_chunk_data,18,head_layer); + WriteDword(fmt_chunk_data,20,head_bit_rate); + WriteSword(fmt_chunk_data,24,head_mode); + WriteSword(fmt_chunk_data,26,head_mode_ext); + WriteSword(fmt_chunk_data,28,head_emphasis); + WriteSword(fmt_chunk_data,30,head_flags); + WriteDword(fmt_chunk_data,32,0); + WriteDword(fmt_chunk_data,36,0); + fmt_size=40; + return true; + } + return false; +} + + +bool RDWaveFile::MakeCart() +{ + for(int i=0;i<CART_CHUNK_SIZE;i++) { + cart_chunk_data[i]=0; + } + sprintf((char *)cart_chunk_data,"%4s", + CART_VERSION); + if(!cart_title.isEmpty()) { + sprintf((char *)cart_chunk_data+4,"%s", + (const char *)cart_title.left(64)); + } + if(!cart_artist.isEmpty()) { + sprintf((char *)cart_chunk_data+68,"%s", + (const char *)cart_artist.left(64)); + } + if(!cart_cut_id.isEmpty()) { + sprintf((char *)cart_chunk_data+132,"%s", + (const char *)cart_cut_id.left(64)); + } + if(!cart_client_id.isEmpty()) { + sprintf((char *)cart_chunk_data+196,"%s", + (const char *)cart_client_id.left(64)); + } + if(!cart_category.isEmpty()) { + sprintf((char *)cart_chunk_data+260,"%s", + (const char *)cart_category.left(64)); + } + if(!cart_classification.isEmpty()) { + sprintf((char *)cart_chunk_data+324,"%s", + (const char *)cart_classification.left(64)); + } + if(!cart_out_cue.isEmpty()) { + sprintf((char *)cart_chunk_data+388,"%s", + (const char *)cart_out_cue.left(64)); + } + sprintf((char *)cart_chunk_data+452,"%04d/%02d/%02d", + cart_start_date.year(), + cart_start_date.month(), + cart_start_date.day()); + sprintf((char *)cart_chunk_data+462,"%02d:%02d:%02d", + cart_start_time.hour(), + cart_start_time.minute(), + cart_start_time.second()); + sprintf((char *)cart_chunk_data+470,"%04d/%02d/%02d", + cart_end_date.year(), + cart_end_date.month(), + cart_end_date.day()); + sprintf((char *)cart_chunk_data+480,"%02d:%02d:%02d", + cart_end_time.hour(), + cart_end_time.minute(), + cart_end_time.second()); + sprintf((char *)cart_chunk_data+488,"%s", + (const char *)PACKAGE); + sprintf((char *)cart_chunk_data+552,"%s", + (const char *)VERSION); + if(!cart_user_def.isEmpty()) { + sprintf((char *)cart_chunk_data+616,"%s", + (const char *)cart_user_def.left(64)); + } + WriteDword(cart_chunk_data,680,cart_level_ref); + for(int i=0;i<MAX_TIMERS;i++) { + if(!cart_timer_label[i].isEmpty()) { + sprintf((char *)cart_chunk_data+684+i*MAX_TIMERS,"%4s", + (const char *)cart_timer_label[i].left(4)); + WriteDword(cart_chunk_data,688+i*MAX_TIMERS,cart_timer_sample[i]); + } + } + if(!cart_url.isEmpty()) { + sprintf((char *)cart_chunk_data+1020,"%s", + (const char *)cart_url.left(1024)); + } + return true; +} + + +bool RDWaveFile::MakeBext() +{ + bext_coding_size=bext_coding_history.length()+BEXT_CHUNK_SIZE; + bext_coding_data=(unsigned char *)realloc(bext_coding_data,bext_coding_size); + + for(int i=0;i<BEXT_CHUNK_SIZE;i++) { + bext_coding_data[i]=0; + } + if(!bext_description.isEmpty()) { + sprintf((char *)bext_coding_data,"%s", + (const char *)bext_description.left(256)); + } + if(!bext_originator.isEmpty()) { + sprintf((char *)bext_coding_data+256,"%s", + (const char *)bext_originator.left(32)); + } + if(!bext_originator_ref.isEmpty()) { + sprintf((char *)bext_coding_data+288,"%s", + (const char *)bext_originator_ref.left(32)); + } + sprintf((char *)bext_coding_data+320,"%04d-%02d-%02d", + bext_origination_date.year(), + bext_origination_date.month(), + bext_origination_date.day()); + sprintf((char *)bext_coding_data+330,"%02d:%02d:%02d", + bext_origination_time.hour(), + bext_origination_time.minute(), + bext_origination_time.second()); + WriteDword(bext_coding_data,338,bext_time_reference_low); + WriteDword(bext_coding_data,342,bext_time_reference_high); + WriteSword(bext_coding_data,346,BWF_VERSION); + for(int i=0;i<64;i++) { + bext_coding_data[i+348]=bext_umid[i]; + } + if(!bext_coding_history.isEmpty()) { + sprintf((char *)bext_coding_data+602,"%s", + (const char *)bext_coding_history); + } + return true; +} + + +bool RDWaveFile::MakeMext() +{ + for(int i=0;i<MEXT_CHUNK_SIZE;i++) { + mext_chunk_data[i]=0; + } + if(mext_homogenous) { + mext_chunk_data[0]|=1; + } + if(!mext_padding_used) { + mext_chunk_data[0]|=2; + } + if(mext_rate_hacked) { + mext_chunk_data[0]|=4; + } + if(mext_free_format) { + mext_chunk_data[0]|=8; + } + if(mext_homogenous) { + WriteSword(mext_chunk_data,2,mext_frame_size); + } + WriteSword(mext_chunk_data,4,mext_anc_length); + if(mext_left_energy) { + mext_chunk_data[6]|=1; + } + if(mext_ancillary_private) { + mext_chunk_data[6]|=2; + } + if(mext_right_energy) { + mext_chunk_data[6]|=4; + } + return true; +} + + +bool RDWaveFile::MakeLevl() +{ + for(int i=0;i<LEVL_CHUNK_SIZE;i++) { + levl_chunk_data[i]=0; + } + WriteDword(levl_chunk_data,0,levl_version); + WriteDword(levl_chunk_data,4,levl_format); // Format + WriteDword(levl_chunk_data,8,levl_points); // Points per Value + WriteDword(levl_chunk_data,12,levl_block_size); // Blocksize + WriteDword(levl_chunk_data,16,levl_channels); // Channels + WriteDword(levl_chunk_data,20,levl_frames); // Total Peak Values + WriteDword(levl_chunk_data,24,levl_peak_offset); // Offset to Peak-of-Peaks + WriteDword(levl_chunk_data,28,128); // Offset to Peak Data + sprintf((char *)levl_chunk_data+32,"%s", + (const char *)levl_timestamp.toString("yyyy:MM:dd:hh:mm:ss:000")); + + return true; +} + + +QString RDWaveFile::cutString(char *buffer,unsigned start_point,unsigned size) +{ + QString string; + + for(unsigned i=start_point;i<start_point+size;i++) { + string=string.append(buffer[i]); + } + + return string; +} + + + + +QDate RDWaveFile::cutDate(char *buffer,unsigned start_point) +{ + int i; + char date_buf[11]; + int day=0,mon=0,year=0; + + for(i=0;i<4;i++) { + date_buf[i]=buffer[start_point+i]; + } + date_buf[4]=0; + sscanf(date_buf,"%d",&year); + if(year>RD_MAX_YEAR) { + year=RD_MAX_YEAR; + } + for(i=0;i<2;i++) { + date_buf[i]=buffer[start_point+i+5]; + } + date_buf[2]=0; + sscanf(date_buf,"%d",&mon); + for(i=0;i<4;i++) { + date_buf[i]=buffer[start_point+i+8]; + } + date_buf[2]=0; + sscanf(date_buf,"%d",&day); + + if((mon>0)&&(mon<13)&&(day>0)&&(day<32)) { + return QDate(year,mon,day); + } + return QDate(); +} + + + + +QTime RDWaveFile::cutTime(char *buffer,unsigned start_point) +{ + int i; + char time_buf[9]; + int hour=0,min=0,sec=0; + + for(i=0;i<8;i++) { + time_buf[i]=buffer[start_point+i]; + } + time_buf[8]=0; + sscanf(time_buf,"%d:%d:%d",&hour,&min,&sec); + + return QTime(hour,min,sec); +} + + +void RDWaveFile::WriteDword(unsigned char *buf,unsigned ptr,unsigned value) +{ + buf[ptr]=value&0xff; + buf[ptr+1]=(value>>8)&0xff; + buf[ptr+2]=(value>>16)&0xff; + buf[ptr+3]=(value>>24)&0xff; +} + + +void RDWaveFile::WriteSword(unsigned char *buf,unsigned ptr, + unsigned short value) +{ + buf[ptr]=value&0xff; + buf[ptr+1]=(value>>8)&0xff; +} + + +unsigned RDWaveFile::ReadDword(unsigned char *buffer,unsigned offset) +{ + return buffer[offset]+256*buffer[offset+1]+ + 65536*buffer[offset+2]+16777216*buffer[offset+3]; +} + + +unsigned short RDWaveFile::ReadSword(unsigned char *buffer,unsigned offset) +{ + return buffer[offset]+256*buffer[offset+1]; +} + + +void RDWaveFile::GetEnergy() +{ + int file_ptr; + + ReadEnergyFile(wave_file.name()); + + if(!levl_chunk) { + GetLevl(wave_file.handle()); + } + if(energy_loaded) { + return; + } + file_ptr=lseek(wave_file.handle(),0,SEEK_CUR); + lseek(wave_file.handle(),0,SEEK_SET); + LoadEnergy(); + energy_loaded=true; + lseek(wave_file.handle(),file_ptr,SEEK_SET); +} + + +unsigned RDWaveFile::LoadEnergy() +{ + unsigned i=0; + unsigned char block[5]; + char pcm[4608]; + int block_size; + int offset; + unsigned energy_size; + + short max=0; + + energy_data.clear(); + + energy_size=getSampleLength()*getChannels()/1152; + seekWave(0,SEEK_SET); + switch(format_tag) { + case WAVE_FORMAT_MPEG: + if((head_layer==2)&&(mext_left_energy||mext_right_energy)) { + while(i<energy_size) { + lseek(wave_file.handle(),block_align-5,SEEK_CUR); + if(read(wave_file.handle(),block,5)<5) { + has_energy=true; + return i; + } + if(mext_left_energy) { + energy_data.push_back(block[4]+256*block[3]); + i++; + } + if(mext_right_energy) { + energy_data.push_back(block[1]+256*block[0]); + i++; + } + } + has_energy=true; + return i; + } + else { + has_energy=false; + return 0; + } + break; + + case WAVE_FORMAT_PCM: + block_size=2304*channels; + while(i<energy_size) { + if(read(wave_file.handle(),pcm,block_size)!=block_size) { + has_energy=true; + return i; + } + for(int j=0;j<channels;j++) { + max=0; + energy_data.push_back(0); + for(int k=0;k<1152;k++) { + offset=2*k*channels+2*j; + if((pcm[offset]+256*pcm[offset+1])>energy_data[i]) { + energy_data[i]=pcm[offset]+256*pcm[offset+1]; + } + } + i++; + } + } + has_energy=true; + return i; + break; + + case WAVE_FORMAT_VORBIS: + block_size=2304*channels; + while(i<energy_size) { + if(readWave(pcm,block_size)!=block_size) { + has_energy=true; + return i; + } + for(int j=0;j<channels;j++) { + max=0; + energy_data.push_back(0); + for(int k=0;k<1152;k++) { + offset=2*k*channels+2*j; + if((pcm[offset]+256*pcm[offset+1])>energy_data[i]) { + energy_data[i]=pcm[offset]+256*pcm[offset+1]; + } + } + i++; + } + } + has_energy=true; + return i; + break; + + default: + has_energy=false; + return 0; + break; + } +} + + +bool RDWaveFile::ReadEnergyFile(QString wave_file_name) +{ + if(has_energy && energy_loaded) return true; + + QFile energy_file; + QString str; + unsigned char frame[50]; + + energy_file.setName(wave_file_name+".energy"); + if(!energy_file.open(IO_ReadOnly)) + return false; + if(energy_file.readLine(str,20) <= 0) + return false; + normalize_level=str.toDouble(); + energy_file.close(); + if(!energy_file.open(IO_ReadOnly)) + return false; + read(energy_file.handle(),frame,str.length()); + int i=0; + while(read(energy_file.handle(),frame,2)>0) { + energy_data.push_back(frame[0]+256*frame[1]); + i++; + } + ext_time_length= + (unsigned)(1000.0*(((double)i*1152)/getChannels())/(double)samples_per_sec); + energy_file.close(); + energy_loaded=true; + has_energy=true; + return true; +} + + +bool RDWaveFile::ReadNormalizeLevel(QString wave_file_name) +{ + QFile energy_file; + QString str; + + energy_file.setName(wave_file_name+".energy"); + if(!energy_file.open(IO_ReadOnly)) + return false; + if(energy_file.readLine(str,20) <= 0) + return false; + normalize_level=str.toDouble(); + energy_file.close(); + return true; +} + + +double RDWaveFile::getNormalizeLevel() const +{ + return normalize_level; +} + + +void RDWaveFile::setNormalizeLevel(double level) +{ + normalize_level=level; +} + + +void RDWaveFile::GrowAlloc(size_t size) +{ + if(size>(size_t)cook_buffer_size) { + cook_buffer=(unsigned char *)realloc(cook_buffer,size); + cook_buffer_size=size; + } +} + + +void RDWaveFile::ValidateMetadata() +{ + if(wave_data==NULL) { + return; + } + + if(!wave_data->metadataFound()) { + return; + } + if(wave_data->startPos()<0) { + wave_data->setStartPos(0); + } + if(wave_data->endPos()<0) { + wave_data->setEndPos(ext_time_length); + } + if((wave_data->segueStartPos()>=0)&&(wave_data->segueEndPos()<0)) { + wave_data->setSegueEndPos(wave_data->endPos()); + } +} + + +#ifdef HAVE_VORBIS +int RDWaveFile::WriteOggPage(ogg_page *page) +{ + int n; + + n=write(wave_file.handle(),page->header,page->header_len); + n+=write(wave_file.handle(),page->body,page->body_len); + return n; +} +#endif // HAVE_VORBIS + + +int RDWaveFile::WriteOggBuffer(char *buf,int size) +{ +#ifdef HAVE_VORBIS + float **buffer=vorbis_analysis_buffer(&vorbis_dsp,size/channels); + for(int i=0;i<(size/(2*channels));i++) { + for(int j=0;j<channels;j++) { +/* + buffer[j][i]= + (float)((buf[2*channels*i+2*j]&0xff)| + ((buf[2*channels*i+2*j+1]&0xff)<<8))/32768.0f; +*/ +/* + if(buffer[j][i]>high) { + high=buffer[j][i]; + } +*/ + buffer[j][i]= + ((float)(buf[2*channels*i+2*j]&0xff)+ + (256.0f*(float)(buf[2*channels*i+2*j+1]&0xff)))/32768.0f; + } +// printf("HIGH: %5.3f\n",high); + } + vorbis_analysis_wrote(&vorbis_dsp,size/(2*channels)); + while(vorbis_analysis_blockout(&vorbis_dsp,&vorbis_blk)==1) { + vorbis_analysis(&vorbis_blk,NULL); + vorbis_bitrate_addblock(&vorbis_blk); + while(vorbis_bitrate_flushpacket(&vorbis_dsp,&ogg_pack)) { + ogg_stream_packetin(&ogg_stream,&ogg_pack); + while(ogg_stream_pageout(&ogg_stream,&ogg_pg)) { + WriteOggPage(&ogg_pg); + } + } + } +#endif // HAVE_VORBIS + return 0; +} diff --git a/lib/rdwavefile.h b/lib/rdwavefile.h new file mode 100644 index 00000000..32b4f9b1 --- /dev/null +++ b/lib/rdwavefile.h @@ -0,0 +1,1324 @@ +// rdwavefile.h +// +// A class for handling Microsoft WAV files. +// +// (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdwavefile.h,v 1.10.6.2 2014/01/15 19:56:32 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU Library General Public License +// version 2 as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDWAVEFILE_H +#define RDWAVEFILE_H + +#include <vector> +#include <sys/types.h> +#include <sys/stat.h> +#ifndef WIN32 +#include <unistd.h> +#endif // WIN32 +#include <qobject.h> +#include <qstring.h> +#include <qdatetime.h> +#include <qfile.h> + +#ifdef HAVE_VORBIS +#include <vorbis/vorbisfile.h> +#include <vorbis/vorbisenc.h> +#endif // HAVE_VORBIS + +#include <rdwavedata.h> +#include <rdringbuffer.h> +#include <rdsettings.h> + +using namespace std; + + +// +// Number of timers allowed in the CartChunk structure. +// The official number is '8'. +// +#define MAX_TIMERS 8 + +// +// Define this if we should guesstimate the overall sample count +// of a MPEG file with a missing or zeroed 'fact' chunk. (Technically, +// such a file is invalid, but there are lots of them floating +// around out there nonetheless.) Otherwise, return '0' for the +// sample count. +// +#define MPEG_FACT_FUDGE + +// +// The default mode bits for new WAV files. +// +#define WAVE_MODE_BITS 0644 + +/* + * Chunk Sizes + */ +#define FMT_CHUNK_SIZE 40 +#define FACT_CHUNK_SIZE 4 +#define CART_CHUNK_SIZE 2048 +#define BEXT_CHUNK_SIZE 602 +#define MEXT_CHUNK_SIZE 12 +#define LEVL_CHUNK_SIZE 128 +#define SCOT_CHUNK_SIZE 424 +#define AV10_CHUNK_SIZE 512 +#define AIR1_CHUNK_SIZE 2048 +#define COMM_CHUNK_SIZE 18 + +// +// Maximum Header Size for ATX Files +#define MAX_ATX_HEADER_SIZE 512 + +// +// The size of the MPEG Ring Buffer +// +#define MPEG_BUFFER_SIZE 32768 + +// +// Default Values +// +#define DEFAULT_LEVL_FORMAT 2 +#define DEFAULT_LEVL_POINTS 1 +#define DEFAULT_LEVL_BLOCK_SIZE 1152 + + +/** + * @short A class for handling Microsoft WAV files. + * @author Fred Gleason <fredg@wava.com> + * + * RDWaveFile provides an abstraction of a Microsoft RIFF-based WAV file. + * In addition to 'FMT' and 'DATA' chunks, chunk types of particular + * interest to broadcast applications are supported, including those + * specified by the Broadcast Wave File specification (EBU Tech Document + * 3285, with suppliments) and the CartChunk specification (currently + * proposed to become AES standard AES-46). + **/ +class RDWaveFile +{ + public: + enum Encoding {Raw=0,Signed16Int=1,Signed32Float=2}; + enum Format {Pcm8=0,Pcm16=1,Float32=2,MpegL1=3,MpegL2=4,MpegL3=5, + DolbyAc2=6,DolbyAc3=7,Vorbis=8}; + enum Type {Unknown=0,Wave=1,Mpeg=2,Ogg=3,Atx=4,Tmc=5,Flac=6,Ambos=7, + Aiff=8}; + enum MpegID {NonMpeg=0,Mpeg1=1,Mpeg2=2}; + + /** + * Create an RDWaveFile object. + * @param file_name The name of the WAV file to load into the object. + **/ + RDWaveFile(QString file_name=""); + + /** + * Destroy an RDWaveFile object. + **/ + ~RDWaveFile(); + + /** + * Get the file type. + **/ + RDWaveFile::Type type() const; + + /** + * Assign a WAV file name. + * @param file_name The WAV filename to assign. + **/ + void nameWave(QString file_name); + + /** + * Open the WAV file for recording. If the file already exists, it's + * prior contents will be overwritten. If not, a new file will be + * created. + * + * It is important that all desired meta-data chunks be enabled (using + * the set<name>Chunk() family of methods) before invoking createWav(). + * Once the WAV file is created, new meta-data chunks cannot be added or + * removed, although the contents of existing ones can be updated. + * At a minimum, the 'FMT' chunk will need to have it's parameters + * (sample rate, channels, etc) defined, or this method will return an + * error. + * + * Returns true if WAV file was created successfully, otherwise false. + **/ + bool createWave(RDWaveData *data=NULL); + + /** + * Open the WAV file for playback. A WAV file name must first have + * been assigned, either in the constructor or by means of nameWav(). + * + * Setting 'allow_broken=true' will permit even patently-broken files + * (like the raw files from an AMR-100 receiver, that have no FMT chunk) + * to be opened to allow the metadata to be read. + **/ + bool openWave(RDWaveData *data=NULL); + + /** + * Close the WAV file. Any pending DATA chunk or meta-data writes + * will be applied, and DATA and FACT chunk size structures updated + * accordingly. + **/ + void closeWave(int samples=-1); + + /** + * Reset the record pointer on the WAV file to zero. Erases any audio + * data previously recorded, but otherwise leaves things (format settings, + * meta-data) as they were. + **/ + void resetWave(); + + /** + * Returns true if the WAV file contains a FMT chunk, otherwise false. + **/ + bool getFormatChunk() const; + + /** + * Returns true if the WAV file contains a FACT chunk, otherwise false. + **/ + bool getFactChunk() const; + + /** + * Returns the length of the audio in samples. + **/ + unsigned getSampleLength() const; + + /** + * Returns the length of the audio in seconds. + **/ + unsigned getTimeLength() const; + + /** + * Returns the length of the audio in milliseconds. + **/ + unsigned getExtTimeLength() const; + + /** + * Returns true if the WAV file contains a DATA chunk, otherwise false. + **/ + bool getDataChunk() const; + + /** + * Returns the length of the contents of the DATA chunk, in bytes. + **/ + unsigned getDataLength() const; + + /** + * Returns the current encoding type. + **/ + RDWaveFile::Encoding encoding() const; + + /** + * Set the encoding type. + * @param code The encoding to use. + **/ + void setEncoding(RDWaveFile::Encoding code); + + /** + * Read a block of data from the DATA chunk, using the current + * encoding type. + * @param buf The buffer in which to place the data. + * @param count The maximum number of bytes to transfer. + * Returns the number of bytes read. + **/ + int readWave(void *buf,int count); + + /** + * Write a block of data to the DATA chunk. + * @param buf The buffer from which to take the data. + * @param count The number of bytes to transfer. + * Returns the number of bytes written. + **/ + int writeWave(void *buf,int count); + + /** + * Set the DATA chunk file pointer. + * @param offset The value to which to set the pointer. The exact meaning + * depends upon the value of the 'whence' parameters, below: + * @param whence If SEEK_SET, set the file pointer to the value given + * in 'offset. If SEEK_CUR, set the pointer to the value given in 'offset', + * plus the current value. + * Returns If successful, return the current pointer position, relative to + * the start of the DATA chunk, otherwise -1. + **/ + int seekWave(int offset,int whence); + + void getSettings(RDSettings *settings); + void setSettings(const RDSettings *settings); + + /** + * Returns true if energy data is available. + **/ + bool hasEnergy(); + + /** + * Returns the size of the energy data, or zero if none available. + **/ + unsigned energySize(); + + /** + * Returns energy data. For stereo files, this will be + * interleaved LEFT>>RIGHT>>LEFT>>... . + * @param frame The frame to reference. + **/ + unsigned short energy(unsigned frame); + + /** + * Read a block of energy data. + * @param buf The buffer in which to place the data. + * @param count The maximum number of bytes to transfer. + * Returns the number of bytes read. + **/ + int readEnergy(unsigned short buf[],int count); + + /** + * Find the first instance of energy at or above the specified level. + * @param level The level, in dbFS * 100. + * Returns: The location in samples from file start, or -1 to indicate + * failure. + **/ + int startTrim(int level); + + /** + * Find the last instance of energy at or above the specified level. + * @param level The level, in dbFS * 100. + * Returns: The location in samples from file start, or -1 to indicate + * failure. + **/ + int endTrim(int level); + + /** + * Returns the filename of the WAV file. + **/ + QString getName() const; + + /** + * Returns the FormatTag of the WAV file, as defined in the 'FMT' chunk. + * Values currently understood by RDWaveFile are: + * WAVE_FORMAT_PCM Linear PCM Data + * WAVE_FORMAT_IEEE_FLOAT IEEE Floating Point Data + * WAVE_FORMAT_MPEG MPEG-1 Encoded Data + **/ + unsigned short getFormatTag() const; + + /** + * Set the format tag in the FMT chunk for a WAV file to be recorded. + * Values currently understood by RDWaveFile are: + * WAVE_FORMAT_PCM Linear PCM Data + * WAVE_FORMAT_MPEG MPEG-1 Encoded Data + * @param format The encoding format. + **/ + void setFormatTag(unsigned short format); + + /** + * Returns the number of audio channels recorded in the WAV file, as + * represented by the 'FMT chunk. + **/ + unsigned short getChannels() const; + + /** + * Sets the number of channels in the FMT chunk for a WAV file to be + * recorded. Currently supported values are '1' or '2'. + * @param chan Number of channels. + **/ + void setChannels(unsigned short chan); + + /** + * Returns the sampling rate of the audio recorded in the WAV file, as + * represented by the 'FMT chunk, in samples per second. + **/ + unsigned getSamplesPerSec() const; + + /** + * Sets the sampling rate in the FMT chunk for a WAV file to be recorded. + * @param rate The sampling rate in samples per second. + **/ + void setSamplesPerSec(unsigned rate); + + /** + * Returns the average data rate of the audio recorded in the WAV file, as + * represented by the 'FMT chunk, in bytes per second. + **/ + unsigned getAvgBytesPerSec() const; + + /** + * Returns the 'atomic' sample size of the audio recorded in the WAV file, + * as represented by the 'FMT' chunk. In the case of a non-homogenous or + * bit-padded MPEG file, this will be set to '1'. + **/ + unsigned short getBlockAlign() const; + + /** + * Returns the bits per audio sample for PCM files, otherwise a '0'. + **/ + unsigned short getBitsPerSample() const; + + /** + * Set the number of bits per sample for PCM files in the FMT chunk + * for a WAV file to be recorded. For MPEG files, this should be set + * to '0'. + * @param bits Number of bits per audio sample, or '0' for an MPEG file. + **/ + void setBitsPerSample(unsigned short bits); + + /** + * Returns the MPEG-1 Layer (1, 2 or 3) for an MPEG-1 file, otherwise a '0'. + **/ + unsigned short getHeadLayer() const; + + /** + * Set the MPEG-1 Layer for MPEG files in the FMT chunk for a WAV file + * to be recorded. Layers 1, 2 and 3 are supported. For PCM files, + * this should be set to '0'. + * @param layer MPEG-1 encoding layer, or '0' for a PCM file. + **/ + void setHeadLayer(unsigned short layer); + + /** + * Returns the bit rate for an MPEG-1 file in bits per second, otherwise + * a '0'. + **/ + unsigned getHeadBitRate() const; + + /** + * Set the bit rate for an MPEG-1 file in the FMT chunk for a WAV file + * to be recorded. This needs to be one of the "official" rates as + * defined in the MPEG-1 standard. Valid rates are: + * LAYER 1: 32000, 64000, 96000,128000,160000,192000,224000, + * 256000,288000,320000,352000,384000,416000,448000 + * + * LAYER 2: 32000, 48000, 56000, 64000, 80000, 96000,112000, + * 128000,160000,192000,224000,256000,320000,384000 + * + * LAYER 3: 32000, 40000, 48000, 56000, 64000, 80000, 96000, + * 112000,128000,160000,192000,224000,256000,320000 + * + * @param rate MPEG bitrate, in bits per second, or '0' for a PCM file. + **/ + void setHeadBitRate(unsigned rate); + + /** + * Returns the MPEG-1 Mode for an MPEG-1 file, otherwise a '0'. Possible + * modes are: + * ACM_MPEG_STEREO Stereo + * ACM_MPEG_JOINTSTEREO Joint Stereo + * ACM_MPEG_DUALCHANNEL Dual Channel + * ACM_MPEG_SINGLECHANNEL Mono + **/ + unsigned short getHeadMode() const; + + /** + * Set the MPEG-1 mode for an MPEG file in the FMT chunk for a WAV + * file to be recorded. This value is a series of flags bitwise-OR'd + * together. The corresponding flag should be set if one or more + * MPEG-1 frames in that mode are present in the audio data. + * + * Valid mode flags are: + * ACM_MPEG_STEREO Stereo + * ACM_MPEG_JOINTSTEREO Joint Stereo + * ACM_MPEG_DUALCHANNEL Dual Channel + * ACM_MPEG_SINGLECHANNEL Mono + * + * @param mode The bitwise-OR'd mode flags for MPEG files, or a '0' for PCM + * files. + **/ + void setHeadMode(unsigned short mode); + + /** + * Returns the extended mode flags for an MPEG-1 file, otherwise a '0'. + **/ + unsigned getHeadModeExt() const; + + /** + * Returns the request preemphasis for an MPEG-1 file, otherwise a '0'. + **/ + unsigned getHeadEmphasis() const; + + /** + * Returns the MPEG-1 flags for an MPEG-1 file, otherwise a '0'. + **/ + unsigned short getHeadFlags() const; + + /** + * Set the MPEG-1 flags for an MPEG file. All appropriate flags should + * be bitwise-OR'd together. Valid flags include: + * ACM_MPEG_PRIVATEBIT Private Bit + * ACM_MPEG_COPYRIGHT Copyright Bit + * ACM_MPEG_ORIGINALHOME Original Home Bit + * ACM_MPEG_PROTECTIONBIT Protection Bit + * ACM_MPEG_ID_MPEG1 MPEG-1 ID Bit + * + * @param flags The MPEG-1 flags to set. + **/ + void setHeadFlags(unsigned short flags); + + /** + * Not currently implemented. + **/ + unsigned long getPTS() const; + + /** + * Returns true if the WAV file contains a CART chunk, otherwise false. + **/ + bool getCartChunk() const; + + /** + * Enable a CartChunk structure. The default is to not create a + * CartChunk structure in the WAV file to be recorded. For more + * information on CartChunk and it's capabilities, see + * http://www.cartchunk.org/. + * @param state true = Enable cart chunk structure, false = disable + **/ + void setCartChunk(bool state); + + /** + * Returns the version of the CartChunk standard used in the WAV file. + **/ + unsigned getCartVersion() const; + + /** + * Returns the contents of the TITLE field in the WAV file's CART chunk. + **/ + QString getCartTitle() const; + + /** + * Set the TITLE field on the WAV file's CartChunk. + * @param string The value for the TITLE field. + **/ + void setCartTitle(QString string); + + /** + * Returns the contents of the ARTIST field in the WAV file's CART chunk. + **/ + QString getCartArtist() const; + + /** + * Set the ARTIST field on the WAV file's CartChunk. + * @param string The value for the ARTIST field. + **/ + void setCartArtist(QString string); + + /** + * Returns the contents of the CutID field in the WAV file's CART chunk. + **/ + QString getCartCutID() const; + + /** + * Set the CutID field on the WAV file's CartChunk. + * @param string The value for the CutID field. + **/ + void setCartCutID(QString string); + + /** + * Returns the contents of the ClientID field in the WAV file's CART chunk. + **/ + QString getCartClientID() const; + + /** + * Set the ClientID field on the WAV file's CartChunk. + * @param string The value for the ClientID field. + **/ + void setCartClientID(QString string); + + /** + * Returns the contents of the CATEGORY field in the WAV file's CART chunk. + **/ + QString getCartCategory() const; + + /** + * Set the Category field on the WAV file's CartChunk. + * @param string The value for the Category field. + **/ + void setCartCategory(QString string); + + /** + * Returns the contents of the CLASSIFICATION field in the WAV file's + * CART chunk. + **/ + QString getCartClassification() const; + + /** + * Set the Classification field on the WAV file's CartChunk. + * @param string The value for the Cclassification field. + **/ + void setCartClassification(QString string); + + /** + * Returns the contents of the OUTCUE field in the WAV file's CART chunk. + **/ + QString getCartOutCue() const; + + /** + * Set the OutCue field on the WAV file's CartChunk. + * @param string The value for the OutCue field. + **/ + void setCartOutCue(QString string); + + /** + * Returns the contents of the STARTDATE field in the WAV file's CART chunk. + **/ + QDate getCartStartDate() const; + + /** + * Set the StartDate field on the WAV file's CartChunk. + * @param date The value for the StartDate field. + **/ + void setCartStartDate(QDate date); + + /** + * Returns the contents of the STARTTIME field in the WAV file's CART chunk. + **/ + QTime getCartStartTime() const; + + /** + * Set the StartTime field on the WAV file's CartChunk. + * @param time The value for the StartTime field. + **/ + void setCartStartTime(QTime time); + + /** + * Returns the contents of the ENDDATE field in the WAV file's CART chunk. + **/ + QDate getCartEndDate() const; + + /** + * Set the EndDate field on the WAV file's CartChunk. + * @param date The value for the EndDate field. + **/ + void setCartEndDate(QDate date); + + /** + * Returns the contents of the ENDTIME field in the WAV file's CART chunk. + **/ + QTime getCartEndTime() const; + + /** + * Set the EndTime field on the WAV file's CartChunk. + * @param time The value for the EndTime field. + **/ + void setCartEndTime(QTime time); + + /** + * Returns the contents of the PRODUCER APPLICATION ID field in the WAV + * file's CART chunk. + **/ + QString getCartProducerAppID() const; + + /** + * Returns the contents of the PRODUCER APPLICATION VERSION field in the + * WAV file's CART chunk. + **/ + QString getCartProducerAppVer() const; + + /** + * Returns the contents of the USERDEF field in the WAV file's CART chunk. + **/ + QString getCartUserDef() const; + + /** + * Set the UserDef field on the WAV file's CartChunk. + * @param string The value for the UserRef field. + **/ + void setCartUserDef(QString string); + + /** + * Returns the contents of the LEVELREF field in the WAV file's CART chunk. + **/ + unsigned getCartLevelRef() const; + + /** + * Set the LevelRef field on the WAV file's CartChunk. + * @param level The value for the LevelRef field. + **/ + void setCartLevelRef(unsigned level); + + /** + * Retrieve the label for one of the eight CartChunk timers. + * @param index The index number of the timer to access (0 - 7). + * Returns the label of the corresponding timer. + **/ + QString getCartTimerLabel(int index) const; + + /** + * Set the label for one of the eight CartChunk timers. + * @param index The index number of the timer to access (0 - 7). + * @param label the label of the corresponding timer. + **/ + void setCartTimerLabel(int index,QString label); + + /** + * Retrieve the sample value for one of the eight CartChunk timers. + * @param index The index number of the timer to access (0 - 7). + * Returns the sample value of the corresponding timer. + **/ + unsigned getCartTimerSample(int index) const; + + /** + * Set the sample value for one of the eight CartChunk timers. + * @param index The index number of the timer to access (0 - 7). + * @param sample the sample value of the corresponding timer. + **/ + void setCartTimerSample(int index,unsigned sample); + + /** + * Returns the contents of the URL field in the WAV file's CART chunk. + **/ + QString getCartURL() const; + + /** + * Set the URL field on the WAV file's CartChunk. + * @param string The value for the URL field. + **/ + void setCartURL(QString string); + + /** + * Returns the contents of the TAGTEXT field in the WAV file's CART chunk. + **/ + QString getCartTagText() const; + + /** + * Returns true if the WAV file contains a BEXT chunk, otherwise false. + **/ + bool getBextChunk() const; + + /** + * Enable a BWF Bext structure. The default is to not create a + * Bext structure in the WAV file to be recorded. For more + * information on the BWF format and it's capabilities, see + * http://www.sr.se/utveckling/tu/bwf/. + * @param state true = Enable Bext structure, false = disable + **/ + void setBextChunk(bool state); + + /** + * Returns the contents of the DESCRIPTION field in the WAV file's BEXT + * chunk. + **/ + QString getBextDescription() const; + + /** + * Set the Description field on the WAV file's Bext structure. + * @param string The value for the Description field. + **/ + void setBextDescription(QString string); + + /** + * Returns the contents of the ORIGINATOR field in the WAV file's BEXT + * chunk. + **/ + QString getBextOriginator() const; + + /** + * Set the Originator field on the WAV file's Bext structure. + * @param string The value for the Originator field. + **/ + void setBextOriginator(QString string); + + /** + * Returns the contents of the ORIGINATOR REFERENCE field in the WAV + * file's BEXT chunk. + **/ + QString getBextOriginatorRef() const; + + /** + * Set the Originator Reference field on the WAV file's Bext structure. + * @param string The value for the Originator Reference field. + **/ + void setBextOriginatorRef(QString string); + + /** + * Returns the contents of the ORIGINATION DATE field in the WAV file's BEXT + * chunk. + **/ + QDate getBextOriginationDate() const; + + /** + * Set the Origination Date field on the WAV file's Bext structure. + * @param date The value for the Origination Date field. + **/ + void setBextOriginationDate(QDate date); + + /** + * Returns the contents of the ORIGINATION TIME field in the WAV file's BEXT + * chunk. + **/ + QTime getBextOriginationTime() const; + + /** + * Set the Origination Time field on the WAV file's Bext structure. + * @param time The value for the Origination Time field. + **/ + void setBextOriginationTime(QTime time); + + /** + * Returns the lower 32 bits of the BWF Time Reference field. + **/ + unsigned getBextTimeReferenceLow() const; + + /** + * Sets the lower 32 bits of the BWF Time Reference field. + * @param sample The sample value for the lower 32 bits + **/ + void setBextTimeReferenceLow(unsigned sample); + + /** + * Returns the upper 32 bits of the BWF Time Reference field. + **/ + unsigned getBextTimeReferenceHigh() const; + + /** + * Sets the upper 32 bits of the BWF Time Reference field. + * @param sample The sample value for the upper 32 bits + **/ + void setBextTimeReferenceHigh(unsigned sample); + + /** + * Returns the version of the BWF standard used by the WAV file. + **/ + unsigned short getBextVersion() const; + + /** + * Gets the SMPTE Unique Material Identifier (UMD) in the WAV file's + * BEXT chunk. See SMPTE Standard 330M-2000 for more info. + * @param buf A 64 byte long buffer in which to place the UMD + **/ + void getBextUMD(unsigned char *buf) const; + + /** + * Sets the SMPTE Unique Material Identifier (UMD) in the WAV file's + * BEXT chunk. See SMPTE Standard 330M-2000 for more info. + * @param buf A 64 byte long buffer containing the UMD + **/ + void setBextUMD(unsigned char *buf); + + /** + * Returns the contents of the CODING HISTORY field from the WAV files' + * BEXT chunk. + **/ + QString getBextCodingHistory() const; + + /** + * Set the Coding History field on the WAV file's Bext structure. + * NOTE: This can only be set prior to calling createWave()! If + * called after createWave(), it will be silently ignored. + * @param string The value for the Coding History field. + **/ + void setBextCodingHistory(QString string); + + /** + * Returns true if the WAV file contains a MEXT chunk, otherwise false. + **/ + bool getMextChunk() const; + + /** + * Enable a BWF Mext structure. The default is to not create a + * Mext structure in the WAV file to be recorded. For more + * information on the BWF format and it's capabilities, see + * http://www.sr.se/utveckling/tu/bwf/. + * @param state true = Enable Mext structure, false = disable + **/ + void setMextChunk(bool state); + + /** + * Returns true if file is tagged as containing homogenous data, otherwise + * false. + **/ + bool getMextHomogenous() const; + + /** + * Returns true if the padding bit is used (and hence the MPEG frame size + * can vary between frames), otherwise false. + **/ + bool getMextPaddingUsed() const; + + /** + * Returns true if the file contains frames with the padding bits all + * set to '0' and a sample rate of 22.025 or 44.1 kHz. According to + * MPEG-1, such files are deprecated (because the overall bit rate is + * not one of the standard MPEG rates). + **/ + bool getMextHackedBitRate() const; + + /** + * Returns true if the file contains free format frames, otherwise false. + **/ + bool getMextFreeFormat() const; + + /** + * Returns the number of bytes in a frame for homogenous data, otherwise + * zero. If the padding bit is used, this will be the frame size for + * frames with the padding bit set to '0'. For frames with the padding + * bit set to '1', the frame size will be four bytes longer for Layer 1 + * and one byte longer for Layer 2 and Layer 3. + **/ + int getMextFrameSize() const; + + /** + * Returns the minimal number of known bytes for ancillary data in the + * full sound file. The value is relative from the end of the audio frame. + **/ + int getMextAncillaryLength() const; + + /** + * Returns true if the ancillary data contains left or mono channel energy + * information, otherise false. + **/ + bool getMextLeftEnergyPresent() const; + + /** + * Returns true if the ancillary data contains right channel energy + * information, otherwise false. + **/ + bool getMextRightEnergyPresent() const; + + /** + * Returns true if the ancillary data contains private data, otherwise + * false. + **/ + bool getMextPrivateDataPresent() const; + + /** + * Set the BWF Mext structure in the WAV file to be recorded as containing + * homogenous or non-homogenous MPEG-1 data. + * @param state True = Data is homogenous, false = data is non-homogenous + **/ + void setMextHomogenous(bool state); + + /** + * Set the BWF Mext structure in the WAV file to be recorded to indicate + * the status of the MPEG-1 padding bit. + * @param state True = padding bit is used, false = padding bit is ignored + **/ + void setMextPaddingUsed(bool state); + + /** + * Set the BWF Mext structure in the WAV file to indicate frames with + * padding bits all set to '0' and a sample rate of 22.025 or 44.1 kHz. + * According to MPEG-1, such files are deprecated (because the overall + * bit rate is not one of the standard MPEG rates). + * @param state True = hacked bit rate used, false = proper bit rate used + **/ + void setMextHackedBitRate(bool state); + + /** + * Set the BWF Mext structure in the WAV file to be recorded to indicate + * free format MPEG-1 frame. + * @param state True = free format frames, false = constant bit rate frames + **/ + void setMextFreeFormat(bool state); + + /** + * Set the BWF Mext structure in the WAV file to be recorded to indicate + * the number of bytes in a frame for homogenous data, otherwise + * zero. If the padding bit is used, this will be the frame size for + * frames with the padding bit set to '0'. For frames with the padding + * bit set to '1', the frame size will be four bytes longer for Layer 1 + * and one byte longer for Layer 2 and Layer 3. + **/ + void setMextFrameSize(int size); + + /** + * Set the BWF Mext structure in the WAV file to be recorded to indicate + * the minimal number of known bytes for ancillary data in the + * full sound file. The value is relative from the end of the audio frame. + **/ + void setMextAncillaryLength(int length); + + /** + * Set the BWF Mext structure in the WAV file to be recorded to indicate + * if the ancillary data contains left or mono channel energy + * information. + * @param state True = left energy data is present, false = is not present + **/ + void setMextLeftEnergyPresent(bool state); + + /** + * Set the BWF Mext structure in the WAV file to be recorded to indicate + * if the ancillary data contains rightchannel energy + * information. + * @param state True = right energy data is present, false = is not present + **/ + void setMextRightEnergyPresent(bool state); + + /** + * Set the BWF Mext structure in the WAV file to be recorded to indicate + * if the ancillary data contains private data. + * @param state True = private data present, false = no private data + **/ + void setMextPrivateDataPresent(bool state); + + /** + * Returns true if the WAV file contains a LEVL chunk, otherwise false. + **/ + bool getLevlChunk() const; + + /** + * Enable a BWF Levl structure. The default is to not create a + * Levl structure in the WAV file to be recorded. For more + * information on the BWF format and it's capabilities, see + * http://www.sr.se/utveckling/tu/bwf/. + * @param state true = Enable Levl structure, false = disable + **/ + void setLevlChunk(bool state); + + /** + * Get the version of the LEVL chunk data. + **/ + int getLevlVersion() const; + + /** + * Set the version of the LEVL chunk data. + * @param ver The version number to set. + **/ + void setLevlVersion(unsigned ver); + + /** + * Get the number of audio samples per peak value of the LEVL chunk. + **/ + int getLevlBlockSize() const; + + /** + * Set the block size of the LEVL chunk data. + * @param ver The block size to set. + **/ + void setLevlBlockSize(unsigned size); + + /** + * Get the number of channels of peak values. + **/ + int getLevlChannels() const; + + /** + * Get the 'peak-of-peaks' value. + **/ + unsigned short getLevlPeak() const; + + /** + * Get the timestamp of the LEVL chunk. + **/ + QDateTime getLevlTimestamp() const; + + /** + * Set the encoding quality (for OggVorbis only) + **/ + void setEncodeQuality(float qual); + + /** + * Get serial number (for OggVorbis only) + **/ + int getSerialNumber() const; + + /** + * Set serial number (for OggVorbis only) + **/ + void setSerialNumber(int serial); + + /** + * Returns true if the WAV file contains a SCOT chunk, otherwise false. + **/ + bool getScotChunk() const; + + bool getAIR1Chunk() const; + + double getNormalizeLevel() const; + void setNormalizeLevel(double level); + + private: + RDWaveFile::Type GetType(int fd); + bool IsWav(int fd); + bool IsMpeg(int fd); + bool IsOgg(int fd); + bool IsAtx(int fd); + bool IsTmc(int fd); + bool IsFlac(int fd); + bool IsAiff(int fd); + off_t FindChunk(int fd,char *chunk_name,unsigned *chunk_size, + bool big_end=false); + bool GetChunk(int fd,char *chunk_name,unsigned *chunk_size, + unsigned char *chunk,size_t size,bool big_end=false); + void WriteChunk(int fd,char *cname,unsigned char *buf,unsigned size, + bool big_end=false); + bool GetFmt(int fd); + bool GetFact(int fd); + bool GetCart(int fd); + bool GetBext(int fd); + bool GetMext(int fd); + bool GetLevl(int fd); + bool GetList(int fd); + bool GetScot(int fd); + bool GetAv10(int fd); + bool GetAir1(int fd); + bool GetComm(int fd); + bool ReadListElement(unsigned char *buffer,unsigned *offset,unsigned size); + bool ReadTmcMetadata(int fd); + void ReadTmcTag(const QString tag,const QString value); + bool GetLine(int fd,char *buffer,int max_len); + void ReadId3Metadata(); + bool GetMpegHeader(int fd,int offset); + int GetAtxOffset(int fd); + bool GetFlacStreamInfo(); + void ReadFlacMetadata(); + bool MakeFmt(); + bool MakeCart(); + bool MakeBext(); + bool MakeMext(); + bool MakeLevl(); + void WriteDword(unsigned char *,unsigned,unsigned); + void WriteSword(unsigned char *,unsigned,unsigned short); + unsigned ReadDword(unsigned char *,unsigned); + unsigned short ReadSword(unsigned char *,unsigned); + void GetEnergy(); + unsigned LoadEnergy(); + bool ReadNormalizeLevel(QString wave_file_name); + bool ReadEnergyFile(QString wave_file_name); + void GrowAlloc(size_t size); + void ValidateMetadata(); +#ifdef HAVE_VORBIS + int WriteOggPage(ogg_page *page); +#endif // HAVE_VORBIS + int WriteOggBuffer(char *buf,int size); + QFile wave_file; + RDWaveData *wave_data; + bool recordable; // Allow DATA chunk writes? + unsigned time_length; // Audio length in secs + unsigned ext_time_length; // Audio length in msec + bool format_chunk; // Does 'fmt ' chunk exist? + bool comm_chunk; // Does 'COMM' chunk exist? + unsigned char comm_chunk_data[COMM_CHUNK_SIZE]; + unsigned short format_tag; // Encoding Format + unsigned short channels; // Number of channels + unsigned samples_per_sec; // Samples/sec/channel + unsigned avg_bytes_per_sec; // Average bytes/sec overall + unsigned short block_align; // Data block size + unsigned short bits_per_sample; // Bits per mono sample (PCM only) + unsigned short cb_size; // Number of bytes of extended data + unsigned short head_layer; // The MPEG audio layer + unsigned head_bit_rate; // MPEG bit rate, in byte/sec + unsigned short head_mode; // MPEG stream mode + unsigned head_mode_ext; // Extra mode parameters (for joint stereo) + unsigned head_emphasis; // De-emphasis + unsigned short head_flags; // MPEG header flags + unsigned long pts; // The MPEG PTS + RDWaveFile::MpegID mpeg_id; + int mpeg_frame_size; + bool id3v1_tag; + bool id3v2_tag[2]; + unsigned id3v2_offset[2]; + unsigned char fmt_chunk_data[FMT_CHUNK_SIZE]; + int fmt_size; // Size of FMT chunk + bool fact_chunk; // Does 'fact' chunk exist? + unsigned sample_length; // Audio length in samples + unsigned char fact_chunk_data[FACT_CHUNK_SIZE]; + bool data_chunk; // Does 'data' chunk exist? + int data_start; // Start position of WAV data + unsigned data_length; // Length of raw audio data + bool cart_chunk; // Does 'cart' chunk exist? + unsigned cart_version; // CartChunk Version field + QString cart_title; // CartChunk Title field + QString cart_artist; // CartChunk Artist field + QString cart_cut_id; // CartChunk CutID field + QString cart_client_id; // CartChunk ClientID field + QString cart_category; // CartChunk Category field + QString cart_classification; // CartChunk Classification field + QString cart_out_cue; // CartChunk OutCue Field + QDate cart_start_date; // CartChunk StartDate field + QTime cart_start_time; // CartChunk StartTime field + QDate cart_end_date; // CartChunk EndDate field + QTime cart_end_time; // CartChunk EndTime field + QString cart_producer_app_id; // CartChunk ProducerAppID field + QString cart_producer_app_ver; // CartChunk ProducerAppVersion field + QString cart_user_def; // CartChunk UserDef field + unsigned cart_level_ref; // CartChunk dwLevelReference field + QString cart_timer_label[MAX_TIMERS]; // CartChunk CartTimer labels + unsigned cart_timer_sample[MAX_TIMERS]; // CarChunk CartTimer samples + QString cart_url; // CartChunk URL field + QString cart_tag_text; // CartChunk TagText field + unsigned char cart_chunk_data[CART_CHUNK_SIZE]; + + bool bext_chunk; // Does the chunk exist? + QString bext_description; // BWF Description of sound sequence + QString bext_originator; // BWF Name of originator + QString bext_originator_ref; // BWF Reference of the originator + QDate bext_origination_date; // BWF Origination date + QTime bext_origination_time; // BWF Origination time + unsigned bext_time_reference_low; // BWF Sample count since midnight, low + unsigned bext_time_reference_high; // BWF Sample count since midnight, high + unsigned short bext_version; // BWF Version of the BWF + unsigned char bext_umid[64]; // BWF SMPTE UMD + QString bext_coding_history; // BWF Coding History + unsigned char bext_chunk_data[BEXT_CHUNK_SIZE]; + unsigned char *bext_coding_data; + unsigned bext_coding_size; + + bool mext_chunk; // Does the chunk exist? + bool mext_homogenous; // Is the data homogenous? + bool mext_padding_used; // Is the padding bit used? + bool mext_rate_hacked; // Is padding not used for a 22 or 44 sr? + bool mext_free_format; // Is it free format? + int mext_frame_size; // Size of MPEG frame, n/c padding + int mext_anc_length; // Ancillary data length + bool mext_left_energy; // Does anc data contain left/mono energy + bool mext_right_energy; // Does anc data contain right energy? + bool mext_ancillary_private; // Does anc data contain private data? + unsigned char mext_chunk_data[MEXT_CHUNK_SIZE]; + bool has_energy; // Can we produce energy data? + + unsigned char levl_chunk_data[LEVL_CHUNK_SIZE]; + unsigned levl_size; // Size of LEVL chunk + bool levl_chunk; // Does LEVL chunk exist? + int levl_version; // Version + int levl_format; // Peak Data Format + int levl_points; // Points per Peak + int levl_block_size; // Frames per Peak Value + int levl_channels; // Channels + unsigned levl_frames; // Total Peaks + unsigned levl_peak_offset; // Pointer to peak-of-peaks + unsigned short levl_peak_value; // Value of peak-of-peaks + unsigned levl_block_offset; // Offset to start of peaks + QDateTime levl_timestamp; // Timestamp + unsigned short levl_block_ptr; + unsigned levl_istate; + short levl_accum; + + QString cutString(char *,unsigned,unsigned); + QDate cutDate(char *,unsigned); + QTime cutTime(char *,unsigned); + vector<unsigned short> energy_data; + bool energy_loaded; + unsigned energy_ptr; + int wave_id; + RDWaveFile::Type wave_type; + + unsigned char *cook_buffer; + int cook_buffer_size; + RDWaveFile::Encoding cook_encoding; + float encode_quality; + int serial_number; + int atx_offset; + bool scot_chunk; + unsigned char scot_chunk_data[SCOT_CHUNK_SIZE]; + QString scot_title; + QString scot_artist; + QString scot_etc; + int scot_year; + QString scot_cut_number; + int scot_intro_length; + int scot_eom_length; + QDate scot_start_date; + QTime scot_start_time; + QDate scot_end_date; + QTime scot_end_time; + + bool AIR1_chunk; + unsigned char AIR1_chunk_data[AIR1_CHUNK_SIZE]; + + double normalize_level; + + bool av10_chunk; + unsigned char av10_chunk_data[AV10_CHUNK_SIZE]; + +#ifdef HAVE_VORBIS + OggVorbis_File vorbis_file; + vorbis_info vorbis_inf; + vorbis_block vorbis_blk; + vorbis_dsp_state vorbis_dsp; + ogg_stream_state ogg_stream; + ogg_page ogg_pg; + ogg_packet ogg_pack; +#endif // HAVE_VORBIS +}; + + +/* + * Cart Chunk Stuff + */ +#define CART_VERSION "0101" +#define CART_DEFAULT_END_YEAR 2099 +#define CART_DEFAULT_END_MONTH 12 +#define CART_DEFAULT_END_DAY 31 +#define CART_DEFAULT_END_HOUR 23 +#define CART_DEFAULT_END_MINUTE 59 +#define CART_DEFAULT_END_SECOND 59 +#define CART_DEFAULT_LEVEL_REF 0x8000 + + +/* + * BWF Stuff + */ +#define BWF_VERSION 1 + + +/* + * WAVE Format Categories + */ +#define WAVE_FORMAT_PCM 0x0001 +#define WAVE_FORMAT_IEEE_FLOAT 0x0003 +#define WAVE_FORMAT_MPEG 0x0050 + +/* + * OggVorbis/FLAC Formats + * + * FIXME: These are made up out of thin air -- if a real registered number + * exists, we should use that instead. + */ +#define WAVE_FORMAT_VORBIS 0xFFFF +#define WAVE_FORMAT_FLAC 0xFFFE + +/* + * Proprietary Format Categories + * (Not supported) + */ +#define MS_FORMAT_ADPCM 0x0002 +#define ITU_FORMAT_G711_ALAW 0x0006 +#define ITU_FORMAT_G711_MLAW 0x0007 +#define IMA_FORMAT_ADPCM 0x0011 +#define ITU_FORMAT_G723_ADPCM 0x0016 +#define GSM_FORMAT_610 0x0031 +#define ITU_FORMAT_G721_ADPCM 0x0040 +#define IBM_FORMAT_MULAW 0x0101 +#define IBM_FORMAT_ALAW 0x0102 +#define IBM_FORMAT_ADPCM 0x0103 + +/* + * MPEG Defines + * + * fwHeadLayer Flags + */ +#define ACM_MPEG_LAYER1 0x0001 +#define ACM_MPEG_LAYER2 0x0002 +#define ACM_MPEG_LAYER3 0x0004 + +/* + * fwHeadMode Flags + */ +#define ACM_MPEG_STEREO 0x0001 +#define ACM_MPEG_JOINTSTEREO 0x0002 +#define ACM_MPEG_DUALCHANNEL 0x0004 +#define ACM_MPEG_SINGLECHANNEL 0x0008 + +/* + * fwHeadFlags Flags + */ +#define ACM_MPEG_PRIVATEBIT 0x0001 +#define ACM_MPEG_COPYRIGHT 0x0002 +#define ACM_MPEG_ORIGINALHOME 0x0004 +#define ACM_MPEG_PROTECTIONBIT 0x0008 +#define ACM_MPEG_ID_MPEG1 0x0010 + + +#endif // RDWAVEFILE_H + diff --git a/lib/rdwavepainter.cpp b/lib/rdwavepainter.cpp new file mode 100644 index 00000000..cf32222b --- /dev/null +++ b/lib/rdwavepainter.cpp @@ -0,0 +1,245 @@ +// rdwavepainter.cpp +// +// A Painter Class for Drawing Audio Waveforms +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdwavepainter.cpp,v 1.13.4.2 2013/11/13 23:36:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <math.h> + +#include <qpointarray.h> +#include <qpixmap.h> +#include <qfile.h> +#include <qmessagebox.h> +#include <qobject.h> + +#include <rdwavepainter.h> + + +RDWavePainter::RDWavePainter(const QPaintDevice *pd,RDCut *cut, + RDStation *station,RDUser *user,RDConfig *config) + : QPainter(pd) +{ + wave_cut=cut; + wave_station=station; + wave_user=user; + wave_config=config; + wave_peaks=NULL; + LoadWave(); +} + + +RDWavePainter::RDWavePainter(RDStation *station,RDUser *user,RDConfig *config) +{ + wave_cut=NULL; + wave_station=station; + wave_user=user; + wave_config=config; + wave_peaks=NULL; +} + + +RDWavePainter::~RDWavePainter() +{ + if(wave_peaks!=NULL) { + delete wave_peaks; + } +} + + +void RDWavePainter::nameWave(RDCut *cut) +{ + wave_cut=cut; + LoadWave(); +} + + +bool RDWavePainter::begin(const QPaintDevice *pd,RDCut *cut) +{ + wave_cut=cut; + LoadWave(); + return QPainter::begin(pd); +} + + +bool RDWavePainter::begin(const QPaintDevice *pd) +{ + return QPainter::begin(pd); +} + + +void RDWavePainter::drawWaveBySamples(int x,int w,int startsamp,int endsamp, + int gain,Channel channel, + const QColor &color, + int startclip,int endclip) +{ + int startblock=startsamp/1152; + int endblock=endsamp/1152; + int startclipblock=-1; + int endclipblock=-1; + + + if((startblock>(int)wave_peaks->energySize())||(wave_peaks->energySize()==0)) { + return; + } + if(startclip>=0) { + startclipblock=startclip/1152; + } + if(endclip>=0) { + endclipblock=endclip/1152; + } + + double time_scale=1.0; + double gain_scale=1.0; + int dx=0; + QPixmap *pix=(QPixmap *)device(); + int center=pix->height()/2; + RDWavePainter::Channel effective_channel=channel; + switch(channel) { + case RDWavePainter::Left: + case RDWavePainter::Right: + if(wave_channels==1) { + effective_channel=RDWavePainter::Mono; + } + break; + + default: + effective_channel=channel; + break; + } + save(); + resetXForm(); + setPen(color); + setBrush(color); + QPointArray array(w+2); + array.setPoint(0,0,center); + array.setPoint(w+1,w+1,center); + switch(effective_channel) { + case RDWavePainter::Left: + time_scale=(double)(endblock-startblock)/(double)w; + gain_scale=(double)(pix->height()/65536.0)* + pow(10.0,(double)gain/2000.0); + for(int i=0;i<w;i++) { + if(((dx=(2*((int)(time_scale*(double)i)+startblock)))< + (int)wave_peaks->energySize())&& + ((startclipblock<0)||(dx>(startclipblock*2)))&& + ((endclipblock<0)||(dx<(endclipblock*2)))) { + array.setPoint(i+1,i+1, + center+(int)(gain_scale*(double)wave_peaks->energy(dx))); + } + else { + array.setPoint(i+1,i+1,center); + } + } + break; + + case RDWavePainter::Right: + time_scale=(double)(endblock-startblock)/(double)w; + gain_scale=(double)(pix->height()/65536.0)* + pow(10.0,(double)gain/2000.0); + for(int i=0;i<w;i++) { + if(((dx=(1+2*((int)(time_scale*(double)i)+startblock)))< + (int)wave_peaks->energySize())&& + ((startclipblock<0)||(dx>(startclipblock*2)))&& + ((endclipblock<0)||(dx<(endclipblock*2)))) { + array.setPoint(i+1,i+1, + center+(int)(gain_scale*(double)wave_peaks->energy(dx))); + } + else { + array.setPoint(i+1,i+1,center); + } + } + break; + + case RDWavePainter::Mono: + switch(wave_channels) { + case 1: + time_scale=(double)(endblock-startblock)/(double)w; + gain_scale=(double)(pix->height()/65536.0)* + pow(10.0,(double)gain/2000.0); + for(int i=0;i<w;i++) { + if(((dx=((int)(time_scale*(double)i)+startblock))< + (int)wave_peaks->energySize())&& + ((startclipblock<0)||(dx>startclipblock))&& + ((endclipblock<0)||(dx<endclipblock))) { + array.setPoint(i+1,i+1, + center+(int)(gain_scale*(double)wave_peaks->energy(dx))); + } + else { + array.setPoint(i+1,i+1,center); + } + } + break; + + case 2: + time_scale=(double)(endblock-startblock)/(double)w; + gain_scale=(double)(pix->height()/65536.0)* + pow(10.0,(double)gain/2000.0); + for(int i=0;i<w;i++) { + if(((dx=(2*((int)(time_scale*(double)i)+startblock)))< + (int)wave_peaks->energySize())&& + ((startclipblock<0)||(dx>(startclipblock*2)))&& + ((endclipblock<0)||(dx<(endclipblock*2)))) { + array.setPoint(i+1,i+1, + center+(int)(gain_scale* + ((double)wave_peaks->energy(dx)+ + (double)wave_peaks->energy(dx+1))/2.0)); + } + else { + array.setPoint(i+1,i+1,center); + } + } + break; + } + break; + } + drawPolygon(array); + for(int i=0;i<(w+2);i++) { + array.setPoint(i,array.point(i).x(),2*center-array.point(i).y()); + } + drawPolygon(array); + restore(); +} + + +void RDWavePainter::drawWaveByMsecs(int x,int w,int startmsecs,int endmsecs, + int gain,Channel channel, + const QColor &color, + int startclip,int endclip) +{ + drawWaveBySamples(x,w, + (unsigned)((double)startmsecs*(double)wave_sample_rate/1000.0), + (unsigned)((double)endmsecs*(double)wave_sample_rate/1000.0), + gain,channel,color, + (int)((double)startclip*(double)wave_sample_rate/1000.0), + (int)((double)endclip*(double)wave_sample_rate/1000.0)); +} + + +void RDWavePainter::LoadWave() +{ + wave_sample_rate=wave_cut->sampleRate(); + wave_channels=wave_cut->channels(); + if(wave_peaks!=NULL) { + delete wave_peaks; + } + wave_peaks=new RDPeaksExport(wave_station,wave_config); + wave_peaks->setCartNumber(wave_cut->cartNumber()); + wave_peaks->setCutNumber(wave_cut->cutNumber()); + wave_peaks->runExport(wave_user->name(),wave_user->password()); +} diff --git a/lib/rdwavepainter.h b/lib/rdwavepainter.h new file mode 100644 index 00000000..f86848fe --- /dev/null +++ b/lib/rdwavepainter.h @@ -0,0 +1,64 @@ +// rdwavepainter.h +// +// A Painter Class for Drawing Audio Waveforms +// +// (C) Copyright 2002-2005 Fred Gleason <fredg@paravelsystems.com> +// +// $Id: rdwavepainter.h,v 1.10.6.1 2013/11/13 23:36:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDWAVEPAINTER_H +#define RDWAVEPAINTER_H + +#include <qpainter.h> + +#include <rdconfig.h> +#include <rdpeaksexport.h> +#include <rdstation.h> +#include <rduser.h> +#include <rdcut.h> + +class RDWavePainter : public QPainter +{ + public: + enum Channel {Mono=0,Left=1,Right=2}; + RDWavePainter(const QPaintDevice *pd,RDCut *cut,RDStation *station, + RDUser *user,RDConfig *config); + RDWavePainter(RDStation *station,RDUser *user,RDConfig *config); + ~RDWavePainter(); + void nameWave(RDCut *cut); + bool begin(const QPaintDevice *pd,RDCut *cut); + bool begin(const QPaintDevice *pd); + void drawWaveBySamples(int x,int w,int startsamp,int endsamp,int gain, + Channel channel,const QColor &color, + int startclip=-1,int endclip=-1); + void drawWaveByMsecs(int x,int w,int startmsecs,int endmsecs,int gain, + Channel channel,const QColor &color, + int startclip=-1,int endclip=-1); + + private: + void LoadWave(); + RDCut *wave_cut; + RDStation *wave_station; + RDUser *wave_user; + RDConfig *wave_config; + RDPeaksExport *wave_peaks; + unsigned wave_sample_rate; + unsigned wave_channels; +}; + + +#endif // RDWAVEPAINTER_H diff --git a/lib/rdweb.cpp b/lib/rdweb.cpp new file mode 100644 index 00000000..553292c8 --- /dev/null +++ b/lib/rdweb.cpp @@ -0,0 +1,1155 @@ +// rdweb.cpp +// +// Functions for interfacing with web components using the +// Common Gateway Interface (CGI) Standard +// +// (C) Copyright 1996-2007 Fred Gleason <fredg@paravelsystems.com> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <qdatetime.h> +#include <qstringlist.h> + +#include <rduser.h> +#include <rddb.h> +#include <rdconf.h> +#include <rdwebresult.h> + +#include <rdweb.h> + + +/* RDReadPost(char *cBuffer,int dSize) */ + +/* This function reads POST data (such as that submitted by an HTML form) into +the buffer pointed to by cBuffer. The size of the buffer is indicated by +dSize. + +RETURNS: Number of bytes read if the function is successful + -1 if an error is encountered. */ + +int RDReadPost(char *cBuffer,int dSize) + +{ + int dPostSize=0; + + if(strcasecmp(getenv("REQUEST_METHOD"),"POST")!=0) { /* No post data to receive! */ + return -1; + } + sscanf(getenv("CONTENT_LENGTH"),"%d",&dPostSize); + if(dPostSize>=dSize) { /* Data block too large! */ + return -1; + } + dPostSize++; + fgets(cBuffer,dPostSize,stdin); + return dPostSize; +} + + + +/* + * int RDPutPostString(char *sPost,char *sArg,char *sValue,int dMaxSize) + * + * This function changes the contents of the POST buffer pointed to by + * 'sPost'. If the entry pointed to by 'sArg' exists, it's value is + * replaced by the string pointed to by 'sValue'. If the entry doesn't + * exist, it is created. 'dMaxSize' is the maximum allowable size of 'sPost'. + * + * RETURNS: If successful, a pointer to the start of the updated value + * If unsuccessful, -1 + */ +int RDPutPostString(char *sPost,char *sArg,char *sValue,int dMaxSize) +{ + int dOrigin; /* Start of insert point */ + int dValue; /* Length of sValue */ + int i; /* General purpose counter */ + char sAccum[CGI_ACCUM_SIZE]; + + /* + * Does the argument already exist? + */ + dOrigin=RDFindPostString(sPost,sArg,sAccum,CGI_ACCUM_SIZE); + if(dOrigin<0) { + /* + * Create a new entry + * Will it fit? + */ + dOrigin=strlen(sPost); + if((dOrigin+strlen(sArg)+strlen(sValue)+2)>=(unsigned)dMaxSize) { + return -1; + } + /* + * Append to the end + */ + strcat(sPost,"&"); + strcat(sPost,sArg); + strcat(sPost,"="); + dOrigin=strlen(sPost); + strcat(sPost,sValue); + } + else { + /* + * The argument exists, so update it + */ + dValue=strlen(sValue); + if(RDBufferDiff(sPost,dOrigin,dValue-strlen(sAccum),dMaxSize)<0) { + return -1; + } + for(i=0;i<dValue;i++) { + sPost[dOrigin+i]=sValue[i]; + } + sPost[dOrigin+dValue]='&'; + } + return dOrigin; +} + + +/* + * int RDFindPostString(char *cBuffer,char *sSearch,char *sReturn, + * int dReturnSize) + * + * This function returns the argument value associated with field name + * pointed to by sSearch in the POST buffer cBuffer. The argument value + * is returned in the buffer pointed to by sReturn, of maximum size + * dReturnSize. + * + * RETURNS: Pointer to the start of the value, if successful + * -1 if the search is unsuccessful + */ + +int RDFindPostString(const char *cBuffer,const char *sSearch,char *sReturn,int dReturnSize) + +{ + int i=0,j=0; + int dMatch,dOrigin; + + while(cBuffer[i]!=0) { + j=0; + dMatch=0; + while(cBuffer[i]!='=' && cBuffer[i]!=0) { + if(cBuffer[i++]!=sSearch[j++]) dMatch=1; + } + if(dMatch==0 && cBuffer[i]=='=' && sSearch[j]==0) { /* Found it! */ + j=0; + i++; + dOrigin=i; + while(cBuffer[i]!='&' && cBuffer[i]!=0 && j<dReturnSize-1) { + sReturn[j++]=cBuffer[i++]; + } + sReturn[j]=0; + return dOrigin; + } + else { + while(cBuffer[i]!='&' && cBuffer[i]!=0) i++; + } + if(cBuffer[i]==0) { + sReturn[0]=0; + return -1; /* No match found! */ + } + else { /* advance to next field */ + i++; + } + } + sReturn[0]=0; + return -1; +} + + + + +/* + * int GetPostString(char *cBuffer,char *sSearch,char *sReturn, + * int dReturnSize) + * + * This function returns the argument value associated with field name + * pointed to by sSearch in the POST buffer cBuffer. The argument value + * is returned in the buffer pointed to by sReturn, of maximum size + * dReturnSize. The argument value is also processed to convert any + * CGI escape sequences back into normal characters. + * + * RETURNS: 0 if successful + * -1 if the search is unsuccessful + */ + +int RDGetPostString(const char *cBuffer,const char *sSearch, + char *sReturn,int dReturnSize) +{ + if(RDFindPostString(cBuffer,sSearch,sReturn,dReturnSize)<0) { + return -1; + } + RDDecodeString(sReturn); + return 0; +} + + + +/* + * int GetPostInt(char *cBuffer,char *sSearch,int *dReturn) + * + * This function returns the integer argument value associated with field name + * pointed to by sSearch in the POST buffer cBuffer. The argument value + * is returned in the integer variable pointed to by dReturn. + * + * RETURNS: 0 if successful + * -1 if the search is unsuccessful + */ + +int RDGetPostInt(const char *cBuffer,const char *sSearch,int *dReturn) +{ + char sAccum[256]; + + if(RDGetPostString(cBuffer,sSearch,sAccum,255)<0) { + return -1; + } + if(sscanf(sAccum,"%d",dReturn)!=1) { + return -1; + } + return 0; +} + + + + +int RDGetPostLongInt(const char *cBuffer,const char *sSearch,long int *dReturn) +{ + char sAccum[256]; + + if(RDGetPostString(cBuffer,sSearch,sAccum,255)<0) { + return -1; + } + if(sscanf(sAccum,"%ld",dReturn)!=1) { + return -1; + } + return 0; +} + + + + +/* + * int PurgePostString(char *sPost,char *sArg) + * + * This function removes the argument/value pair pointed to by 'sArg'. + * + * RETURNS: If successful, the new size of 'sPost' + * If unsuccessful, -1 + */ +int RDPurgePostString(char *sPost,char *sArg,int dMaxSize) +{ + char sAccum[CGI_ACCUM_SIZE]; + int dPointer; + + dPointer=RDFindPostString(sPost,sArg,sAccum,CGI_ACCUM_SIZE); + if(dPointer<0) { + return -1; + } + dPointer-=(strlen(sArg)+1); + RDBufferDiff(sPost,dPointer,-(strlen(sArg)+strlen(sAccum)+2),dMaxSize); + return strlen(sPost); +} + + + +/* + * int RDEncodeString(char *sString,int dMaxSize) + * + * This function processes the string pointed to by 'sString', replacing + * any spaces with + and escaping most punctuation characters in accordance + * with the Common Gateway Interface (CGI) standard + * + * RETURNS: If successful, the new size of 'sString' + * If unsuccessful, -1 + */ +int RDEncodeString(char *sString,int dMaxSize) +{ + int i; /* General Purpose Counter */ + char sAccum[4]; /* General String Buffer */ + + i=0; + while(sString[i]!=0) { + if(((sString[i]!=' ') && (sString[i]!='*') && (sString[i]!='-') && + (sString[i]!='_') && (sString[i]!='.')) && + ((sString[i]<'0') || + ((sString[i]>'9') && (sString[i]<'A')) || + ((sString[i]>'Z') && (sString[i]<'a')) || + (sString[i]>'z'))) { + if(RDBufferDiff(sString,i,2,dMaxSize)<0) { + return -1; + } + sprintf(sAccum,"%%%2x",sString[i]); + sString[i++]=sAccum[0]; + sString[i++]=sAccum[1]; + sString[i]=sAccum[2]; + } + if(sString[i]==' ') { + sString[i]='+'; + } + i++; + } + return strlen(sString); +} + + +/* + * int RDEncodeSQLString(char *sString,int dMaxSize) + * + * This function processes the string pointed to by 'sString', + * escaping the ' \ and " characters. + * + * RETURNS: If successful, the new size of 'sString' + * If unsuccessful, -1 + */ +int RDEncodeSQLString(char *sString,int dMaxSize) +{ + int i; /* General Purpose Counter */ + char sAccum[4]; /* General String Buffer */ + + i=0; + while(sString[i]!=0) { + if((sString[i]=='%')||(sString[i]==34)||(sString[i]==39)) { + if(RDBufferDiff(sString,i,2,dMaxSize)<0) { + return -1; + } + sprintf(sAccum,"%%%2x",sString[i]); + sString[i++]=sAccum[0]; + sString[i++]=sAccum[1]; + sString[i]=sAccum[2]; + } + i++; + } + return strlen(sString); +} + + + + +int RDDecodeString(char *sString) + +{ + int i=0,j=0,k; + char sAccum[4]; + + while(sString[i]!=0) { + switch(sString[i]) { + + case '+': + sString[j]=' '; + break; + + case '%': /* escape sequence */ + sAccum[0]=sString[++i]; + sAccum[1]=sString[++i]; + sAccum[2]=0; + sscanf(sAccum,"%x",&k); + sString[j]=(char)k; + break; + + default: + sString[j]=sString[i]; + break; + } + i++; + j++; + } + sString[j]=0; + return --j; +} + + + +/* + * RDPutPlaintext(char *sPost,int dMaxSize) + * + * This function appends a block of text consisting of the *decoded* values + * of all the POST values found in the buffer pointed to by 'sPost' into + * the buffer pointed to by 'sPost'. The block is enclosed by the HTML + * start and end comment sequence (<! ... -->). 'sPost' is of maximum size + * 'dMaxSize'. + * + * RETURNS: If successful, the new size of 'sPost'. + * If unsuccessful, -1. + */ +int RDPutPlaintext(char *sPost,int dMaxSize) +{ + int dOriginalsize=0,dPostsize=0; /* Current post buffer length */ + int i,j=0; /* General purpose counter */ + int iState=0; /* State Counter */ + char sAccum[CGI_ACCUM_SIZE]; /* General String Buffer */ + int dAccum; /* Length of sAccum */ + + /* + * Initialize some data structures + */ + dOriginalsize=strlen(sPost); + dPostsize=dOriginalsize; + + /* + * Append the start of comment sequence + */ + if((dPostsize+3)>=dMaxSize) { + return -1; + } + strcat(sPost,"&< "); + dPostsize+=3; + + /* + * Scan for value strings + */ + for(i=0;i<dOriginalsize+1;i++) { + switch(iState) { + + case 0: /* Looking for a start of value or comment */ + switch(sPost[i]) { + + case '=': /* Start of value */ + j=0; + sAccum[j]=0; + iState=1; + break; + + case '<': /* Start of comment sequence */ + iState=10; + break; + } + break; + + case 1: + switch(sPost[i]) { + + case '&': /* End of value string */ + sAccum[j++]=' '; + sAccum[j]=0; + RDDecodeString(sAccum); + dAccum=strlen(sAccum); + if(dAccum>=dMaxSize) { + return -1; + } + strcat(sPost,sAccum); + dPostsize+=dAccum; + iState=0; + break; + + default: /* Another character in value string */ + if((sPost[i]!='<') && (sPost[i]!='>')) { + sAccum[j++]=sPost[i]; + } + break; + } + case 10: /* Middle of a comment */ + switch(sPost[i]) { + case '>': /* End of comment */ + iState=0; + break; + } + break; + default: /* Parser error! */ + return -1; + break; + } + } + + /* + * Append the end of comment sequence + */ + if((dPostsize+1)>=dMaxSize) { + return -1; + } + strcat(sPost,">"); + dPostsize+=1; + + return dPostsize; +} + + + + +/* + * int RDPurgePlaintext(char *sPost,int dMaxSize) + * + * This function removes one or more plaintext blocks enclosed by HTML comment + * sequences (<! ... -->) from the buffer pointed to by 'sPost', of + * maximum size 'dMaxSize'. + * + * RETURNS: If successful, the new size of 'sPost'. + * If unsuccessful, -1 + */ +int RDPurgePlaintext(char *sPost,int dMaxSize) +{ + int i=0; /* General Purpose Counters */ + int dComments=0; /* Comment State Switch */ + int dStart=0; /* Comment Startpoint Pointer */ + + /* + * Scan for comment sequences + */ + while(sPost[i]!=0) { + if((sPost[i]=='<') && (dComments==0)) { /* Start of comment */ + dStart=i; + dComments=1; + } + if((sPost[i]=='>') && (dComments==1)) { /* End of comment */ + if(RDBufferDiff(sPost,dStart,dStart-i-1,dMaxSize)<0) { + return -1; + } + if(sPost[i]==0) { /* Ensure a proper exit if at end of string */ + i--; + } + } + i++; + } + + /* + * Clean up and exit nicely + */ + RDPruneAmp(sPost); + return strlen(sPost); +} + + + + +void RDCgiError(const char *str,int resp_code) +{ + /* The cgi header */ + printf("Content-type: text/html\n"); + printf("Status: %d\n",resp_code); + printf("\n"); + + /* The html header */ + printf("<html>\n"); + printf("<head>\n"); + printf("<title>"); + printf("CGI Internal Error %d",resp_code); + printf("\n"); + printf("\n"); + + /* The body of the message */ + printf("

Oops!


\n"); + printf("We seem to have encountered a problem! The system says:
\n"); + printf("
%d
%s

\n",resp_code,str); + + /* The html footer */ + printf("\n"); + exit(0); +} + + +#ifndef WIN32 +extern void RDXMLResult(const char *str,int resp_code, + RDAudioConvert::ErrorCode err) +{ + RDWebResult *we=new RDWebResult(str,resp_code,err); + + printf("Content-type: application/xml\n"); + printf("Status: %d\n",resp_code); + printf("\n"); + printf("%s",(const char *)we->xml()); + delete we; + + exit(0); +} +#endif // WIN32 + + +/* + * int BufferDiff(char sString,int dOrigin,int dDiff,int dMaxSize) + * + * This function adds (+ value) or deletes (- value) 'dDiff' characters + * from the string pointed to by 'sString' at the offset location pointed + * to by 'dOrigin'. 'dMaxSize' is the maximum allowable size of 'sString'. + * + * RETURNS: If successful, the new size of 'sString' + * If unsuccessful, -1 + */ +int RDBufferDiff(char *sString,int dOrigin,int dDiff,int dMaxSize) +{ + int dOldSize,dNewSize; + int i; + + /* + * Will it fit? + */ + dOldSize=strlen(sString); + if((dOldSize+dDiff)>=dMaxSize) { + return -1; + } + dNewSize=dOldSize+dDiff; + + /* + * Adding characters + */ + if(dDiff>0) { + for(i=dOldSize;i>dOrigin;i--) { + sString[i+dDiff]=sString[i]; + } + return dNewSize; + } + + /* + * No Change + */ + if(dDiff==0) { + return dNewSize; + } + + /* + * Deleting Characters + */ + if(dDiff<0) { + for(i=dOrigin;imaxlen) { + dest[j]=0; + return j; + } + dest[j]=0; + strcat(dest,"""); + i++; + j+=6; + } + else { + if((j+2)>maxlen) { + dest[j]=0; + return j; + } + dest[j++]=src[i++]; + } + } + dest[j]=0; + return j; +} + + +long int RDAuthenticateLogin(const QString &username,const QString &passwd, + const QHostAddress &addr) +{ + // + // Authenticate User + // + RDUser *user=new RDUser(username); + if(!user->exists()) { + delete user; + return -1; + } + if(!user->checkPassword(passwd,true)) { + delete user; + return -1; + } + delete user; + + // + // Create Session + // + time_t timeval; + timeval=time(&timeval); + srandom(timeval); + long int session=random(); + QString sql=QString().sprintf("insert into WEB_CONNECTIONS set \ + SESSION_ID=%ld,\ + LOGIN_NAME=\"%s\",\ + IP_ADDRESS=\"%s\",\ + TIME_STAMP=now()", + session, + (const char *)username, + (const char *)addr.toString()); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + + return session; +} + + +QString RDAuthenticateSession(long int session_id,const QHostAddress &addr) +{ + // + // Expire Stale Sessions + // + QDateTime current_datetime= + QDateTime(QDate::currentDate(),QTime::currentTime()); + QString sql=QString().sprintf("delete from WEB_CONNECTIONS \ + where TIME_STAMP<\"%s\"", + (const char *)current_datetime. + addSecs(-RD_WEB_SESSION_TIMEOUT). + toString("yyyy-MM-dd hh:mm:ss")); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + + // + // Check for Session + // + sql=QString().sprintf("select LOGIN_NAME,IP_ADDRESS from WEB_CONNECTIONS \ + where SESSION_ID=%ld", + session_id); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return QString(); + } + if(q->value(1).toString()!=addr.toString()) { + delete q; + return QString(); + } + QString name=q->value(0).toString(); + delete q; + + // + // Update Session + // + sql=QString().sprintf("update WEB_CONNECTIONS set TIME_STAMP=\"%s\" \ + where SESSION_ID=%ld", + (const char *)current_datetime. + toString("yyyy-MM-dd hh:mm:dd"), + session_id); + q=new RDSqlQuery(sql); + delete q; + + return name; +} + + +void RDLogoutSession(long int session_id,const QHostAddress &addr) +{ + QString sql=QString().sprintf("select IP_ADDRESS from WEB_CONNECTIONS \ + where SESSION_ID=%ld", + session_id); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return; + } + if(q->value(0).toString()!=addr.toString()) { + delete q; + return; + } + delete q; + sql=QString().sprintf("delete from WEB_CONNECTIONS where SESSION_ID=%ld", + session_id); + q=new RDSqlQuery(sql); + delete q; +} + + +bool RDParsePost(std::map *vars) +{ + std::map headers; + bool header=true; + FILE *f=NULL; + char *data=NULL; + ssize_t n=0; + QString sep; + QString name; + QString filename; + QString tempdir; + int fd=-1; + + // + // Initialize Temp Directory Path + // + if(getenv("TMPDIR")!=NULL) { + tempdir=getenv("TMPDIR"); + } + else { + tempdir="/tmp"; + } + tempdir+="/rivendellXXXXXX"; + + // + // Get message part separator + // + if(getenv("REQUEST_METHOD")==NULL) { + return false; + } + if(QString(getenv("REQUEST_METHOD")).lower()!="post") { + return false; + } + if((f=fdopen(0,"r"))==NULL) { + return false; + } + if((n=getline(&data,(size_t *)&n,f))<=0) { + return false; + } + sep=QString(data).stripWhiteSpace(); + + // + // Get message parts + // + while((n=getline(&data,(size_t *)&n,f))>0) { + if(QString(data).stripWhiteSpace().contains(sep)>0) { // End of part + if(fd>=0) { + ftruncate(fd,lseek(fd,0,SEEK_CUR)-2); // Remove extraneous final CR/LF + ::close(fd); + fd=-1; + } + name=""; + filename=""; + headers.clear(); + header=true; + continue; + } + if(header) { // Read header + if(QString(data).stripWhiteSpace().isEmpty()) { + if(!headers["content-disposition"].isNull()) { + QStringList fields; + fields=fields.split(";",headers["content-disposition"]); + if(fields.size()>0) { + if(fields[0].lower().stripWhiteSpace()=="form-data") { + for(unsigned i=1;i"+RDXmlEscape(value)+"\n"; +} + + +QString RDXmlField(const QString &tag,const char *value,const QString &attrs) +{ + return RDXmlField(tag,QString(value),attrs); +} + + +QString RDXmlField(const QString &tag,const int value,const QString &attrs) +{ + QString str=""; + + if(!attrs.isEmpty()) { + str=" "+attrs; + } + return QString("<")+tag+str+">"+QString().sprintf("%d",value)+"\n"; +} + + +QString RDXmlField(const QString &tag,const unsigned value,const QString &attrs) +{ + QString str=""; + + if(!attrs.isEmpty()) { + str=" "+attrs; + } + return QString("<")+tag+str+">"+QString().sprintf("%u",value)+"\n"; +} + + +QString RDXmlField(const QString &tag,const bool value,const QString &attrs) +{ + QString str=""; + + if(!attrs.isEmpty()) { + str=" "+attrs; + } + if(value) { + return QString("<")+tag+str+">true\n"; + } + return QString("<")+tag+str+">false\n"; +} + + +QString RDXmlField(const QString &tag,const QDateTime &value, + const QString &attrs) +{ + QString str=""; + + if(!attrs.isEmpty()) { + str=" "+attrs; + } + if(value.isValid()) { + return QString("<")+tag+str+">"+RDWebDateTime(value)+"\n"; + } + return RDXmlField(tag); +} + + +QString RDXmlField(const QString &tag,const QTime &value,const QString &attrs) +{ + QString str=""; + + if(!attrs.isEmpty()) { + str=" "+attrs; + } + if(value.isValid()&&(!value.isNull())) { + return QString("<")+tag+str+">"+value.toString("hh:mm:ss")+"\n"; + } + return RDXmlField(tag); +} + + +QString RDXmlField(const QString &tag) +{ + return QString("<")+tag+"/>\n"; +} + + +QString RDXmlEscape(const QString &str) +{ + /* + * Escape a string in accordance with XML-1.0 + */ + QString ret=str; + ret.replace("&","&"); + ret.replace("<","<"); + ret.replace(">",">"); + ret.replace("'","'"); + ret.replace("\"","""); + return ret; +} + + +QString RDXmlUnescape(const QString &str) +{ + /* + * Unescape a string in accordance with XML-1.0 + */ + QString ret=str; + ret.replace("&","&"); + ret.replace("<","<"); + ret.replace(">",">"); + ret.replace("'","'"); + ret.replace(""","\""); + return ret; +} + + +QString RDUrlEscape(const QString &str) +{ + /* + * Escape a string in accordance with RFC 2396 Section 2.4 + */ + QString ret=str; + + ret.replace("%","%25"); + ret.replace(" ","%20"); + ret.replace("<","%3C"); + ret.replace(">","%3E"); + ret.replace("#","%23"); + ret.replace("\"","%22"); + ret.replace("{","%7B"); + ret.replace("}","%7D"); + ret.replace("|","%7C"); + ret.replace("\\","%5C"); + ret.replace("^","%5E"); + ret.replace("[","%5B"); + ret.replace("]","%5D"); + ret.replace("~","%7E"); + + return ret; +} + + +QString RDUrlUnescape(const QString &str) +{ + /* + * Unescape a string in accordance with RFC 2396 Section 2.4 + */ + QString ret=""; + + for(unsigned i=0;i +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDWEB_H +#define RDWEB_H + +#include + +#include +#include +#include +#include + +#ifndef WIN32 +#include +#endif // WIN32 + +// +// Data Structure Sizes +// +#define CGI_ACCUM_SIZE 1024 +#define RD_WEB_SESSION_TIMEOUT 900 + +// +// Function Prototypes +// +extern int RDReadPost(char *,int); +extern int RDPutPostString(char *,char *,char *,int); +extern int RDFindPostString(const char *,const char *,char *,int); +extern int RDGetPostString(const char *,const char *,char *,int); +extern int RDGetPostInt(const char *,const char *,int *); +extern int RDGetPostLongInt(const char *,const char *,long int *); +extern int RDPurgePostString(const char *,const char *,int); +extern int RDEncodeString(char *,int); +extern int RDEncodeSQLString(char *,int); +extern int RDDecodeString(char *); +extern int RDPutPlaintext(char *,int); +extern int RDPurgePlaintext(char *,int); +extern void RDCgiError(const char *str,int resp_code=200); +#ifndef WIN32 +extern void RDXMLResult(const char *str,int resp_code, + RDAudioConvert::ErrorCode err=RDAudioConvert::ErrorOk); +#endif // WIN32 +extern int RDBufferDiff(char *,int,int,int); +extern void RDPruneAmp(char *); +extern int RDEscapeQuotes(const char *src,char *dest,int maxlen); +extern long int RDAuthenticateLogin(const QString &username, + const QString &passwd, + const QHostAddress &addr); +extern QString RDAuthenticateSession(long int session_id, + const QHostAddress &addr); +extern void RDLogoutSession(long int session_id,const QHostAddress &addr); +extern bool RDParsePost(std::map *vars); +extern QString RDXmlField(const QString &tag,const QString &value, + const QString &attrs=""); +extern QString RDXmlField(const QString &tag,const char *value, + const QString &attrs=""); +extern QString RDXmlField(const QString &tag,const int value, + const QString &attrs=""); +extern QString RDXmlField(const QString &tag,const unsigned value, + const QString &attrs=""); +extern QString RDXmlField(const QString &tag,const bool value, + const QString &attrs=""); +extern QString RDXmlField(const QString &tag,const QDateTime &value, + const QString &attrs=""); +extern QString RDXmlField(const QString &tag,const QTime &value, + const QString &attrs=""); +extern QString RDXmlField(const QString &tag); +extern QString RDXmlEscape(const QString &str); +extern QString RDXmlUnescape(const QString &str); +extern QString RDUrlEscape(const QString &str); +extern QString RDUrlUnescape(const QString &str); +extern QString RDWebDateTime(const QDateTime &datetime); +extern QDateTime RDGetWebDateTime(const QString &str); +extern QTime RDGetWebTime(const QString &str); +extern int RDGetWebMonth(const QString &str); + +#endif // RDWEB_H diff --git a/lib/rdwebresult.cpp b/lib/rdwebresult.cpp new file mode 100644 index 00000000..47a6584c --- /dev/null +++ b/lib/rdwebresult.cpp @@ -0,0 +1,156 @@ +// rdwebresult.cpp +// +// Container class for Rivendel Web Service result messages. +// +// (C) Copyright 2011 Fred Gleason +// +// $Id: rdwebresult.cpp,v 1.1 2011/12/23 23:07:00 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include + +#include + +RDWebResult::RDWebResult(const QString &str,int resp_code, + RDAudioConvert::ErrorCode conv_code) +{ + web_text=str; + web_response_code=resp_code; + web_converter_code=conv_code; +} + + +RDWebResult::RDWebResult() +{ + web_text="Unknown"; + web_response_code=0; + web_converter_code=RDAudioConvert::ErrorOk; +} + + +QString RDWebResult::text() const +{ + return web_text; +} + + +void RDWebResult::setText(const QString &str) +{ + web_text=str; +} + + +int RDWebResult::responseCode() const +{ + return web_response_code; +} + + +void RDWebResult::setResponseCode(int code) +{ + web_response_code=code; +} + + +RDAudioConvert::ErrorCode RDWebResult::converterErrorCode() const +{ + return web_converter_code; +} + + +void RDWebResult::setConverterErrorCode(RDAudioConvert::ErrorCode code) +{ + web_converter_code=code; +} + + +QString RDWebResult::xml() const +{ + QString ret=""; + + ret+="\r\n"; + ret+=QString().sprintf(" %d\r\n", + web_response_code); + ret+=" "+web_text+"\r\n"; + if(web_converter_code!=RDAudioConvert::ErrorOk) { + ret+=QString().sprintf(" %d\r\n", + web_converter_code); + } + ret+="\r\n"; + return ret; +} + + +bool RDWebResult::readXml(const QString &xml) +{ + // + // FIXME: This is totally ad-hoc, but should work until we settle on + // a proper XML parser. + // + QStringList list=list.split("\r\n",xml); + for(unsigned i=0;i=2) { + list2=list2.split(">",list2[1]); + if(list2.size()>=2) { + web_text=list2[1]; + } + } + } + if(list[i].contains("ResponseCode")) { + QStringList list2=list.split("<",list[i]); + if(list2.size()>=2) { + list2=list2.split(">",list2[1]); + if(list2.size()>=2) { + web_response_code=list2[1].toInt(); + } + } + } + if(list[i].contains("AudioConvertError")) { + QStringList list2=list.split("<",list[i]); + if(list2.size()>=2) { + list2=list2.split(">",list2[1]); + if(list2.size()>=2) { + web_converter_code=(RDAudioConvert::ErrorCode)list2[1].toInt(); + } + } + } + } + + return true; +} + + +bool RDWebResult::readXmlFromFile(const QString &filename) +{ + FILE *f=NULL; + char line[1024]; + QString xml=""; + + if((f=fopen(filename,"r"))==NULL) { + return false; + } + while(fgets(line,1024,f)!=NULL) { + xml+=line; + } + fclose(f); + return readXml(xml); +} diff --git a/lib/rdwebresult.h b/lib/rdwebresult.h new file mode 100644 index 00000000..0c15ad76 --- /dev/null +++ b/lib/rdwebresult.h @@ -0,0 +1,51 @@ +// rdwebresult.h +// +// Container class for Rivendel Web Service result messages. +// +// (C) Copyright 2011 Fred Gleason +// +// $Id: rdwebresult.h,v 1.1 2011/12/23 23:07:00 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#ifndef RDWEBRESULT_H +#define RDWEBRESULT_H + +class RDWebResult +{ + public: + RDWebResult(const QString &str,int resp_code, + RDAudioConvert::ErrorCode conv_code); + RDWebResult(); + QString text() const; + void setText(const QString &str); + int responseCode() const; + void setResponseCode(int code); + RDAudioConvert::ErrorCode converterErrorCode() const; + void setConverterErrorCode(RDAudioConvert::ErrorCode code); + QString xml() const; + bool readXml(const QString &xml); + bool readXmlFromFile(const QString &filename); + + private: + QString web_text; + int web_response_code; + RDAudioConvert::ErrorCode web_converter_code; +}; + + +#endif // RDWEBRESULT_H diff --git a/lib/rdwin32.cpp b/lib/rdwin32.cpp new file mode 100644 index 00000000..41062b14 --- /dev/null +++ b/lib/rdwin32.cpp @@ -0,0 +1,30 @@ +// rdwin32.cpp +// +// Missing POSIX functions for Win32 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rdwin32.cpp,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +int isblank(int c) +{ + if(c==' ') { + return 0; + } + return 1; +} diff --git a/lib/rdwin32.h b/lib/rdwin32.h new file mode 100644 index 00000000..e90ad3c2 --- /dev/null +++ b/lib/rdwin32.h @@ -0,0 +1,29 @@ +// rdwin32.h +// +// Missing POSIX functions for Win32 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rdwin32.h,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDWIN32_H +#define RDWIN32_H + +int isblank(int c); + +#endif // RDWIN32_H diff --git a/lib/rdxport_interface.h b/lib/rdxport_interface.h new file mode 100644 index 00000000..c2b66d31 --- /dev/null +++ b/lib/rdxport_interface.h @@ -0,0 +1,47 @@ +/* rdxport_interface.h + * + * Public Interface for the RDXport Service + * + * (C) Copyright 2010 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef RDXPORT_INTERFACE_H +#define RDXPORT_INTERFACE_H + +#define RDXPORT_COMMAND_EXPORT 1 +#define RDXPORT_COMMAND_IMPORT 2 +#define RDXPORT_COMMAND_DELETEAUDIO 3 +#define RDXPORT_COMMAND_LISTGROUPS 4 +#define RDXPORT_COMMAND_LISTGROUP 5 +#define RDXPORT_COMMAND_LISTCARTS 6 +#define RDXPORT_COMMAND_LISTCART 7 +#define RDXPORT_COMMAND_LISTCUT 8 +#define RDXPORT_COMMAND_LISTCUTS 9 +#define RDXPORT_COMMAND_ADDCUT 10 +#define RDXPORT_COMMAND_REMOVECUT 11 +#define RDXPORT_COMMAND_ADDCART 12 +#define RDXPORT_COMMAND_REMOVECART 13 +#define RDXPORT_COMMAND_EDITCART 14 +#define RDXPORT_COMMAND_EDITCUT 15 +#define RDXPORT_COMMAND_EXPORT_PEAKS 16 +#define RDXPORT_COMMAND_TRIMAUDIO 17 +#define RDXPORT_COMMAND_COPYAUDIO 18 +#define RDXPORT_COMMAND_AUDIOINFO 19 +#define RDXPORT_COMMAND_LISTLOGS 20 +#define RDXPORT_COMMAND_LISTSERVICES 21 +#define RDXPORT_COMMAND_LISTLOG 22 + +#endif // RDXPORT_INTERFACE_H diff --git a/lib/schedcartlist.cpp b/lib/schedcartlist.cpp new file mode 100644 index 00000000..bac2fbf7 --- /dev/null +++ b/lib/schedcartlist.cpp @@ -0,0 +1,179 @@ +// schedcartlist.cpp +// +// A class for handling carts to be used in scheduler +// +// Stefan Gabriel +// +// $Id: schedcartlist.cpp,v 1.4.8.1 2012/12/13 22:33:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + + +SchedCartList::SchedCartList(int listsize) +{ + cartnum=new unsigned[listsize]; + cartlen=new int[listsize]; + stackid=new int[listsize]; + artist=new QString[listsize]; + sched_codes=new QString[listsize]; + itemcounter=0; +} + +SchedCartList::~SchedCartList() +{ + delete []cartnum; + delete []cartlen; + delete []stackid; + delete []artist; + delete []sched_codes; +} + +void SchedCartList::insertItem(unsigned cartnumber,int cartlength,int stack_id,QString stack_artist,QString stack_schedcodes) +{ + cartnum[itemcounter]=cartnumber; + cartlen[itemcounter]=cartlength; + stackid[itemcounter]=stack_id; + artist[itemcounter]=stack_artist.lower().replace(" ",""); + sched_codes[itemcounter]=stack_schedcodes; + itemcounter++; +} + + +void SchedCartList::removeItem(int itemnumber) +{ + for(int i=itemnumber;i<(itemcounter-1);i++) + { + cartnum[i]=cartnum[i+1]; + cartlen[i]=cartlen[i+1]; + stackid[i]=stackid[i+1]; + artist[i]=artist[i+1]; + sched_codes[i]=sched_codes[i+1]; + } + itemcounter--; +} + +bool SchedCartList::removeIfCode(int itemnumber,QString test_code) +{ + QString test = test_code; + test+=" "; + test=test.left(11); + + if (sched_codes[itemnumber].find(test)!=-1) + { + for(int i=itemnumber;i<(itemcounter-1);i++) + { + cartnum[i]=cartnum[i+1]; + cartlen[i]=cartlen[i+1]; + stackid[i]=stackid[i+1]; + artist[i]=artist[i+1]; + sched_codes[i]=sched_codes[i+1]; + } + itemcounter--; + return true; + } + return false; +} + +bool SchedCartList::itemHasCode(int itemnumber,QString test_code) +{ + QString test=test_code; + test+=" "; + test=test.left(11); + + if (sched_codes[itemnumber].find(test)!=-1) + return true; + else + return false; +} + + +void SchedCartList::save(void) +{ + savecartnum=new unsigned[itemcounter]; + savecartlen=new int[itemcounter]; + savestackid=new int[itemcounter]; + saveartist=new QString[itemcounter]; + save_sched_codes=new QString[itemcounter]; + + saveitemcounter=itemcounter; + for(int i=0;i +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + + +#ifndef SCHEDCARTLIST_H +#define SCHEDCARTLIST_H + + +class SchedCartList +{ + public: + SchedCartList(int listsize); + ~SchedCartList(); + void insertItem(unsigned cartnumber,int cartlength,int stack_id,QString stack_artist,QString stack_schedcodes); + void removeItem(int itemnumber); + bool removeIfCode(int itemnumber,QString test_code); + bool itemHasCode(int itemnumber,QString test_code); + unsigned getItemCartnumber(int itemnumber); + int getItemCartlength(int itemnumber); + int getItemStackid(int itemnumber); + QString getItemArtist(int itemnumber); + QString getItemSchedCodes(int itemnumber); + int getNumberOfItems(void); + void save(void); + void restore(void); + + private: + int itemcounter; + int saveitemcounter; + unsigned* cartnum; + unsigned* savecartnum; + int* cartlen; + int* savecartlen; + int* stackid; + int* savestackid; + QString* saveartist; + QString* artist; + QString* sched_codes; + QString* save_sched_codes; +}; + + +#endif diff --git a/lib/schedruleslist.cpp b/lib/schedruleslist.cpp new file mode 100644 index 00000000..dc56043c --- /dev/null +++ b/lib/schedruleslist.cpp @@ -0,0 +1,168 @@ +// schedruleslist.cpp +// +// A class for handling the scheduling rules for rdlogmanager/edit clocks +// +// Stefan Gabriel +// +// $Id: schedruleslist.cpp,v 1.7.8.1 2012/12/13 22:33:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +SchedRulesList::SchedRulesList(QString clockname) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + sql=QString().sprintf("create table if not exists `%s_RULES` (\ + CODE varchar(10) not null primary key,\ + MAX_ROW int unsigned,\ + MIN_WAIT int unsigned,\ + NOT_AFTER varchar(10),\ + OR_AFTER varchar(10),\ + OR_AFTER_II varchar(10))",(const char*)clockname.replace(" ","_")); + + q=new RDSqlQuery(sql); + if(!q->isActive()) { + printf("SQL: %s\n",(const char *)sql); + printf("SQL Error: %s\n",(const char *)q->lastError().databaseText()); + } + delete q; + + sql=QString().sprintf("select CODE,DESCRIPTION from SCHED_CODES order by `CODE` asc"); + + q=new RDSqlQuery(sql); + + itemcounter=q->size(); + sched_code = new QString[itemcounter]; + max_row = new int[itemcounter]; + min_wait = new int[itemcounter]; + not_after = new QString[itemcounter]; + or_after = new QString[itemcounter]; + or_after_II = new QString[itemcounter]; + description = new QString[itemcounter]; + + for (int i=0; inext(); + sched_code[i] = q->value(0).toString(); + description[i] = q->value(1).toString(); + sql=QString().sprintf("select MAX_ROW,MIN_WAIT,NOT_AFTER,OR_AFTER,OR_AFTER_II from %s_RULES where CODE=\"%s\"", + (const char *)clockname.replace(" ","_"),(const char *)sched_code[i]); + q1=new RDSqlQuery(sql); + if(q1->first()) + { + max_row[i] = q1->value(0).toInt(); + min_wait[i] = q1->value(1).toInt(); + not_after[i] = q1->value(2).toString(); + or_after[i] = q1->value(3).toString(); + or_after_II[i] = q1->value(3).toString(); + } + else + { + max_row[i] = 1; + min_wait[i] = 0; + not_after[i] = ""; + or_after[i] = ""; + or_after_II[i] = ""; + } + delete q1; + } + delete q; +} + +SchedRulesList::~SchedRulesList() +{ + delete []sched_code; + delete []max_row; + delete []min_wait; + delete []not_after; + delete []or_after; + delete []or_after_II; + delete []description; +} + +void SchedRulesList::insertItem(int pos,int maxrow,int minwait,QString notafter,QString orafter,QString orafterii) +{ + max_row[pos] = maxrow; + min_wait[pos] = minwait; + not_after[pos] = notafter; + or_after[pos] = orafter; + or_after_II[pos] = orafterii; +} + +QString SchedRulesList::getItemSchedCode(int pos) +{ + return sched_code[pos]; +} + +int SchedRulesList::getItemMaxRow(int pos) +{ + return max_row[pos]; +} + +int SchedRulesList::getItemMinWait(int pos) +{ + return min_wait[pos]; +} + +QString SchedRulesList::getItemNotAfter(int pos) +{ + return not_after[pos]; +} + +QString SchedRulesList::getItemOrAfter(int pos) +{ + return or_after[pos]; +} + +QString SchedRulesList::getItemOrAfterII(int pos) +{ + return or_after_II[pos]; +} + +QString SchedRulesList::getItemDescription(int pos) +{ + return description[pos]; +} + +int SchedRulesList::getNumberOfItems(void) +{ + return itemcounter; +} + +void SchedRulesList::Save(QString clockname) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("delete from %s_RULES", + (const char *)clockname.replace(" ","_")); + q=new RDSqlQuery(sql); + delete q; + for (int i=0;i +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef SCHEDRULESLIST_H +#define SCHEDRULESLIST_H + + +#include + +class SchedRulesList +{ + public: + SchedRulesList(QString clockname); + ~SchedRulesList(); + void insertItem(int pos,int maxrow,int minwait,QString notafter,QString orafter,QString orafterii); + QString getItemSchedCode(int pos); + int getItemMaxRow(int pos); + int getItemMinWait(int pos); + int getNumberOfItems(void); + QString getItemNotAfter(int pos); + QString getItemOrAfter(int pos); + QString getItemOrAfterII(int pos); + QString getItemDescription(int pos); + void Save(QString clockname); + + + private: + int itemcounter; + QString* sched_code; + int* max_row; + int* min_wait; + QString* not_after; + QString* or_after; + QString* or_after_II; + QString* description; + +}; + + +#endif + diff --git a/make_slack.in b/make_slack.in new file mode 100755 index 00000000..c16af7cf --- /dev/null +++ b/make_slack.in @@ -0,0 +1,187 @@ +#!/bin/bash + +# make_slack +# +# Make a Slackware package. +# +# (C) Copyright 2006 Fred Gleason +# +# $Id: make_slack.in,v 1.15 2010/07/29 19:32:30 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation; +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, +# Boston, MA 02111-1307 USA +# + +# +# USAGE +# make_slack [] +# + +# +# Clean the build tree +# +BUILD_DIR=/var/tmp/rivendell-@VERSION@ +rm -rf $BUILD_DIR + +# +# Build the package tree +# +mkdir -p $BUILD_DIR@LOCAL_PREFIX@/bin +cp cae/.libs/caed $BUILD_DIR@LOCAL_PREFIX@/bin/ +chmod 4755 $BUILD_DIR@LOCAL_PREFIX@/bin/caed +cp ripcd/.libs/ripcd $BUILD_DIR@LOCAL_PREFIX@/bin/ +chmod 4755 $BUILD_DIR@LOCAL_PREFIX@/bin/ripcd +cp rdcatchd/.libs/rdcatchd $BUILD_DIR@LOCAL_PREFIX@/bin/ +chmod 4755 $BUILD_DIR@LOCAL_PREFIX@/bin/rdcatchd +cp rdadmin/.libs/rdadmin $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp rdairplay/.libs/rdairplay $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp rdpanel/.libs/rdpanel $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp rdcatch/.libs/rdcatch $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp utils/rdgen/rdgen $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp rdlibrary/.libs/rdlibrary $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp rdlogedit/.libs/rdlogedit $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp rdlogmanager/.libs/rdlogmanager $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp rdcastmanager/.libs/rdcastmanager $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp rdlogin/.libs/rdlogin $BUILD_DIR@LOCAL_PREFIX@/bin/ +mkdir -p /$BUILD_DIR@LOCAL_PREFIX@/lib +cp lib/.libs/librd-@VERSION@.so $BUILD_DIR@LOCAL_PREFIX@/lib/ +ln -s @LOCAL_PREFIX@/lib/librd-@VERSION@ $BUILD_DIR@LOCAL_PREFIX@/lib/librd.so +cp utils/rmlsend/.libs/rmlsend $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp utils/rdgpimon/.libs/rdgpimon $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp utils/rdfilewrite/.libs/rdfilewrite $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp utils/rdimport/.libs/rdimport $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp scripts/rd_audio_sync $BUILD_DIR@LOCAL_PREFIX@/bin/ +cp scripts/rd_config $BUILD_DIR@LOCAL_PREFIX@/bin/ +mkdir -p $BUILD_DIR@LOCAL_PREFIX@/sbin +cp utils/sas_shim/.libs/sas_shim $BUILD_DIR@LOCAL_PREFIX@/sbin/ +cp utils/rddbcheck/.libs/rddbcheck $BUILD_DIR@LOCAL_PREFIX@/sbin/ +mkdir -p $BUILD_DIR@libexecdir@ +cp web/rdfeed/.libs/rdfeed.xml $BUILD_DIR@libexecdir@/ +cp web/rdcastmanager/.libs/rdcastmanager.cgi $BUILD_DIR@libexecdir@/ +ln -s @libexecdir@/rdfeed.xml $BUILD_DIR@libexecdir@/rdfeed.mp3 +cp icons/greencheckmark.png $BUILD_DIR@libexecdir@/ +cp icons/redx.png $BUILD_DIR@libexecdir@/ +cp icons/greenball.png $BUILD_DIR@libexecdir@/ +cp icons/redball.png $BUILD_DIR@libexecdir@/ +cp icons/whiteball.png $BUILD_DIR@libexecdir@/ +mkdir -p $BUILD_DIR/etc/httpd/extra +cp conf/rd-bin.conf $BUILD_DIR/etc/httpd/extra/ +mkdir -p $BUILD_DIR@LOCAL_PREFIX@/share/srlabs +cp lib/librd_es.qm $BUILD_DIR@LOCAL_PREFIX@/share/srlabs/ +cp rdadmin/rdadmin_es.qm $BUILD_DIR@LOCAL_PREFIX@/share/srlabs/ +cp rdairplay/rdairplay_es.qm $BUILD_DIR@LOCAL_PREFIX@/share/srlabs/ +cp rdpanel/rdpanel_es.qm $BUILD_DIR@LOCAL_PREFIX@/share/srlabs/ +cp rdcatch/rdcatch_es.qm $BUILD_DIR@LOCAL_PREFIX@/share/srlabs/ +cp rdlibrary/rdlibrary_es.qm $BUILD_DIR@LOCAL_PREFIX@/share/srlabs/ +cp rdlogedit/rdlogedit_es.qm $BUILD_DIR@LOCAL_PREFIX@/share/srlabs/ +cp rdlogin/rdlogin_es.qm $BUILD_DIR@LOCAL_PREFIX@/share/srlabs/ +cp rdlogmanager/rdlogmanager_es.qm @LOCAL_PREFIX@/share/srlabs/ +cp utils/rdgpimon/rdgpimon_es.qm $BUILD_DIR@LOCAL_PREFIX@/share/srlabs/ +cp utils/rmlsend/rmlsend_es.qm $BUILD_DIR@LOCAL_PREFIX@/share/srlabs/ +mkdir -p $BUILD_DIR/etc/init.d +cp rivendell-suse $BUILD_DIR/etc/init.d/rivendell +mkdir -p $BUILD_DIR/usr/share/icons/hicolor/16x16/apps +cp icons/rivendell-16x16.xpm $BUILD_DIR/usr/share/icons/hicolor/16x16/apps/rivendell.xpm +mkdir -p $BUILD_DIR/usr/share/icons/hicolor/22x22/apps +cp icons/rivendell-22x22.xpm $BUILD_DIR/usr/share/icons/hicolor/22x22/apps/rivendell.xpm +mkdir -p $BUILD_DIR/usr/share/icons/hicolor/32x32/apps +cp icons/rivendell-32x32.xpm $BUILD_DIR/usr/share/icons/hicolor/32x32/apps/rivendell.xpm +mkdir -p $BUILD_DIR/usr/share/icons/hicolor/48x48/apps +cp icons/rivendell-48x48.xpm $BUILD_DIR/usr/share/icons/hicolor/48x48/apps/rivendell.xpm +mkdir -p $BUILD_DIR/usr/share/icons/hicolor/64x64/apps +cp icons/rivendell-64x64.xpm $BUILD_DIR/usr/share/icons/hicolor/64x64/apps/rivendell.xpm +mkdir -p $BUILD_DIR/usr/share/icons/hicolor/128x128/apps +cp icons/rivendell-128x128.xpm $BUILD_DIR/usr/share/icons/hicolor/128x128/apps/rivendell.xpm +mkdir -p $BUILD_DIR/usr/share/applications +cp xdg/rdadmin.desktop $BUILD_DIR/usr/share/applications/ +cp xdg/rdairplay.desktop $BUILD_DIR/usr/share/applications/ +cp xdg/rdpanel.desktop $BUILD_DIR/usr/share/applications/ +cp xdg/rdcatch.desktop $BUILD_DIR/usr/share/applications/ +cp xdg/rdgpimon.desktop $BUILD_DIR/usr/share/applications/ +cp xdg/rdlibrary.desktop $BUILD_DIR/usr/share/applications/ +cp xdg/rdlogedit.desktop $BUILD_DIR/usr/share/applications/ +cp xdg/rdlogmanager.desktop $BUILD_DIR/usr/share/applications/ +cp xdg/rmlsend.desktop $BUILD_DIR/usr/share/applications/ +mkdir -p $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp AUTHORS $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp ChangeLog $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp COPYING $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp INSTALL $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp NEWS $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp README $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp SupportedCards $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp ToDo $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp conf/rd.conf-sample $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp conf/rd.conf-complete-sample $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp conf/my.cnf-master $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp conf/my.cnf-standby $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/cae.sxw $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/catchd.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/colors $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/GPIO.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/ripc.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/SWITCHERS.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/JACK.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/ENCODERS.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/pam_rd.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/rml.sxw $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/audio_perms.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/audio_ports.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/cart.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/clipboard.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/cuts.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/decks.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/groups.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/log_format.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/logs.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/panels.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/rd_airplay.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/rd_library.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/rd_logedit.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/recordings.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/services.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/sources.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/svc_rec_format.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/stations.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/triggers.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/ttys.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/users.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/tables/version.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +mkdir -p $BUILD_DIR/var/run/rivendell +cp docs/implemented_macros.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp utils/sas_shim/rc.sas_shim $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/reports.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/NOW+NEXT.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/WIN32.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +cp docs/ALSA.txt $BUILD_DIR/usr/doc/rivendell-@VERSION@ +mkdir -p $BUILD_DIR/install +cp slack-desc $BUILD_DIR/install/ +cp slack_doinst.sh $BUILD_DIR/install/doinst.sh + +# +# Generate the package +# +SOURCE_DIR=`pwd` +cd $BUILD_DIR +makepkg --prepend --linkadd y --chown n rivendell.tgz +cd $SOURCE_DIR +cp $BUILD_DIR/rivendell.tgz ./rivendell-@VERSION@-i586-@RPM_RELEASE@.tgz + +# +# Clean up and exit +# +rm -r $BUILD_DIR + + +# End of make_slack diff --git a/pam_rd/Makefile.am b/pam_rd/Makefile.am new file mode 100644 index 00000000..ee786f79 --- /dev/null +++ b/pam_rd/Makefile.am @@ -0,0 +1,45 @@ +## automake.am +## +## Automake.am for rivendell/pam_rd +## +## by Federico Grau +## based on work by Fred Gleason and from +## libpam-ldap-178 +## +## $Id: Makefile.am,v 1.9.8.1 2012/11/29 01:37:35 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" -fPIC @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +inst_lib_LTLIBRARIES = pam_rd.la +inst_libdir=/@RD_LIB_PATH@/security +dist_pam_rd_la_SOURCES = pam_rd.cpp +pam_rd_la_LDFLAGS = -module -shared -Xlinker -x -avoid-version -export-dynamic +pam_rd_la_LIBADD = @LIB_RDLIBS@ -lpam @LIBVORBIS@ + +CLEANFILES = *~\ + *.qm\ + moc_* + +DISTCLEANFILES = Makefile.in diff --git a/pam_rd/pam_rd.cpp b/pam_rd/pam_rd.cpp new file mode 100644 index 00000000..407b665c --- /dev/null +++ b/pam_rd/pam_rd.cpp @@ -0,0 +1,330 @@ +// pam_rd.c : The PAM authentication module of Rivendell +// +// (C) Copyright 2006 Federico Grau +// +// $Id: pam_rd.cpp,v 1.10 2010/09/10 18:16:27 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// created 2006-06-16 grauf@rfa.org +// + +// ideas borrowed from: +// pam_permit.c from Linux-PAM +// by Andrew Morgan 1996/3/11 +// pam_deny.c from Linux-PAM +// by Andrew Morgan 1996/3/11 +// pam_mysql.c +// by James O'Kane and others +// pam_winbind.c +// by Andrew Bartlett 2002 and others +// Rivendell by Fred Gleason + +/* + * include and definitions + */ +#define PAM_SM_AUTH + +#include +/* note: _pam_macros.h is for _drop_reply() macros. This is specific to + * Linux-PAM and not generally distributed by Sun. */ +#include + +#include +#define SYSLOG_IDENT "pam_rd" +#define SYSLOG_FACILITY LOG_AUTHPRIV + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// The pam module name, this should be unique amongst pam modules. +#define MODULE_NAME SYSLOG_IDENT + + + +/* + * utility functions and related definitions + */ + +#define PAM_RD_DEBUG (1<<0) +#define PAM_RD_TRY_FIRST_PASS (1<<1) +#define PAM_RD_USE_FIRST_PASS (1<<2) +#define PAM_RD_KILL_RD_DAEMONS (1<<3) +#define PAM_RD_IGNORE_PASS (1<<4) +#define PAM_RD_FAIL_DEFAULT_USER (1<<5) + +/* utility function to parse module arguements and return an int with bits set + * to corresponding options */ +static int parse_args(int argc, const char **argv, char **tmp_user) +{ + int ctrl; + /* step through arguments */ + for (ctrl = 0; argc-- > 0; ++argv) { + /* generic options */ + if (!strcmp(*argv,"debug")) { + ctrl |= PAM_RD_DEBUG; + } + else if (!strcasecmp(*argv, "use_first_pass")) { + ctrl |= PAM_RD_USE_FIRST_PASS; + } + else if (!strcasecmp(*argv, "try_first_pass")) { + ctrl |= PAM_RD_TRY_FIRST_PASS; + } + /* pam_rd specific options */ + else if (!strcasecmp(*argv, "kill_rd_daemons")) { + /* kill any previously running rivendell daemons */ + ctrl |= PAM_RD_KILL_RD_DAEMONS; + } + else if (!strcasecmp(*argv, "ignore_pass")) { + /* log the user into rivendell, ignoring any password check. the + * idea is to "trust" the network logon credentials and ignore the + * rivendell credentials */ + ctrl |= PAM_RD_IGNORE_PASS; + } + else if (!strncasecmp(*argv, "fail_default_user=", 18)) { + /* the Rivendell user account is set to the the user specified by + * this option if there is a failure authenticating */ + *tmp_user = strdup(18+*argv); + if (*tmp_user != NULL) { +syslog(LOG_NOTICE, "DEBUG ... read fail_default_user|%s|", *tmp_user); + ctrl |= PAM_RD_FAIL_DEFAULT_USER; + } else { + syslog(LOG_ERR, + "parse_args(): invalid fail_default_user specified - ignored"); + } + } else { + syslog(LOG_ERR, "parse_args(): ignoring unknown option; %s", *argv); + } + } + return ctrl; +} + + +/* utility function to be used for PAM conversation callback */ +int converse(pam_handle_t *pamh, + int nargs, + struct pam_message **message, + struct pam_response **response) +{ + int retval; + struct pam_conv *conv; + + retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv); + if (retval == PAM_SUCCESS) { + retval = conv->conv(nargs, + (const struct pam_message **) message, + response, conv->appdata_ptr); + if ((retval != PAM_SUCCESS) && (retval != PAM_CONV_AGAIN)) + syslog(LOG_ERR, "conversation failure [%s]", + pam_strerror(pamh, retval)); + } else { + syslog(LOG_ERR, "couldn't obtain coversation function [%s]", + pam_strerror(pamh, retval)); + } + + return retval; /* propagate error status */ +} + + +/* utility function to setup PAM conversation callback */ +int ask_passwd(pam_handle_t *pamh, int pwtype) +{ + struct pam_message msg[1], *mesg[1]; + struct pam_response *resp = NULL; + int i = 0; + int retval; + + msg[i].msg = "Password: "; + msg[i].msg_style = PAM_PROMPT_ECHO_OFF; + mesg[i] = &msg[i]; + + retval = converse(pamh, ++i, mesg, &resp); + + if (retval != PAM_SUCCESS) { + if (resp != NULL) + _pam_drop_reply(resp,i); + return ((retval == PAM_CONV_AGAIN) + ? PAM_INCOMPLETE : PAM_AUTHINFO_UNAVAIL); + } + + /* we have a password so set AUTHTOK + */ + retval=pam_set_item(pamh, pwtype, resp->resp); + _pam_drop_reply(resp,i); + return retval; +} + + + + + + +/* PAM authentication management functions */ + +/* Performs the task of authenticating the user. */ +PAM_EXTERN int pam_sm_authenticate (pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + int retval; + int ctrl = 0; + const char *username=NULL; + char *password=NULL; + char *tmp_buf=NULL; // Temporary buffer to get default_username option. + char *fail_default_username=RD_USER_LOGIN_NAME; // Initialize default value. + RDConfig *login_config; + RDStation *login_station; + RDUser * login_user; + QSqlDatabase *login_db; + + openlog(SYSLOG_IDENT, LOG_CONS|LOG_PID, SYSLOG_FACILITY); + + /* parse arguments */ + ctrl = parse_args(argc, argv, &tmp_buf); + if (ctrl & PAM_RD_DEBUG) syslog(LOG_DEBUG, "pam_sm_authenticate called."); + if (ctrl & PAM_RD_DEBUG) { + syslog(LOG_DEBUG, "argument flags ctrl:%d (0x%x)", ctrl, ctrl); + } + if (ctrl & PAM_RD_FAIL_DEFAULT_USER) { + fail_default_username = tmp_buf; + } + + /* get username */ + retval = pam_get_user(pamh, &username, NULL); + if ((retval != PAM_SUCCESS) + || (username == NULL) + || (*username == '\0')) { + syslog(LOG_ERR, "get username returned error: %s", + pam_strerror(pamh, retval)); + return retval; + } + if (ctrl & PAM_RD_DEBUG) syslog(LOG_DEBUG, "got user:%s", username); + + if (ctrl & ~PAM_RD_IGNORE_PASS) { + /* get password */ + if ((ctrl & PAM_RD_TRY_FIRST_PASS) || (ctrl & PAM_RD_USE_FIRST_PASS)) { + retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &password); + } + + /* if no password yet, and not configured to only use the first + * password, then ask */ + if ((password == NULL) && (ctrl & ~PAM_RD_USE_FIRST_PASS)) { + retval = ask_passwd(pamh, PAM_AUTHTOK); + } + retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password); + + if (password == NULL) { + syslog(LOG_ERR, "Could not retrieve user's password"); + return PAM_AUTHINFO_UNAVAIL; + } + if (ctrl & PAM_RD_DEBUG) syslog(LOG_DEBUG, "got password"); + } + + /* Load configs */ + login_config=new RDConfig(); + login_config->load(); + + /* kill daemons if requested */ + if (ctrl & PAM_RD_KILL_RD_DAEMONS) { + if (ctrl & PAM_RD_DEBUG) syslog(LOG_DEBUG, "killing RD daemons"); + RDKillDaemons(); + } + + /* authenticate the user */ + login_station=new RDStation(login_config->stationName()); + + // Initialize QT application, without the gui. Much like the database + // connection, while not used here, it is used by underlying functions. + QApplication a(argc, (char **) argv, false); // FIXME: in QT4 there is a QCoreApplication object that could be used here better. + + // Open Database. + // NOTE: while the database connection is not used in this module/file + // directly, it is required by the underlying functions, ex: + // login_user->checkPassword() + login_db=QSqlDatabase::addDatabase(login_config->mysqlDriver()); + if(!login_db) { + syslog(LOG_ERR, QString().sprintf("Unable to load QSql driver: %s", + login_config->mysqlDriver().ascii())); + return PAM_AUTHINFO_UNAVAIL; + } + login_db->setDatabaseName(login_config->mysqlDbname()); + login_db->setUserName(login_config->mysqlUsername()); + login_db->setPassword(login_config->mysqlPassword()); + login_db->setHostName(login_config->mysqlHostname()); + if(!login_db->open()) { + syslog(LOG_ERR, "Unable to connet to mySQL server"); + login_db->removeDatabase(login_config->mysqlDbname()); + return PAM_AUTHINFO_UNAVAIL; + } + if (ctrl & PAM_RD_DEBUG) syslog(LOG_DEBUG, "connected to database"); + + login_user = new RDUser(username); + if (ctrl & PAM_RD_IGNORE_PASS) { + // Ignore password, simply check if corresponding user exists. + if (login_user->exists()) { + login_station->setDefaultName(username); + syslog(LOG_NOTICE, + "ignoring password. RD Default User set to: %s", username); + } else { + login_station->setDefaultName(fail_default_username); + syslog(LOG_NOTICE, + "ignoring password. RDUser not found, defaulting to: %s", + fail_default_username); + } + } else { + // Check password. + if ( login_user->checkPassword(QString(password), false) ) { + login_station->setDefaultName(username); + syslog(LOG_NOTICE, + "authenticated. RD Default User set to: %s", username); + } else { + login_station->setDefaultName(fail_default_username); + syslog(LOG_NOTICE, + "authentication failed. RDUser defaulting to: %s", + fail_default_username); + } + } + + /* cleanup */ + delete login_user; + login_db->removeDatabase(login_config->mysqlDbname()); + delete login_station; + delete login_config; + +syslog(LOG_NOTICE, "DEBUG ... end pam_rd"); + return PAM_SUCCESS; +} + +/* Performs setting of credentials (after the user is authenticated). In the + * case of Rivendell, the "credential" is registering with the database. */ +PAM_EXTERN +int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc + ,const char **argv) +{ + return PAM_SUCCESS; +} + diff --git a/rdadmin/Makefile.am b/rdadmin/Makefile.am new file mode 100644 index 00000000..3d96c481 --- /dev/null +++ b/rdadmin/Makefile.am @@ -0,0 +1,240 @@ +## automake.am +## +## Automake.am for rivendell/rdadmin +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.72.4.6 2013/03/09 00:21:11 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ +CWRAP = ../helpers/cwrap + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdadmin_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rdadmin_*.qm + +all: + @QT_BIN@/lupdate rdadmin.pro + @QT_BIN@/lrelease rdadmin.pro + +bin_PROGRAMS = rdadmin + +dist_rdadmin_SOURCES = add_aux_field.cpp add_aux_field.h\ + add_encoder.cpp add_encoder.h\ + add_feed.cpp add_feed.h\ + add_group.cpp add_group.h\ + add_hostvar.cpp add_hostvar.h\ + add_matrix.cpp add_matrix.h\ + add_replicator.cpp add_replicator.h\ + add_report.cpp add_report.h\ + add_schedcodes.cpp add_schedcodes.h\ + add_station.cpp add_station.h\ + add_svc.cpp add_svc.h\ + add_user.cpp add_user.h\ + autofill_carts.cpp autofill_carts.h\ + createdb.cpp createdb.h\ + edit_audios.cpp edit_audios.h\ + edit_aux_field.cpp edit_aux_field.h\ + edit_backup.cpp edit_backup.h\ + edit_cartslots.cpp edit_cartslots.h\ + edit_channelgpios.cpp edit_channelgpios.h\ + edit_decks.cpp edit_decks.h\ + edit_dropbox.cpp edit_dropbox.h\ + edit_encoder.cpp edit_encoder.h\ + edit_endpoint.cpp edit_endpoint.h\ + edit_feed.cpp edit_feed.h\ + edit_feed_perms.cpp edit_feed_perms.h\ + edit_gpi.cpp edit_gpi.h\ + edit_group.cpp edit_group.h\ + edit_hostvar.cpp edit_hostvar.h\ + edit_hotkeys.cpp edit_hotkeys.h\ + edit_jack.cpp edit_jack.h\ + edit_jack_client.cpp edit_jack_client.h\ + edit_livewiregpio.cpp edit_livewiregpio.h\ + edit_matrix.cpp edit_matrix.h\ + edit_node.cpp edit_node.h\ + edit_now_next.cpp edit_now_next.h\ + edit_nownextplugin.cpp edit_nownextplugin.h\ + edit_rdairplay.cpp edit_rdairplay.h\ + edit_rdlibrary.cpp edit_rdlibrary.h\ + edit_rdlogedit.cpp edit_rdlogedit.h\ + edit_rdpanel.cpp edit_rdpanel.h\ + edit_replicator.cpp edit_replicator.h\ + edit_report.cpp edit_report.h\ + edit_sas_resource.cpp edit_sas_resource.h\ + edit_schedcodes.cpp edit_schedcodes.h\ + edit_settings.cpp edit_settings.h\ + edit_station.cpp edit_station.h\ + edit_svc.cpp edit_svc.h\ + edit_svc_perms.cpp edit_svc_perms.h\ + edit_ttys.cpp edit_ttys.h\ + edit_user.cpp edit_user.h\ + edit_user_perms.cpp edit_user_perms.h\ + edit_vguest_resource.cpp edit_vguest_resource.h\ + globals.h\ + help_audios.cpp help_audios.h\ + importfields.cpp importfields.h\ + info_dialog.cpp info_dialog.h\ + list_aux_fields.cpp list_aux_fields.h\ + list_dropboxes.cpp list_dropboxes.h\ + list_encoders.cpp list_encoders.h\ + list_endpoints.cpp list_endpoints.h\ + list_feeds.cpp list_feeds.h\ + list_gpis.cpp list_gpis.h\ + list_groups.cpp list_groups.h\ + list_hostvars.cpp list_hostvars.h\ + list_livewiregpios.cpp list_livewiregpios.h\ + list_matrices.cpp list_matrices.h\ + list_nodes.cpp list_nodes.h\ + list_replicator_carts.cpp list_replicator_carts.h\ + list_replicators.cpp list_replicators.h\ + list_reports.cpp list_reports.h\ + list_sas_resources.cpp list_sas_resources.h\ + list_schedcodes.cpp list_schedcodes.h\ + list_stations.cpp list_stations.h\ + list_svcs.cpp list_svcs.h\ + list_users.cpp list_users.h\ + list_vguest_resources.cpp list_vguest_resources.h\ + login.cpp login.h\ + mysql_login.cpp mysql_login.h\ + opendb.cpp opendb.h\ + rdadmin.cpp rdadmin.h\ + rename_group.cpp rename_group.h\ + test_import.cpp test_import.h\ + view_adapters.cpp view_adapters.h\ + view_node_info.cpp view_node_info.h + +nodist_rdadmin_SOURCES = moc_add_aux_field.cpp\ + moc_add_encoder.cpp\ + moc_add_feed.cpp\ + moc_add_group.cpp\ + moc_add_hostvar.cpp\ + moc_add_matrix.cpp\ + moc_add_replicator.cpp\ + moc_add_report.cpp\ + moc_add_schedcodes.cpp\ + moc_add_station.cpp\ + moc_add_svc.cpp\ + moc_add_user.cpp\ + moc_autofill_carts.cpp\ + moc_edit_audios.cpp\ + moc_edit_aux_field.cpp\ + moc_edit_backup.cpp\ + moc_edit_cartslots.cpp\ + moc_edit_channelgpios.cpp\ + moc_edit_decks.cpp\ + moc_edit_dropbox.cpp\ + moc_edit_encoder.cpp\ + moc_edit_endpoint.cpp\ + moc_edit_feed.cpp\ + moc_edit_feed_perms.cpp\ + moc_edit_gpi.cpp\ + moc_edit_group.cpp\ + moc_edit_hostvar.cpp\ + moc_edit_hotkeys.cpp\ + moc_edit_jack.cpp\ + moc_edit_jack_client.cpp\ + moc_edit_livewiregpio.cpp\ + moc_edit_matrix.cpp\ + moc_edit_node.cpp\ + moc_edit_now_next.cpp\ + moc_edit_nownextplugin.cpp\ + moc_edit_rdairplay.cpp\ + moc_edit_rdlibrary.cpp\ + moc_edit_rdlogedit.cpp\ + moc_edit_rdpanel.cpp\ + moc_edit_replicator.cpp\ + moc_edit_report.cpp\ + moc_edit_sas_resource.cpp\ + moc_edit_schedcodes.cpp\ + moc_edit_settings.cpp\ + moc_edit_station.cpp\ + moc_edit_svc.cpp\ + moc_edit_svc_perms.cpp\ + moc_edit_ttys.cpp\ + moc_edit_user.cpp\ + moc_edit_user_perms.cpp\ + moc_edit_vguest_resource.cpp\ + moc_help_audios.cpp\ + moc_importfields.cpp\ + moc_info_dialog.cpp\ + moc_list_aux_fields.cpp\ + moc_list_dropboxes.cpp\ + moc_list_encoders.cpp\ + moc_list_endpoints.cpp\ + moc_list_feeds.cpp\ + moc_list_gpis.cpp\ + moc_list_groups.cpp\ + moc_list_hostvars.cpp\ + moc_list_livewiregpios.cpp\ + moc_list_matrices.cpp\ + moc_list_nodes.cpp\ + moc_list_replicator_carts.cpp\ + moc_list_replicators.cpp\ + moc_list_reports.cpp\ + moc_list_sas_resources.cpp\ + moc_list_schedcodes.cpp\ + moc_list_stations.cpp\ + moc_list_svcs.cpp\ + moc_list_users.cpp\ + moc_list_vguest_resources.cpp\ + moc_login.cpp\ + moc_mysql_login.cpp\ + moc_rdadmin.cpp\ + moc_rename_group.cpp\ + moc_test_import.cpp\ + moc_view_adapters.cpp\ + moc_view_node_info.cpp + +rdadmin_LDADD = @LIB_RDLIBS@ -lsamplerate @LIBVORBIS@ + +EXTRA_DIST = info_banner1.xpm\ + info_banner2.xpm\ + rdadmin.pro\ + rdadmin_cs.ts\ + rdadmin_de.ts\ + rdadmin_es.ts\ + rdadmin_fr.ts\ + rdadmin_nb.ts\ + rdadmin_nn.ts\ + rdadmin_pt_BR.ts\ + xpm_info_banner1.cpp\ + xpm_info_banner2.cpp + +CLEANFILES = *~\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/rdadmin/add_aux_field.cpp b/rdadmin/add_aux_field.cpp new file mode 100644 index 00000000..5a590a00 --- /dev/null +++ b/rdadmin/add_aux_field.cpp @@ -0,0 +1,178 @@ +// add_aux_field.cpp +// +// Add an Auxiliary Field for an RSS Feed +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: add_aux_field.cpp,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + + +AddAuxField::AddAuxField(unsigned feed_id,unsigned *field_id, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + add_feed_id=feed_id; + add_field_id=field_id; + setCaption(tr("Add Aux Field")); + + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Variable Name + // + add_varname_edit=new QLineEdit(this,"add_varname_edit"); + add_varname_edit->setGeometry(165,10,130,20); + add_varname_edit->setMaxLength(11); + QLabel *label= + new QLabel(add_varname_edit,tr("Variable Name: "), + this,"add_varname_label"); + label->setGeometry(10,13,105,20); + label->setFont(bold_font); + label->setAlignment(AlignRight); + label=new QLabel(add_varname_edit,tr("%AUX_"),this); + label->setGeometry(120,13,45,20); + label->setFont(font); + label->setAlignment(AlignRight); + label=new QLabel(add_varname_edit,tr("%"),this); + label->setGeometry(295,13,30,20); + label->setFont(font); + label->setAlignment(AlignLeft); + + + // + // Caption + // + add_caption_edit=new QLineEdit(this,"add_caption_edit"); + add_caption_edit->setGeometry(120,37,sizeHint().width()-130,20); + add_caption_edit->setMaxLength(64); + label=new QLabel(add_caption_edit,tr("Caption: "), + this,"add_caption_label"); + label->setGeometry(10,37,105,20); + label->setFont(bold_font); + label->setAlignment(AlignRight); + + // + // Ok Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +QSize AddAuxField::sizeHint() const +{ + return QSize(400,127); +} + + +QSizePolicy AddAuxField::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddAuxField::okData() +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select ID from AUX_METADATA \ + where (FEED_ID=%u)&&(VAR_NAME=\"%%AUX_%s%%\")", + add_feed_id,(const char *)add_varname_edit->text()); + q=new RDSqlQuery(sql); + if(q->first()) { + delete q; + QMessageBox::warning(this,tr("Name Exists"), + tr("That variable name already exists!")); + return; + } + delete q; + sql=QString().sprintf("insert into AUX_METADATA set VAR_NAME=\"%%AUX_%s%%\",\ + CAPTION=\"%s\",FEED_ID=%u", + (const char *)RDEscapeString(add_varname_edit->text()), + (const char *)RDEscapeString(add_caption_edit->text()), + add_feed_id); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("select ID from AUX_METADATA \ + where (FEED_ID=%u)&&(VAR_NAME=\"%%AUX_%s%%\")", + add_feed_id, + (const char *)RDEscapeString(add_varname_edit-> + text())); + q=new RDSqlQuery(sql); + if(q->first()) { + *add_field_id=q->value(0).toUInt(); + } + delete q; + + sql=QString().sprintf("select KEY_NAME from FEEDS where ID=%u",add_feed_id); + q=new RDSqlQuery(sql); + if(q->first()) { + QString keyname=q->value(0).toString(); + delete q; + keyname.replace(" ","_"); + sql=QString().sprintf("alter table %s_FIELDS add column AUX_%s char(255)", + (const char *)keyname, + (const char *)RDEscapeString(add_varname_edit-> + text())); + q=new RDSqlQuery(sql); + } + delete q; + + done(0); +} + + +void AddAuxField::cancelData() +{ + done(-1); +} diff --git a/rdadmin/add_aux_field.h b/rdadmin/add_aux_field.h new file mode 100644 index 00000000..91f0fba1 --- /dev/null +++ b/rdadmin/add_aux_field.h @@ -0,0 +1,56 @@ +// add_aux_field.h +// +// Add an Auxiliary Field for an RSS Feed +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: add_aux_field.h,v 1.3 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_AUX_FIELD_H +#define ADD_AUX_FIELD_H + +#include +#include +#include +#include +#include +#include + + +class AddAuxField : public QDialog +{ + Q_OBJECT + public: + AddAuxField(unsigned feed_id,unsigned *field_id, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *add_varname_edit; + QLineEdit *add_caption_edit; + unsigned add_feed_id; + unsigned *add_field_id; +}; + + +#endif // ADD_AUX_FIELD + diff --git a/rdadmin/add_encoder.cpp b/rdadmin/add_encoder.cpp new file mode 100644 index 00000000..75967cfe --- /dev/null +++ b/rdadmin/add_encoder.cpp @@ -0,0 +1,151 @@ +// add_encoder.cpp +// +// Add a Rivendell Service +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: add_encoder.cpp,v 1.3 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +AddEncoder::AddEncoder(QString *encname,const QString &stationname, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + encoder_name=encname; + encoder_stationname=stationname; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Add Encoder")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont user_font=QFont("Helvetica",12,QFont::Normal); + user_font.setPixelSize(12); + + // + // Encoder Name + // + encoder_name_edit=new QLineEdit(this,"encoder_name_edit"); + encoder_name_edit->setGeometry(145,11,sizeHint().width()-150,19); + encoder_name_edit->setMaxLength(32); + QLabel *label=new QLabel(encoder_name_edit,tr("&New Encoder Name:"), + this,"encoder_name_label"); + label->setGeometry(10,11,130,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +AddEncoder::~AddEncoder() +{ + delete encoder_name_edit; +} + + +QSize AddEncoder::sizeHint() const +{ + return QSize(250,124); +} + + +QSizePolicy AddEncoder::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddEncoder::okData() +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select NAME from ENCODERS \ + where (NAME=\"%s\")&&(STATION_NAME=\"%s\")", + (const char *)RDEscapeString(encoder_name_edit->text()), + (const char *)RDEscapeString(encoder_stationname)); + q=new RDSqlQuery(sql); + if(q->first()) { + QMessageBox::warning(this,tr("Add Encoder Error"), + tr("A encoder with that name already exists!")); + delete q; + return; + } + delete q; + + // + // Create Encoder + // + sql=QString().sprintf("insert into ENCODERS set NAME=\"%s\",\ + STATION_NAME=\"%s\"", + (const char *)RDEscapeString(encoder_name_edit->text()), + (const char *)RDEscapeString(encoder_stationname)); + q=new RDSqlQuery(sql); + delete q; + *encoder_name=encoder_name_edit->text(); + + done(0); +} + + +void AddEncoder::cancelData() +{ + done(-1); +} diff --git a/rdadmin/add_encoder.h b/rdadmin/add_encoder.h new file mode 100644 index 00000000..2f3a8714 --- /dev/null +++ b/rdadmin/add_encoder.h @@ -0,0 +1,52 @@ +// add_encoder.h +// +// Add a Rivendell Encoder +// +// (C) Copyright 2008 Fred Gleason +// +// $Id: add_encoder.h,v 1.3 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_ENCODER_H +#define ADD_ENCODER_H + +#include +#include +#include + + +class AddEncoder : public QDialog +{ + Q_OBJECT + public: + AddEncoder(QString *encname,const QString &stationname, + QWidget *parent=0,const char *name=0); + ~AddEncoder(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *encoder_name_edit; + QString *encoder_name; + QString encoder_stationname; +}; + + +#endif // ADD_ENCODER_H diff --git a/rdadmin/add_feed.cpp b/rdadmin/add_feed.cpp new file mode 100644 index 00000000..a9031ac2 --- /dev/null +++ b/rdadmin/add_feed.cpp @@ -0,0 +1,203 @@ +// add_feed.cpp +// +// Add a Rivendell Service +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: add_feed.cpp,v 1.7 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +AddFeed::AddFeed(unsigned *id,QString *keyname,QWidget *parent, + const char *name) + : QDialog(parent,name,true) +{ + feed_keyname=keyname; + feed_id=id; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Add Feed")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont user_font=QFont("Helvetica",12,QFont::Normal); + user_font.setPixelSize(12); + + // + // Enable Users Checkbox + // + feed_users_box=new QCheckBox(this,"feed_users_box"); + feed_users_box->setGeometry(40,40,15,15); + feed_users_box->setChecked(true); + QLabel *label=new QLabel(feed_users_box,tr("Enable Feed for All Users"), + this,"feed_users_label"); + label->setGeometry(60,38,sizeHint().width()-60,19); + label->setFont(user_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Feed Name + // + feed_keyname_edit=new QLineEdit(this,"feed_keyname_edit"); + feed_keyname_edit->setGeometry(145,11,sizeHint().width()-150,19); + feed_keyname_edit->setMaxLength(8); + feed_keyname_edit->setValidator(validator); + label=new QLabel(feed_keyname_edit,tr("&New Feed Name:"), + this,"feed_name_label"); + label->setGeometry(10,11,130,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +AddFeed::~AddFeed() +{ + delete feed_keyname_edit; +} + + +QSize AddFeed::sizeHint() const +{ + return QSize(250,124); +} + + +QSizePolicy AddFeed::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddFeed::okData() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + sql=QString().sprintf("select KEY_NAME from FEEDS where KEY_NAME=\"%s\"", + (const char *)feed_keyname_edit->text()); + q=new RDSqlQuery(sql); + if(q->first()) { + QMessageBox::warning(this,tr("Add Feed Error"), + tr("A feed with that key name already exists!")); + delete q; + return; + } + delete q; + + // + // Create Default Feed Perms + // + if(feed_users_box->isChecked()) { + sql="select LOGIN_NAME from USERS \ + where (ADMIN_USERS_PRIV='N')&&(ADMIN_CONFIG_PRIV='N')"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into FEED_PERMS set USER_NAME=\"%s\",\ + KEY_NAME=\"%s\"", + (const char *)q->value(0).toString(), + (const char *)feed_keyname_edit->text()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + } + + // + // Create Feed + // + sql=QString().sprintf("insert into FEEDS set KEY_NAME=\"%s\",\ + ORIGIN_DATETIME=\"%s %s\",HEADER_XML=\"%s\",\ + CHANNEL_XML=\"%s\",ITEM_XML=\"%s\"", + (const char *)feed_keyname_edit->text(), + (const char *)QDate::currentDate(). + toString("yyyy-MM-dd"), + (const char *)QTime::currentTime(). + toString("hh:mm:ss"), + (const char *)RDEscapeString(DEFAULT_HEADER_XML), + (const char *)RDEscapeString(DEFAULT_CHANNEL_XML), + (const char *)RDEscapeString(DEFAULT_ITEM_XML)); + q=new RDSqlQuery(sql); + delete q; + RDCreateFeedLog(feed_keyname_edit->text()); + RDCreateAuxFieldsTable(feed_keyname_edit->text()); + sql=QString().sprintf("select ID from FEEDS where KEY_NAME=\"%s\"", + (const char *)feed_keyname_edit->text()); + q=new RDSqlQuery(sql); + if(q->first()) { + *feed_id=q->value(0).toUInt(); + } + delete q; + *feed_keyname=feed_keyname_edit->text(); + done(0); +} + + +void AddFeed::cancelData() +{ + done(-1); +} diff --git a/rdadmin/add_feed.h b/rdadmin/add_feed.h new file mode 100644 index 00000000..5c406822 --- /dev/null +++ b/rdadmin/add_feed.h @@ -0,0 +1,59 @@ +// add_feed.h +// +// Add a Rivendell Feed +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: add_feed.h,v 1.6 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_FEED_H +#define ADD_FEED_H + +#include +#include +#include + +// +// Default XML Templates +// +#define DEFAULT_HEADER_XML "\n" +#define DEFAULT_CHANNEL_XML "%TITLE%\n%DESCRIPTION%\n%CATEGORY%\n%LINK%\n%LANGUAGE%\n%COPYRIGHT%\n%BUILD_DATE%\n%PUBLISH_DATE%\n%WEBMASTER%\n%GENERATOR%" +#define DEFAULT_ITEM_XML "%ITEM_TITLE%\n%ITEM_LINK%\n%ITEM_GUID%\n%ITEM_DESCRIPTION%\n%ITEM_AUTHOR%\n%ITEM_COMMENTS%\n%ITEM_SOURCE_TEXT%\n\n%ITEM_CATEGORY%\n%ITEM_PUBLISH_DATE%" + + +class AddFeed : public QDialog +{ + Q_OBJECT + public: + AddFeed(unsigned *id,QString *keyname,QWidget *parent=0,const char *name=0); + ~AddFeed(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QCheckBox *feed_users_box; + QLineEdit *feed_keyname_edit; + QString *feed_keyname; + unsigned *feed_id; +}; + + +#endif // ADD_FEED_H diff --git a/rdadmin/add_group.cpp b/rdadmin/add_group.cpp new file mode 100644 index 00000000..ee7dc583 --- /dev/null +++ b/rdadmin/add_group.cpp @@ -0,0 +1,231 @@ +// add_group.cpp +// +// Add a Rivendell Service +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: add_group.cpp,v 1.20 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +AddGroup::AddGroup(QString *group,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + group_group=group; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Add Group")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont user_font=QFont("Helvetica",12,QFont::Normal); + user_font.setPixelSize(12); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Group Name + // + group_name_edit=new QLineEdit(this,"group_name_edit"); + group_name_edit->setGeometry(145,11,sizeHint().width()-150,19); + group_name_edit->setMaxLength(10); + group_name_edit->setValidator(validator); + QLabel *label=new QLabel(group_name_edit,tr("&New Group Name:"), + this,"group_name_label"); + label->setGeometry(10,11,130,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Enable Users Checkbox + // + group_users_box=new QCheckBox(this,"group_users_box"); + group_users_box->setGeometry(40,40,15,15); + group_users_box->setChecked(true); + label=new QLabel(group_users_box,tr("Enable Group for All Users"), + this,"group_users_label"); + label->setGeometry(60,38,sizeHint().width()-60,19); + label->setFont(user_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Enable Services Checkbox + // + group_svcs_box=new QCheckBox(this,"group_svcs_box"); + group_svcs_box->setGeometry(40,61,15,15); + group_svcs_box->setChecked(true); + label=new QLabel(group_svcs_box,tr("Enable Group for All Services"), + this,"group_svcs_label"); + label->setGeometry(60,58,sizeHint().width()-60,19); + label->setFont(user_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +AddGroup::~AddGroup() +{ + delete group_name_edit; +} + + +QSize AddGroup::sizeHint() const +{ + return QSize(250,152); +} + + +QSizePolicy AddGroup::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddGroup::okData() +{ + RDSqlQuery *q; + RDSqlQuery *q1; + QString sql; + + if(group_name_edit->text().isEmpty()) { + QMessageBox::warning(this,tr("Invalid Name"),tr("You must give the group a name!")); + return; + } + + sql=QString().sprintf("insert into GROUPS set NAME=\"%s\"", + (const char *)RDEscapeString(group_name_edit->text())); + + q=new RDSqlQuery(sql); + if(!q->isActive()) { + QMessageBox::warning(this,tr("Group Exists"),tr("Group Already Exists!"), + 1,0,0); + delete q; + return; + } + delete q; + + // + // Create Default Users Perms + // + if(group_users_box->isChecked()) { + sql="select LOGIN_NAME from USERS"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into USER_PERMS set USER_NAME=\"%s\",\ + GROUP_NAME=\"%s\"", + (const char *)q->value(0).toString(), + (const char *)RDEscapeString(group_name_edit->text())); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + } + + // + // Create Default Service Perms + // + if(group_svcs_box->isChecked()) { + sql="select NAME from SERVICES"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into AUDIO_PERMS set SERVICE_NAME=\"%s\",\ + GROUP_NAME=\"%s\"", + (const char *)q->value(0).toString(), + (const char *)RDEscapeString(group_name_edit->text())); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + } + + EditGroup *group=new EditGroup(group_name_edit->text(),this,"group"); + if(group->exec()<0) { + sql=QString().sprintf("delete from USER_PERMS where GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from AUDIO_PERMS where GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from GROUPS where NAME=\"%s\"", + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + delete group; + done(-1); + return; + } + delete group; + *group_group=group_name_edit->text(); + done(0); +} + + +void AddGroup::cancelData() +{ + done(-1); +} diff --git a/rdadmin/add_group.h b/rdadmin/add_group.h new file mode 100644 index 00000000..35d6be5f --- /dev/null +++ b/rdadmin/add_group.h @@ -0,0 +1,53 @@ +// add_group.h +// +// Add a Rivendell Group +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: add_group.h,v 1.8 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_GROUP_H +#define ADD_GROUP_H + +#include +#include +#include + + +class AddGroup : public QDialog +{ + Q_OBJECT + public: + AddGroup(QString *group,QWidget *parent=0,const char *name=0); + ~AddGroup(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *group_name_edit; + QCheckBox *group_users_box; + QCheckBox *group_svcs_box; + QString *group_group; +}; + + +#endif + diff --git a/rdadmin/add_hostvar.cpp b/rdadmin/add_hostvar.cpp new file mode 100644 index 00000000..70327241 --- /dev/null +++ b/rdadmin/add_hostvar.cpp @@ -0,0 +1,164 @@ +// add_hostvar.cpp +// +// Add a Rivendell Workstation Configuration +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: add_hostvar.cpp,v 1.9 2012/02/13 19:26:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +AddHostvar::AddHostvar(QString station,QString *var,QString *varvalue, + QString *remark,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + add_name=var; + add_varvalue=varvalue; + add_remark=remark; + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + setCaption(tr("Add Host Variable")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Variable Name + // + add_name_edit=new QLineEdit(this,"add_name_edit"); + add_name_edit->setGeometry(125,11,120,19); + add_name_edit->setMaxLength(32); + QLabel *label=new QLabel(add_name_edit,tr("Variable Name:"),this,"add_name_label"); + label->setGeometry(10,11,110,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Variable Value + // + add_varvalue_edit=new QLineEdit(this,"add_varvalue_edit"); + add_varvalue_edit->setGeometry(125,33,sizeHint().width()-135,19); + add_varvalue_edit->setMaxLength(255); + label=new QLabel(add_varvalue_edit,tr("Variable Value:"), + this,"add_varvalue_label"); + label->setGeometry(10,33,110,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Remark + // + add_remark_edit=new QLineEdit(this,"add_remark_edit"); + add_remark_edit->setGeometry(125,55,sizeHint().width()-135,19); + add_remark_edit->setMaxLength(255); + label=new QLabel(add_remark_edit,tr("Remark:"),this,"add_remark_label"); + label->setGeometry(10,55,110,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +AddHostvar::~AddHostvar() +{ +} + + +QSize AddHostvar::sizeHint() const +{ + return QSize(385,150); +} + + +QSizePolicy AddHostvar::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddHostvar::okData() +{ + if((add_name_edit->text().left(1)!=QString("%"))|| + (add_name_edit->text().right(1)!=QString("%"))|| + (add_name_edit->text().length()<3)) { + QMessageBox::warning(this,tr("Invalid Name"), + tr("The variable name is invalid.")); + return; + } + *add_name=add_name_edit->text(); + *add_varvalue=add_varvalue_edit->text(); + *add_remark=add_remark_edit->text(); + done(0); +} + + +void AddHostvar::cancelData() +{ + done(-1); +} diff --git a/rdadmin/add_hostvar.h b/rdadmin/add_hostvar.h new file mode 100644 index 00000000..0bfbba39 --- /dev/null +++ b/rdadmin/add_hostvar.h @@ -0,0 +1,65 @@ +// add_hostvar.h +// +// Add a Rivendell Host Variable +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: add_hostvar.h,v 1.6 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_HOSTVAR_H +#define ADD_HOSTVAR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +class AddHostvar : public QDialog +{ + Q_OBJECT + public: + AddHostvar(QString station,QString *var,QString *varvalue,QString *remark, + QWidget *parent=0,const char *name=0); + ~AddHostvar(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *add_name_edit; + QLineEdit *add_varvalue_edit; + QLineEdit *add_remark_edit; + QString *add_name; + QString *add_varvalue; + QString *add_remark; +}; + + +#endif + diff --git a/rdadmin/add_matrix.cpp b/rdadmin/add_matrix.cpp new file mode 100644 index 00000000..0defeb70 --- /dev/null +++ b/rdadmin/add_matrix.cpp @@ -0,0 +1,198 @@ +// +// Add a Rivendell Matrix +// +// (C) Copyright 2002-2012 Fred Gleason +// +// $Id: add_matrix.cpp,v 1.28.2.3 2014/02/17 02:19:02 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "edit_user.h" +#include "add_matrix.h" +#include "rdpasswd.h" + +AddMatrix::AddMatrix(QString station,QWidget *parent,const char *name) + : QDialog(parent,name) +{ + add_station=station; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("RDAdmin - Add Switcher")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Matrix Number + // + add_matrix_box=new QSpinBox(this,"add_matrix_box"); + add_matrix_box->setGeometry(165,11,30,19); + add_matrix_box->setRange(0,MAX_MATRICES-1); + QLabel *label=new QLabel(add_matrix_box,tr("&New Matrix Number:"),this, + "matrix_label"); + label->setGeometry(10,11,150,19); + label->setFont(font); + label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Matrix Type + // + add_type_box=new QComboBox(this,"add_type_box"); + add_type_box->setGeometry(165,36,200,19); + for(int i=0;iinsertItem(RDMatrix::typeString((RDMatrix::Type)i)); + } + label=new QLabel(add_type_box,tr("&Switcher Type:"),this, + "matrix_label"); + label->setGeometry(10,36,150,19); + label->setFont(font); + label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Assign Next Free Matrix + // + int n=GetNextMatrix(); + if(n>=0) { + add_matrix_box->setValue(n); + } +} + + +QSize AddMatrix::sizeHint() const +{ + return QSize(400,130); +} + + +QSizePolicy AddMatrix::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddMatrix::okData() +{ + QString sql=QString("select MATRIX from MATRICES where STATION_NAME=\"")+ + RDEscapeString(add_station)+"\" && MATRIX="+ + QString().sprintf("%d",add_matrix_box->value()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + delete q; + QMessageBox::warning(this,tr("Invalid Matrix"), + tr("Matrix already exists!")); + return; + } + delete q; + + sql=QString("insert into MATRICES set STATION_NAME=\"")+ + RDEscapeString(add_station)+"\","+ + "NAME=\""+tr("New Switcher")+"\","+ + "GPIO_DEVICE=\""+RD_DEFAULT_GPIO_DEVICE+"\","+ + QString(). + sprintf("MATRIX=%d,\ + PORT=0,\ + TYPE=%d,\ + INPUTS=%d,\ + OUTPUTS=%d,\ + GPIS=%d,\ + GPOS=%d,\ + PORT_TYPE=%d,\ + PORT_TYPE_2=%d", + add_matrix_box->value(), + add_type_box->currentItem(), + RDMatrix::defaultControlValue((RDMatrix::Type)add_type_box->currentItem(), + RDMatrix::InputsControl), + RDMatrix::defaultControlValue((RDMatrix::Type)add_type_box->currentItem(), + RDMatrix::OutputsControl), + RDMatrix::defaultControlValue((RDMatrix::Type)add_type_box->currentItem(), + RDMatrix::GpisControl), + RDMatrix::defaultControlValue((RDMatrix::Type)add_type_box->currentItem(), + RDMatrix::GposControl), + RDMatrix::defaultControlValue((RDMatrix::Type)add_type_box->currentItem(), + RDMatrix::PortTypeControl), + RDMatrix::NoPort); + q=new RDSqlQuery(sql); + delete q; + done(add_matrix_box->value()); +} + + +void AddMatrix::cancelData() +{ + done(-1); +} + + +int AddMatrix::GetNextMatrix() +{ + int n=0; + + QString sql=QString("select MATRIX from MATRICES where STATION_NAME=\"")+ + RDEscapeString(add_station)+"\" order by MATRIX"; + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + if(n!=q->value(0).toInt()) { + delete q; + return n; + } + n++; + } + delete q; + if(n +// +// $Id: add_matrix.h,v 1.6 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_MATRIX_H +#define ADD_MATRIX_H + +#include +#include +#include +#include + +#include + + +class AddMatrix : public QDialog +{ + Q_OBJECT + public: + AddMatrix(QString station,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + int GetNextMatrix(); + QComboBox *add_type_box; + QSpinBox *add_matrix_box; + QString add_station; +}; + + +#endif + diff --git a/rdadmin/add_replicator.cpp b/rdadmin/add_replicator.cpp new file mode 100644 index 00000000..6f7b9923 --- /dev/null +++ b/rdadmin/add_replicator.cpp @@ -0,0 +1,163 @@ +// add_replicator.cpp +// +// Add a Rivendell Replicator Configuration +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: add_replicator.cpp,v 1.2.8.1 2013/07/05 22:44:17 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +AddReplicator::AddReplicator(QString *rname,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + repl_name=rname; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Add Replicator")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont user_font=QFont("Helvetica",12,QFont::Normal); + user_font.setPixelSize(12); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Replicator Name + // + repl_name_edit=new QLineEdit(this,"repl_name_edit"); + repl_name_edit->setGeometry(145,11,sizeHint().width()-150,19); + repl_name_edit->setMaxLength(10); + repl_name_edit->setValidator(validator); + QLabel *label=new QLabel(repl_name_edit,tr("&New Replicator Name:"), + this,"repl_name_label"); + label->setGeometry(10,11,130,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +AddReplicator::~AddReplicator() +{ + delete repl_name_edit; +} + + +QSize AddReplicator::sizeHint() const +{ + return QSize(250,108); +} + + +QSizePolicy AddReplicator::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddReplicator::okData() +{ + RDSqlQuery *q; + QString sql; + + if(repl_name_edit->text().isEmpty()) { + QMessageBox::warning(this,tr("Invalid Name"),tr("You must give the replicator a name!")); + return; + } + + sql=QString().sprintf("insert into REPLICATORS set NAME=\"%s\"", + (const char *)repl_name_edit->text()); + + q=new RDSqlQuery(sql); + if(!q->isActive()) { + QMessageBox::warning(this,tr("Replicator Exists"),tr("A replicator with that name already exists!")); + delete q; + return; + } + delete q; + + EditReplicator *replicator=new EditReplicator(repl_name_edit->text(),this,"replicator"); + if(replicator->exec()<0) { + sql=QString().sprintf("delete from REPLICATORS where NAME=\"%s\"", + (const char *)repl_name_edit->text()); + q=new RDSqlQuery(sql); + delete q; + delete replicator; + done(-1); + return; + } + delete replicator; + *repl_name=repl_name_edit->text(); + done(0); +} + + +void AddReplicator::cancelData() +{ + done(-1); +} diff --git a/rdadmin/add_replicator.h b/rdadmin/add_replicator.h new file mode 100644 index 00000000..30a44618 --- /dev/null +++ b/rdadmin/add_replicator.h @@ -0,0 +1,51 @@ +// add_replicator.h +// +// Add a Rivendell Replicator +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: add_replicator.h,v 1.2 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_REPLICATOR_H +#define ADD_REPLICATOR_H + +#include +#include +#include + + +class AddReplicator : public QDialog +{ + Q_OBJECT + public: + AddReplicator(QString *rname,QWidget *parent=0,const char *name=0); + ~AddReplicator(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *repl_name_edit; + QString *repl_name; +}; + + +#endif + diff --git a/rdadmin/add_report.cpp b/rdadmin/add_report.cpp new file mode 100644 index 00000000..5691e300 --- /dev/null +++ b/rdadmin/add_report.cpp @@ -0,0 +1,152 @@ +// add_report.cpp +// +// Edit a Rivendell Report +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: add_report.cpp,v 1.9 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +AddReport::AddReport(QString *rptname,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Add Report")); + add_name=rptname; + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont section_font=QFont("Helvetica",14,QFont::Bold); + section_font.setPixelSize(14); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Report Description + // + add_name_edit=new QLineEdit(this,"add_name_edit"); + add_name_edit->setGeometry(170,10,sizeHint().width()-180,19); + add_name_edit->setMaxLength(64); + add_name_edit->setValidator(validator); + QLabel *label=new QLabel(add_name_edit,tr("&Report Name:"),this, + "add_name_label"); + label->setGeometry(10,10,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +QSize AddReport::sizeHint() const +{ + return QSize(500,104); +} + + +QSizePolicy AddReport::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddReport::okData() +{ + QString sql; + RDSqlQuery *q; + + if(add_name_edit->text().isEmpty()) { + QMessageBox::warning(this,tr("Invalid Name"), + tr("You must provide a report name!")); + return; + } + sql=QString().sprintf("select NAME from REPORTS where NAME=\"%s\"", + (const char *)add_name_edit->text()); + q=new RDSqlQuery(sql); + if(q->first()) { + QMessageBox::warning(this,tr("Report Exists"), + tr("A report with that name already exists!")); + delete q; + return; + } + delete q; + sql=QString().sprintf("insert into REPORTS set NAME=\"%s\"", + (const char *)add_name_edit->text()); + q=new RDSqlQuery(sql); + delete q; + *add_name=add_name_edit->text(); + done(0); +} + + +void AddReport::cancelData() +{ + done(-1); +} diff --git a/rdadmin/add_report.h b/rdadmin/add_report.h new file mode 100644 index 00000000..d8ad22d2 --- /dev/null +++ b/rdadmin/add_report.h @@ -0,0 +1,53 @@ +// add_report.h +// +// Add a Rivendell Report +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: add_report.h,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_REPORT_H +#define ADD_REPORT_H + +#include +#include +#include +#include + +#include + + +class AddReport : public QDialog +{ + Q_OBJECT + public: + AddReport(QString *rptname,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QString *add_name; + QLineEdit *add_name_edit; +}; + + +#endif + diff --git a/rdadmin/add_schedcodes.cpp b/rdadmin/add_schedcodes.cpp new file mode 100644 index 00000000..051974ab --- /dev/null +++ b/rdadmin/add_schedcodes.cpp @@ -0,0 +1,163 @@ +// add_schedcodes.cpp +// +// Add scheduler codes dialog +// +// Stefan Gabriel +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +AddSchedCode::AddSchedCode(QString *schedCode,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + schedCode_schedCode=schedCode; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Add Scheduler Code")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont user_font=QFont("Helvetica",12,QFont::Normal); + user_font.setPixelSize(12); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + validator->addBannedChar(' '); + + // + // Code Name + // + schedCode_name_edit=new QLineEdit(this,"schedCode_name_edit"); + schedCode_name_edit->setGeometry(105,11,sizeHint().width()-150,19); + schedCode_name_edit->setMaxLength(10); + schedCode_name_edit->setValidator(validator); + QLabel *label=new QLabel(schedCode_name_edit,tr("&New Code:"), + this,"schedCode_name_label"); + label->setGeometry(10,11,90,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +AddSchedCode::~AddSchedCode() +{ + delete schedCode_name_edit; +} + + +QSize AddSchedCode::sizeHint() const +{ + return QSize(250,120); +} + + +QSizePolicy AddSchedCode::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddSchedCode::okData() +{ + RDSqlQuery *q; + QString sql; + + if(schedCode_name_edit->text().isEmpty()) { + QMessageBox::warning(this,tr("Invalid Name"),tr("Invalid Name!")); + return; + } + + sql=QString().sprintf("insert into SCHED_CODES set CODE=\"%s\"", + (const char *)schedCode_name_edit->text()); + + q=new RDSqlQuery(sql); + if(!q->isActive()) { + QMessageBox::warning(this,tr("Code Exists"),tr("Code Already Exists!"), + 1,0,0); + delete q; + return; + } + delete q; + + EditSchedCode *schedCode=new EditSchedCode(schedCode_name_edit->text(),"", this,"group"); + if(schedCode->exec()<0) { + delete schedCode; + done(-1); + return; + } + delete schedCode; + *schedCode_schedCode=schedCode_name_edit->text(); + done(0); +} + + +void AddSchedCode::cancelData() +{ + done(-1); +} + diff --git a/rdadmin/add_schedcodes.h b/rdadmin/add_schedcodes.h new file mode 100644 index 00000000..1f0104ce --- /dev/null +++ b/rdadmin/add_schedcodes.h @@ -0,0 +1,48 @@ +// add_schedcodes.h +// +// Add scheduler codes dialog +// +// Stefan Gabriel +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_SCHEDCODES_H +#define ADD_SCHEDCODES_H + +#include +#include +#include + +class AddSchedCode : public QDialog +{ + Q_OBJECT + public: + AddSchedCode(QString *schedCode,QWidget *parent=0,const char *name=0); + ~AddSchedCode(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *schedCode_name_edit; + QString *schedCode_schedCode; +}; + +#endif // ADD_SCHEDCODES_H diff --git a/rdadmin/add_station.cpp b/rdadmin/add_station.cpp new file mode 100644 index 00000000..17473a80 --- /dev/null +++ b/rdadmin/add_station.cpp @@ -0,0 +1,951 @@ +// add_station.cpp +// +// Add a Rivendell Workstation +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: add_station.cpp,v 1.32.6.1 2013/03/09 00:21:11 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +AddStation::AddStation(QString *stationname,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + add_name=stationname; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Add Host")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Station Name + // + add_name_edit=new QLineEdit(this,"add_name_edit"); + add_name_edit->setGeometry(130,10,sizeHint().width()-140,19); + add_name_edit->setMaxLength(64); + add_name_edit->setValidator(validator); + QLabel *label=new QLabel(add_name_edit,tr("New &Host Name:"),this,"label"); + label->setGeometry(10,10,115,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Exemplar + // + add_exemplar_box=new QComboBox(this,"add_exemplar_box"); + add_exemplar_box->setGeometry(130,35,sizeHint().width()-140,19); + label=new QLabel(add_exemplar_box,tr("Base Host On:"),this,"label"); + label->setGeometry(10,35,115,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60, + 80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Fill Exemplar List + // + add_exemplar_box->insertItem(tr("Empty Host Config")); + QString sql="select NAME from STATIONS"; + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + add_exemplar_box->insertItem(q->value(0).toString()); + } + delete q; +} + + +AddStation::~AddStation() +{ + delete add_name_edit; +} + + +QSize AddStation::sizeHint() const +{ + return QSize(380,130); +} + + +QSizePolicy AddStation::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddStation::okData() +{ + RDSqlQuery *q; + RDSqlQuery *q1; + QString sql; + + if(add_name_edit->text().isEmpty()) { + QMessageBox::warning(this,tr("Invalid Name"), + tr("You must give the host a name!")); + return; + } + + if(add_exemplar_box->currentItem()==0) { // Create Blank Host Config + sql=QString().sprintf("insert into STATIONS set NAME=\"%s\",\ + DESCRIPTION=\"Workstation %s\",USER_NAME=\"user\",\ + DEFAULT_NAME=\"user\"", + (const char *)add_name_edit->text(), + (const char *)add_name_edit->text()); + q=new RDSqlQuery(sql); + if(!q->isActive()) { + QMessageBox::warning(this,tr("Host Exists"),tr("Host Already Exists!"), + 1,0,0); + delete q; + return; + } + delete q; + + // + // Create Service Perms + // + sql="select NAME from SERVICES"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into SERVICE_PERMS set\ + SERVICE_NAME=\"%s\",STATION_NAME=\"%s\"", + (const char *)q->value(0).toString(), + (const char *)add_name_edit->text()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // RDAirPlay/RDPanel Channel Data + // + for(unsigned i=0;i<10;i++) { + sql=QString("insert into RDAIRPLAY_CHANNELS set ")+ + "STATION_NAME=\""+RDEscapeString(add_name_edit->text())+"\","+ + QString().sprintf("INSTANCE=%u",i); + q=new RDSqlQuery(sql); + delete q; + + sql=QString("insert into RDPANEL_CHANNELS set ")+ + "STATION_NAME=\""+RDEscapeString(add_name_edit->text())+"\","+ + QString().sprintf("INSTANCE=%u",i); + q=new RDSqlQuery(sql); + delete q; + } + } + else { // Use Specified Config + + sql=QString().sprintf("select DEFAULT_NAME,STARTUP_CART,TIME_OFFSET,\ + BROADCAST_SECURITY,HEARTBEAT_CART,\ + HEARTBEAT_INTERVAL,EDITOR_PATH,FILTER_MODE,\ + SYSTEM_MAINT,HTTP_STATION,CAE_STATION from STATIONS\ + where NAME=\"%s\"", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("insert into STATIONS set NAME=\"%s\",\ + DESCRIPTION=\"Workstation %s\",\ + USER_NAME=\"%s\",\ + DEFAULT_NAME=\"%s\",\ + STARTUP_CART=%u,\ + TIME_OFFSET=%d,\ + BROADCAST_SECURITY=%u,\ + HEARTBEAT_CART=%u,\ + HEARTBEAT_INTERVAL=%u,\ + EDITOR_PATH=\"%s\",\ + FILTER_MODE=%d,\ + SYSTEM_MAINT=\"%s\",\ + HTTP_STATION=\"%s\",\ + CAE_STATION=\"%s\"", + (const char *)RDEscapeString(add_name_edit->text()), + (const char *)RDEscapeString(add_name_edit->text()), + (const char *)RDEscapeString(q->value(0). + toString()), + (const char *)RDEscapeString(q->value(0). + toString()), + q->value(1).toUInt(), + q->value(2).toInt(), + q->value(3).toUInt(), + q->value(4).toUInt(), + q->value(5).toUInt(), + (const char *)RDEscapeString(q->value(6). + toString()), + q->value(7).toInt(), + (const char *)q->value(8).toString(), + (const char *)RDEscapeString(q->value(9). + toString()), + (const char *)RDEscapeString(q->value(10). + toString())); + q1=new RDSqlQuery(sql); + if(!q1->isActive()) { + QMessageBox::warning(this,tr("Host Exists"),tr("Host Already Exists!"), + 1,0,0); + delete q1; + delete q; + return; + } + delete q1; + } + delete q; + + // + // Clone Service Perms + // + sql=QString().sprintf("select SERVICE_NAME from SERVICE_PERMS\ + where STATION_NAME=\"%s\"", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into SERVICE_PERMS set\ + STATION_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *)add_name_edit->text(), + (const char *)q->value(0).toString()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone RDLibrary Config + // + sql=QString().sprintf("select INPUT_CARD,INPUT_PORT,INPUT_TYPE,\ + OUTPUT_CARD,OUTPUT_PORT,VOX_THRESHOLD,\ + TRIM_THRESHOLD,DEFAULT_FORMAT,DEFAULT_CHANNELS,\ + DEFAULT_SAMPRATE,DEFAULT_LAYER,DEFAULT_BITRATE,\ + DEFAULT_RECORD_MODE,DEFAULT_TRIM_STATE,MAXLENGTH,\ + TAIL_PREROLL,RIPPER_DEVICE,PARANOIA_LEVEL,\ + RIPPER_LEVEL,CDDB_SERVER from RDLIBRARY\ + where (STATION=\"%s\")&&(INSTANCE=0)", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("insert into RDLIBRARY set\ + INPUT_CARD=%d,INPUT_PORT=%d,INPUT_TYPE=%d,\ + OUTPUT_CARD=%d,OUTPUT_PORT=%d,VOX_THRESHOLD=%d,\ + TRIM_THRESHOLD=%d,DEFAULT_FORMAT=%u,\ + DEFAULT_CHANNELS=%u,DEFAULT_SAMPRATE=%u,\ + DEFAULT_LAYER=%u,DEFAULT_BITRATE=%u,\ + DEFAULT_RECORD_MODE=%u,DEFAULT_TRIM_STATE=\"%s\",\ + MAXLENGTH=%d,TAIL_PREROLL=%u,\ + RIPPER_DEVICE=\"%s\",PARANOIA_LEVEL=%d,\ + RIPPER_LEVEL=%d,CDDB_SERVER=\"%s\",\ + STATION=\"%s\"", + q->value(0).toInt(), + q->value(1).toInt(), + q->value(2).toInt(), + q->value(3).toInt(), + q->value(4).toInt(), + q->value(5).toInt(), + q->value(6).toInt(), + q->value(7).toUInt(), + q->value(8).toUInt(), + q->value(9).toUInt(), + q->value(10).toUInt(), + q->value(11).toUInt(), + q->value(12).toUInt(), + (const char *)q->value(13).toString(), + q->value(14).toInt(), + q->value(15).toUInt(), + (const char *)q->value(16).toString(), + q->value(17).toInt(), + q->value(18).toInt(), + (const char *)q->value(19).toString(), + (const char *)add_name_edit->text()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone RDLogEdit Config + // + sql=QString().sprintf("select INPUT_CARD,INPUT_PORT,\ + OUTPUT_CARD,OUTPUT_PORT,\ + FORMAT,DEFAULT_CHANNELS,\ + SAMPRATE,LAYER,BITRATE,MAXLENGTH,\ + TAIL_PREROLL,START_CART,END_CART,\ + REC_START_CART,REC_END_CART,TRIM_THRESHOLD,\ + RIPPER_LEVEL,DEFAULT_TRANS_TYPE from RDLOGEDIT\ + where (STATION=\"%s\")", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("insert into RDLOGEDIT set\ + INPUT_CARD=%d,INPUT_PORT=%d,\ + OUTPUT_CARD=%d,OUTPUT_PORT=%d,\ + FORMAT=%u,\ + DEFAULT_CHANNELS=%u,SAMPRATE=%u,\ + LAYER=%u,BITRATE=%u,\ + MAXLENGTH=%d,TAIL_PREROLL=%u,\ + STATION=\"%s\",\ + START_CART=%u,\ + END_CART=%d,\ + REC_START_CART=%u,\ + REC_END_CART=%u,\ + TRIM_THRESHOLD=%d,\ + RIPPER_LEVEL=%d,\ + DEFAULT_TRANS_TYPE=%d", + q->value(0).toInt(), + q->value(1).toInt(), + q->value(2).toInt(), + q->value(3).toInt(), + q->value(4).toUInt(), + q->value(5).toUInt(), + q->value(6).toUInt(), + q->value(7).toUInt(), + q->value(8).toUInt(), + q->value(9).toInt(), + q->value(10).toUInt(), + (const char *)add_name_edit->text(), + q->value(11).toUInt(), + q->value(12).toUInt(), + q->value(13).toUInt(), + q->value(14).toUInt(), + q->value(15).toInt(), + q->value(16).toInt(), + q->value(17).toInt()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone RDCatch Config + // + sql=QString().sprintf("select CHANNEL,CARD_NUMBER,PORT_NUMBER,\ + MON_PORT_NUMBER,PORT_TYPE,DEFAULT_FORMAT,\ + DEFAULT_CHANNELS,DEFAULT_SAMPRATE,DEFAULT_BITRATE,\ + DEFAULT_THRESHOLD,DEFAULT_MONITOR_ON from DECKS\ + where STATION_NAME=\"%s\"", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("insert into DECKS set\ + CHANNEL=%u,CARD_NUMBER=%d,PORT_NUMBER=%d,\ + MON_PORT_NUMBER=%d,PORT_TYPE=\"%s\",\ + DEFAULT_FORMAT=%d,DEFAULT_CHANNELS=%d,\ + DEFAULT_SAMPRATE=%d,DEFAULT_BITRATE=%d,\ + DEFAULT_THRESHOLD=%d,STATION_NAME=\"%s\",\ + DEFAULT_MONITOR_ON=\"%s\"", + q->value(0).toUInt(), + q->value(1).toInt(), + q->value(2).toInt(), + q->value(3).toInt(), + (const char *)q->value(4).toString(), + q->value(5).toInt(), + q->value(6).toInt(), + q->value(7).toInt(), + q->value(8).toInt(), + q->value(9).toInt(), + (const char *)add_name_edit->text(), + (const char *)q->value(10).toString()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone RDAirPlay Config + // + sql=QString().sprintf("select SEGUE_LENGTH,\ + TRANS_LENGTH,OP_MODE,START_MODE,PIE_COUNT_LENGTH,\ + PIE_COUNT_ENDPOINT,CHECK_TIMESYNC,STATION_PANELS,\ + USER_PANELS,SHOW_AUX_1,SHOW_AUX_2,CLEAR_FILTER,\ + DEFAULT_TRANS_TYPE,BAR_ACTION,FLASH_PANEL,\ + PAUSE_ENABLED,UDP_ADDR0,UDP_PORT0,UDP_STRING0,\ + UDP_ADDR1,UDP_PORT1,UDP_STRING1,UDP_ADDR2,\ + UDP_PORT2,UDP_STRING2,DEFAULT_SERVICE,\ + LOG_RML0,LOG_RML1,LOG_RML2,\ + BUTTON_LABEL_TEMPLATE,EXIT_PASSWORD from RDAIRPLAY \ + where (STATION=\"%s\")", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("insert into RDAIRPLAY set\ + SEGUE_LENGTH=%d,TRANS_LENGTH=%d,OP_MODE=%d,\ + START_MODE=%d,PIE_COUNT_LENGTH=%d,\ + PIE_COUNT_ENDPOINT=%d,CHECK_TIMESYNC=\"%s\",\ + STATION_PANELS=%d,USER_PANELS=%d,\ + SHOW_AUX_1=\"%s\",SHOW_AUX_2=\"%s\",\ + CLEAR_FILTER=\"%s\",DEFAULT_TRANS_TYPE=%u,\ + BAR_ACTION=%u,FLASH_PANEL=\"%s\",\ + PAUSE_ENABLED=\"%s\",\ + UDP_ADDR0=\"%s\",UDP_PORT0=%u,UDP_STRING0=\"%s\",\ + UDP_ADDR1=\"%s\",UDP_PORT1=%u,UDP_STRING1=\"%s\",\ + UDP_ADDR2=\"%s\",UDP_PORT2=%u,UDP_STRING2=\"%s\",\ + STATION=\"%s\",DEFAULT_SERVICE=\"%s\",\ + LOG_RML0=\"%s\",\ + LOG_RML1=\"%s\",\ + LOG_RML2=\"%s\",\ + BUTTON_LABEL_TEMPLATE=\"%s\",\ + EXIT_PASSWORD=\"%s\"", + q->value(0).toInt(), + q->value(1).toInt(), + q->value(2).toInt(), + q->value(3).toInt(), + q->value(4).toInt(), + q->value(5).toInt(), + (const char *)q->value(6).toString(), + q->value(7).toInt(), + q->value(8).toInt(), + (const char *)q->value(9).toString(), + (const char *)q->value(10).toString(), + (const char *)q->value(11).toString(), + q->value(12).toUInt(), + q->value(13).toUInt(), + (const char *)q->value(14).toString(), + (const char *)q->value(15).toString(), + (const char *)q->value(16).toString(), + q->value(17).toUInt(), + (const char *)q->value(18).toString(), + (const char *)q->value(19).toString(), + q->value(20).toUInt(), + (const char *)q->value(21).toString(), + (const char *)q->value(22).toString(), + q->value(23).toUInt(), + (const char *)q->value(24).toString(), + (const char *)add_name_edit->text(), + (const char *)q->value(25).toString(), + (const char *)q->value(26).toString(), + (const char *)q->value(27).toString(), + (const char *)q->value(28).toString(), + (const char *)q->value(29).toString(), + (const char *)q->value(30).toString()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + sql=QString("select INSTANCE,CARD,PORT,START_RML,STOP_RML,")+ + "START_GPI_MATRIX,"+ + "START_GPI_LINE,START_GPO_MATRIX,START_GPO_LINE,STOP_GPI_MATRIX,"+ + "STOP_GPI_LINE,STOP_GPO_MATRIX,STOP_GPO_LINE from RDAIRPLAY_CHANNELS "+ + "where STATION_NAME=\""+RDEscapeString(add_exemplar_box->currentText())+ + "\""; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString("insert into RDAIRPLAY_CHANNELS set ")+ + "STATION_NAME=\""+RDEscapeString(add_name_edit->text())+"\","+ + QString().sprintf("INSTANCE=%u,",q->value(0).toUInt())+ + QString().sprintf("CARD=%d,",q->value(1).toInt())+ + QString().sprintf("PORT=%d,",q->value(2).toInt())+ + "START_RML=\""+RDEscapeString(q->value(3).toString())+"\","+ + "STOP_RML=\""+RDEscapeString(q->value(4).toString())+"\","+ + QString().sprintf("START_GPI_MATRIX=%d,",q->value(5).toInt())+ + QString().sprintf("START_GPI_LINE=%d,",q->value(6).toInt())+ + QString().sprintf("START_GPO_MATRIX=%d,",q->value(7).toInt())+ + QString().sprintf("START_GPO_LINE=%d,",q->value(8).toInt())+ + QString().sprintf("STOP_GPI_MATRIX=%d,",q->value(9).toInt())+ + QString().sprintf("STOP_GPI_LINE=%d,",q->value(10).toInt())+ + QString().sprintf("STOP_GPO_MATRIX=%d,",q->value(11).toInt())+ + QString().sprintf("STOP_GPO_LINE=%d",q->value(12).toInt()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone RDPanel Config + // + sql=QString().sprintf("select STATION_PANELS,\ + USER_PANELS,CLEAR_FILTER,\ + FLASH_PANEL,\ + DEFAULT_SERVICE,\ + BUTTON_LABEL_TEMPLATE from RDPANEL \ + where (STATION=\"%s\")", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("insert into RDPANEL set\ + STATION_PANELS=%d,\ + USER_PANELS=%d,\ + CLEAR_FILTER=\"%s\",\ + FLASH_PANEL=\"%s\",\ + STATION=\"%s\",\ + DEFAULT_SERVICE=\"%s\",\ + BUTTON_LABEL_TEMPLATE=\"%s\"", + q->value(0).toInt(), + q->value(1).toInt(), + (const char *)q->value(2).toString(), + (const char *)q->value(3).toString(), + (const char *)add_name_edit->text(), + (const char *)q->value(4).toString(), + (const char *)q->value(5).toString()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + sql=QString("select INSTANCE,CARD,PORT,START_RML,STOP_RML,")+ + "START_GPI_MATRIX,"+ + "START_GPI_LINE,START_GPO_MATRIX,START_GPO_LINE,STOP_GPI_MATRIX,"+ + "STOP_GPI_LINE,STOP_GPO_MATRIX,STOP_GPO_LINE from RDPANEL_CHANNELS "+ + "where STATION_NAME=\""+RDEscapeString(add_exemplar_box->currentText())+ + "\""; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString("insert into RDPANEL_CHANNELS set ")+ + "STATION_NAME=\""+RDEscapeString(add_name_edit->text())+"\","+ + QString().sprintf("INSTANCE=%u,",q->value(0).toUInt())+ + QString().sprintf("CARD=%d,",q->value(1).toInt())+ + QString().sprintf("PORT=%d,",q->value(2).toInt())+ + "START_RML=\""+RDEscapeString(q->value(3).toString())+"\","+ + "STOP_RML=\""+RDEscapeString(q->value(4).toString())+"\","+ + QString().sprintf("START_GPI_MATRIX=%d,",q->value(5).toInt())+ + QString().sprintf("START_GPI_LINE=%d,",q->value(6).toInt())+ + QString().sprintf("START_GPO_MATRIX=%d,",q->value(7).toInt())+ + QString().sprintf("START_GPO_LINE=%d,",q->value(8).toInt())+ + QString().sprintf("STOP_GPI_MATRIX=%d,",q->value(9).toInt())+ + QString().sprintf("STOP_GPI_LINE=%d,",q->value(10).toInt())+ + QString().sprintf("STOP_GPO_MATRIX=%d,",q->value(11).toInt())+ + QString().sprintf("STOP_GPO_LINE=%d",q->value(12).toInt()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone Audio Port Settings + // + sql="select CARD_NUMBER,CLOCK_SOURCE,"; + for(int i=0;icurrentText()); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into AUDIO_PORTS set\ + CARD_NUMBER=%u,CLOCK_SOURCE=%d,\ + STATION_NAME=\"%s\",", + q->value(0).toUInt(), + q->value(1).toInt(), + (const char *)add_name_edit->text()); + for(int i=0;ivalue(2+3*i).toInt(), + i,q->value(3+3*i).toInt(), + i,q->value(4+3*i).toInt(), + i,q->value(5+3*i).toInt()); + } + sql=sql.left(sql.length()-1); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone the Serial Setups + // + sql=QString().sprintf("select PORT_ID,ACTIVE,PORT,BAUD_RATE,DATA_BITS,\ + STOP_BITS,PARITY,TERMINATION from TTYS\ + where STATION_NAME=\"%s\"", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into TTYS set\ + PORT_ID=%u,ACTIVE=\"%s\",PORT=\"%s\",\ + BAUD_RATE=%d,DATA_BITS=%d,STOP_BITS=%d,\ + PARITY=%d,TERMINATION=%d,STATION_NAME=\"%s\"", + q->value(0).toUInt(), + (const char *)q->value(1).toString(), + (const char *)q->value(2).toString(), + q->value(3).toInt(), + q->value(4).toInt(), + q->value(5).toInt(), + q->value(6).toInt(), + q->value(7).toInt(), + (const char *)add_name_edit->text()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone Matrices + // + sql=QString().sprintf("select NAME,MATRIX,TYPE,PORT_TYPE,CARD,PORT,\ + IP_ADDRESS,IP_PORT,USERNAME,PASSWORD,GPIO_DEVICE,\ + INPUTS,OUTPUTS,GPIS,GPOS,DISPLAYS,FADERS,\ + PORT_TYPE_2,PORT_2,IP_ADDRESS_2,IP_PORT_2,\ + USERNAME_2,PASSWORD_2 \ + from MATRICES where STATION_NAME=\"%s\"", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into MATRICES set\ + NAME=\"%s\",MATRIX=%d,TYPE=%d,PORT_TYPE=%d,\ + CARD=%d,PORT=%d,IP_ADDRESS=\"%s\",IP_PORT=%d,\ + USERNAME=\"%s\",PASSWORD=\"%s\",\ + GPIO_DEVICE=\"%s\",INPUTS=%d,OUTPUTS=%d,GPIS=%d,\ + GPOS=%d,DISPLAYS=%d,STATION_NAME=\"%s\",\ + FADERS=%d,PORT_TYPE_2=%d,PORT_2=%d,\ + IP_ADDRESS_2=\"%s\",IP_PORT_2=%d,\ + USERNAME_2=\"%s\",PASSWORD_2=\"%s\"", + (const char *)q->value(0).toString(), + q->value(1).toInt(), + q->value(2).toInt(), + q->value(3).toInt(), + q->value(4).toInt(), + q->value(5).toInt(), + (const char *)q->value(6).toString(), + q->value(7).toInt(), + (const char *)q->value(8).toString(), + (const char *)q->value(9).toString(), + (const char *)q->value(10).toString(), + q->value(11).toInt(), + q->value(12).toInt(), + q->value(13).toInt(), + q->value(14).toInt(), + q->value(15).toInt(), + (const char *)add_name_edit->text(), + q->value(16).toInt(), + q->value(17).toInt(), + q->value(18).toInt(), + (const char *)q->value(19).toString(), + q->value(20).toInt(), + (const char *)q->value(21).toString(), + (const char *)q->value(22).toString()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone Matrix Inputs + // + sql=QString().sprintf("select MATRIX,NUMBER,NAME,FEED_NAME,CHANNEL_MODE,\ + ENGINE_NUM,DEVICE_NUM from INPUTS\ + where STATION_NAME=\"%s\"", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into INPUTS set\ + MATRIX=%d,NUMBER=%d,NAME=\"%s\",FEED_NAME=\"%s\",\ + CHANNEL_MODE=%d,ENGINE_NUM=%d,DEVICE_NUM=%d,\ + STATION_NAME=\"%s\"", + q->value(0).toInt(), + q->value(1).toInt(), + (const char *)q->value(2).toString(), + (const char *)q->value(3).toString(), + q->value(4).toInt(), + q->value(5).toInt(), + q->value(6).toInt(), + (const char *)add_name_edit->text()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone Matrix Outputs + // + sql=QString().sprintf("select MATRIX,NUMBER,NAME,\ + ENGINE_NUM,DEVICE_NUM from OUTPUTS\ + where STATION_NAME=\"%s\"", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into OUTPUTS set\ + MATRIX=%d,NUMBER=%d,NAME=\"%s\",\ + ENGINE_NUM=%d,DEVICE_NUM=%d,\ + STATION_NAME=\"%s\"", + q->value(0).toInt(), + q->value(1).toInt(), + (const char *)q->value(2).toString(), + q->value(3).toInt(), + q->value(4).toInt(), + (const char *)add_name_edit->text()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone GPIs + // + sql=QString().sprintf("select MATRIX,NUMBER,MACRO_CART from GPIS\ + where STATION_NAME=\"%s\"", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into GPIS set\ + MATRIX=%d,NUMBER=%d,MACRO_CART=%d,\ + STATION_NAME=\"%s\"", + q->value(0).toInt(), + q->value(1).toInt(), + q->value(2).toInt(), + (const char *)add_name_edit->text()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Close vGuest Settings + // + sql=QString().sprintf("select MATRIX_NUM,VGUEST_TYPE,NUMBER,ENGINE_NUM,\ + DEVICE_NUM,SURFACE_NUM,RELAY_NUM,BUSS_NUM\ + from VGUEST_RESOURCES where STATION_NAME=\"%s\"", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into VGUEST_RESOURCES set\ + MATRIX_NUM=%d,VGUEST_TYPE=%d,NUMBER=%d,\ + ENGINE_NUM=%d,DEVICE_NUM=%d,SURFACE_NUM=%d,\ + RELAY_NUM=%d,BUSS_NUM=%d,STATION_NAME=\"%s\"", + q->value(0).toInt(), + q->value(1).toInt(), + q->value(2).toInt(), + q->value(3).toInt(), + q->value(4).toInt(), + q->value(5).toInt(), + q->value(6).toInt(), + q->value(7).toInt(), + (const char *)add_name_edit->text()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone Host Variables + // + sql=QString().sprintf("select NAME,VARVALUE,REMARK from HOSTVARS\ + where STATION_NAME=\"%s\"", + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into HOSTVARS set\ + NAME=\"%s\",VARVALUE=\"%s\",REMARK=\"%s\",\ + STATION_NAME=\"%s\"", + (const char *)q->value(0).toString(), + (const char *)q->value(1).toString(), + (const char *)q->value(2).toString(), + (const char *)add_name_edit->text()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone System Panels + // + sql=QString().sprintf("select PANEL_NO,ROW_NO,COLUMN_NO,LABEL,CART,\ + DEFAULT_COLOR from PANELS where \ + (TYPE=%d && OWNER=\"%s\")", + RDAirPlayConf::StationPanel, + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into PANELS set PANEL_NO=%d,ROW_NO=%d,\ + COLUMN_NO=%d,LABEL=\"%s\",CART=%u,\ + DEFAULT_COLOR=\"%s\",TYPE=%d,OWNER=\"%s\"", + q->value(0).toInt(), + q->value(1).toInt(), + q->value(2).toInt(), + (const char *)q->value(3).toString(), + q->value(4).toUInt(), + (const char *)q->value(5).toString(), + RDAirPlayConf::StationPanel, + (const char *)add_name_edit->text()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + sql=QString().sprintf("select PANEL_NO,ROW_NO,COLUMN_NO,LABEL,CART,\ + DEFAULT_COLOR from EXTENDED_PANELS where \ + (TYPE=%d && OWNER=\"%s\")", + RDAirPlayConf::StationPanel, + (const char *)add_exemplar_box->currentText()); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into EXTENDED_PANELS set PANEL_NO=%d,\ + ROW_NO=%d,COLUMN_NO=%d,LABEL=\"%s\",CART=%u,\ + DEFAULT_COLOR=\"%s\",TYPE=%d,OWNER=\"%s\"", + q->value(0).toInt(), + q->value(1).toInt(), + q->value(2).toInt(), + (const char *)q->value(3).toString(), + q->value(4).toUInt(), + (const char *)q->value(5).toString(), + RDAirPlayConf::StationPanel, + (const char *)add_name_edit->text()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Clone Encoders + // + sql=QString().sprintf("select ID,NAME,COMMAND_LINE from ENCODERS \ + where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(add_exemplar_box-> + currentText())); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString(). + sprintf("insert into ENCODERS set NAME=\"%s\",\ + COMMAND_LINE=\"%s\",STATION_NAME=\"%s\"", + (const char *)RDEscapeString(q->value(1).toString()), + (const char *)RDEscapeString(q->value(2).toString()), + (const char *)RDEscapeString(add_name_edit->text())); + q1=new RDSqlQuery(sql); + delete q1; + sql=QString(). + sprintf("select ID from ENCODERS \ + where (NAME=\"%s\")&&(STATION_NAME=\"%s\")", + (const char *)RDEscapeString(q->value(1).toString()), + (const char *)RDEscapeString(add_name_edit->text())); + q1=new RDSqlQuery(sql); + if(q1->first()) { + CloneEncoderValues("CHANNELS",q->value(0).toInt(),q1->value(0).toInt()); + CloneEncoderValues("SAMPLERATES",q->value(0).toInt(), + q1->value(0).toInt()); + CloneEncoderValues("BITRATES",q->value(0).toInt(),q1->value(0).toInt()); + } + delete q1; + } + delete q; + + // + // Clone Hotkeys + // + sql=QString().sprintf("select MODULE_NAME,KEY_ID,KEY_VALUE,KEY_LABEL\ + from RDHOTKEYS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(add_exemplar_box->currentText())); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into RDHOTKEYS set \ + MODULE_NAME=\"%s\",\ + KEY_ID=%d,\ + KEY_VALUE=\"%s\",\ + KEY_LABEL=\"%s\",\ + STATION_NAME=\"%s\"", + (const char *)RDEscapeString(q->value(0). + toString()), + q->value(1).toInt(), + (const char *)RDEscapeString(q->value(2). + toString()), + (const char *)RDEscapeString(q->value(3). + toString()), + (const char *)RDEscapeString(add_name_edit-> + text())); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + } + *add_name=add_name_edit->text(); + + EditStation *station=new EditStation(add_name_edit->text(),this,"station"); + int res=station->exec(); + delete station; + + done(res); +} + + +void AddStation::cancelData() +{ + done(-1); +} + + +void AddStation::CloneEncoderValues(const QString ¶mname, + int src_id,int dest_id) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + sql=QString().sprintf("select %s from ENCODER_%s where ENCODER_ID=%d", + (const char *)RDEscapeString(paramname), + (const char *)RDEscapeString(paramname), + src_id); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into ENCODER_%s set %s=%d,ENCODER_ID=%d", + (const char *)RDEscapeString(paramname), + (const char *)RDEscapeString(paramname), + q->value(0).toInt(), + dest_id); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; +} diff --git a/rdadmin/add_station.h b/rdadmin/add_station.h new file mode 100644 index 00000000..33bd932d --- /dev/null +++ b/rdadmin/add_station.h @@ -0,0 +1,59 @@ +// add_station.h +// +// Add a Rivendell Workstation +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: add_station.h,v 1.11 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_STATION_H +#define ADD_STATION_H + +#include +#include +#include +#include +#include +#include +#include + +#include + + +class AddStation : public QDialog +{ + Q_OBJECT + public: + AddStation(QString *stationname,QWidget *parent=0,const char *name=0); + ~AddStation(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + void CloneEncoderValues(const QString ¶mname,int src_id,int dest_id); + QLineEdit *add_name_edit; + QComboBox *add_exemplar_box; + QString *add_name; +}; + + +#endif + diff --git a/rdadmin/add_svc.cpp b/rdadmin/add_svc.cpp new file mode 100644 index 00000000..cdc2ca5b --- /dev/null +++ b/rdadmin/add_svc.cpp @@ -0,0 +1,181 @@ +// add_svc.cpp +// +// Add a Rivendell Service +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: add_svc.cpp,v 1.20.8.1 2014/01/10 15:58:28 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +AddSvc::AddSvc(QString *svcname,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + svc_name=svcname; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Add Service")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this); + + // + // Service Name + // + svc_name_edit=new QLineEdit(this); + svc_name_edit->setGeometry(155,11,sizeHint().width()-165,19); + svc_name_edit->setMaxLength(10); + svc_name_edit->setValidator(validator); + QLabel *svc_name_label= + new QLabel(svc_name_edit,tr("&New Service Name:"),this); + svc_name_label->setGeometry(10,11,140,19); + svc_name_label->setFont(font); + svc_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Exemplar + // + svc_exemplar_box=new QComboBox(this); + svc_exemplar_box->setGeometry(155,36,sizeHint().width()-165,19); + QLabel *svc_exemplar_label= + new QLabel(svc_exemplar_box,tr("Base Service On:"),this); + svc_exemplar_label->setGeometry(10,36,140,19); + svc_exemplar_label->setFont(font); + svc_exemplar_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Exemplar List + // + svc_exemplar_box->insertItem(tr("Empty Host Config")); + QString sql="select NAME from SERVICES"; + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + svc_exemplar_box->insertItem(q->value(0).toString()); + } + delete q; +} + + +AddSvc::~AddSvc() +{ + delete svc_name_edit; +} + + +QSize AddSvc::sizeHint() const +{ + return QSize(350,135); +} + + +QSizePolicy AddSvc::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddSvc::okData() +{ + if(svc_name_edit->text().isEmpty()) { + QMessageBox::warning(this,tr("Invalid Name"), + tr("You must give the service a name!")); + return; + } + + RDSvc *svc=new RDSvc(svc_name_edit->text(),this,"svc"); + if(svc->exists()) { + QMessageBox::warning(this,tr("Service Exists"), + tr("Service Already Exists!")); + delete svc; + return; + } + if(svc_exemplar_box->currentItem()==0) { // Create Empty Service + svc->create(""); + } + else { + svc->create(svc_exemplar_box->currentText()); + } + delete svc; + *svc_name=svc_name_edit->text(); + + EditSvc *edit_svc=new EditSvc(svc_name_edit->text(),this,"svc"); + if(edit_svc->exec()<0) { + delete edit_svc; + done(-1); + return; + } + delete edit_svc; + done(0); +} + + +void AddSvc::cancelData() +{ + done(-1); +} diff --git a/rdadmin/add_svc.h b/rdadmin/add_svc.h new file mode 100644 index 00000000..45c7bba0 --- /dev/null +++ b/rdadmin/add_svc.h @@ -0,0 +1,58 @@ +// add_svc.h +// +// Add a Rivendell Service +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: add_svc.h,v 1.8 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_SVC_H +#define ADD_SVC_H + +#include +#include +#include +#include +#include +#include +#include + +#include + + +class AddSvc : public QDialog +{ + Q_OBJECT + public: + AddSvc(QString *svcname,QWidget *parent=0,const char *name=0); + ~AddSvc(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *svc_name_edit; + QComboBox *svc_exemplar_box; + QString *svc_name; +}; + + +#endif + diff --git a/rdadmin/add_user.cpp b/rdadmin/add_user.cpp new file mode 100644 index 00000000..f38d0d2f --- /dev/null +++ b/rdadmin/add_user.cpp @@ -0,0 +1,173 @@ +// add_user.cpp +// +// Add a Rivendell User +// +// (C) Copyright 2002-2008 Fred Gleason +// +// $Id: add_user.cpp,v 1.20 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +AddUser::AddUser(QString *username,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + user_name=username; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Add User")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // User Name + // + user_name_edit=new QLineEdit(this,"user_name_edit"); + user_name_edit->setGeometry(125,11,sizeHint().width()-135,19); + user_name_edit->setMaxLength(255); + QLabel *user_name_label=new QLabel(user_name_edit,tr("&New User Name:"),this, + "user_name_label"); + user_name_label->setGeometry(10,13,110,19); + user_name_label->setFont(font); + user_name_label->setAlignment(AlignRight|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +AddUser::~AddUser() +{ + delete user_name_edit; +} + + +QSize AddUser::sizeHint() const +{ + return QSize(400,110); +} + + +QSizePolicy AddUser::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddUser::okData() +{ + RDSqlQuery *q; + RDSqlQuery *q1; + QString sql; + QString username=RDEscapeString(user_name_edit->text()); + + if(user_name_edit->text().isEmpty()) { + QMessageBox::warning(this,tr("Invalid Name"),tr("You must give the user a name!")); + return; + } + + sql=QString().sprintf("insert into USERS set LOGIN_NAME=\"%s\",\ + PASSWORD=PASSWORD(\"\")", + (const char *)username); + q=new RDSqlQuery(sql); + if(!q->isActive()) { + QMessageBox::warning(this,tr("User Exists"),tr("User Already Exists!"), + 1,0,0); + delete q; + return; + } + delete q; + sql="select NAME from GROUPS"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into USER_PERMS set USER_NAME=\"%s\",\ + GROUP_NAME=\"%s\"", + (const char *)username, + (const char *)q->value(0).toString()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + EditUser *user=new EditUser(user_name_edit->text(),this,"user"); + if(user->exec()<0) { + sql=QString().sprintf("delete from USER_PERMS where USER_NAME=\"%s\"", + (const char *)username); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from USERS where LOGIN_NAME=\"%s\"", + (const char *)username); + q=new RDSqlQuery(sql); + delete q; + delete user; + done(-1); + return; + } + delete user; + *user_name=user_name_edit->text(); + done(0); +} + + +void AddUser::cancelData() +{ + done(-1); +} diff --git a/rdadmin/add_user.h b/rdadmin/add_user.h new file mode 100644 index 00000000..df7e9098 --- /dev/null +++ b/rdadmin/add_user.h @@ -0,0 +1,56 @@ +// add_user.h +// +// Add a Rivendell User +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: add_user.h,v 1.8 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_USER_H +#define ADD_USER_H + +#include +#include +#include +#include +#include +#include +#include + +#include + + +class AddUser : public QDialog +{ + Q_OBJECT + public: + AddUser(QString *username,QWidget *parent=0,const char *name=0); + ~AddUser(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *user_name_edit; + QString *user_name; +}; + + +#endif // ADD_USER_H diff --git a/rdadmin/autofill_carts.cpp b/rdadmin/autofill_carts.cpp new file mode 100644 index 00000000..4bea635e --- /dev/null +++ b/rdadmin/autofill_carts.cpp @@ -0,0 +1,223 @@ +// autofill_carts.cpp +// +// Edit a List of Autofill Carts +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: autofill_carts.cpp,v 1.16.8.1 2012/11/26 20:19:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +AutofillCarts::AutofillCarts(RDSvc *svc,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString str; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + svc_svc=svc; + + str=QString(tr("Autofill Carts - Service:")); + setCaption(QString().sprintf("%s %s",(const char *)str, + (const char *)svc_svc->name())); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont section_font=QFont("Helvetica",14,QFont::Bold); + section_font.setPixelSize(14); + + // + // Cart List + // + svc_cart_list=new QListView(this,"svc_cart_list"); + svc_cart_list-> + setGeometry(10,10,sizeHint().width()-20,sizeHint().height()-110); + svc_cart_list->setAllColumnsShowFocus(true); + svc_cart_list->setItemMargin(5); + svc_cart_list->addColumn(tr("Cart")); + svc_cart_list->setColumnAlignment(0,AlignCenter); + svc_cart_list->addColumn(tr("Length")); + svc_cart_list->setColumnAlignment(1,AlignRight); + svc_cart_list->addColumn(tr("Title")); + svc_cart_list->setColumnAlignment(2,AlignLeft); + svc_cart_list->addColumn(tr("Artist")); + svc_cart_list->setColumnAlignment(3,AlignLeft); + svc_cart_list->setSortColumn(1); + + // + // Add Button + // + QPushButton *button=new QPushButton(this,"add_button"); + button->setGeometry(20,sizeHint().height()-90,60,40); + button->setFont(font); + button->setText(tr("&Add")); + connect(button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Delete Button + // + button=new QPushButton(this,"delete_button"); + button->setGeometry(90,sizeHint().height()-90,60,40); + button->setFont(font); + button->setText(tr("&Delete")); + connect(button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + RefreshList(); +} + + +AutofillCarts::~AutofillCarts() +{ +} + + +QSize AutofillCarts::sizeHint() const +{ + return QSize(375,310); +} + + +QSizePolicy AutofillCarts::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AutofillCarts::addData() +{ + int cart=0; + if(admin_cart_dialog->exec(&cart,RDCart::Audio,NULL,0, + admin_user->name(),admin_user->password())<0) { + return; + } + RDCart *rdcart=new RDCart(cart); + QListViewItem *item=new QListViewItem(svc_cart_list); + item->setText(0,QString().sprintf("%06d",cart)); + item->setText(1,RDGetTimeLength(rdcart->forcedLength(),false,true)); + item->setText(2,rdcart->title()); + item->setText(3,rdcart->artist()); + svc_cart_list->setSelected(item,true); + svc_cart_list->ensureItemVisible(item); + delete rdcart; +} + + +void AutofillCarts::deleteData() +{ + QListViewItem *item=svc_cart_list->selectedItem(); + if(item==NULL) { + return; + } + delete item; +} + + +void AutofillCarts::okData() +{ + QString sql=QString().sprintf("delete from AUTOFILLS where SERVICE=\"%s\"", + (const char *)svc_svc->name()); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + QListViewItem *item=svc_cart_list->firstChild(); + while(item!=NULL) { + sql=QString().sprintf("insert into AUTOFILLS set SERVICE=\"%s\",\ + CART_NUMBER=%u",(const char *)svc_svc->name(), + item->text(0).toUInt()); + q=new RDSqlQuery(sql); + delete q; + item=item->nextSibling(); + } + done(0); +} + + +void AutofillCarts::cancelData() +{ + done(1); +} + + +void AutofillCarts::RefreshList() +{ + QListViewItem *item; + + svc_cart_list->clear(); + QString sql=QString().sprintf("select AUTOFILLS.CART_NUMBER,\ + CART.FORCED_LENGTH,CART.TITLE,CART.ARTIST\ + from AUTOFILLS left join CART\ + on AUTOFILLS.CART_NUMBER=CART.NUMBER\ + where SERVICE=\"%s\"", + (const char *)svc_svc->name()); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + item=new QListViewItem(svc_cart_list); + item->setText(0,QString().sprintf("%06u",q->value(0).toUInt())); + item->setText(1,RDGetTimeLength(q->value(1).toInt(),false,true)); + item->setText(2,q->value(2).toString()); + item->setText(3,q->value(3).toString()); + } + delete q; +} diff --git a/rdadmin/autofill_carts.h b/rdadmin/autofill_carts.h new file mode 100644 index 00000000..2e0da13c --- /dev/null +++ b/rdadmin/autofill_carts.h @@ -0,0 +1,57 @@ +// autofill_carts.h +// +// Edit a List of Autofill Carts +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: autofill_carts.h,v 1.6 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef AUTOFILL_CARTS_H +#define AUTOFILL_CARTS_H + +#include +#include +#include + +#include + +class AutofillCarts : public QDialog +{ + Q_OBJECT + public: + AutofillCarts(RDSvc *svc,QWidget *parent=0,const char *name=0); + ~AutofillCarts(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void deleteData(); + void okData(); + void cancelData(); + + private: + void RefreshList(); + RDSvc *svc_svc; + QListView *svc_cart_list; + QString svc_cart_filter; + QString svc_cart_group; +}; + + +#endif + diff --git a/rdadmin/createdb.cpp b/rdadmin/createdb.cpp new file mode 100644 index 00000000..28f7286c --- /dev/null +++ b/rdadmin/createdb.cpp @@ -0,0 +1,8048 @@ +// createdb.cpp +// +// Create, Initialize and/or Update a Rivendell Database +// +// (C) Copyright 2002-2010 Fred Gleason +// +// $Id: createdb.cpp,v 1.195.2.32.2.5 2014/06/05 19:04:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rdconfig.h" +#include +#include + +// +// NOTE TO MAINTAINERS: +// Be sure to use the QSqlQuery class to run queries throughout this file, +// *not* RDSqlQuery! RDSqlQuery will kill outer sql 'select' loops when +// schema updates are reapplied! +// + +bool RunQuery(QString sql) +{ + QSqlQuery *q=new QSqlQuery(sql); + if(!q->isActive()) { + fprintf(stderr,"SQL: %s\n",(const char *)sql); + fprintf(stderr,"SQL Error: %s\n",(const char *)q->lastError().databaseText()); + delete q; + return false; + } + delete q; + return true; +} + + +bool UpdateRDAirplayHotkeys(QString current_station) +{ + QString sql; + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=1,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Start Line 1")); + + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\", \ + KEY_ID=2,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Stop Line 1")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=3,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Pause Line 1")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=4,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Start Line 2")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=5,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Stop Line 2")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=6,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Pause Line 2")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=7,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Start Line 3")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=8,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Stop Line 3")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=9,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Pause Line 3")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=10,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Start Line 4")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=11,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Stop Line 4")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=12,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Pause Line 4")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=13,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Start Line 5")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=14,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Stop Line 5")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=15,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Pause Line 5")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=16,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Start Line 6")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=17,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Stop Line 6")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=18,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Pause Line 6")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=19,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Start Line 7")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=20,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Stop Line 7")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=21,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Pause Line 7")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=22,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Add")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=23,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Delete")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=24,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Copy")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=25,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Move")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=26,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Sound Panel")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=27,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Main Log")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=28,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Aux Log 1")); + if(!RunQuery(sql)) { + return false; + } + + sql=QString().sprintf("insert into RDHOTKEYS set STATION_NAME=\"%s\",\ + MODULE_NAME=\"airplay\",\ + KEY_ID=29,\ + KEY_LABEL=\"%s\" ", + (const char *)current_station, + (const char *)QObject::tr("Aux Log 2")); + if(!RunQuery(sql)) { + return false; + } +return true; +} + +void UpdateImportFormats() +{ + QString sql; + QSqlQuery *q; + + sql="insert into IMPORT_TEMPLATES set\ + NAME=\"Rivendell Standard Import\",\ + CART_OFFSET=10,\ + CART_LENGTH=6,\ + TITLE_OFFSET=25,\ + TITLE_LENGTH=34,\ + HOURS_OFFSET=0,\ + HOURS_LENGTH=2,\ + MINUTES_OFFSET=3,\ + MINUTES_LENGTH=2,\ + SECONDS_OFFSET=6,\ + SECONDS_LENGTH=2,\ + LEN_HOURS_OFFSET=60,\ + LEN_HOURS_LENGTH=2,\ + LEN_MINUTES_OFFSET=63,\ + LEN_MINUTES_LENGTH=2,\ + LEN_SECONDS_OFFSET=66,\ + LEN_SECONDS_LENGTH=2,\ + DATA_OFFSET=69,\ + DATA_LENGTH=32"; + q=new QSqlQuery(sql); + delete q; + + sql="insert into IMPORT_TEMPLATES set\ + NAME=\"PowerGold Music Scheduling\",\ + CART_OFFSET=10,\ + CART_LENGTH=6,\ + TITLE_OFFSET=25,\ + TITLE_LENGTH=34,\ + HOURS_OFFSET=0,\ + HOURS_LENGTH=2,\ + MINUTES_OFFSET=3,\ + MINUTES_LENGTH=2,\ + SECONDS_OFFSET=6,\ + SECONDS_LENGTH=2,\ + LEN_HOURS_OFFSET=60,\ + LEN_HOURS_LENGTH=2,\ + LEN_MINUTES_OFFSET=63,\ + LEN_MINUTES_LENGTH=2,\ + LEN_SECONDS_OFFSET=66,\ + LEN_SECONDS_LENGTH=2,\ + DATA_OFFSET=69,\ + DATA_LENGTH=32"; + q=new QSqlQuery(sql); + delete q; + + sql="insert into IMPORT_TEMPLATES set\ + NAME=\"RadioTraffic.com\",\ + CART_OFFSET=10,\ + CART_LENGTH=6,\ + TITLE_OFFSET=25,\ + TITLE_LENGTH=34,\ + HOURS_OFFSET=0,\ + HOURS_LENGTH=2,\ + MINUTES_OFFSET=3,\ + MINUTES_LENGTH=2,\ + SECONDS_OFFSET=6,\ + SECONDS_LENGTH=2,\ + LEN_HOURS_OFFSET=60,\ + LEN_HOURS_LENGTH=2,\ + LEN_MINUTES_OFFSET=63,\ + LEN_MINUTES_LENGTH=2,\ + LEN_SECONDS_OFFSET=66,\ + LEN_SECONDS_LENGTH=2,\ + DATA_OFFSET=69,\ + DATA_LENGTH=32"; + q=new QSqlQuery(sql); + delete q; + + sql="insert into IMPORT_TEMPLATES set\ + NAME=\"CounterPoint Traffic\",\ + CART_OFFSET=10,\ + CART_LENGTH=6,\ + TITLE_OFFSET=25,\ + TITLE_LENGTH=34,\ + HOURS_OFFSET=0,\ + HOURS_LENGTH=2,\ + MINUTES_OFFSET=3,\ + MINUTES_LENGTH=2,\ + SECONDS_OFFSET=6,\ + SECONDS_LENGTH=2,\ + LEN_HOURS_OFFSET=60,\ + LEN_HOURS_LENGTH=2,\ + LEN_MINUTES_OFFSET=63,\ + LEN_MINUTES_LENGTH=2,\ + LEN_SECONDS_OFFSET=66,\ + LEN_SECONDS_LENGTH=2,\ + EVENT_ID_OFFSET=69,\ + EVENT_ID_LENGTH=32,\ + DATA_OFFSET=102,\ + DATA_LENGTH=32"; + q=new QSqlQuery(sql); + delete q; + + sql="insert into IMPORT_TEMPLATES set\ + NAME=\"WideOrbit Traffic\",\ + CART_OFFSET=10,\ + CART_LENGTH=6,\ + TITLE_OFFSET=25,\ + TITLE_LENGTH=34,\ + HOURS_OFFSET=0,\ + HOURS_LENGTH=2,\ + MINUTES_OFFSET=3,\ + MINUTES_LENGTH=2,\ + SECONDS_OFFSET=6,\ + SECONDS_LENGTH=2,\ + LEN_HOURS_OFFSET=60,\ + LEN_HOURS_LENGTH=2,\ + LEN_MINUTES_OFFSET=63,\ + LEN_MINUTES_LENGTH=2,\ + LEN_SECONDS_OFFSET=66,\ + LEN_SECONDS_LENGTH=2,\ + EVENT_ID_OFFSET=69,\ + EVENT_ID_LENGTH=32,\ + DATA_OFFSET=102,\ + DATA_LENGTH=32"; + q=new QSqlQuery(sql); + delete q; + + sql="insert into IMPORT_TEMPLATES set\ + NAME=\"Visual Traffic\",\ + CART_OFFSET=14,\ + CART_LENGTH=6,\ + TITLE_OFFSET=25,\ + TITLE_LENGTH=39,\ + HOURS_OFFSET=5,\ + HOURS_LENGTH=2,\ + MINUTES_OFFSET=8,\ + MINUTES_LENGTH=2,\ + SECONDS_OFFSET=11,\ + SECONDS_LENGTH=2,\ + LEN_HOURS_OFFSET=0,\ + LEN_HOURS_LENGTH=0,\ + LEN_MINUTES_OFFSET=97,\ + LEN_MINUTES_LENGTH=2,\ + LEN_SECONDS_OFFSET=99,\ + LEN_SECONDS_LENGTH=2,\ + EVENT_ID_OFFSET=0,\ + EVENT_ID_LENGTH=0,\ + DATA_OFFSET=0,\ + DATA_LENGTH=0"; + q=new QSqlQuery(sql); + delete q; + + sql="insert into IMPORT_TEMPLATES set\ + NAME=\"Music 1\",\ + CART_OFFSET=10,\ + CART_LENGTH=6,\ + TITLE_OFFSET=25,\ + TITLE_LENGTH=34,\ + HOURS_OFFSET=0,\ + HOURS_LENGTH=2,\ + MINUTES_OFFSET=3,\ + MINUTES_LENGTH=2,\ + SECONDS_OFFSET=6,\ + SECONDS_LENGTH=2,\ + LEN_HOURS_OFFSET=60,\ + LEN_HOURS_LENGTH=2,\ + LEN_MINUTES_OFFSET=63,\ + LEN_MINUTES_LENGTH=2,\ + LEN_SECONDS_OFFSET=66,\ + LEN_SECONDS_LENGTH=2,\ + DATA_OFFSET=69,\ + DATA_LENGTH=32"; + q=new QSqlQuery(sql); + delete q; + + sql="insert into IMPORT_TEMPLATES set\ + NAME=\"NaturalLog\",\ + CART_OFFSET=9,\ + CART_LENGTH=6,\ + TITLE_OFFSET=19,\ + TITLE_LENGTH=40,\ + HOURS_OFFSET=0,\ + HOURS_LENGTH=2,\ + MINUTES_OFFSET=3,\ + MINUTES_LENGTH=2,\ + SECONDS_OFFSET=6,\ + SECONDS_LENGTH=2,\ + LEN_HOURS_OFFSET=61,\ + LEN_HOURS_LENGTH=2,\ + LEN_MINUTES_OFFSET=64,\ + LEN_MINUTES_LENGTH=2,\ + LEN_SECONDS_OFFSET=67,\ + LEN_SECONDS_LENGTH=2,\ + DATA_OFFSET=0,\ + DATA_LENGTH=0"; + q=new QSqlQuery(sql); + delete q; +} + + +bool CreateDb(QString name,QString pwd) +{ + QString sql; + +// +// Create USERS table +// + sql=QString("CREATE TABLE IF NOT EXISTS USERS (\ + LOGIN_NAME CHAR(255) NOT NULL PRIMARY KEY,\ + FULL_NAME CHAR(255),\ + PHONE_NUMBER CHAR(20),\ + DESCRIPTION CHAR(255),\ + PASSWORD CHAR(32),\ + ENABLE_WEB enum('N','Y') default 'N',\ + ADMIN_USERS_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + ADMIN_CONFIG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + CREATE_CARTS_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + DELETE_CARTS_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + MODIFY_CARTS_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + EDIT_AUDIO_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + ASSIGN_CART_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + CREATE_LOG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + DELETE_LOG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + DELETE_REC_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + PLAYOUT_LOG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + ARRANGE_LOG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + MODIFY_TEMPLATE_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + ADDTO_LOG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + REMOVEFROM_LOG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + CONFIG_PANELS_PRIV enum('N','Y') not null default 'N',\ + VOICETRACK_LOG_PRIV enum('N','Y') not null default 'N',\ + EDIT_CATCHES_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ + ADD_PODCAST_PRIV enum('N','Y') not null default 'N',\ + EDIT_PODCAST_PRIV enum('N','Y') not null default 'N',\ + DELETE_PODCAST_PRIV enum('N','Y') not null default 'N',\ + INDEX FULL_NAME_IDX (FULL_NAME))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create STATIONS table +// + sql=QString("CREATE TABLE IF NOT EXISTS STATIONS (\ + NAME CHAR(64) PRIMARY KEY NOT NULL,\ + DESCRIPTION CHAR(64),\ + USER_NAME CHAR(255),\ + DEFAULT_NAME CHAR(255),\ + IPV4_ADDRESS CHAR(15) default \"127.0.0.2\",\ + HTTP_STATION char(64) default \"localhost\",\ + CAE_STATION char(64) default \"localhost\",\ + TIME_OFFSET int default 0,\ + BACKUP_DIR char(255),\ + BACKUP_LIFE int default 0,\ + BROADCAST_SECURITY int unsigned default 0,\ + HEARTBEAT_CART int unsigned default 0,\ + HEARTBEAT_INTERVAL int unsigned default 0,\ + STARTUP_CART int unsigned default 0,\ + EDITOR_PATH char(255) default \"\",\ + FILTER_MODE int default 0,\ + START_JACK enum('N','Y') default 'N',\ + JACK_SERVER_NAME char(64),\ + JACK_COMMAND_LINE char(255),\ + CUE_CARD int default 0,\ + CUE_PORT int default 0,\ + CUE_START_CART int unsigned,\ + CUE_STOP_CART int unsigned,\ + CARTSLOT_COLUMNS int default 1,\ + CARTSLOT_ROWS int default 8,\ + ENABLE_DRAGDROP enum('N','Y') default 'Y',\ + ENFORCE_PANEL_SETUP enum('N','Y') default 'N',\ + SYSTEM_MAINT enum('N','Y') default 'Y',\ + STATION_SCANNED enum('N','Y') default 'N',\ + HAVE_OGGENC enum('N','Y') default 'N',\ + HAVE_OGG123 enum('N','Y') default 'N',\ + HAVE_FLAC enum('N','Y') default 'N',\ + HAVE_TWOLAME enum('N','Y') default 'N',\ + HAVE_LAME enum('N','Y') default 'N',\ + HAVE_MPG321 enum('N','Y') default 'N',\ + HPI_VERSION char(16),\ + JACK_VERSION char(16),\ + ALSA_VERSION char(16),\ + CARD0_DRIVER int(11) default 0,\ + CARD0_NAME char(64),\ + CARD0_INPUTS int default -1,\ + CARD0_OUTPUTS int default -1,\ + CARD1_DRIVER int(11) default 0,\ + CARD1_NAME char(64),\ + CARD1_INPUTS int default -1,\ + CARD1_OUTPUTS int default -1,\ + CARD2_DRIVER int(11) default 0,\ + CARD2_NAME char(64),\ + CARD2_INPUTS int default -1,\ + CARD2_OUTPUTS int default -1,\ + CARD3_DRIVER int(11) default 0,\ + CARD3_NAME char(64),\ + CARD3_INPUTS int default -1,\ + CARD3_OUTPUTS int default -1,\ + CARD4_DRIVER int(11) default 0,\ + CARD4_NAME char(64),\ + CARD4_INPUTS int default -1,\ + CARD4_OUTPUTS int default -1,\ + CARD5_DRIVER int(11) default 0,\ + CARD5_NAME char(64),\ + CARD5_INPUTS int default -1,\ + CARD5_OUTPUTS int default -1,\ + CARD6_DRIVER int(11) default 0,\ + CARD6_NAME char(64),\ + CARD6_INPUTS int default -1,\ + CARD6_OUTPUTS int default -1,\ + CARD7_DRIVER int(11) default 0,\ + CARD7_NAME char(64),\ + CARD7_INPUTS int default -1,\ + CARD7_OUTPUTS int default -1,\ + INDEX DESCRIPTION_IDX (DESCRIPTION))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create CART table +// + sql=QString("CREATE TABLE IF NOT EXISTS CART (\ + NUMBER INT UNSIGNED NOT NULL PRIMARY KEY,\ + TYPE INT UNSIGNED NOT NULL,\ + GROUP_NAME CHAR(10) NOT NULL,\ + TITLE CHAR(255),\ + ARTIST CHAR(255),\ + ALBUM CHAR(255),\ + YEAR DATE,\ + ISRC CHAR(12),\ + CONDUCTOR CHAR(64),\ + LABEL CHAR(64),\ + CLIENT CHAR(64),\ + AGENCY CHAR(64),\ + PUBLISHER CHAR(64),\ + COMPOSER CHAR(64),\ + USER_DEFINED CHAR(255),\ + SONG_ID CHAR(32),\ + BPM int unsigned default 0,\ + USAGE_CODE int default 0,\ + FORCED_LENGTH INT UNSIGNED,\ + AVERAGE_LENGTH int unsigned,\ + LENGTH_DEVIATION int unsigned default 0,\ + AVERAGE_SEGUE_LENGTH int unsigned,\ + AVERAGE_HOOK_LENGTH int unsigned default 0,\ + CUT_QUANTITY INT UNSIGNED,\ + LAST_CUT_PLAYED INT UNSIGNED,\ + PLAY_ORDER INT UNSIGNED,\ + VALIDITY int unsigned default 2,\ + START_DATETIME DATETIME,\ + END_DATETIME DATETIME,\ + ENFORCE_LENGTH ENUM('N','Y') DEFAULT 'N',\ + PRESERVE_PITCH ENUM('N','Y') DEFAULT 'N',\ + ASYNCRONOUS enum('N','Y') default 'N',\ + OWNER char(64),\ + MACROS text,\ + SCHED_CODES VARCHAR( 255 ) NULL DEFAULT NULL,\ + NOTES text,\ + METADATA_DATETIME datetime,\ + USE_EVENT_LENGTH enum('N','Y') default 'N',\ + PENDING_STATION char(64),\ + PENDING_PID int,\ + PENDING_DATETIME datetime,\ + INDEX GROUP_NAME_IDX (GROUP_NAME),\ + INDEX TITLE_IDX (TITLE),\ + INDEX ARTIST_IDX (ARTIST),\ + INDEX ALBUM_IDX (ALBUM),\ + INDEX CONDUCTOR_IDX (CONDUCTOR),\ + INDEX LABEL_IDX (LABEL),\ + INDEX CLIENT_IDX (CLIENT),\ + INDEX AGENCY_IDX (AGENCY),\ + INDEX PUBLISHER_IDX (PUBLISHER),\ + INDEX COMPOSER_IDX (COMPOSER),\ + INDEX USER_DEFINED_IDX (USER_DEFINED),\ + INDEX SONG_ID_IDX (SONG_ID),\ + INDEX OWNER_IDX (OWNER),\ + index METADATA_DATETIME_IDX (METADATA_DATETIME),\ + index PENDING_STATION_IDX(PENDING_STATION),\ + index PENDING_PID_IDX(PENDING_STATION,PENDING_PID),\ + index PENDING_DATETIME_IDX(PENDING_DATETIME))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create CUTS table +// + sql=QString().sprintf("CREATE TABLE IF NOT EXISTS CUTS (\ + CUT_NAME CHAR(12) PRIMARY KEY NOT NULL,\ + CART_NUMBER INT UNSIGNED NOT NULL,\ + EVERGREEN enum('N','Y') default 'N',\ + DESCRIPTION CHAR(64),\ + OUTCUE CHAR(64),\ + ISRC char(12),\ + ISCI char(32),\ + LENGTH INT UNSIGNED,\ + ORIGIN_DATETIME DATETIME,\ + START_DATETIME DATETIME,\ + END_DATETIME DATETIME,\ + SUN enum('N','Y') default 'Y',\ + MON enum('N','Y') default 'Y',\ + TUE enum('N','Y') default 'Y',\ + WED enum('N','Y') default 'Y',\ + THU enum('N','Y') default 'Y',\ + FRI enum('N','Y') default 'Y',\ + SAT enum('N','Y') default 'Y',\ + START_DAYPART TIME,\ + END_DAYPART TIME,\ + ORIGIN_NAME CHAR(64),\ + WEIGHT INT UNSIGNED DEFAULT 1,\ + LAST_PLAY_DATETIME DATETIME,\ + UPLOAD_DATETIME datetime,\ + PLAY_COUNTER INT UNSIGNED DEFAULT 0,\ + LOCAL_COUNTER int unsigned default 0,\ + VALIDITY int unsigned default 2,\ + CODING_FORMAT INT UNSIGNED,\ + SAMPLE_RATE INT UNSIGNED,\ + BIT_RATE INT UNSIGNED,\ + CHANNELS INT UNSIGNED,\ + PLAY_GAIN INT DEFAULT 0,\ + START_POINT INT DEFAULT -1,\ + END_POINT INT DEFAULT -1,\ + FADEUP_POINT INT DEFAULT -1,\ + FADEDOWN_POINT INT DEFAULT -1,\ + SEGUE_START_POINT INT DEFAULT -1,\ + SEGUE_END_POINT INT DEFAULT -1,\ + SEGUE_GAIN INT DEFAULT %d,\ + HOOK_START_POINT INT DEFAULT -1,\ + HOOK_END_POINT INT DEFAULT -1,\ + TALK_START_POINT INT DEFAULT -1,\ + TALK_END_POINT INT DEFAULT -1,\ + index CART_NUMBER_IDX (CART_NUMBER),\ + index DESCRIPTION_IDX (DESCRIPTION),\ + index OUTCUE_IDX (OUTCUE),\ + index ORIGIN_DATETIME_IDX (ORIGIN_DATETIME),\ + index START_DATETIME_IDX (START_DATETIME),\ + index END_DATETIME_IDX (END_DATETIME),\ + index ISCI_IDX (ISCI),\ + index ISRC_IDX (ISRC))",RD_FADE_DEPTH); + if(!RunQuery(sql)) { + return false; + } + +// +// Create CLIPBOARD table +// + sql=QString("CREATE TABLE IF NOT EXISTS CLIPBOARD (\ + CUT_NAME CHAR(12) PRIMARY KEY NOT NULL,\ + CART_NUMBER INT UNSIGNED NOT NULL,\ + DESCRIPTION CHAR(64),\ + OUTCUE CHAR(64),\ + LENGTH INT UNSIGNED,\ + ORIGIN_DATETIME DATETIME,\ + ORIGIN_NAME CHAR(64),\ + WEIGHT INT UNSIGNED DEFAULT 1,\ + LAST_PLAY_DATETIME DATETIME,\ + PLAY_COUNTER INT UNSIGNED DEFAULT 0,\ + CODING_FORMAT INT UNSIGNED,\ + SAMPLE_RATE INT UNSIGNED,\ + BIT_RATE INT UNSIGNED,\ + CHANNELS INT UNSIGNED,\ + PLAY_GAIN INT DEFAULT 0,\ + START_POINT INT DEFAULT -1,\ + END_POINT INT DEFAULT -1,\ + FADEUP_POINT INT DEFAULT -1,\ + FADEDOWN_POINT INT DEFAULT -1,\ + SEGUE_START_POINT INT DEFAULT -1,\ + SEGUE_END_POINT INT DEFAULT -1,\ + HOOK_START_POINT INT DEFAULT -1,\ + HOOK_END_POINT INT DEFAULT -1,\ + TALK_START_POINT INT DEFAULT -1,\ + TALK_END_POINT INT DEFAULT -1,\ + INDEX CART_NUMBER_IDX (CART_NUMBER),\ + INDEX DESCRIPTION_IDX (DESCRIPTION),\ + INDEX OUTCUE_IDX (OUTCUE))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create SERVICES table +// + sql=QString("CREATE TABLE IF NOT EXISTS SERVICES (\ + NAME CHAR(10) NOT NULL PRIMARY KEY,\ + DESCRIPTION CHAR(255),\ + NAME_TEMPLATE char(255),\ + DESCRIPTION_TEMPLATE char(255),\ + PROGRAM_CODE char(255),\ + CHAIN_LOG enum('N','Y') default 'N',\ + TRACK_GROUP char(10),\ + AUTOSPOT_GROUP char(10),\ + AUTO_REFRESH enum('N','Y') default 'N',\ + DEFAULT_LOG_SHELFLIFE int default -1,\ + ELR_SHELFLIFE int default -1,\ + TFC_PATH char(255),\ + TFC_PREIMPORT_CMD text,\ + TFC_WIN_PATH char(255),\ + TFC_WIN_PREIMPORT_CMD text,\ + TFC_IMPORT_TEMPLATE char(64) default \"Rivendell Standard Import\",\ + TFC_LABEL_CART char(32),\ + TFC_TRACK_CART char(32),\ + TFC_BREAK_STRING char(64),\ + TFC_TRACK_STRING char(64),\ + TFC_CART_OFFSET int,\ + TFC_CART_LENGTH int,\ + TFC_TITLE_OFFSET int,\ + TFC_TITLE_LENGTH int,\ + TFC_START_OFFSET int,\ + TFC_START_LENGTH int,\ + TFC_HOURS_OFFSET int,\ + TFC_HOURS_LENGTH int,\ + TFC_MINUTES_OFFSET int,\ + TFC_MINUTES_LENGTH int,\ + TFC_SECONDS_OFFSET int,\ + TFC_SECONDS_LENGTH int,\ + TFC_LEN_HOURS_OFFSET int,\ + TFC_LEN_HOURS_LENGTH int,\ + TFC_LEN_MINUTES_OFFSET int,\ + TFC_LEN_MINUTES_LENGTH int,\ + TFC_LEN_SECONDS_OFFSET int,\ + TFC_LEN_SECONDS_LENGTH int,\ + TFC_LENGTH_OFFSET int,\ + TFC_LENGTH_LENGTH int,\ + TFC_DATA_OFFSET int,\ + TFC_DATA_LENGTH int,\ + TFC_EVENT_ID_OFFSET int,\ + TFC_EVENT_ID_LENGTH int,\ + TFC_ANNC_TYPE_OFFSET int,\ + TFC_ANNC_TYPE_LENGTH int,\ + MUS_PATH char(255),\ + MUS_PREIMPORT_CMD text,\ + MUS_WIN_PATH char(255),\ + MUS_WIN_PREIMPORT_CMD text,\ + MUS_IMPORT_TEMPLATE char(64) default \"Rivendell Standard Import\",\ + MUS_LABEL_CART char(32),\ + MUS_TRACK_CART char(32),\ + MUS_BREAK_STRING char(64),\ + MUS_TRACK_STRING char(64),\ + MUS_CART_OFFSET int,\ + MUS_CART_LENGTH int,\ + MUS_TITLE_OFFSET int,\ + MUS_TITLE_LENGTH int,\ + MUS_START_OFFSET int,\ + MUS_START_LENGTH int,\ + MUS_HOURS_OFFSET int,\ + MUS_HOURS_LENGTH int,\ + MUS_MINUTES_OFFSET int,\ + MUS_MINUTES_LENGTH int,\ + MUS_SECONDS_OFFSET int,\ + MUS_SECONDS_LENGTH int,\ + MUS_LEN_HOURS_OFFSET int,\ + MUS_LEN_HOURS_LENGTH int,\ + MUS_LEN_MINUTES_OFFSET int,\ + MUS_LEN_MINUTES_LENGTH int,\ + MUS_LEN_SECONDS_OFFSET int,\ + MUS_LEN_SECONDS_LENGTH int,\ + MUS_LENGTH_OFFSET int,\ + MUS_LENGTH_LENGTH int,\ + MUS_DATA_OFFSET int,\ + MUS_DATA_LENGTH int,\ + MUS_EVENT_ID_OFFSET int,\ + MUS_EVENT_ID_LENGTH int,\ + MUS_ANNC_TYPE_OFFSET int,\ + MUS_ANNC_TYPE_LENGTH int, "); + + for(int i=0;i<167;i++) { + sql+=QString().sprintf("CLOCK%d char(64),",i); + } + sql+=QString("CLOCK167 char(64))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create GROUPS table +// + sql=QString("CREATE TABLE IF NOT EXISTS GROUPS (\ + NAME CHAR(10) NOT NULL PRIMARY KEY,\ + DESCRIPTION CHAR(255),\ + DEFAULT_CART_TYPE int unsigned default 1,\ + DEFAULT_LOW_CART int unsigned default 0,\ + DEFAULT_HIGH_CART int unsigned default 0,\ + CUT_SHELFLIFE int default -1,\ + DELETE_EMPTY_CARTS enum('N','Y') default 'N',\ + DEFAULT_TITLE char(255) default \"Imported from %f.%e\",\ + ENFORCE_CART_RANGE enum('N','Y') default 'N',\ + REPORT_TFC enum('N','Y') default 'Y',\ + REPORT_MUS enum('N','Y') default 'Y',\ + ENABLE_NOW_NEXT enum('N','Y') default 'N',\ + COLOR char(7),\ + index IDX_REPORT_TFC (REPORT_TFC),\ + index IDX_REPORT_MUS (REPORT_MUS))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create AUDIO_PERMS table +// + sql=QString("CREATE TABLE IF NOT EXISTS AUDIO_PERMS (\ + ID INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,\ + GROUP_NAME CHAR(10),\ + SERVICE_NAME CHAR(10),\ + INDEX GROUP_IDX (GROUP_NAME),\ + INDEX SERVICE_IDX (SERVICE_NAME))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create RDLIBRARY table +// + sql=QString("CREATE TABLE IF NOT EXISTS RDLIBRARY (\ + ID INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,\ + STATION CHAR(40) NOT NULL,\ + INSTANCE INT UNSIGNED NOT NULL,\ + INPUT_CARD INT DEFAULT 0,\ + INPUT_STREAM INT DEFAULT 0,\ + INPUT_PORT INT DEFAULT 0,\ + INPUT_TYPE ENUM('A','D') DEFAULT 'A',\ + OUTPUT_CARD INT DEFAULT 0,\ + OUTPUT_STREAM INT DEFAULT 0,\ + OUTPUT_PORT INT DEFAULT 0,\ + VOX_THRESHOLD INT DEFAULT -5000,\ + TRIM_THRESHOLD INT DEFAULT 0,\ + RECORD_GPI INT DEFAULT -1,\ + PLAY_GPI INT DEFAULT -1,\ + STOP_GPI INT DEFAULT -1,\ + DEFAULT_FORMAT INT UNSIGNED DEFAULT 0,\ + DEFAULT_CHANNELS INT UNSIGNED DEFAULT 2,\ + DEFAULT_SAMPRATE INT UNSIGNED DEFAULT 44100,\ + DEFAULT_LAYER INT UNSIGNED DEFAULT 0,\ + DEFAULT_BITRATE INT UNSIGNED DEFAULT 0,\ + DEFAULT_RECORD_MODE INT UNSIGNED DEFAULT 0,\ + DEFAULT_TRIM_STATE ENUM('N','Y') DEFAULT 'N',\ + MAXLENGTH INT,\ + TAIL_PREROLL INT UNSIGNED DEFAULT 1500,\ + RIPPER_DEVICE CHAR(64) DEFAULT \"/dev/cdrom\",\ + PARANOIA_LEVEL INT DEFAULT 0,\ + RIPPER_LEVEL INT DEFAULT -1300,\ + CDDB_SERVER CHAR(64) DEFAULT \"freedb.freedb.org\",\ + ENABLE_EDITOR enum('N','Y') default 'N',\ + SRC_CONVERTER int default 1,\ + LIMIT_SEARCH int default 1,\ + SEARCH_LIMITED enum('N','Y') default 'Y',\ + INDEX STATION_IDX (STATION,INSTANCE))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create TRIGGERS table +// + sql=QString("CREATE TABLE IF NOT EXISTS TRIGGERS (\ + ID INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,\ + CUT_NAME CHAR(12),\ + TRIGGER_CODE INT UNSIGNED,\ + OFFSET INT UNSIGNED,\ + INDEX CUT_NAME_IDX (CUT_NAME))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create TTYS table +// + sql=QString("CREATE TABLE IF NOT EXISTS TTYS (\ + ID INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,\ + PORT_ID INT UNSIGNED NOT NULL,\ + ACTIVE ENUM('N','Y') NOT NULL DEFAULT 'N',\ + STATION_NAME CHAR(64) NOT NULL,\ + PORT CHAR(20),\ + BAUD_RATE INT DEFAULT 9600,\ + DATA_BITS INT DEFAULT 8,\ + STOP_BITS INT DEFAULT 1,\ + PARITY INT DEFAULT 0,\ + TERMINATION INT DEFAULT 0,\ + INDEX STATION_NAME_IDX (STATION_NAME),\ + INDEX ACTIVE_IDX (ACTIVE),\ + INDEX PORT_ID_IDX (PORT_ID))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create DECKS table +// + sql=QString("CREATE TABLE IF NOT EXISTS DECKS (\ + ID INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,\ + STATION_NAME CHAR(64) NOT NULL,\ + CHANNEL INT UNSIGNED NOT NULL,\ + CARD_NUMBER INT DEFAULT -1,\ + STREAM_NUMBER INT DEFAULT -1,\ + PORT_NUMBER INT DEFAULT -1,\ + MON_PORT_NUMBER int default -1,\ + DEFAULT_MONITOR_ON enum('N','Y') default 'N',\ + PORT_TYPE ENUM('A','D') DEFAULT 'A',\ + DEFAULT_FORMAT INT DEFAULT 0,\ + DEFAULT_CHANNELS INT DEFAULT 2,\ + DEFAULT_SAMPRATE INT DEFAULT 44100,\ + DEFAULT_BITRATE INT DEFAULT 0,\ + DEFAULT_THRESHOLD INT DEFAULT 0,\ + SWITCH_STATION char(64),\ + SWITCH_MATRIX int default -1,\ + SWITCH_OUTPUT int default -1,\ + SWITCH_DELAY int default 0,\ + INDEX STATION_NAME_IDX (STATION_NAME),\ + INDEX CHANNEL_IDX (CHANNEL))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create RECORDINGS table +// + sql=QString("CREATE TABLE IF NOT EXISTS RECORDINGS (\ + ID INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,\ + IS_ACTIVE enum('N','Y') default 'Y',\ + STATION_NAME CHAR(64) NOT NULL,\ + TYPE int default 0,\ + CHANNEL INT UNSIGNED NOT NULL,\ + CUT_NAME CHAR(12) NOT NULL,\ + SUN ENUM('N','Y') DEFAULT 'N',\ + MON ENUM('N','Y') DEFAULT 'N',\ + TUE ENUM('N','Y') DEFAULT 'N',\ + WED ENUM('N','Y') DEFAULT 'N',\ + THU ENUM('N','Y') DEFAULT 'N',\ + FRI ENUM('N','Y') DEFAULT 'N',\ + SAT ENUM('N','Y') DEFAULT 'N',\ + DESCRIPTION CHAR(64),\ + START_TYPE int unsigned default 0,\ + START_TIME time,\ + START_LENGTH int default 0,\ + START_MATRIX int default -1,\ + START_LINE int default -1,\ + START_OFFSET int default 0,\ + END_TYPE int default 0,\ + END_TIME time,\ + END_LENGTH int default 0,\ + END_MATRIX int default -1,\ + END_LINE int default -1,\ + LENGTH INT UNSIGNED,\ + START_GPI INT DEFAULT -1,\ + END_GPI INT DEFAULT -1,\ + ALLOW_MULT_RECS enum('N','Y') default 'N',\ + MAX_GPI_REC_LENGTH int unsigned default 3600000,\ + TRIM_THRESHOLD int,\ + NORMALIZE_LEVEL int default -1300,\ + STARTDATE_OFFSET INT UNSIGNED DEFAULT 0,\ + ENDDATE_OFFSET INT UNSIGNED DEFAULT 0,\ + EVENTDATE_OFFSET int default 0,\ + FORMAT INT DEFAULT 0,\ + CHANNELS INT DEFAULT 2,\ + SAMPRATE INT DEFAULT 44100,\ + BITRATE INT DEFAULT 0,\ + QUALITY int default 0,\ + MACRO_CART int default -1,\ + SWITCH_INPUT int default -1,\ + SWITCH_OUTPUT int default -1,\ + EXIT_CODE int default 0,\ + EXIT_TEXT text,\ + ONE_SHOT enum('N','Y') default 'N',\ + URL char(255),\ + URL_USERNAME char(64),\ + URL_PASSWORD char(64),\ + ENABLE_METADATA enum('N','Y') default 'N',\ + FEED_ID int default -1,\ + INDEX STATION_NAME_IDX (STATION_NAME))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create AUDIO_PORTS table +// + sql=QString("CREATE TABLE IF NOT EXISTS AUDIO_PORTS (\ + ID INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,\ + STATION_NAME CHAR(64) NOT NULL,\ + CARD_NUMBER INT NOT NULL,\ + CLOCK_SOURCE INT DEFAULT 0,\ + INPUT_0_LEVEL INT DEFAULT 0,\ + INPUT_0_TYPE INT DEFAULT 0,\ + INPUT_0_MODE INT DEFAULT 0,\ + INPUT_1_LEVEL INT DEFAULT 0,\ + INPUT_1_TYPE INT DEFAULT 0,\ + INPUT_1_MODE INT DEFAULT 0,\ + INPUT_2_LEVEL INT DEFAULT 0,\ + INPUT_2_TYPE INT DEFAULT 0,\ + INPUT_2_MODE INT DEFAULT 0,\ + INPUT_3_LEVEL INT DEFAULT 0,\ + INPUT_3_TYPE INT DEFAULT 0,\ + INPUT_3_MODE INT DEFAULT 0,\ + INPUT_4_LEVEL INT DEFAULT 0,\ + INPUT_4_TYPE INT DEFAULT 0,\ + INPUT_4_MODE INT DEFAULT 0,\ + INPUT_5_LEVEL INT DEFAULT 0,\ + INPUT_5_TYPE INT DEFAULT 0,\ + INPUT_5_MODE INT DEFAULT 0,\ + INPUT_6_LEVEL INT DEFAULT 0,\ + INPUT_6_TYPE INT DEFAULT 0,\ + INPUT_6_MODE INT DEFAULT 0,\ + INPUT_7_LEVEL INT DEFAULT 0,\ + INPUT_7_TYPE INT DEFAULT 0,\ + INPUT_7_MODE INT DEFAULT 0,\ + OUTPUT_0_LEVEL INT DEFAULT 0,\ + OUTPUT_1_LEVEL INT DEFAULT 0,\ + OUTPUT_2_LEVEL INT DEFAULT 0,\ + OUTPUT_3_LEVEL INT DEFAULT 0,\ + OUTPUT_4_LEVEL INT DEFAULT 0,\ + OUTPUT_5_LEVEL INT DEFAULT 0,\ + OUTPUT_6_LEVEL INT DEFAULT 0,\ + OUTPUT_7_LEVEL INT DEFAULT 0,\ + INDEX STATION_NAME_IDX (STATION_NAME),\ + INDEX CARD_NUMBER_IDX (CARD_NUMBER))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create LOGS table +// + sql=QString("CREATE TABLE IF NOT EXISTS LOGS (\ + NAME CHAR(64) NOT NULL PRIMARY KEY,\ + LOG_EXISTS enum('N','Y') default 'Y',\ + TYPE int not null default 0,\ + SERVICE CHAR(10) NOT NULL,\ + DESCRIPTION CHAR(64),\ + ORIGIN_USER CHAR(255) NOT NULL,\ + ORIGIN_DATETIME DATETIME NOT NULL,\ + LINK_DATETIME DATETIME NOT NULL,\ + MODIFIED_DATETIME DATETIME NOT NULL,\ + AUTO_REFRESH enum('N','Y') default 'N',\ + START_DATE DATE NOT NULL,\ + END_DATE DATE NOT NULL,\ + PURGE_DATE date,\ + IMPORT_DATE date,\ + SCHEDULED_TRACKS int unsigned default 0,\ + COMPLETED_TRACKS int unsigned default 0,\ + MUSIC_LINKS int default 0,\ + MUSIC_LINKED enum('N','Y') default 'N',\ + TRAFFIC_LINKS int default 0,\ + TRAFFIC_LINKED enum('N','Y') default 'N',\ + NEXT_ID int default 0,\ + index NAME_IDX (NAME,LOG_EXISTS),\ + INDEX SERVICE_IDX (SERVICE),\ + INDEX DESCRIPTION_IDX (DESCRIPTION),\ + INDEX ORIGIN_USER_IDX (ORIGIN_USER),\ + INDEX START_DATE_IDX (START_DATE),\ + INDEX END_DATE_IDX (END_DATE),\ + index TYPE_IDX(TYPE,LOG_EXISTS))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create VERSION table +// + sql="create table if not exists VERSION (\ + DB INT NOT NULL PRIMARY KEY,\ + LAST_MAINT_DATETIME datetime default \"1970-01-01 00:00:00\",\ + LAST_ISCI_XREFERENCE datetime default \"1970-01-01 00:00:00\")"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create RDAIRPLAY Table + // + sql="create table if not exists RDAIRPLAY (\ + ID int not null primary key auto_increment,\ + STATION char(40) not null,\ + INSTANCE int unsigned not null,\ + CARD0 int default 0,\ + PORT0 int default 0,\ + START_RML0 char(255),\ + STOP_RML0 char(255),\ + CARD1 int default 0,\ + PORT1 int default 0,\ + START_RML1 char(255),\ + STOP_RML1 char(255),\ + CARD2 int default 0,\ + PORT2 int default 0,\ + START_RML2 char(255),\ + STOP_RML2 char(255),\ + CARD3 int default 0,\ + PORT3 int default 0,\ + START_RML3 char(255),\ + STOP_RML3 char(255),\ + CARD4 int default 0,\ + PORT4 int default 0,\ + START_RML4 char(255),\ + STOP_RML4 char(255),\ + CARD5 int default 0,\ + PORT5 int default 0,\ + START_RML5 char(255),\ + STOP_RML5 char(255),\ + CARD6 int default 0,\ + PORT6 int default 0,\ + START_RML6 char(255),\ + STOP_RML6 char(255),\ + CARD7 int default 0,\ + PORT7 int default 0,\ + START_RML7 char(255),\ + STOP_RML7 char(255),\ + CARD8 int default 0,\ + PORT8 int default 0,\ + START_RML8 char(255),\ + STOP_RML8 char(255),\ + CARD9 int default 0,\ + PORT9 int default 0,\ + START_RML9 char(255),\ + STOP_RML9 char(255),\ + SEGUE_LENGTH int default 250,\ + TRANS_LENGTH int default 50,\ + OP_MODE int default 2,\ + START_MODE int default 0,\ + LOG_MODE_STYLE int default 0,\ + PIE_COUNT_LENGTH int default 15000,\ + PIE_COUNT_ENDPOINT int default 0,\ + CHECK_TIMESYNC enum('N','Y') default 'N',\ + STATION_PANELS int default 3,\ + USER_PANELS int default 3,\ + SHOW_AUX_1 enum('N','Y') default 'Y',\ + SHOW_AUX_2 enum('N','Y') default 'Y',\ + CLEAR_FILTER enum('N','Y') default 'N',\ + DEFAULT_TRANS_TYPE int default 0,\ + BAR_ACTION int unsigned default 0,\ + FLASH_PANEL enum('N','Y') default 'N',\ + PANEL_PAUSE_ENABLED enum('N','Y') default 'N',\ + BUTTON_LABEL_TEMPLATE char(32) default \"%t\",\ + PAUSE_ENABLED enum('N','Y'),\ + DEFAULT_SERVICE char(10),\ + HOUR_SELECTOR_ENABLED enum('N','Y') default 'N',\ + TITLE_TEMPLATE char(64) default '%t',\ + ARTIST_TEMPLATE char(64) default '%a',\ + OUTCUE_TEMPLATE char(64) default '%o',\ + DESCRIPTION_TEMPLATE char(64) default '%i',\ + UDP_ADDR0 char(255),\ + UDP_PORT0 int unsigned,\ + UDP_STRING0 char(255),\ + LOG_RML0 char(255),\ + UDP_ADDR1 char(255),\ + UDP_PORT1 int unsigned,\ + UDP_STRING1 char(255),\ + LOG_RML1 char(255),\ + UDP_ADDR2 char(255),\ + UDP_PORT2 int unsigned,\ + UDP_STRING2 char(255),\ + LOG_RML2 char(255),\ + EXIT_CODE int default 0,\ + EXIT_PASSWORD char(41) default \"\",\ + SKIN_PATH char(255) default \""; + sql+=RD_DEFAULT_RDAIRPLAY_SKIN; + sql+="\",\ + SHOW_COUNTERS enum('N','Y') default 'N',\ + AUDITION_PREROLL int default 10000,\ + LOG0_START_MODE int default 0,\ + LOG0_AUTO_RESTART enum('N','Y') default 'N',\ + LOG0_LOG_NAME char(64),\ + LOG0_CURRENT_LOG char(64),\ + LOG0_RUNNING enum('N','Y') default 'N',\ + LOG0_LOG_ID int default -1,\ + LOG0_LOG_LINE int default -1,\ + LOG0_NOW_CART int unsigned default 0,\ + LOG0_NEXT_CART int unsigned default 0,\ + LOG1_START_MODE int default 0,\ + LOG1_AUTO_RESTART enum('N','Y') default 'N',\ + LOG1_LOG_NAME char(64),\ + LOG1_CURRENT_LOG char(64),\ + LOG1_RUNNING enum('N','Y') default 'N',\ + LOG1_LOG_ID int default -1,\ + LOG1_LOG_LINE int default -1,\ + LOG1_NOW_CART int unsigned default 0,\ + LOG1_NEXT_CART int unsigned default 0,\ + LOG2_START_MODE int default 0,\ + LOG2_AUTO_RESTART enum('N','Y') default 'N',\ + LOG2_LOG_NAME char(64),\ + LOG2_CURRENT_LOG char(64),\ + LOG2_RUNNING enum('N','Y') default 'N',\ + LOG2_LOG_ID int default -1,\ + LOG2_LOG_LINE int default -1,\ + LOG2_NOW_CART int unsigned default 0,\ + LOG2_NEXT_CART int unsigned default 0,\ + index STATION_IDX (STATION,INSTANCE))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create PANELS Table + // + sql="create table if not exists PANELS (\ + ID int auto_increment not null primary key,\ + TYPE int not null,\ + OWNER char(64) not null,\ + PANEL_NO int not null,\ + ROW_NO int not null,\ + COLUMN_NO int not null,\ + LABEL char(64),\ + CART int,\ + DEFAULT_COLOR char(7),\ + index LOAD_IDX (TYPE,OWNER,PANEL_NO),\ + index SAVE_IDX (TYPE,OWNER,PANEL_NO,ROW_NO,COLUMN_NO))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create MATRICES Table + // + sql="create table if not exists MATRICES (\ + ID int auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + NAME char(64),\ + MATRIX int not null,\ + TYPE int not null,\ + LAYER int default 86,\ + PORT_TYPE int default 0,\ + PORT_TYPE_2 int default 0,\ + CARD int default -1,\ + PORT int not null,\ + PORT_2 int not null,\ + IP_ADDRESS char(16),\ + IP_ADDRESS_2 char(16),\ + IP_PORT int,\ + IP_PORT_2 int,\ + USERNAME char(32),\ + USERNAME_2 char(32),\ + PASSWORD char(32),\ + PASSWORD_2 char(32),\ + START_CART int unsigned,\ + STOP_CART int unsigned,\ + START_CART_2 int unsigned,\ + STOP_CART_2 int unsigned,\ + GPIO_DEVICE char(255),\ + INPUTS int not null,\ + OUTPUTS int not null,\ + GPIS int not null,\ + GPOS int not null,\ + FADERS int default 0,\ + DISPLAYS int default 0,\ + index MATRIX_IDX (STATION_NAME,MATRIX))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create INPUTS Table + // + sql="create table if not exists INPUTS (\ + ID int auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + MATRIX int not null,\ + NUMBER int not null,\ + NAME char(64),\ + FEED_NAME char(8),\ + CHANNEL_MODE int,\ + ENGINE_NUM int default -1,\ + DEVICE_NUM int default -1,\ + NODE_HOSTNAME char(255),\ + NODE_TCP_PORT int,\ + NODE_SLOT int,\ + index MATRIX_IDX (STATION_NAME,MATRIX,NUMBER),\ + index NODE_IDX (STATION_NAME,MATRIX,NUMBER,NODE_HOSTNAME,NODE_TCP_PORT))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create OUTPUTS Table + // + sql="create table if not exists OUTPUTS (\ + ID int auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + MATRIX int not null,\ + NUMBER int not null,\ + NAME char(64),\ + ENGINE_NUM int default -1,\ + DEVICE_NUM int default -1,\ + NODE_HOSTNAME char(255),\ + NODE_TCP_PORT int,\ + NODE_SLOT int,\ + index MATRIX_IDX (STATION_NAME,MATRIX,NUMBER),\ + index NODE_IDX (STATION_NAME,MATRIX,NUMBER,NODE_HOSTNAME,NODE_TCP_PORT))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create GPIS Table + // + sql="create table if not exists GPIS (\ + ID int auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + MATRIX int not null,\ + NUMBER int not null,\ + MACRO_CART int default 0,\ + OFF_MACRO_CART int default 0,\ + index MATRIX_IDX (STATION_NAME,MATRIX,NUMBER))"; + if(!RunQuery(sql)) { + return false; + } + +// +// Create EVENTS table +// + sql=QString("create table if not exists EVENTS (\ + NAME char(64) not null primary key,\ + PROPERTIES char(64),\ + DISPLAY_TEXT char(64),\ + NOTE_TEXT char(255),\ + PREPOSITION int default -1,\ + TIME_TYPE int default 0,\ + GRACE_TIME int default 0,\ + POST_POINT enum('N','Y') default 'N',\ + USE_AUTOFILL enum('N','Y') default 'N',\ + AUTOFILL_SLOP int default -1,\ + USE_TIMESCALE enum('N','Y') default 'N',\ + IMPORT_SOURCE int default 0,\ + START_SLOP int default 0,\ + END_SLOP int default 0,\ + FIRST_TRANS_TYPE int default 0,\ + DEFAULT_TRANS_TYPE int default 0,\ + COLOR char(7),\ + SCHED_GROUP VARCHAR(10),\ + TITLE_SEP INT(10) UNSIGNED,\ + HAVE_CODE VARCHAR(10),\ + HOR_SEP INT(10) UNSIGNED,\ + HOR_DIST INT(10) UNSIGNED,\ + NESTED_EVENT char(64),\ + REMARKS char(255))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create CLOCKS table +// + sql=QString("create table if not exists CLOCKS (\ + NAME char(64) not null primary key,\ + SHORT_NAME char(8),\ + ARTISTSEP int(10) unsigned,\ + COLOR char(7),\ + REMARKS char(255))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create AUTOFILLS table +// + sql=QString("create table if not exists AUTOFILLS (\ + ID int not null primary key auto_increment,\ + SERVICE char(10),\ + CART_NUMBER int unsigned,\ + index SERVICE_IDX (SERVICE))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create HOSTVARS table +// + sql=QString("create table if not exists HOSTVARS (\ + ID int not null primary key auto_increment,\ + STATION_NAME char(64) not null,\ + NAME char(32) not null,\ + VARVALUE char(255),\ + REMARK char(255),\ + index NAME_IDX (STATION_NAME))"); + if(!RunQuery(sql)) { + return false; + } + + // + // Create SERVICE_PERMS Table + // + sql=QString("create table if not exists SERVICE_PERMS (\ + ID int unsigned auto_increment not null primary key,\ + STATION_NAME char(64),\ + SERVICE_NAME char(10),\ + index STATION_IDX (STATION_NAME),\ + index SERVICE_IDX (SERVICE_NAME))"); + if(!RunQuery(sql)) { + return false; + } + + // + // Create REPORTS Table + // + sql=QString("create table if not exists REPORTS (\ + ID int unsigned auto_increment not null primary key,\ + NAME char(64) not null unique,\ + DESCRIPTION char(64),\ + EXPORT_FILTER int,\ + EXPORT_PATH char(255),\ + WIN_EXPORT_PATH char(255),\ + EXPORT_TFC enum('N','Y') default 'N',\ + FORCE_TFC enum('N','Y') default 'N',\ + EXPORT_MUS enum('N','Y') default 'N',\ + FORCE_MUS enum('N','Y') default 'N',\ + EXPORT_GEN enum('N','Y') default 'N',\ + STATION_ID char(16),\ + CART_DIGITS int unsigned default 6,\ + USE_LEADING_ZEROS enum('N','Y') default 'N',\ + LINES_PER_PAGE int default 66,\ + SERVICE_NAME char(64),\ + STATION_TYPE int default 0,\ + STATION_FORMAT char(64),\ + FILTER_ONAIR_FLAG enum('N','Y') default 'N',\ + FILTER_GROUPS enum('N','Y') default 'N',\ + START_TIME time,\ + END_TIME time,\ + index IDX_NAME (NAME))"); + if(!RunQuery(sql)) { + return false; + } + + // + // Create REPORT_SERVICES Table + // + sql=QString("create table if not exists REPORT_SERVICES (\ + ID int unsigned auto_increment not null primary key,\ + REPORT_NAME char(64) not null,\ + SERVICE_NAME char(10),\ + index IDX_REPORT_NAME (REPORT_NAME))"); + if(!RunQuery(sql)) { + return false; + } + + // + // Create REPORT_STATIONS Table + // + sql=QString("create table if not exists REPORT_STATIONS (\ + ID int unsigned auto_increment not null primary key,\ + REPORT_NAME char(64) not null,\ + STATION_NAME char(64),\ + index IDX_REPORT_NAME (REPORT_NAME))"); + if(!RunQuery(sql)) { + return false; + } + + // + // Create REPORT_GROUPS Table + // + sql=QString("create table if not exists REPORT_GROUPS (\ + ID int unsigned auto_increment not null primary key,\ + REPORT_NAME char(64) not null,\ + GROUP_NAME char(10),\ + index IDX_REPORT_NAME (REPORT_NAME))"); + if(!RunQuery(sql)) { + return false; + } + + // + // Create CLOCK_PERMS Table + // + sql=QString("create table if not exists CLOCK_PERMS (\ + ID int unsigned auto_increment not null primary key,\ + CLOCK_NAME char(64),\ + SERVICE_NAME char(10),\ + index STATION_IDX (CLOCK_NAME),\ + index SERVICE_IDX (SERVICE_NAME))"); + if(!RunQuery(sql)) { + return false; + } + + // + // Create EVENT_PERMS Table + // + sql=QString("create table if not exists EVENT_PERMS (\ + ID int unsigned auto_increment not null primary key,\ + EVENT_NAME char(64),\ + SERVICE_NAME char(10),\ + index STATION_IDX (EVENT_NAME),\ + index SERVICE_IDX (SERVICE_NAME))"); + if(!RunQuery(sql)) { + return false; + } + + // + // Create USER_PERMS table + // + sql=QString("create table if not exists USER_PERMS (\ + ID int unsigned auto_increment not null primary key,\ + USER_NAME char(255),\ + GROUP_NAME char(10),\ + index USER_IDX (USER_NAME),\ + index GROUP_IDX (GROUP_NAME))"); + if(!RunQuery(sql)) { + return false; + } + + // + // Create VGUEST_RESOURCES Table + // + sql="create table if not exists VGUEST_RESOURCES (\ + ID int unsigned auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + MATRIX_NUM int not null,\ + VGUEST_TYPE int not null,\ + NUMBER int not null,\ + ENGINE_NUM int default -1,\ + DEVICE_NUM int default -1,\ + SURFACE_NUM int default 0,\ + RELAY_NUM int default -1,\ + BUSS_NUM int default -1,\ + index STATION_MATRIX_IDX (STATION_NAME,MATRIX_NUM,VGUEST_TYPE))"; + if(!RunQuery(sql)) { + return false; + } + +// +// Create RDLOGEDIT table +// + sql=QString("create table if not exists RDLOGEDIT (\ + ID int unsigned primary key auto_increment,\ + STATION char(64) not null,\ + INPUT_CARD int default -1,\ + INPUT_PORT int default 0,\ + OUTPUT_CARD int default -1,\ + OUTPUT_PORT int default 0,\ + FORMAT int unsigned default 0,\ + SAMPRATE int unsigned default 44100,\ + LAYER int unsigned default 0,\ + BITRATE int unsigned default 0,\ + ENABLE_SECOND_START enum('N','Y') default 'Y',\ + DEFAULT_CHANNELS int unsigned default 2,\ + MAXLENGTH int default 0,\ + TAIL_PREROLL int unsigned default 2000,\ + START_CART int unsigned default 0,\ + END_CART int unsigned default 0,\ + REC_START_CART int unsigned default 0,\ + REC_END_CART int unsigned default 0,\ + TRIM_THRESHOLD int default -3000,\ + RIPPER_LEVEL int default -1300,\ + DEFAULT_TRANS_TYPE int default 0,\ + index STATION_IDX (STATION))"); + if(!RunQuery(sql)) { + return false; + } + +// +// Create RDCATCH table +// + sql="create table if not exists RDCATCH (\ + ID int unsigned primary key auto_increment,\ + STATION char(64) not null,\ + ERROR_RML char(255),\ + index STATION_IDX (STATION))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create SCHED_CODES Table + // + sql="create table if not exists SCHED_CODES\ + (CODE varchar(10) not null primary key,\ + DESCRIPTION varchar(255))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create DROPBOXES Table + // + sql="create table if not exists DROPBOXES \ + (ID int auto_increment not null primary key,\ + STATION_NAME char(64),\ + GROUP_NAME char(10),\ + PATH char(255),\ + NORMALIZATION_LEVEL int default 1,\ + AUTOTRIM_LEVEL int default 1,\ + SINGLE_CART enum('N','Y') default 'N',\ + TO_CART int unsigned default 0,\ + USE_CARTCHUNK_ID enum('N','Y') default 'N',\ + TITLE_FROM_CARTCHUNK_ID enum('N','Y') default 'N',\ + DELETE_CUTS enum('N','Y') default 'N',\ + DELETE_SOURCE enum('N','Y') default 'Y',\ + METADATA_PATTERN char(64),\ + STARTDATE_OFFSET int default 0,\ + ENDDATE_OFFSET int default 0,\ + FIX_BROKEN_FORMATS enum('N','Y') default 'N',\ + LOG_PATH char(255),\ + IMPORT_CREATE_DATES enum('N','Y') default 'N',\ + CREATE_STARTDATE_OFFSET int default 0,\ + CREATE_ENDDATE_OFFSET int default 0,\ + SET_USER_DEFINED char(255),\ + index STATION_NAME_IDX (STATION_NAME))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create RDPANEL Table + // + sql="create table if not exists RDPANEL (\ + ID int not null primary key auto_increment,\ + STATION char(40) not null,\ + INSTANCE int unsigned not null,\ + CARD2 int default 0,\ + PORT2 int default 0,\ + START_RML2 char(255),\ + STOP_RML2 char(255),\ + CARD3 int default 0,\ + PORT3 int default 0,\ + START_RML3 char(255),\ + STOP_RML3 char(255),\ + CARD6 int default 0,\ + PORT6 int default 0,\ + START_RML6 char(255),\ + STOP_RML6 char(255),\ + CARD7 int default 0,\ + PORT7 int default 0,\ + START_RML7 char(255),\ + STOP_RML7 char(255),\ + CARD8 int default 0,\ + PORT8 int default 0,\ + START_RML8 char(255),\ + STOP_RML8 char(255),\ + CARD9 int default 0,\ + PORT9 int default 0,\ + START_RML9 char(255),\ + STOP_RML9 char(255),\ + STATION_PANELS int default 3,\ + USER_PANELS int default 3,\ + CLEAR_FILTER enum('N','Y') default 'N',\ + FLASH_PANEL enum('N','Y') default 'N',\ + PANEL_PAUSE_ENABLED enum('N','Y') default 'N',\ + BUTTON_LABEL_TEMPLATE char(32) default \"%t\",\ + DEFAULT_SERVICE char(10),\ + SKIN_PATH char(255) default \""; + sql+=RD_DEFAULT_RDPANEL_SKIN; + sql+="\",\ + index STATION_IDX (STATION,INSTANCE))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create EXTENDED_PANELS Table + // + sql="create table if not exists EXTENDED_PANELS (\ + ID int auto_increment not null primary key,\ + TYPE int not null,\ + OWNER char(64) not null,\ + PANEL_NO int not null,\ + ROW_NO int not null,\ + COLUMN_NO int not null,\ + LABEL char(64),\ + CART int,\ + DEFAULT_COLOR char(7),\ + index LOAD_IDX (TYPE,OWNER,PANEL_NO),\ + index SAVE_IDX (TYPE,OWNER,PANEL_NO,ROW_NO,COLUMN_NO))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create PANEL_NAMES Table + // + sql="create table if not exists PANEL_NAMES (\ + ID int auto_increment not null primary key,\ + TYPE int not null,\ + OWNER char(64) not null,\ + PANEL_NO int not null,\ + NAME char(64),\ + index LOAD_IDX (TYPE,OWNER,PANEL_NO))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create EXTENDED_PANEL_NAMES Table + // + sql="create table if not exists EXTENDED_PANEL_NAMES (\ + ID int auto_increment not null primary key,\ + TYPE int not null,\ + OWNER char(64) not null,\ + PANEL_NO int not null,\ + NAME char(64),\ + index LOAD_IDX (TYPE,OWNER,PANEL_NO))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create FEEDS Table + // + sql="create table if not exists FEEDS (\ + ID int unsigned auto_increment not null primary key,\ + KEY_NAME char(8) unique not null,\ + CHANNEL_TITLE char(255),\ + CHANNEL_DESCRIPTION text,\ + CHANNEL_CATEGORY char(64),\ + CHANNEL_LINK char(255),\ + CHANNEL_COPYRIGHT char(64),\ + CHANNEL_WEBMASTER char(64),\ + CHANNEL_LANGUAGE char(5) default \"en-us\",\ + BASE_URL char(255),\ + BASE_PREAMBLE char(255),\ + PURGE_URL char(255),\ + PURGE_USERNAME char(64),\ + PURGE_PASSWORD char(64),\ + HEADER_XML text,\ + CHANNEL_XML text,\ + ITEM_XML text,\ + CAST_ORDER enum('N','Y') default 'N',\ + MAX_SHELF_LIFE int,\ + LAST_BUILD_DATETIME datetime,\ + ORIGIN_DATETIME datetime,\ + ENABLE_AUTOPOST enum('N','Y') default 'N',\ + KEEP_METADATA enum('N','Y') default 'Y',\ + UPLOAD_FORMAT int default 2,\ + UPLOAD_CHANNELS int default 2,\ + UPLOAD_SAMPRATE int default 44100,\ + UPLOAD_BITRATE int default 32000,\ + UPLOAD_QUALITY int default 0,\ + UPLOAD_EXTENSION char(16) default \"mp3\",\ + NORMALIZE_LEVEL int default -100,\ + REDIRECT_PATH char(255),\ + MEDIA_LINK_MODE int default 0,\ + index KEY_NAME_IDX(KEY_NAME))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create PODCASTS Table + // + sql="create table if not exists PODCASTS (\ + ID int unsigned auto_increment not null primary key,\ + FEED_ID int unsigned not null,\ + STATUS int unsigned default 1,\ + ITEM_TITLE char(255),\ + ITEM_DESCRIPTION text,\ + ITEM_CATEGORY char(64),\ + ITEM_LINK char(255),\ + ITEM_COMMENTS char(255),\ + ITEM_AUTHOR char(255),\ + ITEM_SOURCE_TEXT char(64),\ + ITEM_SOURCE_URL char(255),\ + AUDIO_FILENAME char(255),\ + AUDIO_LENGTH int unsigned,\ + AUDIO_TIME int unsigned,\ + SHELF_LIFE int,\ + ORIGIN_DATETIME datetime,\ + EFFECTIVE_DATETIME datetime,\ + index FEED_ID_IDX(FEED_ID,ORIGIN_DATETIME))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create AUX_METADATA Table + // + sql="create table if not exists AUX_METADATA (\ + ID int unsigned auto_increment not null primary key,\ + FEED_ID int unsigned,\ + VAR_NAME char(16),\ + CAPTION char(64),\ + index FEED_ID_IDX(FEED_ID))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create FEED_PERMS table + // + sql=QString("create table if not exists FEED_PERMS (\ + ID int unsigned auto_increment not null primary key,\ + USER_NAME char(255),\ + KEY_NAME char(8),\ + index USER_IDX (USER_NAME),\ + index KEYNAME_IDX (KEY_NAME))"); + if(!RunQuery(sql)) { + return false; + } + + // + // Create WEB_CONNECTIONS Table + // + sql=QString("create table if not exists WEB_CONNECTIONS (\ + SESSION_ID int unsigned not null primary key,\ + LOGIN_NAME char(255),\ + IP_ADDRESS char(16),\ + TIME_STAMP datetime)"); + if(!RunQuery(sql)) { + return false; + } + + // + // Create SWITCHER_NODES Table + // + sql="create table if not exists SWITCHER_NODES (\ + ID int not null auto_increment primary key,\ + STATION_NAME char(64),\ + MATRIX int,\ + BASE_OUTPUT int default 0,\ + HOSTNAME char(64),\ + PASSWORD char(64),\ + TCP_PORT int,\ + DESCRIPTION char(255),\ + index STATION_IDX (STATION_NAME,MATRIX))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create ENCODERS Table + // + sql="create table if not exists ENCODERS (\ + ID int not null auto_increment primary key,\ + NAME char(32) not null,\ + STATION_NAME char(64),\ + COMMAND_LINE char(255),\ + DEFAULT_EXTENSION char(16),\ + index NAME_IDX(NAME,STATION_NAME))"; + if(!RunQuery(sql)) { + return false; + } + // Ensure that dynamic format IDs start after 100 + sql="insert into ENCODERS set ID=100,NAME=\"dummy\""; + if(!RunQuery(sql)) { + return false; + } + sql="delete from ENCODERS where ID=100"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create ENCODER_BITRATES Table + // + sql="create table if not exists ENCODER_BITRATES (\ + ID int not null auto_increment primary key,\ + ENCODER_ID int not null,\ + BITRATES int not null,\ + index ENCODER_ID_IDX(ENCODER_ID))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create ENCODER_CHANNELS Table + // + sql="create table if not exists ENCODER_CHANNELS (\ + ID int not null auto_increment primary key,\ + ENCODER_ID int not null,\ + CHANNELS int not null,\ + index ENCODER_ID_IDX(ENCODER_ID))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create ENCODER_SAMPLERATES Table + // + sql="create table if not exists ENCODER_SAMPLERATES (\ + ID int not null auto_increment primary key,\ + ENCODER_ID int not null,\ + SAMPLERATES int not null,\ + index ENCODER_ID_IDX(ENCODER_ID))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create GPOS Table + // + sql="create table if not exists GPOS (\ + ID int auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + MATRIX int not null,\ + NUMBER int not null,\ + MACRO_CART int default 0,\ + OFF_MACRO_CART int default 0,\ + index MATRIX_IDX (STATION_NAME,MATRIX,NUMBER))"; + if(!RunQuery(sql)) { + return false; + } + + // + // DROPBOX_PATHS Table + // + sql="create table if not exists DROPBOX_PATHS (\ + ID int auto_increment not null primary key,\ + DROPBOX_ID int not null,\ + FILE_PATH char(255) not null,\ + FILE_DATETIME datetime,\ + index FILE_PATH_IDX (DROPBOX_ID,FILE_PATH))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create NOWNEXT_PLUGINS Table + // + sql="create table if not exists NOWNEXT_PLUGINS (\ + ID int auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + LOG_MACHINE int unsigned not null default 0,\ + PLUGIN_PATH char(255),\ + PLUGIN_ARG char(255),\ + index STATION_IDX (STATION_NAME,LOG_MACHINE))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create SYSTEM Table + // + sql=QString().sprintf("create table if not exists SYSTEM (\ + ID int auto_increment not null primary key,\ + SAMPLE_RATE int unsigned default %d,\ + DUP_CART_TITLES enum('N','Y') not null default 'Y',\ + MAX_POST_LENGTH int unsigned default %u,\ + ISCI_XREFERENCE_PATH char(255),\ + TEMP_CART_GROUP char(10))", + RD_DEFAULT_SAMPLE_RATE, + RD_DEFAULT_MAX_POST_LENGTH); + if(!RunQuery(sql)) { + return false; + } + + // + // Create IMPORT_TEMPLATES table + // + sql="create table if not exists IMPORT_TEMPLATES (\ + NAME char(64) not null primary key,\ + CART_OFFSET int,\ + CART_LENGTH int,\ + TITLE_OFFSET int,\ + TITLE_LENGTH int,\ + HOURS_OFFSET int,\ + HOURS_LENGTH int,\ + MINUTES_OFFSET int,\ + MINUTES_LENGTH int,\ + SECONDS_OFFSET int,\ + SECONDS_LENGTH int,\ + LEN_HOURS_OFFSET int,\ + LEN_HOURS_LENGTH int,\ + LEN_MINUTES_OFFSET int,\ + LEN_MINUTES_LENGTH int,\ + LEN_SECONDS_OFFSET int,\ + LEN_SECONDS_LENGTH int,\ + LENGTH_OFFSET int,\ + LENGTH_LENGTH int,\ + DATA_OFFSET int,\ + DATA_LENGTH int,\ + EVENT_ID_OFFSET int,\ + EVENT_ID_LENGTH int,\ + ANNC_TYPE_OFFSET int,\ + ANNC_TYPE_LENGTH int)"; + if(!RunQuery(sql)) { + return false; + } + UpdateImportFormats(); + + // + // Create REPLICATORS Table + // + sql=QString().sprintf("create table if not exists REPLICATORS (\ + NAME char(32) not null primary key,\ + DESCRIPTION char(64),\ + TYPE_ID int unsigned not null,\ + STATION_NAME char(64),\ + FORMAT int unsigned default 0,\ + CHANNELS int unsigned default 2,\ + SAMPRATE int unsigned default %u,\ + BITRATE int unsigned default 0,\ + QUALITY int unsigned default 0,\ + URL char(255),\ + URL_USERNAME char(64),\ + URL_PASSWORD char(64),\ + ENABLE_METADATA enum('N','Y') default 'N',\ + NORMALIZATION_LEVEL int default 0,\ + index TYPE_ID_IDX (TYPE_ID))", + RD_DEFAULT_SAMPLE_RATE); + if(!RunQuery(sql)) { + return false; + } + + // + // Create REPLICATOR_MAP Table + // + sql="create table if not exists REPLICATOR_MAP (\ + ID int unsigned not null auto_increment primary key,\ + REPLICATOR_NAME char(32) not null,\ + GROUP_NAME char(10) not null,\ + index REPLICATOR_NAME_IDX(REPLICATOR_NAME),\ + index GROUP_NAME_IDX(GROUP_NAME))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create REPL_CART_STATE Table + // + sql="create table if not exists REPL_CART_STATE (\ + ID int unsigned not null auto_increment primary key, \ + REPLICATOR_NAME char(32) not null,\ + CART_NUMBER int unsigned not null,\ + POSTED_FILENAME char(255),\ + ITEM_DATETIME datetime not null,\ + REPOST enum('N','Y') default 'N',\ + unique REPLICATOR_NAME_IDX(REPLICATOR_NAME,CART_NUMBER,POSTED_FILENAME))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create REPL_CUT_STATE Table + // + sql="create table if not exists REPL_CUT_STATE (\ + ID int unsigned not null auto_increment primary key,\ + REPLICATOR_NAME char(32) not null,\ + CUT_NAME char(12) not null,\ + ITEM_DATETIME datetime not null,\ + unique REPLICATOR_NAME_IDX(REPLICATOR_NAME,CUT_NAME))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create ISCI_XREFERENCE Table + // + sql="create table if not exists ISCI_XREFERENCE (\ + ID int unsigned not null auto_increment primary key,\ + CART_NUMBER int unsigned not null,\ + ISCI char(32) not null,\ + FILENAME char(64) not null,\ + LATEST_DATE date not null,\ + TYPE char(1) not null,\ + ADVERTISER_NAME char(30),\ + PRODUCT_NAME char(35),\ + CREATIVE_TITLE char(30),\ + REGION_NAME char(80),\ + index CART_NUMBER_IDX(CART_NUMBER),\ + index TYPE_IDX(TYPE,LATEST_DATE),\ + index LATEST_DATE_IDX(LATEST_DATE))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create RDHOTKEYS table + // + sql=QString("CREATE TABLE IF NOT EXISTS RDHOTKEYS (\ + ID int unsigned not null auto_increment primary key, \ + STATION_NAME CHAR(64), \ + MODULE_NAME CHAR(64), \ + KEY_ID int, \ + KEY_VALUE CHAR(64), \ + KEY_LABEL CHAR(64)) "); + if(!RunQuery(sql)) { + return false; + } + + // + // Create JACK_CLIENTS Table + // + sql=QString("create table if not exists JACK_CLIENTS (\ + ID int unsigned auto_increment not null primary key, \ + STATION_NAME char(64) not null,\ + DESCRIPTION char(64),\ + COMMAND_LINE char(255) not null,\ + index IDX_STATION_NAME (STATION_NAME))"); + if(!RunQuery(sql)) { + return false; + } + + // + // Create CARTSLOTS Table + // + sql=QString("create table if not exists CARTSLOTS (")+ + "ID int unsigned auto_increment not null primary key,"+ + "STATION_NAME char(64) not null,"+ + "SLOT_NUMBER int unsigned not null,"+ + "MODE int not null default 0,"+ + "DEFAULT_MODE int not null default -1,"+ + "STOP_ACTION int not null default 0,"+ + "DEFAULT_STOP_ACTION int not null default -1,"+ + "CART_NUMBER int default 0,"+ + "DEFAULT_CART_NUMBER int not null default 0,"+ + "HOOK_MODE int default 0,"+ + "DEFAULT_HOOK_MODE int not null default -1,"+ + "SERVICE_NAME char(10),"+ + "CARD int not null default 0,"+ + "INPUT_PORT int not null default 0,"+ + "OUTPUT_PORT int not null default 0,"+ + "index STATION_NAME_IDX(STATION_NAME,SLOT_NUMBER))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create LIVEWIRE_GPIO_SLOTS table + // + sql=QString("create table if not exists LIVEWIRE_GPIO_SLOTS (")+ + "ID int unsigned auto_increment not null primary key,"+ + "STATION_NAME char(64) not null,"+ + "MATRIX int not null,"+ + "SLOT int not null,"+ + "IP_ADDRESS char(15),"+ + "SOURCE_NUMBER int,"+ + "index STATION_NAME_IDX(STATION_NAME,MATRIX))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create RDAIRPLAY_CHANNELS table + // + sql=QString("create table if not exists RDAIRPLAY_CHANNELS (")+ + "ID int unsigned auto_increment not null primary key,"+ + "STATION_NAME char(64) not null,"+ + "INSTANCE int unsigned not null,"+ + "CARD int not null default 0,"+ + "PORT int not null default 0,"+ + "START_RML char(255),"+ + "STOP_RML char(255),"+ + "GPIO_TYPE int unsigned default 0,"+ + "START_GPI_MATRIX int not null default -1,"+ + "START_GPI_LINE int not null default -1,"+ + "START_GPO_MATRIX int not null default -1,"+ + "START_GPO_LINE int not null default -1,"+ + "STOP_GPI_MATRIX int not null default -1,"+ + "STOP_GPI_LINE int not null default -1,"+ + "STOP_GPO_MATRIX int not null default -1,"+ + "STOP_GPO_LINE int not null default -1,"+ + "index STATION_NAME_IDX(STATION_NAME,INSTANCE))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create RDPANEL_CHANNELS table + // + sql=QString("create table if not exists RDPANEL_CHANNELS (")+ + "ID int unsigned auto_increment not null primary key,"+ + "STATION_NAME char(64) not null,"+ + "INSTANCE int unsigned not null,"+ + "CARD int not null default 0,"+ + "PORT int not null default 0,"+ + "START_RML char(255),"+ + "STOP_RML char(255),"+ + "GPIO_TYPE int unsigned default 0,"+ + "START_GPI_MATRIX int not null default -1,"+ + "START_GPI_LINE int not null default -1,"+ + "START_GPO_MATRIX int not null default -1,"+ + "START_GPO_LINE int not null default -1,"+ + "STOP_GPI_MATRIX int not null default -1,"+ + "STOP_GPI_LINE int not null default -1,"+ + "STOP_GPO_MATRIX int not null default -1,"+ + "STOP_GPO_LINE int not null default -1,"+ + "index STATION_NAME_IDX(STATION_NAME,INSTANCE))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create LOG_MODES table + // + sql=QString("create table if not exists LOG_MODES (")+ + "ID int unsigned auto_increment not null primary key,"+ + "STATION_NAME char(64) not null,"+ + "MACHINE int unsigned not null,"+ + "START_MODE int not null default 0,"+ + "OP_MODE int not null default 2,"+ + "index STATION_NAME_IDX(STATION_NAME,MACHINE))"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create DROPBOX_SCHED_CODES table + // + sql=QString("create table if not exists DROPBOX_SCHED_CODES(")+ + "ID int auto_increment not null primary key,"+ + "DROPBOX_ID int not null,"+ + "SCHED_CODE char(11) not null," + "index DROPBOX_ID_IDX(DROPBOX_ID),"+ + "index SCHED_CODE_IDX(SCHED_CODE))"; + if(!RunQuery(sql)) { + return false; + } + + return true; +} + + +bool InitDb(QString name,QString pwd,QString station_name) +{ + QString sql; + + // + // Create Default Admin Account + // + sql=QString().sprintf("insert into USERS \ + (LOGIN_NAME,PASSWORD,FULL_NAME,DESCRIPTION,ADMIN_USERS_PRIV,\ + ADMIN_CONFIG_PRIV)\ + values (\"%s\",PASSWORD(\"%s\"),\"%s\",\"%s\",\"Y\",\"Y\")", + RDA_LOGIN_NAME, + RDA_PASSWORD, + RDA_FULLNAME, + RDA_DESCRIPTION); + if(!RunQuery(sql)) { + return false; + } + + // + // Create Default User Account + // + sql=QString().sprintf("insert into USERS (LOGIN_NAME,PASSWORD,FULL_NAME,\ + DESCRIPTION,CREATE_CARTS_PRIV,DELETE_CARTS_PRIV,MODIFY_CARTS_PRIV,\ + EDIT_AUDIO_PRIV,ASSIGN_CART_PRIV,CREATE_LOG_PRIV,DELETE_LOG_PRIV,\ + DELETE_REC_PRIV,PLAYOUT_LOG_PRIV,ARRANGE_LOG_PRIV,ADDTO_LOG_PRIV,\ + REMOVEFROM_LOG_PRIV,CONFIG_PANELS_PRIV,VOICETRACK_LOG_PRIV,\ + EDIT_CATCHES_PRIV,MODIFY_TEMPLATE_PRIV,\ + ADD_PODCAST_PRIV,EDIT_PODCAST_PRIV,DELETE_PODCAST_PRIV)\ + values (\"%s\",PASSWORD(\"%s\"),\"%s\",\"%s\",\ + 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')", + RD_USER_LOGIN_NAME, + RD_USER_PASSWORD, + RD_USER_FULL_NAME, + RD_USER_DESCRIPTION); + if(!RunQuery(sql)) { + return false; + } + + // + // Create Default System-wide Settings Record + // + sql="insert into SYSTEM set ID=1"; + if(!RunQuery(sql)) { + return false; + } + + + // + // Create Default Workstation + // + struct hostent *hostent=gethostbyname((const char *)station_name); + if(hostent==NULL) { + sql=QString().sprintf("insert into STATIONS \ + (NAME,DESCRIPTION,USER_NAME,DEFAULT_NAME) \ + VALUES (\"%s\",\"%s\",\"%s\",\"%s\")", + (const char *)RDEscapeString(station_name), + RD_STATION_DESCRIPTION, + RD_USER_LOGIN_NAME, + RD_USER_LOGIN_NAME); + } + else { + sql=QString().sprintf("insert into STATIONS \ + (NAME,DESCRIPTION,USER_NAME,DEFAULT_NAME,IPV4_ADDRESS) \ + VALUES (\"%s\",\"%s\",\"%s\",\"%s\",\"%d.%d.%d.%d\")", + (const char *)RDEscapeString(station_name), + RD_STATION_DESCRIPTION, + RD_USER_LOGIN_NAME, + RD_USER_LOGIN_NAME, + 0xFF&hostent->h_addr[0],0xFF&hostent->h_addr[1], + 0xFF&hostent->h_addr[2],0xFF&hostent->h_addr[3]); + } + if(!RunQuery(sql)) { + return false; + } + for(unsigned i=0;i<10;i++) { + sql=QString("insert into RDAIRPLAY_CHANNELS set ")+ + "STATION_NAME=\""+RDEscapeString(station_name)+"\","+ + QString().sprintf("INSTANCE=%u",i); + if(!RunQuery(sql)) { + return false; + } + } + for(unsigned i=0;i<10;i++) { + sql=QString("insert into RDPANEL_CHANNELS set ")+ + "STATION_NAME=\""+RDEscapeString(station_name)+"\","+ + QString().sprintf("INSTANCE=%u",i); + if(!RunQuery(sql)) { + return false; + } + } + for(unsigned i=0;i<3;i++) { + sql=QString("insert into LOG_MODES set ")+ + "STATION_NAME=\""+RDEscapeString(station_name)+"\","+ + QString().sprintf("MACHINE=%u",i); + if(!RunQuery(sql)) { + return false; + } + } + + // + // Create Test Tone Cart + // + sql="insert into CART(TYPE,NUMBER,GROUP_NAME,TITLE,ARTIST,CUT_QUANTITY,\ + FORCED_LENGTH,METADATA_DATETIME)\ + values (1,999999,\"TEST\",\"Test Tone\",\"Rivendell Radio Automation\",1,10000,now())"; + if(!RunQuery(sql)) { + return false; + } + + // + // Create Default Audio Cut + // + sql=QString().sprintf("insert into CUTS set CUT_NAME=\"999999_001\",\ + CART_NUMBER=999999,\ + DESCRIPTION=\"1 kHz at Reference Level [-16 dBFS]\",\ + OUTCUE=\"[tone]\",CODING_FORMAT=0,\ + SAMPLE_RATE=%d,BIT_RATE=0,\ + CHANNELS=2,LENGTH=10000,START_POINT=0,END_POINT=10000,\ + ORIGIN_DATETIME=NOW(),ORIGIN_NAME=\"RDGen\"", + RD_DEFAULT_SAMPLE_RATE); + if(!RunQuery(sql)) { + return false; + } + + // + // Create Clipboard Entry + // + sql="insert into CLIPBOARD set CUT_NAME=\"clip\",CART_NUMBER=0,\ + DESCRIPTION=\"Default Clipboard\""; + if(!RunQuery(sql)) { + return false; + } + + // + // Create Default Service + // + RDSvc *svc=new RDSvc(RD_SERVICE_NAME); + svc->create(""); + svc->setDescription(RD_SERVICE_DESCRIPTION); + delete svc; + + // + // Create Default Groups + // + + struct Group + { + const char *group; + const char *description; + int start; + int end; + bool now_next; + bool rpt_traffic; + bool rpt_music; + bool macro; + }; + + static const struct Group group[] = { + {"TEMP","Temporary Carts",0,0,false,false,false,false}, + {"TEST","Test Carts",0,0,false,false,false,false}, + {"TRAFFIC","Traffic Carts",1,10000,false,true,false,false}, + {"MUSIC","Music Carts",10001,40000,true,false,true,false}, + {"BEDS","Music Bed Carts",40001,45000,false,false,false,false}, + {"STINGS","Short stingers",45001,50000,false,false,false,false}, + {"MACROS","Macro Carts",50001,60000,false,false,false,true}, + {"LEGAL","Legal IDs",60001,60100,false,false,false,false}, + {"IDENTS","General IDs",60101,60500,false,false,false,false}, + {NULL,NULL,0,0,false,false,false,false}, + }; + + for (const struct Group *g = group; g->group != NULL; g++){ + + // Create the group + sql=QString().sprintf ("insert into GROUPS (NAME,DESCRIPTION,DEFAULT_CART_TYPE,\ + DEFAULT_LOW_CART,DEFAULT_HIGH_CART,REPORT_TFC,REPORT_MUS,ENABLE_NOW_NEXT) \ + values (\"%s\",\"%s\",%d,%d,%d,\'%s\',\'%s\',\'%s\')", + g->group, + g->description, + g->macro ? 2:1, + g->start, + g->end, + g->rpt_traffic ? "Y" :"N", + g->rpt_music ? "Y" :"N", + g->now_next ? "Y" :"N"); + if(!RunQuery(sql)) { + return false; + } + // Add it to the user permissions table for the default user + sql=QString().sprintf("insert into USER_PERMS (USER_NAME,GROUP_NAME) \ + values (\"%s\",\"%s\")",RD_USER_LOGIN_NAME,g->group); + if(!RunQuery(sql)) { + return false; + } + // Add it to the audio permsmissions table + sql=QString().sprintf("insert into AUDIO_PERMS (GROUP_NAME,SERVICE_NAME) \ + values (\"%s\",\"%s\")",g->group,RD_SERVICE_NAME); + if(!RunQuery(sql)) { + return false; + } + } + + // + // Create Sample Log + // + sql=RDCreateLogTableSql("SAMPLE_LOG"); + if(!RunQuery(sql)) { + return false; + } + sql="insert into LOGS (NAME,SERVICE,DESCRIPTION,ORIGIN_USER,ORIGIN_DATETIME)\ + values (\"SAMPLE\",\"Production\",\"Sample Log\",\"user\",NOW())"; + if(!RunQuery(sql)) { + return false; + } + + // + // Generate Hotkey Definitions + // + if (!UpdateRDAirplayHotkeys(station_name)) { + return false; + } + + // + // Generate Version Number + // + sql=QString().sprintf("insert into VERSION (DB) values (%d)", + RD_VERSION_DATABASE); + if(!RunQuery(sql)) { + return false; + } + + // + // Generate Audio + // + QString filename= + QString().sprintf("%s/999999_001.%s", + RDConfiguration()->audioRoot().ascii(), + RDConfiguration()->audioExtension().ascii()); + + QString cmd=QString().sprintf("rdgen -t 10 -l 16 %s", + (const char *)filename); + system((const char *)cmd); + if(getuid()==0) { + chown(filename,RDConfiguration()->uid(),RDConfiguration()->gid()); + chmod (filename,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); + } + + return true; +} + + +// +// The following two methods are called by the 185=>186 schema update +// +void ConvertTimeField(const QString &table,const QString &field) +{ + QString sql; + QSqlQuery *q; + QSqlQuery *q1; + + // + // Create temporary field + // + sql=QString().sprintf("alter table %s add column %s_TEMP int after %s", + (const char *)table, + (const char *)field, + (const char *)field); + q=new QSqlQuery(sql); + delete q; + + // + // Copy data to temporary field + // + sql=QString().sprintf("select ID,%s from %s", + (const char *)field, + (const char *)table); + q=new QSqlQuery(sql); + while(q->next()) { + if(!q->value(1).isNull()) { + sql=QString().sprintf("update %s set %s_TEMP=%d where ID=%d", + (const char *)table, + (const char *)field, + QTime().msecsTo(q->value(1).toTime()), + q->value(0).toInt()); + q1=new QSqlQuery(sql); + delete q1; + } + } + delete q; + + // + // Convert primary field + // + sql=QString().sprintf("alter table %s modify column %s int", + (const char *)table, + (const char *)field); + q=new QSqlQuery(sql); + delete q; + + // + // Copy data back to primary field + // + sql=QString().sprintf("select ID,%s_TEMP from %s", + (const char *)field, + (const char *)table); + q=new QSqlQuery(sql); + while(q->next()) { + if(!q->value(1).isNull()) { + sql=QString().sprintf("update %s set %s=%d where ID=%d", + (const char *)table, + (const char *)field, + q->value(1).toInt(), + q->value(0).toInt()); + q1=new QSqlQuery(sql); + delete q1; + } + } + delete q; + + // + // Delete Temporary field + // + sql=QString().sprintf("alter table %s drop column %s_TEMP", + (const char *)table, + (const char *)field); + q=new QSqlQuery(sql); + delete q; +} + + +void UpdateLogTable(const QString &table) +{ + QString sql; + QSqlQuery *q; + + // + // Drop POST_TIME + // + sql=QString().sprintf("alter table %s drop column POST_TIME", + (const char *)table); + q=new QSqlQuery(sql); + delete q; + + // + // Convert Fields + // + ConvertTimeField(table,"START_TIME"); + ConvertTimeField(table,"LINK_START_TIME"); +} + + +// +// Main Schema Update Routine +// +int UpdateDb(int ver) +{ + QString cmd; + QString sql; + QSqlQuery *q; + QSqlQuery *q1; + QSqlQuery *q2; + QSqlQuery *q3; + RDCart *cart; + unsigned dev; + QString tablename; + + // + // Create backup + // + if(!admin_skip_backup) { + if(admin_backup_filename.isEmpty()) { + if(getenv("HOME")==NULL) { + admin_backup_filename="/tmp"; + } + else { + admin_backup_filename=getenv("HOME"); + } + admin_backup_filename+= + QString().sprintf("/rdbackup-%s-%d.sql.gz", + (const char *)QDate::currentDate(). + toString("yyyyMMdd"),ver); + } + cmd=QString().sprintf("mysqldump -h %s -u %s -p%s %s | gzip -q -c - > %s", + (const char *)admin_config->mysqlHostname(), + (const char *)admin_config->mysqlUsername(), + (const char *)admin_config->mysqlPassword(), + (const char *)admin_config->mysqlDbname(), + (const char *)admin_backup_filename); + if(system(cmd)!=0) { + return UPDATEDB_BACKUP_FAILED; + } + } + + // **** Start of version updates **** + + if(ver<3) { + // + // Create RDAIRPLAY Table + // + sql="create table if not exists RDAIRPLAY (\ + ID int not null primary key,\ + STATION char(40) not null,\ + INSTANCE int unsigned not null,\ + AUTO_CARD0 int default -1,\ + AUTO_STREAM0 int default -1,\ + AUTO_PORT0 int default -1,\ + AUTO_CARD1 int default -1,\ + AUTO_STREAM1 int default -1,\ + AUTO_PORT1 int default -1,\ + PANEL_CARD0 int default -1,\ + PANEL_STREAM0 int default -1,\ + PANEL_PORT0 int default -1,\ + PANEL_CARD1 int default -1,\ + PANEL_STREAM1 int default -1,\ + PANEL_PORT1 int default -1,\ + index STATION_IDX (STATION,INSTANCE))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + // + // Create Default RDAirPlay Configuration + // + sql="insert into RDAIRPLAY (STATION,INSTANCE) \ + values (\"DEFAULT\",0)"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + } + + if(ver<4) { + if(!RunQuery( + "alter table RDAIRPLAY modify ID int not null auto_increment")) { + return UPDATEDB_QUERY_FAILED; + } + } + + if(ver<5) { + q=new QSqlQuery("select NAME from LOGS"); + while(q->next()) { + RunQuery(QString(). + sprintf("alter table %s_LOG add SOURCE int not null after COUNT", + (const char *)q->value(0).toString())); + } + delete q; + } + + if(ver<6) { + // + // Update RDAIRPLAY Structure + // + q=new QSqlQuery("alter table RDAIRPLAY add column CARD int default -1"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column PORT0 int default -1"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column PORT1 int default -1"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column PORT2 int default -1"); + delete q; + q=new + QSqlQuery("alter table RDAIRPLAY add column STREAM0 int default -1"); + delete q; + q=new + QSqlQuery("alter table RDAIRPLAY add column STREAM1 int default -1"); + delete q; + q=new + QSqlQuery("alter table RDAIRPLAY add column STREAM2 int default -1"); + delete q; + q=new + QSqlQuery("alter table RDAIRPLAY add column STREAM3 int default -1"); + delete q; + q=new + QSqlQuery("alter table RDAIRPLAY add column STREAM4 int default -1"); + delete q; + q=new + QSqlQuery("alter table RDAIRPLAY add column STREAM5 int default -1"); + delete q; + q=new + QSqlQuery("alter table RDAIRPLAY add column STREAM6 int default -1"); + delete q; + q=new + QSqlQuery("alter table RDAIRPLAY add column STREAM7 int default -1"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY drop column AUTO_CARD0"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY drop column AUTO_CARD1"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY drop column AUTO_STREAM0"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY drop column AUTO_STREAM1"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY drop column AUTO_PORT0"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY drop column AUTO_PORT1"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY drop column PANEL_CARD0"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY drop column PANEL_CARD1"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY drop column PANEL_STREAM0"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY drop column PANEL_STREAM1"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY drop column PANEL_PORT0"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY drop column PANEL_PORT1"); + delete q; + } + + if(ver<7) { + q=new + QSqlQuery("alter table RDAIRPLAY add column SEGUE_LENGTH int default 0"); + delete q; + } + + if(ver<8) { + q=new + QSqlQuery("alter table RDAIRPLAY add column PORT3 int default -1"); + delete q; + q=new + QSqlQuery("alter table RDAIRPLAY add column OP_MODE int default 0"); + delete q; + q=new + QSqlQuery("alter table RDAIRPLAY add column START_MODE int default 0"); + delete q; + q=new + QSqlQuery("alter table RDAIRPLAY add column PIE_COUNT_LENGTH int default 15000"); + delete q; + q=new + QSqlQuery("alter table RDAIRPLAY add column PIE_COUNT_ENDPOINT int default 0"); + delete q; + } + + if(ver<9) { + q=new QSqlQuery("alter table RDAIRPLAY add column PORT4 int default -1"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column PORT5 int default -1"); + delete q; + } + + if(ver<10) { + q=new QSqlQuery("select NAME from LOGS"); + while(q->next()) { + RunQuery(QString(). + sprintf("alter table %s_LOG add TYPE int default 0 after COUNT", + (const char *)q->value(0).toString())); + RunQuery(QString(). + sprintf("alter table %s_LOG add COMMENT char(255)", + (const char *)q->value(0).toString())); + RunQuery(QString(). + sprintf("alter table %s_LOG add LABEL char(10)", + (const char *)q->value(0).toString())); + RunQuery(QString(). + sprintf("alter table %s_LOG add POST_TIME time default '24:00:00'", + (const char *)q->value(0).toString())); + RunQuery(QString(). + sprintf("alter table %s_LOG add index LABEL_IDX (LABEL)", + (const char *)q->value(0).toString())); + } + delete q; + } + + + if(ver<11) { + q=new QSqlQuery("alter table RDAIRPLAY add column CHECK_TIMESYNC enum('N','Y') default 'N'"); + delete q; + + // + // Create PANELS Table + // + sql="create table if not exists PANELS (\ + ID int not null primary key,\ + TYPE int not null,\ + OWNER char(64) not null,\ + PANEL_NO int not null,\ + ROW_NO int not null,\ + COLUMN_NO int not null,\ + LABEL char(64),\ + CART int,\ + DEFAULT_COLOR char(6),\ + index OWNER_IDX (OWNER))"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<12) { + q=new QSqlQuery("alter table RDAIRPLAY add column STATION_PANELS int default 3"); + delete q; + + q=new QSqlQuery("alter table RDAIRPLAY add column USER_PANELS int default 3"); + delete q; + } + + if(ver<13) { + sql="drop table PANELS"; + q=new QSqlQuery(sql); + delete q; + + sql="create table if not exists PANELS (\ + ID int auto_increment not null primary key,\ + TYPE int not null,\ + OWNER char(64) not null,\ + PANEL_NO int not null,\ + ROW_NO int not null,\ + COLUMN_NO int not null,\ + LABEL char(64),\ + CART int,\ + DEFAULT_COLOR char(6),\ + index OWNER_IDX (OWNER))"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<14) { + sql="drop table PANELS"; + q=new QSqlQuery(sql); + delete q; + + sql="create table if not exists PANELS (\ + ID int auto_increment not null primary key,\ + TYPE int not null,\ + OWNER char(64) not null,\ + PANEL_NO int not null,\ + ROW_NO int not null,\ + COLUMN_NO int not null,\ + LABEL char(64),\ + CART int,\ + DEFAULT_COLOR char(6),\ + index LOAD_IDX (TYPE,OWNER,PANEL_NO),\ + index SAVE_IDX (TYPE,OWNER,PANEL_NO,ROW_NO,COLUMN_NO))"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<15) { + q=new QSqlQuery("alter table PANELS drop column DEFAULT_COLOR"); + delete q; + + q=new QSqlQuery("alter table PANELS add column DEFAULT_COLOR char(7)"); + delete q; + } + + if(ver<16) { + // + // Create MATRICES Table + // + sql="create table if not exists MATRICES (\ + ID int auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + NAME char(64),\ + MATRIX int not null,\ + TYPE int not null,\ + PORT int not null,\ + GPIO_DEVICE char(255),\ + INPUTS int not null,\ + OUTPUTS int not null,\ + GPIS int not null,\ + GPOS int not null,\ + index MATRIX_IDX (STATION_NAME,MATRIX))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + // + // Create INPUTS Table + // + sql="create table if not exists INPUTS (\ + ID int auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + MATRIX int not null,\ + NUMBER int not null,\ + NAME char(64),\ + FEED_NAME char(8),\ + index MATRIX_IDX (STATION_NAME,MATRIX,NUMBER))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + // + // Create OUTPUTS Table + // + sql="create table if not exists OUTPUTS (\ + ID int auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + MATRIX int not null,\ + NUMBER int not null,\ + NAME char(64),\ + index MATRIX_IDX (STATION_NAME,MATRIX,NUMBER))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + } + + if(ver<17) { + q=new QSqlQuery("alter table INPUTS add column CHANNEL_MODE int"); + delete q; + } + + if(ver<18) { + q=new QSqlQuery("alter table STATIONS add column IPV4_ADDRESS char(15)"); + delete q; + } + + if(ver<19) { + q=new QSqlQuery("create table if not exists EVENTS (\ + ID int auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + SUN enum('N','Y') not null,\ + MON enum('N','Y') not null,\ + TUE enum('N','Y') not null,\ + WED enum('N','Y') not null,\ + THU enum('N','Y') not null,\ + FRI enum('N','Y') not null,\ + SAT enum('N','Y') not null,\ + TIME time not null,\ + DESCRIPTION char(64),\ + COMMAND char(255),\ + index STATION_IDX (STATION_NAME),\ + index SUN_IDX (STATION_NAME,SUN),\ + index MON_IDX (STATION_NAME,MON),\ + index TUE_IDX (STATION_NAME,TUE),\ + index WED_IDX (STATION_NAME,WED),\ + index THU_IDX (STATION_NAME,THU),\ + index FRI_IDX (STATION_NAME,FRI),\ + index SAT_IDX (STATION_NAME,SAT))"); + delete q; + } + + if(ver<20) { + q=new QSqlQuery("alter table CART add column MACROS text"); + delete q; + } + + if(ver<21) { + q=new + QSqlQuery("alter table RECORDINGS add column MACRO_CART int default -1"); + delete q; + q=new + QSqlQuery("drop table EVENTS"); + delete q; + } + + if(ver<22) { + q=new QSqlQuery("alter table DECKS drop column SWITCH_TYPE"); + delete q; + q=new QSqlQuery("alter table DECKS drop column TTY_ID"); + delete q; + q=new QSqlQuery("alter table DECKS add column SWITCH_STATION char(64)"); + delete q; + q=new + QSqlQuery("alter table DECKS add column SWITCH_MATRIX int default -1"); + delete q; + q=new + QSqlQuery("alter table DECKS add column SWITCH_OUTPUT int default -1"); + delete q; + q=new + QSqlQuery("alter table DECKS add column SWITCH_DELAY int default 0"); + delete q; + } + + if(ver<23) { + q=new QSqlQuery("alter table RECORDINGS drop column SOURCE_NAME"); + delete q; + q=new + QSqlQuery("alter table RECORDINGS add column \ + SWITCH_INPUT int default -1"); + delete q; + q=new QSqlQuery("drop table SOURCES"); + delete q; + } + + if(ver<24) { + q=new QSqlQuery("alter table RECORDINGS add column \ + TYPE int default 0 after STATION_NAME"); + delete q; + q=new QSqlQuery("alter table RECORDINGS add column \ + SWITCH_OUTPUT int default -1"); + delete q; + q=new QSqlQuery("update RECORDINGS set TYPE=1 where MACRO_CART!=-1"); + delete q; + } + + if(ver<25) { + q=new QSqlQuery("alter table RECORDINGS drop index SUN_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS drop index MON_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS drop index TUE_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS drop index WED_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS drop index THU_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS drop index FRI_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS drop index SAT_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS add column IS_ACTIVE \ + enum('N','Y') default 'Y' after ID"); + delete q; + q=new QSqlQuery("alter table RECORDINGS add index \ + SUN_IDX (STATION_NAME,SUN,IS_ACTIVE)"); + q=new QSqlQuery("alter table RECORDINGS add index \ + MON_IDX (STATION_NAME,MON,IS_ACTIVE)"); + q=new QSqlQuery("alter table RECORDINGS add index \ + TUE_IDX (STATION_NAME,TUE,IS_ACTIVE)"); + q=new QSqlQuery("alter table RECORDINGS add index \ + WED_IDX (STATION_NAME,WED,IS_ACTIVE)"); + q=new QSqlQuery("alter table RECORDINGS add index \ + THU_IDX (STATION_NAME,THU,IS_ACTIVE)"); + q=new QSqlQuery("alter table RECORDINGS add index \ + FRI_IDX (STATION_NAME,FRI,IS_ACTIVE)"); + q=new QSqlQuery("alter table RECORDINGS add index \ + SAT_IDX (STATION_NAME,SAT,IS_ACTIVE)"); + delete q; + } + + if(ver<26) { + q=new QSqlQuery("alter table RECORDINGS drop index SUN_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS drop index MON_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS drop index TUE_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS drop index WED_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS drop index THU_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS drop index FRI_IDX"); + delete q; + q=new QSqlQuery("alter table RECORDINGS drop index SAT_IDX"); + delete q; + } + + // + // Create GPIS Table + // + if(ver<27) { + sql="create table if not exists GPIS (\ + ID int auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + MATRIX int not null,\ + NUMBER int not null,\ + MACRO_CART int default -1,\ + index MATRIX_IDX (STATION_NAME,MATRIX,NUMBER))"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<28) { + sql="alter table CUTS alter column ORIGIN_DATETIME set default NULL"; + q=new QSqlQuery(sql); + delete q; + sql="alter table CUTS alter column START_DATETIME set default NULL"; + q=new QSqlQuery(sql); + delete q; + sql="alter table CUTS alter column END_DATETIME set default NULL"; + q=new QSqlQuery(sql); + delete q; + sql="alter table CUTS alter column START_DAYPART set default NULL"; + q=new QSqlQuery(sql); + delete q; + sql="alter table CUTS alter column END_DAYPART set default NULL"; + q=new QSqlQuery(sql); + delete q; + sql="update CUTS set ORIGIN_DATETIME=NULL where \ + ORIGIN_DATETIME=\"0000-00-00 00:00:00\""; + q=new QSqlQuery(sql); + delete q; + sql="update CUTS set START_DATETIME=NULL where \ + START_DATETIME=\"0000-00-00 00:00:00\""; + q=new QSqlQuery(sql); + delete q; + sql="update CUTS set END_DATETIME=NULL where \ + END_DATETIME=\"0000-00-00 00:00:00\""; + q=new QSqlQuery(sql); + delete q; + + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("alter table %s_LOG drop index START_TIME_IDX", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_LOG alter column START_TIME \ + set default NULL", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_LOG modify column START_TIME int", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_LOG alter column POST_TIME \ + set default NULL", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("update %s_LOG set START_TIME=NULL where \ + START_TIME=\"00:00:00\"", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("update %s_LOG set POST_TIME=NULL where \ + POST_TIME=\"00:00:00\"", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<29) { + q=new QSqlQuery("alter table RECORDINGS add column \ + EXIT_CODE int default 0"); + delete q; + } + + if(ver<30) { + q=new QSqlQuery("alter table RECORDINGS add column \ + ONE_SHOT enum('N','Y') default 'N'"); + delete q; + } + + if(ver<31) { + q=new QSqlQuery("alter table STATIONS add column \ + TIME_OFFSET int default 0"); + delete q; + } + + if(ver<32) { + q=new QSqlQuery("alter table GROUPS add column \ + DEFAULT_LOW_CART int unsigned default 0"); + q=new QSqlQuery("alter table GROUPS add column \ + DEFAULT_HIGH_CART int unsigned default 0"); + delete q; + } + + if(ver<33) { + q=new QSqlQuery("alter table CUTS add column \ + SUN enum('N','Y') default 'Y' after END_DAYPART"); + q=new QSqlQuery("alter table CUTS add column \ + MON enum('N','Y') default 'Y' after END_DAYPART"); + q=new QSqlQuery("alter table CUTS add column \ + TUE enum('N','Y') default 'Y' after END_DAYPART"); + q=new QSqlQuery("alter table CUTS add column \ + WED enum('N','Y') default 'Y' after END_DAYPART"); + q=new QSqlQuery("alter table CUTS add column \ + THU enum('N','Y') default 'Y' after END_DAYPART"); + q=new QSqlQuery("alter table CUTS add column \ + FRI enum('N','Y') default 'Y' after END_DAYPART"); + q=new QSqlQuery("alter table CUTS add column \ + SAT enum('N','Y') default 'Y' after END_DAYPART"); + } + + if(ver<34) { + q=new QSqlQuery("select NAME from LOGS"); + while(q->next()) { + RunQuery(QString().sprintf("alter table %s_LOG \ + add GRACE_TIME int default 0 after START_TIME", + (const char *)q->value(0).toString())); + } + delete q; + } + + if(ver<35) { + q=new QSqlQuery("alter table RDAIRPLAY add column \ + TRANS_LENGTH int default 0 after SEGUE_LENGTH"); + } + + if(ver<36) { + q=new QSqlQuery("select NAME from LOGS"); + while(q->next()) { + RunQuery(QString().sprintf("alter table %s_LOG \ + add POST_POINT enum('N','Y') default 'N'\ + after TIME_TYPE", + (const char *)q->value(0).toString())); + } + delete q; + } + + if(ver<37) { + q=new QSqlQuery("alter table LOGS add column \ + TYPE int not null default 0 after NAME"); + delete q; + } + + if(ver<38) { + sql=QString("create table if not exists EVENTS (\ + NAME char(64) not null primary key,\ + PROPERTIES char(64),\ + DISPLAY_TEXT char(64),\ + NOTE_TEXT char(255),\ + PREPOSITION int default -1,\ + TIME_TYPE int default 0,\ + GRACE_TIME int default 0,\ + POST_POINT enum('N','Y') default 'N',\ + USE_AUTOFILL enum('N','Y') default 'N',\ + USE_TIMESCALE enum('N','Y') default 'N',\ + IMPORT_SOURCE int default 0,\ + START_SLOP int default 0,\ + END_SLOP int default 0,\ + FIRST_TRANS_TYPE int default 0,\ + DEFAULT_TRANS_TYPE int default 0,\ + COLOR char(7))"); + q=new QSqlQuery(sql); + delete q; + } + + if(ver<39) { // Transpose RDLogLine::Stop and RDLogLine::Segue + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString(). + sprintf("update %s_LOG set TRANS_TYPE=100 where TRANS_TYPE=1", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString(). + sprintf("update %s_LOG set TRANS_TYPE=1 where TRANS_TYPE=2", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString(). + sprintf("update %s_LOG set TRANS_TYPE=2 where TRANS_TYPE=100", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<40) { + sql=QString("create table if not exists CLOCKS (\ + NAME char(64) not null primary key,\ + SHORT_NAME char(8),\ + COLOR char(7))"); + q=new QSqlQuery(sql); + delete q; + } + + if(ver<41) { + q=new QSqlQuery("alter table RDAIRPLAY add column \ + CARD0 int default -1 after INSTANCE"); + delete q; + + q=new QSqlQuery("alter table RDAIRPLAY add column \ + CARD1 int default -1 after PORT0"); + delete q; + + q=new QSqlQuery("alter table RDAIRPLAY add column \ + CARD2 int default -1 after PORT1"); + delete q; + + q=new QSqlQuery("alter table RDAIRPLAY add column \ + CARD3 int default -1 after PORT2"); + delete q; + + q=new QSqlQuery("alter table RDAIRPLAY add column \ + CARD4 int default -1 after PORT3"); + delete q; + + q=new QSqlQuery("alter table RDAIRPLAY add column \ + CARD5 int default -1 after PORT4"); + delete q; + } + + if(ver<42) { + q=new QSqlQuery("alter table SERVICES add column CLOCK0 char(64) \ + after DESCRIPTION"); + delete q; + for(int i=1;i<168;i++) { + q=new QSqlQuery(QString().sprintf("alter table SERVICES \ + add column CLOCK%d char(64) after CLOCK%d",i,i-1)); + delete q; + } + } + + if(ver<43) { + q=new QSqlQuery("alter table RDAIRPLAY \ + add column SHOW_AUX_1 enum('N','Y') default 'Y' \ + after USER_PANELS"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY \ + add column SHOW_AUX_2 enum('N','Y') default 'Y' \ + after SHOW_AUX_1"); + delete q; + } + + if(ver<44) { + q=new QSqlQuery("alter table CUTS \ + add column LOCAL_COUNTER int unsigned default 0 \ + after PLAY_COUNTER"); + delete q; + } + + if(ver<45) { + q=new QSqlQuery("alter table CUTS \ + add column EVERGREEN enum('N','Y') default 'N' \ + after CART_NUMBER"); + delete q; + } + + if(ver<46) { + q=new QSqlQuery("alter table CART \ + add column LENGTH_DEVIATION int unsigned default 0 \ + after FORCED_LENGTH"); + delete q; + q=new QSqlQuery("select NUMBER from CART where TYPE=1"); + while(q->next()) { + cart=new RDCart(q->value(0).toUInt()); + cart->calculateAverageLength(&dev); + cart->setLengthDeviation(dev); + delete cart; + } + delete q; + } + + if(ver<47) { + q=new QSqlQuery("alter table SERVICES \ + add column NAME_TEMPLATE char(255)\ + after DESCRIPTION"); + delete q; + q=new QSqlQuery("alter table SERVICES \ + add column TFC_PATH char(255)\ + after NAME_TEMPLATE"); + delete q; + q=new QSqlQuery("alter table SERVICES \ + add column TFC_WIN_PATH char(255)\ + after TFC_PATH"); + delete q; + q=new QSqlQuery("alter table SERVICES \ + add column TFC_CART_OFFSET int\ + after TFC_WIN_PATH"); + delete q; + q=new QSqlQuery("alter table SERVICES \ + add column TFC_CART_LENGTH int\ + after TFC_CART_OFFSET"); + delete q; + q=new QSqlQuery("alter table SERVICES \ + add column TFC_START_OFFSET int\ + after TFC_CART_LENGTH"); + delete q; + q=new QSqlQuery("alter table SERVICES \ + add column TFC_START_LENGTH int\ + after TFC_START_OFFSET"); + delete q; + q=new QSqlQuery("alter table SERVICES \ + add column MUS_PATH char(255)\ + after TFC_START_LENGTH"); + delete q; + q=new QSqlQuery("alter table SERVICES \ + add column MUS_WIN_PATH char(255)\ + after MUS_PATH"); + delete q; + q=new QSqlQuery("alter table SERVICES \ + add column MUS_CART_OFFSET int\ + after MUS_PATH"); + delete q; + q=new QSqlQuery("alter table SERVICES \ + add column MUS_CART_LENGTH int\ + after MUS_CART_OFFSET"); + delete q; + q=new QSqlQuery("alter table SERVICES \ + add column MUS_START_OFFSET int\ + after MUS_CART_LENGTH"); + delete q; + q=new QSqlQuery("alter table SERVICES \ + add column MUS_START_LENGTH int\ + after MUS_START_OFFSET"); + delete q; + } + + if(ver<48) { + q=new QSqlQuery("alter table SERVICES \ + add column TFC_LENGTH_OFFSET int\ + after TFC_START_LENGTH"); + delete q; + + q=new QSqlQuery("alter table SERVICES \ + add column TFC_LENGTH_LENGTH int\ + after TFC_LENGTH_OFFSET"); + delete q; + + q=new QSqlQuery("alter table SERVICES \ + add column MUS_LENGTH_OFFSET int\ + after MUS_START_LENGTH"); + delete q; + + q=new QSqlQuery("alter table SERVICES \ + add column MUS_LENGTH_LENGTH int\ + after MUS_LENGTH_OFFSET"); + delete q; + } + + if(ver<49) { + q=new QSqlQuery("create table if not exists AUTOFILLS (\ + ID int not null primary key auto_increment,\ + SERVICE char(10),\ + CART_NUMBER int unsigned,\ + index SERVICE_IDX (SERVICE))"); + delete q; + } + + if(ver<50) { + q=new QSqlQuery("alter table SERVICES \ + add column CHAIN_LOG enum('N','Y') default 'N'\ + after NAME_TEMPLATE"); + delete q; + } + + if(ver<51) { + q=new QSqlQuery("alter table USERS \ + modify column PASSWORD char(32)\ + after DESCRIPTION"); + delete q; + } + + if(ver<52) { + q=new QSqlQuery("create table if not exists HOSTVARS (\ + ID int not null primary key auto_increment,\ + STATION_NAME char(64) not null,\ + NAME char(32) not null,\ + VARVALUE char(255),\ + REMARK char(255),\ + index NAME_IDX (STATION_NAME))"); + delete q; + } + + if(ver<53) { + q=new QSqlQuery("alter table STATIONS add column BACKUP_DIR char(255)"); + delete q; + q=new QSqlQuery("alter table STATIONS\ + add column BACKUP_LIFE int default 0"); + delete q; + } + + if(ver<54) { + q=new QSqlQuery("alter table RDAIRPLAY add column \ + CLEAR_FILTER enum(\'N\',\'Y\') default \'N\'"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column \ + BAR_ACTION int unsigned default 0"); + delete q; + } + + if(ver<55) { + q=new QSqlQuery("alter table RDAIRPLAY add column \ + FLASH_PANEL enum(\'N\',\'Y\') default \'N\'"); + delete q; + } + + if(ver<56) { + q=new QSqlQuery("alter table STATIONS add column \ + HEARTBEAT_CART int unsigned default 0"); + delete q; + q=new QSqlQuery("alter table STATIONS add column \ + HEARTBEAT_INTERVAL int unsigned default 0"); + delete q; + } + + if(ver<57) { + q=new QSqlQuery("create table if not exists SERVICE_PERMS (\ + ID int unsigned auto_increment not null primary key,\ + STATION_NAME char(64),\ + SERVICE_NAME char(10),\ + index STATION_IDX (STATION_NAME),\ + index SERVICE_IDX (SERVICE_NAME))"); + delete q; + q=new QSqlQuery("select NAME from STATIONS"); + while(q->next()) { + q1=new QSqlQuery("select NAME from SERVICES"); + while(q1->next()) { + q2=new + QSqlQuery(QString().sprintf("insert into SERVICE_PERMS set \ + STATION_NAME=\"%s\",\ + SERVICE_NAME=\"%s\"", + (const char *)q->value(0).toString(), + (const char *)q1->value(0).toString())); + delete q2; + } + delete q1; + } + delete q; + } + + if(ver<58) { + q=new QSqlQuery("select NAME from LOGS"); + while(q->next()) { + q1=new + QSqlQuery(QString().sprintf("alter table %s_LOG add column\ + EXT_START_TIME time", + (const char *)q->value(0).toString())); + delete q1; + q1=new + QSqlQuery(QString().sprintf("alter table %s_LOG add column\ + EXT_LENGTH int", + (const char *)q->value(0).toString())); + delete q1; + q1=new + QSqlQuery(QString().sprintf("alter table %s_LOG add column\ + EXT_DATA char(32)", + (const char *)q->value(0).toString())); + delete q1; + q1=new + QSqlQuery(QString().sprintf("alter table %s_LOG add column\ + EXT_EVENT_ID char(8)", + (const char *)q->value(0).toString())); + delete q1; + } + delete q; + } + + if(ver<59) { + q=new QSqlQuery("alter table SERVICES add column TFC_DATA_OFFSET int\ + after TFC_LENGTH_LENGTH"); + delete q; + q=new QSqlQuery("alter table SERVICES add column TFC_DATA_LENGTH int\ + after TFC_DATA_OFFSET"); + delete q; + q=new QSqlQuery("alter table SERVICES add column TFC_EVENT_ID_OFFSET int\ + after TFC_DATA_LENGTH"); + delete q; + q=new QSqlQuery("alter table SERVICES add column TFC_EVENT_ID_LENGTH int\ + after TFC_EVENT_ID_OFFSET"); + delete q; + q=new QSqlQuery("alter table SERVICES add column MUS_DATA_OFFSET int\ + after MUS_LENGTH_LENGTH"); + delete q; + q=new QSqlQuery("alter table SERVICES add column MUS_DATA_LENGTH int\ + after MUS_DATA_OFFSET"); + delete q; + q=new QSqlQuery("alter table SERVICES add column MUS_EVENT_ID_OFFSET int\ + after MUS_DATA_LENGTH"); + delete q; + q=new QSqlQuery("alter table SERVICES add column MUS_EVENT_ID_LENGTH int\ + after MUS_EVENT_ID_OFFSET"); + delete q; + } + + // + // Version 60 and 61 code removed, as per-log reconciliation data is no + // longer used. FFG 11/08/2005 + // + + if(ver<62) { + q=new QSqlQuery("alter table GROUPS add column \ + REPORT_TFC enum('N','Y') default 'N'"); + delete q; + q=new QSqlQuery("alter table GROUPS add column \ + REPORT_MUS enum('N','Y') default 'N'"); + delete q; + q=new QSqlQuery("alter table GROUPS add index \ + IDX_REPORT_TFC (REPORT_TFC)"); + delete q; + q=new QSqlQuery("alter table GROUPS add index \ + IDX_REPORT_MUS (REPORT_MUS)"); + delete q; + } + + if(ver<63) { + sql=QString("create table if not exists REPORTS (\ + ID int unsigned auto_increment not null primary key,\ + NAME char(64) not null unique,\ + DESCRIPTION char(64),\ + EXPORT_FILTER int,\ + EXPORT_PATH char(255),\ + WIN_EXPORT_PATH char(255),\ + index IDX_NAME (NAME))"); + q=new QSqlQuery(sql); + delete q; + sql=QString("create table if not exists REPORT_SERVICES (\ + ID int unsigned auto_increment not null primary key,\ + REPORT_NAME char(64) not null,\ + SERVICE_NAME char(10),\ + index IDX_REPORT_NAME (REPORT_NAME))"); + q=new QSqlQuery(sql); + delete q; + sql=QString("create table if not exists REPORT_STATIONS (\ + ID int unsigned auto_increment not null primary key,\ + REPORT_NAME char(64) not null,\ + STATION_NAME char(64),\ + index IDX_REPORT_NAME (REPORT_NAME))"); + q=new QSqlQuery(sql); + delete q; + } + + if(ver<64) { + q=new QSqlQuery("alter table REPORTS add column\ + EXPORT_TFC enum('N','Y') default 'N'"); + delete q; + q=new QSqlQuery("alter table REPORTS add column\ + EXPORT_MUS enum('N','Y') default 'N'"); + delete q; + q=new QSqlQuery("alter table REPORTS add column\ + EXPORT_GEN enum('N','Y') default 'N'"); + delete q; + } + + if(ver<65) { + q=new QSqlQuery("alter table REPORTS add column STATION_ID char(16)"); + delete q; + } + + if(ver<66) { + q=new + QSqlQuery("alter table RDAIRPLAY alter column OP_MODE set default 2"); + delete q; + } + + if(ver<67) { + q=new + QSqlQuery("alter table RDAIRPLAY \ + add column PAUSE_ENABLED enum('N','Y') default 'N'"); + delete q; + } + + if(ver<68) { + q=new QSqlQuery("alter table RDAIRPLAY add column UDP_ADDR0 char(255)"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column UDP_PORT0 int unsigned"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column UDP_STRING0 char(255)"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column UDP_ADDR1 char(255)"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column UDP_PORT1 int unsigned"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column UDP_STRING1 char(255)"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column UDP_ADDR2 char(255)"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column UDP_PORT2 int unsigned"); + delete q; + q=new QSqlQuery("alter table RDAIRPLAY add column UDP_STRING2 char(255)"); + delete q; + q=new QSqlQuery("alter table GROUPS \ + add column ENABLE_NOW_NEXT enum('N','Y') default 'N'"); + delete q; + } + + if(ver<69) { + q=new QSqlQuery("alter table MATRICES add column PORT_TYPE int default 0\ + after TYPE"); + delete q; + q=new QSqlQuery("alter table MATRICES add column IP_ADDRESS char(16)\ + after PORT"); + delete q; + q=new QSqlQuery("alter table MATRICES add column IP_PORT int\ + after IP_ADDRESS"); + delete q; + } + + if(ver<70) { + q=new QSqlQuery("select NAME from LOGS"); + while(q->next()) { + q1=new + QSqlQuery(QString().sprintf("alter table %s_REC\ + add column PLAY_SOURCE int default 0\ + after EVENT_TYPE", + (const char *)q->value(0).toString())); + delete q1; + q1=new + QSqlQuery(QString().sprintf("alter table %s_REC\ + add column CUT_NUMBER int default 0\ + after CART_NUMBER", + (const char *)q->value(0).toString())); + delete q1; + } + delete q; + } + + if(ver<71) { + q=new QSqlQuery("alter table RECORDINGS add column END_LINE int default -1\ + after START_TIME"); + delete q; + q=new + QSqlQuery("alter table RECORDINGS add column END_MATRIX int default -1\ + after START_TIME"); + delete q; + q=new + QSqlQuery("alter table RECORDINGS add column END_LENGTH int default 0\ + after START_TIME"); + delete q; + q=new QSqlQuery("alter table RECORDINGS add column END_TIME time\ + after START_TIME"); + delete q; + q=new + QSqlQuery("alter table RECORDINGS add \ + column END_TYPE int unsigned default 2 after START_TIME"); + delete q; + q=new + QSqlQuery("alter table RECORDINGS add column START_OFFSET int default 0\ + after START_TIME"); + delete q; + q=new + QSqlQuery("alter table RECORDINGS add column START_LINE int default -1\ + after START_TIME"); + delete q; + q=new + QSqlQuery("alter table RECORDINGS add column START_MATRIX int default -1\ + after START_TIME"); + delete q; + q=new + QSqlQuery("alter table RECORDINGS add column START_LENGTH int default 0\ + after START_TIME"); + delete q; + q=new + QSqlQuery("alter table RECORDINGS add column START_TYPE int default 0\ + after DESCRIPTION"); + delete q; + } + + if(ver<72) { + q=new QSqlQuery("alter table GROUPS add column \ + DEFAULT_CART_TYPE int unsigned default 1\ + after DESCRIPTION"); + delete q; + } + + if(ver<73) { + q=new QSqlQuery("alter table RDAIRPLAY add column \ + DEFAULT_TRANS_TYPE int unsigned default 0\ + after CLEAR_FILTER"); + delete q; + } + + if(ver<74) { + // + // Create CLOCK_PERMS Table + // + sql=QString("create table if not exists CLOCK_PERMS (\ + ID int unsigned auto_increment not null primary key,\ + CLOCK_NAME char(64),\ + SERVICE_NAME char(10),\ + index CLOCK_IDX (CLOCK_NAME),\ + index SERVICE_IDX (SERVICE_NAME))"); + printf("SQL: %s\n",(const char *)sql); + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + sql="select NAME from CLOCKS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql="select NAME from SERVICES"; + q1=new QSqlQuery(sql); + while(q1->next()) { + sql=QString().sprintf("insert into CLOCK_PERMS set CLOCK_NAME=\"%s\",\ + SERVICE_NAME=\"%s\"", + (const char *)q->value(0).toString(), + (const char *)q1->value(0).toString()); + q2=new QSqlQuery(sql); + delete q2; + } + delete q1; + } + delete q; + + // + // Create EVENT_PERMS Table + // + sql=QString("create table if not exists EVENT_PERMS (\ + ID int unsigned auto_increment not null primary key,\ + EVENT_NAME char(64),\ + SERVICE_NAME char(10),\ + index EVENT_IDX (EVENT_NAME),\ + index SERVICE_IDX (SERVICE_NAME))"); + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql="select NAME from SERVICES"; + q1=new QSqlQuery(sql); + while(q1->next()) { + sql=QString().sprintf("insert into EVENT_PERMS set EVENT_NAME=\"%s\",\ + SERVICE_NAME=\"%s\"", + (const char *)q->value(0).toString(), + (const char *)q1->value(0).toString()); + q2=new QSqlQuery(sql); + delete q2; + } + delete q1; + } + delete q; + } + + if(ver<75) { + q=new QSqlQuery("alter table MATRICES add column \ + CARD int default -1 after PORT_TYPE"); + delete q; + } + + if(ver<76) { + q=new QSqlQuery("alter table DECKS add column \ + MON_PORT_NUMBER int default -1 after PORT_NUMBER"); + delete q; + } + + if(ver<77) { + // + // Create USER_PERMS table + // + sql=QString("create table if not exists USER_PERMS (\ + ID int unsigned auto_increment not null primary key,\ + USER_NAME char(8),\ + GROUP_NAME char(10),\ + index USER_IDX (USER_NAME),\ + index GROUP_IDX (GROUP_NAME))"); + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + sql=QString("select LOGIN_NAME from USERS"); + q=new QSqlQuery(sql); + sql=QString("select NAME from GROUPS"); + q1=new QSqlQuery(sql); + while(q->next()) { + q1->seek(-1); + while(q1->next()) { + sql=QString().sprintf("insert into USER_PERMS set USER_NAME=\"%s\",\ + GROUP_NAME=\"%s\"", + (const char *)q->value(0).toString(), + (const char *)q1->value(0).toString()); + q2=new QSqlQuery(sql); + delete q2; + } + } + delete q1; + delete q; + + } + + if(ver<78) { + sql="alter table USERS add column \ + MODIFY_TEMPLATE_PRIV enum('N','Y') not null default 'N'\ + after ARRANGE_LOG_PRIV"; + q=new QSqlQuery(sql); + delete q; + sql="update USERS set MODIFY_TEMPLATE_PRIV=\"Y\" where \ + CREATE_LOG_PRIV=\"Y\""; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<79) { + sql="alter table GROUPS add column \ + ENFORCE_CART_RANGE enum('N','Y') default 'N'\ + after DEFAULT_HIGH_CART"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<80) { + sql="alter table SERVICES add column\ + TFC_ANNC_TYPE_OFFSET int after TFC_EVENT_ID_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column\ + TFC_ANNC_TYPE_LENGTH int after TFC_ANNC_TYPE_OFFSET"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column\ + MUS_ANNC_TYPE_OFFSET int after MUS_EVENT_ID_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column\ + MUS_ANNC_TYPE_LENGTH int after MUS_ANNC_TYPE_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table REPORTS add column\ + FORCE_TFC enum('N','Y') default 'N' after EXPORT_TFC"; + q=new QSqlQuery(sql); + delete q; + sql="alter table REPORTS add column\ + FORCE_MUS enum('N','Y') default 'N' after EXPORT_MUS"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table GROUPS alter column REPORT_TFC set default 'Y'"; + q=new QSqlQuery(sql); + delete q; + sql="alter table GROUPS alter column REPORT_MUS set default 'Y'"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<81) { + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_LOG add column\ + EXT_ANNC_TYPE char(8) after EXT_EVENT_ID", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_REC add column\ + EVENT_SOURCE int default 0 after EVENT_TYPE", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_REC add column\ + EXT_ANNC_TYPE char(8) after EXT_EVENT_ID", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_PRE add column\ + EXT_ANNC_TYPE char(8) after EXT_EVENT_ID", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_PRE add column\ + EVENT_SOURCE int default 0 after EVENT_TYPE", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_PRE add column\ + EXT_ANNC_TYPE char(8) after EXT_EVENT_ID", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column\ + EXT_ANNC_TYPE char(8) after EXT_EVENT_ID", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column\ + EVENT_SOURCE int default 0 after EVENT_TYPE", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column\ + EXT_ANNC_TYPE char(8) after EXT_EVENT_ID", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<82) { + sql="alter table INPUTS add column ENGINE_NUM int default -1\ + after CHANNEL_MODE"; + q=new QSqlQuery(sql); + delete q; + sql="alter table INPUTS add column DEVICE_NUM int default -1\ + after ENGINE_NUM"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table OUTPUTS add column ENGINE_NUM int default -1\ + after NAME"; + q=new QSqlQuery(sql); + delete q; + sql="alter table OUTPUTS add column DEVICE_NUM int default -1\ + after ENGINE_NUM"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table MATRICES add column USERNAME char(32) after IP_PORT"; + q=new QSqlQuery(sql); + delete q; + sql="alter table MATRICES add column PASSWORD char(32) after USERNAME"; + q=new QSqlQuery(sql); + delete q; + + sql="create table if not exists VGUEST_RESOURCES (\ + ID int unsigned auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + MATRIX_NUM int not null,\ + VGUEST_TYPE int not null,\ + NUMBER int not null,\ + ENGINE_NUM int default -1,\ + DEVICE_NUM int default -1,\ + SURFACE_NUM int default -1,\ + RELAY_NUM int default -1,\ + BUSS_NUM int default -1,\ + index STATION_MATRIX_IDX (STATION_NAME,MATRIX_NUM,VGUEST_TYPE))"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table MATRICES add column FADERS int default 0 after GPOS"; + q=new QSqlQuery(sql); + delete q; + sql="alter table MATRICES add column DISPLAYS int default 0 after FADERS"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<83) { + sql="alter table RECORDINGS add column URL char(255) after ONE_SHOT"; + q=new QSqlQuery(sql); + delete q; + sql="alter table RECORDINGS add column URL_USERNAME char(64) after URL"; + q=new QSqlQuery(sql); + delete q; + sql="alter table RECORDINGS add column URL_PASSWORD char(64)\ + after URL_USERNAME"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<84) { + sql= + "alter table STATIONS add column STATION_SCANNED enum('N','Y')\ + default 'N'"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table STATIONS add column HPI_VERSION char(16)"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column JACK_VERSION char(16)"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column ALSA_VERSION char(16)"; + q=new QSqlQuery(sql); + delete q; + + sql= + "alter table STATIONS add column HAVE_OGGENC enum('N','Y') default 'N'"; + q=new QSqlQuery(sql); + delete q; + sql= + "alter table STATIONS add column HAVE_OGG123 enum('N','Y') default 'N'"; + q=new QSqlQuery(sql); + delete q; + sql= + "alter table STATIONS add column HAVE_FLAC enum('N','Y') default 'N'"; + q=new QSqlQuery(sql); + delete q; + sql= + "alter table STATIONS add column HAVE_LAME enum('N','Y') default 'N'"; + q=new QSqlQuery(sql); + delete q; + sql= + "alter table STATIONS add column HAVE_MPG321 enum('N','Y') default 'N'"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table STATIONS add column CARD0_DRIVER int default 0"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD0_NAME char(64)"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD0_INPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD0_OUTPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table STATIONS add column CARD1_DRIVER int default 0"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD1_NAME char(64)"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD1_INPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD1_OUTPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table STATIONS add column CARD2_DRIVER int default 0"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD2_NAME char(64)"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD2_INPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD2_OUTPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table STATIONS add column CARD3_DRIVER int default 0"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD3_NAME char(64)"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD3_INPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD3_OUTPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table STATIONS add column CARD4_DRIVER int default 0"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD4_NAME char(64)"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD4_INPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD4_OUTPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table STATIONS add column CARD5_DRIVER int default 0"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD5_NAME char(64)"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD5_INPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD5_OUTPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table STATIONS add column CARD6_DRIVER int default 0"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD6_NAME char(64)"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD6_INPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD6_OUTPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table STATIONS add column CARD7_DRIVER int default 0"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD7_NAME char(64)"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD7_INPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + sql="alter table STATIONS add column CARD7_OUTPUTS int default -1"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<85) { + sql="alter table RECORDINGS add column NORMALIZE_LEVEL int default -1300\ + after TRIM_THRESHOLD"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RECORDINGS add column QUALITY int default 0\ + after BITRATE"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<86) { + sql="alter table RECORDINGS alter column END_TYPE set default 0"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<87) { + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_LOG add column\ + EXT_CART_NAME char(32) after EXT_LENGTH", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_REC add column\ + EXT_CART_NAME char(32) after EXT_LENGTH", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_PRE add column\ + EXT_CART_NAME char(32) after EXT_LENGTH", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column\ + EXT_CART_NAME char(32) after EXT_LENGTH", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<88) { + sql="alter table RECORDINGS add column\ + ALLOW_MULT_RECS enum('N','Y') default 'N' after END_GPI"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RECORDINGS add column\ + MAX_GPI_REC_LENGTH int unsigned default 3600000\ + after ALLOW_MULT_RECS"; + q=new QSqlQuery(sql); + delete q; + + sql=QString(). + sprintf("select ID,START_TIME,END_TIME,END_LENGTH from RECORDINGS\ + where END_TYPE=%d",RDRecording::GpiEnd); + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString(). + sprintf("update RECORDINGS set MAX_GPI_REC_LENGTH=%u where ID=%u", + QTime().msecsTo(q->value(2).toTime())+q->value(3).toUInt()- + QTime().msecsTo(q->value(1).toTime()),q->value(0).toUInt()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<89) { + sql="alter table CART add column AVERAGE_LENGTH int unsigned\ + after FORCED_LENGTH"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table CART add column ASYNCRONOUS enum('N','Y') default 'N'\ + after PRESERVE_PITCH"; + q=new QSqlQuery(sql); + delete q; + + sql=QString().sprintf("select NUMBER from CART where TYPE=%u", + RDCart::Audio); + q=new QSqlQuery(sql); + while(q->next()) { + cart=new RDCart(q->value(0).toUInt()); + sql=QString().sprintf("update CART set AVERAGE_LENGTH=%u\ + where NUMBER=%u",cart->calculateAverageLength(), + cart->number()); + q1=new QSqlQuery(sql); + delete q1; + delete cart; + } + delete q; + + RDMacroEvent *macro_event; + sql=QString().sprintf("select NUMBER from CART where TYPE=%u", + RDCart::Macro); + q=new QSqlQuery(sql); + while(q->next()) { + macro_event=new RDMacroEvent(); + macro_event->load(q->value(0).toUInt()); + sql=QString().sprintf("update CART set AVERAGE_LENGTH=%u,\ + FORCED_LENGTH=%u where NUMBER=%u", + macro_event->length(), + macro_event->length(), + q->value(0).toUInt()); + q1=new QSqlQuery(sql); + delete q1; + delete macro_event; + } + delete q; + } + + if(ver<90) { + sql="alter table REPORTS add column CART_DIGITS int unsigned default 6\ + after STATION_ID"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table REPORTS add column USE_LEADING_ZEROS enum('N','Y')\ + default 'N' after CART_DIGITS"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<91) { + sql="alter table DECKS add column DEFAULT_MONITOR_ON enum('N','Y')\ + default 'N' after MON_PORT_NUMBER"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<92) { + sql="alter table EVENTS add column AUTOFILL_SLOP int default -1\ + after USE_AUTOFILL"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<93) { + sql="alter table LOGS add column IMPORT_DATE DATE after END_DATE"; + q=new QSqlQuery(sql); + delete q; + + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_LOG add column\ + FADEUP_POINT int default -1 after END_POINT", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_LOG add column\ + FADEUP_GAIN int default %d after FADEUP_POINT", + (const char *)tablename,RD_FADE_DEPTH); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_LOG add column\ + FADEDOWN_POINT int default -1 after FADEUP_GAIN", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_LOG add column\ + FADEDOWN_GAIN int default %d after FADEDOWN_POINT", + (const char *)tablename,RD_FADE_DEPTH); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_LOG add column\ + SEGUE_GAIN int default %d after SEGUE_END_POINT", + (const char *)tablename,RD_FADE_DEPTH); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + + sql=QString().sprintf("alter table %s_PRE add column\ + FADEUP_POINT int default -1 after END_POINT", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_PRE add column\ + FADEUP_GAIN int default %d after FADEUP_POINT", + (const char *)tablename,RD_FADE_DEPTH); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_PRE add column\ + FADEDOWN_POINT int default -1 after FADEUP_GAIN", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_PRE add column\ + FADEDOWN_GAIN int default %d after FADEDOWN_POINT", + (const char *)tablename,RD_FADE_DEPTH); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_PRE add column\ + SEGUE_GAIN int default %d after SEGUE_END_POINT", + (const char *)tablename,RD_FADE_DEPTH); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column\ + FADEUP_POINT int default -1 after END_POINT", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column\ + FADEUP_GAIN int default %d after FADEUP_POINT", + (const char *)tablename,RD_FADE_DEPTH); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column\ + FADEDOWN_POINT int default -1 after FADEUP_GAIN", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column\ + FADEDOWN_GAIN int default %d after FADEDOWN_POINT", + (const char *)tablename,RD_FADE_DEPTH); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column\ + SEGUE_GAIN int default %d after SEGUE_END_POINT", + (const char *)tablename,RD_FADE_DEPTH); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<94) { + sql="alter table CART add column OWNER char(64) after ASYNCRONOUS"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table CART add index OWNER_IDX (OWNER)"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column TRACK_GROUP char(10) after CHAIN_LOG"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table LOGS add column SCHEDULED_TRACKS int unsigned default 0\ + after IMPORT_DATE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table LOGS add column COMPLETED_TRACKS int unsigned default 0\ + after SCHEDULED_TRACKS"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<95) { + sql="alter table USERS add column VOICETRACK_LOG_PRIV enum('N','Y') \ + not null default 'N' after ADDTO_LOG_PRIV"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<96) { + sql=QString("create table if not exists RDLOGEDIT (\ + ID int unsigned primary key auto_increment,\ + STATION char(64) not null,\ + INPUT_CARD int default -1,\ + INPUT_PORT int default 0,\ + OUTPUT_CARD int default -1,\ + OUTPUT_PORT int default 0,\ + FORMAT int unsigned default 0,\ + SAMPRATE int unsigned default 44100,\ + LAYER int unsigned default 0,\ + BITRATE int unsigned default 0,\ + DEFAULT_CHANNELS int unsigned default 2,\ + MAXLENGTH int default 0,\ + TAIL_PREROLL int unsigned default 2000,\ + START_CART int unsigned default 0,\ + END_CART int unsigned default 0,\ + index STATION_IDX (STATION))"); + q=new QSqlQuery(sql); + delete q; + + sql="select NAME from STATIONS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into RDLOGEDIT set STATION=\"%s\"", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<97) { + sql="alter table LOGS add column LOG_EXISTS enum('N','Y') default 'Y'\ + after NAME"; + q=new QSqlQuery(sql); + delete q; + sql="alter table LOGS add index NAME_IDX (NAME,LOG_EXISTS)"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table USERS add column DELETE_REC_PRIV enum('N','Y')\ + default 'N' after DELETE_LOG_PRIV"; + q=new QSqlQuery(sql); + delete q; + sql="update USERS set DELETE_REC_PRIV=\"Y\" where DELETE_LOG_PRIV=\"Y\""; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<98) { + QString tablename; + sql="select NAME from SERVICES"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("create table %s_SRT (\ + ID int unsigned auto_increment primary key,\ + LENGTH int,\ + LOG_NAME char(64),\ + LOG_ID int,\ + CART_NUMBER int unsigned,\ + CUT_NUMBER int,\ + TITLE char(255),\ + ARTIST char(255),\ + STATION_NAME char(64),\ + EVENT_DATETIME datetime,\ + SCHEDULED_TIME time,\ + EVENT_TYPE int,\ + EVENT_SOURCE int,\ + PLAY_SOURCE int,\ + START_SOURCE int default 0,\ + EXT_START_TIME time,\ + EXT_LENGTH int,\ + EXT_CART_NAME char(32),\ + EXT_DATA char(32),\ + EXT_EVENT_ID char(8),\ + EXT_ANNC_TYPE char(8),\ + index EVENT_DATETIME_IDX(EVENT_DATETIME))", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("select NAME from LOGS where SERVICE=\"%s\"", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + while(q1->next()) { + tablename=q1->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("select %s_REC.LENGTH,\ + %s_REC.LOG_ID,\ + %s_REC.CART_NUMBER,\ + %s_REC.CUT_NUMBER,\ + %s_REC.STATION_NAME,\ + %s_REC.EVENT_DATETIME,\ + %s_REC.EVENT_TYPE,\ + %s_REC.EVENT_SOURCE,\ + %s_REC.PLAY_SOURCE,\ + %s_REC.EXT_START_TIME,\ + %s_REC.EXT_LENGTH,\ + %s_REC.EXT_CART_NAME,\ + %s_REC.EXT_DATA,\ + %s_REC.EXT_EVENT_ID,\ + %s_REC.EXT_ANNC_TYPE,\ + CART.TITLE,\ + CART.ARTIST \ + from CART right join %s_REC on \ + CART.NUMBER=%s_REC.CART_NUMBER", + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename, + (const char *)tablename); + q2=new QSqlQuery(sql); + while(q2->next()) { + sql=QString().sprintf("insert into %s_SRT set\ + LENGTH=%d,\ + LOG_NAME=\"%s\",\ + LOG_ID=%d,\ + CART_NUMBER=%u,\ + CUT_NUMBER=%d,\ + TITLE=\"%s\",\ + ARTIST=\"%s\",\ + STATION_NAME=\"%s\",\ + EVENT_DATETIME=\"%s\",\ + SCHEDULED_TIME=\"%s\",\ + EVENT_TYPE=%d,\ + EVENT_SOURCE=%d,\ + PLAY_SOURCE=%d,\ + EXT_START_TIME=\"%s\",\ + EXT_LENGTH=%d,\ + EXT_CART_NAME=\"%s\",\ + EXT_DATA=\"%s\",\ + EXT_EVENT_ID=\"%s\",\ + EXT_ANNC_TYPE=\"%s\"", + (const char *)q->value(0).toString(), + q2->value(0).toInt(), + (const char *)q1->value(0).toString(), + q2->value(1).toInt(), + q2->value(2).toUInt(), + q2->value(3).toInt(), + (const char *)q2->value(15).toString(), + (const char *)q2->value(16).toString(), + (const char *)q2->value(4).toString(), + (const char *)q2->value(5).toDateTime(). + toString("yyyy-MM-dd hh:mm:ss"), + "00:00:00", + q2->value(6).toInt(), + q2->value(7).toInt(), + q2->value(8).toInt(), + (const char *)q2->value(9).toTime(). + toString("hh:mm:ss"), + q2->value(10).toInt(), + (const char *)q2->value(11).toString(), + (const char *)q2->value(12).toString(), + (const char *)q2->value(13).toString(), + (const char *)q2->value(14).toString()); + q3=new QSqlQuery(sql); + delete q3; + } + delete q2; + } + delete q1; + } + delete q; + + sql="alter table RDAIRPLAY add column DEFAULT_SERVICE char(10)\ + after PAUSE_ENABLED"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<99) { + sql="alter table USERS add column CONFIG_PANELS_PRIV enum('N','Y')\ + default 'N' after REMOVEFROM_LOG_PRIV"; + q=new QSqlQuery(sql); + delete q; + sql="update USERS set CONFIG_PANELS_PRIV=\"Y\""; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<100) { + sql="alter table CUTS add column ISRC char(12) after OUTCUE"; + q=new QSqlQuery(sql); + delete q; + sql="select NUMBER,ISRC from CART"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("update CUTS set ISRC=\"%s\" where CART_NUMBER=%u", + (const char *)q->value(1).toString(), + q->value(0).toUInt()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<101) { + for(int i=0;inext()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_SRT add column PUBLISHER char(64)\ + after ARTIST",(const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_SRT add column COMPOSER char(64)\ + after PUBLISHER",(const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_SRT add column ISRC char(12)\ + after PUBLISHER",(const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_SRT add column USAGE_CODE int\ + default 0 after ISRC",(const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<105) { + for(int i=0;i<6;i++) { + sql=QString().sprintf("alter table RDAIRPLAY add column START_RML%d\ + char(255) after PORT%d",i,i); + q=new QSqlQuery(sql); + delete q; + sql=QString().sprintf("alter table RDAIRPLAY add column STOP_RML%d\ + char(255) after START_RML%d",i,i); + q=new QSqlQuery(sql); + delete q; + } + } + + if(ver<106) { + for(int i=0;i<3;i++) { + sql=QString().sprintf("alter table RDAIRPLAY add column LOG_RML%d\ + char(255) after UDP_STRING%d",i,i); + q=new QSqlQuery(sql); + delete q; + } + } + + if(ver<107) { + sql="alter table RDLOGEDIT add column REC_START_CART int unsigned\ + default 0 after END_CART"; + q=new QSqlQuery(sql); + delete q; + sql="alter table RDLOGEDIT add column REC_END_CART int unsigned\ + default 0 after REC_START_CART"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<108) { + sql="alter table CART add column AVERAGE_SEGUE_LENGTH int unsigned\ + after LENGTH_DEVIATION"; + q=new QSqlQuery(sql); + delete q; + sql="select NUMBER from CART"; + q=new QSqlQuery(sql); + while(q->next()) { + cart=new RDCart(q->value(0).toUInt()); + cart->updateLength(); + delete cart; + } + delete q; + } + + if(ver<109) { + sql="alter table EVENTS add column NESTED_EVENT char(64) after COLOR"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<110) { + for(unsigned i=6;i<10;i++) { + sql=QString().sprintf("alter table RDAIRPLAY add column CARD%d int\ + default -1 after STOP_RML%d",i,i-1); + q=new QSqlQuery(sql); + delete q; + + sql=QString().sprintf("alter table RDAIRPLAY add column PORT%d int\ + default -1 after CARD%d",i,i); + q=new QSqlQuery(sql); + delete q; + + sql=QString().sprintf("alter table RDAIRPLAY add column START_RML%d\ + char(255) after PORT%d",i,i); + q=new QSqlQuery(sql); + delete q; + + sql=QString().sprintf("alter table RDAIRPLAY add column STOP_RML%d\ + char(255) after START_RML%d",i,i); + q=new QSqlQuery(sql); + delete q; + } + sql="select ID,CARD2,PORT2,START_RML2,STOP_RML2 from RDAIRPLAY"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("update RDAIRPLAY set \ + CARD6=%d,PORT6=%d,\ + START_RML6=\"%s\",STOP_RML6=\"%s\",\ + CARD7=%d,PORT7=%d,\ + START_RML7=\"%s\",STOP_RML7=\"%s\",\ + CARD8=%d,PORT8=%d,\ + START_RML8=\"%s\",STOP_RML8=\"%s\",\ + CARD9=%d,PORT9=%d,\ + START_RML9=\"%s\",STOP_RML9=\"%s\"\ + where ID=%d", + q->value(1).toInt(),q->value(2).toInt(), + (const char *)q->value(3).toString(), + (const char *)q->value(4).toString(), + q->value(1).toInt(),q->value(2).toInt(), + (const char *)q->value(3).toString(), + (const char *)q->value(4).toString(), + q->value(1).toInt(),q->value(2).toInt(), + (const char *)q->value(3).toString(), + (const char *)q->value(4).toString(), + q->value(1).toInt(),q->value(2).toInt(), + (const char *)q->value(3).toString(), + (const char *)q->value(4).toString(), + q->value(0).toInt()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<111) { + sql="alter table CART add column VALIDITY int unsigned default 2\ + after PLAY_ORDER"; + q=new QSqlQuery(sql); + delete q; + sql="alter table CUTS add column VALIDITY int unsigned default 2\ + after LOCAL_COUNTER"; + q=new QSqlQuery(sql); + delete q; + sql="select NUMBER from CART"; + q=new QSqlQuery(sql); + while(q->next()) { + cart=new RDCart(q->value(0).toUInt()); + cart->updateLength(); + delete cart; + } + delete q; + } + + if(ver<112) { + sql="alter table RDLOGEDIT add column TRIM_THRESHOLD int default -3000 \ + after REC_END_CART"; + q=new QSqlQuery(sql); + delete q; + sql="alter table RDLOGEDIT add column RIPPER_LEVEL int default -1300 \ + after TRIM_THRESHOLD"; + q=new QSqlQuery(sql); + delete q; + sql="select STATION,TRIM_THRESHOLD,RIPPER_LEVEL from RDLIBRARY"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("update RDLOGEDIT set TRIM_THRESHOLD=%d,\ + RIPPER_LEVEL=%d where STATION=\"%s\"", + q->value(1).toInt(),q->value(2).toInt(), + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + sql="alter table RDLIBRARY modify RIPPER_LEVEL int default -1300"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDLOGEDIT modify DEFAULT_CHANNELS int unsigned default 1"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<113) { + sql="alter table VGUEST_RESOURCES modify SURFACE_NUM int default 0"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column MUS_BREAK_STRING char(64) \ + after MUS_WIN_PATH"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column MUS_TRACK_STRING char(64) \ + after MUS_BREAK_STRING"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<114) { + sql="alter table LOGS add column MUSIC_LINKS int default 0 \ + after COMPLETED_TRACKS"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table LOGS add column MUSIC_LINKED enum('N','Y') default 'N' \ + after MUSIC_LINKS"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table LOGS add column TRAFFIC_LINKS int default 0 \ + after MUSIC_LINKED"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table LOGS add column TRAFFIC_LINKED enum('N','Y') default 'N' \ + after TRAFFIC_LINKS"; + q=new QSqlQuery(sql); + delete q; + + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_LOG add column\ + LINK_EVENT_NAME char(64) after POST_TIME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_LOG add column\ + LINK_START_TIME time after LINK_EVENT_NAME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_LOG add column\ + LINK_LENGTH int default 0 after LINK_START_TIME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_LOG add column\ + LINK_ID int default -1 after LINK_LENGTH", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_PRE add column\ + LINK_EVENT_NAME char(64) after POST_TIME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_PRE add column\ + LINK_START_TIME time after LINK_EVENT_NAME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_PRE add column\ + LINK_LENGTH int default 0 after LINK_START_TIME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_PRE add column\ + LINK_ID int default -1 after LINK_LENGTH", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_POST add column\ + LINK_EVENT_NAME char(64) after POST_TIME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_POST add column\ + LINK_START_TIME time after LINK_EVENT_NAME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_POST add column\ + LINK_LENGTH int default 0 after LINK_START_TIME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_POST add column\ + LINK_ID int default -1 after LINK_LENGTH", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<115) { + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_LOG modify column LABEL char(64)", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_PRE modify column LABEL char(64)", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_POST modify column LABEL char(64)", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + sql="alter table SERVICES add column TRACK_GROUP char(10) \ + after CHAIN_LOG"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<116) { + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_LOG add column LINK_EMBEDDED \ + enum('N','Y') default 'N' after LINK_ID", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_PRE add column LINK_EMBEDDED \ + enum('N','Y') default 'N' after LINK_ID", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_POST add column LINK_EMBEDDED \ + enum('N','Y') default 'N' after LINK_ID", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<117) { + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_LOG add column ORIGIN_USER char(8)\ + after POST_TIME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_LOG add column ORIGIN_DATETIME \ + datetime after ORIGIN_USER", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + + sql=QString().sprintf("alter table %s_LOG drop column ORIGIN_NAME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + + } + delete q; + + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_PRE add column ORIGIN_USER char(8)\ + after POST_TIME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_PRE add column ORIGIN_DATETIME \ + datetime after ORIGIN_USER", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table %s_POST add column ORIGIN_USER \ + char(8) after POST_TIME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column ORIGIN_DATETIME \ + datetime after ORIGIN_USER", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + + + + sql=QString().sprintf("alter table %s_PRE drop column ORIGIN_NAME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST drop column ORIGIN_NAME", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + + } + delete q; + } + + if(ver<118) { + sql="alter table SERVICES add column TFC_LABEL_CART char(32) \ + after TFC_WIN_PATH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column TFC_TRACK_CART char(32) \ + after TFC_LABEL_CART"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column MUS_LABEL_CART char(32) \ + after MUS_WIN_PATH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column MUS_TRACK_CART char(32) \ + after MUS_LABEL_CART"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column TFC_TITLE_OFFSET int \ + after TFC_CART_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column TFC_TITLE_LENGTH int \ + after TFC_TITLE_OFFSET"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column MUS_TITLE_OFFSET int \ + after MUS_CART_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column MUS_TITLE_LENGTH int \ + after MUS_TITLE_OFFSET"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<119) { + sql="alter table SERVICES add column TFC_HOURS_OFFSET int \ + after TFC_START_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column TFC_HOURS_LENGTH int \ + after TFC_HOURS_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column TFC_MINUTES_OFFSET int \ + after TFC_HOURS_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column TFC_MINUTES_LENGTH int \ + after TFC_MINUTES_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column TFC_SECONDS_OFFSET int \ + after TFC_MINUTES_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column TFC_SECONDS_LENGTH int \ + after TFC_SECONDS_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + sql="select NAME,TFC_START_OFFSET from SERVICES where TFC_START_LENGTH=8"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("update SERVICES set\ + TFC_HOURS_OFFSET=%d,TFC_HOURS_LENGTH=2,\ + TFC_MINUTES_OFFSET=%d,TFC_MINUTES_LENGTH=2,\ + TFC_SECONDS_OFFSET=%d,TFC_SECONDS_LENGTH=2 \ + where NAME=\"%s\"", + q->value(1).toInt(), + q->value(1).toInt()+3, + q->value(1).toInt()+6, + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + + sql="alter table SERVICES add column MUS_HOURS_OFFSET int \ + after MUS_START_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column MUS_HOURS_LENGTH int \ + after MUS_HOURS_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column MUS_MINUTES_OFFSET int \ + after MUS_HOURS_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column MUS_MINUTES_LENGTH int \ + after MUS_MINUTES_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column MUS_SECONDS_OFFSET int \ + after MUS_MINUTES_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column MUS_SECONDS_LENGTH int \ + after MUS_SECONDS_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + + sql="select NAME,MUS_START_OFFSET from SERVICES where MUS_START_LENGTH=8"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("update SERVICES set\ + MUS_HOURS_OFFSET=%d,MUS_HOURS_LENGTH=2,\ + MUS_MINUTES_OFFSET=%d,MUS_MINUTES_LENGTH=2,\ + MUS_SECONDS_OFFSET=%d,MUS_SECONDS_LENGTH=2 \ + where NAME=\"%s\"", + q->value(1).toInt(), + q->value(1).toInt()+3, + q->value(1).toInt()+6, + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<120) { + sql="alter table GROUPS add column COLOR char(7) default \"#000000\" \ + after ENABLE_NOW_NEXT"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDLOGEDIT add column DEFAULT_TRANS_TYPE int default 0 \ + after RIPPER_LEVEL"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<121) { + sql="alter table LOGS add column LINK_DATETIME datetime not null \ + after ORIGIN_DATETIME"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table LOGS add column NEXT_ID int default 0 \ + after TRAFFIC_LINKED"; + q=new QSqlQuery(sql); + delete q; + + sql="select NAME,ORIGIN_DATETIME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("update LOGS set LINK_DATETIME=\"%s\" \ + where NAME=\"%s\"", + (const char *)q->value(1).toDateTime(). + toString("yyyy-MM-dd hh:mm:ss"), + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("select ID from `%s_LOG` order by ID", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + if(q1->last()) { + sql=QString().sprintf("update LOGS set NEXT_ID=%d where NAME=\"%s\"", + q1->value(0).toInt()+1, + (const char *)q->value(0).toString()); + q2=new QSqlQuery(sql); + delete q2; + } + delete q1; + } + delete q; + } + + if(ver<122) { + sql="alter table LOGS add column MODIFIED_DATETIME datetime not null \ + after LINK_DATETIME"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table LOGS add column AUTO_REFRESH enum('N','Y') default 'N' \ + after MODIFIED_DATETIME"; + q=new QSqlQuery(sql); + delete q; + + sql="select NAME,LINK_DATETIME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("update LOGS set MODIFIED_DATETIME=\"%s\" \ + where NAME=\"%s\"", + (const char *)q->value(1).toDateTime(). + toString("yyyy-MM-dd hh:mm:ss"), + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + + sql="alter table SERVICES add column AUTO_REFRESH enum('N','Y') \ + default 'N' after TRACK_GROUP"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<123) { + sql="alter table REPORTS add column FILTER_ONAIR_FLAG enum('N','Y') \ + default 'N' after STATION_FORMAT"; + q=new QSqlQuery(sql); + delete q; + + sql="select NAME from SERVICES"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("alter table `%s_SRT` add column ONAIR_FLAG \ + enum('N','Y') default 'N' after START_SOURCE", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<124) { + sql="alter table SERVICES add column TFC_LEN_HOURS_OFFSET int \ + after TFC_SECONDS_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column TFC_LEN_HOURS_LENGTH int \ + after TFC_LEN_HOURS_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column TFC_LEN_MINUTES_OFFSET int \ + after TFC_LEN_HOURS_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column TFC_LEN_MINUTES_LENGTH int \ + after TFC_LEN_MINUTES_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column TFC_LEN_SECONDS_OFFSET int \ + after TFC_LEN_MINUTES_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column TFC_LEN_SECONDS_LENGTH int \ + after TFC_LEN_SECONDS_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + sql="select NAME,TFC_LENGTH_OFFSET,TFC_LENGTH_LENGTH from SERVICES"; + q=new QSqlQuery(sql); + while(q->next()) { + if(q->value(2).toInt()==5) { + sql=QString().sprintf("update SERVICES set TFC_LEN_MINUTES_OFFSET=%d,\ + TFC_LEN_MINUTES_LENGTH=2,\ + TFC_LEN_SECONDS_OFFSET=%d,\ + TFC_LEN_SECONDS_LENGTH=2 where NAME=\"%s\"", + q->value(1).toInt(),q->value(1).toInt()+3, + (const char *)q->value(0).toString()); + } + else { + sql=QString().sprintf("update SERVICES set TFC_LEN_SECONDS_OFFSET=%d,\ + TFC_LEN_SECONDS_LENGTH=%d where NAME=\"%s\"", + q->value(1).toInt(),q->value(2).toInt(), + (const char *)q->value(0).toString()); + } + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + sql="alter table SERVICES add column MUS_LEN_HOURS_OFFSET int \ + after MUS_SECONDS_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column MUS_LEN_HOURS_LENGTH int \ + after MUS_LEN_HOURS_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column MUS_LEN_MINUTES_OFFSET int \ + after MUS_LEN_HOURS_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column MUS_LEN_MINUTES_LENGTH int \ + after MUS_LEN_MINUTES_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column MUS_LEN_SECONDS_OFFSET int \ + after MUS_LEN_MINUTES_LENGTH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table SERVICES add column MUS_LEN_SECONDS_LENGTH int \ + after MUS_LEN_SECONDS_OFFSET"; + q=new QSqlQuery(sql); + delete q; + + sql="select NAME,MUS_LENGTH_OFFSET,MUS_LENGTH_LENGTH from SERVICES"; + q=new QSqlQuery(sql); + while(q->next()) { + if(q->value(2).toInt()==5) { + sql=QString().sprintf("update SERVICES set MUS_LEN_MINUTES_OFFSET=%d,\ + MUS_LEN_MINUTES_LENGTH=2,\ + MUS_LEN_SECONDS_OFFSET=%d,\ + MUS_LEN_SECONDS_LENGTH=2 where NAME=\"%s\"", + q->value(1).toInt(),q->value(1).toInt()+3, + (const char *)q->value(0).toString()); + } + else { + sql=QString().sprintf("update SERVICES set MUS_LEN_SECONDS_OFFSET=%d,\ + MUS_LEN_SECONDS_LENGTH=%d where NAME=\"%s\"", + q->value(1).toInt(),q->value(2).toInt(), + (const char *)q->value(0).toString()); + } + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<125) { + sql="alter table REPORTS add column SERVICE_NAME char(64) \ + after LINES_PER_PAGE"; + q=new QSqlQuery(sql); + delete q; + + sql="select NAME from SERVICES"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("alter table `%s_SRT` add column ALBUM char(255) \ + after COMPOSER", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table `%s_SRT` add column LABEL char(64) \ + after ALBUM", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<126) { + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("alter table `%s_LOG` add column \ + LINK_START_SLOP int default 0 after LINK_LENGTH", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table `%s_LOG` add column \ + LINK_END_SLOP int default 0 after LINK_START_SLOP", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<127) { + sql="alter table RDAIRPLAY add column \ + PANEL_PAUSE_ENABLED enum('N','Y') default 'N' after FLASH_PANEL"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<128) { + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table `%s_PRE` add column \ + LINK_START_SLOP int default 0 after LINK_LENGTH", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table `%s_PRE` add column \ + LINK_END_SLOP int default 0 after LINK_START_SLOP", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table `%s_POST` add column \ + LINK_START_SLOP int default 0 after LINK_LENGTH", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + + sql=QString().sprintf("alter table `%s_POST` add column \ + LINK_END_SLOP int default 0 after LINK_START_SLOP", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<129) { + sql="alter table RDAIRPLAY add column EXIT_CODE int default 0 \ + after LOG_RML2"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column EXIT_PASSWORD char(41) default \"\" \ + after EXIT_CODE"; + q=new QSqlQuery(sql); + delete q; + + + sql="alter table RDAIRPLAY add column LOG0_START_MODE int default 0 \ + after EXIT_PASSWORD"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG0_AUTO_RESTART enum('N','Y') \ + default 'N' after LOG0_START_MODE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG0_LOG_NAME char(64) \ + after LOG0_AUTO_RESTART"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG0_CURRENT_LOG char(64) \ + after LOG0_LOG_NAME"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG0_RUNNING enum('N','Y') \ + default 'N' after LOG0_CURRENT_LOG"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG0_LOG_ID int default -1 \ + after LOG0_RUNNING"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG0_LOG_LINE int default -1 \ + after LOG0_LOG_ID"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG1_START_MODE int default 0 \ + after LOG0_LOG_LINE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG1_AUTO_RESTART enum('N','Y') \ + default 'N' after LOG1_START_MODE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG1_LOG_NAME char(64) \ + after LOG1_AUTO_RESTART"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG1_CURRENT_LOG char(64) \ + after LOG1_LOG_NAME"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG1_RUNNING enum('N','Y') \ + default 'N' after LOG1_CURRENT_LOG"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG1_LOG_ID int default -1 \ + after LOG1_RUNNING"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG1_LOG_LINE int default -1 \ + after LOG1_LOG_ID"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG2_START_MODE int default 0 \ + after LOG1_LOG_LINE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG2_AUTO_RESTART enum('N','Y') \ + default 'N' after LOG2_START_MODE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG2_LOG_NAME char(64) \ + after LOG2_AUTO_RESTART"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG2_CURRENT_LOG char(64) \ + after LOG2_LOG_NAME"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG2_RUNNING enum('N','Y') \ + default 'N' after LOG2_CURRENT_LOG"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG2_LOG_ID int default -1 \ + after LOG2_RUNNING"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG2_LOG_LINE int default -1 \ + after LOG2_LOG_ID"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<130) { + sql="create table if not exists RDCATCH (\ + ID int unsigned primary key auto_increment,\ + STATION char(64) not null,\ + ERROR_RML char(255),\ + index STATION_IDX (STATION))"; + q=new QSqlQuery(sql); + delete q; + } + + if (ver<131) { + sql="ALTER TABLE `EVENTS` ADD `SCHED_GROUP` VARCHAR(10)"; + q=new QSqlQuery(sql); + delete q; + sql="ALTER TABLE `EVENTS` ADD `TITLE_SEP` INT(10) UNSIGNED"; + q=new QSqlQuery(sql); + delete q; + sql="ALTER TABLE `EVENTS` ADD `HAVE_CODE` VARCHAR(10)"; + q=new QSqlQuery(sql); + delete q; + sql="ALTER TABLE `EVENTS` ADD `HOR_SEP` INT(10) UNSIGNED"; + q=new QSqlQuery(sql); + delete q; + sql="ALTER TABLE `EVENTS` ADD `HOR_DIST` INT(10) UNSIGNED"; + q=new QSqlQuery(sql); + delete q; + sql="ALTER TABLE `CLOCKS` ADD `ARTISTSEP` INT(10) UNSIGNED"; + q=new QSqlQuery(sql); + delete q; + sql="ALTER TABLE `CART` ADD `SCHED_CODES` VARCHAR( 255 ) NULL DEFAULT NULL"; + q=new QSqlQuery(sql); + delete q; + sql="create table if not exists SCHED_CODES\ + (CODE varchar(10) not null primary key,\ + DESCRIPTION varchar(255))"; + q=new QSqlQuery(sql); + delete q; + sql="drop table SCHED_STACK"; + q=new QSqlQuery(sql); + delete q; + sql="select NAME from SERVICES"; + q=new QSqlQuery(sql); + while(q->next()) { + QString svc=q->value(0).toString(); + sql=QString().sprintf("drop table %s_STACK",(const char *)svc.replace(" ","_")); + printf("%s\n",(const char*)sql); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("alter table `%s_LOG` add column \ + DUCK_UP_GAIN int default 0 after SEGUE_GAIN", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table `%s_LOG` add column \ + DUCK_DOWN_GAIN int default 0 after DUCK_UP_GAIN", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("alter table `%s_PRE` add column \ + DUCK_UP_GAIN int default 0 after SEGUE_GAIN", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table `%s_PRE` add column \ + DUCK_DOWN_GAIN int default 0 after DUCK_UP_GAIN", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table `%s_POST` add column \ + DUCK_UP_GAIN int default 0 after SEGUE_GAIN", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table `%s_POST` add column \ + DUCK_DOWN_GAIN int default 0 after DUCK_UP_GAIN", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if (ver<132) { + sql="create table if not exists DROPBOXES \ + (ID int auto_increment not null primary key,\ + STATION_NAME char(64),\ + GROUP_NAME char(10),\ + PATH char(255),\ + NORMALIZATION_LEVEL int default 1,\ + AUTOTRIM_LEVEL int default 1,\ + SINGLE_CART enum('N','Y') default 'N',\ + TO_CART int unsigned default 0,\ + USE_CARTCHUNK_ID enum('N','Y') default 'N',\ + DELETE_CUTS enum('N','Y') default 'N',\ + METADATA_PATTERN char(64),\ + FIX_BROKEN_FORMATS enum('N','Y') default 'N',\ + LOG_PATH char(255),\ + index STATION_NAME_IDX (STATION_NAME))"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<133) { + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table `%s_LOG` add column \ + DUCK_UP_GAIN int default 0 after SEGUE_GAIN", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table `%s_LOG` add column \ + DUCK_DOWN_GAIN int default 0 after DUCK_UP_GAIN", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table `%s_PRE` add column \ + DUCK_UP_GAIN int default 0 after SEGUE_GAIN", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table `%s_PRE` add column \ + DUCK_DOWN_GAIN int default 0 after DUCK_UP_GAIN", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table `%s_POST` add column \ + DUCK_UP_GAIN int default 0 after SEGUE_GAIN", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table `%s_POST` add column \ + DUCK_DOWN_GAIN int default 0 after DUCK_UP_GAIN", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<134) { + sql="create table if not exists RDPANEL (\ + ID int not null primary key auto_increment,\ + STATION char(40) not null,\ + INSTANCE int unsigned not null,\ + CARD2 int default -1,\ + PORT2 int default -1,\ + START_RML2 char(255),\ + STOP_RML2 char(255),\ + CARD6 int default -1,\ + PORT6 int default -1,\ + START_RML6 char(255),\ + STOP_RML6 char(255),\ + CARD7 int default -1,\ + PORT7 int default -1,\ + START_RML7 char(255),\ + STOP_RML7 char(255),\ + CARD8 int default -1,\ + PORT8 int default -1,\ + START_RML8 char(255),\ + STOP_RML8 char(255),\ + CARD9 int default -1,\ + PORT9 int default -1,\ + START_RML9 char(255),\ + STOP_RML9 char(255),\ + STATION_PANELS int default 3,\ + USER_PANELS int default 3,\ + CLEAR_FILTER enum('N','Y') default 'N',\ + FLASH_PANEL enum('N','Y') default 'N',\ + PANEL_PAUSE_ENABLED enum('N','Y') default 'N',\ + DEFAULT_SERVICE char(10),\ + index STATION_IDX (STATION,INSTANCE))"; + q=new QSqlQuery(sql); + delete q; + + // + // Create EXTENDED_PANELS Table + // + sql="create table if not exists EXTENDED_PANELS (\ + ID int auto_increment not null primary key,\ + TYPE int not null,\ + OWNER char(64) not null,\ + PANEL_NO int not null,\ + ROW_NO int not null,\ + COLUMN_NO int not null,\ + LABEL char(64),\ + CART int,\ + DEFAULT_COLOR char(7),\ + index LOAD_IDX (TYPE,OWNER,PANEL_NO),\ + index SAVE_IDX (TYPE,OWNER,PANEL_NO,ROW_NO,COLUMN_NO))"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<135) { + sql="alter table STATIONS add column STARTUP_CART int unsigned default 0 \ + after HEARTBEAT_INTERVAL"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<136) { + // + // Create PANEL_NAMES Table + // + sql="create table if not exists PANEL_NAMES (\ + ID int auto_increment not null primary key,\ + TYPE int not null,\ + OWNER char(64) not null,\ + PANEL_NO int not null,\ + NAME char(64),\ + index LOAD_IDX (TYPE,OWNER,PANEL_NO))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + // + // Create EXTENDED_PANEL_NAMES Table + // + sql="create table if not exists EXTENDED_PANEL_NAMES (\ + ID int auto_increment not null primary key,\ + TYPE int not null,\ + OWNER char(64) not null,\ + PANEL_NO int not null,\ + NAME char(64),\ + index LOAD_IDX (TYPE,OWNER,PANEL_NO))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + } + + if(ver<137) { + sql="alter table CART add column AVERAGE_HOOK_LENGTH int unsigned \ + default 0 after AVERAGE_SEGUE_LENGTH"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + sql="select NUMBER from CART"; + q=new QSqlQuery(sql); + while(q->next()) { + cart=new RDCart(q->value(0).toUInt()); + cart->updateLength(); + delete cart; + } + delete q; + } + + if(ver<138) { + sql="alter table RDAIRPLAY add column BUTTON_LABEL_TEMPLATE char(32) \ + default \"%t\" after PANEL_PAUSE_ENABLED"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDPANEL add column BUTTON_LABEL_TEMPLATE char(32) \ + default \"%t\" after PANEL_PAUSE_ENABLED"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<139) { + sql="alter table RDAIRPLAY modify EXIT_PASSWORD char(41) default \"\""; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<140) { + sql="alter table SERVICES add column TFC_BREAK_STRING char(64) \ + after TFC_TRACK_CART"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column TFC_TRACK_STRING char(64) \ + after TFC_TRACK_CART"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<141) { + sql="alter table DROPBOXES add column TITLE_FROM_CARTCHUNK_ID enum('N','Y') \ + default 'N' after USE_CARTCHUNK_ID"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<142) { + sql="create table if not exists FEEDS (\ + ID int unsigned auto_increment not null primary key,\ + KEY_NAME char(8) unique not null,\ + CHANNEL_TITLE char(255),\ + CHANNEL_DESCRIPTION text,\ + CHANNEL_CATEGORY char(64),\ + CHANNEL_LINK char(255),\ + CHANNEL_COPYRIGHT char(64),\ + CHANNEL_WEBMASTER char(64),\ + CHANNEL_LANGUAGE char(5) default \"en-us\",\ + BASE_URL char(255),\ + PURGE_URL char(255),\ + PURGE_USERNAME char(64),\ + PURGE_PASSWORD char(64),\ + HEADER_XML text,\ + CHANNEL_XML text,\ + ITEM_XML text,\ + MAX_SHELF_LIFE int,\ + LAST_BUILD_DATETIME datetime,\ + ORIGIN_DATETIME datetime,\ + ENABLE_AUTOPOST enum('N','Y') default 'N',\ + index KEY_NAME_IDX(KEY_NAME))"; + q=new QSqlQuery(sql); + delete q; + + sql="create table if not exists PODCASTS (\ + ID int unsigned auto_increment not null primary key,\ + FEED_ID int unsigned not null,\ + STATUS int unsigned default 0,\ + ITEM_TITLE char(255),\ + ITEM_DESCRIPTION text,\ + ITEM_CATEGORY char(64),\ + ITEM_LINK char(255),\ + AUDIO_FILENAME char(255),\ + AUDIO_LENGTH int unsigned,\ + SHELF_LIFE int,\ + ORIGIN_DATETIME datetime,\ + index FEED_ID_IDX(FEED_ID,ORIGIN_DATETIME))"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RECORDINGS add column FEED_ID int default -1 \ + after URL_PASSWORD"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table VERSION add column LAST_MAINT_DATETIME datetime \ + default \"1970-01-01 00:00:00\" after DB"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<143) { + sql="create table if not exists AUX_METADATA (\ + ID int unsigned auto_increment not null primary key,\ + FEED_ID int unsigned,\ + VAR_NAME char(16),\ + CAPTION char(64),\ + index FEED_ID_IDX(FEED_ID))"; + q=new QSqlQuery(sql); + delete q; + + sql="select KEY_NAME from FEEDS"; + q=new QSqlQuery(sql); + while(q->next()) { + RDCreateAuxFieldsTable(q->value(0).toString()); + } + delete q; + } + + if(ver<144) { + sql="alter table FEEDS add column UPLOAD_FORMAT int default 2 \ + after ENABLE_AUTOPOST"; + q=new QSqlQuery(sql); + delete q; + sql="alter table FEEDS add column UPLOAD_CHANNELS int default 2 \ + after UPLOAD_FORMAT"; + q=new QSqlQuery(sql); + delete q; + sql="alter table FEEDS add column UPLOAD_SAMPRATE int default 44100 \ + after UPLOAD_CHANNELS"; + q=new QSqlQuery(sql); + delete q; + sql="alter table FEEDS add column UPLOAD_BITRATE int default 32000 \ + after UPLOAD_CHANNELS"; + q=new QSqlQuery(sql); + delete q; + sql="alter table FEEDS add column UPLOAD_QUALITY int default 0 \ + after UPLOAD_BITRATE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table FEEDS add column NORMALIZE_LEVEL int default -100 \ + after UPLOAD_QUALITY"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table PODCASTS add column ITEM_COMMENTS char(255) \ + after ITEM_LINK"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table PODCASTS add column ITEM_AUTHOR char(255) \ + after ITEM_COMMENTS"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table PODCASTS add column ITEM_SOURCE_TEXT char(64) \ + after ITEM_AUTHOR"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table PODCASTS add column ITEM_SOURCE_URL char(255) \ + after ITEM_SOURCE_TEXT"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<145) { + sql=QString("create table if not exists FEED_PERMS (\ + ID int unsigned auto_increment not null primary key,\ + USER_NAME char(8),\ + KEY_NAME char(8),\ + index USER_IDX (USER_NAME),\ + index KEYNAME_IDX (KEY_NAME))"); + q=new QSqlQuery(sql); + delete q; + + sql="select LOGIN_NAME from USERS \ + where (ADMIN_USERS_PRIV='N')&&(ADMIN_CONFIG_PRIV='N')"; + q=new QSqlQuery(sql); + sql="select KEY_NAME from FEEDS"; + q1=new QSqlQuery(sql); + while(q->next()) { + while(q1->next()) { + sql=QString().sprintf("insert into FEED_PERMS set USER_NAME=\"%s\",\ + KEY_NAME=\"%s\"", + (const char *)q->value(0).toString(), + (const char *)q1->value(0).toString()); + q2=new QSqlQuery(sql); + delete q2; + } + q1->seek(-1); + } + delete q1; + delete q; + + + sql="alter table USERS add column ADD_PODCAST_PRIV enum('N','Y') \ + not null default 'N' after EDIT_CATCHES_PRIV"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table USERS add column EDIT_PODCAST_PRIV enum('N','Y') \ + not null default 'N' after ADD_PODCAST_PRIV"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table USERS add column DELETE_PODCAST_PRIV enum('N','Y') \ + not null default 'N' after EDIT_PODCAST_PRIV"; + q=new QSqlQuery(sql); + delete q; + + sql="update USERS set ADD_PODCAST_PRIV='Y',EDIT_PODCAST_PRIV='Y',\ + DELETE_PODCAST_PRIV='Y' \ + where (ADMIN_CONFIG_PRIV='N')&&(ADMIN_USERS_PRIV='N')"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<146) { + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table %s_POST add column\ + EXT_CART_NAME char(32) after EXT_LENGTH", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column\ + EXT_ANNC_TYPE char(8) after EXT_EVENT_ID", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column\ + EVENT_SOURCE int default 0 after EVENT_TYPE", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString().sprintf("alter table %s_POST add column\ + EXT_ANNC_TYPE char(8) after EXT_EVENT_ID", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<147) { + sql="alter table USERS add column ENABLE_WEB enum('N','Y') default 'N' \ + after PASSWORD"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("create table if not exists WEB_CONNECTIONS (\ + SESSION_ID int unsigned not null primary key,\ + LOGIN_NAME char(8),\ + IP_ADDRESS char(16),\ + TIME_STAMP datetime)"); + q=new QSqlQuery(sql); + delete q; + } + + if(ver<148) { + sql=QString().sprintf("alter table CUTS add column\ + SEGUE_GAIN int default %d after SEGUE_END_POINT",RD_FADE_DEPTH); + q=new QSqlQuery(sql); + delete q; + } + + if(ver<148) { + sql="alter table PODCASTS add column AUDIO_TIME int unsigned \ + after AUDIO_LENGTH"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<149) { + sql="create table if not exists SWITCHER_NODES (\ + ID int not null auto_increment primary key,\ + STATION_NAME char(64),\ + MATRIX int,\ + BASE_OUTPUT int default 0,\ + HOSTNAME char(64),\ + PASSWORD char(64),\ + TCP_PORT int,\ + DESCRIPTION char(255),\ + index STATION_IDX (STATION_NAME,MATRIX))"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table INPUTS add column NODE_HOSTNAME char(255) \ + after DEVICE_NUM"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table INPUTS add column NODE_TCP_PORT int \ + after NODE_HOSTNAME"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table INPUTS add column NODE_SLOT int \ + after NODE_TCP_PORT"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table add index \ + NODE_IDX(STATION_NAME,MATRIX,NUMBER,NODE_HOSTNAME,NODE_TCP_PORT)"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table OUTPUTS add column NODE_HOSTNAME char(255) \ + after DEVICE_NUM"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table OUTPUTS add column NODE_TCP_PORT int \ + after NODE_HOSTNAME"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table OUTPUTS add column NODE_SLOT int \ + after NODE_TCP_PORT"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table add index \ + NODE_IDX(STATION_NAME,MATRIX,NUMBER,NODE_HOSTNAME,NODE_TCP_PORT)"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<150) { + sql="alter table MATRICES add column PORT_2 int not null after PORT"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table MATRICES add column PORT_TYPE_2 int default 0 \ + after PORT_TYPE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table MATRICES add column IP_ADDRESS_2 char(16) \ + after IP_ADDRESS"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table MATRICES add column IP_PORT_2 int after IP_PORT"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table MATRICES add column USERNAME_2 char(32) after USERNAME"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table MATRICES add column PASSWORD_2 char(32) after PASSWORD"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<151) { + sql="alter table FEEDS add column KEEP_METADATA enum('N','Y') default 'Y' \ + after ENABLE_AUTOPOST"; + q=new QSqlQuery(sql); + delete q; + + sql="select KEY_NAME from FEEDS"; + q=new QSqlQuery(sql); + while(q->next()) { + RDCreateFeedLog(q->value(0).toString()); + } + delete q; + } + + if(ver<152) { + sql="alter table STATIONS add column EDITOR_PATH char(255) default \"\"\ + after STARTUP_CART"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDPANEL add column CARD3 int default -1 \ + after STOP_RML2"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDPANEL add column PORT3 int default -1 \ + after CARD3"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDPANEL add column START_RML3 char(255) \ + after PORT3"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDPANEL add column STOP_RML3 char(255) \ + after START_RML3"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<153) { + sql="alter table STATIONS add column FILTER_MODE int default 0 \ + after EDITOR_PATH"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<154) { + sql=QString().sprintf("alter table CUTS add column\ + SEGUE_GAIN int default %d after SEGUE_END_POINT",RD_FADE_DEPTH); + q=new QSqlQuery(sql); + delete q; + } + + if(ver<155) { + sql="alter table RDLIBRARY add column ENABLE_EDITOR enum('N','Y') \ + default 'N' after CDDB_SERVER"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<156) { + sql="alter table MATRICES add column LAYER int default 86 after TYPE"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<157) { + sql="alter table STATIONS \ + add column BROADCAST_SECURITY int unsigned \ + default 0 after BACKUP_LIFE"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<158) { // Convert OVERLAP to SEGUE + sql="select NAME from LOGS;"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("update %s_LOG set TRANS_TYPE=1,SEGUE_GAIN=0 \ + where TRANS_TYPE=3",(const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<159) { + sql="alter table RDAIRPLAY add column SKIN_PATH char(255) \ + default \""; + sql+=RD_DEFAULT_RDAIRPLAY_SKIN; + sql+="\" after EXIT_PASSWORD"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDPANEL add column SKIN_PATH char(255) \ + default \""; + sql+=RD_DEFAULT_RDPANEL_SKIN; + sql+="\" after DEFAULT_SERVICE"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<160) { + // + // Create ENCODERS Table + // + sql="create table if not exists ENCODERS (\ + ID int not null auto_increment primary key,\ + NAME char(32) not null,\ + STATION_NAME char(64),\ + COMMAND_LINE char(255),\ + DEFAULT_EXTENSION char(16),\ + index NAME_IDX(NAME,STATION_NAME))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + // Ensure that dynamic format IDs start after 100 + sql="insert into ENCODERS set ID=100,NAME=\"dummy\""; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + sql="delete from ENCODERS where ID=100"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + // + // Create ENCODER_BITRATES Table + // + sql="create table if not exists ENCODER_BITRATES (\ + ID int not null auto_increment primary key,\ + ENCODER_ID int not null,\ + BITRATES int not null,\ + index ENCODER_ID_IDX(ENCODER_ID))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + // + // Create ENCODER_CHANNELS Table + // + sql="create table if not exists ENCODER_CHANNELS (\ + ID int not null auto_increment primary key,\ + ENCODER_ID int not null,\ + CHANNELS int not null,\ + index ENCODER_ID_IDX(ENCODER_ID))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + // + // Create ENCODER_SAMPLERATES Table + // + sql="create table if not exists ENCODER_SAMPLERATES (\ + ID int not null auto_increment primary key, \ + ENCODER_ID int not null, \ + SAMPLERATES int not null,\ + index ENCODER_ID_IDX(ENCODER_ID))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + } + + if(ver<161) { + sql="alter table FEEDS add column UPLOAD_EXTENSION char(16) default \"mp3\"\ + after UPLOAD_QUALITY"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + } + + if(ver<162) { + sql="alter table GPIS alter column MACRO_CART set default 0"; + q=new QSqlQuery(sql); + delete q; + + sql="create table if not exists GPOS (\ + ID int auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + MATRIX int not null,\ + NUMBER int not null,\ + MACRO_CART int default 0,\ + index MATRIX_IDX (STATION_NAME,MATRIX,NUMBER))"; + q=new QSqlQuery(sql); + delete q; + + sql="select STATION_NAME,MATRIX,GPOS from MATRICES"; + q=new QSqlQuery(sql); + while(q->next()) { + for(int i=0;ivalue(2).toInt();i++) { + sql=QString().sprintf("insert into GPOS set \ + STATION_NAME=\"%s\",\ + MATRIX=%d,\ + NUMBER=%d,\ + MACRO_CART=0", + (const char *)q->value(0).toString(), + q->value(1).toInt(), + i+1); + q1=new QSqlQuery(sql); + delete q1; + } + } + delete q; + } + + if(ver<163) { + sql="alter table RECORDINGS add column EVENTDATE_OFFSET int default 0 \ + after ENDDATE_OFFSET"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<164) { + sql="create table if not exists NOWNEXT_PLUGINS (\ + ID int auto_increment not null primary key, \ + STATION_NAME char(64) not null, \ + LOG_MACHINE int unsigned not null default 0, \ + PLUGIN_PATH char(255),\ + PLUGIN_ARG char(255),\ + index STATION_IDX (STATION_NAME,LOG_MACHINE))"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<165) { + sql="create table if not exists DROPBOX_PATHS (\ + ID int auto_increment not null primary key,\ + DROPBOX_ID int not null,\ + FILE_PATH char(255) not null,\ + FILE_DATETIME datetime,\ + index FILE_PATH_IDX (DROPBOX_ID,FILE_PATH))"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table DROPBOXES add DELETE_SOURCE enum('N','Y') default 'Y' \ + after DELETE_CUTS"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table DROPBOXES add column STARTDATE_OFFSET int default 0 \ + after METADATA_PATTERN"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table DROPBOXES add column ENDDATE_OFFSET int default 0 \ + after STARTDATE_OFFSET"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<166) { + sql="alter table GROUPS add column CUT_SHELFLIFE int default -1 \ + after DEFAULT_HIGH_CART"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table GROUPS add column DEFAULT_TITLE char(255) \ + default \"Imported from %f.%e\" after CUT_SHELFLIFE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table STATIONS add column SYSTEM_MAINT enum('N','Y') \ + default 'Y' after FILTER_MODE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column ELR_SHELFLIFE int default -1 \ + after AUTO_REFRESH"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table EVENTS add column REMARKS char(255) after NESTED_EVENT"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table CLOCKS add column REMARKS char(255) after COLOR"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<167) { + sql="alter table RDAIRPLAY add column LOG0_NOW_CART int unsigned default 0 \ + after LOG0_LOG_LINE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG0_NEXT_CART int unsigned default 0\ + after LOG0_NOW_CART"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG1_NOW_CART int unsigned default 0 \ + after LOG1_LOG_LINE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG1_NEXT_CART int unsigned default 0\ + after LOG1_NOW_CART"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG2_NOW_CART int unsigned default 0 \ + after LOG2_LOG_LINE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column LOG2_NEXT_CART int unsigned default 0\ + after LOG2_NOW_CART"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<168) { + sql="alter table GPIS add column OFF_MACRO_CART int default 0 \ + after MACRO_CART"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table GPOS add column OFF_MACRO_CART int default 0 \ + after MACRO_CART"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<169) { + sql="alter table SERVICES add column DEFAULT_LOG_SHELFLIFE int default -1 \ + after AUTO_REFRESH"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table LOGS add column PURGE_DATE date after END_DATE"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<170) { + sql="alter table USERS modify column LOGIN_NAME char(255) not null"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table USERS modify column FULL_NAME char(255)"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table FEED_PERMS modify column USER_NAME char(255)"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table LOGS modify column ORIGIN_USER char(255) not null"; + q=new QSqlQuery(sql); + delete q; + + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString(). + sprintf("alter table %s_LOG modify column ORIGIN_USER char(255)", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString(). + sprintf("alter table %s_PRE modify column ORIGIN_USER char(255)", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + sql=QString(). + sprintf("alter table %s_POST modify column ORIGIN_USER char(255)", + (const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + sql="alter table STATIONS modify column USER_NAME char(255)"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table STATIONS modify column DEFAULT_NAME char(255)"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table USER_PERMS modify column USER_NAME char(255)"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table WEB_CONNECTIONS modify column LOGIN_NAME char(255)"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<171) { + sql="alter table FEEDS add column CAST_ORDER enum('N','Y') default 'N' \ + after ITEM_XML"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table PODCASTS add column EFFECTIVE_DATETIME datetime \ + after ORIGIN_DATETIME"; + q=new QSqlQuery(sql); + delete q; + + sql="select ID,ORIGIN_DATETIME from PODCASTS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("update PODCASTS set EFFECTIVE_DATETIME=\"%s\" \ + where ID=%u", + (const char *)q->value(1).toDateTime(). + toString("yyyy-MM-dd hh:mm:ss"), + q->value(0).toUInt()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<172) { + sql="alter table FEEDS add column REDIRECT_PATH char(255) \ + after NORMALIZE_LEVEL"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<173) { + sql="alter table FEEDS add column BASE_PREAMBLE char(255) after BASE_URL"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<174) { + sql="alter table MATRICES add column START_CART int unsigned \ + after PASSWORD_2"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table MATRICES add column STOP_CART int unsigned \ + after START_CART"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table MATRICES add column START_CART_2 int unsigned \ + after STOP_CART"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table MATRICES add column STOP_CART_2 int unsigned \ + after START_CART_2"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<175) { + sql="create table if not exists SYSTEM (\ + ID int auto_increment not null primary key, \ + DUP_CART_TITLES enum('N','Y') not null default 'Y')"; + q=new QSqlQuery(sql); + delete q; + sql="insert into SYSTEM set DUP_CART_TITLES=\"Y\""; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<176) { + sql="alter table RDAIRPLAY add column \ + SHOW_COUNTERS enum('N','Y') default 'N' after SKIN_PATH"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table RDAIRPLAY add column AUDITION_PREROLL int default 10000 \ + after SHOW_COUNTERS"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<177) { + sql="alter table RDPANEL add column SKIN_PATH char(255) \ + default \""; + sql+=RD_DEFAULT_RDPANEL_SKIN; + sql+="\" after DEFAULT_SERVICE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table PANELS drop column SKIN_PATH"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<178) { + sql="alter table PODCASTS modify column STATUS int unsigned default 1"; + q=new QSqlQuery(sql); + delete q; + + sql=QString().sprintf("alter table SYSTEM add column \ + MAX_POST_LENGTH int unsigned default %u \ + after DUP_CART_TITLES", + RD_DEFAULT_MAX_POST_LENGTH); + q=new QSqlQuery(sql); + delete q; + } + + if(ver<179) { + sql="alter table FEEDS add column MEDIA_LINK_MODE int default 0 \ + after REDIRECT_PATH"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<180) { + sql="alter table RDLIBRARY add column SRC_CONVERTER int default 1 \ + after ENABLE_EDITOR"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<181) { + sql=QString().sprintf("select NUMBER from CART where TYPE=%u", + RDCart::Audio); + q=new QSqlQuery(sql); + while(q->next()) { + cart=new RDCart(q->value(0).toUInt()); + cart->updateLength(); + delete cart; + } + delete q; + } + + if(ver<182) { + sql="alter table CART add column NOTES text after MACROS"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<183) { + sql="create table if not exists IMPORT_TEMPLATES (\ + NAME char(64) not null primary key,\ + CART_OFFSET int,\ + CART_LENGTH int,\ + TITLE_OFFSET int,\ + TITLE_LENGTH int,\ + HOURS_OFFSET int,\ + HOURS_LENGTH int,\ + MINUTES_OFFSET int,\ + MINUTES_LENGTH int,\ + SECONDS_OFFSET int,\ + SECONDS_LENGTH int,\ + LEN_HOURS_OFFSET int,\ + LEN_HOURS_LENGTH int,\ + LEN_MINUTES_OFFSET int,\ + LEN_MINUTES_LENGTH int,\ + LEN_SECONDS_OFFSET int,\ + LEN_SECONDS_LENGTH int,\ + LENGTH_OFFSET int,\ + LENGTH_LENGTH int,\ + DATA_OFFSET int,\ + DATA_LENGTH int,\ + EVENT_ID_OFFSET int,\ + EVENT_ID_LENGTH int,\ + ANNC_TYPE_OFFSET int,\ + ANNC_TYPE_LENGTH int)"; + q=new QSqlQuery(sql); + delete q; + UpdateImportFormats(); + + sql="alter table SERVICES add column TFC_IMPORT_TEMPLATE char(64)\ + default \"Rivendell Standard Import\" after TFC_WIN_PATH"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column MUS_IMPORT_TEMPLATE char(64)\ + default \"Rivendell Standard Import\" after MUS_WIN_PATH"; + q=new QSqlQuery(sql); + delete q; + + sql="update SERVICES set TFC_IMPORT_TEMPLATE=\"\""; + q=new QSqlQuery(sql); + delete q; + + sql="update SERVICES set MUS_IMPORT_TEMPLATE=\"\""; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<184) { + UpdateImportFormats(); + } + + if(ver<185) { + sql="alter table SERVICES add column TFC_PREIMPORT_CMD text \ + after TFC_PATH"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column TFC_WIN_PREIMPORT_CMD text \ + after TFC_WIN_PATH"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column MUS_PREIMPORT_CMD text \ + after MUS_PATH"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table SERVICES add column MUS_WIN_PREIMPORT_CMD text \ + after MUS_WIN_PATH"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<186) { + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + UpdateLogTable(tablename+"_LOG"); + } + delete q; + + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + UpdateLogTable(tablename+"_PRE"); + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + UpdateLogTable(tablename+"_POST"); + } + + sql="select NAME from CLOCKS"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + ConvertTimeField(tablename+"_CLK","START_TIME"); + } + delete q; + } + + if(ver<187) { + sql="alter table CUTS add column ISCI char(32) after ISRC"; + q=new QSqlQuery(sql); + delete q; + + sql="select NAME from SERVICES"; + q=new QSqlQuery(sql); + while(q->next()) { + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("alter table `%s_SRT` add column ISCI char(32)\ + after ISRC",(const char *)tablename); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<188) { + } + + if(ver<189) { + sql="alter table CUTS add column UPLOAD_DATETIME datetime \ + after LAST_PLAY_DATETIME"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<190) { + sql="alter table STATIONS add column HAVE_TWOLAME enum('N','Y') default 'N'\ + after HAVE_FLAC"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<191) { + sql="alter table SERVICES add column PROGRAM_CODE char(255) \ + after NAME_TEMPLATE"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<192) { + sql="alter table RECORDINGS add column EXIT_TEXT text after EXIT_CODE"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<193) { + sql="alter table STATIONS alter column IPV4_ADDRESS \ + set default \"127.0.0.2\""; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<194) { + sql=QString().sprintf("alter table SYSTEM add column \ + SAMPLE_RATE int unsigned default %d after ID", + RD_DEFAULT_SAMPLE_RATE);; + q=new QSqlQuery(sql); + delete q; + sql="select DEFAULT_SAMPRATE from RDLIBRARY"; + q=new QSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("update SYSTEM set SAMPLE_RATE=%u", + q->value(0).toUInt()); + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + if(ver<195) { + sql="alter table RECORDINGS add column ENABLE_METADATA enum('N','Y') \ + default 'N' after URL_PASSWORD"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<196) { + sql="alter table DROPBOXES add column IMPORT_CREATE_DATES enum('N','Y') default 'N' \ + after LOG_PATH"; + q=new QSqlQuery(sql); + delete q; + sql="alter table DROPBOXES add column CREATE_STARTDATE_OFFSET int default 0 \ + after IMPORT_CREATE_DATES"; + q=new QSqlQuery(sql); + delete q; + sql="alter table DROPBOXES add column CREATE_ENDDATE_OFFSET int default 0 \ + after CREATE_STARTDATE_OFFSET"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<197) { + sql=QString().sprintf("create table if not exists REPLICATORS (\ + NAME char(32) not null primary key,\ + DESCRIPTION char(64),\ + TYPE_ID int unsigned not null,\ + STATION_NAME char(64),\ + FORMAT int unsigned default 0,\ + CHANNELS int unsigned default 2,\ + SAMPRATE int unsigned default %u,\ + BITRATE int unsigned default 0,\ + QUALITY int unsigned default 0,\ + URL char(255),\ + URL_USERNAME char(64),\ + URL_PASSWORD char(64),\ + ENABLE_METADATA enum('N','Y') default 'N',\ + NORMALIZATION_LEVEL int unsigned default 0,\ + index TYPE_ID_IDX (TYPE_ID))", + RD_DEFAULT_SAMPLE_RATE); + q=new QSqlQuery(sql); + delete q; + + sql="create table if not exists REPLICATOR_MAP (\ + ID int unsigned not null auto_increment primary key,\ + REPLICATOR_NAME char(32) not null,\ + GROUP_NAME char(10) not null,\ + index REPLICATOR_NAME_IDX(REPLICATOR_NAME),\ + index GROUP_NAME_IDX(GROUP_NAME))"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table CART add column METADATA_DATETIME datetime after NOTES"; + q=new QSqlQuery(sql); + delete q; + sql="update CART set METADATA_DATETIME=now()"; + q=new QSqlQuery(sql); + delete q; + + // + // Create REPL_CART_STATE Table + // + sql="create table if not exists REPL_CART_STATE (\ + ID int unsigned not null auto_increment primary key,\ + REPLICATOR_NAME char(32) not null,\ + CART_NUMBER int unsigned not null,\ + ITEM_DATETIME datetime not null,\ + unique REPLICATOR_NAME_IDX(REPLICATOR_NAME,CART_NUMBER))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + // + // Create REPL_CUT_STATE Table + // + sql="create table if not exists REPL_CUT_STATE (\ + ID int unsigned not null auto_increment primary key,\ + REPLICATOR_NAME char(32) not null,\ + CUT_NAME char(12) not null,\ + ITEM_DATETIME datetime not null,\ + index REPLICATOR_NAME_IDX(REPLICATOR_NAME),\ + index CUT_NAME_IDX(CUT_NAME))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + } + + if(ver<198) { + sql="create table if not exists ISCI_XREFERENCE (\ + ID int unsigned not null auto_increment primary key,\ + CART_NUMBER int unsigned not null,\ + ISCI char(32) not null,\ + FILENAME char(64) not null,\ + LATEST_DATE date not null,\ + TYPE char(1) not null,\ + ADVERTISER_NAME char(30),\ + PRODUCT_NAME char(35),\ + CREATIVE_TITLE char(30),\ + REGION_NAME char(80),\ + index CART_NUMBER_IDX(CART_NUMBER))"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + sql="alter table VERSION add column LAST_ISCI_XREFERENCE datetime \ + default \"1970-01-01 00:00:00\" after LAST_MAINT_DATETIME"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + sql="alter table SYSTEM add column ISCI_XREFERENCE_PATH char(255) \ + after MAX_POST_LENGTH"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + } + + if(ver<199) { + sql="create index TYPE_IDX on ISCI_XREFERENCE (TYPE,LATEST_DATE)"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + sql="create index LATEST_DATE_IDX on ISCI_XREFERENCE (LATEST_DATE)"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + } + + if(ver<200) { + } + + if(ver<201) { + sql="alter table STATIONS add column HTTP_STATION char(64) \ + default \"localhost\" after IPV4_ADDRESS"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + + sql="alter table STATIONS add column CAE_STATION char(64) \ + default \"localhost\" after HTTP_STATION"; + if(!RunQuery(sql)) { + return UPDATEDB_QUERY_FAILED; + } + } + + if(ver<202) { + sql=QString("CREATE TABLE IF NOT EXISTS RDHOTKEYS (\ + ID int unsigned not null auto_increment primary key, \ + STATION_NAME CHAR(64), \ + MODULE_NAME CHAR(64), \ + KEY_ID int, \ + KEY_VALUE CHAR(64), \ + KEY_LABEL CHAR(64)) "); + q=new QSqlQuery(sql); + delete q; + + sql="select NAME from STATIONS"; + q=new QSqlQuery(sql); + while(q->next()) { + if (!UpdateRDAirplayHotkeys((const char *)q->value(0).toString())) { + return UPDATEDB_QUERY_FAILED; + } + } + delete q; + } + + if(ver<203) { + sql= + "alter table REPLICATORS drop column NORMALIZATION_LEVEL"; + q=new QSqlQuery(sql); + delete q; + sql= + "alter table REPLICATORS add column NORMALIZATION_LEVEL int default 0 \ + after ENABLE_METADATA"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table REPL_CART_STATE add column REPOST enum('N','Y') \ + default 'N' after ITEM_DATETIME"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table REPL_CART_STATE add column POSTED_FILENAME char(255) \ + after CART_NUMBER"; + q=new QSqlQuery(sql); + delete q; + + sql="drop index REPLICATOR_NAME_IDX on REPL_CART_STATE"; + q=new QSqlQuery(sql); + delete q; + + sql="create unique index REPLICATOR_NAME_IDX on REPL_CART_STATE \ + (REPLICATOR_NAME,CART_NUMBER,POSTED_FILENAME)"; + q=new QSqlQuery(sql); + delete q; + + sql="delete from REPL_CART_STATE where POSTED_FILENAME is null"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<204) { + sql="insert into IMPORT_TEMPLATES set\ + NAME=\"The Traffic Light\",\ + CART_OFFSET=10,\ + CART_LENGTH=6,\ + TITLE_OFFSET=25,\ + TITLE_LENGTH=34,\ + HOURS_OFFSET=0,\ + HOURS_LENGTH=2,\ + MINUTES_OFFSET=3,\ + MINUTES_LENGTH=2,\ + SECONDS_OFFSET=6,\ + SECONDS_LENGTH=2,\ + LEN_HOURS_OFFSET=60,\ + LEN_HOURS_LENGTH=2,\ + LEN_MINUTES_OFFSET=63,\ + LEN_MINUTES_LENGTH=2,\ + LEN_SECONDS_OFFSET=66,\ + LEN_SECONDS_LENGTH=2,\ + DATA_OFFSET=69,\ + DATA_LENGTH=32"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<205) { + sql="alter table STATIONS add column START_JACK enum('N','Y') default 'N' \ + after FILTER_MODE"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table STATIONS add column JACK_SERVER_NAME char(64) \ + after START_JACK"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<206) { + sql=QString("create table if not exists REPORT_GROUPS (\ + ID int unsigned auto_increment not null primary key,\ + REPORT_NAME char(64) not null,\ + GROUP_NAME char(10),\ + index IDX_REPORT_NAME (REPORT_NAME))"); + q=new QSqlQuery(sql); + delete q; + + sql="alter table REPORTS add column FILTER_GROUPS enum('N','Y') \ + default 'N' after FILTER_ONAIR_FLAG"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<207) { + sql="insert into IMPORT_TEMPLATES set\ + NAME=\"WideOrbit Traffic\",\ + CART_OFFSET=10,\ + CART_LENGTH=6,\ + TITLE_OFFSET=25,\ + TITLE_LENGTH=34,\ + HOURS_OFFSET=0,\ + HOURS_LENGTH=2,\ + MINUTES_OFFSET=3,\ + MINUTES_LENGTH=2,\ + SECONDS_OFFSET=6,\ + SECONDS_LENGTH=2,\ + LEN_HOURS_OFFSET=60,\ + LEN_HOURS_LENGTH=2,\ + LEN_MINUTES_OFFSET=63,\ + LEN_MINUTES_LENGTH=2,\ + LEN_SECONDS_OFFSET=66,\ + LEN_SECONDS_LENGTH=2,\ + EVENT_ID_OFFSET=69,\ + EVENT_ID_LENGTH=32,\ + DATA_OFFSET=102,\ + DATA_LENGTH=32"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<208) { + sql="alter table RDAIRPLAY add column HOUR_SELECTOR_ENABLED enum('N','Y') \ + default 'N' after DEFAULT_SERVICE"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<209) { + sql="alter table STATIONS add column JACK_COMMAND_LINE char(255) \ + after JACK_SERVER_NAME"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("create table if not exists JACK_CLIENTS (\ + ID int unsigned auto_increment not null primary key,\ + STATION_NAME char(64) not null,\ + DESCRIPTION char(64),\ + COMMAND_LINE char(255) not null,\ + index IDX_STATION_NAME (STATION_NAME))"); + q=new QSqlQuery(sql); + delete q; + } + + if(ver<210) { + sql=QString("create table if not exists CARTSLOTS (")+ + "ID int unsigned auto_increment not null primary key,"+ + "STATION_NAME char(64) not null,"+ + "SLOT_NUMBER int unsigned not null,"+ + "MODE int not null default 0,"+ + "DEFAULT_MODE int not null default -1,"+ + "STOP_ACTION int not null default 0,"+ + "DEFAULT_STOP_ACTION int not null default -1,"+ + "CART_NUMBER int default 0,"+ + "DEFAULT_CART_NUMBER int not null default 0,"+ + "SERVICE_NAME char(10),"+ + "CARD int not null default 0,"+ + "INPUT_PORT int not null default 0,"+ + "OUTPUT_PORT int not null default 0,"+ + "index STATION_NAME_IDX(STATION_NAME,SLOT_NUMBER))"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<211) { + sql=QString("alter table SYSTEM add column TEMP_CART_GROUP char(10) ")+ + "default \"TEMP\" after ISCI_XREFERENCE_PATH"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<212) { + sql=QString("alter table CARTSLOTS add column HOOK_MODE int default 0 ")+ + "after DEFAULT_CART_NUMBER"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table CARTSLOTS add column DEFAULT_HOOK_MODE int ")+ + "default -1 after HOOK_MODE"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<213) { + sql=QString("alter table STATIONS add column CUE_CARD int default 0 ")+ + "after JACK_COMMAND_LINE"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table STATIONS add column CUE_PORT int default 0 ")+ + "after CUE_CARD"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table STATIONS add column CARTSLOT_COLUMNS int ")+ + "default 1 after CUE_PORT"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table STATIONS add column CARTSLOT_ROWS int ")+ + "default 8 after CARTSLOT_COLUMNS"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("select STATION_NAME,CARD_NUMBER,PORT_NUMBER from DECKS ")+ + "where CHANNEL=0"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString("update STATIONS set ")+ + QString().sprintf("CUE_CARD=%d,",q->value(1).toInt())+ + QString().sprintf("CUE_PORT=%d ",q->value(2).toInt())+ + "where NAME=\""+RDEscapeString(q->value(0).toString())+"\""; + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<214) { + sql=QString("alter table SERVICES add column AUTOSPOT_GROUP char(10) ")+ + "after TRACK_GROUP"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<215) { + sql=QString("alter table GROUPS add column DELETE_EMPTY_CARTS ")+ + "enum('N','Y') default 'N' after CUT_SHELFLIFE"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<216) { + sql="alter table CUTS add index ISCI_IDX(ISCI)"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table CUTS add index ISRC_IDX(ISRC)"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<217) { + sql=QString("create table if not exists LIVEWIRE_GPIO_SLOTS (")+ + "ID int unsigned auto_increment not null primary key,"+ + "STATION_NAME char(64) not null,"+ + "MATRIX int not null,"+ + "SLOT int not null,"+ + "SOURCE_NUMBER int,"+ + "index STATION_NAME_IDX(STATION_NAME,MATRIX))"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<218) { + sql=QString("alter table LIVEWIRE_GPIO_SLOTS ")+ + "add column IP_ADDRESS char(15) after SLOT"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<219) { + // + // RDAirPlay Channels + // + sql=QString("create table if not exists RDAIRPLAY_CHANNELS (")+ + "ID int unsigned auto_increment not null primary key,"+ + "STATION_NAME char(64) not null,"+ + "INSTANCE int unsigned not null,"+ + "CARD int not null default 0,"+ + "PORT int not null default 0,"+ + "START_RML char(255),"+ + "STOP_RML char(255),"+ + "START_GPI_MATRIX int not null default -1,"+ + "START_GPI_LINE int not null default -1,"+ + "START_GPO_MATRIX int not null default -1,"+ + "START_GPO_LINE int not null default -1,"+ + "STOP_GPI_MATRIX int not null default -1,"+ + "STOP_GPI_LINE int not null default -1,"+ + "STOP_GPO_MATRIX int not null default -1,"+ + "STOP_GPO_LINE int not null default -1,"+ + "index STATION_NAME_IDX(STATION_NAME,INSTANCE))"; + q=new QSqlQuery(sql); + delete q; + + for(unsigned i=0;i<10;i++) { + sql=QString(). + sprintf("select STATION,CARD%u,PORT%u,START_RML%u,STOP_RML%u ", + i,i,i,i)+ + "from RDAIRPLAY"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString("insert into RDAIRPLAY_CHANNELS set ")+ + "STATION_NAME=\""+RDEscapeString(q->value(0).toString())+"\","+ + QString().sprintf("INSTANCE=%u,",i)+ + QString().sprintf("CARD=%d,",q->value(1).toInt())+ + QString().sprintf("PORT=%d,",q->value(2).toInt())+ + "START_RML=\""+RDEscapeString(q->value(3).toString())+"\","+ + "STOP_RML=\""+RDEscapeString(q->value(4).toString())+"\""; + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + // + // RDPanel Channels + // + sql=QString("create table if not exists RDPANEL_CHANNELS (")+ + "ID int unsigned auto_increment not null primary key,"+ + "STATION_NAME char(64) not null,"+ + "INSTANCE int unsigned not null,"+ + "CARD int not null default 0,"+ + "PORT int not null default 0,"+ + "START_RML char(255),"+ + "STOP_RML char(255),"+ + "START_GPI_MATRIX int not null default -1,"+ + "START_GPI_LINE int not null default -1,"+ + "START_GPO_MATRIX int not null default -1,"+ + "START_GPO_LINE int not null default -1,"+ + "STOP_GPI_MATRIX int not null default -1,"+ + "STOP_GPI_LINE int not null default -1,"+ + "STOP_GPO_MATRIX int not null default -1,"+ + "STOP_GPO_LINE int not null default -1,"+ + "index STATION_NAME_IDX(STATION_NAME,INSTANCE))"; + q=new QSqlQuery(sql); + delete q; + + for(unsigned i=0;i<10;i++) { + if((i==2)||(i==3)||(i==6)||(i==7)||(i==8)||(i==9)) { + sql=QString(). + sprintf("select STATION,CARD%u,PORT%u,START_RML%u,STOP_RML%u ", + i,i,i,i)+ + "from RDPANEL"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString("insert into RDPANEL_CHANNELS set ")+ + "STATION_NAME=\""+RDEscapeString(q->value(0).toString())+"\","+ + QString().sprintf("INSTANCE=%u,",i)+ + QString().sprintf("CARD=%d,",q->value(1).toInt())+ + QString().sprintf("PORT=%d,",q->value(2).toInt())+ + "START_RML=\""+RDEscapeString(q->value(3).toString())+"\","+ + "STOP_RML=\""+RDEscapeString(q->value(4).toString())+"\""; + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + } + + // + // Clean Up RDAirPlay + // + sql="alter table RDAIRPLAY drop column INSTANCE"; + q=new QSqlQuery(sql); + delete q; + for(unsigned i=0;i<10;i++) { + sql=QString().sprintf("alter table RDAIRPLAY drop column CARD%u",i); + q=new QSqlQuery(sql); + delete q; + + sql=QString().sprintf("alter table RDAIRPLAY drop column PORT%u",i); + q=new QSqlQuery(sql); + delete q; + + sql=QString().sprintf("alter table RDAIRPLAY drop column START_RML%u",i); + q=new QSqlQuery(sql); + delete q; + + sql=QString().sprintf("alter table RDAIRPLAY drop column STOP_RML%u",i); + q=new QSqlQuery(sql); + delete q; + } + + // + // Clean Up RDPanel + // + sql="alter table RDPANEL drop column INSTANCE"; + q=new QSqlQuery(sql); + delete q; + for(unsigned i=0;i<10;i++) { + if((i==2)||(i==3)||(i==6)||(i==7)||(i==8)||(i==9)) { + sql=QString().sprintf("alter table RDPANEL drop column CARD%u",i); + q=new QSqlQuery(sql); + delete q; + + sql=QString().sprintf("alter table RDPANEL drop column PORT%u",i); + q=new QSqlQuery(sql); + delete q; + + sql=QString().sprintf("alter table RDPANEL drop column START_RML%u",i); + q=new QSqlQuery(sql); + delete q; + + sql=QString().sprintf("alter table RDPANEL drop column STOP_RML%u",i); + q=new QSqlQuery(sql); + delete q; + } + } + + } + + if(ver<220) { + sql=QString("alter table RDAIRPLAY_CHANNELS add column GPIO_TYPE ")+ + "int unsigned default 0 after STOP_RML"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table RDPANEL_CHANNELS add column GPIO_TYPE ")+ + "int unsigned default 0 after STOP_RML"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<221) { + sql="alter table RDLIBRARY modify column TRIM_THRESHOLD int default 0"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<222) { + sql="insert into IMPORT_TEMPLATES set\ + NAME=\"NaturalLog\",\ + CART_OFFSET=9,\ + CART_LENGTH=6,\ + TITLE_OFFSET=19,\ + TITLE_LENGTH=40,\ + HOURS_OFFSET=0,\ + HOURS_LENGTH=2,\ + MINUTES_OFFSET=3,\ + MINUTES_LENGTH=2,\ + SECONDS_OFFSET=6,\ + SECONDS_LENGTH=2,\ + LEN_HOURS_OFFSET=61,\ + LEN_HOURS_LENGTH=2,\ + LEN_MINUTES_OFFSET=64,\ + LEN_MINUTES_LENGTH=2,\ + LEN_SECONDS_OFFSET=67,\ + LEN_SECONDS_LENGTH=2,\ + DATA_OFFSET=0,\ + DATA_LENGTH=0"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<223) { + sql="alter table CART add column CONDUCTOR char(64) after LABEL"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table CART add index CONDUCTOR_IDX(CONDUCTOR)"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table CART add column SONG_ID char(32) after USER_DEFINED"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table CART add index SONG_ID_IDX(SONG_ID)"; + q=new QSqlQuery(sql); + delete q; + + sql="alter table CART add column BPM int unsigned default 0 after SONG_ID"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<224) { + sql=QString("alter table DROPBOXES add column SET_USER_DEFINED char(255) ")+ + "after CREATE_ENDDATE_OFFSET"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<225) { + sql=QString("alter table RDAIRPLAY add column TITLE_TEMPLATE char(64) ")+ + "default '%t' after HOUR_SELECTOR_ENABLED"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table RDAIRPLAY add column ARTIST_TEMPLATE char(64) ")+ + "default '%a' after TITLE_TEMPLATE"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table RDAIRPLAY add column OUTCUE_TEMPLATE char(64) ")+ + "default '%o' after ARTIST_TEMPLATE"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table RDAIRPLAY add column DESCRIPTION_TEMPLATE char(64) ")+ + "default '%i' after HOUR_SELECTOR_ENABLED"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<226) { + sql=QString("alter table RDLOGEDIT add column ")+ + "ENABLE_SECOND_START enum('N','Y') default 'Y' after BITRATE"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<227) { + sql="alter table LOGS add index TYPE_IDX(TYPE,LOG_EXISTS)"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<228) { + sql=QString("alter table RDLIBRARY add column ")+ + "LIMIT_SEARCH int default 1 after SRC_CONVERTER"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table RDLIBRARY add column ")+ + "SEARCH_LIMITED enum('N','Y') default 'Y' after LIMIT_SEARCH"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<229) { + sql=QString("alter table SERVICES add column ")+ + "DESCRIPTION_TEMPLATE char(255) after NAME_TEMPLATE"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("select NAME from SERVICES"); + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString("update SERVICES set DESCRIPTION_TEMPLATE=\"")+ + RDEscapeString(q->value(0).toString())+" log for %m/%d/%Y\" "+ + "where NAME=\""+RDEscapeString(q->value(0).toString())+"\""; + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<230) { + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql="alter table `"+RDLog::tableName(q->value(0).toString())+ + "` add column EVENT_LENGTH int default -1 after ORIGIN_DATETIME"; + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + sql="alter table `"+RDEvent::preimportTableName(q->value(0).toString())+ + "` add column EVENT_LENGTH int default -1 after ORIGIN_DATETIME"; + q1=new QSqlQuery(sql); + delete q1; + + sql="alter table `"+RDEvent::postimportTableName(q->value(0).toString())+ + "` add column EVENT_LENGTH int default -1 after ORIGIN_DATETIME"; + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<231) { + sql=QString("alter table CART add column ")+ + "USE_EVENT_LENGTH enum('N','Y') default 'N' after METADATA_DATETIME"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<232) { + sql=QString("alter table STATIONS add column ")+ + "ENABLE_DRAGDROP enum('N','Y') default 'Y' after CARTSLOT_ROWS"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table STATIONS add column ")+ + "ENFORCE_PANEL_SETUP enum('N','Y') default 'N' after ENABLE_DRAGDROP"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<233) { + sql=QString("alter table RDAIRPLAY add column ")+ + "LOG_MODE_STYLE int default 0 after START_MODE"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("create table if not exists LOG_MODES (")+ + "ID int unsigned auto_increment not null primary key,"+ + "STATION_NAME char(64) not null,"+ + "MACHINE int unsigned not null,"+ + "START_MODE int not null default 0,"+ + "OP_MODE int not null default 2,"+ + "index STATION_NAME_IDX(STATION_NAME,MACHINE))"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("select STATION,START_MODE,OP_MODE from RDAIRPLAY"); + q=new QSqlQuery(sql); + while(q->next()) { + for(unsigned i=0;i<3;i++) { + sql=QString("insert into LOG_MODES set ")+ + "STATION_NAME=\""+RDEscapeString(q->value(0).toString())+"\","+ + QString().sprintf("MACHINE=%u,",i)+ + QString().sprintf("START_MODE=%d,",q->value(1).toInt())+ + QString().sprintf("OP_MODE=%d",q->value(2).toInt()); + q1=new QSqlQuery(sql); + delete q1; + } + } + delete q; + } + + if(ver<234) { + sql=QString("alter table STATIONS add column ")+ + "CUE_START_CART int unsigned after CUE_PORT"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table STATIONS add column ")+ + "CUE_STOP_CART int unsigned after CUE_START_CART"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<235) { + // Lock Locking Changes, Superceded + } + + if(ver<236) { + sql=QString("select NAME from SERVICES"); + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString("alter table `")+RDSvc::svcTableName(q->value(0).toString())+ + "` add column CONDUCTOR char(64) after LABEL"; + q1=new QSqlQuery(sql); + delete q1; + + sql=QString("alter table `")+RDSvc::svcTableName(q->value(0).toString())+ + "` add column USER_DEFINED char(255) after COMPOSER"; + q1=new QSqlQuery(sql); + delete q1; + + sql=QString("alter table `")+RDSvc::svcTableName(q->value(0).toString())+ + "` add column SONG_ID char(32) after USER_DEFINED"; + q1=new QSqlQuery(sql); + delete q1; + } + delete q; + } + + if(ver<237) { + sql=QString("alter table REPORTS add column ")+ + "START_TIME time after FILTER_GROUPS"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table REPORTS add column ")+ + "END_TIME time after START_TIME"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<238) { + sql=QString("alter table CART add column ")+ + "PENDING_STATION char(64) after USE_EVENT_LENGTH"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table CART add column ")+ + "PENDING_PID int after PENDING_STATION"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table CART add column ")+ + "PENDING_DATETIME datetime after PENDING_PID"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table CART add index ")+ + "PENDING_STATION_IDX(PENDING_STATION)"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table CART add index ")+ + "PENDING_PID_IDX(PENDING_STATION,PENDING_PID)"; + q=new QSqlQuery(sql); + delete q; + + sql=QString("alter table CART add index ")+ + "PENDING_DATETIME_IDX(PENDING_DATETIME)"; + q=new QSqlQuery(sql); + delete q; + } + + if(ver<239) { + sql=QString("create table if not exists DROPBOX_SCHED_CODES(")+ + "ID int auto_increment not null primary key,"+ + "DROPBOX_ID int not null,"+ + "SCHED_CODE char(11) not null," + "index DROPBOX_ID_IDX(DROPBOX_ID),"+ + "index SCHED_CODE_IDX(SCHED_CODE))"; + q=new QSqlQuery(sql); + delete q; + } + + + + // **** End of version updates **** + + // + // Update Version Field + // + q=new QSqlQuery(QString().sprintf("update VERSION set DB=%d", + RD_VERSION_DATABASE)); + delete q; + return UPDATEDB_SUCCESS; +} diff --git a/rdadmin/createdb.h b/rdadmin/createdb.h new file mode 100644 index 00000000..ce199ad6 --- /dev/null +++ b/rdadmin/createdb.h @@ -0,0 +1,41 @@ +// createdb.h +// +// Create a Rivendell Database +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: createdb.h,v 1.8 2011/06/23 22:30:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef CREATEDB_H +#define CREATEDB_H + +#include + +// +// UpdateDB return codes +// +#define UPDATEDB_SUCCESS 0 +#define UPDATEDB_BACKUP_FAILED -1 +#define UPDATEDB_QUERY_FAILED -2 + +bool CreateDb(QString name,QString pwd); +bool InitDb(QString name,QString pwd,QString stationname); +int UpdateDb(int ver); + + +#endif + diff --git a/rdadmin/edit_audios.cpp b/rdadmin/edit_audios.cpp new file mode 100644 index 00000000..3464dfaa --- /dev/null +++ b/rdadmin/edit_audios.cpp @@ -0,0 +1,362 @@ +// edit_audios.cpp +// +// Edit a Rivendell Audio Port Configuration +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: edit_audios.cpp,v 1.16.2.3 2012/08/07 15:48:04 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +EditAudioPorts::EditAudioPorts(QString station,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString str; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + edit_station=station; + edit_card=NULL; + rdstation=NULL; + + setCaption(tr("Edit Audio Ports")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Card Selector + // + edit_card_box=new QComboBox(this,"edit_card_box"); + edit_card_box->setGeometry(75,10,60,26); + edit_card_box->setInsertionPolicy(QComboBox::NoInsertion); + connect(edit_card_box,SIGNAL(activated(int)), + this,SLOT(cardSelectedData(int))); + QLabel *label=new QLabel(edit_card_box,tr("Card:"),this,"edit_card_label"); + label->setGeometry(10,16,60,22); + label->setFont(font); + label->setAlignment(AlignRight); + + // Card Driver + card_driver_edit=new QLineEdit(this,"card_driver_edit"); + card_driver_edit->setGeometry(225,15,170,19);//FIXME: size + card_driver_edit->setReadOnly(true); + label=new QLabel(edit_card_box,tr("Card Driver:"),this,"card_driver_label"); + label->setGeometry(140,16,80,22); + label->setFont(font); + label->setAlignment(AlignRight); + + // + // Clock Selector + // + edit_clock_box=new QComboBox(this,"edit_clock_box"); + edit_clock_box->setGeometry(500,10,150,26); + edit_clock_box->setInsertionPolicy(QComboBox::NoInsertion); + edit_clock_label=new QLabel(edit_clock_box,tr("Clock Source:"),this,"edit_clock_label"); + edit_clock_label->setGeometry(395,16,100,22); + edit_clock_label->setFont(font); + edit_clock_label->setAlignment(AlignRight); + + for(int j=0;jsetGeometry(50+170*i,55+j*180,170,22); + label->setFont(font); + label->setAlignment(AlignHCenter); + QSignalMapper *mapper=new QSignalMapper(this,"input_mapper"); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(inputMapData(int))); + edit_type_box[j*4+i]=new QComboBox(this,"edit_type_box"); + edit_type_box[j*4+i]->setGeometry(95+170*i,75+j*180,110,26); + edit_type_box[j*4+i]->insertItem(tr("Analog")); + edit_type_box[j*4+i]->insertItem(tr("AES/EBU")); + edit_type_box[j*4+i]->insertItem(tr("SP/DIFF")); + mapper->setMapping(edit_type_box[j*4+i],j*4+i); + connect(edit_type_box[j*4+i],SIGNAL(activated(int)),mapper,SLOT(map())); + edit_type_label[j*4+i]=new QLabel(edit_type_box[j*4+i],tr("Type:"), + this,"edit_type_label"); + edit_type_label[j*4+i]->setGeometry(50+170*i,81+j*180,40,22); + edit_type_label[j*4+i]->setAlignment(AlignRight); + edit_mode_box[j*4+i]=new QComboBox(this,"edit_mode_box"); + edit_mode_box[j*4+i]->setGeometry(95+170*i,105+j*180,110,26); + // NOTE: this drop down list box is populated to match RDCae::ChannelMode + edit_mode_box[j*4+i]->insertItem(tr("Normal")); + edit_mode_box[j*4+i]->insertItem(tr("Swap")); + edit_mode_box[j*4+i]->insertItem(tr("Left only")); + edit_mode_box[j*4+i]->insertItem(tr("Right only")); + mapper->setMapping(edit_mode_box[j*4+i],j*4+i); + connect(edit_mode_box[j*4+i],SIGNAL(activated(int)),mapper,SLOT(map())); + edit_mode_label[j*4+i]=new QLabel(edit_type_box[j*4+i],tr("Mode:"), + this,"edit_mode_label"); + edit_mode_label[j*4+i]->setGeometry(50+170*i,111+j*180,40,22); + edit_mode_label[j*4+i]->setAlignment(AlignRight); + + edit_input_box[j*4+i]=new QSpinBox(this,"edit_type_box"); + edit_input_box[j*4+i]->setGeometry(95+170*i,135+j*180,60,24); + edit_input_box[j*4+i]->setRange(-26,6); + edit_input_box[j*4+i]->setSuffix(tr(" dB")); + edit_input_label[j*4+i]=new QLabel(edit_type_box[j*4+i],tr("Ref. Level:"), + this,"edit_type_label"); + edit_input_label[j*4+i]->setGeometry(10+170*i,140+j*180,80,22); + edit_input_label[j*4+i]->setAlignment(AlignRight); + + // + // Output Port Controls + // + str=QString(tr("Output Port")); + label=new QLabel(QString().sprintf("%s %d",(const char *)str,j*4+i), + this,"output_port_label"); + label->setGeometry(50+170*i,170+j*180,170,22); + label->setFont(font); + label->setAlignment(AlignHCenter); + + edit_output_box[j*4+i]=new QSpinBox(this,"edit_type_box"); + edit_output_box[j*4+i]->setGeometry(95+170*i,190+j*180,60,24); + edit_output_box[j*4+i]->setRange(-26,6); + edit_output_box[j*4+i]->setSuffix(tr(" dB")); + edit_output_label[j*4+i]= + new QLabel(edit_type_box[j*4+i],tr("Ref. Level:"),this,"edit_type_label"); + edit_output_label[j*4+i]->setGeometry(10+170*i,195+j*180,80,22); + edit_output_label[j*4+i]->setAlignment(AlignRight); + } + } + + // + // Help Button + // + QPushButton *help_button=new QPushButton(this,"help_button"); + help_button->setGeometry(10,sizeHint().height()-60, 80,50); + help_button->setFont(font); + help_button->setText(tr("&Help")); + connect(help_button,SIGNAL(clicked()),this,SLOT(helpData())); + + // + // Close Button + // + QPushButton *close_button=new QPushButton(this,"close_button"); + close_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + close_button->setFont(font); + close_button->setText(tr("&Close")); + connect(close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Populate Data + // + for(int i=0;iinsertItem(QString().sprintf("%d",i)); + } + edit_clock_box->insertItem(tr("Internal")); + edit_clock_box->insertItem(tr("AES/EBU Signal")); + edit_clock_box->insertItem(tr("SP/DIFF Signal")); + edit_clock_box->insertItem(tr("Word Clock")); + edit_card_num=edit_card_box->currentItem(); + ReadRecord(edit_card_num); +} + + +EditAudioPorts::~EditAudioPorts() +{ +} + + +QSize EditAudioPorts::sizeHint() const +{ + return QSize(730,460); +} + + +QSizePolicy EditAudioPorts::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditAudioPorts::cardSelectedData(int card) +{ + WriteRecord(); + edit_card_num=edit_card_box->currentItem(); + ReadRecord(edit_card_num); +} + + +void EditAudioPorts::inputMapData(int id) +{ + if(rdstation==NULL) { + rdstation=new RDStation(edit_station); + } + if( (rdstation->cardDriver(edit_card_num)==RDStation::Hpi) && + (edit_type_box[id]->currentItem()==RDAudioPort::Analog) ) { + edit_input_label[id]->setEnabled(true); + edit_input_box[id]->setEnabled(true); + } + else { + edit_input_label[id]->setDisabled(true); + edit_input_box[id]->setDisabled(true); + } +} + + +void EditAudioPorts::helpData() +{ + HelpAudioPorts *help_audioports=new HelpAudioPorts(this, "help_audioports"); + help_audioports->exec(); + delete help_audioports; +} + + +void EditAudioPorts::closeData() +{ + WriteRecord(); + done(0); +} + + +void EditAudioPorts::ReadRecord(int card) +{ + if(edit_card!=NULL) { + delete edit_card; + } + edit_card=new RDAudioPort(edit_station,card,true); + if(rdstation!=NULL) { + delete rdstation; + } + rdstation=new RDStation(edit_station); + card_driver_edit->setText(rdstation->name()); + + // NOTE: various controls are disabled for some card driver types if they are not yet implemented within CAE. + switch(rdstation->cardDriver(card)) { + case RDStation::Hpi: + card_driver_edit->setText("AudioScience HPI"); + edit_clock_box->setEnabled(true); + edit_clock_label->setEnabled(true); + for (int i=0;isetEnabled(true); + edit_type_box[i]->setEnabled(true); + edit_mode_label[i]->setEnabled(true); + edit_mode_box[i]->setEnabled(true); + edit_input_label[i]->setEnabled(true); + edit_input_box[i]->setEnabled(true); + edit_output_label[i]->setEnabled(true); + edit_output_box[i]->setEnabled(true); + } + break; + case RDStation::Jack: + card_driver_edit->setText("JACK"); + edit_clock_box->setDisabled(true); + edit_clock_label->setDisabled(true); + for (int i=0;isetDisabled(true); + edit_type_box[i]->setDisabled(true); + edit_mode_label[i]->setEnabled(true); + edit_mode_box[i]->setEnabled(true); + edit_input_label[i]->setDisabled(true); + edit_input_box[i]->setDisabled(true); + edit_output_label[i]->setDisabled(true); + edit_output_box[i]->setDisabled(true); + } + break; + case RDStation::Alsa: + card_driver_edit->setText("ALSA"); + edit_clock_box->setDisabled(true); + edit_clock_label->setDisabled(true); + for (int i=0;isetDisabled(true); + edit_type_box[i]->setDisabled(true); + edit_mode_label[i]->setDisabled(true); + edit_mode_box[i]->setDisabled(true); + edit_input_label[i]->setDisabled(true); + edit_input_box[i]->setDisabled(true); + edit_output_label[i]->setDisabled(true); + edit_output_box[i]->setDisabled(true); + } + break; + case RDStation::None: + default: + card_driver_edit->setText("UNKNOWN"); + edit_clock_box->setDisabled(true); + edit_clock_label->setDisabled(true); + for (int i=0;isetDisabled(true); + edit_type_box[i]->setDisabled(true); + edit_mode_label[i]->setDisabled(true); + edit_mode_box[i]->setDisabled(true); + edit_input_label[i]->setDisabled(true); + edit_input_box[i]->setDisabled(true); + edit_output_label[i]->setDisabled(true); + edit_output_box[i]->setDisabled(true); + } + break; + } + edit_clock_box->setCurrentItem(edit_card->clockSource()); + for(int i=0;isetCurrentItem((int)edit_card->inputPortType(i)); + if( (rdstation->cardDriver(card)==RDStation::Hpi) && + ((RDAudioPort::PortType)edit_type_box[i]->currentItem()== + RDAudioPort::Analog) ) { + edit_input_label[i]->setEnabled(true); + edit_input_box[i]->setEnabled(true); + } + else { + edit_input_label[i]->setDisabled(true); + edit_input_box[i]->setDisabled(true); + } + edit_mode_box[i]->setCurrentItem((int)edit_card->inputPortMode(i)); + edit_input_box[i]->setValue(edit_card->inputPortLevel(i)/100); + edit_output_box[i]->setValue(edit_card->outputPortLevel(i)/100); + } +} + + +void EditAudioPorts::WriteRecord() +{ + edit_card-> + setClockSource((RDCae::ClockSource)edit_clock_box->currentItem()); + for(int i=0;isetInputPortType(i, + (RDAudioPort::PortType)edit_type_box[i]->currentItem()); + edit_card->setInputPortMode(i, + (RDCae::ChannelMode)edit_mode_box[i]->currentItem()); + edit_card->setInputPortLevel(i,edit_input_box[i]->value()*100); + edit_card->setOutputPortLevel(i,edit_output_box[i]->value()*100); + } +} diff --git a/rdadmin/edit_audios.h b/rdadmin/edit_audios.h new file mode 100644 index 00000000..0b75f300 --- /dev/null +++ b/rdadmin/edit_audios.h @@ -0,0 +1,80 @@ +// edit_audios.h +// +// Edit a Rivendell Audio Port Configuration +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: edit_audios.h,v 1.9 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_AUDIOS_H +#define EDIT_AUDIOS_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +class EditAudioPorts : public QDialog +{ + Q_OBJECT + public: + EditAudioPorts(QString station,QWidget *parent=0,const char *name=0); + ~EditAudioPorts(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void cardSelectedData(int); + void inputMapData(int); + void helpData(); + void closeData(); + + private: + void ReadRecord(int card); + void WriteRecord(); + void SetEnable(bool state); + int edit_card_num; + RDAudioPort *edit_card; + RDStation *rdstation; + QString edit_station; + QComboBox *edit_card_box; + QLineEdit *card_driver_edit; + QComboBox *edit_clock_box; + QLabel *edit_clock_label; + QComboBox *edit_type_box[RD_MAX_PORTS]; + QLabel *edit_type_label[RD_MAX_PORTS]; + QComboBox *edit_mode_box[RD_MAX_PORTS]; + QLabel *edit_mode_label[RD_MAX_PORTS]; + QSpinBox *edit_input_box[RD_MAX_PORTS]; + QLabel *edit_input_label[RD_MAX_PORTS]; + QSpinBox *edit_output_box[RD_MAX_PORTS]; + QLabel *edit_output_label[RD_MAX_PORTS]; +}; + + +#endif + diff --git a/rdadmin/edit_aux_field.cpp b/rdadmin/edit_aux_field.cpp new file mode 100644 index 00000000..ec01181c --- /dev/null +++ b/rdadmin/edit_aux_field.cpp @@ -0,0 +1,144 @@ +// edit_aux_field.cpp +// +// Edit an Auxiliary Field for an RSS Feed +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: edit_aux_field.cpp,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + + +EditAuxField::EditAuxField(unsigned feed_id,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + + edit_field_id=feed_id; + setCaption(tr("Edit Auxiliary Metadata Fields")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Variable Name + // + edit_varname_edit=new QLineEdit(this,"edit_varname_edit"); + edit_varname_edit->setGeometry(120,10,130,20); + edit_varname_edit->setReadOnly(true); + QLabel *label= + new QLabel(edit_varname_edit,tr("Variable Name: "), + this,"edit_varname_label"); + label->setGeometry(10,13,105,20); + label->setFont(bold_font); + label->setAlignment(AlignRight); + + // + // Variable Name + // + edit_caption_edit=new QLineEdit(this,"edit_caption_edit"); + edit_caption_edit->setGeometry(120,37,sizeHint().width()-130,20); + edit_caption_edit->setMaxLength(64); + label=new QLabel(edit_caption_edit,tr("Caption: "), + this,"edit_caption_label"); + label->setGeometry(10,37,105,20); + label->setFont(bold_font); + label->setAlignment(AlignRight); + + // + // Ok Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Data + // + sql=QString().sprintf("select VAR_NAME,CAPTION from AUX_METADATA \ + where ID=%u",edit_field_id); + q=new RDSqlQuery(sql); + if(q->first()) { + edit_varname_edit->setText(q->value(0).toString()); + edit_caption_edit->setText(q->value(1).toString()); + } + delete q; +} + + +QSize EditAuxField::sizeHint() const +{ + return QSize(400,127); +} + + +QSizePolicy EditAuxField::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditAuxField::okData() +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("update AUX_METADATA set CAPTION=\"%s\" \ + where ID=%u", + (const char *)RDEscapeString(edit_caption_edit->text()), + edit_field_id); + q=new RDSqlQuery(sql); + delete q; + + done(0); +} + + +void EditAuxField::cancelData() +{ + done(-1); +} diff --git a/rdadmin/edit_aux_field.h b/rdadmin/edit_aux_field.h new file mode 100644 index 00000000..c5e693ed --- /dev/null +++ b/rdadmin/edit_aux_field.h @@ -0,0 +1,54 @@ +// edit_aux_field.h +// +// Edit an Auxiliary Field for an RSS Feed +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: edit_aux_field.h,v 1.3 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_AUX_FIELD_H +#define EDIT_AUX_FIELD_H + +#include +#include +#include +#include +#include +#include + + +class EditAuxField : public QDialog +{ + Q_OBJECT + public: + EditAuxField(unsigned field_id,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *edit_varname_edit; + QLineEdit *edit_caption_edit; + unsigned edit_field_id; +}; + + +#endif // EDIT_AUX_FIELD + diff --git a/rdadmin/edit_backup.cpp b/rdadmin/edit_backup.cpp new file mode 100644 index 00000000..041bb681 --- /dev/null +++ b/rdadmin/edit_backup.cpp @@ -0,0 +1,171 @@ +// edit_backup.cpp +// +// Edit an automatic backup configuration. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_backup.cpp,v 1.10 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include + +#include + + +EditBackup::EditBackup(RDStation *station,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont small_font=QFont("Helvetica",12,QFont::Bold); + small_font.setPixelSize(12); + QFont big_font=QFont("Helvetica",14,QFont::Bold); + big_font.setPixelSize(14); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Dialog Name + // + edit_station=station; + setCaption(tr("Backup config for ")+station->name()); + + // + // Backup Life + // + edit_life_box=new QSpinBox(this,"edit_life_box"); + edit_life_box->setGeometry(155,10,40,19); + edit_life_box->setMinValue(0); + edit_life_box->setMaxValue(30); + QLabel *edit_life_box_label=new QLabel(edit_life_box,tr("Keep Backups For:"), + this,"edit_life_box_label"); + edit_life_box_label->setGeometry(10,10,140,19); + edit_life_box_label->setFont(small_font); + edit_life_box_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QLabel *edit_life_box_unit=new QLabel(tr("days"),this,"edit_life_box_unit"); + edit_life_box_unit->setGeometry(200,10,120,19); + edit_life_box_unit->setFont(small_font); + edit_life_box_unit->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + connect(edit_life_box,SIGNAL(valueChanged(int)), + this,SLOT(lifeChangedData(int))); + + // + // Backup Directory + // + edit_path_edit=new QLineEdit(this,"edit_life_box"); + edit_path_edit->setGeometry(155,35,sizeHint().width()-165,19); + edit_path_edit->setValidator(validator); + edit_path_label=new QLabel(edit_life_box,tr("Backup Directory:"), + this,"edit_path_label"); + edit_path_label->setGeometry(10,35,140,19); + edit_path_label->setFont(small_font); + edit_path_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(small_font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(small_font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + edit_life_box->setValue(edit_station->backupLife()); + edit_path_edit->setText(edit_station->backupPath()); + lifeChangedData(edit_life_box->value()); +} + + +EditBackup::~EditBackup() +{ +} + + +QSize EditBackup::sizeHint() const +{ + return QSize(375,130); +} + + +QSizePolicy EditBackup::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditBackup::lifeChangedData(int days) +{ + if(days==0) { + edit_path_label->setDisabled(true); + edit_path_edit->setDisabled(true); + } + else { + edit_path_label->setEnabled(true); + edit_path_edit->setEnabled(true); + } +} + + +void EditBackup::okData() +{ + if((edit_life_box->value()>0)&&(edit_path_edit->text().isEmpty())) { + QMessageBox::warning(this,tr("Path Missing"), + tr("You must supply a backup path!")); + return; + } + edit_station->setBackupLife(edit_life_box->value()); + edit_station->setBackupPath(edit_path_edit->text()); + done(0); +} + + +void EditBackup::cancelData() +{ + done(-1); +} diff --git a/rdadmin/edit_backup.h b/rdadmin/edit_backup.h new file mode 100644 index 00000000..5d84286b --- /dev/null +++ b/rdadmin/edit_backup.h @@ -0,0 +1,58 @@ +// edit_backup.h +// +// Edit an automatic backup configuration +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_backup.h,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_BACKUP_H +#define EDIT_BACKUP_H + +#include +#include +#include +#include +#include + +#include + + +class EditBackup : public QDialog +{ + Q_OBJECT + public: + EditBackup(RDStation *station,QWidget *parent=0,const char *name=0); + ~EditBackup(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void lifeChangedData(int days); + void okData(); + void cancelData(); + + private: + RDStation *edit_station; + QSpinBox *edit_life_box; + QLineEdit *edit_path_edit; + QLabel *edit_path_label; +}; + + +#endif + diff --git a/rdadmin/edit_cartslots.cpp b/rdadmin/edit_cartslots.cpp new file mode 100644 index 00000000..6678c5bf --- /dev/null +++ b/rdadmin/edit_cartslots.cpp @@ -0,0 +1,472 @@ +// edit_cartslots.cpp +// +// Edit Rivendell CartSlot Configuration +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: edit_cartslots.cpp,v 1.1.2.7 2013/12/23 18:47:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include + +#include +#include + +EditCartSlots::EditCartSlots(RDStation *station,RDStation *cae_station, + QWidget *parent,const char *name) + : QDialog(parent) +{ + QString sql; + RDSqlQuery *q; + + edit_station=station; + edit_cae_station=cae_station; + edit_previous_slot=0; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("RDAdmin - Edit CartSlots")); + + // + // Fonts + // + QFont font("helvetica",12,QFont::Normal); + font.setPixelSize(12); + QFont label_font("helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont title_font("helvetica",14,QFont::Bold); + title_font.setPixelSize(14); + + // + // Global Settings + // + QLabel *label=new QLabel(tr("Global Settings"),this); + label->setGeometry(10,10,sizeHint().width()-20,20); + label->setFont(title_font); + label->setAlignment(AlignCenter); + + // + // Slot Columns + // + edit_slot_columns_spin=new QSpinBox(this); + edit_slot_columns_spin->setGeometry(127,32,50,20); + edit_slot_columns_spin->setRange(1,RDCARTSLOTS_MAX_COLUMNS); + connect(edit_slot_columns_spin,SIGNAL(valueChanged(int)), + this,SLOT(quantityChangedData(int))); + label=new QLabel(edit_slot_columns_spin,tr("Slot Columns:"),this); + label->setGeometry(10,32,112,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Slot Rows + // + edit_slot_rows_spin=new QSpinBox(this); + edit_slot_rows_spin->setGeometry(127,54,50,20); + edit_slot_rows_spin->setRange(1,RDCARTSLOTS_MAX_ROWS); + connect(edit_slot_rows_spin,SIGNAL(valueChanged(int)), + this,SLOT(quantityChangedData(int))); + label=new QLabel(edit_slot_rows_spin,tr("Slot Rows:"),this); + label->setGeometry(10,54,112,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Slot Selector + // + edit_slot_box=new QComboBox(this); + edit_slot_box->setGeometry(107,98,60,20); + connect(edit_slot_box,SIGNAL(activated(int)), + this,SLOT(slotChangedData(int))); + label=new QLabel(edit_slot_box,tr("Slot"),this); + label->setGeometry(10,98,92,20); + label->setFont(title_font); + label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + label=new QLabel(tr("Settings"),this); + label->setGeometry(172,98,sizeHint().width()-172,20); + label->setFont(title_font); + + // + // Channel Assignments + // + label=new QLabel(tr("Channel Assignments"),this); + label->setGeometry(10,123,sizeHint().width()-20,20); + label->setFont(label_font); + label->setAlignment(AlignCenter); + + // + // Card Selector + // + edit_card_spin=new QSpinBox(this); + edit_card_spin->setGeometry(127,145,50,20); + edit_card_spin->setRange(-1,cae_station->cards()-1); + edit_card_spin->setSpecialValueText(tr("None")); + connect(edit_card_spin,SIGNAL(valueChanged(int)), + this,SLOT(cardChangedData(int))); + label=new QLabel(edit_card_spin,tr("Card:"),this); + label->setGeometry(10,145,112,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Input Port Selector + // + edit_input_spin=new QSpinBox(this); + edit_input_spin->setGeometry(127,167,50,20); + edit_input_spin->setRange(-1,RD_MAX_PORTS-1); + edit_input_spin->setSpecialValueText(tr("None")); + label=new QLabel(edit_input_spin,tr("Input Port:"),this); + label->setGeometry(10,167,112,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Output Port Selector + // + edit_output_spin=new QSpinBox(this); + edit_output_spin->setGeometry(127,189,50,20); + edit_output_spin->setRange(-1,RD_MAX_PORTS-1); + edit_output_spin->setSpecialValueText(tr("None")); + label=new QLabel(edit_output_spin,tr("Output Port:"),this); + label->setGeometry(10,189,112,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Default Settings + // + label=new QLabel(tr("Default Settings"),this); + label->setGeometry(10,218,sizeHint().width()-20,20); + label->setFont(label_font); + label->setAlignment(AlignCenter); + + // + // Service + // + edit_service_box=new QComboBox(this); + edit_service_box->setGeometry(127,240,120,20); + edit_service_label= + new QLabel(edit_service_box,tr("Service:"),this); + edit_service_label->setGeometry(10,240,112,20); + edit_service_label->setFont(font); + edit_service_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + sql="select NAME from SERVICES order by NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + edit_service_box->insertItem(q->value(0).toString()); + } + delete q; + + // + // Slot Mode + // + edit_mode_box=new QComboBox(this); + edit_mode_box->setGeometry(127,262,150,20); + edit_mode_box->insertItem(tr("User previous mode")); + for(int i=0;iinsertItem(RDSlotOptions::modeText((RDSlotOptions::Mode)i)); + } + connect(edit_mode_box,SIGNAL(activated(int)),this,SLOT(modeData(int))); + label=new QLabel(edit_mode_box,tr("Slot Mode:"),this); + label->setGeometry(10,262,112,20); + label->setFont(font); + label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Play Mode + // + edit_play_mode_box=new QComboBox(this); + edit_play_mode_box->setGeometry(127,284,150,20); + edit_play_mode_box->insertItem(tr("Use previous mode")); + edit_play_mode_box->insertItem(tr("Full")); + edit_play_mode_box->insertItem(tr("Hook")); + edit_play_mode_label=new QLabel(edit_play_mode_box,tr("Play Mode:"),this); + edit_play_mode_label->setGeometry(10,284,112,20); + edit_play_mode_label->setFont(font); + edit_play_mode_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Cart Action + // + edit_cartaction_box=new QComboBox(this); + edit_cartaction_box->setGeometry(127,306,150,20); + edit_cartaction_box->insertItem(tr("Use previous cart")); + edit_cartaction_box->insertItem(tr("Do Nothing")); + edit_cartaction_box->insertItem(tr("Load Specified Cart")); + connect(edit_cartaction_box,SIGNAL(activated(int)), + this,SLOT(cartActionData(int))); + edit_cartaction_label= + new QLabel(edit_cartaction_box,tr("At Startup:"),this); + edit_cartaction_label->setGeometry(10,306,112,20); + edit_cartaction_label->setFont(font); + edit_cartaction_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Cart + // + edit_cart_edit=new QLineEdit(this); + edit_cart_edit->setGeometry(147,333,60,20); + edit_cart_edit->setReadOnly(true); + edit_cart_label=new QLabel(edit_cart_edit,tr("Cart:"),this); + edit_cart_label->setGeometry(10,333,132,20); + edit_cart_label->setFont(font); + edit_cart_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + edit_cart_button=new QPushButton(tr("Select"),this); + edit_cart_button->setGeometry(212,333,65,26); + edit_cart_button->setFont(font); + connect(edit_cart_button,SIGNAL(clicked()),this,SLOT(cartSelectData())); + + // + // Stop Action + // + edit_stop_action_box=new QComboBox(this); + edit_stop_action_box->setGeometry(127,360,150,20); + edit_stop_action_box->insertItem(tr("Use previous action")); + for(int i=0;i + insertItem(RDSlotOptions::stopActionText((RDSlotOptions::StopAction)i)); + } + edit_stop_action_label=new QLabel(edit_stop_action_box,tr("At Playout End:"),this); + edit_stop_action_label->setGeometry(10,360,112,20); + edit_stop_action_label->setFont(font); + edit_stop_action_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Close Button + // + QPushButton *button=new QPushButton(tr("Close"),this); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(label_font); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Load Values + // + edit_slot_columns_spin->setValue(station->cartSlotColumns()); + edit_slot_rows_spin->setValue(station->cartSlotRows()); + quantityChangedData(0); + ReadSlot(edit_slot_box->currentItem()); +} + + +EditCartSlots::~EditCartSlots() +{ +} + + +QSize EditCartSlots::sizeHint() const +{ + return QSize(300,455); +} + + +void EditCartSlots::quantityChangedData(int index) +{ + int slot=edit_slot_box->currentItem(); + int slot_quan= + edit_slot_columns_spin->value()*edit_slot_rows_spin->value(); + + edit_slot_box->clear(); + for(int i=0;iinsertItem(QString().sprintf("%d",i+1)); + if(i==slot) { + edit_slot_box->setCurrentItem(i); + } + } + if(slot>slot_quan) { + QMessageBox::information(this,"RDAdmin",tr("Slot selected has changed!")); + } +} + + +void EditCartSlots::slotChangedData(int slotnum) +{ + WriteSlot(edit_previous_slot); + ReadSlot(slotnum); + edit_previous_slot=slotnum; +} + + +void EditCartSlots::cardChangedData(int card) +{ + edit_input_spin->setDisabled(card<0); + edit_output_spin->setDisabled(card<0); + if(card<0) { + edit_input_spin->setValue(-1); + edit_output_spin->setValue(-1); + } + else { + edit_input_spin->setRange(-1,edit_cae_station->cardInputs(card)-1); + edit_output_spin->setRange(-1,edit_cae_station->cardOutputs(card)-1); + } +} + + +void EditCartSlots::modeData(int mode) +{ + edit_play_mode_label-> + setDisabled((RDSlotOptions::Mode)mode!=RDSlotOptions::BreakawayMode); + edit_play_mode_box-> + setDisabled((RDSlotOptions::Mode)mode!=RDSlotOptions::BreakawayMode); + edit_cartaction_label-> + setDisabled((RDSlotOptions::Mode)mode!=RDSlotOptions::BreakawayMode); + edit_cartaction_box-> + setDisabled((RDSlotOptions::Mode)mode!=RDSlotOptions::BreakawayMode); + edit_stop_action_label-> + setDisabled((RDSlotOptions::Mode)mode!=RDSlotOptions::BreakawayMode); + edit_stop_action_box-> + setDisabled((RDSlotOptions::Mode)mode!=RDSlotOptions::BreakawayMode); + if((RDSlotOptions::Mode)mode!=RDSlotOptions::BreakawayMode) { + cartActionData(0); + } + else { + cartActionData(edit_cartaction_box->currentItem()); + } +} + + +void EditCartSlots::cartActionData(int action) +{ + edit_cart_label->setEnabled(action==2); + edit_cart_edit->setEnabled(action==2); + edit_cart_button->setEnabled(action==2); +} + + +void EditCartSlots::cartSelectData() +{ + int cartnum=edit_cart_edit->text().toInt(); + + if(admin_cart_dialog->exec(&cartnum,RDCart::All,NULL,0, + admin_user->name(),admin_user->password())==0) { + edit_cart_edit->setText(QString().sprintf("%06d",cartnum)); + } +} + + +void EditCartSlots::closeData() +{ + edit_station->setCartSlotColumns(edit_slot_columns_spin->value()); + edit_station->setCartSlotRows(edit_slot_rows_spin->value()); + WriteSlot(edit_slot_box->currentItem()); + done(0); +} + + +void EditCartSlots::closeEvent(QCloseEvent *e) +{ + closeData(); +} + + +void EditCartSlots::ReadSlot(unsigned slotnum) +{ + QString sql; + RDSqlQuery *q; + + // + // Ensure that the record exists + // + RDSlotOptions *opts=new RDSlotOptions(edit_station->name(),slotnum); + delete opts; + + sql=QString("select CARD,INPUT_PORT,OUTPUT_PORT,DEFAULT_MODE,")+ + "DEFAULT_HOOK_MODE,"+ + "DEFAULT_STOP_ACTION,DEFAULT_CART_NUMBER,SERVICE_NAME from CARTSLOTS "+ + "where (STATION_NAME=\""+RDEscapeString(edit_station->name())+"\")&&"+ + QString().sprintf("(SLOT_NUMBER=%u)",slotnum); + q=new RDSqlQuery(sql); + if(q->first()) { + edit_card_spin->setValue(q->value(0).toInt()); + edit_input_spin->setValue(q->value(1).toInt()); + edit_output_spin->setValue(q->value(2).toInt()); + cardChangedData(edit_card_spin->value()); + edit_mode_box->setCurrentItem(q->value(3).toInt()+1); + edit_play_mode_box->setCurrentItem(q->value(4).toInt()+1); + edit_stop_action_box->setCurrentItem(q->value(5).toInt()+1); + switch(q->value(6).toInt()) { + case -1: + edit_cartaction_box->setCurrentItem(0); + break; + + case 0: + edit_cartaction_box->setCurrentItem(1); + break; + + default: + edit_cartaction_box->setCurrentItem(2); + edit_cart_edit->setText(QString().sprintf("%06d",q->value(6).toInt())); + } + cartActionData(edit_cartaction_box->currentItem()); + modeData(edit_mode_box->currentItem()); + for(int i=0;icount();i++) { + if(q->value(7).toString()==edit_service_box->text(i)) { + edit_service_box->setCurrentItem(i); + } + } + } + delete q; +} + + +void EditCartSlots::WriteSlot(unsigned slotnum) +{ + QString sql; + RDSqlQuery *q; + + sql=QString("update CARTSLOTS set ")+ + QString().sprintf("CARD=%d,INPUT_PORT=%d,OUTPUT_PORT=%d,", + edit_card_spin->value(), + edit_input_spin->value(), + edit_output_spin->value())+ + QString().sprintf("DEFAULT_MODE=%d,", + edit_mode_box->currentItem()-1)+ + QString().sprintf("DEFAULT_HOOK_MODE=%d,", + edit_play_mode_box->currentItem()-1)+ + QString().sprintf("DEFAULT_STOP_ACTION=%d,", + edit_stop_action_box->currentItem()-1); + switch(edit_cartaction_box->currentItem()) { + case 0: + sql+="DEFAULT_CART_NUMBER=-1,"; + break; + + case 1: + sql+="DEFAULT_CART_NUMBER=0,"; + break; + + default: + sql+=QString().sprintf("DEFAULT_CART_NUMBER=%d,", + edit_cart_edit->text().toInt()); + break; + } + sql+="SERVICE_NAME=\""+RDEscapeString(edit_service_box->currentText())+"\" "; + sql+="where (STATION_NAME=\""+RDEscapeString(edit_station->name())+"\")&&"; + sql+=QString().sprintf("(SLOT_NUMBER=%u)",slotnum); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/rdadmin/edit_cartslots.h b/rdadmin/edit_cartslots.h new file mode 100644 index 00000000..19b185c5 --- /dev/null +++ b/rdadmin/edit_cartslots.h @@ -0,0 +1,85 @@ +// edit_cartslots.h +// +// Edit Rivendell CartSlot Configuration +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: edit_cartslots.h,v 1.1.2.5 2013/12/23 18:47:23 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_CARTSLOTS_H +#define EDIT_CARTSLOTS_H + +#include +#include +#include +#include +#include +#include + +#include + +class EditCartSlots : public QDialog +{ + Q_OBJECT + public: + EditCartSlots(RDStation *station,RDStation *cae_station, + QWidget *parent=0,const char *name=0); + ~EditCartSlots(); + QSize sizeHint() const; + + private slots: + void quantityChangedData(int index); + void slotChangedData(int slotnum); + void cardChangedData(int card); + void modeData(int mode); + void cartActionData(int action); + void cartSelectData(); + void closeData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + void ReadSlot(unsigned slotnum); + void WriteSlot(unsigned slotnum); + RDStation *edit_station; + RDStation *edit_cae_station; + QLabel *edit_slot_columns_label; + QSpinBox *edit_slot_columns_spin; + QLabel *edit_slot_rows_label; + QSpinBox *edit_slot_rows_spin; + QComboBox *edit_slot_box; + QComboBox *edit_mode_box; + QLabel *edit_play_mode_label; + QComboBox *edit_play_mode_box; + QLabel *edit_stop_action_label; + QComboBox *edit_stop_action_box; + QLabel *edit_cartaction_label; + QComboBox *edit_cartaction_box; + QLabel *edit_cart_label; + QLineEdit *edit_cart_edit; + QPushButton *edit_cart_button; + QLabel *edit_service_label; + QComboBox *edit_service_box; + QSpinBox *edit_card_spin; + QSpinBox *edit_input_spin; + QSpinBox *edit_output_spin; + int edit_previous_slot; +}; + + +#endif // EDIT_CARTSLOTS_H diff --git a/rdadmin/edit_channelgpios.cpp b/rdadmin/edit_channelgpios.cpp new file mode 100644 index 00000000..212b5652 --- /dev/null +++ b/rdadmin/edit_channelgpios.cpp @@ -0,0 +1,268 @@ +// edit_channelgpios.cpp +// +// Edit Rivendell Channel GPIO Settings +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: edit_channelgpios.cpp,v 1.1.2.3 2013/03/13 15:18:05 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +EditChannelGpios::EditChannelGpios(RDAirPlayConf *conf, + RDAirPlayConf::Channel chan, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_airplay_conf=conf; + edit_channel=chan; + + setCaption(QString("RDAdmin - ")+tr("Edit Channel GPIOs")); + + // + // Fonts + // + QFont title_font("helvetica",14,QFont::Bold); + title_font.setPixelSize(14); + QFont label_font("helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + // + // Title + // + edit_title_label=new QLabel(RDAirPlayConf::channelText(chan),this); + edit_title_label->setFont(title_font); + edit_title_label->setAlignment(Qt::AlignCenter); + + // + // Start GPI + // + edit_start_gpi_label=new QLabel(tr("Start GPI:"),this); + edit_start_gpi_label->setFont(label_font); + edit_start_gpi_label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); + + edit_start_gpi_matrix_spin=new QSpinBox(this); + edit_start_gpi_matrix_spin->setRange(-1,MAX_MATRICES); + edit_start_gpi_matrix_spin->setSpecialValueText(tr("None")); + connect(edit_start_gpi_matrix_spin,SIGNAL(valueChanged(int)), + this,SLOT(startMatrixGpiChangedData(int))); + + edit_start_gpi_line_spin=new QSpinBox(this); + edit_start_gpi_line_spin->setRange(1,MAX_GPIO_PINS); + if((chan==RDAirPlayConf::SoundPanel1Channel)|| + (chan==RDAirPlayConf::SoundPanel2Channel)|| + (chan==RDAirPlayConf::SoundPanel3Channel)|| + (chan==RDAirPlayConf::SoundPanel4Channel)|| + (chan==RDAirPlayConf::SoundPanel5Channel)|| + (chan==RDAirPlayConf::SoundPanel2Channel)|| + (chan==RDAirPlayConf::CueChannel)) { + edit_start_gpi_label->setDisabled(true); + edit_start_gpi_matrix_spin->setDisabled(true); + edit_start_gpi_line_spin->setDisabled(true); + } + + // + // Start GPO + // + edit_start_gpo_label=new QLabel(tr("Start GPO:"),this); + edit_start_gpo_label->setFont(label_font); + edit_start_gpo_label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); + + edit_start_gpo_matrix_spin=new QSpinBox(this); + edit_start_gpo_matrix_spin->setRange(-1,MAX_MATRICES); + edit_start_gpo_matrix_spin->setSpecialValueText(tr("None")); + connect(edit_start_gpo_matrix_spin,SIGNAL(valueChanged(int)), + this,SLOT(startMatrixGpoChangedData(int))); + + edit_start_gpo_line_spin=new QSpinBox(this); + edit_start_gpo_line_spin->setRange(1,MAX_GPIO_PINS); + + // + // Stop GPI + // + edit_stop_gpi_label=new QLabel(tr("Stop GPI:"),this); + edit_stop_gpi_label->setFont(label_font); + edit_stop_gpi_label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); + + edit_stop_gpi_matrix_spin=new QSpinBox(this); + edit_stop_gpi_matrix_spin->setRange(-1,MAX_MATRICES); + edit_stop_gpi_matrix_spin->setSpecialValueText(tr("None")); + connect(edit_stop_gpi_matrix_spin,SIGNAL(valueChanged(int)), + this,SLOT(stopMatrixGpiChangedData(int))); + + edit_stop_gpi_line_spin=new QSpinBox(this); + edit_stop_gpi_line_spin->setRange(1,MAX_GPIO_PINS); + + // + // Stop GPO + // + edit_stop_gpo_label=new QLabel(tr("Stop GPO:"),this); + edit_stop_gpo_label->setFont(label_font); + edit_stop_gpo_label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); + + edit_stop_gpo_matrix_spin=new QSpinBox(this); + edit_stop_gpo_matrix_spin->setRange(-1,MAX_MATRICES); + edit_stop_gpo_matrix_spin->setSpecialValueText(tr("None")); + connect(edit_stop_gpo_matrix_spin,SIGNAL(valueChanged(int)), + this,SLOT(stopMatrixGpoChangedData(int))); + + edit_stop_gpo_line_spin=new QSpinBox(this); + edit_stop_gpo_line_spin->setRange(1,MAX_GPIO_PINS); + + // + // Signaling Type + // + edit_gpio_type_label=new QLabel(tr("Signalling Type:"),this); + edit_gpio_type_label->setFont(label_font); + edit_gpio_type_label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); + + edit_gpio_type_box=new QComboBox(this); + edit_gpio_type_box->insertItem(tr("Edge")); + edit_gpio_type_box->insertItem(tr("Level")); + + // + // Buttons + // + edit_ok_button=new QPushButton(tr("OK"),this); + edit_ok_button->setFont(label_font); + connect(edit_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + edit_cancel_button=new QPushButton(tr("Cancel"),this); + edit_cancel_button->setFont(label_font); + connect(edit_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Values + // + edit_start_gpi_matrix_spin-> + setValue(edit_airplay_conf->startGpiMatrix(edit_channel)); + startMatrixGpiChangedData(edit_start_gpi_matrix_spin->value()); + edit_start_gpi_line_spin-> + setValue(edit_airplay_conf->startGpiLine(edit_channel)); + + edit_start_gpo_matrix_spin-> + setValue(edit_airplay_conf->startGpoMatrix(edit_channel)); + startMatrixGpoChangedData(edit_start_gpo_matrix_spin->value()); + edit_start_gpo_line_spin-> + setValue(edit_airplay_conf->startGpoLine(edit_channel)); + + edit_stop_gpi_matrix_spin-> + setValue(edit_airplay_conf->stopGpiMatrix(edit_channel)); + stopMatrixGpiChangedData(edit_stop_gpi_matrix_spin->value()); + edit_stop_gpi_line_spin-> + setValue(edit_airplay_conf->stopGpiLine(edit_channel)); + + edit_stop_gpo_matrix_spin-> + setValue(edit_airplay_conf->stopGpoMatrix(edit_channel)); + stopMatrixGpoChangedData(edit_stop_gpo_matrix_spin->value()); + edit_stop_gpo_line_spin-> + setValue(edit_airplay_conf->stopGpoLine(edit_channel)); + + edit_gpio_type_box->setCurrentItem(edit_airplay_conf->gpioType(edit_channel)); +} + + +QSize EditChannelGpios::sizeHint() const +{ + return QSize(300,227); +} + + +void EditChannelGpios::resizeEvent(QResizeEvent *e) +{ + edit_title_label->setGeometry(10,10,size().width()-20,20); + + edit_start_gpi_label->setGeometry(10,35,120,20); + edit_start_gpi_matrix_spin->setGeometry(135,35,60,20); + edit_start_gpi_line_spin->setGeometry(205,35,60,20); + + edit_start_gpo_label->setGeometry(10,57,120,20); + edit_start_gpo_matrix_spin->setGeometry(135,57,60,20); + edit_start_gpo_line_spin->setGeometry(205,57,60,20); + + edit_stop_gpi_label->setGeometry(10,79,120,20); + edit_stop_gpi_matrix_spin->setGeometry(135,79,60,20); + edit_stop_gpi_line_spin->setGeometry(205,79,60,20); + + edit_stop_gpo_label->setGeometry(10,101,120,20); + edit_stop_gpo_matrix_spin->setGeometry(135,101,60,20); + edit_stop_gpo_line_spin->setGeometry(205,101,60,20); + + edit_gpio_type_label->setGeometry(10,128,120,20); + edit_gpio_type_box->setGeometry(135,128,80,20); + + edit_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + edit_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void EditChannelGpios::startMatrixGpiChangedData(int n) +{ + edit_start_gpi_line_spin->setEnabled(n>=0); +} + + +void EditChannelGpios::startMatrixGpoChangedData(int n) +{ + edit_start_gpo_line_spin->setEnabled(n>=0); +} + + +void EditChannelGpios::stopMatrixGpiChangedData(int n) +{ + edit_stop_gpi_line_spin->setEnabled(n>=0); +} + + +void EditChannelGpios::stopMatrixGpoChangedData(int n) +{ + edit_stop_gpo_line_spin->setEnabled(n>=0); +} + + +void EditChannelGpios::okData() +{ + edit_airplay_conf-> + setStartGpiMatrix(edit_channel,edit_start_gpi_matrix_spin->value()); + edit_airplay_conf-> + setStartGpiLine(edit_channel,edit_start_gpi_line_spin->value()); + + edit_airplay_conf-> + setStartGpoMatrix(edit_channel,edit_start_gpo_matrix_spin->value()); + edit_airplay_conf-> + setStartGpoLine(edit_channel,edit_start_gpo_line_spin->value()); + + edit_airplay_conf-> + setStopGpiMatrix(edit_channel,edit_stop_gpi_matrix_spin->value()); + edit_airplay_conf-> + setStopGpiLine(edit_channel,edit_stop_gpi_line_spin->value()); + + edit_airplay_conf-> + setStopGpoMatrix(edit_channel,edit_stop_gpo_matrix_spin->value()); + edit_airplay_conf-> + setStopGpoLine(edit_channel,edit_stop_gpo_line_spin->value()); + + edit_airplay_conf->setGpioType(edit_channel, + (RDAirPlayConf::GpioType)edit_gpio_type_box->currentItem()); + + done(0); +} + + +void EditChannelGpios::cancelData() +{ + done(-1); +} diff --git a/rdadmin/edit_channelgpios.h b/rdadmin/edit_channelgpios.h new file mode 100644 index 00000000..4676c187 --- /dev/null +++ b/rdadmin/edit_channelgpios.h @@ -0,0 +1,77 @@ +// edit_channelgpios.h +// +// Edit Rivendell Channel GPIO Settings +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: edit_channelgpios.h,v 1.1.2.2 2013/03/13 15:18:05 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_CHANNELGPIOS_H +#define EDIT_CHANNELGPIOS_H + +#include +#include +#include +#include +#include + +#include + +class EditChannelGpios : public QDialog +{ + Q_OBJECT + public: + EditChannelGpios(RDAirPlayConf *conf,RDAirPlayConf::Channel chan, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + + protected: + void resizeEvent(QResizeEvent *e); + + private slots: + void startMatrixGpiChangedData(int n); + void startMatrixGpoChangedData(int n); + void stopMatrixGpiChangedData(int n); + void stopMatrixGpoChangedData(int n); + void okData(); + void cancelData(); + + private: + QLabel *edit_title_label; + QLabel *edit_start_gpi_label; + QSpinBox *edit_start_gpi_matrix_spin; + QSpinBox *edit_start_gpi_line_spin; + QLabel *edit_start_gpo_label; + QSpinBox *edit_start_gpo_matrix_spin; + QSpinBox *edit_start_gpo_line_spin; + QLabel *edit_stop_gpi_label; + QSpinBox *edit_stop_gpi_matrix_spin; + QSpinBox *edit_stop_gpi_line_spin; + QLabel *edit_stop_gpo_label; + QSpinBox *edit_stop_gpo_matrix_spin; + QSpinBox *edit_stop_gpo_line_spin; + QLabel *edit_gpio_type_label; + QComboBox *edit_gpio_type_box; + QPushButton *edit_ok_button; + QPushButton *edit_cancel_button; + RDAirPlayConf *edit_airplay_conf; + RDAirPlayConf::Channel edit_channel; +}; + + +#endif // EDIT_CHANNELGPIOS + diff --git a/rdadmin/edit_decks.cpp b/rdadmin/edit_decks.cpp new file mode 100644 index 00000000..04a12f2f --- /dev/null +++ b/rdadmin/edit_decks.cpp @@ -0,0 +1,709 @@ +// edit_decks.cpp +// +// Edit a Rivendell RDCatch Deck Configuration +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_decks.cpp,v 1.35.2.1 2012/11/28 18:49:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +EditDecks::EditDecks(RDStation *station,RDStation *cae_station, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + edit_station=station; + + setCaption(tr("Configure RDCatch")); + + // + // Create Fonts + // + QFont small_font=QFont("Helvetica",12,QFont::Bold); + small_font.setPixelSize(12); + QFont big_font=QFont("Helvetica",14,QFont::Bold); + big_font.setPixelSize(14); + + // + // Create RDCatchConf + // + edit_catch_conf=new RDCatchConf(station->name()); + + // + // Record Deck Selector + // + edit_record_deck_box=new QComboBox(this,"edit_record_deck_box"); + edit_record_deck_box->setGeometry(140,10,60,24); + edit_record_deck_box->setInsertionPolicy(QComboBox::NoInsertion); + connect(edit_record_deck_box,SIGNAL(activated(int)), + this,SLOT(recordDeckActivatedData(int))); + QLabel *label=new QLabel(edit_record_deck_box,tr("Record Deck"),this, + "edit_deck_label"); + label->setFont(small_font); + label->setGeometry(35,14,100,22); + label->setAlignment(AlignRight); + + // + // Settings Label + // + label=new QLabel(tr("Settings"),this,"settings_label"); + label->setGeometry(10,40,100,24); + label->setFont(big_font); + + // + // Card Selector + // + edit_record_selector=new RDCardSelector(this,"edit_record_selector"); + edit_record_selector->setGeometry(67,68,120,65); + connect(edit_record_selector,SIGNAL(cardChanged(int)), + this,SLOT(recordCardChangedData(int))); + + // + // Monitor Port Selector + // + edit_monitor_box=new QSpinBox(this,"edit_monitor_box"); + edit_monitor_box->setGeometry(127,112,50,19); + edit_monitor_box->setRange(-1,RD_MAX_PORTS-1); + edit_monitor_box->setSpecialValueText(tr("None")); + connect(edit_monitor_box,SIGNAL(valueChanged(int)), + this,SLOT(monitorPortChangedData(int))); + edit_monitor_label=new QLabel(edit_monitor_box,tr("Monitor Port:"),this, + "edit_monitor_label"); + edit_monitor_label->setGeometry(10,112,112,19); + edit_monitor_label->setAlignment(AlignRight|AlignVCenter); + + edit_default_on_box=new QComboBox(this,"edit_default_on_box"); + edit_default_on_box->setGeometry(305,112,60,19); + edit_default_on_box->insertItem(tr("Off")); + edit_default_on_box->insertItem(tr("On")); + edit_default_on_label=new QLabel(edit_default_on_box, + tr("Monitor defaults to"), + this,"edit_default_on_label"); + edit_default_on_label->setGeometry(195,112,105,19); + edit_default_on_label->setAlignment(AlignRight|AlignVCenter); + + // + // Format + // + edit_format_box=new QComboBox(this,"edit_format_box"); + edit_format_box->setGeometry(125,136,150,24); + edit_format_box->setInsertionPolicy(QComboBox::NoInsertion); + connect(edit_format_box,SIGNAL(activated(int)), + this,SLOT(formatActivatedData(int))); + label=new QLabel(edit_format_box,tr("Format:"),this, + "edit_format_label"); + label->setGeometry(10,136,110,24); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Bit Rate + // + edit_bitrate_box=new QComboBox(this,"edit_bitrate_box"); + edit_bitrate_box->setGeometry(125,160,140,24); + edit_bitrate_box->setInsertionPolicy(QComboBox::NoInsertion); + edit_bitrate_label=new QLabel(edit_bitrate_box,tr("Bit Rate:"),this, + "edit_bitrate_label"); + edit_bitrate_label->setGeometry(10,160,110,24); + edit_bitrate_label->setAlignment(AlignRight|AlignVCenter); + + // + // Switcher Station + // + edit_swstation_box=new QComboBox(this,"edit_swstation_box"); + edit_swstation_box->setGeometry(125,190,250,24); + edit_swstation_box->setInsertionPolicy(QComboBox::NoInsertion); + edit_swstation_label=new QLabel(edit_swstation_box,tr("Switcher Host:"),this, + "edit_swstation_label"); + edit_swstation_label->setGeometry(10,190,110,24); + edit_swstation_label->setAlignment(AlignRight|AlignVCenter); + connect(edit_swstation_box,SIGNAL(activated(const QString &)), + this,SLOT(stationActivatedData(const QString &))); + + // + // Switcher Matrix + // + edit_swmatrix_box=new QComboBox(this,"edit_swmatrix_box"); + edit_swmatrix_box->setGeometry(125,214,250,24); + edit_swmatrix_box->setInsertionPolicy(QComboBox::NoInsertion); + edit_swmatrix_box->setDisabled(true); + edit_swmatrix_label=new QLabel(edit_swmatrix_box,tr("Switcher Matrix:"),this, + "edit_swmatrix_label"); + edit_swmatrix_label->setGeometry(10,214,110,24); + edit_swmatrix_label->setAlignment(AlignRight|AlignVCenter); + edit_swmatrix_label->setDisabled(true); + connect(edit_swmatrix_box,SIGNAL(activated(const QString &)), + this,SLOT(matrixActivatedData(const QString &))); + + // + // Switcher Output + // + edit_swoutput_box=new QComboBox(this,"edit_swoutput_box"); + edit_swoutput_box->setGeometry(125,238,250,24); + edit_swoutput_box->setInsertionPolicy(QComboBox::NoInsertion); + edit_swoutput_box->setDisabled(true); + edit_swoutput_label=new QLabel(edit_swoutput_box,tr("Switcher Output:"),this, + "edit_swoutput_label"); + edit_swoutput_label->setGeometry(10,238,110,24); + edit_swoutput_label->setAlignment(AlignRight|AlignVCenter); + edit_swoutput_label->setDisabled(true); + + // + // Switcher Delay + // + edit_swdelay_box=new QSpinBox(this,"edit_swdelay_box"); + edit_swdelay_box->setGeometry(125,262,40,24); + edit_swdelay_box->setRange(0,20); + edit_swdelay_box->setDisabled(true); + edit_swdelay_label=new QLabel(edit_swdelay_box,tr("Switcher Delay:"),this, + "edit_swdelay_label"); + edit_swdelay_label->setGeometry(10,262,110,24); + edit_swdelay_label->setAlignment(AlignRight|AlignVCenter); + edit_swdelay_label->setDisabled(true); + edit_swdelay_unit=new QLabel(edit_swdelay_box,tr("1/10 sec"),this, + "edit_swdelay_unit"); + edit_swdelay_unit->setGeometry(170,262,60,24); + edit_swdelay_unit->setAlignment(AlignLeft|AlignVCenter); + edit_swdelay_unit->setDisabled(true); + edit_swdelay_box->hide(); + edit_swdelay_label->hide(); + edit_swdelay_unit->hide(); + + // + // Defaults Label + // + label=new QLabel(tr("Defaults"),this,"settings_label"); + label->setGeometry(10,276,100,24); + label->setFont(big_font); + + // + // Default Channels + // + edit_channels_box=new QComboBox(this,"edit_channels_box"); + edit_channels_box->setGeometry(125,300,60,24); + edit_channels_box->setInsertionPolicy(QComboBox::NoInsertion); + label=new QLabel(edit_channels_box,tr("Channels:"),this, + "edit_channels_label"); + label->setGeometry(10,300,110,24); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Default Autotrim Threshold + // + edit_threshold_box=new QSpinBox(this,"edit_threshold_box"); + edit_threshold_box->setGeometry(125,324,70,24); + edit_threshold_box->setSuffix(" dB"); + edit_threshold_box->setRange(-100,0); + label=new QLabel(edit_threshold_box,tr("Trim Threshold:"),this, + "edit_threshold_label"); + label->setGeometry(10,324,110,24); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Host-Wide Settings Label + // + label=new QLabel(tr("Host-Wide Settings"),this,"settings_label"); + label->setGeometry(10,369,200,24); + label->setFont(big_font); + + edit_errorrml_edit=new QLineEdit(this,"edit_errorrml_edit"); + edit_errorrml_edit->setGeometry(125,393,248,24); + label=new QLabel(edit_errorrml_edit,tr("Error RML:"),this, + "edit_errorrml_label"); + label->setGeometry(10,393,110,24); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Play Deck Selector + // + edit_play_deck_box=new QComboBox(this,"edit_record_deck_box"); + edit_play_deck_box->setGeometry(475,10,60,24); + edit_play_deck_box->setInsertionPolicy(QComboBox::NoInsertion); + connect(edit_play_deck_box,SIGNAL(activated(int)), + this,SLOT(playDeckActivatedData(int))); + label=new QLabel(edit_play_deck_box,tr("Play Deck"),this, + "edit_play_deck_label"); + label->setFont(small_font); + label->setGeometry(390,14,80,22); + label->setAlignment(AlignRight); + + // + // Play Deck Card Selector + // + edit_play_selector=new RDCardSelector(this,"edit_play_selector"); + edit_play_selector->setGeometry(387,42,120,10); + + // + // Close Button + // + QPushButton *close_button=new QPushButton(this,"close_button"); + close_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + close_button->setFont(small_font); + close_button->setText(tr("&Close")); + close_button->setDefault(true); + connect(close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Populate Data + // + if(cae_station->scanned()) { + edit_record_selector->setMaxCards(cae_station->cards()); + edit_play_selector->setMaxCards(cae_station->cards()); + for(int i=0;imaxCards();i++) { + edit_record_selector->setMaxPorts(i,cae_station->cardInputs(i)); + edit_play_selector->setMaxPorts(i,cae_station->cardOutputs(i)); + } + } + else { + QMessageBox::information(this,tr("No Audio Configuration Data"), + tr("Channel assignments will not be available for this host as audio resource data\nhas not yet been generated. Please start the Rivendell daemons on the host\nconfigured to run the CAE service in order to populate the audio resources database.")); + edit_record_selector->setDisabled(true); + edit_monitor_box->setDisabled(true); + edit_monitor_label->setDisabled(true); + edit_play_selector->setDisabled(true); + } + edit_errorrml_edit->setText(edit_catch_conf->errorRml()); + edit_record_deck=NULL; + edit_play_deck=NULL; + edit_audition_deck=NULL; + for(int i=0;iinsertItem(QString().sprintf("%d",i+1)); + edit_play_deck_box->insertItem(QString().sprintf("%d",i+1)); + } + edit_record_channel=edit_record_deck_box->currentItem()+1; + edit_play_channel=edit_play_deck_box->currentItem()+129; + edit_format_box->insertItem(tr("PCM16")); + edit_format_box->insertItem(tr("MPEG Layer 2")); + edit_channels_box->insertItem("1"); + edit_channels_box->insertItem("2"); + edit_bitrate_box->insertItem(tr("32 kbps/chan")); + edit_bitrate_box->insertItem(tr("48 kbps/chan")); + edit_bitrate_box->insertItem(tr("56 kbps/chan")); + edit_bitrate_box->insertItem(tr("64 kbps/chan")); + edit_bitrate_box->insertItem(tr("80 kbps/chan")); + edit_bitrate_box->insertItem(tr("96 kbps/chan")); + edit_bitrate_box->insertItem(tr("112 kbps/chan")); + edit_bitrate_box->insertItem(tr("128 kbps/chan")); + edit_bitrate_box->insertItem(tr("160 kbps/chan")); + edit_bitrate_box->insertItem(tr("192 kbps/chan")); + edit_swstation_box->insertItem(tr("[none]")); + RDSqlQuery *q=new RDSqlQuery("select NAME from STATIONS where \ + NAME!=\"DEFAULT\""); + while(q->next()) { + edit_swstation_box->insertItem(q->value(0).toString()); + } + delete q; + ReadRecord(edit_record_channel); + ReadRecord(edit_play_channel); + ReadRecord(0); + recordCardChangedData(edit_record_selector->card()); +} + + +EditDecks::~EditDecks() +{ + delete edit_record_deck_box; + delete edit_format_box; + delete edit_channels_box; + delete edit_bitrate_box; + delete edit_threshold_box; + delete edit_record_selector; + delete edit_record_deck; + delete edit_audition_deck; + delete edit_errorrml_edit; + delete edit_catch_conf; +} + + +QSize EditDecks::sizeHint() const +{ + return QSize(560,454); +} + + +QSizePolicy EditDecks::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditDecks::recordDeckActivatedData(int chan) +{ + WriteRecord(edit_record_channel); + edit_record_channel=chan+1; + ReadRecord(edit_record_channel); +} + + +void EditDecks::playDeckActivatedData(int chan) +{ + WriteRecord(edit_play_channel); + edit_play_channel=chan+129; + ReadRecord(edit_play_channel); +} + + +void EditDecks::recordCardChangedData(int card) +{ + if((card>=0)&&edit_monitor_label->isEnabled()) { + edit_monitor_box->setEnabled(true); + edit_monitor_box->setMaxValue(edit_station->cardOutputs(card)-1); + monitorPortChangedData(edit_monitor_box->value()); + } + else { + edit_monitor_box->setDisabled(true); + edit_default_on_label->setDisabled(true); + edit_default_on_box->setDisabled(true); + } +} + + +void EditDecks::monitorPortChangedData(int port) +{ + if(port<0) { + edit_default_on_label->setDisabled(true); + edit_default_on_box->setDisabled(true); + } + else { + edit_default_on_label->setEnabled(true); + edit_default_on_box->setEnabled(true); + } +} + + +void EditDecks::formatActivatedData(int index) +{ + if(index==0) { + edit_bitrate_label->setDisabled(true); + edit_bitrate_box->setDisabled(true); + } + else { + edit_bitrate_label->setEnabled(true); + edit_bitrate_box->setEnabled(true); + } +} + + +void EditDecks::stationActivatedData(const QString &str) +{ + QString sql; + RDSqlQuery *q; + + if(str=="[none]") { + edit_swmatrix_label->setDisabled(true); + edit_swmatrix_box->setDisabled(true); + edit_swoutput_label->setDisabled(true); + edit_swoutput_box->setDisabled(true); + edit_swdelay_label->setDisabled(true); + edit_swdelay_unit->setDisabled(true); + edit_swdelay_box->setDisabled(true); + return; + } + edit_swmatrix_label->setEnabled(true); + edit_swmatrix_box->setEnabled(true); + edit_swoutput_label->setEnabled(true); + edit_swoutput_box->setEnabled(true); + edit_swdelay_label->setEnabled(true); + edit_swdelay_unit->setEnabled(true); + edit_swdelay_box->setEnabled(true); + + edit_swmatrix_box->clear(); + sql=QString().sprintf("select NAME from MATRICES where \ + (STATION_NAME=\"%s\")&&(OUTPUTS>0)", + (const char *)str); + q=new RDSqlQuery(sql); + while(q->next()) { + edit_swmatrix_box->insertItem(q->value(0).toString()); + } + matrixActivatedData(edit_swmatrix_box->currentText()); + delete q; +} + + +void EditDecks::matrixActivatedData(const QString &str) +{ + QString sql; + RDSqlQuery *q; + + if(str.isEmpty()) { + edit_swoutput_label->setDisabled(true); + edit_swoutput_box->setDisabled(true); + edit_swdelay_label->setDisabled(true); + edit_swdelay_unit->setDisabled(true); + edit_swdelay_box->setDisabled(true); + return; + } + edit_swoutput_label->setEnabled(true); + edit_swoutput_box->setEnabled(true); + edit_swdelay_label->setEnabled(true); + edit_swdelay_unit->setEnabled(true); + edit_swdelay_box->setEnabled(true); + + edit_swoutput_box->clear(); + int matrix=GetMatrix(); + if(matrix<0) { + return; + } + sql=QString().sprintf("select NAME from OUTPUTS where \ + STATION_NAME=\"%s\"&&MATRIX=%d", + (const char *)edit_swstation_box->currentText(), + matrix); + q=new RDSqlQuery(sql); + while(q->next()) { + edit_swoutput_box->insertItem(q->value(0).toString()); + } + delete q; +} + + +void EditDecks::closeData() +{ + edit_catch_conf->setErrorRml(edit_errorrml_edit->text()); + WriteRecord(0); + WriteRecord(edit_record_channel); + WriteRecord(edit_play_channel); + done(0); +} + + +void EditDecks::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->moveTo(385,10); + p->lineTo(385,sizeHint().height()-10); + p->end(); +} + + +void EditDecks::ReadRecord(int chan) +{ + if(chan==0) { // Audition Deck + if(edit_audition_deck==NULL) { + edit_audition_deck=new RDDeck(edit_station->name(),0,true); + } + } + if((chan>128)&&(chan<(MAX_DECKS+129))) { // Play Deck + if(edit_play_deck!=NULL) { + delete edit_play_deck; + } + edit_play_deck=new RDDeck(edit_station->name(),edit_play_channel,true); + edit_play_selector->setCard(edit_play_deck->cardNumber()); + edit_play_selector->setPort(edit_play_deck->portNumber()); + } + if((chan>0)&&(chan<(MAX_DECKS+1))) { // Record Deck + if(edit_record_deck!=NULL) { + delete edit_record_deck; + } + edit_record_deck=new RDDeck(edit_station->name(),edit_record_channel,true); + edit_record_selector->setCard(edit_record_deck->cardNumber()); + edit_record_selector->setPort(edit_record_deck->portNumber()); + edit_monitor_box->setValue(edit_record_deck->monitorPortNumber()); + if(edit_record_deck->defaultMonitorOn()) { + edit_default_on_box->setCurrentItem(1); + } + else { + edit_default_on_box->setCurrentItem(0); + } + switch(edit_record_deck->defaultFormat()) { + case RDSettings::Pcm16: + edit_format_box->setCurrentItem(0); + edit_bitrate_box->setDisabled(true); + break; + + case RDSettings::MpegL2: + case RDSettings::MpegL2Wav: + edit_format_box->setCurrentItem(1); + edit_bitrate_box->setEnabled(true); + break; + + case RDSettings::MpegL1: + case RDSettings::MpegL3: + case RDSettings::Flac: + case RDSettings::OggVorbis: + break; + } + edit_channels_box->setCurrentItem(edit_record_deck->defaultChannels()-1); + switch(edit_record_deck->defaultBitrate()) { + case 32000: + edit_bitrate_box->setCurrentItem(0); + break; + case 48000: + edit_bitrate_box->setCurrentItem(1); + break; + case 56000: + edit_bitrate_box->setCurrentItem(2); + break; + case 64000: + edit_bitrate_box->setCurrentItem(3); + break; + case 80000: + edit_bitrate_box->setCurrentItem(4); + break; + case 96000: + edit_bitrate_box->setCurrentItem(5); + break; + case 112000: + edit_bitrate_box->setCurrentItem(6); + break; + case 128000: + edit_bitrate_box->setCurrentItem(7); + break; + case 160000: + edit_bitrate_box->setCurrentItem(8); + break; + case 192000: + edit_bitrate_box->setCurrentItem(9); + break; + case 224000: + edit_bitrate_box->setCurrentItem(10); + break; + case 256000: + edit_bitrate_box->setCurrentItem(11); + break; + case 320000: + edit_bitrate_box->setCurrentItem(12); + break; + case 384000: + edit_bitrate_box->setCurrentItem(13); + break; + default: + edit_bitrate_box->setCurrentItem(7); // 128 kbps/chan + break; + } + for(int i=0;icount();i++) { + if(edit_record_deck->switchStation()==edit_swstation_box->text(i)) { + edit_swstation_box->setCurrentItem(i); + stationActivatedData(edit_swstation_box->currentText()); + } + } + QString matrix_name=edit_record_deck->switchMatrixName(); + for(int i=0;icount();i++) { + if(edit_swmatrix_box->text(i)==matrix_name) { + edit_swmatrix_box->setCurrentItem(i); + matrixActivatedData(edit_swmatrix_box->currentText()); + } + } + QString output_name=edit_record_deck->switchOutputName(); + for(int i=0;icount();i++) { + if(edit_swoutput_box->text(i)==output_name) { + edit_swoutput_box->setCurrentItem(i); + } + } + edit_swdelay_box->setValue(edit_record_deck->switchDelay()/100); + edit_threshold_box->setValue(-edit_record_deck->defaultThreshold()/100); + } +} + + +void EditDecks::WriteRecord(int chan) +{ + int temp; + + if((chan>128)&&(chan<(MAX_DECKS+129))) { // Play Deck + edit_play_deck->setCardNumber(edit_play_selector->card()); + edit_play_deck->setPortNumber(edit_play_selector->port()); + } + if((chan>0)&&(chan<(MAX_DECKS+1))) { // Record Deck + edit_record_deck->setCardNumber(edit_record_selector->card()); + edit_record_deck->setPortNumber(edit_record_selector->port()); + edit_record_deck->setMonitorPortNumber(edit_monitor_box->value()); + if(edit_monitor_box->value()<0) { + edit_record_deck->setDefaultMonitorOn(false); + } + else { + if(edit_default_on_box->currentItem()==0) { + edit_record_deck->setDefaultMonitorOn(false); + } + else { + edit_record_deck->setDefaultMonitorOn(true); + } + } + switch(edit_format_box->currentItem()) { + case 0: + edit_record_deck->setDefaultFormat(RDSettings::Pcm16); + break; + case 1: + edit_record_deck->setDefaultFormat(RDSettings::MpegL2); + break; + } + edit_record_deck->setDefaultChannels(edit_channels_box->currentItem()+1); + sscanf((const char *)edit_bitrate_box->currentText(),"%d",&temp); + edit_record_deck->setDefaultBitrate(temp*1000); + edit_record_deck->setSwitchStation(edit_swstation_box->currentText()); + edit_record_deck->setSwitchMatrix(GetMatrix()); + edit_record_deck->setSwitchOutput(GetOutput()); + edit_record_deck->setSwitchDelay(100*edit_swdelay_box->value()); + edit_record_deck->setDefaultThreshold(-edit_threshold_box->value()*100); + } +} + + +int EditDecks::GetMatrix() +{ + int matrix=-1; + + QString sql=QString().sprintf("select MATRIX from MATRICES where \ + (STATION_NAME=\"%s\")&&(NAME=\"%s\")", + (const char *)edit_swstation_box->currentText(), + (const char *)edit_swmatrix_box->currentText()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + matrix=q->value(0).toInt(); + } + delete q; + return matrix; +} + + +int EditDecks::GetOutput() +{ + int output=-1; + + QString sql=QString().sprintf("select NUMBER from OUTPUTS where \ + (STATION_NAME=\"%s\")&&(MATRIX=%d)&&\ + (NAME=\"%s\")", + (const char *)edit_swstation_box->currentText(), + GetMatrix(), + (const char *)edit_swoutput_box->currentText()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + output=q->value(0).toInt(); + } + delete q; + return output; +} diff --git a/rdadmin/edit_decks.h b/rdadmin/edit_decks.h new file mode 100644 index 00000000..5b7c6684 --- /dev/null +++ b/rdadmin/edit_decks.h @@ -0,0 +1,101 @@ +// edit_decks.h +// +// Edit Rivendell Netcatcher Configuration +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_decks.h,v 1.15.6.1 2012/11/28 18:49:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_DECKS_H +#define EDIT_DECKS_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +class EditDecks : public QDialog +{ + Q_OBJECT + public: + EditDecks(RDStation *station,RDStation *cae_station, + QWidget *parent=0,const char *name=0); + ~EditDecks(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void recordDeckActivatedData(int); + void playDeckActivatedData(int); + void recordCardChangedData(int card); + void monitorPortChangedData(int port); + void formatActivatedData(int); + void stationActivatedData(const QString &); + void matrixActivatedData(const QString &); + void closeData(); + + protected: + void paintEvent(QPaintEvent *e); + + private: + void ReadRecord(int chan); + void WriteRecord(int chan); + int GetMatrix(); + int GetOutput(); + RDCatchConf *edit_catch_conf; + RDDeck *edit_record_deck; + RDDeck *edit_play_deck; + RDDeck *edit_audition_deck; + RDStation *edit_station; + int edit_record_channel; + int edit_play_channel; + QComboBox *edit_record_deck_box; + QComboBox *edit_play_deck_box; + RDCardSelector *edit_record_selector; + RDCardSelector *edit_play_selector; + QLabel *edit_monitor_label; + QSpinBox *edit_monitor_box; + QLabel *edit_default_on_label; + QComboBox *edit_default_on_box; + QComboBox *edit_format_box; + QComboBox *edit_channels_box; + QLabel *edit_bitrate_label; + QComboBox *edit_bitrate_box; + QLabel *edit_swstation_label; + QComboBox *edit_swstation_box; + QLabel *edit_swmatrix_label; + QComboBox *edit_swmatrix_box; + QLabel *edit_swoutput_label; + QComboBox *edit_swoutput_box; + QLabel *edit_swdelay_label; + QLabel *edit_swdelay_unit; + QSpinBox *edit_swdelay_box; + QSpinBox *edit_threshold_box; + QLineEdit *edit_errorrml_edit; +}; + + +#endif + diff --git a/rdadmin/edit_dropbox.cpp b/rdadmin/edit_dropbox.cpp new file mode 100644 index 00000000..86486df8 --- /dev/null +++ b/rdadmin/edit_dropbox.cpp @@ -0,0 +1,568 @@ +// edit_dropbox.cpp +// +// Edit a Rivendell Dropbox Configuration +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: edit_dropbox.cpp,v 1.11.8.3.2.1 2014/06/03 18:23:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +EditDropbox::EditDropbox(int id,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + box_dropbox=new RDDropbox(id); + + setCaption(tr("Dropbox Configuration")); + + // + // Create Fonts + // + QFont normal_font=QFont("Helvetica",12,QFont::Normal); + normal_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Dialogs + // + box_schedcodes_dialog=new RDSchedCodesDialog(this); + + // + // Group Name + // + box_group_name_box=new QComboBox(this); + box_group_name_box->setGeometry(120,10,100,20); + QLabel *label=new QLabel(box_group_name_box,tr("Default Group:"),this); + label->setGeometry(10,10,105,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Path + // + box_path_edit=new QLineEdit(this); + box_path_edit->setGeometry(120,32,sizeHint().width()-190,19); + box_path_edit->setMaxLength(255); + label=new QLabel(box_path_edit,tr("&Path Spec:"),this); + label->setGeometry(10,32,105,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QPushButton *button= + new QPushButton(tr("Select"),this); + button->setGeometry(sizeHint().width()-60,30,50,23); + button->setFont(normal_font); + connect(button,SIGNAL(clicked()),this,SLOT(selectPathData())); + + // + // To Cart + // + box_to_cart_edit=new QLineEdit(this); + box_to_cart_edit->setGeometry(120,54,60,19); + box_to_cart_edit->setValidator(new QIntValidator(1,999999,this)); + box_to_cart_edit->setMaxLength(6); + label=new QLabel(box_to_cart_edit,tr("To &Cart:"),this); + label->setGeometry(10,54,105,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + box_select_cart_button= + new QPushButton(tr("Select"),this); + box_select_cart_button->setGeometry(190,52,50,23); + box_select_cart_button->setFont(normal_font); + connect(box_to_cart_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(toCartChangedData(const QString &))); + connect(box_select_cart_button,SIGNAL(clicked()), + this,SLOT(selectCartData())); + + // + // Delete Cuts + // + box_delete_cuts_box=new QCheckBox(this); + box_delete_cuts_box->setGeometry(260,56,15,15); + box_delete_cuts_label= + new QLabel(box_delete_cuts_box,tr("Delete cuts before importing"),this); + box_delete_cuts_label->setGeometry(280,54,sizeHint().width()-150,20); + box_delete_cuts_label->setFont(font); + box_delete_cuts_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Metadata Format + // + box_metadata_pattern_edit=new QLineEdit(this); + box_metadata_pattern_edit->setGeometry(120,76,sizeHint().width()-170,19); + box_metadata_pattern_edit->setMaxLength(64); + label=new QLabel(box_metadata_pattern_edit,tr("&Metadata Pattern:"),this); + label->setGeometry(10,76,105,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // User Defined Field + // + box_user_defined_edit=new QLineEdit(this); + box_user_defined_edit->setGeometry(120,98,sizeHint().width()-170,19); + box_user_defined_edit->setMaxLength(255); + label=new QLabel(box_user_defined_edit,tr("&User Defined:"),this); + label->setGeometry(10,98,105,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Log Path + // + box_log_path_edit=new QLineEdit(this); + box_log_path_edit->setGeometry(120,120,sizeHint().width()-190,19); + box_log_path_edit->setMaxLength(255); + label= + new QLabel(box_log_path_edit,tr("&Log File:"),this); + label->setGeometry(10,120,105,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + button=new QPushButton(tr("Select"),this); + button->setGeometry(sizeHint().width()-60,118,50,23); + button->setFont(normal_font); + connect(button,SIGNAL(clicked()),this,SLOT(selectLogPathData())); + + // + // Scheduler Codes + // + box_schedcodes_button=new QPushButton(tr("Scheduler Codes"),this); + box_schedcodes_button->setGeometry(110,145,200,25); + box_schedcodes_button->setFont(font); + connect(box_schedcodes_button,SIGNAL(clicked()),this,SLOT(schedcodesData())); + + // + // Delete Source + // + box_delete_source_box=new QCheckBox(this); + box_delete_source_box->setGeometry(90,177,15,15); + label=new QLabel(box_delete_source_box,tr("Delete source files after import"), + this); + label->setGeometry(110,175,sizeHint().width()-120,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Normalization + // + box_normalization_box=new QCheckBox(this); + box_normalization_box->setGeometry(90,199,15,15); + label=new QLabel(box_normalization_box,tr("Normalize Levels"),this); + label->setGeometry(110,197,100,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + box_normalization_level_spin=new QSpinBox(this); + box_normalization_level_spin->setGeometry(275,197,50,20); + box_normalization_level_spin->setRange(-100,-1); + box_normalization_level_label=new QLabel(tr("Level:"),this); + box_normalization_level_label->setGeometry(210,197,60,20); + box_normalization_level_label->setFont(font); + box_normalization_level_label->setAlignment(AlignVCenter|AlignRight); + box_normalization_level_unit=new QLabel(tr("dBFS"),this); + box_normalization_level_unit->setGeometry(330,197,60,20); + box_normalization_level_unit->setAlignment(AlignVCenter|AlignLeft); + connect(box_normalization_box,SIGNAL(toggled(bool)), + this,SLOT(normalizationToggledData(bool))); + + // + // Autotrim + // + box_autotrim_box=new QCheckBox(this); + box_autotrim_box->setGeometry(90,223,15,15); + label=new QLabel(box_autotrim_box,tr("Autotrim Cuts"),this); + label->setGeometry(110,221,100,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + box_autotrim_level_spin=new QSpinBox(this); + box_autotrim_level_spin->setGeometry(275,221,50,20); + box_autotrim_level_spin->setRange(-100,-1); + box_autotrim_level_label=new QLabel(tr("Level:"),this); + box_autotrim_level_label->setGeometry(210,221,60,20); + box_autotrim_level_label->setFont(font); + box_autotrim_level_label->setAlignment(AlignVCenter|AlignRight); + box_autotrim_level_unit=new QLabel(tr("dBFS"),this); + box_autotrim_level_unit->setGeometry(330,221,60,20); + box_autotrim_level_unit->setAlignment(AlignVCenter|AlignLeft); + connect(box_autotrim_box,SIGNAL(toggled(bool)), + this,SLOT(autotrimToggledData(bool))); + + // + // Use CartChunk ID + // + box_use_cartchunk_id_box=new QCheckBox(this); + box_use_cartchunk_id_box->setGeometry(90,249,15,15); + label=new QLabel(box_use_cartchunk_id_box, + tr("Get cart number from CartChunk CutID"),this); + label->setGeometry(110,247,sizeHint().width()-40,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Title from CartChunk ID + // + box_title_from_cartchunk_id_box=new QCheckBox(this); + box_title_from_cartchunk_id_box->setGeometry(90,273,15,15); + label=new QLabel(box_title_from_cartchunk_id_box, + tr("Get cart title from CartChunk CutID"),this); + label->setGeometry(110,271,sizeHint().width()-40,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Fix Broken Formats + // + box_fix_broken_formats_box=new QCheckBox(this); + box_fix_broken_formats_box->setGeometry(90,297,15,15); + label=new QLabel(box_fix_broken_formats_box, + tr("Attempt to work around malformatted input files"),this); + label->setGeometry(110,295,sizeHint().width()-40,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Start Date Offset + // + box_startoffset_spin= + new QSpinBox(this); + box_startoffset_spin->setGeometry(215,319,50,20); + box_startoffset_spin->setRange(-7,7); + label=new QLabel(box_startoffset_spin,tr("Offset start date by"),this); + label->setGeometry(90,319,120,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + label=new QLabel(box_startoffset_spin,tr("days"),this); + label->setGeometry(275,321,100,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // End Date Offset + // + box_endoffset_spin= + new QSpinBox(this); + box_endoffset_spin->setGeometry(215,343,50,20); + box_endoffset_spin->setRange(-7,7); + label=new QLabel(box_endoffset_spin,tr("Offset end date by"),this); + label->setGeometry(90,343,120,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + label=new QLabel(box_endoffset_spin,tr("days"),this); + label->setGeometry(275,343,100,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Create Dates + // + box_create_dates_box=new QCheckBox(this); + box_create_dates_box->setGeometry(90,377,15,15); + label=new QLabel(box_create_dates_box,tr("Create Dates when no Dates Exist"), + this); + label->setGeometry(110,375,sizeHint().width()-40,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + box_create_startdate_offset_spin= + new QSpinBox(this); + box_create_startdate_offset_spin->setGeometry(300,401,50,20); + box_create_startdate_offset_spin->setRange(-180,180); + box_create_startdate_label= + new QLabel(box_create_startdate_offset_spin,tr("Create start date offset:"), + this); + box_create_startdate_label->setGeometry(120,401,160,20); + box_create_startdate_label->setFont(font); + box_create_startdate_label->setAlignment(AlignVCenter|AlignRight); + box_create_startdate_unit= + new QLabel(box_create_startdate_offset_spin,("days"),this); + box_create_startdate_unit->setGeometry(360,403,60,20); + box_create_startdate_unit->setAlignment(AlignVCenter|AlignLeft); + box_create_enddate_offset_spin=new QSpinBox(this); + box_create_enddate_offset_spin->setGeometry(300,431,50,20); + box_create_enddate_offset_spin->setRange(-180,180); + box_create_enddate_label= + new QLabel(box_create_enddate_offset_spin,tr("Create end date offset:"), + this); + box_create_enddate_label->setGeometry(120,431,160,20); + box_create_enddate_label->setFont(font); + box_create_enddate_label->setAlignment(AlignVCenter|AlignRight); + box_create_enddate_unit= + new QLabel(box_create_enddate_offset_spin,("days"),this); + box_create_enddate_unit->setGeometry(360,431,60,20); + box_create_enddate_unit->setAlignment(AlignVCenter|AlignLeft); + connect(box_create_dates_box,SIGNAL(toggled(bool)), + this,SLOT(createDatesToggledData(bool))); + + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + sql="select NAME from GROUPS order by NAME"; + q=new RDSqlQuery(sql); + QString groupname=box_dropbox->groupName(); + while(q->next()) { + box_group_name_box->insertItem(q->value(0).toString()); + if(q->value(0).toString()==groupname) { + box_group_name_box->setCurrentItem(box_group_name_box->count()-1); + } + } + delete q; + box_path_edit->setText(box_dropbox->path()); + if(box_dropbox->toCart()>0) { + box_to_cart_edit->setText(QString().sprintf("%06u",box_dropbox->toCart())); + } + box_delete_cuts_box->setChecked(box_dropbox->deleteCuts()); + box_metadata_pattern_edit->setText(box_dropbox->metadataPattern()); + box_user_defined_edit->setText(box_dropbox->userDefined()); + box_delete_source_box->setChecked(box_dropbox->deleteSource()); + box_normalization_box->setChecked(box_dropbox->normalizationLevel()<0); + box_normalization_level_spin-> + setValue(box_dropbox->normalizationLevel()/100); + box_autotrim_box->setChecked(box_dropbox->autotrimLevel()<0); + box_autotrim_level_spin->setValue(box_dropbox->autotrimLevel()/100); + box_use_cartchunk_id_box->setChecked(box_dropbox->useCartchunkId()); + box_title_from_cartchunk_id_box->setChecked(box_dropbox->titleFromCartchunkId()); + box_log_path_edit->setText(box_dropbox->logPath()); + box_fix_broken_formats_box->setChecked(box_dropbox->fixBrokenFormats()); + box_startoffset_spin->setValue(box_dropbox->startdateOffset()); + box_endoffset_spin->setValue(box_dropbox->enddateOffset()); + box_create_dates_box->setChecked(box_dropbox->createDates()); + box_create_startdate_offset_spin->setValue(box_dropbox->createStartdateOffset()); + box_create_enddate_offset_spin->setValue(box_dropbox->createEnddateOffset()); + toCartChangedData(box_to_cart_edit->text()); + normalizationToggledData(box_normalization_box->isChecked()); + autotrimToggledData(box_autotrim_box->isChecked()); + createDatesToggledData(box_create_dates_box->isChecked()); + + sql=QString("select SCHED_CODE from DROPBOX_SCHED_CODES ")+ + QString().sprintf("where DROPBOX_ID=%d",box_dropbox->id()); + q=new RDSqlQuery(sql); + while(q->next()) { + box_schedcodes.push_back(q->value(0).toString()); + } + delete q; +} + + +QSize EditDropbox::sizeHint() const +{ + return QSize(450,551); +} + + +QSizePolicy EditDropbox::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditDropbox::selectPathData() +{ + QString path=box_path_edit->text(); + path=QFileDialog::getExistingDirectory(path,this); + if(!path.isEmpty()) { + box_path_edit->setText(path); + } +} + + +void EditDropbox::selectCartData() +{ + int cartnum=box_to_cart_edit->text().toInt(); + admin_cart_dialog->exec(&cartnum,RDCart::Audio,NULL,0, + admin_user->name(),admin_user->password()); + if(cartnum>0) { + box_to_cart_edit->setText(QString().sprintf("%06d",cartnum)); + } +} + + +void EditDropbox::toCartChangedData(const QString &str) +{ + box_delete_cuts_box->setDisabled(str.isEmpty()); + box_delete_cuts_label->setDisabled(str.isEmpty()); +} + + +void EditDropbox::selectLogPathData() +{ + QString path=box_log_path_edit->text(); + path=QFileDialog::getSaveFileName(path,QString::null,this); + if(!path.isEmpty()) { + box_log_path_edit->setText(path); + } +} + + +void EditDropbox::schedcodesData() +{ + box_schedcodes_dialog->exec(&box_schedcodes,NULL); +} + + +void EditDropbox::normalizationToggledData(bool state) +{ + box_normalization_level_spin->setEnabled(state); + box_normalization_level_label->setEnabled(state); + box_normalization_level_unit->setEnabled(state); +} + + +void EditDropbox::autotrimToggledData(bool state) +{ + box_autotrim_level_spin->setEnabled(state); + box_autotrim_level_label->setEnabled(state); + box_autotrim_level_unit->setEnabled(state); +} + +void EditDropbox::createDatesToggledData(bool state) +{ + box_create_startdate_offset_spin->setEnabled(state); + box_create_startdate_label->setEnabled(state); + box_create_startdate_unit->setEnabled(state); + box_create_enddate_offset_spin->setEnabled(state); + box_create_enddate_label->setEnabled(state); + box_create_enddate_unit->setEnabled(state); + if (!state) { + box_create_startdate_offset_spin->setValue(0); + box_create_enddate_offset_spin->setValue(0); + } +} + + +void EditDropbox::okData() +{ + QString sql; + RDSqlQuery *q; + + // + // Validate End Date Offsets + // + if(box_create_startdate_offset_spin->value()> + box_create_enddate_offset_spin->value()) { + QMessageBox::warning(this,tr("Invalid Offsets"), + tr("The Create EndDate Offset is less than the Create Start Date Offset!")); + return; + } + + box_dropbox->setGroupName(box_group_name_box->currentText()); + box_dropbox->setPath(box_path_edit->text()); + if(box_to_cart_edit->text().isEmpty()) { + box_dropbox->setToCart(0); + } + else { + box_dropbox->setToCart(box_to_cart_edit->text().toUInt()); + } + box_dropbox->setDeleteCuts(box_delete_cuts_box->isChecked()); + box_dropbox->setMetadataPattern(box_metadata_pattern_edit->text()); + box_dropbox->setUserDefined(box_user_defined_edit->text()); + box_dropbox->setDeleteSource(box_delete_source_box->isChecked()); + if(box_normalization_box->isChecked()) { + box_dropbox-> + setNormalizationLevel(box_normalization_level_spin->value()*100); + } + else { + box_dropbox->setNormalizationLevel(0); + } + if(box_autotrim_box->isChecked()) { + box_dropbox-> + setAutotrimLevel(box_autotrim_level_spin->value()*100); + } + else { + box_dropbox->setAutotrimLevel(0); + } + box_dropbox->setUseCartchunkId(box_use_cartchunk_id_box->isChecked()); + box_dropbox->setTitleFromCartchunkId(box_title_from_cartchunk_id_box->isChecked()); + box_dropbox->setLogPath(box_log_path_edit->text()); + box_dropbox->setFixBrokenFormats(box_fix_broken_formats_box->isChecked()); + box_dropbox->setStartdateOffset(box_startoffset_spin->value()); + box_dropbox->setEnddateOffset(box_endoffset_spin->value()); + box_dropbox->setCreateDates(box_create_dates_box->isChecked()); + box_dropbox->setCreateStartdateOffset(box_create_startdate_offset_spin->value()); + box_dropbox->setCreateEnddateOffset(box_create_enddate_offset_spin->value()); + + sql=QString("delete from DROPBOX_SCHED_CODES where ")+ + QString().sprintf("DROPBOX_ID=%d",box_dropbox->id()); + q=new RDSqlQuery(sql); + delete q; + for(unsigned i=0;iid())+ + "SCHED_CODE=\""+RDEscapeString(box_schedcodes[i])+"\""; + q=new RDSqlQuery(sql); + delete q; + } + done(0); +} + + +void EditDropbox::cancelData() +{ + done(-1); +} + + diff --git a/rdadmin/edit_dropbox.h b/rdadmin/edit_dropbox.h new file mode 100644 index 00000000..f1fe7c98 --- /dev/null +++ b/rdadmin/edit_dropbox.h @@ -0,0 +1,102 @@ +// edit_dropbox.h +// +// Edit a Rivendell Dropbox Configuration +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: edit_dropbox.h,v 1.5.8.1.2.1 2014/06/03 18:23:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_DROPBOX_H +#define EDIT_DROPBOX_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +class EditDropbox : public QDialog +{ + Q_OBJECT + public: + EditDropbox(int id,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void selectPathData(); + void selectCartData(); + void toCartChangedData(const QString &str); + void selectLogPathData(); + void schedcodesData(); + void normalizationToggledData(bool state); + void autotrimToggledData(bool state); + void createDatesToggledData(bool state); + void okData(); + void cancelData(); + + private: + RDDropbox *box_dropbox; + QComboBox *box_group_name_box; + QLineEdit *box_path_edit; + QLineEdit *box_to_cart_edit; + QPushButton *box_schedcodes_button; + QCheckBox *box_delete_cuts_box; + QLabel *box_delete_cuts_label; + QLineEdit *box_metadata_pattern_edit; + QLineEdit *box_user_defined_edit; + QLineEdit *box_log_path_edit; + QCheckBox *box_delete_source_box; + QCheckBox *box_normalization_box; + QLabel *box_normalization_level_label; + QSpinBox *box_normalization_level_spin; + QLabel *box_normalization_level_unit; + QCheckBox *box_autotrim_box; + QLabel *box_autotrim_level_label; + QSpinBox *box_autotrim_level_spin; + QLabel *box_autotrim_level_unit; + QCheckBox *box_use_cartchunk_id_box; + QCheckBox *box_title_from_cartchunk_id_box; + QCheckBox *box_fix_broken_formats_box; + QPushButton *box_select_cart_button; + QSpinBox *box_startoffset_spin; + QSpinBox *box_endoffset_spin; + QCheckBox *box_create_dates_box; + QSpinBox *box_create_startdate_offset_spin; + QLabel *box_create_startdate_label; + QLabel *box_create_startdate_unit; + QSpinBox *box_create_enddate_offset_spin; + QLabel *box_create_enddate_label; + QLabel *box_create_enddate_unit; + RDSchedCodesDialog *box_schedcodes_dialog; + QStringList box_schedcodes; +}; + + +#endif // EDIT_DROPBOX_H diff --git a/rdadmin/edit_encoder.cpp b/rdadmin/edit_encoder.cpp new file mode 100644 index 00000000..6df977aa --- /dev/null +++ b/rdadmin/edit_encoder.cpp @@ -0,0 +1,223 @@ +// edit_encoder.cpp +// +// Edit a Rivendell Encoder +// +// (C) Copyright 2008 Fred Gleason +// +// $Id: edit_encoder.cpp,v 1.4 2012/02/13 19:26:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + +#include + +EditEncoder::EditEncoder(int encoder_id,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + QSqlQuery *q; + + edit_encoder_id=encoder_id; + setCaption(tr("RDAdmin - Edit Encoder")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Name + // + QLabel *label=new QLabel(tr("Name:"),this); + label->setGeometry(10,10,95,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + QLabel *name_label=new QLabel(this); + name_label->setGeometry(110,10,sizeHint().width()-120,20); + name_label->setFont(font); + name_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Default Extension + // + edit_extension_edit=new QLineEdit(this); + edit_extension_edit->setGeometry(130,32,80,20); + label=new QLabel(edit_extension_edit,tr("Default Extension:"),this); + label->setGeometry(10,32,115,20); + label->setAlignment(AlignRight|AlignVCenter); + label->setFont(bold_font); + + // + // Command Line + // + edit_commandline_edit=new QLineEdit(this); + edit_commandline_edit->setGeometry(130,54,sizeHint().width()-140,20); + label=new QLabel(edit_commandline_edit,tr("Command Line:"),this); + label->setGeometry(10,54,115,20); + label->setAlignment(AlignRight|AlignVCenter); + label->setFont(bold_font); + + // + // Channels + // + edit_channel_edit=new RDIntegerEdit(tr("Allow Channels"),1,2,this); + edit_channel_edit->setGeometry(50,82,120,180); + + // + // Sample Rates + // + edit_samprate_edit=new RDIntegerEdit(tr("Allow Sample Rates"), + 4000,192000,this); + edit_samprate_edit->setGeometry(190,82,120,180); + + // + // Bit Rates + // + edit_bitrate_edit=new RDIntegerEdit(tr("Allow Bit Rates"),0,1000000,this); + edit_bitrate_edit->setGeometry(330,82,120,180); + + // + // Ok Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Data + // + sql=QString().sprintf("select NAME,DEFAULT_EXTENSION,COMMAND_LINE \ + from ENCODERS where ID=%d", + encoder_id); + q=new RDSqlQuery(sql); + if(q->first()) { + name_label->setText(q->value(0).toString()); + edit_extension_edit->setText(q->value(1).toString()); + edit_commandline_edit->setText(q->value(2).toString()); + } + delete q; + LoadList("CHANNELS",edit_channel_edit); + LoadList("SAMPLERATES",edit_samprate_edit); + LoadList("BITRATES",edit_bitrate_edit); +} + + +QSize EditEncoder::sizeHint() const +{ + return QSize(500,332); +} + + +QSizePolicy EditEncoder::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditEncoder::okData() +{ + QString sql; + RDSqlQuery *q; + + sql=QString(). + sprintf("update ENCODERS set DEFAULT_EXTENSION=\"%s\",COMMAND_LINE=\"%s\"", + (const char *)RDEscapeString(edit_extension_edit->text()), + (const char *)RDEscapeString(edit_commandline_edit->text())); + q=new RDSqlQuery(sql); + delete q; + SaveList("CHANNELS",edit_channel_edit); + SaveList("SAMPLERATES",edit_samprate_edit); + SaveList("BITRATES",edit_bitrate_edit); + + done(0); +} + + +void EditEncoder::cancelData() +{ + done(1); +} + + +void EditEncoder::LoadList(const QString ¶mname,RDIntegerEdit *edit) +{ + QString sql; + RDSqlQuery *q; + std::vector values; + + sql=QString().sprintf("select %s from ENCODER_%s where ENCODER_ID=%d\ + order by %s", + (const char *)paramname, + (const char *)paramname, + edit_encoder_id, + (const char *)paramname); + q=new RDSqlQuery(sql); + while(q->next()) { + values.push_back(q->value(0).toInt()); + } + delete q; + edit->setValues(&values); +} + + +void EditEncoder::SaveList(const QString ¶mname,RDIntegerEdit *edit) +{ + QString sql; + RDSqlQuery *q; + std::vector values; + + sql=QString().sprintf("delete from ENCODER_%s where ENCODER_ID=%d", + (const char *)paramname,edit_encoder_id); + q=new RDSqlQuery(sql); + delete q; + edit->values(&values); + for(unsigned i=0;i +// +// $Id: edit_encoder.h,v 1.3 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_ENCODER_H +#define EDIT_ENCODER_H + +#include +#include +#include +#include +#include + +#include + +class EditEncoder : public QDialog +{ + Q_OBJECT + public: + EditEncoder(int encoder_id,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + void LoadList(const QString ¶mname,RDIntegerEdit *edit); + void SaveList(const QString ¶mname,RDIntegerEdit *edit); + QLineEdit *edit_extension_edit; + QLineEdit *edit_commandline_edit; + RDIntegerEdit *edit_channel_edit; + RDIntegerEdit *edit_samprate_edit; + RDIntegerEdit *edit_bitrate_edit; + int edit_encoder_id; +}; + + +#endif // EDIT_ENCODER + diff --git a/rdadmin/edit_endpoint.cpp b/rdadmin/edit_endpoint.cpp new file mode 100644 index 00000000..75312767 --- /dev/null +++ b/rdadmin/edit_endpoint.cpp @@ -0,0 +1,289 @@ +// edit_endpoint.cpp +// +// Edit a Rivendell Endpoint +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: edit_endpoint.cpp,v 1.10 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include + + +EditEndpoint::EditEndpoint(RDMatrix::Type type,RDMatrix::Endpoint endpoint, + int pointnum,QString *pointname,QString *feedname, + RDMatrix::Mode *mode,int *enginenum,int *devicenum, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_type=type; + edit_endpoint=endpoint; + edit_pointnum=pointnum; + edit_pointname=pointname; + edit_feedname=feedname; + edit_mode=mode; + edit_enginenum=enginenum; + edit_devicenum=devicenum; + + switch(edit_endpoint) { + case RDMatrix::Input: + edit_table="INPUTS"; + setCaption(tr("Edit Input")); + break; + + case RDMatrix::Output: + edit_table="OUTPUTS"; + setCaption(tr("Edit Output")); + break; + } + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Endpoint Name + // + edit_endpoint_edit=new QLineEdit(this,"edit_endpoint_edit"); + edit_endpoint_edit->setGeometry(75,10,sizeHint().width()-85,20); + edit_endpoint_edit->setValidator(validator); + QLabel *label= + new QLabel(edit_endpoint_edit,tr("Name: "),this,"edit_endpoint_label"); + label->setGeometry(10,13,60,20); + label->setFont(bold_font); + label->setAlignment(AlignRight); + + // + // Unity Feed + // + edit_feed_edit=new QLineEdit(this,"edit_feed_edit"); + edit_feed_edit->setGeometry(75,40,40,20); + edit_feed_edit->setValidator(validator); + label=new QLabel(edit_feed_edit,tr("Feed: "),this,"edit_feed_label"); + label->setGeometry(10,43,60,20); + label->setFont(bold_font); + label->setAlignment(AlignRight); + if((edit_type!=RDMatrix::Unity4000)||(edit_endpoint!=RDMatrix::Input)) { + edit_feed_edit->hide(); + label->hide(); + } + + // + // Unity Mode + // + edit_mode_box=new QComboBox(this,"edit_mode_box"); + label=new QLabel(edit_mode_box,tr("Mode: "),this,"edit_feed_label"); + if(edit_type==RDMatrix::StarGuideIII) { + edit_mode_box->setGeometry(135,88,85,24); + label->setGeometry(10,93,120,20); + } + else { + edit_mode_box->setGeometry(195,40,85,24); + label->setGeometry(130,43,60,20); + } + label->setFont(bold_font); + label->setAlignment(AlignRight); + if(((edit_type!=RDMatrix::Unity4000)&&(edit_type!=RDMatrix::StarGuideIII))|| + (edit_endpoint!=RDMatrix::Input)) { + edit_mode_box->hide(); + label->hide(); + } + edit_mode_box->insertItem(tr("Stereo")); + edit_mode_box->insertItem(tr("Left")); + edit_mode_box->insertItem(tr("Right")); + + // + // Logitek Engine Number / StarGuide Provider ID + // + edit_enginenum_edit=new QLineEdit(this,"edit_enginenum_edit"); + edit_enginenum_edit->setGeometry(135,36,50,20); + label=new QLabel(edit_enginenum_edit,tr("Engine (Hex): "),this,"edit_enginenum_label"); + if(edit_type==RDMatrix::StarGuideIII) { + label->setText(tr("Provider ID:")); + } + label->setGeometry(10,36,120,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + if((edit_type!=RDMatrix::LogitekVguest)&& + ((edit_type!=RDMatrix::StarGuideIII)||(edit_endpoint!=RDMatrix::Input))) { + edit_enginenum_edit->hide(); + label->hide(); + } + + // + // Logitek Device Number / StarGuide Service ID + // + edit_devicenum_edit=new QLineEdit(this,"edit_devicenum_edit"); + edit_devicenum_edit->setGeometry(135,62,50,20); + label=new QLabel(edit_devicenum_edit,tr("Device (Hex): "),this,"edit_devicenum_label"); + if(edit_type==RDMatrix::StarGuideIII) { + label->setText(tr("Service ID:")); + } + label->setGeometry(10,62,120,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + if((edit_type!=RDMatrix::LogitekVguest)&& + ((edit_type!=RDMatrix::StarGuideIII)||(edit_endpoint!=RDMatrix::Input))) { + edit_devicenum_edit->hide(); + label->hide(); + } + + // + // Ok Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Data + // + edit_endpoint_edit->setText(*edit_pointname); + edit_feed_edit->setText(*edit_feedname); + edit_mode_box->setCurrentItem(*edit_mode); + if(*enginenum>=0) { + if(edit_type==RDMatrix::LogitekVguest) { + edit_enginenum_edit->setText(QString().sprintf("%04X",*enginenum)); + } + else { + edit_enginenum_edit->setText(QString().sprintf("%d",*enginenum)); + } + } + if(*devicenum>=0) { + if(edit_type==RDMatrix::LogitekVguest) { + edit_devicenum_edit->setText(QString().sprintf("%04X",*devicenum)); + } + else { + edit_devicenum_edit->setText(QString().sprintf("%d",*devicenum)); + } + } +} + + +QSize EditEndpoint::sizeHint() const +{ + if((edit_endpoint==RDMatrix::Input)&&(edit_type==RDMatrix::Unity4000)) { + return QSize(400,130); + } + if((edit_endpoint==RDMatrix::Input)&&(edit_type==RDMatrix::StarGuideIII)) { + return QSize(420,156); + } + return QSize(400,100); +} + + +QSizePolicy EditEndpoint::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditEndpoint::okData() +{ + bool ok; + int enginenum=-1; + if(edit_type==RDMatrix::LogitekVguest) { + enginenum=edit_enginenum_edit->text().toInt(&ok,16); + } + else { + enginenum=edit_enginenum_edit->text().toInt(&ok); + } + if(!ok) { + if(edit_enginenum_edit->text().isEmpty()) { + enginenum=-1; + } + else { + if(edit_type==RDMatrix::LogitekVguest) { + QMessageBox::warning(this,tr("Invalid Number"), + tr("The Engine Number is Invalid!")); + } + else { + QMessageBox::warning(this,tr("Invalid Number"), + tr("The Provider ID is Invalid!")); + } + return; + } + } + int devicenum=-1; + if(edit_type==RDMatrix::LogitekVguest) { + devicenum=edit_devicenum_edit->text().toInt(&ok,16); + } + else { + devicenum=edit_devicenum_edit->text().toInt(&ok); + } + if(!ok) { + if(edit_devicenum_edit->text().isEmpty()) { + devicenum=-1; + } + else { + if(edit_type==RDMatrix::LogitekVguest) { + QMessageBox::warning(this,tr("Invalid Number"), + tr("The Device Number is Invalid!")); + } + else { + QMessageBox::warning(this,tr("Invalid Number"), + tr("The Service ID is Invalid!")); + } + return; + } + } + *edit_pointname=edit_endpoint_edit->text(); + *edit_feedname=edit_feed_edit->text(); + *edit_mode=(RDMatrix::Mode)edit_mode_box->currentItem(); + *edit_enginenum=enginenum; + *edit_devicenum=devicenum; + done(0); +} + + +void EditEndpoint::cancelData() +{ + done(1); +} diff --git a/rdadmin/edit_endpoint.h b/rdadmin/edit_endpoint.h new file mode 100644 index 00000000..d141c2f3 --- /dev/null +++ b/rdadmin/edit_endpoint.h @@ -0,0 +1,71 @@ +// edit_endpoint.h +// +// Edit a Rivendell Endpoint +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: edit_endpoint.h,v 1.7 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_ENDPOINT_H +#define EDIT_ENDPOINT_H + +#include +#include +#include +#include +#include +#include + +#include +#include + + +class EditEndpoint : public QDialog +{ + Q_OBJECT + public: + EditEndpoint(RDMatrix::Type type,RDMatrix::Endpoint endpoint, + int pointnum,QString *pointname,QString *feedname, + RDMatrix::Mode *mode,int *enginenum,int *devicenum, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + RDMatrix::Type edit_type; + RDMatrix::Endpoint edit_endpoint; + int edit_pointnum; + QString *edit_pointname; + QString *edit_feedname; + RDMatrix::Mode *edit_mode; + int *edit_enginenum; + int *edit_devicenum; + QString edit_table; + QLineEdit *edit_endpoint_edit; + QLineEdit *edit_feed_edit; + QLineEdit *edit_enginenum_edit; + QLineEdit *edit_devicenum_edit; + QComboBox *edit_mode_box; +}; + + +#endif // EDIT_ENDPOINT + diff --git a/rdadmin/edit_feed.cpp b/rdadmin/edit_feed.cpp new file mode 100644 index 00000000..4c9d7a2f --- /dev/null +++ b/rdadmin/edit_feed.cpp @@ -0,0 +1,748 @@ +// edit_feed.cpp +// +// Edit a Rivendell Feed +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_feed.cpp,v 1.9 2012/01/16 11:16:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + + +EditFeed::EditFeed(const QString &feed,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + feed_feed=new RDFeed(feed,this,"feed_feed"); + + setCaption(tr("Feed: ")+feed); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",12,QFont::Normal); + small_font.setPixelSize(12); + + // + // Feed Name + // + feed_keyname_edit=new QLineEdit(this,"feed_keyname_edit"); + feed_keyname_edit->setGeometry(115,11,100,19); + feed_keyname_edit->setMaxLength(8); + feed_keyname_edit->setReadOnly(true); + QLabel *feed_keyname_label=new QLabel(feed_keyname_edit,tr("Key Name:"),this, + "feed_keyname_label"); + feed_keyname_label->setGeometry(10,11,100,19); + feed_keyname_label->setFont(font); + feed_keyname_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Channel Section + // + feed_channel_section_label=new QLabel(tr("CHANNEL VALUES"),this); + feed_channel_section_label->setGeometry(30,41,130,20); + feed_channel_section_label->setAlignment(AlignCenter); + feed_channel_section_label->setFont(font); + + // + // Channel Title + // + feed_channel_title_edit=new QLineEdit(this,"feed_channel_title_edit"); + feed_channel_title_edit->setGeometry(115,60,375,19); + feed_channel_title_edit->setMaxLength(255); + feed_channel_title_label= + new QLabel(feed_channel_title_edit,tr("Title:"),this, + "feed_channel_title_label"); + feed_channel_title_label->setGeometry(20,60,90,19); + feed_channel_title_label->setFont(font); + feed_channel_title_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Channel Category + // + feed_channel_category_edit=new QLineEdit(this,"feed_channel_category_edit"); + feed_channel_category_edit->setGeometry(115,82,375,19); + feed_channel_category_edit->setMaxLength(64); + feed_channel_category_label= + new QLabel(feed_channel_category_edit,tr("Category:"),this, + "feed_channel_category_label"); + feed_channel_category_label->setGeometry(20,82,90,19); + feed_channel_category_label->setFont(font); + feed_channel_category_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Channel Link + // + feed_channel_link_edit=new QLineEdit(this,"feed_channel_link_edit"); + feed_channel_link_edit->setGeometry(115,104,375,19); + feed_channel_link_edit->setMaxLength(255); + feed_channel_link_label= + new QLabel(feed_channel_link_edit,tr("Link:"),this, + "feed_channel_link_label"); + feed_channel_link_label->setGeometry(20,104,90,19); + feed_channel_link_label->setFont(font); + feed_channel_link_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Channel Copyright + // + feed_channel_copyright_edit= + new QLineEdit(this,"feed_channel_copyright_edit"); + feed_channel_copyright_edit->setGeometry(115,126,375,19); + feed_channel_copyright_edit->setMaxLength(64); + feed_channel_copyright_label= + new QLabel(feed_channel_copyright_edit,tr("Copyright:"),this, + "feed_channel_copyright_label"); + feed_channel_copyright_label->setGeometry(20,126,90,19); + feed_channel_copyright_label->setFont(font); + feed_channel_copyright_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Channel Webmaster + // + feed_channel_webmaster_edit= + new QLineEdit(this,"feed_channel_webmaster_edit"); + feed_channel_webmaster_edit->setGeometry(115,148,375,19); + feed_channel_webmaster_edit->setMaxLength(64); + feed_channel_webmaster_label= + new QLabel(feed_channel_webmaster_edit,tr("Webmaster:"),this, + "feed_channel_webmaster_label"); + feed_channel_webmaster_label->setGeometry(20,148,90,19); + feed_channel_webmaster_label->setFont(font); + feed_channel_webmaster_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Channel Language + // + feed_channel_language_edit= + new QLineEdit(this,"feed_channel_language_edit"); + feed_channel_language_edit-> + setGeometry(115,170,60,19); + feed_channel_language_edit->setMaxLength(5); + feed_channel_language_label= + new QLabel(feed_channel_language_edit,tr("Language:"),this, + "feed_channel_language_label"); + feed_channel_language_label->setGeometry(20,170,90,19); + feed_channel_language_label->setFont(font); + feed_channel_language_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Channel Description + // + feed_channel_description_edit= + new QTextEdit(this,"feed_channel_description_edit"); + feed_channel_description_edit-> + setGeometry(115,192,375,76); + feed_channel_description_label= + new QLabel(feed_channel_description_edit,tr("Description:"),this, + "feed_channel_description_label"); + feed_channel_description_label->setGeometry(20,192,90,19); + feed_channel_description_label->setFont(font); + feed_channel_description_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Purge Audio URL + // + feed_purge_url_edit= + new QLineEdit(this,"feed_purge_url_edit"); + feed_purge_url_edit->setGeometry(155,280,335,19); + feed_purge_url_edit->setMaxLength(255); + connect(feed_purge_url_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(purgeUrlChangedData(const QString &))); + feed_purge_url_label= + new QLabel(feed_purge_url_edit,tr("Audio Upload URL:"),this, + "feed_purge_url_label"); + feed_purge_url_label->setGeometry(20,280,130,19); + feed_purge_url_label->setFont(font); + feed_purge_url_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Purge Username + // + feed_purge_username_edit= + new QLineEdit(this,"feed_purge_username_edit"); + feed_purge_username_edit->setGeometry(225,302,95,19); + feed_purge_username_edit->setMaxLength(64); + connect(feed_purge_username_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(purgeUsernameChangedData(const QString &))); + feed_purge_username_label= + new QLabel(feed_purge_username_edit,tr("Username:"),this, + "feed_purge_username_label"); + feed_purge_username_label->setGeometry(40,302,180,19); + feed_purge_username_label->setFont(font); + feed_purge_username_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Purge Password + // + feed_purge_password_edit= + new QLineEdit(this,"feed_purge_password_edit"); + feed_purge_password_edit->setGeometry(395,302,95,19); + feed_purge_password_edit->setMaxLength(64); + feed_purge_password_edit->setEchoMode(QLineEdit::Password); + feed_purge_password_label= + new QLabel(feed_purge_password_edit,tr("Password:"),this, + "feed_purge_password_label"); + feed_purge_password_label->setGeometry(320,302,70,19); + feed_purge_password_label->setFont(font); + feed_purge_password_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Audio Format + // + feed_format_edit=new QLineEdit(this,"feed_format_edit"); + feed_format_edit->setGeometry(155,324,285,20); + feed_format_edit->setReadOnly(true); + feed_format_label=new QLabel(feed_format_edit, + tr("Upload Format:"),this,"feed_format_label"); + feed_format_label->setGeometry(5,324,145,20); + feed_format_label->setFont(font); + feed_format_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + feed_format_button=new QPushButton(this,"format_button"); + feed_format_button->setGeometry(450,324,40,24); + feed_format_button->setFont(small_font); + feed_format_button->setText(tr("S&et")); + connect(feed_format_button,SIGNAL(clicked()),this,SLOT(setFormatData())); + + // + // Normalize Check Box + // + feed_normalize_box=new QCheckBox(this,"feed_normalize_box"); + feed_normalize_box->setGeometry(155,348,15,15); + feed_normalize_box->setChecked(true); + feed_normalize_check_label=new QLabel(feed_normalize_box,tr("Normalize"), + this,"normalize_check_label"); + feed_normalize_check_label->setGeometry(175,346,83,20); + feed_normalize_check_label->setFont(font); + feed_normalize_check_label->setAlignment(AlignLeft|AlignVCenter); + connect(feed_normalize_box,SIGNAL(toggled(bool)), + this,SLOT(normalizeCheckData(bool))); + + // + // Normalize Level + // + feed_normalize_spin=new QSpinBox(this,"feed_normalize_spin"); + feed_normalize_spin->setGeometry(295,346,40,20); + feed_normalize_spin->setRange(-30,-1); + feed_normalize_label=new QLabel(feed_normalize_spin,tr("Level:"), + this,"normalize_spin_label"); + feed_normalize_label->setGeometry(245,346,45,20); + feed_normalize_label->setFont(font); + feed_normalize_label->setAlignment(AlignRight|AlignVCenter); + feed_normalize_unit_label=new QLabel(tr("dBFS"),this,"normalize_unit_label"); + feed_normalize_unit_label->setGeometry(340,346,40,20); + feed_normalize_unit_label->setFont(font); + feed_normalize_unit_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Base Audio URL + // + feed_base_url_edit= + new QLineEdit(this,"feed_base_url_edit"); + feed_base_url_edit->setGeometry(155,368,335,19); + feed_base_url_edit->setMaxLength(255); + feed_base_url_label= + new QLabel(feed_base_url_edit,tr("Audio Download URL:"),this, + "feed_base_url_label"); + feed_base_url_label->setGeometry(20,368,130,19); + feed_base_url_label->setFont(font); + feed_base_url_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Keep Expired Metadata Checkbox + // + feed_keep_metadata_box=new QCheckBox(this,"feed_keep_metadata_box"); + feed_keep_metadata_box->setGeometry(155,390,15,15); + feed_keep_metadata_label= + new QLabel(feed_keep_metadata_box,tr("Keep Expired Metadata"),this, + "feed_keep_metadata_label"); + feed_keep_metadata_label->setGeometry(175,390,180,19); + feed_keep_metadata_label->setFont(font); + feed_keep_metadata_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // AutoPost Checkbox + // + feed_autopost_box=new QCheckBox(this,"feed_autopost_box"); + feed_autopost_box->setGeometry(365,390,15,15); + feed_autopost_label= + new QLabel(feed_autopost_box,tr("Enable AutoPost"),this, + "feed_autopost_label"); + feed_autopost_label->setGeometry(385,390,200,19); + feed_autopost_label->setFont(font); + feed_autopost_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Enclosure Preamble + // + feed_base_preamble_edit= + new QLineEdit(this,"feed_base_preamble_edit"); + feed_base_preamble_edit->setGeometry(155,412,335,19); + feed_base_preamble_edit->setMaxLength(255); + feed_base_preamble_label= + new QLabel(feed_base_preamble_edit,tr("Enclosure Preamble:"),this, + "feed_base_preamble_label"); + feed_base_preamble_label->setGeometry(20,412,130,19); + feed_base_preamble_label->setFont(font); + feed_base_preamble_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Audio File Extension + // + feed_extension_edit=new QLineEdit(this,"feed_extension_edit"); + feed_extension_edit->setGeometry(155,434,70,19); + feed_extension_edit->setMaxLength(16); + feed_extension_label= + new QLabel(feed_extension_edit,tr("Audio Extension:"),this, + "feed_extension_label"); + feed_extension_label->setGeometry(20,434,130,19); + feed_extension_label->setFont(font); + feed_extension_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Maximum Shelf Life + // + feed_max_shelf_life_spin= + new QSpinBox(this,"feed_max_shelf_life_spin"); + feed_max_shelf_life_spin->setGeometry(155,456,60,19); + feed_max_shelf_life_spin->setRange(0,365); + feed_max_shelf_life_spin->setSpecialValueText(tr("None")); + feed_max_shelf_life_label= + new QLabel(feed_max_shelf_life_spin,tr("Maximum Shelf Life:"),this, + "feed_max_shelf_life_label"); + feed_max_shelf_life_label->setGeometry(20,456,130,19); + feed_max_shelf_life_label->setFont(font); + feed_max_shelf_life_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + feed_max_shelf_life_unit_label= + new QLabel(feed_max_shelf_life_spin,tr("days"),this, + "feed_max_shelf_life_unit"); + feed_max_shelf_life_unit_label->setGeometry(220,456,50,19); + feed_max_shelf_life_unit_label->setFont(font); + feed_max_shelf_life_unit_label-> + setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Episode Order + // + feed_castorder_box=new QComboBox(this,"feed_castorder_box"); + feed_castorder_box->setGeometry(155,478,100,19); + feed_castorder_box->insertItem(tr("Descending")); + feed_castorder_box->insertItem(tr("Ascending")); + feed_castorder_label=new QLabel(feed_castorder_box,tr("Episode Sort Order:"), + this,"feed_castorder_label"); + feed_castorder_label->setGeometry(20,478,130,19); + feed_castorder_label->setFont(font); + feed_castorder_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Media Link Mode + // + feed_media_link_mode_box=new QComboBox(this,"feed_media_link_mode_box"); + feed_media_link_mode_box->setGeometry(155,500,100,19); + feed_media_link_mode_box->insertItem(tr("None")); + feed_media_link_mode_box->insertItem(tr("Direct")); + feed_media_link_mode_box->insertItem(tr("Counted")); + feed_media_link_mode_label=new QLabel(feed_media_link_mode_box, + tr("Media Link Mode:"), + this,"feed_media_link_mode_label"); + feed_media_link_mode_label->setGeometry(20,500,130,19); + feed_media_link_mode_label->setFont(font); + feed_media_link_mode_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Feed Redirection + // + feed_redirect_check=new QCheckBox(this,"feed_redirect_check"); + feed_redirect_check->setGeometry(20,532,15,15); + QLabel *label=new QLabel(feed_redirect_check,tr("Enable Feed Redirection"), + this,"feed_redirect_label"); + label->setGeometry(40,532,200,19); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + feed_redirect_edit=new QLineEdit(this,"feed_redirect_edit"); + feed_redirect_edit->setGeometry(85,552,405,20); + feed_redirect_label=new QLabel(feed_redirect_edit,tr("URL:"), + this,"feed_redirect_label"); + feed_redirect_label->setGeometry(40,552,40,19); + feed_redirect_label->setFont(font); + feed_redirect_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Header XML + // + feed_header_xml_edit= + new QTextEdit(this,"feed_header_xml_edit"); + feed_header_xml_edit-> + setGeometry(615,10,365,76); + feed_header_xml_label= + new QLabel(feed_header_xml_edit,tr("Header XML:"),this, + "feed_header_xml_label"); + feed_header_xml_label->setGeometry(520,10,90,19); + feed_header_xml_label->setFont(font); + feed_header_xml_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Channel XML + // + feed_channel_xml_edit= + new QTextEdit(this,"feed_channel_xml_edit"); + feed_channel_xml_edit-> + setGeometry(615,88,365,176); + feed_channel_xml_label= + new QLabel(feed_channel_xml_edit,tr("Channel XML:"),this, + "feed_channel_xml_label"); + feed_channel_xml_label->setGeometry(520,88,90,19); + feed_channel_xml_label->setFont(font); + feed_channel_xml_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Item XML + // + feed_item_xml_edit= + new QTextEdit(this,"feed_item_xml_edit"); + feed_item_xml_edit-> + setGeometry(615,270,365,176); + feed_item_xml_label= + new QLabel(feed_item_xml_edit,tr("Item XML:"),this, + "feed_item_xml_label"); + feed_item_xml_label->setGeometry(520,270,90,19); + feed_item_xml_label->setFont(font); + feed_item_xml_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Metadata Button + // + feed_metadata_button=new QPushButton(this,"feed_metadata_button"); + feed_metadata_button->setGeometry(615,460,150,50); + feed_metadata_button->setDefault(true); + feed_metadata_button->setFont(font); + feed_metadata_button->setText(tr("&Define Auxiliary\nMetadata Fields")); + connect(feed_metadata_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Values + // + feed_keyname_edit->setText(feed_feed->keyName()); + feed_channel_title_edit->setText(feed_feed->channelTitle()); + feed_channel_category_edit->setText(feed_feed->channelCategory()); + feed_channel_link_edit->setText(feed_feed->channelLink()); + feed_channel_copyright_edit->setText(feed_feed->channelCopyright()); + feed_channel_webmaster_edit->setText(feed_feed->channelWebmaster()); + feed_channel_description_edit->setText(feed_feed->channelDescription()); + feed_channel_language_edit->setText(feed_feed->channelLanguage()); + feed_base_url_edit->setText(feed_feed->baseUrl()); + feed_base_preamble_edit->setText(feed_feed->basePreamble()); + feed_purge_url_edit->setText(feed_feed->purgeUrl()); + feed_purge_username_edit->setText(feed_feed->purgeUsername()); + feed_purge_password_edit->setText(feed_feed->purgePassword()); + feed_header_xml_edit->setText(feed_feed->headerXml()); + feed_channel_xml_edit->setText(feed_feed->channelXml()); + feed_item_xml_edit->setText(feed_feed->itemXml()); + feed_max_shelf_life_spin->setValue(feed_feed->maxShelfLife()); + feed_autopost_box->setChecked(feed_feed->enableAutopost()); + feed_keep_metadata_box->setChecked(feed_feed->keepMetadata()); + feed_settings.setFormat(feed_feed->uploadFormat()); + feed_settings.setChannels(feed_feed->uploadChannels()); + feed_settings.setSampleRate(feed_feed->uploadSampleRate()); + feed_settings.setBitRate(feed_feed->uploadBitRate()); + feed_settings.setQuality(feed_feed->uploadQuality()); + feed_extension_edit->setText(feed_feed->uploadExtension()); + feed_format_edit->setText(feed_settings.description()); + if(feed_feed->normalizeLevel()>0) { + feed_normalize_box->setChecked(false); + } + else { + feed_normalize_box->setChecked(true); + feed_normalize_spin->setValue(feed_feed->normalizeLevel()/1000); + } + feed_castorder_box->setCurrentItem(feed_feed->castOrder()); + feed_media_link_mode_box->setCurrentItem((int)feed_feed->mediaLinkMode()); + feed_redirect_edit->setText(feed_feed->redirectPath()); + feed_redirect_check->setChecked(!feed_redirect_edit->text().isEmpty()); + normalizeCheckData(feed_normalize_box->isChecked()); + + RedirectChanged(feed_redirect_check->isChecked()); + connect(feed_redirect_check,SIGNAL(toggled(bool)), + this,SLOT(redirectToggledData(bool))); +} + + +QSize EditFeed::sizeHint() const +{ + return QSize(1000,591); +} + + +QSizePolicy EditFeed::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditFeed::purgeUrlChangedData(const QString &str) +{ + QUrl url(str); + QString protocol=url.protocol(); + if(((protocol=="ftp")||(protocol=="smb"))&& + (!feed_redirect_check->isChecked())) { + feed_purge_username_label->setEnabled(true); + feed_purge_username_edit->setEnabled(true); + } + else { + feed_purge_username_label->setDisabled(true); + feed_purge_username_edit->setDisabled(true); + } + purgeUsernameChangedData(feed_purge_username_edit->text()); +} + + +void EditFeed::purgeUsernameChangedData(const QString &username) +{ + feed_purge_password_label-> + setDisabled(username.isEmpty()||feed_purge_url_edit->text().isEmpty()|| + feed_redirect_check->isChecked()); + feed_purge_password_edit-> + setDisabled(username.isEmpty()||feed_purge_url_edit->text().isEmpty()|| + feed_redirect_check->isChecked()); +} + + +void EditFeed::setFormatData() +{ + RDStation *station=new RDStation(admin_config->stationName()); + RDExportSettingsDialog *dialog= + new RDExportSettingsDialog(&feed_settings,station,this,"dialog"); + dialog->exec(); + delete dialog; + delete station; + feed_format_edit->setText(feed_settings.description()); +} + + +void EditFeed::normalizeCheckData(bool state) +{ + feed_normalize_label->setEnabled(state); + feed_normalize_spin->setEnabled(state); + feed_normalize_unit_label->setEnabled(state); +} + + +void EditFeed::editData() +{ + ListAuxFields *lf=new ListAuxFields(feed_feed->id(),this); + lf->exec(); + delete lf; +} + + +void EditFeed::redirectToggledData(bool state) +{ + if(state) { + switch(QMessageBox::warning(this,tr("Edit Feed - Redirect"), + tr("Enabling feed redirection will cause clients subscribed to\nthis feed to be PERMANENTLY redirected to the\nspecified URL.\n\nDo you still want to enable redireciton?"),QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::Yes: + break; + + default: + feed_redirect_check->setChecked(false); + return; + } + } + RedirectChanged(state); +} + + +void EditFeed::okData() +{ + feed_feed->setChannelTitle(feed_channel_title_edit->text()); + feed_feed->setChannelCategory(feed_channel_category_edit->text()); + feed_feed->setChannelLink(feed_channel_link_edit->text()); + feed_feed->setChannelCopyright(feed_channel_copyright_edit->text()); + feed_feed->setChannelWebmaster(feed_channel_webmaster_edit->text()); + feed_feed->setChannelDescription(feed_channel_description_edit->text()); + feed_feed->setChannelLanguage(feed_channel_language_edit->text()); + feed_feed->setBaseUrl(feed_base_url_edit->text()); + feed_feed->setBasePreamble(feed_base_preamble_edit->text()); + feed_feed->setPurgeUrl(feed_purge_url_edit->text()); + feed_feed->setPurgeUsername(feed_purge_username_edit->text()); + feed_feed->setPurgePassword(feed_purge_password_edit->text()); + feed_feed->setHeaderXml(feed_header_xml_edit->text()); + feed_feed->setChannelXml(feed_channel_xml_edit->text()); + feed_feed->setItemXml(feed_item_xml_edit->text()); + feed_feed->setMaxShelfLife(feed_max_shelf_life_spin->value()); + feed_feed->setLastBuildDateTime(QDateTime(QDate::currentDate(), + QTime::currentTime())); + feed_feed->setEnableAutopost(feed_autopost_box->isChecked()); + feed_feed->setKeepMetadata(feed_keep_metadata_box->isChecked()); + feed_feed->setUploadFormat(feed_settings.format()); + feed_feed->setUploadChannels(feed_settings.channels()); + feed_feed->setUploadSampleRate(feed_settings.sampleRate()); + feed_feed->setUploadBitRate(feed_settings.bitRate()); + feed_feed->setUploadQuality(feed_settings.quality()); + feed_feed->setUploadExtension(feed_extension_edit->text()); + if(feed_normalize_box->isChecked()) { + feed_feed->setNormalizeLevel(feed_normalize_spin->value()*1000); + } + else { + feed_feed->setNormalizeLevel(1); + } + feed_feed->setCastOrder(feed_castorder_box->currentItem()); + feed_feed->setMediaLinkMode((RDFeed::MediaLinkMode)feed_media_link_mode_box-> + currentItem()); + if(feed_redirect_check->isChecked()) { + feed_feed->setRedirectPath(feed_redirect_edit->text()); + } + else { + feed_feed->setRedirectPath(""); + } + + done(0); +} + + +void EditFeed::cancelData() +{ + done(-1); +} + + +void EditFeed::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->moveTo(10,50); + p->lineTo(sizeHint().width()/2,50); + p->lineTo(sizeHint().width()/2,272); + p->lineTo(10,272); + p->lineTo(10,50); + delete p; +} + + +void EditFeed::RedirectChanged(bool state) +{ + feed_redirect_label->setEnabled(state); + feed_redirect_edit->setEnabled(state); + feed_channel_title_edit->setDisabled(state); + feed_channel_description_edit->setDisabled(state); + feed_channel_category_edit->setDisabled(state); + feed_channel_link_edit->setDisabled(state); + feed_channel_copyright_edit->setDisabled(state); + feed_channel_webmaster_edit->setDisabled(state); + feed_channel_language_edit->setDisabled(state); + feed_base_url_edit->setDisabled(state); + feed_purge_url_edit->setDisabled(state); + feed_purge_username_label->setDisabled(state); + feed_purge_username_edit->setDisabled(state); + feed_purge_password_label->setDisabled(state); + feed_purge_password_edit->setDisabled(state); + feed_header_xml_edit->setDisabled(state); + feed_channel_xml_edit->setDisabled(state); + feed_item_xml_edit->setDisabled(state); + feed_max_shelf_life_spin->setDisabled(state); + feed_autopost_box->setDisabled(state); + feed_keep_metadata_box->setDisabled(state); + feed_format_edit->setDisabled(state); + feed_normalize_box->setDisabled(state); + feed_extension_edit->setDisabled(state); + feed_castorder_box->setDisabled(state); + feed_format_button->setDisabled(state); + feed_metadata_button->setDisabled(state); + feed_channel_title_label->setDisabled(state); + feed_channel_category_label->setDisabled(state); + feed_channel_link_label->setDisabled(state); + feed_channel_copyright_label->setDisabled(state); + feed_channel_webmaster_label->setDisabled(state); + feed_channel_language_label->setDisabled(state); + feed_channel_description_label->setDisabled(state); + feed_base_url_label->setDisabled(state); + feed_base_preamble_label->setDisabled(state); + feed_purge_url_label->setDisabled(state); + feed_max_shelf_life_label->setDisabled(state); + feed_max_shelf_life_unit_label->setDisabled(state); + feed_autopost_label->setDisabled(state); + feed_keep_metadata_label->setDisabled(state); + feed_format_label->setDisabled(state); + feed_normalize_check_label->setDisabled(state); + feed_normalize_unit_label->setDisabled(state); + feed_castorder_label->setDisabled(state); + feed_extension_label->setDisabled(state); + feed_channel_section_label->setDisabled(state); + feed_header_xml_label->setDisabled(state); + feed_channel_xml_label->setDisabled(state); + feed_item_xml_label->setDisabled(state); + feed_normalize_label->setDisabled(state||(!feed_normalize_box->isChecked())); + feed_normalize_spin->setDisabled(state||(!feed_normalize_box->isChecked())); + feed_normalize_unit_label-> + setDisabled(state||(!feed_normalize_box->isChecked())); + feed_media_link_mode_box->setDisabled(state); + feed_media_link_mode_label->setDisabled(state); + purgeUrlChangedData(feed_purge_url_edit->text()); +} diff --git a/rdadmin/edit_feed.h b/rdadmin/edit_feed.h new file mode 100644 index 00000000..ef351d55 --- /dev/null +++ b/rdadmin/edit_feed.h @@ -0,0 +1,129 @@ + +// edit_feed.h +// +// Edit a Rivendell Feed +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: edit_feed.h,v 1.9 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_FEED_H +#define EDIT_FEED_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +class EditFeed : public QDialog +{ + Q_OBJECT + public: + EditFeed(const QString &feed,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void purgeUrlChangedData(const QString &str); + void purgeUsernameChangedData(const QString &username); + void setFormatData(); + void normalizeCheckData(bool state); + void editData(); + void redirectToggledData(bool state); + void okData(); + void cancelData(); + + protected: + void paintEvent(QPaintEvent *e); + + private: + void RedirectChanged(bool state); + RDFeed *feed_feed; + QLineEdit *feed_keyname_edit; + QLineEdit *feed_channel_title_edit; + QTextEdit *feed_channel_description_edit; + QLineEdit *feed_channel_category_edit; + QLineEdit *feed_channel_link_edit; + QLineEdit *feed_channel_copyright_edit; + QLineEdit *feed_channel_webmaster_edit; + QLineEdit *feed_channel_language_edit; + QLineEdit *feed_base_url_edit; + QLineEdit *feed_base_preamble_edit; + QLineEdit *feed_purge_url_edit; + QLabel *feed_purge_username_label; + QLineEdit *feed_purge_username_edit; + QLabel *feed_purge_password_label; + QLineEdit *feed_purge_password_edit; + QTextEdit *feed_header_xml_edit; + QTextEdit *feed_channel_xml_edit; + QTextEdit *feed_item_xml_edit; + QSpinBox *feed_max_shelf_life_spin; + QCheckBox *feed_autopost_box; + QCheckBox *feed_keep_metadata_box; + RDSettings feed_settings; + QLineEdit *feed_format_edit; + QCheckBox *feed_normalize_box; + QLabel *feed_normalize_label; + QSpinBox *feed_normalize_spin; + QLineEdit *feed_extension_edit; + QComboBox *feed_castorder_box; + QComboBox *feed_media_link_mode_box; + QCheckBox *feed_redirect_check; + QLabel *feed_redirect_label; + QLineEdit *feed_redirect_edit; + QPushButton *feed_format_button; + QPushButton *feed_metadata_button; + + QLabel *feed_channel_title_label; + QLabel *feed_channel_category_label; + QLabel *feed_channel_link_label; + QLabel *feed_channel_copyright_label; + QLabel *feed_channel_webmaster_label; + QLabel *feed_channel_language_label; + QLabel *feed_channel_description_label; + QLabel *feed_base_url_label; + QLabel *feed_base_preamble_label; + QLabel *feed_purge_url_label; + QLabel *feed_max_shelf_life_label; + QLabel *feed_max_shelf_life_unit_label; + QLabel *feed_autopost_label; + QLabel *feed_keep_metadata_label; + QLabel *feed_format_label; + QLabel *feed_normalize_check_label; + QLabel *feed_normalize_unit_label; + QLabel *feed_castorder_label; + QLabel *feed_media_link_mode_label; + QLabel *feed_extension_label; + QLabel *feed_header_xml_label; + QLabel *feed_channel_xml_label; + QLabel *feed_item_xml_label; + QLabel *feed_channel_section_label; +}; + + +#endif // EDIT_FEED_H + diff --git a/rdadmin/edit_feed_perms.cpp b/rdadmin/edit_feed_perms.cpp new file mode 100644 index 00000000..f8031e10 --- /dev/null +++ b/rdadmin/edit_feed_perms.cpp @@ -0,0 +1,178 @@ +// edit_feed_perms.cpp +// +// Edit Rivendell RSS Feed Permissions +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_feed_perms.cpp,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +EditFeedPerms::EditFeedPerms(RDUser *user,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + + feed_user=user; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("User: ")+feed_user->name()); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Feeds Selector + // + feed_host_sel=new RDListSelector(this,"feed_host_sel"); + feed_host_sel->sourceSetLabel(tr("Available Feeds")); + feed_host_sel->destSetLabel(tr("Enabled Feeds")); + feed_host_sel->setGeometry(10,10,380,130); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + sql=QString().sprintf("select KEY_NAME from FEED_PERMS \ + where USER_NAME=\"%s\"", + (const char *)feed_user->name()); + + q=new RDSqlQuery(sql); + while(q->next()) { + feed_host_sel->destInsertItem(q->value(0).toString()); + } + delete q; + + sql=QString().sprintf("select KEY_NAME from FEEDS"); + q=new RDSqlQuery(sql); + while(q->next()) { + if(feed_host_sel->destFindItem(q->value(0).toString(),ExactMatch)==0) { + feed_host_sel->sourceInsertItem(q->value(0).toString()); + } + } + delete q; +} + + +EditFeedPerms::~EditFeedPerms() +{ +} + + +QSize EditFeedPerms::sizeHint() const +{ + return QSize(400,212); +} + + +QSizePolicy EditFeedPerms::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditFeedPerms::okData() +{ + RDSqlQuery *q; + QString sql; + + // + // Add New Groups + // + for(unsigned i=0;idestCount();i++) { + sql=QString().sprintf("select KEY_NAME from FEED_PERMS \ + where USER_NAME=\"%s\" && KEY_NAME=\"%s\"", + (const char *)feed_user->name(), + (const char *)feed_host_sel->destText(i)); + q=new RDSqlQuery(sql); + if(q->size()==0) { + delete q; + sql=QString(). + sprintf("insert into FEED_PERMS (USER_NAME,KEY_NAME) \ + values (\"%s\",\"%s\")", + (const char *)feed_user->name(), + (const char *)feed_host_sel->destText(i)); + q=new RDSqlQuery(sql); + } + delete q; + } + + // + // Delete Old Groups + // + sql=QString().sprintf("delete from FEED_PERMS where USER_NAME=\"%s\"", + (const char *)feed_user->name()); + for(unsigned i=0;idestCount();i++) { + sql+=QString().sprintf(" && KEY_NAME<>\"%s\"", + (const char *)feed_host_sel->destText(i)); + } + q=new RDSqlQuery(sql); + delete q; + done(0); +} + + +void EditFeedPerms::cancelData() +{ + done(1); +} diff --git a/rdadmin/edit_feed_perms.h b/rdadmin/edit_feed_perms.h new file mode 100644 index 00000000..5b9cf9bc --- /dev/null +++ b/rdadmin/edit_feed_perms.h @@ -0,0 +1,53 @@ +// edit_feed_perms.h +// +// Edit Rivendell RSS Feed Permissions +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_feed_perms.h,v 1.3 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_FEED_PERMS_H +#define EDIT_FEED_PERMS_H + +#include +#include +#include + +#include + + +class EditFeedPerms : public QDialog +{ + Q_OBJECT + public: + EditFeedPerms(RDUser *user,QWidget *parent=0,const char *name=0); + ~EditFeedPerms(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + RDListSelector *feed_host_sel; + RDUser *feed_user; +}; + + +#endif + diff --git a/rdadmin/edit_gpi.cpp b/rdadmin/edit_gpi.cpp new file mode 100644 index 00000000..8e34aa6f --- /dev/null +++ b/rdadmin/edit_gpi.cpp @@ -0,0 +1,336 @@ +// edit_gpi.cpp +// +// Edit a Rivendell Gpi +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_gpi.cpp,v 1.17.8.1 2012/11/26 20:19:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include + +#include +#include + + +EditGpi::EditGpi(int gpi,int *oncart,QString *ondesc, + int *offcart,QString *offdesc, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString str; + + edit_gpi=gpi; + edit_oncart=oncart; + edit_offcart=offcart; + edit_ondescription=ondesc; + edit_offdescription=offdesc; + str=QString(tr("Edit GPI")); + setCaption(QString().sprintf("%s %d",(const char *)str,gpi)); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont label_font=QFont("Helvetica",14,QFont::Bold); + label_font.setPixelSize(14); + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // On Section Label + // + QLabel *label=new QLabel("ON Transition",this); + label->setGeometry(30,10,120,20); + label->setFont(label_font); + label->setAlignment(AlignCenter); + + // + // On Cart Macro Cart + // + edit_onmacro_edit=new QLineEdit(this,"edit_onmacro_edit"); + edit_onmacro_edit->setGeometry(120,30,60,20); + edit_onmacro_edit->setFont(font); + edit_onmacro_edit->setValidator(validator); + label=new QLabel(tr("Cart Number: "),this,"edit_macro_label"); + label->setGeometry(15,30,100,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // On Select Button + // + QPushButton *button=new QPushButton(this,"select_button"); + button->setGeometry(190,30,60,20); + button->setFont(font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectOnData())); + + // + // On Clear Button + // + button=new QPushButton(this,"select_button"); + button->setGeometry(270,30,60,20); + button->setFont(font); + button->setText(tr("C&lear")); + connect(button,SIGNAL(clicked()),this,SLOT(clearOnData())); + + // + // On Cart Description + // + edit_ondescription_edit=new QLineEdit(this,"edit_ondescription_edit"); + edit_ondescription_edit->setGeometry(120,52,sizeHint().width()-140,20); + edit_ondescription_edit->setFont(font); + edit_ondescription_edit->setReadOnly(true); + label=new QLabel(tr("Description: "),this,"edit_ondescription_label"); + label->setGeometry(15,52,100,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Off Section Label + // + label=new QLabel("OFF Transition",this); + label->setGeometry(30,90,120,20); + label->setFont(label_font); + label->setAlignment(AlignCenter); + + // + // Off Cart Macro Cart + // + edit_offmacro_edit=new QLineEdit(this,"edit_offmacro_edit"); + edit_offmacro_edit->setGeometry(120,110,60,20); + edit_offmacro_edit->setFont(font); + edit_offmacro_edit->setValidator(validator); + label=new QLabel(tr("Cart Number: "),this,"edit_macro_label"); + label->setGeometry(15,110,100,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Off Select Button + // + button=new QPushButton(this,"select_button"); + button->setGeometry(190,110,60,20); + button->setFont(font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectOffData())); + + // + // Off Clear Button + // + button=new QPushButton(this,"select_button"); + button->setGeometry(270,110,60,20); + button->setFont(font); + button->setText(tr("C&lear")); + connect(button,SIGNAL(clicked()),this,SLOT(clearOffData())); + + // + // Off Cart Description + // + edit_offdescription_edit=new QLineEdit(this,"edit_offdescription_edit"); + edit_offdescription_edit->setGeometry(120,132,sizeHint().width()-140,20); + edit_offdescription_edit->setFont(font); + edit_offdescription_edit->setReadOnly(true); + label=new QLabel(tr("Description: "),this,"edit_offdescription_label"); + label->setGeometry(15,132,100,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Data + // + if(*edit_oncart>0) { + RDCart *rdcart=new RDCart(*oncart); + edit_onmacro_edit->setText(QString().sprintf("%06d",*oncart)); + edit_ondescription_edit->setText(rdcart->title()); + delete rdcart; + } + if(*edit_offcart>0) { + RDCart *rdcart=new RDCart(*offcart); + edit_offmacro_edit->setText(QString().sprintf("%06d",*offcart)); + edit_offdescription_edit->setText(rdcart->title()); + delete rdcart; + } +} + + +QSize EditGpi::sizeHint() const +{ + return QSize(420,230); +} + + +QSizePolicy EditGpi::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditGpi::selectOnData() +{ + int oncart=edit_onmacro_edit->text().toInt(); + if(admin_cart_dialog->exec(&oncart,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + if(oncart>0) { + RDCart *rdcart=new RDCart(oncart); + edit_onmacro_edit->setText(QString().sprintf("%06d",oncart)); + edit_ondescription_edit->setText(rdcart->title()); + delete rdcart; + } + else { + edit_onmacro_edit->setText(""); + edit_ondescription_edit->clear(); + } + } +} + + +void EditGpi::clearOnData() +{ + edit_ondescription_edit->clear(); + edit_onmacro_edit->clear(); +} + + +void EditGpi::selectOffData() +{ + int offcart=edit_offmacro_edit->text().toInt(); + if(admin_cart_dialog->exec(&offcart,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + if(offcart>0) { + RDCart *rdcart=new RDCart(offcart); + edit_offmacro_edit->setText(QString().sprintf("%06d",offcart)); + edit_offdescription_edit->setText(rdcart->title()); + delete rdcart; + } + else { + edit_offmacro_edit->setText(""); + edit_offdescription_edit->clear(); + } + } +} + + +void EditGpi::clearOffData() +{ + edit_offdescription_edit->clear(); + edit_offmacro_edit->clear(); +} + + +void EditGpi::okData() +{ + bool ok; + if(!edit_onmacro_edit->text().isEmpty()) { + int oncart=edit_onmacro_edit->text().toInt(&ok); + if(ok) { + *edit_oncart=oncart; + RDCart *rdcart=new RDCart(oncart); + *edit_ondescription=rdcart->title(); + delete rdcart; + done(0); + } + else { + QMessageBox::warning(this,tr("Invalid Cart"),tr("Invalid Cart Number!")); + } + } + else { + *edit_oncart=-1; + *edit_ondescription=""; + } + if(!edit_offmacro_edit->text().isEmpty()) { + int offcart=edit_offmacro_edit->text().toInt(&ok); + if(ok) { + *edit_offcart=offcart; + RDCart *rdcart=new RDCart(offcart); + *edit_offdescription=rdcart->title(); + delete rdcart; + done(0); + } + else { + QMessageBox::warning(this,tr("Invalid Cart"),tr("Invalid Cart Number!")); + } + } + else { + *edit_offcart=-1; + *edit_offdescription=""; + } + done(0); +} + + +void EditGpi::cancelData() +{ + done(-1); +} + + +void EditGpi::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->moveTo(10,20); + p->lineTo(sizeHint().width()-10,20); + p->lineTo(sizeHint().width()-10,82); + p->lineTo(10,82); + p->lineTo(10,20); + + p->moveTo(10,100); + p->lineTo(sizeHint().width()-10,100); + p->lineTo(sizeHint().width()-10,162); + p->lineTo(10,162); + p->lineTo(10,100); + + delete p; +} diff --git a/rdadmin/edit_gpi.h b/rdadmin/edit_gpi.h new file mode 100644 index 00000000..722923f4 --- /dev/null +++ b/rdadmin/edit_gpi.h @@ -0,0 +1,71 @@ +// edit_gpi.h +// +// Edit a Rivendell GPI +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_gpi.h,v 1.8 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_GPI_H +#define EDIT_GPI_H + +#include +#include +#include +#include +#include +#include + +#include +#include + + +class EditGpi : public QDialog +{ + Q_OBJECT + public: + EditGpi(int gpi,int *oncart,QString *ondesc,int *offcart,QString *offdesc, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void selectOnData(); + void clearOnData(); + void selectOffData(); + void clearOffData(); + void okData(); + void cancelData(); + + private: + void paintEvent(QPaintEvent *e); + int edit_gpi; + int *edit_oncart; + QLineEdit *edit_ondescription_edit; + QLineEdit *edit_onmacro_edit; + int *edit_offcart; + QLineEdit *edit_offdescription_edit; + QLineEdit *edit_offmacro_edit; + QString edit_filter; + QString edit_group; + QString *edit_ondescription; + QString *edit_offdescription; +}; + + +#endif // EDIT_GPI + diff --git a/rdadmin/edit_group.cpp b/rdadmin/edit_group.cpp new file mode 100644 index 00000000..2b38c72a --- /dev/null +++ b/rdadmin/edit_group.cpp @@ -0,0 +1,492 @@ +// edit_group.cpp +// +// Edit a Rivendell Group +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_group.cpp,v 1.27.8.1 2013/01/07 13:50:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +EditGroup::EditGroup(QString group,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + group_group=new RDGroup(group); + + setCaption(tr("Group: ")+group); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Group Name + // + group_name_edit=new QLineEdit(this,"group_name_edit"); + group_name_edit->setGeometry(165,11,100,19); + group_name_edit->setMaxLength(10); + group_name_edit->setReadOnly(true); + QLabel *group_name_label=new QLabel(group_name_edit,tr("&Group Name:"),this, + "group_name_label"); + group_name_label->setGeometry(10,11,150,19); + group_name_label->setFont(font); + group_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Group Description + // + group_description_edit=new QLineEdit(this,"group_description_edit"); + group_description_edit->setGeometry(165,32,sizeHint().width()-175,19); + group_description_edit->setMaxLength(255); + group_description_edit->setValidator(validator); + QLabel *group_description_label=new QLabel(group_description_edit, + tr("Group &Description:"),this, + "group_description_label"); + group_description_label->setGeometry(10,32,150,19); + group_description_label->setFont(font); + group_description_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Default Title + // + group_title_edit=new QLineEdit(this,"group_title_edit"); + group_title_edit->setGeometry(165,53,sizeHint().width()-175,19); + group_title_edit->setMaxLength(255); + group_title_edit->setValidator(validator); + QLabel *group_title_label=new QLabel(group_title_edit, + tr("Default Import &Title:"),this, + "group_title_label"); + group_title_label->setGeometry(10,53,150,19); + group_title_label->setFont(font); + group_title_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Default Cart Type + // + group_carttype_box=new QComboBox(this,"group_carttype_box"); + group_carttype_box->setGeometry(165,74,100,19); + group_carttype_box->insertItem(tr("Audio")); + group_carttype_box->insertItem(tr("Macro")); + QLabel *group_carttype_label=new QLabel(group_carttype_box, + tr("Default Cart &Type:"),this, + "group_carttype_label"); + group_carttype_label->setGeometry(10,74,150,19); + group_carttype_label->setFont(font); + group_carttype_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Default Cart Numbers + // + group_lowcart_box=new QSpinBox(this,"group_lowcart_box"); + group_lowcart_box->setGeometry(165,95,70,19); + group_lowcart_box->setRange(0,999999); + group_lowcart_box->setSpecialValueText(tr("None")); + QLabel *label=new QLabel(group_lowcart_box, + tr("Default Cart Number:"),this, + "group_lowcart_label"); + label->setGeometry(10,95,150,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + group_highcart_box=new QSpinBox(this,"group_highcart_box"); + group_highcart_box->setGeometry(265,95,70,19); + group_highcart_box->setRange(1,999999); + group_highcart_label=new QLabel(group_highcart_box, + tr("to"),this, + "group_highcart_label"); + group_highcart_label->setGeometry(240,95,20,19); + group_highcart_label->setFont(font); + group_highcart_label->setAlignment(AlignCenter|ShowPrefix); + connect(group_lowcart_box,SIGNAL(valueChanged(int)), + this,SLOT(lowCartChangedData(int))); + + // + // Enforce Cart Range Checkbox + // + group_enforcerange_box=new QCheckBox(this,"group_enforcerange_box"); + group_enforcerange_box->setGeometry(20,118,15,15); + group_enforcerange_label= + new QLabel(group_enforcerange_box,tr("Enforce Cart Range"), + this,"group_enforcerange_label"); + group_enforcerange_label->setGeometry(40,118,sizeHint().width()-50,19); + group_enforcerange_label->setFont(font); + group_enforcerange_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Traffic Report Checkbox + // + group_traffic_check=new QCheckBox(this,"group_traffic_check"); + group_traffic_check->setGeometry(20,145,15,15); + label= + new QLabel(group_traffic_check,tr("Include this group in Traffic reports"), + this,"group_traffic_label"); + label->setGeometry(40,143,sizeHint().width()-50,19); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Music Report Checkbox + // + group_music_check=new QCheckBox(this,"group_music_check"); + group_music_check->setGeometry(20,166,15,15); + label=new QLabel(group_music_check,tr("Include this group in Music reports"), + this,"group_music_label"); + label->setGeometry(40,164,sizeHint().width()-50,19); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Cut Auto Purging + // + group_shelflife_check=new QCheckBox(this,"group_shelflife_check"); + group_shelflife_check->setGeometry(20,193,15,15); + connect(group_shelflife_check,SIGNAL(toggled(bool)), + this,SLOT(purgeEnabledData(bool))); + group_shelflife_spin=new QSpinBox(this,"group_shelflife_spin"); + group_shelflife_spin->setGeometry(200,191,40,19); + group_shelflife_spin->setRange(0,30); + group_shelflife_label= + new QLabel(group_shelflife_check,tr("Purge expired cuts after"), + this,"group_shelflife_label"); + group_shelflife_label->setGeometry(40,193,160,19); + group_shelflife_label->setFont(font); + group_shelflife_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + group_shelflife_unit= + new QLabel(group_shelflife_check,tr("days"),this,"group_shelflife_unit"); + group_shelflife_unit->setGeometry(250,193,50,19); + group_shelflife_unit->setFont(font); + group_shelflife_unit->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + group_delete_carts_check=new QCheckBox(this); + group_delete_carts_check->setGeometry(40,214,15,15); + group_delete_carts_label= + new QLabel(group_delete_carts_check,tr("Delete cart if empty"),this); + group_delete_carts_label->setGeometry(60,214,160,19); + group_delete_carts_label->setFont(font); + group_delete_carts_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Now & Next Data Checkbox + // + group_nownext_check=new QCheckBox(this,"group_nownext_check"); + group_nownext_check->setGeometry(20,242,15,15); + label=new QLabel(group_nownext_check,tr("Transmit Now && Next data"), + this,"group_nownext_label"); + label->setGeometry(40,241,sizeHint().width()-50,19); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Services Selector + // + group_svcs_sel=new RDListSelector(this,"group_svcs_sel"); + group_svcs_sel->setGeometry(10,261,380,130); + + // + // Color Button + // + group_color_button=new QPushButton(this,"group_colorbutton"); + group_color_button->setGeometry(10,sizeHint().height()-60,80,50); + group_color_button->setFont(font); + group_color_button->setText(tr("C&olor")); + connect(group_color_button,SIGNAL(clicked()),this,SLOT(colorData())); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + group_name_edit->setText(group_group->name()); + group_description_edit->setText(group_group->description()); + group_title_edit->setText(group_group->defaultTitle()); + group_carttype_box->setCurrentItem(group_group->defaultCartType()-1); + group_lowcart_box->setValue(group_group->defaultLowCart()); + group_highcart_box->setValue(group_group->defaultHighCart()); + lowCartChangedData(group_group->defaultLowCart()); + group_enforcerange_box->setChecked(group_group->enforceCartRange()); + group_traffic_check->setChecked(group_group->exportReport(RDGroup::Traffic)); + group_music_check->setChecked(group_group->exportReport(RDGroup::Music)); + if(group_group->cutShelflife()>=0) { + group_shelflife_spin->setValue(group_group->cutShelflife()); + group_shelflife_check->setChecked(true); + group_delete_carts_check->setChecked(group_group->deleteEmptyCarts()); + } + purgeEnabledData(group_shelflife_check->isChecked()); + group_nownext_check->setChecked(group_group->enableNowNext()); + sql=QString().sprintf("select SERVICE_NAME from AUDIO_PERMS \ + where GROUP_NAME=\"%s\"", + (const char *)group_group->name()); + q=new RDSqlQuery(sql); + while(q->next()) { + group_svcs_sel->destInsertItem(q->value(0).toString()); + } + delete q; + + sql=QString().sprintf("select NAME from SERVICES"); + q=new RDSqlQuery(sql); + while(q->next()) { + if(group_svcs_sel->destFindItem(q->value(0).toString())==0) { + group_svcs_sel->sourceInsertItem(q->value(0).toString()); + } + } + delete q; + SetButtonColor(group_group->color()); +} + + +EditGroup::~EditGroup() +{ + delete group_name_edit; + delete group_description_edit; + delete group_svcs_sel; +} + + +QSize EditGroup::sizeHint() const +{ + return QSize(400,472); +} + + +QSizePolicy EditGroup::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditGroup::lowCartChangedData(int value) +{ + if(value==0) { + group_highcart_box->setRange(0,0); + group_highcart_label->setDisabled(true); + group_highcart_box->setDisabled(true); + group_enforcerange_box->setDisabled(true); + group_enforcerange_label->setDisabled(true); + } + else { + group_highcart_label->setEnabled(true); + group_highcart_box->setEnabled(true); + group_highcart_box->setRange(value,999999); + group_enforcerange_box->setEnabled(true); + group_enforcerange_label->setEnabled(true); + } +} + + +void EditGroup::colorData() +{ + QColor color=QColorDialog::getColor(group_color_button-> + palette().color(QPalette::Active, + QColorGroup::ButtonText), + this,"color_dialog"); + if(color.isValid()) { + SetButtonColor(color); + } +} + + +void EditGroup::purgeEnabledData(bool state) +{ + group_shelflife_spin->setEnabled(state); + group_shelflife_unit->setEnabled(state); + group_delete_carts_check->setEnabled(state); + group_delete_carts_label->setEnabled(state); +} + + +void EditGroup::okData() +{ + RDSqlQuery *q; + QString sql; + + if(!CheckRange()) { + return; + } + + group_group->setDescription(group_description_edit->text()); + group_group->setDefaultTitle(group_title_edit->text()); + group_group-> + setDefaultCartType((RDCart::Type)(group_carttype_box->currentItem()+1)); + group_group->setDefaultLowCart(group_lowcart_box->value()); + group_group->setDefaultHighCart(group_highcart_box->value()); + if(group_lowcart_box->value()==0) { + group_group->setEnforceCartRange(false); + } + else { + group_group->setEnforceCartRange(group_enforcerange_box->isChecked()); + } + group_group-> + setExportReport(RDGroup::Traffic,group_traffic_check->isChecked()); + group_group->setExportReport(RDGroup::Music,group_music_check->isChecked()); + if(group_shelflife_check->isChecked()) { + group_group->setCutShelflife(group_shelflife_spin->value()); + group_group->setDeleteEmptyCarts(group_delete_carts_check->isChecked()); + } + else { + group_group->setCutShelflife(-1); + group_group->setDeleteEmptyCarts(false); + } + group_group->setEnableNowNext(group_nownext_check->isChecked()); + group_group->setColor(group_color_button-> + palette().color(QPalette::Active, + QColorGroup::ButtonText)); + + // + // Add New Services + // + for(unsigned i=0;idestCount();i++) { + sql=QString().sprintf("select SERVICE_NAME from AUDIO_PERMS \ +where GROUP_NAME=\"%s\" && SERVICE_NAME=\"%s\"", + (const char *)group_group->name(), + (const char *)group_svcs_sel->destText(i)); + q=new RDSqlQuery(sql); + if(q->size()==0) { + delete q; + sql=QString().sprintf("insert into AUDIO_PERMS (GROUP_NAME,SERVICE_NAME) \ +values (\"%s\",\"%s\")", + (const char *)group_group->name(), + (const char *)group_svcs_sel->destText(i)); + q=new RDSqlQuery(sql); + } + delete q; + } + + // + // Delete Old Services + // + sql=QString().sprintf("delete from AUDIO_PERMS where GROUP_NAME=\"%s\"", + (const char *)group_group->name()); + for(unsigned i=0;idestCount();i++) { + sql+=QString().sprintf(" && SERVICE_NAME<>\"%s\"", + (const char *)group_svcs_sel->destText(i)); + } + q=new RDSqlQuery(sql); + delete q; + + done(0); +} + + +void EditGroup::cancelData() +{ + done(-1); +} + + +bool EditGroup::CheckRange() +{ + if(group_lowcart_box->value()==0) { + return true; + } + + bool conflict_found=false; + QString sql; + RDSqlQuery *q; + QString msg= + tr("The selected cart range conflicts with the following groups:\n\n"); + + sql=QString().sprintf("select NAME,DEFAULT_LOW_CART,DEFAULT_HIGH_CART\ + from GROUPS where NAME!=\"%s\"", + (const char *)group_name_edit->text()); + q=new RDSqlQuery(sql); + while(q->next()) { + if(((group_lowcart_box->value()<=q->value(1).toInt())&& + (group_highcart_box->value()>=q->value(1).toInt()))|| + ((group_lowcart_box->value()<=q->value(2).toInt())&& + (group_highcart_box->value()>=q->value(2).toInt()))) { + msg+=QString().sprintf(" %s\n",(const char *)q->value(0).toString()); + conflict_found=true; + } + } + delete q; + + if(conflict_found) { + msg+=tr("\nDo you still want to save?"); + switch(QMessageBox::warning(this,"Conflict Found",msg, + QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + return false; + + default: + break; + } + } + return true; +} + + +void EditGroup::SetButtonColor(const QColor &color) +{ + QPalette p=group_color_button->palette(); + p.setColor(QColorGroup::ButtonText,color); + group_color_button->setPalette(p); +} diff --git a/rdadmin/edit_group.h b/rdadmin/edit_group.h new file mode 100644 index 00000000..df592ee7 --- /dev/null +++ b/rdadmin/edit_group.h @@ -0,0 +1,87 @@ +// edit_group.h +// +// Edit a Rivendell Group +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_group.h,v 1.16.8.1 2013/01/07 13:50:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_GROUP_H +#define EDIT_GROUP_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + +class EditGroup : public QDialog +{ + Q_OBJECT + public: + EditGroup(QString group,QWidget *parent=0,const char *name=0); + ~EditGroup(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void lowCartChangedData(int value); + void colorData(); + void purgeEnabledData(bool state); + void okData(); + void cancelData(); + + private: + void SetButtonColor(const QColor &color); + bool CheckRange(); + RDGroup *group_group; + QLineEdit *group_name_edit; + QLineEdit *group_description_edit; + QSpinBox *group_lowcart_box; + QLabel *group_highcart_label; + QSpinBox *group_highcart_box; + QLabel *group_enforcerange_label; + QCheckBox *group_enforcerange_box; + RDListSelector *group_svcs_sel; + QCheckBox *group_music_check; + QCheckBox *group_traffic_check; + QCheckBox *group_nownext_check; + QComboBox *group_carttype_box; + QPushButton *group_color_button; + QLineEdit *group_title_edit; + QSpinBox *group_shelflife_spin; + QCheckBox *group_shelflife_check; + QLabel *group_delete_carts_label; + QCheckBox *group_delete_carts_check; + QLabel *group_shelflife_label; + QLabel *group_shelflife_unit; +}; + + +#endif // EDIT_GROUP_H + diff --git a/rdadmin/edit_hostvar.cpp b/rdadmin/edit_hostvar.cpp new file mode 100644 index 00000000..71225795 --- /dev/null +++ b/rdadmin/edit_hostvar.cpp @@ -0,0 +1,165 @@ +// edit_hostvar.cpp +// +// Edit a Rivendell Workstation Configuration +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_hostvar.cpp,v 1.8 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +EditHostvar::EditHostvar(QString station,QString var,QString *varvalue, + QString *remark,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_varvalue=varvalue; + edit_remark=remark; + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + setCaption(tr("Edit Host Variable")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Variable Name + // + edit_name_edit=new QLineEdit(this,"edit_name_edit"); + edit_name_edit->setGeometry(125,11,120,19); + edit_name_edit->setReadOnly(true); + QLabel *label=new QLabel(edit_name_edit,tr("Variable Name:"), + this,"edit_name_label"); + label->setGeometry(10,11,110,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Variable Value + // + edit_varvalue_edit=new QLineEdit(this,"edit_varvalue_edit"); + edit_varvalue_edit->setGeometry(125,33,sizeHint().width()-135,19); + edit_varvalue_edit->setMaxLength(255); + label=new QLabel(edit_varvalue_edit,tr("Variable Value:"), + this,"edit_varvalue_label"); + label->setGeometry(10,33,110,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Remark + // + edit_remark_edit=new QLineEdit(this,"edit_remark_edit"); + edit_remark_edit->setGeometry(125,55,sizeHint().width()-135,19); + edit_remark_edit->setMaxLength(255); + label=new QLabel(edit_remark_edit,tr("Remark:"),this,"edit_remark_label"); + label->setGeometry(10,55,110,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Values + // + edit_name_edit->setText(var); + edit_varvalue_edit->setText(*varvalue); + edit_remark_edit->setText(*remark); +} + + +EditHostvar::~EditHostvar() +{ +} + + +QSize EditHostvar::sizeHint() const +{ + return QSize(385,150); +} + + +QSizePolicy EditHostvar::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditHostvar::okData() +{ + *edit_varvalue=edit_varvalue_edit->text(); + *edit_remark=edit_remark_edit->text(); + done(0); +} + + +void EditHostvar::cancelData() +{ + done(-1); +} + + diff --git a/rdadmin/edit_hostvar.h b/rdadmin/edit_hostvar.h new file mode 100644 index 00000000..679d28ad --- /dev/null +++ b/rdadmin/edit_hostvar.h @@ -0,0 +1,64 @@ +// edit_hostvar.h +// +// Edit a Rivendell Host Variable +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_hostvar.h,v 1.6 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_HOSTVAR_H +#define EDIT_HOSTVAR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +class EditHostvar : public QDialog +{ + Q_OBJECT + public: + EditHostvar(QString station,QString var,QString *varvalue,QString *remark, + QWidget *parent=0,const char *name=0); + ~EditHostvar(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *edit_name_edit; + QLineEdit *edit_varvalue_edit; + QLineEdit *edit_remark_edit; + QString *edit_varvalue; + QString *edit_remark; +}; + + +#endif + diff --git a/rdadmin/edit_hotkeys.cpp b/rdadmin/edit_hotkeys.cpp new file mode 100644 index 00000000..83e2c352 --- /dev/null +++ b/rdadmin/edit_hotkeys.cpp @@ -0,0 +1,495 @@ +// edit_hot_keys.cpp +// +// Edit the Hot Key Configuration for a Rivendell Workstation. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +EditHotkeys::EditHotkeys(const QString &station,const QString &module,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + + hotkey_conf=station; + hotkey_module=module; + station_hotkeys= new RDHotkeys(hotkey_conf,hotkey_module); + myhotkeylist = new RDHotKeyList(); + // + // Create Fonts + // + QFont normal_font=QFont("Helvetica",12,QFont::Normal); + normal_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont section_font=QFont("Helvetica",14,QFont::Bold); + section_font.setPixelSize(14); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Hot Key Configuration Label + // + setCaption(hotkey_module.upper()+" "+tr("Hot Key Configuration for")+" "+ + hotkey_conf); + + list_view=new QListView(this,"list_view"); + list_view->setGeometry(10,24,320,220); + QLabel *label=new QLabel(list_view,tr("Host Hot Key Configurations"), + this,"list_view_label"); + label->setFont(font); + label->setGeometry(14,5,sizeHint().width()-28,19); + //list_view->setItemMargin(5); + list_view->setSorting(-1); + list_view->addColumn(tr("Button / Function ")); + list_view->setColumnAlignment(0,AlignLeft|AlignVCenter); + list_view->addColumn(tr("KeyStroke")); + list_view->setColumnAlignment(1,AlignLeft|AlignVCenter); + list_view->setAllColumnsShowFocus(true); + + connect(list_view,SIGNAL(clicked(QListViewItem *,const QPoint &,int)), + this,SLOT(showCurrentKey())); + connect(list_view,SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this,SLOT(showCurrentKey())); + + + + // Keystroke Value field + keystroke = new QLineEdit(this); + keystroke->setFocusPolicy(QWidget::StrongFocus); + keystroke->setGeometry(sizeHint().width()-270,sizeHint().height()-210,200,35); + + + // Set Button + // + QPushButton *set_button = new QPushButton(this,"set_button"); + set_button->setGeometry(sizeHint().width()-290,sizeHint().height()-160,60,30); + set_button->setDefault(true); + set_button->setFont(font); + set_button->setText(tr("Set")); + connect(set_button,SIGNAL(clicked()), this, SLOT(SetButtonClicked()) ); + + // Clear Button + // + QPushButton *clear_button = new QPushButton(this,"clear_button"); + clear_button->setGeometry(sizeHint().width()-215,sizeHint().height()-160,60,30); + clear_button->setDefault(true); + clear_button->setFont(font); + clear_button->setText(tr("Clear")); + connect(clear_button,SIGNAL(clicked()), this, SLOT(clearCurrentItem()) ); + + // Clear All Hot Keys Button + // + QPushButton *clear_all_button = new QPushButton(this,"clear_all_button"); + clear_all_button->setGeometry(sizeHint().width()-140,sizeHint().height()-160,130,30); + clear_all_button->setDefault(true); + clear_all_button->setFont(font); + clear_all_button->setText(tr("Clear All Hotkeys")); + connect(clear_all_button,SIGNAL(clicked()), this,SLOT(clearAll_Hotkeys()) ); + + // Clone Host Drop Box + // + clone_from_host_box=new QComboBox(this,"clone_from_host_box"); + clone_from_host_box->setGeometry(sizeHint().width()-295,sizeHint().height()-110,130,30); + clone_from_host_label=new QLabel(clone_from_host_box,tr("Set From Host:"), + this,"clone_from_host_label"); + clone_from_host_label->setFont(font); + clone_from_host_label->setGeometry(sizeHint().width()-420,sizeHint().height()-110,120,30); + clone_from_host_label->setAlignment(AlignRight|AlignVCenter); + sql=QString().sprintf("select NAME from STATIONS"); + q=new RDSqlQuery(sql); + while(q->next()) { + clone_from_host_box->insertItem(q->value(0).toString()); + if (hotkey_conf == q->value(0).toString()) { + clone_from_host_box->setCurrentItem(clone_from_host_box->count()-1); + current_station_clone_item = clone_from_host_box->count()-1; + } + } + delete q; + connect (clone_from_host_box,SIGNAL(activated(const QString&)), + this,SLOT(Clone_RefreshList(const QString&))); + + // + // Save Button + // + QPushButton *save_button=new QPushButton(this,"save_button"); + save_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + save_button->setDefault(true); + save_button->setFont(font); + save_button->setText(tr("Save")); + connect(save_button,SIGNAL(clicked()),this,SLOT(save())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("Cancel")); + + + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancel())); + + keystrokecount=0; + AltKeyHit = false; + CtrlKeyHit = false; + + + RefreshList(); + +} + + +EditHotkeys::~EditHotkeys() +{ +} + + +QSize EditHotkeys::sizeHint() const +{ + return QSize(400,500); +} + + +QSizePolicy EditHotkeys::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + +void EditHotkeys::save() +{ + + QString sql; + RDSqlQuery *q; + + QListViewItemIterator *start; + + start = new QListViewItemIterator(list_view); + + QString stringlist [40][45]; // assumes no more than 40 entries... + int cur, top, i = 0; + while (start->current()) { + if (start->current()->text(1).isEmpty()) { + stringlist[i++][0] = QString(""); + } + else { + stringlist[i++][0] = QString().sprintf("%s", + (const char *) start->current()->text(1)); + } + ++(*start); + } + delete start; + + for ( top = 0; top < (i- 1) ; top++) { + for (cur = top + 1; cur < i; cur ++) { + if ( (strcmp(stringlist[top][0],stringlist[cur][0]) == 0) && + (!(stringlist[top][0].isEmpty()) ) ){ + QString str = tr(QString().sprintf( \ + "Duplicate Hotkey defined %s\n No Duplicates allowed.", + (const char *)stringlist[cur][0] )); + QMessageBox::warning(this,tr("Duplicate Entries"),str); + return; + } + } + } + + start = new QListViewItemIterator(list_view); + + while (start->current()) { + sql = QString().sprintf("UPDATE RDHOTKEYS SET KEY_VALUE = \"%s\" \ + WHERE KEY_LABEL = \"%s\" AND \ + STATION_NAME = \"%s\" AND \ + MODULE_NAME = \"%s\"", + (const char *)start->current()->text(1), + (const char *)start->current()->text(0), + (const char *)hotkey_conf, + (const char *)hotkey_module); + q=new RDSqlQuery(sql); + delete q; + ++(*start); + } + + delete start; + delete station_hotkeys; + done(0); +} + +void EditHotkeys::SetHotKey() +{ + + QListViewItem *item=list_view->selectedItem(); + if (item==NULL) return; + + item->setText(1,hotkeystrokes); + keyupdated = true; +} + +void EditHotkeys::clearAll_Hotkeys() +{ + switch(QMessageBox::warning(this,tr("Hotkeys Clear"), + "Are you sure - This will Clear All Hot Key Settings!", + QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + return; + default: + break; + } + + QListViewItem *l = list_view->firstChild(); + while (l) { + l->setText(1,""); + l = l->nextSibling(); + } + keystroke->setText(""); + keystroke->setFocus(); + hotkeystrokes=QString(""); + keystrokecount=0; + keyupdated = true; +} + + + +void EditHotkeys::cancel() +{ + if (keyupdated) { + switch(QMessageBox::warning(this,tr("Hotkeys Updated"), + "Are you sure - All Hot Keys changes will be Lost!", + QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + return; + default: + break; + } + } + close(); +} + +void EditHotkeys::keyPressEvent (QKeyEvent *e) +{ + if ( (e->key() == Qt::Key_Backspace) || + (e->key() == Qt::Key_Delete) ) { + keystroke->setText(""); + keystroke->setFocus(); + hotkeystrokes=QString(""); + keystrokecount=0; + return; + } + + if (e->key() == Qt::Key_Alt) { + keystrokecount++; + AltKeyHit = true; + } + + if (e->key() == Qt::Key_Control) { + keystrokecount++; + CtrlKeyHit = true; + } + +} + +void EditHotkeys::keyReleaseEvent (QKeyEvent *e) +{ + int keyhit = e->key(); + QString mystring=(*myhotkeylist).GetKeyCode(keyhit); + + if (mystring.length() == 0 ) { // should never happen unless shell got it... + keystroke->setFocus(); + keystroke->setText(""); + hotkeystrokes=QString(""); + keystrokecount = 0; + AltKeyHit = false; + CtrlKeyHit = false; + return; + } + + if ( (e->key() == Qt::Key_Backspace) || + (e->key() == Qt::Key_Space) || + (e->key() == Qt::Key_Delete) ) { + keystroke->setFocus(); + keystroke->setText(""); + hotkeystrokes=QString(""); + keystrokecount = 0; + return; + } + + if (e->key() == Qt::Key_Shift) { + QWidget::keyReleaseEvent(e); + return; + } + + if ( (e->key() == Qt::Key_Up) || (e->key() == Qt::Key_Left) || + (e->key() == Qt::Key_Right) || (e->key() == Qt::Key_Down) ) { + QWidget::keyReleaseEvent(e); + keystrokecount = 0; + hotkeystrokes = QString (""); + keystroke->setText(""); + return; + } + + if ( (e->key() == Qt::Key_Tab) || (e->key() == Qt::Key_Left) || + (e->key() == Qt::Key_Right) ){ + QWidget::keyReleaseEvent(e); + keystrokecount = 0; + hotkeystrokes = QString (""); + keystroke->setText(""); + return; + } + + if ((e->key() == Qt::Key_Alt) || + (e->key() == Qt::Key_Control)) { + if (keystrokecount != 0 ) hotkeystrokes = QString (""); + if (AltKeyHit) { + AltKeyHit = false; + if (keystrokecount > 0) keystrokecount--; + } + if (CtrlKeyHit) { + CtrlKeyHit = false; + if (keystrokecount > 0) keystrokecount--; + } + keystroke->setText(QString().sprintf("%s",(const char *)hotkeystrokes)); + return; + } + if (keystrokecount > 2) { + keystroke->setText(QString().sprintf("%s",(const char *)hotkeystrokes)); + return; + } + + if (!e->isAutoRepeat()) { + if (keystrokecount == 0) + hotkeystrokes = QString (""); + if (AltKeyHit) { + hotkeystrokes = (*myhotkeylist).GetKeyCode(Qt::Key_Alt); + hotkeystrokes += QString(" + "); + } + if (CtrlKeyHit) { + if (AltKeyHit) { + hotkeystrokes += (*myhotkeylist).GetKeyCode(Qt::Key_Control); + hotkeystrokes += QString (" + "); + } + else { + hotkeystrokes = (*myhotkeylist).GetKeyCode(Qt::Key_Control); + hotkeystrokes += QString (" + "); + } + } + + hotkeystrokes += mystring; + keystroke->setText(QString().sprintf("%s",(const char *)hotkeystrokes)); + keystrokecount = 0; + return; + } +} + +void EditHotkeys::RefreshList() +{ + + station_hotkeys= new RDHotkeys(hotkey_conf,hotkey_module); + + QString sql; + RDSqlQuery *q; + QListViewItem *l; + list_view->clear(); + + keyupdated = false; + + // Build Rows of List View I do this in reverse... + + sql=QString().sprintf("select KEY_LABEL , KEY_VALUE from RDHOTKEYS \ + where STATION_NAME = \"%s\" AND \ + MODULE_NAME = \"%s\" \ + ORDER BY KEY_ID DESC", + (const char *)hotkey_conf, + (const char *)hotkey_module); + + q=new RDSqlQuery(sql); + while(q->next()) { + l=new QListViewItem(list_view); + l->setText(0,q->value(0).toString()); + l->setText(1,q->value(1).toString()); + } + delete q; +} + +void EditHotkeys::Clone_RefreshList(const QString& clone_station) +{ + QString sql; + RDSqlQuery *q; + + QString tmp_hotkey_conf = QString().sprintf("%s", + (const char *)clone_station); + RDHotkeys *tmp_station_hotkeys= new RDHotkeys(tmp_hotkey_conf,hotkey_module); + keyupdated = true; + QListViewItem *l; + list_view->clear(); + + sql=QString().sprintf("select KEY_LABEL , KEY_VALUE from RDHOTKEYS \ + where STATION_NAME = \"%s\" AND \ + MODULE_NAME = \"%s\" \ + ORDER BY ID DESC", + (const char *)tmp_hotkey_conf, + (const char *)hotkey_module); + + q=new RDSqlQuery(sql); + while(q->next()) { + + l=new QListViewItem(list_view); + l->setText(0,q->value(0).toString()); + l->setText(1,q->value(1).toString()); + } + delete q; + hotkeystrokes = QString (""); + keystroke->setText(QString().sprintf("%s",(const char *)hotkeystrokes)); + delete tmp_station_hotkeys; +} + +void EditHotkeys::showCurrentKey() +{ + QListViewItem *item=list_view->selectedItem(); + if (item==NULL) return; + keystroke->setText((const char *)item->text(1)); + keystroke->displayText(); + hotkeystrokes=QString((const char *)item->text(1)); + return; +} + + +void EditHotkeys::clearCurrentItem() +{ + keystrokecount=0; + keystroke->setText(""); + keystroke->setFocus(); + hotkeystrokes=QString(""); + return; +} + +void EditHotkeys::SetButtonClicked() +{ + + QListViewItem *item=list_view->selectedItem(); + if (item==NULL) { + QMessageBox::warning(this,tr("No Items Selected"), + tr("Please Select an Item From the List")); + return; + } + SetHotKey(); + return; +} + diff --git a/rdadmin/edit_hotkeys.h b/rdadmin/edit_hotkeys.h new file mode 100644 index 00000000..94113c3f --- /dev/null +++ b/rdadmin/edit_hotkeys.h @@ -0,0 +1,84 @@ +// edit_hotkeys.h +// +// Edit the Hot Keys Configuration for a Workstation +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_HOTKEYS_H +#define EDIT_HOTKEYS_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +class EditHotkeys : public QDialog +{ + Q_OBJECT +public: + EditHotkeys(const QString &station,const QString &module,QWidget *parent,const char *name); + ~EditHotkeys(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; +public slots: + void SetHotKey( ); + void showCurrentKey( ); + void RefreshList( ); + void Clone_RefreshList(const QString &); + void SetButtonClicked( ); + void clearCurrentItem( ); + void clearAll_Hotkeys( ); +private slots: + void save(); + void cancel(); +protected: + void keyReleaseEvent(QKeyEvent *e); + void keyPressEvent(QKeyEvent *e); + QLineEdit *keystroke; +private: + void SetRow(const QString ¶m,QString value) const; + RDHotkeys *station_hotkeys; + QListView *list_view; + QString hotkeystrokes; + QString hotkey_conf; + QString hotkey_module; + + QLabel *clone_from_host_label; + QComboBox *clone_from_host_box; + QPushButton *set_button; + QPushButton *clear_button; + QPushButton *show_original_button; + QPushButton *clear_all_button; + QPushButton *save_button; + QPushButton *cancel_button; + int keystrokecount; + bool keyupdated; + bool AltKeyHit ; + bool CtrlKeyHit; + RDHotKeyList *myhotkeylist ; + int current_station_clone_item; +}; + +#endif + diff --git a/rdadmin/edit_jack.cpp b/rdadmin/edit_jack.cpp new file mode 100644 index 00000000..eb81d823 --- /dev/null +++ b/rdadmin/edit_jack.cpp @@ -0,0 +1,348 @@ +// edit_jack.cpp +// +// Edit a Rivendell Jack Configuration +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: edit_jack.cpp,v 1.1.4.4 2012/11/15 19:27:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + + +EditJack::EditJack(RDStation *station,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + + edit_station=station; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + setCaption(tr("JACK Configuration for ")+edit_station->name()); + + // + // Create Fonts + // + QFont normal_font=QFont("Helvetica",12,QFont::Normal); + normal_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Start JACK Server + // + edit_start_jack_box=new QCheckBox(this); + edit_start_jack_label= + new QLabel(edit_start_jack_box,tr("Start JACK Server"),this); + edit_start_jack_label->setFont(font); + edit_start_jack_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // JACK Server Name + // + edit_jack_server_name_edit=new QLineEdit(this); + edit_jack_server_name_label= + new QLabel(edit_jack_server_name_edit,tr("JACK Server Name:"),this); + edit_jack_server_name_label->setFont(font); + edit_jack_server_name_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // JACK Command Line + // + edit_jack_command_line_edit=new QLineEdit(this); + connect(edit_start_jack_box,SIGNAL(toggled(bool)), + this,SLOT(startJackData(bool))); + edit_jack_command_line_label= + new QLabel(edit_jack_command_line_edit,tr("JACK Command Line:"),this); + edit_jack_command_line_label->setFont(font); + edit_jack_command_line_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // JACK Client List + // + edit_jack_client_view=new RDListView(this); + edit_jack_client_label= + new QLabel(edit_jack_client_view,tr("JACK Clients to Start:"),this); + edit_jack_client_label->setFont(font); + edit_jack_client_view->setAllColumnsShowFocus(true); + edit_jack_client_view->setItemMargin(5); + edit_jack_client_view->addColumn(tr("Client")); + edit_jack_client_view->setColumnAlignment(0,Qt::AlignLeft); + edit_jack_client_view->addColumn(tr("Command Line")); + edit_jack_client_view->setColumnAlignment(1,Qt::AlignLeft); + connect(edit_jack_client_view,SIGNAL(doubleClicked(QListViewItem *, + const QPoint &,int)), + this,SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + // + // Add Button + // + edit_add_button=new QPushButton(this); + edit_add_button->setFont(font); + edit_add_button->setText(tr("&Add")); + connect(edit_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + edit_edit_button=new QPushButton(this); + edit_edit_button->setFont(font); + edit_edit_button->setText(tr("&Edit")); + connect(edit_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + edit_delete_button=new QPushButton(this); + edit_delete_button->setFont(font); + edit_delete_button->setText(tr("&Delete")); + connect(edit_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Ok Button + // + edit_ok_button=new QPushButton(this,"edit_ok_button"); + edit_ok_button->setDefault(true); + edit_ok_button->setFont(font); + edit_ok_button->setText(tr("&OK")); + connect(edit_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + edit_cancel_button=new QPushButton(this,"edit_cancel_button"); + edit_cancel_button->setFont(font); + edit_cancel_button->setText(tr("&Cancel")); + connect(edit_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + edit_start_jack_box->setChecked(edit_station->startJack()); + edit_jack_server_name_edit->setText(edit_station->jackServerName()); + edit_jack_command_line_edit->setText(edit_station->jackCommandLine()); + if(edit_jack_server_name_edit->text().isEmpty()) { + edit_jack_server_name_edit->setText(EDITJACK_DEFAULT_SERVERNAME); + } + startJackData(edit_station->startJack()); + + RefreshList(); +} + + +QSize EditJack::sizeHint() const +{ + return QSize(450,330); +} + + +QSizePolicy EditJack::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditJack::startJackData(bool state) +{ + edit_jack_command_line_label->setEnabled(state); + edit_jack_command_line_edit->setEnabled(state); +} + + +void EditJack::addData() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + RDListViewItem *item=NULL; + + sql=QString("insert into JACK_CLIENTS set ")+ + "STATION_NAME=\""+RDEscapeString(edit_station->name())+"\","+ + "DESCRIPTION=\"\",COMMAND_LINE=\"\""; + q=new RDSqlQuery(sql); + delete q; + sql="select last_insert_id() from JACK_CLIENTS"; + q=new RDSqlQuery(sql); + if(q->first()) { + item=new RDListViewItem(edit_jack_client_view); + item->setId(q->value(0).toInt()); + QString desc=tr("[New Client]"); + QString cmd=""; + EditJackClient *d=new EditJackClient(edit_station,this); + if(d->exec(&desc,&cmd)==0) { + item->setText(0,desc); + item->setText(1,cmd); + } + else { + sql=QString().sprintf("delete from JACK_CLIENTS where ID=%d",item->id()); + q1=new RDSqlQuery(sql); + delete q1; + delete item; + } + } + delete q; +} + + +void EditJack::editData() +{ + RDListViewItem *item=(RDListViewItem *)edit_jack_client_view->selectedItem(); + if(item==NULL) { + return; + } + QString desc=item->text(0); + QString cmd=item->text(1); + EditJackClient *d=new EditJackClient(edit_station,this); + if(d->exec(&desc,&cmd)==0) { + item->setText(0,desc); + item->setText(1,cmd); + } + delete d; +} + + +void EditJack::deleteData() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item=(RDListViewItem *)edit_jack_client_view->selectedItem(); + if(item==NULL) { + return; + } + if(QMessageBox::question(this,tr("RDAdmin - JACK Clients"), + tr("Are you sure you want to delete JACK Client")+ + " \""+item->text(0)+"\"?",QMessageBox::Yes, + QMessageBox::No)==QMessageBox::Yes) { + sql=QString().sprintf("delete from JACK_CLIENTS where ID=%d",item->id()); + q=new RDSqlQuery(sql); + delete q; + delete item; + } +} + + +void EditJack::doubleClickedData(QListViewItem *item,const QPoint &pt,int col) +{ + editData(); +} + + +void EditJack::okData() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item=NULL; + + edit_station->setStartJack(edit_start_jack_box->isChecked()); + if(edit_jack_server_name_edit->text()==EDITJACK_DEFAULT_SERVERNAME) { + edit_station->setJackServerName(""); + } + else { + edit_station->setJackServerName(edit_jack_server_name_edit->text()); + } + edit_station->setJackCommandLine(edit_jack_command_line_edit->text()); + item=(RDListViewItem *)edit_jack_client_view->firstChild(); + while(item!=NULL) { + sql=QString("update JACK_CLIENTS set DESCRIPTION=\"")+ + RDEscapeString(item->text(0))+"\",COMMAND_LINE=\""+ + RDEscapeString(item->text(1))+"\" where ID="+ + QString().sprintf("%d",item->id()); + q=new RDSqlQuery(sql); + delete q; + item=(RDListViewItem *)item->nextSibling(); + } + + done(0); +} + + +void EditJack::cancelData() +{ + done(-1); +} + + +void EditJack::resizeEvent(QResizeEvent *e) +{ + edit_start_jack_box->setGeometry(10,11,15,15); + edit_start_jack_label->setGeometry(30,10,sizeHint().width()-70,20); + + edit_jack_server_name_label->setGeometry(10,32,130,20); + edit_jack_server_name_edit->setGeometry(145,32,size().width()-155,20); + + edit_jack_command_line_label->setGeometry(10,54,130,20); + edit_jack_command_line_edit->setGeometry(145,54,size().width()-155,20); + + edit_jack_client_label->setGeometry(15,80,sizeHint().width()-28,20); + edit_jack_client_view-> + setGeometry(10,102,size().width()-20,size().height()-170); + + edit_add_button->setGeometry(15,size().height()-60,50,30); + edit_edit_button->setGeometry(75,size().height()-60,50,30); + edit_delete_button->setGeometry(135,size().height()-60,50,30); + + edit_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + edit_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void EditJack::RefreshList() +{ + RDListViewItem *l; + + edit_jack_client_view->clear(); + QString sql=QString(). + sprintf("select ID,DESCRIPTION,COMMAND_LINE from JACK_CLIENTS \ + where STATION_NAME=\"%s\" order by DESCRIPTION", + (const char *)edit_station->name()); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + l=new RDListViewItem(edit_jack_client_view); + l->setId(q->value(0).toInt()); + l->setText(0,q->value(1).toString()); + l->setText(1,q->value(2).toString()); + } + delete q; +} + diff --git a/rdadmin/edit_jack.h b/rdadmin/edit_jack.h new file mode 100644 index 00000000..bff8bfc3 --- /dev/null +++ b/rdadmin/edit_jack.h @@ -0,0 +1,79 @@ +// edit_jack.h +// +// Edit a Rivendell Jack Configuration +// +// (C) Copyright 2002-2011 Fred Gleason +// +// $Id: edit_jack.h,v 1.2.4.4 2012/11/15 19:27:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_JACK_H +#define EDIT_JACK_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define EDITJACK_DEFAULT_SERVERNAME QObject::tr("(default)") + +class EditJack : public QDialog +{ + Q_OBJECT + public: + EditJack(RDStation *station,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void startJackData(bool state); + void addData(); + void editData(); + void deleteData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void okData(); + void cancelData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshList(); + QLabel *edit_start_jack_label; + QCheckBox *edit_start_jack_box; + QLabel *edit_jack_server_name_label; + QLineEdit *edit_jack_server_name_edit; + QLabel *edit_jack_command_line_label; + QLineEdit *edit_jack_command_line_edit; + QLabel *edit_jack_client_label; + RDListView *edit_jack_client_view; + RDStation *edit_station; + QPushButton *edit_add_button; + QPushButton *edit_edit_button; + QPushButton *edit_delete_button; + QPushButton *edit_ok_button; + QPushButton *edit_cancel_button; +}; + + +#endif // EDIT_JACK_H diff --git a/rdadmin/edit_jack_client.cpp b/rdadmin/edit_jack_client.cpp new file mode 100644 index 00000000..1d7398ae --- /dev/null +++ b/rdadmin/edit_jack_client.cpp @@ -0,0 +1,138 @@ +// edit_jack_client.cpp +// +// Edit a Rivendell Jack Client Configuration +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: edit_jack_client.cpp,v 1.1.2.1 2012/11/14 02:24:23 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include + +EditJackClient::EditJackClient(RDStation *station, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + + edit_station=station; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + setCaption(tr("JACK Client Configuration for ")+edit_station->name()); + + // + // Create Fonts + // + QFont normal_font=QFont("Helvetica",12,QFont::Normal); + normal_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // JACK Client Description + // + edit_jack_description_edit=new QLineEdit(this); + edit_jack_description_label= + new QLabel(edit_jack_description_edit,tr("Description:"),this); + edit_jack_description_label->setFont(font); + edit_jack_description_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // JACK Client Description + // + edit_jack_command_line_edit=new QLineEdit(this); + edit_jack_command_line_label= + new QLabel(edit_jack_command_line_edit,tr("Command Line:"),this); + edit_jack_command_line_label->setFont(font); + edit_jack_command_line_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + edit_ok_button=new QPushButton(this,"edit_ok_button"); + edit_ok_button->setDefault(true); + edit_ok_button->setFont(font); + edit_ok_button->setText(tr("&OK")); + connect(edit_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + edit_cancel_button=new QPushButton(this,"edit_cancel_button"); + edit_cancel_button->setFont(font); + edit_cancel_button->setText(tr("&Cancel")); + connect(edit_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +QSize EditJackClient::sizeHint() const +{ + return QSize(450,130); +} + + +QSizePolicy EditJackClient::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int EditJackClient::exec(QString *desc,QString *cmd) +{ + edit_description=desc; + edit_jack_description_edit->setText(*desc); + edit_command_line=cmd; + edit_jack_command_line_edit->setText(*cmd); + return QDialog::exec(); +} + + +void EditJackClient::okData() +{ + *edit_description=edit_jack_description_edit->text(); + *edit_command_line=edit_jack_command_line_edit->text(); + done(0); +} + + +void EditJackClient::cancelData() +{ + done(-1); +} + + +void EditJackClient::resizeEvent(QResizeEvent *e) +{ + edit_jack_description_label->setGeometry(10,10,130,20); + edit_jack_description_edit->setGeometry(145,10,size().width()-155,20); + + edit_jack_command_line_label->setGeometry(10,32,130,20); + edit_jack_command_line_edit->setGeometry(145,32,size().width()-155,20); + + edit_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + edit_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} diff --git a/rdadmin/edit_jack_client.h b/rdadmin/edit_jack_client.h new file mode 100644 index 00000000..251e2efc --- /dev/null +++ b/rdadmin/edit_jack_client.h @@ -0,0 +1,65 @@ +// edit_jack_client.h +// +// Edit a Rivendell Jack Client Configuration +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: edit_jack_client.h,v 1.1.2.1 2012/11/14 02:24:23 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_JACK_CLIENT_H +#define EDIT_JACK_CLIENT_H + +#include +#include +#include +#include + +#include + +class EditJackClient : public QDialog +{ + Q_OBJECT + public: + EditJackClient(RDStation *station,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(QString *desc,QString *cmd); + + private slots: + void okData(); + void cancelData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshList(); + QLabel *edit_jack_description_label; + QLineEdit *edit_jack_description_edit; + QLabel *edit_jack_command_line_label; + QLineEdit *edit_jack_command_line_edit; + QPushButton *edit_ok_button; + QPushButton *edit_cancel_button; + QString *edit_description; + QString *edit_command_line; + RDStation *edit_station; +}; + + +#endif // EDIT_JACK_CLIENT_H diff --git a/rdadmin/edit_livewiregpio.cpp b/rdadmin/edit_livewiregpio.cpp new file mode 100644 index 00000000..8c7d0523 --- /dev/null +++ b/rdadmin/edit_livewiregpio.cpp @@ -0,0 +1,150 @@ +// edit_livewiregpio.cpp +// +// Edit a Rivendell Livewire GPIO Slot Association +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: edit_livewiregpio.cpp,v 1.1.2.3 2013/03/06 13:28:59 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include + +#include + +EditLiveWireGpio::EditLiveWireGpio(int slot,int *source,QHostAddress *addr, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_slot=slot; + edit_source=source; + edit_address=addr; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + setCaption(tr("Edit GPIO Source")); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // GPIO Lines + // + QLabel *label=new QLabel(tr("GPIO Lines")+ + QString().sprintf(" %d - %d",5*slot+1,5*slot+5),this); + label->setGeometry(10,10,sizeHint().width()-20,20); + label->setFont(bold_font); + label->setAlignment(Qt::AlignCenter); + + // + // Livewire Source Number + // + edit_source_number_spin=new QSpinBox(this); + edit_source_number_spin->setGeometry(130,32,60,20); + edit_source_number_spin->setRange(0,RD_LIVEWIRE_MAX_SOURCE); + edit_source_number_spin->setSpecialValueText(tr("None")); + label=new QLabel(tr("Livewire Source: "),this); + label->setGeometry(10,32,115,20); + label->setFont(bold_font); + label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); + + // + // Surface IP Address + // + edit_ip_address_edit=new QLineEdit(this); + edit_ip_address_edit->setGeometry(130,54,120,20); + label=new QLabel(tr("Surface Address: "),this); + label->setGeometry(10,54,115,20); + label->setFont(bold_font); + label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); + + // + // Ok Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Data + // + edit_source_number_spin->setValue(*edit_source); + if(!edit_address->isNull()) { + edit_ip_address_edit->setText(edit_address->toString()); + } +} + + +QSize EditLiveWireGpio::sizeHint() const +{ + return QSize(270,142); +} + + +QSizePolicy EditLiveWireGpio::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditLiveWireGpio::okData() +{ + QHostAddress addr; + + addr.setAddress(edit_ip_address_edit->text()); + if(addr.isNull()&&(!edit_ip_address_edit->text().isEmpty())&& + (edit_ip_address_edit->text()!="0.0.0.0")) { + QMessageBox::warning(this,"RDAdmin - "+tr("Invalid IP Address"), + tr("The IP address is invalid!")); + return; + } + *edit_source=edit_source_number_spin->value(); + edit_address->setAddress(addr.toString()); + + done(0); +} + + +void EditLiveWireGpio::cancelData() +{ + done(-1); +} diff --git a/rdadmin/edit_livewiregpio.h b/rdadmin/edit_livewiregpio.h new file mode 100644 index 00000000..858890f3 --- /dev/null +++ b/rdadmin/edit_livewiregpio.h @@ -0,0 +1,57 @@ +// edit_livewiregpio.h +// +// Edit a Rivendell Livewire GPIO Slot Association +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: edit_livewiregpio.h,v 1.1.2.2 2013/03/05 23:59:07 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_LIVEWIREGPIO_H +#define EDIT_LIVEWIREGPIO_H + +#include +#include +#include +#include + +#include + + +class EditLiveWireGpio : public QDialog +{ + Q_OBJECT + public: + EditLiveWireGpio(int slot,int *source,QHostAddress *addr, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + int edit_slot; + int *edit_source; + QHostAddress *edit_address; + QSpinBox *edit_source_number_spin; + QLineEdit *edit_ip_address_edit; +}; + + +#endif // EDIT_LIVEWIREGPIO + diff --git a/rdadmin/edit_matrix.cpp b/rdadmin/edit_matrix.cpp new file mode 100644 index 00000000..8cbe1eb2 --- /dev/null +++ b/rdadmin/edit_matrix.cpp @@ -0,0 +1,1377 @@ +// edit_matrix.cpp +// +// Edit a Rivendell Matrix +// +// (C) Copyright 2002-2012 Fred Gleason +// +// $Id: edit_matrix.cpp,v 1.36.6.5.2.1 2014/06/24 18:27:05 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "globals.h" +#include "edit_user.h" +#include "edit_matrix.h" +#include "list_endpoints.h" +#include "list_gpis.h" +#include "list_nodes.h" +#include "list_livewiregpios.h" +#include "list_vguest_resources.h" +#include "list_sas_resources.h" + +EditMatrix::EditMatrix(RDMatrix *matrix,QWidget *parent,const char *name) + : QDialog(parent,name) +{ + QString str; + + edit_matrix=matrix; + edit_stationname=matrix->station(); + edit_matrix_number=matrix->matrix(); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("RDAdmin - Edit Switcher")); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this); + + // + // Matrix Number + // + QLabel *label=new QLabel(QString().sprintf("%d",edit_matrix_number),this); + label->setGeometry(135,10,30,19); + label->setFont(font); + label=new QLabel(tr("Matrix Number:"),this); + label->setGeometry(10,10,120,19); + label->setFont(bold_font); + label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Matrix Type + // + label=new QLabel(RDMatrix::typeString(edit_matrix->type()),this); + label->setGeometry(135,30,200,19); + label->setFont(font); + label=new QLabel(tr("Switcher Type:"),this); + label->setGeometry(10,30,120,19); + label->setFont(bold_font); + label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Descriptive Name + // + edit_name_edit=new QLineEdit(this); + edit_name_edit->setGeometry(135,50,240,19); + edit_name_edit->setValidator(validator); + label=new QLabel(edit_name_edit,tr("Description:"),this); + label->setGeometry(10,50,120,19); + label->setFont(bold_font); + label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Primary Connection + // + label=new QLabel(tr("Primary Connection"),this); + label->setGeometry(20,74,130,20); + label->setFont(bold_font); + label->setAlignment(Qt::AlignCenter); + + // + // Primary Type + // + edit_porttype_box=new QComboBox(this); + edit_porttype_box->setGeometry(90,96,70,19); + edit_porttype_label=new QLabel(edit_porttype_box,tr("Type:"),this); + edit_porttype_label->setGeometry(15,96,70,19); + edit_porttype_label->setFont(bold_font); + edit_porttype_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + edit_porttype_box->insertItem(tr("Serial")); + edit_porttype_box->insertItem(tr("TCP/IP")); + connect(edit_porttype_box,SIGNAL(activated(int)), + this,SLOT(portTypeActivatedData(int))); + + // + // Primary Serial Port + // + edit_port_box=new QComboBox(this); + edit_port_box->setGeometry(290,96,90,19); + edit_port_box->setEditable(false); + edit_port_label= + new QLabel(edit_port_box,tr("Serial Port:"),this); + edit_port_label->setGeometry(195,96,90,19); + edit_port_label->setFont(bold_font); + edit_port_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Primary IP Address + // + edit_ipaddress_edit=new QLineEdit(this); + edit_ipaddress_edit->setGeometry(90,118,115,19); + edit_ipaddress_label=new QLabel(edit_ipaddress_edit,tr("IP Address:"),this); + edit_ipaddress_label->setGeometry(15,118,70,19); + edit_ipaddress_label->setFont(bold_font); + edit_ipaddress_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Primary IP Port + // + edit_ipport_spin=new QSpinBox(this); + edit_ipport_spin->setGeometry(290,118,65,19); + edit_ipport_spin->setRange(0,0xFFFF); + edit_ipport_label= + new QLabel(edit_ipport_spin,tr("IP Port:"),this); + edit_ipport_label->setGeometry(215,118,70,19); + edit_ipport_label->setFont(bold_font); + edit_ipport_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Primary Username + // + edit_username_edit=new QLineEdit(this); + edit_username_edit->setGeometry(90,140,115,19); + edit_username_label=new QLabel(edit_username_edit,tr("Username:"),this); + edit_username_label->setGeometry(15,140,70,19); + edit_username_label->setFont(bold_font); + edit_username_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Primary Password + // + edit_password_edit=new QLineEdit(this); + edit_password_edit->setGeometry(290,140,115,19); + edit_password_edit->setEchoMode(QLineEdit::Password); + edit_password_label=new QLabel(edit_password_edit,tr("Password:"),this); + edit_password_label->setGeometry(215,140,70,19); + edit_password_label->setFont(bold_font); + edit_password_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Primary Start Cart + // + edit_start_cart_edit=new QLineEdit(this); + edit_start_cart_edit->setGeometry(120,164,80,19); + edit_start_cart_label=new QLabel(edit_start_cart_edit,tr("Startup Cart:"), + this); + edit_start_cart_label->setGeometry(15,164,100,19); + edit_start_cart_label->setFont(bold_font); + edit_start_cart_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + edit_start_cart_button= + new QPushButton(tr("Select"),this); + edit_start_cart_button->setFont(font); + edit_start_cart_button->setGeometry(205,162,60,24); + connect(edit_start_cart_button,SIGNAL(clicked()),this,SLOT(startCartData())); + + // + // Primary Stop Cart + // + edit_stop_cart_edit=new QLineEdit(this); + edit_stop_cart_edit->setGeometry(120,188,80,19); + edit_stop_cart_label=new QLabel(edit_stop_cart_edit,tr("Shutdown Cart:"), + this); + edit_stop_cart_label->setGeometry(15,188,100,19); + edit_stop_cart_label->setFont(bold_font); + edit_stop_cart_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + edit_stop_cart_button=new QPushButton(tr("Select"),this); + edit_stop_cart_button->setFont(font); + edit_stop_cart_button->setGeometry(205,186,60,24); + connect(edit_stop_cart_button,SIGNAL(clicked()),this,SLOT(stopCartData())); + + // + // Backup Connection + // + label=new QLabel(tr("Backup Connection"),this); + label->setGeometry(20,221,130,20); + label->setFont(bold_font); + label->setAlignment(Qt::AlignCenter); + + // + // Backup Type + // + edit_porttype2_box=new QComboBox(this); + edit_porttype2_box->setGeometry(90,243,70,19); + edit_porttype2_label=new QLabel(edit_porttype2_box,tr("Type:"),this); + edit_porttype2_label->setGeometry(15,243,70,19); + edit_porttype2_label->setFont(bold_font); + edit_porttype2_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + edit_porttype2_box->insertItem(tr("Serial")); + edit_porttype2_box->insertItem(tr("TCP/IP")); + edit_porttype2_box->insertItem(tr("None")); + connect(edit_porttype2_box,SIGNAL(activated(int)), + this,SLOT(portType2ActivatedData(int))); + + // + // Backup Serial Port + // + edit_port2_box=new QComboBox(this); + edit_port2_box->setGeometry(290,243,90,19); + edit_port2_box->setEditable(false); + edit_port2_label= + new QLabel(edit_port2_box,tr("Serial Port:"),this); + edit_port2_label->setGeometry(195,243,90,19); + edit_port2_label->setFont(bold_font); + edit_port2_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Backup IP Address + // + edit_ipaddress2_edit=new QLineEdit(this); + edit_ipaddress2_edit->setGeometry(90,265,115,19); + edit_ipaddress2_label= + new QLabel(edit_ipaddress2_edit,tr("IP Address:"),this); + edit_ipaddress2_label->setGeometry(15,265,70,19); + edit_ipaddress2_label->setFont(bold_font); + edit_ipaddress2_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Backup IP Port + // + edit_ipport2_spin=new QSpinBox(this); + edit_ipport2_spin->setGeometry(290,265,65,19); + edit_ipport2_spin->setRange(0,0xFFFF); + edit_ipport2_label= + new QLabel(edit_ipport2_spin,tr("IP Port:"),this); + edit_ipport2_label->setGeometry(215,265,70,19); + edit_ipport2_label->setFont(bold_font); + edit_ipport2_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Backup Username + // + edit_username2_edit=new QLineEdit(this); + edit_username2_edit->setGeometry(90,288,115,19); + edit_username2_label=new QLabel(edit_username2_edit,tr("Username:"),this); + edit_username2_label->setGeometry(15,288,70,19); + edit_username2_label->setFont(bold_font); + edit_username2_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Backup Password + // + edit_password2_edit=new QLineEdit(this); + edit_password2_edit->setGeometry(290,288,115,19); + edit_password2_edit->setEchoMode(QLineEdit::Password); + edit_password2_label=new QLabel(edit_password2_edit,tr("Password:"),this); + edit_password2_label->setGeometry(215,288,70,19); + edit_password2_label->setFont(bold_font); + edit_password2_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Backup Start Cart + // + edit_start_cart2_edit=new QLineEdit(this); + edit_start_cart2_edit->setGeometry(120,312,80,19); + edit_start_cart2_label=new QLabel(edit_start_cart2_edit,tr("Startup Cart:"), + this); + edit_start_cart2_label->setGeometry(15,312,100,19); + edit_start_cart2_label->setFont(bold_font); + edit_start_cart2_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + edit_start_cart2_button=new QPushButton(tr("Select"),this); + edit_start_cart2_button->setFont(font); + edit_start_cart2_button->setGeometry(205,310,60,24); + connect(edit_start_cart2_button,SIGNAL(clicked()), + this,SLOT(startCart2Data())); + + // + // Backup Stop Cart + // + edit_stop_cart2_edit=new QLineEdit(this); + edit_stop_cart2_edit->setGeometry(120,336,80,19); + edit_stop_cart2_label=new QLabel(edit_stop_cart2_edit,tr("Shutdown Cart:"), + this); + edit_stop_cart2_label->setGeometry(15,336,100,19); + edit_stop_cart2_label->setFont(bold_font); + edit_stop_cart2_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + edit_stop_cart2_button=new QPushButton(tr("Select"),this); + edit_stop_cart2_button->setFont(font); + edit_stop_cart2_button->setGeometry(205,334,60,24); + connect(edit_stop_cart2_button,SIGNAL(clicked()),this,SLOT(stopCart2Data())); + + // + // Card Number + // + edit_card_box=new QSpinBox(this); + edit_card_box->setGeometry(75,371,50,19); + edit_card_box->setRange(0,RD_MAX_CARDS-1); + edit_card_label=new QLabel(edit_card_box,tr("Card:"),this); + edit_card_label->setGeometry(10,371,60,19); + edit_card_label->setFont(bold_font); + edit_card_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Inputs + // + edit_inputs_box=new QSpinBox(this); + edit_inputs_box->setGeometry(230,371,50,19); + edit_inputs_box->setRange(0,MAX_ENDPOINTS); + edit_inputs_label=new QLabel(edit_inputs_box,tr("Inputs:"),this); + edit_inputs_label->setGeometry(175,371,50,19); + edit_inputs_label->setFont(bold_font); + edit_inputs_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + connect(edit_inputs_box,SIGNAL(valueChanged(int)), + this,SLOT(inputsChangedData(int))); + + // + // Outputs + // + edit_outputs_box=new QSpinBox(this); + edit_outputs_box->setGeometry(355,371,50,19); + edit_outputs_box->setRange(0,MAX_ENDPOINTS); + edit_outputs_label=new QLabel(edit_outputs_box,tr("Outputs:"),this); + edit_outputs_label->setGeometry(280,371,70,19); + edit_outputs_label->setFont(bold_font); + edit_outputs_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Device + // + edit_device_edit=new QLineEdit(this); + edit_device_edit->setGeometry(75,396,90,19); + edit_device_edit->setValidator(validator); + edit_device_label=new QLabel(edit_device_edit,tr("Device:"),this); + edit_device_label->setGeometry(5,396,65,19); + edit_device_label->setFont(bold_font); + edit_device_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // GPIs + // + edit_gpis_box=new QSpinBox(this); + edit_gpis_box->setGeometry(230,396,50,19); + edit_gpis_box->setRange(0,MAX_GPIO_PINS); + edit_gpis_label=new QLabel(edit_gpis_box,tr("GPIs:"),this); + edit_gpis_label->setGeometry(175,396,50,19); + edit_gpis_label->setFont(bold_font); + edit_gpis_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + connect(edit_gpis_box,SIGNAL(valueChanged(int)), + this,SLOT(gpisChangedData(int))); + + // + // GPOs + // + edit_gpos_box=new QSpinBox(this); + edit_gpos_box->setGeometry(355,396,50,19); + edit_gpos_box->setRange(0,MAX_GPIO_PINS); + edit_gpos_label=new QLabel(edit_gpos_box,tr("GPOs:"),this); + edit_gpos_label->setGeometry(280,396,70,19); + edit_gpos_label->setFont(bold_font); + edit_gpos_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + connect(edit_gpos_box,SIGNAL(valueChanged(int)), + this,SLOT(gposChangedData(int))); + + // + // Layer + // + edit_layer_box=new QComboBox(this); + edit_layer_box->setGeometry(75,421,50,19); + edit_layer_label=new QLabel(edit_layer_box,tr("Layer:"),this); + edit_layer_label->setGeometry(10,421,60,19); + edit_layer_label->setFont(bold_font); + edit_layer_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + edit_layer_box->insertItem("V"); + edit_layer_box->insertItem("A"); + edit_layer_box->insertItem("B"); + edit_layer_box->insertItem("C"); + edit_layer_box->insertItem("D"); + edit_layer_box->insertItem("E"); + edit_layer_box->insertItem("F"); + edit_layer_box->insertItem("G"); + edit_layer_box->insertItem("H"); + edit_layer_box->insertItem("I"); + edit_layer_box->insertItem("J"); + edit_layer_box->insertItem("K"); + edit_layer_box->insertItem("L"); + edit_layer_box->insertItem("M"); + edit_layer_box->insertItem("N"); + edit_layer_box->insertItem("O"); + + // + // Displays + // + edit_displays_box=new QSpinBox(this); + edit_displays_box->setGeometry(355,421,50,19); + edit_displays_box->setRange(0,1024); + edit_displays_label=new QLabel(edit_displays_box,tr("Displays:"),this); + edit_displays_label->setGeometry(280,421,70,19); + edit_displays_label->setFont(bold_font); + edit_displays_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Configure Inputs Button + // + edit_inputs_button=new QPushButton(this); + edit_inputs_button->setGeometry(35,446,80,50); + edit_inputs_button->setFont(bold_font); + edit_inputs_button->setText(tr("Configure\n&Inputs")); + connect(edit_inputs_button,SIGNAL(clicked()),this,SLOT(inputsButtonData())); + + // + // Configure Outputs Button + // + edit_outputs_button=new QPushButton(this); + edit_outputs_button->setGeometry(125,446,80,50); + edit_outputs_button->setFont(bold_font); + edit_outputs_button->setText(tr("Configure\n&Outputs")); + connect(edit_outputs_button,SIGNAL(clicked()), + this,SLOT(outputsButtonData())); + + // + // Configure GPIs Button + // + edit_gpis_button=new QPushButton(this); + edit_gpis_button->setGeometry(215,446,80,50); + edit_gpis_button->setDefault(true); + edit_gpis_button->setFont(bold_font); + edit_gpis_button->setText(tr("Configure\n&GPIs")); + connect(edit_gpis_button,SIGNAL(clicked()),this,SLOT(gpisButtonData())); + + // + // Configure GPOs Button + // + edit_gpos_button=new QPushButton(this); + edit_gpos_button->setGeometry(305,446,80,50); + edit_gpos_button->setDefault(true); + edit_gpos_button->setFont(bold_font); + edit_gpos_button->setText(tr("Configure\nG&POs")); + connect(edit_gpos_button,SIGNAL(clicked()),this,SLOT(gposButtonData())); + + // + // LiveWire Nodes Button + // + edit_livewire_button=new QPushButton(this); + edit_livewire_button->setGeometry(35,506,80,50); + edit_livewire_button->setFont(bold_font); + edit_livewire_button->setText(tr("LiveWire\nNodes")); + connect(edit_livewire_button,SIGNAL(clicked()), + this,SLOT(livewireButtonData())); + + // + // Livewire GPIOs Button + // + edit_livewire_gpio_button=new QPushButton(this); + edit_livewire_gpio_button->setGeometry(125,506,80,50); + edit_livewire_gpio_button->setFont(bold_font); + edit_livewire_gpio_button->setText(tr("LiveWire\nGPIOs")); + connect(edit_livewire_gpio_button,SIGNAL(clicked()), + this,SLOT(livewireGpioButtonData())); + + // + // vGuest Switches Button + // + edit_vguestrelays_button=new QPushButton(this); + edit_vguestrelays_button->setGeometry(215,506,80,50); + edit_vguestrelays_button->setFont(bold_font); + edit_vguestrelays_button->setText(tr("vGuest\nSwitches")); + connect(edit_vguestrelays_button,SIGNAL(clicked()), + this,SLOT(vguestRelaysButtonData())); + + // + // vGuest Displays Button + // + edit_vguestdisplays_button=new QPushButton(this); + edit_vguestdisplays_button->setGeometry(305,506,80,50); + edit_vguestdisplays_button->setFont(bold_font); + edit_vguestdisplays_button->setText(tr("vGuest\nDisplays")); + connect(edit_vguestdisplays_button,SIGNAL(clicked()), + this,SLOT(vguestDisplaysButtonData())); + + // + // SAS Switches Button + // + edit_sasresources_button=new QPushButton(this); + edit_sasresources_button->setGeometry(170,561,80,50); + edit_sasresources_button->setFont(bold_font); + edit_sasresources_button->setText(tr("SAS\nSwitches")); + connect(edit_sasresources_button,SIGNAL(clicked()), + this,SLOT(sasResourcesButtonData())); + + // + // Ok Button + // + QPushButton *button=new QPushButton(this); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Values + // + edit_name_edit->setText(edit_matrix->name()); + str=QString(tr("Serial")); + for(int i=0;iinsertItem(str+QString().sprintf("%d",i)); + edit_port2_box->insertItem(str+QString().sprintf("%d",i)); + } + edit_porttype_box-> + setCurrentItem((int)edit_matrix->portType(RDMatrix::Primary)); + edit_porttype2_box-> + setCurrentItem((int)edit_matrix->portType(RDMatrix::Backup)); + switch((RDMatrix::PortType)edit_porttype_box->currentItem()) { + case RDMatrix::TtyPort: + edit_port_box->setCurrentItem(edit_matrix->port(RDMatrix::Primary)); + edit_port2_box->setCurrentItem(edit_matrix->port(RDMatrix::Backup)); + break; + + case RDMatrix::TcpPort: + edit_ipaddress_edit-> + setText(edit_matrix->ipAddress(RDMatrix::Primary).toString()); + edit_ipport_spin->setValue(edit_matrix->ipPort(RDMatrix::Primary)); + edit_ipaddress2_edit-> + setText(edit_matrix->ipAddress(RDMatrix::Backup).toString()); + edit_ipport2_spin->setValue(edit_matrix->ipPort(RDMatrix::Backup)); + break; + + case RDMatrix::NoPort: + break; + } + edit_card_box->setValue(edit_matrix->card()); + edit_inputs_box->setValue(edit_matrix->inputs()); + edit_outputs_box->setValue(edit_matrix->outputs()); + edit_device_edit->setText(edit_matrix->gpioDevice()); + edit_gpis_box->setValue(edit_matrix->gpis()); + edit_gpos_box->setValue(edit_matrix->gpos()); + edit_username_edit->setText(edit_matrix->username(RDMatrix::Primary)); + edit_password_edit->setText(edit_matrix->password(RDMatrix::Primary)); + edit_username2_edit->setText(edit_matrix->username(RDMatrix::Backup)); + edit_password2_edit->setText(edit_matrix->password(RDMatrix::Backup)); + if(edit_matrix->startCart(RDMatrix::Primary)>0) { + edit_start_cart_edit-> + setText(QString().sprintf("%06u", + edit_matrix->startCart(RDMatrix::Primary))); + } + if(edit_matrix->stopCart(RDMatrix::Primary)>0) { + edit_stop_cart_edit-> + setText(QString().sprintf("%06u", + edit_matrix->stopCart(RDMatrix::Primary))); + } + if(edit_matrix->startCart(RDMatrix::Backup)>0) { + edit_start_cart2_edit-> + setText(QString().sprintf("%06u", + edit_matrix->startCart(RDMatrix::Backup))); + } + if(edit_matrix->stopCart(RDMatrix::Backup)>0) { + edit_stop_cart2_edit-> + setText(QString().sprintf("%06u", + edit_matrix->stopCart(RDMatrix::Backup))); + } + edit_displays_box->setValue(edit_matrix->displays()); + if(edit_matrix->layer()=='V') { + edit_layer_box->setCurrentItem(0); + } + else { + edit_layer_box->setCurrentItem(edit_matrix->layer()-'@'); + } + + RDMatrix::Type type=edit_matrix->type(); + + // + // Connection Sections + // + edit_porttype_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::PortTypeControl)); + edit_porttype_box-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::PortTypeControl)); + edit_porttype2_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::PortTypeControl)); + edit_porttype2_box-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::PortTypeControl)); + + edit_port_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::SerialPortControl)); + edit_port_box-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::SerialPortControl)); + edit_port2_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::SerialPortControl)); + edit_port2_box-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::SerialPortControl)); + + edit_ipaddress_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::IpAddressControl)); + edit_ipaddress_edit-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::IpAddressControl)); + edit_ipaddress2_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::IpAddressControl)); + edit_ipaddress2_edit-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::IpAddressControl)); + + edit_ipport_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::IpPortControl)); + edit_ipport_spin-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::IpPortControl)); + edit_ipport2_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::IpPortControl)); + edit_ipport2_spin-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::IpPortControl)); + + edit_username_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::UsernameControl)); + edit_username_edit-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::UsernameControl)); + edit_username2_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::UsernameControl)); + edit_username2_edit-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::UsernameControl)); + + edit_password_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::PasswordControl)); + edit_password_edit-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::PasswordControl)); + edit_password2_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::PasswordControl)); + edit_password2_edit-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::PasswordControl)); + + edit_start_cart_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::StartupCartControl)); + edit_start_cart_edit-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::StartupCartControl)); + edit_start_cart_button-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::StartupCartControl)); + + edit_start_cart2_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::StartupCartControl)); + edit_start_cart2_edit-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::StartupCartControl)); + edit_start_cart2_button-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::StartupCartControl)); + + edit_stop_cart_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::ShutdownCartControl)); + edit_stop_cart_edit-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::ShutdownCartControl)); + edit_stop_cart_button-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Primary, + RDMatrix::ShutdownCartControl)); + + edit_stop_cart2_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::ShutdownCartControl)); + edit_stop_cart2_edit-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::ShutdownCartControl)); + edit_stop_cart2_button-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::Backup, + RDMatrix::ShutdownCartControl)); + + // + // Device Settings Section + // + edit_card_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::CardControl)); + edit_card_box-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::CardControl)); + + edit_device_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::GpioDeviceControl)); + edit_device_edit-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::GpioDeviceControl)); + + edit_layer_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::LayerControl)); + edit_layer_box-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::LayerControl)); + + edit_inputs_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::InputsControl)); + edit_inputs_box-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::InputsControl)); + + edit_outputs_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::OutputsControl)); + edit_outputs_box-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::OutputsControl)); + + edit_gpis_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::GpisControl)); + edit_gpis_box-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::GpisControl)); + edit_gpis_box-> + setLineStep(RDMatrix::defaultControlValue(type,RDMatrix::GpioStepSize)); + + edit_gpos_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::GposControl)); + edit_gpos_box-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::GposControl)); + edit_gpos_box-> + setLineStep(RDMatrix::defaultControlValue(type,RDMatrix::GpioStepSize)); + + edit_displays_label-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::DisplaysControl)); + edit_displays_box-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::DisplaysControl)); + + // + // Button Section + // + edit_inputs_button-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::InputsButtonControl)); + edit_outputs_button-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::OutputsButtonControl)); + edit_gpis_button-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::GpisButtonControl)); + edit_gpos_button-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::GposButtonControl)); + edit_livewire_button-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::NodesButtonControl)); + edit_livewire_gpio_button-> + setEnabled(RDMatrix::controlActive(type,RDMatrix::LivewireGpioButtonControl)); + edit_vguestrelays_button-> + setEnabled(RDMatrix::controlActive(type, + RDMatrix::VguestSwitchesButtonControl)); + edit_vguestdisplays_button-> + setEnabled(RDMatrix::controlActive(type, + RDMatrix::VguestDisplaysButtonControl)); + edit_sasresources_button-> + setEnabled(RDMatrix::controlActive(type, + RDMatrix::SasSwitchesButtonControl)); + + portTypeActivatedData(edit_porttype_box->currentItem()); + portType2ActivatedData(edit_porttype2_box->currentItem()); + gpisChangedData(edit_gpis_box->value()); + gposChangedData(edit_gpos_box->value()); +} + + +QSize EditMatrix::sizeHint() const +{ + return QSize(420,686); +} + + +QSizePolicy EditMatrix::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditMatrix::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(Qt::black)); + + p->drawLine(10,84,20,84); + p->drawLine(150,84,sizeHint().width()-10,84); + p->drawLine(sizeHint().width()-10,84,sizeHint().width()-10,218); + p->drawLine(10,218,sizeHint().width()-10,218); + p->drawLine(10,84,10,218); + + p->drawLine(10,232,20,232); + p->drawLine(150,232,sizeHint().width()-10,232); + p->drawLine(sizeHint().width()-10,232,sizeHint().width()-10,364); + p->drawLine(10,364,sizeHint().width()-10,364); + p->drawLine(10,232,10,364); + + p->end(); +} + + +void EditMatrix::portTypeActivatedData(int index) +{ + RDMatrix::Type type=edit_matrix->type(); + + switch((RDMatrix::PortType)edit_porttype_box->currentItem()) { + case RDMatrix::TtyPort: + edit_port_box->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::SerialPortControl)); + edit_port_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::SerialPortControl)); + edit_username_edit->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::UsernameControl)); + edit_username_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::UsernameControl)); + edit_password_edit->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::PasswordControl)); + edit_password_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::PasswordControl)); + edit_ipaddress_edit->setDisabled(true); + edit_ipaddress_label->setDisabled(true); + edit_ipport_spin->setDisabled(true); + edit_ipport_label->setDisabled(true); + edit_start_cart_label->setDisabled(true); + edit_start_cart_edit->setDisabled(true); + edit_start_cart_button->setDisabled(true); + edit_stop_cart_label->setDisabled(true); + edit_stop_cart_edit->setDisabled(true); + edit_stop_cart_button->setDisabled(true); + break; + + case RDMatrix::TcpPort: + edit_port_box->setDisabled(true); + edit_port_label->setDisabled(true); + edit_ipaddress_edit->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::IpAddressControl)); + edit_ipaddress_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::IpAddressControl)); + edit_ipport_spin->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::IpPortControl)); + edit_ipport_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::IpPortControl)); + edit_start_cart_edit->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::StartupCartControl)); + edit_start_cart_button->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::StartupCartControl)); + edit_start_cart_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::StartupCartControl)); + edit_stop_cart_edit->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::ShutdownCartControl)); + edit_stop_cart_button->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::ShutdownCartControl)); + edit_stop_cart_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Primary,RDMatrix::ShutdownCartControl)); + break; + + case RDMatrix::NoPort: + break; + } +} + + +void EditMatrix::portType2ActivatedData(int index) +{ + RDMatrix::Type type=edit_matrix->type(); + + switch((RDMatrix::PortType)edit_porttype2_box->currentItem()) { + case RDMatrix::TtyPort: + edit_port2_box->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::SerialPortControl)); + edit_port2_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::SerialPortControl)); + edit_username2_edit->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::UsernameControl)); + edit_username2_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::UsernameControl)); + edit_password2_edit->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::PasswordControl)); + edit_password2_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::PasswordControl)); + edit_ipaddress2_edit->setDisabled(true); + edit_ipaddress2_label->setDisabled(true); + edit_ipport2_spin->setDisabled(true); + edit_ipport2_label->setDisabled(true); + edit_start_cart2_label->setDisabled(true); + edit_start_cart2_edit->setDisabled(true); + edit_start_cart2_button->setDisabled(true); + edit_stop_cart2_label->setDisabled(true); + edit_stop_cart2_edit->setDisabled(true); + edit_stop_cart2_button->setDisabled(true); + break; + + case RDMatrix::TcpPort: + edit_ipaddress2_edit->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::IpAddressControl)); + edit_ipaddress2_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::IpAddressControl)); + edit_ipport2_spin->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::IpPortControl)); + edit_ipport2_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::IpPortControl)); + edit_start_cart2_edit->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::StartupCartControl)); + edit_start_cart2_button->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::StartupCartControl)); + edit_start_cart2_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::StartupCartControl)); + edit_stop_cart2_edit->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::ShutdownCartControl)); + edit_stop_cart2_button->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::ShutdownCartControl)); + edit_stop_cart2_label->setEnabled(RDMatrix::controlActive(type, + RDMatrix::Backup,RDMatrix::ShutdownCartControl)); + edit_port2_box->setDisabled(true); + edit_port2_label->setDisabled(true); + break; + + case RDMatrix::NoPort: + edit_port2_box->setDisabled(true); + edit_port2_label->setDisabled(true); + edit_ipaddress2_edit->setDisabled(true); + edit_ipaddress2_label->setDisabled(true); + edit_ipport2_spin->setDisabled(true); + edit_ipport2_label->setDisabled(true); + edit_username2_edit->setDisabled(true); + edit_username2_label->setDisabled(true); + edit_password2_edit->setDisabled(true); + edit_password2_label->setDisabled(true); + edit_start_cart2_label->setDisabled(true); + edit_start_cart2_edit->setDisabled(true); + edit_start_cart2_button->setDisabled(true); + edit_stop_cart2_label->setDisabled(true); + edit_stop_cart2_edit->setDisabled(true); + edit_stop_cart2_button->setDisabled(true); + break; + } +} + + +void EditMatrix::inputsButtonData() +{ + if(!WriteMatrix()) { + return; + } + ListEndpoints *ep=new ListEndpoints(edit_matrix,RDMatrix::Input,this); + ep->exec(); + delete ep; +} + + +void EditMatrix::outputsButtonData() +{ + if(!WriteMatrix()) { + return; + } + ListEndpoints *ep=new ListEndpoints(edit_matrix,RDMatrix::Output,this); + ep->exec(); + delete ep; +} + + +void EditMatrix::xpointsButtonData() +{ +} + + +void EditMatrix::gpisButtonData() +{ + if(!WriteMatrix()) { + return; + } + ListGpis *ep=new ListGpis(edit_matrix,RDMatrix::GpioInput,this); + ep->exec(); + delete ep; +} + + +void EditMatrix::gposButtonData() +{ + if(!WriteMatrix()) { + return; + } + ListGpis *ep=new ListGpis(edit_matrix,RDMatrix::GpioOutput,this); + ep->exec(); + delete ep; +} + + +void EditMatrix::inputsChangedData(int value) +{ + if(RDMatrix::controlActive(edit_matrix->type(), + RDMatrix::GpioInputsLinkedControl)) { + edit_gpis_box->setValue(value); + edit_gpos_box->setValue(value); + } + edit_inputs_button->setEnabled(value>0); +} + + +void EditMatrix::gpisChangedData(int value) +{ + if(RDMatrix::controlActive(edit_matrix->type(), + RDMatrix::GpiGpoLinkedControl)) { + edit_gpos_box->setValue(value); + } + if(RDMatrix::controlActive(edit_matrix->type(), + RDMatrix::GpioInputsLinkedControl)) { + edit_inputs_box->setValue(value); + } + edit_gpis_button->setEnabled(value>0); +} + + +void EditMatrix::gposChangedData(int value) +{ + if(RDMatrix::controlActive(edit_matrix->type(), + RDMatrix::GpiGpoLinkedControl)) { + edit_gpis_box->setValue(value); + } + if(RDMatrix::controlActive(edit_matrix->type(), + RDMatrix::GpioInputsLinkedControl)) { + edit_inputs_box->setValue(value); + } + edit_gpos_button->setEnabled(value>0); +} + + +void EditMatrix::livewireButtonData() +{ + ListNodes *dialog=new ListNodes(edit_matrix,this); + dialog->exec(); + delete dialog; +} + + +void EditMatrix::livewireGpioButtonData() +{ + ListLiveWireGpios *dialog=new ListLiveWireGpios(edit_matrix, + edit_gpis_box->value()/RD_LIVEWIRE_GPIO_BUNDLE_SIZE,this); + dialog->exec(); + delete dialog; +} + + +void EditMatrix::vguestRelaysButtonData() +{ + ListVguestResources *dialog= + new ListVguestResources(edit_matrix,RDMatrix::VguestTypeRelay, + edit_gpos_box->value(),this); + dialog->exec(); + delete dialog; +} + + +void EditMatrix::vguestDisplaysButtonData() +{ + ListVguestResources *dialog= + new ListVguestResources(edit_matrix,RDMatrix::VguestTypeDisplay, + edit_displays_box->value(),this); + dialog->exec(); + delete dialog; +} + + +void EditMatrix::sasResourcesButtonData() +{ + ListSasResources *dialog= + new ListSasResources(edit_matrix,edit_displays_box->value(),this); + dialog->exec(); + delete dialog; +} + + +void EditMatrix::startCartData() +{ + int cartnum=edit_start_cart_edit->text().toUInt(); + if(admin_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + if(cartnum>0) { + edit_start_cart_edit->setText(QString().sprintf("%06u",cartnum)); + } + else { + edit_start_cart_edit->setText(""); + } + } +} + + +void EditMatrix::stopCartData() +{ + int cartnum=edit_stop_cart_edit->text().toUInt(); + if(admin_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + if(cartnum>0) { + edit_stop_cart_edit->setText(QString().sprintf("%06u",cartnum)); + } + else { + edit_stop_cart_edit->setText(""); + } + } +} + + +void EditMatrix::startCart2Data() +{ + int cartnum=edit_start_cart2_edit->text().toUInt(); + if(admin_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + if(cartnum>0) { + edit_start_cart2_edit->setText(QString().sprintf("%06u",cartnum)); + } + else { + edit_start_cart2_edit->setText(""); + } + } +} + + +void EditMatrix::stopCart2Data() +{ + int cartnum=edit_stop_cart2_edit->text().toUInt(); + if(admin_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + if(cartnum>0) { + edit_stop_cart2_edit->setText(QString().sprintf("%06u",cartnum)); + } + else { + edit_stop_cart2_edit->setText(""); + } + } +} + + +void EditMatrix::okData() +{ + if(!WriteMatrix()) { + return; + } + done(0); +} + + +void EditMatrix::cancelData() +{ + done(1); +} + + +bool EditMatrix::WriteMatrix() +{ + QHostAddress addr; + QHostAddress addr2; + RDMatrix::Type type=edit_matrix->type(); + + // + // Ensure Sane Values + // + switch((RDMatrix::PortType)edit_porttype_box->currentItem()) { + case RDMatrix::TcpPort: + if(!addr.setAddress(edit_ipaddress_edit->text())) { + QMessageBox::warning(this,tr("Invalid Address"), + tr("The primary IP address is invalid!")); + return false; + } + break; + + default: + break; + } + + if(RDMatrix::controlActive(type,RDMatrix::Backup,RDMatrix::PortTypeControl)) { + switch((RDMatrix::PortType)edit_porttype2_box->currentItem()) { + case RDMatrix::TcpPort: + if(!addr2.setAddress(edit_ipaddress2_edit->text())) { + QMessageBox::warning(this,tr("Invalid Address"), + tr("The backup IP address is invalid!")); + return false; + } + if(edit_porttype_box->currentItem()==RDMatrix::TcpPort) { + if((addr==addr2)&& + (edit_ipport_spin->value()==edit_ipport2_spin->value())) { + QMessageBox::warning(this,tr("Duplicate Connections"), + tr("The primary and backup connections must be different!")); + return false; + } + } + break; + + case RDMatrix::TtyPort: + if(edit_porttype_box->currentItem()==RDMatrix::TtyPort) { + if(edit_port_box->currentItem()==edit_port2_box->currentItem()) { + QMessageBox::warning(this,tr("Duplicate Connections"), + tr("The primary and backup connections must be different!")); + return false; + } + } + break; + + case RDMatrix::NoPort: + break; + } + } + + switch((RDMatrix::PortType)edit_porttype_box->currentItem()) { + case RDMatrix::TtyPort: + edit_matrix->setPortType(RDMatrix::Primary,RDMatrix::TtyPort); + edit_matrix->setPort(RDMatrix::Primary,edit_port_box->currentItem()); + edit_matrix->setIpAddress(RDMatrix::Primary,QHostAddress()); + edit_matrix->setIpPort(RDMatrix::Primary,0); + break; + + case RDMatrix::TcpPort: + edit_matrix->setPortType(RDMatrix::Primary,RDMatrix::TcpPort); + edit_matrix->setPort(RDMatrix::Primary,-1); + edit_matrix->setIpAddress(RDMatrix::Primary,addr); + edit_matrix->setIpPort(RDMatrix::Primary,edit_ipport_spin->value()); + break; + + case RDMatrix::NoPort: + break; +} + switch((RDMatrix::PortType)edit_porttype2_box->currentItem()) { + case RDMatrix::TtyPort: + edit_matrix->setPortType(RDMatrix::Backup,RDMatrix::TtyPort); + edit_matrix->setPort(RDMatrix::Backup,edit_port2_box->currentItem()); + edit_matrix->setIpAddress(RDMatrix::Backup,QHostAddress()); + edit_matrix->setIpPort(RDMatrix::Backup,0); + break; + + case RDMatrix::TcpPort: + edit_matrix->setPortType(RDMatrix::Backup,RDMatrix::TcpPort); + edit_matrix->setPort(RDMatrix::Backup,-1); + edit_matrix->setIpAddress(RDMatrix::Backup,addr2); + edit_matrix->setIpPort(RDMatrix::Backup,edit_ipport2_spin->value()); + break; + + case RDMatrix::NoPort: + edit_matrix->setPortType(RDMatrix::Backup,RDMatrix::NoPort); + break; + } + if(edit_layer_box->currentItem()==0) { + edit_matrix->setLayer('V'); + } + else { + edit_matrix->setLayer('@'+edit_layer_box->currentItem()); + } + + // + // Update GPIO Tables + // + WriteGpioTable(RDMatrix::GpioInput); + WriteGpioTable(RDMatrix::GpioOutput); + + edit_matrix->setName(edit_name_edit->text()); + edit_matrix->setCard(edit_card_box->value()); + edit_matrix->setInputs(edit_inputs_box->value()); + edit_matrix->setOutputs(edit_outputs_box->value()); + edit_matrix->setGpioDevice(edit_device_edit->text()); + edit_matrix->setGpis(edit_gpis_box->value()); + edit_matrix->setGpos(edit_gpos_box->value()); + edit_matrix->setUsername(RDMatrix::Primary,edit_username_edit->text()); + edit_matrix->setPassword(RDMatrix::Primary,edit_password_edit->text()); + edit_matrix->setUsername(RDMatrix::Backup,edit_username2_edit->text()); + edit_matrix->setPassword(RDMatrix::Backup,edit_password2_edit->text()); + edit_matrix->setDisplays(edit_displays_box->value()); + edit_matrix-> + setStartCart(RDMatrix::Primary,edit_start_cart_edit->text().toUInt()); + edit_matrix-> + setStopCart(RDMatrix::Primary,edit_stop_cart_edit->text().toUInt()); + edit_matrix-> + setStartCart(RDMatrix::Backup,edit_start_cart2_edit->text().toUInt()); + edit_matrix-> + setStopCart(RDMatrix::Backup,edit_stop_cart2_edit->text().toUInt()); + + return true; +} + + +void EditMatrix::WriteGpioTable(RDMatrix::GpioType type) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + QString tablename; + int line_quan=0; + switch(type) { + case RDMatrix::GpioInput: + tablename="GPIS"; + line_quan=edit_gpis_box->value(); + break; + + case RDMatrix::GpioOutput: + tablename="GPOS"; + line_quan=edit_gpos_box->value(); + break; + } + + if(!RDMatrix::controlActive(edit_matrix->type(), + RDMatrix::DynamicGpioControl)) { + for(int i=0;ifirst()) { + sql=QString("insert into `")+tablename+ + "` set STATION_NAME=\""+RDEscapeString(edit_stationname)+"\","+ + QString().sprintf("MATRIX=%d,NUMBER=%d,MACRO_CART=0", + edit_matrix_number,i+1); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + } + + // + // Purge Stale Entries + // + sql=QString("delete from `")+tablename+ + "` where (STATION_NAME=\""+RDEscapeString(edit_stationname)+ + QString().sprintf("\")&&(MATRIX=%d)&&(NUMBER>%d)", + edit_matrix_number,line_quan); + q=new RDSqlQuery(sql); + delete q; + } +} diff --git a/rdadmin/edit_matrix.h b/rdadmin/edit_matrix.h new file mode 100644 index 00000000..10f79c5e --- /dev/null +++ b/rdadmin/edit_matrix.h @@ -0,0 +1,144 @@ +// edit_matrix.h +// +// Edit a Rivendell Matrix +// +// (C) Copyright 2002-2012 Fred Gleason +// +// $Id: edit_matrix.h,v 1.17.6.3 2013/02/21 02:46:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_MATRIX_H +#define EDIT_MATRIX_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class EditMatrix : public QDialog +{ + Q_OBJECT + public: + EditMatrix(RDMatrix *matrix,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + void paintEvent(QPaintEvent *e); + + private slots: + void portTypeActivatedData(int index); + void portType2ActivatedData(int index); + void inputsButtonData(); + void outputsButtonData(); + void xpointsButtonData(); + void gpisButtonData(); + void gposButtonData(); + void livewireButtonData(); + void livewireGpioButtonData(); + void vguestRelaysButtonData(); + void vguestDisplaysButtonData(); + void sasResourcesButtonData(); + void inputsChangedData(int value); + void gpisChangedData(int value); + void gposChangedData(int value); + void startCartData(); + void stopCartData(); + void startCart2Data(); + void stopCart2Data(); + void okData(); + void cancelData(); + + private: + bool WriteMatrix(); + void WriteGpioTable(RDMatrix::GpioType type); + RDMatrix *edit_matrix; + QString edit_stationname; + int edit_matrix_number; + QLineEdit *edit_name_edit; + QLabel *edit_porttype_label; + QComboBox *edit_porttype_box; + QLabel *edit_porttype2_label; + QComboBox *edit_porttype2_box; + QComboBox *edit_layer_box; + QLabel *edit_layer_label; + QLabel *edit_ipaddress_label; + QLineEdit *edit_ipaddress_edit; + QLabel *edit_ipport_label; + QSpinBox *edit_ipport_spin; + QLabel *edit_username_label; + QLineEdit *edit_username_edit; + QLabel *edit_password_label; + QLineEdit *edit_password_edit; + QLabel *edit_ipaddress2_label; + QLineEdit *edit_ipaddress2_edit; + QLabel *edit_ipport2_label; + QSpinBox *edit_ipport2_spin; + QLabel *edit_username2_label; + QLineEdit *edit_username2_edit; + QLabel *edit_password2_label; + QLineEdit *edit_password2_edit; + QLabel *edit_start_cart_label; + QLineEdit *edit_start_cart_edit; + QPushButton *edit_start_cart_button; + QLabel *edit_start_cart2_label; + QLineEdit *edit_start_cart2_edit; + QPushButton *edit_start_cart2_button; + QLabel *edit_stop_cart_label; + QLineEdit *edit_stop_cart_edit; + QPushButton *edit_stop_cart_button; + QLabel *edit_stop_cart2_label; + QLineEdit *edit_stop_cart2_edit; + QPushButton *edit_stop_cart2_button; + QLabel *edit_port_label; + QComboBox *edit_port_box; + QLabel *edit_port2_label; + QComboBox *edit_port2_box; + QLabel *edit_inputs_label; + QSpinBox *edit_inputs_box; + QLabel *edit_outputs_label; + QSpinBox *edit_outputs_box; + QPushButton *edit_inputs_button; + QPushButton *edit_outputs_button; + QPushButton *edit_gpis_button; + QPushButton *edit_gpos_button; + QPushButton *edit_livewire_button; + QPushButton *edit_livewire_gpio_button; + QPushButton *edit_vguestrelays_button; + QPushButton *edit_vguestdisplays_button; + QPushButton *edit_sasresources_button; + QLabel *edit_device_label; + QLineEdit *edit_device_edit; + QLabel *edit_gpis_label; + QSpinBox *edit_gpis_box; + QLabel *edit_gpos_label; + QSpinBox *edit_gpos_box; + QLabel *edit_card_label; + QSpinBox *edit_card_box; + QLabel *edit_displays_label; + QSpinBox *edit_displays_box; + +}; + + +#endif + diff --git a/rdadmin/edit_node.cpp b/rdadmin/edit_node.cpp new file mode 100644 index 00000000..7f05cff2 --- /dev/null +++ b/rdadmin/edit_node.cpp @@ -0,0 +1,288 @@ +// edit_node.cpp +// +// Edit a Rivendell LiveWire Node +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: edit_node.cpp,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +EditNode::EditNode(int *id,RDMatrix *matrix,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_id=id; + edit_matrix=matrix; + edit_password_changed=false; + setCaption(tr("Edit LiveWire Node")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Node Hostname + // + edit_hostname_edit=new QLineEdit(this,"edit_hostname_edit"); + edit_hostname_edit->setGeometry(90,10,190,20); + QLabel *label= + new QLabel(edit_hostname_edit,tr("Hostname: "),this,"edit_hostname_label"); + label->setGeometry(10,10,80,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Node TCP Port + // + edit_tcpport_spin=new QSpinBox(this,"edit_tcpport_spin"); + edit_tcpport_spin->setGeometry(335,10,sizeHint().width()-345,20); + edit_tcpport_spin->setRange(0,0xFFFF); + label=new QLabel(edit_tcpport_spin,tr("Port: "),this,"edit_tcpport_label"); + label->setGeometry(290,10,45,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Node Description + // + edit_description_edit=new QLineEdit(this,"edit_description_edit"); + edit_description_edit->setGeometry(90,32,sizeHint().width()-100,20); + label=new QLabel(edit_description_edit,tr("Description: "), + this,"edit_description_label"); + label->setGeometry(10,32,80,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Base Output + // + edit_output_spin=new QSpinBox(this,"edit_output_spin"); + edit_output_spin->setGeometry(90,54,60,20); + edit_output_spin->setRange(0,0x7FFF); + edit_output_spin->setSpecialValueText(tr("None")); + label= + new QLabel(edit_output_spin,tr("First Output: "),this,"edit_output_label"); + label->setGeometry(10,54,80,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Node Password + // + edit_password_edit=new QLineEdit(this,"edit_password_edit"); + edit_password_edit->setGeometry(245,54,90,20); + edit_password_edit->setEchoMode(QLineEdit::Password); + edit_password_edit->setText("********"); + connect(edit_password_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(passwordChangedData(const QString &))); + label= + new QLabel(edit_password_edit,tr("Password: "),this,"edit_password_label"); + label->setGeometry(160,54,80,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // View Node Info Button + // + QPushButton *button=new QPushButton(this,"cancel_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&View Node\nInfo")); + connect(button,SIGNAL(clicked()),this,SLOT(viewData())); + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Data + // + if((*edit_id)<0) { + edit_tcpport_spin->setValue(RD_LIVEWIRE_DEFAULT_TCP_PORT); + } + else { + QString sql; + RDSqlQuery *q; + sql=QString().sprintf("select HOSTNAME,TCP_PORT,DESCRIPTION,PASSWORD,\ + BASE_OUTPUT \ + from SWITCHER_NODES \ + where ID=%d",*edit_id); + q=new RDSqlQuery(sql); + if(q->first()) { + edit_hostname_edit->setText(q->value(0).toString()); + edit_tcpport_spin->setValue(q->value(1).toInt()); + edit_description_edit->setText(q->value(2).toString()); + edit_password=q->value(3).toString(); + edit_output_spin->setValue(q->value(4).toInt()); + } + delete q; + } +} + + +QSize EditNode::sizeHint() const +{ + return QSize(400,144); +} + + +QSizePolicy EditNode::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditNode::passwordChangedData(const QString &) +{ + edit_password_changed=true; +} + + +void EditNode::viewData() +{ + QString password=edit_password; + if(edit_password_changed) { + password=edit_password_edit->text(); + } + ViewNodeInfo *node=new ViewNodeInfo(this); + node->exec(edit_hostname_edit->text(),edit_tcpport_spin->value(), + password,edit_output_spin->value()); + delete node; +} + + +void EditNode::okData() +{ + QString sql; + RDSqlQuery *q; + + if(edit_password_changed) { + edit_password=edit_password_edit->text(); + } + + if((*edit_id)<0) { + sql=QString().sprintf("select ID from SWITCHER_NODES \ + where (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&\ + (HOSTNAME=\"%s\")&&\ + (TCP_PORT=%d)", + (const char *)edit_matrix->station(), + edit_matrix->matrix(), + (const char *)edit_hostname_edit->text(), + edit_tcpport_spin->value()); + q=new RDSqlQuery(sql); + if(q->first()) { + delete q; + QMessageBox::warning(this,tr("Duplicate Node"), + tr("That node is already listed for this matrix!")); + return; + } + delete q; + + sql="select ID from SWITCHER_NODES order by ID desc"; + q=new RDSqlQuery(sql); + if(q->first()) { + *edit_id=q->value(0).toInt()+1; + } + else { + *edit_id=1; + } + delete q; + sql=QString().sprintf("insert into SWITCHER_NODES set \ + ID=%d,\ + STATION_NAME=\"%s\",\ + MATRIX=%d,\ + HOSTNAME=\"%s\",\ + TCP_PORT=%d,\ + DESCRIPTION=\"%s\",\ + BASE_OUTPUT=%d,\ + PASSWORD=\"%s\"", + *edit_id, + (const char *)edit_matrix->station(), + edit_matrix->matrix(), + (const char *)edit_hostname_edit->text(), + edit_tcpport_spin->value(), + (const char *)edit_description_edit->text(), + edit_output_spin->value(), + (const char *)RDEscapeString(edit_password)); + q=new RDSqlQuery(sql); + delete q; + } + else { + sql=QString().sprintf("update SWITCHER_NODES set HOSTNAME=\"%s\",\ + TCP_PORT=%d,\ + DESCRIPTION=\"%s\",\ + BASE_OUTPUT=%d,\ + PASSWORD=\"%s\" \ + where ID=%d", + (const char *)edit_hostname_edit->text(), + edit_tcpport_spin->value(), + (const char *)edit_description_edit->text(), + edit_output_spin->value(), + (const char *)RDEscapeString(edit_password), + *edit_id); + q=new RDSqlQuery(sql); + delete q; + } + + done(0); +} + + +void EditNode::cancelData() +{ + done(1); +} diff --git a/rdadmin/edit_node.h b/rdadmin/edit_node.h new file mode 100644 index 00000000..8d712c83 --- /dev/null +++ b/rdadmin/edit_node.h @@ -0,0 +1,62 @@ +// edit_node.h +// +// Edit a Rivendell LiveWire Node +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: edit_node.h,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_NODE_H +#define EDIT_NODE_H + +#include +#include +#include +#include + +#include + + +class EditNode : public QDialog +{ + Q_OBJECT + public: + EditNode(int *id,RDMatrix *matrix,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void passwordChangedData(const QString &); + void viewData(); + void okData(); + void cancelData(); + + private: + int *edit_id; + RDMatrix *edit_matrix; + QLineEdit *edit_hostname_edit; + QSpinBox *edit_tcpport_spin; + QLineEdit *edit_description_edit; + QSpinBox *edit_output_spin; + QLineEdit *edit_password_edit; + QString edit_password; + bool edit_password_changed; +}; + + +#endif // EDIT_NODE + diff --git a/rdadmin/edit_now_next.cpp b/rdadmin/edit_now_next.cpp new file mode 100644 index 00000000..0338cffa --- /dev/null +++ b/rdadmin/edit_now_next.cpp @@ -0,0 +1,603 @@ +// edit_now_next.cpp +// +// Edit the Now & Next Configuration for a Rivendell Workstation. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_now_next.cpp,v 1.10.2.1 2012/11/26 20:19:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + + +EditNowNext::EditNowNext(RDAirPlayConf *conf,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + nownext_conf=conf; + + // + // Create Fonts + // + QFont normal_font=QFont("Helvetica",12,QFont::Normal); + normal_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont section_font=QFont("Helvetica",14,QFont::Bold); + section_font.setPixelSize(14); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Edit Now & Next Data")); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + QIntValidator *int_validator=new QIntValidator(1,999999,this); + + // + // Button Mappers + // + QSignalMapper *now_mapper=new QSignalMapper(this,"nowcart_mapper"); + connect(now_mapper,SIGNAL(mapped(int)),this,SLOT(editNowcartData(int))); + QSignalMapper *next_mapper=new QSignalMapper(this,"nextcart_mapper"); + connect(next_mapper,SIGNAL(mapped(int)),this,SLOT(editNextcartData(int))); + + // + // Master Log Label + // + QLabel *label=new QLabel(tr("Master Log"),this,"masterlog_label"); + label->setGeometry(10,7,100,19); + label->setFont(section_font); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Master Log UDP Address + // + nownext_address_edit[0]=new QLineEdit(this,"nownext_address_edit[0]"); + nownext_address_edit[0]->setGeometry(135,33,120,19); + label=new QLabel(nownext_address_edit[0],tr("IP Address:"),this, + "nownext_address_label"); + label->setGeometry(10,33,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Master Log UDP Port + // + nownext_port_spin[0]=new QSpinBox(this,"nownext_port_spin[0]"); + nownext_port_spin[0]->setGeometry(375,33,60,19); + nownext_port_spin[0]->setRange(0,65535); + label=new QLabel(nownext_port_spin[0],tr("UDP Port:"),this,"nownext_port_label"); + label->setGeometry(270,33,100,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Master Log UDP String + // + nownext_string_edit[0]=new QLineEdit(this,"nownext_string_edit[0]"); + nownext_string_edit[0]->setGeometry(135,55,sizeHint().width()-145,19); + label=new QLabel(nownext_string_edit[0], + tr("UDP String:"),this, + "nownext_string_label"); + label->setGeometry(10,55,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Master Log RML + // + nownext_rml_edit[0]=new QLineEdit(this,"nownext_rml_edit[0]"); + nownext_rml_edit[0]->setGeometry(135,77,sizeHint().width()-145,19); + nownext_rml_edit[0]->setValidator(validator); + label=new QLabel(nownext_rml_edit[0], + tr("RML:"),this, + "nownext_rml_label"); + label->setGeometry(10,77,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Main Log Default Now Cart + // + nownext_nowcart_edit[0]=new QLineEdit(this,"nownext_nowcart_edit[0]"); + nownext_nowcart_edit[0]->setGeometry(135,104,60,19); + nownext_nowcart_edit[0]->setValidator(int_validator); + label=new QLabel(nownext_nowcart_edit[0],tr("Default Now Cart:"),this, + "nownext_nowcart_label"); + label->setGeometry(10,104,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QPushButton *button=new QPushButton(this); + button->setGeometry(205,101,50,26); + button->setFont(normal_font); + button->setText(tr("Select")); + now_mapper->setMapping(button,0); + connect(button,SIGNAL(clicked()),now_mapper,SLOT(map())); + + // + // Main Log Default Next Cart + // + nownext_nextcart_edit[0]=new QLineEdit(this,"nownext_nextcart_edit[0]"); + nownext_nextcart_edit[0]->setGeometry(135,136,60,19); + nownext_nextcart_edit[0]->setValidator(int_validator); + label=new QLabel(nownext_nextcart_edit[0],tr("Default Next Cart:"),this, + "nownext_nextcart_label"); + label->setGeometry(10,136,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + button=new QPushButton(this); + button->setGeometry(205,132,50,26); + button->setFont(normal_font); + button->setText(tr("Select")); + next_mapper->setMapping(button,0); + connect(button,SIGNAL(clicked()),next_mapper,SLOT(map())); + + // + // Aux Log 1 Label + // + label=new QLabel(tr("Aux Log 1"),this,"masterlog_label"); + label->setGeometry(10,175,100,19); + label->setFont(section_font); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Aux Log 1 UDP Address + // + nownext_address_edit[1]=new QLineEdit(this,"nownext_address_edit[1]"); + nownext_address_edit[1]->setGeometry(135,201,120,19); + label=new QLabel(nownext_address_edit[1],tr("IP Address:"),this, + "nownext_address_label"); + label->setGeometry(10,201,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Aux Log 1 UDP Port + // + nownext_port_spin[1]=new QSpinBox(this,"nownext_port_spin[1]"); + nownext_port_spin[1]->setGeometry(375,201,60,19); + nownext_port_spin[1]->setRange(0,65535); + label=new QLabel(nownext_port_spin[1],tr("UDP Port:"), + this,"nownext_port_label"); + label->setGeometry(270,201,100,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Aux Log 1 UDP String + // + nownext_string_edit[1]=new QLineEdit(this,"nownext_string_edit[1]"); + nownext_string_edit[1]->setGeometry(135,223,sizeHint().width()-145,19); + label=new QLabel(nownext_string_edit[1],tr("UDP String:"),this, + "nownext_string_label"); + label->setGeometry(10,223,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Aux Log 1 RML + // + nownext_rml_edit[1]=new QLineEdit(this,"nownext_rml_edit[1]"); + nownext_rml_edit[1]->setGeometry(135,245,sizeHint().width()-145,19); + nownext_rml_edit[1]->setValidator(validator); + label=new QLabel(nownext_rml_edit[1], + tr("RML:"),this, + "nownext_rml_label"); + label->setGeometry(10,245,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Aux 1 Log Default Now Cart + // + nownext_nowcart_edit[1]=new QLineEdit(this,"nownext_nowcart_edit[1]"); + nownext_nowcart_edit[1]->setGeometry(135,272,60,19); + nownext_nowcart_edit[1]->setValidator(int_validator); + label=new QLabel(nownext_nowcart_edit[1],tr("Default Now Cart:"),this, + "nownext_nowcart_label"); + label->setGeometry(10,272,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + button=new QPushButton(this); + button->setGeometry(205,269,50,26); + button->setFont(normal_font); + button->setText(tr("Select")); + now_mapper->setMapping(button,1); + connect(button,SIGNAL(clicked()),now_mapper,SLOT(map())); + + // + // Aux 1 Log Default Next Cart + // + nownext_nextcart_edit[1]=new QLineEdit(this,"nownext_nextcart_edit[1]"); + nownext_nextcart_edit[1]->setGeometry(135,304,60,19); + nownext_nextcart_edit[1]->setValidator(int_validator); + label=new QLabel(nownext_nextcart_edit[1],tr("Default Next Cart:"),this, + "nownext_nextcart_label"); + label->setGeometry(10,304,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + button=new QPushButton(this); + button->setGeometry(205,300,50,26); + button->setFont(normal_font); + button->setText(tr("Select")); + next_mapper->setMapping(button,1); + connect(button,SIGNAL(clicked()),next_mapper,SLOT(map())); + + // + // Aux Log 2 Label + // + label=new QLabel(tr("Aux Log 2"),this,"masterlog_label"); + label->setGeometry(10,343,100,19); + label->setFont(section_font); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Aux Log 2 UDP Address + // + nownext_address_edit[2]=new QLineEdit(this,"nownext_address_edit[2]"); + nownext_address_edit[2]->setGeometry(135,369,120,19); + label=new QLabel(nownext_address_edit[2],tr("IP Address:"),this, + "nownext_address_label"); + label->setGeometry(10,369,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Aux Log 2 UDP Port + // + nownext_port_spin[2]=new QSpinBox(this,"nownext_port_spin[2]"); + nownext_port_spin[2]->setGeometry(375,369,60,19); + nownext_port_spin[2]->setRange(0,65535); + label=new QLabel(nownext_port_spin[2],tr("UDP Port:"), + this,"nownext_port_label"); + label->setGeometry(270,369,100,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Aux Log 2 UDP String + // + nownext_string_edit[2]=new QLineEdit(this,"nownext_string_edit[2]"); + nownext_string_edit[2]->setGeometry(135,391,sizeHint().width()-145,19); + label=new QLabel(nownext_string_edit[2],tr("UDP String:"),this, + "nownext_string_label"); + label->setGeometry(10,391,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Aux Log 2 RML + // + nownext_rml_edit[2]=new QLineEdit(this,"nownext_rml_edit[2]"); + nownext_rml_edit[2]->setGeometry(135,413,sizeHint().width()-145,19); + nownext_rml_edit[2]->setValidator(validator); + label=new QLabel(nownext_rml_edit[2], + tr("RML:"),this, + "nownext_rml_label"); + label->setGeometry(10,413,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Aux 1 Log Default Now Cart + // + nownext_nowcart_edit[2]=new QLineEdit(this,"nownext_nowcart_edit[2]"); + nownext_nowcart_edit[2]->setGeometry(135,440,60,19); + nownext_nowcart_edit[2]->setValidator(int_validator); + label=new QLabel(nownext_nowcart_edit[2],tr("Default Now Cart:"),this, + "nownext_nowcart_label"); + label->setGeometry(10,440,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + button=new QPushButton(this); + button->setGeometry(205,437,50,26); + button->setFont(normal_font); + button->setText(tr("Select")); + now_mapper->setMapping(button,2); + connect(button,SIGNAL(clicked()),now_mapper,SLOT(map())); + + // + // Aux 1 Log Default Next Cart + // + nownext_nextcart_edit[2]=new QLineEdit(this,"nownext_nextcart_edit[2]"); + nownext_nextcart_edit[2]->setGeometry(135,472,60,19); + nownext_nextcart_edit[2]->setValidator(int_validator); + label=new QLabel(nownext_nextcart_edit[2],tr("Default Next Cart:"),this, + "nownext_nextcart_label"); + label->setGeometry(10,472,120,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + button=new QPushButton(this); + button->setGeometry(205,469,50,26); + button->setFont(normal_font); + button->setText(tr("Select")); + next_mapper->setMapping(button,2); + connect(button,SIGNAL(clicked()),next_mapper,SLOT(map())); + + // + // Plugin List + // + nownext_plugin_list=new RDListView(this); + nownext_plugin_list->setGeometry(10,540,sizeHint().width()-20,120); + nownext_plugin_list->setItemMargin(5); + nownext_plugin_list->addColumn(tr("Path")); + nownext_plugin_list->setColumnAlignment(0,AlignLeft|AlignVCenter); + nownext_plugin_list->addColumn(tr("Argument")); + nownext_plugin_list->setColumnAlignment(1,AlignLeft|AlignVCenter); + nownext_plugin_list->setAllColumnsShowFocus(true); + connect(nownext_plugin_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(pluginDoubleClickedData(QListViewItem *,const QPoint &,int))); + + label=new QLabel(nownext_plugin_list, + tr("Loadable Modules:"),this, + "nownext_plugins_label"); + label->setGeometry(10,518,sizeHint().width()-20,19); + label->setFont(section_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + nownext_add_button=new QPushButton(tr("Add"),this); + nownext_add_button->setGeometry(sizeHint().width()-210,665,60,25); + nownext_add_button->setFont(font); + connect(nownext_add_button,SIGNAL(clicked()),this,SLOT(addPluginData())); + + nownext_edit_button=new QPushButton(tr("Edit"),this); + nownext_edit_button->setGeometry(sizeHint().width()-140,665,60,25); + nownext_edit_button->setFont(font); + connect(nownext_edit_button,SIGNAL(clicked()),this,SLOT(editPluginData())); + + nownext_delete_button=new QPushButton(tr("Delete"),this); + nownext_delete_button->setGeometry(sizeHint().width()-70,665,60,25); + nownext_delete_button->setFont(font); + connect(nownext_delete_button,SIGNAL(clicked()), + this,SLOT(deletePluginData())); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + for(int i=0;i<3;i++) { + nownext_address_edit[i]->setText(nownext_conf->udpAddress(i).toString()); + nownext_port_spin[i]->setValue(nownext_conf->udpPort(i)); + nownext_string_edit[i]->setText(nownext_conf->udpString(i)); + nownext_rml_edit[i]->setText(nownext_conf->logRml(i)); + if(nownext_conf->logNowCart(i)>0) { + nownext_nowcart_edit[i]-> + setText(QString().sprintf("%06u",nownext_conf->logNowCart(i))); + } + if(nownext_conf->logNextCart(i)>0) { + nownext_nextcart_edit[i]-> + setText(QString().sprintf("%06u",nownext_conf->logNextCart(i))); + } + } + sql=QString().sprintf("select ID,PLUGIN_PATH,PLUGIN_ARG \ + from NOWNEXT_PLUGINS \ + where (STATION_NAME=\"%s\")&& \ + (LOG_MACHINE=0)", + (const char *)nownext_conf->station()); + q=new RDSqlQuery(sql); + while(q->next()) { + item=new RDListViewItem(nownext_plugin_list); + item->setId(q->value(0).toInt()); + item->setText(0,q->value(1).toString()); + item->setText(1,q->value(2).toString()); + } + delete q; +} + + +EditNowNext::~EditNowNext() +{ +} + + +QSize EditNowNext::sizeHint() const +{ + return QSize(445,770); +} + + +QSizePolicy EditNowNext::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditNowNext::addPluginData() +{ + QString path; + QString arg; + EditNowNextPlugin *d=new EditNowNextPlugin(&path,&arg,this); + if(d->exec()==0) { + RDListViewItem *item=new RDListViewItem(nownext_plugin_list); + item->setId(-1); + item->setText(0,path); + item->setText(1,arg); + nownext_plugin_list->ensureItemVisible(item); + } + delete d; +} + + +void EditNowNext::editPluginData() +{ + RDListViewItem *item= + (RDListViewItem *)nownext_plugin_list->selectedItem(); + if(item==NULL) { + return; + } + QString path=item->text(0); + QString arg=item->text(1); + EditNowNextPlugin *d=new EditNowNextPlugin(&path,&arg,this); + if(d->exec()==0) { + item->setText(0,path); + item->setText(1,arg); + } + delete d; +} + + +void EditNowNext::deletePluginData() +{ + RDListViewItem *item=(RDListViewItem *)nownext_plugin_list->selectedItem(); + if(item==NULL) { + return; + } + delete item; +} + + +void EditNowNext::pluginDoubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editPluginData(); +} + + +void EditNowNext::editNowcartData(int lognum) +{ + int cartnum=nownext_nowcart_edit[lognum]->text().toInt(); + if(admin_cart_dialog->exec(&cartnum,RDCart::All,NULL,0, + admin_user->name(),admin_user->password())==0) { + nownext_nowcart_edit[lognum]->setText(QString().sprintf("%06d",cartnum)); + } +} + + +void EditNowNext::editNextcartData(int lognum) +{ + int cartnum=nownext_nextcart_edit[lognum]->text().toInt(); + if(admin_cart_dialog->exec(&cartnum,RDCart::All,NULL,0, + admin_user->name(),admin_user->password())==0) { + nownext_nextcart_edit[lognum]->setText(QString().sprintf("%06d",cartnum)); + } +} + + +void EditNowNext::okData() +{ + QHostAddress addr[3]; + QString str1; + QString str2; + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + for(int i=0;i<3;i++) { + if(nownext_address_edit[i]->text().isEmpty()) { + nownext_address_edit[i]->setText("0.0.0.0"); + } + if(!addr[i].setAddress(nownext_address_edit[i]->text())) { + str1=QString(tr("The IP address")); + str2=QString(tr("is invalid!")); + QMessageBox::warning(this,tr("Invalid Address"), + QString(). + sprintf("%s \"%s\" %s",(const char *)str1, + (const char *)nownext_address_edit[i]-> + text(), + (const char *)str2)); + return; + } + } + for(int i=0;i<3;i++) { + nownext_conf->setUdpAddress(i,addr[i]); + nownext_conf->setUdpPort(i,(Q_UINT16)nownext_port_spin[i]->value()); + nownext_conf->setUdpString(i,nownext_string_edit[i]->text()); + nownext_conf->setLogRml(i,nownext_rml_edit[i]->text()); + if(nownext_nowcart_edit[i]->text().isEmpty()) { + nownext_conf->setLogNowCart(i,0); + } + else { + nownext_conf->setLogNowCart(i,nownext_nowcart_edit[i]->text().toUInt()); + } + if(nownext_nextcart_edit[i]->text().isEmpty()) { + nownext_conf->setLogNextCart(i,0); + } + else { + nownext_conf->setLogNextCart(i,nownext_nextcart_edit[i]->text().toUInt()); + } + sql=QString().sprintf("delete from NOWNEXT_PLUGINS where \ + (STATION_NAME=\"%s\")&&(LOG_MACHINE=%d)", + (const char *)RDEscapeString(nownext_conf->station()), + i); + q=new RDSqlQuery(sql); + delete q; + } + item=(RDListViewItem *)nownext_plugin_list->firstChild(); + while(item!=NULL) { + sql=QString().sprintf("insert into NOWNEXT_PLUGINS set \ + STATION_NAME=\"%s\", \ + LOG_MACHINE=0, \ + PLUGIN_PATH=\"%s\", \ + PLUGIN_ARG=\"%s\"", + (const char *) + RDEscapeString(nownext_conf->station()), + (const char *)RDEscapeString(item->text(0)), + (const char *)RDEscapeString(item->text(1))); + q=new RDSqlQuery(sql); + delete q; + item=(RDListViewItem *)item->nextSibling(); + } + done(0); +} + + +void EditNowNext::cancelData() +{ + done(-1); +} diff --git a/rdadmin/edit_now_next.h b/rdadmin/edit_now_next.h new file mode 100644 index 00000000..ecfce40f --- /dev/null +++ b/rdadmin/edit_now_next.h @@ -0,0 +1,73 @@ +// edit_now_next.h +// +// Edit the Now & Next Configuration for a Rivendell Workstation +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_now_next.h,v 1.7 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_NOW_NEXT_H +#define EDIT_NOW_NEXT_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +class EditNowNext : public QDialog +{ + Q_OBJECT + public: + EditNowNext(RDAirPlayConf *conf,QWidget *parent=0,const char *name=0); + ~EditNowNext(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addPluginData(); + void editPluginData(); + void deletePluginData(); + void pluginDoubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void editNowcartData(int lognum); + void editNextcartData(int lognum); + void okData(); + void cancelData(); + + private: + QLineEdit *nownext_address_edit[3]; + QSpinBox *nownext_port_spin[3]; + QLineEdit *nownext_string_edit[3]; + QLineEdit *nownext_rml_edit[3]; + QLineEdit *nownext_nowcart_edit[3]; + QLineEdit *nownext_nextcart_edit[3]; + RDListView *nownext_plugin_list; + QPushButton *nownext_add_button; + QPushButton *nownext_edit_button; + QPushButton *nownext_delete_button; + RDAirPlayConf *nownext_conf; +}; + + +#endif + diff --git a/rdadmin/edit_nownextplugin.cpp b/rdadmin/edit_nownextplugin.cpp new file mode 100644 index 00000000..61b7c742 --- /dev/null +++ b/rdadmin/edit_nownextplugin.cpp @@ -0,0 +1,154 @@ +// edit_nownextplugin.cpp +// +// Edit a Rivendell Now & Next Plugin Configuration +// +// (C) Copyright 2008 Fred Gleason +// +// $Id: edit_nownextplugin.cpp,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include +#include + +#include + + +EditNowNextPlugin::EditNowNextPlugin(QString *path,QString *arg, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + plugin_path=path; + plugin_arg=arg; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Edit Plugin")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont user_font=QFont("Helvetica",12,QFont::Normal); + user_font.setPixelSize(12); + + // + // Path + // + plugin_path_edit=new QLineEdit(this); + plugin_path_edit->setGeometry(110,11,sizeHint().width()-180,19); + plugin_path_edit->setMaxLength(255); + QLabel *label=new QLabel(plugin_path_edit,tr("Plugin Path:"),this); + label->setGeometry(10,11,95,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QPushButton *button=new QPushButton(tr("Select"),this); + button->setGeometry(sizeHint().width()-60,10,50,22); + button->setFont(user_font); + connect(button,SIGNAL(clicked()),this,SLOT(selectData())); + + // + // Argument + // + plugin_arg_edit=new QLineEdit(this); + plugin_arg_edit->setGeometry(110,38,sizeHint().width()-120,19); + plugin_arg_edit->setMaxLength(255); + label=new QLabel(plugin_arg_edit,tr("Argument:"),this); + label->setGeometry(10,38,95,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + plugin_path_edit->setText(*path); + plugin_arg_edit->setText(*arg); +} + + +EditNowNextPlugin::~EditNowNextPlugin() +{ + delete plugin_path_edit; + delete plugin_arg_edit; +} + + +QSize EditNowNextPlugin::sizeHint() const +{ + return QSize(400,130); +} + + +QSizePolicy EditNowNextPlugin::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditNowNextPlugin::selectData() +{ + QString filename=RD_MODULES_DIR; + if(!plugin_path_edit->text().isEmpty()) { + filename=plugin_path_edit->text(); + } + filename=QFileDialog::getOpenFileName(filename,RD_MODULE_FILE_FILTER, + this,"",tr("Select plugin")); + if(!filename.isNull()) { + plugin_path_edit->setText(filename); + } +} + + +void EditNowNextPlugin::okData() +{ + *plugin_path=plugin_path_edit->text(); + *plugin_arg=plugin_arg_edit->text(); + done(0); +} + + +void EditNowNextPlugin::cancelData() +{ + done(-1); +} diff --git a/rdadmin/edit_nownextplugin.h b/rdadmin/edit_nownextplugin.h new file mode 100644 index 00000000..989bc26f --- /dev/null +++ b/rdadmin/edit_nownextplugin.h @@ -0,0 +1,53 @@ +// edit_nownextplugin.h +// +// Edit a Rivendell Now & Next Plugin Configuration +// +// (C) Copyright 2008 Fred Gleason +// +// $Id: edit_nownextplugin.h,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_NOWNEXTPLUGIN_H +#define EDIT_NOWNEXTPLUGIN_H + +#include +#include + + +class EditNowNextPlugin : public QDialog +{ + Q_OBJECT + public: + EditNowNextPlugin(QString *path,QString *arg, + QWidget *parent=0,const char *name=0); + ~EditNowNextPlugin(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void selectData(); + void okData(); + void cancelData(); + + private: + QLineEdit *plugin_path_edit; + QLineEdit *plugin_arg_edit; + QString *plugin_path; + QString *plugin_arg; +}; + + +#endif // EDIT_NOWNEXTPLUGIN_H diff --git a/rdadmin/edit_rdairplay.cpp b/rdadmin/edit_rdairplay.cpp new file mode 100644 index 00000000..68e0ad34 --- /dev/null +++ b/rdadmin/edit_rdairplay.cpp @@ -0,0 +1,1165 @@ +// edit_rdairplay.cpp +// +// Edit an RDAirPlay Configuration +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_rdairplay.cpp,v 1.53.6.9 2014/02/11 23:46:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +EditRDAirPlay::EditRDAirPlay(RDStation *station,RDStation *cae_station, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + + air_exitpasswd_changed=false; + air_logmachine=0; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + air_conf=new RDAirPlayConf(station->name(),"RDAIRPLAY"); + + // + // Create Fonts + // + QFont unit_font=QFont("Helvetica",12,QFont::Normal); + unit_font.setPixelSize(12); + QFont small_font=QFont("Helvetica",12,QFont::Bold); + small_font.setPixelSize(12); + QFont big_font=QFont("Helvetica",14,QFont::Bold); + big_font.setPixelSize(14); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this); + + // + // Dialog Name + // + setCaption(tr("RDAirPlay config for ")+station->name()); + + // + // Channel Assignments Section + // + QLabel *label=new QLabel(tr("Channel Assignments"),this); + label->setFont(big_font); + label->setGeometry(10,10,200,16); + + QSignalMapper *mapper=new QSignalMapper(this); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(editGpiosData(int))); + + // + // Main Log Output 1 + // + label=new QLabel(tr("Main Log Output 1"),this); + label->setFont(small_font); + label->setGeometry(25,32,200,16); + air_card_sel[0]=new RDCardSelector(this); + air_card_sel[0]->setId(0); + air_card_sel[0]->setGeometry(20,50,120,117); + air_start_rml_edit[0]=new QLineEdit(this); + air_start_rml_edit[0]->setGeometry(210,50,95,19); + air_start_rml_edit[0]->setValidator(validator); + air_start_rml_label[0]=new QLabel(air_start_rml_edit[0],tr("Start RML:"),this); + air_start_rml_label[0]->setGeometry(140,50,65,19); + air_start_rml_label[0]->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[0]=new QLineEdit(this); + air_stop_rml_edit[0]->setGeometry(210,71,95,19); + air_stop_rml_edit[0]->setValidator(validator); + air_stop_rml_label[0]=new QLabel(air_start_rml_edit[0],tr("Stop RML:"),this); + air_stop_rml_label[0]->setGeometry(140,71,65,19); + air_stop_rml_label[0]->setAlignment(AlignVCenter|AlignRight); + + air_channel_button[0]=new QPushButton(tr("Edit\nGPIOs"),this); + air_channel_button[0]->setGeometry(310,46,60,50); + air_channel_button[0]->setFont(small_font); + mapper->setMapping(air_channel_button[0],RDAirPlayConf::MainLog1Channel); + connect(air_channel_button[0],SIGNAL(clicked()),mapper,SLOT(map())); + connect(air_card_sel[0],SIGNAL(settingsChanged(int,int,int)), + this,SLOT(audioSettingsChangedData(int,int,int))); + + // + // Main Log Output 2 + // + label=new QLabel(tr("Main Log Output 2"),this); + label->setFont(small_font); + label->setGeometry(25,100,200,16); + air_card_sel[1]=new RDCardSelector(this); + air_card_sel[1]->setId(1); + air_card_sel[1]->setGeometry(20,118,120,117); + air_start_rml_edit[1]=new QLineEdit(this); + air_start_rml_edit[1]->setGeometry(210,118,95,19); + air_start_rml_edit[1]->setValidator(validator); + air_start_rml_label[1]=new QLabel(air_start_rml_edit[1],tr("Start RML:"),this); + air_start_rml_label[1]->setGeometry(140,118,65,19); + air_start_rml_label[1]->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[1]=new QLineEdit(this); + air_stop_rml_edit[1]->setGeometry(210,139,95,19); + air_stop_rml_edit[1]->setValidator(validator); + air_stop_rml_label[1]=new QLabel(air_start_rml_edit[1],tr("Stop RML:"),this); + air_stop_rml_label[1]->setGeometry(140,139,65,19); + air_stop_rml_label[1]->setAlignment(AlignVCenter|AlignRight); + + air_channel_button[1]=new QPushButton(tr("Edit\nGPIOs"),this); + air_channel_button[1]->setGeometry(310,114,60,50); + air_channel_button[1]->setFont(small_font); + mapper->setMapping(air_channel_button[1],RDAirPlayConf::MainLog2Channel); + connect(air_channel_button[1],SIGNAL(clicked()),mapper,SLOT(map())); + connect(air_card_sel[1],SIGNAL(settingsChanged(int,int,int)), + this,SLOT(audioSettingsChangedData(int,int,int))); + + // + // Aux Log 1 Output + // + label=new QLabel(tr("Aux Log 1 Output"),this); + label->setFont(small_font); + label->setGeometry(25,168,200,16); + air_card_sel[4]=new RDCardSelector(this); + air_card_sel[4]->setId(4); + air_card_sel[4]->setGeometry(20,186,120,117); + air_start_rml_edit[4]=new QLineEdit(this); + air_start_rml_edit[4]->setGeometry(210,186,95,19); + air_start_rml_edit[4]->setValidator(validator); + air_start_rml_label[4]=new QLabel(air_start_rml_edit[4],tr("Start RML:"),this); + air_start_rml_label[4]->setGeometry(140,186,65,19); + air_start_rml_label[4]->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[4]=new QLineEdit(this); + air_stop_rml_edit[4]->setGeometry(210,207,95,19); + air_stop_rml_edit[4]->setValidator(validator); + air_stop_rml_label[4]=new QLabel(air_start_rml_edit[4],tr("Stop RML:"),this); + air_stop_rml_label[4]->setGeometry(140,207,65,19); + air_stop_rml_label[4]->setAlignment(AlignVCenter|AlignRight); + + air_channel_button[4]=new QPushButton(tr("Edit\nGPIOs"),this); + air_channel_button[4]->setGeometry(310,182,60,50); + air_channel_button[4]->setFont(small_font); + mapper->setMapping(air_channel_button[4],RDAirPlayConf::AuxLog1Channel); + connect(air_channel_button[4],SIGNAL(clicked()),mapper,SLOT(map())); + connect(air_card_sel[4],SIGNAL(settingsChanged(int,int,int)), + this,SLOT(audioSettingsChangedData(int,int,int))); + + // + // Aux Log 2 Output + // + label=new QLabel(tr("Aux Log 2 Output"),this); + label->setFont(small_font); + label->setGeometry(25,236,200,16); + air_card_sel[5]=new RDCardSelector(this); + air_card_sel[5]->setId(5); + air_card_sel[5]->setGeometry(20,254,120,117); + air_start_rml_edit[5]=new QLineEdit(this); + air_start_rml_edit[5]->setGeometry(210,254,95,19); + air_start_rml_edit[5]->setValidator(validator); + air_start_rml_label[5]=new QLabel(air_start_rml_edit[5],tr("Start RML:"),this); + air_start_rml_label[5]->setGeometry(140,254,65,19); + air_start_rml_label[5]->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[5]=new QLineEdit(this); + air_stop_rml_edit[5]->setGeometry(210,275,95,19); + air_stop_rml_edit[5]->setValidator(validator); + air_stop_rml_label[5]=new QLabel(air_start_rml_edit[5],tr("Stop RML:"),this); + air_stop_rml_label[5]->setGeometry(140,275,65,19); + air_stop_rml_label[5]->setAlignment(AlignVCenter|AlignRight); + + air_channel_button[5]=new QPushButton(tr("Edit\nGPIOs"),this); + air_channel_button[5]->setGeometry(310,250,60,50); + air_channel_button[5]->setFont(small_font); + mapper->setMapping(air_channel_button[5],RDAirPlayConf::AuxLog2Channel); + connect(air_channel_button[5],SIGNAL(clicked()),mapper,SLOT(map())); + connect(air_card_sel[5],SIGNAL(settingsChanged(int,int,int)), + this,SLOT(audioSettingsChangedData(int,int,int))); + + // + // Audition/Cue Output + // + /* + label=new QLabel(tr("Audition/Cue Output"),this); + label->setFont(small_font); + label->setGeometry(25,304,200,16); + */ + air_card_sel[3]=new RDCardSelector(this); + air_card_sel[3]->setId(3); + air_card_sel[3]->setGeometry(20,322,120,117); + air_start_rml_edit[3]=new QLineEdit(this); + air_start_rml_edit[3]->setGeometry(210,322,160,19); + air_start_rml_edit[3]->setValidator(validator); + air_start_rml_label[3]=new QLabel(air_start_rml_edit[3],tr("Start RML:"),this); + air_start_rml_label[3]->setGeometry(140,322,65,19); + air_start_rml_label[3]->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[3]=new QLineEdit(this); + air_stop_rml_edit[3]->setGeometry(210,343,160,19); + air_stop_rml_edit[3]->setValidator(validator); + air_stop_rml_label[3]=new QLabel(air_start_rml_edit[3],tr("Stop RML:"),this); + air_stop_rml_label[3]->setGeometry(140,343,65,19); + air_stop_rml_label[3]->setAlignment(AlignVCenter|AlignRight); + + air_channel_button[3]=NULL; + connect(air_card_sel[3],SIGNAL(settingsChanged(int,int,int)), + this,SLOT(audioSettingsChangedData(int,int,int))); + air_card_sel[3]->hide(); + air_start_rml_edit[3]->hide(); + air_start_rml_label[3]->hide(); + air_stop_rml_edit[3]->hide(); + air_stop_rml_label[3]->hide(); + + // + // HotKeys Configuration Button + // + QPushButton *button=new QPushButton(this); + button->setGeometry(10,310,180,50); + button->setFont(small_font); + button->setText(tr("Configure Hot Keys")); + connect(button,SIGNAL(clicked()),this,SLOT(editHotKeys())); + + // + // Now & Next Button + // + button=new QPushButton(this); + button->setGeometry(200,310,180,50); + button->setFont(small_font); + button->setText(tr("Configure Now && Next\nParameters")); + connect(button,SIGNAL(clicked()),this,SLOT(nownextData())); + + // + // Sound Panel First Play Output + // + label=new QLabel(tr("SoundPanel First Play Output"),this); + label->setFont(small_font); + label->setGeometry(395,32,300,16); + air_card_sel[2]=new RDCardSelector(this); + air_card_sel[2]->setId(2); + air_card_sel[2]->setGeometry(390,50,120,117); + air_start_rml_edit[2]=new QLineEdit(this); + air_start_rml_edit[2]->setGeometry(580,50,95,19); + air_start_rml_edit[2]->setValidator(validator); + air_start_rml_label[2]=new QLabel(air_start_rml_edit[2],tr("Start RML:"),this); + air_start_rml_label[2]->setGeometry(510,50,65,19); + air_start_rml_label[2]->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[2]=new QLineEdit(this); + air_stop_rml_edit[2]->setGeometry(580,71,95,19); + air_stop_rml_edit[2]->setValidator(validator); + air_stop_rml_label[2]=new QLabel(air_start_rml_edit[2],tr("Stop RML:"),this); + air_stop_rml_label[2]->setGeometry(510,71,65,19); + air_stop_rml_label[2]->setAlignment(AlignVCenter|AlignRight); + + air_channel_button[2]=new QPushButton(tr("Edit\nGPIOs"),this); + air_channel_button[2]->setGeometry(680,46,60,50); + air_channel_button[2]->setFont(small_font); + mapper->setMapping(air_channel_button[2],RDAirPlayConf::SoundPanel1Channel); + connect(air_channel_button[2],SIGNAL(clicked()),mapper,SLOT(map())); + connect(air_card_sel[2],SIGNAL(settingsChanged(int,int,int)), + this,SLOT(audioSettingsChangedData(int,int,int))); + + // + // Sound Panel Second Play Output + // + label=new QLabel(tr("SoundPanel Second Play Output"),this); + label->setFont(small_font); + label->setGeometry(395,100,300,16); + air_card_sel[6]=new RDCardSelector(this); + air_card_sel[6]->setId(6); + air_card_sel[6]->setGeometry(390,118,120,117); + air_start_rml_edit[6]=new QLineEdit(this); + air_start_rml_edit[6]->setGeometry(580,118,95,19); + air_start_rml_edit[6]->setValidator(validator); + air_start_rml_label[6]=new QLabel(air_start_rml_edit[6],tr("Start RML:"),this); + air_start_rml_label[6]->setGeometry(510,118,65,19); + air_start_rml_label[6]->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[6]=new QLineEdit(this); + air_stop_rml_edit[6]->setGeometry(580,139,95,19); + air_stop_rml_edit[6]->setValidator(validator); + air_stop_rml_label[6]=new QLabel(air_start_rml_edit[6],tr("Stop RML:"),this); + air_stop_rml_label[6]->setGeometry(510,139,65,19); + air_stop_rml_label[6]->setAlignment(AlignVCenter|AlignRight); + + air_channel_button[6]=new QPushButton(tr("Edit\nGPIOs"),this); + air_channel_button[6]->setGeometry(680,114,60,50); + air_channel_button[6]->setFont(small_font); + mapper->setMapping(air_channel_button[6],RDAirPlayConf::SoundPanel2Channel); + connect(air_channel_button[6],SIGNAL(clicked()),mapper,SLOT(map())); + connect(air_card_sel[6],SIGNAL(settingsChanged(int,int,int)), + this,SLOT(audioSettingsChangedData(int,int,int))); + + // + // Sound Panel Third Play Output + // + label=new QLabel(tr("SoundPanel Third Play Output"),this); + label->setFont(small_font); + label->setGeometry(395,168,300,16); + air_card_sel[7]=new RDCardSelector(this); + air_card_sel[7]->setId(7); + air_card_sel[7]->setGeometry(390,186,120,117); + air_start_rml_edit[7]=new QLineEdit(this); + air_start_rml_edit[7]->setGeometry(580,186,95,19); + air_start_rml_edit[7]->setValidator(validator); + air_start_rml_label[7]=new QLabel(air_start_rml_edit[7],tr("Start RML:"),this); + air_start_rml_label[7]->setGeometry(510,186,65,19); + air_start_rml_label[7]->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[7]=new QLineEdit(this); + air_stop_rml_edit[7]->setGeometry(580,207,95,19); + air_stop_rml_edit[7]->setValidator(validator); + air_stop_rml_label[7]=new QLabel(air_start_rml_edit[7],tr("Stop RML:"),this); + air_stop_rml_label[7]->setGeometry(510,207,65,19); + air_stop_rml_label[7]->setAlignment(AlignVCenter|AlignRight); + + air_channel_button[7]=new QPushButton(tr("Edit\nGPIOs"),this); + air_channel_button[7]->setGeometry(680,182,60,50); + air_channel_button[7]->setFont(small_font); + mapper->setMapping(air_channel_button[7],RDAirPlayConf::SoundPanel3Channel); + connect(air_channel_button[7],SIGNAL(clicked()),mapper,SLOT(map())); + connect(air_card_sel[7],SIGNAL(settingsChanged(int,int,int)), + this,SLOT(audioSettingsChangedData(int,int,int))); + + // + // Sound Panel Fourth Play Output + // + label=new QLabel(tr("SoundPanel Fourth Play Output"),this); + label->setFont(small_font); + label->setGeometry(395,236,300,16); + air_card_sel[8]=new RDCardSelector(this); + air_card_sel[8]->setId(8); + air_card_sel[8]->setGeometry(390,254,120,117); + air_start_rml_edit[8]=new QLineEdit(this); + air_start_rml_edit[8]->setGeometry(580,254,95,19); + air_start_rml_edit[8]->setValidator(validator); + air_start_rml_label[8]=new QLabel(air_start_rml_edit[8],tr("Start RML:"),this); + air_start_rml_label[8]->setGeometry(510,254,65,19); + air_start_rml_label[8]->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[8]=new QLineEdit(this); + air_stop_rml_edit[8]->setGeometry(580,275,95,19); + air_stop_rml_edit[8]->setValidator(validator); + air_stop_rml_label[8]=new QLabel(air_start_rml_edit[8],tr("Stop RML:"),this); + air_stop_rml_label[8]->setGeometry(510,275,65,19); + air_stop_rml_label[8]->setAlignment(AlignVCenter|AlignRight); + + air_channel_button[8]=new QPushButton(tr("Edit\nGPIOs"),this); + air_channel_button[8]->setGeometry(680,250,60,50); + air_channel_button[8]->setFont(small_font); + mapper->setMapping(air_channel_button[8],RDAirPlayConf::SoundPanel4Channel); + connect(air_channel_button[8],SIGNAL(clicked()),mapper,SLOT(map())); + connect(air_card_sel[8],SIGNAL(settingsChanged(int,int,int)), + this,SLOT(audioSettingsChangedData(int,int,int))); + + // + // Sound Panel Fifth Play Output + // + label=new QLabel(tr("SoundPanel Fifth and Later Play Output"),this); + label->setFont(small_font); + label->setGeometry(395,304,300,16); + air_card_sel[9]=new RDCardSelector(this); + air_card_sel[9]->setId(9); + air_card_sel[9]->setGeometry(390,322,120,117); + air_start_rml_edit[9]=new QLineEdit(this); + air_start_rml_edit[9]->setGeometry(580,322,95,19); + air_start_rml_edit[9]->setValidator(validator); + air_start_rml_label[9]=new QLabel(air_start_rml_edit[9],tr("Start RML:"),this); + air_start_rml_label[9]->setGeometry(510,322,65,19); + air_start_rml_label[9]->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[9]=new QLineEdit(this); + air_stop_rml_edit[9]->setGeometry(580,343,95,19); + air_stop_rml_edit[9]->setValidator(validator); + air_stop_rml_label[9]=new QLabel(air_start_rml_edit[9],tr("Stop RML:"),this); + air_stop_rml_label[9]->setGeometry(510,343,65,19); + air_stop_rml_label[9]->setAlignment(AlignVCenter|AlignRight); + + air_channel_button[9]=new QPushButton(tr("Edit\nGPIOs"),this); + air_channel_button[9]->setGeometry(680,318,60,50); + air_channel_button[9]->setFont(small_font); + mapper->setMapping(air_channel_button[9],RDAirPlayConf::SoundPanel5Channel); + connect(air_channel_button[9],SIGNAL(clicked()),mapper,SLOT(map())); + connect(air_card_sel[9],SIGNAL(settingsChanged(int,int,int)), + this,SLOT(audioSettingsChangedData(int,int,int))); + + // + // Main Log Play Section + // + label=new QLabel("Log Settings",this); + label->setFont(big_font); + label->setGeometry(805,10,200,16); + + // + // Segue Length + // + air_segue_edit=new QLineEdit(this); + air_segue_edit->setGeometry(895,32,50,20); + air_segue_label=new QLabel(air_segue_edit,tr("Manual Segue:"),this); + air_segue_label->setGeometry(790,32,100,20); + air_segue_label->setAlignment(AlignRight|AlignVCenter); + air_segue_unit=new QLabel(air_segue_edit,tr("msecs"),this); + air_segue_unit->setGeometry(950,32,40,20); + air_segue_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Forced Transition Length + // + air_trans_edit=new QLineEdit(this); + air_trans_edit->setGeometry(895,54,50,20); + air_trans_label=new QLabel(air_trans_edit,tr("Forced Segue:"),this); + air_trans_label->setGeometry(790,54,100,20); + air_trans_label->setAlignment(AlignRight|AlignVCenter); + air_trans_unit=new QLabel(air_trans_edit,tr("msecs"),this); + air_trans_unit->setGeometry(950,54,40,20); + air_trans_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Pie Countdown Length + // + air_piecount_box=new QSpinBox(this); + air_piecount_box->setGeometry(895,76,50,20); + air_piecount_box->setRange(0,60); + air_piecount_label=new QLabel(air_piecount_box,tr("Pie Counts Last:"),this); + air_piecount_label->setGeometry(785,76,105,20); + air_piecount_label->setAlignment(AlignRight|AlignVCenter); + air_piecount_unit=new QLabel(tr("secs"),this); + air_piecount_unit->setGeometry(950,76,40,20); + air_piecount_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Pie Countdown To + // + air_countto_box=new QComboBox(this); + air_countto_box->setGeometry(895,98,100,20); + air_countto_label=new QLabel(air_countto_box,tr("Pie Counts To:"),this); + air_countto_label->setGeometry(785,98,105,20); + air_countto_label->setAlignment(AlignRight|AlignVCenter); + air_countto_box->insertItem(tr("Cart End")); + air_countto_box->insertItem(tr("Transition")); + + // + // Default Transition Type + // + air_default_transtype_box=new QComboBox(this); + air_default_transtype_box->setGeometry(895,120,100,20); + label=new QLabel(air_default_transtype_box,tr("Default Trans. Type:"),this); + label->setGeometry(760,120,130,20); + label->setAlignment(AlignRight|AlignVCenter); + air_default_transtype_box->insertItem(tr("Play")); + air_default_transtype_box->insertItem(tr("Segue")); + air_default_transtype_box->insertItem(tr("Stop")); + + // + // Default Service + // + air_defaultsvc_box=new QComboBox(this); + air_defaultsvc_box->setGeometry(895,142,100,20); + label=new QLabel(air_defaultsvc_box,tr("Default Service:"),this); + label->setGeometry(760,142,130,20); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Sound Panel Section + // + label=new QLabel(tr("Sound Panel Settings"),this); + label->setFont(big_font); + label->setGeometry(805,179,200,16); + + // + // # of Station Panels + // + air_station_box=new QSpinBox(this); + air_station_box->setGeometry(895,204,50,20); + air_station_box->setRange(0,MAX_PANELS); + air_station_box->setSpecialValueText(tr("None")); + air_station_label=new QLabel(air_station_box,tr("Host Panels:"),this); + air_station_label->setGeometry(790,204,100,20); + air_station_label->setAlignment(AlignRight|AlignVCenter); + + // + // # of User Panels + // + air_user_box=new QSpinBox(this); + air_user_box->setGeometry(895,226,50,20); + air_user_box->setRange(0,MAX_PANELS); + air_user_box->setSpecialValueText(tr("None")); + air_user_label=new QLabel(air_user_box,tr("User Panels:"),this); + air_user_label->setGeometry(790,226,100,20); + air_user_label->setAlignment(AlignRight|AlignVCenter); + + // + // Flash Active Button + // + air_flash_box=new QCheckBox(this); + air_flash_box->setGeometry(810,254,15,15); + label=new QLabel(air_flash_box,tr("Flash Active Buttons"),this); + label->setGeometry(830,254,150,15); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Pause Panel Button + // + air_panel_pause_box=new QCheckBox(this); + air_panel_pause_box->setGeometry(810,276,15,15); + label=new QLabel(air_panel_pause_box,tr("Enable Button Pausing"),this); + label->setGeometry(830,276,150,15); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Label Template + // + air_label_template_edit=new QLineEdit(this); + air_label_template_edit->setGeometry(895,298,sizeHint().width()-910,20); + label=new QLabel(air_label_template_edit,tr("Label Template:"),this); + label->setGeometry(790,298,100,20); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Miscellaneous Section + // + label=new QLabel(tr("Miscellaneous Settings"),this); + label->setFont(big_font); + label->setGeometry(805,330,200,16); + + // + // Check Timesync + // + air_timesync_box=new QCheckBox(this); + air_timesync_box->setGeometry(810,356,15,15); + air_timesync_label=new QLabel(air_timesync_box,tr("Check TimeSync"),this); + air_timesync_label->setGeometry(830,356,100,15); + air_timesync_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Show Log Buttons + // + air_auxlog_box[0]=new QCheckBox(this); + air_auxlog_box[0]->setGeometry(810,378,15,15); + label=new QLabel(air_auxlog_box[0],tr("Show Auxlog 1 Button"),this); + label->setGeometry(830,378,150,15); + label->setAlignment(AlignLeft|AlignVCenter); + + air_auxlog_box[1]=new QCheckBox(this); + air_auxlog_box[1]->setGeometry(810,400,15,15); + label=new QLabel(air_auxlog_box[1],tr("Show Auxlog 2 Button"),this); + label->setGeometry(830,400,150,15); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Clear Cart Filter + // + air_clearfilter_box=new QCheckBox(this); + air_clearfilter_box->setGeometry(810,422,15,15); + label=new QLabel(air_clearfilter_box,tr("Clear Cart Search Filter"),this); + label->setGeometry(830,422,150,15); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Pause Enable Checkbox + // + air_pause_box=new QCheckBox(this); + air_pause_box->setGeometry(810,444,15,15); + label=new QLabel(air_pause_box,tr("Enable Paused Events"),this); + label->setGeometry(830,444,150,15); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Show Extra Counters/Buttons + // + air_show_counters_box=new QCheckBox(this); + air_show_counters_box->setGeometry(810,466,15,15); + label= + new QLabel(air_show_counters_box,tr("Show Extra Buttons/Counters"),this); + label->setGeometry(830,466,170,15); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Show Hour Selector + // + air_hour_selector_box=new QCheckBox(this); + air_hour_selector_box->setGeometry(810,488,15,15); + label=new QLabel(air_hour_selector_box,tr("Show Hour Selector"),this); + label->setGeometry(830,488,170,15); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Audition Preroll + // + air_audition_preroll_spin=new QSpinBox(this); + air_audition_preroll_spin->setGeometry(895,507,45,20); + air_audition_preroll_spin->setRange(1,60); + air_audition_preroll_label= + new QLabel(air_audition_preroll_spin,tr("Audition Preroll:"),this); + air_audition_preroll_label->setGeometry(800,510,90,15); + air_audition_preroll_label->setAlignment(AlignRight|AlignVCenter); + air_audition_preroll_unit=new QLabel(tr("secs"),this); + air_audition_preroll_unit->setGeometry(945,510,100,15); + air_audition_preroll_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Space Bar Action + // + air_bar_group=new QButtonGroup(1,Qt::Vertical,tr("Space Bar Action"),this); + air_bar_group->setGeometry(805,532,sizeHint().width()-815,55); + QRadioButton *rbutton= + new QRadioButton(tr("None"),air_bar_group); + rbutton=new QRadioButton(tr("Start Next"),air_bar_group); + + // + // Start/Stop Section + // + label=new QLabel(tr("Start/Stop Settings"),this); + label->setFont(big_font); + label->setGeometry(10,381,200,16); + + // + // Exit Password + // + air_exitpasswd_edit=new QLineEdit(this); + air_exitpasswd_edit->setGeometry(100,404,sizeHint().width()-905,20); + air_exitpasswd_edit->setEchoMode(QLineEdit::Password); + air_exitpasswd_edit->setText("******"); + label=new QLabel(air_exitpasswd_edit,tr("Exit Password:"),this); + label->setGeometry(0,404,95,20); + label->setAlignment(AlignRight|AlignVCenter); + connect(air_exitpasswd_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(exitPasswordChangedData(const QString &))); + + // + // Log Machine Selector + // + air_logmachine_box=new QComboBox(this); + air_logmachine_box->setGeometry(45,429,100,20); + air_logmachine_box->insertItem(tr("Main Log")); + for(unsigned i=1;iinsertItem(QString().sprintf("Aux %d Log",i)); + } + connect(air_logmachine_box,SIGNAL(activated(int)), + this,SLOT(logActivatedData(int))); + + // + // Startup Mode + // + air_startmode_box=new QComboBox(this); + air_startmode_box->setGeometry(100,454,240,20); + air_startmode_box->insertItem(tr("start with empty log")); + air_startmode_box->insertItem(tr("load previous log")); + air_startmode_box->insertItem(tr("load specified log")); + label=new QLabel(air_exitpasswd_edit,tr("At Startup:"),this); + label->setGeometry(30,454,65,20); + label->setAlignment(AlignRight|AlignVCenter); + connect(air_startmode_box,SIGNAL(activated(int)), + this,SLOT(startModeChangedData(int))); + + // + // Auto Restart Checkbox + // + air_autorestart_box=new QCheckBox(this); + air_autorestart_box->setGeometry(105,479,15,15); + air_autorestart_label= + new QLabel(air_autorestart_box, + tr("Restart Log After Unclean Shutdown"),this); + air_autorestart_label->setGeometry(125,479,250,15); + air_autorestart_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Startup Log + // + air_startlog_edit=new QLineEdit(this); + air_startlog_edit->setGeometry(100,499,240,20); + air_startlog_label=new QLabel(air_startlog_edit,tr("Log:"),this); + air_startlog_label->setGeometry(30,499,65,20); + air_startlog_label->setAlignment(AlignRight|AlignVCenter); + + // + // Log Select Button + // + air_startlog_button=new QPushButton(this); + air_startlog_button->setGeometry(350,497,50,24); + air_startlog_button->setFont(small_font); + air_startlog_button->setText(tr("&Select")); + connect(air_startlog_button,SIGNAL(clicked()),this,SLOT(selectData())); + + // + // Display Settings Section + // + label=new QLabel(tr("Display Settings"),this,"globals_label"); + label->setFont(big_font); + label->setGeometry(435,381,200,16); + + // + // Skin Path + // + air_skin_edit=new QLineEdit(this); + air_skin_edit->setGeometry(555,403,180,20); + label=new QLabel(air_skin_edit,tr("Background Image:"),this); + label->setGeometry(435,403,115,20); + label->setAlignment(AlignRight|AlignVCenter); + button=new QPushButton(tr("Select"),this); + button->setGeometry(745,400,50,25); + connect(button,SIGNAL(clicked()),this,SLOT(selectSkinData())); + + // + // Title Template + // + air_title_template_edit=new QLineEdit(this); + air_title_template_edit->setGeometry(555,425,180,20); + label=new QLabel(air_label_template_edit,tr("Title Template:"),this); + label->setGeometry(430,425,120,20); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Artist Template + // + air_artist_template_edit=new QLineEdit(this); + air_artist_template_edit->setGeometry(555,447,180,20); + label=new QLabel(air_label_template_edit,tr("Artist Template:"),this); + label->setGeometry(430,447,120,20); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Outcue Template + // + air_outcue_template_edit=new QLineEdit(this); + air_outcue_template_edit->setGeometry(555,469,180,20); + label=new QLabel(air_label_template_edit,tr("Outcue Template:"),this); + label->setGeometry(430,469,120,20); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Description Template + // + air_description_template_edit=new QLineEdit(this); + air_description_template_edit->setGeometry(555,491,180,20); + label=new QLabel(air_label_template_edit,tr("Description Template:"),this); + label->setGeometry(430,491,120,20); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Log Mode Control Section + // + label=new QLabel(tr("Log Mode Control"),this); + label->setFont(big_font); + label->setGeometry(435,530,200,16); + + // + // Mode Control Style + // + air_modecontrol_box=new QComboBox(this); + air_modecontrol_box->setGeometry(560,550,110,20); + connect(air_modecontrol_box,SIGNAL(activated(int)), + this,SLOT(modeControlActivatedData(int))); + label=new QLabel(air_modecontrol_box,tr("Mode Control Style:"),this); + label->setGeometry(435,550,120,20); + label->setAlignment(AlignRight|AlignVCenter); + air_modecontrol_box->insertItem(tr("Unified")); + air_modecontrol_box->insertItem(tr("Independent")); + + // + // Startup Mode + // + for(int i=0;i<3;i++) { + air_logstartmode_box[i]=new QComboBox(this); + air_logstartmode_box[i]->setGeometry(615,572+i*22,110,20); + connect(air_logstartmode_box[i],SIGNAL(activated(int)), + this,SLOT(logStartupModeActivatedData(int))); + air_logstartmode_label[i]=new QLabel(air_logstartmode_box[i],"",this); + air_logstartmode_label[i]->setGeometry(470,572+i*22,140,20); + air_logstartmode_label[i]->setAlignment(AlignRight|AlignVCenter); + air_logstartmode_box[i]->insertItem(tr("Previous")); + air_logstartmode_box[i]->insertItem(tr("LiveAssist")); + air_logstartmode_box[i]->insertItem(tr("Automatic")); + air_logstartmode_box[i]->insertItem(tr("Manual")); + } + air_logstartmode_label[0]->setText(tr("Main Log Startup Mode:")); + air_logstartmode_label[1]->setText(tr("Aux 1 Log Startup Mode:")); + air_logstartmode_label[2]->setText(tr("Aux 2 Log Startup Mode:")); + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(small_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(small_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + if(cae_station->scanned()) { + for(int i=0;i<10;i++) { + air_card_sel[i]->setMaxCards(cae_station->cards()); + for(int j=0;jmaxCards();j++) { + air_card_sel[i]->setMaxPorts(j,cae_station->cardOutputs(j)); + } + } + } + else { + QMessageBox::information(this,tr("No Audio Configuration Data"), + tr("Channel assignments will not be available for this host as audio resource data\nhas not yet been generated. Please start the Rivendell daemons on the host\nconfigured to run the CAE service in order to populate the audio resources database.")); + for(int i=0;i<10;i++) { + air_card_sel[i]->setDisabled(true); + } + } + for(int i=0;isetCard(air_conf->card((RDAirPlayConf::Channel)i)); + air_card_sel[i]->setPort(air_conf->port((RDAirPlayConf::Channel)i)); + } + air_segue_edit->setText(QString().sprintf("%d",air_conf->segueLength())); + air_trans_edit->setText(QString().sprintf("%d",air_conf->transLength())); + air_piecount_box->setValue(air_conf->pieCountLength()/1000); + air_countto_box->setCurrentItem(air_conf->pieEndPoint()); + air_default_transtype_box->setCurrentItem(air_conf->defaultTransType()); + air_defaultsvc_box->insertItem(tr("[none]")); + QString defaultsvc=air_conf->defaultSvc(); + sql=QString().sprintf("select SERVICE_NAME from SERVICE_PERMS \ + where STATION_NAME=\"%s\"", + (const char *)air_conf->station()); + q=new RDSqlQuery(sql); + while(q->next()) { + air_defaultsvc_box->insertItem(q->value(0).toString()); + if(defaultsvc==q->value(0).toString()) { + air_defaultsvc_box->setCurrentItem(air_defaultsvc_box->count()-1); + } + } + delete q; + air_station_box->setValue(air_conf->panels(RDAirPlayConf::StationPanel)); + air_user_box->setValue(air_conf->panels(RDAirPlayConf::UserPanel)); + air_timesync_box->setChecked(air_conf->checkTimesync()); + for(int i=0;i<2;i++) { + air_auxlog_box[i]->setChecked(air_conf->showAuxButton(i)); + } + air_clearfilter_box->setChecked(air_conf->clearFilter()); + air_bar_group->setButton((int)air_conf->barAction()); + air_flash_box->setChecked(air_conf->flashPanel()); + air_panel_pause_box->setChecked(air_conf->panelPauseEnabled()); + air_label_template_edit->setText(air_conf->buttonLabelTemplate()); + air_pause_box->setChecked(air_conf->pauseEnabled()); + air_show_counters_box->setChecked(air_conf->showCounters()); + air_hour_selector_box->setChecked(air_conf->hourSelectorEnabled()); + air_audition_preroll_spin->setValue(air_conf->auditionPreroll()/1000); + air_title_template_edit->setText(air_conf->titleTemplate()); + air_artist_template_edit->setText(air_conf->artistTemplate()); + air_outcue_template_edit->setText(air_conf->outcueTemplate()); + air_description_template_edit->setText(air_conf->descriptionTemplate()); + for(int i=0;isetText(air_conf-> + startRml((RDAirPlayConf::Channel)i)); + air_stop_rml_edit[i]->setText(air_conf-> + stopRml((RDAirPlayConf::Channel)i)); + } + air_modecontrol_box->setCurrentItem((int)air_conf->opModeStyle()); + for(int i=0;istartMode(i); + air_startlog[i]=air_conf->logName(i); + air_autorestart[i]=air_conf->autoRestart(i); + air_logstartmode_box[i]->setCurrentItem(air_conf->logStartMode(i)); + } + air_startmode_box->setCurrentItem((int)air_startmode[air_logmachine]); + air_startlog_edit->setText(air_startlog[air_logmachine]); + air_autorestart_box->setChecked(air_autorestart[air_logmachine]); + air_skin_edit->setText(air_conf->skinPath()); + startModeChangedData(air_startmode[air_logmachine]); + + for(unsigned i=0;icard(),air_card_sel[i]->port()); + } +} + + +EditRDAirPlay::~EditRDAirPlay() +{ +} + + +QSize EditRDAirPlay::sizeHint() const +{ + return QSize(1010,660); +} + + +QSizePolicy EditRDAirPlay::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditRDAirPlay::audioSettingsChangedData(int id,int card,int port) +{ + if(air_channel_button[id]!=NULL) { + bool state=air_card_sel[id]->isDisabled(); + air_start_rml_label[id]->setDisabled(state); + air_start_rml_edit[id]->setDisabled(state); + air_stop_rml_label[id]->setDisabled(state); + air_stop_rml_edit[id]->setDisabled(state); + if((id==RDAirPlayConf::MainLog1Channel)|| + (id==RDAirPlayConf::MainLog2Channel)) { + air_channel_button[RDAirPlayConf::MainLog1Channel]-> + setDisabled(air_card_sel[RDAirPlayConf::MainLog1Channel]->isDisabled()); + bool state2=(air_card_sel[RDAirPlayConf::MainLog2Channel]->isDisabled()) + ||((air_card_sel[RDAirPlayConf::MainLog1Channel]->card()== + air_card_sel[RDAirPlayConf::MainLog2Channel]->card())&& + (air_card_sel[RDAirPlayConf::MainLog1Channel]->port()== + air_card_sel[RDAirPlayConf::MainLog2Channel]->port())); + air_channel_button[RDAirPlayConf::MainLog2Channel]->setDisabled(state2); + air_start_rml_label[RDAirPlayConf::MainLog2Channel]->setDisabled(state2); + air_start_rml_edit[RDAirPlayConf::MainLog2Channel]->setDisabled(state2); + air_stop_rml_label[RDAirPlayConf::MainLog2Channel]->setDisabled(state2); + air_stop_rml_edit[RDAirPlayConf::MainLog2Channel]->setDisabled(state2); + } + else { + air_channel_button[id]->setDisabled(air_card_sel[id]->isDisabled()); + } + } +} + + +void EditRDAirPlay::editGpiosData(int num) +{ + EditChannelGpios *d= + new EditChannelGpios(air_conf,(RDAirPlayConf::Channel)num,this); + d->exec(); + delete d; +} + + +void EditRDAirPlay::exitPasswordChangedData(const QString &str) +{ + air_exitpasswd_changed=true; +} + + +void EditRDAirPlay::logActivatedData(int lognum) +{ + air_startmode[air_logmachine]= + (RDAirPlayConf::StartMode)air_startmode_box->currentItem(); + air_startlog[air_logmachine]=air_startlog_edit->text(); + air_autorestart[air_logmachine]=air_autorestart_box->isChecked(); + + air_logmachine=lognum; + air_startmode_box->setCurrentItem((int)air_startmode[lognum]); + air_startlog_edit->setText(air_startlog[lognum]); + air_autorestart_box->setChecked(air_autorestart[lognum]); + startModeChangedData((int)air_startmode[lognum]); +} + + +void EditRDAirPlay::startModeChangedData(int mode) +{ + air_startlog_edit->setEnabled((RDAirPlayConf::StartMode)mode== + RDAirPlayConf::StartSpecified); + air_startlog_label->setEnabled((RDAirPlayConf::StartMode)mode== + RDAirPlayConf::StartSpecified); + air_startlog_button->setEnabled((RDAirPlayConf::StartMode)mode== + RDAirPlayConf::StartSpecified); + air_autorestart_box->setDisabled((RDAirPlayConf::StartMode)mode== + RDAirPlayConf::StartEmpty); + air_autorestart_label->setDisabled((RDAirPlayConf::StartMode)mode== + RDAirPlayConf::StartEmpty); +} + + +void EditRDAirPlay::selectData() +{ + QString logname=air_startlog_edit->text(); + + RDListLogs *ll=new RDListLogs(&logname,air_conf->station(),this, + "log",admin_user); + if(ll->exec()==0) { + air_startlog_edit->setText(logname); + } + delete ll; +} + + +void EditRDAirPlay::nownextData() +{ + EditNowNext *edit=new EditNowNext(air_conf,this,"edit"); + edit->exec(); + delete edit; +} + +void EditRDAirPlay::editHotKeys() +{ + QString module_name = QString("airplay"); + EditHotkeys *edit_hotkeys=new EditHotkeys(air_conf->station(), + (const char *)module_name, + this,"hotkeys"); + edit_hotkeys->exec(); + delete edit_hotkeys; +} + + +void EditRDAirPlay::selectSkinData() +{ + QString filename=air_skin_edit->text(); + filename=QFileDialog::getOpenFileName(filename,RD_IMAGE_FILE_FILTER,this,"", + tr("Select Image File")); + if(!filename.isNull()) { + air_skin_edit->setText(filename); + } +} + + +void EditRDAirPlay::modeControlActivatedData(int n) +{ + if(n==0) { + for(int i=1;i + setCurrentItem(air_logstartmode_box[0]->currentItem()); + } + } +} + + +void EditRDAirPlay::logStartupModeActivatedData(int n) +{ + if(air_modecontrol_box->currentItem()==0) { + for(int i=0;isetCurrentItem(n); + } + } +} + + +void EditRDAirPlay::okData() +{ + bool ok=false; + int segue=air_segue_edit->text().toInt(&ok); + if(!ok) { + QMessageBox::warning(this,tr("Data Error"),tr("Invalid Segue Length!")); + return; + } + int trans=air_trans_edit->text().toInt(&ok); + if(!ok) { + QMessageBox::warning(this,tr("Data Error"), + tr("Invalid Forced Segue Length!")); + return; + } + for(int i=0;isetStartRml(chan,air_start_rml_edit[i]->text()); + air_conf->setStopRml(chan,air_stop_rml_edit[i]->text()); + air_conf->setCard(chan,air_card_sel[i]->card()); + air_conf->setPort(chan,air_card_sel[i]->port()); + if(air_card_sel[i]->isDisabled()) { + air_conf->setStartGpiMatrix(chan,-1); + air_conf->setStartGpoMatrix(chan,-1); + air_conf->setStopGpiMatrix(chan,-1); + air_conf->setStopGpoMatrix(chan,-1); + } + } + air_conf->setSegueLength(segue); + air_conf->setTransLength(trans); + air_conf->setPieCountLength(air_piecount_box->value()*1000); + air_conf-> + setPieEndPoint((RDAirPlayConf::PieEndPoint)air_countto_box->currentItem()); + air_conf->setDefaultTransType((RDLogLine::TransType) + air_default_transtype_box->currentItem()); + if(air_defaultsvc_box->currentItem()==0) { + air_conf->setDefaultSvc(""); + } + else { + air_conf->setDefaultSvc(air_defaultsvc_box->currentText()); + } + air_conf->setPanels(RDAirPlayConf::StationPanel,air_station_box->value()); + air_conf->setPanels(RDAirPlayConf::UserPanel,air_user_box->value()); + air_conf->setCheckTimesync(air_timesync_box->isChecked()); + for(int i=0;i<2;i++) { + air_conf->setShowAuxButton(i,air_auxlog_box[i]->isChecked()); + } + air_conf->setClearFilter(air_clearfilter_box->isChecked()); + air_conf-> + setBarAction((RDAirPlayConf::BarAction)air_bar_group->selectedId()); + air_conf->setFlashPanel(air_flash_box->isChecked()); + air_conf->setPanelPauseEnabled(air_panel_pause_box->isChecked()); + air_conf->setButtonLabelTemplate(air_label_template_edit->text()); + air_conf->setPauseEnabled(air_pause_box->isChecked()); + air_conf->setShowCounters(air_show_counters_box->isChecked()); + air_conf->setHourSelectorEnabled(air_hour_selector_box->isChecked()); + air_conf->setAuditionPreroll(air_audition_preroll_spin->value()*1000); + air_conf->setTitleTemplate(air_title_template_edit->text()); + air_conf->setArtistTemplate(air_artist_template_edit->text()); + air_conf->setOutcueTemplate(air_outcue_template_edit->text()); + air_conf->setDescriptionTemplate(air_description_template_edit->text()); + if(air_exitpasswd_changed) { + air_conf->setExitPassword(air_exitpasswd_edit->text()); + } + air_startmode[air_logmachine]= + (RDAirPlayConf::StartMode)air_startmode_box->currentItem(); + air_startlog[air_logmachine]=air_startlog_edit->text(); + air_autorestart[air_logmachine]=air_autorestart_box->isChecked(); + air_conf->setOpModeStyle((RDAirPlayConf::OpModeStyle) + air_modecontrol_box->currentItem()); + for(int i=0;isetStartMode(i,air_startmode[i]); + air_conf->setLogName(i,air_startlog[i]); + air_conf->setAutoRestart(i,air_autorestart[i]); + air_conf-> + setLogStartMode(i,(RDAirPlayConf::OpMode)air_logstartmode_box[i]-> + currentItem()); + } + air_conf->setSkinPath(air_skin_edit->text()); + done(0); +} + + +void EditRDAirPlay::cancelData() +{ + done(1); +} + + +void EditRDAirPlay::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(black); + p->drawRect(25,415,395,95); + p->end(); + delete p; +} diff --git a/rdadmin/edit_rdairplay.h b/rdadmin/edit_rdairplay.h new file mode 100644 index 00000000..e228fe4a --- /dev/null +++ b/rdadmin/edit_rdairplay.h @@ -0,0 +1,145 @@ +// edit_rdairplay.h +// +// Edit an RDAirPlay Configuration +// +// (C) Copyright 2002-2010 Fred Gleason +// +// $Id: edit_rdairplay.h,v 1.29.6.5 2014/02/10 20:45:10 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_RDAIRPLAY_H +#define EDIT_RDAIRPLAY_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Application Settings + */ +#define LOG_PLAY_PORTS 2 +#define MAX_MANUAL_SEGUE 10 + +class EditRDAirPlay : public QDialog +{ + Q_OBJECT + public: + EditRDAirPlay(RDStation *station,RDStation *cae_station, + QWidget *parent=0,const char *name=0); + ~EditRDAirPlay(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void audioSettingsChangedData(int id,int card,int port); + void editGpiosData(int num); + void exitPasswordChangedData(const QString &str); + void logActivatedData(int lognum); + void startModeChangedData(int mode); + void selectData(); + void nownextData(); + void editHotKeys(); + void selectSkinData(); + void modeControlActivatedData(int n); + void logStartupModeActivatedData(int n); + void okData(); + void cancelData(); + + protected: + void paintEvent(QPaintEvent *e); + + private: + RDAirPlayConf *air_conf; + RDCardSelector *air_card_sel[RDAirPlayConf::LastChannel]; + QLabel *air_start_rml_label[RDAirPlayConf::LastChannel]; + QLineEdit *air_start_rml_edit[RDAirPlayConf::LastChannel]; + QLabel *air_stop_rml_label[RDAirPlayConf::LastChannel]; + QLineEdit *air_stop_rml_edit[RDAirPlayConf::LastChannel]; + QPushButton *air_channel_button[RDAirPlayConf::LastChannel]; + // QLabel *air_startup_label; + // QComboBox *air_startup_box; + QLabel *air_segue_label; + QLineEdit *air_segue_edit; + QLabel *air_trans_label; + QLineEdit *air_trans_edit; + QLabel *air_trans_unit; + QLabel *air_piecount_label; + QSpinBox *air_piecount_box; + QLabel *air_piecount_unit; + QLabel *air_countto_label; + QComboBox *air_countto_box; + QLabel *air_segue_unit; + QLabel *air_station_label; + QSpinBox *air_station_box; + QLabel *air_user_label; + QSpinBox *air_user_box; + QLabel *air_timesync_label; + QCheckBox *air_timesync_box; + QLabel *air_aux1_label; + QSpinBox *air_aux1_box; + QLabel *air_aux2_label; + QSpinBox *air_aux2_box; + QCheckBox *air_auxlog_box[2]; + QCheckBox *air_clearfilter_box; + QButtonGroup *air_bar_group; + QCheckBox *air_flash_box; + QCheckBox *air_panel_pause_box; + QCheckBox *air_show_counters_box; + QLabel *air_audition_preroll_label; + QLabel *air_audition_preroll_unit; + QSpinBox *air_audition_preroll_spin; + QLineEdit *air_label_template_edit; + QCheckBox *air_pause_box; + QCheckBox *air_hour_selector_box; + QComboBox *air_default_transtype_box; + QComboBox *air_defaultsvc_box; + QLineEdit *air_exitpasswd_edit; + bool air_exitpasswd_changed; + int air_logmachine; + QComboBox *air_logmachine_box; + QComboBox *air_startmode_box; + RDAirPlayConf::StartMode air_startmode[RDAIRPLAY_LOG_QUANTITY]; + QLineEdit *air_startlog_edit; + QLabel *air_startlog_label; + QPushButton *air_startlog_button; + QString air_startlog[RDAIRPLAY_LOG_QUANTITY]; + QCheckBox *air_autorestart_box; + bool air_autorestart[RDAIRPLAY_LOG_QUANTITY]; + QLabel *air_autorestart_label; + QLineEdit *air_skin_edit; + QLineEdit *air_title_template_edit; + QLineEdit *air_artist_template_edit; + QLineEdit *air_outcue_template_edit; + QLineEdit *air_description_template_edit; + QComboBox *air_modecontrol_box; + QLabel *air_logstartmode_label[RDAIRPLAY_LOG_QUANTITY]; + QComboBox *air_logstartmode_box[RDAIRPLAY_LOG_QUANTITY]; +}; + + +#endif // EDIT_RDAIRPLAY_H + diff --git a/rdadmin/edit_rdlibrary.cpp b/rdadmin/edit_rdlibrary.cpp new file mode 100644 index 00000000..1747d3a6 --- /dev/null +++ b/rdadmin/edit_rdlibrary.cpp @@ -0,0 +1,624 @@ +// edit_rdlibrary.cpp +// +// Edit an RDLibrary Configuration +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: edit_rdlibrary.cpp,v 1.33.6.1 2014/01/09 01:03:55 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +EditRDLibrary::EditRDLibrary(RDStation *station,RDStation *cae_station, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + lib_lib=new RDLibraryConf(station->name(),0); + + // + // Create Fonts + // + QFont small_font=QFont("Helvetica",12,QFont::Bold); + small_font.setPixelSize(12); + QFont big_font=QFont("Helvetica",14,QFont::Bold); + big_font.setPixelSize(14); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Dialog Name + // + setCaption(tr("RDLibrary config for ")+station->name()); + + // + // Input Configuration + // + lib_input_card=new RDCardSelector(this,"lib_input_card"); + lib_input_card->setGeometry(10,29,120,117); + QLabel *label=new QLabel(lib_input_card,tr("INPUT"),this,"lib_input_label"); + label->setGeometry(10,10,110,19); + label->setFont(big_font); + label->setAlignment(AlignCenter); + + // + // Output Configuration + // + lib_output_card=new RDCardSelector(this,"lib_output_card"); + lib_output_card->setGeometry(170,29,120,87); + label=new QLabel(lib_output_card,tr("OUTPUT"),this,"lib_output_label"); + label->setGeometry(170,10,110,19); + label->setFont(big_font); + label->setAlignment(AlignCenter); + + // + // Settings + // + QLabel *setting_label=new QLabel(tr("Settings"),this,"setting_label"); + setting_label->setGeometry(25,79,120,19); + setting_label->setFont(big_font); + setting_label->setAlignment(AlignRight|ShowPrefix); + + // + // Maximum Record Length + // + lib_maxlength_time=new QTimeEdit(this,"lib_maxlength_time"); + lib_maxlength_time->setGeometry(160,100,85,19); + QLabel *lib_maxlength_label=new QLabel(lib_maxlength_time, + tr("&Max Record Time:"),this, + "lib_maxlength_label"); + lib_maxlength_label->setGeometry(25,101,130,19); + lib_maxlength_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // VOX threshold + // + lib_vox_spin=new QSpinBox(this,"lib_vox_spin"); + lib_vox_spin->setGeometry(160,122,40,19); + lib_vox_spin->setMinValue(-99); + lib_vox_spin->setMaxValue(0); + QLabel *lib_vox_spin_label=new QLabel(lib_vox_spin,tr("&VOX Threshold:"), + this,"lib_vox_spin_label"); + lib_vox_spin_label->setGeometry(25,122,130,19); + lib_vox_spin_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QLabel *lib_vox_spin_unit=new QLabel(tr("dbFS"),this,"lib_vox_spin_unit"); + lib_vox_spin_unit->setGeometry(205,122,120,19); + lib_vox_spin_unit->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // AutoTrim threshold + // + lib_trim_spin=new QSpinBox(this,"lib_trim_spin"); + lib_trim_spin->setGeometry(160,144,40,19); + lib_trim_spin->setMinValue(-99); + lib_trim_spin->setMaxValue(0); + QLabel *lib_trim_spin_label= + new QLabel(lib_trim_spin,tr("&AutoTrim Threshold:"), + this,"lib_trim_spin_label"); + lib_trim_spin_label->setGeometry(25,144,130,19); + lib_trim_spin_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QLabel *lib_trim_spin_unit=new QLabel(tr("dbFS"),this,"lib_trim_spin_unit"); + lib_trim_spin_unit->setGeometry(205,144,120,19); + lib_trim_spin_unit->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Tail Preroll + // + lib_preroll_spin=new QSpinBox(this,"lib_preroll_spin"); + lib_preroll_spin->setGeometry(160,166,50,19); + lib_preroll_spin->setMinValue(0); + lib_preroll_spin->setMaxValue(10000); + lib_preroll_spin->setLineStep(100); + QLabel *lib_preroll_spin_label=new QLabel(lib_preroll_spin, + tr("&Tail Preroll:"),this, + "lib_preroll_spin_label"); + lib_preroll_spin_label->setGeometry(25,166,130,19); + lib_preroll_spin_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QLabel *lib_preroll_spin_unit=new QLabel(tr("milliseconds"),this, + "lib_preroll_spin_unit"); + lib_preroll_spin_unit->setGeometry(215,166,120,19); + lib_preroll_spin_unit->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Ripper Device + // + lib_ripdev_edit=new QLineEdit(this,"lib_ripper_device"); + lib_ripdev_edit->setGeometry(160,188,100,19); + lib_ripdev_edit->setValidator(validator); + QLabel *lib_ripdev_label=new QLabel(lib_ripdev_edit,tr("&Ripper Device:"), + this,"lib_format_label"); + lib_ripdev_label->setGeometry(25,188,130,19); + lib_ripdev_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Paranoia Level + // + lib_paranoia_box=new QComboBox(this,"lib_paranoia_box"); + lib_paranoia_box->setGeometry(160,210,100,19); + QLabel *lib_paranoia_label= + new QLabel(lib_paranoia_box,tr("&Paranoia Level:"), + this,"lib_paranoia_label"); + lib_paranoia_label->setGeometry(25,210,130,19); + lib_paranoia_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ripper Level + // + lib_riplevel_spin=new QSpinBox(this,"lib_riplevel_spin"); + lib_riplevel_spin->setGeometry(160,232,40,19); + lib_riplevel_spin->setMinValue(-99); + lib_riplevel_spin->setMaxValue(0); + QLabel *lib_riplevel_spin_label=new QLabel(lib_riplevel_spin, + tr("Ripper Level:"),this, + "lib_riplevel_spin_label"); + lib_riplevel_spin_label->setGeometry(25,232,130,19); + lib_riplevel_spin_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QLabel *lib_riplevel_spin_unit=new QLabel(tr("dbFS"), + this,"lib_riplevel_spin_unit"); + lib_riplevel_spin_unit->setGeometry(205,232,120,19); + lib_riplevel_spin_unit->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // FreeDB Server + // + lib_cddb_edit=new QLineEdit(this,"lib_cddb_edit"); + lib_cddb_edit->setGeometry(160,256,160,19); + lib_cddb_edit->setValidator(validator); + QLabel *lib_cddb_label=new QLabel(lib_cddb_edit,tr("&FreeDB Server:"),this, + "lib_cddb_label"); + lib_cddb_label->setGeometry(25,256,130,19); + lib_cddb_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Format + // + lib_format_box=new QComboBox(this,"lib_format_box"); + lib_format_box->setGeometry(160,280,150,19); + connect(lib_format_box,SIGNAL(activated(int)),this,SLOT(formatData(int))); + QLabel *lib_format_label=new QLabel(lib_format_box,tr("&Format:"),this, + "lib_format_label"); + lib_format_label->setGeometry(25,280,130,19); + lib_format_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Bitrate + // + lib_bitrate_box=new QComboBox(this,"lib_bitrate_box"); + lib_bitrate_box->setGeometry(160,304,130,19); + QLabel *lib_bitrate_label=new QLabel(lib_bitrate_box,tr("&Bitrate:"),this, + "lib_bitrate_label"); + lib_bitrate_label->setGeometry(25,304,130,19); + lib_bitrate_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Enable Editor + // + lib_editor_box=new QComboBox(this,"lib_editor_box"); + lib_editor_box->setGeometry(160,328,60,19); + lib_editor_box->insertItem(tr("No")); + lib_editor_box->insertItem(tr("Yes")); + QLabel *lib_editor_label=new QLabel(lib_editor_box, + tr("Allow E&xternal Editing:"),this, + "lib_editor_label"); + lib_editor_label->setGeometry(25,328,130,19); + lib_editor_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Sample Rate Converter + // + lib_converter_box=new QComboBox(this,"lib_converter_box"); + lib_converter_box->setGeometry(160,352,sizeHint().width()-170,19); + int conv=0; + while(src_get_name(conv)!=NULL) { + lib_converter_box->insertItem(src_get_name(conv++)); + } + QLabel *lib_converter_label=new QLabel(lib_converter_box, + tr("Sample Rate Converter:"),this, + "lib_converter_label"); + lib_converter_label->setGeometry(10,352,145,19); + lib_converter_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Limit Searches at Startup + // + lib_limit_search_box=new QComboBox(this); + lib_limit_search_box->setGeometry(160,376,80,19); + lib_limit_search_box->insertItem(tr("No")); + lib_limit_search_box->insertItem(tr("Yes")); + lib_limit_search_box->insertItem(tr("Previous")); + QLabel *lib_limit_search_label= + new QLabel(lib_limit_search_box,tr("Limit Searches at Startup")+":",this); + lib_limit_search_label->setGeometry(10,376,145,19); + lib_limit_search_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Defaults + // + QLabel *default_label=new QLabel(tr("Defaults"),this,"default_label"); + default_label->setGeometry(25,415,120,19); + default_label->setFont(big_font); + default_label->setAlignment(AlignRight|ShowPrefix); + + // + // Default Channels + // + lib_channels_box=new QComboBox(this,"lib_channels_box"); + lib_channels_box->setGeometry(160,434,60,19); + QLabel *lib_channels_label=new QLabel(lib_channels_box,tr("&Channels:"),this, + "lib_channels_label"); + lib_channels_label->setGeometry(25,434,130,19); + lib_channels_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Default Record Mode + // + lib_recmode_box=new QComboBox(this,"lib_recmode_box"); + lib_recmode_box->setGeometry(160,456,100,19); + QLabel *lib_recmode_label=new QLabel(lib_recmode_box,tr("Record Mode:"),this, + "lib_recmode_label"); + lib_recmode_label->setGeometry(25,456,130,19); + lib_recmode_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Default Trim State + // + lib_trimstate_box=new QComboBox(this,"lib_trimstate_box"); + lib_trimstate_box->setGeometry(160,480,100,19); + QLabel *lib_trimstate_label=new QLabel(lib_trimstate_box,tr("AutoTrim:"), + this,"lib_trimstate_label"); + lib_trimstate_label->setGeometry(25,480,130,19); + lib_trimstate_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(small_font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(small_font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + if(cae_station->scanned()) { + lib_input_card->setMaxCards(cae_station->cards()); + lib_output_card->setMaxCards(cae_station->cards()); + for(int i=0;imaxCards();i++) { + lib_input_card->setMaxPorts(i,cae_station->cardInputs(i)); + lib_output_card->setMaxPorts(i,cae_station->cardOutputs(i)); + } + } + else { + QMessageBox::information(this,tr("No Audio Configuration Data"), + tr("Channel assignments will not be available for this host as audio resource data\nhas not yet been generated. Please start the Rivendell daemons on the host\nconfigured to run the CAE service in order to populate the audio resources database.")); + lib_input_card->setDisabled(true); + lib_output_card->setDisabled(true); + } + lib_input_card->setCard(lib_lib->inputCard()); + lib_input_card->setPort(lib_lib->inputPort()); + lib_output_card->setCard(lib_lib->outputCard()); + lib_output_card->setPort(lib_lib->outputPort()); + lib_maxlength_time->setTime(QTime().addMSecs(lib_lib->maxLength())); + lib_vox_spin->setValue(lib_lib->voxThreshold()/100); + lib_trim_spin->setValue(lib_lib->trimThreshold()/100); + lib_preroll_spin->setValue(lib_lib->tailPreroll()); + lib_ripdev_edit->setText(lib_lib->ripperDevice()); + lib_paranoia_box->insertItem(tr("Normal")); + lib_paranoia_box->insertItem(tr("Low")); + lib_paranoia_box->insertItem(tr("None")); + lib_paranoia_box->setCurrentItem(lib_lib->paranoiaLevel()); + lib_riplevel_spin->setValue(lib_lib->ripperLevel()/100); + lib_format_box->insertItem(tr("PCM16")); + lib_format_box->insertItem(tr("MPEG Layer 2")); + lib_format_box->setCurrentItem(lib_lib->defaultFormat()); + lib_channels_box->insertItem("1"); + lib_channels_box->insertItem("2"); + lib_channels_box->setCurrentItem(lib_lib->defaultChannels()-1); + ShowBitRates(lib_lib->defaultFormat(),lib_lib->defaultBitrate()); + lib_recmode_box->insertItem(tr("Manual")); + lib_recmode_box->insertItem(tr("VOX")); + switch(lib_lib->defaultRecordMode()) { + case RDLibraryConf::Manual: + lib_recmode_box->setCurrentItem(0); + break; + + case RDLibraryConf::Vox: + lib_recmode_box->setCurrentItem(1); + break; + } + lib_trimstate_box->insertItem("On"); + lib_trimstate_box->insertItem("Off"); + if(lib_lib->defaultTrimState()) { + lib_trimstate_box->setCurrentItem(0); + } + else { + lib_trimstate_box->setCurrentItem(1); + } + lib_cddb_edit->setText(lib_lib->cddbServer()); + lib_editor_box->setCurrentItem(lib_lib->enableEditor()); + lib_converter_box->setCurrentItem(lib_lib->srcConverter()); + lib_limit_search_box->setCurrentItem((int)lib_lib->limitSearch()); +} + + +EditRDLibrary::~EditRDLibrary() +{ + delete lib_input_card; + delete lib_output_card; + delete lib_format_box; + delete lib_channels_box; + delete lib_bitrate_box; + delete lib_maxlength_time; +} + + +QSize EditRDLibrary::sizeHint() const +{ + return QSize(375,584); +} + + +QSizePolicy EditRDLibrary::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditRDLibrary::formatData(int index) +{ + ShowBitRates(index,lib_lib->defaultBitrate()); +} + + +void EditRDLibrary::okData() +{ + unsigned rate=0; + + lib_lib->setInputCard(lib_input_card->card()); + lib_lib->setInputPort(lib_input_card->port()); + lib_lib->setOutputCard(lib_output_card->card()); + lib_lib->setOutputPort(lib_output_card->port()); + lib_lib->setMaxLength(QTime().msecsTo(lib_maxlength_time->time())); + lib_lib->setVoxThreshold(100*lib_vox_spin->value()); + lib_lib->setTrimThreshold(100*lib_trim_spin->value()); + lib_lib->setTailPreroll(lib_preroll_spin->value()); + lib_lib->setRipperDevice(lib_ripdev_edit->text()); + lib_lib->setParanoiaLevel(lib_paranoia_box->currentItem()); + lib_lib->setRipperLevel(lib_riplevel_spin->value()*100); + lib_lib->setDefaultFormat(lib_format_box->currentItem()); + lib_lib->setDefaultChannels(lib_channels_box->currentItem()+1); + rate=0; + if(lib_format_box->currentItem()!=0) { + sscanf(lib_bitrate_box->currentText(),"%d",&rate); + } + lib_lib->setDefaultBitrate(rate*1000); + switch(lib_recmode_box->currentItem()) { + case 0: + lib_lib->setDefaultRecordMode(RDLibraryConf::Manual); + break; + + case 1: + lib_lib->setDefaultRecordMode(RDLibraryConf::Vox); + break; + } + switch(lib_trimstate_box->currentItem()) { + case 0: + lib_lib->setDefaultTrimState(true); + break; + + case 1: + lib_lib->setDefaultTrimState(false); + break; + } + lib_lib->setCddbServer(lib_cddb_edit->text()); + lib_lib->setEnableEditor(lib_editor_box->currentItem()); + lib_lib->setSrcConverter(lib_converter_box->currentItem()); + lib_lib->setLimitSearch((RDLibraryConf::SearchLimit) + lib_limit_search_box->currentItem()); + done(0); +} + + +void EditRDLibrary::cancelData() +{ + done(1); +} + + +void EditRDLibrary::ShowBitRates(int layer,int rate) +{ + lib_bitrate_box->clear(); + switch(layer) { + case 0: // PCM16 + lib_bitrate_box->setDisabled(true); + break; + + case 1: // MPEG-1 Layer 2 + lib_bitrate_box->setEnabled(true); + lib_bitrate_box->insertItem(tr("32 kbps/chan")); + lib_bitrate_box->insertItem(tr("48 kbps/chan")); + lib_bitrate_box->insertItem(tr("56 kbps/chan")); + lib_bitrate_box->insertItem(tr("64 kbps/chan")); + lib_bitrate_box->insertItem(tr("80 kbps/chan")); + lib_bitrate_box->insertItem(tr("96 kbps/chan")); + lib_bitrate_box->insertItem(tr("112 kbps/chan")); + lib_bitrate_box->insertItem(tr("128 kbps/chan")); + lib_bitrate_box->insertItem(tr("160 kbps/chan")); + lib_bitrate_box->insertItem(tr("192 kbps/chan")); + switch(lib_lib->defaultBitrate()) { + case 32000: + lib_bitrate_box->setCurrentItem(0); + break; + + case 48000: + lib_bitrate_box->setCurrentItem(1); + break; + + case 56000: + lib_bitrate_box->setCurrentItem(2); + break; + + case 64000: + lib_bitrate_box->setCurrentItem(3); + break; + + case 80000: + lib_bitrate_box->setCurrentItem(4); + break; + + case 96000: + lib_bitrate_box->setCurrentItem(5); + break; + + case 112000: + lib_bitrate_box->setCurrentItem(6); + break; + + case 128000: + lib_bitrate_box->setCurrentItem(7); + break; + + case 160000: + lib_bitrate_box->setCurrentItem(8); + break; + + case 192000: + lib_bitrate_box->setCurrentItem(9); + break; + + default: + lib_bitrate_box->setCurrentItem(7); // 128 kbps/chan + break; + } + break; + + case 2: // MPEG-1 Layer 3 + lib_bitrate_box->setEnabled(true); + lib_bitrate_box->insertItem(tr("32 kbps/chan")); + lib_bitrate_box->insertItem(tr("40 kbps/chan")); + lib_bitrate_box->insertItem(tr("48 kbps/chan")); + lib_bitrate_box->insertItem(tr("56 kbps/chan")); + lib_bitrate_box->insertItem(tr("64 kbps/chan")); + lib_bitrate_box->insertItem(tr("80 kbps/chan")); + lib_bitrate_box->insertItem(tr("96 kbps/chan")); + lib_bitrate_box->insertItem(tr("112 kbps/chan")); + lib_bitrate_box->insertItem(tr("128 kbps/chan")); + lib_bitrate_box->insertItem(tr("160 kbps/chan")); + lib_bitrate_box->insertItem(tr("192 kbps/chan")); + lib_bitrate_box->insertItem(tr("224 kbps/chan")); + lib_bitrate_box->insertItem(tr("256 kbps/chan")); + lib_bitrate_box->insertItem(tr("320 kbps/chan")); + switch(lib_lib->defaultLayer()) { + case 32000: + lib_bitrate_box->setCurrentItem(0); + break; + + case 40000: + lib_bitrate_box->setCurrentItem(1); + break; + + case 48000: + lib_bitrate_box->setCurrentItem(2); + break; + + case 56000: + lib_bitrate_box->setCurrentItem(3); + break; + + case 64000: + lib_bitrate_box->setCurrentItem(4); + break; + + case 80000: + lib_bitrate_box->setCurrentItem(5); + break; + + case 96000: + lib_bitrate_box->setCurrentItem(6); + break; + + case 112000: + lib_bitrate_box->setCurrentItem(7); + break; + + case 128000: + lib_bitrate_box->setCurrentItem(8); + break; + + case 160000: + lib_bitrate_box->setCurrentItem(9); + break; + + case 192000: + lib_bitrate_box->setCurrentItem(10); + break; + + case 224000: + lib_bitrate_box->setCurrentItem(11); + break; + + case 256000: + lib_bitrate_box->setCurrentItem(12); + break; + + case 320000: + lib_bitrate_box->setCurrentItem(13); + break; + } + break; + + } +} diff --git a/rdadmin/edit_rdlibrary.h b/rdadmin/edit_rdlibrary.h new file mode 100644 index 00000000..121d851d --- /dev/null +++ b/rdadmin/edit_rdlibrary.h @@ -0,0 +1,78 @@ +// edit_rdlibrary.h +// +// Edit an RDLibrry Configuration +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: edit_rdlibrary.h,v 1.19.6.1 2014/01/09 01:03:55 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_RDLIBRARY_H +#define EDIT_RDLIBRARY_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +class EditRDLibrary : public QDialog +{ + Q_OBJECT + public: + EditRDLibrary(RDStation *station,RDStation *cae_station, + QWidget *parent=0,const char *name=0); + ~EditRDLibrary(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void formatData(int); + void okData(); + void cancelData(); + + private: + void ShowBitRates(int layer,int rate); + RDLibraryConf *lib_lib; + RDCardSelector *lib_input_card; + RDCardSelector *lib_output_card; + QComboBox *lib_format_box; + QComboBox *lib_channels_box; + QComboBox *lib_bitrate_box; + QComboBox *lib_recmode_box; + QComboBox *lib_trimstate_box; + QSpinBox *lib_vox_spin; + QSpinBox *lib_trim_spin; + QSpinBox *lib_preroll_spin; + QTimeEdit *lib_maxlength_time; + QLineEdit *lib_ripdev_edit; + QComboBox *lib_paranoia_box; + QSpinBox *lib_riplevel_spin; + QLineEdit *lib_cddb_edit; + QComboBox *lib_editor_box; + QComboBox *lib_converter_box; + QComboBox *lib_limit_search_box; +}; + + +#endif + diff --git a/rdadmin/edit_rdlogedit.cpp b/rdadmin/edit_rdlogedit.cpp new file mode 100644 index 00000000..b21bad97 --- /dev/null +++ b/rdadmin/edit_rdlogedit.cpp @@ -0,0 +1,626 @@ +// edit_rdlogedit.cpp +// +// Edit an RDLogedit Configuration +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_rdlogedit.cpp,v 1.18.6.2 2014/01/08 18:14:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + + +EditRDLogedit::EditRDLogedit(RDStation *station,RDStation *cae_station, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + lib_lib=new RDLogeditConf(station->name()); + + // + // Create Fonts + // + QFont small_font=QFont("Helvetica",12,QFont::Bold); + small_font.setPixelSize(12); + QFont big_font=QFont("Helvetica",14,QFont::Bold); + big_font.setPixelSize(14); + + // + // Dialog Name + // + setCaption(tr("RDLogedit config for ")+station->name()); + + // + // Input Configuration + // + lib_input_card=new RDCardSelector(this,"lib_input_card"); + lib_input_card->setGeometry(10,29,120,117); + QLabel *label=new QLabel(lib_input_card,tr("INPUT"),this,"lib_input_label"); + label->setGeometry(10,10,110,19); + label->setFont(big_font); + label->setAlignment(AlignCenter); + + // + // Output Configuration + // + lib_output_card=new RDCardSelector(this,"lib_output_card"); + lib_output_card->setGeometry(170,29,120,87); + label=new QLabel(lib_output_card,tr("OUTPUT"),this,"lib_output_label"); + label->setGeometry(170,10,110,19); + label->setFont(big_font); + label->setAlignment(AlignCenter); + + // + // Settings + // + QLabel *setting_label=new QLabel(tr("Voice Tracker Settings"),this,"setting_label"); + setting_label->setGeometry(70,79,sizeHint().width()-80,19); + setting_label->setFont(big_font); + setting_label->setAlignment(AlignLeft|ShowPrefix); + + // + // Maximum Record Length + // + lib_maxlength_time=new QTimeEdit(this,"lib_maxlength_time"); + lib_maxlength_time->setGeometry(160,100,85,19); + QLabel *lib_maxlength_label=new QLabel(lib_maxlength_time, + tr("&Max Record Time:"),this, + "lib_maxlength_label"); + lib_maxlength_label->setGeometry(25,101,130,19); + lib_maxlength_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Autotrim Level + // + lib_threshold_spin=new QSpinBox(this,"lib_threshold_spin"); + lib_threshold_spin->setGeometry(160,124,50,19); + lib_threshold_spin->setMinValue(-99); + lib_threshold_spin->setMaxValue(0); + label=new QLabel(lib_threshold_spin,tr("&AutoTrim Threshold:"),this, + "lib_threshold_spin_label"); + label->setGeometry(25,124,130,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + label=new QLabel(tr("dbFS"),this,"lib_threshold_spin_unit"); + label->setGeometry(215,124,120,19); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Normalization Level + // + lib_normalization_spin=new QSpinBox(this,"lib_normalization_spin"); + lib_normalization_spin->setGeometry(160,148,50,19); + lib_normalization_spin->setMinValue(-99); + lib_normalization_spin->setMaxValue(0); + label=new QLabel(lib_normalization_spin,tr("&Normalization Level:"), + this,"lib_normalization_spin_label"); + label->setGeometry(25,148,130,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + label=new QLabel(tr("dbFS"),this,"lib_normalization_spin_unit"); + label->setGeometry(215,148,120,19); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Audio Margin + // + lib_preroll_spin=new QSpinBox(this,"lib_preroll_spin"); + lib_preroll_spin->setGeometry(160,172,60,19); + lib_preroll_spin->setMinValue(0); + lib_preroll_spin->setMaxValue(10000); + lib_preroll_spin->setLineStep(100); + QLabel *lib_preroll_spin_label=new QLabel(lib_preroll_spin, + tr("&Audio Margin:"),this, + "lib_preroll_spin_label"); + lib_preroll_spin_label->setGeometry(25,172,130,19); + lib_preroll_spin_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QLabel *lib_preroll_spin_unit=new QLabel(tr("milliseconds"),this, + "lib_preroll_spin_unit"); + lib_preroll_spin_unit->setGeometry(225,172,120,19); + lib_preroll_spin_unit->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Format + // + lib_format_box=new QComboBox(this,"lib_name_edit"); + lib_format_box->setGeometry(160,196,150,19); + connect(lib_format_box,SIGNAL(activated(int)),this,SLOT(formatData(int))); + QLabel *lib_format_label=new QLabel(lib_format_box,tr("&Format:"),this, + "lib_format_label"); + lib_format_label->setGeometry(25,196,130,19); + lib_format_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Bitrate + // + lib_bitrate_box=new QComboBox(this,"lib_name_edit"); + lib_bitrate_box->setGeometry(160,220,130,19); + QLabel *lib_bitrate_label=new QLabel(lib_bitrate_box,tr("&Bitrate:"),this, + "lib_bitrate_label"); + lib_bitrate_label->setGeometry(25,220,130,19); + lib_bitrate_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Enable Second Start Button + // + lib_enable_second_start_box=new QComboBox(this); + lib_enable_second_start_box->setGeometry(160,244,60,19); + lib_enable_second_start_box->insertItem(tr("No")); + lib_enable_second_start_box->insertItem(tr("Yes")); + QLabel *lib_enable_second_start_label= + new QLabel(lib_enable_second_start_box,tr("Enable &2nd Start Button:"),this); + lib_enable_second_start_label->setGeometry(10,244,145,19); + lib_enable_second_start_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Validator + // + QIntValidator *validator=new QIntValidator(this,"validator"); + validator->setRange(1,999999); + + // + // Play Start Cart + // + lib_startcart_edit=new QLineEdit(this,"lib_name_edit"); + lib_startcart_edit->setGeometry(160,268,70,19); + lib_startcart_edit->setValidator(validator); + QLabel *lib_startcart_label= + new QLabel(lib_startcart_edit,tr("Play &Start Cart:"),this, + "lib_startcart_label"); + lib_startcart_label->setGeometry(25,268,130,19); + lib_startcart_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QPushButton *button=new QPushButton(this,"start_select_button"); + button->setGeometry(240,266,55,23); + button->setText(tr("Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectStartData())); + + // + // Play End Cart + // + lib_endcart_edit=new QLineEdit(this,"lib_name_edit"); + lib_endcart_edit->setGeometry(160,292,70,19); + lib_endcart_edit->setValidator(validator); + QLabel *lib_endcart_label= + new QLabel(lib_endcart_edit,tr("Play &End Cart:"),this, + "lib_endcart_label"); + lib_endcart_label->setGeometry(25,292,130,19); + lib_endcart_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + button=new QPushButton(this,"end_select_button"); + button->setGeometry(240,290,55,23); + button->setText(tr("Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectEndData())); + + // + // Record Start Cart + // + lib_recstartcart_edit=new QLineEdit(this,"lib_name_edit"); + lib_recstartcart_edit->setGeometry(160,316,70,19); + lib_recstartcart_edit->setValidator(validator); + QLabel *lib_recstartcart_label= + new QLabel(lib_recstartcart_edit,tr("&Record Start Cart:"),this, + "lib_recstartcart_label"); + lib_recstartcart_label->setGeometry(25,316,130,19); + lib_recstartcart_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + button=new QPushButton(this,"start_select_button"); + button->setGeometry(240,314,55,23); + button->setText(tr("Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectRecordStartData())); + + // + // Record End Cart + // + lib_recendcart_edit=new QLineEdit(this,"lib_name_edit"); + lib_recendcart_edit->setGeometry(160,340,70,19); + lib_recendcart_edit->setValidator(validator); + QLabel *lib_recendcart_label= + new QLabel(lib_recendcart_edit,tr("Re&cord End Cart:"),this, + "lib_recendcart_label"); + lib_recendcart_label->setGeometry(25,340,130,19); + lib_recendcart_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + button=new QPushButton(this,"end_select_button"); + button->setGeometry(240,338,55,23); + button->setText(tr("Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectRecordEndData())); + + // + // Default Channels + // + lib_channels_box=new QComboBox(this,"lib_name_edit"); + lib_channels_box->setGeometry(160,364,60,19); + QLabel *lib_channels_label=new QLabel(lib_channels_box,tr("&Channels:"),this, + "lib_channels_label"); + lib_channels_label->setGeometry(25,364,130,19); + lib_channels_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Default Transition Type + // + lib_default_transtype_box=new QComboBox(this,"lib_name_edit"); + lib_default_transtype_box->setGeometry(160,388,100,19); + QLabel *lib_default_transtype_label= + new QLabel(lib_default_transtype_box,tr("Default Transition:"), + this,"lib_default_transtype_label"); + lib_default_transtype_label->setGeometry(20,388,130,19); + lib_default_transtype_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + lib_default_transtype_box->insertItem(tr("Play")); + lib_default_transtype_box->insertItem(tr("Segue")); + lib_default_transtype_box->insertItem(tr("Stop")); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(small_font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(small_font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + if(cae_station->scanned()) { + lib_input_card->setMaxCards(cae_station->cards()); + lib_output_card->setMaxCards(cae_station->cards()); + for(int i=0;imaxCards();i++) { + lib_input_card->setMaxPorts(i,cae_station->cardInputs(i)); + lib_output_card->setMaxPorts(i,cae_station->cardOutputs(i)); + } + } + else { + QMessageBox::information(this,tr("No Audio Configuration Data"), + tr("Channel assignments will not be available for this host as audio resource data\nhas not yet been generated. Please start the Rivendell daemons on the host\nconfigured to run the CAE service in order to populate the audio resources database.")); + lib_input_card->setDisabled(true); + lib_output_card->setDisabled(true); + } + lib_input_card->setCard(lib_lib->inputCard()); + lib_input_card->setPort(lib_lib->inputPort()); + lib_output_card->setCard(lib_lib->outputCard()); + lib_output_card->setPort(lib_lib->outputPort()); + lib_maxlength_time->setTime(QTime().addMSecs(lib_lib->maxLength())); + lib_threshold_spin->setValue(lib_lib->trimThreshold()/100); + lib_normalization_spin->setValue(lib_lib->ripperLevel()/100); + unsigned cart=lib_lib->startCart(); + if(cart>0) { + lib_startcart_edit->setText(QString().sprintf("%06u",cart)); + } + if((cart=lib_lib->endCart())>0) { + lib_endcart_edit->setText(QString().sprintf("%06u",cart)); + } + cart=lib_lib->recStartCart(); + if(cart>0) { + lib_recstartcart_edit->setText(QString().sprintf("%06u",cart)); + } + if((cart=lib_lib->recEndCart())>0) { + lib_recendcart_edit->setText(QString().sprintf("%06u",cart)); + } + lib_preroll_spin->setValue(lib_lib->tailPreroll()); + lib_format_box->insertItem(tr("PCM16")); + lib_format_box->insertItem(tr("MPEG Layer 2")); + lib_format_box->setCurrentItem(lib_lib->format()); + lib_channels_box->insertItem("1"); + lib_channels_box->insertItem("2"); + lib_channels_box->setCurrentItem(lib_lib->defaultChannels()-1); + ShowBitRates(lib_lib->format(),lib_lib->bitrate()); + lib_enable_second_start_box->setCurrentItem(lib_lib->enableSecondStart()); + lib_default_transtype_box->setCurrentItem(lib_lib->defaultTransType()); +} + + +EditRDLogedit::~EditRDLogedit() +{ + delete lib_input_card; + delete lib_output_card; + delete lib_format_box; + delete lib_channels_box; + delete lib_bitrate_box; + delete lib_maxlength_time; +} + + +QSize EditRDLogedit::sizeHint() const +{ + return QSize(375,478); +} + + +QSizePolicy EditRDLogedit::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditRDLogedit::formatData(int index) +{ + ShowBitRates(index,lib_lib->bitrate()); +} + + +void EditRDLogedit::selectStartData() +{ + int cartnum=lib_startcart_edit->text().toInt(); + + if(admin_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + lib_startcart_edit->setText(QString().sprintf("%d",cartnum)); + } +} + + +void EditRDLogedit::selectEndData() +{ + int cartnum=lib_endcart_edit->text().toInt(); + if(admin_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + lib_endcart_edit->setText(QString().sprintf("%d",cartnum)); + } +} + + +void EditRDLogedit::selectRecordStartData() +{ + int cartnum=lib_recstartcart_edit->text().toInt(); + if(admin_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + lib_recstartcart_edit->setText(QString().sprintf("%d",cartnum)); + } +} + + +void EditRDLogedit::selectRecordEndData() +{ + int cartnum=lib_recendcart_edit->text().toInt(); + if(admin_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + lib_recendcart_edit->setText(QString().sprintf("%d",cartnum)); + } +} + + +void EditRDLogedit::okData() +{ + unsigned rate=0; + + lib_lib->setInputCard(lib_input_card->card()); + lib_lib->setInputPort(lib_input_card->port()); + lib_lib->setOutputCard(lib_output_card->card()); + lib_lib->setOutputPort(lib_output_card->port()); + lib_lib->setMaxLength(QTime().msecsTo(lib_maxlength_time->time())); + lib_lib->setTrimThreshold(lib_threshold_spin->value()*100); + lib_lib->setRipperLevel(lib_normalization_spin->value()*100); + lib_lib->setTailPreroll(lib_preroll_spin->value()); + if(lib_startcart_edit->text().isEmpty()) { + lib_lib->setStartCart(0); + } + else { + lib_lib->setStartCart(lib_startcart_edit->text().toUInt()); + } + if(lib_endcart_edit->text().isEmpty()) { + lib_lib->setEndCart(0); + } + else { + lib_lib->setEndCart(lib_endcart_edit->text().toUInt()); + } + if(lib_recstartcart_edit->text().isEmpty()) { + lib_lib->setRecStartCart(0); + } + else { + lib_lib->setRecStartCart(lib_recstartcart_edit->text().toUInt()); + } + if(lib_recendcart_edit->text().isEmpty()) { + lib_lib->setRecEndCart(0); + } + else { + lib_lib->setRecEndCart(lib_recendcart_edit->text().toUInt()); + } + lib_lib->setFormat(lib_format_box->currentItem()); + lib_lib->setDefaultChannels(lib_channels_box->currentItem()+1); + rate=0; + if(lib_format_box->currentItem()!=0) { + sscanf(lib_bitrate_box->currentText(),"%d",&rate); + } + lib_lib->setBitrate(rate*1000); + lib_lib->setEnableSecondStart(lib_enable_second_start_box->currentItem()); + lib_lib->setDefaultTransType( + (RDLogLine::TransType)lib_default_transtype_box->currentItem()); + done(0); +} + + +void EditRDLogedit::cancelData() +{ + done(1); +} + + +void EditRDLogedit::ShowBitRates(int layer,int rate) +{ + lib_bitrate_box->clear(); + switch(layer) { + case 0: // PCM16 + lib_bitrate_box->setDisabled(true); + break; + + case 1: // MPEG-1 Layer 2 + lib_bitrate_box->setEnabled(true); + lib_bitrate_box->insertItem(tr("32 kbps/chan")); + lib_bitrate_box->insertItem(tr("48 kbps/chan")); + lib_bitrate_box->insertItem(tr("56 kbps/chan")); + lib_bitrate_box->insertItem(tr("64 kbps/chan")); + lib_bitrate_box->insertItem(tr("80 kbps/chan")); + lib_bitrate_box->insertItem(tr("96 kbps/chan")); + lib_bitrate_box->insertItem(tr("112 kbps/chan")); + lib_bitrate_box->insertItem(tr("128 kbps/chan")); + lib_bitrate_box->insertItem(tr("160 kbps/chan")); + lib_bitrate_box->insertItem(tr("192 kbps/chan")); + switch(lib_lib->bitrate()) { + case 32000: + lib_bitrate_box->setCurrentItem(0); + break; + + case 48000: + lib_bitrate_box->setCurrentItem(1); + break; + + case 56000: + lib_bitrate_box->setCurrentItem(2); + break; + + case 64000: + lib_bitrate_box->setCurrentItem(3); + break; + + case 80000: + lib_bitrate_box->setCurrentItem(4); + break; + + case 96000: + lib_bitrate_box->setCurrentItem(5); + break; + + case 112000: + lib_bitrate_box->setCurrentItem(6); + break; + + case 128000: + lib_bitrate_box->setCurrentItem(7); + break; + + case 160000: + lib_bitrate_box->setCurrentItem(8); + break; + + case 192000: + lib_bitrate_box->setCurrentItem(9); + break; + + default: + lib_bitrate_box->setCurrentItem(7); // 128 kbps/chan + break; + } + break; + + case 2: // MPEG-1 Layer 3 + lib_bitrate_box->setEnabled(true); + lib_bitrate_box->insertItem(tr("32 kbps/chan")); + lib_bitrate_box->insertItem(tr("40 kbps/chan")); + lib_bitrate_box->insertItem(tr("48 kbps/chan")); + lib_bitrate_box->insertItem(tr("56 kbps/chan")); + lib_bitrate_box->insertItem(tr("64 kbps/chan")); + lib_bitrate_box->insertItem(tr("80 kbps/chan")); + lib_bitrate_box->insertItem(tr("96 kbps/chan")); + lib_bitrate_box->insertItem(tr("112 kbps/chan")); + lib_bitrate_box->insertItem(tr("128 kbps/chan")); + lib_bitrate_box->insertItem(tr("160 kbps/chan")); + lib_bitrate_box->insertItem(tr("192 kbps/chan")); + lib_bitrate_box->insertItem(tr("224 kbps/chan")); + lib_bitrate_box->insertItem(tr("256 kbps/chan")); + lib_bitrate_box->insertItem(tr("320 kbps/chan")); + switch(lib_lib->layer()) { + case 32000: + lib_bitrate_box->setCurrentItem(0); + break; + + case 40000: + lib_bitrate_box->setCurrentItem(1); + break; + + case 48000: + lib_bitrate_box->setCurrentItem(2); + break; + + case 56000: + lib_bitrate_box->setCurrentItem(3); + break; + + case 64000: + lib_bitrate_box->setCurrentItem(4); + break; + + case 80000: + lib_bitrate_box->setCurrentItem(5); + break; + + case 96000: + lib_bitrate_box->setCurrentItem(6); + break; + + case 112000: + lib_bitrate_box->setCurrentItem(7); + break; + + case 128000: + lib_bitrate_box->setCurrentItem(8); + break; + + case 160000: + lib_bitrate_box->setCurrentItem(9); + break; + + case 192000: + lib_bitrate_box->setCurrentItem(10); + break; + + case 224000: + lib_bitrate_box->setCurrentItem(11); + break; + + case 256000: + lib_bitrate_box->setCurrentItem(12); + break; + + case 320000: + lib_bitrate_box->setCurrentItem(13); + break; + } + break; + + } +} diff --git a/rdadmin/edit_rdlogedit.h b/rdadmin/edit_rdlogedit.h new file mode 100644 index 00000000..af35679c --- /dev/null +++ b/rdadmin/edit_rdlogedit.h @@ -0,0 +1,80 @@ +// edit_rdlogedit.h +// +// Edit an RDLogEdit Configuration +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_rdlogedit.h,v 1.9.6.1 2014/01/08 18:14:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_RDLOGEDIT_H +#define EDIT_RDLOGEDIT_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +class EditRDLogedit : public QDialog +{ + Q_OBJECT + public: + EditRDLogedit(RDStation *station,RDStation *cae_station, + QWidget *parent=0,const char *name=0); + ~EditRDLogedit(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void formatData(int); + void selectStartData(); + void selectEndData(); + void selectRecordStartData(); + void selectRecordEndData(); + void okData(); + void cancelData(); + + private: + void ShowBitRates(int layer,int rate); + RDLogeditConf *lib_lib; + RDCardSelector *lib_input_card; + RDCardSelector *lib_output_card; + QComboBox *lib_format_box; + QComboBox *lib_channels_box; + QComboBox *lib_bitrate_box; + QComboBox *lib_enable_second_start_box; + QSpinBox *lib_preroll_spin; + QSpinBox *lib_threshold_spin; + QSpinBox *lib_normalization_spin; + QTimeEdit *lib_maxlength_time; + QLineEdit *lib_startcart_edit; + QLineEdit *lib_endcart_edit; + QLineEdit *lib_recstartcart_edit; + QLineEdit *lib_recendcart_edit; + QComboBox *lib_default_transtype_box; + QString lib_filter; + QString lib_group; +}; + + +#endif diff --git a/rdadmin/edit_rdpanel.cpp b/rdadmin/edit_rdpanel.cpp new file mode 100644 index 00000000..65c6484e --- /dev/null +++ b/rdadmin/edit_rdpanel.cpp @@ -0,0 +1,516 @@ +// edit_rdpanel.cpp +// +// Edit an RDPanel Configuration +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: edit_rdpanel.cpp,v 1.9.8.2 2013/12/23 18:35:15 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + + +EditRDPanel::EditRDPanel(RDStation *station,RDStation *cae_station, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + air_conf=new RDAirPlayConf(station->name(),"RDPANEL"); + + // + // Create Fonts + // + QFont unit_font=QFont("Helvetica",12,QFont::Normal); + unit_font.setPixelSize(12); + QFont small_font=QFont("Helvetica",12,QFont::Bold); + small_font.setPixelSize(12); + QFont big_font=QFont("Helvetica",14,QFont::Bold); + big_font.setPixelSize(14); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Dialog Name + // + setCaption(tr("RDPanel config for ")+station->name()); + + // + // Channel Assignments Section + // + QLabel *label=new QLabel(tr("Channel Assignments"),this,"globals_label"); + label->setFont(big_font); + label->setGeometry(10,10,200,16); + + // + // Sound Panel First Play Output + // + label=new QLabel(tr("SoundPanel First Play Output"),this,"globals_label"); + label->setFont(small_font); +// label->setGeometry(395,32,300,16); + label->setGeometry(20,32,300,16); + air_card_sel[0]=new RDCardSelector(this,"air_card5_sel"); + air_card_sel[0]->setGeometry(15,50,120,117); + air_start_rml_edit[0]=new QLineEdit(this); + air_start_rml_edit[0]->setGeometry(205,50,160,19); + air_start_rml_edit[0]->setValidator(validator); + label=new QLabel(air_start_rml_edit[0],tr("Start RML:"),this); + label->setGeometry(135,50,65,19); + label->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[0]=new QLineEdit(this); + air_stop_rml_edit[0]->setGeometry(205,71,160,19); + air_stop_rml_edit[0]->setValidator(validator); + label=new QLabel(air_start_rml_edit[0],tr("Stop RML:"),this); + label->setGeometry(135,71,65,19); + label->setAlignment(AlignVCenter|AlignRight); + + // + // Sound Panel Second Play Output + // + label=new QLabel(tr("SoundPanel Second Play Output"),this,"globals_label"); + label->setFont(small_font); + label->setGeometry(20,100,300,16); + air_card_sel[1]=new RDCardSelector(this,"air_card5_sel"); + air_card_sel[1]->setGeometry(15,118,120,117); + air_start_rml_edit[1]=new QLineEdit(this); + air_start_rml_edit[1]->setGeometry(205,118,160,19); + air_start_rml_edit[1]->setValidator(validator); + label=new QLabel(air_start_rml_edit[1],tr("Start RML:"),this); + label->setGeometry(135,118,65,19); + label->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[1]=new QLineEdit(this); + air_stop_rml_edit[1]->setGeometry(205,139,160,19); + air_stop_rml_edit[1]->setValidator(validator); + label=new QLabel(air_start_rml_edit[1],tr("Stop RML:"),this); + label->setGeometry(135,139,65,19); + label->setAlignment(AlignVCenter|AlignRight); + + // + // Sound Panel Third Play Output + // + label=new QLabel(tr("SoundPanel Third Play Output"),this,"globals_label"); + label->setFont(small_font); + label->setGeometry(20,168,300,16); + air_card_sel[2]=new RDCardSelector(this,"air_card5_sel"); + air_card_sel[2]->setGeometry(15,186,120,117); + air_start_rml_edit[2]=new QLineEdit(this); + air_start_rml_edit[2]->setGeometry(205,186,160,19); + air_start_rml_edit[2]->setValidator(validator); + label=new QLabel(air_start_rml_edit[2],tr("Start RML:"),this); + label->setGeometry(135,186,65,19); + label->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[2]=new QLineEdit(this); + air_stop_rml_edit[2]->setGeometry(205,207,160,19); + air_stop_rml_edit[2]->setValidator(validator); + label=new QLabel(air_start_rml_edit[2],tr("Stop RML:"),this); + label->setGeometry(135,207,65,19); + label->setAlignment(AlignVCenter|AlignRight); + + // + // Sound Panel Fourth Play Output + // + label=new QLabel(tr("SoundPanel Fourth Play Output"),this,"globals_label"); + label->setFont(small_font); + label->setGeometry(20,236,300,16); + air_card_sel[3]=new RDCardSelector(this,"air_card5_sel"); + air_card_sel[3]->setGeometry(15,254,120,117); + air_start_rml_edit[3]=new QLineEdit(this); + air_start_rml_edit[3]->setGeometry(205,254,160,19); + air_start_rml_edit[3]->setValidator(validator); + label=new QLabel(air_start_rml_edit[3],tr("Start RML:"),this); + label->setGeometry(135,254,65,19); + label->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[3]=new QLineEdit(this); + air_stop_rml_edit[3]->setGeometry(205,275,160,19); + air_stop_rml_edit[3]->setValidator(validator); + label=new QLabel(air_start_rml_edit[3],tr("Stop RML:"),this); + label->setGeometry(135,275,65,19); + label->setAlignment(AlignVCenter|AlignRight); + + // + // Sound Panel Fifth Play Output + // + label=new QLabel(tr("SoundPanel Fifth and Later Play Output"), + this,"globals_label"); + label->setFont(small_font); + label->setGeometry(20,304,300,16); + air_card_sel[4]=new RDCardSelector(this,"air_card5_sel"); + air_card_sel[4]->setGeometry(15,322,120,117); + air_start_rml_edit[4]=new QLineEdit(this); + air_start_rml_edit[4]->setGeometry(205,322,160,19); + air_start_rml_edit[4]->setValidator(validator); + label=new QLabel(air_start_rml_edit[4],tr("Start RML:"),this); + label->setGeometry(135,322,65,19); + label->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[4]=new QLineEdit(this); + air_stop_rml_edit[4]->setGeometry(205,343,160,19); + air_stop_rml_edit[4]->setValidator(validator); + label=new QLabel(air_start_rml_edit[4],tr("Stop RML:"),this); + label->setGeometry(135,343,65,19); + label->setAlignment(AlignVCenter|AlignRight); + + // + // Sound Panel Cue Play Output + // + label=new QLabel(tr("SoundPanel Cue Output"),this,"globals_label"); + label->setFont(small_font); + label->setGeometry(20,372,300,16); + air_card_sel[5]=new RDCardSelector(this,"air_card5_sel"); + air_card_sel[5]->setGeometry(15,390,120,117); + air_start_rml_edit[5]=new QLineEdit(this); + air_start_rml_edit[5]->setGeometry(205,390,160,19); + air_start_rml_edit[5]->setValidator(validator); + label=new QLabel(air_start_rml_edit[5],tr("Start RML:"),this); + label->setGeometry(135,390,65,19); + label->setAlignment(AlignVCenter|AlignRight); + air_stop_rml_edit[5]=new QLineEdit(this); + air_stop_rml_edit[5]->setGeometry(205,411,160,19); + air_stop_rml_edit[5]->setValidator(validator); + label=new QLabel(air_start_rml_edit[5],tr("Stop RML:"),this); + label->setGeometry(135,411,65,19); + label->setAlignment(AlignVCenter|AlignRight); + + // + // Display Settings Section + // + label=new QLabel(tr("Display Settings"),this,"globals_label"); + label->setFont(big_font); + label->setGeometry(20,438,200,16); + + // + // Skin Path + // + air_skin_edit=new QLineEdit(this,"air_skin_edit"); + air_skin_edit->setGeometry(135,460,180,20); + label=new QLabel(air_skin_edit,tr("Background Image:"), + this,"air_skin_label"); + label->setGeometry(10,460,115,20); + label->setAlignment(AlignRight|AlignVCenter); + QPushButton *button=new QPushButton(tr("Select"),this,"skin_select_button"); + button->setGeometry(320,458,50,25); + connect(button,SIGNAL(clicked()),this,SLOT(selectSkinData())); + + // + // Sound Panel Section + // + label=new QLabel(tr("Sound Panel Settings"),this,"globals_label"); + label->setFont(big_font); +// label->setGeometry(430,179,200,16); + label->setGeometry(430,10,200,16); + + // + // # of Station Panels + // + air_station_box=new QSpinBox(this,"air_station_box"); + air_station_box->setGeometry(510,35,50,20); + air_station_box->setRange(0,MAX_PANELS); + air_station_box->setSpecialValueText(tr("None")); + air_station_label=new QLabel(air_station_box,tr("Host Panels:"), + this,"air_station_label"); + air_station_label->setGeometry(405,35,100,20); + air_station_label->setAlignment(AlignRight|AlignVCenter); + + // + // # of User Panels + // + air_user_box=new QSpinBox(this,"air_user_box"); + air_user_box->setGeometry(510,57,50,20); + air_user_box->setRange(0,MAX_PANELS); + air_user_box->setSpecialValueText(tr("None")); + air_user_label=new QLabel(air_user_box,tr("User Panels:"), + this,"air_user_label"); + air_user_label->setGeometry(405,57,100,20); + air_user_label->setAlignment(AlignRight|AlignVCenter); + + // + // Flash Active Button + // + air_flash_box=new QCheckBox(this,"air_flash_box"); + air_flash_box->setGeometry(435,85,15,15); + label=new QLabel(air_flash_box,tr("Flash Active Buttons"), + this,"air_flash_label"); + label->setGeometry(455,85,150,15); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Pause Panel Button + // + air_panel_pause_box=new QCheckBox(this,"air_panel_pause_box"); + air_panel_pause_box->setGeometry(435,107,15,15); + label=new QLabel(air_panel_pause_box,tr("Enable Button Pausing"), + this,"air_panel_pause_label"); + label->setGeometry(455,107,150,15); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Clear Cart Filter + // + air_clearfilter_box=new QCheckBox(this,"air_clearfilter_box"); + air_clearfilter_box->setGeometry(435,129,15,15); + label=new QLabel(air_clearfilter_box,tr("Clear Cart Search Filter"), + this,"air_clearfilter_label"); + label->setGeometry(455,129,150,15); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Default Service + // + air_defaultsvc_box=new QComboBox(this,"air_defaultsvc_box"); + air_defaultsvc_box->setGeometry(520,151,100,20); + label=new QLabel(air_defaultsvc_box,tr("Default Service:"), + this,"air_defaultsvc_label"); + label->setGeometry(385,151,130,20); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Label Template + // + air_label_template_edit=new QLineEdit(this,"air_label_template_edit"); + air_label_template_edit->setGeometry(520,173,sizeHint().width()-530,20); + label=new QLabel(air_label_template_edit,tr("Label Template:"), + this,"air_label_template_label"); + label->setGeometry(415,173,100,20); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(small_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(small_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + if(station->scanned()) { + for(int i=0;i<6;i++) { + air_card_sel[i]->setMaxCards(cae_station->cards()); + for(int j=0;jmaxCards();j++) { + air_card_sel[i]->setMaxPorts(j,cae_station->cardOutputs(j)); + } + } + } + else { + QMessageBox::information(this,tr("No Audio Configuration Data"), + tr("Channel assignments will not be available for this host, as audio resource data\nhas not yet been generated. Please start the Rivendell daemons on this host\n(by executing, as user 'root', the command \"/etc/init.d/rivendell start\")\nin order to populate the audio resources database.")); + for(int i=0;i<6;i++) { + air_card_sel[i]->setDisabled(true); + } + } + air_card_sel[0]->setCard(air_conf->card(RDAirPlayConf::SoundPanel1Channel)); + air_card_sel[0]->setPort(air_conf->port(RDAirPlayConf::SoundPanel1Channel)); + + air_card_sel[1]->setCard(air_conf->card(RDAirPlayConf::SoundPanel2Channel)); + air_card_sel[1]->setPort(air_conf->port(RDAirPlayConf::SoundPanel2Channel)); + + air_card_sel[2]->setCard(air_conf->card(RDAirPlayConf::SoundPanel3Channel)); + air_card_sel[2]->setPort(air_conf->port(RDAirPlayConf::SoundPanel3Channel)); + + air_card_sel[3]->setCard(air_conf->card(RDAirPlayConf::SoundPanel4Channel)); + air_card_sel[3]->setPort(air_conf->port(RDAirPlayConf::SoundPanel4Channel)); + + air_card_sel[4]->setCard(air_conf->card(RDAirPlayConf::SoundPanel5Channel)); + air_card_sel[4]->setPort(air_conf->port(RDAirPlayConf::SoundPanel5Channel)); + + air_card_sel[5]->setCard(air_conf->card(RDAirPlayConf::CueChannel)); + air_card_sel[5]->setPort(air_conf->port(RDAirPlayConf::CueChannel)); + + air_defaultsvc_box->insertItem(tr("[none]")); + QString defaultsvc=air_conf->defaultSvc(); + sql=QString().sprintf("select SERVICE_NAME from SERVICE_PERMS \ + where STATION_NAME=\"%s\"", + (const char *)air_conf->station()); + q=new RDSqlQuery(sql); + while(q->next()) { + air_defaultsvc_box->insertItem(q->value(0).toString()); + if(defaultsvc==q->value(0).toString()) { + air_defaultsvc_box->setCurrentItem(air_defaultsvc_box->count()-1); + } + } + delete q; + air_skin_edit->setText(air_conf->skinPath()); + air_station_box->setValue(air_conf->panels(RDAirPlayConf::StationPanel)); + air_user_box->setValue(air_conf->panels(RDAirPlayConf::UserPanel)); + air_clearfilter_box->setChecked(air_conf->clearFilter()); + air_flash_box->setChecked(air_conf->flashPanel()); + air_panel_pause_box->setChecked(air_conf->panelPauseEnabled()); + air_label_template_edit->setText(air_conf->buttonLabelTemplate()); + air_start_rml_edit[0]-> + setText(air_conf->startRml(RDAirPlayConf::SoundPanel1Channel)); + air_stop_rml_edit[0]-> + setText(air_conf->stopRml(RDAirPlayConf::SoundPanel1Channel)); + + air_start_rml_edit[1]-> + setText(air_conf->startRml(RDAirPlayConf::SoundPanel2Channel)); + air_stop_rml_edit[1]-> + setText(air_conf->stopRml(RDAirPlayConf::SoundPanel2Channel)); + + air_start_rml_edit[2]-> + setText(air_conf->startRml(RDAirPlayConf::SoundPanel3Channel)); + air_stop_rml_edit[2]-> + setText(air_conf->stopRml(RDAirPlayConf::SoundPanel3Channel)); + + air_start_rml_edit[3]-> + setText(air_conf->startRml(RDAirPlayConf::SoundPanel4Channel)); + air_stop_rml_edit[3]-> + setText(air_conf->stopRml(RDAirPlayConf::SoundPanel4Channel)); + + air_start_rml_edit[4]-> + setText(air_conf->startRml(RDAirPlayConf::SoundPanel5Channel)); + air_stop_rml_edit[4]-> + setText(air_conf->stopRml(RDAirPlayConf::SoundPanel5Channel)); + + air_start_rml_edit[5]->setText(air_conf->startRml(RDAirPlayConf::CueChannel)); + air_stop_rml_edit[5]->setText(air_conf->stopRml(RDAirPlayConf::CueChannel)); +} + + +EditRDPanel::~EditRDPanel() +{ +} + + +QSize EditRDPanel::sizeHint() const +{ + return QSize(630,496); +} + + +QSizePolicy EditRDPanel::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditRDPanel::selectSkinData() +{ + QString filename=air_skin_edit->text(); + filename=QFileDialog::getOpenFileName(filename,RD_IMAGE_FILE_FILTER,this,"", + tr("Select Image File")); + if(!filename.isNull()) { + air_skin_edit->setText(filename); + } +} + + +void EditRDPanel::okData() +{ + air_conf->setStartRml(RDAirPlayConf::SoundPanel1Channel, + air_start_rml_edit[0]->text()); + air_conf->setStopRml(RDAirPlayConf::SoundPanel1Channel, + air_stop_rml_edit[0]->text()); + air_conf->setCard(RDAirPlayConf::SoundPanel1Channel,air_card_sel[0]->card()); + air_conf->setPort(RDAirPlayConf::SoundPanel1Channel,air_card_sel[0]->port()); + + air_conf->setStartRml(RDAirPlayConf::SoundPanel2Channel, + air_start_rml_edit[1]->text()); + air_conf->setStopRml(RDAirPlayConf::SoundPanel2Channel, + air_stop_rml_edit[1]->text()); + air_conf->setCard(RDAirPlayConf::SoundPanel2Channel,air_card_sel[1]->card()); + air_conf->setPort(RDAirPlayConf::SoundPanel2Channel,air_card_sel[1]->port()); + + air_conf->setStartRml(RDAirPlayConf::SoundPanel3Channel, + air_start_rml_edit[2]->text()); + air_conf->setStopRml(RDAirPlayConf::SoundPanel3Channel, + air_stop_rml_edit[2]->text()); + air_conf->setCard(RDAirPlayConf::SoundPanel3Channel,air_card_sel[2]->card()); + air_conf->setPort(RDAirPlayConf::SoundPanel3Channel,air_card_sel[2]->port()); + + air_conf->setStartRml(RDAirPlayConf::SoundPanel4Channel, + air_start_rml_edit[3]->text()); + air_conf->setStopRml(RDAirPlayConf::SoundPanel4Channel, + air_stop_rml_edit[3]->text()); + air_conf->setCard(RDAirPlayConf::SoundPanel4Channel,air_card_sel[3]->card()); + air_conf->setPort(RDAirPlayConf::SoundPanel4Channel,air_card_sel[3]->port()); + + air_conf->setStartRml(RDAirPlayConf::SoundPanel5Channel, + air_start_rml_edit[4]->text()); + air_conf->setStopRml(RDAirPlayConf::SoundPanel5Channel, + air_stop_rml_edit[4]->text()); + air_conf->setCard(RDAirPlayConf::SoundPanel5Channel,air_card_sel[4]->card()); + air_conf->setPort(RDAirPlayConf::SoundPanel5Channel,air_card_sel[4]->port()); + + air_conf->setStartRml(RDAirPlayConf::CueChannel, + air_start_rml_edit[5]->text()); + air_conf->setStopRml(RDAirPlayConf::CueChannel,air_stop_rml_edit[5]->text()); + air_conf->setCard(RDAirPlayConf::CueChannel,air_card_sel[5]->card()); + air_conf->setPort(RDAirPlayConf::CueChannel,air_card_sel[5]->port()); + air_conf->setSkinPath(air_skin_edit->text()); + if(air_defaultsvc_box->currentItem()==0) { + air_conf->setDefaultSvc(""); + } + else { + air_conf->setDefaultSvc(air_defaultsvc_box->currentText()); + } + air_conf->setPanels(RDAirPlayConf::StationPanel,air_station_box->value()); + air_conf->setPanels(RDAirPlayConf::UserPanel,air_user_box->value()); + air_conf->setClearFilter(air_clearfilter_box->isChecked()); + air_conf->setFlashPanel(air_flash_box->isChecked()); + air_conf->setPanelPauseEnabled(air_panel_pause_box->isChecked()); + air_conf->setButtonLabelTemplate(air_label_template_edit->text()); + + done(0); +} + + +void EditRDPanel::cancelData() +{ + done(1); +} diff --git a/rdadmin/edit_rdpanel.h b/rdadmin/edit_rdpanel.h new file mode 100644 index 00000000..590e6d45 --- /dev/null +++ b/rdadmin/edit_rdpanel.h @@ -0,0 +1,81 @@ +// edit_rdpanel.h +// +// Edit an RDPanel Configuration +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: edit_rdpanel.h,v 1.6.8.2 2013/12/23 18:35:15 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_RDPANEL_H +#define EDIT_RDPANEL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Application Settings + */ +#define LOG_PLAY_PORTS 2 +#define MAX_MANUAL_SEGUE 10 + +class EditRDPanel : public QDialog +{ + Q_OBJECT + public: + EditRDPanel(RDStation *station,RDStation *cae_station, + QWidget *parent=0,const char *name=0); + ~EditRDPanel(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void selectSkinData(); + void okData(); + void cancelData(); + + private: + RDAirPlayConf *air_conf; + RDCardSelector *air_card_sel[6]; + QLineEdit *air_start_rml_edit[6]; + QLineEdit *air_stop_rml_edit[6]; + QLabel *air_station_label; + QSpinBox *air_station_box; + QLabel *air_user_label; + QSpinBox *air_user_box; + QCheckBox *air_clearfilter_box; + QCheckBox *air_flash_box; + QCheckBox *air_panel_pause_box; + QLineEdit *air_label_template_edit; + QComboBox *air_defaultsvc_box; + QLineEdit *air_skin_edit; +}; + + +#endif // EDIT_RDPANEL_H + diff --git a/rdadmin/edit_replicator.cpp b/rdadmin/edit_replicator.cpp new file mode 100644 index 00000000..068c30cd --- /dev/null +++ b/rdadmin/edit_replicator.cpp @@ -0,0 +1,392 @@ +// edit_replicator.cpp +// +// Edit a Rivendell Replicator +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_replicator.cpp,v 1.2 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + + +EditReplicator::EditReplicator(const QString &repl_name, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + repl_replicator=new RDReplicator(repl_name); + repl_settings=new RDSettings(); + + setCaption(tr("Replicator: ")+repl_name); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",12,QFont::Normal); + small_font.setPixelSize(12); + + // + // Replicator Name + // + repl_name_edit=new QLineEdit(this,"repl_name_edit"); + repl_name_edit->setGeometry(105,11,sizeHint().width()-115,19); + repl_name_edit->setMaxLength(32); + repl_name_edit->setReadOnly(true); + QLabel *repl_name_label=new QLabel(repl_name_edit,tr("Name:"),this, + "repl_name_label"); + repl_name_label->setGeometry(10,11,90,19); + repl_name_label->setFont(font); + repl_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Replicator Description + // + repl_description_edit=new QLineEdit(this,"repl_description_edit"); + repl_description_edit->setGeometry(105,33,sizeHint().width()-115,19); + repl_description_edit->setMaxLength(64); + QLabel *repl_description_label=new QLabel(repl_description_edit,tr("Description:"),this, + "repl_description_label"); + repl_description_label->setGeometry(10,33,90,19); + repl_description_label->setFont(font); + repl_description_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Replicator Type + // + repl_type_box=new QComboBox(this,"repl_type_box"); + repl_type_box->setGeometry(105,55,sizeHint().width()-115,19); + for(unsigned i=0;i<(int)RDReplicator::TypeLast;i++) { + repl_type_box->insertItem(RDReplicator::typeString((RDReplicator::Type)i)); + if(repl_replicator->type()==(RDReplicator::Type)i) { + repl_type_box->setCurrentItem(i); + } + } + QLabel *repl_type_label=new QLabel(repl_type_box,tr("Type:"),this, + "repl_type_label"); + repl_type_label->setGeometry(10,55,90,19); + repl_type_label->setFont(font); + repl_type_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Host System + // + repl_station_box=new QComboBox(this,"repl_station_box"); + repl_station_box->setGeometry(155,77,sizeHint().width()-165,19); + sql="select NAME from STATIONS order by NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + repl_station_box->insertItem(q->value(0).toString()); + if(repl_replicator->stationName()==q->value(0).toString()) { + repl_station_box->setCurrentItem(repl_station_box->count()-1); + } + } + delete q; + QLabel *repl_station_label= + new QLabel(repl_station_box,tr("Host System:"),this,"repl_station_label"); + repl_station_label->setGeometry(10,77,140,19); + repl_station_label->setFont(font); + repl_station_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Upload Audio URL + // + repl_url_edit= + new QLineEdit(this,"repl_url_edit"); + repl_url_edit->setGeometry(155,99,335,19); + repl_url_edit->setMaxLength(255); + repl_url_label= + new QLabel(repl_url_edit,tr("Audio Upload URL:"),this, + "repl_url_label"); + repl_url_label->setGeometry(20,99,130,19); + repl_url_label->setFont(font); + repl_url_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Upload Username + // + repl_username_edit= + new QLineEdit(this,"repl_username_edit"); + repl_username_edit->setGeometry(225,121,95,19); + repl_username_edit->setMaxLength(64); + repl_username_label= + new QLabel(repl_username_edit,tr("Username:"),this, + "repl_username_label"); + repl_username_label->setGeometry(40,121,180,19); + repl_username_label->setFont(font); + repl_username_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Upload Password + // + repl_password_edit= + new QLineEdit(this,"repl_password_edit"); + repl_password_edit->setGeometry(395,121,95,19); + repl_password_edit->setMaxLength(64); + repl_password_edit->setEchoMode(QLineEdit::Password); + repl_password_label= + new QLabel(repl_password_edit,tr("Password:"),this, + "repl_password_label"); + repl_password_label->setGeometry(320,121,70,19); + repl_password_label->setFont(font); + repl_password_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Audio Format + // + repl_format_edit=new QLineEdit(this,"repl_format_edit"); + repl_format_edit->setGeometry(155,143,285,20); + repl_format_edit->setReadOnly(true); + repl_format_label=new QLabel(repl_format_edit, + tr("Upload Format:"),this,"repl_format_label"); + repl_format_label->setGeometry(5,143,145,20); + repl_format_label->setFont(font); + repl_format_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + repl_format_button=new QPushButton(this,"format_button"); + repl_format_button->setGeometry(450,142,40,24); + repl_format_button->setFont(small_font); + repl_format_button->setText(tr("S&et")); + connect(repl_format_button,SIGNAL(clicked()),this,SLOT(setFormatData())); + + // + // Normalize Check Box + // + repl_normalize_box=new QCheckBox(this,"repl_normalize_box"); + repl_normalize_box->setGeometry(155,167,15,15); + repl_normalize_box->setChecked(true); + repl_normalize_check_label=new QLabel(repl_normalize_box,tr("Normalize"), + this,"normalize_check_label"); + repl_normalize_check_label->setGeometry(175,165,83,20); + repl_normalize_check_label->setFont(font); + repl_normalize_check_label->setAlignment(AlignLeft|AlignVCenter); + connect(repl_normalize_box,SIGNAL(toggled(bool)), + this,SLOT(normalizeCheckData(bool))); + + // + // Normalize Level + // + repl_normalize_spin=new QSpinBox(this,"repl_normalize_spin"); + repl_normalize_spin->setGeometry(295,165,40,20); + repl_normalize_spin->setRange(-30,-1); + repl_normalize_label=new QLabel(repl_normalize_spin,tr("Level:"), + this,"normalize_spin_label"); + repl_normalize_label->setGeometry(245,165,45,20); + repl_normalize_label->setFont(font); + repl_normalize_label->setAlignment(AlignRight|AlignVCenter); + repl_normalize_unit_label=new QLabel(tr("dBFS"),this,"normalize_unit_label"); + repl_normalize_unit_label->setGeometry(340,165,40,20); + repl_normalize_unit_label->setFont(font); + repl_normalize_unit_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Groups Selector + // + repl_groups_sel=new RDListSelector(this,"repl_groups_sel"); + repl_groups_sel->setGeometry(60,192,380,130); + repl_groups_sel->sourceSetLabel(tr("Available Groups")); + repl_groups_sel->destSetLabel(tr("Active Groups")); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Values + // + repl_name_edit->setText(repl_replicator->name()); + repl_description_edit->setText(repl_replicator->description()); + repl_url_edit->setText(repl_replicator->url()); + repl_username_edit->setText(repl_replicator->urlUsername()); + repl_password_edit->setText(repl_replicator->urlPassword()); + repl_settings->setFormat(repl_replicator->format()); + repl_settings->setChannels(repl_replicator->channels()); + repl_settings->setSampleRate(repl_replicator->sampleRate()); + repl_settings->setBitRate(repl_replicator->bitRate()); + repl_settings->setQuality(repl_replicator->quality()); + repl_format_edit->setText(repl_settings->description()); + if(repl_replicator->normalizeLevel()>0) { + repl_normalize_box->setChecked(false); + } + else { + repl_normalize_box->setChecked(true); + repl_normalize_spin->setValue(repl_replicator->normalizeLevel()/1000); + } + sql=QString().sprintf("select GROUP_NAME from REPLICATOR_MAP \ + where REPLICATOR_NAME=\"%s\"", + (const char *)RDEscapeString(repl_name_edit->text())); + q=new RDSqlQuery(sql); + while(q->next()) { + repl_groups_sel->destInsertItem(q->value(0).toString()); + } + delete q; + + sql=QString().sprintf("select NAME from GROUPS"); + q=new RDSqlQuery(sql); + while(q->next()) { + if(repl_groups_sel->destFindItem(q->value(0).toString())==0) { + repl_groups_sel->sourceInsertItem(q->value(0).toString()); + } + } + delete q; +} + + +EditReplicator::~EditReplicator() +{ + delete repl_settings; + delete repl_replicator; +} + + +QSize EditReplicator::sizeHint() const +{ + return QSize(500,409); +} + + +QSizePolicy EditReplicator::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditReplicator::setFormatData() +{ + RDStation *station=new RDStation(admin_config->stationName()); + RDExportSettingsDialog *dialog= + new RDExportSettingsDialog(repl_settings,station,this,"dialog"); + dialog->exec(); + delete dialog; + delete station; + repl_format_edit->setText(repl_settings->description()); +} + + +void EditReplicator::normalizeCheckData(bool state) +{ + repl_normalize_label->setEnabled(state); + repl_normalize_spin->setEnabled(state); + repl_normalize_unit_label->setEnabled(state); +} + + +void EditReplicator::okData() +{ + QString sql; + RDSqlQuery *q; + + repl_replicator->setDescription(repl_description_edit->text()); + repl_replicator->setType((RDReplicator::Type)repl_type_box->currentItem()); + repl_replicator->setStationName(repl_station_box->currentText()); + repl_replicator->setUrl(repl_url_edit->text()); + repl_replicator->setUrlUsername(repl_username_edit->text()); + repl_replicator->setUrlPassword(repl_password_edit->text()); + repl_replicator->setFormat(repl_settings->format()); + repl_replicator->setChannels(repl_settings->channels()); + repl_replicator->setSampleRate(repl_settings->sampleRate()); + repl_replicator->setBitRate(repl_settings->bitRate()); + repl_replicator->setQuality(repl_settings->quality()); + if(repl_normalize_box->isChecked()) { + repl_replicator->setNormalizeLevel(repl_normalize_spin->value()*1000); + } + else { + repl_replicator->setNormalizeLevel(1); + } + + // + // Add New Groups + // + for(unsigned i=0;idestCount();i++) { + sql=QString().sprintf("select GROUP_NAME from REPLICATOR_MAP \ +where REPLICATOR_NAME=\"%s\" && GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(repl_name_edit->text()), + (const char *)RDEscapeString(repl_groups_sel->destText(i))); + q=new RDSqlQuery(sql); + if(q->size()==0) { + delete q; + sql=QString().sprintf("insert into REPLICATOR_MAP (REPLICATOR_NAME,GROUP_NAME) \ +values (\"%s\",\"%s\")", + (const char *)RDEscapeString(repl_name_edit->text()), + (const char *)RDEscapeString(repl_groups_sel->destText(i))); + q=new RDSqlQuery(sql); + } + delete q; + } + + // + // Delete Old Groups + // + sql=QString().sprintf("delete from REPLICATOR_MAP where REPLICATOR_NAME=\"%s\"", + (const char *)RDEscapeString(repl_name_edit->text())); + for(unsigned i=0;idestCount();i++) { + sql+=QString().sprintf(" && GROUP_NAME<>\"%s\"", + (const char *)RDEscapeString(repl_groups_sel->destText(i))); + } + q=new RDSqlQuery(sql); + delete q; + + done(0); +} + + +void EditReplicator::cancelData() +{ + done(-1); +} diff --git a/rdadmin/edit_replicator.h b/rdadmin/edit_replicator.h new file mode 100644 index 00000000..8fec3bd6 --- /dev/null +++ b/rdadmin/edit_replicator.h @@ -0,0 +1,85 @@ + +// edit_replicator.h +// +// Edit a Rivendell Replicator +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: edit_replicator.h,v 1.2 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_REPLICATOR_H +#define EDIT_REPLICATOR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +class EditReplicator : public QDialog +{ + Q_OBJECT + public: + EditReplicator(const QString &repl_name,QWidget *parent=0,const char *name=0); + ~EditReplicator(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void setFormatData(); + void normalizeCheckData(bool state); + void okData(); + void cancelData(); + + private: + RDReplicator *repl_replicator; + QLineEdit *repl_name_edit; + QLineEdit *repl_description_edit; + QComboBox *repl_type_box; + QComboBox *repl_station_box; + QLineEdit *repl_url_edit; + QLabel *repl_username_label; + QLineEdit *repl_username_edit; + QLabel *repl_password_label; + QLineEdit *repl_password_edit; + QLineEdit *repl_format_edit; + QCheckBox *repl_normalize_box; + QLabel *repl_normalize_label; + QSpinBox *repl_normalize_spin; + QPushButton *repl_format_button; + QPushButton *repl_metadata_button; + RDSettings *repl_settings; + + QLabel *repl_url_label; + QLabel *repl_format_label; + QLabel *repl_normalize_check_label; + QLabel *repl_normalize_unit_label; + RDListSelector *repl_groups_sel; +}; + + +#endif // EDIT_REPLICATOR_H + diff --git a/rdadmin/edit_report.cpp b/rdadmin/edit_report.cpp new file mode 100644 index 00000000..73808fe9 --- /dev/null +++ b/rdadmin/edit_report.cpp @@ -0,0 +1,656 @@ +// edit_report.cpp +// +// Edit a Rivendell Report +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_report.cpp,v 1.21.8.1.2.1 2014/05/22 01:21:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +EditReport::EditReport(QString rptname,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + QString str; + bool ok=false; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + edit_report=new RDReport(rptname); + str=QString(tr("Edit Report")); + setCaption(QString().sprintf("%s - %s",(const char *)str, + (const char *)rptname)); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont check_font=QFont("Helvetica",12,QFont::Normal); + check_font.setPixelSize(12); + QFont section_font=QFont("Helvetica",14,QFont::Bold); + section_font.setPixelSize(14); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this); + + // + // Report Description + // + edit_description_edit=new QLineEdit(this); + edit_description_edit->setGeometry(170,10,sizeHint().width()-180,19); + edit_description_edit->setMaxLength(64); + QLabel *label= + new QLabel(edit_description_edit,tr("&Report Description:"),this); + label->setGeometry(10,10,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Export Filter Type + // + edit_filter_box=new QComboBox(this); + edit_filter_box->setGeometry(170,31,sizeHint().width()-180,19); + for(int i=0;i<(int)RDReport::LastFilter;i++) { + edit_filter_box-> + insertItem(RDReport::filterText((RDReport::ExportFilter)i)); + } + label=new QLabel(edit_description_edit,tr("Export &Filter:"),this); + label->setGeometry(10,31,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Station ID + // + edit_stationid_edit=new QLineEdit(this); + edit_stationid_edit->setGeometry(170,52,180,19); + edit_stationid_edit->setMaxLength(16); + edit_stationid_edit->setValidator(validator); + label=new QLabel(edit_stationid_edit,tr("Station ID:"),this); + label->setGeometry(10,52,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Cart Number Parameters + // + label=new QLabel(tr("Cart Number Parameters:"),this); + label->setGeometry(10,73,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + edit_cartzeros_box=new QCheckBox(this); + edit_cartzeros_box->setGeometry(170,75,15,15); + connect(edit_cartzeros_box,SIGNAL(toggled(bool)), + this,SLOT(leadingZerosToggled(bool))); + label=new QLabel(edit_cartzeros_box, + tr("Use Leading Zeros"),this, + "edit_cartzeros_label"); + label->setGeometry(187,73,120,19); + label->setFont(check_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + edit_cartdigits_spin=new QSpinBox(this); + edit_cartdigits_spin->setGeometry(350,73,40,19); + edit_cartdigits_spin->setRange(1,6); + edit_cartdigits_label=new QLabel(edit_cartdigits_spin,tr("Digits:"),this); + edit_cartdigits_label->setGeometry(300,73,45,19); + edit_cartdigits_label->setFont(check_font); + edit_cartdigits_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Station Type + // + edit_stationtype_box=new QComboBox(this); + edit_stationtype_box->setGeometry(170,94,70,19); + for(int i=0;i + insertItem(RDReport::stationTypeText((RDReport::StationType)i)); + } + label=new QLabel(edit_stationtype_box,tr("Station Type:"),this); + label->setGeometry(10,94,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Lines Per Page + // + edit_linesperpage_spin=new QSpinBox(this); + edit_linesperpage_spin->setGeometry(360,94,50,19); + edit_linesperpage_spin->setRange(10,200); + label=new QLabel(edit_linesperpage_spin,tr("Lines per Page:"),this); + label->setGeometry(255,94,100,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + edit_linesperpage_spin->hide(); + label->hide(); + + // + // Service Name + // + edit_servicename_edit=new QLineEdit(this); + edit_servicename_edit->setGeometry(170,115,sizeHint().width()-180,19); + edit_servicename_edit->setMaxLength(64); + label=new QLabel(edit_servicename_edit,tr("Ser&vice Name:"),this); + label->setGeometry(10,115,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Station Format + // + edit_stationformat_edit=new QLineEdit(this); + edit_stationformat_edit->setGeometry(170,136,sizeHint().width()-180,19); + edit_stationformat_edit->setMaxLength(64); + label=new QLabel(edit_stationformat_edit,tr("Station &Format:"),this); + label->setGeometry(10,136,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Linux Export Path + // + edit_path_edit=new QLineEdit(this); + edit_path_edit->setGeometry(170,157,sizeHint().width()-180,19); + edit_path_edit->setMaxLength(255); + edit_path_edit->setValidator(validator); + label=new QLabel(edit_path_edit,tr("Linux Export Path:"),this); + label->setGeometry(10,157,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Windows Export Path + // + edit_winpath_edit=new QLineEdit(this); + edit_winpath_edit->setGeometry(170,178,sizeHint().width()-180,19); + edit_winpath_edit->setMaxLength(255); + label=new QLabel(edit_winpath_edit,tr("Windows Export Path:"),this); + label->setGeometry(10,178,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Type Selectors + // + label=new QLabel(tr("Export Event Types:"),this); + label->setGeometry(10,199,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + edit_traffic_box=new QCheckBox(this); + edit_traffic_box->setGeometry(170,200,15,15); + edit_traffic_label=new QLabel(tr("Traffic"),this); + edit_traffic_label->setGeometry(187,199,80,19); + edit_traffic_label->setFont(check_font); + edit_traffic_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + edit_music_box=new QCheckBox(this); + edit_music_box->setGeometry(270,201,15,15); + edit_music_label=new QLabel(tr("Music"),this); + edit_music_label->setGeometry(287,199,80,19); + edit_music_label->setFont(check_font); + edit_music_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + edit_generic_box=new QCheckBox(this); + edit_generic_box->setGeometry(370,201,15,15); + label=new QLabel(tr("All"),this); + label->setGeometry(387,199,80,19); + label->setFont(check_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + connect(edit_generic_box,SIGNAL(toggled(bool)), + this,SLOT(genericEventsToggledData(bool))); + + // + // Force Event Source Selectors + // + label=new QLabel(tr("Export Events From:"),this); + label->setGeometry(10,220,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + edit_forcetraffic_box=new QCheckBox(this); + edit_forcetraffic_box->setGeometry(170,222,15,15); + label=new QLabel(tr("Traffic Log"),this); + label->setGeometry(187,220,80,19); + label->setFont(check_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + edit_forcemusic_box=new QCheckBox(this); + edit_forcemusic_box->setGeometry(270,222,15,15); + label=new QLabel(tr("Music Log"),this); + label->setGeometry(287,220,80,19); + label->setFont(check_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Include Only On Air Events + // + edit_onairflag_box=new QComboBox(this); + edit_onairflag_box->setGeometry(170,241,60,19); + edit_onairflag_box->insertItem(tr("No")); + edit_onairflag_box->insertItem(tr("Yes")); + label=new QLabel(edit_onairflag_box,tr("Include Only OnAir Events:"),this); + label->setGeometry(10,241,155,19); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Daypart Filter + // + edit_daypart_check=new QCheckBox(this); + edit_daypart_check->setGeometry(60,271,15,15); + edit_daypart_label= + new QLabel(edit_daypart_check,tr("Filter by Daypart"),this); + edit_daypart_label->setGeometry(edit_daypart_check->geometry().x()+20,271,155,19); + edit_daypart_label->setFont(font); + edit_daypart_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + edit_starttime_edit=new QTimeEdit(this); + edit_starttime_edit->setGeometry(150,292,80,20); + edit_starttime_label=new QLabel(edit_starttime_edit,tr("Start Time:"),this); + edit_starttime_label->setGeometry(65,292,80,20); + edit_starttime_label->setFont(font); + edit_starttime_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + edit_endtime_edit=new QTimeEdit(this); + edit_endtime_edit->setGeometry(335,292,80,20); + edit_endtime_label=new QLabel(edit_endtime_edit,tr("End Time:"),this); + edit_endtime_label->setGeometry(250,292,80,20); + edit_endtime_label->setFont(font); + edit_endtime_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + connect(edit_daypart_check,SIGNAL(toggled(bool)), + edit_starttime_label,SLOT(setEnabled(bool))); + connect(edit_daypart_check,SIGNAL(toggled(bool)), + edit_starttime_edit,SLOT(setEnabled(bool))); + connect(edit_daypart_check,SIGNAL(toggled(bool)), + edit_endtime_label,SLOT(setEnabled(bool))); + connect(edit_daypart_check,SIGNAL(toggled(bool)), + edit_endtime_edit,SLOT(setEnabled(bool))); + + // + // Service Selector + // + edit_service_sel=new RDListSelector(this); + edit_service_sel-> + setGeometry((sizeHint().width()-edit_service_sel->sizeHint().width())/2, + 331,edit_service_sel->sizeHint().width(), + edit_service_sel->sizeHint().height()); + edit_service_sel->sourceSetLabel(tr("Available Services")); + edit_service_sel->destSetLabel(tr("Source Services")); + + // + // Station Selector + // + edit_station_sel=new RDListSelector(this); + edit_station_sel-> + setGeometry((sizeHint().width()-edit_station_sel->sizeHint().width())/2, + 445,edit_station_sel->sizeHint().width(), + edit_station_sel->sizeHint().height()); + edit_station_sel->sourceSetLabel(tr("Available Hosts")); + edit_station_sel->destSetLabel(tr("Source Hosts")); + + // + // Group Selector + // + edit_group_sel=new RDListSelector(this); + edit_group_sel-> + setGeometry((sizeHint().width()-edit_group_sel->sizeHint().width())/2, + 576,edit_group_sel->sizeHint().width(), + edit_group_sel->sizeHint().height()); + edit_group_sel->sourceSetLabel(tr("Available Groups")); + edit_group_sel->destSetLabel(tr("Allowed Groups")); + + edit_group_box=new QCheckBox(this); + edit_group_box->setGeometry(60,552,15,15); + label=new QLabel(edit_group_box,tr("Filter by Groups"),this); + label->setGeometry(edit_group_box->geometry().x()+20,551,155,19); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + connect(edit_group_box,SIGNAL(toggled(bool)), + edit_group_sel,SLOT(setEnabled(bool))); + + + // + // Ok Button + // + QPushButton *button=new QPushButton(this); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + edit_description_edit->setText(edit_report->description()); + edit_filter_box->setCurrentItem((int)edit_report->filter()); + edit_stationid_edit->setText(edit_report->stationId()); + edit_cartzeros_box->setChecked(edit_report->useLeadingZeros()); + leadingZerosToggled(edit_cartzeros_box->isChecked()); + edit_cartdigits_spin->setValue(edit_report->cartDigits()); + edit_stationtype_box->setCurrentItem((int)edit_report->stationType()); + edit_servicename_edit->setText(edit_report->serviceName()); + edit_stationformat_edit->setText(edit_report->stationFormat()); + edit_linesperpage_spin->setValue(edit_report->linesPerPage()); + edit_path_edit->setText(edit_report->exportPath(RDReport::Linux)); + edit_winpath_edit->setText(edit_report->exportPath(RDReport::Windows)); + edit_traffic_box-> + setChecked(edit_report->exportTypeEnabled(RDReport::Traffic)); + edit_music_box-> + setChecked(edit_report->exportTypeEnabled(RDReport::Music)); + edit_generic_box-> + setChecked(edit_report->exportTypeEnabled(RDReport::Generic)); + edit_forcetraffic_box-> + setChecked(edit_report->exportTypeForced(RDReport::Traffic)); + edit_forcemusic_box-> + setChecked(edit_report->exportTypeForced(RDReport::Music)); + genericEventsToggledData(edit_generic_box->isChecked()); + if(edit_report->filterOnairFlag()) { + edit_onairflag_box->setCurrentItem(1); + } + else { + edit_onairflag_box->setCurrentItem(0); + } + edit_starttime_edit->setTime(edit_report->startTime(&ok)); + edit_starttime_label->setDisabled(ok); + edit_starttime_edit->setDisabled(ok); + edit_endtime_edit->setTime(edit_report->endTime(&ok)); + edit_endtime_label->setDisabled(ok); + edit_endtime_edit->setDisabled(ok); + edit_daypart_check->setChecked(!ok); + + sql=QString().sprintf("select SERVICE_NAME from REPORT_SERVICES \ + where REPORT_NAME=\"%s\"", + (const char *)edit_report->name()); + q=new RDSqlQuery(sql); + while(q->next()) { + edit_service_sel->destInsertItem(q->value(0).toString()); + } + delete q; + + sql=QString().sprintf("select NAME from SERVICES"); + q=new RDSqlQuery(sql); + while(q->next()) { + if(edit_service_sel->destFindItem(q->value(0).toString())==0) { + edit_service_sel->sourceInsertItem(q->value(0).toString()); + } + } + delete q; + + sql=QString().sprintf("select STATION_NAME from REPORT_STATIONS \ + where REPORT_NAME=\"%s\"", + (const char *)edit_report->name()); + q=new RDSqlQuery(sql); + while(q->next()) { + edit_station_sel->destInsertItem(q->value(0).toString()); + } + delete q; + + sql=QString().sprintf("select NAME from STATIONS"); + q=new RDSqlQuery(sql); + while(q->next()) { + if(edit_station_sel->destFindItem(q->value(0).toString())==0) { + edit_station_sel->sourceInsertItem(q->value(0).toString()); + } + } + delete q; + + edit_group_box->setChecked(edit_report->filterGroups()); + edit_group_sel->setEnabled(edit_report->filterGroups()); + sql=QString().sprintf("select GROUP_NAME from REPORT_GROUPS \ + where REPORT_NAME=\"%s\"", + (const char *)edit_report->name()); + q=new RDSqlQuery(sql); + while(q->next()) { + edit_group_sel->destInsertItem(q->value(0).toString()); + } + delete q; + + sql=QString().sprintf("select NAME from GROUPS"); + q=new RDSqlQuery(sql); + while(q->next()) { + if(edit_group_sel->destFindItem(q->value(0).toString())==0) { + edit_group_sel->sourceInsertItem(q->value(0).toString()); + } + } + delete q; +} + + +EditReport::~EditReport() +{ +} + + +QSize EditReport::sizeHint() const +{ + return QSize(500,732); +} + + +QSizePolicy EditReport::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditReport::leadingZerosToggled(bool state) +{ + edit_cartdigits_label->setEnabled(state); + edit_cartdigits_spin->setEnabled(state); +} + + +void EditReport::genericEventsToggledData(bool state) +{ + edit_traffic_label->setDisabled(state); + edit_traffic_box->setDisabled(state); + edit_music_label->setDisabled(state); + edit_music_box->setDisabled(state); +} + + +void EditReport::okData() +{ + QString sql; + RDSqlQuery *q; + + edit_report->setDescription(edit_description_edit->text()); + edit_report-> + setFilter((RDReport::ExportFilter)edit_filter_box->currentItem()); + edit_report->setStationId(edit_stationid_edit->text()); + edit_report->setCartDigits(edit_cartdigits_spin->value()); + edit_report->setUseLeadingZeros(edit_cartzeros_box->isChecked()); + edit_report->setLinesPerPage(edit_linesperpage_spin->value()); + edit_report-> + setStationType((RDReport::StationType)edit_stationtype_box->currentItem()); + edit_report->setServiceName(edit_servicename_edit->text()); + edit_report->setStationFormat(edit_stationformat_edit->text()); + edit_report->setExportPath(RDReport::Linux,edit_path_edit->text()); + edit_report->setExportPath(RDReport::Windows,edit_winpath_edit->text()); + edit_report-> + setExportTypeEnabled(RDReport::Traffic,edit_traffic_box->isChecked()); + edit_report-> + setExportTypeEnabled(RDReport::Music,edit_music_box->isChecked()); + edit_report-> + setExportTypeForced(RDReport::Traffic,edit_forcetraffic_box->isChecked()); + edit_report-> + setExportTypeForced(RDReport::Music,edit_forcemusic_box->isChecked()); + edit_report-> + setExportTypeEnabled(RDReport::Generic,edit_generic_box->isChecked()); + edit_report->setFilterOnairFlag(edit_onairflag_box->currentItem()==1); + edit_report->setFilterGroups(edit_group_box->isChecked()); + if(edit_daypart_check->isChecked()) { + edit_report->setStartTime(edit_starttime_edit->time()); + edit_report->setEndTime(edit_endtime_edit->time()); + } + else { + edit_report->setStartTime(); + edit_report->setEndTime(); + } + + // + // Add New Services + // + for(unsigned i=0;idestCount();i++) { + sql=QString().sprintf("select SERVICE_NAME from REPORT_SERVICES \ +where REPORT_NAME=\"%s\" && SERVICE_NAME=\"%s\"", + (const char *)edit_report->name(), + (const char *)edit_service_sel->destText(i)); + q=new RDSqlQuery(sql); + if(q->size()==0) { + delete q; + sql=QString(). + sprintf("insert into REPORT_SERVICES (REPORT_NAME,SERVICE_NAME) \ + values (\"%s\",\"%s\")", + (const char *)edit_report->name(), + (const char *)edit_service_sel->destText(i)); + q=new RDSqlQuery(sql); + } + delete q; + } + + // + // Delete Old Services + // + sql=QString().sprintf("delete from REPORT_SERVICES where REPORT_NAME=\"%s\"", + (const char *)edit_report->name()); + for(unsigned i=0;idestCount();i++) { + sql+=QString().sprintf(" && SERVICE_NAME<>\"%s\"", + (const char *)edit_service_sel->destText(i)); + } + q=new RDSqlQuery(sql); + delete q; + + // + // Add New Stations + // + for(unsigned i=0;idestCount();i++) { + sql=QString().sprintf("select STATION_NAME from REPORT_STATIONS \ +where REPORT_NAME=\"%s\" && STATION_NAME=\"%s\"", + (const char *)edit_report->name(), + (const char *)edit_station_sel->destText(i)); + q=new RDSqlQuery(sql); + if(q->size()==0) { + delete q; + sql=QString(). + sprintf("insert into REPORT_STATIONS (REPORT_NAME,STATION_NAME) \ + values (\"%s\",\"%s\")", + (const char *)edit_report->name(), + (const char *)edit_station_sel->destText(i)); + q=new RDSqlQuery(sql); + } + delete q; + } + + // + // Delete Old Stations + // + sql=QString().sprintf("delete from REPORT_STATIONS where REPORT_NAME=\"%s\"", + (const char *)edit_report->name()); + for(unsigned i=0;idestCount();i++) { + sql+=QString().sprintf(" && STATION_NAME<>\"%s\"", + (const char *)edit_station_sel->destText(i)); + } + q=new RDSqlQuery(sql); + delete q; + + // + // Add New Groups + // + for(unsigned i=0;idestCount();i++) { + sql=QString().sprintf("select GROUP_NAME from REPORT_GROUPS \ +where REPORT_NAME=\"%s\" && GROUP_NAME=\"%s\"", + (const char *)edit_report->name(), + (const char *)edit_group_sel->destText(i)); + q=new RDSqlQuery(sql); + if(q->size()==0) { + delete q; + sql=QString(). + sprintf("insert into REPORT_GROUPS (REPORT_NAME,GROUP_NAME) \ + values (\"%s\",\"%s\")", + (const char *)edit_report->name(), + (const char *)edit_group_sel->destText(i)); + q=new RDSqlQuery(sql); + } + delete q; + } + + // + // Delete Old Groups + // + sql=QString().sprintf("delete from REPORT_GROUPS where REPORT_NAME=\"%s\"", + (const char *)edit_report->name()); + for(unsigned i=0;idestCount();i++) { + sql+=QString().sprintf(" && GROUP_NAME<>\"%s\"", + (const char *)edit_group_sel->destText(i)); + } + q=new RDSqlQuery(sql); + delete q; + + done(0); +} + + +void EditReport::cancelData() +{ + done(-1); +} diff --git a/rdadmin/edit_report.h b/rdadmin/edit_report.h new file mode 100644 index 00000000..677c7ced --- /dev/null +++ b/rdadmin/edit_report.h @@ -0,0 +1,91 @@ +// edit_report.h +// +// Edit a Rivendell Report +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_report.h,v 1.14.8.1.2.1 2014/05/22 01:21:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_REPORT_H +#define EDIT_REPORT_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + +class EditReport : public QDialog +{ + Q_OBJECT + public: + EditReport(QString rptname,QWidget *parent=0,const char *name=0); + ~EditReport(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void leadingZerosToggled(bool state); + void genericEventsToggledData(bool state); + void okData(); + void cancelData(); + + private: + RDReport *edit_report; + QLineEdit *edit_description_edit; + QComboBox *edit_filter_box; + QLineEdit *edit_stationid_edit; + QLabel *edit_cartdigits_label; + QSpinBox *edit_cartdigits_spin; + QCheckBox *edit_cartzeros_box; + QComboBox *edit_stationtype_box; + QLineEdit *edit_servicename_edit; + QLineEdit *edit_stationformat_edit; + QSpinBox *edit_linesperpage_spin; + QLineEdit *edit_path_edit; + QLineEdit *edit_winpath_edit; + QLabel *edit_traffic_label; + QCheckBox *edit_traffic_box; + QLabel *edit_music_label; + QCheckBox *edit_music_box; + QCheckBox *edit_generic_box; + QCheckBox *edit_forcetraffic_box; + QCheckBox *edit_forcemusic_box; + QComboBox *edit_onairflag_box; + RDListSelector *edit_service_sel; + RDListSelector *edit_station_sel; + QCheckBox *edit_group_box; + RDListSelector *edit_group_sel; + QCheckBox *edit_daypart_check; + QLabel *edit_daypart_label; + QLabel *edit_starttime_label; + QTimeEdit *edit_starttime_edit; + QLabel *edit_endtime_label; + QTimeEdit *edit_endtime_edit; +}; + + +#endif + diff --git a/rdadmin/edit_sas_resource.cpp b/rdadmin/edit_sas_resource.cpp new file mode 100644 index 00000000..f8cce3a9 --- /dev/null +++ b/rdadmin/edit_sas_resource.cpp @@ -0,0 +1,180 @@ +// edit_sas_resource.cpp +// +// Edit an SAS Resource Record. +// +// (C) Copyright 2002-2005,2011 Fred Gleason +// +// $Id: edit_sas_resource.cpp,v 1.1 2011/05/07 00:32:29 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include + +EditSasResource::EditSasResource(int *enginenum,int *devicenum,int *relaynum, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_enginenum=enginenum; + edit_devicenum=devicenum; + edit_relaynum=relaynum; + setCaption(tr("Edit SAS Switch")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Console Number + // + edit_enginenum_edit=new QLineEdit(this,"edit_enginenum_edit"); + edit_enginenum_edit->setGeometry(135,10,50,20); + QLabel *label=new QLabel(edit_enginenum_edit,tr("Console Number: "), + this,"edit_enginenum_label"); + label->setGeometry(10,10,120,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Source Number + // + edit_devicenum_edit=new QLineEdit(this,"edit_devicenum_edit"); + edit_devicenum_edit->setGeometry(135,36,50,20); + label=new QLabel(edit_devicenum_edit,tr("Source Number: "), + this,"edit_devicenum_label"); + label->setGeometry(10,36,120,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Opto/Relay Number + // + edit_relaynum_edit=new QLineEdit(this,"edit_relaynum_edit"); + edit_relaynum_edit->setGeometry(135,62,50,20); + edit_relaynum_label=new QLabel(edit_relaynum_edit,tr("Opto/Relay Number: "), + this,"edit_relaynum_label"); + edit_relaynum_label->setGeometry(10,62,120,20); + edit_relaynum_label->setFont(bold_font); + edit_relaynum_label->setAlignment(AlignRight|AlignVCenter); + + // + // Ok Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Data + // + if(*enginenum>=0) { + edit_enginenum_edit->setText(QString().sprintf("%d",*enginenum)); + } + if(*devicenum>=0) { + edit_devicenum_edit->setText(QString().sprintf("%d",*devicenum)); + } + if(*relaynum>=0) { + edit_relaynum_edit->setText(QString().sprintf("%d",*relaynum)); + } +} + + +QSize EditSasResource::sizeHint() const +{ + return QSize(250,152); +} + + +QSizePolicy EditSasResource::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditSasResource::okData() +{ + bool ok; + int enginenum=edit_enginenum_edit->text().toInt(&ok); + if(!ok) { + if(edit_enginenum_edit->text().isEmpty()) { + enginenum=-1; + } + else { + QMessageBox::warning(this,tr("Invalid Number"), + tr("The Console Number is Invalid!")); + return; + } + } + int devicenum=edit_devicenum_edit->text().toInt(&ok); + if(!ok) { + if(edit_devicenum_edit->text().isEmpty()) { + devicenum=-1; + } + else { + QMessageBox::warning(this,tr("Invalid Number"), + tr("The Source Number is Invalid!")); + return; + } + } + int relaynum=edit_relaynum_edit->text().toInt(&ok); + if(!ok) { + if(edit_relaynum_edit->text().isEmpty()) { + relaynum=-1; + } + else { + QMessageBox::warning(this,tr("Invalid Number"), + tr("The Opto/Relay Number is Invalid!")); + return; + } + } + *edit_enginenum=enginenum; + *edit_devicenum=devicenum; + *edit_relaynum=relaynum; + done(0); +} + + +void EditSasResource::cancelData() +{ + done(1); +} diff --git a/rdadmin/edit_sas_resource.h b/rdadmin/edit_sas_resource.h new file mode 100644 index 00000000..b3bc2a85 --- /dev/null +++ b/rdadmin/edit_sas_resource.h @@ -0,0 +1,62 @@ +// edit_sas_resource.h +// +// Edit an SAS Resource Record. +// +// (C) Copyright 2002-2005,2011 Fred Gleason +// +// $Id: edit_sas_resource.h,v 1.1 2011/05/07 00:32:29 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_SAS_RESOURCE_H +#define EDIT_SAS_RESOURCE_H + +#include +#include +#include +#include +#include +#include + +#include +#include + + +class EditSasResource : public QDialog +{ + Q_OBJECT + public: + EditSasResource(int *enginenum,int *devicenum,int *relaynum, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + int *edit_enginenum; + int *edit_devicenum; + int *edit_relaynum; + QLineEdit *edit_enginenum_edit; + QLineEdit *edit_devicenum_edit; + QLabel *edit_relaynum_label; + QLineEdit *edit_relaynum_edit; +}; + + +#endif // EDIT_ENDPOINT + diff --git a/rdadmin/edit_schedcodes.cpp b/rdadmin/edit_schedcodes.cpp new file mode 100644 index 00000000..6eeb254a --- /dev/null +++ b/rdadmin/edit_schedcodes.cpp @@ -0,0 +1,156 @@ +// edit_schedcodes.cpp +// +// Edit scheduler codes dialog +// +// Stefan Gabriel +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +EditSchedCode::EditSchedCode(QString schedCode,QString description,QWidget *parent,const char *name) : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + schedCode_code=new QString(schedCode); + schedCode_description=new QString(description); + + setCaption(tr("Scheduler Code: ")+schedCode); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Text Validators + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + // + // Code Name + // + schedCode_name_edit=new QLineEdit(this,"schedCode_name_edit"); + schedCode_name_edit->setGeometry(125,11,100,19); + schedCode_name_edit->setMaxLength(10); + schedCode_name_edit->setReadOnly(true); + QLabel *schedCode_name_label=new QLabel(schedCode_name_edit,tr("Scheduler Code:"),this,"schedCode_name_label"); + schedCode_name_label->setGeometry(10,11,110,19); + schedCode_name_label->setFont(font); + schedCode_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Code Description + // + schedCode_description_edit=new QLineEdit(this,"schedCode_description_edit"); + schedCode_description_edit->setGeometry(125,32,sizeHint().width()-135,19); + schedCode_description_edit->setMaxLength(255); + schedCode_description_edit->setValidator(validator); + QLabel *schedCode_description_label=new QLabel(schedCode_description_edit, + tr("Code Description:"),this, + "schedCode_description_label"); + schedCode_description_label->setGeometry(10,32,110,19); + schedCode_description_label->setFont(font); + schedCode_description_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + schedCode_name_edit->setText(*schedCode_code); + schedCode_description_edit->setText(*schedCode_description); +} + + +EditSchedCode::~EditSchedCode() +{ + delete schedCode_name_edit; + delete schedCode_description_edit; +} + + +QSize EditSchedCode::sizeHint() const +{ + return QSize(400,140); +} + + +QSizePolicy EditSchedCode::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditSchedCode::okData() +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("update SCHED_CODES set DESCRIPTION=\"%s\" where CODE=\"%s\"",(const char *)schedCode_description_edit->text(),(const char *)schedCode_name_edit->text()); + + q=new RDSqlQuery(sql); + delete q; + + *schedCode_description=schedCode_description_edit->text(); + done(0); +} + + +void EditSchedCode::cancelData() +{ + done(-1); +} + diff --git a/rdadmin/edit_schedcodes.h b/rdadmin/edit_schedcodes.h new file mode 100644 index 00000000..7e0c930e --- /dev/null +++ b/rdadmin/edit_schedcodes.h @@ -0,0 +1,54 @@ +// edit_schedcodes.h +// +// Edit scheduler codes dialog +// +// Stefan Gabriel +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_SCHEDCODES_H +#define EDIT_SCHEDCODES_H + +#include +#include +#include +#include +#include +#include + +class EditSchedCode : public QDialog +{ + Q_OBJECT + public: + EditSchedCode(QString schedCode,QString description,QWidget *parent=0,const char *name=0); + ~EditSchedCode(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QString *schedCode_code; + QString *schedCode_description; + QLineEdit *schedCode_name_edit; + QLineEdit *schedCode_description_edit; + }; + + +#endif // EDIT_SCHEDCODES_H diff --git a/rdadmin/edit_settings.cpp b/rdadmin/edit_settings.cpp new file mode 100644 index 00000000..8e2665e4 --- /dev/null +++ b/rdadmin/edit_settings.cpp @@ -0,0 +1,403 @@ +// edit_station.cpp +// +// Edit Rivendell Systemwide Configuration +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_settings.cpp,v 1.4.8.1 2012/11/26 20:19:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +EditSettings::EditSettings(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + QFont normal_font=QFont("Helvetica",12,QFont::Normal); + normal_font.setPixelSize(12); + + y_pos=0; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + edit_system=new RDSystem(); + + setCaption(tr("System-Wide Settings")); + + edit_system=new RDSystem(); + + // + // System Sample Rate + // + edit_sample_rate_box=new QComboBox(this,"edit_sample_rate_box"); + edit_sample_rate_box->setGeometry(200,10,70,20); + edit_sample_rate_box->insertItem("32000"); + edit_sample_rate_box->insertItem("44100"); + edit_sample_rate_box->insertItem("48000"); + QLabel *label=new QLabel(edit_sample_rate_box, + tr("System Sample Rate:"),this, + "edit_sample_rate_label"); + label->setGeometry(10,10,185,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + label=new QLabel(tr("samples/second"),this,"edit_sample_rate_unit"); + label->setGeometry(275,10,sizeHint().width()-285,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Allow Duplicate Cart Titles Box + // + edit_duplicate_carts_box=new QCheckBox(this,"edit_duplicate_carts_box"); + edit_duplicate_carts_box->setGeometry(20,32,15,15); + label=new QLabel(edit_duplicate_carts_box, + tr("Allow Duplicate Cart Titles"),this, + "edit_duplicate_carts_box"); + label->setGeometry(40,30,sizeHint().width()-50,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // ISCI Cross Reference Path + // + edit_isci_path_edit=new QLineEdit(this,"edit_isci_path_box"); + edit_isci_path_edit->setGeometry(200,54,sizeHint().width()-210,20); + label=new QLabel(edit_isci_path_edit,tr("ISCI Cross Reference Path:"),this, + "edit_isci_path_label"); + label->setGeometry(10,54,185,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Maximum POST Size + // + edit_maxpost_spin=new QSpinBox(this,"edit_maxpost_spin"); + edit_maxpost_spin->setGeometry(200,76,60,20); + edit_maxpost_spin->setRange(1,1000); + label=new QLabel(edit_maxpost_spin, + tr("Maximum Remote Post Length:"),this, + "edit_maxpost_label"); + label->setGeometry(10,76,185,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + label=new QLabel(tr("Mbytes"),this,"edit_maxpost_unit"); + label->setGeometry(265,76,60,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Temporary Cart Group + // + edit_temp_cart_group_box=new QComboBox(this); + edit_temp_cart_group_box->setGeometry(200,97,100,20); + sql="select NAME from GROUPS order by NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + edit_temp_cart_group_box->insertItem(q->value(0).toString()); + } + delete q; + label=new QLabel(edit_temp_cart_group_box,tr("Temporary Cart Group:"),this); + label->setGeometry(10,97,185,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Duplicate List (initially hidden) + // + edit_duplicate_label=new RDLabel(this,"edit_duplicate_label"); + edit_duplicate_label->setText(tr("The following duplicate titles must be corrected before \"Allow Duplicate Values\" can be turned off.")); + edit_duplicate_label->setWordWrapEnabled(true); + edit_duplicate_label->setGeometry(15,120,sizeHint().width()-30,50); + edit_duplicate_label->setFont(normal_font); + edit_duplicate_label->hide(); + edit_duplicate_list=new QListView(this); + edit_duplicate_list->setGeometry(10,165,sizeHint().width()-20,200); + edit_duplicate_list->setItemMargin(5); + edit_duplicate_list->setAllColumnsShowFocus(true); + edit_duplicate_list->addColumn(tr("CART")); + edit_duplicate_list->setColumnAlignment(0,AlignCenter); + edit_duplicate_list->addColumn(tr("TITLE")); + edit_duplicate_list->setColumnAlignment(1,AlignLeft); + edit_duplicate_list->hide(); + edit_save_button=new QPushButton(this,"save_button"); + edit_save_button-> + setGeometry(sizeHint().width()-85,370,70,25); + edit_save_button->setFont(normal_font); + edit_save_button->setText(tr("&Save List")); + connect(edit_save_button,SIGNAL(clicked()),this,SLOT(saveData())); + edit_save_button->hide(); + + // + // Ok Button + // + edit_ok_button=new QPushButton(this,"ok_button"); + edit_ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60, + 80,50); + edit_ok_button->setFont(font); + edit_ok_button->setText(tr("&OK")); + connect(edit_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + edit_cancel_button=new QPushButton(this,"cancel_button"); + edit_cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + edit_cancel_button->setFont(font); + edit_cancel_button->setText(tr("&Cancel")); + connect(edit_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + edit_duplicate_carts_box->setChecked(edit_system->allowDuplicateCartTitles()); + edit_maxpost_spin->setValue(edit_system->maxPostLength()/1000000); + edit_isci_path_edit->setText(edit_system->isciXreferencePath()); + + for(int i=0;icount();i++) { + if(edit_sample_rate_box->text(i).toUInt()==edit_system->sampleRate()) { + edit_sample_rate_box->setCurrentItem(i); + } + } + for(int i=0;icount();i++) { + if(edit_temp_cart_group_box->text(i)==edit_system->tempCartGroup()) { + edit_temp_cart_group_box->setCurrentItem(i); + } + } +} + + +EditSettings::~EditSettings() +{ + delete edit_system; + delete edit_duplicate_carts_box; + delete edit_duplicate_label; + delete edit_duplicate_list; +} + + +QSize EditSettings::sizeHint() const +{ + return QSize(500,196+y_pos); +} + + +QSizePolicy EditSettings::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditSettings::saveData() +{ + QString filename=RDGetHomeDir(); + filename=QFileDialog::getSaveFileName(filename,"Text Files *.txt",this); + if(filename.isNull()) { + return; + } + if(filename.find(".")<0) { + filename+=".txt"; + } + if(QFile::exists(filename)) { + if(QMessageBox::question(this,tr("File Exists"), + tr("The file \"")+filename+ + tr("\" exists.\n\nOverwrite?"), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + return; + } + } + FILE *f=fopen(filename,"w"); + if(f==NULL) { + QMessageBox::warning(this,tr("File Error"), + tr("Unable to write file \""+filename+"\".")); + return; + } + QDateTime dt=QDateTime(QDate::currentDate(),QTime::currentTime()); + fprintf(f,"Rivendell Duplicate Cart Title List\n"); + fprintf(f,"Generated %s\n", + (const char *)dt.toString("hh:mm:ss - MM/dd/yyyy")); + fprintf(f,"\n"); + fprintf(f,"Cart Title\n"); + fprintf(f,"---- -----\n"); + QListViewItem *item=edit_duplicate_list->firstChild(); + while(item!=NULL) { + fprintf(f,"%s %s\n",(const char *)item->text(0), + (const char *)item->text(1)); + item=item->nextSibling(); + } + fclose(f); +} + + +void EditSettings::okData() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + std::map dups; + + if(edit_duplicate_carts_box->isChecked()!= + edit_system->allowDuplicateCartTitles()) { + QLabel *msg=new QLabel(this); + QProgressDialog *pd=new QProgressDialog(this); + pd->setLabel(msg); + pd->setCancelButton(NULL); + pd->setMinimumDuration(2); + if(!edit_duplicate_carts_box->isChecked()) { + // + // Check for dups + // + msg->setText(tr("Checking the Library for duplicates.")); + sql="select NUMBER,TITLE from CART order by NUMBER"; + q=new RDSqlQuery(sql); + int count=0; + int step=0; + int step_size=q->size()/10; + pd->setProgress(0,10); + while(q->next()) { + sql=QString().sprintf("select NUMBER from CART \ + where (TITLE=\"%s\")&&(NUMBER!=%u)", + (const char *)RDEscapeString(q->value(1).toString()), + q->value(0).toUInt()); + q1=new RDSqlQuery(sql); + while(q1->next()) { + dups[q1->value(0).toUInt()]=q->value(1).toString(); + } + delete q1; + count++; + if(count>=step_size) { + pd->setProgress(++step); + count=0; + qApp->processEvents(); + } + } + delete q; + pd->reset(); + if(dups.size()>0) { + QListViewItem *item; + y_pos=305; + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + edit_duplicate_carts_box->setChecked(true); + edit_duplicate_label->show(); + edit_duplicate_list->show(); + edit_save_button->show(); + edit_duplicate_list->clear(); + edit_ok_button->setGeometry(sizeHint().width()-180, + sizeHint().height()-60, + 80,50); + edit_cancel_button-> + setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + for(std::map::const_iterator ci=dups.begin(); + ci!=dups.end();ci++) { + item=new QListViewItem(edit_duplicate_list); + item->setText(0,QString().sprintf("%06u",ci->first)); + item->setText(1,ci->second); + } + return; + } + + // + // All ok -- make the change + // + sql="alter table CART drop index TITLE_IDX"; + q=new RDSqlQuery(sql); + delete q; + sql="alter table CART modify column TITLE char(255) unique"; + q=new RDSqlQuery(sql); + delete q; + edit_system->setAllowDuplicateCartTitles(false); + } + else { + sql="alter table CART drop index TITLE"; + q=new RDSqlQuery(sql); + delete q; + sql="alter table CART modify column TITLE char(255)"; + q=new RDSqlQuery(sql); + delete q; + sql="alter table CART add index TITLE_IDX(TITLE)"; + q=new RDSqlQuery(sql); + delete q; + edit_system->setAllowDuplicateCartTitles(true); + } + delete pd; + } + edit_system->setSampleRate(edit_sample_rate_box->currentText().toUInt()); + edit_system->setMaxPostLength(edit_maxpost_spin->value()*1000000); + edit_system->setIsciXreferencePath(edit_isci_path_edit->text()); + edit_system->setTempCartGroup(edit_temp_cart_group_box->currentText()); + done(0); +} + + +void EditSettings::cancelData() +{ + done(-1); +} + + +void EditSettings::BuildDuplicatesList(std::map *dups) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + sql="select NUMBER,TITLE from CART order by NUMBER"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("select NUMBER from CART \ + where (TITLE=\"%s\")&&(NUMBER!=%u)", + (const char *)RDEscapeString(q->value(1).toString()), + q->value(0).toUInt()); + q1=new RDSqlQuery(sql); + while(q1->next()) { + (*dups)[q1->value(0).toUInt()]=q->value(1).toString(); + } + delete q1; + } + delete q; +} diff --git a/rdadmin/edit_settings.h b/rdadmin/edit_settings.h new file mode 100644 index 00000000..43ab1020 --- /dev/null +++ b/rdadmin/edit_settings.h @@ -0,0 +1,72 @@ +// edit_settings.h +// +// Edit Rivendell System-wide Settings. +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: edit_settings.h,v 1.4.8.1 2012/11/26 20:19:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_SETTINGS_H +#define EDIT_SETTINGS_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +class EditSettings : public QDialog +{ + Q_OBJECT + public: + EditSettings(QWidget *parent=0,const char *name=0); + ~EditSettings(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void BuildDuplicatesList(std::map *dups); + void saveData(); + void okData(); + void cancelData(); + + private: + QComboBox *edit_sample_rate_box; + QCheckBox *edit_duplicate_carts_box; + QSpinBox *edit_maxpost_spin; + RDLabel *edit_duplicate_label; + QLineEdit *edit_isci_path_edit; + QComboBox *edit_temp_cart_group_box; + QListView *edit_duplicate_list; + QPushButton *edit_settings_button; + QPushButton *edit_save_button; + QPushButton *edit_ok_button; + QPushButton *edit_cancel_button; + RDSystem *edit_system; + int y_pos; +}; + + +#endif // EDIT_SETTINGS_H diff --git a/rdadmin/edit_station.cpp b/rdadmin/edit_station.cpp new file mode 100644 index 00000000..a6f32622 --- /dev/null +++ b/rdadmin/edit_station.cpp @@ -0,0 +1,992 @@ +// edit_station.cpp +// +// Edit a Rivendell Workstation Configuration +// +// (C) Copyright 2002-2010 Fred Gleason +// +// $Id: edit_station.cpp,v 1.57.4.12 2014/03/05 17:59:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +EditStation::EditStation(QString sname,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + RDSqlQuery *q; + QString sql; + int item=0; + char temp[256]; + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + station_station=new RDStation(sname); + station_cae_station=NULL; + + setCaption(tr("Host: ")+sname); + + GetPrivateProfileString(RD_CONF_FILE,"Identity","Password",temp,"",255); + station_catch_connect=new RDCatchConnect(0,this); + station_catch_connect->connectHost(station_station->address().toString(), + RDCATCHD_TCP_PORT,temp); + + // + // Validators + // + RDTextValidator *validator=new RDTextValidator(this); + QIntValidator *macro_validator=new QIntValidator(1,RD_MAX_CART_NUMBER,this); + + + // + // Station Name + // + station_name_edit=new QLineEdit(this); + station_name_edit->setGeometry(115,11,80,19); + station_name_edit->setReadOnly(true); + QLabel *station_name_label= + new QLabel(station_name_edit,tr("Ho&st Name:"),this); + station_name_label->setGeometry(10,11,100,19); + station_name_label->setFont(font); + station_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Station Description + // + station_description_edit=new QLineEdit(this); + station_description_edit->setGeometry(115,32,sizeHint().width()-125,19); + station_description_edit->setMaxLength(64); + station_description_edit->setValidator(validator); + QLabel *station_description_label=new QLabel(station_description_edit, + tr("&Description:"),this); + station_description_label->setGeometry(10,32,100,19); + station_description_label->setFont(font); + station_description_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Station Default Name + // + station_default_name_edit=new QComboBox(this); + station_default_name_edit->setGeometry(115,53,160,19); + station_default_name_edit->setEditable(false); + QLabel *station_default_name_label=new QLabel(station_default_name_edit, + tr("Default &User:"),this); + station_default_name_label->setGeometry(10,53,100,19); + station_default_name_label->setFont(font); + station_default_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Broadcast security model + // + station_broadcast_sec_edit=new QComboBox(this); + station_broadcast_sec_edit->setGeometry(115,74,140,19); + // Index values should match RDStation class enum and database schema. + station_broadcast_sec_edit->insertItem(tr("Host"),0); + station_broadcast_sec_edit->insertItem(tr("User"),1); + station_broadcast_sec_edit->setEditable(false); + QLabel *station_broadcast_sec_label=new QLabel(station_broadcast_sec_edit, + tr("Security Model:"),this); + station_broadcast_sec_label->setGeometry(10,74,100,19); + station_broadcast_sec_label->setFont(font); + station_broadcast_sec_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Station IP Address + // + station_address_edit=new QLineEdit(this); + station_address_edit->setGeometry(115,95,120,19); + station_address_edit->setMaxLength(15); + station_address_edit->setValidator(validator); + QLabel *station_address_label=new QLabel(station_address_edit, + tr("&IP Address:"),this); + station_address_label->setGeometry(10,95,100,19); + station_address_label->setFont(font); + station_address_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Station Editor Command + // + station_editor_cmd_edit=new QLineEdit(this); + station_editor_cmd_edit->setGeometry(115,116,sizeHint().width()-130,19); + station_editor_cmd_edit->setMaxLength(255); + QLabel *station_editor_cmd_label=new QLabel(station_editor_cmd_edit, + tr("Editor &Command:"),this); + station_editor_cmd_label->setGeometry(10,116,100,19); + station_editor_cmd_label->setFont(font); + station_editor_cmd_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Station Time Offset + // + station_timeoffset_box=new QSpinBox(this); + station_timeoffset_box->setGeometry(115,137,80,19); + station_timeoffset_box->setRange(-RD_MAX_TIME_OFFSET,RD_MAX_TIME_OFFSET); + station_timeoffset_box->setSuffix(tr(" mS")); + QLabel *station_timeoffset_label=new QLabel(station_timeoffset_box, + tr("&Time Offset:"),this); + station_timeoffset_label->setGeometry(10,137,100,19); + station_timeoffset_label->setFont(font); + station_timeoffset_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Startup Cart + // + station_startup_cart_edit=new QLineEdit(this); + station_startup_cart_edit->setGeometry(115,158,60,19); + station_startup_cart_edit->setMaxLength(15); + station_startup_cart_edit->setValidator(macro_validator); + QLabel *station_startup_cart_label=new QLabel(station_startup_cart_edit, + tr("&Startup Cart:"),this); + station_startup_cart_label->setGeometry(10,158,100,19); + station_startup_cart_label->setFont(font); + station_startup_cart_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + QPushButton *select_button=new QPushButton(tr("Select"),this); + select_button->setFont(small_font); + select_button->setGeometry(180,157,50,22); + connect(select_button,SIGNAL(clicked()),this,SLOT(selectClicked())); + + // + // Cue Output + // + station_cue_sel=new RDCardSelector(this); + station_cue_sel->setGeometry(90,179,110,117); + QLabel *station_cue_sel_label=new QLabel(station_cue_sel, + tr("Cue &Output:"),this); + station_cue_sel_label->setGeometry(10,179,100,19); + station_cue_sel_label->setFont(font); + station_cue_sel_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + station_start_cart_edit=new QLineEdit(this); + station_start_cart_edit->setGeometry(270,179,60,20); + station_start_cart_edit->setValidator(macro_validator); + QLabel *station_start_cart_label=new QLabel(station_start_cart_edit, + tr("Start Cart")+":",this); + station_start_cart_label->setGeometry(205,179,60,20); + station_start_cart_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + station_start_cart_button=new QPushButton(tr("Select"),this); + station_start_cart_button->setGeometry(335,178,50,22); + station_start_cart_button->setFont(small_font); + connect(station_start_cart_button,SIGNAL(clicked()), + this,SLOT(startCartClickedData())); + + station_stop_cart_edit=new QLineEdit(this); + station_stop_cart_edit->setGeometry(270,201,60,20); + station_stop_cart_edit->setValidator(macro_validator); + QLabel *station_stop_cart_label=new QLabel(station_stop_cart_edit, + tr("Stop Cart")+":",this); + station_stop_cart_label->setGeometry(205,201,60,20); + station_stop_cart_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + station_stop_cart_button=new QPushButton(tr("Select"),this); + station_stop_cart_button->setGeometry(335,200,50,22); + station_stop_cart_button->setFont(small_font); + connect(station_stop_cart_button,SIGNAL(clicked()), + this,SLOT(stopCartClickedData())); + caeStationActivatedData(station_station->caeStation()); + + // + // Heartbeat Checkbox + // + station_heartbeat_box=new QCheckBox(this); + station_heartbeat_box->setGeometry(10,226,15,15); + QLabel *label=new QLabel(station_heartbeat_box,tr("Enable Heartbeat"),this); + label->setGeometry(30,224,150,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + connect(station_heartbeat_box,SIGNAL(toggled(bool)), + this,SLOT(heartbeatToggledData(bool))); + + // + // Filter Checkbox + // + station_filter_box=new QCheckBox(this); + station_filter_box->setGeometry(210,226,15,15); + label=new QLabel(station_filter_box,tr("Use Realtime Filtering"),this); + label->setGeometry(230,226,150,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Heartbeat Cart + // + station_hbcart_edit=new QLineEdit(this); + station_hbcart_edit->setGeometry(65,248,60,19); + station_hbcart_edit->setValidator(macro_validator); + station_hbcart_label=new QLabel(station_hbcart_edit,tr("Cart:"),this); + station_hbcart_label->setGeometry(10,248,50,19); + station_hbcart_label->setFont(font); + station_hbcart_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + station_hbcart_button=new QPushButton(this); + station_hbcart_button->setGeometry(140,245,60,26); + station_hbcart_button->setFont(font); + station_hbcart_button->setText(tr("Select")); + connect(station_hbcart_button,SIGNAL(clicked()), + this,SLOT(heartbeatClickedData())); + + // + // Heartbeat Interval + // + station_hbinterval_spin=new QSpinBox(this); + station_hbinterval_spin->setGeometry(275,248,45,19); + station_hbinterval_spin->setRange(1,300); + station_hbinterval_label= + new QLabel(station_hbinterval_spin,tr("Interval:"),this); + station_hbinterval_label->setGeometry(220,248,50,19); + station_hbinterval_label->setFont(font); + station_hbinterval_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + station_hbinterval_unit=new QLabel(tr("secs"),this); + station_hbinterval_unit->setGeometry(325,248,100,19); + station_hbinterval_unit->setFont(font); + station_hbinterval_unit->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // System Maintenance Checkbox + // + station_maint_box=new QCheckBox(this); + station_maint_box->setGeometry(10,275,15,15); + label= + new QLabel(station_maint_box,tr("Include in System Maintenance Pool"),this); + label->setGeometry(30,273,sizeHint().width()-40,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Enable Drag & Drop Checkbox + // + station_dragdrop_box=new QCheckBox(this); + station_dragdrop_box->setGeometry(10,296,15,15); + label=new QLabel(station_dragdrop_box,tr("Enable Drag && Drop"),this); + label->setGeometry(30,293,sizeHint().width()-40,20); + label->setFont(font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Enforce Panel Setup Checkbox + // + station_panel_enforce_box=new QCheckBox(this); + station_panel_enforce_box->setGeometry(25,314,15,15); + station_panel_enforce_label= + new QLabel(station_panel_enforce_box, + tr("Allow Drops on Panels not in Setup Mode"),this); + station_panel_enforce_label->setGeometry(45,312,sizeHint().width()-55,20); + station_panel_enforce_label->setFont(font); + station_panel_enforce_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + connect(station_dragdrop_box,SIGNAL(toggled(bool)), + station_panel_enforce_label,SLOT(setEnabled(bool))); + connect(station_dragdrop_box,SIGNAL(toggled(bool)), + station_panel_enforce_box,SLOT(setEnabled(bool))); + + // + // System Services Section + // + label=new QLabel(tr("System Services"),this); + label->setGeometry(30,333,110,20); + label->setFont(font); + label->setAlignment(AlignCenter|ShowPrefix); + + // + // HTTP Service Host + // + station_http_station_box=new QComboBox(this); + station_http_station_box->setGeometry(145,354,200,19); + station_http_station_box->setEditable(false); + QLabel *station_http_station_label= + new QLabel(station_http_station_box,tr("HTTP Xport:"),this); + station_http_station_label->setGeometry(11,354,130,19); + station_http_station_label->setFont(font); + station_http_station_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // CAE Service Host + // + station_cae_station_box=new QComboBox(this); + station_cae_station_box->setGeometry(145,375,200,19); + station_cae_station_box->setEditable(false); + connect(station_cae_station_box,SIGNAL(activated(const QString &)), + this,SLOT(caeStationActivatedData(const QString &))); + QLabel *station_cae_station_label=new QLabel(station_cae_station_box, + tr("Core Audio Engine:"),this); + station_cae_station_label->setGeometry(11,375,130,19); + station_cae_station_label->setFont(font); + station_cae_station_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // RDLibrary Configuration Button + // + QPushButton *button=new QPushButton(this); + button->setGeometry(20,413,80,50); + button->setFont(font); + button->setText(tr("RD&Library")); + connect(button,SIGNAL(clicked()),this,SLOT(editLibraryData())); + + // + // RDCatch Configuration Button + // + button=new QPushButton(this); + button->setGeometry(110,413,80,50); + button->setFont(font); + button->setText(tr("RDCatch")); + connect(button,SIGNAL(clicked()),this,SLOT(editDeckData())); + + // + // RDAirPlay Configuration Button + // + button=new QPushButton(this); + button->setGeometry(200,413,80,50); + button->setFont(font); + button->setText(tr("RDAirPlay")); + connect(button,SIGNAL(clicked()),this,SLOT(editAirPlayData())); + + // + // RDPanel Configuration Button + // + button=new QPushButton(this); + button->setGeometry(290,413,80,50); + button->setFont(font); + button->setText(tr("RDPanel")); + connect(button,SIGNAL(clicked()),this,SLOT(editPanelData())); + + // + // RDLogEdit Configuration Button + // + button=new QPushButton(this); + button->setGeometry(20,473,80,50); + button->setFont(font); + button->setText(tr("RDLogEdit")); + connect(button,SIGNAL(clicked()),this,SLOT(editLogEditData())); + + // + // RDCartSlots Configuration Button + // + button=new QPushButton(this); + button->setGeometry(110,473,80,50); + button->setFont(font); + button->setText(tr("RDCart\nSlots")); + connect(button,SIGNAL(clicked()),this,SLOT(editCartSlotsData())); + + // + // Dropboxes Configuration Button + // + button=new QPushButton(this); + button->setGeometry(200,473,80,50); + button->setFont(font); + button->setText(tr("Dropboxes")); + connect(button,SIGNAL(clicked()),this,SLOT(editDropboxesData())); + + // + // Switcher Configuration Button + // + button=new QPushButton(this); + button->setGeometry(290,473,80,50); + button->setFont(font); + button->setText(tr("Switchers\nGPIO")); + connect(button,SIGNAL(clicked()),this,SLOT(editSwitcherData())); + + // + // Host Variables Configuration Button + // + button=new QPushButton(this); + button->setGeometry(20,533,80,50); + button->setFont(font); + button->setText(tr("Host\nVariables")); + connect(button,SIGNAL(clicked()),this,SLOT(editHostvarsData())); + + // + // Audio Ports Configuration Button + // + button=new QPushButton(this); + button->setGeometry(110,533,80,50); + button->setFont(font); + button->setText(tr("Audio\nPorts")); + connect(button,SIGNAL(clicked()),this,SLOT(editAudioData())); + + // + // TTY Configuration Button + // + button=new QPushButton(this); + button->setGeometry(200,533,80,50); + button->setFont(font); + button->setText(tr("Serial\nPorts")); + connect(button,SIGNAL(clicked()),this,SLOT(editTtyData())); + + // + // View Adapters (Audio Resources) Configuration Button + // + button=new QPushButton(this); + button->setGeometry(290,533,80,50); + button->setFont(font); + button->setText(tr("Audio\nResources")); + connect(button,SIGNAL(clicked()),this,SLOT(viewAdaptersData())); + + // + // JACK Settings Button + // + button=new QPushButton(this); + button->setGeometry(110,593,80,50); + button->setFont(font); + button->setText(tr("JACK\nSettings")); + connect(button,SIGNAL(clicked()),this,SLOT(jackSettingsData())); + + // + // Backups Configuration Button + // + button=new QPushButton(this); + button->setGeometry(200,593,80,50); + button->setFont(font); + button->setText(tr("Backups")); + connect(button,SIGNAL(clicked()),this,SLOT(editBackupsData())); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + station_name_edit->setText(station_station->name()); + station_description_edit->setText(station_station->description()); + station_address_edit->setText(station_station->address().toString()); + station_editor_cmd_edit->setText(station_station->editorPath()); + station_timeoffset_box->setValue(station_station->timeOffset()); + unsigned cartnum=station_station->startupCart(); + if(cartnum>0) { + station_startup_cart_edit->setText(QString().sprintf("%06u",cartnum)); + } + + RDStation *cue_station=station_station; + if(station_station->caeStation()!="localhost") { + cue_station=new RDStation(station_station->caeStation()); + } + if(cue_station->scanned()) { + station_cue_sel->setMaxCards(cue_station->cards()); + for(int i=0;imaxCards();i++) { + station_cue_sel->setMaxPorts(i,cue_station->cardOutputs(i)); + } + } + else { + QMessageBox::information(this,tr("RDAdmin - No Audio Configuration Data"), + tr("Channel assignments will not be available for this host as audio resource data\nhas not yet been generated. Please start the Rivendell daemons on the host\nconfigured to run the CAE service in order to populate the audio resources database.")); + station_cue_sel->setDisabled(true); + station_cue_sel->setDisabled(true); + } + if(cue_station!=station_station) { + delete cue_station; + } + station_cue_sel->setCard(station_station->cueCard()); + station_cue_sel->setPort(station_station->cuePort()); + if(station_station->cueStartCart()>0) { + station_start_cart_edit-> + setText(QString().sprintf("%06u",station_station->cueStartCart())); + } + if(station_station->cueStopCart()>0) { + station_stop_cart_edit-> + setText(QString().sprintf("%06u",station_station->cueStopCart())); + } + + sql="select LOGIN_NAME from USERS"; + q=new RDSqlQuery(sql); + while(q->next()) { + station_default_name_edit->insertItem(q->value(0).toString()); + if(q->value(0).toString()==station_station->defaultName()) { + station_default_name_edit->setCurrentItem(item); + } + item++; + } + delete q; + station_broadcast_sec_edit-> + setCurrentItem((RDStation::BroadcastSecurityMode)station_station-> + broadcastSecurity()); + if((cartnum=station_station->heartbeatCart())>0) { + station_heartbeat_box->setChecked(true); + station_hbcart_edit->setText(QString().sprintf("%u",cartnum)); + station_hbinterval_spin-> + setValue(station_station->heartbeatInterval()/1000); + heartbeatToggledData(true); + } + else { + station_heartbeat_box->setChecked(false); + heartbeatToggledData(false); + } + switch(station_station->filterMode()) { + case RDStation::FilterSynchronous: + station_filter_box->setChecked(true); + break; + + case RDStation::FilterAsynchronous: + station_filter_box->setChecked(false); + break; + } + station_maint_box->setChecked(station_station->systemMaint()); + station_dragdrop_box->setChecked(station_station->enableDragdrop()); + station_panel_enforce_box->setChecked(!station_station->enforcePanelSetup()); + if(!station_station->enableDragdrop()) { + station_panel_enforce_label->setDisabled(true); + station_panel_enforce_box->setDisabled(true); + } + + station_http_station_box->insertItem("localhost"); + //station_http_station_box->insertItem(RD_RDSELECT_LABEL); + station_cae_station_box->insertItem("localhost"); + //station_cae_station_box->insertItem(RD_RDSELECT_LABEL); + sql=QString().sprintf("select NAME from STATIONS \ + where NAME!=\"%s\" order by NAME", + (const char *)RDEscapeString(sname)); + q=new RDSqlQuery(sql); + while(q->next()) { + station_http_station_box->insertItem(q->value(0).toString()); + if(q->value(0).toString()==station_station->httpStation()) { + station_http_station_box-> + setCurrentItem(station_http_station_box->count()-1); + } + station_cae_station_box->insertItem(q->value(0).toString()); + if(q->value(0).toString()==station_station->caeStation()) { + station_cae_station_box-> + setCurrentItem(station_cae_station_box->count()-1); + } + } + delete q; + for(int i=0;icount();i++) { + if(station_http_station_box->text(i)==station_station->httpStation()) { + station_http_station_box->setCurrentItem(i); + } + if(station_cae_station_box->text(i)==station_station->caeStation()) { + station_cae_station_box->setCurrentItem(i); + } + } +} + + +EditStation::~EditStation() +{ + delete station_station; + delete station_cae_station; +} + + +QSize EditStation::sizeHint() const +{ + return QSize(395,723); + return QSize(375,723); +} + + +void EditStation::selectClicked() +{ + int cartnum=station_startup_cart_edit->text().toInt(); + + if(admin_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + station_startup_cart_edit->setText(QString().sprintf("%06d",cartnum)); + } +} + + +void EditStation::heartbeatToggledData(bool state) +{ + station_hbcart_label->setEnabled(state); + station_hbcart_edit->setEnabled(state); + station_hbcart_button->setEnabled(state); + station_hbinterval_label->setEnabled(state); + station_hbinterval_spin->setEnabled(state); + station_hbinterval_unit->setEnabled(state); +} + + +void EditStation::heartbeatClickedData() +{ + int cartnum=station_hbcart_edit->text().toInt(); + + if(admin_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + station_hbcart_edit->setText(QString().sprintf("%06d",cartnum)); + } +} + + +void EditStation::caeStationActivatedData(const QString &station_name) +{ + if(station_cae_station!=NULL) { + delete station_cae_station; + } + if(station_name=="localhost") { + station_cae_station=new RDStation(station_station->name()); + } + else { + station_cae_station=new RDStation(station_name); + } + if(station_cae_station->scanned()) { + station_cue_sel->setMaxCards(station_cae_station->cards()); + for(int i=0;imaxCards();i++) { + station_cue_sel->setMaxPorts(i,station_cae_station->cardOutputs(i)); + } + } + else { + QMessageBox::information(this,tr("RDAdmin - No Audio Configuration Data"), + tr("Channel assignments will not be available for this host as audio resource data\nhas not yet been generated. Please start the Rivendell daemons on the host\nconfigured to run the CAE service in order to populate the audio resources database.")); + station_cue_sel->setDisabled(true); + station_cue_sel->setDisabled(true); + } + +} + + +QSizePolicy EditStation::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditStation::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(black); + p->setBrush(black); + + // + // System Services + // + p->moveTo(10,343); + p->lineTo(sizeHint().width()-10,343); + p->lineTo(sizeHint().width()-10,401); + p->lineTo(10,401); + p->lineTo(10,343); + + delete p; +} + + +void EditStation::okData() +{ + QHostAddress addr; + unsigned cartnum=0; + bool ok=false; + QString sql; + RDSqlQuery *q; + + if(!station_maint_box->isChecked()) { + sql=QString().sprintf("select NAME from STATIONS where \ + (NAME!=\"%s\")&&(SYSTEM_MAINT=\"Y\")", + (const char *)RDEscapeString(station_station->name())); + q=new RDSqlQuery(sql); + if(!q->first()) { + QMessageBox::warning(this,tr("System Maintenance"), + tr("At least one host must belong to the system maintenance pool!")); + delete q; + return; + } + delete q; + } + if(!addr.setAddress(station_address_edit->text())) { + QMessageBox::warning(this,tr("Invalid Address"), + tr("The specified IP address is invalid!")); + return; + } + if(station_heartbeat_box->isChecked()) { + cartnum=station_hbcart_edit->text().toUInt(); + if((cartnum==0)||(cartnum>999999)) { + QMessageBox::warning(this,tr("Invalid Cart"), + tr("The Heartbeat Cart number is invalid!")); + return; + } + station_station->setHeartbeatCart(station_hbcart_edit->text().toUInt()); + station_station-> + setHeartbeatInterval(station_hbinterval_spin->value()*1000); + } + else { + station_station->setHeartbeatCart(0); + station_station->setHeartbeatInterval(0); + } + station_station->setCueCard(station_cue_sel->card()); + station_station->setCuePort(station_cue_sel->port()); + station_station->setCueStartCart(station_start_cart_edit->text().toInt()); + station_station->setCueStopCart(station_stop_cart_edit->text().toInt()); + station_station->setDescription(station_description_edit->text()); + station_station->setDefaultName(station_default_name_edit->currentText()); + station_station-> + setBroadcastSecurity((RDStation::BroadcastSecurityMode) + station_broadcast_sec_edit->currentItem()); + station_station->setAddress(addr); + station_station-> + setEditorPath(station_editor_cmd_edit->text()); + station_station->setTimeOffset(station_timeoffset_box->value()); + cartnum=station_startup_cart_edit->text().toUInt(&ok); + if(ok&&(cartnum<=999999)) { + station_station->setStartupCart(cartnum); + } + else { + station_station->setStartupCart(0); + } + if(station_filter_box->isChecked()) { + station_station->setFilterMode(RDStation::FilterSynchronous); + } + else { + station_station->setFilterMode(RDStation::FilterAsynchronous); + } + station_station->setSystemMaint(station_maint_box->isChecked()); + station_station->setEnableDragdrop(station_dragdrop_box->isChecked()); + station_station-> + setEnforcePanelSetup(!station_panel_enforce_box->isChecked()); + station_station->setHttpStation(station_http_station_box->currentText()); + station_station->setCaeStation(station_cae_station_box->currentText()); + station_catch_connect->reloadHeartbeat(); + station_catch_connect->reloadOffset(); + + // + // Allow the event loop to run so the packets get delivered + // + QTimer *timer=new QTimer(this,"ok_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(okTimerData())); + timer->start(1,true); +} + + +void EditStation::okTimerData() +{ + done(0); +} + + +void EditStation::cancelData() +{ + done(-1); +} + + +void EditStation::editLibraryData() +{ + EditRDLibrary *edit_conf= + new EditRDLibrary(station_station,station_cae_station); + edit_conf->exec(); + delete edit_conf; +} + + +void EditStation::editDeckData() +{ + EditDecks *edit_conf=new EditDecks(station_station,station_cae_station,this); + if(edit_conf->exec()==0) { + station_catch_connect->reload(); + } + delete edit_conf; +} + + +void EditStation::editAirPlayData() +{ + EditRDAirPlay *edit_conf= + new EditRDAirPlay(station_station,station_cae_station); + edit_conf->exec(); + delete edit_conf; +} + + +void EditStation::editPanelData() +{ + EditRDPanel *edit_conf= + new EditRDPanel(station_station,station_cae_station,this); + edit_conf->exec(); + delete edit_conf; +} + + +void EditStation::editLogEditData() +{ + EditRDLogedit *edit_conf= + new EditRDLogedit(station_station,station_cae_station); + edit_conf->exec(); + delete edit_conf; +} + + +void EditStation::editCartSlotsData() +{ + EditCartSlots *edit_conf= + new EditCartSlots(station_station,station_cae_station,this); + edit_conf->exec(); + delete edit_conf; +} + + +void EditStation::viewAdaptersData() +{ + ViewAdapters *view=new ViewAdapters(station_station,this,"view"); + view->exec(); + delete view; +} + + +void EditStation::editAudioData() +{ + EditAudioPorts *edit_conf=new EditAudioPorts(station_station->name(),0); + edit_conf->exec(); + delete edit_conf; +} + + +void EditStation::editTtyData() +{ + EditTtys *edit_conf=new EditTtys(station_station->name(),0); + edit_conf->exec(); + delete edit_conf; +} + + +void EditStation::editSwitcherData() +{ + ListMatrices *list_conf=new ListMatrices(station_station->name(),this); + list_conf->exec(); + delete list_conf; +} + + +void EditStation::editHostvarsData() +{ + ListHostvars *list_conf=new ListHostvars(station_station->name(),this); + list_conf->exec(); + delete list_conf; +} + +void EditStation::editBackupsData() +{ + EditBackup *edit_backup=new EditBackup(station_station,this); + edit_backup->exec(); + delete edit_backup; +} + + +void EditStation::editDropboxesData() +{ + ListDropboxes *list_conf=new ListDropboxes(station_station->name(),this); + list_conf->exec(); + station_catch_connect->reloadDropboxes(); + delete list_conf; +} + + +void EditStation::jackSettingsData() +{ + EditJack *d=new EditJack(station_station,this); + d->exec(); + delete d; +} + + +void EditStation::startCartClickedData() +{ + int cartnum=station_start_cart_edit->text().toUInt(); + + if(admin_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + station_start_cart_edit->setText(QString().sprintf("%06d",cartnum)); + } +} + + +void EditStation::stopCartClickedData() +{ + int cartnum=station_stop_cart_edit->text().toUInt(); + + if(admin_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + admin_user->name(),admin_user->password())==0) { + station_stop_cart_edit->setText(QString().sprintf("%06d",cartnum)); + } +} + + +QString EditStation::DisplayPart(QString string) +{ + for(unsigned i=0;i +// +// $Id: edit_station.h,v 1.36.4.4 2014/02/11 23:46:27 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_STATION_H +#define EDIT_STATION_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +class EditStation : public QDialog +{ + Q_OBJECT + public: + EditStation(QString station,QWidget *parent=0,const char *name=0); + ~EditStation(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + void paintEvent(QPaintEvent *e); + + private slots: + void selectClicked(); + void heartbeatToggledData(bool state); + void heartbeatClickedData(); + void caeStationActivatedData(const QString &station_name); + void okData(); + void okTimerData(); + void cancelData(); + void editLibraryData(); + void editDeckData(); + void editAirPlayData(); + void editPanelData(); + void editLogEditData(); + void editCartSlotsData(); + void viewAdaptersData(); + void editAudioData(); + void editTtyData(); + void editSwitcherData(); + void editHostvarsData(); + void editBackupsData(); + void editDropboxesData(); + void jackSettingsData(); + void startCartClickedData(); + void stopCartClickedData(); + + private: + QString DisplayPart(QString); + QString HostPart(QString); + RDStation *station_station; + RDStation *station_cae_station; + RDCatchConnect *station_catch_connect; + QLineEdit *station_name_edit; + QLineEdit *station_description_edit; + QComboBox *station_default_name_edit; + QComboBox *station_broadcast_sec_edit; + QLineEdit *station_address_edit; + QLineEdit *station_editor_cmd_edit; + QSpinBox *station_timeoffset_box; + QLineEdit *station_startup_cart_edit; + RDCardSelector *station_cue_sel; + QLineEdit *station_start_cart_edit; + QPushButton *station_start_cart_button; + QLineEdit *station_stop_cart_edit; + QPushButton *station_stop_cart_button; + QCheckBox *station_heartbeat_box; + QCheckBox *station_filter_box; + QLabel *station_hbcart_label; + QLineEdit *station_hbcart_edit; + QPushButton *station_hbcart_button; + QLabel *station_hbinterval_label; + QSpinBox *station_hbinterval_spin; + QLabel *station_hbinterval_unit; + QString station_cart_filter; + QString station_cart_group; + QCheckBox *station_maint_box; + QCheckBox *station_dragdrop_box; + QLabel *station_panel_enforce_label; + QCheckBox *station_panel_enforce_box; + QComboBox *station_http_station_box; + QComboBox *station_cae_station_box; +}; + + +#endif + diff --git a/rdadmin/edit_svc.cpp b/rdadmin/edit_svc.cpp new file mode 100644 index 00000000..bd3de5ed --- /dev/null +++ b/rdadmin/edit_svc.cpp @@ -0,0 +1,785 @@ +// edit_svc.cpp +// +// Edit a Rivendell Service +// +// (C) Copyright 2002-2004,2008 Fred Gleason +// +// $Id: edit_svc.cpp,v 1.43.8.2.2.1 2014/05/21 20:29:02 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +EditSvc::EditSvc(QString svc,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + QString group; + QString autospot; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + svc_svc=new RDSvc(svc); + + setCaption(tr("Edit Service")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont section_font=QFont("Helvetica",14,QFont::Bold); + section_font.setPixelSize(14); + + // + // Text Validators + // + RDTextValidator *validator=new RDTextValidator(this); + RDIdValidator *log_validator=new RDIdValidator(this); + log_validator->addBannedChar(' '); + + // + // General Section + // + QLabel *label=new QLabel("General",this,"traffic_import_label"); + label->setGeometry(10,10,120,24); + label->setFont(section_font); + label->setAlignment(AlignLeft); + + // + // Service Name + // + svc_name_edit=new QLineEdit(this); + svc_name_edit->setGeometry(185,31,80,19); + svc_name_edit->setMaxLength(10); + svc_name_edit->setReadOnly(true); + label=new QLabel(svc_name_edit,tr("&Service Name:"),this); + label->setGeometry(10,33,170,19); + label->setAlignment(AlignRight|ShowPrefix); + + // + // Service Description + // + svc_description_edit=new QLineEdit(this); + svc_description_edit->setGeometry(185,52,240,19); + svc_description_edit->setMaxLength(255); + svc_description_edit->setValidator(validator); + label=new QLabel(svc_description_edit,tr("Service &Description:"),this); + label->setGeometry(10,54,170,19); + label->setAlignment(AlignRight|ShowPrefix); + + // + // Service Program Code + // + svc_program_code_edit=new QLineEdit(this); + svc_program_code_edit->setGeometry(185,73,240,19); + svc_program_code_edit->setMaxLength(255); + svc_program_code_edit->setValidator(validator); + label=new QLabel(svc_program_code_edit,tr("&Program Code:"),this); + label->setGeometry(10,73,170,19); + label->setAlignment(AlignRight|ShowPrefix); + + // + // Log Name Template + // + svc_name_template_edit=new QLineEdit(this); + svc_name_template_edit->setGeometry(185,94,240,19); + svc_name_template_edit->setMaxLength(255); + svc_name_template_edit->setValidator(log_validator); + label=new QLabel(svc_name_template_edit, + tr("Log Name &Template:"),this); + label->setGeometry(10,94,170,19); + label->setAlignment(AlignRight|ShowPrefix); + + // + // Log Description Template + // + svc_description_template_edit=new QLineEdit(this); + svc_description_template_edit->setGeometry(185,115,240,19); + svc_description_template_edit->setMaxLength(255); + label=new QLabel(svc_description_template_edit, + tr("Log &Description Template:"),this); + label->setGeometry(10,115,170,19); + label->setAlignment(AlignRight|ShowPrefix); + + // + // Voicetracking Group + // + svc_voice_group_box=new QComboBox(this); + svc_voice_group_box->setGeometry(185,136,240,19); + svc_voice_group_box->insertItem(tr("[none]")); + label=new QLabel(svc_voice_group_box,tr("Voicetrack Group:"),this); + label->setGeometry(10,136,170,19); + label->setAlignment(AlignRight|ShowPrefix); + + // + // Autospot Group + // + svc_autospot_group_box=new QComboBox(this); + svc_autospot_group_box->setGeometry(185,157,240,19); + svc_autospot_group_box->insertItem(tr("[none]")); + label=new QLabel(svc_autospot_group_box,tr("AutoSpot Group:"),this); + label->setGeometry(10,157,170,19); + label->setAlignment(AlignRight|ShowPrefix); + + // + // Chain Log + // + svc_chain_box=new QCheckBox(this); + svc_chain_box->setGeometry(30,180,15,15); + label=new QLabel(svc_chain_box,tr("Insert CHAIN TO at log end"),this); + label->setGeometry(50,180,170,19); + label->setAlignment(AlignLeft|ShowPrefix); + + // + // Default Auto Refresh + // + svc_autorefresh_box=new QCheckBox(this); + svc_autorefresh_box->setGeometry(230,180,15,15); + label= + new QLabel(svc_autorefresh_box,tr("Enable AutoRefresh By Default"),this); + label->setGeometry(250,180,200,19); + label->setAlignment(AlignLeft|ShowPrefix); + + // + // Autofill Button + // + QPushButton *button=new QPushButton(this,"autofill_button"); + button->setGeometry(455,31,150,50); + button->setFont(font); + button->setText(tr("Configure \n&Autofill Carts")); + connect(button,SIGNAL(clicked()),this,SLOT(autofillData())); + + // + // Purge Expired Logs + // + svc_loglife_box=new QCheckBox(this,"svc_loglife_box"); + svc_loglife_box->setGeometry(460,95,15,15); + label=new QLabel(svc_loglife_box,tr("Purge Logs after"), + this,"svc_loglife_label"); + label->setGeometry(480,95,200,19); + label->setAlignment(AlignLeft|ShowPrefix); + svc_loglife_spin=new QSpinBox(this,"svc_loglife_spin"); + svc_loglife_spin->setGeometry(585,93,50,19); + svc_loglife_spin->setRange(0,365); + connect(svc_loglife_box,SIGNAL(toggled(bool)), + svc_loglife_spin,SLOT(setEnabled(bool))); + label=new QLabel(svc_loglife_box,tr("days"), + this,"svc_loglife_unit"); + label->setGeometry(645,95,40,19); + label->setAlignment(AlignLeft|ShowPrefix); + + // + // Purge Expired ELR Data + // + svc_shelflife_box=new QCheckBox(this,"svc_shelflife_box"); + svc_shelflife_box->setGeometry(460,117,15,15); + label=new QLabel(svc_shelflife_box,tr("Purge ELR Data after"), + this,"svc_shelflife_label"); + label->setGeometry(480,117,200,19); + label->setAlignment(AlignLeft|ShowPrefix); + svc_shelflife_spin=new QSpinBox(this,"svc_shelflife_spin"); + svc_shelflife_spin->setGeometry(610,115,50,19); + svc_shelflife_spin->setRange(0,365); + connect(svc_shelflife_box,SIGNAL(toggled(bool)), + svc_shelflife_spin,SLOT(setEnabled(bool))); + label=new QLabel(svc_shelflife_box,tr("days"), + this,"svc_shelflife_unit"); + label->setGeometry(670,117,40,19); + label->setAlignment(AlignLeft|ShowPrefix); + + // + // Enable Hosts Button + // + button=new QPushButton(this,"hosts_button"); + button->setGeometry(625,31,150,50); + button->setFont(font); + button->setText(tr("Enable &Hosts")); + connect(button,SIGNAL(clicked()),this,SLOT(enableHostsData())); + + + + // + // Traffic Import Section + // + label=new QLabel(tr("Traffic Data Import"),this,"traffic_import_label"); + label->setGeometry(10,213,160,24); + label->setFont(section_font); + label->setAlignment(AlignLeft); + + // + // Linux Traffic Import Path + // + svc_tfc_path_edit=new QLineEdit(this,"svc_tfc_path_edit"); + svc_tfc_path_edit->setGeometry(185,234,240,19); + svc_tfc_path_edit->setMaxLength(255); + svc_tfc_path_edit->setValidator(validator); + label=new QLabel(svc_tfc_path_edit, + tr("Linux Import Path:"),this, + "svc_tfc_path_label"); + label->setGeometry(10,234,170,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_tfc_path_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Linux Traffic Preimport Command + // + svc_tfc_preimport_cmd_edit=new QLineEdit(this,"svc_tfc_preimport_cmd_edit"); + svc_tfc_preimport_cmd_edit->setGeometry(185,255,240,19); + svc_tfc_preimport_cmd_edit->setValidator(validator); + label=new QLabel(svc_tfc_preimport_cmd_edit, + tr("Linux Preimport Command:"),this, + "svc_tfc_preimport_label"); + label->setGeometry(10,255,170,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_tfc_preimport_cmd_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Windows Traffic Import Path + // + svc_tfc_win_path_edit=new QLineEdit(this,"svc_tfc_win_path_edit"); + svc_tfc_win_path_edit->setGeometry(185,276,240,19); + svc_tfc_win_path_edit->setMaxLength(255); + label=new QLabel(svc_tfc_win_path_edit, + tr("Windows Import Path:"),this, + "svc_tfc_win_path_label"); + label->setGeometry(10,276,170,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_tfc_win_path_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Linux Traffic Preimport Command + // + svc_tfc_win_preimport_cmd_edit= + new QLineEdit(this,"svc_tfc_win_preimport_cmd_edit"); + svc_tfc_win_preimport_cmd_edit->setGeometry(185,297,240,19); + label=new QLabel(svc_tfc_win_preimport_cmd_edit, + tr("Windows Preimport Command:"),this, + "svc_tfc_win_preimport_label"); + label->setGeometry(10,297,170,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_tfc_win_preimport_cmd_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Note Cart + // + svc_tfc_label_cart_edit=new QLineEdit(this,"svc_tfc_label_cart_edit"); + svc_tfc_label_cart_edit->setGeometry(185,318,240,19); + svc_tfc_label_cart_edit->setMaxLength(32); + label=new QLabel(svc_tfc_label_cart_edit, + tr("Note Cart String:"),this, + "svc_tfc_label_cart_label"); + label->setGeometry(10,318,170,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_tfc_label_cart_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Track String + // + svc_tfc_track_edit=new QLineEdit(this,"svc_tfc_track_edit"); + svc_tfc_track_edit->setGeometry(185,339,240,19); + svc_tfc_track_edit->setMaxLength(32); + label=new QLabel(svc_tfc_track_edit, + tr("Insert Voice Track String:"),this, + "svc_tfc_track_cart_track"); + label->setGeometry(10,339,170,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_tfc_track_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Traffic Import Template + // + svc_tfc_import_template_box=new QComboBox(this,"svc_tfc_import_template_box"); + svc_tfc_import_template_box->setGeometry(185,360,240,19); + label=new QLabel(svc_tfc_import_template_box, + tr("Import Template:"),this, + "svc_tfc_import_template_label"); + label->setGeometry(10,360,170,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_tfc_import_template_box,SIGNAL(activated(int)), + this,SLOT(tfcTemplateActivatedData(int))); + + // + // Traffic Parser Settings + // + svc_tfc_fields=new ImportFields(this); + svc_tfc_fields->setGeometry(10,381,svc_tfc_fields->sizeHint().width(), + svc_tfc_fields->sizeHint().height()); + + // + // Traffic Test Button + // + button=new QPushButton(this,"tfc_button"); + button->setGeometry(360,381,60,40); + button->setFont(font); + button->setText(tr("Test \n&Traffic")); + connect(button,SIGNAL(clicked()),this,SLOT(trafficData())); + + // + // Music Import Section + // + label=new QLabel(tr("Music Data Import"),this,"music_import_label"); + label->setGeometry(445,213,160,24); + label->setFont(section_font); + label->setAlignment(AlignLeft); + + // + // Linux Music Import Path + // + svc_mus_path_edit=new QLineEdit(this,"svc_mus_path_edit"); + svc_mus_path_edit->setGeometry(620,234,240,19); + svc_mus_path_edit->setMaxLength(255); + svc_mus_path_edit->setValidator(validator); + label=new QLabel(svc_mus_path_edit, + tr("Linux Import Path:"),this, + "svc_mus_path_label"); + label->setGeometry(450,234,165,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_mus_path_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Linux Music Preimport Command + // + svc_mus_preimport_cmd_edit=new QLineEdit(this,"svc_mus_preimport_cmd_edit"); + svc_mus_preimport_cmd_edit->setGeometry(620,255,240,19); + svc_mus_preimport_cmd_edit->setValidator(validator); + label=new QLabel(svc_mus_preimport_cmd_edit, + tr("Linux Preimport Command:"),this, + "svc_mus_preimport_label"); + label->setGeometry(450,255,170,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_mus_preimport_cmd_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Windows Music Import Path + // + svc_mus_win_path_edit=new QLineEdit(this,"svc_mus_win_path_edit"); + svc_mus_win_path_edit->setGeometry(620,276,240,19); + svc_mus_win_path_edit->setMaxLength(255); + label=new QLabel(svc_mus_win_path_edit, + tr("Windows Import Path:"),this, + "svc_mus_win_path_label"); + label->setGeometry(450,276,165,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_mus_win_path_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Windows Music Preimport Command + // + svc_mus_win_preimport_cmd_edit= + new QLineEdit(this,"svc_mus_win_preimport_cmd_edit"); + svc_mus_win_preimport_cmd_edit->setGeometry(620,297,240,19); + label=new QLabel(svc_mus_win_preimport_cmd_edit, + tr("Windows Preimport Command:"),this, + "svc_mus_win_preimport_label"); + label->setGeometry(450,297,170,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_mus_win_preimport_cmd_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Label Cart + // + svc_mus_label_cart_edit=new QLineEdit(this,"svc_mus_label_cart_edit"); + svc_mus_label_cart_edit->setGeometry(620,318,240,19); + svc_mus_label_cart_edit->setMaxLength(32); + label=new QLabel(svc_mus_label_cart_edit, + tr("Note Cart String:"),this, + "svc_mus_label_cart_label"); + label->setGeometry(450,318,170,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_mus_label_cart_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Insert Voice Track String + // + svc_mus_track_edit=new QLineEdit(this,"svc_mus_track_edit"); + svc_mus_track_edit->setGeometry(620,339,240,19); + svc_mus_track_edit->setMaxLength(255); + label=new QLabel(svc_mus_track_edit, + tr("Insert Voice Track String:"),this, + "svc_mus_track_label"); + label->setGeometry(450,339,165,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_mus_track_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Insert Spot Break String + // + svc_mus_break_edit=new QLineEdit(this,"svc_mus_break_edit"); + svc_mus_break_edit->setGeometry(620,360,240,19); + svc_mus_break_edit->setMaxLength(255); + label=new QLabel(svc_mus_break_edit, + tr("Insert Traffic Break String:"),this, + "svc_mus_break_label"); + label->setGeometry(450,360,165,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_mus_break_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(textChangedData(const QString &))); + + // + // Music Import Template + // + svc_mus_import_template_box=new QComboBox(this,"svc_mus_import_template_box"); + svc_mus_import_template_box->setGeometry(620,381,240,19); + label=new QLabel(svc_mus_import_template_box, + tr("Import Template:"),this, + "svc_mus_import_template_label"); + label->setGeometry(450,381,170,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(svc_mus_import_template_box,SIGNAL(activated(int)), + this,SLOT(musTemplateActivatedData(int))); + + // + // Music Parser Settings + // + svc_mus_fields=new ImportFields(this); + svc_mus_fields->setGeometry(445,402,svc_mus_fields->sizeHint().width(), + svc_mus_fields->sizeHint().height()); + + // + // Music Test Button + // + button=new QPushButton(this,"mus_button"); + button->setGeometry(795,402,60,40); + button->setFont(font); + button->setText(tr("Test \n&Music")); + connect(button,SIGNAL(clicked()),this,SLOT(musicData())); + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Group Lists + // + group=svc_svc->trackGroup(); + autospot=svc_svc->autospotGroup(); + sql="select NAME from GROUPS order by NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + svc_voice_group_box->insertItem(q->value(0).toString()); + if(q->value(0).toString()==group) { + svc_voice_group_box->setCurrentItem(svc_voice_group_box->count()-1); + } + svc_autospot_group_box->insertItem(q->value(0).toString()); + if(q->value(0).toString()==autospot) { + svc_autospot_group_box->setCurrentItem(svc_autospot_group_box->count()-1); + } + } + delete q; + + // + // Populate Fields + // + svc_name_edit->setText(svc_svc->name()); + svc_description_edit->setText(svc_svc->description()); + svc_program_code_edit->setText(svc_svc->programCode()); + svc_name_template_edit->setText(svc_svc->nameTemplate()); + svc_description_template_edit->setText(svc_svc->descriptionTemplate()); + svc_chain_box->setChecked(svc_svc->chainto()); + svc_autorefresh_box->setChecked(svc_svc->autoRefresh()); + if(svc_svc->defaultLogShelflife()>=0) { + svc_loglife_box->setChecked(true); + svc_loglife_spin->setValue(svc_svc->defaultLogShelflife()); + } + else { + svc_loglife_spin->setDisabled(true); + } + if(svc_svc->elrShelflife()>=0) { + svc_shelflife_box->setChecked(true); + svc_shelflife_spin->setValue(svc_svc->elrShelflife()); + } + else { + svc_shelflife_spin->setDisabled(true); + } + svc_tfc_path_edit->setText(svc_svc->importPath(RDSvc::Traffic,RDSvc::Linux)); + svc_tfc_preimport_cmd_edit-> + setText(svc_svc->preimportCommand(RDSvc::Traffic,RDSvc::Linux)); + svc_tfc_win_path_edit-> + setText(svc_svc->importPath(RDSvc::Traffic,RDSvc::Windows)); + svc_tfc_win_preimport_cmd_edit-> + setText(svc_svc->preimportCommand(RDSvc::Traffic,RDSvc::Windows)); + + svc_tfc_import_template_box->insertItem(tr("[custom]")); + svc_mus_import_template_box->insertItem(tr("[custom]")); + sql="select NAME from IMPORT_TEMPLATES order by NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + svc_tfc_import_template_box->insertItem(q->value(0).toString()); + if(q->value(0).toString()==svc_svc->importTemplate(RDSvc::Traffic)) { + svc_tfc_import_template_box-> + setCurrentItem(svc_tfc_import_template_box->count()-1); + } + svc_mus_import_template_box->insertItem(q->value(0).toString()); + if(q->value(0).toString()==svc_svc->importTemplate(RDSvc::Music)) { + svc_mus_import_template_box-> + setCurrentItem(svc_mus_import_template_box->count()-1); + } + } + delete q; + svc_tfc_label_cart_edit->setText(svc_svc->labelCart(RDSvc::Traffic)); + svc_tfc_track_edit->setText(svc_svc->trackString(RDSvc::Traffic)); + svc_mus_path_edit->setText(svc_svc->importPath(RDSvc::Music,RDSvc::Linux)); + svc_mus_preimport_cmd_edit-> + setText(svc_svc->preimportCommand(RDSvc::Music,RDSvc::Linux)); + svc_mus_win_path_edit-> + setText(svc_svc->importPath(RDSvc::Music,RDSvc::Windows)); + svc_mus_win_preimport_cmd_edit-> + setText(svc_svc->preimportCommand(RDSvc::Music,RDSvc::Windows)); + svc_mus_label_cart_edit->setText(svc_svc->labelCart(RDSvc::Music)); + svc_mus_break_edit-> + setText(svc_svc->breakString()); + svc_mus_track_edit-> + setText(svc_svc->trackString(RDSvc::Music)); + svc_tfc_fields->setFields(svc_svc,RDSvc::Traffic); + tfcTemplateActivatedData(svc_tfc_import_template_box->currentItem()); + musTemplateActivatedData(svc_mus_import_template_box->currentItem()); + svc_mus_fields->setFields(svc_svc,RDSvc::Music); + import_changed=false; +} + + +EditSvc::~EditSvc() +{ + delete svc_name_edit; + delete svc_description_edit; +} + + +QSize EditSvc::sizeHint() const +{ + return QSize(870,712); +} + + +QSizePolicy EditSvc::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditSvc::autofillData() +{ + AutofillCarts *autofill=new AutofillCarts(svc_svc,this,"autofill"); + autofill->exec(); + delete autofill; +} + + +void EditSvc::enableHostsData() +{ + EditSvcPerms *edit_perms=new EditSvcPerms(svc_svc,this,"edit_perms"); + edit_perms->exec(); + delete edit_perms; +} + + +void EditSvc::trafficData() +{ + TestDataImport(RDSvc::Traffic); +} + + +void EditSvc::musicData() +{ + TestDataImport(RDSvc::Music); +} + + +void EditSvc::textChangedData(const QString &) +{ + import_changed=true; +} + + +void EditSvc::tfcTemplateActivatedData(int index) +{ + svc_tfc_fields->setEnabled(index==0); + import_changed=true; +} + + +void EditSvc::musTemplateActivatedData(int index) +{ + svc_mus_fields->setEnabled(index==0); + import_changed=true; +} + + +void EditSvc::okData() +{ + Save(); + done(0); +} + + +void EditSvc::cancelData() +{ + done(-1); +} + + +void EditSvc::TestDataImport(RDSvc::ImportSource src) +{ + if(import_changed|| + ((src==RDSvc::Traffic)&&(svc_tfc_fields->changed()))|| + ((src==RDSvc::Music)&&(svc_mus_fields->changed()))) { + switch(QMessageBox::question(this,tr("Save Import Data"), + tr("Before testing, the import configuration\nmust be saved. Save now?"),QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + return; + + default: + break; + } + Save(); + } + TestImport *testimport=new TestImport(svc_svc,src,this,"testimport"); + testimport->exec(); + delete testimport; +} + + +void EditSvc::Save() +{ + svc_svc->setDescription(svc_description_edit->text()); + svc_svc->setProgramCode(svc_program_code_edit->text()); + svc_svc->setNameTemplate(svc_name_template_edit->text().stripWhiteSpace()); + svc_svc->setDescriptionTemplate(svc_description_template_edit->text()); + svc_svc->setChainto(svc_chain_box->isChecked()); + svc_svc->setAutoRefresh(svc_autorefresh_box->isChecked()); + if(svc_loglife_box->isChecked()) { + svc_svc->setDefaultLogShelflife(svc_loglife_spin->value()); + } + else { + svc_svc->setDefaultLogShelflife(-1); + } + if(svc_shelflife_box->isChecked()) { + svc_svc->setElrShelflife(svc_shelflife_spin->value()); + } + else { + svc_svc->setElrShelflife(-1); + } + svc_svc-> + setImportPath(RDSvc::Traffic,RDSvc::Linux,svc_tfc_path_edit->text()); + svc_svc-> + setPreimportCommand(RDSvc::Traffic,RDSvc::Linux, + svc_tfc_preimport_cmd_edit->text()); + svc_svc-> + setImportPath(RDSvc::Traffic,RDSvc::Windows,svc_tfc_win_path_edit->text()); + svc_svc-> + setPreimportCommand(RDSvc::Traffic,RDSvc::Windows, + svc_tfc_win_preimport_cmd_edit->text()); + if(svc_tfc_import_template_box->currentItem()==0) { + svc_svc->setImportTemplate(RDSvc::Traffic,""); + } + else { + svc_svc->setImportTemplate(RDSvc::Traffic, + svc_tfc_import_template_box->currentText()); + } + svc_svc->setLabelCart(RDSvc::Traffic,svc_tfc_label_cart_edit->text()); + svc_svc->setTrackString(RDSvc::Traffic,svc_tfc_track_edit->text()); + svc_tfc_fields->readFields(svc_svc,RDSvc::Traffic); + svc_svc->setImportPath(RDSvc::Music,RDSvc::Linux,svc_mus_path_edit->text()); + svc_svc->setPreimportCommand(RDSvc::Music,RDSvc::Linux, + svc_mus_preimport_cmd_edit->text()); + svc_svc-> + setImportPath(RDSvc::Music,RDSvc::Windows,svc_mus_win_path_edit->text()); + svc_svc-> + setPreimportCommand(RDSvc::Music,RDSvc::Windows, + svc_mus_win_preimport_cmd_edit->text()); + if(svc_mus_import_template_box->currentItem()==0) { + svc_svc->setImportTemplate(RDSvc::Music,""); + } + else { + svc_svc->setImportTemplate(RDSvc::Music, + svc_mus_import_template_box->currentText()); + } + svc_svc->setBreakString(svc_mus_break_edit->text()); + svc_svc->setTrackString(RDSvc::Music,svc_mus_track_edit->text()); + svc_svc->setLabelCart(RDSvc::Music,svc_mus_label_cart_edit->text()); + svc_mus_fields->readFields(svc_svc,RDSvc::Music); + import_changed=false; + if(svc_voice_group_box->currentItem()==0) { + svc_svc->setTrackGroup(""); + } + else { + svc_svc->setTrackGroup(svc_voice_group_box->currentText()); + } + if(svc_autospot_group_box->currentItem()==0) { + svc_svc->setAutospotGroup(""); + } + else { + svc_svc->setAutospotGroup(svc_autospot_group_box->currentText()); + } +} diff --git a/rdadmin/edit_svc.h b/rdadmin/edit_svc.h new file mode 100644 index 00000000..9d974732 --- /dev/null +++ b/rdadmin/edit_svc.h @@ -0,0 +1,95 @@ +// edit_svc.h +// +// Edit a Rivendell Service +// +// (C) Copyright 2002-2010 Fred Gleason +// +// $Id: edit_svc.h,v 1.24.8.2 2014/01/10 15:40:15 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_SVC_H +#define EDIT_SVC_H + +#include +#include +#include +#include +#include +#include + +#include +#include + +class EditSvc : public QDialog +{ + Q_OBJECT + public: + EditSvc(QString svc,QWidget *parent=0,const char *name=0); + ~EditSvc(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void autofillData(); + void enableHostsData(); + void trafficData(); + void musicData(); + void textChangedData(const QString &); + void tfcTemplateActivatedData(int index); + void musTemplateActivatedData(int index); + void okData(); + void cancelData(); + + private: + void TestDataImport(RDSvc::ImportSource src); + void Save(); + RDSvc *svc_svc; + QLineEdit *svc_name_edit; + QLineEdit *svc_description_edit; + QLineEdit *svc_program_code_edit; + QLineEdit *svc_name_template_edit; + QLineEdit *svc_description_template_edit; + QComboBox *svc_voice_group_box; + QComboBox *svc_autospot_group_box; + QLineEdit *svc_tfc_path_edit; + QLineEdit *svc_tfc_preimport_cmd_edit; + QLineEdit *svc_tfc_win_path_edit; + QLineEdit *svc_tfc_win_preimport_cmd_edit; + QComboBox *svc_tfc_import_template_box; + QLineEdit *svc_tfc_label_cart_edit; + QLineEdit *svc_tfc_track_edit; + ImportFields *svc_tfc_fields; + ImportFields *svc_mus_fields; + QLineEdit *svc_mus_path_edit; + QLineEdit *svc_mus_preimport_cmd_edit; + QLineEdit *svc_mus_win_path_edit; + QLineEdit *svc_mus_win_preimport_cmd_edit; + QComboBox *svc_mus_import_template_box; + QLineEdit *svc_mus_label_cart_edit; + QLineEdit *svc_mus_break_edit; + QLineEdit *svc_mus_track_edit; + QCheckBox *svc_chain_box; + QCheckBox *svc_autorefresh_box; + QCheckBox *svc_loglife_box; + QSpinBox *svc_loglife_spin; + QCheckBox *svc_shelflife_box; + QSpinBox *svc_shelflife_spin; + bool import_changed; +}; + + +#endif + diff --git a/rdadmin/edit_svc_perms.cpp b/rdadmin/edit_svc_perms.cpp new file mode 100644 index 00000000..6dc75326 --- /dev/null +++ b/rdadmin/edit_svc_perms.cpp @@ -0,0 +1,176 @@ +// edit_svc_perms.cpp +// +// Edit Rivendell Service Permissions +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_svc_perms.cpp,v 1.9 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +EditSvcPerms::EditSvcPerms(RDSvc *svc,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + + svc_svc=svc; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Service: ")+svc_svc->name()); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Services Selector + // + svc_host_sel=new RDListSelector(this,"svc_host_sel"); + svc_host_sel->sourceSetLabel(tr("Available Hosts")); + svc_host_sel->destSetLabel(tr("Enabled Hosts")); + svc_host_sel->setGeometry(10,10,380,130); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + sql=QString().sprintf("select STATION_NAME from SERVICE_PERMS \ + where SERVICE_NAME=\"%s\"", + (const char *)svc_svc->name()); + q=new RDSqlQuery(sql); + while(q->next()) { + svc_host_sel->destInsertItem(q->value(0).toString()); + } + delete q; + + sql=QString().sprintf("select NAME from STATIONS"); + q=new RDSqlQuery(sql); + while(q->next()) { + if(svc_host_sel->destFindItem(q->value(0).toString())==0) { + svc_host_sel->sourceInsertItem(q->value(0).toString()); + } + } + delete q; +} + + +EditSvcPerms::~EditSvcPerms() +{ +} + + +QSize EditSvcPerms::sizeHint() const +{ + return QSize(400,212); +} + + +QSizePolicy EditSvcPerms::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditSvcPerms::okData() +{ + RDSqlQuery *q; + QString sql; + + // + // Add New Hosts + // + for(unsigned i=0;idestCount();i++) { + sql=QString().sprintf("select STATION_NAME from SERVICE_PERMS \ + where SERVICE_NAME=\"%s\" && STATION_NAME=\"%s\"", + (const char *)svc_svc->name(), + (const char *)svc_host_sel->destText(i)); + q=new RDSqlQuery(sql); + if(q->size()==0) { + delete q; + sql=QString(). + sprintf("insert into SERVICE_PERMS (SERVICE_NAME,STATION_NAME) \ + values (\"%s\",\"%s\")", + (const char *)svc_svc->name(), + (const char *)svc_host_sel->destText(i)); + q=new RDSqlQuery(sql); + } + delete q; + } + + // + // Delete Old Hosts + // + sql=QString().sprintf("delete from SERVICE_PERMS where SERVICE_NAME=\"%s\"", + (const char *)svc_svc->name()); + for(unsigned i=0;idestCount();i++) { + sql+=QString().sprintf(" && STATION_NAME<>\"%s\"", + (const char *)svc_host_sel->destText(i)); + } + q=new RDSqlQuery(sql); + delete q; + done(0); +} + + +void EditSvcPerms::cancelData() +{ + done(1); +} diff --git a/rdadmin/edit_svc_perms.h b/rdadmin/edit_svc_perms.h new file mode 100644 index 00000000..450fe864 --- /dev/null +++ b/rdadmin/edit_svc_perms.h @@ -0,0 +1,54 @@ +// edit_svc_perms.h +// +// Edit Rivendell Service Permissions +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_svc_perms.h,v 1.6 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_SVC_PERMS_H +#define EDIT_SVC_PERMS_H + +#include +#include + +#include + +#include + + +class EditSvcPerms : public QDialog +{ + Q_OBJECT + public: + EditSvcPerms(RDSvc *svc,QWidget *parent=0,const char *name=0); + ~EditSvcPerms(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + RDListSelector *svc_host_sel; + RDSvc *svc_svc; +}; + + +#endif + diff --git a/rdadmin/edit_ttys.cpp b/rdadmin/edit_ttys.cpp new file mode 100644 index 00000000..40540fa7 --- /dev/null +++ b/rdadmin/edit_ttys.cpp @@ -0,0 +1,419 @@ +// edit_ttys.cpp +// +// Edit a Rivendell TTY Configuration +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_ttys.cpp,v 1.16 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +EditTtys::EditTtys(QString station,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString str; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + edit_station=station; + for(int i=0;isetGeometry(75,10,100,24); + edit_port_box->setInsertionPolicy(QComboBox::NoInsertion); + connect(edit_port_box,SIGNAL(activated(int)),this,SLOT(idSelectedData())); + QLabel *label=new QLabel(edit_port_box,tr("Port ID:"), + this,"edit_port_label"); + label->setGeometry(10,14,60,22); + label->setFont(font); + label->setAlignment(AlignRight); + + // + // Enable Button + // + edit_enable_button=new QCheckBox(this,"edit_enable_button"); + edit_enable_button->setGeometry(265,14,15,15); + connect(edit_enable_button,SIGNAL(stateChanged(int)), + this,SLOT(enableButtonData(int))); + label=new QLabel(edit_enable_button,tr("Enabled"),this,"edit_enable_button"); + label->setGeometry(200,14,60,22); + label->setFont(font); + label->setAlignment(AlignRight); + + // + // The TTY Port + // + edit_port_edit=new QLineEdit(this,"edit_port_edit"); + edit_port_edit->setGeometry(145,54,100,20); + edit_port_edit->setValidator(validator); + edit_port_label=new QLabel(edit_port_edit,tr("TTY Device:"),this, + "edit_port_edit"); + edit_port_label->setGeometry(20,56,120,22); + edit_port_label->setFont(font); + edit_port_label->setAlignment(AlignRight); + + // + // Baudrate Selector + // + edit_baudrate_box=new QComboBox(this,"edit_baudrate_box"); + edit_baudrate_box->setGeometry(145,80,90,24); + edit_baudrate_box->setInsertionPolicy(QComboBox::NoInsertion); + edit_baudrate_label=new QLabel(edit_baudrate_box,tr("Baud Rate:"),this, + "edit_baudrate_label"); + edit_baudrate_label->setGeometry(20,84,120,22); + edit_baudrate_label->setFont(font); + edit_baudrate_label->setAlignment(AlignRight); + + // + // Parity Selector + // + edit_parity_box=new QComboBox(this,"edit_parity_box"); + edit_parity_box->setGeometry(145,108,90,24); + edit_parity_box->setInsertionPolicy(QComboBox::NoInsertion); + edit_parity_label=new QLabel(edit_parity_box,tr("Parity:"),this, + "edit_parity_label"); + edit_parity_label->setGeometry(20,110,120,22); + edit_parity_label->setFont(font); + edit_parity_label->setAlignment(AlignRight); + + // + // Data Bits Selector + // + edit_databits_box=new QComboBox(this,"edit_databits_box"); + edit_databits_box->setGeometry(145,136,60,24); + edit_databits_box->setInsertionPolicy(QComboBox::NoInsertion); + edit_databits_label=new QLabel(edit_databits_box,tr("Data Bits:"),this, + "edit_databits_label"); + edit_databits_label->setGeometry(20,138,120,22); + edit_databits_label->setFont(font); + edit_databits_label->setAlignment(AlignRight); + + // + // Stop Bits Selector + // + edit_stopbits_box=new QComboBox(this,"edit_stopbits_box"); + edit_stopbits_box->setGeometry(145,164,60,24); + edit_stopbits_box->setInsertionPolicy(QComboBox::NoInsertion); + edit_stopbits_label=new QLabel(edit_stopbits_box,tr("Stop Bits:"),this, + "edit_stopbits_label"); + edit_stopbits_label->setGeometry(20,166,120,22); + edit_stopbits_label->setFont(font); + edit_stopbits_label->setAlignment(AlignRight); + + // + // Termination Character Selector + // + edit_termination_box=new QComboBox(this,"edit_termination_box"); + edit_termination_box->setGeometry(145,192,90,24); + edit_termination_box->setInsertionPolicy(QComboBox::NoInsertion); + edit_termination_label=new QLabel(edit_termination_box,tr("Terminator:"), + this,"edit_termination_label"); + edit_termination_label->setGeometry(20,194,120,22); + edit_termination_label->setFont(font); + edit_termination_label->setAlignment(AlignRight); + + // + // Close Button + // + QPushButton *close_button=new QPushButton(this,"close_button"); + close_button->setGeometry(210,230,80,50); + close_button->setFont(font); + close_button->setText(tr("&Close")); + connect(close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Populate Data + // + str=QString(tr("Serial")); + for(int i=0;iinsertItem(QString().sprintf("%s%d",(const char *)str,i)); + } + edit_baudrate_box->insertItem("50"); + edit_baudrate_box->insertItem("75"); + edit_baudrate_box->insertItem("110"); + edit_baudrate_box->insertItem("134"); + edit_baudrate_box->insertItem("150"); + edit_baudrate_box->insertItem("200"); + edit_baudrate_box->insertItem("300"); + edit_baudrate_box->insertItem("600"); + edit_baudrate_box->insertItem("1200"); + edit_baudrate_box->insertItem("1800"); + edit_baudrate_box->insertItem("2400"); + edit_baudrate_box->insertItem("4800"); + edit_baudrate_box->insertItem("9600"); + edit_baudrate_box->insertItem("19200"); + edit_baudrate_box->insertItem("38400"); + edit_baudrate_box->insertItem("57600"); + edit_baudrate_box->insertItem("115200"); + edit_baudrate_box->insertItem("230400"); + + edit_parity_box->insertItem(tr("None")); + edit_parity_box->insertItem(tr("Even")); + edit_parity_box->insertItem(tr("Odd")); + + edit_databits_box->insertItem("5"); + edit_databits_box->insertItem("6"); + edit_databits_box->insertItem("7"); + edit_databits_box->insertItem("8"); + + edit_stopbits_box->insertItem("1"); + edit_stopbits_box->insertItem("2"); + + edit_termination_box->insertItem(tr("None")); + edit_termination_box->insertItem(tr("CR")); + edit_termination_box->insertItem(tr("LF")); + edit_termination_box->insertItem(tr("CR/LF")); + + edit_id=edit_port_box->currentItem(); + edit_tty=NULL; + ReadRecord(edit_id); +} + + +EditTtys::~EditTtys() +{ + delete edit_port_label; + delete edit_port_edit; + delete edit_baudrate_label; + delete edit_baudrate_box; + delete edit_databits_label; + delete edit_databits_box; + delete edit_stopbits_label; + delete edit_stopbits_box; + delete edit_parity_label; + delete edit_parity_box; + delete edit_termination_label; + delete edit_termination_box; + delete edit_tty; +} + + +QSize EditTtys::sizeHint() const +{ + return QSize(300,290); +} + + +QSizePolicy EditTtys::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditTtys::idSelectedData() +{ + WriteRecord(edit_id); + edit_id=edit_port_box->currentItem(); + ReadRecord(edit_id); +} + + +void EditTtys::enableButtonData(int state) +{ + if(state==0) { // Off + SetEnable(false); + } + + if(state==2) { // On + SetEnable(true); + } +} + + +void EditTtys::closeData() +{ + QString sql; + RDSqlQuery *q; + + WriteRecord(edit_id); + + RDStation *rmt_station=new RDStation(edit_station); + QHostAddress addr=rmt_station->address(); + RDMacro macro; + + macro.setCommand(RDMacro::SY); + macro.setRole(RDMacro::Cmd); + macro.setEchoRequested(false); + macro.setArgQuantity(1); + for(int i=0;ifirst()) { + macro.setCommand(RDMacro::SZ); + macro.setArg(0,q->value(0).toInt()); + } + else { + macro.setCommand(RDMacro::SY); + macro.setArg(0,i); + } + macro.setAddress(rmt_station->address()); + rdripc->sendRml(¯o); + delete q; + } + } + delete rmt_station; + + done(0); +} + + +void EditTtys::ReadRecord(int id) +{ + if(edit_tty!=NULL) { + delete edit_tty; + } + edit_tty=new RDTty(edit_station,id,true); + edit_port_edit->setText(edit_tty->port()); + switch(edit_tty->baudRate()) { + case 50: + edit_baudrate_box->setCurrentItem(0); + break; + case 75: + edit_baudrate_box->setCurrentItem(1); + break; + case 110: + edit_baudrate_box->setCurrentItem(2); + break; + case 134: + edit_baudrate_box->setCurrentItem(3); + break; + case 150: + edit_baudrate_box->setCurrentItem(4); + break; + case 200: + edit_baudrate_box->setCurrentItem(5); + break; + case 300: + edit_baudrate_box->setCurrentItem(6); + break; + case 600: + edit_baudrate_box->setCurrentItem(7); + break; + case 1200: + edit_baudrate_box->setCurrentItem(8); + break; + case 1800: + edit_baudrate_box->setCurrentItem(9); + break; + case 2400: + edit_baudrate_box->setCurrentItem(10); + break; + case 4800: + edit_baudrate_box->setCurrentItem(11); + break; + case 9600: + edit_baudrate_box->setCurrentItem(12); + break; + case 19200: + edit_baudrate_box->setCurrentItem(13); + break; + case 38400: + edit_baudrate_box->setCurrentItem(14); + break; + case 57600: + edit_baudrate_box->setCurrentItem(15); + break; + case 115200: + edit_baudrate_box->setCurrentItem(16); + break; + case 230400: + edit_baudrate_box->setCurrentItem(17); + break; + default: + edit_baudrate_box->setCurrentItem(12); + break; + } + edit_parity_box->setCurrentItem(edit_tty->parity()); + edit_databits_box->setCurrentItem(edit_tty->dataBits()-5); + edit_stopbits_box->setCurrentItem(edit_tty->stopBits()-1); + edit_termination_box->setCurrentItem(edit_tty->termination()); + edit_enable_button->setChecked(edit_tty->active()); + SetEnable(edit_tty->active()); +} + + +void EditTtys::WriteRecord(int id) +{ + int baud; + + edit_tty->setActive(edit_enable_button->isChecked()); + edit_tty->setPort(edit_port_edit->text()); + sscanf((const char *)edit_baudrate_box->currentText(),"%d",&baud); + edit_tty->setBaudRate(baud); + edit_tty->setParity((RDTTYDevice::Parity)edit_parity_box->currentItem()); + edit_tty->setDataBits(edit_databits_box->currentItem()+5); + edit_tty->setStopBits(edit_stopbits_box->currentItem()+1); + edit_tty-> + setTermination((RDTty::Termination)edit_termination_box->currentItem()); + edit_port_modified[id]=true; +} + + +void EditTtys::SetEnable(bool state) +{ + edit_port_label->setEnabled(state); + edit_port_edit->setEnabled(state); + edit_baudrate_label->setEnabled(state); + edit_baudrate_box->setEnabled(state); + edit_databits_label->setEnabled(state); + edit_databits_box->setEnabled(state); + edit_stopbits_label->setEnabled(state); + edit_stopbits_box->setEnabled(state); + edit_parity_label->setEnabled(state); + edit_parity_box->setEnabled(state); + edit_termination_label->setEnabled(state); + edit_termination_box->setEnabled(state); +} diff --git a/rdadmin/edit_ttys.h b/rdadmin/edit_ttys.h new file mode 100644 index 00000000..dd0e8984 --- /dev/null +++ b/rdadmin/edit_ttys.h @@ -0,0 +1,78 @@ +// edit_ttys.h +// +// Edit a Rivendell TTY Configuration +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: edit_ttys.h,v 1.7 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_TTYS_H +#define EDIT_TTYS_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +class EditTtys : public QDialog +{ + Q_OBJECT + public: + EditTtys(QString station,QWidget *parent=0,const char *name=0); + ~EditTtys(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void idSelectedData(); + void enableButtonData(int); + void closeData(); + + private: + void ReadRecord(int id); + void WriteRecord(int id); + void SetEnable(bool state); + RDTty *edit_tty; + int edit_id; + bool edit_port_modified[MAX_TTYS]; + QString edit_station; + QComboBox *edit_port_box; + QCheckBox *edit_enable_button; + QLabel *edit_port_label; + QLineEdit *edit_port_edit; + QLabel *edit_baudrate_label; + QComboBox *edit_baudrate_box; + QLabel *edit_databits_label; + QComboBox *edit_databits_box; + QLabel *edit_stopbits_label; + QComboBox *edit_stopbits_box; + QLabel *edit_parity_label; + QComboBox *edit_parity_box; + QLabel *edit_termination_label; + QComboBox *edit_termination_box; +}; + + +#endif + diff --git a/rdadmin/edit_user.cpp b/rdadmin/edit_user.cpp new file mode 100644 index 00000000..ceec9938 --- /dev/null +++ b/rdadmin/edit_user.cpp @@ -0,0 +1,616 @@ +// edit_user.cpp +// +// Edit a Rivendell User +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: edit_user.cpp,v 1.32 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + + +EditUser::EditUser(const QString &user,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("User: ")+user); + user_user=new RDUser(user); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // User Name + // + user_name_edit=new QLineEdit(this,"user_name_edit"); + user_name_edit->setGeometry(100,11,sizeHint().width()-110,19); + user_name_edit->setMaxLength(255); + user_name_edit->setValidator(validator); + QLabel *user_name_label=new QLabel(user_name_edit,tr("&User Name:"),this, + "user_name_label"); + user_name_label->setGeometry(5,11,90,19); + user_name_label->setFont(font); + user_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Full Name + // + user_full_name_edit=new QLineEdit(this,"user_full_name_edit"); + user_full_name_edit->setGeometry(100,32,sizeHint().width()-110,19); + user_full_name_edit->setMaxLength(255); + user_full_name_edit->setValidator(validator); + QLabel *user_full_name_label= + new QLabel(user_full_name_edit,tr("&Full Name:"),this, + "user_full_name_label"); + user_full_name_label->setGeometry(10,32,85,19); + user_full_name_label->setFont(font); + user_full_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // User Description + // + user_description_edit=new QLineEdit(this,"user_description_edit"); + user_description_edit->setGeometry(100,53,sizeHint().width()-110,19); + user_description_edit->setMaxLength(255); + user_description_edit->setValidator(validator); + QLabel *user_description_label= + new QLabel(user_description_edit,tr("&Description:"),this, + "user_description_label"); + user_description_label->setGeometry(5,53,90,19); + user_description_label->setFont(font); + user_description_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // User Phone + // + user_phone_edit=new QLineEdit(this,"user_phone_edit"); + user_phone_edit->setGeometry(100,75,120,19); + user_phone_edit->setMaxLength(20); + user_phone_edit->setValidator(validator); + QLabel *user_phone_label= + new QLabel(user_phone_edit,tr("&Phone:"),this,"user_phone_label"); + user_phone_label->setGeometry(10,75,85,19); + user_phone_label->setFont(font); + user_phone_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Enable Web Login + // + user_web_box=new QCheckBox(this,"user_web_box"); + user_web_box->setGeometry(20,96,15,15); + user_web_label= + new QLabel(user_web_box,tr("Allow Web Logins"),this,"user_web_label"); + user_web_label->setGeometry(40,96,180,19); + user_web_label->setFont(font); + user_web_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Change Password Button + // + QPushButton *password_button=new QPushButton(this,"password_button"); + password_button->setGeometry(230,75,80,50); + password_button->setFont(font); + password_button->setText(tr("Change\n&Password")); + connect(password_button,SIGNAL(clicked()),this,SLOT(passwordData())); + + // + // Administrative Group Priviledges + // + user_admin_group=new QButtonGroup(tr("Administrative Rights"),this, + "user_admin_group"); + user_admin_group->setGeometry(10,125,355,45); + user_admin_group->setFont(font); + + user_admin_config_button=new QCheckBox(user_admin_group, + "user_admin_config_button"); + user_admin_config_button->setGeometry(10,21,15,15); + connect(user_admin_config_button,SIGNAL(toggled(bool)), + this,SLOT(adminToggledData(bool))); + QLabel *user_admin_config_label=new QLabel(user_admin_config_button, + tr("Administer S&ystem"), + user_admin_group, + "user_admin_config_label"); + user_admin_config_label->setGeometry(192,21,150,19); + user_admin_config_label->setGeometry(30,21,150,19); + user_admin_config_label->setFont(small_font); + user_admin_config_label->setAlignment(AlignLeft|ShowPrefix); + + // + // Production Group Priviledges + // + user_prod_group=new QButtonGroup(tr("Production Rights"),this, + "user_prod_group"); + user_prod_group->setGeometry(10,180,355,85); + user_prod_group->setFont(font); + + user_create_carts_button=new QCheckBox(user_prod_group, + "user_create_carts_button"); + user_create_carts_button->setGeometry(10,21,15,15); + user_create_carts_label=new QLabel(user_create_carts_button, + tr("&Create Carts"), + user_prod_group, + "user_create_carts_label"); + user_create_carts_label->setGeometry(30,21,150,19); + user_create_carts_label->setFont(small_font); + user_create_carts_label->setAlignment(AlignLeft|ShowPrefix); + + user_delete_carts_button=new QCheckBox(user_prod_group, + "user_delete_carts_button"); + user_delete_carts_button->setGeometry(172,21,15,15); + user_delete_carts_label=new QLabel(user_delete_carts_button, + tr("&Delete Carts"), + user_prod_group, + "user_delete_carts_label"); + user_delete_carts_label->setGeometry(192,21,150,19); + user_delete_carts_label->setFont(small_font); + user_delete_carts_label->setAlignment(AlignLeft|ShowPrefix); + + user_modify_carts_button=new QCheckBox(user_prod_group, + "user_modify_carts_button"); + user_modify_carts_button->setGeometry(10,42,15,15); + user_modify_carts_label=new QLabel(user_modify_carts_button, + tr("&Modify Carts"), + user_prod_group, + "user_modify_carts_label"); + user_modify_carts_label->setGeometry(30,41,150,19); + user_modify_carts_label->setFont(small_font); + user_modify_carts_label->setAlignment(AlignLeft|ShowPrefix); + + user_edit_audio_button=new QCheckBox(user_prod_group, + "user_edit_audio_button"); + user_edit_audio_button->setGeometry(10,63,15,15); + user_edit_audio_label=new QLabel(user_edit_audio_button, + tr("&Edit Audio"), + user_prod_group, + "user_edit_audio_label"); + user_edit_audio_label->setGeometry(30,62,150,19); + user_edit_audio_label->setFont(small_font); + user_edit_audio_label->setAlignment(AlignLeft|ShowPrefix); + + user_edit_catches_button=new QCheckBox(user_prod_group, + "user_edit_catches_button"); + user_edit_catches_button->setGeometry(172,42,15,15); + user_edit_catches_label=new QLabel(user_edit_catches_button, + tr("&Edit Netcatch Schedule"), + user_prod_group, + "user_edit_catches_label"); + user_edit_catches_label->setGeometry(192,41,150,19); + user_edit_catches_label->setFont(small_font); + user_edit_catches_label->setAlignment(AlignLeft|ShowPrefix); + + user_voicetrack_log_button=new QCheckBox(user_prod_group, + "user_voicetrack_log_button"); + user_voicetrack_log_button->setGeometry(172,63,15,15); + user_voicetrack_log_label=new QLabel(user_voicetrack_log_button, + tr("&Voicetrack Logs"), + user_prod_group, + "user_voicetrack_log_label"); + user_voicetrack_log_label->setGeometry(192,62,150,19); + user_voicetrack_log_label->setFont(small_font); + user_voicetrack_log_label->setAlignment(AlignLeft|ShowPrefix); + + // + // Traffic Group Priviledges + // + user_traffic_group=new QButtonGroup(tr("Traffic Rights"),this, + "user_traffic_group"); + user_traffic_group->setGeometry(10,275,355,66); + user_traffic_group->setFont(font); + + user_create_log_button=new QCheckBox(user_traffic_group, + "user_create_log_button"); + user_create_log_button->setGeometry(10,21,15,15); + user_create_log_label=new QLabel(user_create_log_button, + tr("Create &Log"), + user_traffic_group, + "user_create_log_label"); + user_create_log_label->setGeometry(30,21,150,19); + user_create_log_label->setFont(small_font); + user_create_log_label->setAlignment(AlignLeft|ShowPrefix); + + user_delete_log_button=new QCheckBox(user_traffic_group, + "user_delete_log_button"); + user_delete_log_button->setGeometry(172,21,15,15); + user_delete_log_label=new QLabel(user_delete_log_button, + tr("De&lete Log"), + user_traffic_group, + "user_delete_log_label"); + user_delete_log_label->setGeometry(192,21,150,19); + user_delete_log_label->setFont(small_font); + user_delete_log_label->setAlignment(AlignLeft|ShowPrefix); + + user_delete_rec_button=new QCheckBox(user_traffic_group, + "user_delete_rec_button"); + user_delete_rec_button->setGeometry(172,42,15,15); + user_delete_rec_label=new QLabel(user_delete_rec_button, + tr("Delete &Report Data"), + user_traffic_group, + "user_delete_rec_label"); + user_delete_rec_label->setGeometry(192,42,150,19); + user_delete_rec_label->setFont(small_font); + user_delete_rec_label->setAlignment(AlignLeft|ShowPrefix); + + user_modify_template_button=new QCheckBox(user_traffic_group, + "user_modify_template_button"); + user_modify_template_button->setGeometry(10,42,15,15); + user_modify_template_label=new QLabel(user_modify_template_button, + tr("&Modify Template"), + user_traffic_group, + "user_modify_template_label"); + user_modify_template_label->setGeometry(30,42,100,19); + user_modify_template_label->setFont(small_font); + user_modify_template_label->setAlignment(AlignLeft|ShowPrefix); + + // + // OnAir Group Priviledges + // + user_onair_group=new QButtonGroup(tr("OnAir Rights"),this, + "user_onair_group"); + user_onair_group->setGeometry(10,351,355,85); + user_onair_group->setFont(font); + + user_playout_log_button=new QCheckBox(user_onair_group, + "user_playout_log_button"); + user_playout_log_button->setGeometry(10,21,15,15); + user_playout_log_label=new QLabel(user_playout_log_button, + tr("&Playout Logs"), + user_onair_group, + "user_playout_log_label"); + user_playout_log_label->setGeometry(30,21,150,19); + user_playout_log_label->setFont(small_font); + user_playout_log_label->setAlignment(AlignLeft|ShowPrefix); + + user_arrange_log_button=new QCheckBox(user_onair_group, + "user_arrange_log_button"); + user_arrange_log_button->setGeometry(172,21,15,15); + user_arrange_log_label=new QLabel(user_arrange_log_button, + tr("&Rearrange Log Items"), + user_onair_group, + "user_arrange_log_label"); + user_arrange_log_label->setGeometry(192,21,150,19); + user_arrange_log_label->setFont(small_font); + user_arrange_log_label->setAlignment(AlignLeft|ShowPrefix); + + user_addto_log_button=new QCheckBox(user_onair_group, + "user_addto_log_button"); + user_addto_log_button->setGeometry(10,42,15,15); + user_addto_log_label=new QLabel(user_addto_log_button, + tr("Add Log &Items"), + user_onair_group, + "user_addto_log_label"); + user_addto_log_label->setGeometry(30,42,150,19); + user_addto_log_label->setFont(small_font); + user_addto_log_label->setAlignment(AlignLeft|ShowPrefix); + + user_removefrom_log_button=new QCheckBox(user_onair_group, + "user_removefrom_log_button"); + user_removefrom_log_button->setGeometry(172,42,15,15); + user_removefrom_log_label=new QLabel(user_removefrom_log_button, + tr("Delete Lo&g Items"), + user_onair_group, + "user_removefrom_log_label"); + user_removefrom_log_label->setGeometry(192,42,150,19); + user_removefrom_log_label->setFont(small_font); + user_removefrom_log_label->setAlignment(AlignLeft|ShowPrefix); + + user_config_panels_button=new QCheckBox(user_onair_group, + "user_config_panels_button"); + user_config_panels_button->setGeometry(10,63,15,15); + user_config_panels_label=new QLabel(user_config_panels_button, + tr("Configure System Panels"), + user_onair_group, + "user_config_panels_label"); + user_config_panels_label->setGeometry(30,63,150,19); + user_config_panels_label->setFont(small_font); + user_config_panels_label->setAlignment(AlignLeft|ShowPrefix); + + // + // Podcast Group Priviledges + // + user_podcast_group=new QButtonGroup(tr("Podcasting Rights"),this, + "user_podcast_group"); + user_podcast_group->setGeometry(10,446,355,66); + user_podcast_group->setFont(font); + + user_add_podcast_button=new QCheckBox(user_podcast_group, + "user_add_podcast_button"); + user_add_podcast_button->setGeometry(10,21,15,15); + user_add_podcast_label=new QLabel(user_add_podcast_button, + tr("Cre&ate Podcast"), + user_podcast_group, + "user_add_podcast_label"); + user_add_podcast_label->setGeometry(30,21,150,19); + user_add_podcast_label->setFont(small_font); + user_add_podcast_label->setAlignment(AlignLeft|ShowPrefix); + + user_edit_podcast_button=new QCheckBox(user_podcast_group, + "user_edit_podcast_button"); + user_edit_podcast_button->setGeometry(172,21,15,15); + user_edit_podcast_label=new QLabel(user_edit_podcast_button, + tr("E&dit Podcast"), + user_podcast_group, + "user_edit_podcast_label"); + user_edit_podcast_label->setGeometry(192,21,150,19); + user_edit_podcast_label->setFont(small_font); + user_edit_podcast_label->setAlignment(AlignLeft|ShowPrefix); + + user_delete_podcast_button=new QCheckBox(user_podcast_group, + "user_delete_podcast_button"); + user_delete_podcast_button->setGeometry(10,42,15,15); + user_delete_podcast_label=new QLabel(user_delete_podcast_button, + tr("Dele&te Podcast"), + user_podcast_group, + "user_delete_podcast_label"); + user_delete_podcast_label->setGeometry(30,42,150,19); + user_delete_podcast_label->setFont(small_font); + user_delete_podcast_label->setAlignment(AlignLeft|ShowPrefix); + + // + // Group Permissions Button + // + user_assign_perms_button=new QPushButton(this,"user_assign_perms_button"); + user_assign_perms_button->setGeometry(10,516,sizeHint().width()/2-20,50); + user_assign_perms_button->setFont(font); + user_assign_perms_button->setText(tr("Assign Group\nPermissions")); + connect(user_assign_perms_button,SIGNAL(clicked()),this,SLOT(groupsData())); + + // + // Feeds Permissions Button + // + user_assign_feeds_button=new QPushButton(this,"user_assign_feeds_button"); + user_assign_feeds_button-> + setGeometry(sizeHint().width()/2+10,516,sizeHint().width()/2-20,50); + user_assign_feeds_button->setFont(font); + user_assign_feeds_button->setText(tr("Assign Podcast Feed\nPermissions")); + connect(user_assign_feeds_button,SIGNAL(clicked()),this,SLOT(feedsData())); + + // + // Ok Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + user_name_edit->setText(user_user->name()); + user_name_edit->setReadOnly(true); + user_full_name_edit->setText(user_user->fullName()); + user_description_edit->setText(user_user->description()); + user_phone_edit->setText(user_user->phone()); + user_web_box->setChecked(user_user->enableWeb()); + if(user_user->adminConfig()) { + user_admin_config_button->setChecked(true); + adminToggledData(true); + } + else { + user_create_carts_button->setChecked(user_user->createCarts()); + user_delete_carts_button->setChecked(user_user->deleteCarts()); + user_modify_carts_button->setChecked(user_user->modifyCarts()); + user_edit_audio_button->setChecked(user_user->editAudio()); + user_edit_catches_button->setChecked(user_user->editCatches()); + user_voicetrack_log_button->setChecked(user_user->voicetrackLog()); + + user_create_log_button->setChecked(user_user->createLog()); + user_delete_log_button->setChecked(user_user->deleteLog()); + user_delete_rec_button->setChecked(user_user->deleteRec()); + + user_playout_log_button->setChecked(user_user->playoutLog()); + user_arrange_log_button->setChecked(user_user->arrangeLog()); + user_addto_log_button->setChecked(user_user->addtoLog()); + user_removefrom_log_button->setChecked(user_user->removefromLog()); + user_config_panels_button->setChecked(user_user->configPanels()); + user_modify_template_button->setChecked(user_user->modifyTemplate()); + + user_add_podcast_button->setChecked(user_user->addPodcast()); + user_edit_podcast_button->setChecked(user_user->editPodcast()); + user_delete_podcast_button->setChecked(user_user->deletePodcast()); + } + + // + // Don't Allow an Administrator to Disable Himself! + // + if(user_user->name()==admin_user->name()) { + user_admin_config_label->setDisabled(true); + user_admin_config_button->setDisabled(true); + } +} + + +EditUser::~EditUser() +{ + delete user_name_edit; + delete user_full_name_edit; + delete user_description_edit; + delete user_phone_edit; + delete user_admin_group; + delete user_prod_group; + delete user_traffic_group; + delete user_onair_group; +} + + +QSize EditUser::sizeHint() const +{ + return QSize(375,636); +} + + +QSizePolicy EditUser::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditUser::passwordData() +{ + QString password; + + RDPasswd *passwd=new RDPasswd(&password,this,"passwd"); + if(passwd->exec()==0) { + user_user->setPassword(password); + } + delete passwd; +} + + +void EditUser::groupsData() +{ + EditUserPerms *dialog=new EditUserPerms(user_user,this,"dialog"); + dialog->exec(); + delete dialog; +} + + +void EditUser::feedsData() +{ + EditFeedPerms *dialog=new EditFeedPerms(user_user,this,"dialog"); + dialog->exec(); + delete dialog; +} + + +void EditUser::adminToggledData(bool state) +{ + user_web_box->setDisabled(state); + user_web_label->setDisabled(state); + user_create_carts_button->setDisabled(state); + user_delete_carts_button->setDisabled(state); + user_modify_carts_button->setDisabled(state); + user_edit_audio_button->setDisabled(state); + user_create_log_button->setDisabled(state); + user_delete_log_button->setDisabled(state); + user_delete_rec_button->setDisabled(state); + user_playout_log_button->setDisabled(state); + user_arrange_log_button->setDisabled(state); + user_addto_log_button->setDisabled(state); + user_removefrom_log_button->setDisabled(state); + user_config_panels_button->setDisabled(state); + user_modify_template_button->setDisabled(state); + user_edit_catches_button->setDisabled(state); + user_voicetrack_log_button->setDisabled(state); + user_add_podcast_button->setDisabled(state); + user_edit_podcast_button->setDisabled(state); + user_delete_podcast_button->setDisabled(state); + user_create_carts_label->setDisabled(state); + user_delete_carts_label->setDisabled(state); + user_modify_carts_label->setDisabled(state); + user_edit_audio_label->setDisabled(state); + user_create_log_label->setDisabled(state); + user_delete_log_label->setDisabled(state); + user_delete_rec_label->setDisabled(state); + user_playout_log_label->setDisabled(state); + user_arrange_log_label->setDisabled(state); + user_addto_log_label->setDisabled(state); + user_removefrom_log_label->setDisabled(state); + user_config_panels_label->setDisabled(state); + user_modify_template_label->setDisabled(state); + user_edit_catches_label->setDisabled(state); + user_add_podcast_label->setDisabled(state); + user_edit_podcast_label->setDisabled(state); + user_delete_podcast_label->setDisabled(state); + user_voicetrack_log_label->setDisabled(state); + user_assign_perms_button->setDisabled(state); + user_assign_feeds_button->setDisabled(state); +} + + +void EditUser::okData() +{ + user_user->setFullName(user_full_name_edit->text()); + user_user->setDescription(user_description_edit->text()); + user_user->setPhone(user_phone_edit->text()); + user_user->setEnableWeb(user_web_box->isChecked()); + user_user->setAdminConfig(user_admin_config_button->isChecked()); + user_user->setCreateCarts(user_create_carts_button->isChecked()); + user_user->setDeleteCarts(user_delete_carts_button->isChecked()); + user_user->setModifyCarts(user_modify_carts_button->isChecked()); + user_user->setEditAudio(user_edit_audio_button->isChecked()); + user_user->setEditCatches(user_edit_catches_button->isChecked()); + user_user->setVoicetrackLog(user_voicetrack_log_button->isChecked()); + user_user->setCreateLog(user_create_log_button->isChecked()); + user_user->setDeleteLog(user_delete_log_button->isChecked()); + user_user->setDeleteRec(user_delete_rec_button->isChecked()); + user_user->setPlayoutLog(user_playout_log_button->isChecked()); + user_user->setArrangeLog(user_arrange_log_button->isChecked()); + user_user->setAddtoLog(user_addto_log_button->isChecked()); + user_user->setRemovefromLog(user_removefrom_log_button->isChecked()); + user_user->setConfigPanels(user_config_panels_button->isChecked()); + user_user->setModifyTemplate(user_modify_template_button->isChecked()); + user_user->setAddPodcast(user_add_podcast_button->isChecked()); + user_user->setEditPodcast(user_edit_podcast_button->isChecked()); + user_user->setDeletePodcast(user_delete_podcast_button->isChecked()); + + done(0); +} + + +void EditUser::cancelData() +{ + done(-1); +} diff --git a/rdadmin/edit_user.h b/rdadmin/edit_user.h new file mode 100644 index 00000000..5d62305d --- /dev/null +++ b/rdadmin/edit_user.h @@ -0,0 +1,112 @@ +// edit_user.h +// +// Edit a Rivendell User +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: edit_user.h,v 1.21 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_USER_H +#define EDIT_USER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +class EditUser : public QDialog +{ + Q_OBJECT + public: + EditUser(const QString &user,QWidget *parent=0,const char *name=0); + ~EditUser(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void passwordData(); + void groupsData(); + void feedsData(); + void adminToggledData(bool state); + void okData(); + void cancelData(); + + private: + QLineEdit *user_name_edit; + QLineEdit *user_full_name_edit; + QLineEdit *user_description_edit; + QLineEdit *user_phone_edit; + QCheckBox *user_web_box; + QLabel *user_web_label; + QButtonGroup *user_admin_group; + QButtonGroup *user_prod_group; + QButtonGroup *user_traffic_group; + QButtonGroup *user_onair_group; + QButtonGroup *user_podcast_group; + QCheckBox *user_admin_config_button; + QCheckBox *user_create_carts_button; + QCheckBox *user_delete_carts_button; + QCheckBox *user_modify_carts_button; + QCheckBox *user_edit_audio_button; + QCheckBox *user_voicetrack_log_button; + QCheckBox *user_create_log_button; + QCheckBox *user_delete_log_button; + QCheckBox *user_delete_rec_button; + QCheckBox *user_playout_log_button; + QCheckBox *user_arrange_log_button; + QCheckBox *user_addto_log_button; + QCheckBox *user_removefrom_log_button; + QCheckBox *user_config_panels_button; + QCheckBox *user_modify_template_button; + QCheckBox *user_edit_catches_button; + QCheckBox *user_add_podcast_button; + QCheckBox *user_edit_podcast_button; + QCheckBox *user_delete_podcast_button; + QPushButton *user_assign_perms_button; + QPushButton *user_assign_feeds_button; + QLabel *user_create_carts_label; + QLabel *user_delete_carts_label; + QLabel *user_modify_carts_label; + QLabel *user_edit_audio_label; + QLabel *user_create_log_label; + QLabel *user_delete_log_label; + QLabel *user_delete_rec_label; + QLabel *user_playout_log_label; + QLabel *user_arrange_log_label; + QLabel *user_addto_log_label; + QLabel *user_removefrom_log_label; + QLabel *user_config_panels_label; + QLabel *user_modify_template_label; + QLabel *user_edit_catches_label; + QLabel *user_add_podcast_label; + QLabel *user_edit_podcast_label; + QLabel *user_delete_podcast_label; + QLabel *user_voicetrack_log_label; + RDUser *user_user; +}; + + +#endif + diff --git a/rdadmin/edit_user_perms.cpp b/rdadmin/edit_user_perms.cpp new file mode 100644 index 00000000..d259869e --- /dev/null +++ b/rdadmin/edit_user_perms.cpp @@ -0,0 +1,177 @@ +// edit_user_perms.cpp +// +// Edit Rivendell User/Group Permissions +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_user_perms.cpp,v 1.7 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +EditUserPerms::EditUserPerms(RDUser *user,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + + user_user=user; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("User: ")+user_user->name()); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Groups Selector + // + user_host_sel=new RDListSelector(this,"user_host_sel"); + user_host_sel->sourceSetLabel(tr("Available Groups")); + user_host_sel->destSetLabel(tr("Enabled Groups")); + user_host_sel->setGeometry(10,10,380,130); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + sql=QString().sprintf("select GROUP_NAME from USER_PERMS \ + where USER_NAME=\"%s\"", + (const char *)user_user->name()); + q=new RDSqlQuery(sql); + while(q->next()) { + user_host_sel->destInsertItem(q->value(0).toString()); + } + delete q; + + sql=QString().sprintf("select NAME from GROUPS"); + q=new RDSqlQuery(sql); + while(q->next()) { + if(user_host_sel->destFindItem(q->value(0).toString())==0) { + user_host_sel->sourceInsertItem(q->value(0).toString()); + } + } + delete q; +} + + +EditUserPerms::~EditUserPerms() +{ +} + + +QSize EditUserPerms::sizeHint() const +{ + return QSize(400,212); +} + + +QSizePolicy EditUserPerms::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditUserPerms::okData() +{ + RDSqlQuery *q; + QString sql; + + // + // Add New Groups + // + for(unsigned i=0;idestCount();i++) { + sql=QString().sprintf("select GROUP_NAME from USER_PERMS \ + where USER_NAME=\"%s\" && GROUP_NAME=\"%s\"", + (const char *)user_user->name(), + (const char *)user_host_sel->destText(i)); + q=new RDSqlQuery(sql); + if(q->size()==0) { + delete q; + sql=QString(). + sprintf("insert into USER_PERMS (USER_NAME,GROUP_NAME) \ + values (\"%s\",\"%s\")", + (const char *)user_user->name(), + (const char *)user_host_sel->destText(i)); + q=new RDSqlQuery(sql); + } + delete q; + } + + // + // Delete Old Groups + // + sql=QString().sprintf("delete from USER_PERMS where USER_NAME=\"%s\"", + (const char *)user_user->name()); + for(unsigned i=0;idestCount();i++) { + sql+=QString().sprintf(" && GROUP_NAME<>\"%s\"", + (const char *)user_host_sel->destText(i)); + } + q=new RDSqlQuery(sql); + delete q; + done(0); +} + + +void EditUserPerms::cancelData() +{ + done(1); +} diff --git a/rdadmin/edit_user_perms.h b/rdadmin/edit_user_perms.h new file mode 100644 index 00000000..a10e4bb7 --- /dev/null +++ b/rdadmin/edit_user_perms.h @@ -0,0 +1,53 @@ +// edit_user_perms.h +// +// Edit Rivendell Service Permissions +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_user_perms.h,v 1.6 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_USER_PERMS_H +#define EDIT_USER_PERMS_H + +#include +#include +#include + +#include + + +class EditUserPerms : public QDialog +{ + Q_OBJECT + public: + EditUserPerms(RDUser *user,QWidget *parent=0,const char *name=0); + ~EditUserPerms(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + RDListSelector *user_host_sel; + RDUser *user_user; +}; + + +#endif + diff --git a/rdadmin/edit_vguest_resource.cpp b/rdadmin/edit_vguest_resource.cpp new file mode 100644 index 00000000..7c57e194 --- /dev/null +++ b/rdadmin/edit_vguest_resource.cpp @@ -0,0 +1,220 @@ +// edit_vguest_resource.cpp +// +// Edit a vGuest Resource Record. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_vguest_resource.cpp,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include + + +EditVguestResource::EditVguestResource(RDMatrix::VguestType type, + int *enginenum,int *devicenum, + int *surfacenum,int *relaynum, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_type=type; + edit_enginenum=enginenum; + edit_devicenum=devicenum; + edit_surfacenum=surfacenum; + edit_relaynum=relaynum; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Logitek Engine Number + // + edit_enginenum_edit=new QLineEdit(this,"edit_enginenum_edit"); + edit_enginenum_edit->setGeometry(135,10,50,20); + QLabel *label=new QLabel(edit_enginenum_edit,tr("Engine (Hex): "), + this,"edit_enginenum_label"); + label->setGeometry(10,10,120,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Logitek Device Number + // + edit_devicenum_edit=new QLineEdit(this,"edit_devicenum_edit"); + edit_devicenum_edit->setGeometry(135,36,50,20); + label=new QLabel(edit_devicenum_edit,tr("Device (Hex): "), + this,"edit_devicenum_label"); + label->setGeometry(10,36,120,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Logitek Surface Number + // + edit_surfacenum_edit=new QLineEdit(this,"edit_surfacenum_edit"); + edit_surfacenum_edit->setGeometry(135,62,50,20); + label=new QLabel(edit_surfacenum_edit,tr("Surface (Hex): "), + this,"edit_surfacenum_label"); + label->setGeometry(10,62,120,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Logitek Relay Number + // + edit_relaynum_edit=new QLineEdit(this,"edit_relaynum_edit"); + edit_relaynum_edit->setGeometry(135,88,50,20); + edit_relaynum_label=new QLabel(edit_relaynum_edit,tr("Bus/Relay (Hex): "), + this,"edit_relaynum_label"); + edit_relaynum_label->setGeometry(10,88,120,20); + edit_relaynum_label->setFont(bold_font); + edit_relaynum_label->setAlignment(AlignRight|AlignVCenter); + + // + // Ok Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Data + // + if(*enginenum>=0) { + edit_enginenum_edit->setText(QString().sprintf("%04X",*enginenum)); + } + if(*devicenum>=0) { + edit_devicenum_edit->setText(QString().sprintf("%04X",*devicenum)); + } + if(*surfacenum>=0) { + edit_surfacenum_edit->setText(QString().sprintf("%04X",*surfacenum)); + } + switch(edit_type) { + case RDMatrix::VguestTypeRelay: + setCaption(tr("Edit vGuest Switch")); + if(*relaynum>=0) { + edit_relaynum_edit->setText(QString().sprintf("%04X",*relaynum)); + } + break; + + case RDMatrix::VguestTypeDisplay: + setCaption(tr("Edit vGuest Display")); + edit_relaynum_edit->setDisabled(true); + break; + } +} + + +QSize EditVguestResource::sizeHint() const +{ + return QSize(400,174); +} + + +QSizePolicy EditVguestResource::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditVguestResource::okData() +{ + bool ok; + int enginenum=edit_enginenum_edit->text().toInt(&ok,16); + if(!ok) { + if(edit_enginenum_edit->text().isEmpty()) { + enginenum=-1; + } + else { + QMessageBox::warning(this,tr("Invalid Number"), + tr("The Engine Number is Invalid!")); + return; + } + } + int devicenum=edit_devicenum_edit->text().toInt(&ok,16); + if(!ok) { + if(edit_devicenum_edit->text().isEmpty()) { + devicenum=-1; + } + else { + QMessageBox::warning(this,tr("Invalid Number"), + tr("The Device Number is Invalid!")); + return; + } + } + int surfacenum=edit_surfacenum_edit->text().toInt(&ok,16); + if(!ok) { + if(edit_surfacenum_edit->text().isEmpty()) { + surfacenum=-1; + } + else { + QMessageBox::warning(this,tr("Invalid Number"), + tr("The Surface Number is Invalid!")); + return; + } + } + int relaynum=edit_relaynum_edit->text().toInt(&ok,16); + if(!ok) { + if(edit_relaynum_edit->text().isEmpty()) { + relaynum=-1; + } + else { + QMessageBox::warning(this,tr("Invalid Number"), + tr("The Bus/Relay Number is Invalid!")); + return; + } + } + *edit_enginenum=enginenum; + *edit_devicenum=devicenum; + *edit_surfacenum=surfacenum; + *edit_relaynum=relaynum; + done(0); +} + + +void EditVguestResource::cancelData() +{ + done(1); +} diff --git a/rdadmin/edit_vguest_resource.h b/rdadmin/edit_vguest_resource.h new file mode 100644 index 00000000..a4ddcb94 --- /dev/null +++ b/rdadmin/edit_vguest_resource.h @@ -0,0 +1,66 @@ +// edit_vguest_resource.h +// +// Edit a vGuest Resource Record. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_vguest_resource.h,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_VGUEST_RESOURCE_H +#define EDIT_VGUEST_RESOURCE_H + +#include +#include +#include +#include +#include +#include + +#include +#include + + +class EditVguestResource : public QDialog +{ + Q_OBJECT + public: + EditVguestResource(RDMatrix::VguestType type,int *enginenum,int *devicenum, + int *surfacenum,int *relaynum, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + RDMatrix::VguestType edit_type; + int *edit_enginenum; + int *edit_devicenum; + int *edit_surfacenum; + int *edit_relaynum; + QLineEdit *edit_enginenum_edit; + QLineEdit *edit_devicenum_edit; + QLineEdit *edit_surfacenum_edit; + QLabel *edit_relaynum_label; + QLineEdit *edit_relaynum_edit; +}; + + +#endif // EDIT_ENDPOINT + diff --git a/rdadmin/globals.h b/rdadmin/globals.h new file mode 100644 index 00000000..eadc984f --- /dev/null +++ b/rdadmin/globals.h @@ -0,0 +1,52 @@ +// globals.h +// +// Global Definitions for RDAdmin +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: globals.h,v 1.11.4.1 2012/11/26 20:19:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef GLOBALS_H +#define GLOBALS_H + +#include +#include +#include +#include +#include +#include + +// +// Global Classes +// +extern RDRipc *rdripc; +extern RDConfig *admin_config; +extern RDUser *admin_user; +extern RDStation *admin_station; +extern RDSystem *admin_system; +extern RDCartDialog *admin_cart_dialog; +extern QString admin_svc_name; +extern QString admin_admin_username; +extern QString admin_admin_password; +extern QString admin_admin_hostname; +extern QString admin_admin_dbname; +extern bool admin_skip_backup; +extern QString admin_backup_filename; +extern void PrintError(const QString &str,bool interactive); + +#endif // GLOBALS_H diff --git a/rdadmin/help_audios.cpp b/rdadmin/help_audios.cpp new file mode 100644 index 00000000..6867cc47 --- /dev/null +++ b/rdadmin/help_audios.cpp @@ -0,0 +1,95 @@ +// help_audios.cpp +// +// Display help for audio ports (edit_audios.*) +// +// (C) Copyright 2006 Fred Gleason +// +// $Id: help_audios.cpp,v 1.7 2012/02/13 19:26:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include + +#include + + +HelpAudioPorts::HelpAudioPorts(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Audio Ports Help")); + + // + // Create Fonts + // + QFont button_font=QFont("Helvetica",14,QFont::Bold); + button_font.setPixelSize(14); + + // Help Text + help_edit=new QTextEdit(this,"help_edit"); + help_edit-> + setGeometry(10,10,sizeHint().width()-20,sizeHint().height()-70); + help_edit->setTextFormat(RichText); + help_edit->setReadOnly(true); +// FIXME: add context sensitive help for other options on the Audio Port screen. + help_edit->setText(tr("Mode - short for Channel Mode, configures the Left and Right behaviour when recording.
\ + Behaviour varies depending on the number of channels to record as summarized in the table below:
\ +\ +\ +\ +\ +\ +\ +\ +\ +\ +\ +
Channels Mode Effect
Mono Normal L+R sum to mono
Mono Swap R+L sum to mono (same result as Normal)
Mono Left only L -> mono
Mono Right only R -> mono
Stereo Normal Stereo
Stereo Swap Swapped stereo
Stereo Left only L -> to L channel only, R channel is silent
Stereo Right only R -> to R channel only, L channel is silent
")); + + // + // Close Button + // + QPushButton *button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Close")); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +QSize HelpAudioPorts::sizeHint() const +{ + return QSize(600,400); +} + + +QSizePolicy HelpAudioPorts::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void HelpAudioPorts::closeData() +{ + done(0); +} diff --git a/rdadmin/help_audios.h b/rdadmin/help_audios.h new file mode 100644 index 00000000..591cada7 --- /dev/null +++ b/rdadmin/help_audios.h @@ -0,0 +1,47 @@ +// help_audios.h +// +// Display help for audio ports (edit_audios.*) +// +// (C) Copyright 2006 Fred Gleason +// +// $Id: help_audios.h,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef HELP_AUDIOS_H +#define HELP_AUDIOS_H + +#include +#include + + +class HelpAudioPorts : public QDialog +{ + Q_OBJECT + public: + HelpAudioPorts(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void closeData(); + + private: + QTextEdit *help_edit; +}; + + +#endif diff --git a/rdadmin/importfields.cpp b/rdadmin/importfields.cpp new file mode 100644 index 00000000..b86dce1d --- /dev/null +++ b/rdadmin/importfields.cpp @@ -0,0 +1,517 @@ +// importfields.cpp +// +// Parser Parameters for RDAdmin. +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: importfields.cpp,v 1.2 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include + +#include + +ImportFields::ImportFields(QWidget *parent,const char *name) + : QWidget(parent,name) +{ + QLabel *label; + import_changed=false; + + // + // Traffic Cartname Parser Data Section + // + label=new QLabel(tr("Cart Number:"),this, + "_cartname_label"); + label->setGeometry(0,0,120,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Traffic Cart Offset + // + cart_offset_spin=new QSpinBox(this,"cart_offset_spin"); + cart_offset_spin->setGeometry(175,0,50,19); + cart_offset_spin->setRange(0,1024); + label=new QLabel(cart_offset_spin, + tr("Offset:"),this, + "cart_win_path_label"); + label->setGeometry(125,0,45,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(cart_offset_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Cart Length + // + cart_length_spin=new QSpinBox(this,"cart_length_spin"); + cart_length_spin->setGeometry(285,0,50,19); + cart_length_spin->setRange(0,6); + label=new QLabel(cart_length_spin, + tr("Length:"),this, + "cart_win_path_label"); + label->setGeometry(230,0,50,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(cart_length_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Title Parser Data Section + // + label=new QLabel(tr("Title:"),this,"_cartname_label"); + label->setGeometry(0,21,120,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Title Cart Offset + // + title_offset_spin=new QSpinBox(this,"title_offset_spin"); + title_offset_spin->setGeometry(175,21,50,19); + title_offset_spin->setRange(0,1024); + label=new QLabel(title_offset_spin, + tr("Offset:"),this, + "title_win_path_label"); + label->setGeometry(125,21,45,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(title_offset_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Title Cart Length + // + title_length_spin=new QSpinBox(this,"title_length_spin"); + title_length_spin->setGeometry(285,21,50,19); + title_length_spin->setRange(0,255); + label=new QLabel(title_length_spin, + tr("Length:"),this, + "title_win_path_label"); + label->setGeometry(230,21,50,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(title_length_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Start Hours Parser Data Section + // + label=new QLabel(tr("Start Time - Hours:"),this, + "_startname_label"); + label->setGeometry(0,42,120,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Traffic Start Hours Offset + // + hours_offset_spin=new QSpinBox(this,"hours_offset_spin"); + hours_offset_spin->setGeometry(175,42,50,19); + hours_offset_spin->setRange(0,RD_MAX_IMPORT_LINE_LENGTH); + label=new QLabel(hours_offset_spin, + tr("Offset:"),this, + "hours_win_path_label"); + label->setGeometry(125,42,45,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(hours_offset_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Start Hours Length + // + hours_length_spin=new QSpinBox(this,"hours_length_spin"); + hours_length_spin->setGeometry(285,42,50,19); + hours_length_spin->setRange(0,8); + label=new QLabel(hours_length_spin, + tr("Length:"),this, + "hours_win_path_label"); + label->setGeometry(230,42,50,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(hours_length_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Start Minutes Parser Data Section + // + label=new QLabel(tr("Start Time - Minutes:"),this, + "_startname_label"); + label->setGeometry(0,63,120,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Traffic Start Minutes Offset + // + minutes_offset_spin=new QSpinBox(this,"minutes_offset_spin"); + minutes_offset_spin->setGeometry(175,63,50,19); + minutes_offset_spin->setRange(0,RD_MAX_IMPORT_LINE_LENGTH); + label=new QLabel(minutes_offset_spin, + tr("Offset:"),this, + "minutes_win_path_label"); + label->setGeometry(125,63,45,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(minutes_offset_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Start Minutes Length + // + minutes_length_spin=new QSpinBox(this,"minutes_length_spin"); + minutes_length_spin->setGeometry(285,63,50,19); + minutes_length_spin->setRange(0,8); + label=new QLabel(minutes_length_spin, + tr("Length:"),this, + "minutes_win_path_label"); + label->setGeometry(230,63,50,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(minutes_length_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Start Seconds Parser Data Section + // + label=new QLabel(tr("Start Time - Seconds:"),this, + "_startname_label"); + label->setGeometry(0,84,120,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Traffic Start Seconds Offset + // + seconds_offset_spin=new QSpinBox(this,"seconds_offset_spin"); + seconds_offset_spin->setGeometry(175,84,50,19); + seconds_offset_spin->setRange(0,RD_MAX_IMPORT_LINE_LENGTH); + label=new QLabel(seconds_offset_spin, + tr("Offset:"),this, + "seconds_win_path_label"); + label->setGeometry(125,84,45,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(seconds_offset_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Start Seconds Length + // + seconds_length_spin=new QSpinBox(this,"seconds_length_spin"); + seconds_length_spin->setGeometry(285,84,50,19); + seconds_length_spin->setRange(0,8); + label=new QLabel(seconds_length_spin, + tr("Length:"),this, + "seconds_win_path_label"); + label->setGeometry(230,84,50,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(seconds_length_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Length Hours Parser Data Section + // + label=new QLabel(tr("Length - Hours:"),this, + "_lengthname_label"); + label->setGeometry(0,106,120,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Traffic Length Hours Offset + // + len_hours_offset_spin=new QSpinBox(this,"len_hours_offset_spin"); + len_hours_offset_spin->setGeometry(175,106,50,19); + len_hours_offset_spin->setRange(0,RD_MAX_IMPORT_LINE_LENGTH); + label=new QLabel(len_hours_offset_spin, + tr("Offset:"),this, + "len_hours_win_path_label"); + label->setGeometry(125,106,45,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(len_hours_offset_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Length Hours Length + // + len_hours_length_spin=new QSpinBox(this,"len_hours_length_spin"); + len_hours_length_spin->setGeometry(285,106,50,19); + len_hours_length_spin->setRange(0,8); + label=new QLabel(len_hours_length_spin, + tr("Length:"),this, + "len_hours_win_path_label"); + label->setGeometry(230,106,50,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(len_hours_length_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Length Minutes Parser Data Section + // + label=new QLabel(tr("Length - Minutes:"),this, + "_lengthname_label"); + label->setGeometry(0,127,120,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Traffic Length Minutes Offset + // + len_minutes_offset_spin=new QSpinBox(this,"len_minutes_offset_spin"); + len_minutes_offset_spin->setGeometry(175,127,50,19); + len_minutes_offset_spin->setRange(0,RD_MAX_IMPORT_LINE_LENGTH); + label=new QLabel(len_minutes_offset_spin, + tr("Offset:"),this, + "len_minutes_win_path_label"); + label->setGeometry(125,127,45,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(len_minutes_offset_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Length Minutes Length + // + len_minutes_length_spin=new QSpinBox(this,"len_minutes_length_spin"); + len_minutes_length_spin->setGeometry(285,127,50,19); + len_minutes_length_spin->setRange(0,8); + label=new QLabel(len_minutes_length_spin, + tr("Length:"),this, + "len_minutes_win_path_label"); + label->setGeometry(230,127,50,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(len_minutes_length_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Length Seconds Parser Data Section + // + label=new QLabel(tr("Length - Seconds:"),this, + "_lengthname_label"); + label->setGeometry(0,148,120,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Traffic Length Seconds Offset + // + len_seconds_offset_spin=new QSpinBox(this,"len_seconds_offset_spin"); + len_seconds_offset_spin->setGeometry(175,148,50,19); + len_seconds_offset_spin->setRange(0,RD_MAX_IMPORT_LINE_LENGTH); + label=new QLabel(len_seconds_offset_spin, + tr("Offset:"),this, + "len_seconds_win_path_label"); + label->setGeometry(125,148,45,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(len_seconds_offset_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Length Seconds Length + // + len_seconds_length_spin=new QSpinBox(this,"len_seconds_length_spin"); + len_seconds_length_spin->setGeometry(285,148,50,19); + len_seconds_length_spin->setRange(0,8); + label=new QLabel(len_seconds_length_spin, + tr("Length:"),this, + "len_seconds_win_path_label"); + label->setGeometry(230,148,50,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(len_seconds_length_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Contract # Parser Data Section + // + label=new QLabel(tr("Contract #:"),this, + "_dataname_label"); + label->setGeometry(0,169,120,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Traffic Contract # Offset + // + data_offset_spin=new QSpinBox(this,"data_offset_spin"); + data_offset_spin->setGeometry(175,169,50,19); + data_offset_spin->setRange(0,RD_MAX_IMPORT_LINE_LENGTH); + label=new QLabel(data_offset_spin, + tr("Offset:"),this, + "data_win_path_label"); + label->setGeometry(125,169,45,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(data_offset_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Contract # Length + // + data_length_spin=new QSpinBox(this,"data_length_spin"); + data_length_spin->setGeometry(285,169,50,19); + data_length_spin->setRange(0,32); + label=new QLabel(data_length_spin, + tr("Length:"),this, + "data_win_path_label"); + label->setGeometry(230,169,50,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(data_length_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Event ID Parser Data Section + // + label=new QLabel(tr("Event ID:"),this, + "_event_idname_label"); + label->setGeometry(0,190,120,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Traffic Event ID Offset + // + event_id_offset_spin=new QSpinBox(this,"event_id_offset_spin"); + event_id_offset_spin->setGeometry(175,190,50,19); + event_id_offset_spin->setRange(0,RD_MAX_IMPORT_LINE_LENGTH); + label=new QLabel(event_id_offset_spin, + tr("Offset:"),this, + "event_id_win_path_label"); + label->setGeometry(125,190,45,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(event_id_offset_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Event ID Length + // + event_id_length_spin=new QSpinBox(this,"event_id_length_spin"); + event_id_length_spin->setGeometry(285,190,50,19); + event_id_length_spin->setRange(0,8); + label=new QLabel(event_id_length_spin, + tr("Length:"),this, + "event_id_win_path_label"); + label->setGeometry(230,190,50,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(event_id_length_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Announcement Type Parser Data Section + // + label=new QLabel(tr("Annc. Type:"),this, + "_annctypename_label"); + label->setGeometry(0,211,120,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Traffic Announcement Type Offset + // + annctype_offset_spin=new QSpinBox(this,"annctype_offset_spin"); + annctype_offset_spin->setGeometry(175,211,50,19); + annctype_offset_spin->setRange(0,RD_MAX_IMPORT_LINE_LENGTH); + label=new QLabel(annctype_offset_spin, + tr("Offset:"),this, + "annctype_win_path_label"); + label->setGeometry(125,211,45,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(annctype_offset_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + + // + // Traffic Announcement Type Length + // + annctype_length_spin=new QSpinBox(this,"annctype_length_spin"); + annctype_length_spin->setGeometry(285,211,50,19); + annctype_length_spin->setRange(0,8); + label=new QLabel(annctype_length_spin, + tr("Length:"),this, + "annctype_win_path_label"); + label->setGeometry(230,211,50,19); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(annctype_length_spin,SIGNAL(valueChanged(int)), + this,SLOT(valueChangedData(int))); + +} + + +QSize ImportFields::sizeHint() const +{ + return QSize(335,230); +} + + +QSizePolicy ImportFields::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +bool ImportFields::changed() const +{ + return import_changed; +} + + +void ImportFields::readFields(RDSvc *svc,RDSvc::ImportSource type) +{ + svc->setImportOffset(type,RDSvc::CartNumber,cart_offset_spin->value()); + svc->setImportLength(type,RDSvc::CartNumber,cart_length_spin->value()); + svc->setImportOffset(type,RDSvc::Title,title_offset_spin->value()); + svc->setImportLength(type,RDSvc::Title,title_length_spin->value()); + svc->setImportOffset(type,RDSvc::StartHours,hours_offset_spin->value()); + svc->setImportLength(type,RDSvc::StartHours,hours_length_spin->value()); + svc->setImportOffset(type,RDSvc::StartMinutes,minutes_offset_spin->value()); + svc->setImportLength(type,RDSvc::StartMinutes,minutes_length_spin->value()); + svc->setImportOffset(type,RDSvc::StartSeconds,seconds_offset_spin->value()); + svc->setImportLength(type,RDSvc::StartSeconds,seconds_length_spin->value()); + svc->setImportOffset(type,RDSvc::LengthHours,len_hours_offset_spin->value()); + svc->setImportLength(type,RDSvc::LengthHours,len_hours_length_spin->value()); + svc->setImportOffset(type,RDSvc::LengthMinutes, + len_minutes_offset_spin->value()); + svc->setImportLength(type,RDSvc::LengthMinutes, + len_minutes_length_spin->value()); + svc->setImportOffset(type,RDSvc::LengthSeconds, + len_seconds_offset_spin->value()); + svc->setImportLength(type,RDSvc::LengthSeconds, + len_seconds_length_spin->value()); + svc->setImportOffset(type,RDSvc::ExtData,data_offset_spin->value()); + svc->setImportLength(type,RDSvc::ExtData,data_length_spin->value()); + svc->setImportOffset(type,RDSvc::ExtEventId,event_id_offset_spin->value()); + svc->setImportLength(type,RDSvc::ExtEventId,event_id_length_spin->value()); + svc->setImportOffset(type,RDSvc::ExtAnncType,annctype_offset_spin->value()); + svc->setImportLength(type,RDSvc::ExtAnncType,annctype_length_spin->value()); + import_changed=false; +} + + +void ImportFields::setFields(RDSvc *svc,RDSvc::ImportSource type) +{ + cart_offset_spin->setValue(svc->importOffset(type,RDSvc::CartNumber)); + cart_length_spin->setValue(svc->importLength(type,RDSvc::CartNumber)); + title_offset_spin->setValue(svc->importOffset(type,RDSvc::Title)); + title_length_spin->setValue(svc->importLength(type,RDSvc::Title)); + hours_offset_spin->setValue(svc->importOffset(type,RDSvc::StartHours)); + hours_length_spin->setValue(svc->importLength(type,RDSvc::StartHours)); + minutes_offset_spin->setValue(svc->importOffset(type,RDSvc::StartMinutes)); + minutes_length_spin->setValue(svc->importLength(type,RDSvc::StartMinutes)); + seconds_offset_spin->setValue(svc->importOffset(type,RDSvc::StartSeconds)); + seconds_length_spin->setValue(svc->importLength(type,RDSvc::StartSeconds)); + len_hours_offset_spin->setValue(svc->importOffset(type,RDSvc::LengthHours)); + len_hours_length_spin->setValue(svc->importLength(type,RDSvc::LengthHours)); + len_minutes_offset_spin-> + setValue(svc->importOffset(type,RDSvc::LengthMinutes)); + len_minutes_length_spin-> + setValue(svc->importLength(type,RDSvc::LengthMinutes)); + len_seconds_offset_spin-> + setValue(svc->importOffset(type,RDSvc::LengthSeconds)); + len_seconds_length_spin-> + setValue(svc->importLength(type,RDSvc::LengthSeconds)); + data_offset_spin->setValue(svc->importOffset(type,RDSvc::ExtData)); + data_length_spin->setValue(svc->importLength(type,RDSvc::ExtData)); + event_id_offset_spin->setValue(svc->importOffset(type,RDSvc::ExtEventId)); + event_id_length_spin->setValue(svc->importLength(type,RDSvc::ExtEventId)); + annctype_offset_spin->setValue(svc->importOffset(type,RDSvc::ExtAnncType)); + annctype_length_spin->setValue(svc->importLength(type,RDSvc::ExtAnncType)); + import_changed=false; +} + + +void ImportFields::valueChangedData(int) +{ + import_changed=true; +} diff --git a/rdadmin/importfields.h b/rdadmin/importfields.h new file mode 100644 index 00000000..d0dbb836 --- /dev/null +++ b/rdadmin/importfields.h @@ -0,0 +1,74 @@ +// importfields.h +// +// Parser Parameters for RDAdmin. +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: importfields.h,v 1.2 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef IMPORTFIELDS_H +#define IMPORTFIELDS_H + +#include +#include +#include + +#include + +class ImportFields : public QWidget +{ + Q_OBJECT + public: + ImportFields(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + bool changed() const; + void readFields(RDSvc *svc,RDSvc::ImportSource type); + void setFields(RDSvc *svc,RDSvc::ImportSource type); + + private slots: + void valueChangedData(int); + + private: + bool import_changed; + QSpinBox *cart_offset_spin; + QSpinBox *cart_length_spin; + QSpinBox *title_offset_spin; + QSpinBox *title_length_spin; + QSpinBox *hours_offset_spin; + QSpinBox *hours_length_spin; + QSpinBox *minutes_offset_spin; + QSpinBox *minutes_length_spin; + QSpinBox *seconds_offset_spin; + QSpinBox *seconds_length_spin; + QSpinBox *len_hours_offset_spin; + QSpinBox *len_hours_length_spin; + QSpinBox *len_minutes_offset_spin; + QSpinBox *len_minutes_length_spin; + QSpinBox *len_seconds_offset_spin; + QSpinBox *len_seconds_length_spin; + QSpinBox *annctype_offset_spin; + QSpinBox *annctype_length_spin; + QSpinBox *data_offset_spin; + QSpinBox *data_length_spin; + QSpinBox *event_id_offset_spin; + QSpinBox *event_id_length_spin; +}; + + +#endif // IMPORTFIELDS_H diff --git a/rdadmin/info_banner1.xpm b/rdadmin/info_banner1.xpm new file mode 100644 index 00000000..d9d029e4 --- /dev/null +++ b/rdadmin/info_banner1.xpm @@ -0,0 +1,70 @@ +/* XPM */ +static char * info_banner1_xpm[] = { +"460 35 32 1", +" c #FFFFFFFFFFFF", +". c #E79DE79DE79D", +"X c #B6DAB6DAB6DA", +"o c #596559655965", +"O c #CF3CCF3CCF3C", +"+ c #EFBEEFBEEFBE", +"@ c #C71BC71BC71B", +"# c #9E799E799E79", +"$ c #000000000000", +"% c #082008200820", +"& c #F7DEF7DEF7DE", +"* c #AEBAAEBAAEBA", +"= c #104010401040", +"- c #618561856185", +"; c #A699A699A699", +": c #8E388A288E38", +"> c #30C230C230C2", +", c #28A228A228A2", +"< c #186118611861", +"1 c #DF7DDF7DDF7D", +"2 c #38E338E338E3", +"3 c #208120812081", +"4 c #69A669A669A6", +"5 c #492449244924", +"6 c #514451445144", +"7 c #71C671C671C6", +"8 c #BEFBBEFBBEFB", +"9 c #79E779E779E7", +"0 c #965896589658", +"q c #410341034103", +"w c #D75CD75CD75C", +"e c #861782078617", +" ", +" ", +" ", +" . ", +" Xo O+ O+ O+ Xo @ # ", +" @o$% &* # *=- # # &* @o$% ;=- ;=- &X #$: +; ", +" $% &>, +; .<;, +; +; &>, $% 1=;, 1=;, &23 .41 :& ", +" $% 56+ >, 7& 7X 8 >, >> 7& 7& 56+ $% 7* 8 7* 8 65+ >> >> O: >> ", +" $% 9; oo #0 7 oo 65 #0 #0 9; $% 4 4 9# 65 56 @5 65 ", +" $% +4- +4- +4- $% 1oq+ ", +" $% +7<0 +7<0 +7<0 $% 16<# ", +" $% #=5+ #=5+ #=5+ $% 9$o& ", +" +#5%wo<$<-X5%%o+ @2q $%wq%=-+ +#5%Oq%=o. +#5%wo<$<-X5%%6. 1q$$$$$$$$$$$$$$3w+o$$$$$$$$$$: +#5%Oq%=o. 1q$$$$$$$$$$$$$$3w @2q +#5%wo<$<-X5%%6. @2q 5$9 +098 &74. *o* $$0 ", +" O;$$41 @2$$w&9$3+ q$X $$9+.-$,& 1;$$e++7$<. O;$$9. Oq$$O&e$<. O$0 O$e $$ *%e& o<8 .0=<& *$2 e$$$o O;$$9. Oq$$O&e$<. O;$$41 @2$$w&9$3+ q$X 25 7,+ $$ o<8 .0=<& *$2 e$$$o *$2 e$$$o O;$$:++7$<. @;$$9+.4$$O O2$q $$9+.-$,& 1;$$e++7$<. #,8 .-$2&1;$$e++7$<. O$0 O$e $$ q$X O;$$9. Oq$$O&e$<. q$X #$5 @=$$$o 25 7,+ $$ ", +" $$ >$- 6$7 8@=, $$ 5$4 $$ -$o $$ q$6 4$o 6$. 6$1 $$ w$- 0$X @9 q$@ &8*4%$: $$ q$6 -$o $$ >$- 6$7 8@=, :$@ *$X $$ 0$X @9 q$@ &8*4%$: q$@ &8*4%$: $$ o$o $$ 5$- >$e $$ 5$4 $$ -$o 8$X 5$4 $$ -$o 6$. 6$1 $$ 8@=, $$ q$6 -$o 8@=, 2$O ..@7%$; :$@ *$X $$ ", +" $$ X$< @$< 0 e$0 $$ 8$< $$ O$= $$ @$= w$= =$ =$ $$ o$w ,$& =$& .3, $$ @$= w$= $$ X$< @$< 0 e$0 ,$& >$& $$ ,$& =$& .3, =$& .3, $$ O$= $$ 8$< X$3 $$ 8$< $$ O$= 2$& @$= $$ O$= =$ =$ $$ 0 e$0 $$ @$= w$= 0 e$0 %$& w=6 ,$& >$& $$ ww ", +" $$ +$$ &$$ #+ &==& $$ +$$ $$ $$ $$ &$% $% $$& $$+ $$ <$ $$& $$1 8$ $$ &$% $% $$ +$$ &$$ #+ &==& $$ %$& $$ $$& $$1 8$ $$1 8$ $$ &$$ $$ &$$ +$$ $$ +$$ $$ $$ $$& &$% $$ $$ $$& $$+ $$ #+ &==& $$ &$% $% #+ &==& =$w :q $$ %$& $$ == ", +" $$ $< $< +; :$7 $$ $= $$ &$, $$ &$> &$> <$8 <$* $$ $$& 3$8 ,$9 &< $$ &$> &$> $$ $< $< +; :$7 =$O =$@ $$ 3$8 ,$9 &< ,$9 &< $$ &$, $$ $< $< $$ $= $$ &$, =$8 &$2 $$ &$, <$8 <$* $$ +; :$7 $$ &$> &$> +; :$7 5$4 O- =$O =$@ $$ ;# ", +" $$ 1$o 1$4 +57 &<%. $$ .$6 $$ @$0 $$ X$# 8$# 7$6 4$,& $$ =$@ e$2 +w e$%8 87 $$ X$# 8$0 $$ 1$o 1$4 +57 &<%. o$o -$2 $$& e$2 +w e$%8 87 e$%8 87 $$ 8$0 $$ .$o w$7 $$ .$6 $$ @$0 7$2 @$X $$ @$0 7$6 4$,& $$ +57 &<%. $$ X$# 8$0 +57 &<%. @$$# :O o$o -$2 $$& ", +" $$ 9$O :=+ 4$8 #$5w $$ 0$O $$ 25 $$ +36 >5 &,$9&w$$>@ 17$$ 6$6 0 5$5w +9o &2$$608895& $$ +36 25 $$ 9$O :=+ 4$8 #$5w 1=$4.@$$>*1@4$$e* 5$5w +9o &2$$608895& &2$$608895& $$ 2q $$ 0$w o=+ $$ 0$O $$ 25 &2$61 @,: $$ 25 &,$9&w$$>@ 17$$ 4$8 #$5w $$ +36 25 4$8 #$5w *=$2e*@*9X 1=$4.@$$>*1@4$$e* ", +" $$$$$$$$$$$$$$3O:- 3q8 O3$$$$$$$$qw e$$ 1oe $$ ;5: .4e +o%%5843%34.$$ O$$# :; 0>%%28 :>=$=5* :$$ ;5: 1-e $$$$$$$$$$$$$$3O:- 3q8 15%%6@43%,7.%6*& 0>%%28 :>=$=<* :>=$=5* $$ 1oe $$$$$$$$$$$$$$3O O3$$$$$$$$qw e$$ 1oe &:,%%5w e$$ 1oe +o%%5843%34.$$ :- 3q8 :$$ ;5: 1-e :- 3q8 &#<%5e8 15%%6@43%,7.%6*& ", +" $$ $$ $$ #$$4O&&@o: $$ +7O $$ $$ ;3e& ", +" $$ $$ $$ O5=$%,4w $$ O-& $$ $$ :$@ :>58 ", +" $$ $$ $$ $$ w2& $$ $$ &%> .#7%% ", +" $$ $$ $$ $$ q; $$ $$ w$, @$+ ", +" $$ $$ $$ $$ %;XX $$ $$ %$8 1> ", +" $$1. $$1. $$O1 $$1. 2$$w $$&+ $$O1 ;$=:1 .;qw ", +" %oX %-8 =-@ %oX +#w $$41 =-@ 17,%$,e& ", +" 9. ", +" ", +" ", +" ", +" ", +"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"}; diff --git a/rdadmin/info_banner2.xpm b/rdadmin/info_banner2.xpm new file mode 100644 index 00000000..47f3dcbe --- /dev/null +++ b/rdadmin/info_banner2.xpm @@ -0,0 +1,71 @@ +/* XPM */ +static char * info_banner2_xpm[] = { +"460 35 33 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"@ c #C5C5C5", +"# c #A4A4A4", +"$ c #101010", +"% c #626262", +"& c #F6F6F6", +"* c #B4B4B4", +"= c #9C9C9C", +"- c #8B8B8B", +"; c #DEDEDE", +"> c #292929", +", c #393939", +"' c #202020", +") c #E6E6E6", +"! c #6A6A6A", +"~ c #737373", +"{ c #ACACAC", +"] c #BDBDBD", +"^ c #525252", +"/ c #4A4A4A", +"( c #EEEEEE", +"_ c #313131", +": c #7B7B7B", +"< c #080808", +"[ c #949494", +"} c #CDCDCD", +"| c #414141", +"1 c #5A5A5A", +"2 c #D5D5D5", +"3 c #181818", +"4 c #838383", +"............................................................................................................................................................................................................................................................................................................................................................................................................................................................................", +"............................................................................................................................................................................................................................................................................................................................................................................................................................................................................", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++@+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++@++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++@++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"+++++++++++++++++++++++++++#$%+++++++++++++++++++++++++++++++++++&*++++++++++++++++++++++++++++++++++++++++++++++=.-+++++++++++++++++++++&*++++++++++++++++++++++++++++++#$%+++++++++++++++++++++++++++++&*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&*++++++++++++++++++++++++++=.-++++++++#$%++++++++++++++++++++++++++++++++++++++++++++#$%++++++++++++++++++++++++++++++++++++++++=.-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++;$#>++++++++++++++++++++++++++++++++++&,'++++++++++++++++++++++++++++++++++++++++++++++)!;++++++++++++++++++++&,'+++++++++++++++++++++++++++++;$#>++++++++++++++++++++++++++++&,'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++&,'++++++++++++++++++++++++++)!;+++++++;$#>+++++++++++++++++++++++++++++++++++++++++++;$#>++++++++++++++++++++++++++++++++++++++++)!;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++~{+]++++++++++++++++++++++++++++++++++^/(+++++++++++++++++++++++__++++++++++++++++++++__+__+++++++++++++++++++^/(+++++++++++++++++++++++++++++~{+]++++++++++++++++++++++++++++^/(+++++++++++++++++++++++__++++++++++++++++++++++++++++++++^/(+++++++++++++++++++++++++__+__++++++~{+]+++++++++++++++++++++++++++++++++++++++++++~{+]+++++++++++++++++++++++++++++++++++++++__+__+++++++++++++++++++++++__+++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++!++++++++++++++++++++++++++++++++++++:=+++++++++++++++++++++++++^/++++++++++++++++++++^/+/^++++++++++++++++++:=+++++++++++++++++++++++++++++++!++++++++++++++++++++++++++++++:=+++++++++++++++++++++++++^/+++++++++++++++++++++++++++++++:=+++++++++++++++++++++++++++^/+/^++++++!++++++++++++++++++++++++++++++++++++++++++++++!++++++++++++++++++++++++++++++++++++++++++^/+/^+++++++++++++++++++++++^/+++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/...........,++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++;^<<_-++)[/<}|<$%(++(=/<}|<$1)++++++@,|+++++(=/<@|<$1)++++&~!)++{1{+++..[+++++++(=/<213.3%*/<<^)++++++++++++@,|++++++++;^<<_-++(=/<@|<$1)+++++;^<<_-++(=/<}/<<^*13.>-+++++++@,|+++++(=/<@|<$1)++++&~!)++{1{+++..[+++++++(=/<}|<$1)++++++@,|+++++(=/<213.3%*/<<^)++++++@,|++++++++;^<<_-++++++++(=/<213.3%*/<<1(++(=/<}|<$1)+++++#|<.':(+(=/<213.3%*/<<^)++;|........>}++*>...$|[+++(=/<@|<$1)++++&~!)++{1{+++..[++++++++++++++++++++++++++++++++++", +"+++++++++++++++++++++++++=>]+)%.,&2#..:()!.>&+;#..4((~.3)++++++|.*++++}#..-((~.3)+++,/+++~>(++++..++++++++}#..:)+}|..}&4.3)++++++++++++|.*++++++=>]+)%.,&}#..-((~.3)+++=>]+)%.,&@#..:()!..}+},.|+++++++|.*++++}#..-((~.3)+++,/+++~>(++++..++++++++;#..4((~.3)++++++|.*++++}#..:)+}|..}&4.3)++++++|.*++++++=>]+)%.,&++++++}#..!;+@,..2&:.'(+;#..4((~.3)+++13]+)[$3&}#..:)+}|..}&4.3)++}.[+++&..+++{_@+&;[$._(+}#..-((~.3)+++,/+++~>(++++..+++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++].*++++/.!++..++++/.~+++..++++%.1+++++]@$>++++++..++++1.1++-.@++{.*+++++..++++++++++..+++++|.^++!.1+++++++++++]@$>+++++].*++++/.!++..++++1.1++].*++++/.!++..++++/.%+++_.4+++++]@$>++++++..++++1.1++-.@++{.*+++++..++++++++++..++++%.1+++++]@$>++++++..+++++|.^++!.1+++++]@$>+++++].*++++/.!++++++++..+++++_.%++^.~+++..++++%.1++[.*++++@:+++..+++++|.^++!.1++^.)++++..+++')+++++;$.~+++..++++1.1++-.@++{.*+++++..+++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++,.&++++@.$++..++++].'+++..++++}.$+++++[+4.[+++++..++++}.$++>.&++_.&+++++..++++++++++..+++++@.$++2.$+++++++++++[+4.[++++,.&++++@.$++..++++}.$++,.&++++@.$++..++++].3+++*.'+++++[+4.[+++++..++++}.$++>.&++_.&+++++..++++++++++..++++}.$+++++[+4.[+++++..+++++@.$++2.$+++++[+4.[++++,.&++++@.$++++++++..+++++*.3++@.3+++..++++}.$++>.&+++++++++..+++++@.$++2.$++$.+++++..++(.&++++++-.'+++..++++}.$++>.&++_.&+++++..+++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++..&++++&.<++..++++(..+++..+++++..++++=(+&$$&++++..++++&..++..+++<.&+++++..++++++++++..+++++&.<+++.<++++++++++=(+&$$&+++..&++++&.<++..++++&..++..&++++&.<++..++++&..+++(..++++=(+&$$&++++..++++&..++..+++<.&+++++..++++++++++..+++++..++++=(+&$$&++++..+++++&.<+++.<++++=(+&$$&+++..&++++&.<++++++++..+++++(..++&..+++..+++++..++..&+++++++++..+++++&.<+++.<++..(++++..++(.-++++++)..+++..++++&..++..+++<.&+++++..+++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++$.]++++&.,++..+++++.$+++..++++&.>+++(#+++-.~++++..++++&.>++$.}++$.@+++++..++++++++++..+++++&._++&._+++++++++(#+++-.~+++$.]++++&.,++..++++&.>++$.]++++&.,++..+++++.3++++.3+++(#+++-.~++++..++++&.>++$.}++$.@+++++..++++++++++..++++&.>+++(#+++-.~++++..+++++&._++&._+++(#+++-.~+++$.]++++&.,++++++++..++++++.3+++.3+++..++++&.>++'.]+++++++++..+++++&._++&._++3.]++++..+++<.!#@+++&.$+++..++++&.>++$.}++$.@+++++..+++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++~.,++++@.*++..++++).^+++..++++@.[+(/~++++&3<)+++..++++].[++1.1++%.,+++++..&+++++++++..+++++*.=++].=+++++++(/~++++&3<)++~.,++++@.*++..++++].[++~.,++++@.*++..++++).1+++2.~+(/~++++&3<)+++..++++].[++1.1++%.,+++++..&+++++++++..++++@.[+(/~++++&3<)+++..+++++*.=++].=+(/~++++&3<)++~.,++++@.*++++++++..+++++;.1++;.!+++..++++@.[++4.,+++++(2++..+++++*.=++].=++~.|++++..+++~...}+++*.^+++..++++].[++1.1++%.,+++++..&++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++&,.^;+@>-+++..++++#.@+++..++++,/++!.]+++++=./2++..++++,|+++;$.!)@.._{;@!..4{++++++++..++++('^+++_/++++++++!.]+++++=./2+&,.^;+@>-+++..++++,|+++&,.^;+@>-+++..++++[.2+++1$(+!.]+++++=./2++..++++,|+++;$.!)@.._{;@!..4{++++++++..++++,/++!.]+++++=./2++..++++('^+++_/++!.]+++++=./2+&,.^;+@>-+++++++++..+++++:.}++-$(+++..++++,/++++/./2+(:1+++..++++('^+++_/+++&>.%)(:..++++]4{+++&>.]+++..++++,|+++;$.!)@.._{;@!..4{+++++++++++++++++++++++++++++++++", +"+++++++++++++++++++++++++&-><~)<^{&++++++++..+++#/-++)!4+++++++++-%+++++++'|]++&-><<~)<^{&+++++++4..++;14+++-%+++++++'|]++..+++#/-++)!4+++-%+++++++'|]++&-><~)<^{&+++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++..++++++++2_>@+++++..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++..+++++++:'[+++++++..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++..+++++&/:&++++++++..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++..+++++~]++++++++++..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++..+++++++++++++>>+++++++++++++++++++..++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++++>'+''++++..+++++++++++++++++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++++++++..+++++++++++++++++++++++++++++++++++++++..++++++++++++++++++++++..++++;[+++++++++++..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++..))+++++++++++%%+++++++++++++++++++..&(++++++++++++++++++++++++++++++++..;)++++++++++++++++++++++++++++++++++%1+1%++++..&(+++++++++++++++++++++++++++++++++++++++++++++++++..&(++++++++++++++++++++++++++++++++++++++++++++++++++++++++..;)+++++++++++++++++++++++++++++++++++++++++++..;)+++++++++++++++++++++++++++++++++++++..;)++++++++++++++++++++..2;++[++++++++++++..&(+++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++<1*+++++++++++++++++++++++++++++++++..!;++++++++++++++++++++++++++++++++<%]++++++++++++++++++++++++++++++++++++++++++++..!;+++++++++++++++++++++++++++++++++++++++++++++++++..!;++++++++++++++++++++++++++++++++++++++++++++++++++++++++<%]++++++++++++++++++++++++++++++++++++++++++++<1*++++++++++++++++++++++++++++++++++++++<%]+++++++++++++++++++++$1]+++#++++++++++++..!;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++:)+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++:)+++++++++++++++++++++++++++++++++++++++++++++++++++:)+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++})++++++++++++:)+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"}; diff --git a/rdadmin/info_dialog.cpp b/rdadmin/info_dialog.cpp new file mode 100644 index 00000000..581a361a --- /dev/null +++ b/rdadmin/info_dialog.cpp @@ -0,0 +1,192 @@ +// info_dialog.cpp +// +// Display System Information for Rivendell +// +// (C) Copyright 2002-2014 Fred Gleason +// +// $Id: info_dialog.cpp,v 1.17.8.1 2014/01/06 22:35:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +// +// This is a kludge, but apparently needed to get the bitmap data +// for the info banners, as Automake refuses to process the cwrap +// dependency correctly. +// +#include +#include + +InfoDialog::InfoDialog(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString str; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("System Information")); + + // + // Create Fonts + // + QFont title_font=QFont("Helvetica",24,QFont::DemiBold); + title_font.setPixelSize(22); + QFont slogan_font=QFont("Helvetica",14,QFont::Normal); + slogan_font.setPixelSize(14); + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont bold_font=QFont("Helvetica",10,QFont::Bold); + bold_font.setPixelSize(10); + QFont font=QFont("Helvetica",10,QFont::Normal); + font.setPixelSize(10); + + // + // Banners + // + QImage *image=new QImage(460,35,16); + image->loadFromData(xpm_info_banner1,strlen((const char *)xpm_info_banner1), + "XPM"); + QLabel *label=new QLabel(this,"top_banner"); + QPixmap pix(460,35); + pix.convertFromImage(*image); + label->setGeometry(0,0,460,35); + label->setPixmap(pix); + + image->loadFromData(xpm_info_banner2,strlen((const char *)xpm_info_banner2), + "XPM"); + label=new QLabel(this,"bottom_banner"); + pix.convertFromImage(*image); + label->setGeometry(0,sizeHint().height()-35,460,35); + label->setPixmap(pix); + + // + // Title + // + label=new QLabel(tr("Rivendell"),this,"title_label"); + label->setGeometry(10,41,120,36); + label->setFont(title_font); + + // + // Slogan + // + label=new QLabel(tr("A Radio Automation System"),this,"title_label"); + label->setGeometry(130,52,200,18); + label->setAlignment(AlignVCenter|AlignRight); + label->setFont(slogan_font); + + // + // Version + // + str=QString(tr("Version")); + label=new QLabel(QString().sprintf("%s %s",(const char *)str,VERSION), + this,"title_label"); + label->setGeometry(10,73,200,14); + label->setFont(font); + + str=QString(tr("Database Schema")); + label=new QLabel(QString().sprintf("%s %d",(const char *)str, + RD_VERSION_DATABASE), + this,"title_label"); + label->setGeometry(210,73,120,14); + label->setAlignment(AlignVCenter|AlignRight); + label->setFont(font); + + // + // Signature + // + str=QString(tr("Copyright 2002-2014")); + label=new QLabel(QString().sprintf("%s %s",(const char *)str, + PACKAGE_BUGREPORT),this,"title_label"); + label->setGeometry(10,87,sizeHint().width()-20,14); + label->setFont(font); + + // + // Disclaimer + // + label=new RDLabel(this,"title_label"); + label->setGeometry(10,104,sizeHint().width()-20,60); + label->setFont(font); + label->setText(tr("This program is free software, and comes with ABSOLUTELY NO WARRANTY,\nnot even the implied warranties of MERCHANTIBILITY or FITNESS FOR A\nPARTICULAR PURPOSE. Touch the \"View License\" button for details.")); + + // + // License Button + // + QPushButton *button=new QPushButton(this,"license_button"); + button->setGeometry(sizeHint().width()/2-45,174,80,50); + button->setFont(button_font); + button->setText(tr("View\n&License")); + connect(button,SIGNAL(clicked()),this,SLOT(viewLicenseData())); + + // + // Close Button + // + button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-90, + 80,50); + button->setFont(button_font); + button->setText(tr("&Close")); + button->setDefault(true); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +QSize InfoDialog::sizeHint() const +{ + return QSize(460,310); +} + + +QSizePolicy InfoDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void InfoDialog::viewLicenseData() +{ + RDLicense *lic=new RDLicense(this,"license_dialog"); + lic->exec(RDLicense::GplV2); + delete lic; +} + + +void InfoDialog::closeData() +{ + done(0); +} diff --git a/rdadmin/info_dialog.h b/rdadmin/info_dialog.h new file mode 100644 index 00000000..11074f61 --- /dev/null +++ b/rdadmin/info_dialog.h @@ -0,0 +1,58 @@ +// info_dialog.h +// +// Display System Information for Rivendell +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: info_dialog.h,v 1.7 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +#ifndef INFO_DIALOG_H +#define INFO_DIALOG_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// Globals +// +extern const unsigned char xpm_infobanner1[]; +extern const unsigned char xpm_infobanner2[]; + + + +class InfoDialog : public QDialog +{ + Q_OBJECT + public: + InfoDialog(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void viewLicenseData(); + void closeData(); +}; + + +#endif + diff --git a/rdadmin/list_aux_fields.cpp b/rdadmin/list_aux_fields.cpp new file mode 100644 index 00000000..c020dd40 --- /dev/null +++ b/rdadmin/list_aux_fields.cpp @@ -0,0 +1,243 @@ +// list_aux_fields.cpp +// +// List Auxiliary Fields for an RSS Feed +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: list_aux_fields.cpp,v 1.5 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +ListAuxFields::ListAuxFields(unsigned feed_id,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + list_feed_id=feed_id; + setCaption(tr("Auxiliary Metadata Fields")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Fields List Box + // + list_list_view=new QListView(this,"list_box"); + list_list_view-> + setGeometry(10,24,sizeHint().width()-20,sizeHint().height()-94); + QLabel *label= + new QLabel(list_list_view,tr("Auxiliary Metadata Fields"), + this,"list_list_view_label"); + label->setFont(bold_font); + label->setGeometry(14,5,sizeHint().width()-28,19); + list_list_view->setAllColumnsShowFocus(true); + list_list_view->setItemMargin(5); + list_list_view->addColumn(tr("Var Name")); + list_list_view->setColumnAlignment(0,Qt::AlignHCenter); + list_list_view->addColumn(tr("Caption")); + list_list_view->setColumnAlignment(1,Qt::AlignLeft); + connect(list_list_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + // + // Add Button + // + QPushButton *button=new QPushButton(this,"add_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Add")); + connect(button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + button=new QPushButton(this,"edit_button"); + button->setGeometry(100,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Edit")); + connect(button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + button=new QPushButton(this,"delete_button"); + button->setGeometry(190,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Delete")); + connect(button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Close Button + // + button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Close")); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); + + RefreshList(); +} + + +QSize ListAuxFields::sizeHint() const +{ + return QSize(400,250); +} + + +QSizePolicy ListAuxFields::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListAuxFields::addData() +{ + unsigned field_id=0; + + AddAuxField *af=new AddAuxField(list_feed_id,&field_id,this); + if(af->exec()==0) { + RDListViewItem *item=new RDListViewItem(list_list_view); + item->setId(field_id); + RefreshItem(item); + list_list_view->setSelected(item,true); + list_list_view->ensureItemVisible(item); + } + delete af; +} + + +void ListAuxFields::editData() +{ + RDListViewItem *item=(RDListViewItem *)list_list_view->selectedItem(); + if(item==NULL) { + return; + } + EditAuxField *ef=new EditAuxField(item->id(),this); + if(ef->exec()==0) { + RefreshItem(item); + } + delete ef; +} + + +void ListAuxFields::deleteData() +{ + QString sql; + RDSqlQuery *q; + + RDListViewItem *item=(RDListViewItem *)list_list_view->selectedItem(); + if(item==NULL) { + return; + } + + if(QMessageBox::question(this,tr("Warning"), + tr("This will delete all data associated with this field!\nAre you sure you want to continue?"),QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) { + return; + } + + sql=QString().sprintf("select KEY_NAME from FEEDS where ID=%d",list_feed_id); + q=new RDSqlQuery(sql); + if(q->first()) { + QString keyname=q->value(0).toString(); + delete q; + keyname.replace(" ","_"); + QString varname=item->text(0).mid(1,item->text(0).length()-2); + sql=QString().sprintf("alter table %s_FIELDS drop column %s", + (const char *)keyname,(const char *)varname); + q=new RDSqlQuery(sql); + } + delete q; + + sql=QString().sprintf("delete from AUX_METADATA where ID=%d",item->id()); + q=new RDSqlQuery(sql); + delete q; + delete item; +} + + +void ListAuxFields::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListAuxFields::closeData() +{ + done(0); +} + + +void ListAuxFields::RefreshList() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + list_list_view->clear(); + sql=QString().sprintf("select ID,VAR_NAME,CAPTION from AUX_METADATA \ + where FEED_ID=%u order by CAPTION",list_feed_id); + q=new RDSqlQuery(sql); + while(q->next()) { + item=new RDListViewItem(list_list_view); + item->setId(q->value(0).toInt()); + item->setText(0,q->value(1).toString()); + item->setText(1,q->value(2).toString()); + } + delete q; +} + + +void ListAuxFields::RefreshItem(RDListViewItem *item) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select VAR_NAME,CAPTION from AUX_METADATA \ + where ID=%d",item->id()); + q=new RDSqlQuery(sql); + if(q->first()) { + item->setText(0,q->value(0).toString()); + item->setText(1,q->value(1).toString()); + } + delete q; +} diff --git a/rdadmin/list_aux_fields.h b/rdadmin/list_aux_fields.h new file mode 100644 index 00000000..99f7fe53 --- /dev/null +++ b/rdadmin/list_aux_fields.h @@ -0,0 +1,58 @@ +// list_aux_fields.h +// +// List Auxiliary Fields for an RSS Feed +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: list_aux_fields.h,v 1.3 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_AUX_FIELDS_H +#define LIST_AUX_FIELDS_H + +#include +#include +#include +#include +#include + +#include + + +class ListAuxFields : public QDialog +{ + Q_OBJECT + public: + ListAuxFields(unsigned feed_id,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void closeData(); + + private: + void RefreshList(); + void RefreshItem(RDListViewItem *item); + QListView *list_list_view; + unsigned list_feed_id; +}; + + +#endif // LIST_AUX_FIELDS_H diff --git a/rdadmin/list_dropboxes.cpp b/rdadmin/list_dropboxes.cpp new file mode 100644 index 00000000..68ddda84 --- /dev/null +++ b/rdadmin/list_dropboxes.cpp @@ -0,0 +1,312 @@ +// list_dropboxes.cpp +// +// List Rivendell Dropboxes +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: list_dropboxes.cpp,v 1.7.8.1 2013/12/11 20:17:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +ListDropboxes::ListDropboxes(const QString &stationname, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + list_stationname=stationname; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + setCaption(QString().sprintf("Rivendell Dropbox Configurations on %s", + (const char *)stationname)); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont list_font=QFont("Helvetica",12,QFont::Normal); + list_font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Add Button + // + list_add_button=new QPushButton(this,"list_add_button"); + list_add_button->setFont(font); + list_add_button->setText(tr("&Add")); + connect(list_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + list_edit_button=new QPushButton(this,"list_edit_button"); + list_edit_button->setFont(font); + list_edit_button->setText(tr("&Edit")); + connect(list_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + list_delete_button=new QPushButton(this,"list_delete_button"); + list_delete_button->setFont(font); + list_delete_button->setText(tr("&Delete")); + connect(list_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Close Button + // + list_close_button=new QPushButton(this,"list_close_button"); + list_close_button->setDefault(true); + list_close_button->setFont(font); + list_close_button->setText(tr("&Close")); + connect(list_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Group List + // + list_dropboxes_view=new RDListView(this,"list_dropboxes_view"); + list_dropboxes_view->setFont(list_font); + list_dropboxes_view->setAllColumnsShowFocus(true); + list_dropboxes_view->addColumn(tr("Group")); + list_dropboxes_view->setColumnAlignment(0,Qt::AlignVCenter|Qt::AlignLeft); + list_dropboxes_view->addColumn(tr("Path")); + list_dropboxes_view->setColumnAlignment(1,Qt::AlignVCenter|Qt::AlignLeft); + list_dropboxes_view->addColumn(tr("Normalization Level")); + list_dropboxes_view->setColumnAlignment(2,Qt::AlignCenter); + list_dropboxes_view->addColumn(tr("Autotrim Level")); + list_dropboxes_view->setColumnAlignment(3,Qt::AlignCenter); + list_dropboxes_view->addColumn(tr("To Cart")); + list_dropboxes_view->setColumnAlignment(4,Qt::AlignCenter); + list_dropboxes_view->addColumn(tr("Use CartChunk ID")); + list_dropboxes_view->setColumnAlignment(5,Qt::AlignCenter); + list_dropboxes_view->addColumn(tr("Delete Cuts")); + list_dropboxes_view->setColumnAlignment(6,Qt::AlignCenter); + list_dropboxes_view->addColumn(tr("Metadata Pattern")); + list_dropboxes_view->setColumnAlignment(7,Qt::AlignCenter); + list_dropboxes_view->addColumn(tr("Fix Broken Formats")); + list_dropboxes_view->setColumnAlignment(8,Qt::AlignCenter); + list_dropboxes_view->addColumn(tr("User Defined")); + list_dropboxes_view->setColumnAlignment(9,Qt::AlignVCenter|Qt::AlignLeft); + connect(list_dropboxes_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + RefreshList(); +} + + +ListDropboxes::~ListDropboxes() +{ +} + + +QSize ListDropboxes::sizeHint() const +{ + return QSize(640,420); +} + + +QSizePolicy ListDropboxes::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListDropboxes::addData() +{ + RDDropbox *box=new RDDropbox(-1,list_stationname); + int id=box->id(); + delete box; + EditDropbox *edit_dropbox=new EditDropbox(id,this,"edit_dropbox"); + if(edit_dropbox->exec()<0) { + QString sql=QString().sprintf("delete from DROPBOXES where ID=%d",id); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + delete edit_dropbox; + return; + } + RDListViewItem *item=new RDListViewItem(list_dropboxes_view); + item->setId(id); + RefreshItem(item); + item->setSelected(true); + list_dropboxes_view->setCurrentItem(item); + list_dropboxes_view->ensureItemVisible(item); +} + + +void ListDropboxes::editData() +{ + RDListViewItem *item=(RDListViewItem *)list_dropboxes_view->selectedItem(); + if(item==NULL) { + return; + } + EditDropbox *edit_dropbox=new EditDropbox(item->id(),this,"edit_dropbox"); + edit_dropbox->exec(); + delete edit_dropbox; + RefreshItem(item); +} + + +void ListDropboxes::deleteData() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item=(RDListViewItem *)list_dropboxes_view->selectedItem(); + if(item==NULL) { + return; + } + sql=QString().sprintf("delete from DROPBOX_PATHS where DROPBOX_ID=%d", + item->id()); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("delete from DROPBOXES where ID=%d",item->id()); + q=new RDSqlQuery(sql); + delete q; + delete item; +} + + +void ListDropboxes::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListDropboxes::closeData() +{ + done(0); +} + + +void ListDropboxes::resizeEvent(QResizeEvent *e) +{ + list_add_button->setGeometry(size().width()-90,10,80,50); + list_edit_button->setGeometry(size().width()-90,70,80,50); + list_delete_button->setGeometry(size().width()-90,130,80,50); + list_close_button->setGeometry(size().width()-90,size().height()-60,80,50); + list_dropboxes_view-> + setGeometry(10,10,size().width()-120,size().height()-40); +} + + +void ListDropboxes::RefreshList() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + list_dropboxes_view->clear(); + sql=QString().sprintf("select DROPBOXES.ID,DROPBOXES.GROUP_NAME,\ + DROPBOXES.PATH,DROPBOXES.NORMALIZATION_LEVEL,\ + DROPBOXES.AUTOTRIM_LEVEL,\ + DROPBOXES.TO_CART,DROPBOXES.USE_CARTCHUNK_ID,\ + DROPBOXES.DELETE_CUTS,DROPBOXES.METADATA_PATTERN,\ + DROPBOXES.FIX_BROKEN_FORMATS,\ + DROPBOXES.SET_USER_DEFINED,GROUPS.COLOR \ + from DROPBOXES left join GROUPS on \ + DROPBOXES.GROUP_NAME=GROUPS.NAME \ + where DROPBOXES.STATION_NAME=\"%s\"", + (const char *)list_stationname); + q=new RDSqlQuery(sql); + while (q->next()) { + item=new RDListViewItem(list_dropboxes_view); + WriteItem(item,q); + } + delete q; +} + + +void ListDropboxes::RefreshItem(RDListViewItem *item) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select DROPBOXES.ID,DROPBOXES.GROUP_NAME,\ + DROPBOXES.PATH,DROPBOXES.NORMALIZATION_LEVEL,\ + DROPBOXES.AUTOTRIM_LEVEL,\ + DROPBOXES.TO_CART,DROPBOXES.USE_CARTCHUNK_ID,\ + DROPBOXES.DELETE_CUTS,DROPBOXES.METADATA_PATTERN,\ + DROPBOXES.FIX_BROKEN_FORMATS,\ + DROPBOXES.SET_USER_DEFINED,GROUPS.COLOR \ + from DROPBOXES left join GROUPS on \ + DROPBOXES.GROUP_NAME=GROUPS.NAME \ + where DROPBOXES.ID=%d",item->id()); + q=new RDSqlQuery(sql); + if(q->next()) { + WriteItem(item,q); + } + delete q; +} + + +void ListDropboxes::WriteItem(RDListViewItem *item,RDSqlQuery *q) +{ + item->setId(q->value(0).toInt()); + item->setText(0,q->value(1).toString()); + item->setTextColor(0,q->value(11).toString(),QFont::Bold); + item->setText(1,q->value(2).toString()); + if(q->value(3).toInt()<0) { + item->setText(2,QString().sprintf("%d",q->value(3).toInt()/100)); + } + else { + item->setText(2,tr("[off]")); + } + if(q->value(4).toInt()<0) { + item->setText(3,QString().sprintf("%d",q->value(4).toInt()/100)); + } + else { + item->setText(3,tr("[off]")); + } + if(q->value(5).toUInt()>0) { + item->setText(4,QString().sprintf("%06u",q->value(5).toUInt())); + } + else { + item->setText(4,tr("[auto]")); + } + item->setText(5,q->value(6).toString()); + item->setText(6,q->value(7).toString()); + if(q->value(8).toString().isEmpty()) { + item->setText(7,tr("[none]")); + } + else { + item->setText(7,q->value(8).toString()); + } + item->setText(8,q->value(9).toString()); + item->setText(9,q->value(10).toString()); +} diff --git a/rdadmin/list_dropboxes.h b/rdadmin/list_dropboxes.h new file mode 100644 index 00000000..5b64eeaf --- /dev/null +++ b/rdadmin/list_dropboxes.h @@ -0,0 +1,71 @@ +// list_dropboxes.h +// +// List Rivendell Dropbox Configurations +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: list_dropboxes.h,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_DROPBOXES_H +#define LIST_DROPBOXES_H + +#include +#include +#include +#include +#include + +#include +#include + + +class ListDropboxes : public QDialog +{ + Q_OBJECT + public: + ListDropboxes(const QString &stationname, + QWidget *parent=0,const char *name=0); + ~ListDropboxes(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void closeData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshList(); + void RefreshItem(RDListViewItem *item); + void WriteItem(RDListViewItem *item,RDSqlQuery *q); + RDListView *list_dropboxes_view; + QPushButton *list_add_button; + QPushButton *list_edit_button; + QPushButton *list_delete_button; + QPushButton *list_close_button; + QString list_stationname; +}; + + +#endif // LIST_DROPBOXES_H + + diff --git a/rdadmin/list_encoders.cpp b/rdadmin/list_encoders.cpp new file mode 100644 index 00000000..bbb035fa --- /dev/null +++ b/rdadmin/list_encoders.cpp @@ -0,0 +1,314 @@ +// list_encoders.cpp +// +// List a Rivendell Encoders +// +// (C) Copyright 2008 Fred Gleason +// +// $Id: list_encoders.cpp,v 1.5 2012/02/13 19:26:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +ListEncoders::ListEncoders(const QString &stationname, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + list_stationname=stationname; + setCaption(tr("RDAdmin - List Encoders")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Encoders List Box + // + list_list_view=new RDListView(this,"list_box"); + list_list_label=new QLabel(list_list_view,tr("Encoders on")+" "+stationname, + this,"list_list_label"); + list_list_label->setFont(bold_font); + list_list_view->setAllColumnsShowFocus(true); + list_list_view->setItemMargin(5); + list_list_view->addColumn(tr("Format Name")); + list_list_view->setColumnAlignment(0,Qt::AlignHCenter); + list_list_view->addColumn(tr("Extension")); + list_list_view->setColumnAlignment(1,Qt::AlignHCenter); + list_list_view->addColumn(tr("Valid Channels")); + list_list_view->setColumnAlignment(2,Qt::AlignLeft); + list_list_view->addColumn(tr("Valid Sample Rates")); + list_list_view->setColumnAlignment(3,Qt::AlignLeft); + list_list_view->addColumn(tr("Valid Bit Rates")); + list_list_view->setColumnAlignment(4,Qt::AlignLeft); + connect(list_list_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this,SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + // + // Add Button + // + list_add_button=new QPushButton(this,"list_add_button"); + list_add_button->setFont(bold_font); + list_add_button->setText(tr("&Add")); + connect(list_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + list_edit_button=new QPushButton(this,"edit_button"); + list_edit_button->setFont(bold_font); + list_edit_button->setText(tr("&Edit")); + connect(list_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + list_delete_button=new QPushButton(this,"delete_button"); + list_delete_button->setFont(bold_font); + list_delete_button->setText(tr("&Delete")); + connect(list_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Close Button + // + list_close_button=new QPushButton(this,"close_button"); + list_close_button->setDefault(true); + list_close_button->setFont(bold_font); + list_close_button->setText(tr("&Close")); + connect(list_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + RefreshList(); +} + + +QSize ListEncoders::sizeHint() const +{ + return QSize(600,375); +} + + +QSizePolicy ListEncoders::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListEncoders::resizeEvent(QResizeEvent *e) +{ + list_list_label->setGeometry(14,5,size().width()-20,19); + list_list_view->setGeometry(10,24,size().width()-20,size().height()-94); + list_add_button->setGeometry(10,size().height()-60,80,50); + list_edit_button->setGeometry(100,size().height()-60,80,50); + list_delete_button->setGeometry(190,size().height()-60,80,50); + list_close_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void ListEncoders::addData() +{ + QString name; + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + AddEncoder *ad=new AddEncoder(&name,list_stationname,this); + if(ad->exec()==0) { + sql=QString().sprintf("select ID from ENCODERS \ + where (NAME=\"%s\")&&(STATION_NAME=\"%s\")", + (const char *)RDEscapeString(name), + (const char *)RDEscapeString(list_stationname)); + q=new RDSqlQuery(sql); + if(q->first()) { + EditEncoder *ee=new EditEncoder(q->value(0).toInt()); + if(ee->exec()==0) { + RDListViewItem *item=new RDListViewItem(list_list_view); + item->setId(q->value(0).toInt()); + item->setText(0,name); + RefreshItem(item); + list_list_view->ensureItemVisible(item); + } + else { + sql=QString().sprintf("delete from ENCODERS \ + where (NAME=\"%s\")&&(STATION_NAME=\"%s\")", + (const char *)RDEscapeString(name), + (const char *)RDEscapeString(list_stationname)); + q1=new RDSqlQuery(sql); + delete q1; + } + delete ee; + } + delete q; + } + else { + sql=QString().sprintf("delete from ENCODERS \ + where (NAME=\"%s\")&&(STATION_NAME=\"%s\")", + (const char *)RDEscapeString(name), + (const char *)RDEscapeString(list_stationname)); + q1=new RDSqlQuery(sql); + delete q1; + } + delete ad; +} + + +void ListEncoders::editData() +{ + RDListViewItem *item; + + if((item=(RDListViewItem *)list_list_view->selectedItem())==NULL) { + return; + } + EditEncoder *ee=new EditEncoder(item->id()); + if(ee->exec()==0) { + RefreshItem(item); + } + delete ee; +} + + +void ListEncoders::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListEncoders::deleteData() +{ + QString sql; + RDSqlQuery *q; + QString feedlist; + + RDListViewItem *item; + + if((item=(RDListViewItem *)list_list_view->selectedItem())==NULL) { + return; + } + if(QMessageBox::question(this,tr("RDAdmin - Delete Encoder"), + tr("Are you sure you want to delete this encoder?"), + QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) { + return; + } + sql=QString().sprintf("select KEY_NAME,CHANNEL_TITLE from FEEDS \ + where UPLOAD_FORMAT=%d",item->id()); + q=new RDSqlQuery(sql); + while(q->next()) { + feedlist+=(q->value(0).toString()+" - "+q->value(1).toString()); + } + delete q; + if(!feedlist.isEmpty()) { + if(QMessageBox::warning(this,tr("RDAdmin - List Encoders"), + tr("This encoder is in use by the following RSS feeds:\n\n")+feedlist+tr("\n\nDo you still want to delete it?"),QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) { + return; + } + } + + sql=QString().sprintf("delete from ENCODERS where ID=%d",item->id()); + q=new RDSqlQuery(sql); + delete q; + delete item; +} + + +void ListEncoders::closeData() +{ + done(0); +} + + +void ListEncoders::RefreshList() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item=NULL; + + sql=QString().sprintf("select ID,NAME,COMMAND_LINE from ENCODERS\ + where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(list_stationname)); + q=new RDSqlQuery(sql); + while(q->next()) { + item=new RDListViewItem(list_list_view); + item->setId(q->value(0).toInt()); + item->setText(0,q->value(1).toString()); + RefreshItem(item); + } + delete q; +} + + +void ListEncoders::RefreshItem(RDListViewItem *item) +{ + QString sql; + RDSqlQuery *q; + sql=QString().sprintf("select DEFAULT_EXTENSION from ENCODERS \ + where ID=%d",item->id()); + q=new RDSqlQuery(sql); + if(q->first()) { + item->setText(1,q->value(0).toString()); + } + delete q; + item->setText(2,BuildList(item->id(),"CHANNELS")); + item->setText(3,BuildList(item->id(),"SAMPLERATES")); + item->setText(4,BuildList(item->id(),"BITRATES")); +} + + +QString ListEncoders::BuildList(int encoder_id,const QString ¶mname) +{ + QString sql; + RDSqlQuery *q; + QString ret; + + sql=QString().sprintf("select %s from ENCODER_%s where ENCODER_ID=%d\ + order by %s", + (const char *)paramname, + (const char *)paramname, + encoder_id, + (const char *)paramname); + q=new RDSqlQuery(sql); + while(q->next()) { + ret=ret+QString().sprintf("%d,",q->value(0).toInt()); + } + delete q; + if(ret.isEmpty()) { + ret=tr("[none]"); + } + else { + ret=ret.left(ret.length()-1); + } + + return ret; +} diff --git a/rdadmin/list_encoders.h b/rdadmin/list_encoders.h new file mode 100644 index 00000000..3a6d1859 --- /dev/null +++ b/rdadmin/list_encoders.h @@ -0,0 +1,68 @@ +// list_encoders.h +// +// List Rivendell Encoders +// +// (C) Copyright 2008 Fred Gleason +// +// $Id: list_encoders.h,v 1.4 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_ENCODERS_H +#define LIST_ENCODERS_H + +#include +#include +#include +#include +#include + +#include +#include + + +class ListEncoders : public QDialog +{ + Q_OBJECT + public: + ListEncoders(const QString &stationname,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + void resizeEvent(QResizeEvent *e); + + private slots: + void addData(); + void editData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void deleteData(); + void closeData(); + + private: + void RefreshList(); + void RefreshItem(RDListViewItem *item); + QString BuildList(int encoder_id,const QString ¶mname); + QString list_stationname; + QLabel *list_list_label; + RDListView *list_list_view; + QPushButton *list_add_button; + QPushButton *list_edit_button; + QPushButton *list_delete_button; + QPushButton *list_close_button; +}; + + +#endif // LIST_ENCODERS_H diff --git a/rdadmin/list_endpoints.cpp b/rdadmin/list_endpoints.cpp new file mode 100644 index 00000000..e8bd12d4 --- /dev/null +++ b/rdadmin/list_endpoints.cpp @@ -0,0 +1,738 @@ +// list_endpoints.cpp +// +// List a Rivendell Endpoints +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: list_endpoints.cpp,v 1.18.8.1 2013/11/17 04:27:05 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +ListEndpoints::ListEndpoints(RDMatrix *matrix,RDMatrix::Endpoint endpoint, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + QListViewItem *l; + QString str; + + list_matrix=matrix; + list_endpoint=endpoint; + switch(list_endpoint) { + case RDMatrix::Input: + list_size=list_matrix->inputs(); + list_table="INPUTS"; + setCaption(tr("List Inputs")); + break; + + case RDMatrix::Output: + list_size=list_matrix->outputs(); + list_table="OUTPUTS"; + setCaption(tr("List Outputs")); + break; + } + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Endpoints List Box + // + list_list_view=new QListView(this,"list_box"); + list_list_view-> + setGeometry(10,24,sizeHint().width()-20,sizeHint().height()-94); + QLabel *label= + new QLabel(list_list_view,list_table,this,"list_list_view_label"); + label->setFont(bold_font); + label->setGeometry(14,5,85,19); + list_list_view->setAllColumnsShowFocus(true); + list_list_view->setItemMargin(5); + switch(list_endpoint) { + case RDMatrix::Input: + list_list_view->addColumn(tr("INPUT")); + break; + + case RDMatrix::Output: + list_list_view->addColumn(tr("OUTPUT")); + break; + } + list_list_view->setColumnAlignment(0,Qt::AlignHCenter); + list_list_view->addColumn(tr("LABEL")); + list_list_view->setColumnAlignment(1,Qt::AlignLeft); + switch(matrix->type()) { + case RDMatrix::Unity4000: + list_readonly=false; + if(list_endpoint==RDMatrix::Input) { + list_list_view->addColumn(tr("SOURCE")); + list_list_view->setColumnAlignment(2,Qt::AlignHCenter); + list_list_view->addColumn(tr("MODE")); + list_list_view->setColumnAlignment(3,Qt::AlignHCenter); + } + break; + + case RDMatrix::LogitekVguest: + list_readonly=false; + list_list_view->addColumn(tr("ENGINE (Hex)")); + list_list_view->setColumnAlignment(2,Qt::AlignHCenter); + list_list_view->addColumn(tr("DEVICE (Hex)")); + list_list_view->setColumnAlignment(2,Qt::AlignHCenter); + break; + + case RDMatrix::StarGuideIII: + list_readonly=false; + if(list_endpoint==RDMatrix::Input) { + list_list_view->addColumn(tr("PROVIDER ID")); + list_list_view->setColumnAlignment(2,Qt::AlignHCenter); + list_list_view->addColumn(tr("SERVICE ID")); + list_list_view->setColumnAlignment(3,Qt::AlignHCenter); + list_list_view->addColumn(tr("MODE")); + list_list_view->setColumnAlignment(4,Qt::AlignHCenter); + } + break; + + case RDMatrix::LiveWireLwrpAudio: + list_readonly=true; + list_list_view->addColumn(tr("NODE")); + list_list_view->setColumnAlignment(2,Qt::AlignHCenter); + list_list_view->addColumn(tr("#")); + list_list_view->setColumnAlignment(3,Qt::AlignHCenter); + break; + + case RDMatrix::SasUsi: + list_readonly=true; + break; + + default: + list_readonly=false; + break; + } + if(!list_readonly) { + connect(list_list_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + } + + // + // Edit Button + // + QPushButton *button=new QPushButton(this,"edit_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Edit")); + connect(button,SIGNAL(clicked()),this,SLOT(editData())); + button->setDisabled(list_readonly); + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Values + // + switch(list_matrix->type()) { + case RDMatrix::Unity4000: + if(list_endpoint==RDMatrix::Input) { + sql=QString().sprintf("select NUMBER,NAME,FEED_NAME,CHANNEL_MODE\ + from %s where STATION_NAME=\"%s\" && \ + MATRIX=%d order by NUMBER", + (const char *)list_table, + (const char *)list_matrix->station(), + list_matrix->matrix()); + } + else { + sql=QString().sprintf("select NUMBER,NAME from %s\ + where STATION_NAME=\"%s\" && \ + MATRIX=%d order by NUMBER", + (const char *)list_table, + (const char *)list_matrix->station(), + list_matrix->matrix()); + } + break; + + case RDMatrix::LogitekVguest: + sql=QString().sprintf("select NUMBER,NAME,ENGINE_NUM,DEVICE_NUM\ + from %s where (STATION_NAME=\"%s\")&&\ + MATRIX=%d order by NUMBER", + (const char *)list_table, + (const char *)list_matrix->station(), + list_matrix->matrix()); + break; + + case RDMatrix::StarGuideIII: + if(list_endpoint==RDMatrix::Input) { + sql=QString().sprintf("select NUMBER,NAME,ENGINE_NUM,DEVICE_NUM,\ + CHANNEL_MODE\ + from %s where (STATION_NAME=\"%s\")&&\ + MATRIX=%d order by NUMBER", + (const char *)list_table, + (const char *)list_matrix->station(), + list_matrix->matrix()); + } + else { + sql=QString().sprintf("select NUMBER,NAME from %s\ + where STATION_NAME=\"%s\" && \ + MATRIX=%d order by NUMBER", + (const char *)list_table, + (const char *)list_matrix->station(), + list_matrix->matrix()); + } + break; + + case RDMatrix::LiveWireLwrpAudio: + sql=QString().sprintf("select NUMBER,NAME,NODE_HOSTNAME,NODE_SLOT \ + from %s where STATION_NAME=\"%s\" && \ + MATRIX=%d order by NUMBER", + (const char *)list_table, + (const char *)list_matrix->station(), + list_matrix->matrix()); + break; + + default: + sql=QString().sprintf("select NUMBER,NAME from %s\ + where STATION_NAME=\"%s\" && \ + MATRIX=%d order by NUMBER", + (const char *)list_table, + (const char *)list_matrix->station(), + list_matrix->matrix()); + break; + } + q=new RDSqlQuery(sql); + if(list_matrix->type()==RDMatrix::LiveWireLwrpAudio) { + while(q->next()) { + l=new QListViewItem(list_list_view); + l->setText(0,QString().sprintf("%05d",q->value(0).toInt())); + l->setText(1,q->value(1).toString()); + l->setText(2,q->value(2).toString()); + l->setText(3,QString().sprintf("%d",q->value(3).toInt())); + } + } + else { + q->first(); + for(int i=0;isetText(0,QString().sprintf("%03d",i+1)); + if(q->isValid()&&(q->value(0).toInt()==(i+1))){ + l->setText(1,q->value(1).toString()); + switch(list_matrix->type()) { + case RDMatrix::Unity4000: + if(list_endpoint==RDMatrix::Input) { + l->setText(2,q->value(2).toString()); + switch((RDMatrix::Mode)q->value(3).toInt()) { + case RDMatrix::Stereo: + l->setText(3,tr("Stereo")); + break; + + case RDMatrix::Left: + l->setText(3,tr("Left")); + break; + + case RDMatrix::Right: + l->setText(3,tr("Right")); + break; + } + } + break; + + case RDMatrix::LogitekVguest: + if(q->value(2).toInt()>=0) { + l->setText(2,QString().sprintf("%04X",q->value(2).toInt())); + } + else { + l->setText(2,""); + } + if(q->value(3).toInt()>=0) { + l->setText(3,QString().sprintf("%04X",q->value(3).toInt())); + } + else { + l->setText(3,""); + } + break; + + case RDMatrix::StarGuideIII: + if(list_endpoint==RDMatrix::Input) { + if(q->value(2).toInt()>=0) { + l->setText(2,q->value(2).toString()); + } + if(q->value(3).toInt()>=0) { + l->setText(3,q->value(3).toString()); + } + switch((RDMatrix::Mode)q->value(4).toInt()) { + case RDMatrix::Stereo: + l->setText(4,tr("Stereo")); + break; + + case RDMatrix::Left: + l->setText(4,tr("Left")); + break; + + case RDMatrix::Right: + l->setText(4,tr("Right")); + break; + } + } + break; + + default: + break; + } + q->next(); + } + else { + switch(list_endpoint) { + case RDMatrix::Input: + str=QString(tr("Input")); + l->setText(1,QString().sprintf("%s %03d",(const char *)str,i+1)); + switch(list_matrix->type()) { + case RDMatrix::Unity4000: + l->setText(3,tr("Stereo")); + break; + + case RDMatrix::StarGuideIII: + l->setText(4,tr("Stereo")); + break; + + default: + break; + } + break; + + case RDMatrix::Output: + str=QString(tr("Output")); + l->setText(1,QString().sprintf("%s %03d",(const char *)str,i+1)); + break; + } + } + } + } + delete q; +} + + +QSize ListEndpoints::sizeHint() const +{ + return QSize(400,250); +} + + +QSizePolicy ListEndpoints::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListEndpoints::editData() +{ + QListViewItem *item; + RDMatrix::Mode mode=RDMatrix::Stereo; + bool ok; + QString feedname; + int enginenum=-1; + int devicenum=-1; + + if((item=list_list_view->selectedItem())==NULL) { + return; + } + int pointnum=item->text(0).toInt()-1; + QString pointname=item->text(1); + switch(list_matrix->type()) { + case RDMatrix::Unity4000: + feedname=item->text(2); + if(item->text(3).lower()==QString(tr("stereo"))) { + mode=RDMatrix::Stereo; + } + if(item->text(3).lower()==QString(tr("left"))) { + mode=RDMatrix::Left; + } + if(item->text(3).lower()==QString(tr("right"))) { + mode=RDMatrix::Right; + } + break; + + case RDMatrix::LogitekVguest: + enginenum=item->text(2).toInt(&ok,16); + if(!ok) { + enginenum=-1; + } + devicenum=item->text(3).toInt(&ok,16); + if(!ok) { + devicenum=-1; + } + break; + + case RDMatrix::StarGuideIII: + enginenum=item->text(2).toInt(&ok); + if(!ok) { + enginenum=-1; + } + devicenum=item->text(3).toInt(&ok); + if(!ok) { + devicenum=-1; + } + if(item->text(4).lower()==QString(tr("stereo"))) { + mode=RDMatrix::Stereo; + } + if(item->text(4).lower()==QString(tr("left"))) { + mode=RDMatrix::Left; + } + if(item->text(4).lower()==QString(tr("right"))) { + mode=RDMatrix::Right; + } + break; + + default: + break; + } + EditEndpoint *edit=new EditEndpoint(list_matrix->type(),list_endpoint, + pointnum,&pointname,&feedname,&mode, + &enginenum,&devicenum,this); + if(edit->exec()==0) { + item->setText(1,pointname); + item->setText(2,feedname); + switch(list_matrix->type()) { + case RDMatrix::Unity4000: + if(list_endpoint==RDMatrix::Input) { + switch(mode) { + case RDMatrix::Stereo: + item->setText(3,tr("Stereo")); + break; + + case RDMatrix::Left: + item->setText(3,tr("Left")); + break; + + case RDMatrix::Right: + item->setText(3,tr("Right")); + break; + } + } + break; + + case RDMatrix::LogitekVguest: + if(enginenum>=0) { + item->setText(2,QString().sprintf("%04X",enginenum)); + } + else { + item->setText(2,""); + } + if(devicenum>=0) { + item->setText(3,QString().sprintf("%04X",devicenum)); + } + else { + item->setText(3,""); + } + break; + + case RDMatrix::StarGuideIII: + if(enginenum>=0) { + item->setText(2,QString().sprintf("%d",enginenum)); + } + else { + item->setText(2,""); + } + if(devicenum>=0) { + item->setText(3,QString().sprintf("%d",devicenum)); + } + else { + item->setText(3,""); + } + if(list_endpoint==RDMatrix::Input) { + switch(mode) { + case RDMatrix::Stereo: + item->setText(4,tr("Stereo")); + break; + + case RDMatrix::Left: + item->setText(4,tr("Left")); + break; + + case RDMatrix::Right: + item->setText(4,tr("Right")); + break; + } + } + break; + + default: + break; + } + } + delete edit; +} + + +void ListEndpoints::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListEndpoints::okData() +{ + if(!list_readonly) { + QListViewItem *item; + QString sql; + RDSqlQuery *q; + RDMatrix::Mode mode=RDMatrix::Stereo; + int enginenum; + int devicenum; + int modecol=3; + + if(list_matrix->type()==RDMatrix::StarGuideIII) { + modecol=4; + } + for(int i=0;ifindItem(QString().sprintf("%03d",i+1),0); + if(item->text(modecol).lower()==QString(tr("stereo"))) { + mode=RDMatrix::Stereo; + } + if(item->text(modecol).lower()==QString(tr("left"))) { + mode=RDMatrix::Left; + } + if(item->text(modecol).lower()==QString(tr("right"))) { + mode=RDMatrix::Right; + } + sql=QString().sprintf("select ID from %s where\ + STATION_NAME=\"%s\" && \ + MATRIX=%d && \ + NUMBER=%d", + (const char *)list_table, + (const char *)list_matrix->station(), + list_matrix->matrix(), + i+1); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + sql=QString().sprintf("insert into %s set STATION_NAME=\"%s\",\ + MATRIX=%d,\ + NUMBER=%d,\ + NAME=\"%s\"", + (const char *)list_table, + (const char *)list_matrix->station(), + list_matrix->matrix(), + i+1, + (const char *)item->text(1)); + switch(list_matrix->type()) { + case RDMatrix::Unity4000: + if(list_endpoint==RDMatrix::Input) { + sql+=QString().sprintf(",FEED_NAME=\"%s\",CHANNEL_MODE=%d", + (const char *)item->text(2), + mode); + } + break; + + case RDMatrix::LogitekVguest: + if(item->text(2).isEmpty()) { + sql+=",ENGINE_NUM=-1"; + } + else { + sql+=QString().sprintf(",ENGINE_NUM=%d", + item->text(2).toInt(NULL,16)); + } + if(item->text(3).isEmpty()) { + sql+=",DEVICE_NUM=-1"; + } + else { + sql+=QString().sprintf(",DEVICE_NUM=%d", + item->text(3).toInt(NULL,16)); + } + break; + + case RDMatrix::StarGuideIII: + if(item->text(2).isEmpty()) { + sql+=",ENGINE_NUM=-1"; + } + else { + sql+=QString().sprintf(",ENGINE_NUM=%d", + item->text(2).toInt()); + } + if(item->text(3).isEmpty()) { + sql+=",DEVICE_NUM=-1"; + } + else { + sql+=QString().sprintf(",DEVICE_NUM=%d", + item->text(3).toInt()); + } + if(list_endpoint==RDMatrix::Input) { + sql+=QString().sprintf(",CHANNEL_MODE=%d",mode); + } + break; + + default: + break; + } + q=new RDSqlQuery(sql); + delete q; + } + else { + delete q; + switch(list_matrix->type()) { + case RDMatrix::Unity4000: + if(list_endpoint==RDMatrix::Input) { + sql=QString().sprintf("update %s set NAME=\"%s\",\ + FEED_NAME=\"%s\",\ + CHANNEL_MODE=%d where\ + STATION_NAME=\"%s\" && \ + MATRIX=%d && \ + NUMBER=%d", + (const char *)list_table, + (const char *)item->text(1), + (const char *)item->text(2), + mode, + (const char *)list_matrix->station(), + list_matrix->matrix(), + i+1); + } + else { + sql=QString().sprintf("update %s set NAME=\"%s\" where \ + STATION_NAME=\"%s\" && \ + MATRIX=%d && \ + NUMBER=%d", + (const char *)list_table, + (const char *)item->text(1), + (const char *)list_matrix->station(), + list_matrix->matrix(), + i+1); + } + break; + + case RDMatrix::LogitekVguest: + if(item->text(2).isEmpty()) { + enginenum=-1; + } + else { + enginenum=item->text(2).toInt(NULL,16); + } + if(item->text(3).isEmpty()) { + devicenum=-1; + } + else { + devicenum=item->text(3).toInt(NULL,16); + } + sql=QString().sprintf("update %s set NAME=\"%s\",\ + ENGINE_NUM=%d,DEVICE_NUM=%d where\ + STATION_NAME=\"%s\" && \ + MATRIX=%d && \ + NUMBER=%d", + (const char *)list_table, + (const char *)item->text(1), + enginenum, + devicenum, + (const char *)list_matrix->station(), + list_matrix->matrix(), + i+1); + break; + + case RDMatrix::StarGuideIII: + if(list_endpoint==RDMatrix::Input) { + if(item->text(2).isEmpty()) { + enginenum=-1; + } + else { + enginenum=item->text(2).toInt(NULL); + } + if(item->text(3).isEmpty()) { + devicenum=-1; + } + else { + devicenum=item->text(3).toInt(NULL); + } + sql=QString().sprintf("update %s set NAME=\"%s\",\ + ENGINE_NUM=%d,DEVICE_NUM=%d,\ + CHANNEL_MODE=%d where\ + STATION_NAME=\"%s\" && \ + MATRIX=%d && \ + NUMBER=%d", + (const char *)list_table, + (const char *)item->text(1), + enginenum, + devicenum, + mode, + (const char *)list_matrix->station(), + list_matrix->matrix(), + i+1); + } + break; + + default: + sql=QString().sprintf("update %s set NAME=\"%s\" where\ + STATION_NAME=\"%s\" && \ + MATRIX=%d && \ + NUMBER=%d", + (const char *)list_table, + (const char *)item->text(1), + (const char *)list_matrix->station(), + list_matrix->matrix(), + i+1); + break; + } + q=new RDSqlQuery(sql); + delete q; + } + } + } + done(0); +} + + +void ListEndpoints::cancelData() +{ + done(1); +} diff --git a/rdadmin/list_endpoints.h b/rdadmin/list_endpoints.h new file mode 100644 index 00000000..141872ac --- /dev/null +++ b/rdadmin/list_endpoints.h @@ -0,0 +1,62 @@ +// list_endpoints.h +// +// List Rivendell Endpoints +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: list_endpoints.h,v 1.8 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_ENDPOINTS_H +#define LIST_ENDPOINTS_H + +#include +#include +#include +#include +#include + +#include +#include + + +class ListEndpoints : public QDialog +{ + Q_OBJECT + public: + ListEndpoints(RDMatrix *matrix,RDMatrix::Endpoint endpoint, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void editData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void okData(); + void cancelData(); + + private: + RDMatrix *list_matrix; + RDMatrix::Endpoint list_endpoint; + QListView *list_list_view; + int list_size; + QString list_table; + bool list_readonly; +}; + + +#endif + diff --git a/rdadmin/list_feeds.cpp b/rdadmin/list_feeds.cpp new file mode 100644 index 00000000..2c7edaaf --- /dev/null +++ b/rdadmin/list_feeds.cpp @@ -0,0 +1,359 @@ +// list_feeds.cpp +// +// List Rivendell Feeds +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: list_feeds.cpp,v 1.9 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +ListFeeds::ListFeeds(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + setCaption(tr("Rivendell Feed List")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont list_font=QFont("Helvetica",12,QFont::Normal); + list_font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Add Button + // + list_add_button=new QPushButton(this,"list_add_button"); + list_add_button->setFont(font); + list_add_button->setText(tr("&Add")); + connect(list_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + list_edit_button=new QPushButton(this,"list_edit_button"); + list_edit_button->setFont(font); + list_edit_button->setText(tr("&Edit")); + connect(list_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + list_delete_button=new QPushButton(this,"list_delete_button"); + list_delete_button->setFont(font); + list_delete_button->setText(tr("&Delete")); + connect(list_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Close Button + // + list_close_button=new QPushButton(this,"list_close_button"); + list_close_button->setDefault(true); + list_close_button->setFont(font); + list_close_button->setText(tr("&Close")); + connect(list_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Group List + // + list_feeds_view=new RDListView(this,"list_feeds_view"); + list_feeds_view->setFont(list_font); + list_feeds_view->setAllColumnsShowFocus(true); + list_feeds_view->addColumn(tr("Key")); + list_feeds_view->setColumnAlignment(0,AlignCenter); + list_feeds_view->addColumn(tr("Title")); + list_feeds_view->setColumnAlignment(1,AlignVCenter|AlignLeft); + list_feeds_view->addColumn(tr("AutoPost")); + list_feeds_view->setColumnAlignment(2,AlignVCenter|AlignLeft); + list_feeds_view->addColumn(tr("Keep Metadata")); + list_feeds_view->setColumnAlignment(3,AlignVCenter|AlignLeft); + list_feeds_view->addColumn(tr("Creation Date")); + list_feeds_view->setColumnAlignment(4,AlignCenter); + QLabel *list_box_label=new QLabel(list_feeds_view,tr("&Feeds:"), + this,"list_box_label"); + list_box_label->setFont(font); + list_box_label->setGeometry(14,11,85,19); + connect(list_feeds_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + RefreshList(); +} + + +ListFeeds::~ListFeeds() +{ +} + + +QSize ListFeeds::sizeHint() const +{ + return QSize(400,280); +} + + +QSizePolicy ListFeeds::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListFeeds::addData() +{ + QString feed; + unsigned id; + QString sql; + RDSqlQuery *q; + + AddFeed *add_feed=new AddFeed(&id,&feed,this,"add_feed"); + if(add_feed->exec()<0) { + delete add_feed; + return; + } + delete add_feed; + add_feed=NULL; + + EditFeed *edit_feed=new EditFeed(feed,this); + if(edit_feed->exec()<0) { + sql=QString().sprintf("delete from FEED_PERMS where KEY_NAME=\"%s\"", + (const char *)feed); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from FEEDS where KEY_NAME=\"%s\"", + (const char *)feed); + q=new RDSqlQuery(sql); + delete q; + RDDeleteFeedLog(feed); + feed.replace(" ","_"); + sql=QString().sprintf("drop table %s_FIELDS",(const char *)feed); + q=new RDSqlQuery(sql); + delete q; + delete edit_feed; + return; + } + delete edit_feed; + RDListViewItem *item=new RDListViewItem(list_feeds_view); + item->setId(id); + item->setText(0,feed); + RefreshItem(item); + item->setSelected(true); + list_feeds_view->setCurrentItem(item); + list_feeds_view->ensureItemVisible(item); +} + + +void ListFeeds::editData() +{ + RDListViewItem *item=(RDListViewItem *)list_feeds_view->selectedItem(); + if(item==NULL) { + return; + } + EditFeed *edit_feed=new EditFeed(item->text(0),this,"edit_feed"); + edit_feed->exec(); + delete edit_feed; + RefreshItem(item); +} + + +void ListFeeds::deleteData() +{ + RDListViewItem *item=(RDListViewItem *)list_feeds_view->selectedItem(); + if(item==NULL) { + return; + } + + QString sql; + RDSqlQuery *q; + QString warning; + QString str; + RDFeed *feed; + QString errs; + + QString feedname=item->text(0); + if(feedname.isEmpty()) { + return; + } + str=QString(tr("Are you sure you want to delete feed")); + warning+=QString().sprintf("%s %s?",(const char *)str, + (const char *)feedname); + switch(QMessageBox::warning(this,tr("Delete Feed"),warning, + QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + return; + + default: + break; + } + feed=new RDFeed(feedname); + + // + // Delete Casts + // + // First, Delete Remote Audio + // + RDPodcast *cast; + sql=QString().sprintf("select ID from PODCASTS where FEED_ID=%d",item->id()); + q=new RDSqlQuery(sql); + QProgressDialog *pd=new QProgressDialog(tr("Deleting Audio..."),tr("Cancel"), + q->size()+1,this); + pd->setCaption(tr("Deleting")); + pd->setProgress(0); + qApp->processEvents(); + sleep(1); + while(q->next()) { + pd->setProgress(pd->progress()+1); + qApp->processEvents(); + cast=new RDPodcast(q->value(0).toUInt()); + cast->removeAudio(feed,&errs,admin_config->logXloadDebugData()); + delete cast; + } + delete q; + + // + // Delete Cast Entries + // + sql=QString().sprintf("delete from PODCASTS where FEED_ID=%d",item->id()); + q=new RDSqlQuery(sql); + delete q; + + // + // Delete Feed + // + sql=QString().sprintf("delete from FEED_PERMS where KEY_NAME=\"%s\"", + (const char *)feedname); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from FEEDS where KEY_NAME=\"%s\"", + (const char *)feedname); + q=new RDSqlQuery(sql); + delete q; + RDDeleteFeedLog(feedname); + feedname.replace(" ","_"); + sql=QString().sprintf("drop table %s_FIELDS",(const char *)feedname); + q=new RDSqlQuery(sql); + delete q; + item->setSelected(false); + + pd->reset(); + + delete pd; + delete feed; + delete item; +} + + +void ListFeeds::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListFeeds::closeData() +{ + done(0); +} + + +void ListFeeds::resizeEvent(QResizeEvent *e) +{ + list_add_button->setGeometry(size().width()-90,30,80,50); + list_edit_button->setGeometry(size().width()-90,90,80,50); + list_delete_button->setGeometry(size().width()-90,150,80,50); + list_close_button->setGeometry(size().width()-90,size().height()-60,80,50); + list_feeds_view->setGeometry(10,30,size().width()-120,size().height()-40); +} + + +void ListFeeds::RefreshList() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + list_feeds_view->clear(); + q=new + RDSqlQuery("select ID,KEY_NAME,CHANNEL_TITLE,ENABLE_AUTOPOST,\ + KEEP_METADATA,ORIGIN_DATETIME from FEEDS"); + while (q->next()) { + item=new RDListViewItem(list_feeds_view); + item->setId(q->value(0).toInt()); + item->setText(0,q->value(1).toString()); + item->setText(1,q->value(2).toString()); + item->setText(2,q->value(3).toString()); + item->setText(3,q->value(4).toString()); + item->setText(4,q->value(5).toDateTime().toString("MM/dd/yyyy")); + } + delete q; +} + + +void ListFeeds::RefreshItem(RDListViewItem *item) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select KEY_NAME,CHANNEL_TITLE,ENABLE_AUTOPOST,\ + KEEP_METADATA,ORIGIN_DATETIME from FEEDS \ + where ID=%d",item->id()); + q=new RDSqlQuery(sql); + if(q->next()) { + item->setText(0,q->value(0).toString()); + item->setText(1,q->value(1).toString()); + item->setText(2,q->value(2).toString()); + item->setText(3,q->value(3).toString()); + item->setText(4,q->value(4).toDateTime().toString("MM/dd/yyyy")); + } + delete q; +} diff --git a/rdadmin/list_feeds.h b/rdadmin/list_feeds.h new file mode 100644 index 00000000..1e9e2bcf --- /dev/null +++ b/rdadmin/list_feeds.h @@ -0,0 +1,67 @@ +// list_feeds.h +// +// List Rivendell Feeds +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: list_feeds.h,v 1.3 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_FEEDS_H +#define LIST_FEEDS_H + +#include +#include +#include +#include +#include + +#include + + +class ListFeeds : public QDialog +{ + Q_OBJECT + public: + ListFeeds(QWidget *parent=0,const char *name=0); + ~ListFeeds(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void closeData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshList(); + void RefreshItem(RDListViewItem *item); + RDListView *list_feeds_view; + QPushButton *list_add_button; + QPushButton *list_edit_button; + QPushButton *list_delete_button; + QPushButton *list_close_button; +}; + + +#endif + + diff --git a/rdadmin/list_gpis.cpp b/rdadmin/list_gpis.cpp new file mode 100644 index 00000000..85be7eae --- /dev/null +++ b/rdadmin/list_gpis.cpp @@ -0,0 +1,358 @@ +// list_gpis.cpp +// +// List a Rivendell GPIOs +// +// (C) Copyright 2002-2008 Fred Gleason +// +// $Id: list_gpis.cpp,v 1.13.8.1 2013/11/17 04:27:05 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + + +ListGpis::ListGpis(RDMatrix *matrix,RDMatrix::GpioType type, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + QListViewItem *l; + QString list_label; + + list_matrix=matrix; + list_type=type; + switch(type) { + case RDMatrix::GpioInput: + list_tablename="GPIS"; + list_size=list_matrix->gpis(); + list_label=tr("GPI Lines"); + setCaption(tr("List GPIs")); + break; + + case RDMatrix::GpioOutput: + list_tablename="GPOS"; + list_size=list_matrix->gpos(); + list_label=tr("GPO Lines"); + setCaption(tr("List GPOs")); + break; + } + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Gpis List Box + // + list_list_view=new QListView(this,"list_box"); + list_list_label= + new QLabel(list_list_view,list_label,this,"list_view_label"); + list_list_label->setFont(bold_font); + list_list_view->setAllColumnsShowFocus(true); + list_list_view->setItemMargin(5); + connect(list_list_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + switch(list_type) { + case RDMatrix::GpioInput: + list_list_view->addColumn(tr("GPI")); + break; + + case RDMatrix::GpioOutput: + list_list_view->addColumn(tr("GPO")); + break; + } + list_list_view->setColumnAlignment(0,Qt::AlignHCenter); + + list_list_view->addColumn(tr("ON MACRO CART")); + list_list_view->setColumnAlignment(1,Qt::AlignHCenter); + + list_list_view->addColumn(tr("ON DESCRIPTION")); + list_list_view->setColumnAlignment(2,Qt::AlignLeft); + + list_list_view->addColumn(tr("OFF MACRO CART")); + list_list_view->setColumnAlignment(3,Qt::AlignHCenter); + + list_list_view->addColumn(tr("OFF DESCRIPTION")); + list_list_view->setColumnAlignment(4,Qt::AlignLeft); + + // + // Edit Button + // + list_edit_button=new QPushButton(this,"list_edit_button"); + list_edit_button->setFont(bold_font); + list_edit_button->setText(tr("&Edit")); + connect(list_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Ok Button + // + list_ok_button=new QPushButton(this,"list_ok_button"); + list_ok_button->setDefault(true); + list_ok_button->setFont(bold_font); + list_ok_button->setText(tr("&OK")); + connect(list_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + list_cancel_button=new QPushButton(this,"list_cancel_button"); + list_cancel_button->setFont(bold_font); + list_cancel_button->setText(tr("&Cancel")); + connect(list_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Values + // + sql=QString().sprintf("select %s.NUMBER,%s.MACRO_CART,%s.OFF_MACRO_CART,\ + CART.TITLE \ + from %s left join CART \ + on %s.MACRO_CART=CART.NUMBER \ + where (%s.STATION_NAME=\"%s\")&&(%s.MATRIX=%d)\ + order by %s.NUMBER", + (const char *)list_tablename, + (const char *)list_tablename, + (const char *)list_tablename, + (const char *)list_tablename, + (const char *)list_tablename, + (const char *)list_tablename, + (const char *)list_matrix->station(), + (const char *)list_tablename, + list_matrix->matrix(), + (const char *)list_tablename); + q=new RDSqlQuery(sql); + if(list_matrix->type()==RDMatrix::LiveWireLwrpAudio) { + while(q->next()) { + l=new QListViewItem(list_list_view); + l->setText(0,QString().sprintf("%05d",q->value(0).toInt())); + if(q->value(1).toInt()>0) { + l->setText(1,QString().sprintf("%06d",q->value(1).toInt())); + } + if(q->value(2).toInt()>0) { + l->setText(3,QString().sprintf("%06d",q->value(2).toInt())); + } + if(q->value(1).toInt()>0) { + l->setText(2,q->value(3).toString()); + } + else { + l->setText(2,tr("[unassigned]")); + } + } + } + else { + q->first(); + for(int i=0;isetText(0,QString().sprintf("%03d",i+1)); + if(q->isValid()&&(q->value(0).toInt()==(i+1))){ + if(q->value(1).toInt()>0) { + l->setText(1,QString().sprintf("%06d",q->value(1).toInt())); + } + if(q->value(2).toInt()>0) { + l->setText(3,QString().sprintf("%06d",q->value(2).toInt())); + } + if(q->value(1).toInt()>0) { + l->setText(2,q->value(3).toString()); + } + else { + l->setText(2,tr("[unassigned]")); + } + q->next(); + } + else { + l->setText(2,tr("[unassigned]")); + } + } + } + delete q; + + // + // Now go back and get the descriptions for the 'Off' carts + // + l=list_list_view->firstChild(); + while(l!=NULL) { + if(l->text(0).toInt()>0) { + if(l->text(3).toInt()>0) { + RDCart *cart=new RDCart(l->text(3).toUInt()); + l->setText(4,cart->title()); + delete cart; + } + else { + l->setText(4,tr("[unassigned]")); + } + } + l=l->nextSibling(); + } + +} + + +QSize ListGpis::sizeHint() const +{ + return QSize(600,400); +} + + +QSizePolicy ListGpis::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListGpis::editData() +{ + int oncart=-1; + int offcart=-1; + + QString ondesc; + QString offdesc; + QListViewItem *item=list_list_view->selectedItem(); + if(item==NULL) { + return; + } + int gpi=item->text(0).toInt(); + if(!item->text(1).isEmpty()) { + oncart=item->text(1).toInt(); + } + if(!item->text(3).isEmpty()) { + offcart=item->text(3).toInt(); + } + EditGpi *gpi_box= + new EditGpi(gpi,&oncart,&ondesc,&offcart,&offdesc,this,"gpi_box"); + if(gpi_box->exec()==0) { + if(oncart>0) { + item->setText(1,QString().sprintf("%06d",oncart)); + item->setText(2,ondesc); + } + else { + item->setText(1,""); + item->setText(2,tr("[unassigned]")); + } + if(offcart>0) { + item->setText(3,QString().sprintf("%06d",offcart)); + item->setText(4,offdesc); + } + else { + item->setText(3,""); + item->setText(4,tr("[unassigned]")); + } + } + delete gpi_box; +} + + +void ListGpis::doubleClickedData(QListViewItem *,const QPoint &,int) +{ + editData(); +} + + +void ListGpis::okData() +{ + QString sql; + RDSqlQuery *q; + RDMacro rml; + + sql=QString().sprintf("delete from %s where (STATION_NAME=\"%s\")&&\ + MATRIX=%d", + (const char *)list_tablename, + (const char *)list_matrix->station(), + list_matrix->matrix()); + q=new RDSqlQuery(sql); + delete q; + RDStation *station=new RDStation(list_matrix->station()); + rml.setCommand(RDMacro::GI); + rml.setRole(RDMacro::Cmd); + rml.setArgQuantity(5); + rml.setArg(0,list_matrix->matrix()); + switch(list_type) { + case RDMatrix::GpioInput: + rml.setArg(1,"I"); + break; + + case RDMatrix::GpioOutput: + rml.setArg(1,"O"); + break; + } + rml.setAddress(station->address()); + rml.setEchoRequested(false); + delete station; + + QListViewItem *item=list_list_view->firstChild(); + while(item!=NULL) { + sql=QString().sprintf("insert into %s set STATION_NAME=\"%s\",\ + MATRIX=%d,NUMBER=%d,MACRO_CART=%d,OFF_MACRO_CART=%d", + (const char *)list_tablename, + (const char *)list_matrix->station(), + list_matrix->matrix(), + item->text(0).toInt(), + item->text(1).toInt(), + item->text(3).toInt()); + q=new RDSqlQuery(sql); + delete q; + rml.setArg(2,item->text(0).toInt()); + rml.setArg(3,true); + rml.setArg(4,item->text(1).toInt()); + rdripc->sendRml(&rml); + rml.setArg(3,false); + rml.setArg(4,item->text(3).toInt()); + rdripc->sendRml(&rml); + item=item->nextSibling(); + } + done(0); +} + + +void ListGpis::cancelData() +{ + done(1); +} + + +void ListGpis::resizeEvent(QResizeEvent *e) +{ + list_list_view->setGeometry(10,24,size().width()-20,size().height()-94); + list_list_label->setGeometry(14,5,85,19); + list_edit_button->setGeometry(10,size().height()-60,80,50); + list_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + list_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} diff --git a/rdadmin/list_gpis.h b/rdadmin/list_gpis.h new file mode 100644 index 00000000..5249d9d6 --- /dev/null +++ b/rdadmin/list_gpis.h @@ -0,0 +1,68 @@ +// list_gpis.h +// +// List Rivendell GPIs +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_gpis.h,v 1.7 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_GPIS_H +#define LIST_GPIS_H + +#include +#include +#include +#include +#include + +#include +#include + + +class ListGpis : public QDialog +{ + Q_OBJECT + public: + ListGpis(RDMatrix *matrix,RDMatrix::GpioType type, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void editData(); + void doubleClickedData(QListViewItem *,const QPoint &,int); + void okData(); + void cancelData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + RDMatrix *list_matrix; + RDMatrix::GpioType list_type; + QString list_tablename; + QListView *list_list_view; + QLabel *list_list_label; + int list_size; + QPushButton *list_edit_button; + QPushButton *list_ok_button; + QPushButton *list_cancel_button; +}; + + +#endif + diff --git a/rdadmin/list_groups.cpp b/rdadmin/list_groups.cpp new file mode 100644 index 00000000..39c211b4 --- /dev/null +++ b/rdadmin/list_groups.cpp @@ -0,0 +1,496 @@ +// list_groups.cpp +// +// List Rivendell Groups +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: list_groups.cpp,v 1.27.6.1 2013/11/13 23:36:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + + +ListGroups::ListGroups(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + setCaption(tr("Rivendell Group List")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont list_font=QFont("Helvetica",12,QFont::Normal); + list_font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Add Button + // + list_add_button=new QPushButton(this,"list_add_button"); + list_add_button->setFont(font); + list_add_button->setText(tr("&Add")); + connect(list_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + list_edit_button=new QPushButton(this,"list_edit_button"); + list_edit_button->setFont(font); + list_edit_button->setText(tr("&Edit")); + connect(list_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Rename Button + // + list_rename_button=new QPushButton(this,"list_rename_button"); + list_rename_button->setFont(font); + list_rename_button->setText(tr("&Rename")); + connect(list_rename_button,SIGNAL(clicked()),this,SLOT(renameData())); + + // + // Delete Button + // + list_delete_button=new QPushButton(this,"list_delete_button"); + list_delete_button->setFont(font); + list_delete_button->setText(tr("&Delete")); + connect(list_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Report Button + // + list_report_button=new QPushButton(this,"list_report_button"); + list_report_button->setFont(font); + list_report_button->setText(tr("Generate\n&Report")); + connect(list_report_button,SIGNAL(clicked()),this,SLOT(reportData())); + + // + // Close Button + // + list_close_button=new QPushButton(this,"list_close_button"); + list_close_button->setDefault(true); + list_close_button->setFont(font); + list_close_button->setText(tr("&Close")); + connect(list_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Group List + // + list_groups_view=new RDListView(this,"list_groups_view"); + list_groups_view->setFont(list_font); + list_groups_view->setAllColumnsShowFocus(true); + list_groups_view->addColumn(tr("NAME")); + list_groups_view->addColumn(tr("DESCRIPTION")); + list_groups_view->addColumn(tr("START CART")); + list_groups_view->setColumnAlignment(2,Qt::AlignCenter); + list_groups_view->addColumn(tr("END CART")); + list_groups_view->setColumnAlignment(3,Qt::AlignHCenter); + list_groups_view->addColumn(tr("ENFORCE RANGE")); + list_groups_view->setColumnAlignment(4,Qt::AlignHCenter); + list_groups_view->addColumn(tr("DEFAULT TYPE")); + list_groups_view->setColumnAlignment(5,Qt::AlignHCenter); + list_groups_view->addColumn(tr("TRAFFIC REPORT")); + list_groups_view->setColumnAlignment(6,Qt::AlignHCenter); + list_groups_view->addColumn(tr("MUSIC REPORT")); + list_groups_view->setColumnAlignment(7,Qt::AlignHCenter); + list_groups_view->addColumn(tr("NOW & NEXT")); + list_groups_view->setColumnAlignment(8,Qt::AlignHCenter); + QLabel *list_box_label=new QLabel(list_groups_view,tr("&Groups:"), + this,"list_box_label"); + list_box_label->setFont(font); + list_box_label->setGeometry(14,11,85,19); + connect(list_groups_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + RefreshList(); +} + + +ListGroups::~ListGroups() +{ +} + + +QSize ListGroups::sizeHint() const +{ + return QSize(640,480); +} + + +QSizePolicy ListGroups::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListGroups::addData() +{ + QString group; + + AddGroup *add_group=new AddGroup(&group,this,"add_group"); + if(add_group->exec()<0) { + delete add_group; + return; + } + delete add_group; + add_group=NULL; + RDListViewItem *item=new RDListViewItem(list_groups_view); + item->setText(0,group); + RefreshItem(item); + item->setSelected(true); + list_groups_view->setCurrentItem(item); + list_groups_view->ensureItemVisible(item); +} + + +void ListGroups::editData() +{ + RDListViewItem *item=(RDListViewItem *)list_groups_view->selectedItem(); + if(item==NULL) { + return; + } + EditGroup *edit_group=new EditGroup(item->text(0),this,"edit_group"); + edit_group->exec(); + delete edit_group; + edit_group=NULL; + RefreshItem(item); +} + + +void ListGroups::renameData() +{ + RDListViewItem *item=(RDListViewItem *)list_groups_view->selectedItem(); + if(item==NULL) { + return; + } + + QString groupname=item->text(0); + RenameGroup *rename_group=new RenameGroup(groupname,this,"rename_group"); + rename_group->exec(); + delete rename_group; + rename_group=NULL; + RefreshList(); +} + + +void ListGroups::deleteData() +{ + RDListViewItem *item=(RDListViewItem *)list_groups_view->selectedItem(); + if(item==NULL) { + return; + } + + QString sql; + RDSqlQuery *q; + QString warning; + int carts=0; + QString str; + + QString groupname=item->text(0); + if(groupname.isEmpty()) { + return; + } + sql=QString().sprintf("select NUMBER from CART where GROUP_NAME=\"%s\"", + (const char *)groupname); + q=new RDSqlQuery(sql); + if((carts=q->size())>0) { + str=QString(tr("member carts will be deleted along with group")); + warning=QString(). + sprintf("%d %s %s!\n", + carts,(const char *)str,(const char *)groupname); + } + str=QString(tr("Are you sure you want to delete group")); + warning+=QString().sprintf("%s %s?",(const char *)str, + (const char *)groupname); + switch(QMessageBox::warning(this,tr("Delete Group"),warning, + QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + delete q; + return; + + default: + break; + } + + // + // Delete Member Carts + // + RDCart *cart; + while(q->next()) { + cart=new RDCart(q->value(0).toUInt()); + cart->remove(admin_station,admin_user,admin_config); + delete cart; + } + delete q; + + // + // Delete Member Audio Perms + // + sql=QString().sprintf("delete from AUDIO_PERMS where GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(groupname)); + q=new RDSqlQuery(sql); + delete q; + + // + // Delete Member User Perms + // + sql=QString().sprintf("delete from USER_PERMS where GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(groupname)); + q=new RDSqlQuery(sql); + delete q; + + // + // Delete Replicator Map Records + // + sql=QString().sprintf("delete from REPLICATOR_MAP where GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(groupname)); + q=new RDSqlQuery(sql); + delete q; + + // + // Delete from Group List + // + sql=QString().sprintf("delete from GROUPS where NAME=\"%s\"", + (const char *)RDEscapeString(groupname)); + q=new RDSqlQuery(sql); + delete q; + item->setSelected(false); + delete item; +} + + +void ListGroups::reportData() +{ + QString sql; + RDSqlQuery *q; + QString report; + + // + // Generate Header + // + report=" Rivendell Group Report\n"; + report+=QString().sprintf("Generated: %s\n", + (const char *)QDateTime(QDate::currentDate(), + QTime::currentTime()). + toString("MM/dd/yyyy - hh:mm:ss")); + report+="\n"; + report+="-Name----- -Description-------------------------------- -Cart Range---- Enf DefType Mus Tfc N&N\n"; + + // + // Generate Body + // + sql="select NAME,DESCRIPTION,DEFAULT_LOW_CART,DEFAULT_HIGH_CART,\ + ENFORCE_CART_RANGE,DEFAULT_CART_TYPE,REPORT_MUS,REPORT_TFC,\ + ENABLE_NOW_NEXT from GROUPS order by NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + // + // Group Name + // + report+=QString().sprintf("%-10s ",(const char *)q->value(0).toString()); + + // + // Group Description + // + report+=QString().sprintf("%-44s ",(const char *)q->value(1).toString()); + + // + // Cart Range + // + if((q->value(2).isNull())||(q->value(2).toUInt()==0)) { + report+=" [none] "; + } + else { + report+=QString().sprintf("%06u - %06u ",q->value(2).toUInt(), + q->value(3).toUInt()); + } + + // + // Enforce Range + // + report+=QString().sprintf(" %s ",(const char *)q->value(4).toString()); + + // + // Default Cart Type + // + switch((RDCart::Type)q->value(5).toInt()) { + case RDCart::Audio: + report+="Audio "; + break; + + case RDCart::Macro: + report+="Macro "; + break; + + default: + report+="Unknown "; + break; + } + + // + // Music Reports + // + report+=QString().sprintf(" %s ",(const char *)q->value(6).toString()); + + // + // Traffic Reports + // + report+=QString().sprintf(" %s ",(const char *)q->value(7).toString()); + + // + // Now & Next + // + report+=QString().sprintf(" %s",(const char *)q->value(8).toString()); + + // + // End of Line + // + report+="\n"; + } + delete q; + + // + // Display Report + // + RDTextFile(report); +} + + +void ListGroups::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListGroups::closeData() +{ + done(0); +} + + +void ListGroups::resizeEvent(QResizeEvent *e) +{ + list_add_button->setGeometry(size().width()-90,30,80,50); + list_edit_button->setGeometry(size().width()-90,90,80,50); + list_rename_button->setGeometry(size().width()-90,150,80,50); + list_delete_button->setGeometry(size().width()-90,210,80,50); + list_report_button->setGeometry(size().width()-90,300,80,50); + list_close_button->setGeometry(size().width()-90,size().height()-60,80,50); + list_groups_view->setGeometry(10,30,size().width()-120,size().height()-40); +} + + +void ListGroups::RefreshList() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + list_groups_view->clear(); + q=new RDSqlQuery("select NAME,DESCRIPTION,DEFAULT_LOW_CART,DEFAULT_HIGH_CART,\ + ENFORCE_CART_RANGE,DEFAULT_CART_TYPE,REPORT_TFC,REPORT_MUS,\ + ENABLE_NOW_NEXT,COLOR from GROUPS", + 0); + while (q->next()) { + item=new RDListViewItem(list_groups_view); + WriteItem(item,q); + } + delete q; +} + + +void ListGroups::RefreshItem(RDListViewItem *item) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select NAME,DESCRIPTION,DEFAULT_LOW_CART,\ + DEFAULT_HIGH_CART,ENFORCE_CART_RANGE,\ + DEFAULT_CART_TYPE,REPORT_TFC,REPORT_MUS,\ + ENABLE_NOW_NEXT,COLOR from GROUPS where NAME=\"%s\"", + (const char *)item->text(0)); + q=new RDSqlQuery(sql); + if(q->next()) { + WriteItem(item,q); + } + delete q; +} + + +void ListGroups::WriteItem(RDListViewItem *item,RDSqlQuery *q) +{ + item->setText(0,q->value(0).toString()); + item->setTextColor(0,q->value(9).toString(),QFont::Bold); + item->setText(1,q->value(1).toString()); + if(q->value(2).toUInt()>0) { + item->setText(2,QString().sprintf("%06u",q->value(2).toUInt())); + item->setText(3,QString().sprintf("%06u",q->value(3).toUInt())); + } + else { + item->setText(2,"[none]"); + item->setText(3,"[none]"); + } + item->setText(4,q->value(4).toString()); + switch((RDCart::Type)q->value(5).toUInt()) { + case RDCart::Audio: + item->setText(5,"Audio"); + break; + + case RDCart::Macro: + item->setText(5,"Macro"); + break; + + default: + item->setText(5,"[none]"); + break; + } + item->setText(6,q->value(6).toString()); + item->setText(7,q->value(7).toString()); + item->setText(8,q->value(8).toString()); +} diff --git a/rdadmin/list_groups.h b/rdadmin/list_groups.h new file mode 100644 index 00000000..fd09fd2f --- /dev/null +++ b/rdadmin/list_groups.h @@ -0,0 +1,73 @@ +// list_groups.h +// +// List Rivendell Groups +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: list_groups.h,v 1.13 2010/07/29 19:32:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_GROUPS_H +#define LIST_GROUPS_H + +#include +#include +#include +#include +#include + +#include +#include + + +class ListGroups : public QDialog +{ + Q_OBJECT + public: + ListGroups(QWidget *parent=0,const char *name=0); + ~ListGroups(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void renameData(); + void deleteData(); + void reportData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void closeData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshList(); + void RefreshItem(RDListViewItem *item); + void WriteItem(RDListViewItem *item,RDSqlQuery *q); + RDListView *list_groups_view; + QPushButton *list_add_button; + QPushButton *list_edit_button; + QPushButton *list_rename_button; + QPushButton *list_delete_button; + QPushButton *list_report_button; + QPushButton *list_close_button; +}; + + +#endif + + diff --git a/rdadmin/list_hostvars.cpp b/rdadmin/list_hostvars.cpp new file mode 100644 index 00000000..8d0ae3c2 --- /dev/null +++ b/rdadmin/list_hostvars.cpp @@ -0,0 +1,265 @@ +// list_hostvars.cpp +// +// List Rivendell Host Variables +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_hostvars.cpp,v 1.12 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +ListHostvars::ListHostvars(QString station,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString str; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + list_station=station; + str=QString(tr("Host Variables for")); + setCaption(QString().sprintf("%s %s",(const char *)str, + (const char *)station.upper())); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Bold); + small_font.setPixelSize(10); + + // + // Matrix List Box + // + list_view=new QListView(this,"list_box"); + list_view->setGeometry(10,24,sizeHint().width()-20,sizeHint().height()-114); + QLabel *label=new QLabel(list_view,tr("Host Variables"), + this,"list_view_label"); + label->setFont(font); + label->setGeometry(14,5,sizeHint().width()-28,19); + list_view->setAllColumnsShowFocus(true); + list_view->setItemMargin(5); + list_view->addColumn(tr("NAME")); + list_view->setColumnAlignment(0,Qt::AlignHCenter); + list_view->addColumn(tr("VALUE")); + list_view->setColumnAlignment(1,Qt::AlignLeft); + list_view->addColumn(tr("REMARK")); + list_view->setColumnAlignment(2,Qt::AlignLeft); + connect(list_view,SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this,SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + RefreshList(); + + // + // Add Button + // + QPushButton *add_button=new QPushButton(this,"add_button"); + add_button->setGeometry(10,sizeHint().height()-80,80,50); + add_button->setFont(font); + add_button->setText(tr("&Add")); + connect(add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + QPushButton *edit_button=new QPushButton(this,"edit_button"); + edit_button->setGeometry(100,sizeHint().height()-80,80,50); + edit_button->setFont(font); + edit_button->setText(tr("&Edit")); + connect(edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + QPushButton *delete_button=new QPushButton(this,"delete_button"); + delete_button->setGeometry(190,sizeHint().height()-80,80,50); + delete_button->setFont(font); + delete_button->setText(tr("&Delete")); + connect(delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // OK Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60, + 80,50); + button->setDefault(true); + button->setFont(font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setDefault(true); + button->setFont(font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +ListHostvars::~ListHostvars() +{ + delete list_view; +} + + +QSize ListHostvars::sizeHint() const +{ + return QSize(490,320); +} + + +QSizePolicy ListHostvars::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListHostvars::addData() +{ + QString varname; + QString varvalue; + QString varremark; + AddHostvar *var_dialog= + new AddHostvar(list_station,&varname,&varvalue,&varremark, + this,"var_dialog"); + if(var_dialog->exec()==0) { + QListViewItem *item=new QListViewItem(list_view); + item->setText(0,varname); + item->setText(1,varvalue); + item->setText(2,varremark); + } + delete var_dialog; +} + + +void ListHostvars::editData() +{ + QListViewItem *item=list_view->selectedItem(); + if(item==NULL) { + return; + } + QString varvalue=item->text(1); + QString varremark=item->text(2); + EditHostvar *var_dialog= + new EditHostvar(list_station,item->text(0),&varvalue,&varremark, + this,"var_dialog"); + if(var_dialog->exec()==0) { + item->setText(1,varvalue); + item->setText(2,varremark); + } + delete var_dialog; +} + + +void ListHostvars::deleteData() +{ + QListViewItem *item=list_view->selectedItem(); + if(item==NULL) { + return; + } + if(QMessageBox::question(this,"Delete Host Variable", + QString().sprintf("Are you sure you want to delete the variable %s?", + (const char *)item->text(0)), + QMessageBox::Yes,QMessageBox::No)!=QMessageBox::Yes) { + return; + } + delete item; +} + + +void ListHostvars::doubleClickedData(QListViewItem *,const QPoint &,int) +{ + editData(); +} + + +void ListHostvars::okData() +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("delete from HOSTVARS where STATION_NAME=\"%s\"", + (const char *)list_station); + q=new RDSqlQuery(sql); + delete q; + QListViewItem *item=list_view->firstChild(); + while(item!=NULL) { + sql=QString().sprintf("insert into HOSTVARS set STATION_NAME=\"%s\",\ + NAME=\"%s\",VARVALUE=\"%s\",REMARK=\"%s\"", + (const char *)list_station, + (const char *)item->text(0), + (const char *)item->text(1), + (const char *)item->text(2)); + q=new RDSqlQuery(sql); + delete q; + item=item->nextSibling(); + } + done(0); +} + + +void ListHostvars::cancelData() +{ + done(-1); +} + + +void ListHostvars::RefreshList() +{ + QListViewItem *l; + + list_view->clear(); + QString sql=QString().sprintf("select NAME,VARVALUE,REMARK from HOSTVARS \ + where STATION_NAME=\"%s\" order by NAME", + (const char *)list_station); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + l=new QListViewItem(list_view); + l->setText(0,q->value(0).toString()); + l->setText(1,q->value(1).toString()); + l->setText(2,q->value(2).toString()); + } + delete q; +} diff --git a/rdadmin/list_hostvars.h b/rdadmin/list_hostvars.h new file mode 100644 index 00000000..190b5879 --- /dev/null +++ b/rdadmin/list_hostvars.h @@ -0,0 +1,62 @@ +// list_hostvars.h +// +// List Rivendell Host Variables +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_hostvars.h,v 1.5 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_HOSTVARS_H +#define LIST_HOSTVARS_H + +#include +#include +#include +#include +#include +#include + +#include +#include + + +class ListHostvars : public QDialog +{ + Q_OBJECT + public: + ListHostvars(QString station,QWidget *parent=0,const char *name=0); + ~ListHostvars(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void doubleClickedData(QListViewItem *,const QPoint &,int); + void okData(); + void cancelData(); + + private: + void RefreshList(); + QListView *list_view; + QString list_station; +}; + + +#endif + diff --git a/rdadmin/list_livewiregpios.cpp b/rdadmin/list_livewiregpios.cpp new file mode 100644 index 00000000..5344cd9e --- /dev/null +++ b/rdadmin/list_livewiregpios.cpp @@ -0,0 +1,255 @@ +// list_livewiregpios.cpp +// +// List Rivendell Livewire GPIO Slot Associations +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: list_livewiregpios.cpp,v 1.1.2.3 2013/03/09 00:21:12 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +ListLiveWireGpios::ListLiveWireGpios(RDMatrix *matrix,int slot_quan, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + list_matrix=matrix; + list_slot_quan=slot_quan; + setCaption(tr("LiveWire GPIO Source Assignments")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Bold); + small_font.setPixelSize(10); + + // + // Matrix List Box + // + list_view=new RDListView(this,"list_box"); + list_view->setGeometry(10,24,sizeHint().width()-20,sizeHint().height()-94); + QLabel *label=new QLabel(list_view,tr("Switchers:"),this,"list_view_label"); + label->setFont(font); + label->setGeometry(14,5,85,19); + list_view->setAllColumnsShowFocus(true); + list_view->setItemMargin(5); + list_view->addColumn(tr("Lines")); + list_view->setColumnAlignment(0,Qt::AlignHCenter); + list_view->addColumn(tr("Source #")); + list_view->setColumnAlignment(1,Qt::AlignCenter); + list_view->addColumn(tr("Surface Address")); + list_view->setColumnAlignment(2,Qt::AlignCenter); + list_view->setColumnSortType(0,RDListView::GpioSort); + connect(list_view,SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this,SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + RefreshList(); + + // + // Edit Button + // + QPushButton *edit_button=new QPushButton(this,"edit_button"); + edit_button->setGeometry(10,sizeHint().height()-60,80,50); + edit_button->setFont(font); + edit_button->setText(tr("&Edit")); + connect(edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60, + 80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setDefault(true); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +ListLiveWireGpios::~ListLiveWireGpios() +{ + delete list_view; +} + + +QSize ListLiveWireGpios::sizeHint() const +{ + return QSize(400,300); +} + + +QSizePolicy ListLiveWireGpios::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListLiveWireGpios::editData() +{ + if(list_view->selectedItem()==NULL) { + return; + } + int source=list_view->currentItem()->text(1).toInt(); + QHostAddress addr; + addr.setAddress(list_view->currentItem()->text(2)); + EditLiveWireGpio *d= + new EditLiveWireGpio(list_view->currentItem()->text(0).toInt(), + &source,&addr); + if(d->exec()==0) { + if(source==0) { + list_view->currentItem()->setText(1,tr("[none]")); + } + else { + list_view->currentItem()->setText(1,QString().sprintf("%d",source)); + } + if(addr.isNull()) { + list_view->currentItem()->setText(2,tr("[all]")); + } + else { + list_view->currentItem()->setText(2,addr.toString()); + } + } + delete d; +} + + +void ListLiveWireGpios::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListLiveWireGpios::okData() +{ + QString sql; + RDSqlQuery *q; + int slot=0; + QString addr_str="NULL"; + + RDListViewItem *item=(RDListViewItem *)list_view->firstChild(); + while(item!=NULL) { + QHostAddress addr; + addr_str="NULL"; + addr.setAddress(item->text(2)); + if(!addr.isNull()) { + addr_str="\""+addr.toString()+"\""; + } + sql=QString("update LIVEWIRE_GPIO_SLOTS set ")+ + QString().sprintf("SOURCE_NUMBER=%d,",item->text(1).toInt())+ + "IP_ADDRESS="+addr_str+" "+ + "where (STATION_NAME=\""+RDEscapeString(list_matrix->station())+"\")&&"+ + QString().sprintf("(MATRIX=%d)&&",list_matrix->matrix())+ + QString().sprintf("(SLOT=%d)",slot); + q=new RDSqlQuery(sql); + delete q; + slot++; + item=(RDListViewItem *)item->nextSibling(); + } + + done(0); +} + + +void ListLiveWireGpios::cancelData() +{ + done(-1); +} + + +void ListLiveWireGpios::RefreshList() +{ + QListViewItem *l; + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + list_view->clear(); + sql=QString("select SLOT,SOURCE_NUMBER,IP_ADDRESS from LIVEWIRE_GPIO_SLOTS ")+ + "where (STATION_NAME=\""+RDEscapeString(list_matrix->station())+"\")&&"+ + QString().sprintf("(MATRIX=%d) ",list_matrix->matrix())+ + "order by SLOT"; + q=new RDSqlQuery(sql); + q->first(); + for(int i=0;isetText(0,QString().sprintf("%d - %d",5*i+1,5*i+5)); + if(q->isValid()&&(q->value(0).toInt()==i)) { + if(q->value(1).toInt()==0) { + l->setText(1,tr("[none]")); + } + else { + l->setText(1,QString().sprintf("%d",q->value(1).toInt())); + } + if(q->value(2).toString().isEmpty()) { + l->setText(2,tr("[all]")); + } + else { + l->setText(2,q->value(2).toString()); + } + q->next(); + } + else { + sql=QString("insert into LIVEWIRE_GPIO_SLOTS set ")+ + "STATION_NAME=\""+RDEscapeString(list_matrix->station())+"\","+ + QString().sprintf("MATRIX=%d,",list_matrix->matrix())+ + QString().sprintf("SLOT=%d",i); + q1=new RDSqlQuery(sql); + delete q1; + l->setText(1,tr("[none]")); + l->setText(2,tr("[all]")); + } + } + delete q; +} diff --git a/rdadmin/list_livewiregpios.h b/rdadmin/list_livewiregpios.h new file mode 100644 index 00000000..5533a431 --- /dev/null +++ b/rdadmin/list_livewiregpios.h @@ -0,0 +1,61 @@ +// list_livewiregpios.h +// +// List Rivendell Livewire GPIO Slot Associations +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: list_livewiregpios.h,v 1.1.2.2 2013/03/05 23:59:07 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_LIVEWIREGPIOS_H +#define LIST_LIVEWIREGPIOS_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +class ListLiveWireGpios : public QDialog +{ + Q_OBJECT + public: + ListLiveWireGpios(RDMatrix *matrix,int slot_quan, + QWidget *parent=0,const char *name=0); + ~ListLiveWireGpios(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void editData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void okData(); + void cancelData(); + + private: + void RefreshList(); + RDListView *list_view; + RDMatrix *list_matrix; + int list_slot_quan; +}; + + +#endif + diff --git a/rdadmin/list_matrices.cpp b/rdadmin/list_matrices.cpp new file mode 100644 index 00000000..12273e58 --- /dev/null +++ b/rdadmin/list_matrices.cpp @@ -0,0 +1,336 @@ +// list_matrices.cpp +// +// List Rivendell Matrices +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: list_matrices.cpp,v 1.28.6.2 2012/12/10 15:40:15 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +ListMatrices::ListMatrices(QString station,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + list_station=station; + setCaption(tr("Rivendell Switcher List")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Bold); + small_font.setPixelSize(10); + + // + // Initialize Data Structures + // + for(int i=0;isetGeometry(10,24,sizeHint().width()-20,sizeHint().height()-94); + QLabel *label=new QLabel(list_view,tr("Switchers:"),this,"list_view_label"); + label->setFont(font); + label->setGeometry(14,5,85,19); + list_view->setAllColumnsShowFocus(true); + list_view->setItemMargin(5); + list_view->addColumn(tr("MATRIX")); + list_view->setColumnAlignment(0,Qt::AlignHCenter); + list_view->addColumn(tr("DESCRIPTION")); + list_view->setColumnAlignment(1,Qt::AlignLeft); + list_view->addColumn(tr("TYPE")); + list_view->setColumnAlignment(2,Qt::AlignLeft); + connect(list_view,SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this,SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + RefreshList(); + + // + // Add Button + // + QPushButton *add_button=new QPushButton(this,"add_button"); + add_button->setGeometry(10,sizeHint().height()-60,80,50); + add_button->setFont(font); + add_button->setText(tr("&Add")); + connect(add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + QPushButton *edit_button=new QPushButton(this,"edit_button"); + edit_button->setGeometry(100,sizeHint().height()-60,80,50); + edit_button->setFont(font); + edit_button->setText(tr("&Edit")); + connect(edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + QPushButton *delete_button=new QPushButton(this,"delete_button"); + delete_button->setGeometry(190,sizeHint().height()-60,80,50); + delete_button->setFont(font); + delete_button->setText(tr("&Delete")); + connect(delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Close Button + // + QPushButton *close_button=new QPushButton(this,"close_button"); + close_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + close_button->setDefault(true); + close_button->setFont(font); + close_button->setText(tr("&Close")); + connect(close_button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +ListMatrices::~ListMatrices() +{ + delete list_view; +} + + +QSize ListMatrices::sizeHint() const +{ + return QSize(400,300); +} + + +QSizePolicy ListMatrices::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListMatrices::addData() +{ + int matrix_num; + + AddMatrix *add=new AddMatrix(list_station,this); + if((matrix_num=add->exec())<0) { + delete add; + return; + } + delete add; + RDMatrix *matrix=new RDMatrix(list_station,matrix_num); + EditMatrix *edit=new EditMatrix(matrix,this); + if(edit->exec()!=0) { + DeleteMatrix(matrix_num); + } + else { + list_matrix_modified[matrix_num]=true; + AddList(matrix_num); + } + delete edit; + delete matrix; +} + + +void ListMatrices::editData() +{ + if(list_view->selectedItem()==NULL) { + return; + } + int matrix_num=list_view->currentItem()->text(0).toInt(); + RDMatrix *matrix=new RDMatrix(list_station,matrix_num); + QListViewItem *item=list_view->selectedItem(); + EditMatrix *edit=new EditMatrix(matrix,this); + if(edit->exec()==0) { + RefreshRecord(item); + list_matrix_modified[matrix_num]=true; + } + delete edit; + delete matrix; +} + + +void ListMatrices::deleteData() +{ + QString str1; + QString str2; + QString str3; + + if(list_view->currentItem()==NULL) { + return; + } + int matrix=list_view->currentItem()->text(0).toInt(); + QString desc=list_view->currentItem()->text(1); + str1=QString(tr("Are you sure you want to delete switcher")); + str2=QString(tr("on")); + str3=QString(tr("ALL references to this switcher will be deleted!")); + QString msg=QString().sprintf("%s \"%d:%s\" %s \"%s\"?\n%s", + (const char *)str1, + matrix, + (const char *)desc, + (const char *)str2, + (const char *)list_station, + (const char *)str3); + if(QMessageBox::warning(this,tr("Deleting Switcher"),msg, + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + return; + } + DeleteMatrix(matrix); + list_matrix_modified[matrix]=true; + RefreshList(); +} + + +void ListMatrices::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListMatrices::closeData() +{ + RDStation *rmt_station=new RDStation(list_station); + QHostAddress addr=rmt_station->address(); + RDMacro macro; + + macro.setCommand(RDMacro::SZ); + macro.setRole(RDMacro::Cmd); + macro.setEchoRequested(false); + macro.setArgQuantity(1); + for(int i=0;iaddress()); + macro.setArg(0,i); + rdripc->sendRml(¯o); + } + } + delete rmt_station; + done(0); +} + + +void ListMatrices::DeleteMatrix(int matrix) +{ + QString sql=QString().sprintf("delete from MATRICES where \ + STATION_NAME=\"%s\" && MATRIX=%d", + (const char *)list_station, + matrix); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from INPUTS where \ + STATION_NAME=\"%s\" && MATRIX=%d", + (const char *)list_station, + matrix); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from OUTPUTS where \ + STATION_NAME=\"%s\" && MATRIX=%d", + (const char *)list_station, + matrix); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from SWITCHER_NODES where \ + STATION_NAME=\"%s\" && MATRIX=%d", + (const char *)list_station, + matrix); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from GPIS where \ + STATION_NAME=\"%s\" && MATRIX=%d", + (const char *)list_station, + matrix); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from GPOS where \ + STATION_NAME=\"%s\" && MATRIX=%d", + (const char *)list_station, + matrix); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from VGUEST_RESOURCES where \ + STATION_NAME=\"%s\" && MATRIX_NUM=%d", + (const char *)list_station, + matrix); + q=new RDSqlQuery(sql); + delete q; +} + + +void ListMatrices::RefreshList() +{ + QListViewItem *l; + + list_view->clear(); + QString sql=QString().sprintf("select MATRIX,NAME,TYPE from MATRICES \ + where STATION_NAME=\"%s\" order by MATRIX", + (const char *)list_station); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + l=new QListViewItem(list_view); + l->setText(0,q->value(0).toString()); + l->setText(1,q->value(1).toString()); + l->setText(2,RDMatrix::typeString((RDMatrix::Type)q->value(2).toInt())); + } + delete q; +} + + +void ListMatrices::AddList(int matrix_num) +{ + RDMatrix *matrix=new RDMatrix(list_station,matrix_num); + QListViewItem *item=new QListViewItem(list_view); + item->setText(0,QString().sprintf("%d",matrix_num)); + item->setText(1,matrix->name()); + item->setText(2,RDMatrix::typeString(matrix->type())); + delete matrix; + list_view->setCurrentItem(item); + list_view->setSelected(item,true); +} + + +void ListMatrices::RefreshRecord(QListViewItem *item) +{ + RDMatrix *matrix=new RDMatrix(list_station,item->text(0).toInt()); + item->setText(1,matrix->name()); + delete matrix; +} diff --git a/rdadmin/list_matrices.h b/rdadmin/list_matrices.h new file mode 100644 index 00000000..6c248db6 --- /dev/null +++ b/rdadmin/list_matrices.h @@ -0,0 +1,65 @@ +// list_matrices.h +// +// List Rivendell Matrices +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: list_matrices.h,v 1.9.8.1 2012/12/10 15:40:15 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_MATRICES_H +#define LIST_MATRICES_H + +#include +#include +#include +#include +#include +#include + +#include +#include + + +class ListMatrices : public QDialog +{ + Q_OBJECT + public: + ListMatrices(QString station,QWidget *parent=0,const char *name=0); + ~ListMatrices(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void closeData(); + + private: + void DeleteMatrix(int matrix); + void RefreshList(); + void AddList(int matrix_num); + void RefreshRecord(QListViewItem *item); + QListView *list_view; + QString list_station; + bool list_matrix_modified[MAX_MATRICES]; +}; + + +#endif + diff --git a/rdadmin/list_nodes.cpp b/rdadmin/list_nodes.cpp new file mode 100644 index 00000000..37f20906 --- /dev/null +++ b/rdadmin/list_nodes.cpp @@ -0,0 +1,279 @@ +// list_nodes.cpp +// +// List Rivendell LiveWire Nodes +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: list_nodes.cpp,v 1.3 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + + +ListNodes::ListNodes(RDMatrix *matrix,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + list_matrix=matrix; + setCaption(tr("LiveWire Node List")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Nodes List Box + // + list_list_view=new RDListView(this,"list_box"); + list_list_view-> + setGeometry(10,10,sizeHint().width()-20,sizeHint().height()-80); + list_list_view->setAllColumnsShowFocus(true); + list_list_view->setItemMargin(5); + list_list_view->addColumn(tr("HOSTNAME")); + list_list_view->setColumnAlignment(0,Qt::AlignLeft); + list_list_view->addColumn(tr("DESCRIPTION")); + list_list_view->setColumnAlignment(1,Qt::AlignLeft); + list_list_view->addColumn(tr("FIRST OUTPUT")); + list_list_view->setColumnAlignment(2,Qt::AlignLeft); + list_list_view->addColumn(tr("TCP PORT")); + list_list_view->setColumnAlignment(3,Qt::AlignCenter); + connect(list_list_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + // + // Add Button + // + QPushButton *button=new QPushButton(this,"add_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Add")); + connect(button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + button=new QPushButton(this,"edit_button"); + button->setGeometry(100,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Edit")); + connect(button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + button=new QPushButton(this,"delete_button"); + button->setGeometry(190,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Delete")); + connect(button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Close Button + // + button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&Close")); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Load Values + // + RefreshList(); +} + + +QSize ListNodes::sizeHint() const +{ + return QSize(400,250); +} + + +QSizePolicy ListNodes::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListNodes::addData() +{ + RDListViewItem *item; + int id=-1; + EditNode *node=new EditNode(&id,list_matrix,this); + if(node->exec()==0) { + item=new RDListViewItem(list_list_view); + item->setId(id); + RefreshItem(item); + list_list_view->setSelected(item,true); + list_list_view->ensureItemVisible(item); + } + delete node; +} + + +void ListNodes::editData() +{ + RDListViewItem *item; + + if((item=(RDListViewItem *)list_list_view->selectedItem())==NULL) { + return; + } + int id=item->id(); + EditNode *node=new EditNode(&id,list_matrix,this); + if(node->exec()==0) { + RefreshItem(item); + } + delete node; +} + + +void ListNodes::deleteData() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + if((item=(RDListViewItem *)list_list_view->selectedItem())==NULL) { + return; + } + if(QMessageBox::question(this,tr("Delete Node"), + tr("Are your sure you want to delete this node?"), + QMessageBox::Yes,QMessageBox::No)== + QMessageBox::No) { + return; + } + sql=QString().sprintf("delete from SWITCHER_NODES where ID=%d",item->id()); + q=new RDSqlQuery(sql); + delete q; + delete item; +} + + +void ListNodes::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListNodes::closeData() +{ + PurgeEndpoints("INPUTS"); + PurgeEndpoints("OUTPUTS"); + done(0); +} + + +void ListNodes::RefreshList() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + list_list_view->clear(); + sql=QString().sprintf("select ID,HOSTNAME,DESCRIPTION,BASE_OUTPUT,TCP_PORT \ + from SWITCHER_NODES \ + where (STATION_NAME=\"%s\")&&(MATRIX=%d)", + (const char *)list_matrix->station(), + list_matrix->matrix()); + q=new RDSqlQuery(sql); + while(q->next()) { + item=new RDListViewItem(list_list_view); + item->setId(q->value(0).toInt()); + item->setText(0,q->value(1).toString()); + item->setText(1,q->value(2).toString()); + if(q->value(3).toInt()==0) { + item->setText(2,tr("[none]")); + } + else { + item->setText(2,QString().sprintf("%d",q->value(3).toInt())); + } + item->setText(3,q->value(4).toString()); + } + delete q; +} + + +void ListNodes::RefreshItem(RDListViewItem *item) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select HOSTNAME,DESCRIPTION,BASE_OUTPUT,TCP_PORT \ + from SWITCHER_NODES where ID=%d",item->id()); + q=new RDSqlQuery(sql); + if(q->first()) { + item->setText(0,q->value(0).toString()); + item->setText(1,q->value(1).toString()); + if(q->value(2).toInt()==0) { + item->setText(2,tr("[none]")); + } + else { + item->setText(2,QString().sprintf("%d",q->value(2).toInt())); + } + item->setText(3,q->value(3).toString()); + } + delete q; +} + + +void ListNodes::PurgeEndpoints(const QString &tablename) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("delete from %s where \ + (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&", + (const char *)tablename, + (const char *)list_matrix->station(), + list_matrix->matrix()); + RDListViewItem *item=(RDListViewItem *)list_list_view->firstChild(); + while(item!=NULL) { + sql+=QString().sprintf("((NODE_HOSTNAME!=\"%s\")&&(NODE_TCP_PORT!=%d))&&", + (const char *)item->text(0),item->text(3).toInt()); + item=(RDListViewItem *)item->nextSibling(); + } + sql=sql.left(sql.length()-2); + q=new RDSqlQuery(sql); + delete q; +} diff --git a/rdadmin/list_nodes.h b/rdadmin/list_nodes.h new file mode 100644 index 00000000..31e45b4b --- /dev/null +++ b/rdadmin/list_nodes.h @@ -0,0 +1,62 @@ +// list_nodes.h +// +// List Rivendell LiveWire Nodes +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: list_nodes.h,v 1.3 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_NODES_H +#define LIST_NODES_H + +#include +#include +#include +#include + +#include +#include +#include +#include + + +class ListNodes : public QDialog +{ + Q_OBJECT + public: + ListNodes(RDMatrix *matrix,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void closeData(); + + private: + void RefreshList(); + void RefreshItem(RDListViewItem *item); + void PurgeEndpoints(const QString &tablename); + RDMatrix *list_matrix; + RDListView *list_list_view; +}; + + +#endif + diff --git a/rdadmin/list_replicator_carts.cpp b/rdadmin/list_replicator_carts.cpp new file mode 100644 index 00000000..bb7358e1 --- /dev/null +++ b/rdadmin/list_replicator_carts.cpp @@ -0,0 +1,260 @@ +// list_replicator_carts.cpp +// +// List Rivendell Replicators +// +// (C) Copyright 2002-2008 Fred Gleason +// +// $Id: list_replicator_carts.cpp,v 1.1 2011/10/17 18:48:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" + +ListReplicatorCarts::ListReplicatorCarts(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont list_font=QFont("Helvetica",12,QFont::Normal); + list_font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Create Icons + // + list_playout_map=new QPixmap(play_xpm); + list_macro_map=new QPixmap(rml5_xpm); + + // + // Refresh Timer + // + list_refresh_timer=new QTimer(this); + connect(list_refresh_timer,SIGNAL(timeout()),this,SLOT(refreshTimeoutData())); + + // + // Repost Button + // + list_repost_button=new QPushButton(this,"list_repost_button"); + list_repost_button->setFont(font); + list_repost_button->setText(tr("&Repost")); + connect(list_repost_button,SIGNAL(clicked()),this,SLOT(repostData())); + + // + // Repost All Button + // + list_repost_all_button=new QPushButton(this,"list_repost_button"); + list_repost_all_button->setFont(font); + list_repost_all_button->setText(tr("Repost\n&All")); + connect(list_repost_all_button,SIGNAL(clicked()),this,SLOT(repostAllData())); + + // + // Close Button + // + list_close_button=new QPushButton(this,"list_close_button"); + list_close_button->setDefault(true); + list_close_button->setFont(font); + list_close_button->setText(tr("&Close")); + connect(list_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Replicator List + // + list_view=new RDListView(this,"list_view"); + list_view->setFont(list_font); + list_view->setAllColumnsShowFocus(true); + list_view->setItemMargin(5); + list_view->addColumn(" "); + list_view->addColumn(tr("CART")); + list_view->addColumn(tr("TITLE")); + list_view->addColumn(tr("LAST POSTED")); + list_view->addColumn(tr("POSTED FILENAME")); + QLabel *list_box_label=new QLabel(list_view,tr("&Active Carts:"), + this,"list_box_label"); + list_box_label->setFont(font); + list_box_label->setGeometry(14,11,85,19); +} + + +ListReplicatorCarts::~ListReplicatorCarts() +{ +} + + +QSize ListReplicatorCarts::sizeHint() const +{ + return QSize(500,400); +} + + +QSizePolicy ListReplicatorCarts::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int ListReplicatorCarts::exec(const QString &replname) +{ + list_replicator_name=replname; + setCaption(replname+tr(" Replicator Carts")); + RefreshList(); + list_refresh_timer->start(5000,true); + return QDialog::exec(); +} + + +void ListReplicatorCarts::repostData() +{ + QString sql; + RDSqlQuery *q; + + RDListViewItem *item=(RDListViewItem *)list_view->selectedItem(); + if(item==NULL) { + return; + } + sql=QString().sprintf("update REPL_CART_STATE set REPOST=\"Y\" \ + where ID=%d",item->id()); + q=new RDSqlQuery(sql); + delete q; +} + + +void ListReplicatorCarts::repostAllData() +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("update REPL_CART_STATE set REPOST=\"Y\" \ + where REPLICATOR_NAME=\"%s\"", + (const char *)list_replicator_name); + q=new RDSqlQuery(sql); + delete q; +} + + +void ListReplicatorCarts::closeData() +{ + list_refresh_timer->stop(); + done(0); +} + + +void ListReplicatorCarts::refreshTimeoutData() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + sql=QString().sprintf("select ID,ITEM_DATETIME from REPL_CART_STATE \ + where REPLICATOR_NAME=\"%s\"", + (const char *)RDEscapeString(list_replicator_name)); + q=new RDSqlQuery(sql); + while(q->next()) { + item=(RDListViewItem *)list_view->firstChild(); + while(item!=NULL) { + if(item->id()==q->value(0).toInt()) { + item->setText(3,q->value(1). + toDateTime().toString("hh:mm:ss dd/MM/yyyy")); + break; + } + item=(RDListViewItem *)item->nextSibling(); + } + } + delete q; + list_refresh_timer->start(5000,true); +} + + +void ListReplicatorCarts::resizeEvent(QResizeEvent *e) +{ + list_repost_button->setGeometry(size().width()-90,30,80,50); + list_repost_all_button->setGeometry(size().width()-90,90,80,50); + list_close_button->setGeometry(size().width()-90,size().height()-60,80,50); + list_view->setGeometry(10,30,size().width()-120,size().height()-40); +} + + +void ListReplicatorCarts::RefreshList() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + list_view->clear(); + sql=QString().sprintf("select REPL_CART_STATE.ID,\ + CART.TYPE,REPL_CART_STATE.CART_NUMBER,\ + CART.TITLE,\ + REPL_CART_STATE.ITEM_DATETIME,\ + REPL_CART_STATE.POSTED_FILENAME \ + from REPL_CART_STATE left join CART \ + on REPL_CART_STATE.CART_NUMBER=CART.NUMBER \ + where REPLICATOR_NAME=\"%s\"", + (const char *)RDEscapeString(list_replicator_name)); + q=new RDSqlQuery(sql); + while (q->next()) { + item=new RDListViewItem(list_view); + item->setId(q->value(0).toInt()); + item->setText(1,QString().sprintf("%06u",q->value(2).toUInt())); + switch((RDCart::Type)q->value(1).toInt()) { + case RDCart::Audio: + item->setPixmap(0,*list_playout_map); + break; + + case RDCart::Macro: + item->setPixmap(0,*list_macro_map); + break; + + case RDCart::All: + break; + } + item->setText(2,q->value(3).toString()); + item->setText(3,q->value(4).toDateTime().toString("hh:mm:ss dd/MM/yyyy")); + item->setText(4,q->value(5).toString()); + } + delete q; +} diff --git a/rdadmin/list_replicator_carts.h b/rdadmin/list_replicator_carts.h new file mode 100644 index 00000000..ccc585e9 --- /dev/null +++ b/rdadmin/list_replicator_carts.h @@ -0,0 +1,73 @@ +// list_replicator_carts.h +// +// List Rivendell Replication Configurations +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: list_replicator_carts.h,v 1.1 2011/10/17 18:48:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_REPLICATOR_CARTS_H +#define LIST_REPLICATOR_CARTS_H + +#include +#include +#include +#include +#include +#include + +#include +#include + + +class ListReplicatorCarts : public QDialog +{ + Q_OBJECT + public: + ListReplicatorCarts(QWidget *parent=0,const char *name=0); + ~ListReplicatorCarts(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(const QString &replname); + + private slots: + void repostData(); + void repostAllData(); + void closeData(); + void refreshTimeoutData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshList(); + RDListView *list_view; + QPushButton *list_repost_button; + QPushButton *list_repost_all_button; + QPushButton *list_close_button; + QString list_replicator_name; + QPixmap *list_playout_map; + QPixmap *list_macro_map; + QTimer *list_refresh_timer; +}; + + +#endif + + diff --git a/rdadmin/list_replicators.cpp b/rdadmin/list_replicators.cpp new file mode 100644 index 00000000..6a364328 --- /dev/null +++ b/rdadmin/list_replicators.cpp @@ -0,0 +1,317 @@ +// list_replicators.cpp +// +// List Rivendell Replicators +// +// (C) Copyright 2002-2008 Fred Gleason +// +// $Id: list_replicators.cpp,v 1.3 2011/10/17 18:48:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +ListReplicators::ListReplicators(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + setCaption(tr("Rivendell Replicators")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont list_font=QFont("Helvetica",12,QFont::Normal); + list_font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Add Button + // + list_add_button=new QPushButton(this,"list_add_button"); + list_add_button->setFont(font); + list_add_button->setText(tr("&Add")); + connect(list_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + list_edit_button=new QPushButton(this,"list_edit_button"); + list_edit_button->setFont(font); + list_edit_button->setText(tr("&Edit")); + connect(list_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + list_delete_button=new QPushButton(this,"list_delete_button"); + list_delete_button->setFont(font); + list_delete_button->setText(tr("&Delete")); + connect(list_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // List Carts Button + // + list_list_button=new QPushButton(this,"list_list_button"); + list_list_button->setFont(font); + list_list_button->setText(tr("&List\nCarts")); + connect(list_list_button,SIGNAL(clicked()),this,SLOT(listData())); + + // + // Close Button + // + list_close_button=new QPushButton(this,"list_close_button"); + list_close_button->setDefault(true); + list_close_button->setFont(font); + list_close_button->setText(tr("&Close")); + connect(list_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Replicator List + // + list_replicators_view=new RDListView(this,"list_replicators_view"); + list_replicators_view->setFont(list_font); + list_replicators_view->setAllColumnsShowFocus(true); + list_replicators_view->setItemMargin(5); + list_replicators_view->addColumn(tr("NAME")); + list_replicators_view->addColumn(tr("TYPE")); + list_replicators_view->addColumn(tr("DESCRIPTION")); + list_replicators_view->addColumn(tr("HOST")); + QLabel *list_box_label=new QLabel(list_replicators_view,tr("&Replicators:"), + this,"list_box_label"); + list_box_label->setFont(font); + list_box_label->setGeometry(14,11,85,19); + connect(list_replicators_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + RefreshList(); +} + + +ListReplicators::~ListReplicators() +{ +} + + +QSize ListReplicators::sizeHint() const +{ + return QSize(640,480); +} + + +QSizePolicy ListReplicators::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListReplicators::addData() +{ + QString name; + + AddReplicator *d=new AddReplicator(&name,this); + if(d->exec()<0) { + delete d; + return; + } + delete d; + RDListViewItem *item=new RDListViewItem(list_replicators_view); + item->setText(0,name); + RefreshItem(item); + item->setSelected(true); + list_replicators_view->setCurrentItem(item); + list_replicators_view->ensureItemVisible(item); +} + + +void ListReplicators::editData() +{ + RDListViewItem *item=(RDListViewItem *)list_replicators_view->selectedItem(); + if(item==NULL) { + return; + } + EditReplicator *d=new EditReplicator(item->text(0),this); + if(d->exec()==0) { + RefreshItem(item); + } + delete d; +} + + +void ListReplicators::deleteData() +{ + RDListViewItem *item=(RDListViewItem *)list_replicators_view->selectedItem(); + if(item==NULL) { + return; + } + + QString sql; + RDSqlQuery *q; + QString warning; + QString str; + + QString name=RDEscapeString(item->text(0)); + + str=QString(tr("Are you sure you want to delete replicator")); + warning+=QString().sprintf("%s \"%s\"?",(const char *)str, + (const char *)item->text(0)); + switch(QMessageBox::warning(this,tr("Delete Replicator"),warning, + QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + return; + + default: + break; + } + + // + // Delete Group Assignments + // + sql=QString().sprintf("delete from REPLICATOR_MAP \ + where REPLICATOR_NAME=\"%s\"", + (const char *)name); + q=new RDSqlQuery(sql); + delete q; + + // + // Delete State Records + // + sql=QString().sprintf("delete from REPL_CART_STATE \ + where REPLICATOR_NAME=\"%s\"", + (const char *)name); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from REPL_CUT_STATE \ + where REPLICATOR_NAME=\"%s\"", + (const char *)name); + q=new RDSqlQuery(sql); + delete q; + + // + // Delete from Replicator List + // + sql=QString().sprintf("delete from REPLICATORS where NAME=\"%s\"", + (const char *)name); + q=new RDSqlQuery(sql); + delete q; + delete item; +} + + +void ListReplicators::listData() +{ + RDListViewItem *item=(RDListViewItem *)list_replicators_view->selectedItem(); + if(item==NULL) { + return; + } + ListReplicatorCarts *d=new ListReplicatorCarts(this); + d->exec(item->text(0)); + delete d; +} + + +void ListReplicators::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListReplicators::closeData() +{ + done(0); +} + + +void ListReplicators::resizeEvent(QResizeEvent *e) +{ + list_add_button->setGeometry(size().width()-90,30,80,50); + list_edit_button->setGeometry(size().width()-90,90,80,50); + list_delete_button->setGeometry(size().width()-90,150,80,50); + list_list_button->setGeometry(size().width()-90,250,80,50); + list_close_button->setGeometry(size().width()-90,size().height()-60,80,50); + list_replicators_view->setGeometry(10,30,size().width()-120,size().height()-40); +} + + +void ListReplicators::RefreshList() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + list_replicators_view->clear(); + sql="select NAME,TYPE_ID,DESCRIPTION,STATION_NAME from REPLICATORS"; + q=new RDSqlQuery(sql); + while (q->next()) { + item=new RDListViewItem(list_replicators_view); + item->setText(0,q->value(0).toString()); + item->setText(1, + RDReplicator::typeString((RDReplicator::Type)q->value(1).toUInt())); + item->setText(2,q->value(2).toString()); + item->setText(3,q->value(3).toString()); + } + delete q; +} + + +void ListReplicators::RefreshItem(RDListViewItem *item) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select TYPE_ID,DESCRIPTION,STATION_NAME \ + from REPLICATORS where NAME=\"%s\"", + (const char *)RDEscapeString(item->text(0))); + q=new RDSqlQuery(sql); + if(q->first()) { + item->setText(1, + RDReplicator::typeString((RDReplicator::Type)q->value(0).toUInt())); + item->setText(2,q->value(1).toString()); + item->setText(3,q->value(2).toString()); + } + delete q; +} diff --git a/rdadmin/list_replicators.h b/rdadmin/list_replicators.h new file mode 100644 index 00000000..9f1dd4e3 --- /dev/null +++ b/rdadmin/list_replicators.h @@ -0,0 +1,70 @@ +// list_replicators.h +// +// List Rivendell Replication Configurations +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: list_replicators.h,v 1.3 2011/10/17 18:48:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_REPLICATORS_H +#define LIST_REPLICATORS_H + +#include +#include +#include +#include +#include + +#include +#include + + +class ListReplicators : public QDialog +{ + Q_OBJECT + public: + ListReplicators(QWidget *parent=0,const char *name=0); + ~ListReplicators(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void listData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void closeData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshList(); + void RefreshItem(RDListViewItem *item); + RDListView *list_replicators_view; + QPushButton *list_add_button; + QPushButton *list_edit_button; + QPushButton *list_delete_button; + QPushButton *list_list_button; + QPushButton *list_close_button; +}; + + +#endif + + diff --git a/rdadmin/list_reports.cpp b/rdadmin/list_reports.cpp new file mode 100644 index 00000000..030ee682 --- /dev/null +++ b/rdadmin/list_reports.cpp @@ -0,0 +1,234 @@ +// list_reports.cpp +// +// List Rivendell Reports +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_reports.cpp,v 1.12 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +ListReports::ListReports(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Rivendell Report List")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Add Button + // + QPushButton *add_button=new QPushButton(this,"add_button"); + add_button->setGeometry(410,30,80,50); + add_button->setFont(font); + add_button->setText(tr("&Add")); + connect(add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + QPushButton *edit_button=new QPushButton(this,"edit_button"); + edit_button->setGeometry(410,90,80,50); + edit_button->setFont(font); + edit_button->setText(tr("&Edit")); + connect(edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + QPushButton *delete_button=new QPushButton(this,"delete_button"); + delete_button->setGeometry(410,150,80,50); + delete_button->setFont(font); + delete_button->setText(tr("&Delete")); + connect(delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Close Button + // + QPushButton *close_button=new QPushButton(this,"close_button"); + close_button->setGeometry(410,240,80,50); + close_button->setDefault(true); + close_button->setFont(font); + close_button->setText(tr("&Close")); + connect(close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Report List Box + // + list_box=new QListBox(this,"list_box"); + list_box->setGeometry(10,30,390,260); + QLabel *list_box_label=new QLabel(list_box,tr("R&eports:"), + this,"list_box_label"); + list_box_label->setFont(font); + list_box_label->setGeometry(14,10,85,19); + connect(list_box,SIGNAL(doubleClicked(QListBoxItem *)), + this,SLOT(doubleClickedData(QListBoxItem *))); + + RefreshList(); +} + + +ListReports::~ListReports() +{ +} + + +QSize ListReports::sizeHint() const +{ + return QSize(500,300); +} + + +QSizePolicy ListReports::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListReports::addData() +{ + QString rptname; + + AddReport *add_report=new AddReport(&rptname,this,"add_report"); + if(add_report->exec()<0) { + delete add_report; + return; + } + delete add_report; + EditReport *edit_report=new EditReport(rptname,this,"edit_report"); + if(edit_report->exec()<0) { + DeleteReport(rptname); + delete edit_report; + return; + } + delete edit_report; + RefreshList(rptname); +} + + +void ListReports::editData() +{ + if(list_box->currentItem()<0) { + return; + } + EditReport *edit_report= + new EditReport(list_box->currentText(),this,"edit_report"); + edit_report->exec(); + delete edit_report; +} + + +void ListReports::deleteData() +{ + QString str; + + if(list_box->currentText().isEmpty()) { + return; + } + str=QString(tr("Are you sure you want to delete report")); + if(QMessageBox::warning(this,tr("Delete Report"), + QString().sprintf( + "%s \"%s\"?",(const char *)str, + (const char *)list_box->currentText()), + QMessageBox::Yes,QMessageBox::No)== + QMessageBox::Yes) { + DeleteReport(list_box->currentText()); + + list_box->removeItem(list_box->currentItem()); + if(list_box->currentItem()>=0) { + list_box->setSelected(list_box->currentItem(),true); + } + } +} + + +void ListReports::closeData() +{ + done(0); +} + + +void ListReports::doubleClickedData(QListBoxItem *item) +{ + editData(); +} + + +void ListReports::DeleteReport(QString rptname) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("delete from REPORTS where NAME=\"%s\"", + (const char *)rptname); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from REPORT_SERVICES where \ + REPORT_NAME=\"%s\"",(const char *)rptname); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from REPORT_STATIONS where \ + REPORT_NAME=\"%s\"",(const char *)rptname); + q=new RDSqlQuery(sql); + delete q; +} + + +void ListReports::RefreshList(QString rptname) +{ + QString sql; + RDSqlQuery *q; + + list_box->clear(); + q=new RDSqlQuery("SELECT NAME FROM REPORTS",0); + while (q->next()) { + list_box->insertItem(q->value(0).toString()); + if(rptname==list_box->text(list_box->count()-1)) { + list_box->setCurrentItem(list_box->count()-1); + } + } + delete q; +} diff --git a/rdadmin/list_reports.h b/rdadmin/list_reports.h new file mode 100644 index 00000000..82a64e79 --- /dev/null +++ b/rdadmin/list_reports.h @@ -0,0 +1,59 @@ +// list_reports.h +// +// List Rivendell Reports +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_reports.h,v 1.7 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_REPORTS_H +#define LIST_REPORTS_H + +#include +#include +#include +#include +#include +#include + + +class ListReports : public QDialog +{ + Q_OBJECT + public: + ListReports(QWidget *parent=0,const char *name=0); + ~ListReports(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void doubleClickedData(QListBoxItem *item); + void closeData(); + + private: + void DeleteReport(QString rptname); + void RefreshList(QString rptname=""); + QListBox *list_box; +}; + + +#endif + + diff --git a/rdadmin/list_sas_resources.cpp b/rdadmin/list_sas_resources.cpp new file mode 100644 index 00000000..2f592571 --- /dev/null +++ b/rdadmin/list_sas_resources.cpp @@ -0,0 +1,337 @@ +// list_sas_resources.cpp +// +// List SAS Resources. +// +// (C) Copyright 2002-2005,2011 Fred Gleason +// +// $Id: list_sas_resources.cpp,v 1.2 2011/05/23 21:53:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +ListSasResources::ListSasResources(RDMatrix *matrix,int size, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + QString str; + + list_matrix=matrix; + list_size=size; + setCaption(tr("SAS Switches")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Resources List Box + // + list_list_view=new QListView(this,"list_box"); + list_list_view-> + setGeometry(10,24,sizeHint().width()-20,sizeHint().height()-94); + QLabel *label= + new QLabel(list_list_view,list_table,this,"list_list_view_label"); + label->setFont(bold_font); + label->setGeometry(14,5,85,19); + list_list_view->setAllColumnsShowFocus(true); + list_list_view->setItemMargin(5); + list_list_view->addColumn(tr("GPIO LINE")); + list_list_view->setColumnAlignment(0,Qt::AlignHCenter); + list_list_view->addColumn(tr("CONSOLE")); + list_list_view->setColumnAlignment(1,Qt::AlignHCenter); + list_list_view->addColumn(tr("SOURCE")); + list_list_view->setColumnAlignment(2,Qt::AlignHCenter); + list_list_view->addColumn(tr("OPTO/RELAY")); + list_list_view->setColumnAlignment(3,Qt::AlignHCenter); + connect(list_list_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + // + // Edit Button + // + QPushButton *button=new QPushButton(this,"edit_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Edit")); + connect(button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Values + // + RefreshList(); +} + + +QSize ListSasResources::sizeHint() const +{ + return QSize(400,250); +} + + +QSizePolicy ListSasResources::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListSasResources::editData() +{ + int engine_num=-1; + int device_num=-1; + int relay_num=-1; + + QListViewItem *item=list_list_view->selectedItem(); + if(item==NULL) { + return; + } + if(!item->text(1).isEmpty()) { + engine_num=item->text(1).toInt(); + } + if(!item->text(2).isEmpty()) { + device_num=item->text(2).toInt(); + } + if(!item->text(3).isEmpty()) { + relay_num=item->text(3).toInt(); + } + EditSasResource *dialog= + new EditSasResource(&engine_num,&device_num,&relay_num,this,"dialog"); + if(dialog->exec()==0) { + if(engine_num>=0) { + item->setText(1,QString().sprintf("%d",engine_num)); + } + else { + item->setText(1,""); + } + if(device_num>=0) { + item->setText(2,QString().sprintf("%d",device_num)); + } + else { + item->setText(2,""); + } + if(relay_num>=0) { + item->setText(3,QString().sprintf("%d",relay_num)); + } + else { + item->setText(3,""); + } + } + delete dialog; +} + + +void ListSasResources::doubleClickedData(QListViewItem *item, + const QPoint &pt,int col) +{ + editData(); +} + + +void ListSasResources::okData() +{ + QString sql; + RDSqlQuery *q; + int engine_num=-1; + int device_num=-1; + int surface_num=-1; + int relay_num=-1; + + QListViewItem *item=list_list_view->firstChild(); + while(item!=NULL) { + engine_num=-1; + device_num=-1; + surface_num=-1; + relay_num=-1; + if(!item->text(1).isEmpty()) { + engine_num=item->text(1).toInt(); + } + if(!item->text(2).isEmpty()) { + device_num=item->text(2).toInt(); + } + if(!item->text(3).isEmpty()) { + relay_num=item->text(3).toInt(); + } + sql=QString().sprintf("select ID from VGUEST_RESOURCES where\ + (STATION_NAME=\"%s\")&&\ + (MATRIX_NUM=%d)&&\ + (NUMBER=%d)", + (const char *)list_matrix->station(), + list_matrix->matrix(),item->text(0).toInt()); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("update VGUEST_RESOURCES set\ + ENGINE_NUM=%d,DEVICE_NUM=%d,\ + SURFACE_NUM=%d,RELAY_NUM=%d\ + where\ + (STATION_NAME=\"%s\")&&\ + (MATRIX_NUM=%d)&&\ + (NUMBER=%d)", + engine_num,device_num,surface_num, + relay_num, + (const char *)list_matrix->station(), + list_matrix->matrix(), + item->text(0).toInt()); + } + else { + sql=QString().sprintf("insert into VGUEST_RESOURCES set\ + STATION_NAME=\"%s\",MATRIX_NUM=%d,\ + NUMBER=%d,\ + ENGINE_NUM=%d,DEVICE_NUM=%d,\ + SURFACE_NUM=%d,RELAY_NUM=%d", + (const char *)list_matrix->station(), + list_matrix->matrix(), + item->text(0).toInt(), + engine_num,device_num,surface_num, + relay_num); + } + delete q; + q=new RDSqlQuery(sql); + delete q; + item=item->nextSibling(); + } + done(0); +} + + +void ListSasResources::cancelData() +{ + done(-1); +} + + +void ListSasResources::RefreshList() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + QListViewItem *item; + int n=1; + int gpis; + + // + // Populate Resource Records + // + sql=QString().sprintf("select GPIS from MATRICES \ + where (STATION_NAME=\"%s\")&&(MATRIX=%d)", + (const char *)RDEscapeString(list_matrix->station()), + list_matrix->matrix()); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return; + } + gpis=q->value(0).toInt(); + delete q; + for(int i=0;istation()), + list_matrix->matrix(), + i+1); + q=new RDSqlQuery(sql); + if(!q->first()) { + sql=QString().sprintf("insert into VGUEST_RESOURCES set \ + NUMBER=%d,\ + STATION_NAME=\"%s\",\ + MATRIX_NUM=%d", + i+1, + (const char *)RDEscapeString(list_matrix->station()), + list_matrix->matrix()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + } + + sql=QString().sprintf("select NUMBER,ENGINE_NUM,DEVICE_NUM,RELAY_NUM \ + from VGUEST_RESOURCES where\ + (STATION_NAME=\"%s\")&&(MATRIX_NUM=%d) \ + order by NUMBER", + (const char *)RDEscapeString(list_matrix->station()), + list_matrix->matrix()); + q=new RDSqlQuery(sql); + list_list_view->clear(); + while(q->next()) { + while(q->value(0).toInt()>n) { + item=new QListViewItem(list_list_view); + item->setText(0,QString().sprintf("%03d",n++)); + } + item=new QListViewItem(list_list_view); + item->setText(0,QString().sprintf("%03d",q->value(0).toInt())); + if(q->value(1).toInt()>=0) { + item->setText(1,QString().sprintf("%d",q->value(1).toInt())); + } + if(q->value(2).toInt()>=0) { + item->setText(2,QString().sprintf("%d",q->value(2).toInt())); + } + if(q->value(3).toInt()>=0) { + item->setText(3,QString().sprintf("%d",q->value(3).toInt())); + } + n++; + } + for(int i=n;i<(list_size+1);i++) { + item=new QListViewItem(list_list_view); + item->setText(0,QString().sprintf("%03d",i)); + } + delete q; +} diff --git a/rdadmin/list_sas_resources.h b/rdadmin/list_sas_resources.h new file mode 100644 index 00000000..8d72de6c --- /dev/null +++ b/rdadmin/list_sas_resources.h @@ -0,0 +1,60 @@ +// list_sas_resources.h +// +// List SAS Resources +// +// (C) Copyright 2002-2005,2011 Fred Gleason +// +// $Id: list_sas_resources.h,v 1.1 2011/05/07 00:32:29 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_SAS_RESOURCES_H +#define LIST_SAS_RESOURCES_H + +#include +#include +#include +#include +#include + +#include +#include + + +class ListSasResources : public QDialog +{ + Q_OBJECT + public: + ListSasResources(RDMatrix *matrix,int size, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void editData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void okData(); + void cancelData(); + + private: + void RefreshList(); + RDMatrix *list_matrix; + QListView *list_list_view; + int list_size; + QString list_table; +}; + + +#endif // LIST_SAS_RESOURCES_H diff --git a/rdadmin/list_schedcodes.cpp b/rdadmin/list_schedcodes.cpp new file mode 100644 index 00000000..0d0928c8 --- /dev/null +++ b/rdadmin/list_schedcodes.cpp @@ -0,0 +1,265 @@ +// List_schedcodes.cpp +// +// The scheduler codes dialog for rdadmin +// +// Stefan Gabriel +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +ListSchedCodes::ListSchedCodes(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + setCaption(tr("Rivendell Scheduler Codes List")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Add Button + // + list_add_button=new QPushButton(this); + list_add_button->setFont(font); + list_add_button->setText(tr("&Add")); + connect(list_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + list_edit_button=new QPushButton(this); + list_edit_button->setFont(font); + list_edit_button->setText(tr("&Edit")); + connect(list_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + list_delete_button=new QPushButton(this); + list_delete_button->setFont(font); + list_delete_button->setText(tr("&Delete")); + connect(list_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Close Button + // + list_close_button=new QPushButton(this); + list_close_button->setDefault(true); + list_close_button->setFont(font); + list_close_button->setText(tr("&Close")); + connect(list_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Group List + // + list_schedCodes_view=new QListView(this); + list_schedCodes_view->setAllColumnsShowFocus(true); + list_schedCodes_view->addColumn(tr("CODE")); + list_schedCodes_view->addColumn(tr("DESCRIPTION")); + QLabel *list_box_label= + new QLabel(list_schedCodes_view,tr("Scheduler Codes:"),this); + list_box_label->setFont(font); + list_box_label->setGeometry(14,11,200,19); + connect(list_schedCodes_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + RefreshList(); +} + + +ListSchedCodes::~ListSchedCodes() +{ +} + + +QSize ListSchedCodes::sizeHint() const +{ + return QSize(640,480); +} + + +QSizePolicy ListSchedCodes::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListSchedCodes::addData() +{ + QString schedCode; + + AddSchedCode *add_schedCode=new AddSchedCode(&schedCode,this); + if(add_schedCode->exec()<0) { + delete add_schedCode; + return; + } + delete add_schedCode; + add_schedCode=NULL; + QListViewItem *item=new QListViewItem(list_schedCodes_view); + item->setText(0,schedCode); + RefreshItem(item); + item->setSelected(true); + list_schedCodes_view->setCurrentItem(item); + list_schedCodes_view->ensureItemVisible(item); +} + + +void ListSchedCodes::editData() +{ + QListViewItem *item=list_schedCodes_view->selectedItem(); + if(item==NULL) { + return; + } + EditSchedCode *edit_schedCode= + new EditSchedCode(item->text(0),item->text(1),this); + edit_schedCode->exec(); + delete edit_schedCode; + edit_schedCode=NULL; + RefreshItem(item); +} + + +void ListSchedCodes::deleteData() +{ + QListViewItem *item=list_schedCodes_view->selectedItem(); + if(item==NULL) { + return; + } + + QString sql; + RDSqlQuery *q; + QString warning; + QString str; + + QString codename=item->text(0); + if(codename.isEmpty()) { + return; + } + if(QMessageBox::question(this,"RDAdmin - "+tr("Delete Scheduler Code"), + tr("This operation will delete the selected scheduler code and")+ + "\n"+tr("all of its associated data.")+" "+ + tr("This operation cannot be undone.")+"\n\n"+ + tr("Delete scheduler code")+" \""+codename+"\"?", + QMessageBox::Yes,QMessageBox::No)!=QMessageBox::Yes) { + return; + } + + sql=QString("delete from DROPBOX_SCHED_CODES where ")+ + "SCHED_CODE=\""+RDEscapeString(codename)+"\""; + q=new RDSqlQuery(sql); + delete q; + + sql=QString("delete from SCHED_CODES where ")+ + "CODE=\""+RDEscapeString(codename)+"\""; + q=new RDSqlQuery(sql); + delete q; + item->setSelected(false); + delete item; +} + + +void ListSchedCodes::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListSchedCodes::closeData() +{ + done(0); +} + + +void ListSchedCodes::resizeEvent(QResizeEvent *e) +{ + list_add_button->setGeometry(size().width()-90,30,80,50); + list_edit_button->setGeometry(size().width()-90,90,80,50); + list_delete_button->setGeometry(size().width()-90,210,80,50); + list_close_button->setGeometry(size().width()-90,size().height()-60,80,50); + list_schedCodes_view->setGeometry(10,30,size().width()-120,size().height()-40); +} + + +void ListSchedCodes::RefreshList() +{ + QString sql; + RDSqlQuery *q; + QListViewItem *item; + + list_schedCodes_view->clear(); + q=new RDSqlQuery("select CODE,DESCRIPTION from SCHED_CODES",0); + while (q->next()) { + item=new QListViewItem(list_schedCodes_view); + WriteItem(item,q); + } + delete q; +} + + +void ListSchedCodes::RefreshItem(QListViewItem *item) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select CODE,DESCRIPTION from SCHED_CODES where CODE=\"%s\"", + (const char *)item->text(0)); + q=new RDSqlQuery(sql); + if(q->next()) { + WriteItem(item,q); + } + delete q; +} + + +void ListSchedCodes::WriteItem(QListViewItem *item,RDSqlQuery *q) +{ + item->setText(0,q->value(0).toString()); + item->setText(1,q->value(1).toString()); +} + diff --git a/rdadmin/list_schedcodes.h b/rdadmin/list_schedcodes.h new file mode 100644 index 00000000..06198c0f --- /dev/null +++ b/rdadmin/list_schedcodes.h @@ -0,0 +1,67 @@ +// List_schedcodes.h +// +// The scheduler codes dialog for rdadmin +// +// Stefan Gabriel +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_SCHEDCODES_H +#define LIST_SCHEDCODES_H + +#include +#include +#include +#include + +#include +#include + + +class ListSchedCodes : public QDialog +{ + Q_OBJECT + public: + ListSchedCodes(QWidget *parent=0,const char *name=0); + ~ListSchedCodes(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void closeData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshList(); + void RefreshItem(QListViewItem *item); + void WriteItem(QListViewItem *item,RDSqlQuery *q); + QListView *list_schedCodes_view; + QPushButton *list_add_button; + QPushButton *list_edit_button; + QPushButton *list_delete_button; + QPushButton *list_close_button; +}; + + + +#endif // LIST_SCHEDCODES_H diff --git a/rdadmin/list_stations.cpp b/rdadmin/list_stations.cpp new file mode 100644 index 00000000..5dfc7601 --- /dev/null +++ b/rdadmin/list_stations.cpp @@ -0,0 +1,333 @@ +// list_stations.cpp +// +// List Rivendell Workstations +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: list_stations.cpp,v 1.28.6.1 2013/03/09 00:21:12 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +ListStations::ListStations(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Rivendell Workstation List")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Add Button + // + QPushButton *add_button=new QPushButton(this,"add_button"); + add_button->setGeometry(410,30,80,50); + add_button->setFont(font); + add_button->setText(tr("&Add")); + connect(add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + QPushButton *edit_button=new QPushButton(this,"edit_button"); + edit_button->setGeometry(410,90,80,50); + edit_button->setFont(font); + edit_button->setText(tr("&Edit")); + connect(edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + QPushButton *delete_button=new QPushButton(this,"delete_button"); + delete_button->setGeometry(410,150,80,50); + delete_button->setFont(font); + delete_button->setText(tr("&Delete")); + connect(delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Close Button + // + QPushButton *close_button=new QPushButton(this,"close_button"); + close_button->setGeometry(410,240,80,50); + close_button->setDefault(true); + close_button->setFont(font); + close_button->setText(tr("&Close")); + connect(close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Station List Box + // + list_box=new QListBox(this,"list_box"); + list_box->setGeometry(10,30,390,260); + QLabel *list_box_label=new QLabel(list_box,tr("Ho&sts:"), + this,"list_box_label"); + list_box_label->setFont(font); + list_box_label->setGeometry(14,10,85,19); + connect(list_box,SIGNAL(doubleClicked(QListBoxItem *)), + this,SLOT(doubleClickedData(QListBoxItem *))); + + RefreshList(); +} + + +ListStations::~ListStations() +{ + delete list_box; +} + + +QSize ListStations::sizeHint() const +{ + return QSize(500,300); +} + + +QSizePolicy ListStations::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListStations::addData() +{ + QString stationname; + + AddStation *add_station=new AddStation(&stationname,this,"add_station"); + if(add_station->exec()<0) { + DeleteStation(stationname); + delete add_station; + return; + } + delete add_station; + RefreshList(stationname); +} + + +void ListStations::editData() +{ + if(list_box->currentItem()<0) { + return; + } + EditStation *edit_station=new EditStation(list_box->currentText(), + this,"edit_station"); + edit_station->exec(); + delete edit_station; +} + + +void ListStations::deleteData() +{ + QString str; + + str=QString(tr("Are you sure you want to delete host")); + if(QMessageBox::warning(this,tr("Delete Station"), + QString().sprintf( + "%s %s?",(const char *)str, + (const char *)list_box->currentText()), + QMessageBox::Yes,QMessageBox::No)== + QMessageBox::Yes) { + DeleteStation(list_box->currentText()); + list_box->removeItem(list_box->currentItem()); + if(list_box->currentItem()>=0) { + list_box->setSelected(list_box->currentItem(),true); + } + } +} + + +void ListStations::closeData() +{ + done(0); +} + + +void ListStations::doubleClickedData(QListBoxItem *item) +{ + editData(); +} + + +void ListStations::RefreshList(QString stationname) +{ + QString sql; + RDSqlQuery *q; + + list_box->clear(); + q=new RDSqlQuery("select NAME from STATIONS",0); + while (q->next()) { + list_box->insertItem(q->value(0).toString()); + if(stationname==list_box->text(list_box->count()-1)) { + list_box->setCurrentItem(list_box->count()-1); + } + } + delete q; +} + + +void ListStations::DeleteStation(QString name) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + sql=QString().sprintf("delete from DECKS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from TTYS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from AUDIO_PORTS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from RECORDINGS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql= + QString().sprintf("delete from SERVICE_PERMS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from RDAIRPLAY where STATION=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from RDAIRPLAY_CHANNELS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from RDPANEL where STATION=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from RDPANEL_CHANNELS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from RDLOGEDIT where STATION=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from MATRICES where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from INPUTS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from OUTPUTS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from VGUEST_RESOURCES where\ + STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from RDLIBRARY where STATION=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from GPIS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from HOSTVARS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from STATIONS where NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql= + QString().sprintf("delete from REPORT_STATIONS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from PANELS where (TYPE=%d && OWNER=\"%s\")", + RDAirPlayConf::StationPanel, + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString(). + sprintf("delete from EXTENDED_PANELS where (TYPE=%d && OWNER=\"%s\")", + RDAirPlayConf::StationPanel,(const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("select ID from ENCODERS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("delete from ENCODER_CHANNELS where ENCODER_ID=%d", + q->value(0).toInt()); + q1=new RDSqlQuery(sql); + delete q1; + sql=QString().sprintf("delete from ENCODER_SAMPLERATES where ENCODER_ID=%d", + q->value(0).toInt()); + q1=new RDSqlQuery(sql); + delete q1; + sql=QString().sprintf("delete from ENCODER_BITRATES where ENCODER_ID=%d", + q->value(0).toInt()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + sql=QString().sprintf("delete from ENCODERS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from RDHOTKEYS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; +} + diff --git a/rdadmin/list_stations.h b/rdadmin/list_stations.h new file mode 100644 index 00000000..3cdacc72 --- /dev/null +++ b/rdadmin/list_stations.h @@ -0,0 +1,59 @@ +// list_stations.h +// +// List Rivendell Stations +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: list_stations.h,v 1.9 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_STATIONS_H +#define LIST_STATIONS_H + +#include +#include +#include +#include +#include +#include + + +class ListStations : public QDialog +{ + Q_OBJECT + public: + ListStations(QWidget *parent=0,const char *name=0); + ~ListStations(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void doubleClickedData(QListBoxItem *item); + void closeData(); + + private: + void RefreshList(QString stationname=""); + void DeleteStation(QString name); + QListBox *list_box; +}; + + +#endif + + diff --git a/rdadmin/list_svcs.cpp b/rdadmin/list_svcs.cpp new file mode 100644 index 00000000..747a0776 --- /dev/null +++ b/rdadmin/list_svcs.cpp @@ -0,0 +1,227 @@ +// list_svcs.cpp +// +// List Rivendell Services +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: list_svcs.cpp,v 1.26 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +ListSvcs::ListSvcs(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Services")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Add Button + // + QPushButton *add_button=new QPushButton(this,"add_button"); + add_button->setGeometry(100,30,80,50); + add_button->setFont(font); + add_button->setText(tr("&Add")); + connect(add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + QPushButton *edit_button=new QPushButton(this,"edit_button"); + edit_button->setGeometry(100,90,80,50); + edit_button->setFont(font); + edit_button->setText(tr("&Edit")); + connect(edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + QPushButton *delete_button=new QPushButton(this,"delete_button"); + delete_button->setGeometry(100,150,80,50); + delete_button->setFont(font); + delete_button->setText(tr("&Delete")); + connect(delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Close Button + // + QPushButton *close_button=new QPushButton(this,"close_button"); + close_button->setGeometry(100,240,80,50); + close_button->setDefault(true); + close_button->setFont(font); + close_button->setText(tr("&Close")); + connect(close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Services List Box + // + list_box=new QListBox(this,"list_box"); + list_box->setGeometry(10,30,80,260); + QLabel *list_box_label=new QLabel(list_box,tr("&Services:"), + this,"list_box_label"); + list_box_label->setFont(font); + list_box_label->setGeometry(14,11,85,19); + connect(list_box,SIGNAL(doubleClicked(QListBoxItem *)), + this,SLOT(doubleClickedData(QListBoxItem *))); + + RefreshList(); +} + + +ListSvcs::~ListSvcs() +{ + delete list_box; +} + + +QSize ListSvcs::sizeHint() const +{ + return QSize(200,300); +} + + +QSizePolicy ListSvcs::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListSvcs::addData() +{ + QString svcname; + + AddSvc *add_svc=new AddSvc(&svcname,this,"add_svc"); + if(add_svc->exec()<0) { + delete add_svc; + return; + } + delete add_svc; + RefreshList(svcname); +} + + +void ListSvcs::editData() +{ + if(list_box->currentItem()<0) { + return; + } + EditSvc *edit_svc=new EditSvc(list_box->currentText(),this,"edit_svc"); + edit_svc->exec(); + delete edit_svc; +} + + +void ListSvcs::deleteData() +{ + QString str1; + QString str2; + QString sql; + RDSqlQuery *q; + + str1=QString(tr("Are you sure you want to delete service")); + if(QMessageBox::warning(this,tr("Delete Service"), + QString().sprintf( + "%s %s?",(const char *)str1, + (const char *)list_box->currentText()), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + return; + } + sql=QString().sprintf("select NAME from LOGS where SERVICE=\"%s\"", + (const char *)list_box->currentText()); + q=new RDSqlQuery(sql); + if(q->first()) { + str1=tr("There are"); + str2=tr("logs owned by this service that will also be deleted.\nDo you still want to proceed?"); + if(QMessageBox::warning(this,tr("Logs Exist"), + QString().sprintf("%s %d %s", + (const char *)str1, + q->size(), + (const char *)str2), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + delete q; + return; + } + } + delete q; + RDSvc *svc=new RDSvc(list_box->currentText()); + svc->remove(); + delete svc; + list_box->removeItem(list_box->currentItem()); + if(list_box->currentItem()>=0) { + list_box->setSelected(list_box->currentItem(),true); + } +} + + +void ListSvcs::closeData() +{ + done(0); +} + + +void ListSvcs::doubleClickedData(QListBoxItem *item) +{ + editData(); +} + + +void ListSvcs::RefreshList(QString svcname) +{ + QString sql; + RDSqlQuery *q; + + list_box->clear(); + q=new RDSqlQuery("select NAME from SERVICES"); + while (q->next()) { + list_box->insertItem(q->value(0).toString()); + if(svcname==list_box->text(list_box->count()-1)) { + list_box->setCurrentItem(list_box->count()-1); + } + } + delete q; +} diff --git a/rdadmin/list_svcs.h b/rdadmin/list_svcs.h new file mode 100644 index 00000000..231de4c3 --- /dev/null +++ b/rdadmin/list_svcs.h @@ -0,0 +1,58 @@ +// list_svcs.h +// +// List Rivendell Services +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: list_svcs.h,v 1.10 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_SVCS_H +#define LIST_SVCS_H + +#include +#include +#include +#include +#include +#include + + +class ListSvcs : public QDialog +{ + Q_OBJECT + public: + ListSvcs(QWidget *parent=0,const char *name=0); + ~ListSvcs(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void doubleClickedData(QListBoxItem *); + void closeData(); + + private: + void RefreshList(QString svcname=""); + QListBox *list_box; +}; + + +#endif + + diff --git a/rdadmin/list_users.cpp b/rdadmin/list_users.cpp new file mode 100644 index 00000000..11122e62 --- /dev/null +++ b/rdadmin/list_users.cpp @@ -0,0 +1,345 @@ +// list_users.cpp +// +// List Rivendell Users +// +// (C) Copyright 2002-2008 Fred Gleason +// +// $Id: list_users.cpp,v 1.24 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +// +// Icons +// +#include "../icons/admin.xpm" +#include "../icons/user.xpm" + +ListUsers::ListUsers(const QString &admin_name,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + list_admin_name=admin_name; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + setCaption(tr("Rivendell User List")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont list_font=QFont("Helvetica",12,QFont::Normal); + list_font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Create Icons + // + list_admin_map=new QPixmap(admin_xpm); + list_user_map=new QPixmap(user_xpm); + + // + // Add Button + // + list_add_button=new QPushButton(this,"list_add_button"); + list_add_button->setFont(font); + list_add_button->setText(tr("&Add")); + connect(list_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + list_edit_button=new QPushButton(this,"list_edit_button"); + list_edit_button->setFont(font); + list_edit_button->setText(tr("&Edit")); + connect(list_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + list_delete_button=new QPushButton(this,"list_delete_button"); + list_delete_button->setFont(font); + list_delete_button->setText(tr("&Delete")); + connect(list_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Close Button + // + list_close_button=new QPushButton(this,"list_close_button"); + list_close_button->setDefault(true); + list_close_button->setFont(font); + list_close_button->setText(tr("&Close")); + connect(list_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // User List + // + list_users_view=new RDListView(this,"list_users_view"); + list_users_view->setFont(list_font); + list_users_view->setAllColumnsShowFocus(true); + list_users_view->setItemMargin(5); + list_users_view->addColumn(""); + list_users_view->addColumn(tr("USER NAME")); + list_users_view->addColumn(tr("FULL NAME")); + list_users_view->addColumn(tr("DESCRIPTION")); + QLabel *list_box_label=new QLabel(list_users_view,tr("&Users:"), + this,"list_box_label"); + list_box_label->setFont(font); + list_box_label->setGeometry(14,11,85,19); + connect(list_users_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + RefreshList(); +} + + +ListUsers::~ListUsers() +{ +} + + +QSize ListUsers::sizeHint() const +{ + return QSize(640,480); +} + + +QSizePolicy ListUsers::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListUsers::addData() +{ + QString user; + + AddUser *add_user=new AddUser(&user,this,"add_user"); + if(add_user->exec()<0) { + delete add_user; + return; + } + delete add_user; + add_user=NULL; + RDListViewItem *item=new RDListViewItem(list_users_view); + item->setText(1,user); + RefreshItem(item); + item->setSelected(true); + list_users_view->setCurrentItem(item); + list_users_view->ensureItemVisible(item); +} + + +void ListUsers::editData() +{ + RDListViewItem *item=(RDListViewItem *)list_users_view->selectedItem(); + if(item==NULL) { + return; + } + EditUser *edit_user=new EditUser(item->text(1),this,"edit_user"); + if(edit_user->exec()==0) { + RefreshItem(item); + } + delete edit_user; +} + + +void ListUsers::deleteData() +{ + RDListViewItem *item=(RDListViewItem *)list_users_view->selectedItem(); + if(item==NULL) { + return; + } + + if(list_admin_name==item->text(1)) { + QMessageBox::warning(this,tr("Delete User"), + tr("You cannot delete yourself!")); + return; + } + + QString sql; + RDSqlQuery *q; + QString warning; + QString str; + + QString username=RDEscapeString(item->text(1)); + + // + // Check for default user assignments + // + sql=QString().sprintf("select NAME from STATIONS where DEFAULT_NAME=\"%s\"", + (const char *)username); + q=new RDSqlQuery(sql); + if(q->size()>0) { + str=tr("This user is set as the default user for the following hosts:\n\n"); + while(q->next()) { + str+=(" "+q->value(0).toString()+"\n"); + } + str+="\n"; + str+=tr("You must change this before deleting the user."); + delete q; + QMessageBox::warning(this,tr("Delete User"),str); + return; + } + delete q; + + str=QString(tr("Are you sure you want to delete user")); + warning+=QString().sprintf("%s \"%s\"?",(const char *)str, + (const char *)item->text(1)); + switch(QMessageBox::warning(this,tr("Delete User"),warning, + QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + return; + + default: + break; + } + + // + // Delete RSS Feed Perms + // + sql=QString().sprintf("delete from FEED_PERMS where USER_NAME=\"%s\"", + (const char *)username); + q=new RDSqlQuery(sql); + delete q; + + // + // Delete Member User Perms + // + sql=QString().sprintf("delete from USER_PERMS where USER_NAME=\"%s\"", + (const char *)username); + q=new RDSqlQuery(sql); + delete q; + + // + // Delete from User List + // + sql=QString().sprintf("delete from USERS where LOGIN_NAME=\"%s\"", + (const char *)username); + q=new RDSqlQuery(sql); + delete q; + + // + // Delete from Cached Web Connections + // + sql=QString().sprintf("delete from WEB_CONNECTIONS where LOGIN_NAME=\"%s\"", + (const char *)username); + q=new RDSqlQuery(sql); + delete q; + + item->setSelected(false); + delete item; +} + + +void ListUsers::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListUsers::closeData() +{ + done(0); +} + + +void ListUsers::resizeEvent(QResizeEvent *e) +{ + list_add_button->setGeometry(size().width()-90,30,80,50); + list_edit_button->setGeometry(size().width()-90,90,80,50); + list_delete_button->setGeometry(size().width()-90,150,80,50); + list_close_button->setGeometry(size().width()-90,size().height()-60,80,50); + list_users_view->setGeometry(10,30,size().width()-120,size().height()-40); +} + + +void ListUsers::RefreshList() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + list_users_view->clear(); + sql="select ADMIN_CONFIG_PRIV,LOGIN_NAME,FULL_NAME,DESCRIPTION from USERS"; + q=new RDSqlQuery(sql); + while (q->next()) { + item=new RDListViewItem(list_users_view); + if(q->value(0).toString()=="Y") { + item->setPixmap(0,*list_admin_map); + } + else { + item->setPixmap(0,*list_user_map); + } + item->setText(1,q->value(1).toString()); + item->setText(2,q->value(2).toString()); + item->setText(3,q->value(3).toString()); + } + delete q; +} + + +void ListUsers::RefreshItem(RDListViewItem *item) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select ADMIN_CONFIG_PRIV,FULL_NAME,DESCRIPTION \ + from USERS where LOGIN_NAME=\"%s\"", + (const char *)RDEscapeString(item->text(1))); + q=new RDSqlQuery(sql); + if(q->first()) { + if(q->value(0).toString()=="Y") { + item->setPixmap(0,*list_admin_map); + } + else { + item->setPixmap(0,*list_user_map); + } + item->setText(2,q->value(1).toString()); + item->setText(3,q->value(2).toString()); + } + delete q; +} diff --git a/rdadmin/list_users.h b/rdadmin/list_users.h new file mode 100644 index 00000000..e4b117aa --- /dev/null +++ b/rdadmin/list_users.h @@ -0,0 +1,72 @@ +// list_users.h +// +// List Rivendell Users +// +// (C) Copyright 2002-2008 Fred Gleason +// +// $Id: list_users.h,v 1.11 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_USERS_H +#define LIST_USERS_H + +#include +#include +#include +#include +#include +#include + +#include +#include + + +class ListUsers : public QDialog +{ + Q_OBJECT + public: + ListUsers(const QString &admin_name,QWidget *parent=0,const char *name=0); + ~ListUsers(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void closeData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshList(); + void RefreshItem(RDListViewItem *item); + RDListView *list_users_view; + QPushButton *list_add_button; + QPushButton *list_edit_button; + QPushButton *list_delete_button; + QPushButton *list_close_button; + QString list_admin_name; + QPixmap *list_admin_map; + QPixmap *list_user_map; +}; + + +#endif + + diff --git a/rdadmin/list_vguest_resources.cpp b/rdadmin/list_vguest_resources.cpp new file mode 100644 index 00000000..f2a14814 --- /dev/null +++ b/rdadmin/list_vguest_resources.cpp @@ -0,0 +1,371 @@ +// list_vguest_resources.cpp +// +// List vGuest Resources. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: list_vguest_resources.cpp,v 1.7 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +ListVguestResources::ListVguestResources(RDMatrix *matrix, + RDMatrix::VguestType type,int size, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + QString str; + + list_matrix=matrix; + list_type=type; + list_size=size; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Resources List Box + // + list_list_view=new QListView(this,"list_box"); + list_list_view-> + setGeometry(10,24,sizeHint().width()-20,sizeHint().height()-94); + QLabel *label= + new QLabel(list_list_view,list_table,this,"list_list_view_label"); + label->setFont(bold_font); + label->setGeometry(14,5,85,19); + list_list_view->setAllColumnsShowFocus(true); + list_list_view->setItemMargin(5); + switch(list_type) { + case RDMatrix::VguestTypeRelay: + + setCaption(tr("vGuest Switches")); + list_list_view->addColumn(tr("GPIO LINE")); + break; + + case RDMatrix::VguestTypeDisplay: + setCaption(tr("vGuest Displays")); + list_list_view->addColumn(tr("DISPLAY")); + break; + } + list_list_view->setColumnAlignment(0,Qt::AlignHCenter); + list_list_view->addColumn(tr("ENGINE (Hex)")); + list_list_view->setColumnAlignment(1,Qt::AlignHCenter); + list_list_view->addColumn(tr("DEVICE (Hex)")); + list_list_view->setColumnAlignment(2,Qt::AlignHCenter); + switch(list_type) { + case RDMatrix::VguestTypeRelay: + list_list_view->addColumn(tr("SURFACE (Hex)")); + list_list_view->setColumnAlignment(3,Qt::AlignHCenter); + list_list_view->addColumn(tr("BUS/RELAY (Hex)")); + list_list_view->setColumnAlignment(4,Qt::AlignHCenter); + break; + + case RDMatrix::VguestTypeDisplay: + list_list_view->addColumn(tr("SURFACE (Hex)")); + list_list_view->setColumnAlignment(3,Qt::AlignHCenter); + break; + } + connect(list_list_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + // + // Edit Button + // + QPushButton *button=new QPushButton(this,"edit_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Edit")); + connect(button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Values + // + RefreshList(); +} + + +QSize ListVguestResources::sizeHint() const +{ + return QSize(400,250); +} + + +QSizePolicy ListVguestResources::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListVguestResources::editData() +{ + int engine_num=-1; + int device_num=-1; + int surface_num=-1; + int relay_num=-1; + + QListViewItem *item=list_list_view->selectedItem(); + if(item==NULL) { + return; + } + if(!item->text(1).isEmpty()) { + engine_num=item->text(1).toInt(NULL,16); + } + if(!item->text(2).isEmpty()) { + device_num=item->text(2).toInt(NULL,16); + } + if(!item->text(3).isEmpty()) { + surface_num=item->text(3).toInt(NULL,16); + } + switch(list_type) { + case RDMatrix::VguestTypeRelay: + if(!item->text(4).isEmpty()) { + relay_num=item->text(4).toInt(NULL,16); + } + break; + + case RDMatrix::VguestTypeDisplay: + break; + } + EditVguestResource *dialog=new EditVguestResource(list_type,&engine_num, + &device_num,&surface_num, + &relay_num, + this,"dialog"); + if(dialog->exec()==0) { + if(engine_num>=0) { + item->setText(1,QString().sprintf("%04X",engine_num)); + } + else { + item->setText(1,""); + } + if(device_num>=0) { + item->setText(2,QString().sprintf("%04X",device_num)); + } + else { + item->setText(2,""); + } + if(surface_num>=0) { + item->setText(3,QString().sprintf("%04X",surface_num)); + } + else { + item->setText(3,""); + } + switch(list_type) { + case RDMatrix::VguestTypeRelay: + if(relay_num>=0) { + item->setText(4,QString().sprintf("%04X",relay_num)); + } + else { + item->setText(4,""); + } + break; + + case RDMatrix::VguestTypeDisplay: + break; + } + } + delete dialog; +} + + +void ListVguestResources::doubleClickedData(QListViewItem *item, + const QPoint &pt,int col) +{ + editData(); +} + + +void ListVguestResources::okData() +{ + QString sql; + RDSqlQuery *q; + int engine_num=-1; + int device_num=-1; + int surface_num=-1; + int relay_num=-1; + + QListViewItem *item=list_list_view->firstChild(); + while(item!=NULL) { + engine_num=-1; + device_num=-1; + surface_num=-1; + relay_num=-1; + if(!item->text(1).isEmpty()) { + engine_num=item->text(1).toInt(NULL,16); + } + if(!item->text(2).isEmpty()) { + device_num=item->text(2).toInt(NULL,16); + } + if(!item->text(3).isEmpty()) { + surface_num=item->text(3).toInt(NULL,16); + } + switch(list_type) { + case RDMatrix::VguestTypeRelay: + if(!item->text(4).isEmpty()) { + relay_num=item->text(4).toInt(NULL,16); + } + break; + + case RDMatrix::VguestTypeDisplay: + break; + } + sql=QString().sprintf("select ID from VGUEST_RESOURCES where\ + (STATION_NAME=\"%s\")&&\ + (MATRIX_NUM=%d)&&\ + (VGUEST_TYPE=%d)&&\ + (NUMBER=%d)", + (const char *)list_matrix->station(), + list_matrix->matrix(),list_type, + item->text(0).toInt()); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("update VGUEST_RESOURCES set\ + ENGINE_NUM=%d,DEVICE_NUM=%d,\ + SURFACE_NUM=%d,RELAY_NUM=%d\ + where\ + (STATION_NAME=\"%s\")&&\ + (MATRIX_NUM=%d)&&\ + (VGUEST_TYPE=%d)&&\ + (NUMBER=%d)", + engine_num,device_num,surface_num, + relay_num, + (const char *)list_matrix->station(), + list_matrix->matrix(), + list_type,item->text(0).toInt()); + } + else { + sql=QString().sprintf("insert into VGUEST_RESOURCES set\ + STATION_NAME=\"%s\",MATRIX_NUM=%d,\ + VGUEST_TYPE=%d,NUMBER=%d,\ + ENGINE_NUM=%d,DEVICE_NUM=%d,\ + SURFACE_NUM=%d,RELAY_NUM=%d", + (const char *)list_matrix->station(), + list_matrix->matrix(), + list_type,item->text(0).toInt(), + engine_num,device_num,surface_num, + relay_num); + } + delete q; + q=new RDSqlQuery(sql); + delete q; + item=item->nextSibling(); + } + done(0); +} + + +void ListVguestResources::cancelData() +{ + done(-1); +} + + +void ListVguestResources::RefreshList() +{ + QString sql; + RDSqlQuery *q; + QListViewItem *item; + int n=1; + + sql=QString().sprintf("select NUMBER,ENGINE_NUM,DEVICE_NUM,SURFACE_NUM,\ + RELAY_NUM,BUSS_NUM from VGUEST_RESOURCES where\ + (STATION_NAME=\"%s\")&&(MATRIX_NUM=%d)&&\ + (VGUEST_TYPE=%d) order by NUMBER", + (const char *)list_matrix->station(), + list_matrix->matrix(), + list_type); + q=new RDSqlQuery(sql); + list_list_view->clear(); + while(q->next()) { + while(q->value(0).toInt()>n) { + item=new QListViewItem(list_list_view); + item->setText(0,QString().sprintf("%03d",n++)); + } + item=new QListViewItem(list_list_view); + item->setText(0,QString().sprintf("%03d",q->value(0).toInt())); + if(q->value(1).toInt()>=0) { + item->setText(1,QString().sprintf("%04X",q->value(1).toInt())); + } + if(q->value(2).toInt()>=0) { + item->setText(2,QString().sprintf("%04X",q->value(2).toInt())); + } + if(q->value(3).toInt()>=0) { + item->setText(3,QString().sprintf("%04X",q->value(3).toInt())); + } + switch(list_type) { + case RDMatrix::VguestTypeRelay: + if(q->value(4).toInt()>=0) { + item->setText(4,QString().sprintf("%04X",q->value(4).toInt())); + } + break; + + case RDMatrix::VguestTypeDisplay: + break; + } + n++; + } + for(int i=n;i<(list_size+1);i++) { + item=new QListViewItem(list_list_view); + item->setText(0,QString().sprintf("%03d",i)); + } + delete q; +} diff --git a/rdadmin/list_vguest_resources.h b/rdadmin/list_vguest_resources.h new file mode 100644 index 00000000..b919aad6 --- /dev/null +++ b/rdadmin/list_vguest_resources.h @@ -0,0 +1,61 @@ +// list_vguest_resources.h +// +// List vGuest Resources +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: list_vguest_resources.h,v 1.5 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_VGUEST_RESOURCES_H +#define LIST_VGUEST_RESOURCES_H + +#include +#include +#include +#include +#include + +#include +#include + + +class ListVguestResources : public QDialog +{ + Q_OBJECT + public: + ListVguestResources(RDMatrix *matrix,RDMatrix::VguestType type,int size, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void editData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void okData(); + void cancelData(); + + private: + void RefreshList(); + RDMatrix *list_matrix; + RDMatrix::VguestType list_type; + QListView *list_list_view; + int list_size; + QString list_table; +}; + + +#endif // LIST_VGUEST_RESOURCES_H diff --git a/rdadmin/login.cpp b/rdadmin/login.cpp new file mode 100644 index 00000000..15f16ece --- /dev/null +++ b/rdadmin/login.cpp @@ -0,0 +1,156 @@ +// login.cpp +// +// Login widget for RDAdmin. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: login.cpp,v 1.14 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + +Login::Login(QString *username,QString *password,QWidget *parent, + const char *name) : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Login")); + login_name=username; + login_password=password; + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // OK Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(10,60,100,55); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + ok_button->setDefault(true); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // CANCEL Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(120,60,100,55); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Login Name + // + login_name_edit=new QLineEdit(this,"login_name_edit"); + login_name_edit->setGeometry(100,10,100,19); + login_name_edit->setMaxLength(16); + login_name_edit->setFocus(); + login_name_edit->setValidator(validator); + QLabel *login_name_label=new QLabel(login_name_edit,tr("User &Name:"),this, + "login_name_label"); + login_name_label->setGeometry(10,10,85,19); + login_name_label->setFont(font); + login_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Login Password + // + login_password_edit=new QLineEdit(this,"login_password_edit"); + login_password_edit->setGeometry(100,31,100,19); + login_password_edit->setMaxLength(16); + login_password_edit->setEchoMode(QLineEdit::Password); + login_password_edit->setValidator(validator); + QLabel *login_password_label=new QLabel(login_password_edit,tr("&Password:"), + this,"login_password_label"); + login_password_label->setGeometry(10,31,85,19); + login_password_label->setFont(font); + login_password_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + +} + + +Login::~Login() +{ + delete login_name_edit; + delete login_password_edit; +} + + +QSize Login::sizeHint() const +{ + return QSize(230,125); +} + + +QSizePolicy Login::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void Login::okData() +{ + *login_name=login_name_edit->text(); + *login_password=login_password_edit->text(); + done(0); +} + + +void Login::cancelData() +{ + done(1); +} + + +void Login::paintEvent(QPaintEvent *paintevent) +{ + QPainter *p=new QPainter(this); + + p->end(); +} diff --git a/rdadmin/login.h b/rdadmin/login.h new file mode 100644 index 00000000..973b055b --- /dev/null +++ b/rdadmin/login.h @@ -0,0 +1,59 @@ +// login.h +// +// Login Widget for RDAdmin. +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: login.h,v 1.6 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LOGIN_H +#define LOGIN_H + +#include +#include +#include +#include +#include + + + +class Login : public QDialog +{ + Q_OBJECT + public: + Login(QString *username,QString *password,QWidget *parent=0,const char *name=0); + ~Login(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + void paintEvent(QPaintEvent *); + + private slots: + void okData(); + void cancelData(); + + private: + QString *login_name; + QLineEdit *login_name_edit; + QString *login_password; + QLineEdit *login_password_edit; +}; + + +#endif + diff --git a/rdadmin/mysql_login.cpp b/rdadmin/mysql_login.cpp new file mode 100644 index 00000000..59071f07 --- /dev/null +++ b/rdadmin/mysql_login.cpp @@ -0,0 +1,143 @@ +// mysql_login.cpp +// +// mySQL Administrative Login widget for RDAdmin. +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: mysql_login.cpp,v 1.9 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + +MySqlLogin::MySqlLogin(QString msg,QString *username,QString *password, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + setCaption(tr("mySQL Admin")); + login_name=username; + login_password=password; + + // + // Create Fonts + // + QFont font=QFont("Helvetica",10,QFont::Normal); + font.setPixelSize(10); + + // + // Message Label + // + RDLabel *label=new RDLabel(msg,this,"message_label"); + label->setFont(font); + label->setGeometry(10,10,sizeHint().width()-20,sizeHint().height()-130); + label->setAlignment(AlignCenter); + + + // + // MySql Login Name + // + login_name_edit=new QLineEdit(this,"login_name_edit"); + login_name_edit->setFont(font); + login_name_edit->setGeometry(100,sizeHint().height()-110,100,19); + login_name_edit->setMaxLength(16); + login_name_edit->setFocus(); + QLabel *login_name_label=new QLabel(login_name_edit,tr("User &Name:"),this, + "login_name_label"); + login_name_label->setFont(font); + login_name_label->setGeometry(10,sizeHint().height()-109,85,19); + login_name_label->setAlignment(AlignRight|ShowPrefix); + + // + // MySql Login Password + // + login_password_edit=new QLineEdit(this,"login_password_edit"); + login_password_edit->setFont(font); + login_password_edit->setGeometry(100,sizeHint().height()-90,100,19); + login_password_edit->setMaxLength(16); + login_password_edit->setEchoMode(QLineEdit::Password); + QLabel *login_password_label=new QLabel(login_password_edit,tr("&Password:"), + this,"login_password_label"); + login_password_label->setFont(font); + login_password_label->setGeometry(10,sizeHint().height()-88,85,19); + login_password_label->setAlignment(AlignRight|ShowPrefix); + + // + // OK Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + ok_button->setDefault(true); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // CANCEL Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +MySqlLogin::~MySqlLogin() +{ + delete login_name_edit; + delete login_password_edit; +} + + +QSize MySqlLogin::sizeHint() const +{ + return QSize(360,210); +} + + +QSizePolicy MySqlLogin::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MySqlLogin::okData() +{ + *login_name=login_name_edit->text(); + *login_password=login_password_edit->text(); + done(0); +} + + +void MySqlLogin::cancelData() +{ + done(1); +} diff --git a/rdadmin/mysql_login.h b/rdadmin/mysql_login.h new file mode 100644 index 00000000..17822881 --- /dev/null +++ b/rdadmin/mysql_login.h @@ -0,0 +1,57 @@ +// mysql_login.h +// +// mySQL Administrative Login Widget for RDAdmin. +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: mysql_login.h,v 1.7 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef MYSQL_LOGIN_H +#define MYSQL_LOGIN_H + +#include +#include +#include +#include +#include + + + +class MySqlLogin : public QDialog +{ + Q_OBJECT + public: + MySqlLogin(QString msg,QString *username,QString *password, + QWidget *parent=0,const char *name=0); + ~MySqlLogin(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QString *login_name; + QLineEdit *login_name_edit; + QString *login_password; + QLineEdit *login_password_edit; +}; + + +#endif + diff --git a/rdadmin/opendb.cpp b/rdadmin/opendb.cpp new file mode 100644 index 00000000..13a7f932 --- /dev/null +++ b/rdadmin/opendb.cpp @@ -0,0 +1,441 @@ +// opendb.cpp +// +// Open a Rivendell Database +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: opendb.cpp,v 1.38.4.1 2013/11/13 00:12:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Includes used for netmask and remote server detection. +#include +#include +#include +#include + +#include + +/** + * Get the netmask of an interface and return it via an in_addr struct pointer. + * + * Note: uses linux IOCTL call SIOCGIFNETMASK to retrieve the netmask from a + * temporary socket. + * + * @param interface String with the interface to query. + * @param netmask Pointer to struct in_addr that will be populated with the netmask. + * @return true on success + **/ +bool get_netmask(const char * interface, struct in_addr * netmask) +{ + int fd; + struct ifreq ifr; + struct sockaddr_in *nmask; + + fd=socket(AF_INET, SOCK_DGRAM, 0); + ifr.ifr_addr.sa_family=AF_INET; + strncpy(ifr.ifr_name, interface, IFNAMSIZ-1); + ioctl(fd, SIOCGIFNETMASK, &ifr); + close(fd); + nmask=(struct sockaddr_in *)&ifr.ifr_netmask; + netmask->s_addr=nmask->sin_addr.s_addr; + return true; +} + + +/** + * Check if creating the database on the local machine or on a remote server in + * the same subnet. + * + * @param host QString with the hostname of machine to create the database. + * @return true if database is to be created on a remote server. + **/ +bool check_remote_server(QString host) { + char local_hostname[256]; + int rc; + struct hostent *temp_hostent; + struct hostent local_hostent; + struct hostent host_hostent; + struct in_addr local_ip; + struct in_addr host_ip; + struct in_addr local_netmask; + + // check if host is 'localhost' + if (0==strncasecmp("localhost", (const char *)host, 255)) + return false; + + rc=gethostname(local_hostname, 255); + // compare hostnames + if ((0==rc) && (0!=strncasecmp(local_hostname, (const char *)host, 255))) { + if ((temp_hostent=gethostbyname(local_hostname))) + local_hostent=*temp_hostent; + else + return false; + local_ip=*(struct in_addr *)temp_hostent->h_addr; + + if ((temp_hostent=gethostbyname((const char *)host))) + host_hostent=*temp_hostent; + else + return false; + host_ip=*(struct in_addr *)temp_hostent->h_addr; + + // compare IPs + if ((local_hostent.h_addrtype == AF_INET) && + (host_hostent.h_addrtype == AF_INET) && + (local_ip.s_addr != host_ip.s_addr)) { + // FIXME: ideally do something smarter than just testing eth0 (note use + // below in format_remote_host() also) + // get list of interfaces if_nameindex() + // loop through list of interfaces, get IP, see if it matches local IP + // once have good interface, get netmask + rc=get_netmask("eth0", &local_netmask); + + // compare if IPs are on same subnet. note: use of bitwise sum + if ( (local_ip.s_addr & local_netmask.s_addr) == + (host_ip.s_addr & local_netmask.s_addr) ) + return true; + } // endif compare IPs + } // endif compare hostnames + return false; +} + + +/** + * Format a QString with the MySQL host portion for a remote host. The + * resulting string will use the local subnet and mask to generate something + * like "192.168.1.0/255.255.255.0" . + * + * @param host string with the hostname to use for the subnet and mask. + * @return QString with formated result. + **/ +QString format_remote_host(const char *hostname) { + struct in_addr local_netmask; + struct hostent *temp_hostent; + struct in_addr local_ip; + struct in_addr local_subnet; + + temp_hostent=gethostbyname(hostname); + local_ip=*(struct in_addr *)temp_hostent->h_addr; + // FIXME: ideally do something smarter than just testing eth0 (see above in check_remote_server() also) + get_netmask("eth0", &local_netmask); + local_subnet.s_addr=(local_ip.s_addr & local_netmask.s_addr); + return QString().sprintf("%s/%s", strdupa(inet_ntoa(local_subnet)), strdupa(inet_ntoa(local_netmask)) ); +} + + +bool OpenDb(QString dbname,QString login,QString pwd, + QString host,QString stationname,bool interactive) +{ + // + // Yeesh, this whole method really needs a rewrite! + // They shoot horses, don't they?? + // + + int db_ver; + QString admin_name; + QString admin_pwd; + QString sql; + QSqlQuery *q; + QString msg; + MySqlLogin *mysql_login; + QString str; + int err=0; + QString err_str=""; + + // + // Open Database + // + QSqlDatabase *db=QSqlDatabase::addDatabase(admin_config->mysqlDriver()); + if(!db) { + return false; + } + db->setDatabaseName(dbname); + db->setUserName(login); + db->setPassword(pwd); + db->setHostName(host); + if(!db->open()) { + /* + if(!interactive) { + return false; + } + */ + RDKillDaemons(); + if(interactive) { + msg=QObject::tr("Unable to access the Rivendell Database!\n\ +Please enter a login for an account with\n\ +administrative rights on the mySQL server,\n\ +and we will try to get this straightened out."); + mysql_login=new MySqlLogin(msg,&admin_name,&admin_pwd); + if(mysql_login->exec()!=0) { + delete mysql_login; + db->removeDatabase(dbname); + return false; + } + delete mysql_login; + } + else { + admin_name=admin_admin_username; + admin_pwd=admin_admin_password; + if(!admin_admin_hostname.isEmpty()) { + db->setHostName(admin_admin_hostname); + } + } + db->setUserName(admin_name); + db->setPassword(admin_pwd); + if(db->open()) { // Fixup DB Access Permsissions + PrintError(QObject::tr("Wrong access permissions for accessing mySQL!"), + interactive); + db->removeDatabase("mysql"); + return false; + } + else { + db->setDatabaseName("mysql"); + if(!db->open()) { // mySQL is hosed -- scream and die. + PrintError(QObject::tr("Unable to connect to mySQL!"),interactive); + db->removeDatabase("mysql"); + return false; + } + else { // Create a new Rivendell Database + sql=QString().sprintf("create database %s",(const char *)dbname); + q=new QSqlQuery(sql); + if(!q->isActive()) { // Can't create DB. + delete q; + PrintError(QObject::tr("Unable to create a Rivendell Database!"), + interactive); + db->removeDatabase("mysql"); + return false; + } + delete q; + + // Check if creating the database on the local machine or on a remote + // server in the same subnet. If creating on a remote server, set the + // host portion of the MySQL user to the subnet that is common between + // the local workstation and the server. + if (check_remote_server(host)) { + host=format_remote_host(host); + } + sql=QString().sprintf("insert into user set Host=\"%s\",\ + User=\"%s\",Password=PASSWORD(\"%s\")", + (const char *)host, (const char *)login,(const char *)pwd); + q=new QSqlQuery(sql); + delete q; + sql=QString(). + sprintf("insert into db set Host=\"%s\",Db=\"%s\",\ + User=\"%s\",Select_priv=\"Y\",Insert_priv=\"Y\",Update_priv=\"Y\",\ + Delete_priv=\"Y\",Create_priv=\"Y\",Drop_priv=\"Y\",\ + Index_priv=\"Y\",Alter_priv=\"Y\",Lock_tables_priv=\"Y\"", + (const char *)host, (const char *)dbname,(const char *)login); + q=new QSqlQuery(sql); + delete q; + q=new QSqlQuery("flush privileges"); + delete q; + db->close(); // Relinquish admin perms + if(!admin_admin_dbname.isEmpty()) { + dbname=admin_admin_dbname; + } + db->setDatabaseName(dbname); + db->setUserName(login); + db->setPassword(pwd); + db->setHostName(host); + if(!db->open()) { // Can't open new database + PrintError(QObject::tr("Unable to connect to new Rivendell Database!"), + interactive); + db->removeDatabase(dbname); + return false; + } + if(!CreateDb(login,pwd)) { // Can't create tables. + PrintError(QObject::tr("Unable to create Rivendell Database!"), + interactive); + db->removeDatabase(dbname); + return false; + } + db->close(); + db->setDatabaseName(dbname); + db->setUserName(login); + db->setPassword(pwd); + if(!db->open()) { + PrintError(QObject::tr("Unable to connect to Rivendell Database!"), + interactive); + db->removeDatabase(dbname); + return false; + } + if(!InitDb(login,pwd,stationname)) { // Can't initialize tables. + PrintError(QObject::tr("Unable to initialize Rivendell Database!"), + interactive); + db->removeDatabase(dbname); + return false; + } + if(interactive) { + QMessageBox::information(NULL,QObject::tr("RDAdmin"), + QObject::tr("New Rivendell Database Created!")); + } + return true; + } + } + return false; + } + if((db_ver=RDCheckVersion())exec()!=0) { + delete mysql_login; + db->removeDatabase(dbname); + return false; + } + delete mysql_login; + } + else { + admin_name=admin_admin_username; + admin_pwd=admin_admin_password; + } + RDKillDaemons(); + db->close(); + db->setDatabaseName("mysql"); + db->setUserName(admin_name); + db->setPassword(admin_pwd); + if(!db->open()) { + PrintError(QObject::tr("Unable to log into Administrator account!"), + interactive); + db->removeDatabase(dbname); + return false; + } + q=new QSqlQuery(QString().sprintf ("drop database %s",(const char *)dbname)); + delete q; + q=new QSqlQuery(QString().sprintf("create database %s",(const char *)dbname)); + if(!q->isActive()) { // Can't create DB. + delete q; + PrintError(QObject::tr("Unable to create a Rivendell Database!"), + interactive); + db->removeDatabase("mysql"); + return false; + } + delete q; + sql=QString(). + sprintf("grant all on %s to %s identified by \"%s\"", + (const char *)dbname,(const char *)login,(const char *)pwd); + q=new QSqlQuery(sql); + if(!q->isActive()) { // Can't authorize DB. + PrintError(QObject::tr("Unable to authorize a Rivendell Database!"), + interactive); + db->removeDatabase("mysql"); + return false; + } + db->close(); // Relinquish admin perms + db->setDatabaseName(dbname); + db->setUserName(login); + db->setPassword(pwd); + if(!db->open()) { // Can't open new database + PrintError(QObject::tr("Unable to connect to new Rivendell Database!"), + interactive); + db->removeDatabase(dbname); + return false; + } + if(!CreateDb(login,pwd)) { // Can't create tables. + PrintError(QObject::tr("Unable to create Rivendell Database!"), + interactive); + db->removeDatabase(dbname); + return false; + } + db->close(); + db->setDatabaseName(dbname); + db->setUserName(login); + db->setPassword(pwd); + if(!db->open()) { + PrintError(QObject::tr("Unable to connect to Rivendell Database!"), + interactive); + db->removeDatabase(dbname); + return false; + } + if(!InitDb(login,pwd,stationname)) { // Can't initialize tables. + PrintError(QObject::tr("Unable to initialize Rivendell Database!"), + interactive); + db->removeDatabase(dbname); + return false; + } + } + else { // Out-of-date version + if(interactive) { + if(QMessageBox::warning(NULL,QObject::tr("Update Needed"), + QObject::tr("The Rivendell Database needs to be updated.\n\ +All audio and settings will be preserved, but\n\ +this will STOP any audio playout or recording\n\ +on this machine for a few seconds. Continue?"), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + db->removeDatabase(dbname); + return false; + } + } + RDKillDaemons(); + if((err=UpdateDb(db_ver))!=UPDATEDB_SUCCESS) { + err_str=QObject::tr("Unable to update Rivendell Database:"); + switch(err) { + case UPDATEDB_BACKUP_FAILED: + err_str+=QObject::tr("\nDatabase backup failed!"); + break; + + case UPDATEDB_QUERY_FAILED: + err_str+=QObject::tr("\nSchema modification failed!"); + break; + + default: + err_str+=QObject::tr("\nUnknown/unspecified error!"); + break; + } + PrintError(err_str,interactive); + db->removeDatabase(dbname); + return false; + } + str=QString( + QObject::tr("The Rivendell Database has been updated to version")); + msg=QString(). + sprintf("%s %d",(const char *)str,RD_VERSION_DATABASE); + if(!admin_skip_backup) { + msg+=QObject::tr("\nand a backup of the original database saved in "); + msg+=admin_backup_filename; + } + msg+="."; + if(interactive) { + QMessageBox::information(NULL,QObject::tr("Database Updated"),msg); + } + } + } + + return true; +} diff --git a/rdadmin/opendb.h b/rdadmin/opendb.h new file mode 100644 index 00000000..78c09b5c --- /dev/null +++ b/rdadmin/opendb.h @@ -0,0 +1,34 @@ +// opendb.h +// +// Open a Rivendell Database +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: opendb.h,v 1.8 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef OPENDB_H +#define OPENDB_H + +#include + + +bool OpenDb(QString dbname,QString username,QString password,QString hostname, + QString stationname,bool interactive); + + +#endif + diff --git a/rdadmin/rdadmin.cpp b/rdadmin/rdadmin.cpp new file mode 100644 index 00000000..c1026dba --- /dev/null +++ b/rdadmin/rdadmin.cpp @@ -0,0 +1,663 @@ +// rdadmin.cpp +// +// The Administrator Utility for Rivendell. +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: rdadmin.cpp,v 1.72.4.7 2014/02/11 23:46:27 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// Icons +// +#include "../icons/rivendell-22x22.xpm" + +// +// Global Classes +// +RDRipc *rdripc; +RDConfig *admin_config; +RDUser *admin_user; +RDStation *admin_station; +RDSystem *admin_system; +RDCartDialog *admin_cart_dialog; +bool exiting=false; +QString admin_admin_username; +QString admin_admin_password; +QString admin_admin_hostname; +QString admin_admin_dbname; +QString admin_create_db_hostname; +bool admin_skip_backup=false; +QString admin_backup_filename=""; + +void SigHandler(int signo) +{ + pid_t pLocalPid; + + switch(signo) { + case SIGCHLD: + pLocalPid=waitpid(-1,NULL,WNOHANG); + while(pLocalPid>0) { + pLocalPid=waitpid(-1,NULL,WNOHANG); + } + signal(SIGCHLD,SigHandler); + break; + } +} + + +void PrintError(const QString &str,bool interactive) +{ + if(interactive) { + QMessageBox::warning(NULL,QObject::tr("RDAdmin Error"),str); + } + else { + fprintf(stderr,QString().sprintf("rdadmin: %s\n",(const char *)str)); + } +} + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + QString str; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont default_font("Helvetica",12,QFont::Normal); + default_font.setPixelSize(12); + qApp->setFont(default_font); + + // + // Create And Set Icon + // + admin_rivendell_map=new QPixmap(rivendell_xpm); + setIcon(*admin_rivendell_map); + + // + // Load Configs + // + admin_config=new RDConfig(); + admin_config->load(); + + str=QString(tr("RDAdmin")+" v"+VERSION+" - Host:"); + setCaption(QString(). + sprintf("%s %s",(const char *)str, + (const char *)admin_config->stationName())); + + // + // Open Database + // + if(!OpenDb(admin_config->mysqlDbname(),admin_config->mysqlUsername(), + admin_config->mysqlPassword(),admin_config->mysqlHostname(), + admin_config->stationName(),true)) { + exit(1); + } + new RDDbHeartbeat(admin_config->mysqlHeartbeatInterval()); + + // + // Check (and possibly start) daemons + // + if(!RDStartDaemons()) { + QMessageBox::warning(this,tr("Daemons Failed"), + tr("Unable to start Rivendell System Daemons!")); + exit(1); + } + + // + // Initialize Global Classes + // + char temp[256]; + GetPrivateProfileString(RD_CONF_FILE,"Identity","Password", + temp,"",255); + rdripc=new RDRipc(admin_config->stationName(),this,"rdripc"); + rdripc->connectHost("localhost",RIPCD_TCP_PORT,temp); + admin_station=new RDStation(admin_config->stationName(),this); + admin_system=new RDSystem(); + + // + // Log In + // + Login *login=new Login(&admin_username,&admin_password,this,"login"); + if(login->exec()!=0) { + exit(0); + } + admin_user=new RDUser(admin_username); + if(!admin_user->checkPassword(admin_password,false)) { + QMessageBox::warning(this,"Login Failed","Login Failed!.\n"); + exiting=true; + } + else { + if(!admin_user->adminConfig()) { + QMessageBox::warning(this,tr("Insufficient Priviledges"), + tr("This account has insufficient priviledges for this operation.")); + exiting=true; + } + } + + // + // Cart Dialog + // + admin_cart_dialog= + new RDCartDialog(&admin_filter,&admin_group,&admin_schedcode,NULL, + rdripc,admin_station,admin_system,admin_config,this); + + // + // User Labels + // + QLabel *name_label=new QLabel(this,"name_label"); + name_label->setGeometry(0,5,sizeHint().width(),20); + name_label->setAlignment(Qt::AlignVCenter|Qt::AlignCenter); + name_label->setFont(font); + name_label->setText(QString().sprintf("USER: %s",(const char *)admin_user->name())); + + QLabel *description_label=new QLabel(this,"description_label"); + description_label->setGeometry(0,24,sizeHint().width(),14); + description_label->setAlignment(Qt::AlignVCenter|Qt::AlignCenter); + name_label->setFont(font); + description_label->setText(admin_user->description()); + + // + // Manage Users Button + // + QPushButton *users_button=new QPushButton(this,"users_button"); + users_button->setGeometry(10,50,80,60); + users_button->setFont(font); + users_button->setText(tr("Manage\n&Users")); + connect(users_button,SIGNAL(clicked()),this,SLOT(manageUsersData())); + + // + // Manage Groups Button + // + QPushButton *groups_button=new QPushButton(this,"groups_button"); + groups_button->setGeometry(10,120,80,60); + groups_button->setFont(font); + groups_button->setText(tr("Manage\n&Groups")); + connect(groups_button,SIGNAL(clicked()),this,SLOT(manageGroupsData())); + + // + // Manage Services Button + // + QPushButton *services_button=new QPushButton(this,"services_button"); + services_button->setGeometry(100,50,80,60); + services_button->setFont(font); + services_button->setText(tr("Manage\n&Services")); + connect(services_button,SIGNAL(clicked()),this,SLOT(manageServicesData())); + + // + // Manage Stations (Hosts) Button + // + QPushButton *stations_button=new QPushButton(this,"stations_button"); + stations_button->setGeometry(100,120,80,60); + stations_button->setFont(font); + stations_button->setText(tr("Manage\nHo&sts")); + connect(stations_button,SIGNAL(clicked()),this,SLOT(manageStationsData())); + + // + // Manage Reports + // + QPushButton *reports_button=new QPushButton(this,"reports_button"); + reports_button->setGeometry(190,50,80,60); + reports_button->setFont(font); + reports_button->setText(tr("Manage\nR&eports")); + connect(reports_button,SIGNAL(clicked()),this,SLOT(reportsData())); + + // + // Manage Podcasts + // + QPushButton *podcasts_button=new QPushButton(this,"podcasts_button"); + podcasts_button->setGeometry(280,50,80,60); + podcasts_button->setFont(font); + podcasts_button->setText(tr("Manage\n&Feeds")); + connect(podcasts_button,SIGNAL(clicked()),this,SLOT(podcastsData())); + + // + // System Wide Settings Button + // + QPushButton *system_button=new QPushButton(this,"system_button"); + system_button->setGeometry(190,120,80,60); + system_button->setFont(font); + system_button->setText(tr("System\nSettings")); + connect(system_button,SIGNAL(clicked()),this,SLOT(systemSettingsData())); + + // + // Manage Scheduler Codes Button + // + QPushButton *schedcodes_button=new QPushButton(this,"schedcodes_button"); + schedcodes_button->setGeometry(280,120,80,60); + schedcodes_button->setFont(font); + schedcodes_button->setText(tr("Scheduler\nCodes")); + connect(schedcodes_button,SIGNAL(clicked()),this,SLOT(manageSchedCodes())); + + // + // Manage Replicators Button + // + QPushButton *repl_button=new QPushButton(this,"repl_button"); + repl_button->setGeometry(10,190,80,60); + repl_button->setFont(font); + repl_button->setText(tr("Manage\nReplicators")); + connect(repl_button,SIGNAL(clicked()),this,SLOT(manageReplicatorsData())); + + // + // System Info Button + // + QPushButton *info_button=new QPushButton(this,"info_button"); + info_button->setGeometry(100,190,80,60); + info_button->setFont(font); + info_button->setText(tr("System\nInfo")); + connect(info_button,SIGNAL(clicked()),this,SLOT(systemInfoData())); + + // + // Backup Database Button + // + QPushButton *backup_button=new QPushButton(this,"backup_button"); + backup_button->setGeometry(190,190,80,60); + backup_button->setFont(font); + backup_button->setText(tr("&Backup\nDatabase")); + connect(backup_button,SIGNAL(clicked()),this,SLOT(backupData())); + + // + // Restore Database Button + // + QPushButton *restore_button=new QPushButton(this,"restore_button"); + restore_button->setGeometry(280,190,80,60); + restore_button->setFont(font); + restore_button->setText(tr("&Restore\nDatabase")); + connect(restore_button,SIGNAL(clicked()),this,SLOT(restoreData())); + + // + // Quit Button + // + QPushButton *quit_button=new QPushButton(this,"quit_button"); + quit_button->setGeometry(10,sizeHint().height()-70,sizeHint().width()-20,60); + quit_button->setFont(font); + quit_button->setText(tr("&Quit")); + connect(quit_button,SIGNAL(clicked()),this,SLOT(quitMainWidget())); + + signal(SIGCHLD,SigHandler); +} + + +MainWidget::~MainWidget() +{ + delete admin_user; +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(370,330); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::manageUsersData() +{ + ListUsers *list_users=new ListUsers(admin_user->name(),this,"list_users"); + list_users->exec(); + delete list_users; +} + + +void MainWidget::manageGroupsData() +{ + ListGroups *list_groups=new ListGroups(this,"list_groups"); + list_groups->exec(); + delete list_groups; +} + +void MainWidget::manageSchedCodes() +{ + ListSchedCodes *list_schedCodes=new ListSchedCodes(this,"list_schedCodes"); + list_schedCodes->exec(); + delete list_schedCodes; +} + +void MainWidget::manageServicesData() +{ + ListSvcs *list_svcs=new ListSvcs(this,"list_svcs"); + list_svcs->exec(); + delete list_svcs; +} + + +void MainWidget::manageStationsData() +{ + ListStations *list_stations=new ListStations(this,"list_stations"); + list_stations->exec(); + delete list_stations; +} + + +void MainWidget::systemSettingsData() +{ + EditSettings *edit_settings=new EditSettings(this,"edit_settings"); + edit_settings->exec(); + delete edit_settings; +} + + +void MainWidget::backupData() +{ + QString filename; + QString cmd; + int status; + + filename=QFileDialog::getSaveFileName(RDGetHomeDir(), + tr("Rivendell Database Backup (*.sql)"), + this); + if(filename.isEmpty()) { + return; + } + if(filename.right(4)!=QString(".sql")) { + filename+=".sql"; + } + cmd=QString().sprintf("mysqldump -c %s -h %s -u %s -p%s > %s", + (const char *)admin_config->mysqlDbname(), + (const char *)admin_config->mysqlHostname(), + (const char *)admin_config->mysqlUsername(), + (const char *)admin_config->mysqlPassword(), + (const char *)filename); + status=system((const char *)cmd); + if(WEXITSTATUS(status)!=0) { + unlink((const char *)filename); + QMessageBox::warning(this,tr("Backup Error"), + tr("Unable to create backup!")); + return; + } + QMessageBox::information(this,tr("Backup Complete"), + tr("Backup completed successfully.")); +} + + +void MainWidget::restoreData() +{ + QString filename; + QString cmd; + int status; + RDSqlQuery *q; + int ver=RD_VERSION_DATABASE; + + if(QMessageBox::warning(NULL,tr("Restore Database"), + tr("WARNING: This operation will COMPLETELY\nOVERWRITE the existing Rivendell Database!\nDo you want to continue?"), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + return; + } + filename=QFileDialog::getOpenFileName(RDGetHomeDir(), + tr("Rivendell Database Backup (*.sql)"), + this); + if(filename.isEmpty()) { + return; + } + RDKillDaemons(); + ClearTables(); + cmd=QString().sprintf("cat %s | mysql %s -h %s -u %s -p%s", + (const char *)filename, + (const char *)admin_config->mysqlDbname(), + (const char *)admin_config->mysqlHostname(), + (const char *)admin_config->mysqlUsername(), + (const char *)admin_config->mysqlPassword()); + status=system((const char *)cmd); + if(WEXITSTATUS(status)!=0) { + QMessageBox::warning(this,tr("Restore Error"), + tr("Unable to restore backup!")); + return; + } + q=new RDSqlQuery("select DB from VERSION"); + if(q->first()) { + ver=q->value(0).toInt(); + } + delete q; + admin_skip_backup=true; + UpdateDb(ver); + QMessageBox::information(this,tr("Restore Complete"), + tr("Restore completed successfully.")); + RDStartDaemons(); +} + + +void MainWidget::manageReplicatorsData() +{ + ListReplicators *d=new ListReplicators(this); + d->exec(); + delete d; +} + + +void MainWidget::systemInfoData() +{ + InfoDialog *info=new InfoDialog(this,"info_dialog"); + info->exec(); + delete info; +} + + +void MainWidget::reportsData() +{ + ListReports *list_reports=new ListReports(this,"list_reports"); + list_reports->exec(); + delete list_reports; +} + + +void MainWidget::podcastsData() +{ + ListFeeds *list_feeds=new ListFeeds(this,"list_feeds"); + list_feeds->exec(); + delete list_feeds; +} + + +void MainWidget::quitMainWidget() +{ + exit(0); +} + + +void MainWidget::ClearTables() +{ + RDSqlQuery *q1; + + QString sql="show tables"; + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("drop table %s", + (const char *)q->value(0).toString()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; +} + + +int gui_main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(), + "."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rdadmin_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + if(exiting) { + exit(0); + } + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} + + +int cmdline_main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + + // + // Load Configs + // + admin_config=new RDConfig(); + admin_config->load(); + + // + // Open Database + // + QString station_name=admin_config->stationName(); + if(!admin_create_db_hostname.isEmpty()) { + station_name=admin_create_db_hostname; + } + if(!OpenDb(admin_config->mysqlDbname(),admin_config->mysqlUsername(), + admin_config->mysqlPassword(),admin_config->mysqlHostname(), + station_name,false)) { + return 1; + } + + return 0; +} + + +int main(int argc,char *argv[]) +{ + int ret; + bool found_check_db=false; + + RDCmdSwitch *cmd=new RDCmdSwitch(argc,argv,"rdadmin",RDADMIN_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--check-db") { + found_check_db=true; + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--mysql-admin-user") { + admin_admin_username=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--mysql-admin-password") { + admin_admin_password=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--mysql-admin-hostname") { + admin_admin_hostname=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--mysql-admin-dbname") { + admin_admin_dbname=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--create-db-hostname") { + admin_create_db_hostname=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--backup-filename") { + admin_backup_filename=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--skip-backup") { + admin_skip_backup=true; + cmd->setProcessed(i,true); + } + } + if(found_check_db) { + ret=cmdline_main(argc,argv); + } + else { + ret=gui_main(argc,argv); + } + return ret; +} diff --git a/rdadmin/rdadmin.h b/rdadmin/rdadmin.h new file mode 100644 index 00000000..8550bcd5 --- /dev/null +++ b/rdadmin/rdadmin.h @@ -0,0 +1,73 @@ +// rdadmin.h +// +// The Administration Utility for Rivendell. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: rdadmin.h,v 1.28.4.1 2013/11/13 00:12:55 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDADMIN_H +#define RDADMIN_H + +#include +#include +#include +#include +#include + +#include +#include + +#define RDADMIN_USAGE "[--check-db][--mysql-admin-user=][--mysql-admin-password=]\n\n--check-db'\n Check and (if necessary) create or update the database schema to the\n current version, then exit.\n\n--mysql-admin-user=\n--mysql-admin-password=\n--mysql-admin-hostname=\n--mysql-admin-dbname=\n When creating a new database, use the supplied credentials for the\n MySQL administrative user instead of prompting for them.\n\n--create-db-hostname=\n When creating a new database, create a host entry called \n instead of autodetecting the hostname.\n\n--backup-filename=\n When performing a schema update, RDAdmin will automatically execute a\n database backup to the file specified in [default value\n $HOME/rdbackup--.sql.gz].\n\n--skip-backup\n When doing a schema update, suppress generation of an automatic backup.\n" + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + ~MainWidget(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void manageUsersData(); + void manageGroupsData(); + void manageServicesData(); + void manageStationsData(); + void systemSettingsData(); + void reportsData(); + void podcastsData(); + void quitMainWidget(); + void manageSchedCodes(); + void manageReplicatorsData(); + void systemInfoData(); + void backupData(); + void restoreData(); + + private: + void ClearTables(); + QString admin_username; + QString admin_password; + QPixmap *admin_rivendell_map; + QString admin_filter; + QString admin_group; + QString admin_schedcode; +}; + + +#endif diff --git a/rdadmin/rdadmin.pro b/rdadmin/rdadmin.pro new file mode 100644 index 00000000..47452cfb --- /dev/null +++ b/rdadmin/rdadmin.pro @@ -0,0 +1,180 @@ +// rdadmin.pro +// +// The QMake project file for RDAdmin. +// +// (C) Copyright 2003-2005 Fred Gleason +// +// $Id: rdadmin.pro,v 1.14.2.5 2013/02/21 02:46:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +x11 { + SOURCES += add_aux_field.cpp + SOURCES += add_encoder.cpp + SOURCES += add_feed.cpp + SOURCES += add_group.cpp + SOURCES += add_hostvar.cpp + SOURCES += add_matrix.cpp + SOURCES += add_replicator.cpp + SOURCES += add_report.cpp + SOURCES += add_station.cpp + SOURCES += add_svc.cpp + SOURCES += add_user.cpp + SOURCES += autofill_carts.cpp + SOURCES += createdb.cpp + SOURCES += edit_audios.cpp + SOURCES += edit_aux_field.cpp + SOURCES += edit_backup.cpp + SOURCES += edit_cartslots.cpp + SOURCES += edit_decks.cpp + SOURCES += edit_dropbox.cpp + SOURCES += edit_encoder.cpp + SOURCES += edit_endpoint.cpp + SOURCES += edit_feed.cpp + SOURCES += edit_feed_perms.cpp + SOURCES += edit_gpi.cpp + SOURCES += edit_group.cpp + SOURCES += edit_hostvar.cpp + SOURCES += edit_hotkeys.cpp + SOURCES += edit_jack.cpp + SOURCES += edit_jack_client.cpp + SOURCES += edit_livewiregpio.cpp + SOURCES += edit_matrix.cpp + SOURCES += edit_nownextplugin.cpp + SOURCES += edit_now_next.cpp + SOURCES += edit_rdairplay.cpp + SOURCES += edit_rdlibrary.cpp + SOURCES += edit_rdlogedit.cpp + SOURCES += edit_rdpanel.cpp + SOURCES += edit_replicator.cpp + SOURCES += edit_report.cpp + SOURCES += edit_settings.cpp + SOURCES += edit_station.cpp + SOURCES += edit_svc.cpp + SOURCES += edit_svc_perms.cpp + SOURCES += edit_ttys.cpp + SOURCES += edit_user.cpp + SOURCES += edit_user_perms.cpp + SOURCES += edit_vguest_resource.cpp + SOURCES += info_dialog.cpp + SOURCES += list_aux_fields.cpp + SOURCES += list_dropboxes.cpp + SOURCES += list_encoders.cpp + SOURCES += list_endpoints.cpp + SOURCES += list_feeds.cpp + SOURCES += list_gpis.cpp + SOURCES += list_groups.cpp + SOURCES += list_hostvars.cpp + SOURCES += list_livewiregpios.cpp + SOURCES += list_matrices.cpp + SOURCES += list_reports.cpp + SOURCES += list_replicator_carts.cpp + SOURCES += list_replicators.cpp + SOURCES += list_stations.cpp + SOURCES += list_svcs.cpp + SOURCES += list_users.cpp + SOURCES += login.cpp + SOURCES += mysql_login.cpp + SOURCES += opendb.cpp + SOURCES += rdadmin.cpp + SOURCES += rename_group.cpp + SOURCES += test_import.cpp + SOURCES += view_adapters.cpp + SOURCES += xpm_info_banner1.cpp + SOURCES += xpm_info_banner2.cpp +} + +x11 { + HEADERS += add_aux_field.h + HEADERS += add_encoder.h + HEADERS += add_feed.h + HEADERS += add_group.h + HEADERS += add_hostvar.h + HEADERS += add_matrix.h + HEADERS += add_replicator.h + HEADERS += add_report.h + HEADERS += add_station.h + HEADERS += add_svc.h + HEADERS += add_user.h + HEADERS += autofill_carts.h + HEADERS += createdb.h + HEADERS += edit_audios.h + HEADERS += edit_aux_field.h + HEADERS += edit_backup.h + HEADERS += edit_cartslots.h + HEADERS += edit_decks.h + HEADERS += edit_dropbox.h + HEADERS += edit_encoder.h + HEADERS += edit_endpoint.h + HEADERS += edit_feed.h + HEADERS += edit_feed_perms.h + HEADERS += edit_gpi.h + HEADERS += edit_group.h + HEADERS += edit_hostvar.h + HEADERS += edit_hotkeys.h + HEADERS += edit_jack.h + HEADERS += edit_jack_client.h + HEADERS += edit_livewiregpio.h + HEADERS += edit_matrix.h + HEADERS += edit_nownextplugin.h + HEADERS += edit_now_next.h + HEADERS += edit_rdairplay.h + HEADERS += edit_rdlibrary.h + HEADERS += edit_rdlogedit.h + HEADERS += edit_rdpanel.h + HEADERS += edit_replicator.h + HEADERS += edit_report.h + HEADERS += edit_settings.h + HEADERS += edit_station.h + HEADERS += edit_svc.h + HEADERS += edit_svc_perms.h + HEADERS += edit_ttys.h + HEADERS += edit_user.h + HEADERS += edit_user_perms.h + HEADERS += edit_vguest_resource.h + HEADERS += info_dialog.h + HEADERS += list_aux_fields.h + HEADERS += list_dropboxes.h + HEADERS += list_encoders.h + HEADERS += list_endpoints.h + HEADERS += list_feeds.h + HEADERS += list_gpis.h + HEADERS += list_groups.h + HEADERS += list_hostvars.h + HEADERS += list_livewiregpios.h + HEADERS += list_matrices.h + HEADERS += list_reports.h + HEADERS += list_replicator_carts.h + HEADERS += list_replicators.h + HEADERS += list_stations.h + HEADERS += list_svcs.h + HEADERS += list_users.h + HEADERS += login.h + HEADERS += mysql_login.h + HEADERS += opendb.h + HEADERS += rdadmin.h + HEADERS += rename_group.h + HEADERS += test_import.h + HEADERS += view_adapters.h +} + +TRANSLATIONS += rdadmin_cs.ts +TRANSLATIONS += rdadmin_de.ts +TRANSLATIONS += rdadmin_es.ts +TRANSLATIONS += rdadmin_fr.ts +TRANSLATIONS += rdadmin_nb.ts +TRANSLATIONS += rdadmin_nn.ts +TRANSLATIONS += rdadmin_pt_BR.ts diff --git a/rdadmin/rdadmin_cs.ts b/rdadmin/rdadmin_cs.ts new file mode 100644 index 00000000..6a4b8e5e --- /dev/null +++ b/rdadmin/rdadmin_cs.ts @@ -0,0 +1,5886 @@ + + + @default + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + Nelze přistupovat k databázi Rivendell! +Zadejte, prosím, přihlašovací údaje k účtu s +administrátorskými právy k mySQL serveru +a my se pokusíme toto opravit. + + + Can't Connect + Kann nicht verbinden + + + Wrong access permissions for accessing mySQL! + Špatná přístupová práva pro přístup k mySQL! + + + Unable to connect to mySQL! + Nelze se spojit s mySQL! + + + Can't Create DB + Kann die Datenbank nicht erstellen + + + Unable to create a Rivendell Database! + Nelze vytvořit databázi Rivendell! + + + Unable to connect to new Rivendell Database! + Nelze se spojit s novou databází Rivendell! + + + Can't Create + Kann nicht erstellen + + + Unable to create Rivendell Database! + Nelze vytvořit databázi Rivendell! + + + Unable to connect to Rivendell Database! + Nelze se spojit s databází Rivendell! + + + Can't Initialize + Kann nicht initialisieren + + + Unable to initialize Rivendell Database! + Nelze spustit databází Rivendell! + + + Created Database + Datenbank erstellt + + + New Rivendell Database Created! + Nová databáze Rivendell vytvořena! + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + Databáze Rivendell je příliš stará na to, aby byla povýšena a +musí se nahradit. Toto SMAŽE všechny stávající nahrávky +a data! Pokud to chcete udělat, zadejte uživatelské jméno +a heslo k účtu mySQL se správcovskými právy, jinak klepněte na +zrušit. + + + Unable to log into Administrator account! + Nelze se přihlásit k správcovskému účtu! + + + Unable to authorize a Rivendell Database! + Nelze povolit databází Rivendell! + + + Update Needed + Aktualizace potřeba + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + Databázi Rivendell je potřeba obnovit. +Všechny nahrávky a nastavení budou uloženy, ale toto +ZASTAVÍ všechna přehrávání zvuku nebo nahrávání +na tomto počítači na několik sekund. Pokračovat? + + + Can't Update + Kann nicht updaten + + + Unable to update Rivendell Database! + Kann die Rivendell-Datenbank nicht updaten! + + + The Rivendell Database has +been updated to Version + Die Rivendell-Datenbank ist geupdatet +worden. Aktuelle Version + + + Database Updated + Databáze obnovena + + + RDAdmin Error + Chyba RDadmin + + + Unable to upgrade database + Aktualizace databáze není možná + + + RDAdmin + RDAdmin + + + +Database backup failed! + +Záloha databáze se nezdařila! + + + +Schema modification failed! + +Změna schématu se nezdařila! + + + Unable to update Rivendell Database: + Nelze obnovit databázi Rivendell: + + + +Unknown/unspecified error! + +Neznámá/blíže neurčená chyba! + + + +and a backup of the original database saved in + +a záloha původní databáze uložena v + + + The Rivendell Database has been updated to version + Databáze Rivendell byla zaktualizována na verzi + + + + AddAuxField + + Add Aux Field + Přidat pomocné pole + + + Variable Name: + Název proměnné: + + + %AUX_ + %AUX_ + + + % + % + + + Caption: + Popisek: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Name Exists + Název existuje + + + That variable name already exists! + Proměnná s tímto názvem již existuje! + + + + AddEncoder + + Add Encoder + + + + &New Encoder Name: + + + + &OK + &OK + + + &Cancel + Z&rušit + + + Add Encoder Error + + + + A encoder with that name already exists! + + + + + AddFeed + + Add Feed + Přidat přívod + + + Enable Feed for All Users + Povolit přívod pro všechny uživatele + + + &New Feed Name: + Název nového &přívodu: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Add Feed Error + Chyba při přidávání přívodu + + + A feed with that key name already exists! + Přívod s tímto názvem klíče již existuje! + + + + AddGroup + + Add Group + Přidat skupinu + + + &New Group Name: + Název &nové skupiny: + + + Enable Group for All Users + Povolit skupinu pro všechny uživatele + + + Enable Group for All Services + Povolit skupinu pro všechny služby + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Name + Neplatný název + + + You must give the group a name! + Musíte zadat skupinu nebo název! + + + Group Exists + Skupina existuje + + + Group Already Exists! + Skupina již existuje! + + + + AddHostvar + + Add Host Variable + Přidat proměnnou serveru + + + Variable Name: + Název proměnné: + + + Variable Value: + Hodnota proměnné: + + + Remark: + Poznámka: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Name + Neplatný název + + + The variable name is invalid. + Název proměnné je neplatný. + + + + AddMatrix + + Add Switcher + Přidat přepínač + + + &New Matrix Number: + Č&íslo nové matice: + + + Local GPIO + Místní GPIO + + + Generic GPO + Obecné GPO + + + Generic Serial + Obecné sériové + + + Local Audio Adapter + Místní přípojka zvuku + + + Logitek vGuest + Logitek vGuest + + + BroadcastTools SS16.4 + BroadcastTools SS16.4 + + + StarGuide III + StarGuide III + + + BroadcastTools SS4.2 + BroadcastTools SS4.2 + + + Axia LiveWire + Axia LiveWire + + + Quartz Type 1 + Quartz Typ 1 + + + &Switcher Type: + Typ &přepínače: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Matrix + Neplatná matice + + + Matrix already exists! + Matrix existiert bereits! + + + BroadcastTools SS4.4 + BroadcastTools SS4.4 + + + BroadcastTools SRC-8 III + BroadcastTools SRC-8 III + + + BroadcastTools SRC-16 + BroadcastTools SRC-16 + + + New Switcher + Nový přepínač + + + RDAdmin - Add Switcher + + + + + AddReplicator + + Add Replicator + Přidat kopírovací stroj + + + &New Replicator Name: + Název nového &kopírovacího stroje: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Name + Neplatný název + + + You must give the replicator a name! + Musíte zadat název kopírovacího stroje! + + + Replicator Exists + Kopírovací stroj existuje + + + A replicator with that name already exists! + Kopírovací stroj s tímto názvem již existuje! + + + + AddReport + + Add Report + Přidat zprávu + + + &Report Name: + &Název zprávy: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Name + Neplatný název + + + You must provide a report name! + Musíte zadat název zprávy! + + + Report Exists + Zpráva existuje + + + A report with that name already exists! + Zpráva s tímto názvem již existuje! + + + + AddStation + + Add Host + Přidat server + + + New &Host Name: + Název nového &serveru: + + + Base Host On: + Server založený na: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Empty Host Config + Vyprázdnit nastavení serveru + + + Invalid Name + Neplatný název + + + You must give the host a name! + Musíte zadat název serveru! + + + Host Exists + Server existuje + + + Host Already Exists! + Server již existuje! + + + + AddSvc + + Add Service + Přidat službu + + + &New Service Name: + Název nové &služby: + + + Base Service On: + Služba založená na: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Empty Host Config + Vyprázdnit nastavení serveru + + + Invalid Name + Neplatný název + + + You must give the service a name! + Musíte zadat název služby! + + + Service Exists + Služba existuje + + + Service Already Exists! + Služba již existuje! + + + + AddUser + + Add User + Přidat uživatele + + + &New User Name: + Jméno nového &uživatele: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Name + Neplatný název + + + You must give the user a name! + Musíte zadat jméno uživatele! + + + User Exists + Uživatel existuje + + + User Already Exists! + Uživatel již existuje! + + + + AutofillCarts + + Autofill Carts - Service: + Služba automatického naplnění vozíku: + + + Cart + Vozík + + + Length + Délka + + + Title + Název + + + Artist + Umělec + + + &Add + &Přidat + + + &Delete + S&mazat + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditAudioPorts + + Edit Audio Ports + Upravit přípojky zvuku + + + Clock Source: + Zdroj hodin: + + + Input Port + Vstupní přípojka + + + Analog + Analog + + + AES/EBU + AES/EBU + + + SP/DIFF + SP/DIFF + + + Type: + Typ: + + + Normal + Normální + + + Swap + Vyměnit + + + Left only + Jen levý + + + Right only + Jen pravý + + + Mode: + Režim: + + + dB + dB + + + Level: + Úroveň: + + + Output Port + Výstupní přípojka + + + &Help + &Nápověda + + + &Close + &Zavřít + + + Internal + Vnitřní + + + AES/EBU Signal + Signál AES/EBU + + + SP/DIFF Signal + AES/EBU SP/DIFF + + + Word Clock + Slovní hodiny + + + Card: + Karta: + + + Card Driver: + Ovladač karty: + + + Ref. Level: + + + + + EditAuxField + + Edit Auxiliary Metadata Fields + Upravit pole pomocných popisných dat + + + Variable Name: + Název proměnné: + + + Caption: + Popisek: + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditBackup + + Backup config for + Záloha nastavení pro + + + Keep Backups For: + Uchovat zálohy po: + + + days + dnů + + + Backup Directory: + Adresář pro zálohy: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Path Missing + Cesta chybí + + + You must supply a backup path! + Musíte zadat cestu pro zálohu! + + + + EditCartSlots + + RDAdmin - Edit CartSlots + + + + Global Settings + + + + Slot Columns: + + + + Slot Rows: + + + + Slot + + + + Settings + Nastavení + + + Channel Assignments + Přiřazení kanálu + + + None + + + + Card: + Karta: + + + Input Port: + + + + Output Port: + + + + Default Settings + + + + Service: + + + + User previous mode + + + + Slot Mode: + + + + Use previous mode + + + + Full + + + + Hook + + + + Play Mode: + + + + Use previous cart + + + + Do Nothing + + + + Load Specified Cart + + + + At Startup: + Při spuštění: + + + Cart: + Vozík: + + + Select + Vybrat + + + Use previous action + + + + At Playout End: + + + + Close + + + + Slot selected has changed! + + + + + EditDecks + + Configure RDCatch + Nastavit RDCatch + + + Record Deck + Nahrávací panel + + + None + Žádný + + + Monitor Port: + Sledovací přípojka: + + + Off + Vypnuto + + + On + Zapnuto + + + Monitor defaults to + Sledovat ve výchozím nastavení + + + Format: + Formát: + + + Sample Rate: + Sample-Rate: + + + Bit Rate: + Datový tok: + + + Switcher Host: + Server přepínače: + + + Switcher Matrix: + Matice přepínače: + + + Switcher Output: + Výstup přepínače: + + + Switcher Delay: + Zpoždění přepínače: + + + 1/10 sec + 1/10 s + + + Channels: + Kanály: + + + Trim Threshold: + Práh pro zastřižení: + + + Error RML: + Chyba RML: + + + Play Deck + Přehrávací panel + + + Audition Deck + Poslechový panel + + + &Close + &Zavřít + + + No Audio Configuration Data + Žádná data k nastavení zvuku + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Kanalbestimmungen werden für diesen Host nicht verfügbar sein, da Audio- +Ressourcendaten nich nicht generiert wurden. Bitte starten sie die Rivendell- +deamons auf diesem Host, indem sie als Benutzer 'root' das Kommando "/etc/init.d/rivendell start" +eingeben um die Audioressourcendatenbank zu füllen. + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG Layer 2 + + + 32 kbps/chan + 32 kB/s/kanál + + + 48 kbps/chan + 48 kB/s/kanál + + + 56 kbps/chan + 56 kB/s/kanál + + + 64 kbps/chan + 64 kB/s/kanál + + + 80 kbps/chan + 80 kB/s/kanál + + + 96 kbps/chan + 96 kB/s/kanál + + + 112 kbps/chan + 112 kB/s/kanál + + + 128 kbps/chan + 128 kB/s/kanál + + + 160 kbps/chan + 160 kB/s/kanál + + + 192 kbps/chan + 192 kB/s/kanál + + + [none] + [žádný] + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + Přiřazení kanálů nebudou dostupná pro tento server jako zdroj zvuku, data +ještě nebyla vytvořena. Spusťte, prosím, démony Rivendell na serveru +nastaveném pro běh služby CAE pro naplnění databáze se zdroji zvuku. + + + Settings + Nastavení + + + Defaults + Výchozí + + + Host-Wide Settings + Nastavení serveru-wide + + + + EditDropbox + + Dropbox Configuration + Nastavení pro Dropbox + + + Default Group: + Výchozí skupina: + + + &Path Spec: + Zadání &cesty: + + + Select + Vybrat + + + To &Cart: + Do &vozíku: + + + Delete cuts before importing + Smazat záběry před zavedením + + + &Metadata Pattern: + Vzor pro &popisná data: + + + &Log File: + Soubor se &zápisem: + + + Delete source files after import + Smazat zdrojové soubory po zavedení + + + Normalize Levels + Normalizovat úrovně + + + Level: + Úroveň: + + + dBFS + dbFS + + + Autotrim Cuts + Automaticky zastřihnout záběry + + + Get cart number from CartChunk CutID + Dostat číslo vozíku z ID záběru Kousku vozíku + + + Get cart title from CartChunk CutID + Dostat název vozíku z ID záběru Kousku vozíku + + + Attempt to work around malformatted input files + Pokusit se ošetřit zpotvořené vstupní soubory + + + Offset start date by + Vyrovnat počáteční čas podle + + + days + dnů + + + Offset end date by + Vyrovnat koncový čas podle + + + Create Dates when no Dates Exist + Vytvořit datum, když žádné datum neexistuje + + + Create start date offset: + Posun vytvoření počátečního data: + + + Create end date offset: + Posun vytvoření koncového data: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Offsets + Neplatné posuny + + + The Create EndDate Offset is less than the Create Start Date Offset! + Posun vytvoření koncového data je menší než Posun vytvoření počátečního data! + + + The EndDate Offset is less than the Start Date Offset! + Posun koncového data je menší než Posun počátečního data! + + + &User Defined: + + + + Scheduler Codes + + + + + EditEncoder + + RDAdmin - Edit Encoder + RDAdmin - Upravit kodér + + + Name: + Název: + + + Allow Channels + Povolit kanály + + + Allow Sample Rates + Povolit vzorkovací kmitočty + + + Allow Bit Rates + Povolit datové toky + + + &OK + &OK + + + &Cancel + Z&rušit + + + Default Extension: + Výchozí přípona: + + + Command Line: + Příkazový řádek: + + + + EditEndpoint + + Edit Input + Upravit vstup + + + Edit Output + Upravit výstup + + + Name: + Název: + + + Feed: + Přívod: + + + Mode: + Režim: + + + Stereo + Stereo + + + Left + Vlevo + + + Right + Vpravo + + + Engine (Hex): + Stroj (Hex): + + + Provider ID: + ID poskytovatele: + + + Device (Hex): + Zařízení (Hex): + + + Service ID: + ID služby: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Number + Neplatné číslo + + + The Engine Number is Invalid! + Číslo stroje je neplatné! + + + The Provider ID is Invalid! + ID poskytovatele je neplatné! + + + The Device Number is Invalid! + Číslo zařízení je neplatné! + + + The Service ID is Invalid! + ID služby je neplatné! + + + + EditFeed + + Feed: + Přívod: + + + Key Name: + Název klíče: + + + CHANNEL VALUES + HODNOTY KANÁLŮ + + + Title: + Název: + + + Category: + Skupina: + + + Link: + Odkaz: + + + Copyright: + Autorské právo: + + + Webmaster: + Tvůrce internetových stránek: + + + Language: + Jazyk: + + + Description: + Popis: + + + Audio Upload URL: + Adresa (URL) nahrání zvuku: + + + Username: + Uživatelské jméno: + + + Password: + Heslo: + + + Upload Format: + Formát nahrání: + + + S&et + &Nastavit + + + Normalize + Normalizovat + + + Level: + Úroveň: + + + dBFS + dbFS + + + Audio Download URL: + Adresa (URL) stažení zvuku: + + + Keep Expired Metadata + Zachovat prošlá popisná data + + + Enable AutoPost + Povolit automatické vyvěšení + + + Enclosure Preamble: + Předpona adresy (URL) přílohy (Enclosure): + + + Audio Extension: + Přípona zvuku: + + + None + Žádná + + + Maximum Shelf Life: + Největší čas před vypršením: + + + days + dnů + + + Descending + Sestupně + + + Ascending + Vzestupně + + + Episode Sort Order: + Pořadí třídění dílů: + + + Direct + Přímé + + + Counted + Počítané + + + Media Link Mode: + Režim odkazu na media: + + + Enable Feed Redirection + Povolit přesměrování přívodu + + + URL: + Adresa (URL): + + + Header XML: + Hlavička XML: + + + Channel XML: + Kanál XML: + + + Item XML: + Položka XML: + + + &Define Auxiliary +Metadata Fields + &Vymezit pomocná +pole popisných dat + + + &OK + &OK + + + &Cancel + Z&rušit + + + Edit Feed - Redirect + Upravit přívod - Přesměrovat + + + Enabling feed redirection will cause clients subscribed to +this feed to be PERMANENTLY redirected to the +specified URL. + +Do you still want to enable redireciton? + Povolení přesměrování přívodu způsobí, že klienti přihlášení k tomuto +přívodu budou TRVALE přesměrováni na zadanou adresu. + +Pořád ještě chcete povolit přesměrování? + + + + EditFeedPerms + + User: + Uživatel: + + + Available Feeds + Dostupné přívody + + + Enabled Feeds + Povolit přívody + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditGpi + + Edit GPI + Upravit GPI + + + Description: + Popis: + + + Cart Number: + Číslo vozíku: + + + &Select + &Vybrat + + + C&lear + Sma&zat + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Cart + Neplatný vozík + + + Invalid Cart Number! + Neplatné číslo vozíku! + + + + EditGroup + + Group: + Skupina: + + + &Group Name: + Název &skupiny: + + + Group &Description: + &Popis skupiny: + + + Audio + Zvuk + + + Macro + Makro + + + Default Cart &Type: + Výchozí &typ vozíku: + + + None + Žádný + + + Default Cart Number: + Výchozí číslo vozíku: + + + to + do + + + Enforce Cart Range + Vynutit oblast vozíku + + + Include this group in Traffic reports + Tuto skupinu zahrnout do zpráv o přenosech + + + Include this group in Music reports + Tuto skupinu zahrnout do zpráv o hudbě + + + Transmit Now && Next data + Přenést data Nyní && Další + + + C&olor + &Barva + + + &OK + &OK + + + &Cancel + Z&rušit + + + The selected cart range conflicts with the following groups: + + + Vybraný obsah vozíku stojí ve střetu s následujícími skupinami: + + + + + +Do you still want to save? + +Stále ještě chcete uložit? + + + Default Import &Title: + Výchozí &název zavedení: + + + Purge expired cuts after + Prošlé záběry smazat po + + + days + dnů + + + Delete cart if empty + + + + + EditHostvar + + Edit Host Variable + Upravit proměnnou serveru + + + Variable Name: + Název proměnné: + + + Variable Value: + Hodnota proměnné: + + + Remark: + Poznámka: + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditHotkeys + + Hot Key Configuration for + Nastavení klávesové zkratky pro + + + Host Hot Key Configurations + Nastavení klávesových zkratek pro server + + + Button / Function + Tlačítko/Funkce + + + KeyStroke + Klávesová zkratka + + + Set + Nastavit + + + Clear + Smazat + + + Clear All Hotkeys + Smazat všechny klávesové zkratky + + + Set From Host: + Nastavit ze serveru: + + + Save + Uložit + + + Cancel + Zrušit + + + Duplicate Entries + Zdvojené záznamy + + + Hotkeys Clear + Smazání klávesových zkratek + + + Hotkeys Updated + Klávesové zkratky obnoveny + + + No Items Selected + Nevybrány žádné položky + + + Please Select an Item From the List + Vyberte, prosím, položku ze seznamu + + + + EditJack + + JACK Configuration for + Nastavení JACK pro + + + Start JACK Server + Spustit server JACK + + + JACK Server Name: + Název serveru JACK: + + + &OK + &OK + + + &Cancel + Z&rušit + + + JACK Command Line: + + + + JACK Clients to Start: + + + + Client + + + + Command Line + + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + [New Client] + + + + RDAdmin - JACK Clients + + + + Are you sure you want to delete JACK Client + + + + + EditJackClient + + JACK Client Configuration for + + + + Description: + Popis: + + + Command Line: + Příkazový řádek: + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditLiveWireGpio + + &OK + &OK + + + &Cancel + Z&rušit + + + Edit GPIO Source + + + + Livewire Source: + + + + GPIO Lines + + + + Surface Address: + + + + Invalid IP Address + + + + The IP address is invalid! + + + + None + + + + + EditMatrix + + Edit Switcher + Upravit přepínač + + + Matrix Number: + Číslo matice: + + + Switcher Type: + Typ přepínače: + + + Description: + Popis: + + + Primary Connection + Hlavní spojení + + + Type: + Typ: + + + Serial + Sériový + + + TCP/IP + TCP/IP + + + Serial Port: + Sériová přípojka + + + IP Address: + Adresa IP: + + + IP Port: + Přípojka IP: + + + Username: + Uživatelské jméno: + + + Password: + Heslo: + + + Backup Connection + Záložní spojení + + + None + Žádný + + + Card: + Karta: + + + Inputs: + Vstupy: + + + Outputs: + Výstupy: + + + Device: + Zařízení: + + + GPIs: + GPIs: + + + GPOs: + GPOs: + + + Layer: + Vrstva: + + + Displays: + Zobrazení: + + + Configure +&Inputs + Nastavit +&vstupy + + + Configure +&Outputs + Nastavit +vý&stupy + + + Configure +&Xpoints + Nastavit +&Xpoints + + + LiveWire +Nodes + Uzly LiveWire + + + vGuest +Switches + Přepínače vGuest + + + vGuest +Displays + Zobrazení +vGuest + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Address + Neplatná adresa + + + The primary IP address is invalid! + Hlavní adresa IP je neplatná! + + + The backup IP address is invalid! + Záložní adresa IP je neplatná! + + + Duplicate Connections + Zdvojené spojení + + + The primary and backup connections must be different! + Hlavní a záložní spojení se musí lišit! + + + Configure +&GPIs + Nastavit +&GPIs + + + Configure +G&POs + Nastavit +G&POs + + + Startup Cart: + Spouštěcí vozík: + + + Select + Vybrat + + + Shutdown Cart: + Vypínací vozík: + + + SAS +Switches + Přepínače +SAS + + + RDAdmin - Edit Switcher + + + + LiveWire +GPIOs + + + + + EditNowNext + + Edit Now & Next Data + Upravit data Nyní & Další + + + Master Log + Hlavní zápis + + + IP Address: + Adresa IP: + + + UDP Port: + Přípojka UDP: + + + UDP String: + Řetězec UDP: + + + RML: + RML: + + + Aux Log 1 + Pomocný zápis 1 + + + &OK + &OK + + + &Cancel + Z&rušit + + + The IP address + Adresa IP + + + is invalid! + je neplatná! + + + Invalid Address + Neplatná adresa + + + Add + Přidat + + + Edit + Upravit + + + Delete + Smazat + + + Path + Cesta + + + Argument + Argument + + + Loadable Modules: + Nahratelné moduly: + + + Default Now Cart: + Výchozí vozík Nyní: + + + Default Next Cart: + Výchozí vozík Další: + + + Select + Vybrat + + + Aux Log 2 + Pomocný zápis 2 + + + + EditNowNextPlugin + + Edit Plugin + Upravit přídavný modul + + + Plugin Path: + Cesta k přídavnému modulu: + + + Argument: + Argument: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Select + Vybrat + + + Select plugin + Vybrat přídavný modul + + + + EditRDAirPlay + + RDAirPlay config for + Nastavení RDAirPlay pro + + + Channel Assignments + Přiřazení kanálu + + + Main Log Output 1 + Výstup hlavního zápisu 1 + + + Start RML: + Spustit RML: + + + Stop RML: + Zastavit RML: + + + Main Log Output 2 + Výstup hlavního zápisu 2 + + + Aux Log 1 Output + Výstup pomocného zápisu 1 + + + Aux Log 2 Output + Výstup pomocného zápisu 2 + + + Audition/Cue Output + Výstup poslech/CUE + + + SoundPanel First Play Output + Panel zvuku první výstup + + + SoundPanel Second Play Output + Panel zvuku druhý výstup + + + SoundPanel Third Play Output + Panel zvuku třetí výstup + + + SoundPanel Fourth Play Output + Panel zvuku čtvrtý výstup + + + SoundPanel Fifth and Later Play Output + Panel zvuku pátý a další výstupy + + + Manual Segue: + Ruční přechod: + + + msecs + ms + + + Forced Segue: + Vynucený přechod: + + + Pie Counts Last: + Pie počítá poslední: + + + secs + s + + + Pie Counts To: + Pie počítá k: + + + Cart End + Konec vozíku + + + Transition + Přechod + + + Default Trans. Type: + Výchozí typ přechodu: + + + Play + Přehrát + + + Segue + Přechod + + + Stop + Zastavit + + + Default Service: + Výchozí služba: + + + Sound Panel Settings + Nastavení zvukového panelu + + + None + Žádný + + + Host Panels: + Panely serveru: + + + User Panels: + Panely uživatele: + + + Flash Active Buttons + Blikat činnými tlačítky + + + Enable Button Pausing + Povolit pozastavení záznamu + + + Label Template: + Předloha štítku: + + + Miscellaneous Settings + Různá nastavení + + + Startup Mode: + Režim spouštění: + + + Previous + Předchozí + + + LiveAssist + Živá pomoc + + + Automatic + Automatický + + + Manual + Ruční + + + Check TimeSync + Přezkoušet seřízení času + + + Show Auxlog 1 Button + Ukázat tlačítko pomocného zápisu 1 + + + Show Auxlog 2 Button + Ukázat tlačítko pomocného zápisu 2 + + + Clear Cart Search Filter + Smazat filtr hledání vozíku + + + Enable Paused Events + Zapnout pozastavené události + + + Space Bar Action + Činnost mezerníku + + + Start Next + Spustit další + + + Configure Now && Next +Parameters + Nastavit parametry +Nyní && Další + + + Start/Stop Settings + Nastavení spustit/zastavit + + + Exit Password: + Heslo pro ukončení: + + + Main Log + Hlavní zápis + + + start with empty log + Začít s prázdným zápisem + + + load previous log + Nahrát předchozí zápis + + + load specified log + Nahrát určitý zápis + + + At Startup: + Při spuštění: + + + Restart Log After Unclean Shutdown + Po nečistém ukončení spustit zápis znovu + + + Log: + Zápis: + + + &Select + &Vybrat + + + &OK + &OK + + + &Cancel + Z&rušit + + + No Audio Configuration Data + Žádná data k nastavení zvuku + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Kanalzuordnungen werden für diesen Host nicht verfügbar sein, da bisher +keine Audio-Ressourcendaten generiert wurden. Bitte starten Sie die Rivendell- +Daemons auf diesem Host neu, indem sie als 'root'-Benutzer den Befehl +'/etc/init.d/rivendell start' ausführen, um die Audioressourcendatenbank zu füllen. + + + [none] + [žádný] + + + Data Error + Chyba v datech + + + Invalid Segue Length! + Neplatná délka přechodu! + + + Invalid Forced Segue Length! + Neplatná délka vynuceného přechodu! + + + Display Settings + Nastavení zobrazení + + + Background Image: + Obrázek pozadí: + + + Select + Vybrat + + + Select Image File + Vybrat soubor s obrázkem + + + Show Extra Buttons/Counters + Ukázat další tlačítka/počítadla + + + Audition Preroll: + Umístění přehrání zkušebního výstupu před: + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + Přiřazení kanálů nebudou dostupná pro tento server jako zdroj zvuku, data +ještě nebyla vytvořena. Spusťte, prosím, démony Rivendell na serveru +nastaveném pro běh služby CAE pro naplnění databáze se zdroji zvuku. + + + Configure Hot Keys + Nastavit zkratkové klávesy + + + Show Hour Selector + + + + Edit +GPIOs + + + + Title Template: + + + + Artist Template: + + + + Outcue Template: + + + + Description Template: + + + + Log Mode Control + + + + Mode Control Style: + + + + Unified + + + + Independent + + + + Main Log Startup Mode: + + + + Aux 1 Log Startup Mode: + + + + Aux 2 Log Startup Mode: + + + + + EditRDLibrary + + RDLibrary config for + Nastavení RDLibrary pro + + + INPUT + VSTUP + + + OUTPUT + VÝSTUP + + + Settings + Nastavení + + + &Max Record Time: + &Největší čas nahrávání: + + + &VOX Threshold: + Práh &VOX: + + + dbFS + dbFS + + + &AutoTrim Threshold: + Práh pro &automatické zastřižení: + + + &Tail Preroll: + Předtočení &ocasu: + + + milliseconds + Milisekundy + + + &Ripper Device: + Zařízení &trhače: + + + &Paranoia Level: + Úroveň &Paranoia: + + + Ripper Level: + Úroveň trhače: + + + &FreeDB Server: + Server &FreeDB: + + + &Format: + &Formát: + + + &Sample Rate: + &Samplerate: + + + &Bitrate: + &Datový tok: + + + No + Ne + + + Yes + Ano + + + Allow E&xternal Editing: + Povolit &vnější úpravy: + + + Defaults + Výchozí + + + &Channels: + &Kanály: + + + Record Mode: + Režim nahrávání: + + + AutoTrim: + Automatické zastřižení: + + + &OK + &OK + + + &Cancel + Z&rušit + + + No Audio Configuration Data + Žádná data k nastavení zvuku + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Kanalzuordnungen werden für diesen Host nicht verfügbar sein, da Audio- +Ressourcendaten nich nicht generiert wurden. Bitte starten sie die Rivendell- +deamons auf diesem Host, indem sie als Benutzer 'root' das Kommando "/etc/init.d/rivendell start" +eingeben um die Audioressourcendatenbank zu füllen. + + + Normal + Normální + + + Low + Nízký + + + None + Žádný + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG Layer 2 + + + Manual + Ruční + + + VOX + VOX + + + 32 kbps/chan + 32 kB/s/kanál + + + 48 kbps/chan + 48 kB/s/kanál + + + 56 kbps/chan + 56 kB/s/kanál + + + 64 kbps/chan + 64 kB/s/kanál + + + 80 kbps/chan + 80 kB/s/kanál + + + 96 kbps/chan + 96 kB/s/kanál + + + 112 kbps/chan + 112 kB/s/kanál + + + 128 kbps/chan + 128 kB/s/kanál + + + 160 kbps/chan + 160 kB/s/kanál + + + 192 kbps/chan + 192 kB/s/kanál + + + 40 kbps/chan + 40 kB/s/kanál + + + 224 kbps/chan + 224 kB/s/kanál + + + 256 kbps/chan + 256 kB/s/kanál + + + 320 kbps/chan + 320 kB/s/kanál + + + Sample Rate Converter: + Převodník vzorkovacího kmitočtu: + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + Přiřazení kanálů nebudou dostupná pro tento server jako zdroj zvuku, data +ještě nebyla vytvořena. Spusťte, prosím, démony Rivendell na serveru +nastaveném pro běh služby CAE pro naplnění databáze se zdroji zvuku. + + + Limit Searches at Startup + + + + Previous + Předchozí + + + + EditRDLogedit + + RDLogedit config for + Nastavení RDLogedit pro + + + INPUT + VSTUP + + + OUTPUT + VÝSTUP + + + Voice Tracker Settings + Nastavení rozdělovače hlasu + + + &Max Record Time: + &Největší čas nahrávání: + + + &AutoTrim Threshold: + Práh pro &automatické zastřižení: + + + dbFS + dbFS + + + &Normalization Level: + Úroveň &normalizace: + + + &Audio Margin: + Okraj &zvuku: + + + milliseconds + milisekund + + + &Format: + &Formát: + + + &Bitrate: + &Datový tok: + + + Play &Start Cart: + Přehrát &počáteční vozík: + + + Select + Vybrat + + + Play &End Cart: + Přehrát &koncový vozík: + + + &Record Start Cart: + &Nahrát počátečníí vozík: + + + Re&cord End Cart: + Na&hrát koncový vozík: + + + &Channels: + &Kanály: + + + Default Transition: + Výchozí přechod: + + + Play + Přehrát + + + Segue + Přechod + + + Stop + Zastavit + + + &OK + &OK + + + &Cancel + Z&rušit + + + No Audio Configuration Data + Žádná data k nastavení zvuku + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + Přiřazení kanálů nebudou dostupná pro tento server jako zdroj zvuku, data +ještě nebyla vytvořena. Spusťte, prosím, démony Rivendell na serveru +nastaveném pro běh služby CAE pro naplnění databáze se zdroji zvuku. + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG Layer 2 + + + 32 kbps/chan + 32 kB/s/kanál + + + 48 kbps/chan + 48 kB/s/kanál + + + 56 kbps/chan + 56 kB/s/kanál + + + 64 kbps/chan + 64 kB/s/kanál + + + 80 kbps/chan + 80 kB/s/kanál + + + 96 kbps/chan + 96 kB/s/kanál + + + 112 kbps/chan + 112 kB/s/kanál + + + 128 kbps/chan + 128 kB/s/kanál + + + 160 kbps/chan + 160 kB/s/kanál + + + 192 kbps/chan + 192 kB/s/kanál + + + 40 kbps/chan + 40 kB/s/kanál + + + 224 kbps/chan + 224 kB/s/kanál + + + 256 kbps/chan + 256 kB/s/kanál + + + 320 kbps/chan + 320 kB/s/kanál + + + No + Ne + + + Yes + Ano + + + Enable &2nd Start Button: + + + + + EditRDPanel + + RDPanel config for + Nastavení RDPanel pro + + + Channel Assignments + Přiřazení kanálu + + + SoundPanel First Play Output + Panel zvuku výstup prvního přehrání + + + Start RML: + Spustit RML: + + + Stop RML: + Zastavit RML: + + + SoundPanel Second Play Output + Panel zvuku výstup druhého přehrání + + + SoundPanel Third Play Output + Panel zvuku výstup třetího přehrání + + + SoundPanel Fourth Play Output + Panel zvuku výstup čtvrtého přehrání + + + SoundPanel Fifth and Later Play Output + Panel zvuku výstup pátého a pozdějšího přehrání + + + SoundPanel Cue Output + Panel zvuku Výstup náhledu + + + Display Settings + Nastavení zobrazení + + + Background Image: + Obrázek pozadí: + + + Select + Vybrat + + + Sound Panel Settings + Nastavení zvukového panelu + + + None + Žádný + + + Host Panels: + Panely serveru: + + + User Panels: + Panely uživatele: + + + Flash Active Buttons + Blikat činnými tlačítky + + + Enable Button Pausing + Povolit pozastavení záznamu + + + Clear Cart Search Filter + Smazat filtr hledání vozíku + + + Default Service: + Výchozí služba: + + + Label Template: + Předloha štítku: + + + &OK + &OK + + + &Cancel + Z&rušit + + + No Audio Configuration Data + Žádná data k nastavení zvuku + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Přiřazení kanálů nebudou dostupná pro tento server jako zdroj zvuku, data +ještě nebyla vytvořena. Spusťte, prosím, démony Rivendell na tomto serveru. +Zadejte jako superuživatel 'root' příkaz "/etc/init.d/rivendell start" +pro naplnění databáze zdroji zvuku. + + + [none] + [žádný] + + + Select Image File + Vybrat soubor s obrázkem + + + + EditReplicator + + Replicator: + Zopakování: + + + Name: + Název: + + + Description: + Popis: + + + Type: + Typ: + + + Host System: + Systém serveru: + + + Audio Upload URL: + Adresa (URL) nahrání zvuku: + + + Username: + Uživatelské jméno: + + + Password: + Heslo: + + + Upload Format: + Formát nahrání: + + + S&et + &Nastavit + + + Normalize + Normalizovat + + + Level: + Úroveň: + + + dBFS + dbFS + + + Available Groups + Dostupné skupiny + + + Active Groups + Činné skupiny + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditReport + + Edit Report + Upravit zprávu + + + &Report Description: + &Popis zprávy: + + + Export &Filter: + &Filter pro vyvedení: + + + Station ID: + ID stanice: + + + Cart Number Parameters: + Parametry pro čísla vozíků: + + + Use Leading Zeros + Použít nuly na začátku + + + Digits: + Místa: + + + Station Type: + Typ stanice: + + + Lines per Page: + Řádků na stranu: + + + Ser&vice Name: + Název &služby: + + + Station &Format: + &Formát stanice: + + + Linux Export Path: + Cesta pro vyvedení v Linuxu: + + + Windows Export Path: + Cesta pro vyvedení ve Windows: + + + Export Event Types: + Vyvést tyto typy událostí: + + + Traffic + Přenos + + + Music + Hudba + + + All + Vše + + + Export Events From: + Vyvést událost z: + + + Traffic Log + Zápis přenosu + + + Music Log + Zápis hudby + + + No + Ne + + + Yes + Ano + + + Include Only OnAir Events: + Zahrnout jen události V éteru (OnAir): + + + Available Services + Dostupné služby + + + Source Services + Zdrojové služby + + + Available Hosts + Dostupné servery + + + Source Hosts + Zdrojové servery + + + &OK + &OK + + + &Cancel + Z&rušit + + + Available Groups + Dostupné skupiny + + + Allowed Groups + + + + Filter by Groups + + + + Filter by Daypart + + + + Start Time: + + + + End Time: + + + + + EditSettings + + System-Wide Settings + Nastavení systému-wide + + + System Sample Rate: + Vzorkovací kmitočet systému: + + + samples/second + vzorky/sekundy + + + Allow Duplicate Cart Titles + Povolit zdvojené názvy vozíků + + + ISCI Cross Reference Path: + Cesta křížového odkazu ISCI: + + + Maximum Remote Post Length: + Největší délka vzdáleného vyvěšení: + + + Mbytes + MiB + + + The following duplicate titles must be corrected before "Allow Duplicate Values" can be turned off. + Následující zdvojené názvy musí být opraveny před vypnutím Povolit zdvojené hodnoty. + + + CART + VOZÍK + + + TITLE + NÁZEV + + + &Save List + &Uložit seznam + + + &OK + &OK + + + &Cancel + Z&rušit + + + File Exists + Soubor existuje + + + The file " + Soubor " + + + " exists. + +Overwrite? + " existuje. + +Přepsat? + + + File Error + Chyba v souboru + + + Unable to write file " + Nelze zapsat soubor " + + + Checking the Library for duplicates. + Přezkušuje se knihovna kvůli zdvojeným názvům. + + + Temporary Cart Group: + + + + + EditStation + + Host: + Server: + + + Ho&st Name: + Název &serveru: + + + &Description: + &Popis: + + + Default &User: + Výchozí &uživatel: + + + &IP Address: + Adresa &IP: + + + Editor &Command: + &Příkaz pro editor: + + + mS + mS + + + &Time Offset: + Č&asový odstup: + + + &Startup Cart: + Vozík &spuštění: + + + Select + Vybrat + + + Enable Heartbeat + Povolit srdeční tep + + + Use Realtime Filtering + Použít filtrování ve skutečném čase + + + Cart: + Vozík: + + + Interval: + Interval: + + + secs + s + + + RD&Library + RD&Library + + + RDCatch + RDCatch + + + RDAirPlay + RDAirplay + + + RDPanel + RDPanel + + + RDLogEdit + RDLogedit + + + Dropboxes + Dropboxy (stoupací člunečníky) + + + Audio +Resources + Zdroje +zvuku + + + Audio +Ports + Zvukové +přípojky + + + Serial +Ports + Sériové +přípojky + + + Switchers +GPIO + GPIO +přepínače + + + Host +Variables + Proměnné +serveru + + + Backups + Zálohy + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Address + Neplatná adresa + + + The specified IP address is invalid! + Zadaná adresa IP je neplatná! + + + Invalid Cart + Neplatný vozík + + + The Heartbeat Cart number is invalid! + Číslo vozíku srdečního tepu je neplatné! + + + Security Model: + Bezpečnostní model: + + + Host + Server + + + User + Uživatel + + + Custom +Encoders + Vlastní +kodéry + + + Include in System Maintenance Pool + Zahrnout do sdílených prostředků pro údržbu systému + + + System Maintenance + Údržba systému + + + At least one host must belong to the system maintenance pool! + Alespoň jeden server musí náležet do sdílených prostředků pro údržbu systému! + + + HTTP Xport: + HTTP Xport: + + + Core Audio Engine: + Jaderný zvukový stroj: + + + System Services + Systémové služby + + + JACK +Settings + Nastavení +pro JACK + + + Cue &Output: + + + + RDCart +Slots + + + + RDAdmin - No Audio Configuration Data + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + Přiřazení kanálů nebudou dostupná pro tento server jako zdroj zvuku, data +ještě nebyla vytvořena. Spusťte, prosím, démony Rivendell na serveru +nastaveném pro běh služby CAE pro naplnění databáze se zdroji zvuku. + + + Enable Drag && Drop + + + + Allow Drops on Panels not in Setup Mode + + + + Start Cart + + + + Stop Cart + + + + + EditSvc + + Edit Service + Upravit službu + + + &Service Name: + Název &služby: + + + Service &Description: + &Popis služby: + + + Log &Template Name: + Název &předlohy zápisu: + + + [none] + [žádný] + + + Voicetrack Group: + Skupina hlasová stopa: + + + Insert CHAIN TO at log end + Na konci zápisu vložit přechod k + + + Enable AutoRefresh By Default + Povolit automatickou obnovu ve výchozím nastavení + + + Configure +&Autofill Carts + Nastavit +&automatické naplnění vozíků + + + Enable &Hosts + Povolit &servery + + + Traffic Data Import + Zavedení přenosových dat + + + Linux Import Path: + Cesta pro zavedení v Linuxu: + + + Windows Import Path: + Cesta pro zavedení ve Windows: + + + Note Cart String: + Poznamenat řetězec vozíku: + + + Insert Voice Track String: + Vložit řetězec hlasové stopy: + + + Cart Number: + Cart Nummer: + + + Offset: + Abstand: + + + Length: + Länge: + + + Title: + Titel: + + + Start Time - Hours: + Startzeit-Stunden: + + + Start Time - Minutes: + Startzeit-Minuten: + + + Start Time - Seconds: + Startzeit-Sekunden: + + + Length - Hours: + Länge Stunden: + + + Length - Minutes: + Länge Minuten: + + + Length - Seconds: + Länge Sekunden: + + + Contract #: + Vertragsnummer: + + + Event ID: + Event-ID: + + + Annc. Type: + Annc.-Typ: + + + Test +&Traffic + Vyzkoušet +&přenos + + + Music Data Import + Zavedení hudebních dat + + + Insert Traffic Break String: + Vložit řetězec přerušení přenosu: + + + Test +&Music + Vyzkoušet +&hudbu + + + &OK + &OK + + + &Cancel + Z&rušit + + + Save Import Data + Uložit data zavedení + + + Before testing, the import configuration +must be saved. Save now? + Před zkouškou musí být nastavení zavedení +uloženo. Uložit nyní? + + + Purge ELR Data after + Smazat data ELR po + + + days + dnů + + + Purge Logs after + Smazat zápisy po + + + Import Template: + Předloha pro zavedení: + + + [custom] + [vlastní] + + + Linux Preimport Command: + Příkaz pro před-zavedení v Linuxu: + + + Windows Preimport Command: + Příkaz pro před-zavedení ve Windows: + + + &Program Code: + &Programový kód: + + + AutoSpot Group: + + + + Log Name &Template: + + + + Log &Description Template: + + + + + EditSvcPerms + + Service: + Služba: + + + Available Hosts + Dostupné servery + + + Enabled Hosts + Povolené servery + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditTtys + + Edit TTYs + Upravit TTY + + + Port ID: + ID přípojky: + + + Enabled + Povoleno + + + TTY Device: + Zařízení TTY: + + + Baud Rate: + Rychlost datového přenosu: + + + Parity: + Rovnost: + + + Data Bits: + Bity dat: + + + Stop Bits: + Bity zastavení: + + + Terminator: + Ukončovatel: + + + &Close + &Zavřít + + + Serial + Sériový + + + None + Žádný + + + Even + Sudý + + + Odd + Lichý + + + CR + CR + + + LF + LF + + + CR/LF + CR/LF + + + + EditUser + + User: + Uživatel: + + + &User Name: + &Uživatelské jméno: + + + &Full Name: + &Celé jméno: + + + &Description: + &Popis: + + + &Phone: + &Telefon: + + + Allow Web Logins + Dovolit webová přihlášení + + + Change +&Password + Změnit +&heslo + + + Administrative Rights + Správcovská práva + + + Administer S&ystem + Spravovat s&ystém + + + Production Rights + Výrobní práva + + + &Create Carts + &Vytvořit vozíky + + + &Delete Carts + &Smazat vozíky + + + &Modify Carts + &Upravit vozíky + + + &Edit Audio + U&pravit zvuk + + + &Edit Netcatch Schedule + U&pravit rozvrh zachycení sítě + + + &Voicetrack Logs + Zápisy &hlasové stopy + + + Traffic Rights + Přenosová práva + + + Create &Log + Vytvořit &zápis + + + De&lete Log + &Smazat zápis + + + Delete &Report Data + Smazat data zprávy + + + &Modify Template + Up&ravit předlohu + + + OnAir Rights + Práva k V éteru + + + &Playout Logs + Zápisy o &hraní + + + &Rearrange Log Items + &Přeuspořádat položky zápisu + + + Add Log &Items + Přidat po&ložky zápisu + + + Delete Lo&g Items + Smazat položky záp&isu + + + Configure System Panels + Nastavit systémové panely + + + Podcasting Rights + Práva k podcastu + + + Cre&ate Podcast + Vytvořit podc&ast + + + E&dit Podcast + Upr&avit podcast + + + Dele&te Podcast + Smaza&t podcast + + + Assign Group +Permissions + Přiřadit povolení +pro skupinu + + + Assign Podcast Feed +Permissions + Přiřadit povolení +pro přívod pro podcast + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditUserPerms + + User: + Uživatel: + + + Available Groups + Dostupné skupiny + + + Enabled Groups + Povolené skupiny + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditVguestResource + + Engine (Hex): + Stroj (Hex): + + + Device (Hex): + Zařízení (Hex): + + + Surface (Hex): + Povrch (Hex): + + + Bus/Relay (Hex): + Sběrnice/relé (hex): + + + &OK + &OK + + + &Cancel + Z&rušit + + + Edit vGuest Switch + Upravit přepínač vGuest + + + Edit vGuest Display + Upravit zobrazení vGuest + + + Invalid Number + Neplatné číslo + + + The Engine Number is Invalid! + Číslo stroje je neplatné! + + + The Device Number is Invalid! + Číslo zařízení je neplatné! + + + The Surface Number is Invalid! + Číslo povrchu je neplatné! + + + The Bus/Relay Number is Invalid! + Číslo sběrnice/relé je neplatné! + + + + InfoDialog + + System Information + Informace o systému + + + Rivendell + Rivendell + + + A Radio Automation System + Sestava pro automatizaci rádia + + + Version + Verze + + + Database Schema + Databázové schéma + + + This program is free software, and comes with ABSOLUTELY NO WARRANTY, +not even the implied warranties of MERCHANTIBILITY or FITNESS FOR A +PARTICULAR PURPOSE. Touch the "View License" button for details. + Tento program je svobodným softwarem a je šířen v naději, že bude užitečný, ale +BEZ JAKÉKOLI ZÁRUKY; také bez předpokládané záruky PRODEJNOSTI nebo +POUŽITELNOSTI PRO NĚJAKÝ URČITÝ ÚČEL: Více podrobností naleznete v +GNU Library General Public License. Klepněte na tlačítko pro zobrazení povolení. + + + View +&License + Zobrazit +&povolení + + + &Close + &Zavřít + + + Copyright 2002-2008 + Copyright 2002-2009 + + + Copyright 2002-2010 + Autorské právo 2002-2010 + + + Copyright 2002-2014 + Autorské právo 2002-2014 + + + + ListAuxFields + + Auxiliary Metadata Fields + Pomocná pole s popisnými daty + + + Var Name + Název proměnné + + + Caption + Popisek + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &Close + &Zavřít + + + Warning + Varování + + + This will delete all data associated with this field! +Are you sure you want to continue? + Toto smaže všechna data spojená s tímto polem! +Jste si jistý, že chcete pokračovat? + + + + ListDropboxes + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &Close + &Zavřít + + + Group + Skupina + + + Path + Cesta + + + Normalization Level + Úroveň normalizace + + + Autotrim Level + Úroveň automatického zastřižení + + + To Cart + Do vozíku + + + Use CartChunk ID + Použít ID kousku vozík + + + Delete Cuts + Smazat záběry + + + Metadata Pattern + Vzor pro popisná data + + + Fix Broken Formats + Opravit poškozené formáty + + + [off] + [vypnuto] + + + [auto] + [automaticky] + + + [none] + [žádný] + + + User Defined + + + + + ListEncoders + + RDAdmin - List Encoders + RDAdmin - Zobrazit kodéry + + + Format Name + Název formátu + + + Valid Channels + Platné kanály + + + Valid Sample Rates + Platné vzorkovací kmitočty + + + Valid Bit Rates + Platné datové toky + + + &Edit + &Upravit + + + &Close + &Zavřít + + + [none] + [žádný] + + + &Add + &Přidat + + + &Delete + S&mazat + + + RDAdmin - Delete Encoder + RDAdmin - Smazat kodér + + + Are you sure you want to delete this encoder? + Opravdu chcete smazat tento kodér? + + + Extension + Rozšíření + + + This encoder is in use by the following RSS feeds: + + + Tento kodér je používán následujícími přívody RSS: + + + + + + +Do you still want to delete it? + + +Stále ještě jej chcete smazat? + + + Encoders on + Kodéry na + + + + ListEndpoints + + List Inputs + Zobrazit vstupy + + + List Outputs + Zobrazit výstupy + + + INPUT + VSTUP + + + OUTPUT + VÝSTUP + + + LABEL + ŠTÍTEK + + + SOURCE + ZDROJ + + + MODE + REŽIM + + + ENGINE (Hex) + STROJ (Hex) + + + DEVICE (Hex) + ZAŘÍZENÍ (Hex) + + + PROVIDER ID + ID POSKYTOVATELE + + + SERVICE ID + ID SLUŽBY + + + NODE + UZEL + + + # + # + + + &Edit + &Upravit + + + &OK + &OK + + + &Cancel + Z&rušit + + + Stereo + Stereo + + + Left + Vlevo + + + Right + Vpravo + + + Input + Vstup + + + Output + Výstup + + + stereo + Stereo + + + left + Vlevo + + + right + Vpravo + + + + ListFeeds + + Rivendell Feed List + Seznam přívodů Rivendell + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &Close + &Zavřít + + + Key + Klíč + + + Title + Název + + + AutoPost + Automatické vyvěšení + + + Keep Metadata + Zachovat popisná data + + + Creation Date + Datum vytvoření + + + &Feeds: + &Přívod: + + + Are you sure you want to delete feed + Opravdu chcete smazat tento přívod + + + Delete Feed + Smazat přívod + + + Deleting Audio... + Mazání zvuku... + + + Cancel + Zrušit + + + Deleting + Mazání + + + + ListGpis + + List GPIs + Zobrazit GPI + + + GPI Lines + Řádky GPI + + + GPI + GPI + + + &Edit + &Upravit + + + &OK + &OK + + + &Cancel + Z&rušit + + + [unassigned] + [nepřiřazeno] + + + GPO + GPO + + + List GPOs + Zobrazit GPO + + + GPO Lines + Řádky GPO + + + ON MACRO CART + ZAPNUTO - MAKROVOZÍK + + + ON DESCRIPTION + ZAPNUTO - POPIS + + + OFF MACRO CART + VYPPNUTO - MAKROVOZÍK + + + OFF DESCRIPTION + ZAPNUTO - POPIS + + + + ListGroups + + Rivendell Group List + Seznam skupin Rivendell + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Rename + &Přejmenovat + + + &Delete + S&mazat + + + Generate +&Report + Vytvořit +&zprávu + + + &Close + &Zavřít + + + NAME + NÁZEV + + + DESCRIPTION + POPIS + + + START CART + ZAČÍT VOZÍK + + + END CART + UKONČIT VOZÍK + + + ENFORCE RANGE + VYNUTIT ROZSAH + + + DEFAULT TYPE + VÝCHOZÍ TYP + + + TRAFFIC REPORT + PŘENOSOVÁ ZPRÁVA + + + MUSIC REPORT + HUDEBNÍ ZPRÁVA + + + NOW & NEXT + NYNÍ & DALŠÍ + + + &Groups: + &Skupiny: + + + member carts will be deleted along with group + Členské vozíky budou smazány se skupinou + + + Are you sure you want to delete group + Opravdu chcete smazat tuto skupinu + + + Delete Group + Smazat skupinu + + + + ListHostvars + + Host Variables for + Proměnné serveru pro + + + Host Variables + Proměnné serveru + + + NAME + NÁZEV + + + VALUE + HODNOTA + + + REMARK + POZNÁMKA + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &OK + &OK + + + &Cancel + Z&rušit + + + + ListLiveWireGpios + + LiveWire GPIO Source Assignments + + + + Switchers: + Přepínače: + + + &Edit + &Upravit + + + &OK + &OK + + + &Cancel + Z&rušit + + + [none] + [žádný] + + + Lines + + + + Surface Address + + + + [all] + + + + Source # + + + + + ListMatrices + + Rivendell Switcher List + Seznam přepínačů Rivendell + + + Switchers: + Přepínače: + + + MATRIX + MATICE + + + DESCRIPTION + POPIS + + + TYPE + TYP + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &Close + &Zavřít + + + Are you sure you want to delete switcher + Opravdu chcete smazat tento přepínač + + + on + na + + + ALL references to this switcher will be deleted! + VŠECHNY odkazy na tento přepínač budou smazány! + + + Deleting Switcher + Mazání přepínače + + + Local GPIO + Místní GPIO + + + Generic GPO + Obecné GPO + + + Generic Serial + Obecné sériové + + + Local Audio Adapter + Místní přípojka zvuku + + + Logitek vGuest + Logitek vGuest + + + BroadcastTools SS16.4 + BroadcastTools SS16.4 + + + StarGuide III + StarGuide III + + + BroadcastTools SS4.2 + BroadcastTools SS4.2 + + + Axia LiveWire + Axia LiveWire + + + Quartz Type 1 + Quartz Typ 1 + + + Unknown + Neznámý + + + BroadcastTools SS4.4 + BroadcastTools SS4.4 + + + BroadcastTools SRC-8 III + BroadcastTools SRC-8 III + + + BroadcastTools SRC-16 + BroadcastTools SRC-16 + + + + ListReplicatorCarts + + &Repost + &Vyvěsit znovu + + + Repost +&All + Vyvěsit &vše +znovu + + + &Close + &Zavřít + + + CART + VOZÍK + + + TITLE + NÁZEV + + + LAST POSTED + NAPOSLEDY VYVĚŠENO + + + &Active Carts: + Č&inné vozíky: + + + Replicator Carts + Vozíky zopakování + + + POSTED FILENAME + VYVĚŠENÝ NÁZEV SOUBORU + + + + ListReplicators + + Rivendell Replicators + Zopakování Rivendell + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &List +Carts + &Vypsat +vozíky + + + &Close + &Zavřít + + + NAME + NÁZEV + + + TYPE + TYP + + + DESCRIPTION + POPIS + + + HOST + SERVER + + + &Replicators: + &Zopakování: + + + Are you sure you want to delete replicator + Opravdu chcete smazat toto zopakování + + + Delete Replicator + Smazat zopakování + + + + ListReports + + Rivendell Report List + Seznam zpráv Rivendell + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &Close + &Zavřít + + + R&eports: + Z&právy: + + + Are you sure you want to delete report + Opravdu chcete smazat tuto zprávu + + + Delete Report + Smazat zprávu + + + + ListStations + + Rivendell Workstation List + Seznam pracovních stanic Rivendell + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &Close + &Zavřít + + + Ho&sts: + &Servery: + + + Are you sure you want to delete host + Opravdu chcete smazat tento server + + + Delete Station + Smazat stanici + + + + ListSvcs + + Services + Služby + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &Close + &Zavřít + + + &Services: + &Služby: + + + Are you sure you want to delete service + Opravdu chcete smazat tuto službu + + + Delete Service + Smazat službu + + + There are + Jsou tu + + + logs owned by this service that will also be deleted. +Do you still want to proceed? + zápisy náležející této službě, které budou taktéž smazány. +Stále ještě chcete pokračovat? + + + Logs Exist + Zápisy existují + + + + ListUsers + + Rivendell User List + Seznam uživatelů Rivendell + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &Close + &Zavřít + + + &Users: + &Uživatelé: + + + DESCRIPTION + POPIS + + + USER NAME + UŽIVATELSKÉ JMÉNO + + + FULL NAME + CELÉ JMÉNO + + + Are you sure you want to delete user + Opravdu chcete smazat tohoto uživatele + + + Delete User + Smazat uživatele + + + You must change this before deleting the user. + Toto musíte před smazáním uživatele změnit. + + + This user is set as the default user for the following hosts: + + + Tento uživatel je nastaven jako výchozí u následujících serverů: + + + + + You cannot delete yourself! + Nemůžete vymazat sám sebe! + + + + Login + + Login + Přihlášení + + + &OK + &OK + + + &Cancel + Z&rušit + + + User &Name: + &Uživatelské jméno: + + + &Password: + He&slo: + + + + MainWidget + + RDAdmin - Host: + RDAdmin-Server: + + + Daemons Failed + Chyba démona + + + Unable to start Rivendell System Daemons! + Nelze spustit démony systému Rivendell! + + + Insufficient Priviledges + Nedostatečná oprávnění + + + This account has insufficient priviledges for this operation. + Tento účet nemá pro tuto operaci dostatečná oprávnění. + + + Manage +&Users + Spravovat +&uživatele + + + Manage +&Groups + Spravovat +&skupiny + + + Manage +&Services + Spravovat +s&lužby + + + Manage +Ho&sts + Spravovat +se&rvery + + + Manage +R&eports + Spravovat +&zprávy + + + Manage +&Feeds + Spravovat +&přívody + + + System +Info + Systemové +informace + + + Scheduler +Codes + Kódy +rozvrhovače + + + &Backup +Database + &Záložní +databáze + + + &Restore +Database + O&bnovit +databázi + + + &Quit + &Ukončit + + + Rivendell Database Backup (*.sql) + Záloha databáze Rivendell (*.sql) + + + Backup Error + Chyba při zálohování + + + Unable to create backup! + Nelze vytvořit zálohu! + + + Backup Complete + Záloha hotova + + + Backup completed successfully. + Záloha úspěšně dokončena. + + + Restore Database + Obnovit databázi + + + WARNING: This operation will COMPLETELY +OVERWRITE the existing Rivendell Database! +Do you want to continue? + VAROVÁNÍ: Tato operace zcela přepíše stávající +databázi Rivendell! +Chcete pokračovat? + + + Restore Error + Chyba při obnově + + + Unable to restore backup! + Nelze obnovit zálohu! + + + Restore Complete + Obnova hotova + + + Restore completed successfully. + Obnova úspěšně dokončena. + + + System +Settings + Nastavení +systému + + + Manage +Replicators + Spravovat +zopakování + + + RDAdmin + RDAdmin + + + + MySqlLogin + + mySQL Admin + Správce mySQL + + + User &Name: + &Uživatelské jméno: + + + &Password: + He&slo: + + + &OK + &OK + + + &Cancel + Z&rušit + + + + QObject + + Start Line 1 + Spustit řádek 1 + + + Stop Line 1 + Zastavit řádek 1 + + + Pause Line 1 + Pozastavit řádek 1 + + + Start Line 2 + Spustit řádek 2 + + + Stop Line 2 + Zastavit řádek 2 + + + Pause Line 2 + Pozastavit řádek 2 + + + Start Line 3 + Spustit řádek 3 + + + Stop Line 3 + Zastavit řádek 3 + + + Pause Line 3 + Pozastavit řádek 3 + + + Start Line 4 + Spustit řádek 4 + + + Stop Line 4 + Zastavit řádek 4 + + + Pause Line 4 + Pozastavit řádek 4 + + + Start Line 5 + Spustit řádek 5 + + + Stop Line 5 + Zastavit řádek 5 + + + Pause Line 5 + Pozastavit řádek 5 + + + Start Line 6 + Spustit řádek 6 + + + Stop Line 6 + Zastavit řádek 6 + + + Pause Line 6 + Pozastavit řádek 6 + + + Start Line 7 + Spustit řádek 7 + + + Stop Line 7 + Zastavit řádek 7 + + + Pause Line 7 + Pozastavit řádek 7 + + + Add + Přidat + + + Delete + Smazat + + + Copy + Kopírovat + + + Move + Posunout + + + Sound Panel + Zvukový panel + + + Main Log + Hlavní zápis + + + Aux Log 1 + Pomocný zápis 1 + + + Aux Log 2 + Pomocný zápis 2 + + + (default) + (výchozí) + + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + Nelze přistupovat k databázi Rivendell! +Zadejte, prosím, přihlašovací údaje k účtu s +administrátorskými právy k mySQL serveru +a my se pokusíme toto opravit. + + + Wrong access permissions for accessing mySQL! + Špatná přístupová práva pro přístup k mySQL! + + + Unable to connect to mySQL! + Nelze se spojit s mySQL! + + + Unable to create a Rivendell Database! + Nelze vytvořit databázi Rivendell! + + + Unable to connect to new Rivendell Database! + Nelze se spojit s novou databází Rivendell! + + + Unable to create Rivendell Database! + Nelze vytvořit databázi Rivendell! + + + Unable to connect to Rivendell Database! + Nelze se spojit s databází Rivendell! + + + Unable to initialize Rivendell Database! + Nelze spustit databází Rivendell! + + + RDAdmin + RDAdmin + + + New Rivendell Database Created! + Nová databáze Rivendell vytvořena! + + + Unable to upgrade database + Aktualizace databáze není možná + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + Databáze Rivendell je příliš stará na to, aby byla povýšena a +musí se nahradit. Toto SMAŽE všechny stávající nahrávky +a data! Pokud to chcete udělat, zadejte uživatelské jméno +a heslo k účtu mySQL se správcovskými právy, jinak klepněte na +zrušit. + + + Unable to log into Administrator account! + Nelze se přihlásit k správcovskému účtu! + + + Unable to authorize a Rivendell Database! + Nelze povolit databází Rivendell! + + + Update Needed + Aktualizace potřeba + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + Databázi Rivendell je potřeba obnovit. +Všechny nahrávky a nastavení budou uloženy, ale toto +ZASTAVÍ všechna přehrávání zvuku nebo nahrávání +na tomto počítači na několik sekund. Pokračovat? + + + Unable to update Rivendell Database: + Nelze obnovit databázi Rivendell: + + + +Database backup failed! + +Záloha databáze se nezdařila! + + + +Schema modification failed! + +Změna schématu se nezdařila! + + + +Unknown/unspecified error! + +Neznámá/blíže neurčená chyba! + + + The Rivendell Database has been updated to version + Databáze Rivendell byla zaktualizována na verzi + + + +and a backup of the original database saved in + +a záloha původní databáze uložena v + + + Database Updated + Databáze obnovena + + + RDAdmin Error + Chyba RDadmin + + + + RenameGroup + + Rename Group + Přejmenovat skupinu + + + Current Group Name: + Název nynější skupiny: + + + New &Group Name: + Název &nové skupiny: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Group + Neplatná skupina + + + The group name is invalid! + Název skupiny je neplatný! + + + A + Tato + + + group already exists. +Do you want to combine the two? + skupina již existuje. +Chcete obě spojit? + + + Group Exists + Skupina existuje + + + + TestImport + + Test Traffic Import + Vyzkoušet zavedení přenosu + + + Test Music Import + Vyzkoušet zavedení hudby + + + Test Date: + Datum zkoušky: + + + &Select + &Vybrat + + + &Import + &Zavést + + + Using source file: + Použít zdrojový soubor: + + + Start Time + Počáteční čas + + + Cart + Vozík + + + Len + Délka + + + Title + Název + + + Contract # + Číslo smlouvy + + + Event ID + ID události + + + Announcement Type + Typ oznámení + + + Imported Events + Zavedené události + + + &Close + &Zavřít + + + Import Error + Chyba při zavedení + + + There was an error during import +please check your settings and try again. + Během zavedení se vyskytla chyba. +Prověřte, prosím, svá nastavení a zkuste to znovu. + + + [spot break] + [přerušení místa] + + + + ViewAdapters + + Audio Resource Information + Informace o zdrojích zvuku + + + Audio Resources on + Zdroje zvuku na + + + SUPPORTED AUDIO DRIVERS + + PODPOROVANÉ OVLADAČE ZVUKU + + + SUPPORTED IMPORT FORMATS + + PODPOROVANÉ FORMÁTY ZAVEDENÍ + + + + PCM16 Linear + + PCM 16 Linear + + + + MPEG Layer 1 + + MPEG Layer 1 + + + + MPEG Layer 2 + + MPEG Layer 2 + + + + MPEG Layer 3 + + MPEG Layer 3 + + + + OggVorbis + + OggVorbis + + + + SUPPORTED EXPORT FORMATS + + PODPOROVANÉ FORMÁTY VYVEDENÍ + + + + Free Lossless Audio Codec (FLAC) + + Free Lossless Audio Codec (FLAC) + + + + AUDIO ADAPTERS + + AUDIOADAPTÉR + + + + Card + Karta + + + Not present + Nepřítomné + + + Driver: AudioScience HPI + + Ovladač: AudioScience HPI + + + + Driver: JACK Audio Connection Kit + + Driver: JACK Audio Connection Kit + + + + Driver: Advanced Linux Sound Architecture (ALSA) + + Ovladač: Advanced Linux Sound Architecture (ALSA) + + + + Driver: UNKNOWN + + Ovladač: NEZNÁMÝ + + + + Inputs: + Vstupy: + + + Outputs: + Výstupy: + + + NO DATA AVAILABLE + + + ŽÁDNÁ DATA NEJSOU DOSTUPNÁ + + + + + Please start the Rivendell daemons on this host (by executing, as user 'root', the command "/etc/init.d/rivendell start") in order to populate the audio resources database. + Spusťte, prosím, démony Rivendell na tomto serveru. Zadejte jako superuživatel 'root' příkaz "/etc/init.d/rivendell start" +pro naplnění databáze zdroji zvuku. + + + &Close + &Zavřít + + + diff --git a/rdadmin/rdadmin_de.ts b/rdadmin/rdadmin_de.ts new file mode 100644 index 00000000..53eac7bb --- /dev/null +++ b/rdadmin/rdadmin_de.ts @@ -0,0 +1,5836 @@ + + + @default + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + Kann nicht auf die Rivendell-Datenbank zugreifen! +Bitte geben sie einen login für einen Account mit +administrativen Rechten auf dem mySQL-Server an +und wir werden versuchen, das zu korrigieren. + + + Can't Connect + Kann nicht verbinden + + + Wrong access permissions for accessing mySQL! + Falsche Zugriffsrechte für mySQL! + + + Unable to connect to mySQL! + Kann nicht zu mySQL verbinden! + + + Can't Create DB + Kann die Datenbank nicht erstellen + + + Unable to create a Rivendell Database! + Kann keine Rivendell-Datenbank erstellen! + + + Unable to connect to new Rivendell Database! + Kann nicht zur neuen Rivendell-Datenbank verbinden! + + + Can't Create + Kann nicht erstellen + + + Unable to create Rivendell Database! + Kann die Rivendell-Datenbank nicht erstellen! + + + Unable to connect to Rivendell Database! + Kann nicht zur Rivendell-Datenbank verbinden! + + + Can't Initialize + Kann nicht initialisieren + + + Unable to initialize Rivendell Database! + Kann die Rivendell-Datenbank nicht initialisieren! + + + Created Database + Datenbank erstellt + + + New Rivendell Database Created! + Neue Rivendell-Datenbank erstellt! + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + Die Rivendell-Datenbank ist zu alt zum upgraden und +muss ersetzt werden. Dies wird ALLE existierenden Aufnahmen +und Daten LÖSCHEN! Wenn sie dies tun wollen, geben sie +einen Benutzernamen und ein Paßwort für einen mySQL- +Account mit administrativen Rechten ein, ansonsten klicken +sie abbrechen. + + + Unable to log into Administrator account! + Kann nicht in den Administratoraccount einloggen! + + + Unable to authorize a Rivendell Database! + Kann keine Rivendelldatenbank authorisieren! + + + Update Needed + Update notwendig + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + Die Rivendell-Datenbank benötigt ein Update. +Alle Aufnahmen und Einstellungen werden gespeichert, +aber dies wird alle Audio-Auspielungen oder Aufnahmen +auf diesem Rechner für ein paar Sekunden STOPPEN. +Fortfahren? + + + Can't Update + Kann nicht updaten + + + Unable to update Rivendell Database! + Kann die Rivendell-Datenbank nicht updaten! + + + The Rivendell Database has +been updated to Version + Die Rivendell-Datenbank ist geupdatet +worden. Aktuelle Version + + + Database Updated + Datenbank geupdatet + + + RDAdmin Error + RDadmin Fehler + + + Unable to upgrade database + Upgrade der Datenbank nicht möglich + + + + AddAuxField + + Add Aux Field + + + + Variable Name: + + + + %AUX_ + + + + % + + + + Caption: + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Name Exists + + + + That variable name already exists! + + + + + AddEncoder + + Add Encoder + + + + &New Encoder Name: + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Add Encoder Error + + + + A encoder with that name already exists! + + + + + AddFeed + + Add Feed + + + + Enable Feed for All Users + + + + &New Feed Name: + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Add Feed Error + + + + A feed with that key name already exists! + + + + + AddGroup + + Add Group + Gruppe hinzufügen + + + &New Group Name: + &Neuer Gruppenname: + + + Enable Group for All Users + Gruppe für alle Benutzer freischalten + + + Enable Group for All Services + Gruppe für alle Services freischalten + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Name + Ungültiger Name + + + You must give the group a name! + Sie müssen der Gruppe einen Namen geben! + + + Group Exists + Gruppe Existiert + + + Group Already Exists! + Gruppe existiert bereits! + + + + AddHostvar + + Add Host Variable + Hostvariable hinzufügen + + + Variable Name: + Variablenname: + + + Variable Value: + Variablenwert: + + + Remark: + Bemerkung: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Name + Ungültiger Name + + + The variable name is invalid. + + + + + AddMatrix + + Add Switcher + Switcher hinzufügen + + + &New Matrix Number: + &Neue Matrixnummer: + + + Local GPIO + Lokaler GPIO + + + Generic GPO + Generischer GPO + + + Generic Serial + Generisch Seriell + + + Local Audio Adapter + Lokaler Audioanschluss + + + Logitek vGuest + Logitek vGuest + + + BroadcastTools SS16.4 + BroadcastTools SS16.4 + + + StarGuide III + StarGuide III + + + BroadcastTools SS4.2 + BroadcastTools SS4.2 + + + Axia LiveWire + Axia LiveWire + + + Quartz Type 1 + Quartz Typ 1 + + + &Switcher Type: + &Switcher-Typ: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Matrix + Ungültige Matrix + + + Matrix already exists! + Matrix existiert bereits! + + + BroadcastTools SS4.4 + BroadcastTools SS4.4 + + + BroadcastTools SRC-8 III + BroadcastTools SRC-8 III + + + BroadcastTools SRC-16 + BroadcastTools SRC-16 + + + New Switcher + + + + RDAdmin - Add Switcher + + + + + AddReplicator + + Add Replicator + + + + &New Replicator Name: + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Name + Ungültiger Name + + + You must give the replicator a name! + + + + Replicator Exists + + + + A replicator with that name already exists! + + + + + AddReport + + Add Report + Report hinzufügen + + + &Report Name: + &Report-Name: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Name + Ungültiger Name + + + You must provide a report name! + Sie müssen einen Reportnamen angeben! + + + Report Exists + Report existiert + + + A report with that name already exists! + Ein report mit diesem Namen existiert bereits! + + + + AddStation + + Add Host + Host hinzufügen + + + New &Host Name: + Neuer &Hostname: + + + Base Host On: + Host basierend auf: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Empty Host Config + Host Konfiguration leeren + + + Invalid Name + Ungültiger Name + + + You must give the host a name! + Sie müssen dem Host einen Namen geben! + + + Host Exists + Host existiert + + + Host Already Exists! + Host existiert bereits! + + + + AddSvc + + Add Service + Service hinzufügen + + + &New Service Name: + &Neuer Servicename: + + + Base Service On: + Service basierend auf: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Empty Host Config + Host Konfiguration leeren + + + Invalid Name + Ungültiger Name + + + You must give the service a name! + Sie müssen dem Service einen Namen geben! + + + Service Exists + Service existiert + + + Service Already Exists! + Service existiert bereits! + + + + AddUser + + Add User + Benutzer hinzufügen + + + &New User Name: + &Neuer Benutzername: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Name + Ungültiger Name + + + You must give the user a name! + Sie müssen dem Benutzer einen Namen geben! + + + User Exists + Benutzer existiert + + + User Already Exists! + Benutzer existiert bereits! + + + + AutofillCarts + + Autofill Carts - Service: + Automatischer Cartfüllservice: + + + Cart + Cart + + + Length + Länge + + + Title + Titel + + + Artist + Künstler + + + &Add + &Hinzufügen + + + &Delete + &Löschen + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + EditAudioPorts + + Edit Audio Ports + Audioports editieren + + + Clock Source: + Uhrenquelle: + + + Input Port + Eingangsport + + + Analog + Analog + + + AES/EBU + AES/EBU + + + SP/DIFF + SP/DIFF + + + Type: + Typ: + + + Normal + Normal + + + Swap + Swap + + + Left only + nur links + + + Right only + nur rechts + + + Mode: + Modus: + + + dB + dB + + + Level: + Level: + + + Output Port + Ausgangsport + + + &Help + &Hilfe + + + &Close + &Schliessen + + + Internal + Intern + + + AES/EBU Signal + AES/EBU-Signal + + + SP/DIFF Signal + SP/DIFF-Signal + + + Word Clock + Word Clock + + + Card: + Karte: + + + Card Driver: + + + + Ref. Level: + + + + + EditAuxField + + Edit Auxiliary Metadata Fields + + + + Variable Name: + + + + Caption: + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + EditBackup + + Backup config for + Konfigurationsbackup für + + + Keep Backups For: + Backups behalten für: + + + days + Tage + + + Backup Directory: + Backup-Verzeichnis: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Path Missing + Pfad fehlt + + + You must supply a backup path! + Sie müssen einen Backup-Pfad angeben! + + + + EditCartSlots + + RDAdmin - Edit CartSlots + + + + Close + + + + None + + + + Output Port: + + + + Card: + Karte: + + + Input Port: + + + + Cart + Cart + + + Mode: + Modus: + + + Cart: + Cart: + + + At Playout End: + + + + Channel Assignments + Kanal-Zuordnungen + + + Default Settings + + + + Select + Auswählen + + + Load Specified Cart + + + + At Startup: + Beim Start: + + + Do Nothing + + + + Slot Mode: + + + + Full + + + + Hook + + + + Play Mode: + + + + User previous mode + + + + Use previous mode + + + + Use previous cart + + + + Use previous action + + + + Service: + + + + Global Settings + + + + Slot Columns: + + + + Slot Rows: + + + + Slot + + + + Settings + Einstellungen + + + Slot selected has changed! + + + + + EditDecks + + Configure RDCatch + RDCatch konfigurieren + + + Record Deck + Aufnahmedeck + + + None + Kein + + + Monitor Port: + Monitor-Port: + + + Off + Aus + + + On + An + + + Monitor defaults to + Monitor per default + + + Format: + Format: + + + Sample Rate: + Sample-Rate: + + + Bit Rate: + Bitrate: + + + Switcher Host: + Switcher Host: + + + Switcher Matrix: + Switcher-Matrix: + + + Switcher Output: + Switcher-Ausgang: + + + Switcher Delay: + Switcher-Verzögerung: + + + 1/10 sec + 1/10 sek + + + Channels: + Kanäle: + + + Trim Threshold: + Trim Threshold: + + + Error RML: + Fehler-RML: + + + Play Deck + Abspieldeck + + + Audition Deck + Vorhördeck + + + &Close + &Schliessen + + + No Audio Configuration Data + Keine Audiokonfigurationsdaten + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Kanalbestimmungen werden für diesen Host nicht verfügbar sein, da Audio- +Ressourcendaten nich nicht generiert wurden. Bitte starten sie die Rivendell- +deamons auf diesem Host, indem sie als Benutzer 'root' das Kommando "/etc/init.d/rivendell start" +eingeben um die Audioressourcendatenbank zu füllen. + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG Layer 2 + + + 32 kbps/chan + 32 kbps/Kanal + + + 48 kbps/chan + 48 kbps/Kanals + + + 56 kbps/chan + 56 knps/Kanal + + + 64 kbps/chan + 64 kbps/Kanal + + + 80 kbps/chan + 80 kbps/Kanal + + + 96 kbps/chan + 96 kbps/Kanal + + + 112 kbps/chan + 112 kbps/Kanal + + + 128 kbps/chan + 128 kbps/Kanal + + + 160 kbps/chan + 160 kbps/Kanal + + + 192 kbps/chan + 192 kbps/Kanal + + + [none] + [keine] + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Settings + Einstellungen + + + Defaults + Standards + + + Host-Wide Settings + + + + + EditDropbox + + Dropbox Configuration + + + + Default Group: + + + + &Path Spec: + + + + Select + Auswählen + + + To &Cart: + + + + Delete cuts before importing + + + + &Metadata Pattern: + + + + &Log File: + + + + Delete source files after import + + + + Normalize Levels + + + + Level: + Level: + + + dBFS + + + + Autotrim Cuts + + + + Get cart number from CartChunk CutID + + + + Get cart title from CartChunk CutID + + + + Attempt to work around malformatted input files + + + + Offset start date by + + + + days + + + + Offset end date by + + + + Create Dates when no Dates Exist + + + + Create start date offset: + + + + Create end date offset: + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Offsets + + + + The Create EndDate Offset is less than the Create Start Date Offset! + + + + &User Defined: + + + + Scheduler Codes + + + + + EditEncoder + + RDAdmin - Edit Encoder + RDAdmin - Encoder editieren + + + Name: + Name: + + + Allow Channels + Kanäle erlauben + + + Allow Sample Rates + Sampleraten erlauben + + + Allow Bit Rates + Bitraten erlauben + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Default Extension: + + + + Command Line: + + + + + EditEndpoint + + Edit Input + Eingang editieren + + + Edit Output + Ausgang editieren + + + Name: + Name: + + + Feed: + Feed: + + + Mode: + Modus: + + + Stereo + Stereo + + + Left + Links + + + Right + Rechts + + + Engine (Hex): + Engine (Hex): + + + Provider ID: + Provider ID: + + + Device (Hex): + Gerät (Hex): + + + Service ID: + Service ID: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Number + Ungültige Nummer + + + The Engine Number is Invalid! + Die Engine-Nummer ist ungültig! + + + The Provider ID is Invalid! + Die Provider-ID ist ungültig! + + + The Device Number is Invalid! + Die Gerätenummer ist ungültig! + + + The Service ID is Invalid! + Die Service-ID ist ungültig! + + + + EditFeed + + Feed: + Feed: + + + Key Name: + + + + CHANNEL VALUES + + + + Title: + Titel: + + + Category: + + + + Link: + + + + Copyright: + + + + Webmaster: + + + + Language: + + + + Description: + Beschreibung: + + + Audio Upload URL: + + + + Username: + Benutzername: + + + Password: + Passwort: + + + Upload Format: + + + + S&et + + + + Normalize + + + + Level: + Level: + + + dBFS + + + + Audio Download URL: + + + + Keep Expired Metadata + + + + Enable AutoPost + + + + Enclosure Preamble: + + + + Audio Extension: + + + + None + + + + Maximum Shelf Life: + + + + days + + + + Descending + + + + Ascending + + + + Episode Sort Order: + + + + Direct + + + + Counted + + + + Media Link Mode: + + + + Enable Feed Redirection + + + + URL: + + + + Header XML: + + + + Channel XML: + + + + Item XML: + + + + &Define Auxiliary +Metadata Fields + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Edit Feed - Redirect + + + + Enabling feed redirection will cause clients subscribed to +this feed to be PERMANENTLY redirected to the +specified URL. + +Do you still want to enable redireciton? + + + + + EditFeedPerms + + User: + Benutzer: + + + Available Feeds + + + + Enabled Feeds + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + EditGpi + + Edit GPI + GPI editieren + + + Description: + Beschreibung: + + + Cart Number: + Cart Nummer: + + + &Select + Au&swählen + + + C&lear + &Löschen + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Cart + Ungültiger Cart + + + Invalid Cart Number! + Ungültige Cartnummer! + + + + EditGroup + + Group: + Gruppe: + + + &Group Name: + &Gruppenname: + + + Group &Description: + Beschreibung &der Gruppe: + + + Audio + Audio + + + Macro + Makro + + + Default Cart &Type: + Standard-Cart-&Typ: + + + None + Kein + + + Default Cart Number: + Standard Cartnummer: + + + to + zu + + + Enforce Cart Range + Cartbereich erzwingen + + + Include this group in Traffic reports + Diese Gruppe in Trafficberichten einbinden + + + Include this group in Music reports + Diese Gruppe in Musikberichten einbinden + + + Transmit Now && Next data + Now && Next - Daten übertragen + + + C&olor + &Farbe + + + &OK + &OK + + + &Cancel + Abbre&chen + + + The selected cart range conflicts with the following groups: + + + Der ausgewählte Cartbereich steht in Konflikt mit folgenden Gruppen: + + + + + +Do you still want to save? + Wollen sie trotzdem speichern? + + + Default Import &Title: + Standard Import-&Titel: + + + Purge expired cuts after + Abgelaufene Carts löschen nach + + + days + Tagen + + + Delete cart if empty + + + + + EditHostvar + + Edit Host Variable + Hostvariable editieren + + + Variable Name: + Variablenname: + + + Variable Value: + Variablenwert: + + + Remark: + Bemerkung: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + EditHotkeys + + Host Hot Key Configurations + + + + Button / Function + + + + KeyStroke + + + + Set + + + + Clear + + + + Clear All Hotkeys + + + + Set From Host: + + + + Save + + + + Cancel + + + + Duplicate Entries + + + + Hotkeys Clear + + + + Hotkeys Updated + + + + No Items Selected + + + + Please Select an Item From the List + + + + Hot Key Configuration for + + + + + EditJack + + JACK Configuration for + + + + Start JACK Server + + + + JACK Server Name: + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + JACK Command Line: + + + + NAME + NAME + + + VALUE + WERT + + + REMARK + BEMERKUNG + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + JACK Clients to Start: + + + + Client + + + + Command Line + + + + [New Client] + + + + RDAdmin - JACK Clients + + + + Are you sure you want to delete JACK Client + + + + + EditJackClient + + JACK Client Configuration for + + + + Description: + Beschreibung: + + + Command Line: + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + EditLiveWireGpio + + &OK + &OK + + + &Cancel + Abbre&chen + + + Edit GPIO Source + + + + Livewire Source: + + + + GPIO Lines + + + + Surface Address: + + + + Invalid IP Address + + + + The IP address is invalid! + + + + None + + + + + EditMatrix + + Edit Switcher + Switcher editieren + + + Matrix Number: + Matrixnummer: + + + Switcher Type: + Switcher-Typ: + + + Description: + Beschreibung: + + + Primary Connection + Hauptverbindung + + + Type: + Typ: + + + Serial + Seriell + + + TCP/IP + TCP/IP + + + Serial Port: + Serieller Port: + + + IP Address: + IP-Adresse: + + + IP Port: + IP Port: + + + Username: + Benutzername: + + + Password: + Passwort: + + + Backup Connection + Backup-Verbindung + + + None + Keine + + + Card: + Karte: + + + Inputs: + Eingänge: + + + Outputs: + Ausgänge: + + + Device: + Gerät: + + + GPIs: + GPIs: + + + GPOs: + GPOs: + + + Layer: + Layer: + + + Displays: + Displays: + + + Configure +&Inputs + Eingänge +konf&igurieren + + + Configure +&Outputs + Ausgänge +konf&igurieren + + + Configure +&Xpoints + &Xpoints +konfigurieren + + + LiveWire +Nodes + LiveWire Nodes + + + vGuest +Switches + vGuest- +Schalter + + + vGuest +Displays + vGuest- +Anzeigen + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Address + Ungültige Adresse + + + The primary IP address is invalid! + Die Haupt-IP-Adresse ist ungültig! + + + The backup IP address is invalid! + Die Backup-IP-Adresse ist ungültig! + + + Duplicate Connections + Doppelte Verbindungen + + + The primary and backup connections must be different! + Die Haupt- und Backupverbindungen müssen sich unterscheiden! + + + Configure +&GPIs + &GPIs +konfigurieren + + + Configure +G&POs + G&POs +konfigurieren + + + Startup Cart: + Start-Cart: + + + Select + Auswählen + + + Shutdown Cart: + End-Cart: + + + SAS +Switches + + + + RDAdmin - Edit Switcher + + + + LiveWire +GPIOs + + + + + EditNowNext + + Edit Now & Next Data + Now & Next Daten editieren + + + Master Log + Hauptlog + + + IP Address: + IP-Adresse: + + + UDP Port: + UDP Port: + + + UDP String: + UDP String: + + + RML: + RML: + + + Aux Log 1 + Aux Log 1 + + + &OK + &OK + + + &Cancel + Abbre&chen + + + The IP address + Die IP-Adresse + + + is invalid! + ist ungültig! + + + Invalid Address + Ungültige Adresse + + + Add + Hinzufügen + + + Edit + Editieren + + + Delete + Löschen + + + Path + Pfad + + + Argument + Argument + + + Loadable Modules: + Ladbare Module: + + + Default Now Cart: + Standard-Now-Cart: + + + Default Next Cart: + Standard-Next-Cart: + + + Select + Auswählen + + + Aux Log 2 + Aux Log 2 + + + + EditNowNextPlugin + + Edit Plugin + Plugin editieren + + + Plugin Path: + Plugin-Pfad: + + + Argument: + Argument: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Select + Auswählen + + + Select plugin + Plugin wählen + + + + EditRDAirPlay + + RDAirPlay config for + RDAirPlay Konfiguration für + + + Channel Assignments + Kanal-Zuordnungen + + + Main Log Output 1 + Haupt-Log-Ausgang 1 + + + Start RML: + Start-RML: + + + Stop RML: + Stop-RML: + + + Main Log Output 2 + Haupt-Log-Ausgang 2 + + + Aux Log 1 Output + Aux Log1 Ausgang + + + Aux Log 2 Output + Aux Log 2 Ausgang + + + Audition/Cue Output + Vorhör-/Cue - Ausgang + + + SoundPanel First Play Output + SoundPanel Erster Ausgang + + + SoundPanel Second Play Output + SoundPanel zweiter Ausgang + + + SoundPanel Third Play Output + SoundPanel dritter Ausgang + + + SoundPanel Fourth Play Output + SoundPanel vierter Ausgang + + + SoundPanel Fifth and Later Play Output + Sound Panel fünfter und weitere Ausgänge + + + Manual Segue: + Manueller Übergang: + + + msecs + msecs + + + Forced Segue: + Erzwungener Übergang: + + + Pie Counts Last: + Pie zählt letzte: + + + secs + secs + + + Pie Counts To: + Pie Zählt zu: + + + Cart End + Cart-Ende + + + Transition + Übergang + + + Default Trans. Type: + Standard-Übergangstyp: + + + Play + Play + + + Segue + Übergang + + + Stop + Stop + + + Default Service: + Standardservice: + + + Sound Panel Settings + Sound Panel Einstellungen + + + None + Keine + + + Host Panels: + Host-Panels: + + + User Panels: + User-Panels: + + + Flash Active Buttons + Aktive Buttons blinken + + + Enable Button Pausing + Button-Pause aktivieren + + + Label Template: + Label Vorlage: + + + Miscellaneous Settings + Verschiedene Einstellungen + + + Startup Mode: + Startmodus: + + + Previous + Vorherige + + + LiveAssist + LiveAssist + + + Automatic + Automatik + + + Manual + Manuell + + + Check TimeSync + TimeSync überprüfen + + + Show Auxlog 1 Button + Auxlog 1 Button zeigen + + + Show Auxlog 2 Button + Auxlog 2 Button zeigen + + + Clear Cart Search Filter + Cartsuchfilter löschen + + + Enable Paused Events + Pausierte Events einschalten + + + Space Bar Action + Leertastenaktion + + + Start Next + Nächstes starten + + + Configure Now && Next +Parameters + Now && Next-Parameter +konfigurieren + + + Start/Stop Settings + Start/Stop - Einstellungen + + + Exit Password: + Passwort zum beenden: + + + Main Log + Haupt-Log + + + start with empty log + mit leerem Log starten + + + load previous log + vorheriges Log laden + + + load specified log + Bestimmtes Log laden + + + At Startup: + Beim Start: + + + Restart Log After Unclean Shutdown + Log nach unsauberem beenden neustarten + + + Log: + Log: + + + &Select + Au&swählen + + + &OK + &OK + + + &Cancel + Abbre&chen + + + No Audio Configuration Data + Keine Audio-Konfigurationsdaten + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Kanalzuordnungen werden für diesen Host nicht verfügbar sein, da bisher +keine Audio-Ressourcendaten generiert wurden. Bitte starten Sie die Rivendell- +Daemons auf diesem Host neu, indem sie als 'root'-Benutzer den Befehl +'/etc/init.d/rivendell start' ausführen, um die Audioressourcendatenbank zu füllen. + + + [none] + [keine] + + + Data Error + Datenfehler + + + Invalid Segue Length! + Ungültige Übergangslänge! + + + Invalid Forced Segue Length! + Ungültige Länge für erzwungenen Übergang! + + + Display Settings + Anzeigeeinstellungen + + + Background Image: + Hintergrundbild: + + + Select + Auswählen + + + Select Image File + Bilddatei auswählen + + + Show Extra Buttons/Counters + Weitere Buttons/Zähler anzeigen + + + Audition Preroll: + Vorhör-Preroll: + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Configure Hot Keys + + + + Show Hour Selector + + + + Edit +GPIOs + + + + Title Template: + + + + Artist Template: + + + + Outcue Template: + + + + Description Template: + + + + Log Mode Control + + + + Mode Control Style: + + + + Unified + + + + Independent + + + + Main Log Startup Mode: + + + + Aux 1 Log Startup Mode: + + + + Aux 2 Log Startup Mode: + + + + + EditRDLibrary + + RDLibrary config for + RDLibrary Konfiguration für + + + INPUT + EINGANG + + + OUTPUT + AUSGANG + + + Settings + Einstellungen + + + &Max Record Time: + &Max Aufnahmezeit: + + + &VOX Threshold: + &VOX Threshold: + + + dbFS + dbFS + + + &AutoTrim Threshold: + &AutoTrim Threshold: + + + &Tail Preroll: + &Tail Preroll: + + + milliseconds + Millisekunden + + + &Ripper Device: + &Ripper Gerät: + + + &Paranoia Level: + &Paranoia-Level: + + + Ripper Level: + Ripper Level: + + + &FreeDB Server: + &FreeDB Server: + + + &Format: + &Format: + + + &Sample Rate: + &Samplerate: + + + &Bitrate: + &Bitrate: + + + No + Nein + + + Yes + Ja + + + Allow E&xternal Editing: + E&xternes editieren erlauben: + + + Defaults + Standards + + + &Channels: + &Kanäle: + + + Record Mode: + Aufnahmemodus: + + + AutoTrim: + AutoTrim: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + No Audio Configuration Data + Keine Audiokonfigurationsdaten + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Kanalzuordnungen werden für diesen Host nicht verfügbar sein, da Audio- +Ressourcendaten nich nicht generiert wurden. Bitte starten sie die Rivendell- +deamons auf diesem Host, indem sie als Benutzer 'root' das Kommando "/etc/init.d/rivendell start" +eingeben um die Audioressourcendatenbank zu füllen. + + + Normal + Normal + + + Low + Niedrig + + + None + Keine + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG Layer 2 + + + Manual + Manuell + + + VOX + VOX + + + 32 kbps/chan + 32 kbps/Kanal + + + 48 kbps/chan + 48 kbps/Kanals + + + 56 kbps/chan + 56 knps/Kanal + + + 64 kbps/chan + 64 kbps/Kanal + + + 80 kbps/chan + 80 kbps/Kanal + + + 96 kbps/chan + 96 kbps/Kanal + + + 112 kbps/chan + 112 kbps/Kanal + + + 128 kbps/chan + 128 kbps/Kanal + + + 160 kbps/chan + 160 kbps/Kanal + + + 192 kbps/chan + 192 kbps/Kanal + + + 40 kbps/chan + 48 kbps/Kanals + + + 224 kbps/chan + 64 kbps/Kanal + + + 256 kbps/chan + 256 knps/Kanal + + + 320 kbps/chan + 320 kbps/Kanal + + + Sample Rate Converter: + Samplerate-Konverter: + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Limit Searches at Startup + + + + Previous + Vorherige + + + + EditRDLogedit + + RDLogedit config for + + + + INPUT + EINGANG + + + OUTPUT + AUSGANG + + + Voice Tracker Settings + + + + &Max Record Time: + &Max Aufnahmezeit: + + + &AutoTrim Threshold: + &AutoTrim Threshold: + + + dbFS + dbFS + + + &Normalization Level: + + + + &Audio Margin: + + + + milliseconds + Millisekunden + + + &Format: + &Format: + + + &Bitrate: + &Bitrate: + + + Play &Start Cart: + + + + Select + Auswählen + + + Play &End Cart: + + + + &Record Start Cart: + + + + Re&cord End Cart: + + + + &Channels: + &Kanäle: + + + Default Transition: + + + + Play + Play + + + Segue + Übergang + + + Stop + Stop + + + &OK + &OK + + + &Cancel + Abbre&chen + + + No Audio Configuration Data + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG Layer 2 + + + 32 kbps/chan + 32 kbps/Kanal + + + 48 kbps/chan + 48 kbps/Kanals + + + 56 kbps/chan + 56 knps/Kanal + + + 64 kbps/chan + 64 kbps/Kanal + + + 80 kbps/chan + 80 kbps/Kanal + + + 96 kbps/chan + 96 kbps/Kanal + + + 112 kbps/chan + 112 kbps/Kanal + + + 128 kbps/chan + 128 kbps/Kanal + + + 160 kbps/chan + 160 kbps/Kanal + + + 192 kbps/chan + 192 kbps/Kanal + + + 40 kbps/chan + 48 kbps/Kanals + + + 224 kbps/chan + 64 kbps/Kanal + + + 256 kbps/chan + 256 knps/Kanal + + + 320 kbps/chan + 320 kbps/Kanal + + + No + Nein + + + Yes + Ja + + + Enable &2nd Start Button: + + + + + EditRDPanel + + RDPanel config for + + + + Channel Assignments + Kanal-Zuordnungen + + + SoundPanel First Play Output + SoundPanel Erster Ausgang + + + Start RML: + Start-RML: + + + Stop RML: + Stop-RML: + + + SoundPanel Second Play Output + SoundPanel zweiter Ausgang + + + SoundPanel Third Play Output + SoundPanel dritter Ausgang + + + SoundPanel Fourth Play Output + SoundPanel vierter Ausgang + + + SoundPanel Fifth and Later Play Output + Sound Panel fünfter und weitere Ausgänge + + + SoundPanel Cue Output + + + + Display Settings + Anzeigeeinstellungen + + + Background Image: + Hintergrundbild: + + + Select + Auswählen + + + Sound Panel Settings + Sound Panel Einstellungen + + + None + + + + Host Panels: + Host-Panels: + + + User Panels: + User-Panels: + + + Flash Active Buttons + Aktive Buttons blinken + + + Enable Button Pausing + Button-Pause aktivieren + + + Clear Cart Search Filter + Cartsuchfilter löschen + + + Default Service: + Standardservice: + + + Label Template: + Label Vorlage: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + No Audio Configuration Data + + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + + + + [none] + [keine] + + + Select Image File + Bilddatei auswählen + + + + EditReplicator + + Replicator: + + + + Name: + Name: + + + Description: + Beschreibung: + + + Type: + Typ: + + + Host System: + + + + Audio Upload URL: + + + + Username: + Benutzername: + + + Password: + Passwort: + + + Upload Format: + + + + S&et + + + + Normalize + + + + Level: + Level: + + + dBFS + + + + Available Groups + + + + Active Groups + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + EditReport + + Edit Report + Report Editieren + + + &Report Description: + &Report Beschreibung: + + + Export &Filter: + Export-&Filter: + + + Station ID: + Stations-ID: + + + Cart Number Parameters: + Cartnummernparameter: + + + Use Leading Zeros + Führende Nullen verwenden + + + Digits: + Stellen: + + + Station Type: + Stationstyp: + + + Lines per Page: + Zeilen pro Seite: + + + Ser&vice Name: + Ser&vicename: + + + Station &Format: + Stations-&Format: + + + Linux Export Path: + Linux-Exportpfad: + + + Windows Export Path: + Windows-Exportpfad: + + + Export Event Types: + Exportiere flg. Eventtypen: + + + Traffic + Traffic + + + Music + Musik + + + All + Alle(s) + + + Export Events From: + Exportiere Events von: + + + Traffic Log + Traffic Log + + + Music Log + Musiklog + + + No + Nein + + + Yes + Ja + + + Include Only OnAir Events: + Nur OnAir-Events einschließen: + + + Available Services + Verfügbare Services + + + Source Services + Herkunftsservices + + + Available Hosts + Verfügbare Hosts + + + Source Hosts + Herkunftshosts + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Available Groups + + + + Allowed Groups + + + + Filter by Groups + + + + Filter by Daypart + + + + Start Time: + + + + End Time: + + + + + EditSettings + + System-Wide Settings + + + + System Sample Rate: + + + + samples/second + + + + Allow Duplicate Cart Titles + + + + ISCI Cross Reference Path: + + + + Maximum Remote Post Length: + + + + Mbytes + + + + The following duplicate titles must be corrected before "Allow Duplicate Values" can be turned off. + + + + CART + + + + TITLE + + + + &Save List + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + File Exists + + + + The file " + + + + " exists. + +Overwrite? + + + + File Error + + + + Checking the Library for duplicates. + + + + Temporary Cart Group: + + + + + EditStation + + Host: + Host: + + + Ho&st Name: + Ho&stname: + + + &Description: + &Beschreibung: + + + Default &User: + Standard-&User: + + + &IP Address: + &IP-Adresse: + + + Editor &Command: + Editor-&Kommando: + + + mS + mS + + + &Time Offset: + &Zeitabstand: + + + &Startup Cart: + &Start.Cart: + + + Select + Auswählen + + + Enable Heartbeat + Herzschlag einstellen + + + Use Realtime Filtering + Echtzeitfilterung verwenden + + + Cart: + Cart: + + + Interval: + Intervall: + + + secs + secs + + + RD&Library + RD&Library + + + RDCatch + RDCatch + + + RDAirPlay + RDAirplay + + + RDPanel + RDPanel + + + RDLogEdit + RDLogedit + + + Dropboxes + Dropboxen + + + Audio +Resources + Audio- +Ressourcen + + + Audio +Ports + Audio +Ports + + + Serial +Ports + Serielle +Ports + + + Switchers +GPIO + Switcher +GPIO + + + Host +Variables + Host- +Variablen + + + Backups + Backups + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Address + Ungültige Adresse + + + The specified IP address is invalid! + Die angegebene-IP-Adresse ist ungültig! + + + Invalid Cart + Ungültiger Cart + + + The Heartbeat Cart number is invalid! + Die Herzschlag-Cartnummer ist ungültig! + + + Security Model: + Sicherheitsmodell: + + + Host + Host + + + User + Benutzer + + + Custom +Encoders + Custom +Encoder + + + Include in System Maintenance Pool + Im Systemwartungspool einschließen + + + System Maintenance + Systemwartung + + + At least one host must belong to the system maintenance pool! + Es muss mindestens ein Host zum Systemwartungspool gehören! + + + HTTP Xport: + + + + Core Audio Engine: + + + + System Services + + + + JACK +Settings + + + + RDCart +Slots + + + + Cue &Output: + + + + RDAdmin - No Audio Configuration Data + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Enable Drag && Drop + + + + Allow Drops on Panels not in Setup Mode + + + + Start Cart + + + + Stop Cart + + + + + EditSvc + + Edit Service + Service editieren + + + &Service Name: + &Servicename: + + + Service &Description: + Service&beschreibung: + + + Log &Template Name: + Log- & Templatename: + + + [none] + [keine] + + + Voicetrack Group: + Voicetrackgruppe: + + + Insert CHAIN TO at log end + Am Ende des Logs Übergang zu... einfügen + + + Enable AutoRefresh By Default + AutoRefresh standardmäßig verwenden + + + Configure +&Autofill Carts + &Autofill-Carts +konfigurieren + + + Enable &Hosts + &Hosts verwenden + + + Traffic Data Import + Trafficdatenimport + + + Linux Import Path: + Linux Importpfad: + + + Windows Import Path: + Windowsimportpfad: + + + Note Cart String: + Note Cart String: + + + Insert Voice Track String: + Voice Track String einfügen: + + + Cart Number: + Cart Nummer: + + + Offset: + Abstand: + + + Length: + Länge: + + + Title: + Titel: + + + Start Time - Hours: + Startzeit-Stunden: + + + Start Time - Minutes: + Startzeit-Minuten: + + + Start Time - Seconds: + Startzeit-Sekunden: + + + Length - Hours: + Länge Stunden: + + + Length - Minutes: + Länge Minuten: + + + Length - Seconds: + Länge Sekunden: + + + Contract #: + Vertragsnummer: + + + Event ID: + Event-ID: + + + Annc. Type: + Annc.-Typ: + + + Test +&Traffic + &Traffic +testen + + + Music Data Import + Musikdatenimport + + + Insert Traffic Break String: + Traffic Break-String einfügen: + + + Test +&Music + &Musik +testen + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Save Import Data + Importdaten speichern + + + Before testing, the import configuration +must be saved. Save now? + Vor dem Testen muss die Importkonfiguration +gespeichert werden. Jetzt speichern? + + + Purge ELR Data after + lösche ELR-Daten nach + + + days + Tagen + + + Purge Logs after + Lösche Logs nach + + + Import Template: + Importvorlage: + + + [custom] + [custom] + + + Linux Preimport Command: + Vor-Import-Befehl Linux: + + + Windows Preimport Command: + Vor-Import-Befehl Windows: + + + &Program Code: + &Programmcode: + + + AutoSpot Group: + + + + Log Name &Template: + + + + Log &Description Template: + + + + + EditSvcPerms + + Service: + Service: + + + Available Hosts + Verfügbare Hosts + + + Enabled Hosts + verwendete Hosts + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + EditTtys + + Edit TTYs + TTYs editieren + + + Port ID: + Port-ID: + + + Enabled + verwendet + + + TTY Device: + TTY-Gerät: + + + Baud Rate: + Baudrate: + + + Parity: + Parität: + + + Data Bits: + Datenbits: + + + Stop Bits: + Stopbits: + + + Terminator: + Terminator: + + + &Close + &Schliessen + + + Serial + Seriell + + + None + Kein + + + Even + gerade + + + Odd + Ungerade + + + CR + CR + + + LF + LF + + + CR/LF + CR/LF + + + + EditUser + + User: + Benutzer: + + + &User Name: + &Benutzername: + + + &Full Name: + &voller Name: + + + &Description: + B&eschreibung: + + + &Phone: + &Telephon: + + + Allow Web Logins + Web-Logins erlauben + + + Change +&Password + &Passwort +ändern + + + Administrative Rights + Administrative Rechte + + + Administer S&ystem + S&ystem Administrieren + + + Production Rights + Produktionsrechte + + + &Create Carts + &Carts erstellen + + + &Delete Carts + Carts &Löschen + + + &Modify Carts + Carts &modifizieren + + + &Edit Audio + Audio &editieren + + + &Edit Netcatch Schedule + Netcatch-Plan &editieren + + + &Voicetrack Logs + &Voicetrack-Logs + + + Traffic Rights + Trafficrechte + + + Create &Log + &Log erstellen + + + De&lete Log + Log &löschen + + + Delete &Report Data + &Reportdaten löschen + + + &Modify Template + Template &Modifizieren + + + OnAir Rights + OnAir-Rechte + + + &Playout Logs + &Playout-Logs + + + &Rearrange Log Items + Logeinträge &Rearrangieren + + + Add Log &Items + Log-&Items hinzufügen + + + Delete Lo&g Items + Lo&g-Items löschen + + + Configure System Panels + System-Panels konfigurieren + + + Podcasting Rights + Podcastingrechte + + + Cre&ate Podcast + Podc&ast erstellen + + + E&dit Podcast + Podcast e&ditieren + + + Dele&te Podcast + Podcas&t löschen + + + Assign Group +Permissions + Gruppenerlaubnisse +zuweisen + + + Assign Podcast Feed +Permissions + Podcastfeed-Erlaubnisse +zuweisen + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + EditUserPerms + + User: + Benutzer: + + + Available Groups + + + + Enabled Groups + + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + EditVguestResource + + Engine (Hex): + Engine (Hex): + + + Device (Hex): + Gerät (Hex): + + + Surface (Hex): + Oberfläche (Hex): + + + Bus/Relay (Hex): + Bus/Relay (hex): + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Edit vGuest Switch + vGuest-Schalter editieren + + + Edit vGuest Display + vGuest-Anzeige editieren + + + Invalid Number + Ungültige Nummer + + + The Engine Number is Invalid! + Die Engine-Nummer ist ungültig! + + + The Device Number is Invalid! + Die Gerätenummer ist ungültig! + + + The Surface Number is Invalid! + Die Oberflächennummer ist ungültig! + + + The Bus/Relay Number is Invalid! + Die Bus-/Relaynummer ist ungültig! + + + + InfoDialog + + System Information + Systeminformation + + + Rivendell + Rivendell + + + A Radio Automation System + Ein Radioautomationssystem + + + Version + Version + + + Database Schema + Datenbankschema + + + This program is free software, and comes with ABSOLUTELY NO WARRANTY, +not even the implied warranties of MERCHANTIBILITY or FITNESS FOR A +PARTICULAR PURPOSE. Touch the "View License" button for details. + Dieses Programm ist freie Software und kommt mit ABSOLUT KEINER GARANTIE +nicht einmal die implizierte Garantie der ANWENDBARKEIT oder EIGNUNG FÜR EINEN +BESTIMMTEN ZWECK. Drücken Sie auf "Lizenz anzeigen" für Details. + + + View +&License + &Lizenz +anzeigen + + + &Close + &Schliessen + + + Copyright 2002-2008 + Copyright 2002-2009 + + + Copyright 2002-2010 + Copyright 2002-2010 + + + Copyright 2002-2014 + Copyright 2002-2014 + + + + ListAuxFields + + Auxiliary Metadata Fields + + + + Var Name + + + + Caption + + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &Close + &Schliessen + + + Warning + + + + This will delete all data associated with this field! +Are you sure you want to continue? + + + + + ListDropboxes + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &Close + &Schliessen + + + Group + + + + Path + Pfad + + + Normalization Level + + + + Autotrim Level + + + + To Cart + + + + Use CartChunk ID + + + + Delete Cuts + + + + Metadata Pattern + + + + Fix Broken Formats + + + + [off] + + + + [auto] + + + + [none] + [keine] + + + User Defined + + + + + ListEncoders + + RDAdmin - List Encoders + RDAdmin Encoder anzeigen + + + Format Name + Formatname + + + Valid Channels + Gültige Kanäle + + + Valid Sample Rates + Gültige Sampleraten + + + Valid Bit Rates + Gültige Bitraten + + + &Edit + &Editieren + + + &Close + &Schliessen + + + [none] + [keine] + + + &Add + &Hinzufügen + + + &Delete + &Löschen + + + RDAdmin - Delete Encoder + RDAdmin - Encoder löschen + + + Are you sure you want to delete this encoder? + Sind Sie sicher, daß sie diesen encoder löschen wollen? + + + Extension + Erweiterung + + + This encoder is in use by the following RSS feeds: + + + Dieser Encoder wird von folgenden RSS-Feeds verwendet: + + + + + + +Do you still want to delete it? + + +Wollen Sie ihn immernoch löschen? + + + Encoders on + + + + + ListEndpoints + + List Inputs + Eingänge anzeigen + + + List Outputs + Ausgänge anzeigen + + + INPUT + EINGANG + + + OUTPUT + AUSGANG + + + LABEL + LABEL + + + SOURCE + QUELLE + + + MODE + MODUS + + + ENGINE (Hex) + ENGINE (Hex) + + + DEVICE (Hex) + GERÄT (Hex) + + + PROVIDER ID + PROVIDER ID + + + SERVICE ID + SERVICE ID + + + NODE + NODE + + + # + # + + + &Edit + &Editieren + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Stereo + Stereo + + + Left + Links + + + Right + Rechts + + + Input + Eingang + + + Output + Ausgang + + + stereo + Stereo + + + left + Links + + + right + Rechts + + + + ListFeeds + + Rivendell Feed List + + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &Close + &Schliessen + + + Key + + + + Title + Titel + + + AutoPost + + + + Keep Metadata + + + + Creation Date + + + + &Feeds: + + + + Are you sure you want to delete feed + + + + Delete Feed + + + + Deleting Audio... + + + + Cancel + + + + Deleting + + + + + ListGpis + + List GPIs + GPIs anzeigen + + + GPI Lines + GPI-Lines + + + GPI + GPI + + + &Edit + &Editieren + + + &OK + &OK + + + &Cancel + Abbre&chen + + + [unassigned] + [nicht zugewiesen] + + + GPO + GPO + + + List GPOs + GPOs anzeigen + + + GPO Lines + GPO Lines + + + ON MACRO CART + AN-MAKROCART + + + ON DESCRIPTION + AN-BESCHREIBUNG + + + OFF MACRO CART + AUS MAKROCART + + + OFF DESCRIPTION + AUS BESCHREIBUNG + + + + ListGroups + + Rivendell Group List + Rivendell Gruppenliste + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Rename + &Neubenennen + + + &Delete + &Löschen + + + Generate +&Report + &Report +Generieren + + + &Close + &Schliessen + + + NAME + NAME + + + DESCRIPTION + BESCHREIBUNG + + + START CART + STARTCART + + + END CART + ENDCART + + + ENFORCE RANGE + BEREICH ERZWINGEN + + + DEFAULT TYPE + STANDARDTYP + + + TRAFFIC REPORT + TRAFFIC REPORT + + + MUSIC REPORT + MUSIKREPORT + + + NOW & NEXT + NOW & NEXT + + + &Groups: + &Gruppen: + + + member carts will be deleted along with group + Mitgliedscarts werden mit der Gruppe gelöscht + + + Are you sure you want to delete group + Sind Sie sicher, daß sie diese Gruppr löschen wollen + + + Delete Group + Gruppe löschen + + + + ListHostvars + + Host Variables for + Hostvariablen für + + + Host Variables + Hostvariablen + + + NAME + NAME + + + VALUE + WERT + + + REMARK + BEMERKUNG + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + ListLiveWireGpios + + LiveWire GPIO Source Assignments + + + + Switchers: + Schalter: + + + &Edit + &Editieren + + + &OK + &OK + + + &Cancel + Abbre&chen + + + [none] + [keine] + + + Lines + + + + Surface Address + + + + [all] + + + + Source # + + + + + ListMatrices + + Rivendell Switcher List + Rivendell Schalterliste + + + Switchers: + Schalter: + + + MATRIX + MATRIX + + + DESCRIPTION + BESCHREIBUNG + + + TYPE + TYP + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &Close + &Schliessen + + + Are you sure you want to delete switcher + Sind Sie sicher, daß sie diesen Schalter löschen wollen + + + on + An + + + ALL references to this switcher will be deleted! + ALLE Referenzen zu diesem Switcher werden gelöscht! + + + Deleting Switcher + Lösche Schalter + + + Local GPIO + Lokaler GPIO + + + Generic GPO + Generischer GPO + + + Generic Serial + Generisch Seriell + + + Local Audio Adapter + Lokaler Audioanschluss + + + Logitek vGuest + Logitek vGuest + + + BroadcastTools SS16.4 + BroadcastTools SS16.4 + + + StarGuide III + StarGuide III + + + BroadcastTools SS4.2 + BroadcastTools SS4.2 + + + Axia LiveWire + Axia LiveWire + + + Quartz Type 1 + Quartz Typ 1 + + + Unknown + Unbekannt + + + BroadcastTools SS4.4 + BroadcastTools SS4.4 + + + BroadcastTools SRC-8 III + BroadcastTools SRC-8 III + + + BroadcastTools SRC-16 + BroadcastTools SRC-16 + + + + ListReplicatorCarts + + &Repost + + + + Repost +&All + + + + &Close + &Schliessen + + + CART + + + + TITLE + + + + LAST POSTED + + + + &Active Carts: + + + + Replicator Carts + + + + POSTED FILENAME + + + + + ListReplicators + + Rivendell Replicators + + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &List +Carts + + + + &Close + &Schliessen + + + NAME + NAME + + + TYPE + TYP + + + DESCRIPTION + BESCHREIBUNG + + + HOST + + + + &Replicators: + + + + Are you sure you want to delete replicator + + + + Delete Replicator + + + + + ListReports + + Rivendell Report List + Rivendell Reportliste + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &Close + &Schliessen + + + R&eports: + R&eporte: + + + Are you sure you want to delete report + Sind Sie sicher,, dass sie den Report löschen wollen + + + Delete Report + Report Löschen + + + + ListStations + + Rivendell Workstation List + Rivendell Workstation-Liste + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &Close + &Schliessen + + + Ho&sts: + Ho&sts: + + + Are you sure you want to delete host + Sind Sie sicher, daß sie den Host löschen wollen + + + Delete Station + Station löschen + + + + ListSvcs + + Services + Services + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &Close + &Schliessen + + + &Services: + &Services: + + + Are you sure you want to delete service + Sind Sie sicher, daß sie den Service löschen wollen + + + Delete Service + Service löschen + + + There are + Es gibt + + + logs owned by this service that will also be deleted. +Do you still want to proceed? + Logs die diesem Service gehören, die auch gelöscht werden. +Wollen Sie immernoch fortfahren? + + + Logs Exist + Logs existieren + + + + ListUsers + + Rivendell User List + Rivendell Nutzerliste + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &Close + &Schliessen + + + &Users: + &Benutzer: + + + DESCRIPTION + BESCHREIBUNG + + + USER NAME + BENUTZERNAME + + + FULL NAME + VOLLER NAME + + + Are you sure you want to delete user + Sind Sie sicher, daß sie diesen Benutzer löschen wollen + + + Delete User + Benutzer löschen + + + You must change this before deleting the user. + Sie müssen dies ändern, bevor sie den Benutzer löschen können. + + + This user is set as the default user for the following hosts: + + + Dieser Benutzer ist der Standardbenutzer folgender Hosts: + + + + + You cannot delete yourself! + Die können sich nicht selbst löschen! + + + + Login + + Login + Login + + + &OK + &OK + + + &Cancel + Abbre&chen + + + User &Name: + Benutzer-&Name: + + + &Password: + &Passwort: + + + + MainWidget + + RDAdmin - Host: + RDAdmin-Host: + + + Daemons Failed + Daemonfehler + + + Unable to start Rivendell System Daemons! + Kann Rivendell-System-Daemons nicht starten! + + + Insufficient Priviledges + Ungenügende Befugnisse + + + This account has insufficient priviledges for this operation. + Dieser Account hat ungenügende Befugnisse für diese Operation. + + + Manage +&Users + Ben&Utzer +Managen + + + Manage +&Groups + &Gruppen +managen + + + Manage +&Services + &Services +managen + + + Manage +Ho&sts + Ho&sts +managen + + + Manage +R&eports + R&eporte +managen + + + Manage +&Feeds + &Feeds +managen + + + System +Info + System- +Info + + + Scheduler +Codes + Scheduler +Codes + + + &Backup +Database + Datenbank- +&Backup + + + &Restore +Database + Datenbank- +wiederhe&rstellung + + + &Quit + &Beenden + + + Rivendell Database Backup (*.sql) + Rivendell Datenbankbackup (*.sql) + + + Backup Error + Backupfehler + + + Unable to create backup! + Kann Backup nicht erstellen! + + + Backup Complete + Backup komplett + + + Backup completed successfully. + Backup erfolgreich beendet. + + + Restore Database + Datenbank wiederherstellen + + + WARNING: This operation will COMPLETELY +OVERWRITE the existing Rivendell Database! +Do you want to continue? + WARNUNG: Diese Operation wird die existierende +Rivendell-Datenbank VOLLSTÄNDIG ÜBERSCHREIBEN! +Wollen Sie fortfahren? + + + Restore Error + Wiederherstellungsfehler + + + Unable to restore backup! + Kann Backup nicht wiederherstellen! + + + Restore Complete + Wiederherstellung komplett + + + Restore completed successfully. + Wiederherstellung erfolgreich abgeschlossen. + + + System +Settings + System- +einstellungen + + + Manage +Replicators + Replikatoren +managen + + + RDAdmin + + + + + MySqlLogin + + mySQL Admin + mySQL Admin + + + User &Name: + Benutzer&name: + + + &Password: + &Passwort: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + QObject + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + Kann nicht auf die Rivendell-Datenbank zugreifen! +Bitte geben sie einen login für einen Account mit +administrativen Rechten auf dem mySQL-Server an +und wir werden versuchen, das zu korrigieren. + + + Wrong access permissions for accessing mySQL! + Falsche Zugriffsrechte für mySQL! + + + Unable to connect to mySQL! + Kann nicht zu mySQL verbinden! + + + Unable to create a Rivendell Database! + Kann keine Rivendell-Datenbank erstellen! + + + Unable to connect to new Rivendell Database! + Kann nicht zur neuen Rivendell-Datenbank verbinden! + + + Unable to create Rivendell Database! + Kann die Rivendell-Datenbank nicht erstellen! + + + Unable to connect to Rivendell Database! + Kann nicht zur Rivendell-Datenbank verbinden! + + + Unable to initialize Rivendell Database! + Kann die Rivendell-Datenbank nicht initialisieren! + + + RDAdmin + + + + New Rivendell Database Created! + Neue Rivendell-Datenbank erstellt! + + + Unable to upgrade database + Upgrade der Datenbank nicht möglich + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + Die Rivendell-Datenbank ist zu alt zum upgraden und +muss ersetzt werden. Dies wird ALLE existierenden Aufnahmen +und Daten LÖSCHEN! Wenn sie dies tun wollen, geben sie +einen Benutzernamen und ein Paßwort für einen mySQL- +Account mit administrativen Rechten ein, ansonsten klicken +sie abbrechen. + + + Unable to log into Administrator account! + Kann nicht in den Administratoraccount einloggen! + + + Unable to authorize a Rivendell Database! + Kann keine Rivendelldatenbank authorisieren! + + + Update Needed + Update notwendig + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + Die Rivendell-Datenbank benötigt ein Update. +Alle Aufnahmen und Einstellungen werden gespeichert, +aber dies wird alle Audio-Auspielungen oder Aufnahmen +auf diesem Rechner für ein paar Sekunden STOPPEN. +Fortfahren? + + + Unable to update Rivendell Database: + + + + +Database backup failed! + + + + +Schema modification failed! + + + + +Unknown/unspecified error! + + + + The Rivendell Database has been updated to version + + + + +and a backup of the original database saved in + + + + Database Updated + Datenbank geupdatet + + + RDAdmin Error + RDadmin Fehler + + + (default) + + + + Start Line 1 + + + + Stop Line 1 + + + + Pause Line 1 + + + + Start Line 2 + + + + Stop Line 2 + + + + Pause Line 2 + + + + Start Line 3 + + + + Stop Line 3 + + + + Pause Line 3 + + + + Start Line 4 + + + + Stop Line 4 + + + + Pause Line 4 + + + + Start Line 5 + + + + Stop Line 5 + + + + Pause Line 5 + + + + Start Line 6 + + + + Stop Line 6 + + + + Pause Line 6 + + + + Start Line 7 + + + + Stop Line 7 + + + + Pause Line 7 + + + + Add + Hinzufügen + + + Delete + Löschen + + + Copy + + + + Move + + + + Sound Panel + + + + Main Log + Haupt-Log + + + Aux Log 1 + Aux Log 1 + + + Aux Log 2 + Aux Log 2 + + + + RenameGroup + + Rename Group + Gruppe umbenennen + + + Current Group Name: + Derzeitiger Gruppenname: + + + New &Group Name: + Neuer &Gruppenname: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Group + Ungültige Gruppe + + + The group name is invalid! + Der Gruppenname ist ungültig! + + + A + Eine + + + group already exists. +Do you want to combine the two? + Gruppe existiert bereits. +Wollen Sie die beiden kombinieren? + + + Group Exists + Gruppe Existiert + + + + TestImport + + Test Traffic Import + Traffic-Import testen + + + Test Music Import + Musikimport testen + + + Test Date: + Testdatum: + + + &Select + Au&swählen + + + &Import + &Importieren + + + Using source file: + Benutze Ursprungsdatei: + + + Start Time + Startzeit + + + Cart + Cart + + + Len + Länge + + + Title + Titel + + + Contract # + Vertragsnummer + + + Event ID + Event-ID + + + Announcement Type + Ankündigungstyp + + + Imported Events + Importierte Events + + + &Close + &Schliessen + + + Import Error + Importfehler + + + There was an error during import +please check your settings and try again. + Es gab einen Fehler während des Imports. +Bitte überprüfen Sie ihre Einstellungen und versuchen sie es erneut. + + + [spot break] + [spot break] + + + + ViewAdapters + + Audio Resource Information + Audioressourceninformation + + + Audio Resources on + Audio Ressourcen auf + + + SUPPORTED AUDIO DRIVERS + + UNTERSTÜTZTE AUDIOTREIBER + + + SUPPORTED IMPORT FORMATS + + UNTERSTÜTZTE IMPORTFORMATE + + + PCM16 Linear + + PCM 16 Linear + + + + MPEG Layer 1 + + MPEG Layer 1 + + + + MPEG Layer 2 + + MPEG Layer 2 + + + + MPEG Layer 3 + + MPEG Layer 3 + + + + OggVorbis + + OggVorbis + + + + SUPPORTED EXPORT FORMATS + + UNTERSTÜTZTE EXPORTFORMATE + + + + Free Lossless Audio Codec (FLAC) + + Free Lossless Audio Codec (FLAC) + + + + AUDIO ADAPTERS + + AUDIOADAPTER + + + + Card + Karte + + + Not present + Nicht verfügbar + + + Driver: AudioScience HPI + + Driver: AudioScience HPI + + + + Driver: JACK Audio Connection Kit + + Driver: JACK Audio Connection Kit + + + + Driver: Advanced Linux Sound Architecture (ALSA) + + Driver: Advanced Linux Sound Architecture (ALSA) + + + + Driver: UNKNOWN + + Driver: UNBEKANNT + + + + Inputs: + Eingänge: + + + Outputs: + Ausgänge: + + + NO DATA AVAILABLE + + + KEINE DATEN VERFÜGBAR + + + + + Please start the Rivendell daemons on this host (by executing, as user 'root', the command "/etc/init.d/rivendell start") in order to populate the audio resources database. + Bitte starten sie die Rivendelldeamons auf diesem Host, indem sie als Benutzer 'root' das Kommando "/etc/init.d/rivendell start" +eingeben um die Audioressourcendatenbank zu füllen. + + + &Close + &Schliessen + + + diff --git a/rdadmin/rdadmin_es.ts b/rdadmin/rdadmin_es.ts new file mode 100644 index 00000000..becd1b14 --- /dev/null +++ b/rdadmin/rdadmin_es.ts @@ -0,0 +1,5838 @@ + + + @default + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + ¡No se pudo acceder a la base de datos Rivendell! +Si desea crear una NUEVA base de datos, ingrese +el login y la clave de una cuenta Mysql con +derechos administrativos. + + + Can't Connect + No pude conectar + + + Wrong access permissions for accessing mySQL! + ¡Permisología errónea al acceder a la base de datos MySQL! + + + Unable to connect to mySQL! + ¡No es posible conectarse con la base de datos MySQL! + + + Can't Create DB + No pude crear la base de datos + + + Unable to create a Rivendell Database! + ¡No pude crear la base de datos Rivendell! + + + Unable to connect to new Rivendell Database! + ¡No pude conectarme a la nueva base de datos Rivendell! + + + Can't Create + No pude crear + + + Unable to create Rivendell Database! + ¡No pude crear la base de datos Rivendell! + + + Unable to connect to Rivendell Database! + ¡No pude conectarme a la base de datos Rivendell! + + + Can't Initialize + No pude inicializar + + + Unable to initialize Rivendell Database! + ¡No fue posible inicializar la base de datos Rivendell! + + + Created Database + Base de datos creada + + + New Rivendell Database Created! + ¡Se ha creado una nueva base de datos! + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + La base de datos Rivendell es muy antigua y no +puede ser actualizada, por lo que será reemplazada. +¡Esto DESTRUIRÁ todo audio y datos existentes! +Si desea continuar, introduzca el usuario y la clave +de una cuenta MySQL con privilegios administrativos, +o de lo contrario seleccione CANCELAR. + + + Unable to log into Administrator account! + ¡No pudo ingresar a una cuenta administrativa! + + + Unable to authorize a Rivendell Database! + ¡No puedo autorizar la base de datos Rivendell! + + + Update Needed + Se necesita actualizar + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + La base de datos requiere ser actualizada. Todo el audio +y la configuración se van a preservar, pero hay que +DETENER las reproducciones y grabaciones por unos +segundos. ¿Desea continuar? + + + Can't Update + No puedo actualizar + + + Unable to update Rivendell Database! + ¡No fue posible actualizar la base de datos Rivendell! + + + The Rivendell Database has +been updated to Version + La base de datos Rivendell ha +sido actualizada a la versión + + + Database Updated + Base de datos actualizada + + + RDAdmin Error + Error de RDAdmin + + + Unable to upgrade database + No fue posible actualizar la base de datos + + + RDAdmin + RDAdmin + + + Unable to update Rivendell Database: + No fue posible actualizar la base de datos: + + + +Database backup failed! + +¡No se pudo respaldar la base de datos! + + + +Schema modification failed! + +¡Falló la modificación del esquema! + + + +Unknown/unspecified error! + +¡Error desconocido/no especificado! + + + The Rivendell Database has been updated to version + La base de datos de Rivendell ha sido actualizada a la versión + + + +and a backup of the original database saved in + +y un respaldo de la base de datos se guardó en + + + + AddAuxField + + Add Aux Field + Añadir Campo Aux + + + Variable Name: + Nombre: + + + %AUX_ + + + + % + + + + Caption: + Texto: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Name Exists + El nombre existe + + + That variable name already exists! + ¡Una variable con ese nombre ya existe! + + + + AddEncoder + + Add Encoder + Agregar Codificador + + + &New Encoder Name: + &Nombre: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Add Encoder Error + Error añadiendo Codificador + + + A encoder with that name already exists! + ¡Un codificador con ese nombre ya existe! + + + + AddFeed + + Add Feed + Añadir Feed + + + Enable Feed for All Users + Activar feed en todos los usuarios + + + &New Feed Name: + &Nombre del Feed: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Add Feed Error + Error añadiendo feed + + + A feed with that key name already exists! + ¡Un feed con ese nombre ya existe! + + + + AddGroup + + Add Group + Añadir grupo + + + &New Group Name: + &Nombre del grupo: + + + Enable Group for All Users + Activar para todos los usuario + + + Enable Group for All Services + Activar para todos los servicios + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Name + Nombre inválido + + + You must give the group a name! + ¡Debe indicar un nombre para el grupo! + + + Group Exists + El grupo ya existe + + + Group Already Exists! + ¡El grupo ya existe! + + + + AddHostvar + + Add Host Variable + Añadir variable para el computador + + + Variable Name: + Nombre: + + + Variable Value: + Valor: + + + Remark: + Comentario: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Name + Nombre inválido + + + The variable name is invalid. + El nombre de la variable es inválido. + + + + AddMatrix + + Add Switcher + Agregar Suichera + + + &New Matrix Number: + &Número de nueva Matriz: + + + Local GPIO + GPIO Local + + + Generic GPO + GPO Genérico + + + Generic Serial + Serial Genérico + + + Local Audio Adapter + Adaptador de Audio Local + + + &Switcher Type: + Tipo de &Suichera: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Matrix + Matriz inválida + + + Matrix already exists! + ¡La matriz ya existe! + + + New Switcher + Nueva Suichera + + + RDAdmin - Add Switcher + + + + + AddReplicator + + Add Replicator + Añadir Replicador + + + &New Replicator Name: + &Nombre del Replicad.: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Name + Nombre inválido + + + You must give the replicator a name! + ¡Debe darle un nombre al replicador! + + + Replicator Exists + El replicador ya existe + + + A replicator with that name already exists! + ¡Un replicador con ese nombre ya existe! + + + + AddReport + + Add Report + Añadir Reporte + + + &Report Name: + Nombre del &Reporte: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Name + Nombre inválido + + + You must provide a report name! + Usted debe indicar el nombre del reporte! + + + Report Exists + El reporte ya existe + + + A report with that name already exists! + ¡Ya existe un reporte con ese nombre! + + + + AddSchedCode + + Add Scheduler Code + Añadir código para musicalizar + + + &New Code: + &Nuevo Código: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Name + Nombre inválido + + + Invalid Name! + ¡El nombre es inválido! + + + Code Exists + El código ya existe + + + Code Already Exists! + ¡El código ya existe! + + + + AddStation + + Add Host + Añadir nuevo computador + + + New &Host Name: + Nombre del &Equipo: + + + Base Host On: + Basado en: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Empty Host Config + Vaciar configuración + + + Invalid Name + Nombre inválido + + + You must give the host a name! + ¡Debe asignar un nombre al equipo! + + + Host Exists + El equipo ya existe + + + Host Already Exists! + ¡El equipo ya existe! + + + + AddSvc + + Add Service + Añadir Servicio + + + &New Service Name: + &Nombre del Servicio: + + + Base Service On: + Basar servicio en: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Empty Host Config + Configuración en blanco + + + Invalid Name + Nombre inválido + + + You must give the service a name! + ¡Debe darle un nombre al servicio! + + + Service Exists + El servicio ya existe + + + Service Already Exists! + ¡El servicio ya existe! + + + + AddUser + + Add User + Añadir usuario + + + &New User Name: + &Nombre: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Name + Nombre inválido + + + You must give the user a name! + ¡Debe darle un nombre e este usuario! + + + User Exists + El usuario ya existe + + + User Already Exists! + ¡El usuario ya existe! + + + + AutofillCarts + + Autofill Carts - Service: + Autollenado de cartuchos - Servicio: + + + Cart + Cartucho + + + Length + Duración + + + Title + Título + + + Artist + Artista + + + &Add + &Añadir + + + &Delete + E&liminar + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + EditAudioPorts + + Edit Audio Ports + Editar Puertos de Audio + + + Clock Source: + Fuente del Clock: + + + Input Port + Puerto de Entrada + + + Analog + Análogo + + + AES/EBU + + + + SP/DIFF + + + + Type: + Tipo: + + + Normal + Normal + + + Swap + Invertir + + + Left only + Sólo Izquierdo + + + Right only + Sólo Derecho + + + Mode: + Modo: + + + dB + dB + + + Level: + Nivel: + + + Output Port + Puerto de Salida + + + &Help + A&yuda + + + &Close + &Cerrar + + + Internal + Intern + + + AES/EBU Signal + Señal AES/EBU + + + SP/DIFF Signal + Señal SP/DIFF + + + Word Clock + + + + Card: + Tarjeta: + + + Card Driver: + Controlador: + + + Ref. Level: + + + + + EditAuxField + + Edit Auxiliary Metadata Fields + Editar campos de metadatos auxiliares + + + Variable Name: + Variable: + + + Caption: + Texto: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + EditBackup + + Backup config for + Configuración de respaldo para + + + Keep Backups For: + Mantener respald. por: + + + days + días + + + Backup Directory: + Carpeta de Respaldos: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Path Missing + Directorio no encontrado + + + You must supply a backup path! + ¡Debe indicar un directorio para el respaldo! + + + + EditCartSlots + + RDAdmin - Edit CartSlots + + + + Close + + + + None + Ninguno + + + Output Port: + + + + Card: + Tarjeta: + + + Input Port: + + + + Cart + Cartucho + + + Mode: + Modo: + + + Cart: + Cartucho: + + + At Playout End: + + + + Channel Assignments + Asignación de Canales + + + Default Settings + + + + Select + Elegir + + + Load Specified Cart + + + + At Startup: + Al inicio: + + + Do Nothing + + + + Slot Mode: + + + + Full + + + + Hook + + + + Play Mode: + + + + User previous mode + + + + Use previous mode + + + + Use previous cart + + + + Use previous action + + + + Service: + + + + Global Settings + + + + Slot Columns: + + + + Slot Rows: + + + + Slot + + + + Settings + Parámetros + + + Slot selected has changed! + + + + + EditDecks + + Configure RDCatch + Configurar RDCatch + + + Record Deck + Bandeja Grabac. + + + None + Ninguno + + + Monitor Port: + Puerto Monitor: + + + Off + Apagado + + + On + Encendido + + + Monitor defaults to + Monitor por omisión + + + Format: + Formato: + + + Bit Rate: + Tasa de bits: + + + Switcher Host: + Suichera en equipo: + + + Switcher Matrix: + Matriz de Suichera: + + + Switcher Output: + Salida de Suichera: + + + Switcher Delay: + Retraso en la Suichera: + + + 1/10 sec + 1/10 seg + + + Channels: + Canales: + + + Trim Threshold: + Nivel para recortar: + + + Error RML: + RML de Error: + + + Play Deck + Band Repr + + + Audition Deck + Bandeja Escucha + + + &Close + &Cerrar + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG Capa 2 + + + 32 kbps/chan + 32 kbps/canal + + + 48 kbps/chan + 48 kbps/canal + + + 56 kbps/chan + 56 kbps/canal + + + 64 kbps/chan + 64 kbps/canal + + + 80 kbps/chan + 80 kbps/canal + + + 96 kbps/chan + 96 kbps/canal + + + 112 kbps/chan + 112 kbps/canal + + + 128 kbps/chan + 128 kbps/canal + + + 160 kbps/chan + 160 kbps/canal + + + 192 kbps/chan + 192 kbps/canal + + + [none] + [ninguno] + + + No Audio Configuration Data + No hay datos de configuración de datos + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + Las asignaciones de canales no estarán disponibles para este computador, +debido a que no se han generado datos. Inicie los servicios de Rivendell en el +computador para obtener los recursos de audio de dicho equipo. + + + Settings + Parámetros + + + Defaults + Por omisión + + + Host-Wide Settings + Parám. por equipo + + + + EditDropbox + + Dropbox Configuration + Configuración de Dropbox + + + Default Group: + Grupo p/omisión: + + + &Path Spec: + &Ruta: + + + Select + Elegir + + + To &Cart: + A &cartucho: + + + Delete cuts before importing + Borrar audios antes de importar + + + &Metadata Pattern: + Patrón &metadat.: + + + &Log File: + &Registro: + + + Delete source files after import + Borrar archivos después de importarlos + + + Normalize Levels + Nivel Normalizac. + + + Level: + Nivel: + + + dBFS + dBFS + + + Autotrim Cuts + AutoRecortar + + + Get cart number from CartChunk CutID + Obtener nro. de cartucho desde el CartChunk CutID + + + Get cart title from CartChunk CutID + Obtener título desde el CartChunk CutID + + + Attempt to work around malformatted input files + Intentar recuperar archivos mal formateados + + + Offset start date by + Desplaz. fecha inicio en + + + days + días + + + Offset end date by + Desplaz. fecha fin en + + + Create Dates when no Dates Exist + Crear fechas cuando no existan + + + Create start date offset: + Desplaz. fecha inicio: + + + Create end date offset: + Desplaz. fecha fin: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Offsets + Desplazamientos inválidos + + + The Create EndDate Offset is less than the Create Start Date Offset! + ¡La fecha de fin creada, al desplazarse, ocurre antes que la fecha de inicio! + + + The EndDate Offset is less than the Start Date Offset! + ¡La fecha de fin, al desplazarse, ocurre antes que la fecha de inicio! + + + &User Defined: + + + + Scheduler Codes + + + + + EditEncoder + + RDAdmin - Edit Encoder + RDAdmin - Editar Codificador + + + Name: + Nombre: + + + Allow Channels + Canales permitidos + + + Allow Sample Rates + Tasas muest permit + + + Allow Bit Rates + Tasas bit permitidas + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Default Extension: + Extensión por omisión: + + + Command Line: + Línea de comandos: + + + + EditEndpoint + + Edit Input + Editar Entrada + + + Edit Output + Editar Salida + + + Name: + Nombre: + + + Feed: + Feed: + + + Mode: + Modo: + + + Stereo + Estéreo + + + Left + Izquierda + + + Right + Derecha + + + Engine (Hex): + Motor (Hex): + + + Provider ID: + ID Proveedor: + + + Device (Hex): + Disposit (Hex): + + + Service ID: + ID del Servicio: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Number + Número inválido + + + The Engine Number is Invalid! + ¡El número del motor es inválido! + + + The Provider ID is Invalid! + ¡El ID del proveedor es inválido! + + + The Device Number is Invalid! + ¡El número del dispositivo es inválido! + + + The Service ID is Invalid! + ¡El ID del servicio es inválido! + + + + EditFeed + + Feed: + Feed: + + + Key Name: + Nombre: + + + Title: + Título: + + + Category: + Categoría: + + + Link: + Enlace: + + + Copyright: + Copyright: + + + Webmaster: + Webmaster: + + + Language: + Lenguaje: + + + Description: + Descripción: + + + Audio Upload URL: + URL subida audio: + + + Username: + Usuario: + + + Password: + Clave: + + + Upload Format: + Formato de subida: + + + S&et + &Asignar + + + Normalize + Normalizar + + + Level: + Nivel: + + + dBFS + dBFS + + + Audio Download URL: + URL descarga audio: + + + Keep Expired Metadata + Mantener metadatos vencidos + + + Enable AutoPost + Activar AutoPublicar + + + Enclosure Preamble: + Preámbulo de encierro: + + + Audio Extension: + Extensión de audio: + + + None + Ninguno + + + Maximum Shelf Life: + Vida útil máxima: + + + days + días + + + Descending + Descendente + + + Ascending + Ascendente + + + Episode Sort Order: + Orden de Episodios: + + + Direct + Directo + + + Counted + Contado + + + Media Link Mode: + Modo de los Enlaces: + + + Enable Feed Redirection + Activar redirec. de feed + + + URL: + URL: + + + Header XML: + Cabecera XML: + + + Channel XML: + Canal XML: + + + Item XML: + Ítem XML: + + + &Define Auxiliary +Metadata Fields + &Definir campos de +metadatos auxiliares + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Edit Feed - Redirect + Edtar feed - Redireccionar + + + Enabling feed redirection will cause clients subscribed to +this feed to be PERMANENTLY redirected to the +specified URL. + +Do you still want to enable redireciton? + Activar el redireccionamiento de feeds causará que los clientes +suscritos a este feed sean redireccionados PERMANENTEMENTE +al URL especificado. + +¿Está seguro de activar la redirección? + + + CHANNEL VALUES + VALORES DEL CANAL + + + + EditFeedPerms + + User: + Usuario: + + + Available Feeds + Feeds disponibles + + + Enabled Feeds + Feeds activados + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + EditGpi + + Edit GPI + Edtar GPI + + + Description: + Descripción: + + + Cart Number: + Nro Cartucho: + + + &Select + &Elegir + + + C&lear + &Limpiar + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Cart + Cartucho inválido + + + Invalid Cart Number! + ¡Número de cartucho inválido! + + + + EditGroup + + Group: + Grupo: + + + &Group Name: + Nombre del &Grupo: + + + Group &Description: + &Descripción del grupo: + + + Audio + Audio + + + Macro + Macro + + + Default Cart &Type: + &Tipo de Cart. inicial: + + + None + Ninguno + + + Default Cart Number: + Nro de cartucho inicial: + + + to + a + + + Enforce Cart Range + Obligar a seguir cargo + + + Include this group in Traffic reports + Incluir grupo en reportes de Tráfico + + + Include this group in Music reports + Incluir grupo en reportes de Música + + + Transmit Now && Next data + Transmitir datos Now && Next + + + C&olor + C&olor + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + The selected cart range conflicts with the following groups: + + + El rango seleccionado choca con el de los siguientes grupos: + + + + + +Do you still want to save? + ¿Aún así, desea guardar? + + + Default Import &Title: + &Título inicial al importar: + + + Purge expired cuts after + Borrar aud. vencidos tras + + + days + días + + + Delete cart if empty + + + + + EditHostvar + + Edit Host Variable + Editar Variable + + + Variable Name: + Nombre de la variable: + + + Variable Value: + Valor: + + + Remark: + Comentario: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + EditHotkeys + + Host Hot Key Configurations + Configuración de atajos de teclado + + + Button / Function + Botón / Función + + + KeyStroke + Teclas + + + Set + Asignar + + + Clear + Limpiar + + + Clear All Hotkeys + Borrar todo + + + Set From Host: + Copiar desde: + + + Save + Guardar + + + Cancel + Cancelar + + + Duplicate Entries + Entradas duplicadas + + + Hotkeys Clear + Borrar atajos de teclado + + + Hotkeys Updated + Atajos de teclado actualizados + + + No Items Selected + No se han seleccionado ítems + + + Please Select an Item From the List + Por favor, seleccione un ítem de la lista + + + Hot Key Configuration for + Atajos de teclado para + + + + EditJack + + JACK Configuration for + Configuración JACK para + + + Start JACK Server + Iniciar servidor JACK + + + JACK Server Name: + Nombre del servidor: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + JACK Command Line: + + + + NAME + NOMBRE + + + VALUE + VALOR + + + REMARK + COMENTARIO + + + &Edit + &Editar + + + &Delete + E&liminar + + + JACK Clients to Start: + + + + Client + + + + Command Line + + + + &Add + + + + [New Client] + + + + RDAdmin - JACK Clients + + + + Are you sure you want to delete JACK Client + + + + + EditJackClient + + JACK Client Configuration for + + + + Description: + Descripción: + + + Command Line: + Línea de comandos: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + EditLiveWireGpio + + None + Ninguno + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Edit GPIO Source + + + + Livewire Source: + + + + GPIO Lines + + + + Surface Address: + + + + Invalid IP Address + + + + The IP address is invalid! + + + + + EditMatrix + + Edit Switcher + Editar Suichera + + + Matrix Number: + Número de Matriz: + + + Switcher Type: + Tipo de Suichera: + + + Description: + Descripción: + + + Serial + + + + TCP/IP + + + + Card: + Tarjeta: + + + IP Address: + Direc. IP: + + + IP Port: + Puerto IP: + + + Username: + Usuario: + + + Password: + Clave: + + + Inputs: + Entradas: + + + Outputs: + Salidas: + + + Device: + Dispos: + + + GPIs: + + + + GPOs: + + + + Displays: + + + + Configure +&Inputs + Configurar +&Entradas + + + Configure +&Outputs + Configurar +&Salidas + + + Configure +&Xpoints + Configurar +&Xpoints + + + vGuest +Switches + + + + vGuest +Displays + + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Address + Dirección inválida + + + LiveWire +Nodes + Nodos LiveWire + + + Primary Connection + Conexión Primaria + + + Backup Connection + Conexión Respaldo + + + Type: + Tipo: + + + Serial Port: + Puerto Serial: + + + None + Ninguno + + + The primary IP address is invalid! + ¡La dirección IP primaria es inválida! + + + The backup IP address is invalid! + ¡La dirección IP de respaldo es inválida! + + + Duplicate Connections + Conexiones duplicadas + + + The primary and backup connections must be different! + ¡Las conexión primaria debe ser distinta que la de respaldo! + + + Layer: + Capa: + + + Configure +&GPIs + Configurar +&GPIs + + + Configure +G&POs + Configurar +G&POs + + + Startup Cart: + Cart. Inicio: + + + Select + Elegir + + + Shutdown Cart: + Cart. Cierre: + + + SAS +Switches + Switches +SAS + + + RDAdmin - Edit Switcher + + + + LiveWire +GPIOs + + + + + EditNowNext + + Edit Now & Next Data + Editar datos Now & Next + + + Master Log + Lista Maestra + + + IP Address: + Dirección IP: + + + UDP Port: + Puerto UDP: + + + UDP String: + Cadena UDP: + + + RML: + RML: + + + Aux Log 1 + Lista aux. 1 + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + The IP address + ¡La dirección IP + + + is invalid! + es inválida! + + + Invalid Address + Dirección inválida + + + Add + Añadir + + + Edit + Editar + + + Delete + Borrar + + + Path + Carpeta + + + Argument + Argumento + + + Loadable Modules: + Módulos Cargables: + + + Default Now Cart: + Cart.Now p/omis.: + + + Default Next Cart: + Cart.Next p/omis.: + + + Select + Elegir + + + Aux Log 2 + Lista aux. 2 + + + + EditNowNextPlugin + + Edit Plugin + Editar Plugin + + + Plugin Path: + Carpeta Plugins: + + + Argument: + Argumento: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Select + Elegir + + + Select plugin + Elegir plugin + + + + EditRDAirPlay + + RDAirPlay config for + Configuración de RDAirplay para + + + Channel Assignments + Asignación de Canales + + + Main Log Output 1 + Salida PlayList Ppal 1 + + + Start RML: + Inicio RML: + + + Stop RML: + Fin RML: + + + Main Log Output 2 + Salida PlayList Ppal 2 + + + Aux Log 1 Output + Salida PlayList Aux 1 + + + Aux Log 2 Output + Salida PlayList Aux 2 + + + Audition/Cue Output + Salida para "Cue" + + + SoundPanel First Play Output + 1era salida del Panel de Sonido + + + SoundPanel Second Play Output + 2da salida del Panel de Sonido + + + SoundPanel Third Play Output + 3era salida del Panel de Sonido + + + SoundPanel Fourth Play Output + 4ta salida del Panel de Sonido + + + SoundPanel Fifth and Later Play Output + 5ta salida del Panel de Sonido + + + Configure Now && Next +Parameters + Parámetros Now && Next + + + Manual Segue: + Segue Manual: + + + msecs + msegs + + + Forced Segue: + Segue forzado: + + + Pie Counts Last: + Rueda contará: + + + secs + segs + + + Pie Counts To: + Rueda cuenta a: + + + Cart End + Fin Cartucho + + + Transition + Transición + + + Default Trans. Type: + Tipo Trans. Pedeterm: + + + Play + Reproducir + + + Segue + Segue + + + Stop + Detener + + + Default Service: + Servicio Predeterm.: + + + Sound Panel Settings + Config. Panel de Sonido + + + None + Ninguno + + + Host Panels: + Paneles/Equipo: + + + User Panels: + Paneles/Usuario: + + + Flash Active Buttons + Parpad. botón activo + + + Enable Button Pausing + Permitir pausar reproduc. + + + Miscellaneous Settings + Parámetros misceláneos + + + Startup Mode: + Modo de inicio: + + + Previous + Previo + + + LiveAssist + AsistEnVivo + + + Automatic + Automático + + + Manual + Manual + + + Check TimeSync + Cheq. TimeSync + + + Show Auxlog 1 Button + Mostrar botón Auxlog 1 + + + Show Auxlog 2 Button + Mostrar botón Auxlog 2 + + + Clear Cart Search Filter + Limpiar filtro busq. cart + + + Enable Paused Events + Activar eventos pausados + + + Space Bar Action + Barra espaciadora + + + Start Next + Iniciar Sig + + + Start/Stop Settings + Parámetros Inicio/Fin + + + Exit Password: + Clave para salir: + + + Main Log + PlayList Ppal + + + start with empty log + comenzar con PlayList vacío + + + load previous log + cargar PlayList anterior + + + load specified log + cargar PlayList específico + + + At Startup: + Al inicio: + + + Restart Log After Unclean Shutdown + Reiniciar PlayList si apagan el equipo + + + Log: + PlayList: + + + &Select + &Elegir + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + [none] + [ninguno] + + + No Audio Configuration Data + No hay datos para config. audio + + + Data Error + Error de datos + + + Invalid Segue Length! + ¡Duración de segue inválida! + + + Invalid Forced Segue Length! + ¡Duración de segue forzado inválida! + + + Label Template: + Plantilla etiqueta: + + + Display Settings + Config. de Pantalla + + + Background Image: + Imagen de Fondo: + + + Select + Elegir + + + Select Image File + Seleccione una imagen + + + Show Extra Buttons/Counters + Mostrar botones/contad extra + + + Audition Preroll: + Escucha previa: + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + La configuración de canales no estará disponible en este equipo debido a que +no se ha generado información sobre los recursos de audio. Por favor, inicie los +servicios de Rivendell en el equipo configurado para ejecutar el servicio CAE. + + + Configure Hot Keys + Configurar atajos de teclado + + + Show Hour Selector + + + + Edit +GPIOs + + + + Title Template: + + + + Artist Template: + + + + Outcue Template: + + + + Description Template: + + + + Log Mode Control + + + + Mode Control Style: + + + + Unified + + + + Independent + + + + Main Log Startup Mode: + + + + Aux 1 Log Startup Mode: + + + + Aux 2 Log Startup Mode: + + + + + EditRDLibrary + + RDLibrary config for + Configuración de RDLibrary para + + + INPUT + ENTRADA + + + OUTPUT + SALIDA + + + Settings + Parámetros + + + &Max Record Time: + Tiempo &Máx Grab: + + + &VOX Threshold: + Nivel de &VOX: + + + dbFS + dbFS + + + &AutoTrim Threshold: + Nivel de &autorecorte: + + + &Tail Preroll: + &Tiempo al final: + + + milliseconds + milisegundos + + + &Ripper Device: + Dispositivo de &lectura: + + + &Paranoia Level: + Nivel en &Paranoia: + + + Ripper Level: + Nivel de Ripper: + + + &FreeDB Server: + Servidor &FreeDB: + + + &Format: + &Formato: + + + &Bitrate: + Tasa de &bits: + + + Defaults + Por omisión + + + &Channels: + &Canales: + + + Record Mode: + Modo de Grabación: + + + AutoTrim: + Auto Recortar: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Normal + Normal + + + Low + Bajo + + + None + Ninguno + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG Capa 2 + + + Manual + Manual + + + VOX + VOX + + + No Audio Configuration Data + Audio sin datos de configuración + + + 32 kbps/chan + 32 kbps/canal + + + 48 kbps/chan + 48 kbps/canal + + + 56 kbps/chan + 56 kbps/canal + + + 64 kbps/chan + 64 kbps/canal + + + 80 kbps/chan + 80 kbps/canal + + + 96 kbps/chan + 96 kbps/canal + + + 112 kbps/chan + 112 kbps/canal + + + 128 kbps/chan + 128 kbps/canal + + + 160 kbps/chan + 160 kbps/canal + + + 192 kbps/chan + 192 kbps/canal + + + 40 kbps/chan + 40 kbps/canal + + + 224 kbps/chan + 224 kbps/canal + + + 256 kbps/chan + 256 kbps/canal + + + 320 kbps/chan + 320 kbps/canal + + + No + No + + + Yes + + + + Allow E&xternal Editing: + Permitir edición e&xterna: + + + Sample Rate Converter: + Convertid. Tasa Muestra: + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + No podrá ver la asignación de canales en este equipo debido a que no se ha +generado información de audio. Por favor, inicie los servicios de Rivendell en el +equipo configurado para ejecutar CAE para obtener la información de audio. + + + Previous + Previo + + + Limit Searches at Startup + + + + + EditRDLogedit + + RDLogedit config for + Configuración de RDLogEdit para + + + INPUT + ENTRADA + + + OUTPUT + SALIDA + + + Voice Tracker Settings + Parámetros de las Pistas de Voz + + + &Max Record Time: + Tiempo &Máx. Grab: + + + &AutoTrim Threshold: + Nivel de &autorecorte: + + + dbFS + dbFS + + + &Normalization Level: + Nivel de &Normalización: + + + &Audio Margin: + Margen de &Audio: + + + milliseconds + milisegundos + + + &Format: + &Formato: + + + &Bitrate: + Tasa de &bits: + + + Play &Start Cart: + Cart. &Inicial en Reprod.: + + + Select + Elegir + + + Play &End Cart: + Cart. &Final en Reprod.: + + + &Record Start Cart: + Cart. Inicial en &Grabac.: + + + Re&cord End Cart: + Cart. Fin en G&rabac.: + + + &Channels: + &Canales: + + + Default Transition: + Transición por Omisión: + + + Play + Reproducir + + + Segue + Segue + + + Stop + Parar + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + No Audio Configuration Data + No hay datos de configuración de audio + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + Las asignaciones de canales no estarán disponibles para este computador, +debido a que no se han generado datos. Inicie los servicios de Rivendell en el +computador para obtener los recursos de audio de dicho equipo. + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG Capa 2 + + + 32 kbps/chan + 32 kbps/canal + + + 48 kbps/chan + 48 kbps/canal + + + 56 kbps/chan + 56 kbps/canal + + + 64 kbps/chan + 64 kbps/canal + + + 80 kbps/chan + 80 kbps/canal + + + 96 kbps/chan + 96 kbps/canal + + + 112 kbps/chan + 112 kbps/canal + + + 128 kbps/chan + 128 kbps/canal + + + 160 kbps/chan + 160 kbps/canal + + + 192 kbps/chan + 192 kbps/canal + + + 40 kbps/chan + 40 kbps/canal + + + 224 kbps/chan + 224 kbps/canal + + + 256 kbps/chan + 256 kbps/canal + + + 320 kbps/chan + 320 kbps/canal + + + No + + + + Yes + + + + Enable &2nd Start Button: + + + + + EditRDPanel + + RDPanel config for + Configuración de RDPanel para + + + Channel Assignments + Asignación de Canales + + + SoundPanel First Play Output + 1era salida del Panel de Sonido + + + Start RML: + Inicio RML: + + + Stop RML: + Fin RML: + + + SoundPanel Second Play Output + 2da salida del Panel de Sonido + + + SoundPanel Third Play Output + 3era salida del Panel de Sonido + + + SoundPanel Fourth Play Output + 4ta salida del Panel de Sonido + + + SoundPanel Fifth and Later Play Output + 5ta salida del Panel de Sonido + + + SoundPanel Cue Output + Salida "Cue" del Panel de Sonido + + + Display Settings + Config. de Pantalla + + + Background Image: + Imagen de Fondo: + + + Select + Elegir + + + Sound Panel Settings + Config. Panel de Sonido + + + None + Ninguno + + + Host Panels: + Paneles/Equipo: + + + User Panels: + Paneles/Usuario: + + + Flash Active Buttons + Parpad. botón activo + + + Enable Button Pausing + Permitir pausar reproduc. + + + Clear Cart Search Filter + Limpiar filtro busq. cart + + + Default Service: + Serv. Predeterminado: + + + Label Template: + Plantilla etiqueta: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + No Audio Configuration Data + No hay datos de configuración de audio + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + La asignación de canales no estará disponible para este equipo, debido a que la +configuración de audio aún no ha sido generada. Inicie los servicios de Rivendell +en el equipo (ejecutando, como 'root', el comando "/etc/init.d/rivendell start") +para generar la base de datos con los recursos de audio disponibles. + + + [none] + [ninguno] + + + Select Image File + Seleccione una imagen + + + + EditReplicator + + Replicator: + Replicador: + + + Name: + Nombre: + + + Description: + Descripción: + + + Type: + Tipo: + + + Host System: + Equipo: + + + Audio Upload URL: + URL subida audio: + + + Username: + Usuario: + + + Password: + Clave: + + + Upload Format: + Formato de subida: + + + S&et + &Asign + + + Normalize + Normalizar + + + Level: + Nivel: + + + dBFS + dBFS + + + Available Groups + Grupos disponibles + + + Active Groups + Grupos activos + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + EditReport + + Edit Report + Editar Reportes + + + &Report Description: + Descripción del &Reporte: + + + Export &Filter: + &Filtro Exportación: + + + Station ID: + ID de la estación: + + + Cart Number Parameters: + Config. Números del Cart: + + + Use Leading Zeros + Usar ceros a la izq + + + Digits: + Dígitos: + + + Station Type: + Tipo de emisora: + + + Lines per Page: + Líneas por página: + + + Ser&vice Name: + Nombre del Ser&vicio: + + + Station &Format: + &Formato de Estación: + + + Linux Export Path: + Exportar en (Linux): + + + Windows Export Path: + Exportar en (Windows): + + + Export Event Types: + Eventos a exportar: + + + Traffic + Tráfico + + + Music + Música + + + All + Todos + + + Export Events From: + Exportar eventos desde: + + + Traffic Log + Lst. Tráfico + + + Music Log + Lst. Música + + + No + + + + Yes + + + + Include Only OnAir Events: + Sólo eventos Al-Aire: + + + Available Services + Serv. Disponibles + + + Source Services + Fuentes + + + Available Hosts + Equipos dispon.: + + + Source Hosts + Fuentes + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Available Groups + Grupos disponibles + + + Allowed Groups + + + + Filter by Groups + + + + Filter by Daypart + + + + Start Time: + + + + End Time: + + + + + EditSchedCode + + Scheduler Code: + Código para Musicalizar: + + + Scheduler Code: + Código: + + + Code Description: + Descripción: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + EditSettings + + System-Wide Settings + Parámetros de todo el Sistema + + + System Sample Rate: + Tasa de Muestreo del Sistema: + + + samples/second + muestras/segundo + + + Allow Duplicate Cart Titles + Permitir títulos duplicados de cartuchos + + + ISCI Cross Reference Path: + Ubicac. de Ref. Cruzadas ISCI: + + + Maximum Remote Post Length: + Long. máx. de posts remotos: + + + Mbytes + MBytes + + + The following duplicate titles must be corrected before "Allow Duplicate Values" can be turned off. + Los siguientes títulos duplicados deben ser corregidos antes de desactivar la opción respectiva. + + + CART + CARTUCHO + + + TITLE + TÍTULO + + + &Save List + &Guardar lista + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + File Exists + El archivo ya existe + + + The file " + El archivo " + + + " exists. + +Overwrite? + " ya existe. + +¿Sobreescribir? + + + File Error + Error de archivo + + + Checking the Library for duplicates. + Buscando duplicados en la biblioteca. + + + Temporary Cart Group: + + + + + EditStation + + Host: + Computador: + + + Ho&st Name: + &Nombre: + + + &Description: + &Descripción: + + + Default &User: + &Usuario Predet.: + + + &IP Address: + Dirección &IP: + + + mS + + + + &Time Offset: + Offset &tiempo: + + + &Startup Cart: + Cartucho &Inicial: + + + Select + Elegir + + + Enable Heartbeat + Activar "Heartbeat" + + + Cart: + Cartucho: + + + Interval: + Interval.: + + + secs + segs + + + RD&Library + RD&Library + + + RDCatch + RDCatch + + + RDAirPlay + RDAirPlay + + + RDPanel + RDPanel + + + RDLogEdit + RDLogEdit + + + Dropboxes + Dropboxes + + + Audio +Resources + Recursos +de audio + + + Audio +Ports + Puertos +de audio + + + Serial +Ports + Puertos +Seriales + + + Switchers +GPIO + Suicheras +GPIO + + + Host +Variables + Variables +del Equipo + + + Backups + Respaldos + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Address + Dirección inválida + + + The specified IP address is invalid! + ¡La IP especificada es inválida! + + + Invalid Cart + Cartucho inválido + + + The Heartbeat Cart number is invalid! + El número de cartucho para "heartbeat" es inválido! + + + Editor &Command: + &Comando editor: + + + Use Realtime Filtering + Búsqueda tiempo real + + + Security Model: + Modelo segurid: + + + Host + Equipo + + + User + Usuario + + + Custom +Encoders + Codificad. +propios + + + Include in System Maintenance Pool + Incluir en Mantenimiento del Sistema + + + System Maintenance + Mantenimiento del Sistema + + + At least one host must belong to the system maintenance pool! + ¡Al menos un equipo debe pertenecer al mantenimiento del sistema! + + + HTTP Xport: + HTTP Xport: + + + Core Audio Engine: + Servidor de Audio: + + + System Services + Serv. del Sistema + + + JACK +Settings + Parámetros +de JACK + + + RDCart +Slots + + + + Cue &Output: + + + + RDAdmin - No Audio Configuration Data + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Enable Drag && Drop + + + + Allow Drops on Panels not in Setup Mode + + + + Start Cart + + + + Stop Cart + + + + + EditSvc + + Edit Service + Editar Servicio + + + &Service Name: + Nombre del &Servicio: + + + Service &Description: + &Descripción: + + + Log &Template Name: + &Plantilla Nmbr de Lista: + + + [none] + [ninguno] + + + Voicetrack Group: + Grupo para Pistas Voz: + + + Insert CHAIN TO at log end + CHAIN TO al fin de la Lista + + + Enable AutoRefresh By Default + Activar AutoRefrescar prederm. + + + Configure +&Autofill Carts + Configurar +&Cartuchos Autofill + + + Enable &Hosts + Activar &Equipos + + + Traffic Data Import + Importar Info. Tráfico + + + Linux Import Path: + Importar desde (Linux): + + + Windows Import Path: + Importar desde (Windows): + + + Note Cart String: + + + + Test +&Traffic + Probar +&Tráfico + + + Music Data Import + Importar Info. Música + + + Insert Traffic Break String: + Texto para romper tráfico: + + + Insert Voice Track String: + Texto para dividir pista de voz: + + + Test +&Music + Probar +&Música + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Save Import Data + Guardar datos importados + + + Before testing, the import configuration +must be saved. Save now? + Antes de iniciar pruebas, la configuración +debe guardarse. ¿Hacerlo ahora? + + + Purge ELR Data after + Borrar datos ELR tras + + + days + días + + + Purge Logs after + Borrar Listas tras + + + Import Template: + Importar Plantilla: + + + [custom] + [personalizado] + + + Linux Preimport Command: + Cmd antes de importar (Linux): + + + Windows Preimport Command: + Cmd antes de importar (Win): + + + &Program Code: + Código &Progr.: + + + AutoSpot Group: + + + + Log Name &Template: + + + + Log &Description Template: + + + + + EditSvcPerms + + Service: + Servicio: + + + Available Hosts + Equipos disponibles + + + Enabled Hosts + Equipos activos + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + EditTtys + + Edit TTYs + Editar TTYs + + + Port ID: + ID: + + + Enabled + Activo + + + TTY Device: + Dispositivo TTY: + + + Baud Rate: + Tasa de baudios: + + + Parity: + Paridad: + + + Data Bits: + Bits de datos: + + + Stop Bits: + Bits de parada: + + + Terminator: + Terminador: + + + &Close + &Cerrar + + + Serial + Serial + + + None + Ninguno + + + Even + Par + + + Odd + Impar + + + CR + + + + LF + + + + CR/LF + + + + + EditUser + + User: + Usuario: + + + &User Name: + &Usuario: + + + &Full Name: + &Nb. Completo: + + + &Description: + &Descripción: + + + &Phone: + Telé&fono: + + + Change +&Password + Cambiar +&Contraseña + + + Administrative Rights + Permisos administrativos + + + Administer S&ystem + Administrador del S&istema + + + Production Rights + Permisos de Producción + + + &Create Carts + C&rear Cartuchos + + + &Delete Carts + &Borrar Cartuchos + + + &Modify Carts + &Modificar Cartuchos + + + &Edit Audio + &Editar Audio + + + &Edit Netcatch Schedule + Editar programación &Netcatch + + + &Voicetrack Logs + Listas de &VoiceTrack + + + Traffic Rights + Permisos de Tráfico + + + Create &Log + Crear &Listas + + + De&lete Log + Borrar Li&stas + + + Delete &Report Data + Borrar datos de &Reportes + + + &Modify Template + &Modificar Plantillas + + + OnAir Rights + Permisos al aire + + + &Playout Logs + Re&producir Listas + + + &Rearrange Log Items + &Reordenar ítem en Listas + + + Add Log &Items + Aña&dir ítems a Listas + + + Delete Lo&g Items + Borrar ítems &de Listas + + + Configure System Panels + Configurar Paneles del Sistema + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Podcasting Rights + Permisos de Podcasts + + + Cre&ate Podcast + Crear &Podcasts + + + E&dit Podcast + Editar Po&dcast + + + Dele&te Podcast + Borrar P&odcast + + + Assign Group +Permissions + Asignar Permisos +de Grupo + + + Assign Podcast Feed +Permissions + Asignar permisos de +Feeds para Podcasts + + + Allow Web Logins + Permitir ingreso vía Web + + + + EditUserPerms + + User: + Usuario: + + + Available Groups + Grupos disponibles + + + Enabled Groups + Grupos activos + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + EditVguestResource + + Engine (Hex): + Motor (Hex): + + + Device (Hex): + Disposit (Hex): + + + Surface (Hex): + Superficie (Hex): + + + Bus/Relay (Hex): + Bus/Relay (Hex): + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Edit vGuest Switch + Editar Suiche vGuest + + + Edit vGuest Display + Editar display vGuest + + + Invalid Number + Número inválido + + + The Engine Number is Invalid! + ¡El número de motor es inválido! + + + The Device Number is Invalid! + ¡El número de dispositivo es inválido! + + + The Surface Number is Invalid! + ¡El número de superficie es inválido! + + + The Bus/Relay Number is Invalid! + ¡El número Bus/Relay es inválido! + + + + HelpAudioPorts + + Audio Ports Help + Ayuda para puertos de audio + + + Mode - short for Channel Mode, configures the Left and Right behaviour when recording.<BR> Behaviour varies depending on the number of channels to record as summarized in the table below:<BR><TABLE><TR> <TH>Channels</TH> <TH>Mode</TH> <TH>Effect</TH> </TR><TR> <TD>Mono</TD> <TD>Normal</TD> <TD>L+R sum to mono</TD> </TR><TR> <TD>Mono</TD> <TD>Swap</TD> <TD>R+L sum to mono (same result as Normal)</TD> </TR><TR> <TD>Mono</TD> <TD>Left only</TD> <TD>L -> mono</TD> </TR><TR> <TD>Mono</TD> <TD>Right only</TD> <TD>R -> mono</TD> </TR><TR> <TD>Stereo</TD> <TD>Normal</TD> <TD>Stereo</TD> </TR><TR> <TD>Stereo</TD> <TD>Swap</TD> <TD>Swapped stereo</TD> </TR><TR> <TD>Stereo</TD> <TD>Left only</TD> <TD>L -> to L channel only, R channel is silent</TD> </TR><TR> <TD>Stereo</TD> <TD>Right only</TD> <TD>R -> to R channel only, L channel is silent</TD> </TR></TABLE> + Modo - abreviatura para Modo de Canal, configura el comportamiento a la Izquierda y Derecha mientra se graba.<BR> El comportamiento varía dependiendo del número de canales para grabar, como se resume en la siguiente tabla:<BR><TABLE><TR> <TH>Canales</TH> <TH>Modo</TH> <TH>Efecto</TH> </TR><TR> <TD>Mono</TD> <TD>Normal</TD> <TD>L+R se suman para ser mono</TD> </TR><TR> <TD>Mono</TD> <TD>Intercambio</TD> <TD>R+L se suman para mono (mismo resultado que en Normal)</TD> </TR><TR> <TD>Mono</TD> <TD>Sólo Izquierda</TD> <TD>Izq -> mono</TD> </TR><TR> <TD>Mono</TD> <TD>Sólo derecha</TD> <TD>Der -> mono</TD> </TR><TR> <TD>Estéreo</TD> <TD>Normal</TD> <TD>Estéreo</TD> </TR><TR> <TD>Estéreo</TD> <TD>Intercambio</TD> <TD>Estéreo con los canales intercambiados</TD> </TR><TR> <TD>Estéreo</TD> <TD>Sólo izquierda</TD> <TD>Izq -> al canal izquierdo solamente, el canal derecho permanece en silencio</TD> </TR><TR> <TD>Estéreo</TD> <TD>Sólo derecha</TD> <TD>Der -> al canal derecho solamente, el canal izquierdo permanece en silencio</TD> </TR></TABLE> + + + &Close + &Cerrar + + + + InfoDialog + + System Information + Información del Sistema + + + Rivendell + + + + A Radio Automation System + Sistema de Automatización de Emisoras + + + Version + Version + + + Database Schema + Esq. Base de Datos + + + This program is free software, and comes with ABSOLUTELY NO WARRANTY, +not even the implied warranties of MERCHANTIBILITY or FITNESS FOR A +PARTICULAR PURPOSE. Touch the "View License" button for details. + Este programa es Software Libre, y se proporciona SIN GARANTÍAS DE NINGÚN +TIPO, ni siquiera las garantías MERCANTILES implícitas o LA CONVENIENCIA +PARA UN PROPÓSITO PARTICULAR. Oprima el botón "Ver licencia" para detalles. + + + View +&License + Ver +&Licencia + + + &Close + &Cerrar + + + Copyright 2002-2010 + Copyright 2002-2010 + + + Copyright 2002-2014 + Copyright 2002-2014 + + + + ListAuxFields + + Auxiliary Metadata Fields + Campos de metadatos auxiliares + + + Var Name + Nombre + + + Caption + Texto + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + E&liminar + + + &Close + &Cerrar + + + Warning + Advertencia + + + This will delete all data associated with this field! +Are you sure you want to continue? + ¡Esto eliminará todos los datos asociados con este campo! +¿Está seguro de continuar? + + + + ListDropboxes + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + E&liminar + + + &Close + &Cerrar + + + Group + Grupo + + + Path + Carpeta + + + Normalization Level + Nivel de Normalización + + + Autotrim Level + Nivel de AutoRecorte + + + To Cart + A Cartucho + + + Use CartChunk ID + Usar ID de CartChunk + + + Delete Cuts + Borrar audios + + + Metadata Pattern + Patrón de metadatos + + + Fix Broken Formats + Arreglar formatos rotos + + + [off] + [apagado] + + + [auto] + [auto] + + + [none] + [ninguno] + + + User Defined + + + + + ListEncoders + + RDAdmin - List Encoders + RDAdmin - Lista de codificadores + + + Format Name + Nombre del formato + + + Valid Channels + Canales válidos + + + Valid Sample Rates + Tasas muestra válidas + + + Valid Bit Rates + Tasas de bit válidas + + + &Edit + &Editar + + + &Close + &Cerrar + + + [none] + [ninguna] + + + &Add + &Agregar + + + &Delete + E&liminar + + + RDAdmin - Delete Encoder + RDAdmin - Eliminar codificador + + + Are you sure you want to delete this encoder? + ¿Está seguro de querer eliminar este codificador? + + + Extension + Extensión + + + This encoder is in use by the following RSS feeds: + + + Este codificador está siendo usado por las fuentes RSS: + + + + + + +Do you still want to delete it? + + +¿Aún desea eliminarlo? + + + Encoders on + Codificad. en + + + + ListEndpoints + + List Inputs + Listar Entradas + + + List Outputs + Listar Salidas + + + INPUT + ENTRADA + + + OUTPUT + SALIDA + + + LABEL + ETIQ + + + SOURCE + FUENTE + + + MODE + MODO + + + ENGINE (Hex) + MOTOR (Hex) + + + DEVICE (Hex) + DISPOSIT (Hex) + + + PROVIDER ID + ID PROVEEDOR + + + SERVICE ID + ID SERVICIO + + + &Edit + &Editar + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Stereo + Estéreo + + + Left + Izquierda + + + Right + Derecha + + + Input + Entrada + + + Output + Salida + + + stereo + estéreo + + + left + izq + + + right + der + + + NODE + NODO + + + # + # + + + + ListFeeds + + Rivendell Feed List + Lista de feeds Rivendell + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + E&liminar + + + &Close + &Cerrar + + + Key + Nombre + + + Title + Título + + + AutoPost + AutoPublicar + + + Keep Metadata + Mantener metadatos + + + Creation Date + Fecha de creación + + + &Feeds: + &Feeds: + + + Are you sure you want to delete feed + ¿Está seguro de borrar el feed + + + Delete Feed + Eliminar Feed + + + Deleting Audio... + Eliminando Audio... + + + Cancel + Cancelar + + + Deleting + Borrando + + + + ListGpis + + List GPIs + Listar GPIs + + + GPI Lines + Líneas GPI + + + GPI + GPI + + + &Edit + &Editar + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + [unassigned] + [no asignado] + + + GPO + GPO + + + List GPOs + Listar GPOs + + + GPO Lines + Líneas GPO + + + ON MACRO CART + CART MACRO ON + + + ON DESCRIPTION + DESCRIPCIÓN ON + + + OFF MACRO CART + CART MACRO OFF + + + OFF DESCRIPTION + DESCRIPCIÓN OFF + + + + ListGroups + + Rivendell Group List + Lista de Grupos de Rivendell + + + &Add + &Añadir + + + &Edit + &Editar + + + &Rename + &Renombrar + + + &Delete + E&liminar + + + Generate +&Report + Generar +&Reporte + + + &Close + &Cerrar + + + NAME + NOMBRE + + + DESCRIPTION + DESCRIPCIÓN + + + START CART + CART INICIO + + + END CART + CART FIN + + + ENFORCE RANGE + OBLIGAR RANGO + + + DEFAULT TYPE + TIPO INICIAL + + + TRAFFIC REPORT + REPORTE TRÁFICO + + + MUSIC REPORT + REPORTE MÚSICA + + + NOW & NEXT + NOW & NEXT + + + &Groups: + &Grupos: + + + member carts will be deleted along with group + cartuchos serán borrados junto con el grupo + + + Are you sure you want to delete group + Desea eliminar el grupo + + + Delete Group + Borrar grupo + + + + ListHostvars + + Host Variables for + Variables de equipo para + + + Host Variables + Variables de equipo + + + NAME + NOMBRE + + + VALUE + VALOR + + + REMARK + COMENTARIO + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + E&liminar + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + ListLiveWireGpios + + LiveWire GPIO Source Assignments + + + + Switchers: + Suicheras: + + + &Edit + &Editar + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + [none] + + + + Lines + + + + Surface Address + + + + [all] + + + + Source # + + + + + ListMatrices + + Rivendell Switcher List + Lista de Suicheras en Rivendell + + + Switchers: + Suicheras: + + + MATRIX + + + + DESCRIPTION + DESCRIPCIÓN + + + TYPE + TIPO + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + E&liminar + + + &Close + &Cerrar + + + Are you sure you want to delete switcher + ¿Está seguro de borrar la suichera + + + on + en + + + ALL references to this switcher will be deleted! + ¡TODAS las referencias a esta suichera serán borradas! + + + Deleting Switcher + Borrando suichera + + + Local GPIO + GPIO Local + + + Generic GPO + GPO Genérico + + + Generic Serial + Serial Genérico + + + Local Audio Adapter + Adaptador de Audio Local + + + + ListReplicatorCarts + + &Repost + &Republicar + + + Repost +&All + Republicar +&Todos + + + &Close + &Cerrar + + + CART + CARTUCHO + + + TITLE + TÍTULO + + + LAST POSTED + ÚLTIMO COLOCADO + + + POSTED FILENAME + NOMBRE DEL ARCHIVO + + + &Active Carts: + Cart. &Activos: + + + Replicator Carts + Cartuchos Replicadores + + + + ListReplicators + + Rivendell Replicators + Replicadores Rivendell + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + E&liminar + + + &List +Carts + &Listar +Cartuchos + + + &Close + &Cerrar + + + NAME + NOMBRE + + + TYPE + TIPO + + + DESCRIPTION + DESCRIPCIÓN + + + HOST + COMPUTADOR + + + &Replicators: + &Replicadores: + + + Are you sure you want to delete replicator + Desea eliminar el replicador + + + Delete Replicator + Eliminar Replicador + + + + ListReports + + Rivendell Report List + Lista de Reportes de Rivendell + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + E&liminar + + + &Close + &Cerrar + + + R&eports: + R&eportes: + + + Are you sure you want to delete report + Está seguro de querer eliminar este reporte + + + Delete Report + Eliminar reporte + + + + ListSchedCodes + + Rivendell Scheduler Codes List + Lista de Códigos de Musicalización + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + E&liminar + + + &Close + &Cerrar + + + CODE + CÓDIGO + + + DESCRIPTION + DESCRIPCIÓN + + + Scheduler Codes: + Códigos para Musicalizar: + + + Are you sure you want to delete scheduler code + ¿Está seguro de querer eliminar el código + + + Delete Scheduler Code + Eliminar código de musicalización + + + + ListStations + + Rivendell Workstation List + Lista de computadores usando Rivendell + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + E&liminar + + + &Close + &Cerrar + + + Ho&sts: + C&omputadores: + + + Are you sure you want to delete host + Está seguro de querer eliminar este equipo + + + Delete Station + Eliminar equipo + + + + ListSvcs + + Services + Servicios + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + E&liminar + + + &Close + &Cerrar + + + &Services: + &Servicios: + + + Are you sure you want to delete service + Está seguro de querer eliminar este servicio + + + Delete Service + Eliminar un servicio + + + There are + Hay + + + logs owned by this service that will also be deleted. +Do you still want to proceed? + PlayLists pertenecientes a este servicio que serán eliminados. +¿Desea continuar y eliminarlos? + + + Logs Exist + El PlayList ya existe + + + + ListUsers + + Rivendell User List + Lista de usuarios de Rivendell + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + E&liminar + + + &Close + &Cerrar + + + &Users: + &Usuarios: + + + DESCRIPTION + DESCRIPCIÓN + + + USER NAME + NMBRE USUAR + + + FULL NAME + NMBRE COMPLETO + + + Are you sure you want to delete user + Está seguro de querer eliminar el usuario + + + Delete User + Eliminar usuario + + + You must change this before deleting the user. + Usted debe cambiar esto antes de eliminar el usuario. + + + This user is set as the default user for the following hosts: + + + Este usuario es el predeterminado en los siguientes equipos: + + + + + You cannot delete yourself! + ¡Ud. no puede borrarse a sí mismo! + + + + Login + + Login + Ingreso + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + User &Name: + &Usuario: + + + &Password: + C&ontraseña: + + + + MainWidget + + RDAdmin - Host: + RDAdmin - Computador: + + + Daemons Failed + Falla en los servicios + + + Unable to start Rivendell System Daemons! + ¡No fue posible iniciar los Servicios del Sistema Rivendell! + + + Insufficient Priviledges + No hay suficientes privilegios + + + This account has insufficient priviledges for this operation. + Esta cuenta no tiene suficientes privilegios para la operación. + + + Manage +&Users + Administrar +&Usuarios + + + Manage +&Groups + Administrar +&Grupos + + + Manage +&Services + Administrar +&Servicios + + + Manage +Ho&sts + Administrar +&Equipos + + + Manage +R&eports + Administrar +&Reportes + + + System +Info + Información +del Sistema + + + Scheduler +Codes + Códigos para +musicalizar + + + &Backup +Database + &Respaldar +Base datos + + + &Restore +Database + &Restaurar +base datos + + + &Quit + &Salir + + + Rivendell Database Backup (*.sql) + Respaldo de la base de datos (*.sql) + + + Backup Error + Error en el respaldo + + + Unable to create backup! + ¡No pude crear el respaldo! + + + Backup Complete + Respaldo completado + + + Backup completed successfully. + Respaldo completado exitosamente. + + + Restore Database + Restaurar base de datos + + + WARNING: This operation will COMPLETELY +OVERWRITE the existing Rivendell Database! +Do you want to continue? + ADVERTENCIA: Esta operación SOBREESCRIBIRÁ +COMPLETAMENTE la base de datos existente. +¿Desea continuar? + + + Restore Error + Error en la restauración + + + Unable to restore backup! + ¡No pude restaurar la base de datos! + + + Restore Complete + Restauración finalizada + + + Restore completed successfully. + La restauración fue completada exitosamente. + + + Manage +&Feeds + Administrar +&Feeds + + + System +Settings + Config. del +Sistema + + + Manage +Replicators + Administrar +Replicadores + + + RDAdmin + RDAdmin + + + + MySqlLogin + + mySQL Admin + Admin. MySQL + + + User &Name: + &Usuario: + + + &Password: + &Contraseña: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + QObject + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + ¡No se pudo acceder a la base de datos Rivendell! +Si desea crear una NUEVA base de datos, ingrese +el login y la clave de una cuenta Mysql con +derechos administrativos. + + + Wrong access permissions for accessing mySQL! + ¡Permisología errónea al acceder a la base de datos MySQL! + + + Unable to connect to mySQL! + ¡No es posible conectarse con la base de datos MySQL! + + + Unable to create a Rivendell Database! + ¡No pude crear la base de datos Rivendell! + + + Unable to connect to new Rivendell Database! + ¡No pude conectarme a la nueva base de datos Rivendell! + + + Unable to create Rivendell Database! + ¡No pude crear la base de datos Rivendell! + + + Unable to connect to Rivendell Database! + ¡No pude conectarme a la base de datos Rivendell! + + + Unable to initialize Rivendell Database! + ¡No fue posible inicializar la base de datos Rivendell! + + + RDAdmin + RDAdmin + + + New Rivendell Database Created! + ¡Se ha creado una nueva base de datos! + + + Unable to upgrade database + No fue posible actualizar la base de datos + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + La base de datos Rivendell es muy antigua y no +puede ser actualizada, por lo que será reemplazada. +¡Esto DESTRUIRÁ todo audio y datos existentes! +Si desea continuar, introduzca el usuario y la clave +de una cuenta MySQL con privilegios administrativos, +o de lo contrario seleccione CANCELAR. + + + Unable to log into Administrator account! + ¡No pudo ingresar a una cuenta administrativa! + + + Unable to authorize a Rivendell Database! + ¡No puedo autorizar la base de datos Rivendell! + + + Update Needed + Se necesita actualizar + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + La base de datos requiere ser actualizada. Todo el audio +y la configuración se van a preservar, pero hay que +DETENER las reproducciones y grabaciones por unos +segundos. ¿Desea continuar? + + + Unable to update Rivendell Database: + No fue posible actualizar la base de datos: + + + +Database backup failed! + +¡No se pudo respaldar la base de datos! + + + +Schema modification failed! + +¡Falló la modificación del esquema! + + + +Unknown/unspecified error! + +¡Error desconocido/no especificado! + + + The Rivendell Database has been updated to version + La base de datos de Rivendell ha sido actualizada a la versión + + + +and a backup of the original database saved in + +y un respaldo de la base de datos se guardó en + + + Database Updated + Base de datos actualizada + + + RDAdmin Error + Error de RDAdmin + + + (default) + (por omisión) + + + Start Line 1 + Iniciar Línea 1 + + + Stop Line 1 + Detener Línea 1 + + + Pause Line 1 + Pausar Línea 1 + + + Start Line 2 + Iniciar Línea 2 + + + Stop Line 2 + Detener Línea 2 + + + Pause Line 2 + Pausar Línea 2 + + + Start Line 3 + Iniciar Línea 3 + + + Stop Line 3 + Detener Línea 3 + + + Pause Line 3 + Pausar Línea 3 + + + Start Line 4 + Iniciar Línea 4 + + + Stop Line 4 + Detener Línea 4 + + + Pause Line 4 + Pausar Línea 4 + + + Start Line 5 + Iniciar Línea 5 + + + Stop Line 5 + Detener Línea 5 + + + Pause Line 5 + Pausar Línea 5 + + + Start Line 6 + Iniciar Línea 6 + + + Stop Line 6 + Detener Línea 6 + + + Pause Line 6 + Pausar Línea 6 + + + Start Line 7 + Iniciar Línea 7 + + + Stop Line 7 + Detener Línea 7 + + + Pause Line 7 + Pausar Línea 7 + + + Add + Añadir + + + Delete + Borrar + + + Copy + Copiar + + + Move + Mover + + + Sound Panel + Panel de sonidos + + + Main Log + Lista Ppal + + + Aux Log 1 + Lista aux. 1 + + + Aux Log 2 + Lista aux. 2 + + + + RenameGroup + + Rename Group + Cambiar nombre del grupo + + + Current Group Name: + Nombre actual: + + + New &Group Name: + Nuevo &Nombre: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Group + Grupo inválido + + + The group name is invalid! + ¡El nombre del grupo es inválido! + + + A + Un grupo + + + group already exists. +Do you want to combine the two? + ya existe. +¿Desea combinar ambos? + + + Group Exists + El grupo ya existe + + + + TestImport + + Test Traffic Import + Probar importación de Tráfico + + + Test Music Import + Probar importación de Música + + + Test Date: + Fecha prueba: + + + &Select + &Elegir + + + &Import + &Importar + + + Using source file: + Usando archivo fuente: + + + Start Time + Hora de inicio + + + Cart + Cartucho + + + Len + Lon + + + Title + Título + + + Contract # + Contrato # + + + Event ID + ID de evento + + + Announcement Type + Tipo de Anuncio + + + Imported Events + Eventos importados + + + &Close + &Cerrar + + + Import Error + Error de importación + + + There was an error during import +please check your settings and try again. + Ha habido un error durante la importación +Revise los parámetros e intente de nuevo. + + + [spot break] + [parada del spot] + + + + ViewAdapters + + Audio Resource Information + Información de recursos de audio + + + Audio Resources on + Recursos de audio en + + + SUPPORTED AUDIO DRIVERS + + DRIVERS DE AUDIO SOPORTADOS + + + SUPPORTED IMPORT FORMATS + + FORMATOS DE IMPORTACIÓN SOPORTADOS + + + + PCM16 Linear + + PCM16 lineal + + + MPEG Layer 1 + + MPEG Capa 1 + + + + MPEG Layer 2 + + MPEG Capa 2 + + + + MPEG Layer 3 + + MPEG Capa 3 + + + + OggVorbis + + OGGVorbis + + + SUPPORTED EXPORT FORMATS + + FORMATOS DE EXPORTACIÓN SOPORTADOS + + + Free Lossless Audio Codec (FLAC) + + FLAC (Free Lossless Audio Codec) + + + + AUDIO ADAPTERS + + ADAPTADORES DE AUDIO + + + + Card + Tarjeta + + + Not present + No presente + + + Driver: AudioScience HPI + + + + + Driver: JACK Audio Connection Kit + + + + + Driver: Advanced Linux Sound Architecture (ALSA) + + + + + Driver: UNKNOWN + + Driver: DESCONOCIDO + + + + Inputs: + Entradas: + + + Outputs: + Salidas: + + + NO DATA AVAILABLE + + + NO HAY DATOS DISPONIBLES + + + + + Please start the Rivendell daemons on this host (by executing, as user 'root', the command "/etc/init.d/rivendell start") in order to populate the audio resources database. + Inicie los servicios Rivendell en este equipo (ejecutando, como 'root', el comando "/etc/init.d/rivendell start") para iniciar la base de datos de recursos de audio. + + + &Close + &Cerrar + + + diff --git a/rdadmin/rdadmin_fr.ts b/rdadmin/rdadmin_fr.ts new file mode 100644 index 00000000..0c422f78 --- /dev/null +++ b/rdadmin/rdadmin_fr.ts @@ -0,0 +1,5364 @@ + + + AddAuxField + + Add Aux Field + + + + Variable Name: + + + + %AUX_ + + + + % + + + + Caption: + + + + &OK + + + + &Cancel + + + + Name Exists + + + + That variable name already exists! + + + + + AddEncoder + + Add Encoder + + + + &New Encoder Name: + + + + &OK + + + + &Cancel + + + + Add Encoder Error + + + + A encoder with that name already exists! + + + + + AddFeed + + Add Feed + + + + Enable Feed for All Users + + + + &New Feed Name: + + + + &OK + + + + &Cancel + + + + Add Feed Error + + + + A feed with that key name already exists! + + + + + AddGroup + + Add Group + + + + &New Group Name: + + + + Enable Group for All Users + + + + Enable Group for All Services + + + + &OK + + + + &Cancel + + + + Invalid Name + + + + You must give the group a name! + + + + Group Exists + + + + Group Already Exists! + + + + + AddHostvar + + Add Host Variable + + + + Variable Name: + + + + Variable Value: + + + + Remark: + + + + &OK + + + + &Cancel + + + + Invalid Name + + + + The variable name is invalid. + + + + + AddMatrix + + &New Matrix Number: + + + + &Switcher Type: + + + + &OK + + + + &Cancel + + + + Invalid Matrix + + + + Matrix already exists! + + + + New Switcher + + + + RDAdmin - Add Switcher + + + + + AddReplicator + + Add Replicator + + + + &New Replicator Name: + + + + &OK + + + + &Cancel + + + + Invalid Name + + + + You must give the replicator a name! + + + + Replicator Exists + + + + A replicator with that name already exists! + + + + + AddReport + + Add Report + + + + &Report Name: + + + + &OK + + + + &Cancel + + + + Invalid Name + + + + You must provide a report name! + + + + Report Exists + + + + A report with that name already exists! + + + + + AddStation + + Add Host + + + + New &Host Name: + + + + Base Host On: + + + + &OK + + + + &Cancel + + + + Empty Host Config + + + + Invalid Name + + + + You must give the host a name! + + + + Host Exists + + + + Host Already Exists! + + + + + AddSvc + + Add Service + + + + &New Service Name: + + + + Base Service On: + + + + &OK + + + + &Cancel + + + + Empty Host Config + + + + Invalid Name + + + + You must give the service a name! + + + + Service Exists + + + + Service Already Exists! + + + + + AddUser + + Add User + + + + &New User Name: + + + + &OK + + + + &Cancel + + + + Invalid Name + + + + You must give the user a name! + + + + User Exists + + + + User Already Exists! + + + + + AutofillCarts + + Autofill Carts - Service: + + + + Cart + + + + Length + + + + Title + + + + Artist + + + + &Add + + + + &Delete + + + + &OK + + + + &Cancel + + + + + EditAudioPorts + + Edit Audio Ports + + + + Clock Source: + + + + Input Port + + + + Analog + + + + AES/EBU + + + + SP/DIFF + + + + Type: + + + + Normal + + + + Swap + + + + Left only + + + + Right only + + + + Mode: + + + + dB + + + + Output Port + + + + &Help + + + + &Close + + + + Internal + + + + AES/EBU Signal + + + + SP/DIFF Signal + + + + Word Clock + + + + Card: + + + + Card Driver: + + + + Ref. Level: + + + + + EditAuxField + + Edit Auxiliary Metadata Fields + + + + Variable Name: + + + + Caption: + + + + &OK + + + + &Cancel + + + + + EditBackup + + Backup config for + + + + Keep Backups For: + + + + days + + + + Backup Directory: + + + + &OK + + + + &Cancel + + + + Path Missing + + + + You must supply a backup path! + + + + + EditCartSlots + + RDAdmin - Edit CartSlots + + + + Close + + + + None + + + + Output Port: + + + + Card: + + + + Input Port: + + + + Cart: + + + + At Playout End: + + + + Channel Assignments + + + + Default Settings + + + + Select + + + + Load Specified Cart + + + + At Startup: + + + + Do Nothing + + + + Slot Mode: + + + + Full + + + + Hook + + + + Play Mode: + + + + User previous mode + + + + Use previous mode + + + + Use previous cart + + + + Use previous action + + + + Service: + + + + Global Settings + + + + Slot Columns: + + + + Slot Rows: + + + + Slot + + + + Settings + + + + Slot selected has changed! + + + + + EditDecks + + Configure RDCatch + + + + Record Deck + + + + None + + + + Monitor Port: + + + + Off + + + + On + + + + Monitor defaults to + + + + Format: + + + + Bit Rate: + + + + Switcher Host: + + + + Switcher Matrix: + + + + Switcher Output: + + + + Switcher Delay: + + + + 1/10 sec + + + + Channels: + + + + Trim Threshold: + + + + Error RML: + + + + Play Deck + + + + &Close + + + + No Audio Configuration Data + + + + PCM16 + + + + MPEG Layer 2 + + + + 32 kbps/chan + + + + 48 kbps/chan + + + + 56 kbps/chan + + + + 64 kbps/chan + + + + 80 kbps/chan + + + + 96 kbps/chan + + + + 112 kbps/chan + + + + 128 kbps/chan + + + + 160 kbps/chan + + + + 192 kbps/chan + + + + [none] + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Settings + + + + Defaults + + + + Host-Wide Settings + + + + + EditDropbox + + Dropbox Configuration + + + + Default Group: + + + + &Path Spec: + + + + Select + + + + To &Cart: + + + + Delete cuts before importing + + + + &Metadata Pattern: + + + + &Log File: + + + + Delete source files after import + + + + Normalize Levels + + + + Level: + + + + dBFS + + + + Autotrim Cuts + + + + Get cart number from CartChunk CutID + + + + Get cart title from CartChunk CutID + + + + Attempt to work around malformatted input files + + + + Offset start date by + + + + days + + + + Offset end date by + + + + Create Dates when no Dates Exist + + + + Create start date offset: + + + + Create end date offset: + + + + &OK + + + + &Cancel + + + + Invalid Offsets + + + + The Create EndDate Offset is less than the Create Start Date Offset! + + + + &User Defined: + + + + Scheduler Codes + + + + + EditEncoder + + RDAdmin - Edit Encoder + + + + Name: + + + + Allow Channels + + + + Allow Sample Rates + + + + Allow Bit Rates + + + + &OK + + + + &Cancel + + + + Default Extension: + + + + Command Line: + + + + + EditEndpoint + + Edit Input + + + + Edit Output + + + + Name: + + + + Feed: + + + + Mode: + + + + Stereo + + + + Left + + + + Right + + + + Engine (Hex): + + + + Provider ID: + + + + Device (Hex): + + + + Service ID: + + + + &OK + + + + &Cancel + + + + Invalid Number + + + + The Engine Number is Invalid! + + + + The Provider ID is Invalid! + + + + The Device Number is Invalid! + + + + The Service ID is Invalid! + + + + + EditFeed + + Feed: + + + + Key Name: + + + + CHANNEL VALUES + + + + Title: + + + + Category: + + + + Link: + + + + Copyright: + + + + Webmaster: + + + + Language: + + + + Description: + + + + Audio Upload URL: + + + + Username: + + + + Password: + + + + Upload Format: + + + + S&et + + + + Normalize + + + + Level: + + + + dBFS + + + + Audio Download URL: + + + + Keep Expired Metadata + + + + Enable AutoPost + + + + Enclosure Preamble: + + + + Audio Extension: + + + + None + + + + Maximum Shelf Life: + + + + days + + + + Descending + + + + Ascending + + + + Episode Sort Order: + + + + Direct + + + + Counted + + + + Media Link Mode: + + + + Enable Feed Redirection + + + + URL: + + + + Header XML: + + + + Channel XML: + + + + Item XML: + + + + &Define Auxiliary +Metadata Fields + + + + &OK + + + + &Cancel + + + + Edit Feed - Redirect + + + + Enabling feed redirection will cause clients subscribed to +this feed to be PERMANENTLY redirected to the +specified URL. + +Do you still want to enable redireciton? + + + + + EditFeedPerms + + User: + + + + Available Feeds + + + + Enabled Feeds + + + + &OK + + + + &Cancel + + + + + EditGpi + + Edit GPI + + + + Description: + + + + Cart Number: + + + + &Select + + + + C&lear + + + + &OK + + + + &Cancel + + + + Invalid Cart + + + + Invalid Cart Number! + + + + + EditGroup + + Group: + + + + &Group Name: + + + + Group &Description: + + + + Audio + + + + Macro + + + + Default Cart &Type: + + + + None + + + + Default Cart Number: + + + + to + + + + Enforce Cart Range + + + + Include this group in Traffic reports + + + + Include this group in Music reports + + + + Transmit Now && Next data + + + + C&olor + + + + &OK + + + + &Cancel + + + + The selected cart range conflicts with the following groups: + + + + + + +Do you still want to save? + + + + Default Import &Title: + + + + Purge expired cuts after + + + + days + + + + Delete cart if empty + + + + + EditHostvar + + Edit Host Variable + + + + Variable Name: + + + + Variable Value: + + + + Remark: + + + + &OK + + + + &Cancel + + + + + EditHotkeys + + Host Hot Key Configurations + + + + Button / Function + + + + KeyStroke + + + + Set + + + + Clear + + + + Clear All Hotkeys + + + + Set From Host: + + + + Save + + + + Cancel + + + + Duplicate Entries + + + + Hotkeys Clear + + + + Hotkeys Updated + + + + No Items Selected + + + + Please Select an Item From the List + + + + Hot Key Configuration for + + + + + EditJack + + JACK Configuration for + + + + Start JACK Server + + + + JACK Server Name: + + + + &OK + + + + &Cancel + + + + JACK Command Line: + + + + JACK Clients to Start: + + + + Client + + + + Command Line + + + + &Add + + + + &Edit + + + + &Delete + + + + [New Client] + + + + RDAdmin - JACK Clients + + + + Are you sure you want to delete JACK Client + + + + + EditJackClient + + JACK Client Configuration for + + + + Description: + + + + Command Line: + + + + &OK + + + + &Cancel + + + + + EditLiveWireGpio + + &OK + + + + &Cancel + + + + Edit GPIO Source + + + + Livewire Source: + + + + GPIO Lines + + + + Surface Address: + + + + Invalid IP Address + + + + The IP address is invalid! + + + + None + + + + + EditMatrix + + Matrix Number: + + + + Switcher Type: + + + + Description: + + + + Primary Connection + + + + Type: + + + + Serial + + + + TCP/IP + + + + Serial Port: + + + + IP Address: + + + + IP Port: + + + + Username: + + + + Password: + + + + Backup Connection + + + + None + + + + Card: + + + + Inputs: + + + + Outputs: + + + + Device: + + + + GPIs: + + + + GPOs: + + + + Layer: + + + + Displays: + + + + Configure +&Inputs + + + + LiveWire +Nodes + + + + vGuest +Switches + + + + vGuest +Displays + + + + &OK + + + + &Cancel + + + + Invalid Address + + + + The primary IP address is invalid! + + + + The backup IP address is invalid! + + + + Duplicate Connections + + + + The primary and backup connections must be different! + + + + Configure +&GPIs + + + + Configure +G&POs + + + + Startup Cart: + + + + Select + + + + Shutdown Cart: + + + + SAS +Switches + + + + RDAdmin - Edit Switcher + + + + Configure +&Outputs + + + + LiveWire +GPIOs + + + + + EditNowNext + + Edit Now & Next Data + + + + Master Log + + + + IP Address: + + + + UDP Port: + + + + UDP String: + + + + RML: + + + + Aux Log 1 + + + + &OK + + + + &Cancel + + + + The IP address + + + + is invalid! + + + + Invalid Address + + + + Add + + + + Edit + + + + Delete + + + + Path + + + + Argument + + + + Loadable Modules: + + + + Default Now Cart: + + + + Default Next Cart: + + + + Select + + + + Aux Log 2 + + + + + EditNowNextPlugin + + Edit Plugin + + + + Plugin Path: + + + + Argument: + + + + &OK + + + + &Cancel + + + + Select + + + + Select plugin + + + + + EditRDAirPlay + + RDAirPlay config for + + + + Channel Assignments + + + + Main Log Output 1 + + + + Start RML: + + + + Stop RML: + + + + Main Log Output 2 + + + + Aux Log 1 Output + + + + Aux Log 2 Output + + + + SoundPanel First Play Output + + + + SoundPanel Second Play Output + + + + SoundPanel Third Play Output + + + + SoundPanel Fourth Play Output + + + + SoundPanel Fifth and Later Play Output + + + + Manual Segue: + + + + msecs + + + + Forced Segue: + + + + Pie Counts Last: + + + + secs + + + + Pie Counts To: + + + + Cart End + + + + Transition + + + + Default Trans. Type: + + + + Play + + + + Segue + + + + Stop + + + + Default Service: + + + + Sound Panel Settings + + + + None + + + + Host Panels: + + + + User Panels: + + + + Flash Active Buttons + + + + Enable Button Pausing + + + + Label Template: + + + + Miscellaneous Settings + + + + Previous + + + + LiveAssist + + + + Automatic + + + + Manual + + + + Check TimeSync + + + + Show Auxlog 1 Button + + + + Show Auxlog 2 Button + + + + Clear Cart Search Filter + + + + Enable Paused Events + + + + Space Bar Action + + + + Start Next + + + + Configure Now && Next +Parameters + + + + Start/Stop Settings + + + + Exit Password: + + + + Main Log + + + + Restart Log After Unclean Shutdown + + + + Log: + + + + &Select + + + + &OK + + + + &Cancel + + + + No Audio Configuration Data + + + + [none] + + + + Data Error + + + + Invalid Segue Length! + + + + Invalid Forced Segue Length! + + + + Display Settings + + + + Background Image: + + + + Select + + + + Select Image File + + + + Show Extra Buttons/Counters + + + + Audition Preroll: + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Configure Hot Keys + + + + Show Hour Selector + + + + Edit +GPIOs + + + + Title Template: + + + + Artist Template: + + + + Outcue Template: + + + + Description Template: + + + + Log Mode Control + + + + start with empty log + + + + load previous log + + + + load specified log + + + + At Startup: + + + + Mode Control Style: + + + + Unified + + + + Independent + + + + Main Log Startup Mode: + + + + Aux 1 Log Startup Mode: + + + + Aux 2 Log Startup Mode: + + + + + EditRDLibrary + + RDLibrary config for + + + + INPUT + + + + OUTPUT + + + + Settings + + + + &Max Record Time: + + + + &VOX Threshold: + + + + dbFS + + + + &AutoTrim Threshold: + + + + &Tail Preroll: + + + + milliseconds + + + + &Ripper Device: + + + + &Paranoia Level: + + + + Ripper Level: + + + + &FreeDB Server: + + + + &Format: + + + + &Bitrate: + + + + No + + + + Yes + + + + Allow E&xternal Editing: + + + + Defaults + + + + &Channels: + + + + Record Mode: + + + + AutoTrim: + + + + &OK + + + + &Cancel + + + + No Audio Configuration Data + + + + Normal + + + + Low + + + + None + + + + PCM16 + + + + MPEG Layer 2 + + + + Manual + + + + VOX + + + + 32 kbps/chan + + + + 48 kbps/chan + + + + 56 kbps/chan + + + + 64 kbps/chan + + + + 80 kbps/chan + + + + 96 kbps/chan + + + + 112 kbps/chan + + + + 128 kbps/chan + + + + 160 kbps/chan + + + + 192 kbps/chan + + + + 40 kbps/chan + + + + 224 kbps/chan + + + + 256 kbps/chan + + + + 320 kbps/chan + + + + Sample Rate Converter: + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Limit Searches at Startup + + + + Previous + + + + + EditRDLogedit + + RDLogedit config for + + + + INPUT + + + + OUTPUT + + + + Voice Tracker Settings + + + + &Max Record Time: + + + + &AutoTrim Threshold: + + + + dbFS + + + + &Normalization Level: + + + + &Audio Margin: + + + + milliseconds + + + + &Format: + + + + &Bitrate: + + + + Play &Start Cart: + + + + Select + + + + Play &End Cart: + + + + &Record Start Cart: + + + + Re&cord End Cart: + + + + &Channels: + + + + Default Transition: + + + + Play + + + + Segue + + + + Stop + + + + &OK + + + + &Cancel + + + + No Audio Configuration Data + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + PCM16 + + + + MPEG Layer 2 + + + + 32 kbps/chan + + + + 48 kbps/chan + + + + 56 kbps/chan + + + + 64 kbps/chan + + + + 80 kbps/chan + + + + 96 kbps/chan + + + + 112 kbps/chan + + + + 128 kbps/chan + + + + 160 kbps/chan + + + + 192 kbps/chan + + + + 40 kbps/chan + + + + 224 kbps/chan + + + + 256 kbps/chan + + + + 320 kbps/chan + + + + No + + + + Yes + + + + Enable &2nd Start Button: + + + + + EditRDPanel + + RDPanel config for + + + + Channel Assignments + + + + SoundPanel First Play Output + + + + Start RML: + + + + Stop RML: + + + + SoundPanel Second Play Output + + + + SoundPanel Third Play Output + + + + SoundPanel Fourth Play Output + + + + SoundPanel Fifth and Later Play Output + + + + SoundPanel Cue Output + + + + Display Settings + + + + Background Image: + + + + Select + + + + Sound Panel Settings + + + + None + + + + Host Panels: + + + + User Panels: + + + + Flash Active Buttons + + + + Enable Button Pausing + + + + Clear Cart Search Filter + + + + Default Service: + + + + Label Template: + + + + &OK + + + + &Cancel + + + + No Audio Configuration Data + + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + + + + [none] + + + + Select Image File + + + + + EditReplicator + + Replicator: + + + + Name: + + + + Description: + + + + Type: + + + + Host System: + + + + Audio Upload URL: + + + + Username: + + + + Password: + + + + Upload Format: + + + + S&et + + + + Normalize + + + + Level: + + + + dBFS + + + + Available Groups + + + + Active Groups + + + + &OK + + + + &Cancel + + + + + EditReport + + Edit Report + + + + &Report Description: + + + + Export &Filter: + + + + Station ID: + + + + Cart Number Parameters: + + + + Use Leading Zeros + + + + Digits: + + + + Station Type: + + + + Lines per Page: + + + + Ser&vice Name: + + + + Station &Format: + + + + Linux Export Path: + + + + Windows Export Path: + + + + Export Event Types: + + + + Traffic + + + + Music + + + + All + + + + Export Events From: + + + + Traffic Log + + + + Music Log + + + + No + + + + Yes + + + + Include Only OnAir Events: + + + + Available Services + + + + Source Services + + + + Available Hosts + + + + Source Hosts + + + + &OK + + + + &Cancel + + + + Available Groups + + + + Allowed Groups + + + + Filter by Groups + + + + Filter by Daypart + + + + Start Time: + + + + End Time: + + + + + EditSettings + + System-Wide Settings + + + + System Sample Rate: + + + + samples/second + + + + Allow Duplicate Cart Titles + + + + ISCI Cross Reference Path: + + + + Maximum Remote Post Length: + + + + Mbytes + + + + The following duplicate titles must be corrected before "Allow Duplicate Values" can be turned off. + + + + CART + + + + TITLE + + + + &Save List + + + + &OK + + + + &Cancel + + + + File Exists + + + + The file " + + + + " exists. + +Overwrite? + + + + File Error + + + + Checking the Library for duplicates. + + + + Temporary Cart Group: + + + + + EditStation + + Host: + + + + Ho&st Name: + + + + &Description: + + + + Default &User: + + + + &IP Address: + + + + Editor &Command: + + + + mS + + + + &Time Offset: + + + + &Startup Cart: + + + + Select + + + + Enable Heartbeat + + + + Use Realtime Filtering + + + + Cart: + + + + Interval: + + + + secs + + + + RD&Library + + + + RDCatch + + + + RDAirPlay + + + + RDPanel + + + + RDLogEdit + + + + Dropboxes + + + + Audio +Resources + + + + Audio +Ports + + + + Serial +Ports + + + + Switchers +GPIO + + + + Host +Variables + + + + Backups + + + + &OK + + + + &Cancel + + + + Invalid Address + + + + The specified IP address is invalid! + + + + Invalid Cart + + + + The Heartbeat Cart number is invalid! + + + + Security Model: + + + + Host + + + + User + + + + Include in System Maintenance Pool + + + + System Maintenance + + + + At least one host must belong to the system maintenance pool! + + + + HTTP Xport: + + + + Core Audio Engine: + + + + System Services + + + + JACK +Settings + + + + RDCart +Slots + + + + Cue &Output: + + + + RDAdmin - No Audio Configuration Data + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Enable Drag && Drop + + + + Allow Drops on Panels not in Setup Mode + + + + Start Cart + + + + Stop Cart + + + + + EditSvc + + Edit Service + + + + &Service Name: + + + + Service &Description: + + + + [none] + + + + Voicetrack Group: + + + + Insert CHAIN TO at log end + + + + Enable AutoRefresh By Default + + + + Configure +&Autofill Carts + + + + Enable &Hosts + + + + Traffic Data Import + + + + Linux Import Path: + + + + Windows Import Path: + + + + Note Cart String: + + + + Insert Voice Track String: + + + + Test +&Traffic + + + + Music Data Import + + + + Insert Traffic Break String: + + + + Test +&Music + + + + &OK + + + + &Cancel + + + + Save Import Data + + + + Before testing, the import configuration +must be saved. Save now? + + + + Purge ELR Data after + + + + days + + + + Purge Logs after + + + + Import Template: + + + + [custom] + + + + Linux Preimport Command: + + + + Windows Preimport Command: + + + + &Program Code: + + + + AutoSpot Group: + + + + Log Name &Template: + + + + Log &Description Template: + + + + + EditSvcPerms + + Service: + + + + Available Hosts + + + + Enabled Hosts + + + + &OK + + + + &Cancel + + + + + EditTtys + + Edit TTYs + + + + Port ID: + + + + Enabled + + + + TTY Device: + + + + Baud Rate: + + + + Parity: + + + + Data Bits: + + + + Stop Bits: + + + + Terminator: + + + + &Close + + + + Serial + + + + None + + + + Even + + + + Odd + + + + CR + + + + LF + + + + CR/LF + + + + + EditUser + + User: + + + + &User Name: + + + + &Full Name: + + + + &Description: + + + + &Phone: + + + + Allow Web Logins + + + + Change +&Password + + + + Administrative Rights + + + + Administer S&ystem + + + + Production Rights + + + + &Create Carts + + + + &Delete Carts + + + + &Modify Carts + + + + &Edit Audio + + + + &Edit Netcatch Schedule + + + + &Voicetrack Logs + + + + Traffic Rights + + + + Create &Log + + + + De&lete Log + + + + Delete &Report Data + + + + &Modify Template + + + + OnAir Rights + + + + &Playout Logs + + + + &Rearrange Log Items + + + + Add Log &Items + + + + Delete Lo&g Items + + + + Configure System Panels + + + + Podcasting Rights + + + + Cre&ate Podcast + + + + E&dit Podcast + + + + Dele&te Podcast + + + + Assign Group +Permissions + + + + Assign Podcast Feed +Permissions + + + + &OK + + + + &Cancel + + + + + EditUserPerms + + User: + + + + Available Groups + + + + Enabled Groups + + + + &OK + + + + &Cancel + + + + + EditVguestResource + + Engine (Hex): + + + + Device (Hex): + + + + Surface (Hex): + + + + Bus/Relay (Hex): + + + + &OK + + + + &Cancel + + + + Edit vGuest Switch + + + + Edit vGuest Display + + + + Invalid Number + + + + The Engine Number is Invalid! + + + + The Device Number is Invalid! + + + + The Surface Number is Invalid! + + + + The Bus/Relay Number is Invalid! + + + + + InfoDialog + + System Information + + + + Rivendell + + + + A Radio Automation System + + + + Version + + + + Database Schema + + + + This program is free software, and comes with ABSOLUTELY NO WARRANTY, +not even the implied warranties of MERCHANTIBILITY or FITNESS FOR A +PARTICULAR PURPOSE. Touch the "View License" button for details. + + + + View +&License + + + + &Close + + + + Copyright 2002-2014 + + + + + ListAuxFields + + Auxiliary Metadata Fields + + + + Var Name + + + + Caption + + + + &Add + + + + &Edit + + + + &Delete + + + + &Close + + + + Warning + + + + This will delete all data associated with this field! +Are you sure you want to continue? + + + + + ListDropboxes + + &Add + + + + &Edit + + + + &Delete + + + + &Close + + + + Group + + + + Path + + + + Normalization Level + + + + Autotrim Level + + + + To Cart + + + + Use CartChunk ID + + + + Delete Cuts + + + + Metadata Pattern + + + + Fix Broken Formats + + + + [off] + + + + [auto] + + + + [none] + + + + User Defined + + + + + ListEncoders + + RDAdmin - List Encoders + + + + Format Name + + + + Valid Channels + + + + Valid Sample Rates + + + + Valid Bit Rates + + + + &Edit + + + + &Close + + + + [none] + + + + &Add + + + + &Delete + + + + RDAdmin - Delete Encoder + + + + Are you sure you want to delete this encoder? + + + + Extension + + + + This encoder is in use by the following RSS feeds: + + + + + + + +Do you still want to delete it? + + + + Encoders on + + + + + ListEndpoints + + List Inputs + + + + List Outputs + + + + INPUT + + + + OUTPUT + + + + LABEL + + + + SOURCE + + + + MODE + + + + ENGINE (Hex) + + + + DEVICE (Hex) + + + + PROVIDER ID + + + + SERVICE ID + + + + NODE + + + + # + + + + &Edit + + + + &OK + + + + &Cancel + + + + Stereo + + + + Left + + + + Right + + + + Input + + + + Output + + + + stereo + + + + left + + + + right + + + + + ListFeeds + + Rivendell Feed List + + + + &Add + + + + &Edit + + + + &Delete + + + + &Close + + + + Key + + + + Title + + + + AutoPost + + + + Keep Metadata + + + + Creation Date + + + + &Feeds: + + + + Are you sure you want to delete feed + + + + Delete Feed + + + + Deleting Audio... + + + + Cancel + + + + Deleting + + + + + ListGpis + + List GPIs + + + + GPI Lines + + + + GPI + + + + &Edit + + + + &OK + + + + &Cancel + + + + [unassigned] + + + + GPO + + + + List GPOs + + + + GPO Lines + + + + ON MACRO CART + + + + ON DESCRIPTION + + + + OFF MACRO CART + + + + OFF DESCRIPTION + + + + + ListGroups + + Rivendell Group List + + + + &Add + + + + &Edit + + + + &Rename + + + + &Delete + + + + Generate +&Report + + + + &Close + + + + NAME + + + + DESCRIPTION + + + + START CART + + + + END CART + + + + ENFORCE RANGE + + + + DEFAULT TYPE + + + + TRAFFIC REPORT + + + + MUSIC REPORT + + + + NOW & NEXT + + + + &Groups: + + + + member carts will be deleted along with group + + + + Are you sure you want to delete group + + + + Delete Group + + + + + ListHostvars + + Host Variables for + + + + Host Variables + + + + NAME + + + + VALUE + + + + REMARK + + + + &Add + + + + &Edit + + + + &Delete + + + + &OK + + + + &Cancel + + + + + ListLiveWireGpios + + LiveWire GPIO Source Assignments + + + + Switchers: + + + + &Edit + + + + &OK + + + + &Cancel + + + + [none] + + + + Lines + + + + Surface Address + + + + [all] + + + + Source # + + + + + ListMatrices + + Rivendell Switcher List + + + + Switchers: + + + + MATRIX + + + + DESCRIPTION + + + + TYPE + + + + &Add + + + + &Edit + + + + &Delete + + + + &Close + + + + Are you sure you want to delete switcher + + + + on + + + + ALL references to this switcher will be deleted! + + + + Deleting Switcher + + + + + ListReplicatorCarts + + &Repost + + + + Repost +&All + + + + &Close + + + + CART + + + + TITLE + + + + LAST POSTED + + + + &Active Carts: + + + + Replicator Carts + + + + POSTED FILENAME + + + + + ListReplicators + + Rivendell Replicators + + + + &Add + + + + &Edit + + + + &Delete + + + + &List +Carts + + + + &Close + + + + NAME + + + + TYPE + + + + DESCRIPTION + + + + HOST + + + + &Replicators: + + + + Are you sure you want to delete replicator + + + + Delete Replicator + + + + + ListReports + + Rivendell Report List + + + + &Add + + + + &Edit + + + + &Delete + + + + &Close + + + + R&eports: + + + + Are you sure you want to delete report + + + + Delete Report + + + + + ListStations + + Rivendell Workstation List + + + + &Add + + + + &Edit + + + + &Delete + + + + &Close + + + + Ho&sts: + + + + Are you sure you want to delete host + + + + Delete Station + + + + + ListSvcs + + Services + + + + &Add + + + + &Edit + + + + &Delete + + + + &Close + + + + &Services: + + + + Are you sure you want to delete service + + + + Delete Service + + + + There are + + + + logs owned by this service that will also be deleted. +Do you still want to proceed? + + + + Logs Exist + + + + + ListUsers + + Rivendell User List + + + + &Add + + + + &Edit + + + + &Delete + + + + &Close + + + + &Users: + + + + DESCRIPTION + + + + USER NAME + + + + FULL NAME + + + + Are you sure you want to delete user + + + + Delete User + + + + You must change this before deleting the user. + + + + This user is set as the default user for the following hosts: + + + + + + You cannot delete yourself! + + + + + Login + + Login + + + + &OK + + + + &Cancel + + + + User &Name: + + + + &Password: + + + + + MainWidget + + Daemons Failed + + + + Unable to start Rivendell System Daemons! + + + + Insufficient Priviledges + + + + This account has insufficient priviledges for this operation. + + + + Manage +&Users + + + + Manage +&Groups + + + + Manage +&Services + + + + Manage +Ho&sts + + + + Manage +R&eports + + + + Manage +&Feeds + + + + System +Info + + + + Scheduler +Codes + + + + &Backup +Database + + + + &Restore +Database + + + + &Quit + + + + Rivendell Database Backup (*.sql) + + + + Backup Error + + + + Unable to create backup! + + + + Backup Complete + + + + Backup completed successfully. + + + + Restore Database + + + + WARNING: This operation will COMPLETELY +OVERWRITE the existing Rivendell Database! +Do you want to continue? + + + + Restore Error + + + + Unable to restore backup! + + + + Restore Complete + + + + Restore completed successfully. + + + + System +Settings + + + + Manage +Replicators + + + + RDAdmin + + + + + MySqlLogin + + mySQL Admin + + + + User &Name: + + + + &Password: + + + + &OK + + + + &Cancel + + + + + QObject + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + + + + Wrong access permissions for accessing mySQL! + + + + Unable to connect to mySQL! + + + + Unable to create a Rivendell Database! + + + + Unable to connect to new Rivendell Database! + + + + Unable to create Rivendell Database! + + + + Unable to connect to Rivendell Database! + + + + Unable to initialize Rivendell Database! + + + + RDAdmin + + + + New Rivendell Database Created! + + + + Unable to upgrade database + + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + + + + Unable to log into Administrator account! + + + + Unable to authorize a Rivendell Database! + + + + Update Needed + + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + + + + Unable to update Rivendell Database: + + + + +Database backup failed! + + + + +Schema modification failed! + + + + +Unknown/unspecified error! + + + + The Rivendell Database has been updated to version + + + + +and a backup of the original database saved in + + + + Database Updated + + + + RDAdmin Error + + + + (default) + + + + Start Line 1 + + + + Stop Line 1 + + + + Pause Line 1 + + + + Start Line 2 + + + + Stop Line 2 + + + + Pause Line 2 + + + + Start Line 3 + + + + Stop Line 3 + + + + Pause Line 3 + + + + Start Line 4 + + + + Stop Line 4 + + + + Pause Line 4 + + + + Start Line 5 + + + + Stop Line 5 + + + + Pause Line 5 + + + + Start Line 6 + + + + Stop Line 6 + + + + Pause Line 6 + + + + Start Line 7 + + + + Stop Line 7 + + + + Pause Line 7 + + + + Add + + + + Delete + + + + Copy + + + + Move + + + + Sound Panel + + + + Main Log + + + + Aux Log 1 + + + + Aux Log 2 + + + + + RenameGroup + + Rename Group + + + + Current Group Name: + + + + New &Group Name: + + + + &OK + + + + &Cancel + + + + Invalid Group + + + + The group name is invalid! + + + + A + + + + group already exists. +Do you want to combine the two? + + + + Group Exists + + + + + TestImport + + Test Traffic Import + + + + Test Music Import + + + + Test Date: + + + + &Select + + + + &Import + + + + Using source file: + + + + Start Time + + + + Cart + + + + Len + + + + Title + + + + Contract # + + + + Event ID + + + + Announcement Type + + + + Imported Events + + + + &Close + + + + Import Error + + + + There was an error during import +please check your settings and try again. + + + + [spot break] + + + + + ViewAdapters + + Audio Resource Information + + + + Audio Resources on + + + + SUPPORTED AUDIO DRIVERS + + + + + SUPPORTED IMPORT FORMATS + + + + + PCM16 Linear + + + + + MPEG Layer 1 + + + + + MPEG Layer 2 + + + + + MPEG Layer 3 + + + + + OggVorbis + + + + + SUPPORTED EXPORT FORMATS + + + + + Free Lossless Audio Codec (FLAC) + + + + + AUDIO ADAPTERS + + + + + Card + + + + Not present + + + + Driver: AudioScience HPI + + + + + Driver: JACK Audio Connection Kit + + + + + Driver: Advanced Linux Sound Architecture (ALSA) + + + + + Driver: UNKNOWN + + + + + Inputs: + + + + Outputs: + + + + NO DATA AVAILABLE + + + + + + Please start the Rivendell daemons on this host (by executing, as user 'root', the command "/etc/init.d/rivendell start") in order to populate the audio resources database. + + + + &Close + + + + diff --git a/rdadmin/rdadmin_nb.ts b/rdadmin/rdadmin_nb.ts new file mode 100644 index 00000000..b1742c2a --- /dev/null +++ b/rdadmin/rdadmin_nb.ts @@ -0,0 +1,5823 @@ + + + @default + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + Greier ikkje kopla til Rivendell-databasen! +Skriv inn eit brukarnamn til ein konto som har +rettar til å administrera mySQL-tenaren, +så prøver me å ordna opp i dette. + + + Can't Connect + Kan ikkje kopla til + + + Wrong access permissions for accessing mySQL! + Feil tilgangsrettar for å kopla til mySQL! + + + Unable to connect to mySQL! + Greier ikkje kopla til mySQL! + + + Can't Create DB + Greier ikkje laga database + + + Unable to create a Rivendell Database! + Greier ikkje laga ein Rivendell-database! + + + Unable to connect to new Rivendell Database! + Greier ikkje kopla til den nye Rivendell-databasen! + + + Can't Create + Greier ikkje laga + + + Unable to create Rivendell Database! + Greier ikkje laga ein Rivendell-database! + + + Unable to connect to Rivendell Database! + Greier ikkje kopla til Rivendell-databasen! + + + Can't Initialize + Greier ikkje setja opp + + + Unable to initialize Rivendell Database! + Greier ikkje setja opp Rivendell-databasen! + + + Created Database + Laga database + + + New Rivendell Database Created! + Du har laga ein ny Rivendell-database. + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + Rivendell-databasen er for gamal til å oppgradera, +så han må bytast ut. Dette VIL ØYDELEGGJA alle +lyd- og datafiler! Viss du vil gjera dette, skriv du inn +eit brukarnamn og passord med administrasjons- +rettar for mySQL-kontoen. Viss ikkje, trykk avbryt. + + + Unable to log into Administrator account! + Greier ikkje logga på Administrator-kontoen! + + + Unable to authorize a Rivendell Database! + Greier ikkje godkjenna Rivendell-databasen! + + + Update Needed + Treng oppdatering + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + Rivendell-databasen treng ei oppdatering. +Alle lydfiler og innstillingar blir tekne vare på, +men dette VIL STOPPA alt opptak eller avspeling +på denne maskina i nokre sekund. Halda fram? + + + Can't Update + Greier ikkje oppdatera + + + Unable to update Rivendell Database! + Greidde ikkje oppdatera Rivendell-databasen! + + + The Rivendell Database has +been updated to Version + Rivendell-databasen er +oppdatert til versjon + + + Database Updated + Databasen oppdatert + + + + AddAuxField + + Add Aux Field + + + + Variable Name: + + + + %AUX_ + + + + % + + + + Caption: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Name Exists + + + + That variable name already exists! + + + + + AddEncoder + + Add Encoder + + + + &New Encoder Name: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Add Encoder Error + + + + A encoder with that name already exists! + + + + + AddFeed + + Add Feed + + + + Enable Feed for All Users + + + + &New Feed Name: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Add Feed Error + + + + A feed with that key name already exists! + + + + + AddGroup + + Add Group + Legg til gruppe + + + &New Group Name: + &Nytt gruppenamn: + + + Enable Group for All Users + Skru på gruppa for alle brukarar + + + Enable Group for All Services + Skru på gruppa for alle tenester + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Name + Ugyldig namn + + + You must give the group a name! + Du må gje gruppa eit namn! + + + Group Exists + Gruppa finst + + + Group Already Exists! + Gruppa finst alt! + + + + AddHostvar + + Add Host Variable + Legg til tenarvariabel + + + Variable Name: + Namn på variabelen: + + + Variable Value: + Variabelverdi: + + + Remark: + Merknad: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Name + Ugyldig namn + + + The variable name is invalid. + + + + + AddMatrix + + Add Switcher + Legg til bytar + + + &New Matrix Number: + &Nytt matrisenummer: + + + Local GPIO + Lokal Generell inn/ut + + + Generic GPO + Vanleg Generell ut + + + Generic Serial + Vanleg seriell + + + Local Audio Adapter + Lokalt lydkort + + + Logitek vGuest + Logitek vGuest + + + BroadcastTools SS16.4 + BroadcastTools SS16.4 + + + StarGuide III + StarGuide III + + + BroadcastTools SS4.2 + BroadcastTools SS4.2 + + + Axia LiveWire + Axia LiveWire + + + Quartz Type 1 + Quartz type 1 + + + &Switcher Type: + &Bytar-type: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Matrix + Ugyldig matrise + + + Matrix already exists! + Matrisen finst frå før! + + + BroadcastTools SS4.4 + BroadcastTools SS4.4 + + + New Switcher + + + + RDAdmin - Add Switcher + + + + + AddReplicator + + Add Replicator + + + + &New Replicator Name: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Name + Ugyldig namn + + + You must give the replicator a name! + + + + Replicator Exists + + + + A replicator with that name already exists! + + + + + AddReport + + Add Report + Legg til rapport + + + &Report Name: + &Namn på rapporten: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Name + Ugyldig namn + + + You must provide a report name! + Du må skriva inn eit namn på rapporten! + + + Report Exists + Rapporten finst + + + A report with that name already exists! + Det finst alt ein rapport med dette namnet! + + + + AddStation + + Add Host + Legg til vert + + + New &Host Name: + Nytt &Vertsnamn: + + + Base Host On: + Grunnvert på: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Empty Host Config + Tomt vertsoppsett + + + Invalid Name + Ugyldig namn + + + You must give the host a name! + Du må gje verten eit namn! + + + Host Exists + Verten eksisterer + + + Host Already Exists! + Verten finst frå før! + + + + AddSvc + + Add Service + Legg til teneste + + + &New Service Name: + &Nytt tenestenamn: + + + Base Service On: + Hovudtenest på: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Empty Host Config + Tomt vertsoppsett + + + Invalid Name + Ugyldig namn + + + You must give the service a name! + Du må gje tenesta eit namn! + + + Service Exists + Tenesta eksisterer + + + Service Already Exists! + Tenesta finst frå før! + + + + AddUser + + Add User + Legg til brukar + + + &New User Name: + &Nytt brukarnamn: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Name + Ugyldig namn + + + You must give the user a name! + Du må gje brukaren eit namn! + + + User Exists + Brukaren eksisterer + + + User Already Exists! + Brukaren finst frå før! + + + + AutofillCarts + + Autofill Carts - Service: + Tenest for å autofylla korger: + + + Cart + Korg + + + Length + Lengd + + + Title + Tittel + + + Artist + Artist + + + &Add + &Legg til + + + &Delete + &Slett + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditAudioPorts + + Edit Audio Ports + Rediger lydportar + + + Clock Source: + Klokkekjelde: + + + Input Port + Inngangsport + + + Analog + Analog + + + AES/EBU + AES/EBU + + + SP/DIFF + SP/DIFF + + + Type: + Type: + + + Normal + Normal + + + Swap + Byt om + + + Left only + Berre venstre + + + Right only + Berre høgre + + + Mode: + Modus: + + + dB + dB + + + Level: + Nivå: + + + Output Port + Utgangsport + + + &Help + &Hjelp + + + &Close + &Lukk + + + Internal + Intern + + + AES/EBU Signal + AES/EBU-signal + + + SP/DIFF Signal + SP/DIFF-signal + + + Word Clock + Ordklokke + + + Card: + Kort: + + + Card Driver: + + + + Ref. Level: + + + + + EditAuxField + + Edit Auxiliary Metadata Fields + + + + Variable Name: + + + + Caption: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditBackup + + Backup config for + Sikringskopi-oppsett for + + + Keep Backups For: + Lagra sikringskopiar i: + + + days + dagar + + + Backup Directory: + Mappe for sikringskopiar: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Path Missing + Manglar stig + + + You must supply a backup path! + Du må velja ein stig til sikringskopi-mappa! + + + + EditCartSlots + + RDAdmin - Edit CartSlots + + + + Close + + + + None + Ingen + + + Output Port: + + + + Card: + Kort: + + + Input Port: + + + + Cart + Korg + + + Mode: + Modus: + + + Cart: + Korg: + + + At Playout End: + + + + Channel Assignments + Kanaltilkoplingar + + + Default Settings + + + + Select + Vel + + + Load Specified Cart + + + + At Startup: + Ved oppstart: + + + Do Nothing + + + + Slot Mode: + + + + Full + + + + Hook + + + + Play Mode: + + + + User previous mode + + + + Use previous mode + + + + Use previous cart + + + + Use previous action + + + + Service: + + + + Global Settings + + + + Slot Columns: + + + + Slot Rows: + + + + Slot + + + + Settings + Innstillingar + + + Slot selected has changed! + + + + + EditDecks + + Configure RDCatch + Set opp RDCatch + + + Record Deck + Opptak + + + None + Ingen + + + Monitor Port: + Lytteport: + + + Off + Av + + + On + + + + Monitor defaults to + Lyttinga går automatisk til + + + Format: + Format: + + + Sample Rate: + Punktprøverate: + + + Bit Rate: + Bitrate: + + + Switcher Host: + Svitsjar-vert: + + + Switcher Matrix: + Svitsjar-matrise: + + + Switcher Output: + Svitsjar-utgang: + + + Switcher Delay: + Svitsjar-seinking: + + + 1/10 sec + 1/10 sek + + + Channels: + Kanalar: + + + Trim Threshold: + Trimmeterskel: + + + Error RML: + Feil RML: + + + Play Deck + Spel + + + Audition Deck + Lytt + + + &Close + &Lukk + + + No Audio Configuration Data + Ingen data for lydoppsett + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Det vil ikkje vera tilgjengelege kanalar for denne verten, fordi det ikkje har vorte laga +data for lydressursar enno. Start Rivendell-programma på denne verten ved å køyra +kommandoen "/etc/init.d/rivendell-start" som root-brukaren for å fylla ut databasen +for lydressursar. + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG lag 2 + + + 32 kbps/chan + 32 kbps/kanal + + + 48 kbps/chan + 48 kbps/kanal + + + 56 kbps/chan + 56 kbps/kanal + + + 64 kbps/chan + 64 kbps/kanal + + + 80 kbps/chan + 80 kbps/kanal + + + 96 kbps/chan + 96 kbps/kanal + + + 112 kbps/chan + 112 kbps/kanal + + + 128 kbps/chan + 128 kbps/kanal + + + 160 kbps/chan + 160 kbps/kanal + + + 192 kbps/chan + 192 kbps/kanal + + + [none] + [ingen] + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Settings + Innstillingar + + + Defaults + Standard + + + Host-Wide Settings + + + + + EditDropbox + + Dropbox Configuration + + + + Default Group: + + + + &Path Spec: + + + + Select + Vel + + + To &Cart: + + + + Delete cuts before importing + + + + &Metadata Pattern: + + + + &Log File: + + + + Delete source files after import + + + + Normalize Levels + + + + Level: + Nivå: + + + dBFS + + + + Autotrim Cuts + + + + Get cart number from CartChunk CutID + + + + Get cart title from CartChunk CutID + + + + Attempt to work around malformatted input files + + + + Offset start date by + + + + days + dagar + + + Offset end date by + + + + Create Dates when no Dates Exist + + + + Create start date offset: + + + + Create end date offset: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Offsets + + + + The Create EndDate Offset is less than the Create Start Date Offset! + + + + &User Defined: + + + + Scheduler Codes + + + + + EditEncoder + + RDAdmin - Edit Encoder + + + + Name: + + + + Allow Channels + + + + Allow Sample Rates + + + + Allow Bit Rates + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Default Extension: + + + + Command Line: + + + + + EditEndpoint + + Edit Input + Rediger inngang + + + Edit Output + Rediger utgang + + + Name: + Namn: + + + Feed: + Straum: + + + Mode: + Modus: + + + Stereo + Stereo + + + Left + Venstre + + + Right + Høgre + + + Engine (Hex): + Maskin (heksadesimal): + + + Provider ID: + Tilbydar-ID: + + + Device (Hex): + Eining (heksadesimal): + + + Service ID: + Tenest-ID: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Number + Ugyldig nummer + + + The Engine Number is Invalid! + Ugyldig nummer! + + + The Provider ID is Invalid! + Tilbydar-ID-en er ugyldig! + + + The Device Number is Invalid! + Einingsnummeret er ugyldig! + + + The Service ID is Invalid! + Tenest-ID-en er ugyldig! + + + + EditFeed + + Feed: + Straum: + + + Key Name: + + + + CHANNEL VALUES + + + + Title: + Tittel: + + + Category: + + + + Link: + + + + Copyright: + + + + Webmaster: + + + + Language: + + + + Description: + Skildring: + + + Audio Upload URL: + + + + Username: + Brukarnamn: + + + Password: + Passord: + + + Upload Format: + + + + S&et + + + + Normalize + + + + Level: + Nivå: + + + dBFS + + + + Audio Download URL: + + + + Keep Expired Metadata + + + + Enable AutoPost + + + + Enclosure Preamble: + + + + Audio Extension: + + + + None + Ingen + + + Maximum Shelf Life: + + + + days + dagar + + + Descending + + + + Ascending + + + + Episode Sort Order: + + + + Direct + + + + Counted + + + + Media Link Mode: + + + + Enable Feed Redirection + + + + URL: + + + + Header XML: + + + + Channel XML: + + + + Item XML: + + + + &Define Auxiliary +Metadata Fields + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Edit Feed - Redirect + + + + Enabling feed redirection will cause clients subscribed to +this feed to be PERMANENTLY redirected to the +specified URL. + +Do you still want to enable redireciton? + + + + + EditFeedPerms + + User: + Brukar: + + + Available Feeds + + + + Enabled Feeds + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditGpi + + Edit GPI + Rediger generell inngang + + + GPI: + Generell inngang: + + + Description: + Skildring: + + + Cart Number: + Korgnummer: + + + &Select + &Vel + + + C&lear + &Tøm + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Cart + Ugyldig korg + + + Invalid Cart Number! + Ugyldig korgnummer! + + + + EditGroup + + Group: + Gruppe: + + + &Group Name: + &Gruppenamn: + + + Group &Description: + Gruppe&skildring: + + + Audio + Lyd + + + Macro + Makro + + + Default Cart &Type: + Standard korg&type: + + + None + Ingen + + + Default Cart Number: + Standard korgnummer: + + + to + til + + + Enforce Cart Range + Tving korgområde + + + Include this group in Traffic reports + Legg til denne gruppa i trafikkrapportar + + + Include this group in Music reports + Legg til denne gruppa i musikkrapportar + + + Transmit Now && Next data + Send no && Neste data + + + C&olor + F&arge + + + &OK + &OK + + + &Cancel + &Avbryt + + + The selected cart range conflicts with the following groups: + + + Det valde korgområdet stemmer ikkje med desse gruppene: + + + + + +Do you still want to save? + +Vil du framleis lagra? + + + Default Import &Title: + + + + Purge expired cuts after + + + + days + dagar + + + Delete cart if empty + + + + + EditHostvar + + Edit Host Variable + Rediger vertsvarliabe + + + Variable Name: + Variabelnamn: + + + Variable Value: + Variabelverdi: + + + Remark: + Merknad: + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditHotkeys + + Host Hot Key Configurations + + + + Button / Function + + + + KeyStroke + + + + Set + + + + Clear + + + + Clear All Hotkeys + + + + Set From Host: + + + + Save + + + + Cancel + + + + Duplicate Entries + + + + Hotkeys Clear + + + + Hotkeys Updated + + + + No Items Selected + + + + Please Select an Item From the List + + + + Hot Key Configuration for + + + + + EditJack + + JACK Configuration for + + + + Start JACK Server + + + + JACK Server Name: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + JACK Command Line: + + + + NAME + NAMN + + + VALUE + VERDI + + + REMARK + MERKNAD + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + JACK Clients to Start: + + + + Client + + + + Command Line + + + + [New Client] + + + + RDAdmin - JACK Clients + + + + Are you sure you want to delete JACK Client + + + + + EditJackClient + + JACK Client Configuration for + + + + Description: + Skildring: + + + Command Line: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditLiveWireGpio + + None + Ingen + + + &OK + &OK + + + &Cancel + &Avbryt + + + Edit GPIO Source + + + + Livewire Source: + + + + GPIO Lines + + + + Surface Address: + + + + Invalid IP Address + + + + The IP address is invalid! + + + + + EditMatrix + + Edit Switcher + Rediger svitsjar + + + Matrix Number: + Matrisenummer: + + + Switcher Type: + Svitsjartype: + + + Description: + Skildring: + + + Primary Connection + Hovudtilkopling + + + Type: + Type: + + + Serial + Seriell + + + TCP/IP + TCP/IP + + + Serial Port: + Seriellport: + + + IP Address: + IP-adresse: + + + IP Port: + IP-port: + + + Username: + Brukarnamn: + + + Password: + Passord: + + + Backup Connection + Sikringstilkopling + + + None + Ingen + + + Card: + Kort: + + + Inputs: + Inngangar: + + + Outputs: + Utgangar: + + + Device: + Eining: + + + GPIs: + Generelle inngangar: + + + GPOs: + Generelle utgangar: + + + Layer: + Lag: + + + Displays: + Skjermar: + + + Configure +&Inputs + Set opp +&inngangar + + + Configure +&Outputs + Set opp +&utgangar + + + Configure +&Xpoints + Set opp +&Xpunkt + + + Configure +GP&Is + Set opp +G&I-ar + + + LiveWire +Nodes + LiveWire- +nodar + + + vGuest +Switches + vGuest- +svitsjar + + + vGuest +Displays + vGuest- +visingar + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Address + Ugyldig adresse + + + The primary IP address is invalid! + Hovud-IP-adressa er ugyldig! + + + The backup IP address is invalid! + Sikrings-IP-adressa er ugyldig! + + + Duplicate Connections + Dublett-tilkoplingar + + + The primary and backup connections must be different! + Hovud- og sikringstilkoplingane må vera ulike! + + + Startup Cart: + + + + Select + Vel + + + Shutdown Cart: + + + + Configure +&GPIs + + + + Configure +G&POs + + + + SAS +Switches + + + + RDAdmin - Edit Switcher + + + + LiveWire +GPIOs + + + + + EditNowNext + + Edit Now & Next Data + Rediger no & neste data + + + Master Log + Hovudlogg + + + IP Address: + IP-adresse: + + + UDP Port: + UDP-port: + + + UDP String: + UDP-streng: + + + RML: + RMS: + + + Aux Log 1 + Hjelpelogg 1 + + + &OK + &OK + + + &Cancel + &Avbryt + + + The IP address + IP-adressa + + + is invalid! + er ugyldig! + + + Invalid Address + Ugyldig adresse + + + Default Now Cart: + + + + Select + Vel + + + Default Next Cart: + + + + Path + + + + Argument + + + + Loadable Modules: + + + + Add + + + + Edit + + + + Delete + + + + Aux Log 2 + Hjelpelogg 2 + + + + EditNowNextPlugin + + Edit Plugin + + + + Plugin Path: + + + + Select + Vel + + + Argument: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Select plugin + + + + + EditRDAirPlay + + RDAirPlay config for + RDAirPlay-oppsett for + + + Channel Assignments + Kanaltilkoplingar + + + Main Log Output 1 + Hovudlogg-utgang 1 + + + Start RML: + Start RML: + + + Stop RML: + Slutt-RML: + + + Main Log Output 2 + Hovudloggutgang 2 + + + Aux Log 1 Output + Hjelpelogg 1-utgang + + + Aux Log 2 Output + Hjelpelogg 2-utgang + + + Audition/Cue Output + Lytting/cue-utgang + + + SoundPanel First Play Output + Fyrste spelutgang for Lydpanel + + + SoundPanel Second Play Output + Andre speleutgang for lydpanelet + + + SoundPanel Third Play Output + Tredje speleutgang for lydpanelet + + + SoundPanel Fourth Play Output + Fjerde speleutgang for lydpanelet + + + SoundPanel Fifth and Later Play Output + Femte og høgare speleutgangar for lydpanelet + + + Manual Segue: + Manuell overgang: + + + msecs + msek + + + Forced Segue: + Tvungen overgang: + + + Pie Counts Last: + Urskivenedtellinga varar: + + + secs + sek + + + Pie Counts To: + Urskiva teller til: + + + Cart End + Slutten på korga + + + Transition + Overtoning + + + Default Trans. Type: + Standard overtoningstype: + + + Play + Spel + + + Segue + Overgang + + + Stop + Stopp + + + Overlap + Overlapp + + + Default Service: + Standardtenest: + + + Sound Panel Settings + Lydpaneloppsett + + + None + Ingen + + + Host Panels: + Vertspanel: + + + User Panels: + Brukarpanel: + + + Flash Active Buttons + Aktive knappar blinkar + + + Enable Button Pausing + Skru på pause med knapp + + + Label Template: + Merkemal: + + + Miscellaneous Settings + Ymse innstillingar + + + Startup Mode: + Oppstartsmåte: + + + Previous + Førre + + + LiveAssist + Live-hjelp + + + Automatic + Automatisk + + + Manual + Manuelt + + + Check TimeSync + Sjekk tidssynk + + + Show Auxlog 1 Button + Vis hjelpelogg 1-knappen + + + Show Auxlog 2 Button + Vis hjelpelogg 2-knappen + + + Clear Cart Search Filter + Tøm korgsøkjefilteret + + + Enable Paused Events + Set igang pausa hendingar + + + Space Bar Action + Kva mellomromstasten gjer + + + Start Next + Start neste + + + Configure Now && Next +Parameters + Set opp no && Neste +parametrar + + + Start/Stop Settings + Start/stopp-oppsett + + + Exit Password: + Passord for å lukka: + + + Main Log + Hovudlogg + + + start with empty log + start med tom logg + + + load previous log + last førre loggen + + + load specified log + last oppgjeven logg + + + At Startup: + Ved oppstart: + + + Restart Log After Unclean Shutdown + Start omatt loggen etter feil avslutting + + + Log: + Logg: + + + &Select + &Vel + + + &OK + &OK + + + &Cancel + &Avbryt + + + No Audio Configuration Data + Ingen data for lydoppsett + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Det vil ikkje vera tilgjengelege kanalar for denne verten, fordi det ikkje har vorte laga +data for lydressursar enno. Start Rivendell-programma på denne verten ved å køyra +kommandoen "/etc/init.d/rivendell-start" som root-brukaren for å fylla ut databasen +for lydressursar. + + + [none] + [ingen] + + + Data Error + Datafeil + + + Invalid Segue Length! + Ugyldig lengd på overgangen! + + + Invalid Forced Segue Length! + Ugyldig lengd på den tvungne overgangen! + + + Show Extra Buttons/Counters + + + + Audition Preroll: + + + + Display Settings + + + + Background Image: + + + + Select + Vel + + + Select Image File + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Configure Hot Keys + + + + Show Hour Selector + + + + Edit +GPIOs + + + + Title Template: + + + + Artist Template: + + + + Outcue Template: + + + + Description Template: + + + + Log Mode Control + + + + Mode Control Style: + + + + Unified + + + + Independent + + + + Main Log Startup Mode: + + + + Aux 1 Log Startup Mode: + + + + Aux 2 Log Startup Mode: + + + + + EditRDLibrary + + RDLibrary config for + RDBibliotek-oppsett for + + + INPUT + INNGANG + + + OUTPUT + UTGANG + + + Settings + Innstillingar + + + &Max Record Time: + &Maks opptakstid: + + + &VOX Threshold: + &VOX-terskel: + + + dbFS + dBum + + + &AutoTrim Threshold: + &Autotrim-terskel: + + + &Tail Preroll: + &Hale-førrull: + + + milliseconds + millisekund + + + &Ripper Device: + &Eining for uthenting: + + + &Paranoia Level: + &Paranoia-nivå: + + + Ripper Level: + Uthenting-nivå: + + + &FreeDB Server: + &FreeDB-tenar: + + + &Format: + &Format: + + + &Sample Rate: + &Punktprøverate: + + + &Bitrate: + &Bitrate: + + + No + Nei + + + Yes + Ja + + + Allow E&xternal Editing: + Gje høve til ek&stern redigering: + + + Defaults + Standard + + + &Channels: + &Kanalar: + + + Record Mode: + Opptaksmodus: + + + AutoTrim: + Autotrim: + + + &OK + &OK + + + &Cancel + &Avbryt + + + No Audio Configuration Data + Ingen data for lydoppsett + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Det vil ikkje vera tilgjengelege kanalar for denne verten, fordi det ikkje har vorte laga +data for lydressursar enno. Start Rivendell-programma på denne verten ved å køyra +kommandoen "/etc/init.d/rivendell-start" som root-brukaren for å fylla ut databasen +for lydressursar. + + + Normal + Normal + + + Low + Låg + + + None + Ingen + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG lag 2 + + + Manual + Manuelt + + + VOX + VOX + + + 32 kbps/chan + 32 kbps/kanal + + + 48 kbps/chan + 48 kbps/kanal + + + 56 kbps/chan + 56 kbps/kanal + + + 64 kbps/chan + 64 kbps/kanal + + + 80 kbps/chan + 80 kbps/kanal + + + 96 kbps/chan + 96 kbps/kanal + + + 112 kbps/chan + 112 kbps/kanal + + + 128 kbps/chan + 128 kbps/kanal + + + 160 kbps/chan + 160 kbps/kanal + + + 192 kbps/chan + 192 kbps/kanal + + + 40 kbps/chan + 40 kbps/kanal + + + 224 kbps/chan + 224 kbps/kanal + + + 256 kbps/chan + 256 kbps/kanal + + + 320 kbps/chan + 320 kbps/kanal + + + Sample Rate Converter: + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Limit Searches at Startup + + + + Previous + Førre + + + + EditRDLogedit + + RDLogedit config for + + + + INPUT + INNGANG + + + OUTPUT + UTGANG + + + Voice Tracker Settings + + + + &Max Record Time: + &Maks opptakstid: + + + &AutoTrim Threshold: + &Autotrim-terskel: + + + dbFS + dBum + + + &Normalization Level: + + + + &Audio Margin: + + + + milliseconds + millisekund + + + &Format: + &Format: + + + &Bitrate: + &Bitrate: + + + Play &Start Cart: + + + + Select + Vel + + + Play &End Cart: + + + + &Record Start Cart: + + + + Re&cord End Cart: + + + + &Channels: + &Kanalar: + + + Default Transition: + + + + Play + Spel + + + Segue + Overgang + + + Stop + Stopp + + + &OK + &OK + + + &Cancel + &Avbryt + + + No Audio Configuration Data + Ingen data for lydoppsett + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG lag 2 + + + 32 kbps/chan + 32 kbps/kanal + + + 48 kbps/chan + 48 kbps/kanal + + + 56 kbps/chan + 56 kbps/kanal + + + 64 kbps/chan + 64 kbps/kanal + + + 80 kbps/chan + 80 kbps/kanal + + + 96 kbps/chan + 96 kbps/kanal + + + 112 kbps/chan + 112 kbps/kanal + + + 128 kbps/chan + 128 kbps/kanal + + + 160 kbps/chan + 160 kbps/kanal + + + 192 kbps/chan + 192 kbps/kanal + + + 40 kbps/chan + 40 kbps/kanal + + + 224 kbps/chan + 224 kbps/kanal + + + 256 kbps/chan + 256 kbps/kanal + + + 320 kbps/chan + 320 kbps/kanal + + + No + Nei + + + Yes + Ja + + + Enable &2nd Start Button: + + + + + EditRDPanel + + RDPanel config for + + + + Channel Assignments + Kanaltilkoplingar + + + SoundPanel First Play Output + Fyrste spelutgang for Lydpanel + + + Start RML: + Start RML: + + + Stop RML: + Slutt-RML: + + + SoundPanel Second Play Output + Andre speleutgang for lydpanelet + + + SoundPanel Third Play Output + Tredje speleutgang for lydpanelet + + + SoundPanel Fourth Play Output + Fjerde speleutgang for lydpanelet + + + SoundPanel Fifth and Later Play Output + Femte og høgare speleutgangar for lydpanelet + + + SoundPanel Cue Output + + + + Display Settings + + + + Background Image: + + + + Select + Vel + + + Sound Panel Settings + Lydpaneloppsett + + + None + Ingen + + + Host Panels: + Vertspanel: + + + User Panels: + Brukarpanel: + + + Flash Active Buttons + Aktive knappar blinkar + + + Enable Button Pausing + Skru på pause med knapp + + + Clear Cart Search Filter + Tøm korgsøkjefilteret + + + Default Service: + Standardtenest: + + + Label Template: + Merkemal: + + + &OK + &OK + + + &Cancel + &Avbryt + + + No Audio Configuration Data + Ingen data for lydoppsett + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Det vil ikkje vera tilgjengelege kanalar for denne verten, fordi det ikkje har vorte laga +data for lydressursar enno. Start Rivendell-programma på denne verten ved å køyra +kommandoen "/etc/init.d/rivendell-start" som root-brukaren for å fylla ut databasen +for lydressursar. + + + [none] + [ingen] + + + Select Image File + + + + + EditReplicator + + Replicator: + + + + Name: + + + + Description: + Skildring: + + + Type: + Type: + + + Host System: + + + + Audio Upload URL: + + + + Username: + Brukarnamn: + + + Password: + Passord: + + + Upload Format: + + + + S&et + + + + Normalize + + + + Level: + Nivå: + + + dBFS + + + + Available Groups + + + + Active Groups + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditReport + + Edit Report + Rediger rapport + + + &Report Description: + &Rapportskildring: + + + Export &Filter: + Eksport&filter: + + + Station ID: + Stasjons-ID: + + + Cart Number Parameters: + Parametrar for korgnummer: + + + Use Leading Zeros + Bruk nullar føre + + + Digits: + Siffer: + + + Station Type: + Stasjonstype: + + + Lines per Page: + Linjer per side: + + + Ser&vice Name: + &Tenestnamn: + + + Station &Format: + Stasjons&format: + + + Linux Export Path: + Linux-eksportstig: + + + Windows Export Path: + Windows-eksportstig: + + + Export Event Types: + Eksport-handlingstypar: + + + Traffic + Trafikk + + + Music + Musikk + + + All + Alt + + + Export Events From: + Eksporter hendingar frå: + + + Traffic Log + Trafikklogg + + + Music Log + Musikklogg + + + No + Nei + + + Yes + Ja + + + Include Only OnAir Events: + Ta med berre På lufta-hendingar: + + + Available Services + Tilgjengelege tenester + + + Source Services + Kjeldetenester + + + Available Hosts + Tilgjengelege vertar + + + Source Hosts + Kjeldevertar + + + &OK + &OK + + + &Cancel + &Avbryt + + + Available Groups + + + + Allowed Groups + + + + Filter by Groups + + + + Filter by Daypart + + + + Start Time: + + + + End Time: + + + + + EditSettings + + System-Wide Settings + + + + System Sample Rate: + + + + samples/second + + + + Allow Duplicate Cart Titles + + + + ISCI Cross Reference Path: + + + + Maximum Remote Post Length: + + + + Mbytes + + + + The following duplicate titles must be corrected before "Allow Duplicate Values" can be turned off. + + + + CART + + + + TITLE + + + + &Save List + + + + &OK + &OK + + + &Cancel + &Avbryt + + + File Exists + + + + The file " + + + + " exists. + +Overwrite? + + + + File Error + + + + Checking the Library for duplicates. + + + + Temporary Cart Group: + + + + + EditStation + + Host: + Vert: + + + Ho&st Name: + Verts&namn: + + + &Description: + &Skildring: + + + Default &User: + Standard&brukar: + + + &IP Address: + &IP-adresse: + + + Editor &Command: + Redigerings&kommando: + + + mS + ms + + + &Time Offset: + &Tidsavvik: + + + &Startup Cart: + &Oppstartskorg: + + + Select + Vel + + + Enable Heartbeat + Skru på hjarteslag + + + Use Realtime Filtering + Bruk sanntidsfiltrering + + + Cart: + Korg: + + + Interval: + Intervall: + + + secs + sek + + + RD&Library + RDbib&liotek + + + RDCatch + RDFang + + + RDAirPlay + RDAirPlay + + + RDPanel + RDPanel + + + RDLogEdit + RDLoggredigering + + + Dropboxes + Sleppboksar + + + Audio +Resources + Lydressursar + + + Audio +Ports + Lydportar + + + Serial +Ports + Seriell- +portar + + + Switchers +GPIO + Svitsjar- +inn/ut + + + Host +Variables + Vertsvariablar + + + Backups + Sikringskopiar + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Address + Ugyldig adresse + + + The specified IP address is invalid! + IP-adressa er ugyldig! + + + Invalid Cart + Ugyldig korg + + + The Heartbeat Cart number is invalid! + Hjarteslag-korgnummeret er ugyldig! + + + Host + + + + User + + + + Security Model: + + + + Include in System Maintenance Pool + + + + System Maintenance + + + + At least one host must belong to the system maintenance pool! + + + + HTTP Xport: + + + + Core Audio Engine: + + + + System Services + + + + JACK +Settings + + + + RDCart +Slots + + + + Cue &Output: + + + + RDAdmin - No Audio Configuration Data + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Enable Drag && Drop + + + + Allow Drops on Panels not in Setup Mode + + + + Start Cart + + + + Stop Cart + + + + + EditSvc + + Edit Service + Rediger tenest + + + &Service Name: + &Tenestnamn: + + + Service &Description: + Tenest&skildring: + + + Log &Template Name: + Logg&malnamn: + + + [none] + [ingen] + + + Voicetrack Group: + Stemmespor-gruppe: + + + Insert CHAIN TO at log end + Set inn KJEDE TIL på slutten av loggen + + + Enable AutoRefresh By Default + Skru på auto-oppdatering som standard + + + Configure +&Autofill Carts + Set opp +&Autofyll-korger + + + Enable &Hosts + Skru på &vertar + + + Traffic Data Import + Trafikkdataimport + + + Linux Import Path: + Linux-importstig: + + + Windows Import Path: + Windows-importstig: + + + Note Cart String: + Notat-korgstreng: + + + Insert Voice Track String: + Set inn stemmesporstreng: + + + Cart Number: + Korgnummer: + + + Offset: + Avvik: + + + Length: + Lengd: + + + Title: + Tittel: + + + Start Time - Hours: + Starttid - timar: + + + Start Time - Minutes: + Starttid - minutt: + + + Start Time - Seconds: + Starttid - sekund: + + + Length - Hours: + Lengd - timar: + + + Length - Minutes: + Lengd - minutt: + + + Length - Seconds: + Lengd - sekund: + + + Contract #: + Kontrakt #: + + + Event ID: + Hendings-ID: + + + Annc. Type: + Annonseringstype: + + + Test +&Traffic + Test- +&trafikk + + + Music Data Import + Musikkdataimport + + + Insert Traffic Break String: + Set inn trafikkbrytestreng: + + + Test +&Music + Test- +&musikk + + + &OK + &OK + + + &Cancel + &Avbryt + + + Save Import Data + Lagre importdata + + + Before testing, the import configuration +must be saved. Save now? + Før du prøver ut, må du lagra oppsettet. +Lagre no? + + + Purge Logs after + + + + days + dagar + + + Purge ELR Data after + + + + Import Template: + + + + [custom] + + + + Linux Preimport Command: + + + + Windows Preimport Command: + + + + &Program Code: + + + + AutoSpot Group: + + + + Log Name &Template: + + + + Log &Description Template: + + + + + EditSvcPerms + + Service: + Tenest: + + + Available Hosts + Tilgjengelege vertar + + + Enabled Hosts + Vertar som er skrudde på + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditTtys + + Edit TTYs + Rediger TTYar + + + Port ID: + Port-ID: + + + Enabled + + + + TTY Device: + TTY-eining: + + + Baud Rate: + Baudrate: + + + Parity: + Paritet: + + + Data Bits: + Databitar: + + + Stop Bits: + Stoppbitar: + + + Terminator: + Terminator: + + + &Close + &Lukk + + + Serial + Seriell + + + None + Ingen + + + Even + Partal + + + Odd + Oddetal + + + CR + Retur/CR + + + LF + Linjemating/LF + + + CR/LF + CR/LF + + + + EditUser + + User: + Brukar: + + + &User Name: + Br&ukarnamn: + + + &Full Name: + &Fullt namn: + + + &Description: + &Skildring: + + + &Phone: + Tele&fon: + + + Allow Web Logins + Gje høve til pålogging frå nettet + + + Change +&Password + Endre +&passord + + + Administrative Rights + Administrative tilgangsrettar + + + Administer S&ystem + Administrer s&ystemet + + + Production Rights + Produksjons-tilgangsrettar + + + &Create Carts + &Lag korger + + + &Delete Carts + &Slett korger + + + &Modify Carts + &Endra korger + + + &Edit Audio + Endra &lyd + + + &Edit Netcatch Schedule + Endra &opptaksskjemaet + + + &Voicetrack Logs + S&temmespor-loggar + + + Traffic Rights + Trafikkrettar + + + Create &Log + Lag &Loggar + + + De&lete Log + &Slett loggar + + + Delete &Report Data + Slett &rapportdata + + + &Modify Template + Endra &malar + + + OnAir Rights + På lufta-rettar + + + &Playout Logs + S&peleloggar + + + &Rearrange Log Items + Snu om på loggoppfø&ringar + + + Add Log &Items + Legg t&il loggoppføringar + + + Delete Lo&g Items + Slett lo&ggoppføringar + + + Configure System Panels + Set opp systempanel + + + Podcasting Rights + Podkasting-rettar + + + Cre&ate Podcast + L&ag podkastar + + + E&dit Podcast + Re&diger podkastar + + + Dele&te Podcast + Sle&tt podkastar + + + Assign Group +Permissions + Styr gruppe- +tilgang + + + Assign Podcast Feed +Permissions + Styr podkastsraum- +tilgangsrettar + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditUserPerms + + User: + Brukar: + + + Available Groups + + + + Enabled Groups + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditVguestResource + + Engine (Hex): + Maskin (heksadesimal): + + + Device (Hex): + Eining (heksadesimal): + + + Surface (Hex): + Flate (heksadesimal): + + + Bus/Relay (Hex): + Buss/rele (heksadesimal): + + + &OK + &OK + + + &Cancel + &Avbryt + + + Edit vGuest Switch + Rediger vGuest-svitsj + + + Edit vGuest Display + Rediger vGuest-vising + + + Invalid Number + Ugyldig nummer + + + The Engine Number is Invalid! + Maskinnummeret er ugyldig! + + + The Device Number is Invalid! + Einingsnummeret er ugyldig! + + + The Surface Number is Invalid! + Flatenummeret er ugyldig! + + + The Bus/Relay Number is Invalid! + Buss/relenummeret er ugyldig! + + + + InfoDialog + + System Information + Systeminformasjon + + + Rivendell + Rivendell + + + A Radio Automation System + Eit radioautomasjonssystem + + + Version + Versjon + + + Database Schema + Databaseskjema + + + Copyright 2002-2007 + Copyright 2002-2007 + + + This program is free software, and comes with ABSOLUTELY NO WARRANTY, +not even the implied warranties of MERCHANTIBILITY or FITNESS FOR A +PARTICULAR PURPOSE. Touch the "View License" button for details. + Dette programmet er fri programvare, og har INGEN GARANTIAR,ikkje ein gong garantiar +som gjeld MOGLEIK FOR KJØP OG SAL eller om det er TURVANDE TIL NOKO FØREMÅL. +Klikk på "Lisens"-knappen for fleire opplysningar. + + + View +&License + Sjå +&Lisensen + + + &Close + &Lukk + + + Copyright 2002-2008 + Copyright 2002-2008 + + + Copyright 2002-2010 + Copyright 2002-2010 + + + Copyright 2002-2014 + Copyright 2002-2014 + + + + ListAuxFields + + Auxiliary Metadata Fields + + + + Var Name + + + + Caption + + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + Warning + + + + This will delete all data associated with this field! +Are you sure you want to continue? + + + + + ListDropboxes + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + Group + + + + Path + + + + Normalization Level + + + + Autotrim Level + + + + To Cart + + + + Use CartChunk ID + + + + Delete Cuts + + + + Metadata Pattern + + + + Fix Broken Formats + + + + [off] + + + + [auto] + + + + [none] + [ingen] + + + User Defined + + + + + ListEncoders + + RDAdmin - List Encoders + + + + Format Name + + + + Extension + + + + Valid Channels + + + + Valid Sample Rates + + + + Valid Bit Rates + + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + RDAdmin - Delete Encoder + + + + Are you sure you want to delete this encoder? + + + + This encoder is in use by the following RSS feeds: + + + + + + + +Do you still want to delete it? + + + + [none] + [ingen] + + + Encoders on + + + + + ListEndpoints + + List Inputs + List opp inngangar + + + List Outputs + List opp utgangar + + + INPUT + INNGANG + + + OUTPUT + UTGANG + + + LABEL + MERKE + + + SOURCE + KJELDE + + + MODE + MODUS + + + ENGINE (Hex) + MASKIN (heksadesimal) + + + DEVICE (Hex) + EINING (heksadesimal) + + + PROVIDER ID + TILBYDAR-ID + + + SERVICE ID + TENEST-ID + + + NODE + NODE + + + # + # + + + &Edit + R&ediger + + + &OK + &OK + + + &Cancel + &Avbryt + + + Stereo + Stereo + + + Left + Venstre + + + Right + Høgre + + + Input + Inngang + + + Output + Utgang + + + stereo + stereo + + + left + venstre + + + right + høgre + + + + ListFeeds + + Rivendell Feed List + + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + Key + + + + Title + Tittel + + + AutoPost + + + + Keep Metadata + + + + Creation Date + + + + &Feeds: + + + + Are you sure you want to delete feed + + + + Delete Feed + + + + Deleting Audio... + + + + Cancel + + + + Deleting + + + + + ListGpis + + List GPIs + List opp generelle inngangar + + + GPI Lines + GI-linjer + + + GPI + GI + + + MACRO CART + MAKROKORG + + + DESCRIPTION + SKILDRING + + + &Edit + R&ediger + + + &OK + &OK + + + &Cancel + &Avbryt + + + [unassigned] + [ikkje kopla til] + + + GPO Lines + + + + List GPOs + + + + GPO + + + + ON MACRO CART + + + + ON DESCRIPTION + + + + OFF MACRO CART + + + + OFF DESCRIPTION + + + + + ListGroups + + Rivendell Group List + Rivendell-gruppeliste + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Rename + &Døyp om + + + &Delete + &Slett + + + Generate +&Report + Lag +&rapport + + + &Close + &Lukk + + + NAME + NAMN + + + DESCRIPTION + SKILDRING + + + START CART + START KORG + + + END CART + SLUTT KORG + + + ENFORCE RANGE + TVING OMRÅDE + + + DEFAULT TYPE + STANDARDTYPE + + + TRAFFIC REPORT + TRAFIKKRAPPORT + + + MUSIC REPORT + MUSIKKRAPPORT + + + NOW & NEXT + NO & NESTE + + + &Groups: + &Grupper: + + + member carts will be deleted along with group + medlemskorger blir sletta saman med gruppa + + + Are you sure you want to delete group + Er du sikker på at du vil sletta gruppa + + + Delete Group + Slett gruppa + + + + ListHostvars + + Host Variables for + Vertsvariablar for + + + Host Variables + Vertsvariablar + + + NAME + NAMN + + + VALUE + VERDI + + + REMARK + MERKNAD + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &OK + &OK + + + &Cancel + &Avbryt + + + + ListLiveWireGpios + + LiveWire GPIO Source Assignments + + + + Switchers: + Svitsjarar: + + + &Edit + R&ediger + + + &OK + &OK + + + &Cancel + &Avbryt + + + [none] + [ingen] + + + Lines + + + + Surface Address + + + + [all] + + + + Source # + + + + + ListMatrices + + Rivendell Switcher List + Rivendell-svitsjarliste + + + Switchers: + Svitsjarar: + + + MATRIX + MATRISE + + + DESCRIPTION + SKILDRING + + + TYPE + TYPE + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + Are you sure you want to delete switcher + Er du sikker på at du vil sletta svitsjaren + + + on + + + + ALL references to this switcher will be deleted! + ALLE referansar til denne svitsjaren blir sletta! + + + Deleting Switcher + Slettar svitsjar + + + Local GPIO + Lokal Generell inn/ut + + + Generic GPO + Vanleg Generell ut + + + Generic Serial + Vanleg seriell + + + Local Audio Adapter + Lokalt lydkort + + + Logitek vGuest + Logitek vGuest + + + BroadcastTools SS16.4 + BroadcastTools SS16.4 + + + StarGuide III + StarGuide III + + + BroadcastTools SS4.2 + BroadcastTools SS4.2 + + + Axia LiveWire + Axia LiveWire + + + Quartz Type 1 + Quartz type 1 + + + Unknown + Ukjent + + + BroadcastTools SS4.4 + BroadcastTools SS4.4 + + + + ListReplicatorCarts + + &Repost + + + + Repost +&All + + + + &Close + &Lukk + + + CART + + + + TITLE + + + + LAST POSTED + + + + &Active Carts: + + + + Replicator Carts + + + + POSTED FILENAME + + + + + ListReplicators + + Rivendell Replicators + + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &List +Carts + + + + &Close + &Lukk + + + NAME + NAMN + + + TYPE + TYPE + + + DESCRIPTION + SKILDRING + + + HOST + + + + &Replicators: + + + + Are you sure you want to delete replicator + + + + Delete Replicator + + + + + ListReports + + Rivendell Report List + Rivendell-rapportliste + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + R&eports: + R&apportar: + + + Are you sure you want to delete report + Er du sikker på at du vil sletta rapporten + + + Delete Report + Slett rapporten + + + + ListStations + + Rivendell Workstation List + Rivendell-arbeidsstasjonliste + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + Ho&sts: + Ver&tar: + + + Are you sure you want to delete host + Er du sikker på at du vil sletta verten + + + Delete Station + Slett stasjonen + + + + ListSvcs + + Services + Tenester + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + &Services: + &Tenester: + + + Are you sure you want to delete service + Er du sikker på at du vil sletta tenesta + + + Delete Service + Slett tenesta + + + There are + Denne tenesta eig + + + logs owned by this service that will also be deleted. +Do you still want to proceed? + loggar som òg vil bli sletta. +Er du sikker på at du vil halda fram? + + + Logs Exist + Loggen eksisterer + + + + ListUsers + + Rivendell User List + Rivendell-brukarliste + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + &Users: + Br&ukarar: + + + Can't Delete User + Kan ikkje sletta brukar + + + You cannot delete yourself! + Du kan ikkje sletta deg sjølv! + + + Are you sure you want to delete user + Er du sikker på at du vil sletta brukaren + + + Delete User + Slett brukaren + + + USER NAME + + + + FULL NAME + + + + DESCRIPTION + SKILDRING + + + This user is set as the default user for the following hosts: + + + + + + You must change this before deleting the user. + + + + + Login + + Login + Logg inn + + + &OK + &OK + + + &Cancel + &Avbryt + + + User &Name: + Br&ukarnamn: + + + &Password: + &Passord: + + + + MainWidget + + RDAdmin - Host: + RDAdmin-vert: + + + Daemons Failed + Nissane vart ikkje starta + + + Unable to start Rivendell System Daemons! + Greidde ikkje starta Rivendell-systemnissane! + + + Insufficient Priviledges + Ikkje nok tilgangsrettar + + + This account has insufficient priviledges for this operation. + Denne brukarkontoen har ikkje nok tilgangsrettar til å gjera dette. + + + Manage +&Users + Styr +br&ukarar + + + Manage +&Groups + Styr +&grupper + + + Manage +&Services + Styr +Tene&ster + + + Manage +Ho&sts + Styr +ver&tar + + + Manage +R&eports + Styr +&Rapportar + + + Manage +&Feeds + Styr +str&aumar + + + System +Info + System- +info + + + Scheduler +Codes + Timeplan- +kodar + + + &Backup +Database + S&ikringskopier +databasen + + + &Restore +Database + Gjenopp&rett +databasen + + + &Quit + A&vslutt + + + Rivendell Database Backup (*.sql) + Rivendell databasesikring (*.sql) + + + Backup Error + Feil under sikring + + + Unable to create backup! + Greidde ikkje laga sikringskopi! + + + Backup Complete + Sikringa ferdig + + + Backup completed successfully. + Tok sikringskopi utan vanskar. + + + Restore Database + Gjenopprett database + + + WARNING: This operation will COMPLETELY +OVERWRITE the existing Rivendell Database! +Do you want to continue? + ÅTVARING: Dette vil OVERSKRIVA Rivendell- +databasen heilt! Er du sikker på at du vil halda fram? + + + Restore Error + Gjenopprettingsfeil + + + Unable to restore backup! + Greidde ikkje gjenoppretta sikringskopien! + + + Restore Complete + Gjennoppretting fullført + + + Restore completed successfully. + Gjenopprettinga vart fullført utan vanskar. + + + System +Settings + + + + Manage +Replicators + + + + RDAdmin + + + + + MySqlLogin + + mySQL Admin + mySQL-admin + + + User &Name: + Br&ukarnamn: + + + &Password: + &Passord: + + + &OK + &OK + + + &Cancel + &Avbryt + + + + QObject + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + Greier ikkje kopla til Rivendell-databasen! +Skriv inn eit brukarnamn til ein konto som har +rettar til å administrera mySQL-tenaren, +så prøver me å ordna opp i dette. + + + Wrong access permissions for accessing mySQL! + Feil tilgangsrettar for å kopla til mySQL! + + + Unable to connect to mySQL! + Greier ikkje kopla til mySQL! + + + Unable to create a Rivendell Database! + Greier ikkje laga ein Rivendell-database! + + + Unable to connect to new Rivendell Database! + Greier ikkje kopla til den nye Rivendell-databasen! + + + Unable to create Rivendell Database! + Greier ikkje laga ein Rivendell-database! + + + Unable to connect to Rivendell Database! + Greier ikkje kopla til Rivendell-databasen! + + + Unable to initialize Rivendell Database! + Greier ikkje setja opp Rivendell-databasen! + + + RDAdmin + + + + New Rivendell Database Created! + Du har laga ein ny Rivendell-database. + + + Unable to upgrade database + + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + Rivendell-databasen er for gamal til å oppgradera, +så han må bytast ut. Dette VIL ØYDELEGGJA alle +lyd- og datafiler! Viss du vil gjera dette, skriv du inn +eit brukarnamn og passord med administrasjons- +rettar for mySQL-kontoen. Viss ikkje, trykk avbryt. + + + Unable to log into Administrator account! + Greier ikkje logga på Administrator-kontoen! + + + Unable to authorize a Rivendell Database! + Greier ikkje godkjenna Rivendell-databasen! + + + Update Needed + Treng oppdatering + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + Rivendell-databasen treng ei oppdatering. +Alle lydfiler og innstillingar blir tekne vare på, +men dette VIL STOPPA alt opptak eller avspeling +på denne maskina i nokre sekund. Halda fram? + + + Unable to update Rivendell Database: + + + + +Database backup failed! + + + + +Schema modification failed! + + + + +Unknown/unspecified error! + + + + The Rivendell Database has been updated to version + + + + +and a backup of the original database saved in + + + + Database Updated + Databasen oppdatert + + + RDAdmin Error + + + + (default) + + + + Start Line 1 + + + + Stop Line 1 + + + + Pause Line 1 + + + + Start Line 2 + + + + Stop Line 2 + + + + Pause Line 2 + + + + Start Line 3 + + + + Stop Line 3 + + + + Pause Line 3 + + + + Start Line 4 + + + + Stop Line 4 + + + + Pause Line 4 + + + + Start Line 5 + + + + Stop Line 5 + + + + Pause Line 5 + + + + Start Line 6 + + + + Stop Line 6 + + + + Pause Line 6 + + + + Start Line 7 + + + + Stop Line 7 + + + + Pause Line 7 + + + + Add + + + + Delete + + + + Copy + + + + Move + + + + Sound Panel + + + + Main Log + Hovudlogg + + + Aux Log 1 + Hjelpelogg 1 + + + Aux Log 2 + Hjelpelogg 2 + + + + RenameGroup + + Rename Group + Døyp om gruppa + + + Current Group Name: + Gjeldande gruppenamn: + + + New &Group Name: + Nytt &gruppenamn: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Group + Ugyldig gruppe + + + The group name is invalid! + Gruppenamnet er ugyldig! + + + A + Ei + + + group already exists. +Do you want to combine the two? + gruppe eksisterer frå før. +Vil du kombinera desse to? + + + Group Exists + Gruppa eksisterer + + + + TestImport + + Test Traffic Import + Test trafikkrapport + + + Test Music Import + Test musikkrapport + + + Test Date: + Testdato: + + + &Select + &Vel + + + &Import + &Importer + + + Using source file: + Bruker kjeldefila: + + + Start Time + Starttid + + + Cart + Korg + + + Len + Len + + + Title + Tittel + + + Contract # + Kontrakt # + + + Event ID + Hendings-ID + + + Announcement Type + Annonseringstype + + + Imported Events + Importerte hendingar + + + &Close + &Lukk + + + Import Error + Importfeil + + + There was an error during import +please check your settings and try again. + Det vart ein feil under importen. +Sjekk oppsettet ditt og prøv att. + + + [spot break] + [spott-avbrot] + + + + ViewAdapters + + Audio Resource Information + Lydressursinformasjon + + + Audio Resources on + Lydressursar på + + + SUPPORTED AUDIO DRIVERS + + STØTTA LYDDRIVARAR + + + + SUPPORTED IMPORT FORMATS + + STØTTA IMPORTFORMAT + + + + PCM16 Linear + + Lineær PCM16 + + + MPEG Layer 1 + + MPEG lag 1 + + + + MPEG Layer 2 + + MPEG lag 2 + + + + MPEG Layer 3 + + MPEG lag 3 + + + + OggVorbis + + OggVorbis + + + + SUPPORTED EXPORT FORMATS + + STØTTA EKSPORTFORMAT + + + + Free Lossless Audio Codec (FLAC) + + Fri lydkodek utan tap (FLAC) + + + + AUDIO ADAPTERS + + LYDKORT + + + + Card + Kort + + + Not present + Ikkje til stades + + + Driver: AudioScience HPI + + Drivar: AudioScience HPI + + + + Driver: JACK Audio Connection Kit + + Drivar: JACK Audio Connection Kit + + + + Driver: Advanced Linux Sound Architecture (ALSA) + + Drivar: Advanced Linux Sound Architecture (ALSA) + + + + Driver: UNKNOWN + + Drivar: UKJENT + + + + Inputs: + Inngangar: + + + Outputs: + Utgangar: + + + NO DATA AVAILABLE + + + INGEN DATA FINST + + + + + Please start the Rivendell daemons on this host (by executing, as user 'root', the command "/etc/init.d/rivendell start") in order to populate the audio resources database. + Start Rivendell-nisseprogramma på denne verten ved å køyra kommandoen "/etc/init.d/rivendell-start" som root-brukaren for å fylla ut lydressursdatabasen. + + + &Close + &Lukk + + + diff --git a/rdadmin/rdadmin_nn.ts b/rdadmin/rdadmin_nn.ts new file mode 100644 index 00000000..b1742c2a --- /dev/null +++ b/rdadmin/rdadmin_nn.ts @@ -0,0 +1,5823 @@ + + + @default + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + Greier ikkje kopla til Rivendell-databasen! +Skriv inn eit brukarnamn til ein konto som har +rettar til å administrera mySQL-tenaren, +så prøver me å ordna opp i dette. + + + Can't Connect + Kan ikkje kopla til + + + Wrong access permissions for accessing mySQL! + Feil tilgangsrettar for å kopla til mySQL! + + + Unable to connect to mySQL! + Greier ikkje kopla til mySQL! + + + Can't Create DB + Greier ikkje laga database + + + Unable to create a Rivendell Database! + Greier ikkje laga ein Rivendell-database! + + + Unable to connect to new Rivendell Database! + Greier ikkje kopla til den nye Rivendell-databasen! + + + Can't Create + Greier ikkje laga + + + Unable to create Rivendell Database! + Greier ikkje laga ein Rivendell-database! + + + Unable to connect to Rivendell Database! + Greier ikkje kopla til Rivendell-databasen! + + + Can't Initialize + Greier ikkje setja opp + + + Unable to initialize Rivendell Database! + Greier ikkje setja opp Rivendell-databasen! + + + Created Database + Laga database + + + New Rivendell Database Created! + Du har laga ein ny Rivendell-database. + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + Rivendell-databasen er for gamal til å oppgradera, +så han må bytast ut. Dette VIL ØYDELEGGJA alle +lyd- og datafiler! Viss du vil gjera dette, skriv du inn +eit brukarnamn og passord med administrasjons- +rettar for mySQL-kontoen. Viss ikkje, trykk avbryt. + + + Unable to log into Administrator account! + Greier ikkje logga på Administrator-kontoen! + + + Unable to authorize a Rivendell Database! + Greier ikkje godkjenna Rivendell-databasen! + + + Update Needed + Treng oppdatering + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + Rivendell-databasen treng ei oppdatering. +Alle lydfiler og innstillingar blir tekne vare på, +men dette VIL STOPPA alt opptak eller avspeling +på denne maskina i nokre sekund. Halda fram? + + + Can't Update + Greier ikkje oppdatera + + + Unable to update Rivendell Database! + Greidde ikkje oppdatera Rivendell-databasen! + + + The Rivendell Database has +been updated to Version + Rivendell-databasen er +oppdatert til versjon + + + Database Updated + Databasen oppdatert + + + + AddAuxField + + Add Aux Field + + + + Variable Name: + + + + %AUX_ + + + + % + + + + Caption: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Name Exists + + + + That variable name already exists! + + + + + AddEncoder + + Add Encoder + + + + &New Encoder Name: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Add Encoder Error + + + + A encoder with that name already exists! + + + + + AddFeed + + Add Feed + + + + Enable Feed for All Users + + + + &New Feed Name: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Add Feed Error + + + + A feed with that key name already exists! + + + + + AddGroup + + Add Group + Legg til gruppe + + + &New Group Name: + &Nytt gruppenamn: + + + Enable Group for All Users + Skru på gruppa for alle brukarar + + + Enable Group for All Services + Skru på gruppa for alle tenester + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Name + Ugyldig namn + + + You must give the group a name! + Du må gje gruppa eit namn! + + + Group Exists + Gruppa finst + + + Group Already Exists! + Gruppa finst alt! + + + + AddHostvar + + Add Host Variable + Legg til tenarvariabel + + + Variable Name: + Namn på variabelen: + + + Variable Value: + Variabelverdi: + + + Remark: + Merknad: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Name + Ugyldig namn + + + The variable name is invalid. + + + + + AddMatrix + + Add Switcher + Legg til bytar + + + &New Matrix Number: + &Nytt matrisenummer: + + + Local GPIO + Lokal Generell inn/ut + + + Generic GPO + Vanleg Generell ut + + + Generic Serial + Vanleg seriell + + + Local Audio Adapter + Lokalt lydkort + + + Logitek vGuest + Logitek vGuest + + + BroadcastTools SS16.4 + BroadcastTools SS16.4 + + + StarGuide III + StarGuide III + + + BroadcastTools SS4.2 + BroadcastTools SS4.2 + + + Axia LiveWire + Axia LiveWire + + + Quartz Type 1 + Quartz type 1 + + + &Switcher Type: + &Bytar-type: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Matrix + Ugyldig matrise + + + Matrix already exists! + Matrisen finst frå før! + + + BroadcastTools SS4.4 + BroadcastTools SS4.4 + + + New Switcher + + + + RDAdmin - Add Switcher + + + + + AddReplicator + + Add Replicator + + + + &New Replicator Name: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Name + Ugyldig namn + + + You must give the replicator a name! + + + + Replicator Exists + + + + A replicator with that name already exists! + + + + + AddReport + + Add Report + Legg til rapport + + + &Report Name: + &Namn på rapporten: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Name + Ugyldig namn + + + You must provide a report name! + Du må skriva inn eit namn på rapporten! + + + Report Exists + Rapporten finst + + + A report with that name already exists! + Det finst alt ein rapport med dette namnet! + + + + AddStation + + Add Host + Legg til vert + + + New &Host Name: + Nytt &Vertsnamn: + + + Base Host On: + Grunnvert på: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Empty Host Config + Tomt vertsoppsett + + + Invalid Name + Ugyldig namn + + + You must give the host a name! + Du må gje verten eit namn! + + + Host Exists + Verten eksisterer + + + Host Already Exists! + Verten finst frå før! + + + + AddSvc + + Add Service + Legg til teneste + + + &New Service Name: + &Nytt tenestenamn: + + + Base Service On: + Hovudtenest på: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Empty Host Config + Tomt vertsoppsett + + + Invalid Name + Ugyldig namn + + + You must give the service a name! + Du må gje tenesta eit namn! + + + Service Exists + Tenesta eksisterer + + + Service Already Exists! + Tenesta finst frå før! + + + + AddUser + + Add User + Legg til brukar + + + &New User Name: + &Nytt brukarnamn: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Name + Ugyldig namn + + + You must give the user a name! + Du må gje brukaren eit namn! + + + User Exists + Brukaren eksisterer + + + User Already Exists! + Brukaren finst frå før! + + + + AutofillCarts + + Autofill Carts - Service: + Tenest for å autofylla korger: + + + Cart + Korg + + + Length + Lengd + + + Title + Tittel + + + Artist + Artist + + + &Add + &Legg til + + + &Delete + &Slett + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditAudioPorts + + Edit Audio Ports + Rediger lydportar + + + Clock Source: + Klokkekjelde: + + + Input Port + Inngangsport + + + Analog + Analog + + + AES/EBU + AES/EBU + + + SP/DIFF + SP/DIFF + + + Type: + Type: + + + Normal + Normal + + + Swap + Byt om + + + Left only + Berre venstre + + + Right only + Berre høgre + + + Mode: + Modus: + + + dB + dB + + + Level: + Nivå: + + + Output Port + Utgangsport + + + &Help + &Hjelp + + + &Close + &Lukk + + + Internal + Intern + + + AES/EBU Signal + AES/EBU-signal + + + SP/DIFF Signal + SP/DIFF-signal + + + Word Clock + Ordklokke + + + Card: + Kort: + + + Card Driver: + + + + Ref. Level: + + + + + EditAuxField + + Edit Auxiliary Metadata Fields + + + + Variable Name: + + + + Caption: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditBackup + + Backup config for + Sikringskopi-oppsett for + + + Keep Backups For: + Lagra sikringskopiar i: + + + days + dagar + + + Backup Directory: + Mappe for sikringskopiar: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Path Missing + Manglar stig + + + You must supply a backup path! + Du må velja ein stig til sikringskopi-mappa! + + + + EditCartSlots + + RDAdmin - Edit CartSlots + + + + Close + + + + None + Ingen + + + Output Port: + + + + Card: + Kort: + + + Input Port: + + + + Cart + Korg + + + Mode: + Modus: + + + Cart: + Korg: + + + At Playout End: + + + + Channel Assignments + Kanaltilkoplingar + + + Default Settings + + + + Select + Vel + + + Load Specified Cart + + + + At Startup: + Ved oppstart: + + + Do Nothing + + + + Slot Mode: + + + + Full + + + + Hook + + + + Play Mode: + + + + User previous mode + + + + Use previous mode + + + + Use previous cart + + + + Use previous action + + + + Service: + + + + Global Settings + + + + Slot Columns: + + + + Slot Rows: + + + + Slot + + + + Settings + Innstillingar + + + Slot selected has changed! + + + + + EditDecks + + Configure RDCatch + Set opp RDCatch + + + Record Deck + Opptak + + + None + Ingen + + + Monitor Port: + Lytteport: + + + Off + Av + + + On + + + + Monitor defaults to + Lyttinga går automatisk til + + + Format: + Format: + + + Sample Rate: + Punktprøverate: + + + Bit Rate: + Bitrate: + + + Switcher Host: + Svitsjar-vert: + + + Switcher Matrix: + Svitsjar-matrise: + + + Switcher Output: + Svitsjar-utgang: + + + Switcher Delay: + Svitsjar-seinking: + + + 1/10 sec + 1/10 sek + + + Channels: + Kanalar: + + + Trim Threshold: + Trimmeterskel: + + + Error RML: + Feil RML: + + + Play Deck + Spel + + + Audition Deck + Lytt + + + &Close + &Lukk + + + No Audio Configuration Data + Ingen data for lydoppsett + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Det vil ikkje vera tilgjengelege kanalar for denne verten, fordi det ikkje har vorte laga +data for lydressursar enno. Start Rivendell-programma på denne verten ved å køyra +kommandoen "/etc/init.d/rivendell-start" som root-brukaren for å fylla ut databasen +for lydressursar. + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG lag 2 + + + 32 kbps/chan + 32 kbps/kanal + + + 48 kbps/chan + 48 kbps/kanal + + + 56 kbps/chan + 56 kbps/kanal + + + 64 kbps/chan + 64 kbps/kanal + + + 80 kbps/chan + 80 kbps/kanal + + + 96 kbps/chan + 96 kbps/kanal + + + 112 kbps/chan + 112 kbps/kanal + + + 128 kbps/chan + 128 kbps/kanal + + + 160 kbps/chan + 160 kbps/kanal + + + 192 kbps/chan + 192 kbps/kanal + + + [none] + [ingen] + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Settings + Innstillingar + + + Defaults + Standard + + + Host-Wide Settings + + + + + EditDropbox + + Dropbox Configuration + + + + Default Group: + + + + &Path Spec: + + + + Select + Vel + + + To &Cart: + + + + Delete cuts before importing + + + + &Metadata Pattern: + + + + &Log File: + + + + Delete source files after import + + + + Normalize Levels + + + + Level: + Nivå: + + + dBFS + + + + Autotrim Cuts + + + + Get cart number from CartChunk CutID + + + + Get cart title from CartChunk CutID + + + + Attempt to work around malformatted input files + + + + Offset start date by + + + + days + dagar + + + Offset end date by + + + + Create Dates when no Dates Exist + + + + Create start date offset: + + + + Create end date offset: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Offsets + + + + The Create EndDate Offset is less than the Create Start Date Offset! + + + + &User Defined: + + + + Scheduler Codes + + + + + EditEncoder + + RDAdmin - Edit Encoder + + + + Name: + + + + Allow Channels + + + + Allow Sample Rates + + + + Allow Bit Rates + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Default Extension: + + + + Command Line: + + + + + EditEndpoint + + Edit Input + Rediger inngang + + + Edit Output + Rediger utgang + + + Name: + Namn: + + + Feed: + Straum: + + + Mode: + Modus: + + + Stereo + Stereo + + + Left + Venstre + + + Right + Høgre + + + Engine (Hex): + Maskin (heksadesimal): + + + Provider ID: + Tilbydar-ID: + + + Device (Hex): + Eining (heksadesimal): + + + Service ID: + Tenest-ID: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Number + Ugyldig nummer + + + The Engine Number is Invalid! + Ugyldig nummer! + + + The Provider ID is Invalid! + Tilbydar-ID-en er ugyldig! + + + The Device Number is Invalid! + Einingsnummeret er ugyldig! + + + The Service ID is Invalid! + Tenest-ID-en er ugyldig! + + + + EditFeed + + Feed: + Straum: + + + Key Name: + + + + CHANNEL VALUES + + + + Title: + Tittel: + + + Category: + + + + Link: + + + + Copyright: + + + + Webmaster: + + + + Language: + + + + Description: + Skildring: + + + Audio Upload URL: + + + + Username: + Brukarnamn: + + + Password: + Passord: + + + Upload Format: + + + + S&et + + + + Normalize + + + + Level: + Nivå: + + + dBFS + + + + Audio Download URL: + + + + Keep Expired Metadata + + + + Enable AutoPost + + + + Enclosure Preamble: + + + + Audio Extension: + + + + None + Ingen + + + Maximum Shelf Life: + + + + days + dagar + + + Descending + + + + Ascending + + + + Episode Sort Order: + + + + Direct + + + + Counted + + + + Media Link Mode: + + + + Enable Feed Redirection + + + + URL: + + + + Header XML: + + + + Channel XML: + + + + Item XML: + + + + &Define Auxiliary +Metadata Fields + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Edit Feed - Redirect + + + + Enabling feed redirection will cause clients subscribed to +this feed to be PERMANENTLY redirected to the +specified URL. + +Do you still want to enable redireciton? + + + + + EditFeedPerms + + User: + Brukar: + + + Available Feeds + + + + Enabled Feeds + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditGpi + + Edit GPI + Rediger generell inngang + + + GPI: + Generell inngang: + + + Description: + Skildring: + + + Cart Number: + Korgnummer: + + + &Select + &Vel + + + C&lear + &Tøm + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Cart + Ugyldig korg + + + Invalid Cart Number! + Ugyldig korgnummer! + + + + EditGroup + + Group: + Gruppe: + + + &Group Name: + &Gruppenamn: + + + Group &Description: + Gruppe&skildring: + + + Audio + Lyd + + + Macro + Makro + + + Default Cart &Type: + Standard korg&type: + + + None + Ingen + + + Default Cart Number: + Standard korgnummer: + + + to + til + + + Enforce Cart Range + Tving korgområde + + + Include this group in Traffic reports + Legg til denne gruppa i trafikkrapportar + + + Include this group in Music reports + Legg til denne gruppa i musikkrapportar + + + Transmit Now && Next data + Send no && Neste data + + + C&olor + F&arge + + + &OK + &OK + + + &Cancel + &Avbryt + + + The selected cart range conflicts with the following groups: + + + Det valde korgområdet stemmer ikkje med desse gruppene: + + + + + +Do you still want to save? + +Vil du framleis lagra? + + + Default Import &Title: + + + + Purge expired cuts after + + + + days + dagar + + + Delete cart if empty + + + + + EditHostvar + + Edit Host Variable + Rediger vertsvarliabe + + + Variable Name: + Variabelnamn: + + + Variable Value: + Variabelverdi: + + + Remark: + Merknad: + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditHotkeys + + Host Hot Key Configurations + + + + Button / Function + + + + KeyStroke + + + + Set + + + + Clear + + + + Clear All Hotkeys + + + + Set From Host: + + + + Save + + + + Cancel + + + + Duplicate Entries + + + + Hotkeys Clear + + + + Hotkeys Updated + + + + No Items Selected + + + + Please Select an Item From the List + + + + Hot Key Configuration for + + + + + EditJack + + JACK Configuration for + + + + Start JACK Server + + + + JACK Server Name: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + JACK Command Line: + + + + NAME + NAMN + + + VALUE + VERDI + + + REMARK + MERKNAD + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + JACK Clients to Start: + + + + Client + + + + Command Line + + + + [New Client] + + + + RDAdmin - JACK Clients + + + + Are you sure you want to delete JACK Client + + + + + EditJackClient + + JACK Client Configuration for + + + + Description: + Skildring: + + + Command Line: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditLiveWireGpio + + None + Ingen + + + &OK + &OK + + + &Cancel + &Avbryt + + + Edit GPIO Source + + + + Livewire Source: + + + + GPIO Lines + + + + Surface Address: + + + + Invalid IP Address + + + + The IP address is invalid! + + + + + EditMatrix + + Edit Switcher + Rediger svitsjar + + + Matrix Number: + Matrisenummer: + + + Switcher Type: + Svitsjartype: + + + Description: + Skildring: + + + Primary Connection + Hovudtilkopling + + + Type: + Type: + + + Serial + Seriell + + + TCP/IP + TCP/IP + + + Serial Port: + Seriellport: + + + IP Address: + IP-adresse: + + + IP Port: + IP-port: + + + Username: + Brukarnamn: + + + Password: + Passord: + + + Backup Connection + Sikringstilkopling + + + None + Ingen + + + Card: + Kort: + + + Inputs: + Inngangar: + + + Outputs: + Utgangar: + + + Device: + Eining: + + + GPIs: + Generelle inngangar: + + + GPOs: + Generelle utgangar: + + + Layer: + Lag: + + + Displays: + Skjermar: + + + Configure +&Inputs + Set opp +&inngangar + + + Configure +&Outputs + Set opp +&utgangar + + + Configure +&Xpoints + Set opp +&Xpunkt + + + Configure +GP&Is + Set opp +G&I-ar + + + LiveWire +Nodes + LiveWire- +nodar + + + vGuest +Switches + vGuest- +svitsjar + + + vGuest +Displays + vGuest- +visingar + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Address + Ugyldig adresse + + + The primary IP address is invalid! + Hovud-IP-adressa er ugyldig! + + + The backup IP address is invalid! + Sikrings-IP-adressa er ugyldig! + + + Duplicate Connections + Dublett-tilkoplingar + + + The primary and backup connections must be different! + Hovud- og sikringstilkoplingane må vera ulike! + + + Startup Cart: + + + + Select + Vel + + + Shutdown Cart: + + + + Configure +&GPIs + + + + Configure +G&POs + + + + SAS +Switches + + + + RDAdmin - Edit Switcher + + + + LiveWire +GPIOs + + + + + EditNowNext + + Edit Now & Next Data + Rediger no & neste data + + + Master Log + Hovudlogg + + + IP Address: + IP-adresse: + + + UDP Port: + UDP-port: + + + UDP String: + UDP-streng: + + + RML: + RMS: + + + Aux Log 1 + Hjelpelogg 1 + + + &OK + &OK + + + &Cancel + &Avbryt + + + The IP address + IP-adressa + + + is invalid! + er ugyldig! + + + Invalid Address + Ugyldig adresse + + + Default Now Cart: + + + + Select + Vel + + + Default Next Cart: + + + + Path + + + + Argument + + + + Loadable Modules: + + + + Add + + + + Edit + + + + Delete + + + + Aux Log 2 + Hjelpelogg 2 + + + + EditNowNextPlugin + + Edit Plugin + + + + Plugin Path: + + + + Select + Vel + + + Argument: + + + + &OK + &OK + + + &Cancel + &Avbryt + + + Select plugin + + + + + EditRDAirPlay + + RDAirPlay config for + RDAirPlay-oppsett for + + + Channel Assignments + Kanaltilkoplingar + + + Main Log Output 1 + Hovudlogg-utgang 1 + + + Start RML: + Start RML: + + + Stop RML: + Slutt-RML: + + + Main Log Output 2 + Hovudloggutgang 2 + + + Aux Log 1 Output + Hjelpelogg 1-utgang + + + Aux Log 2 Output + Hjelpelogg 2-utgang + + + Audition/Cue Output + Lytting/cue-utgang + + + SoundPanel First Play Output + Fyrste spelutgang for Lydpanel + + + SoundPanel Second Play Output + Andre speleutgang for lydpanelet + + + SoundPanel Third Play Output + Tredje speleutgang for lydpanelet + + + SoundPanel Fourth Play Output + Fjerde speleutgang for lydpanelet + + + SoundPanel Fifth and Later Play Output + Femte og høgare speleutgangar for lydpanelet + + + Manual Segue: + Manuell overgang: + + + msecs + msek + + + Forced Segue: + Tvungen overgang: + + + Pie Counts Last: + Urskivenedtellinga varar: + + + secs + sek + + + Pie Counts To: + Urskiva teller til: + + + Cart End + Slutten på korga + + + Transition + Overtoning + + + Default Trans. Type: + Standard overtoningstype: + + + Play + Spel + + + Segue + Overgang + + + Stop + Stopp + + + Overlap + Overlapp + + + Default Service: + Standardtenest: + + + Sound Panel Settings + Lydpaneloppsett + + + None + Ingen + + + Host Panels: + Vertspanel: + + + User Panels: + Brukarpanel: + + + Flash Active Buttons + Aktive knappar blinkar + + + Enable Button Pausing + Skru på pause med knapp + + + Label Template: + Merkemal: + + + Miscellaneous Settings + Ymse innstillingar + + + Startup Mode: + Oppstartsmåte: + + + Previous + Førre + + + LiveAssist + Live-hjelp + + + Automatic + Automatisk + + + Manual + Manuelt + + + Check TimeSync + Sjekk tidssynk + + + Show Auxlog 1 Button + Vis hjelpelogg 1-knappen + + + Show Auxlog 2 Button + Vis hjelpelogg 2-knappen + + + Clear Cart Search Filter + Tøm korgsøkjefilteret + + + Enable Paused Events + Set igang pausa hendingar + + + Space Bar Action + Kva mellomromstasten gjer + + + Start Next + Start neste + + + Configure Now && Next +Parameters + Set opp no && Neste +parametrar + + + Start/Stop Settings + Start/stopp-oppsett + + + Exit Password: + Passord for å lukka: + + + Main Log + Hovudlogg + + + start with empty log + start med tom logg + + + load previous log + last førre loggen + + + load specified log + last oppgjeven logg + + + At Startup: + Ved oppstart: + + + Restart Log After Unclean Shutdown + Start omatt loggen etter feil avslutting + + + Log: + Logg: + + + &Select + &Vel + + + &OK + &OK + + + &Cancel + &Avbryt + + + No Audio Configuration Data + Ingen data for lydoppsett + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Det vil ikkje vera tilgjengelege kanalar for denne verten, fordi det ikkje har vorte laga +data for lydressursar enno. Start Rivendell-programma på denne verten ved å køyra +kommandoen "/etc/init.d/rivendell-start" som root-brukaren for å fylla ut databasen +for lydressursar. + + + [none] + [ingen] + + + Data Error + Datafeil + + + Invalid Segue Length! + Ugyldig lengd på overgangen! + + + Invalid Forced Segue Length! + Ugyldig lengd på den tvungne overgangen! + + + Show Extra Buttons/Counters + + + + Audition Preroll: + + + + Display Settings + + + + Background Image: + + + + Select + Vel + + + Select Image File + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Configure Hot Keys + + + + Show Hour Selector + + + + Edit +GPIOs + + + + Title Template: + + + + Artist Template: + + + + Outcue Template: + + + + Description Template: + + + + Log Mode Control + + + + Mode Control Style: + + + + Unified + + + + Independent + + + + Main Log Startup Mode: + + + + Aux 1 Log Startup Mode: + + + + Aux 2 Log Startup Mode: + + + + + EditRDLibrary + + RDLibrary config for + RDBibliotek-oppsett for + + + INPUT + INNGANG + + + OUTPUT + UTGANG + + + Settings + Innstillingar + + + &Max Record Time: + &Maks opptakstid: + + + &VOX Threshold: + &VOX-terskel: + + + dbFS + dBum + + + &AutoTrim Threshold: + &Autotrim-terskel: + + + &Tail Preroll: + &Hale-førrull: + + + milliseconds + millisekund + + + &Ripper Device: + &Eining for uthenting: + + + &Paranoia Level: + &Paranoia-nivå: + + + Ripper Level: + Uthenting-nivå: + + + &FreeDB Server: + &FreeDB-tenar: + + + &Format: + &Format: + + + &Sample Rate: + &Punktprøverate: + + + &Bitrate: + &Bitrate: + + + No + Nei + + + Yes + Ja + + + Allow E&xternal Editing: + Gje høve til ek&stern redigering: + + + Defaults + Standard + + + &Channels: + &Kanalar: + + + Record Mode: + Opptaksmodus: + + + AutoTrim: + Autotrim: + + + &OK + &OK + + + &Cancel + &Avbryt + + + No Audio Configuration Data + Ingen data for lydoppsett + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Det vil ikkje vera tilgjengelege kanalar for denne verten, fordi det ikkje har vorte laga +data for lydressursar enno. Start Rivendell-programma på denne verten ved å køyra +kommandoen "/etc/init.d/rivendell-start" som root-brukaren for å fylla ut databasen +for lydressursar. + + + Normal + Normal + + + Low + Låg + + + None + Ingen + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG lag 2 + + + Manual + Manuelt + + + VOX + VOX + + + 32 kbps/chan + 32 kbps/kanal + + + 48 kbps/chan + 48 kbps/kanal + + + 56 kbps/chan + 56 kbps/kanal + + + 64 kbps/chan + 64 kbps/kanal + + + 80 kbps/chan + 80 kbps/kanal + + + 96 kbps/chan + 96 kbps/kanal + + + 112 kbps/chan + 112 kbps/kanal + + + 128 kbps/chan + 128 kbps/kanal + + + 160 kbps/chan + 160 kbps/kanal + + + 192 kbps/chan + 192 kbps/kanal + + + 40 kbps/chan + 40 kbps/kanal + + + 224 kbps/chan + 224 kbps/kanal + + + 256 kbps/chan + 256 kbps/kanal + + + 320 kbps/chan + 320 kbps/kanal + + + Sample Rate Converter: + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Limit Searches at Startup + + + + Previous + Førre + + + + EditRDLogedit + + RDLogedit config for + + + + INPUT + INNGANG + + + OUTPUT + UTGANG + + + Voice Tracker Settings + + + + &Max Record Time: + &Maks opptakstid: + + + &AutoTrim Threshold: + &Autotrim-terskel: + + + dbFS + dBum + + + &Normalization Level: + + + + &Audio Margin: + + + + milliseconds + millisekund + + + &Format: + &Format: + + + &Bitrate: + &Bitrate: + + + Play &Start Cart: + + + + Select + Vel + + + Play &End Cart: + + + + &Record Start Cart: + + + + Re&cord End Cart: + + + + &Channels: + &Kanalar: + + + Default Transition: + + + + Play + Spel + + + Segue + Overgang + + + Stop + Stopp + + + &OK + &OK + + + &Cancel + &Avbryt + + + No Audio Configuration Data + Ingen data for lydoppsett + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG lag 2 + + + 32 kbps/chan + 32 kbps/kanal + + + 48 kbps/chan + 48 kbps/kanal + + + 56 kbps/chan + 56 kbps/kanal + + + 64 kbps/chan + 64 kbps/kanal + + + 80 kbps/chan + 80 kbps/kanal + + + 96 kbps/chan + 96 kbps/kanal + + + 112 kbps/chan + 112 kbps/kanal + + + 128 kbps/chan + 128 kbps/kanal + + + 160 kbps/chan + 160 kbps/kanal + + + 192 kbps/chan + 192 kbps/kanal + + + 40 kbps/chan + 40 kbps/kanal + + + 224 kbps/chan + 224 kbps/kanal + + + 256 kbps/chan + 256 kbps/kanal + + + 320 kbps/chan + 320 kbps/kanal + + + No + Nei + + + Yes + Ja + + + Enable &2nd Start Button: + + + + + EditRDPanel + + RDPanel config for + + + + Channel Assignments + Kanaltilkoplingar + + + SoundPanel First Play Output + Fyrste spelutgang for Lydpanel + + + Start RML: + Start RML: + + + Stop RML: + Slutt-RML: + + + SoundPanel Second Play Output + Andre speleutgang for lydpanelet + + + SoundPanel Third Play Output + Tredje speleutgang for lydpanelet + + + SoundPanel Fourth Play Output + Fjerde speleutgang for lydpanelet + + + SoundPanel Fifth and Later Play Output + Femte og høgare speleutgangar for lydpanelet + + + SoundPanel Cue Output + + + + Display Settings + + + + Background Image: + + + + Select + Vel + + + Sound Panel Settings + Lydpaneloppsett + + + None + Ingen + + + Host Panels: + Vertspanel: + + + User Panels: + Brukarpanel: + + + Flash Active Buttons + Aktive knappar blinkar + + + Enable Button Pausing + Skru på pause med knapp + + + Clear Cart Search Filter + Tøm korgsøkjefilteret + + + Default Service: + Standardtenest: + + + Label Template: + Merkemal: + + + &OK + &OK + + + &Cancel + &Avbryt + + + No Audio Configuration Data + Ingen data for lydoppsett + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Det vil ikkje vera tilgjengelege kanalar for denne verten, fordi det ikkje har vorte laga +data for lydressursar enno. Start Rivendell-programma på denne verten ved å køyra +kommandoen "/etc/init.d/rivendell-start" som root-brukaren for å fylla ut databasen +for lydressursar. + + + [none] + [ingen] + + + Select Image File + + + + + EditReplicator + + Replicator: + + + + Name: + + + + Description: + Skildring: + + + Type: + Type: + + + Host System: + + + + Audio Upload URL: + + + + Username: + Brukarnamn: + + + Password: + Passord: + + + Upload Format: + + + + S&et + + + + Normalize + + + + Level: + Nivå: + + + dBFS + + + + Available Groups + + + + Active Groups + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditReport + + Edit Report + Rediger rapport + + + &Report Description: + &Rapportskildring: + + + Export &Filter: + Eksport&filter: + + + Station ID: + Stasjons-ID: + + + Cart Number Parameters: + Parametrar for korgnummer: + + + Use Leading Zeros + Bruk nullar føre + + + Digits: + Siffer: + + + Station Type: + Stasjonstype: + + + Lines per Page: + Linjer per side: + + + Ser&vice Name: + &Tenestnamn: + + + Station &Format: + Stasjons&format: + + + Linux Export Path: + Linux-eksportstig: + + + Windows Export Path: + Windows-eksportstig: + + + Export Event Types: + Eksport-handlingstypar: + + + Traffic + Trafikk + + + Music + Musikk + + + All + Alt + + + Export Events From: + Eksporter hendingar frå: + + + Traffic Log + Trafikklogg + + + Music Log + Musikklogg + + + No + Nei + + + Yes + Ja + + + Include Only OnAir Events: + Ta med berre På lufta-hendingar: + + + Available Services + Tilgjengelege tenester + + + Source Services + Kjeldetenester + + + Available Hosts + Tilgjengelege vertar + + + Source Hosts + Kjeldevertar + + + &OK + &OK + + + &Cancel + &Avbryt + + + Available Groups + + + + Allowed Groups + + + + Filter by Groups + + + + Filter by Daypart + + + + Start Time: + + + + End Time: + + + + + EditSettings + + System-Wide Settings + + + + System Sample Rate: + + + + samples/second + + + + Allow Duplicate Cart Titles + + + + ISCI Cross Reference Path: + + + + Maximum Remote Post Length: + + + + Mbytes + + + + The following duplicate titles must be corrected before "Allow Duplicate Values" can be turned off. + + + + CART + + + + TITLE + + + + &Save List + + + + &OK + &OK + + + &Cancel + &Avbryt + + + File Exists + + + + The file " + + + + " exists. + +Overwrite? + + + + File Error + + + + Checking the Library for duplicates. + + + + Temporary Cart Group: + + + + + EditStation + + Host: + Vert: + + + Ho&st Name: + Verts&namn: + + + &Description: + &Skildring: + + + Default &User: + Standard&brukar: + + + &IP Address: + &IP-adresse: + + + Editor &Command: + Redigerings&kommando: + + + mS + ms + + + &Time Offset: + &Tidsavvik: + + + &Startup Cart: + &Oppstartskorg: + + + Select + Vel + + + Enable Heartbeat + Skru på hjarteslag + + + Use Realtime Filtering + Bruk sanntidsfiltrering + + + Cart: + Korg: + + + Interval: + Intervall: + + + secs + sek + + + RD&Library + RDbib&liotek + + + RDCatch + RDFang + + + RDAirPlay + RDAirPlay + + + RDPanel + RDPanel + + + RDLogEdit + RDLoggredigering + + + Dropboxes + Sleppboksar + + + Audio +Resources + Lydressursar + + + Audio +Ports + Lydportar + + + Serial +Ports + Seriell- +portar + + + Switchers +GPIO + Svitsjar- +inn/ut + + + Host +Variables + Vertsvariablar + + + Backups + Sikringskopiar + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Address + Ugyldig adresse + + + The specified IP address is invalid! + IP-adressa er ugyldig! + + + Invalid Cart + Ugyldig korg + + + The Heartbeat Cart number is invalid! + Hjarteslag-korgnummeret er ugyldig! + + + Host + + + + User + + + + Security Model: + + + + Include in System Maintenance Pool + + + + System Maintenance + + + + At least one host must belong to the system maintenance pool! + + + + HTTP Xport: + + + + Core Audio Engine: + + + + System Services + + + + JACK +Settings + + + + RDCart +Slots + + + + Cue &Output: + + + + RDAdmin - No Audio Configuration Data + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Enable Drag && Drop + + + + Allow Drops on Panels not in Setup Mode + + + + Start Cart + + + + Stop Cart + + + + + EditSvc + + Edit Service + Rediger tenest + + + &Service Name: + &Tenestnamn: + + + Service &Description: + Tenest&skildring: + + + Log &Template Name: + Logg&malnamn: + + + [none] + [ingen] + + + Voicetrack Group: + Stemmespor-gruppe: + + + Insert CHAIN TO at log end + Set inn KJEDE TIL på slutten av loggen + + + Enable AutoRefresh By Default + Skru på auto-oppdatering som standard + + + Configure +&Autofill Carts + Set opp +&Autofyll-korger + + + Enable &Hosts + Skru på &vertar + + + Traffic Data Import + Trafikkdataimport + + + Linux Import Path: + Linux-importstig: + + + Windows Import Path: + Windows-importstig: + + + Note Cart String: + Notat-korgstreng: + + + Insert Voice Track String: + Set inn stemmesporstreng: + + + Cart Number: + Korgnummer: + + + Offset: + Avvik: + + + Length: + Lengd: + + + Title: + Tittel: + + + Start Time - Hours: + Starttid - timar: + + + Start Time - Minutes: + Starttid - minutt: + + + Start Time - Seconds: + Starttid - sekund: + + + Length - Hours: + Lengd - timar: + + + Length - Minutes: + Lengd - minutt: + + + Length - Seconds: + Lengd - sekund: + + + Contract #: + Kontrakt #: + + + Event ID: + Hendings-ID: + + + Annc. Type: + Annonseringstype: + + + Test +&Traffic + Test- +&trafikk + + + Music Data Import + Musikkdataimport + + + Insert Traffic Break String: + Set inn trafikkbrytestreng: + + + Test +&Music + Test- +&musikk + + + &OK + &OK + + + &Cancel + &Avbryt + + + Save Import Data + Lagre importdata + + + Before testing, the import configuration +must be saved. Save now? + Før du prøver ut, må du lagra oppsettet. +Lagre no? + + + Purge Logs after + + + + days + dagar + + + Purge ELR Data after + + + + Import Template: + + + + [custom] + + + + Linux Preimport Command: + + + + Windows Preimport Command: + + + + &Program Code: + + + + AutoSpot Group: + + + + Log Name &Template: + + + + Log &Description Template: + + + + + EditSvcPerms + + Service: + Tenest: + + + Available Hosts + Tilgjengelege vertar + + + Enabled Hosts + Vertar som er skrudde på + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditTtys + + Edit TTYs + Rediger TTYar + + + Port ID: + Port-ID: + + + Enabled + + + + TTY Device: + TTY-eining: + + + Baud Rate: + Baudrate: + + + Parity: + Paritet: + + + Data Bits: + Databitar: + + + Stop Bits: + Stoppbitar: + + + Terminator: + Terminator: + + + &Close + &Lukk + + + Serial + Seriell + + + None + Ingen + + + Even + Partal + + + Odd + Oddetal + + + CR + Retur/CR + + + LF + Linjemating/LF + + + CR/LF + CR/LF + + + + EditUser + + User: + Brukar: + + + &User Name: + Br&ukarnamn: + + + &Full Name: + &Fullt namn: + + + &Description: + &Skildring: + + + &Phone: + Tele&fon: + + + Allow Web Logins + Gje høve til pålogging frå nettet + + + Change +&Password + Endre +&passord + + + Administrative Rights + Administrative tilgangsrettar + + + Administer S&ystem + Administrer s&ystemet + + + Production Rights + Produksjons-tilgangsrettar + + + &Create Carts + &Lag korger + + + &Delete Carts + &Slett korger + + + &Modify Carts + &Endra korger + + + &Edit Audio + Endra &lyd + + + &Edit Netcatch Schedule + Endra &opptaksskjemaet + + + &Voicetrack Logs + S&temmespor-loggar + + + Traffic Rights + Trafikkrettar + + + Create &Log + Lag &Loggar + + + De&lete Log + &Slett loggar + + + Delete &Report Data + Slett &rapportdata + + + &Modify Template + Endra &malar + + + OnAir Rights + På lufta-rettar + + + &Playout Logs + S&peleloggar + + + &Rearrange Log Items + Snu om på loggoppfø&ringar + + + Add Log &Items + Legg t&il loggoppføringar + + + Delete Lo&g Items + Slett lo&ggoppføringar + + + Configure System Panels + Set opp systempanel + + + Podcasting Rights + Podkasting-rettar + + + Cre&ate Podcast + L&ag podkastar + + + E&dit Podcast + Re&diger podkastar + + + Dele&te Podcast + Sle&tt podkastar + + + Assign Group +Permissions + Styr gruppe- +tilgang + + + Assign Podcast Feed +Permissions + Styr podkastsraum- +tilgangsrettar + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditUserPerms + + User: + Brukar: + + + Available Groups + + + + Enabled Groups + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditVguestResource + + Engine (Hex): + Maskin (heksadesimal): + + + Device (Hex): + Eining (heksadesimal): + + + Surface (Hex): + Flate (heksadesimal): + + + Bus/Relay (Hex): + Buss/rele (heksadesimal): + + + &OK + &OK + + + &Cancel + &Avbryt + + + Edit vGuest Switch + Rediger vGuest-svitsj + + + Edit vGuest Display + Rediger vGuest-vising + + + Invalid Number + Ugyldig nummer + + + The Engine Number is Invalid! + Maskinnummeret er ugyldig! + + + The Device Number is Invalid! + Einingsnummeret er ugyldig! + + + The Surface Number is Invalid! + Flatenummeret er ugyldig! + + + The Bus/Relay Number is Invalid! + Buss/relenummeret er ugyldig! + + + + InfoDialog + + System Information + Systeminformasjon + + + Rivendell + Rivendell + + + A Radio Automation System + Eit radioautomasjonssystem + + + Version + Versjon + + + Database Schema + Databaseskjema + + + Copyright 2002-2007 + Copyright 2002-2007 + + + This program is free software, and comes with ABSOLUTELY NO WARRANTY, +not even the implied warranties of MERCHANTIBILITY or FITNESS FOR A +PARTICULAR PURPOSE. Touch the "View License" button for details. + Dette programmet er fri programvare, og har INGEN GARANTIAR,ikkje ein gong garantiar +som gjeld MOGLEIK FOR KJØP OG SAL eller om det er TURVANDE TIL NOKO FØREMÅL. +Klikk på "Lisens"-knappen for fleire opplysningar. + + + View +&License + Sjå +&Lisensen + + + &Close + &Lukk + + + Copyright 2002-2008 + Copyright 2002-2008 + + + Copyright 2002-2010 + Copyright 2002-2010 + + + Copyright 2002-2014 + Copyright 2002-2014 + + + + ListAuxFields + + Auxiliary Metadata Fields + + + + Var Name + + + + Caption + + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + Warning + + + + This will delete all data associated with this field! +Are you sure you want to continue? + + + + + ListDropboxes + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + Group + + + + Path + + + + Normalization Level + + + + Autotrim Level + + + + To Cart + + + + Use CartChunk ID + + + + Delete Cuts + + + + Metadata Pattern + + + + Fix Broken Formats + + + + [off] + + + + [auto] + + + + [none] + [ingen] + + + User Defined + + + + + ListEncoders + + RDAdmin - List Encoders + + + + Format Name + + + + Extension + + + + Valid Channels + + + + Valid Sample Rates + + + + Valid Bit Rates + + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + RDAdmin - Delete Encoder + + + + Are you sure you want to delete this encoder? + + + + This encoder is in use by the following RSS feeds: + + + + + + + +Do you still want to delete it? + + + + [none] + [ingen] + + + Encoders on + + + + + ListEndpoints + + List Inputs + List opp inngangar + + + List Outputs + List opp utgangar + + + INPUT + INNGANG + + + OUTPUT + UTGANG + + + LABEL + MERKE + + + SOURCE + KJELDE + + + MODE + MODUS + + + ENGINE (Hex) + MASKIN (heksadesimal) + + + DEVICE (Hex) + EINING (heksadesimal) + + + PROVIDER ID + TILBYDAR-ID + + + SERVICE ID + TENEST-ID + + + NODE + NODE + + + # + # + + + &Edit + R&ediger + + + &OK + &OK + + + &Cancel + &Avbryt + + + Stereo + Stereo + + + Left + Venstre + + + Right + Høgre + + + Input + Inngang + + + Output + Utgang + + + stereo + stereo + + + left + venstre + + + right + høgre + + + + ListFeeds + + Rivendell Feed List + + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + Key + + + + Title + Tittel + + + AutoPost + + + + Keep Metadata + + + + Creation Date + + + + &Feeds: + + + + Are you sure you want to delete feed + + + + Delete Feed + + + + Deleting Audio... + + + + Cancel + + + + Deleting + + + + + ListGpis + + List GPIs + List opp generelle inngangar + + + GPI Lines + GI-linjer + + + GPI + GI + + + MACRO CART + MAKROKORG + + + DESCRIPTION + SKILDRING + + + &Edit + R&ediger + + + &OK + &OK + + + &Cancel + &Avbryt + + + [unassigned] + [ikkje kopla til] + + + GPO Lines + + + + List GPOs + + + + GPO + + + + ON MACRO CART + + + + ON DESCRIPTION + + + + OFF MACRO CART + + + + OFF DESCRIPTION + + + + + ListGroups + + Rivendell Group List + Rivendell-gruppeliste + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Rename + &Døyp om + + + &Delete + &Slett + + + Generate +&Report + Lag +&rapport + + + &Close + &Lukk + + + NAME + NAMN + + + DESCRIPTION + SKILDRING + + + START CART + START KORG + + + END CART + SLUTT KORG + + + ENFORCE RANGE + TVING OMRÅDE + + + DEFAULT TYPE + STANDARDTYPE + + + TRAFFIC REPORT + TRAFIKKRAPPORT + + + MUSIC REPORT + MUSIKKRAPPORT + + + NOW & NEXT + NO & NESTE + + + &Groups: + &Grupper: + + + member carts will be deleted along with group + medlemskorger blir sletta saman med gruppa + + + Are you sure you want to delete group + Er du sikker på at du vil sletta gruppa + + + Delete Group + Slett gruppa + + + + ListHostvars + + Host Variables for + Vertsvariablar for + + + Host Variables + Vertsvariablar + + + NAME + NAMN + + + VALUE + VERDI + + + REMARK + MERKNAD + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &OK + &OK + + + &Cancel + &Avbryt + + + + ListLiveWireGpios + + LiveWire GPIO Source Assignments + + + + Switchers: + Svitsjarar: + + + &Edit + R&ediger + + + &OK + &OK + + + &Cancel + &Avbryt + + + [none] + [ingen] + + + Lines + + + + Surface Address + + + + [all] + + + + Source # + + + + + ListMatrices + + Rivendell Switcher List + Rivendell-svitsjarliste + + + Switchers: + Svitsjarar: + + + MATRIX + MATRISE + + + DESCRIPTION + SKILDRING + + + TYPE + TYPE + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + Are you sure you want to delete switcher + Er du sikker på at du vil sletta svitsjaren + + + on + + + + ALL references to this switcher will be deleted! + ALLE referansar til denne svitsjaren blir sletta! + + + Deleting Switcher + Slettar svitsjar + + + Local GPIO + Lokal Generell inn/ut + + + Generic GPO + Vanleg Generell ut + + + Generic Serial + Vanleg seriell + + + Local Audio Adapter + Lokalt lydkort + + + Logitek vGuest + Logitek vGuest + + + BroadcastTools SS16.4 + BroadcastTools SS16.4 + + + StarGuide III + StarGuide III + + + BroadcastTools SS4.2 + BroadcastTools SS4.2 + + + Axia LiveWire + Axia LiveWire + + + Quartz Type 1 + Quartz type 1 + + + Unknown + Ukjent + + + BroadcastTools SS4.4 + BroadcastTools SS4.4 + + + + ListReplicatorCarts + + &Repost + + + + Repost +&All + + + + &Close + &Lukk + + + CART + + + + TITLE + + + + LAST POSTED + + + + &Active Carts: + + + + Replicator Carts + + + + POSTED FILENAME + + + + + ListReplicators + + Rivendell Replicators + + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &List +Carts + + + + &Close + &Lukk + + + NAME + NAMN + + + TYPE + TYPE + + + DESCRIPTION + SKILDRING + + + HOST + + + + &Replicators: + + + + Are you sure you want to delete replicator + + + + Delete Replicator + + + + + ListReports + + Rivendell Report List + Rivendell-rapportliste + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + R&eports: + R&apportar: + + + Are you sure you want to delete report + Er du sikker på at du vil sletta rapporten + + + Delete Report + Slett rapporten + + + + ListStations + + Rivendell Workstation List + Rivendell-arbeidsstasjonliste + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + Ho&sts: + Ver&tar: + + + Are you sure you want to delete host + Er du sikker på at du vil sletta verten + + + Delete Station + Slett stasjonen + + + + ListSvcs + + Services + Tenester + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + &Services: + &Tenester: + + + Are you sure you want to delete service + Er du sikker på at du vil sletta tenesta + + + Delete Service + Slett tenesta + + + There are + Denne tenesta eig + + + logs owned by this service that will also be deleted. +Do you still want to proceed? + loggar som òg vil bli sletta. +Er du sikker på at du vil halda fram? + + + Logs Exist + Loggen eksisterer + + + + ListUsers + + Rivendell User List + Rivendell-brukarliste + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Close + &Lukk + + + &Users: + Br&ukarar: + + + Can't Delete User + Kan ikkje sletta brukar + + + You cannot delete yourself! + Du kan ikkje sletta deg sjølv! + + + Are you sure you want to delete user + Er du sikker på at du vil sletta brukaren + + + Delete User + Slett brukaren + + + USER NAME + + + + FULL NAME + + + + DESCRIPTION + SKILDRING + + + This user is set as the default user for the following hosts: + + + + + + You must change this before deleting the user. + + + + + Login + + Login + Logg inn + + + &OK + &OK + + + &Cancel + &Avbryt + + + User &Name: + Br&ukarnamn: + + + &Password: + &Passord: + + + + MainWidget + + RDAdmin - Host: + RDAdmin-vert: + + + Daemons Failed + Nissane vart ikkje starta + + + Unable to start Rivendell System Daemons! + Greidde ikkje starta Rivendell-systemnissane! + + + Insufficient Priviledges + Ikkje nok tilgangsrettar + + + This account has insufficient priviledges for this operation. + Denne brukarkontoen har ikkje nok tilgangsrettar til å gjera dette. + + + Manage +&Users + Styr +br&ukarar + + + Manage +&Groups + Styr +&grupper + + + Manage +&Services + Styr +Tene&ster + + + Manage +Ho&sts + Styr +ver&tar + + + Manage +R&eports + Styr +&Rapportar + + + Manage +&Feeds + Styr +str&aumar + + + System +Info + System- +info + + + Scheduler +Codes + Timeplan- +kodar + + + &Backup +Database + S&ikringskopier +databasen + + + &Restore +Database + Gjenopp&rett +databasen + + + &Quit + A&vslutt + + + Rivendell Database Backup (*.sql) + Rivendell databasesikring (*.sql) + + + Backup Error + Feil under sikring + + + Unable to create backup! + Greidde ikkje laga sikringskopi! + + + Backup Complete + Sikringa ferdig + + + Backup completed successfully. + Tok sikringskopi utan vanskar. + + + Restore Database + Gjenopprett database + + + WARNING: This operation will COMPLETELY +OVERWRITE the existing Rivendell Database! +Do you want to continue? + ÅTVARING: Dette vil OVERSKRIVA Rivendell- +databasen heilt! Er du sikker på at du vil halda fram? + + + Restore Error + Gjenopprettingsfeil + + + Unable to restore backup! + Greidde ikkje gjenoppretta sikringskopien! + + + Restore Complete + Gjennoppretting fullført + + + Restore completed successfully. + Gjenopprettinga vart fullført utan vanskar. + + + System +Settings + + + + Manage +Replicators + + + + RDAdmin + + + + + MySqlLogin + + mySQL Admin + mySQL-admin + + + User &Name: + Br&ukarnamn: + + + &Password: + &Passord: + + + &OK + &OK + + + &Cancel + &Avbryt + + + + QObject + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + Greier ikkje kopla til Rivendell-databasen! +Skriv inn eit brukarnamn til ein konto som har +rettar til å administrera mySQL-tenaren, +så prøver me å ordna opp i dette. + + + Wrong access permissions for accessing mySQL! + Feil tilgangsrettar for å kopla til mySQL! + + + Unable to connect to mySQL! + Greier ikkje kopla til mySQL! + + + Unable to create a Rivendell Database! + Greier ikkje laga ein Rivendell-database! + + + Unable to connect to new Rivendell Database! + Greier ikkje kopla til den nye Rivendell-databasen! + + + Unable to create Rivendell Database! + Greier ikkje laga ein Rivendell-database! + + + Unable to connect to Rivendell Database! + Greier ikkje kopla til Rivendell-databasen! + + + Unable to initialize Rivendell Database! + Greier ikkje setja opp Rivendell-databasen! + + + RDAdmin + + + + New Rivendell Database Created! + Du har laga ein ny Rivendell-database. + + + Unable to upgrade database + + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + Rivendell-databasen er for gamal til å oppgradera, +så han må bytast ut. Dette VIL ØYDELEGGJA alle +lyd- og datafiler! Viss du vil gjera dette, skriv du inn +eit brukarnamn og passord med administrasjons- +rettar for mySQL-kontoen. Viss ikkje, trykk avbryt. + + + Unable to log into Administrator account! + Greier ikkje logga på Administrator-kontoen! + + + Unable to authorize a Rivendell Database! + Greier ikkje godkjenna Rivendell-databasen! + + + Update Needed + Treng oppdatering + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + Rivendell-databasen treng ei oppdatering. +Alle lydfiler og innstillingar blir tekne vare på, +men dette VIL STOPPA alt opptak eller avspeling +på denne maskina i nokre sekund. Halda fram? + + + Unable to update Rivendell Database: + + + + +Database backup failed! + + + + +Schema modification failed! + + + + +Unknown/unspecified error! + + + + The Rivendell Database has been updated to version + + + + +and a backup of the original database saved in + + + + Database Updated + Databasen oppdatert + + + RDAdmin Error + + + + (default) + + + + Start Line 1 + + + + Stop Line 1 + + + + Pause Line 1 + + + + Start Line 2 + + + + Stop Line 2 + + + + Pause Line 2 + + + + Start Line 3 + + + + Stop Line 3 + + + + Pause Line 3 + + + + Start Line 4 + + + + Stop Line 4 + + + + Pause Line 4 + + + + Start Line 5 + + + + Stop Line 5 + + + + Pause Line 5 + + + + Start Line 6 + + + + Stop Line 6 + + + + Pause Line 6 + + + + Start Line 7 + + + + Stop Line 7 + + + + Pause Line 7 + + + + Add + + + + Delete + + + + Copy + + + + Move + + + + Sound Panel + + + + Main Log + Hovudlogg + + + Aux Log 1 + Hjelpelogg 1 + + + Aux Log 2 + Hjelpelogg 2 + + + + RenameGroup + + Rename Group + Døyp om gruppa + + + Current Group Name: + Gjeldande gruppenamn: + + + New &Group Name: + Nytt &gruppenamn: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Group + Ugyldig gruppe + + + The group name is invalid! + Gruppenamnet er ugyldig! + + + A + Ei + + + group already exists. +Do you want to combine the two? + gruppe eksisterer frå før. +Vil du kombinera desse to? + + + Group Exists + Gruppa eksisterer + + + + TestImport + + Test Traffic Import + Test trafikkrapport + + + Test Music Import + Test musikkrapport + + + Test Date: + Testdato: + + + &Select + &Vel + + + &Import + &Importer + + + Using source file: + Bruker kjeldefila: + + + Start Time + Starttid + + + Cart + Korg + + + Len + Len + + + Title + Tittel + + + Contract # + Kontrakt # + + + Event ID + Hendings-ID + + + Announcement Type + Annonseringstype + + + Imported Events + Importerte hendingar + + + &Close + &Lukk + + + Import Error + Importfeil + + + There was an error during import +please check your settings and try again. + Det vart ein feil under importen. +Sjekk oppsettet ditt og prøv att. + + + [spot break] + [spott-avbrot] + + + + ViewAdapters + + Audio Resource Information + Lydressursinformasjon + + + Audio Resources on + Lydressursar på + + + SUPPORTED AUDIO DRIVERS + + STØTTA LYDDRIVARAR + + + + SUPPORTED IMPORT FORMATS + + STØTTA IMPORTFORMAT + + + + PCM16 Linear + + Lineær PCM16 + + + MPEG Layer 1 + + MPEG lag 1 + + + + MPEG Layer 2 + + MPEG lag 2 + + + + MPEG Layer 3 + + MPEG lag 3 + + + + OggVorbis + + OggVorbis + + + + SUPPORTED EXPORT FORMATS + + STØTTA EKSPORTFORMAT + + + + Free Lossless Audio Codec (FLAC) + + Fri lydkodek utan tap (FLAC) + + + + AUDIO ADAPTERS + + LYDKORT + + + + Card + Kort + + + Not present + Ikkje til stades + + + Driver: AudioScience HPI + + Drivar: AudioScience HPI + + + + Driver: JACK Audio Connection Kit + + Drivar: JACK Audio Connection Kit + + + + Driver: Advanced Linux Sound Architecture (ALSA) + + Drivar: Advanced Linux Sound Architecture (ALSA) + + + + Driver: UNKNOWN + + Drivar: UKJENT + + + + Inputs: + Inngangar: + + + Outputs: + Utgangar: + + + NO DATA AVAILABLE + + + INGEN DATA FINST + + + + + Please start the Rivendell daemons on this host (by executing, as user 'root', the command "/etc/init.d/rivendell start") in order to populate the audio resources database. + Start Rivendell-nisseprogramma på denne verten ved å køyra kommandoen "/etc/init.d/rivendell-start" som root-brukaren for å fylla ut lydressursdatabasen. + + + &Close + &Lukk + + + diff --git a/rdadmin/rdadmin_pt_BR.ts b/rdadmin/rdadmin_pt_BR.ts new file mode 100644 index 00000000..483cfee3 --- /dev/null +++ b/rdadmin/rdadmin_pt_BR.ts @@ -0,0 +1,5816 @@ + + + @default + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + Não é possível acessar o Base de Dados do Rivendell! +Por Favor, insira uma autenticação para uma conta com +privilégios administrativos no servidor mySQL, +que resolveremos isso. + + + Can't Connect + Não foi possível conectar + + + Wrong access permissions for accessing mySQL! + Permissão errada de acesso ao mySQL! + + + Unable to connect to mySQL! + Não foi possível conectar ao mySQL! + + + Can't Create DB + Não foi possível criar um Banco de Dados + + + Unable to create a Rivendell Database! + Não foi possível criar um Base de Dados do Rivendell! + + + Unable to connect to new Rivendell Database! + Não foi possível conectar à nova Base de Dados do Rivendell! + + + Can't Create + Não foi possível criar + + + Unable to create Rivendell Database! + Não foi possível criar uma Base de Dados! + + + Unable to connect to Rivendell Database! + Não foi possível conectar ao Banco de Dados do Rivendell! + + + Can't Initialize + Não foi possível inicializar + + + Unable to initialize Rivendell Database! + Não foi possível inicializar a Base de Dados do Rivendell! + + + Created Database + Base de Dados Criada + + + New Rivendell Database Created! + Nova Base de Dados do Rivendell Criada! + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + A Base de Dados do Rivendell é muita velha para ser atualizada, +mas precisa ser substituída. Esta ação DESTRUIRÁ todos os +dados e arquivos de áudio!! Se você deseja fazer isso, +entre com um usuário e código de acesso para a conta mySQL +com privilégios administrativos, caso contrário, aperte cancelar. + + + Unable to log into Administrator account! + Não foi possível acessar na conta do Administrador! + + + Unable to authorize a Rivendell Database! + Não foi possível autorizar a Base de Dados do Rivendell! + + + + Update Needed + É Necessária a atualização + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + A Base de Dados do Rivendell precisa ser atualizada. +Todas as configurações de áudio serão preservadas, mas +esta ação PARARÁ por alguns segundos qualquer +áudio sendo tocado ou gravado nesta máquina. Continuar ? + + + Can't Update + Não foi possível atualizar + + + Unable to update Rivendell Database! + Não foi possível atualizar a Base de Dados do Rivendell! + + + The Rivendell Database has +been updated to Version + A Base de Dados do Rivendell foi +atualizada para a Versão + + + Database Updated + Base de Dados atualizada + + + + AddAuxField + + Add Aux Field + + + + Variable Name: + + + + %AUX_ + + + + % + + + + Caption: + + + + &OK + + + + &Cancel + &Cancelar + + + Name Exists + + + + That variable name already exists! + + + + + AddEncoder + + Add Encoder + + + + &New Encoder Name: + + + + &OK + + + + &Cancel + &Cancelar + + + Add Encoder Error + + + + A encoder with that name already exists! + + + + + AddFeed + + Add Feed + + + + Enable Feed for All Users + + + + &New Feed Name: + + + + &OK + + + + &Cancel + &Cancelar + + + Add Feed Error + + + + A feed with that key name already exists! + + + + + AddGroup + + Add Group + Adicionar Grupo + + + &New Group Name: + &Novo nome de Grupo: + + + Enable Group for All Users + Habilitar para todos os Usuários + + + Enable Group for All Services + Habilita para todos os Serviços + + + &OK + &OK + + + &Cancel + &Cancelar + + + Invalid Name + Nome Inválido + + + You must give the group a name! + Você deve dar nome ao Grupo! + + + Group Exists + Grupo existente + + + Group Already Exists! + Grupo já Existe! + + + + AddHostvar + + Add Host Variable + Adicionar Variável do Cliente + + + Variable Name: + Nome da Variável: + + + Variable Value: + Valor da Variável: + + + Remark: + Observação: + + + &OK + &OK + + + &Cancel + &Cancelar + + + Invalid Name + Nome Inválido + + + The variable name is invalid. + + + + + AddMatrix + + Add Switcher + Adicionar Switcher + + + &New Matrix Number: + &Novo Número Matrix: + + + Local GPIO + GPIO Local + + + Generic GPO + GPO Genérico + + + Generic Serial + Serial Genérico + + + Local Audio Adapter + Placa de Som Local + + + Logitek vGuest + Logitek vGuest + + + BroadcastTools SS16.4 + BroadcastTools SS16.4 + + + StarGuide III + StarGuide III + + + BroadcastTools SS4.2 + BroadcastTools SS4.2 + + + Axia LiveWire + Axia LiveWire + + + Quartz Type 1 + Quartz Type 1 + + + &Switcher Type: + Tipo de &Switcher: + + + &OK + &OK + + + &Cancel + &Cancelar + + + Invalid Matrix + Matrix Inválido + + + Matrix already exists! + Matrix já Existe! + + + BroadcastTools SS4.4 + BroadcastTools SS4.4 + + + New Switcher + + + + RDAdmin - Add Switcher + + + + + AddReplicator + + Add Replicator + + + + &New Replicator Name: + + + + &OK + + + + &Cancel + &Cancelar + + + Invalid Name + Nome Inválido + + + You must give the replicator a name! + + + + Replicator Exists + + + + A replicator with that name already exists! + + + + + AddReport + + Add Report + Adicionar Relatório + + + &Report Name: + Nome do &Relatório: + + + &OK + &OK + + + &Cancel + &Cancelar + + + Invalid Name + Nome Inválido + + + You must provide a report name! + Você deve dar nome ao Relatório! + + + Report Exists + Relatório existente + + + A report with that name already exists! + Um Relatório com este nome já Existe! + + + + AddStation + + Add Host + Adicionar Cliente + + + New &Host Name: + Nome do &Cliente: + + + Base Host On: + Basear Cliente em: + + + &OK + &OK + + + &Cancel + &Cancelar + + + Empty Host Config + Configuração Vazia + + + Invalid Name + Nome Inválido + + + You must give the host a name! + Você deve dar nome ao Cliente! + + + Host Exists + Cliente existente + + + Host Already Exists! + Cliente já Existe! + + + + AddSvc + + Add Service + Adicionar Serviço + + + &New Service Name: + &Novo nome de Serviço: + + + Base Service On: + Basear o Serviço no: + + + &OK + &OK + + + &Cancel + &Cancelar + + + Empty Host Config + Configuração vazia de Cliente + + + Invalid Name + Nome Inválido + + + You must give the service a name! + Você deve dar nome ao Serviço! + + + Service Exists + Serviço existente + + + Service Already Exists! + Serviço já Existe! + + + + AddUser + + Add User + Adicionar Usuário + + + &New User Name: + &Nome de Usuário: + + + &OK + &OK + + + &Cancel + &Cancelar + + + Invalid Name + Nome Inválido + + + You must give the user a name! + Você deve dar nome ao Usuário! + + + User Exists + Usuário existente + + + User Already Exists! + Usuário já Existe! + + + + AutofillCarts + + Autofill Carts - Service: + Carts de Preenchimento - Serviço: + + + Cart + Cartão + + + Length + Duração + + + Title + Título + + + Artist + Artista + + + &Add + &Adicionar + + + &Delete + &Deletar + + + &OK + &OK + + + &Cancel + &Cancelar + + + + EditAudioPorts + + Edit Audio Ports + Editar Portas de Áudio + + + Clock Source: + Fonte de Sincronia: + + + Input Port + Porta de entrada + + + Analog + Analógica + + + AES/EBU + AES/EBU + + + SP/DIFF + SP/DIFF + + + Type: + Tipo: + + + Normal + Normal + + + Swap + Inverter + + + Left only + Somente Canal Esquerdo + + + Right only + Somente Canal Direito + + + Mode: + Modo: + + + dB + dB + + + Level: + Nível: + + + Output Port + Porta de Saída + + + &Help + &Ajuda + + + &Close + &Fechar + + + Internal + Interno + + + AES/EBU Signal + Sinal AES/EBU + + + SP/DIFF Signal + Sinal SP/DIFF + + + Word Clock + Relógio Digital de Sincronia + + + Card: + Placa: + + + Card Driver: + + + + Ref. Level: + + + + + EditAuxField + + Edit Auxiliary Metadata Fields + + + + Variable Name: + + + + Caption: + + + + &OK + + + + &Cancel + &Cancelar + + + + EditBackup + + Backup config for + Configuração de cópia de Segurança para + + + Keep Backups For: + Guardar Backups por: + + + days + dias + + + Backup Directory: + Diretório do Backup: + + + &OK + &OK + + + &Cancel + &Cancelar + + + Path Missing + Está faltando o caminho + + + You must supply a backup path! + Você deve inserir um caminho para a cópia de segurança! + + + + EditCartSlots + + RDAdmin - Edit CartSlots + + + + Close + + + + None + Nenhum + + + Output Port: + + + + Card: + Placa: + + + Input Port: + + + + Cart + Cartão + + + Mode: + Modo: + + + Cart: + Cartão: + + + At Playout End: + + + + Channel Assignments + Configurações de Canais + + + Default Settings + + + + Select + + + + Load Specified Cart + + + + At Startup: + Ao Iniciar: + + + Do Nothing + + + + Slot Mode: + + + + Full + + + + Hook + + + + Play Mode: + + + + User previous mode + + + + Use previous mode + + + + Use previous cart + + + + Use previous action + + + + Service: + + + + Global Settings + + + + Slot Columns: + + + + Slot Rows: + + + + Slot + + + + Settings + Configurações + + + Slot selected has changed! + + + + + EditDecks + + Configure RDCatch + Configurar RDCatch + + + Record Deck + Gravação + + + None + Nenhum + + + Monitor Port: + Porta de Mon: + + + Off + Desligado + + + On + Ligado + + + Monitor defaults to + Monitor sempre + + + Format: + Formato: + + + Sample Rate: + Amostragem: + + + Bit Rate: + Taxa de Bits: + + + Switcher Host: + Switcher do Cliente: + + + Switcher Matrix: + Matrix do Switcher: + + + Switcher Output: + Saída do Switcher: + + + Switcher Delay: + Atraso do Switcher: + + + 1/10 sec + 1/10 segundos + + + Channels: + Canais: + + + Trim Threshold: + Valor Mínimo para Cortar: + + + Error RML: + RML de Erro: + + + Play Deck + Execução + + + Audition Deck + Disp. de Audição + + + &Close + &Fechar + + + No Audio Configuration Data + Áudio não Configurado + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Configurações de canais não estão disponível para este cliente pois recursos de dados +ainda não foram gerados. Por Favor, Inicie as processos constantes neste cliente +(executando, como usuário 'root', the command "/etc/init.d/rivendell start") +Isto para popular os recursos de áudio na Base de Dados. + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG Layer 2 + + + 32 kbps/chan + 32 kbps/chan + + + 48 kbps/chan + 48 kbps/chan + + + 56 kbps/chan + 56 kbps/chan + + + 64 kbps/chan + 64 kbps/chan + + + 80 kbps/chan + 80 kbps/chan + + + 96 kbps/chan + 96 kbps/chan + + + 112 kbps/chan + 112 kbps/chan + + + 128 kbps/chan + 128 kbps/chan + + + 160 kbps/chan + 160 kbps/chan + + + 192 kbps/chan + 192 kbps/chan + + + [none] + [Nenhum] + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Settings + Configurações + + + Defaults + Padrões + + + Host-Wide Settings + + + + + EditDropbox + + Dropbox Configuration + + + + Default Group: + + + + &Path Spec: + + + + Select + + + + To &Cart: + + + + Delete cuts before importing + + + + &Metadata Pattern: + + + + &Log File: + + + + Delete source files after import + + + + Normalize Levels + + + + Level: + Nível: + + + dBFS + + + + Autotrim Cuts + + + + Get cart number from CartChunk CutID + + + + Get cart title from CartChunk CutID + + + + Attempt to work around malformatted input files + + + + Offset start date by + + + + days + dias + + + Offset end date by + + + + Create Dates when no Dates Exist + + + + Create start date offset: + + + + Create end date offset: + + + + &OK + + + + &Cancel + &Cancelar + + + Invalid Offsets + + + + The Create EndDate Offset is less than the Create Start Date Offset! + + + + &User Defined: + + + + Scheduler Codes + + + + + EditEncoder + + RDAdmin - Edit Encoder + RDAdmin - Editar Codificador + + + Name: + Nome: + + + Allow Channels + Permita Canais + + + Allow Sample Rates + Permitir Taxas de Amostragem + + + Allow Bit Rates + Permitir Taxa de Bits + + + &OK + +&OK + + + &Cancel + &Cancelar + + + Default Extension: + + + + Command Line: + + + + + EditEndpoint + + Edit Input + Editar Entrada + + + Edit Output + Editar Saída + + + Name: + Nome: + + + Feed: + Feed: + + + Mode: + Modo: + + + Stereo + Estéreo + + + Left + Esquerda + + + Right + Direita + + + Engine (Hex): + Mecanismo (Hex): + + + Provider ID: + Identificação do Provedor: + + + Device (Hex): + Dispositivo (Hex): + + + Service ID: + Identificação do Serviço: + + + &OK + &OK + + + &Cancel + &Cancelar + + + Invalid Number + Número Inválido + + + The Engine Number is Invalid! + O Número do Mecanismo é inválido! + + + The Provider ID is Invalid! + A Identificação do Provedor é inválida! + + + The Device Number is Invalid! + O Número do Dispositivo é inválido! + + + The Service ID is Invalid! + A Identificação do Serviçor é inválida! + + + + EditFeed + + Feed: + Feed: + + + Key Name: + + + + CHANNEL VALUES + + + + Title: + Título: + + + Category: + + + + Link: + + + + Copyright: + + + + Webmaster: + + + + Language: + + + + Description: + Descrição: + + + Audio Upload URL: + + + + Username: + Usuário: + + + Password: + Senha: + + + Upload Format: + + + + S&et + + + + Normalize + + + + Level: + Nível: + + + dBFS + + + + Audio Download URL: + + + + Keep Expired Metadata + + + + Enable AutoPost + + + + Enclosure Preamble: + + + + Audio Extension: + + + + None + Nenhum + + + Maximum Shelf Life: + + + + days + dias + + + Descending + + + + Ascending + + + + Episode Sort Order: + + + + Direct + + + + Counted + + + + Media Link Mode: + + + + Enable Feed Redirection + + + + URL: + + + + Header XML: + + + + Channel XML: + + + + Item XML: + + + + &Define Auxiliary +Metadata Fields + + + + &OK + + + + &Cancel + &Cancelar + + + Edit Feed - Redirect + + + + Enabling feed redirection will cause clients subscribed to +this feed to be PERMANENTLY redirected to the +specified URL. + +Do you still want to enable redireciton? + + + + + EditFeedPerms + + User: + Usuário: + + + Available Feeds + + + + Enabled Feeds + + + + &OK + + + + &Cancel + &Cancelar + + + + EditGpi + + Edit GPI + Editar GPI + + + Cart Number: + Cartão: + + + &Select + &Sel + + + C&lear + &Limpar + + + Description: + Descrição: + + + &OK + &OK + + + &Cancel + &Cancelar + + + Invalid Cart + Cartão Inválido + + + Invalid Cart Number! + Númerodo Cartão Inválido! + + + + EditGroup + + Group: + Grupo: + + + &Group Name: + Nome do &Grupo: + + + Group &Description: + Descrição do &Grupo: + + + Default Import &Title: + &Tíltulo Padrão para Imp.: + + + Audio + Áudio + + + Macro + Macro + + + Default Cart &Type: + &Tipo Padrão de Cartão: + + + None + Nenhum + + + Default Cart Number: + Número de Cartões: + + + to + até + + + Enforce Cart Range + Force a Variação de Cartões + + + Include this group in Traffic reports + Incluir este Grupo no Relatório de Tráfego + + + Include this group in Music reports + Incluir este Grupo no Relatório de Músicas + + + Purge expired cuts after + Remover Conteúdos expirados depois de + + + days + dias + + + Transmit Now && Next data + Transmitir dados Agora && Próximo + + + C&olor + &Cor + + + &OK + &OK + + + &Cancel + &Cancelar + + + The selected cart range conflicts with the following groups: + + + A Variação de cartões selecionadas conflita com os seguintes Grupos: + + + + + +Do you still want to save? + +Você ainda quer salvar? + + + Delete cart if empty + + + + + EditHostvar + + Edit Host Variable + Editar Variável do Cliente + + + Variable Name: + :Nome da Variável: + + + Variable Value: + Valor da Variável: + + + Remark: + Observação: + + + &OK + &OK + + + &Cancel + &Cancelar + + + + EditHotkeys + + Host Hot Key Configurations + + + + Button / Function + + + + KeyStroke + + + + Set + + + + Clear + + + + Clear All Hotkeys + + + + Set From Host: + + + + Save + + + + Cancel + + + + Duplicate Entries + + + + Hotkeys Clear + + + + Hotkeys Updated + + + + No Items Selected + + + + Please Select an Item From the List + + + + Hot Key Configuration for + + + + + EditJack + + JACK Configuration for + + + + Start JACK Server + + + + JACK Server Name: + + + + &OK + + + + &Cancel + &Cancelar + + + JACK Command Line: + + + + NAME + NOME + + + VALUE + VALOR + + + REMARK + OBSERVAÇÃO + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + JACK Clients to Start: + + + + Client + + + + Command Line + + + + [New Client] + + + + RDAdmin - JACK Clients + + + + Are you sure you want to delete JACK Client + + + + + EditJackClient + + JACK Client Configuration for + + + + Description: + Descrição: + + + Command Line: + + + + &OK + + + + &Cancel + &Cancelar + + + + EditLiveWireGpio + + None + Nenhum + + + &OK + + + + &Cancel + &Cancelar + + + Edit GPIO Source + + + + Livewire Source: + + + + GPIO Lines + + + + Surface Address: + + + + Invalid IP Address + + + + The IP address is invalid! + + + + + EditMatrix + + Edit Switcher + Editar Switcher + + + Matrix Number: + Número Matrix: + + + Switcher Type: + Tipo de Switcher: + + + Description: + Descrição: + + + Primary Connection + Conexão Primária + + + Type: + Tipo: + + + + Serial + Serial + + + TCP/IP + TCP/IP + + + Serial Port: + Porta Serial: + + + IP Address: + Endereço do IP: + + + IP Port: + Porta do IP: + + + Username: + Usuário: + + + Password: + Senha: + + + Startup Cart: + Cartão de Partida: + + + Select + Selecionar + + + Shutdown Cart: + Cartão de Saída: + + + Backup Connection + Conexão da Cópia de Segurança + + + None + Nenhum + + + Card: + Placa: + + + Inputs: + Entradas: + + + Outputs: + Saídas: + + + Device: + Dispositivo: + + + GPIs: + GPIs: + + + GPOs: + GPOs: + + + Layer: + Camada: + + + Displays: + Exibições: + + + Configure +&Inputs + Configurar +&Entradas + + + Configure +&Outputs + Configurar +&Saídas + + + Configure +&Xpoints + Configurar +&PontosX + + + Configure +&GPIs + Configurar +&GPIs + + + Configure +G&POs + Configurar +&GPOS + + + LiveWire +Nodes + Nódulos +LiveWire + + + vGuest +Switches + vGuest +Switches + + + vGuest +Displays + vGuest +Displays + + + &OK + &OK + + + &Cancel + &Cancelar + + + Invalid Address + Endereço Inválido + + + The primary IP address is invalid! + O IP primário é inválido! + + + The backup IP address is invalid! + O IP da Cópia de Segurança é Inválido! + + + Duplicate Connections + Duplicar Conexões + + + The primary and backup connections must be different! + As conexões primárias e para cópias de segurança devem ser diferente! + + + SAS +Switches + + + + RDAdmin - Edit Switcher + + + + LiveWire +GPIOs + + + + + EditNowNext + + Edit Now & Next Data + Editar Agora & Próximo + + + Master Log + Lista Principal + + + IP Address: + Endereço de IP: + + + UDP Port: + Porta UDP: + + + UDP String: + String UDP: + + + RML: + RML: + + + Default Now Cart: + Cartão 'Agora': + + + Select + Sel + + + Default Next Cart: + Cartão 'Próximo': + + + Aux Log 1 + Lista Auxiliar 1 + + + Path + Caminho + + + Argument + Argumento + + + Loadable Modules: + Módulos Carregáveis: + + + Add + Adicionar + + + Edit + Editar + + + Delete + Deletar + + + &OK + &OK + + + &Cancel + &Cancelar + + + The IP address + Endereço de IP + + + is invalid! + é inválido! + + + Invalid Address + Endereço Inválido + + + Aux Log 2 + Lista Auxiliar 2 + + + + EditNowNextPlugin + + Edit Plugin + Editar Plugin + + + Plugin Path: + Pasta do Plugin: + + + Select + Sel + + + Argument: + Argumento: + + + &OK + &OK + + + &Cancel + &Cancelar + + + Select plugin + Selecionar Plugin + + + + EditRDAirPlay + + RDAirPlay config for + Configuração do RaDAr para + + + Channel Assignments + Configurações de Canais + + + Main Log Output 1 + Saída da Lista Principal 1 + + + Start RML: + RML iniciar: + + + Stop RML: + RML finalizar: + + + Main Log Output 2 + Saída da Lista Principal 2 + + + Aux Log 1 Output + Saída da Lista Auxiliar 1 + + + Aux Log 2 Output + Saída da Lista Auxiliar 2 + + + Audition/Cue Output + Saída de Audição/Cue + + + SoundPanel First Play Output + Saída do Painel de Som 1 + + + SoundPanel Second Play Output + Saída do Painel de Som 2 + + + SoundPanel Third Play Output + Saída do Painel de Som 3 + + + SoundPanel Fourth Play Output + Saída do Painel de Som 4 + + + SoundPanel Fifth and Later Play Output + Saída do Painel de Som 5 e adiante + + + Manual Segue: + Sobre Manual: + + + msecs + msecs + + + Forced Segue: + Sobre Forçado: + + + Pie Counts Last: + Rel. conta últimos: + + + secs + secs + + + Pie Counts To: + Relógio conta @: + + + Cart End + Fim do Cartão + + + Transition + Transição + + + Default Trans. Type: + Transição padrão: + + + Play + Simples + + + Segue + Sobre + + + Stop + Pare + + + Default Service: + Serviço Padrão: + + + Sound Panel Settings + Configurações do Painel + + + None + Nenhum + + + Host Panels: + Painéis Cliente: + + + User Panels: + Painéis Usuário: + + + Flash Active Buttons + Piscar Botões Ativos + + + Enable Button Pausing + Habilitar pausa pelo Botão + + + Label Template: + Modelo para Identificação: + + + Miscellaneous Settings + Configurações Diversas + + + Startup Mode: + Modo ao Iniciar: + + + Previous + Anterior + + + LiveAssist + ManuAuto + + + Automatic + Automático + + + Manual + Manual + + + Check TimeSync + Checar Sincronia + + + Show Auxlog 1 Button + Mostrar Botão Lista Aux1 + + + Show Auxlog 2 Button + Mostrar Botão Lista Aux2 + + + Clear Cart Search Filter + Limpar Filtro de Procura + + + Enable Paused Events + Habilitar Eventos Pausados + + + Space Bar Action + Ação da Barra de espaço + + + Start Next + Inicie Próxima + + + Configure Now && Next +Parameters + Configurar Parâmetros do +Agora && Próximo + + + + Start/Stop Settings + Configurações de Começar e Parar + + + Exit Password: + Senha para Sair: + + + Main Log + Lista Principal + + + start with empty log + Começar com Lista vazia + + + load previous log + Carregar Lista anterior + + + load specified log + Carregar Lista específica + + + At Startup: + Ao Iniciar: + + + Restart Log After Unclean Shutdown + Recomeçar Lista após Queda + + + Log: + Lista: + + + &Select + &Sel + + + Display Settings + Config. de Visualização + + + Background Image: + Imagem de Fundo: + + + Select + Sel + + + &OK + &OK + + + &Cancel + &Cancelar + + + No Audio Configuration Data + Não há dados de Configuração de Áudio + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Configurações de canais não estão disponível para este cliente pois recursos de dados +ainda não foram gerados. Por Favor, Inicie as processos constantes neste cliente +(executando, como usuário 'root', the command "/etc/init.d/rivendell start") +Isto para popular os recursos de áudio na Base de Dados. + + + [none] + [Nenhum] + + + Select Image File + Selecionar Arquivo de Imagem + + + Data Error + Erro de Dados + + + Invalid Segue Length! + Duração de Sobre Inválida! + + + Invalid Forced Segue Length! + Duração de Sobre Forçado Inválida! + + + Show Extra Buttons/Counters + + + + Audition Preroll: + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Configure Hot Keys + + + + Show Hour Selector + + + + Edit +GPIOs + + + + Title Template: + + + + Artist Template: + + + + Outcue Template: + + + + Description Template: + + + + Log Mode Control + + + + Mode Control Style: + + + + Unified + + + + Independent + + + + Main Log Startup Mode: + + + + Aux 1 Log Startup Mode: + + + + Aux 2 Log Startup Mode: + + + + + EditRDLibrary + + RDLibrary config for + Configuração do RDBiblio para + + + INPUT + ENTRADA + + + OUTPUT + SAÍDA + + + Settings + Configurações + + + &Max Record Time: + Tempo &máx de Grav: + + + &VOX Threshold: + Valor Mínimo de &VOX: + + + dbFS + dbFS + + + &AutoTrim Threshold: + Vol.Mínimo para &Corte: + + + &Tail Preroll: + &Espera para gravar: + + + milliseconds + millisegundos + + + &Ripper Device: + Dispositivo para &Extrair: + + + &Paranoia Level: + Nível do &Paranoia: + + + Ripper Level: + Nível de Extração: + + + &FreeDB Server: + Servidor &FreeDB: + + + &Format: + &Formato: + + + &Sample Rate: + &Taxa de Amostragem: + + + &Bitrate: + &Taxa de Bits: + + + No + Não + + + Yes + Sim + + + Allow E&xternal Editing: + Permitir Editor &Externo: + + + Defaults + Padrões + + + &Channels: + &Canais: + + + Record Mode: + Modo de Gravação: + + + AutoTrim: + Corte Automático: + + + &OK + &OK + + + &Cancel + &Cancelar + + + No Audio Configuration Data + Áudio não Configurado + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Configurações de canais não estão disponível para este cliente pois recursos de dados +ainda não foram gerados. Por Favor, Inicie as processos constantes neste cliente +(executando, como usuário 'root', the command "/etc/init.d/rivendell start") +Isto para popular os recursos de áudio na Base de Dados. + + + Normal + Normal + + + Low + Baixa + + + None + Nenhum + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG Layer 2 + + + Manual + Manual + + + VOX + VOX + + + 32 kbps/chan + 32 kbps/chan + + + 48 kbps/chan + 48 kbps/chan + + + 56 kbps/chan + 56 kbps/chan + + + 64 kbps/chan + 64 kbps/chan + + + 80 kbps/chan + 80 kbps/chan + + + 96 kbps/chan + 96 kbps/chan + + + 112 kbps/chan + 112 kbps/chan + + + 128 kbps/chan + 128 kbps/chan + + + 160 kbps/chan + 160 kbps/chan + + + 192 kbps/chan + 192 kbps/chan + + + 40 kbps/chan + 40 kbps/chan + + + 224 kbps/chan + 224 kbps/chan + + + 256 kbps/chan + 256 kbps/chan + + + 320 kbps/chan + 320 kbps/chan + + + Sample Rate Converter: + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Limit Searches at Startup + + + + Previous + Anterior + + + + EditRDLogedit + + RDLogedit config for + + + + INPUT + ENTRADA + + + OUTPUT + SAÍDA + + + Voice Tracker Settings + + + + &Max Record Time: + Tempo &máx de Grav: + + + &AutoTrim Threshold: + Vol.Mínimo para &Corte: + + + dbFS + dbFS + + + &Normalization Level: + + + + &Audio Margin: + + + + milliseconds + millisegundos + + + &Format: + &Formato: + + + &Bitrate: + &Taxa de Bits: + + + Play &Start Cart: + + + + Select + + + + Play &End Cart: + + + + &Record Start Cart: + + + + Re&cord End Cart: + + + + &Channels: + &Canais: + + + Default Transition: + + + + Play + Simples + + + Segue + Sobre + + + Stop + Pare + + + &OK + + + + &Cancel + &Cancelar + + + No Audio Configuration Data + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + PCM16 + PCM16 + + + MPEG Layer 2 + MPEG Layer 2 + + + 32 kbps/chan + 32 kbps/chan + + + 48 kbps/chan + 48 kbps/chan + + + 56 kbps/chan + 56 kbps/chan + + + 64 kbps/chan + 64 kbps/chan + + + 80 kbps/chan + 80 kbps/chan + + + 96 kbps/chan + 96 kbps/chan + + + 112 kbps/chan + 112 kbps/chan + + + 128 kbps/chan + 128 kbps/chan + + + 160 kbps/chan + 160 kbps/chan + + + 192 kbps/chan + 192 kbps/chan + + + 40 kbps/chan + 40 kbps/chan + + + 224 kbps/chan + 224 kbps/chan + + + 256 kbps/chan + 256 kbps/chan + + + 320 kbps/chan + 320 kbps/chan + + + No + Não + + + Yes + Sim + + + Enable &2nd Start Button: + + + + + EditRDPanel + + RDPanel config for + + + + Channel Assignments + Configurações de Canais + + + SoundPanel First Play Output + Saída do Painel de Som 1 + + + Start RML: + RML iniciar: + + + Stop RML: + RML finalizar: + + + SoundPanel Second Play Output + Saída do Painel de Som 2 + + + SoundPanel Third Play Output + Saída do Painel de Som 3 + + + SoundPanel Fourth Play Output + Saída do Painel de Som 4 + + + SoundPanel Fifth and Later Play Output + Saída do Painel de Som 5 e adiante + + + SoundPanel Cue Output + + + + Display Settings + Config. de Visualização + + + Background Image: + Imagem de Fundo: + + + Select + + + + Sound Panel Settings + Configurações do Painel + + + None + Nenhum + + + Host Panels: + Painéis Cliente: + + + User Panels: + Painéis Usuário: + + + Flash Active Buttons + Piscar Botões Ativos + + + Enable Button Pausing + Habilitar pausa pelo Botão + + + Clear Cart Search Filter + Limpar Filtro de Procura + + + Default Service: + Serviço Padrão: + + + Label Template: + Modelo para Identificação: + + + &OK + + + + &Cancel + &Cancelar + + + No Audio Configuration Data + + + + Channel assignments will not be available for this host, as audio resource data +has not yet been generated. Please start the Rivendell daemons on this host +(by executing, as user 'root', the command "/etc/init.d/rivendell start") +in order to populate the audio resources database. + Configurações de canais não estão disponível para este cliente pois recursos de dados +ainda não foram gerados. Por Favor, Inicie as processos constantes neste cliente +(executando, como usuário 'root', the command "/etc/init.d/rivendell start") +Isto para popular os recursos de áudio na Base de Dados. + + + [none] + [Nenhum] + + + Select Image File + Selecionar Arquivo de Imagem + + + + EditReplicator + + Replicator: + + + + Name: + Nome: + + + Description: + Descrição: + + + Type: + + + + Host System: + + + + Audio Upload URL: + + + + Username: + Usuário: + + + Password: + Senha: + + + Upload Format: + + + + S&et + + + + Normalize + + + + Level: + Nível: + + + dBFS + + + + Available Groups + + + + Active Groups + + + + &OK + + + + &Cancel + &Cancelar + + + + EditReport + + Edit Report + Editar Relatório + + + + &Report Description: + Descrição do &Relatório: + + + Export &Filter: + &Filtro de Exportação: + + + Station ID: + Identificação da Estação: + + + Cart Number Parameters: + Considerar Nº dos Cartões: + + + Use Leading Zeros + Usar Zeros no Início + + + Digits: + Dígitos: + + + Station Type: + Tipo de Estação: + + + Lines per Page: + Linhas por Página: + + + Ser&vice Name: + Nome do &Serviço: + + + Station &Format: + &Formato da Estação: + + + Linux Export Path: + Pasta de exp. - Linux: + + + Windows Export Path: + Pasta de exp. - Windows: + + + Export Event Types: + Tipos de Eventos para Exp: + + + Traffic + Sistema externo de Tráfego + + + Music + Sistema externo de Músicas + + + All + Todos + + + Export Events From: + Exportar Eventos de: + + + Traffic Log + de Tráfego + + + Music Log + de Músicas + + + No + Não + + + Yes + Sim + + + Include Only OnAir Events: + Somente que foram pro Ar: + + + Available Services + Serviços Disponíveis + + + Source Services + Fonte dos Serviços + + + Available Hosts + Clientes Disponíveis + + + Source Hosts + Fontes do Cliente + + + &OK + &OK + + + &Cancel + &Cancelar + + + Available Groups + + + + Allowed Groups + + + + Filter by Groups + + + + Filter by Daypart + + + + Start Time: + + + + End Time: + + + + + EditSettings + + System-Wide Settings + + + + System Sample Rate: + + + + samples/second + + + + Allow Duplicate Cart Titles + + + + ISCI Cross Reference Path: + + + + Maximum Remote Post Length: + + + + Mbytes + + + + The following duplicate titles must be corrected before "Allow Duplicate Values" can be turned off. + + + + CART + + + + TITLE + + + + &Save List + + + + &OK + + + + &Cancel + &Cancelar + + + File Exists + + + + The file " + + + + " exists. + +Overwrite? + + + + File Error + + + + Checking the Library for duplicates. + + + + Temporary Cart Group: + + + + + EditStation + + Host: + Cliente: + + + Ho&st Name: + Nome da &Cliente: + + + &Description: + &Descrição: + + + Default &User: + &Usuário Padrão: + + + Host + Cliente + + + User + Usuário + + + Security Model: + Modelo de Seg: + + + &IP Address: + Endereço do &IP: + + + Editor &Command: + &Editor : + + + mS + mS + + + &Time Offset: + Comp.&Tempo: + + + &Startup Cart: + Cartão de &Início: + + + Select + Sel + + + Enable Heartbeat + Habilitar Heartbeat + + + Use Realtime Filtering + Usar Filtagem em Tempo Real + + + Cart: + Cartão: + + + Interval: + Intervalo: + + + secs + segs + + + Include in System Maintenance Pool + Incluir no Grupo de Manutenção do Sistema + + + RD&Library + &RDBiblio + + + RDCatch + RDCaptura + + + RDAirPlay + RaDAr + + + RDPanel + RDPainel + + + RDLogEdit + RDListas + + + Dropboxes + Importadores + + + Switchers +GPIO + Switcher +GPIO + + + Host +Variables + Variáveis +do Cliente + + + Audio +Ports + Portas de +Áudio + + + Serial +Ports + Portas +Serial + + + Audio +Resources + Recuros de +Áudio + + + Custom +Encoders + Codificadores + + + + Backups + Cópias de +Segurança + + + &OK + &OK + + + &Cancel + &Cancelar + + + System Maintenance + Manutenção do Sistema + + + At least one host must belong to the system maintenance pool! + Ao menos um Cliente deve pertencer ao grupo de manutenção do Sistema! + + + Invalid Address + Endereço Inválido + + + The specified IP address is invalid! + O IP especificado é inválido! + + + Invalid Cart + Cartão Inválido + + + The Heartbeat Cart number is invalid! + O Número do Cartão de Batimento de Coração é inválido! + + + HTTP Xport: + + + + Core Audio Engine: + + + + System Services + + + + JACK +Settings + + + + RDCart +Slots + + + + Cue &Output: + + + + RDAdmin - No Audio Configuration Data + + + + Channel assignments will not be available for this host as audio resource data +has not yet been generated. Please start the Rivendell daemons on the host +configured to run the CAE service in order to populate the audio resources database. + + + + Enable Drag && Drop + + + + Allow Drops on Panels not in Setup Mode + + + + Start Cart + + + + Stop Cart + + + + + EditSvc + + Edit Service + Editar Serviço + + + &Service Name: + Nome do &Serviço: + + + Service &Description: + Descrição do &Serviço: + + + Log &Template Name: + &Modelo Nome Listas: + + + [none] + [Nenhum] + + + Voicetrack Group: + Grupo da Faixa de Voz: + + + Insert CHAIN TO at log end + Inserir Corrente ao fim da Lista + + + Enable AutoRefresh By Default + Auto-atualização por Padrão + + + Configure +&Autofill Carts + Configurar &Cartões +de Preenchimento + + + Purge Logs after + Remover Lista após + + + days + dias + + + Purge ELR Data after + Remover Dados ELR após + + + Enable &Hosts + Habilitar &Clientes + + + Traffic Data Import + Dados de Tráfego + + + Linux Import Path: + Pasta de importação - Linux: + + + Windows Import Path: + Pasta de imp. - Windows: + + + Note Cart String: + Cartão para Nota de Série: + + + Insert Voice Track String: + Inserir Série da Faixa de Voz: + + + Cart Number: + Número do Cartão: + + + Offset: + Offset: + + + Length: + Duração: + + + Title: + Título: + + + Start Time - Hours: + Começar - Horas: + + + Start Time - Minutes: + Começar - Minutos: + + + Start Time - Seconds: + Começar - Segundos: + + + Length - Hours: + Duração - Horas: + + + Length - Minutes: + Duração - Minutos: + + + Length - Seconds: + Duração - Segundos: + + + Contract #: + Contrato #: + + + Event ID: + ID do Evento: + + + Annc. Type: + Anúncio Tipo: + + + Test +&Traffic + Testar +&Tráfego + + + Music Data Import + Dados de Músicas + + + Insert Traffic Break String: + Ins. Série de Break Tráfego: + + + Test +&Music + Testar +&Músicas + + + &OK + &OK + + + &Cancel + &Cancelar + + + Save Import Data + Salvar Dados de Importação + + + Before testing, the import configuration +must be saved. Save now? + Antes de testar, a configuração de importação +deve ser salva. Salvar Agora? + + + &Program Code: + + + + Linux Preimport Command: + + + + Windows Preimport Command: + + + + Import Template: + + + + [custom] + + + + AutoSpot Group: + + + + Log Name &Template: + + + + Log &Description Template: + + + + + EditSvcPerms + + Service: + Identificação do Serviço: + + + Available Hosts + Clientes Disponíveis + + + Enabled Hosts + Clientes Habilitados + + + &OK + &OK + + + &Cancel + &Cancelar + + + + EditTtys + + Edit TTYs + Editar TTYs + + + Port ID: + ID: + + + Enabled + Habilitado + + + TTY Device: + Dispositivo TTY: + + + Baud Rate: + Taxa de Baud: + + + Parity: + Paridade: + + + Data Bits: + Bits de Dados: + + + Stop Bits: + Bits de Parada: + + + Terminator: + Exterminador: + + + &Close + &Fechar + + + Serial + Serial + + + None + Nenhum + + + Even + Par + + + Odd + Ímpar + + + CR + CR + + + LF + LF + + + CR/LF + CR/LF + + + + EditUser + + User: + Usuário: + + + &User Name: + &Usuário: + + + &Full Name: + Nome &Real: + + + &Description: + &Descrição: + + + &Phone: + &TEL: + + + Allow Web Logins + Permitir Login Online + + + Change +&Password + Mudar +&Senha + + + Administrative Rights + Direitos Administrativos + + + Administer S&ystem + Administrar o &Sistema + + + Production Rights + Direitos de Produção + + + &Create Carts + &Criar Cartões + + + &Delete Carts + &Deletar Cartões + + + &Modify Carts + &Modificar Cartões + + + &Edit Audio + &Editar Áudio + + + &Edit Netcatch Schedule + &Editar Netcatch Schedule + + + &Voicetrack Logs + Listas de &Faixa de Voz: + + + Traffic Rights + Direitos de Tráfego + + + Create &Log + &Criar Listas + + + De&lete Log + &Deletar Listas + + + Delete &Report Data + Deletar Dados de Relatórios + + + &Modify Template + &Modificar Modelos + + + OnAir Rights + Direitos no Ar + + + &Playout Logs + Tocar Listas + + + &Rearrange Log Items + Modificar Itens de Listas + + + Add Log &Items + Adicionar &Itens em Listas + + + Delete Lo&g Items + Deletar Itens de Listas + + + Configure System Panels + Configurar Paineis do Sistema + + + Podcasting Rights + Direitos de Podcasts + + + Cre&ate Podcast + &Criar Podcasts + + + E&dit Podcast + &Editar Podcasts + + + Dele&te Podcast + &Deletar Podcasts + + + Assign Group +Permissions + Determinar Permissões +de Grupo + + + Assign Podcast Feed +Permissions + Determinar Permissões de +Feeds de Podcasts + + + &OK + &OK + + + &Cancel + &Cancelar + + + + EditUserPerms + + User: + Usuário: + + + Available Groups + + + + Enabled Groups + + + + &OK + + + + &Cancel + &Cancelar + + + + EditVguestResource + + Engine (Hex): + Mecanismo (Hex): + + + Device (Hex): + Dispositivo (Hex): + + + Surface (Hex): + Surface (Hex): + + + Bus/Relay (Hex): + Bus/Relay (Hex): + + + &OK + &OK + + + &Cancel + &Cancelar + + + Edit vGuest Switch + Editar vGuest Switch + + + Edit vGuest Display + Editar Visualização do vGuest + + + Invalid Number + Número Inválido + + + The Engine Number is Invalid! + O Número do Mecanismo é inválido! + + + The Device Number is Invalid! + O Número do Dispositivo é inválido! + + + The Surface Number is Invalid! + O Número da surface é inválido! + + + The Bus/Relay Number is Invalid! + O Número do Bus/Relay é inválido! + + + + InfoDialog + + System Information + Informação do Sistema + + + Rivendell + Rivendell + + + A Radio Automation System + Automação para Rádios + + + Version + Versão + + + Database Schema + Schema da Base de Dados + + + Copyright 2002-2008 + Copyright 2002-2009 + + + This program is free software, and comes with ABSOLUTELY NO WARRANTY, +not even the implied warranties of MERCHANTIBILITY or FITNESS FOR A +PARTICULAR PURPOSE. Touch the "View License" button for details. + Este Programa e um Software Livre, a não ABSOLUTAMENTE NENHUMA GARANTIA, +nem mesmo as garantias de COMERCIALIZAÇÃO ou de ADEQUAÇÃO PARA ALGUMA +FINALIDADE PARTICULAR. Aperte o botão VER LICENÇA para mais detalhes. + + + View +&License + Ver +&Licença + + + &Close + &Fechar + + + Copyright 2002-2010 + Copyright 2002-2009 {2002-2010?} + + + Copyright 2002-2014 + Copyright 2002-2009 {2002-2014?} + + + + ListAuxFields + + Auxiliary Metadata Fields + + + + Var Name + + + + Caption + + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &Close + &Fechar + + + Warning + + + + This will delete all data associated with this field! +Are you sure you want to continue? + + + + + ListDropboxes + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &Close + &Fechar + + + Group + + + + Path + Caminho + + + Normalization Level + + + + Autotrim Level + + + + To Cart + + + + Use CartChunk ID + + + + Delete Cuts + + + + Metadata Pattern + + + + Fix Broken Formats + + + + [off] + + + + [auto] + + + + [none] + [Nenhum] + + + User Defined + + + + + ListEncoders + + RDAdmin - List Encoders + RDAdmin - Listar Codificadores + + + + Format Name + Formato + + + Extension + Extensão + + + Valid Channels + Canais Válidos + + + Valid Sample Rates + Taxas de Amostragem + + + Valid Bit Rates + Taxa de Bits Válidas + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &Close + &Fechar + + + RDAdmin - Delete Encoder + RDAdmin - Deletar Codificador + + + Are you sure you want to delete this encoder? + Tem certeza que quer deletar este codificador? + + + This encoder is in use by the following RSS feeds: + + + Este Codificador está em uso pelo Feed RRS: + + + + + + +Do you still want to delete it? + +Você ainda quer Deletar? + + + [none] + [Nenhum] + + + Encoders on + + + + + ListEndpoints + + List Inputs + Listar Entradas + + + List Outputs + Listar Saídas + + + INPUT + ENTRADA + + + OUTPUT + SAÍDA + + + LABEL + IDENTIFICAÇÃO + + + SOURCE + FONTE + + + MODE + MODO + + + ENGINE (Hex) + MECANISMO (Hex) + + + DEVICE (Hex) + DISPOSITIVO (Hex) + + + PROVIDER ID + PROVEDOR DE ID + + + SERVICE ID + ID DO SERVIÇO + + + NODE + NÓDULO + + + # + # + + + &Edit + &Editar + + + &OK + &OK + + + &Cancel + &Cancelar + + + Stereo + Estéreo + + + Left + Esquerda + + + Right + Direita + + + Input + Entrada + + + Output + Saída + + + stereo + Estéreo + + + left + esquerda + + + right + direita + + + + ListFeeds + + Rivendell Feed List + + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &Close + &Fechar + + + Key + + + + Title + Título + + + AutoPost + + + + Keep Metadata + + + + Creation Date + + + + &Feeds: + + + + Are you sure you want to delete feed + + + + Delete Feed + + + + Deleting Audio... + + + + Cancel + + + + Deleting + + + + + ListGpis + + GPI Lines + Linhas GPI + + + List GPIs + Listar GPIs + + + GPO Lines + Linhas GPO + + + List GPOs + Listar GPOs + + + GPI + GPI + + + GPO + GPO + + + ON MACRO CART + CARTÃO MACRO PARA LIGAR + + + ON DESCRIPTION + DESCRIÇÃO DE LIGAR + + + OFF MACRO CART + CARTÃO MACRO PARA DESLIGAR + + + OFF DESCRIPTION + DESCRIÇÃO DE DESLIGAR + + + &Edit + &Editar + + + &OK + &OK + + + &Cancel + &Cancelar + + + [unassigned] + Não Configurado + + + + ListGroups + + Rivendell Group List + Lista de Grupos do Rivendell + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Rename + &Renomear + + + &Delete + &Deletar + + + Generate +&Report + Gerar +&Relatório + + + &Close + &Fechar + + + NAME + NOME + + + DESCRIPTION + DESCRIÇÃO + + + START CART + INÍCIO DOS CARTÕES + + + END CART + FIM DOS CARTÕES + + + ENFORCE RANGE + FORÇAR VARIAÇÃO + + + DEFAULT TYPE + TIPO PADRÃO + + + TRAFFIC REPORT + RELATÓRIO DE TRÁFEGO + + + MUSIC REPORT + RELATÓRIO DE MÚSICAS + + + NOW & NEXT + AGORA & PRÓXIMO + + + &Groups: + &Grupos: + + + member carts will be deleted along with group + Cartões do Grupo serão deletados junto com o Grupo + + + Are you sure you want to delete group + Tem certeza que quer deletar este grupo? + + + Delete Group + Deletar Grupo + + + + ListHostvars + + Host Variables for + Variáveis de Cliente para + + + Host Variables + Variáveis de Cliente + + + NAME + NOME + + + VALUE + VALOR + + + REMARK + OBSERVAÇÃO + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &OK + &OK + + + &Cancel + &Cancelar + + + + ListLiveWireGpios + + LiveWire GPIO Source Assignments + + + + Switchers: + Switchers: + + + &Edit + &Editar + + + &OK + + + + &Cancel + &Cancelar + + + [none] + [Nenhum] + + + Lines + + + + Surface Address + + + + [all] + + + + Source # + + + + + ListMatrices + + Rivendell Switcher List + Lista de Switchers do Rivendell + + + Switchers: + Switchers: + + + MATRIX + MATRIX + + + DESCRIPTION + DESCRIÇÃO + + + TYPE + TIPO + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &Close + &Fechar + + + Are you sure you want to delete switcher + Tem certeza que quer deletar este switcher? + + + on + Ligado + + + ALL references to this switcher will be deleted! + TODAS as referências deste switcher serão deletadas + + + Deleting Switcher + Deletando Switcher + + + Local GPIO + GPIO Local + + + Generic GPO + GPO Genérico + + + Generic Serial + Serial Genérico + + + Local Audio Adapter + Placa de Som Local + + + Logitek vGuest + Logitek vGuest + + + BroadcastTools SS16.4 + BroadcastTools SS16.4 + + + StarGuide III + StarGuide III + + + BroadcastTools SS4.2 + BroadcastTools SS4.2 + + + Axia LiveWire + Axia LiveWire + + + Quartz Type 1 + Quartz Type 1 + + + Unknown + Desconhecido + + + BroadcastTools SS4.4 + BroadcastTools SS4.4 + + + + ListReplicatorCarts + + &Repost + + + + Repost +&All + + + + &Close + &Fechar + + + CART + + + + TITLE + + + + LAST POSTED + + + + &Active Carts: + + + + Replicator Carts + + + + POSTED FILENAME + + + + + ListReplicators + + Rivendell Replicators + + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &List +Carts + + + + &Close + &Fechar + + + NAME + NOME + + + TYPE + TIPO + + + DESCRIPTION + DESCRIÇÃO + + + HOST + + + + &Replicators: + + + + Are you sure you want to delete replicator + + + + Delete Replicator + + + + + ListReports + + Rivendell Report List + Lista de Relatórios do Rivendell + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &Close + &Fechar + + + R&eports: + &Relatórios: + + + Are you sure you want to delete report + Tem certeza que quer deletar este Relatório? + + + Delete Report + Deletar Relatório + + + + ListStations + + Rivendell Workstation List + Lista de Estações de Trabalho do Rivendell + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &Close + &Fechar + + + Ho&sts: + &Clientes: + + + Are you sure you want to delete host + Tem certeza que quer deletar este Cliente? + + + Delete Station + Deletar Estação + + + + ListSvcs + + Services + Serviços + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &Close + &Fechar + + + &Services: + &Serviços: + + + Are you sure you want to delete service + Tem certeza que quer deletar este Serviço? + + + Delete Service + Deletar Serviço + + + There are + + + + logs owned by this service that will also be deleted. +Do you still want to proceed? + listas pertencentes a este serviço que serão deletadas também. +Você quer proceder? + + + Logs Exist + Lista Existente + + + + ListUsers + + Rivendell User List + Lista de Usuários do Rivendell + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &Close + &Fechar + + + USER NAME + USUÁRIO + + + FULL NAME + NOME COMPLETO + + + DESCRIPTION + DESCRIÇÃO + + + &Users: + &Usuários: + + + Delete User + Deletar Usuário + + + You cannot delete yourself! + Você não pode se deletar! + + + This user is set as the default user for the following hosts: + + + Este usuário é o padrão para os seguintes clientes: + + + + + You must change this before deleting the user. + Você deve mudar isto antes de deletar o usuário. + + + Are you sure you want to delete user + Tem certeza que quer deletar este Usuário? + + + + Login + + Login + Administrar + + + &OK + &OK + + + &Cancel + &Cancelar + + + User &Name: + &Usuário: + + + &Password: + &Senha: + + + + MainWidget + + RDAdmin - Host: + RDAdmin - Cliente: + + + Daemons Failed + Daemons Falharam + + + Unable to start Rivendell System Daemons! + Não foi possível iniciar os daemons do Rivendell! + + + Insufficient Priviledges + Privilégios Insuficientes + + + This account has insufficient priviledges for this operation. + Esta Conta não tem privilégios suficientes para esta operação. + + + Manage +&Users + Gerenciar +&Usuários + + + Manage +&Groups + Gerenciar +&Grupos + + + Manage +&Services + Gerenciar +&Serviços + + + Manage +Ho&sts + Gerenciar +&Clientes + + + Manage +R&eports + Gerenciar +&Relatórios + + + Manage +&Feeds + Gerenciar +&Feeds + + + System +Info + Informações +do Sistema + + + Scheduler +Codes + Códigos do +Agendador + + + &Backup +Database + &Backup +mySQL + + + &Restore +Database + &Recuperar +mySQL + + + &Quit + &Sair + + + Rivendell Database Backup (*.sql) + Backup da Base de Dados do Rivendell (*.sql) + + + Backup Error + Erro no Backup + + + Unable to create backup! + Não foi possível criar o Backup! + + + Backup Complete + Backup Completo + + + Backup completed successfully. + Backup realizado com sucesso. + + + Restore Database + Recuperar Base de Dados + + + WARNING: This operation will COMPLETELY +OVERWRITE the existing Rivendell Database! +Do you want to continue? + ATENÇÃO: Esta operação SOBRESCREVERÁ +COMPLETAMENTE a Base de Dados Existente! +Você quer continuar? + + + Restore Error + Erro ao Recuperar + + + Unable to restore backup! + Não foi possível Recuperar o Backup! + + + Restore Complete + Recuperação Completa + + + Restore completed successfully. + Recuperação realizado com sucesso. + + + System +Settings + + + + Manage +Replicators + + + + RDAdmin + + + + + MySqlLogin + + mySQL Admin + mySQL Admin + + + User &Name: + Usuário &Nome: + + + &Password: + &Senha: + + + &OK + &OK + + + &Cancel + &Cancelar + + + + QObject + + Unable to access the Rivendell Database! +Please enter a login for an account with +administrative rights on the mySQL server, +and we will try to get this straightened out. + Não é possível acessar o Base de Dados do Rivendell! +Por Favor, insira uma autenticação para uma conta com +privilégios administrativos no servidor mySQL, +que resolveremos isso. + + + Wrong access permissions for accessing mySQL! + Permissão errada de acesso ao mySQL! + + + Unable to connect to mySQL! + Não foi possível conectar ao mySQL! + + + Unable to create a Rivendell Database! + Não foi possível criar um Base de Dados do Rivendell! + + + Unable to connect to new Rivendell Database! + Não foi possível conectar à nova Base de Dados do Rivendell! + + + Unable to create Rivendell Database! + Não foi possível criar uma Base de Dados! + + + Unable to connect to Rivendell Database! + Não foi possível conectar ao Banco de Dados do Rivendell! + + + Unable to initialize Rivendell Database! + Não foi possível inicializar a Base de Dados do Rivendell! + + + RDAdmin + + + + New Rivendell Database Created! + Nova Base de Dados do Rivendell Criada! + + + Unable to upgrade database + + + + The Rivendell Database is too old to be upgraded, +and so must be replaced. This will DESTROY any +existing audio and data! If you want to do this, +enter a username and password for a mySQL account +with administrative privledges, otherwise hit cancel. + A Base de Dados do Rivendell é muita velha para ser atualizada, +mas precisa ser substituída. Esta ação DESTRUIRÁ todos os +dados e arquivos de áudio!! Se você deseja fazer isso, +entre com um usuário e código de acesso para a conta mySQL +com privilégios administrativos, caso contrário, aperte cancelar. + + + Unable to log into Administrator account! + Não foi possível acessar na conta do Administrador! + + + Unable to authorize a Rivendell Database! + Não foi possível autorizar a Base de Dados do Rivendell! + + + + Update Needed + É Necessária a atualização + + + The Rivendell Database needs to be updated. +All audio and settings will be preserved, but +this will STOP any audio playout or recording +on this machine for a few seconds. Continue? + A Base de Dados do Rivendell precisa ser atualizada. +Todas as configurações de áudio serão preservadas, mas +esta ação PARARÁ por alguns segundos qualquer +áudio sendo tocado ou gravado nesta máquina. Continuar ? + + + Unable to update Rivendell Database: + + + + +Database backup failed! + + + + +Schema modification failed! + + + + +Unknown/unspecified error! + + + + The Rivendell Database has been updated to version + + + + +and a backup of the original database saved in + + + + Database Updated + Base de Dados atualizada + + + RDAdmin Error + + + + (default) + + + + Start Line 1 + + + + Stop Line 1 + + + + Pause Line 1 + + + + Start Line 2 + + + + Stop Line 2 + + + + Pause Line 2 + + + + Start Line 3 + + + + Stop Line 3 + + + + Pause Line 3 + + + + Start Line 4 + + + + Stop Line 4 + + + + Pause Line 4 + + + + Start Line 5 + + + + Stop Line 5 + + + + Pause Line 5 + + + + Start Line 6 + + + + Stop Line 6 + + + + Pause Line 6 + + + + Start Line 7 + + + + Stop Line 7 + + + + Pause Line 7 + + + + Add + Adicionar + + + Delete + Deletar + + + Copy + + + + Move + + + + Sound Panel + + + + Main Log + Lista Principal + + + Aux Log 1 + Lista Auxiliar 1 + + + Aux Log 2 + Lista Auxiliar 2 + + + + RenameGroup + + Rename Group + Renomear Grupo + + + Current Group Name: + Nome do Grupo Atual: + + + New &Group Name: + Novo &Nome de Grupo: + + + &OK + &OK + + + &Cancel + &Cancelar + + + Invalid Group + Grupo Inválido + + + The group name is invalid! + O Nome do Grupo é inválido! + + + A + Um + + + group already exists. +Do you want to combine the two? + grupo já existe. Você gostaria de Unir os dois? + + + Group Exists + Grupo Existente + + + + TestImport + + Test Traffic Import + Testar Importação de Tráfego + + + Test Music Import + Testar Importação de Músicas + + + Test Date: + Testar Data: + + + &Select + &Sel + + + &Import + &Importar + + + Using source file: + Usando arquivo de fonte: + + + Start Time + Hora de Início + + + Cart + Cartão + + + Len + Duração + + + Title + Título + + + Contract # + Contrato #: + + + Event ID + ID do Evento + + + Announcement Type + Tipo de Anunciante + + + Imported Events + Eventos Importados + + + &Close + &Fechar + + + Import Error + Erro ao Importar + + + There was an error during import +please check your settings and try again. + Houve um Erro ao importar +por favor, cheque suas configurações e tente novamente + + + [spot break] + [spot break] + + + + ViewAdapters + + Audio Resource Information + Informação dos Recusrsos de Áudio + + + Audio Resources on + Recuros de Áudio em + + + SUPPORTED AUDIO DRIVERS + + DRIVERS DE ÁUDIO SUPORTADOS + + + + SUPPORTED IMPORT FORMATS + + FORMATOS SUPORTADOS PARA IMPORTAÇÃO + + + + PCM16 Linear + + PCM16 Linear + + + + + MPEG Layer 1 + + MPEG Layer 1 + + + + MPEG Layer 2 + + MPEG Layer 2 + + + + MPEG Layer 3 + + MPEG Layer 3 + + + + OggVorbis + + OggVorbis + + + + SUPPORTED EXPORT FORMATS + + FORMATOS SUPORTADOS PARA EXPORTAÇÃO + + + + Free Lossless Audio Codec (FLAC) + + Free Lossless Audio Codec (FLAC) + + + + AUDIO ADAPTERS + + PLACAS DE SOM + + + Card + Placa + + + Not present + Não há + + + Driver: AudioScience HPI + + Driver: AudioScience HPI + + + + Driver: JACK Audio Connection Kit + + Driver: JACK Audio Connection Kit + + + + Driver: Advanced Linux Sound Architecture (ALSA) + + Driver: Advanced Linux Sound Architecture (ALSA) + + + + Driver: UNKNOWN + + Driver: Desconhecido + + + + Inputs: + Entradas: + + + Outputs: + Saídas: + + + NO DATA AVAILABLE + + + NÃO HÁ DADOS DISPONÍVEIS + + + Please start the Rivendell daemons on this host (by executing, as user 'root', the command "/etc/init.d/rivendell start") in order to populate the audio resources database. + Por Favor, Inicie os 'daemons' do Rivendell neste Cliente (executando, como 'root' o comando "/etc/init.d/rivendell start"). isso proverá a Base de Dados com as informações de Áudio. + + + &Close + &Fechar + + + diff --git a/rdadmin/rename_group.cpp b/rdadmin/rename_group.cpp new file mode 100644 index 00000000..54014167 --- /dev/null +++ b/rdadmin/rename_group.cpp @@ -0,0 +1,283 @@ +// rename_group.cpp +// +// Rename a Rivendell Group +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rename_group.cpp,v 1.14 2010/08/03 16:26:03 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +RenameGroup::RenameGroup(QString group,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + group_name=group; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Rename Group")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Current Group Name + // + group_name_edit=new QLineEdit(this,"group_name_edit"); + group_name_edit->setGeometry(165,11,sizeHint().width()-175,19); + group_name_edit->setMaxLength(10); + group_name_edit->setReadOnly(true); + QLabel *group_name_label= + new QLabel(group_name_edit,tr("Current Group Name:"), + this,"group_name_label"); + group_name_label->setGeometry(10,11,150,19); + group_name_label->setFont(font); + group_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // New Group Name + // + group_newname_edit=new QLineEdit(this,"group_newname_edit"); + group_newname_edit->setGeometry(165,33,sizeHint().width()-175,19); + group_newname_edit->setMaxLength(10); + group_newname_edit->setValidator(validator); + QLabel *group_newname_label= + new QLabel(group_newname_edit,tr("New &Group Name:"), + this,"group_newname_label"); + group_newname_label->setGeometry(10,33,150,19); + group_newname_label->setFont(font); + group_newname_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + group_name_edit->setText(group_name); +} + + +RenameGroup::~RenameGroup() +{ +} + + +QSize RenameGroup::sizeHint() const +{ + return QSize(300,130); +} + + +QSizePolicy RenameGroup::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RenameGroup::okData() +{ + QString sql; + RDSqlQuery *q; + bool merging=false; + QString str1; + QString str2; + + if(group_newname_edit->text().isEmpty()) { + QMessageBox::warning(this,tr("Invalid Group"), + tr("The group name is invalid!")); + return; + } + + sql=QString(). + sprintf("select NAME from GROUPS where NAME=\"%s\"", + (const char *)RDEscapeString(group_newname_edit->text())); + q=new RDSqlQuery(sql); + if(q->first()) { + str1=QString(tr("A")); + str2=QString(tr("group already exists.\nDo you want to combine the two?")); + if(QMessageBox::question(this,tr("Group Exists"), + QString().sprintf("%s %s %s",(const char *)str1, + (const char *)RDEscapeString(group_newname_edit->text()), + (const char *)str2), + QMessageBox::Yes,QMessageBox::No)!=QMessageBox::Yes) { + delete q; + return; + } + merging=true; + } + delete q; + + // + // Update Cart List + // + sql=QString(). + sprintf("update CART set GROUP_NAME=\"%s\" where GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(group_newname_edit->text()), + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + + // + // Update LogManager Events + // + sql=QString(). + sprintf("update EVENTS set SCHED_GROUP=\"%s\" where SCHED_GROUP=\"%s\"", + (const char *)RDEscapeString(group_newname_edit->text()), + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + + // + // Update Replicators + // + sql=QString(). + sprintf("update REPLICATOR_MAP set GROUP_NAME=\"%s\" \ + where GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(group_newname_edit->text()), + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + + // + // Update Dropboxes + // + sql=QString(). + sprintf("update DROPBOXES set GROUP_NAME=\"%s\" \ + where GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(group_newname_edit->text()), + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + + // + // Update Group List + // + if(!merging) { + sql=QString(). + sprintf("update GROUPS set NAME=\"%s\" where NAME=\"%s\"", + (const char *)RDEscapeString(group_newname_edit->text()), + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + + // + // Update AUDIO_PERMS + // + sql=QString(). + sprintf("update AUDIO_PERMS set GROUP_NAME=\"%s\" \ + where GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(group_newname_edit->text()), + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + + // + // Update USER_PERMS + // + sql=QString(). + sprintf("update USER_PERMS set GROUP_NAME=\"%s\" where GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(group_newname_edit->text()), + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + } + else { + sql=QString(). + sprintf("delete from GROUPS where NAME=\"%s\"", + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + + // + // Update AUDIO_PERMS + // + sql=QString(). + sprintf("delete from AUDIO_PERMS where GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + + // + // Update USER_PERMS + // + sql=QString(). + sprintf("delete from USER_PERMS where GROUP_NAME=\"%s\"", + (const char *)RDEscapeString(group_name_edit->text())); + q=new RDSqlQuery(sql); + delete q; + } + + done(0); +} + + +void RenameGroup::cancelData() +{ + done(-1); +} diff --git a/rdadmin/rename_group.h b/rdadmin/rename_group.h new file mode 100644 index 00000000..375be417 --- /dev/null +++ b/rdadmin/rename_group.h @@ -0,0 +1,58 @@ +// rename_group.h +// +// Rename a Rivendell Group +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rename_group.h,v 1.6 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RENAME_GROUP_H +#define RENAME_GROUP_H + +#include +#include +#include +#include +#include +#include +#include + +#include + + +class RenameGroup : public QDialog +{ + Q_OBJECT + public: + RenameGroup(QString group,QWidget *parent=0,const char *name=0); + ~RenameGroup(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *group_name_edit; + QLineEdit *group_newname_edit; + QString group_name; +}; + + +#endif // RENAME_GROUP_H + diff --git a/rdadmin/test_import.cpp b/rdadmin/test_import.cpp new file mode 100644 index 00000000..4de0f93a --- /dev/null +++ b/rdadmin/test_import.cpp @@ -0,0 +1,290 @@ +// test_import.cpp +// +// Test a Rivendell Log Import +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: test_import.cpp,v 1.22 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +TestImport::TestImport(RDSvc *svc,RDSvc::ImportSource src, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + QDate current_date=QDate::currentDate(); + + test_svc=svc; + test_src=src; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + switch(test_src) { + case RDSvc::Traffic: + setCaption(tr("Test Traffic Import")); + break; + + case RDSvc::Music: + setCaption(tr("Test Music Import")); + break; + } + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont section_font=QFont("Helvetica",14,QFont::Bold); + section_font.setPixelSize(14); + + // + // Date Selector + // + test_date_edit=new QDateEdit(this,"test_date_edit"); + test_date_edit->setGeometry(95,10,95,20); + QLabel *label=new QLabel(test_date_edit,tr("Test Date:"),this,"test_date_label"); + label->setGeometry(5,10,85,20); + label->setFont(font); + label->setAlignment(AlignVCenter|AlignRight); + test_date_edit->setDate(current_date); + connect(test_date_edit,SIGNAL(valueChanged(const QDate &)), + this,SLOT(dateChangedData(const QDate &))); + + // + // Select Date Button + // + QPushButton *button=new QPushButton(this,"select_date_button"); + button->setGeometry(200,5,60,30); + button->setFont(font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectData())); + + // + // Import Button + // + button=new QPushButton(this,"import_button"); + button->setGeometry(30,45,sizeHint().width()-60,50); + button->setFont(font); + button->setText(tr("&Import")); + connect(button,SIGNAL(clicked()),this,SLOT(importData())); + + // + // Import Filename + // + test_filename_edit=new QLineEdit(this,"test_filename_edit"); + test_filename_edit->setReadOnly(true); + test_filename_edit->setGeometry(10,133,sizeHint().width()-20,18); + label=new QLabel(test_filename_edit,tr("Using source file:"), + this,"test_filename_label"); + label->setGeometry(15,115,sizeHint().width()-30,18); + label->setFont(font); + + // + // Events List + // + test_events_list=new RDListView(this,"test_events_list"); + test_events_list-> + setGeometry(10,178,sizeHint().width()-20,sizeHint().height()-248); + test_events_list->setItemMargin(2); + test_events_list->addColumn(tr("Start Time")); + test_events_list->setColumnAlignment(0,AlignCenter); + test_events_list->addColumn(tr("Cart")); + test_events_list->setColumnAlignment(1,AlignCenter); + test_events_list->addColumn(tr("Len")); + test_events_list->setColumnAlignment(2,AlignRight); + test_events_list->addColumn(tr("Title")); + test_events_list->setColumnAlignment(3,AlignLeft); + test_events_list->addColumn(tr("Contract #")); + test_events_list->setColumnAlignment(4,AlignCenter); + test_events_list->addColumn(tr("Event ID")); + test_events_list->setColumnAlignment(5,AlignCenter); + test_events_list->addColumn(tr("Announcement Type")); + test_events_list->setColumnAlignment(6,AlignCenter); + test_events_list->setColumnSortType(0,RDListView::LineSort); + label=new QLabel(test_events_list,tr("Imported Events"), + this,"test_events_label"); + label->setGeometry(15,160,sizeHint().width()-30,18); + label->setFont(font); + + // + // Close Button + // + button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(font); + button->setText(tr("&Close")); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); + + dateChangedData(current_date); +} + + +TestImport::~TestImport() +{ +} + + +QSize TestImport::sizeHint() const +{ + return QSize(270,400); +} + + +QSizePolicy TestImport::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void TestImport::selectData() +{ + RDDateDialog *datedialog=new RDDateDialog(QDate::currentDate().year(), + QDate::currentDate().year()+1, + this,"timedialog"); + QDate date=test_date_edit->date(); + if(datedialog->exec(&date)<0) { + delete datedialog; + return; + } + test_date_edit->setDate(date); + delete datedialog; +} + + +void TestImport::importData() +{ + RDListViewItem *item; + int next_line=0; + + test_events_list->clear(); + if(!test_svc->import(test_src,test_date_edit->date(),test_svc->breakString(), + test_svc->trackString(test_src),QString(). + sprintf("%s_TEST_IMP", + (const char *)test_svc->name()))) { + QMessageBox::information(this,tr("Import Error"), + tr("There was an error during import\nplease check your settings and try again.")); + return; + } + QString sql=QString().sprintf("select START_HOUR,START_SECS,EXT_CART_NAME,\ + LENGTH,EXT_DATA,EXT_EVENT_ID,EXT_ANNC_TYPE,\ + INSERT_BREAK,INSERT_TRACK,INSERT_FIRST,TITLE,\ + TRACK_STRING from `%s_TEST_IMP`", + (const char *)test_svc->name()); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + if(q->value(9).toUInt()==RDEventLine::InsertBreak) { + if(q->value(7).toString()=="Y") { + item=new RDListViewItem(test_events_list); + item->setLine(next_line++); + item-> + setText(0,RDSvc::timeString(q->value(0).toInt(), + q->value(1).toInt())); + item->setText(1,tr("[spot break]")); + } + if(q->value(8).toString()=="Y") { + item=new RDListViewItem(test_events_list); + item->setLine(next_line++); + item->setText(0,RDSvc::timeString(q->value(0).toInt(), + q->value(1).toInt())); + item->setText(1,QString(). + sprintf("[%s]",(const char *)q->value(11).toString())); + } + } + else { + if(q->value(8).toString()=="Y") { + item=new RDListViewItem(test_events_list); + item->setLine(next_line++); + item->setText(0,RDSvc::timeString(q->value(0).toInt(), + q->value(1).toInt())); + item->setText(1,QString(). + sprintf("[%s]",(const char *)q->value(11).toString())); + } + if(q->value(7).toString()=="Y") { + item=new RDListViewItem(test_events_list); + item->setLine(next_line++); + item-> + setText(0,RDSvc::timeString(q->value(0).toInt(), + q->value(1).toInt())); + item->setText(1,tr("[spot break]")); + } + } + item=new RDListViewItem(test_events_list); + item->setLine(next_line++); + item->setText(0,RDSvc::timeString(q->value(0).toInt(), + q->value(1).toInt())); + item->setText(1,q->value(2).toString()); + if(q->value(3).toInt()>=0) { + item->setText(2,RDGetTimeLength(q->value(3).toInt(),false,false)); + } + item->setText(3,q->value(10).toString()); + item->setText(4,q->value(4).toString()); + item->setText(5,q->value(5).toString()); + item->setText(6,q->value(6).toString()); + } + delete q; + // printf("IMPORT TABLE: %s_TEST_IMP\n",(const char *)test_svc->name()); + sql=QString().sprintf("drop table `%s_TEST_IMP`", + (const char *)test_svc->name()); + q=new RDSqlQuery(sql); + delete q; +} + + +void TestImport::dateChangedData(const QDate &date) +{ + test_filename_edit-> + setText(RDDateDecode(test_svc->importPath(test_src,RDSvc::Linux),date)); +} + + +void TestImport::closeData() +{ + done(0); +} + + +void TestImport::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->moveTo(10,105); + p->lineTo(sizeHint().width()-20,105); + p->end(); + delete p; +} diff --git a/rdadmin/test_import.h b/rdadmin/test_import.h new file mode 100644 index 00000000..70676cf4 --- /dev/null +++ b/rdadmin/test_import.h @@ -0,0 +1,64 @@ +// test_import.h +// +// Test a Rivendell Log Import +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: test_import.h,v 1.6 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef TEST_IMPORT_H +#define TEST_IMPORT_H + +#include +#include +#include +#include + +#include +#include + + +class TestImport : public QDialog +{ + Q_OBJECT + public: + TestImport(RDSvc *svc,RDSvc::ImportSource src, + QWidget *parent=0,const char *name=0); + ~TestImport(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void selectData(); + void importData(); + void dateChangedData(const QDate &date); + void closeData(); + + protected: + void paintEvent(QPaintEvent *e); + + private: + RDSvc *test_svc; + RDSvc::ImportSource test_src; + QDateEdit *test_date_edit; + RDListView *test_events_list; + QLineEdit *test_filename_edit; +}; + + +#endif + diff --git a/rdadmin/view_adapters.cpp b/rdadmin/view_adapters.cpp new file mode 100644 index 00000000..91d407bc --- /dev/null +++ b/rdadmin/view_adapters.cpp @@ -0,0 +1,200 @@ +// view_adapters.cpp +// +// Display Audio Adapter Information +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: view_adapters.cpp,v 1.14 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include +#include + +#include + + +ViewAdapters::ViewAdapters(RDStation *rdstation, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString str1; + QString str2; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Audio Resource Information")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",16,QFont::Bold); + font.setPixelSize(16); + QFont button_font=QFont("Helvetica",14,QFont::Bold); + button_font.setPixelSize(14); + + // + // Title + // + str1=tr("Audio Resources on"); + QLabel *label= + new QLabel(QString().sprintf("%s %s",(const char *)str1, + (const char *)rdstation->name()), + this,"title_label"); + label->setGeometry(15,10,sizeHint().width()-20,16); + label->setFont(font); + + // + // Resource List + // + QTextEdit *text_edit=new QTextEdit(this,"adapter_edit"); + text_edit->setGeometry(10,28,sizeHint().width()-20,sizeHint().height()-98); + text_edit->setReadOnly(true); + QString text; + if(rdstation->scanned()) { + text+=tr("SUPPORTED AUDIO DRIVERS\n"); + if(!rdstation->driverVersion(RDStation::Hpi).isEmpty()) { + text+=QString().sprintf(" AudioScience HPI [%s]\n", + (const char *)rdstation->driverVersion(RDStation::Hpi)); + } + if(!rdstation->driverVersion(RDStation::Jack).isEmpty()) { + text+=QString().sprintf(" JACK Audio Connection Kit [%s]\n", + (const char *)rdstation->driverVersion(RDStation::Jack)); + } + if(!rdstation->driverVersion(RDStation::Alsa).isEmpty()) { + text+=QString().sprintf(" Advanced Linux Sound Architecture (ALSA) [%s]\n", + (const char *)rdstation->driverVersion(RDStation::Alsa)); + } + text+="\n"; + + text+=tr("SUPPORTED IMPORT FORMATS\n"); + if(rdstation->haveCapability(RDStation::HaveFlac)) { + text+=tr(" Free Lossless Audio Codec (FLAC)\n"); + } + if(rdstation->haveCapability(RDStation::HaveMpg321)) { + text+=tr(" MPEG Layer 1\n"); + text+=tr(" MPEG Layer 2\n"); + text+=tr(" MPEG Layer 3\n"); + } + if(rdstation->haveCapability(RDStation::HaveOgg123)) { + text+=tr(" OggVorbis\n"); + } + text+=tr(" PCM16 Linear\n"); + text+="\n"; + text+=tr("SUPPORTED EXPORT FORMATS\n"); + if(rdstation->haveCapability(RDStation::HaveFlac)) { + text+=tr(" Free Lossless Audio Codec (FLAC)\n"); + } + if(rdstation->haveCapability(RDStation::HaveTwoLame)) { + text+=tr(" MPEG Layer 2\n"); + } + if(rdstation->haveCapability(RDStation::HaveLame)) { + text+=tr(" MPEG Layer 3\n"); + } + if(rdstation->haveCapability(RDStation::HaveOggenc)) { + text+=tr(" OggVorbis\n"); + } + text+=tr(" PCM16 Linear\n"); + RDEncoderList *encoders=new RDEncoderList(rdstation->name()); + for(unsigned i=0;iencoderQuantity();i++) { + text+=" "+encoders->encoder(i)->name()+" [Custom]\n"; + } + delete encoders; + + text+="\n"; + + text+=tr("AUDIO ADAPTERS\n"); + for(int i=0;icardName(i).isEmpty()) { + text+=QString().sprintf(" %s %d: %s\n\n",(const char *)str1,i, + (const char *)str2); + } + else { + text+=QString().sprintf(" %s %d: %s\n",(const char *)str1,i, + (const char *)rdstation->cardName(i)); + switch(rdstation->cardDriver(i)) { + case RDStation::Hpi: + text+=QString(tr(" Driver: AudioScience HPI\n")); + break; + + case RDStation::Jack: + text+=QString(tr(" Driver: JACK Audio Connection Kit\n")); + break; + + case RDStation::Alsa: + text+=QString( + tr(" Driver: Advanced Linux Sound Architecture (ALSA)\n")); + break; + + case RDStation::None: + text+=QString(tr(" Driver: UNKNOWN\n")); + break; + } + str1=QString(tr("Inputs:")); + text+=QString().sprintf(" %s %d\n",(const char *)str1, + rdstation->cardInputs(i)); + str1=QString(tr("Outputs:")); + text+=QString().sprintf(" %s %d\n\n",(const char *)str1, + rdstation->cardOutputs(i)); + } + } + } + else { + text=tr("NO DATA AVAILABLE\n\n"); + text+=tr("Please start the Rivendell daemons on this host (by executing, as user 'root', the command \"/etc/init.d/rivendell start\") in order to populate the audio resources database."); + } + text_edit->setText(text); + + // + // Close Button + // + QPushButton *button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(button_font); + button->setText(tr("&Close")); + button->setDefault(true); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +QSize ViewAdapters::sizeHint() const +{ + return QSize(460,290); +} + + +QSizePolicy ViewAdapters::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ViewAdapters::closeData() +{ + done(0); +} diff --git a/rdadmin/view_adapters.h b/rdadmin/view_adapters.h new file mode 100644 index 00000000..4b6bbcf3 --- /dev/null +++ b/rdadmin/view_adapters.h @@ -0,0 +1,52 @@ +// view_adapter.h +// +// Display Audio Adapter Information +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: view_adapters.h,v 1.7 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef VIEW_ADAPTER_H +#define VIEW_ADAPTER_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +class ViewAdapters : public QDialog +{ + Q_OBJECT + public: + ViewAdapters(RDStation *station,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void closeData(); +}; + + +#endif + diff --git a/rdadmin/view_node_info.cpp b/rdadmin/view_node_info.cpp new file mode 100644 index 00000000..d2e4382f --- /dev/null +++ b/rdadmin/view_node_info.cpp @@ -0,0 +1,356 @@ +// view_node_info.cpp +// +// Edit a Rivendell LiveWire Node +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: view_node_info.cpp,v 1.3.8.1 2013/01/30 21:06:04 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include +#include +#include + +#include + + +ViewNodeInfo::ViewNodeInfo(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + setCaption(tr("Viewing LiveWire Node")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // LiveWire Driver + // + view_livewire=new RDLiveWire(0,this,"view_livewire"); + connect(view_livewire,SIGNAL(connected(unsigned)), + this,SLOT(connectedData(unsigned))); + connect(view_livewire,SIGNAL(sourceChanged(unsigned,RDLiveWireSource *)), + this,SLOT(sourceChangedData(unsigned,RDLiveWireSource *))); + connect(view_livewire, + SIGNAL(destinationChanged(unsigned,RDLiveWireDestination *)), + this, + SLOT(destinationChangedData(unsigned,RDLiveWireDestination *))); + + // + // Node Hostname + // + view_hostname_edit=new QLineEdit(this,"view_hostname_edit"); + view_hostname_edit->setGeometry(90,10,190,20); + view_hostname_edit->setReadOnly(true); + QLabel *label= + new QLabel(view_hostname_edit,tr("Hostname:"),this,"view_hostname_label"); + label->setGeometry(10,10,80,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Node TCP Port + // + view_tcpport_edit=new QLineEdit(this,"view_tcpport_edit"); + view_tcpport_edit->setGeometry(335,10,sizeHint().width()-345,20); + view_tcpport_edit->setReadOnly(true); + label=new QLabel(view_tcpport_edit,tr("Port:"),this,"view_tcpport_label"); + label->setGeometry(305,10,30,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // System Version + // + view_system_edit=new QLineEdit(this,"view_system_edit"); + view_system_edit->setGeometry(135,32,70,20); + view_system_edit->setReadOnly(true); + label=new QLabel(view_system_edit,tr("System Version:"), + this,"view_system_label"); + label->setGeometry(10,32,120,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Protocol Version + // + view_protocol_edit=new QLineEdit(this,"view_protocol_edit"); + view_protocol_edit->setGeometry(335,32,40,20); + view_protocol_edit->setReadOnly(true); + label=new QLabel(view_protocol_edit,tr("Protocol Version:"), + this,"view_protocol_label"); + label->setGeometry(210,32,120,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Sources + // + view_sources_edit=new QLineEdit(this,"view_sources_edit"); + view_sources_edit->setGeometry(75,54,30,20); + view_sources_edit->setReadOnly(true); + label=new QLabel(view_sources_edit,tr("Sources:"), + this,"view_sources_label"); + label->setGeometry(10,54,60,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Destinations + // + view_destinations_edit=new QLineEdit(this,"view_destinations_edit"); + view_destinations_edit->setGeometry(225,54,30,20); + view_destinations_edit->setReadOnly(true); + label=new QLabel(view_destinations_edit,tr("Destinations:"), + this,"view_destinations_label"); + label->setGeometry(120,54,100,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Channels + // + view_channels_edit=new QLineEdit(this,"view_channels_edit"); + view_channels_edit->setGeometry(360,54,30,20); + view_channels_edit->setReadOnly(true); + label=new QLabel(view_channels_edit,tr("Channels:"), + this,"view_channels_label"); + label->setGeometry(260,54,95,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // GPIs + // + view_gpis_edit=new QLineEdit(this,"view_gpis_edit"); + view_gpis_edit->setGeometry(135,76,70,20); + view_gpis_edit->setReadOnly(true); + label=new QLabel(view_gpis_edit,tr("GPIs:"), + this,"view_gpis_label"); + label->setGeometry(10,76,120,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // GPOs + // + view_gpos_edit=new QLineEdit(this,"view_gpos_edit"); + view_gpos_edit->setGeometry(305,76,70,20); + view_gpos_edit->setReadOnly(true); + label=new QLabel(view_gpos_edit,tr("GPOs:"), + this,"view_gpos_label"); + label->setGeometry(210,76,90,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Sources List + // + label=new QLabel(view_gpos_edit,tr("Sources"), + this,"view_sources_label"); + label->setGeometry(15,98,90,20); + label->setFont(bold_font); + label->setAlignment(AlignLeft|AlignVCenter); + view_sources_view=new RDListView(this,"view_sources_view"); + view_sources_view-> + setGeometry(10,118,sizeHint().width()-20,200); + view_sources_view->setAllColumnsShowFocus(true); + view_sources_view->setItemMargin(5); + view_sources_view->addColumn(tr("#")); + view_sources_view->setColumnAlignment(0,Qt::AlignCenter); + view_sources_view->addColumn(tr("CHAN")); + view_sources_view->setColumnAlignment(1,Qt::AlignCenter); + view_sources_view->addColumn(tr("NAME")); + view_sources_view->setColumnAlignment(2,Qt::AlignLeft); + view_sources_view->addColumn(tr("STREAMING")); + view_sources_view->setColumnAlignment(3,Qt::AlignCenter); + view_sources_view->addColumn(tr("SHAREABLE")); + view_sources_view->setColumnAlignment(4,Qt::AlignCenter); + view_sources_view->addColumn(tr("CHANS")); + view_sources_view->setColumnAlignment(5,Qt::AlignCenter); + view_sources_view->addColumn(tr("GAIN")); + view_sources_view->setColumnAlignment(6,Qt::AlignCenter); + + // + // Destinations List + // + label=new QLabel(view_gpos_edit,tr("Destinations"), + this,"view_destinations_label"); + label->setGeometry(15,325,90,20); + label->setFont(bold_font); + label->setAlignment(AlignLeft|AlignVCenter); + view_destinations_view=new RDListView(this,"view_destinations_view"); + view_destinations_view-> + setGeometry(10,345,sizeHint().width()-20,200); + view_destinations_view->setAllColumnsShowFocus(true); + view_destinations_view->setItemMargin(5); + view_destinations_view->addColumn(tr("#")); + view_destinations_view->setColumnAlignment(0,Qt::AlignCenter); + view_destinations_view->addColumn(tr("CHAN")); + view_destinations_view->setColumnAlignment(1,Qt::AlignCenter); + view_destinations_view->addColumn(tr("NAME")); + view_destinations_view->setColumnAlignment(2,Qt::AlignLeft); + view_destinations_view->addColumn(tr("CHANS")); + view_destinations_view->setColumnAlignment(3,Qt::AlignCenter); + view_destinations_view->addColumn(tr("LOAD")); + view_destinations_view->setColumnAlignment(4,Qt::AlignCenter); + view_destinations_view->addColumn(tr("GAIN")); + view_destinations_view->setColumnAlignment(5,Qt::AlignCenter); + + // + // Close Button + // + QPushButton *button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&Close")); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +QSize ViewNodeInfo::sizeHint() const +{ + return QSize(400,615); +} + + +QSizePolicy ViewNodeInfo::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ViewNodeInfo::exec(const QString &hostname,Q_UINT16 port, + const QString &passwd,unsigned base_output) +{ + view_hostname_edit->setText(hostname); + view_tcpport_edit->setText(QString().sprintf("%u",(unsigned)port)); + view_base_output=base_output; + view_livewire->connectToHost(hostname,port,passwd,base_output); + QDialog::exec(); +} + + +void ViewNodeInfo::connectedData(unsigned id) +{ + view_protocol_edit->setText(view_livewire->protocolVersion()); + view_system_edit->setText(view_livewire->systemVersion()); + view_sources_edit->setText(QString().sprintf("%d",view_livewire->sources())); + view_destinations_edit-> + setText(QString().sprintf("%d",view_livewire->destinations())); + view_channels_edit-> + setText(QString().sprintf("%d",view_livewire->channels())); + view_gpis_edit-> + setText(QString().sprintf("%d [%d X %d]", + RD_LIVEWIRE_GPIO_BUNDLE_SIZE*view_livewire->gpis(), + view_livewire->gpis(), + RD_LIVEWIRE_GPIO_BUNDLE_SIZE)); + view_gpos_edit-> + setText(QString().sprintf("%d [%d X %d]", + RD_LIVEWIRE_GPIO_BUNDLE_SIZE*view_livewire->gpos(), + view_livewire->gpos(), + RD_LIVEWIRE_GPIO_BUNDLE_SIZE)); +} + + +void ViewNodeInfo::sourceChangedData(unsigned id,RDLiveWireSource *src) +{ + RDListViewItem *item=(RDListViewItem *)view_sources_view->firstChild(); + while(item!=NULL) { + if(item->text(0).toInt()==src->slotNumber()) { + WriteSourceItem(src,item); + return; + } + item=(RDListViewItem *)item->nextSibling(); + } + item=new RDListViewItem(view_sources_view); + item->setText(0,QString().sprintf("%d",src->slotNumber())); + WriteSourceItem(src,item); +} + + +void ViewNodeInfo::destinationChangedData(unsigned id, + RDLiveWireDestination *dst) +{ + RDListViewItem *item=(RDListViewItem *)view_destinations_view->firstChild(); + while(item!=NULL) { + if(item->text(0).toInt()==dst->slotNumber()) { + WriteDestinationItem(dst,item); + return; + } + item=(RDListViewItem *)item->nextSibling(); + } + item=new RDListViewItem(view_destinations_view); + item->setText(0,QString().sprintf("%d",dst->slotNumber())); + WriteDestinationItem(dst,item); +} + + +void ViewNodeInfo::closeData() +{ + done(0); +} + + +void ViewNodeInfo::WriteSourceItem(RDLiveWireSource *src,RDListViewItem *item) +{ + item->setText(1,QString().sprintf("%05d",src->channelNumber())); + item->setText(2,src->primaryName()); + if(src->rtpEnabled()) { + item->setText(3,tr("Yes")); + } + else { + item->setText(3,tr("No")); + } + if(src->shareable()) { + item->setText(4,tr("Yes")); + } + else { + item->setText(4,tr("No")); + } + item->setText(5,QString().sprintf("%d",src->channels())); + item->setText(6,QString().sprintf("%4.1f",(float)src->inputGain()/10.0)); +} + + +void ViewNodeInfo::WriteDestinationItem(RDLiveWireDestination *dst, + RDListViewItem *item) +{ + item-> + setText(1,QString().sprintf("%05u",view_base_output+dst->slotNumber()-1)); + item->setText(2,dst->primaryName()); + item->setText(3,QString().sprintf("%d",dst->channels())); + item->setText(4,RDLiveWireDestination::loadString(dst->load())); + item->setText(5,QString().sprintf("%4.1f",(float)dst->outputGain()/10.0)); +} diff --git a/rdadmin/view_node_info.h b/rdadmin/view_node_info.h new file mode 100644 index 00000000..471ad096 --- /dev/null +++ b/rdadmin/view_node_info.h @@ -0,0 +1,75 @@ +// view_node_info.h +// +// Edit a Rivendell LiveWire Node +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: view_node_info.h,v 1.3 2010/07/29 19:32:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef VIEW_NODE_INFO_H +#define VIEW_NODE_INFO_H + +#include +#include +#include +#include + +#include +#include +#include + + +class ViewNodeInfo : public QDialog +{ + Q_OBJECT + public: + ViewNodeInfo(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + void exec(const QString &hostname,Q_UINT16 port,const QString &passwd, + unsigned base_output); + + private slots: + void connectedData(unsigned id); + void sourceChangedData(unsigned id,RDLiveWireSource *src); + void destinationChangedData(unsigned id,RDLiveWireDestination *dst); + void closeData(); + + private: + void WriteSourceItem(RDLiveWireSource *src,RDListViewItem *item); + void WriteDestinationItem(RDLiveWireDestination *dst,RDListViewItem *item); + RDLiveWire *view_livewire; + QLineEdit *view_hostname_edit; + QLineEdit *view_tcpport_edit; + QLineEdit *view_protocol_edit; + QLineEdit *view_system_edit; + QLineEdit *view_type_edit; + QLineEdit *view_sources_edit; + QLineEdit *view_destinations_edit; + QLineEdit *view_channels_edit; + QLineEdit *view_gpis_edit; + QLineEdit *view_gpos_edit; + RDListView *view_sources_view; + RDListView *view_destinations_view; + unsigned view_base_output; +}; + + +#endif // VIEW_NODE_INFO + diff --git a/rdadmin/xpm_info_banner1.cpp b/rdadmin/xpm_info_banner1.cpp new file mode 100644 index 00000000..a6d5b807 --- /dev/null +++ b/rdadmin/xpm_info_banner1.cpp @@ -0,0 +1,1086 @@ +// xpm_info_banner1.cpp +// +// Elvish Script for the Copyright Screen +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: xpm_info_banner1.cpp,v 1.3 2007/02/14 21:51:02 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +const unsigned char xpm_info_banner1[16976] = { +47,42,32,88,80,77,32,42,47,10,115,116,97,116,105,99, +32,99,104,97,114,32,42,32,105,110,102,111,95,98,97,110, +110,101,114,49,95,120,112,109,91,93,32,61,32,123,10,34, +52,54,48,32,51,53,32,51,50,32,49,34,44,10,34,32, +9,99,32,35,70,70,70,70,70,70,70,70,70,70,70,70, +34,44,10,34,46,9,99,32,35,69,55,57,68,69,55,57, +68,69,55,57,68,34,44,10,34,88,9,99,32,35,66,54, +68,65,66,54,68,65,66,54,68,65,34,44,10,34,111,9, +99,32,35,53,57,54,53,53,57,54,53,53,57,54,53,34, +44,10,34,79,9,99,32,35,67,70,51,67,67,70,51,67, +67,70,51,67,34,44,10,34,43,9,99,32,35,69,70,66, +69,69,70,66,69,69,70,66,69,34,44,10,34,64,9,99, +32,35,67,55,49,66,67,55,49,66,67,55,49,66,34,44, +10,34,35,9,99,32,35,57,69,55,57,57,69,55,57,57, +69,55,57,34,44,10,34,36,9,99,32,35,48,48,48,48, +48,48,48,48,48,48,48,48,34,44,10,34,37,9,99,32, +35,48,56,50,48,48,56,50,48,48,56,50,48,34,44,10, +34,38,9,99,32,35,70,55,68,69,70,55,68,69,70,55, +68,69,34,44,10,34,42,9,99,32,35,65,69,66,65,65, +69,66,65,65,69,66,65,34,44,10,34,61,9,99,32,35, +49,48,52,48,49,48,52,48,49,48,52,48,34,44,10,34, +45,9,99,32,35,54,49,56,53,54,49,56,53,54,49,56, +53,34,44,10,34,59,9,99,32,35,65,54,57,57,65,54, +57,57,65,54,57,57,34,44,10,34,58,9,99,32,35,56, +69,51,56,56,65,50,56,56,69,51,56,34,44,10,34,62, +9,99,32,35,51,48,67,50,51,48,67,50,51,48,67,50, +34,44,10,34,44,9,99,32,35,50,56,65,50,50,56,65, +50,50,56,65,50,34,44,10,34,60,9,99,32,35,49,56, +54,49,49,56,54,49,49,56,54,49,34,44,10,34,49,9, +99,32,35,68,70,55,68,68,70,55,68,68,70,55,68,34, +44,10,34,50,9,99,32,35,51,56,69,51,51,56,69,51, +51,56,69,51,34,44,10,34,51,9,99,32,35,50,48,56, +49,50,48,56,49,50,48,56,49,34,44,10,34,52,9,99, +32,35,54,57,65,54,54,57,65,54,54,57,65,54,34,44, +10,34,53,9,99,32,35,52,57,50,52,52,57,50,52,52, +57,50,52,34,44,10,34,54,9,99,32,35,53,49,52,52, +53,49,52,52,53,49,52,52,34,44,10,34,55,9,99,32, +35,55,49,67,54,55,49,67,54,55,49,67,54,34,44,10, +34,56,9,99,32,35,66,69,70,66,66,69,70,66,66,69, +70,66,34,44,10,34,57,9,99,32,35,55,57,69,55,55, +57,69,55,55,57,69,55,34,44,10,34,48,9,99,32,35, +57,54,53,56,57,54,53,56,57,54,53,56,34,44,10,34, +113,9,99,32,35,52,49,48,51,52,49,48,51,52,49,48, +51,34,44,10,34,119,9,99,32,35,68,55,53,67,68,55, +53,67,68,55,53,67,34,44,10,34,101,9,99,32,35,56, +54,49,55,56,50,48,55,56,54,49,55,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,46,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,88,111,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,79, +43,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,79,43,32,32,32, +32,32,32,32,32,32,32,32,79,43,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,88,111,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,64,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,35,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,64,111,36,37,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,38,42,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,35, +32,32,32,32,32,32,32,32,32,32,42,61,45,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,35,32,32,32,32, +32,32,32,32,32,32,32,32,35,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +38,42,32,32,32,32,32,32,32,32,32,32,32,32,32,64, +111,36,37,32,32,32,32,32,32,32,32,32,32,32,32,32, +59,61,45,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,59,61,45,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,38,88,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,35,36,58,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,43,59,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,37,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,38,62,44,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,43,59, +32,32,32,32,32,32,32,32,32,46,60,59,44,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,43,59,32,32,32,32, +32,32,32,32,32,32,32,43,59,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,38, +62,44,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,36,37,32,32,32,32,32,32,32,32,32,32,32,32,49, +61,59,44,32,32,32,32,32,32,32,32,32,32,32,32,32, +49,61,59,44,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,38,50,51,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,46,52,49,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,58,38,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,37,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,53,54,43,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,62,44, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,55,38, +32,32,32,32,32,32,32,32,32,55,88,32,56,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,62,44,32,32,32,32,32,32,32,32,32,32,32,32,32, +62,62,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,55,38,32,32,32,32, +32,32,32,32,32,32,32,55,38,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,53, +54,43,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,36,37,32,32,32,32,32,32,32,32,32,32,32,32,55, +42,32,56,32,32,32,32,32,32,32,32,32,32,32,32,32, +55,42,32,56,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,54,53,43,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,62,62,32,62,62,32,32,32, +32,32,32,32,32,32,32,32,32,79,58,32,32,32,32,32, +32,32,32,32,32,62,62,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,37,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,57,59,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,111,111, +32,32,32,32,32,32,32,32,32,32,32,32,32,35,48,32, +32,32,32,32,32,32,32,32,32,55,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,111,111,32,32,32,32,32,32,32,32,32,32,32,32,32, +54,53,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,35,48,32,32,32,32,32, +32,32,32,32,32,32,35,48,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,57,59, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,36,37,32,32,32,32,32,32,32,32,32,32,32,32,52, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +52,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,57,35,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,54,53,32,53,54,32,32,32, +32,32,32,32,32,32,32,32,64,53,32,32,32,32,32,32, +32,32,32,32,32,54,53,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,37,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,43,52,45,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,43,52,45,32,32,32,32,32,32, +32,32,32,32,43,52,45,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,36,37,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,49,111,113,43,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,37,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,43,55,60,48,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,43,55,60,48,32,32,32,32,32,32,32, +32,32,43,55,60,48,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,36,37,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,49,54,60,35,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,37,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,35,61,53,43,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,35,61,53,43,32,32,32,32,32,32,32,32, +32,35,61,53,43,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,36,37,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,57,36,111,38,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,43,35,53,37,119,111,60,36,60,45, +88,53,37,37,111,43,32,32,32,32,32,32,64,50,113,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,37,119,113, +37,61,45,43,32,32,43,35,53,37,79,113,37,61,111,46, +32,32,43,35,53,37,119,111,60,36,60,45,88,53,37,37, +54,46,32,32,32,32,32,32,32,32,49,113,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,51,119,43,111,36,36, +36,36,36,36,36,36,36,36,60,88,32,32,32,59,113,37, +36,51,57,43,32,32,32,52,36,45,32,32,46,88,119,32, +32,32,43,35,53,37,119,111,60,36,60,45,88,53,37,37, +54,46,32,32,32,32,32,32,32,32,43,35,53,37,119,111, +60,36,60,45,88,53,37,37,111,43,32,32,32,32,32,32, +64,50,113,32,32,32,32,32,32,32,38,55,52,46,32,32, +42,111,42,32,32,32,36,36,48,32,32,32,32,32,32,32, +32,32,32,59,113,37,36,51,57,43,32,32,32,32,32,32, +32,32,32,52,36,45,32,32,46,88,119,32,32,32,32,32, +52,36,45,32,32,46,88,119,32,32,32,43,35,53,37,64, +113,37,61,111,46,32,32,43,35,53,37,79,53,37,37,54, +88,111,60,36,44,58,32,32,32,32,32,32,32,32,32,32, +32,36,37,119,113,37,61,45,43,32,32,43,35,53,37,79, +113,37,61,111,46,32,32,32,32,32,32,32,32,32,32,32, +49,54,37,37,62,58,32,32,43,35,53,37,79,113,37,61, +111,46,32,32,49,113,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,51,119,32,32,32,32,64,50,113,32,32,32, +32,32,43,35,53,37,119,111,60,36,60,45,88,53,37,37, +54,46,32,32,32,32,32,32,64,50,113,32,32,32,32,32, +32,32,53,36,57,32,32,43,48,57,56,32,32,32,32,38, +55,52,46,32,32,42,111,42,32,32,32,36,36,48,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,79,59,36,36,52,49,32,64,50,36, +36,119,38,57,36,51,43,32,32,32,32,32,32,113,36,88, +32,32,32,32,32,32,32,32,32,32,32,32,36,36,57,43, +46,45,36,44,38,32,49,59,36,36,101,43,43,55,36,60, +46,32,79,59,36,36,57,46,32,79,113,36,36,79,38,101, +36,60,46,32,32,32,32,32,32,32,32,79,36,48,32,32, +79,36,101,32,32,32,32,32,36,36,32,32,32,32,32,42, +37,101,38,32,32,32,32,32,32,32,32,32,111,60,56,32, +46,48,61,60,38,32,42,36,50,32,32,101,36,36,36,111, +32,32,79,59,36,36,57,46,32,79,113,36,36,79,38,101, +36,60,46,32,32,32,32,32,32,32,79,59,36,36,52,49, +32,64,50,36,36,119,38,57,36,51,43,32,32,32,32,32, +32,113,36,88,32,32,32,32,32,32,50,53,32,32,32,55, +44,43,32,32,32,32,36,36,32,32,32,32,32,32,32,32, +32,32,111,60,56,32,46,48,61,60,38,32,32,32,32,32, +32,32,42,36,50,32,32,101,36,36,36,111,32,32,32,42, +36,50,32,32,101,36,36,36,111,32,32,79,59,36,36,58, +43,43,55,36,60,46,32,64,59,36,36,57,43,46,52,36, +36,79,32,79,50,36,113,32,32,32,32,32,32,32,32,32, +32,36,36,57,43,46,45,36,44,38,32,49,59,36,36,101, +43,43,55,36,60,46,32,32,32,32,32,32,32,32,32,35, +44,56,32,46,45,36,50,38,49,59,36,36,101,43,43,55, +36,60,46,32,32,79,36,48,32,32,79,36,101,32,32,32, +32,32,36,36,32,32,32,32,32,32,32,113,36,88,32,32, +32,32,79,59,36,36,57,46,32,79,113,36,36,79,38,101, +36,60,46,32,32,32,32,32,32,113,36,88,32,32,32,32, +32,35,36,53,32,32,64,61,36,36,36,111,32,32,32,50, +53,32,32,32,55,44,43,32,32,32,32,36,36,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,62, +36,45,32,32,54,36,55,32,32,32,32,32,56,64,61,44, +32,32,32,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,53,36,52,32,32,32,36,36,32,32,32,32,45,36, +111,32,32,32,36,36,32,32,32,32,32,113,36,54,32,32, +52,36,111,32,32,32,32,32,32,32,32,54,36,46,32,32, +54,36,49,32,32,32,32,32,36,36,32,32,32,32,119,36, +45,32,32,32,32,32,32,32,32,32,32,48,36,88,32,32, +32,32,64,57,32,32,113,36,64,32,38,56,42,52,37,36, +58,32,32,32,36,36,32,32,32,32,32,113,36,54,32,32, +45,36,111,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,32,62,36,45,32,32,54,36,55,32,32,32,32,32, +56,64,61,44,32,32,32,32,32,58,36,64,32,32,42,36, +88,32,32,32,32,32,36,36,32,32,32,32,32,32,32,32, +32,48,36,88,32,32,32,32,64,57,32,32,32,32,32,32, +32,32,113,36,64,32,38,56,42,52,37,36,58,32,32,113, +36,64,32,38,56,42,52,37,36,58,32,32,32,36,36,32, +32,32,32,111,36,111,32,32,32,36,36,32,32,32,32,53, +36,45,32,32,32,62,36,101,32,32,32,32,32,32,32,32, +32,36,36,32,32,32,32,53,36,52,32,32,32,36,36,32, +32,32,32,45,36,111,32,32,32,32,32,32,32,32,56,36, +88,32,32,32,32,53,36,52,32,32,36,36,32,32,32,32, +45,36,111,32,32,54,36,46,32,32,54,36,49,32,32,32, +32,32,36,36,32,32,32,32,32,32,56,64,61,44,32,32, +32,32,32,32,36,36,32,32,32,32,32,113,36,54,32,32, +45,36,111,32,32,32,32,32,56,64,61,44,32,32,32,32, +32,50,36,79,32,32,46,46,64,55,37,36,59,32,58,36, +64,32,32,42,36,88,32,32,32,32,32,36,36,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,88, +36,60,32,32,64,36,60,32,32,32,32,32,48,32,101,36, +48,32,32,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,56,36,60,32,32,32,36,36,32,32,32,32,79,36, +61,32,32,32,36,36,32,32,32,32,32,64,36,61,32,32, +119,36,61,32,32,32,32,32,32,32,32,61,36,32,32,32, +61,36,32,32,32,32,32,32,36,36,32,32,32,32,111,36, +119,32,32,32,32,32,32,32,32,32,32,44,36,38,32,32, +32,32,32,32,32,32,61,36,38,32,32,32,32,32,46,51, +44,32,32,32,36,36,32,32,32,32,32,64,36,61,32,32, +119,36,61,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,32,88,36,60,32,32,64,36,60,32,32,32,32,32, +48,32,101,36,48,32,32,32,32,44,36,38,32,32,62,36, +38,32,32,32,32,32,36,36,32,32,32,32,32,32,32,32, +32,44,36,38,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,61,36,38,32,32,32,32,32,46,51,44,32,32,61, +36,38,32,32,32,32,32,46,51,44,32,32,32,36,36,32, +32,32,32,79,36,61,32,32,32,36,36,32,32,32,32,56, +36,60,32,32,32,88,36,51,32,32,32,32,32,32,32,32, +32,36,36,32,32,32,32,56,36,60,32,32,32,36,36,32, +32,32,32,79,36,61,32,32,32,32,32,32,32,32,50,36, +38,32,32,32,32,64,36,61,32,32,36,36,32,32,32,32, +79,36,61,32,32,61,36,32,32,32,61,36,32,32,32,32, +32,32,36,36,32,32,32,32,32,32,48,32,101,36,48,32, +32,32,32,32,36,36,32,32,32,32,32,64,36,61,32,32, +119,36,61,32,32,32,32,32,48,32,101,36,48,32,32,32, +32,37,36,38,32,32,32,32,32,32,119,61,54,32,44,36, +38,32,32,62,36,38,32,32,32,32,32,36,36,32,32,32, +32,119,119,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,43, +36,36,32,32,38,36,36,32,32,32,32,35,43,32,38,61, +61,38,32,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,43,36,36,32,32,32,36,36,32,32,32,32,32,36, +36,32,32,32,36,36,32,32,32,32,32,38,36,37,32,32, +32,36,37,32,32,32,32,32,32,32,32,36,36,38,32,32, +36,36,43,32,32,32,32,32,36,36,32,32,32,32,60,36, +32,32,32,32,32,32,32,32,32,32,32,36,36,38,32,32, +32,32,32,32,32,32,36,36,49,32,32,32,32,32,32,56, +36,32,32,32,36,36,32,32,32,32,32,38,36,37,32,32, +32,36,37,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,32,43,36,36,32,32,38,36,36,32,32,32,32,35, +43,32,38,61,61,38,32,32,32,36,36,32,32,32,37,36, +38,32,32,32,32,32,36,36,32,32,32,32,32,32,32,32, +32,36,36,38,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,36,36,49,32,32,32,32,32,32,56,36,32,32,36, +36,49,32,32,32,32,32,32,56,36,32,32,32,36,36,32, +32,32,32,38,36,36,32,32,32,36,36,32,32,32,32,38, +36,36,32,32,32,43,36,36,32,32,32,32,32,32,32,32, +32,36,36,32,32,32,32,43,36,36,32,32,32,36,36,32, +32,32,32,32,36,36,32,32,32,32,32,32,32,32,36,36, +38,32,32,32,32,38,36,37,32,32,36,36,32,32,32,32, +32,36,36,32,32,36,36,38,32,32,36,36,43,32,32,32, +32,32,36,36,32,32,32,32,32,35,43,32,38,61,61,38, +32,32,32,32,36,36,32,32,32,32,32,38,36,37,32,32, +32,36,37,32,32,32,32,35,43,32,38,61,61,38,32,32, +32,61,36,119,32,32,32,32,32,32,32,58,113,32,36,36, +32,32,32,37,36,38,32,32,32,32,32,36,36,32,32,32, +32,61,61,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,32, +36,60,32,32,32,36,60,32,32,32,43,59,32,32,32,58, +36,55,32,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,32,36,61,32,32,32,36,36,32,32,32,32,38,36, +44,32,32,32,36,36,32,32,32,32,32,38,36,62,32,32, +38,36,62,32,32,32,32,32,32,32,32,60,36,56,32,32, +60,36,42,32,32,32,32,32,36,36,32,32,32,32,36,36, +38,32,32,32,32,32,32,32,32,32,32,51,36,56,32,32, +32,32,32,32,32,32,44,36,57,32,32,32,32,32,32,38, +60,32,32,32,36,36,32,32,32,32,32,38,36,62,32,32, +38,36,62,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,32,32,36,60,32,32,32,36,60,32,32,32,43,59, +32,32,32,58,36,55,32,32,32,61,36,79,32,32,61,36, +64,32,32,32,32,32,36,36,32,32,32,32,32,32,32,32, +32,51,36,56,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,44,36,57,32,32,32,32,32,32,38,60,32,32,44, +36,57,32,32,32,32,32,32,38,60,32,32,32,36,36,32, +32,32,32,38,36,44,32,32,32,36,36,32,32,32,32,32, +36,60,32,32,32,32,36,60,32,32,32,32,32,32,32,32, +32,36,36,32,32,32,32,32,36,61,32,32,32,36,36,32, +32,32,32,38,36,44,32,32,32,32,32,32,32,32,61,36, +56,32,32,32,32,38,36,50,32,32,36,36,32,32,32,32, +38,36,44,32,32,60,36,56,32,32,60,36,42,32,32,32, +32,32,36,36,32,32,32,32,43,59,32,32,32,58,36,55, +32,32,32,32,36,36,32,32,32,32,32,38,36,62,32,32, +38,36,62,32,32,32,43,59,32,32,32,58,36,55,32,32, +32,53,36,52,32,32,32,32,32,32,32,79,45,32,61,36, +79,32,32,61,36,64,32,32,32,32,32,36,36,32,32,32, +32,59,35,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,49, +36,111,32,32,49,36,52,32,43,53,55,32,32,32,32,38, +60,37,46,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,46,36,54,32,32,32,36,36,32,32,32,32,64,36, +48,32,32,32,36,36,32,32,32,32,32,88,36,35,32,32, +56,36,35,32,32,32,32,32,32,32,32,55,36,54,32,32, +52,36,44,38,32,32,32,32,36,36,32,32,32,32,61,36, +64,32,32,32,32,32,32,32,32,32,32,101,36,50,32,32, +32,32,32,43,119,32,101,36,37,56,32,32,32,32,32,56, +55,32,32,32,36,36,32,32,32,32,32,88,36,35,32,32, +56,36,48,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,32,49,36,111,32,32,49,36,52,32,43,53,55,32, +32,32,32,38,60,37,46,32,32,111,36,111,32,32,45,36, +50,32,32,32,32,32,36,36,38,32,32,32,32,32,32,32, +32,101,36,50,32,32,32,32,32,43,119,32,32,32,32,32, +32,32,101,36,37,56,32,32,32,32,32,56,55,32,32,101, +36,37,56,32,32,32,32,32,56,55,32,32,32,36,36,32, +32,32,32,56,36,48,32,32,32,36,36,32,32,32,32,46, +36,111,32,32,32,119,36,55,32,32,32,32,32,32,32,32, +32,36,36,32,32,32,32,46,36,54,32,32,32,36,36,32, +32,32,32,64,36,48,32,32,32,32,32,32,32,32,55,36, +50,32,32,32,32,64,36,88,32,32,36,36,32,32,32,32, +64,36,48,32,32,55,36,54,32,32,52,36,44,38,32,32, +32,32,36,36,32,32,43,53,55,32,32,32,32,38,60,37, +46,32,32,32,36,36,32,32,32,32,32,88,36,35,32,32, +56,36,48,32,43,53,55,32,32,32,32,38,60,37,46,32, +32,64,36,36,35,32,32,32,32,32,32,58,79,32,111,36, +111,32,32,45,36,50,32,32,32,32,32,36,36,38,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,57, +36,79,32,32,58,61,43,32,52,36,56,32,32,32,32,32, +35,36,53,119,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,48,36,79,32,32,32,36,36,32,32,32,32,50,53, +32,32,32,32,36,36,32,32,32,32,43,51,54,32,32,32, +62,53,32,32,32,32,32,32,32,32,32,38,44,36,57,38, +119,36,36,62,64,32,49,55,36,36,32,32,32,32,54,36, +54,32,32,32,32,32,32,32,32,48,32,32,53,36,53,119, +32,43,57,111,32,32,38,50,36,36,54,48,56,56,57,53, +38,32,32,32,36,36,32,32,32,32,43,51,54,32,32,32, +50,53,32,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,32,57,36,79,32,32,58,61,43,32,52,36,56,32, +32,32,32,32,35,36,53,119,32,49,61,36,52,46,64,36, +36,62,42,49,64,52,36,36,101,42,32,32,32,32,32,32, +32,32,53,36,53,119,32,43,57,111,32,32,32,32,32,32, +32,32,38,50,36,36,54,48,56,56,57,53,38,32,32,38, +50,36,36,54,48,56,56,57,53,38,32,32,32,36,36,32, +32,32,32,50,113,32,32,32,32,36,36,32,32,32,32,48, +36,119,32,32,32,111,61,43,32,32,32,32,32,32,32,32, +32,36,36,32,32,32,32,48,36,79,32,32,32,36,36,32, +32,32,32,50,53,32,32,32,32,32,32,32,32,32,38,50, +36,54,49,32,64,44,58,32,32,32,36,36,32,32,32,32, +50,53,32,32,32,38,44,36,57,38,119,36,36,62,64,32, +49,55,36,36,32,32,52,36,56,32,32,32,32,32,35,36, +53,119,32,32,36,36,32,32,32,32,43,51,54,32,32,32, +50,53,32,32,52,36,56,32,32,32,32,32,35,36,53,119, +32,32,42,61,36,50,101,42,64,42,57,88,32,32,49,61, +36,52,46,64,36,36,62,42,49,64,52,36,36,101,42,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,51,79,58,45,32,32,32,32,32,32, +32,51,113,56,32,32,32,32,32,32,79,51,36,36,36,36, +36,36,36,36,113,119,32,101,36,36,32,32,49,111,101,32, +32,32,32,32,36,36,32,32,32,59,53,58,32,32,46,52, +101,32,32,32,32,32,32,32,32,32,32,32,43,111,37,37, +53,56,52,51,37,51,52,46,36,36,32,32,32,32,79,36, +36,35,32,32,32,32,32,32,58,59,32,32,32,48,62,37, +37,50,56,32,32,32,32,32,58,62,61,36,61,53,42,32, +32,32,32,58,36,36,32,32,32,59,53,58,32,32,49,45, +101,32,32,32,32,32,32,32,32,32,32,32,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,51,79,58,45,32,32, +32,32,32,32,32,51,113,56,32,32,49,53,37,37,54,64, +52,51,37,44,55,46,37,54,42,38,32,32,32,32,32,32, +32,32,32,48,62,37,37,50,56,32,32,32,32,32,32,32, +32,32,32,32,58,62,61,36,61,60,42,32,32,32,32,32, +32,58,62,61,36,61,53,42,32,32,32,32,32,36,36,32, +32,49,111,101,32,32,32,32,32,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,51,79,32,32,32,32,32,32,79, +51,36,36,36,36,36,36,36,36,113,119,32,101,36,36,32, +32,49,111,101,32,32,32,32,32,32,32,32,32,32,32,38, +58,44,37,37,53,119,32,32,32,101,36,36,32,32,49,111, +101,32,32,32,32,32,43,111,37,37,53,56,52,51,37,51, +52,46,36,36,32,32,58,45,32,32,32,32,32,32,32,51, +113,56,32,58,36,36,32,32,32,59,53,58,32,32,49,45, +101,32,32,32,58,45,32,32,32,32,32,32,32,51,113,56, +32,32,32,38,35,60,37,53,101,56,32,32,32,32,32,49, +53,37,37,54,64,52,51,37,44,55,46,37,54,42,38,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,36,36,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,35, +36,36,52,79,38,38,64,111,58,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,43,55,79,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,36,36,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,36,36,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,59,51,101,38,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,36,36,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,32, +79,53,61,36,37,44,52,119,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,79,45,38,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,36,36,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,36,36,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,58,36,64,32,32,32,58,62,53,56,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,36,36,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,119,50,38,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,36,36,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,36,36,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,38,37,62,32,32,32,46,35,55,37,37,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,36,36,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,113,59,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,36,36,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,36,36,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,119,36,44,32,32,32,32,32,32,64,36,43,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,36,36,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,36,36,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,36,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,37,59,88,88,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,36,36,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,36,36,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,37,36,56,32,32,32,32,32,49,62,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,36,36,49,46,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,36,36,49,46,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,36,36,79,49,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,36,36,49,46, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,50,36,36,119,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,36,36,38, +43,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,36,36,79,49,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,59,36,61,58,49,32,46,59,113,119,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,37,111,88,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,37,45,56,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,61,45,64,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,37,111,88,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,43,35,119,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,36,36,52, +49,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,61,45,64,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,49,55,44,37,36,44,101,38,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,57,46,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,34,44,10,34,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,34,44,10,34,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,34,125,59,10, +0}; diff --git a/rdadmin/xpm_info_banner2.cpp b/rdadmin/xpm_info_banner2.cpp new file mode 100644 index 00000000..c6bdbbf7 --- /dev/null +++ b/rdadmin/xpm_info_banner2.cpp @@ -0,0 +1,1075 @@ +// xpm_info_banner2.cpp +// +// Elvish Script for the Copyright Screen +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: xpm_info_banner2.cpp,v 1.3 2007/02/14 21:51:02 fredg Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +const unsigned char xpm_info_banner2[16796] = { +47,42,32,88,80,77,32,42,47,10,115,116,97,116,105,99, +32,99,104,97,114,32,42,32,105,110,102,111,95,98,97,110, +110,101,114,50,95,120,112,109,91,93,32,61,32,123,10,34, +52,54,48,32,51,53,32,51,51,32,49,34,44,10,34,32, +9,99,32,78,111,110,101,34,44,10,34,46,9,99,32,35, +48,48,48,48,48,48,34,44,10,34,43,9,99,32,35,70, +70,70,70,70,70,34,44,10,34,64,9,99,32,35,67,53, +67,53,67,53,34,44,10,34,35,9,99,32,35,65,52,65, +52,65,52,34,44,10,34,36,9,99,32,35,49,48,49,48, +49,48,34,44,10,34,37,9,99,32,35,54,50,54,50,54, +50,34,44,10,34,38,9,99,32,35,70,54,70,54,70,54, +34,44,10,34,42,9,99,32,35,66,52,66,52,66,52,34, +44,10,34,61,9,99,32,35,57,67,57,67,57,67,34,44, +10,34,45,9,99,32,35,56,66,56,66,56,66,34,44,10, +34,59,9,99,32,35,68,69,68,69,68,69,34,44,10,34, +62,9,99,32,35,50,57,50,57,50,57,34,44,10,34,44, +9,99,32,35,51,57,51,57,51,57,34,44,10,34,39,9, +99,32,35,50,48,50,48,50,48,34,44,10,34,41,9,99, +32,35,69,54,69,54,69,54,34,44,10,34,33,9,99,32, +35,54,65,54,65,54,65,34,44,10,34,126,9,99,32,35, +55,51,55,51,55,51,34,44,10,34,123,9,99,32,35,65, +67,65,67,65,67,34,44,10,34,93,9,99,32,35,66,68, +66,68,66,68,34,44,10,34,94,9,99,32,35,53,50,53, +50,53,50,34,44,10,34,47,9,99,32,35,52,65,52,65, +52,65,34,44,10,34,40,9,99,32,35,69,69,69,69,69, +69,34,44,10,34,95,9,99,32,35,51,49,51,49,51,49, +34,44,10,34,58,9,99,32,35,55,66,55,66,55,66,34, +44,10,34,60,9,99,32,35,48,56,48,56,48,56,34,44, +10,34,91,9,99,32,35,57,52,57,52,57,52,34,44,10, +34,125,9,99,32,35,67,68,67,68,67,68,34,44,10,34, +124,9,99,32,35,52,49,52,49,52,49,34,44,10,34,49, +9,99,32,35,53,65,53,65,53,65,34,44,10,34,50,9, +99,32,35,68,53,68,53,68,53,34,44,10,34,51,9,99, +32,35,49,56,49,56,49,56,34,44,10,34,52,9,99,32, +35,56,51,56,51,56,51,34,44,10,34,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,34,44,10,34,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,64,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,64,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,64,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,35,36,37,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,38,42,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,61,46,45,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,38,42,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,35,36,37,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,38,42,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +38,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,61,46,45,43, +43,43,43,43,43,43,43,35,36,37,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,35,36,37,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,61,46,45,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,59,36,35,62,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,38,44,39,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,41,33,59,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,38,44,39,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,59,36,35,62,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,38,44,39,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,38, +44,39,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,41,33,59,43, +43,43,43,43,43,43,59,36,35,62,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,59,36,35,62,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,41,33,59,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,126,123,43,93,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,94,47,40,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,95,95,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,95,95,43,95,95, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,94,47,40,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,126,123,43,93,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,94,47,40,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,95,95,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,94, +47,40,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,95,95,43,95,95, +43,43,43,43,43,43,126,123,43,93,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,126,123,43,93,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +95,95,43,95,95,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,95,95,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,33,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,58,61,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,94,47,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,94,47,43,47,94, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,58,61,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,33,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,58,61,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,94,47,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,58,61, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,94,47,43,47,94, +43,43,43,43,43,43,33,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,33,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +94,47,43,47,94,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,94,47,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,47,46,46,46,46,46,46,46, +46,46,46,46,44,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,59,94,60,60,95,45,43,43,41,91,47, +60,125,124,60,36,37,40,43,43,40,61,47,60,125,124,60, +36,49,41,43,43,43,43,43,43,64,44,124,43,43,43,43, +43,40,61,47,60,64,124,60,36,49,41,43,43,43,43,38, +126,33,41,43,43,123,49,123,43,43,43,46,46,91,43,43, +43,43,43,43,43,40,61,47,60,50,49,51,46,51,37,42, +47,60,60,94,41,43,43,43,43,43,43,43,43,43,43,43, +43,64,44,124,43,43,43,43,43,43,43,43,59,94,60,60, +95,45,43,43,40,61,47,60,64,124,60,36,49,41,43,43, +43,43,43,59,94,60,60,95,45,43,43,40,61,47,60,125, +47,60,60,94,42,49,51,46,62,45,43,43,43,43,43,43, +43,64,44,124,43,43,43,43,43,40,61,47,60,64,124,60, +36,49,41,43,43,43,43,38,126,33,41,43,43,123,49,123, +43,43,43,46,46,91,43,43,43,43,43,43,43,40,61,47, +60,125,124,60,36,49,41,43,43,43,43,43,43,64,44,124, +43,43,43,43,43,40,61,47,60,50,49,51,46,51,37,42, +47,60,60,94,41,43,43,43,43,43,43,64,44,124,43,43, +43,43,43,43,43,43,59,94,60,60,95,45,43,43,43,43, +43,43,43,43,40,61,47,60,50,49,51,46,51,37,42,47, +60,60,49,40,43,43,40,61,47,60,125,124,60,36,49,41, +43,43,43,43,43,35,124,60,46,39,58,40,43,40,61,47, +60,50,49,51,46,51,37,42,47,60,60,94,41,43,43,59, +124,46,46,46,46,46,46,46,46,62,125,43,43,42,62,46, +46,46,36,124,91,43,43,43,40,61,47,60,64,124,60,36, +49,41,43,43,43,43,38,126,33,41,43,43,123,49,123,43, +43,43,46,46,91,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,61,62,93,43,41,37,46,44,38,50,35,46, +46,58,40,41,33,46,62,38,43,59,35,46,46,52,40,40, +126,46,51,41,43,43,43,43,43,43,124,46,42,43,43,43, +43,125,35,46,46,45,40,40,126,46,51,41,43,43,43,44, +47,43,43,43,126,62,40,43,43,43,43,46,46,43,43,43, +43,43,43,43,43,125,35,46,46,58,41,43,125,124,46,46, +125,38,52,46,51,41,43,43,43,43,43,43,43,43,43,43, +43,43,124,46,42,43,43,43,43,43,43,61,62,93,43,41, +37,46,44,38,125,35,46,46,45,40,40,126,46,51,41,43, +43,43,61,62,93,43,41,37,46,44,38,64,35,46,46,58, +40,41,33,46,46,125,43,125,44,46,124,43,43,43,43,43, +43,43,124,46,42,43,43,43,43,125,35,46,46,45,40,40, +126,46,51,41,43,43,43,44,47,43,43,43,126,62,40,43, +43,43,43,46,46,43,43,43,43,43,43,43,43,59,35,46, +46,52,40,40,126,46,51,41,43,43,43,43,43,43,124,46, +42,43,43,43,43,125,35,46,46,58,41,43,125,124,46,46, +125,38,52,46,51,41,43,43,43,43,43,43,124,46,42,43, +43,43,43,43,43,61,62,93,43,41,37,46,44,38,43,43, +43,43,43,43,125,35,46,46,33,59,43,64,44,46,46,50, +38,58,46,39,40,43,59,35,46,46,52,40,40,126,46,51, +41,43,43,43,49,51,93,43,41,91,36,51,38,125,35,46, +46,58,41,43,125,124,46,46,125,38,52,46,51,41,43,43, +125,46,91,43,43,43,38,46,46,43,43,43,123,95,64,43, +38,59,91,36,46,95,40,43,125,35,46,46,45,40,40,126, +46,51,41,43,43,43,44,47,43,43,43,126,62,40,43,43, +43,43,46,46,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,93,46,42,43,43,43,43,47,46,33,43,43,46, +46,43,43,43,43,47,46,126,43,43,43,46,46,43,43,43, +43,37,46,49,43,43,43,43,43,93,64,36,62,43,43,43, +43,43,43,46,46,43,43,43,43,49,46,49,43,43,45,46, +64,43,43,123,46,42,43,43,43,43,43,46,46,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,124,46, +94,43,43,33,46,49,43,43,43,43,43,43,43,43,43,43, +43,93,64,36,62,43,43,43,43,43,93,46,42,43,43,43, +43,47,46,33,43,43,46,46,43,43,43,43,49,46,49,43, +43,93,46,42,43,43,43,43,47,46,33,43,43,46,46,43, +43,43,43,47,46,37,43,43,43,95,46,52,43,43,43,43, +43,93,64,36,62,43,43,43,43,43,43,46,46,43,43,43, +43,49,46,49,43,43,45,46,64,43,43,123,46,42,43,43, +43,43,43,46,46,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,37,46,49,43,43,43,43,43,93,64,36, +62,43,43,43,43,43,43,46,46,43,43,43,43,43,124,46, +94,43,43,33,46,49,43,43,43,43,43,93,64,36,62,43, +43,43,43,43,93,46,42,43,43,43,43,47,46,33,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,95,46,37, +43,43,94,46,126,43,43,43,46,46,43,43,43,43,37,46, +49,43,43,91,46,42,43,43,43,43,64,58,43,43,43,46, +46,43,43,43,43,43,124,46,94,43,43,33,46,49,43,43, +94,46,41,43,43,43,43,46,46,43,43,43,39,41,43,43, +43,43,43,59,36,46,126,43,43,43,46,46,43,43,43,43, +49,46,49,43,43,45,46,64,43,43,123,46,42,43,43,43, +43,43,46,46,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,44,46,38,43,43,43,43,64,46,36,43,43,46, +46,43,43,43,43,93,46,39,43,43,43,46,46,43,43,43, +43,125,46,36,43,43,43,43,43,91,43,52,46,91,43,43, +43,43,43,46,46,43,43,43,43,125,46,36,43,43,62,46, +38,43,43,95,46,38,43,43,43,43,43,46,46,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,64,46, +36,43,43,50,46,36,43,43,43,43,43,43,43,43,43,43, +43,91,43,52,46,91,43,43,43,43,44,46,38,43,43,43, +43,64,46,36,43,43,46,46,43,43,43,43,125,46,36,43, +43,44,46,38,43,43,43,43,64,46,36,43,43,46,46,43, +43,43,43,93,46,51,43,43,43,42,46,39,43,43,43,43, +43,91,43,52,46,91,43,43,43,43,43,46,46,43,43,43, +43,125,46,36,43,43,62,46,38,43,43,95,46,38,43,43, +43,43,43,46,46,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,125,46,36,43,43,43,43,43,91,43,52, +46,91,43,43,43,43,43,46,46,43,43,43,43,43,64,46, +36,43,43,50,46,36,43,43,43,43,43,91,43,52,46,91, +43,43,43,43,44,46,38,43,43,43,43,64,46,36,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,42,46,51, +43,43,64,46,51,43,43,43,46,46,43,43,43,43,125,46, +36,43,43,62,46,38,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,64,46,36,43,43,50,46,36,43,43, +36,46,43,43,43,43,43,46,46,43,43,40,46,38,43,43, +43,43,43,43,45,46,39,43,43,43,46,46,43,43,43,43, +125,46,36,43,43,62,46,38,43,43,95,46,38,43,43,43, +43,43,46,46,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,46,46,38,43,43,43,43,38,46,60,43,43,46, +46,43,43,43,43,40,46,46,43,43,43,46,46,43,43,43, +43,43,46,46,43,43,43,43,61,40,43,38,36,36,38,43, +43,43,43,46,46,43,43,43,43,38,46,46,43,43,46,46, +43,43,43,60,46,38,43,43,43,43,43,46,46,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,38,46, +60,43,43,43,46,60,43,43,43,43,43,43,43,43,43,43, +61,40,43,38,36,36,38,43,43,43,46,46,38,43,43,43, +43,38,46,60,43,43,46,46,43,43,43,43,38,46,46,43, +43,46,46,38,43,43,43,43,38,46,60,43,43,46,46,43, +43,43,43,38,46,46,43,43,43,40,46,46,43,43,43,43, +61,40,43,38,36,36,38,43,43,43,43,46,46,43,43,43, +43,38,46,46,43,43,46,46,43,43,43,60,46,38,43,43, +43,43,43,46,46,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,46,46,43,43,43,43,61,40,43,38, +36,36,38,43,43,43,43,46,46,43,43,43,43,43,38,46, +60,43,43,43,46,60,43,43,43,43,61,40,43,38,36,36, +38,43,43,43,46,46,38,43,43,43,43,38,46,60,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,40,46,46, +43,43,38,46,46,43,43,43,46,46,43,43,43,43,43,46, +46,43,43,46,46,38,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,38,46,60,43,43,43,46,60,43,43, +46,46,40,43,43,43,43,46,46,43,43,40,46,45,43,43, +43,43,43,43,41,46,46,43,43,43,46,46,43,43,43,43, +38,46,46,43,43,46,46,43,43,43,60,46,38,43,43,43, +43,43,46,46,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,36,46,93,43,43,43,43,38,46,44,43,43,46, +46,43,43,43,43,43,46,36,43,43,43,46,46,43,43,43, +43,38,46,62,43,43,43,40,35,43,43,43,45,46,126,43, +43,43,43,46,46,43,43,43,43,38,46,62,43,43,36,46, +125,43,43,36,46,64,43,43,43,43,43,46,46,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,38,46, +95,43,43,38,46,95,43,43,43,43,43,43,43,43,43,40, +35,43,43,43,45,46,126,43,43,43,36,46,93,43,43,43, +43,38,46,44,43,43,46,46,43,43,43,43,38,46,62,43, +43,36,46,93,43,43,43,43,38,46,44,43,43,46,46,43, +43,43,43,43,46,51,43,43,43,43,46,51,43,43,43,40, +35,43,43,43,45,46,126,43,43,43,43,46,46,43,43,43, +43,38,46,62,43,43,36,46,125,43,43,36,46,64,43,43, +43,43,43,46,46,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,38,46,62,43,43,43,40,35,43,43,43, +45,46,126,43,43,43,43,46,46,43,43,43,43,43,38,46, +95,43,43,38,46,95,43,43,43,40,35,43,43,43,45,46, +126,43,43,43,36,46,93,43,43,43,43,38,46,44,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,43,46,51, +43,43,43,46,51,43,43,43,46,46,43,43,43,43,38,46, +62,43,43,39,46,93,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,38,46,95,43,43,38,46,95,43,43, +51,46,93,43,43,43,43,46,46,43,43,43,60,46,33,35, +64,43,43,43,38,46,36,43,43,43,46,46,43,43,43,43, +38,46,62,43,43,36,46,125,43,43,36,46,64,43,43,43, +43,43,46,46,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,126,46,44,43,43,43,43,64,46,42,43,43,46, +46,43,43,43,43,41,46,94,43,43,43,46,46,43,43,43, +43,64,46,91,43,40,47,126,43,43,43,43,38,51,60,41, +43,43,43,46,46,43,43,43,43,93,46,91,43,43,49,46, +49,43,43,37,46,44,43,43,43,43,43,46,46,38,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,42,46, +61,43,43,93,46,61,43,43,43,43,43,43,43,40,47,126, +43,43,43,43,38,51,60,41,43,43,126,46,44,43,43,43, +43,64,46,42,43,43,46,46,43,43,43,43,93,46,91,43, +43,126,46,44,43,43,43,43,64,46,42,43,43,46,46,43, +43,43,43,41,46,49,43,43,43,50,46,126,43,40,47,126, +43,43,43,43,38,51,60,41,43,43,43,46,46,43,43,43, +43,93,46,91,43,43,49,46,49,43,43,37,46,44,43,43, +43,43,43,46,46,38,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,64,46,91,43,40,47,126,43,43,43,43, +38,51,60,41,43,43,43,46,46,43,43,43,43,43,42,46, +61,43,43,93,46,61,43,40,47,126,43,43,43,43,38,51, +60,41,43,43,126,46,44,43,43,43,43,64,46,42,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,59,46,49, +43,43,59,46,33,43,43,43,46,46,43,43,43,43,64,46, +91,43,43,52,46,44,43,43,43,43,43,40,50,43,43,46, +46,43,43,43,43,43,42,46,61,43,43,93,46,61,43,43, +126,46,124,43,43,43,43,46,46,43,43,43,126,46,46,46, +125,43,43,43,42,46,94,43,43,43,46,46,43,43,43,43, +93,46,91,43,43,49,46,49,43,43,37,46,44,43,43,43, +43,43,46,46,38,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,38,44,46,94,59,43,64,62,45,43,43,43,46, +46,43,43,43,43,35,46,64,43,43,43,46,46,43,43,43, +43,44,47,43,43,33,46,93,43,43,43,43,43,61,46,47, +50,43,43,46,46,43,43,43,43,44,124,43,43,43,59,36, +46,33,41,64,46,46,95,123,59,64,33,46,46,52,123,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,40,39,94, +43,43,43,95,47,43,43,43,43,43,43,43,43,33,46,93, +43,43,43,43,43,61,46,47,50,43,38,44,46,94,59,43, +64,62,45,43,43,43,46,46,43,43,43,43,44,124,43,43, +43,38,44,46,94,59,43,64,62,45,43,43,43,46,46,43, +43,43,43,91,46,50,43,43,43,49,36,40,43,33,46,93, +43,43,43,43,43,61,46,47,50,43,43,46,46,43,43,43, +43,44,124,43,43,43,59,36,46,33,41,64,46,46,95,123, +59,64,33,46,46,52,123,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,44,47,43,43,33,46,93,43,43,43,43, +43,61,46,47,50,43,43,46,46,43,43,43,43,40,39,94, +43,43,43,95,47,43,43,33,46,93,43,43,43,43,43,61, +46,47,50,43,38,44,46,94,59,43,64,62,45,43,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,58,46,125, +43,43,45,36,40,43,43,43,46,46,43,43,43,43,44,47, +43,43,43,43,47,46,47,50,43,40,58,49,43,43,43,46, +46,43,43,43,43,40,39,94,43,43,43,95,47,43,43,43, +38,62,46,37,41,40,58,46,46,43,43,43,43,93,52,123, +43,43,43,38,62,46,93,43,43,43,46,46,43,43,43,43, +44,124,43,43,43,59,36,46,33,41,64,46,46,95,123,59, +64,33,46,46,52,123,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,38,45,62,60,60,47,50,43,43,43,43,46, +46,46,46,46,46,46,46,95,50,43,52,46,46,43,43,59, +49,52,43,43,43,45,37,43,43,43,43,43,43,43,39,124, +93,43,43,46,46,43,43,59,49,52,43,43,43,43,43,59, +47,60,60,94,64,33,39,60,62,126,41,60,94,123,38,43, +43,43,43,43,43,43,43,46,46,43,43,43,35,47,45,43, +43,41,33,52,43,43,43,43,43,43,43,43,43,45,37,43, +43,43,43,43,43,43,39,124,93,43,43,38,45,62,60,60, +47,50,43,43,43,43,46,46,43,43,59,49,52,43,43,43, +43,43,38,45,62,60,60,47,50,43,43,43,43,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,39,125,45,37,43, +43,43,43,43,43,43,39,124,93,43,43,46,46,43,43,59, +49,52,43,43,43,43,43,59,47,60,60,94,64,33,39,60, +62,126,41,60,94,123,38,43,43,43,43,43,43,43,52,46, +46,43,43,59,49,52,43,43,43,45,37,43,43,43,43,43, +43,43,39,124,93,43,43,46,46,43,43,43,35,47,45,43, +43,41,33,52,43,43,43,45,37,43,43,43,43,43,43,43, +39,124,93,43,43,38,45,62,60,60,47,50,43,43,43,43, +43,43,43,43,43,43,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,39,125,43,52,46,46,43,43,59,49,52,43, +43,43,43,43,43,91,95,60,60,44,93,43,43,43,43,46, +46,43,43,43,35,47,45,43,43,41,33,52,43,43,43,43, +43,40,49,36,60,124,50,46,46,43,43,43,43,43,43,43, +43,43,38,47,46,45,43,43,43,43,46,46,43,43,59,49, +52,43,43,43,43,43,59,47,60,60,94,64,33,39,60,62, +126,41,60,94,123,38,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,46,46,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,46,46,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,43,43, +43,50,95,62,64,43,43,43,43,43,46,46,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,46,46,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,46,46,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,43,43, +58,39,91,43,43,43,43,43,43,43,46,46,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,46,46,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,46,46,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,38,47, +58,38,43,43,43,43,43,43,43,43,46,46,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,46,46,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,46,46,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,126,93, +43,43,43,43,43,43,43,43,43,43,46,46,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,43,43,43,43,43,43,43,43,62,62, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,46,46,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,62,39,43, +39,39,43,43,43,43,46,46,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,46,46,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,46,46,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46, +46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,43,43,43,43,59,91,43, +43,43,43,43,43,43,43,43,43,43,46,46,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46, +46,41,41,43,43,43,43,43,43,43,43,43,43,43,37,37, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,46,46,38,40,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,59,41,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,37,49,43, +49,37,43,43,43,43,46,46,38,40,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,46,46,38,40,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,59,41,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,46,46,59,41,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46, +46,59,41,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,46,46,50,59,43,43,91,43,43, +43,43,43,43,43,43,43,43,43,43,46,46,38,40,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,60, +49,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,46,46,33,59,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,60,37,93,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,46,46,33,59,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,46,46,33,59,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,60,37,93,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,60,49,42,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,60, +37,93,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,36,49,93,43,43,43,35,43,43, +43,43,43,43,43,43,43,43,43,43,46,46,33,59,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,58,41,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,58,41,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,58,41,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,125,41,43,43, +43,43,43,43,43,43,43,43,43,43,58,41,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,44,10,34,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,34,125,59,10, +0}; diff --git a/rdairplay/Makefile.am b/rdairplay/Makefile.am new file mode 100644 index 00000000..696a06c3 --- /dev/null +++ b/rdairplay/Makefile.am @@ -0,0 +1,108 @@ +## automake.am +## +## Automake.am for rivendell/rdairplay +## +## (C) 2002-2008 Fred Gleason +## +## $Id: Makefile.am,v 1.48.8.5 2013/12/28 00:00:33 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdairplay_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/srlabs/rdairplay_*.qm + +all: + @QT_BIN@/lupdate rdairplay.pro + @QT_BIN@/lrelease rdairplay.pro + +bin_PROGRAMS = rdairplay + +dist_rdairplay_SOURCES = button_log.cpp button_log.h\ + edit_event.cpp edit_event.h\ + globals.h\ + hourselector.cpp hourselector.h\ + lib_listview.cpp lib_listview.h\ + list_log.cpp list_log.h\ + list_logs.cpp list_logs.h\ + local_macros.cpp colors.h\ + log_play.cpp log_play.h\ + log_traffic.cpp log_traffic.h\ + loglinebox.cpp loglinebox.h\ + mode_display.cpp mode_display.h\ + nownext.cpp\ + pie_counter.cpp pie_counter.h\ + post_counter.cpp post_counter.h\ + rdairplay.cpp rdairplay.h\ + rlmhost.cpp rlmhost.h\ + start_button.cpp start_button.h\ + stop_counter.cpp stop_counter.h\ + wall_clock.cpp wall_clock.h + + +nodist_rdairplay_SOURCES = moc_button_log.cpp\ + moc_edit_event.cpp\ + moc_hourselector.cpp\ + moc_lib_listview.cpp\ + moc_list_log.cpp\ + moc_list_logs.cpp\ + moc_log_play.cpp\ + moc_loglinebox.cpp\ + moc_mode_display.cpp\ + moc_pie_counter.cpp\ + moc_post_counter.cpp\ + moc_rdairplay.cpp\ + moc_rlmhost.cpp\ + moc_start_button.cpp\ + moc_stop_counter.cpp\ + moc_wall_clock.cpp + +rdairplay_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ +rdairplay_LDFLAGS = -rdynamic + +EXTRA_DIST = rdairplay.pro\ + rdairplay_cs.ts\ + rdairplay_de.ts\ + rdairplay_es.ts\ + rdairplay_fr.ts\ + rdairplay_nb.ts\ + rdairplay_nn.ts\ + rdairplay_pt_BR.ts + +CLEANFILES = *~\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/rdairplay/button_log.cpp b/rdairplay/button_log.cpp new file mode 100644 index 00000000..4eebf370 --- /dev/null +++ b/rdairplay/button_log.cpp @@ -0,0 +1,657 @@ +// button_log.cpp +// +// The button log widget for RDAirPlay +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: button_log.cpp,v 1.46.6.3 2014/02/06 20:43:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include + +#include +#include +#include + +ButtonLog::ButtonLog(LogPlay *log,int id,RDAirPlayConf *conf,bool allow_pause, + QWidget *parent,const char *name) + : QWidget(parent,name) +{ + log_id=id; + log_log=log; + log_action_mode=RDAirPlayConf::Normal; + log_op_mode=RDAirPlayConf::LiveAssist; + log_time_mode=RDAirPlayConf::TwentyFourHour; + log_pause_enabled=allow_pause; + + QFont font=QFont("Helvetica",14,QFont::Bold); + font.setPixelSize(14); + + // + // Set Mappings + // + connect(log_log,SIGNAL(transportChanged()), + this,SLOT(transportChangedData())); + connect(log_log,SIGNAL(modified(int)),this,SLOT(modifiedData(int))); + connect(log_log,SIGNAL(played(int)),this,SLOT(playedData(int))); + connect(log_log,SIGNAL(stopped(int)),this,SLOT(stoppedData(int))); + connect(log_log,SIGNAL(paused(int)),this,SLOT(pausedData(int))); + connect(log_log,SIGNAL(position(int,int)),this,SLOT(positionData(int,int))); + + // + // Edit Event Dialog + // + log_event_edit=new EditEvent(log_log,this,"list_event_edit"); + + // + // Line Boxes / Start Buttons + // + QSignalMapper *mapper=new QSignalMapper(this,"start_button_mapper"); + connect(mapper,SIGNAL(mapped(int)), + this,SLOT(startButton(int))); + for(int i=0;isetMode(LogLineBox::Full); + log_line_box[i]->setAcceptDrops(rdstation_conf->enableDragdrop()); + log_line_box[i]->setAllowDrags(rdstation_conf->enableDragdrop()); + log_line_box[i]->setGeometry(10+log_line_box[i]->sizeHint().height(), + (log_line_box[i]->sizeHint().height()+12)*i, + log_line_box[i]->sizeHint().width(), + log_line_box[i]->sizeHint().height()); + connect(log_line_box[i],SIGNAL(doubleClicked(int)), + this,SLOT(boxDoubleClickedData(int))); + connect(log_line_box[i],SIGNAL(cartDropped(int,RDLogLine *)), + this,SLOT(cartDroppedData(int,RDLogLine *))); + log_start_button[i]=new StartButton(allow_pause,this); + log_start_button[i]->setGeometry(5, + (log_line_box[i]->sizeHint().height()+12)*i, + log_line_box[i]->sizeHint().height(), + log_line_box[i]->sizeHint().height()); + mapper->setMapping(log_start_button[i],i); + connect(log_start_button[i],SIGNAL(clicked()), + mapper,SLOT(map())); + } + + for(int i=BUTTON_PLAY_BUTTONS;isetMode(LogLineBox::Half); + log_line_box[i]->setAcceptDrops(rdstation_conf->enableDragdrop()); + log_line_box[i]->setAllowDrags(rdstation_conf->enableDragdrop()); + log_line_box[i]->setGeometry(10+log_line_box[0]->sizeHint().height(), + (log_line_box[0]->sizeHint().height()+12)*3+ + (log_line_box[i]->sizeHint().height()+12)*(i-3), + log_line_box[i]->sizeHint().width(), + log_line_box[i]->sizeHint().height()); + connect(log_line_box[i],SIGNAL(doubleClicked(int)), + this,SLOT(boxDoubleClickedData(int))); + connect(log_line_box[i],SIGNAL(cartDropped(int,RDLogLine *)), + this,SLOT(cartDroppedData(int,RDLogLine *))); + log_start_button[i]=new StartButton(allow_pause,this); + log_start_button[i]->setGeometry(5, + (log_line_box[0]->sizeHint().height()+12)*3+ + (log_line_box[i]->sizeHint().height()+12)*(i-3), + log_line_box[0]->sizeHint().height(), + log_line_box[i]->sizeHint().height()); + mapper->setMapping(log_start_button[i],i); + connect(log_start_button[i],SIGNAL(clicked()), + mapper,SLOT(map())); + } +} + + +QSize ButtonLog::sizeHint() const +{ + return QSize(500,530); +} + + +QSizePolicy ButtonLog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +RDAirPlayConf::OpMode ButtonLog::opMode() const +{ + return log_op_mode; +} + + +void ButtonLog::setOpMode(RDAirPlayConf::OpMode mode) +{ + if(mode==log_op_mode) { + return; + } + log_op_mode=mode; + UpdateButtons(); +} + + +RDAirPlayConf::ActionMode ButtonLog::actionMode() const +{ + return log_action_mode; +} + + +void ButtonLog::setActionMode(RDAirPlayConf::ActionMode mode,int *cartnum) +{ + int lines[TRANSPORT_QUANTITY]; + RDLogLine *logline=NULL; + bool end_button=false; + + log_cart=cartnum; + + log_log->transportEvents(lines); + + for(int i=0;ilogLine(lines[i]))!=NULL)) { + switch(logline->status()) { + case RDLogLine::Playing: + case RDLogLine::Finishing: + if(mode==RDAirPlayConf::CopyFrom) { + log_start_button[i]-> + setMode(StartButton::CopyFrom,logline->cartType()); + } + else { + log_start_button[i]-> + setMode(StartButton::Play,logline->cartType()); + } + break; + + case RDLogLine::Paused: + switch(mode) { + case RDAirPlayConf::DeleteFrom: + log_start_button[i]-> + setMode(StartButton::DeleteFrom,logline->cartType()); + break; + + case RDAirPlayConf::CopyFrom: + log_start_button[i]-> + setMode(StartButton::CopyFrom,logline->cartType()); + break; + + default: + log_start_button[i]-> + setMode(StartButton::Pause,logline->cartType()); + } + break; + + default: + switch(mode) { + case RDAirPlayConf::Normal: + log_start_button[i]-> + setMode(StartButton::Stop,logline->cartType()); + break; + + case RDAirPlayConf::AddTo: + log_start_button[i]-> + setMode(StartButton::AddTo,logline->cartType()); + break; + + case RDAirPlayConf::DeleteFrom: + log_start_button[i]-> + setMode(StartButton::DeleteFrom,logline->cartType()); + break; + + case RDAirPlayConf::MoveFrom: + log_start_button[i]-> + setMode(StartButton::MoveFrom,logline->cartType()); + break; + + case RDAirPlayConf::MoveTo: + log_start_button[i]-> + setMode(StartButton::MoveTo,logline->cartType()); + break; + + case RDAirPlayConf::CopyFrom: + switch(logline->type()) { + case RDLogLine::Marker: + case RDLogLine::OpenBracket: + case RDLogLine::CloseBracket: + case RDLogLine::Chain: + case RDLogLine::Track: + case RDLogLine::MusicLink: + case RDLogLine::TrafficLink: + case RDLogLine::UnknownType: + log_start_button[i]-> + setMode(StartButton::Stop,logline->cartType()); + break; + + case RDLogLine::Cart: + case RDLogLine::Macro: + log_start_button[i]-> + setMode(StartButton::CopyFrom,logline->cartType()); + break; + } + break; + + case RDAirPlayConf::CopyTo: + log_start_button[i]-> + setMode(StartButton::CopyTo,logline->cartType()); + break; + + default: + break; + } + } + } + else { + if(!end_button) { + switch(mode) { + case RDAirPlayConf::AddTo: + log_start_button[i]-> + setMode(StartButton::AddTo,RDCart::All); + end_button=true; + break; + + case RDAirPlayConf::MoveTo: + log_start_button[i]-> + setMode(StartButton::MoveTo,RDCart::All); + end_button=true; + break; + + case RDAirPlayConf::CopyTo: + log_start_button[i]-> + setMode(StartButton::CopyTo,RDCart::All); + end_button=true; + break; + + default: + log_start_button[i]-> + setMode(StartButton::Disabled,RDCart::All); + break; + } + end_button=true; + } + else { + log_start_button[i]-> + setMode(StartButton::Disabled,RDCart::All); + } + } + } + log_action_mode=mode; +} + + +void ButtonLog::setTimeMode(RDAirPlayConf::TimeMode mode) +{ + if(mode==log_time_mode) { + return; + } + log_time_mode=mode; + for(int i=0;isetTimeMode(mode); + log_line_box[i]->setTimeMode(mode); + } +} + + +void ButtonLog::startButton(int id) +{ +#ifdef SHOW_SLOTS + printf("startMapperData(%d)\n",id); +#endif + RDLogLine::Status status=RDLogLine::Scheduled; + int line=log_line_box[id]->line(); + RDLogLine *logline=log_log->logLine(line); + if(line<0) { + line=log_log->size(); + } + switch(log_start_button[id]->mode()) { + case StartButton::Stop: + log_log->makeNext(line,false); + log_log->play(line,RDLogLine::StartManual); + break; + + case StartButton::Pause: + log_log->play(line,RDLogLine::StartManual); + break; + + case StartButton::Play: + if(log_pause_enabled&&(logline!=NULL)&& + (logline->cartType()==RDCart::Audio)) { + log_log->pause(line); + } + else { + log_log->stop(line); + } + break; + + case StartButton::AddTo: + case StartButton::DeleteFrom: + case StartButton::MoveFrom: + case StartButton::MoveTo: + case StartButton::CopyFrom: + case StartButton::CopyTo: + if((logline=log_log->logLine(line))==NULL) { + status=RDLogLine::Scheduled; + } + else { + status=logline->status(); + } + emit selectClicked(log_id,line,status); + break; + + default: + break; + } +} + +void ButtonLog::pauseButtonHotkey(int id) +{ + int line=log_line_box[id]->line(); + if (line<0) { + line=log_log->size(); + } + if (log_start_button[id]->mode() == StartButton::Play) { + log_log->pause(line); + } +} + +void ButtonLog::stopButtonHotkey(int id) +{ + int line=log_line_box[id]->line(); + if (line<0) { + line=log_log->size(); + } + log_log->stop(line); +} + +void ButtonLog::transportChangedData() +{ + UpdateEvents(); + UpdateButtons(); + if(log_action_mode!=RDAirPlayConf::Normal) { + setActionMode(log_action_mode); + } +} + + +void ButtonLog::modifiedData(int line) +{ + int lines[TRANSPORT_QUANTITY]; + RDLogLine *logline; + RDLogLine *next_logline; + + log_log->transportEvents(lines); + for(int i=0;ilogLine(line))!=NULL) { + if((next_logline=log_log->logLine(line+1))!=NULL) { + log_line_box[i]->setEvent(line,next_logline->transType(),logline); + } + else { + log_line_box[i]->setEvent(line,RDLogLine::Stop,logline); + } + } + else { + log_line_box[i]->clear(); + } + } + } +} + + +void ButtonLog::boxDoubleClickedData(int line) +{ + if(line<0) { + return; + } + if(log_event_edit->exec(line)==0) { + log_log->lineModified(line); + } + if(line==1) { + return; + } +} + + +void ButtonLog::playedData(int line) +{ + for(int i=0;iline()==line) { + log_start_button[i]->setMode(StartButton::Play, + log_log->logLine(line)->cartType()); + UpdateButtons(); + return; + } + } + UpdateEvents(); +} + + +void ButtonLog::stoppedData(int line) +{ + for(int i=0;iline()==line) { + return; + } + } + UpdateEvents(); +} + + +void ButtonLog::pausedData(int line) +{ + for(int i=0;iline()==line) { + return; + } + } + UpdateEvents(); +} + + +void ButtonLog::positionData(int line,int point) +{ + for(int i=0;iline()==line) { + log_line_box[i]->setTimer(point); + return; + } + } +} + + +void ButtonLog::cartDroppedData(int line,RDLogLine *ll) +{ + emit cartDropped(log_id,line,ll); +} + + +void ButtonLog::UpdateEvents() +{ + RDLogLine *logline=NULL; + RDLogLine::TransType trans_type; + int lines[TRANSPORT_QUANTITY]; + log_log->transportEvents(lines); + int next_line; + for(int i=0;i=0) { + if((logline=log_log->logLine(lines[i]))!=NULL) { + log_start_button[i]->setPort(logline->portName()); + log_line_box[i]->setStatus(log_log->logLine(lines[i])->status()); + switch(log_log->logLine(lines[i])->status()) { + case RDLogLine::Playing: + case RDLogLine::Finishing: + log_start_button[i]-> + setMode(StartButton::Play,logline->cartType()); + break; + + case RDLogLine::Paused: + log_start_button[i]-> + setMode(StartButton::Pause,logline->cartType()); + break; + + case RDLogLine::Scheduled: + log_start_button[i]-> + setMode(StartButton::Stop,logline->cartType()); + break; + + default: + log_start_button[i]-> + setMode(StartButton::Disabled,logline->cartType()); + break; + } + } + if((next_line=log_log->nextLine(lines[i]))>=0) { + trans_type=log_log->logLine(next_line)->transType(); + } + else { + trans_type=RDLogLine::Stop; + } + log_line_box[i]-> + setEvent(lines[i],trans_type,log_log->logLine(lines[i])); + } + else { + log_start_button[i]->setMode(StartButton::Disabled,RDCart::All); + log_line_box[i]->clear(); + } + } +} + + +void ButtonLog::UpdateButtons() +{ + QTime time; + QTime end_time; + int lines[TRANSPORT_QUANTITY]; + RDLogLine *logline; + RDLogLine *next_logline; + int running; + int longest_line=-1; + + // + // Get Longest-Running Event + // + if((running=log_log->runningEvents(lines,false))>0) { + for(int i=0;ilogLine(lines[i]))!=NULL) { + if((time=logline->startTime(RDLogLine::Actual). + addMSecs(logline->effectiveLength()))>end_time) { + end_time=time; + longest_line=lines[i]; + } + } + } + } + log_log->transportEvents(lines); + + for(int i=0;i=0) { + if((logline=log_log->logLine(lines[i]))!=NULL) { + // + // Set Buttons + // + switch(logline->status()) { + case RDLogLine::Playing: + case RDLogLine::Finishing: + log_start_button[i]-> + setMode(StartButton::Play,logline->cartType()); + log_start_button[i]-> + setTime(logline->startTime(RDLogLine::Actual)); + break; + + case RDLogLine::Paused: + log_start_button[i]-> + setMode(StartButton::Pause,logline->cartType()); + log_start_button[i]-> + setTime(logline->startTime(RDLogLine::Predicted)); + break; + + case RDLogLine::Scheduled: + log_start_button[i]-> + setMode(StartButton::Stop,logline->cartType()); + log_start_button[i]-> + setTime(logline->startTime(RDLogLine::Predicted)); + break; + + default: + log_start_button[i]-> + setMode(StartButton::Disabled,logline->cartType()); + break; + } + + // + // Set Progress Bars + // + if((next_logline=log_log->logLine(log_log->nextLine(lines[i])))!= + NULL) { + switch(log_log->mode()) { + case RDAirPlayConf::Auto: + switch(next_logline->transType()) { + case RDLogLine::Play: + case RDLogLine::Segue: + log_line_box[i]->setBarMode(LogLineBox::Transitioning); + break; + + case RDLogLine::Stop: + if(lines[i]==longest_line) { + log_line_box[i]->setBarMode(LogLineBox::Stopping); + } + else { + log_line_box[i]->setBarMode(LogLineBox::Transitioning); + } + break; + + default: + break; + } + break; + + case RDAirPlayConf::LiveAssist: + case RDAirPlayConf::Manual: + switch(next_logline->status()) { + case RDLogLine::Playing: + case RDLogLine::Finishing: + log_line_box[i]->setBarMode(LogLineBox::Transitioning); + break; + + default: + if(lines[i]==longest_line) { + log_line_box[i]->setBarMode(LogLineBox::Stopping); + } + else { + log_line_box[i]->setBarMode(LogLineBox::Transitioning); + } + break; + } + break; + + default: + break; + } + } + else { + if(lines[i]==longest_line) { + log_line_box[i]->setBarMode(LogLineBox::Stopping); + } + else { + log_line_box[i]->setBarMode(LogLineBox::Transitioning); + } + } + } + else { + log_start_button[i]-> + setMode(StartButton::Disabled,logline->cartType()); + } + } + } +} diff --git a/rdairplay/button_log.h b/rdairplay/button_log.h new file mode 100644 index 00000000..81b0d37f --- /dev/null +++ b/rdairplay/button_log.h @@ -0,0 +1,101 @@ + +// button_log.h +// +// The button play widget for RDAirPlay. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: button_log.h,v 1.17.6.2 2014/01/07 18:18:32 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BUTTON_LOG_H +#define BUTTON_LOG_H + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// +// Widget Settings +// +#define BUTTON_PLAY_BUTTONS 3 +#define BUTTON_TOTAL_BUTTONS 7 + + +class ButtonLog : public QWidget +{ + Q_OBJECT + public: + ButtonLog(LogPlay *log,int id,RDAirPlayConf *conf,bool allow_pause=false, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + RDAirPlayConf::OpMode opMode() const; + void setOpMode(RDAirPlayConf::OpMode mode); + RDAirPlayConf::ActionMode actionMode() const; + void setActionMode(RDAirPlayConf::ActionMode mode,int *cartnum=0); + void setTimeMode(RDAirPlayConf::TimeMode mode); + + public slots: + void startButton(int); + void stopButtonHotkey(int); + void pauseButtonHotkey(int); + + private slots: + void transportChangedData(); + void modifiedData(int line); + void boxDoubleClickedData(int line); + void playedData(int line); + void stoppedData(int line); + void pausedData(int line); + void positionData(int line,int point); + void cartDroppedData(int line,RDLogLine *ll); + + signals: + void selectClicked(int id,int line,RDLogLine::Status); + void cartDropped(int id,int line,RDLogLine *ll); + + private: + void UpdateEvents(); + void UpdateButtons(); + LogPlay *log_log; + int log_id; + int *log_cart; + RDAirPlayConf::OpMode log_op_mode; + RDAirPlayConf::ActionMode log_action_mode; + LogLineBox *log_line_box[BUTTON_TOTAL_BUTTONS]; + StartButton *log_start_button[BUTTON_TOTAL_BUTTONS]; + int log_line_counter; + RDAirPlayConf::TimeMode log_time_mode; + EditEvent *log_event_edit; + bool log_pause_enabled; +}; + + +#endif // BUTTON_LOG_H diff --git a/rdairplay/colors.h b/rdairplay/colors.h new file mode 100644 index 00000000..e11f8bef --- /dev/null +++ b/rdairplay/colors.h @@ -0,0 +1,99 @@ +// colors.h +// +// The color definitions for RDAirPlay. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: colors.h,v 1.37.4.2 2013/07/05 21:07:28 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef COLORS_H +#define COLORS_H + +// +// Mode Titles +// +#define STOP_MODE_TITLE QObject::tr("START") +#define PLAY0_MODE_TITLE QObject::tr("STOP") +#define PLAY1_MODE_TITLE QObject::tr("PAUSE") +#define PAUSE_MODE_TITLE QObject::tr("RESUME") +#define ADD_TO_MODE_TITLE QObject::tr("WHERE?") +#define DELETE_FROM_MODE_TITLE QObject::tr("DELETE?") +#define MOVE_FROM_MODE_TITLE QObject::tr("MOVE?") +#define MOVE_TO_MODE_TITLE QObject::tr("TO?") +#define COPY_FROM_MODE_TITLE QObject::tr("COPY?") +#define COPY_TO_MODE_TITLE QObject::tr("TO?") +#define DISABLED_MODE_TITLE "" +#define ERROR_MODE_TITLE QObject::tr("ERROR") + +// +// Wall Clock +// +#define BUTTON_TIME_SYNC_LOST_COLOR red + +// +// Mode Button +// +#define BUTTON_MODE_LIVE_ASSIST_COLOR yellow +#define BUTTON_MODE_AUTO_COLOR green +#define BUTTON_MODE_MANUAL_COLOR red + +// +// Log Selector Buttons +// +#define BUTTON_LOG_ACTIVE_TEXT_COLOR white +#define BUTTON_LOG_ACTIVE_BACKGROUND_COLOR blue + +// +// Full Log Colors +// +#define LOG_NEXT_COLOR "#CCFFCC" +#define LOG_EVERGREEN_COLOR "#008000" + +// +// Pie Counter Color +// +#define PIE_COUNTER_COLOR darkGreen +#define PIE_TALK_COLOR blue +#define PIE_FINAL_COLOR black +#define PIE_FINAL_BG_COLOR white +#define PIE_ONAIR_COLOR red + +// +// Widget Colors +// +#define AIR_FLASH_COLOR blue +#define AIR_ERROR_COLOR red + +// +// LogLineBox Colors +// +#define LOGLINEBOX_BACKGROUND_COLOR white +#define LOGLINEBOX_MISSING_COLOR red +#define LOGLINEBOX_MARKER_COLOR cyan +#define LOGLINEBOX_CHAIN_COLOR magenta +#define LOGLINEBOX_EVERGREEN_COLOR "#008000" +#define LOGLINEBOX_TIMESCALE_COLOR green + +// +// Post Point Widget +// +#define POSTPOINT_EARLY_COLOR yellow +#define POSTPOINT_ONTIME_COLOR green +#define POSTPOINT_LATE_COLOR red + +#endif // COLORS_H diff --git a/rdairplay/edit_event.cpp b/rdairplay/edit_event.cpp new file mode 100644 index 00000000..3ac3dc7d --- /dev/null +++ b/rdairplay/edit_event.cpp @@ -0,0 +1,508 @@ +// edit_event.cpp +// +// Event Editor for RDAirPlay +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_event.cpp,v 1.48.8.3.2.3 2014/05/20 18:46:17 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include + +#include +#include + + +EditEvent::EditEvent(LogPlay *log,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_log=log; + edit_height=385; + setCaption(tr("Edit Event")); + + // + // Create Fonts + // + QFont radio_font=QFont("Helvetica",10,QFont::Normal); + radio_font.setPixelSize(10); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont notes_font=QFont("Helvetica",16,QFont::Normal); + notes_font.setPixelSize(16); + QFont counter_font=QFont("Helvetica",20,QFont::Bold); + counter_font.setPixelSize(20); + + // + // Time Type + // + edit_timetype_box=new QCheckBox(this); + edit_timetype_label=new QLabel(edit_timetype_box,tr("Start at:"),this); + edit_timetype_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Start Time + // + edit_time_edit=new RDTimeEdit(this); + edit_time_edit->setDisplay(RDTimeEdit::Hours|RDTimeEdit::Minutes| + RDTimeEdit::Seconds|RDTimeEdit::Tenths); + connect(edit_time_edit,SIGNAL(valueChanged(const QTime &)), + this,SLOT(timeChangedData(const QTime &))); + + // + // Grace Time + // + edit_grace_group + =new QButtonGroup(1,Qt::Vertical, + tr("Action If Previous Event Still Playing"),this); + edit_grace_group->setFont(label_font); + edit_grace_group->setRadioButtonExclusive(true); + QRadioButton *radio_button= + new QRadioButton(tr("Start Immediately"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + radio_button=new QRadioButton(tr("Make Next"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + radio_button=new QRadioButton(tr("Wait up to"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + edit_grace_edit=new RDTimeEdit(this); + edit_grace_edit->setDisplay(RDTimeEdit::Minutes|RDTimeEdit::Seconds| + RDTimeEdit::Tenths); + connect(edit_timetype_box,SIGNAL(toggled(bool)), + this,SLOT(timeToggledData(bool))); + connect(edit_grace_group,SIGNAL(clicked(int)), + this,SLOT(graceClickedData(int))); + + // + // Transition Type + // + edit_transtype_box=new QComboBox(this); + edit_timetype_label->setFont(label_font); + edit_transtype_box->insertItem(tr("Play")); + edit_transtype_box->insertItem(tr("Segue")); + edit_transtype_box->insertItem(tr("Stop")); + edit_time_label= + new QLabel(edit_transtype_box,tr("Start Transition Type:"),this); + edit_time_label->setFont(label_font); + edit_time_label->setAlignment(AlignRight|AlignVCenter); + + // Overlap Box + edit_overlap_box=new QCheckBox(this); + edit_overlap_label= + new QLabel(edit_overlap_box,tr("No Fade at Segue Out"),this); + edit_overlap_label->setFont(button_font); + edit_overlap_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + + // + // Horizontal Rule + // + edit_horizrule_label=new QLabel(this); + QPixmap *pix=new QPixmap(sizeHint().width(),3); + QPainter *p=new QPainter(pix); + p->setPen(QColor(black)); + p->setBrush(QColor(black)); + p->fillRect(0,0,sizeHint().width(),3,backgroundColor()); + p->moveTo(10,1); + p->lineTo(sizeHint().width()-10,1); + p->end(); + edit_horizrule_label->setPixmap(*pix); + delete p; + delete pix; + + // + // Cue Editor + // + edit_cue_edit= + new RDCueEdit(rdcae,rdairplay_conf->card(RDAirPlayConf::CueChannel), + rdairplay_conf->port(RDAirPlayConf::CueChannel),this); + + // + // Cart Notes + // + edit_cart_notes_label=new QLabel(tr("Cart Notes"),this); + edit_cart_notes_label->setFont(label_font); + edit_cart_notes_text=new QTextEdit(this); + edit_cart_notes_text->setFont(notes_font); + edit_cart_notes_text->setReadOnly(true); + + // + // Ok Button + // + edit_ok_button=new QPushButton(this); + edit_ok_button->setDefault(true); + edit_ok_button->setFont(button_font); + edit_ok_button->setText(tr("&OK")); + connect(edit_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + edit_cancel_button=new QPushButton(this); + edit_cancel_button->setFont(button_font); + edit_cancel_button->setText(tr("&Cancel")); + connect(edit_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +EditEvent::~EditEvent() +{ +} + + +QSize EditEvent::sizeHint() const +{ + return QSize(625,edit_height); +} + + +QSizePolicy EditEvent::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int EditEvent::exec(int line) +{ + edit_line=line; + edit_time_changed=false; + if((edit_logline=edit_log->logLine(line))==NULL) { + return -1; + } + switch(edit_logline->timeType()) { + case ::RDLogLine::Hard: + edit_timetype_box->setChecked(true); + timeToggledData(true); + break; + + default: + edit_timetype_box->setChecked(false); + timeToggledData(false); + break; + } + timeChangedData(edit_time_edit->time()); + switch(edit_logline->graceTime()) { + case -1: + edit_grace_group->setButton(1); + graceClickedData(1); + break; + + case 0: + edit_grace_group->setButton(0); + graceClickedData(0); + break; + + default: + edit_grace_group->setButton(2); + graceClickedData(2); + edit_grace_edit->setTime(QTime().addMSecs(edit_logline->graceTime())); + break; + } + edit_transtype_box->setCurrentItem((int)edit_logline->transType()); + if(edit_logline->segueStartPoint(RDLogLine::LogPointer)<0 + && edit_logline->segueEndPoint(RDLogLine::LogPointer)<0 + && edit_logline->endPoint(RDLogLine::LogPointer)<0 + && edit_logline->fadedownPoint(RDLogLine::LogPointer)<0) { + edit_overlap_box->setEnabled(true); + edit_overlap_label->setEnabled(true); + if(edit_logline->segueGain()==0) { + edit_overlap_box->setChecked(true); + } + else { + edit_overlap_box->setChecked(false); + } + } + else { + edit_overlap_box->setEnabled(false); + edit_overlap_label->setEnabled(false); + edit_overlap_box->setChecked(false); + } + if(!edit_logline->startTime(RDLogLine::Logged).isNull()) { + edit_time_edit->setTime(edit_logline->startTime(RDLogLine::Logged)); + } + else { + edit_time_edit->setTime(QTime()); + } + setCaption(QString().sprintf("%d - %s", + edit_logline->cartNumber(), + (const char *)edit_logline->title())); + edit_cart_notes_text->setText(edit_logline->cartNotes()); + switch(edit_logline->type()) { + case RDLogLine::Cart: + if((edit_logline->cutNumber()<1)|| + (edit_logline->forcedLength()<=0)) { + edit_cue_edit->hide(); + if(edit_logline->cartNotes().isEmpty()) { + edit_height=170; + edit_cart_notes_label->hide(); + edit_cart_notes_text->hide(); + } + else { + edit_height=350; + edit_cart_notes_label->show(); + edit_cart_notes_text->show(); + } + } + else { + edit_cue_edit->initialize(edit_logline); + edit_cue_edit->show(); + if(edit_logline->cartNotes().isEmpty()) { + edit_height=335; + edit_cart_notes_label->hide(); + edit_cart_notes_text->hide(); + } + else { + edit_height=515; + edit_cart_notes_label->show(); + edit_cart_notes_text->show(); + } + } + break; + + case RDLogLine::Macro: + edit_cue_edit->hide(); + if(edit_logline->cartNotes().isEmpty()) { + edit_height=170; + edit_cart_notes_label->hide(); + edit_cart_notes_text->hide(); + } + else { + edit_height=300; + edit_cart_notes_label->show(); + edit_cart_notes_text->show(); + } + break; + + case RDLogLine::Marker: + setCaption(tr("Edit Marker")); + edit_cue_edit->hide(); + edit_cart_notes_label->hide(); + edit_cart_notes_text->hide(); + edit_height=170; + break; + + case RDLogLine::Track: + setCaption(tr("Edit Track")); + edit_cue_edit->hide(); + edit_cart_notes_label->hide(); + edit_cart_notes_text->hide(); + edit_height=170; + break; + + case RDLogLine::Chain: + setCaption(tr("Edit Log Track")); + edit_cue_edit->hide(); + edit_cart_notes_label->hide(); + edit_cart_notes_text->hide(); + edit_height=170; + break; + + default: + edit_cue_edit->hide(); + edit_height=170; + break; + } + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + edit_ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60, + 80,50); + edit_cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + resize(sizeHint()); + + return QDialog::exec(); +} + + +void EditEvent::timeChangedData(const QTime &time) +{ + QString str; + + if(edit_timetype_box->isChecked()) { + str=QString(tr("Transition If Previous Cart Ends Before")); + edit_time_label-> + setText(QString().sprintf("%s %s:",(const char *)str, + (const char *)edit_time_edit->time(). + toString("hh:mm:ss.zzz").left(10))); + } +} + + +void EditEvent::timeToggledData(bool state) +{ + QString str; + + edit_time_edit->setEnabled(state); + edit_grace_group->setEnabled(state); + if(state) { + graceClickedData(edit_grace_group->selectedId()); + str=QString(tr("Transition If Previous Cart Ends Before")); + edit_time_label-> + setText(QString().sprintf("%s %s:",(const char *)str, + (const char *)edit_time_edit->time(). + toString("hh:mm:ss.zzz").left(10))); + } + else { + edit_grace_edit->setDisabled(true); + edit_time_label->setText(tr("Start Transition Type:")); + } +} + + +void EditEvent::graceClickedData(int id) +{ + switch(id) { + case 0: + edit_grace_edit->setDisabled(true); + break; + + case 1: + edit_grace_edit->setDisabled(true); + break; + + case 2: + edit_grace_edit->setEnabled(true); + break; + } +} + + +void EditEvent::okData() +{ + if(edit_timetype_box->isChecked()&& + edit_log->exists(edit_time_edit->time(),edit_line)) { + QMessageBox::warning(this,tr("Duplicate Start Time"), + tr("An event is already scheduled with this start time!")); + return; + } + edit_cue_edit->stop(); + if((edit_logline->status()==RDLogLine::Scheduled)|| + (edit_logline->status()==RDLogLine::Paused)) { + if(edit_timetype_box->isChecked()) { + edit_logline->setTimeType(RDLogLine::Hard); + switch(edit_grace_group->selectedId()) { + case 0: + edit_logline->setGraceTime(0); + break; + + case 1: + edit_logline->setGraceTime(-1); + break; + + case 2: + edit_logline-> + setGraceTime(QTime().msecsTo(edit_grace_edit->time())); + break; + } + } + else { + edit_logline->setTimeType(RDLogLine::Relative); + edit_logline->setStartTime(RDLogLine::Logged,edit_logline-> + startTime(RDLogLine::Imported)); + } + edit_logline-> + setTransType((RDLogLine::TransType)edit_transtype_box->currentItem()); + if(edit_logline->segueStartPoint(RDLogLine::LogPointer)<0 + && edit_logline->segueEndPoint(RDLogLine::LogPointer)<0 + && edit_logline->endPoint(RDLogLine::LogPointer)<0 + && edit_logline->fadedownPoint(RDLogLine::LogPointer)<0) { + if(edit_overlap_box->isChecked()) { + edit_logline->setSegueGain(0); + } + else { + edit_logline->setSegueGain(RD_FADE_DEPTH); + } + } + if(edit_time_changed|| + (edit_logline->timeType()!=RDLogLine::Relative)) { + edit_logline-> + setStartTime(RDLogLine::Logged,edit_time_edit->time()); + } + if(edit_cue_edit->playPosition(RDMarkerBar::Start)!= + edit_logline->playPosition()) { + edit_logline-> + setPlayPosition(edit_cue_edit->playPosition(RDMarkerBar::Start)); + edit_logline->setPlayPositionChanged(true); + } + if(edit_cue_edit->playPosition(RDMarkerBar::End)!= + (unsigned)edit_logline->endPoint()) { + edit_logline->setEndPoint(edit_cue_edit->playPosition(RDMarkerBar::End), + RDLogLine::LogPointer); + edit_logline->setPlayPositionChanged(true); + } + edit_log->lineModified(edit_line); + } + + done(0); +} + + +void EditEvent::cancelData() +{ + edit_cue_edit->stop(); + + done(1); +} + + +void EditEvent::resizeEvent(QResizeEvent *e) +{ + edit_time_edit->setGeometry(85,19,85,20); + edit_grace_group->setGeometry(175,11,435,50); + edit_grace_edit->setGeometry(538,31,65,20); + edit_transtype_box->setGeometry(485,68,110,26); + edit_timetype_box->setGeometry(10,22,15,15); + edit_time_label->setGeometry(190,68,290,26); + edit_timetype_label->setGeometry(30,21,85,17); + edit_overlap_box->setGeometry(30,72,15,15); + edit_overlap_label->setGeometry(50,68,130,26); + edit_horizrule_label->setGeometry(0,100,size().width(),3); + edit_cue_edit->setGeometry(20,110,edit_cue_edit->sizeHint().width(), + edit_cue_edit->sizeHint().height()); + if(edit_cue_edit->isShown()) { + edit_cart_notes_label-> + setGeometry(15,105+edit_cue_edit->sizeHint().height(), + size().width()-20,20); + edit_cart_notes_text->setGeometry(10,125+edit_cue_edit->sizeHint().height(), + size().width()-20,100); + } + else { + edit_cart_notes_label->setGeometry(15,105,size().width()-20,20); + edit_cart_notes_text->setGeometry(10,125,size().width()-20,100); + } + edit_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + edit_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void EditEvent::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/rdairplay/edit_event.h b/rdairplay/edit_event.h new file mode 100644 index 00000000..2660eb19 --- /dev/null +++ b/rdairplay/edit_event.h @@ -0,0 +1,97 @@ +// edit_event.h +// +// Event Editor for RDAirPlay +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_event.h,v 1.25.8.2.2.1 2014/05/20 01:45:17 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_EVENT_H +#define EDIT_EVENT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +class EditEvent : public QDialog +{ + Q_OBJECT + public: + EditEvent(LogPlay *log,QWidget *parent=0,const char *name=0); + ~EditEvent(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(int line); + + private slots: + void timeChangedData(const QTime &); + void timeToggledData(bool state); + void graceClickedData(int id); + void okData(); + void cancelData(); + + protected: + void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e); + + private: + LogPlay *edit_log; + RDLogLine *edit_logline; + int edit_line; + RDTimeEdit *edit_time_edit; + bool edit_time_changed; + QCheckBox *edit_timetype_box; + QLabel *edit_timetype_label; + QButtonGroup *edit_grace_group; + RDTimeEdit *edit_grace_edit; + QLabel *edit_time_label; + QComboBox *edit_transtype_box; + QLabel *edit_transtype_label; + QCheckBox *edit_overlap_box; + QLabel *edit_overlap_label; + RDCueEdit *edit_cue_edit; + QFont normal_font; + QLabel *edit_cart_notes_label; + QTextEdit *edit_cart_notes_text; + QPushButton *edit_ok_button; + QPushButton *edit_cancel_button; + QLabel *edit_horizrule_label; + int edit_height; +}; + + +#endif // EDIT_EVENT_H diff --git a/rdairplay/globals.h b/rdairplay/globals.h new file mode 100644 index 00000000..8ffdfcd8 --- /dev/null +++ b/rdairplay/globals.h @@ -0,0 +1,54 @@ + +// globals.h +// +// Global Variable Declarations for RDAirPlay +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: globals.h,v 1.12.14.1 2012/11/26 20:19:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef GLOBALS_H +#define GLOBALS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Global Resources +// +extern RDStation *rdstation_conf; +extern RDSystem *rdsystem_conf; +extern RDAirPlayConf *rdairplay_conf; +extern RDAudioPort *rdaudioport_conf; +extern RDUser *rduser; +extern RDRipc *rdripc; +extern RDCae *rdcae; +extern RDEventPlayer *rdevent_player; +extern RDCartDialog *rdcart_dialog; +extern void LogLine(RDConfig::LogPriority prio,const QString &line); +extern QString logfile; +extern RDConfig *air_config; + +#endif // GLOBALS_H diff --git a/rdairplay/hourselector.cpp b/rdairplay/hourselector.cpp new file mode 100644 index 00000000..c733e9b3 --- /dev/null +++ b/rdairplay/hourselector.cpp @@ -0,0 +1,143 @@ +// hourselector.cpp +// +// Hour Selector widget for RDAirPlay +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: hourselector.cpp,v 1.1.2.1 2012/11/13 23:45:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +HourSelector::HourSelector(QWidget *parent,const char *name) + : QWidget(parent,name) +{ + // + // Fonts + // + QFont font("helvetica",16,QFont::Bold); + font.setPixelSize(16); + + // + // Palettes + // + hour_active_palette= + QPalette(QColor(BUTTON_STOPPED_BACKGROUND_COLOR),backgroundColor()); + + // + // Buttons + // + QSignalMapper *mapper=new QSignalMapper(this); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(hourClicked(int))); + for(unsigned i=0;i<24;i++) { + hour_button[i]=new QPushButton(this); + hour_button[i]->setFont(font); + hour_button[i]->setDisabled(true); + mapper->setMapping(hour_button[i],i); + connect(hour_button[i],SIGNAL(clicked()),mapper,SLOT(map())); + } + + // + // Update Timer + // + hour_update_timer=new QTimer(this); + connect(hour_update_timer,SIGNAL(timeout()),this,SLOT(updateTimeData())); + updateTimeData(); +} + + +QSizePolicy HourSelector::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void HourSelector::setTimeMode(RDAirPlayConf::TimeMode mode) +{ + switch(mode) { + case RDAirPlayConf::TwelveHour: + hour_button[0]->setText(tr("12a")); + hour_button[1]->setText(tr("1a")); + hour_button[2]->setText(tr("2a")); + hour_button[3]->setText(tr("3a")); + hour_button[4]->setText(tr("4a")); + hour_button[5]->setText(tr("5a")); + hour_button[6]->setText(tr("6a")); + hour_button[7]->setText(tr("7a")); + hour_button[8]->setText(tr("8a")); + hour_button[9]->setText(tr("9a")); + hour_button[10]->setText(tr("10a")); + hour_button[11]->setText(tr("11a")); + hour_button[12]->setText(tr("12p")); + hour_button[13]->setText(tr("1p")); + hour_button[14]->setText(tr("2p")); + hour_button[15]->setText(tr("3p")); + hour_button[16]->setText(tr("4p")); + hour_button[17]->setText(tr("5p")); + hour_button[18]->setText(tr("6p")); + hour_button[19]->setText(tr("7p")); + hour_button[20]->setText(tr("8p")); + hour_button[21]->setText(tr("9p")); + hour_button[22]->setText(tr("10p")); + hour_button[23]->setText(tr("11p")); + break; + + case RDAirPlayConf::TwentyFourHour: + for(unsigned i=0;i<24;i++) { + hour_button[i]->setText(QString().sprintf("%02u",i)); + } + break; + } +} + + +void HourSelector::updateHours(bool states[24]) +{ + for(unsigned i=0;i<24;i++) { + hour_button[i]->setEnabled(states[i]); + } +} + + +void HourSelector::resizeEvent(QResizeEvent *e) +{ + for(unsigned i=0;i<2;i++) { + for(unsigned j=0;j<12;j++) { + unsigned hour=12*i+j; + hour_button[hour]->setGeometry(j*size().width()/12,i*size().height()/2, + size().width()/12,size().height()/2); + } + } +} + + +void HourSelector::hourClicked(int hour) +{ + emit hourSelected(hour); +} + + +void HourSelector::updateTimeData() +{ + QTime now=QTime::currentTime(); + for(unsigned i=0;i<24;i++) { + hour_button[i]->setPalette(palette()); + } + hour_button[now.hour()]->setPalette(hour_active_palette); + hour_update_timer->start(now.msecsTo(QTime(now.hour()+1,0,1)),true); +} diff --git a/rdairplay/hourselector.h b/rdairplay/hourselector.h new file mode 100644 index 00000000..338facf6 --- /dev/null +++ b/rdairplay/hourselector.h @@ -0,0 +1,62 @@ +// hourselector.h +// +// Hour Selector widget for RDAirPlay +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: hourselector.h,v 1.1.2.1 2012/11/13 23:45:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef HOURSELECTOR_H +#define HOURSELECTOR_H + +#include +#include +#include + +#include +#include +#include + +#include + +class HourSelector : public QWidget +{ + Q_OBJECT + public: + HourSelector(QWidget *parent=0,const char *name=0); + QSizePolicy sizePolicy() const; + void setTimeMode(RDAirPlayConf::TimeMode mode); + void updateHours(bool states[24]); + + signals: + void hourSelected(int hour); + + protected: + void resizeEvent(QResizeEvent *e); + + private slots: + void hourClicked(int hour); + void updateTimeData(); + + private: + QPushButton *hour_button[24]; + QPalette hour_active_palette; + QTimer *hour_update_timer; +}; + + +#endif // HOURSELECTOR_H diff --git a/rdairplay/lib_listview.cpp b/rdairplay/lib_listview.cpp new file mode 100644 index 00000000..3d85b55b --- /dev/null +++ b/rdairplay/lib_listview.cpp @@ -0,0 +1,55 @@ +// lib_listview.cpp +// +// The Log ListView widget for RDAirPlay's Full Log widget. +// +// (C) Copyright 2002-2013 Fred Gleason +// +// $Id: lib_listview.cpp,v 1.1.2.2 2014/02/20 00:43:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include + +LibListView::LibListView(QWidget *parent,const char *name) + : RDListView(parent,name) +{ + setAcceptDrops(true); +} + + +void LibListView::dragEnterEvent(QDragEnterEvent *e) +{ + e->accept(RDCartDrag::canDecode(e)); +} + + +void LibListView::dropEvent(QDropEvent *e) +{ + RDLogLine ll; + int line=-1; + QPoint pos(e->pos().x(),e->pos().y()-header()->sectionRect(0).height()); + + if(RDCartDrag::decode(e,&ll)) { + RDListViewItem *item=(RDListViewItem *)itemAt(pos); + if(item!=NULL) { + line=item->text(15).toInt(); + } + emit cartDropped(line,&ll); + } +} diff --git a/rdairplay/lib_listview.h b/rdairplay/lib_listview.h new file mode 100644 index 00000000..62ba85b5 --- /dev/null +++ b/rdairplay/lib_listview.h @@ -0,0 +1,44 @@ +// lib_listview.h +// +// The Log ListView widget for RDAirPlay's Full Log widget. +// +// (C) Copyright 2002-2013 Fred Gleason +// +// $Id: lib_listview.h,v 1.1.2.1 2013/12/28 00:00:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIB_LISTVIEW_H +#define LIB_LISTVIEW_H + +#include +#include + +class LibListView : public RDListView +{ + Q_OBJECT + public: + LibListView(QWidget *parent,const char *name=0); + + signals: + void cartDropped(int line,RDLogLine *ll); + + protected: + void dragEnterEvent(QDragEnterEvent *e); + void dropEvent(QDropEvent *e); +}; + + +#endif // LIB_LISTVIEW_H diff --git a/rdairplay/list_log.cpp b/rdairplay/list_log.cpp new file mode 100644 index 00000000..56670675 --- /dev/null +++ b/rdairplay/list_log.cpp @@ -0,0 +1,1595 @@ +// list_log.cpp +// +// The full log list for RDAirPlay +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: list_log.cpp,v 1.105.6.11.2.1 2014/05/21 18:19:42 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" +#include "../icons/chain.xpm" +#include "../icons/track_cart.xpm" +#include "../icons/mic16.xpm" +#include "../icons/notemarker.xpm" +#include "../icons/traffic.xpm" +#include "../icons/music.xpm" + + +ListLog::ListLog(LogPlay *log,int id,bool allow_pause, + QWidget *parent,const char *name) + : QWidget(parent,name) +{ + list_id=id; + list_log=log; + list_op_mode=RDAirPlayConf::LiveAssist; + list_action_mode=RDAirPlayConf::Normal; + list_time_mode=RDAirPlayConf::TwentyFourHour; + list_scroll=true; + list_pause_allowed=allow_pause; + list_playbutton_mode=ListLog::ButtonDisabled; + list_audition_head_playing=false; + list_audition_tail_playing=false; + + // + // Create Fonts + // + QFont list_font=QFont("Helvetica",12,QFont::Normal); + list_font.setPixelSize(12); + setFont(list_font); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont font=QFont("Helvetica",14,QFont::Bold); + font.setPixelSize(14); + QFont name_font=QFont("Helvetica",18,QFont::Bold); + name_font.setPixelSize(18); + + // + // Create Icons + // + list_playout_map=new QPixmap(play_xpm); + list_macro_map=new QPixmap(rml5_xpm); + list_chain_map=new QPixmap(chain_xpm); + list_track_cart_map=new QPixmap(track_cart_xpm); + list_mic16_map=new QPixmap(mic16_xpm); + list_notemarker_map=new QPixmap(notemarker_xpm); + list_traffic_map=new QPixmap(traffic_xpm); + list_music_map=new QPixmap(music_xpm); + + // + // Create Palettes + // + list_from_color= + QPalette(QColor(BUTTON_FROM_BACKGROUND_COLOR),QColor(lightGray)); + list_from_color. + setColor(QColorGroup::ButtonText,QColor(BUTTON_FROM_TEXT_COLOR)); + + list_to_color= + QPalette(QColor(BUTTON_TO_BACKGROUND_COLOR),QColor(lightGray)); + list_to_color. + setColor(QColorGroup::ButtonText,QColor(BUTTON_TO_TEXT_COLOR)); + list_list_to_color=palette(); + list_list_to_color.setColor(QPalette::Active,QColorGroup::Highlight, + BUTTON_TO_BACKGROUND_COLOR); + list_list_to_color.setColor(QPalette::Active,QColorGroup::HighlightedText, + BUTTON_TO_TEXT_COLOR); + list_list_to_color.setColor(QPalette::Inactive,QColorGroup::Highlight, + BUTTON_TO_BACKGROUND_COLOR); + list_list_to_color.setColor(QPalette::Inactive,QColorGroup::HighlightedText, + BUTTON_TO_TEXT_COLOR); + list_list_from_color=palette(); + list_list_from_color.setColor(QPalette::Active,QColorGroup::Highlight, + BUTTON_FROM_BACKGROUND_COLOR); + list_list_from_color.setColor(QPalette::Active,QColorGroup::HighlightedText, + BUTTON_FROM_TEXT_COLOR); + list_list_from_color.setColor(QPalette::Inactive,QColorGroup::Highlight, + BUTTON_FROM_BACKGROUND_COLOR); + list_list_from_color. + setColor(QPalette::Inactive,QColorGroup::HighlightedText, + BUTTON_FROM_TEXT_COLOR); + list_scroll_color[0]=palette(); + list_scroll_color[0].setColor(QPalette::Active,QColorGroup::ButtonText, + BUTTON_LOG_ACTIVE_TEXT_COLOR); + list_scroll_color[0].setColor(QPalette::Active,QColorGroup::Button, + BUTTON_LOG_ACTIVE_BACKGROUND_COLOR); + list_scroll_color[0].setColor(QPalette::Active,QColorGroup::Background, + lightGray); + list_scroll_color[0].setColor(QPalette::Inactive,QColorGroup::ButtonText, + BUTTON_LOG_ACTIVE_TEXT_COLOR); + list_scroll_color[0].setColor(QPalette::Inactive,QColorGroup::Button, + BUTTON_LOG_ACTIVE_BACKGROUND_COLOR); + list_scroll_color[0].setColor(QPalette::Inactive,QColorGroup::Background, + lightGray); + list_scroll_color[1]=QPalette(backgroundColor(),lightGray); + + // + // Hour Selector + // + list_hour_selector=new HourSelector(this); + list_hour_selector->setTimeMode(list_time_mode); + connect(list_hour_selector,SIGNAL(hourSelected(int)), + this,SLOT(selectHour(int))); + list_hour_selector->hide(); + + // + // Log List + // + list_log_list=new LibListView(this,"list_log_list"); + list_log_list->setFont(list_font); + int y=0; + int h=sizeHint().height()-60; + if(rdairplay_conf->showCounters()) { + h-=60; + } + if(rdairplay_conf->hourSelectorEnabled()) { + y+=80; + h-=80; + list_hour_selector->setGeometry(0,0,sizeHint().width(),80); + list_hour_selector->show(); + } + list_log_list->setGeometry(0,y,sizeHint().width(),h); + list_log_list->setAllColumnsShowFocus(true); + list_log_list->setSelectionMode(QListView::Extended); + list_log_list->setItemMargin(5); + list_log_list->addColumn(""); + list_log_list->setColumnAlignment(0,Qt::AlignHCenter); + list_log_list->addColumn(tr("EST TIME")); + list_log_list->setColumnAlignment(1,Qt::AlignRight); + list_log_list->addColumn(tr("LEN")); + list_log_list->setColumnAlignment(2,Qt::AlignRight); + list_log_list->addColumn(tr("TRANS")); + list_log_list->setColumnAlignment(3,Qt::AlignHCenter); + list_log_list->addColumn(tr("CART")); + list_log_list->setColumnAlignment(4,Qt::AlignHCenter); + list_log_list->addColumn(tr("TITLE")); + list_log_list->setColumnAlignment(5,Qt::AlignLeft); + list_log_list->addColumn(tr("ARTIST")); + list_log_list->setColumnAlignment(6,Qt::AlignLeft); + list_log_list->addColumn(tr("GROUP")); + list_log_list->setColumnAlignment(7,Qt::AlignHCenter); + list_log_list->addColumn(tr("TIME")); + list_log_list->setColumnAlignment(8,Qt::AlignHCenter); + list_log_list->addColumn(tr("ALBUM")); + list_log_list->setColumnAlignment(9,Qt::AlignLeft); + list_log_list->addColumn(tr("LABEL")); + list_log_list->setColumnAlignment(10,Qt::AlignLeft); + list_log_list->addColumn(tr("CLIENT")); + list_log_list->setColumnAlignment(11,Qt::AlignLeft); + list_log_list->addColumn(tr("AGENCY")); + list_log_list->setColumnAlignment(12,Qt::AlignLeft); + list_log_list->addColumn(tr("MARKER")); + list_log_list->setColumnAlignment(13,Qt::AlignHCenter); + list_log_list->addColumn(tr("LINE ID")); + list_log_list->setColumnAlignment(14,Qt::AlignHCenter); + list_log_list->addColumn(tr("COUNT")); + list_log_list->setColumnAlignment(15,Qt::AlignHCenter); + list_log_list->addColumn(tr("STATUS")); + list_log_list->setColumnAlignment(16,Qt::AlignHCenter); + list_log_list->setHardSortColumn(15); + list_log_list->setFocusPolicy(QWidget::NoFocus); + connect(list_log_list,SIGNAL(selectionChanged()), + this,SLOT(selectionChangedData())); + connect(list_log_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleclickedData(QListViewItem *,const QPoint &,int))); + connect(list_log_list,SIGNAL(cartDropped(int,RDLogLine *)), + this,SLOT(cartDroppedData(int,RDLogLine *))); + + // + // List Logs Dialog + // + list_logs_dialog=new ListLogs(list_log,this,"list_logs"); + + // + // Time Counter Section + // + QLabel *label=new QLabel(tr("Run Length"),this); + label->setGeometry(372,sizeHint().height()-120,75,20); + label->setFont(label_font); + label->setAlignment(AlignCenter); + label->setBackgroundColor(QColor(lightGray)); + if(!rdairplay_conf->showCounters()) { + label->hide(); + } + + // + // Stop Time Counter + // + list_stoptime_edit=new QLineEdit(this,"list_stoptime_edit"); + list_stoptime_edit->setGeometry(407,sizeHint().height()-100,70,18); + list_stoptime_label=new QLabel(list_stoptime_edit,tr("Next Stop:"),this); + list_stoptime_label->setGeometry(337,sizeHint().height()-100,65,18); + list_stoptime_label->setFont(label_font); + list_stoptime_label->setAlignment(AlignRight|AlignVCenter); + list_stoptime_label->setBackgroundColor(QColor(lightGray)); + if(!rdairplay_conf->showCounters()) { + list_stoptime_edit->hide(); + list_stoptime_label->hide(); + } + + // + // End Time Counter + // + list_endtime_edit=new QLineEdit(this,"list_endtime_edit"); + list_endtime_edit->setGeometry(407,sizeHint().height()-80,70,18); + label=new QLabel(list_endtime_edit,tr("Log End:"),this); + label->setGeometry(337,sizeHint().height()-80,65,18); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter); + label->setBackgroundColor(QColor(lightGray)); + if(!rdairplay_conf->showCounters()) { + list_endtime_edit->hide(); + label->hide(); + } + + // + // Select Button + // + list_take_button=new QPushButton(this,"list_take_button"); + list_take_button->setGeometry(10,sizeHint().height()-55,80,50); + list_take_button->setFont(font); + list_take_button->setPalette(QPalette(backgroundColor(),QColor(lightGray))); + list_take_button->setText(tr("Select")); + list_take_button->setFocusPolicy(QWidget::NoFocus); + connect(list_take_button,SIGNAL(clicked()),this,SLOT(takeButtonData())); + list_take_button->hide(); + + // + // Audition Head Button + // + list_head_button=new QPushButton(this,"list_head_button"); + list_head_button->setGeometry(10,sizeHint().height()-113,80,50); + list_head_button->setFont(font); + list_head_button->setPalette(QPalette(backgroundColor(),QColor(lightGray))); + list_head_button->setText(tr("Audition\nHead")); + list_head_button->setFocusPolicy(QWidget::NoFocus); + connect(list_head_button,SIGNAL(clicked()),this,SLOT(headButtonData())); + if(!rdairplay_conf->showCounters()) { + list_head_button->hide(); + } + + // + // Audition Tail Button + // + list_tail_button=new QPushButton(this,"list_tail_button"); + list_tail_button->setGeometry(90,sizeHint().height()-113,80,50); + list_tail_button->setFont(font); + list_tail_button->setPalette(QPalette(backgroundColor(),QColor(lightGray))); + list_tail_button->setText(tr("Audition\nTail")); + list_tail_button->setFocusPolicy(QWidget::NoFocus); + connect(list_tail_button,SIGNAL(clicked()),this,SLOT(tailButtonData())); + if(!rdairplay_conf->showCounters()) { + list_tail_button->hide(); + } + + // + // Play Button + // + list_play_button=new QPushButton(this,"list_play_button"); + list_play_button->setGeometry(10,sizeHint().height()-55,80,50); + list_play_button->setFont(font); + list_play_button->setPalette(QPalette(backgroundColor(),QColor(lightGray))); + list_play_button->setText(tr("Start")); + list_play_button->setDisabled(true); + list_play_button->setFocusPolicy(QWidget::NoFocus); + connect(list_play_button,SIGNAL(clicked()),this,SLOT(playButtonData())); + + // + // Next Button + // + list_next_button=new QPushButton(this,"list_next_button"); + list_next_button->setGeometry(90,sizeHint().height()-55,80,50); + list_next_button->setFont(font); + list_next_button->setPalette(QPalette(backgroundColor(), + QColor(lightGray))); + list_next_button->setText(tr("Make\nNext")); + list_next_button->setDisabled(true); + list_next_button->setFocusPolicy(QWidget::NoFocus); + connect(list_next_button,SIGNAL(clicked()),this,SLOT(nextButtonData())); + + // + // Modify Button + // + list_modify_button=new QPushButton(this,"list_modify_button"); + list_modify_button->setGeometry(170,sizeHint().height()-55,80,50); + list_modify_button->setFont(font); + list_modify_button->setPalette(QPalette(backgroundColor(), + QColor(lightGray))); + list_modify_button->setText(tr("Modify")); + list_modify_button->setDisabled(true); + list_modify_button->setFocusPolicy(QWidget::NoFocus); + connect(list_modify_button,SIGNAL(clicked()),this,SLOT(modifyButtonData())); + + // + // Scroll Button + // + list_scroll_button=new QPushButton(this,"list_scroll_button"); + list_scroll_button->setGeometry(250,sizeHint().height()-55,80,50); + list_scroll_button->setFont(font); + list_scroll_button->setPalette(QPalette(backgroundColor(), + QColor(lightGray))); + list_scroll_button->setText(tr("Scroll")); + list_scroll_button->setFocusPolicy(QWidget::NoFocus); + connect(list_scroll_button,SIGNAL(clicked()),this,SLOT(scrollButtonData())); + list_scroll_button->setPalette(list_scroll_color[0]); + + // + // Refresh Button + // + list_refresh_button=new QPushButton(this,"list_refresh_button"); + list_refresh_button->setGeometry(330,sizeHint().height()-55,80,50); + list_refresh_button->setFont(font); + list_refresh_button-> + setPalette(QPalette(backgroundColor(),QColor(lightGray))); + list_refresh_button->setText(tr("Refresh\nLog")); + list_refresh_button->setDisabled(true); + list_refresh_button->setFocusPolicy(QWidget::NoFocus); + connect(list_refresh_button,SIGNAL(clicked()), + this,SLOT(refreshButtonData())); + + // + // Log Load + // + list_load_button=new QPushButton(this,"list_load_button"); + list_load_button->setGeometry(sizeHint().width()-90,sizeHint().height()-55, + 80,50); + list_load_button->setFont(font); + list_load_button->setPalette(QPalette(backgroundColor(),QColor(lightGray))); + list_load_button->setText(tr("Select\nLog")); + list_load_button->setFocusPolicy(QWidget::NoFocus); + connect(list_load_button,SIGNAL(clicked()),this,SLOT(loadButtonData())); + + // + // Edit Event Dialog + // + list_event_edit=new EditEvent(list_log,this,"list_event_edit"); + + // + // Map Slots + // + connect(list_log,SIGNAL(reloaded()),this,SLOT(logReloadedData())); + connect(list_log,SIGNAL(played(int)),this,SLOT(logPlayedData(int))); + connect(list_log,SIGNAL(paused(int)),this,SLOT(logPausedData(int))); + connect(list_log,SIGNAL(stopped(int)),this,SLOT(logStoppedData(int))); + connect(list_log,SIGNAL(inserted(int)),this,SLOT(logInsertedData(int))); + connect(list_log,SIGNAL(removed(int,int,bool)), + this,SLOT(logRemovedData(int,int,bool))); + connect(list_log,SIGNAL(transportChanged()), + this,SLOT(transportChangedData())); + connect(list_log,SIGNAL(modified(int)),this,SLOT(modifiedData(int))); + connect(list_log,SIGNAL(refreshabilityChanged(bool)), + this,SLOT(refreshabilityChangedData(bool))); + connect(list_log,SIGNAL(auditionHeadPlayed(int)), + this,SLOT(auditionHeadData(int))); + connect(list_log,SIGNAL(auditionTailPlayed(int)), + this,SLOT(auditionTailData(int))); + connect(list_log,SIGNAL(auditionStopped(int)), + this,SLOT(auditionStoppedData(int))); + + setBackgroundColor(QColor(lightGray)); + + RefreshList(); + UpdateTimes(); +} + + +QSize ListLog::sizeHint() const +{ + return QSize(500,530); +} + + +QSizePolicy ListLog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListLog::refresh() +{ + RefreshList(); + UpdateTimes(); +} + + +void ListLog::refresh(int line) +{ + RefreshList(line); + UpdateTimes(); +} + + +void ListLog::setStatus(int line,RDLogLine::Status status) +{ + RDListViewItem *next=GetItem(line); + if(next==NULL) { + return; + } + next->setText(16,QString().sprintf("%d",status)); +} + + +void ListLog::setOpMode(RDAirPlayConf::OpMode mode) +{ + if(mode==list_op_mode) { + return; + } + list_op_mode=mode; + UpdateTimes(); +} + + +RDAirPlayConf::ActionMode ListLog::actionMode() const +{ + return list_action_mode; +} + + +void ListLog::setActionMode(RDAirPlayConf::ActionMode mode,int *cartnum) +{ + list_cart=cartnum; + + if(mode==list_action_mode) { + return; + } + switch(mode) { + case RDAirPlayConf::Normal: + list_log_list->setSelectionMode(QListView::Extended); + list_log_list->setPalette(palette()); + list_take_button->hide(); + list_play_button->show(); + list_next_button->show(); + list_modify_button->show(); + list_scroll_button->show(); + list_refresh_button->show(); + list_load_button->show(); + break; + + case RDAirPlayConf::AddTo: + list_log_list->setSelectionMode(QListView::Single); + list_log_list->setPalette(list_list_to_color); + list_take_button->setText(ADD_TO_MODE_TITLE); + list_take_button->setPalette(list_to_color); + list_take_button->show(); + list_play_button->hide(); + list_next_button->hide(); + list_modify_button->hide(); + list_scroll_button->hide(); + list_refresh_button->hide(); + list_load_button->hide(); + break; + + case RDAirPlayConf::DeleteFrom: + list_log_list->setSelectionMode(QListView::Single); + list_log_list->setPalette(list_list_from_color); + list_take_button->setText(DELETE_FROM_MODE_TITLE); + list_take_button->setPalette(list_from_color); + list_take_button->show(); + list_play_button->hide(); + list_next_button->hide(); + list_modify_button->hide(); + list_scroll_button->hide(); + list_refresh_button->hide(); + list_load_button->hide(); + break; + + case RDAirPlayConf::MoveFrom: + list_log_list->setSelectionMode(QListView::Single); + list_log_list->setPalette(list_list_from_color); + list_take_button->setText(MOVE_FROM_MODE_TITLE); + list_take_button->setPalette(list_from_color); + list_take_button->show(); + list_play_button->hide(); + list_next_button->hide(); + list_modify_button->hide(); + list_scroll_button->hide(); + list_refresh_button->hide(); + list_load_button->hide(); + break; + + case RDAirPlayConf::MoveTo: + list_log_list->setSelectionMode(QListView::Single); + list_log_list->setPalette(list_list_to_color); + list_take_button->setText(MOVE_TO_MODE_TITLE); + list_take_button->setPalette(list_to_color); + list_take_button->show(); + list_play_button->hide(); + list_next_button->hide(); + list_modify_button->hide(); + list_scroll_button->hide(); + list_refresh_button->hide(); + list_load_button->hide(); + break; + + case RDAirPlayConf::CopyFrom: + list_log_list->setSelectionMode(QListView::Single); + list_log_list->setPalette(list_list_from_color); + list_take_button->setText(COPY_FROM_MODE_TITLE); + list_take_button->setPalette(list_from_color); + list_take_button->show(); + list_play_button->hide(); + list_next_button->hide(); + list_modify_button->hide(); + list_scroll_button->hide(); + list_refresh_button->hide(); + list_load_button->hide(); + break; + + case RDAirPlayConf::CopyTo: + list_log_list->setSelectionMode(QListView::Single); + list_log_list->setPalette(list_list_to_color); + list_take_button->setText(COPY_TO_MODE_TITLE); + list_take_button->setPalette(list_to_color); + list_take_button->show(); + list_play_button->hide(); + list_next_button->hide(); + list_modify_button->hide(); + list_scroll_button->hide(); + list_refresh_button->hide(); + list_load_button->hide(); + break; + + default: + break; + } + if(mode==RDAirPlayConf::Normal) { + list_scroll=list_suspended_scroll; + } + else { + if(list_action_mode==RDAirPlayConf::Normal) { + list_suspended_scroll=list_scroll; + list_scroll=false; + } + } + list_action_mode=mode; +} + + +void ListLog::setTimeMode(RDAirPlayConf::TimeMode mode) +{ + if(mode==list_time_mode) { + return; + } + list_hour_selector->setTimeMode(mode); + list_time_mode=mode; + UpdateTimes(); + RefreshList(); +} + + +void ListLog::userChanged(bool add_allowed,bool delete_allowed, + bool arrange_allowed,bool playout_allowed) +{ + list_load_button->setEnabled(playout_allowed); +} + + +void ListLog::selectHour(int hour) +{ + RDListViewItem *item=(RDListViewItem *)list_log_list->firstChild(); + while(item!=NULL) { + if(PredictedStartHour(item)==hour) { + list_log_list->clearSelection(); + list_log_list->ensureItemVisible(item); + list_log_list->setSelected(item,true); + return; + } + item=(RDListViewItem *)item->nextSibling(); + } +} + + +void ListLog::takeButtonData() +{ + int line=0; + + RDLogLine::Status status=CurrentStatus(); + switch(list_action_mode) { + case RDAirPlayConf::AddTo: + case RDAirPlayConf::MoveTo: + case RDAirPlayConf::CopyTo: + switch(status) { + case RDLogLine::Finished: + case RDLogLine::Playing: + case RDLogLine::Paused: + case RDLogLine::Finishing: + return; + + default: + line=list_log_list->currentItem()->text(15).toInt(); + break; + } + break; + + case RDAirPlayConf::CopyFrom: + line=list_log_list->currentItem()->text(15).toInt(); + if(list_log->logLine(line)!=NULL) { + switch(list_log->logLine(line)->type()) { + case RDLogLine::Marker: + case RDLogLine::OpenBracket: + case RDLogLine::CloseBracket: + case RDLogLine::Chain: + case RDLogLine::Track: + case RDLogLine::MusicLink: + case RDLogLine::TrafficLink: + case RDLogLine::UnknownType: + return; + + default: + break; + } + } + break; + + case RDAirPlayConf::MoveFrom: + switch(status) { + case RDLogLine::Finished: + case RDLogLine::Playing: + case RDLogLine::Paused: + case RDLogLine::Finishing: + return; + + default: + line=list_log_list->currentItem()->text(15).toInt(); + break; + } + break; + + case RDAirPlayConf::DeleteFrom: + switch(status) { + case RDLogLine::Finished: + case RDLogLine::Playing: + case RDLogLine::Finishing: + return; + + default: + line=list_log_list->currentItem()->text(15).toInt(); + // Don't try delete "end of log" or other invalid log entries. + if (line<0) { + return; + } + break; + } + break; + + default: + break; + } + emit selectClicked(list_id,line,status); +} + + +void ListLog::headButtonData() +{ + if(list_audition_head_playing) { + list_log->auditionStop(); + } + else { + if(!list_audition_tail_playing) { + list_log->auditionHead(CurrentLine()); + } + } +} + + +void ListLog::tailButtonData() +{ + if(list_audition_tail_playing) { + list_log->auditionStop(); + } + else { + if(!list_audition_head_playing) { + list_log->auditionTail(CurrentLine()); + } + } +} + + +void ListLog::auditionHeadData(int line) +{ + list_head_button->setPalette(list_scroll_color[0]); + list_audition_head_playing=true; +} + + +void ListLog::auditionTailData(int line) +{ + list_tail_button->setPalette(list_scroll_color[0]); + list_audition_tail_playing=true; +} + + +void ListLog::auditionStoppedData(int line) +{ + list_head_button->setPalette(list_scroll_color[1]); + list_tail_button->setPalette(list_scroll_color[1]); + list_audition_head_playing=false; + list_audition_tail_playing=false; +} + + +void ListLog::playButtonData() +{ + int line=CurrentLine(); + if(line<0) { + return; + } + + switch(list_playbutton_mode) { + case ListLog::ButtonPlay: + switch(CurrentStatus()) { + case RDLogLine::Scheduled: + case RDLogLine::Paused: + if(line<0) { + return; + } + list_log->play(line,RDLogLine::StartManual); + ClearSelection(); + break; + + default: + break; + } + break; + + case ListLog::ButtonStop: + if(list_pause_allowed) { + list_log->pause(line); + } + else { + list_log->stop(line); + } + ClearSelection(); + break; + + case ListLog::ButtonDisabled: + break; + } +} + + +void ListLog::modifyButtonData() +{ + RDListViewItem *item=(RDListViewItem *)list_log_list->currentItem(); + if((item==NULL)|| + ((item->text(16).toInt()!=RDLogLine::Scheduled)&& + (item->text(16).toInt()!=RDLogLine::Paused)&& + (item->text(16).toInt()!=RDLogLine::NoCart)&& + (item->text(16).toInt()!=RDLogLine::NoCut))) { + return; + } + int line=item->text(15).toInt(); + if(list_event_edit->exec(line)==0) { + list_log->lineModified(line); + } + if(line==1) { + return; + } + refresh(line); + ClearSelection(); +} + + +void ListLog::doubleclickedData(QListViewItem *,const QPoint &,int) +{ + modifyButtonData(); +} + + + +void ListLog::scrollButtonData() +{ + if(list_scroll) { + list_scroll_button->setPalette(list_scroll_color[1]); + list_scroll=false; +} + else { + list_scroll_button->setPalette(list_scroll_color[0]); + list_scroll=true; + ScrollTo(list_log->nextLine()); + } +} + + +void ListLog::refreshButtonData() +{ + list_log->refresh(); +} + + +void ListLog::nextButtonData() +{ + if((list_log_list->currentItem()==NULL)|| + (list_log_list->currentItem()->text(16).toInt()!=RDLogLine::Scheduled)) { + return; + } + int line=list_log_list->currentItem()->text(15).toInt(); + list_log->makeNext(line); + ClearSelection(); +} + + +void ListLog::loadButtonData() +{ + QString name=list_log->logName().left(list_log->logName().length()-4); + QString svcname=list_log->serviceName(); + + RDLog *edit_log; + QString sql; + RDSqlQuery *q; + + switch(list_logs_dialog->exec(&name,&svcname)) { + case 0: + list_log->setLogName(RDLog::tableName(name)); + list_log->load(); + break; + + case 2: + list_log->save(); + edit_log=new RDLog(list_log->logName(). + left(list_log->logName().length()-4)); + delete edit_log; + break; + + case 3: + sql=QString().sprintf("insert into LOGS set \ + NAME=\"%s\",TYPE=0,\ + DESCRIPTION=\"%s log\",\ + ORIGIN_USER=\"%s\",\ + ORIGIN_DATETIME=NOW(),\ + LINK_DATETIME=NOW(),\ + MODIFIED_DATETIME=NOW(),\ + SERVICE=\"%s\"", + (const char *)name, + (const char *)name, + (const char *)rdripc->user(), + (const char *)svcname); + q=new RDSqlQuery(sql); + if(!q->isActive()) { + QMessageBox::warning(this,tr("Log Exists"), + tr("Log Already Exists!")); + delete q; + return; + } + delete q; + edit_log=new RDLog(name,true); + RDCreateLogTable(RDLog::tableName(name)); + list_log->setServiceName(svcname); + list_log->setLogName(RDLog::tableName(name)); + list_log->save(); + edit_log->setModifiedDatetime(QDateTime(QDate::currentDate(), + QTime::currentTime())); + delete edit_log; + break; + + case -1: + list_log->clear(); + break; + } +} + + +void ListLog::logReloadedData() +{ + RefreshList(); + UpdateTimes(); + selectionChangedData(); +} + + +void ListLog::logPlayedData(int line) +{ + setStatus(line,RDLogLine::Playing); + UpdateTimes(); +} + + +void ListLog::logPausedData(int line) +{ + setStatus(line,RDLogLine::Paused); + UpdateTimes(); +} + + +void ListLog::logStoppedData(int line) +{ + setStatus(line,RDLogLine::Finished); + UpdateTimes(); +} + + +void ListLog::logInsertedData(int line) +{ + bool appended=false; + + if(line>=list_log->size()) { + line=list_log->size()-1; + } + if(line>=list_log->size()-1) { + appended=true; + } + int count; + RDListViewItem *item=GetItem(line+1); + while(item!=NULL) { + if((count=item->text(15).toInt())>=0) { + item->setText(15,QString().sprintf("%d",count+1)); + } + item=(RDListViewItem *)item->nextSibling(); + } + item=new RDListViewItem(list_log_list); + list_log->logLine(line)->setListViewItem(item); + RefreshItem(item,line); + if(appended) { + if((item=(RDListViewItem *)list_log_list->findItem("-2",13))!=NULL) { + list_log_list->ensureItemVisible(item); + } + } +} + + +void ListLog::logRemovedData(int line,int num,bool moving) +{ + int count; + RDListViewItem *item=GetItem(line+num); + while(item!=NULL) { + if((count=item->text(15).toInt())>=0) { + item->setText(15,QString().sprintf("%d",count-num)); + } + item=(RDListViewItem *)item->nextSibling(); + } + for(int i=line;i<(line+num);i++) { + delete GetItem(i); + } + if(!moving) { + UpdateTimes(line,num); + } +} + + +void ListLog::selectionChangedData() +{ + int count=0; + RDListViewItem *item=NULL; + RDListViewItem *next=(RDListViewItem *)list_log_list->firstChild(); + int start_line=-1; + int end_line=-1; + + while(next!=NULL) { + if(list_log_list->isSelected(next)) { + item=next; + if((start_line<0)&&(next->text(14).toInt()!=END_MARKER_ID)) { + start_line=next->text(15).toInt(); + } + if(next->text(12).toInt()!=END_MARKER_ID) { + end_line=next->text(15).toInt(); + } + count++; + } + next=(RDListViewItem *)next->nextSibling(); + } + if(count!=1) { + list_endtime_edit->setText(""); + list_stoptime_label->setText(tr("Selected:")); + SetPlaybuttonMode(ListLog::ButtonDisabled); + list_modify_button->setDisabled(true); + list_next_button->setDisabled(true); + if(start_line>=0) { + list_stoptime_edit->setText(RDGetTimeLength(list_log-> + length(start_line,end_line+1),true,false)); + } + return; + } + switch(CurrentStatus()) { + case RDLogLine::Scheduled: + case RDLogLine::Paused: + SetPlaybuttonMode(ListLog::ButtonPlay); + list_modify_button->setEnabled(true); + list_next_button->setEnabled(true); + break; + + case RDLogLine::Playing: + SetPlaybuttonMode(ListLog::ButtonStop); + list_modify_button->setEnabled(true); + list_next_button->setDisabled(true); + break; + + case RDLogLine::Finished: + SetPlaybuttonMode(ListLog::ButtonDisabled); + list_modify_button->setDisabled(true); + list_next_button->setDisabled(true); + break; + + default: + break; + } + if(item->text(15).toInt()>=0) { + list_endtime_edit->setText(RDGetTimeLength(list_log-> + length(item->text(15).toInt(),list_log->size()),true,false)); + list_stoptime_label->setText(tr("Next Stop:")); + int stoplen=list_log->lengthToStop(item->text(15).toInt()); + if(stoplen>=0) { + list_stoptime_edit->setText(RDGetTimeLength(stoplen,true,false)); + } + else { + list_stoptime_edit->setText(""); + } + } + else { + list_endtime_edit->setText(""); + list_stoptime_edit->setText(""); + } +} + + +void ListLog::transportChangedData() +{ + int count=0; + int transport_line[TRANSPORT_QUANTITY]; + + SetColor(); + + count=0; + list_log->transportEvents(transport_line); + for(int i=0;i=0)) { + ScrollTo(transport_line[0]); + } +} + + +void ListLog::modifiedData(int line) +{ + RefreshList(line); + UpdateTimes(); +} + + +void ListLog::refreshabilityChangedData(bool state) +{ + list_refresh_button->setEnabled(state); +} + + +void ListLog::cartDroppedData(int line,RDLogLine *ll) +{ + emit cartDropped(list_id,line,ll); +} + + +void ListLog::paintEvent(QPaintEvent *e) +{ + if(!rdairplay_conf->showCounters()) { + return; + } + int x=336; + int y=sizeHint().height()-111; + + QPainter *p=new QPainter(this); + p->setPen(black); + p->setBrush(black); + p->moveTo(x,y); + p->lineTo(x+146,y); + p->lineTo(x+146,y+53); + p->lineTo(x,y+53); + p->lineTo(x,y); + + p->end(); + delete p; + +} + + +void ListLog::RefreshList() +{ + RDListViewItem *l; + RDLogLine *logline; + + list_log_list->clear(); + l=new RDListViewItem(list_log_list); + l->setText(5,tr("--- end of log ---")); + l->setText(15,QString().sprintf("%d",END_MARKER_ID)); + l->setText(14,QString().sprintf("%d",list_log->size())); + for(int i=list_log->size()-1;i>=0;i--) { + if((logline=list_log->logLine(i))!=NULL) { + l=new RDListViewItem(list_log_list); + logline->setListViewItem(l); + } + RefreshItem(l,i); + } +} + + +void ListLog::RefreshList(int line) +{ + RDListViewItem *next=(RDListViewItem *)list_log_list->firstChild(); + while((next!=NULL)&&next->text(15).toInt()!=line) { + next=(RDListViewItem *)next->nextSibling(); + } + if(next!=NULL) { + RefreshItem(next,line); + } +} + + +void ListLog::RefreshItem(RDListViewItem *l,int line) +{ + int lines[TRANSPORT_QUANTITY]; + bool is_next=false; + + RDLogLine *log_line=list_log->logLine(line); + if(log_line==NULL) { + return; + } + switch(log_line->timeType()) { + case RDLogLine::Hard: + l->setText(1,QString("T")+ + TimeString(log_line->startTime(RDLogLine::Logged))); + l->setText(8,QString("T")+ + TimeString(log_line->startTime(RDLogLine::Logged))); + for(int i=0;icolumns();i++) { + l->setTextColor(i,LOG_HARDTIME_TEXT_COLOR,QFont::Bold); + } + l->setText(14,"N"); + break; + default: + if(!log_line->startTime(RDLogLine::Logged).isNull()) { + l->setText(8,TimeString(log_line->startTime(RDLogLine::Logged))); + } + else { + l->setText(8,""); + } + for(int i=0;icolumns();i++) { + l->setTextColor(i,LOG_RELATIVE_TEXT_COLOR,QFont::Normal); + } + l->setText(14,""); + break; + } + switch(log_line->transType()) { + case RDLogLine::Play: + l->setText(3,tr("PLAY")); + l->setTextColor(3,l->textColor(2),QFont::Normal); + break; + case RDLogLine::Stop: + l->setText(3,tr("STOP")); + l->setTextColor(3,l->textColor(2),QFont::Normal); + break; + case RDLogLine::Segue: + l->setText(3,tr("SEGUE")); + if(log_line->hasCustomTransition()) { + l->setTextColor(3,RD_CUSTOM_TRANSITION_COLOR,QFont::Bold); + } + else { + if(log_line->timeType()==RDLogLine::Hard) { + l->setTextColor(3,l->textColor(2),QFont::Bold); + } + else { + l->setTextColor(3,l->textColor(2),QFont::Normal); + } + } + break; + + default: + break; + } + switch(log_line->type()) { + case RDLogLine::Cart: + switch(log_line->source()) { + case RDLogLine::Tracker: + l->setPixmap(0,*list_track_cart_map); + break; + + default: + l->setPixmap(0,*list_playout_map); + break; + } + l->setText(2,RDGetTimeLength(log_line->effectiveLength(),false,false)); + l->setText(4,QString(). + sprintf("%06u",log_line->cartNumber())); + if((log_line->source()!=RDLogLine::Tracker)|| + log_line->originUser().isEmpty()|| + (!log_line->originDateTime().isValid())) { + l->setText(5,log_line->title()); + } + else { + l->setText(5,QString(). + sprintf("%s -- %s %s", + (const char *)log_line->title(), + (const char *)log_line->originUser(), + (const char *)log_line->originDateTime(). + toString("M/d hh:mm"))); + } + l->setText(6,log_line->artist()); + l->setText(7,log_line->groupName()); + l->setTextColor(7,log_line->groupColor(),QFont::Bold); + l->setText(9,log_line->album()); + l->setText(10,log_line->label()); + l->setText(11,log_line->client()); + l->setText(12,log_line->agency()); + break; + + case RDLogLine::Macro: + l->setPixmap(0,*list_macro_map); + l->setText(2,RDGetTimeLength(log_line->forcedLength(),false,false)); + l->setText(4,QString(). + sprintf("%06u",log_line->cartNumber())); + l->setText(5,log_line->title()); + l->setText(6,log_line->artist()); + l->setText(7,log_line->groupName()); + l->setTextColor(7,log_line->groupColor(),QFont::Bold); + l->setText(9,log_line->album()); + l->setText(10,log_line->label()); + l->setText(11,log_line->client()); + l->setText(12,log_line->agency()); + break; + + case RDLogLine::Marker: + l->setPixmap(0,*list_notemarker_map); + l->setText(2,"00:00"); + l->setText(4,tr("MARKER")); + l->setText(5,RDTruncateAfterWord(log_line->markerComment(),5,true)); + l->setText(13,log_line->markerLabel()); + break; + + case RDLogLine::Track: + l->setPixmap(0,*list_mic16_map); + l->setText(2,"00:00"); + l->setText(4,tr("TRACK")); + l->setText(5,RDTruncateAfterWord(log_line->markerComment(),5,true)); + break; + + case RDLogLine::MusicLink: + l->setPixmap(0,*list_music_map); + l->setText(2,"00:00"); + l->setText(4,tr("LINK")); + l->setText(5,tr("[music import]")); + break; + + case RDLogLine::TrafficLink: + l->setPixmap(0,*list_traffic_map); + l->setText(2,"00:00"); + l->setText(4,tr("LINK")); + l->setText(5,tr("[traffic import]")); + break; + + case RDLogLine::Chain: + l->setPixmap(0,*list_chain_map); + l->setText(2,""); + l->setText(4,tr("CHAIN TO")); + l->setText(5,log_line->markerLabel()); + l->setText(6,RDTruncateAfterWord(log_line->markerComment(),5,true)); + break; + + default: + break; + } + l->setText(14,QString().sprintf("%d",log_line->id())); + l->setText(15,QString().sprintf("%d",line)); + l->setText(16,QString().sprintf("%d",log_line->status())); + SetPlaybuttonMode(ListLog::ButtonDisabled); + list_modify_button->setDisabled(true); + switch(log_line->state()) { + case RDLogLine::NoCart: + if(log_line->type()==RDLogLine::Cart) { + l->setPixmap(0,NULL); + l->setText(8,""); + l->setText(3,""); + l->setText(5,tr("[CART NOT FOUND]")); + } + break; + + case RDLogLine::NoCut: + if(log_line->type()==RDLogLine::Cart) { + l->setText(6,tr("[NO VALID CUT AVAILABLE]")); + } + break; + + default: + if((log_line->type()==RDLogLine::Cart)&& + (log_line->effectiveLength()==0)) { + l->setText(6,tr("[NO AUDIO AVAILABLE]")); + } + break; + } + list_log->transportEvents(lines); + for(int i=0;ilogLine(line))==NULL) { + return NULL; + } + return logline->listViewItem(); +} + + +int ListLog::CurrentLine() { + RDListViewItem *item; + + if((item=(RDListViewItem *)list_log_list->currentItem())==NULL) { + return -1; + } + if(!list_log_list->isSelected(item)) { + return -1; + } + return list_log_list->currentItem()->text(15).toInt(); +} + + +RDLogLine::Status ListLog::CurrentStatus() { + if(list_log_list->currentItem()==NULL) { + return RDLogLine::Finished; + } + return (RDLogLine::Status)list_log_list->currentItem()->text(16).toInt(); +} + + +RDLogLine::State ListLog::CurrentState() { + if(list_log_list->currentItem()==NULL) { + return RDLogLine::NoCart; + } + return list_log-> + logLine(list_log_list->currentItem()->text(14).toInt())->state(); +} + + +void ListLog::ClearSelection() +{ + list_log_list->clearSelection(); + SetPlaybuttonMode(ListLog::ButtonDisabled); + list_modify_button->setDisabled(true); + list_next_button->setDisabled(true); +} + + +void ListLog::UpdateTimes(int removed_line,int num_lines) +{ + QTime time; + QTime end_time; + int line; + RDLogLine *logline; + + RDListViewItem *next=(RDListViewItem *)list_log_list->firstChild(); + for(int i=0;i<(list_log_list->childCount()-1);i++) { + if((line=next->text(15).toInt())>=removed_line) { + line+=num_lines; + } + if((logline=list_log->logLine(line))!=NULL) { + switch((RDLogLine::Status)next->text(16).toInt()) { + case RDLogLine::Scheduled: + case RDLogLine::Paused: + switch(logline->timeType()) { + case RDLogLine::Hard: + next->setText(1,QString(tr("T"))+ + TimeString(logline->startTime(RDLogLine::Logged))); + break; + + default: + if(!logline->startTime(RDLogLine::Predicted).isNull()) { + next->setText(1, + TimeString(logline->startTime(RDLogLine::Predicted))); + } + else { + next->setText(1,""); + } + break; + } + break; + + default: + next->setText(1,TimeString(logline->startTime(RDLogLine::Actual))); + break; + } + next=(RDListViewItem *)next->nextSibling(); + } + } + UpdateHourSelector(); +} + + +void ListLog::ScrollTo(int line) +{ + RDListViewItem *item=GetItem(line); + + list_log_list->ensureVisible(0,list_log_list->itemPos(item), + 0,list_log_list->size().height()/2); + list_log_list->setCurrentItem(item); + list_log_list->clearSelection(); +} + + +void ListLog::UpdateColor(int line,bool next) +{ + RDLogLine *logline; + if((logline=list_log->logLine(line))==NULL) { + return; + } + RDListViewItem *item=GetItem(line); + if(item==NULL) { + return; + } + switch(logline->status()) { + case RDLogLine::Scheduled: + case RDLogLine::Auditioning: + if((logline->type()==RDLogLine::Cart)&& + (logline->state()==RDLogLine::NoCart)) { + item->setBackgroundColor(QColor(LOG_ERROR_COLOR)); + } + else { + if(((logline->cutNumber()<0)&&(logline->type()==RDLogLine::Cart))|| + (logline->state()==RDLogLine::NoCut)) { + item->setBackgroundColor(QColor(LOG_ERROR_COLOR)); + item->setText(6,tr("[NO VALID CUT AVAILABLE]")); + } + else { + if(next) { + if(logline->evergreen()) { + item->setBackgroundColor(QColor(LOG_EVERGREEN_COLOR)); + } + else { + item->setBackgroundColor(QColor(LOG_NEXT_COLOR)); + } + } + else { + if(logline->evergreen()) { + item->setBackgroundColor(QColor(LOG_EVERGREEN_COLOR)); + } + else { + item->setBackgroundColor(QColor(LOG_SCHEDULED_COLOR)); + } + } + } + } + break; + + case RDLogLine::Playing: + case RDLogLine::Finishing: + item->setBackgroundColor(QColor(LOG_PLAYING_COLOR)); + break; + + case RDLogLine::Paused: + item->setBackgroundColor(QColor(LOG_PAUSED_COLOR)); + break; + + case RDLogLine::Finished: + if(logline->state()==RDLogLine::Ok) { + item->setBackgroundColor(QColor(LOG_FINISHED_COLOR)); + } + else { + item->setBackgroundColor(QColor(LOG_ERROR_COLOR)); + } + break; + } +} + + +void ListLog::SetColor() +{ + for(int i=0;isize();i++) { + UpdateColor(i); + } +} + + +void ListLog::SetPlaybuttonMode(ListLog::PlayButtonMode mode) +{ + if(mode==list_playbutton_mode) { + return; + } + switch(mode) { + case ListLog::ButtonPlay: + list_play_button->setEnabled(true); + list_play_button->setText(tr("Start")); + break; + + case ListLog::ButtonStop: + list_play_button->setEnabled(true); + if(list_pause_allowed) { + list_play_button->setText(tr("Pause")); + } + else { + list_play_button->setText(tr("Stop")); + } + break; + + case ListLog::ButtonDisabled: + list_play_button->setDisabled(true); + list_play_button->setText(tr("Start")); + break; + } + list_playbutton_mode=mode; +} + + +QString ListLog::TimeString(const QTime &time) const +{ + QString ret; + switch(list_time_mode) { + case RDAirPlayConf::TwelveHour: + ret=time.toString("h:mm:ss.zzz"); + ret=ret.left(ret.length()-2); + ret+=(" "+time.toString("ap")); + break; + + case RDAirPlayConf::TwentyFourHour: + ret=time.toString("hh:mm:ss.zzz").left(10); + break; + } + return ret; +} + + +void ListLog::UpdateHourSelector() +{ + bool found[24]={false}; + RDListViewItem *item=(RDListViewItem *)list_log_list->firstChild(); + int hour=-1; + + while(item!=NULL) { + if((hour=PredictedStartHour(item))>=0) { + found[hour]=true; + } + item=(RDListViewItem *)item->nextSibling(); + } + list_hour_selector->updateHours(found); +} + + +int ListLog::PredictedStartHour(RDListViewItem *item) +{ + bool ok=false; + + if(item==NULL) { + return -1; + } + QStringList item_fields=QStringList().split(":",item->text(1)); + if(item_fields.size()==3) { + int item_hour=item_fields[0].replace("T","").toInt(&ok); + if(ok) { + return item_hour; + } + } + return -1; +} diff --git a/rdairplay/list_log.h b/rdairplay/list_log.h new file mode 100644 index 00000000..d5fcd6fa --- /dev/null +++ b/rdairplay/list_log.h @@ -0,0 +1,158 @@ +// list_log.h +// +// The full log list widget for RDAirPlay. +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: list_log.h,v 1.36.6.2 2013/12/28 00:00:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_LOG_H +#define LIST_LOG_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define END_MARKER_ID -2 + +class ListLog : public QWidget +{ + Q_OBJECT + public: + ListLog(LogPlay *log,int id,bool allow_pause=false, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void refresh(); + void refresh(int line); + void setStatus(int line,RDLogLine::Status status); + RDAirPlayConf::ActionMode actionMode() const; + void setActionMode(RDAirPlayConf::ActionMode mode,int *cartnum=0); + void setOpMode(RDAirPlayConf::OpMode mode); + void setTimeMode(RDAirPlayConf::TimeMode mode); + void userChanged(bool add_allowed,bool delete_allowed, + bool arrange_allowed,bool playout_allowed); + + signals: + void selectClicked(int id,int line,RDLogLine::Status status); + void cartDropped(int id,int line,RDLogLine *ll); + + private slots: + void selectHour(int hour); + void headButtonData(); + void tailButtonData(); + void auditionHeadData(int line); + void auditionTailData(int line); + void auditionStoppedData(int line); + void takeButtonData(); + void playButtonData(); + void modifyButtonData(); + void doubleclickedData(QListViewItem *,const QPoint &,int); + void scrollButtonData(); + void refreshButtonData(); + void nextButtonData(); + void loadButtonData(); + void logReloadedData(); + void logPlayedData(int line); + void logPausedData(int line); + void logStoppedData(int line); + void logInsertedData(int line); + void logRemovedData(int line,int num,bool moving); + void selectionChangedData(); + void transportChangedData(); + void modifiedData(int line); + void refreshabilityChangedData(bool state); + void cartDroppedData(int line,RDLogLine *ll); + + protected: + void paintEvent(QPaintEvent *e); + + private: + enum PlayButtonMode {ButtonDisabled=0,ButtonPlay=1,ButtonStop=2}; + void RefreshList(); + void RefreshList(int line); + void RefreshItem(RDListViewItem *l,int line); + int CurrentLine(); + RDLogLine::Status CurrentStatus(); + RDLogLine::State CurrentState(); + void ClearSelection(); + RDListViewItem *GetItem(int line); + void UpdateTimes(int removed_line=-1,int num_lines=0); + void ScrollTo(int line); + void UpdateColor(int line,bool next=false); + void SetColor(); + void SetPlaybuttonMode(ListLog::PlayButtonMode mode); + QString TimeString(const QTime &time) const; + void UpdateHourSelector(); + int PredictedStartHour(RDListViewItem *item); + HourSelector *list_hour_selector; + LibListView *list_log_list; + LogPlay *list_log; + ListLogs *list_logs_dialog; + RDAirPlayConf::ActionMode list_action_mode; + ListLog::PlayButtonMode list_playbutton_mode; + EditEvent *list_event_edit; + QLineEdit *list_endtime_edit; + QLabel *list_stoptime_label; + QLineEdit *list_stoptime_edit; + QPushButton *list_take_button; + QPushButton *list_play_button; + QPushButton *list_modify_button; + QPushButton *list_scroll_button; + QPushButton *list_next_button; + QPushButton *list_refresh_button; + QPushButton *list_load_button; + QPushButton *list_head_button; + QPushButton *list_tail_button; + int *list_cart; + int list_id; + RDAirPlayConf::OpMode list_op_mode; + RDAirPlayConf::TimeMode list_time_mode; + QPalette list_to_color; + QPalette list_from_color; + QPalette list_list_to_color; + QPalette list_list_from_color; + bool list_scroll; + bool list_suspended_scroll; + QPalette list_scroll_color[2]; + QPixmap *list_playout_map; + QPixmap *list_macro_map; + QPixmap *list_chain_map; + QPixmap *list_track_cart_map; + QPixmap *list_mic16_map; + QPixmap *list_notemarker_map; + QPixmap *list_traffic_map; + QPixmap *list_music_map; + bool list_pause_allowed; + bool list_audition_head_playing; + bool list_audition_tail_playing; +}; + + +#endif // LIST_LOG_H diff --git a/rdairplay/list_logs.cpp b/rdairplay/list_logs.cpp new file mode 100644 index 00000000..7521e59f --- /dev/null +++ b/rdairplay/list_logs.cpp @@ -0,0 +1,262 @@ +// list_logs.cpp +// +// Select a Rivendell Log +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_logs.cpp,v 1.22.6.1 2012/08/10 19:07:21 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include + +ListLogs::ListLogs(LogPlay *log,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + + list_log=log; + setCaption(tr("Select a Log")); + + // + // Log List + // + list_log_list=new QListView(this,"list_log_list"); + list_log_list->setGeometry(10,10, + sizeHint().width()-20,sizeHint().height()-80); + list_log_list->setAllColumnsShowFocus(true); + list_log_list->setItemMargin(5); + connect(list_log_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + list_log_list->addColumn(tr("NAME")); + list_log_list->setColumnAlignment(0,Qt::AlignLeft); + list_log_list->addColumn(tr("DESCRIPTION")); + list_log_list->setColumnAlignment(1,Qt::AlignLeft); + list_log_list->addColumn(tr("SERVICE")); + list_log_list->setColumnAlignment(2,Qt::AlignLeft); + + // + // Load Button + // + QPushButton *button=new QPushButton(this,"load_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("Load")); + connect(button,SIGNAL(clicked()),this,SLOT(loadButtonData())); + + // + // Unload Button + // + list_unload_button=new QPushButton(this,"list_unload_button"); + list_unload_button->setGeometry(100,sizeHint().height()-60,80,50); + list_unload_button->setFont(button_font); + list_unload_button->setText(tr("Unload")); + connect(list_unload_button,SIGNAL(clicked()),this,SLOT(unloadButtonData())); + + // + // Save Button + // + button=new QPushButton(this,"save_button"); + button->setGeometry(210,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("Save")); + connect(button,SIGNAL(clicked()),this,SLOT(saveButtonData())); + + // + // Save As Button + // + list_saveas_button=new QPushButton(this,"list_saveas_button"); + list_saveas_button->setGeometry(300,sizeHint().height()-60,80,50); + list_saveas_button->setFont(button_font); + list_saveas_button->setText(tr("Save &As")); + connect(list_saveas_button,SIGNAL(clicked()),this,SLOT(saveAsButtonData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("Cancel")); + button->setDefault(true); + connect(button,SIGNAL(clicked()),this,SLOT(cancelButtonData())); + + RefreshList(); +} + + +QSize ListLogs::sizeHint() const +{ + return QSize(500,300); +} + + +QSizePolicy ListLogs::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int ListLogs::exec(QString *logname,QString *svcname) +{ + list_logname=logname; + list_svcname=svcname; + list_saveas_button->setEnabled(rduser->createLog()); + RefreshList(); + return QDialog::exec(); +} + + +void ListLogs::closeEvent(QCloseEvent *e) +{ + done(1); +} + + +void ListLogs::doubleClickedData(QListViewItem *,const QPoint &,int) +{ + loadButtonData(); +} + + +void ListLogs::loadButtonData() +{ + QListViewItem *item=list_log_list->selectedItem(); + if(item==NULL) { + return; + } + *list_logname=item->text(0); + done(0); +} + + +void ListLogs::saveButtonData() +{ + if(list_logname->isEmpty()) { + saveAsButtonData(); + } + else { + done(2); + } +} + + +void ListLogs::saveAsButtonData() +{ + QString logname; + QString svcname=*list_svcname; + RDAddLog *log; + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec) { + log=new RDAddLog(&logname,&svcname,rdstation_conf, + tr("Rename Log"),this,"log", rduser); + } else { // RDStation::HostSec + log=new RDAddLog(&logname,&svcname,rdstation_conf, + tr("Rename Log"),this,"log"); + } + + if(log->exec()<0) { + delete log; + return; + } + delete log; + *list_logname=logname; + *list_svcname=svcname; + done(3); +} + + +void ListLogs::unloadButtonData() +{ + done(-1); +} + + +void ListLogs::cancelButtonData() +{ + done(1); +} + + +void ListLogs::RefreshList() +{ + RDSqlQuery *q; + QString sql; + QListViewItem *l; + QDate current_date=QDate::currentDate(); + QStringList services_list; + + list_log_list->clear(); + + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec) { + if(rduser!=NULL) { + services_list = rduser->services(); + } + } + else { // RDStation::HostSec + sql=QString().sprintf("select SERVICE_NAME from SERVICE_PERMS \ + where STATION_NAME=\"%s\"", + (const char *)rdstation_conf->name()); + q=new RDSqlQuery(sql); + while(q->next()) { + services_list.append( q->value(0).toString() ); + } + delete q; + } + + if(services_list.size()==0) { + return; + } + sql=QString().sprintf("select NAME,DESCRIPTION,SERVICE from LOGS \ + where (TYPE=0)&&(LOG_EXISTS=\"Y\")&&\ + ((START_DATE<=\"%s\")||(START_DATE=\"0000-00-00\"))&&\ + ((END_DATE>=\"%s\")||(END_DATE=\"0000-00-00\"))&&(", + (const char *)current_date.toString("yyyy-MM-dd"), + (const char *)current_date.toString("yyyy-MM-dd")); + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end(); ++it ) { + sql+=QString().sprintf("SERVICE=\"%s\"||", + (const char *)*it); + } + sql=sql.left(sql.length()-2); + sql+=")"; + + q=new RDSqlQuery(sql); + while(q->next()) { + l=new QListViewItem(list_log_list); + l->setText(0,q->value(0).toString()); + l->setText(1,q->value(1).toString()); + l->setText(2,q->value(2).toString()); + } + delete q; +} diff --git a/rdairplay/list_logs.h b/rdairplay/list_logs.h new file mode 100644 index 00000000..14839dc7 --- /dev/null +++ b/rdairplay/list_logs.h @@ -0,0 +1,65 @@ +// list_logs.h +// +// Select a Rivendell Log +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_logs.h,v 1.10 2010/10/11 16:07:12 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_LOGS_H +#define LIST_LOGS_H + +#include +#include +#include +#include + +#include + +class ListLogs : public QDialog +{ + Q_OBJECT + + public: + ListLogs(LogPlay *log,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(QString *logname,QString *svcname); + + private slots: + void doubleClickedData(QListViewItem *,const QPoint &,int); + void closeEvent(QCloseEvent *); + void loadButtonData(); + void saveButtonData(); + void saveAsButtonData(); + void unloadButtonData(); + void cancelButtonData(); + + private: + void RefreshList(); + QListView *list_log_list; + QString *list_logname; + QString *list_svcname; + QPushButton *list_unload_button; + QPushButton *list_saveas_button; + LogPlay *list_log; +}; + + +#endif diff --git a/rdairplay/local_macros.cpp b/rdairplay/local_macros.cpp new file mode 100644 index 00000000..1733902e --- /dev/null +++ b/rdairplay/local_macros.cpp @@ -0,0 +1,940 @@ +// local_macros.cpp +// +// Local RML Macros for the Rivendell's RDAirPlay +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: local_macros.cpp,v 1.31.6.3.2.2 2014/05/22 19:37:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include + +#include +#include + +void MainWidget::RunLocalMacros(RDMacro *rml) +{ + QString str; + QString logname; + RDAirPlayConf::PanelType panel_type; + int panel_number; + QString sql; + QPalette pal; + bool ret=false; + int fade; + RDLogLine *logline=NULL; + QString label; + int mach=0; + + if(rml->role()!=RDMacro::Cmd) { + return; + } + + switch(rml->command()) { + case RDMacro::LB: // Label + if(rml->argQuantity()==0) { + air_message_label->clear(); + } + else { + for(int i=0;i<(rml->argQuantity()-1);i++) { + str+=(rml->arg(i).toString()+" "); + } + str+=rml->arg(rml->argQuantity()-1).toString(); + pal=air_message_label->palette(); + pal.setColor(QPalette::Active,QColorGroup::Foreground,QColor(black)); + pal.setColor(QPalette::Inactive,QColorGroup::Foreground, + QColor(black)); + air_message_label->setPalette(pal); + air_message_label->setFont(MessageFont(str)); + air_message_label->setText(str); + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::LC: // Color Label + if(rml->argQuantity()<=1) { + air_message_label->clear(); + } + else { + QColor color(rml->arg(0).toString()); + if(!color.isValid()) { + color=QColor(black); + } + for(int i=1;i<(rml->argQuantity()-1);i++) { + str+=(rml->arg(i).toString()+" "); + } + str+=rml->arg(rml->argQuantity()-1).toString(); + pal=air_message_label->palette(); + pal.setColor(QPalette::Active,QColorGroup::Foreground,color); + pal.setColor(QPalette::Inactive,QColorGroup::Foreground,color); + air_message_label->setPalette(pal); + air_message_label->setFont(MessageFont(str)); + air_message_label->setText(str); + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::LL: // Load Log + if((rml->argQuantity()<1)||(rml->argQuantity()>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(0).toInt()<1)||(rml->arg(0).toInt()>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(rml->argQuantity()==1) { // Clear Log + air_log[rml->arg(0).toInt()-1]->clear(); + } + else { // Load Log + logname=rml->arg(1).toString(); + if(!RDLog::exists(logname)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + air_log[rml->arg(0).toInt()-1]->setLogName(RDLog::tableName(logname)); + air_log[rml->arg(0).toInt()-1]->load(); + } + if(rml->argQuantity()==3) { // Start Log + if(rml->arg(2).toInt()arg(0).toInt()-1]->size()) { + if(rml->arg(2).toInt()>=0) { // Unconditional start + air_log[rml->arg(0).toInt()-1]->play(rml->arg(2).toInt(), + RDLogLine::StartMacro); + } + if(rml->arg(2).toInt()==-2) { // Start if trans type allows + // Find first non-running event + bool found=false; + for(int i=0;iarg(0).toInt()-1]->size();i++) { + if((logline=air_log[rml->arg(0).toInt()-1]->logLine(i))!=NULL) { + if(logline->status()==RDLogLine::Scheduled) { + found=true; + i=air_log[rml->arg(0).toInt()-1]->size(); + } + } + } + if(found) { + switch(logline->transType()) { + case RDLogLine::Play: + case RDLogLine::Segue: + air_log[rml->arg(0).toInt()-1]-> + play(0,RDLogLine::StartMacro); + break; + + case RDLogLine::Stop: + case RDLogLine::NoTrans: + break; + } + } + } + } + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::AL: // Append Log + if(rml->argQuantity()!=2) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(0).toInt()<1)||(rml->arg(0).toInt()>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + logname=rml->arg(1).toString(); + if(!RDLog::exists(logname)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + air_log[rml->arg(0).toInt()-1]->append(logname); + break; + + case RDMacro::MN: // Make Next + if(rml->argQuantity()!=2) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(0).toInt()<1)||(rml->arg(0).toInt()>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(1).toInt()<0)|| + (rml->arg(1).toInt()>=air_log[rml->arg(0).toInt()-1]->size())) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + air_log[rml->arg(0).toInt()-1]->makeNext(rml->arg(1).toInt()); + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::PB: // Push Button + if(rml->argQuantity()!=1) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(0).toInt()<1)|| + (rml->arg(0).toInt()>BUTTON_TOTAL_BUTTONS)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + return; + } + } + air_button_list->startButton(rml->arg(0).toInt()-1); + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::PC: // Label Button + if(rml->argQuantity()<5) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(!GetPanel(rml->arg(0).toString(),&panel_type,&panel_number)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(1).toInt()<=0)|| + (rml->arg(1).toInt()>AIR_PANEL_BUTTON_COLUMNS)|| + (rml->arg(2).toInt()<=0)|| + (rml->arg(2).toInt()>AIR_PANEL_BUTTON_ROWS)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + for(int i=3;i<(rml->argQuantity()-1);i++) { + label+=(rml->arg(i).toString()+" "); + } + label=label.left(label.length()-1); + air_panel->setText(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,label); + air_panel->setColor(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1, + rml->arg(rml->argQuantity()-1).toString()); + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::PE: // Load Panel Button + if(rml->argQuantity()!=4) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(!GetPanel(rml->arg(0).toString(),&panel_type,&panel_number)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(1).toInt()<=0)|| + (rml->arg(1).toInt()>AIR_PANEL_BUTTON_COLUMNS)|| + (rml->arg(2).toInt()<=0)|| + (rml->arg(2).toInt()>AIR_PANEL_BUTTON_ROWS)|| + (rml->arg(3).toUInt()>999999)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + air_panel->setButton(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,rml->arg(3).toUInt()); + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::PL: // Start + if(rml->argQuantity()!=2) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(0).toInt()<1)||(rml->arg(0).toInt()>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(1).toInt()<0)|| + (rml->arg(1).toInt()>=air_log[rml->arg(0).toInt()-1]->size())) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(!air_log[rml->arg(0).toInt()-1]->running()) { + if(!air_log[rml->arg(0).toInt()-1]->play(rml->arg(1).toInt(), + RDLogLine::StartMacro)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::PM: // Set Mode + if((rml->argQuantity()!=1)&&(rml->argQuantity()!=2)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(rml->argQuantity()==2) { + mach=rml->arg(1).toInt(); + if((mach<0)||(mach>RDAIRPLAY_LOG_QUANTITY)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + } + switch((RDAirPlayConf::OpMode)rml->arg(0).toInt()) { + case RDAirPlayConf::LiveAssist: + SetLiveAssistMode(mach-1); + break; + + case RDAirPlayConf::Manual: + SetManualMode(mach-1); + break; + + case RDAirPlayConf::Auto: + SetAutoMode(mach-1); + break; + + default: + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + return; + } + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::PN: // Start Next + if((rml->argQuantity()<1)||(rml->argQuantity()>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(0).toInt()<1)||(rml->arg(0).toInt()>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(rml->argQuantity()>=2) { + if((rml->arg(1).toInt()<1)||(rml->arg(1).toInt()>2)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(rml->argQuantity()==3) { + if((rml->arg(2).toInt()<0)||(rml->arg(2).toInt()>1)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + } + } + if(air_log[rml->arg(0).toInt()-1]->nextLine()>=0) { + if(rml->argQuantity()==1) { + air_log[rml->arg(0).toInt()-1]-> + play(air_log[rml->arg(0).toInt()-1]->nextLine(), + RDLogLine::StartMacro); + } + else { + if(rml->argQuantity()==2) { + air_log[rml->arg(0).toInt()-1]-> + play(air_log[rml->arg(0).toInt()-1]->nextLine(), + RDLogLine::StartMacro,rml->arg(1).toInt()-1); + } + else { + air_log[rml->arg(0).toInt()-1]-> + play(air_log[rml->arg(0).toInt()-1]->nextLine(), + RDLogLine::StartMacro, + rml->arg(1).toInt()-1,rml->arg(2).toInt()); + } + } + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::PP: // Play Panel Button + if(rml->argQuantity()<3 || rml->argQuantity()>5) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(!GetPanel(rml->arg(0).toString(),&panel_type,&panel_number)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(1).toInt()<0)|| + (rml->arg(1).toInt()>AIR_PANEL_BUTTON_COLUMNS)|| + (rml->arg(2).toInt()<0)|| + (rml->arg(2).toInt()>AIR_PANEL_BUTTON_ROWS)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + switch(rml->argQuantity()) { + case 3: + air_panel->play(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,RDLogLine::StartMacro); + break; + + case 4: + air_panel->play(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,RDLogLine::StartMacro,rml->arg(3).toInt()); + break; + + case 5: + if(rml->arg(4).toInt()==1) { + air_panel->play(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1, + RDLogLine::StartMacro,rml->arg(3).toInt(),true); + } + else { + air_panel->play(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,RDLogLine::StartMacro,rml->arg(3).toInt()); + } + break; + + default: + break; + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::PS: // Stop + if(rml->argQuantity()<1 || rml->argQuantity()>3) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(0).toInt()<0)||(rml->arg(0).toInt()>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + fade=0; + if(rml->argQuantity()>1) { + fade=rml->arg(1).toInt(); + } + switch(rml->arg(0).toInt()) { + case 0: // Stop All Logs + air_log[0]->stop(true,0,fade); + air_log[1]->stop(true,0,fade); + air_log[2]->stop(true,0,fade); + break; + + case 1: + case 2: + case 3: + if(rml->argQuantity()==3) { + air_log[rml->arg(0).toInt()-1]->stop(false,rml->arg(2).toInt(),fade); + } + else { + air_log[rml->arg(0).toInt()-1]->stop(true,0,fade); + } + break; + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::MD: // Duck Machine + if(rml->argQuantity()<3 || rml->argQuantity()>4) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(0).toInt()<0)||(rml->arg(0).toInt()>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + switch(rml->arg(0).toInt()) { + case 0: // Duck All Logs + air_log[0]->duckVolume(rml->arg(1).toInt()*100,rml->arg(2).toInt()); + air_log[1]->duckVolume(rml->arg(1).toInt()*100,rml->arg(2).toInt()); + air_log[2]->duckVolume(rml->arg(1).toInt()*100,rml->arg(2).toInt()); + break; + + case 1: + case 2: + case 3: + if(rml->argQuantity()==3) { + air_log[rml->arg(0).toInt()-1]->duckVolume(rml->arg(1).toInt()*100,rml->arg(2).toInt()); + } + else { + air_log[rml->arg(0).toInt()-1]->duckVolume(rml->arg(1).toInt()*100, + rml->arg(2).toInt(),rml->arg(3).toInt()); + } + break; + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::PT: // Stop Panel Button + if(rml->argQuantity()<3 || rml->argQuantity()>6) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(!GetPanel(rml->arg(0).toString(),&panel_type,&panel_number)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(1).toInt()<0)|| + (rml->arg(1).toInt()>AIR_PANEL_BUTTON_COLUMNS)|| + (rml->arg(2).toInt()<0)|| + (rml->arg(2).toInt()>AIR_PANEL_BUTTON_ROWS)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + switch(rml->argQuantity()) { + case 3: + air_panel->stop(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1); + break; + + case 4: + air_panel->stop(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,rml->arg(3).toInt()); + break; + + case 5: + if(rml->arg(4).toInt()==1) { + air_panel->stop(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,rml->arg(3).toInt(),true); + } + else { + air_panel->stop(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,rml->arg(3).toInt(),false); + } + break; + + case 6: + if(rml->arg(4).toInt()==1) { + air_panel->stop(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,rml->arg(3).toInt(),true, + rml->arg(5).toInt()); + } + else { + air_panel->stop(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,rml->arg(3).toInt(),false, + rml->arg(5).toInt()); + } + break; + + default: + break; + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::PU: // Pause Panel Button + if(rml->argQuantity()<3 || rml->argQuantity()>4) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(!GetPanel(rml->arg(0).toString(),&panel_type,&panel_number)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(1).toInt()<0)|| + (rml->arg(1).toInt()>AIR_PANEL_BUTTON_COLUMNS)|| + (rml->arg(2).toInt()<0)|| + (rml->arg(2).toInt()>AIR_PANEL_BUTTON_ROWS)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(rml->argQuantity()==3) { + ret=air_panel->pause(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1); + } + else { + ret=air_panel->pause(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,rml->arg(3).toInt()); + } + if(rml->echoRequested()) { + rml->acknowledge(ret); + rdripc->sendRml(rml); + } + break; + + case RDMacro::PD: // Duck Panel Button + if(rml->argQuantity()<5 || rml->argQuantity()>6) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(!GetPanel(rml->arg(0).toString(),&panel_type,&panel_number)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(1).toInt()<0)|| + (rml->arg(1).toInt()>AIR_PANEL_BUTTON_COLUMNS)|| + (rml->arg(2).toInt()<0)|| + (rml->arg(2).toInt()>AIR_PANEL_BUTTON_ROWS)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(rml->argQuantity()==5) { + air_panel->duckVolume(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,(rml->arg(3).toInt())*100,rml->arg(4).toInt()); + } + else { + air_panel->duckVolume(panel_type,panel_number,rml->arg(2).toInt()-1, + rml->arg(1).toInt()-1,(rml->arg(3).toInt())*100,rml->arg(4).toInt(), + rml->arg(5).toInt()); + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + + case RDMacro::PW: // Select Widget + if(rml->argQuantity()!=1) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(0).toInt()<0)||(rml->arg(0).toInt()>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + switch(rml->arg(0).toInt()) { + case 0: // Sound Panel + panelButtonData(); + break; + + case 1: + case 2: + case 3: + fullLogButtonData(rml->arg(0).toInt()-1); + break; + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::PX: // Add Next + if(rml->argQuantity()!=2) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(0).toInt()<1)||(rml->arg(0).toInt()>3)|| + (rml->arg(1).toUInt()>999999)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(air_log[rml->arg(0).toInt()-1]->nextLine()>=0) { + air_log[rml->arg(0).toInt()-1]-> + insert(air_log[rml->arg(0).toInt()-1]->nextLine(), + rml->arg(1).toUInt(),RDLogLine::Play); + } + else { + air_log[rml->arg(0).toInt()-1]-> + insert(air_log[rml->arg(0).toInt()-1]->size(), + rml->arg(1).toUInt(),RDLogLine::Play); + air_log[rml->arg(0).toInt()-1]-> + makeNext(air_log[rml->arg(0).toInt()-1]->size()-1); + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::RL: // Refresh Log + if(rml->argQuantity()!=1) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(0).toInt()<1)||(rml->arg(0).toInt()>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(!air_log[rml->arg(0).toInt()-1]->refresh()) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + case RDMacro::SN: // Set default Now & Next Cart + if(rml->argQuantity()!=3) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(0).toString().lower()!="now")&& + (rml->arg(0).toString().lower()!="next")) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if((rml->arg(1).toInt()<1)||(rml->arg(1).toInt()>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(rml->arg(2).toUInt()>999999) { + if(rml->echoRequested()) { + rml->acknowledge(false); + rdripc->sendRml(rml); + } + return; + } + if(rml->arg(0).toString().lower()=="now") { + air_log[rml->arg(1).toInt()-1]->setNowCart(rml->arg(2).toUInt()); + } + else { + air_log[rml->arg(1).toInt()-1]->setNextCart(rml->arg(2).toUInt()); + } + if(rml->echoRequested()) { + rml->acknowledge(true); + rdripc->sendRml(rml); + } + break; + + default: + break; + } +} + + +QFont MainWidget::MessageFont(QString str) +{ + for(int i=(AIR_MESSAGE_FONT_QUANTITY-1);i>=0;i--) { + if(air_message_metrics[i]->width(str)currentType(); + *panel=air_panel->currentNumber(); + return true; + break; + + + default: + return false; + } + if(sscanf(((const char *)str)+1,"%d",panel)!=1) { + return false; + } + if((*panel<=0)||(*panel>rdairplay_conf->panels(*type))) { + return false; + } + (*panel)--; + return true; +} diff --git a/rdairplay/log_play.cpp b/rdairplay/log_play.cpp new file mode 100644 index 00000000..512e892b --- /dev/null +++ b/rdairplay/log_play.cpp @@ -0,0 +1,2775 @@ +// log_play.cpp +// +// Rivendell Log Playout Machine +// +// (C) Copyright 2002-2009 Fred Gleason +// +// $Id: log_play.cpp,v 1.197.8.7.2.2 2014/05/22 19:37:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +LogPlay::LogPlay(RDCae *cae,int id,QSocketDevice *nn_sock,QString logname, + std::vector *rlm_hosts, + QObject *parent,const char *name) + : QObject(parent,name),RDLogEvent(logname) +{ + // + // Initialize Data Structures + // + play_cae=cae; + play_log=NULL; + play_id=id; + play_rlm_hosts=rlm_hosts; + play_onair_flag=false; + play_segue_length=rdairplay_conf->segueLength()+1; + play_trans_length=rdairplay_conf->transLength()+1; + play_duck_volume_port1=0; + play_duck_volume_port2=0; + play_start_next=false; + play_running=false; + play_next_line=0; + play_post_time=QTime(); + play_post_offset=-1; + play_active_line=-1; + play_active_trans=RDLogLine::Play; + play_trans_line=-1; + play_grace_line=-1; + next_channel=0; + play_nownext_socket=nn_sock; + play_timescaling_available=false; + play_rescan_pos=0; + play_refreshable=false; + play_audition_preroll=rdairplay_conf->auditionPreroll(); + for(int i=0;iudpString(id); + play_nownext_address=rdairplay_conf->udpAddress(id); + play_nownext_port=rdairplay_conf->udpPort(id); + play_nownext_rml=rdairplay_conf->logRml(id); + play_now_cartnum=0; + play_next_cartnum=0; + play_prevnow_cartnum=0; + play_prevnext_cartnum=0; + play_op_mode=RDAirPlayConf::Auto; + + // + // Macro Cart Decks + // + play_macro_deck=new RDMacroEvent(rdstation_conf->address(),rdripc, + this,"play_macro_deck"); + connect(play_macro_deck,SIGNAL(started()),this,SLOT(macroStartedData())); + connect(play_macro_deck,SIGNAL(finished()),this,SLOT(macroFinishedData())); + connect(play_macro_deck,SIGNAL(stopped()),this,SLOT(macroStoppedData())); + + // + // CAE Signals + // + connect(rdcae,SIGNAL(timescalingSupported(int,bool)), + this,SLOT(timescalingSupportedData(int,bool))); + + // + // RIPC Signals + // + connect(rdripc,SIGNAL(onairFlagChanged(bool)), + this,SLOT(onairFlagChangedData(bool))); + + // + // Audition Player + // + play_audition_line=-1; + if((rdairplay_conf->card(RDAirPlayConf::CueChannel)>=0)&& + (rdairplay_conf->port(RDAirPlayConf::CueChannel)>=0)) { + play_audition_player=new RDSimplePlayer(rdcae,rdripc, + rdairplay_conf->card(RDAirPlayConf::CueChannel), + rdairplay_conf->port(RDAirPlayConf::CueChannel), + 0,0); + play_audition_player->playButton()->hide(); + play_audition_player->stopButton()->hide(); + connect(play_audition_player,SIGNAL(played()), + this,SLOT(auditionStartedData())); + connect(play_audition_player,SIGNAL(stopped()), + this,SLOT(auditionStoppedData())); + } + else { + play_audition_player=NULL; + } + + // + // Transition Timers + // + play_trans_timer=new QTimer(this,"play_trans_timer"); + connect(play_trans_timer,SIGNAL(timeout()), + this,SLOT(transTimerData())); + play_grace_timer=new QTimer(this,"play_grace_timer"); + connect(play_grace_timer,SIGNAL(timeout()), + this,SLOT(graceTimerData())); + + // + // Rescan Timer + // + play_rescan_timer=new QTimer(this,"play_rescan_timer"); + connect(play_rescan_timer,SIGNAL(timeout()), + this,SLOT(rescanEventsData())); + play_rescan_timer->start(LOGPLAY_RESCAN_INTERVAL); +} + + +QString LogPlay::serviceName() const +{ + if(play_svc_name.isEmpty()) { + return play_defaultsvc_name; + } + return play_svc_name; +} + + +void LogPlay::setServiceName(const QString &svcname) +{ + play_svc_name=svcname; +} + + +QString LogPlay::defaultServiceName() const +{ + return play_defaultsvc_name; +} + + +void LogPlay::setDefaultServiceName(const QString &svcname) +{ + play_defaultsvc_name=svcname; +} + + +int LogPlay::card(int channum) const +{ + return play_card[channum]; +} + + +int LogPlay::port(int channum) const +{ + return play_port[channum]; +} + + +RDAirPlayConf::OpMode LogPlay::mode() const +{ + return play_op_mode; +} + + +void LogPlay::setOpMode(RDAirPlayConf::OpMode mode) +{ + if(mode==play_op_mode) { + return; + } + play_op_mode=mode; + UpdateStartTimes(play_line_counter); +} + + +void LogPlay::setLogName(QString name) +{ + if(logName()!=name) { + RDLogEvent::setLogName(name); + emit renamed(); + rdairplay_conf->setCurrentLog(play_id,name.left(name.length()-4)); + } +} + + +void LogPlay::setChannels(int cards[2],int ports[2], + const QString start_rml[2],const QString stop_rml[2]) +{ + for(int i=0;i<2;i++) { + play_card[i]=cards[i]; + play_port[i]=ports[i]; + play_start_rml[i]=start_rml[i]; + play_stop_rml[i]=stop_rml[i]; + rdcae->requestTimescale(play_card[i]); + } +} + + +void LogPlay::setSegueLength(int len) +{ + play_segue_length=len; +} + + +void LogPlay::setNowCart(unsigned cartnum) +{ + play_now_cartnum=cartnum; +} + + +void LogPlay::setNextCart(unsigned cartnum) +{ + play_next_cartnum=cartnum; +} + + +void LogPlay::auditionHead(int line) +{ + RDLogLine *logline=logLine(line); + if((play_audition_player==NULL)||(logline==NULL)) { + return; + } + if(play_audition_line>=0) { + play_audition_player->stop(); + } + play_audition_line=line; + play_audition_head_played=true; + play_audition_player->setCart(logline->cartNumber()); + play_audition_player->play(); +} + + +void LogPlay::auditionTail(int line) +{ + RDLogLine *logline=logLine(line); + if((play_audition_player==NULL)||(logline==NULL)) { + return; + } + if(play_audition_line>=0) { + play_audition_player->stop(); + } + play_audition_line=line; + play_audition_head_played=false; + play_audition_player->setCart(logline->cartNumber()); + int start_pos=logline->endPoint()-play_audition_preroll; + if(start_pos<0) { + start_pos=0; + } + play_audition_player->play(start_pos); +} + + +void LogPlay::auditionStop() +{ + if(play_audition_player==NULL) { + return; + } + if(play_audition_line>=0) { + play_audition_player->stop(); + } +} + + +bool LogPlay::play(int line,RDLogLine::StartSource src, + int mport,bool skip_meta) +{ + QTime current_time=QTime::currentTime(); + RDLogLine *logline; + if((logline=logLine(line))==NULL) { + return false; + } + if((runningEvents(NULL)>=LOGPLAY_MAX_PLAYS)&& + (logline->status()!=RDLogLine::Paused)) { + return false; + } + if(play_op_mode==RDAirPlayConf::Auto) { + skip_meta=false; + } + + // + // Remove any intervening events + // + if(play_line_counter!=line) { + int start_line=-1; + int num_lines; + for(int i=play_line_counter;istatus()==RDLogLine::Scheduled) { + if(start_line==-1) { + start_line=i; + num_lines=1; + } + else { + num_lines++; + } + } + } + } + } + // + // Play it + // + if(!GetNextPlayable(&line,skip_meta,true)) { + return false; + } + + bool ret = false; + if(play_segue_length==0) { + ret = StartEvent(line,RDLogLine::Play,0,src,mport); + } else { + ret = StartEvent(line,RDLogLine::Segue,play_segue_length,src,mport); + } + SetTransTimer(current_time); + return ret; +} + + +bool LogPlay::channelPlay(int mport) +{ + if(nextLine()<0) { + return false; + } + return play(nextLine(),RDLogLine::StartChannel,mport,false); +} + + +bool LogPlay::stop(bool all,int port,int fade) +{ + RDLogLine *logline; + int lines[TRANSPORT_QUANTITY]; + + int n=runningEvents(lines); + for(int i=0;icartType()==RDCart::Audio) + &&(RDPlayDeck *)logline->playDeck()!=NULL + &&logline->portName().toInt()==port ) { + stop(lines[i],fade); + } + } + } + if(n>0) { + return true; + } + return false; +} + + +bool LogPlay::stop(int line,int fade) +{ + RDLogLine *logline; + + if((logline=logLine(line))==NULL) { + return false; + } + switch(logline->cartType()) { + case RDCart::Audio: + if(((RDPlayDeck *)logline->playDeck())==NULL) { + return false; + } + ((RDPlayDeck *)logline->playDeck())->stop(fade,RD_FADE_DEPTH); + return true; + break; + + case RDCart::Macro: + play_macro_deck->stop(); + break; + + case RDCart::All: + break; + } + return false; +} + + +bool LogPlay::channelStop(int mport) +{ + RDLogLine *logline; + int lines[TRANSPORT_QUANTITY]; + bool ret=false; + + int n=runningEvents(lines); + for(int i=0;icartType()==RDCart::Audio) + &&((RDPlayDeck *)logline->playDeck()!=NULL)) { + if(((RDPlayDeck *)logline->playDeck())->channel()==mport) { + stop(lines[i]); + ret=true; + } + } + } + return ret; +} + + +bool LogPlay::pause(int line) +{ + RDLogLine *logline; + + if((logline=logLine(line))==NULL) { + return false; + } + switch(logline->cartType()) { + case RDCart::Audio: + if(logline->playDeck()==NULL) { + return false; + } + ((RDPlayDeck *)logline->playDeck())->pause(); + return true; + break; + + case RDCart::Macro: + case RDCart::All: + break; + } + return false; +} + + +void LogPlay::duckVolume(int level,int fade,int mport) +{ + RDLogLine *logline; + int lines[TRANSPORT_QUANTITY]; + + if(mport==-1 || mport==1) { + play_duck_volume_port1=level; + } + if(mport==-1 || mport==2) { + play_duck_volume_port2=level; + } + int n=runningEvents(lines); + for(int i=0;icartType()==RDCart::Audio) + && (RDPlayDeck *)logline->playDeck()!=NULL + && ((logline->portName().toInt()==mport) || mport<1) ) { + ((RDPlayDeck *)logline->playDeck())->duckVolume(level,fade); + } + } +} + + + +void LogPlay::makeNext(int line,bool refresh_status) +{ + play_next_line=line; + if(refresh_status) { + RefreshEvents(line,LOGPLAY_LOOKAHEAD_EVENTS); + } + SendNowNext(); + SetTransTimer(); + UpdatePostPoint(); + emit nextEventChanged(line); + emit transportChanged(); +} + + +void LogPlay::load() +{ + int lines[TRANSPORT_QUANTITY]; + int running=0; + + play_duck_volume_port1=0; + play_duck_volume_port2=0; + + // + // Remove All Idle Events + // + if((running=runningEvents(lines))==0) { + remove(0,size(),false); + } + else { + if(lines[running-1]<(size()-1)) { + remove(lines[running-1]+1,size()-lines[running-1]-1,false); + } + for(int i=running-2;i>0;i--) { + remove(lines[i-1]+1,lines[i]-lines[i-1]-1,false); + } + if(lines[0]!=0) { + remove(0,lines[0],false); + } + } + + // + // Load Events + // + RDLogEvent::load(); + play_rescan_pos=0; + if(play_timescaling_available) { + for(int i=0;isetTimescalingActive(logLine(i)->enforceLength()); + } + } + RefreshEvents(0,size()); + RDLog *log=new RDLog(logName().left(logName().length()-4)); + play_svc_name=log->service(); + delete log; + play_line_counter=0; + play_next_line=0; + UpdateStartTimes(0); + emit reloaded(); + SetTransTimer(); + emit transportChanged(); + UpdatePostPoint(); + if((running>0)&&(size()>running)) { + makeNext(running); + } + + // + // Update Refreshability + // + if(play_log!=NULL) { + delete play_log; + } + play_log=new RDLog(logName().left(logName().length()-4)); + play_link_datetime=play_log->linkDatetime(); + play_modified_datetime=play_log->modifiedDatetime(); + if(play_refreshable) { + play_refreshable=false; + emit refreshabilityChanged(play_refreshable); + } +} + + +void LogPlay::append(const QString &log_name) +{ + int old_size=size(); + + if(size()==0) { + setLogName(RDLog::tableName(log_name)); + load(); + return; + } + + RDLogEvent::append(log_name); + if(play_timescaling_available) { + for(int i=old_size;isetTimescalingActive(logLine(i)->enforceLength()); + } + } + RefreshEvents(old_size,size()-old_size); + UpdateStartTimes(old_size); + emit reloaded(); + SetTransTimer(); + emit transportChanged(); + UpdatePostPoint(); +} + + +bool LogPlay::refresh() +{ + RDLogLine *s; + RDLogLine *d; + int prev_line; + int prev_id; + int next_line=-1; + int next_id=-1; + int current_id=-1; + int lines[TRANSPORT_QUANTITY]; + int running; + + if(play_macro_running) { + play_refresh_pending=true; + return true; + } + emit refreshStatusChanged(true); + if((size()==0)||(play_log==NULL)) { + emit refreshStatusChanged(false); + return true; + } + + // + // Load the Updated Log + // + RDLogEvent *e=new RDLogEvent(); + e->setLogName(logName()); + e->load(); + play_modified_datetime=play_log->modifiedDatetime(); + + // + // Get the Next Event + // + if(nextEvent()!=NULL) { //End of the log? + next_id=nextEvent()->id(); + } + + // + // Get Running Events + // + running=runningEvents(lines); + for(int i=0;iid(); + } + } + if(running>0 && next_id==-1) { //Last Event of Log Running? + current_id=logLine(lines[running-1])->id(); + } + + // + // Pass 1: Finished or Active Events + // + for(int i=0;istatus()!=RDLogLine::Scheduled) { + if((s=e->loglineById(d->id()))!=NULL) { + s->incrementPass(); + } + d->incrementPass(); + } + } + + // + // Pass 2: Purge Deleted Events + // + for(int i=size()-1;i>=0;i--) { + if(logLine(i)->pass()==0) { + remove(i,1,false,true); + } + } + + // + // Pass 3: Add New Events + // + for(int i=0;isize();i++) { + s=e->logLine(i); + if(s->pass()==0) { + if((prev_line=(i-1))<0) { // First Event + insert(0,s,false,true); + } + else { + prev_id=e->logLine(prev_line)->id(); + insert(lineById(prev_id)+1,s,false,true); + } + } + else { + loglineById(s->id())->incrementPass(); + } + } + + // + // Pass 4: Delete Orphaned Past Playouts + // + for(int i=size()-1;i>=0;i--) { + d=logLine(i); + if((d->status()==RDLogLine::Finished)&&(d->pass()!=2)) { + remove(i,1,false,true); + } + } + + // + // Restore Next Event + // + if(current_id!=-1 && e->loglineById(current_id)!=NULL) { //Make Next after currently playing cart + if((next_line=lineById(current_id))>=0) { + makeNext(next_line+1,false); + } + } + else { + if((next_line=lineById(next_id))>=0) { + makeNext(next_line,false); + } + } + + // + // Clean Up + // + delete e; + for(int i=0;iclearPass(); + } + RefreshEvents(0,size()); + UpdateStartTimes(next_line); + UpdatePostPoint(); + SetTransTimer(); + emit transportChanged(); + emit reloaded(); + if(!play_refreshable) { + play_refreshable=false; + emit refreshabilityChanged(play_refreshable); + } + + emit refreshStatusChanged(false); + + return true; +} + + +void LogPlay::save(int line) +{ + RDLogEvent::save(line); + if(play_log!=NULL) { + delete play_log; + } + play_log=new RDLog(logName().left(logName().length()-4)); + QDateTime current_datetime= + QDateTime(QDate::currentDate(),QTime::currentTime()); + play_log->setModifiedDatetime(current_datetime); + play_modified_datetime=current_datetime; + if(play_refreshable) { + play_refreshable=false; + emit refreshabilityChanged(play_refreshable); + } +} + + +void LogPlay::clear() +{ + setLogName(""); + int start_line=0; + play_duck_volume_port1=0; + play_duck_volume_port2=0; + while(ClearBlock(start_line++)); + play_svc_name=play_defaultsvc_name; + play_rescan_pos=0; + if(play_log!=NULL) { + delete play_log; + play_log=NULL; + } + SetTransTimer(); + UpdatePostPoint(); + if(play_refreshable) { + play_refreshable=false; + emit refreshabilityChanged(play_refreshable); + } + emit reloaded(); +} + + +void LogPlay::insert(int line,int cartnum,RDLogLine::TransType next_type, + RDLogLine::TransType type) +{ + RDLogLine *logline; + int lines[TRANSPORT_QUANTITY]; + RDPlayDeck *playdeck; + int mod_line=-1; + + if(line<(size()-1)) { + if(logLine(line)->hasCustomTransition()) { + mod_line=line+1; + } + } + + int running=runningEvents(lines); + for(int i=0;iplayDeck())!=NULL) { + if((playdeck->id()>=0)&& + (playdeck->id()>=line)) { + playdeck->setId(playdeck->id()+1); + } + } + } + } + if(play_macro_deck->line()>=0) { + play_macro_deck->setLine(play_macro_deck->line()+1); + } + RDLogEvent::insert(line,1); + if((logline=logLine(line))==NULL) { + RDLogEvent::remove(line,1); + return; + } + if(nextLine()>line) { + makeNext(nextLine()+1); + } + if(nextLine()<0) { + play_next_line=line; + } + logline->loadCart(cartnum,next_type,play_id,play_timescaling_available, + rdairplay_conf->defaultTransType()); + logline-> + setTimescalingActive(play_timescaling_available&&logline->enforceLength()); + UpdateStartTimes(line); + emit inserted(line); + UpdatePostPoint(); + if(mod_line>=0) { + emit modified(mod_line); + } + emit transportChanged(); + SetTransTimer(); + UpdatePostPoint(); +} + + +void LogPlay::insert(int line,RDLogLine *l,bool update,bool preserv_custom_transition) +{ + RDLogLine *logline; + int lines[TRANSPORT_QUANTITY]; + RDPlayDeck *playdeck; + int mod_line=-1; + + if(line<(size()-1)) { + if(logLine(line)->hasCustomTransition()) { + mod_line=line+1; + } + } + + int running=runningEvents(lines); + for(int i=0;iplayDeck())!=NULL) { + if((playdeck->id()>=0)&& + (playdeck->id()>=line)) { + playdeck->setId(playdeck->id()+1); + } + } + } + } + if(play_macro_deck->line()>=0) { + play_macro_deck->setLine(play_macro_deck->line()+1); + } + RDLogEvent::insert(line,1,preserv_custom_transition); + if((logline=logLine(line))==NULL) { + RDLogEvent::remove(line,1); + return; + } + *logline=*l; + if(nextLine()>line && update) { + makeNext(nextLine()+1); + } + if(nextLine()<0) { + play_next_line=line; + } + logline-> + setTimescalingActive(play_timescaling_available&&logline->enforceLength()); + if(update) { + UpdateStartTimes(line); + emit inserted(line); + UpdatePostPoint(); + if(mod_line>=0) { + emit modified(mod_line); + } + emit transportChanged(); + SetTransTimer(); + UpdatePostPoint(); + } +} + + +void LogPlay::remove(int line,int num_lines,bool update,bool preserv_custom_transition) +{ + RDPlayDeck *playdeck; + RDLogLine *logline; + int mod_line=-1; + + if((num_lines==0)||(line<0)||(line>=size())) { + return; + } + if((line+num_lines)<(size()-1)) { + if(logLine(line+num_lines)->hasCustomTransition()) { + mod_line=line; + } + } + + for(int i=line;i<(line+num_lines);i++) { + if((logline=logLine(i))!=NULL) { + if((playdeck=(RDPlayDeck *)logline->playDeck())!=NULL) { + playdeck->clear(); + FreePlayDeck(playdeck); + } + } + } + + int lines[TRANSPORT_QUANTITY]; + + if(update) { + emit removed(line,num_lines,false); + } + int running=runningEvents(lines); + for(int i=0;itype()==RDLogLine::Cart) { + playdeck=(RDPlayDeck *)logline->playDeck(); + if((playdeck->id()>=0)&&(playdeck->id()>line)) { + playdeck->setId(playdeck->id()-num_lines); + } + } + } + } + if(play_macro_deck->line()>0) { + play_macro_deck->setLine(play_macro_deck->line()-num_lines); + } + + RDLogEvent::remove(line,num_lines,preserv_custom_transition); + if(update) { + if(nextLine()>line) { + makeNext(nextLine()-num_lines); + } + UpdateStartTimes(line); + if(size()==0) { + emit reloaded(); + } + if(mod_line>=0) { + emit modified(mod_line); + } + emit transportChanged(); + SetTransTimer(); + UpdatePostPoint(); + } +} + + +void LogPlay::move(int from_line,int to_line) +{ + int offset=0; + int lines[TRANSPORT_QUANTITY]; + RDLogLine *logline; + RDPlayDeck *playdeck; + int mod_line[2]={-1,-1}; + + if(from_line<(size()-1)) { + if(logLine(from_line+1)->hasCustomTransition()) { + if(from_linehasCustomTransition()) { + if(to_line>to_line) { + mod_line[1]=to_line; + } + else { + mod_line[1]=to_line+1; + } + } + } + + emit removed(from_line,1,true); + int running=runningEvents(lines,false); + for(int i=0;iplayDeck(); + if(playdeck->id()>=0) { + if((playdeck->id()>from_line)&& + (playdeck->id()<=to_line)) { + playdeck->setId(playdeck->id()-1); + } + else { + if((playdeck->id()id()>to_line)) { + playdeck->setId(playdeck->id()+1); + } + } + } + } + } + if(play_macro_deck->line()>=0) { + if((play_macro_deck->line()>from_line)&& + (play_macro_deck->line()<=to_line)) { + play_macro_deck->setLine(play_macro_deck->line()-1); + } + else { + if((play_macro_deck->line()line()>to_line)) { + play_macro_deck->setLine(play_macro_deck->line()+1); + } + } + } + + if(to_line>from_line) { + offset=1; + } + RDLogEvent::move(from_line,to_line); + if(from_line>to_line) { + UpdateStartTimes(to_line); + } + else { + UpdateStartTimes(from_line); + } + SetTransTimer(); + UpdatePostPoint(); + emit inserted(to_line); + for(int i=0;i<2;i++) { + if(mod_line[i]>=0) { + emit modified(mod_line[i]); + } + } + if((nextLine()>from_line)&&(nextLine()<=(to_line+offset))) { + makeNext(nextLine()-1); + } + else { + if((nextLine()to_line)) { + makeNext(nextLine()+1); + } + else { + emit transportChanged(); + } + } +} + + +void LogPlay::copy(int from_line,int to_line,RDLogLine::TransType type) +{ + RDLogLine *logline; + + if((logline=logLine(from_line))==NULL) { + return; + } + insert(to_line,logline->cartNumber(),RDLogLine::Play,type); +} + + +int LogPlay::topLine() +{ + for(int i=0;istatus()==RDLogLine::Playing)|| + (logLine(i)->status()==RDLogLine::Finishing)|| + (logLine(i)->status()==RDLogLine::Paused)) { + return i; + } + } + return nextLine(); +} + + +int LogPlay::currentLine() const +{ + return play_line_counter; +} + + +int LogPlay::nextLine() const +{ + return play_next_line; +} + + +int LogPlay::nextLine(int line) +{ + int lines[TRANSPORT_QUANTITY]; + + // FIXME: Do we really need this codeblock? + transportEvents(lines); + for(int i=0;i<(TRANSPORT_QUANTITY-1);i++) { + if(line==lines[i]) { + for(int j=i+1;jstatus()==RDLogLine::Scheduled) { + return lines[j]; + } + } + } + } + // End of FIXME + + for(int i=line+1;istatus()==RDLogLine::Scheduled) { + return i; + } + } + return -1; +} + + +RDLogLine *LogPlay::nextEvent() +{ + if(play_next_line<0) { + return NULL; + } + return logLine(play_next_line); +} + + +RDLogLine::TransType LogPlay::nextTrans() +{ + RDLogLine *logline=nextEvent(); + if(logline==NULL) { + return RDLogLine::Stop; + } + return logline->transType(); +} + + +RDLogLine::TransType LogPlay::nextTrans(int line) +{ + RDLogLine *logline; + +// if((logline=logLine(nextLine(line)))!=NULL) { + + int next_line; + next_line=nextLine(line); + logline=logLine(next_line); + if(logline!=NULL) { + return logline->transType(); + } + return RDLogLine::Stop; +} + + +void LogPlay::transportEvents(int line[]) +{ + int count=0; + int start=topLine(); + RDLogLine *logline; + + for(int i=0;istatus()) { + case RDLogLine::Scheduled: + if(countstatus()==RDLogLine::Playing)|| + (logLine(i)->status()==RDLogLine::Finishing)|| + (logLine(i)->status()==RDLogLine::Paused)) { + events[count++]=i; + if(count==TRANSPORT_QUANTITY) { + break; + } + } + } + } + else { + for(int i=0;istatus()==RDLogLine::Playing)|| + (logLine(i)->status()==RDLogLine::Finishing)) { + events[count++]=i; + if(count==TRANSPORT_QUANTITY) { + break; + } + } + } + } + if (!lines){ + return count; + } + // + // Sort 'Em (by start time) + // + while(changed) { + changed=false; + for(int i=0;i<(count-1);i++) { + if(logLine(events[table[i]])->startTime(RDLogLine::Initial)> + logLine(events[table[i+1]])->startTime(RDLogLine::Initial)) { + int event=table[i]; + table[i]=table[i+1]; + table[i+1]=event; + changed=true; + } + } + } + + // + // Write out the table + // + for(int i=0;iloadCart(logline->cartNumber(),RDLogLine::Play, + play_id,logline->timescalingActive()); + } + else { + logline->loadCart(logline->cartNumber(),next_logline->transType(), + play_id,logline->timescalingActive()); + } + } + emit modified(line); + int lines[TRANSPORT_QUANTITY] = {-1}; + int count; + count = runningEvents(lines,false); + if (count > 0){ + line=lines[count-1]; + } + UpdatePostPoint(); + emit transportChanged(); +} + + +RDLogLine::Status LogPlay::status(int line) +{ + RDLogLine *logline; + + if((logline=logLine(line))==NULL) { + return RDLogLine::Scheduled; + } + return logline->status(); +} + + +QTime LogPlay::startTime(int line) +{ + RDLogLine *logline; + + if((logline=logLine(line))==NULL) { + return QTime(); + } + switch(logline->cartType()) { + case RDCart::Audio: + if(((RDPlayDeck *)logline->playDeck())==NULL) { + return logline->startTime(RDLogLine::Predicted); + } + return logline->startTime(RDLogLine::Actual); + break; + + case RDCart::Macro: + case RDCart::All: + return logline->startTime(RDLogLine::Predicted); + break; + } + return QTime(); +} + + +QTime LogPlay::nextStop() const +{ + return play_next_stop; +} + + +bool LogPlay::running(bool include_paused) +{ + if(runningEvents(NULL,include_paused)==0) { + return false; + } + return true; +} + + +void LogPlay::resync() +{ + SetTransTimer(); +} + + +void LogPlay::transTimerData() +{ + int lines[TRANSPORT_QUANTITY]; + RDLogLine *logline=NULL; + int grace=0; + int trans_line=play_trans_line; + + if(play_grace_timer->isActive()) { + play_grace_timer->stop(); + } + + if(play_op_mode==RDAirPlayConf::Auto) { + if(!GetNextPlayable(&play_trans_line,false)) { + SetTransTimer(); + return; + } + if((logline=logLine(play_trans_line))!=NULL) { + grace=logline->graceTime(); + } + if((runningEvents(lines)==0)) { + makeNext(play_trans_line); + if(logline->transType()!=RDLogLine::Stop || grace>=0) { + StartEvent(trans_line,RDLogLine::Play,0,RDLogLine::StartTime); + } + } + else { + if(logline==NULL) { + LogLine(RDConfig::LogNotice," invalid logline"); + SetTransTimer(); + return; + } + switch(logline->graceTime()) { + case 0: + makeNext(play_trans_line); + if(play_trans_length==0) { + StartEvent(trans_line,RDLogLine::Play,0,RDLogLine::StartTime); + } + else { + StartEvent(trans_line,RDLogLine::Segue,play_trans_length, + RDLogLine::StartTime); + } + break; + + case -1: + makeNext(play_trans_line); + break; + + default: + if(logline->transType()==RDLogLine::Stop) { + logline->setTransType(RDLogLine::Play); + } + logline->setStartTime(RDLogLine::Predicted,logline-> + startTime(RDLogLine::Predicted). + addMSecs(grace)); + play_grace_line=play_trans_line; + play_grace_timer->start(grace,true); + break; + } + } + } + SetTransTimer(); +} + + +void LogPlay::graceTimerData() +{ + int lines[TRANSPORT_QUANTITY]; + int line=play_grace_line; + + if(play_op_mode==RDAirPlayConf::Auto) { + if(!GetNextPlayable(&line,false)) { + SetTransTimer(); + return; + } + if(line!=play_grace_line) { + return; + } + if((runningEvents(lines)==0)) { + makeNext(play_grace_line); + StartEvent(play_grace_line,RDLogLine::Play,0,RDLogLine::StartTime); + } + else { + makeNext(play_grace_line); + if(play_trans_length==0) { + StartEvent(play_grace_line,RDLogLine::Play,0,RDLogLine::StartTime); + } + else { + StartEvent(play_grace_line,RDLogLine::Segue,play_trans_length, + RDLogLine::StartTime); + } + } + } +} + + +void LogPlay::playStateChangedData(int id,RDPlayDeck::State state) +{ +#ifdef SHOW_SLOTS + printf("playStateChangedData(%d)\n",id); +#endif + switch(state) { + case RDPlayDeck::Playing: + Playing(id); + break; + + case RDPlayDeck::Paused: + Paused(id); + break; + + case RDPlayDeck::Stopping: + Stopping(id); + break; + + case RDPlayDeck::Stopped: + Stopped(id); + break; + + case RDPlayDeck::Finished: + Finished(id); + break; + } +} + + +void LogPlay::onairFlagChangedData(bool state) +{ + play_onair_flag=state; +} + + +void LogPlay::segueStartData(int id) +{ +#ifdef SHOW_SLOTS + printf("segueStartData(%d)\n",id); +#endif + int line=GetLineById(id); + RDLogLine *logline; + RDLogLine *next_logline=nextEvent(); + if(next_logline==NULL) { + return; + } + if((logline=logLine(line))==NULL) { + return; + } + if((play_op_mode==RDAirPlayConf::Auto)&& + ((next_logline->transType()==RDLogLine::Segue))&& + (logline->status()==RDLogLine::Playing)&& + (logline->id()!=-1)) { + if(!GetNextPlayable(&play_next_line,false)) { + return; + } + StartEvent(play_next_line,next_logline->transType(), + logline->segueTail(next_logline->transType()), + RDLogLine::StartSegue,-1, + logline->segueTail(next_logline->transType())); + SetTransTimer(); + } +} + + +void LogPlay::segueEndData(int id) +{ +#ifdef SHOW_SLOTS + printf("segueEndData(%d)\n",id); +#endif + + int line=GetLineById(id); + RDLogLine *logline; + if((logline=logLine(line))==NULL) { + return; + } + if((play_op_mode==RDAirPlayConf::Auto)&& + (logline->status()==RDLogLine::Finishing)) { + ((RDPlayDeck *)logline->playDeck())->stop(); + CleanupEvent(id); + UpdateStartTimes(line); + LogTraffic(serviceName(),logName().left(logName().length()-4),logline, + (RDLogLine::PlaySource)(play_id+1), + RDAirPlayConf::TrafficFinish,play_onair_flag); + emit stopped(line); + emit transportChanged(); + } +} + + +void LogPlay::talkStartData(int id) +{ +#ifdef SHOW_SLOTS + printf("talkStartData(%d)\n",id); +#endif +} + + +void LogPlay::talkEndData(int id) +{ +#ifdef SHOW_SLOTS + printf("talkEndData(%d)\n",id); +#endif +} + + +void LogPlay::positionData(int id,int pos) +{ + int line=GetLineById(id); + + RDLogLine *logline; + if((logline=logLine(line))==NULL) { + return; + } + if(pos>logline->effectiveLength()) { + LogLine(RDConfig::LogWarning,QString().sprintf("*** position out of bounds on signal: Line: %d Cart: %d Pos: %d ***",line,logline->cartNumber(),logline->playPosition())); + return; + } + logline->setPlayPosition(pos); + emit position(line,pos); +} + + +void LogPlay::macroStartedData() +{ +#ifdef SHOW_SLOTS + printf("macroStartedData()\n"); +#endif + play_macro_running=true; + int line=play_macro_deck->line(); + RDLogLine *logline; + if((logline=logLine(line))==NULL) { + return; + } + logline->setStatus(RDLogLine::Playing); + logline-> + setStartTime(RDLogLine::Initial, + QTime::currentTime().addMSecs(rdstation_conf->timeOffset())); + UpdateStartTimes(line); + emit played(line); + UpdatePostPoint(); + emit transportChanged(); +} + + +void LogPlay::macroFinishedData() +{ +#ifdef SHOW_SLOTS + printf("macroFinishedData()\n"); +#endif + int line=play_macro_deck->line(); + play_macro_deck->clear(); + FinishEvent(line); + RDLogLine *logline; + if((logline=logLine(line))!=NULL) { + logline->setStatus(RDLogLine::Finished); + LogTraffic(serviceName(),logName().left(logName().length()-4),logline, + (RDLogLine::PlaySource)(play_id+1),RDAirPlayConf::TrafficMacro, + play_onair_flag); + } + play_macro_running=false; + UpdatePostPoint(); + if(play_refresh_pending) { + refresh(); + play_refresh_pending=false; + } + emit transportChanged(); +} + + +void LogPlay::macroStoppedData() +{ +#ifdef SHOW_SLOTS + printf("macroStoppedData()\n"); +#endif + int line=play_macro_deck->line(); + play_macro_deck->clear(); + RDLogLine *logline; + if((logline=logLine(line))!=NULL) { + logline->setStatus(RDLogLine::Finished); + LogTraffic(serviceName(),logName().left(logName().length()-4),logline, + (RDLogLine::PlaySource)(play_id+1),RDAirPlayConf::TrafficMacro, + play_onair_flag); + } + UpdatePostPoint(); + emit transportChanged(); +} + + +void LogPlay::timescalingSupportedData(int card,bool state) +{ + if(card>=0) { + play_timescaling_supported[card]=state; + if(play_timescaling_supported[play_card[0]]&& + play_timescaling_supported[play_card[1]]) { + play_timescaling_available=true; + } + else { + play_timescaling_available=false; + } + } + else { + play_timescaling_available=false; + } +} + + +void LogPlay::rescanEventsData() +{ + int start_pos=play_rescan_pos; + int start_size=LOGPLAY_RESCAN_SIZE; + if((start_pos+start_size)>=size()) { + start_size=size()-start_pos; + play_rescan_pos=0; + } + else { + play_rescan_pos+=LOGPLAY_RESCAN_SIZE; + } + RefreshEvents(start_pos,start_size); +} + + +void LogPlay::auditionStartedData() +{ + if(play_audition_head_played) { + emit auditionHeadPlayed(play_audition_line); + } + else { + emit auditionTailPlayed(play_audition_line); + } +} + + +void LogPlay::auditionStoppedData() +{ + int line=play_audition_line; + play_audition_line=-1; + emit auditionStopped(line); +} + + +bool LogPlay::StartEvent(int line,RDLogLine::TransType trans_type, + int trans_length,RDLogLine::StartSource src,int mport,int duck_length) +{ + int running; + int lines[TRANSPORT_QUANTITY]; + RDLogLine *logline; + RDLogLine *next_logline; + RDPlayDeck *playdeck; + int card; + int port; + int aport; + bool was_paused=false; + + if((logline=logLine(line))==NULL) { + return false; + } + if(logline->id()<0) { + return false; + } + + // + // Transition running events + // + running=runningEvents(lines); + if(play_op_mode!=RDAirPlayConf::Manual) { + switch(trans_type) { + case RDLogLine::Play: + for(int i=0;itype()==RDLogLine::Cart)|| + (logLine(lines[i])->type()==RDLogLine::Macro))&& + (logLine(lines[i])->status()!=RDLogLine::Paused)) { + switch(logLine(lines[i])->cartType()) { + case RDCart::Audio: + ((RDPlayDeck *)logLine(lines[i])->playDeck())->stop(); + break; + + case RDCart::Macro: + play_macro_deck->stop(); + break; + + case RDCart::All: + break; + } + } + } + } + break; + + case RDLogLine::Segue: + for(int i=0;istatus()==RDLogLine::Playing) { + if(((prev_logline->type()==RDLogLine::Cart)|| + (prev_logline->type()==RDLogLine::Macro))&& + (prev_logline->status()!=RDLogLine::Paused)) { + switch(logLine(lines[i])->cartType()) { + case RDCart::Audio: + prev_logline->setStatus(RDLogLine::Finishing); + ((RDPlayDeck *)prev_logline->playDeck())-> + stop(trans_length); + break; + + case RDCart::Macro: + play_macro_deck->stop(); + break; + + case RDCart::All: + break; + } + } + } + } + } + break; + + default: + break; + } + } + + // + // Clear Unplayed Custom Transition + // + if(logLine(line-1)!=NULL) { + if(logLine(line-1)->status()==RDLogLine::Scheduled) { + logLine(line-1)->clearTrackData(RDLogLine::TrailingTrans); + } + } + + // + // Start Playout + // + logline->setStartSource(src); + switch(logline->type()) { + case RDLogLine::Cart: + if(!StartAudioEvent(line)) { + rdairplay_conf->setLogCurrentLine(play_id,nextLine()); + return false; + } + aport=GetNextChannel(mport,&card,&port); + playdeck=(RDPlayDeck *)logline->playDeck(); + playdeck->setCard(card); + playdeck->setPort(port); + playdeck->setChannel(aport); + logline->setPauseCard(card); + logline->setPausePort(port); + logline->setPortName(GetPortName(playdeck->card(), + playdeck->port())); + if(logline->portName().toInt()==2){ + playdeck->duckVolume(play_duck_volume_port2,0); + } + else { + playdeck->duckVolume(play_duck_volume_port1,0); + } + + if(!playdeck->setCart(logline,logline->status()!=RDLogLine::Paused)) { + // No audio to play, so fake it + logline->setZombified(true); + playStateChangedData(playdeck->id(),RDPlayDeck::Playing); + logline->setStatus(RDLogLine::Playing); + playStateChangedData(playdeck->id(),RDPlayDeck::Finished); + logline->setStatus(RDLogLine::Finished); + LogLine(RDConfig::LogErr,QString(). + sprintf("LogPlay::StartEvent(): no audio,CUT=%s", + (const char *)logline->cutName())); + rdairplay_conf->setLogCurrentLine(play_id,nextLine()); + return false; + } + emit modified(line); + logline->setCutNumber(playdeck->cut()->cutNumber()); + logline->setEvergreen(playdeck->cut()->evergreen()); + if(play_timescaling_available&&logline->enforceLength()) { + logline->setTimescalingActive(true); + } + RDSetMixerOutputPort(play_cae,playdeck->card(), + playdeck->stream(), + playdeck->port()); + if((int)logline->playPosition()>logline->effectiveLength()) { + LogLine(RDConfig::LogWarning,QString().sprintf("*** position out of bounds: Line: %d Cart: %d Pos: %d ***",line,logline->cartNumber(),logline->playPosition())); + logline->setPlayPosition(0); + } + playdeck->play(logline->playPosition(),-1,-1,duck_length); + if(logline->status()==RDLogLine::RDLogLine::Paused) { + logline-> + setStartTime(RDLogLine::Actual,playdeck->startTime()); + was_paused=true; + } + else { + logline-> + setStartTime(RDLogLine::Initial,playdeck->startTime()); + } + logline->setStatus(RDLogLine::Playing); + if(!play_start_rml[aport].isEmpty()) { + rdevent_player-> + exec(logline->resolveWildcards(play_start_rml[aport])); + } + emit channelStarted(play_id,playdeck->channel(), + playdeck->card(),playdeck->port()); + LogLine(RDConfig::LogInfo,QString().sprintf( + "started audio cart: Line: %d Cart: %u Cut: %u Pos: %d Card: %d Stream: %d Port: %d", + line,logline->cartNumber(), + playdeck->cut()->cutNumber(), + logline->playPosition(), + playdeck->card(), + playdeck->stream(), + playdeck->port())); + + // + // Assign Next Event + // + if((play_next_line>=0)&&(!was_paused)) { + play_next_line=line+1; + if((next_logline=logLine(play_next_line))!=NULL) { + if(next_logline->id()==-2) { + play_start_next=false; + } + } + emit nextEventChanged(play_next_line); + } + break; + + case RDLogLine::Macro: + // + // Assign Next Event + // + if(play_next_line>=0) { + play_next_line=line+1; + if((next_logline=logLine(play_next_line))!=NULL) { + if(logline->id()==-2) { + play_start_next=false; + } + if(logline->forcedStop()) { + next_logline->setTransType(RDLogLine::Stop); + } + } + } + if(logline->asyncronous()) { + RDMacro *rml=new RDMacro(); + rml->setCommand(RDMacro::EX); + QHostAddress addr; + addr.setAddress("127.0.0.1"); + rml->setAddress(addr); + rml->setRole(RDMacro::Cmd); + rml->setEchoRequested(false); + rml->setArgQuantity(1); + rml->setArg(0,logline->cartNumber()); + rdripc->sendRml(rml); + delete rml; + emit played(line); + logline->setStartTime(RDLogLine::Actual,QTime::currentTime()); + logline->setStatus(RDLogLine::Finished); + LogTraffic(serviceName(),logName().left(logName().length()-4), + logline,(RDLogLine::PlaySource)(play_id+1), + RDAirPlayConf::TrafficMacro,play_onair_flag); + FinishEvent(line); + emit transportChanged(); + LogLine(RDConfig::LogInfo,QString(). + sprintf("asynchronously executed macro cart: Line: %d Cart: %u", + line,logline->cartNumber())); + } + else { + play_macro_deck->load(logline->cartNumber()); + play_macro_deck->setLine(line); + LogLine(RDConfig::LogInfo,QString(). + sprintf("started macro cart: Line: %d Cart: %u", + line,logline->cartNumber())); + play_macro_deck->exec(); + } + break; + + case RDLogLine::Marker: + case RDLogLine::Track: + case RDLogLine::MusicLink: + case RDLogLine::TrafficLink: + // + // Assign Next Event + // + if(play_next_line>=0) { + play_next_line=line+1; + if((next_logline=logLine(play_next_line))!=NULL) { + if(logLine(play_next_line)->id()==-2) { + play_start_next=false; + } + } + else { + play_start_next=false; + } + } + + // + // Skip Past + // + logline->setStatus(RDLogLine::Finished); + UpdateStartTimes(line); + emit played(line); + FinishEvent(line); + emit nextEventChanged(play_next_line); + break; + + case RDLogLine::Chain: + // + // Assign Next Event + // + if(play_next_line>0) { + play_next_line=line+1; + if((next_logline=logLine(play_next_line))!=NULL) { + if(logLine(play_next_line)->id()==-2) { + play_start_next=false; + } + } + else { + play_start_next=false; + } + } + if(GetTransType(logline->markerLabel(),0)!=RDLogLine::Stop) { + play_macro_deck-> + load(QString().sprintf("LL %d %s -2!", + play_id+1, + (const char *)logline->markerLabel())); + } + else { + play_macro_deck-> + load(QString().sprintf("LL %d %s -2!", + play_id+1, + (const char *)logline->markerLabel())); + } + play_macro_deck->setLine(line); + play_macro_deck->exec(); + LogLine(RDConfig::LogInfo,QString(). + sprintf("chained to log: Line: %d Log: %s", + line, + (const char *)logline->markerLabel())); + break; + + default: + break; + } + while((play_next_linestate()==RDLogLine::Ok)|| + (logline->state()==RDLogLine::NoCart)|| + (logline->state()==RDLogLine::NoCut)) { + rdairplay_conf->setLogCurrentLine(play_id,nextLine()); + return true; + } + play_next_line++; + } + play_next_line=-1; + rdairplay_conf->setLogCurrentLine(play_id,nextLine()); + return true; +} + + +bool LogPlay::StartAudioEvent(int line) +{ + RDLogLine *logline; + RDPlayDeck *playdeck=NULL; + + if((logline=logLine(line))==NULL) { + return false; + } + + // + // Get a Play Deck + // + if(logline->status()!=RDLogLine::Paused) { + logline->setPlayDeck(GetPlayDeck()); + if(logline->playDeck()==NULL) { + return false; + } + playdeck=(RDPlayDeck *)logline->playDeck(); + playdeck->setId(line); + } + else { + playdeck=(RDPlayDeck *)logline->playDeck(); + } + + // + // Assign Mappings + // + connect(playdeck,SIGNAL(stateChanged(int,RDPlayDeck::State)), + this,SLOT(playStateChangedData(int,RDPlayDeck::State))); + connect(playdeck,SIGNAL(position(int,int)), + this,SLOT(positionData(int,int))); + connect(playdeck,SIGNAL(segueStart(int)), + this,SLOT(segueStartData(int))); + connect(playdeck,SIGNAL(segueEnd(int)), + this,SLOT(segueEndData(int))); + connect(playdeck,SIGNAL(talkStart(int)), + this,SLOT(talkStartData(int))); + connect(playdeck,SIGNAL(talkEnd(int)), + this,SLOT(talkEndData(int))); + + return true; +} + + +void LogPlay::CleanupEvent(int id) +{ + int line=GetLineById(id); + bool top_changed=false; + RDLogLine *logline; + RDPlayDeck *playdeck=NULL; + if((logline=logLine(line))==NULL) { + return; + } + playdeck=(RDPlayDeck *)logline->playDeck(); + if(playdeck->cut()==NULL) { + LogLine(RDConfig::LogErr,QString(). + sprintf("event failed: Line: %d Cart: %u",line, + logline->cartNumber())); + } + else { + LogLine(RDConfig::LogInfo,QString(). + sprintf("finished event: Line: %d Cart: %u Cut: %u Card: %d Stream: %d Port: %d", + line,logline->cartNumber(), + playdeck->cut()->cutNumber(), + playdeck->card(), + playdeck->stream(),playdeck->port())); + } + RDLogLine *prev_logline; + if((prev_logline=logLine(line-1))==NULL) { + } + else { + if((line==0)||(prev_logline->status()!=RDLogLine::Playing)) { + play_line_counter++; + top_changed=true; + } + } + logline->setStatus(RDLogLine::Finished); + FreePlayDeck(playdeck); + logline->setPlayDeck(NULL); + UpdatePostPoint(); + if(top_changed) { + emit topEventChanged(play_line_counter); + } +} + + +void LogPlay::UpdateStartTimes(int line) +{ + QTime time; + QTime new_time; + QTime end_time; + QTime prev_time; + QTime next_stop; + int running=0; + int prev_total_length=0; + int prev_segue_length=0; + bool playing=false; + bool stop_set=false; + bool stop; + RDLogLine *logline; + RDLogLine *next_logline; + RDLogLine::TransType next_trans; + int next_length=0; + int lines[TRANSPORT_QUANTITY]; + + if((running=runningEvents(lines,false))>0) { + line=lines[0]; + } + else { + line=play_next_line; + } + for(int i=line;itransType(); + next_length=next_logline->segueLength(next_trans); + } + else { + next_trans=RDLogLine::Stop; + } + stop=false; + switch(logline->status()) { + case RDLogLine::Playing: + case RDLogLine::Finishing: + time=logline->startTime(RDLogLine::Actual); + playing=true; + break; + + default: + time=GetStartTime(logline->startTime(RDLogLine::Logged), + logline->transType(), + logline->timeType(), + time,prev_total_length,prev_segue_length, + &stop,running); + logline->setStartTime(RDLogLine::Predicted,time); + break; + } + if(stop&&(!stop_set)) { + next_stop=time.addMSecs(prev_total_length); + stop_set=true; + } + + prev_total_length=logline->effectiveLength()- + logline->playPosition(); + prev_segue_length= + logline->segueLength(next_trans)-logline->playPosition(); + end_time= + time.addMSecs(logline->effectiveLength()- + logline->playPosition()); + + switch(logline->status()) { + case RDLogLine::Scheduled: + case RDLogLine::Paused: + prev_total_length=logline->effectiveLength()- + logline->playPosition(); + prev_segue_length= + logline->segueLength(next_trans)-logline->playPosition(); + end_time= + time.addMSecs(logline->effectiveLength()- + logline->playPosition()); + break; + default: + prev_total_length=logline->effectiveLength(); + prev_segue_length= + logline->segueLength(next_trans); + end_time= + time.addMSecs(logline->effectiveLength()); + } + } + } + next_stop=GetNextStop(line); + + if(next_stop!=play_next_stop) { + play_next_stop=next_stop; + emit nextStopChanged(play_next_stop); + } + SendNowNext(); +} + + +void LogPlay::FinishEvent(int line) +{ + int prev_next_line=play_next_line; + if(GetNextPlayable(&play_next_line,false)) { + if(play_next_line>=0) { + RDLogLine *logline; + if((logline=logLine(play_next_line))==NULL) { + return; + } + if((play_op_mode==RDAirPlayConf::Auto)&& + (logline->id()!=-1)&&(play_next_line=0) { + if(logline->transType()==RDLogLine::Play) { + StartEvent(play_next_line,RDLogLine::Play,0,RDLogLine::StartPlay); + SetTransTimer(QTime(),prev_next_line==play_trans_line); + } + if(logline->transType()==RDLogLine::Segue) { + StartEvent(play_next_line,RDLogLine::Segue,0,RDLogLine::StartPlay); + SetTransTimer(QTime(),prev_next_line==play_trans_line); + } + } + } + } + } + UpdateStartTimes(line); + emit stopped(line); +} + + +QTime LogPlay::GetStartTime(QTime sched_time, + RDLogLine::TransType trans_type, + RDLogLine::TimeType time_type,QTime prev_time, + int prev_total_length,int prev_segue_length, + bool *stop,int running_events) +{ + QTime time; + + if((play_op_mode==RDAirPlayConf::LiveAssist)|| + (play_op_mode==RDAirPlayConf::Manual)) { + *stop=true; + return QTime(); + } + switch(trans_type) { + case RDLogLine::Play: + if(!prev_time.isNull()) { + time=prev_time.addMSecs(prev_total_length); + } + break; + + case RDLogLine::Segue: + if(!prev_time.isNull()) { + time=prev_time.addMSecs(prev_segue_length); + } + break; + + case RDLogLine::Stop: + time=QTime(); + break; + + default: + break; + } + switch(time_type) { + case RDLogLine::Relative: + if(!prev_time.isNull()) { + *stop=false; + return time; + } + *stop=true; + return QTime(); + break; + + case RDLogLine::Hard: + if((timetype()==RDLogLine::Cart)&& + ((logLine(i)->status()==RDLogLine::Playing)|| + (logLine(i)->status()==RDLogLine::Finishing))) { + time= + startTime(i).addMSecs(logLine(i)->segueLength(nextTrans(i))- + ((RDPlayDeck *)logLine(i)->playDeck())-> + lastStartPosition()); + } + else { + time=startTime(i).addMSecs(logLine(i)->segueLength(nextTrans(i))); + } + running=true; + } + else { + if(running&&(play_op_mode==RDAirPlayConf::Auto)&& + (status(i)==RDLogLine::Scheduled)) { + switch(logLine(i)->transType()) { + case RDLogLine::Stop: + return time; + break; + + case RDLogLine::Play: + case RDLogLine::Segue: + time=time.addMSecs(logLine(i)->segueLength(nextTrans(i))- + logLine(i)->playPosition()); + break; + + default: + break; + } + } + } + } + if(running!=play_running) { + play_running=running; + emit runStatusChanged(running); + } + return time; +} + +void LogPlay::UpdatePostPoint() +{ + int lines[TRANSPORT_QUANTITY] = {-1}; + int count = runningEvents(lines,false); + if (count > 0){ + UpdatePostPoint(lines[count -1]); + return; + } + transportEvents(lines); + UpdatePostPoint(lines[0]); +} + +void LogPlay::UpdatePostPoint(int line) +{ + int post_line=-1; + QTime post_time; + int offset=0; + + if((line<0)||(play_trans_line<0)) { + post_line=-1; + post_time=QTime(); + offset=0; + } + else { + if((line=0)&&(play_trans_linestartTime(RDLogLine::Logged); + offset=length(line,post_line)-QTime::currentTime().msecsTo(post_time); + } + } + if((post_time!=play_post_time)||(offset!=play_post_offset)) { + play_post_time=post_time; + play_post_offset=offset; + emit postPointChanged(play_post_time,offset,post_line>=line,running(false)); + } +} + + +void LogPlay::AdvanceActiveEvent() +{ + int line=-1; + RDLogLine::TransType trans=RDLogLine::Play; + + for(int i=0;ideck()!=-1) { + line=play_line_counter+i; + } + } + } + if(line==-1) { + if(line!=play_active_line) { + play_active_line=line; + emit activeEventChanged(line,RDLogLine::Stop); + } + } + else { + if(line<(size()-1)) { + RDLogLine *logline; + if((logline=logLine(line+1))!=NULL) { + trans=logLine(line+1)->transType(); + } + } + else { + trans=RDLogLine::Stop; + } + if((line!=play_active_line)||(trans!=play_active_trans)) { + play_active_line=line; + play_active_trans=trans; + emit activeEventChanged(line,trans); + } + } +} + + +QString LogPlay::GetPortName(int card,int port) +{ + for(int i=0;i<2;i++) { + for(int j=0;j<2;j++) { + if((play_card[i]==card)&&(play_port[i]==port)) { + return QString().sprintf("%d",i+1); + } + } + } + return QString(); +} + + +void LogPlay::SetTransTimer(QTime current_time,bool stop) +{ + int next_line=-1; + QTime next_time=QTime(23,59,59); + + if(current_time.isNull()) { + current_time=QTime::currentTime(); + } + RDLogLine *logline; + + if(play_trans_timer->isActive()) { + if(stop) + play_trans_timer->stop(); + else + return; + } + play_trans_line=-1; + for(int i=0;itimeType()==RDLogLine::Hard)&& + ((logline->status()==RDLogLine::Scheduled)|| + (logline->status()==RDLogLine::Auditioning))&& + (logline->startTime(RDLogLine::Logged)>current_time)&& + (logline->startTime(RDLogLine::Logged)<=next_time)) { + next_time=logline->startTime(RDLogLine::Logged); + next_line=i; + } + } + } + if(next_line>=0) { + play_trans_line=next_line; + play_trans_timer->start(current_time.msecsTo(next_time),true); + } +} + + +int LogPlay::GetNextChannel(int mport,int *card,int *port) +{ + int chan=next_channel; + if(mport<0) { + *card=play_card[next_channel]; + *port=play_port[next_channel]; + if(++next_channel>1) { + next_channel=0; + } + } + else { + chan=mport; + *card=play_card[mport]; + *port=play_port[mport]; + next_channel=mport+1; + if(next_channel>1) { + next_channel=0; + } + } + return chan; +} + + +int LogPlay::GetLineById(int id) +{ + return id; +} + + +RDPlayDeck *LogPlay::GetPlayDeck() +{ + for(int i=0;idisconnect(); + play_deck[i]->reset(); + play_deck_active[i]=false; + return; + } + } +} + + +bool LogPlay::GetNextPlayable(int *line,bool skip_meta,bool forced_start) +{ + RDLogLine *logline; + RDLogLine *next_logline; + RDLogLine::TransType next_type=RDLogLine::Play; + int skipped=0; + + for(int i=*line;itype()==RDLogLine::Marker)|| + (logline->type()==RDLogLine::OpenBracket)|| + (logline->type()==RDLogLine::CloseBracket)|| + (logline->type()==RDLogLine::Track)|| + (logline->type()==RDLogLine::MusicLink)|| + (logline->type()==RDLogLine::TrafficLink))) { + logline->setStatus(RDLogLine::Finished); + skipped++; + emit modified(i); + } + else { + if(logline->status()==RDLogLine::Scheduled || logline->status()==RDLogLine::Paused || + logline->status()==RDLogLine::Auditioning) { + if(((logline->transType()==RDLogLine::Stop)|| + (play_op_mode==RDAirPlayConf::LiveAssist))&&((i-skipped)!=*line)) { + makeNext(i); + return false; + } + if((next_logline=logLine(i+1))!=NULL) { + next_type=next_logline->transType(); + } + if((logline->setEvent(play_id,next_type,logline->timescalingActive())== + RDLogLine::Ok)&&((logline->status()==RDLogLine::Scheduled)|| + (logline->status()==RDLogLine::Paused))&& + (!logline->zombified())) { + emit modified(i); + *line=i; + return true; + } + else { + logline->setStartTime(RDLogLine::Initial,QTime::currentTime()); + if((logline->transType()==RDLogLine::Stop)) { + if((logline->cutNumber()>=0)&&(!logline->zombified())) { + emit modified(i); + *line=i; + return true; + } + else { + if(!forced_start) { + emit modified(i); + *line=i; + return true; + } + } + } + } + emit modified(i); + } + } + } + return false; +} + + +void LogPlay::LogPlayEvent(RDLogLine *logline) +{ + RDCut *cut=new RDCut(QString().sprintf("%06u_%03d", + logline->cartNumber(), + logline->cutNumber())); + cut->logPlayout(); + delete cut; +} + + +void LogPlay::RefreshEvents(int line,int line_quan,bool force_update) +{ + //QTime st=QTime::currentTime(); + + // + // Check Event Status + // + RDLogLine *logline; + RDLogLine *next_logline; + RDLogLine::State state=RDLogLine::Ok; + + for(int i=line;i<(line+line_quan);i++) { + if((logline=logLine(i))!=NULL) { + if(logline->type()==RDLogLine::Cart) { + switch(logline->state()) { + case RDLogLine::Ok: + case RDLogLine::NoCart: + case RDLogLine::NoCut: + if(logline->status()==RDLogLine::Scheduled) { + state=logline->state(); + if((next_logline=logLine(i+1))!=NULL) { + logline-> + loadCart(logline->cartNumber(),next_logline->transType(), + play_id,logline->timescalingActive()); + } + else { + logline->loadCart(logline->cartNumber(),RDLogLine::Play, + play_id,logline->timescalingActive()); + } + if(force_update||(state!=logline->state())) { + emit modified(i); + } + } + break; + + default: + break; + } + } + } + } + + // + // Check Refreshability + // + if(play_log!=NULL) { + if((!play_log->exists())||(play_log->linkDatetime()!=play_link_datetime)|| + (play_log->modifiedDatetime()<=play_modified_datetime)) { + if(play_refreshable) { + play_refreshable=false; + emit refreshabilityChanged(play_refreshable); + } + } + else { + if(play_log->autoRefresh()) { + refresh(); + } + else { + if(!play_refreshable) { + play_refreshable=true; + emit refreshabilityChanged(play_refreshable); + } + } + } + } + +/* + if(play_id==0) { + printf("LogPlay::RefreshEvents(%d,%d) took: %d msec\n",line,line_quan, + st.msecsTo(QTime::currentTime())); + } +*/ +} + + +void LogPlay::Playing(int id) +{ + RDLogLine *logline; + + int line=GetLineById(id); + if((logline=logLine(line))==NULL) { + return; + } + UpdateStartTimes(line); + emit played(line); + AdvanceActiveEvent(); + UpdatePostPoint(); + // TEST + RefreshEvents(line,LOGPLAY_LOOKAHEAD_EVENTS); + // + LogPlayEvent(logline); + emit transportChanged(); +} + + +void LogPlay::Paused(int id) +{ + int line=GetLineById(id); + RDLogLine *logline=logLine(line); + if(logline!=NULL) { + logline->playDeck()->disconnect(); + logline->setPortName(""); + logline->setStatus(RDLogLine::Paused); + } + UpdateStartTimes(line); + emit paused(line); + UpdatePostPoint(); + LogTraffic(serviceName(),logName().left(logName().length()-4),logLine(line), + (RDLogLine::PlaySource)(play_id+1),RDAirPlayConf::TrafficPause, + play_onair_flag); + emit transportChanged(); +} + + +void LogPlay::Stopping(int id) +{ +} + + +void LogPlay::Stopped(int id) +{ + int line=GetLineById(id); + int lines[TRANSPORT_QUANTITY]; + CleanupEvent(id); + UpdateStartTimes(line); + emit stopped(line); + AdvanceActiveEvent(); + UpdatePostPoint(); + if(runningEvents(lines)==0) { + next_channel=0; + } + LogTraffic(serviceName(),logName().left(logName().length()-4),logLine(line), + (RDLogLine::PlaySource)(play_id+1),RDAirPlayConf::TrafficStop, + play_onair_flag); + emit transportChanged(); +} + + +void LogPlay::Finished(int id) +{ + int line=GetLineById(id); + RDLogLine *logline; + int lines[TRANSPORT_QUANTITY]; + if((logline=logLine(line))==NULL) { + return; + } + switch(logline->status()) { + case RDLogLine::Playing: + CleanupEvent(id); + FinishEvent(line); + break; + + case RDLogLine::Auditioning: + break; + + default: + break; + } + UpdatePostPoint(); + if(runningEvents(lines)==0) { + next_channel=0; + } + LogTraffic(serviceName(),logName().left(logName().length()-4),logline, + (RDLogLine::PlaySource)(play_id+1),RDAirPlayConf::TrafficFinish, + play_onair_flag); + emit transportChanged(); +} + + +void LogPlay::ClearChannel(int deckid) +{ + if(play_deck[deckid]->channel()<0) { + return; + } + if(rdcae->playPortActive(play_deck[deckid]->card(), + play_deck[deckid]->port(), + play_deck[deckid]->stream())) { + return; + } + + if(play_deck[deckid]->channel()>=0) { + rdevent_player->exec(play_stop_rml[play_deck[deckid]->channel()]); + emit channelStopped(play_id,play_deck[deckid]->channel(), + play_deck[deckid]->card(), + play_deck[deckid]->port()); + } + play_deck[deckid]->setChannel(-1); +} + + +RDLogLine::TransType LogPlay::GetTransType(const QString &logname,int line) +{ + RDLogLine::TransType trans=RDLogLine::Stop; + QString sql=QString("select TRANS_TYPE from ")+ + RDLog::tableName(logname)+" where "+QString().sprintf("COUNT=%d",line); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + trans=(RDLogLine::TransType)q->value(0).toUInt(); + } + delete q; + return trans; +} + + +bool LogPlay::ClearBlock(int start_line) +{ + RDLogLine::Status status; + + for(int i=start_line;istatus(); + if((status!=RDLogLine::Scheduled)&&(status!=RDLogLine::Finished)) { + remove(start_line,i-start_line); + return true; + } + } + remove(start_line,size()-start_line); + return false; +} diff --git a/rdairplay/log_play.h b/rdairplay/log_play.h new file mode 100644 index 00000000..5b933215 --- /dev/null +++ b/rdairplay/log_play.h @@ -0,0 +1,257 @@ +// log_play.h +// +// Rivendell Log Playout Machine +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: log_play.h,v 1.90.8.3.2.1 2014/05/22 19:37:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LOG_PLAY_H +#define LOG_PLAY_H + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// Widget Settings +// +#define LOGPLAY_MAX_PLAYS 7 +#define TRANSPORT_QUANTITY 7 +#define LOGPLAY_LOOKAHEAD_EVENTS 20 +#define LOGPLAY_RESCAN_INTERVAL 5000 +#define LOGPLAY_RESCAN_SIZE 30 + +// +// Debug Settings +// +//#define SHOW_SLOTS +//#define SHOW_METER_SLOTS + +class LogPlay : public QObject,public RDLogEvent +{ + Q_OBJECT + public: + LogPlay(RDCae *cae,int id,QSocketDevice *nn_sock,QString logname, + std::vector *rlm_hosts, + QObject *parent=0,const char *name=0); + QString serviceName() const; + void setServiceName(const QString &svcname); + QString defaultServiceName() const; + void setDefaultServiceName(const QString &svcname); + int card(int channum) const; + int port(int channum) const; + RDAirPlayConf::OpMode mode() const; + void setOpMode(RDAirPlayConf::OpMode mode); + void setLogName(QString name); + void setChannels(int cards[2],int ports[2], + const QString start_rml[2],const QString stop_rml[2]); + void setSegueLength(int len); + void setNowCart(unsigned cartnum); + void setNextCart(unsigned cartnum); + void auditionHead(int line); + void auditionTail(int line); + void auditionStop(); + bool play(int line,RDLogLine::StartSource src, + int mport=-1,bool skip_meta=false); + bool channelPlay(int mport); + bool stop(bool all=true,int port=0,int fade=0); + bool stop(int line,int fade=0); + bool channelStop(int mport); + bool pause(int line); + void duckVolume(int level,int fade,int mport=-1); + void makeNext(int line,bool refresh_status=true); + void load(); + void append(const QString &log_name); + bool refresh(); + void save(int line=-1); + void clear(); + void insert(int line,int cartnum,RDLogLine::TransType next_type, + RDLogLine::TransType type=RDLogLine::Play); + void insert(int line,RDLogLine *logline,bool update=true,bool preserv_custom_transition=false); + void remove(int line,int num_lines,bool update=true,bool preserv_custom_transition=false); + void move(int from_line,int to_line); + void copy(int from_line,int to_line, + RDLogLine::TransType type=RDLogLine::Play); + int topLine(); + int currentLine() const; + int nextLine() const; + int nextLine(int line); + RDLogLine *nextEvent(); + RDLogLine::TransType nextTrans(); + RDLogLine::TransType nextTrans(int line); + void transportEvents(int line[]); + int runningEvents(int *line, bool include_paused=true); + void lineModified(int line); + RDLogLine::Status status(int line); + QTime startTime(int line); + QTime nextStop() const; + bool running(bool include_paused=true); + void resync(); + + private slots: + void transTimerData(); + void graceTimerData(); + void playStateChangedData(int id,RDPlayDeck::State state); + void onairFlagChangedData(bool state); + void segueStartData(int); + void segueEndData(int); + void talkStartData(int); + void talkEndData(int); + void positionData(int,int); + void macroStartedData(); + void macroFinishedData(); + void macroStoppedData(); + void timescalingSupportedData(int card,bool state); + void rescanEventsData(); + void auditionStartedData(); + void auditionStoppedData(); + + signals: + void renamed(); + void reloaded(); + void transportChanged(); + void inserted(int line); + void removed(int line,int num,bool moving); + void modified(int line); + void auditionHeadPlayed(int line); + void auditionTailPlayed(int line); + void auditionStopped(int line); + void played(int line); + void paused(int line); + void stopped(int line); + void position(int line,int point); + void topEventChanged(int line); + void nextEventChanged(int line); + void activeEventChanged(int line,RDLogLine::TransType trans); + void nextStopChanged(QTime time); + void postPointChanged(QTime point,int offset,bool offset_valid,bool running); + void runStatusChanged(bool running); + void refreshabilityChanged(bool state); + void refreshStatusChanged(bool active); + void channelStarted(int id,int mport,int card,int port); + void channelStopped(int id,int mport,int card,int port); + + private: + bool StartEvent(int line,RDLogLine::TransType trans_type,int trans_length, + RDLogLine::StartSource src,int mport=-1,int duck_length=0); + bool StartAudioEvent(int line); + void CleanupEvent(int id); + void UpdateStartTimes(int line); + void FinishEvent(int line); + QTime GetStartTime(QTime sched_time,RDLogLine::TransType trans_type, + RDLogLine::TimeType time_type,QTime prev_time, + int prev_total_length,int prev_segue_length,bool *stop, + int running_events); + QTime GetNextStop(int line); + void UpdatePostPoint(); + void UpdatePostPoint(int line); + void AdvanceActiveEvent(); + void SetTransTimer(QTime current_time=QTime(),bool stop=true); + QString GetPortName(int card,int port); + int GetNextChannel(int mport,int *card,int *port); + int GetLineById(int id); + RDPlayDeck *GetPlayDeck(); + void FreePlayDeck(RDPlayDeck *); + bool GetNextPlayable(int *line,bool skip_meta,bool forced_start=false); + void LogPlayEvent(RDLogLine *logline); + void RefreshEvents(int line,int line_quan,bool force_update=false); + void Playing(int id); + void Paused(int id); + void Stopping(int id); + void Stopped(int id); + void Finished(int id); + void ClearChannel(int deckid); + RDLogLine::TransType GetTransType(const QString &logname,int line); + bool ClearBlock(int start_line); + void SendNowNext(); + RDCae *play_cae; + RDAirPlayConf::OpMode play_op_mode; + int play_slot_id[LOGPLAY_MAX_PLAYS]; + int play_segue_length; + int play_trans_length; + int play_next_line; + int play_line_counter; + bool play_start_next; + int play_id; + QTime play_next_stop; + bool play_running; + QTime play_post_time; + int play_post_offset; + int play_active_line; + RDLogLine::TransType play_active_trans; + RDMacroEvent *play_macro_deck; + bool play_macro_running; + bool play_refresh_pending; + QTimer *play_trans_timer; + QTimer *play_grace_timer; + int play_trans_line; + int play_grace_line; + int play_card[2]; + int play_port[2]; + QString play_start_rml[2]; + QString play_stop_rml[2]; + bool play_timescaling_available; + RDPlayDeck *play_deck[RD_MAX_STREAMS]; + bool play_deck_active[RD_MAX_STREAMS]; + int next_channel; + QSocketDevice *play_nownext_socket; + QString play_nownext_string; + QHostAddress play_nownext_address; + Q_UINT16 play_nownext_port; + QString play_nownext_rml; + bool play_timescaling_supported[RD_MAX_CARDS]; + QString play_svc_name; + QString play_defaultsvc_name; + QTimer *play_rescan_timer; + int play_rescan_pos; + RDLog *play_log; + QDateTime play_link_datetime; + QDateTime play_modified_datetime; + bool play_refreshable; + bool play_onair_flag; + int play_duck_volume_port1; + int play_duck_volume_port2; + std::vector *play_rlm_hosts; + unsigned play_now_cartnum; + unsigned play_next_cartnum; + unsigned play_prevnow_cartnum; + unsigned play_prevnext_cartnum; + RDSimplePlayer *play_audition_player; + int play_audition_line; + bool play_audition_head_played; + int play_audition_preroll; +}; + + +#endif diff --git a/rdairplay/log_traffic.cpp b/rdairplay/log_traffic.cpp new file mode 100644 index 00000000..00c7f3be --- /dev/null +++ b/rdairplay/log_traffic.cpp @@ -0,0 +1,86 @@ +// log_traffic.cpp +// +// Add an entry to the reconciliation table. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: log_traffic.cpp,v 1.20.8.2.2.3 2014/06/24 18:27:05 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include + +#include +#include + + +void LogTraffic(const QString &svcname,const QString &logname, + RDLogLine *logline,RDLogLine::PlaySource src, + RDAirPlayConf::TrafficAction action,bool onair_flag) +{ + QString sql; + RDSqlQuery *q; + QDateTime datetime=QDateTime(QDate::currentDate(),QTime::currentTime()); + int length=logline->startTime(RDLogLine::Actual).msecsTo(datetime.time()); + if(length<0) { // Event crossed midnight! + length+=86400000; + datetime.setDate(datetime.date().addDays(-1)); + } + + if((logline==NULL)||(svcname.isEmpty())) { + return; + } + sql=QString("insert into `")+svcname+"_SRT` set "+ + QString().sprintf("LENGTH=%d,",length)+ + "LOG_NAME=\""+RDEscapeString(logname.utf8())+"\","+ + QString().sprintf("LOG_ID=%d,",logline->id())+ + QString().sprintf("CART_NUMBER=%u,",logline->cartNumber())+ + "STATION_NAME=\""+RDEscapeString(rdstation_conf->name().utf8())+"\","+ + "EVENT_DATETIME=\""+datetime.toString("yyyy-MM-dd")+" "+ + logline->startTime(RDLogLine::Actual).toString("hh:mm:ss")+"\","+ + QString().sprintf("EVENT_TYPE=%d,",action)+ + QString().sprintf("EVENT_SOURCE=%d,",logline->source())+ + "EXT_START_TIME=\""+logline->extStartTime().toString("hh:mm:ss")+"\","+ + QString().sprintf("EXT_LENGTH=%d,",logline->extLength())+ + "EXT_DATA=\""+RDEscapeString(logline->extData())+"\","+ + "EXT_EVENT_ID=\""+RDEscapeString(logline->extEventId())+"\","+ + "EXT_ANNC_TYPE=\""+RDEscapeString(logline->extAnncType())+"\","+ + QString().sprintf("PLAY_SOURCE=%d,",src)+ + QString().sprintf("CUT_NUMBER=%d,",logline->cutNumber())+ + "EXT_CART_NAME=\""+RDEscapeString(logline->extCartName().utf8())+"\","+ + "TITLE=\""+RDEscapeString(logline->title().utf8())+"\","+ + "ARTIST=\""+RDEscapeString(logline->artist().utf8())+"\","+ + "SCHEDULED_TIME=\""+RDEscapeString(logline->startTime(RDLogLine::Logged). + toString("hh:mm:ss"))+"\","+ + "ISRC=\""+RDEscapeString(logline->isrc().utf8())+"\","+ + "PUBLISHER=\""+RDEscapeString(logline->publisher().utf8())+"\","+ + "COMPOSER=\""+RDEscapeString(logline->composer().utf8())+"\","+ + QString().sprintf("USAGE_CODE=%d,",logline->usageCode())+ + QString().sprintf("START_SOURCE=%d,",logline->startSource())+ + "ONAIR_FLAG=\""+RDYesNo(onair_flag)+"\","+ + "ALBUM=\""+RDEscapeString(logline->album().utf8())+"\","+ + "LABEL=\""+RDEscapeString(logline->label().utf8())+"\","+ + "USER_DEFINED=\""+RDEscapeString(logline->userDefined().utf8())+"\","+ + "CONDUCTOR=\""+RDEscapeString(logline->conductor().utf8())+"\","+ + "SONG_ID=\""+RDEscapeString(logline->songId().utf8())+"\","+ + "ISCI=\""+RDEscapeString(logline->isci().utf8())+"\""; + + q=new RDSqlQuery(sql); + delete q; +} diff --git a/rdairplay/log_traffic.h b/rdairplay/log_traffic.h new file mode 100644 index 00000000..3ed46413 --- /dev/null +++ b/rdairplay/log_traffic.h @@ -0,0 +1,35 @@ +// log_traffic.h +// +// Add an entry to the reconciliation table. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: log_traffic.h,v 1.9 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LOG_TRAFFIC_H +#define LOG_TRAFFIC_H + +#include +#include + + +void LogTraffic(const QString &svcname,const QString &logname, + RDLogLine *logline,RDLogLine::PlaySource src, + RDAirPlayConf::TrafficAction action,bool onair_flag); + + +#endif // LOG_TRAFFIC_H diff --git a/rdairplay/loglinebox.cpp b/rdairplay/loglinebox.cpp new file mode 100644 index 00000000..a1b002b1 --- /dev/null +++ b/rdairplay/loglinebox.cpp @@ -0,0 +1,929 @@ +// loglinebox.cpp +// +// On Air Playout Utility for Rivendell. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: loglinebox.cpp,v 1.89.6.8 2014/02/06 20:43:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" +#include "../icons/chain.xpm" +#include "../icons/track_cart.xpm" +#include "../icons/mic16.xpm" +#include "../icons/notemarker.xpm" +#include "../icons/traffic.xpm" +#include "../icons/music.xpm" + + +LogLineBox::LogLineBox(RDAirPlayConf *conf,QWidget *parent,const char *name) + : QWidget(parent,name) +{ + line_status=RDLogLine::Scheduled; + line_type=RDLogLine::UnknownType; + line_mode=LogLineBox::Full; + line_time_mode=RDAirPlayConf::TwentyFourHour; + line_logline=NULL; + log_id=-1; + log_line=-1; + line_move_count=-1; + line_allow_drags=false; + + // + // Templates + // + line_title_template=conf->titleTemplate(); + line_artist_template=conf->artistTemplate(); + line_outcue_template=conf->outcueTemplate(); + line_description_template=conf->descriptionTemplate(); + + // + // Create Font + // + line_bold_font=QFont("Helvetica",12,QFont::Bold); + line_bold_font.setPixelSize(12); + line_font=QFont("Helvetica",12,QFont::Normal); + line_font.setPixelSize(12); + talk_font=QFont("Helvetica",12,QFont::Bold); + talk_font.setPixelSize(12); + QFont outcue_font=QFont("Helvetica",12,QFont::Normal); + outcue_font.setPixelSize(12); + outcue_font.setItalic(true); + + // + // Create Icons + // + line_playout_map=new QPixmap(play_xpm); + line_macro_map=new QPixmap(rml5_xpm); + line_chain_map=new QPixmap(chain_xpm); + line_track_cart_map=new QPixmap(track_cart_xpm); + line_mic16_map=new QPixmap(mic16_xpm); + line_notemarker_map=new QPixmap(notemarker_xpm); + line_traffic_map=new QPixmap(traffic_xpm); + line_music_map=new QPixmap(music_xpm); + + // + // Create Palettes + // + line_unchanged_stop_palette=palette(); + line_unchanged_stop_palette.setColor(QPalette::Active,QColorGroup::Highlight, + QColor(BAR_UNCHANGED_STOPPING_COLOR)); + line_unchanged_stop_palette.setColor(QPalette::Inactive, + QColorGroup::Highlight, + QColor(BAR_UNCHANGED_STOPPING_COLOR)); + line_unchanged_play_palette=palette(); + line_unchanged_play_palette.setColor(QPalette::Active,QColorGroup::Highlight, + QColor(BAR_UNCHANGED_TRANSITION_COLOR)); + line_unchanged_play_palette.setColor(QPalette::Inactive, + QColorGroup::Highlight, + QColor(BAR_UNCHANGED_TRANSITION_COLOR)); + line_changed_stop_palette=palette(); + line_changed_stop_palette.setColor(QPalette::Active,QColorGroup::Highlight, + QColor(BAR_CHANGED_STOPPING_COLOR)); + line_changed_stop_palette.setColor(QPalette::Inactive,QColorGroup::Highlight, + QColor(BAR_CHANGED_STOPPING_COLOR)); + line_changed_play_palette=palette(); + line_changed_play_palette.setColor(QPalette::Active,QColorGroup::Highlight, + QColor(BAR_CHANGED_TRANSITION_COLOR)); + line_changed_play_palette.setColor(QPalette::Inactive,QColorGroup::Highlight, + QColor(BAR_CHANGED_TRANSITION_COLOR)); + line_time_palette=palette(); + line_hard_palette=palette(); + line_hard_palette.setColor(QPalette::Active,QColorGroup::Foreground, + QColor(LOG_HARDTIME_TEXT_COLOR)); + line_hard_palette.setColor(QPalette::Inactive,QColorGroup::Foreground, + QColor(LOG_HARDTIME_TEXT_COLOR)); + + line_timescale_palette=palette(); + line_timescale_palette.setColor(QPalette::Active,QColorGroup::Foreground, + QColor(LOGLINEBOX_TIMESCALE_COLOR)); + line_timescale_palette.setColor(QPalette::Inactive,QColorGroup::Foreground, + QColor(LOGLINEBOX_TIMESCALE_COLOR)); + + line_transition_palette=palette(); + line_transition_palette.setColor(QPalette::Active,QColorGroup::Foreground, + QColor(RD_CUSTOM_TRANSITION_COLOR)); + line_transition_palette.setColor(QPalette::Inactive,QColorGroup::Foreground, + QColor(RD_CUSTOM_TRANSITION_COLOR)); + + // + // Count Up + // + line_up_label=new QLabel(this,"line_up_label"); + line_up_label->setGeometry(5,65,65,16); + line_up_label->setAlignment(AlignLeft|AlignVCenter); + line_up_label->setFont(line_font); + line_up_label->hide(); + + // + // Position Slider + // + line_position_bar=new QProgressBar(this,"line_position_bar"); + line_position_bar->setGeometry(75,66,sizeHint().width()-150,13); + line_position_bar->setPercentageVisible(false); + line_position_bar->hide(); + + // + // Count Down + // + line_down_label=new QLabel(this,"line_down_label"); + line_down_label->setGeometry(sizeHint().width()-72,65,65,16); + line_down_label->setAlignment(AlignLeft|AlignVCenter); + line_down_label->setFont(line_font); + line_down_label->hide(); + + // + // Cut Description + // + line_description_label=new QLabel(this,"line_description_label"); + line_description_label->setGeometry((sizeHint().width()/2),48,(sizeHint().width()/2 -10),16); + line_description_label->setFont(line_font); + line_description_label->hide(); + + // + // Outcue + // + line_outcue_label=new QLabel(this,"line_outcue_label"); + line_outcue_label->setGeometry(5,48, (sizeHint().width()/2 -10),16); + line_outcue_label->setFont(outcue_font); + line_outcue_label->hide(); + + // + // Artist + // + line_artist_label=new QLabel(this,"line_artist_label"); + line_artist_label->setGeometry(5,33,sizeHint().width()-10,16); + line_artist_label->setFont(line_font); + + // + // Title + // + line_title_label=new QLabel(this,"line_title_label"); + line_title_label->setGeometry(5,18,sizeHint().width()-10,18); + line_title_label->setFont(line_bold_font); + + // + // Marker Comment + // + line_comment_label=new RDLabel(this,"line_comment_label"); + line_comment_label->setGeometry(5,18,sizeHint().width()-10,62); + line_comment_label->setFont(line_font); + line_comment_label->setAlignment(AlignTop|AlignLeft); + line_comment_label->setWordWrapEnabled(true); + line_comment_label->hide(); + + // + // Icon + // + line_icon_label=new QLabel(this,"line_icon_label"); + line_icon_label->setGeometry(5,3,45,16); + + // + // Cart + // + line_cart_label=new QLabel(this,"line_cart_label"); + line_cart_label->setGeometry(25,3,53,16); + line_cart_label->setFont(line_font); + + // + // Cut + // + line_cut_label=new QLabel(this,"line_cut_label"); + line_cut_label->setGeometry(80,3,24,16); + line_cut_label->setFont(line_font); + + // + // Group + // + line_group_label=new QLabel(this,"line_group_label"); + line_group_label->setGeometry(107,3,75,16); + line_group_label->setFont(line_bold_font); + + // + // Time + // + line_time_label=new QLabel(this,"line_time_label"); + line_time_label->setGeometry(185,3,85,16); + line_time_label->setFont(line_font); + line_time_label->setAlignment(AlignRight); + line_time_label->setPalette(line_time_palette); + + // + // Talk Time + // + line_talktime_label=new QLabel(this,"line_talktime_label"); + line_talktime_label->setGeometry(273,3,21,16); + line_talktime_label->setFont(talk_font); + line_talktime_label->setAlignment(AlignRight); + + // + // Length + // + line_length_label=new QLabel(this,"line_length_label"); + line_length_label->setGeometry(297,3,40,16); + line_length_label->setFont(line_font); + line_length_label->setAlignment(AlignRight); + + // + // Transition Type + // + line_trans_label=new QLabel(this,"line_trans_label"); + line_trans_label->setGeometry(sizeHint().width()-53,3,48,16); + line_trans_label->setAlignment(AlignRight); + line_trans_label->setFont(line_bold_font); + + SetColor(QColor(LOGLINEBOX_BACKGROUND_COLOR)); + + // + // Countdown Timer + // + line_countdown_timer=new QTimer(this,"line_countdown_timer"); + connect(line_countdown_timer,SIGNAL(timeout()),this,SLOT(countdownData())); + + setAcceptDrops(true); +} + + +QSize LogLineBox::sizeHint() const +{ + switch(line_mode) { + case LogLineBox::Full: + return QSize(393,LOGLINEBOX_FULL_HEIGHT); + break; + + case LogLineBox::Half: + return QSize(393,LOGLINEBOX_HALF_HEIGHT); + break; + } + return QSize(0,0); +} + + +QSizePolicy LogLineBox::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +LogLineBox::Mode LogLineBox::mode() const +{ + return line_mode; +} + + +int LogLineBox::line() const +{ + return log_line; +} + + +void LogLineBox::setLine(int line) +{ + log_line=line; +} + + +void LogLineBox::setAllowDrags(bool state) +{ + line_allow_drags=state; +} + + +RDLogLine *LogLineBox::logLine() +{ + return line_logline; +} + + +void LogLineBox::setMode(LogLineBox::Mode mode) +{ + switch(mode) { + case LogLineBox::Full: + switch(line_type) { + case RDLogLine::Cart: + if(log_id!=-1) { + line_up_label->show(); + line_down_label->show(); + line_position_bar->show(); + line_description_label->show(); + } + else { + line_up_label->hide(); + line_down_label->hide(); + line_position_bar->hide(); + line_description_label->hide(); + } + break; + + case RDLogLine::Marker: + case RDLogLine::Track: + case RDLogLine::Macro: + case RDLogLine::Chain: + line_up_label->hide(); + line_down_label->hide(); + line_position_bar->hide(); + line_description_label->hide(); + break; + + default: + break; + } + line_comment_label->setGeometry(5,18,sizeHint().width()-10,62); + break; + + case LogLineBox::Half: + line_up_label->hide(); + line_down_label->hide(); + line_position_bar->hide(); + line_description_label->hide(); + line_comment_label->setGeometry(5,18,sizeHint().width()-10,31); + break; + } + line_mode=mode; + update(); +} + + +void LogLineBox::setStatus(RDLogLine::Status status) +{ + switch(status) { + case RDLogLine::Scheduled: + line_outcue_label->hide(); + break; + + default: + line_outcue_label->show(); + break; + } + line_status=status; +} + + +void LogLineBox::setEvent(int line,RDLogLine::TransType next_type, + RDLogLine *logline) +{ + QString cutname; + QPalette p; + + line_logline=logline; + line_next_type=next_type; + + RDCart *cart; + RDCut *cut; + + log_id=logline->id(); + log_line=line; + line_type=logline->type(); + switch(line_logline->transType()) { + case RDLogLine::Stop: + line_trans_label->setText(tr("STOP")); + line_trans_label->setPalette(palette()); + break; + + case RDLogLine::Play: + line_trans_label->setText(tr("PLAY")); + line_trans_label->setPalette(palette()); + break; + + case RDLogLine::Segue: + line_trans_label->setText(tr("SEGUE")); + if(logline->hasCustomTransition()) { + line_trans_label->setPalette(line_transition_palette); + } + else { + line_trans_label->setPalette(palette()); + } + break; + + default: + break; + } + switch(line_type) { + case RDLogLine::Cart: + line_comment_label->hide(); + cart=new RDCart(logline->cartNumber()); + cut=new RDCut(logline->cartNumber(),logline->cutNumber()); + if(!cart->exists()) { + line_cart_label-> + setText(QString().sprintf("%06u",logline->cartNumber())); + line_description_label->clear(); + line_artist_label->clear(); + line_cut_label->clear(); + line_group_label->clear(); + line_outcue_label->clear(); + line_length_label->setText("00:00"); + line_talktime_label->setText(":00"); + line_up_label->setText("0:00:00"); + line_down_label->setText("0:00:00"); + line_comment_label->clear(); + line_title_label->setText(tr("[CART NOT FOUND]")); + switch(cart->type()) { + case RDCart::Audio: + case RDCart::Macro: + case RDCart::All: + line_icon_label->setPixmap(*line_playout_map); + break; + } + SetColor(QColor(LOGLINEBOX_MISSING_COLOR)); + delete cart; + delete cut; + } + else { + if(((cart->forcedLength()==0)&&(cart->type()==RDCart::Audio))|| + (line_logline->state()==RDLogLine::NoCut)) { + line_cart_label-> + setText(QString().sprintf("%06u",logline->cartNumber())); + line_description_label->setText(cut->description()); + line_artist_label->setText(tr("[NO AUDIO AVAILABLE]")); + line_cut_label->clear(); + line_group_label->clear(); + line_outcue_label->clear(); + line_length_label->setText("00:00"); + line_talktime_label->setText(":00"); + line_up_label->setText("0:00:00"); + line_down_label->setText("0:00:00"); + line_comment_label->clear(); + line_icon_label->setPixmap(*line_playout_map); + line_title_label->setText(logline->title()); + SetColor(QColor(LOGLINEBOX_MISSING_COLOR)); + delete cart; + delete cut; + } + else { + line_cart_label-> + setText(QString().sprintf("%06u",logline->cartNumber())); + if(line_logline->evergreen()) { + SetColor(QColor(LOGLINEBOX_EVERGREEN_COLOR)); + } + else { + SetColor(QColor(LOGLINEBOX_BACKGROUND_COLOR)); + } + if(line_logline->source()==RDLogLine::Tracker) { + line_icon_label->setPixmap(*line_track_cart_map); + } + else { + switch(cart->type()) { + case RDCart::Audio: + case RDCart::All: + line_icon_label->setPixmap(*line_playout_map); + break; + + case RDCart::Macro: + line_icon_label->setPixmap(*line_macro_map); + break; + } + } + line_group_label->setText(cart->groupName()); + p=line_group_label->palette(); + p.setColor(QColorGroup::Foreground,line_logline->groupColor()); + line_group_label->setPalette(p); + if(line_logline->talkLength()<=0) { + line_talktime_label->setText(":00"); + } + else { + line_talktime_label-> + setText(RDGetTimeLength(line_logline->talkLength(), + false,false)); + } + line_length_label-> + setText(RDGetTimeLength(line_logline->effectiveLength(), + false,false)); + if(line_logline->timescalingActive()) { + line_length_label->setPalette(line_hard_palette); + } + else { + line_length_label->setPalette(line_time_palette); + } + if((line_logline->source()!=RDLogLine::Tracker)|| + line_logline->originUser().isEmpty()|| + (!line_logline->originDateTime().isValid())) { + line_title_label-> + setText(RDResolveNowNext(line_title_template,line_logline)); + } + else { + line_title_label->setText(QString(). + sprintf("%s -- %s %s", + (const char *)line_logline->title(), + (const char *)line_logline->originUser(), + (const char *)line_logline->originDateTime(). + toString("M/d hh:mm"))); + } + line_description_label-> + setText(RDResolveNowNext(line_description_template,line_logline)); + line_artist_label-> + setText(RDResolveNowNext(line_artist_template,line_logline)); + line_up_label-> + setText(RDGetTimeLength(line_logline->playPosition(),true,true)); + line_down_label-> + setText(RDGetTimeLength(line_logline->effectiveLength()- + line_logline->playPosition(),true,true)); + line_position_bar->setTotalSteps(line_logline->effectiveLength()); + line_position_bar->setProgress(line_logline->playPosition()); + if(logline->cutNumber()>=0) { + line_cut_label-> + setText(QString().sprintf("%03u",logline->cutNumber())); + line_outcue_label-> + setText(RDResolveNowNext(line_outcue_template,line_logline)); + } + else { + SetColor(QColor(LOGLINEBOX_MISSING_COLOR)); + line_cut_label->clear(); + line_outcue_label->setText(tr("[NO VALID CUT AVAILABLE]")); + } + delete cart; + delete cut; + setMode(line_mode); + line_title_label->show(); + line_artist_label->show(); + } + } + break; + + case RDLogLine::Marker: + line_icon_label->setPixmap(*line_notemarker_map); + SetColor(QColor(LOGLINEBOX_MARKER_COLOR)); + line_title_label->hide(); + line_description_label->hide(); + line_artist_label->hide(); + line_cart_label->setText(tr("MARKER")); + line_group_label->setText(logline->markerLabel()); + line_length_label->setText(":00"); + line_transition=logline->transType(); + line_comment_label->setText(logline->markerComment()); + setMode(line_mode); + line_comment_label->show(); + break; + + case RDLogLine::Track: + line_icon_label->setPixmap(*line_mic16_map); + SetColor(QColor(LOGLINEBOX_MARKER_COLOR)); + line_title_label->hide(); + line_description_label->hide(); + line_artist_label->hide(); + line_cart_label->setText(tr("TRACK")); + line_group_label->setText(""); + line_length_label->setText(":00"); + line_transition=logline->transType(); + line_comment_label->setText(logline->markerComment()); + setMode(line_mode); + line_comment_label->show(); + break; + + case RDLogLine::MusicLink: + line_icon_label->setPixmap(*line_music_map); + SetColor(QColor(LOGLINEBOX_MARKER_COLOR)); + line_title_label->hide(); + line_description_label->hide(); + line_artist_label->hide(); + line_cart_label->setText(tr("LINK")); + line_group_label->setText(""); + line_length_label->setText(":00"); + line_transition=logline->transType(); + line_comment_label->setText(tr("[music import]")); + setMode(line_mode); + line_comment_label->show(); + break; + + case RDLogLine::TrafficLink: + line_icon_label->setPixmap(*line_traffic_map); + SetColor(QColor(LOGLINEBOX_MARKER_COLOR)); + line_title_label->hide(); + line_description_label->hide(); + line_artist_label->hide(); + line_cart_label->setText(tr("LINK")); + line_group_label->setText(""); + line_length_label->setText(":00"); + line_transition=logline->transType(); + line_comment_label->setText(tr("[traffic import]")); + setMode(line_mode); + line_comment_label->show(); + break; + + case RDLogLine::Chain: + line_icon_label->setPixmap(*line_chain_map); + SetColor(QColor(LOGLINEBOX_CHAIN_COLOR)); + line_title_label->setText(logline->markerLabel()); + line_description_label->setText(""); + line_artist_label->setText(logline->markerComment()); + line_cart_label->setText(tr("CHAIN")); + line_group_label->setText(""); + line_length_label->setText(":00"); + line_transition=logline->transType(); + line_comment_label->hide(); + setMode(line_mode); + line_title_label->show(); + line_artist_label->show(); + break; + + case RDLogLine::Macro: + line_icon_label->setPixmap(*line_macro_map); + line_comment_label->hide(); + cart=new RDCart(logline->cartNumber()); + cut=new RDCut(QString().sprintf("%06u_%03u",logline->cartNumber(), + logline->cutNumber())); + if(!cart->exists()) { + SetColor(QColor(LOGLINEBOX_MISSING_COLOR)); + } + else { + SetColor(QColor(LOGLINEBOX_BACKGROUND_COLOR)); + } + line_cart_label->setText(QString().sprintf("%06u",cart->number())); + line_cut_label->setText(""); + line_group_label->setText(cart->groupName()); + p=line_group_label->palette(); + p.setColor(QColorGroup::Foreground,line_logline->groupColor()); + line_group_label->setPalette(p); + line_length_label-> + setText(RDGetTimeLength(line_logline->effectiveLength(), + false,false)); + + line_title_label-> + setText(RDResolveNowNext(line_title_template,line_logline)); + line_description_label-> + setText(RDResolveNowNext(line_description_template,line_logline)); + line_artist_label-> + setText(RDResolveNowNext(line_artist_template,line_logline)); + line_outcue_label-> + setText(RDResolveNowNext(line_outcue_template,line_logline)); + delete cart; + delete cut; + setMode(line_mode); + line_title_label->show(); + line_artist_label->show(); + break; + + default: + break; + } + PrintTime(); +} + + +void LogLineBox::setTimer(int msecs) +{ + line_up_label->setText(RDGetTimeLength(msecs,true,true)); + line_down_label-> + setText(RDGetTimeLength(line_logline->effectiveLength()-msecs,true,true)); + line_position_bar->setProgress(msecs); +} + + +void LogLineBox::clear() +{ + SetColor(QColor(LOGLINEBOX_BACKGROUND_COLOR)); + line_cart_label->setText(""); + line_cut_label->setText(""); + line_group_label->setText(""); + line_trans_label->setText(""); + line_title_label->setText(""); + line_description_label->setText(""); + line_artist_label->setText(""); + line_outcue_label->setText(""); + line_outcue_label->hide(); + line_comment_label->setText(""); + line_time_label->setText(""); + line_talktime_label->setText(""); + line_length_label->setText(""); + line_up_label->setText(""); + line_down_label->setText(""); + line_position_bar->reset(); + line_countdown_timer->stop(); + line_end_time=QTime(); + log_id=-1; + log_line=-1; + line_transition=RDLogLine::Stop; + line_logline=NULL; + line_time_mode=RDAirPlayConf::TwentyFourHour; + line_type=RDLogLine::Cart; + line_up_label->hide(); + line_position_bar->hide(); + line_down_label->hide(); + line_icon_label->clear(); + setBarMode(LogLineBox::Stopping); +} + + +void LogLineBox::setBarMode(LogLineBox::BarMode mode) +{ + switch(mode) { + case LogLineBox::Transitioning: + if(line_logline!=NULL) { + if(line_logline->playPositionChanged()) { + line_position_bar->setPalette(line_changed_play_palette); + } + else { + line_position_bar->setPalette(line_unchanged_play_palette); + } + } + else { + line_position_bar->setPalette(line_unchanged_play_palette); + } + break; + + case LogLineBox::Stopping: + if(line_logline!=NULL) { + if(line_logline->playPositionChanged()) { + line_position_bar->setPalette(line_changed_stop_palette); + } + else { + line_position_bar->setPalette(line_unchanged_stop_palette); + } + } + else { + line_position_bar->setPalette(line_unchanged_stop_palette); + } + break; + } +} + + +void LogLineBox::setTimeMode(RDAirPlayConf::TimeMode mode) +{ + if(mode==line_time_mode) { + return; + } + line_time_mode=mode; + PrintTime(); +} + + +void LogLineBox::countdownData() +{ + UpdateCountdown(); +} + + +void LogLineBox::mousePressEvent(QMouseEvent *e) +{ + QWidget::mousePressEvent(e); + line_move_count=3; +} + + +void LogLineBox::mouseMoveEvent(QMouseEvent *e) +{ + QWidget::mouseMoveEvent(e); + line_move_count--; + if(line_move_count==0) { + if(line_allow_drags&&(line_logline!=NULL)) { + RDCartDrag *d= + new RDCartDrag(line_logline->cartNumber(),line_icon_label->pixmap(), + this); + d->dragCopy(); + } + } +} + + +void LogLineBox::mouseReleaseEvent(QMouseEvent *e) +{ + line_move_count=-1; +} + + +void LogLineBox::mouseDoubleClickEvent(QMouseEvent *e) +{ + if(line_logline==NULL) { + return; + } + emit doubleClicked(log_line); + QWidget::mouseDoubleClickEvent(e); +} + + +void LogLineBox::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->drawRect(0,0,sizeHint().width(),sizeHint().height()); + p->end(); + delete p; +} + + +void LogLineBox::dragEnterEvent(QDragEnterEvent *e) +{ + e->accept(RDCartDrag::canDecode(e)&&(line_status==RDLogLine::Scheduled)); +} + + +void LogLineBox::dropEvent(QDropEvent *e) +{ + RDLogLine ll; + + if(RDCartDrag::decode(e,&ll)) { + emit cartDropped(log_line,&ll); + } +} + + +void LogLineBox::SetColor(QColor color) +{ + setBackgroundColor(color); + line_cart_label->setBackgroundColor(color); + line_cut_label->setBackgroundColor(color); + line_group_label->setBackgroundColor(color); + line_trans_label->setBackgroundColor(color); + line_title_label->setBackgroundColor(color); + line_description_label->setBackgroundColor(color); + line_artist_label->setBackgroundColor(color); + line_outcue_label->setBackgroundColor(color); + line_time_label->setBackgroundColor(color); + line_length_label->setBackgroundColor(color); + line_talktime_label->setBackgroundColor(color); + line_up_label->setBackgroundColor(color); + line_position_bar->setBackgroundColor(QColor(lightGray)); + line_down_label->setBackgroundColor(color); + line_comment_label->setBackgroundColor(color); + line_icon_label->setBackgroundColor(color); +} + + +void LogLineBox::UpdateCountdown() +{ + QTime current=QTime::currentTime().addMSecs(rdstation_conf->timeOffset()); + + if(currentsetText(RDGetTimeLength(current.msecsTo(line_end_time), + false,false)); + } + else { + line_length_label->setText(RDGetTimeLength(0,false,false)); + } +} + + +void LogLineBox::PrintTime() +{ + QString str; + + if(line_logline==NULL) { + return; + } + switch(line_logline->timeType()) { + case RDLogLine::Hard: + line_time_label->setFont(line_bold_font); + str=QString(tr("T")); + line_time_label->setText(QString().sprintf("%s%s",(const char *)str, + (const char *)TimeString(line_logline-> + startTime(RDLogLine::Logged)))); + line_time_label->setPalette(line_hard_palette); + break; + + default: + line_time_label->setFont(line_font); + if(!line_logline->startTime(RDLogLine::Logged).isNull()) { + line_time_label-> + setText(QString().sprintf("%s", + (const char *)TimeString(line_logline-> + startTime(RDLogLine::Logged)))); + } + else { + line_time_label->setText(""); + } + line_time_label->setPalette(line_time_palette); + break; + } +} + + +QString LogLineBox::TimeString(const QTime &time) +{ + QString ret; + switch(line_time_mode) { + case RDAirPlayConf::TwelveHour: + ret=time.toString("h:mm:ss.zzz"); + ret=ret.left(ret.length()-2); + ret+=(" "+time.toString("ap")); + break; + + case RDAirPlayConf::TwentyFourHour: + ret=time.toString("hh:mm:ss.zzz").left(10); + break; + } + return ret; +} diff --git a/rdairplay/loglinebox.h b/rdairplay/loglinebox.h new file mode 100644 index 00000000..c39cac3a --- /dev/null +++ b/rdairplay/loglinebox.h @@ -0,0 +1,151 @@ +// loglinebox.h +// +// On Air Playout Utility for Rivendell. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: loglinebox.h,v 1.47.8.6 2014/02/06 20:43:51 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef LOGLINEBOX_H +#define LOGLINEBOX_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +// +// Widget Settings +// +#define LOGLINEBOX_FULL_HEIGHT 85 +#define LOGLINEBOX_HALF_HEIGHT 50 + +class LogLineBox : public QWidget +{ + Q_OBJECT + public: + enum Mode {Full=0,Half=1}; + enum BarMode {Transitioning=0,Stopping=1}; + LogLineBox(RDAirPlayConf *conf,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + LogLineBox::Mode mode() const; + int line() const; + void setLine(int line); + RDLogLine *logLine(); + void setMode(LogLineBox::Mode mode); + void setEvent(int line,RDLogLine::TransType next_type,RDLogLine *logline); + void setTimer(int msecs); + void clear(); + void setBarMode(LogLineBox::BarMode); + void setTimeMode(RDAirPlayConf::TimeMode); + void setStatus(RDLogLine::Status status); + void setAllowDrags(bool state); + + signals: + void doubleClicked(int line); + void cartDropped(int line,RDLogLine *ll); + + private slots: + void countdownData(); + + protected: + void mousePressEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); + void paintEvent(QPaintEvent *); + void dragEnterEvent(QDragEnterEvent *e); + void dropEvent(QDropEvent *e); + + private: + void SetColor(QColor); + void UpdateCountdown(); + void PrintTime(); + QString TimeString(const QTime &time); + LogLineBox::Mode line_mode; + QLabel *line_icon_label; + QLabel *line_cart_label; + QLabel *line_cut_label; + QLabel *line_group_label; + QLabel *line_trans_label; + QLabel *line_title_label; + QLabel *line_description_label; + QLabel *line_artist_label; + QLabel *line_outcue_label; + QLabel *line_time_label; + QLabel *line_length_label; + QLabel *line_talktime_label; + QLabel *line_up_label; + QLabel *line_down_label; + RDLabel *line_comment_label; + QProgressBar *line_position_bar; + QTimer *line_countdown_timer; + QTime line_end_time; + int log_id; + int log_line; + RDLogLine *line_logline; + RDLogLine::TransType line_transition; + QFont line_font; + QFont talk_font; + QFont line_bold_font; + QPalette line_unchanged_stop_palette; + QPalette line_unchanged_play_palette; + QPalette line_changed_stop_palette; + QPalette line_changed_play_palette; + QPalette line_time_palette; + QPalette line_hard_palette; + QPalette line_timescale_palette; + QPalette line_transition_palette; + RDLogLine::TransType line_next_type; + RDAirPlayConf::TimeMode line_time_mode; + RDLogLine::Type line_type; + QPixmap *line_playout_map; + QPixmap *line_macro_map; + QPixmap *line_chain_map; + QPixmap *line_track_cart_map; + QPixmap *line_mic16_map; + QPixmap *line_notemarker_map; + QPixmap *line_traffic_map; + QPixmap *line_music_map; + int line_move_count; + RDLogLine::Status line_status; + QString line_title_template; + QString line_artist_template; + QString line_outcue_template; + QString line_description_template; + bool line_allow_drags; +}; + + +#endif diff --git a/rdairplay/mode_display.cpp b/rdairplay/mode_display.cpp new file mode 100644 index 00000000..a312e718 --- /dev/null +++ b/rdairplay/mode_display.cpp @@ -0,0 +1,205 @@ +// mode_display.cpp +// +// The mode display widget for RDAirPlay in Rivendell +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: mode_display.cpp,v 1.17.6.1 2014/02/10 20:45:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + +ModeDisplay::ModeDisplay(QWidget *parent) + : QPushButton(parent) +{ + for(int i=0;ifillRect(0,0,sizeHint().width(),sizeHint().height(), + BUTTON_MODE_LIVE_ASSIST_COLOR); + p->setPen(QColor(color1)); + p->setFont(mode_small_font); + p->drawText((sizeHint().width()-p->fontMetrics(). + width(tr("Operating Mode")))/2, + 22,tr("Operating Mode")); + p->setFont(mode_large_font); + p->drawText((sizeHint().width()-p->fontMetrics().width(tr("LiveAssist")))/2, + 48,tr("LiveAssist")); + setPalette(live_assist_color); + break; + + case RDAirPlayConf::Auto: + p->fillRect(0,0,sizeHint().width(),sizeHint().height(), + BUTTON_MODE_AUTO_COLOR); + p->setPen(QColor(color1)); + p->setFont(mode_small_font); + p->drawText((sizeHint().width()-p->fontMetrics(). + width(tr("Operating Mode")))/2, + 22,tr("Operating Mode")); + p->setFont(mode_large_font); + p->drawText((sizeHint().width()-p->fontMetrics().width(tr("Automatic")))/2, + 48,tr("Automatic")); + setPalette(auto_color); + break; + + case RDAirPlayConf::Manual: + p->fillRect(0,0,sizeHint().width(),sizeHint().height(), + BUTTON_MODE_MANUAL_COLOR); + p->setPen(QColor(color1)); + p->setFont(mode_small_font); + p->drawText((sizeHint().width()-p->fontMetrics(). + width(tr("Operating Mode")))/2, + 22,tr("Operating Mode")); + p->setFont(mode_large_font); + p->drawText((sizeHint().width()-p->fontMetrics().width(tr("Manual")))/2, + 48,tr("Manual")); + setPalette(manual_color); + break; + + case RDAirPlayConf::Previous: + break; + } + } + else { + switch(mode_mode[0]) { + case RDAirPlayConf::LiveAssist: + p->fillRect(0,0,sizeHint().width(),sizeHint().height(), + BUTTON_MODE_LIVE_ASSIST_COLOR); + p->setPen(QColor(color1)); + p->setFont(mode_small_font); + p->drawText((sizeHint().width()-p->fontMetrics(). + width(tr("Operating Mode")))/2, + 12,tr("Operating Mode")); + p->setFont(mode_large_font); + p->drawText((sizeHint().width()-p->fontMetrics().width(tr("LiveAssist")))/2, + 38,tr("LiveAssist")); + setPalette(live_assist_color); + break; + + case RDAirPlayConf::Auto: + p->fillRect(0,0,sizeHint().width(),sizeHint().height(), + BUTTON_MODE_AUTO_COLOR); + p->setPen(QColor(color1)); + p->setFont(mode_small_font); + p->drawText((sizeHint().width()-p->fontMetrics(). + width(tr("Operating Mode")))/2, + 12,tr("Operating Mode")); + p->setFont(mode_large_font); + p->drawText((sizeHint().width()-p->fontMetrics().width(tr("Automatic")))/2, + 39,tr("Automatic")); + setPalette(auto_color); + break; + + case RDAirPlayConf::Manual: + p->fillRect(0,0,sizeHint().width(),sizeHint().height(), + BUTTON_MODE_MANUAL_COLOR); + p->setPen(QColor(color1)); + p->setFont(mode_small_font); + p->drawText((sizeHint().width()-p->fontMetrics(). + width(tr("Operating Mode")))/2, + 12,tr("Operating Mode")); + p->setFont(mode_large_font); + p->drawText((sizeHint().width()-p->fontMetrics().width(tr("Manual")))/2, + 38,tr("Manual")); + setPalette(manual_color); + break; + + case RDAirPlayConf::Previous: + break; + } + p->setFont(mode_tiny_font); + str=tr("Aux1")+": "+RDAirPlayConf::logModeText(mode_mode[1]); + p->drawText((sizeHint().width()/2-p->fontMetrics().width(str))/2,sizeHint().height()-5,str); + str=tr("Aux2")+": "+RDAirPlayConf::logModeText(mode_mode[2]); + p->drawText(sizeHint().width()/2+(sizeHint().width()/2-p->fontMetrics().width(str))/2,sizeHint().height()-5,str); + } + p->end(); + delete p; + + setPixmap(*pix); + delete pix; +} diff --git a/rdairplay/mode_display.h b/rdairplay/mode_display.h new file mode 100644 index 00000000..36faa46e --- /dev/null +++ b/rdairplay/mode_display.h @@ -0,0 +1,61 @@ +// mode_display.h +// +// The mode display widget for RDAirPlay in Rivendell +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: mode_display.h,v 1.12.6.1 2014/02/10 20:45:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef MODE_DISPLAY_H +#define MODE_DISPLAY_H + +#include +#include +#include +#include + +#include + +// +// Widget Settings +// +#define MANUAL_LABEL "Manual" +#define AUTO_LABEL "Automatic" + +class ModeDisplay : public QPushButton +{ + Q_OBJECT + public: + ModeDisplay(QWidget *parent=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void setOpMode(int mach,RDAirPlayConf::OpMode mode); + void setOpModeStyle(RDAirPlayConf::OpModeStyle style); + + private: + void WriteMap(); + RDAirPlayConf::OpMode mode_mode[RDAIRPLAY_LOG_QUANTITY]; + RDAirPlayConf::OpModeStyle mode_style; + QPalette auto_color; + QPalette manual_color; + QPalette live_assist_color; + QFont mode_large_font; + QFont mode_small_font; + QFont mode_tiny_font; +}; + +#endif diff --git a/rdairplay/nownext.cpp b/rdairplay/nownext.cpp new file mode 100644 index 00000000..f17c7c63 --- /dev/null +++ b/rdairplay/nownext.cpp @@ -0,0 +1,140 @@ +// nownext.cpp +// +// Rivendell Now & Next Implementation +// +// (C) Copyright 2002-2008 Fred Gleason +// +// $Id: nownext.cpp,v 1.4.8.3 2014/01/13 16:51:21 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include + +void LogPlay::SendNowNext() +{ + QTime end_time; + QTime time; + int now_line=-1; + RDLogLine *logline[2]; + RDLogLine *ll; + RDLogLine *default_now_logline=NULL; + RDLogLine *default_next_logline=NULL; + + // + // Get NOW PLAYING Event + // + if(play_nownext_address.isNull()&&play_nownext_rml.isEmpty()&& + (play_rlm_hosts->size()==0)) { + return; + } + QString cmd=play_nownext_string; + int lines[TRANSPORT_QUANTITY]; + int running=runningEvents(lines,false); + for(int i=0;istartTime(RDLogLine::Actual). + addMSecs(logLine(lines[i])->effectiveLength()))>end_time) { + end_time=time; + now_line=lines[i]; + } + } + if((now_line>=0)&&(logLine(now_line)->nowNextEnabled())) { + logline[0]=logLine(now_line); + } + else { + if(play_now_cartnum==0) { + logline[0]=NULL; + } + else { + default_now_logline=new RDLogLine(play_now_cartnum); + logline[0]=default_now_logline; + } + } + + // + // Get NEXT Event + // + logline[1]=NULL; + for(int i=nextLine();istatus()==RDLogLine::Scheduled)&& + logLine(i)->nowNextEnabled()) { + logline[1]=logLine(i); + i=size(); + } + } + } + if((logline[1]==NULL)&&(play_next_cartnum!=0)) { + default_next_logline=new RDLogLine(play_next_cartnum); + logline[1]=default_next_logline; + } + + // + // Process and Send It + // + unsigned nowcart=0; + unsigned nextcart=0; + if(logline[0]!=NULL) { + nowcart=logline[0]->cartNumber(); + } + if(logline[1]!=NULL) { + nextcart=logline[1]->cartNumber(); + } + if((nowcart==play_prevnow_cartnum)&&(nextcart==play_prevnext_cartnum)) { + return; + } + if(logline[0]==NULL) { + play_prevnow_cartnum=0; + } + else { + play_prevnow_cartnum=logline[0]->cartNumber(); + } + if(logline[1]==NULL) { + play_prevnext_cartnum=0; + } + else { + play_prevnext_cartnum=logline[1]->cartNumber(); + } + QString svcname=play_svc_name; + if(svcname.isEmpty()) { + svcname=play_defaultsvc_name; + } + for(unsigned i=0;isize();i++) { + play_rlm_hosts->at(i)-> + sendEvent(svcname,logName().left(logName().length()-4),play_id,logline, + play_onair_flag,play_op_mode); + } + RDResolveNowNext(&cmd,logline,0); + play_nownext_socket-> + writeBlock(cmd,cmd.length(),play_nownext_address,play_nownext_port); + + cmd=play_nownext_rml; + RDResolveNowNext(&cmd,logline,0); + rdevent_player->exec(cmd); + + // + // Clean up + // + if(default_now_logline!=NULL) { + delete default_now_logline; + } + if(default_next_logline!=NULL) { + delete default_next_logline; + } +} diff --git a/rdairplay/pie_counter.cpp b/rdairplay/pie_counter.cpp new file mode 100644 index 00000000..9df5f441 --- /dev/null +++ b/rdairplay/pie_counter.cpp @@ -0,0 +1,346 @@ +// pie_counter.cpp +// +// The pie counter widget for Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: pie_counter.cpp,v 1.39 2010/10/06 19:24:02 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include + +#include +#include + +PieCounter::PieCounter(int count_length,QWidget *parent,const char *name) + : QWidget(parent,name) +{ + pie_length=0; + pie_time=0; + pie_count_length=count_length; + pie_running=false; + pie_color=BUTTON_PLAY_BACKGROUND_COLOR; + pie_talk_start=-1; + pie_talk_end=-1; + pie_op_mode=RDAirPlayConf::LiveAssist; + pie_trans_type=RDLogLine::Stop; + air_line=-1; + pie_onair=false; + const int ring = (PIE_COUNTER_BBOX-PIE_COUNTER_SIZE)/2; + QFont font=QFont("Helvetica",30,QFont::Bold); + font.setPixelSize(30); + pie_time_label=new QLabel(":00",this,"pie_time_label"); + pie_time_label-> + setGeometry(PIE_X_PADDING+ring+25,PIE_Y_PADDING+ring+32,48,36); + pie_time_label->setFont(font); + pie_time_label->setAlignment(AlignCenter); + pie_time_label->hide(); + + pie_talk_label=new QLabel(":00",this,"pie_talk_label"); + pie_talk_label-> + setGeometry(PIE_X_PADDING+ring+25,PIE_Y_PADDING+ring+32,48,36); + QPalette pal=palette(); + pal. + setColor(QPalette::Active,QColorGroup::Foreground,QColor(PIE_TALK_COLOR)); + pie_talk_label->setPalette(pal); + pie_talk_label->setFont(font); + pie_talk_label->setAlignment(AlignCenter); + pie_talk_label->hide(); + onair_off_color=backgroundColor(); + pie_logline=NULL; + + resetTime(); +} + + +QSize PieCounter::sizeHint() const +{ + return QSize(2*PIE_X_PADDING+PIE_COUNTER_BBOX, + 2*PIE_Y_PADDING+PIE_COUNTER_BBOX); +} + + +QSizePolicy PieCounter::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int PieCounter::line() const +{ + return air_line; +} + + +void PieCounter::setLine(int line) +{ + air_line=line; +} + + +void PieCounter::setTime(int msecs) +{ + stop(); + pie_length=msecs; + pie_time=msecs; + pie_time_label->setText(QString().sprintf(":%02d",pie_time/1000)); +} + + +void PieCounter::setCountLength(int msecs) +{ + pie_count_length=msecs; +} + + +void PieCounter::setTalkStart(int msecs) +{ + pie_talk_start=msecs; +} + + +void PieCounter::setTalkEnd(int msecs) +{ + pie_talk_end=msecs; +} + + +void PieCounter::resetTime() +{ + stop(); + pie_time=pie_length; + pie_length=1; +} + + +void PieCounter::setOpMode(RDAirPlayConf::OpMode opmode) +{ + if(opmode==pie_op_mode) { + return; + } + pie_op_mode=opmode; + SetPieColor(); +} + + +void PieCounter::setTransType(RDLogLine::TransType trans) +{ + if(trans==pie_trans_type) { + return; + } + pie_trans_type=trans; + SetPieColor(); +} + + +void PieCounter::start(int offset) +{ + pie_time=pie_length-offset; + pie_running=true; + repaint(); +} + +void PieCounter::setLogline(RDLogLine *logline) +{ + pie_logline=logline; +} + + +void PieCounter::setErasePixmap(const QPixmap &pix) +{ + pie_pixmap=pix; + if(!pie_onair) { + QWidget::setErasePixmap(pie_pixmap); + } +} + + +void PieCounter::stop() +{ + pie_running=false; + pie_time_label->hide(); + pie_talk_label->hide(); + repaint(); +} + + +void PieCounter::setOnairFlag(bool state) +{ + if(state) { + setBackgroundColor(PIE_ONAIR_COLOR); + QWidget::setErasePixmap(QPixmap()); + pie_time_label->setBackgroundColor(PIE_ONAIR_COLOR); + pie_talk_label->setBackgroundColor(PIE_ONAIR_COLOR); + } + else { + setBackgroundColor(onair_off_color); + if(!pie_pixmap.isNull()) { + QWidget::setErasePixmap(pie_pixmap); + } + pie_time_label->setBackgroundColor(onair_off_color); + pie_talk_label->setBackgroundColor(onair_off_color); + } + pie_onair=state; +} + + +void PieCounter::tickCounter() +{ + int pie_pos=pie_length-pie_time; + if(pie_running && (pie_time>0)) { + if (pie_logline!=NULL) { + pie_pos=pie_logline->playPosition(); + pie_time=pie_length-pie_pos; + } else { + pie_time-=100; + } + if(pie_time>pie_count_length) { + pie_time_label->hide(); + } + else { + pie_time_label->show(); + } + if((pie_pospie_talk_end)|| + (((750+pie_talk_end-pie_pos)/1000)>99)) { + pie_talk_label->hide(); + } + else { + pie_talk_label->show(); + pie_talk_label-> + setText(QString().sprintf(":%02d",(750+pie_talk_end-pie_pos)/1000)); + } + if(pie_time<=0) { + stop(); + } + else { + pie_time_label->setText(QString().sprintf(":%02d",(1000+pie_time)/1000)); + repaint(false); + } + } +} + + +void PieCounter::paintEvent(QPaintEvent *e) +{ + int pie_pos=pie_length-pie_time; + static QPixmap pix=QPixmap(PIE_COUNTER_BBOX,PIE_COUNTER_BBOX); + const int ring = (PIE_COUNTER_BBOX-PIE_COUNTER_SIZE)/2; + int angle=(int)(((double)pie_time*5760.0)/(double)pie_length); + int talk_start= + (int)(1440.0-5760.0*(double)pie_talk_start/(double)pie_length); + int talk_angle=(int) + (-5760.0*((double)pie_talk_end-(double)pie_talk_start)/(double)pie_length); + QPainter *p=new QPainter(&pix,false); + double ring_angle = ((pie_length < (pie_count_length) ? pie_length : pie_count_length) - + ((pie_time > pie_count_length) ? pie_count_length : pie_time)); + if (pie_count_length) + ring_angle *= 5760.0/(pie_length < pie_count_length ? pie_length : pie_count_length); + else ring_angle = 0; + if (pie_time > pie_count_length) + ring_angle = 0; + + if(pie_onair||pie_pixmap.isNull()) { + p->fillRect(0,0,PIE_COUNTER_BBOX,PIE_COUNTER_BBOX,backgroundColor()); + } + else { + p->drawPixmap(-PIE_X_PADDING,-PIE_Y_PADDING,pie_pixmap); + } + if((!pie_running)||(pie_length==0)||(angle>5760)) { + p->setBrush (PIE_FINAL_BG_COLOR); + p->setPen(PIE_FINAL_BG_COLOR); + p->drawPie(0,0,PIE_COUNTER_BBOX,PIE_COUNTER_BBOX,0,5759); + p->setBrush(PIE_COUNTER_COLOR); + p->setPen(PIE_COUNTER_COLOR); + p->drawPie(ring,ring,PIE_COUNTER_SIZE,PIE_COUNTER_SIZE,0,5759); + } + else { + // Clear the pixmap + // This is the outer ring + p->setBrush (PIE_FINAL_BG_COLOR); + p->setPen(PIE_FINAL_BG_COLOR); + p->drawPie(0,0,PIE_COUNTER_BBOX,PIE_COUNTER_BBOX,0,5759); + p->setBrush(PIE_FINAL_COLOR); + p->setPen(PIE_FINAL_COLOR); + if (ring_angle > 0) + p->drawPie(0,0,PIE_COUNTER_BBOX,PIE_COUNTER_BBOX,1440, + (int)(ring_angle < 5760 ? (-1 * ring_angle) : 0)); + + // The background for the inner ring + p->setBrush(PIE_COUNTER_COLOR); + p->setPen(PIE_COUNTER_COLOR); + p->drawPie(ring,ring,PIE_COUNTER_SIZE,PIE_COUNTER_SIZE,0,5759); + // And this the inner + p->setBrush(PIE_COUNTER_COLOR); + p->setPen(PIE_COUNTER_COLOR); + p->drawPie(ring,ring,PIE_COUNTER_SIZE,PIE_COUNTER_SIZE,1440,angle); + p->setBrush(PIE_TALK_COLOR); + if((pie_talk_start>=0)&&(pie_talk_end>=0)) { + p->setPen(PIE_TALK_COLOR); + p->drawPie(ring,ring,PIE_COUNTER_SIZE,PIE_COUNTER_SIZE,talk_start,talk_angle); + } + p->setBrush(pie_color); + p->setPen(pie_color); + p->drawPie(ring,ring,PIE_COUNTER_SIZE,PIE_COUNTER_SIZE,1440+angle,5760-angle); + if(((pie_time0))|| + (((750+pie_talk_end-pie_pos)/1000)<100)&& + ((pie_pos>=pie_talk_start)&&(pie_pos<=pie_talk_end))) { + p->setBrush(backgroundColor()); + p->setPen(backgroundColor()); + p->drawPie(ring+20,ring+20,PIE_COUNTER_SIZE-40,PIE_COUNTER_SIZE-40,0,5760); + } + } + p->end(); + delete p; + p=new QPainter(this); + p->drawPixmap(PIE_X_PADDING,PIE_Y_PADDING,pix); + p->end(); + delete p; +} + + +void PieCounter::SetPieColor() +{ + switch(pie_op_mode) { + case RDAirPlayConf::Manual: + case RDAirPlayConf::LiveAssist: + pie_color=BUTTON_PLAY_BACKGROUND_COLOR; + break; + + case RDAirPlayConf::Auto: + switch(pie_trans_type) { + case RDLogLine::Play: + case RDLogLine::Segue: + pie_color=BUTTON_STOPPED_BACKGROUND_COLOR; + break; + + case RDLogLine::Stop: + pie_color=BUTTON_PLAY_BACKGROUND_COLOR; + break; + + default: + break; + } + break; + + default: + break; + } + update(); +} diff --git a/rdairplay/pie_counter.h b/rdairplay/pie_counter.h new file mode 100644 index 00000000..d47974cb --- /dev/null +++ b/rdairplay/pie_counter.h @@ -0,0 +1,101 @@ +// pie_counter.h +// +// The pie counter widget for Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: pie_counter.h,v 1.20 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef PIE_COUNTER_H +#define PIE_COUNTER_H + +#include +#include +#include +#include + +#include +#include + +#include + +// +// Inner pie timer +// +#define PIE_COUNTER_SIZE 100 + +// +// diameter of last seconds ring (and the bounding box for the whole thing) +// +#define PIE_COUNTER_BBOX 112 + +// +// Extra padding for the bounding box +// +#define PIE_X_PADDING 28 +#define PIE_Y_PADDING 7 + + +class PieCounter : public QWidget +{ + Q_OBJECT + public: + PieCounter(int count_length,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + int line() const; + void setLine(int line); + void setTime(int msecs); + void setCountLength(int msecs); + void setTalkStart(int msecs); + void setTalkEnd(int msecs); + void resetTime(); + void setOpMode(RDAirPlayConf::OpMode opmode); + void setTransType(RDLogLine::TransType trans); + void start(int offset=0); + void stop(); + void setLogline(RDLogLine *logline); + void setErasePixmap(const QPixmap &pix); + + public slots: + void setOnairFlag(bool state); + void tickCounter(); + + protected: + void paintEvent(QPaintEvent *e); + + private: + void SetPieColor(); + QLabel *pie_time_label; + QLabel *pie_talk_label; + int pie_time; + int pie_talk_start; + int pie_talk_end; + int pie_length; + int pie_count_length; + bool pie_running; + QColor pie_color; + RDAirPlayConf::OpMode pie_op_mode; + RDLogLine::TransType pie_trans_type; + int air_line; + QColor onair_off_color; + RDLogLine *pie_logline; + QPixmap pie_pixmap; + bool pie_onair; +}; + +#endif diff --git a/rdairplay/post_counter.cpp b/rdairplay/post_counter.cpp new file mode 100644 index 00000000..5201d6ba --- /dev/null +++ b/rdairplay/post_counter.cpp @@ -0,0 +1,189 @@ +// post_counter.cpp +// +// The post counter widget for Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: post_counter.cpp,v 1.22.6.1 2012/11/26 20:19:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include + +PostCounter::PostCounter(QWidget *parent,const char *name) + : QPushButton(parent,name) +{ + post_running=false; + post_time_format="hh:mm:ss"; + post_time=QTime(); + post_offset=0; + post_offset_valid=false; + + // + // Generate Fonts + // + post_small_font=QFont("Helvetica",12,QFont::Normal); + post_small_font.setPixelSize(12); + post_large_font=QFont("Helvetica",26,QFont::Normal); + post_large_font.setPixelSize(26); + + // + // Generate Palettes + // + post_idle_palette=palette(); + post_early_palette= + QPalette(QColor(POSTPOINT_EARLY_COLOR),backgroundColor()); + post_ontime_palette= + QPalette(QColor(POSTPOINT_ONTIME_COLOR),backgroundColor()); + post_late_palette= + QPalette(QColor(POSTPOINT_LATE_COLOR),backgroundColor()); + + post_offset = 0; + UpdateDisplay(); +} + +void PostCounter::setTimeMode(RDAirPlayConf::TimeMode mode) +{ + switch(mode) { + case RDAirPlayConf::TwentyFourHour: + post_time_format="hh:mm:ss"; + break; + + case RDAirPlayConf::TwelveHour: + post_time_format="h:mm:ss ap"; + break; + } + UpdateDisplay(); +} + +QSize PostCounter::sizeHint() const +{ + return QSize(200,60); +} + + +QSizePolicy PostCounter::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void PostCounter::setPostPoint(QTime point,int offset,bool offset_valid, + bool running) +{ + post_time=point; + post_offset=offset; + post_offset_valid=offset_valid; + post_running=running; + post_set_time=QTime::currentTime(); + UpdateDisplay(); +} + + +void PostCounter::tickCounter() +{ + if(!post_running) { + UpdateDisplay(); + } +} + + +void PostCounter::setEnabled(bool state) +{ + QWidget::setEnabled(state); + UpdateDisplay(); +} + + +void PostCounter::setDisabled(bool state) +{ + setEnabled(!state); +} + + +void PostCounter::keyPressEvent(QKeyEvent *e) +{ + e->ignore(); +} + + +void PostCounter::UpdateDisplay() +{ + QColor color=backgroundColor(); + QString str; + QString point; + QString state; + QTime current_time= + QTime::currentTime().addMSecs(rdstation_conf->timeOffset()); + int offset=post_offset; + if(!post_running) { + offset-=current_time.msecsTo(post_set_time); + } + + if(isEnabled()&&(!post_time.isNull())) { + str=QString(tr("Next Timed Start")); + point=QString().sprintf("%s [%s]",(const char *)str, + (const char *)post_time.toString(post_time_format)); + if(post_offset_valid) { + if(offset<-POST_COUNTER_MARGIN) { + state=QString().sprintf("-%s",(const char *) + QTime().addMSecs(-offset).toString()); + setPalette(post_early_palette); + color=POSTPOINT_EARLY_COLOR; + } + else { + if(offset>POST_COUNTER_MARGIN) { + state=QString().sprintf("+%s",(const char *) + QTime().addMSecs(offset).toString()); + setPalette(post_late_palette); + color=POSTPOINT_LATE_COLOR; + } + else { + state=tr("On Time"); + setPalette(post_ontime_palette); + color=POSTPOINT_ONTIME_COLOR; + } + } + } + else { + state="--------"; + setPalette(post_idle_palette); + } + } + else { // No postpoint/disabled + point=tr("Next Timed Start [--:--:--]"); + state="--------"; + setPalette(post_idle_palette); + } + QPixmap pix(sizeHint().width(),sizeHint().height()); + QPainter *p=new QPainter(&pix); + p->fillRect(0,0,sizeHint().width(),sizeHint().height(),color); + // p->eraseRect(0,0,sizeHint().width(),sizeHint().height()); + p->setPen(color1); + p->setFont(post_small_font); + p->drawText((sizeHint().width()-p-> + fontMetrics().width(point))/2,22,point); + p->setFont(post_large_font); + p->drawText((sizeHint().width()-p-> + fontMetrics().width(state))/2,48,state); + p->end(); + delete p; + setPixmap(pix); +} diff --git a/rdairplay/post_counter.h b/rdairplay/post_counter.h new file mode 100644 index 00000000..cdcb6803 --- /dev/null +++ b/rdairplay/post_counter.h @@ -0,0 +1,69 @@ +// post_counter.h +// +// The post counter widget for Rivendell +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: post_counter.h,v 1.13 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef POST_COUNTER_H +#define POST_COUNTER_H + +#include +#include +#include +#include +// +// Settings +// +#define POST_COUNTER_MARGIN 1000 + +class PostCounter : public QPushButton +{ + Q_OBJECT + public: + PostCounter(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void setTimeMode(RDAirPlayConf::TimeMode mode); + + public slots: + void setPostPoint(QTime point,int offset,bool offset_valid,bool running); + void tickCounter(); + void setEnabled(bool state); + void setDisabled(bool state); + + protected: + void keyPressEvent(QKeyEvent *e); + + private: + void UpdateDisplay(); + QTime post_time; + int post_offset; + bool post_offset_valid; + bool post_running; + QFont post_large_font; + QFont post_small_font; + QPalette post_early_palette; + QPalette post_ontime_palette; + QPalette post_late_palette; + QPalette post_idle_palette; + QString post_time_format; + QTime post_set_time; +}; + +#endif diff --git a/rdairplay/rdairplay.cpp b/rdairplay/rdairplay.cpp new file mode 100644 index 00000000..53df1f38 --- /dev/null +++ b/rdairplay/rdairplay.cpp @@ -0,0 +1,2658 @@ +// rdairplay.cpp +// +// The On Air Playout Utility for Rivendell. +// +// (C) Copyright 2002-2010 Fred Gleason +// +// $Id: rdairplay.cpp,v 1.189.2.24 2014/03/02 03:21:52 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +// +// Global Resources +// +RDStation *rdstation_conf; +RDSystem *rdsystem_conf; +RDAirPlayConf *rdairplay_conf; +RDAudioPort *rdaudioport_conf; +RDUser *rduser; +RDRipc *rdripc; +RDCae *rdcae; +RDEventPlayer *rdevent_player; +RDCartDialog *rdcart_dialog; +RDConfig *air_config; +MainWidget *prog_ptr; +RDHotKeyList *rdkeylist; +RDHotkeys *rdhotkeys; + +// +// Icons +// +#include "../icons/rivendell-128x128.xpm" +#include "../icons/rivendell-22x22.xpm" + +// +// Prototypes +// +void SigHandler(int signo); + +void MainWidget::logLine(RDConfig::LogPriority prio,const QString &s) +{ + LogLine(prio,s); +} + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + prog_ptr=this; + QString str; + int cards[3]; + int ports[3]; + QString start_rmls[3]; + QString stop_rmls[3]; + QPixmap *mainmap=NULL; + QPixmap *pm=NULL; + QPainter *pd=NULL; + air_refresh_pixmap=NULL; + air_panel=NULL; + bool skip_db_check=false; + unsigned schema=0; + + // + // Ensure Single Instance + // + air_lock=new RDInstanceLock(QString().sprintf("%s/.rdairplaylock", + (const char *)RDHomeDir())); + if(!air_lock->lock()) { + QMessageBox::information(this,tr("RDAirPlay"), + tr("Multiple instances not allowed!")); + exit(1); + } + + // + // Splash Screen + // + air_splash_screen=new QSplashScreen(QPixmap(rivendell_128x128_xpm)); + air_splash_screen->hide(); + QTimer *timer=new QTimer(this,"splash_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(clearSplashData())); + timer->start(AIR_PLAY_SPLASH_TIME,true); + + // + // Get the Startup Date/Time + // + air_startup_datetime=QDateTime(QDate::currentDate(),QTime::currentTime()); + + // + // Read Command Options + // + QString lineno; + RDCmdSwitch *cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdairplay", + RDAIRPLAY_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + } + for(unsigned i=0;ikeys();j++) { + if(cmd->key(j)==QString().sprintf("--log%u",i+1)) { + air_start_logname[i]=cmd->value(j); + for(unsigned k=0;kvalue(j).length();k++) { + if(cmd->value(j).at(k)==QChar(':')) { + air_start_logname[i]= + RDDateTimeDecode(cmd->value(j).left(k),air_startup_datetime); + lineno=cmd->value(j).right(cmd->value(j).length()-(k+1)); + if(lineno.right(1)=="+") { + air_start_start[i]=true; + lineno=lineno.left(lineno.length()-1); + } + air_start_line[i]=lineno.toInt(); + } + } + } + } + } + delete cmd; + + // + // Fix the Window Size + // +#ifndef RESIZABLE + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); +#endif // RESIZABLE + + // + // Initialize the Random Number Generator + // + srandom(QTime::currentTime().msec()); + + // + // Generate Fonts + // + QFont default_font("Helvetica",12,QFont::Normal); + default_font.setPixelSize(12); + qApp->setFont(default_font); + QFont button_font=QFont("Helvetica",16,QFont::Bold); + button_font.setPixelSize(16); + for(unsigned i=0;iload(); + logfile=air_config->airplayLogname(); + + str=QString("RDAirPlay")+" v"+VERSION+" - "+tr("Host:"); + setCaption(QString().sprintf("%s %s",(const char *)str, + (const char *)air_config->stationName())); + + // + // Open Database + // + QString err; + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + QMessageBox::warning(this,tr("Database Error"), + //tr("Can't Connect","Unable to connect to mySQL Server!")); + err); + exit(0); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr,"rdlogin: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + connect (RDDbStatus(),SIGNAL(logText(RDConfig::LogPriority,const QString &)), + this,SLOT(logLine(RDConfig::LogPriority,const QString &))); + + // + // Master Clock Timer + // + air_master_timer=new QTimer(this,"air_master_timer"); + connect(air_master_timer,SIGNAL(timeout()),this,SLOT(masterTimerData())); + air_master_timer->start(MASTER_TIMER_INTERVAL); + + // + // Allocate Global Resources + // + rdstation_conf=new RDStation(air_config->stationName()); + rdsystem_conf=new RDSystem(); + rdairplay_conf=new RDAirPlayConf(air_config->stationName(),"RDAIRPLAY"); + rdairplay_previous_exit_code=rdairplay_conf->exitCode(); + rdairplay_conf->setExitCode(RDAirPlayConf::ExitDirty); + air_clear_filter=rdairplay_conf->clearFilter(); + air_bar_action=rdairplay_conf->barAction(); + air_op_mode_style=rdairplay_conf->opModeStyle(); + for(int i=0;ieditorPath(); + mainmap=new QPixmap(rdairplay_conf->skinPath()); + if(mainmap->isNull()||(mainmap->width()<1024)||(mainmap->height()<738)) { + delete mainmap; + mainmap=NULL; + } + else { + setErasePixmap(*mainmap); + } + + // + // Load GPIO Channel Configuration + // + for(unsigned i=0;istartGpiMatrix(chan); + air_start_gpi_lines[i]=rdairplay_conf->startGpiLine(chan)-1; + air_start_gpo_matrices[i]=rdairplay_conf->startGpoMatrix(chan); + air_start_gpo_lines[i]=rdairplay_conf->startGpoLine(chan)-1; + air_stop_gpi_matrices[i]=rdairplay_conf->stopGpiMatrix(chan); + air_stop_gpi_lines[i]=rdairplay_conf->stopGpiLine(chan)-1; + air_stop_gpo_matrices[i]=rdairplay_conf->stopGpoMatrix(chan); + air_stop_gpo_lines[i]=rdairplay_conf->stopGpoLine(chan)-1; + air_channel_gpio_types[i]=rdairplay_conf->gpioType(chan); + air_audio_channels[i]= + AudioChannel(rdairplay_conf->card(chan),rdairplay_conf->port(chan)); + + if((rdairplay_conf->card(chan)>=0)&&(rdairplay_conf->port(chan)>=0)) { + int achan= + AudioChannel(rdairplay_conf->card(chan),rdairplay_conf->port(chan)); + if(air_channel_timers[0][achan]==NULL) { + air_channel_timers[0][achan]=new QTimer(this); + air_channel_timers[1][achan]=new QTimer(this); + } + } + } + + // + // Fixup Main Log GPIO Channel Assignments + // + if(((rdairplay_conf->card(RDAirPlayConf::MainLog1Channel)== + rdairplay_conf->card(RDAirPlayConf::MainLog2Channel))&& + (rdairplay_conf->port(RDAirPlayConf::MainLog1Channel)== + rdairplay_conf->port(RDAirPlayConf::MainLog2Channel)))|| + rdairplay_conf->card(RDAirPlayConf::MainLog2Channel)<0) { + air_start_gpi_matrices[RDAirPlayConf::MainLog2Channel]=-1; + air_start_gpo_matrices[RDAirPlayConf::MainLog2Channel]=-1; + air_stop_gpi_matrices[RDAirPlayConf::MainLog2Channel]= + air_stop_gpi_matrices[RDAirPlayConf::MainLog1Channel]; + air_stop_gpo_matrices[RDAirPlayConf::MainLog2Channel]=-1; + } + + // + // CAE Connection + // + rdcae=new RDCae(rdstation_conf,air_config,parent,name); + rdcae->connectHost(); + + // + // Set Audio Assignments + // + air_segue_length=rdairplay_conf->segueLength()+1; + RDSetMixerPorts(air_config->stationName(),rdcae); + + // + // RIPC Connection + // + rdripc=new RDRipc(air_config->stationName()); + connect(rdripc,SIGNAL(connected(bool)),this,SLOT(ripcConnected(bool))); + connect(rdripc,SIGNAL(userChanged()),this,SLOT(userData())); + connect(rdripc,SIGNAL(rmlReceived(RDMacro *)), + this,SLOT(rmlReceivedData(RDMacro *))); + connect(rdripc,SIGNAL(gpiStateChanged(int,int,bool)), + this,SLOT(gpiStateChangedData(int,int,bool))); + + // + // Macro Player + // + rdevent_player=new RDEventPlayer(rdripc,this); + + // + // User + // + rduser=NULL; + + // + // UDP Transmission Socket + // + air_nownext_socket=new QSocketDevice(QSocketDevice::Datagram); + + // + // Log Machines + // + QSignalMapper *reload_mapper=new QSignalMapper(this,"reload_mapper"); + connect(reload_mapper,SIGNAL(mapped(int)),this,SLOT(logReloadedData(int))); + QSignalMapper *rename_mapper=new QSignalMapper(this,"rename_mapper"); + connect(rename_mapper,SIGNAL(mapped(int)),this,SLOT(logRenamedData(int))); + QString default_svcname=rdairplay_conf->defaultSvc(); + for(int i=0;isetDefaultServiceName(default_svcname); + air_log[i]->setNowCart(rdairplay_conf->logNowCart(i)); + air_log[i]->setNextCart(rdairplay_conf->logNextCart(i)); + reload_mapper->setMapping(air_log[i],i); + connect(air_log[i],SIGNAL(reloaded()),reload_mapper,SLOT(map())); + rename_mapper->setMapping(air_log[i],i); + connect(air_log[i],SIGNAL(renamed()),rename_mapper,SLOT(map())); + connect(air_log[i],SIGNAL(refreshStatusChanged(bool)), + this,SLOT(refreshStatusChangedData(bool))); + connect(air_log[i],SIGNAL(channelStarted(int,int,int,int)), + this,SLOT(logChannelStartedData(int,int,int,int))); + connect(air_log[i],SIGNAL(channelStopped(int,int,int,int)), + this,SLOT(logChannelStoppedData(int,int,int,int))); + } + connect(air_log[0],SIGNAL(transportChanged()), + this,SLOT(transportChangedData())); + + // + // Audio Channel Assignments + // + air_cue_card=rdairplay_conf->card(RDAirPlayConf::CueChannel); + air_cue_port=rdairplay_conf->port(RDAirPlayConf::CueChannel); + for(int i=0;i<3;i++) { + air_meter_card[i]=rdairplay_conf->card((RDAirPlayConf::Channel)i); + air_meter_port[i]=rdairplay_conf->port((RDAirPlayConf::Channel)i); + cards[i]=rdairplay_conf->card((RDAirPlayConf::Channel)i); + ports[i]=rdairplay_conf->port((RDAirPlayConf::Channel)i); + start_rmls[i]=rdairplay_conf->startRml((RDAirPlayConf::Channel)i); + stop_rmls[i]=rdairplay_conf->stopRml((RDAirPlayConf::Channel)i); + } + if(air_meter_card[1]<0) { // Fixup disabled main log port 2 playout + air_meter_card[1]=air_meter_card[0]; + air_meter_port[1]=air_meter_port[0]; + cards[1]=cards[0]; + ports[1]=ports[0]; + } + air_log[0]->setChannels(cards,ports,start_rmls,stop_rmls); + + for(int i=0;i<2;i++) { + cards[i]=rdairplay_conf->card(RDAirPlayConf::AuxLog1Channel); + ports[i]=rdairplay_conf->port(RDAirPlayConf::AuxLog1Channel); + start_rmls[i]=rdairplay_conf->startRml(RDAirPlayConf::AuxLog1Channel); + stop_rmls[i]=rdairplay_conf->stopRml(RDAirPlayConf::AuxLog1Channel); + } + air_log[1]->setChannels(cards,ports,start_rmls,stop_rmls); + + for(int i=0;i<2;i++) { + cards[i]=rdairplay_conf->card(RDAirPlayConf::AuxLog2Channel); + ports[i]=rdairplay_conf->port(RDAirPlayConf::AuxLog2Channel); + start_rmls[i]=rdairplay_conf->startRml(RDAirPlayConf::AuxLog2Channel); + stop_rmls[i]=rdairplay_conf->stopRml(RDAirPlayConf::AuxLog2Channel); + } + air_log[2]->setChannels(cards,ports,start_rmls,stop_rmls); + + // + // Cart Picker + // + rdcart_dialog= + new RDCartDialog(&air_add_filter,&air_add_group,&air_add_schedcode, + rdcae,rdripc,rdstation_conf,rdsystem_conf,air_config,this); + + // + // Wall Clock + // + WallClock *clock=new WallClock(this,"wall_clock"); + clock-> + setGeometry(10,5,clock->sizeHint().width(),clock->sizeHint().height()); + clock->setCheckSyncEnabled(rdairplay_conf->checkTimesync()); + connect(air_master_timer,SIGNAL(timeout()),clock,SLOT(tickClock())); + clock->setFocusPolicy(QWidget::NoFocus); + connect(clock,SIGNAL(timeModeChanged(RDAirPlayConf::TimeMode)), + this,SLOT(timeModeData(RDAirPlayConf::TimeMode))); + + // + // Post Counter + // + air_post_counter=new PostCounter(this,"air_post_counter"); + air_post_counter->setGeometry(220,5,air_post_counter->sizeHint().width(), + air_post_counter->sizeHint().height()); + air_post_counter->setPostPoint(QTime(),0,false,false); + air_post_counter->setFocusPolicy(QWidget::NoFocus); + connect(air_master_timer,SIGNAL(timeout()), + air_post_counter,SLOT(tickCounter())); + connect(air_log[0],SIGNAL(postPointChanged(QTime,int,bool,bool)), + air_post_counter,SLOT(setPostPoint(QTime,int,bool,bool))); + + // + // Pie Counter + // + air_pie_counter=new PieCounter(rdairplay_conf->pieCountLength(), + this,"air_pie_counter"); + air_pie_counter->setGeometry(426,5,air_pie_counter->sizeHint().width(), + air_pie_counter->sizeHint().height()); + air_pie_counter->setCountLength(rdairplay_conf->pieCountLength()); + air_pie_end=rdairplay_conf->pieEndPoint(); + air_pie_counter->setOpMode(air_op_mode[0]); + air_pie_counter->setFocusPolicy(QWidget::NoFocus); + if(mainmap!=NULL) { + pm=new QPixmap(1024,738); + pd=new QPainter(pm); + pd->drawPixmap(-426,-5,*mainmap); + pd->end(); + air_pie_counter->setErasePixmap(*pm); + delete pd; + delete pm; + } + connect(air_master_timer,SIGNAL(timeout()), + air_pie_counter,SLOT(tickCounter())); + connect(rdripc,SIGNAL(onairFlagChanged(bool)), + air_pie_counter,SLOT(setOnairFlag(bool))); + + // + // Audio Meter + // + air_stereo_meter=new RDStereoMeter(this,"air_stereo_meter"); + air_stereo_meter->setGeometry(50,70,air_stereo_meter->sizeHint().width(), + air_stereo_meter->sizeHint().height()); + air_stereo_meter->setMode(RDSegMeter::Peak); + air_stereo_meter->setFocusPolicy(QWidget::NoFocus); + if(air_config->useStreamMeters()) { + air_stereo_meter->hide(); + } + + // + // Message Label + // + air_message_label=new RDLabel(this,"air_message_label"); + air_message_label->setGeometry(sizeHint().width()-425,70, + MESSAGE_WIDGET_WIDTH,air_stereo_meter->sizeHint().height()); + air_message_label->setWordWrapEnabled(true); + air_message_label->setLineWidth(1); + air_message_label->setMidLineWidth(1); + air_message_label->setFrameStyle(QFrame::Box|QFrame::Raised); + air_message_label->setAlignment(AlignCenter); + air_message_label->setFocusPolicy(QWidget::NoFocus); + + // + // Stop Counter + // + air_stop_counter=new StopCounter(this,"air_stop_counter"); + air_stop_counter->setGeometry(600,5,air_stop_counter->sizeHint().width(), + air_stop_counter->sizeHint().height()); + air_stop_counter->setTime(QTime(0,0,0)); + air_stop_counter->setFocusPolicy(QWidget::NoFocus); + connect(air_master_timer,SIGNAL(timeout()), + air_stop_counter,SLOT(tickCounter())); + connect(air_log[0],SIGNAL(nextStopChanged(QTime)), + air_stop_counter,SLOT(setTime(QTime))); + + // + // Mode Display/Button + // + air_mode_display=new ModeDisplay(this); + air_mode_display-> + setGeometry(sizeHint().width()-air_mode_display->sizeHint().width()-10, + 5,air_mode_display->sizeHint().width(), + air_mode_display->sizeHint().height()); + air_mode_display->setFocusPolicy(QWidget::NoFocus); + air_mode_display->setOpModeStyle(air_op_mode_style); + connect(air_mode_display,SIGNAL(clicked()),this,SLOT(modeButtonData())); + + // + // Create Palettes + // + auto_color= + QPalette(QColor(BUTTON_MODE_AUTO_COLOR),backgroundColor()); + manual_color= + QPalette(QColor(BUTTON_MODE_MANUAL_COLOR),backgroundColor()); + active_color=palette(); + active_color.setColor(QPalette::Active,QColorGroup::ButtonText, + BUTTON_LOG_ACTIVE_TEXT_COLOR); + active_color.setColor(QPalette::Active,QColorGroup::Button, + BUTTON_LOG_ACTIVE_BACKGROUND_COLOR); + active_color.setColor(QPalette::Active,QColorGroup::Background, + backgroundColor()); + active_color.setColor(QPalette::Inactive,QColorGroup::ButtonText, + BUTTON_LOG_ACTIVE_TEXT_COLOR); + active_color.setColor(QPalette::Inactive,QColorGroup::Button, + BUTTON_LOG_ACTIVE_BACKGROUND_COLOR); + active_color.setColor(QPalette::Inactive,QColorGroup::Background, + backgroundColor()); + + // + // Add Button + // + air_add_button=new RDPushButton(this,"air_add_button"); + air_add_button->setGeometry(10,sizeHint().height()-65,80,60); + air_add_button->setFont(button_font); + air_add_button->setText(tr("ADD")); + air_add_button->setFocusPolicy(QWidget::NoFocus); + connect(air_add_button,SIGNAL(clicked()),this,SLOT(addButtonData())); + + // + // Delete Button + // + air_delete_button=new RDPushButton(this,"air_delete_button"); + air_delete_button->setGeometry(100,sizeHint().height()-65,80,60); + air_delete_button->setFont(button_font); + air_delete_button->setText(tr("DEL")); + air_delete_button->setFlashColor(AIR_FLASH_COLOR); + air_delete_button->setFocusPolicy(QWidget::NoFocus); + connect(air_delete_button,SIGNAL(clicked()),this,SLOT(deleteButtonData())); + + // + // Move Button + // + air_move_button=new RDPushButton(this,"air_move_button"); + air_move_button->setGeometry(190,sizeHint().height()-65,80,60); + air_move_button->setFont(button_font); + air_move_button->setText(tr("MOVE")); + air_move_button->setFlashColor(AIR_FLASH_COLOR); + air_move_button->setFocusPolicy(QWidget::NoFocus); + connect(air_move_button,SIGNAL(clicked()),this,SLOT(moveButtonData())); + + // + // Copy Button + // + air_copy_button=new RDPushButton(this,"air_copy_button"); + air_copy_button->setGeometry(280,sizeHint().height()-65,80,60); + air_copy_button->setFont(button_font); + air_copy_button->setText(tr("COPY")); + air_copy_button->setFlashColor(AIR_FLASH_COLOR); + air_copy_button->setFocusPolicy(QWidget::NoFocus); + connect(air_copy_button,SIGNAL(clicked()),this,SLOT(copyButtonData())); + + // + // Refresh Indicator + // + air_refresh_label=new RDLabel(this,"air_refresh_label"); + air_refresh_label->setGeometry(390,sizeHint().height()-65,120,60); + air_refresh_label->setFont(button_font); + QPalette p=palette(); + p.setColor(QColorGroup::Foreground,red); + air_refresh_label->setPalette(p); + air_refresh_label->setAlignment(AlignCenter); + if(mainmap!=NULL) { + air_refresh_pixmap=new QPixmap(1024,738); + pd=new QPainter(air_refresh_pixmap); + pd->drawPixmap(-390,-sizeHint().height()+65,*mainmap); + pd->end(); + air_refresh_label->setErasePixmap(*air_refresh_pixmap); + delete pd; + } + + // + // Meter Timer + // + timer=new QTimer(this,"meter_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(meterData())); + timer->start(RD_METER_UPDATE_INTERVAL); + + // + // Sound Panel Array + // + if (rdairplay_conf->panels(RDAirPlayConf::StationPanel) || + rdairplay_conf->panels(RDAirPlayConf::UserPanel)){ + int card=-1; + air_panel= + new RDSoundPanel(AIR_PANEL_BUTTON_COLUMNS,AIR_PANEL_BUTTON_ROWS, + rdairplay_conf->panels(RDAirPlayConf::StationPanel), + rdairplay_conf->panels(RDAirPlayConf::UserPanel), + rdairplay_conf->flashPanel(), + rdairplay_conf->buttonLabelTemplate(),false, + rdevent_player,rdripc,rdcae,rdstation_conf, + rdcart_dialog,this,"air_panel"); + air_panel->setLogfile(air_config->airplayLogname()); + air_panel->setGeometry(510,140,air_panel->sizeHint().width(), + air_panel->sizeHint().height()); + if(mainmap!=NULL) { + pm=new QPixmap(1024,738); + pd=new QPainter(pm); + pd->drawPixmap(-510,-140,*mainmap); + pd->end(); + air_panel->setErasePixmap(*pm); + delete pd; + delete pm; + } + air_panel->setPauseEnabled(rdairplay_conf->panelPauseEnabled()); + air_panel->setCard(0,rdairplay_conf->card(RDAirPlayConf::SoundPanel1Channel)); + air_panel->setPort(0,rdairplay_conf->port(RDAirPlayConf::SoundPanel1Channel)); + air_panel->setFocusPolicy(QWidget::NoFocus); + if((card=rdairplay_conf->card(RDAirPlayConf::SoundPanel2Channel))<0) { + air_panel->setCard(1,air_panel->card(RDAirPlayConf::MainLog1Channel)); + air_panel->setPort(1,air_panel->port(RDAirPlayConf::MainLog1Channel)); + } + else { + air_panel->setCard(1,card); + air_panel->setPort(1,rdairplay_conf->port(RDAirPlayConf::SoundPanel2Channel)); + } + if((card=rdairplay_conf->card(RDAirPlayConf::SoundPanel3Channel))<0) { + air_panel->setCard(2,air_panel->card(RDAirPlayConf::MainLog2Channel)); + air_panel->setPort(2,air_panel->port(RDAirPlayConf::MainLog2Channel)); + } + else { + air_panel->setCard(2,card); + air_panel->setPort(2,rdairplay_conf->port(RDAirPlayConf::SoundPanel3Channel)); + } + if((card=rdairplay_conf->card(RDAirPlayConf::SoundPanel4Channel))<0) { + air_panel->setCard(3,air_panel->card(RDAirPlayConf::SoundPanel1Channel)); + air_panel->setPort(3,air_panel->port(RDAirPlayConf::SoundPanel1Channel)); + } + else { + air_panel->setCard(3,card); + air_panel->setPort(3,rdairplay_conf->port(RDAirPlayConf::SoundPanel4Channel)); + } + if((card=rdairplay_conf->card(RDAirPlayConf::SoundPanel5Channel))<0) { + air_panel->setCard(4,air_panel->card(RDAirPlayConf::CueChannel)); + air_panel->setPort(4,air_panel->port(RDAirPlayConf::CueChannel)); + } + else { + air_panel->setCard(4,card); + air_panel->setPort(4,rdairplay_conf-> + port(RDAirPlayConf::SoundPanel5Channel)); + } + air_panel->setRmls(0,rdairplay_conf-> + startRml(RDAirPlayConf::SoundPanel1Channel), + rdairplay_conf->stopRml(RDAirPlayConf::SoundPanel1Channel)); + air_panel->setRmls(1,rdairplay_conf-> + startRml(RDAirPlayConf::SoundPanel2Channel), + rdairplay_conf->stopRml(RDAirPlayConf::SoundPanel2Channel)); + air_panel->setRmls(2,rdairplay_conf-> + startRml(RDAirPlayConf::SoundPanel3Channel), + rdairplay_conf->stopRml(RDAirPlayConf::SoundPanel3Channel)); + air_panel->setRmls(3,rdairplay_conf-> + startRml(RDAirPlayConf::SoundPanel4Channel), + rdairplay_conf->stopRml(RDAirPlayConf::SoundPanel4Channel)); + air_panel->setRmls(4,rdairplay_conf-> + startRml(RDAirPlayConf::SoundPanel5Channel), + rdairplay_conf->stopRml(RDAirPlayConf::SoundPanel5Channel)); + int next_output=0; + int channum[2]; + bool assigned=false; + if((air_log[0]->card(0)==air_log[0]->card(RDAirPlayConf::MainLog2Channel))&& + (air_log[0]->port(0)==air_log[0]->port(RDAirPlayConf::MainLog2Channel))) { + next_output=2; + channum[0]=1; + channum[1]=1; + } + else { + next_output=3; + channum[0]=1; + channum[1]=2; + } + for(int i=0;isetOutputText(i,QString().sprintf("%d",next_output++)); + assigned=false; + for(int j=0;j<2;j++) { + if((air_panel->card((RDAirPlayConf::Channel)i)==air_log[0]->card(j))&& + (air_panel->port((RDAirPlayConf::Channel)i)==air_log[0]->port(j))) { + air_panel->setOutputText(i,QString().sprintf("%d",channum[j])); + next_output--; + assigned=true; + j=2; + } + } + if(!assigned) { + for(int j=0;jcard((RDAirPlayConf::Channel)i)==air_panel->card(j))&& + (air_panel->port((RDAirPlayConf::Channel)i)==air_panel->port(j))) { + air_panel->setOutputText(i,air_panel->outputText(j)); + next_output--; + j=PANEL_MAX_OUTPUTS; + } + } + } + } + + air_panel->setSvcName(rdairplay_conf->defaultSvc()); + connect(rdripc,SIGNAL(userChanged()),air_panel,SLOT(changeUser())); + connect(air_master_timer,SIGNAL(timeout()),air_panel,SLOT(tickClock())); + connect(air_panel,SIGNAL(selectClicked(unsigned,int,int)), + this,SLOT(selectClickedData(unsigned,int,int))); + connect(air_panel,SIGNAL(channelStarted(int,int,int)), + this,SLOT(panelChannelStartedData(int,int,int))); + connect(air_panel,SIGNAL(channelStopped(int,int,int)), + this,SLOT(panelChannelStoppedData(int,int,int))); + } + + // + // Full Log List + // + air_pause_enabled=rdairplay_conf->pauseEnabled(); + for(int i=0;isetGeometry(510,140,air_log_list[i]->sizeHint().width(), + air_log_list[i]->sizeHint().height()); + air_log_list[i]->hide(); + connect(air_log_list[i],SIGNAL(selectClicked(int,int,RDLogLine::Status)), + this,SLOT(selectClickedData(int,int,RDLogLine::Status))); + connect(air_log_list[i],SIGNAL(cartDropped(int,int,RDLogLine *)), + this,SLOT(cartDroppedData(int,int,RDLogLine *))); + } + + // + // Full Log Buttons + // + QSignalMapper *mapper=new QSignalMapper(this,"log_mapper"); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(fullLogButtonData(int))); + for(int i=0;isetGeometry(647+i*123,sizeHint().height()-65,118,60); + air_log_button[i]->setFont(button_font); + air_log_button[i]->setFocusPolicy(QWidget::NoFocus); + mapper->setMapping(air_log_button[i],i); + connect(air_log_button[i],SIGNAL(clicked()),mapper,SLOT(map())); + } + air_log_button[0]->setText(tr("Main Log\n[--]")); + air_log_button[1]->setText(tr("Aux 1 Log\n[--]")); + if(!rdairplay_conf->showAuxButton(0)) { + air_log_button[1]->hide(); + } + air_log_button[2]->setText(tr("Aux 2 Log\n[--]")); + if(!rdairplay_conf->showAuxButton(1)) { + air_log_button[2]->hide(); + } + + // + // Empty Cart + // + air_empty_cart=new RDEmptyCart(this); + air_empty_cart->setGeometry(520,sizeHint().height()-51,32,32); + if(!rdstation_conf->enableDragdrop()) { + air_empty_cart->hide(); + } + + // + // SoundPanel Button + // + air_panel_button=new QPushButton(this,"air_panel_button"); + air_panel_button->setGeometry(562,sizeHint().height()-65,80,60); + air_panel_button->setFont(button_font); + air_panel_button->setText(tr("Sound\nPanel")); + air_panel_button->setPalette(active_color); + air_panel_button->setFocusPolicy(QWidget::NoFocus); + connect(air_panel_button,SIGNAL(clicked()),this,SLOT(panelButtonData())); + if (rdairplay_conf->panels(RDAirPlayConf::StationPanel) || + rdairplay_conf->panels(RDAirPlayConf::UserPanel)){ + } + else { + air_panel_button->hide(); + air_log_button[0]->setPalette (active_color); + air_log_list[0]->show(); + } + + + // + // Button Log + // + air_button_list=new ButtonLog(air_log[0],0,rdairplay_conf,air_pause_enabled, + this,"air_button_list"); + air_button_list->setGeometry(10,140,air_button_list->sizeHint().width(), + air_button_list->sizeHint().height()); + if(mainmap!=NULL) { + pm=new QPixmap(1024,738); + pd=new QPainter(pm); + pd->drawPixmap(-10,-140,*mainmap); + pd->end(); + air_button_list->setErasePixmap(*pm); + delete pd; + delete pm; + } + connect(air_button_list,SIGNAL(selectClicked(int,int,RDLogLine::Status)), + this,SLOT(selectClickedData(int,int,RDLogLine::Status))); + connect(air_button_list,SIGNAL(cartDropped(int,int,RDLogLine *)), + this,SLOT(cartDroppedData(int,int,RDLogLine *))); + + // + // Set Startup Mode + // + for(int i=0;ilogStartMode(i)) { + case RDAirPlayConf::Manual: + SetManualMode(i); + break; + + case RDAirPlayConf::LiveAssist: + SetLiveAssistMode(i); + break; + + case RDAirPlayConf::Auto: + SetAutoMode(i); + break; + + case RDAirPlayConf::Previous: + if(air_op_mode_style==RDAirPlayConf::Unified) { + SetMode(i,rdairplay_conf->opMode(0)); + } + else { + SetMode(i,rdairplay_conf->opMode(i)); + } + break; + } + } + + // + // Load Plugins + // + QString sql; + RDSqlQuery *q; + + // + // Load Plugins + // + sql=QString().sprintf("select PLUGIN_PATH,PLUGIN_ARG from NOWNEXT_PLUGINS \ + where (STATION_NAME=\"%s\")&&(LOG_MACHINE=0)", + (const char *) + RDEscapeString(air_config->stationName())); + q=new RDSqlQuery(sql); + while(q->next()) { + air_plugin_hosts. + push_back(new RLMHost(q->value(0).toString(),q->value(1).toString(), + air_nownext_socket,this)); + LogLine(RDConfig::LogInfo,QString(). + sprintf("Loading RLM \"%s\"", + (const char *)q->value(0).toString())); + if(!air_plugin_hosts.back()->load()) { + LogLine(RDConfig::LogWarning,QString(). + sprintf("Failed to load RLM \"%s\"", + (const char *)q->value(0).toString())); + } + } + delete q; + + // Create the HotKeyList object + // + rdkeylist = new RDHotKeyList(); + rdhotkeys = new RDHotkeys(RDEscapeString(air_config->stationName()), + "airplay"); + AltKeyHit = false; + CtrlKeyHit = false; + + // + // Set Signal Handlers + // + signal(SIGCHLD,SigHandler); + + // + // Start the RIPC Connection + // + rdripc->connectHost("localhost",RIPCD_TCP_PORT,air_config->password()); + + LogLine(RDConfig::LogInfo,"RDAirPlay started"); +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(1024,738); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::ripcConnected(bool state) +{ + QString logname; + QHostAddress addr; + QString sql; + RDSqlQuery *q; + RDMacro rml; + rml.setRole(RDMacro::Cmd); + addr.setAddress("127.0.0.1"); + rml.setAddress(addr); + rml.setEchoRequested(false); + + // + // Get Onair Flag State + // + rdripc->sendOnairFlag(); + + // + // Load Initial Logs + // + for(unsigned i=0;istartMode(i)) { + case RDAirPlayConf::StartEmpty: + break; + + case RDAirPlayConf::StartPrevious: + air_start_logname[i]= + RDDateTimeDecode(rdairplay_conf->currentLog(i), + air_startup_datetime); + if(!air_start_logname[i].isEmpty()) { + if(rdairplay_previous_exit_code==RDAirPlayConf::ExitDirty) { + if((air_start_line[i]=rdairplay_conf->logCurrentLine(i))>=0) { + air_start_start[i]=rdairplay_conf->autoRestart(i)&& + rdairplay_conf->logRunning(i); + } + } + else { + air_start_line[i]=0; + air_start_start[i]=false; + } + } + break; + + case RDAirPlayConf::StartSpecified: + air_start_logname[i]= + RDDateTimeDecode(rdairplay_conf->logName(i), + air_startup_datetime); + if(!air_start_logname[i].isEmpty()) { + if(rdairplay_previous_exit_code==RDAirPlayConf::ExitDirty) { + if(air_start_logname[i]==rdairplay_conf->currentLog(i)) { + if((air_start_line[i]=rdairplay_conf->logCurrentLine(i))>= + 0) { + air_start_start[i]=rdairplay_conf->autoRestart(i)&& + rdairplay_conf->logRunning(i); + } + else { + air_start_line[i]=0; + air_start_start[i]=false; + } + } + } + } + break; + } + } + if(!air_start_logname[i].isEmpty()) { + sql=QString().sprintf("select NAME from LOGS where NAME=\"%s\"", + (const char *)air_start_logname[i]); + q=new RDSqlQuery(sql); + if(q->first()) { + rml.setCommand(RDMacro::LL); // Load Log + rml.setArgQuantity(2); + rml.setArg(0,i+1); + rml.setArg(1,air_start_logname[i]); + rdripc->sendRml(&rml); + } + else { + fprintf(stderr,"rdairplay: log \"%s\" doesn't exist\n", + (const char *)air_start_logname[i]); + } + delete q; + } + } +} + + +void MainWidget::rmlReceivedData(RDMacro *rml) +{ + RunLocalMacros(rml); +} + + +void MainWidget::gpiStateChangedData(int matrix,int line,bool state) +{ + // + // Main Logs + // + for(unsigned i=0;i<2;i++) { + if(state) { + if((air_start_gpi_matrices[i]==matrix)&& + (air_start_gpi_lines[i]==line)) { + if(AssertChannelLock(1,air_audio_channels[i])) { + air_log[0]->channelPlay(i); + } + } + } + else { + if((air_stop_gpi_matrices[i]==matrix)&& + (air_stop_gpi_lines[i]==line)) { + air_log[0]->channelStop(i); + } + } + } + + // + // Aux Logs + // + for(unsigned i=4;i<6;i++) { + if(state) { + if((air_start_gpi_matrices[i]==matrix)&& + (air_start_gpi_lines[i]==line)) { + if(air_channel_timers[0][air_audio_channels[i]]->isActive()) { + air_channel_timers[0][air_audio_channels[i]]->stop(); + } + else { + air_channel_timers[1][air_audio_channels[i]]-> + start(AIR_CHANNEL_LOCKOUT_INTERVAL,true); + air_log[i-3]->channelPlay(0); + } + } + } + else { + if((air_stop_gpi_matrices[i]==matrix)&& + (air_stop_gpi_lines[i]==line)) { + air_log[i-3]->channelStop(0); + } + } + } + + // + // Sound Panel + // + if(!state) { + if((air_stop_gpi_matrices[RDAirPlayConf::SoundPanel1Channel]==matrix)&& + (air_stop_gpi_lines[RDAirPlayConf::SoundPanel1Channel]==line)) { + air_panel->channelStop(0); + } + for(unsigned i=6;i<10;i++) { + if((air_stop_gpi_matrices[i]==matrix)&& + (air_stop_gpi_lines[i]==line)) { + air_panel->channelStop(i-5); + } + } + } +} + + +void MainWidget::logChannelStartedData(int id,int mport,int card,int port) +{ + if(!AssertChannelLock(0,card,port)) { + return; + } + switch(id) { + case 0: // Main Log + switch(mport) { + case 0: + if(air_start_gpo_matrices[RDAirPlayConf::MainLog1Channel]>=0) { + switch(air_channel_gpio_types[RDAirPlayConf::MainLog1Channel]) { + case RDAirPlayConf::LevelGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 0!", + air_start_gpo_matrices[RDAirPlayConf::MainLog1Channel], + air_start_gpo_lines[RDAirPlayConf::MainLog1Channel]+1)); + break; + + case RDAirPlayConf::EdgeGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 300!", + air_start_gpo_matrices[RDAirPlayConf::MainLog1Channel], + air_start_gpo_lines[RDAirPlayConf::MainLog1Channel]+1)); + break; + } + } + break; + + case 1: + if(air_start_gpo_matrices[RDAirPlayConf::MainLog2Channel]>=0) { + switch(air_channel_gpio_types[RDAirPlayConf::MainLog2Channel]) { + case RDAirPlayConf::LevelGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 0!", + air_start_gpo_matrices[RDAirPlayConf::MainLog2Channel], + air_start_gpo_lines[RDAirPlayConf::MainLog2Channel]+1)); + break; + + case RDAirPlayConf::EdgeGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 300!", + air_start_gpo_matrices[RDAirPlayConf::MainLog2Channel], + air_start_gpo_lines[RDAirPlayConf::MainLog2Channel]+1)); + break; + } + } + break; + } + break; + + case 1: // Aux Log 1 + if(air_start_gpo_matrices[RDAirPlayConf::AuxLog1Channel]>=0) { + switch(air_channel_gpio_types[RDAirPlayConf::AuxLog1Channel]) { + case RDAirPlayConf::LevelGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 0!", + air_start_gpo_matrices[RDAirPlayConf::AuxLog1Channel], + air_start_gpo_lines[RDAirPlayConf::AuxLog1Channel]+1)); + break; + + case RDAirPlayConf::EdgeGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 300!", + air_start_gpo_matrices[RDAirPlayConf::AuxLog1Channel], + air_start_gpo_lines[RDAirPlayConf::AuxLog1Channel]+1)); + break; + } + } + break; + + case 2: // Aux Log 2 + if(air_start_gpo_matrices[RDAirPlayConf::AuxLog2Channel]>=0) { + switch(air_channel_gpio_types[RDAirPlayConf::AuxLog2Channel]) { + case RDAirPlayConf::LevelGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 0!", + air_start_gpo_matrices[RDAirPlayConf::AuxLog2Channel], + air_start_gpo_lines[RDAirPlayConf::AuxLog2Channel]+1)); + break; + + case RDAirPlayConf::EdgeGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 300!", + air_start_gpo_matrices[RDAirPlayConf::AuxLog2Channel], + air_start_gpo_lines[RDAirPlayConf::AuxLog2Channel]+1)); + break; + } + } + break; + } +} + + +void MainWidget::logChannelStoppedData(int id,int mport,int card,int port) +{ + switch(id) { + case 0: // Main Log + switch(mport) { + case 0: + if(air_stop_gpo_matrices[RDAirPlayConf::MainLog1Channel]>=0) { + switch(air_channel_gpio_types[RDAirPlayConf::MainLog1Channel]) { + case RDAirPlayConf::LevelGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 0 0!", + air_stop_gpo_matrices[RDAirPlayConf::MainLog1Channel], + air_stop_gpo_lines[RDAirPlayConf::MainLog1Channel]+1)); + break; + + case RDAirPlayConf::EdgeGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 300!", + air_stop_gpo_matrices[RDAirPlayConf::MainLog1Channel], + air_stop_gpo_lines[RDAirPlayConf::MainLog1Channel]+1)); + break; + } + } + break; + + case 1: + if(air_stop_gpo_matrices[RDAirPlayConf::MainLog2Channel]>=0) { + switch(air_channel_gpio_types[RDAirPlayConf::MainLog2Channel]) { + case RDAirPlayConf::LevelGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 0 0!", + air_stop_gpo_matrices[RDAirPlayConf::MainLog2Channel], + air_stop_gpo_lines[RDAirPlayConf::MainLog2Channel]+1)); + break; + + case RDAirPlayConf::EdgeGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 300!", + air_stop_gpo_matrices[RDAirPlayConf::MainLog2Channel], + air_stop_gpo_lines[RDAirPlayConf::MainLog2Channel]+1)); + break; + } + } + break; + } + break; + + case 1: // Aux Log 1 + if(air_stop_gpo_matrices[RDAirPlayConf::AuxLog1Channel]>=0) { + switch(air_channel_gpio_types[RDAirPlayConf::AuxLog1Channel]) { + case RDAirPlayConf::LevelGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 0 0!", + air_stop_gpo_matrices[RDAirPlayConf::AuxLog1Channel], + air_stop_gpo_lines[RDAirPlayConf::AuxLog1Channel]+1)); + break; + + case RDAirPlayConf::EdgeGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 300!", + air_stop_gpo_matrices[RDAirPlayConf::AuxLog1Channel], + air_stop_gpo_lines[RDAirPlayConf::AuxLog1Channel]+1)); + break; + } + } + break; + + case 2: // Aux Log 2 + if(air_stop_gpo_matrices[RDAirPlayConf::AuxLog2Channel]>=0) { + switch(air_channel_gpio_types[RDAirPlayConf::AuxLog2Channel]) { + case RDAirPlayConf::LevelGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 0 0!", + air_stop_gpo_matrices[RDAirPlayConf::AuxLog2Channel], + air_stop_gpo_lines[RDAirPlayConf::AuxLog2Channel]+1)); + break; + + case RDAirPlayConf::EdgeGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 300!", + air_stop_gpo_matrices[RDAirPlayConf::AuxLog2Channel], + air_stop_gpo_lines[RDAirPlayConf::AuxLog2Channel]+1)); + break; + } + } + break; + } +} + + +void MainWidget::panelChannelStartedData(int mport,int card,int port) +{ + if(!AssertChannelLock(0,card,port)) { + return; + } + RDAirPlayConf::Channel chan=PanelChannel(mport); + if(air_start_gpo_matrices[chan]>=0) { + switch(air_channel_gpio_types[chan]) { + case RDAirPlayConf::LevelGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 0!", + air_start_gpo_matrices[chan], + air_start_gpo_lines[chan]+1)); + break; + + case RDAirPlayConf::EdgeGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 300!", + air_start_gpo_matrices[chan], + air_start_gpo_lines[chan]+1)); + break; + } + } +} + + +void MainWidget::panelChannelStoppedData(int mport,int card,int port) +{ + RDAirPlayConf::Channel chan=PanelChannel(mport); + + if(air_stop_gpo_matrices[chan]>=0) { + switch(air_channel_gpio_types[chan]) { + case RDAirPlayConf::LevelGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 0 0!", + air_stop_gpo_matrices[chan], + air_stop_gpo_lines[chan]+1)); + break; + + case RDAirPlayConf::EdgeGpio: + rdevent_player-> + exec(QString().sprintf("GO %d %d 1 300!", + air_stop_gpo_matrices[chan], + air_stop_gpo_lines[chan]+1)); + break; + } + } +} + + +void MainWidget::logRenamedData(int log) +{ + QString str; + QString logname= + air_log[log]->logName().left(air_log[log]->logName().length()-4); + QString labelname=logname; + if(logname.isEmpty()) { + labelname="--"; + } + switch(log) { + case 0: + str=QString(tr("Main Log")); + air_log_button[0]-> + setText(QString().sprintf("%s\n[%s]",(const char *)str, + (const char *)labelname)); + SetCaption(); + if(air_panel) { + air_panel->setLogName(logname); + } + break; + + case 1: + str=QString(tr("Aux 1 Log")); + air_log_button[1]-> + setText(QString().sprintf("%s\n[%s]",(const char *)str, + (const char *)labelname)); + break; + + case 2: + str=QString(tr("Aux 2 Log")); + air_log_button[2]-> + setText(QString().sprintf("%s\n[%s]",(const char *)str, + (const char *)labelname)); + break; + } +} + + +void MainWidget::logReloadedData(int log) +{ + QString str; + QHostAddress addr; + QString labelname= + air_log[log]->logName().left(air_log[log]->logName().length()-4); + if(labelname.isEmpty()) { + labelname="--"; + } + + switch(log) { + case 0: + str=QString(tr("Main Log")); + air_log_button[0]-> + setText(QString().sprintf("%s\n[%s]",(const char *)str, + (const char *)labelname)); + LogLine(RDConfig::LogInfo,QString(). + sprintf("loaded log '%s' in Main Log", + (const char *)air_log[0]->logName(). + left(air_log[0]->logName().length()-4))); + if(air_log[0]->logName().isEmpty()) { + if(air_panel!=NULL) { + if(rdstation_conf->broadcastSecurity()==RDStation::UserSec) { + air_panel->setSvcName( + rduser->serviceCheckDefault( rdairplay_conf->defaultSvc() ) ); + } else { // RDStation::HostSec + air_panel->setSvcName(rdairplay_conf->defaultSvc()); + } + } + } + else { + if(air_panel!=NULL) { + air_panel->setSvcName(air_log[0]->serviceName()); + } + } + break; + + case 1: + str=QString(tr("Aux 1 Log")); + air_log_button[1]-> + setText(QString().sprintf("%s\n[%s]",(const char *)str, + (const char *)labelname)); + LogLine(RDConfig::LogInfo,QString(). + sprintf("loaded log '%s' in Aux 1 Log", + (const char *)air_log[1]->logName(). + left(air_log[1]->logName().length()-4))); + break; + + case 2: + str=QString(tr("Aux 2 Log")); + air_log_button[2]-> + setText(QString().sprintf("%s\n[%s]",(const char *)str, + (const char *)labelname)); + LogLine(RDConfig::LogInfo,QString(). + sprintf("loaded log '%s' in Aux 2 Log", + (const char *)air_log[2]->logName(). + left(air_log[2]->logName().length()-4))); + break; + } + SetCaption(); + + // + // Load Initial Log + // + if(air_start_logname[log].isEmpty()) { + return; + } + RDMacro rml; + rml.setRole(RDMacro::Cmd); + addr.setAddress("127.0.0.1"); + rml.setAddress(addr); + rml.setEchoRequested(false); + + if(air_start_line[log]size()) { + rml.setCommand(RDMacro::MN); // Make Next + rml.setArgQuantity(2); + rml.setArg(0,log+1); + rml.setArg(1,air_start_line[log]); + rdripc->sendRml(&rml); + + if(air_start_start[log]) { + rml.setCommand(RDMacro::PN); // Start Next + rml.setArgQuantity(1); + rml.setArg(0,log+1); + rdripc->sendRml(&rml); + } + } + else { + fprintf(stderr,"rdairplay: line %d doesn't exist in log \"%s\"\n", + air_start_line[log],(const char *)air_start_logname[log]); + } + air_start_logname[log]=""; +} + + +void MainWidget::userData() +{ + if(rduser!=NULL) { + delete rduser; + } + rduser=new RDUser(rdripc->user()); + LogLine(RDConfig::LogInfo,QString(). + sprintf("user changed to '%s'",(const char *)rdripc->user())); + SetCaption(); + + // + // Set Control Perms + // + bool add_allowed=rduser->addtoLog(); + bool delete_allowed=rduser->removefromLog(); + bool arrange_allowed=rduser->arrangeLog(); + bool playout_allowed=rduser->playoutLog(); + + air_add_button->setEnabled(add_allowed&&arrange_allowed&&playout_allowed); + air_move_button->setEnabled(arrange_allowed&&playout_allowed); + air_delete_button-> + setEnabled(delete_allowed&&arrange_allowed&&playout_allowed); + air_copy_button->setEnabled(add_allowed&&arrange_allowed&&playout_allowed); + for(int i=0;iuserChanged(add_allowed,delete_allowed, + arrange_allowed,playout_allowed); + } + + // Update default services for the new user, if applicable. + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec) { + QString default_svcname = + rduser->serviceCheckDefault( rdairplay_conf->defaultSvc() ); + for(int i=0;isetDefaultServiceName(default_svcname); + } + if(air_panel!=NULL) { + air_panel->setSvcName(default_svcname); + } + } + +} + + +void MainWidget::addButtonData() +{ + if((air_action_mode==StartButton::AddFrom)|| + (air_action_mode==StartButton::AddTo)) { + SetActionMode(StartButton::Stop); + } + else { + SetActionMode(StartButton::AddFrom); + } +} + + +void MainWidget::deleteButtonData() +{ + if(air_action_mode==StartButton::DeleteFrom) { + SetActionMode(StartButton::Stop); + } + else { + SetActionMode(StartButton::DeleteFrom); + } +} + + +void MainWidget::moveButtonData() +{ + if((air_action_mode==StartButton::MoveFrom)|| + (air_action_mode==StartButton::MoveTo)) { + SetActionMode(StartButton::Stop); + } + else { + SetActionMode(StartButton::MoveFrom); + } +} + + +void MainWidget::copyButtonData() +{ + if((air_action_mode==StartButton::CopyFrom)|| + (air_action_mode==StartButton::CopyTo)) { + SetActionMode(StartButton::Stop); + } + else { + SetActionMode(StartButton::CopyFrom); + } +} + + +void MainWidget::fullLogButtonData(int id) +{ +#ifdef SHOW_SLOTS + printf("fullLogButtonData()\n"); +#endif + if(air_log_list[id]->isVisible()) { + return; + } + else { + for(int i=0;iisVisible()) { + air_log_list[i]->hide(); + air_log_button[i]->setPalette(palette()); + } + } + air_log_list[id]->show(); + air_log_button[id]->setPalette(active_color); + if (air_panel_button) air_panel_button->setPalette(palette()); + } +} + + +void MainWidget::panelButtonData() +{ + for(int i=0;iisVisible()) { + air_log_list[i]->hide(); + air_log_button[i]->setPalette(palette()); + } + } + air_panel_button->setPalette(active_color); +} + + +void MainWidget::modeButtonData() +{ + int mach=-1; + switch(air_op_mode_style) { + case RDAirPlayConf::Unified: + mach=-1; + break; + + case RDAirPlayConf::Independent: + mach=0; + break; + } + switch(air_op_mode[0]) { + case RDAirPlayConf::Manual: + SetMode(mach,RDAirPlayConf::LiveAssist); + break; + + case RDAirPlayConf::LiveAssist: + SetMode(mach,RDAirPlayConf::Auto); + break; + + case RDAirPlayConf::Auto: + SetMode(mach,RDAirPlayConf::Manual); + break; + + default: + break; + } +} + + +void MainWidget::selectClickedData(int id,int line,RDLogLine::Status status) +{ + RDLogLine *logline; + + switch(air_action_mode) { + case StartButton::AddTo: + if(line<0) { + air_log[id]-> + insert(air_log[id]->size(),air_add_cart,RDLogLine::Play); + air_log[id]->logLine(air_log[id]->size()-1)-> + setTransType(rdairplay_conf->defaultTransType()); + air_log_list[id]->refresh(air_log[id]->size()-1); + } + else { + air_log[id]-> + insert(line,air_add_cart,air_log[id]->nextTransType(line)); + air_log[id]->logLine(line)-> + setTransType(rdairplay_conf->defaultTransType()); + air_log_list[id]->refresh(line); + } + SetActionMode(StartButton::Stop); + break; + + case StartButton::DeleteFrom: + if(status==RDLogLine::Finished) { + return; + } + air_log[id]->remove(line,1); + SetActionMode(StartButton::Stop); + break; + + case StartButton::MoveFrom: + if((logline=air_log[id]->logLine(line))!=NULL) { + air_copy_line=line; + air_add_cart=logline->cartNumber(); + air_source_id=id; + SetActionMode(StartButton::MoveTo); + } + else { + SetActionMode(StartButton::Stop); + } + break; + + case StartButton::MoveTo: + if(air_source_id==id) { + if(line<0) { + air_log[id]->move(air_copy_line,air_log[id]->size()); + air_log_list[id]->refresh(air_log[id]->size()-1); + } + else { + if(line>air_copy_line) { + line--; + } + air_log[id]->move(air_copy_line,line); + air_log_list[id]->refresh(line); + } + } + else { + air_log[air_source_id]->remove(air_copy_line,1); + if(line<0) { + air_log[id]-> + insert(air_log[id]->size(),air_add_cart,RDLogLine::Play); + air_log_list[id]->refresh(air_log[id]->size()-1); + + } + else { + air_log[id]-> + insert(line,air_add_cart,air_log[id]->nextTransType(line)); + air_log_list[id]->refresh(line); + } + } + SetActionMode(StartButton::Stop); + break; + + case StartButton::CopyFrom: + if((logline=air_log[id]->logLine(line))!=NULL) { + air_copy_line=line; + air_add_cart=logline->cartNumber(); + air_source_id=id; + SetActionMode(StartButton::CopyTo); + } + else { + SetActionMode(StartButton::Stop); + } + break; + + case StartButton::CopyTo: + if(air_source_id==id) { + if(line<0) { + air_log[id]->copy(air_copy_line,air_log[id]->size()); + } + else { + air_log[id]->copy(air_copy_line,line); + } + } + else { + if(line<0) { + air_log[id]->insert(air_log[id]->size(),air_add_cart, + rdairplay_conf->defaultTransType(), + rdairplay_conf->defaultTransType()); + air_log[id]->logLine(air_log[id]->size()-1)-> + setTransType(rdairplay_conf->defaultTransType()); + air_log_list[id]->refresh(air_log[id]->size()-1); + } + else { + air_log[id]-> + insert(line,air_add_cart,air_log[id]->nextTransType(line), + rdairplay_conf->defaultTransType()); + air_log[id]->logLine(line)-> + setTransType(rdairplay_conf->defaultTransType()); + air_log_list[id]->refresh(line); + } + } + SetActionMode(StartButton::Stop); + break; + + default: + break; + } +} + + +void MainWidget::selectClickedData(unsigned cartnum,int row,int col) +{ + switch(air_action_mode) { + case StartButton::CopyFrom: + air_copy_line=-1; + air_add_cart=cartnum; + air_source_id=-1; + SetActionMode(StartButton::CopyTo); + break; + + case StartButton::CopyTo: + if(air_panel!=NULL) { + air_panel->setButton(air_panel->currentType(), + air_panel->currentNumber(),row,col,air_add_cart); + } + SetActionMode(StartButton::Stop); + break; + + case StartButton::AddTo: + if(air_panel!=NULL) { + air_panel->setButton(air_panel->currentType(), + air_panel->currentNumber(),row,col,air_add_cart); + } + SetActionMode(StartButton::Stop); + break; + + case StartButton::DeleteFrom: + if(air_panel!=NULL) { + air_panel->setButton(air_panel->currentType(), + air_panel->currentNumber(),row,col,0); + } + SetActionMode(StartButton::Stop); + break; + + default: + break; + } +} + + +void MainWidget::cartDroppedData(int id,int line,RDLogLine *ll) +{ + if(ll->cartNumber()==0) { + air_log[id]->remove(line,1); + } + else { + if(line<0) { + air_log[id]-> + insert(air_log[id]->size(),ll->cartNumber(),RDLogLine::Play); + air_log[id]->logLine(air_log[id]->size()-1)-> + setTransType(rdairplay_conf->defaultTransType()); + air_log_list[id]->refresh(air_log[id]->size()-1); + } + else { + air_log[id]-> + insert(line,ll->cartNumber(),air_log[id]->nextTransType(line)); + air_log[id]->logLine(line)-> + setTransType(rdairplay_conf->defaultTransType()); + air_log_list[id]->refresh(line); + } + } +} + + +void MainWidget::meterData() +{ +#ifdef SHOW_METER_SLOTS + printf("meterData()\n"); +#endif + double ratio[2]={0.0,0.0}; + short level[2]; + + for(int i=0;ioutputMeterUpdate(air_meter_card[i],air_meter_port[i],level); + for(int j=0;j<2;j++) { + ratio[j]+=pow(10.0,((double)level[j])/1000.0); + } + } + } + air_stereo_meter->setLeftPeakBar((int)(log10(ratio[0])*1000.0)); + air_stereo_meter->setRightPeakBar((int)(log10(ratio[1])*1000.0)); +} + + +void MainWidget::masterTimerData() +{ + static unsigned counter=0; + static QTime last_time=QTime::currentTime(); + + if(counter++>=5) { + QTime current_time=QTime::currentTime(); + if(current_timeresync(); + } + } + last_time=current_time; + counter=0; + } +} + + +void MainWidget::transportChangedData() +{ + int lines[TRANSPORT_QUANTITY]; + int line=0; + int count; + QTime end_time; + RDLogLine *logline; + RDLogLine *next_logline; + RDAirPlayConf::PieEndPoint pie_end=RDAirPlayConf::CartEnd; + + if((count=air_log[0]->runningEvents(lines,false))>0) { + for(int i=0;ilogLine(lines[i]))!=NULL) { + switch(logline->type()) { + case RDLogLine::Cart: + if(logline->startTime(RDLogLine::Actual). + addMSecs(logline->effectiveLength()- + ((RDPlayDeck *)logline->playDeck())-> + lastStartPosition())>end_time) { + end_time=logline->startTime(RDLogLine::Actual). + addMSecs(logline->effectiveLength()- + ((RDPlayDeck *)logline->playDeck())-> + lastStartPosition()); + line=lines[i]; + } + break; + + case RDLogLine::Macro: + line=lines[i]; + break; + + default: + break; + } + } + } + + logline=air_log[0]->logLine(line); + switch(air_op_mode[0]) { + case RDAirPlayConf::Manual: + case RDAirPlayConf::LiveAssist: + pie_end=RDAirPlayConf::CartEnd; + break; + + case RDAirPlayConf::Auto: + pie_end=air_pie_end; + break; + + default: + break; + } + if(logline->effectiveLength()>0) { + if((air_pie_counter->line()!=logline->id())) { + switch(pie_end) { + case RDAirPlayConf::CartEnd: + air_pie_counter->setTime(logline->effectiveLength()); + break; + + case RDAirPlayConf::CartTransition: + if((next_logline=air_log[0]-> + logLine(air_log[0]->nextLine(line)))!=NULL) { + if((unsigned)logline->startTime(RDLogLine::Actual). + msecsTo(QTime::currentTime())< + logline->segueLength(next_logline->transType())- + logline->playPosition()) { + air_pie_counter-> + setTime(logline->segueLength(next_logline->transType())); + } + else { + air_pie_counter->setTime(logline->effectiveLength()); + } + } + else { + air_pie_counter->setTime(logline->effectiveLength()); + } + break; + } + if(logline->talkStartPoint()==0) { + air_pie_counter->setTalkStart(0); + air_pie_counter->setTalkEnd(logline->talkEndPoint()); + } + else { + air_pie_counter-> + setTalkStart(logline->talkStartPoint()-logline-> + startPoint()); + air_pie_counter-> + setTalkEnd(logline->talkEndPoint()-logline-> + startPoint()); + } + air_pie_counter->setTransType(air_log[0]->nextTrans(line)); + if(logline->playDeck()==NULL) { + air_pie_counter->setLogline(NULL); + air_pie_counter->start(rdstation_conf->timeOffset()); + } + else { + air_pie_counter->setLogline(logline); + air_pie_counter->start(((RDPlayDeck *)logline->playDeck())-> + currentPosition()+ + rdstation_conf->timeOffset()); + } + } + } + else { + air_pie_counter->stop(); + air_pie_counter->resetTime(); + air_pie_counter->setLine(-1); + } + } + else { + air_pie_counter->stop(); + air_pie_counter->resetTime(); + air_pie_counter->setLine(-1); + } +} + + +void MainWidget::timeModeData(RDAirPlayConf::TimeMode mode) +{ + air_button_list->setTimeMode(mode); + for(int i=0;isetTimeMode(mode); + } + air_stop_counter->setTimeMode(mode); + air_post_counter->setTimeMode(mode); +} + + +void MainWidget::refreshStatusChangedData(bool active) +{ + if(active) { + air_refresh_label->setErasePixmap(QPixmap()); + air_refresh_label->setText(tr("LOG\nREFRESHING")); + } + else { + if(air_refresh_pixmap!=NULL) { + air_refresh_label->setErasePixmap(*air_refresh_pixmap); + } + air_refresh_label->setText(""); + } + qApp->processEvents(); +} + + +void MainWidget::clearSplashData() +{ + air_splash_screen->hide(); + delete air_splash_screen; + air_splash_screen=NULL; +} + + +void MainWidget::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Space: + break; + + case Qt::Key_X: + if(((e->state()&AltButton)!=0)&& + ((e->state()&ShiftButton)==0)&&((e->state()&ControlButton)==0)) { + QCloseEvent *ce=new QCloseEvent(); + closeEvent(ce); + delete ce; + } + break; + + case Qt::Key_Alt: + keystrokecount++; + AltKeyHit = true; + break; + + case Qt::Key_Control: + keystrokecount++; + CtrlKeyHit = true; + break; + + default: + QWidget::keyPressEvent(e); + break; + } +} + +void MainWidget::keyReleaseEvent(QKeyEvent *e) +{ + int keyhit = e->key(); + QString mystring=(*rdkeylist).GetKeyCode(keyhit); + QString hotkeystrokes; + QString hot_label; + QString temp_string; + + switch(e->key()) { + case Qt::Key_Space: + switch(air_bar_action) { + case RDAirPlayConf::StartNext: + if(!e->isAutoRepeat()){ + air_log[0]-> + play(air_log[0]->nextLine(),RDLogLine::StartManual); + } + break; + + default: + break; + } + break; + } +// Try to figure out if this is a hot key combination + if ( (e->key() == Qt::Key_Shift) || + (e->key() == Qt::Key_Up) || + (e->key() == Qt::Key_Left) || + (e->key() == Qt::Key_Right) || + (e->key() == Qt::Key_Down) ) { + QWidget::keyReleaseEvent(e); + keystrokecount = 0; + hotkeystrokes = QString (""); + return; + } + + if ((e->key() == Qt::Key_Alt) || + (e->key() == Qt::Key_Control)) { + if (keystrokecount != 0 ) hotkeystrokes = QString (""); + if (AltKeyHit) { + AltKeyHit = false; + if (keystrokecount > 0) keystrokecount--; + } + if (CtrlKeyHit) { + CtrlKeyHit = false; + if (keystrokecount > 0) keystrokecount--; + } + return; + } + + if (!e->isAutoRepeat()) { + if (keystrokecount == 0) + hotkeystrokes = QString (""); + if (AltKeyHit) { + hotkeystrokes = (*rdkeylist).GetKeyCode(Qt::Key_Alt); + hotkeystrokes += QString(" + "); + } + if (CtrlKeyHit) { + if (AltKeyHit) { + hotkeystrokes += (*rdkeylist).GetKeyCode(Qt::Key_Control); + hotkeystrokes += QString (" + "); + } + else { + hotkeystrokes = (*rdkeylist).GetKeyCode(Qt::Key_Control); + hotkeystrokes += QString (" + "); + } + } + + hotkeystrokes += mystring; + keystrokecount = 0 ; + } + + // Have any Hot Key Combinations now... + + if (hotkeystrokes.length() > 0) { + + hot_label=(*rdhotkeys).GetRowLabel(RDEscapeString(air_config->stationName()), + (const char *)"airplay",(const char *)hotkeystrokes); + + if (hot_label.length()>0) { + + // "we found a keystroke label + + if (strcmp(hot_label,"Add") == 0) + { + addButtonData(); + return; + } + + if (strcmp(hot_label,"Delete") == 0) + { + deleteButtonData(); + return; + } + + if (strcmp(hot_label,"Copy") == 0) + { + copyButtonData(); + return; + } + + if (strcmp(hot_label,"Move") == 0) + { + moveButtonData(); + return; + } + + if (strcmp(hot_label,"Sound Panel") == 0) + { + panelButtonData(); + return; + } + + if (strcmp(hot_label,"Main Log") == 0) + { + fullLogButtonData(0); + return; + } + + if ((strcmp(hot_label,"Aux Log 1") == 0) && + (rdairplay_conf->showAuxButton(0) ) ) + { + fullLogButtonData(1); + return; + } + + if ( (strcmp(hot_label,"Aux Log 2") == 0) && + (rdairplay_conf->showAuxButton(1) ) ) + { + fullLogButtonData(2); + return; + } + + for (int i = 1; i < 8 ; i++) + { + temp_string = QString().sprintf("Start Line %d",i); + if (strcmp(hot_label,temp_string) == 0) + air_button_list->startButton(i-1); + + temp_string = QString().sprintf("Stop Line %d",i); + if (strcmp(hot_label,temp_string) == 0) + air_button_list->stopButtonHotkey(i-1); + + temp_string = QString().sprintf("Pause Line %d",i); + if (strcmp(hot_label,temp_string) == 0) + air_button_list->pauseButtonHotkey(i-1); + } + } + } + QWidget::keyReleaseEvent(e); +} + +void MainWidget::closeEvent(QCloseEvent *e) +{ + if(!rdairplay_conf->exitPasswordValid("")) { + QString passwd; + RDGetPasswd *gw=new RDGetPasswd(&passwd,this); + gw->exec(); + if(!rdairplay_conf->exitPasswordValid(passwd)) { + return; + } + rdairplay_conf->setExitCode(RDAirPlayConf::ExitClean); + LogLine(RDConfig::LogInfo,"RDAirPlay exiting"); + air_lock->unlock(); + exit(0); + } + if(QMessageBox::question(this,"",tr("Exit RDAirPlay?"), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + return; + } + for(unsigned i=0;iunload(); + } + for(int i=0;isetExitCode(RDAirPlayConf::ExitClean); + LogLine(RDConfig::LogInfo,"RDAirPlay exiting"); + air_lock->unlock(); + exit(0); +} + + +void MainWidget::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(black); + p->fillRect(10,70,410,air_stereo_meter->sizeHint().height(),black); + p->end(); + delete p; +} + + +void SigHandler(int signo) +{ + pid_t pLocalPid; + + switch(signo) { + case SIGCHLD: + pLocalPid=waitpid(-1,NULL,WNOHANG); + while(pLocalPid>0) { + pLocalPid=waitpid(-1,NULL,WNOHANG); + } + signal(SIGCHLD,SigHandler); + return; + } +} + + +void MainWidget::SetCaption() +{ + QString log=air_log[0]->logName(); + if(log.isEmpty()) { + log="-- "; + } + setCaption(QString("RDAirPlay")+" v"+VERSION+" - "+tr("Host")+": "+ + air_config->stationName()+" "+ + tr("User:")+" "+rdripc->user()+" "+ + tr("Log:")+" "+log.left(log.length()-4)+" "+ + tr("Service:")+" "+air_log[0]->serviceName()); +} + + +void MainWidget::SetMode(int mach,RDAirPlayConf::OpMode mode) +{ + if(mach<0) { + for(int i=0;isetOpMode(RDAirPlayConf::Manual); + } + air_mode_display->setOpMode(mach,RDAirPlayConf::Manual); + air_op_mode[mach]=RDAirPlayConf::Manual; + rdairplay_conf->setOpMode(mach,RDAirPlayConf::Manual); + air_log[mach]->setOpMode(RDAirPlayConf::Manual); + air_log_list[mach]->setOpMode(RDAirPlayConf::Manual); + if(mach==0) { + air_button_list->setOpMode(RDAirPlayConf::Manual); + air_post_counter->setDisabled(true); + } + LogLine(RDConfig::LogInfo, + QString().sprintf("log machine %d mode set to MANUAL",mach+1)); +} + + +void MainWidget::SetAutoMode(int mach) +{ + if(mach<0) { + for(int i=0;isetOpMode(RDAirPlayConf::Auto); + } + air_mode_display->setOpMode(mach,RDAirPlayConf::Auto); + air_op_mode[mach]=RDAirPlayConf::Auto; + rdairplay_conf->setOpMode(mach,RDAirPlayConf::Auto); + air_log[mach]->setOpMode(RDAirPlayConf::Auto); + air_log_list[mach]->setOpMode(RDAirPlayConf::Auto); + if(mach==0) { + air_button_list->setOpMode(RDAirPlayConf::Auto); + air_post_counter->setEnabled(true); + } + LogLine(RDConfig::LogInfo, + QString().sprintf("log machine %d mode set to AUTO",mach+1)); +} + + +void MainWidget::SetLiveAssistMode(int mach) +{ + if(mach<0) { + for(int i=0;isetOpMode(RDAirPlayConf::LiveAssist); + } + air_mode_display->setOpMode(mach,RDAirPlayConf::LiveAssist); + air_op_mode[mach]=RDAirPlayConf::LiveAssist; + rdairplay_conf->setOpMode(mach,RDAirPlayConf::LiveAssist); + air_log[mach]->setOpMode(RDAirPlayConf::LiveAssist); + air_log_list[mach]->setOpMode(RDAirPlayConf::LiveAssist); + if(mach==0) { + air_button_list->setOpMode(RDAirPlayConf::LiveAssist); + air_post_counter->setDisabled(true); + } + LogLine(RDConfig::LogInfo, + QString().sprintf("log machine %d mode set to LIVE ASSIST",mach+1)); +} + + +void MainWidget::SetActionMode(StartButton::Mode mode) +{ + QString svc_name[RD_MAX_DEFAULT_SERVICES]; + int svc_quan=0; + QString sql; + RDSqlQuery *q; + QStringList services_list; + + if(air_action_mode==mode) { + return; + } + air_action_mode=mode; + switch(mode) { + case StartButton::Stop: + air_add_button->setFlashingEnabled(false); + air_delete_button->setFlashingEnabled(false); + air_move_button->setFlashingEnabled(false); + air_copy_button->setFlashingEnabled(false); + for(int i=0;isetActionMode(RDAirPlayConf::Normal); + } + air_button_list->setActionMode(RDAirPlayConf::Normal); + if(air_panel!=NULL) { + air_panel->setActionMode(RDAirPlayConf::Normal); + } + + break; + + case StartButton::AddFrom: + if(air_clear_filter) { + air_add_filter=""; + } + air_add_cart=0; + for(int i=0;iserviceName(); + if(!svc_name[i].isEmpty()) { + svc_quan=RDAIRPLAY_LOG_QUANTITY; + } + } + if(svc_quan==0) { + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec) { + services_list = rduser->services(); + } else { // RDStation::HostSec + sql=QString().sprintf("select SERVICE_NAME from SERVICE_PERMS \ + where STATION_NAME=\"%s\"", + (const char *)rdstation_conf->name()); + q=new RDSqlQuery(sql); + while(q->next()) { + services_list.append( q->value(0).toString() ); + } + delete q; + } + + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end()&&svc_quan<(RD_MAX_DEFAULT_SERVICES-1); + ++it ) { + svc_name[svc_quan++]=*it; + } + + } + air_add_button->setFlashColor(BUTTON_FROM_BACKGROUND_COLOR); + air_add_button->setFlashingEnabled(true); + air_delete_button->setFlashingEnabled(false); + air_move_button->setFlashingEnabled(false); + air_copy_button->setFlashingEnabled(false); + for(int i=0;isetActionMode(RDAirPlayConf::Normal); + } + air_button_list->setActionMode(RDAirPlayConf::Normal); + if(air_panel!=NULL) { + air_panel->setActionMode(RDAirPlayConf::Normal); + } + if(rdcart_dialog->exec(&air_add_cart,RDCart::All,0,0, + rduser->name(),rduser->password())==0) { + SetActionMode(StartButton::AddTo); + } + else { + SetActionMode(StartButton::Stop); + } + break; + + case StartButton::AddTo: + air_add_button->setFlashColor(BUTTON_TO_BACKGROUND_COLOR); + air_add_button->setFlashingEnabled(true); + air_delete_button->setFlashingEnabled(false); + air_move_button->setFlashingEnabled(false); + air_copy_button->setFlashingEnabled(false); + for(int i=0;isetActionMode(RDAirPlayConf::AddTo,&air_add_cart); + } + air_button_list->setActionMode(RDAirPlayConf::AddTo); + if(air_panel!=NULL) { + air_panel->setActionMode(RDAirPlayConf::AddTo); + } + break; + + case StartButton::DeleteFrom: + air_delete_button->setFlashColor(BUTTON_FROM_BACKGROUND_COLOR); + air_add_button->setFlashingEnabled(false); + air_delete_button->setFlashingEnabled(true); + air_move_button->setFlashingEnabled(false); + air_copy_button->setFlashingEnabled(false); + for(int i=0;isetActionMode(RDAirPlayConf::DeleteFrom); + } + air_button_list->setActionMode(RDAirPlayConf::DeleteFrom); + if(air_panel!=NULL) { + air_panel->setActionMode(RDAirPlayConf::DeleteFrom); + } + break; + + case StartButton::MoveFrom: + air_move_button->setFlashColor(BUTTON_FROM_BACKGROUND_COLOR); + air_add_button->setFlashingEnabled(false); + air_delete_button->setFlashingEnabled(false); + air_move_button->setFlashingEnabled(true); + air_copy_button->setFlashingEnabled(false); + for(int i=0;isetActionMode(RDAirPlayConf::MoveFrom); + } + air_button_list->setActionMode(RDAirPlayConf::MoveFrom); + if(air_panel!=NULL) { + air_panel->setActionMode(RDAirPlayConf::MoveFrom); + } + break; + + case StartButton::MoveTo: + air_move_button->setFlashColor(BUTTON_TO_BACKGROUND_COLOR); + air_add_button->setFlashingEnabled(false); + air_delete_button->setFlashingEnabled(false); + air_move_button->setFlashingEnabled(true); + air_copy_button->setFlashingEnabled(false); + for(int i=0;isetActionMode(RDAirPlayConf::MoveTo); + } + air_button_list->setActionMode(RDAirPlayConf::MoveTo); + if(air_panel!=NULL) { + air_panel->setActionMode(RDAirPlayConf::MoveTo); + } + break; + + case StartButton::CopyFrom: + air_copy_button->setFlashColor(BUTTON_FROM_BACKGROUND_COLOR); + air_add_button->setFlashingEnabled(false); + air_delete_button->setFlashingEnabled(false); + air_move_button->setFlashingEnabled(false); + air_copy_button->setFlashingEnabled(true); + for(int i=0;isetActionMode(RDAirPlayConf::CopyFrom); + } + air_button_list->setActionMode(RDAirPlayConf::CopyFrom); + if(air_panel!=NULL) { + air_panel->setActionMode(RDAirPlayConf::CopyFrom); + } + break; + + case StartButton::CopyTo: + air_move_button->setFlashColor(BUTTON_TO_BACKGROUND_COLOR); + air_add_button->setFlashingEnabled(false); + air_delete_button->setFlashingEnabled(false); + air_move_button->setFlashingEnabled(false); + air_copy_button->setFlashingEnabled(true); + for(int i=0;isetActionMode(RDAirPlayConf::CopyTo); + } + air_button_list->setActionMode(RDAirPlayConf::CopyTo); + if(air_panel!=NULL) { + air_panel->setActionMode(RDAirPlayConf::CopyTo); + } + break; + + default: + break; + } +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(), + "."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rdairplay_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} + + +QString logfile; + + +void LogLine(RDConfig::LogPriority prio,const QString &line) +{ + FILE *file; + + air_config->log("rdairplay",prio,line); + + if(logfile.isEmpty()) { + return; + } + + QDateTime current=QDateTime::currentDateTime(); + if((file=fopen(logfile,"a"))==NULL) { + return; + } + chmod(logfile,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); + fprintf(file,"%02d/%02d/%4d - %02d:%02d:%02d.%03d : %s\n", + current.date().month(), + current.date().day(), + current.date().year(), + current.time().hour(), + current.time().minute(), + current.time().second(), + current.time().msec(), + (const char *)line); + fclose(file); +} + + +bool MainWidget::FirstPort(int index) +{ + for(int i=0;i=0) { + int odir=!dir; + if(air_channel_timers[odir][achan]->isActive()) { + air_channel_timers[odir][achan]->stop(); + return false; + } + air_channel_timers[dir][achan]->start(AIR_CHANNEL_LOCKOUT_INTERVAL,true); + return true; + } + return false; +} + + +int MainWidget::AudioChannel(int card,int port) const +{ + return RD_MAX_PORTS*card+port; +} + + +RDAirPlayConf::Channel MainWidget::PanelChannel(int mport) const +{ + RDAirPlayConf::Channel chan=RDAirPlayConf::SoundPanel1Channel; + switch(mport) { + case 0: + chan=RDAirPlayConf::SoundPanel1Channel; + break; + + case 1: + chan=RDAirPlayConf::SoundPanel2Channel; + break; + + case 2: + chan=RDAirPlayConf::SoundPanel3Channel; + break; + + case 3: + chan=RDAirPlayConf::SoundPanel4Channel; + break; + + case 4: + chan=RDAirPlayConf::SoundPanel5Channel; + break; + } + return chan; +} diff --git a/rdairplay/rdairplay.h b/rdairplay/rdairplay.h new file mode 100644 index 00000000..0f5cbbbe --- /dev/null +++ b/rdairplay/rdairplay.h @@ -0,0 +1,227 @@ +// rdairplay.h +// +// The On Air Playout Utility for Rivendell. +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: rdairplay.h,v 1.89.4.9 2014/02/10 20:45:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDAIRPLAY_H +#define RDAIRPLAY_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Debug Settings +// +//#define RESIZABLE + +// +// Widget Settings +// +#define AIR_PLAY_SPLASH_TIME 5000 +#define AIR_PLAY_BUTTONS 3 +#define AIR_START_BUTTONS 4 +#define AIR_TOTAL_BUTTONS 7 +#define AIR_LOG_PORTS 2 +#define AIR_PANEL_PORTS 1 +#define AIR_PANEL_BUTTON_ROWS 5 +#define AIR_PANEL_BUTTON_COLUMNS 5 +#define AIR_TOTAL_PORTS 3 +#define AIR_MESSAGE_FONT_QUANTITY 8 +#define AIR_CHANNEL_LOCKOUT_INTERVAL 1000 +#define METER_INTERVAL 20 +#define MASTER_TIMER_INTERVAL 100 +#define MESSAGE_WIDGET_WIDTH 410 +#define RDAIRPLAY_USAGE "[=[:[+]]] [...]\n\nWhere refers to one of the three log machines\n('--log1', '--log2' or '--log3') and to the line number\nto do a 'make next' to after the log is loaded (default = 0). If the\n'+' is appended, then the log is started after the 'make next'.\n\nExamples:\n rdairplay --log1=MyLog\n Load 'MyLog' into the Main Log machine\n\n rdairplay --log2=MyLog:14+\n Load 'MyLog' into the Aux Log 1 machine, 'Make Next'\n to line 14 and then start the log.\n\n rdairplay --log1=YourLog --log2=MyLog\n Load 'YourLog' into the Main Log machine and 'MyLog' into the\n Aux Log 1 machine.\n" + + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void logLine(RDConfig::LogPriority prio,const QString &msg); + void ripcConnected(bool state); + void rmlReceivedData(RDMacro *rml); + void gpiStateChangedData(int matrix,int line,bool state); + void logChannelStartedData(int id,int mport,int card,int port); + void logChannelStoppedData(int id,int mport,int card,int port); + void panelChannelStartedData(int mport,int card,int port); + void panelChannelStoppedData(int mport,int card,int port); + void logRenamedData(int log); + void logReloadedData(int log); + void userData(); + void addButtonData(); + void deleteButtonData(); + void moveButtonData(); + void copyButtonData(); + void fullLogButtonData(int); + void panelButtonData(); + void modeButtonData(); + void selectClickedData(int id,int line,RDLogLine::Status status); + void selectClickedData(unsigned cartnum,int row,int col); + void cartDroppedData(int id,int line,RDLogLine *ll); + void meterData(); + void masterTimerData(); + void transportChangedData(); + void timeModeData(RDAirPlayConf::TimeMode mode); + void refreshStatusChangedData(bool active); + void clearSplashData(); + void keyPressEvent(QKeyEvent *e); + void keyReleaseEvent(QKeyEvent *e); + void closeEvent(QCloseEvent *); + void paintEvent(QPaintEvent *e); + + private: + void RunLocalMacros(RDMacro *rml); + void StopEvent(int button_id); + void SetCaption(); + void SetMode(int mach,RDAirPlayConf::OpMode mode); + void SetManualMode(int mach); + void SetAutoMode(int mach); + void SetLiveAssistMode(int mach); + void SetActionMode(StartButton::Mode mode); + bool FirstPort(int index); + bool GetPanel(QString str,RDAirPlayConf::PanelType *type,int *panel); + QFont MessageFont(QString str); + bool AssertChannelLock(int dir,int card,int port); + bool AssertChannelLock(int dir,int achan); + int AudioChannel(int card,int port) const; + RDAirPlayConf::Channel PanelChannel(int mport) const; + LogPlay *air_log[RDAIRPLAY_LOG_QUANTITY]; + RDSoundPanel *air_panel; + PostCounter *air_post_counter; + PieCounter *air_pie_counter; + RDStereoMeter *air_stereo_meter; + StopCounter *air_stop_counter; + ModeDisplay *air_mode_display; + RDPushButton *air_add_button; + RDPushButton *air_delete_button; + RDPushButton *air_move_button; + RDPushButton *air_copy_button; + QPushButton *air_log_button[RDAIRPLAY_LOG_QUANTITY]; + QPushButton *air_panel_button; + ListLog *air_log_list[RDAIRPLAY_LOG_QUANTITY]; + ButtonLog *air_button_list; + StartButton::Mode air_action_mode; + QString air_logname; + QTimer *air_master_timer; + int air_line_counter; + int air_segue_length; + int air_next_button; + RDAirPlayConf::OpModeStyle air_op_mode_style; + RDAirPlayConf::OpMode air_op_mode[RDAIRPLAY_LOG_QUANTITY]; + bool air_start_next; + int air_time_start_line; + RDAirPlayConf::PieEndPoint air_pie_end; + QPalette auto_color; + QPalette manual_color; + QPalette active_color; + int air_add_cart; + int air_copy_line; + QString air_add_filter; + QString air_add_group; + QString air_add_schedcode; + RDLabel *air_message_label; + int air_source_id; + int air_meter_card[3]; + int air_meter_port[3]; + int air_cue_card; + int air_cue_port; + RDInstanceLock *air_lock; + bool air_clear_filter; + RDAirPlayConf::BarAction air_bar_action; + bool air_pause_enabled; + QPixmap *air_rivendell_map; + QString air_start_logname[RDAIRPLAY_LOG_QUANTITY]; + int air_start_line[RDAIRPLAY_LOG_QUANTITY]; + bool air_start_start[RDAIRPLAY_LOG_QUANTITY]; + RDAirPlayConf::ExitCode rdairplay_previous_exit_code; + QDateTime air_startup_datetime; + RDLabel *air_refresh_label; + QPixmap *air_refresh_pixmap; + QString air_editor_cmd; + QSocketDevice *air_nownext_socket; + std::vector air_plugin_hosts; + QSplashScreen *air_splash_screen; + int keystrokecount; + bool AltKeyHit ; + bool CtrlKeyHit; + QFont air_message_fonts[AIR_MESSAGE_FONT_QUANTITY]; + QFontMetrics *air_message_metrics[AIR_MESSAGE_FONT_QUANTITY]; + int air_audio_channels[RDAirPlayConf::LastChannel]; + int air_start_gpi_matrices[RDAirPlayConf::LastChannel]; + int air_start_gpi_lines[RDAirPlayConf::LastChannel]; + int air_start_gpo_matrices[RDAirPlayConf::LastChannel]; + int air_start_gpo_lines[RDAirPlayConf::LastChannel]; + int air_stop_gpi_matrices[RDAirPlayConf::LastChannel]; + int air_stop_gpi_lines[RDAirPlayConf::LastChannel]; + int air_stop_gpo_matrices[RDAirPlayConf::LastChannel]; + int air_stop_gpo_lines[RDAirPlayConf::LastChannel]; + RDAirPlayConf::GpioType air_channel_gpio_types[RDAirPlayConf::LastChannel]; + std::map air_channel_timers[2]; + RDEmptyCart *air_empty_cart; +}; + + +#endif diff --git a/rdairplay/rdairplay.pro b/rdairplay/rdairplay.pro new file mode 100644 index 00000000..6264ed91 --- /dev/null +++ b/rdairplay/rdairplay.pro @@ -0,0 +1,70 @@ +# rdairplay.pro +# +# The QMake project file for RDAirPlay. +# +# (C) Copyright 2003-2005 Fred Gleason +# +# $Id: rdairplay.pro,v 1.8.4.4 2013/12/28 00:00:34 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +x11 { + SOURCES += button_log.cpp + SOURCES += edit_event.cpp + SOURCES += hourselector.cpp + SOURCES += lib_listview.cpp + SOURCES += list_log.cpp + SOURCES += list_logs.cpp + SOURCES += local_macros.cpp + SOURCES += log_play.cpp + SOURCES += log_traffic.cpp + SOURCES += loglinebox.cpp + SOURCES += mode_display.cpp + SOURCES += pie_counter.cpp + SOURCES += post_counter.cpp + SOURCES += rdairplay.cpp + SOURCES += start_button.cpp + SOURCES += stop_counter.cpp + SOURCES += wall_clock.cpp +} + +x11 { + HEADERS += button_log.h + HEADERS += colors.h + HEADERS += edit_event.h + HEADERS += hourselector.h + HEADERS += lib_listview.h + HEADERS += list_log.h + HEADERS += list_logs.h + HEADERS += log_play.h + HEADERS += log_traffic.h + HEADERS += loglinebox.h + HEADERS += mode_display.h + HEADERS += pie_counter.h + HEADERS += post_counter.h + HEADERS += rdairplay.h + HEADERS += start_button.h + HEADERS += stop_counter.h + HEADERS += wall_clock.h +} + +TRANSLATIONS += rdairplay_cs.ts +TRANSLATIONS += rdairplay_de.ts +TRANSLATIONS += rdairplay_es.ts +TRANSLATIONS += rdairplay_fr.ts +TRANSLATIONS += rdairplay_nb.ts +TRANSLATIONS += rdairplay_nn.ts +TRANSLATIONS += rdairplay_pt_BR.ts diff --git a/rdairplay/rdairplay_cs.ts b/rdairplay/rdairplay_cs.ts new file mode 100644 index 00000000..21f25f29 --- /dev/null +++ b/rdairplay/rdairplay_cs.ts @@ -0,0 +1,700 @@ + + + EditEvent + + Edit Event + Upravit událost + + + Start at: + Začít na: + + + Action If Previous Event Still Playing + Činnost, když předchozí událost ještě běží + + + Start Immediately + Spustit ihned + + + Make Next + Jako další + + + Wait up to + Počkat až do + + + Play + Přehrát + + + Segue + Přechod + + + Stop + Zastavit + + + Start Transition Type: + Typ spuštění přechodu: + + + No Fade at Segue Out + Žádné prolínání při přechodu ven + + + &Audition + &Poslech + + + &Pause + P&ozastavit + + + &Stop + Za&stavit + + + Start + Začátek + + + &OK + &OK + + + &Cancel + Z&rušit + + + Edit Marker + Upravit značku + + + Edit Track + Upravit stopu + + + Edit Log Track + Upravit stopu zápisu + + + Transition If Previous Cart Ends Before + Přechod, když předchozí vozík skončí dříve + + + End + Konec + + + Duplicate Start Time + Zdvojený čas začátku + + + An event is already scheduled with this start time! + Již existuje událost s tímto začátečním časem! + + + Cart Notes + + + + + HourSelector + + 12a + + + + 1a + + + + 2a + + + + 3a + + + + 4a + + + + 5a + + + + 6a + + + + 7a + + + + 8a + + + + 9a + + + + 10a + + + + 11a + + + + 12p + + + + 1p + + + + 2p + + + + 3p + + + + 4p + + + + 5p + + + + 6p + + + + 7p + + + + 8p + + + + 9p + + + + 10p + + + + 11p + + + + + ListLog + + EST TIME + ODH. ČAS + + + LEN + DÉLKA + + + TRANS + PŘECHOD + + + CART + VOZÍK + + + TITLE + NÁZEV + + + ARTIST + UMĚLEC + + + GROUP + SKUPINA + + + TIME + ČAS + + + CLIENT + ZÁKAZNÍK + + + AGENCY + AGENTURA + + + LABEL + ŠTÍTEK + + + LINE ID + ID ŘÁDKU + + + COUNT + POČÍTADLO + + + STATUS + STAV + + + Select + Vybrat + + + Make +Next + Jako +další + + + Modify + Upravit + + + Scroll + Projíždět + + + Refresh +Log + Obnovit +zápis + + + Select +Log + Vybrat +zápis + + + Log Exists + Zápis existuje + + + Log Already Exists! + Zápis již existuje! + + + --- end of log --- + --- konec zápisu --- + + + PLAY + PŘEHRÁT + + + STOP + ZASTAVIT + + + SEGUE + PŘECHOD + + + MARKER + ZNAČKA + + + TRACK + STOPA + + + LINK + ODKAZ + + + [music import] + [zavedení hudby] + + + [traffic import] + [zavedení přenosu] + + + CHAIN TO + ŘETĚZ K + + + [CART NOT FOUND] + [VOZÍK NENALEZEN] + + + [NO VALID CUT AVAILABLE] + [ŽÁDNÝ PLATNÝ ZÁBĚR NENÍ DOSTUPNÝ] + + + [NO AUDIO AVAILABLE] + [ŽÁDNÝ ZVUK NENÍ DOSTUPNÝ] + + + T + T + + + Pause + Pozastavit + + + Stop + Zastavit + + + Start + Spustit + + + Run Length + Délka běhu + + + Next Stop: + Další zastavení: + + + Log End: + Konec zápisu: + + + Selected: + Vybráno: + + + Audition +Head + Začátek +poslechu + + + Audition +Tail + Konec +poslechu + + + ALBUM + + + + + ListLogs + + Select a Log + Vybrat zápis + + + NAME + NÁZEV + + + DESCRIPTION + POPIS + + + SERVICE + SLUŽBA + + + Load + Nahrát + + + Unload + Vyložit + + + Save + Uložit + + + Save &As + Uložit &jako + + + Cancel + Zrušit + + + Rename Log + Přejmenovat zápis + + + + LogLineBox + + STOP + ZASTAVIT + + + PLAY + PŘEHRÁT + + + SEGUE + PŘECHOD + + + [CART NOT FOUND] + [VOZÍK NENALEZEN] + + + [NO AUDIO AVAILABLE] + [ŽÁDNÝ ZVUK NENÍ DOSTUPNÝ] + + + [NO VALID CUT AVAILABLE] + [ŽÁDNÝ PLATNÝ ZÁBĚR NENÍ DOSTUPNÝ] + + + MARKER + ZNAČKA + + + TRACK + STOPA + + + LINK + ODKAZ + + + [music import] + [zavedení hudby] + + + [traffic import] + [zavedení přenosu] + + + CHAIN + ŘETĚZ + + + T + T + + + + MainWidget + + RDAirPlay + RDAirplay + + + Multiple instances not allowed! + Více instancí není dovoleno! + + + RDAirPlay - Host: + RDAirPlay - Server + + + Database Error + Chyba databáze + + + ADD + PŘIDAT + + + DEL + SMAZAT + + + MOVE + PŘESUNOUT + + + COPY + KOPÍROVAT + + + Main Log +[--] + Hlavní zápis +[--] + + + Aux 1 Log +[--] + Pomocný zápis 1 +[--] + + + Aux 2 Log +[--] + Pomocný zápis 2 +[--] + + + Sound +Panel + Zvukový +panel + + + Main Log + Hlavní zápis + + + Aux 1 Log + Pomocný zápis 1 + + + Aux 2 Log + Pomocný zápis 2 + + + LOG +REFRESHING + ZÁPIS +OBNOVEN + + + Exit RDAirPlay? + Ukončit RDAirPlay? + + + Host: + + + + Host + + + + User: + + + + Log: + + + + Service: + + + + + ModeDisplay + + Operating Mode + Operační režim + + + LiveAssist + Živá pomoc + + + Automatic + Automatický + + + Manual + Ruční + + + Aux1 + + + + Aux2 + + + + + PostCounter + + Next Timed Start + Další načasovaný začátek + + + On Time + Přesně na čas + + + Next Timed Start [--:--:--] + Další načasovaný začátek [--:--:--] + + + + QObject + + START + + + + STOP + ZASTAVIT + + + PAUSE + + + + RESUME + + + + WHERE? + + + + DELETE? + + + + MOVE? + + + + TO? + + + + COPY? + + + + ERROR + + + + + StopCounter + + Next Stop [none] + Další zastavení [žádné] + + + Next Stop + Další zastavení + + + Stopped + Zastaveno + + + diff --git a/rdairplay/rdairplay_de.ts b/rdairplay/rdairplay_de.ts new file mode 100644 index 00000000..f3270bb2 --- /dev/null +++ b/rdairplay/rdairplay_de.ts @@ -0,0 +1,700 @@ + + + EditEvent + + Edit Event + Event editieren + + + Start at: + Starte um: + + + Action If Previous Event Still Playing + Aktion wenn das vorherige Event noch läuft + + + Start Immediately + Sofort starten + + + Make Next + Als nächstes + + + Wait up to + Warte bis zu + + + Play + Play + + + Segue + Segue + + + Stop + Stop + + + Start Transition Type: + Start-Übergangstyp: + + + No Fade at Segue Out + Kein faden beim Segue Out + + + &Audition + &Anhören + + + &Pause + &Pause + + + &Stop + &Stop + + + Start + Start + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Edit Marker + Marker editieren + + + Edit Track + Track editieren + + + Edit Log Track + Log-Track editieren + + + Transition If Previous Cart Ends Before + Übergang, wenn vorheriger Cart eher endet + + + End + Ende + + + Duplicate Start Time + Doppelte Startzeit + + + An event is already scheduled with this start time! + Es existiert bereits ein Event mit dieser Startzeit! + + + Cart Notes + + + + + HourSelector + + 12a + + + + 1a + + + + 2a + + + + 3a + + + + 4a + + + + 5a + + + + 6a + + + + 7a + + + + 8a + + + + 9a + + + + 10a + + + + 11a + + + + 12p + + + + 1p + + + + 2p + + + + 3p + + + + 4p + + + + 5p + + + + 6p + + + + 7p + + + + 8p + + + + 9p + + + + 10p + + + + 11p + + + + + ListLog + + EST TIME + CA. ZEIT + + + LEN + LÄNGE + + + TRANS + ÜBERG + + + CART + CART + + + TITLE + TITEL + + + ARTIST + KÜNSTLER + + + GROUP + GRUPPE + + + TIME + ZEIT + + + CLIENT + KUNDE + + + AGENCY + AGENTUR + + + LABEL + LABEL + + + LINE ID + LINE ID + + + COUNT + ZÄHLER + + + STATUS + STATUS + + + Select + Auswählen + + + Make +Next + Als +Nächstes + + + Modify + Ändern + + + Scroll + Scrollen + + + Refresh +Log + Log +erneuern + + + Select +Log + Log +auswählen + + + Log Exists + Log existiert + + + Log Already Exists! + Log existiert bereits! + + + --- end of log --- + --- ende des Logs --- + + + PLAY + PLAY + + + STOP + STOP + + + SEGUE + SEGUE + + + MARKER + MARKER + + + TRACK + TRACK + + + LINK + LINK + + + [music import] + [musikimport] + + + [traffic import] + [traffic import] + + + CHAIN TO + CHAIN TO + + + [CART NOT FOUND] + [CART NICHT GEFUNDEN] + + + [NO VALID CUT AVAILABLE] + [KEIN GÜLTIGER CUT VERFÜGBAR] + + + [NO AUDIO AVAILABLE] + [KEIN AUDIO VERFÜGBAR] + + + T + T + + + Pause + Pause + + + Stop + Stop + + + Start + Start + + + Run Length + Laufzeit + + + Next Stop: + Nächster Stop: + + + Log End: + Log Ende: + + + Selected: + Ausgewählt: + + + Audition +Head + Anfang +vorhören + + + Audition +Tail + Ende +vorhören + + + ALBUM + + + + + ListLogs + + Select a Log + Log auswählen + + + NAME + NAME + + + DESCRIPTION + BESCHREIBUNG + + + SERVICE + SERVICE + + + Load + Laden + + + Unload + Entladen + + + Save + Speichern + + + Save &As + Speichern &Als + + + Cancel + Abbrechen + + + Rename Log + Log umbenennen + + + + LogLineBox + + STOP + STOP + + + PLAY + PLAY + + + SEGUE + SEGUE + + + [CART NOT FOUND] + [CART NICHT GEFUNDEN] + + + [NO AUDIO AVAILABLE] + [KEIN AUDIO VERFÜGBAR] + + + [NO VALID CUT AVAILABLE] + [KEIN GÜLTIGER CUT VERFÜGBAR] + + + MARKER + MARKER + + + TRACK + TRACK + + + LINK + LINK + + + [music import] + [musikimport] + + + [traffic import] + [traffic import] + + + CHAIN + CHAIN + + + T + T + + + + MainWidget + + RDAirPlay + RDAirPlay + + + Multiple instances not allowed! + Mehrere Instanzen sind nicht erlaubt! + + + RDAirPlay - Host: + RDAirPlay - Host: + + + Database Error + Datenbankfehler + + + ADD + HINZUFÜGEN + + + DEL + DEL + + + MOVE + VERSCHIEBEN + + + COPY + KOPIEREN + + + Main Log +[--] + Main Log +[--] + + + Aux 1 Log +[--] + Aux 1 Log +[--] + + + Aux 2 Log +[--] + Aux 2 Log +[--] + + + Sound +Panel + Sound +Panel + + + Main Log + Main Log + + + Aux 1 Log + Aux 1 Log + + + Aux 2 Log + Aux 2 Log + + + LOG +REFRESHING + LOG +AKTUALISIERT + + + Exit RDAirPlay? + RDAirPlay verlassen? + + + User: + + + + Log: + + + + Service: + + + + Host + + + + Host: + + + + + ModeDisplay + + Operating Mode + Operationsmodus + + + LiveAssist + LiveAssist + + + Automatic + Automatik + + + Manual + Manuell + + + Aux1 + + + + Aux2 + + + + + PostCounter + + Next Timed Start + Nächster Zeit-Start + + + On Time + Pünktlich + + + Next Timed Start [--:--:--] + Nächste Zeit-Start [--:--:--] + + + + QObject + + START + + + + STOP + STOP + + + PAUSE + + + + RESUME + + + + WHERE? + + + + DELETE? + + + + MOVE? + + + + TO? + + + + COPY? + + + + ERROR + + + + + StopCounter + + Next Stop [none] + Nächster Stop [keiner] + + + Next Stop + Nächster Stop + + + Stopped + Gestoppt + + + diff --git a/rdairplay/rdairplay_es.ts b/rdairplay/rdairplay_es.ts new file mode 100644 index 00000000..d0a47e24 --- /dev/null +++ b/rdairplay/rdairplay_es.ts @@ -0,0 +1,700 @@ + + + EditEvent + + Edit Event + Editar Evento + + + Start at: + Comienzo: + + + Action If Previous Event Still Playing + Acción si el evento anterior está sonando + + + Start Immediately + Iniciar de inmediato + + + Make Next + Convertir en siguiente + + + Wait up to + Espera hasta + + + Play + Reproducir + + + Segue + Segue + + + Stop + Parar + + + &Audition + Escuc&har + + + &Pause + &Pausar + + + &Stop + &Parar + + + Start + Iniciar + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Edit Marker + Editar marcador + + + Transition If Previous Cart Ends Before + Transición si el cartucho previo termina antes + + + Edit Track + Editar pista + + + Edit Log Track + Editar Pista del Log + + + Start Transition Type: + Tipo de transición inicial: + + + No Fade at Segue Out + No desvanecer al terminar + + + End + Fin + + + Duplicate Start Time + Tiempo de inicio duplicado + + + An event is already scheduled with this start time! + Un evento ha sido programado con esa misma hora de inicio! + + + Cart Notes + + + + + HourSelector + + 12a + + + + 1a + + + + 2a + + + + 3a + + + + 4a + + + + 5a + + + + 6a + + + + 7a + + + + 8a + + + + 9a + + + + 10a + + + + 11a + + + + 12p + + + + 1p + + + + 2p + + + + 3p + + + + 4p + + + + 5p + + + + 6p + + + + 7p + + + + 8p + + + + 9p + + + + 10p + + + + 11p + + + + + ListLog + + TIME + HORA + + + TRANS + TRANS + + + CART + CARTUCHO + + + TITLE + TÍTULO + + + ARTIST + ARTISTA + + + CLIENT + CLIENTE + + + AGENCY + AGENCIA + + + LABEL + ETIQUETA + + + LINE ID + ID DE LÍNEA + + + COUNT + CUENTA + + + STATUS + ESTADO + + + Select + Seleccionar + + + Pause + Pausar + + + Stop + Parar + + + Make +Next + Hacer +Siguiente + + + Modify + Modificar + + + Scroll + Desplazar + + + Select +Log + Elegir +Lista + + + Log Exists + La lista ya existe + + + Log Already Exists! + ¡La lista de reproducción ya existe! + + + --- end of log --- + --- fin de la lista --- + + + PLAY + REPRO + + + STOP + PARAR + + + SEGUE + SEGUE + + + MARKER + MARCADOR + + + CHAIN TO + ENCADENAR A + + + [CART NOT FOUND] + [CARTUCHO NO ENCONTRADO] + + + [NO VALID CUT AVAILABLE] + [NO HAY AUDIOS VÁLIDOS] + + + T + T + + + [NO AUDIO AVAILABLE] + [NO HAY AUDIO DISPONIBLE] + + + TRACK + PISTA + + + LEN + LONG + + + LINK + ENLACE + + + [music import] + [importar música] + + + [traffic import] + [importar tráfico] + + + EST TIME + TIEMPO EST + + + GROUP + GRUPO + + + Refresh +Log + Actualizar +Lista + + + Start + Empezar + + + Run Length + Duración + + + Next Stop: + Próximo: + + + Log End: + Fin de PL: + + + Selected: + Selecc.: + + + Audition +Head + Escuchar +Comienzo + + + Audition +Tail + Escuchar +Final + + + ALBUM + + + + + ListLogs + + Select a Log + Seleccione una lista + + + NAME + NOMBRE + + + DESCRIPTION + DESCRIPCIÓN + + + SERVICE + SERVICIO + + + Load + Cargar + + + Unload + Descargar + + + Save + Guardar + + + Save &As + Gu&ard. como + + + Cancel + Cancelar + + + Rename Log + Cambiar nombre de la lista + + + + LogLineBox + + STOP + PARAR + + + PLAY + REPRO + + + SEGUE + SEGUE + + + [CART NOT FOUND] + [CARTUCHO NO ENCONTRADO] + + + [NO AUDIO AVAILABLE] + [NO HAY AUDIO DISPONIBLE] + + + [NO VALID CUT AVAILABLE] + [NO HAY CUTS DISPONIBLES] + + + MARKER + MARCADOR + + + T + T + + + TRACK + PISTA + + + CHAIN + CADENA + + + LINK + ENLACE + + + [music import] + [importar música] + + + [traffic import] + [importar tráfico] + + + + MainWidget + + Main Log + Lista ppal + + + Aux 1 Log + Lista aux. 1 + + + Aux 2 Log + Lista aux. 2 + + + Exit RDAirPlay? + ¿Salir de RDAirPlay? + + + RDAirPlay - Host: + RDAirPlay - Equipo: + + + Database Error + Error en la base de datos + + + ADD + AÑADIR + + + DEL + QUITAR + + + MOVE + MOVER + + + COPY + COPIAR + + + Main Log +[--] + Lista ppal. +[--] + + + Aux 1 Log +[--] + Lista aux. 1 +[--] + + + Aux 2 Log +[--] + Lista aux. 2 +[--] + + + Sound +Panel + Panel de +sonidos + + + RDAirPlay + RDAirPlay + + + Multiple instances not allowed! + ¡No se permiten múltiples instancias! + + + LOG +REFRESHING + LEYENDO +LISTA + + + User: + Usuario: + + + Log: + Lista: + + + Service: + Servicio: + + + Host + Equipo + + + Host: + Equipo: + + + + ModeDisplay + + Operating Mode + Modo de operación + + + LiveAssist + Asist. en Vivo + + + Automatic + Automatico + + + Manual + Manual + + + Aux1 + + + + Aux2 + + + + + PostCounter + + On Time + A tiempo + + + Next Timed Start + Sig. Inicio Programado + + + Next Timed Start [--:--:--] + Sig. Inicio Programado [--:--:--] + + + + QObject + + START + INICIAR + + + STOP + PARAR + + + PAUSE + PAUSA + + + RESUME + SEGUIR + + + WHERE? + ¿DÓNDE? + + + DELETE? + ¿BORRAR? + + + MOVE? + ¿MOVER? + + + TO? + ¿HACIA? + + + COPY? + ¿COPIAR? + + + ERROR + ERROR + + + + StopCounter + + Next Stop [none] + Prox parada [ninguna] + + + Next Stop + Prox parada + + + Stopped + Detenido + + + diff --git a/rdairplay/rdairplay_fr.ts b/rdairplay/rdairplay_fr.ts new file mode 100644 index 00000000..228d4246 --- /dev/null +++ b/rdairplay/rdairplay_fr.ts @@ -0,0 +1,666 @@ + + + EditEvent + + Edit Event + + + + Start at: + + + + Action If Previous Event Still Playing + + + + Start Immediately + + + + Make Next + + + + Wait up to + + + + Play + + + + Segue + + + + Stop + + + + Start Transition Type: + + + + No Fade at Segue Out + + + + &OK + + + + &Cancel + + + + Transition If Previous Cart Ends Before + + + + Duplicate Start Time + + + + An event is already scheduled with this start time! + + + + Edit Marker + + + + Edit Track + + + + Edit Log Track + + + + Cart Notes + + + + + HourSelector + + 12a + + + + 1a + + + + 2a + + + + 3a + + + + 4a + + + + 5a + + + + 6a + + + + 7a + + + + 8a + + + + 9a + + + + 10a + + + + 11a + + + + 12p + + + + 1p + + + + 2p + + + + 3p + + + + 4p + + + + 5p + + + + 6p + + + + 7p + + + + 8p + + + + 9p + + + + 10p + + + + 11p + + + + + ListLog + + EST TIME + + + + LEN + + + + TRANS + + + + CART + + + + TITLE + + + + ARTIST + + + + GROUP + + + + TIME + + + + CLIENT + + + + AGENCY + + + + LABEL + + + + LINE ID + + + + COUNT + + + + STATUS + + + + Select + + + + Make +Next + + + + Modify + + + + Scroll + + + + Refresh +Log + + + + Select +Log + + + + Log Exists + + + + Log Already Exists! + + + + --- end of log --- + + + + PLAY + + + + STOP + + + + SEGUE + + + + MARKER + + + + TRACK + + + + LINK + + + + [music import] + + + + [traffic import] + + + + CHAIN TO + + + + [CART NOT FOUND] + + + + [NO VALID CUT AVAILABLE] + + + + [NO AUDIO AVAILABLE] + + + + T + + + + Pause + + + + Stop + + + + Start + + + + Run Length + + + + Next Stop: + + + + Log End: + + + + Selected: + + + + Audition +Head + + + + Audition +Tail + + + + ALBUM + + + + + ListLogs + + Select a Log + + + + NAME + + + + DESCRIPTION + + + + SERVICE + + + + Load + + + + Unload + + + + Save + + + + Save &As + + + + Cancel + + + + Rename Log + + + + + LogLineBox + + STOP + + + + PLAY + + + + SEGUE + + + + [CART NOT FOUND] + + + + [NO AUDIO AVAILABLE] + + + + [NO VALID CUT AVAILABLE] + + + + MARKER + + + + TRACK + + + + LINK + + + + [music import] + + + + [traffic import] + + + + CHAIN + + + + T + + + + + MainWidget + + RDAirPlay + + + + Multiple instances not allowed! + + + + Database Error + + + + ADD + + + + DEL + + + + MOVE + + + + COPY + + + + Main Log +[--] + + + + Aux 1 Log +[--] + + + + Aux 2 Log +[--] + + + + Sound +Panel + + + + Main Log + + + + Aux 1 Log + + + + Aux 2 Log + + + + LOG +REFRESHING + + + + Exit RDAirPlay? + + + + User: + + + + Log: + + + + Service: + + + + Host + + + + Host: + + + + + ModeDisplay + + LiveAssist + + + + Automatic + + + + Manual + + + + Operating Mode + + + + Aux1 + + + + Aux2 + + + + + PostCounter + + Next Timed Start + + + + On Time + + + + Next Timed Start [--:--:--] + + + + + QObject + + START + + + + STOP + + + + PAUSE + + + + RESUME + + + + WHERE? + + + + DELETE? + + + + MOVE? + + + + TO? + + + + COPY? + + + + ERROR + + + + + StopCounter + + Next Stop [none] + + + + Next Stop + + + + Stopped + + + + diff --git a/rdairplay/rdairplay_nb.ts b/rdairplay/rdairplay_nb.ts new file mode 100644 index 00000000..77160fd2 --- /dev/null +++ b/rdairplay/rdairplay_nb.ts @@ -0,0 +1,710 @@ + + + EditEvent + + Edit Event + Rediger hending + + + Start at: + Start på: + + + Action If Previous Event Still Playing + Handling viss førre hending spelar enno + + + Start Immediately + Start med ein gong + + + Make Next + Lag neste + + + Wait up to + Vent opp til + + + Play + Spel + + + Segue + Overgang + + + Stop + Stopp + + + Overlap + Overlapp + + + Start Transition Type: + Start overtoningstype: + + + No Fade at Segue Out + Inga toning ved Overgang ut + + + &Audition + &Lytt + + + &Pause + &Pause + + + &Stop + &Stopp + + + Start + Start + + + &OK + &OK + + + &Cancel + &Avbryt + + + Edit Marker + Rediger markør + + + Edit Track + Rediger spor + + + Edit Log Track + Rediger loggspor + + + Transition If Previous Cart Ends Before + Overtoning viss førre korga endar før + + + Duplicate Start Time + + + + An event is already scheduled with this start time! + + + + Cart Notes + + + + + HourSelector + + 12a + + + + 1a + + + + 2a + + + + 3a + + + + 4a + + + + 5a + + + + 6a + + + + 7a + + + + 8a + + + + 9a + + + + 10a + + + + 11a + + + + 12p + + + + 1p + + + + 2p + + + + 3p + + + + 4p + + + + 5p + + + + 6p + + + + 7p + + + + 8p + + + + 9p + + + + 10p + + + + 11p + + + + + ListLog + + EST TIME + OMTR TID + + + LEN + LENGD + + + TRANS + OVERT + + + CART + KORG + + + TITLE + TITTEL + + + ARTIST + ARTIST + + + GROUP + GRUPPE + + + TIME + TID + + + CLIENT + KLIENT + + + AGENCY + AGENT + + + LABEL + SELSKAP + + + LINE ID + LINJE-ID + + + COUNT + TELLING + + + STATUS + STATUS + + + Select + Vel + + + Play + Spel + + + Make +Next + Lag +neste + + + Modify + Endre + + + Scroll + Rull + + + Refresh +Log + Last loggen +på nytt + + + Select +Log + Vel +logg + + + Log Exists + Loggen eksisterer + + + Log Already Exists! + Loggen finst frå før! + + + --- end of log --- + --- slutt på loggen --- + + + PLAY + SPEL + + + STOP + STOPP + + + SEGUE + OVERGANG + + + OVERLAP + OVERLAPP + + + MARKER + MARKØR + + + TRACK + SPOR + + + LINK + LENKJE + + + [music import] + [musikkimport] + + + [traffic import] + [trafikkimport] + + + CHAIN TO + LENK TIL + + + [CART NOT FOUND] + [FANN IKKJE KORG] + + + [NO VALID CUT AVAILABLE] + [GYLDIG KUTT FINST IKKJE + + + [NO AUDIO AVAILABLE] + [LYD FINST IKKJE] + + + T + S + + + Pause + Pause + + + Stop + Stopp + + + Run Length + + + + Next Stop: + + + + Log End: + + + + Audition +Head + + + + Audition +Tail + + + + Start + Start + + + Selected: + + + + ALBUM + + + + + ListLogs + + Select a Log + Vel ein logg + + + NAME + NAMN + + + DESCRIPTION + SKILDRING + + + SERVICE + TENEST + + + Load + Last + + + Unload + Last ut + + + Save + Lagre + + + Save &As + Lagre &som + + + Cancel + Avbryt + + + Rename Log + Døyp om loggen + + + + LogLineBox + + STOP + STOPP + + + PLAY + SPEL + + + SEGUE + OVERGANG + + + OVRLAP + OVERLAPP + + + [CART NOT FOUND] + [FANN IKKJE KORG] + + + [NO AUDIO AVAILABLE] + [LYD FINST IKKJE] + + + [NO VALID CUT AVAILABLE] + [GYLDIG KUTT FINST IKKJE + + + MARKER + MARKØR + + + TRACK + SPOR + + + LINK + LENKJE + + + [music import] + [musikkimport] + + + [traffic import] + [trafikkimport] + + + CHAIN + LENKJE + + + T + S + + + + MainWidget + + RDAirPlay + RDAirPlay + + + Multiple instances not allowed! + Det er ikkje lov med fleire førekomstar! + + + RDAirPlay - Host: + RDAirPlay-vert: + + + Database Error + Databasefeil + + + ADD + LEGG TIL + + + DEL + SLETT + + + MOVE + FLYTT + + + COPY + KOPIER + + + Main Log +[--] + Hovudlogg +[---] + + + Aux 1 Log +[--] + Hjelpelogg 1 +[---] + + + Aux 2 Log +[--] + Hjelpelogg 2 +[---] + + + Sound +Panel + Lyd- +panel + + + Main Log + Hovudlogg + + + Aux 1 Log + Hjelpelogg 1 + + + Aux 2 Log + Hjelpelogg 2 + + + LOG +REFRESHING + LOGGEN +LASTAR PÅ NYTT + + + Exit RDAirPlay? + Gå ut av RDAirPlay? + + + User: + + + + Log: + + + + Service: + + + + Host + + + + Host: + + + + + ModeDisplay + + Operating Mode + Køyremodus + + + LiveAssist + Live-hjelp + + + Automatic + Automatisk + + + Manual + Manuelt + + + Aux1 + + + + Aux2 + + + + + PostCounter + + Next Timed Start + Neste tidlagte star + + + On Time + På tida + + + Next Timed Start [--:--:--] + Neste tidlagte start [--:--:--] + + + + QObject + + START + + + + STOP + STOPP + + + PAUSE + + + + RESUME + + + + WHERE? + + + + DELETE? + + + + MOVE? + + + + TO? + + + + COPY? + + + + ERROR + + + + + StopCounter + + Next Stop [none] + Neste stopp [ingen] + + + Next Stop + Neste stopp + + + Stopped + Stoppa + + + diff --git a/rdairplay/rdairplay_nn.ts b/rdairplay/rdairplay_nn.ts new file mode 100644 index 00000000..77160fd2 --- /dev/null +++ b/rdairplay/rdairplay_nn.ts @@ -0,0 +1,710 @@ + + + EditEvent + + Edit Event + Rediger hending + + + Start at: + Start på: + + + Action If Previous Event Still Playing + Handling viss førre hending spelar enno + + + Start Immediately + Start med ein gong + + + Make Next + Lag neste + + + Wait up to + Vent opp til + + + Play + Spel + + + Segue + Overgang + + + Stop + Stopp + + + Overlap + Overlapp + + + Start Transition Type: + Start overtoningstype: + + + No Fade at Segue Out + Inga toning ved Overgang ut + + + &Audition + &Lytt + + + &Pause + &Pause + + + &Stop + &Stopp + + + Start + Start + + + &OK + &OK + + + &Cancel + &Avbryt + + + Edit Marker + Rediger markør + + + Edit Track + Rediger spor + + + Edit Log Track + Rediger loggspor + + + Transition If Previous Cart Ends Before + Overtoning viss førre korga endar før + + + Duplicate Start Time + + + + An event is already scheduled with this start time! + + + + Cart Notes + + + + + HourSelector + + 12a + + + + 1a + + + + 2a + + + + 3a + + + + 4a + + + + 5a + + + + 6a + + + + 7a + + + + 8a + + + + 9a + + + + 10a + + + + 11a + + + + 12p + + + + 1p + + + + 2p + + + + 3p + + + + 4p + + + + 5p + + + + 6p + + + + 7p + + + + 8p + + + + 9p + + + + 10p + + + + 11p + + + + + ListLog + + EST TIME + OMTR TID + + + LEN + LENGD + + + TRANS + OVERT + + + CART + KORG + + + TITLE + TITTEL + + + ARTIST + ARTIST + + + GROUP + GRUPPE + + + TIME + TID + + + CLIENT + KLIENT + + + AGENCY + AGENT + + + LABEL + SELSKAP + + + LINE ID + LINJE-ID + + + COUNT + TELLING + + + STATUS + STATUS + + + Select + Vel + + + Play + Spel + + + Make +Next + Lag +neste + + + Modify + Endre + + + Scroll + Rull + + + Refresh +Log + Last loggen +på nytt + + + Select +Log + Vel +logg + + + Log Exists + Loggen eksisterer + + + Log Already Exists! + Loggen finst frå før! + + + --- end of log --- + --- slutt på loggen --- + + + PLAY + SPEL + + + STOP + STOPP + + + SEGUE + OVERGANG + + + OVERLAP + OVERLAPP + + + MARKER + MARKØR + + + TRACK + SPOR + + + LINK + LENKJE + + + [music import] + [musikkimport] + + + [traffic import] + [trafikkimport] + + + CHAIN TO + LENK TIL + + + [CART NOT FOUND] + [FANN IKKJE KORG] + + + [NO VALID CUT AVAILABLE] + [GYLDIG KUTT FINST IKKJE + + + [NO AUDIO AVAILABLE] + [LYD FINST IKKJE] + + + T + S + + + Pause + Pause + + + Stop + Stopp + + + Run Length + + + + Next Stop: + + + + Log End: + + + + Audition +Head + + + + Audition +Tail + + + + Start + Start + + + Selected: + + + + ALBUM + + + + + ListLogs + + Select a Log + Vel ein logg + + + NAME + NAMN + + + DESCRIPTION + SKILDRING + + + SERVICE + TENEST + + + Load + Last + + + Unload + Last ut + + + Save + Lagre + + + Save &As + Lagre &som + + + Cancel + Avbryt + + + Rename Log + Døyp om loggen + + + + LogLineBox + + STOP + STOPP + + + PLAY + SPEL + + + SEGUE + OVERGANG + + + OVRLAP + OVERLAPP + + + [CART NOT FOUND] + [FANN IKKJE KORG] + + + [NO AUDIO AVAILABLE] + [LYD FINST IKKJE] + + + [NO VALID CUT AVAILABLE] + [GYLDIG KUTT FINST IKKJE + + + MARKER + MARKØR + + + TRACK + SPOR + + + LINK + LENKJE + + + [music import] + [musikkimport] + + + [traffic import] + [trafikkimport] + + + CHAIN + LENKJE + + + T + S + + + + MainWidget + + RDAirPlay + RDAirPlay + + + Multiple instances not allowed! + Det er ikkje lov med fleire førekomstar! + + + RDAirPlay - Host: + RDAirPlay-vert: + + + Database Error + Databasefeil + + + ADD + LEGG TIL + + + DEL + SLETT + + + MOVE + FLYTT + + + COPY + KOPIER + + + Main Log +[--] + Hovudlogg +[---] + + + Aux 1 Log +[--] + Hjelpelogg 1 +[---] + + + Aux 2 Log +[--] + Hjelpelogg 2 +[---] + + + Sound +Panel + Lyd- +panel + + + Main Log + Hovudlogg + + + Aux 1 Log + Hjelpelogg 1 + + + Aux 2 Log + Hjelpelogg 2 + + + LOG +REFRESHING + LOGGEN +LASTAR PÅ NYTT + + + Exit RDAirPlay? + Gå ut av RDAirPlay? + + + User: + + + + Log: + + + + Service: + + + + Host + + + + Host: + + + + + ModeDisplay + + Operating Mode + Køyremodus + + + LiveAssist + Live-hjelp + + + Automatic + Automatisk + + + Manual + Manuelt + + + Aux1 + + + + Aux2 + + + + + PostCounter + + Next Timed Start + Neste tidlagte star + + + On Time + På tida + + + Next Timed Start [--:--:--] + Neste tidlagte start [--:--:--] + + + + QObject + + START + + + + STOP + STOPP + + + PAUSE + + + + RESUME + + + + WHERE? + + + + DELETE? + + + + MOVE? + + + + TO? + + + + COPY? + + + + ERROR + + + + + StopCounter + + Next Stop [none] + Neste stopp [ingen] + + + Next Stop + Neste stopp + + + Stopped + Stoppa + + + diff --git a/rdairplay/rdairplay_pt_BR.ts b/rdairplay/rdairplay_pt_BR.ts new file mode 100644 index 00000000..c237b203 --- /dev/null +++ b/rdairplay/rdairplay_pt_BR.ts @@ -0,0 +1,709 @@ + + + EditEvent + + Edit Event + Editar Evento + + + Start at: + Comece: + + + + Action If Previous Event Still Playing + Ação se evento prévio ainda está tocando + + + + Start Immediately + Inicie Imediatamente + + + + Make Next + Próximo + + + Wait up to + Espere até + + + Play + Simples + + + Segue + Sobre + + + Stop + Parar + + + Start Transition Type: + Tipo de Transição ao iniciar: + + + + No Fade at Segue Out + Sem Sobreposição de Fade na Saída + + + &Audition + &Audição + + + &Pause + &Pause + + + &Stop + &Pare + + + Start + Início + + + End + Fim + + + &OK + &OK + + + &Cancel + &Cancelar + + + Edit Marker + Editar Marcador + + + Edit Track + Editar Pista + + + Edit Log Track + Editar Pista da Lista + + + Transition If Previous Cart Ends Before + Transição se o Cartão anterior Terminar Antes + + + Duplicate Start Time + Duplicar Hora de Início + + + An event is already scheduled with this start time! + Um evento já está agendado com esta hora de início! + + + Cart Notes + + + + + HourSelector + + 12a + + + + 1a + + + + 2a + + + + 3a + + + + 4a + + + + 5a + + + + 6a + + + + 7a + + + + 8a + + + + 9a + + + + 10a + + + + 11a + + + + 12p + + + + 1p + + + + 2p + + + + 3p + + + + 4p + + + + 5p + + + + 6p + + + + 7p + + + + 8p + + + + 9p + + + + 10p + + + + 11p + + + + + ListLog + + EST TIME + HORA EST + + + LEN + DURAÇÃO + + + TRANS + TRANSIÇÃO + + + CART + CART + + + TITLE + TÍTULO + + + ARTIST + ARTISTA + + + GROUP + GRUPO + + + TIME + HORA PROGRAMDA + + + CLIENT + CLIENTE + + + AGENCY + AGÊNCIA + + + LABEL + SELO + + + LINE ID + ID de LINHA + + + COUNT + CONTADOR + + + STATUS + STATUS + + + Run Length + Durações + + + Next Stop: + Próxima Parada: + + + Log End: + Fim da Lista: + + + Select + Selecionar + + + Audition +Head + Audição +Início + + + Audition +Tail + Audição +Fim + + + Start + Início + + + Make +Next + Próximo + + + Modify + Modificar + + + Scroll + Rolagem + + + Refresh +Log + Atualizar + + + Select +Log + Sel Lista + + + Log Exists + Lista Existe + + + Log Already Exists! + Lista já Existe! + + + Selected: + Selecionado: + + + --- end of log --- + Fim da Lista + + + PLAY + TOQUE + + + STOP + PARE + + + SEGUE + SOBRE + + + MARKER + MARCADOR + + + TRACK + PISTA + + + LINK + LINK + + + [music import] + [importar música] + + + [traffic import] + [importar tráfego] + + + CHAIN TO + CORRENTE PARA + + + [CART NOT FOUND] + [CART NÃO ENCONTRADO] + + + [NO VALID CUT AVAILABLE] + [NÃO HÁ CONTEÚDO VÁLIDO] + + + [NO AUDIO AVAILABLE] + [NÃO HÁ ÁUDIO VÁLIDO] + + + T + T + + + Pause + Pausar + + + Stop + Parar + + + ALBUM + + + + + ListLogs + + Select a Log + Sel uma Lista + + + NAME + NOME + + + DESCRIPTION + Descrição + + + SERVICE + SERVIÇO + + + Load + Carregar + + + Unload + Descarregar + + + Save + Salvar + + + Save &As + Salvar &Como + + + Cancel + Cancelar + + + Rename Log + Renomear lista + + + + LogLineBox + + STOP + PARE + + + PLAY + Reproduzir + + + SEGUE + SOBRE + + + [CART NOT FOUND] + [CART NÃO ENCONTRADO] + + + [NO AUDIO AVAILABLE] + [NÃO HÁ ÁUDIO VÁLIDO] + + + [NO VALID CUT AVAILABLE] + [NÃO HÁ CONTEÚDO VÁLIDO] + + + MARKER + MARCADOR + + + TRACK + PISTA + + + LINK + LINK + + + [music import] + [importar música] + + + [traffic import] + [importar tráfego] + + + CHAIN + CORRENTE + + + T + T + + + + MainWidget + + RDAirPlay + RaDAr + + + Multiple instances not allowed! + Não é permitido múltiplas instâncias + + + RDAirPlay - Host: + RDAovivo - Cliente: + + + Database Error + Erro na Base de Dados + + + ADD + + + + + DEL + DEL + + + + MOVE + MOVER + + + + COPY + COPIAR + + + + Main Log +[--] + Lista Principal +[--] + + + + Aux 1 Log +[--] + LIsta Auxiliar 1 +[--] + + + + Aux 2 Log +[--] + Lista Auxiliar 2 +[--] + + + Sound +Panel + Painel +de Sons + + + Main Log + Lista Principal + + + Aux 1 Log + Lista Auxiliar 1 + + + Aux 2 Log + Lista Auxiliar 2 + + + LOG +REFRESHING + ATUALIZANDO +LISTA + + + Exit RDAirPlay? + Sair do RaDAr? + + + User: + + + + Log: + + + + Service: + + + + Host + + + + Host: + + + + + ModeDisplay + + Operating Mode + Modo de Operação + + + LiveAssist + Manuauto + + + Automatic + Automático + + + Manual + Manual + + + + Aux1 + + + + Aux2 + + + + + PostCounter + + Next Timed Start + Próxima com hora certa + + + On Time + No horário + + + Next Timed Start [--:--:--] + Próxima com hora certa [--:--:--] + + + + + + QObject + + START + + + + STOP + PARE + + + PAUSE + + + + RESUME + + + + WHERE? + + + + DELETE? + + + + MOVE? + + + + TO? + + + + COPY? + + + + ERROR + + + + + StopCounter + + Next Stop [none] + Próxima Parada [nehum] + + + Next Stop + Próxima Parada + + + Stopped + Parado + + + diff --git a/rdairplay/rlmhost.cpp b/rdairplay/rlmhost.cpp new file mode 100644 index 00000000..b76c8f9d --- /dev/null +++ b/rdairplay/rlmhost.cpp @@ -0,0 +1,528 @@ +// rlmhost.cpp +// +// A container class for a Rivendell Loadable Module host. +// +// (C) Copyright 2008 Fred Gleason +// +// $Id: rlmhost.cpp,v 1.7.6.9.2.1 2014/03/19 19:25:18 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include +#include + +#include +#include + + +RLMHost::RLMHost(const QString &path,const QString &arg, + QSocketDevice *udp_socket,QObject *parent,const char *name) + : QObject(parent,name) +{ + plugin_path=path; + plugin_arg=arg; + plugin_udp_socket=udp_socket; + plugin_handle=NULL; + plugin_start_sym=NULL; + plugin_free_sym=NULL; + plugin_pad_data_sent_sym=NULL; + plugin_timer_expired_sym=NULL; + plugin_serial_data_received_sym=NULL; + + // + // Utility Timers + // + QSignalMapper *mapper=new QSignalMapper(this); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(timerData(int))); + for(int i=0;isetMapping(plugin_callback_timers[i],i); + connect(plugin_callback_timers[i],SIGNAL(timeout()),mapper,SLOT(map())); + } +} + + +RLMHost::~RLMHost() +{ +} + + +QString RLMHost::pluginPath() const +{ + return plugin_path; +} + + +QString RLMHost::pluginArg() const +{ + return plugin_arg; +} + + +void RLMHost::sendEvent(const QString &svcname,const QString &logname, + int lognum,RDLogLine **loglines,bool onair, + RDAirPlayConf::OpMode mode) +{ + if(plugin_pad_data_sent_sym!=NULL) { + QDateTime now_dt(QDate::currentDate(),QTime::currentTime()); + struct rlm_svc *svc=new struct rlm_svc; + struct rlm_log *log=new struct rlm_log; + struct rlm_pad *now=new struct rlm_pad; + struct rlm_pad *next=new struct rlm_pad; + memset(svc,0,sizeof(svc)); + RDSvc *service=new RDSvc(svcname); + if(!svcname.isEmpty()) { + sprintf(svc->svc_name,"%s",(const char *)svcname.left(255)); + if(!service->programCode().isEmpty()) { + sprintf(svc->svc_pgmcode,"%s",(const char *)service->programCode()); + } + else { + svc->svc_pgmcode[0]=0; + } + } + else { + svc->svc_name[0]=0; + svc->svc_pgmcode[0]=0; + } + delete service; + memset(log,0,sizeof(log)); + if(!logname.isEmpty()) { + sprintf(log->log_name,"%s",(const char *)logname.left(64)); + } + else { + log->log_name[0]=0; + } + log->log_mach=lognum; + log->log_onair=onair; + log->log_mode=mode; + RLMHost::loadMetadata(loglines[0],now,now_dt); + RLMHost::loadMetadata(loglines[1],next); + plugin_pad_data_sent_sym(this,svc,log,now,next); + delete next; + delete now; + delete log; + delete svc; + } +} + + +bool RLMHost::load() +{ + QString basename=RDGetBasePart(plugin_path); + basename=basename.left(basename.findRev(".")); + if((plugin_handle=dlopen(plugin_path,RTLD_LAZY))==NULL) { + return false; + } + *(void **)(&plugin_start_sym)=dlsym(plugin_handle,basename+"_RLMStart"); + *(void **)(&plugin_free_sym)=dlsym(plugin_handle,basename+"_RLMFree"); + *(void **)(&plugin_pad_data_sent_sym)= + dlsym(plugin_handle,basename+"_RLMPadDataSent"); + *(void **)(&plugin_timer_expired_sym)= + dlsym(plugin_handle,basename+"_RLMTimerExpired"); + *(void **)(&plugin_serial_data_received_sym)= + dlsym(plugin_handle,basename+"_RLMSerialDataReceived"); + if(plugin_start_sym!=NULL) { + plugin_start_sym(this,plugin_arg); + } + + return true; +} + + +void RLMHost::unload() +{ + if(plugin_free_sym!=NULL) { + plugin_free_sym(this); + } +} + + +void RLMHost::loadMetadata(const RDLogLine *logline,struct rlm_pad *pad, + const QDateTime &start_datetime) +{ + QDateTime now(QDate::currentDate(),QTime::currentTime()); + + if(pad==NULL) { + return; + } + memset(pad,0,sizeof(struct rlm_pad)); + if(logline==NULL) { + return; + } + if(logline!=NULL) { + pad->rlm_cartnum=logline->cartNumber(); + switch(logline->cartType()) { + case RDCart::Audio: + pad->rlm_len=logline->effectiveLength(); + break; + + case RDCart::Macro: + if((logline->eventLength()>=0)&&logline->useEventLength()) { + pad->rlm_len=logline->eventLength(); + } + else { + pad->rlm_len=logline->effectiveLength(); + } + break; + + case RDCart::All: + break; + } + pad->rlm_carttype=logline->cartType(); + if(!logline->year().isNull()) { + snprintf(pad->rlm_year,5,"%s", + (const char *)logline->year().toString("YYYY")); + } + if(!logline->groupName().isEmpty()) { + snprintf(pad->rlm_group,11,"%s", + (const char *)logline->groupName().utf8()); + } + if(!logline->title().isEmpty()) { + snprintf(pad->rlm_title,256,"%s",(const char *)logline->title().utf8()); + } + if(!logline->artist().isEmpty()) { + snprintf(pad->rlm_artist,256,"%s",(const char *)logline->artist().utf8()); + } + if(!logline->label().isEmpty()) { + snprintf(pad->rlm_label,65,"%s",(const char *)logline->label().utf8()); + } + if(!logline->client().isEmpty()) { + snprintf(pad->rlm_client,65,"%s",(const char *)logline->client().utf8()); + } + if(!logline->agency().isEmpty()) { + snprintf(pad->rlm_agency,65,"%s",(const char *)logline->agency().utf8()); + } + if(!logline->composer().isEmpty()) { + snprintf(pad->rlm_comp,65,"%s",(const char *)logline->composer().utf8()); + } + if(!logline->publisher().isEmpty()) { + snprintf(pad->rlm_pub,65,"%s",(const char *)logline->publisher().utf8()); + } + if(!logline->userDefined().isEmpty()) { + snprintf(pad->rlm_userdef,256,"%s", + (const char *)logline->userDefined().utf8()); + } + if(!logline->outcue().isEmpty()) { + snprintf(pad->rlm_outcue,65,"%s",(const char *)logline->outcue().utf8()); + } + if(!logline->description().isEmpty()) { + snprintf(pad->rlm_description,65,"%s", + (const char *)logline->description().utf8()); + } + if(!logline->conductor().isEmpty()) { + snprintf(pad->rlm_conductor,65,"%s", + (const char *)logline->conductor().utf8()); + } + if(!logline->songId().isEmpty()) { + snprintf(pad->rlm_song_id,33,"%s",(const char *)logline->songId().utf8()); + } + if(!logline->album().isEmpty()) { + snprintf(pad->rlm_album,256,"%s",(const char *)logline->album().utf8()); + } + if(!logline->isrc().isEmpty()) { + strncpy(pad->rlm_isrc,(const char *)logline->isrc().utf8().left(12),12); + } + if(!logline->isci().isEmpty()) { + strncpy(pad->rlm_isci,(const char *)logline->isci().utf8().left(32),32); + } + if(!logline->extData().isEmpty()) { + snprintf(pad->rlm_ext_data,32,"%s",(const char *)logline->extData()); + } + if(!logline->extEventId().isEmpty()) { + snprintf(pad->rlm_ext_eventid,32,"%s", + (const char *)logline->extEventId()); + } + if(!logline->extAnncType().isEmpty()) { + snprintf(pad->rlm_ext_annctype,32,"%s", + (const char *)logline->extAnncType()); + } + if(start_datetime.isValid()) { + pad->rlm_start_msec=start_datetime.time().msec(); + pad->rlm_start_sec=start_datetime.time().second(); + pad->rlm_start_min=start_datetime.time().minute(); + pad->rlm_start_hour=start_datetime.time().hour(); + pad->rlm_start_day=start_datetime.date().day(); + pad->rlm_start_mon=start_datetime.date().month(); + pad->rlm_start_year=start_datetime.date().year(); + } + else { + QTime start_time=logline->startTime(RDLogLine::Predicted); + if(start_time.isNull()) { + start_time=logline->startTime(RDLogLine::Imported); + } + if(!start_time.isNull()) { + if(start_timerlm_start_msec=start_time.msec(); + pad->rlm_start_sec=start_time.second(); + pad->rlm_start_min=start_time.minute(); + pad->rlm_start_hour=start_time.hour(); + pad->rlm_start_day=now.date().day(); + pad->rlm_start_mon=now.date().month(); + pad->rlm_start_year=now.date().year(); + } + } +} + + +void RLMHost::saveMetadata(const struct rlm_pad *pad,RDLogLine *logline) +{ + if(logline==NULL) { + return; + } + logline->clear(); + if(pad==NULL) { + return; + } + logline->setCartNumber(pad->rlm_cartnum); + logline->setForcedLength(pad->rlm_len); + logline->setYear(QDate(QString(pad->rlm_year).toInt(),1,1)); + logline->setGroupName(pad->rlm_group); + logline->setTitle(pad->rlm_title); + logline->setArtist(pad->rlm_artist); + logline->setLabel(pad->rlm_label); + logline->setClient(pad->rlm_client); + logline->setAgency(pad->rlm_agency); + logline->setComposer(pad->rlm_comp); + logline->setPublisher(pad->rlm_pub); + logline->setUserDefined(pad->rlm_userdef); + logline->setOutcue(pad->rlm_outcue); + logline->setDescription(pad->rlm_description); + logline->setAlbum(pad->rlm_album); + logline->setIsrc(QString::fromAscii(pad->rlm_isrc,12)); + logline->setIsci(QString::fromAscii(pad->rlm_isci,32)); + if((pad->rlm_start_year>0)&&(pad->rlm_start_mon>0)&&(pad->rlm_start_day)) { + logline->setStartDatetime(QDateTime(QDate(pad->rlm_start_year, + pad->rlm_start_mon, + pad->rlm_start_day), + QTime(pad->rlm_start_hour, + pad->rlm_start_min, + pad->rlm_start_sec, + pad->rlm_start_msec))); + } + else { + logline->setStartDatetime(QDateTime()); + } +} + + +void RLMHost::timerData(int timernum) +{ + if(plugin_timer_expired_sym!=NULL) { + plugin_timer_expired_sym(this,timernum); + } +} + + +void RLMHost::ttyReceiveReadyData(int fd) +{ + char data[1024]; + int n; + + for(unsigned i=0;isocket()==fd) { + while((n=plugin_tty_devices[i]->readBlock(data,1024))>0) { + if(plugin_serial_data_received_sym!=NULL) { + plugin_serial_data_received_sym(this,i,data,n); + } + } + return; + } + } + fprintf(stderr,"unknown tty descriptor: %d\n",fd); +} + + +// +// RLM Utility Functions +// +void RLMSendUdp(void *ptr,const char *ipaddr,uint16_t port, + const char *data,int len) +{ + RLMHost *host=(RLMHost *)ptr; + QHostAddress addr; + addr.setAddress(ipaddr); + if(!addr.isNull()) { + host->plugin_udp_socket->writeBlock(data,len,addr,port); + } +} + + +int RLMOpenSerial(void *ptr,const char *port,int speed,int parity, + int word_length) +{ + RLMHost *host=(RLMHost *)ptr; + host->plugin_tty_devices.push_back(new RDTTYDevice); + host->plugin_tty_devices.back()->setName(port); + host->plugin_tty_devices.back()->setSpeed(speed); + host->plugin_tty_devices.back()->setParity((RDTTYDevice::Parity)parity); + host->plugin_tty_devices.back()->setWordLength(word_length); + if(host->plugin_tty_devices.back()->open(IO_ReadWrite)) { + + host->plugin_tty_notifiers. + push_back(new QSocketNotifier(host->plugin_tty_devices.back()->socket(), + QSocketNotifier::Read)); + host->connect(host->plugin_tty_notifiers.back(),SIGNAL(activated(int)), + host,SLOT(ttyReceiveReadyData(int))); + return (int)host->plugin_tty_devices.size()-1; + } + return -1; +} + + +void RLMSendSerial(void *ptr,int handle,const char *data,int len) +{ + RLMHost *host=(RLMHost *)ptr; + if((handle<0)||(handle>=(int)host->plugin_tty_devices.size())) { + return; + } + host->plugin_tty_devices[handle]->writeBlock(data,len); +} + + +void RLMCloseSerial(void *ptr,int handle) +{ + RLMHost *host=(RLMHost *)ptr; + + // + // FIXME: We really ought to take out the trash here! + // + host->plugin_tty_devices[handle]->close(); + delete host->plugin_tty_devices[handle]; + host->plugin_tty_devices[handle]=NULL; +} + + +const char *RLMDateTime(void *ptr,int offset_msecs,const char *format) +{ + RLMHost *host=(RLMHost *)ptr; + QDateTime datetime=QDateTime(QDate::currentDate(),QTime::currentTime(). + addMSecs(offset_msecs)); + strncpy(host->plugin_value_string,datetime.toString(format),1024); + return host->plugin_value_string; +} + + +const char *RLMResolveNowNextEncoded(void *ptr,const struct rlm_pad *now, + const struct rlm_pad *next, + const char *format,int encoding) +{ + RLMHost *host=(RLMHost *)ptr; + RDLogLine *loglines[2]; + QString str=format; + + loglines[0]=new RDLogLine(); + loglines[1]=new RDLogLine(); + RLMHost::saveMetadata(now,loglines[0]); + RLMHost::saveMetadata(next,loglines[1]); + RDResolveNowNext(&str,loglines,encoding); + strncpy(host->plugin_value_string,str,1024); + delete loglines[1]; + delete loglines[0]; + + return host->plugin_value_string; +} + + +const char *RLMResolveNowNext(void *ptr,const struct rlm_pad *now, + const struct rlm_pad *next,const char *format) +{ + return RLMResolveNowNextEncoded(ptr,now,next,format,RLM_ENCODE_NONE); +} + + +void RLMLog(void *ptr,int prio,const char *msg) +{ + LogLine((RDConfig::LogPriority)prio,msg); +} + + +void RLMStartTimer(void *ptr,int timernum,int msecs,int mode) +{ + RLMHost *host=(RLMHost *)ptr; + if((timernum<0)||(timernum>=RLM_MAX_TIMERS)) { + return; + } + if(host->plugin_callback_timers[timernum]->isActive()) { + host->plugin_callback_timers[timernum]->stop(); + } + host->plugin_callback_timers[timernum]->start(msecs,mode); +} + + +void RLMStopTimer(void *ptr,int timernum) +{ + RLMHost *host=(RLMHost *)ptr; + if((timernum<0)||(timernum>=RLM_MAX_TIMERS)) { + return; + } + if(host->plugin_callback_timers[timernum]->isActive()) { + host->plugin_callback_timers[timernum]->stop(); + } +} + + +int RLMGetIntegerValue(void *ptr,const char *filename,const char *section, + const char *label,int default_value) +{ + RDProfile *p=new RDProfile(); + p->setSource(filename); + int r=p->intValue(section,label,default_value); + delete p; + return r; +} + + +int RLMGetHexValue(void *ptr,const char *filename,const char *section, + const char *label,int default_value) +{ + RDProfile *p=new RDProfile(); + p->setSource(filename); + int r=p->hexValue(section,label,default_value); + delete p; + return r; +} + + +int RLMGetBooleanValue(void *ptr,const char *filename,const char *section, + const char *label,int default_value) +{ + RDProfile *p=new RDProfile(); + p->setSource(filename); + bool r=p->boolValue(section,label,default_value); + delete p; + return (int)r; +} + + +const char *RLMGetStringValue(void *ptr,const char *filename, + const char *section,const char *label, + const char *default_value) +{ + RLMHost *host=(RLMHost *)ptr; + RDProfile *p=new RDProfile(); + p->setSource(filename); + strncpy(host->plugin_value_string, + p->stringValue(section,label,default_value),1024); + delete p; + return host->plugin_value_string; +} diff --git a/rdairplay/rlmhost.h b/rdairplay/rlmhost.h new file mode 100644 index 00000000..e4afa086 --- /dev/null +++ b/rdairplay/rlmhost.h @@ -0,0 +1,106 @@ +// rlmhost.h +// +// A container class for a Rivendell Loadable Module host. +// +// (C) Copyright 2008 Fred Gleason +// +// $Id: rlmhost.h,v 1.6.6.3 2013/11/05 20:16:41 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RLMHOST_H +#define RLMHOST_H + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "../rlm/rlm.h" + +class RLMHost : public QObject +{ + Q_OBJECT + public: + RLMHost(const QString &path,const QString &arg,QSocketDevice *udp_socket, + QObject *parent=0,const char *name=0); + ~RLMHost(); + QString pluginPath() const; + QString pluginArg() const; + void sendEvent(const QString &svcname,const QString &logname, + int lognum,RDLogLine **loglines,bool onair, + RDAirPlayConf::OpMode mode); + bool load(); + void unload(); + static void loadMetadata(const RDLogLine *logline,struct rlm_pad *pad, + const QDateTime &start_datetime=QDateTime()); + static void saveMetadata(const struct rlm_pad *pad,RDLogLine *logline); + private slots: + void timerData(int timernum); + void ttyReceiveReadyData(int fd); + + private: + QString plugin_path; + QString plugin_arg; + QSocketDevice *plugin_udp_socket; + void *plugin_handle; + void (*plugin_start_sym)(void *,const char *); + void (*plugin_free_sym)(void *); + void (*plugin_pad_data_sent_sym) + (void *,const struct rlm_svc *,const struct rlm_log *, + const struct rlm_pad *,const struct rlm_pad *); + void (*plugin_timer_expired_sym)(void *,int); + void (*plugin_serial_data_received_sym)(void *,int,const char *,int); + + std::vector plugin_tty_devices; + std::vector plugin_tty_notifiers; + QTimer *plugin_callback_timers[RLM_MAX_TIMERS]; + friend void RLMSendUdp(void *ptr,const char *ipaddr,uint16_t port, + const char *data,int len); + friend int RLMOpenSerial(void *ptr,const char *port,int speed, + int parity,int word_length); + friend void RLMSendSerial(void *ptr,int handle,const char *data, + int len); + friend void RLMCloseSerial(void *ptr,int handle); + friend const char *RLMDateTime(int offset_msecs,const char *format); + friend const char *RLMResolveNowNextEncoded(void *ptr, + const struct rlm_pad *now, + const struct rlm_pad *next, + const char *format, + int encoding); + friend const char *RLMResolveNowNext(void *ptr, + const struct rlm_pad *now, + const struct rlm_pad *next, + const char *format); + friend void RLMLog(void *ptr,int prio,const char *msg); + friend void RLMStartTimer(void *ptr,int timernum,int msecs, + int mode); + friend void RLMStopTimer(void *ptr,int timernum); + friend const char *RLMDateTime(void *ptr,int offset_msecs, + const char *format); + friend const char *RLMGetStringValue(void *ptr,const char *filename, + const char *section,const char *label, + const char *default_value); + char plugin_value_string[1024]; +}; + + +#endif // RLMHOST_H diff --git a/rdairplay/start_button.cpp b/rdairplay/start_button.cpp new file mode 100644 index 00000000..19fafa17 --- /dev/null +++ b/rdairplay/start_button.cpp @@ -0,0 +1,250 @@ +// start_button.cpp +// +// The Start Button for RDAirPlay Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: start_button.cpp,v 1.27 2011/02/11 23:06:05 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include + +#include +#include + + +StartButton::StartButton(bool allow_pause,QWidget *parent,const char *name) + : QPushButton(parent,name) +{ + start_time_mode=RDAirPlayConf::TwentyFourHour; + start_time=QTime(); + start_allow_pause=allow_pause; + + // + // Create Fonts + // + start_label_font=QFont("Helvetica",12,QFont::Bold); + start_label_font.setPixelSize(12); + start_counter_font=QFont("Helvetica",10,QFont::Normal); + start_counter_font.setPixelSize(10); + start_port_font=QFont("Helvetica",20,QFont::Bold); + start_port_font.setPixelSize(20); + + // + // Create Palettes + // + start_stop_color= + QPalette(QColor(BUTTON_STOPPED_BACKGROUND_COLOR),backgroundColor()); + start_play_color= + QPalette(QColor(BUTTON_PLAY_BACKGROUND_COLOR),backgroundColor()); + start_play_color. + setColor(QColorGroup::ButtonText,QColor(BUTTON_PLAY_TEXT_COLOR)); + start_pause_color= + QPalette(QColor(BUTTON_PAUSE_BACKGROUND_COLOR),backgroundColor()); + start_pause_color. + setColor(QColorGroup::ButtonText,QColor(BUTTON_PAUSE_TEXT_COLOR)); + + start_from_color= + QPalette(QColor(BUTTON_FROM_BACKGROUND_COLOR),backgroundColor()); + start_from_color. + setColor(QColorGroup::ButtonText,QColor(BUTTON_FROM_TEXT_COLOR)); + + start_to_color= + QPalette(QColor(BUTTON_TO_BACKGROUND_COLOR),backgroundColor()); + start_to_color. + setColor(QColorGroup::ButtonText,QColor(BUTTON_TO_TEXT_COLOR)); + + start_disabled_color= + QPalette(QColor(BUTTON_DISABLED_BACKGROUND_COLOR),backgroundColor()); + start_disabled_color. + setColor(QColorGroup::ButtonText,QColor(BUTTON_DISABLED_TEXT_COLOR)); + + start_error_color= + QPalette(QColor(BUTTON_ERROR_BACKGROUND_COLOR),backgroundColor()); + start_error_color. + setColor(QColorGroup::ButtonText,QColor(BUTTON_ERROR_TEXT_COLOR)); + + start_mode=StartButton::Stop; + setMode(StartButton::Disabled,RDCart::All); +} + + +void StartButton::setTime(QString str) +{ + start_time=QTime(); + Resize(geometry().x(),geometry().y(),geometry().width(),geometry().height()); +} + + +void StartButton::setTime(QTime time) +{ + start_time=time; + Resize(geometry().x(),geometry().y(),geometry().width(),geometry().height()); +} + + +void StartButton::setPort(QString port) +{ + start_port=port; + Resize(geometry().x(),geometry().y(),geometry().width(),geometry().height()); +} + + +StartButton::Mode StartButton::mode() const +{ + return start_mode; +} + + +void StartButton::setMode(Mode mode,RDCart::Type cart_type) +{ + if(mode==start_mode) { + return; + } + start_mode=mode; + switch(mode) { + case StartButton::Stop: + setPalette(start_stop_color); + start_title=STOP_MODE_TITLE; + break; + + case StartButton::Play: + setPalette(start_play_color); + if(start_allow_pause&&(cart_type!=RDCart::Macro)) { + start_title=PLAY1_MODE_TITLE; + } + else { + start_title=PLAY0_MODE_TITLE; + } + break; + + case StartButton::Pause: + setPalette(start_pause_color); + start_title=PAUSE_MODE_TITLE; + break; + + case StartButton::MoveFrom: + setPalette(start_from_color); + start_title=MOVE_FROM_MODE_TITLE; + break; + + case StartButton::DeleteFrom: + setPalette(start_from_color); + start_title=DELETE_FROM_MODE_TITLE; + break; + + case StartButton::AddFrom: + break; + + case StartButton::AddTo: + setPalette(start_to_color); + start_title=ADD_TO_MODE_TITLE; + break; + + case StartButton::MoveTo: + setPalette(start_to_color); + start_title=MOVE_TO_MODE_TITLE; + break; + + case StartButton::CopyTo: + setPalette(start_to_color); + start_title=COPY_TO_MODE_TITLE; + break; + + case StartButton::CopyFrom: + setPalette(start_from_color); + start_title=COPY_FROM_MODE_TITLE; + break; + + case StartButton::Disabled: + setPalette(start_disabled_color); + start_title=DISABLED_MODE_TITLE; + break; + + case StartButton::Error: + setPalette(start_error_color); + start_title=ERROR_MODE_TITLE; + break; + } + Resize(geometry().x(),geometry().y(),geometry().width(),geometry().height()); +} + + +void StartButton::setTimeMode(RDAirPlayConf::TimeMode mode) +{ + if(mode==start_time_mode) { + return; + } + start_time_mode=mode; + Resize(geometry().x(),geometry().y(),geometry().width(),geometry().height()); +} + + +void StartButton::setGeometry(int x,int y,int w,int h) +{ + Resize(x,y,w,h); + QPushButton::setGeometry(x,y,w,h); +} + + +void StartButton::setGeometry(QRect rect) +{ + setGeometry(rect.x(),rect.y(),rect.width(),rect.height()); +} + + +void StartButton::Resize(int x,int y,int w,int h) +{ + QPixmap *pix=new QPixmap(w,h); + QPainter *p=new QPainter(); + p->begin(pix); + p->fillRect(0,0,w,h,palette().color(QPalette::Active,QColorGroup::Button)); + //p->eraseRect(0,0,w,h); + if(start_mode!=StartButton::Disabled) { + p->setPen(QColor(color1)); + p->setFont(start_label_font); + p->drawText((geometry().width()-p->fontMetrics().width(start_title))/2, + 22,start_title); + p->moveTo(10,24); + p->lineTo(70,24); + p->setFont(start_counter_font); + if(!start_time.isNull()) { + if(start_time_mode==RDAirPlayConf::TwentyFourHour) { + p->drawText((geometry().width()-p-> + fontMetrics().width(start_time.toString("hh:mm:ss")))/2, + 40,start_time.toString("hh:mm:ss")); + } + else { + p->drawText((geometry().width()-p-> + fontMetrics().width(start_time.toString("h:mm:ss ap")))/2, + 40,start_time.toString("h:mm:ss ap")); + } + } + else { + p->drawText((geometry().width()-p->fontMetrics().width("--:--:--"))/2, + 40,"--:--:--"); + } + p->setFont(start_port_font); + p->drawText(15,70,start_port); + } + p->end(); + setPixmap(*pix); + delete p; + delete pix; +} diff --git a/rdairplay/start_button.h b/rdairplay/start_button.h new file mode 100644 index 00000000..734fa48b --- /dev/null +++ b/rdairplay/start_button.h @@ -0,0 +1,72 @@ +// start_button.h +// +// The Start Button for RDAirPlay Rivendell +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: start_button.h,v 1.16 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef START_BUTTON_H +#define START_BUTTON_H + +#include +#include +#include +#include + +#include +#include + +class StartButton : public QPushButton +{ + Q_OBJECT + public: + enum Mode {Stop=0,Play=1,Pause=2,AddFrom=3,AddTo=4,DeleteFrom=5, + MoveFrom=6,MoveTo=7,CopyFrom=8,CopyTo=9,Disabled=10,Error=11}; + StartButton(bool allow_pause=false,QWidget *parent=0,const char *name=0); + void setTime(QString); + void setTime(QTime); + void setPort(QString port); + StartButton::Mode mode() const; + void setMode(Mode mode,RDCart::Type cart_type); + void setTimeMode(RDAirPlayConf::TimeMode mode); + + public slots: + void setGeometry(int x,int y,int w,int h); + void setGeometry(QRect rect); + + private: + void Resize(int x,int y,int w,int h); + StartButton::Mode start_mode; + QFont start_label_font; + QFont start_counter_font; + QFont start_port_font; + QString start_title; + QString start_port; + QPalette start_stop_color; + QPalette start_play_color; + QPalette start_pause_color; + QPalette start_from_color; + QPalette start_to_color; + QPalette start_disabled_color; + QPalette start_error_color; + RDAirPlayConf::TimeMode start_time_mode; + QTime start_time; + bool start_allow_pause; +}; + +#endif diff --git a/rdairplay/stop_counter.cpp b/rdairplay/stop_counter.cpp new file mode 100644 index 00000000..a4978059 --- /dev/null +++ b/rdairplay/stop_counter.cpp @@ -0,0 +1,172 @@ +// stop_counter.cpp +// +// The stop counter widget for Rivendell +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: stop_counter.cpp,v 1.21 2011/01/10 19:27:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include + +StopCounter::StopCounter(QWidget *parent,const char *name) + : QPushButton(parent,name) +{ + stop_running=false; + + // + // Generate Fonts + // + stop_text_font=QFont("Helvetica",12,QFont::Normal); + stop_text_font.setPixelSize(12); + stop_time_font=QFont("Helvetica",26,QFont::Normal); + stop_time_font.setPixelSize(26); + + time_format = "hh:mm:ss"; + stop_text=tr("Next Stop [none]"); + old_stop_running = true; + old_msecs = 0; + setTime(QTime()); + setState(false); +} + +void StopCounter::setTimeMode(RDAirPlayConf::TimeMode mode) +{ + switch(mode) { + case RDAirPlayConf::TwentyFourHour: + time_format="hh:mm:ss"; + break; + + case RDAirPlayConf::TwelveHour: + time_format="h:mm:ss ap"; + break; + } + old_msecs = 0; + if (stop_running) { + setTime (stop_time); + } + UpdateTime(); +} + + +QSize StopCounter::sizeHint() const +{ + return QSize(200,60); +} + + +QSizePolicy StopCounter::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void StopCounter::setState(bool state) +{ + QString str; + + if(state) { + if(!stop_running) { + UpdateTime(); + stop_running=true; + str=QString(tr("Next Stop")); + stop_text= + QString().sprintf("%s [%s]",(const char *)str, + (const char *)stop_time.toString(time_format)); + } + } + else { + if(stop_running) { + stop_text=tr("Next Stop [none]"); + stop_running=false; + UpdateTime(); + } + } +} + + +void StopCounter::setTime(QTime time) +{ + QString str; + + if(!time.isNull()) { + stop_time=time; + setState(true); + str=QString(tr("Next Stop")); + stop_text=QString().sprintf("%s [%s]",(const char *)str, + (const char *)stop_time.toString(time_format)); + } + else { + setState(false); + } + UpdateTime(); +} + + +void StopCounter::tickCounter() +{ + if(stop_running) { + UpdateTime(); + } +} + + +void StopCounter::UpdateTime() +{ + QString text; + int msecs=QTime::currentTime(). + addMSecs(rdstation_conf->timeOffset()).msecsTo(stop_time); + + if ((old_stop_running != stop_running) || (msecs/1000 != old_msecs/1000)){ + QPixmap pix(sizeHint().width(),sizeHint().height()); + QPainter *p=new QPainter(&pix); + old_stop_running = stop_running; + old_msecs = msecs; + + p->fillRect(0,0,sizeHint().width(),sizeHint().height(), + backgroundColor()); + //p->eraseRect(0,0,sizeHint().width(),sizeHint().height()); + p->setPen(QColor(color1)); + p->setFont(stop_text_font); + p->drawText((sizeHint().width()-p->fontMetrics().width(stop_text))/2,22, + stop_text); + p->setFont(stop_time_font); + if (msecs < 0){ + /* HACK HACK HACK TODO */ + /* msecs is **PROBABLY** in the next day + (we have a log crossing midnight - logs + longer then 24 hours are NOT supported by this, + please fix).... */ + msecs += 86400000; /* 1 day */ + } + if(stop_running) { + text=QTime(0,0,1).addMSecs(msecs).toString("hh:mm:ss"); + p->drawText((sizeHint().width()-p->fontMetrics().width(text))/2,49,text); + } + else { + p->drawText((sizeHint().width()-p-> + fontMetrics().width(tr("Stopped")))/2,49, + tr("Stopped")); + } + p->end(); + delete p; + setPixmap(pix); + } +} diff --git a/rdairplay/stop_counter.h b/rdairplay/stop_counter.h new file mode 100644 index 00000000..126a3ecc --- /dev/null +++ b/rdairplay/stop_counter.h @@ -0,0 +1,57 @@ +// stop_counter.h +// +// The post counter widget for Rivendell +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: stop_counter.h,v 1.11 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef STOP_COUNTER_H +#define STOP_COUNTER_H + +#include +#include +#include +#include + +class StopCounter : public QPushButton +{ + Q_OBJECT + public: + StopCounter(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void setState(bool state); + void setTimeMode(RDAirPlayConf::TimeMode mode); + + public slots: + void setTime(QTime time); + void tickCounter(); + + private: + void UpdateTime(); + QTime stop_time; + bool stop_running; + bool old_stop_running; + int old_msecs; + QFont stop_time_font; + QFont stop_text_font; + QString stop_text; + QString time_format; +}; + +#endif diff --git a/rdairplay/wall_clock.cpp b/rdairplay/wall_clock.cpp new file mode 100644 index 00000000..b8b142ea --- /dev/null +++ b/rdairplay/wall_clock.cpp @@ -0,0 +1,183 @@ +// wall_clock.cpp +// +// A wall-clock widget with date. +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: wall_clock.cpp,v 1.21 2011/01/11 12:20:31 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +WallClock::WallClock(QWidget *parent,const char *name) + :QPushButton(parent,name) +{ + time_offset=rdstation_conf->timeOffset(); + previous_time=QTime::currentTime().addMSecs(time_offset); + time_mode=RDAirPlayConf::TwentyFourHour; + previous_time_mode = RDAirPlayConf::TwentyFourHour; + show_date=true; + // setFlashColor(QColor(BUTTON_TIME_SYNC_LOST_COLOR)); + check_sync=true; + flash_state=false; + + // + // Generate Fonts + // + label_font=QFont("Helvetica",10,QFont::Normal); + label_font.setPixelSize(10); + label_metrics=new QFontMetrics(label_font); + time_font=QFont("Helvetica",26,QFont::Normal); + time_font.setPixelSize(26); + + connect(this,SIGNAL(clicked()),this,SLOT(clickedData())); +} + + +QSize WallClock::sizeHint() const +{ + return QSize(200,60); +} + + +QSizePolicy WallClock::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); +} + + +void WallClock::setDateDisplay(bool state) +{ + show_date=state; +} + + +void WallClock::setTimeMode(RDAirPlayConf::TimeMode mode) +{ + if(mode==time_mode) { + return; + } + time_mode=mode; + emit timeModeChanged(time_mode); +} + + +void WallClock::setCheckSyncEnabled(bool state) +{ + check_sync=state; +} + + +void WallClock::clickedData() +{ + if(time_mode==RDAirPlayConf::TwelveHour) { + setTimeMode(RDAirPlayConf::TwentyFourHour); + } + else { + setTimeMode(RDAirPlayConf::TwelveHour); + } +} + + +void WallClock::tickClock() +{ + static QString date; + QString accum; + static QPixmap *pix=new QPixmap(sizeHint().width(),sizeHint().height()); + static bool synced=true; + + if(check_sync) { + if(RDTimeSynced()!=synced) { + synced=RDTimeSynced(); + //setFlashingEnabled(!synced); + } + } + current_time=QTime::currentTime().addMSecs(time_offset); + current_date=QDate::currentDate(); + if((current_time.second()==previous_time.second()) && (previous_time_mode == time_mode)) { + return; + } + previous_time_mode = time_mode; + previous_time=current_time; + + // + // Clock Display + // + if(time_mode==RDAirPlayConf::TwelveHour) { + accum=current_time.toString("h:mm:ss ap"); + } + else { + accum=current_time.toString("hh:mm:ss"); + } + if(time_string==accum) { + return; + } + time_string=accum; + if(synced) { + flash_state=false; + } + else { + flash_state=!flash_state; + } + if(previous_date!=current_date) { + previous_date=current_date; + date=current_date.toString("dddd, MMMM d, yyyy"); + } + QPainter p(pix); + if(flash_state) { + p.fillRect(0,0,width(),height(),BUTTON_TIME_SYNC_LOST_COLOR); + } + else { + p.fillRect(0,0,width(),height(),backgroundColor()); + } + //p.eraseRect(0,0,width(),height()); + p.setPen(color1); + p.setBrush(color1); + p.setFont(label_font); + p.drawText((sizeHint().width()-p.fontMetrics().width(date))/2,22,date); + p.setFont(time_font); + p.drawText((sizeHint().width()-p.fontMetrics().width(accum))/2,48,accum); + p.end(); + setPixmap(*pix); +} + + +void WallClock::flashButton(bool state) +{ + printf("flashButton()\n"); + flash_state=state; + tickClock(); + // RDPushButton::flashButton(state); +} + + +void WallClock::keyPressEvent(QKeyEvent *e) +{ + e->ignore(); +} diff --git a/rdairplay/wall_clock.h b/rdairplay/wall_clock.h new file mode 100644 index 00000000..ad40420d --- /dev/null +++ b/rdairplay/wall_clock.h @@ -0,0 +1,73 @@ +// wall_clock.h +// +// The wall clock widget for Rivendell +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: wall_clock.h,v 1.14 2011/01/11 12:20:31 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WALL_CLOCK_H +#define WALL_CLOCK_H + +#include +#include +#include + +#include + +#include + +class WallClock : public QPushButton +{ + Q_OBJECT + public: + WallClock(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void setDateDisplay(bool state); + void setTimeMode(RDAirPlayConf::TimeMode mode); + void setCheckSyncEnabled(bool); + + private slots: + void clickedData(); + + public slots: + void tickClock(); + + signals: + void timeModeChanged(RDAirPlayConf::TimeMode); + + protected: + void flashButton(bool state); + void keyPressEvent(QKeyEvent *e); + + private: + QTime previous_time,current_time; + QDate previous_date,current_date; + QString time_string; + RDAirPlayConf::TimeMode time_mode; + RDAirPlayConf::TimeMode previous_time_mode; + bool show_date; + QFont time_font; + QFont label_font; + QFontMetrics *label_metrics; + bool check_sync; + int time_offset; + bool flash_state; +}; + +#endif diff --git a/rdcartslots/Makefile.am b/rdcartslots/Makefile.am new file mode 100644 index 00000000..c87a80bb --- /dev/null +++ b/rdcartslots/Makefile.am @@ -0,0 +1,69 @@ +## automake.am +## +## Automake.am for rivendell/rdcartslots +## +## (C) Copyright 2012 Fred Gleason +## +## $Id: Makefile.am,v 1.4.2.2 2012/11/16 18:10:40 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdcartslots_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rdcartslots_*.qm + +all: + lupdate rdcartslots.pro + lrelease rdcartslots.pro + +bin_PROGRAMS = rdcartslots + +dist_rdcartslots_SOURCES = local_macros.cpp\ + rdcartslots.cpp rdcartslots.h + +nodist_rdcartslots_SOURCES = moc_rdcartslots.cpp + +rdcartslots_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdcartslots.pro\ + rdcartslots_de.ts\ + rdcartslots_es.ts\ + rdcartslots_fr.ts\ + rdcartslots_nb.ts\ + rdcartslots_nn.ts\ + rdcartslots_pt_BR.ts + +CLEANFILES = *~\ + moc_*\ + *.qm + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/rdcartslots/local_macros.cpp b/rdcartslots/local_macros.cpp new file mode 100644 index 00000000..e7f0995a --- /dev/null +++ b/rdcartslots/local_macros.cpp @@ -0,0 +1,201 @@ +// local_macros.cpp +// +// A Dedicated Cart Slot Utility for Rivendell. +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: local_macros.cpp,v 1.2.2.3 2012/11/28 21:44:08 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include "rdcartslots.h" + +void MainWidget::RunLocalMacros(RDMacro *rml) +{ + bool ok=false; + unsigned slotnum; + unsigned cartnum; + unsigned len; + + if(rml->role()!=RDMacro::Cmd) { + return; + } + + switch(rml->command()) { + case RDMacro::DL: + if(rml->argQuantity()!=2) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + slotnum=rml->arg(0).toUInt(&ok)-1; + if((!ok)||(slotnum>=panel_slots.size())) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + if(panel_slots[slotnum]->slotOptions()->mode()!= + RDSlotOptions::CartDeckMode) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + cartnum=rml->arg(1).toUInt(&ok); + if((!ok)||(cartnum>999999)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + if(cartnum==0) { + panel_slots[slotnum]->unload(); + } + else { + if(!panel_slots[slotnum]->load(cartnum)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + } + if(rml->echoRequested()) { + rml->acknowledge(true); + panel_ripc->sendRml(rml); + } + break; + + case RDMacro::DP: + if(rml->argQuantity()!=1) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + slotnum=rml->arg(0).toUInt(&ok)-1; + if((!ok)||(slotnum>=panel_slots.size())) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + if(panel_slots[slotnum]->slotOptions()->mode()!= + RDSlotOptions::CartDeckMode) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + if(!panel_slots[slotnum]->play()) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + if(rml->echoRequested()) { + rml->acknowledge(true); + panel_ripc->sendRml(rml); + } + break; + + case RDMacro::DS: + if(rml->argQuantity()!=1) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + slotnum=rml->arg(0).toUInt(&ok)-1; + if((!ok)||(slotnum>=panel_slots.size())) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + if(panel_slots[slotnum]->slotOptions()->mode()!= + RDSlotOptions::CartDeckMode) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + if(!panel_slots[slotnum]->stop()) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + if(rml->echoRequested()) { + rml->acknowledge(true); + panel_ripc->sendRml(rml); + } + break; + + case RDMacro::DX: + if(rml->argQuantity()!=2) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + slotnum=rml->arg(0).toUInt(&ok)-1; + if((!ok)||(slotnum>=panel_slots.size())) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + len=rml->arg(1).toUInt(&ok); + if(!ok) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + if(!panel_slots[slotnum]->breakAway(len)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + panel_ripc->sendRml(rml); + } + return; + } + if(rml->echoRequested()) { + rml->acknowledge(true); + panel_ripc->sendRml(rml); + } + break; + + default: + break; + } +} diff --git a/rdcartslots/rdcartslots.cpp b/rdcartslots/rdcartslots.cpp new file mode 100644 index 00000000..818fcc49 --- /dev/null +++ b/rdcartslots/rdcartslots.cpp @@ -0,0 +1,291 @@ +// rdcartslots.cpp +// +// A Dedicated Cart Slot Utility for Rivendell. +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: rdcartslots.cpp,v 1.8.2.13 2014/02/11 23:46:29 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// +// Icons +// +#include "../icons/rivendell-22x22.xpm" + +MainWidget::MainWidget(QWidget *parent) + :QWidget(parent) +{ + bool skip_db_check=false; + unsigned schema=0; + + // + // Force a reasonable default font. + // + QFont mfont("helvetica",12,QFont::Normal); + mfont.setPixelSize(12); + qApp->setFont(mfont); + + // + // Load Local Configs + // + panel_config=new RDConfig(); + panel_config->load(); + + // + // Load the command-line arguments + // + RDCmdSwitch *cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdcartslots", + RDCARTSLOTS_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + } + + // + // Create Icons + // + lib_rivendell_map=new QPixmap(rivendell_xpm); + setIcon(*lib_rivendell_map); + + // + // Ensure that system daemons are running + // + RDInitializeDaemons(); + + // + // Open Database + // + QString err; + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + QMessageBox::warning(this,tr("Can't Connect"),err); + exit(0); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr, + "rdcastmanager: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + new RDDbHeartbeat(panel_config->mysqlHeartbeatInterval(),this); + + // + // Allocate Global Resources + // + panel_station=new RDStation(panel_config->stationName()); + panel_system=new RDSystem(); + + // + // RDAirPlay Configuration + // + panel_airplay_conf=new RDAirPlayConf(panel_config->stationName(),"RDAIRPLAY"); + + // + // CAE Connection + // + panel_cae=new RDCae(panel_station,panel_config,parent); + panel_cae->connectHost(); + + // + // RIPC Connection + // + panel_ripc=new RDRipc(panel_config->stationName()); + connect(panel_ripc,SIGNAL(userChanged()),this,SLOT(userData())); + connect(panel_ripc,SIGNAL(rmlReceived(RDMacro *)), + this,SLOT(rmlReceivedData(RDMacro *))); + + // + // User + // + panel_user=NULL; + + // + // Service Picker + // + panel_svcs_dialog=new RDListSvcs(tr("RDCartSlots"),this); + + // + // Macro Player + // + panel_player=new RDEventPlayer(panel_ripc,this); + + // + // Dialogs + // + panel_cart_dialog=new RDCartDialog(&panel_filter,&panel_group, + &panel_schedcode,panel_cae,panel_ripc, + panel_station,panel_system,panel_config, + this); + panel_slot_dialog=new RDSlotDialog(tr("RDCartSlots"),this); + panel_cue_dialog=new RDCueEditDialog(panel_cae,panel_station->cueCard(), + panel_station->cuePort(), + tr("RDCartSlots"),this); + + // + // Cart Slots + // + QTimer *timer=new QTimer(this); + for(int i=0;icartSlotColumns();i++) { + for(int j=0;jcartSlotRows();j++) { + panel_slots. + push_back(new RDCartSlot(panel_slots.size(),panel_ripc,panel_cae, + panel_station,panel_config,panel_svcs_dialog, + panel_slot_dialog,panel_cart_dialog, + panel_cue_dialog,tr("RDCartSlots"), + panel_airplay_conf,this)); + panel_slots.back()-> + setGeometry(10+i*(panel_slots.back()->sizeHint().width()+10), + 10+j*(panel_slots.back()->sizeHint().height()+5), + panel_slots.back()->sizeHint().width(), + panel_slots.back()->sizeHint().height()); + connect(timer,SIGNAL(timeout()), + panel_slots.back(),SLOT(updateMeters())); + } + } + timer->start(METER_INTERVAL); + panel_ripc->connectHost("localhost",RIPCD_TCP_PORT,panel_config->password()); + + // + // Fix the Window Size + // +#ifndef RESIZABLE + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); +#endif // RESIZABLE +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(10+panel_station->cartSlotColumns()* + (10+panel_slots[0]->size().width()), + 10+panel_station->cartSlotRows()* + (5+panel_slots[0]->size().height())); +} + + +void MainWidget::rmlReceivedData(RDMacro *rml) +{ + RunLocalMacros(rml); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::userData() +{ + if(panel_user!=NULL) { + delete panel_user; + } + panel_user=new RDUser(panel_ripc->user()); + for(unsigned i=0;isetUser(panel_user); + } + SetCaption(); + panel_ripc->sendOnairFlag(); +} + + +void MainWidget::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(Qt::black); + p->setBrush(Qt::black); + for(int i=1;icartSlotColumns();i++) { + p->fillRect(i*(panel_slots[0]->size().width()+10),10, + 5,size().height()-15,Qt::black); + } + delete p; +} + + +void MainWidget::closeEvent(QCloseEvent *e) +{ + for(unsigned i=0;istationName()+" "+tr("User")+": "+ + panel_ripc->user()); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(),"."); + a.installTranslator(&qt); + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rdcartslots_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + MainWidget *w=new MainWidget(); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} diff --git a/rdcartslots/rdcartslots.h b/rdcartslots/rdcartslots.h new file mode 100644 index 00000000..6f483dac --- /dev/null +++ b/rdcartslots/rdcartslots.h @@ -0,0 +1,92 @@ +// rdcartslots.h +// +// A Dedicated Cart Slot Utility for Rivendell. +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: rdcartslots.h,v 1.5.2.6 2014/01/07 23:23:18 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDCARTSLOTS_H +#define RDCARTSLOTS_H + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Settings +// +#define MASTER_TIMER_INTERVAL 100 +#define METER_INTERVAL 50 +#define RDCARTSLOTS_USAGE "\n" + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void userData(); + void rmlReceivedData(RDMacro *rml); + + protected: + void paintEvent(QPaintEvent *e); + void closeEvent(QCloseEvent *e); + + private: + void RunLocalMacros(RDMacro *rml); + void SetCaption(); + RDConfig *panel_config; + RDCae *panel_cae; + RDRipc *panel_ripc; + RDUser *panel_user; + RDStation *panel_station; + RDSystem *panel_system; + RDEventPlayer *panel_player; + QPixmap *lib_rivendell_map; + QString panel_filter; + QString panel_group; + QString panel_schedcode; + std::vector panel_slots; + RDCartDialog *panel_cart_dialog; + RDSlotDialog *panel_slot_dialog; + RDCueEditDialog *panel_cue_dialog; + RDListSvcs *panel_svcs_dialog; + RDAirPlayConf *panel_airplay_conf; +}; + + +#endif // RDCARTSLOTS_H diff --git a/rdcartslots/rdcartslots.pro b/rdcartslots/rdcartslots.pro new file mode 100644 index 00000000..68e283bf --- /dev/null +++ b/rdcartslots/rdcartslots.pro @@ -0,0 +1,37 @@ +# rdcartslots.pro +# +# The QMake project file for RDCartSlots. +# +# (C) Copyright 2012 Fred Gleason +# +# $Id: rdcartslots.pro,v 1.1.2.2 2012/11/16 18:10:41 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +x11 { + SOURCES += rdcartslots.cpp +} + +x11 { + HEADERS += rdcartslots.h +} + +TRANSLATIONS += rdcartslots_de.ts +TRANSLATIONS += rdcartslots_es.ts +TRANSLATIONS += rdcartslots_fr.ts +TRANSLATIONS += rdcartslots_nb.ts +TRANSLATIONS += rdcartslots_nn.ts +TRANSLATIONS += rdcartslots_pt_BR.ts diff --git a/rdcartslots/rdcartslots_de.ts b/rdcartslots/rdcartslots_de.ts new file mode 100644 index 00000000..112432c5 --- /dev/null +++ b/rdcartslots/rdcartslots_de.ts @@ -0,0 +1,25 @@ + + + MainWidget + + RDCartSlots + + + + [None] + + + + Station + + + + User + + + + Can't Connect + + + + diff --git a/rdcartslots/rdcartslots_es.ts b/rdcartslots/rdcartslots_es.ts new file mode 100644 index 00000000..112432c5 --- /dev/null +++ b/rdcartslots/rdcartslots_es.ts @@ -0,0 +1,25 @@ + + + MainWidget + + RDCartSlots + + + + [None] + + + + Station + + + + User + + + + Can't Connect + + + + diff --git a/rdcartslots/rdcartslots_fr.ts b/rdcartslots/rdcartslots_fr.ts new file mode 100644 index 00000000..112432c5 --- /dev/null +++ b/rdcartslots/rdcartslots_fr.ts @@ -0,0 +1,25 @@ + + + MainWidget + + RDCartSlots + + + + [None] + + + + Station + + + + User + + + + Can't Connect + + + + diff --git a/rdcartslots/rdcartslots_nb.ts b/rdcartslots/rdcartslots_nb.ts new file mode 100644 index 00000000..112432c5 --- /dev/null +++ b/rdcartslots/rdcartslots_nb.ts @@ -0,0 +1,25 @@ + + + MainWidget + + RDCartSlots + + + + [None] + + + + Station + + + + User + + + + Can't Connect + + + + diff --git a/rdcartslots/rdcartslots_nn.ts b/rdcartslots/rdcartslots_nn.ts new file mode 100644 index 00000000..112432c5 --- /dev/null +++ b/rdcartslots/rdcartslots_nn.ts @@ -0,0 +1,25 @@ + + + MainWidget + + RDCartSlots + + + + [None] + + + + Station + + + + User + + + + Can't Connect + + + + diff --git a/rdcartslots/rdcartslots_pt_BR.ts b/rdcartslots/rdcartslots_pt_BR.ts new file mode 100644 index 00000000..112432c5 --- /dev/null +++ b/rdcartslots/rdcartslots_pt_BR.ts @@ -0,0 +1,25 @@ + + + MainWidget + + RDCartSlots + + + + [None] + + + + Station + + + + User + + + + Can't Connect + + + + diff --git a/rdcastmanager/Makefile.am b/rdcastmanager/Makefile.am new file mode 100644 index 00000000..0e6696e4 --- /dev/null +++ b/rdcastmanager/Makefile.am @@ -0,0 +1,83 @@ +## automake.am +## +## Automake.am for rivendell/rdcastmanager +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.8.8.2 2013/01/01 21:36:30 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdcastmanager_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/srlabs/rdcastmanager_*.qm + +all: + @QT_BIN@/lupdate rdcastmanager.pro + @QT_BIN@/lrelease rdcastmanager.pro + +bin_PROGRAMS = rdcastmanager + +dist_rdcastmanager_SOURCES = edit_cast.cpp edit_cast.h\ + globals.h\ + list_casts.cpp list_casts.h\ + pick_report_dates.cpp pick_report_dates.h\ + rdcastmanager.cpp rdcastmanager.h + +nodist_rdcastmanager_SOURCES = moc_edit_cast.cpp\ + moc_list_casts.cpp\ + moc_pick_report_dates.cpp\ + moc_rdcastmanager.cpp + +rdcastmanager_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdcastmanager.pro\ + rdcastmanager_cs.ts\ + rdcastmanager_de.ts\ + rdcastmanager_es.ts\ + rdcastmanager_fr.ts\ + rdcastmanager_nb.ts\ + rdcastmanager_nn.ts\ + rdcastmanager_pt_BR.ts + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/rdcastmanager/edit_cast.cpp b/rdcastmanager/edit_cast.cpp new file mode 100644 index 00000000..f55afad1 --- /dev/null +++ b/rdcastmanager/edit_cast.cpp @@ -0,0 +1,542 @@ +// edit_cast.cpp +// +// Edit a Rivendell Cast +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_cast.cpp,v 1.11 2011/09/09 20:23:28 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +EditCast::EditCast(unsigned cast_id,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + int ypos=0; + + cast_cast=new RDPodcast(cast_id); + cast_feed=new RDFeed(cast_cast->feedId()); + cast_status=cast_cast->status(); + setCaption(tr("Editing PodCast")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont select_font=QFont("Helvetica",12,QFont::Normal); + select_font.setPixelSize(12); + + // + // Item Media Link + // + cast_item_medialink_edit=new QLineEdit(this,"cast_item_medialink_edit"); + cast_item_medialink_edit->setGeometry(115,10,sizeHint().width()-125,20); + cast_item_medialink_edit->setReadOnly(true); + QLabel *cast_item_medialink_label= + new QLabel(cast_item_medialink_edit,tr("Media Link:"),this, + "cast_item_medialink_label"); + cast_item_medialink_label->setGeometry(20,10,90,20); + cast_item_medialink_label->setFont(font); + cast_item_medialink_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + if(cast_feed->mediaLinkMode()==RDFeed::LinkNone) { + cast_item_medialink_edit->hide(); + cast_item_medialink_label->hide(); + ypos=10; + } + else { + ypos=42; + } + + // + // Item Title + // + cast_item_title_edit=new QLineEdit(this,"cast_item_title_edit"); + cast_item_title_edit->setGeometry(115,ypos,sizeHint().width()-125,20); + cast_item_title_edit->setMaxLength(255); + QLabel *cast_item_title_label= + new QLabel(cast_item_title_edit,tr("Title:"),this, + "cast_item_title_label"); + cast_item_title_label->setGeometry(20,ypos,90,20); + cast_item_title_label->setFont(font); + cast_item_title_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Item Author + // + cast_item_author_edit=new QLineEdit(this,"cast_item_author_edit"); + cast_item_author_edit->setGeometry(115,ypos+22,sizeHint().width()-125,20); + cast_item_author_edit->setMaxLength(255); + QLabel *cast_item_author_label= + new QLabel(cast_item_author_edit,tr("Author E-Mail:"),this, + "cast_item_author_label"); + cast_item_author_label->setGeometry(20,ypos+22,90,20); + cast_item_author_label->setFont(font); + cast_item_author_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Item Category + // + cast_item_category_edit=new QLineEdit(this,"cast_item_category_edit"); + cast_item_category_edit->setGeometry(115,ypos+44,sizeHint().width()-125,20); + cast_item_category_edit->setMaxLength(64); + QLabel *cast_item_category_label= + new QLabel(cast_item_category_edit,tr("Category:"),this, + "cast_item_category_label"); + cast_item_category_label->setGeometry(20,ypos+44,90,20); + cast_item_category_label->setFont(font); + cast_item_category_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Item Link + // + cast_item_link_edit=new QLineEdit(this,"cast_item_link_edit"); + cast_item_link_edit->setGeometry(115,ypos+66,sizeHint().width()-125,20); + cast_item_link_edit->setMaxLength(255); + QLabel *cast_item_link_label= + new QLabel(cast_item_link_edit,tr("Link URL:"),this, + "cast_item_link_label"); + cast_item_link_label->setGeometry(20,ypos+66,90,20); + cast_item_link_label->setFont(font); + cast_item_link_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Item Description + // + cast_item_description_edit= + new QTextEdit(this,"cast_item_description_edit"); + cast_item_description_edit-> + setGeometry(115,ypos+88,sizeHint().width()-125,76); + QLabel *cast_item_description_label= + new QLabel(cast_item_description_edit,tr("Description:"),this, + "cast_item_description_label"); + cast_item_description_label->setGeometry(20,ypos+88,90,20); + cast_item_description_label->setFont(font); + cast_item_description_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Item Source Text + // + cast_item_sourcetext_edit=new QLineEdit(this,"cast_item_sourcetext_edit"); + cast_item_sourcetext_edit->setGeometry(115,ypos+169,sizeHint().width()-125,20); + cast_item_sourcetext_edit->setMaxLength(64); + QLabel *cast_item_sourcetext_label= + new QLabel(cast_item_sourcetext_edit,tr("Source Text:"),this, + "cast_item_sourcetext_label"); + cast_item_sourcetext_label->setGeometry(20,ypos+169,90,20); + cast_item_sourcetext_label->setFont(font); + cast_item_sourcetext_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Item Source URL + // + cast_item_sourceurl_edit=new QLineEdit(this,"cast_item_sourceurl_edit"); + cast_item_sourceurl_edit->setGeometry(115,ypos+191,sizeHint().width()-125,20); + cast_item_sourceurl_edit->setMaxLength(64); + QLabel *cast_item_sourceurl_label= + new QLabel(cast_item_sourceurl_edit,tr("Source URL:"),this, + "cast_item_sourceurl_label"); + cast_item_sourceurl_label->setGeometry(20,ypos+191,90,20); + cast_item_sourceurl_label->setFont(font); + cast_item_sourceurl_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Item Comments + // + cast_item_comments_edit=new QLineEdit(this,"cast_item_comments_edit"); + cast_item_comments_edit->setGeometry(115,ypos+213,sizeHint().width()-125,20); + cast_item_comments_edit->setMaxLength(64); + QLabel *cast_item_comments_label= + new QLabel(cast_item_comments_edit,tr("Comments URL:"),this, + "cast_item_comments_label"); + cast_item_comments_label->setGeometry(10,ypos+213,100,20); + cast_item_comments_label->setFont(font); + cast_item_comments_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Auxiliary Fields + // + cast_ypos=233+ypos; + QString keyname=cast_cast->keyName(); + keyname.replace(" ","_"); + QLabel *label; + sql=QString().sprintf("select VAR_NAME,CAPTION from AUX_METADATA \ + where FEED_ID=%u order by VAR_NAME", + cast_cast->feedId()); + q=new RDSqlQuery(sql); + while(q->next()) { + cast_aux_varnames.push_back(q->value(0).toString(). + mid(1,q->value(0).toString().length()-2)); + cast_aux_edits.push_back(new QLineEdit(this)); + cast_aux_edits.back()-> + setGeometry(115,cast_ypos,sizeHint().width()-125,20); + cast_aux_edits.back()->setMaxLength(255); + sql=QString().sprintf("select %s from %s_FIELDS where CAST_ID=%u", + (const char *)cast_aux_varnames.back(), + (const char *)keyname,cast_cast->id()); + q1=new RDSqlQuery(sql); + if(q1->first()) { + cast_aux_edits.back()->setText(q1->value(0).toString()); + } + delete q1; + label=new QLabel(cast_aux_edits.back(),q->value(1).toString()+":",this); + label->setGeometry(20,cast_ypos,90,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + cast_ypos+=22; + } + delete q; + cast_ypos+=3; + + // + // Effective DateTime + // + cast_item_effective_edit=new QDateTimeEdit(this); + cast_item_effective_edit-> + setGeometry(115,cast_ypos,165,20); + label=new QLabel(cast_item_effective_edit,tr("Air Date/Time:"),this, + "cast_item_effective_label"); + label->setGeometry(20,cast_ypos,90,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QPushButton *button=new QPushButton(this,"cast_item_effective_button"); + button->setGeometry(290,cast_ypos-3,50,25); + button->setFont(select_font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(effectiveSelectData())); + cast_ypos+=22; + + // + // Item Origin + // + cast_item_origin_edit=new QLineEdit(this,"cast_item_origin_edit"); + cast_item_origin_edit->setReadOnly(true); + cast_item_origin_edit->setGeometry(115,cast_ypos,165,20); + cast_item_origin_edit->setMaxLength(64); + QLabel *cast_item_origin_label= + new QLabel(cast_item_origin_edit,tr("Posted At:"),this, + "cast_item_origin_label"); + cast_item_origin_label->setGeometry(20,cast_ypos,90,20); + cast_item_origin_label->setFont(font); + cast_item_origin_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + cast_ypos+=22; + + // + // Item Expiration + // + cast_item_expiration_box=new QComboBox(this,"cast_item_expiration_box"); + cast_item_expiration_box->setGeometry(115,cast_ypos,50,20); + cast_item_expiration_box->insertItem(tr("No")); + cast_item_expiration_box->insertItem(tr("Yes")); + connect(cast_item_expiration_box,SIGNAL(activated(int)), + this,SLOT(expirationSelectedData(int))); + label=new QLabel(cast_item_expiration_box,tr("Cast Expires:"),this,"label"); + label->setGeometry(20,cast_ypos,90,20); + label->setFont(font); + label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + cast_ypos+=22; + cast_item_expiration_box->setEnabled(cast_status!=RDPodcast::StatusExpired); + label->setEnabled(cast_status!=RDPodcast::StatusExpired); + + cast_item_expiration_edit=new QDateEdit(this); + cast_item_expiration_edit->setGeometry(115,cast_ypos,95,20); + cast_item_expiration_label= + new QLabel(cast_item_expiration_edit,tr("Expires On:"),this, + "cast_item_expiration_label"); + cast_item_expiration_label->setGeometry(20,cast_ypos,90,20); + cast_item_expiration_label->setFont(font); + cast_item_expiration_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + cast_item_expiration_button= + new QPushButton(this,"cast_item_expiration_button"); + cast_item_expiration_button->setGeometry(220,cast_ypos-3,50,25); + cast_item_expiration_button->setFont(select_font); + cast_item_expiration_button->setText(tr("&Select")); + connect(cast_item_expiration_button,SIGNAL(clicked()), + this,SLOT(expirationSelectData())); + cast_ypos+=27; + cast_item_expiration_edit->setEnabled(cast_status!=RDPodcast::StatusExpired); + cast_item_expiration_label-> + setEnabled(cast_status!=RDPodcast::StatusExpired); + cast_item_expiration_button-> + setEnabled(cast_status!=RDPodcast::StatusExpired); + + // + // Cast Status + // + cast_item_status_group=new QButtonGroup(this,"cast_item_status_group"); + cast_item_status_group->setExclusive(true); + cast_item_status_group->hide(); + + QRadioButton *rbutton=new QRadioButton(this,"hold_button"); + rbutton->setGeometry(120,cast_ypos,15,15); + cast_item_status_group->insert(rbutton); + label=new QLabel(rbutton,tr("Hold"),this,"hold_label"); + label->setFont(select_font); + label->setGeometry(140,cast_ypos,30,15); + label->setAlignment(AlignVCenter|AlignLeft); + rbutton->setChecked(true); + label->setEnabled(cast_status!=RDPodcast::StatusExpired); + rbutton->setEnabled(cast_status!=RDPodcast::StatusExpired); + + rbutton=new QRadioButton(this,"active_button"); + rbutton->setGeometry(190,cast_ypos,15,15); + cast_item_status_group->insert(rbutton); + label=new QLabel(rbutton,tr("Active"),this,"hold_label"); + label->setFont(select_font); + label->setGeometry(210,cast_ypos,80,15); + label->setAlignment(AlignVCenter|AlignLeft); + label->setEnabled(cast_status!=RDPodcast::StatusExpired); + label=new QLabel(cast_item_status_group,tr("Posting Status:"),this, + "cast_item_status_label"); + label->setGeometry(20,cast_ypos-1,90,20); + label->setFont(font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + label->setEnabled(cast_status!=RDPodcast::StatusExpired); + rbutton->setEnabled(cast_status!=RDPodcast::StatusExpired); + + // + // Report Button + // + button=new QPushButton(this,"button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(font); + button->setText(tr("Episode\n&Report")); + connect(button,SIGNAL(clicked()),this,SLOT(reportData())); + + // + // Ok Button + // + button=new QPushButton(this,"button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Values + // + cast_item_medialink_edit-> + setText(cast_feed->audioUrl(cast_feed->mediaLinkMode(), + "[web-hostname]",cast_cast->id())); + cast_item_title_edit->setText(cast_cast->itemTitle()); + cast_item_author_edit->setText(cast_cast->itemAuthor()); + cast_item_origin_edit->setText(RDUtcToLocal(cast_cast->originDateTime()). + toString("MM/dd/yyyy - hh:mm:ss")); + cast_item_category_edit->setText(cast_cast->itemCategory()); + cast_item_link_edit->setText(cast_cast->itemLink()); + cast_item_sourcetext_edit->setText(cast_cast->itemSourceText()); + cast_item_sourceurl_edit->setText(cast_cast->itemSourceUrl()); + cast_item_description_edit->setText(cast_cast->itemDescription()); + cast_item_comments_edit->setText(cast_cast->itemComments()); + cast_item_effective_edit-> + setDateTime(RDUtcToLocal(cast_cast->effectiveDateTime())); + if(cast_cast->shelfLife()>0) { + cast_item_expiration_box->setCurrentItem(1); + } + cast_item_expiration_edit-> + setDate(RDUtcToLocal(cast_cast->originDateTime()).date(). + addDays(cast_cast->shelfLife())); + expirationSelectedData(cast_item_expiration_box->currentItem()); + switch(cast_status) { + case RDPodcast::StatusActive: + cast_item_status_group->setButton(1); + break; + + case RDPodcast::StatusPending: + cast_item_status_group->setButton(0); + break; + + case RDPodcast::StatusExpired: + cast_item_status_group->setDisabled(true); + break; + } + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); +} + + +EditCast::~EditCast() +{ + delete cast_feed; + delete cast_cast; +} + + +QSize EditCast::sizeHint() const +{ + return QSize(640,cast_ypos+92); +} + + +QSizePolicy EditCast::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditCast::expirationSelectedData(int state) +{ + state=state&&(cast_status!=RDPodcast::StatusExpired); + cast_item_expiration_edit->setEnabled(state); + cast_item_expiration_button->setEnabled(state); + cast_item_expiration_label->setEnabled(state); +} + + +void EditCast::effectiveSelectData() +{ + QDate current_date=QDate::currentDate(); + QDateTime datetime=cast_item_effective_edit->dateTime(); + QDate date=datetime.date(); + + RDDateDialog *dd= + new RDDateDialog(current_date.year()-5,current_date.year()+5,this); + if(dd->exec(&date)==0) { + datetime.setDate(date); + cast_item_effective_edit->setDateTime(datetime); + } + delete dd; +} + + +void EditCast::expirationSelectData() +{ + QDate current_date=QDate::currentDate(); + QDate date=cast_item_expiration_edit->date(); + + RDDateDialog *dd= + new RDDateDialog(current_date.year(),current_date.year()+10,this); + if(dd->exec(&date)==0) { + cast_item_expiration_edit->setDate(date); + } + delete dd; +} + + +void EditCast::reportData() +{ + PickReportDates *rd=new PickReportDates(cast_cast->feedId(),cast_cast->id()); + rd->exec(); + delete rd; +} + + +void EditCast::okData() +{ + QString sql; + RDSqlQuery *q; + + cast_cast->setItemTitle(cast_item_title_edit->text()); + cast_cast->setItemAuthor(cast_item_author_edit->text()); + cast_cast->setItemCategory(cast_item_category_edit->text()); + cast_cast->setItemLink(cast_item_link_edit->text()); + cast_cast->setItemSourceText(cast_item_sourcetext_edit->text()); + cast_cast->setItemSourceUrl(cast_item_sourceurl_edit->text()); + cast_cast->setItemDescription(cast_item_description_edit->text()); + cast_cast->setItemComments(cast_item_comments_edit->text()); + cast_cast-> + setEffectiveDateTime(RDLocalToUtc(cast_item_effective_edit->dateTime())); + if(cast_item_status_group->isEnabled()) { + if(cast_item_expiration_box->currentItem()) { + int shelf_life=RDUtcToLocal(cast_cast->originDateTime()).date(). + daysTo(cast_item_expiration_edit->date()); + if(shelf_life<1) { + shelf_life=1; + } + cast_cast->setShelfLife(shelf_life); + } + else { + cast_cast->setShelfLife(0); + } + switch(cast_item_status_group->selectedId()) { + case 0: + cast_cast->setStatus(RDPodcast::StatusPending); + break; + + case 1: + cast_cast->setStatus(RDPodcast::StatusActive); + break; + } + } + + QString keyname=cast_cast->keyName(); + keyname.replace(" ","_"); + for(unsigned i=0;i + text()), + cast_cast->id()); + q=new RDSqlQuery(sql); + delete q; + } + + cast_feed-> + setLastBuildDateTime(RDLocalToUtc(QDateTime(QDate::currentDate(), + QTime::currentTime()))); + done(0); +} + + +void EditCast::cancelData() +{ + done(-1); +} diff --git a/rdcastmanager/edit_cast.h b/rdcastmanager/edit_cast.h new file mode 100644 index 00000000..bebdf5f2 --- /dev/null +++ b/rdcastmanager/edit_cast.h @@ -0,0 +1,87 @@ +// edit_cast.h +// +// Edit a Rivendell Cast +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_cast.h,v 1.8 2011/09/09 20:23:28 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_CAST_H +#define EDIT_CAST_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +class EditCast : public QDialog +{ + Q_OBJECT + public: + EditCast(unsigned cast_id,QWidget *parent=0,const char *name=0); + ~EditCast(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void expirationSelectedData(int state); + void effectiveSelectData(); + void expirationSelectData(); + void reportData(); + void okData(); + void cancelData(); + + private: + RDFeed *cast_feed; + RDPodcast *cast_cast; + QLineEdit *cast_item_medialink_edit; + QLineEdit *cast_item_title_edit; + QLineEdit *cast_item_author_edit; + QLineEdit *cast_item_origin_edit; + QTextEdit *cast_item_description_edit; + QLineEdit *cast_item_category_edit; + QLineEdit *cast_item_comments_edit; + QLineEdit *cast_item_sourcetext_edit; + QLineEdit *cast_item_sourceurl_edit; + QLineEdit *cast_item_link_edit; + QComboBox *cast_item_expiration_box; + QLabel *cast_item_expiration_label; + QPushButton *cast_item_expiration_button; + QDateEdit *cast_item_expiration_edit; + QDateTimeEdit *cast_item_effective_edit; + QButtonGroup *cast_item_status_group; + std::vector cast_aux_varnames; + std::vector cast_aux_edits; + int cast_ypos; + RDPodcast::Status cast_status; +}; + + +#endif // EDIT_CAST_H + diff --git a/rdcastmanager/globals.h b/rdcastmanager/globals.h new file mode 100644 index 00000000..423a8cb9 --- /dev/null +++ b/rdcastmanager/globals.h @@ -0,0 +1,46 @@ +// globals.h +// +// Global Variable Declarations for RDCastManager +// +// (C) Copyright 2007 Fred Gleason +// +// $Id: globals.h,v 1.5 2011/08/30 23:35:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef GLOBALS_H +#define GLOBALS_H + +#include +#include +#include +#include +#include +#include + +// +// Global Resources +// +extern QString cast_filter; +extern QString cast_group; +extern QString cast_schedcode; +extern RDUser *cast_user; +extern RDRipc *cast_ripc; +extern RDConfig *config; +extern RDStation *rdstation_conf; +extern RDSystem *cast_system; + + +#endif // GLOBALS_H diff --git a/rdcastmanager/list_casts.cpp b/rdcastmanager/list_casts.cpp new file mode 100644 index 00000000..b5c28d56 --- /dev/null +++ b/rdcastmanager/list_casts.cpp @@ -0,0 +1,542 @@ +// list_casts.cpp +// +// List Rivendell Casts +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: list_casts.cpp,v 1.18.4.1 2013/11/13 23:36:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// +// Icons +// +#include "../icons/redball.xpm" +#include "../icons/greenball.xpm" +#include "../icons/whiteball.xpm" + + +ListCasts::ListCasts(unsigned feed_id,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + list_feed_id=feed_id; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + setCaption(tr("Podcast List")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont list_font=QFont("Helvetica",12,QFont::Normal); + list_font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Normal); + small_font.setPixelSize(10); + + // + // Create Icons + // + list_greenball_map=new QPixmap(greenball_xpm); + list_redball_map=new QPixmap(redball_xpm); + list_whiteball_map=new QPixmap(whiteball_xpm); + + // + // The Feed + // + list_feed=new RDFeed(feed_id,this); + + // + // Progress Dialog + // + list_progress_dialog= + new QProgressDialog(tr("Uploading Audio..."),"Cancel",4,this); + list_progress_dialog->setCaption(tr("Progress")); + list_progress_dialog->setMinimumDuration(0); + list_progress_dialog->setTotalSteps(list_feed->totalPostSteps()); + connect(list_feed,SIGNAL(postProgressChanged(int)), + this,SLOT(postProgressChangedData(int))); + + // + // Filter + // + list_filter_edit=new QLineEdit(this,"list_filter_edit"); + list_filter_label= + new QLabel(list_filter_edit,tr("Filter:"),this,"list_filter_label"); + list_filter_label->setFont(font); + list_filter_label->setAlignment(AlignRight|AlignVCenter); + connect(list_filter_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(filterChangedData(const QString &))); + + // + // Unexpired Check Box + // + list_unexpired_check=new QCheckBox(this,"list_unexpired_check"); + list_unexpired_label= + new QLabel(list_unexpired_check,tr("Only Show Unexpired Casts"),this, + "list_unexpired_label"); + list_unexpired_label->setFont(font); + list_unexpired_label->setAlignment(AlignLeft|AlignVCenter); + connect(list_unexpired_check,SIGNAL(toggled(bool)), + this,SLOT(notexpiredToggledData(bool))); + + // + // Active Check Box + // + list_active_check=new QCheckBox(this,"list_active_check"); + list_active_label= + new QLabel(list_active_check,tr("Only Show Active Casts"),this, + "list_active_label"); + list_active_label->setFont(font); + list_active_label->setAlignment(AlignLeft|AlignVCenter); + connect(list_active_check,SIGNAL(toggled(bool)), + this,SLOT(activeToggledData(bool))); + + // + // Group List + // + list_casts_view=new RDListView(this,"list_casts_view"); + list_casts_view->setAllColumnsShowFocus(true); + list_casts_view->setItemMargin(5); + list_casts_view->addColumn(tr(" ")); + list_casts_view->setColumnAlignment(0,AlignCenter); + list_casts_view->addColumn(tr("Title")); + list_casts_view->setColumnAlignment(1,AlignLeft); + list_casts_view->addColumn(tr("Origin")); + list_casts_view->setColumnAlignment(2,AlignLeft); + list_casts_view->addColumn(tr("Expires")); + list_casts_view->setColumnAlignment(3,AlignCenter); + list_casts_view->addColumn(tr("Length")); + list_casts_view->setColumnAlignment(4,AlignRight); + list_casts_view->addColumn(tr("Description")); + list_casts_view->setColumnAlignment(5,AlignLeft); + list_casts_view->addColumn(tr("Category")); + list_casts_view->setColumnAlignment(6,AlignCenter); + list_casts_view->addColumn(tr("Link")); + list_casts_view->setColumnAlignment(7,AlignCenter); + connect(list_casts_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + // + // Post Cart Button + // + list_cart_button=new QPushButton(this,"list_cart_button"); + list_cart_button->setFont(font); + list_cart_button->setText(tr("Post From\nCar&t/Cut")); + connect(list_cart_button,SIGNAL(clicked()),this,SLOT(addCartData())); + + // + // Post File Button + // + list_file_button=new QPushButton(this,"list_file_button"); + list_file_button->setFont(font); + list_file_button->setText(tr("Post From\n&File")); + connect(list_file_button,SIGNAL(clicked()),this,SLOT(addFileData())); + + // + // Edit Button + // + list_edit_button=new QPushButton(this,"list_edit_button"); + list_edit_button->setFont(font); + list_edit_button->setText(tr("&Edit")); + connect(list_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + list_delete_button=new QPushButton(this,"list_delete_button"); + list_delete_button->setFont(font); + list_delete_button->setText(tr("&Delete")); + connect(list_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Report Button + // + list_report_button=new QPushButton(this,"list_report_button"); + list_report_button->setFont(font); + list_report_button->setText(tr("Subscription\n&Report")); + connect(list_report_button,SIGNAL(clicked()),this,SLOT(reportData())); + + // + // Close Button + // + list_close_button=new QPushButton(this,"list_close_button"); + list_close_button->setDefault(true); + list_close_button->setFont(font); + list_close_button->setText(tr("&Close")); + connect(list_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + RefreshList(); + GetEncoderId(); + connect(cast_ripc,SIGNAL(userChanged()),this,SLOT(userChangedData())); + userChangedData(); +} + + +ListCasts::~ListCasts() +{ + delete list_progress_dialog; + delete list_feed; +} + + +QSize ListCasts::sizeHint() const +{ + return QSize(640,480); +} + + +QSizePolicy ListCasts::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListCasts::addCartData() +{ + QString cutname; + RDCutDialog *cd=new RDCutDialog(&cutname,rdstation_conf,cast_system, + &cast_filter,&cast_group,&cast_schedcode, + cast_ripc->user()); + if(cd->exec()!=0) { + delete cd; + return; + } + delete cd; + RDFeed::Error err; + unsigned cast_id=list_feed->postCut(cast_user,rdstation_conf,cutname,&err, + config->logXloadDebugData(),config); + if(err!=RDFeed::ErrorOk) { + QMessageBox::warning(this,tr("Posting Error"),RDFeed::errorString(err)); + return; + } + EditCast *edit_cast=new EditCast(cast_id,this); + edit_cast->exec(); + RDListViewItem *item=new RDListViewItem(list_casts_view); + item->setId(cast_id); + RefreshItem(item); + list_casts_view->setSelected(item,true); + list_casts_view->ensureItemVisible(item); + delete edit_cast; +} + + +void ListCasts::addFileData() +{ + QString srcfile=QFileDialog::getOpenFileName("",RD_AUDIO_FILE_FILTER,this); + if(srcfile.isNull()) { + return; + } + RDFeed::Error err; + unsigned cast_id=list_feed->postFile(rdstation_conf,srcfile,&err, + config->logXloadDebugData(),config); + if(err!=RDFeed::ErrorOk) { + QMessageBox::warning(this,tr("Posting Error"),RDFeed::errorString(err)); + return; + } + EditCast *edit_cast=new EditCast(cast_id,this); + edit_cast->exec(); + RDListViewItem *item=new RDListViewItem(list_casts_view); + item->setId(cast_id); + RefreshItem(item); + list_casts_view->setSelected(item,true); + list_casts_view->ensureItemVisible(item); + delete edit_cast; +} + + +void ListCasts::editData() +{ + RDListViewItem *item=(RDListViewItem *)list_casts_view->selectedItem(); + if(item==NULL) { + return; + } + EditCast *edit_cast=new EditCast(item->id(),this); + if(edit_cast->exec()==0) { + RefreshItem(item); + } + delete edit_cast; +} + + +void ListCasts::deleteData() +{ + QString sql; + RDSqlQuery *q; + QString err_text; + + RDListViewItem *item=(RDListViewItem *)list_casts_view->selectedItem(); + if(item==NULL) { + return; + } + if(QMessageBox::question(this,tr("Delete Podcast"), + tr("Are you sure you want to delete this podcast?"), + QMessageBox::Yes,QMessageBox::No)== + QMessageBox::No) { + return; + } + + QProgressDialog *pd= + new QProgressDialog(tr("Deleting Podcast..."),"Cancel",2,this); + pd->setCaption(tr("Progress")); + pd->setMinimumDuration(0); + pd->setProgress(0); + qApp->processEvents(); + sleep(1); + qApp->processEvents(); + RDPodcast *cast=new RDPodcast(item->id()); + if(!cast->removeAudio(list_feed,&err_text,config->logXloadDebugData())) { + if(QMessageBox::warning(this,tr("Remote Error"), + tr("Unable to delete remote audio!\n")+ + tr("The server said: \"")+err_text+"\".\n\n"+ + tr("Continue deleting cast?"), + QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) { + delete pd; + delete cast; + return; + } + } + pd->setProgress(1); + qApp->processEvents(); + sql=QString().sprintf("delete from PODCASTS where ID=%u",item->id()); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("update FEEDS set LAST_BUILD_DATETIME=now() \ + where ID=%u",list_feed_id); + q=new RDSqlQuery(sql); + delete q; + + RDDeleteCastCount(list_feed_id,item->id()); + + pd->reset(); + + delete pd; + delete cast; + delete item; +} + + +void ListCasts::reportData() +{ + PickReportDates *rd=new PickReportDates(list_feed_id,0); + rd->exec(); + delete rd; +} + + +void ListCasts::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + editData(); +} + + +void ListCasts::userChangedData() +{ + list_cart_button->setEnabled(cast_user->addPodcast()&&(list_encoder_id>=0)); + list_file_button->setEnabled(cast_user->addPodcast()&&(list_encoder_id>=0)); + list_edit_button->setEnabled(cast_user->editPodcast()); + list_delete_button->setEnabled(cast_user->deletePodcast()); +} + + +void ListCasts::filterChangedData(const QString &str) +{ + RefreshList(); +} + + +void ListCasts::notexpiredToggledData(bool state) +{ + RefreshList(); +} + + +void ListCasts::activeToggledData(bool state) +{ + RefreshList(); +} + + +void ListCasts::postProgressChangedData(int step) +{ + list_progress_dialog->setProgress(step); + if(step==list_progress_dialog->totalSteps()) { + list_progress_dialog->reset(); + } + qApp->processEvents(); +} + + +void ListCasts::closeData() +{ + done(0); +} + + +void ListCasts::resizeEvent(QResizeEvent *e) +{ + list_filter_label->setGeometry(10,10,40,20); + list_filter_edit->setGeometry(55,10,size().width()-65,20); + list_unexpired_check->setGeometry(55,35,15,15); + list_unexpired_label->setGeometry(75,33,200,20); + list_active_check->setGeometry(300,35,15,15); + list_active_label->setGeometry(320,33,200,20); + list_casts_view->setGeometry(10,54,size().width()-20,size().height()-124); + list_cart_button->setGeometry(10,size().height()-60,80,50); + list_file_button->setGeometry(100,size().height()-60,80,50); + list_edit_button->setGeometry(190,size().height()-60,80,50); + list_delete_button->setGeometry(280,size().height()-60,80,50); + list_report_button->setGeometry(415,size().height()-60,80,50); + list_close_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void ListCasts::RefreshList() +{ + QString sql; + RDSqlQuery *q; + RDListViewItem *item; + + list_casts_view->clear(); + sql=QString().sprintf("select ID from PODCASTS %s \ + order by ORIGIN_DATETIME", + (const char *)RDCastSearch(list_feed_id,list_filter_edit->text(), + list_unexpired_check->isChecked(), + list_active_check->isChecked())); + q=new RDSqlQuery(sql); + while (q->next()) { + item=new RDListViewItem(list_casts_view); + item->setId(q->value(0).toInt()); + RefreshItem(item); + } + delete q; +} + + +void ListCasts::RefreshItem(RDListViewItem *item) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select STATUS,ITEM_TITLE,ORIGIN_DATETIME,SHELF_LIFE,\ + AUDIO_TIME,ITEM_DESCRIPTION,ITEM_CATEGORY,ITEM_LINK \ + from PODCASTS where ID=%d",item->id()); + q=new RDSqlQuery(sql); + if(q->first()) { + switch((RDPodcast::Status)q->value(0).toUInt()) { + case RDPodcast::StatusActive: + item->setPixmap(0,*list_greenball_map); + break; + + case RDPodcast::StatusPending: + item->setPixmap(0,*list_redball_map); + break; + + case RDPodcast::StatusExpired: + item->setPixmap(0,*list_whiteball_map); + break; + } + item->setText(1,q->value(1).toString()); + item->setText(2,RDUtcToLocal(q->value(2).toDateTime()). + toString("MM/dd/yyyy hh:mm:ss")); + if(q->value(3).toInt()==0) { + item->setText(3,tr("Never")); + } + else { + item->setText(3,RDUtcToLocal(q->value(2).toDateTime()). + addDays(q->value(3).toInt()).toString("MM/dd/yyyy")); + } + item->setText(4,RDGetTimeLength(q->value(4).toInt(),false,false)); + item->setText(5,q->value(5).toString()); + item->setText(6,q->value(6).toString()); + item->setText(7,q->value(7).toString()); + } + delete q; +} + + +void ListCasts::GetEncoderId() +{ + QString sql; + RDSqlQuery *q; + + list_encoder_id=-1; + RDFeed *feed=new RDFeed(list_feed_id); + int format=feed->uploadFormat(); + delete feed; + if((format>0)&&(format<100)) { // Built-in format + list_encoder_id=format; + return; + } + sql=QString().sprintf("select NAME from ENCODERS where ID=%d",format); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("select ID from ENCODERS \ + where (NAME=\"%s\")&&(STATION_NAME=\"%s\")", + (const char *)RDEscapeString(q->value(0).toString()), + (const char *)RDEscapeString(rdstation_conf->name())); + delete q; + q=new RDSqlQuery(sql); + if(q->first()) { + list_encoder_id=q->value(0).toInt(); + } + } + delete q; +} diff --git a/rdcastmanager/list_casts.h b/rdcastmanager/list_casts.h new file mode 100644 index 00000000..215d90bd --- /dev/null +++ b/rdcastmanager/list_casts.h @@ -0,0 +1,93 @@ +// list_casts.h +// +// List Rivendell Casts +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: list_casts.h,v 1.9 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_CASTS_H +#define LIST_CASTS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +class ListCasts : public QDialog +{ + Q_OBJECT + public: + ListCasts(unsigned feed_id,QWidget *parent=0,const char *name=0); + ~ListCasts(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addCartData(); + void addFileData(); + void editData(); + void deleteData(); + void reportData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void userChangedData(); + void filterChangedData(const QString &str); + void notexpiredToggledData(bool state); + void activeToggledData(bool state); + void postProgressChangedData(int step); + void closeData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshList(); + void RefreshItem(RDListViewItem *item); + void GetEncoderId(); + RDListView *list_casts_view; + QPushButton *list_cart_button; + QPushButton *list_file_button; + QPushButton *list_edit_button; + QPushButton *list_delete_button; + QPushButton *list_report_button; + QPushButton *list_close_button; + QPixmap *list_redball_map; + QPixmap *list_greenball_map; + QPixmap *list_whiteball_map; + unsigned list_feed_id; + int list_encoder_id; + QLabel *list_filter_label; + QLineEdit *list_filter_edit; + QLabel *list_unexpired_label; + QCheckBox *list_unexpired_check; + QLabel *list_active_label; + QCheckBox *list_active_check; + QProgressDialog *list_progress_dialog; + RDFeed *list_feed; +}; + + +#endif // LIST_CASTS_H diff --git a/rdcastmanager/pick_report_dates.cpp b/rdcastmanager/pick_report_dates.cpp new file mode 100644 index 00000000..6b2f7404 --- /dev/null +++ b/rdcastmanager/pick_report_dates.cpp @@ -0,0 +1,320 @@ +// pick_report_date.cpp +// +// Select a Set of Dates for a Rivendell Report +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: pick_report_dates.cpp,v 1.5 2011/09/07 13:44:59 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +PickReportDates::PickReportDates(unsigned feed_id,unsigned cast_id, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + QDate yesterday_date=QDate::currentDate().addDays(-1); + + edit_cast_id=feed_id; + edit_cast_id=cast_id; + setCaption(tr("Select Report Dates")); + + sql=QString().sprintf("select KEY_NAME from FEEDS where ID=%d",feed_id); + q=new RDSqlQuery(sql); + if(q->first()) { + edit_keyname=q->value(0).toString(); + } + delete q; + + // + // Fix the Window Size + // + setMaximumWidth(sizeHint().width()); + setMaximumHeight(sizeHint().height()); + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Start Date + // + edit_startdate_edit=new QDateEdit(this,"edit_startdate_edit"); + edit_startdate_edit->setGeometry(150,10,100,20); + edit_startdate_edit->setDate(yesterday_date.addMonths(-1)); + QLabel *label=new QLabel(edit_startdate_edit,tr("&Start Date:"), + this,"edit_startdate_label"); + label->setGeometry(75,10,70,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QPushButton *button=new QPushButton(this,"startdate_button"); + button->setGeometry(260,7,50,27); + button->setFont(font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectStartDateData())); + + // + // End Date + // + edit_enddate_edit=new QDateEdit(this,"edit_enddate_edit"); + edit_enddate_edit->setGeometry(150,40,100,20); + edit_enddate_edit->setDate(yesterday_date); + label=new QLabel(edit_enddate_edit,tr("&End Date:"), + this,"edit_enddate_label"); + label->setGeometry(75,40,70,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + button=new QPushButton(this,"enddate_button"); + button->setGeometry(260,37,50,27); + button->setFont(font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectEndDateData())); + + // + // Generate Button + // + button=new QPushButton(this,"list_purge_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Generate\nReport")); + connect(button,SIGNAL(clicked()),this,SLOT(generateData())); + + // + // Close Button + // + button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("C&lose")); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +PickReportDates::~PickReportDates() +{ +} + + +QSize PickReportDates::sizeHint() const +{ + return QSize(400,134); +} + + +QSizePolicy PickReportDates::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void PickReportDates::selectStartDateData() +{ + RDDateDialog *dialog=new RDDateDialog(2002,QDate::currentDate().year(),this); + QDate date=edit_startdate_edit->date(); + if(dialog->exec(&date)<0) { + delete dialog; + return; + } + edit_startdate_edit->setDate(date); + edit_enddate_edit->setDate(date); + delete dialog; +} + + +void PickReportDates::selectEndDateData() +{ + RDDateDialog *dialog=new RDDateDialog(2002,QDate::currentDate().year(),this); + QDate date=edit_enddate_edit->date(); + if(dialog->exec(&date)<0) { + delete dialog; + return; + } + edit_enddate_edit->setDate(date); + delete dialog; +} + + +void PickReportDates::generateData() +{ + QString report; + if(edit_cast_id>0) { + GenerateEpisodeReport(edit_keyname,edit_cast_id,&report); + } + else { + GenerateSubscriptionReport(edit_keyname,&report); + } + RDTextFile(report); +} + + +void PickReportDates::closeData() +{ + done(0); +} + + +void PickReportDates::GenerateSubscriptionReport(const QString &keyname, + QString *rpt) +{ + QString sql; + RDSqlQuery *q; + + RDFeed *feed=new RDFeed(keyname,this); + unsigned total=0; + unsigned rss_total=0; + unsigned audio_total=0; + + // + // Header + // + *rpt+=" Rivendell Podcast Subscription Report\n"; + QString title=feed->channelTitle(); + for(unsigned i=0;i<((80-title.length())/2);i++) { + *rpt+=" "; + } + *rpt+=title; + *rpt+="\n\n"; + *rpt+=" ----- Downloads -----\n"; + *rpt+=" Date RSS Audio\n"; + *rpt+=" ---------------------------------------------\n"; + + // + // Data Rows + // + QString keyname_esc=keyname; + keyname_esc.replace(" ","_"); + sql=QString().sprintf("select ACCESS_DATE,ACCESS_COUNT,CAST_ID from %s_FLG \ + where (ACCESS_DATE>=\"%s\")&&(ACCESS_DATE<=\"%s\") \ + order by ACCESS_DATE,CAST_ID desc", + (const char *)keyname_esc, + (const char *)edit_startdate_edit->date(). + toString("yyyy-MM-dd"), + (const char *)edit_enddate_edit->date(). + toString("yyyy-MM-dd")); + q=new RDSqlQuery(sql); + while(q->next()) { + if(q->value(2).toUInt()==0) { + *rpt+=QString().sprintf(" %s %9u %9u\n", + (const char *)q->value(0).toDate(). + toString("MM/dd/yyyy"), + q->value(1).toUInt(),total); + total=0; + rss_total+=q->value(1).toUInt(); + } + else { + total+=q->value(1).toUInt(); + audio_total+=q->value(1).toUInt(); + } + } + delete q; + *rpt+=QString().sprintf(" ------------ ------------\n"); + *rpt+=QString().sprintf(" %9u %9u\n", + rss_total,audio_total); + + delete feed; +} + + +void PickReportDates::GenerateEpisodeReport(const QString &keyname, + unsigned cast_id,QString *rpt) +{ + QString sql; + RDSqlQuery *q; + + RDFeed *feed=new RDFeed(keyname,this); + RDPodcast *cast=new RDPodcast(cast_id); + + // + // Header + // + *rpt+=" Rivendell Podcast Episode Report\n"; + QString channel_title=feed->channelTitle(); + for(unsigned i=0;i<((80-channel_title.length())/2);i++) { + *rpt+=" "; + } + *rpt+=channel_title; + *rpt+="\n"; + QString item_title=cast->itemTitle(); + for(unsigned i=0;i<((80-item_title.length())/2);i++) { + *rpt+=" "; + } + *rpt+=item_title; + *rpt+="\n"; + *rpt+=QString().sprintf(" Posted on %s at %s\n\n", + (const char *)cast->originDateTime(). + toString("MM/dd/yyyy"), + (const char *)cast->originDateTime(). + toString("hh:mm:ss")); + *rpt+=" Date Downloads\n"; + *rpt+=" --------------------------------\n"; + + // + // Data Rows + // + unsigned total=0; + QString keyname_esc=keyname; + keyname_esc.replace(" ","_"); + sql=QString().sprintf("select ACCESS_DATE,ACCESS_COUNT from %s_FLG \ + where (ACCESS_DATE>=\"%s\")&&(ACCESS_DATE<=\"%s\")&& \ + (CAST_ID=%u) order by ACCESS_DATE", + (const char *)keyname_esc, + (const char *)edit_startdate_edit->date(). + toString("yyyy-MM-dd"), + (const char *)edit_enddate_edit->date(). + toString("yyyy-MM-dd"), + cast_id); + q=new RDSqlQuery(sql); + while(q->next()) { + *rpt+=QString().sprintf(" %s %9u\n", + (const char *)q->value(0).toDate(). + toString("MM/dd/yyyy"), + q->value(1).toUInt()); + total+=q->value(1).toUInt(); + } + delete q; + + *rpt+=QString(). + sprintf(" ------------\n"); + *rpt+=QString(). + sprintf(" %9u\n",total); + + delete cast; + delete feed; +} diff --git a/rdcastmanager/pick_report_dates.h b/rdcastmanager/pick_report_dates.h new file mode 100644 index 00000000..6b524b44 --- /dev/null +++ b/rdcastmanager/pick_report_dates.h @@ -0,0 +1,60 @@ +// pick_report_date.h +// +// Select a Set of Dates for a Rivendell Podcast Report +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: pick_report_dates.h,v 1.3 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef PICK_REPORT_DATE_H +#define PICK_REPORT_DATE_H + +#include +#include +#include +#include + + +class PickReportDates : public QDialog +{ + Q_OBJECT + public: + PickReportDates(unsigned feed_id,unsigned cast_id, + QWidget *parent=0,const char *name=0); + ~PickReportDates(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void selectStartDateData(); + void selectEndDateData(); + void generateData(); + void closeData(); + + private: + void GenerateSubscriptionReport(const QString &keyname,QString *rpt); + void GenerateEpisodeReport(const QString &keyname,unsigned cast_id, + QString *rpt); + QDateEdit *edit_startdate_edit; + QDateEdit *edit_enddate_edit; + QString edit_keyname; + unsigned edit_feed_id; + unsigned edit_cast_id; +}; + + +#endif // PICK_REPORT_DATES_H diff --git a/rdcastmanager/rdcastmanager.cpp b/rdcastmanager/rdcastmanager.cpp new file mode 100644 index 00000000..73723e4c --- /dev/null +++ b/rdcastmanager/rdcastmanager.cpp @@ -0,0 +1,403 @@ +// rdcastmanager.cpp +// +// A PodCast Management Utility for Rivendell. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: rdcastmanager.cpp,v 1.15.4.3 2014/01/21 21:59:31 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WIN32 +#include +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// +// Icons +// +#include "../icons/rivendell-22x22.xpm" +#include "../icons/greencheckmark.xpm" +#include "../icons/redx.xpm" + +// +// Global Resources +// +QString cast_filter; +QString cast_group; +QString cast_schedcode; +RDUser *cast_user; +RDRipc *cast_ripc; +RDStation *rdstation_conf; +RDConfig *config; +RDSystem *cast_system=NULL; + +MainWidget::MainWidget(QWidget *parent,const char *name,WFlags f) + :QMainWindow(parent,name,f) +{ + QString str1; + QString str2; + bool skip_db_check=false; + unsigned schema=0; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdcastmanager","\n"); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + } + delete cmd; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Load Local Configs + // + config=new RDConfig(); + config->load(); + str1=QString("RDCastManager")+" v"+VERSION+" - "+tr("Host"); + str2=QString(tr("User: [Unknown]")); + setCaption(QString().sprintf("%s: %s, %s",(const char *)str1, + (const char *)config->stationName(), + (const char *)str2)); + + // + // Open Database + // + QString err; + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + QMessageBox::warning(this,tr("Can't Connect"),err); + exit(0); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr, + "rdcastmanager: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + + // + // RIPC Connection + // +#ifndef WIN32 + cast_ripc=new RDRipc(config->stationName()); + connect(cast_ripc,SIGNAL(userChanged()),this,SLOT(userChangedData())); + cast_ripc->connectHost("localhost",RIPCD_TCP_PORT,config->password()); +#else + cast_ripc=NULL; +#endif // WIN32 + + // + // Station Configuration + // + rdstation_conf=new RDStation(config->stationName(),this); + cast_system=new RDSystem(); + + // + // User + // +#ifndef WIN32 + cast_user=NULL; +#else + cast_user=new RDUser(RD_USER_LOGIN_NAME); +#endif // WIN32 + + // + // Create Fonts + // + QFont default_font("Helvetica",12,QFont::Normal); + default_font.setPixelSize(12); + qApp->setFont(default_font); + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + + // + // Create Icons + // + cast_rivendell_map=new QPixmap(rivendell_xpm); + setIcon(*cast_rivendell_map); + cast_greencheckmark_map=new QPixmap(greencheckmark_xpm); + cast_redx_map=new QPixmap(redx_xpm); + + // + // Feed List + // + cast_feed_list=new RDListView(this,"cast_feed_list"); + cast_feed_list->setFont(default_font); + cast_feed_list->setAllColumnsShowFocus(true); + cast_feed_list->setItemMargin(5); + connect(cast_feed_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(feedDoubleclickedData(QListViewItem *,const QPoint &,int))); + cast_feed_list->addColumn(""); + cast_feed_list->setColumnAlignment(0,Qt::AlignCenter); + cast_feed_list->addColumn(tr("Key Name")); + cast_feed_list->setColumnAlignment(1,Qt::AlignHCenter); + cast_feed_list->addColumn(tr("Feed Name")); + cast_feed_list->setColumnAlignment(2,Qt::AlignLeft); + cast_feed_list->addColumn(tr("Description")); + cast_feed_list->setColumnAlignment(3,Qt::AlignLeft); + cast_feed_list->addColumn(tr("Casts")); + cast_feed_list->setColumnAlignment(3,Qt::AlignCenter); + + // + // Open Button + // + cast_open_button=new QPushButton(this,"cast_open_button"); + cast_open_button->setFont(button_font); + cast_open_button->setText(tr("&View\nFeed")); + connect(cast_open_button,SIGNAL(clicked()),this,SLOT(openData())); + + // + // Close Button + // + cast_close_button=new QPushButton(this,"cast_close_button"); + cast_close_button->setFont(button_font); + cast_close_button->setText(tr("&Close")); + connect(cast_close_button,SIGNAL(clicked()),this,SLOT(quitMainWidget())); +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(640,480); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::userChangedData() +{ + QString str1; + QString str2; + + if(cast_user!=NULL) { + delete cast_user; + } + str1=QString("RDCastManager")+" v"+VERSION+" - "+tr("Host"); + str2=QString(tr("User")); + setCaption(QString().sprintf("%s: %s, %s: %s",(const char *)str1, + (const char *)config->stationName(), + (const char *)str2, + (const char *)cast_ripc->user())); + cast_user=new RDUser(cast_ripc->user()); + RefreshList(); +} + + +void MainWidget::openData() +{ + RDListViewItem *item=(RDListViewItem *)cast_feed_list->selectedItem(); + if(item==NULL) { + return; + } + ListCasts *casts=new ListCasts(item->id(),this); + casts->exec(); + RefreshItem(item); + delete casts; +} + + +void MainWidget::feedDoubleclickedData(QListViewItem *,const QPoint &,int) +{ + openData(); +} + + +void MainWidget::quitMainWidget() +{ + exit(0); +} + + +void MainWidget::resizeEvent(QResizeEvent *e) +{ + cast_feed_list->setGeometry(10,10,size().width()-20,size().height()-70); + cast_open_button->setGeometry(10,size().height()-55,80,50); + cast_close_button->setGeometry(size().width()-90,size().height()-55,80,50); +} + + +void MainWidget::RefreshItem(RDListViewItem *item) +{ + RDSqlQuery *q; + RDSqlQuery *q1; + QString sql; + int active=0; + int total=0; + + sql=QString().sprintf("select CHANNEL_TITLE,CHANNEL_DESCRIPTION,ID \ + from FEEDS where KEY_NAME=\"%s\"", + (const char *)item->text(1)); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("select STATUS from PODCASTS where FEED_ID=%u", + q->value(2).toUInt()); + q1=new RDSqlQuery(sql); + while(q1->next()) { + total++; + switch((RDPodcast::Status)q1->value(0).toUInt()) { + case RDPodcast::StatusActive: + case RDPodcast::StatusExpired: + active++; + break; + + case RDPodcast::StatusPending: + break; + } + } + delete q1; + if(active==total) { + item->setPixmap(0,*cast_greencheckmark_map); + } + else { + item->setPixmap(0,*cast_redx_map); + } + item->setText(2,q->value(0).toString()); + item->setText(3,q->value(1).toString()); + item->setText(4,QString().sprintf("%d / %d",active,total)); + } + delete q; +} + + +void MainWidget::RefreshList() +{ + RDSqlQuery *q; + QString sql; + int id=-1; + RDListViewItem *selected_item=NULL; + RDListViewItem *item=(RDListViewItem *)cast_feed_list->selectedItem(); + if(item!=NULL) { + id=item->id(); + } + cast_feed_list->clear(); + sql=QString().sprintf("select KEY_NAME from FEED_PERMS \ + where USER_NAME=\"%s\"", + (const char *)cast_user->name()); + q=new RDSqlQuery(sql); + if(q->size()<=0) { // No valid feeds! + delete q; + return; + } + sql="select ID,KEY_NAME from FEEDS where "; + while(q->next()) { + sql+=QString().sprintf("(KEY_NAME=\"%s\")||", + (const char *)q->value(0).toString()); + } + delete q; + sql=sql.left(sql.length()-2); + q=new RDSqlQuery(sql); + while(q->next()) { + item=new RDListViewItem(cast_feed_list); + item->setId(q->value(0).toInt()); + item->setText(1,q->value(1).toString()); + RefreshItem(item); + if(item->id()==id) { + selected_item=item; + } + } + delete q; + if(selected_item!=NULL) { + cast_feed_list->setSelected(selected_item,true); + cast_feed_list->ensureItemVisible(item); + } +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QString tr_path; + QString qt_path; +#ifdef WIN32 + QSettings settings; + settings.insertSearchPath(QSettings::Windows,"/SalemRadioLabs"); + tr_path=QString().sprintf("%s\\", + (const char *)settings. + readEntry("/Rivendell/InstallDir")); + qt_path=tr_path; +#else + tr_path=QString(PREFIX)+QString("/share/rivendell/"); + qt_path=QString(QTDIR)+QString("/translation/"); +#endif // WIN32 + QTranslator qt(0); + qt.load(qt_path+QString("qt_")+QTextCodec::locale(),"."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(tr_path+QString("librd_")+QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(tr_path+QString("librdhpi_")+QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(tr_path+QString("rdcastmanager_")+QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main",0); + a.setMainWidget(w); + w->setGeometry(w->geometry().x(),w->geometry().y(),w->sizeHint().width(),w->sizeHint().height()); + w->show(); + return a.exec(); +} diff --git a/rdcastmanager/rdcastmanager.h b/rdcastmanager/rdcastmanager.h new file mode 100644 index 00000000..b8f9d0bd --- /dev/null +++ b/rdcastmanager/rdcastmanager.h @@ -0,0 +1,73 @@ +// rdcastmanager.h +// +// A RSS Feed Management Utility for Rivendell. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdcastmanager.h,v 1.6 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDCASTMANAGER_H +#define RDCASTMANAGER_H + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +class MainWidget : public QMainWindow +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0,WFlags f=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void openData(); + void userChangedData(); + void feedDoubleclickedData(QListViewItem *item,const QPoint &pt,int col); + void quitMainWidget(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshItem(RDListViewItem *item); + void RefreshList(); + RDListView *cast_feed_list; + QPixmap *cast_rivendell_map; + QPixmap *cast_greencheckmark_map; + QPixmap *cast_redx_map; + QPushButton *cast_open_button; + QPushButton *cast_close_button; +}; + + +#endif // RDCASTMANAGER_H diff --git a/rdcastmanager/rdcastmanager.pro b/rdcastmanager/rdcastmanager.pro new file mode 100644 index 00000000..4361a405 --- /dev/null +++ b/rdcastmanager/rdcastmanager.pro @@ -0,0 +1,59 @@ +# rdcastmanager.pro +# +# The rdcastmanager/ QMake project file for Rivendell +# +# (C) Copyright 2003-2004 Fred Gleason +# +# $Id: rdcastmanager.pro,v 1.5.2.1 2013/01/01 21:36:30 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +TARGET = rdlogmanager + +win32 { + DEFINES += WIN32 + DEFINES += VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE=\"rivendell\" + DEFINES += PACKAGE_VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE_NAME=\"rivendell\" + DEFINES += PACKAGE_BUGREPORT=\"fredg@paravelsystems.com\" +} + +SOURCES += rdcastmanager.cpp +SOURCES += edit_cast.cpp +SOURCES += list_casts.cpp +SOURCES += pick_report_dates.cpp + +HEADERS += rdcastmanager.h +HEADERS += edit_cast.h +HEADERS += list_casts.h +HEADERS += pick_report_dates.h + +RES_FILE += ..\icons\rivendell.res + +INCLUDEPATH += ..\lib + +LIBS = -lqui -L..\lib -llib + +CONFIG += qt + +TRANSLATIONS += rdcastmanager_cs.ts +TRANSLATIONS += rdcastmanager_de.ts +TRANSLATIONS += rdcastmanager_es.ts +TRANSLATIONS += rdcastmanager_fr.ts +TRANSLATIONS += rdcastmanager_nb.ts +TRANSLATIONS += rdcastmanager_nn.ts +TRANSLATIONS += rdcastmanager_pt_BR.ts diff --git a/rdcastmanager/rdcastmanager_cs.ts b/rdcastmanager/rdcastmanager_cs.ts new file mode 100644 index 00000000..d5bbc271 --- /dev/null +++ b/rdcastmanager/rdcastmanager_cs.ts @@ -0,0 +1,367 @@ + + + EditCast + + Editing PodCast + Upravit podcast + + + Title: + Název: + + + Author E-Mail: + Adresa el. pošty autora: + + + Category: + Skupina: + + + Link URL: + Adresa (URL) odkazu: + + + Description: + Popis: + + + Source Text: + Zdrojový text: + + + Source URL: + Adresa (URL) zdroje: + + + Comments URL: + Adresa (URL) poznámky: + + + Posted At: + Vyvěšeno: + + + No + Ne + + + Yes + Ano + + + Cast Expires: + Přestane platit: + + + Expires At: + Läuft ab am/um: + + + &Select + &Vybrat + + + Hold + Držet + + + Active + Činný + + + Posting Status: + Stav vyvěšení: + + + Episode +&Report + &Zpráva o +dílu + + + &OK + &OK + + + &Cancel + Z&rušit + + + Air Date/Time: + Datum/Čas poslání: + + + Media Link: + Multimediální odkaz: + + + Expires On: + Přestane platit: + + + + ListCasts + + Podcast List + Seznam podcastů + + + Post From +Car&t/Cut + Vyvěsit z +vozí&ku/záběru + + + Post From +&File + Vyvěsit ze +&souboru + + + &Edit + &Upravit + + + &Delete + S&mazat + + + Subscription +&Report + Zpráva o +&odběru + + + &Close + &Zavřít + + + + Project-Id-Version: amarok +Report-Msgid-Bugs-To: http://bugs.kde.org +POT-Creation-Date: 2010-05-20 04:55+0200 +PO-Revision-Date: 2010-05-22 09:34+0200 +Last-Translator: Pavel Fric +Language-Team: Czech <kde-i18n-doc@kde.org> +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +X-Generator: Lokalize 1.0 +Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; + + + + Title + Název + + + Origin + Původ + + + Expires + Přestane platit + + + Length + Délka + + + Description + Popis + + + Category + Skupina + + + Link + Odkaz + + + Uploading Audio... + Nahrává se zvuk... + + + Progress + Postup + + + Format Error + Formatfehler + + + Unable to convert audio file! + Kann die Audiodatei nicht konvertieren! + + + Upload Error + Fehler beim Hochladen + + + Unable to upload audio file! + Kann die Audiodatei nicht hochladen! + + + Delete Podcast + Smazat podcast + + + Are you sure you want to delete this podcast? + Opravdu chcete smazat tento podcast? + + + Deleting Podcast... + Maže se podcast... + + + Internal Error + Interner Fehler + + + Unable to generate purge command! + Kann den Löschbefehl nicht generieren! + + + Remote Error + Chyba u protistrany + + + Unable to delete remote audio! +Continue deleting cast? + Kann das entfernte Audio nicht Löschen! +Podcast trotzdem löschen? + + + Never + Nikdy + + + File Error + Dateifehler + + + File does not exist! + Datei existiert nicht! + + + Cannot open file! + Kann die Datei nicht öffnen! + + + Unsupported file type! + Nicht unterstützter Dateityp! + + + + + + + Filter: + Filtr: + + + Only Show Unexpired Casts + Ukázat jen podcasty, co platí + + + Only Show Active Casts + Ukázat jen činné podcasty + + + Posting Error + Chyba při vyvěšení + + + Unable to delete remote audio! + + Nelze smazat soubory se zvukem na jiném serveru! + + + The server said: " + Server hlásí: " + + + Continue deleting cast? + Pokračovat v mazání podcastu? + + + + MainWidget + + RDCastManager - Host + RDCastManager - Server + + + User: [Unknown] + Uživatel: [Neznámý] + + + Can't Connect + Nelze spojit + + + Key Name + Název klíče + + + Feed Name + Název přívodu + + + Description + Popis + + + Casts + Podcasty + + + &View +Feed + &Zobrazit +přívod + + + &Close + &Zavřít + + + User + Uživatel + + + Host + + + + + PickReportDates + + Select Report Dates + + + + &Start Date: + + + + &Select + &Vybrat + + + &End Date: + + + + &Generate +Report + + + + C&lose + + + + diff --git a/rdcastmanager/rdcastmanager_de.ts b/rdcastmanager/rdcastmanager_de.ts new file mode 100644 index 00000000..9898556a --- /dev/null +++ b/rdcastmanager/rdcastmanager_de.ts @@ -0,0 +1,356 @@ + + + EditCast + + Editing PodCast + Podcast editieren + + + Title: + Titel: + + + Author E-Mail: + eMail des Autors: + + + Category: + Kategorie: + + + Link URL: + Link URL: + + + Description: + Beschreibung: + + + Source Text: + Quelltext: + + + Source URL: + Quell-URL: + + + Comments URL: + Kommentar-URL: + + + Posted At: + Gepostet am: + + + No + Nein + + + Yes + Ja + + + Cast Expires: + Cast läuft ab: + + + Expires At: + Läuft ab am/um: + + + &Select + &Auswählen + + + Hold + Hold + + + Active + Aktiv + + + Posting Status: + Posting Status: + + + Episode +&Report + Episoden- +&Report + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Air Date/Time: + Sendezeit/-Datum: + + + Media Link: + Medienlink: + + + Expires On: + + + + + ListCasts + + Podcast List + Podcastliste + + + Post From +Car&t/Cut + Poste von +Car&t/Cut + + + Post From +&File + Poste von +&Datei + + + &Edit + &Editieren + + + &Delete + &Löschen + + + Subscription +&Report + Abonnement +&Report + + + &Close + S&chliessen + + + + + + + Title + Titel + + + Origin + Herkunft + + + Expires + Läuf ab + + + Length + Länge + + + Description + Beschreibung + + + Category + Kategorie + + + Link + Link + + + Uploading Audio... + Lade Audio hoch... + + + Progress + Fortschritt + + + Format Error + Formatfehler + + + Unable to convert audio file! + Kann die Audiodatei nicht konvertieren! + + + Upload Error + Fehler beim Hochladen + + + Unable to upload audio file! + Kann die Audiodatei nicht hochladen! + + + Delete Podcast + Podcast löschen + + + Are you sure you want to delete this podcast? + Sind Sie sicher, daß sie diesen Podcast löschen wollen? + + + Deleting Podcast... + Lösche Podcast... + + + Internal Error + Interner Fehler + + + Unable to generate purge command! + Kann den Löschbefehl nicht generieren! + + + Remote Error + Fehler an Gegenstelle + + + Unable to delete remote audio! +Continue deleting cast? + Kann das entfernte Audio nicht Löschen! +Podcast trotzdem löschen? + + + Never + Nie + + + File Error + Dateifehler + + + File does not exist! + Datei existiert nicht! + + + Cannot open file! + Kann die Datei nicht öffnen! + + + Unsupported file type! + Nicht unterstützter Dateityp! + + + + + + + Filter: + Filter: + + + Only Show Unexpired Casts + Zeige nur nichtabgelaufene Casts + + + Only Show Active Casts + Zeige nur aktive Casts + + + Posting Error + Fehler beim posten + + + Unable to delete remote audio! + + Kann die Audiodatei(en) auf dem anderen Server nicht löschen! + + + The server said: " + Der Server meldet: " + + + Continue deleting cast? + Löschen des Podcasts fortsetzen? + + + + MainWidget + + RDCastManager - Host + RDCastManager - Host + + + User: [Unknown] + Benutzer: [Unbekannt] + + + Can't Connect + Kann mich nicht verbinden + + + Key Name + Schlüsselname + + + Feed Name + Feedname + + + Description + Beschreibung + + + Casts + Casts + + + &View +Feed + &Zeige +Feed + + + &Close + S&chliessen + + + User + Benutzer + + + Host + + + + + PickReportDates + + Select Report Dates + + + + &Start Date: + + + + &Select + &Auswählen + + + &End Date: + + + + &Generate +Report + + + + C&lose + + + + diff --git a/rdcastmanager/rdcastmanager_es.ts b/rdcastmanager/rdcastmanager_es.ts new file mode 100644 index 00000000..a7b66ffd --- /dev/null +++ b/rdcastmanager/rdcastmanager_es.ts @@ -0,0 +1,307 @@ + + + EditCast + + Editing PodCast + Editando PodCast + + + Title: + Título: + + + Category: + Categoría: + + + Description: + Descripción: + + + Posted At: + Colocado el: + + + No + No + + + Yes + + + + Cast Expires: + Expira: + + + &Select + &Elegir + + + Hold + Mantener + + + Active + Activo + + + Posting Status: + Estado del Post: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Author E-Mail: + E-Mail del autor: + + + Link URL: + URL del artículo: + + + Comments URL: + URL comentarios: + + + Source Text: + Texto fuente: + + + Source URL: + URL fuente: + + + Episode +&Report + &Reporte de +Episodios + + + Air Date/Time: + Fecha/Ho al aire: + + + Media Link: + Enlace al medio: + + + Expires On: + Expira el: + + + + ListCasts + + &Edit + &Editar + + + &Close + &Cerrar + + + + + + + Title + Título + + + Origin + Origen + + + Expires + Expira + + + Description + Descripción + + + Category + Categoría + + + Link + Enlace + + + Never + Nunca + + + Podcast List + Lista de Podcasts + + + Post From +Car&t/Cut + Publicar de +Car&t./Audio + + + Post From +&File + Publicar de +&Archivo + + + Uploading Audio... + Subiendo Audio... + + + Progress + Progreso + + + &Delete + &Borrar + + + Length + Longitud + + + Subscription +&Report + &Reporte de +Suscripción + + + + + + + Filter: + Filtro: + + + Only Show Unexpired Casts + Sólo Mostrar sin Expirar + + + Only Show Active Casts + Sólo mostrar activos + + + Posting Error + Error de Post + + + Delete Podcast + Borrar Podcast + + + Are you sure you want to delete this podcast? + ¿Está seguro de borrar este Podcast? + + + Deleting Podcast... + Eliminando Podcast... + + + Remote Error + Error remoto + + + Unable to delete remote audio! + + ¡No fue posible eliminar audio remoto! + + + + The server said: " + El servidor dio el error: " + + + Continue deleting cast? + ¿Continuar eliminando podcasts? + + + + MainWidget + + RDCastManager - Host + RDCastManager - Equipo + + + User: [Unknown] + Usuario: [Desconocido] + + + Can't Connect + No puedo conectarme + + + Key Name + Nombre Clave + + + Feed Name + Nombre del Feed + + + Description + Descripción + + + Casts + Podcasts + + + &Close + &Cerrar + + + User + Usuario + + + &View +Feed + &Ver Feed + + + Host + + + + + PickReportDates + + Select Report Dates + Elegir Fechas del Reporte + + + &Start Date: + Fech. &Inicio: + + + &Select + &Elegir + + + &End Date: + Fech. &Fin: + + + &Generate +Report + &Generar +Reporte + + + C&lose + &Cerrar + + + diff --git a/rdcastmanager/rdcastmanager_fr.ts b/rdcastmanager/rdcastmanager_fr.ts new file mode 100644 index 00000000..9785e17b --- /dev/null +++ b/rdcastmanager/rdcastmanager_fr.ts @@ -0,0 +1,297 @@ + + + EditCast + + Editing PodCast + + + + Title: + + + + Author E-Mail: + + + + Category: + + + + Link URL: + + + + Description: + + + + Source Text: + + + + Source URL: + + + + Comments URL: + + + + Posted At: + + + + No + + + + Yes + + + + Cast Expires: + + + + &Select + + + + Hold + + + + Active + + + + Posting Status: + + + + Episode +&Report + + + + &OK + + + + &Cancel + + + + Air Date/Time: + + + + Media Link: + + + + Expires On: + + + + + ListCasts + + Podcast List + + + + Post From +Car&t/Cut + + + + Post From +&File + + + + &Edit + + + + &Delete + + + + Subscription +&Report + + + + &Close + + + + + + + + Title + + + + Origin + + + + Expires + + + + Length + + + + Description + + + + Category + + + + Link + + + + Uploading Audio... + + + + Progress + + + + Never + + + + + + + + Filter: + + + + Only Show Unexpired Casts + + + + Only Show Active Casts + + + + Posting Error + + + + Delete Podcast + + + + Are you sure you want to delete this podcast? + + + + Deleting Podcast... + + + + Remote Error + + + + Unable to delete remote audio! + + + + + The server said: " + + + + Continue deleting cast? + + + + + MainWidget + + User: [Unknown] + + + + Can't Connect + + + + Key Name + + + + Feed Name + + + + Description + + + + Casts + + + + &View +Feed + + + + &Close + + + + User + + + + Host + + + + + PickReportDates + + Select Report Dates + + + + &Start Date: + + + + &Select + + + + &End Date: + + + + &Generate +Report + + + + C&lose + + + + diff --git a/rdcastmanager/rdcastmanager_nb.ts b/rdcastmanager/rdcastmanager_nb.ts new file mode 100644 index 00000000..121a4ad4 --- /dev/null +++ b/rdcastmanager/rdcastmanager_nb.ts @@ -0,0 +1,355 @@ + + + EditCast + + Editing PodCast + Redigerer podkast + + + Title: + Tittel: + + + Author E-Mail: + E-post til forfattaren: + + + Category: + Kategori: + + + Link URL: + Lenkjeadresse: + + + Description: + Skildring: + + + Source Text: + Kjeldetekst: + + + Source URL: + Kjeldeadresse: + + + Comments URL: + Kommentaradresse: + + + Posted At: + Lagt inn: + + + No + Nei + + + Yes + Ja + + + Cast Expires: + Podkasten går ut: + + + Expires At: + Går ut: + + + &Select + &Vel + + + Hold + Hald + + + Active + Aktiv + + + Posting Status: + Postestatus: + + + Episode +&Report + Episode- +&rapport + + + &OK + &OK + + + &Cancel + &Avbryt + + + Media Link: + + + + Air Date/Time: + + + + Expires On: + + + + + ListCasts + + Podcast List + Podkastliste + + + Post From +Car&t/Cut + Post frå +Korg/Ku&tt + + + Post From +&File + Post frå +&fil + + + &Edit + R&ediger + + + &Delete + &Slett + + + Subscription +&Report + Abonnements&rapport + + + &Close + &Lukk + + + + + + + Title + Tittel + + + Origin + Opphav + + + Expires + Går ut + + + Length + Lengd + + + Description + Skildring + + + Category + Kategori + + + Link + Lenkje + + + &Casts: + &Kastar: + + + Uploading Audio... + Lastar opp lyd... + + + Progress + Framgang + + + Format Error + Formatfeil + + + Unable to convert audio file! + Greidde ikkje koda om lydfila! + + + Upload Error + Opplastingsfeil + + + Unable to upload audio file! + Greidde ikkje lasta opp lydfila! + + + Delete Podcast + Slett podkast + + + Are you sure you want to delete this podcast? + Er du sikker på at du vil sletta denne podkasten? + + + Deleting Podcast... + Slettar podkast... + + + Internal Error + Intern feil + + + Unable to generate purge command! + Greidde ikkje laga tømmekommando! + + + Remote Error + Ekstern feil + + + Unable to delete remote audio! +Continue deleting cast? + Greidde ikkje sletta ekstern lyd! +Vil du halda fram med å sletta podkasten? + + + Never + Aldri + + + File Error + Filfeil + + + File does not exist! + Fila finst ikkje! + + + Cannot open file! + Greier ikkje opna fila! + + + Unsupported file type! + Filtypen er ikkje støtta! + + + Filter: + + + + Only Show Unexpired Casts + + + + Only Show Active Casts + + + + Posting Error + + + + Unable to delete remote audio! + + + + + The server said: " + + + + Continue deleting cast? + + + + + MainWidget + + RDCastManager - Host + RDCastManager - Vert + + + User: [Unknown] + Brukar: [Ukjend] + + + Can't Connect + Greier ikkje kopla til + + + Key Name + Lykjelnamn + + + Feed Name + Straumnamn + + + Description + Skildring + + + Casts + Kastar + + + &View +Feed + &Sjå +straum + + + &Close + &Lukk + + + User + Brukar + + + Host + + + + + PickReportDates + + Select Report Dates + + + + &Start Date: + + + + &Select + &Vel + + + &End Date: + + + + &Generate +Report + + + + C&lose + + + + diff --git a/rdcastmanager/rdcastmanager_nn.ts b/rdcastmanager/rdcastmanager_nn.ts new file mode 100644 index 00000000..121a4ad4 --- /dev/null +++ b/rdcastmanager/rdcastmanager_nn.ts @@ -0,0 +1,355 @@ + + + EditCast + + Editing PodCast + Redigerer podkast + + + Title: + Tittel: + + + Author E-Mail: + E-post til forfattaren: + + + Category: + Kategori: + + + Link URL: + Lenkjeadresse: + + + Description: + Skildring: + + + Source Text: + Kjeldetekst: + + + Source URL: + Kjeldeadresse: + + + Comments URL: + Kommentaradresse: + + + Posted At: + Lagt inn: + + + No + Nei + + + Yes + Ja + + + Cast Expires: + Podkasten går ut: + + + Expires At: + Går ut: + + + &Select + &Vel + + + Hold + Hald + + + Active + Aktiv + + + Posting Status: + Postestatus: + + + Episode +&Report + Episode- +&rapport + + + &OK + &OK + + + &Cancel + &Avbryt + + + Media Link: + + + + Air Date/Time: + + + + Expires On: + + + + + ListCasts + + Podcast List + Podkastliste + + + Post From +Car&t/Cut + Post frå +Korg/Ku&tt + + + Post From +&File + Post frå +&fil + + + &Edit + R&ediger + + + &Delete + &Slett + + + Subscription +&Report + Abonnements&rapport + + + &Close + &Lukk + + + + + + + Title + Tittel + + + Origin + Opphav + + + Expires + Går ut + + + Length + Lengd + + + Description + Skildring + + + Category + Kategori + + + Link + Lenkje + + + &Casts: + &Kastar: + + + Uploading Audio... + Lastar opp lyd... + + + Progress + Framgang + + + Format Error + Formatfeil + + + Unable to convert audio file! + Greidde ikkje koda om lydfila! + + + Upload Error + Opplastingsfeil + + + Unable to upload audio file! + Greidde ikkje lasta opp lydfila! + + + Delete Podcast + Slett podkast + + + Are you sure you want to delete this podcast? + Er du sikker på at du vil sletta denne podkasten? + + + Deleting Podcast... + Slettar podkast... + + + Internal Error + Intern feil + + + Unable to generate purge command! + Greidde ikkje laga tømmekommando! + + + Remote Error + Ekstern feil + + + Unable to delete remote audio! +Continue deleting cast? + Greidde ikkje sletta ekstern lyd! +Vil du halda fram med å sletta podkasten? + + + Never + Aldri + + + File Error + Filfeil + + + File does not exist! + Fila finst ikkje! + + + Cannot open file! + Greier ikkje opna fila! + + + Unsupported file type! + Filtypen er ikkje støtta! + + + Filter: + + + + Only Show Unexpired Casts + + + + Only Show Active Casts + + + + Posting Error + + + + Unable to delete remote audio! + + + + + The server said: " + + + + Continue deleting cast? + + + + + MainWidget + + RDCastManager - Host + RDCastManager - Vert + + + User: [Unknown] + Brukar: [Ukjend] + + + Can't Connect + Greier ikkje kopla til + + + Key Name + Lykjelnamn + + + Feed Name + Straumnamn + + + Description + Skildring + + + Casts + Kastar + + + &View +Feed + &Sjå +straum + + + &Close + &Lukk + + + User + Brukar + + + Host + + + + + PickReportDates + + Select Report Dates + + + + &Start Date: + + + + &Select + &Vel + + + &End Date: + + + + &Generate +Report + + + + C&lose + + + + diff --git a/rdcastmanager/rdcastmanager_pt_BR.ts b/rdcastmanager/rdcastmanager_pt_BR.ts new file mode 100644 index 00000000..4fa6350d --- /dev/null +++ b/rdcastmanager/rdcastmanager_pt_BR.ts @@ -0,0 +1,321 @@ + + + EditCast + + Editing PodCast + Editando Podcast + + + Media Link: + Link de Mídia: + + + Title: + Título: + + + Author E-Mail: + E-mail do autor: + + + Category: + Categoria: + + + Link URL: + Link URL: + + + Description: + Descrição: + + + Source Text: + Texto Fonte: + + + Source URL: + Fonte URL: + + + Comments URL: + Comentários da URL: + + + Air Date/Time: + Ar Data/Hora: + + + &Select + &Selecionar + + + Posted At: + Postado em: + + + No + Não + + + Yes + Sim + + + Cast Expires: + Cast Expira: + + + Expires At: + Expira em: + + + Hold + Espere + + + Active + Ativo + + + Posting Status: + Publicação: + + + Episode +&Report + &Relatório do +Episódio + + + &OK + &OK + + + &Cancel + &Cancelar + + + Expires On: + + + + + ListCasts + + Podcast List + Lista de POdcast + + + Uploading Audio... + Áudio Uploading... + + + Progress + Progresso + + + Filter: + Filtro: + + + Only Show Unexpired Casts + Mostrar Casts não expirados + + + Only Show Active Casts + Mostrar Casts Ativos + + + + + + + + Title + Título + + + Origin + Origem + + + Expires + Expira + + + Length + Duração + + + Description + Descrição + + + Category + Categoria + + + Link + Link + + + Post From +Car&t/Cut + Postar +&Cartão + + + Post From +&File + Postar +&Arquivo + + + &Edit + &Editar + + + &Delete + &Deletar + + + Subscription +&Report + &Relatório de +Assinaturas + + + &Close + &Fechar + + + Posting Error + Erro na Postagem + + + Delete Podcast + Deletar PodCast + + + Are you sure you want to delete this podcast? + Tem certeza que você quer deletar este podcast? + + + Deleting Podcast... + Deletando Podcast... + + + Internal Error + Erro Interno + + + Unable to generate purge command! + Não foi Possível gerar comando para eliminar! + + + Remote Error + Erro Remoto + + + Unable to delete remote audio! +Continue deleting cast? + Não foi possível deletar áudio remoto! +Continuar deletando cast? + + + Never + Nunca + + + Unable to delete remote audio! + + + + + The server said: " + + + + Continue deleting cast? + + + + + MainWidget + + RDCastManager - Host + RDPodcast - Cliente + + + User: [Unknown] + Usuário: [Desconhecido] + + + Can't Connect + Não foi possível conectar + + + Key Name + Nome chave + + + Feed Name + Nome do Feed + + + Description + Descrição + + + Casts + Casts + + + &View +Feed + &Ver +Feed + + + &Close + &Fechar + + + User + Usuário + + + Host + + + + + PickReportDates + + Select Report Dates + + + + &Start Date: + + + + &Select + &Selecionar + + + &End Date: + + + + &Generate +Report + + + + C&lose + + + + diff --git a/rdcatch/Makefile.am b/rdcatch/Makefile.am new file mode 100644 index 00000000..b4cc85b2 --- /dev/null +++ b/rdcatch/Makefile.am @@ -0,0 +1,97 @@ +## automake.am +## +## Automake.am for rivendell/rdcatch +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.40.8.2 2013/01/01 21:36:30 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdcatch_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/srlabs/rdcatch_*.qm + +all: + @QT_BIN@/lupdate rdcatch.pro + @QT_BIN@/lrelease rdcatch.pro + +bin_PROGRAMS = rdcatch + +dist_rdcatch_SOURCES = add_recording.cpp add_recording.h\ + catch_monitor.cpp catch_monitor.h\ + catch_listview.cpp catch_listview.h\ + colors.h\ + deckmon.cpp deckmon.h\ + edit_cartevent.cpp edit_cartevent.h\ + edit_download.cpp edit_download.h\ + edit_playout.cpp edit_playout.h\ + edit_recording.cpp edit_recording.h\ + edit_switchevent.cpp edit_switchevent.h\ + edit_upload.cpp edit_upload.h\ + globals.h\ + list_reports.cpp list_reports.h\ + rdcatch.cpp rdcatch.h\ + vbox.cpp vbox.h + +nodist_rdcatch_SOURCES = moc_add_recording.cpp\ + moc_catch_listview.cpp\ + moc_deckmon.cpp\ + moc_edit_cartevent.cpp\ + moc_edit_download.cpp\ + moc_edit_playout.cpp\ + moc_edit_recording.cpp\ + moc_edit_switchevent.cpp\ + moc_edit_upload.cpp\ + moc_list_reports.cpp\ + moc_rdcatch.cpp\ + moc_vbox.cpp + + +rdcatch_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdcatch.pro\ + rdcatch_cs.ts\ + rdcatch_de.ts\ + rdcatch_es.ts\ + rdcatch_fr.ts\ + rdcatch_nb.ts\ + rdcatch_nn.ts\ + rdcatch_pt_BR.ts + +CLEANFILES = *~\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in diff --git a/rdcatch/add_recording.cpp b/rdcatch/add_recording.cpp new file mode 100644 index 00000000..e256c6bc --- /dev/null +++ b/rdcatch/add_recording.cpp @@ -0,0 +1,291 @@ +// add_recording.cpp +// +// Add a Rivendell RDCatch Event +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: add_recording.cpp,v 1.26.8.1 2014/01/07 23:40:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +extern RDStation *rdstation_conf; + + +AddRecording::AddRecording(int id,QString *filter, + QWidget *parent,const char *name) + : QDialog(parent,name,true,Qt::WStyle_Customize|Qt::WStyle_DialogBorder) +{ + setCaption(""); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont day_font=QFont("Helvetica",12,QFont::Normal); + day_font.setPixelSize(12); + + add_id=id; + add_filter=filter; + + // + // Title Label + // + QLabel *label=new QLabel(tr("Schedule a:"),this,"title_label"); + label->setGeometry(0,0,sizeHint().width(),30); + label->setFont(label_font); + label->setAlignment(AlignCenter); + + // + // Recording Button + // + QPushButton *button=new QPushButton(this,"recording_button"); + button->setGeometry(10,30,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("&Recording")); + button->setDisabled(true); + QString sql=QString("select CHANNEL from DECKS \ + where (CARD_NUMBER>=0)&&(CHANNEL>0)&&(CHANNEL<=9)"); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + button->setEnabled(true); + } + delete q; + connect(button,SIGNAL(clicked()),this,SLOT(recordingData())); + + // + // Playout Button + // + button=new QPushButton(this,"playout_button"); + button->setGeometry(10,80,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("&Playout")); + button->setDisabled(true); + sql=QString("select CHANNEL from DECKS where (CARD_NUMBER>=0)&&")+ + "(PORT_NUMBER>=0)&&(CHANNEL>128)&&(CHANNEL<=137)"; + q=new RDSqlQuery(sql); + if(q->first()) { + button->setEnabled(true); + } + delete q; + connect(button,SIGNAL(clicked()),this,SLOT(playoutData())); + + // + // Download Event Button + // + button=new QPushButton(this,"download_button"); + button->setGeometry(10,130,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("&Download")); + connect(button,SIGNAL(clicked()),this,SLOT(downloadData())); + + // + // Upload Event Button + // + button=new QPushButton(this,"upload_button"); + button->setGeometry(10,180,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("&Upload")); + connect(button,SIGNAL(clicked()),this,SLOT(uploadData())); + + // + // Macro Event Cart Button + // + button=new QPushButton(this,"macro_button"); + button->setGeometry(10,230,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("&Macro Cart")); + connect(button,SIGNAL(clicked()),this,SLOT(macroData())); + + // + // Switch Event Cart Button + // + button=new QPushButton(this,"switch_button"); + button->setGeometry(10,280,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("&Switch Event")); + connect(button,SIGNAL(clicked()),this,SLOT(switchData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(10,350,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + button->setDefault(true); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +AddRecording::~AddRecording() +{ +} + + +QSize AddRecording::sizeHint() const +{ + return QSize(200,400); +} + + +QSizePolicy AddRecording::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddRecording::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void AddRecording::recordingData() +{ + EditRecording *recording=new EditRecording(add_id,NULL,add_filter, + this,"recording"); + if(recording->exec()<0) { + delete recording; + done(-1); + return; + } + delete recording; + done((int)RDRecording::Recording); +} + + +void AddRecording::playoutData() +{ + EditPlayout *playout=new EditPlayout(add_id,NULL,add_filter,this,"playout"); + if(playout->exec()<0) { + delete playout; + done(-1); + return; + } + delete playout; + done((int)RDRecording::Playout); +} + + +void AddRecording::downloadData() +{ + EditDownload *recording= + new EditDownload(add_id,NULL,add_filter,this,"recording"); + if(recording->exec()<0) { + delete recording; + done(-1); + return; + } + delete recording; + done((int)RDRecording::Download); +} + + +void AddRecording::uploadData() +{ + EditUpload *recording=new EditUpload(add_id,NULL,add_filter, + this,"recording"); + if(recording->exec()<0) { + delete recording; + done(-1); + return; + } + delete recording; + done((int)RDRecording::Upload); +} + + +void AddRecording::macroData() +{ + EditCartEvent *recording=new EditCartEvent(add_id,NULL,this,"recording"); + if(recording->exec()<0) { + delete recording; + done(-1); + return; + } + delete recording; + done((int)RDRecording::MacroEvent); +} + + +void AddRecording::switchData() +{ + EditSwitchEvent *recording=new EditSwitchEvent(add_id,NULL,this,"recording"); + if(recording->exec()<0) { + delete recording; + done(-1); + return; + } + delete recording; + done((int)RDRecording::SwitchEvent); +} + + +void AddRecording::cancelData() +{ + done(-1); +} + + +void AddRecording::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Escape: + cancelData(); + break; + + default: + QWidget::keyPressEvent(e); + break; + } +} diff --git a/rdcatch/add_recording.h b/rdcatch/add_recording.h new file mode 100644 index 00000000..e5842e0d --- /dev/null +++ b/rdcatch/add_recording.h @@ -0,0 +1,69 @@ +// add_recording.h +// +// Add a Rivendell RDCatch Event +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: add_recording.h,v 1.15 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_RECORDING_H +#define ADD_RECORDING_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class AddRecording : public QDialog +{ + Q_OBJECT + public: + AddRecording(int id,QString *filter,QWidget *parent=0,const char *name=0); + ~AddRecording(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + void closeEvent(QCloseEvent *e); + + private slots: + void recordingData(); + void playoutData(); + void downloadData(); + void uploadData(); + void macroData(); + void switchData(); + void cancelData(); + + protected: + void keyPressEvent(QKeyEvent *e); + + private: + int add_id; + QString *add_filter; +}; + + +#endif + diff --git a/rdcatch/catch_listview.cpp b/rdcatch/catch_listview.cpp new file mode 100644 index 00000000..1325dd85 --- /dev/null +++ b/rdcatch/catch_listview.cpp @@ -0,0 +1,112 @@ +// catch_listview.cpp +// +// Events List Widget for RDCatch +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: catch_listview.cpp,v 1.5.6.1 2013/11/13 23:36:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include + +#include +#include +#include + +#include +#include + + +CatchListView::CatchListView(QWidget *parent,const char *name) + : RDListView(parent,name) +{ + catch_parent=parent; + + // + // Right-Click Menu + // + catch_menu=new QPopupMenu(NULL,"catch_menu"); + connect(catch_menu,SIGNAL(aboutToShow()),this,SLOT(aboutToShowData())); + catch_menu-> + insertItem(tr("Edit Cue Markers"),this,SLOT(editAudioMenuData()),0,0); +} + + +void CatchListView::aboutToShowData() +{ + catch_menu->setItemEnabled(0,!catch_cutname.isEmpty()); +} + + +void CatchListView::editAudioMenuData() +{ + RDCart *rdcart=new RDCart(catch_cutname.left(6).toUInt()); + RDEditAudio *edit= + new RDEditAudio(rdcart,catch_cutname,catch_cae,catch_user,rdstation_conf, + catch_config,catch_audition_card,catch_audition_port, + 1500,-400,this); + if(edit->exec()!=-1) { + rdcart->updateLength(); + } + delete edit; + delete rdcart; +} + + +void CatchListView::contentsMousePressEvent(QMouseEvent *e) +{ + QListView::contentsMousePressEvent(e); + QListView::contentsMousePressEvent(e); + catch_menu_item=selectedItem(); + if(catch_menu_item==NULL) { + catch_cutname=""; + } + else { + switch(catch_menu_item->text(28).toUInt()) { + case RDRecording::Recording: + case RDRecording::Playout: + case RDRecording::Upload: + case RDRecording::Download: + catch_cutname=catch_menu_item->text(25); + break; + + case RDRecording::MacroEvent: + case RDRecording::SwitchEvent: + catch_cutname=""; + break; + } + } + switch(e->button()) { + case QMouseEvent::RightButton: + catch_menu->setGeometry(e->globalX(),e->globalY(), + catch_menu->sizeHint().width(), + catch_menu->sizeHint().height()); + catch_menu->exec(); + break; + + default: + e->ignore(); + break; + } +} + + +void CatchListView::contentsMouseDoubleClickEvent(QMouseEvent *e) +{ + QListView::contentsMouseDoubleClickEvent(e); +} diff --git a/rdcatch/catch_listview.h b/rdcatch/catch_listview.h new file mode 100644 index 00000000..9acab918 --- /dev/null +++ b/rdcatch/catch_listview.h @@ -0,0 +1,56 @@ +// catch_listview.h +// +// Events List Widget for RDCatch +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: catch_listview.h,v 1.4 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef CATCH_LISTVIEW_H +#define CATCH_LISTVIEW_H + +#include + +#include + + +class CatchListView : public RDListView +{ + Q_OBJECT + + public: + CatchListView(QWidget *parent,const char *name=0); + + private slots: + void aboutToShowData(); + void editAudioMenuData(); + + protected: + void contentsMousePressEvent(QMouseEvent *e); + void contentsMouseDoubleClickEvent(QMouseEvent *e); + + private: + QPopupMenu *catch_menu; + QListViewItem *catch_menu_item; + QString catch_cutname; + QWidget *catch_parent; +}; + + +#endif // CATCH_LISTVIEW_H diff --git a/rdcatch/catch_monitor.cpp b/rdcatch/catch_monitor.cpp new file mode 100644 index 00000000..ac592768 --- /dev/null +++ b/rdcatch/catch_monitor.cpp @@ -0,0 +1,75 @@ +// catch_monitor.cpp +// +// A container class for RDCatch deck monitors and assorted metadata. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: catch_monitor.cpp,v 1.5 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + + +CatchMonitor::CatchMonitor() +{ + catch_deck_mon=NULL; + catch_serial_number=-1; + catch_channel_number=-1; +} + + +CatchMonitor::CatchMonitor(DeckMon *mon,int serial,int channel) +{ + catch_deck_mon=mon; + catch_serial_number=serial; + catch_channel_number=channel; +} + + +DeckMon *CatchMonitor::deckMon() const +{ + return catch_deck_mon; +} + + +void CatchMonitor::setDeckMon(DeckMon *mon) +{ + catch_deck_mon=mon; +} + + +int CatchMonitor::serialNumber() const +{ + return catch_serial_number; +} + + +void CatchMonitor::setSerialNumber(int num) +{ + catch_serial_number=num; +} + + +int CatchMonitor::channelNumber() const +{ + return catch_channel_number; +} + + +void CatchMonitor::setChannelNumber(int num) +{ + catch_channel_number=num; +} diff --git a/rdcatch/catch_monitor.h b/rdcatch/catch_monitor.h new file mode 100644 index 00000000..d3fd3069 --- /dev/null +++ b/rdcatch/catch_monitor.h @@ -0,0 +1,49 @@ +// catch_monitor.h +// +// A container class for RDCatch deck monitors and assorted metadata. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: catch_monitor.h,v 1.5 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef CATCH_MONITOR_H +#define CATCH_MONITOR_H + +#include + + +class CatchMonitor +{ + public: + CatchMonitor(); + CatchMonitor(DeckMon *mon,int serial,int channel); + DeckMon *deckMon() const; + void setDeckMon(DeckMon *mon); + int serialNumber() const; + void setSerialNumber(int num); + int channelNumber() const; + void setChannelNumber(int num); + + private: + DeckMon *catch_deck_mon; + int catch_serial_number; + int catch_channel_number; +}; + + +#endif // CATCH_MONITOR_H + diff --git a/rdcatch/colors.h b/rdcatch/colors.h new file mode 100644 index 00000000..6d447b95 --- /dev/null +++ b/rdcatch/colors.h @@ -0,0 +1,52 @@ +// colors.h +// +// The color definitions for RDCatch +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: colors.h,v 1.10 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef COLORS_H +#define COLORS_H + +// +// Text Colors +// +#define EVENT_ACTIVE_TEXT_COLOR black +#define EVENT_INACTIVE_TEXT_COLOR darkGray + +// +// Background Event List Colors +// +#define EVENT_IDLE_COLOR white +#define EVENT_READY_COLOR cyan +#define EVENT_ACTIVE_COLOR green +#define EVENT_NEXT_COLOR yellow +#define EVENT_WAITING_COLOR magenta +#define EVENT_ERROR_COLOR "#F08888" +#define EVENT_ERROR_TEXT_COLOR white + +// +// Button Colors +// +#define BUTTON_ACTIVE_TEXT_COLOR white +#define BUTTON_ACTIVE_BACKGROUND_COLOR blue +#define BUTTON_MONITOR_FLASHING_COLOR red + + +#endif // COLORS_H diff --git a/rdcatch/deckmon.cpp b/rdcatch/deckmon.cpp new file mode 100644 index 00000000..58a080a9 --- /dev/null +++ b/rdcatch/deckmon.cpp @@ -0,0 +1,306 @@ +// deckmon.cpp +// +// Monitor a Rivendell RDCatch Deck +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: deckmon.cpp,v 1.25 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include + + +DeckMon::DeckMon(QString station,unsigned channel, + QWidget *parent,const char *name) + : QFrame(parent,name) +{ + mon_station=station; + mon_channel=channel; + + setFrameStyle(Box|Raised); + setLineWidth(1); + setMidLineWidth(2); + + // + // Generate Fonts + // + QFont small_font=QFont("Helvetica",6,QFont::Bold); + small_font.setPixelSize(6); + QFont label_font("Helvetica",12,QFont::Normal); + label_font.setPixelSize(12); + + // + // Station/Channel + // + mon_station_label=new QLabel(this,"mon_station_label"); + mon_station_label->setFont(label_font); + if((mon_channel>0)&&(mon_channel<(MAX_DECKS+1))) { + mon_station_label-> + setText(QString(). + sprintf("%s : %uR",(const char *)mon_station,mon_channel)); + } + if((mon_channel>128)&&(mon_channel<(MAX_DECKS+129))) { + mon_station_label-> + setText(QString(). + sprintf("%s : %uP",(const char *)mon_station,mon_channel-128)); + } + + // + // Monitor Button + // + mon_monitor_button=new QPushButton(this,"mon_monitor_button"); + mon_monitor_button->setFont(small_font); + mon_monitor_button->setText(tr("MON")); + mon_monitor_palette=new QPalette(QColor(BUTTON_MONITOR_FLASHING_COLOR), + backgroundColor()); + if((mon_channel>128)&&(mon_channel<(MAX_DECKS+129))) { + mon_monitor_button->hide(); + } + connect(mon_monitor_button,SIGNAL(clicked()), + this,SLOT(monitorButtonData())); + + // + // Abort Button + // + mon_abort_button=new QPushButton(this,"mon_abort_button"); + mon_abort_button->setFont(small_font); + mon_abort_button->setText(tr("ABORT")); + mon_abort_button->setDisabled(true); + connect(mon_abort_button,SIGNAL(clicked()),this,SLOT(abortButtonData())); + + // + // Cut + // + mon_cut_label=new QLabel(this,"mon_cut_label"); + mon_cut_label->setFont(label_font); + + // + // Status + // + mon_status_label=new QLabel(tr("OFFLINE"),this,"mon_status_label"); + mon_status_label->setFont(label_font); + + // + // Audio Meter + // + mon_left_meter=new RDPlayMeter(RDSegMeter::Right,this,"mon_left_meter"); + mon_left_meter->setMode(RDSegMeter::Peak); + mon_left_meter->setRange(-4600,-800); + mon_left_meter->setHighThreshold(-1600); + mon_left_meter->setClipThreshold(-1100); + mon_left_meter->setLabel(tr("L")); + mon_right_meter=new RDPlayMeter(RDSegMeter::Right,this,"mon_right_meter"); + mon_right_meter->setMode(RDSegMeter::Peak); + mon_right_meter->setRange(-4600,-800); + mon_right_meter->setHighThreshold(-1600); + mon_right_meter->setClipThreshold(-1100); + mon_right_meter->setLabel(tr("R")); +} + + +DeckMon::~DeckMon() +{ +} + + +QSize DeckMon::sizeHint() const +{ + return QSize(780,30); +} + + +QSizePolicy DeckMon::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void DeckMon::enableMonitorButton(bool state) +{ + mon_monitor_button->setEnabled(state); +} + + +void DeckMon::setGeometry(int x,int y,int w,int h) +{ + QFrame::setGeometry(x,y,w,h); +} + + +void DeckMon::setGeometry(const QRect &r) +{ + setGeometry(r.x(),r.y(),r.width(),r.height()); +} + + +void DeckMon::setMonitor(bool state) +{ + if(state) { + mon_monitor_button->setPalette(*mon_monitor_palette); + } + else { + mon_monitor_button->setPalette(palette()); + } +} + + +void DeckMon::setStatus(RDDeck::Status status,int id,const QString &cutname) +{ + if(id==0) { + mon_status_label->setText(tr("IDLE")); + SetCutInfo(0,""); + mon_left_meter->setPeakBar(-10000); + mon_right_meter->setPeakBar(-10000); + mon_abort_button->setDisabled(true); + return; + } + switch(status) { + case RDDeck::Offline: + mon_status_label->setText(tr("OFFLINE")); + SetCutInfo(0,""); + mon_left_meter->setPeakBar(-10000); + mon_right_meter->setPeakBar(-10000); + mon_abort_button->setDisabled(true); + break; + + case RDDeck::Idle: + mon_status_label->setText(tr("IDLE")); + SetCutInfo(0,""); + mon_left_meter->setPeakBar(-10000); + mon_right_meter->setPeakBar(-10000); + mon_abort_button->setDisabled(true); + break; + + case RDDeck::Ready: + mon_status_label->setText(tr("READY")); + SetCutInfo(id,""); + mon_left_meter->setPeakBar(-10000); + mon_right_meter->setPeakBar(-10000); + mon_abort_button->setEnabled(true); + break; + + case RDDeck::Waiting: + mon_status_label->setText(tr("WAITING")); + SetCutInfo(id,""); + mon_left_meter->setPeakBar(-10000); + mon_right_meter->setPeakBar(-10000); + mon_abort_button->setEnabled(true); + break; + + case RDDeck::Recording: + if((mon_channel>0)&&(mon_channel<(MAX_DECKS+1))) { + mon_status_label->setText(tr("RECORDING")); + } + if((mon_channel>128)&&(mon_channel<(MAX_DECKS+129))) { + mon_status_label->setText(tr("PLAYING")); + } + SetCutInfo(id,cutname); + mon_abort_button->setEnabled(true); + break; + } +} + + +void DeckMon::setLeftMeter(int level) +{ + mon_left_meter->setPeakBar(level); +} + + +void DeckMon::setRightMeter(int level) +{ + mon_right_meter->setPeakBar(level); +} + + +void DeckMon::monitorButtonData() +{ + emit monitorClicked(); +} + + +void DeckMon::abortButtonData() +{ + emit abortClicked(); +} + + +void DeckMon::resizeEvent(QResizeEvent *e) +{ + mon_station_label->setGeometry(10,10,150,12); + mon_monitor_button->setGeometry(155,5,40,20); + mon_abort_button->setGeometry(200,5,40,20); + mon_cut_label->setGeometry(260,10,e->size().width()-580,12); + mon_status_label->setGeometry(e->size().width()-320,10,80,12); + mon_left_meter->setGeometry(e->size().width()-235,6,225,10); + mon_right_meter->setGeometry(e->size().width()-235,16,225,10); + QFrame::resizeEvent(e); +} + + +void DeckMon::SetCutInfo(int id,const QString &cutname) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + if(id<0) { + mon_cut_label->setText(tr("[multiple events]")); + return; + } + if(id==0) { + mon_cut_label->setText(""); + return; + } + sql=QString().sprintf("select DESCRIPTION from RECORDINGS where ID=%d",id); + q=new RDSqlQuery(sql); + if(!q->first()) { + if(cutname.isEmpty()) { + mon_cut_label->setText(tr("[unknown cut]")); + } + else { + sql=QString().sprintf("select CART.TITLE,CUTS.DESCRIPTION from \ + CART left join CUTS \ + on CART.NUMBER=CUTS.CART_NUMBER \ + where CUTS.CUT_NAME=\"%s\"", + (const char *)cutname); + q1=new RDSqlQuery(sql); + if(q1->first()) { + mon_cut_label-> + setText(q1->value(0).toString()+"->"+q1->value(1).toString()); + } + else { + mon_cut_label->setText(tr("[unknown cut]")); + } + delete q1; + } + delete q; + return; + } + if(q->value(0).toString().isEmpty()) { + mon_cut_label->setText(tr("[no description]")); + delete q; + return; + } + mon_cut_label->setText(q->value(0).toString()); + delete q; +} diff --git a/rdcatch/deckmon.h b/rdcatch/deckmon.h new file mode 100644 index 00000000..97dace09 --- /dev/null +++ b/rdcatch/deckmon.h @@ -0,0 +1,84 @@ +// deckmon.h +// +// Monitor a Rivendell Netcatcher Deck +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: deckmon.h,v 1.15 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef DECKMON_H +#define DECKMON_H + +#include +#include +#include +#include + +#include +#include +#include + + +class DeckMon : public QFrame +{ + Q_OBJECT + public: + DeckMon(QString station,unsigned channel, + QWidget *parent=0,const char *name=0); + ~DeckMon(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void enableMonitorButton(bool state); + + public slots: + void setGeometry(int x,int y,int w,int h); + void setGeometry(const QRect &r); + + public slots: + void setMonitor(bool state); + void setStatus(RDDeck::Status status,int id,const QString &cutname); + void setLeftMeter(int level); + void setRightMeter(int level); + + signals: + void monitorClicked(); + void abortClicked(); + + protected: + void resizeEvent(QResizeEvent *e); + + private slots: + void monitorButtonData(); + void abortButtonData(); + + private: + void SetCutInfo(int id,const QString &cutname); + QLabel *mon_station_label; + QLabel *mon_cut_label; + QLabel *mon_status_label; + QPushButton *mon_abort_button; + QPushButton *mon_monitor_button; + QPalette *mon_monitor_palette; + RDPlayMeter *mon_left_meter; + RDPlayMeter *mon_right_meter; + QString mon_station; + unsigned mon_channel; +}; + + +#endif + diff --git a/rdcatch/edit_cartevent.cpp b/rdcatch/edit_cartevent.cpp new file mode 100644 index 00000000..c9598696 --- /dev/null +++ b/rdcatch/edit_cartevent.cpp @@ -0,0 +1,480 @@ +// edit_cartevent.cpp +// +// Edit a Rivendell Netcatch Cart Event +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_cartevent.cpp,v 1.27.8.1 2012/11/26 20:19:41 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +EditCartEvent::EditCartEvent(int id,std::vector *adds, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + QString temp; + int cartnum; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont day_font=QFont("Helvetica",10,QFont::Normal); + day_font.setPixelSize(10); + + edit_deck=NULL; + edit_added_events=adds; + + setCaption(tr("Edit Cart Event")); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // The Recording Record + // + edit_recording=new RDRecording(id); + if((cartnum=edit_recording->macroCart())>=0) { + edit_cart=new RDCart(cartnum); + } + else { + edit_cart=NULL; + } + + // + // Active Button + // + edit_active_button=new QCheckBox(this,"edit_active_button"); + edit_active_button->setGeometry(10,11,20,20); + QLabel *label=new QLabel(edit_active_button, + tr("Event Active"),this,"edit_active_label"); + label->setGeometry(30,11,125,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Station + // + edit_station_box=new QComboBox(this,"edit_station_box"); + edit_station_box->setGeometry(200,10,140,23); + label=new QLabel(edit_station_box,tr("Location:"),this, + "edit_station_label"); + label->setGeometry(125,10,70,23); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Start Time + // + edit_starttime_edit=new QTimeEdit(this,"edit_starttime_edit"); + edit_starttime_edit->setGeometry(sizeHint().width()-90,12,80,20); + label=new QLabel(edit_starttime_edit, + tr("Start Time:"),this,"edit_starttime_label"); + label->setGeometry(sizeHint().width()-175,12,80,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Description + // + edit_description_edit=new QLineEdit(this,"edit_description_edit"); + edit_description_edit->setGeometry(115,43,sizeHint().width()-125,20); + edit_description_edit->setValidator(validator); + label=new QLabel(edit_description_edit, + tr("Description:"),this,"edit_description_label"); + label->setGeometry(10,43,100,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Cart Number + // + edit_destination_edit=new QLineEdit(this,"edit_destination_edit"); + edit_destination_edit->setGeometry(115,70,60,20); + edit_destination_edit->setReadOnly(false); + label=new QLabel(edit_destination_edit, + tr("Cart Number:"),this,"edit_destination_label"); + label->setGeometry(10,73,100,19); + label->setFont(label_font); + label->setAlignment(AlignRight|ShowPrefix); + QPushButton *button=new QPushButton(this,"destination_button"); + button->setGeometry(185,68,60,24); + button->setFont(day_font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectCartData())); + + // + // Button Label + // + label=new QLabel(tr("Active Days"),this,"active_days_label"); + label->setGeometry(47,101,90,19); + label->setFont(label_font); + label->setAlignment(AlignHCenter|ShowPrefix); + + // + // Monday Button + // + edit_mon_button=new QCheckBox(this,"edit_mon_button"); + edit_mon_button->setGeometry(20,120,20,20); + label=new QLabel(edit_mon_button, + tr("Monday"),this,"edit_mon_label"); + label->setGeometry(40,120,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Tuesday Button + // + edit_tue_button=new QCheckBox(this,"edit_tue_button"); + edit_tue_button->setGeometry(115,120,20,20); + label=new QLabel(edit_tue_button, + tr("Tuesday"),this,"edit_tue_label"); + label->setGeometry(135,120,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Wednesday Button + // + edit_wed_button=new QCheckBox(this,"edit_wed_button"); + edit_wed_button->setGeometry(215,120,20,20); + label=new QLabel(edit_wed_button, + tr("Wednesday"),this,"edit_wed_label"); + label->setGeometry(235,120,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Thursday Button + // + edit_thu_button=new QCheckBox(this,"edit_thu_button"); + edit_thu_button->setGeometry(335,120,20,20); + label=new QLabel(edit_thu_button, + tr("Thursday"),this,"edit_thu_label"); + label->setGeometry(355,120,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Friday Button + // + edit_fri_button=new QCheckBox(this,"edit_fri_button"); + edit_fri_button->setGeometry(440,120,20,20); + label=new QLabel(edit_fri_button, + tr("Friday"),this,"edit_fri_label"); + label->setGeometry(460,120,40,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Saturday Button + // + edit_sat_button=new QCheckBox(this,"edit_sat_button"); + edit_sat_button->setGeometry(130,145,20,20); + label=new QLabel(edit_sat_button, + tr("Saturday"),this,"edit_sat_label"); + label->setGeometry(150,145,60,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Sunday Button + // + edit_sun_button=new QCheckBox(this,"edit_sun_button"); + edit_sun_button->setGeometry(300,145,20,20); + label=new QLabel(edit_sun_button, + tr("Sunday"),this,"edit_sun_label"); + label->setGeometry(320,145,60,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // OneShot Button + // + edit_oneshot_box=new QCheckBox(this,"edit_oneshot_box"); + edit_oneshot_box->setGeometry(20,180,15,15); + label=new QLabel(edit_oneshot_box, + tr("Make OneShot"),this,"edit_oneshot_label"); + label->setGeometry(40,178,115,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Save As Button + // + button=new QPushButton(this,"saveas_button"); + button->setGeometry(sizeHint().width()-300,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Save As\nNew")); + connect(button,SIGNAL(clicked()),this,SLOT(saveasData())); + if(adds==NULL) { + button->hide(); + } + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(button_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + q=new RDSqlQuery("select NAME from STATIONS where NAME!=\"DEFAULT\""); + while(q->next()) { + edit_station_box->insertItem(q->value(0).toString()); + if(edit_recording->station()==q->value(0).toString()) { + edit_station_box->setCurrentItem(edit_station_box->count()-1); + } + } + delete q; + edit_active_button->setChecked(edit_recording->isActive()); + edit_starttime_edit->setTime(edit_recording->startTime()); + edit_description_edit->setText(edit_recording->description()); + if(edit_cart!=NULL) { + edit_destination_edit-> + setText(QString().sprintf("%06d",edit_cart->number())); + } + edit_mon_button->setChecked(edit_recording->mon()); + edit_tue_button->setChecked(edit_recording->tue()); + edit_wed_button->setChecked(edit_recording->wed()); + edit_thu_button->setChecked(edit_recording->thu()); + edit_fri_button->setChecked(edit_recording->fri()); + edit_sat_button->setChecked(edit_recording->sat()); + edit_sun_button->setChecked(edit_recording->sun()); + edit_oneshot_box->setChecked(edit_recording->oneShot()); +} + + +EditCartEvent::~EditCartEvent() +{ + delete edit_station_box; + if(edit_deck!=NULL) { + delete edit_deck; + } +} + + +QSize EditCartEvent::sizeHint() const +{ + return QSize(520,255); +} + + +QSizePolicy EditCartEvent::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditCartEvent::selectCartData() +{ + int cartnum=0; + if(edit_cart!=NULL) { + cartnum=edit_cart->number(); + } + switch(catch_cart_dialog->exec(&cartnum,RDCart::Macro,NULL,0, + catch_user->name(),catch_user->password())) { + case 0: + if(edit_cart!=NULL) { + delete edit_cart; + } + edit_cart=new RDCart(cartnum); + edit_destination_edit->setText(QString().sprintf("%d",cartnum)); + edit_description_edit->setText(edit_cart->title()); + break; + } +} + + +void EditCartEvent::saveasData() +{ + if(!CheckEvent(true)) { + QMessageBox::warning(this,tr("Duplicate Event"), + tr("An event with these parameters already exists!")); + return; + } + delete edit_recording; + edit_recording=new RDRecording(-1,true); + edit_added_events->push_back(edit_recording->id()); + Save(); +} + + +void EditCartEvent::okData() +{ + if(edit_cart!=NULL) { + delete edit_cart; + } + edit_cart=new RDCart(edit_destination_edit->text().toUInt()); + if(!edit_cart->exists()) { + QMessageBox:: + information(this,tr("Invalid Cart"),tr("That cart doesn't exist!")); + return; + } + if(!CheckEvent(false)) { + QMessageBox::warning(this,tr("Duplicate Event"), + tr("An event with these parameters already exists!")); + return; + } + Save(); + done(0); +} + + +void EditCartEvent::cancelData() +{ + done(-1); +} + + +void EditCartEvent::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->drawRect(10,109,sizeHint().width()-20,62); + p->end(); +} + + +void EditCartEvent::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Escape: + e->accept(); + cancelData(); + break; + + default: + QDialog::keyPressEvent(e); + break; + } +} + + +void EditCartEvent::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void EditCartEvent::Save() +{ + edit_recording->setIsActive(edit_active_button->isChecked()); + edit_recording->setStation(edit_station_box->currentText()); + edit_recording->setType(RDRecording::MacroEvent); + edit_recording->setStartTime(edit_starttime_edit->time()); + edit_recording->setDescription(edit_description_edit->text()); + edit_recording->setMacroCart(edit_cart->number()); + edit_recording->setMon(edit_mon_button->isChecked()); + edit_recording->setTue(edit_tue_button->isChecked()); + edit_recording->setWed(edit_wed_button->isChecked()); + edit_recording->setThu(edit_thu_button->isChecked()); + edit_recording->setFri(edit_fri_button->isChecked()); + edit_recording->setSat(edit_sat_button->isChecked()); + edit_recording->setSun(edit_sun_button->isChecked()); + edit_recording->setOneShot(edit_oneshot_box->isChecked()); +} + + +bool EditCartEvent::CheckEvent(bool include_myself) +{ + QString sql= + QString().sprintf("select ID from RECORDINGS \ + where (STATION_NAME=\"%s\")&&\ + (TYPE=%d)&&(START_TIME=\"%s\")&&(MACRO_CART=%u)", + (const char *)edit_station_box->currentText(), + RDRecording::MacroEvent, + (const char *)edit_starttime_edit->time(). + toString("hh:mm:ss"),edit_destination_edit->text(). + toUInt()); + if(edit_sun_button->isChecked()) { + sql+="&&(SUN=\"Y\")"; + } + if(edit_mon_button->isChecked()) { + sql+="&&(MON=\"Y\")"; + } + if(edit_tue_button->isChecked()) { + sql+="&&(TUE=\"Y\")"; + } + if(edit_wed_button->isChecked()) { + sql+="&&(WED=\"Y\")"; + } + if(edit_thu_button->isChecked()) { + sql+="&&(THU=\"Y\")"; + } + if(edit_fri_button->isChecked()) { + sql+="&&(FRI=\"Y\")"; + } + if(edit_sat_button->isChecked()) { + sql+="&&(SAT=\"Y\")"; + } + if(!include_myself) { + sql+=QString().sprintf("&&(ID!=%d)",edit_recording->id()); + } + RDSqlQuery *q=new RDSqlQuery(sql); + bool res=!q->first(); + delete q; + + return res; +} diff --git a/rdcatch/edit_cartevent.h b/rdcatch/edit_cartevent.h new file mode 100644 index 00000000..f1660873 --- /dev/null +++ b/rdcatch/edit_cartevent.h @@ -0,0 +1,87 @@ +// edit_cartevent.h +// +// Edit a Rivendell Netcatch Cart Event +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_cartevent.h,v 1.11 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_CARTEVENT_H +#define EDIT_CARTEVENT_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +class EditCartEvent : public QDialog +{ + Q_OBJECT + public: + EditCartEvent(int id,std::vector *adds, + QWidget *parent=0,const char *name=0); + ~EditCartEvent(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void selectCartData(); + void saveasData(); + void okData(); + void cancelData(); + + protected: + void paintEvent(QPaintEvent *e); + void keyPressEvent(QKeyEvent *); + void closeEvent(QCloseEvent *e); + + private: + void Save(); + bool CheckEvent(bool include_myself); + RDDeck *edit_deck; + RDCart *edit_cart; + RDRecording *edit_recording; + QCheckBox *edit_active_button; + QComboBox *edit_station_box; + QTimeEdit *edit_starttime_edit; + QLineEdit *edit_description_edit; + QString edit_cutname; + QLineEdit *edit_destination_edit; + QCheckBox *edit_sun_button; + QCheckBox *edit_mon_button; + QCheckBox *edit_tue_button; + QCheckBox *edit_wed_button; + QCheckBox *edit_thu_button; + QCheckBox *edit_fri_button; + QCheckBox *edit_sat_button; + QCheckBox *edit_oneshot_box; + std::vector *edit_added_events; +}; + + +#endif + diff --git a/rdcatch/edit_download.cpp b/rdcatch/edit_download.cpp new file mode 100644 index 00000000..2d5ea1a5 --- /dev/null +++ b/rdcatch/edit_download.cpp @@ -0,0 +1,695 @@ +// edit_download.cpp +// +// Edit a Rivendell Download Event +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_download.cpp,v 1.20 2011/08/30 23:35:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +EditDownload::EditDownload(int id,std::vector *adds,QString *filter, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + QString temp; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont day_font=QFont("Helvetica",10,QFont::Normal); + day_font.setPixelSize(10); + + edit_deck=NULL; + edit_added_events=adds; + edit_filter=filter; + + setCaption(tr("Edit Download")); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // The Recording Record + // + edit_recording=new RDRecording(id); + + // + // Active Button + // + edit_active_button=new QCheckBox(this,"edit_active_button"); + edit_active_button->setGeometry(10,11,20,20); + QLabel *label=new QLabel(edit_active_button, + tr("Event Active"),this,"edit_active_label"); + label->setGeometry(30,11,125,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Station + // + edit_station_box=new QComboBox(this,"edit_station_box"); + edit_station_box->setGeometry(200,10,140,23); + label=new QLabel(edit_station_box,tr("Location:"),this, + "edit_station_label"); + label->setGeometry(125,10,70,23); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Start Time + // + edit_starttime_edit=new QTimeEdit(this,"edit_starttime_edit"); + edit_starttime_edit->setGeometry(sizeHint().width()-90,12,80,20); + label=new QLabel(edit_starttime_edit, + tr("Start Time:"),this,"edit_starttime_label"); + label->setGeometry(sizeHint().width()-175,12,80,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Description + // + edit_description_edit=new QLineEdit(this,"edit_description_edit"); + edit_description_edit->setGeometry(115,43,sizeHint().width()-125,20); + edit_description_edit->setValidator(validator); + label=new QLabel(edit_description_edit, + tr("Description:"),this,"edit_description_label"); + label->setGeometry(10,43,100,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Url + // + edit_url_edit=new QLineEdit(this,"edit_url_edit"); + edit_url_edit->setGeometry(115,70,sizeHint().width()-125,20); + edit_url_edit->setMaxLength(255); + edit_url_edit->setValidator(validator); + connect(edit_url_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(urlChangedData(const QString &))); + label=new QLabel(edit_url_edit,tr("Url:"),this,"edit_url_label"); + label->setGeometry(10,70,100,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Username + // + edit_username_edit=new QLineEdit(this,"edit_username_edit"); + edit_username_edit->setGeometry(115,97,150,20); + edit_username_edit->setMaxLength(64); + edit_username_edit->setValidator(validator); + edit_username_label=new QLabel(edit_username_edit, + tr("Username:"),this,"edit_username_label"); + edit_username_label->setGeometry(10,97,100,20); + edit_username_label->setFont(label_font); + edit_username_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Password + // + edit_password_edit=new QLineEdit(this,"edit_password_edit"); + edit_password_edit->setGeometry(360,97,sizeHint().width()-370,20); + edit_password_edit->setEchoMode(QLineEdit::Password); + edit_password_edit->setMaxLength(64); + edit_username_edit->setValidator(validator); + edit_password_label=new QLabel(edit_password_edit, + tr("Password:"),this,"edit_password_label"); + edit_password_label->setGeometry(275,97,80,20); + edit_password_label->setFont(label_font); + edit_password_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Destination + // + edit_destination_edit=new QLineEdit(this,"edit_destination_edit"); + edit_destination_edit->setGeometry(115,124,sizeHint().width()-195,20); + edit_destination_edit->setReadOnly(true); + label=new QLabel(edit_destination_edit, + tr("Destination:"),this,"edit_destination_label"); + label->setGeometry(10,127,100,19); + label->setFont(label_font); + label->setAlignment(AlignRight|ShowPrefix); + QPushButton *button=new QPushButton(this,"destination_button"); + button->setGeometry(sizeHint().width()-70,122,60,24); + button->setFont(day_font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectCartData())); + + // + // Channels + // + edit_channels_box=new QComboBox(this,"edit_channels_box"); + edit_channels_box->setGeometry(190,149,40,20); + edit_channels_box->insertItem("1"); + edit_channels_box->insertItem("2"); + label= + new QLabel(edit_channels_box,tr("Channels:"),this,"edit_autotrim_label"); + label->setGeometry(120,149,70,20); + label->setFont(label_font); + label->setAlignment(AlignVCenter|AlignLeft); + + // + // Autotrim Controls + // + edit_autotrim_box=new QCheckBox(this,"edit_autotrim_box"); + edit_autotrim_box->setGeometry(120,175,15,15); + connect(edit_autotrim_box,SIGNAL(toggled(bool)), + this,SLOT(autotrimToggledData(bool))); + label=new QLabel(edit_autotrim_box,tr("Autotrim"),this); + label->setGeometry(140,173,80,20); + label->setFont(label_font); + label->setAlignment(AlignVCenter|AlignLeft); + edit_autotrim_spin=new QSpinBox(this,"edit_autotrim_spin"); + edit_autotrim_spin->setGeometry(265,173,40,20); + edit_autotrim_spin->setRange(-99,-1); + edit_autotrim_label= + new QLabel(edit_autotrim_spin,tr("Level:"),this,"edit_autotrim_label"); + edit_autotrim_label->setGeometry(220,173,40,20); + edit_autotrim_label->setFont(label_font); + edit_autotrim_label->setAlignment(AlignVCenter|AlignRight); + edit_autotrim_unit= + new QLabel(edit_autotrim_spin,tr("dBFS"),this,"edit_autotrim_unit"); + edit_autotrim_unit->setGeometry(310,173,40,20); + edit_autotrim_unit->setFont(label_font); + edit_autotrim_unit->setAlignment(AlignVCenter|AlignLeft); + + // + // Normalize Controls + // + edit_normalize_box=new QCheckBox(this,"edit_normalize_box"); + edit_normalize_box->setGeometry(120,199,15,15); + connect(edit_normalize_box,SIGNAL(toggled(bool)), + this,SLOT(normalizeToggledData(bool))); + label=new QLabel(edit_normalize_box,tr("Normalize"),this); + label->setGeometry(140,197,80,20); + label->setFont(label_font); + label->setAlignment(AlignVCenter|AlignLeft); + edit_normalize_spin=new QSpinBox(this,"edit_normalize_spin"); + edit_normalize_spin->setGeometry(265,197,40,20); + edit_normalize_spin->setRange(-99,-1); + edit_normalize_label= + new QLabel(edit_normalize_spin,tr("Level:"),this,"edit_normalize_label"); + edit_normalize_label->setGeometry(220,197,40,20); + edit_normalize_label->setFont(label_font); + edit_normalize_label->setAlignment(AlignVCenter|AlignRight); + edit_normalize_unit= + new QLabel(edit_normalize_spin,tr("dBFS"),this,"edit_normalize_unit"); + edit_normalize_unit->setGeometry(310,197,40,20); + edit_normalize_unit->setFont(label_font); + edit_normalize_unit->setAlignment(AlignVCenter|AlignLeft); + + // + // Export Metadata Box + // + edit_metadata_box=new QCheckBox(this,"edit_metadata_box"); + edit_metadata_box->setGeometry(120,222,15,15); + label=new QLabel(edit_metadata_box,tr("Update Library Metadata"), + this,"metadata_check_label"); + label->setGeometry(140,222,160,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Button Label + // + label=new QLabel(tr("Active Days"),this,"active_days_label"); + label->setGeometry(47,254,90,19); + label->setFont(label_font); + label->setAlignment(AlignHCenter|ShowPrefix); + + // + // Monday Button + // + edit_mon_button=new QCheckBox(this,"edit_mon_button"); + edit_mon_button->setGeometry(20,273,20,20); + label=new QLabel(edit_mon_button, + tr("Monday"),this,"edit_mon_label"); + label->setGeometry(40,273,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Tuesday Button + // + edit_tue_button=new QCheckBox(this,"edit_tue_button"); + edit_tue_button->setGeometry(115,273,20,20); + label=new QLabel(edit_tue_button, + tr("Tuesday"),this,"edit_tue_label"); + label->setGeometry(135,273,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Wednesday Button + // + edit_wed_button=new QCheckBox(this,"edit_wed_button"); + edit_wed_button->setGeometry(215,273,20,20); + label=new QLabel(edit_wed_button, + tr("Wednesday"),this,"edit_wed_label"); + label->setGeometry(235,273,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Thursday Button + // + edit_thu_button=new QCheckBox(this,"edit_thu_button"); + edit_thu_button->setGeometry(335,273,20,20); + label=new QLabel(edit_thu_button, + tr("Thursday"),this,"edit_thu_label"); + label->setGeometry(355,273,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Friday Button + // + edit_fri_button=new QCheckBox(this,"edit_fri_button"); + edit_fri_button->setGeometry(440,273,20,20); + label=new QLabel(edit_fri_button, + tr("Friday"),this,"edit_fri_label"); + label->setGeometry(460,273,40,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Saturday Button + // + edit_sat_button=new QCheckBox(this,"edit_sat_button"); + edit_sat_button->setGeometry(130,298,20,20); + label=new QLabel(edit_sat_button, + tr("Saturday"),this,"edit_sat_label"); + label->setGeometry(150,298,60,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Sunday Button + // + edit_sun_button=new QCheckBox(this,"edit_sun_button"); + edit_sun_button->setGeometry(300,298,20,20); + label=new QLabel(edit_sun_button, + tr("Sunday"),this,"edit_sun_label"); + label->setGeometry(320,298,60,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // OneShot Button + // + edit_oneshot_box=new QCheckBox(this,"edit_oneshot_box"); + edit_oneshot_box->setGeometry(20,335,15,15); + label=new QLabel(edit_oneshot_box, + tr("Make OneShot"),this,"edit_oneshot_label"); + label->setGeometry(40,333,115,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Event Offset + // + edit_eventoffset_spin=new QSpinBox(this,"edit_eventoffset_spin"); + edit_eventoffset_spin->setGeometry(245,333,45,20); + edit_eventoffset_spin->setRange(-30,30); + label=new QLabel(edit_eventoffset_spin,tr("Event Offset:"), + this,"edit_eventoffset_label"); + label->setGeometry(140,333,100,20); + label->setFont(label_font); + label->setAlignment(AlignVCenter|AlignRight); + label=new QLabel(edit_eventoffset_spin,tr("days"), + this,"edit_eventoffset_unit"); + label->setGeometry(295,333,40,20); + label->setFont(label_font); + label->setAlignment(AlignVCenter|AlignLeft); + + // + // Save As Button + // + button=new QPushButton(this,"saveas_button"); + button->setGeometry(sizeHint().width()-300,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Save As\nNew")); + connect(button,SIGNAL(clicked()),this,SLOT(saveasData())); + if(adds==NULL) { + button->hide(); + } + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(button_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + q=new RDSqlQuery("select NAME from STATIONS where NAME!=\"DEFAULT\""); + while(q->next()) { + edit_station_box->insertItem(q->value(0).toString()); + if(edit_recording->station()==q->value(0).toString()) { + edit_station_box->setCurrentItem(edit_station_box->count()-1); + } + } + delete q; + edit_active_button->setChecked(edit_recording->isActive()); + edit_starttime_edit->setTime(edit_recording->startTime()); + edit_description_edit->setText(edit_recording->description()); + edit_url_edit->setText(edit_recording->url()); + edit_username_edit->setText(edit_recording->urlUsername()); + edit_password_edit->setText(edit_recording->urlPassword()); + edit_destination_edit->setText("Cut "+edit_recording->cutName()); + edit_channels_box->setCurrentItem(edit_recording->channels()-1); + if(edit_recording->trimThreshold()>0) { + edit_autotrim_box->setChecked(true); + edit_autotrim_spin->setValue(-(edit_recording->trimThreshold()/100)); + } + else { + edit_autotrim_box->setChecked(false); + edit_autotrim_spin->setValue(rdlibrary_conf->trimThreshold()/100); + } + autotrimToggledData(edit_autotrim_box->isChecked()); + if(edit_recording->normalizationLevel()<0) { + edit_normalize_box->setChecked(true); + edit_normalize_spin->setValue(edit_recording->normalizationLevel()/100); + } + else { + edit_normalize_box->setChecked(false); + edit_normalize_spin->setValue(rdlibrary_conf->ripperLevel()/100); + } + normalizeToggledData(edit_normalize_box->isChecked()); + edit_metadata_box->setChecked(edit_recording->enableMetadata()); + edit_mon_button->setChecked(edit_recording->mon()); + edit_tue_button->setChecked(edit_recording->tue()); + edit_wed_button->setChecked(edit_recording->wed()); + edit_thu_button->setChecked(edit_recording->thu()); + edit_fri_button->setChecked(edit_recording->fri()); + edit_sat_button->setChecked(edit_recording->sat()); + edit_sun_button->setChecked(edit_recording->sun()); + edit_eventoffset_spin->setValue(edit_recording->eventdateOffset()); + edit_oneshot_box->setChecked(edit_recording->oneShot()); +} + + +EditDownload::~EditDownload() +{ + delete edit_station_box; + if(edit_deck!=NULL) { + delete edit_deck; + } +} + + +QSize EditDownload::sizeHint() const +{ + return QSize(520,432); +} + + +QSizePolicy EditDownload::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditDownload::urlChangedData(const QString &str) +{ + QUrl url(str); + QString protocol=url.protocol(); + if((protocol=="ftp")||(protocol=="http")||(protocol=="file")) { + edit_username_label->setEnabled(true); + edit_username_edit->setEnabled(true); + edit_password_label->setEnabled(true); + edit_password_edit->setEnabled(true); + } + else { + edit_username_label->setDisabled(true); + edit_username_edit->setDisabled(true); + edit_password_label->setDisabled(true); + edit_password_edit->setDisabled(true); + } +} + + +void EditDownload::selectCartData() +{ + QString str; + + RDCutDialog *cut=new RDCutDialog(&edit_cutname,rdstation_conf,catch_system, + edit_filter,NULL,NULL,catch_user->name(), + false,true); + switch(cut->exec()) { + case 0: + edit_description_edit->setText(RDCutPath(edit_cutname)); + str=QString(tr("Cut")); + edit_destination_edit-> + setText(QString().sprintf("%s %s",(const char *)str, + (const char *)edit_cutname)); + break; + } + delete cut; +} + + +void EditDownload::autotrimToggledData(bool state) +{ + edit_autotrim_label->setEnabled(state); + edit_autotrim_spin->setEnabled(state); + edit_autotrim_unit->setEnabled(state); +} + + +void EditDownload::normalizeToggledData(bool state) +{ + edit_normalize_label->setEnabled(state); + edit_normalize_spin->setEnabled(state); + edit_normalize_unit->setEnabled(state); +} + + +void EditDownload::saveasData() +{ + if(!CheckEvent(true)) { + QMessageBox::warning(this,tr("Duplicate Event"), + tr("An event with these parameters already exists!")); + return; + } + delete edit_recording; + edit_recording=new RDRecording(-1,true); + edit_added_events->push_back(edit_recording->id()); + Save(); +} + + +void EditDownload::okData() +{ + if(QUrl::isRelativeUrl(edit_url_edit->text())|| + (edit_url_edit->text().right(1)=="/")) { + QMessageBox::warning(this,tr("Invalid URL"),tr("The URL is invalid!")); + return; + } + RDUrl url(edit_url_edit->text()); + QString protocol=url.protocol(); + if((protocol!="ftp")&&(protocol!="http")&&(protocol!="https")&& + (protocol!="file")) { + QMessageBox::warning(this, + tr("Invalid URL"),tr("Unsupported URL protocol!")); + return; + } + if((protocol=="file")&&(edit_username_edit->text().isEmpty())) { + QMessageBox::warning(this,tr("Missing Username"), + tr("You must specify a username!")); + return; + } + if(!CheckEvent(false)) { + QMessageBox::warning(this,tr("Duplicate Event"), + tr("An event with these parameters already exists!")); + return; + } + Save(); + done(0); +} + + +void EditDownload::cancelData() +{ + done(-1); +} + + +void EditDownload::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->drawRect(10,262,sizeHint().width()-20,62); + p->end(); +} + + +void EditDownload::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Escape: + e->accept(); + cancelData(); + break; + + default: + QDialog::keyPressEvent(e); + break; + } +} + + +void EditDownload::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void EditDownload::Save() +{ + edit_recording->setIsActive(edit_active_button->isChecked()); + edit_recording->setStation(edit_station_box->currentText()); + edit_recording->setType(RDRecording::Download); + edit_recording->setStartTime(edit_starttime_edit->time()); + edit_recording->setDescription(edit_description_edit->text()); + edit_recording->setChannels(edit_channels_box->currentItem()+1); + if(edit_autotrim_box->isChecked()) { + edit_recording->setTrimThreshold(-100*edit_autotrim_spin->value()); + } + else { + edit_recording->setTrimThreshold(0); + } + if(edit_normalize_box->isChecked()) { + edit_recording->setNormalizationLevel(100*edit_normalize_spin->value()); + } + else { + edit_recording->setNormalizationLevel(0); + } + edit_recording->setCutName(edit_destination_edit->text().right(10)); + edit_recording->setUrl(edit_url_edit->text()); + edit_recording->setUrlUsername(edit_username_edit->text()); + edit_recording->setUrlPassword(edit_password_edit->text()); + edit_recording->setEnableMetadata(edit_metadata_box->isChecked()); + edit_recording->setMon(edit_mon_button->isChecked()); + edit_recording->setTue(edit_tue_button->isChecked()); + edit_recording->setWed(edit_wed_button->isChecked()); + edit_recording->setThu(edit_thu_button->isChecked()); + edit_recording->setFri(edit_fri_button->isChecked()); + edit_recording->setSat(edit_sat_button->isChecked()); + edit_recording->setSun(edit_sun_button->isChecked()); + edit_recording->setEventdateOffset(edit_eventoffset_spin->value()); + edit_recording->setOneShot(edit_oneshot_box->isChecked()); +} + + +bool EditDownload::CheckEvent(bool include_myself) +{ + QString sql= + QString().sprintf("select ID from RECORDINGS \ + where (STATION_NAME=\"%s\")&&\ + (TYPE=%d)&&(START_TIME=\"%s\")&&\ + (URL=\"%s\")&&(CUT_NAME=\"%s\")", + (const char *)edit_station_box->currentText(), + RDRecording::Download, + (const char *)edit_starttime_edit->time(). + toString("hh:mm:ss"), + (const char *)edit_url_edit->text(), + (const char *)edit_destination_edit->text().right(10)); + if(edit_sun_button->isChecked()) { + sql+="&&(SUN=\"Y\")"; + } + if(edit_mon_button->isChecked()) { + sql+="&&(MON=\"Y\")"; + } + if(edit_tue_button->isChecked()) { + sql+="&&(TUE=\"Y\")"; + } + if(edit_wed_button->isChecked()) { + sql+="&&(WED=\"Y\")"; + } + if(edit_thu_button->isChecked()) { + sql+="&&(THU=\"Y\")"; + } + if(edit_fri_button->isChecked()) { + sql+="&&(FRI=\"Y\")"; + } + if(edit_sat_button->isChecked()) { + sql+="&&(SAT=\"Y\")"; + } + if(!include_myself) { + sql+=QString().sprintf("&&(ID!=%d)",edit_recording->id()); + } + RDSqlQuery *q=new RDSqlQuery(sql); + bool res=!q->first(); + delete q; + + return res; +} + diff --git a/rdcatch/edit_download.h b/rdcatch/edit_download.h new file mode 100644 index 00000000..c11efb6b --- /dev/null +++ b/rdcatch/edit_download.h @@ -0,0 +1,105 @@ +// edit_download.h +// +// Edit a Rivendell Download Event +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_download.h,v 1.10 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_DOWNLOAD_H +#define EDIT_DOWNLOAD_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +class EditDownload : public QDialog +{ + Q_OBJECT + public: + EditDownload(int id,std::vector *adds,QString *filter, + QWidget *parent=0,const char *name=0); + ~EditDownload(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void urlChangedData(const QString &str); + void selectCartData(); + void autotrimToggledData(bool state); + void normalizeToggledData(bool state); + void saveasData(); + void okData(); + void cancelData(); + + protected: + void paintEvent(QPaintEvent *e); + void keyPressEvent(QKeyEvent *); + void closeEvent(QCloseEvent *e); + + private: + void Save(); + bool CheckEvent(bool include_myself); + RDDeck *edit_deck; + RDRecording *edit_recording; + QCheckBox *edit_active_button; + QComboBox *edit_station_box; + QTimeEdit *edit_starttime_edit; + QLineEdit *edit_description_edit; + QLineEdit *edit_url_edit; + QLabel *edit_username_label; + QLineEdit *edit_username_edit; + QLabel *edit_password_label; + QLineEdit *edit_password_edit; + QString edit_cutname; + QLineEdit *edit_destination_edit; + QCheckBox *edit_metadata_box; + QCheckBox *edit_sun_button; + QCheckBox *edit_mon_button; + QCheckBox *edit_tue_button; + QCheckBox *edit_wed_button; + QCheckBox *edit_thu_button; + QCheckBox *edit_fri_button; + QCheckBox *edit_sat_button; + QSpinBox *edit_eventoffset_spin; + QCheckBox *edit_oneshot_box; + std::vector *edit_added_events; + QComboBox *edit_channels_box; + QCheckBox *edit_autotrim_box; + QLabel *edit_autotrim_label; + QSpinBox *edit_autotrim_spin; + QLabel *edit_autotrim_unit; + QCheckBox *edit_normalize_box; + QLabel *edit_normalize_label; + QSpinBox *edit_normalize_spin; + QLabel *edit_normalize_unit; + QString *edit_filter; +}; + + +#endif diff --git a/rdcatch/edit_playout.cpp b/rdcatch/edit_playout.cpp new file mode 100644 index 00000000..0a37b540 --- /dev/null +++ b/rdcatch/edit_playout.cpp @@ -0,0 +1,538 @@ +// edit_playout.cpp +// +// Edit a Rivendell RDCatch Playout +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_playout.cpp,v 1.23.4.1 2014/01/07 23:40:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +EditPlayout::EditPlayout(int id,std::vector *adds,QString *filter, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString temp; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont day_font=QFont("Helvetica",10,QFont::Normal); + day_font.setPixelSize(10); + + edit_deck=NULL; + edit_added_events=adds; + edit_filter=filter; + + setCaption(tr("Edit Playout")); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // The Recording Record + // + edit_recording=new RDRecording(id); + + // + // Active Button + // + edit_active_button=new QCheckBox(this,"edit_active_button"); + edit_active_button->setGeometry(10,11,20,20); + QLabel *label=new QLabel(edit_active_button, + tr("Event Active"),this,"edit_active_label"); + label->setGeometry(30,11,125,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Station + // + edit_station_box=new QComboBox(this,"edit_station_box"); + edit_station_box->setGeometry(200,10,140,23); + label=new QLabel(edit_station_box,tr("Location:"),this, + "edit_station_label"); + label->setGeometry(125,10,70,23); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(edit_station_box,SIGNAL(activated(int)), + this,SLOT(activateStationData(int))); + + // + // Start Time + // + edit_starttime_edit=new QTimeEdit(this,"edit_starttime_edit"); + edit_starttime_edit->setGeometry(sizeHint().width()-90,12,80,20); + label=new QLabel(edit_starttime_edit, + tr("Start Time:"),this,"edit_starttime_label"); + label->setGeometry(sizeHint().width()-175,12,80,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Description + // + edit_description_edit=new QLineEdit(this,"edit_description_edit"); + edit_description_edit->setGeometry(105,43,sizeHint().width()-115,20); + edit_description_edit->setValidator(validator); + label=new QLabel(edit_description_edit, + tr("Description:"),this,"edit_description_label"); + label->setGeometry(10,43,90,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Destination + // + edit_destination_edit=new QLineEdit(this,"edit_destination_edit"); + edit_destination_edit->setGeometry(105,70,sizeHint().width()-185,20); + edit_destination_edit->setReadOnly(true); + label=new QLabel(edit_destination_edit, + tr("Destination:"),this,"edit_destination_label"); + label->setGeometry(10,70,90,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QPushButton *button=new QPushButton(this,"destination_button"); + button->setGeometry(sizeHint().width()-70,65,60,30); + button->setFont(day_font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectCutData())); + + // + // Button Label + // + label=new QLabel(tr("Active Days"),this,"active_days_label"); + label->setGeometry(47,101,90,19); + label->setFont(label_font); + label->setAlignment(AlignHCenter|ShowPrefix); + + // + // Monday Button + // + edit_mon_button=new QCheckBox(this,"edit_mon_button"); + edit_mon_button->setGeometry(20,120,20,20); + label=new QLabel(edit_mon_button, + tr("Monday"),this,"edit_mon_label"); + label->setGeometry(40,120,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Tuesday Button + // + edit_tue_button=new QCheckBox(this,"edit_tue_button"); + edit_tue_button->setGeometry(115,120,20,20); + label=new QLabel(edit_tue_button, + tr("Tuesday"),this,"edit_tue_label"); + label->setGeometry(135,120,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Wednesday Button + // + edit_wed_button=new QCheckBox(this,"edit_wed_button"); + edit_wed_button->setGeometry(215,120,20,20); + label=new QLabel(edit_wed_button, + tr("Wednesday"),this,"edit_wed_label"); + label->setGeometry(235,120,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Thursday Button + // + edit_thu_button=new QCheckBox(this,"edit_thu_button"); + edit_thu_button->setGeometry(335,120,20,20); + label=new QLabel(edit_thu_button, + tr("Thursday"),this,"edit_thu_label"); + label->setGeometry(355,120,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Friday Button + // + edit_fri_button=new QCheckBox(this,"edit_fri_button"); + edit_fri_button->setGeometry(440,120,20,20); + label=new QLabel(edit_fri_button, + tr("Friday"),this,"edit_fri_label"); + label->setGeometry(460,120,40,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Saturday Button + // + edit_sat_button=new QCheckBox(this,"edit_sat_button"); + edit_sat_button->setGeometry(130,145,20,20); + label=new QLabel(edit_sat_button, + tr("Saturday"),this,"edit_sat_label"); + label->setGeometry(150,145,60,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Sunday Button + // + edit_sun_button=new QCheckBox(this,"edit_sun_button"); + edit_sun_button->setGeometry(300,145,20,20); + label=new QLabel(edit_sun_button, + tr("Sunday"),this,"edit_sun_label"); + label->setGeometry(320,145,60,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // OneShot Button + // + edit_oneshot_box=new QCheckBox(this,"edit_oneshot_box"); + edit_oneshot_box->setGeometry(20,180,15,15); + label=new QLabel(edit_oneshot_box, + tr("Make OneShot"),this,"edit_oneshot_label"); + label->setGeometry(40,178,115,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Save As Button + // + button=new QPushButton(this,"saveas_button"); + button->setGeometry(sizeHint().width()-300,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Save As\nNew")); + connect(button,SIGNAL(clicked()),this,SLOT(saveasData())); + if(adds==NULL) { + button->hide(); + } + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(button_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + PopulateDecks(edit_station_box); + edit_active_button->setChecked(edit_recording->isActive()); + edit_starttime_edit->setTime(edit_recording->startTime()); + edit_description_edit->setText(edit_recording->description()); + edit_cutname=edit_recording->cutName(); + edit_destination_edit->setText(RDCutPath(edit_cutname)); + edit_mon_button->setChecked(edit_recording->mon()); + edit_tue_button->setChecked(edit_recording->tue()); + edit_wed_button->setChecked(edit_recording->wed()); + edit_thu_button->setChecked(edit_recording->thu()); + edit_fri_button->setChecked(edit_recording->fri()); + edit_sat_button->setChecked(edit_recording->sat()); + edit_sun_button->setChecked(edit_recording->sun()); + edit_oneshot_box->setChecked(edit_recording->oneShot()); + activateStationData(edit_station_box->currentItem(),false); +} + + +EditPlayout::~EditPlayout() +{ + delete edit_station_box; + if(edit_deck!=NULL) { + delete edit_deck; + } +} + + +QSize EditPlayout::sizeHint() const +{ + return QSize(540,245); +} + + +QSizePolicy EditPlayout::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditPlayout::activateStationData(int id,bool use_temp) +{ + char station[65]; + char gunk[3]; + int chan; + + if(edit_station_box->currentText().isEmpty()) { + return; + } + sscanf((const char *)edit_station_box->currentText(),"%s%s%d", + station,gunk,&chan); + if(edit_deck!=NULL) { + delete edit_deck; + } + edit_deck=new RDDeck(station,chan); +} + + +void EditPlayout::selectCutData() +{ + RDCutDialog *cut=new RDCutDialog(&edit_cutname,rdstation_conf,catch_system, + edit_filter,NULL,NULL,"",false,false,false, + this); + switch(cut->exec()) { + case 0: + edit_destination_edit->setText(edit_cutname); + edit_description_edit->setText(RDCutPath(edit_cutname)); + break; + } + delete cut; +} + + +void EditPlayout::saveasData() +{ + if(!CheckEvent(true)) { + QMessageBox::warning(this,tr("Duplicate Event"), + tr("An event with these parameters already exists!")); + return; + } + delete edit_recording; + edit_recording=new RDRecording(-1,true); + edit_added_events->push_back(edit_recording->id()); + Save(); +} + + +void EditPlayout::okData() +{ + if(!CheckEvent(false)) { + QMessageBox::warning(this,tr("Duplicate Event"), + tr("An event with these parameters already exists!")); + return; + } + Save(); + done(0); +} + + +void EditPlayout::cancelData() +{ + done(-1); +} + + +void EditPlayout::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->drawRect(10,109,sizeHint().width()-20,62); + p->end(); +} + + +void EditPlayout::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Escape: + e->accept(); + cancelData(); + break; + + default: + QDialog::keyPressEvent(e); + break; + } +} + + +void EditPlayout::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void EditPlayout::PopulateDecks(QComboBox *box) +{ + int count=0; + + box->clear(); + QString sql=QString("select STATION_NAME,CHANNEL from DECKS \ +where (CARD_NUMBER!=-1)&&(PORT_NUMBER!=-1)&&\ +(CHANNEL>128) order by STATION_NAME,CHANNEL"); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + box->insertItem(QString().sprintf("%s : %dP", + (const char *)q->value(0).toString(),q->value(1).toInt()-128)); + if((q->value(0).toString()==edit_recording->station())&& + (q->value(1).toUInt()==edit_recording->channel())) { + box->setCurrentItem(count); + } + count++; + } + if(q->size()>0) { + if(edit_deck!=NULL) { + delete edit_deck; + } + q->first(); + edit_deck=new RDDeck(q->value(0).toString(),q->value(1).toUInt()); + } + delete q; +} + + +void EditPlayout::Save() +{ + char station[65]; + char gunk[3]; + int chan; + + sscanf((const char *)edit_station_box->currentText(),"%s%s%d", + station,gunk,&chan); + edit_recording->setIsActive(edit_active_button->isChecked()); + edit_recording->setStation(station); + edit_recording->setType(RDRecording::Playout); + edit_recording->setChannel(chan+128); + if(edit_starttime_edit->time().isNull()) { + edit_recording->setStartTime(edit_starttime_edit->time().addMSecs(1)); + } + else { + edit_recording->setStartTime(edit_starttime_edit->time()); + } + edit_recording->setDescription(edit_description_edit->text()); + edit_recording->setCutName(edit_cutname); + edit_recording->setMon(edit_mon_button->isChecked()); + edit_recording->setTue(edit_tue_button->isChecked()); + edit_recording->setWed(edit_wed_button->isChecked()); + edit_recording->setThu(edit_thu_button->isChecked()); + edit_recording->setFri(edit_fri_button->isChecked()); + edit_recording->setSat(edit_sat_button->isChecked()); + edit_recording->setSun(edit_sun_button->isChecked()); + edit_recording->setOneShot(edit_oneshot_box->isChecked()); +} + + +bool EditPlayout::CheckEvent(bool include_myself) +{ + char station[65]; + char gunk[3]; + int chan; + QTime test_start_time; + QTime test_end_time; + + RDCut *cut=new RDCut(edit_cutname); + QTime start_time=edit_starttime_edit->time(); + QTime end_time=edit_starttime_edit->time().addMSecs(cut->length()); + delete cut; + + sscanf((const char *)edit_station_box->currentText(),"%s%s%d", + station,gunk,&chan); + QString sql= + QString().sprintf("select RECORDINGS.START_TIME,CUTS.LENGTH\ + from RECORDINGS left join CUTS\ + on(RECORDINGS.CUT_NAME=CUTS.CUT_NAME)\ + where (RECORDINGS.STATION_NAME=\"%s\")&&\ + (RECORDINGS.TYPE=%d)&&(RECORDINGS.CHANNEL=%d)", + station,RDRecording::Playout,chan+128); + if(edit_sun_button->isChecked()) { + sql+="&&(RECORDINGS.SUN=\"Y\")"; + } + if(edit_mon_button->isChecked()) { + sql+="&&(RECORDINGS.MON=\"Y\")"; + } + if(edit_tue_button->isChecked()) { + sql+="&&(RECORDINGS.TUE=\"Y\")"; + } + if(edit_wed_button->isChecked()) { + sql+="&&(RECORDINGS.WED=\"Y\")"; + } + if(edit_thu_button->isChecked()) { + sql+="&&(RECORDINGS.THU=\"Y\")"; + } + if(edit_fri_button->isChecked()) { + sql+="&&(RECORDINGS.FRI=\"Y\")"; + } + if(edit_sat_button->isChecked()) { + sql+="&&(RECORDINGS.SAT=\"Y\")"; + } + if(!include_myself) { + sql+=QString().sprintf("&&(RECORDINGS.ID!=%d)",edit_recording->id()); + } + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + test_start_time=q->value(0).toTime(); + test_end_time=q->value(0).toTime().addMSecs(q->value(1).toUInt()); + if(test_end_timetest_start_time)&&(start_time>test_end_time)&& + (end_time>test_start_time)&&(end_time>test_end_time))) { + } + else { + delete q; + return false; + } + } + delete q; + + return true; +} diff --git a/rdcatch/edit_playout.h b/rdcatch/edit_playout.h new file mode 100644 index 00000000..5334eaa7 --- /dev/null +++ b/rdcatch/edit_playout.h @@ -0,0 +1,88 @@ +// edit_playout.h +// +// Edit a Rivendell RDCatch Playout +// +// (C) Copyright 2002-2004 Fred Gleason / +// +// $Id: edit_playout.h,v 1.9 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_PLAYOUT_H +#define EDIT_PLAYOUT_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class EditPlayout : public QDialog +{ + Q_OBJECT + public: + EditPlayout(int id,std::vector *adds,QString *filter, + QWidget *parent=0,const char *name=0); + ~EditPlayout(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void activateStationData(int,bool use_temp=true); + void selectCutData(); + void saveasData(); + void okData(); + void cancelData(); + + protected: + void paintEvent(QPaintEvent *e); + void keyPressEvent(QKeyEvent *); + void closeEvent(QCloseEvent *e); + + private: + void PopulateDecks(QComboBox *box); + void Save(); + bool CheckEvent(bool include_myself); + RDDeck *edit_deck; + RDRecording *edit_recording; + QCheckBox *edit_active_button; + QComboBox *edit_station_box; + QTimeEdit *edit_starttime_edit; + QLineEdit *edit_description_edit; + QString edit_cutname; + QLineEdit *edit_destination_edit; + QCheckBox *edit_sun_button; + QCheckBox *edit_mon_button; + QCheckBox *edit_tue_button; + QCheckBox *edit_wed_button; + QCheckBox *edit_thu_button; + QCheckBox *edit_fri_button; + QCheckBox *edit_sat_button; + QCheckBox *edit_oneshot_box; + std::vector *edit_added_events; + QString *edit_filter; +}; + + +#endif + diff --git a/rdcatch/edit_recording.cpp b/rdcatch/edit_recording.cpp new file mode 100644 index 00000000..020a62da --- /dev/null +++ b/rdcatch/edit_recording.cpp @@ -0,0 +1,1208 @@ +// edit_recording.cpp +// +// Edit a Rivendell RDCatch Recording +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_recording.cpp,v 1.53 2012/02/13 19:26:16 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +EditRecording::EditRecording(int id,std::vector *adds,QString *filter, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString temp; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont day_font=QFont("Helvetica",10,QFont::Normal); + day_font.setPixelSize(10); + + edit_deck=NULL; + edit_added_events=adds; + edit_filter=filter; + + setCaption(tr("Edit Recording")); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // The Recording Record + // + edit_recording=new RDRecording(id); + + // + // Active Button + // + edit_active_button=new QCheckBox(tr("Event Active"),this,"edit_active_button"); + edit_active_button->setGeometry(10,11,145,20); + edit_active_button->setFont(label_font); + + // + // Station + // + edit_station_box=new QComboBox(this,"edit_station_box"); + edit_station_box->setGeometry(200,10,140,23); + QLabel * label=new QLabel(edit_station_box,tr("Location:"),this, + "edit_station_label"); + label->setGeometry(125,10,70,23); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(edit_station_box,SIGNAL(activated(int)), + this,SLOT(activateStationData(int))); + + // + // Start Parameters + // + edit_starttype_group=new QButtonGroup(this,"edit_starttype_group"); + edit_starttype_group->setGeometry(10,47,sizeHint().width()-20,104); + connect(edit_starttype_group,SIGNAL(clicked(int)), + this,SLOT(startTypeClickedData(int))); + + label=new QLabel(tr("Start Parameters"),this,"start_params_label"); + label->setGeometry(47,38,120,19); + label->setFont(label_font); + label->setAlignment(AlignHCenter|ShowPrefix); + + QRadioButton *rbutton=new QRadioButton(tr("Use Hard Time"),this,"hard_button"); + rbutton->setGeometry(20,57,100,15); + edit_starttype_group->insert(rbutton,RDRecording::HardStart); + rbutton->setFont(day_font); + + edit_starttime_edit=new QTimeEdit(this,"edit_starttime_edit"); + edit_starttime_edit->setGeometry(235,53,80,20); + edit_starttime_label=new QLabel(edit_starttime_edit,tr("Record Start Time:"), + this,"edit_starttime_label"); + edit_starttime_label->setGeometry(125,57,105,15); + edit_starttime_label->setFont(day_font); + edit_starttime_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + rbutton=new QRadioButton(tr("Use GPI"),this,"gpi_button"); + rbutton->setGeometry(20,81,100,15); + rbutton->setFont(day_font); + + edit_start_startwindow_edit= + new QTimeEdit(this,"edit_start_startwindow_edit"); + edit_start_startwindow_edit->setGeometry(235,77,80,20); + edit_start_startwindow_label= + new QLabel(edit_start_startwindow_edit,tr("Window Start Time:"), + this,"edit_start_startwindow_label"); + edit_start_startwindow_label->setGeometry(125,81,105,15); + edit_start_startwindow_label->setFont(day_font); + edit_start_startwindow_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + edit_start_endwindow_edit= + new QTimeEdit(this,"edit_start_endwindow_edit"); + edit_start_endwindow_edit->setGeometry(435,77,80,20); + edit_start_endwindow_label= + new QLabel(edit_start_endwindow_edit,"Window End Time:", + this,"edit_start_endwindow_label"); + edit_start_endwindow_label->setGeometry(325,81,105,15); + edit_start_endwindow_label->setFont(day_font); + edit_start_endwindow_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + edit_startmatrix_spin=new QSpinBox(this,"edit_startmatrix_spin"); + edit_startmatrix_spin->setGeometry(185,99,30,20); + edit_startmatrix_spin->setRange(0,MAX_MATRICES-1); + edit_startmatrix_label=new QLabel(edit_startmatrix_spin,tr("GPI Matrix:"), + this,"edit_startmatrix_label"); + edit_startmatrix_label->setGeometry(100,100,80,20); + edit_startmatrix_label->setFont(day_font); + edit_startmatrix_label->setAlignment(AlignRight|AlignVCenter); + + edit_startline_spin=new QSpinBox(this,"edit_startline_spin"); + edit_startline_spin->setGeometry(295,99,30,20); + edit_startline_spin->setRange(1,MAX_GPIO_PINS); + edit_startline_label=new QLabel(edit_startline_spin,tr("GPI Line:"), + this,"edit_startline_label"); + edit_startline_label->setGeometry(230,100,60,20); + edit_startline_label->setFont(day_font); + edit_startline_label->setAlignment(AlignRight|AlignVCenter); + + edit_startoffset_edit= + new QTimeEdit(this,"edit_startoffset_edit"); + edit_startoffset_edit->setGeometry(435,99,80,20); + edit_startoffset_label= + new QLabel(edit_startoffset_edit,tr("Start Delay:"), + this,"edit_startoffset_label"); + edit_startoffset_label->setGeometry(325,100,105,20); + edit_startoffset_label->setFont(day_font); + edit_startoffset_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + edit_multirec_box=new QCheckBox(tr("Allow Multiple Recordings within this Window"),this,"edit_multirec_box"); + edit_multirec_box->setGeometry(140,124,sizeHint().width()-170,15); + edit_multirec_box->setFont(day_font); + + edit_starttype_group->insert(rbutton,RDRecording::GpiStart); + + // + // End Parameters + // + edit_endtype_group=new QButtonGroup(this,"edit_endtype_group"); + edit_endtype_group->setGeometry(10,171,sizeHint().width()-20,104); + connect(edit_endtype_group,SIGNAL(clicked(int)), + this,SLOT(endTypeClickedData(int))); + + label=new QLabel(tr("End Parameters"),this,"end_params_label"); + label->setGeometry(47,162,120,19); + label->setFont(label_font); + label->setAlignment(AlignHCenter|ShowPrefix); + + rbutton=new QRadioButton(tr("Use Length"),this,"length_button"); + rbutton->setGeometry(20,205,100,15); + edit_endtype_group->insert(rbutton,RDRecording::LengthEnd); + rbutton->setFont(day_font); + edit_endlength_edit=new QTimeEdit(this,"edit_endlength_edit"); + edit_endlength_edit->setGeometry(235,201,80,20); + edit_endlength_label=new QLabel(tr("Record Length:"), + this,"edit_endlength_label"); + edit_endlength_label->setGeometry(125,205,105,15); + edit_endlength_label->setFont(day_font); + edit_endlength_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + rbutton=new QRadioButton(tr("Use Hard Time"),this,"hard_button"); + rbutton->setGeometry(20,181,1100,15); + edit_endtype_group->insert(rbutton,RDRecording::HardEnd); + rbutton->setFont(day_font); + edit_endtime_edit=new QTimeEdit(this,"edit_endtime_edit"); + edit_endtime_edit->setGeometry(235,177,80,20); + edit_endtime_label=new QLabel(edit_endtime_edit,tr("Record End Time:"), + this,"edit_endtime_label"); + edit_endtime_label->setGeometry(125,177,105,15); + edit_endtime_label->setFont(day_font); + edit_endtime_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + rbutton=new QRadioButton(tr("Use GPI"),this,"gpi_button"); + rbutton->setGeometry(20,229,100,15); + rbutton->setFont(day_font); + edit_end_startwindow_edit= + new QTimeEdit(this,"edit_end_startwindow_edit"); + edit_end_startwindow_edit->setGeometry(235,225,80,20); + edit_end_startwindow_label= + new QLabel(edit_end_startwindow_edit,tr("Window Start Time:"), + this,"edit_end_startwindow_label"); + edit_end_startwindow_label->setGeometry(125,229,105,15); + edit_end_startwindow_label->setFont(day_font); + edit_end_startwindow_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + edit_end_endwindow_edit= + new QTimeEdit(this,"edit_end_endwindow_edit"); + edit_end_endwindow_edit->setGeometry(435,225,80,20); + edit_end_endwindow_label= + new QLabel(edit_end_endwindow_edit,tr("Window End Time:"), + this,"edit_end_endwindow_label"); + edit_end_endwindow_label->setGeometry(325,229,105,15); + edit_end_endwindow_label->setFont(day_font); + edit_end_endwindow_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + edit_endmatrix_spin=new QSpinBox(this,"edit_endmatrix_spin"); + edit_endmatrix_spin->setGeometry(185,247,30,20); + edit_endmatrix_spin->setRange(0,MAX_MATRICES-1); + edit_endmatrix_label=new QLabel(edit_endmatrix_spin,tr("GPI Matrix:"), + this,"edit_endmatrix_label"); + edit_endmatrix_label->setGeometry(100,248,80,20); + edit_endmatrix_label->setFont(day_font); + edit_endmatrix_label->setAlignment(AlignRight|AlignVCenter); + + edit_endline_spin=new QSpinBox(this,"edit_endline_spin"); + edit_endline_spin->setGeometry(295,247,30,20); + edit_endline_spin->setRange(1,MAX_GPIO_PINS); + edit_endline_label=new QLabel(edit_endline_spin,tr("GPI Line:"), + this,"edit_endline_label"); + edit_endline_label->setGeometry(230,248,60,20); + edit_endline_label->setFont(day_font); + edit_endline_label->setAlignment(AlignRight|AlignVCenter); + + edit_maxlength_edit= + new QTimeEdit(this,"edit_maxlength_edit"); + edit_maxlength_edit->setGeometry(435,247,80,20); + edit_maxlength_label= + new QLabel(edit_maxlength_edit,tr("Max Record Length:"), + this,"edit_maxlength_label"); + edit_maxlength_label->setGeometry(325,248,105,20); + edit_maxlength_label->setFont(day_font); + edit_maxlength_label-> + setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + edit_endtype_group->insert(rbutton,RDRecording::GpiEnd); + + // + // Description + // + edit_description_edit=new QLineEdit(this,"edit_description_edit"); + edit_description_edit->setGeometry(105,291,sizeHint().width()-115,20); + edit_description_edit->setValidator(validator); + label=new QLabel(edit_description_edit, + tr("Description:"),this,"edit_description_label"); + label->setGeometry(10,291,90,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Source Name + // + edit_source_box=new QComboBox(this,"edit_source_box"); + edit_source_box->setGeometry(105,317,sizeHint().width()-115,24); + label=new QLabel(edit_source_box, + tr("Source:"),this,"edit_source_label"); + label->setGeometry(10,317,90,24); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Destination + // + edit_destination_edit=new QLineEdit(this,"edit_destination_edit"); + edit_destination_edit->setGeometry(105,345,sizeHint().width()-185,20); + edit_destination_edit->setReadOnly(true); + label=new QLabel(edit_destination_edit, + tr("Destination:"),this,"edit_destination_label"); + label->setGeometry(10,345,90,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QPushButton *button=new QPushButton(this,"destination_button"); + button->setGeometry(sizeHint().width()-70,344,60,24); + button->setFont(day_font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectCutData())); + + // + // Channels + // + edit_channels_box=new QComboBox(this,"edit_channels_box"); + edit_channels_box->setGeometry(190,370,40,20); + edit_channels_box->insertItem("1"); + edit_channels_box->insertItem("2"); + label= + new QLabel(edit_channels_box,tr("Channels:"),this,"edit_channels_label"); + label->setGeometry(120,370,70,20); + label->setFont(label_font); + label->setAlignment(AlignVCenter|AlignLeft); + + // + // Autotrim Controls + // + edit_autotrim_box=new QCheckBox(tr("Autotrim"),this,"edit_autotrim_box"); + edit_autotrim_box->setGeometry(120,395,100,15); + edit_autotrim_box->setFont(label_font); + connect(edit_autotrim_box,SIGNAL(toggled(bool)), + this,SLOT(autotrimToggledData(bool))); + edit_autotrim_spin=new QSpinBox(this,"edit_autotrim_spin"); + edit_autotrim_spin->setGeometry(265,393,40,20); + edit_autotrim_spin->setRange(-99,-1); + edit_autotrim_label= + new QLabel(edit_autotrim_spin,tr("Level:"),this,"edit_autotrim_label"); + edit_autotrim_label->setGeometry(220,393,40,20); + edit_autotrim_label->setFont(label_font); + edit_autotrim_label->setAlignment(AlignVCenter|AlignRight); + edit_autotrim_unit= + new QLabel(edit_autotrim_spin,tr("dBFS"),this,"edit_autotrim_unit"); + edit_autotrim_unit->setGeometry(310,393,40,20); + edit_autotrim_unit->setFont(label_font); + edit_autotrim_unit->setAlignment(AlignVCenter|AlignLeft); + + // + // Normalize Controls + // + edit_normalize_box=new QCheckBox(tr("Normalize"),this,"edit_normalize_box"); + edit_normalize_box->setGeometry(120,420,100,15); + connect(edit_normalize_box,SIGNAL(toggled(bool)), + this,SLOT(normalizeToggledData(bool))); + edit_normalize_box->setFont(label_font); + edit_normalize_spin=new QSpinBox(this,"edit_normalize_spin"); + edit_normalize_spin->setGeometry(265,418,40,20); + edit_normalize_spin->setRange(-99,-1); + edit_normalize_label= + new QLabel(edit_normalize_spin,tr("Level:"),this,"edit_normalize_label"); + edit_normalize_label->setGeometry(220,418,40,20); + edit_normalize_label->setFont(label_font); + edit_normalize_label->setAlignment(AlignVCenter|AlignRight); + edit_normalize_unit= + new QLabel(edit_normalize_spin,tr("dBFS"),this,"edit_normalize_unit"); + edit_normalize_unit->setGeometry(310,418,40,20); + edit_normalize_unit->setFont(label_font); + edit_normalize_unit->setAlignment(AlignVCenter|AlignLeft); + + // + // Button Label + // + label=new QLabel(tr("Active Days"),this,"active_days_label"); + label->setGeometry(47,440,90,19); + label->setFont(label_font); + label->setAlignment(AlignHCenter|ShowPrefix); + + // + // Monday Button + // + edit_mon_button=new QCheckBox(tr("Monday"),this,"edit_mon_button"); + edit_mon_button->setGeometry(20,459,135,20); + edit_mon_button->setFont(day_font); + + // + // Tuesday Button + // + edit_tue_button=new QCheckBox(tr("Tuesday"),this,"edit_tue_button"); + edit_tue_button->setGeometry(115,459,135,20); + edit_tue_button->setFont(day_font); + + // + // Wednesday Button + // + edit_wed_button=new QCheckBox(tr("Wednesday"),this,"edit_wed_button"); + edit_wed_button->setGeometry(215,459,135,20); + edit_wed_button->setFont(day_font); + + // + // Thursday Button + // + edit_thu_button=new QCheckBox(tr("Thursday"),this,"edit_thu_button"); + edit_thu_button->setGeometry(335,459,135,20); + edit_thu_button->setFont(day_font); + + // + // Friday Button + // + edit_fri_button=new QCheckBox(tr("Friday"),this,"edit_fri_button"); + edit_fri_button->setGeometry(440,459,135,20); + edit_fri_button->setFont(day_font); + + // + // Saturday Button + // + edit_sat_button=new QCheckBox(tr("Saturday"),this,"edit_sat_button"); + edit_sat_button->setGeometry(130,484,80,20); + edit_sat_button->setFont(day_font); + + // + // Sunday Button + // + edit_sun_button=new QCheckBox(tr("Sunday"),this,"edit_sun_button"); + edit_sun_button->setGeometry(300,484,80,20); + edit_sun_button->setFont(day_font); + + // + // Start Date Offset + // + edit_startoffset_box=new QSpinBox(this,"edit_startoffset_box"); + edit_startoffset_box->setGeometry(140,516,55,24); + edit_startoffset_box->setRange(0,355); + edit_startoffset_box->setSpecialValueText(tr("None")); + label=new QLabel(edit_startoffset_box, + tr("Start Date Offset:"),this,"edit_startoffset_label"); + label->setGeometry(10,516,125,24); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // End Date Offset + // + edit_endoffset_box=new QSpinBox(this,"edit_endoffset_box"); + edit_endoffset_box->setGeometry(440,516,55,24); + edit_endoffset_box->setRange(0,355); + edit_endoffset_box->setSpecialValueText(tr("None")); + label=new QLabel(edit_endoffset_box, + tr("End Date Offset:"),this,"edit_endoffset_label"); + label->setGeometry(310,516,125,24); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // OneShot Button + // + edit_oneshot_box=new QCheckBox(tr("Make OneShot"),this,"edit_oneshot_box"); + edit_oneshot_box->setGeometry(20,553,125,15); + edit_oneshot_box->setFont(label_font); + + // + // Save As Button + // + button=new QPushButton(this,"saveas_button"); + button->setGeometry(sizeHint().width()-300,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Save As\nNew")); + connect(button,SIGNAL(clicked()),this,SLOT(saveasData())); + if(adds==NULL) { + button->hide(); + } + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(button_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + PopulateDecks(edit_station_box); + edit_active_button->setChecked(edit_recording->isActive()); + edit_starttime_edit->setTime(edit_recording->startTime()); + edit_description_edit->setText(edit_recording->description()); + edit_starttype_group->setButton((int)edit_recording->startType()); + switch((RDRecording::StartType)edit_starttype_group->selectedId()) { + case RDRecording::HardStart: + edit_starttime_edit->setTime(edit_recording->startTime()); + break; + + case RDRecording::GpiStart: + edit_start_startwindow_edit->setTime(edit_recording->startTime()); + edit_start_endwindow_edit-> + setTime(edit_start_startwindow_edit->time(). + addMSecs(edit_recording->startLength())); + edit_startmatrix_spin->setValue(edit_recording->startMatrix()); + edit_startline_spin->setValue(edit_recording->startLine()); + edit_startoffset_edit-> + setTime(QTime().addMSecs(edit_recording->startOffset())); + edit_multirec_box-> + setChecked(edit_recording->allowMultipleRecordings()); + break; + } + startTypeClickedData(edit_starttype_group->selectedId()); + edit_endtype_group->setButton((int)edit_recording->endType()); + switch((RDRecording::EndType)edit_endtype_group->selectedId()) { + case RDRecording::LengthEnd: + edit_endlength_edit-> + setTime(QTime().addMSecs(edit_recording->length())); + break; + + case RDRecording::HardEnd: + edit_endtime_edit->setTime(edit_recording->endTime()); + break; + + case RDRecording::GpiEnd: + edit_end_startwindow_edit->setTime(edit_recording->endTime()); + edit_end_endwindow_edit-> + setTime(edit_end_startwindow_edit->time(). + addMSecs(edit_recording->endLength())); + edit_endmatrix_spin->setValue(edit_recording->endMatrix()); + edit_endline_spin->setValue(edit_recording->endLine()); + break; + } + edit_maxlength_edit-> + setTime(QTime().addMSecs(edit_recording->maxGpiRecordingLength())); + endTypeClickedData(edit_endtype_group->selectedId()); + + edit_cutname=edit_recording->cutName(); + edit_destination_edit->setText(RDCutPath(edit_cutname)); + edit_mon_button->setChecked(edit_recording->mon()); + edit_tue_button->setChecked(edit_recording->tue()); + edit_wed_button->setChecked(edit_recording->wed()); + edit_thu_button->setChecked(edit_recording->thu()); + edit_fri_button->setChecked(edit_recording->fri()); + edit_sat_button->setChecked(edit_recording->sat()); + edit_sun_button->setChecked(edit_recording->sun()); + edit_startoffset_box->setValue(edit_recording->startdateOffset()); + edit_endoffset_box->setValue(edit_recording->enddateOffset()); + activateStationData(edit_station_box->currentItem(),false); + + QString source=GetSourceName(edit_recording->switchSource()); + for(int i=0;icount();i++) { + if(edit_source_box->text(i)==source) { + edit_source_box->setCurrentItem(i); + } + } + if(edit_recording->trimThreshold()>0) { + edit_autotrim_box->setChecked(true); + edit_autotrim_spin->setValue(-(edit_recording->trimThreshold()/100)); + } + else { + edit_autotrim_box->setChecked(false); + edit_autotrim_spin->setValue(rdlibrary_conf->trimThreshold()/100); + } + autotrimToggledData(edit_autotrim_box->isChecked()); + if(edit_recording->normalizationLevel()<0) { + edit_normalize_box->setChecked(true); + edit_normalize_spin->setValue(edit_recording->normalizationLevel()/100); + } + else { + edit_normalize_box->setChecked(false); + edit_normalize_spin->setValue(rdlibrary_conf->ripperLevel()/100); + } + normalizeToggledData(edit_normalize_box->isChecked()); + // Populate number of channels; if creating a new recording entry and a valid + // deck exists, use the deck default for num. channels. Otherwise use the + // previously entered (or DB default) recording num. channels. + if( (edit_recording->station().length() == 0) && (edit_deck!=NULL) ) { + edit_channels_box->setCurrentItem(edit_deck->defaultChannels()-1); + } else { + edit_channels_box->setCurrentItem(edit_recording->channels()-1); + } + edit_oneshot_box->setChecked(edit_recording->oneShot()); +} + + +EditRecording::~EditRecording() +{ + delete edit_station_box; + if(edit_deck!=NULL) { + delete edit_deck; + } +} + + +QSize EditRecording::sizeHint() const +{ + return QSize(540,619); +} + + +QSizePolicy EditRecording::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditRecording::activateStationData(int id,bool use_temp) +{ + char station[65]; + char gunk[3]; + int chan; + RDSqlQuery *q; + + if(edit_station_box->currentText().isEmpty()) { + return; + } + QString temp=edit_source_box->currentText(); + sscanf((const char *)edit_station_box->currentText(),"%s%s%d", + station,gunk,&chan); + if(edit_deck!=NULL) { + delete edit_deck; + } + edit_deck=new RDDeck(station,chan); + if(edit_channels_box->count()>0) { + edit_channels_box->setCurrentItem(edit_deck->defaultChannels()-1); + } + edit_source_box->clear(); + q=new RDSqlQuery(QString().sprintf("select NAME from INPUTS where \ + (STATION_NAME=\"%s\")&&(MATRIX=%d)", + (const char *)edit_deck->switchStation(), + edit_deck->switchMatrix())); + while(q->next()) { + edit_source_box->insertItem(q->value(0).toString()); + } + delete q; +} + + +void EditRecording::startTypeClickedData(int id) +{ + bool state=false; + + if(((RDRecording::StartType)id)==RDRecording::HardStart) { + state=true; + edit_multirec_box->setDisabled(true); + } + else { + switch((RDRecording::EndType)edit_endtype_group->selectedId()) { + case RDRecording::HardEnd: + edit_multirec_box->setDisabled(true); + break; + + case RDRecording::GpiEnd: + case RDRecording::LengthEnd: + edit_multirec_box->setEnabled(true); + break; + } + } + edit_starttime_edit->setEnabled(state); + edit_starttime_label->setEnabled(state); + edit_start_startwindow_edit->setDisabled(state); + edit_start_startwindow_label->setDisabled(state); + edit_start_endwindow_edit->setDisabled(state); + edit_start_endwindow_label->setDisabled(state); + edit_startoffset_edit->setDisabled(state); + edit_startoffset_label->setDisabled(state); + edit_startmatrix_spin->setDisabled(state); + edit_startmatrix_label->setDisabled(state); + edit_startline_spin->setDisabled(state); + edit_startline_label->setDisabled(state); +} + + +void EditRecording::endTypeClickedData(int id) +{ + bool hard_state=false; + bool gpi_state=false; + bool length_state=false; + + if(((RDRecording::EndType)id)==RDRecording::HardEnd) { + hard_state=true; + edit_multirec_box->setDisabled(true); + } + if(((RDRecording::EndType)id)==RDRecording::GpiEnd) { + gpi_state=true; + edit_multirec_box-> + setEnabled(edit_starttype_group->selectedId()==RDRecording::GpiStart); + } + if(((RDRecording::EndType)id)==RDRecording::LengthEnd) { + length_state=true; + edit_multirec_box-> + setEnabled(edit_starttype_group->selectedId()==RDRecording::GpiStart); + } + edit_endtime_edit->setEnabled(hard_state); + edit_endtime_label->setEnabled(hard_state); + edit_end_startwindow_edit->setEnabled(gpi_state); + edit_end_startwindow_label->setEnabled(gpi_state); + edit_end_endwindow_edit->setEnabled(gpi_state); + edit_end_endwindow_label->setEnabled(gpi_state); + edit_endmatrix_spin->setEnabled(gpi_state); + edit_endmatrix_label->setEnabled(gpi_state); + edit_endline_spin->setEnabled(gpi_state); + edit_endline_label->setEnabled(gpi_state); + edit_endlength_edit->setEnabled(length_state); + edit_endlength_label->setEnabled(length_state); + edit_maxlength_label->setEnabled(gpi_state); + edit_maxlength_edit->setEnabled(gpi_state); +} + + +void EditRecording::selectCutData() +{ + QString str; + + RDCutDialog *cut=new RDCutDialog(&edit_cutname,rdstation_conf,catch_system, + edit_filter,NULL,NULL,catch_user->name(), + false,true); + switch(cut->exec()) { + case 0: + edit_description_edit->setText(RDCutPath(edit_cutname)); + str=QString(tr("Cut")); + edit_destination_edit-> + setText(QString().sprintf("%s %s",(const char *)str, + (const char *)edit_cutname)); + break; + } + delete cut; +} + + +void EditRecording::autotrimToggledData(bool state) +{ + edit_autotrim_label->setEnabled(state); + edit_autotrim_spin->setEnabled(state); + edit_autotrim_unit->setEnabled(state); +} + + +void EditRecording::normalizeToggledData(bool state) +{ + edit_normalize_label->setEnabled(state); + edit_normalize_spin->setEnabled(state); + edit_normalize_unit->setEnabled(state); +} + + +void EditRecording::saveasData() +{ + if(!CheckEvent(true)) { + return; + } + delete edit_recording; + edit_recording=new RDRecording(-1,true); + edit_added_events->push_back(edit_recording->id()); + Save(); +} + + +void EditRecording::okData() +{ + if(!CheckEvent(false)) { + return; + } + Save(); + done(0); +} + + +void EditRecording::cancelData() +{ + done(-1); +} + + +void EditRecording::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->drawRect(10,447,sizeHint().width()-20,62); + p->end(); +} + + +void EditRecording::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Escape: + e->accept(); + cancelData(); + break; + + default: + QDialog::keyPressEvent(e); + break; + } +} + + +void EditRecording::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void EditRecording::PopulateDecks(QComboBox *box) +{ + int count=0; + + box->clear(); + QString sql=QString("select STATION_NAME,CHANNEL from DECKS \ +where (CARD_NUMBER!=-1)&&(PORT_NUMBER!=-1)&&(CHANNEL!=0) \ +&&(CHANNEL<9) order by STATION_NAME,CHANNEL"); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + box->insertItem(QString().sprintf("%s : %dR", + (const char *)q->value(0).toString(),q->value(1).toInt())); + if((q->value(0).toString()==edit_recording->station())&& + (q->value(1).toUInt()==edit_recording->channel())) { + box->setCurrentItem(count); + } + count++; + } + if(q->size()>0) { + if(edit_deck!=NULL) { + delete edit_deck; + } + q->first(); + edit_deck=new RDDeck(q->value(0).toString(),q->value(1).toUInt()); + if(edit_channels_box->count()>0) { + edit_channels_box->setCurrentItem(edit_deck->defaultChannels()-1); + } + } + delete q; + if(box->count()==0) { // In case the deck has been disabled + box->insertItem(QString().sprintf("%s : %dR", + (const char *)edit_recording->station(), + edit_recording->channel())); + } +} + + +void EditRecording::Save() +{ + char station[65]; + char gunk[3]; + int chan; + + sscanf((const char *)edit_station_box->currentText(),"%s%s%d", + station,gunk,&chan); + edit_recording->setIsActive(edit_active_button->isChecked()); + edit_recording->setStation(station); + edit_recording->setType(RDRecording::Recording); + edit_recording->setChannel(chan); + edit_recording->setDescription(edit_description_edit->text()); + edit_recording->setCutName(edit_cutname); + edit_recording->setMon(edit_mon_button->isChecked()); + edit_recording->setTue(edit_tue_button->isChecked()); + edit_recording->setWed(edit_wed_button->isChecked()); + edit_recording->setThu(edit_thu_button->isChecked()); + edit_recording->setFri(edit_fri_button->isChecked()); + edit_recording->setSat(edit_sat_button->isChecked()); + edit_recording->setSun(edit_sun_button->isChecked()); + edit_recording->setSwitchSource(GetSource()); + edit_recording->setStartdateOffset(edit_startoffset_box->value()); + edit_recording->setEnddateOffset(edit_endoffset_box->value()); + edit_recording->setFormat(edit_deck->defaultFormat()); + if(edit_deck->defaultFormat()>0) { + edit_recording->setBitrate(edit_deck->defaultBitrate()* + (edit_channels_box->currentItem()+1)); + } + else { + edit_recording->setBitrate(0); + } + edit_recording->setChannels(edit_channels_box->currentItem()+1); + if(edit_autotrim_box->isChecked()) { + edit_recording->setTrimThreshold(-100*edit_autotrim_spin->value()); + } + else { + edit_recording->setTrimThreshold(0); + } + if(edit_normalize_box->isChecked()) { + edit_recording->setNormalizationLevel(100*edit_normalize_spin->value()); + } + else { + edit_recording->setNormalizationLevel(0); + } + edit_recording->setOneShot(edit_oneshot_box->isChecked()); + edit_recording-> + setStartType((RDRecording::StartType)edit_starttype_group->selectedId()); + switch((RDRecording::StartType)edit_starttype_group->selectedId()) { + case RDRecording::HardStart: + if(edit_starttime_edit->time().isNull()) { + edit_recording-> + setStartTime(edit_starttime_edit->time().addMSecs(1)); + } + else { + edit_recording->setStartTime(edit_starttime_edit->time()); + } + edit_recording->setAllowMultipleRecordings(false); + break; + + case RDRecording::GpiStart: + if(edit_start_startwindow_edit->time().isNull()) { + edit_recording-> + setStartTime(edit_start_startwindow_edit->time().addMSecs(1)); + } + else { + edit_recording->setStartTime(edit_start_startwindow_edit->time()); + } + edit_recording-> + setStartLength(edit_start_startwindow_edit->time(). + msecsTo(edit_start_endwindow_edit->time())); + edit_recording->setStartMatrix(edit_startmatrix_spin->value()); + edit_recording->setStartLine(edit_startline_spin->value()); + edit_recording-> + setStartOffset(QTime().msecsTo(edit_startoffset_edit->time())); + edit_recording-> + setAllowMultipleRecordings(edit_multirec_box->isChecked()); + break; + } + edit_recording-> + setEndType((RDRecording::EndType)edit_endtype_group->selectedId()); + edit_recording-> + setMaxGpiRecordingLength(QTime().msecsTo(edit_maxlength_edit->time())); + switch((RDRecording::EndType)edit_endtype_group->selectedId()) { + case RDRecording::LengthEnd: + edit_recording-> + setLength(QTime().msecsTo(edit_endlength_edit->time())); + break; + + case RDRecording::HardEnd: + if(edit_endtime_edit->time().isNull()) { + edit_recording->setEndTime(edit_endtime_edit->time().addMSecs(1)); + } + else { + edit_recording->setEndTime(edit_endtime_edit->time()); + } + break; + + case RDRecording::GpiEnd: + if(edit_end_startwindow_edit->time().isNull()) { + edit_recording-> + setEndTime(edit_end_startwindow_edit->time().addMSecs(1)); + } + else { + edit_recording->setEndTime(edit_end_startwindow_edit->time()); + } + edit_recording-> + setEndLength(edit_end_startwindow_edit->time(). + msecsTo(edit_end_endwindow_edit->time())); + edit_recording->setEndMatrix(edit_endmatrix_spin->value()); + edit_recording->setEndLine(edit_endline_spin->value()); + break; + } +} + + +bool EditRecording::CheckEvent(bool include_myself) +{ + char station[65]; + char gunk[3]; + int chan; + QTime start; + QTime finish; + QTime begin; + QTime end; + RDMatrix *matrix; + + // + // Record Cut + // + if(edit_cutname.isEmpty()) { + QMessageBox::warning(this,tr("Missing Cut"), + tr("You must assign a record cut!")); + return false; + } + + // + // Ensure that the time values are sane + // + switch((RDRecording::StartType)edit_starttype_group->selectedId()) { + case RDRecording::GpiStart: + if(edit_start_startwindow_edit->time()>= + edit_start_endwindow_edit->time()) { + QMessageBox::warning(this,tr("Record Parameter Error"), + tr("The start GPI window cannot end before it begins!")); + return false; + } + switch((RDRecording::EndType)edit_endtype_group->selectedId()) { + case RDRecording::HardEnd: + if(edit_start_startwindow_edit->time()>= + edit_endtime_edit->time()) { + QMessageBox::warning(this,tr("Record Parameter Error"), + tr("The recording cannot end before it begins!")); + return false; + } + break; + + case RDRecording::GpiEnd: + if(edit_start_startwindow_edit->time()> + edit_end_startwindow_edit->time()) { + QMessageBox::warning(this,tr("Record Parameter Error"), + tr("The end GPI window cannot end before it begins!")); + return false; + } + break; + + case RDRecording::LengthEnd: + break; + } + break; + + case RDRecording::HardStart: + switch((RDRecording::EndType)edit_endtype_group->selectedId()) { + case RDRecording::HardEnd: + if(edit_starttime_edit->time()>= + edit_endtime_edit->time()) { + QMessageBox::warning(this,tr("Record Parameter Error"), + tr("The recording cannot end before it begins!")); + return false; + } + break; + + case RDRecording::GpiEnd: + if(edit_starttime_edit->time()>= + edit_end_startwindow_edit->time()) { + QMessageBox::warning(this,tr("Record Parameter Error"), + tr("The end GPI window cannot end before it begins!")); + return false; + } + break; + + case RDRecording::LengthEnd: + break; + } + break; + } + switch((RDRecording::EndType)edit_endtype_group->selectedId()) { + case RDRecording::GpiEnd: + if(edit_end_startwindow_edit->time()>= + edit_end_endwindow_edit->time()) { + QMessageBox::warning(this,tr("Record Parameter Error"), + tr("The end GPI window cannot end before it begins!")); + return false; + } + break; + + default: + break; + } + + // + // Verify that the GPI values are valid + // + sscanf((const char *)edit_station_box->currentText(),"%s%s%d", + station,gunk,&chan); + switch((RDRecording::StartType)edit_starttype_group->selectedId()) { + case RDRecording::GpiStart: + matrix=new RDMatrix(station,edit_startmatrix_spin->value()); + if(!matrix->exists()) { + QMessageBox::warning(this,tr("Record Parameter Error"), + tr("The start GPI matrix doesn't exist!")); + delete matrix; + return false; + } + if(matrix->gpis()value()) { + QMessageBox::warning(this,tr("Record Parameter Error"), + tr("The start GPI line doesn't exist!")); + delete matrix; + return false; + } + delete matrix; + edit_starttime_edit->setTime(edit_start_startwindow_edit->time()); + break; + + default: + break; + } + switch((RDRecording::EndType)edit_endtype_group->selectedId()) { + case RDRecording::GpiEnd: + matrix=new RDMatrix(station,edit_endmatrix_spin->value()); + if(!matrix->exists()) { + QMessageBox::warning(this,tr("Record Parameter Error"), + tr("The end GPI matrix doesn't exist!")); + delete matrix; + return false; + } + if(matrix->gpis()value()) { + QMessageBox::warning(this,tr("Record Parameter Error"), + tr("The end GPI line doesn't exist!")); + delete matrix; + return false; + } + delete matrix; + break; + + default: + break; + } + + QString sql= + QString().sprintf("select ID from RECORDINGS \ + where (STATION_NAME=\"%s\")&&\ + (TYPE=%d)&&(START_TIME=\"%s\")&&\ + (CHANNEL=%d)", + station,RDRecording::Recording, + (const char *)edit_starttime_edit->time(). + toString("hh:mm:ss"),chan); + switch((RDRecording::StartType)edit_starttype_group->selectedId()) { + case RDRecording::HardStart: + break; + + case RDRecording::GpiStart: + sql+=QString().sprintf("&&(START_MATRIX=%d)&&(START_LINE=%d)", + edit_startmatrix_spin->value(), + edit_startline_spin->value()); + break; + } + if(edit_sun_button->isChecked()) { + sql+="&&(SUN=\"Y\")"; + } + if(edit_mon_button->isChecked()) { + sql+="&&(MON=\"Y\")"; + } + if(edit_tue_button->isChecked()) { + sql+="&&(TUE=\"Y\")"; + } + if(edit_wed_button->isChecked()) { + sql+="&&(WED=\"Y\")"; + } + if(edit_thu_button->isChecked()) { + sql+="&&(THU=\"Y\")"; + } + if(edit_fri_button->isChecked()) { + sql+="&&(FRI=\"Y\")"; + } + if(edit_sat_button->isChecked()) { + sql+="&&(SAT=\"Y\")"; + } + if(!include_myself) { + sql+=QString().sprintf("&&(ID!=%d)",edit_recording->id()); + } + RDSqlQuery *q=new RDSqlQuery(sql); + bool res=!q->first(); + delete q; + if(!res) { + QMessageBox::warning(this,tr("Duplicate Event"), + tr("An event with these parameters already exists!")); + } + + return res; +} + + +QString EditRecording::GetSourceName(int input) +{ + if(edit_deck==NULL) { + return QString("[unknown]"); + } + QString input_name; + QString sql=QString().sprintf("select NAME from INPUTS where \ + (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&(NUMBER=%d)", + (const char *)edit_deck->switchStation(), + edit_deck->switchMatrix(),input); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + input_name=q->value(0).toString(); + } + delete q; + return input_name; +} + + +int EditRecording::GetSource() +{ + int source=-1; + + QString sql=QString().sprintf("select NUMBER from INPUTS where \ + (STATION_NAME=\"%s\")&&(MATRIX=%d)&&\ + (NAME=\"%s\")", + (const char *)edit_deck->switchStation(), + edit_deck->switchMatrix(), + (const char *)edit_source_box->currentText()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + source=q->value(0).toInt(); + } + delete q; + return source; +} diff --git a/rdcatch/edit_recording.h b/rdcatch/edit_recording.h new file mode 100644 index 00000000..e156c94c --- /dev/null +++ b/rdcatch/edit_recording.h @@ -0,0 +1,137 @@ +// edit_recording.h +// +// Edit a Rivendell Netcatch Recording +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: edit_recording.h,v 1.22 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_RECORDING_H +#define EDIT_RECORDING_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class EditRecording : public QDialog +{ + Q_OBJECT + public: + EditRecording(int id,std::vector *adds,QString *filter, + QWidget *parent=0,const char *name=0); + ~EditRecording(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void activateStationData(int,bool use_temp=true); + void startTypeClickedData(int id); + void endTypeClickedData(int id); + void selectCutData(); + void autotrimToggledData(bool state); + void normalizeToggledData(bool state); + void saveasData(); + void okData(); + void cancelData(); + + protected: + void paintEvent(QPaintEvent *e); + void keyPressEvent(QKeyEvent *); + void closeEvent(QCloseEvent *e); + + private: + void PopulateDecks(QComboBox *box); + void Save(); + bool CheckEvent(bool include_myself); + QString GetSourceName(int input); + int GetSource(); + RDDeck *edit_deck; + RDRecording *edit_recording; + QCheckBox *edit_active_button; + QComboBox *edit_station_box; + QLineEdit *edit_description_edit; + QString edit_cutname; + QLineEdit *edit_destination_edit; + QCheckBox *edit_sun_button; + QCheckBox *edit_mon_button; + QCheckBox *edit_tue_button; + QCheckBox *edit_wed_button; + QCheckBox *edit_thu_button; + QCheckBox *edit_fri_button; + QCheckBox *edit_sat_button; + QComboBox *edit_source_box; + QSpinBox *edit_startoffset_box; + QSpinBox *edit_endoffset_box; + QCheckBox *edit_oneshot_box; + QButtonGroup *edit_starttype_group; + QLabel *edit_starttime_label; + QButtonGroup *edit_endtype_group; + QLabel *edit_endtime_label; + QLabel *edit_endlength_label; + QTimeEdit *edit_starttime_edit; + QTimeEdit *edit_endtime_edit; + QTimeEdit *edit_endlength_edit; + QLabel *edit_start_startwindow_label; + QTimeEdit *edit_start_startwindow_edit; + QLabel *edit_start_endwindow_label; + QTimeEdit *edit_start_endwindow_edit; + QLabel *edit_end_startwindow_label; + QCheckBox *edit_multirec_box; + QLabel *edit_maxlength_label; + QTimeEdit *edit_maxlength_edit; + QTimeEdit *edit_end_startwindow_edit; + QLabel *edit_end_endwindow_label; + QTimeEdit *edit_end_endwindow_edit; + QLabel *edit_startmatrix_label; + QSpinBox *edit_startmatrix_spin; + QLabel *edit_startline_label; + QSpinBox *edit_startline_spin; + QLabel *edit_endmatrix_label; + QSpinBox *edit_endmatrix_spin; + QLabel *edit_endline_label; + QSpinBox *edit_endline_spin; + QLabel *edit_startlength_label; + QTimeEdit *edit_startlength_edit; + QLabel *edit_startoffset_label; + QTimeEdit *edit_startoffset_edit; + std::vector *edit_added_events; + QComboBox *edit_channels_box; + QCheckBox *edit_autotrim_box; + QLabel *edit_autotrim_label; + QSpinBox *edit_autotrim_spin; + QLabel *edit_autotrim_unit; + QCheckBox *edit_normalize_box; + QLabel *edit_normalize_label; + QSpinBox *edit_normalize_spin; + QLabel *edit_normalize_unit; + QString *edit_filter; +}; + + +#endif + diff --git a/rdcatch/edit_switchevent.cpp b/rdcatch/edit_switchevent.cpp new file mode 100644 index 00000000..78f88ff9 --- /dev/null +++ b/rdcatch/edit_switchevent.cpp @@ -0,0 +1,653 @@ +// edit_switchevent.cpp +// +// Edit a Rivendell Netcatch Cart Event +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_switchevent.cpp,v 1.24 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +EditSwitchEvent::EditSwitchEvent(int id,std::vector *adds, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + QString temp; + edit_matrix=NULL; + edit_added_events=adds; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont day_font=QFont("Helvetica",10,QFont::Normal); + day_font.setPixelSize(10); + + edit_deck=NULL; + + setCaption(tr("Edit Switcher Event")); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // The Recording Record + // + edit_recording=new RDRecording(id); + + // + // Active Button + // + edit_active_button=new QCheckBox(this,"edit_active_button"); + edit_active_button->setGeometry(10,11,20,20); + QLabel *label=new QLabel(edit_active_button, + tr("Event Active"),this,"edit_active_label"); + label->setGeometry(30,11,125,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Station + // + edit_station_box=new QComboBox(this,"edit_station_box"); + edit_station_box->setGeometry(200,10,140,23); + label=new QLabel(edit_station_box,tr("Location:"),this, + "edit_station_label"); + label->setGeometry(125,10,70,23); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Start Time + // + edit_starttime_edit=new QTimeEdit(this,"edit_starttime_edit"); + edit_starttime_edit->setGeometry(sizeHint().width()-90,12,80,20); + label=new QLabel(edit_starttime_edit, + tr("Start Time:"),this,"edit_starttime_label"); + label->setGeometry(sizeHint().width()-175,12,80,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Description + // + edit_description_edit=new QLineEdit(this,"edit_description_edit"); + edit_description_edit->setGeometry(120,43,sizeHint().width()-130,20); + edit_description_edit->setValidator(validator); + label=new QLabel(edit_description_edit, + tr("Description:"),this,"edit_description_label"); + label->setGeometry(10,43,105,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Switch Matrix + // + edit_matrix_box=new QComboBox(this,"edit_matrix_box"); + edit_matrix_box->setGeometry(120,70,sizeHint().width()-130,20); + label=new QLabel(edit_matrix_box,tr("Switch Matrix:"), + this,"edit_matrix_label"); + label->setGeometry(10,70,105,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(edit_matrix_box,SIGNAL(activated(const QString &)), + this,SLOT(activateMatrixData(const QString &))); + + // + // Switch Input + // + edit_input_box=new QComboBox(this,"edit_input_box"); + edit_input_box->setGeometry(120,100,sizeHint().width()-130,20); + label=new QLabel(edit_input_box,tr("Switch Input:"), + this,"edit_input_label"); + label->setGeometry(10,100,105,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + edit_input_spin=new QSpinBox(this,"edit_input_spin"); + edit_input_spin->setGeometry(140,125,50,20); + connect(edit_input_box,SIGNAL(activated(const QString &)), + this,SLOT(activateInputData(const QString &))); + + // + // Switch Output + // + edit_output_box=new QComboBox(this,"edit_output_box"); + edit_output_box->setGeometry(120,155,sizeHint().width()-130,20); + label=new QLabel(edit_output_box,tr("Switch Output:"), + this,"edit_output_label"); + label->setGeometry(10,155,105,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + edit_output_spin=new QSpinBox(this,"edit_input_spin"); + edit_output_spin->setGeometry(140,180,50,20); + connect(edit_output_box,SIGNAL(activated(const QString &)), + this,SLOT(activateOutputData(const QString &))); + + // + // Button Label + // + label=new QLabel(tr("Active Days"),this,"active_days_label"); + label->setGeometry(47,210,80,19); + label->setFont(label_font); + label->setAlignment(AlignHCenter|ShowPrefix); + + // + // Monday Button + // + edit_mon_button=new QCheckBox(this,"edit_mon_button"); + edit_mon_button->setGeometry(20,228,20,20); + label=new QLabel(edit_mon_button, + tr("Monday"),this,"edit_mon_label"); + label->setGeometry(40,228,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Tuesday Button + // + edit_tue_button=new QCheckBox(this,"edit_tue_button"); + edit_tue_button->setGeometry(115,228,20,20); + label=new QLabel(edit_tue_button, + tr("Tuesday"),this,"edit_tue_label"); + label->setGeometry(135,228,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Wednesday Button + // + edit_wed_button=new QCheckBox(this,"edit_wed_button"); + edit_wed_button->setGeometry(215,228,20,20); + label=new QLabel(edit_wed_button, + tr("Wednesday"),this,"edit_wed_label"); + label->setGeometry(235,228,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Thursday Button + // + edit_thu_button=new QCheckBox(this,"edit_thu_button"); + edit_thu_button->setGeometry(335,228,20,20); + label=new QLabel(edit_thu_button, + tr("Thursday"),this,"edit_thu_label"); + label->setGeometry(355,228,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Friday Button + // + edit_fri_button=new QCheckBox(this,"edit_fri_button"); + edit_fri_button->setGeometry(440,228,20,20); + label=new QLabel(edit_fri_button, + tr("Friday"),this,"edit_fri_label"); + label->setGeometry(460,228,40,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Saturday Button + // + edit_sat_button=new QCheckBox(this,"edit_sat_button"); + edit_sat_button->setGeometry(130,253,20,20); + label=new QLabel(edit_sat_button, + tr("Saturday"),this,"edit_sat_label"); + label->setGeometry(150,253,60,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Sunday Button + // + edit_sun_button=new QCheckBox(this,"edit_sun_button"); + edit_sun_button->setGeometry(300,253,20,20); + label=new QLabel(edit_sun_button, + tr("Sunday"),this,"edit_sun_label"); + label->setGeometry(320,253,60,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // OneShot Button + // + edit_oneshot_box=new QCheckBox(this,"edit_oneshot_box"); + edit_oneshot_box->setGeometry(20,290,15,15); + label=new QLabel(edit_oneshot_box, + tr("Make OneShot"),this,"edit_oneshot_label"); + label->setGeometry(40,288,115,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Save As Button + // + QPushButton *button=new QPushButton(this,"saveas_button"); + button->setGeometry(sizeHint().width()-300,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Save As\nNew")); + connect(button,SIGNAL(clicked()),this,SLOT(saveasData())); + if(adds==NULL) { + button->hide(); + } + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(button_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + edit_active_button->setChecked(edit_recording->isActive()); + q=new RDSqlQuery("select NAME from STATIONS where NAME!=\"DEFAULT\""); + while(q->next()) { + edit_station_box->insertItem(q->value(0).toString()); + if(edit_recording->station()==q->value(0).toString()) { + edit_station_box->setCurrentItem(edit_station_box->count()-1); + } + } + delete q; + edit_starttime_edit->setTime(edit_recording->startTime()); + edit_description_edit->setText(edit_recording->description()); + edit_mon_button->setChecked(edit_recording->mon()); + edit_tue_button->setChecked(edit_recording->tue()); + edit_wed_button->setChecked(edit_recording->wed()); + edit_thu_button->setChecked(edit_recording->thu()); + edit_fri_button->setChecked(edit_recording->fri()); + edit_sat_button->setChecked(edit_recording->sat()); + edit_sun_button->setChecked(edit_recording->sun()); + edit_oneshot_box->setChecked(edit_recording->oneShot()); + activateStationData(edit_station_box->currentText()); + + // + // Input/Output Spin Box Connections + // (Placed here to avoid a QComboBox::changeItem error) + // + connect(edit_input_spin,SIGNAL(valueChanged(int)), + this,SLOT(inputChangedData(int))); + connect(edit_output_spin,SIGNAL(valueChanged(int)), + this,SLOT(outputChangedData(int))); +} + + +EditSwitchEvent::~EditSwitchEvent() +{ + delete edit_station_box; + if(edit_deck!=NULL) { + delete edit_deck; + } +} + + +QSize EditSwitchEvent::sizeHint() const +{ + return QSize(540,360); +} + + +QSizePolicy EditSwitchEvent::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditSwitchEvent::activateStationData(const QString &str) +{ + QString sql=QString().sprintf("select NAME,MATRIX from MATRICES where \ + (STATION_NAME=\"%s\")&&(INPUTS>0)&&\ + (OUTPUTS>0) order by NAME", + (const char *)str); + edit_matrix_box->clear(); + RDSqlQuery *q=new RDSqlQuery(sql); + int matrix=edit_recording->channel(); + while(q->next()) { + edit_matrix_box->insertItem(q->value(0).toString()); + if(q->value(1).toInt()==matrix) { + edit_matrix_box->setCurrentItem(edit_matrix_box->count()-1); + } + } + delete q; + activateMatrixData(edit_matrix_box->currentText()); +} + + +void EditSwitchEvent::activateMatrixData(const QString &str) +{ + int inputs; + int outputs; + + if(edit_matrix!=NULL) { + delete edit_matrix; + } + edit_matrix=new RDMatrix(edit_station_box->currentText(),GetMatrix()); + QString sql=QString().sprintf("select NAME,NUMBER from INPUTS where \ + (STATION_NAME=\"%s\")&&(MATRIX=%d) \ + order by NAME", + (const char *)edit_station_box->currentText(), + GetMatrix()); + edit_input_box->clear(); + edit_input_box->insertItem(tr("--OFF--")); + int input=edit_recording->switchSource(); + if((inputs=edit_matrix->inputs())>0) { + edit_input_spin->setRange(0,inputs); + edit_input_spin->setEnabled(true); + } + else { + edit_input_spin->setRange(0,0); + edit_input_spin->setDisabled(true); + } + edit_input_spin->setValue(input); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + edit_input_box->insertItem(q->value(0).toString()); + if(q->value(1).toInt()==input) { + edit_input_box->setCurrentItem(edit_input_box->count()-1); + } + } + delete q; + + sql=QString().sprintf("select NAME,NUMBER from OUTPUTS where \ + (STATION_NAME=\"%s\")&&(MATRIX=%d) \ + order by NAME", + (const char *)edit_station_box->currentText(), + GetMatrix()); + edit_output_box->clear(); + int output=edit_recording->switchDestination(); + if((outputs=edit_matrix->outputs())>0) { + edit_output_spin->setRange(1,outputs); + edit_output_spin->setEnabled(true); + } + else { + edit_output_spin->setRange(0,0); + edit_output_spin->setDisabled(true); + } + edit_output_spin->setValue(output); + q=new RDSqlQuery(sql); + while(q->next()) { + edit_output_box->insertItem(q->value(0).toString()); + if(q->value(1).toInt()==output) { + edit_output_box->setCurrentItem(edit_output_box->count()-1); + } + } + delete q; +} + + +void EditSwitchEvent::activateInputData(const QString &str) +{ + edit_input_spin->setValue(GetSource()); +} + + +void EditSwitchEvent::activateOutputData(const QString &str) +{ + edit_output_spin->setValue(GetDestination()); +} + + +void EditSwitchEvent::inputChangedData(int value) +{ + if(value>0) { + edit_input_box->setCurrentText(edit_matrix->inputName(value)); + } + else { + edit_input_box->setCurrentText(tr("--OFF--")); + } +} + + +void EditSwitchEvent::outputChangedData(int value) +{ + if(value>0) { + edit_output_box->setCurrentText(edit_matrix->outputName(value)); + } +} + + +void EditSwitchEvent::saveasData() +{ + if(!CheckEvent(true)) { + QMessageBox::warning(this,tr("Duplicate Event"), + tr("An event with these parameters already exists!")); + return; + } + delete edit_recording; + edit_recording=new RDRecording(-1,true); + edit_added_events->push_back(edit_recording->id()); + Save(); +} + + +void EditSwitchEvent::okData() +{ + if(!CheckEvent(false)) { + QMessageBox::warning(this,tr("Duplicate Event"), + tr("An event with these parameters already exists!")); + return; + } + Save(); + done(0); +} + + +void EditSwitchEvent::cancelData() +{ + done(-1); +} + + +void EditSwitchEvent::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->drawRect(10,218,sizeHint().width()-20,62); + p->end(); +} + + +void EditSwitchEvent::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Escape: + e->accept(); + cancelData(); + break; + + default: + QDialog::keyPressEvent(e); + break; + } +} + + +void EditSwitchEvent::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void EditSwitchEvent::Save() +{ + int matrix=GetMatrix(); + int source=GetSource(); + int dest=GetDestination(); + + edit_recording->setIsActive(edit_active_button->isChecked()); + edit_recording->setStation(edit_station_box->currentText()); + edit_recording->setType(RDRecording::SwitchEvent); + edit_recording->setStartTime(edit_starttime_edit->time()); + edit_recording->setDescription(edit_description_edit->text()); + edit_recording->setChannel(matrix); + edit_recording->setSwitchSource(source); + edit_recording->setSwitchDestination(dest); + edit_recording->setMon(edit_mon_button->isChecked()); + edit_recording->setTue(edit_tue_button->isChecked()); + edit_recording->setWed(edit_wed_button->isChecked()); + edit_recording->setThu(edit_thu_button->isChecked()); + edit_recording->setFri(edit_fri_button->isChecked()); + edit_recording->setSat(edit_sat_button->isChecked()); + edit_recording->setSun(edit_sun_button->isChecked()); + edit_recording->setOneShot(edit_oneshot_box->isChecked()); +} + + +int EditSwitchEvent::GetMatrix() +{ + int matrix=-1; + + QString sql=QString().sprintf("select MATRIX from MATRICES where \ + (STATION_NAME=\"%s\")&&(NAME=\"%s\")&&\ + (INPUTS>0)&&(OUTPUTS>0)", + (const char *)edit_station_box->currentText(), + (const char *)edit_matrix_box->currentText()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + matrix=q->value(0).toInt(); + } + delete q; + return matrix; +} + + +int EditSwitchEvent::GetSource() +{ + int input=0; + + QString sql=QString().sprintf("select NUMBER from INPUTS where \ + (STATION_NAME=\"%s\")&&(MATRIX=%d)&&\ + (NAME=\"%s\")", + (const char *)edit_station_box->currentText(), + GetMatrix(), + (const char *)edit_input_box->currentText()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + input=q->value(0).toInt(); + } + delete q; + return input; +} + + +int EditSwitchEvent::GetDestination() +{ + int output=-1; + + QString sql=QString().sprintf("select NUMBER from OUTPUTS where \ + (STATION_NAME=\"%s\")&&(MATRIX=%d)&&\ + (NAME=\"%s\")", + (const char *)edit_station_box->currentText(), + GetMatrix(), + (const char *)edit_output_box->currentText()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + output=q->value(0).toInt(); + } + delete q; + return output; +} + + +bool EditSwitchEvent::CheckEvent(bool include_myself) +{ + QString sql= + QString().sprintf("select ID from RECORDINGS \ + where (STATION_NAME=\"%s\")&&\ + (TYPE=%d)&&(START_TIME=\"%s\")&&\ + (CHANNEL=%d)&&(SWITCH_INPUT=%d)&&\ + (SWITCH_OUTPUT=%d)", + (const char *)edit_station_box->currentText(), + RDRecording::SwitchEvent, + (const char *)edit_starttime_edit->time(). + toString("hh:mm:ss"),GetMatrix(),GetSource(), + GetDestination()); + if(edit_sun_button->isChecked()) { + sql+="&&(SUN=\"Y\")"; + } + if(edit_mon_button->isChecked()) { + sql+="&&(MON=\"Y\")"; + } + if(edit_tue_button->isChecked()) { + sql+="&&(TUE=\"Y\")"; + } + if(edit_wed_button->isChecked()) { + sql+="&&(WED=\"Y\")"; + } + if(edit_thu_button->isChecked()) { + sql+="&&(THU=\"Y\")"; + } + if(edit_fri_button->isChecked()) { + sql+="&&(FRI=\"Y\")"; + } + if(edit_sat_button->isChecked()) { + sql+="&&(SAT=\"Y\")"; + } + if(!include_myself) { + sql+=QString().sprintf("&&(ID!=%d)",edit_recording->id()); + } + RDSqlQuery *q=new RDSqlQuery(sql); + bool res=!q->first(); + delete q; + + return res; +} diff --git a/rdcatch/edit_switchevent.h b/rdcatch/edit_switchevent.h new file mode 100644 index 00000000..4f923754 --- /dev/null +++ b/rdcatch/edit_switchevent.h @@ -0,0 +1,100 @@ +// edit_switchevent.h +// +// Edit a Rivendell Netcatch Cart Event +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_switchevent.h,v 1.12 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_SWITCHEVENT_H +#define EDIT_SWITCHEVENT_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +class EditSwitchEvent : public QDialog +{ + Q_OBJECT + public: + EditSwitchEvent(int id,std::vector *adds, + QWidget *parent=0,const char *name=0); + ~EditSwitchEvent(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void activateStationData(const QString &str); + void activateMatrixData(const QString &str); + void activateInputData(const QString &str); + void activateOutputData(const QString &str); + void inputChangedData(int value); + void outputChangedData(int value); + void saveasData(); + void okData(); + void cancelData(); + + protected: + void paintEvent(QPaintEvent *e); + void keyPressEvent(QKeyEvent *); + void closeEvent(QCloseEvent *e); + + private: + void Save(); + int GetMatrix(); + int GetSource(); + int GetDestination(); + bool CheckEvent(bool include_myself); + RDMatrix *edit_matrix; + RDDeck *edit_deck; + RDRecording *edit_recording; + QCheckBox *edit_active_button; + QComboBox *edit_station_box; + QTimeEdit *edit_starttime_edit; + QLineEdit *edit_description_edit; + QComboBox *edit_matrix_box; + QComboBox *edit_input_box; + QSpinBox *edit_input_spin; + QComboBox *edit_output_box; + QSpinBox *edit_output_spin; + QCheckBox *edit_sun_button; + QCheckBox *edit_mon_button; + QCheckBox *edit_tue_button; + QCheckBox *edit_wed_button; + QCheckBox *edit_thu_button; + QCheckBox *edit_fri_button; + QCheckBox *edit_sat_button; + QString *edit_filter; + QCheckBox *edit_oneshot_box; + std::vector*edit_added_events; +}; + + +#endif + diff --git a/rdcatch/edit_upload.cpp b/rdcatch/edit_upload.cpp new file mode 100644 index 00000000..820a7336 --- /dev/null +++ b/rdcatch/edit_upload.cpp @@ -0,0 +1,769 @@ +// edit_upload.cpp +// +// Edit a Rivendell Upload Event +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_upload.cpp,v 1.22 2011/06/21 18:31:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +EditUpload::EditUpload(int id,std::vector *adds,QString *filter, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + QString temp; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont day_font=QFont("Helvetica",10,QFont::Normal); + day_font.setPixelSize(10); + + edit_deck=NULL; + edit_added_events=adds; + edit_filter=filter; + + setCaption(tr("Edit Upload")); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // The Recording Record + // + edit_recording=new RDRecording(id); + + // + // Active Button + // + edit_active_button=new QCheckBox(this,"edit_active_button"); + edit_active_button->setGeometry(10,11,20,20); + QLabel *label=new QLabel(edit_active_button, + tr("Event Active"),this,"edit_active_label"); + label->setGeometry(30,11,125,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Station + // + edit_station_box=new QComboBox(this,"edit_station_box"); + edit_station_box->setGeometry(200,10,140,23); + connect(edit_station_box,SIGNAL(textChanged(const QString &)), + this,SLOT(stationChangedData(const QString &))); + label=new QLabel(edit_station_box,tr("Location:"),this, + "edit_station_label"); + label->setGeometry(125,10,70,23); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Start Time + // + edit_starttime_edit=new QTimeEdit(this,"edit_starttime_edit"); + edit_starttime_edit->setGeometry(sizeHint().width()-90,12,80,20); + label=new QLabel(edit_starttime_edit, + tr("Start Time:"),this,"edit_starttime_label"); + label->setGeometry(sizeHint().width()-175,12,80,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // RSS Feed + // + edit_feed_box=new QComboBox(this,"edit_feed_box"); + edit_feed_box->setGeometry(115,43,100,20); + edit_feed_box->insertItem(tr("[none]")); + label=new QLabel(edit_feed_box, + tr("RSS Feed:"),this,"edit_feed_label"); + label->setGeometry(10,43,100,19); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Source + // + edit_destination_edit=new QLineEdit(this,"edit_destination_edit"); + edit_destination_edit->setGeometry(115,70,sizeHint().width()-195,20); + edit_destination_edit->setReadOnly(true); + label=new QLabel(edit_destination_edit, + tr("Source:"),this,"edit_destination_label"); + label->setGeometry(10,70,100,19); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QPushButton *button=new QPushButton(this,"destination_button"); + button->setGeometry(sizeHint().width()-70,68,60,24); + button->setFont(day_font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectCartData())); + + // + // Description + // + edit_description_edit=new QLineEdit(this,"edit_description_edit"); + edit_description_edit->setGeometry(115,97,sizeHint().width()-125,20); + edit_description_edit->setValidator(validator); + label=new QLabel(edit_description_edit, + tr("Description:"),this,"edit_description_label"); + label->setGeometry(10,97,100,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Url + // + edit_url_edit=new QLineEdit(this,"edit_url_edit"); + edit_url_edit->setGeometry(115,124,sizeHint().width()-125,20); + edit_url_edit->setMaxLength(255); + edit_url_edit->setValidator(validator); + connect(edit_url_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(urlChangedData(const QString &))); + label=new QLabel(edit_url_edit,tr("Url:"),this,"edit_url_label"); + label->setGeometry(10,124,100,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Username + // + edit_username_edit=new QLineEdit(this,"edit_username_edit"); + edit_username_edit->setGeometry(115,151,150,20); + edit_username_edit->setMaxLength(64); + edit_username_edit->setValidator(validator); + edit_username_label=new QLabel(edit_username_edit, + tr("Username:"),this,"edit_username_label"); + edit_username_label->setGeometry(10,151,100,20); + edit_username_label->setFont(label_font); + edit_username_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Password + // + edit_password_edit=new QLineEdit(this,"edit_password_edit"); + edit_password_edit->setGeometry(360,151,sizeHint().width()-370,20); + edit_password_edit->setEchoMode(QLineEdit::Password); + edit_password_edit->setMaxLength(64); + edit_username_edit->setValidator(validator); + edit_password_label=new QLabel(edit_password_edit, + tr("Password:"),this,"edit_password_label"); + edit_password_label->setGeometry(275,151,80,20); + edit_password_label->setFont(label_font); + edit_password_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Audio Format + // + edit_format_edit=new QLineEdit(this,"edit_format_edit"); + edit_format_edit->setGeometry(115,178,sizeHint().width()-195,20); + edit_format_edit->setReadOnly(true); + label=new QLabel(edit_format_edit, + tr("Export Format:"),this,"edit_format_label"); + label->setGeometry(5,178,105,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + button=new QPushButton(this,"format_button"); + button->setGeometry(sizeHint().width()-70,176,60,24); + button->setFont(day_font); + button->setText(tr("S&et")); + connect(button,SIGNAL(clicked()),this,SLOT(setFormatData())); + + // + // Normalize Check Box + // + edit_normalize_box=new QCheckBox(this,"edit_normalize_box"); + edit_normalize_box->setGeometry(115,208,15,15); + edit_normalize_box->setChecked(true); + label=new QLabel(edit_normalize_box,tr("Normalize"), + this,"normalize_check_label"); + label->setGeometry(135,206,83,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter); + connect(edit_normalize_box,SIGNAL(toggled(bool)), + this,SLOT(normalizeCheckData(bool))); + + // + // Normalize Level + // + edit_normalize_spin=new QSpinBox(this,"edit_normalize_spin"); + edit_normalize_spin->setGeometry(265,206,40,20); + edit_normalize_spin->setRange(-30,0); + edit_normalize_label=new QLabel(edit_normalize_spin,tr("Level:"), + this,"normalize_spin_label"); + edit_normalize_label->setGeometry(215,206,45,20); + edit_normalize_label->setFont(label_font); + edit_normalize_label->setAlignment(AlignRight|AlignVCenter); + edit_normalize_unit=new QLabel(tr("dBFS"),this,"normalize_unit_label"); + edit_normalize_unit->setGeometry(310,206,40,20); + edit_normalize_unit->setFont(label_font); + edit_normalize_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Export Metadata Box + // + edit_metadata_box=new QCheckBox(this,"edit_metadata_box"); + edit_metadata_box->setGeometry(115,231,15,15); + label=new QLabel(edit_metadata_box,tr("Export Library Metadata"), + this,"metadata_check_label"); + label->setGeometry(135,231,160,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Button Label + // + label=new QLabel(tr("Active Days"),this,"active_days_label"); + label->setGeometry(47,263,90,19); + label->setFont(label_font); + label->setAlignment(AlignHCenter|ShowPrefix); + + // + // Monday Button + // + edit_mon_button=new QCheckBox(this,"edit_mon_button"); + edit_mon_button->setGeometry(20,282,20,20); + label=new QLabel(edit_mon_button, + tr("Monday"),this,"edit_mon_label"); + label->setGeometry(40,282,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Tuesday Button + // + edit_tue_button=new QCheckBox(this,"edit_tue_button"); + edit_tue_button->setGeometry(115,282,20,20); + label=new QLabel(edit_tue_button, + tr("Tuesday"),this,"edit_tue_label"); + label->setGeometry(135,282,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Wednesday Button + // + edit_wed_button=new QCheckBox(this,"edit_wed_button"); + edit_wed_button->setGeometry(215,282,20,20); + label=new QLabel(edit_wed_button, + tr("Wednesday"),this,"edit_wed_label"); + label->setGeometry(235,282,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Thursday Button + // + edit_thu_button=new QCheckBox(this,"edit_thu_button"); + edit_thu_button->setGeometry(335,282,20,20); + label=new QLabel(edit_thu_button, + tr("Thursday"),this,"edit_thu_label"); + label->setGeometry(355,282,115,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Friday Button + // + edit_fri_button=new QCheckBox(this,"edit_fri_button"); + edit_fri_button->setGeometry(440,282,20,20); + label=new QLabel(edit_fri_button, + tr("Friday"),this,"edit_fri_label"); + label->setGeometry(460,282,40,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Saturday Button + // + edit_sat_button=new QCheckBox(this,"edit_sat_button"); + edit_sat_button->setGeometry(130,307,20,20); + label=new QLabel(edit_sat_button, + tr("Saturday"),this,"edit_sat_label"); + label->setGeometry(150,307,60,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Sunday Button + // + edit_sun_button=new QCheckBox(this,"edit_sun_button"); + edit_sun_button->setGeometry(300,307,20,20); + label=new QLabel(edit_sun_button, + tr("Sunday"),this,"edit_sun_label"); + label->setGeometry(320,307,60,20); + label->setFont(day_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // OneShot Button + // + edit_oneshot_box=new QCheckBox(this,"edit_oneshot_box"); + edit_oneshot_box->setGeometry(20,342,15,15); + label=new QLabel(edit_oneshot_box, + tr("Make OneShot"),this,"edit_oneshot_label"); + label->setGeometry(40,343,115,20); + label->setFont(label_font); + label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Event Offset + // + edit_eventoffset_spin=new QSpinBox(this,"edit_eventoffset_spin"); + edit_eventoffset_spin->setGeometry(245,340,45,20); + edit_eventoffset_spin->setRange(-30,30); + label=new QLabel(edit_eventoffset_spin,tr("Event Offset:"), + this,"edit_eventoffset_label"); + label->setGeometry(140,340,100,20); + label->setFont(label_font); + label->setAlignment(AlignVCenter|AlignRight); + label=new QLabel(edit_eventoffset_spin,tr("days"), + this,"edit_eventoffset_unit"); + label->setGeometry(295,335,40,20); + label->setFont(label_font); + label->setAlignment(AlignVCenter|AlignLeft); + + // + // Save As Button + // + button=new QPushButton(this,"saveas_button"); + button->setGeometry(sizeHint().width()-300,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Save As\nNew")); + connect(button,SIGNAL(clicked()),this,SLOT(saveasData())); + if(adds==NULL) { + button->hide(); + } + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(button_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + q=new RDSqlQuery("select NAME from STATIONS where NAME!=\"DEFAULT\""); + while(q->next()) { + edit_station_box->insertItem(q->value(0).toString()); + if(edit_recording->station()==q->value(0).toString()) { + edit_station_box->setCurrentItem(edit_station_box->count()-1); + } + } + delete q; + edit_active_button->setChecked(edit_recording->isActive()); + edit_starttime_edit->setTime(edit_recording->startTime()); + edit_description_edit->setText(edit_recording->description()); + edit_url_edit->setText(edit_recording->url()); + edit_username_edit->setText(edit_recording->urlUsername()); + edit_password_edit->setText(edit_recording->urlPassword()); + if(!edit_recording->cutName().isEmpty()) { + edit_destination_edit->setText("Cut "+edit_recording->cutName()); + } + edit_metadata_box->setChecked(edit_recording->enableMetadata()); + edit_mon_button->setChecked(edit_recording->mon()); + edit_tue_button->setChecked(edit_recording->tue()); + edit_wed_button->setChecked(edit_recording->wed()); + edit_thu_button->setChecked(edit_recording->thu()); + edit_fri_button->setChecked(edit_recording->fri()); + edit_sat_button->setChecked(edit_recording->sat()); + edit_sun_button->setChecked(edit_recording->sun()); + edit_eventoffset_spin->setValue(edit_recording->eventdateOffset()); + edit_oneshot_box->setChecked(edit_recording->oneShot()); + edit_settings.setFormat(edit_recording->format()); + edit_settings.setChannels(edit_recording->channels()); + edit_settings.setSampleRate(edit_recording->sampleRate()); + edit_settings.setBitRate(edit_recording->bitrate()); + edit_settings.setQuality(edit_recording->quality()); + edit_format_edit->setText(edit_settings.description()); + if(edit_recording->normalizationLevel()>0) { + edit_normalize_box->setChecked(false); + } + else { + edit_normalize_box->setChecked(true); + edit_normalize_spin->setValue(edit_recording->normalizationLevel()/100); + } + normalizeCheckData(edit_normalize_box->isChecked()); + int feed_id=edit_recording->feedId(); + sql="select ID,KEY_NAME from FEEDS order by KEY_NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + edit_feed_box->insertItem(q->value(1).toString()); + if(q->value(0).toInt()==feed_id) { + edit_feed_box->setCurrentItem(edit_feed_box->count()-1); + } + } + delete q; +} + + +EditUpload::~EditUpload() +{ + delete edit_station_box; + if(edit_deck!=NULL) { + delete edit_deck; + } +} + + +QSize EditUpload::sizeHint() const +{ + return QSize(520,441); +} + + +QSizePolicy EditUpload::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditUpload::stationChangedData(const QString &str) +{ + if(!CheckFormat()) { + QMessageBox::warning(this,tr("Unsupported Format"), + tr("The currently selected export format is unsupported on this host!")); + } +} + + +void EditUpload::urlChangedData(const QString &str) +{ + QUrl url(str); + QString protocol=url.protocol().lower(); + if((protocol=="ftp")||(protocol=="file")) { + edit_username_label->setEnabled(true); + edit_username_edit->setEnabled(true); + edit_password_label->setEnabled(true); + edit_password_edit->setEnabled(true); + } + else { + edit_username_label->setDisabled(true); + edit_username_edit->setDisabled(true); + edit_password_label->setDisabled(true); + edit_password_edit->setDisabled(true); + } +} + + +void EditUpload::selectCartData() +{ + QString str; + + RDCutDialog *cut=new RDCutDialog(&edit_cutname,rdstation_conf,catch_system, + edit_filter); + switch(cut->exec()) { + case 0: + edit_description_edit->setText(RDCutPath(edit_cutname)); + str=QString(tr("Cut")); + edit_destination_edit-> + setText(QString().sprintf("%s %s",(const char *)str, + (const char *)edit_cutname)); + break; + } + delete cut; +} + + +void EditUpload::setFormatData() +{ + RDStation *station=new RDStation(edit_station_box->currentText()); + RDExportSettingsDialog *dialog= + new RDExportSettingsDialog(&edit_settings,station,this,"dialog"); + dialog->exec(); + delete dialog; + delete station; + edit_format_edit->setText(edit_settings.description()); +} + + +void EditUpload::normalizeCheckData(bool state) +{ + edit_normalize_label->setEnabled(state); + edit_normalize_spin->setEnabled(state); + edit_normalize_unit->setEnabled(state); +} + + +void EditUpload::saveasData() +{ + if(!CheckEvent(true)) { + QMessageBox::warning(this,tr("Duplicate Event"), + tr("An event with these parameters already exists!")); + return; + } + delete edit_recording; + edit_recording=new RDRecording(-1,true); + edit_added_events->push_back(edit_recording->id()); + Save(); +} + + +void EditUpload::okData() +{ + if(!CheckFormat()) { + QMessageBox::warning(this,tr("Unsupported Format"), + tr("The currently selected export format is unsupported on host ")+edit_station_box->currentText()+"!"); + return; + } + if(QUrl::isRelativeUrl(edit_url_edit->text())|| + (edit_url_edit->text().right(1)=="/")) { + QMessageBox::warning(this,tr("Invalid URL"),tr("The URL is invalid!")); + return; + } + RDUrl url(edit_url_edit->text()); + QString protocol=url.protocol(); + if((protocol!="ftp")&&(protocol!="file")) { + QMessageBox::warning(this, + tr("Invalid URL"),tr("Unsupported URL protocol!")); + return; + } + if((protocol=="file")&&(edit_username_edit->text().isEmpty())) { + QMessageBox::warning(this,tr("Missing Username"), + tr("You must specify a username!")); + return; + } + if(!CheckEvent(false)) { + QMessageBox::warning(this,tr("Duplicate Event"), + tr("An event with these parameters already exists!")); + return; + } + Save(); + done(0); +} + + +void EditUpload::cancelData() +{ + done(-1); +} + + +void EditUpload::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->drawRect(10,271,sizeHint().width()-20,62); + p->end(); +} + + +void EditUpload::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Escape: + e->accept(); + cancelData(); + break; + + default: + QDialog::keyPressEvent(e); + break; + } +} + + +void EditUpload::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +bool EditUpload::CheckFormat() +{ + bool res=false; + + RDStation *station=new RDStation(edit_station_box->currentText()); + switch(edit_settings.format()) { + case RDSettings::Pcm16: + case RDSettings::MpegL2: + case RDSettings::MpegL2Wav: + res=true; + break; + + case RDSettings::MpegL1: + res=false; + break; + + case RDSettings::MpegL3: + if(station->haveCapability(RDStation::HaveLame)) { + res=true; + } + break; + + case RDSettings::Flac: + if(station->haveCapability(RDStation::HaveFlac)) { + res=true; + } + break; + + case RDSettings::OggVorbis: + if(station->haveCapability(RDStation::HaveOggenc)) { + res=true; + } + break; + } + delete station; + + QString sql; + RDSqlQuery *q; + sql=QString().sprintf("select STATION_NAME from ENCODERS \ + where (NAME=\"%s\")&&(STATION_NAME=\"%s\")", + (const char *)RDEscapeString(edit_settings. + formatName()), + (const char *)RDEscapeString(edit_station_box-> + currentText())); + q=new RDSqlQuery(sql); + if(q->first()) { + res=true; + } + delete q; + + return res; +} + + +void EditUpload::Save() +{ + edit_recording->setIsActive(edit_active_button->isChecked()); + edit_recording->setStation(edit_station_box->currentText()); + edit_recording->setType(RDRecording::Upload); + edit_recording->setStartTime(edit_starttime_edit->time()); + edit_recording->setDescription(edit_description_edit->text()); + edit_recording->setCutName(edit_destination_edit->text().right(10)); + edit_recording->setUrl(edit_url_edit->text()); + edit_recording->setUrlUsername(edit_username_edit->text()); + edit_recording->setUrlPassword(edit_password_edit->text()); + edit_recording->setEnableMetadata(edit_metadata_box->isChecked()); + edit_recording->setMon(edit_mon_button->isChecked()); + edit_recording->setTue(edit_tue_button->isChecked()); + edit_recording->setWed(edit_wed_button->isChecked()); + edit_recording->setThu(edit_thu_button->isChecked()); + edit_recording->setFri(edit_fri_button->isChecked()); + edit_recording->setSat(edit_sat_button->isChecked()); + edit_recording->setSun(edit_sun_button->isChecked()); + edit_recording->setEventdateOffset(edit_eventoffset_spin->value()); + edit_recording->setOneShot(edit_oneshot_box->isChecked()); + edit_recording->setFormat(edit_settings.format()); + edit_recording->setChannels(edit_settings.channels()); + edit_recording->setSampleRate(edit_settings.sampleRate()); + edit_recording->setBitrate(edit_settings.bitRate()); + edit_recording->setQuality(edit_settings.quality()); + if(edit_normalize_box->isChecked()) { + edit_recording->setNormalizationLevel(edit_normalize_spin->value()*100); + } + else { + edit_recording->setNormalizationLevel(1); + } + edit_recording->setFeedId(edit_feed_box->currentText()); +} + + +bool EditUpload::CheckEvent(bool include_myself) +{ + QString sql= + QString().sprintf("select ID from RECORDINGS \ + where (STATION_NAME=\"%s\")&&\ + (TYPE=%d)&&(START_TIME=\"%s\")&&\ + (URL=\"%s\")&&(CUT_NAME=\"%s\")", + (const char *)edit_station_box->currentText(), + RDRecording::Upload, + (const char *)edit_starttime_edit->time(). + toString("hh:mm:ss"), + (const char *)edit_url_edit->text(), + (const char *)edit_destination_edit->text().right(10)); + if(edit_sun_button->isChecked()) { + sql+="&&(SUN=\"Y\")"; + } + if(edit_mon_button->isChecked()) { + sql+="&&(MON=\"Y\")"; + } + if(edit_tue_button->isChecked()) { + sql+="&&(TUE=\"Y\")"; + } + if(edit_wed_button->isChecked()) { + sql+="&&(WED=\"Y\")"; + } + if(edit_thu_button->isChecked()) { + sql+="&&(THU=\"Y\")"; + } + if(edit_fri_button->isChecked()) { + sql+="&&(FRI=\"Y\")"; + } + if(edit_sat_button->isChecked()) { + sql+="&&(SAT=\"Y\")"; + } + if(!include_myself) { + sql+=QString().sprintf("&&(ID!=%d)",edit_recording->id()); + } + RDSqlQuery *q=new RDSqlQuery(sql); + bool res=!q->first(); + delete q; + + return res; +} + diff --git a/rdcatch/edit_upload.h b/rdcatch/edit_upload.h new file mode 100644 index 00000000..8bc02a88 --- /dev/null +++ b/rdcatch/edit_upload.h @@ -0,0 +1,106 @@ +// edit_upload.h +// +// Edit a Rivendell Upload Event +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_upload.h,v 1.12 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_UPLOAD_H +#define EDIT_UPLOAD_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +class EditUpload : public QDialog +{ + Q_OBJECT + public: + EditUpload(int id,std::vector *adds,QString *filter, + QWidget *parent=0,const char *name=0); + ~EditUpload(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void stationChangedData(const QString &str); + void urlChangedData(const QString &str); + void selectCartData(); + void setFormatData(); + void normalizeCheckData(bool state); + void saveasData(); + void okData(); + void cancelData(); + + protected: + void paintEvent(QPaintEvent *e); + void keyPressEvent(QKeyEvent *); + void closeEvent(QCloseEvent *e); + + private: + void Save(); + bool CheckEvent(bool include_myself); + bool CheckFormat(); + RDDeck *edit_deck; + RDRecording *edit_recording; + RDSettings edit_settings; + QCheckBox *edit_active_button; + QComboBox *edit_station_box; + QTimeEdit *edit_starttime_edit; + QComboBox *edit_feed_box; + QLineEdit *edit_description_edit; + QLineEdit *edit_url_edit; + QLabel *edit_username_label; + QLineEdit *edit_username_edit; + QLabel *edit_password_label; + QLineEdit *edit_password_edit; + QString edit_cutname; + QLineEdit *edit_destination_edit; + QLineEdit *edit_format_edit; + QCheckBox *edit_normalize_box; + QLabel *edit_normalize_label; + QSpinBox *edit_normalize_spin; + QLabel *edit_normalize_unit; + QCheckBox *edit_metadata_box; + QCheckBox *edit_sun_button; + QCheckBox *edit_mon_button; + QCheckBox *edit_tue_button; + QCheckBox *edit_wed_button; + QCheckBox *edit_thu_button; + QCheckBox *edit_fri_button; + QCheckBox *edit_sat_button; + QSpinBox *edit_eventoffset_spin; + QCheckBox *edit_oneshot_box; + std::vector *edit_added_events; + QString *edit_filter; +}; + + +#endif diff --git a/rdcatch/globals.h b/rdcatch/globals.h new file mode 100644 index 00000000..2ca2c1c7 --- /dev/null +++ b/rdcatch/globals.h @@ -0,0 +1,51 @@ +// globals.h +// +// Global Variable Declarations for RDCatch +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: globals.h,v 1.8 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef GLOBALS_H +#define GLOBALS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Global Resources +// +extern RDConfig *catch_config; +extern RDStation *rdstation_conf; +extern RDAudioPort *rdaudioport_conf; +extern RDUser *catch_user; +extern RDLibraryConf *rdlibrary_conf; +extern RDRipc *catch_ripc; +extern RDCae *catch_cae; +extern RDCartDialog *catch_cart_dialog; +extern int catch_audition_card; +extern int catch_audition_port; +extern RDSystem *catch_system; + +#endif // GLOBALS_H diff --git a/rdcatch/list_reports.cpp b/rdcatch/list_reports.cpp new file mode 100644 index 00000000..93408cdb --- /dev/null +++ b/rdcatch/list_reports.cpp @@ -0,0 +1,584 @@ +// list_reports.cpp +// +// List and Generate RDCatch Reports +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: list_reports.cpp,v 1.8 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +ListReports::ListReports(bool today_only,bool active_only,int dow, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + list_today_only=today_only; + list_active_only=active_only; + list_dow=dow; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("RDLibrary Reports")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Reports List + // + list_reports_box=new QComboBox(this,"list_reports_box"); + list_reports_box->setGeometry(50,10,sizeHint().width()-60,19); + list_reports_box->insertItem(tr("Event Report")); + list_reports_box->insertItem(tr("Upload/Download Report")); + QLabel *list_reports_label= + new QLabel(list_reports_box,tr("Type:"), + this,"list_reports_label"); + list_reports_label->setGeometry(10,10,35,19); + list_reports_label->setFont(font); + list_reports_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Generate Button + // + QPushButton *generate_button=new QPushButton(this,"generate_button"); + generate_button-> + setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + generate_button->setDefault(true); + generate_button->setFont(font); + generate_button->setText(tr("&Generate")); + connect(generate_button,SIGNAL(clicked()),this,SLOT(generateData())); + + // + // Close Button + // + QPushButton *close_button=new QPushButton(this,"close_button"); + close_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + close_button->setFont(font); + close_button->setText(tr("&Close")); + connect(close_button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +ListReports::~ListReports() +{ +} + + +QSize ListReports::sizeHint() const +{ + return QSize(350,110); +} + + +QSizePolicy ListReports::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListReports::generateData() +{ + QString report; + + switch(list_reports_box->currentItem()) { + case 0: // Event Report + GenerateEventReport(&report); + break; + + case 1: // XLoad Report + GenerateXloadReport(&report); + break; + + default: + return; + } + RDTextFile(report); +} + + +void ListReports::closeData() +{ + done(-1); +} + + +void ListReports::GenerateEventReport(QString *report) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + QString str; + bool exists=false; + + // + // Generate Header + // + *report=" Rivendell RDCatch Event Report\n"; + *report+=QString(). + sprintf("Generated: %s\n", + (const char *)QDateTime(QDate::currentDate(),QTime::currentTime()). + toString("MM/dd/yyyy - hh:mm:ss")); + *report+="\n"; + *report+="T -Start-------- -End---------- -Days of Week- -Location----- -Source------------- -Destination-------- -Description-----------------\n"; + + // + // Generate Rows + // + sql="select TYPE,START_TYPE,START_TIME,END_TYPE,END_TIME,LENGTH,SUN,MON,\ + TUE,WED,THU,FRI,SAT,STATION_NAME,CHANNEL,CUT_NAME,URL,MACRO_CART,\ + SWITCH_INPUT,SWITCH_OUTPUT,DESCRIPTION \ + from RECORDINGS order by START_TIME"; + q=new RDSqlQuery(sql); + while(q->next()) { + // + // Event Type + // + switch((RDRecording::Type)q->value(0).toInt()) { + case RDRecording::Recording: + *report+="R"; + exists=RDCut::exists(q->value(15).toString()); + break; + + case RDRecording::MacroEvent: + *report+="M"; + exists=RDCart::exists(q->value(17).toUInt()); + break; + + case RDRecording::SwitchEvent: + *report+="S"; + exists=true; + break; + + case RDRecording::Playout: + *report+="P"; + exists=RDCut::exists(q->value(15).toString()); + break; + + case RDRecording::Download: + *report+="D"; + exists=RDCut::exists(q->value(15).toString()); + break; + + case RDRecording::Upload: + *report+="U"; + exists=RDCut::exists(q->value(15).toString()); + break; + + default: + *report+="?"; + exists=true; + break; + } + if(exists) { + *report+=" "; + } + else { + *report+="*"; + } + + // + // Start Time + // + switch((RDRecording::StartType)q->value(1).toInt()) { + case RDRecording::HardStart: + *report+=QString(). + sprintf("Hard: %-8s ",(const char *)q->value(2).toTime(). + toString("hh:mm:ss")); + break; + + case RDRecording::GpiStart: + *report+=QString(). + sprintf("Gpi: %-8s ",(const char *)q->value(2).toTime(). + toString("hh:mm:ss")); + break; + } + + // + // End Time + // + switch((RDRecording::Type)q->value(0).toInt()) { + case RDRecording::Recording: + switch((RDRecording::EndType)q->value(3).toInt()) { + case RDRecording::HardEnd: + *report+=QString(). + sprintf("Hard: %-8s ",(const char *)q->value(4).toTime(). + toString("hh:mm:ss")); + break; + + case RDRecording::GpiEnd: + *report+=QString(). + sprintf("Gpi: %-8s ",(const char *)q->value(4).toTime(). + toString("hh:mm:ss")); + break; + + case RDRecording::LengthEnd: + *report+=QString().sprintf("Len: %-8s ", + (const char *)RDGetTimeLength(q->value(5).toInt(),false,false)); + break; + } + break; + + default: + *report+=" "; + break; + } + + // + // Days of the Week + // + if(q->value(6).toString()=="Y") { + *report+="Su"; + } + else { + *report+=" "; + } + if(q->value(7).toString()=="Y") { + *report+="Mo"; + } + else { + *report+=" "; + } + if(q->value(8).toString()=="Y") { + *report+="Tu"; + } + else { + *report+=" "; + } + if(q->value(9).toString()=="Y") { + *report+="We"; + } + else { + *report+=" "; + } + if(q->value(10).toString()=="Y") { + *report+="Th"; + } + else { + *report+=" "; + } + if(q->value(11).toString()=="Y") { + *report+="Fr"; + } + else { + *report+=" "; + } + if(q->value(12).toString()=="Y") { + *report+="Sa "; + } + else { + *report+=" "; + } + + // + // Location + // + switch((RDRecording::Type)q->value(0).toInt()) { + case RDRecording::Recording: + str=QString().sprintf("%s:%d", + (const char *)q->value(13).toString().left(12), + q->value(14).toInt()); + break; + + case RDRecording::Playout: + str=QString().sprintf("%s:%d", + (const char *)q->value(13).toString().left(12), + q->value(14).toInt()-128); + break; + + default: + str=q->value(13).toString().left(14); + break; + } + *report+=QString().sprintf("%-14s ",(const char *)str); + + // + // Source and Destination + // + switch((RDRecording::Type)q->value(0).toInt()) { + case RDRecording::Recording: + sql=QString().sprintf("select SWITCH_STATION,SWITCH_MATRIX\ + from DECKS where \ + (STATION_NAME=\"%s\")&&(CHANNEL=%d)", + (const char *)q->value(13).toString(), + q->value(14).toInt()); + q1=new RDSqlQuery(sql); + if(q1->first()) { + *report+=QString().sprintf("%-20s ", + (const char *)GetSourceName(q1->value(0).toString(), + q1->value(1).toInt(), + q->value(18).toInt()).left(20)); + } + else { + *report+=" "; + } + delete q1; + *report+=QString().sprintf("Cut %10s ", + (const char *)q->value(15).toString().left(20)); + break; + + case RDRecording::MacroEvent: + *report+=QString().sprintf("Cart %06u ", + q->value(17).toUInt()); + *report+=" "; + break; + + case RDRecording::SwitchEvent: + *report+=QString().sprintf("%-20s ", + (const char *)GetSourceName(q->value(13).toString(), + q->value(14).toInt(), + q->value(18).toInt()).left(20)); + *report+=QString().sprintf("%-20s ", + (const char *)GetDestinationName(q->value(13).toString(), + q->value(14).toInt(), + q->value(19).toInt()).left(20)); + break; + + case RDRecording::Playout: + *report+=QString().sprintf("Cut %10s ", + (const char *)q->value(15).toString().left(20)); + *report+=" "; + break; + + case RDRecording::Download: + *report+=QString().sprintf("%-20s ", + (const char *)q->value(16).toString().left(20)); + *report+=QString().sprintf("Cut %10s ", + (const char *)q->value(15).toString().left(20)); + break; + + case RDRecording::Upload: + *report+=QString().sprintf("Cut %10s ", + (const char *)q->value(15).toString().left(20)); + *report+=QString().sprintf("%-20s ", + (const char *)q->value(16).toString().left(20)); + break; + } + + // + // Description + // + *report+=QString().sprintf("%s", + (const char *)q->value(20).toString().left(29)); + + // + // End of Line + // + *report+="\n"; + } + delete q; +} + + +void ListReports::GenerateXloadReport(QString *report) +{ + QString sql; + RDSqlQuery *q; + bool exists=false; + + // + // Generate Header + // + *report=" Rivendell RDCatch Upload/Download Report\n"; + *report+=QString(). + sprintf("Generated: %s\n", + (const char *)QDateTime(QDate::currentDate(),QTime::currentTime()). + toString("MM/dd/yyyy - hh:mm:ss")); + *report+="\n"; + *report+="T -Start-- -Days of Week- -Location----- -Cut------- -URL------------------------------------- -Username---- -Description------------\n"; + + // + // Generate Rows + // + sql=QString().sprintf("select TYPE,START_TIME,SUN,MON,TUE,WED,THU,FRI,SAT,\ + STATION_NAME,CUT_NAME,URL,URL_USERNAME,DESCRIPTION \ + from RECORDINGS where (TYPE=%d)||(TYPE=%d) order by START_TIME", + RDRecording::Upload,RDRecording::Download); + q=new RDSqlQuery(sql); + while(q->next()) { + // + // Event Type + // + switch((RDRecording::Type)q->value(0).toInt()) { + case RDRecording::Download: + *report+="D"; + exists=RDCut::exists(q->value(10).toString()); + break; + + case RDRecording::Upload: + *report+="U"; + exists=RDCut::exists(q->value(10).toString()); + break; + + default: + *report+="?"; + exists=true; + break; + } + if(exists) { + *report+=" "; + } + else { + *report+="*"; + } + + // + // Start Time + // + *report+=QString().sprintf("%8s ", + (const char *)q->value(1).toTime().toString("hh:mm:ss")); + + // + // Days of the Week + // + if(q->value(2).toString()=="Y") { + *report+="Su"; + } + else { + *report+=" "; + } + if(q->value(3).toString()=="Y") { + *report+="Mo"; + } + else { + *report+=" "; + } + if(q->value(4).toString()=="Y") { + *report+="Tu"; + } + else { + *report+=" "; + } + if(q->value(5).toString()=="Y") { + *report+="We"; + } + else { + *report+=" "; + } + if(q->value(6).toString()=="Y") { + *report+="Th"; + } + else { + *report+=" "; + } + if(q->value(7).toString()=="Y") { + *report+="Fr"; + } + else { + *report+=" "; + } + if(q->value(8).toString()=="Y") { + *report+="Sa "; + } + else { + *report+=" "; + } + + // + // Location + // + *report+=QString().sprintf("%-14s ", + (const char *)q->value(9).toString().left(14)); + + // + // Cut + // + *report+=QString().sprintf("%11s ",(const char *)q->value(10).toString()); + + // + // URL + // + *report+=QString().sprintf("%-41s ", + (const char *)q->value(11).toString().left(41)); + + // + // URL Username + // + *report+=QString().sprintf("%-13s ", + (const char *)q->value(12).toString().left(13)); + + // + // Description + // + *report+=QString().sprintf("%s", + (const char *)q->value(13).toString().left(24)); + + // + // End of Line + // + *report+="\n"; + } + + delete q; +} + + +QString ListReports::GetSourceName(const QString &station,int matrix,int input) +{ + QString input_name; + QString sql=QString().sprintf("select NAME from INPUTS where \ + (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&(NUMBER=%d)", + (const char *)station, + matrix,input); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + input_name=q->value(0).toString(); + } + delete q; + return input_name; +} + + +QString ListReports::GetDestinationName(const QString &station,int matrix, + int output) +{ + QString output_name; + QString sql=QString().sprintf("select NAME from OUTPUTS where \ + (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&(NUMBER=%d)", + (const char *)station, + matrix,output); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + output_name=q->value(0).toString(); + } + delete q; + return output_name; +} diff --git a/rdcatch/list_reports.h b/rdcatch/list_reports.h new file mode 100644 index 00000000..372bc874 --- /dev/null +++ b/rdcatch/list_reports.h @@ -0,0 +1,59 @@ +// list_reports.h +// +// List and Generate RDCatch Reports +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: list_reports.h,v 1.5 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_REPORTS_H +#define LIST_REPORTS_H + +#include +#include +#include + +#include + + +class ListReports : public QDialog +{ + Q_OBJECT + public: + ListReports(bool active_only,bool today_only,int dow, + QWidget *parent=0,const char *name=0); + ~ListReports(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void generateData(); + void closeData(); + + private: + void GenerateEventReport(QString *report); + void GenerateXloadReport(QString *report); + QString GetSourceName(const QString &station,int matrix,int input); + QString GetDestinationName(const QString &station,int matrix,int output); + QComboBox *list_reports_box; + bool list_active_only; + bool list_today_only; + int list_dow; +}; + + +#endif // LIST_REPORTS_H diff --git a/rdcatch/rdcatch.cpp b/rdcatch/rdcatch.cpp new file mode 100644 index 00000000..1b49023d --- /dev/null +++ b/rdcatch/rdcatch.cpp @@ -0,0 +1,2585 @@ +// rdcatch.cpp +// +// The Event Schedule Manager for Rivendell. +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: rdcatch.cpp,v 1.127.4.8 2014/02/11 23:46:30 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Global Resources +// +RDConfig *catch_config; +RDStation *rdstation_conf; +RDAudioPort *rdaudioport_conf; +RDUser *catch_user; +RDLibraryConf *rdlibrary_conf; +RDRipc *catch_ripc; +RDCae *catch_cae; +RDCartDialog *catch_cart_dialog; +int catch_audition_card=-1; +int catch_audition_port=-1; +RDSystem *catch_system=NULL; + +// +// Icons +// +#include "../icons/record.xpm" +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" +#include "../icons/switch3.xpm" +#include "../icons/download.xpm" +#include "../icons/upload.xpm" +#include "../icons/rivendell-22x22.xpm" + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + QString str; + catch_host_warnings=false; + catch_audition_stream=-1; + bool skip_db_check=false; + unsigned schema=0; + + catch_scroll=false; + + // + // Read Command Options + // + RDCmdSwitch *cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdcatch", + RDCATCH_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--offline-host-warnings") { + catch_host_warnings=RDBool(cmd->value(i)); + } + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + } + delete cmd; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont default_font("Helvetica",12,QFont::Normal); + default_font.setPixelSize(12); + qApp->setFont(default_font); + QFont list_font=QFont("Helvetica",12,QFont::Normal); + list_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",10,QFont::Bold); + label_font.setPixelSize(10); + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont clock_font=QFont("Helvetica",18,QFont::Bold); + clock_font.setPixelSize(18); + + // + // Create Icons + // + catch_record_map=new QPixmap(record_xpm); + catch_playout_map=new QPixmap(play_xpm); + catch_macro_map=new QPixmap(rml5_xpm); + catch_switch_map=new QPixmap(switch3_xpm); + catch_download_map=new QPixmap(download_xpm); + catch_upload_map=new QPixmap(upload_xpm); + catch_rivendell_map=new QPixmap(rivendell_xpm); + setIcon(*catch_rivendell_map); + + + // + // Generate Palettes + // + catch_scroll_color[0]=palette(); + catch_scroll_color[0].setColor(QPalette::Active,QColorGroup::ButtonText, + BUTTON_ACTIVE_TEXT_COLOR); + catch_scroll_color[0].setColor(QPalette::Active,QColorGroup::Button, + BUTTON_ACTIVE_BACKGROUND_COLOR); + catch_scroll_color[0].setColor(QPalette::Active,QColorGroup::Background, + backgroundColor()); + catch_scroll_color[0].setColor(QPalette::Inactive,QColorGroup::ButtonText, + BUTTON_ACTIVE_TEXT_COLOR); + catch_scroll_color[0].setColor(QPalette::Inactive,QColorGroup::Button, + BUTTON_ACTIVE_BACKGROUND_COLOR); + catch_scroll_color[0].setColor(QPalette::Inactive,QColorGroup::Background, + backgroundColor()); + catch_scroll_color[1]=QPalette(backgroundColor(),backgroundColor()); + + // + // Ensure the system daemons are running + // + RDInitializeDaemons(); + + // + // Load Local Configs + // + catch_config=new RDConfig(); + catch_config->load(); + + str=QString("RDCatch")+" v"+VERSION+" - "+tr("Host")+":"; + setCaption(QString().sprintf("%s %s",(const char *)str, + (const char *)catch_config->stationName())); + + // + // Open Database + // + QString err (tr("rdcatch : ")); + catch_db=RDInitDb(&schema,&err); + if(!catch_db) { + log(RDConfig::LogErr,err); + exit(0); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr,"rdcatch: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + + connect(RDDbStatus(),SIGNAL(logText(RDConfig::LogPriority,const QString &)), + this,SLOT(log(RDConfig::LogPriority,const QString &))); + // + // Allocate Global Resources + // + rdstation_conf=new RDStation(catch_config->stationName()); + catch_audition_card=rdstation_conf->cueCard(); + catch_audition_port=rdstation_conf->cuePort(); + catch_time_offset=rdstation_conf->timeOffset(); + catch_system=new RDSystem(); + + // + // Load Audio Settings + // + RDDeck *deck=new RDDeck(catch_config->stationName(),0); + delete deck; + head_playing=false; + tail_playing=false; + rdaudioport_conf=new RDAudioPort(rdstation_conf->name(),catch_audition_card); + + // + // Library Config + // + rdlibrary_conf=new RDLibraryConf(catch_config->stationName(),0); + + // + // RIPC Connection + // + catch_ripc=new RDRipc(catch_config->stationName()); + connect(catch_ripc,SIGNAL(connected(bool)), + this,SLOT(ripcConnectedData(bool))); + catch_user=NULL; + connect(catch_ripc,SIGNAL(userChanged()),this,SLOT(ripcUserData())); + catch_ripc->connectHost("localhost",RIPCD_TCP_PORT,catch_config->password()); + + // + // CAE Connection + // + catch_cae=new RDCae(rdstation_conf,catch_config,this,"catch_cae"); + connect(catch_cae,SIGNAL(isConnected(bool)),this,SLOT(initData(bool))); + connect(catch_cae,SIGNAL(playing(int)),this,SLOT(playedData(int))); + connect(catch_cae,SIGNAL(playStopped(int)), + this,SLOT(playStoppedData(int))); + catch_cae->connectHost(); + + // + // Set Audio Assignments + // + RDSetMixerPorts(rdstation_conf->name(),catch_cae); + + // + // Deck Monitors + // + catch_monitor_view=new QScrollView(this,"catch_monitor_view", + Qt::WNoAutoErase); + catch_monitor_vbox=new VBox(catch_monitor_view); + catch_monitor_vbox->setSpacing(2); + catch_monitor_view->addChild(catch_monitor_vbox); + + QSignalMapper *mapper=new QSignalMapper(this,"deck_mapper"); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(abortData(int))); + QSignalMapper *mon_mapper=new QSignalMapper(this,"monitor_mapper"); + connect(mon_mapper,SIGNAL(mapped(int)),this,SLOT(monitorData(int))); + QString sql; + RDSqlQuery *q1; + RDSqlQuery *q= + new RDSqlQuery("select NAME,IPV4_ADDRESS from STATIONS\ + where NAME!=\"DEFAULT\""); + catch_station_count=0; + while(q->next()) { + catch_connect[catch_station_count].connect= + new RDCatchConnect(catch_station_count,this,"catch_connect"); + catch_connect[catch_station_count].station= + q->value(0).toString().lower(); + connect(catch_connect[catch_station_count].connect, + SIGNAL(statusChanged(int,unsigned,RDDeck::Status,int,const QString &)), + this, + SLOT(statusChangedData(int,unsigned,RDDeck::Status,int,const QString &))); + connect(catch_connect[catch_station_count].connect, + SIGNAL(monitorChanged(int,unsigned,bool)), + this,SLOT(monitorChangedData(int,unsigned,bool))); + connect(catch_connect[catch_station_count].connect, + SIGNAL(connected(int,bool)), + this,SLOT(connectedData(int,bool))); + connect(catch_connect[catch_station_count].connect, + SIGNAL(meterLevel(int,int,int,int)), + this,SLOT(meterLevelData(int,int,int,int))); + connect(catch_connect[catch_station_count].connect, + SIGNAL(eventUpdated(int)), + this,SLOT(eventUpdatedData(int))); + connect(catch_connect[catch_station_count].connect, + SIGNAL(eventPurged(int)), + this,SLOT(eventPurgedData(int))); + connect(catch_connect[catch_station_count].connect, + SIGNAL(heartbeatFailed(int)), + this,SLOT(heartbeatFailedData(int))); + catch_connect[catch_station_count].connect-> + connectHost(q->value(1).toString(),RDCATCHD_TCP_PORT, + catch_config->password()); + catch_station_count++; + + sql=QString().sprintf("select CHANNEL,MON_PORT_NUMBER from DECKS \ +where (CARD_NUMBER!=-1)&&(PORT_NUMBER!=-1)&&(CHANNEL>0)&&(STATION_NAME=\"%s\") \ +order by CHANNEL",(const char *)q->value(0).toString().lower()); + q1=new RDSqlQuery(sql); + while(q1->next()) { + catch_connect[catch_station_count-1]. + chan.push_back(q1->value(0).toUInt()); + catch_connect[catch_station_count-1]. + mon_id.push_back(catch_monitor.size()); + + + catch_monitor.push_back(new CatchMonitor()); + catch_monitor.back()->setDeckMon(new DeckMon(q->value(0).toString(), + q1->value(0).toUInt(), + catch_monitor_vbox)); + catch_monitor.back()->setSerialNumber(catch_station_count-1); + catch_monitor.back()->setChannelNumber(q1->value(0).toUInt()); + catch_monitor_vbox->addWidget(catch_monitor.back()->deckMon()); + + catch_monitor.back()->deckMon()-> + enableMonitorButton((q1->value(1).toInt()>=0)&& + (catch_config->stationName().lower()== + q->value(0).toString().lower())); + catch_monitor.back()->deckMon()->show(); + mapper->setMapping(catch_monitor.back()->deckMon(), + catch_monitor.size()-1); + connect(catch_monitor.back()->deckMon(),SIGNAL(abortClicked()), + mapper,SLOT(map())); + mon_mapper->setMapping(catch_monitor.back()->deckMon(), + catch_monitor.size()-1); + connect(catch_monitor.back()->deckMon(),SIGNAL(monitorClicked()), + mon_mapper,SLOT(map())); + } + delete q1; + } + delete q; + if(catch_monitor.size()==0) { + catch_monitor_view->hide(); + } + + // + // User + // + catch_user=NULL; + + // + // Filter Selectors + // + catch_show_active_box=new QCheckBox(this,"catch_show_active_box"); + catch_show_active_label=new QLabel(catch_show_active_box, + tr("Show Only Active Events"), + this,"catch_show_active_label"); + catch_show_active_label->setFont(label_font); + catch_show_active_label->setAlignment(AlignLeft|AlignVCenter); + connect(catch_show_active_box,SIGNAL(toggled(bool)), + this,SLOT(filterChangedData(bool))); + catch_show_today_box=new QCheckBox(this,"catch_show_today_box"); + catch_show_today_label=new QLabel(catch_show_active_box, + tr("Show Only Today's Events"), + this,"catch_show_today_label"); + catch_show_today_label->setFont(label_font); + catch_show_today_label->setAlignment(AlignLeft|AlignVCenter); + connect(catch_show_today_box,SIGNAL(toggled(bool)), + this,SLOT(filterChangedData(bool))); + + catch_dow_box=new QComboBox(this,"catch_down_box"); + catch_dow_label=new QLabel(catch_dow_box,tr("Show DayOfWeek:"), + this,"catch_dow_label"); + catch_dow_label->setFont(label_font); + catch_dow_label->setAlignment(AlignRight|AlignVCenter); + catch_dow_box->insertItem(tr("All")); + catch_dow_box->insertItem(tr("Weekdays")); + catch_dow_box->insertItem(tr("Sunday")); + catch_dow_box->insertItem(tr("Monday")); + catch_dow_box->insertItem(tr("Tuesday")); + catch_dow_box->insertItem(tr("Wednesday")); + catch_dow_box->insertItem(tr("Thursday")); + catch_dow_box->insertItem(tr("Friday")); + catch_dow_box->insertItem(tr("Saturday")); + connect(catch_dow_box,SIGNAL(activated(int)),this,SLOT(dowChangedData(int))); + + // + // Cart Picker + // + catch_cart_dialog=new RDCartDialog(&catch_filter,&catch_group, + &catch_schedcode,catch_cae,catch_ripc, + rdstation_conf,catch_system,catch_config, + this); + + // + // Cart List + // + catch_recordings_list=new CatchListView(this,"catch_recordings_list"); + catch_recordings_list->setAllColumnsShowFocus(true); + catch_recordings_list->setItemMargin(5); + catch_recordings_list->setFont(list_font); + connect(catch_recordings_list,SIGNAL(selectionChanged(QListViewItem *)), + this,SLOT(selectionChangedData(QListViewItem *))); + connect(catch_recordings_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + catch_recordings_list->addColumn(""); + catch_recordings_list->setColumnAlignment(0,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("DESCRIPTION")); + catch_recordings_list->setColumnAlignment(1,Qt::AlignLeft); + catch_recordings_list->addColumn(tr("LOCATION")); + catch_recordings_list->setColumnAlignment(2,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("START")); + catch_recordings_list->setColumnAlignment(3,Qt::AlignLeft); + catch_recordings_list->addColumn(tr("END")); + catch_recordings_list->setColumnAlignment(4,Qt::AlignLeft); + catch_recordings_list->addColumn(tr("SOURCE")); + catch_recordings_list->setColumnAlignment(5,Qt::AlignLeft); + catch_recordings_list->addColumn(tr("DESTINATION")); + catch_recordings_list->setColumnAlignment(6,Qt::AlignLeft); + catch_recordings_list->addColumn(""); + catch_recordings_list->setColumnAlignment(7,Qt::AlignHCenter); + catch_recordings_list->addColumn(""); + catch_recordings_list->setColumnAlignment(8,Qt::AlignHCenter); + catch_recordings_list->addColumn(""); + catch_recordings_list->setColumnAlignment(9,Qt::AlignHCenter); + catch_recordings_list->addColumn(""); + catch_recordings_list->setColumnAlignment(10,Qt::AlignHCenter); + catch_recordings_list->addColumn(""); + catch_recordings_list->setColumnAlignment(11,Qt::AlignHCenter); + catch_recordings_list->addColumn(""); + catch_recordings_list->setColumnAlignment(12,Qt::AlignHCenter); + catch_recordings_list->addColumn(""); + catch_recordings_list->setColumnAlignment(13,Qt::AlignHCenter); + catch_recordings_list->addColumn("RSS FEED"); + catch_recordings_list->setColumnAlignment(14,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("ORIGIN")); + catch_recordings_list->setColumnAlignment(15,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("ONE SHOT")); + catch_recordings_list->setColumnAlignment(16,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("TRIM THRESHOLD")); + catch_recordings_list->setColumnAlignment(17,Qt::AlignRight); + catch_recordings_list->addColumn(tr("STARTDATE OFFSET")); + catch_recordings_list->setColumnAlignment(18,Qt::AlignRight); + catch_recordings_list->addColumn(tr("ENDDATE OFFSET")); + catch_recordings_list->setColumnAlignment(19,Qt::AlignRight); + catch_recordings_list->addColumn(tr("FORMAT")); + catch_recordings_list->setColumnAlignment(20,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("CHANNELS")); + catch_recordings_list->setColumnAlignment(21,Qt::AlignRight); + catch_recordings_list->addColumn(tr("SAMPLE RATE")); + catch_recordings_list->setColumnAlignment(22,Qt::AlignRight); + catch_recordings_list->addColumn(tr("BIT RATE")); + catch_recordings_list->setColumnAlignment(23,Qt::AlignRight); + catch_recordings_list->addColumn(tr("STATION")); + catch_recordings_list->setColumnAlignment(24,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("DECK")); + catch_recordings_list->setColumnAlignment(25,Qt::AlignRight); + catch_recordings_list->addColumn(tr("CUT")); + catch_recordings_list->setColumnAlignment(26,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("CART")); + catch_recordings_list->setColumnAlignment(27,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("ID")); + catch_recordings_list->setColumnAlignment(28,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("TYPE")); + catch_recordings_list->setColumnAlignment(29,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("STATUS")); + catch_recordings_list->setColumnAlignment(30,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("EXIT CODE")); + catch_recordings_list->setColumnAlignment(31,Qt::AlignHCenter); + catch_recordings_list->addColumn(tr("STATE")); + catch_recordings_list->setColumnAlignment(32,Qt::AlignHCenter); + catch_recordings_list->setSorting(3); // Start Time + + // + // Add Button + // + catch_add_button=new QPushButton(this,"add_button"); + catch_add_button->setFont(button_font); + catch_add_button->setText(tr("&Add")); + connect(catch_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + catch_edit_button=new QPushButton(this,"edit_button"); + catch_edit_button->setFont(button_font); + catch_edit_button->setText(tr("&Edit")); + connect(catch_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + catch_delete_button=new QPushButton(this,"delete_button"); + catch_delete_button->setFont(button_font); + catch_delete_button->setText(tr("&Delete")); + connect(catch_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Scroll Button + // + catch_scroll_button=new QPushButton(this,"catch_scroll_button"); + catch_scroll_button->setFont(button_font); + catch_scroll_button->setText(tr("Scroll")); + connect(catch_scroll_button,SIGNAL(clicked()),this,SLOT(scrollButtonData())); + + // + // Reports Button + // + catch_reports_button=new QPushButton(this,"catch_reports_button"); + catch_reports_button->setFont(button_font); + catch_reports_button->setText(tr("Reports")); + connect(catch_reports_button,SIGNAL(clicked()),this,SLOT(reportsButtonData())); + + // + // Wall Clock + // + catch_clock_label=new QLabel("00:00:00",this,"catch_clock_label"); + catch_clock_label->setFont(clock_font); + catch_clock_label->setAlignment(AlignCenter); + catch_clock_timer=new QTimer(this,"catch_clock_timer"); + connect(catch_clock_timer,SIGNAL(timeout()),this,SLOT(clockData())); + clockData(); + + // + // Play Head Button + // + catch_head_button= + new RDTransportButton(RDTransportButton::PlayFrom,this,"catch_head_button"); + catch_head_button->setDisabled(true); + connect(catch_head_button,SIGNAL(clicked()),this,SLOT(headButtonData())); + + // + // Play Tail Button + // + catch_tail_button= + new RDTransportButton(RDTransportButton::PlayTo,this,"catch_tail_button"); + catch_tail_button->setDisabled(true); + connect(catch_tail_button,SIGNAL(clicked()),this,SLOT(tailButtonData())); + + // + // Play Stop Button + // + catch_stop_button= + new RDTransportButton(RDTransportButton::Stop,this,"catch_stop_button"); + catch_stop_button->setDisabled(true); + catch_stop_button->setOnColor(red); + connect(catch_stop_button,SIGNAL(clicked()),this,SLOT(stopButtonData())); + catch_stop_button->on(); + + // + // Close Button + // + catch_close_button=new QPushButton(this,"close_button"); + catch_close_button->setFont(button_font); + catch_close_button->setText(tr("&Close")); + catch_close_button->setFocus(); + catch_close_button->setDefault(true); + connect(catch_close_button,SIGNAL(clicked()),this,SLOT(quitMainWidget())); + + // + // Next Event Timer + // + catch_next_timer=new QTimer(this,"catch_next_timer"); + connect(catch_next_timer,SIGNAL(timeout()),this,SLOT(nextEventData())); + + // + // Midnight Timer + // + catch_midnight_timer=new QTimer(this,"catch_midnight_timer"); + connect(catch_midnight_timer,SIGNAL(timeout()),this,SLOT(midnightData())); + midnightData(); + LoadGeometry(); + + RefreshList(); + + QTime current_time=QTime::currentTime().addMSecs(catch_time_offset); + QDate current_date=QDate::currentDate(); + QTime next_time; + if(ShowNextEvents(current_date.dayOfWeek(),current_time,&next_time)>0) { + catch_next_timer->start(current_time.msecsTo(next_time),true); + } + nextEventData(); + + // + // Silly Resize Workaround + // (so that the deck monitors get laid out properly) + // + QTimer *timer=new QTimer(this,"resize_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(resizeData())); + timer->start(1,true); +} + +void MainWidget::log(RDConfig::LogPriority prio,const QString &msg) +{ + catch_config->log("RDCatch",prio,msg); +} + +QSize MainWidget::sizeHint() const +{ + return QSize(940,600); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::resizeData() +{ + QResizeEvent *e=new QResizeEvent(QSize(geometry().width(), + geometry().height()), + QSize(geometry().width(), + geometry().height())); + resizeEvent(e); + delete e; +} + + +void MainWidget::connectedData(int serial,bool state) +{ + if(state) { + catch_connect[serial].connect->enableMetering(true); + } +} + + +void MainWidget::nextEventData() +{ + QTime next_time; + RDListViewItem *item=(RDListViewItem *)catch_recordings_list->firstChild(); + if(item!=NULL) { + do { + if(item->backgroundColor()==EVENT_NEXT_COLOR) { + item->setBackgroundColor(catch_recordings_list->palette().color(QPalette::Active,QColorGroup::Base)); + } + } while((item=(RDListViewItem *)item->nextSibling())!=NULL); + } + QTime current_time=QTime::currentTime().addMSecs(catch_time_offset); + QDate current_date=QDate::currentDate(); + if(ShowNextEvents(current_date.dayOfWeek(),current_time,&next_time)>0) { + catch_next_timer->start(current_time.msecsTo(next_time),true); + if(catch_scroll) { + UpdateScroll(); + } + return; + } + int extra_day=0; + for(int i=current_date.dayOfWeek()+1;i<8;i++) { + if(ShowNextEvents(i,QTime(),&next_time)>0) { + int interval=current_time.msecsTo(QTime(23,59,59))+1000+ + 86400000*extra_day+ + QTime().msecsTo(next_time); + catch_next_timer->start(interval,true); + if(catch_scroll) { + UpdateScroll(); + } + return; + } + extra_day++; + } + for(int i=1;i<(current_date.dayOfWeek()+1);i++) { + if(ShowNextEvents(i,QTime(),&next_time)>0) { + int interval=current_time.msecsTo(QTime(23,59,59))+1000+ + 86400000*extra_day+ + QTime().msecsTo(next_time); + catch_next_timer->start(interval,true); + if(catch_scroll) { + UpdateScroll(); + } + return; + } + extra_day++; + } +} + + +void MainWidget::addData() +{ + RDSqlQuery *q; + RDListViewItem *item; + int conn; + + if(!catch_user->editCatches()) { + return; + } + EnableScroll(false); + int n=AddRecord(); + AddRecording *recording=new AddRecording(n,&catch_filter,this,"recording"); + switch((RDRecording::Type)recording->exec()) { + case RDRecording::Recording: + case RDRecording::Playout: + case RDRecording::MacroEvent: + case RDRecording::SwitchEvent: + case RDRecording::Download: + case RDRecording::Upload: + item=new RDListViewItem(catch_recordings_list); + item->setBackgroundColor(catch_recordings_list->palette().color(QPalette::Active,QColorGroup::Base)); + item->setText(28,QString().sprintf("%d",n)); + RefreshLine(item); + conn=GetConnection(item->text(24)); + if(conn<0) { + fprintf(stderr,"rdcatch: invalid connection index!\n"); + return; + } + catch_recordings_list->setSelected(item,true); + catch_recordings_list->ensureItemVisible(item); + catch_connect[conn].connect->addEvent(n); + nextEventData(); + break; + + default: + q=new RDSqlQuery(QString(). + sprintf("delete from RECORDINGS where ID=%d",n)); + delete q; + break; + } + delete recording; +} + + +void MainWidget::editData() +{ + int old_conn; + int new_conn; + std::vector new_events; + + RDListViewItem *item=(RDListViewItem *)catch_recordings_list->selectedItem(); + EditRecording *recording; + EditPlayout *playout; + EditCartEvent *event; + EditSwitchEvent *switch_event; + EditDownload *download; + EditUpload *upload; + + if(!catch_user->editCatches()) { + return; + } + if(item==NULL) { + return; + } + switch((RDRecording::ExitCode)item->text(31).toUInt()) { + case RDRecording::Downloading: + case RDRecording::Uploading: + case RDRecording::RecordActive: + case RDRecording::PlayActive: + case RDRecording::Waiting: + QMessageBox::information(this,tr("Event Active"), + tr("You cannot edit an active event!")); + return; + + default: + break; + } + EnableScroll(false); + int id=item->text(28).toInt(); + old_conn=GetConnection(item->text(24)); + if(old_conn<0) { + fprintf(stderr,"rdcatch: invalid connection index!\n"); + return; + } + switch((RDRecording::Type)item->text(29).toInt()) { + case RDRecording::Recording: + recording=new EditRecording(id,&new_events,&catch_filter, + this,"recording"); + if(recording->exec()>=0) { + RefreshLine(item); + new_conn=GetConnection(item->text(24)); + if(new_conn<0) { + fprintf(stderr,"rdcatch: invalid connection index!\n"); + return; + } + catch_connect[old_conn].connect->removeEvent(id); + catch_connect[new_conn].connect->addEvent(id); + nextEventData(); + } + delete recording; + break; + + case RDRecording::Playout: + playout=new EditPlayout(id,&new_events,&catch_filter,this,"playout"); + if(playout->exec()>=0) { + RefreshLine(item); + new_conn=GetConnection(item->text(24)); + if(new_conn<0) { + fprintf(stderr,"rdcatch: invalid connection index!\n"); + return; + } + catch_connect[old_conn].connect->removeEvent(id); + catch_connect[new_conn].connect->addEvent(id); + nextEventData(); + } + delete playout; + break; + + case RDRecording::MacroEvent: + event=new EditCartEvent(id,&new_events,this,"recording"); + if(event->exec()>=0) { + RefreshLine(item); + new_conn=GetConnection(item->text(24)); + if(new_conn<0) { + fprintf(stderr,"rdcatch: invalid connection index!\n"); + return; + } + catch_connect[old_conn].connect->removeEvent(id); + catch_connect[new_conn].connect->addEvent(id); + nextEventData(); + } + delete event; + break; + + case RDRecording::SwitchEvent: + switch_event=new EditSwitchEvent(id,&new_events,this,"recording"); + if(switch_event->exec()>=0) { + RefreshLine(item); + new_conn=GetConnection(item->text(24)); + if(new_conn<0) { + fprintf(stderr,"rdcatch: invalid connection index!\n"); + return; + } + catch_connect[old_conn].connect->removeEvent(id); + catch_connect[new_conn].connect->addEvent(id); + nextEventData(); + } + delete switch_event; + break; + + case RDRecording::Download: + download=new EditDownload(id,&new_events,&catch_filter,this,"playout"); + if(download->exec()>=0) { + RefreshLine(item); + new_conn=GetConnection(item->text(24)); + if(new_conn<0) { + fprintf(stderr,"rdcatch: invalid connection index!\n"); + return; + } + catch_connect[old_conn].connect->removeEvent(id); + catch_connect[new_conn].connect->addEvent(id); + nextEventData(); + } + delete download; + break; + + case RDRecording::Upload: + upload=new EditUpload(id,&new_events,&catch_filter,this,"playout"); + if(upload->exec()>=0) { + RefreshLine(item); + new_conn=GetConnection(item->text(24)); + if(new_conn<0) { + fprintf(stderr,"rdcatch: invalid connection index!\n"); + return; + } + catch_connect[old_conn].connect->removeEvent(id); + catch_connect[new_conn].connect->addEvent(id); + nextEventData(); + } + delete upload; + break; + } + ProcessNewRecords(&new_events); +} + + +void MainWidget::deleteData() +{ + QString str; + QString warning; + QString filename; + QString sql; + RDSqlQuery *q; + RDListViewItem *item=(RDListViewItem *)catch_recordings_list->selectedItem(); + int conn; + + if(!catch_user->editCatches()||(item==NULL)) { + return; + } + EnableScroll(false); + if(item->text(1).isEmpty()) { + str=QString(tr("Are you sure you want to delete event")); + warning=QString(). + sprintf("%s\n at %s?",(const char *)str,(const char *)item->text(3)); + } + else { + str=QString(tr("Are you sure you want to delete event")); + warning=QString(). + sprintf("Are you sure you want to delete event\n\"%s\" at %s?", + (const char *)item->text(1),(const char *)item->text(3)); + } + if(QMessageBox::warning(this,tr("Delete Event"),warning, + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + return; + } + conn=GetConnection(item->text(24)); + if(conn<0) { + fprintf(stderr,"rdcatch: invalid connection index!\n"); + return; + } + catch_connect[conn].connect->removeEvent(item->text(28).toInt()); + sql=QString().sprintf("delete from RECORDINGS where ID=%s", + (const char *)item->text(28)); + q=new RDSqlQuery(sql); + delete q; + RDListViewItem *next=(RDListViewItem *)item->nextSibling(); + catch_recordings_list->removeItem(item); + if(next!=NULL) { + catch_recordings_list->setSelected(next,true); + } + nextEventData(); +} + + +void MainWidget::ripcConnectedData(bool state) +{ + if(!state) { + QMessageBox::warning(this,"Can't Connect","Unable to connect to ripcd!"); + exit(0); + } +} + + +void MainWidget::ripcUserData() +{ + QString str; + + str=QString("RDCatch")+" v"+VERSION+" - "+tr("Host")+":"; + setCaption(str+" "+catch_config->stationName()+", "+tr("User")+": "+ + catch_ripc->user()); + if(catch_user!=NULL) { + delete catch_user; + } + catch_user=new RDUser(catch_ripc->user()); + + // + // Set Control Perms + // + bool modification_allowed=catch_user->editCatches(); + catch_add_button->setEnabled(modification_allowed); + catch_edit_button->setEnabled(modification_allowed); + catch_delete_button->setEnabled(modification_allowed); +} + + +void MainWidget::statusChangedData(int serial,unsigned chan, + RDDeck::Status status,int id, + const QString &cutname) +{ + // printf("statusChangedData(%d,%u,%d,%d)\n",serial,chan,status,id); + int mon=GetMonitor(serial,chan); + if(id>0) { + RDListViewItem *item=GetItem(id); + if(item!=NULL) { + switch(status) { + case RDDeck::Offline: + item->setBackgroundColor(EVENT_ERROR_COLOR); + break; + + case RDDeck::Idle: + item->setBackgroundColor(catch_recordings_list->palette(). + color(QPalette::Active,QColorGroup::Base)); + break; + + case RDDeck::Ready: + item->setBackgroundColor(EVENT_READY_COLOR); + break; + + case RDDeck::Waiting: + item->setBackgroundColor(EVENT_WAITING_COLOR); + break; + + case RDDeck::Recording: + item->setBackgroundColor(EVENT_ACTIVE_COLOR); + break; + } + item->setText(32,QString().sprintf("%u",status)); + UpdateExitCode(item); + } + else { + if(id=0) { + int waiting_count=0; + int active_count=0; + int waiting_id=0; + RDListViewItem *item= + (RDListViewItem *)catch_recordings_list->firstChild(); + while(item!=NULL) { + if(item->text(25).toUInt()==chan) { + switch((RDDeck::Status)item->text(32).toUInt()) { + case RDDeck::Waiting: + active_count++; + waiting_count++; + waiting_id=item->text(28).toInt(); + break; + + case RDDeck::Ready: + case RDDeck::Recording: + active_count++; + break; + + default: + break; + } + } + item=(RDListViewItem *)item->nextSibling(); + } + if(waiting_count>1) { + catch_monitor[mon]->deckMon()->setStatus(status,-1,cutname); + } + else { + if((active_count==0)||(status!=RDDeck::Idle)) { + catch_monitor[mon]->deckMon()->setStatus(status,id,cutname); + } + else { + catch_monitor[mon]->deckMon()-> + setStatus(RDDeck::Waiting,waiting_id,cutname); + } + } + } + nextEventData(); +} + + +void MainWidget::monitorChangedData(int serial,unsigned chan,bool state) +{ + // printf("monitorChangedData(%d,%u,%d)\n",serial,chan,state); + int mon=GetMonitor(serial,chan); + if(mon>=0) { + catch_monitor[mon]->deckMon()->setMonitor(state); + } +} + + +void MainWidget::scrollButtonData() +{ + EnableScroll(!catch_scroll); +} + + +void MainWidget::reportsButtonData() +{ + ListReports *lr=new ListReports(catch_show_today_box->isChecked(), + catch_show_active_box->isChecked(), + catch_dow_box->currentItem(),this); + lr->exec(); + delete lr; +} + + +void MainWidget::headButtonData() +{ + RDListViewItem *item=(RDListViewItem *)catch_recordings_list->selectedItem(); + if(item==NULL) { + return; + } + EnableScroll(false); + if((!head_playing)&&(!tail_playing)) { // Start Head Play + RDCut *cut=new RDCut(item->text(26)); + catch_cae->loadPlay(catch_audition_card,item->text(26), + &catch_audition_stream,&catch_play_handle); + if(catch_audition_stream<0) { + return; + } + RDSetMixerOutputPort(catch_cae,catch_audition_card,catch_audition_stream, + catch_audition_port); + catch_cae->positionPlay(catch_play_handle,cut->startPoint()); + catch_cae->setPlayPortActive(catch_audition_card,catch_audition_port,catch_audition_stream); + catch_cae->setOutputVolume(catch_audition_card,catch_audition_stream,catch_audition_port, + 0+cut->playGain()); + catch_cae->play(catch_play_handle,RDCATCH_AUDITION_LENGTH, + RD_TIMESCALE_DIVISOR,false); + head_playing=true; + delete cut; + } +} + + +void MainWidget::tailButtonData() +{ + RDListViewItem *item=(RDListViewItem *)catch_recordings_list->selectedItem(); + if(item==NULL) { + return; + } + EnableScroll(false); + if((!head_playing)&&(!tail_playing)) { // Start Tail Play + RDCut *cut=new RDCut(item->text(26)); + catch_cae->loadPlay(catch_audition_card,item->text(26), + &catch_audition_stream,&catch_play_handle); + if(catch_audition_stream<0) { + return; + } + RDSetMixerOutputPort(catch_cae,catch_audition_card,catch_audition_stream, + catch_audition_port); + if((cut->endPoint()-cut->startPoint()-RDCATCH_AUDITION_LENGTH)>0) { + catch_cae->positionPlay(catch_play_handle, + cut->endPoint()-RDCATCH_AUDITION_LENGTH); + } + else { + catch_cae->positionPlay(catch_play_handle,cut->startPoint()); + } + catch_cae->setPlayPortActive(catch_audition_card,catch_audition_port,catch_audition_stream); + catch_cae->setOutputVolume(catch_audition_card,catch_audition_stream,catch_audition_port, + 0+cut->playGain()); + catch_cae->play(catch_play_handle,RDCATCH_AUDITION_LENGTH, + RD_TIMESCALE_DIVISOR,false); + tail_playing=true; + delete cut; + } +} + + +void MainWidget::stopButtonData() +{ + if(head_playing||tail_playing) { // Stop Play + catch_cae->stopPlay(catch_play_handle); + catch_cae->unloadPlay(catch_play_handle); + } +} + + +void MainWidget::initData(bool state) +{ + if(!state) { + QMessageBox::warning(this,tr("Can't Connect"), + tr("Unable to connect to Core AudioEngine")); + exit(1); + } +} + + +void MainWidget::playedData(int handle) +{ + if(head_playing) { + catch_head_button->on(); + } + if(tail_playing) { + catch_tail_button->on(); + } + catch_stop_button->off(); +} + + +void MainWidget::playStoppedData(int handle) +{ + head_playing=false; + tail_playing=false; + catch_head_button->off(); + catch_tail_button->off(); + catch_stop_button->on(); + catch_cae->unloadPlay(catch_play_handle); +} + + +void MainWidget::meterLevelData(int serial,int deck,int l_r,int level) +{ + DeckMon *monitor; + + for(unsigned i=0;ideckMon(); + if(l_r==0) { + monitor->setLeftMeter(level); + } + if(l_r==1) { + monitor->setRightMeter(level); + } + return; + } + } +} + + +void MainWidget::abortData(int id) +{ + catch_connect[catch_monitor[id]->serialNumber()].connect-> + stop(catch_monitor[id]->channelNumber()); +} + + +void MainWidget::monitorData(int id) +{ + catch_connect[catch_monitor[id]->serialNumber()].connect-> + toggleMonitor(catch_monitor[id]->channelNumber()); +} + + +void MainWidget::selectionChangedData(QListViewItem *item) +{ + if(item==NULL) { + catch_head_button->setDisabled(true); + catch_tail_button->setDisabled(true); + catch_stop_button->setDisabled(true); + catch_edit_button->setDisabled(true); + return; + } + if(((item->text(29).toInt()==RDRecording::Recording)|| + (item->text(29).toInt()==RDRecording::Playout)|| + (item->text(29).toInt()==RDRecording::Upload)|| + (item->text(29).toInt()==RDRecording::Download))) { + catch_head_button-> + setEnabled((catch_audition_card>=0)&&(catch_audition_port>=0)); + catch_tail_button-> + setEnabled((catch_audition_card>=0)&&(catch_audition_port>=0)); + catch_stop_button->setEnabled(true); + } + else { + catch_head_button->setDisabled(true); + catch_tail_button->setDisabled(true); + catch_stop_button->setDisabled(true); + } +} + + +void MainWidget::doubleClickedData(QListViewItem *,const QPoint &,int) +{ + editData(); +} + + +void MainWidget::eventUpdatedData(int id) +{ + // printf("eventUpdatedData(%d)\n",id); + RDListViewItem *item=GetItem(id); + if(item==NULL) { // New Event + item=new RDListViewItem(catch_recordings_list); + item->setText(28,QString().sprintf("%d",id)); + } + RefreshLine(item); + nextEventData(); +} + + +void MainWidget::eventPurgedData(int id) +{ + RDListViewItem *item=GetItem(id); + if(item==NULL) { + return; + } + catch_recordings_list->removeItem(item); +} + + +void MainWidget::heartbeatFailedData(int id) +{ + if(!catch_host_warnings) { + return; + } + QString str; + + str=QString(tr("Control connection timed out to host")); + QString msg=QString().sprintf("%s '%s'!",(const char *)str, + (const char *)catch_connect[id].station); + QMessageBox::warning(this,"RDCatch",msg); +} + + +void MainWidget::quitMainWidget() +{ + catch_db->removeDatabase(catch_config->mysqlDbname()); + SaveGeometry(); + exit(0); +} + + +void MainWidget::filterChangedData(bool) +{ + RDListViewItem *item=(RDListViewItem *)catch_recordings_list->firstChild(); + int day=QDate::currentDate().dayOfWeek(); + int day_column=0; + switch(day) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + day_column=day+7; + break; + + case 7: + day_column=7; + } + if(catch_show_active_box->isChecked()) { + if(catch_show_today_box->isChecked()) { + while(item!=NULL) { + if((item->textColor(1)==EVENT_ACTIVE_TEXT_COLOR)&& + (!item->text(day_column).isEmpty())) { + ShowEvent(item); + } + else { + item->setVisible(false); + } + item=(RDListViewItem *)item->nextSibling(); + } + } + else { + if(catch_show_active_box->isChecked()) { + while(item!=NULL) { + if(item->textColor(1)==EVENT_ACTIVE_TEXT_COLOR) { + ShowEvent(item); + } + else { + item->setVisible(false); + } + item=(RDListViewItem *)item->nextSibling(); + } + } + } + } + else { + if(catch_show_today_box->isChecked()) { + while(item!=NULL) { + if(!item->text(day_column).isEmpty()) { + ShowEvent(item); + } + else { + item->setVisible(false); + } + item=(RDListViewItem *)item->nextSibling(); + } + } + else { + while(item!=NULL) { + ShowEvent(item); + item=(RDListViewItem *)item->nextSibling(); + } + } + } +} + + +void MainWidget::dowChangedData(int id) +{ + filterChangedData(false); +} + + +void MainWidget::clockData() +{ + QTime current_time=QTime::currentTime().addMSecs(catch_time_offset); + catch_clock_label->setText(current_time.toString("hh:mm:ss")); + catch_clock_timer->start(1000-current_time.msec(),true); +} + + +void MainWidget::midnightData() +{ + filterChangedData(false); + catch_midnight_timer-> + start(86400000+QTime::currentTime().addMSecs(catch_time_offset). + msecsTo(QTime()),true); +} + + +void MainWidget::closeEvent(QCloseEvent *e) +{ + quitMainWidget(); +} + + +void MainWidget::resizeEvent(QResizeEvent *e) +{ + assert (e); + assert (catch_monitor_view); + if(catch_monitor.size()<=RDCATCH_MAX_VISIBLE_MONITORS) { + catch_monitor_view-> + setGeometry(10,10,e->size().width()-20,32*catch_monitor.size()+4); + catch_monitor_vbox-> + setGeometry(0,0,e->size().width()-25,32*catch_monitor.size()); + } + else { + catch_monitor_view-> + setGeometry(10,10,e->size().width()-20,32*RDCATCH_MAX_VISIBLE_MONITORS); + catch_monitor_vbox-> + setGeometry(0,0,e->size().width()- + catch_monitor_view->verticalScrollBar()->geometry().width()- + 25,32*catch_monitor.size()); + } + int deck_height=0; + if (catch_monitor.size()>0){ + deck_height=catch_monitor_view->geometry().y()+ + catch_monitor_view->geometry().height(); + } + catch_show_active_label->setGeometry(35,deck_height+5,160,20); + catch_show_active_box->setGeometry(15,deck_height+7,15,15); + catch_show_today_label->setGeometry(265,deck_height+5,165,20); + catch_show_today_box->setGeometry(245,deck_height+7,15,15); + catch_dow_label->setGeometry(480,deck_height+5,125,20); + catch_dow_box->setGeometry(610,deck_height+4,120,20); + catch_recordings_list-> + setGeometry(10,deck_height+25,e->size().width()-20, + e->size().height()-90-deck_height); + catch_add_button->setGeometry(10,e->size().height()-55,80,50); + catch_edit_button->setGeometry(100,e->size().height()-55,80,50); + catch_delete_button->setGeometry(190,e->size().height()-55,80,50); + catch_scroll_button->setGeometry(290,e->size().height()-55,80,50); + catch_reports_button->setGeometry(380,e->size().height()-55,80,50); + catch_clock_label->setGeometry(470,e->size().height()-38, + e->size().width()-850,20); + catch_head_button-> + setGeometry(e->size().width()-370,e->size().height()-55,80,50); + catch_tail_button-> + setGeometry(e->size().width()-280,e->size().height()-55,80,50); + catch_stop_button-> + setGeometry(e->size().width()-190,e->size().height()-55,80,50); + catch_close_button-> + setGeometry(e->size().width()-90,e->size().height()-55,80,50); +} + + +void MainWidget::ShowEvent(RDListViewItem *item) +{ + switch(catch_dow_box->currentItem()) { + case 0: // All Days + item->setVisible(true); + break; + + case 1: // Weekdays + if(item->text(8).isEmpty()&& + item->text(9).isEmpty()&& + item->text(10).isEmpty()&& + item->text(11).isEmpty()&& + item->text(12).isEmpty()) { + item->setVisible(false); + } + else { + item->setVisible(true); + } + break; + + case 2: // Sunday + if(item->text(7).isEmpty()) { + item->setVisible(false); + } + else { + item->setVisible(true); + } + break; + + case 3: // Monday + if(item->text(8).isEmpty()) { + item->setVisible(false); + } + else { + item->setVisible(true); + } + break; + + case 4: // Tuesday + if(item->text(9).isEmpty()) { + item->setVisible(false); + } + else { + item->setVisible(true); + } + break; + + case 5: // Wednesday + if(item->text(10).isEmpty()) { + item->setVisible(false); + } + else { + item->setVisible(true); + } + break; + + case 6: // Thursday + if(item->text(11).isEmpty()) { + item->setVisible(false); + } + else { + item->setVisible(true); + } + break; + + case 7: // Friday + if(item->text(12).isEmpty()) { + item->setVisible(false); + } + else { + item->setVisible(true); + } + break; + + case 8: // Saturday + if(item->text(13).isEmpty()) { + item->setVisible(false); + } + else { + item->setVisible(true); + } + break; + } +} + + +int MainWidget::ShowNextEvents(int day,QTime time,QTime *next) +{ + RDListViewItem *item=NULL; + QString sql; + int count=0; + if(time.isNull()) { + sql=QString().sprintf("select ID,START_TIME from RECORDINGS \ + where (IS_ACTIVE=\"Y\")&& \ + (%s=\"Y\") \ + order by START_TIME", + (const char *)RDGetShortDayNameEN(day).upper()); + } + else { + sql=QString().sprintf("select ID,START_TIME from RECORDINGS \ + where (IS_ACTIVE=\"Y\")&& \ + (time_to_sec(START_TIME)>time_to_sec(\"%s\"))&& \ + (%s=\"Y\") \ + order by START_TIME", + (const char *)time.toString("hh:mm:ss"), + (const char *)RDGetShortDayNameEN(day).upper()); + } + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return count; + } + *next=q->value(1).toTime(); + if((item=GetItem(q->value(0).toInt()))!=NULL) { + if((item->backgroundColor()!=EVENT_ACTIVE_COLOR)&& + (item->backgroundColor()!=EVENT_WAITING_COLOR)){ + item->setBackgroundColor(QColor(EVENT_NEXT_COLOR)); + } + count++; + } + while(q->next()&&(q->value(1).toTime()==*next)) { + if((item=GetItem(q->value(0).toInt()))!=NULL) { + if((item->backgroundColor()!=EVENT_ACTIVE_COLOR)&& + (item->backgroundColor()!=EVENT_WAITING_COLOR)){ + item->setBackgroundColor(QColor(EVENT_NEXT_COLOR)); + } + count++; + } + } + delete q; + return count; +} + + +int MainWidget::AddRecord() +{ + QString sql; + RDSqlQuery *q; + int n; + + sql=QString("select ID from RECORDINGS order by ID desc limit 1"); + q=new RDSqlQuery(sql); + if(q->first()) { + n=q->value(0).toInt()+1; + } + else { + n=1; + } + delete q; + sql=QString().sprintf("insert into RECORDINGS set ID=%d",n); + q=new RDSqlQuery(sql); + delete q; + return n; +} + + +void MainWidget::ProcessNewRecords(std::vector *adds) +{ + int conn=0; + RDListViewItem *item; + + for(unsigned i=0;isize();i++) { + item=new RDListViewItem(catch_recordings_list); + item->setBackgroundColor(catch_recordings_list->palette().color(QPalette::Active,QColorGroup::Base)); + item->setText(28,QString().sprintf("%d",adds->at(i))); + RefreshLine(item); + conn=GetConnection(item->text(24)); + if(conn<0) { + fprintf(stderr,"rdcatch: invalid connection index!\n"); + return; + } + catch_connect[conn].connect->addEvent(adds->at(i)); + } + nextEventData(); +} + + +void MainWidget::EnableScroll(bool state) +{ + if(state) { + catch_scroll_button->setPalette(catch_scroll_color[0]); + catch_scroll=true; + UpdateScroll(); + } + else { + catch_scroll_button->setPalette(catch_scroll_color[1]); + catch_scroll=false; + } +} + + +void MainWidget::UpdateScroll() +{ + RDListViewItem *item=(RDListViewItem *)catch_recordings_list->firstChild(); + + // + // Search for active event + // + while(item!=NULL) { + if(item->backgroundColor()==EVENT_ACTIVE_COLOR) { + catch_recordings_list-> + ensureVisible(0,catch_recordings_list->itemPos(item), + 0,catch_recordings_list->size().height()/2); + catch_recordings_list->setCurrentItem(item); + catch_recordings_list->clearSelection(); + return; + } + item=(RDListViewItem *)item->nextSibling(); + } + + // + // Search for next event + // + item=(RDListViewItem *)catch_recordings_list->firstChild(); + while(item!=NULL) { + if(item->backgroundColor()==EVENT_NEXT_COLOR) { + catch_recordings_list-> + ensureVisible(0,catch_recordings_list->itemPos(item), + 0,catch_recordings_list->size().height()/2); + catch_recordings_list->setCurrentItem(item); + catch_recordings_list->clearSelection(); + return; + } + item=(RDListViewItem *)item->nextSibling(); + } +} + + +void MainWidget::RefreshList() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + RDListViewItem *l; + RDCut *cut; + QString str; + + catch_recordings_list->clear(); + sql=QString("select RECORDINGS.DESCRIPTION,RECORDINGS.IS_ACTIVE,\ + RECORDINGS.STATION_NAME,RECORDINGS.START_TIME,\ + RECORDINGS.LENGTH,RECORDINGS.CUT_NAME,RECORDINGS.SUN,\ + RECORDINGS.MON,RECORDINGS.TUE,RECORDINGS.WED,RECORDINGS.THU,\ + RECORDINGS.FRI,RECORDINGS.SAT,RECORDINGS.SWITCH_INPUT,\ + RECORDINGS.START_GPI,RECORDINGS.END_GPI,\ + RECORDINGS.TRIM_THRESHOLD,RECORDINGS.STARTDATE_OFFSET,\ + RECORDINGS.ENDDATE_OFFSET,RECORDINGS.FORMAT,\ + RECORDINGS.CHANNELS,RECORDINGS.SAMPRATE,RECORDINGS.BITRATE,\ + RECORDINGS.CHANNEL,RECORDINGS.MACRO_CART,RECORDINGS.ID,\ + RECORDINGS.TYPE,RECORDINGS.SWITCH_OUTPUT,RECORDINGS.EXIT_CODE,\ + RECORDINGS.ONE_SHOT,RECORDINGS.START_TYPE,\ + RECORDINGS.START_LENGTH,RECORDINGS.START_MATRIX,\ + RECORDINGS.START_LINE,RECORDINGS.START_OFFSET,\ + RECORDINGS.END_TYPE,RECORDINGS.END_TIME,RECORDINGS.END_LENGTH,\ + RECORDINGS.END_MATRIX,RECORDINGS.END_LINE,CUTS.ORIGIN_NAME,\ + CUTS.ORIGIN_DATETIME,RECORDINGS.URL,RECORDINGS.QUALITY,\ + FEEDS.KEY_NAME,EXIT_TEXT from RECORDINGS left join CUTS\ + on (RECORDINGS.CUT_NAME=CUTS.CUT_NAME) left join FEEDS \ + on (RECORDINGS.FEED_ID=FEEDS.ID)"); + // Field Offsets: + // + // 0 - REC.DESCRIPTION 18 - REC.ENDDATE_OFFSET 36 - REC.END_TIME + // 1 - REC.IS_ACTIVE 19 - REC.FORMAT 37 - REC.END_LENGTH + // 2 - REC.STATION_NAME 20 - REC.CHANNELS 38 - REC.END_MATRIX + // 3 - REC.START_TIME 21 - REC.SAMPRATE 39 - REC.END_LINE + // 4 - REC.LENGTH 22 - REC.BITRATE 40 - CUTS.ORIGIN_NAME + // 5 - REC.CUT_NAME 23 - REC.CHANNEL 41 - CUTS.ORIGIN_DATETIME + // 6 - REC.SUN 24 - REC.MACRO_CART 42 - REC.URL + // 7 - REC.MON 25 - REC.ID 43 - REC.QUALITY + // 8 - REC.TUE 26 - REC.TYPE 44 - FEEDS.KEY_NAME + // 9 - REC.WED 27 - REC.SWITCH_OUTPUT 45 - REC.EXIT_TEXT + // 10 - REC.THU 28 - REC.EXIT_CODE + // 11 - REC.FRI 29 - REC.ONE_SHOT + // 12 - REC.SAT 30 - REC.START_TYPE + // 13 - REC.SWITCH_INPUT 31 - REC.START_LENGTH + // 14 - REC.START_GPI 32 - REC.START_MATRIX + // 15 - REC.END_GPI 33 - REC.START_LINE + // 16 - REC.TRIM_THRESHOLD 34 - REC.START_OFFSET + // 17 - REC.STARTDATE_OFFSET 35 - REC.END_TYPE + q=new RDSqlQuery(sql); + while(q->next()) { + l=new RDListViewItem(catch_recordings_list); + l->setBackgroundColor(catch_recordings_list->palette().color(QPalette::Active,QColorGroup::Base)); + if(RDBool(q->value(1).toString())) { + l->setTextColor(QColor(EVENT_ACTIVE_TEXT_COLOR)); + } + else { + l->setTextColor(QColor(EVENT_INACTIVE_TEXT_COLOR)); + } + l->setText(1,q->value(0).toString()); // Description + if(RDBool(q->value(6).toString())) { // Sun + l->setText(7,tr("Su")); + } + if(RDBool(q->value(7).toString())) { // Mon + l->setText(8,tr("Mo")); + } + if(RDBool(q->value(8).toString())) { // Tue + l->setText(9,tr("Tu")); + } + if(RDBool(q->value(9).toString())) { // Wed + l->setText(10,tr("We")); + } + if(RDBool(q->value(10).toString())) { // Thu + l->setText(11,tr("Th")); + } + if(RDBool(q->value(11).toString())) { // Fri + l->setText(12,tr("Fr")); + } + if(RDBool(q->value(12).toString())) { // Sat + l->setText(13,tr("Sa")); + } + switch((RDRecording::Type)q->value(26).toInt()) { + case RDRecording::Recording: + case RDRecording::Playout: + case RDRecording::Download: + case RDRecording::Upload: + l->setText(15,q->value(40).toString()+" - "+ + q->value(41).toDateTime(). + toString("M/dd/yyyy hh:mm:ss")); + break; + + default: + l->setText(15,""); + break; + } + l->setText(16,q->value(29).toString()); // One Shot + str=QString(tr("dB")); + l->setText(17,QString().sprintf("%d %s", // Trim Threshold + -q->value(17).toInt(),(const char *)str)); + l->setText(18,q->value(17).toString()); // Startdate Offset + l->setText(19,q->value(18).toString()); // Enddate Offset + l->setText(24,q->value(2).toString()); // Station + l->setText(25,q->value(23).toString()); // Deck + l->setText(26,q->value(5).toString()); // Cut Name + if(q->value(24).toInt()>=0) { + l->setText(27,q->value(24).toString()); // Macro Cart + } + else { + l->setText(27,""); + } + l->setText(28,q->value(25).toString()); // Id + l->setText(29,q->value(26).toString()); // Type + l->setText(32,QString().sprintf("%u",RDDeck::Idle)); + switch((RDRecording::Type)q->value(26).toInt()) { + case RDRecording::Recording: + l->setPixmap(0,*catch_record_map); + l->setText(2,QString().sprintf("%s : %dR", + (const char *)q->value(2).toString(), + q->value(23).toInt())); + switch((RDRecording::StartType)q->value(30).toUInt()) { + case RDRecording::HardStart: + str=QString(tr("Hard")); + l->setText(3,q->value(3).toTime(). + toString(QString().sprintf("%s: hh:mm:ss", + (const char *)str))); + break; + + case RDRecording::GpiStart: + str=QString(tr("Gpi")); + l->setText(3,QString(). + sprintf("%s: %s,%s,%d:%d,%s", + (const char *)str, + (const char *)q->value(3). + toTime().toString("hh:mm:ss"), + (const char *)q->value(3).toTime(). + addMSecs(q->value(31).toInt()). + toString("hh:mm:ss"), + q->value(32).toInt(), + q->value(33).toInt(), + (const char *)QTime(). + addMSecs(q->value(34).toUInt()). + toString("mm:ss"))); + break; + } + switch((RDRecording::EndType)q->value(35).toUInt()) { + case RDRecording::LengthEnd: + str=QString(tr("Len")); + l->setText(4,QString().sprintf("%s: %s", + (const char *)str, + (const char *) + RDGetTimeLength(q->value(4).toUInt(), + false,false))); + break; + + case RDRecording::HardEnd: + str=QString(tr("Hard")); + l->setText(4,QString().sprintf("%s: %s", + (const char *)str, + (const char *) + q->value(36).toTime(). + toString("hh:mm:ss"))); + break; + + case RDRecording::GpiEnd: + str=QString(tr("Gpi")); + l->setText(4,QString(). + sprintf("%s: %s,%s,%d:%d", + (const char *)str, + (const char *)q->value(36). + toTime().toString("hh:mm:ss"), + (const char *)q->value(36).toTime(). + addMSecs(q->value(37).toInt()). + toString("hh:mm:ss"), + q->value(38).toInt(), + q->value(39).toInt())); + break; + } + str=QString(tr("Cut")); + l->setText(6,QString(). + sprintf("%s %s",(const char *)str, + (const char *)q->value(5).toString())); + sql=QString().sprintf("select SWITCH_STATION,SWITCH_MATRIX\ + from DECKS where \ + (STATION_NAME=\"%s\")&&(CHANNEL=%d)", + (const char *)q->value(2).toString(), + q->value(23).toInt()); + q1=new RDSqlQuery(sql); + if(q1->first()) { // Source + l->setText(5,GetSourceName(q1->value(0).toString(), + q1->value(1).toInt(), + q->value(13).toInt())); + } + delete q1; + switch((RDSettings::Format)q->value(19).toInt()) { // Format + case RDSettings::Pcm16: + l->setText(20,tr("PCM16")); + break; + case RDSettings::MpegL1: + l->setText(20,tr("MPEG Layer 1")); + break; + case RDSettings::MpegL2: + case RDSettings::MpegL2Wav: + l->setText(20,tr("MPEG Layer 2")); + break; + case RDSettings::MpegL3: + l->setText(20,tr("MPEG Layer 3")); + break; + case RDSettings::Flac: + l->setText(20,tr("FLAC")); + break; + case RDSettings::OggVorbis: + l->setText(20,tr("OggVorbis")); + break; + } + l->setText(21,q->value(20).toString()); // Channels + l->setText(22,q->value(21).toString()); // Sample Rate + l->setText(23,q->value(22).toString()); // Bit Rate + break; + + case RDRecording::Playout: + l->setPixmap(0,*catch_playout_map); + l->setText(2,QString().sprintf("%s : %dP", + (const char *)q->value(2).toString(), + q->value(23).toInt()-128)); + l->setText(3,q->value(3).toTime().toString("Hard: hh:mm:ss")); + cut=new RDCut(q->value(5).toString()); + str=QString(tr("Len")); + if(cut->exists()) { + l->setText(4,QString().sprintf("%s: %s",(const char *)str, + (const char *)RDGetTimeLength(cut->length(),false,false))); + } + delete cut; + str=QString(tr("Cut")); + l->setText(5,QString(). + sprintf("%s %s",(const char *)str, + (const char *)q->value(5).toString())); + break; + + case RDRecording::MacroEvent: + l->setPixmap(0,*catch_macro_map); + l->setText(2,q->value(2).toString()); + str=QString(tr("Hard")); + l->setText(3,q->value(3).toTime(). + toString(QString(). + sprintf("%s: hh:mm:ss",(const char *)str))); + str=QString(tr("Cart")); + l->setText(5,QString().sprintf("%s %06d",(const char *)str, + q->value(24).toInt())); + break; + + case RDRecording::SwitchEvent: + l->setPixmap(0,*catch_switch_map); + l->setText(2,q->value(2).toString()); + str=QString(tr("Hard")); + l->setText(3,q->value(3).toTime(). + toString(QString().sprintf("%s: hh:mm:ss",(const char *)str))); + l->setText(5,GetSourceName(q->value(2).toString(), // Source + q->value(23).toInt(), + q->value(13).toInt())); + l->setText(6,GetDestinationName(q->value(2).toString(), // Dest + q->value(23).toInt(), + q->value(27).toInt())); + break; + + case RDRecording::Download: + l->setPixmap(0,*catch_download_map); + l->setText(2,q->value(2).toString()); + str=QString(tr("Hard")); + l->setText(3,q->value(3).toTime(). + toString(QString(). + sprintf("%s: hh:mm:ss",(const char *)str))); + str=QString(tr("Cut")); + l->setText(5,q->value(42).toString()); + l->setText(6,QString(). + sprintf("%s %s",(const char *)str, + (const char *)q->value(5).toString())); + break; + + case RDRecording::Upload: + l->setPixmap(0,*catch_upload_map); + l->setText(2,q->value(2).toString()); + str=QString(tr("Hard")); + l->setText(3,q->value(3).toTime(). + toString(QString(). + sprintf("%s: hh:mm:ss",(const char *)str))); + str=QString(tr("Cut")); + l->setText(5,QString(). + sprintf("%s %s",(const char *)str, + (const char *)q->value(5).toString())); + l->setText(6,q->value(42).toString()); + switch((RDSettings::Format)q->value(19).toInt()) { // Format + case RDSettings::Pcm16: + l->setText(20,tr("PCM16")); + break; + case RDSettings::MpegL1: + l->setText(20,tr("MPEG Layer 1")); + break; + case RDSettings::MpegL2: + case RDSettings::MpegL2Wav: + l->setText(20,tr("MPEG Layer 2")); + break; + case RDSettings::MpegL3: + l->setText(20,tr("MPEG Layer 3")); + break; + case RDSettings::Flac: + l->setText(20,tr("FLAC")); + break; + case RDSettings::OggVorbis: + l->setText(20,tr("OggVorbis")); + break; + } + if(q->value(44).toString().isEmpty()) { + l->setText(14,tr("[none]")); + } + else { + l->setText(14,q->value(44).toString()); // Feed Key Name + } + l->setText(21,q->value(20).toString()); // Channels + l->setText(22,q->value(21).toString()); // Sample Rate + if(q->value(22).toInt()==0) { // Bit Rate/Quality + l->setText(23,QString().sprintf("Qual %d",q->value(43).toInt())); + } + else { + l->setText(23,QString().sprintf("%d kb/sec", + q->value(22).toInt()/1000)); + } + break; + } + DisplayExitCode(l,(RDRecording::ExitCode)q->value(28).toInt(), + q->value(45).toString()); + } + delete q; +} + + +void MainWidget::RefreshLine(RDListViewItem *item) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + RDCut *cut; + QString str; + + int id=item->text(28).toInt(); + sql=QString().sprintf("select RECORDINGS.DESCRIPTION,\ + RECORDINGS.IS_ACTIVE,\ + RECORDINGS.STATION_NAME,\ + RECORDINGS.START_TIME,\ + RECORDINGS.LENGTH,\ + RECORDINGS.CUT_NAME,\ + RECORDINGS.SUN,\ + RECORDINGS.MON,\ + RECORDINGS.TUE,\ + RECORDINGS.WED,\ + RECORDINGS.THU,\ + RECORDINGS.FRI,\ + RECORDINGS.SAT,\ + RECORDINGS.SWITCH_INPUT,\ + RECORDINGS.START_GPI,\ + RECORDINGS.END_GPI,\ + RECORDINGS.TRIM_THRESHOLD,\ + RECORDINGS.STARTDATE_OFFSET,\ + RECORDINGS.ENDDATE_OFFSET,\ + RECORDINGS.FORMAT,\ + RECORDINGS.CHANNELS,\ + RECORDINGS.SAMPRATE,\ + RECORDINGS.BITRATE,\ + RECORDINGS.CHANNEL,\ + RECORDINGS.MACRO_CART,\ + RECORDINGS.TYPE,\ + RECORDINGS.SWITCH_OUTPUT,\ + RECORDINGS.EXIT_CODE,\ + RECORDINGS.ONE_SHOT,\ + RECORDINGS.START_TYPE,\ + RECORDINGS.START_LENGTH,\ + RECORDINGS.START_MATRIX,\ + RECORDINGS.START_LINE,\ + RECORDINGS.START_OFFSET,\ + RECORDINGS.END_TYPE,\ + RECORDINGS.END_TIME,\ + RECORDINGS.END_LENGTH,\ + RECORDINGS.END_MATRIX,\ + RECORDINGS.END_LINE,\ + CUTS.ORIGIN_NAME,\ + CUTS.ORIGIN_DATETIME,\ + RECORDINGS.URL,\ + RECORDINGS.QUALITY,\ + FEEDS.KEY_NAME,\ + RECORDINGS.EXIT_TEXT \ + from RECORDINGS left join CUTS \ + on (RECORDINGS.CUT_NAME=CUTS.CUT_NAME) left join FEEDS\ + on (RECORDINGS.FEED_ID=FEEDS.ID) \ + where RECORDINGS.ID=%d",id); + q=new RDSqlQuery(sql); + if(q->first()) { + if(RDBool(q->value(1).toString())) { + item->setTextColor(QColor(EVENT_ACTIVE_TEXT_COLOR)); + } + else { + item->setTextColor(QColor(EVENT_INACTIVE_TEXT_COLOR)); + } + item->setText(1,q->value(0).toString()); // Description + if(q->value(25).toInt()==RDRecording::Recording) { + item->setText(2,q->value(2).toString()+QString(" : ")+ // Station : Deck + q->value(23).toString()); + } + else { + item->setText(2,q->value(2).toString()); + } + item->setText(4,RDGetTimeLength(q->value(4).toUInt())); // Length + if(RDBool(q->value(6).toString())) { // Sun + item->setText(7,tr("Su")); + } + else { + item->setText(7,""); + } + if(RDBool(q->value(7).toString())) { // Mon + item->setText(8,tr("Mo")); + } + else { + item->setText(8,""); + } + if(RDBool(q->value(8).toString())) { // Tue + item->setText(9,tr("Tu")); + } + else { + item->setText(9,""); + } + if(RDBool(q->value(9).toString())) { // Wed + item->setText(10,tr("We")); + } + else { + item->setText(10,""); + } + if(RDBool(q->value(10).toString())) { // Thu + item->setText(11,tr("Th")); + } + else { + item->setText(11,""); + } + if(RDBool(q->value(11).toString())) { // Fri + item->setText(12,tr("Fr")); + } + else { + item->setText(12,""); + } + if(RDBool(q->value(12).toString())) { // Sat + item->setText(13,tr("Sa")); + } + else { + item->setText(13,""); + } + switch((RDRecording::Type)q->value(25).toInt()) { + case RDRecording::Recording: + case RDRecording::Playout: + case RDRecording::Download: + case RDRecording::Upload: + item->setText(15,q->value(39).toString()+" - "+ + q->value(40).toDateTime(). + toString("M/dd/yyyy hh:mm:ss")); + break; + + default: + item->setText(15,""); + } + item->setText(16,q->value(28).toString()); // One Shot + str=QString(tr("dB")); + item->setText(17,QString().sprintf("%d %s", // Trim Threshold + -q->value(17).toInt(),(const char *)str)); + item->setText(18,q->value(17).toString()); // Startdate Offset + item->setText(19,q->value(18).toString()); // Enddate Offset + + /* + */ + item->setText(24,q->value(2).toString()); // Station + item->setText(25,q->value(23).toString()); // Deck + item->setText(26,q->value(5).toString()); // Cut Name + if(q->value(24).toInt()>0) { + item->setText(27,q->value(24).toString()); // Macro Cart + } + else { + item->setText(27,""); + } + item->setText(29,q->value(25).toString()); // Type + switch((RDRecording::Type)q->value(25).toInt()) { // Source + case RDRecording::Recording: + item->setText(2,QString().sprintf("%s : %dR", + (const char *)q->value(2).toString(), + q->value(23).toInt())); + switch((RDRecording::StartType)q->value(29).toUInt()) { + case RDRecording::HardStart: + str=QString(tr("Hard")); + item-> + setText(3,q->value(3).toTime(). + toString(QString(). + sprintf("%s: hh:mm:ss",(const char *)str))); + break; + + case RDRecording::GpiStart: + str=QString(tr("Gpi")); + item->setText(3,QString(). + sprintf("%s: %s,%s,%d:%d,%s", + (const char *)str, + (const char *)q->value(3). + toTime().toString("hh:mm:ss"), + (const char *)q->value(3).toTime(). + addMSecs(q->value(30).toInt()). + toString("hh:mm:ss"), + q->value(31).toInt(), + q->value(32).toInt(), + (const char *)QTime(). + addMSecs(q->value(33).toUInt()). + toString("mm:ss"))); + break; + } + switch((RDRecording::EndType)q->value(34).toUInt()) { + case RDRecording::LengthEnd: + str=QString(tr("Len")); + item->setText(4,QString().sprintf("%s: %s",(const char *)str, + (const char *) + RDGetTimeLength(q->value(4).toUInt(), + false,false))); + break; + + case RDRecording::HardEnd: + str=QString(tr("Hard")); + item->setText(4,QString().sprintf("%s: %s",(const char *)str, + (const char *) + q->value(35).toTime(). + toString("hh:mm:ss"))); + break; + + case RDRecording::GpiEnd: + str=QString(tr("Gpi")); + item->setText(4,QString(). + sprintf("%s: %s,%s,%d:%d",(const char *)str, + (const char *)q->value(35). + toTime().toString("hh:mm:ss"), + (const char *)q->value(35).toTime(). + addMSecs(q->value(36).toInt()). + toString("hh:mm:ss"), + q->value(37).toInt(), + q->value(38).toInt())); + break; + } + sql=QString().sprintf("select SWITCH_STATION,SWITCH_MATRIX\ + from DECKS where \ + (STATION_NAME=\"%s\")&&(CHANNEL=%d)", + (const char *)q->value(2).toString(), + q->value(23).toInt()); + q1=new RDSqlQuery(sql); + if(q1->first()) { + item->setText(5,GetSourceName(q1->value(0).toString(), + q1->value(1).toInt(), + q->value(13).toInt())); + } + delete q1; + item->setText(6,QString(). + sprintf("Cut %s",(const char *)q->value(5).toString())); + item->setPixmap(0,*catch_record_map); + switch((RDSettings::Format)q->value(19).toInt()) { // Format + case RDSettings::Pcm16: + item->setText(20,tr("PCM16")); + break; + case RDSettings::MpegL1: + item->setText(20,tr("MPEG Layer 1")); + break; + case RDSettings::MpegL2: + case RDSettings::MpegL2Wav: + item->setText(20,tr("MPEG Layer 2")); + break; + case RDSettings::MpegL3: + item->setText(20,tr("MPEG Layer 3")); + break; + case RDSettings::Flac: + item->setText(20,tr("FLAC")); + break; + case RDSettings::OggVorbis: + item->setText(20,tr("OggVorbis")); + break; + } + item->setText(21,q->value(20).toString()); // Channels + item->setText(22,q->value(21).toString()); // Sample Rate + item->setText(23,q->value(22).toString()); // Bit Rate + break; + + case RDRecording::Playout: + item->setText(2,QString().sprintf("%s : %dP", + (const char *)q->value(2).toString(), + q->value(23).toInt()-128)); + item->setText(3,q->value(3).toTime().toString("Hard: hh:mm:ss")); + cut=new RDCut(q->value(5).toString()); + if(cut->exists()) { + str=QString(tr("Len")); + item->setText(4,QString().sprintf("%s: %s",(const char *)str, + (const char *)RDGetTimeLength(cut->length(),false,false))); + } + else { + item->setText(4,""); + } + delete cut; + str=QString(tr("Cut")); + item->setText(5,QString(). + sprintf("%s %s",(const char *)str, + (const char *)q->value(5).toString())); + item->setPixmap(0,*catch_playout_map); + item->setText(20,""); + item->setText(21,""); + item->setText(22,""); + item->setText(23,""); + break; + + case RDRecording::MacroEvent: + str=QString(tr("Hard")); + item->setText(3,q->value(3).toTime(). + toString(QString(). + sprintf("%s: hh:mm:ss",(const char *)str))); + item->setText(4,""); + item->setText(5,QString().sprintf("Cart %06d",q->value(24).toInt())); + item->setPixmap(0,*catch_macro_map); + item->setText(20,""); + item->setText(21,""); + item->setText(22,""); + item->setText(23,""); + break; + + case RDRecording::SwitchEvent: + str=QString(tr("Hard")); + item->setText(3,q->value(3).toTime(). + toString(QString(). + sprintf("%s: hh:mm:ss",(const char *)str))); + item->setText(4,""); + item->setText(5,GetSourceName(q->value(2).toString(), + q->value(23).toInt(), + q->value(13).toInt())); + item->setPixmap(0,*catch_switch_map); + item->setText(6,GetDestinationName(q->value(2).toString(), // Dest + q->value(23).toInt(), + q->value(26).toInt())); + item->setText(20,""); + item->setText(21,""); + item->setText(22,""); + item->setText(23,""); + break; + + case RDRecording::Download: + item->setPixmap(0,*catch_download_map); + str=QString(tr("Hard")); + item->setText(2,q->value(2).toString()); + item->setText(3,q->value(3).toTime(). + toString(QString(). + sprintf("%s: hh:mm:ss",(const char *)str))); + item->setText(4,""); + item->setText(5,q->value(41).toString()); + item->setText(6,QString(). + sprintf("Cut %s",(const char *)q->value(5).toString())); + item->setText(20,""); + item->setText(21,""); + item->setText(22,""); + item->setText(23,""); + break; + + case RDRecording::Upload: + item->setPixmap(0,*catch_upload_map); + str=QString(tr("Hard")); + item->setText(2,q->value(2).toString()); + item->setText(3,q->value(3).toTime(). + toString(QString(). + sprintf("%s: hh:mm:ss",(const char *)str))); + item->setText(4,""); + item->setText(5,QString(). + sprintf("Cut %s",(const char *)q->value(5).toString())); + item->setText(6,q->value(41).toString()); + if(q->value(43).toString().isEmpty()) { + item->setText(14,tr("[none]")); + } + else { + item->setText(14,q->value(43).toString()); + } + switch((RDSettings::Format)q->value(19).toInt()) { // Format + case RDSettings::Pcm16: + item->setText(20,tr("PCM16")); + break; + case RDSettings::MpegL1: + item->setText(20,tr("MPEG Layer 1")); + break; + case RDSettings::MpegL2: + case RDSettings::MpegL2Wav: + item->setText(20,tr("MPEG Layer 2")); + break; + case RDSettings::MpegL3: + item->setText(20,tr("MPEG Layer 3")); + break; + case RDSettings::Flac: + item->setText(20,tr("FLAC")); + break; + case RDSettings::OggVorbis: + item->setText(20,tr("OggVorbis")); + break; + } + item->setText(21,q->value(20).toString()); // Channels + item->setText(22,q->value(21).toString()); // Sample Rate + item->setText(23,q->value(22).toString()); // Bit Rate + if(q->value(22).toInt()==0) { // Bit Rate/Quality + item->setText(23,QString().sprintf("Qual %d", + q->value(42).toInt())); + } + else { + item->setText(23,QString().sprintf("%d kb/sec", + q->value(22).toInt()/1000)); + } + break; + } + DisplayExitCode(item,(RDRecording::ExitCode)q->value(27).toInt(), + q->value(44).toString()); + } + else { // Event removed + delete item; + } + delete q; +} + + +void MainWidget::UpdateExitCode(RDListViewItem *item) +{ + RDRecording::ExitCode code=RDRecording::InternalError; + QString err_text=tr("Unknown"); + QString sql=QString().sprintf("select RECORDINGS.EXIT_CODE,\ + CUTS.ORIGIN_NAME,CUTS.ORIGIN_DATETIME,\ + RECORDINGS.EXIT_TEXT \ + from RECORDINGS left join CUTS \ + on RECORDINGS.CUT_NAME=CUTS.CUT_NAME \ + where RECORDINGS.ID=%d", + item->text(28).toInt()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + code=(RDRecording::ExitCode)q->value(0).toInt(); + err_text=q->value(3).toString(); + item->setText(15,q->value(1).toString()+" - "+q->value(2).toDateTime(). + toString("M/dd/yyyy hh:mm:ss")); + } + else { + item->setText(15,""); + } + delete q; + DisplayExitCode(item,code,err_text); +} + + +void MainWidget::DisplayExitCode(RDListViewItem *item, + RDRecording::ExitCode code, + const QString &err_text) +{ + item->setText(31,QString().sprintf("%u",code)); + switch(code) { + case RDRecording::Ok: + case RDRecording::Downloading: + case RDRecording::Uploading: + case RDRecording::RecordActive: + case RDRecording::PlayActive: + case RDRecording::Waiting: + item->setText(30,RDRecording::exitString(code)); + break; + + case RDRecording::Short: + case RDRecording::LowLevel: + case RDRecording::HighLevel: + case RDRecording::Interrupted: + case RDRecording::DeviceBusy: + case RDRecording::NoCut: + case RDRecording::UnknownFormat: + item->setText(30,RDRecording::exitString(code)); + item->setBackgroundColor(EVENT_ERROR_COLOR); + break; + + case RDRecording::ServerError: + case RDRecording::InternalError: + item->setText(30,RDRecording::exitString(code)+": "+err_text); + item->setBackgroundColor(EVENT_ERROR_COLOR); + break; + } +} + + +QString MainWidget::GetSourceName(QString station,int matrix,int input) +{ + QString input_name; + QString sql=QString().sprintf("select NAME from INPUTS where \ + (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&(NUMBER=%d)", + (const char *)station, + matrix,input); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + input_name=q->value(0).toString(); + } + delete q; + return input_name; +} + + +QString MainWidget::GetDestinationName(QString station,int matrix,int output) +{ + QString output_name; + QString sql=QString().sprintf("select NAME from OUTPUTS where \ + (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&(NUMBER=%d)", + (const char *)station, + matrix,output); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + output_name=q->value(0).toString(); + } + delete q; + return output_name; +} + + +RDListViewItem *MainWidget::GetItem(int id) +{ + RDListViewItem *item=(RDListViewItem *)catch_recordings_list->firstChild(); + if(item==NULL) { + return NULL; + } + do { + if(item->text(28).toInt()==id) { + return item; + } + } while ((item=(RDListViewItem *)item->nextSibling())!=NULL); + return NULL; +} + + +int MainWidget::GetMonitor(int serial,int chan) +{ + for(unsigned i=0;iserialNumber()==serial)&& + (catch_monitor[i]->channelNumber()==chan)) { + return i; + } + } + return -1; +} + + +int MainWidget::GetConnection(QString station,unsigned chan) +{ + for(int i=0;i + setSource(QString().sprintf("%s/%s",getenv("HOME"),RDCATCH_GEOMETRY_FILE)); + resize(profile->intValue("RDCatch","Width",sizeHint().width()), + profile->intValue("RDCatch","Height",sizeHint().height())); + + delete profile; +} + + +void MainWidget::SaveGeometry() +{ + if(getenv("HOME")==NULL) { + return; + } + FILE *file=fopen((const char *)QString(). + sprintf("%s/%s",getenv("HOME"),RDCATCH_GEOMETRY_FILE), + "w"); + if(file==NULL) { + return; + } + fprintf(file,"[RDCatch]\n"); + fprintf(file,"Width=%d\n",geometry().width()); + fprintf(file,"Height=%d\n",geometry().height()); + fclose(file); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(), + "."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rdcatch_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->show(); + return a.exec(); +} diff --git a/rdcatch/rdcatch.h b/rdcatch/rdcatch.h new file mode 100644 index 00000000..02eb0669 --- /dev/null +++ b/rdcatch/rdcatch.h @@ -0,0 +1,184 @@ +// rdcatch.h +// +// The Netcatch Manager for Rivendell. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rdcatch.h,v 1.51 2011/08/30 23:35:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDCATCH_H +#define RDCATCH_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; + +/* + * Widget Settings + */ +#define RDCATCH_AUDITION_LENGTH 5000 +#define RDCATCH_GEOMETRY_FILE ".rdcatch" +#define RDCATCH_MAX_VISIBLE_MONITORS 8 +#define RDCATCH_USAGE "[--offline-host-warnings=yes|no]\n" + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void log(RDConfig::LogPriority prio,const QString &msg); + void resizeData(); + void connectedData(int serial,bool state); + void nextEventData(); + void addData(); + void editData(); + void deleteData(); + void ripcConnectedData(bool); + void ripcUserData(); + void statusChangedData(int,unsigned,RDDeck::Status,int, + const QString &cutname); + void monitorChangedData(int serial,unsigned chan,bool state); + void scrollButtonData(); + void reportsButtonData(); + void headButtonData(); + void tailButtonData(); + void stopButtonData(); + void initData(bool); + void playedData(int); + void playStoppedData(int); + void meterLevelData(int,int,int,int); + void abortData(int); + void monitorData(int); + void selectionChangedData(QListViewItem *item); + void doubleClickedData(QListViewItem *,const QPoint &,int); + void filterChangedData(bool state); + void dowChangedData(int id); + void clockData(); + void midnightData(); + void eventUpdatedData(int id); + void eventPurgedData(int id); + void heartbeatFailedData(int id); + void quitMainWidget(); + + protected: + void closeEvent(QCloseEvent *e); + void resizeEvent(QResizeEvent *e); + + private: + void ShowEvent(RDListViewItem *item); + int ShowNextEvents(int day,QTime time,QTime *next); + int AddRecord(); + void ProcessNewRecords(std::vector *adds); + void EnableScroll(bool state); + void UpdateScroll(); + void RefreshList(); + void RefreshLine(RDListViewItem *item); + void UpdateExitCode(RDListViewItem *item); + void DisplayExitCode(RDListViewItem *item,RDRecording::ExitCode code, + const QString &err_text); + QString GetSourceName(QString station,int matrix,int input); + QString GetDestinationName(QString station,int matrix,int output); + RDListViewItem *GetItem(int id); + int GetMonitor(int serial,int chan); + int GetConnection(QString station,unsigned chan=0); + void LoadGeometry(); + void SaveGeometry(); + std::vector catch_monitor; + QScrollView *catch_monitor_view; + VBox *catch_monitor_vbox; + struct { + RDCatchConnect *connect; + QString station; + vector chan; + vector mon_id; + } catch_connect[RD_MAX_STATIONS]; + int catch_station_count; + QSqlDatabase *catch_db; + int catch_audition_stream; + int catch_play_handle; + CatchListView *catch_recordings_list; + RDTransportButton *catch_head_button; + RDTransportButton *catch_tail_button; + RDTransportButton *catch_stop_button; + QPushButton *catch_add_button; + QPushButton *catch_edit_button; + QPushButton *catch_delete_button; + QPushButton *catch_close_button; + QPushButton *catch_scroll_button; + QPushButton *catch_reports_button; + bool head_playing; + bool tail_playing; + QString catch_filter; + QString catch_group; + QString catch_schedcode; + QPixmap *catch_record_map; + QPixmap *catch_playout_map; + QPixmap *catch_macro_map; + QPixmap *catch_switch_map; + QPixmap *catch_download_map; + QPixmap *catch_upload_map; + QTimer *catch_next_timer; + QPalette catch_scroll_color[2]; + bool catch_scroll; + QLabel *catch_clock_label; + QTimer *catch_clock_timer; + QLabel *catch_show_active_label; + QCheckBox *catch_show_active_box; + QLabel *catch_show_today_label; + QCheckBox *catch_show_today_box; + QLabel *catch_dow_label; + QComboBox *catch_dow_box; + QString catch_filter_string; + QTimer *catch_midnight_timer; + int catch_time_offset; + QPixmap *catch_rivendell_map; + bool catch_host_warnings; +}; + + +#endif diff --git a/rdcatch/rdcatch.pro b/rdcatch/rdcatch.pro new file mode 100644 index 00000000..61b908e1 --- /dev/null +++ b/rdcatch/rdcatch.pro @@ -0,0 +1,58 @@ +# rdcatch.pro +# +# The QMake project file for RDCatch. +# +# (C) Copyright 2003-2005 Fred Gleason +# +# $Id: rdcatch.pro,v 1.9.8.1 2013/01/01 21:36:30 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +x11 { + SOURCES += add_recording.cpp + SOURCES += deckmon.cpp + SOURCES += edit_cartevent.cpp + SOURCES += edit_playout.cpp + SOURCES += edit_recording.cpp + SOURCES += edit_switchevent.cpp + SOURCES += edit_download.cpp + SOURCES += edit_upload.cpp + SOURCES += rdcatch.cpp + SOURCES += list_reports.cpp + SOURCES += catch_listview.cpp +} + +x11 { + HEADERS += add_recording.h + HEADERS += deckmon.h + HEADERS += edit_cartevent.h + HEADERS += edit_playout.h + HEADERS += edit_recording.h + HEADERS += edit_switchevent.h + HEADERS += edit_download.h + HEADERS += edit_upload.h + HEADERS += rdcatch.h + HEADERS += list_reports.h + HEADERS += catch_listview.h +} + +TRANSLATIONS += rdcatch_cs.ts +TRANSLATIONS += rdcatch_de.ts +TRANSLATIONS += rdcatch_es.ts +TRANSLATIONS += rdcatch_fr.ts +TRANSLATIONS += rdcatch_nb.ts +TRANSLATIONS += rdcatch_nn.ts +TRANSLATIONS += rdcatch_pt_BR.ts diff --git a/rdcatch/rdcatch_cs.ts b/rdcatch/rdcatch_cs.ts new file mode 100644 index 00000000..00d3bf53 --- /dev/null +++ b/rdcatch/rdcatch_cs.ts @@ -0,0 +1,1323 @@ + + + AddRecording + + Schedule a: + Rozvrhnout: + + + &Recording + &Nahrávat + + + &Playout + &Přehrávat + + + &Download + &Stáhnout + + + &Upload + &Nahrát + + + &Macro Cart + &Makro vozík + + + &Switch Event + Událost &přepnutí + + + &Cancel + Z&rušit + + + + CatchListView + + Edit Cue Markers + &Upravit značky CUE + + + + DeckMon + + MON + MON + + + ABORT + ZRUŠIT + + + OFFLINE + NEPŘIPOJENÝ + + + L + L + + + R + P + + + IDLE + NEČINNÝ + + + READY + PŘIPRAVENÝ + + + WAITING + ČEKÁNÍ + + + RECORDING + NAHRÁVÁNÍ + + + PLAYING + PŘEHRÁVÁNÍ + + + [multiple events] + [více událostí] + + + [unknown cut] + [neznámý záběr] + + + [no description] + [bez popisu] + + + + EditCartEvent + + Edit Cart Event + Upravit událost vozíku + + + Event Active + Událost činná + + + Location: + Umístění: + + + Start Time: + Počáteční čas: + + + Description: + Popis: + + + Cart Number: + Číslo vozíku: + + + &Select + &Vybrat + + + Active Days + Činné dny + + + Monday + Pondělí + + + Tuesday + Úterý + + + Wednesday + Středa + + + Thursday + Čtvrtek + + + Friday + Pátek + + + Saturday + Sobota + + + Sunday + Neděle + + + Make OneShot + Jen jednou + + + &Save As +New + &Uložit jako +nové + + + &OK + &OK + + + &Cancel + Z&rušit + + + Duplicate Event + Zdvojená událost + + + An event with these parameters already exists! + Událost s těmito parametry již existuje! + + + Invalid Cart + Neplatný vozík + + + That cart doesn't exist! + Vozík neexistuje! + + + + EditDownload + + Edit Download + Upravit stahování + + + Event Active + Událost činná + + + Location: + Umístění: + + + Start Time: + Počáteční čas: + + + Description: + Popis: + + + Url: + Adresa (URL): + + + Username: + Uživatelské jméno: + + + Password: + Heslo: + + + Destination: + Cíl: + + + &Select + &Vybrat + + + Channels: + Kanály: + + + Autotrim + Automatické zastřižení + + + Level: + Úroveň: + + + dBFS + dbFS + + + Normalize + Normalizovat + + + Active Days + Činné dny + + + Monday + Pondělí + + + Tuesday + Úterý + + + Wednesday + Středa + + + Thursday + Čtvrtek + + + Friday + Pátek + + + Saturday + Sobota + + + Sunday + Neděle + + + Make OneShot + Jen jednou + + + &Save As +New + &Uložit jako +nové + + + &OK + &OK + + + &Cancel + Z&rušit + + + Cut + Vyjmout + + + Duplicate Event + Zdvojená událost + + + An event with these parameters already exists! + Událost s těmito parametry již existuje! + + + Invalid URL + Neplatná adresa (URL) + + + The URL is invalid! + Adresa je neplatná! + + + Unsupported URL protocol! + Nepodporovaný protokol URL! + + + Event Offset: + Posun události: + + + days + dny + + + Missing Username + Chybí uživatelské jméno + + + You must specify a username! + Musíte zadat uživatelské jméno! + + + Update Library Metadata + Obnovit knihovní popisná data + + + + EditPlayout + + Edit Playout + Upravit přehrávání + + + Event Active + Událost činná + + + Location: + Umístění: + + + Start Time: + Počáteční čas: + + + Description: + Popis: + + + Destination: + Cíl: + + + &Select + &Vybrat + + + Active Days + Činné dny + + + Monday + Pondělí + + + Tuesday + Úterý + + + Wednesday + Středa + + + Thursday + Čtvrtek + + + Friday + Pátek + + + Saturday + Sobota + + + Sunday + Neděle + + + Make OneShot + Jen jednou + + + &Save As +New + &Uložit jako +nové + + + &OK + &OK + + + &Cancel + Z&rušit + + + Duplicate Event + Zdvojená událost + + + An event with these parameters already exists! + Událost s těmito parametry již existuje! + + + + EditRecording + + Edit Recording + Upravit nahrávání + + + Event Active + Událost činná + + + Location: + Umístění: + + + Start Parameters + Počáteční parametry + + + Use Hard Time + Použít pevný čas + + + Record Start Time: + Počáteční čas nahrávání: + + + Use GPI + Použít GPI + + + Window Start Time: + Počáteční čas okna: + + + GPI Matrix: + Matice GPI: + + + GPI Line: + Řádek GPI: + + + Start Delay: + Zpoždění začátku: + + + Allow Multiple Recordings within this Window + Dovolit v tomto okně více nahrávek + + + End Parameters + Koncové parametry + + + Use Length + Použít délku + + + Record Length: + Délka nahrávání: + + + Record End Time: + Koncový čas nahrávání: + + + Window End Time: + Koncový čas okna: + + + Max Record Length: + Největší délka nahrávání: + + + Description: + Popis: + + + Source: + Zdroj: + + + Destination: + Cíl: + + + &Select + &Vybrat + + + Channels: + Kanály: + + + Autotrim + Automatické zastřižení + + + Level: + Úroveň: + + + dBFS + dbFS + + + Normalize + Normalizovat + + + Active Days + Činné dny + + + Monday + Pondělí + + + Tuesday + Úterý + + + Wednesday + Středa + + + Thursday + Čtvrtek + + + Friday + Pátek + + + Saturday + Sobota + + + Sunday + Neděle + + + Start Date Offset: + Posun počátečního data: + + + None + Žádný + + + End Date Offset: + Posun koncového data: + + + Make OneShot + Jen jednou + + + &Save As +New + &Uložit jako +nové + + + &OK + &OK + + + &Cancel + Z&rušit + + + Cut + Vyjmout + + + Missing Cut + Chybí záběr + + + You must assign a record cut! + Musíte vybrat záběr nahrávání! + + + Record Parameter Error + Chyba v parametru nahrávání + + + The start GPI window cannot end before it begins! + Počáteční okno GPI nemůže skončit předtím, než začne! + + + The recording cannot end before it begins! + Nahrávání nemůže skončit předtím, než začne! + + + The end GPI window cannot end before it begins! + Koncové okno GPI nemůže skončit předtím, než začne! + + + The start GPI matrix doesn't exist! + Počáteční matice GPI neexistuje! + + + The start GPI line doesn't exist! + Počáteční řádek GPI neexistuje! + + + The end GPI matrix doesn't exist! + Koncová matice GPI neexistuje! + + + The end GPI line doesn't exist! + Koncový řádek GPI neexistuje! + + + Duplicate Event + Zdvojená událost + + + An event with these parameters already exists! + Událost s těmito parametry již existuje! + + + + EditSwitchEvent + + Edit Switcher Event + Upravit událost přepínače + + + Event Active + Událost činná + + + Location: + Umístění: + + + Start Time: + Počáteční čas: + + + Description: + Popis: + + + Switch Matrix: + Matice přepnutí: + + + Switch Input: + Vstup přepnutí: + + + Switch Output: + Výstup přepnutí: + + + Active Days + Činné dny + + + Monday + Pondělí + + + Tuesday + Úterý + + + Wednesday + Středa + + + Thursday + Čtvrtek + + + Friday + Pátek + + + Saturday + Sobota + + + Sunday + Neděle + + + Make OneShot + Jen jednou + + + &Save As +New + &Uložit jako +nové + + + &OK + &OK + + + &Cancel + Z&rušit + + + --OFF-- + --VYPNUTO-- + + + Duplicate Event + Zdvojená událost + + + An event with these parameters already exists! + Událost s těmito parametry již existuje! + + + + EditUpload + + Edit Upload + Upravit nahrání + + + Event Active + Událost činná + + + Location: + Umístění: + + + Start Time: + Počáteční čas: + + + [none] + [žádný] + + + RSS Feed: + Přívod RSS: + + + Source: + Zdroj: + + + &Select + &Vybrat + + + Description: + Popis: + + + Url: + Adresa (URL): + + + Username: + Uživatelské jméno: + + + Password: + Heslo: + + + Export Format: + Formát vyvedení: + + + S&et + &Nastavit + + + Normalize + Normalizovat + + + Level: + Úroveň: + + + dBFS + dbFS + + + Active Days + Činné dny + + + Monday + Pondělí + + + Tuesday + Úterý + + + Wednesday + Středa + + + Thursday + Čtvrtek + + + Friday + Pátek + + + Saturday + Sobota + + + Sunday + Neděle + + + Make OneShot + Jen jednou + + + &Save As +New + &Uložit jako +nové + + + &OK + &OK + + + &Cancel + Z&rušit + + + Unsupported Format + Nepodporovaný formát + + + The currently selected export format is unsupported on this host! + Nyní vybraný formát vyvedení není tímto serverem podporován! + + + Cut + Vyjmout + + + Duplicate Event + Zdvojená událost + + + An event with these parameters already exists! + Událost s těmito parametry již existuje! + + + The currently selected export format is unsupported on host + Nyní vybraný formát vyvedení není podporován serverem + + + Invalid URL + Neplatná adresa (URL) + + + The URL is invalid! + Adresa je neplatná! + + + Unsupported URL protocol! + Nepodporovaný protokol URL! + + + Event Offset: + Posun události: + + + days + dny + + + Missing Username + Chybí uživatelské jméno + + + You must specify a username! + Musíte zadat uživatelské jméno! + + + Export Library Metadata + Vyvést knihovní popisná data + + + + ListReports + + RDLibrary Reports + Zprávy RDLibrary + + + Event Report + Zpráva o události + + + Upload/Download Report + Nahrát/Stáhnout zprávu + + + Type: + Typ: + + + &Generate + Vy&tvořit: + + + &Close + &Zavřít + + + + MainWidget + + RDCatch - Host: + RDCatch - Server: + + + rdcatch : + rdcatch: + + + Show Only Active Events + Ukázat pouze činné události + + + Show Only Today's Events + Ukázat pouze dnešní události + + + Show DayOfWeek: + Ukázat dny v týdnu: + + + All + Vše + + + Weekdays + Dny v týdnu + + + Sunday + Neděle + + + Monday + Pondělí + + + Tuesday + Úterý + + + Wednesday + Středa + + + Thursday + Čtvrtek + + + Friday + Pátek + + + Saturday + Sobota + + + DESCRIPTION + POPIS + + + LOCATION + UMÍSTĚNÍ + + + START + ZAČÁTEK + + + END + KONEC + + + SOURCE + ZDROJ + + + DESTINATION + CÍL + + + ORIGIN + PŮVOD + + + ONE SHOT + JEDNOU + + + TRIM THRESHOLD + PRÁH ZASTŘIŽENÍ + + + STARTDATE OFFSET + POSUN POČÁTEČNÍHO DATA + + + ENDDATE OFFSET + POSUN KONCOVÉHO DATA + + + FORMAT + FORMÁT + + + CHANNELS + KANÁLY + + + SAMPLE RATE + VZORKOVACÍ KMITOČET + + + BIT RATE + DATOVÝ TOK + + + STATION + STANICE + + + DECK + PATRO + + + CUT + ZÁBĚR + + + CART + VOZÍK + + + ID + ID + + + TYPE + TYP + + + STATUS + STAV + + + EXIT CODE + UKONČOVACÍ KÓD + + + STATE + STAV + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + Scroll + Projíždět + + + Reports + Zprávy + + + &Close + &Zavřít + + + Event Active + Událost činná + + + You cannot edit an active event! + Nemůžete upravovat činnou událost! + + + Are you sure you want to delete event + Jste si jistý, že chcete smazat událost + + + Delete Event + Smazat událost + + + Can't Connect + Nelze spojit + + + Unable to connect to Core AudioEngine + Spojení s Core AudioEngine se nezdařilo + + + Control connection timed out to host + Kontrolní spojení k serveru vypršelo + + + Su + Ne + + + Mo + Po + + + Tu + Út + + + We + St + + + Th + Čt + + + Fr + + + + Sa + So + + + dB + dB + + + Hard + Ostré + + + Gpi + GPI + + + Len + Délka + + + Cut + Záběr + + + PCM16 + PCM16 + + + MPEG Layer 1 + MPEG Layer 1 + + + MPEG Layer 2 + MPEG Layer 2 + + + MPEG Layer 3 + MPEG Layer 3 + + + FLAC + FLAC + + + OggVorbis + OggVorbis + + + Cart + Vozík + + + [none] + [žádný] + + + OK + OK + + + Short Length + Kurze Länge + + + Low Level + Niedriges Level + + + High Level + Hohes Level + + + Downloading + Herunterladen + + + Uploading + Hochladen + + + Recording + Aufnehmen + + + Playing + Abspielen + + + Waiting + Warten + + + Server Error + Serverfehler + + + Internal Error + Interner Fehler + + + Interrupted + Unterbrochen + + + Device Busy + Gerät beschäftigt + + + No Such Cart/Cut + Kein solcher Cart/Cut + + + Unknown + Neznámý + + + Host + + + + User + + + + diff --git a/rdcatch/rdcatch_de.ts b/rdcatch/rdcatch_de.ts new file mode 100644 index 00000000..d967d417 --- /dev/null +++ b/rdcatch/rdcatch_de.ts @@ -0,0 +1,1323 @@ + + + AddRecording + + Schedule a: + Plane eine(n): + + + &Recording + &Aufnahme + + + &Playout + A&bspielen + + + &Download + &Herunterladen + + + &Upload + H&ochladen + + + &Macro Cart + &Makro Cart + + + &Switch Event + &Switch Event + + + &Cancel + Abbre&chen + + + + CatchListView + + Edit Cue Markers + Cue Marker editieren + + + + DeckMon + + MON + MON + + + ABORT + ABBRECHEN + + + OFFLINE + OFFLINE + + + L + L + + + R + R + + + IDLE + LEERLAUF + + + READY + FERTIG + + + WAITING + WARTEN + + + RECORDING + AUFNAHME + + + PLAYING + ABSPIELEN + + + [multiple events] + [mehrere events] + + + [unknown cut] + [unbekannter cut] + + + [no description] + [keine beschreibung] + + + + EditCartEvent + + Edit Cart Event + Cart Event editieren + + + Event Active + Event Aktiv + + + Location: + Ort: + + + Start Time: + Startzeit: + + + Description: + Beschreibung: + + + Cart Number: + Cart-Nummer: + + + &Select + Au&swählen + + + Active Days + Aktive Tage + + + Monday + Montag + + + Tuesday + Dienstag + + + Wednesday + Mittwoch + + + Thursday + Donnerstag + + + Friday + Freitag + + + Saturday + Samstag + + + Sunday + Sonntag + + + Make OneShot + Nur Einmal + + + &Save As +New + &Speichern als +Neu + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Duplicate Event + Doppeltes Event + + + An event with these parameters already exists! + Ein Event mit diesen Parametern existiert bereits! + + + Invalid Cart + Ungültiger Cart + + + That cart doesn't exist! + Dieser Cart existiert nicht! + + + + EditDownload + + Edit Download + Download editieren + + + Event Active + Event aktiv + + + Location: + Ort: + + + Start Time: + Startzeit: + + + Description: + Beschreibung: + + + Url: + URL: + + + Username: + Benutzername: + + + Password: + Passwort: + + + Destination: + Ziel: + + + &Select + Au&swählen + + + Channels: + Kanäle: + + + Autotrim + Autotrim + + + Level: + Level: + + + dBFS + dBFS + + + Normalize + Normalisieren + + + Active Days + Aktive Tage + + + Monday + Montag + + + Tuesday + Dienstag + + + Wednesday + Mittwoch + + + Thursday + Donnerstag + + + Friday + Freitag + + + Saturday + Samstag + + + Sunday + Sonntag + + + Make OneShot + Nur Einmal + + + &Save As +New + &Speichern als +Neu + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Cut + Cut + + + Duplicate Event + Doppeltes Event + + + An event with these parameters already exists! + Ein Event mit diesen Parametern existiert bereits! + + + Invalid URL + Ungültige URL + + + The URL is invalid! + Die URL ist ungültig! + + + Unsupported URL protocol! + Nicht unterstütztes URL-Protokoll! + + + Event Offset: + Event-Abstand: + + + days + Tage + + + Missing Username + FehlenderBenutzername + + + You must specify a username! + Sie müssen einen Benutzernamen angeben! + + + Update Library Metadata + Bibliotheksmetadaten updaten + + + + EditPlayout + + Edit Playout + Auspielung editieren + + + Event Active + Event aktiv + + + Location: + Ort: + + + Start Time: + Startzeit: + + + Description: + Beschreibung: + + + Destination: + Ziel: + + + &Select + Au&swählen + + + Active Days + Aktive Tage + + + Monday + Montag + + + Tuesday + Dienstag + + + Wednesday + Mittwoch + + + Thursday + Donnerstag + + + Friday + Freitag + + + Saturday + Samstag + + + Sunday + Sonntag + + + Make OneShot + Nur Einmal + + + &Save As +New + &Speichern als +Neu + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Duplicate Event + Doppeltes Event + + + An event with these parameters already exists! + Ein Event mit diesen Parametern existiert bereits! + + + + EditRecording + + Edit Recording + Aufnahme editieren + + + Event Active + Event aktiv + + + Location: + Ort: + + + Start Parameters + Startparameter + + + Use Hard Time + Feste Zeit verwenden + + + Record Start Time: + Aufnahmestartzeit: + + + Use GPI + GPI verwenden + + + Window Start Time: + Fensterstartzeit: + + + GPI Matrix: + GPI Matrix: + + + GPI Line: + GPI-Line: + + + Start Delay: + Startverzögerung: + + + Allow Multiple Recordings within this Window + Mehrfache Aufnahmen in diesem Fenster erlauben + + + End Parameters + Endparameter + + + Use Length + Verwende Länge + + + Record Length: + Aufnahmelänge: + + + Record End Time: + Aufnahmeendzeit: + + + Window End Time: + Fensterendzeit: + + + Max Record Length: + Maximale Aufnahmelänge: + + + Description: + Beschreibung: + + + Source: + Quelle: + + + Destination: + Ziel: + + + &Select + Au&swählen + + + Channels: + Kanäle: + + + Autotrim + Autotrim + + + Level: + Level: + + + dBFS + dBFS + + + Normalize + Normalisieren + + + Active Days + Aktive Tage + + + Monday + Montag + + + Tuesday + Dienstag + + + Wednesday + Mittwoch + + + Thursday + Donnerstag + + + Friday + Freitag + + + Saturday + Samstag + + + Sunday + Sonntag + + + Start Date Offset: + Startdatums-Abstand: + + + None + Keine + + + End Date Offset: + Enddatums-Abstand: + + + Make OneShot + Nur Einmal + + + &Save As +New + &Speichern als +Neu + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Cut + CUT + + + Missing Cut + Cut fehlt + + + You must assign a record cut! + Sie müssen einen Aufnahme-Cut auswählen! + + + Record Parameter Error + Aufnahmeparameter-Fehler + + + The start GPI window cannot end before it begins! + Das Start-GPI-Fenster kann nicht enden, bevor es anfängt! + + + The recording cannot end before it begins! + Die Aufnahme kann nicht enden, bevor sie anfängt! + + + The end GPI window cannot end before it begins! + Das End-GPI-Fenster kann nicht enden, bevor es anfängt! + + + The start GPI matrix doesn't exist! + Die Start-GPI-Matrix existiert nicht! + + + The start GPI line doesn't exist! + Die Start-GPI-LINE existiert nicht! + + + The end GPI matrix doesn't exist! + Die End-GPI-Matrix existiert nicht! + + + The end GPI line doesn't exist! + Die End-GPI-Line existiert nicht! + + + Duplicate Event + Doppeltes Event + + + An event with these parameters already exists! + Ein Event mit diesen Parametern existiert bereits! + + + + EditSwitchEvent + + Edit Switcher Event + Switcher-Event editieren + + + Event Active + Event aktiv + + + Location: + Ort: + + + Start Time: + Startzeit: + + + Description: + Beschreibung: + + + Switch Matrix: + Switch-Matrix: + + + Switch Input: + Switch-Input: + + + Switch Output: + Switch-Output: + + + Active Days + Aktive Tage + + + Monday + Montag + + + Tuesday + Dienstag + + + Wednesday + Mittwoch + + + Thursday + Donnerstag + + + Friday + Freitag + + + Saturday + Samstag + + + Sunday + Sonntag + + + Make OneShot + Nur Einmal + + + &Save As +New + &Speichern als +Neu + + + &OK + &OK + + + &Cancel + Abbre&chen + + + --OFF-- + --AUS-- + + + Duplicate Event + Doppeltes Event + + + An event with these parameters already exists! + Ein Event mit diesen Parametern existiert bereits! + + + + EditUpload + + Edit Upload + Hochladen editieren + + + Event Active + Event aktiv + + + Location: + Ort: + + + Start Time: + Startzeit: + + + [none] + [keine] + + + RSS Feed: + RSS Feed: + + + Source: + Quelle: + + + &Select + Au&swählen + + + Description: + Beschreibung: + + + Url: + URL: + + + Username: + Benutzername: + + + Password: + Passwort: + + + Export Format: + Exportformat: + + + S&et + S&etzen + + + Normalize + Normalisieren + + + Level: + Level: + + + dBFS + dBFS + + + Active Days + Aktive Tage + + + Monday + Montag + + + Tuesday + Dienstag + + + Wednesday + Mittwoch + + + Thursday + Donnerstag + + + Friday + Freitag + + + Saturday + Samstag + + + Sunday + Sonntag + + + Make OneShot + Nur Einmal + + + &Save As +New + &Speichern als +Neu + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Unsupported Format + Nicht unterstützes Format + + + The currently selected export format is unsupported on this host! + Das derzeit ausgewählte Exportformat wird auf diesem Host nicht unterstützt! + + + Cut + CUT + + + Duplicate Event + Doppeltes Event + + + An event with these parameters already exists! + Ein Event mit diesen Parametern existiert bereits! + + + The currently selected export format is unsupported on host + Das derzeit ausgewählte Exportformat wird auf diesem Host nicht unterstützt + + + Invalid URL + Ungültige URL + + + The URL is invalid! + Die URL ist ungültig! + + + Unsupported URL protocol! + Nicht unterstütztes URL-Protokoll! + + + Event Offset: + Event-Abstand: + + + days + Tage + + + Missing Username + FehlenderBenutzername + + + You must specify a username! + Sie müssen einen Benutzernamen angeben! + + + Export Library Metadata + Bibliotheksmetadaten exportieren + + + + ListReports + + RDLibrary Reports + RDLibrary Reports + + + Event Report + Event Report + + + Upload/Download Report + Upload/Download-Report + + + Type: + Typ: + + + &Generate + &Generieren + + + &Close + S&chließen + + + + MainWidget + + RDCatch - Host: + RDCatch - Host: + + + rdcatch : + rdcatch : + + + Show Only Active Events + Nur aktive Events zeigen + + + Show Only Today's Events + Nur heutige Events zeigen + + + Show DayOfWeek: + Wochentage anzeigen: + + + All + Alle + + + Weekdays + Wochentage + + + Sunday + Sonntag + + + Monday + Montag + + + Tuesday + Dienstag + + + Wednesday + Mittwoch + + + Thursday + Donnerstag + + + Friday + Freitag + + + Saturday + Samstag + + + DESCRIPTION + BESCHREIBUNG + + + LOCATION + ORT + + + START + START + + + END + ENDE + + + SOURCE + QUELLE + + + DESTINATION + ZIEL + + + ORIGIN + HERKUNFT + + + ONE SHOT + EINMAL + + + TRIM THRESHOLD + TRIM THRESHOLD + + + STARTDATE OFFSET + Startdatums-Abstand + + + ENDDATE OFFSET + Enddatums-Abstand + + + FORMAT + FORMAT + + + CHANNELS + KANÄLE + + + SAMPLE RATE + SAMPLE RATE + + + BIT RATE + BITRATE + + + STATION + STATION + + + DECK + DECK + + + CUT + CUT + + + CART + CART + + + ID + ID + + + TYPE + TYP + + + STATUS + STATUS + + + EXIT CODE + EXIT CODE + + + STATE + ZUSTAND + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + Scroll + Scrollen + + + Reports + Reporte + + + &Close + S&chliessen + + + Event Active + Event aktiv + + + You cannot edit an active event! + Sie können kein aktives event editieren! + + + Are you sure you want to delete event + Sind sie sicher, daß sie das Event löschen wollen + + + Delete Event + Event löschen + + + Can't Connect + kann nicht verbinden + + + Unable to connect to Core AudioEngine + Verbindung zur Core AudioEngine fehlgeschlagen + + + Control connection timed out to host + Kontrollverbindungs-TimeOut zum Host + + + Su + So + + + Mo + Mo + + + Tu + Di + + + We + Mi + + + Th + Do + + + Fr + fr + + + Sa + Sa + + + dB + dB + + + Hard + Hard + + + Gpi + Gpi + + + Len + Länge + + + Cut + Cut + + + PCM16 + PCM16 + + + MPEG Layer 1 + MPEG Layer 1 + + + MPEG Layer 2 + MPEG Layer 2 + + + MPEG Layer 3 + MPEG Layer 3 + + + FLAC + FLAC + + + OggVorbis + OggVorbis + + + Cart + Cart + + + [none] + [keine] + + + OK + OK + + + Short Length + Kurze Länge + + + Low Level + Niedriges Level + + + High Level + Hohes Level + + + Downloading + Herunterladen + + + Uploading + Hochladen + + + Recording + Aufnehmen + + + Playing + Abspielen + + + Waiting + Warten + + + Server Error + Serverfehler + + + Internal Error + Interner Fehler + + + Interrupted + Unterbrochen + + + Device Busy + Gerät beschäftigt + + + No Such Cart/Cut + Kein solcher Cart/Cut + + + Unknown + Unbekannt + + + Host + + + + User + + + + diff --git a/rdcatch/rdcatch_es.ts b/rdcatch/rdcatch_es.ts new file mode 100644 index 00000000..fc7e92f9 --- /dev/null +++ b/rdcatch/rdcatch_es.ts @@ -0,0 +1,1267 @@ + + + AddRecording + + Schedule a: + Programar: + + + &Recording + &Grabación + + + &Playout + &Reproducción + + + &Macro Cart + Cartucho &Macro + + + &Switch Event + &Evento con la Suichera + + + &Cancel + &Cancelar + + + &Download + &Descarga + + + &Upload + &Subida + + + + CatchListView + + Edit Cue Markers + Editar marcadores Cue + + + + DeckMon + + MON + MON + + + ABORT + ABORTAR + + + OFFLINE + OFFLINE + + + L + Iz + + + R + De + + + IDLE + IDLE + + + READY + LISTO + + + WAITING + ESPERA + + + RECORDING + GRABANDO + + + PLAYING + REPROD + + + [no description] + [sin descripción] + + + [multiple events] + [múltiples eventos] + + + [unknown cut] + [audio desconocido] + + + + EditCartEvent + + Edit Cart Event + Editar evento de cartucho + + + Event Active + Evento activo + + + Location: + Ubicación: + + + Start Time: + Hora inicio: + + + Description: + Descripción: + + + Cart Number: + Nro. cartucho: + + + &Select + &Seleccionar + + + Active Days + Días activos + + + Monday + Lunes + + + Tuesday + Martes + + + Wednesday + Miércoles + + + Thursday + Jueves + + + Friday + Viernes + + + Saturday + Sábado + + + Sunday + Domingo + + + Make OneShot + Una sola vez + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Cart + Cartucho inválido + + + That cart doesn't exist! + ¡El cartucho no existe! + + + Duplicate Event + Evento duplicado + + + An event with these parameters already exists! + ¡Un evento con esos parámetros ya existe! + + + &Save As +New + &Guardar +como nuevo + + + + EditDownload + + Edit Download + Edtar Descarga + + + Event Active + Evento Activo + + + Location: + Ubicación: + + + Start Time: + Hora Inicio: + + + Description: + Descripción: + + + Url: + Url: + + + Username: + Usuario: + + + Password: + Contraseña: + + + Destination: + Destino: + + + &Select + &Seleccionar + + + Active Days + Días activo + + + Monday + Lunes + + + Tuesday + Martes + + + Wednesday + Miércoles + + + Thursday + Jueves + + + Friday + Viernes + + + Saturday + Sábado + + + Sunday + + + + Make OneShot + Una sola vez + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Cut + Audio + + + Invalid URL + URL inválido + + + The URL is invalid! + ¡El URL es inválido! + + + Unsupported URL protocol! + ¡Protocolo de URL no soportado! + + + Duplicate Event + Evento duplicado + + + An event with these parameters already exists! + ¡Un evento con esos parámetros ya existe! + + + &Save As +New + &Guardar +como Nuevo + + + Autotrim + Autorecortar + + + Level: + Nivel: + + + dBFS + dBFS + + + Normalize + Normalizar + + + Channels: + Canales: + + + Event Offset: + Desplaz.Evento: + + + days + días + + + Missing Username + Falta el usuario + + + You must specify a username! + ¡Debe especificar un nombre de usuario! + + + Update Library Metadata + Actualizar metadatos en biblioteca + + + + EditPlayout + + Edit Playout + Editar Reproducción + + + Event Active + Evento activo + + + Location: + Ubicación: + + + Start Time: + Hora Inicio: + + + Description: + Descripción: + + + Destination: + Destino: + + + &Select + &Seleccionar + + + Active Days + Días Activo + + + Monday + Lunes + + + Tuesday + Martes + + + Wednesday + Miércoles + + + Thursday + Jueves + + + Friday + Viernes + + + Saturday + Sábado + + + Sunday + Domingo + + + Make OneShot + Una sola vez + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Duplicate Event + Evento duplicado + + + An event with these parameters already exists! + ¡Un evento con esos parámetros ya existe! + + + &Save As +New + &Guardar +como Nuevo + + + + EditRecording + + Edit Recording + Edtar Grabación + + + Event Active + Evento activo + + + Location: + Ubicación: + + + Start Parameters + Parámetros de Inicio + + + Use Hard Time + Hora estricta + + + Record Start Time: + Inicio de grabación: + + + Use GPI + Usar GPI + + + Window Start Time: + Margen de inicio: + + + GPI Matrix: + Matriz GPI: + + + GPI Line: + Línea GPI: + + + Start Delay: + Demora en Inicio: + + + End Parameters + Parámetros de Fin + + + Use Length + Usar duración + + + Record Length: + Duración de Grabación: + + + Record End Time: + Hora fin de grabación: + + + Window End Time: + Margen de fin: + + + Description: + Descripción: + + + Source: + Fuente: + + + Destination: + Destino: + + + &Select + &Seleccionar + + + Active Days + Días activo + + + Monday + Lunes + + + Tuesday + Martes + + + Wednesday + Miércoles + + + Thursday + Jueves + + + Friday + Viernes + + + Saturday + Sábado + + + Sunday + Domingo + + + Start Date Offset: + Desplaz. Fecha Inicio: + + + None + Nada + + + End Date Offset: + Desplaz. Fecha Fin: + + + Channels: + Canales: + + + Make OneShot + Una sola vez + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Cut + Audio + + + Missing Cut + Audio no encontrado + + + You must assign a record cut! + ¡Debe asignar un audio para la grabación! + + + Record Parameter Error + Error de parámetros de la grabación + + + The start GPI window cannot end before it begins! + ¡La ventana GPI inicial no puede terminar antes de que empiece! + + + The recording cannot end before it begins! + ¡La grabación no puede terminar antes de que empiece! + + + The end GPI window cannot end before it begins! + ¡La ventana GPI final no puede terminar antes de que empiece! + + + The start GPI matrix doesn't exist! + ¡La matriz GPI de inicio no existe! + + + The start GPI line doesn't exist! + ¡La línea GPI de inicio no existe! + + + The end GPI matrix doesn't exist! + ¡La matriz GPI final no existe! + + + The end GPI line doesn't exist! + ¡La línea GPi final no existe! + + + &Save As +New + &Guardar +como Nuevo + + + Duplicate Event + Evento duplicado + + + An event with these parameters already exists! + ¡Un evento con esos parámetros ya existe! + + + Max Record Length: + Máx Duración de la Grabación: + + + Allow Multiple Recordings within this Window + Permitir múltiples grabaciones en esta ventana + + + Autotrim + Autorecortar + + + Level: + Nivel: + + + dBFS + dBFS + + + Normalize + Normalizar + + + + EditSwitchEvent + + Edit Switcher Event + Editar Eventos de Suichera + + + Event Active + Evento Activo + + + Location: + Ubicación: + + + Start Time: + Tiempo Inicio: + + + Description: + Descripción: + + + Switch Matrix: + Matriz de Suich.: + + + Switch Input: + Entrada de Suich.: + + + Switch Output: + Salida de Suich.: + + + Active Days + Días Activo + + + Monday + Lunes + + + Tuesday + Martes + + + Wednesday + Miércoles + + + Thursday + Jueves + + + Friday + Viernes + + + Saturday + Sábado + + + Sunday + Domingo + + + Make OneShot + Una sola vez + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Duplicate Event + Evento duplicado + + + An event with these parameters already exists! + ¡Un evento con esos parámetros ya existe! + + + &Save As +New + &Guardar +como Nuevo + + + --OFF-- + --APAGADO-- + + + + EditUpload + + Edit Upload + Editar Subida + + + Event Active + Evento Activo + + + Location: + Ubicación: + + + Start Time: + Tiempo de Inicio: + + + Source: + Fuente: + + + &Select + &Seleccionar + + + Description: + Descripción: + + + Url: + Url: + + + Username: + Usuario: + + + Password: + Contraseña: + + + S&et + Po&ner + + + Active Days + Días activos + + + Monday + Lunes + + + Tuesday + Martes + + + Wednesday + Miércoles + + + Thursday + Jueves + + + Friday + Viernes + + + Saturday + Sábado + + + Sunday + + + + Make OneShot + Una sola vez + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Cut + Audio + + + Invalid URL + URL inválido + + + The URL is invalid! + ¡El URL es inválido! + + + Unsupported URL protocol! + ¡Protocolo de URL no soportado! + + + Export Format: + Formato Exportac.: + + + Unsupported Format + Formato no soportado + + + The currently selected export format is unsupported on this host! + ¡El formato seleccionado no está soportado por este equipo! + + + The currently selected export format is unsupported on host + El formato de exportación seleccionado no está soportado en el equipo + + + Normalize + Normalizar + + + Level: + Nivel: + + + dBFS + dBFS + + + &Save As +New + &Guardar +como Nuevo + + + Duplicate Event + Evento duplicado + + + An event with these parameters already exists! + ¡Un evento con esos parámetros ya existe! + + + RSS Feed: + Flujo RSS: + + + [none] + [ninguno] + + + Event Offset: + Desplaz. Evento: + + + days + días + + + Missing Username + Falta el usuario + + + You must specify a username! + ¡Debe especificar un nombre de usuario! + + + Export Library Metadata + Exportar Bibliot. Metadatos + + + + ListReports + + RDLibrary Reports + Reportes RDLibrary + + + Type: + Tipo: + + + &Generate + &Generar + + + &Close + &Cerrar + + + Event Report + Reporte de Evento + + + Upload/Download Report + Reporte Subidas/Descargas + + + + MainWidget + + RDCatch - Host: + RDCatch - Computador: + + + Can't Connect + No puedo conectarme + + + Show Only Active Events + Ver sólo eventos activos + + + Show Only Today's Events + Ver sólo eventos de hoy + + + Show DayOfWeek: + Mostrar Día de Semana: + + + All + Todo + + + Weekdays + Días de semana + + + Sunday + Domingo + + + Monday + Lunes + + + Tuesday + Martes + + + Wednesday + Miércoles + + + Thursday + Jueves + + + Friday + Viernes + + + Saturday + Sábado + + + DESCRIPTION + DESCRIPCIÓN + + + LOCATION + UBICACIÓN + + + START + INICIO + + + END + FIN + + + SOURCE + FUENTE + + + DESTINATION + DESTINO + + + ONE SHOT + UNA VEZ + + + TRIM THRESHOLD + RECORTAR NIVEL + + + STARTDATE OFFSET + DESPLAZ. FECHA INICIO + + + ENDDATE OFFSET + DESPLAZ. FECHA FIN + + + FORMAT + FORMATO + + + CHANNELS + CANALES + + + SAMPLE RATE + TASA DE SAMPLEO + + + BIT RATE + TASA DE BITS + + + STATION + ESTACIÓN + + + DECK + DECK + + + CUT + AUDIO + + + CART + CARTUCHO + + + ID + ID + + + TYPE + TIPO + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + &Borrar + + + Scroll + Deslizar + + + &Close + &Cerrar + + + Are you sure you want to delete event + Desea borrar el evento + + + Delete Event + Borrar evento + + + Control connection timed out to host + La conexión de control no pudo realizarse + + + Su + Do + + + Mo + Lu + + + Tu + Ma + + + We + Mi + + + Th + Ju + + + Fr + Vi + + + Sa + Sa + + + dB + dB + + + Hard + Estricto + + + Gpi + Gpi + + + Len + Lon + + + Cut + Audio + + + Cart + Cartucho + + + ORIGIN + ORIGEN + + + STATUS + ESTADO + + + PCM16 + + + + MPEG Layer 1 + + + + MPEG Layer 2 + + + + MPEG Layer 3 + + + + FLAC + + + + OggVorbis + + + + STATE + ESTADO + + + Event Active + Evento activo + + + You cannot edit an active event! + ¡No puede editar un evento activo! + + + EXIT CODE + COD DE SALIDA + + + Unable to connect to Core AudioEngine + No pude conectar al Core AudioEngine + + + Reports + Reportes + + + [none] + [ninguno] + + + rdcatch : + rdcatch : + + + Unknown + Desconocido + + + Host + + + + User + + + + diff --git a/rdcatch/rdcatch_fr.ts b/rdcatch/rdcatch_fr.ts new file mode 100644 index 00000000..9c8932dd --- /dev/null +++ b/rdcatch/rdcatch_fr.ts @@ -0,0 +1,1257 @@ + + + AddRecording + + Schedule a: + + + + &Recording + + + + &Playout + + + + &Download + + + + &Upload + + + + &Macro Cart + + + + &Switch Event + + + + &Cancel + + + + + CatchListView + + Edit Cue Markers + + + + + DeckMon + + MON + + + + ABORT + + + + OFFLINE + + + + L + + + + R + + + + IDLE + + + + READY + + + + WAITING + + + + RECORDING + + + + PLAYING + + + + [multiple events] + + + + [unknown cut] + + + + [no description] + + + + + EditCartEvent + + Edit Cart Event + + + + Event Active + + + + Location: + + + + Start Time: + + + + Description: + + + + Cart Number: + + + + &Select + + + + Active Days + + + + Monday + + + + Tuesday + + + + Wednesday + + + + Thursday + + + + Friday + + + + Saturday + + + + Sunday + + + + Make OneShot + + + + &Save As +New + + + + &OK + + + + &Cancel + + + + Duplicate Event + + + + An event with these parameters already exists! + + + + Invalid Cart + + + + That cart doesn't exist! + + + + + EditDownload + + Edit Download + + + + Event Active + + + + Location: + + + + Start Time: + + + + Description: + + + + Url: + + + + Username: + + + + Password: + + + + Destination: + + + + &Select + + + + Channels: + + + + Autotrim + + + + Level: + + + + dBFS + + + + Normalize + + + + Active Days + + + + Monday + + + + Tuesday + + + + Wednesday + + + + Thursday + + + + Friday + + + + Saturday + + + + Sunday + + + + Make OneShot + + + + &Save As +New + + + + &OK + + + + &Cancel + + + + Cut + + + + Duplicate Event + + + + An event with these parameters already exists! + + + + Invalid URL + + + + The URL is invalid! + + + + Unsupported URL protocol! + + + + Event Offset: + + + + days + + + + Missing Username + + + + You must specify a username! + + + + Update Library Metadata + + + + + EditPlayout + + Edit Playout + + + + Event Active + + + + Location: + + + + Start Time: + + + + Description: + + + + Destination: + + + + &Select + + + + Active Days + + + + Monday + + + + Tuesday + + + + Wednesday + + + + Thursday + + + + Friday + + + + Saturday + + + + Sunday + + + + Make OneShot + + + + &Save As +New + + + + &OK + + + + &Cancel + + + + Duplicate Event + + + + An event with these parameters already exists! + + + + + EditRecording + + Edit Recording + + + + Event Active + + + + Location: + + + + Start Parameters + + + + Use Hard Time + + + + Record Start Time: + + + + Use GPI + + + + Window Start Time: + + + + GPI Matrix: + + + + GPI Line: + + + + Start Delay: + + + + Allow Multiple Recordings within this Window + + + + End Parameters + + + + Use Length + + + + Record Length: + + + + Record End Time: + + + + Window End Time: + + + + Max Record Length: + + + + Description: + + + + Source: + + + + Destination: + + + + &Select + + + + Channels: + + + + Autotrim + + + + Level: + + + + dBFS + + + + Normalize + + + + Active Days + + + + Monday + + + + Tuesday + + + + Wednesday + + + + Thursday + + + + Friday + + + + Saturday + + + + Sunday + + + + Start Date Offset: + + + + None + + + + End Date Offset: + + + + Make OneShot + + + + &Save As +New + + + + &OK + + + + &Cancel + + + + Cut + + + + Missing Cut + + + + You must assign a record cut! + + + + Record Parameter Error + + + + The start GPI window cannot end before it begins! + + + + The recording cannot end before it begins! + + + + The end GPI window cannot end before it begins! + + + + The start GPI matrix doesn't exist! + + + + The start GPI line doesn't exist! + + + + The end GPI matrix doesn't exist! + + + + The end GPI line doesn't exist! + + + + Duplicate Event + + + + An event with these parameters already exists! + + + + + EditSwitchEvent + + Edit Switcher Event + + + + Event Active + + + + Location: + + + + Start Time: + + + + Description: + + + + Switch Matrix: + + + + Switch Input: + + + + Switch Output: + + + + Active Days + + + + Monday + + + + Tuesday + + + + Wednesday + + + + Thursday + + + + Friday + + + + Saturday + + + + Sunday + + + + Make OneShot + + + + &Save As +New + + + + &OK + + + + &Cancel + + + + --OFF-- + + + + Duplicate Event + + + + An event with these parameters already exists! + + + + + EditUpload + + Edit Upload + + + + Event Active + + + + Location: + + + + Start Time: + + + + [none] + + + + RSS Feed: + + + + Source: + + + + &Select + + + + Description: + + + + Url: + + + + Username: + + + + Password: + + + + Export Format: + + + + S&et + + + + Normalize + + + + Level: + + + + dBFS + + + + Active Days + + + + Monday + + + + Tuesday + + + + Wednesday + + + + Thursday + + + + Friday + + + + Saturday + + + + Sunday + + + + Make OneShot + + + + &Save As +New + + + + &OK + + + + &Cancel + + + + Unsupported Format + + + + The currently selected export format is unsupported on this host! + + + + Cut + + + + Duplicate Event + + + + An event with these parameters already exists! + + + + The currently selected export format is unsupported on host + + + + Invalid URL + + + + The URL is invalid! + + + + Unsupported URL protocol! + + + + Event Offset: + + + + days + + + + Missing Username + + + + You must specify a username! + + + + Export Library Metadata + + + + + ListReports + + RDLibrary Reports + + + + Event Report + + + + Upload/Download Report + + + + Type: + + + + &Generate + + + + &Close + + + + + MainWidget + + rdcatch : + + + + Show Only Active Events + + + + Show Only Today's Events + + + + Show DayOfWeek: + + + + All + + + + Weekdays + + + + Sunday + + + + Monday + + + + Tuesday + + + + Wednesday + + + + Thursday + + + + Friday + + + + Saturday + + + + DESCRIPTION + + + + LOCATION + + + + START + + + + END + + + + SOURCE + + + + DESTINATION + + + + ORIGIN + + + + ONE SHOT + + + + TRIM THRESHOLD + + + + STARTDATE OFFSET + + + + ENDDATE OFFSET + + + + FORMAT + + + + CHANNELS + + + + SAMPLE RATE + + + + BIT RATE + + + + STATION + + + + DECK + + + + CUT + + + + CART + + + + ID + + + + TYPE + + + + STATUS + + + + EXIT CODE + + + + STATE + + + + &Add + + + + &Edit + + + + &Delete + + + + Scroll + + + + Reports + + + + &Close + + + + Event Active + + + + You cannot edit an active event! + + + + Are you sure you want to delete event + + + + Delete Event + + + + Can't Connect + + + + Unable to connect to Core AudioEngine + + + + Control connection timed out to host + + + + Su + + + + Mo + + + + Tu + + + + We + + + + Th + + + + Fr + + + + Sa + + + + dB + + + + Hard + + + + Gpi + + + + Len + + + + Cut + + + + PCM16 + + + + MPEG Layer 1 + + + + MPEG Layer 2 + + + + MPEG Layer 3 + + + + FLAC + + + + OggVorbis + + + + Cart + + + + [none] + + + + Unknown + + + + Host + + + + User + + + + diff --git a/rdcatch/rdcatch_nb.ts b/rdcatch/rdcatch_nb.ts new file mode 100644 index 00000000..708103d5 --- /dev/null +++ b/rdcatch/rdcatch_nb.ts @@ -0,0 +1,1320 @@ + + + AddRecording + + Schedule a: + Køyreplan a: + + + &Recording + &Opptak + + + &Playout + &Utspeling + + + &Download + &Nedlasting + + + &Upload + &Opplasting + + + &Macro Cart + &Makrovogn + + + &Switch Event + &Byt hending + + + &Cancel + &Avbryt + + + + CatchListView + + Edit Cue Markers + Rediger cue-markørar + + + + DeckMon + + MON + MON + + + ABORT + AVBRYT + + + OFFLINE + AVLINJE + + + L + V + + + R + H + + + IDLE + LEDIG + + + READY + KLAR + + + WAITING + VENTAR + + + RECORDING + TEK OPP + + + PLAYING + SPELAR + + + [multiple events] + [fleire hendingar + + + [unknown cut] + [ukjent klipp] + + + [no description] + [inga skildring] + + + + EditCartEvent + + Edit Cart Event + Rediger korghending + + + Event Active + Hendinga aktiv + + + Location: + Plass: + + + Start Time: + Starttid: + + + Description: + Skildring: + + + Cart Number: + Korgnummer: + + + &Select + &Vel + + + Active Days + Aktiv dagar + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Make OneShot + Lag enkeltskot + + + &Save As +New + &Lagra som ny + + + &OK + &OK + + + &Cancel + &Avbryt + + + Duplicate Event + Kopier hending + + + An event with these parameters already exists! + Det finst alt ei hending med dette oppsettet! + + + Invalid Cart + Ugyldig korg + + + That cart doesn't exist! + Den korga finst ikkje! + + + + EditDownload + + Edit Download + Rediger nedlasting + + + Event Active + Hendinga aktiv + + + Location: + Plass: + + + Start Time: + Starttid: + + + Description: + Skildring: + + + Url: + Adresse: + + + Username: + Brukarnamn: + + + Password: + Passord: + + + Destination: + Mål: + + + &Select + &Vel + + + Channels: + Kanalar: + + + Autotrim + Autotrim + + + Level: + Nivå: + + + dBFS + dBFS + + + Normalize + Normaliser + + + Active Days + Aktiv dagar + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Make OneShot + Lag enkeltskot + + + &Save As +New + &Lagra som ny + + + &OK + &OK + + + &Cancel + &Avbryt + + + Cut + Klipp + + + Duplicate Event + Kopier hending + + + An event with these parameters already exists! + Det finst alt ei hending med dette oppsettet! + + + Invalid URL + Ugyldig adresse + + + The URL is invalid! + Adressa er ugyldig! + + + Unsupported URL protocol! + Ikkje støtta adresseprotokoll! + + + Event Offset: + + + + days + + + + Missing Username + + + + You must specify a username! + + + + Update Library Metadata + + + + + EditPlayout + + Edit Playout + Rediger utspeling + + + Event Active + Hendinga aktiv + + + Location: + Plass: + + + Start Time: + Starttid: + + + Description: + Skildring: + + + Destination: + Mål: + + + &Select + &Vel + + + Active Days + Aktiv dagar + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Make OneShot + Lag enkeltskot + + + &Save As +New + &Lagra som ny + + + &OK + &OK + + + &Cancel + &Avbryt + + + Duplicate Event + Kopier hending + + + An event with these parameters already exists! + Det finst alt ei hending med dette oppsettet! + + + + EditRecording + + Edit Recording + Rediger opptak + + + Event Active + Hendinga aktiv + + + Location: + Plass: + + + Start Parameters + Startoppsett + + + Use Hard Time + Bruk hardtid + + + Record Start Time: + Starttid for opptak: + + + Use GPI + Bruk GPI + + + Window Start Time: + Vindauge-starttid: + + + GPI Matrix: + GPI-matrise: + + + GPI Line: + GPI-linje: + + + Start Delay: + Startforseinking: + + + Allow Multiple Recordings within this Window + Gje løyve til fleire opptak i dette vindauget + + + End Parameters + Sluttoppsett + + + Use Length + Bruk lengd + + + Record Length: + Opptakslengd: + + + Record End Time: + Opptakssluttid: + + + Window End Time: + Vindaugssluttid: + + + Max Record Length: + Største opptakslengd: + + + Description: + Skildring: + + + Source: + Kjelde: + + + Destination: + Mål: + + + &Select + &Vel + + + Channels: + Kanalar: + + + Autotrim + Autotrim + + + Level: + Nivå: + + + dBFS + dBFS + + + Normalize + Normaliser + + + Active Days + Aktiv dagar + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Start Date Offset: + Avvik for startdato: + + + None + Ikkje noko + + + End Date Offset: + Avvik for sluttdato: + + + Make OneShot + Lag enkeltskot + + + &Save As +New + &Lagra som +ny + + + &OK + &OK + + + &Cancel + &Avbryt + + + Cut + Klipp + + + Missing Cut + Manglar klipp + + + You must assign a record cut! + Du må tildela eit opptaksklipp! + + + Record Parameter Error + Feil i opptaksoppsettet + + + The start GPI window cannot end before it begins! + Startvindauget for GPI kan ikkje byrja før det sluttar! + + + The recording cannot end before it begins! + Opptaket kan ikkje slutta før det byrjar! + + + The end GPI window cannot end before it begins! + Sluttvindauget for GPI kan ikkje slutta før det byrjar! + + + The start GPI matrix doesn't exist! + Startmatrisen for GPI finst ikkje! + + + The start GPI line doesn't exist! + Startlinja for GPI finst ikkje! + + + The end GPI matrix doesn't exist! + Sluttmatrisen for GPI finst ikkje! + + + The end GPI line doesn't exist! + Sluttlinja for GPI finst ikkje! + + + Duplicate Event + Kopier hending + + + An event with these parameters already exists! + Det finst alt ei hending med dette oppsettet! + + + + EditSwitchEvent + + Edit Switcher Event + Rediger svitsjarhending + + + Event Active + Hendinga aktiv + + + Location: + Plass: + + + Start Time: + Starttid: + + + Description: + Skildring: + + + Switch Matrix: + Byt matrise: + + + Switch Input: + Byt inngang: + + + Switch Output: + Byt utgang: + + + Active Days + Aktiv dagar + + + Monday + Måndag + + + Tuesday + + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Make OneShot + Lag enkeltskot + + + &Save As +New + &Lagra som +ny + + + &OK + &OK + + + &Cancel + &Avbryt + + + --OFF-- + --AV-- + + + Duplicate Event + Kopier hending + + + An event with these parameters already exists! + Det finst alt ei hending med dette oppsettet! + + + + EditUpload + + Edit Upload + Rediger opplasting + + + Event Active + Hendinga aktiv + + + Location: + Plass: + + + Start Time: + Starttid: + + + [none] + [ingen] + + + RSS Feed: + RSS-straum: + + + Source: + Kjelde: + + + &Select + &Vel + + + Description: + Skildring: + + + Url: + Adresse: + + + Username: + Brukarnamn: + + + Password: + Passord: + + + Export Format: + Eksportformat: + + + S&et + S&et + + + Normalize + Normaliser + + + Level: + Nivå: + + + dBFS + dBFS + + + Active Days + Aktiv dagar + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Make OneShot + Lag enkeltskot + + + &Save As +New + &Lagra som +ny + + + &OK + &OK + + + &Cancel + &Avbryt + + + Unsupported Format + Formatet er ikkje støtta + + + The currently selected export format is unsupported on this host! + Dette eksportformatet er ikkje støtta på denne verten! + + + Cut + Klipp + + + Duplicate Event + Kopier hending + + + An event with these parameters already exists! + Det finst alt ei hending med dette oppsettet! + + + The currently selected export format is unsupported on host + Dette eksportformatet er ikkje støtta på denne verten + + + Invalid URL + Ugyldig adresse + + + The URL is invalid! + Adressa er ugyldig! + + + Unsupported URL protocol! + Ikkje støtta adresseprotokoll! + + + Event Offset: + + + + days + + + + Missing Username + + + + You must specify a username! + + + + Export Library Metadata + + + + + ListReports + + RDLibrary Reports + RDLibrary-rapportar + + + Event Report + Hendingsrapport + + + Upload/Download Report + Opp- og nedlastingsrapport + + + Type: + Type: + + + &Generate + La&g + + + &Close + &Lukk + + + + MainWidget + + RDCatch - Host: + RDCatch - vert: + + + rdcatch : + rdcatch: + + + Show Only Active Events + Vis berre aktive hendingar + + + Show Only Today's Events + Vis berre hendingar i dag + + + Show DayOfWeek: + Vis vekedag: + + + All + Alle + + + Weekdays + Vekedagar + + + Sunday + Sundag + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + DESCRIPTION + SKILDRING + + + LOCATION + PLASS + + + START + START + + + END + SLUTT + + + SOURCE + KJELDE + + + DESTINATION + MÅL + + + ORIGIN + OPPHAV + + + ONE SHOT + ENKELTSKOT + + + TRIM THRESHOLD + TRIMMETERSKEL + + + STARTDATE OFFSET + AVVIK STARTDATO + + + ENDDATE OFFSET + AVVIK SLUTTDATO + + + FORMAT + FORMAT + + + CHANNELS + KANALAR + + + SAMPLE RATE + PUNKTPRØVERATE + + + BIT RATE + BITRATE + + + STATION + STASJON + + + DECK + SPELAR + + + CUT + KLIPP + + + CART + KORG + + + ID + ID + + + TYPE + TYPE + + + STATUS + STATUS + + + EXIT CODE + AVSLUTT-KODE + + + STATE + TILSTAND + + + &Add + Legg &til + + + &Edit + &Rediger + + + &Delete + &Slett + + + Scroll + Rull + + + Reports + Rapportar + + + &Close + &Lukk + + + Event Active + Hendinga aktiv + + + You cannot edit an active event! + Du kan ikkje redigera ei aktiv hending! + + + Are you sure you want to delete event + Er du sikker på at du vil sletta hendinga + + + Delete Event + Slett hending + + + Can't Connect + Greier ikkje kopla til + + + Unable to connect to Core AudioEngine + Greier ikkje kopla til hovud-lydmotoren + + + Control connection timed out to host + Tidsavbrot på kontrolltilkoplinga til verten + + + Su + Su + + + Mo + + + + Tu + Ty + + + We + On + + + Th + To + + + Fr + Fr + + + Sa + La + + + dB + dB + + + Hard + Hard + + + Gpi + Gpi + + + Len + Len + + + Cut + Klipp + + + PCM16 + PCM16 + + + MPEG Layer 1 + MPEG lag 1 + + + MPEG Layer 2 + MPEG lag 2 + + + MPEG Layer 3 + MPEG lag 3 + + + FLAC + FLAC + + + OggVorbis + Ogg Vorbis + + + Cart + Korg + + + [none] + [inga] + + + OK + OK + + + Short Length + Kort lengd + + + Low Level + Lågt nivå + + + High Level + Høgt nivå + + + Downloading + Lastar ned + + + Uploading + Lastar opp + + + Recording + Tek opp + + + Playing + Spelar + + + Waiting + Ventar + + + Server Error + Tenarfeil + + + Internal Error + Intern feil + + + Interrupted + Avbrote + + + Device Busy + Eininga er oppteken + + + No Such Cart/Cut + Inga slik korg/klipp + + + Unknown + + + + Host + + + + User + + + + diff --git a/rdcatch/rdcatch_nn.ts b/rdcatch/rdcatch_nn.ts new file mode 100644 index 00000000..708103d5 --- /dev/null +++ b/rdcatch/rdcatch_nn.ts @@ -0,0 +1,1320 @@ + + + AddRecording + + Schedule a: + Køyreplan a: + + + &Recording + &Opptak + + + &Playout + &Utspeling + + + &Download + &Nedlasting + + + &Upload + &Opplasting + + + &Macro Cart + &Makrovogn + + + &Switch Event + &Byt hending + + + &Cancel + &Avbryt + + + + CatchListView + + Edit Cue Markers + Rediger cue-markørar + + + + DeckMon + + MON + MON + + + ABORT + AVBRYT + + + OFFLINE + AVLINJE + + + L + V + + + R + H + + + IDLE + LEDIG + + + READY + KLAR + + + WAITING + VENTAR + + + RECORDING + TEK OPP + + + PLAYING + SPELAR + + + [multiple events] + [fleire hendingar + + + [unknown cut] + [ukjent klipp] + + + [no description] + [inga skildring] + + + + EditCartEvent + + Edit Cart Event + Rediger korghending + + + Event Active + Hendinga aktiv + + + Location: + Plass: + + + Start Time: + Starttid: + + + Description: + Skildring: + + + Cart Number: + Korgnummer: + + + &Select + &Vel + + + Active Days + Aktiv dagar + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Make OneShot + Lag enkeltskot + + + &Save As +New + &Lagra som ny + + + &OK + &OK + + + &Cancel + &Avbryt + + + Duplicate Event + Kopier hending + + + An event with these parameters already exists! + Det finst alt ei hending med dette oppsettet! + + + Invalid Cart + Ugyldig korg + + + That cart doesn't exist! + Den korga finst ikkje! + + + + EditDownload + + Edit Download + Rediger nedlasting + + + Event Active + Hendinga aktiv + + + Location: + Plass: + + + Start Time: + Starttid: + + + Description: + Skildring: + + + Url: + Adresse: + + + Username: + Brukarnamn: + + + Password: + Passord: + + + Destination: + Mål: + + + &Select + &Vel + + + Channels: + Kanalar: + + + Autotrim + Autotrim + + + Level: + Nivå: + + + dBFS + dBFS + + + Normalize + Normaliser + + + Active Days + Aktiv dagar + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Make OneShot + Lag enkeltskot + + + &Save As +New + &Lagra som ny + + + &OK + &OK + + + &Cancel + &Avbryt + + + Cut + Klipp + + + Duplicate Event + Kopier hending + + + An event with these parameters already exists! + Det finst alt ei hending med dette oppsettet! + + + Invalid URL + Ugyldig adresse + + + The URL is invalid! + Adressa er ugyldig! + + + Unsupported URL protocol! + Ikkje støtta adresseprotokoll! + + + Event Offset: + + + + days + + + + Missing Username + + + + You must specify a username! + + + + Update Library Metadata + + + + + EditPlayout + + Edit Playout + Rediger utspeling + + + Event Active + Hendinga aktiv + + + Location: + Plass: + + + Start Time: + Starttid: + + + Description: + Skildring: + + + Destination: + Mål: + + + &Select + &Vel + + + Active Days + Aktiv dagar + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Make OneShot + Lag enkeltskot + + + &Save As +New + &Lagra som ny + + + &OK + &OK + + + &Cancel + &Avbryt + + + Duplicate Event + Kopier hending + + + An event with these parameters already exists! + Det finst alt ei hending med dette oppsettet! + + + + EditRecording + + Edit Recording + Rediger opptak + + + Event Active + Hendinga aktiv + + + Location: + Plass: + + + Start Parameters + Startoppsett + + + Use Hard Time + Bruk hardtid + + + Record Start Time: + Starttid for opptak: + + + Use GPI + Bruk GPI + + + Window Start Time: + Vindauge-starttid: + + + GPI Matrix: + GPI-matrise: + + + GPI Line: + GPI-linje: + + + Start Delay: + Startforseinking: + + + Allow Multiple Recordings within this Window + Gje løyve til fleire opptak i dette vindauget + + + End Parameters + Sluttoppsett + + + Use Length + Bruk lengd + + + Record Length: + Opptakslengd: + + + Record End Time: + Opptakssluttid: + + + Window End Time: + Vindaugssluttid: + + + Max Record Length: + Største opptakslengd: + + + Description: + Skildring: + + + Source: + Kjelde: + + + Destination: + Mål: + + + &Select + &Vel + + + Channels: + Kanalar: + + + Autotrim + Autotrim + + + Level: + Nivå: + + + dBFS + dBFS + + + Normalize + Normaliser + + + Active Days + Aktiv dagar + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Start Date Offset: + Avvik for startdato: + + + None + Ikkje noko + + + End Date Offset: + Avvik for sluttdato: + + + Make OneShot + Lag enkeltskot + + + &Save As +New + &Lagra som +ny + + + &OK + &OK + + + &Cancel + &Avbryt + + + Cut + Klipp + + + Missing Cut + Manglar klipp + + + You must assign a record cut! + Du må tildela eit opptaksklipp! + + + Record Parameter Error + Feil i opptaksoppsettet + + + The start GPI window cannot end before it begins! + Startvindauget for GPI kan ikkje byrja før det sluttar! + + + The recording cannot end before it begins! + Opptaket kan ikkje slutta før det byrjar! + + + The end GPI window cannot end before it begins! + Sluttvindauget for GPI kan ikkje slutta før det byrjar! + + + The start GPI matrix doesn't exist! + Startmatrisen for GPI finst ikkje! + + + The start GPI line doesn't exist! + Startlinja for GPI finst ikkje! + + + The end GPI matrix doesn't exist! + Sluttmatrisen for GPI finst ikkje! + + + The end GPI line doesn't exist! + Sluttlinja for GPI finst ikkje! + + + Duplicate Event + Kopier hending + + + An event with these parameters already exists! + Det finst alt ei hending med dette oppsettet! + + + + EditSwitchEvent + + Edit Switcher Event + Rediger svitsjarhending + + + Event Active + Hendinga aktiv + + + Location: + Plass: + + + Start Time: + Starttid: + + + Description: + Skildring: + + + Switch Matrix: + Byt matrise: + + + Switch Input: + Byt inngang: + + + Switch Output: + Byt utgang: + + + Active Days + Aktiv dagar + + + Monday + Måndag + + + Tuesday + + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Make OneShot + Lag enkeltskot + + + &Save As +New + &Lagra som +ny + + + &OK + &OK + + + &Cancel + &Avbryt + + + --OFF-- + --AV-- + + + Duplicate Event + Kopier hending + + + An event with these parameters already exists! + Det finst alt ei hending med dette oppsettet! + + + + EditUpload + + Edit Upload + Rediger opplasting + + + Event Active + Hendinga aktiv + + + Location: + Plass: + + + Start Time: + Starttid: + + + [none] + [ingen] + + + RSS Feed: + RSS-straum: + + + Source: + Kjelde: + + + &Select + &Vel + + + Description: + Skildring: + + + Url: + Adresse: + + + Username: + Brukarnamn: + + + Password: + Passord: + + + Export Format: + Eksportformat: + + + S&et + S&et + + + Normalize + Normaliser + + + Level: + Nivå: + + + dBFS + dBFS + + + Active Days + Aktiv dagar + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Make OneShot + Lag enkeltskot + + + &Save As +New + &Lagra som +ny + + + &OK + &OK + + + &Cancel + &Avbryt + + + Unsupported Format + Formatet er ikkje støtta + + + The currently selected export format is unsupported on this host! + Dette eksportformatet er ikkje støtta på denne verten! + + + Cut + Klipp + + + Duplicate Event + Kopier hending + + + An event with these parameters already exists! + Det finst alt ei hending med dette oppsettet! + + + The currently selected export format is unsupported on host + Dette eksportformatet er ikkje støtta på denne verten + + + Invalid URL + Ugyldig adresse + + + The URL is invalid! + Adressa er ugyldig! + + + Unsupported URL protocol! + Ikkje støtta adresseprotokoll! + + + Event Offset: + + + + days + + + + Missing Username + + + + You must specify a username! + + + + Export Library Metadata + + + + + ListReports + + RDLibrary Reports + RDLibrary-rapportar + + + Event Report + Hendingsrapport + + + Upload/Download Report + Opp- og nedlastingsrapport + + + Type: + Type: + + + &Generate + La&g + + + &Close + &Lukk + + + + MainWidget + + RDCatch - Host: + RDCatch - vert: + + + rdcatch : + rdcatch: + + + Show Only Active Events + Vis berre aktive hendingar + + + Show Only Today's Events + Vis berre hendingar i dag + + + Show DayOfWeek: + Vis vekedag: + + + All + Alle + + + Weekdays + Vekedagar + + + Sunday + Sundag + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + DESCRIPTION + SKILDRING + + + LOCATION + PLASS + + + START + START + + + END + SLUTT + + + SOURCE + KJELDE + + + DESTINATION + MÅL + + + ORIGIN + OPPHAV + + + ONE SHOT + ENKELTSKOT + + + TRIM THRESHOLD + TRIMMETERSKEL + + + STARTDATE OFFSET + AVVIK STARTDATO + + + ENDDATE OFFSET + AVVIK SLUTTDATO + + + FORMAT + FORMAT + + + CHANNELS + KANALAR + + + SAMPLE RATE + PUNKTPRØVERATE + + + BIT RATE + BITRATE + + + STATION + STASJON + + + DECK + SPELAR + + + CUT + KLIPP + + + CART + KORG + + + ID + ID + + + TYPE + TYPE + + + STATUS + STATUS + + + EXIT CODE + AVSLUTT-KODE + + + STATE + TILSTAND + + + &Add + Legg &til + + + &Edit + &Rediger + + + &Delete + &Slett + + + Scroll + Rull + + + Reports + Rapportar + + + &Close + &Lukk + + + Event Active + Hendinga aktiv + + + You cannot edit an active event! + Du kan ikkje redigera ei aktiv hending! + + + Are you sure you want to delete event + Er du sikker på at du vil sletta hendinga + + + Delete Event + Slett hending + + + Can't Connect + Greier ikkje kopla til + + + Unable to connect to Core AudioEngine + Greier ikkje kopla til hovud-lydmotoren + + + Control connection timed out to host + Tidsavbrot på kontrolltilkoplinga til verten + + + Su + Su + + + Mo + + + + Tu + Ty + + + We + On + + + Th + To + + + Fr + Fr + + + Sa + La + + + dB + dB + + + Hard + Hard + + + Gpi + Gpi + + + Len + Len + + + Cut + Klipp + + + PCM16 + PCM16 + + + MPEG Layer 1 + MPEG lag 1 + + + MPEG Layer 2 + MPEG lag 2 + + + MPEG Layer 3 + MPEG lag 3 + + + FLAC + FLAC + + + OggVorbis + Ogg Vorbis + + + Cart + Korg + + + [none] + [inga] + + + OK + OK + + + Short Length + Kort lengd + + + Low Level + Lågt nivå + + + High Level + Høgt nivå + + + Downloading + Lastar ned + + + Uploading + Lastar opp + + + Recording + Tek opp + + + Playing + Spelar + + + Waiting + Ventar + + + Server Error + Tenarfeil + + + Internal Error + Intern feil + + + Interrupted + Avbrote + + + Device Busy + Eininga er oppteken + + + No Such Cart/Cut + Inga slik korg/klipp + + + Unknown + + + + Host + + + + User + + + + diff --git a/rdcatch/rdcatch_pt_BR.ts b/rdcatch/rdcatch_pt_BR.ts new file mode 100644 index 00000000..71839468 --- /dev/null +++ b/rdcatch/rdcatch_pt_BR.ts @@ -0,0 +1,1323 @@ + + + AddRecording + + Schedule a: + Agende : + + + &Recording + &Gravação + + + &Playout + &Execução + + + &Download + &Download + + + &Upload + &Upload + + + &Macro Cart + &Cartão Macro + + + &Switch Event + &Evento de Switch + + + &Cancel + &Cancelar + + + + CatchListView + + Edit Cue Markers + Editar Marcadores + + + + DeckMon + + MON + MON + + + ABORT + ABORTAR + + + OFFLINE + DESCONECT + + + L + L + + + R + R + + + IDLE + CONECTADO + + + READY + PRONTO + + + WAITING + ESPERANDO + + + RECORDING + GRAVANDO + + + PLAYING + EXECUTANDO + + + [multiple events] + [múltiplos eventos] + + + [unknown cut] + [conteúdo desconhecido] + + + [no description] + + + + + EditCartEvent + + Edit Cart Event + Editar Evento Macro + + + Event Active + Evento Ativo + + + Location: + Local: + + + Start Time: + Início: + + + Description: + Descrição: + + + Cart Number: + Cartão: + + + &Select + &Selecionar + + + Active Days + Dias Ativos + + + Monday + Segunda-Feira + + + Tuesday + Terça-Feira + + + Wednesday + Quarta-Feira + + + Thursday + Quinta-Feira + + + Friday + Sexta + + + Saturday + Sábado + + + Sunday + Domingo + + + Make OneShot + Somente Uma Vez + + + &Save As +New + &Salvar como +Novo + + + &OK + &OK + + + &Cancel + &Cancelar + + + Duplicate Event + Duplicar Evento + + + An event with these parameters already exists! + Um Evento com estes parâmetros já existe! + + + Invalid Cart + Cartão Inválido + + + That cart doesn't exist! + O Cartão não existe! + + + + EditDownload + + Edit Download + Editar Download + + + Event Active + Evento Ativo + + + Location: + Local: + + + Start Time: + Início: + + + Description: + Descrição: + + + Url: + Url: + + + Username: + Usuário: + + + Password: + Senha: + + + Destination: + Destino: + + + &Select + &Selecionar + + + Channels: + Canais: + + + Autotrim + Auto-Corte + + + Level: + Nível: + + + dBFS + dBFS + + + Normalize + Normalizar + + + Active Days + Dias Ativos + + + Monday + Segunda-Feira + + + Tuesday + Terça-Feira + + + Wednesday + Quarta-Feira + + + Thursday + Quinta-Feira + + + Friday + Sexta + + + Saturday + Sábado + + + Sunday + Domingo + + + Make OneShot + Uma Vez + + + Event Offset: + Offset do Evento: + + + days + dias + + + &Save As +New + &Salvar como +Novo + + + &OK + &OK + + + &Cancel + &Cancelar + + + Cut + Conteúdo + + + Duplicate Event + Duplicar Evento + + + An event with these parameters already exists! + Um Evento com estes parâmetros já existe! + + + Invalid URL + URL Inválida + + + The URL is invalid! + A URL é Inválida! + + + Unsupported URL protocol! + Protocolo URL sem suporte! + + + Update Library Metadata + + + + Missing Username + + + + You must specify a username! + + + + + EditPlayout + + Edit Playout + Editar Execução + + + Event Active + Evento Ativo + + + Location: + Local: + + + Start Time: + Início: + + + Description: + Descrição: + + + Destination: + Destino: + + + &Select + &Selecionar + + + Active Days + Dias Ativos + + + Monday + Segunda-Feira + + + Tuesday + Terça-Feira + + + Wednesday + Quarta-Feira + + + Thursday + Quinta-Feira + + + Friday + Sexta + + + Saturday + Sábado + + + Sunday + Domingo + + + Make OneShot + Somente Uma Vez + + + &Save As +New + &Salvar como +Novo + + + &OK + &OK + + + &Cancel + &Cancelar + + + Duplicate Event + Duplicar Evento + + + An event with these parameters already exists! + Um Evento com estes parâmetros já existe! + + + + EditRecording + + Edit Recording + Editar Gravação + + + Event Active + Evento Ativo + + + Location: + Local: + + + Start Parameters + Parâmetros de Início + + + Use Hard Time + Usar Hora Certa + + + Record Start Time: + Início da Gravação: + + + Use GPI + Usar GPI + + + Window Start Time: + Início - Intervalo: + + + GPI Matrix: + GPI Matrix: + + + GPI Line: + Linha GPI: + + + Start Delay: + Atraso de Início: + + + Allow Multiple Recordings within this Window + Permitir Múltiplas Gravações dentro desta Intervalo + + + End Parameters + Parâmetros de Término + + + Use Length + Usar Duração + + + Record Length: + Duração da Gravação: + + + Record End Time: + Hora de Término da Gravação: + + + Window End Time: + Término - Intervalo: + + + Max Record Length: + Duração Máxima: + + + Description: + Descrição: + + + Source: + Fonte: + + + Destination: + Destino: + + + &Select + &Selecionar + + + Channels: + Canais: + + + Autotrim + Auto-Corte + + + Level: + Nível: + + + dBFS + dBFS + + + Normalize + Normalizar + + + Active Days + Dias Ativos + + + Monday + Segunda-Feira + + + Tuesday + Terça-Feira + + + Wednesday + Quarta-Feira + + + Thursday + Quinta-Feira + + + Friday + Sexta-Feira + + + Saturday + Sábado + + + Sunday + Domingo + + + Start Date Offset: + Offset - data Início: + + + None + Nenhum + + + End Date Offset: + Offset - data Término: + + + Make OneShot + Somente Uma Vez + + + &Save As +New + &Salvar como +Novo + + + &OK + &OK + + + &Cancel + &Cancelar + + + Cut + Conteúdo + + + Missing Cut + Conteúdo Faltando + + + You must assign a record cut! + Você deve designar um Conteúdo para a gravação! + + + Record Parameter Error + Erro no Parâmetro de Garvação + + + The start GPI window cannot end before it begins! + O Intervalo de início GPI não pode terminar antes de iniciar! + + + The recording cannot end before it begins! + A Gravação não pode terminar antes de começar! + + + The end GPI window cannot end before it begins! + O Intervalo de término GPI não pode terminar antes de iniciar! + + + The start GPI matrix doesn't exist! + A matrix de início GPI não existe! + + + The start GPI line doesn't exist! + A Linha de início GPI não existe! + + + The end GPI matrix doesn't exist! + A matrix de término GPI não existe! + + + The end GPI line doesn't exist! + A Linha de término GPI não existe! + + + Duplicate Event + Duplicar Evento + + + An event with these parameters already exists! + Um Evento com estes parâmetros já existe! + + + + EditSwitchEvent + + Edit Switcher Event + Editar Evento de Switch + + + Event Active + Evento Ativo + + + Location: + Local: + + + Start Time: + Início: + + + Description: + Descrição: + + + Switch Matrix: + Matrix de Switch: + + + Switch Input: + Entrada do Switch: + + + Switch Output: + Saída do Switch: + + + Active Days + Dias Ativos + + + Monday + Segunda-Feira + + + Tuesday + Terça-Feira + + + Wednesday + Quarta-Feira + + + Thursday + Quinta-Feira + + + Friday + Sexta + + + Saturday + Sábado + + + Sunday + Domingo + + + Make OneShot + Somente Uma Vez + + + &Save As +New + &Salvar como +Novo + + + &OK + &OK + + + &Cancel + &Cancelar + + + --OFF-- + --DESLIGADO-- + + + Duplicate Event + Duplicar Evento + + + An event with these parameters already exists! + Um Evento com estes parâmetros já existe! + + + + EditUpload + + Edit Upload + Editar Upload + + + Event Active + Evento Ativo + + + Location: + Local: + + + Start Time: + Início: + + + [none] + [nenhum] + + + RSS Feed: + Feed de RSS: + + + Source: + Fonte: + + + &Select + &Selecionar + + + Description: + Descrição: + + + Url: + Url: + + + Username: + Usuário: + + + Password: + Senha: + + + Export Format: + Exportação: + + + S&et + &Ajustar + + + Normalize + Normalizar + + + Level: + Nível: + + + dBFS + dBFS + + + Active Days + Dias Ativos + + + Monday + Segunda-Feira + + + Tuesday + Terça-Feira + + + Wednesday + Quarta-Feira + + + Thursday + Quinta-Feira + + + Friday + Sexta + + + Saturday + Sábado + + + Sunday + Domingo + + + Make OneShot + Uma Vez + + + Event Offset: + Offset do Evento: + + + days + dias + + + &Save As +New + &Salvar como +Novo + + + &OK + &OK + + + &Cancel + &Cancelar + + + Unsupported Format + Formato sem suporte + + + The currently selected export format is unsupported on this host! + O atual formato de exportação selecionado não tem suporte no cliente! + + + Cut + Conteúdo + + + Duplicate Event + Duplicar Evento + + + An event with these parameters already exists! + Um Evento com estes parâmetros já existe! + + + The currently selected export format is unsupported on host + O atual formato de exportação selecionado não tem suporte neste cliente + + + Invalid URL + URL Inválida + + + The URL is invalid! + A URL é Inválida! + + + Unsupported URL protocol! + Protocolo URL sem suporte! + + + Export Library Metadata + + + + Missing Username + + + + You must specify a username! + + + + + ListReports + + RDLibrary Reports + Relatórios do RDBiblio + + + Event Report + Relatório de Evento + + + Upload/Download Report + Relatório de Download/Upload + + + Type: + Tipo: + + + &Generate + &Gerar + + + &Close + &Fechar + + + + MainWidget + + RDCatch - Host: + RDCaptura - Cliente: + + + rdcatch : + rdcaptura : + + + Show Only Active Events + Mostrar somente Eventos Ativo + + + Show Only Today's Events + Mostrar somente Eventos de Hoje + + + Show DayOfWeek: + Mostrar Dia da Semana: + + + All + Todos + + + Weekdays + Dias da Semana + + + Sunday + Domingo + + + Monday + Segunda-Feira + + + Tuesday + Terça-Feira + + + Wednesday + Quarta-Feira + + + Thursday + Quinta-Feira + + + Friday + Sexta + + + Saturday + Sábado + + + DESCRIPTION + DESCRIÇÃO + + + LOCATION + LOCALIZAÇÃO + + + START + INÍCIO + + + END + FIM + + + SOURCE + FONTE + + + DESTINATION + DESTINO + + + ORIGIN + ORIGEM + + + ONE SHOT + UMA VEZ + + + TRIM THRESHOLD + LIMIAR PARA CORTE + + + STARTDATE OFFSET + COMPENSAR DATA INÍCIO + + + ENDDATE OFFSET + COMPENSAR DATA FIM + + + FORMAT + FORMATO + + + CHANNELS + CANAIS + + + SAMPLE RATE + TAXA DE AMOSTRAGEM + + + BIT RATE + TAXA DE BITS + + + STATION + ESTAÇÃO + + + DECK + DECK + + + CUT + CONTEÚDO + + + CART + CARTÃO + + + ID + ID + + + TYPE + TIPO + + + STATUS + ESTADO + + + EXIT CODE + CÓDIGO DE SAÍDA + + + STATE + ESTADO + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + Scroll + Rolagem + + + Reports + Relatórios + + + &Close + &Fechar + + + Event Active + Evento Ativo + + + You cannot edit an active event! + Você não pode editar um evento ativo! + + + Are you sure you want to delete event + Tem certeza que quer deletar este evento + + + Delete Event + Deletar Evento + + + Can't Connect + Não foi Possível Conectar + + + Unable to connect to Core AudioEngine + Não foi Possível Conectar ao Sistema de áudio + + + Control connection timed out to host + Conexão de Controle expirou para o Cliente + + + Su + Dom + + + Mo + Seg + + + Tu + Ter + + + We + Qua + + + Th + Qui + + + Fr + Sex + + + Sa + Sab + + + dB + dB + + + Hard + Certa + + + Gpi + Gpi + + + Len + Dur + + + Cut + Conteúdo + + + PCM16 + PCM16 + + + MPEG Layer 1 + MPEG Layer 1 + + + MPEG Layer 2 + MPEG Layer 2 + + + MPEG Layer 3 + MPEG Layer 3 + + + FLAC + FLAC + + + OggVorbis + OggVorbis + + + Cart + Cartão + + + [none] + [nenhum] + + + OK + OK + + + Short Length + Duração Curta + + + Low Level + Nível Baixo + + + High Level + Nível Alto + + + Downloading + Baixando + + + Uploading + Subindo + + + Recording + Gravando + + + Playing + Executando + + + Waiting + Esperando + + + Server Error + Erro de Servidor + + + Internal Error + Erro Interno + + + Interrupted + Interrompido + + + Device Busy + Dispositivo Ocupado + + + No Such Cart/Cut + Este Cartão não existe + + + Unknown + + + + Host + + + + User + + + + diff --git a/rdcatch/vbox.cpp b/rdcatch/vbox.cpp new file mode 100644 index 00000000..00051199 --- /dev/null +++ b/rdcatch/vbox.cpp @@ -0,0 +1,64 @@ +// vbox.cpp +// +// A QVBox widget with dynamic horizontal resizing. +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: vbox.cpp,v 1.5 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + + +VBox::VBox(QWidget *parent,const char *name,WFlags f) + : QWidget(parent,name,f) +{ + box_spacing=0; + setGeometry(QWidget::geometry()); +} + + +void VBox::addWidget(QWidget *widget) +{ + box_children.push_back(widget); +} + + +void VBox::setSpacing(int space) +{ + box_spacing=space; +} + + +void VBox::setGeometry(int x,int y,int w,int h) +{ + int ypos=0; + + for(unsigned i=0;i + setGeometry(0,ypos,w,box_children[i]->sizeHint().height()); + ypos+=(box_children[i]->sizeHint().height()+box_spacing); + } + QWidget::setGeometry(x,y,w,h); +} + + +void VBox::setGeometry(const QRect &r) +{ + setGeometry(r.x(),r.y(),r.width(),r.height()); +} diff --git a/rdcatch/vbox.h b/rdcatch/vbox.h new file mode 100644 index 00000000..91d9b75b --- /dev/null +++ b/rdcatch/vbox.h @@ -0,0 +1,50 @@ +// vbox.h +// +// A QVBox widget with dynamic horizontal resizing. +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: vbox.h,v 1.5 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef VBOX_H +#define VBOX_H + +#include + +#include + + +class VBox : public QWidget +{ + Q_OBJECT + public: + VBox(QWidget *parent=0,const char *name=0,WFlags f=0); + void addWidget(QWidget *widget); + void setSpacing(int space); + + public slots: + void setGeometry(int x,int y,int w,int h); + void setGeometry(const QRect &r); + + private: + int box_spacing; + std::vector box_children; +}; + + +#endif // VBOX_H diff --git a/rdcatchd/Makefile.am b/rdcatchd/Makefile.am new file mode 100644 index 00000000..242666b8 --- /dev/null +++ b/rdcatchd/Makefile.am @@ -0,0 +1,57 @@ +## automake.am +## +## rdcatchd/ Makefile.am for Rivendell +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.20.8.1 2012/11/29 01:37:36 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# QT's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rdcatchd + +dist_rdcatchd_SOURCES = batch.cpp\ + catch_event.cpp catch_event.h\ + local_macros.cpp\ + rdcatchd.cpp rdcatchd.h\ + rdcatchd_socket.cpp rdcatchd_socket.h + +nodist_rdcatchd_SOURCES = moc_rdcatchd.cpp\ + moc_rdcatchd_socket.cpp + +rdcatchd_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +CLEANFILES = *~\ + moc_* + +DISTCLEANFILES = moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/rdcatchd/batch.cpp b/rdcatchd/batch.cpp new file mode 100644 index 00000000..cfb60cc3 --- /dev/null +++ b/rdcatchd/batch.cpp @@ -0,0 +1,550 @@ +// batch.cpp +// +// Batch Routines for the Rivendell netcatcher daemon +// +// (C) Copyright 2002-2007, 2010 Fred Gleason +// +// $Id: batch.cpp,v 1.6.2.1 2012/05/10 16:00:53 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void MainObject::catchConnectedData(int serial,bool state) +{ + if(!state) { + LogLine(RDConfig::LogErr,"unable to connect to rdcatchd(8) daemon"); + exit(256); + } + + // + // Dispatch Handler + // + switch(batch_event->type()) { + case RDRecording::Recording: + RunImport(batch_event); + break; + + case RDRecording::Download: + RunDownload(batch_event); + break; + + case RDRecording::Upload: + RunUpload(batch_event); + break; + + default: + fprintf(stderr,"rdcatchd: nothing to do for this event type\n"); + exit(256); + } + + exit(0); +} + + +void MainObject::RunBatch(RDCmdSwitch *cmd) +{ + bool ok=false; + int id=-1; + unsigned schema=0; + + // + // Set Process Priority + // + struct sched_param sp; + memset(&sp,0,sizeof(sp)); + if(sched_setscheduler(getpid(),SCHED_BATCH,&sp)!=0) { + LogLine(RDConfig::LogWarning, + QString().sprintf("unable to set batch permissions, %s", + strerror(errno))); + } + + // + // Get ID + // + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--event-id") { + id=cmd->value(i).toInt(&ok); + if((!ok)||(id<0)) { + fprintf(stderr,"rdcatchd: invalid event-id\n"); + exit(256); + } + } + } + if(id<0) { + fprintf(stderr,"rdcatchd: missing event-id\n"); + exit(256); + } + + // + // Calculate Temporary Directory + // + catch_temp_dir=RDTempDir(); + + // + // Open Database + // + QString err (tr("ERROR rdcatchd aborting - ")); + + catch_db=RDInitDb (&schema,&err); + if(!catch_db) { + printf(err.ascii()); + exit(1); + } + connect (RDDbStatus(),SIGNAL(logText(RDConfig::LogPriority,const QString &)), + this,SLOT(log(RDConfig::LogPriority,const QString &))); + + // + // Load Event + // + QString sql=LoadEventSql()+QString().sprintf(" where ID=%d",id); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + fprintf(stderr,"rdcatchd: id %d not found\n",id); + exit(256); + } + batch_event=new CatchEvent(); + LoadEvent(q,batch_event,false); + delete q; + + // + // Open Status Connection + // + catch_connect=new RDCatchConnect(0,this); + connect(catch_connect,SIGNAL(connected(int,bool)), + this,SLOT(catchConnectedData(int,bool))); + catch_connect-> + connectHost("localhost",RDCATCHD_TCP_PORT,catch_config->password()); +} + + +void MainObject::RunImport(CatchEvent *evt) +{ + evt->setTempName(GetTempRecordingName(evt->id())); + evt->setDeleteTempFile(true); + Import(evt); +} + + +void MainObject::RunDownload(CatchEvent *evt) +{ + RDDownload::ErrorCode conv_err; + + // + // Resolve Wildcards + // + RDStation *station=new RDStation(catch_config->stationName()); + evt->resolveUrl(station->timeOffset()); + delete station; + + // + // Execute Download + // + LogLine(RDConfig::LogInfo,QString(). + sprintf("starting download of %s to %s, id=%d", + (const char *)evt->resolvedUrl(), + (const char *)evt->tempName(), + evt->id())); + evt->setTempName(BuildTempName(evt,"download")); + RDDownload *conv=new RDDownload(catch_config->stationName(),this); + conv->setSourceUrl(evt->resolvedUrl()); + conv->setDestinationFile(evt->tempName()); + QString url_username=evt->urlUsername(); + QString url_password=evt->urlPassword(); + if(url_username.isEmpty()&& + (QUrl(evt->resolvedUrl()).protocol().lower()=="ftp")) { + url_username=RD_ANON_FTP_USERNAME; + url_password=QString(RD_ANON_FTP_PASSWORD)+"-"+VERSION; + } + switch((conv_err=conv->runDownload(url_username,url_password, + catch_config->logXloadDebugData()))) { + case RDDownload::ErrorOk: + LogLine(RDConfig::LogInfo,QString(). + sprintf("finished download of %s to %s, id=%d", + (const char *)evt->tempName(), + (const char *)evt->resolvedUrl(), + evt->id())); + break; + + case RDDownload::ErrorInternal: + catch_connect->setExitCode(evt->id(),RDRecording::InternalError, + RDDownload::errorText(conv_err)); + qApp->processEvents(); + LogLine(RDConfig::LogWarning,QString(). + sprintf("download of %s returned an error: \"%s\", id=%d", + (const char *)evt->tempName(), + (const char *)RDDownload::errorText(conv_err), + evt->id())); + delete conv; + unlink(evt->tempName()); + exit(0); + + default: + catch_connect->setExitCode(evt->id(),RDRecording::ServerError, + RDDownload::errorText(conv_err)); + qApp->processEvents(); + LogLine(RDConfig::LogWarning,QString(). + sprintf("download of %s returned an error: \"%s\", id=%d", + (const char *)evt->tempName(), + (const char *)RDDownload::errorText(conv_err), + evt->id())); + delete conv; + unlink(evt->tempName()); + exit(0); + } + delete conv; + + // + // Execute Import + // + if(Import(evt)) { + catch_connect->setExitCode(evt->id(),RDRecording::Ok,tr("OK")); + qApp->processEvents(); + } + LogLine(RDConfig::LogInfo,QString().sprintf("deleting file %s, id=%d", + (const char *)evt->tempName(), + evt->id())); + unlink(evt->tempName()); +} + +void MainObject::RunUpload(CatchEvent *evt) +{ + RDUpload::ErrorCode conv_err; + + // + // Resolve Wildcards + // + RDStation *station=new RDStation(catch_config->stationName()); + evt->resolveUrl(station->timeOffset()); + delete station; + + // + // Execute Export + // + evt->setTempName(BuildTempName(evt,"upload")); + evt->setDeleteTempFile(true); + LogLine(RDConfig::LogInfo,QString(). + sprintf("started export of cut %s to %s, id=%d", + (const char *)evt->cutName(), + (const char *)evt->tempName(), + evt->id())); + if(!Export(evt)) { + LogLine(RDConfig::LogWarning,QString(). + sprintf("export of cut %s returned an error, id=%d", + (const char *)evt->cutName(), + evt->id())); + catch_connect->setExitCode(evt->id(),RDRecording::InternalError, + tr("Export Error")); + qApp->processEvents(); + return; + } + LogLine(RDConfig::LogInfo,QString(). + sprintf("finished export of cut %s to %s, id=%d", + (const char *)evt->cutName(), + (const char *)evt->tempName(), + evt->id())); + + // + // Load Podcast Parameters + // + if(evt->feedId()>0) { + QFile *file=new QFile(evt->tempName()); + evt->setPodcastLength(file->size()); + delete file; + RDWaveFile *wave=new RDWaveFile(evt->tempName()); + if(wave->openWave()) { + evt->setPodcastTime(wave->getExtTimeLength()); + } + delete wave; + } + + // + // Execute Upload + // + LogLine(RDConfig::LogInfo,QString(). + sprintf("starting upload of %s to %s, id=%d", + (const char *)evt->tempName(), + (const char *)evt-> + resolvedUrl(), + evt->id())); + RDUpload *conv=new RDUpload(catch_config->stationName(),this); + conv->setSourceFile(evt->tempName()); + conv->setDestinationUrl(evt->resolvedUrl()); + QString url_username=evt->urlUsername(); + QString url_password=evt->urlPassword(); + if(url_username.isEmpty()&& + (QUrl(evt->resolvedUrl()).protocol().lower()=="ftp")) { + url_username=RD_ANON_FTP_USERNAME; + url_password=QString(RD_ANON_FTP_PASSWORD)+"-"+VERSION; + } + switch((conv_err=conv->runUpload(url_username,url_password, + catch_config->logXloadDebugData()))) { + case RDUpload::ErrorOk: + catch_connect->setExitCode(evt->id(),RDRecording::Ok,tr("Ok")); + qApp->processEvents(); + LogLine(RDConfig::LogInfo,QString(). + sprintf("finished upload of %s to %s, id=%d", + (const char *)evt->tempName(), + (const char *)evt->resolvedUrl(), + evt->id())); + break; + + case RDUpload::ErrorInternal: + catch_connect->setExitCode(evt->id(),RDRecording::InternalError, + RDUpload::errorText(conv_err)); + qApp->processEvents(); + LogLine(RDConfig::LogWarning,QString(). + sprintf("upload of %s returned an error: \"%s\", id=%d", + (const char *)evt->tempName(), + (const char *)RDUpload::errorText(conv_err), + evt->id())); + break; + + default: + catch_connect->setExitCode(evt->id(),RDRecording::ServerError, + RDUpload::errorText(conv_err)); + qApp->processEvents(); + LogLine(RDConfig::LogWarning,QString(). + sprintf("upload of %s returned an error: \"%s\", id=%d", + (const char *)evt->tempName(), + (const char *)RDUpload::errorText(conv_err), + evt->id())); + break; + } + delete conv; + + // + // Clean Up + // + if(evt->feedId()>0) { + CheckInPodcast(evt); + } + if(evt->deleteTempFile()) { + unlink(evt->tempName()); + LogLine(RDConfig::LogDebug,QString().sprintf("deleted file %s", + (const char *)evt->tempName())); + } + else { + chown(evt->tempName(),catch_config->uid(), + catch_config->gid()); + } +} + + +bool MainObject::Export(CatchEvent *evt) +{ + bool ret=false; + RDAudioConvert::ErrorCode conv_err; + + RDCut *cut=new RDCut(evt->cutName()); + if(!cut->exists()) { + LogLine(RDConfig::LogErr,QString().sprintf("Cut not found: %s, id: %d", + (const char *)evt->cutName(), + evt->id())); + delete cut; + return false; + } + RDCart *cart=new RDCart(cut->cartNumber()); + RDAudioConvert *conv=new RDAudioConvert(catch_config->stationName(),this); + conv->setSourceFile(RDCut::pathName(evt->cutName())); + conv->setRange(cut->startPoint(),cut->endPoint()); + conv->setDestinationFile(RDEscapeString(evt->tempName())); + RDSettings *settings=new RDSettings(); + settings->setFormat((RDSettings::Format)evt->format()); + settings->setChannels(evt->channels()); + settings->setSampleRate(evt->sampleRate()); + settings->setBitRate(evt->bitrate()); + settings->setQuality(evt->quality()); + settings->setNormalizationLevel(evt->normalizeLevel()/100); + conv->setDestinationSettings(settings); + RDWaveData *wavedata=NULL; + if(evt->enableMetadata()) { + wavedata=new RDWaveData(); + cart->getMetadata(wavedata); + cut->getMetadata(wavedata); + conv->setDestinationWaveData(wavedata); + } + switch((conv_err=conv->convert())) { + case RDAudioConvert::ErrorOk: + ret=true; + break; + + default: + LogLine(RDConfig::LogErr, + QString().sprintf("Export error: %s, id: %d", + (const char *)RDAudioConvert::errorText(conv_err), + evt->id())); + ret=false; + break; + } + if(wavedata!=NULL) { + delete wavedata; + } + delete settings; + delete conv; + delete cart; + delete cut; + return ret; +} + + +bool MainObject::Import(CatchEvent *evt) +{ + bool ret=false; + RDAudioConvert::ErrorCode conv_err; + + RDCut *cut=new RDCut(evt->cutName()); + if(!cut->exists()) { + LogLine(RDConfig::LogErr, + QString().sprintf("Cut not found: %s, id: %d", + (const char *)evt->cutName(),evt->id())); + catch_connect->setExitCode(evt->id(),RDRecording::NoCut,tr("No such cut")); + qApp->processEvents(); + delete cut; + return false; + } + RDWaveFile *wave=new RDWaveFile(evt->tempName()); + if(!wave->openWave()) { + LogLine(RDConfig::LogErr, + QString().sprintf("Unknown file format: %s, id: %d", + (const char *)evt->cutName(),evt->id())); + catch_connect->setExitCode(evt->id(),RDRecording::UnknownFormat, + tr("Unknown Format")); + qApp->processEvents(); + delete wave; + return false; + } + unsigned msecs=wave->getExtTimeLength(); + delete wave; + RDCart *cart=new RDCart(cut->cartNumber()); + RDAudioConvert *conv=new RDAudioConvert(catch_config->stationName(),this); + conv->setSourceFile(RDEscapeString(evt->tempName())); + conv->setDestinationFile(RDCut::pathName(evt->cutName())); + RDSettings *settings=new RDSettings(); + switch(evt->format()) { + case RDCae::Pcm16: + settings->setFormat(RDSettings::Pcm16); + break; + + case RDCae::MpegL1: + case RDCae::MpegL2: + case RDCae::MpegL3: + settings->setFormat(RDSettings::MpegL2Wav); + break; + } + settings->setChannels(evt->channels()); + settings->setSampleRate(catch_system->sampleRate()); + settings->setBitRate(evt->bitrate()); + settings->setNormalizationLevel(evt->normalizeLevel()/100); + LogLine(RDConfig::LogInfo,QString(). + sprintf("started import of %s to cut %s, id=%d", + (const char *)evt->tempName(), + (const char *)evt->cutName(), + evt->id())); + conv->setDestinationSettings(settings); + switch((conv_err=conv->convert())) { + case RDAudioConvert::ErrorOk: + CheckInRecording(evt->cutName(),evt,msecs,evt->trimThreshold()); + ret=true; + break; + + case RDAudioConvert::ErrorFormatNotSupported: + LogLine(RDConfig::LogErr, + QString().sprintf("Import error: %s, id: %d", + (const char *)RDAudioConvert::errorText(conv_err), + evt->id())); + catch_connect->setExitCode(evt->id(),RDRecording::UnknownFormat, + RDAudioConvert::errorText(conv_err)); + qApp->processEvents(); + ret=false; + break; + + default: + LogLine(RDConfig::LogErr, + QString().sprintf("Import error: %s, id: %d", + (const char *)RDAudioConvert::errorText(conv_err), + evt->id())); + catch_connect->setExitCode(evt->id(),RDRecording::InternalError, + RDAudioConvert::errorText(conv_err)); + qApp->processEvents(); + ret=false; + break; + } + if((conv->sourceWaveData()!=NULL)&&(evt->enableMetadata())) { + cart->setMetadata(conv->sourceWaveData()); + cut->setMetadata(conv->sourceWaveData()); + } + LogLine(RDConfig::LogInfo,QString(). + sprintf("completed import of %s to cut %s, id=%d", + (const char *)evt->tempName(), + (const char *)evt->cutName(), + evt->id())); + if(evt->deleteTempFile()) { + unlink(evt->tempName()); + LogLine(RDConfig::LogDebug,QString(). + sprintf("deleted file %s", + (const char *)evt->tempName())); + } + delete settings; + delete conv; + delete cart; + delete cut; + + return ret; +} + + diff --git a/rdcatchd/catch_event.cpp b/rdcatchd/catch_event.cpp new file mode 100644 index 00000000..0cedf985 --- /dev/null +++ b/rdcatchd/catch_event.cpp @@ -0,0 +1,724 @@ +// catch_event.cpp +// +// A container class for a Rivendell netcatch event. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: catch_event.cpp,v 1.21 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +CatchEvent::CatchEvent() +{ + clear(); +} + + +unsigned CatchEvent::id() const +{ + return catch_id; +} + + +void CatchEvent::setId(int id) +{ + catch_id=id; +} + + +bool CatchEvent::isActive() const +{ + return catch_is_active; +} + + +void CatchEvent::setIsActive(bool state) +{ + catch_is_active=state; +} + + +RDRecording::Type CatchEvent::type() const +{ + return catch_type; +} + + +void CatchEvent::setType(RDRecording::Type type) +{ + catch_type=type; +} + + +unsigned CatchEvent::channel() const +{ + return catch_channel; +} + + +void CatchEvent::setChannel(unsigned chan) +{ + catch_channel=chan; +} + + +QString CatchEvent::cutName() const +{ + return catch_cut_name; +} + + +void CatchEvent::setCutName(const QString &str) +{ + catch_cut_name=str; +} + + +QString CatchEvent::tempName() const +{ + return catch_temp_name; +} + + +void CatchEvent::setTempName(const QString &str) +{ + catch_temp_name=str; +} + + +bool CatchEvent::deleteTempFile() const +{ + return catch_delete_temp_file; +} + + +void CatchEvent::setDeleteTempFile(bool state) +{ + catch_delete_temp_file=state; +} + + +bool CatchEvent::dayOfWeek(int day) const +{ + return catch_day_of_week[day-1]; +} + + +void CatchEvent::setDayOfWeek(int day,bool state) +{ + catch_day_of_week[day-1]=state; +} + + +RDRecording::StartType CatchEvent::startType() const +{ + return catch_start_type; +} + + +void CatchEvent::setStartType(RDRecording::StartType type) +{ + catch_start_type=type; +} + + +QTime CatchEvent::startTime() const +{ + return catch_start_time; +} + + +void CatchEvent::setStartTime(QTime time) +{ + catch_start_time=time; +} + + +int CatchEvent::startLength() const +{ + return catch_start_length; +} + + +void CatchEvent::setStartLength(int len) +{ + catch_start_length=len; +} + + +int CatchEvent::startMatrix() const +{ + return catch_start_matrix; +} + + +void CatchEvent::setStartMatrix(int matrix) +{ + catch_start_matrix=matrix; +} + + +int CatchEvent::startLine() const +{ + return catch_start_line; +} + + +void CatchEvent::setStartLine(int line) +{ + catch_start_line=line; +} + + +int CatchEvent::startOffset() const +{ + return catch_start_offset; +} + + +void CatchEvent::setStartOffset(int offset) +{ + catch_start_offset=offset; +} + + +RDRecording::EndType CatchEvent::endType() const +{ + return catch_end_type; +} + + +void CatchEvent::setEndType(RDRecording::EndType type) +{ + catch_end_type=type; +} + + +QTime CatchEvent::endTime() const +{ + return catch_end_time; +} + + +void CatchEvent::setEndTime(QTime time) +{ + catch_end_time=time; +} + + +int CatchEvent::endLength() const +{ + return catch_end_length; +} + + +void CatchEvent::setEndLength(int len) +{ + catch_end_length=len; +} + + +int CatchEvent::endMatrix() const +{ + return catch_end_matrix; +} + + +void CatchEvent::setEndMatrix(int matrix) +{ + catch_end_matrix=matrix; +} + + +int CatchEvent::endLine() const +{ + return catch_end_line; +} + + +void CatchEvent::setEndLine(int line) +{ + catch_end_line=line; +} + + +unsigned CatchEvent::length() const +{ + return catch_length; +} + + +void CatchEvent::setLength(unsigned len) +{ + catch_length=len; +} + + +int CatchEvent::startGpi() const +{ + return catch_start_gpi; +} + + +void CatchEvent::setStartGpi(int gpi) +{ + catch_start_gpi=gpi; +} + + +int CatchEvent::endGpi() const +{ + return catch_end_gpi; +} + + +void CatchEvent::setEndGpi(int gpi) +{ + catch_end_gpi=gpi; +} + + +bool CatchEvent::allowMultipleRecordings() const +{ + return catch_allow_multiple_recordings; +} + + +void CatchEvent::setAllowMultipleRecordings(bool state) +{ + catch_allow_multiple_recordings=state; +} + + +int CatchEvent::maxGpiRecordLength() const +{ + return catch_max_gpi_record_length; +} + + +void CatchEvent::setMaxGpiRecordLength(int len) +{ + catch_max_gpi_record_length=len; +} + + +unsigned CatchEvent::trimThreshold() const +{ + return catch_trim_threshold; +} + + +void CatchEvent::setTrimThreshold(unsigned level) +{ + catch_trim_threshold=level; +} + + +unsigned CatchEvent::startdateOffset() const +{ + return catch_startdate_offset; +} + + +void CatchEvent::setStartdateOffset(unsigned offset) +{ + catch_startdate_offset=offset; +} + + +unsigned CatchEvent::enddateOffset() const +{ + return catch_enddate_offset; +} + + +void CatchEvent::setEnddateOffset(unsigned offset) +{ + catch_enddate_offset=offset; +} + + +RDCae::AudioCoding CatchEvent::format() const +{ + return catch_format; +} + + +void CatchEvent::setFormat(RDCae::AudioCoding fmt) +{ + catch_format=fmt; +} + + +int CatchEvent::channels() const +{ + return catch_channels; +} + + +void CatchEvent::setChannels(int chans) +{ + catch_channels=chans; +} + + +int CatchEvent::sampleRate() const +{ + return catch_samplerate; +} + + +void CatchEvent::setSampleRate(int rate) +{ + catch_samplerate=rate; +} + + +int CatchEvent::bitrate() const +{ + return catch_bitrate; +} + + +void CatchEvent::setBitrate(int rate) +{ + catch_bitrate=rate; +} + + +int CatchEvent::normalizeLevel() const +{ + return catch_normalize_level; +} + + +void CatchEvent::setNormalizeLevel(int level) +{ + catch_normalize_level=level; +} + + +int CatchEvent::quality() const +{ + return catch_quality; +} + + +void CatchEvent::setQuality(int qual) +{ + catch_quality=qual; +} + + +int CatchEvent::macroCart() const +{ + return catch_macro_cart; +} + + +void CatchEvent::setMacroCart(int cart) +{ + catch_macro_cart=cart; +} + + +int CatchEvent::switchInput() const +{ + return catch_switch_input; +} + + +void CatchEvent::setSwitchInput(int input) +{ + catch_switch_input=input; +} + + +int CatchEvent::switchOutput() const +{ + return catch_switch_output; +} + + +void CatchEvent::setSwitchOutput(int output) +{ + catch_switch_output=output; +} + + +RDDeck::Status CatchEvent::status() const +{ + return catch_status; +} + + +void CatchEvent::setStatus(RDDeck::Status status) +{ + catch_status=status; +} + + +bool CatchEvent::oneShot() const +{ + return catch_oneshot; +} + + +void CatchEvent::setOneShot(bool state) +{ + catch_oneshot=state; +} + + +QString CatchEvent::url()const +{ + return catch_url; +} + + +void CatchEvent::setUrl(const QString &url) +{ + catch_url=url; +} + + +QString CatchEvent::resolvedUrl() const +{ + return catch_resolved_url; +} + + +void CatchEvent::setResolvedUrl(const QString &url) +{ + catch_resolved_url=url; +} + + +QString CatchEvent::urlUsername() const +{ + return catch_url_username; +} + + +void CatchEvent::setUrlUsername(const QString &name) +{ + catch_url_username=name; +} + + +QString CatchEvent::urlPassword() const +{ + return catch_url_password; +} + + +bool CatchEvent::enableMetadata() const +{ + return catch_enable_metadata; +} + + +void CatchEvent::setEnableMetadata(bool state) +{ + catch_enable_metadata=state; +} + + +void CatchEvent::setUrlPassword(const QString &passwd) +{ + catch_url_password=passwd; +} + + +unsigned CatchEvent::tempLength() const +{ + return catch_temp_length; +} + + +void CatchEvent::setTempLength(unsigned len) +{ + catch_temp_length=len; +} + + +unsigned CatchEvent::finalLength() const +{ + return catch_final_length; +} + + +void CatchEvent::setFinalLength(unsigned len) +{ + catch_final_length=len; +} + + +QTimer *CatchEvent::gpiStartTimer() const +{ + return catch_gpi_start_timer; +} + + +void CatchEvent::setGpiStartTimer(QTimer *timer) +{ + catch_gpi_start_timer=timer; +} + + +QTimer *CatchEvent::gpiOffsetTimer() const +{ + return catch_gpi_offset_timer; +} + + +void CatchEvent::setGpiOffsetTimer(QTimer *timer) +{ + catch_gpi_offset_timer=timer; +} + + +QString CatchEvent::description() const +{ + return catch_description; +} + + +void CatchEvent::setDescription(const QString &desc) +{ + catch_description=desc; +} + + +int CatchEvent::feedId() const +{ + return catch_feed_id; +} + + +void CatchEvent::setFeedId(int id) +{ + catch_feed_id=id; +} + + +int CatchEvent::podcastLength() const +{ + return catch_podcast_length; +} + + +void CatchEvent::setPodcastLength(int bytes) +{ + catch_podcast_length=bytes; +} + + +int CatchEvent::podcastTime() const +{ + return catch_podcast_time; +} + + +void CatchEvent::setPodcastTime(int msecs) +{ + catch_podcast_time=msecs; +} + + +int CatchEvent::eventdateOffset() const +{ + return catch_eventdate_offset; +} + + +void CatchEvent::setEventdateOffset(int days) +{ + catch_eventdate_offset=days; +} + + +void CatchEvent::resolveUrl(int time_offset) +{ + QDate date=QDate::currentDate(); + QTime current_time=QTime::currentTime(); + if((current_time.msecsTo(QTime(23,59,59))+1000) +// +// $Id: catch_event.h,v 1.22 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef CATCH_CONNECT_H +#define CATCH_CONNECT_H + +#include + +#include +#include +#include + +class CatchEvent +{ + public: + CatchEvent(); + unsigned id() const; + void setId(int id); + bool isActive() const; + void setIsActive(bool state); + RDRecording::Type type() const; + void setType(RDRecording::Type type); + unsigned channel() const; + void setChannel(unsigned chan); + QString cutName() const; + void setCutName(const QString &str); + QString tempName() const; + void setTempName(const QString &str); + bool deleteTempFile() const; + void setDeleteTempFile(bool state); + bool dayOfWeek(int day) const; + void setDayOfWeek(int day,bool state); + RDRecording::StartType startType() const; + void setStartType(RDRecording::StartType type); + QTime startTime() const; + void setStartTime(QTime time); + int startLength() const; + void setStartLength(int len); + int startMatrix() const; + void setStartMatrix(int matrix); + int startLine() const; + void setStartLine(int line); + int startOffset() const; + void setStartOffset(int offset); + RDRecording::EndType endType() const; + void setEndType(RDRecording::EndType type); + QTime endTime() const; + void setEndTime(QTime time); + int endLength() const; + void setEndLength(int len); + int endMatrix() const; + void setEndMatrix(int matrix); + int endLine() const; + void setEndLine(int line); + unsigned length() const; + void setLength(unsigned len); + int startGpi() const; + void setStartGpi(int gpi); + int endGpi() const; + void setEndGpi(int gpi); + bool allowMultipleRecordings() const; + void setAllowMultipleRecordings(bool state); + int maxGpiRecordLength() const; + void setMaxGpiRecordLength(int len); + unsigned trimThreshold() const; + void setTrimThreshold(unsigned level); + unsigned startdateOffset() const; + void setStartdateOffset(unsigned offset); + unsigned enddateOffset() const; + void setEnddateOffset(unsigned offset); + RDCae::AudioCoding format() const; + void setFormat(RDCae::AudioCoding fmt); + int channels() const; + void setChannels(int chans); + int sampleRate() const; + void setSampleRate(int rate); + int bitrate() const; + void setBitrate(int rate); + int quality() const; + void setQuality(int qual); + int normalizeLevel() const; + void setNormalizeLevel(int level); + int macroCart() const; + void setMacroCart(int cart); + int switchInput() const; + void setSwitchInput(int input); + int switchOutput() const; + void setSwitchOutput(int output); + RDDeck::Status status() const; + void setStatus(RDDeck::Status status); + bool oneShot() const; + void setOneShot(bool state); + QString url()const; + void setUrl(const QString &url); + QString resolvedUrl() const; + void setResolvedUrl(const QString &url); + QString urlUsername() const; + void setUrlUsername(const QString &name); + QString urlPassword() const; + void setUrlPassword(const QString &passwd); + bool enableMetadata() const; + void setEnableMetadata(bool state); + unsigned tempLength() const; + void setTempLength(unsigned len); + unsigned finalLength() const; + void setFinalLength(unsigned len); + QTimer *gpiStartTimer() const; + void setGpiStartTimer(QTimer *timer); + QTimer *gpiOffsetTimer() const; + void setGpiOffsetTimer(QTimer *timer); + QString description() const; + void setDescription(const QString &desc); + int feedId() const; + void setFeedId(int id); + int podcastLength() const; + void setPodcastLength(int bytes); + int podcastTime() const; + void setPodcastTime(int msecs); + int eventdateOffset() const; + void setEventdateOffset(int days); + void resolveUrl(int time_offset); + void clear(); + + private: + unsigned catch_id; + bool catch_is_active; + RDRecording::Type catch_type; + unsigned catch_channel; + QString catch_cut_name; + QString catch_temp_name; + bool catch_delete_temp_file; + bool catch_day_of_week[7]; + RDRecording::StartType catch_start_type; + QTime catch_start_time; + int catch_start_length; + int catch_start_matrix; + int catch_start_line; + int catch_start_offset; + RDRecording::EndType catch_end_type; + QTime catch_end_time; + int catch_end_length; + int catch_end_matrix; + int catch_end_line; + unsigned catch_length; + int catch_start_gpi; + int catch_end_gpi; + unsigned catch_trim_threshold; + unsigned catch_startdate_offset; + unsigned catch_enddate_offset; + RDCae::AudioCoding catch_format; + int catch_channels; + int catch_samplerate; + int catch_bitrate; + int catch_quality; + int catch_normalize_level; + int catch_macro_cart; + int catch_switch_input; + int catch_switch_output; + bool catch_oneshot; + RDDeck::Status catch_status; + QString catch_url; + QString catch_resolved_url; + QString catch_url_username; + QString catch_url_password; + bool catch_enable_metadata; + unsigned catch_temp_length; + unsigned catch_final_length; + QTimer *catch_gpi_start_timer; + QTimer *catch_gpi_offset_timer; + bool catch_allow_multiple_recordings; + int catch_max_gpi_record_length; + QString catch_description; + int catch_feed_id; + int catch_podcast_length; + int catch_podcast_time; + int catch_eventdate_offset; +}; + + +#endif // CATCH_CONNECT_H diff --git a/rdcatchd/local_macros.cpp b/rdcatchd/local_macros.cpp new file mode 100644 index 00000000..0f81bf6e --- /dev/null +++ b/rdcatchd/local_macros.cpp @@ -0,0 +1,166 @@ +// local_macros.cpp +// +// Local macros for the Rivendell netcatcher daemon +// +// (C) Copyright 2002-2009 Fred Gleason +// +// $Id: local_macros.cpp,v 1.4 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +void MainObject::RunLocalMacros(RDMacro *rml) +{ + RDCart *cart; + RDCut *cut; + RDDeck *deck; + int chan; + unsigned cartnum; + unsigned cutnum; + unsigned len; + QDateTime dt; + + switch(rml->command()) { + case RDMacro::EX: + cart=new RDCart(rml->arg(0).toUInt()); + if(cart->exists()) { + if(ExecuteMacroCart(cart)) { + if(rml->echoRequested()) { + rml->acknowledge(true); + catch_ripc->sendRml(rml); + } + delete cart; + return; + } + } + else { + if(rml->echoRequested()) { + rml->acknowledge(false); + catch_ripc->sendRml(rml); + } + } + delete cart; + return; + break; + + case RDMacro::RS: + // + // Validate Parameters + // + if(rml->argQuantity()!=4) { + if(rml->echoRequested()) { + rml->acknowledge(false); + catch_ripc->sendRml(rml); + } + return; + } + chan=rml->arg(0).toInt(); + cartnum=rml->arg(1).toUInt(); + cutnum=rml->arg(2).toUInt(); + len=rml->arg(3).toUInt(); + if((chan<=0)||(chan>MAX_DECKS)||(cartnum>999999)||(cutnum>999) + ||len==0) { + if(rml->echoRequested()) { + rml->acknowledge(false); + catch_ripc->sendRml(rml); + } + return; + } + cut=new RDCut(cartnum,cutnum); + deck=new RDDeck(catch_config->stationName(),chan); + if((!cut->exists())||(!deck->isActive())) { + delete cut; + delete deck; + if(rml->echoRequested()) { + rml->acknowledge(false); + catch_ripc->sendRml(rml); + } + return; + } + delete cut; + delete deck; + if(catch_record_deck_status[chan-1]!=RDDeck::Idle) { + if(catch_record_aborting[chan-1]&& + (catch_record_pending_cartnum[chan-1]==0)) { + // Cache Event + catch_record_pending_cartnum[chan-1]=cartnum; + catch_record_pending_cutnum[chan-1]=cutnum; + catch_record_pending_maxlen[chan-1]=len; + if(rml->echoRequested()) { + rml->acknowledge(true); + catch_ripc->sendRml(rml); + } + return; + } + else { + LogLine(RDConfig::LogWarning,QString(). + sprintf("unable to handle RS macro for deck %d: device busy", + chan)); + if(rml->echoRequested()) { + rml->acknowledge(false); + catch_ripc->sendRml(rml); + } + return; + } + } + + // + // Create Event + // + StartRmlRecording(chan,cartnum,cutnum,len); + if(rml->echoRequested()) { + rml->acknowledge(true); + catch_ripc->sendRml(rml); + } + break; + + case RDMacro::RR: + if(rml->argQuantity()!=1) { + if(rml->echoRequested()) { + rml->acknowledge(false); + catch_ripc->sendRml(rml); + } + return; + } + chan=rml->arg(0).toInt(); + if((chan>0)&&(chan<(MAX_DECKS+1))) { + switch(catch_record_deck_status[chan-1]) { + case RDDeck::Recording: + catch_record_aborting[chan-1]=true; + catch_cae->stopRecord(catch_record_card[chan-1], + catch_record_stream[chan-1]); + break; + + case RDDeck::Waiting: + startTimerData(catch_record_id[chan-1]); + break; + + default: + break; + } + } + if(rml->echoRequested()) { + rml->acknowledge(true); + catch_ripc->sendRml(rml); + } + break; + + default: + break; + } +} diff --git a/rdcatchd/rdcatchd.cpp b/rdcatchd/rdcatchd.cpp new file mode 100644 index 00000000..385e7c84 --- /dev/null +++ b/rdcatchd/rdcatchd.cpp @@ -0,0 +1,2736 @@ +// rdcatchd.cpp +// +// The Rivendell Netcatcher Daemon +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdcatchd.cpp,v 1.142.4.2.2.1 2014/06/03 18:23:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +RDConfig *catch_config; + + +// Logging function that works within and outside the MainObject. +//static RDConfig *rd_config = NULL; +void LogLine(RDConfig::LogPriority prio,const QString &line) +{ + FILE *logfile; + + catch_config->log("rdcatchd",prio,line); + + if(catch_config->catchdLogname().isEmpty()) { + return; + } + + QDateTime current=QDateTime::currentDateTime(); + logfile=fopen(catch_config->catchdLogname(),"a"); + if(logfile==NULL) { + return; + } + chmod(catch_config->catchdLogname(),S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); + fprintf(logfile,"%02d/%02d/%4d - %02d:%02d:%02d.%03d : %s\n", + current.date().month(), + current.date().day(), + current.date().year(), + current.time().hour(), + current.time().minute(), + current.time().second(), + current.time().msec(), + (const char *)line); + fclose(logfile); +} + + +void SigHandler(int signum) +{ + pid_t local_pid; + + switch(signum) { + case SIGINT: + case SIGTERM: + RDDeletePid(RD_PID_DIR,"rdcatchd.pid"); + LogLine(RDConfig::LogNotice,"rdcatchd exiting"); + delete catch_config; + exit(0); + break; + + case SIGCHLD: + local_pid=waitpid(-1,NULL,WNOHANG); + while(local_pid>0) { + local_pid=waitpid(-1,NULL,WNOHANG); + } + signal(SIGCHLD,SigHandler); + return; + } +} + + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + QString sql; + RDSqlQuery *q; + bool skip_db_check=false; + unsigned schema=0; + + // + // Load the config + // + catch_config=new RDConfig(); + catch_config->load(); + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdcatchd",RDCATCHD_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--event-id") { + RunBatch(cmd); + return; + } + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + } + + // + // Make sure we're the only instance running + // + if(RDCheckDaemon(RD_RDCATCHD_PID)) { + printf("rdcatchd: aborting - multiple instances not allowed"); + exit(1); + } + + // + // Initialize Data Structures + // + debug=false; + for(int i=0;istart(RDCATCHD_FREE_EVENTS_INTERVAL); + + server=new RDCatchdSocket(RDCATCHD_TCP_PORT,0,this,"socket"); + if(!server->ok()) { + printf("rdcatchd: aborting - couldn't bind socket"); + exit(1); + } + connect(server,SIGNAL(connection(int)),this,SLOT(newConnection(int))); + + // + // Open Database + // + QString err (tr("ERROR rdcatchd aborting - ")); + + catch_db=RDInitDb(&schema,&err); + if(!catch_db) { + printf(err.ascii()); + exit(1); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr, + "rdcatchd: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + connect (RDDbStatus(),SIGNAL(logText(RDConfig::LogPriority,const QString &)), + this,SLOT(log(RDConfig::LogPriority,const QString &))); + + // + // Create RDCatchConf + // + catch_conf=new RDCatchConf(catch_config->stationName()); + + // + // GPI Mappers + // + catch_gpi_start_mapper=new QSignalMapper(this,"catch_gpi_start_mapper"); + connect(catch_gpi_start_mapper,SIGNAL(mapped(int)), + this,SLOT(startTimerData(int))); + catch_gpi_offset_mapper=new QSignalMapper(this,"catch_gpi_offset_mapper"); + connect(catch_gpi_offset_mapper,SIGNAL(mapped(int)), + this,SLOT(offsetTimerData(int))); + + // + // Xload Timer + // + catch_xload_timer=new QTimer(this,"catch_xload_timer"); + connect(catch_xload_timer,SIGNAL(timeout()),this,SLOT(updateXloadsData())); + + // + // RIPCD Connection + // + catch_ripc=new RDRipc(catch_config->stationName()); + catch_ripc->connectHost("localhost",RIPCD_TCP_PORT,catch_config->password()); + connect(catch_ripc,SIGNAL(rmlReceived(RDMacro *)), + this,SLOT(rmlReceivedData(RDMacro *))); + connect(catch_ripc,SIGNAL(gpiStateChanged(int,int,bool)), + this,SLOT(gpiStateChangedData(int,int,bool))); + + // + // System Configuration + // + catch_system=new RDSystem(); + + // + // Station Configuration + // + catch_rdstation=new RDStation(catch_config->stationName()); + + // + // CAE Connection + // + catch_cae=new RDCae(catch_rdstation,catch_config,this,"catch_cae"); + connect(catch_cae,SIGNAL(isConnected(bool)), + this,SLOT(isConnectedData(bool))); + connect(catch_cae,SIGNAL(recordLoaded(int,int)), + this,SLOT(recordLoadedData(int,int))); + connect(catch_cae,SIGNAL(recording(int,int)), + this,SLOT(recordingData(int,int))); + connect(catch_cae,SIGNAL(recordStopped(int,int)), + this,SLOT(recordStoppedData(int,int))); + connect(catch_cae,SIGNAL(recordUnloaded(int,int,unsigned)), + this,SLOT(recordUnloadedData(int,int,unsigned))); + connect(catch_cae,SIGNAL(playLoaded(int)), + this,SLOT(playLoadedData(int))); + connect(catch_cae,SIGNAL(playing(int)), + this,SLOT(playingData(int))); + connect(catch_cae,SIGNAL(playStopped(int)), + this,SLOT(playStoppedData(int))); + connect(catch_cae,SIGNAL(playUnloaded(int)), + this,SLOT(playUnloadedData(int))); + catch_cae->connectHost(); + + // + // Sound Initialization + // + RDSetMixerPorts(catch_config->stationName(),catch_cae); + sql=QString().sprintf("select CHANNEL,CARD_NUMBER,PORT_NUMBER from DECKS \ + where (STATION_NAME=\"%s\")&&\ + (CARD_NUMBER!=-1)&&(CHANNEL>0)&&(CHANNEL<9)", + (const char *)catch_config->stationName()); + q=new RDSqlQuery(sql); + while(q->next()) { + if((q->value(1).toInt()>=0)&&(q->value(2).toInt()>=0)) { + catch_record_deck_status[q->value(0).toUInt()-1]=RDDeck::Idle; + } + } + delete q; + LoadDeckList(); + + // + // Initialize Monitor Passthroughs + // + sql=QString().sprintf("select CARD_NUMBER,PORT_NUMBER,\ + MON_PORT_NUMBER,CHANNEL from DECKS\ + where (STATION_NAME=\"%s\")&&(CHANNEL<=%d)&&\ + (CARD_NUMBER>=0)&&(MON_PORT_NUMBER>=0)&&\ + (DEFAULT_MONITOR_ON=\"Y\")", + (const char *)catch_config->stationName(), + MAX_DECKS); + q=new RDSqlQuery(sql); + while(q->next()) { + catch_cae->setPassthroughVolume(q->value(0).toInt(),q->value(1).toInt(), + q->value(2).toInt(),0); + catch_monitor_state[q->value(3).toUInt()-1]=true; + } + delete q; + + StartDropboxes(); + + // + // Time Engine + // + catch_engine=new RDTimeEngine(this,"catch_engine"); + catch_engine->setTimeOffset(catch_rdstation->timeOffset()); + connect(catch_engine,SIGNAL(timeout(int)),this,SLOT(engineData(int))); + LoadEngine(); + + if(qApp->argc()==1) { + RDDetach(catch_config->logCoreDumpDirectory()); + } + else { + debug=true; + } + + ::signal(SIGINT,SigHandler); + ::signal(SIGTERM,SigHandler); + ::signal(SIGCHLD,SigHandler); + if(!RDWritePid(RD_PID_DIR,"rdcatchd.pid")) { + printf("rdcatchd: aborting - can't write pid file\n"); + exit(1); + } + + // + // Start Heartbeat Timer + // + timer=new QTimer(this,"heartbeat_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(heartbeatData())); + timer->start(RDCATCHD_HEARTBEAT_INTERVAL); + + // + // Meter Timer + // + timer=new QTimer(this,"meter_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(meterData())); + timer->start(RD_METER_UPDATE_INTERVAL); + + // + // Heartbeat Timer + // + catch_heartbeat_timer=new QTimer(this,"catch_heartbeat_timer"); + connect(catch_heartbeat_timer,SIGNAL(timeout()), + this,SLOT(sysHeartbeatData())); + LoadHeartbeat(); + + // + // Mark Interrupted Events + // + sql=QString().sprintf("update RECORDINGS set EXIT_CODE=%d\ + where ((EXIT_CODE=%d)||(EXIT_CODE=%d))||\ + (EXIT_CODE=%d)&&(STATION_NAME=\"%s\")", + RDRecording::Interrupted, + RDRecording::Uploading, + RDRecording::Downloading, + RDRecording::RecordActive, + (const char *)catch_config->stationName()); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("update RECORDINGS set EXIT_CODE=%d\ + where ((EXIT_CODE=%d)||(EXIT_CODE=%d))&&\ + (STATION_NAME=\"%s\")", + RDRecording::Ok, + RDRecording::Waiting, + RDRecording::PlayActive, + (const char *)catch_config->stationName()); + q=new RDSqlQuery(sql); + delete q; + + // + // Schedule Startup Cart + // + timer=new QTimer(this,"startup_cart_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(startupCartData())); + timer->start(10000,true); + + // + // Set Realtime Permissions + // + if(catch_config->useRealtime()) { + struct sched_param sp; + memset(&sp,0,sizeof(sp)); + if(catch_config->realtimePriority()>0) { + sp.sched_priority=catch_config->realtimePriority()-1; + } + if(sched_setscheduler(getpid(),SCHED_FIFO,&sp)!=0) { + LogLine(RDConfig::LogWarning, + QString().sprintf("unable to set realtime permissions, %s", + strerror(errno))); + } + mlockall(MCL_CURRENT|MCL_FUTURE); + } + + LogLine(RDConfig::LogNotice,"rdcatchd started"); +} + +void MainObject::log(RDConfig::LogPriority prio,const QString &msg) +{ + LogLine(prio,msg); +} + + +void MainObject::newConnection(int fd) +{ + int i=0; + + while((isetSocket(fd); + connect(socket[i],SIGNAL(readyReadID(int)),this,SLOT(socketData(int))); + connect(socket[i],SIGNAL(connectionClosedID(int)), + this,SLOT(socketKill(int))); + LogLine(RDConfig::LogDebug,"rdcatchd new connection open"); +} + + +void MainObject::rmlReceivedData(RDMacro *rml) +{ + if(rml->role()!=RDMacro::Cmd) { + return; + } + RunLocalMacros(rml); +} + + +void MainObject::gpiStateChangedData(int matrix,int line,bool state) +{ + // LogLine(QString().sprintf("gpiStateChangedData(%d,%d,%d)", + // matrix,line,state)); + if(!state) { + return; + } + + std::vector handled_events; + QTime current_time=QTime::currentTime(); + + // + // Start Events + // + for(unsigned i=0;iisActive())) { + if(catch_events[i].startOffset()>0) { + catch_events[i].gpiOffsetTimer()-> + start(catch_events[i].startOffset(),true); + catch_events[i].gpiStartTimer()->stop(); + BroadcastCommand(QString().sprintf("RE %d %d %d!", + catch_events[i].channel(), + RDDeck::Ready, + catch_events[i].id())); + } + else { + if(StartRecording(i)) { + catch_events[i].gpiStartTimer()->stop(); + } + } + handled_events.push_back(i); + } + } + } + + // + // End Events + // + for(unsigned i=0;i + current_time)) { + bool handled=false; + for(unsigned j=0;j + stopRecord(catch_record_card[catch_events[i].channel()-1], + catch_record_stream[catch_events[i].channel()-1]); + } + } + } + } +} + + +void MainObject::startTimerData(int id) +{ + int event=GetEvent(id); + unsigned deck=catch_events[event].channel()-1; + bool waiting=false; + + catch_events[event].setStatus(RDDeck::Idle); + for(unsigned i=0;istop(); + } +} + + +void MainObject::engineData(int id) +{ + // LogLine(QString().sprintf("engineData(%d)",id)); + QString sql; + RDSqlQuery *q; + RDStation *rdstation; + int event=GetEvent(id); + + // + // Generate Effective Date + // + QDate date=QDate::currentDate(); + QTime current_time=QTime::currentTime(); + if((current_time.msecsTo(QTime(23,59,59))+1000)timeOffset()) { + date=date.addDays(1); + } + + // + // Ignore inactive or non-existent events + // + if(event<0) { + LogLine(RDConfig::LogDebug,QString(). + sprintf("cannot find event %d, ignoring!",id)); + return; + } + if(!catch_events[event].isActive()) { + LogLine(RDConfig::LogDebug,QString(). + sprintf("event %d is marked inactive, ignoring",id)); + return; + } + if(!catch_events[event].dayOfWeek(date.dayOfWeek())) { + LogLine(RDConfig::LogDebug,QString(). + sprintf("event %d is not valid for this DOW, ignoring", + id)); + return; + } + + // + // Check for Playout Deck Availability + // + if(catch_events[event].type()==RDRecording::Playout) { + if(catch_playout_deck_status[catch_events[event].channel()-129]!= + RDDeck::Idle) { + LogLine(RDConfig::LogWarning,QString(). + sprintf("playout deck P%d is busy for event %d, skipping", + catch_events[event].channel()-128, + catch_events[event].id())); + WriteExitCode(event,RDRecording::DeviceBusy); + BroadcastCommand(QString().sprintf("RE 0 %d %d %s!",RDDeck::Recording, + catch_events[event].id(), + (const char *)catch_events[event].cutName())); + return; + } + } + + // + // Load Deck Parameters + // + switch(catch_events[event].type()) { + case RDRecording::Recording: + if(!RDCut::exists(catch_events[event].cutName())) { + WriteExitCode(event,RDRecording::NoCut); + BroadcastCommand(QString(). + sprintf("RE %d %d %d!", + catch_events[event].channel(), + catch_record_deck_status[catch_events[event]. + channel()-1], + catch_events[event].id())); + LogLine(RDConfig::LogWarning,QString(). + sprintf("record aborted: no such cut: %s, id: %d", + (const char *)catch_events[event].cutName(), + catch_events[event].id())); + return; + } + catch_record_card[catch_events[event].channel()-1]=-1; + catch_record_stream[catch_events[event].channel()-1]=-1; + sql=QString().sprintf("select CARD_NUMBER,PORT_NUMBER,\ + SWITCH_STATION,SWITCH_MATRIX,SWITCH_OUTPUT,\ + SWITCH_DELAY from DECKS \ + where (STATION_NAME=\"%s\")&&(CHANNEL=%d)", + (const char *)catch_config->stationName(), + catch_events[event].channel()); + q=new RDSqlQuery(sql); + if(q->first()) { + catch_record_card[catch_events[event].channel()-1]= + q->value(0).toInt(); + catch_record_stream[catch_events[event].channel()-1]= + q->value(1).toInt(); + if(q->value(2).toString()==QString("[none]")) { + catch_swaddress[catch_events[event].channel()-1]=QHostAddress(); + } + else { + rdstation=new RDStation(q->value(2).toString()); + catch_swaddress[catch_events[event].channel()-1]= + rdstation->address(); + delete rdstation; + } + catch_swmatrix[catch_events[event].channel()-1]=q->value(3).toInt(); + catch_swoutput[catch_events[event].channel()-1]=q->value(4).toInt(); + catch_swdelay[catch_events[event].channel()-1]=q->value(5).toInt(); + } + else { + LogLine(RDConfig::LogNotice,QString(). + sprintf("id %d specified non-existent record deck, ignored", + catch_events[event].id())); + delete q; + return; + } + delete q; + + switch(catch_events[event].startType()) { + case RDRecording::HardStart: + StartRecording(event); + break; + + case RDRecording::GpiStart: + catch_events[event].gpiStartTimer()-> + start(catch_events[event].startLength()- + (QTime().msecsTo(current_time)- + QTime().msecsTo(catch_events[event].startTime())),true); + catch_record_deck_status[catch_events[event].channel()-1]= + RDDeck::Waiting; + catch_record_id[catch_events[event].channel()-1]= + catch_events[event].id(); + catch_events[event].setStatus(RDDeck::Waiting); + WriteExitCode(event,RDRecording::Waiting); + BroadcastCommand(QString().sprintf("RE %d %d %d!", + catch_events[event].channel(), + catch_record_deck_status[catch_events[event]. + channel()-1], + catch_events[event].id())); + LogLine(RDConfig::LogNotice,QString(). + sprintf("gpi start window opens: event: %d, gpi: %d:%d", + id,catch_events[event].startMatrix(), + catch_events[event].startLine())); + break; + } + break; + + case RDRecording::Playout: + if(!RDCut::exists(catch_events[event].cutName())) { + WriteExitCode(event,RDRecording::NoCut); + BroadcastCommand(QString(). + sprintf("RE %d %d %d!", + catch_events[event].channel(), + catch_playout_deck_status[catch_events[event]. + channel()-129], + catch_events[event].id())); + LogLine(RDConfig::LogNotice,QString(). + sprintf("playout aborted: no such cut: %s, id: %d", + (const char *)catch_events[event].cutName(), + catch_events[event].id())); + return; + } + catch_playout_card[catch_events[event].channel()-129]=-1; + catch_playout_stream[catch_events[event].channel()-129]=-1; + sql=QString().sprintf("select CARD_NUMBER,PORT_NUMBER,PORT_NUMBER \ + from DECKS where (STATION_NAME=\"%s\")&&(CHANNEL=%d)", + (const char *)catch_config->stationName(), + catch_events[event].channel()); + q=new RDSqlQuery(sql); + if(q->first()) { + catch_playout_id[catch_events[event].channel()-129]=id; + catch_playout_card[catch_events[event].channel()-129]= + q->value(0).toInt(); + catch_playout_stream[catch_events[event].channel()-129]= + q->value(1).toInt(); + catch_playout_port[catch_events[event].channel()-129]= + q->value(2).toInt(); + } + else { + LogLine(RDConfig::LogDebug,QString(). + sprintf("id %d specified non-existent play deck, ignored", + catch_events[event].id())); + delete q; + return; + } + delete q; + StartPlayout(event); + break; + + case RDRecording::MacroEvent: + if(!RDCart::exists(catch_events[event].macroCart())) { + WriteExitCode(event,RDRecording::NoCut); + BroadcastCommand(QString(). + sprintf("RE 0 0 %d!",catch_events[event].id())); + LogLine(RDConfig::LogDebug, + QString().sprintf("macro aborted: no such cart: %u, id: %d", + catch_events[event].macroCart(), + catch_events[event].id())); + return; + } + StartMacroEvent(event); + break; + + case RDRecording::SwitchEvent: + StartSwitchEvent(event); + break; + + case RDRecording::Download: + if(!RDCut::exists(catch_events[event].cutName())) { + WriteExitCode(event,RDRecording::NoCut); + BroadcastCommand(QString(). + sprintf("RE 0 0 %d!",catch_events[event].id())); + LogLine(RDConfig::LogDebug,QString(). + sprintf("download aborted: no such cut: %s, id: %d", + (const char *)catch_events[event].cutName(), + catch_events[event].id())); + return; + } + + // + // Load Import Parameters + // + sql=QString().sprintf("select DEFAULT_FORMAT,DEFAULT_CHANNELS,\ + DEFAULT_SAMPRATE,DEFAULT_LAYER,DEFAULT_BITRATE,\ + RIPPER_LEVEL\ + from RDLIBRARY where STATION=\"%s\"", + (const char *)catch_config->stationName()); + q=new RDSqlQuery(sql); + if(q->first()) + { + catch_default_format=q->value(0).toInt(); + catch_default_channels=q->value(1).toInt(); + catch_default_samplerate=q->value(2).toInt(); + catch_default_layer=q->value(3).toInt(); + catch_default_bitrate=q->value(4).toInt(); + catch_ripper_level=q->value(5).toInt(); + } + else { + LogLine(RDConfig::LogWarning, + "unable to load import audio configuration"); + delete q; + return; + } + delete q; + catch_events[event]. + setResolvedUrl(RDDateTimeDecode(catch_events[event].url(), + QDateTime(date.addDays(catch_events[event].eventdateOffset()), + current_time))); + StartDownloadEvent(event); + break; + + case RDRecording::Upload: + if(!RDCut::exists(catch_events[event].cutName())) { + WriteExitCode(event,RDRecording::NoCut); + BroadcastCommand(QString(). + sprintf("RE 0 0 %d!",catch_events[event].id())); + LogLine(RDConfig::LogNotice,QString(). + sprintf("upload aborted: no such cut: %s, id: %d", + (const char *)catch_events[event].cutName(), + catch_events[event].id())); + return; + } + StartUploadEvent(event); + break; + } +} + + +void MainObject::socketData(int ch) +{ + ParseCommand(ch); +} + + +void MainObject::socketKill(int ch) +{ + KillSocket(ch); +} + + +void MainObject::isConnectedData(bool state) +{ + if(!state) { + LogLine(RDConfig::LogErr, + "aborting - unable to connect to Core AudioEngine"); + exit(1); + } +} + + +void MainObject::recordLoadedData(int card,int stream) +{ + int deck=GetRecordDeck(card,stream); + catch_record_deck_status[deck-1]=RDDeck::Ready; + BroadcastCommand(QString().sprintf("RE %d %d %d!", + deck,catch_record_deck_status[deck-1], + catch_record_id[deck-1])); + LogLine(RDConfig::LogDebug,QString(). + sprintf("Loaded - Card: %d Stream: %d\n",card,stream)); +} + + +void MainObject::recordingData(int card,int stream) +{ + int deck=GetRecordDeck(card,stream); + catch_record_deck_status[deck-1]=RDDeck::Recording; + WriteExitCodeById(catch_record_id[deck-1],RDRecording::RecordActive); + QString cutname; + int event=GetEvent(catch_record_id[deck-1]); + if(event>=0) { + cutname=catch_events[event].cutName(); + } + BroadcastCommand(QString().sprintf("RE %d %d %d %s!", + deck,catch_record_deck_status[deck-1], + catch_record_id[deck-1], + (const char *)cutname)); + catch_record_status[deck-1]=true; + if(debug) { + printf("Recording - Card: %d Stream: %d, Id: %d\n",card,stream, + catch_record_id[deck-1]); + } +} + + +void MainObject::recordStoppedData(int card,int stream) +{ + int deck=GetRecordDeck(card,stream); + short levels[2]={-10000,-10000}; + + catch_record_status[deck-1]=false; + if(debug) { + printf("Stopped - Card: %d Stream: %d\n",card,stream); + } + SendMeterLevel(deck-1,levels); + catch_cae->unloadRecord(card,stream); +} + + +void MainObject::recordUnloadedData(int card,int stream,unsigned msecs) +{ + int deck=GetRecordDeck(card,stream); + if(deck<1) { + LogLine(RDConfig::LogDebug,QString(). + sprintf("invalid record deck: Card: %d Stream: %d", + card,stream)); + return; + } + int event=GetEvent(catch_record_id[deck-1]); + if(event<0) { + catch_record_deck_status[deck-1]=RDDeck::Idle; + catch_record_aborting[deck-1]=false; + LogLine(RDConfig::LogDebug,QString(). + sprintf("invalid record event: Id: %d", + catch_record_id[deck-1])); + RunRmlRecordingCache(deck); + return; + } + + if(catch_events[event].normalizeLevel()==0) { + CheckInRecording(catch_record_name[deck-1],&catch_events[event],msecs, + catch_record_threshold[deck-1]); + } + else { + StartBatch(catch_events[event].id()); + } + if(catch_record_aborting[deck-1]) { + LogLine(RDConfig::LogNotice,QString(). + sprintf("record aborted: cut %s", + (const char *)catch_record_name[deck-1])); + WriteExitCodeById(catch_record_id[deck-1],RDRecording::Interrupted); + } + else { + LogLine(RDConfig::LogInfo,QString(). + sprintf("record complete: cut %s", + (const char *)catch_record_name[deck-1])); + WriteExitCodeById(catch_record_id[deck-1],RDRecording::Ok); + } + BroadcastCommand(QString().sprintf("RE %d %d %d!", + deck,RDDeck::Idle, + catch_record_id[deck-1])); + catch_record_id[deck-1]=0; + if(debug) { + printf("Unloaded - Card: %d Stream: %d\n",card,stream); + } + if(catch_events[event].oneShot()) { + PurgeEvent(event); + } + catch_record_deck_status[deck-1]=RDDeck::Idle; + catch_events[event].setStatus(RDDeck::Idle); + catch_record_aborting[deck-1]=false; + + // + // Restart the event (if needed) + // + if((catch_events[event].type()==RDRecording::Recording)&& + (catch_events[event].startType()==RDRecording::GpiStart)&& + ((catch_events[event].endType()==RDRecording::GpiEnd)|| + (catch_events[event].endType()==RDRecording::LengthEnd))&& + catch_events[event].allowMultipleRecordings()) { + engineData(catch_events[event].id()); + } + else { + RunRmlRecordingCache(deck); + } +} + + +void MainObject::playLoadedData(int handle) +{ + int deck=GetPlayoutDeck(handle); + catch_playout_deck_status[deck-129]=RDDeck::Ready; + BroadcastCommand(QString().sprintf("RE %d %d %d!", + deck,catch_playout_deck_status[deck-129], + catch_playout_id[deck-129])); + if(debug) { + printf("Play Loaded - Card: %d Stream: %d\n", + catch_playout_card[deck-129], + catch_playout_stream[deck-129]); + } +} + + +void MainObject::playingData(int handle) +{ + int deck=GetPlayoutDeck(handle); + catch_playout_deck_status[deck-129]=RDDeck::Recording; + WriteExitCodeById(catch_playout_id[deck-129], + RDRecording::PlayActive); + BroadcastCommand(QString().sprintf("RE %d %d %d!", + deck,catch_playout_deck_status[deck-129], + catch_playout_id[deck-129])); + catch_playout_status[GetPlayoutDeck(handle)]=true; + if(debug) { + printf("Playing - Card: %d Stream: %d\n", + catch_playout_card[deck-129], + catch_playout_stream[deck-129]); + } +} + + +void MainObject::playStoppedData(int handle) +{ + int deck=GetPlayoutDeck(handle); + short levels[2]={-10000,-10000}; + + catch_playout_status[deck-129]=false; + LogLine(RDConfig::LogNotice,QString(). + sprintf("playout stopped: cut %s", + (const char *)catch_playout_name[deck-129])); + if(debug) { + printf("Playout stopped - Card: %d Stream: %d\n", + catch_playout_card[deck-129], + catch_playout_stream[deck-129]); + } + SendMeterLevel(deck,levels); + catch_cae->unloadPlay(handle); +} + + +void MainObject::playUnloadedData(int handle) +{ + int deck=GetPlayoutDeck(handle); + + LogLine(RDConfig::LogInfo,QString(). + sprintf("play complete: cut %s", + (const char *)catch_playout_name[deck-129])); + catch_playout_deck_status[deck-129]=RDDeck::Idle; + WriteExitCodeById(catch_playout_id[deck-129],RDRecording::Ok); + BroadcastCommand(QString().sprintf("RE %d %d %d!",deck, + catch_playout_deck_status[deck-129], + catch_playout_id[deck-129])); + if(debug) { + printf("Play unloaded - Card: %d Stream: %d\n", + catch_playout_card[deck-129],catch_playout_stream[deck-129]); + } + if(catch_events[catch_playout_event_id[deck-129]].oneShot()) { + PurgeEvent(catch_playout_event_id[deck-129]); + } + catch_events[catch_playout_event_id[deck-129]].setStatus(RDDeck::Idle); + catch_playout_event_id[deck-129]=-1; + catch_playout_id[deck-129]=0; +} + + +void MainObject::meterData() +{ + short levels[2]; + + for(int i=0;iinputMeterUpdate(catch_record_card[i],catch_record_stream[i], + levels); + SendMeterLevel(i+1,levels); + } + if(catch_playout_deck_status[i]==RDDeck::Recording) { + catch_cae-> + outputMeterUpdate(catch_playout_card[i],catch_playout_port[i], + levels); + SendMeterLevel(i+129,levels); + } + } +} + + +void MainObject::eventFinishedData(int id) +{ + LogLine(RDConfig::LogDebug,QString().sprintf("eventFinishedData(%d)",id)); + if(catch_macro_event_id[id]>=0) { + LogLine(RDConfig::LogDebug,QString(). + sprintf("Clearing event_id: %d",catch_macro_event_id[id])); + if(catch_macro_event_id[id]exists()) { + ExecuteMacroCart(cart); + } + delete cart; +} + + +void MainObject::updateXloadsData() +{ + vector::iterator it; + for(unsigned i=0;istop(); + } +} + + +void MainObject::startupCartData() +{ + unsigned cartnum=catch_rdstation->startupCart(); + if(cartnum>0) { + RDCart *cart=new RDCart(cartnum); + if(cart->exists()) { + ExecuteMacroCart(cart); + LogLine(RDConfig::LogInfo,QString(). + sprintf("ran startup cart %06u",cartnum)); + } + else { + LogLine(RDConfig::LogNotice,QString(). + sprintf("startup cart %06u was invalid",cartnum)); + } + delete cart; + } +} + + +bool MainObject::StartRecording(int event) +{ + QString str; + int length=0; + QTime current_time=QTime::currentTime(); + + if((event<0)||(event>=(int)catch_events.size())) { + LogLine(RDConfig::LogDebug,"invalid event offset received, ignored"); + return false; + } + + // + // Ensure the Deck is Valid + // + unsigned deck=catch_events[event].channel(); + if((catch_record_card[deck-1]<0)|| + (catch_record_stream[deck-1]<0)) { + WriteExitCodeById(catch_events[event].id(),RDRecording::InternalError); + BroadcastCommand(QString().sprintf("RE %d %d %d!", + deck,catch_record_deck_status[deck-1], + catch_events[event].id())); + LogLine(RDConfig::LogWarning,QString(). + sprintf("invalid audio device for deck: %d, event: %d", + deck,catch_events[event].id())); + return false; + } + + // + // Ensure the Deck is Available + // + if((catch_record_deck_status[deck-1]!=RDDeck::Idle)&& + (catch_record_deck_status[deck-1]!=RDDeck::Waiting)) { + WriteExitCodeById(catch_events[event].id(),RDRecording::DeviceBusy); + BroadcastCommand(QString().sprintf("RE %d %d %d!", + deck,catch_record_deck_status[deck-1], + catch_events[event].id())); + LogLine(RDConfig::LogNotice,QString(). + sprintf("device busy for deck: %d, event: %d | in use by event: %d", + deck,catch_events[event].id(),catch_record_id[deck-1])); + return false; + } + + // + // Get Record Length + // + switch(catch_events[event].endType()) { + case RDRecording::LengthEnd: + length=catch_events[event].length(); + break; + + case RDRecording::HardEnd: + length=current_time.msecsTo(catch_events[event].endTime()); + break; + + case RDRecording::GpiEnd: + length=current_time.msecsTo(catch_events[event].endTime(). + addMSecs(catch_events[event].endLength())); + if(catch_events[event].maxGpiRecordLength()setRole(RDMacro::Cmd); + rml->setAddress(catch_swaddress[deck-1]); + rml->setEchoRequested(false); + rml->setArgQuantity(3); + rml->setCommand(RDMacro::ST); + rml->setArg(0,catch_swmatrix[deck-1]); + rml->setArg(1,catch_events[event].switchInput()); + rml->setArg(2,catch_swoutput[deck-1]); + char str[RD_RML_MAX_LENGTH]; + if(rml->generateString(str,RD_RML_MAX_LENGTH)) { + catch_ripc->sendRml(rml); + LogLine(RDConfig::LogDebug,QString(). + sprintf("sending switcher command: %s",str)); + } + else { + LogLine(RDConfig::LogNotice,"switcher command is malformed!"); + } + delete rml; + } + + // + // Set Temp Name + // + RDCae::AudioCoding format=catch_events[event].format(); + QString cut_name; + if(catch_events[event].normalizeLevel()==0) { + cut_name=catch_events[event].cutName(); + } + else { + cut_name=QString().sprintf("rdcatchd-record-%d",catch_events[event].id()); + catch_events[event]. + setTempName(GetTempRecordingName(catch_events[event].id())); + catch_events[event].setDeleteTempFile(true); + format=RDCae::Pcm16; + } + + // + // Start the recording + // + catch_cae->loadRecord(catch_record_card[deck-1], + catch_record_stream[deck-1], + cut_name, + format, + catch_events[event].channels(), + catch_events[event].sampleRate(), + catch_events[event].bitrate()); + catch_cae->record(catch_record_card[deck-1],catch_record_stream[deck-1], + length,0); + catch_events[event].setStatus(RDDeck::Recording); + + str=QString().sprintf("record started: deck: %d, event: %d", + deck,catch_events[event].id()); + str+=QString().sprintf(" card: %d, stream: %d, cut: %s length: %d", + catch_record_card[deck-1], + catch_record_stream[deck-1], + (const char *)cut_name,length); + LogLine(RDConfig::LogInfo,str); + + // + // Cache Selected Fields + // + catch_record_name[deck-1]=catch_events[event].cutName(); + catch_record_threshold[deck-1]=catch_events[event].trimThreshold(); + catch_record_id[deck-1]=catch_events[event].id(); + + // + // Update Cut Record + // + RDCut *cut=new RDCut(catch_events[event].cutName()); + cut->setOriginDatetime(QDateTime::currentDateTime()); + cut->setOriginName(catch_config->stationName()); + switch(catch_events[event].format()) { + case RDCae::Pcm16: + cut->setCodingFormat(0); + break; + + case RDCae::MpegL2: + cut->setCodingFormat(1); + break; + + default: + cut->setCodingFormat(0); + break; + } + cut->setChannels(catch_events[event].channels()); + cut->setSampleRate(catch_events[event].sampleRate()); + cut->setBitRate(catch_events[event].bitrate()); + cut->setPlayCounter(0); + cut->setSegueStartPoint(-1); + cut->setSegueEndPoint(-1); + cut->setTalkStartPoint(-1); + cut->setTalkEndPoint(-1); + cut->setHookStartPoint(-1); + cut->setHookEndPoint(-1); + cut->setFadeupPoint(-1); + cut->setFadedownPoint(-1); + bool valid; + QDateTime datetime=cut->startDatetime(&valid); + if(valid) { + datetime.setDate(QDate::currentDate(). + addDays(catch_events[event].startdateOffset())); + cut->setStartDatetime(datetime,true); + datetime=cut->endDatetime(&valid); + datetime.setDate(QDate::currentDate(). + addDays(catch_events[event].enddateOffset())); + cut->setEndDatetime(datetime,true); + } + delete cut; + + return true; +} + + +void MainObject::StartPlayout(int event) +{ + unsigned deck=catch_events[event].channel(); + if((catch_playout_card[deck-129]<0)) { + LogLine(RDConfig::LogWarning,QString(). + sprintf("invalid audio device for deck: %d, event: %d", + deck,catch_events[event].id())); + return; + } + + // + // Get cut parameters + // + QString sql=QString().sprintf("select START_POINT,END_POINT from CUTS\ + where CUT_NAME=\"%s\"", + (const char *)catch_events[event].cutName()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + return; + } + int start=q->value(0).toInt(); + int end=q->value(1).toInt(); + delete q; + + // + // Start the playout + // + catch_cae->loadPlay(catch_playout_card[deck-129], + catch_events[event].cutName(), + &catch_playout_stream[deck-129], + &catch_playout_handle[deck-129]); + RDSetMixerOutputPort(catch_cae,catch_playout_card[deck-129], + catch_playout_stream[deck-129], + catch_playout_port[deck-129]); + catch_cae->positionPlay(catch_playout_handle[deck-129],start); + catch_cae-> + play(catch_playout_handle[deck-129],end-start,RD_TIMESCALE_DIVISOR,0); + catch_cae->setPlayPortActive(catch_playout_card[deck-129], + catch_playout_port[deck-129], + catch_playout_stream[deck-129]); + catch_events[event].setStatus(RDDeck::Recording); + + LogLine(RDConfig::LogDebug,QString(). + sprintf("playout started: deck: %d, event %d", + deck,catch_events[event].id())); + LogLine(RDConfig::LogDebug,QString(). + sprintf(" card %d, stream %d , cut=%s", + catch_playout_card[deck-129], + catch_playout_stream[deck-129], + (const char *)catch_events[event].cutName())); + + // + // Cache Selected Fields + // + catch_playout_name[deck-129]=catch_events[event].cutName(); + catch_playout_event_id[deck-129]=event; +} + + +void MainObject::StartMacroEvent(int event) +{ + RDCart *cart=new RDCart(catch_events[event].macroCart()); + if(!cart->exists()) { + LogLine(RDConfig::LogWarning,QString(). + sprintf("cart %u does not exist!", + catch_events[event].macroCart())); + delete cart; + return; + } + if(cart->type()!=RDCart::Macro) { + LogLine(RDConfig::LogWarning,QString(). + sprintf("%u is not a macro cart!", + catch_events[event].macroCart())); + delete cart; + return; + } + if(ExecuteMacroCart(cart,catch_events[event].id(),event)) { + LogLine(RDConfig::LogInfo,QString(). + sprintf("executing macro cart: %u",catch_events[event].macroCart())); + } + delete cart; +} + + +void MainObject::StartSwitchEvent(int event) +{ + char cmd[RD_RML_MAX_LENGTH]; + + RDMacro *rml=new RDMacro(); + rml->setAddress(catch_rdstation->address()); + rml->setRole(RDMacro::Cmd); + rml->setEchoRequested(false); + rml->setCommand(RDMacro::ST); + rml->setArgQuantity(3); + rml->setArg(0,catch_events[event].channel()); + rml->setArg(1,catch_events[event].switchInput()); + rml->setArg(2,catch_events[event].switchOutput()); + rml->generateString(cmd,RD_RML_MAX_LENGTH); + LogLine(RDConfig::LogInfo,QString(). + sprintf("sent switch event, rml: %s",cmd)); + catch_ripc->sendRml(rml); + delete rml; + if(catch_events[event].oneShot()) { + PurgeEvent(event); + } +} + + +void MainObject::StartDownloadEvent(int event) +{ + WriteExitCode(event,RDRecording::Downloading); + catch_active_xloads.push_back(event); + if(!catch_xload_timer->isActive()) { + catch_xload_timer->start(XLOAD_UPDATE_INTERVAL); + } + BroadcastCommand(QString().sprintf("RE 0 %d %d!", + RDDeck::Recording, + catch_events[event].id())); + StartBatch(catch_events[event].id()); +} + + +void MainObject::StartUploadEvent(int event) +{ + WriteExitCode(event,RDRecording::Uploading); + catch_active_xloads.push_back(event); + if(!catch_xload_timer->isActive()) { + catch_xload_timer->start(XLOAD_UPDATE_INTERVAL); + } + BroadcastCommand(QString().sprintf("RE 0 %d %d!",RDDeck::Recording, + catch_events[event].id())); + StartBatch(catch_events[event].id()); +} + + +bool MainObject::ExecuteMacroCart(RDCart *cart,int id,int event) +{ + int event_id=GetFreeEvent(); + if(event_id<0) { + LogLine(RDConfig::LogWarning,"unable to allocate event context!"); + return false; + } + if(event!=-1) { + catch_events[event].setStatus(RDDeck::Recording); + } + if(id!=-1) { + BroadcastCommand(QString().sprintf("RE 0 %d %d!",RDDeck::Recording,id)); + } + catch_macro_event_id[event_id]=id; + catch_event_pool[event_id]= + new RDMacroEvent(catch_rdstation->address(),catch_ripc,this,"event"); + catch_event_mapper->setMapping(catch_event_pool[event_id],event_id); + connect(catch_event_pool[event_id],SIGNAL(finished()), + catch_event_mapper,SLOT(map())); + QString cmd=cart->macros(); + catch_event_pool[event_id]->load(cmd); + catch_event_pool[event_id]->exec(); + return true; +} + + +void MainObject::SendFullStatus(int ch) +{ + for(unsigned i=0;ireadBlock(buf,256))>0) { + buf[c]=0; + for(int i=0;iclose(); + KillSocket(ch); + return; + } + if(!strcmp(args[ch][0],"PW")) { // Password Authenticate + if(!strcmp(args[ch][1],catch_config->password())) { + auth[ch]=true; + EchoCommand(ch,"PW +!"); + return; + } + else { + auth[ch]=false; + EchoCommand(ch,"PW -!"); + return; + } + } + + // + // Priviledged Commands + // Authentication required to execute these! + // + if(!auth[ch]) { + EchoArgs(ch,'-'); + return; + } + + if(!strcmp(args[ch][0],"RS")) { // Reset + EchoArgs(ch,'+'); + LoadEngine(); + } + + if(!strcmp(args[ch][0],"RA")) { // Add Event + if(AddEvent(QString(args[ch][1]).toInt())) { + EchoArgs(ch,'+'); + BroadcastCommand(QString().sprintf("RU %s!",args[ch][1]),ch); + } + else { + EchoArgs(ch,'-'); + } + } + + if(!strcmp(args[ch][0],"RR")) { // Remove Event + RemoveEvent(QString(args[ch][1]).toInt()); + EchoArgs(ch,'+'); + BroadcastCommand(QString().sprintf("RU %s!",args[ch][1]),ch); + } + + if(!strcmp(args[ch][0],"RU")) { // Update Event + if(UpdateEvent(QString(args[ch][1]).toInt())) { + EchoArgs(ch,'+'); + } + else { + EchoArgs(ch,'-'); + } + } + + if(!strcmp(args[ch][0],"RD")) { // Load Deck List + EchoArgs(ch,'+'); + LoadDeckList(); + } + + if(!strcmp(args[ch][0],"RO")) { // Reload Time Offset + EchoArgs(ch,'+'); + catch_engine->setTimeOffset(catch_rdstation->timeOffset()); + } + + if(!strcmp(args[ch][0],"RE")) { // Request Status + if(sscanf(args[ch][1],"%u",&chan)!=1) { + EchoArgs(ch,'-'); + return; + } + if(chan==0) { + SendFullStatus(ch); + return; + } + chan--; + if(chan=128)&&(chan<(MAX_DECKS+128))) { + if(catch_playout_deck_status[chan-128]==RDDeck::Offline) { + EchoArgs(ch,'-'); + return; + } + EchoCommand(ch, + QString().sprintf("RE %u %d %d!", + chan+1,catch_playout_deck_status[chan-128], + catch_playout_id[chan-128])); + return; + } + EchoArgs(ch,'-'); + return; + } + + if(!strcmp(args[ch][0],"RM")) { // Enable/Disable Metering + if(!strcmp(args[ch][1],"0")) { // Disable Metering + catch_meter_enabled[ch]=false; + } + if(!strcmp(args[ch][1],"1")) { // Enable Metering + catch_meter_enabled[ch]=true; + } + } + + if(!strcmp(args[ch][0],"SR")) { // Stop Recording + if(sscanf(args[ch][1],"%d",&chan)!=1) { + return; + } + if((chan>0)&&(chan<(MAX_DECKS+1))) { + switch(catch_record_deck_status[chan-1]) { + case RDDeck::Recording: + catch_record_aborting[chan-1]=true; + catch_cae->stopRecord(catch_record_card[chan-1], + catch_record_stream[chan-1]); + break; + + case RDDeck::Waiting: + startTimerData(catch_record_id[chan-1]); + break; + + default: + break; + } + } + if((chan>128)&&(chan<(MAX_DECKS+129))) { + switch(catch_playout_deck_status[chan-129]) { + case RDDeck::Recording: + catch_cae->stopPlay(catch_playout_handle[chan-129]); + break; + + default: + break; + } + } + } + + if(!strcmp(args[ch][0],"RH")) { // Reload Heartbeat Configuration + LoadHeartbeat(); + } + + if(!strcmp(args[ch][0],"RX")) { // Restart Dropbox Instances + StartDropboxes(); + } + + if(!strcmp(args[ch][0],"MN")) { // Monitor State + if(sscanf(args[ch][1],"%d",&chan)!=1) { + return; + } + if((chan>0)&&(chan<(MAX_DECKS+1))) { + if(catch_monitor_port[chan-1]>=0) { + if(args[ch][2][0]=='1') { + catch_cae->setPassthroughVolume(catch_record_card[chan-1], + catch_record_stream[chan-1], + catch_monitor_port[chan-1],0); + catch_monitor_state[chan-1]=true; + BroadcastCommand(QString().sprintf("MN %d 1!",chan)); + } + else { + catch_cae->setPassthroughVolume(catch_record_card[chan-1], + catch_record_stream[chan-1], + catch_monitor_port[chan-1], + RD_MUTE_DEPTH); + catch_monitor_state[chan-1]=false; + BroadcastCommand(QString().sprintf("MN %d 0!",chan)); + } + } + } + } + + if(!strcmp(args[ch][0],"SC")) { // Set Exit Code + if(sscanf(args[ch][1],"%d",&id)!=1) { + return; + } + if(sscanf(args[ch][2],"%d",&code)!=1) { + return; + } + str=""; + for(int i=3;istate()==QSocket::Connection) { + socket[ch]->writeBlock(command,strlen(command)); + } +} + + +void MainObject::BroadcastCommand(const char *command,int except_ch) +{ +// LogLine(RDConfig::LogDebug,QString().sprintf("rdcatchd: BroadcastCommand(%s)",command)); + for(int i=0;iname()); + q=new RDSqlQuery(sql); + while(q->next()) { + catch_events.push_back(CatchEvent()); + LoadEvent(q,&catch_events.back(),true); + } + LogLine(RDConfig::LogInfo,QString().sprintf("loaded %d events",(int)catch_events.size())); + delete q; + LogLine(RDConfig::LogInfo,"rdcatchd engine load ends"); +} + + +QString MainObject::LoadEventSql() +{ + return QString("select ID,IS_ACTIVE,TYPE,CHANNEL,CUT_NAME,\ + SUN,MON,TUE,WED,THU,FRI,SAT,START_TIME,LENGTH,\ + START_GPI,END_GPI,TRIM_THRESHOLD,STARTDATE_OFFSET,\ + ENDDATE_OFFSET,FORMAT,CHANNELS,SAMPRATE,BITRATE,\ + MACRO_CART,SWITCH_INPUT,SWITCH_OUTPUT,ONE_SHOT,\ + START_TYPE,START_LENGTH,START_MATRIX,START_LINE,\ + START_OFFSET,END_TYPE,END_TIME,END_LENGTH,\ + END_MATRIX,END_LINE,URL,URL_USERNAME,URL_PASSWORD,\ + QUALITY,NORMALIZE_LEVEL,ALLOW_MULT_RECS,\ + MAX_GPI_REC_LENGTH,DESCRIPTION,FEED_ID,\ + EVENTDATE_OFFSET,ENABLE_METADATA from RECORDINGS"); +} + + +void MainObject::LoadEvent(RDSqlQuery *q,CatchEvent *e,bool add) +{ + e->setId(q->value(0).toUInt()); + e->setIsActive(RDBool(q->value(1).toString())); + e->setType((RDRecording::Type)q->value(2).toInt()); + e->setChannel(q->value(3).toUInt()); + e->setCutName(q->value(4).toString()); + e->setDayOfWeek(7,RDBool(q->value(5).toString())); + e->setDayOfWeek(1,RDBool(q->value(6).toString())); + e->setDayOfWeek(2,RDBool(q->value(7).toString())); + e->setDayOfWeek(3,RDBool(q->value(8).toString())); + e->setDayOfWeek(4,RDBool(q->value(9).toString())); + e->setDayOfWeek(5,RDBool(q->value(10).toString())); + e->setDayOfWeek(6,RDBool(q->value(11).toString())); + e->setStartTime(q->value(12).toTime()); + e->setLength(q->value(13).toUInt()); + e->setStartGpi(q->value(14).toInt()); + e->setEndGpi(q->value(15).toInt()); + e->setTrimThreshold(q->value(16).toUInt()); + e->setStartdateOffset(q->value(17).toUInt()); + e->setEnddateOffset(q->value(18).toUInt()); + e->setFormat((RDCae::AudioCoding)q->value(19).toInt()); + e->setChannels(q->value(20).toInt()); + e->setSampleRate(catch_system->sampleRate()); + //e->setSampleRate(q->value(21).toInt()); + e->setBitrate(q->value(22).toInt()); + e->setMacroCart(q->value(23).toInt()); + e->setSwitchInput(q->value(24).toInt()); + e->setSwitchOutput(q->value(25).toInt()); + e->setStatus(RDDeck::Idle); + e->setOneShot(RDBool(q->value(26).toString())); + e->setStartType((RDRecording::StartType)q->value(27).toInt()); + e->setStartLength(q->value(28).toInt()); + e->setStartMatrix(q->value(29).toInt()); + e->setStartLine(q->value(30).toInt()); + e->setStartOffset(q->value(31).toInt()); + e->setEndType((RDRecording::EndType)q->value(32).toInt()); + e->setEndTime(q->value(33).toTime()); + e->setEndLength(q->value(34).toInt()); + e->setEndMatrix(q->value(35).toInt()); + e->setEndLine(q->value(36).toInt()); + e->setUrl(q->value(37).toString()); + e->setUrlUsername(q->value(38).toString()); + e->setUrlPassword(q->value(39).toString()); + e->setQuality(q->value(40).toInt()); + e->setNormalizeLevel(q->value(41).toInt()); + e->setAllowMultipleRecordings(RDBool(q->value(42).toString())); + e->setMaxGpiRecordLength(q->value(43).toUInt()); + e->setDescription(q->value(44).toString()); + e->setFeedId(q->value(45).toUInt()); + e->setEventdateOffset(q->value(46).toInt()); + e->setEnableMetadata(RDBool(q->value(47).toString())); + + if(add) { + if(e->startType()==RDRecording::GpiStart) { + e->setGpiStartTimer(new QTimer(this)); + catch_gpi_start_mapper->setMapping(e->gpiStartTimer(),e->id()); + connect(e->gpiStartTimer(),SIGNAL(timeout()), + catch_gpi_start_mapper,SLOT(map())); + e->setGpiOffsetTimer(new QTimer(this)); + catch_gpi_offset_mapper->setMapping(e->gpiOffsetTimer(),e->id()); + connect(e->gpiOffsetTimer(),SIGNAL(timeout()), + catch_gpi_offset_mapper,SLOT(map())); + } + catch_engine->addEvent(e->id(),e->startTime()); + } +} + + +void MainObject::LoadDeckList() +{ + RDDeck::Status status[MAX_DECKS]; + + // + // Record Decks + // + for(int i=0;i0)&&(CHANNEL<9)", + (const char *)catch_config->stationName()); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + status[q->value(0).toUInt()-1]=RDDeck::Idle; + catch_record_card[q->value(0).toUInt()-1]=q->value(1).toInt(); + catch_record_stream[q->value(0).toUInt()-1]=q->value(2).toInt(); + catch_monitor_port[q->value(0).toUInt()-1]=q->value(3).toInt(); + } + delete q; + for(int i=0;istopRecord(catch_record_card[i],catch_record_stream[i]); + catch_record_deck_status[i]=RDDeck::Offline; + } + } + else { + catch_record_deck_status[i]=status[i]; + } + } + + // + // Playout Decks + // + for(int i=0;i128)&&(CHANNEL<137)", + (const char *)catch_config->stationName()); + q=new RDSqlQuery(sql); + while(q->next()) { + status[q->value(0).toUInt()-129]=RDDeck::Idle; + } + delete q; + for(int i=0;istopPlay(catch_playout_handle[i]); + catch_playout_deck_status[i]=RDDeck::Offline; + } + } + else { + catch_playout_deck_status[i]=status[i]; + } + } +} + + +int MainObject::GetRecordDeck(int card,int stream) +{ + for(int i=0;iname(),id); + q=new RDSqlQuery(sql); + if(q->first()) { + catch_events.push_back(CatchEvent()); + LoadEvent(q,&catch_events.back(),true); + switch((RDRecording::Type)q->value(2).toInt()) { + case RDRecording::Recording: + LogLine(RDConfig::LogNotice,QString(). + sprintf("loading event %d, Type: recording, Cut: %s", + id,(const char *)q->value(4).toString())); + break; + + case RDRecording::Playout: + LogLine(RDConfig::LogNotice,QString(). + sprintf("loading event %d, Type: playout, Cut: %s", + id,(const char *)q->value(4).toString())); + break; + + case RDRecording::MacroEvent: + LogLine(RDConfig::LogNotice,QString(). + sprintf("loading event %d, Type: macro, Cart: %d", + id,q->value(23).toUInt())); + break; + + case RDRecording::SwitchEvent: + LogLine(RDConfig::LogNotice,QString().sprintf( + "loading event %d, Type: switch, Matrix: %d, Source: %d Dest: %d", + id,q->value(3).toInt(),q->value(24).toInt(), + q->value(25).toInt())); + break; + + case RDRecording::Download: + LogLine(RDConfig::LogNotice,QString(). + sprintf("loading event %d, Type: download, Cut: %s", + id,(const char *)q->value(4).toString())); + break; + + case RDRecording::Upload: + LogLine(RDConfig::LogNotice,QString(). + sprintf("loading event %d, Type: upload, Cut: %s", + id,(const char *)q->value(4).toString())); + break; + } + delete q; + return true; + } + LogLine(RDConfig::LogWarning,QString().sprintf("event %d not found, not loaded",id)); + delete q; + return false; +} + + +void MainObject::RemoveEvent(int id) +{ + int event=GetEvent(id); + if(event<0) { + LogLine(RDConfig::LogNotice,QString(). + sprintf("event %d not found, not removed",id)); + return; + } + switch(catch_events[event].type()) { + case RDRecording::Recording: + LogLine(RDConfig::LogDebug,QString(). + sprintf("removed event %d, Type: recording, Cut: %s", + id,(const char *)catch_events[event].cutName())); + break; + + case RDRecording::Playout: + LogLine(RDConfig::LogDebug,QString(). + sprintf("removed event %d, Type: playout, Cut: %s", + id, + (const char *)catch_events[event].cutName())); + break; + + case RDRecording::MacroEvent: + LogLine(RDConfig::LogDebug,QString(). + sprintf("removed event %d, Type: macro, Cart: %u", + id, + catch_events[event].macroCart())); + break; + + case RDRecording::SwitchEvent: + LogLine(RDConfig::LogDebug,QString().sprintf( + "removed event %d, Type: switch, Matrix: %d, Source: %d Dest: %d", + id, + catch_events[event].channel(), + catch_events[event].switchInput(), + catch_events[event].switchOutput())); + break; + + case RDRecording::Download: + LogLine(RDConfig::LogDebug,QString(). + sprintf("removed event %d, Type: download, Cut: %s", + id,(const char *)catch_events[event].cutName())); + break; + + case RDRecording::Upload: + LogLine(RDConfig::LogDebug,QString(). + sprintf("removed event %d, Type: upload, Cut: %s", + id,(const char *)catch_events[event].cutName())); + break; + + } + vector::iterator it=catch_events.begin()+event; + catch_events.erase(it,it+1); + catch_engine->removeEvent(id); +} + + +bool MainObject::UpdateEvent(int id) +{ + RemoveEvent(id); + return AddEvent(id); +} + + +int MainObject::GetEvent(int id) +{ + for(unsigned i=0;iremoveEvent(catch_events[event].id()); + vector::iterator it=catch_events.begin()+event; + catch_events.erase(it,it+1); +} + + +void MainObject::LoadHeartbeat() +{ + if(catch_heartbeat_timer->isActive()) { + catch_heartbeat_timer->stop(); + } + QString sql=QString().sprintf("select HEARTBEAT_CART,HEARTBEAT_INTERVAL\ + from STATIONS where NAME=\"%s\"", + (const char *)catch_rdstation->name()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + if((q->value(0).toUInt()!=0)&&(q->value(1).toUInt()!=0)) { + catch_heartbeat_cart=q->value(0).toUInt(); + sysHeartbeatData(); + catch_heartbeat_timer->start(q->value(1).toUInt()); + } + } + delete q; +} + + +void MainObject::CheckInRecording(QString cutname,CatchEvent *evt, + unsigned msecs,unsigned threshold) +{ + RDCut *cut=new RDCut(cutname); + RDSettings *s=new RDSettings(); + s->setFormat((RDSettings::Format)evt->format()); + s->setSampleRate(evt->sampleRate()); + s->setBitRate(evt->bitrate()); + s->setChannels(evt->channels()); + cut->checkInRecording(catch_config->stationName(),s,msecs); + delete s; + cut->autoTrim(RDCut::AudioBoth,-threshold); + RDCart *cart=new RDCart(cut->cartNumber()); + cart->updateLength(); + delete cart; + delete cut; + chown(RDCut::pathName(cutname),catch_config->uid(),catch_config->gid()); +} + + +void MainObject::CheckInPodcast(CatchEvent *e) const +{ + QString sql; + RDSqlQuery *q; + + // + // Purge Stale Casts + // + sql=QString().sprintf("delete from PODCASTS where \ + (FEED_ID=%d)&&(AUDIO_FILENAME=\"%s\")", + e->feedId(), + (const char *)RDGetBasePart(e->resolvedUrl())); + q=new RDSqlQuery(sql); + delete q; + + // + // Get Channel Parameters + // + sql=QString().sprintf("select ENABLE_AUTOPOST,CHANNEL_TITLE,\ + CHANNEL_DESCRIPTION,CHANNEL_CATEGORY,\ + CHANNEL_LINK,MAX_SHELF_LIFE from FEEDS \ + where ID=%u",e->feedId()); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + return; + } + + // + // Add the Cast Entry + // + RDPodcast::Status status=RDPodcast::StatusPending; + if(q->value(0).toString().lower()=="y") { + status=RDPodcast::StatusActive; + } + sql=QString().sprintf("insert into PODCASTS set \ + FEED_ID=%u,\ + STATUS=%u,\ + ITEM_TITLE=\"%s\",\ + ITEM_DESCRIPTION=\"%s\",\ + ITEM_CATEGORY=\"%s\",\ + ITEM_LINK=\"%s\",\ + AUDIO_FILENAME=\"%s\",\ + AUDIO_LENGTH=%u,\ + AUDIO_TIME=%u,\ + SHELF_LIFE=%u,\ + EFFECTIVE_DATETIME=now(),\ + ORIGIN_DATETIME=now()", + e->feedId(), + status, + (const char *)RDEscapeString(q->value(1).toString()), + (const char *)RDEscapeString(q->value(2).toString()), + (const char *)RDEscapeString(q->value(3).toString()), + (const char *)RDEscapeString(q->value(4).toString()), + (const char *)RDGetBasePart(e->resolvedUrl()), + e->podcastLength(), + e->podcastTime(), + q->value(5).toUInt()); + delete q; + q=new RDSqlQuery(sql); + delete q; + + // + // Update the Build Date + // + sql=QString().sprintf("update FEEDS set LAST_BUILD_DATETIME=now() \ + where ID=%u",e->feedId()); + q=new RDSqlQuery(sql); + delete q; +} + + +RDRecording::ExitCode MainObject::ReadExitCode(int event) +{ + RDRecording::ExitCode code=RDRecording::InternalError; + QString sql=QString().sprintf("select EXIT_CODE from RECORDINGS\ + where ID=%d",catch_events[event].id()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + code=(RDRecording::ExitCode)q->value(0).toInt(); + } + delete q; + + return code; +} + + +void MainObject::WriteExitCode(int event,RDRecording::ExitCode code, + const QString &err_text) +{ + QString sql=QString().sprintf("update RECORDINGS set EXIT_CODE=%d,\ + EXIT_TEXT=\"%s\"\ + where ID=%d",code, + (const char *)RDEscapeString(err_text), + catch_events[event].id()); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + switch(code) { + case RDRecording::Ok: + case RDRecording::Downloading: + case RDRecording::Uploading: + case RDRecording::RecordActive: + case RDRecording::PlayActive: + case RDRecording::Waiting: + break; + + case RDRecording::ServerError: + case RDRecording::InternalError: + SendErrorMessage(&catch_events[event], + RDRecording::exitString(code)+": "+err_text, + catch_conf->errorRml()); + break; + + default: + SendErrorMessage(&catch_events[event],RDRecording::exitString(code), + catch_conf->errorRml()); + break; + } +} + + +void MainObject::WriteExitCodeById(int id,RDRecording::ExitCode code, + const QString &err_text) +{ + QString sql=QString().sprintf("update RECORDINGS set EXIT_CODE=%d,\ + EXIT_TEXT=\"%s\" \ + where ID=%d",code, + (const char *)RDEscapeString(err_text), + id); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; +} + + +QString MainObject::BuildTempName(int event,QString str) +{ + return BuildTempName(&catch_events[event],str); +} + + +QString MainObject::BuildTempName(CatchEvent *evt,QString str) +{ + return QString().sprintf("%s/rdcatchd-%s-%d.%s",(const char *)catch_temp_dir, + (const char *)str,evt->id(), + (const char *)GetFileExtension(evt->resolvedUrl())); +} + + +QString MainObject::GetFileExtension(QString filename) +{ + for(int i=filename.length()-1;i>=0;i--) { + if(((const char *)filename)[i]=='/') { + return QString(); + } + if(((const char *)filename)[i]=='.') { + return filename.right(filename.length()-i-1); + } + } + return QString(); +} + +/* This is an overloaded virtual function to tell a session manager not to restart this daemon. */ +void QApplication::saveState(QSessionManager &sm) { + sm.setRestartHint(QSessionManager::RestartNever); + LogLine(RDConfig::LogDebug,"rdcatchd saveState(), set restart hint to Never"); + return; +}; + + +bool MainObject::SendErrorMessage(CatchEvent *event,const QString &err_desc, + QString rml) +{ + if(rml.isEmpty()) { + return false; + } + ResolveErrorWildcards(event,err_desc,&rml); + + // + // Execute the RML + // + int event_id=GetFreeEvent(); + if(event_id<0) { + LogLine(RDConfig::LogWarning,"unable to allocate event context!"); + } + catch_macro_event_id[event_id]=event->id()+RDCATCHD_ERROR_ID_OFFSET; + catch_event_pool[event_id]= + new RDMacroEvent(catch_rdstation->address(),catch_ripc,this,"event"); + catch_event_mapper->setMapping(catch_event_pool[event_id],event_id); + connect(catch_event_pool[event_id],SIGNAL(finished()), + catch_event_mapper,SLOT(map())); + bool res=catch_event_pool[event_id]->load(rml); + catch_event_pool[event_id]->exec(); + LogLine(RDConfig::LogNotice,QString(). + sprintf("executed error rml: id=%d, rml=\"%s\", res=%d", + event->id(),(const char *)rml,res)); + return true; +} + + +void MainObject::ResolveErrorWildcards(CatchEvent *event, + const QString &err_desc,QString *rml) +{ + rml->replace("%d",event->description()); + rml->replace("%e",err_desc); // Error Description + rml->replace("%i",QString().sprintf("%u",event->id())); + rml->replace("%t",event->startTime().toString("hh:mm:ss")); + rml->replace("%y",RDRecording::typeString(event->type())); + switch(event->type()) { + case RDRecording::Recording: + rml->replace("%k",QString().sprintf("%d",event->channel())); + rml->replace("%n",event->cutName().left(6)); + rml->replace("%u","n/a"); + break; + + case RDRecording::Playout: + rml->replace("%k",QString().sprintf("%d",event->channel()-128)); + rml->replace("%n",event->cutName().left(6)); + rml->replace("%u","n/a"); + break; + + case RDRecording::Upload: + rml->replace("%k","n/a"); + rml->replace("%n",event->cutName().left(6)); + rml->replace("%u",event->resolvedUrl()); + break; + + case RDRecording::Download: + rml->replace("%k","n/a"); + rml->replace("%n",event->cutName().left(6)); + rml->replace("%u",event->resolvedUrl()); + break; + + case RDRecording::MacroEvent: + rml->replace("%k","n/a"); + rml->replace("%n",QString().sprintf("%06u",event->macroCart())); + rml->replace("%u","n/a"); + break; + + case RDRecording::SwitchEvent: + rml->replace("%k","n/a"); + rml->replace("%n",tr("n/a")); + rml->replace("%u","n/a"); + break; + } +} + + +void MainObject::StartDropboxes() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + // + // Kill Old Instances + // + system("killall rdimport"); + + // + // Launch Dropbox Configurations + // + sql=QString("select ID,GROUP_NAME,PATH,NORMALIZATION_LEVEL,")+ + "AUTOTRIM_LEVEL,TO_CART,USE_CARTCHUNK_ID,TITLE_FROM_CARTCHUNK_ID,"+ + "DELETE_CUTS,METADATA_PATTERN,FIX_BROKEN_FORMATS,LOG_PATH,"+ + "DELETE_SOURCE,STARTDATE_OFFSET,ENDDATE_OFFSET,ID,"+ + "IMPORT_CREATE_DATES,CREATE_STARTDATE_OFFSET,"+ + "CREATE_ENDDATE_OFFSET,SET_USER_DEFINED "+ + "from DROPBOXES where STATION_NAME=\""+ + RDEscapeString(catch_config->stationName())+"\""; + q=new RDSqlQuery(sql); + while(q->next()) { + QString cmd=QString(). + sprintf("nice rdimport --persistent-dropbox-id=%d --drop-box --log-mode", + q->value(15).toInt()); + sql=QString("select SCHED_CODE from DROPBOX_SCHED_CODES where ")+ + QString().sprintf("DROPBOX_ID=%d",q->value(0).toInt()); + q1=new RDSqlQuery(sql); + while(q1->next()) { + cmd+=QString(" --add-scheduler-code=\"")+q1->value(0).toString()+"\""; + } + delete q1; + cmd+= + QString().sprintf(" --normalization-level=%d",q->value(3).toInt()/100); + cmd+= + QString().sprintf(" --autotrim-level=%d",q->value(4).toInt()/100); + if(q->value(5).toUInt()>0) { + cmd+=QString().sprintf(" --to-cart=%u",q->value(5).toUInt()); + } + if(q->value(6).toString()=="Y") { + cmd+=" --use-cartchunk-cutid"; + } + if(q->value(7).toString()=="Y") { + cmd+=" --title-from-cartchunk-cutid"; + } + if(q->value(8).toString()=="Y") { + cmd+=" --delete-cuts"; + } + if(!q->value(9).toString().isEmpty()) { + cmd+=QString().sprintf(" \"--metadata-pattern=%s\"", + (const char *)q->value(9).toString()); + } + if(q->value(10).toString()=="Y") { + cmd+=" --fix-broken-formats"; + } + if(q->value(12).toString()=="Y") { + cmd+=" --delete-source"; + } + if(q->value(16).toString()=="Y") { + cmd+=QString().sprintf(" --create-startdate-offset=%d", + q->value(17).toInt()); + cmd+=QString().sprintf(" --create-enddate-offset=%d", + q->value(18).toInt()); + } + if(!q->value(19).toString().isEmpty()) { + cmd+=" --set-user-defined="+RDEscapeString(q->value(19).toString()); + } + cmd+=QString().sprintf(" --startdate-offset=%d",q->value(13).toInt()); + cmd+=QString().sprintf(" --enddate-offset=%d",q->value(14).toInt()); + cmd+=QString().sprintf(" %s \"%s\"",(const char *)q->value(1).toString(), + (const char *)q->value(2).toString()); + if(!q->value(11).toString().isEmpty()) { + cmd+=QString().sprintf(" >> %s 2>> %s", + (const char *)q->value(11).toString(), + (const char *)q->value(11).toString()); + } + else { + cmd+=" > /dev/null 2> /dev/null"; + } + cmd+=" &"; + LogLine(RDConfig::LogInfo,QString(). + sprintf("launching dropbox configuration: \"%s\"", + (const char *)cmd)); + if(fork()==0) { + system(cmd); + exit(0); + } + } + delete q; +} + + +unsigned MainObject::GetNextDynamicId() +{ + unsigned id=RDCATCHD_DYNAMIC_BASE_ID; + + for(unsigned i=0;i=id) { + id=catch_events[id].id()+1; + } + } + return id; +} + + +void MainObject::RunRmlRecordingCache(int chan) +{ + if(catch_record_pending_cartnum[chan-1]==0) { + return; + } + StartRmlRecording(chan,catch_record_pending_cartnum[chan-1], + catch_record_pending_cutnum[chan-1], + catch_record_pending_maxlen[chan-1]); + catch_record_pending_cartnum[chan-1]=0; +} + + +void MainObject::StartRmlRecording(int chan,int cartnum,int cutnum,int maxlen) +{ + RDDeck *deck=new RDDeck(catch_config->stationName(),chan); + RDCut *cut=new RDCut(cartnum,cutnum); + QDateTime dt=QDateTime(QDate::currentDate(),QTime::currentTime()); + catch_events.push_back(CatchEvent()); + catch_events.back().setId(GetNextDynamicId()); + catch_events.back().setIsActive(true); + catch_events.back().setOneShot(true); + catch_events.back().setType(RDRecording::Recording); + catch_events.back().setChannel(chan); + catch_events.back().setCutName(cut->cutName()); + catch_events.back().setDayOfWeek(dt.date().dayOfWeek(),true); + catch_events.back().setStartTime(dt.time()); + catch_events.back().setEndType(RDRecording::LengthEnd); + catch_events.back().setLength(maxlen); + catch_events.back(). + setFormat((RDCae::AudioCoding)deck->defaultFormat()); + catch_events.back().setChannels(deck->defaultChannels()); + catch_events.back().setSampleRate(catch_system->sampleRate()); + catch_events.back().setBitrate(deck->defaultBitrate()); + catch_events.back().setNormalizeLevel(0); + StartRecording(catch_events.size()-1); + delete cut; + delete deck; +} + + +void MainObject::StartBatch(int id) +{ + if((fork())==0) { + QString bin=QString(RD_PREFIX)+"/"+"bin/rdcatchd"; + execl(bin,(const char *)bin, + (const char *)QString().sprintf("--event-id=%d",id), + (char *)NULL); + LogLine(RDConfig::LogErr,QString(). + sprintf("failed to exec %s --event-id=%d: %s",(const char *)bin, + id,strerror(errno))); + exit(0); + } +} + + +QString MainObject::GetTempRecordingName(int id) const +{ + return QString().sprintf("%s/rdcatchd-record-%d.%s", + RDConfiguration()->audioRoot().ascii(),id, + RDConfiguration()->audioExtension().ascii()); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/rdcatchd/rdcatchd.h b/rdcatchd/rdcatchd.h new file mode 100644 index 00000000..c7992451 --- /dev/null +++ b/rdcatchd/rdcatchd.h @@ -0,0 +1,265 @@ +// rdcatchd.h +// +// The Rivendell Netcatcher. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rdcatchd.h,v 1.56 2010/09/16 19:52:08 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCATCHD_H +#define RDCATCHD_H + + +//#define RDCATCHD_TEMP_DIR "/tmp" +#define XLOAD_UPDATE_INTERVAL 1000 +#define RDCATCHD_USAGE "[-d][--event-id=]\n\nOptions:\n\n-d\n Set 'debug' mode, causing rdcatchd(8) to stay in the foreground\n and print debugging info on standard output.\n\n--event-id=\n Execute event and then exit.\n\n" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// Global RDCATCHD Definitions +// +#define RDCATCHD_MAX_CONNECTIONS 32 +#define RDCATCHD_MAX_ARGS 10 +#define RDCATCHD_MAX_LENGTH 256 +#define RDCATCHD_GPO_INTERVAL 333 +#define RDCATCHD_MAX_MACROS 64 +#define RDCATCHD_FREE_EVENTS_INTERVAL 1000 +#define RDCATCHD_HEARTBEAT_INTERVAL 10000 +#define RDCATCHD_ERROR_ID_OFFSET 1000000 +extern RDConfig *catch_config; + +// +// Function Prototypes +// +void LogLine(RDConfig::LogPriority prio,const QString &line); + + +class MainObject : public QObject +{ + Q_OBJECT + public: + MainObject(QObject *parent=0,const char *name=0); + + public slots: + void newConnection(int fd); + + private slots: + // + // rdcatchd.cpp + // + void rmlReceivedData(RDMacro *rml); + void gpiStateChangedData(int matrix,int line,bool state); + void startTimerData(int id); + void offsetTimerData(int id); + void engineData(int); + void socketData(int); + void socketKill(int); + void isConnectedData(bool state); + void recordLoadedData(int card,int stream); + void recordingData(int card,int stream); + void recordStoppedData(int card,int stream); + void recordUnloadedData(int card,int stream,unsigned msecs); + void playLoadedData(int handle); + void playingData(int handle); + void playStoppedData(int handle); + void playUnloadedData(int handle); + void meterData(); + void eventFinishedData(int id); + void freeEventsData(); + void heartbeatData(); + void sysHeartbeatData(); + void updateXloadsData(); + void startupCartData(); + void log(RDConfig::LogPriority prio,const QString &line); + + // + // batch.cpp + // + void catchConnectedData(int serial,bool state); + + private: + // + // batch.cpp + // + void RunBatch(RDCmdSwitch *cmd); + void RunImport(CatchEvent *evt); + void RunDownload(CatchEvent *evt); + void RunUpload(CatchEvent *evt); + CatchEvent *batch_event; + bool Export(CatchEvent *evt); + QString GetExportCmd(CatchEvent *evt,QString *tempname); + bool Import(CatchEvent *evt); + QString GetImportCmd(CatchEvent *evt,QString *tempname); + + // + // rdcatchd.cpp + // + bool StartRecording(int event); + void StartPlayout(int event); + void StartMacroEvent(int event); + void StartSwitchEvent(int event); + void StartDownloadEvent(int event); + void StartUploadEvent(int event); + bool ExecuteMacroCart(RDCart *cart,int id=-1,int event=-1); + void SendFullStatus(int ch); + void SendMeterLevel(int deck,short levels[2]); + void ParseCommand(int); + void DispatchCommand(int); + void KillSocket(int); + void EchoCommand(int,const char *); + void BroadcastCommand(const char *,int except_ch=-1); + void EchoArgs(int,const char); + void LoadEngine(bool adv_day=false); + QString LoadEventSql(); + void LoadEvent(RDSqlQuery *q,CatchEvent *e,bool add); + void LoadDeckList(); + int GetRecordDeck(int card,int stream); + int GetPlayoutDeck(int handle); + int GetFreeEvent(); + bool AddEvent(int id); + void RemoveEvent(int id); + bool UpdateEvent(int id); + int GetEvent(int id); + void PurgeEvent(int event); + void LoadHeartbeat(); + void CheckInRecording(QString cutname,CatchEvent *evt,unsigned msecs, + unsigned threshold); + void CheckInPodcast(CatchEvent *e) const; + RDRecording::ExitCode ReadExitCode(int event); + void WriteExitCode(int event,RDRecording::ExitCode code, + const QString &err_text=""); + void WriteExitCodeById(int id,RDRecording::ExitCode code, + const QString &err_text=""); + QString BuildTempName(int event,QString str); + QString BuildTempName(CatchEvent *evt,QString str); + QString GetFileExtension(QString filename); + bool SendErrorMessage(CatchEvent *event,const QString &err_desc,QString rml); + void ResolveErrorWildcards(CatchEvent *event,const QString &err_desc, + QString *rml); + void StartDropboxes(); + void RunLocalMacros(RDMacro *rml); + unsigned GetNextDynamicId(); + void RunRmlRecordingCache(int chan); + void StartRmlRecording(int chan,int cartnum,int cutnum,int maxlen); + void StartBatch(int id); + QString GetTempRecordingName(int id) const; + QSqlDatabase *catch_db; + RDSystem *catch_system; + RDStation *catch_rdstation; + RDRipc *catch_ripc; + QString catch_default_user; + QString catch_host; + bool debug; + RDTimeEngine *catch_engine; + RDCae *catch_cae; + Q_INT16 tcp_port; + QServerSocket *server; + RDCatchConnect *catch_connect; + RDSocket *socket[RDCATCHD_MAX_CONNECTIONS]; + char args[RDCATCHD_MAX_CONNECTIONS][RDCATCHD_MAX_ARGS][RDCATCHD_MAX_LENGTH]; + int istate[RDCATCHD_MAX_CONNECTIONS]; + int argnum[RDCATCHD_MAX_CONNECTIONS]; + int argptr[RDCATCHD_MAX_CONNECTIONS]; + bool auth[RDCATCHD_MAX_CONNECTIONS]; + bool catch_meter_enabled[RDCATCHD_MAX_CONNECTIONS]; + + bool catch_record_status[MAX_DECKS]; + int catch_record_card[MAX_DECKS]; + int catch_record_stream[MAX_DECKS]; + RDDeck::Status catch_record_deck_status[MAX_DECKS]; + int catch_record_id[MAX_DECKS]; + QString catch_record_name[MAX_DECKS]; + bool catch_record_aborting[MAX_DECKS]; + + unsigned catch_record_pending_cartnum[MAX_DECKS]; + unsigned catch_record_pending_cutnum[MAX_DECKS]; + unsigned catch_record_pending_maxlen[MAX_DECKS]; + + bool catch_playout_status[MAX_DECKS]; + int catch_playout_card[MAX_DECKS]; + int catch_playout_stream[MAX_DECKS]; + int catch_playout_port[MAX_DECKS]; + int catch_playout_handle[MAX_DECKS]; + RDDeck::Status catch_playout_deck_status[MAX_DECKS]; + int catch_playout_event_id[MAX_DECKS]; + int catch_playout_id[MAX_DECKS]; + QString catch_playout_name[MAX_DECKS]; + + int catch_monitor_port[MAX_DECKS]; + bool catch_monitor_state[MAX_DECKS]; + + unsigned catch_record_threshold[MAX_DECKS]; + QHostAddress catch_swaddress[MAX_DECKS]; + int catch_swmatrix[MAX_DECKS]; + int catch_swoutput[MAX_DECKS]; + int catch_swdelay[MAX_DECKS]; + QSignalMapper *catch_gpi_start_mapper; + QSignalMapper *catch_gpi_offset_mapper; + uid_t catch_uid; + gid_t catch_gid; + bool catch_event_free[RDCATCHD_MAX_MACROS]; + RDMacroEvent *catch_event_pool[RDCATCHD_MAX_MACROS]; + int catch_macro_event_id[RDCATCHD_MAX_MACROS]; + QSignalMapper *catch_event_mapper; + std::vector catch_events; + QTimer *catch_heartbeat_timer; + unsigned catch_heartbeat_cart; + + int catch_default_format; + int catch_default_samplerate; + int catch_default_channels; + int catch_default_layer; + int catch_default_bitrate; + int catch_ripper_level; + std::vector catch_active_xloads; + QTimer *catch_xload_timer; + QString catch_temp_dir; + RDCatchConf *catch_conf; +}; + + +#endif diff --git a/rdcatchd/rdcatchd_socket.cpp b/rdcatchd/rdcatchd_socket.cpp new file mode 100644 index 00000000..e6675375 --- /dev/null +++ b/rdcatchd/rdcatchd_socket.cpp @@ -0,0 +1,52 @@ +// rdcatchd_socket.cpp +// +// An automated event executer. +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: rdcatchd_socket.cpp,v 1.7 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +RDCatchdSocket::RDCatchdSocket(Q_UINT16 port,int backlog,QObject *parent, + const char *name) + : QServerSocket(port,0,parent,name) +{ +} + + +RDCatchdSocket::RDCatchdSocket(const QHostAddress &address,Q_UINT16 port,int backlog, + QObject *parent,const char *name) + : QServerSocket(address,port,0,parent,name) +{ +} + + +void RDCatchdSocket::newConnection(int fd) +{ + emit connection(fd); +} diff --git a/rdcatchd/rdcatchd_socket.h b/rdcatchd/rdcatchd_socket.h new file mode 100644 index 00000000..61233b6f --- /dev/null +++ b/rdcatchd/rdcatchd_socket.h @@ -0,0 +1,50 @@ +// rdcatchd_socket.h +// +// A telephone services server for Mithlond +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: rdcatchd_socket.h,v 1.6 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDCATCHD_SOCKET_H +#define RDCATCHD_SOCKET_H + +#include +#include +#include +#include + + +class RDCatchdSocket : public QServerSocket +{ + Q_OBJECT + public: + RDCatchdSocket(Q_UINT16 port,int backlog=0,QObject *parent=0, + const char *name=0); + RDCatchdSocket(const QHostAddress &address,Q_UINT16 port,int backlog=0, + QObject *parent=0,const char *name=0); + void newConnection(int socket); + + signals: + void connection(int); + + private: + QServerSocket *socket; +}; + + +#endif diff --git a/rdhpi/Makefile.am b/rdhpi/Makefile.am new file mode 100644 index 00000000..8a38e5f5 --- /dev/null +++ b/rdhpi/Makefile.am @@ -0,0 +1,95 @@ +## automake.am +## +## Automake.am for rivendell/mlhpi +## +## by Fred Gleason +## +## Use automake to process this into a Makefile.in +## +## (C) Copyright 2002-2007 Fred Gleason +## +## $Id: Makefile.am,v 1.7.8.3 2013/01/01 21:36:30 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ +CWRAP = ../helpers/cwrap + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# The cwrap dependency +html_%.cpp: %.html + $(CWRAP) -o $@ $< + +instdir = @LOCAL_PREFIX@/lib + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdhpi_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rdhpi_*.qm + +all: + @QT_BIN@/lupdate rdhpi.pro + @QT_BIN@/lrelease rdhpi.pro + +lib_LTLIBRARIES = librdhpi.la +dist_librdhpi_la_SOURCES = rdhpicardselector.cpp rdhpicardselector.h\ + rdhpiinformation.cpp rdhpiinformation.h\ + rdhpiplaystream.cpp rdhpiplaystream.h\ + rdhpirecordstream.cpp rdhpirecordstream.h\ + rdhpisoundcard.cpp rdhpisoundcard.h\ + rdhpisoundselector.cpp rdhpisoundselector.h + +nodist_librdhpi_la_SOURCES = moc_rdhpicardselector.cpp\ + moc_rdhpiplaystream.cpp\ + moc_rdhpirecordstream.cpp\ + moc_rdhpisoundcard.cpp\ + moc_rdhpisoundselector.cpp + + +librdhpi_la_LDFLAGS = -release $(VERSION) + +EXTRA_DIST = rdhpi.pro\ + rdhpi_cs.ts\ + rdhpi_de.ts\ + rdhpi_es.ts\ + rdhpi_fr.ts\ + rdhpi_nb.ts\ + rdhpi_nn.ts\ + rdhpi_pt_BR.ts + +CLEANFILES = *~\ + *.idb\ + *.ilk\ + *.lib\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +DISTCLEAN = Makefile + +MAINTAINERCLEANFILES = *~\ + Makefile\ + Makefile.in\ + moc_* diff --git a/rdhpi/rdhpi.pro b/rdhpi/rdhpi.pro new file mode 100644 index 00000000..da3ec4a4 --- /dev/null +++ b/rdhpi/rdhpi.pro @@ -0,0 +1,59 @@ +# rdhpi.pro +# +# The rdhpi/ QMake project file for Rivendell. +# +# (C) Copyright 2003-2007 Fred Gleason +# +# $Id: rdhpi.pro,v 1.4.8.1 2013/01/01 21:36:31 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = lib + +win32 { + DEFINES += WIN32 + DEFINES += VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE=\"rivendell\" + DEFINES += PACKAGE_VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE_NAME=\"rivendell\" + DEFINES += PACKAGE_BUGREPORT=\"fredg@paravelsystems.com\" +} + +x11 { + SOURCES += rdhpicardselector.cpp + SOURCES += rdhpiinformation.cpp + SOURCES += rdhpiplaystream.cpp + SOURCES += rdhpirecordstream.cpp + SOURCES += rdhpisoundcard.cpp + SOURCES += rdhpisoundselector.cpp +} + +x11 { + HEADERS += rdhpicardselector.h + HEADERS += rdhpiinformation.h + HEADERS += rdhpiplaystream.h + HEADERS += rdhpirecordstream.h + HEADERS += rdhpisoundcard.h + HEADERS += rdhpisoundselector.h +} + +CONFIG += qt staticlib + +TRANSLATIONS += rdhpi_cs.ts +TRANSLATIONS += rdhpi_de.ts +TRANSLATIONS += rdhpi_es.ts +TRANSLATIONS += rdhpi_fr.ts +TRANSLATIONS += rdhpi_nb.ts +TRANSLATIONS += rdhpi_nn.ts +TRANSLATIONS += rdhpi_pt_BR.ts diff --git a/rdhpi/rdhpi_cs.ts b/rdhpi/rdhpi_cs.ts new file mode 100644 index 00000000..6efaa214 --- /dev/null +++ b/rdhpi/rdhpi_cs.ts @@ -0,0 +1,67 @@ + + + RDHPIPlayStream + + Ok + OK + + + No such file or directory + Nepodařilo se najít žádný takový soubor nebo adresář + + + No output stream available + Není dostupný žádný výstupní proud + + + Stream is already open + Proud je již otevřen + + + Unknown Error: + Neznámá chyba: + + + + RDHPIRecordStream + + Ok + OK + + + Unable to create/open file + Soubor nelze vytvořit/otevřít + + + Input stream unavailable + Vstupní proud je nedostupný + + + Stream is already open + Proud je již otevřen + + + Unknown Error: + Neznámá chyba: + + + + RDHPISoundCard + + Input Stream + Vstupní proud + + + Output Stream + Výstupní proud + + + Input Port + Vstupní přípojka + + + Output Port + Výstupní přípojka + + + diff --git a/rdhpi/rdhpi_de.ts b/rdhpi/rdhpi_de.ts new file mode 100644 index 00000000..78cd96b9 --- /dev/null +++ b/rdhpi/rdhpi_de.ts @@ -0,0 +1,67 @@ + + + RDHPIPlayStream + + Ok + OK + + + No such file or directory + Keine solche Datei oder Verzeichnis + + + No output stream available + Kein Outputstream verfügbar + + + Stream is already open + Stream ist schon geöffnet + + + Unknown Error: + Unbekannter Fehler: + + + + RDHPIRecordStream + + Ok + OK + + + Unable to create/open file + Kann die Datei nicht erstellen/öffnen + + + Input stream unavailable + Eingangsstream nicht verfügbar + + + Stream is already open + Stream ist schon geöffnet + + + Unknown Error: + Unbekannter Fehler: + + + + RDHPISoundCard + + Input Stream + Eingansstream + + + Output Stream + Ausgangsstream + + + Input Port + Eingangsport + + + Output Port + Ausgangsport + + + diff --git a/rdhpi/rdhpi_es.ts b/rdhpi/rdhpi_es.ts new file mode 100644 index 00000000..06927ae4 --- /dev/null +++ b/rdhpi/rdhpi_es.ts @@ -0,0 +1,67 @@ + + + RDHPIPlayStream + + Ok + + + + No such file or directory + + + + No output stream available + + + + Stream is already open + + + + Unknown Error: + + + + + RDHPIRecordStream + + Ok + + + + Unable to create/open file + + + + Input stream unavailable + + + + Stream is already open + + + + Unknown Error: + + + + + RDHPISoundCard + + Input Stream + + + + Output Stream + + + + Input Port + + + + Output Port + + + + diff --git a/rdhpi/rdhpi_fr.ts b/rdhpi/rdhpi_fr.ts new file mode 100644 index 00000000..06927ae4 --- /dev/null +++ b/rdhpi/rdhpi_fr.ts @@ -0,0 +1,67 @@ + + + RDHPIPlayStream + + Ok + + + + No such file or directory + + + + No output stream available + + + + Stream is already open + + + + Unknown Error: + + + + + RDHPIRecordStream + + Ok + + + + Unable to create/open file + + + + Input stream unavailable + + + + Stream is already open + + + + Unknown Error: + + + + + RDHPISoundCard + + Input Stream + + + + Output Stream + + + + Input Port + + + + Output Port + + + + diff --git a/rdhpi/rdhpi_nb.ts b/rdhpi/rdhpi_nb.ts new file mode 100644 index 00000000..34ad9266 --- /dev/null +++ b/rdhpi/rdhpi_nb.ts @@ -0,0 +1,67 @@ + + + RDHPIPlayStream + + Ok + Ok + + + No such file or directory + Inga slik fil eller mappe + + + No output stream available + Ingen tilgjengeleg utstraum + + + Stream is already open + Straumen er alt open + + + Unknown Error: + Ukjend feil: + + + + RDHPIRecordStream + + Ok + Ok + + + Unable to create/open file + Greier ikkje opna/laga fila + + + Input stream unavailable + Innstraumen er ikkje tilgjengeleg + + + Stream is already open + Straumen er alt open + + + Unknown Error: + Ukjend feil: + + + + RDHPISoundCard + + Input Stream + Innstraum + + + Output Stream + Utstraum + + + Input Port + Innport + + + Output Port + Utport + + + diff --git a/rdhpi/rdhpi_nn.ts b/rdhpi/rdhpi_nn.ts new file mode 100644 index 00000000..34ad9266 --- /dev/null +++ b/rdhpi/rdhpi_nn.ts @@ -0,0 +1,67 @@ + + + RDHPIPlayStream + + Ok + Ok + + + No such file or directory + Inga slik fil eller mappe + + + No output stream available + Ingen tilgjengeleg utstraum + + + Stream is already open + Straumen er alt open + + + Unknown Error: + Ukjend feil: + + + + RDHPIRecordStream + + Ok + Ok + + + Unable to create/open file + Greier ikkje opna/laga fila + + + Input stream unavailable + Innstraumen er ikkje tilgjengeleg + + + Stream is already open + Straumen er alt open + + + Unknown Error: + Ukjend feil: + + + + RDHPISoundCard + + Input Stream + Innstraum + + + Output Stream + Utstraum + + + Input Port + Innport + + + Output Port + Utport + + + diff --git a/rdhpi/rdhpi_pt_BR.ts b/rdhpi/rdhpi_pt_BR.ts new file mode 100644 index 00000000..24cac993 --- /dev/null +++ b/rdhpi/rdhpi_pt_BR.ts @@ -0,0 +1,67 @@ + + + RDHPIPlayStream + + Ok + Ok + + + No such file or directory + Este arquivo ou diretório não existe + + + No output stream available + Não há saída de fluxo disponível + + + Stream is already open + Fluxo já está aberto + + + Unknown Error: + Erro Desconhecido: + + + + RDHPIRecordStream + + Ok + Ok + + + Unable to create/open file + Não foi possível criar/abrir arquivo + + + Input stream unavailable + Não há entrada de fluxo disponível + + + Stream is already open + Fluxo já está aberto + + + Unknown Error: + Erro Desconhecido: + + + + RDHPISoundCard + + Input Stream + Entrada de fluxo + + + Output Stream + Saída de fluxo + + + Input Port + Porta de Entrada + + + Output Port + Porta de Saída + + + diff --git a/rdhpi/rdhpicardselector.cpp b/rdhpi/rdhpicardselector.cpp new file mode 100644 index 00000000..dfed07d1 --- /dev/null +++ b/rdhpi/rdhpicardselector.cpp @@ -0,0 +1,176 @@ +// rdhpicardselector.cpp +// +// Audio card selector widget for Rivendell +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdhpicardselector.cpp,v 1.3 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +RDHPICardSelector::RDHPICardSelector(QWidget *parent,const char *name) + : QWidget(parent,name) +{ + QFont font; + + yoffset=0; + + // + // Generate Font + // + font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Title + // + card_title=new QLabel(this,"card_title"); + card_title->setGeometry(0,0,geometry().width(),19); + card_title->setFont(font); + card_title->setAlignment(AlignHCenter); + card_title->hide(); + + // + // Card + // + card_card_box=new QSpinBox(this,"card_card_box"); + card_card_box->setGeometry(60,yoffset,50,19); + card_card_box->setSpecialValueText("None"); + card_card_box->setMinValue(-1); + card_card_box->setMaxValue(HPI_MAX_ADAPTERS-1); + card_card_box->setValue(-1); + connect(card_card_box,SIGNAL(valueChanged(int)),this,SLOT(cardData(int))); + card_card_label=new QLabel(card_card_box,"Card:",this, + "card_card_label"); + card_card_label->setGeometry(0,yoffset+2,55,19); + card_card_label->setAlignment(AlignRight|ShowPrefix); + + // + // Port + // + card_port_box=new QSpinBox(this,"card_port_box"); + card_port_box->setGeometry(60,yoffset+22,50,19); + card_port_box->setMinValue(0); + card_port_box->setMaxValue(HPI_MAX_NODES-1); + card_port_box->setDisabled(true); + connect(card_port_box,SIGNAL(valueChanged(int)),this,SLOT(portData(int))); + card_port_label=new QLabel(card_port_box,"Port:",this, + "card_port_label"); + card_port_label->setGeometry(0,yoffset+24,55,19); + card_port_label->setAlignment(AlignRight|ShowPrefix); +} + + +RDHPICardSelector::~RDHPICardSelector() +{ + delete card_title; + delete card_card_box; + delete card_port_box; +} + + +QSize RDHPICardSelector::sizeHint() const +{ + return QSize(110,43+yoffset); +} + + +QSizePolicy RDHPICardSelector::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +QString RDHPICardSelector::title() const +{ + return card_title->text(); +} + + +void RDHPICardSelector::setTitle(QString title) +{ + card_title->setText(title); + if(title.isEmpty()) { + yoffset=0; + card_title->hide(); + } + else { + yoffset=22; + card_title->show(); + } + card_card_box->setGeometry(60,yoffset,50,19); + card_card_label->setGeometry(0,yoffset+2,55,19); + card_port_box->setGeometry(60,yoffset+22,50,19); + card_port_label->setGeometry(0,yoffset+24,55,19); +} + + +int RDHPICardSelector::card() const +{ + return card_card_box->value(); +} + + +void RDHPICardSelector::setCard(int card) +{ + card_card_box->setValue(card); +} + + +int RDHPICardSelector::port() const +{ + return card_port_box->value(); +} + + +void RDHPICardSelector::setPort(int port) +{ + card_port_box->setValue(port); +} + + +void RDHPICardSelector::cardData(int card) +{ + if(card>=0) { + card_port_box->setEnabled(true); + } + else { + card_port_box->setDisabled(true); + } + emit cardChanged(card); +} + + +void RDHPICardSelector::portData(int port) +{ + emit portChanged(port); +} + diff --git a/rdhpi/rdhpicardselector.h b/rdhpi/rdhpicardselector.h new file mode 100644 index 00000000..cedc697c --- /dev/null +++ b/rdhpi/rdhpicardselector.h @@ -0,0 +1,64 @@ +// rdhpicardselector.h +// +// Audio Card Selector Widget +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdhpicardselector.h,v 1.3 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDHPICARDSELECTOR_H +#define RDHPICARDSELECTOR_H + +#include +#include +#include + + +class RDHPICardSelector : public QWidget +{ + Q_OBJECT + public: + RDHPICardSelector(QWidget *parent=0,const char *name=0); + ~RDHPICardSelector(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + QString title() const; + void setTitle(QString title); + int card() const; + void setCard(int card); + int port() const; + void setPort(int port); + + signals: + void cardChanged(int card); + void portChanged(int port); + + private slots: + void cardData(int); + void portData(int); + + private: + QLabel *card_card_label; + QSpinBox *card_card_box; + QLabel *card_port_label; + QSpinBox *card_port_box; + QLabel *card_title; + int yoffset; +}; + + +#endif // RDHPICARDSELECTOR_H diff --git a/rdhpi/rdhpiinformation.cpp b/rdhpi/rdhpiinformation.cpp new file mode 100644 index 00000000..43219e9d --- /dev/null +++ b/rdhpi/rdhpiinformation.cpp @@ -0,0 +1,130 @@ +// rdhpiinformation.cpp +// +// A Container Class for AudioScience HPI Adapter Info +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdhpiinformation.cpp,v 1.4 2011/05/18 15:25:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + + +RDHPIInformation::RDHPIInformation() +{ + clear(); +} + + +unsigned RDHPIInformation::serialNumber() const +{ + return serial_number; +} + + +void RDHPIInformation::setSerialNumber(unsigned num) +{ + serial_number=num; +} + + +unsigned RDHPIInformation::hpiMajorVersion() const +{ + return (hpi_version>>16)&0xffff; +} + + +unsigned RDHPIInformation::hpiMinorVersion() const +{ + return (hpi_version>>8)&0xff; +} + + +unsigned RDHPIInformation::hpiPointVersion() const +{ + return hpi_version&0xff; +} + + +uint32_t RDHPIInformation::hpiVersion() const +{ + return hpi_version; +} + + +void RDHPIInformation::setHpiVersion(uint32_t ver) +{ + hpi_version=ver; +} + + +unsigned RDHPIInformation::dspMajorVersion() const +{ + return dsp_major_version; +} + + +void RDHPIInformation::setDspMajorVersion(unsigned ver) +{ + dsp_major_version=ver; +} + + +unsigned RDHPIInformation::dspMinorVersion() const +{ + return dsp_minor_version; +} + + +void RDHPIInformation::setDspMinorVersion(unsigned ver) +{ + dsp_minor_version=ver; +} + + +char RDHPIInformation::pcbVersion() const +{ + return pcb_version; +} + + +void RDHPIInformation::setPcbVersion(char ver) +{ + pcb_version=ver; +} + + +unsigned RDHPIInformation::assemblyVersion() const +{ + return assembly_version; +} + + +void RDHPIInformation::setAssemblyVersion(unsigned ver) +{ + assembly_version=ver; +} + + +void RDHPIInformation::clear() +{ + serial_number=0; + hpi_version=0; + dsp_major_version=0; + dsp_minor_version=0; + pcb_version='0'; + assembly_version=0; +} diff --git a/rdhpi/rdhpiinformation.h b/rdhpi/rdhpiinformation.h new file mode 100644 index 00000000..4a78bdca --- /dev/null +++ b/rdhpi/rdhpiinformation.h @@ -0,0 +1,63 @@ +// rdhpiinformation.h +// +// A Container Class for AudioScience HPI Adapter Info +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdhpiinformation.h,v 1.2 2011/05/18 15:25:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDHPIINFORMATION_H +#define RDHPIINFORMATION_H + +#include + +class RDHPIInformation +{ + public: + RDHPIInformation(); + unsigned serialNumber() const; + void setSerialNumber(unsigned num); + unsigned hpiMajorVersion() const; + void setHpiMajorVersion(unsigned ver); + unsigned hpiMinorVersion() const; + void setHpiMinorVersion(unsigned ver); + unsigned hpiPointVersion() const; + void setHpiPointVersion(unsigned ver); + uint32_t hpiVersion() const; + void setHpiVersion(uint32_t ver); + unsigned dspMajorVersion() const; + void setDspMajorVersion(unsigned ver); + unsigned dspMinorVersion() const; + void setDspMinorVersion(unsigned ver); + char pcbVersion() const; + void setPcbVersion(char ver); + unsigned assemblyVersion() const; + void setAssemblyVersion(unsigned ver); + void clear(); + + private: + unsigned serial_number; + unsigned dsp_major_version; + uint32_t hpi_version; + unsigned dsp_minor_version; + char pcb_version; + unsigned assembly_version; +}; + + +#endif // RDHPIINFORMATION_H + diff --git a/rdhpi/rdhpiplaystream.cpp b/rdhpi/rdhpiplaystream.cpp new file mode 100644 index 00000000..7b2d416b --- /dev/null +++ b/rdhpi/rdhpiplaystream.cpp @@ -0,0 +1,798 @@ +// rdhpiplaystream.cpp +// +// A class for playing Microsoft WAV files. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdhpiplaystream.cpp,v 1.8.6.1 2012/05/04 14:56:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define RDHPIPLAYSTREAM_USE_LOCAL_MUTEX + +#ifdef RDHPIPLAYSTREAM_USE_LOCAL_MUTEX +volatile static int stream_mutex[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]= + {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; +#endif + + +RDHPIPlayStream::RDHPIPlayStream(RDHPISoundCard *card, + QWidget *parent,const char *name) + :QObject(parent,name),RDWaveFile() +{ + hpi_err_t hpi_err; + int quan; + uint16_t type[HPI_MAX_ADAPTERS]; + + sound_card=card; + card_number=-1; + stream_number=-1; + is_open=false; + playing=false; + is_paused=false; + repositioned=false; + stopping=false; + samples_skipped=0; + play_length=0; + play_speed=1000; + pitch_can_vary=false; + rate_can_vary=false; + stream_state=RDHPIPlayStream::Stopped; + pdata=NULL; + restart_transport=false; + samples_pending=0; + current_position=0; + + // + // Get Adapter Indices + // +#if HPI_VER < 0x00030600 + for(unsigned i=0;igetCardOutputStreams(card_number);i++) { + if((hpi_error=HPI_OutStreamOpen(NULL,card_index[card_number],i, + &hostream))==0) { + found=true; + break; + } + } + if(!found) { + return false; + } + } + else { + hostream=hpi_stream; + } + switch(format) { + case RDWaveFile::Pcm16: + hpi_error=HPI_FormatCreate(&hpi_format,getChannels(), + HPI_FORMAT_PCM16_SIGNED, + getSamplesPerSec(),getHeadBitRate(),0); + state=HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format); + break; + + case RDWaveFile::MpegL1: + hpi_error=HPI_FormatCreate(&hpi_format,getChannels(), + HPI_FORMAT_MPEG_L1, + getSamplesPerSec(),getHeadBitRate(),0); + state=HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format); + break; + + case RDWaveFile::MpegL2: + hpi_error=HPI_FormatCreate(&hpi_format,getChannels(), + HPI_FORMAT_MPEG_L2, + getSamplesPerSec(),getHeadBitRate(),0); + state=HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format); + break;; + + case RDWaveFile::MpegL3: + hpi_error=HPI_FormatCreate(&hpi_format,getChannels(), + HPI_FORMAT_MPEG_L3, + getSamplesPerSec(),getHeadBitRate(),0); + state=HPI_OutStreamQueryFormat(NULL,hostream,&hpi_format); + break; + + default: + state=1; + break; + } + if(!is_open) { + hpi_error=HPI_OutStreamClose(NULL,hostream); + } + if(state!=0) { + return false; + } + return true; +} + + +bool RDHPIPlayStream::formatSupported() +{ + switch(getFormatTag()) { + case WAVE_FORMAT_PCM: + switch(getBitsPerSample()) { + case 8: + return formatSupported(RDWaveFile::Pcm8); + break; + + case 16: + return formatSupported(RDWaveFile::Pcm16); + break; + + default: + return false; + } + break; + + case WAVE_FORMAT_MPEG: + switch(getHeadLayer()) { + case 1: + return formatSupported(RDWaveFile::MpegL1); + break; + + case 2: + return formatSupported(RDWaveFile::MpegL2); + break; + + case 3: + return formatSupported(RDWaveFile::MpegL3); + break; + + default: + return false; + } + break; + + default: + return false; + } +} + + +RDHPIPlayStream::Error RDHPIPlayStream::openWave() +{ + if(is_open) { + return RDHPIPlayStream::AlreadyOpen; + } + nameWave(wave_name); + samples_skipped=0; + samples_pending=0; + if(!RDWaveFile::openWave()) { + return RDHPIPlayStream::NoFile; + } + if(GetStream()<0) { + RDWaveFile::closeWave(); + return RDHPIPlayStream::NoStream; + } + is_open=true; + return RDHPIPlayStream::Ok; +} + + +RDHPIPlayStream::Error RDHPIPlayStream::openWave(QString file_name) +{ + if(is_open) { + return RDHPIPlayStream::AlreadyOpen; + } + wave_name=file_name; + return openWave(); +} + + + +void RDHPIPlayStream::closeWave() +{ + if(!is_open) { + return; + } + if(playing||is_paused) { + stop(); + } + FreeStream(); + RDWaveFile::closeWave(); + is_open=false; +} + + +int RDHPIPlayStream::getCard() const +{ + return card_number; +} + + +void RDHPIPlayStream::setCard(int card) +{ + if(!playing) { + card_number=card; + } +} + + +int RDHPIPlayStream::getStream() const +{ + return stream_number; +} + + +int RDHPIPlayStream::getSpeed() const +{ + return play_speed; +} + + +bool RDHPIPlayStream::setSpeed(int speed,bool pitch,bool rate) +{ + if(speed!=RD_TIMESCALE_DIVISOR) { + if(!pitch) { + if(!sound_card->haveTimescaling(card_number)) { + return false; + } + if((speedTIMESCALE_HIGH_LIMIT)) { + return false; + } + } + else { + if(!rate) { // Variable speed with resampling not yet supported! + return false; + } + if((speed<96000)||(speed>104000)) { // Max variation +/- 4% + return false; + } + } + } + play_speed=speed; + pitch_can_vary=pitch; + rate_can_vary=rate; + return true; +} + + +RDHPIPlayStream::State RDHPIPlayStream::getState() const +{ + return stream_state; +} + + +bool RDHPIPlayStream::play() +{ +#ifdef RPLAYSTREAM_SHOW_SLOTS + printf("play() -- Card: %d Stream: %d\n",card_number,stream_number); +#endif // RPLAYSTREAM_SHOW_SLOTS + hpi_err_t hpi_error; + syslog(LOG_ERR,"Play - 1\n"); + if(!is_open) { + return false; + } + if((!playing)&&(!is_paused)) { + hpi_error=HPI_OutStreamSetTimeScale(NULL,hpi_stream, + (uint16_t)((RD_TIMESCALE_DIVISOR/(double)play_speed)* + HPI_OSTREAM_TIMESCALE_UNITS)); + if(HPI_OutStreamGetInfoEx(NULL,hpi_stream, + &state,&buffer_size,&data_to_play, + &samples_played,&reserved)!=0) { + return false; + } + fragment_size=buffer_size/4; + if(fragment_size>MAX_FRAGMENT_SIZE) { + fragment_size=MAX_FRAGMENT_SIZE; + } + if(pdata!=NULL) { + delete pdata; + } + pdata=(uint8_t *)malloc(fragment_size); + if(pdata==NULL) { + return false; + } + switch(getFormatTag()) { + case WAVE_FORMAT_PCM: + case WAVE_FORMAT_VORBIS: + switch(getBitsPerSample()) { + case 8: + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_PCM8_UNSIGNED,getSamplesPerSec(), + 0,0); + break; + case 16: + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_PCM16_SIGNED,getSamplesPerSec(), + 0,0); + break; + case 32: + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_PCM32_SIGNED,getSamplesPerSec(), + 0,0); + break; + default: + hpi_error=HPI_AdapterClose(NULL,card_index[card_number]); + return false; + break; + } + break; + case WAVE_FORMAT_MPEG: + switch(getHeadLayer()) { + case 1: + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_MPEG_L1,getSamplesPerSec(), + getHeadBitRate(),getHeadFlags()); + break; + case 2: + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_MPEG_L2,getSamplesPerSec(), + getHeadBitRate(),getHeadFlags()); + break; + case 3: + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_MPEG_L3,getSamplesPerSec(), + getHeadBitRate(),getHeadFlags()); + break; + default: + hpi_error=HPI_AdapterClose(NULL,card_index[card_number]); + return false; + } + break; + default: + return false; + } +#if HPI_VER < 0x00030500 + if(HPI_DataCreate(&hpi_data,&format,pdata,fragment_size)!=0) { + return false; + } +#endif + } + if(!is_paused) { + memset(pdata,0,fragment_size); + left_to_write=getDataLength()-seekWave(0,SEEK_CUR); + if(left_to_write 0x00030500 + hpi_error= + HPI_OutStreamWriteBuf(NULL,hpi_stream,pdata,read_bytes,&format); +#else + hpi_error=HPI_DataCreate(&hpi_data,&format,pdata,read_bytes); + hpi_error=HPI_OutStreamWrite(NULL,hpi_stream,&hpi_data); +#endif + if(HPI_OutStreamStart(NULL,hpi_stream)!=0) { + return false; + } + clock->start(50); + clock->start(FRAGMENT_TIME); + playing=true; + is_paused=false; + stopping=false; + if(play_length>0) { + play_timer->start(play_length,true); + start_time=QTime::currentTime(); + } + stream_state=RDHPIPlayStream::Playing; + if(!restart_transport) { + emit isStopped(false); + emit played(); + emit stateChanged(card_number,stream_number,(int)stream_state); + } + } + if((!playing)&(is_paused|repositioned)) { + hpi_error=HPI_OutStreamStart(NULL,hpi_stream); + clock->start(FRAGMENT_TIME); + playing=true; + stopping=false; + is_paused=false; + stream_state=RDHPIPlayStream::Playing; + if(!restart_transport) { + emit isStopped(false); + emit played(); + emit stateChanged(card_number,stream_number,(int)stream_state); + } + } + return true; +} + + +void RDHPIPlayStream::pause() +{ +#ifdef RPLAYSTREAM_SHOW_SLOTS + printf("pause() -- Card: %d Stream: %d\n",card_number,stream_number); +#endif // RPLAYSTREAM_SHOW_SLOTS + hpi_err_t hpi_error; + uint16_t state; + uint32_t buffer_size; + uint32_t data_to_play; + uint32_t reserved; + + if(!is_open) { + return; + } + if(playing) { + hpi_error=HPI_OutStreamStop(NULL,hpi_stream); + clock->stop(); + hpi_error=HPI_OutStreamGetInfoEx(NULL,hpi_stream,&state,&buffer_size, + &data_to_play,&samples_played,&reserved); + switch(getFormatTag()) { + case WAVE_FORMAT_PCM: + samples_pending=data_to_play/(getChannels()*getBitsPerSample()/8); + break; + + case WAVE_FORMAT_MPEG: + samples_pending= + 1152*data_to_play/(144*getHeadBitRate()/getSamplesPerSec()); + break; + } + playing=false; + is_paused=true; + stream_state=RDHPIPlayStream::Paused; + if(!restart_transport) { + emit paused(); + emit stateChanged(card_number,stream_number,(int)stream_state); + } + } +} + + + +void RDHPIPlayStream::stop() +{ +#ifdef RPLAYSTREAM_SHOW_SLOTS + + printf("stop() -- Card: %d Stream: %d\n",card_number,stream_number); +#endif // RPLAYSTREAM_SHOW_SLOTS + hpi_err_t hpi_error; + + if(!is_open) { + return; + } + if(playing|is_paused) { + hpi_error=HPI_OutStreamStop(NULL,hpi_stream); + clock->stop(); + playing=false; + is_paused=false; + seekWave(0,SEEK_SET); + hpi_error=HPI_OutStreamReset(NULL,hpi_stream); + samples_pending=0; + samples_skipped=0; + stream_state=RDHPIPlayStream::Stopped; + current_position=0; + if(pdata!=NULL) { + delete pdata; + pdata=NULL; + } + if(!restart_transport) { + emit position(0); + emit isStopped(true); + emit stopped(); + emit stateChanged(card_number,stream_number,0); + } + } +} + + +int RDHPIPlayStream::currentPosition() +{ + if(current_position!=samples_played+samples_skipped) { + current_position=samples_played+samples_skipped; + } + return samples_played+samples_skipped; +} + + +bool RDHPIPlayStream::setPosition(unsigned samples) +{ + hpi_err_t hpi_error; + +#ifdef RPLAYSTREAM_SHOW_SLOTS + printf("setPosition(%d) -- Card: %d Stream: %d\n",samples, + card_number,stream_number); +#endif // RPLAYSTREAM_SHOW_SLOTS + if((samples<0)||(samples>getSampleLength())) { + return false; + } + if(playing&&((unsigned)samples!=(samples_skipped+samples_played))) { + restart_transport=true; + pause(); + } + + if(!playing) { + if(is_paused) { + is_paused=false; + repositioned=true; + } + hpi_error=HPI_OutStreamReset(NULL,hpi_stream); + samples_played=0; + switch(getFormatTag()) { + case WAVE_FORMAT_PCM: + case WAVE_FORMAT_VORBIS: + samples_skipped= + (unsigned)((double)getBlockAlign()* + ((double)samples/(double)getBlockAlign())); + seekWave((int)((double)samples_skipped*(double)getBlockAlign()), + SEEK_SET); + break; + case WAVE_FORMAT_MPEG: + samples_skipped= + (unsigned)((double)getBlockAlign()* + ((double)samples/(double)getBlockAlign())); + seekWave((int)((double)(getAvgBytesPerSec())* + ((double)(samples_skipped)/ + ((double)getSamplesPerSec()))), + SEEK_SET); + break; + } + emit position(samples); + } + if(restart_transport) { + play(); + restart_transport=false; + } + return true; +} + + +void RDHPIPlayStream::setPlayLength(int length) +{ + int diff; + + if(play_timer->isActive()) { + QTime current_time=QTime::currentTime(); + if((diff=length-start_time.msecsTo(current_time))<=0) { + diff=0; + } + play_timer->changeInterval(diff); + start_time=current_time; + } + play_length=length; +} + + +void RDHPIPlayStream::tickClock() +{ + static int count=0; + hpi_err_t hpi_err; + char hpi_text[100]; + int n; + + hpi_err=HPI_OutStreamGetInfoEx(NULL,hpi_stream, + &state,&buffer_size,&data_to_play, + &samples_played,&reserved); + if(!stopping) { + while((buffer_size-data_to_play)>=fragment_size) { + n=readWave(pdata,fragment_size); + if((n<=0)||(((uint32_t)n) 0x00030500 + if((hpi_err=HPI_OutStreamWriteBuf(NULL,hpi_stream, + pdata,n,&format))!=0) { + HPI_GetErrorText(hpi_err,hpi_text); + fprintf(stderr,"*** HPI Error: %s ***\n",hpi_text); + } +#else + HPI_DataCreate(&hpi_data,&format,pdata,n); + if((hpi_err=HPI_OutStreamWrite(NULL,hpi_stream, + &hpi_data))!=0) { + HPI_GetErrorText(hpi_err,hpi_text); + fprintf(stderr,"*** HPI Error: %s ***\n",hpi_text); + } +#endif + left_to_write=0; + stopping=true; + return; + } + left_to_write-=n; +#if HPI_VER > 0x00030500 + hpi_err=HPI_OutStreamWriteBuf(NULL,hpi_stream, + pdata,n,&format); +#else + hpi_err=HPI_DataCreate(&hpi_data,&format,pdata,n); + hpi_err=HPI_OutStreamWrite(NULL,hpi_stream,&hpi_data); +#endif + hpi_err=HPI_OutStreamGetInfoEx(NULL,hpi_stream, + &state,&buffer_size,&data_to_play, + &samples_played,&reserved); + } + } + else { + if(state==HPI_STATE_DRAINED) { + hpi_err=HPI_OutStreamStop(NULL,hpi_stream); + hpi_err=HPI_OutStreamClose(NULL,hpi_stream); + hpi_err=HPI_AdapterClose(NULL,card_index[card_number]); + clock->stop(); + playing=false; + seekWave(0,SEEK_SET); + hpi_err=HPI_OutStreamReset(NULL,hpi_stream); + samples_pending=0; + samples_skipped=0; + stream_state=RDHPIPlayStream::Stopped; + emit position(0); + emit isStopped(true); + emit stopped(); + emit stateChanged(card_number,stream_number,(int)stream_state); + return; + } + } + if(count++==2) { + count=0; + emit position(samples_played+samples_skipped); + } +} + + +void RDHPIPlayStream::Drained() +{ +} + + +int RDHPIPlayStream::GetStream() +{ + hpi_err_t hpi_error; + +#ifdef RDHPIPLAYSTREAM_USE_LOCAL_MUTEX + for(int i=0;igetCardOutputStreams(card_number);i++) { + if(++stream_mutex[card_number][i]==1) { + hpi_error=HPI_OutStreamOpen(NULL,card_index[card_number],i,&hpi_stream); + stream_number=i; + return stream_number; + } + else { + stream_mutex[card_number][i]--; + } + } + return -1; +#else + for(int i=0;igetCardOutputStreams(card_number);i++) { + if(HPI_OutStreamOpen(NULL,card_index[card_number],i,&hpi_stream)==0) { + stream_number=i; +// syslog(LOG_ERR,"HPI allocating ostream: %d",stream_number); + return stream_number; + } + } + return -1; +#endif +} + + +void RDHPIPlayStream::FreeStream() +{ + hpi_err_t hpi_error; + +#ifdef RDHPIPLAYSTREAM_USE_LOCAL_MUTEX + stream_mutex[card_number][stream_number]--; + hpi_error=HPI_OutStreamClose(NULL,hpi_stream); + stream_number=-1; +#else + hpi_error=HPI_OutStreamClose(NULL,hpi_stream); +// syslog(LOG_ERR,"HPI closing ostream: %d",stream_number); + stream_number=-1; +#endif +} diff --git a/rdhpi/rdhpiplaystream.h b/rdhpi/rdhpiplaystream.h new file mode 100644 index 00000000..80944ab4 --- /dev/null +++ b/rdhpi/rdhpiplaystream.h @@ -0,0 +1,139 @@ +// rdhpiplaystream.h +// +// A class for playing Microsoft WAV files. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdhpiplaystream.h,v 1.7.6.1 2012/05/04 14:56:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDHPIPLAYSTREAM_H +#define RDHPIPLAYSTREAM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifndef HPI_VER +#include +#endif + +#define MAX_FRAGMENT_SIZE 192000 +#define FRAGMENT_TIME 50 +#define TIMESCALE_LOW_LIMIT 83300 +#define TIMESCALE_HIGH_LIMIT 125000 +//#define RPLAYSTREAM_SHOW_SLOTS yes + + +class RDHPIPlayStream : public QObject,public RDWaveFile +{ + Q_OBJECT + + public: + enum State {Stopped=0,Playing=1,Paused=2}; + enum Error {Ok=0,NoFile=1,NoStream=2,AlreadyOpen=3}; + RDHPIPlayStream(RDHPISoundCard *card,QWidget *parent=0,const char *name=0); + ~RDHPIPlayStream(); + QString errorString(RDHPIPlayStream::Error err); + bool formatSupported(RDWaveFile::Format format); + bool formatSupported(); + RDHPIPlayStream::Error openWave(); + RDHPIPlayStream::Error openWave(QString filename); + void closeWave(); + int getCard() const; + int getStream() const; + int getSpeed() const; + bool setSpeed(int speed,bool pitch=false,bool rate=false); + RDHPIPlayStream::State getState() const; + + signals: + void isStopped(bool state); + void played(); + void paused(); + void stopped(); + void position(int samples); + void stateChanged(int card,int stream,int state); + + public slots: + void setCard(int card); + bool play(); + void pause(); + void stop(); + int currentPosition(); + bool setPosition(unsigned samples); + void setPlayLength(int length); + void tickClock(); + + private: + void Drained(); + int GetStream(); + void FreeStream(); + RDHPISoundCard *sound_card; + RDHPIPlayStream::State stream_state; + QString wave_name; + QTimer *clock; + uint32_t card_index[HPI_MAX_ADAPTERS]; + int card_number; + int stream_number; + bool is_open; + bool playing; + bool is_paused; + bool repositioned; + bool stopping; + unsigned audio_ptr; + unsigned left_to_write; + unsigned read_bytes; + unsigned samples_skipped; + int play_length; + QTimer *play_timer; + QTime start_time; + int play_speed; + bool pitch_can_vary; + bool rate_can_vary; + hpi_handle_t hpi_stream; + uint16_t state; + uint32_t buffer_size; + uint32_t data_to_play; + uint32_t samples_played; + uint32_t reserved; + int fragment_time; + uint8_t *pdata; +#if HPI_VER < 0x030a00 + HPI_FORMAT format; +#else + struct hpi_format format; +#endif +#if HPI_VER < 0x00030500 + HPI_DATA hpi_data; +#endif + uint32_t fragment_size; + bool restart_transport; + int samples_pending; + unsigned current_position; +}; + + +#endif // RDHPIPLAYSTREAM_H diff --git a/rdhpi/rdhpirecordstream.cpp b/rdhpi/rdhpirecordstream.cpp new file mode 100644 index 00000000..918849ff --- /dev/null +++ b/rdhpi/rdhpirecordstream.cpp @@ -0,0 +1,703 @@ +// rdhpirecordstream.cpp +// +// A class for recording Microsoft WAV files. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdhpirecordstream.cpp,v 1.7 2011/05/19 22:16:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +RDHPIRecordStream::RDHPIRecordStream(RDHPISoundCard *card, + QWidget *parent,const char *name) + :QObject(parent,name),RDWaveFile() +{ + hpi_err_t hpi_err; + int quan; + uint16_t type[HPI_MAX_ADAPTERS]; + + if(getenv(DEBUG_VAR)==NULL) { + debug=false; + } + else { + debug=true; + printf("RDHPIRecordStream: debugging enabled\n"); + } + if(getenv(XRUN_VAR)==NULL) { + xrun=false; + } + else { + xrun=true; + printf("RDHPIRecordStream: xrun notification enabled\n"); + } + + sound_card=card; + + card_number=-1; + stream_number=-1; + is_ready=false; + is_recording=false; + is_paused=false; + stopping=false; + record_started=false; + record_length=0; + is_open=false; + pdata=NULL; + + // + // Get Adapter Indices + // +#if HPI_VER < 0x00030600 + for(unsigned i=0;igetCardInputStreams(card_number);i++) { + if(HPI_InStreamOpen(NULL,card_index[card_number],i,&histream)==0) { + found=true; + break; + } + } + if(!found) { + return false; + } + } + else { + histream=hpi_stream; + } + switch(format) { + case RDWaveFile::Pcm8: + hpi_err=HPI_FormatCreate(&hformat,getChannels(), + HPI_FORMAT_PCM8_UNSIGNED, + getSamplesPerSec(),getHeadBitRate(),0); + state=HPI_InStreamQueryFormat(NULL,histream,&hformat); + break; + + case RDWaveFile::Pcm16: + hpi_err=HPI_FormatCreate(&hformat,getChannels(), + HPI_FORMAT_PCM16_SIGNED, + getSamplesPerSec(),getHeadBitRate(),0); + state=HPI_InStreamQueryFormat(NULL,histream,&hformat); + break; + + case RDWaveFile::MpegL1: + hpi_err=HPI_FormatCreate(&hformat,getChannels(),HPI_FORMAT_MPEG_L1, + getSamplesPerSec(),getHeadBitRate(),0); + state=HPI_InStreamQueryFormat(NULL,histream,&hformat); + break; + + case RDWaveFile::MpegL2: + hpi_err=HPI_FormatCreate(&hformat,getChannels(),HPI_FORMAT_MPEG_L2, + getSamplesPerSec(),getHeadBitRate(),0); + state=HPI_InStreamQueryFormat(NULL,histream,&hformat); + break; + + case RDWaveFile::MpegL3: + hpi_err=HPI_FormatCreate(&hformat,getChannels(),HPI_FORMAT_MPEG_L3, + getSamplesPerSec(),getHeadBitRate(),0); + state=HPI_InStreamQueryFormat(NULL,histream,&hformat); + break; + + default: + state=1; + break; + } + if(!is_open) { + hpi_err=HPI_InStreamClose(NULL,histream); + } + if(state!=0) { + return false; + } + return true; +} + + +bool RDHPIRecordStream::formatSupported() +{ + switch(getFormatTag()) { + case WAVE_FORMAT_PCM: + switch(getBitsPerSample()) { + case 8: + return formatSupported(RDWaveFile::Pcm8); + break; + + case 16: + return formatSupported(RDWaveFile::Pcm16); + break; + + default: + return false; + } + break; + + case WAVE_FORMAT_MPEG: + switch(getHeadLayer()) { + case 1: + return formatSupported(RDWaveFile::MpegL1); + break; + + case 2: + return formatSupported(RDWaveFile::MpegL2); + break; + + case 3: + return formatSupported(RDWaveFile::MpegL3); + break; + + default: + return false; + } + break; + + default: + return false; + } +} + + +int RDHPIRecordStream::getCard() const +{ + return card_number; +} + + +void RDHPIRecordStream::setCard(int card) +{ + if(!is_recording) { + card_number=card; + if(debug) { + printf("RDHPIRecordStream: using card %d\n",card_number); + } + } +} + + +int RDHPIRecordStream::getStream() const +{ + return stream_number; +} + + +void RDHPIRecordStream::setStream(int stream) +{ + stream_number=stream; +} + + +bool RDHPIRecordStream::haveInputVOX() const +{ + return sound_card->haveInputStreamVOX(card_number,stream_number); +} + + +RDHPIRecordStream::RecordState RDHPIRecordStream::getState() +{ + if(is_recording) { + if(record_started) { + return RDHPIRecordStream::RecordStarted; + } + return RDHPIRecordStream::Recording; + } + if(is_paused) { + return RDHPIRecordStream::Paused; + } + if(is_ready) { + return RDHPIRecordStream::RecordReady; + } + return RDHPIRecordStream::Stopped; +} + + +int RDHPIRecordStream::getPosition() const +{ + if((!is_recording)&&(!is_ready)&&(!is_paused)) { + return 0; + } + return samples_recorded; +} + + +unsigned RDHPIRecordStream::samplesRecorded() const +{ + return samples_recorded; +} + + +bool RDHPIRecordStream::recordReady() +{ + hpi_err_t hpi_error=0; + char hpi_text[200]; + + if(debug) { + printf("RDHPIRecordStream: received recordReady()\n"); + } + if(!is_open) { + return false; + } + if((!is_recording)&&(!is_paused)) { + resetWave(); + if(HPI_InStreamGetInfoEx(NULL,hpi_stream, + &state,&buffer_size,&data_recorded, + &samples_recorded,&reserved)!=0) { + if(debug) { + printf("RDHPIRecordStream: HPI_InStreamGetInfoEx() failed\n"); + } + return false; + } + fragment_size=buffer_size/4; + if(fragment_size>192000) { // ALSA Compatibility Limitation + fragment_size=192000; + } + fragment_time=(1000*fragment_size)/(getAvgBytesPerSec()); + if(pdata!=NULL) { + delete pdata; + } + pdata=(uint8_t *)malloc(fragment_size); + if(pdata==NULL) { + if(debug) { + printf("RDHPIRecordStream: couldn't allocate buffer\n"); + } + return false; + } + switch(getFormatTag()) { + case WAVE_FORMAT_PCM: + if(debug) { + printf("RDHPIRecordStream: using PCM%d format\n", + getBitsPerSample()); + } + switch(getBitsPerSample()) { + case 8: + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_PCM8_UNSIGNED,getSamplesPerSec(), + 0,0); + break; + case 16: + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_PCM16_SIGNED,getSamplesPerSec(), + 0,0); + break; + case 32: + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_PCM32_SIGNED,getSamplesPerSec(), + 0,0); + break; + default: + if(debug) { + printf("RDHPIRecordStream: unsupported sample size\n"); + } + return false; + } + break; + + case WAVE_FORMAT_MPEG: + if(debug) { + printf("RDHPIRecordStream: using MPEG-1 Layer %d\n",getHeadLayer()); + } + switch(getHeadLayer()) { + case 1: + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_MPEG_L1,getSamplesPerSec(), + getHeadBitRate(),getHeadFlags()); + break; + case 2: + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_MPEG_L2,getSamplesPerSec(), + getHeadBitRate(),getHeadFlags()); + break; + case 3: + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_MPEG_L3,getSamplesPerSec(), + getHeadBitRate(),getHeadFlags()); + break; + default: + hpi_error=HPI_AdapterClose(NULL,card_index[card_number]); + if(debug) { + printf("RDHPIRecordStream: invalid MPEG-1 layer\n"); + } + return false; + } + if(getMextChunk()) { + setMextHomogenous(true); + setMextPaddingUsed(false); + setMextHackedBitRate(true); + setMextFreeFormat(false); + setMextFrameSize(144*getHeadBitRate()/getSamplesPerSec()); + setMextAncillaryLength(5); + setMextLeftEnergyPresent(true); + if(getChannels()>1) { + setMextRightEnergyPresent(true); + } + else { + setMextRightEnergyPresent(false); + } + setMextPrivateDataPresent(false); + } + break; + + case WAVE_FORMAT_VORBIS: + if(debug) { + printf("RDHPIRecordStream: using OggVorbis\n"); + } + hpi_error=HPI_FormatCreate(&format,getChannels(), + HPI_FORMAT_PCM16_SIGNED,getSamplesPerSec(), + 0,0); + break; + + default: + if(debug) { + printf("RDHPIRecordStream: invalid format tag\n"); + } + return false; + break; + } + if((hpi_error=HPI_InStreamQueryFormat(NULL,hpi_stream, + &format))!=0) { + if(debug) { + HPI_GetErrorText(hpi_error,hpi_text); + printf("Num: %d\n",hpi_error); + printf("RDHPIRecordStream: %s\n",hpi_text); + } + return false; + } + } +#if HPI_VER < 0x00030500 + HPI_DataCreate(&hpi_data,&format,pdata,fragment_size); +#endif + hpi_error=HPI_InStreamSetFormat(NULL,hpi_stream,&format); + hpi_error=HPI_InStreamStart(NULL,hpi_stream); +// clock->start(2*fragment_time/3); + clock->start(100); + is_ready=true; + is_recording=false; + is_paused=false; + stopping=false; + emit isStopped(false); + emit ready(); + emit stateChanged(card_number,stream_number,1); // RecordReady + if(debug) { + printf("RDHPIRecordStream: emitted isStopped(false)\n"); + printf("RDHPIRecordStream: emitted ready()\n"); + printf("RDHPIRecordStream: emitted stateChanged(%d,%d,RDHPIRecordStream::RecordReady)\n",card_number,stream_number); + } + + return true; +} + + +void RDHPIRecordStream::record() +{ + hpi_err_t hpi_err; + + if(debug) { + printf("RDHPIRecordStream: received record()\n"); + } + if(!is_open) { + return; + } + if(!is_ready) { + recordReady(); + } + record_started=false; + hpi_err=HPI_InStreamReset(NULL,hpi_stream); + hpi_err=HPI_InStreamStart(NULL,hpi_stream); + is_recording=true; + is_paused=false; + emit isStopped(false); + emit recording(); + emit stateChanged(card_number,stream_number,0); // Recording + if(debug) { + printf("RDHPIRecordStream: emitted isStopped(false)\n"); + printf("RDHPIRecordStream: emitted recording()\n"); + printf("RDHPIRecordStream: emitted stateChanged(%d,%d,RDHPIRecordStream::Recording)\n",card_number,stream_number); + } + tickClock(); +} + + +void RDHPIRecordStream::pause() +{ + hpi_err_t hpi_err; + + if(debug) { + printf("RDHPIRecordStream: received pause()\n"); + } + if(!is_recording) { + return; + } + hpi_err=HPI_InStreamStop(NULL,hpi_stream); + tickClock(); + hpi_err=HPI_InStreamGetInfoEx(NULL,hpi_stream,&state,&buffer_size, + &data_recorded,&samples_recorded,&reserved); + is_recording=false; + is_paused=true; + hpi_err=HPI_InStreamStart(NULL,hpi_stream); + emit paused(); + emit stateChanged(card_number,stream_number,2); // Paused + if(debug) { + printf("RDHPIRecordStream: emitted paused()\n"); + printf("RDHPIRecordStream: emitted stateChanged(%d,%d,RDHPIRecordStream::Paused)\n",card_number,stream_number); + } +} + + +void RDHPIRecordStream::stop() +{ + hpi_err_t hpi_err; + + if(debug) { + printf("RDHPIRecordStream: received stop()\n"); + } + if(is_ready|is_recording|is_paused) { + hpi_err=HPI_InStreamStop(NULL,hpi_stream); + tickClock(); + clock->stop(); + is_recording=false; + is_paused=false; + is_ready=false; + if(pdata!=NULL) { + delete pdata; + pdata=NULL; + } + emit isStopped(true); + emit stopped(); + emit stateChanged(card_number,stream_number,RDHPIRecordStream::Stopped); + emit position(0); + if(debug) { + printf("RDHPIRecordStream: emitted isStopped(true)\n"); + printf("RDHPIRecordStream: emitted stopped()\n"); + printf("RDHPIRecordStream: emitted stateChanged(%d,%d,RDHPIRecordStream::Stopped)\n",card_number,stream_number); + printf("RDHPIRecordStream: emitted position(0)\n"); + } + } +} + + +void RDHPIRecordStream::setInputVOX(int gain) +{ + sound_card->setInputStreamVOX(card_number,stream_number,gain); +} + + +void RDHPIRecordStream::setRecordLength(int length) +{ + record_length=length; +} + + +void RDHPIRecordStream::tickClock() +{ + hpi_err_t hpi_err; + + hpi_err=HPI_InStreamGetInfoEx(NULL,hpi_stream, + &state,&buffer_size,&data_recorded, + &samples_recorded,&reserved); + if((!record_started)&&(is_recording)) { + if(samples_recorded>0) { + if(record_length>0) { + length_timer->start(record_length,true); + } + emit recordStart(); + emit stateChanged(card_number,stream_number,4); // RecordStarted + if(debug) { + printf("RDHPIRecordStream: emitted recordStart()\n"); + printf("RDHPIRecordStream: emitted stateChanged(%d,%d,RDHPIRecordStream::RecordStarted)\n",card_number,stream_number); + } + record_started=true; + } + } + while(data_recorded>fragment_size) { +#if HPI_VER > 0x00030500 + hpi_err=HPI_InStreamReadBuf(NULL,hpi_stream,pdata,fragment_size); +#else + hpi_err=HPI_InStreamRead(NULL,hpi_stream,&hpi_data); +#endif + if(is_recording) { + writeWave(pdata,fragment_size); + } + hpi_err=HPI_InStreamGetInfoEx(NULL,hpi_stream, + &state,&buffer_size,&data_recorded, + &samples_recorded,&reserved); + } + if(state==HPI_STATE_STOPPED) { +#if HPI_VER > 0x00030500 + hpi_err=HPI_InStreamReadBuf(NULL,hpi_stream,pdata,data_recorded); +#else + hpi_err=HPI_DataCreate(&hpi_data,&format,pdata,data_recorded); + hpi_err=HPI_InStreamRead(NULL,hpi_stream,&hpi_data); +#endif + if(is_recording) { + writeWave(pdata,data_recorded); + } + } + emit position(samples_recorded); + if(debug) { + printf("RDHPIRecordStream: emitted position(%u)\n", + (unsigned)samples_recorded); + } +} + + +bool RDHPIRecordStream::GetStream() +{ + hpi_err_t hpi_err; + char hpi_text[100]; + + if((hpi_err= + HPI_InStreamOpen(NULL,card_index[card_number],stream_number,&hpi_stream))!=0) { + if(debug) { + HPI_GetErrorText(hpi_err,hpi_text); + fprintf(stderr,"*** HPI Error: %s ***\n",hpi_text); + } + return false; + } + return true; +} + + +void RDHPIRecordStream::FreeStream() +{ + hpi_err_t hpi_err; + + hpi_err=HPI_InStreamClose(NULL,hpi_stream); +} + diff --git a/rdhpi/rdhpirecordstream.h b/rdhpi/rdhpirecordstream.h new file mode 100644 index 00000000..2c5e1bd8 --- /dev/null +++ b/rdhpi/rdhpirecordstream.h @@ -0,0 +1,137 @@ +// rdhpirecordstream.h +// +// A class for recording Microsoft WAV files. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdhpirecordstream.h,v 1.6.6.1 2012/05/04 14:56:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDHPIRECORDSTREAM_H +#define RDHPIRECORDSTREAM_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define DEBUG_VAR "_RDHPIRECORDSTREAM" +#define XRUN_VAR "_RSOUND_XRUN" + +#include +#ifndef HPI_VER +#include +#endif +#define AUDIO_SIZE 32768 +#define RDHPIRECORDSTREAM_CLOCK_INTERVAL 100 + + +class RDHPIRecordStream : public QObject,public RDWaveFile +{ + Q_OBJECT + + public: + enum RecordState {Recording=0,RecordReady=1,Paused=2,Stopped=3, + RecordStarted=4}; + enum Error {Ok=0,NoFile=1,NoStream=2,AlreadyOpen=3}; + RDHPIRecordStream(RDHPISoundCard *card,QWidget *parent=0,const char *name=0); + ~RDHPIRecordStream(); + QString errorString(RDHPIRecordStream::Error err); + RDHPIRecordStream::Error createWave(); + void closeWave(); + RDHPIRecordStream::Error createWave(QString filename); + bool formatSupported(RDWaveFile::Format format); + bool formatSupported(); + int getCard() const; + int getStream() const; + bool haveInputVOX() const; + RDHPIRecordStream::RecordState getState(); + int getPosition() const; + unsigned samplesRecorded() const; + + signals: + void isStopped(bool state); + void ready(); + void recording(); + void recordStart(); + void paused(); + void stopped(); + void position(int samples); + void stateChanged(int card,int stream,int state); + + public slots: + void setCard(int card); + void setStream(int stream); + bool recordReady(); + void record(); + void pause(); + void stop(); + void setInputVOX(int gain); + void setRecordLength(int length); + + private slots: + void tickClock(); + + private: + bool GetStream(); + void FreeStream(); + RDHPISoundCard *sound_card; + bool debug; + bool xrun; + QTimer *clock; + uint32_t card_index[HPI_MAX_ADAPTERS]; + int card_number; + int stream_number; + bool is_recording; + bool is_ready; + bool is_paused; + bool stopping; + bool record_started; + QTimer *length_timer; + int record_length; + unsigned audio_ptr; + unsigned char abuf[AUDIO_SIZE]; + unsigned left_to_write; + hpi_handle_t hpi_stream; + uint16_t state; + uint32_t buffer_size; + uint32_t data_recorded; + uint32_t samples_recorded; + uint32_t reserved; + uint32_t fragment_size; + int fragment_time; + uint8_t *pdata; +#if HPI_VER < 0x030a00 + HPI_FORMAT format; +#else + struct hpi_format format; +#endif +#if HPI_VER < 0x00030500 + HPI_DATA hpi_data; +#endif + bool is_open; +}; + + +#endif // RDHPIRECORDSTREAM_H diff --git a/rdhpi/rdhpisoundcard.cpp b/rdhpi/rdhpisoundcard.cpp new file mode 100644 index 00000000..2ae1273d --- /dev/null +++ b/rdhpi/rdhpisoundcard.cpp @@ -0,0 +1,996 @@ +// rdhpisoundcard.cpp +// +// The audio card subsystem for the HPI Library. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdhpisoundcard.cpp,v 1.10.6.3 2012/08/07 15:48:04 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + + +#include +#include + +#include + +RDHPISoundCard::RDHPISoundCard(QObject *parent,const char *name) + : QObject(parent,name) +{ + card_quantity=0; + fade_type=RDHPISoundCard::Log; + for(int i=0;i=card_quantity) { + return false; + } + if(stream>=card_input_streams[card]) { + return false; + } + hpi_err=HPI_MeterGetPeak(NULL, + input_stream_meter_control[card][stream],level); + return true; +} + + +bool RDHPISoundCard::outputStreamMeter(int card,int stream,short *level) +{ + hpi_err_t hpi_err; + + if(card>=card_quantity) { + return false; + } + if(stream>=card_output_streams[card]) { + return false; + } + hpi_err=HPI_MeterGetPeak(NULL, + output_stream_meter_control[card][stream],level); + return true; +} + + +bool RDHPISoundCard::inputPortMeter(int card,int port,short *level) +{ + hpi_err_t hpi_err; + + if(card>=card_quantity) { + return false; + } + if(port>=card_input_ports[card]) { + return false; + } + hpi_err=HPI_MeterGetPeak(NULL, + input_port_meter_control[card][port],level); + return true; +} + + +bool RDHPISoundCard::outputPortMeter(int card,int port,short *level) +{ + hpi_err_t hpi_err; + + if(card>=card_quantity) { + return false; + } + if(port>=card_output_ports[card]) { + return false; + } + hpi_err=HPI_MeterGetPeak(NULL, + output_port_meter_control[card][port],level); + return true; +} + + +bool RDHPISoundCard::haveInputMode(int card,int port) const +{ + return input_port_mode[card][port]; +} + + +bool RDHPISoundCard::haveOutputMode(int card,int stream) const +{ + return output_stream_mode[card][stream]; +} + + +bool RDHPISoundCard::haveInputPortMux(int card,int port) const +{ + return input_port_mux[card][port]; +} + + +bool RDHPISoundCard::queryInputPortMux(int card,int port,SourceNode node) const +{ + switch(node) { + case RDHPISoundCard::LineIn: + return input_port_mux_type[card][port][0]; + break; + case RDHPISoundCard::AesEbuIn: + return input_port_mux_type[card][port][1]; + break; + default: + return false; + break; + } +} + + +bool RDHPISoundCard::haveInputStreamMux(int card,int stream) const +{ + return input_stream_mux[card][stream]; +} + + +int RDHPISoundCard::getInputVolume(int card,int stream,int port) +{ + short gain[2]; + hpi_err_t hpi_err; + + hpi_err=HPI_VolumeGetGain(NULL, + input_stream_volume_control[card][stream][port],gain); + return gain[0]; +} + + +int RDHPISoundCard::getOutputVolume(int card,int stream,int port) +{ + short gain[2]; + hpi_err_t hpi_err; + + hpi_err=HPI_VolumeGetGain(NULL, + output_stream_volume_control[card][stream][port],gain); + return gain[0]; +} + + +int RDHPISoundCard::getInputLevel(int card,int port) +{ + short gain[2]; + hpi_err_t hpi_err; + + hpi_err=HPI_VolumeGetGain(NULL, + input_port_level_control[card][port],gain); + return gain[0]; +} + + +int RDHPISoundCard::getOutputLevel(int card,int port) +{ + short gain[2]; + hpi_err_t hpi_err; + + hpi_err=HPI_VolumeGetGain(NULL, + output_port_level_control[card][port],gain); + return gain[0]; +} + + + +void RDHPISoundCard::setInputVolume(int card,int stream,int level) +{ + hpi_err_t hpi_err; + + if(!haveInputVolume(card,stream,0)) { + return; + } + short gain[2]; + gain[0]=level; + gain[1]=level; + hpi_err=HPI_VolumeSetGain(NULL, + input_stream_volume_control[card][stream][0],gain); +} + + +void RDHPISoundCard::setOutputVolume(int card,int stream,int port,int level) +{ + hpi_err_t hpi_err; + + if(!haveOutputVolume(card,stream,port)) { + return; + } + short gain[2]; + gain[0]=level; + gain[1]=level; + hpi_err=HPI_VolumeSetGain(NULL, + output_stream_volume_control[card][stream][port],gain); +} + + + +void RDHPISoundCard::fadeOutputVolume(int card,int stream,int port, + int level,int length) +{ + hpi_err_t hpi_err; + + if(!haveOutputVolume(card,stream,port)) { + return; + } + short gain[2]; + + gain[0]=level; + gain[1]=level; + hpi_err=HPI_VolumeAutoFadeProfile(NULL, + output_stream_volume_control[card][stream][port], + gain,length,hpi_fade_type); +} + + +void RDHPISoundCard::setInputLevel(int card,int port,int level) +{ + hpi_err_t hpi_err; + short gain[HPI_MAX_CHANNELS]; + + if(!haveInputLevel(card,port)) { + return; + } + for(unsigned i=0;i>8); + hpi_info[i].setHpiMinorVersion(dummy_hpi&255); + */ + hpi_info[i].setDspMajorVersion((dummy_version>>13)&7); + hpi_info[i].setDspMinorVersion((dummy_version>>7)&63); + hpi_info[i].setPcbVersion((char)(((dummy_version>>3)&7)+'A')); + hpi_info[i].setAssemblyVersion(dummy_version&7); + hpi_err=HPI_AdapterClose(NULL,card_index[i]); + str=QString(tr("Input Stream")); + for(int j=0;jstart(METER_INTERVAL); +} diff --git a/rdhpi/rdhpisoundcard.h b/rdhpi/rdhpisoundcard.h new file mode 100644 index 00000000..57f31dfb --- /dev/null +++ b/rdhpi/rdhpisoundcard.h @@ -0,0 +1,238 @@ +// rdhpisoundcard.h +// +// Sound card subsystem for the HPI Library. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdhpisoundcard.h,v 1.5.6.3 2012/08/07 15:48:04 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDHPISOUNDCARD_H +#define RDHPISOUNDCARD_H + +#define METER_INTERVAL 20 + +#include +#include +#include + +#include + +#include +#ifndef HPI_VER +#include +#endif + +#if HPI_VER < 0x40411 +typedef uint16_t hpi_err_t; +typedef uint32_t hpi_handle_t; +#endif + +/* + * Definitions + */ +#define RDHPISOUNDCARD_HPI_MAX_LEVEL 2400 +#define RDHPISOUNDCARD_HPI_MIN_LEVEL 0 + + +class RDHPISoundCard : public QObject +{ + Q_OBJECT; + + public: + enum FadeProfile {Linear=0,Log=1}; + enum Channel {Left=0,Right=1}; + enum ChannelMode {Normal=0, // HPI_CHANNEL_MODE_NORMAL-1 + Swap=1, // HPI_CHANNEL_MODE_SWAP-1 + LeftOnly=2, // HPI_CHANNEL_MODE_LEFT_TO_STEREO-1 + RightOnly=3}; // HPI_CHANNEL_MODE_RIGHT_TO_STEREO-1 + enum DeviceClass {RecordDevice=0,PlayDevice=1}; + enum Driver {Alsa=0,Hpi=1,Jack=2}; + enum ClockSource {Internal=0,AesEbu=1,SpDiff=2,WordClock=4}; + enum SourceNode {SourceBase=100, // HPI_SOURCENODE_BASE + OStream=101, // HPI_SOURCENODE_OSTREAM + LineIn=102, // HPI_SOURCENODE_LINEIN + AesEbuIn=103, // HPI_SOURCENODE_AESEBU_IN + Tuner=104, // HPI_SOURCENODE_TUNER + RfIn=105, // HPI_SOURCENODE_RF + Clock=106, // HPI_SOURCENODE_CLOCK_SOURCE + Raw=107, // HPI_SOURCENODE_RAW_BITSTREAM + Mic=108 // HPI_SOURCENODE_MICROPHONE + }; + + /** + * Mixer Destination Nodes + **/ + enum DestNode {DestBase=200, // HPI_DESTNODE_BASE + IStream=201, // HPI_DESTNODE_ISTREAM + LineOut=202, // HPI_DESTNODE_LINEOUT + AesEbuOut=203, // HPI_DESTNODE_AESEBU_OUT + RfOut=204, // HPI_DESTNODE_RF + Speaker=205 // HPI_DESTNODE_SPEAKER + }; + + enum TunerBand {Fm=0,FmStereo=1,Am=2,Tv=3}; + + enum Subcarrier {Mpx=0,Rds=1}; + RDHPISoundCard(QObject *parent=0,const char *name=0); + ~RDHPISoundCard(); + Driver driver() const; + RDHPIInformation *hpiInformation(int card); + int getCardQuantity() const; + int getCardInputStreams(int card) const; + int getCardOutputStreams(int card) const; + int getCardInputPorts(int card) const; + int getCardOutputPorts(int card) const; + const void *getCardInfo(int card) const; + QString getCardDescription(int card) const; + QString getInputStreamDescription(int card,int stream) const; + QString getOutputStreamDescription(int card,int stream) const; + QString getInputPortDescription(int card,int port) const; + QString getOutputPortDescription(int card,int port) const; + bool setClockSource(int card,RDHPISoundCard::ClockSource src); + bool haveTimescaling(int card) const; + bool haveInputVolume(int card,int stream,int port) const; + bool haveOutputVolume(int card,int stream,int port) const; + bool haveInputLevel(int card,int port) const; + bool haveOutputLevel(int card,int port) const; + bool haveInputStreamMeter(int card,int stream) const; + bool haveOutputStreamMeter(int card,int stream) const; + bool haveInputPortMeter(int card,int port) const; + bool haveOutputPortMeter(int card,int port) const; + bool haveTuner(int card,int port) const; + RDHPISoundCard::TunerBand tunerBand(int card,int port); + void setTunerBand(int card,int port,RDHPISoundCard::TunerBand band); + int tunerFrequency(int card,int port); + void setTunerFrequency(int card,int port,int freq); + bool tunerSubcarrier(int card,int port,RDHPISoundCard::Subcarrier sub); + int tunerLowFrequency(int card,int port,RDHPISoundCard::TunerBand band); + int tunerHighFrequency(int card,int port,RDHPISoundCard::TunerBand band); + bool inputStreamMeter(int card,int stream,short *level); + bool outputStreamMeter(int card,int stream,short *level); + bool inputPortMeter(int card,int port,short *level); + bool outputPortMeter(int card,int port,short *level); + bool haveInputMode(int card,int port) const; + bool haveOutputMode(int card,int stream) const; + bool haveInputStreamVOX(int card,int stream) const; + bool haveInputPortMux(int card,int port) const; + bool queryInputPortMux(int card,int port,SourceNode node) const; + bool haveInputStreamMux(int card,int stream) const; + int getInputVolume(int card,int stream,int port); + int getOutputVolume(int card,int stream,int port); + int getInputLevel(int card,int port); + int getOutputLevel(int card,int port); + RDHPISoundCard::SourceNode getInputPortMux(int card,int port); + bool setInputPortMux(int card,int port,RDHPISoundCard::SourceNode node); + RDHPISoundCard::FadeProfile getFadeProfile() const; + unsigned short getInputPortError(int card,int port); + void setFadeProfile(RDHPISoundCard::FadeProfile profile); + + signals: + void inputPortError(int card,int port); + void leftInputStreamMeter(int card,int stream,int level); + void leftOutputStreamMeter(int card,int stream,int level); + void rightInputStreamMeter(int card,int stream,int level); + void rightOutputStreamMeter(int card,int stream,int level); + void leftInputPortMeter(int card,int port,int level); + void leftOutputPortMeter(int card,int port,int level); + void rightInputPortMeter(int card,int port,int level); + void rightOutputPortMeter(int card,int port,int level); + void inputMode(int card,int port,RDHPISoundCard::ChannelMode mode); + void outputMode(int card,int stream,RDHPISoundCard::ChannelMode mode); + void tunerSubcarrierChanged(RDHPISoundCard::Subcarrier car,bool state); + + public slots: + void setInputVolume(int card,int stream,int level); + void setOutputVolume(int card,int stream,int port,int level); + void fadeOutputVolume(int card,int stream,int port,int level,int length); + void setInputLevel(int card,int port,int level); + void setOutputLevel(int card,int port,int level); + void setInputMode(int card,int port,RDHPISoundCard::ChannelMode mode); + void setOutputMode(int card,int stream,RDHPISoundCard::ChannelMode mode); + void setInputStreamVOX(int card,int stream,short gain); + bool havePassthroughVolume(int card,int in_port,int out_port); + bool setPassthroughVolume(int card,int in_port,int out_port,int level); + + private slots: + void clock(); + + private: + void HPIProbe(); + uint16_t card_input_streams[HPI_MAX_ADAPTERS]; + uint16_t card_output_streams[HPI_MAX_ADAPTERS]; + uint16_t card_input_ports[HPI_MAX_ADAPTERS]; + uint16_t card_output_ports[HPI_MAX_ADAPTERS]; + QString card_description[HPI_MAX_ADAPTERS]; + QString input_stream_description[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + QString output_stream_description[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + QString input_port_description[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + QString output_port_description[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + bool input_stream_volume[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS][HPI_MAX_NODES]; + bool output_stream_volume[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS][HPI_MAX_NODES]; + bool input_port_level[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + bool output_port_level[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + bool input_stream_meter[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + bool output_stream_meter[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + bool input_port_meter[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + bool output_port_meter[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + bool input_port_mode[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + bool output_stream_mode[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + bool input_stream_vox[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + bool input_port_mux[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + bool input_port_mux_type[HPI_MAX_ADAPTERS][HPI_MAX_NODES][2]; + bool passthrough_port_volume[HPI_MAX_ADAPTERS][HPI_MAX_NODES][HPI_MAX_NODES]; + uint16_t input_mux_index[HPI_MAX_ADAPTERS][HPI_MAX_NODES][2]; + bool input_stream_mux[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + bool input_port_aesebu[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + uint16_t input_port_aesebu_error[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + bool timescale_support[HPI_MAX_ADAPTERS]; + int card_quantity; + QTimer *clock_timer; + RDHPISoundCard::FadeProfile fade_type; + uint32_t card_index[HPI_MAX_ADAPTERS]; + hpi_handle_t hpi_mixer[HPI_MAX_ADAPTERS]; + hpi_handle_t clock_source_control[HPI_MAX_ADAPTERS]; + hpi_handle_t input_stream_volume_control[HPI_MAX_ADAPTERS] + [HPI_MAX_STREAMS][HPI_MAX_NODES]; + hpi_handle_t output_stream_volume_control[HPI_MAX_ADAPTERS] + [HPI_MAX_STREAMS][HPI_MAX_NODES]; + hpi_handle_t input_port_level_control[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + hpi_handle_t output_port_level_control[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + hpi_handle_t input_stream_meter_control[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + hpi_handle_t output_stream_meter_control[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + hpi_handle_t input_port_meter_control[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + hpi_handle_t output_port_meter_control[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + hpi_handle_t input_port_mode_control[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + hpi_handle_t output_stream_mode_control[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + hpi_handle_t input_stream_vox_control[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + bool input_mux_type[HPI_MAX_ADAPTERS]; + hpi_handle_t input_mux_control[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS]; + hpi_handle_t passthrough_port_volume_control[HPI_MAX_ADAPTERS] + [HPI_MAX_NODES][HPI_MAX_NODES]; + hpi_handle_t input_port_aesebu_control[HPI_MAX_ADAPTERS][HPI_MAX_NODES]; + uint16_t hpi_fade_type; + short + input_stream_meter_peak[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS][HPI_MAX_CHANNELS]; + short + output_stream_meter_peak[HPI_MAX_ADAPTERS][HPI_MAX_STREAMS][HPI_MAX_CHANNELS]; + short input_port_meter_peak[HPI_MAX_ADAPTERS][HPI_MAX_NODES][HPI_MAX_CHANNELS]; + short output_port_meter_peak[HPI_MAX_ADAPTERS][HPI_MAX_NODES][HPI_MAX_CHANNELS]; + RDHPIInformation hpi_info[HPI_MAX_ADAPTERS]; +}; + + +#endif // RDHPISOUNDCARD_H diff --git a/rdhpi/rdhpisoundselector.cpp b/rdhpi/rdhpisoundselector.cpp new file mode 100644 index 00000000..8a2848f2 --- /dev/null +++ b/rdhpi/rdhpisoundselector.cpp @@ -0,0 +1,71 @@ +// rdhpisoundselector.cpp +// +// A selection widget for audio devices. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdhpisoundselector.cpp,v 1.3 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + + +RDHPISoundSelector::RDHPISoundSelector(RDHPISoundCard::DeviceClass dev_class, + QWidget *parent, + const char *name) :QListBox(parent,name) +{ + sound_card=new RDHPISoundCard(this,"sound_card"); + + if(dev_class==RDHPISoundCard::PlayDevice) { + for(int i=0;igetCardQuantity();i++) { + for(int j=0;jgetCardOutputPorts(i);j++) { + insertItem(sound_card->getOutputPortDescription(i,j), + i*HPI_MAX_NODES+j); + } + } + } + if(dev_class==RDHPISoundCard::RecordDevice) { + for(int i=0;igetCardQuantity();i++) { + for(int j=0;jgetCardInputPorts(i);j++) { + insertItem(sound_card->getInputPortDescription(i,j), + i*HPI_MAX_NODES+j); + } + } + } + connect(this,SIGNAL(highlighted(int)),this,SLOT(selection(int))); +} + + +void RDHPISoundSelector::selection(int selection) +{ + emit changed(selection/HPI_MAX_ADAPTERS, + selection-HPI_MAX_ADAPTERS*(selection/HPI_MAX_ADAPTERS)); + emit cardChanged(selection/HPI_MAX_ADAPTERS); + emit portChanged(selection-HPI_MAX_ADAPTERS*(selection/HPI_MAX_ADAPTERS)); +} diff --git a/rdhpi/rdhpisoundselector.h b/rdhpi/rdhpisoundselector.h new file mode 100644 index 00000000..4bbbd4bc --- /dev/null +++ b/rdhpi/rdhpisoundselector.h @@ -0,0 +1,68 @@ +// rdhpisoundselector.h +// +// A selection widget for audio devices. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdhpisoundselector.h,v 1.4 2011/05/18 14:38:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef RDHPISOUNDSELECTOR_H +#define RDHPISOUNDSELECTOR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef ALSA +#include +#endif // HPI + +#ifdef JACK +#include +#endif // JACK + +class RDHPISoundSelector : public QListBox +{ + Q_OBJECT + + public: + RDHPISoundSelector(RDHPISoundCard::DeviceClass dev_class, + QWidget *parent=0,const char *name=0); + + signals: + void changed(int card,int port); + void cardChanged(int card); + void portChanged(int port); + + private slots: + void selection(int selection); + + private: + RDHPISoundCard *sound_card; +}; + + +#endif // RDHPISOUNDSELECTOR_H diff --git a/rdlibrary/Makefile.am b/rdlibrary/Makefile.am new file mode 100644 index 00000000..c5e31a53 --- /dev/null +++ b/rdlibrary/Makefile.am @@ -0,0 +1,102 @@ +## automake.am +## +## Automake.am for rivendell/rdlibrary +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.51.8.4 2014/01/08 02:08:37 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdlibrary_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rdlibrary_*.qm + +all: + @QT_BIN@/lupdate rdlibrary.pro + @QT_BIN@/lrelease rdlibrary.pro + +bin_PROGRAMS = rdlibrary + +dist_rdlibrary_SOURCES = audio_cart.cpp audio_cart.h\ + audio_controls.h\ + cart_tip.cpp cart_tip.h\ + cdripper.cpp cdripper.h\ + disk_gauge.cpp disk_gauge.h\ + disk_ripper.cpp disk_ripper.h\ + edit_cart.cpp edit_cart.h\ + edit_macro.cpp edit_macro.h\ + edit_notes.cpp edit_notes.h\ + edit_schedulercodes.cpp edit_schedulercodes.h\ + filter.cpp filter.h\ + globals.h\ + lib_listview.cpp lib_listview.h\ + list_reports.cpp list_reports.h\ + macro_cart.cpp macro_cart.h\ + rdlibrary.cpp rdlibrary.h\ + record_cut.cpp record_cut.h\ + validate_cut.cpp validate_cut.h + +nodist_rdlibrary_SOURCES = moc_audio_cart.cpp\ + moc_cdripper.cpp\ + moc_disk_gauge.cpp\ + moc_disk_ripper.cpp\ + moc_edit_cart.cpp\ + moc_edit_macro.cpp\ + moc_edit_notes.cpp\ + moc_edit_schedulercodes.cpp \ + moc_filter.cpp\ + moc_lib_listview.cpp\ + moc_list_reports.cpp\ + moc_macro_cart.cpp\ + moc_rdlibrary.cpp\ + moc_record_cut.cpp + +rdlibrary_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdlibrary.pro\ + rdlibrary_cs.ts\ + rdlibrary_de.ts\ + rdlibrary_es.ts\ + rdlibrary_fr.ts\ + rdlibrary_nb.ts\ + rdlibrary_nn.ts\ + rdlibrary_pt_BR.ts + +CLEANFILES = *~\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/rdlibrary/audio_cart.cpp b/rdlibrary/audio_cart.cpp new file mode 100644 index 00000000..8100d98d --- /dev/null +++ b/rdlibrary/audio_cart.cpp @@ -0,0 +1,894 @@ +// audio_cart.cpp +// +// The audio cart editor for RDLibrary. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: audio_cart.cpp,v 1.57.6.9.2.2 2014/05/22 14:30:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +bool import_active=false; + + +AudioCart::AudioCart(AudioControls *controls,RDCart *cart,QString *path, + bool select_cut,bool profile_rip, + QWidget *parent,const char *name) + : QWidget(parent,name) +{ + rdcart_import_metadata=true; + rdcart_controls=controls; + rdcart_cart=cart; + rdcart_import_path=path; + rdcart_select_cut=select_cut; + rdcart_profile_rip=profile_rip; + rdcart_modification_allowed=lib_user->editAudio()&&cart->owner().isEmpty(); + + setCaption(QString().sprintf("%u",rdcart_cart->number())+" - "+ + rdcart_cart->title()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont line_edit_font=QFont("Helvetica",12,QFont::Normal); + line_edit_font.setPixelSize(12); + + // + // Progress Dialog + // + rdcart_progress_dialog=new QProgressDialog(this); + rdcart_progress_dialog->setLabelText(tr("Copying audio...")); + rdcart_progress_dialog->setCancelButton(NULL); + rdcart_progress_dialog->setTotalSteps(10); + rdcart_progress_dialog->setMinimumDuration(1000); + + // + // Add Cut Button + // + QPushButton *add_cut_button=new QPushButton(this,"add_cut_button"); + add_cut_button->setGeometry(10,0,80,50); + add_cut_button->setFont(button_font); + add_cut_button->setText(tr("Add")); + connect(add_cut_button,SIGNAL(clicked()),this,SLOT(addCutData())); + + // + // Delete Cut Button + // + QPushButton *delete_cut_button=new QPushButton(this,"delete_cut_button"); + delete_cut_button->setGeometry(10,60,80,50); + delete_cut_button->setFont(button_font); + delete_cut_button->setText(tr("Delete")); + connect(delete_cut_button,SIGNAL(clicked()),this,SLOT(deleteCutData())); + + // + // Copy Cut Button + // + QPushButton *copy_cut_button=new QPushButton(this,"copy_cut_button"); + copy_cut_button->setGeometry(10,120,80,50); + copy_cut_button->setFont(button_font); + copy_cut_button->setText(tr("Copy")); + connect(copy_cut_button,SIGNAL(clicked()),this,SLOT(copyCutData())); + + // + // Paste Cut Button + // + paste_cut_button=new QPushButton(this,"paste_cut_button"); + paste_cut_button->setGeometry(10,180,80,50); + paste_cut_button->setFont(button_font); + paste_cut_button->setText(tr("Paste")); + connect(paste_cut_button,SIGNAL(clicked()),this,SLOT(pasteCutData())); + + // + // Cart Cut List + // + rdcart_cut_list=new RDListView(this,"rdcart_cut_list"); + rdcart_cut_list->setGeometry(100,0,430,sizeHint().height()); + rdcart_cut_list->setAllColumnsShowFocus(true); + rdcart_cut_list->setSelectionMode(QListView::Extended); + rdcart_cut_list->setItemMargin(5); + rdcart_cut_list->setSorting(11); + connect(rdcart_cut_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + rdcart_cut_list->addColumn(tr("WT")); + rdcart_cut_list->setColumnAlignment(0,Qt::AlignHCenter); + + rdcart_cut_list->addColumn(tr("DESCRIPTION")); + rdcart_cut_list->setColumnAlignment(1,Qt::AlignLeft); + + rdcart_cut_list->addColumn(tr("LENGTH")); + rdcart_cut_list->setColumnAlignment(2,Qt::AlignRight); + rdcart_cut_list->setColumnSortType(2,RDListView::TimeSort); + + rdcart_cut_list->addColumn(tr("LAST PLAYED")); + rdcart_cut_list->setColumnAlignment(3,Qt::AlignHCenter); + + rdcart_cut_list->addColumn(tr("# OF PLAYS")); + rdcart_cut_list->setColumnAlignment(4,Qt::AlignHCenter); + + rdcart_cut_list->addColumn(tr("ORIGIN")); + rdcart_cut_list->setColumnAlignment(5,Qt::AlignHCenter); + + rdcart_cut_list->addColumn(tr("OUTCUE")); + rdcart_cut_list->setColumnAlignment(6,Qt::AlignLeft); + + rdcart_cut_list->addColumn(tr("START DATE")); + rdcart_cut_list->setColumnAlignment(7,Qt::AlignLeft); + + rdcart_cut_list->addColumn(tr("END DATE")); + rdcart_cut_list->setColumnAlignment(8,Qt::AlignLeft); + + rdcart_cut_list->addColumn(tr("DAYPART START")); + rdcart_cut_list->setColumnAlignment(9,Qt::AlignLeft); + + rdcart_cut_list->addColumn(tr("DAYPART END")); + rdcart_cut_list->setColumnAlignment(10,Qt::AlignLeft); + + rdcart_cut_list->addColumn(tr("NAME")); + rdcart_cut_list->setColumnAlignment(11,Qt::AlignLeft); + + RefreshList(); + + // + // Record Cut Button + // + QPixmap *pix=new QPixmap(QSize(80,50)); + QPainter *p=new QPainter(pix); + QFontMetrics *m=new QFontMetrics(button_font); + p->fillRect(0,0,80,50,palette().color(QPalette::Active,QColorGroup::Button)); + p->setPen(QColor(color1)); + p->setFont(button_font); + p->drawText((80-m->width(tr("Cut Info")))/2,20,tr("Cut Info")); + p->moveTo(10,24); + p->lineTo(70,24); + p->drawText((80-m->width(tr("Record")))/2,38,tr("Record")); + p->end(); + QPushButton *record_cut_button=new QPushButton(this,"record_cut_button"); + record_cut_button->setGeometry(550,0,80,50); + record_cut_button->setPixmap(*pix); + connect(record_cut_button,SIGNAL(clicked()),this,SLOT(recordCutData())); + + // + // Send to (external) Editor Button (ex: Audacity) + // + QPushButton *ext_editor_cut_button= + new QPushButton(this,"ext_editor_cut_button"); + ext_editor_cut_button->setGeometry(550,60,80,50); + ext_editor_cut_button->setFont(button_font); + ext_editor_cut_button->setText(tr("Edit\nAudio")); + connect(ext_editor_cut_button,SIGNAL(clicked()), + this,SLOT(extEditorCutData())); + int yoffset=60; + if((!rdlibrary_conf->enableEditor())|| + rdstation_conf->editorPath().isEmpty()) { + ext_editor_cut_button->hide(); + yoffset=0; + } + + // + // Edit Cut Button + // + QPushButton *edit_cut_button=new QPushButton(this,"edit_cut_button"); + edit_cut_button->setGeometry(550,60+yoffset,80,50); + edit_cut_button->setFont(button_font); + edit_cut_button->setText(tr("Edit\nMarkers")); + connect(edit_cut_button,SIGNAL(clicked()),this,SLOT(editCutData())); + + // + // Import Cut Button + // + p=new QPainter(pix); + m=new QFontMetrics(button_font); + p->fillRect(0,0,80,50,palette().color(QPalette::Active,QColorGroup::Button)); + p->setPen(QColor(color1)); + p->setFont(button_font); + p->drawText((80-m->width(tr("Import")))/2,20,tr("Import")); + p->moveTo(10,24); + p->lineTo(70,24); + p->drawText((80-m->width(tr("Export")))/2,38,tr("Export")); + p->end(); + QPushButton *import_cut_button=new QPushButton(this,"import_cut_button"); + import_cut_button->setPixmap(*pix); + import_cut_button->setGeometry(550,120+yoffset,80,50); + connect(import_cut_button,SIGNAL(clicked()),this,SLOT(importCutData())); + + // + // Rip Cut Button + // + QPushButton *rip_cut_button=new QPushButton(this,"rip_cut_button"); + rip_cut_button->setGeometry(550,180+yoffset,80,50); + rip_cut_button->setFont(button_font); + rip_cut_button->setText(tr("Rip CD")); + connect(rip_cut_button,SIGNAL(clicked()),this,SLOT(ripCutData())); + + // + // Set Control Perms + // + add_cut_button->setEnabled(rdcart_modification_allowed); + delete_cut_button->setEnabled(rdcart_modification_allowed); + if((cut_clipboard==NULL)||(!rdcart_modification_allowed)) { + paste_cut_button->setDisabled(true); + } + rip_cut_button->setEnabled(rdcart_modification_allowed); + import_cut_button->setEnabled(rdcart_modification_allowed); + ext_editor_cut_button->setEnabled(rdcart_modification_allowed); +} + + +QSize AudioCart::sizeHint() const +{ + return QSize(640,290); +} + + +QSizePolicy AudioCart::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AudioCart::addCutData() +{ + QString next_name=RDCut::cutName(rdcart_cart->number(), + rdcart_cart->addCut(rdlibrary_conf->defaultFormat(), + rdlibrary_conf->defaultBitrate(), + rdlibrary_conf->defaultChannels())); + if(next_name.isEmpty()) { + QMessageBox::warning(this,tr("RDLibrary - Edit Cart"), + tr("This cart cannot contain any additional cuts!")); + return; + } + rdcart_cut_list->clearSelection(); + RDListViewItem *item=new RDListViewItem(rdcart_cut_list); + item->setText(11,next_name); + // UpdateCutCount(); + RefreshLine(item); + rdcart_cut_list->setSelected(item,true); + rdcart_cut_list->ensureItemVisible(item); + disk_gauge->update(); + emit cartDataChanged(); +} + + +void AudioCart::deleteCutData() +{ + QString filename; + QString str; + std::vector cutnames; + RDListViewItem *item=NULL; + + item=SelectedCuts(&cutnames); + if(cutnames.size()==0) { + return; + } + + // + // Prompt for Deletion + // + if(cutnames.size()==1) { + switch(QMessageBox::question(this,"RDLibrary - "+tr("Delete Cut"), + tr("Are you sure you want to delete")+" \""+ + item->text(1)+"\"?", + QMessageBox::Yes,QMessageBox::No)) { + + case QMessageBox::No: + case QMessageBox::NoButton: + return; + + default: + break; + } + } + else { + if(QMessageBox::question(this,"RDLibrary - "+tr("Delete Cuts"), + tr("Are you sure you want to delete")+ + QString().sprintf(" %lu ",cutnames.size())+ + tr("cuts")+"?",QMessageBox::Yes, + QMessageBox::No)!=QMessageBox::Yes) { + return; + } + } + + // + // Check for RDCatch Events + // + for(unsigned i=0;ifirst()) { + if(QMessageBox::warning(this,tr("RDCatch Event Exists"), + tr("One or more cuts are used in one or more RDCatch events!\nDo you still want to delete?"),QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) { + delete q; + return; + } + } + delete q; + } + + // + // Check Clipboard + // + if(cut_clipboard!=NULL) { + if(item->text(11)==cut_clipboard->cutName()) { + if(QMessageBox::question(this,tr("Empty Clipboard"), + tr("Deleting this cut will also empty the clipboard.\nDo you still want to proceed?"),QMessageBox::Yes,QMessageBox::No)== + QMessageBox::No) { + return; + } + delete cut_clipboard; + cut_clipboard=NULL; + paste_cut_button->setDisabled(true); + } + } + + // + // Delete Cuts + // + for(unsigned i=0;iremoveCut(rdstation_conf,lib_user,cutnames[i], + lib_config)) { + QMessageBox::warning(this,tr("RDLibrary"), + tr("Unable to delete audio for cut")+ + QString().sprintf(" %d!",RDCut::cutNumber(cutnames[i]))); + return; + } + } + // UpdateCutCount(); + + rdcart_cart->updateLength(rdcart_controls->enforce_length_box->isChecked(), + QTime().msecsTo(rdcart_controls-> + forced_length_edit->time())); + rdcart_cart->resetRotation(); + disk_gauge->update(); + + // + // Update List + // + item=(RDListViewItem *)rdcart_cut_list->firstChild(); + while(item!=NULL) { + RDListViewItem *del=NULL; + if(item->isSelected()) { + del=item; + } + item=(RDListViewItem *)item->nextSibling(); + if(del!=NULL) { + delete del; + } + } + + emit cartDataChanged(); +} + + +void AudioCart::copyCutData() +{ + std::vector cutnames; + RDListViewItem *item=NULL; + + if((item=SelectedCuts(&cutnames))==NULL) { + QMessageBox::information(this,"RDLibrary - "+tr("Copy Cut"), + tr("No data copied - you must select a single cut!")); + return; + } + if(cut_clipboard!=NULL) { + delete cut_clipboard; + } + cut_clipboard=new RDCut(item->text(11)); + paste_cut_button->setEnabled(rdcart_modification_allowed); +} + + +void AudioCart::extEditorCutData() +{ + std::vector cutnames; + RDListViewItem *item=NULL; + + if((item=SelectedCuts(&cutnames))==NULL) { + return; + } + + QString cmd=rdstation_conf->editorPath(); + cmd.replace("%f",RDCut::pathName(rdcart_cut_list->currentItem()->text(11))); + // FIXME: other replace commands to match: lib/rdcart_dialog.cpp editorData() + // These substitions should be documented (maybe a text file), + // ex: %f = cart_cut filename + // and possibly also add some tooltips with help advice + + if(fork()==0) { + system(cmd+" &"); + exit(0); + } +} + +void AudioCart::pasteCutData() +{ + std::vector cutnames; + RDListViewItem *item=NULL; + + if((item=SelectedCuts(&cutnames))==NULL) { + QMessageBox::information(this,"RDLibrary - "+tr("Paste Cut"), + tr("You must select a single cut!")); + return; + } + if(!cut_clipboard->exists()) { + QMessageBox::information(this,tr("Clipboard Empty"), + tr("Clipboard is currently empty.")); + delete cut_clipboard; + cut_clipboard=NULL; + paste_cut_button->setDisabled(true); + return; + } + if(QFile::exists(RDCut::pathName(item->text(11)))) { + if(QMessageBox::warning(this,tr("Audio Exists"), + tr("This will overwrite the existing recording.\nDo you want to proceed?"), + QMessageBox::Yes, + QMessageBox::No)==QMessageBox::No) { + return; + } + } + cut_clipboard->connect(this,SLOT(copyProgressData(const QVariant &))); + cut_clipboard->copyTo(rdstation_conf,lib_user,item->text(11),lib_config); + cut_clipboard->disconnect(this,SLOT(copyProgressData(const QVariant &))); + rdcart_cart->updateLength(rdcart_controls->enforce_length_box->isChecked(), + QTime().msecsTo(rdcart_controls-> + forced_length_edit->time())); + rdcart_cart->resetRotation(); + disk_gauge->update(); + emit cartDataChanged(); + RefreshList(); +} + + +void AudioCart::editCutData() +{ + RDListViewItem *item=NULL; + std::vector cutnames; + if((item=SelectedCuts(&cutnames))==NULL) { + return; + } + QString cutname=item->text(11); + if(!RDAudioExists(cutname)) { + QMessageBox::information(this,"RDLibrary", + tr("No audio is present in the cut!")); + return; + } + RDEditAudio *edit= + new RDEditAudio(rdcart_cart,cutname,rdcae,lib_user,rdstation_conf, + lib_config,rdlibrary_conf->outputCard(), + rdlibrary_conf->outputPort(),rdlibrary_conf->tailPreroll(), + rdlibrary_conf->trimThreshold(),this); + if(edit->exec()!=-1) { + emit cartDataChanged(); + rdcart_cart->updateLength(rdcart_controls->enforce_length_box->isChecked(), + QTime().msecsTo(rdcart_controls-> + forced_length_edit->time())); + RefreshLine(item); + } + delete edit; +} + + +void AudioCart::recordCutData() +{ + RDListViewItem *item=NULL; + std::vector cutnames; + if((item=SelectedCuts(&cutnames))==NULL) { + return; + } + QString cutname=item->text(11); + RecordCut *cut=new RecordCut(rdcart_cart,cutname,this,"cut"); + cut->exec(); + delete cut; + if(cut_clipboard==NULL) { + paste_cut_button->setDisabled(true); + } + disk_gauge->update(); + emit cartDataChanged(); + rdcart_cart->updateLength(rdcart_controls->enforce_length_box->isChecked(), + QTime().msecsTo(rdcart_controls-> + forced_length_edit->time())); + RefreshLine(item); +} + + +void AudioCart::ripCutData() +{ + int track; + QString cutname; + QString title; + QString artist; + QString album; + + RDListViewItem *item=NULL; + std::vector cutnames; + if((item=SelectedCuts(&cutnames))==NULL) { + return; + } + cutname=item->text(11); + RDCddbRecord *rec=new RDCddbRecord(); + CdRipper *ripper=new CdRipper(cutname,rec,rdlibrary_conf,rdcart_profile_rip); + if((track=ripper->exec(&title,&artist,&album))>=0) { + if((rdcart_controls->title_edit->text().isEmpty()|| + (rdcart_controls->title_edit->text()==tr("[new cart]")))&& + (!title.isEmpty())) { + rdcart_controls->title_edit->setText(title); + } + rdcart_controls->artist_edit->setText(artist); + rdcart_controls->album_edit->setText(album); + RDCut *cut=new RDCut(cutname); + cut->setIsrc(rec->isrc(track)); + delete cut; + } + if(cut_clipboard==NULL) { + paste_cut_button->setDisabled(true); + } + emit cartDataChanged(); + delete ripper; + delete rec; + disk_gauge->update(); + rdcart_cart->updateLength(rdcart_controls->enforce_length_box->isChecked(), + QTime().msecsTo(rdcart_controls-> + forced_length_edit->time())); + RefreshLine(item); +} + + +void AudioCart::importCutData() +{ + QString cutname; + RDWaveData wavedata; + RDListViewItem *item=NULL; + std::vector cutnames; + if((item=SelectedCuts(&cutnames))==NULL) { + return; + } + cutname=item->text(11); + RDSettings settings; + rdlibrary_conf->getSettings(&settings); + RDImportAudio *import=new RDImportAudio(cutname,rdcart_import_path, + &settings,&rdcart_import_metadata, + &wavedata,cut_clipboard, + rdstation_conf,lib_user, + &import_active,lib_config); + import->enableAutotrim(rdlibrary_conf->defaultTrimState()); + import->setAutotrimLevel(rdlibrary_conf->trimThreshold()); + import->enableNormalization(rdlibrary_conf->ripperLevel()!=0); + import->setNormalizationLevel(rdlibrary_conf->ripperLevel()); + if(import->exec(true,true)==0) { + if(rdcart_controls->title_edit->text().isEmpty()|| + (rdcart_controls->title_edit->text()==tr("[new cart]"))) { + rdcart_controls->title_edit->setText(wavedata.title()); + } + if(rdcart_controls->artist_edit->text().isEmpty()) { + rdcart_controls->artist_edit->setText(wavedata.artist()); + } + if(rdcart_controls->album_edit->text().isEmpty()) { + rdcart_controls->album_edit->setText(wavedata.album()); + } + + if(rdcart_controls->year_edit->text().isEmpty()&& + wavedata.releaseYear()>0) { + rdcart_controls->year_edit-> + setText(QString().sprintf("%d",wavedata.releaseYear())); + } + if(rdcart_controls->label_edit->text().isEmpty()) { + rdcart_controls->label_edit->setText(wavedata.label()); + } + if(rdcart_controls->client_edit->text().isEmpty()) { + rdcart_controls->client_edit->setText(wavedata.client()); + } + if(rdcart_controls->agency_edit->text().isEmpty()) { + rdcart_controls->agency_edit->setText(wavedata.agency()); + } + if(rdcart_controls->publisher_edit->text().isEmpty()) { + rdcart_controls->publisher_edit->setText(wavedata.publisher()); + } + if(rdcart_controls->composer_edit->text().isEmpty()) { + rdcart_controls->composer_edit->setText(wavedata.composer()); + } + if(rdcart_controls->user_defined_edit->text().isEmpty()) { + rdcart_controls->user_defined_edit->setText(wavedata.userDefined()); + } + RDCut *cut=new RDCut(cutname); + cut->setMetadata(&wavedata); + delete cut; + } + if(cut_clipboard==NULL) { + paste_cut_button->setDisabled(true); + } + emit cartDataChanged(); + delete import; + disk_gauge->update(); + rdcart_cart->updateLength(rdcart_controls->enforce_length_box->isChecked(), + QTime().msecsTo(rdcart_controls-> + forced_length_edit->time())); + RefreshLine(item); +} + + +void AudioCart::doubleClickedData(QListViewItem *,const QPoint &,int) +{ + recordCutData(); +} + + +void AudioCart::copyProgressData(const QVariant &step) +{ + rdcart_progress_dialog->setProgress(step.toInt()); + qApp->processEvents(); +} + + +RDListViewItem *AudioCart::SelectedCuts(std::vector *cutnames) +{ + RDListViewItem *ret=NULL; + RDListViewItem *item=(RDListViewItem *)rdcart_cut_list->firstChild(); + while(item!=NULL) { + if(item->isSelected()) { + cutnames->push_back(item->text(11)); + ret=item; + } + item=(RDListViewItem *)item->nextSibling(); + } + if(cutnames->size()==1) { + return ret; + } + return NULL; +} + + +void AudioCart::RefreshList() +{ + RDSqlQuery *q; + QString sql; + RDListViewItem *l; + unsigned total_length=0; + QDateTime current_datetime= + QDateTime(QDate::currentDate(),QTime::currentTime()); + int pass=0; + bool err=false; + + rdcart_cut_list->clear(); + sql=ValidateCutFields()+ + QString().sprintf(" where CART_NUMBER=%u",rdcart_cart->number()); + q=new RDSqlQuery(sql); + while(q->next()) { + l=new RDListViewItem(rdcart_cut_list); + l->setText(0,q->value(0).toString()); + l->setText(1,q->value(1).toString()); + l->setText(2,RDGetTimeLength(q->value(2).toUInt())); + if (q->value(0) == 0){// zero weight + l->setBackgroundColor(RD_CART_ERROR_COLOR); + if(pass==0) { + err=true; + } + } else { + switch(ValidateCut(q,9,RDCart::NeverValid,current_datetime)) { + case RDCart::NeverValid: + l->setBackgroundColor(RD_CART_ERROR_COLOR); + if(pass==0) { + err=true; + } + break; + + case RDCart::ConditionallyValid: + if((!q->value(10).isNull())&& + (q->value(10).toDateTime()setBackgroundColor(RD_CART_ERROR_COLOR); + } + else { + l->setBackgroundColor(RD_CART_CONDITIONAL_COLOR); + } + if(pass==0) { + err=true; + } + break; + + case RDCart::FutureValid: + l->setBackgroundColor(RD_CART_FUTURE_COLOR); + if(pass==0) { + err=true; + } + break; + + case RDCart::EvergreenValid: + l->setBackgroundColor(RD_CART_EVERGREEN_COLOR); + if(pass==0) { + err=true; + } + break; + + case RDCart::AlwaysValid: + break; + } + } + if(q->value(4).toUInt()>0) { + l->setText(3,q->value(3).toDateTime().toString("M/d/yy")); + } + else { + l->setText(3,tr("Never")); + } + l->setText(4,q->value(4).toString()); + if(!q->value(5).toDateTime().isNull()) { + l->setText(5,q->value(6).toString()+" - "+ + q->value(5).toDateTime().toString("M/d/yy hh:mm:ss")); + } + l->setText(6,q->value(7).toString()); + if(!q->value(11).toDateTime().isNull()) { + l->setText(7,q->value(11).toDateTime().toString("M/d/yyyy hh:mm:ss")); + } + else { + l->setText(7,tr("None")); + } + if(!q->value(12).toDateTime().isNull()) { + l->setText(8,q->value(12).toDateTime().toString("M/d/yyyy hh:mm:ss")); + } + else { + l->setText(8,tr("None")); + } + if(!q->value(14).isNull()) { + l->setText(9,q->value(13).toTime().toString("hh:mm:ss")); + l->setText(10,q->value(14).toTime().toString("hh:mm:ss")); + } + else { + l->setText(9,tr("None")); + l->setText(10,tr("None")); + } + l->setText(11,q->value(8).toString()); + total_length+=q->value(2).toUInt(); + pass++; + } + if(q->size()>0) { + rdcart_average_length=total_length/q->size(); + } + else { + rdcart_average_length=0; + } + delete q; + if(((l=(RDListViewItem *)rdcart_cut_list->firstChild())!=NULL)&& + ((!err)||rdcart_select_cut)) { + rdcart_cut_list->setSelected(l,true); + rdcart_select_cut=false; + } +} + + +void AudioCart::RefreshLine(RDListViewItem *item) +{ + QString sql; + unsigned total_length=0; + QDateTime current_datetime= + QDateTime(QDate::currentDate(),QTime::currentTime()); + QString cut_name=item->text(11); + sql=ValidateCutFields()+ + QString().sprintf(" where (CART_NUMBER=%u)&&",rdcart_cart->number())+ + "(CUT_NAME=\""+RDEscapeString(cut_name)+"\")"; + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + item->setText(0,q->value(0).toString()); + item->setText(1,q->value(1).toString()); + item->setText(2,RDGetTimeLength(q->value(2).toUInt())); + if (q->value(0) == 0){ //zero weight + item->setBackgroundColor(RD_CART_ERROR_COLOR); + } else { + switch(ValidateCut(q,9,RDCart::NeverValid,current_datetime)) { + case RDCart::NeverValid: + item->setBackgroundColor(RD_CART_ERROR_COLOR); + break; + + case RDCart::ConditionallyValid: + if((!q->value(11).isNull())&& + (q->value(11).toDateTime()setBackgroundColor(RD_CART_ERROR_COLOR); + } + else { + item->setBackgroundColor(RD_CART_CONDITIONAL_COLOR); + } + break; + + case RDCart::FutureValid: + item->setBackgroundColor(RD_CART_FUTURE_COLOR); + break; + + case RDCart::EvergreenValid: + item->setBackgroundColor(RD_CART_EVERGREEN_COLOR); + break; + + case RDCart::AlwaysValid: + item->setBackgroundColor(backgroundColor()); + break; + } + } + if(q->value(4).toUInt()>0) { + item->setText(3,q->value(3).toDateTime().toString("M/d/yy")); + } + else { + item->setText(3,tr("Never")); + } + item->setText(4,q->value(4).toString()); + if(!q->value(5).toDateTime().isNull()) { + item->setText(5,q->value(6).toString()+" - "+ + q->value(5).toDateTime().toString("M/d/yy hh:mm:ss")); + } + item->setText(6,q->value(7).toString()); + if(!q->value(11).toDateTime().isNull()) { + item->setText(7,q->value(11).toDateTime().toString("M/d/yyyy hh:mm:ss")); + } + else { + item->setText(7,tr("None")); + } + if(!q->value(12).toDateTime().isNull()) { + item->setText(8,q->value(12).toDateTime().toString("M/d/yyyy hh:mm:ss")); + } + else { + item->setText(8,tr("None")); + } + if(!q->value(14).isNull()) { + item->setText(9,q->value(13).toTime().toString("hh:mm:ss")); + item->setText(10,q->value(14).toTime().toString("hh:mm:ss")); + } + else { + item->setText(9,tr("None")); + item->setText(10,tr("None")); + } + item->setText(11,q->value(8).toString()); + total_length+=q->value(2).toUInt(); + } + if(q->size()>0) { + rdcart_average_length=total_length/q->size(); + } + else { + rdcart_average_length=0; + } + delete q; +} diff --git a/rdlibrary/audio_cart.h b/rdlibrary/audio_cart.h new file mode 100644 index 00000000..d4891e6d --- /dev/null +++ b/rdlibrary/audio_cart.h @@ -0,0 +1,102 @@ +// audio_cart.h +// +// The audio cart editor for RDLibrary. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: audio_cart.h,v 1.19.8.2.2.1 2014/03/19 22:12:58 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef AUDIO_CART_H +#define AUDIO_CART_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern bool import_active; + +class AudioCart : public QWidget +{ + Q_OBJECT + public: + AudioCart(AudioControls *controls,RDCart *cart,QString *path,bool select_cut, + bool profile_rip,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addCutData(); + void deleteCutData(); + void copyCutData(); + void pasteCutData(); + void editCutData(); + void recordCutData(); + void ripCutData(); + void importCutData(); + + /** + * fork() a child process and start an external audio application to open a + * cut of audio. + **/ + void extEditorCutData(); + void doubleClickedData(QListViewItem *,const QPoint &,int); + void copyProgressData(const QVariant &step); + + signals: + void cartDataChanged(); + void audioChanged(); + + private: + RDListViewItem *SelectedCuts(std::vector *cutnames); + void RefreshList(); + void RefreshLine(RDListViewItem *item); + unsigned NextCut(); + RDCart *rdcart_cart; + RDListView *rdcart_cut_list; + unsigned rdcart_average_length; + QString *rdcart_import_path; + bool rdcart_select_cut; + AudioControls *rdcart_controls; + QPushButton *paste_cut_button; + QProgressDialog *rdcart_progress_dialog; + bool rdcart_modification_allowed; + bool rdcart_import_metadata; + bool rdcart_profile_rip; +}; + + +#endif + diff --git a/rdlibrary/audio_controls.h b/rdlibrary/audio_controls.h new file mode 100644 index 00000000..e092d68a --- /dev/null +++ b/rdlibrary/audio_controls.h @@ -0,0 +1,55 @@ +// audio_controls.h +// +// A Container Class for RDLibrary Cart Label Controls +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: audio_controls.h,v 1.6.8.1 2013/12/11 18:51:48 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef AUDIO_CONTROLS_H +#define AUDIO_CONTROLS_H + +#include +#include +#include +#include + +#include + +class AudioControls +{ + public: + QCheckBox *enforce_length_box; + RDTimeEdit *forced_length_edit; + QLineEdit *song_id_edit; + QSpinBox *bpm_spin; + QLineEdit *title_edit; + QLineEdit *artist_edit; + QLineEdit *album_edit; + QLineEdit *year_edit; + QLineEdit *label_edit; + QLineEdit *client_edit; + QLineEdit *agency_edit; + QLineEdit *publisher_edit; + QLineEdit *conductor_edit; + QLineEdit *composer_edit; + QLineEdit *user_defined_edit; +}; + + +#endif // AUDIO_CONTROLS_H + diff --git a/rdlibrary/cart_tip.cpp b/rdlibrary/cart_tip.cpp new file mode 100644 index 00000000..bc6d7e20 --- /dev/null +++ b/rdlibrary/cart_tip.cpp @@ -0,0 +1,46 @@ +// cart_tip.cpp +// +// Custom ToolTip for RDLibrary's Cart List +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: cart_tip.cpp,v 1.2 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +CartTip::CartTip(QWidget *widget,QToolTipGroup *group) + : QToolTip(widget,group) +{ +} + + +void CartTip::setCartNumber(const QRect &item_rect,unsigned cartnum) +{ + RDCart *cart=new RDCart(cartnum); + tip_notes=cart->notes(); + delete cart; + tip_item_rect=item_rect; + tip_cart_number=cartnum; +} + + +void CartTip::maybeTip(const QPoint &pt) +{ + tip(tip_item_rect,tip_notes); +} diff --git a/rdlibrary/cart_tip.h b/rdlibrary/cart_tip.h new file mode 100644 index 00000000..9091d554 --- /dev/null +++ b/rdlibrary/cart_tip.h @@ -0,0 +1,43 @@ +// cart_tip.h +// +// Custom ToolTip for RDLibrary's Cart List +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: cart_tip.h,v 1.2 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef CART_TIP_H +#define CART_TIP_H + +#include + +class CartTip : public QToolTip +{ + public: + CartTip(QWidget *widget,QToolTipGroup *group=0); + void setCartNumber(const QRect &item_rect,unsigned cartnum); + + protected: + void maybeTip(const QPoint &pt); + + private: + unsigned tip_cart_number; + QRect tip_item_rect; + QString tip_notes; +}; + +#endif // CART_TIP_H diff --git a/rdlibrary/cdripper.cpp b/rdlibrary/cdripper.cpp new file mode 100644 index 00000000..ca8ff372 --- /dev/null +++ b/rdlibrary/cdripper.cpp @@ -0,0 +1,740 @@ +// cdripper.cpp +// +// CD Ripper Dialog for Rivendell. +// +// (C) Copyright 2002-2003, 2009 Fred Gleason +// +// $Id: cdripper.cpp,v 1.41.4.6.2.2 2014/05/20 15:45:08 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// +// Global Variables +// +bool ripper_running; + + +CdRipper::CdRipper(QString cutname,RDCddbRecord *rec,RDLibraryConf *conf, + bool profile_rip,QWidget *parent,const char *name) + : QDialog(parent,name) +{ + rip_profile_rip=profile_rip; + rip_isrc_read=false; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + rip_conf=conf; + rip_cddb_record=rec; + rip_track[0]=-1; + rip_track[1]=-1; + rip_title=NULL; + + setCaption("Rip CD"); + + // + // Create Temporary Directory + // + char path[PATH_MAX]; + strncpy(path,RIPPER_TEMP_DIR,PATH_MAX); + strcat(path,"/XXXXXX"); + if(mkdtemp(path)==NULL) { + QMessageBox::warning(this,"RDLibrary - "+tr("Ripper Error"), + tr("Unable to create temporary directory!")); + } + else { + rip_cdda_dir.setPath(path); + } + + // + // Target Cut + // + rip_cut=new RDCut(cutname); + + // + // The CDROM Drive + // + if(rip_profile_rip) { + rip_cdrom=new RDCdPlayer(stdout,this); + } + else { + rip_cdrom=new RDCdPlayer(NULL,this); + } + connect(rip_cdrom,SIGNAL(ejected()),this,SLOT(ejectedData())); + connect(rip_cdrom,SIGNAL(mediaChanged()),this,SLOT(mediaChangedData())); + connect(rip_cdrom,SIGNAL(played(int)),this,SLOT(playedData(int))); + connect(rip_cdrom,SIGNAL(stopped()),this,SLOT(stoppedData())); + rip_cdrom->setDevice(rip_conf->ripperDevice()); + rip_cdrom->open(); + + // + // CDDB Stuff + // + if(rip_profile_rip) { + rip_cddb_lookup=new RDCddbLookup(stdout,this,"rip_cddb_lookup"); + } + else { + rip_cddb_lookup=new RDCddbLookup(NULL,this,"rip_cddb_lookup"); + } + connect(rip_cddb_lookup,SIGNAL(done(RDCddbLookup::Result)), + this,SLOT(cddbDoneData(RDCddbLookup::Result))); + + // + // Title Selector + // + rip_title_label=new QLabel(tr("Title:"),this); + rip_title_label->setFont(label_font); + rip_title_label->setAlignment(AlignRight|AlignVCenter); + rip_title_box=new QComboBox(this); + rip_title_box->insertItem(tr("[none]")); + + // + // Artist Label + // + rip_artist_label=new QLabel(tr("Artist:"),this); + rip_artist_label->setFont(label_font); + rip_artist_label->setAlignment(AlignRight|AlignVCenter); + rip_artist_edit=new QLineEdit(this,"rip_artist_edit"); + + // + // Album Edit + // + rip_album_label=new QLabel(tr("Album:"),this); + rip_album_label->setFont(label_font); + rip_album_label->setAlignment(AlignRight|AlignVCenter); + rip_album_edit=new QLineEdit(this,"rip_album_edit"); + + // + // Other Edit + // + rip_other_label=new QLabel(tr("Other:"),this); + rip_other_label->setFont(label_font); + rip_other_label->setAlignment(AlignRight); + rip_other_edit=new QTextEdit(this,"rip_other_edit"); + rip_other_edit->setReadOnly(true); + + // + // Apply FreeDB Check Box + // + rip_apply_box=new QCheckBox(this,"rip_apply_box"); + rip_apply_box->setChecked(true); + rip_apply_box->setDisabled(true); + rip_apply_label=new QLabel(rip_apply_box,tr("Apply FreeDB Values to Cart"), + this,"rip_apply_label"); + rip_apply_label->setFont(label_font); + rip_apply_label->setAlignment(AlignLeft); + rip_apply_box->setChecked(false); + rip_apply_label->setDisabled(true); + + // + // Track List + // + rip_track_list=new RDListView(this); + rip_track_list->setAllColumnsShowFocus(true); + rip_track_list->setSelectionMode(QListView::Extended); + rip_track_list->setItemMargin(5); + rip_track_list->setSorting(-1); + connect(rip_track_list,SIGNAL(selectionChanged()), + this,SLOT(trackSelectionChangedData())); + rip_track_label=new QLabel(rip_track_list,tr("Tracks"),this); + rip_track_label->setFont(label_font); + rip_track_list->addColumn(tr("TRACK")); + rip_track_list->setColumnAlignment(0,Qt::AlignHCenter); + rip_track_list->addColumn(tr("LENGTH")); + rip_track_list->setColumnAlignment(1,Qt::AlignRight); + rip_track_list->addColumn(tr("TITLE")); + rip_track_list->setColumnAlignment(2,Qt::AlignLeft); + rip_track_list->addColumn(tr("OTHER")); + rip_track_list->setColumnAlignment(3,Qt::AlignLeft); + rip_track_list->addColumn(tr("TYPE")); + rip_track_list->setColumnAlignment(4,Qt::AlignLeft); + + // + // Progress Bar + // + rip_bar=new QProgressBar(this,"rip_bar"); + + // + // Eject Button + // + rip_eject_button=new RDTransportButton(RDTransportButton::Eject, + this,"close_button"); + connect(rip_eject_button,SIGNAL(clicked()),this,SLOT(ejectButtonData())); + + // + // Play Button + // + rip_play_button=new RDTransportButton(RDTransportButton::Play, + this,"close_button"); + connect(rip_play_button,SIGNAL(clicked()),this,SLOT(playButtonData())); + + // + // Stop Button + // + rip_stop_button=new RDTransportButton(RDTransportButton::Stop, + this,"close_button"); + rip_stop_button->setOnColor(red); + rip_stop_button->on(); + connect(rip_stop_button,SIGNAL(clicked()),this,SLOT(stopButtonData())); + + // + // Rip Track Button + // + rip_rip_button=new QPushButton(tr("&Rip\nTrack"),this,"rip_track_button"); + rip_rip_button->setFont(button_font); + rip_rip_button->setDisabled(true); + connect(rip_rip_button,SIGNAL(clicked()),this,SLOT(ripTrackButtonData())); + + // + // Normalize Check Box + // + rip_normalize_box=new QCheckBox(this); + rip_normalize_box->setChecked(true); + rip_normalize_box_label=new QLabel(rip_normalize_box,tr("Normalize"),this); + rip_normalize_box_label->setFont(label_font); + rip_normalize_box_label->setAlignment(AlignLeft|AlignVCenter); + connect(rip_normalize_box,SIGNAL(toggled(bool)), + this,SLOT(normalizeCheckData(bool))); + + // + // Normalize Level + // + rip_normalize_spin=new QSpinBox(this,"rip_normalize_spin"); + rip_normalize_spin->setRange(-30,0); + rip_normalize_label=new QLabel(rip_normalize_spin,tr("Level:"), + this,"normalize_spin_label"); + rip_normalize_label->setFont(label_font); + rip_normalize_label->setAlignment(AlignRight|AlignVCenter); + rip_normalize_unit=new QLabel(tr("dBFS"),this,"normalize_unit_label"); + rip_normalize_unit->setFont(label_font); + rip_normalize_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Autotrim Check Box + // + rip_autotrim_box=new QCheckBox(this); + rip_autotrim_box->setChecked(true); + rip_autotrim_box_label=new QLabel(rip_autotrim_box,tr("Autotrim"),this); + rip_autotrim_box_label->setFont(label_font); + rip_autotrim_box_label->setAlignment(AlignLeft|AlignVCenter); + connect(rip_autotrim_box,SIGNAL(toggled(bool)), + this,SLOT(autotrimCheckData(bool))); + + // + // Autotrim Level + // + rip_autotrim_spin=new QSpinBox(this,"rip_autotrim_spin"); + rip_autotrim_spin->setRange(-99,0); + rip_autotrim_label=new QLabel(rip_autotrim_spin,tr("Level:"), + this,"autotrim_spin_label"); + rip_autotrim_label->setFont(label_font); + rip_autotrim_label->setAlignment(AlignRight|AlignVCenter); + rip_autotrim_unit=new QLabel(tr("dBFS"),this,"autotrim_unit_label"); + rip_autotrim_unit->setFont(label_font); + rip_autotrim_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Channels + // + rip_channels_box=new QComboBox(this); + rip_channels_label=new QLabel(rip_channels_box,tr("Channels:"),this); + rip_channels_label->setFont(label_font); + rip_channels_label->setAlignment(AlignRight|AlignVCenter); + + // + // Close Button + // + rip_close_button=new QPushButton("&Close",this,"close_button"); + rip_close_button->setFont(button_font); + connect(rip_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Populate Data + // + rip_normalize_spin->setValue(rip_conf->ripperLevel()/100); + rip_autotrim_spin->setValue(rip_conf->trimThreshold()/100); + rip_channels_box->insertItem("1"); + rip_channels_box->insertItem("2"); + rip_channels_box->setCurrentItem(rip_conf->defaultChannels()-1); + rip_done=false; +} + + +CdRipper::~CdRipper() +{ + QStringList files=rip_cdda_dir.entryList(); + for(unsigned i=0;iclose(); + delete rip_cdrom; + delete rip_track_list; + delete rip_rip_button; + delete rip_close_button; + delete rip_eject_button; + delete rip_play_button; + delete rip_stop_button; + delete rip_bar; +} + + +QSize CdRipper::sizeHint() const +{ + return QSize(470,606); +} + + +QSizePolicy CdRipper::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int CdRipper::exec(QString *title,QString *artist,QString *album) +{ + rip_title=title; + rip_artist=artist; + rip_album=album; + return QDialog::exec(); +} + + +void CdRipper::trackSelectionChangedData() +{ + QListViewItem *item=rip_track_list->firstChild(); + QStringList titles; + + while(item!=NULL) { + if(item->isSelected()) { + titles.push_back(item->text(2)); + } + item=item->nextSibling(); + } + rip_title_box->clear(); + switch(titles.size()) { + case 0: + rip_title_box->insertItem(tr("[none]")); + break; + + case 1: + rip_title_box->insertItem(titles[0]); + break; + + default: + rip_title_box->insertItem(titles.join(" / ")); + for(unsigned i=0;iinsertItem(titles[i]); + } + break; + } + rip_rip_button->setEnabled(titles.size()>0); +} + + +void CdRipper::ejectButtonData() +{ + rip_cdrom->eject(); +} + + +void CdRipper::playButtonData() +{ + if(rip_track_list->currentItem()!=NULL) { + rip_cdrom->play(rip_track_list->currentItem()->text(0).toInt()); + rip_play_button->on(); + rip_stop_button->off(); + } +} + + +void CdRipper::stopButtonData() +{ + rip_cdrom->stop(); + rip_play_button->off(); + rip_stop_button->on(); +} + + +void CdRipper::ripTrackButtonData() +{ + RDCdRipper *ripper=NULL; + + rip_done=false; + rip_rip_aborted=false; + if(rip_cut->length()>0) { + switch(QMessageBox::warning(this,tr("Audio Exists"), + tr("This will overwrite the existing recording.\nDo you want to proceed?"), + QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + return; + + default: + break; + } + } + if(cut_clipboard!=NULL) { + if(rip_cut->cutName()==cut_clipboard->cutName()) { + switch(QMessageBox::warning(this,tr("Empty Clipboard"), + tr("Ripping this cut will also empty the clipboard.\nDo you still want to proceed?"), + QMessageBox::Yes, + QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + return; + + default: + break; + } + delete cut_clipboard; + cut_clipboard=NULL; + } + } + rip_eject_button->setDisabled(true); + rip_play_button->setDisabled(true); + rip_stop_button->setDisabled(true); + rip_rip_button->setText(tr("Abort\nRip")); + rip_close_button->setDisabled(true); + + // + // Set Track Title + // + if(rip_apply_box->isChecked()) { + *rip_title=rip_title_box->currentText(); + *rip_artist=rip_artist_edit->text(); + *rip_album=rip_album_edit->text(); + } + + // + // Read ISRCs + // + if(!rip_isrc_read) { + rip_cddb_lookup->readIsrc(rip_cdda_dir.path(),rip_conf->ripperDevice()); + rip_isrc_read=true; + } + + // + // Rip from disc + // + RDAudioImport::ErrorCode conv_err; + RDAudioConvert::ErrorCode audio_conv_err; + RDCdRipper::ErrorCode ripper_err; + QString tmpdir=RDTempDir(); + QString tmpfile=tmpdir+"/"+RIPPER_TEMP_WAV; + if(rip_profile_rip) { + ripper=new RDCdRipper(stdout,this); + } + else { + ripper=new RDCdRipper(NULL,this); + } + disconnect(rip_rip_button,SIGNAL(clicked()),this,SLOT(ripTrackButtonData())); + connect(rip_rip_button,SIGNAL(clicked()),ripper,SLOT(abort())); + rip_bar->setTotalSteps(ripper->totalSteps()+1); + connect(ripper,SIGNAL(progressChanged(int)),rip_bar,SLOT(setProgress(int))); + RDAudioImport *conv=NULL; + RDSettings *settings=NULL; + ripper->setDevice(rip_conf->ripperDevice()); + ripper->setDestinationFile(tmpfile); + + + rip_track[0]=-1; + rip_track[1]=-1; + QListViewItem *item=rip_track_list->firstChild(); + while(item!=NULL) { + if(item->isSelected()) { + if(rip_track[0]<0) { + rip_track[0]=item->text(0).toInt()-1; + } + rip_track[1]=item->text(0).toInt()-1; + } + item=item->nextSibling(); + } + switch((ripper_err=ripper->rip(rip_track[0],rip_track[1]))) { + case RDCdRipper::ErrorOk: + conv=new RDAudioImport(rdstation_conf,lib_config,this); + conv->setSourceFile(tmpfile); + conv->setCartNumber(rip_cut->cartNumber()); + conv->setCutNumber(rip_cut->cutNumber()); + conv->setUseMetadata(false); + settings=new RDSettings(); + if(rdlibrary_conf->defaultFormat()==1) { + settings->setFormat(RDSettings::MpegL2Wav); + } + else { + settings->setFormat(RDSettings::Pcm16); + } + settings->setChannels(rip_channels_box->currentText().toInt()); + settings->setSampleRate(lib_system->sampleRate()); + settings->setBitRate(rdlibrary_conf->defaultBitrate()); + if(rip_normalize_box->isChecked()) { + settings->setNormalizationLevel(rip_normalize_spin->value()); + } + if(rip_autotrim_box->isChecked()) { + settings->setAutotrimLevel(rip_autotrim_spin->value()); + } + conv->setDestinationSettings(settings); + switch((conv_err=conv-> + runImport(lib_user->name(),lib_user->password(),&audio_conv_err))) { + case RDAudioImport::ErrorOk: + QMessageBox::information(this,tr("Rip Complete"),tr("Rip complete!")); + break; + + default: + QMessageBox::warning(this,tr("RDLibrary - Importer Error"), + RDAudioImport::errorText(conv_err,audio_conv_err)); + break; + } + delete settings; + delete conv; + break; + + case RDCdRipper::ErrorNoDevice: + case RDCdRipper::ErrorNoDestination: + case RDCdRipper::ErrorInternal: + case RDCdRipper::ErrorNoDisc: + case RDCdRipper::ErrorNoTrack: + case RDCdRipper::ErrorAborted: + QMessageBox::warning(this,tr("RDLibrary - Ripper Error"), + RDCdRipper::errorText(ripper_err)); + break; + } + delete ripper; + unlink(tmpfile); + rmdir(tmpdir); + rip_bar->setPercentageVisible(false); + rip_bar->reset(); + rip_eject_button->setEnabled(true); + rip_play_button->setEnabled(true); + rip_stop_button->setEnabled(true); + rip_rip_button->setText(tr("Rip Track")); + connect(rip_rip_button,SIGNAL(clicked()),this,SLOT(ripTrackButtonData())); + rip_close_button->setEnabled(true); + rip_cdrom->unlock(); + rip_done=true; + rip_bar->setProgress(0); + rip_bar->setPercentageVisible(true); +} + + +void CdRipper::ejectedData() +{ + rip_track_list->clear(); + rip_artist_edit->clear(); + rip_album_edit->clear(); + rip_other_edit->clear(); + rip_apply_box->setChecked(false); + rip_apply_box->setDisabled(true); + rip_apply_label->setDisabled(true); +} + + +void CdRipper::mediaChangedData() +{ + QListViewItem *l; + + rip_isrc_read=false; + rip_track_list->clear(); + rip_track[0]=-1; + rip_track[1]=-1; + for(int i=rip_cdrom->tracks();i>0;i--) { + l=new QListViewItem(rip_track_list); + l->setText(0,QString().sprintf("%d",i)); + if(rip_cdrom->isAudio(i)) { + l->setText(4,tr("Audio Track")); + } + else { + l->setText(4,tr("Data Track")); + } + l->setText(1,RDGetTimeLength(rip_cdrom->trackLength(i))); + } + rip_cddb_record->clear(); + rip_cdrom->setCddbRecord(rip_cddb_record); + rip_cddb_lookup->setCddbRecord(rip_cddb_record); + Profile("starting metadata lookup"); + rip_cddb_lookup->lookupRecord(rip_cdda_dir.path(),rip_conf->ripperDevice(), + rip_conf->cddbServer(),8880, + RIPPER_CDDB_USER,PACKAGE_NAME,VERSION); + Profile("metadata lookup finished"); +} + + +void CdRipper::playedData(int track) +{ + rip_play_button->on(); + rip_stop_button->off(); +} + + +void CdRipper::stoppedData() +{ + rip_play_button->off(); + rip_stop_button->on(); +} + + +void CdRipper::cddbDoneData(RDCddbLookup::Result result) +{ + switch(result) { + case RDCddbLookup::ExactMatch: + if(rip_cdrom->status()!=RDCdPlayer::Ok) { + return; + } + rip_artist_edit->setText(rip_cddb_record->discArtist()); + rip_album_edit->setText(rip_cddb_record->discAlbum()); + rip_other_edit->setText(rip_cddb_record->discExtended()); + for(int i=0;itracks();i++) { + rip_track_list->findItem(QString().sprintf("%d",i+1),0)-> + setText(2,rip_cddb_record->trackTitle(i)); + rip_track_list->findItem(QString().sprintf("%d",i+1),0)-> + setText(3,rip_cddb_record->trackExtended(i)); + } + rip_apply_box->setChecked(true); + rip_apply_box->setEnabled(true); + rip_apply_label->setEnabled(true); + trackSelectionChangedData(); + break; + + case RDCddbLookup::PartialMatch: + rip_track[0]=-1; + rip_track[1]=-1; + printf("Partial Match!\n"); + break; + + default: + rip_track[0]=-1; + rip_track[1]=-1; + break; + } +} + + +void CdRipper::normalizeCheckData(bool state) +{ + rip_normalize_spin->setEnabled(state); + rip_normalize_label->setEnabled(state); + rip_normalize_unit->setEnabled(state); +} + + +void CdRipper::autotrimCheckData(bool state) +{ + rip_autotrim_spin->setEnabled(state); + rip_autotrim_label->setEnabled(state); + rip_autotrim_unit->setEnabled(state); +} + + +void CdRipper::closeData() +{ + if(rip_done) { + done(rip_track[0]); + } + else { + done(-1); + } +} + + +void CdRipper::resizeEvent(QResizeEvent *e) +{ + rip_title_label->setGeometry(10,10,50,18); + rip_title_box->setGeometry(65,9,size().width()-125,18); + rip_artist_label->setGeometry(10,32,50,18); + rip_artist_edit->setGeometry(65,31,size().width()-125,18); + rip_album_label->setGeometry(10,54,50,18); + rip_album_edit->setGeometry(65,53,size().width()-125,18); + rip_other_label->setGeometry(10,76,50,16); + rip_other_edit->setGeometry(65,75,size().width()-125,60); + rip_apply_box->setGeometry(65,140,15,15); + rip_apply_label->setGeometry(85,140,250,20); + rip_track_list->setGeometry(10,178,size().width()-110,size().height()-290); + rip_track_label->setGeometry(10,162,100,14); + rip_bar->setGeometry(10,size().height()-100,size().width()-112,20); + rip_eject_button->setGeometry(size().width()-90,178,80,50); + rip_play_button->setGeometry(size().width()-90,238,80,50); + rip_stop_button->setGeometry(size().width()-90,298,80,50); + rip_rip_button->setGeometry(size().width()-90,402,80,50); + rip_normalize_box->setGeometry(10,size().height()-76,20,20); + rip_normalize_box_label->setGeometry(30,size().height()-76,85,20); + rip_normalize_spin->setGeometry(170,size().height()-76,40,20); + rip_normalize_label->setGeometry(120,size().height()-76,45,20); + rip_normalize_unit->setGeometry(215,size().height()-76,40,20); + rip_autotrim_box->setGeometry(10,size().height()-52,20,20); + rip_autotrim_box_label->setGeometry(30,size().height()-52,85,20); + rip_autotrim_spin->setGeometry(170,size().height()-52,40,20); + rip_autotrim_label->setGeometry(120,size().height()-52,45,20); + rip_autotrim_unit->setGeometry(215,size().height()-52,40,20); + rip_channels_box->setGeometry(90,size().height()-28,50,20); + rip_channels_label->setGeometry(10,size().height()-28,75,20); + rip_close_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void CdRipper::closeEvent(QCloseEvent *e) +{ + if(!ripper_running) { + closeData(); + } +} + + +void CdRipper::Profile(const QString &msg) +{ + if(rip_profile_rip) { + printf("%s | CdRipper::%s\n", + (const char *)QTime::currentTime().toString("hh:mm:ss.zzz"), + (const char *)msg.utf8()); + } +} diff --git a/rdlibrary/cdripper.h b/rdlibrary/cdripper.h new file mode 100644 index 00000000..3520e7f0 --- /dev/null +++ b/rdlibrary/cdripper.h @@ -0,0 +1,130 @@ +// cdripper.h +// +// CD Ripper Dialog for Rivendell +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: cdripper.h,v 1.14.8.5 2014/01/14 18:02:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef CDRIPPER_H +#define CDRIPPER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +class CdRipper : public QDialog +{ + Q_OBJECT + public: + CdRipper(QString cutname,RDCddbRecord *rec,RDLibraryConf *conf, + bool profile_rip,QWidget *parent=0,const char *name=0); + ~CdRipper(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(QString *title,QString *artist,QString *album); + + private slots: + void trackSelectionChangedData(); + void ejectButtonData(); + void playButtonData(); + void stopButtonData(); + void ripTrackButtonData(); + void ejectedData(); + void mediaChangedData(); + void playedData(int); + void stoppedData(); + void cddbDoneData(RDCddbLookup::Result); + void normalizeCheckData(bool); + void autotrimCheckData(bool); + void closeData(); + + protected: + void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e); + + private: + void Profile(const QString &msg); + RDLibraryConf *rip_conf; + RDCdPlayer *rip_cdrom; + RDCddbRecord *rip_cddb_record; + RDCddbLookup *rip_cddb_lookup; + RDCut *rip_cut; + QLabel *rip_track_label; + RDListView *rip_track_list; + QPushButton *rip_rip_button; + bool rip_rip_aborted; + QPushButton *rip_close_button; + QString *rip_title; + QString *rip_artist; + QString *rip_album; + QLabel *rip_title_label; + QComboBox *rip_title_box; + QLabel *rip_album_label; + QLineEdit *rip_album_edit; + QLabel *rip_artist_label; + QLineEdit *rip_artist_edit; + QLabel *rip_other_label; + QTextEdit *rip_other_edit; + QCheckBox *rip_apply_box; + QLabel *rip_apply_label; + RDTransportButton *rip_eject_button; + RDTransportButton *rip_play_button; + RDTransportButton *rip_stop_button; + QProgressBar *rip_bar; + QLabel *rip_normalize_label; + QCheckBox *rip_normalize_box; + QLabel *rip_normalize_box_label; + QSpinBox *rip_normalize_spin; + QLabel *rip_normalize_unit; + QLabel *rip_autotrim_box_label; + QLabel *rip_channels_label; + QComboBox *rip_channels_box; + int rip_track[2]; + QCheckBox *rip_autotrim_box; + QSpinBox *rip_autotrim_spin; + QLabel *rip_autotrim_label; + QLabel *rip_autotrim_unit; + bool rip_done; + bool rip_profile_rip; + QDir rip_cdda_dir; + bool rip_isrc_read; +}; + + +#endif // CDRIPPER_H diff --git a/rdlibrary/disk_gauge.cpp b/rdlibrary/disk_gauge.cpp new file mode 100644 index 00000000..355156b7 --- /dev/null +++ b/rdlibrary/disk_gauge.cpp @@ -0,0 +1,107 @@ +// disk_gauge.cpp +// +// Disk Gauge Widget for RDLibrary. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: disk_gauge.cpp,v 1.7.8.1 2014/01/08 02:08:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + +#include +#include +#include + +DiskGauge::DiskGauge(int samp_rate,int chans,QWidget *parent,const char *name) + : QWidget(parent,name) +{ + disk_sample_rate=samp_rate; + disk_channels=chans; + + // + // Generate Fonts + // + QFont label_font("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + disk_label=new QLabel("Free:",this,"free_label"); + disk_label->setGeometry(0,0,50,sizeHint().height()); + disk_label->setFont(label_font); + disk_label->setAlignment(AlignRight|AlignVCenter); + + disk_bar=new QProgressBar(this); + disk_bar->setPercentageVisible(false); + disk_bar->setGeometry(55,0,sizeHint().width()-55,sizeHint().height()); + + disk_space_label=new QLabel(this); + disk_space_label->setFont(label_font); + disk_space_label->setAlignment(AlignCenter); + + struct statfs diskstat; + statfs(RDConfiguration()->audioRoot().ascii(),&diskstat); + disk_bar->setTotalSteps(GetMinutes(diskstat.f_blocks,diskstat.f_bsize)); + update(); + + QTimer *timer=new QTimer(this,"update_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(update())); + timer->start(DISK_GAUGE_UPDATE_INTERVAL); +} + + +QSize DiskGauge::sizeHint() const +{ + return QSize(160,40); +} + + +QSizePolicy DiskGauge::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void DiskGauge::update() +{ + struct statfs diskstat; + statfs(RDConfiguration()->audioRoot().ascii() ,&diskstat); + int mins=GetMinutes(diskstat.f_bavail,diskstat.f_bsize); + disk_bar->setProgress(mins); + disk_space_label-> + setText(QString().sprintf("%dh %02dm",mins/60,mins-60*(mins/60))); +} + + +void DiskGauge::resizeEvent(QResizeEvent *e) +{ + QFontMetrics *fm=new QFontMetrics(disk_label->font()); + disk_label->setGeometry(0,0,fm->width(disk_label->text()),size().height()/2); + disk_bar->setGeometry(fm->width(disk_label->text())+5,0, + size().width()-fm->width(disk_label->text())-10,size().height()/2); + disk_space_label-> + setGeometry(0,size().height()/2,size().width(),size().height()/2); + delete fm; +} + + +int DiskGauge::GetMinutes(long blocks,long block_size) +{ + return (int)(((double)blocks*(double)block_size)/ + (disk_sample_rate*disk_channels*120.0)); +} diff --git a/rdlibrary/disk_gauge.h b/rdlibrary/disk_gauge.h new file mode 100644 index 00000000..ee227e77 --- /dev/null +++ b/rdlibrary/disk_gauge.h @@ -0,0 +1,56 @@ +// disk_gauge.h +// +// Disk Gauge Widget for RDLibrary. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: disk_gauge.h,v 1.6.8.1 2014/01/08 02:08:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef DISK_GAUGE_H +#define DISK_GAUGE_H + +#include +#include +#include + +#define DISK_GAUGE_UPDATE_INTERVAL 60000 + +class DiskGauge : public QWidget +{ + Q_OBJECT + public: + DiskGauge(int samp_rate,int chans,QWidget *parent,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + void update(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + int GetMinutes(long blocks,long block_size); + QLabel *disk_label; + QProgressBar *disk_bar; + QLabel *disk_space_label; + double disk_sample_rate; + double disk_channels; +}; + + +#endif // DISK_GAUGE diff --git a/rdlibrary/disk_ripper.cpp b/rdlibrary/disk_ripper.cpp new file mode 100644 index 00000000..e49eed21 --- /dev/null +++ b/rdlibrary/disk_ripper.cpp @@ -0,0 +1,1144 @@ +// disk_ripper.cpp +// +// CD Ripper Dialog for Rivendell. +// +// (C) Copyright 2002-2003,2010 Fred Gleason +// +// $Id: disk_ripper.cpp,v 1.30.4.3.2.7 2014/06/02 18:59:24 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +DiskRipper::DiskRipper(QString *filter,QString *group,QString *schedcode, + bool profile_rip,QWidget *parent,const char *name) + : QDialog(parent,name) +{ + rip_isrc_read=false; + rip_filter_text=filter; + rip_group_text=group; + rip_schedcode_text=schedcode; + rip_profile_rip=profile_rip; + rip_aborting=false; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + setCaption(tr("Rip Disk")); + + // + // Create Dialogs + // + rip_wavedata_dialog=new RDWaveDataDialog("RDLibrary",this); + + // + // Create Temporary Directory + // + char path[PATH_MAX]; + strncpy(path,RIPPER_TEMP_DIR,PATH_MAX); + strcat(path,"/XXXXXX"); + if(mkdtemp(path)==NULL) { + QMessageBox::warning(this,"RDLibrary - "+tr("Ripper Error"), + tr("Unable to create temporary directory!")); + } + else { + rip_cdda_dir.setPath(path); + } + + // + // The CDROM Drive + // + if(rip_profile_rip) { + rip_cdrom=new RDCdPlayer(stdout,this); + } + else { + rip_cdrom=new RDCdPlayer(NULL,this); + } + connect(rip_cdrom,SIGNAL(ejected()),this,SLOT(ejectedData())); + connect(rip_cdrom,SIGNAL(mediaChanged()),this,SLOT(mediaChangedData())); + connect(rip_cdrom,SIGNAL(played(int)),this,SLOT(playedData(int))); + connect(rip_cdrom,SIGNAL(stopped()),this,SLOT(stoppedData())); + rip_cdrom->setDevice(rdlibrary_conf->ripperDevice()); + rip_cdrom->open(); + + // + // CDDB Stuff + // + if(rip_profile_rip) { + rip_cddb_lookup=new RDCddbLookup(stdout,this); + } + else { + rip_cddb_lookup=new RDCddbLookup(NULL,this); + } + connect(rip_cddb_lookup,SIGNAL(done(RDCddbLookup::Result)), + this,SLOT(cddbDoneData(RDCddbLookup::Result))); + + // + // Artist Label + // + QLabel *label=new QLabel(tr("Artist:"),this); + label->setGeometry(10,10,50,18); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter); + rip_artist_edit=new QLineEdit(this); + + // + // Album Edit + // + label=new QLabel(tr("Album:"),this); + label->setGeometry(10,32,50,18); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter); + rip_album_edit=new QLineEdit(this); + + // + // Other Edit + // + label=new QLabel(tr("Other:"),this); + label->setGeometry(10,54,50,16); + label->setFont(label_font); + label->setAlignment(AlignRight); + rip_other_edit=new QTextEdit(this); + rip_other_edit->setReadOnly(true); + + // + // Apply FreeDB Check Box + // + rip_apply_box=new QCheckBox(this,"rip_apply_box"); + rip_apply_box->setChecked(true); + rip_apply_box->setDisabled(true); + rip_apply_label= + new QLabel(rip_apply_box,tr("Apply FreeDB Values to Carts"),this); + rip_apply_label->setFont(label_font); + rip_apply_label->setAlignment(AlignLeft); + rip_apply_box->setChecked(false); + rip_apply_label->setDisabled(true); + + // + // Track List + // + rip_track_list=new QListView(this); + rip_track_list->setAllColumnsShowFocus(true); + rip_track_list->setItemMargin(5); + rip_track_list->setSorting(-1); + rip_track_list->setSelectionMode(QListView::Extended); + connect(rip_track_list,SIGNAL(selectionChanged()), + this,SLOT(selectionChangedData())); + connect(rip_track_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + rip_track_label=new QLabel(rip_track_list,tr("Tracks"),this); + rip_track_label->setFont(label_font); + rip_track_list->addColumn(tr("TRACK")); + rip_track_list->setColumnAlignment(0,Qt::AlignHCenter); + rip_track_list->addColumn(tr("LENGTH")); + rip_track_list->setColumnAlignment(1,Qt::AlignRight); + rip_track_list->addColumn(tr("TITLE")); + rip_track_list->setColumnAlignment(2,Qt::AlignLeft); + rip_track_list->addColumn(tr("OTHER")); + rip_track_list->setColumnAlignment(3,Qt::AlignLeft); + rip_track_list->addColumn(tr("TYPE")); + rip_track_list->setColumnAlignment(4,Qt::AlignLeft); + rip_track_list->addColumn(tr("CUT")); + rip_track_list->setColumnAlignment(5,Qt::AlignLeft); + + // + // Progress Bars + // + rip_disk_bar=new QProgressBar(this); + rip_diskbar_label=new QLabel(tr("Disk Progress"),this); + rip_diskbar_label->setFont(label_font); + rip_diskbar_label->setAlignment(AlignLeft|AlignVCenter); + rip_diskbar_label->setDisabled(true); + rip_track_bar=new QProgressBar(this); + rip_trackbar_label=new QLabel(tr("Track Progress"),this); + rip_trackbar_label->setFont(label_font); + rip_trackbar_label->setAlignment(AlignLeft|AlignVCenter); + rip_trackbar_label->setDisabled(true); + + // + // Eject Button + // + rip_eject_button=new RDTransportButton(RDTransportButton::Eject,this); + connect(rip_eject_button,SIGNAL(clicked()),this,SLOT(ejectButtonData())); + + // + // Play Button + // + rip_play_button=new RDTransportButton(RDTransportButton::Play,this); + connect(rip_play_button,SIGNAL(clicked()),this,SLOT(playButtonData())); + + // + // Stop Button + // + rip_stop_button=new RDTransportButton(RDTransportButton::Stop,this); + rip_stop_button->setOnColor(red); + rip_stop_button->on(); + connect(rip_stop_button,SIGNAL(clicked()),this,SLOT(stopButtonData())); + + // + // Set Cut Button + // + rip_setcut_button=new QPushButton(tr("Set\n&Cart/Cut"),this); + rip_setcut_button->setFont(button_font); + rip_setcut_button->setDisabled(true); + connect(rip_setcut_button,SIGNAL(clicked()),this,SLOT(setCutButtonData())); + + // + // Set Multi Tracks Button + // + rip_setall_button=new QPushButton(tr("Add Cart\nPer Track"),this); + rip_setall_button->setFont(button_font); + rip_setall_button->setDisabled(true); + connect(rip_setall_button,SIGNAL(clicked()),this,SLOT(setMultiButtonData())); + + // + // Set Single Button + // + rip_setsingle_button=new QPushButton(tr("Add Single\nCart"),this); + rip_setsingle_button->setFont(button_font); + rip_setsingle_button->setDisabled(true); + connect(rip_setsingle_button,SIGNAL(clicked()), + this,SLOT(setSingleButtonData())); + + // + // Set Cart Label Button + // + rip_cartlabel_button=new QPushButton(tr("Modify\nCart Label"),this); + rip_cartlabel_button->setFont(button_font); + rip_cartlabel_button->setDisabled(true); + connect(rip_cartlabel_button,SIGNAL(clicked()), + this,SLOT(modifyCartLabelData())); + + // + // Clear Selection Button + // + rip_clear_button=new QPushButton(tr("Clear\nSelection"),this); + rip_clear_button->setFont(button_font); + rip_clear_button->setDisabled(true); + connect(rip_clear_button,SIGNAL(clicked()),this,SLOT(clearSelectionData())); + + // + // Normalize Check Box + // + rip_normalize_box=new QCheckBox(this); + rip_normalize_box->setChecked(true); + rip_normalizebox_label=new QLabel(rip_normalize_box,tr("Normalize"),this); + rip_normalizebox_label->setFont(label_font); + rip_normalizebox_label->setAlignment(AlignLeft|AlignVCenter); + connect(rip_normalize_box,SIGNAL(toggled(bool)), + this,SLOT(normalizeCheckData(bool))); + + // + // Normalize Level + // + rip_normalize_spin=new QSpinBox(this); + rip_normalize_spin->setRange(-30,0); + rip_normalize_label=new QLabel(rip_normalize_spin,tr("Level:"),this); + rip_normalize_label->setFont(label_font); + rip_normalize_label->setAlignment(AlignRight|AlignVCenter); + rip_normalize_unit=new QLabel(tr("dBFS"),this); + rip_normalize_unit->setFont(label_font); + rip_normalize_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Autotrim Check Box + // + rip_autotrim_box=new QCheckBox(this); + rip_autotrim_box->setChecked(true); + rip_autotrimbox_label=new QLabel(rip_autotrim_box,tr("Autotrim"),this); + rip_autotrimbox_label->setFont(label_font); + rip_autotrimbox_label->setAlignment(AlignLeft|AlignVCenter); + connect(rip_autotrim_box,SIGNAL(toggled(bool)), + this,SLOT(autotrimCheckData(bool))); + + // + // Autotrim Level + // + rip_autotrim_spin=new QSpinBox(this); + rip_autotrim_spin->setRange(-99,0); + rip_autotrim_label=new QLabel(rip_autotrim_spin,tr("Level:"),this); + rip_autotrim_label->setFont(label_font); + rip_autotrim_label->setAlignment(AlignRight|AlignVCenter); + rip_autotrim_unit=new QLabel(tr("dBFS"),this); + rip_autotrim_unit->setFont(label_font); + rip_autotrim_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Channels + // + rip_channels_box=new QComboBox(this); + rip_channels_label=new QLabel(rip_channels_box,tr("Channels:"),this); + rip_channels_label->setFont(label_font); + rip_channels_label->setAlignment(AlignRight|AlignVCenter); + + // + // Rip Disc Button + // + rip_rip_button=new QPushButton(tr("&Rip\nDisc"),this); + rip_rip_button->setFont(button_font); + connect(rip_rip_button,SIGNAL(clicked()),this,SLOT(ripDiskButtonData())); + rip_rip_button->setDisabled(true); + + // + // Close Button + // + rip_close_button=new QPushButton(tr("&Close"),this); + rip_close_button->setFont(button_font); + connect(rip_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Populate Data + // + rip_normalize_spin->setValue(rdlibrary_conf->ripperLevel()/100); + rip_autotrim_spin->setValue(rdlibrary_conf->trimThreshold()/100); + rip_channels_box->insertItem("1"); + rip_channels_box->insertItem("2"); + rip_channels_box->setCurrentItem(rdlibrary_conf->defaultChannels()-1); + rip_done=false; +} + + +DiskRipper::~DiskRipper() +{ + QStringList files=rip_cdda_dir.entryList(); + for(unsigned i=0;iclose(); + delete rip_cdrom; + delete rip_track_list; + delete rip_rip_button; + delete rip_close_button; + delete rip_eject_button; + delete rip_play_button; + delete rip_stop_button; + delete rip_track_bar; + delete rip_wavedata_dialog; +} + + +QSize DiskRipper::sizeHint() const +{ + return QSize(730,716); +} + + +QSizePolicy DiskRipper::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void DiskRipper::ejectButtonData() +{ + rip_cdrom->eject(); +} + + +void DiskRipper::playButtonData() +{ + if(rip_track_list->currentItem()!=NULL) { + rip_cdrom->play(rip_track_list->currentItem()->text(0).toInt()); + rip_play_button->on(); + rip_stop_button->off(); + } +} + + +void DiskRipper::stopButtonData() +{ + rip_cdrom->stop(); + rip_play_button->off(); + rip_stop_button->on(); +} + + +void DiskRipper::ripDiskButtonData() +{ + RDListViewItem *item=(RDListViewItem *)rip_track_list->selectedItem(); + if(item!=NULL) { + rip_track_list->setSelected(item,false); + } + rip_aborting=false; + + // + // Calculate number of tracks to rip + // + int tracks=0; + for(unsigned i=0;isetTotalSteps(tracks); + + // + // Read ISRCs + // + if(!rip_isrc_read) { + rip_cddb_lookup-> + readIsrc(rip_cdda_dir.path(),rdlibrary_conf->ripperDevice()); + rip_isrc_read=true; + } + + // + // Rip + // + tracks=0; + item=(RDListViewItem *)rip_track_list->firstChild(); + while((item!=NULL)&&(!rip_aborting)) { + if(!rip_cutnames[item->text(0).toInt()-1].isEmpty()) { + rip_eject_button->setDisabled(true); + rip_play_button->setDisabled(true); + rip_stop_button->setDisabled(true); + rip_rip_button->setText(tr("Abort\nRip")); + disconnect(rip_rip_button,SIGNAL(clicked()), + this,SLOT(ripDiskButtonData())); + rip_setcut_button->setDisabled(true); + rip_setall_button->setDisabled(true); + rip_cartlabel_button->setDisabled(true); + rip_clear_button->setDisabled(true); + rip_close_button->setDisabled(true); + rip_normalize_box->setDisabled(true); + rip_normalize_spin->setDisabled(true); + rip_channels_box->setDisabled(true); + rip_autotrim_box->setDisabled(true); + rip_autotrim_spin->setDisabled(true); + rip_disk_bar->setProgress(tracks++); + rip_disk_bar->setPercentageVisible(true); + int start_track=item->text(0).toInt(); + int end_track=rip_end_track[item->text(0).toInt()-1]; + RipTrack(start_track,end_track,rip_cutnames[item->text(0).toInt()-1], + BuildTrackName(start_track,end_track)); + } + item=(RDListViewItem *)item->nextSibling(); + } + rip_eject_button->setEnabled(true); + rip_play_button->setEnabled(true); + rip_stop_button->setEnabled(true); + rip_setcut_button->setEnabled(false); + rip_setall_button->setEnabled(false); + rip_setsingle_button->setEnabled(false); + rip_cartlabel_button->setEnabled(false); + rip_clear_button->setEnabled(false); + rip_close_button->setEnabled(true); + rip_rip_button->setText(tr("Rip\nDisk")); + rip_rip_button->setEnabled(false); + connect(rip_rip_button,SIGNAL(clicked()),this,SLOT(ripDiskButtonData())); + rip_normalize_box->setEnabled(true); + rip_normalize_spin->setEnabled(true); + rip_channels_box->setEnabled(true); + rip_autotrim_box->setEnabled(true); + rip_autotrim_spin->setEnabled(true); + rip_disk_bar->setPercentageVisible(false); + rip_disk_bar->reset(); + rip_diskbar_label->setDisabled(true); + rip_trackbar_label->setDisabled(true); + rip_diskbar_label->setText(tr("Total Progress")); + rip_trackbar_label->setText(tr("Track Progress")); + item=(RDListViewItem *)rip_track_list->firstChild(); + while(item!=NULL) { + item->setText(5,""); + item=(RDListViewItem *)item->nextSibling(); + } + rip_cdrom->eject(); + if(rip_aborting) { + QMessageBox::information(this,tr("Rip Complete"),tr("Rip aborted!")); + } + else { + QMessageBox::information(this,tr("Rip Complete"),tr("Rip complete!")); + } +} + + +void DiskRipper::ejectedData() +{ + rip_track_list->clear(); + rip_track=-1; + rip_artist_edit->clear(); + rip_album_edit->clear(); + rip_other_edit->clear(); + rip_apply_box->setChecked(false); + rip_apply_box->setDisabled(true); + rip_apply_label->setDisabled(true); +} + + +void DiskRipper::setCutButtonData() +{ + RDListViewItem *item=(RDListViewItem *)rip_track_list->firstChild(); + while(item!=NULL) { + if(item->isSelected()) { + break; + } + item=(RDListViewItem *)item->nextSibling(); + } + if(item==NULL) { + return; + } + QString cutname=rip_cutnames[item->text(0).toUInt()-1]; + RDCutDialog *dialog=new RDCutDialog(&cutname,rdstation_conf,lib_system, + rip_filter_text, + rip_group_text,rip_schedcode_text, + lib_user->name(),true, + true,true,this,"cut_dialog"); + if(dialog->exec()==0) { + if(cutname.isEmpty()) { + rip_cutnames[item->text(0).toUInt()-1]=""; + item->setText(5,""); + } + else { + for(unsigned i=0;icutName()) { + switch(QMessageBox::warning(this,tr("Empty Clipboard"), + tr("Ripping this cut will also empty the clipboard.\nDo you still want to proceed?"), + QMessageBox::Yes, + QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + return; + + default: + break; + } + delete cut_clipboard; + cut_clipboard=NULL; + } + } + rip_cutnames[item->text(0).toUInt()-1]=cutname; + rip_end_track[item->text(0).toUInt()-1]=item->text(0).toInt(); + RDCart *cart=new RDCart(cutname.left(6).toUInt()); + RDCut *cut=new RDCut(cutname); + item->setId(cart->number()); + item->setText(5,cart->title()+" -> "+cut->description()); + delete cut; + delete cart; + } + } + delete dialog; + + bool track_selected=false; + item=(RDListViewItem *)rip_track_list->firstChild(); + while(item!=NULL) { + if(!item->text(5).isEmpty()) { + track_selected=true; + } + item=(RDListViewItem *)item->nextSibling(); + } + rip_setcut_button->setEnabled(false); + rip_setall_button->setEnabled(false); + rip_setsingle_button->setEnabled(false); + rip_cartlabel_button->setEnabled(true); + rip_clear_button->setEnabled(true); + rip_rip_button->setEnabled(track_selected); +} + + +void DiskRipper::setMultiButtonData() +{ + // + // Get Destination Group + // + RDListGroups *list_groups=new RDListGroups(rip_group_text,lib_user->name(), + this); + if(list_groups->exec()<0) { + delete list_groups; + return; + } + delete list_groups; + RDGroup *group=new RDGroup(*rip_group_text); + + // + // Reserve Carts + // + unsigned count=0; + std::vector cart_nums; + RDListViewItem *item=(RDListViewItem *)rip_track_list->firstChild(); + while(item!=NULL) { + if(item->isSelected()) { + count++; + } + item=(RDListViewItem *)item->nextSibling(); + } + if(!group->reserveCarts(&cart_nums,rdstation_conf->name(),RDCart::Audio, + count)) { + QMessageBox::warning(this,"RDLibrary - "+tr("Error"), + tr("Unable to allocate carts in group")+" \""+ + group->name()+"\"."); + return; + } + + // + // Schedule Rips + // + count=0; + item=(RDListViewItem *)rip_track_list->firstChild(); + while(item!=NULL) { + if(item->isSelected()) { + rip_cutnames[item->text(0).toUInt()-1]= + QString().sprintf("%06u_001",cart_nums[count]); + rip_end_track[item->text(0).toUInt()-1]=item->text(0).toInt(); + item->setId(cart_nums[count]); + item->setText(5,QString().sprintf("[New Cart %06u] -> Cut 001", + cart_nums[count])); + count++; + } + item=(RDListViewItem *)item->nextSibling(); + } + rip_setcut_button->setEnabled(false); + rip_setall_button->setEnabled(false); + rip_setsingle_button->setEnabled(false); + rip_cartlabel_button->setEnabled(true); + rip_clear_button->setEnabled(true); + rip_rip_button->setEnabled(true); +} + + +void DiskRipper::setSingleButtonData() +{ + // + // Get Destination Group + // + RDListGroups *list_groups=new RDListGroups(rip_group_text,lib_user->name(), + this); + if(list_groups->exec()<0) { + delete list_groups; + return; + } + delete list_groups; + RDGroup *group=new RDGroup(*rip_group_text); + std::vector cart_nums; + unsigned new_cart=0; + int first_track=-1; + + // + // Reserve Cart + // + if(!group->reserveCarts(&cart_nums,rdstation_conf->name(),RDCart::Audio,1)) { + QMessageBox::warning(this,"RDLibrary - "+tr("Error"), + tr("Unable to allocate cart in group")+" \""+ + group->name()+"\"."); + return; + } + + // + // Schedule Rips + // + RDListViewItem *item=(RDListViewItem *)rip_track_list->firstChild(); + while(item!=NULL) { + if(item->isSelected()) { + if(new_cart==0) { + first_track=item->text(0).toUInt()-1; + new_cart=group->nextFreeCart(cart_nums[0]); + rip_cutnames[item->text(0).toUInt()-1]= + QString().sprintf("%06u_001",cart_nums[0]); + item->setId(cart_nums[0]); + item-> + setText(5,QString().sprintf("[New Cart %06u] -> Cut 001", + cart_nums[0])); + } + else { + rip_end_track[first_track]=item->text(0).toUInt(); + item->setId(cart_nums[0]); + item->setText(5,tr("[continued]")); + } + } + item=(RDListViewItem *)item->nextSibling(); + } + rip_setcut_button->setEnabled(false); + rip_setall_button->setEnabled(false); + rip_setsingle_button->setEnabled(false); + rip_cartlabel_button->setEnabled(true); + rip_clear_button->setEnabled(true); + rip_rip_button->setEnabled(true); +} + + +void DiskRipper::modifyCartLabelData() +{ + RDListViewItem *item=(RDListViewItem *)rip_track_list->firstChild(); + while(item!=NULL) { + if(item->isSelected()) { + int track=item->text(0).toInt()-1; + if(rip_wavedata_dialog->exec(rip_wave_datas[track])==0) { + item->setText(2,rip_wave_datas[track]->title()); + } + return; + } + item=(RDListViewItem *)item->nextSibling(); + } +} + + +void DiskRipper::clearSelectionData() +{ + RDListViewItem *item=(RDListViewItem *)rip_track_list->firstChild(); + while(item!=NULL) { + if(item->isSelected()) { + rip_cutnames[item->text(0).toInt()-1]=""; + rip_end_track[item->text(0).toInt()-1]=-1; + item->setId(0); + item->setText(5,""); + item->setSelected(false); + } + item=(RDListViewItem *)item->nextSibling(); + } + rip_setcut_button->setDisabled(true); + rip_setall_button->setDisabled(true); + rip_setsingle_button->setDisabled(true); + rip_cartlabel_button->setDisabled(true); + rip_clear_button->setDisabled(true); + UpdateRipButton(); +} + + +void DiskRipper::mediaChangedData() +{ + RDListViewItem *l; + + rip_isrc_read=false; + rip_cutnames.clear(); + rip_end_track.clear(); + for(unsigned i=0;iclear(); + rip_track=-1; + rip_setcut_button->setDisabled(true); + rip_setall_button->setDisabled(true); + rip_setsingle_button->setDisabled(true); + rip_cartlabel_button->setDisabled(true); + rip_clear_button->setDisabled(true); + for(int i=rip_cdrom->tracks();i>0;i--) { + rip_cutnames.push_back(QString()); + rip_end_track.push_back(-1); + rip_wave_datas.push_back(new RDWaveData()); + rip_wave_datas.back()->setTitle(tr("Track")+QString().sprintf(" %d",i+1)); + l=new RDListViewItem(rip_track_list); + l->setText(0,QString().sprintf("%d",i)); + if(rip_cdrom->isAudio(i)) { + l->setText(4,tr("Audio Track")); + } + else { + l->setText(4,tr("Data Track")); + } + l->setText(1,RDGetTimeLength(rip_cdrom->trackLength(i))); + } + rip_cddb_record.clear(); + rip_cdrom->setCddbRecord(&rip_cddb_record); + rip_cddb_lookup->setCddbRecord(&rip_cddb_record); + rip_cddb_lookup-> + lookupRecord(rip_cdda_dir.path(),rdlibrary_conf->ripperDevice(), + rdlibrary_conf->cddbServer(),8880, + RIPPER_CDDB_USER,PACKAGE_NAME,VERSION); +} + + +void DiskRipper::playedData(int track) +{ + rip_play_button->on(); + rip_stop_button->off(); +} + + +void DiskRipper::stoppedData() +{ + rip_play_button->off(); + rip_stop_button->on(); +} + + +void DiskRipper::cddbDoneData(RDCddbLookup::Result result) +{ + switch(result) { + case RDCddbLookup::ExactMatch: + if(rip_cdrom->status()!=RDCdPlayer::Ok) { + return; + } + rip_artist_edit->setText(rip_cddb_record.discArtist()); + rip_album_edit->setText(rip_cddb_record.discAlbum()); + rip_other_edit->setText(rip_cddb_record.discExtended()); + for(int i=0;ifindItem(QString().sprintf("%d",i+1),0)-> + setText(2,rip_cddb_record.trackTitle(i)); + rip_track_list->findItem(QString().sprintf("%d",i+1),0)-> + setText(3,rip_cddb_record.trackExtended(i)); + rip_wave_datas[i]->setTitle(rip_cddb_record.trackTitle(i)); + rip_wave_datas[i]->setArtist(rip_cddb_record.discArtist()); + rip_wave_datas[i]->setAlbum(rip_cddb_record.discAlbum()); + } + rip_apply_box->setChecked(true); + rip_apply_box->setEnabled(true); + rip_apply_label->setEnabled(true); + break; + case RDCddbLookup::PartialMatch: + rip_track=-1; + printf("Partial Match!\n"); + break; + default: + rip_track=-1; + break; + } +} + + +void DiskRipper::normalizeCheckData(bool state) +{ + rip_normalize_spin->setEnabled(state); + rip_normalize_label->setEnabled(state); + rip_normalize_unit->setEnabled(state); +} + + +void DiskRipper::autotrimCheckData(bool state) +{ + rip_autotrim_spin->setEnabled(state); + rip_autotrim_label->setEnabled(state); + rip_autotrim_unit->setEnabled(state); +} + + +void DiskRipper::selectionChangedData() +{ + int count=0; + int last_track=0; + bool contiguous=true; + RDListViewItem *item=(RDListViewItem *)rip_track_list->firstChild(); + + while(item!=NULL) { + int track=item->text(0).toInt(); + if(item->isSelected()) { + if(item->id()>0) { + FocusSelection(item->id()); + rip_setcut_button->setEnabled(false); + rip_setall_button->setEnabled(false); + rip_setsingle_button->setEnabled(false); + rip_cartlabel_button->setEnabled(true); + rip_clear_button->setEnabled(true); + return; + } + if((last_track!=0)&&(last_track!=(track-1))) { + contiguous=false; + } + last_track=track; + count++; + } + item=(RDListViewItem *)item->nextSibling(); + } + rip_setcut_button->setEnabled(count==1); + rip_setall_button->setEnabled(count>0); + rip_setsingle_button->setEnabled((count>1)&&contiguous); + rip_cartlabel_button->setEnabled(false); + rip_clear_button->setEnabled(false); +} + + +void DiskRipper::doubleClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + setCutButtonData(); +} + + +void DiskRipper::closeData() +{ + RDCart::removePending(rdstation_conf,lib_user,lib_config); + if(rip_done&&rip_apply_box->isChecked()) { + done(0); + } + else { + done(-1); + } +} + + +void DiskRipper::resizeEvent(QResizeEvent *e) +{ + rip_artist_edit->setGeometry(65,9,size().width()-125,18); + rip_album_edit->setGeometry(65,31,size().width()-125,18); + rip_other_edit->setGeometry(65,53,size().width()-125,60); + rip_apply_box->setGeometry(65,118,15,15); + rip_apply_label->setGeometry(85,118,250,20); + rip_track_label->setGeometry(100,140,100,14); + rip_track_list->setGeometry(100,156,size().width()-202,size().height()-342); + rip_diskbar_label->setGeometry(10,size().height()-174,size().width()-110,20); + rip_disk_bar->setGeometry(10,size().height()-154,size().width()-110,20); + rip_trackbar_label->setGeometry(10,size().height()-126,size().width()-110,20); + rip_track_bar->setGeometry(10,size().height()-106,size().width()-110,20); + rip_eject_button->setGeometry(10,156,80,50); + rip_play_button->setGeometry(10,216,80,50); + rip_stop_button->setGeometry(10,276,80,50); + rip_setcut_button->setGeometry(size().width()-90,156,80,50); + rip_setall_button->setGeometry(size().width()-90,216,80,50); + rip_setsingle_button->setGeometry(size().width()-90,276,80,50); + rip_cartlabel_button->setGeometry(size().width()-90,420,80,50); + rip_clear_button->setGeometry(size().width()-90,480,80,50); + rip_normalizebox_label->setGeometry(30,size().height()-78,85,20); + rip_normalize_box->setGeometry(10,size().height()-78,20,20); + rip_normalize_spin->setGeometry(170,size().height()-79,40,20); + rip_normalize_label->setGeometry(120,size().height()-78,45,20); + rip_normalize_unit->setGeometry(215,size().height()-78,40,20); + rip_autotrimbox_label->setGeometry(30,size().height()-54,85,20); + rip_autotrim_box->setGeometry(10,size().height()-54,20,20); + rip_autotrim_spin->setGeometry(170,size().height()-54,40,20); + rip_autotrim_label->setGeometry(120,size().height()-54,45,20); + rip_autotrim_unit->setGeometry(215,size().height()-54,40,20); + rip_channels_label->setGeometry(10,size().height()-30,75,20); + rip_channels_box->setGeometry(90,size().height()-30,50,20); + rip_rip_button->setGeometry(size().width()-200,size().height()-60,80,50); + rip_close_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void DiskRipper::closeEvent(QCloseEvent *e) +{ + if(!ripper_running) { + closeData(); + } +} + + +void DiskRipper::FocusSelection(int cart_num) +{ + RDListViewItem *item=(RDListViewItem *)rip_track_list->firstChild(); + while(item!=NULL) { + item->setSelected(item->id()==cart_num); + item=(RDListViewItem *)item->nextSibling(); + } +} + + +void DiskRipper::RipTrack(int track,int end_track,QString cutname,QString title) +{ + RDCdRipper *ripper=NULL; + RDCut *cut=new RDCut(cutname); + RDCart *cart=new RDCart(cut->cartNumber()); + QString sql; + RDSqlQuery *q; + + // + // Create Cut + // + sql=QString("insert into CUTS set ")+ + "CUT_NAME=\""+RDEscapeString(cutname)+"\","+ + QString().sprintf("CART_NUMBER=%u,",cut->cartNumber())+ + "DESCRIPTION=\""+tr("Cut")+" 001\""; + q=new RDSqlQuery(sql); + delete q; + + rip_done=false; + rip_rip_aborted=false; + rip_track_number=track; + rip_title=title; + rip_cutname=cutname; + if(title.isEmpty()) { + rip_trackbar_label->setText(tr("Track Progress")+" - "+tr("Track")+ + QString().sprintf(" %d",track)); + } + else { + rip_trackbar_label->setText(tr("Track Progress")+" - "+title); + } + rip_diskbar_label->setEnabled(true); + rip_trackbar_label->setEnabled(true); + + // + // Rip from disc + // + RDAudioImport::ErrorCode conv_err; + RDAudioConvert::ErrorCode audio_conv_err; + RDCdRipper::ErrorCode ripper_err; + QString tmpdir=RDTempDir(); + QString tmpfile=tmpdir+"/"+RIPPER_TEMP_WAV; + if(rip_profile_rip) { + ripper=new RDCdRipper(stdout,this); + } + else { + ripper=new RDCdRipper(NULL,this); + } + rip_track_bar->setTotalSteps(ripper->totalSteps()+1); + connect(ripper,SIGNAL(progressChanged(int)), + rip_track_bar,SLOT(setProgress(int))); + connect(rip_rip_button,SIGNAL(clicked()),ripper,SLOT(abort())); + RDAudioImport *conv=NULL; + RDSettings *settings=NULL; + ripper->setDevice(rdlibrary_conf->ripperDevice()); + ripper->setDestinationFile(tmpfile); + switch((ripper_err=ripper->rip(rip_track_number-1,end_track-1))) { + case RDCdRipper::ErrorOk: + conv=new RDAudioImport(rdstation_conf,lib_config,this); + conv->setSourceFile(tmpfile); + conv->setCartNumber(cut->cartNumber()); + conv->setCutNumber(cut->cutNumber()); + conv->setUseMetadata(false); + settings=new RDSettings(); + if(rdlibrary_conf->defaultFormat()==1) { + settings->setFormat(RDSettings::MpegL2Wav); + } + else { + settings->setFormat(RDSettings::Pcm16); + } + settings->setChannels(rip_channels_box->currentText().toInt()); + settings->setSampleRate(lib_system->sampleRate()); + settings->setBitRate(rdlibrary_conf->defaultBitrate()); + if(rip_normalize_box->isChecked()) { + settings->setNormalizationLevel(rip_normalize_spin->value()); + } + if(rip_autotrim_box->isChecked()) { + settings->setAutotrimLevel(rip_autotrim_spin->value()); + } + conv->setDestinationSettings(settings); + switch((conv_err=conv-> + runImport(lib_user->name(),lib_user->password(), + &audio_conv_err))) { + case RDAudioImport::ErrorOk: + cart->setMetadata(rip_wave_datas[track-1]); + cut->setDescription(rip_wave_datas[track-1]->title()); + cut->setIsrc(rip_cddb_record.isrc(rip_track_number-1)); + cart->clearPending(); + break; + + default: + cart->remove(rdstation_conf,lib_user,lib_config); + QMessageBox::warning(this,tr("RDLibrary - Importer Error"), + RDAudioImport::errorText(conv_err,audio_conv_err)); + break; + } + delete settings; + delete conv; + break; + + case RDCdRipper::ErrorNoDevice: + case RDCdRipper::ErrorNoDestination: + case RDCdRipper::ErrorInternal: + case RDCdRipper::ErrorNoDisc: + case RDCdRipper::ErrorNoTrack: + cart->remove(rdstation_conf,lib_user,lib_config); + QMessageBox::warning(this,tr("RDLibrary - Ripper Error"), + RDCdRipper::errorText(ripper_err)); + break; + + case RDCdRipper::ErrorAborted: + rip_aborting=true; + cart->remove(rdstation_conf,lib_user,lib_config); + break; + } + delete ripper; + unlink(tmpfile); + rmdir(tmpdir); + rip_track_bar->setProgress(0); + rip_track_bar->setPercentageVisible(true); + + delete cart; + delete cut; +} + + +void DiskRipper::UpdateRipButton() +{ + bool ready=false; + RDListViewItem *item=(RDListViewItem *)rip_track_list->firstChild(); + while(item!=NULL) { + ready=ready||(!item->text(5).isEmpty()); + item=(RDListViewItem *)item->nextSibling(); + } + rip_rip_button->setEnabled(ready); +} + + +QString DiskRipper::BuildTrackName(int start_track,int end_track) const +{ + QString ret; + RDListViewItem *item=(RDListViewItem *)rip_track_list->firstChild(); + while(item!=NULL) { + if(item->text(0).toInt()==start_track) { + ret=item->text(2); + } + else { + if((item->text(0).toInt()>start_track)&& + (item->text(0).toInt()<=end_track)) { + ret+=" / "+item->text(2); + } + } + item=(RDListViewItem *)item->nextSibling(); + } + return ret; +} diff --git a/rdlibrary/disk_ripper.h b/rdlibrary/disk_ripper.h new file mode 100644 index 00000000..e03ebf89 --- /dev/null +++ b/rdlibrary/disk_ripper.h @@ -0,0 +1,150 @@ +// disk_ripper.h +// +// CD Ripper Dialog for Rivendell +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: disk_ripper.h,v 1.8.4.2.2.3 2014/06/02 17:17:00 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef DISK_RIPPER_H +#define DISK_RIPPER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +class DiskRipper : public QDialog +{ + Q_OBJECT + public: + DiskRipper(QString *filter,QString *group,QString *schedcode, + bool profile_rip,QWidget *parent=0,const char *name=0); + ~DiskRipper(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void ejectButtonData(); + void playButtonData(); + void stopButtonData(); + void ripDiskButtonData(); + void ejectedData(); + void setCutButtonData(); + void setMultiButtonData(); + void setSingleButtonData(); + void modifyCartLabelData(); + void clearSelectionData(); + void mediaChangedData(); + void playedData(int); + void stoppedData(); + void cddbDoneData(RDCddbLookup::Result); + void normalizeCheckData(bool); + void autotrimCheckData(bool); + void selectionChangedData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void closeData(); + + protected: + void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e); + + private: + void FocusSelection(int cart_num); + void RipTrack(int track,int end_track,QString cutname,QString title); + void UpdateRipButton(); + QString BuildTrackName(int start_track,int end_track) const; + RDCdPlayer *rip_cdrom; + RDCddbRecord rip_cddb_record; + RDCddbLookup *rip_cddb_lookup; + QLabel *rip_track_label; + QListView *rip_track_list; + QPushButton *rip_rip_button; + bool rip_rip_aborted; + QPushButton *rip_close_button; + QLineEdit *rip_album_edit; + QLineEdit *rip_artist_edit; + QTextEdit *rip_other_edit; + QCheckBox *rip_apply_box; + QLabel *rip_apply_label; + RDTransportButton *rip_eject_button; + RDTransportButton *rip_play_button; + RDTransportButton *rip_stop_button; + QPushButton *rip_setcut_button; + QPushButton *rip_setall_button; + QPushButton *rip_setsingle_button; + QPushButton *rip_cartlabel_button; + QPushButton *rip_clear_button; + QString rip_cutname; + QString rip_track; + QString rip_title; + QLabel *rip_diskbar_label; + QProgressBar *rip_disk_bar; + QLabel *rip_trackbar_label; + QProgressBar *rip_track_bar; + QCheckBox *rip_normalize_box; + QSpinBox *rip_normalize_spin; + QLabel *rip_normalize_label; + QLabel *rip_normalize_unit; + QLabel *rip_channels_label; + QComboBox *rip_channels_box; + int rip_track_number; + QLabel *rip_autotrimbox_label; + QLabel *rip_normalizebox_label; + QCheckBox *rip_autotrim_box; + QSpinBox *rip_autotrim_spin; + QLabel *rip_autotrim_label; + QLabel *rip_autotrim_unit; + bool rip_done; + QString *rip_filter_text; + QString *rip_group_text; + QString *rip_schedcode_text; + std::vector rip_cutnames; + std::vector rip_end_track; + std::vector rip_wave_datas; + bool rip_aborting; + bool rip_profile_rip; + QDir rip_cdda_dir; + bool rip_isrc_read; + RDWaveDataDialog *rip_wavedata_dialog; +}; + + +#endif + diff --git a/rdlibrary/edit_cart.cpp b/rdlibrary/edit_cart.cpp new file mode 100644 index 00000000..35d825a6 --- /dev/null +++ b/rdlibrary/edit_cart.cpp @@ -0,0 +1,1071 @@ +// edit_cart.cpp +// +// Edit a Rivendell Cart +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_cart.cpp,v 1.74.2.7.2.2 2014/05/28 21:21:41 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +EditCart::EditCart(unsigned number,QString *path,bool new_cart,bool profile_rip, + QWidget *parent,const char *name,QListView *lib_cart_list) + : QDialog(parent,name,true) +{ + bool modification_allowed; + rdcart_cart=NULL; + rdcart_profile_rip=profile_rip; + + rdcart_new_cart=new_cart; + sched_codes=""; + add_codes=""; + remove_codes=""; + lib_cart_list_edit=lib_cart_list; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + if(lib_cart_list_edit==NULL) { + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + } + else { + setMinimumHeight(sizeHint().height()-270); + setMaximumHeight(sizeHint().height()-270); + } + + if(lib_cart_list_edit==NULL) { + rdcart_cart=new RDCart(number); + rdcart_import_path=path; + setCaption(QString().sprintf("%06u",rdcart_cart->number())+" - "+ + rdcart_cart->title()); + modification_allowed= + lib_user->modifyCarts()&&rdcart_cart->owner().isEmpty(); + } + else { + setCaption("Edit Carts"); + modification_allowed=true; + } + + // + // Create Default Audio Cut + // + if(new_cart&&((rdcart_cart->type()==RDCart::Audio))) { + if(rdcart_cart->addCut(rdlibrary_conf->defaultFormat(), + rdlibrary_conf->defaultBitrate(), + rdlibrary_conf->defaultChannels())<0) { + QMessageBox::warning(this,tr("RDLibrary - Edit Cart"), + tr("This cart cannot contain any additional cuts!")); + } + } + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont line_edit_font=QFont("Helvetica",12,QFont::Normal); + line_edit_font.setPixelSize(12); + + if(lib_cart_list_edit==NULL) { + // + // Cart Number + // + rdcart_number_edit=new QLineEdit(this,"rdcart_number_edit"); + rdcart_number_edit->setGeometry(135,11,70,21); + rdcart_number_edit->setFont(line_edit_font); + rdcart_number_edit->setMaxLength(6); + rdcart_number_edit->setReadOnly(true); + QLabel *rdcart_number_label=new QLabel(rdcart_number_edit,tr("Number:"),this, + "rdcart_number_label"); + rdcart_number_label->setGeometry(10,13,120,19); + rdcart_number_label->setFont(button_font); + rdcart_number_label->setAlignment(AlignRight|ShowPrefix); + } + + // + // Cart Group + // + rdcart_group_box=new QComboBox(this,"rdcart_group_box"); + if(lib_cart_list_edit==NULL) { + rdcart_group_box->setGeometry(280,11,140,21); + } + else { + rdcart_group_box->setGeometry(135,38,110,19); + } + rdcart_group_box->setFont(line_edit_font); + rdcart_group_edit=new QLineEdit(this,"rdcart_group_edit"); + rdcart_group_edit->setGeometry(280,11,140,21); + rdcart_group_edit->setFont(line_edit_font); + rdcart_group_edit->setReadOnly(true); + QLabel *rdcart_group_label=new QLabel(rdcart_group_box,tr("Group:"),this, + "rdcart_group_label"); + if(lib_cart_list_edit==NULL) { + rdcart_group_label->setGeometry(215,13,60,19); + } + else { + rdcart_group_label->setGeometry(10,38,120,19); + } + rdcart_group_label->setFont(button_font); + rdcart_group_label->setAlignment(AlignRight|ShowPrefix); + + // + // Cart Type + // + rdcart_type_edit=new QLineEdit(this,"rdcart_type_edit"); + rdcart_type_edit->setGeometry(500,11,80,21); + rdcart_type_edit->setFont(line_edit_font); + rdcart_type_edit->setMaxLength(6); + rdcart_type_edit->setReadOnly(true); + QLabel *rdcart_type_label=new QLabel(rdcart_type_edit,tr("Type:"),this, + "rdcart_type_label"); + rdcart_type_label->setGeometry(440,13,55,19); + rdcart_type_label->setFont(button_font); + rdcart_type_label->setAlignment(AlignRight|ShowPrefix); + if(lib_cart_list_edit!=NULL) { + rdcart_type_label->hide(); + rdcart_type_edit->hide(); + } + + // + // Cart Average Length + // + rdcart_average_length_edit=new QLineEdit(this,"rdcart_average_length_edit"); + rdcart_average_length_edit->setGeometry(135,36,70,21); + rdcart_average_length_edit->setFont(line_edit_font); + rdcart_average_length_edit->setMaxLength(10); + rdcart_average_length_edit->setAlignment(AlignRight); + rdcart_average_length_edit->setReadOnly(true); + QLabel *rdcart_average_length_label=new QLabel(rdcart_average_length_edit, + tr("Average Length:"),this, + "rdcart_average_length_label"); + rdcart_average_length_label->setGeometry(10,38,120,19); + rdcart_average_length_label->setFont(button_font); + rdcart_average_length_label->setAlignment(AlignRight|ShowPrefix); + if(lib_cart_list_edit!=NULL) { + rdcart_average_length_label->hide(); + rdcart_average_length_edit->hide(); + } + + // + // Cart Enforce Length + // + rdcart_controls.enforce_length_box=new QCheckBox(this, + "rdcart_enforce_length_button"); + rdcart_controls.enforce_length_box->setGeometry(285,38,20,15); + QLabel *rdcart_enforce_length_label=new QLabel(rdcart_controls.enforce_length_box, + tr("Enforce Length"),this, + "rdcart_enforce_length_label"); + rdcart_enforce_length_label->setGeometry(305,38,110,19); + rdcart_enforce_length_label->setFont(button_font); + rdcart_enforce_length_label->setAlignment(AlignLeft|ShowPrefix); + connect(rdcart_controls.enforce_length_box,SIGNAL(toggled(bool)), + this,SLOT(forcedLengthData(bool))); + if(lib_cart_list_edit!=NULL) { + rdcart_enforce_length_label->hide(); + rdcart_controls.enforce_length_box->hide(); + } + + // + // Cart Forced Length + // + rdcart_controls.forced_length_edit= + new RDTimeEdit(this,"rdcart_forced_length_edit"); + rdcart_controls.forced_length_edit->setGeometry(530,36,85,21); + rdcart_controls.forced_length_edit-> + setDisplay(RDTimeEdit::Hours|RDTimeEdit::Minutes|RDTimeEdit::Seconds| + RDTimeEdit::Tenths); + rdcart_controls.forced_length_edit->setFont(line_edit_font); + rdcart_forced_length_ledit=new QLineEdit(this,"rdcart_forced_length_edit"); + rdcart_forced_length_ledit->setGeometry(535,36,80,21); + rdcart_forced_length_ledit->setFont(line_edit_font); + rdcart_forced_length_ledit->hide(); + rdcart_forced_length_ledit->setReadOnly(true); + rdcart_forced_length_label=new QLabel(rdcart_controls.forced_length_edit, + tr("Forced Length:"),this, + "rdcart_forced_length_label"); + rdcart_forced_length_label->setGeometry(415,38,110,19); + rdcart_forced_length_label->setFont(button_font); + rdcart_forced_length_label->setAlignment(AlignRight|ShowPrefix); + if(lib_cart_list_edit!=NULL) { + rdcart_forced_length_label->hide(); + rdcart_controls.forced_length_edit->hide(); + } + + // + // Cart Preserve Pitch + // + rdcart_preserve_pitch_button=new QCheckBox(this, + "rdcart_preserve_pitch_button"); + rdcart_preserve_pitch_button->setGeometry(430,38,20,15); + rdcart_preserve_pitch_label=new QLabel(rdcart_preserve_pitch_button, + tr("Preserve Pitch"),this, + "rdcart_preserve_pitch_label"); + rdcart_preserve_pitch_label->setGeometry(450,38,140,19); + rdcart_preserve_pitch_label->setFont(button_font); + rdcart_preserve_pitch_label->setAlignment(AlignLeft|ShowPrefix); + // ??????????????????????????????? + rdcart_preserve_pitch_button->hide(); + rdcart_preserve_pitch_label->hide(); + + // + // Cart Title + // + rdcart_controls.title_edit=new QLineEdit(this,"rdcart_title_edit"); + rdcart_controls.title_edit->setGeometry(135,60,480,21); + rdcart_controls.title_edit->setFont(line_edit_font); + rdcart_controls.title_edit->setMaxLength(255); + QLabel *rdcart_title_label=new QLabel(rdcart_controls.title_edit,tr("&Title:"),this, + "rdcart_title_label"); + rdcart_title_label->setGeometry(10,62,120,19); + rdcart_title_label->setFont(button_font); + rdcart_title_label->setAlignment(AlignRight|ShowPrefix); + + // + // Cart Start Date + // + rdcart_start_date_edit=new QLineEdit(this,"rdcart_start_date_edit"); + rdcart_start_date_edit->setGeometry(135,84,100,21); + rdcart_start_date_edit->setFont(line_edit_font); + rdcart_start_date_edit->setMaxLength(255); + QLabel *rdcart_start_date_label=new QLabel(rdcart_start_date_edit, + tr("&Start Date:"),this, + "rdcart_start_date_label"); + rdcart_start_date_label->setGeometry(10,86,120,19); + rdcart_start_date_label->setFont(button_font); + rdcart_start_date_label->setAlignment(AlignRight|ShowPrefix); + rdcart_start_date_edit->hide(); + rdcart_start_date_label->hide(); + + // + // Cart End Date + // + rdcart_end_date_edit=new QLineEdit(this,"rdcart_end_date_edit"); + rdcart_end_date_edit->setGeometry(350,84,100,21); + rdcart_end_date_edit->setFont(line_edit_font); + rdcart_end_date_edit->setMaxLength(255); + QLabel *rdcart_end_date_label=new QLabel(rdcart_end_date_edit, + tr("&End Date:"),this, + "rdcart_end_date_label"); + rdcart_end_date_label->setGeometry(260,86,85,19); + rdcart_end_date_label->setFont(button_font); + rdcart_end_date_label->setAlignment(AlignRight|ShowPrefix); + rdcart_end_date_edit->hide(); + rdcart_end_date_label->hide(); + + // + // Cart Artist + // + rdcart_controls.artist_edit=new QLineEdit(this,"rdcart_artist_edit"); + rdcart_controls.artist_edit->setGeometry(135,84,480,21); + rdcart_controls.artist_edit->setFont(line_edit_font); + rdcart_controls.artist_edit->setMaxLength(255); + QLabel *rdcart_artist_label=new QLabel(rdcart_controls.artist_edit,tr("&Artist:"), + this,"rdcart_artist_label"); + rdcart_artist_label->setGeometry(10,86,120,19); + rdcart_artist_label->setFont(button_font); + rdcart_artist_label->setAlignment(AlignRight|ShowPrefix); + + // + // Cart Origination Year + // + QIntValidator *val=new QIntValidator(this); + val->setBottom(1); + rdcart_controls.year_edit=new QLineEdit(this,"rdcart_year_edit"); + rdcart_controls.year_edit->setGeometry(135,110,50,21); + rdcart_controls.year_edit->setFont(line_edit_font); + rdcart_controls.year_edit->setValidator(val); + rdcart_controls.year_edit->setMaxLength(255); + QLabel *rdcart_year_label=new QLabel(rdcart_controls.year_edit, + tr("&Year Released:"),this, + "rdcart_year_label"); + rdcart_year_label->setGeometry(10,112,120,19); + rdcart_year_label->setFont(button_font); + rdcart_year_label->setAlignment(AlignRight|ShowPrefix); + + // + // Cart Usage Code + // + rdcart_usage_box=new QComboBox(this,"rdcart_usage_box"); + rdcart_usage_box->setGeometry(270,110,150,21); + if(lib_cart_list_edit!=0) { + rdcart_usage_box->insertItem(""); + } + for(int i=0;i<(int)RDCart::UsageLast;i++) { + rdcart_usage_box->insertItem(RDCart::usageText((RDCart::UsageCode)i)); + } + QLabel *label= + new QLabel(rdcart_usage_box,tr("U&sage:"),this,"rdcart_usage_label"); + label->setGeometry(195,112,70,19); + label->setFont(button_font); + label->setAlignment(AlignRight|ShowPrefix); + rdcart_usage_edit=new QLineEdit(this,"rdcart_usage_edit"); + rdcart_usage_edit->setGeometry(270,110,150,21); + rdcart_usage_edit->setReadOnly(true); + + // + // Scheduler Codes + // + QPushButton *sched_codes_button=new QPushButton(this,"sched_codes_button"); + sched_codes_button->setGeometry(470,106,150,28); + sched_codes_button->setDefault(true); + sched_codes_button->setFont(button_font); + sched_codes_button->setText(tr("Scheduler Codes")); + connect(sched_codes_button,SIGNAL(clicked()),this,SLOT(schedCodesData())); + + // + // Song ID + // + rdcart_controls.song_id_edit=new QLineEdit(this); + rdcart_controls.song_id_edit->setGeometry(135,135,240,21); + rdcart_controls.song_id_edit->setFont(line_edit_font); + rdcart_controls.song_id_edit->setMaxLength(32); + QLabel *rdcart_song_id_label= + new QLabel(rdcart_controls.song_id_edit,tr("Song &ID:"),this); + rdcart_song_id_label->setGeometry(10,135,120,21); + rdcart_song_id_label->setFont(button_font); + rdcart_song_id_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Beats per Minute + // + rdcart_controls.bpm_spin=new QSpinBox(this); + rdcart_controls.bpm_spin->setGeometry(515,135,100,21); + rdcart_controls.bpm_spin->setFont(line_edit_font); + rdcart_controls.bpm_spin->setRange(0,300); + rdcart_controls.bpm_spin->setSpecialValueText(tr("Unknown")); + QLabel *rdcart_bpm_label= + new QLabel(rdcart_controls.bpm_spin,tr("&Beats per Minute:"),this); + rdcart_bpm_label->setGeometry(390,135,120,21); + rdcart_bpm_label->setFont(button_font); + rdcart_bpm_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Cart Album + // + rdcart_controls.album_edit=new QLineEdit(this,"rdcart_album_edit"); + rdcart_controls.album_edit->setGeometry(135,158,480,21); + rdcart_controls.album_edit->setFont(line_edit_font); + rdcart_controls.album_edit->setMaxLength(64); + QLabel *rdcart_album_label=new QLabel(rdcart_controls.album_edit,tr("Al&bum:"),this, + "rdcart_album_label"); + rdcart_album_label->setGeometry(10,158,120,21); + rdcart_album_label->setFont(button_font); + rdcart_album_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Cart Label + // + rdcart_controls.label_edit=new QLineEdit(this,"rdcart_label_edit"); + rdcart_controls.label_edit->setGeometry(135,182,480,21); + rdcart_controls.label_edit->setFont(line_edit_font); + rdcart_controls.label_edit->setMaxLength(64); + QLabel *rdcart_label_label=new QLabel(rdcart_controls.label_edit,tr("Re&cord Label:"), + this,"rdcart_label_label"); + rdcart_label_label->setGeometry(10,182,120,21); + rdcart_label_label->setFont(button_font); + rdcart_label_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Cart Client + // + rdcart_controls.client_edit=new QLineEdit(this,"rdcart_client_edit"); + rdcart_controls.client_edit->setGeometry(135,206,480,21); + rdcart_controls.client_edit->setFont(line_edit_font); + rdcart_controls.client_edit->setMaxLength(64); + QLabel *rdcart_client_label=new QLabel(rdcart_controls.label_edit,tr("C&lient:"),this, + "rdcart_client_label"); + rdcart_client_label->setGeometry(10,206,120,21); + rdcart_client_label->setFont(button_font); + rdcart_client_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Cart Agency + // + rdcart_controls.agency_edit=new QLineEdit(this,"rdcart_agency_edit"); + rdcart_controls.agency_edit->setGeometry(135,230,480,21); + rdcart_controls.agency_edit->setFont(line_edit_font); + rdcart_controls.agency_edit->setMaxLength(64); + QLabel *rdcart_agency_label=new QLabel(rdcart_controls.label_edit,tr("A&gency:"),this, + "rdcart_agency_label"); + rdcart_agency_label->setGeometry(10,230,120,21); + rdcart_agency_label->setFont(button_font); + rdcart_agency_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Cart Publisher + // + rdcart_controls.publisher_edit=new QLineEdit(this,"rdcart_publisher_edit"); + rdcart_controls.publisher_edit->setGeometry(135,254,480,21); + rdcart_controls.publisher_edit->setFont(line_edit_font); + rdcart_controls.publisher_edit->setMaxLength(64); + QLabel *rdcart_publisher_label=new QLabel(rdcart_controls.label_edit, + tr("&Publisher:"),this, + "rdcart_publisher_label"); + rdcart_publisher_label->setGeometry(10,254,120,21); + rdcart_publisher_label->setFont(button_font); + rdcart_publisher_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Cart Composer + // + rdcart_controls.composer_edit=new QLineEdit(this,"rdcart_composer_edit"); + rdcart_controls.composer_edit->setGeometry(135,278,480,21); + rdcart_controls.composer_edit->setFont(line_edit_font); + rdcart_controls.composer_edit->setMaxLength(64); + QLabel *rdcart_composer_label=new QLabel(rdcart_controls.label_edit, + tr("Compos&er:"),this, + "rdcart_composer_label"); + rdcart_composer_label->setGeometry(10,278,120,21); + rdcart_composer_label->setFont(button_font); + rdcart_composer_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Cart Conductor + // + rdcart_controls.conductor_edit=new QLineEdit(this,"rdcart_conductor_edit"); + rdcart_controls.conductor_edit->setGeometry(135,302,480,21); + rdcart_controls.conductor_edit->setFont(line_edit_font); + rdcart_controls.conductor_edit->setMaxLength(255); + QLabel *rdcart_conductor_label= + new QLabel(rdcart_controls.label_edit,tr("Cond&uctor:"),this, + "rdcart_conductor_label"); + rdcart_conductor_label->setGeometry(10,302,120,21); + rdcart_conductor_label->setFont(button_font); + rdcart_conductor_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Cart User Defined + // + rdcart_controls.user_defined_edit=new QLineEdit(this); + rdcart_controls.user_defined_edit->setGeometry(135,325,480,21); + rdcart_controls.user_defined_edit->setFont(line_edit_font); + rdcart_controls.user_defined_edit->setMaxLength(255); + QLabel *rdcart_user_defined_label= + new QLabel(rdcart_controls.label_edit,tr("&User Defined:"),this, + "rdcart_user_defined_label"); + rdcart_user_defined_label->setGeometry(10,325,120,21); + rdcart_user_defined_label->setFont(button_font); + rdcart_user_defined_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Synchronous Scheduling Policy + // + rdcart_syncronous_box=new QCheckBox(this,"rdcart_syncronous_box"); + rdcart_syncronous_box->setGeometry(135,351,15,15); + connect(rdcart_syncronous_box,SIGNAL(toggled(bool)), + this,SLOT(asyncronousToggledData(bool))); + rdcart_syncronous_box->hide(); + QLabel *rdcart_syncronous_label=new QLabel(rdcart_syncronous_box, + tr("Execute Asynchronously"),this, + "rdcart_syncronous_label"); + rdcart_syncronous_label->setGeometry(155,351,200,19); + rdcart_syncronous_label->setFont(button_font); + rdcart_syncronous_label->setAlignment(AlignLeft|ShowPrefix); + rdcart_syncronous_label->hide(); + + // + // Use Event Length Policy + // + rdcart_use_event_length_box=new QCheckBox(this); + rdcart_use_event_length_box->setGeometry(330,351,15,15); + connect(rdcart_use_event_length_box,SIGNAL(toggled(bool)), + this,SLOT(asyncronousToggledData(bool))); + rdcart_use_event_length_box->hide(); + QLabel *rdcart_use_event_length_label= + new QLabel(rdcart_use_event_length_box, + tr("Use Event Length for Now && Next Updates"),this); + rdcart_use_event_length_label->setGeometry(350,351,sizeHint().width()-350,19); + rdcart_use_event_length_label->setFont(button_font); + rdcart_use_event_length_label->setAlignment(AlignLeft|ShowPrefix); + rdcart_use_event_length_label->hide(); + + // + // Notes Button + // + rdcart_notes_button=new QPushButton(this,"rdcart_notes_button"); + // rdcart_notes_button->setGeometry(360,304,80,50); + rdcart_notes_button->setGeometry(10,sizeHint().height()-60,80,50); + rdcart_notes_button->setFont(button_font); + rdcart_notes_button->setText(tr("&Edit\nNotes")); + connect(rdcart_notes_button,SIGNAL(clicked()),this,SLOT(notesData())); + + // + // Script Button + // + QPushButton *script_button=new QPushButton(this,"script_button"); + script_button->setGeometry(450,304,80,50); + script_button->setFont(button_font); + script_button->setText(tr("&Edit\nScript")); + connect(script_button,SIGNAL(clicked()),this,SLOT(scriptData())); + script_button->hide(); + + if(lib_cart_list_edit==NULL) { + // + // Cut Widget + // + switch(rdcart_cart->type()) { + case RDCart::Audio: + rdcart_audio_cart=new AudioCart(&rdcart_controls,rdcart_cart, + rdcart_import_path,new_cart, + rdcart_profile_rip,this); + rdcart_audio_cart-> + setGeometry(0,378,rdcart_audio_cart->sizeHint().width(), + rdcart_audio_cart->sizeHint().height()); + connect(rdcart_audio_cart,SIGNAL(cartDataChanged()), + this,SLOT(cartDataChangedData())); + rdcart_macro_cart=NULL; + break; + + case RDCart::Macro: + rdcart_macro_cart=new MacroCart(rdcart_cart,this,"rdcart_macro_cart"); + rdcart_macro_cart-> + setGeometry(0,378,rdcart_macro_cart->sizeHint().width(), + rdcart_macro_cart->sizeHint().height()); + connect(rdcart_macro_cart,SIGNAL(lengthChanged(unsigned)), + this,SLOT(lengthChangedData(unsigned))); + rdcart_audio_cart=NULL; + rdcart_controls.enforce_length_box->setDisabled(true); + rdcart_enforce_length_label->setDisabled(true); + rdcart_syncronous_box->show(); + rdcart_use_event_length_box->show(); + rdcart_syncronous_label->show(); + rdcart_use_event_length_label->show(); + break; + + default: + break; + } + } + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + if(lib_cart_list_edit==NULL) + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + else + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60-270,80,50); + ok_button->setDefault(true); + ok_button->setFont(button_font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + if(lib_cart_list_edit==NULL) + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + else + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60-270, + 80,50); + cancel_button->setFont(button_font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + if(lib_cart_list_edit==NULL) { //single edit + rdcart_number_edit-> + setText(QString().sprintf("%06d",rdcart_cart->number())); + if(rdcart_group_box->count() == 0) + { + PopulateGroupList(); + for(int i=0;icount();i++) { + if(rdcart_group_box->text(i)==rdcart_cart->groupName()) { + rdcart_group_box->setCurrentItem(i); + } + } + rdcart_group_edit->setText(rdcart_cart->groupName()); + } + switch(rdcart_cart->type()) { + case RDCart::Audio: + rdcart_type_edit->setText(tr("AUDIO")); + break; + + case RDCart::Macro: + rdcart_type_edit->setText(tr("MACRO")); + rdcart_controls.enforce_length_box->setDisabled(true); + rdcart_enforce_length_label->setDisabled(true); + break; + + default: + rdcart_type_edit->setText(tr("UNKNOWN")); + break; + } + rdcart_controls.enforce_length_box->setChecked(rdcart_cart->enforceLength()); + forcedLengthData(rdcart_controls.enforce_length_box->isChecked()); + if(lib_cart_list_edit==NULL) { + rdcart_average_length_edit-> + setText(RDGetTimeLength(rdcart_cart->averageLength())); + } + rdcart_controls.forced_length_edit-> + setTime(QTime().addMSecs(rdcart_cart->forcedLength())); + rdcart_forced_length_ledit-> + setText(rdcart_controls.forced_length_edit->time().toString("hh:mm:ss")); + if(rdcart_cart->preservePitch()) { + rdcart_preserve_pitch_button->setChecked(true); + } + rdcart_preserve_pitch_button-> + setEnabled(rdcart_controls.enforce_length_box->isChecked()); + rdcart_preserve_pitch_label-> + setEnabled(rdcart_controls.enforce_length_box->isChecked()); + rdcart_controls.title_edit->setText(rdcart_cart->title()); + if(!rdcart_cart->startDateTime().isNull()) { + rdcart_start_date_edit-> + setText(rdcart_cart->startDateTime().toString("M/d/yyyy")); + } + if(!rdcart_cart->endDateTime().isNull()) { + rdcart_end_date_edit-> + setText(rdcart_cart->endDateTime().toString("M/d/yyyy")); + } + else { + rdcart_end_date_edit->setText(tr("TFN")); + } + if(rdcart_cart->year()>0) { + rdcart_controls.year_edit-> + setText(QString().sprintf("%d",rdcart_cart->year())); + } + sched_codes=rdcart_cart->schedCodes(); + rdcart_controls.artist_edit->setText(rdcart_cart->artist()); + rdcart_controls.song_id_edit->setText(rdcart_cart->songId()); + rdcart_controls.bpm_spin->setValue(rdcart_cart->beatsPerMinute()); + rdcart_controls.album_edit->setText(rdcart_cart->album()); + rdcart_controls.label_edit->setText(rdcart_cart->label()); + rdcart_controls.client_edit->setText(rdcart_cart->client()); + rdcart_controls.agency_edit->setText(rdcart_cart->agency()); + rdcart_controls.publisher_edit->setText(rdcart_cart->publisher()); + rdcart_controls.conductor_edit->setText(rdcart_cart->conductor()); + rdcart_controls.composer_edit->setText(rdcart_cart->composer()); + rdcart_controls.user_defined_edit->setText(rdcart_cart->userDefined()); + rdcart_usage_box->setCurrentItem((int)rdcart_cart->usageCode()); + rdcart_usage_edit-> + setText(RDCart::usageText((RDCart::UsageCode)rdcart_usage_box-> + currentItem())); + rdcart_syncronous_box->setChecked(rdcart_cart->asyncronous()); + rdcart_use_event_length_box-> + setChecked(rdcart_cart->useEventLength()); + } + else {//multi edit + if(rdcart_group_box->count() == 0) { + rdcart_group_box->insertItem(""); + PopulateGroupList(); + rdcart_group_box->setCurrentItem(0); + } + rdcart_usage_box->setCurrentItem(0); + rdcart_notes_button->hide(); + } + + // + // Set Control Perms + // + if(modification_allowed) { + rdcart_group_edit->hide(); + rdcart_usage_edit->hide(); + } + else { + rdcart_group_box->hide(); + rdcart_usage_box->hide(); + } + rdcart_syncronous_box->setEnabled(modification_allowed); + rdcart_use_event_length_box->setEnabled(modification_allowed); + rdcart_controls.title_edit->setReadOnly(!modification_allowed); + rdcart_controls.artist_edit->setReadOnly(!modification_allowed); + rdcart_controls.song_id_edit->setReadOnly(!modification_allowed); + rdcart_controls.album_edit->setReadOnly(!modification_allowed); + rdcart_controls.year_edit->setReadOnly(!modification_allowed); + rdcart_controls.label_edit->setReadOnly(!modification_allowed); + rdcart_controls.client_edit->setReadOnly(!modification_allowed); + rdcart_controls.agency_edit->setReadOnly(!modification_allowed); + rdcart_controls.publisher_edit->setReadOnly(!modification_allowed); + rdcart_controls.conductor_edit->setReadOnly(!modification_allowed); + rdcart_controls.composer_edit->setReadOnly(!modification_allowed); + rdcart_controls.user_defined_edit->setReadOnly(!modification_allowed); + rdcart_start_date_edit->setReadOnly(!modification_allowed); + rdcart_end_date_edit->setReadOnly(!modification_allowed); + rdcart_notes_button->setEnabled(modification_allowed); + if(lib_cart_list_edit==NULL) { + rdcart_average_length_edit-> + setReadOnly((!modification_allowed)|| + (!rdcart_controls.enforce_length_box->isChecked())); + if(rdcart_cart->type()!=RDCart::Audio) { + rdcart_controls.enforce_length_box->setDisabled(true); + } + else { + rdcart_controls.enforce_length_box->setEnabled(modification_allowed); + } + } + if(modification_allowed) { + rdcart_controls.bpm_spin->setRange(0,200); + } + else { + rdcart_controls.bpm_spin-> + setRange(rdcart_cart->beatsPerMinute(),rdcart_cart->beatsPerMinute()); + rdcart_controls.forced_length_edit->hide(); + rdcart_forced_length_ledit->show(); + } +} + + +EditCart::~EditCart() +{ + if(rdcart_cart!=NULL) { + delete rdcart_cart; + } +} + + +QSize EditCart::sizeHint() const +{ + return QSize(640,750); +} + + +QSizePolicy EditCart::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditCart::notesData() +{ + EditNotes *d=new EditNotes(rdcart_cart,this); + d->exec(); + delete d; +} + + +void EditCart::scriptData() +{ +} + + +void EditCart::lengthChangedData(unsigned len) +{ + if(!rdcart_syncronous_box->isChecked()) { + rdcart_average_length_edit->setText(RDGetTimeLength(len)); + rdcart_cart->calculateAverageLength(&rdcart_length_deviation); + } +} + + +void EditCart::okData() +{ + QListViewItemIterator *it; + RDCart *rdcart_cart_medit; + RDSystem *system; + QString sql; + RDSqlQuery *q; + + if(lib_cart_list_edit==NULL) { // Single Edit + if(rdcart_controls.title_edit->text().isEmpty()) { + QMessageBox::warning(this,tr("Missing Title"), + tr("You must provide at least a Cart Title!")); + return; + } + system=new RDSystem(); + if(!system->allowDuplicateCartTitles()) { + sql=QString("select NUMBER from CART where ")+ + "(TITLE=\""+RDEscapeString(rdcart_controls.title_edit->text())+"\") &&"+ + QString().sprintf("(NUMBER=%u)",rdcart_cart->number()); + q=new RDSqlQuery(sql); + if(q->first()) { + QMessageBox::warning(this,tr("Duplicate Title"), + tr("The cart title must be unique!")); + delete q; + delete system; + return; + } + delete q; + } + delete system; + if(rdcart_controls.enforce_length_box->isChecked()) { + if(!ValidateLengths()) { + switch(QMessageBox::warning(this,tr("Length Mismatch"), + tr("One or more cut lengths exceed the timescaling\nlimits of the system! Do you still want to save?"),QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + return; + + default: + break; + } + } + } + rdcart_cart->setGroupName(rdcart_group_box->currentText()); + rdcart_cart->calculateAverageLength(&rdcart_length_deviation); + rdcart_cart->setLengthDeviation(rdcart_length_deviation); + rdcart_cart->updateLength(rdcart_controls.enforce_length_box->isChecked(), + QTime().msecsTo(rdcart_controls. + forced_length_edit->time())); + rdcart_cart-> + setAverageLength(RDSetTimeLength(rdcart_average_length_edit->text())); + if(rdcart_controls.enforce_length_box->isChecked()) { + rdcart_cart-> + setForcedLength(QTime().msecsTo(rdcart_controls.forced_length_edit->time())); + rdcart_cart->setEnforceLength(true); + } + else { + rdcart_cart-> + setForcedLength(RDSetTimeLength(rdcart_average_length_edit->text())); + rdcart_cart->setEnforceLength(false); + } + rdcart_cart->setPreservePitch(rdcart_preserve_pitch_button->isChecked()); + rdcart_cart->setTitle(rdcart_controls.title_edit->text()); + if(rdcart_controls.year_edit->text().toInt()==0) { + rdcart_cart->setYear(); + } + else { + rdcart_cart->setYear(rdcart_controls.year_edit->text().toInt()); + } + rdcart_cart->setSchedCodes(sched_codes); + rdcart_cart->setArtist(rdcart_controls.artist_edit->text()); + rdcart_cart->setSongId(rdcart_controls.song_id_edit->text()); + rdcart_cart->setBeatsPerMinute(rdcart_controls.bpm_spin->value()); + rdcart_cart->setAlbum(rdcart_controls.album_edit->text()); + rdcart_cart->setLabel(rdcart_controls.label_edit->text()); + rdcart_cart->setClient(rdcart_controls.client_edit->text()); + rdcart_cart->setAgency(rdcart_controls.agency_edit->text()); + rdcart_cart->setPublisher(rdcart_controls.publisher_edit->text()); + rdcart_cart->setConductor(rdcart_controls.conductor_edit->text()); + rdcart_cart->setComposer(rdcart_controls.composer_edit->text()); + rdcart_cart->setUserDefined(rdcart_controls.user_defined_edit->text()); + rdcart_cart-> + setUsageCode((RDCart::UsageCode)rdcart_usage_box->currentItem()); + if(rdcart_cart->type()==RDCart::Macro) { + rdcart_macro_cart->save(); + rdcart_cart->setAsyncronous(rdcart_syncronous_box->isChecked()); + rdcart_cart->setUseEventLength(rdcart_use_event_length_box->isChecked()); + } + } + else { // Multi Edit + it=new QListViewItemIterator(lib_cart_list_edit); + while(it->current()) { + if(it->current()->isSelected()) { + RDListViewItem *item=(RDListViewItem *)it->current(); + if(item->text(21).isEmpty()) { + + rdcart_cart_medit=new RDCart(item->text(1).toUInt()); + + if(!rdcart_group_box->currentText().stripWhiteSpace().isEmpty()) { + rdcart_cart_medit->setGroupName(rdcart_group_box->currentText()); + } + if(!rdcart_controls.title_edit->text().stripWhiteSpace().isEmpty()) { + rdcart_cart_medit->setTitle(rdcart_controls.title_edit->text()); + } + rdcart_cart_medit->setYear(rdcart_controls.year_edit->text().toInt()); + if(!rdcart_controls.artist_edit->text().stripWhiteSpace().isEmpty()) { + rdcart_cart_medit->setArtist(rdcart_controls.artist_edit->text()); + } + if(!rdcart_controls.album_edit->text().stripWhiteSpace().isEmpty()) { + rdcart_cart_medit->setAlbum(rdcart_controls.album_edit->text()); + } + if(!rdcart_controls.label_edit->text().stripWhiteSpace().isEmpty()) { + rdcart_cart_medit->setLabel(rdcart_controls.label_edit->text()); + } + if(!rdcart_controls.client_edit->text().stripWhiteSpace().isEmpty()) { + rdcart_cart_medit->setClient(rdcart_controls.client_edit->text()); + } + if(!rdcart_controls.agency_edit->text().stripWhiteSpace().isEmpty()) { + rdcart_cart_medit->setAgency(rdcart_controls.agency_edit->text()); + } + if(!rdcart_controls.song_id_edit-> + text().stripWhiteSpace().isEmpty()) { + rdcart_cart_medit-> + setSongId(rdcart_controls.song_id_edit->text()); + } + if(!rdcart_controls.publisher_edit->text().stripWhiteSpace(). + isEmpty()) { + rdcart_cart_medit-> + setPublisher(rdcart_controls.publisher_edit->text()); + } + if(!rdcart_controls.composer_edit-> + text().stripWhiteSpace().isEmpty()) { + rdcart_cart_medit-> + setComposer(rdcart_controls.composer_edit->text()); + } + if(!rdcart_controls.conductor_edit->text(). + stripWhiteSpace().isEmpty()) { + rdcart_cart_medit-> + setConductor(rdcart_controls.conductor_edit->text()); + } + if(!rdcart_controls.user_defined_edit->text(). + stripWhiteSpace().isEmpty()) { + rdcart_cart_medit-> + setUserDefined(rdcart_controls.user_defined_edit->text()); + } + if(!rdcart_usage_box->currentText().stripWhiteSpace().isEmpty()) { + rdcart_cart_medit->setUsageCode((RDCart::UsageCode) + (rdcart_usage_box->currentItem()-1)); + } + rdcart_cart_medit->updateSchedCodes(add_codes,remove_codes); + delete rdcart_cart_medit; + } + } + ++(*it); + } + delete it; + } + + done(0); +} + + +void EditCart::cancelData() +{ + unsigned len; + if((lib_cart_list_edit==NULL)&&(rdcart_cart->type()==RDCart::Audio)) { + len=rdcart_cart->calculateAverageLength(&rdcart_length_deviation); + rdcart_cart->setLengthDeviation(rdcart_length_deviation); + if(!rdcart_controls.enforce_length_box->isChecked()) { + rdcart_cart->setForcedLength(len); + } + rdcart_cart->updateLength(rdcart_controls.enforce_length_box->isChecked(), + QTime().msecsTo(rdcart_controls. + forced_length_edit->time())); + } + done(-1); +} + + +void EditCart::forcedLengthData(bool state) +{ + rdcart_forced_length_label->setEnabled(state); + rdcart_controls.forced_length_edit->setEnabled(state); + if(state) { + rdcart_controls.forced_length_edit-> + setTime(QTime(). + addMSecs(RDSetTimeLength(rdcart_average_length_edit->text()))); + } +} + + +void EditCart::asyncronousToggledData(bool state) +{ + if(state) { + rdcart_average_length_edit->setText("00.0"); + } + else { + rdcart_average_length_edit-> + setText(RDGetTimeLength(rdcart_macro_cart->length())); + } +} + + +void EditCart::cartDataChangedData() +{ + if(!rdcart_controls.enforce_length_box->isChecked()) { + rdcart_average_length_edit-> + setText(RDGetTimeLength(rdcart_cart->calculateAverageLength())); + } +} + + +void EditCart::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +bool EditCart::ValidateLengths() +{ + return rdcart_cart->validateLengths(QTime(). + msecsTo(rdcart_controls.forced_length_edit->time())); + /* + int maxlen=(int)(RD_TIMESCALE_MAX* + (double)QTime().msecsTo(rdcart_controls.forced_length_edit-> + time())); + int minlen=(int)(RD_TIMESCALE_MIN* + (double)QTime().msecsTo(rdcart_controls.forced_length_edit-> + time())); + QString sql=QString().sprintf("select LENGTH from CUTS where CART_NUMBER=%u", + rdcart_cart->number()); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + if((q->value(0).toInt()>maxlen)||(q->value(0).toInt()exec(); + delete dialog; + } + else { + EditSchedulerCodes *dialog=new EditSchedulerCodes(&add_codes,&remove_codes,this,"dialog"); + dialog->exec(); + delete dialog; + } +} + + +void EditCart::PopulateGroupList() +{ + QString sql=QString("select GROUP_NAME from USER_PERMS where ")+ + "USER_NAME=\""+RDEscapeString(lib_user->name())+"\" "+ + "order by GROUP_NAME"; + + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + rdcart_group_box->insertItem(q->value(0).toString()); + } + delete q; +} diff --git a/rdlibrary/edit_cart.h b/rdlibrary/edit_cart.h new file mode 100644 index 00000000..ff979039 --- /dev/null +++ b/rdlibrary/edit_cart.h @@ -0,0 +1,108 @@ +// edit_cart.h +// +// Edit a Rivendell Cart +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: edit_cart.h,v 1.30.2.2 2014/01/13 23:02:42 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_CART_H +#define EDIT_CART_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +class EditCart : public QDialog +{ + Q_OBJECT + public: + EditCart(unsigned number,QString *path,bool new_cart,bool profile_rip, + QWidget *parent=0,const char *name=0,QListView *lib_cart_list=NULL); + ~EditCart(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void notesData(); + void scriptData(); + void lengthChangedData(unsigned len); + void okData(); + void cancelData(); + void forcedLengthData(bool); + void asyncronousToggledData(bool state); + void cartDataChangedData(); + void schedCodesData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + void PopulateGroupList(); + QListView *lib_cart_list_edit; + bool ValidateLengths(); + RDCart *rdcart_cart; + QLineEdit *rdcart_type_edit; + QLineEdit *rdcart_number_edit; + QComboBox *rdcart_group_box; + QLineEdit *rdcart_group_edit; + AudioControls rdcart_controls; + QCheckBox *rdcart_syncronous_box; + QCheckBox *rdcart_use_event_length_box; + QLabel *rdcart_syncronous_label; + QLineEdit *rdcart_start_date_edit; + QLineEdit *rdcart_end_date_edit; + QLineEdit *rdcart_average_length_edit; + QLabel *rdcart_forced_length_label; + QLineEdit *rdcart_forced_length_ledit; + QCheckBox *rdcart_preserve_pitch_button; + QLabel *rdcart_preserve_pitch_label; + unsigned rdcart_average_length; + unsigned rdcart_length_deviation; + AudioCart *rdcart_audio_cart; + MacroCart *rdcart_macro_cart; + QString *rdcart_import_path; + bool rdcart_new_cart; + QComboBox *rdcart_usage_box; + QLineEdit *rdcart_usage_edit; + QPushButton *rdcart_notes_button; + QString sched_codes; + QString add_codes; + QString remove_codes; + bool rdcart_profile_rip; +}; + +#endif + diff --git a/rdlibrary/edit_macro.cpp b/rdlibrary/edit_macro.cpp new file mode 100644 index 00000000..2fd57f98 --- /dev/null +++ b/rdlibrary/edit_macro.cpp @@ -0,0 +1,130 @@ +// edit_macro.cpp +// +// Edit a Rivendell Macro +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_macro.cpp,v 1.11.8.2 2013/12/23 22:04:02 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include + +#include + + +EditMacro::EditMacro(RDMacro *cmd,bool highlight, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + + setCaption(tr("Edit Macro")); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Macro + // + edit_macro=cmd; + + edit_macro_edit=new QLineEdit(this,"edit_macro_edit"); + edit_macro_edit->setMaxLength(RD_RML_MAX_LENGTH-1); + edit_macro_edit->setValidator(validator); + + // + // Ok Button + // + edit_ok_button=new QPushButton(this,"ok_button"); + edit_ok_button->setDefault(true); + edit_ok_button->setFont(button_font); + edit_ok_button->setText(tr("&OK")); + connect(edit_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + edit_cancel_button=new QPushButton(this,"cancel_button"); + edit_cancel_button->setFont(button_font); + edit_cancel_button->setText(tr("&Cancel")); + connect(edit_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + char cmdstr[RD_RML_MAX_LENGTH]; + edit_macro->generateString(cmdstr,RD_RML_MAX_LENGTH); + edit_macro_edit->setText(cmdstr); + if(highlight) { + edit_macro_edit->selectAll(); + } +} + + +QSize EditMacro::sizeHint() const +{ + return QSize(400,110); +} + + +QSizePolicy EditMacro::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditMacro::okData() +{ + edit_macro->parseString((const char *)edit_macro_edit->text(), + edit_macro_edit->text().length()); + done(0); +} + + +void EditMacro::cancelData() +{ + done(-1); +} + + +void EditMacro::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void EditMacro::resizeEvent(QResizeEvent *e) +{ + edit_macro_edit->setGeometry(10,11,size().width()-20,19); + edit_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + edit_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} diff --git a/rdlibrary/edit_macro.h b/rdlibrary/edit_macro.h new file mode 100644 index 00000000..5032e19d --- /dev/null +++ b/rdlibrary/edit_macro.h @@ -0,0 +1,59 @@ +// edit_macro.h +// +// Edit a Rivendell Macro +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_macro.h,v 1.8.8.2 2013/12/23 22:04:03 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_MACRO_H +#define EDIT_MACRO_H + +#include +#include +#include + +#include +#include + + +class EditMacro : public QDialog +{ + Q_OBJECT + public: + EditMacro(RDMacro *cmd,bool highlight,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + void resizeEvent(QResizeEvent *e); + + private: + QLineEdit *edit_macro_edit; + QPushButton *edit_ok_button; + QPushButton *edit_cancel_button; + RDMacro *edit_macro; +}; + + +#endif + diff --git a/rdlibrary/edit_notes.cpp b/rdlibrary/edit_notes.cpp new file mode 100644 index 00000000..d3ba82f9 --- /dev/null +++ b/rdlibrary/edit_notes.cpp @@ -0,0 +1,109 @@ +// edit_notes.cpp +// +// Edit Cart Notes. +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: edit_notes.cpp,v 1.3.4.1 2014/03/19 22:12:59 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include + +EditNotes::EditNotes(RDCart *cart,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + notes_cart=cart; + setCaption("RDLibrary - "+tr("Notes for cart")+ + QString().sprintf(" %06u - ",cart->number())+cart->title()); + + // + // Create Fonts + // + QFont button_font=QFont("helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Variable Name + // + notes_view=new QTextView(this,"notes_view"); + notes_view->setTextFormat(QTextView::PlainText); + notes_view->setReadOnly(false); + + // + // Ok Button + // + notes_ok_button=new QPushButton(this,"notes_ok_button"); + notes_ok_button->setDefault(true); + notes_ok_button->setFont(button_font); + notes_ok_button->setText(tr("&OK")); + notes_ok_button->setDefault(true); + connect(notes_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + notes_cancel_button=new QPushButton(this,"notes_cancel_button"); + notes_cancel_button->setFont(button_font); + notes_cancel_button->setText(tr("&Cancel")); + connect(notes_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Data + // + notes_view->setText(notes_cart->notes()); +} + + +QSize EditNotes::sizeHint() const +{ + return QSize(640,480); +} + + +QSizePolicy EditNotes::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditNotes::resizeEvent(QResizeEvent *e) +{ + notes_view->setGeometry(10,10,size().width()-20,size().height()-80); + notes_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + notes_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void EditNotes::okData() +{ + notes_cart->setNotes(notes_view->text().stripWhiteSpace()); + done(0); +} + + +void EditNotes::cancelData() +{ + done(-1); +} diff --git a/rdlibrary/edit_notes.h b/rdlibrary/edit_notes.h new file mode 100644 index 00000000..b1d61f22 --- /dev/null +++ b/rdlibrary/edit_notes.h @@ -0,0 +1,56 @@ +// edit_notes.h +// +// Edit Cart Notes. +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: edit_notes.h,v 1.2 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_NOTES_H +#define EDIT_NOTES_H + +#include +#include +#include +#include + +#include + +class EditNotes : public QDialog +{ + Q_OBJECT + public: + EditNotes(RDCart *cart,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + void resizeEvent(QResizeEvent *e); + + private slots: + void okData(); + void cancelData(); + + private: + QTextView *notes_view; + QPushButton *notes_ok_button; + QPushButton *notes_cancel_button; + RDCart *notes_cart; +}; + + +#endif // EDIT_NOTES_H diff --git a/rdlibrary/edit_schedulercodes.cpp b/rdlibrary/edit_schedulercodes.cpp new file mode 100644 index 00000000..18a61444 --- /dev/null +++ b/rdlibrary/edit_schedulercodes.cpp @@ -0,0 +1,209 @@ +// edit_schedulercodes.cpp +// +// Edit the scheduler codes of a cart +// +// Stefan Gabriel +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include + + +EditSchedulerCodes::EditSchedulerCodes(QString *sched_codes,QString *remove_codes,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_sched_codes=sched_codes; + edit_remove_codes=remove_codes; + + QString sql; + RDSqlQuery *q; + QString str; + + // + // Fix the Window Size + // + if(edit_remove_codes==NULL) { + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + } + else { + setMinimumWidth(2*sizeHint().width()); + setMaximumWidth(2*sizeHint().width()); + } + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Select Scheduler Codes")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",11,QFont::Bold); + font.setPixelSize(11); + + QFont listfont=QFont("Helvetica",11); + font.setPixelSize(11); + + + // + // Services Selector + // + codes_sel=new RDListSelector(this,"codes_sel"); + codes_sel->setFont(listfont); + codes_sel->setGeometry(10,10,380,200); + codes_sel->sourceSetLabel(tr("Available Codes")); + if(edit_remove_codes==NULL) { + codes_sel->destSetLabel(tr("Assigned Codes")); + } + else { + codes_sel->destSetLabel(tr("ASSIGN to Carts")); + + remove_codes_sel=new RDListSelector(this,"codes_sel"); + remove_codes_sel->setFont(listfont); + remove_codes_sel->setGeometry(sizeHint().width()+10,10,380,200); + remove_codes_sel->sourceSetLabel(tr("Available Codes")); + remove_codes_sel->destSetLabel(tr("REMOVE from Carts")); + } + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + if(edit_remove_codes==NULL) + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + else + ok_button->setGeometry(2*sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + if(edit_remove_codes==NULL) + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + else + cancel_button->setGeometry(2*sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + + for(unsigned i=0;ilength()/11;i++) { + codes_sel->destInsertItem(edit_sched_codes->mid(i*11,11).stripWhiteSpace()); + } + if(edit_remove_codes!=NULL) { + for(unsigned i=0;ilength()/11;i++) { + remove_codes_sel->destInsertItem(remove_codes->mid(i*11,11).stripWhiteSpace()); + } + } + + sql=QString().sprintf("select CODE from SCHED_CODES"); + q=new RDSqlQuery(sql); + while(q->next()) { + if(codes_sel->destFindItem(q->value(0).toString())==0) { + codes_sel->sourceInsertItem(q->value(0).toString()); + } + if(edit_remove_codes!=NULL) { + if(remove_codes_sel->destFindItem(q->value(0).toString())==0) { + remove_codes_sel->sourceInsertItem(q->value(0).toString()); + } + } + } + delete q; +} + + +EditSchedulerCodes::~EditSchedulerCodes() +{ +} + + +QSize EditSchedulerCodes::sizeHint() const +{ + return QSize(400,292); +} + + +QSizePolicy EditSchedulerCodes::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditSchedulerCodes::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->moveTo(sizeHint().width(),10); + p->lineTo(sizeHint().width(),210); + p->end(); +} + + +void EditSchedulerCodes::okData() +{ + *edit_sched_codes=""; + // + // Add New Objects + // + for(unsigned i=0;idestCount();i++) { + *edit_sched_codes+=codes_sel->destText(i).append(" ").left(11); + } + if (edit_sched_codes->length()>254) + { + QMessageBox::information(this,"Warning","There is a maximum of 23 Codes per Cart!",QMessageBox::Ok); + *edit_sched_codes=edit_sched_codes->left(253); + } + *edit_sched_codes+="."; + + if(edit_remove_codes!=NULL) { + *edit_remove_codes=""; + for(unsigned i=0;idestCount();i++) { + *edit_remove_codes+=remove_codes_sel->destText(i).append(" ").left(11); + } + if (edit_remove_codes->length()>254) + { + QMessageBox::information(this,"Warning","There is a maximum of 23 Codes per Cart!",QMessageBox::Ok); + *edit_remove_codes=edit_remove_codes->left(253); + } + *edit_remove_codes+="."; + } + + done(0); +} + + +void EditSchedulerCodes::cancelData() +{ + done(-1); +} + + + + diff --git a/rdlibrary/edit_schedulercodes.h b/rdlibrary/edit_schedulercodes.h new file mode 100644 index 00000000..22b9f281 --- /dev/null +++ b/rdlibrary/edit_schedulercodes.h @@ -0,0 +1,56 @@ +// edit_schedulercodes.h +// +// Edit the scheduler codes of a cart +// +// Stefan Gabriel +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_SCHEDULERCODES_H +#define EDIT_SCHEDULERCODES_H + +#include +#include +#include + +#include + +class EditSchedulerCodes : public QDialog +{ + Q_OBJECT + public: + EditSchedulerCodes(QString *sched_codes,QString *remove_codes,QWidget *parent=0,const char *name=0); + ~EditSchedulerCodes(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + void paintEvent(QPaintEvent *e); + + private slots: + void okData(); + void cancelData(); + + private: + RDListSelector *codes_sel; + RDListSelector *remove_codes_sel; + QString *edit_sched_codes; + QString *edit_remove_codes; +}; + + + +#endif + diff --git a/rdlibrary/filter.cpp b/rdlibrary/filter.cpp new file mode 100644 index 00000000..c308bff9 --- /dev/null +++ b/rdlibrary/filter.cpp @@ -0,0 +1,133 @@ +// filter.cpp +// +// Set Filter widget for RDLibrary. +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: filter.cpp,v 1.11 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +Filter::Filter(QString *filter,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont button_font=QFont("Helvetica",14,QFont::Bold); + button_font.setPixelSize(14); + + filter_text=filter; + setCaption(tr("Library Filter")); + + // + // OK Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(15,40,100,55); + ok_button->setFont(button_font); + ok_button->setText(tr("&OK")); + ok_button->setDefault(true); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Clear Button + // + QPushButton *clear_button=new QPushButton(this,"clear_button"); + clear_button->setGeometry(125,40,100,55); + clear_button->setFont(button_font); + clear_button->setText(tr("C&lear")); + connect(clear_button,SIGNAL(clicked()),this,SLOT(clearData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(235,40,100,55); + cancel_button->setFont(button_font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Filter Text + // + filter_text_edit=new QLineEdit(this,"filter_text_edit"); + filter_text_edit->setGeometry(65,10,275,19); + filter_text_edit->setMaxLength(16); + filter_text_edit->setFocus(); + filter_text_edit->setFont(QFont("Helvetica",14,QFont::Normal)); + filter_text_edit->setText(*filter); + QLabel *filter_text_label=new QLabel(filter_text_edit,tr("&Filter:"),this, + "filter_text_label"); + filter_text_label->setGeometry(10,12,50,19); + filter_text_label->setFont(label_font); + filter_text_label->setAlignment(AlignRight|ShowPrefix); +} + + +QSize Filter::sizeHint() const +{ + return QSize(350,100); +} + + +QSizePolicy Filter::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void Filter::okData() +{ + *filter_text=filter_text_edit->text(); + done(0); +} + + +void Filter::clearData() +{ + filter_text_edit->clear(); +} + + +void Filter::cancelData() +{ + done(1); +} diff --git a/rdlibrary/filter.h b/rdlibrary/filter.h new file mode 100644 index 00000000..44864748 --- /dev/null +++ b/rdlibrary/filter.h @@ -0,0 +1,54 @@ +// filter.h +// +// Set Filter Widget for RDLibrary. +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: filter.h,v 1.5 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef FILTER_H +#define FILTER_H + +#include +#include +#include +#include +#include + + + +class Filter : public QDialog +{ + Q_OBJECT + public: + Filter(QString *filter,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void clearData(); + void cancelData(); + + private: + QString *filter_text; + QLineEdit *filter_text_edit; +}; + + +#endif + diff --git a/rdlibrary/globals.h b/rdlibrary/globals.h new file mode 100644 index 00000000..b5996642 --- /dev/null +++ b/rdlibrary/globals.h @@ -0,0 +1,52 @@ +// globals.h +// +// Global Resources for RDLibrary. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: globals.h,v 1.17 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef GLOBALS_H +#define GLOBALS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern RDLibraryConf *rdlibrary_conf; +extern RDStation *rdstation_conf; +extern RDAudioPort *rdaudioport_conf; +extern RDRipc *rdripc; +extern RDCae *rdcae; +extern DiskGauge *disk_gauge; +extern RDCut *cut_clipboard; +extern RDConfig *lib_config; +extern RDUser *lib_user; +extern RDSystem *lib_system; + +extern bool import_running; +extern bool ripper_running; + +#endif diff --git a/rdlibrary/lib_listview.cpp b/rdlibrary/lib_listview.cpp new file mode 100644 index 00000000..39c152c2 --- /dev/null +++ b/rdlibrary/lib_listview.cpp @@ -0,0 +1,69 @@ +// lib_listview.cpp +// +// A drag & drop QListView widget for Rivendell's RDLibrary +// +// (C) Copyright 2002-2013 Fred Gleason +// +// $Id: lib_listview.cpp,v 1.1.2.3.2.1 2014/05/20 14:23:12 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include + +#include +#include +#include + +LibListView::LibListView(QWidget *parent,const char *name) + : RDListView(parent,name) +{ + list_move_count=-1; +} + + +void LibListView::contentsMousePressEvent(QMouseEvent *e) +{ + list_move_count=3; + QListView::contentsMousePressEvent(e); +} + + +void LibListView::contentsMouseMoveEvent(QMouseEvent *e) +{ + QListView::contentsMouseMoveEvent(e); + list_move_count--; + if(list_move_count==0) { + RDListViewItem *item=(RDListViewItem *)selectedItem(); + + if(item==NULL) { + return; + } + if(item->text(21).isEmpty()) { // Voice tracks cannot be dragged + RDCartDrag *d= + new RDCartDrag(item->text(1).toUInt(),item->text(4),item->textColor(2), + this); + d->dragCopy(); + emit clicked(item); + } + } +} + + +void LibListView::contentsMouseReleaseEvent(QMouseEvent *e) +{ + list_move_count=-1; + QListView::contentsMouseReleaseEvent(e); +} diff --git a/rdlibrary/lib_listview.h b/rdlibrary/lib_listview.h new file mode 100644 index 00000000..de776bca --- /dev/null +++ b/rdlibrary/lib_listview.h @@ -0,0 +1,45 @@ +// lib_listview.h +// +// A drag & drop QListView widget for Rivendell's RDLibrary +// +// (C) Copyright 2002-2013 Fred Gleason +// +// $Id: lib_listview.h,v 1.1.2.2 2014/01/08 00:00:51 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef LIB_LISTVIEW_H +#define LIB_LISTVIEW_H + +#include + +class LibListView : public RDListView +{ + Q_OBJECT + public: + LibListView(QWidget *parent,const char *name=0); + + protected: + void contentsMousePressEvent(QMouseEvent *e); + void contentsMouseMoveEvent(QMouseEvent *e); + void contentsMouseReleaseEvent(QMouseEvent *e); + + private: + int list_move_count; +}; + + +#endif // LIB_LISTVIEW_H diff --git a/rdlibrary/list_reports.cpp b/rdlibrary/list_reports.cpp new file mode 100644 index 00000000..a0f2d992 --- /dev/null +++ b/rdlibrary/list_reports.cpp @@ -0,0 +1,744 @@ +// list_reports.cpp +// +// Add a Rivendell Service +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: list_reports.cpp,v 1.11.4.4.2.1 2014/03/19 22:12:59 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +ListReports::ListReports(const QString &filter,const QString &type_filter, + const QString &group,const QString &schedcode, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + list_filter=filter; + list_type_filter=type_filter; + list_group=group; + list_schedcode=schedcode; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("RDLibrary Reports")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Reports List + // + list_reports_box=new QComboBox(this,"list_reports_box"); + list_reports_box->setGeometry(50,10,sizeHint().width()-60,19); + list_reports_box->insertItem(tr("Cart Report")); + list_reports_box->insertItem(tr("Cut Report")); + list_reports_box->insertItem(tr("Cart Data Dump (fixed width)")); + list_reports_box->insertItem(tr("Cart Data Dump (CSV)")); + list_reports_label=new QLabel(list_reports_box,tr("Type:"),this); + list_reports_label->setGeometry(10,10,35,19); + list_reports_label->setFont(font); + list_reports_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(list_reports_box,SIGNAL(activated(int)), + this,SLOT(typeActivatedData(int))); + + // + // Field Names Checkbox + // + list_fieldnames_check=new QCheckBox(this); + list_fieldnames_check->setGeometry(55,34,15,15); + list_fieldnames_check->setChecked(true); + list_fieldnames_check->setDisabled(true); + list_fieldnames_label= + new QLabel(list_fieldnames_check,tr("Prepend Field Names"),this); + list_fieldnames_label->setGeometry(75,32,sizeHint().width()-75,19); + list_fieldnames_label->setFont(font); + list_fieldnames_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + list_fieldnames_label->setDisabled(true); + + // + // Generate Button + // + QPushButton *generate_button=new QPushButton(this,"generate_button"); + generate_button-> + setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + generate_button->setDefault(true); + generate_button->setFont(font); + generate_button->setText(tr("&Generate")); + connect(generate_button,SIGNAL(clicked()),this,SLOT(generateData())); + + // + // Close Button + // + QPushButton *close_button=new QPushButton(this,"close_button"); + close_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + close_button->setFont(font); + close_button->setText(tr("&Close")); + connect(close_button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +ListReports::~ListReports() +{ +} + + +QSize ListReports::sizeHint() const +{ + return QSize(350,130); +} + + +QSizePolicy ListReports::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListReports::typeActivatedData(int index) +{ + list_fieldnames_check->setEnabled((index==2)||(index==3)); + list_fieldnames_label->setEnabled((index==2)||(index==3)); +} + + +void ListReports::generateData() +{ + QString report; + + switch(list_reports_box->currentItem()) { + case 0: // Cart Report + GenerateCartReport(&report); + break; + + case 1: // Cut Report + GenerateCutReport(&report); + break; + + case 2: // Cart Data Dump (fixed) + GenerateCartDumpFixed(&report,list_fieldnames_check->isChecked()); + break; + + case 3: // Cart Data Dump (CSV) + GenerateCartDumpCsv(&report,list_fieldnames_check->isChecked()); + break; + + default: + return; + } + RDTextFile(report); +} + + +void ListReports::closeData() +{ + done(-1); +} + + +void ListReports::GenerateCartReport(QString *report) +{ + QString sql; + RDSqlQuery *q; + QString schedcode=""; + + if(list_schedcode!=tr("ALL")) { + schedcode=list_schedcode; + } + + // + // Generate Header + // + QString filter=list_filter; + if(list_filter.isEmpty()) { + filter="[none]"; + } + *report=" Rivendell Cart Report\n"; + *report+=QString(). + sprintf("Generated: %s Group: %-10s Filter: %s\n", + (const char *)QDateTime(QDate::currentDate(),QTime::currentTime()). + toString("MM/dd/yyyy - hh:mm:ss"), + (const char *)list_group.utf8(),(const char *)filter.utf8()); + *report+="\n"; + *report+="Type -Cart- -Group---- -Len- -Title------------------------- -Artist----------------------- Cuts Rot Enf -LenDev -Owner--------------\n"; + + // + // Generate Rows + // + if(list_type_filter.isEmpty()) { + return; + } + sql=QString("select CART.TYPE,CART.NUMBER,CART.GROUP_NAME,")+ + "CART.FORCED_LENGTH,CART.TITLE,CART.ARTIST,CART.CUT_QUANTITY,"+ + "CART.PLAY_ORDER,CART.ENFORCE_LENGTH,CART.LENGTH_DEVIATION,CART.OWNER "+ + "from CART left join CUTS on CART.NUMBER=CUTS.CART_NUMBER"; + if(list_group==QString("ALL")) { + sql+=QString(" where ")+ + RDAllCartSearchText(list_filter,schedcode,lib_user->name(),true)+" && "+ + list_type_filter+" order by NUMBER"; + } + else { + sql+=QString(" where ")+ + RDCartSearchText(list_filter,list_group,schedcode,true)+" && "+ + list_type_filter+" order by NUMBER"; + } + q=new RDSqlQuery(sql); + while(q->next()) { + // + // Cart Type + // + switch((RDCart::Type)q->value(0).toInt()) { + case RDCart::Audio: + *report+=" A "; + break; + + case RDCart::Macro: + *report+=" M "; + break; + + default: + *report+=" ? "; + break; + } + + // + // Cart Number + // + *report+=QString().sprintf("%06u ",q->value(1).toUInt()); + + // + // Group + // + *report+= + QString().sprintf("%-10s ",(const char *)q->value(2).toString().utf8()); + + // + // Length + // + *report+= + QString().sprintf("%5s ", + (const char *)RDGetTimeLength(q->value(3).toInt(),false,false)); + + // + // Title + // + *report+=QString().sprintf("%-31s ",(const char *)q->value(4).toString(). + utf8().left(31)); + + // + // Artist + // + *report+=QString().sprintf("%-30s ",(const char *)q->value(5).toString(). + utf8().left(30)); + + // + // Cut Quantity + // + *report+=QString().sprintf("%4d ",q->value(6).toInt()); + + // + // Play Order + // + switch((RDCart::PlayOrder)q->value(7).toInt()) { + case RDCart::Sequence: + *report+="SEQ "; + break; + + case RDCart::Random: + *report+="RND "; + break; + + default: + *report+="???"; + break; + } + + // + // Enforce Length + // + if(q->value(8).toString()=="Y") { + *report+="Yes "; + } + else { + *report+="No "; + } + + // + // Length Deviation + // + *report+= + QString().sprintf("%7s ", + (const char *)RDGetTimeLength(q->value(9).toInt(),false,true)); + + // + // Owner + // + if(q->value(10).toString().isEmpty()) { + *report+="[none]"; + } + else { + *report+=QString().sprintf("%s",(const char *)q->value(10).toString(). + utf8().left(20)); + } + + // + // End of Line + // + *report+="\n"; + } + delete q; +} + + +void ListReports::GenerateCutReport(QString *report) +{ + QString sql; + RDSqlQuery *q; + unsigned current_cart=0; + QString schedcode=""; + + if(list_schedcode!=tr("ALL")) { + schedcode=list_schedcode; + } + + // + // Generate Header + // + QString filter=list_filter; + if(list_filter.isEmpty()) { + filter="[none]"; + } + *report=" Rivendell Cut Report\n"; + *report+=QString(). + sprintf("Generated: %s Group: %-10s Filter: %s\n", + (const char *)QDateTime(QDate::currentDate(),QTime::currentTime()). + toString("MM/dd/yyyy - hh:mm:ss"), + (const char *)list_group.utf8(),(const char *)filter.utf8()); + *report+="\n"; + *report+="-Cart- Cut Wht -Cart Title-------------- -Description--- -Len- Last Play Plays Start Date End Date -Days of Week- -Daypart-----------\n"; + + // + // Generate Rows + // + if(list_type_filter.isEmpty()) { + return; + } + sql="select CART.NUMBER,CUTS.CUT_NAME,CUTS.WEIGHT,CART.TITLE,\ + CUTS.DESCRIPTION,CUTS.LENGTH,CUTS.LAST_PLAY_DATETIME,CUTS.PLAY_COUNTER,\ + CUTS.START_DATETIME,CUTS.END_DATETIME,SUN,MON,TUE,WED,THU,FRI,SAT,\ + CUTS.START_DAYPART,CUTS.END_DAYPART from CART join CUTS \ + on CART.NUMBER=CUTS.CART_NUMBER"; + if(list_group==QString("ALL")) { + sql+=QString(" where ")+ + RDAllCartSearchText(list_filter,schedcode,lib_user->name(),true)+" && "+ + list_type_filter+" order by CART.NUMBER"; + } + else { + sql+=QString(" where ")+ + RDCartSearchText(list_filter,list_group,schedcode,true)+" && "+ + list_type_filter+" order by CART.NUMBER"; + } + q=new RDSqlQuery(sql); + while(q->next()) { + // + // Cart Number + // + if(q->value(0).toUInt()!=current_cart) { + *report+=QString().sprintf("%06u ",q->value(0).toUInt()); + } + else { + *report+=" "; + } + + // + // Cut Number + // + *report+= + QString().sprintf("%03d ",q->value(1).toString().right(3).toInt()); + + // + // Weight + // + *report+=QString().sprintf("%3d ",q->value(2).toInt()); + + // + // Title + // + if(q->value(0).toUInt()!=current_cart) { + *report+=QString().sprintf("%-25s ",(const char *)q->value(3).toString(). + utf8().left(25)); + } + else { + *report+=" "; + } + + // + // Description + // + *report+=QString().sprintf("%-15s ",(const char *)q->value(4).toString(). + utf8().left(15)); + + // + // Length + // + *report+= + QString().sprintf("%5s ", + (const char *)RDGetTimeLength(q->value(5).toInt(),false,false)); + + // + // Last Play + // + if(q->value(6).toDateTime().isNull()) { + *report+=" [none] "; + } + else { + *report+=QString().sprintf(" %8s ", + (const char *)q->value(6).toDate().toString("MM/dd/yy")); + } + + // + // Plays + // + *report+=QString().sprintf("%4d ",q->value(7).toInt()); + + // + // Start Date + // + if(q->value(8).toDateTime().isNull()) { + *report+=" [none] "; + } + else { + *report+=QString().sprintf(" %8s ", + (const char *)q->value(8).toDateTime().toString("MM/dd/yy")); + } + + // + // End Date + // + if(q->value(9).toDateTime().isNull()) { + *report+=" TFN "; + } + else { + *report+=QString().sprintf(" %8s ", + (const char *)q->value(9).toDateTime().toString("MM/dd/yy")); + } + + // + // Days of the Week + // + if(q->value(10).toString()=="Y") { + *report+="Su"; + } + else { + *report+=" "; + } + if(q->value(11).toString()=="Y") { + *report+="Mo"; + } + else { + *report+=" "; + } + if(q->value(12).toString()=="Y") { + *report+="Tu"; + } + else { + *report+=" "; + } + if(q->value(13).toString()=="Y") { + *report+="We"; + } + else { + *report+=" "; + } + if(q->value(14).toString()=="Y") { + *report+="Th"; + } + else { + *report+=" "; + } + if(q->value(15).toString()=="Y") { + *report+="Fr"; + } + else { + *report+=" "; + } + if(q->value(16).toString()=="Y") { + *report+="Sa "; + } + else { + *report+=" "; + } + + // + // Dayparts + // + if(q->value(18).toTime().isNull()) { + *report+="[none]"; + } + else { + *report+=QString().sprintf("%8s - %8s", + (const char *)q->value(17).toTime().toString("hh:mm:ss"), + (const char *)q->value(18).toTime().toString("hh:mm:ss")); + } + + // + // End of Line + // + *report+="\n"; + + current_cart=q->value(0).toUInt(); + } + delete q; +} + + +void ListReports::GenerateCartDumpFixed(QString *report,bool prepend_names) +{ + QString sql; + RDSqlQuery *q; + QString schedcode=""; + + if(list_schedcode!=tr("ALL")) { + schedcode=list_schedcode; + } + + // + // Prepend Field Names + // + if(prepend_names) { + *report="CART |"; + *report+="CUT|"; + *report+="GROUP_NAME|"; + *report+="TITLE |"; + *report+="ARTIST |"; + *report+="ALBUM |"; + *report+="YEAR|"; + *report+="ISRC |"; + *report+="LABEL |"; + *report+="CLIENT |"; + *report+="AGENCY |"; + *report+="PUBLISHER |"; + *report+="COMPOSER |"; + *report+="USER_DEFINED |"; + *report+="LENGTH |\n"; + } + + // + // Generate Rows + // + if(list_type_filter.isEmpty()) { + return; + } + sql="select CUTS.CUT_NAME,CART.GROUP_NAME,CART.TITLE,CART.ARTIST,CART.ALBUM,\ + CART.YEAR,CUTS.ISRC,CART.LABEL,CART.CLIENT,CART.AGENCY,CART.PUBLISHER,\ + CART.COMPOSER,CART.USER_DEFINED,CUTS.LENGTH from CART \ + join CUTS on CART.NUMBER=CUTS.CART_NUMBER"; + if(list_group==QString("ALL")) { + sql+=QString(" where ")+ + RDAllCartSearchText(list_filter,schedcode,lib_user->name(),true)+" && "+ + list_type_filter+" order by CUTS.CUT_NAME"; + } + else { + sql+=QString(" where ")+ + RDCartSearchText(list_filter,list_group,schedcode,true)+" && "+ + list_type_filter+" order by CUTS.CUT_NAME"; + } + q=new RDSqlQuery(sql); + while(q->next()) { + // + // Cart Number + // + *report+=QString().sprintf("%-6s|",(const char *)q->value(0).toString(). + utf8().left(6)); + + // + // Cut Number + // + *report+= + QString().sprintf("%-3s|",(const char *)q->value(0).toString().right(3)); + + // + // Group Name + // + *report+=QString().sprintf("%-10s|",(const char *)q->value(1).toString(). + utf8()); + + // + // Title + // + *report+=QString().sprintf("%-255s|",(const char *)q->value(2).toString(). + utf8()); + + // + // Artist + // + *report+=QString().sprintf("%-255s|",(const char *)q->value(3).toString(). + utf8()); + + // + // Album + // + *report+=QString().sprintf("%-255s|",(const char *)q->value(4).toString(). + utf8()); + + // + // Year + // + if(q->value(5).toDate().isNull()) { + *report+=" |"; + } + else { + *report+=QString().sprintf("%4d|",q->value(5).toDate().year()); + } + + // + // ISRC + // + *report+=QString().sprintf("%-12s|",(const char *)q->value(6).toString(). + utf8()); + + // + // Label + // + *report+=QString().sprintf("%-64s|",(const char *)q->value(7).toString(). + utf8()); + + // + // Client + // + *report+=QString().sprintf("%-64s|",(const char *)q->value(8).toString(). + utf8()); + + // + // Agency + // + *report+=QString().sprintf("%-64s|",(const char *)q->value(9).toString(). + utf8()); + + // + // Publisher + // + *report+=QString().sprintf("%-64s|",(const char *)q->value(10).toString(). + utf8()); + + // + // Composer + // + *report+=QString().sprintf("%-64s|",(const char *)q->value(11).toString(). + utf8()); + + // + // User Defined + // + *report+=QString().sprintf("%-255s|",(const char *)q->value(12).toString(). + utf8()); + + // + // Length + // + *report+=QString().sprintf("%9s|", + (const char *)RDGetTimeLength(q->value(13).toInt(),true,true)); + + // + // End of Line + // + *report+="\n"; + } + + delete q; +} + + +void ListReports::GenerateCartDumpCsv(QString *report,bool prepend_names) +{ + QString sql; + RDSqlQuery *q; + QString schedcode=""; + + if(list_schedcode!=tr("ALL")) { + schedcode=list_schedcode; + } + + // + // Prepend Field Names + // + if(prepend_names) { + *report="CART,CUT,GROUP_NAME,TITLE,ARTIST,ALBUM,YEAR,ISRC,ISCI,LABEL,"; + *report+="CLIENT,AGENCY,PUBLISHER,COMPOSER,USER_DEFINED,LENGTH\n"; + } + + // + // Generate Rows + // + if(list_type_filter.isEmpty()) { + return; + } + sql="select CUTS.CUT_NAME,CART.GROUP_NAME,CART.TITLE,CART.ARTIST,CART.ALBUM,\ + CART.YEAR,CUTS.ISRC,CUTS.ISCI,CART.LABEL,CART.CLIENT,CART.AGENCY,\ + CART.PUBLISHER,CART.COMPOSER,CART.USER_DEFINED,CUTS.LENGTH from CART \ + join CUTS on CART.NUMBER=CUTS.CART_NUMBER"; + if(list_group==QString("ALL")) { + sql+=QString(" where ")+ + RDAllCartSearchText(list_filter,schedcode,lib_user->name(),true)+" && "+ + list_type_filter+" order by CUTS.CUT_NAME"; + } + else { + sql=QString(" where ")+ + RDCartSearchText(list_filter,list_group,schedcode,true)+" && "+ + list_type_filter+" order by CUTS.CUT_NAME"; + } + q=new RDSqlQuery(sql); + while(q->next()) { + *report+=QString().sprintf("%u,",RDCut::cartNumber(q->value(0).toString())); + *report+=QString().sprintf("%u,",RDCut::cutNumber(q->value(0).toString())); + *report+="\""+q->value(1).toString()+"\","; + *report+="\""+q->value(2).toString()+"\","; + *report+="\""+q->value(3).toString()+"\","; + *report+="\""+q->value(4).toString()+"\","; + *report+="\""+q->value(5).toString()+"\","; + *report+="\""+q->value(6).toString()+"\","; + *report+="\""+q->value(7).toString()+"\","; + *report+="\""+q->value(8).toString()+"\","; + *report+="\""+q->value(9).toString()+"\","; + *report+="\""+q->value(10).toString()+"\","; + *report+="\""+q->value(11).toString()+"\","; + *report+="\""+q->value(12).toString()+"\","; + *report+="\""+q->value(13).toString()+"\","; + *report+="\""+RDGetTimeLength(q->value(14).toInt(),false,false)+"\","; + *report+="\n"; + } +} diff --git a/rdlibrary/list_reports.h b/rdlibrary/list_reports.h new file mode 100644 index 00000000..c519b211 --- /dev/null +++ b/rdlibrary/list_reports.h @@ -0,0 +1,67 @@ +// list_reports.h +// +// List and Generate RDLibrary Reports +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: list_reports.h,v 1.6.4.1 2013/09/12 23:26:10 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_REPORTS_H +#define LIST_REPORTS_H + +#include +#include +#include +#include +#include + +#include + + +class ListReports : public QDialog +{ + Q_OBJECT + public: + ListReports(const QString &filter,const QString &type_filter, + const QString &group,const QString &schedcode, + QWidget *parent=0,const char *name=0); + ~ListReports(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void typeActivatedData(int index); + void generateData(); + void closeData(); + + private: + void GenerateCartReport(QString *report); + void GenerateCutReport(QString *report); + void GenerateCartDumpFixed(QString *report,bool prepend_names); + void GenerateCartDumpCsv(QString *report,bool prepend_names); + QLabel *list_reports_label; + QComboBox *list_reports_box; + QCheckBox *list_fieldnames_check; + QLabel *list_fieldnames_label; + QString list_filter; + QString list_type_filter; + QString list_group; + QString list_schedcode; +}; + + +#endif // LIST_REPORTS_H diff --git a/rdlibrary/macro_cart.cpp b/rdlibrary/macro_cart.cpp new file mode 100644 index 00000000..0585bc10 --- /dev/null +++ b/rdlibrary/macro_cart.cpp @@ -0,0 +1,383 @@ +// macro_cart.cpp +// +// The macro cart editor for RDLibrary. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: macro_cart.cpp,v 1.13.8.2 2013/12/23 21:51:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + + +MacroCart::MacroCart(RDCart *cart,QWidget *parent,const char *name) + : QWidget(parent,name) +{ + rdcart_length=0; + rdcart_cart=cart; + setCaption(QString().sprintf("%u",rdcart_cart->number())+" - "+ + rdcart_cart->title()); + rdcart_allow_modification=lib_user->modifyCarts(); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont line_edit_font=QFont("Helvetica",12,QFont::Normal); + line_edit_font.setPixelSize(12); + + // + // Add Macro Button + // + rdcart_add_button=new QPushButton(this,"add_macro_button"); + rdcart_add_button->setGeometry(10,0,80,50); + rdcart_add_button->setFont(button_font); + rdcart_add_button->setText(tr("Add")); + connect(rdcart_add_button,SIGNAL(clicked()),this,SLOT(addMacroData())); + + // + // Delete Macro Button + // + rdcart_delete_button=new QPushButton(this,"delete_macro_button"); + rdcart_delete_button->setGeometry(10,60,80,50); + rdcart_delete_button->setFont(button_font); + rdcart_delete_button->setText(tr("Delete")); + connect(rdcart_delete_button,SIGNAL(clicked()),this,SLOT(deleteMacroData())); + + // + // Copy Macro Button + // + rdcart_copy_button=new QPushButton(this,"copy_macro_button"); + rdcart_copy_button->setGeometry(10,120,80,50); + rdcart_copy_button->setFont(button_font); + rdcart_copy_button->setText(tr("Copy")); + connect(rdcart_copy_button,SIGNAL(clicked()),this,SLOT(copyMacroData())); + + // + // Paste Macro Button + // + paste_macro_button=new QPushButton(this,"paste_macro_button"); + paste_macro_button->setGeometry(10,180,80,50); + paste_macro_button->setFont(button_font); + paste_macro_button->setText(tr("Paste")); + paste_macro_button->setDisabled(true); + connect(paste_macro_button,SIGNAL(clicked()),this,SLOT(pasteMacroData())); + + // + // Cart Macro List + // + rdcart_events=new RDMacroEvent(rdstation_conf->address(),rdripc, + this,"rdcart_events"); + rdcart_events->load(rdcart_cart->macros()); + + rdcart_macro_list=new QListView(this,"rdcart_macro_list"); + rdcart_macro_list->setGeometry(100,0,430,sizeHint().height()); + rdcart_macro_list->setAllColumnsShowFocus(true); + rdcart_macro_list->setItemMargin(5); + rdcart_macro_list->setSorting(0); + connect(rdcart_macro_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + rdcart_macro_list->addColumn(tr("LINE")); + rdcart_macro_list->setColumnAlignment(0,Qt::AlignHCenter); + + rdcart_macro_list->addColumn(tr("COMMAND")); + rdcart_macro_list->setColumnAlignment(1,Qt::AlignLeft); + + rdcart_macro_list_label=new QLabel(rdcart_macro_list,tr("Macros"), + this,"rdcartmacro_list_label"); + rdcart_macro_list_label->setGeometry(105,345,430,22); + rdcart_macro_list_label->setFont(QFont("Helvetica",16,QFont::Bold)); + + RefreshList(); + + // + // Edit Macro Button + // + rdcart_edit_button=new QPushButton(this,"edit_edit_button"); + rdcart_edit_button->setGeometry(550,0,80,50); + rdcart_edit_button->setFont(button_font); + rdcart_edit_button->setText(tr("Edit")); + connect(rdcart_edit_button,SIGNAL(clicked()),this,SLOT(editMacroData())); + + // + // Run Line Button + // + rdcart_runline_button=new QPushButton(this,"run_macro_button"); + rdcart_runline_button->setGeometry(550,120,80,50); + rdcart_runline_button->setFont(button_font); + rdcart_runline_button->setText(tr("Run\nLine")); + connect(rdcart_runline_button,SIGNAL(clicked()), + this,SLOT(runLineMacroData())); + + // + // Run Cart Button + // + rdcart_runcart_button=new QPushButton(this,"run_macro_button"); + rdcart_runcart_button->setGeometry(550,180,80,50); + rdcart_runcart_button->setFont(button_font); + rdcart_runcart_button->setText(tr("Run\nCart")); + connect(rdcart_runcart_button,SIGNAL(clicked()), + this,SLOT(runCartMacroData())); + + // + // Set Control Permissions + // + rdcart_add_button->setEnabled(rdcart_allow_modification); + rdcart_delete_button->setEnabled(rdcart_allow_modification); + rdcart_copy_button->setEnabled(rdcart_allow_modification); + rdcart_edit_button->setEnabled(rdcart_allow_modification); +} + + +QSize MacroCart::sizeHint() const +{ + return QSize(640,290); +} + + +QSizePolicy MacroCart::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +unsigned MacroCart::length() +{ + return rdcart_events->length(); +} + + +void MacroCart::save() +{ + rdcart_cart->setMacros(rdcart_events->save()); +} + + +void MacroCart::addMacroData() +{ + QListViewItem *item=rdcart_macro_list->selectedItem(); + RDMacro cmd; + unsigned line; + + if(item==NULL) { + return; + } + if(item->text(0).isEmpty()) { + line=rdcart_events->size(); + } + else { + line=item->text(0).toUInt()-1; + } + EditMacro *edit=new EditMacro(&cmd,true,this,"edit_macro"); + if(edit->exec()!=-1) { + AddLine(line,&cmd); + UpdateLength(); + } + delete edit; +} + + +void MacroCart::deleteMacroData() +{ + QListViewItem *item=rdcart_macro_list->selectedItem(); + + if((item==NULL)||(item->text(0).isEmpty())) { + return; + } + DeleteLine(item); + UpdateLength(); +} + + +void MacroCart::copyMacroData() +{ + QListViewItem *item=rdcart_macro_list->selectedItem(); + + if((item==NULL)||(item->text(0).isEmpty())) { + return; + } + rdcart_clipboard=*rdcart_events->command(item->text(0).toUInt()-1); + paste_macro_button->setEnabled(true); +} + + +void MacroCart::pasteMacroData() +{ + QListViewItem *item=rdcart_macro_list->selectedItem(); + unsigned line; + + if(item==NULL) { + return; + } + if(item->text(0).isEmpty()) { + line=rdcart_events->size(); + } + else { + line=item->text(0).toUInt()-1; + } + AddLine(line,&rdcart_clipboard); + UpdateLength(); +} + + +void MacroCart::editMacroData() +{ + QListViewItem *item=rdcart_macro_list->selectedItem(); + + if((item==NULL)||(item->text(0).isEmpty())) { + return; + } + unsigned line=item->text(0).toUInt()-1; + EditMacro *edit=new EditMacro(rdcart_events->command(line),false,this,"edit"); + if(edit->exec()!=-1) { + RefreshLine(item); + UpdateLength(); + } + delete edit; +} + + +void MacroCart::runLineMacroData() +{ + QListViewItem *item=rdcart_macro_list->selectedItem(); + + if((item==NULL)||(item->text(0).isEmpty())) { + return; + } + unsigned line=item->text(0).toUInt()-1; + rdcart_events->exec(line); +} + + +void MacroCart::runCartMacroData() +{ + rdcart_events->exec(); +} + + +void MacroCart::doubleClickedData(QListViewItem *,const QPoint &,int) +{ + if(rdcart_allow_modification) { + QListViewItem *item=rdcart_macro_list->selectedItem(); + + if((item==NULL)||(item->text(0).isEmpty())) { + addMacroData(); + } + else { + editMacroData(); + } + } +} + + +void MacroCart::RefreshList() +{ + QListViewItem *item; + char cmdstr[RD_RML_MAX_LENGTH]; + + item=new QListViewItem(rdcart_macro_list); + item->setText(1,tr("--- End of cart ---")); + for(int i=0;isize();i++) { + item=new QListViewItem(rdcart_macro_list); + rdcart_events->command(i)->generateString(cmdstr,RD_RML_MAX_LENGTH); + item->setText(0,QString().sprintf("%03d",i+1)); + item->setText(1,cmdstr); + } +} + + +void MacroCart::RefreshLine(QListViewItem *item) +{ + char cmdstr[RD_RML_MAX_LENGTH]; + int line=item->text(0).toInt()-1; + rdcart_events->command(line)->generateString(cmdstr,RD_RML_MAX_LENGTH); + item->setText(1,cmdstr); +} + + +void MacroCart::AddLine(unsigned line,RDMacro *cmd) +{ + unsigned curr_line; + + QListViewItem *item=rdcart_macro_list->firstChild(); + for(int i=0;ichildCount();i++) { + if(((curr_line=(item->text(0).toUInt()-1))>=line)&& + (!item->text(0).isEmpty())) { + item->setText(0,QString().sprintf("%03u",curr_line+2)); + } + item=item->nextSibling(); + } + rdcart_events->insert(line,cmd); + item=new QListViewItem(rdcart_macro_list); + item->setText(0,QString().sprintf("%03u",line+1)); + RefreshLine(item); + rdcart_macro_list->setSelected(item,true); +} + + +void MacroCart::DeleteLine(QListViewItem *item) +{ + unsigned line=item->text(0).toUInt()-1; + unsigned curr_line; + QListViewItem *next=item->nextSibling(); + rdcart_macro_list->removeItem(item); + rdcart_events->remove(line); + QListViewItem *l=rdcart_macro_list->firstChild(); + for(int i=0;ichildCount();i++) { + if(((curr_line=(l->text(0).toUInt()-1))>line)&& + (!l->text(0).isEmpty())) { + l->setText(0,QString().sprintf("%03u",curr_line)); + } + l=l->nextSibling(); + } + if(next!=NULL) { + rdcart_macro_list->setSelected(next,true); + } +} + + +void MacroCart::UpdateLength() +{ + if(rdcart_events->length()!=rdcart_length) { + rdcart_length=rdcart_events->length(); + emit lengthChanged(rdcart_length); + } +} diff --git a/rdlibrary/macro_cart.h b/rdlibrary/macro_cart.h new file mode 100644 index 00000000..b99d0652 --- /dev/null +++ b/rdlibrary/macro_cart.h @@ -0,0 +1,93 @@ +// macro_cart.h +// +// The macro cart editor for RDLibrary. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: macro_cart.h,v 1.10 2010/07/29 19:32:36 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef MACRO_CART_H +#define MACRO_CART_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +class MacroCart : public QWidget +{ + Q_OBJECT + public: + MacroCart(RDCart *cart,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + unsigned length(); + void save(); + + signals: + void lengthChanged(unsigned len); + + private slots: + void addMacroData(); + void deleteMacroData(); + void copyMacroData(); + void pasteMacroData(); + void editMacroData(); + void runLineMacroData(); + void runCartMacroData(); + void doubleClickedData(QListViewItem *,const QPoint &,int); + + private: + void RefreshList(); + void RefreshLine(QListViewItem *item); + void AddLine(unsigned line,RDMacro *cmd); + void DeleteLine(QListViewItem *item); + void UpdateLength(); + RDCart *rdcart_cart; + QListView *rdcart_macro_list; + QLabel *rdcart_macro_list_label; + RDMacroEvent *rdcart_events; + RDMacro rdcart_clipboard; + QPushButton *paste_macro_button; + QPushButton *rdcart_add_button; + QPushButton *rdcart_delete_button; + QPushButton *rdcart_copy_button; + QPushButton *rdcart_edit_button; + QPushButton *rdcart_runline_button; + QPushButton *rdcart_runcart_button; + unsigned rdcart_length; + bool rdcart_allow_modification; +}; + + +#endif + diff --git a/rdlibrary/rdlibrary.cpp b/rdlibrary/rdlibrary.cpp new file mode 100644 index 00000000..9c3f2cbc --- /dev/null +++ b/rdlibrary/rdlibrary.cpp @@ -0,0 +1,1512 @@ +// rdlibrary.cpp +// +// The Library Utility for Rivendell. +// +// (C) Copyright 2002-2010 Fred Gleason +// +// $Id: rdlibrary.cpp,v 1.117.4.18.2.2 2014/05/22 14:30:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Global Resources +// +RDLibraryConf *rdlibrary_conf; +RDStation *rdstation_conf; +RDAudioPort *rdaudioport_conf; +RDRipc *rdripc; +RDCae *rdcae; +DiskGauge *disk_gauge; +RDCut *cut_clipboard=NULL; +RDConfig *lib_config; +RDUser *lib_user; +bool audio_changed; +RDSystem *lib_system=NULL; + +// +// Prototypes +// +void SigHandler(int signo); + +// +// Icons +// +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" +#include "../icons/track_cart.xpm" +#include "../icons/rivendell-22x22.xpm" + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + unsigned schema=0; + bool skip_db_check=false; + profile_ripping=false; + lib_edit_pending=false; + lib_user_changed=false; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdlibrary",RDLIBRARY_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--profile-ripping") { + profile_ripping=true; + cmd->setProcessed(i,true); + } + if(!cmd->processed(i)) { + QMessageBox::warning(this,"RDLibrary - "+tr("Error"), + tr("Unknown command-line option")+ + " \""+cmd->key(i)+"\"."); + exit(256); + } + } + delete cmd; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Initialize LibCurl + // + curl_global_init(CURL_GLOBAL_ALL); + + // + // Generate Fonts + // + QFont default_font("Helvetica",12,QFont::Normal); + default_font.setPixelSize(12); + qApp->setFont(default_font); + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont filter_font=QFont("Helvetica",16,QFont::Bold); + filter_font.setPixelSize(16); + + // + // Create Icons + // + lib_playout_map=new QPixmap(play_xpm); + lib_macro_map=new QPixmap(rml5_xpm); + lib_track_cart_map=new QPixmap(track_cart_xpm); + lib_rivendell_map=new QPixmap(rivendell_xpm); + setIcon(*lib_rivendell_map); + + // + // Progress Dialog + // + lib_progress_dialog= + new QProgressDialog(tr("Please Wait..."),"Cancel",10,this, + "lib_progress_dialog",false, + Qt::WStyle_Customize|Qt::WStyle_NormalBorder); + lib_progress_dialog->setCaption(" "); + QLabel *label=new QLabel(tr("Please Wait..."),lib_progress_dialog); + label->setAlignment(AlignCenter); + label->setFont(filter_font); + lib_progress_dialog->setLabel(label); + lib_progress_dialog->setCancelButton(NULL); + lib_progress_dialog->setMinimumDuration(2000); + + // + // Ensure that the system daemons are running + // + RDInitializeDaemons(); + + // + // Load Local Configs + // + lib_config=new RDConfig(); + lib_config->load(); + + SetCaption(""); + lib_import_path=RDGetHomeDir(); + + // + // Open Database + // + QString err(tr("rdlibrary : ")); + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + QMessageBox::warning(this, + tr("Can't Connect"),err); + exit(0); + } + if((RD_VERSION_DATABASE!=schema)&&(!skip_db_check)) { + fprintf(stderr, + "rdlibrary: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + + // + // Allocate Global Resources + // + rdlibrary_conf=new RDLibraryConf(lib_config->stationName(),0); + rdstation_conf=new RDStation(lib_config->stationName()); + lib_filter_mode=rdstation_conf->filterMode(); + rdaudioport_conf=new RDAudioPort(lib_config->stationName(), + rdlibrary_conf->inputCard()); + rdripc=new RDRipc(lib_config->stationName()); + connect(rdripc,SIGNAL(connected(bool)),this,SLOT(connectedData(bool))); + connect(rdripc,SIGNAL(userChanged()),this,SLOT(userData())); + rdripc->connectHost("localhost",RIPCD_TCP_PORT,lib_config->password()); + cut_clipboard=NULL; + lib_system=new RDSystem(); + lib_user_timer=new QTimer(this); + connect(lib_user_timer,SIGNAL(timeout()),this,SLOT(userData())); + + // + // CAE Connection + // + rdcae=new RDCae(rdstation_conf,lib_config,parent,name); + rdcae->connectHost(); + + // + // Load Audio Assignments + // + RDSetMixerPorts(lib_config->stationName(),rdcae); + + // + // User + // + lib_user=NULL; + + // + // Filter + // + lib_filter_edit=new QLineEdit(this,"filter_edit"); + lib_filter_edit->setFont(default_font); + lib_filter_label=new QLabel(lib_filter_edit,tr("Filter:"), + this,"filter_label"); + lib_filter_label->setFont(button_font); + lib_filter_label->setAlignment(AlignVCenter|AlignRight); + connect(lib_filter_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(filterChangedData(const QString &))); + connect(lib_filter_edit,SIGNAL(returnPressed()), + this,SLOT(searchClickedData())); + + // + // Filter Search Button + // + lib_search_button=new QPushButton(tr("&Search"),this,"search_button"); + lib_search_button->setFont(button_font); + connect(lib_search_button,SIGNAL(clicked()),this,SLOT(searchClickedData())); + switch(lib_filter_mode) { + case RDStation::FilterSynchronous: + lib_search_button->hide(); + break; + + case RDStation::FilterAsynchronous: + break; + } + + // + // Filter Clear Button + // + lib_clear_button=new QPushButton(tr("&Clear"),this,"clear_button"); + lib_clear_button->setFont(button_font); + lib_clear_button->setDisabled(true); + connect(lib_clear_button,SIGNAL(clicked()),this,SLOT(clearClickedData())); + + // + // Group Filter + // + lib_group_box=new QComboBox(this,"lib_group_box"); + lib_group_box->setFont(default_font); + lib_group_label=new QLabel(lib_group_box,tr("Group:"), + this,"lib_group_label"); + lib_group_label->setFont(button_font); + lib_group_label->setAlignment(AlignVCenter|AlignRight); + connect(lib_group_box,SIGNAL(activated(const QString &)), + this,SLOT(groupActivatedData(const QString &))); + + // + // Scheduler Codes Filter + // + lib_codes_box=new QComboBox(this,"lib_codes_box"); + lib_codes_box->setFont(default_font); + lib_codes_label=new QLabel(lib_codes_box,tr("Scheduler Code:"), + this,"lib_codes_label"); + lib_codes_label->setFont(button_font); + lib_codes_label->setAlignment(AlignVCenter|AlignRight); + connect(lib_codes_box,SIGNAL(activated(const QString &)), + this,SLOT(groupActivatedData(const QString &))); + + // + // Show Allow Cart Drags Checkbox + // + lib_allowdrag_box=new QCheckBox(this); + lib_allowdrag_box->setChecked(false); + lib_allowdrag_label= + new QLabel(lib_allowdrag_box,tr("Allow Cart Dragging"),this); + lib_allowdrag_label->setFont(button_font); + lib_allowdrag_label->setAlignment(AlignVCenter|AlignLeft); + connect(lib_allowdrag_box,SIGNAL(stateChanged(int)), + this,SLOT(dragsChangedData(int))); + if(!rdstation_conf->enableDragdrop()) { + lib_allowdrag_box->hide(); + lib_allowdrag_label->hide(); + } + + // + // Show Audio Carts Checkbox + // + lib_showaudio_box=new QCheckBox(this,"lib_showaudio_box"); + lib_showaudio_box->setChecked(true); + lib_showaudio_label=new QLabel(lib_showaudio_box,tr("Show Audio Carts"), + this,"lib_showaudio_label"); + lib_showaudio_label->setFont(button_font); + lib_showaudio_label->setAlignment(AlignVCenter|AlignLeft); + connect(lib_showaudio_box,SIGNAL(stateChanged(int)), + this,SLOT(audioChangedData(int))); + + // + // Show Macro Carts Checkbox + // + lib_showmacro_box=new QCheckBox(this,"lib_showmacro_box"); + lib_showmacro_box->setChecked(true); + lib_showmacro_label=new QLabel(lib_showmacro_box,tr("Show Macro Carts"), + this,"lib_showmacro_label"); + lib_showmacro_label->setFont(button_font); + lib_showmacro_label->setAlignment(AlignVCenter|AlignLeft); + connect(lib_showmacro_box,SIGNAL(stateChanged(int)), + this,SLOT(macroChangedData(int))); + + // + // Show Cart Notes Checkbox + // + lib_shownotes_box=new QCheckBox(this,"lib_shownotes_box"); + lib_shownotes_box->setChecked(true); + lib_shownotes_label=new QLabel(lib_shownotes_box,tr("Show Note Bubbles"), + this,"lib_shownotes_label"); + lib_shownotes_label->setFont(button_font); + lib_shownotes_label->setAlignment(AlignVCenter|AlignLeft); + + // + // Show Matches Checkbox + // + lib_showmatches_box=new QCheckBox(this,"lib_showmatches_box"); + lib_showmatches_label= + new QLabel(lib_showmatches_box,tr("Show Only First ")+ + QString().sprintf("%d",RD_LIMITED_CART_SEARCH_QUANTITY)+ + tr(" Matches"), + this,"lib_showmatches_label"); + lib_showmatches_label->setFont(button_font); + lib_showmatches_label->setAlignment(AlignVCenter|AlignLeft); + connect(lib_showmatches_box,SIGNAL(stateChanged(int)), + this,SLOT(searchLimitChangedData(int))); + + // + // Cart List + // + lib_cart_list=new LibListView(this,"lib_cart_list"); + lib_cart_list->setFont(default_font); + lib_cart_list->setAllColumnsShowFocus(true); + lib_cart_list->setItemMargin(5); + lib_cart_list->setSelectionMode(QListView::Extended); + lib_cart_tip=new CartTip(lib_cart_list->viewport()); + connect(lib_cart_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(cartDoubleclickedData(QListViewItem *,const QPoint &,int))); + connect(lib_cart_list,SIGNAL(pressed(QListViewItem *)), + this,SLOT(cartClickedData(QListViewItem *))); + connect(lib_cart_list,SIGNAL(onItem(QListViewItem *)), + this,SLOT(cartOnItemData(QListViewItem *))); + lib_cart_list->addColumn(""); + lib_cart_list->setColumnAlignment(0,Qt::AlignHCenter); + lib_cart_list->addColumn(tr("CART")); + lib_cart_list->setColumnAlignment(1,Qt::AlignHCenter); + + lib_cart_list->addColumn(tr("GROUP")); + lib_cart_list->setColumnAlignment(2,Qt::AlignHCenter); + + lib_cart_list->addColumn(tr("LENGTH")); + lib_cart_list->setColumnAlignment(3,Qt::AlignRight); + lib_cart_list->setColumnSortType(3,RDListView::TimeSort); + + lib_cart_list->addColumn(tr("TITLE")); + + lib_cart_list->addColumn(tr("ARTIST")); + + lib_cart_list->addColumn(tr("START")); + lib_cart_list->setColumnAlignment(6,Qt::AlignHCenter); + + lib_cart_list->addColumn(tr("END")); + lib_cart_list->setColumnAlignment(7,Qt::AlignHCenter); + + lib_cart_list->addColumn(tr("ALBUM")); + + lib_cart_list->addColumn(tr("LABEL")); + + lib_cart_list->addColumn(tr("COMPOSER")); + + lib_cart_list->addColumn(tr("CONDUCTOR")); + + lib_cart_list->addColumn(tr("PUBLISHER")); + + lib_cart_list->addColumn(tr("CLIENT")); + + lib_cart_list->addColumn(tr("AGENCY")); + + lib_cart_list->addColumn(tr("USER DEFINED")); + + lib_cart_list->addColumn(tr("CUTS")); + lib_cart_list->setColumnAlignment(16,Qt::AlignRight); + + lib_cart_list->addColumn(tr("LAST CUT PLAYED")); + lib_cart_list->setColumnAlignment(17,Qt::AlignHCenter); + + lib_cart_list->addColumn(tr("ENFORCE LENGTH")); + lib_cart_list->setColumnAlignment(18,Qt::AlignHCenter); + + lib_cart_list->addColumn(tr("PRESERVE PITCH")); + lib_cart_list->setColumnAlignment(19,Qt::AlignHCenter); + + lib_cart_list->addColumn(tr("LENGTH DEVIATION")); + lib_cart_list->setColumnAlignment(20,Qt::AlignHCenter); + + lib_cart_list->addColumn(tr("OWNED BY")); + lib_cart_list->setColumnAlignment(21,Qt::AlignHCenter); + + // + // Add Button + // + lib_add_button=new QPushButton(this,"lib_add_button"); + lib_add_button->setFont(button_font); + lib_add_button->setText(tr("&Add")); + connect(lib_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + lib_edit_button=new QPushButton(this,"lib_edit_button"); + lib_edit_button->setFont(button_font); + lib_edit_button->setText(tr("&Edit")); + connect(lib_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + lib_delete_button=new QPushButton(this,"lib_delete_button"); + lib_delete_button->setFont(button_font); + lib_delete_button->setText(tr("&Delete")); + connect(lib_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Disk Gauge + // + disk_gauge=new DiskGauge(lib_system->sampleRate(), + rdlibrary_conf->defaultChannels(), + this,"disk_gauge"); + + // + // Rip Button + // + lib_rip_button=new QPushButton(this,"lib_rip_button"); + lib_rip_button->setFont(button_font); + lib_rip_button->setText(tr("&Rip\nCD")); + connect(lib_rip_button,SIGNAL(clicked()),this,SLOT(ripData())); + + // + // Reports Button + // + lib_reports_button=new QPushButton(this,"lib_reports_button"); + lib_reports_button->setFont(button_font); + lib_reports_button->setText(tr("Re&ports")); + connect(lib_reports_button,SIGNAL(clicked()),this,SLOT(reportsData())); + + // + // Close Button + // + lib_close_button=new QPushButton(this,"lib_close_button"); + lib_close_button->setFont(button_font); + lib_close_button->setText(tr("&Close")); + connect(lib_close_button,SIGNAL(clicked()),this,SLOT(quitMainWidget())); + + // + // Setup Signal Handling + // + ::signal(SIGCHLD,SigHandler); + + // + // Load Data + // + switch(rdlibrary_conf->limitSearch()) { + case RDLibraryConf::LimitNo: + lib_showmatches_box->setChecked(false); + break; + + case RDLibraryConf::LimitYes: + lib_showmatches_box->setChecked(true); + break; + + case RDLibraryConf::LimitPrevious: + lib_showmatches_box->setChecked(rdlibrary_conf->searchLimited()); + break; + } + + LoadGeometry(); +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(800,600); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::connectedData(bool state) +{ +} + + +void MainWidget::userData() +{ + QString sql; + RDSqlQuery *q; + + if(lib_edit_pending) { + lib_user_changed=true; + return; + } + + SetCaption(rdripc->user()); + if(lib_user!=NULL) { + delete lib_user; + } + lib_user=new RDUser(rdripc->user()); + + lib_group_box->clear(); + lib_group_box->insertItem(tr("ALL")); + sql=QString("select GROUP_NAME from USER_PERMS where ")+ + "USER_NAME=\""+RDEscapeString(lib_user->name())+"\" order by GROUP_NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + lib_group_box->insertItem(q->value(0).toString()); + } + delete q; + + if(lib_group_box->count()==1) { + lib_add_button->setDisabled(true); + lib_edit_button->setDisabled(true); + lib_delete_button->setDisabled(true); + lib_rip_button->setDisabled(true); + } + else { + lib_add_button->setEnabled(lib_user->createCarts()); + lib_edit_button->setEnabled(true); + lib_delete_button->setEnabled(lib_user->deleteCarts()); + lib_rip_button->setEnabled(lib_user->editAudio()); + } + + lib_codes_box->clear(); + lib_codes_box->insertItem(tr("ALL")); + sql=QString().sprintf("select CODE from SCHED_CODES"); + q=new RDSqlQuery(sql); + while(q->next()) { + lib_codes_box->insertItem(q->value(0).toString()); + } + delete q; + lib_search_button->setDisabled(true); + groupActivatedData(lib_group_box->currentText()); +} + + +void MainWidget::filterChangedData(const QString &str) +{ + lib_search_button->setEnabled(true); + if(lib_filter_mode!=RDStation::FilterSynchronous) { + return; + } + searchClickedData(); +} + + +void MainWidget::searchClickedData() +{ + lib_search_button->setDisabled(true); + if(lib_filter_edit->text().isEmpty()) { + lib_clear_button->setDisabled(true); + } + else { + lib_clear_button->setEnabled(true); + } + RefreshList(); +} + + +void MainWidget::clearClickedData() +{ + lib_filter_edit->clear(); + filterChangedData(""); +} + + +void MainWidget::groupActivatedData(const QString &str) +{ + if(str!=tr("ALL")) { + lib_default_group=str; + } + filterChangedData(""); +} + + +void MainWidget::addData() +{ + QString sql; + RDSqlQuery *q; + int cart_num; + RDCart::Type cart_type=RDCart::All; + QString cart_title; + + LockUser(); + + RDAddCart *add_cart=new RDAddCart(&lib_default_group,&cart_type,&cart_title, + lib_user->name(),lib_system, + this,"add_cart"); + if((cart_num=add_cart->exec())<0) { + delete add_cart; + UnlockUser(); + return; + } + delete add_cart; + sql=QString("insert into CART set ")+ + QString().sprintf("NUMBER=%u,TYPE=%d,",cart_num,cart_type)+ + "GROUP_NAME=\""+RDEscapeString(lib_default_group)+"\","+ + "TITLE=\""+RDEscapeString(cart_title)+"\""; + q=new RDSqlQuery(sql); + delete q; + + EditCart *cart= + new EditCart(cart_num,&lib_import_path,true,profile_ripping,this); + if(cart->exec() <0) { + RDCart *rdcart=new RDCart(cart_num); + rdcart->remove(rdstation_conf,lib_user,lib_config); + delete rdcart; + } + else { + RDListViewItem *item=new RDListViewItem(lib_cart_list); + item->setText(1,QString().sprintf("%06u",cart_num)); + RefreshLine(item); + QListViewItemIterator it(lib_cart_list); + while(it.current()) { + lib_cart_list->setSelected(it.current(),false); + ++it; + } + lib_cart_list->setSelected(item,true); + lib_cart_list->ensureItemVisible(item); + } + delete cart; + + UnlockUser(); +} + + + +void MainWidget::editData() +{ + int sel_count=0; + QListViewItemIterator *it; + + LockUser(); + + it=new QListViewItemIterator(lib_cart_list); + while(it->current()) { + if (it->current()->isSelected()) { + sel_count++; + } + ++(*it); + } + delete it; + + if(sel_count==0) { + UnlockUser(); + return; + } + if(sel_count==1) { //single edit + it=new QListViewItemIterator(lib_cart_list); + while(!it->current()->isSelected()) { + ++(*it); + } + RDListViewItem *item=(RDListViewItem *)it->current(); + + EditCart *edit_cart=new EditCart(item->text(1).toUInt(),&lib_import_path, + false,profile_ripping,this); + edit_cart->exec(); + RefreshLine(item); + cartOnItemData(item); + delete edit_cart; + delete it; + } + else { //multi edit + if(lib_user->modifyCarts()) { + EditCart *edit_cart= + new EditCart(0,&lib_import_path,false,profile_ripping,this,"", + lib_cart_list); + + edit_cart->exec(); + delete edit_cart; + + it=new QListViewItemIterator(lib_cart_list); + while(it->current()) { + if (it->current()->isSelected()) { + RefreshLine((RDListViewItem *)it->current()); + } + ++(*it); + } + delete it; + } + } + UnlockUser(); +} + + +void MainWidget::deleteData() +{ + QString filename; + QString sql; + RDSqlQuery *q; + QString str; + int sel_count=0; + QListViewItemIterator *it; + bool del_flag; + + LockUser(); + + it=new QListViewItemIterator(lib_cart_list); + while(it->current()) { + if (it->current()->isSelected()) { + sel_count++; + } + ++(*it); + } + delete it; + + if(sel_count==0) { + UnlockUser(); + return; + } + + str=QString(tr("Are you sure you want to delete cart(s)")); + if(QMessageBox::question(this,tr("Delete Cart(s)"),str,QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + UnlockUser(); + return; + } + it=new QListViewItemIterator(lib_cart_list); + while(it->current()) { + if (it->current()->isSelected()) { + del_flag=true; + RDListViewItem *item=(RDListViewItem *)it->current(); + sql=QString().sprintf("select CUT_NAME from RECORDINGS where \ + (CUT_NAME like \"%06u_%%\")||(MACRO_CART=%u)", + item->text(1).toUInt(),item->text(1).toUInt()); + q=new RDSqlQuery(sql); + if(q->first()) { + QString str=QString().sprintf(tr("Cart %06u is used in one or more RDCatch events!\n\ +Do you still want to delete it?"),item->text(1).toUInt()); + if(QMessageBox::warning(this,tr("RDCatch Event Exists"),str, + QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) { + del_flag=false; + } + } + delete q; + if(cut_clipboard!=NULL) { + if(item->text(1).toUInt()==cut_clipboard->cartNumber()) { + QString str=QString().sprintf(tr("Deleting cart %06u will also empty the clipboard.\n\ + Do you still want to proceed?"),item->text(1).toUInt()); + switch(QMessageBox::question(this,tr("Empty Clipboard"),str, + QMessageBox::Yes, + QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + del_flag=false; + + default: + break; + } + delete cut_clipboard; + cut_clipboard=NULL; + } + } + if(del_flag && item->text(21).isEmpty()) { + RDCart *rdcart=new RDCart(item->text(1).toUInt()); + if(!rdcart->remove(rdstation_conf,lib_user,lib_config)) { + QMessageBox::warning(this,tr("RDLibrary"),tr("Unable to delete audio!")); + return; + } + delete rdcart; + delete item; + } + else { + ++(*it); + } + } + else { + ++(*it); + } + } + delete it; + + UnlockUser(); +} + + +void MainWidget::ripData() +{ + LockUser(); + QString group=lib_group_box->currentText(); + QString schedcode=lib_codes_box->currentText(); + DiskRipper *dialog=new DiskRipper(&lib_filter_text,&group,&schedcode, + profile_ripping,this,"disk_ripper"); + if(dialog->exec()==0) { + for(int i=0;icount();i++) { + if(lib_group_box->text(i)==*group) { + lib_filter_edit->setText(lib_filter_text); + lib_group_box->setCurrentItem(i); + groupActivatedData(lib_group_box->currentText()); + } + } + } + delete dialog; + if(!UnlockUser()) { + RefreshList(); + } +} + + +void MainWidget::reportsData() +{ + LockUser(); + ListReports *lr= + new ListReports(lib_filter_edit->text(),GetTypeFilter(), + lib_group_box->currentText(),lib_codes_box->currentText(), + this,"lr"); + lr->exec(); + delete lr; + UnlockUser(); +} + + +void MainWidget::cartOnItemData(QListViewItem *item) +{ + if((!lib_shownotes_box->isChecked())||(item==NULL)) { + return; + } + lib_cart_tip-> + setCartNumber(lib_cart_list->itemRect(item),item->text(1).toUInt()); +} + + +void MainWidget::cartClickedData(QListViewItem *item) +{ + int del_count=0; + int sel_count=0; + QListViewItemIterator *it; + + it=new QListViewItemIterator(lib_cart_list); + while(it->current()) { + if (it->current()->isSelected()) { + sel_count++; + if(it->current()->text(21).isEmpty()) { + del_count++; + } + } + ++(*it); + } + delete it; + + if(del_count>0) { + lib_delete_button->setEnabled(lib_user->deleteCarts()); + } + else { + lib_delete_button->setEnabled(false); + } + if(sel_count>1) { + if(del_count==0) { + lib_edit_button->setEnabled(false); + } + else { + lib_edit_button->setEnabled(lib_user->modifyCarts()); + } + } + else { + lib_edit_button->setEnabled(true); + } +} + + +void MainWidget::cartDoubleclickedData(QListViewItem *,const QPoint &,int) +{ + editData(); +} + + +void MainWidget::audioChangedData(int state) +{ + filterChangedData(""); +} + + +void MainWidget::macroChangedData(int state) +{ + filterChangedData(""); +} + + +void MainWidget::searchLimitChangedData(int state) +{ + rdlibrary_conf->setSearchLimited(state); + filterChangedData(""); +} + + +void MainWidget::dragsChangedData(int state) +{ + if(state) { + lib_cart_list->setSelectionMode(QListView::Single); + } + else { + lib_cart_list->setSelectionMode(QListView::Extended); + } +} + + +void MainWidget::quitMainWidget() +{ + SaveGeometry(); + exit(0); +} + + +void MainWidget::closeEvent(QCloseEvent *e) +{ + quitMainWidget(); +} + + +void MainWidget::resizeEvent(QResizeEvent *e) +{ + switch(lib_filter_mode) { + case RDStation::FilterSynchronous: + lib_filter_edit->setGeometry(70,10,e->size().width()-170,20); + break; + + case RDStation::FilterAsynchronous: + lib_search_button->setGeometry(e->size().width()-180,10,80,50); + lib_filter_edit->setGeometry(70,10,e->size().width()-260,20); + break; + } + lib_clear_button->setGeometry(e->size().width()-90,10,80,50); + lib_filter_label->setGeometry(10,10,55,20); + lib_group_box->setGeometry(70,40,120,20); + lib_group_label->setGeometry(10,40,55,20); + lib_codes_box->setGeometry(330,40,120,20); + lib_codes_label->setGeometry(195,40,130,20); + lib_allowdrag_box->setGeometry(470,42,15,15); + lib_allowdrag_label->setGeometry(490,40,130,20); + lib_showaudio_box->setGeometry(70,67,15,15); + lib_showaudio_label->setGeometry(90,65,130,20); + lib_showmacro_box->setGeometry(230,67,15,15); + lib_showmacro_label->setGeometry(250,65,130,20); + lib_shownotes_box->setGeometry(390,67,15,15); + lib_shownotes_label->setGeometry(410,65,130,20); + lib_showmatches_box->setGeometry(550,67,15,15); + lib_showmatches_label->setGeometry(570,65,200,20); + lib_cart_list-> + setGeometry(10,90,e->size().width()-20,e->size().height()-155); + lib_add_button->setGeometry(10,e->size().height()-60,80,50); + lib_edit_button->setGeometry(100,e->size().height()-60,80,50); + lib_delete_button->setGeometry(190,e->size().height()-60,80,50); + disk_gauge->setGeometry(285,e->size().height()-55, + e->size().width()-585, + disk_gauge->sizeHint().height()); + lib_rip_button-> + setGeometry(e->size().width()-290,e->size().height()-60,80,50); + lib_reports_button-> + setGeometry(e->size().width()-200,e->size().height()-60,80,50); + lib_close_button->setGeometry(e->size().width()-90,e->size().height()-60, + 80,50); +} + + +void MainWidget::RefreshList() +{ + RDSqlQuery *q; + QString sql; + RDListViewItem *l=NULL; + QString type_filter; + QDateTime current_datetime(QDate::currentDate(),QTime::currentTime()); + unsigned cartnum=0; + RDCart::Validity validity=RDCart::NeverValid; + QDateTime end_datetime; + + lib_cart_list->clear(); + + type_filter=GetTypeFilter(); + if(type_filter.isEmpty()) { + return; + } + + // + // 00 - CART.NUMBER + // 01 - CART.FORCED_LENGTH + // 02 - CART.TITLE + // 03 - CART.ARTIST + // 04 - CART.ALBUM + // 05 - CART.LABEL + // 06 - CART.CLIENT + // 07 - CART.AGENCY + // 08 - CART.USER_DEFINED + // 09 - CART.COMPOSER + // 10 - CART.PUBLISHER + // 11 - CART.CONDUCTOR + // 12 - CART.GROUP_NAME + // 13 - CART.START_DATETIME + // 14 - CART.END_DATETIME + // 15 - CART.TYPE + // 16 - CART.CUT_QUANTITY + // 17 - CART.LAST_CUT_PLAYED + // 18 - CART.ENFORCE_LENGTH + // 19 - CART.PRESERVE_PITCH + // 20 - CART.LENGTH_DEVIATION + // 21 - CART.OWNER + // 22 - CART.VALIDITY + // 23 - GROUPS.COLOR + // 24 - CUTS.LENGTH + // 25 - CUTS.EVERGREEN + // 26 - CUTS.START_DATETIME + // 27 - CUTS.END_DATETIME + // 28 - CUTS.START_DAYPART + // 29 - CUTS.END_DAYPART + // 30 - CUTS.MON + // 31 - CUTS.TUE + // 32 - CUTS.WED + // 33 - CUTS.THU + // 34 - CUTS.FRI + // 35 - CUTS.SAT + // 36 - CUTS.SUN + // + + sql="select CART.NUMBER,CART.FORCED_LENGTH,CART.TITLE,CART.ARTIST,\ + CART.ALBUM,CART.LABEL,\ + CART.CLIENT,CART.AGENCY,CART.USER_DEFINED,\ + CART.COMPOSER,CART.PUBLISHER,CART.CONDUCTOR,\ + CART.GROUP_NAME,CART.START_DATETIME,CART.END_DATETIME,CART.TYPE,\ + CART.CUT_QUANTITY,CART.LAST_CUT_PLAYED,\ + CART.ENFORCE_LENGTH,CART.PRESERVE_PITCH,\ + CART.LENGTH_DEVIATION,CART.OWNER,CART.VALIDITY,GROUPS.COLOR, \ + CUTS.LENGTH,CUTS.EVERGREEN,CUTS.START_DATETIME,CUTS.END_DATETIME,\ + CUTS.START_DAYPART,CUTS.END_DAYPART,CUTS.MON,CUTS.TUE,\ + CUTS.WED,CUTS.THU,CUTS.FRI,CUTS.SAT,CUTS.SUN from CART \ + left join GROUPS on CART.GROUP_NAME=GROUPS.NAME \ + left join CUTS on CART.NUMBER=CUTS.CART_NUMBER"; + QString schedcode=""; + if(lib_codes_box->currentText()!=tr("ALL")) { + schedcode=lib_codes_box->currentText(); + } + if(lib_group_box->currentText()==QString(tr("ALL"))) { + sql+=QString(" where ")+ + RDAllCartSearchText(lib_filter_edit->text(),schedcode, + lib_user->name(),true)+" && "+type_filter; + + } + else { + sql+=QString(" where ")+ + RDCartSearchText(lib_filter_edit->text(),lib_group_box->currentText(), + schedcode,true)+" && "+type_filter; + } + sql+=" order by CART.NUMBER"; + if(lib_showmatches_box->isChecked()) { + sql+=QString().sprintf(" limit %d",RD_LIMITED_CART_SEARCH_QUANTITY); + } + q=new RDSqlQuery(sql); + int step=0; + int count=0; + lib_progress_dialog->setTotalSteps(q->size()/RDLIBRARY_STEP_SIZE); + lib_progress_dialog->setProgress(0); + while(q->next()) { + end_datetime=q->value(14).toDateTime(); + if(q->value(0).toUInt()==cartnum) { + if((RDCart::Type)q->value(15).toUInt()==RDCart::Macro) { + validity=RDCart::AlwaysValid; + } + else { + validity=ValidateCut(q,24,validity,current_datetime); + } + } + else { + // + // Write availability color + // + UpdateItemColor(l,validity,q->value(14).toDateTime(),current_datetime); + + // + // Start a new entry + // + if((RDCart::Type)q->value(15).toUInt()==RDCart::Macro) { + validity=RDCart::AlwaysValid; + } + else { + validity=ValidateCut(q,24,RDCart::NeverValid,current_datetime); + } + l=new RDListViewItem(lib_cart_list); + switch((RDCart::Type)q->value(15).toUInt()) { + case RDCart::Audio: + if(q->value(21).isNull()) { + l->setPixmap(0,*lib_playout_map); + } + else { + l->setPixmap(0,*lib_track_cart_map); + } + break; + + case RDCart::Macro: + l->setPixmap(0,*lib_macro_map); + l->setBackgroundColor(backgroundColor()); + break; + + case RDCart::All: + break; + } + l->setText(1,QString().sprintf("%06d",q->value(0).toUInt())); + l->setText(2,q->value(12).toString()); + l->setTextColor(2,q->value(23).toString(),QFont::Bold); + l->setText(3,RDGetTimeLength(q->value(1).toUInt())); + l->setText(4,q->value(2).toString()); + l->setText(5,q->value(3).toString()); + if(!q->value(13).toDateTime().isNull()) { + l->setText(6,q->value(13).toDateTime(). + toString("MM/dd/yyyy - hh:mm:ss")); + } + if(!q->value(14).toDateTime().isNull()) { + l->setText(7,q->value(14).toDateTime(). + toString("MM/dd/yyyy - hh:mm:ss")); + } + else { + l->setText(7,"TFN"); + } + l->setText(8,q->value(4).toString()); + l->setText(9,q->value(5).toString()); + l->setText(10,q->value(9).toString()); + l->setText(11,q->value(11).toString()); + l->setText(12,q->value(10).toString()); + l->setText(13,q->value(6).toString()); + l->setText(14,q->value(7).toString()); + l->setText(15,q->value(8).toString()); + l->setText(16,q->value(16).toString()); + l->setText(17,q->value(17).toString()); + l->setText(18,q->value(18).toString()); + l->setText(19,q->value(19).toString()); + l->setText(20,q->value(20).toString()); + l->setText(21,q->value(21).toString()); + if(q->value(18).toString()=="Y") { + l->setTextColor(3,QColor(RDLIBRARY_ENFORCE_LENGTH_COLOR),QFont::Bold); + } + else { + if((q->value(20).toUInt()>RDLIBRARY_MID_LENGTH_LIMIT)&& + (q->value(18).toString()=="N")) { + if(q->value(20).toUInt()>RDLIBRARY_MAX_LENGTH_LIMIT) { + l->setTextColor(3,QColor(RDLIBRARY_MAX_LENGTH_COLOR),QFont::Bold); + } + else { + l->setTextColor(3,QColor(RDLIBRARY_MID_LENGTH_COLOR),QFont::Bold); + } + } + else { + l->setTextColor(3,QColor(black),QFont::Normal); + } + } + } + cartnum=q->value(0).toUInt(); + if(count++>RDLIBRARY_STEP_SIZE) { + lib_progress_dialog->setProgress(++step); + count=0; + qApp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput); + } + } + UpdateItemColor(l,validity,end_datetime,current_datetime); + lib_progress_dialog->reset(); + delete q; +} + + +void SigHandler(int signo) +{ + pid_t pLocalPid; + + switch(signo) { + case SIGCHLD: + pLocalPid=waitpid(-1,NULL,WNOHANG); + while(pLocalPid>0) { + pLocalPid=waitpid(-1,NULL,WNOHANG); + } + ripper_running=false; + import_active=false; + signal(SIGCHLD,SigHandler); + break; + } +} + + +void MainWidget::RefreshLine(RDListViewItem *item) +{ + RDCart::Validity validity=RDCart::NeverValid; + QDateTime current_datetime(QDate::currentDate(),QTime::currentTime()); + QString sql=QString().sprintf("select CART.FORCED_LENGTH,CART.TITLE,\ + CART.ARTIST,\ + CART.ALBUM,CART.LABEL,\ + CART.CLIENT,\ + CART.AGENCY,CART.USER_DEFINED,\ + CART.COMPOSER,CART.CONDUCTOR,CART.PUBLISHER,\ + CART.GROUP_NAME,CART.START_DATETIME,\ + CART.END_DATETIME,CART.TYPE,\ + CART.CUT_QUANTITY,CART.LAST_CUT_PLAYED,\ + CART.ENFORCE_LENGTH,\ + CART.PRESERVE_PITCH,\ + CART.LENGTH_DEVIATION,CART.OWNER,\ + CART.VALIDITY,GROUPS.COLOR,CUTS.LENGTH,\ + CUTS.EVERGREEN,CUTS.START_DATETIME,\ + CUTS.END_DATETIME,CUTS.START_DAYPART,\ + CUTS.END_DAYPART,CUTS.MON,CUTS.TUE,\ + CUTS.WED,CUTS.THU,CUTS.FRI,CUTS.SAT,CUTS.SUN \ + from CART left join GROUPS on \ + CART.GROUP_NAME=GROUPS.NAME left join \ + CUTS on CART.NUMBER=CUTS.CART_NUMBER \ + where CART.NUMBER=%u", + item->text(1).toUInt()); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + if((RDCart::Type)q->value(14).toUInt()==RDCart::Macro) { + validity=RDCart::AlwaysValid; + } + else { + validity=ValidateCut(q,23,validity,current_datetime); + } + switch((RDCart::Type)q->value(14).toUInt()) { + case RDCart::Audio: + if(q->value(20).isNull()) { + item->setPixmap(0,*lib_playout_map); + } + else { + item->setPixmap(0,*lib_track_cart_map); + } + if(q->value(0).toUInt()==0) { + item->setBackgroundColor(RD_CART_ERROR_COLOR); + } + else { + UpdateItemColor(item,validity, + q->value(13).toDateTime(),current_datetime); + } + break; + + case RDCart::Macro: + item->setPixmap(0,*lib_macro_map); + break; + + case RDCart::All: + break; + } + item->setText(2,q->value(11).toString()); + item->setTextColor(2,q->value(22).toString(),QFont::Bold); + item->setText(3,RDGetTimeLength(q->value(0).toUInt())); + item->setText(4,q->value(1).toString()); + item->setText(5,q->value(2).toString()); + item->setText(8,q->value(3).toString()); + item->setText(9,q->value(4).toString()); + item->setText(10,q->value(8).toString()); + item->setText(11,q->value(9).toString()); + + item->setText(12,q->value(10).toString()); + item->setText(13,q->value(5).toString()); + item->setText(14,q->value(6).toString()); + if(!q->value(12).toDateTime().isNull()) { + item->setText(6,q->value(12).toDateTime(). + toString("MM/dd/yyyy - hh:mm:ss")); + } + else { + item->setText(6,""); + } + if(!q->value(13).toDateTime().isNull()) { + item->setText(7,q->value(13).toDateTime(). + toString("MM/dd/yyyy - hh:mm:ss")); + } + else { + item->setText(7,tr("TFN")); + } + item->setText(16,q->value(15).toString()); + item->setText(17,q->value(16).toString()); + item->setText(18,q->value(17).toString()); + item->setText(19,q->value(18).toString()); + item->setText(20,q->value(19).toString()); + item->setText(21,q->value(20).toString()); + if(q->value(17).toString()=="Y") { + item->setTextColor(3,QColor(RDLIBRARY_ENFORCE_LENGTH_COLOR),QFont::Bold); + } + else { + if((q->value(19).toUInt()>RDLIBRARY_MID_LENGTH_LIMIT)&& + (q->value(17).toString()=="N")) { + if(q->value(19).toUInt()>RDLIBRARY_MAX_LENGTH_LIMIT) { + item->setTextColor(3,QColor(RDLIBRARY_MAX_LENGTH_COLOR),QFont::Bold); + } + else { + item->setTextColor(3,QColor(RDLIBRARY_MID_LENGTH_COLOR),QFont::Bold); + } + } + else { + item->setTextColor(3,QColor(black),QFont::Normal); + } + } + } + delete q; +} + + +void MainWidget::UpdateItemColor(RDListViewItem *item, + RDCart::Validity validity, + const QDateTime &end_datetime, + const QDateTime ¤t_datetime) +{ + if(item!=NULL) { + switch(validity) { + case RDCart::NeverValid: + item->setBackgroundColor(RD_CART_ERROR_COLOR); + break; + + case RDCart::ConditionallyValid: + if(end_datetime.isValid()&& + (end_datetimesetBackgroundColor(RD_CART_ERROR_COLOR); + } + else { + item->setBackgroundColor(RD_CART_CONDITIONAL_COLOR); + } + break; + + case RDCart::FutureValid: + item->setBackgroundColor(RD_CART_FUTURE_COLOR); + break; + + case RDCart::AlwaysValid: + item->setBackgroundColor(palette().color(QPalette::Active, + QColorGroup::Base)); + break; + + case RDCart::EvergreenValid: + item->setBackgroundColor(RD_CART_EVERGREEN_COLOR); + break; + } + } +} + + +void MainWidget::SetCaption(QString user) +{ + QString str1; + QString str2; + + str1=QString("RDLibrary")+" v"+VERSION+" - "+tr("Host")+":"; + str2=tr("User")+":"; + setCaption(str1+" "+lib_config->stationName()+", "+str2+" "+user); +} + + +QString MainWidget::GetTypeFilter() +{ + QString type_filter; + + if(lib_showaudio_box->isChecked()) { + if(lib_showmacro_box->isChecked()) { + type_filter="((TYPE=1)||(TYPE=2)||(TYPE=3))"; + } + else { + type_filter="((TYPE=1)||(TYPE=3))"; + } + } + else { + if(lib_showmacro_box->isChecked()) { + type_filter="(TYPE=2)"; + } + } + return type_filter; +} + + +void MainWidget::LoadGeometry() +{ + if(getenv("HOME")==NULL) { + return; + } + RDProfile *profile=new RDProfile(); + profile-> + setSource(QString().sprintf("%s/%s",getenv("HOME"), + RDLIBRARY_GEOMETRY_FILE)); + resize(profile->intValue("RDLibrary","Width",sizeHint().width()), + profile->intValue("RDLibrary","Height",sizeHint().height())); + lib_shownotes_box-> + setChecked(profile->boolValue("RDLibrary","ShowNoteBubbles",true)); + + delete profile; +} + + +void MainWidget::SaveGeometry() +{ + if(getenv("HOME")==NULL) { + return; + } + FILE *file=fopen((const char *)QString(). + sprintf("%s/%s",getenv("HOME"),RDLIBRARY_GEOMETRY_FILE), + "w"); + if(file==NULL) { + return; + } + fprintf(file,"[RDLibrary]\n"); + fprintf(file,"Width=%d\n",geometry().width()); + fprintf(file,"Height=%d\n",geometry().height()); + fprintf(file,"ShowNoteBubbles="); + if(lib_shownotes_box->isChecked()) { + fprintf(file,"Yes\n"); + } + else { + fprintf(file,"No\n"); + } + fprintf(file,"LimitMatches="); + if(lib_showmatches_box->isChecked()) { + fprintf(file,"Yes\n"); + } + else { + fprintf(file,"No\n"); + } + + fclose(file); +} + + +void MainWidget::LockUser() +{ + lib_edit_pending=true; +} + + +bool MainWidget::UnlockUser() +{ + bool ret=lib_user_changed; + lib_edit_pending=false; + if(lib_user_changed) { + lib_user_timer->start(0,true); + lib_user_changed=false; + } + return ret; +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(), + "."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rdlibrary_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->show(); + return a.exec(); +} diff --git a/rdlibrary/rdlibrary.h b/rdlibrary/rdlibrary.h new file mode 100644 index 00000000..50bc3422 --- /dev/null +++ b/rdlibrary/rdlibrary.h @@ -0,0 +1,155 @@ +// rdlibrary.h +// +// The Production Utility for Rivendell. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rdlibrary.h,v 1.45.8.4 2014/01/21 19:12:42 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDLIBRARY_H +#define RDLIBRARY_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define RDLIBRARY_GEOMETRY_FILE ".rdlibrary" +#define RDLIBRARY_STEP_SIZE 5000 + +// +// Cut Length Deviation Values +// +#define RDLIBRARY_MID_LENGTH_LIMIT 500 +#define RDLIBRARY_MID_LENGTH_COLOR darkYellow +#define RDLIBRARY_MAX_LENGTH_LIMIT 1500 +#define RDLIBRARY_MAX_LENGTH_COLOR red +#define RDLIBRARY_ENFORCE_LENGTH_COLOR blue + +#define RDLIBRARY_USAGE "[--profile-ripping]\n\n--profile-ripping\n Print profiling information to stdout when performing rips from\n optical media.\n\n" + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void connectedData(bool state); + void userData(); + void filterChangedData(const QString &str); + void searchClickedData(); + void clearClickedData(); + void groupActivatedData(const QString &str); + void addData(); + void editData(); + void deleteData(); + void ripData(); + void reportsData(); + void cartOnItemData(QListViewItem *item); + void cartClickedData(QListViewItem *item); + void cartDoubleclickedData(QListViewItem *,const QPoint &,int); + void audioChangedData(int state); + void macroChangedData(int state); + void searchLimitChangedData(int state); + void dragsChangedData(int state); + void quitMainWidget(); + + protected: + void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e); + + private: + void RefreshList(); + void RefreshLine(RDListViewItem *item); + void UpdateItemColor(RDListViewItem *item,RDCart::Validity validity, + const QDateTime &end_datetime, + const QDateTime ¤t_datetime); + void SetCaption(QString user); + QString GetTypeFilter(); + void LoadGeometry(); + void SaveGeometry(); + void LockUser(); + bool UnlockUser(); + LibListView *lib_cart_list; + CartTip *lib_cart_tip; + QString lib_filter_text; + QString lib_search_text; + QPixmap *lib_playout_map; + QPixmap *lib_macro_map; + QPixmap *lib_track_cart_map; + QLineEdit *lib_filter_edit; + QLabel *lib_filter_label; + QComboBox *lib_group_box; + QLabel *lib_group_label; + QComboBox *lib_codes_box; + QLabel *lib_codes_label; + QPushButton *lib_search_button; + QPushButton *lib_clear_button; + QPushButton *lib_add_button; + QPushButton *lib_edit_button; + QPushButton *lib_delete_button; + QPushButton *lib_rip_button; + QPushButton *lib_reports_button; + QPushButton *lib_close_button; + QCheckBox *lib_allowdrag_box; + QLabel *lib_allowdrag_label; + QCheckBox *lib_showaudio_box; + QLabel *lib_showaudio_label; + QCheckBox *lib_showmacro_box; + QLabel *lib_shownotes_label; + QCheckBox *lib_shownotes_box; + QLabel *lib_showmatches_label; + QCheckBox *lib_showmatches_box; + QLabel *lib_showmacro_label; + QString lib_default_group; + QString lib_import_path; + QPixmap *lib_rivendell_map; + RDStation::FilterMode lib_filter_mode; + QProgressDialog *lib_progress_dialog; + bool profile_ripping; + bool lib_edit_pending; + bool lib_user_changed; + QTimer *lib_user_timer; +}; + + +#endif diff --git a/rdlibrary/rdlibrary.pro b/rdlibrary/rdlibrary.pro new file mode 100644 index 00000000..273238b7 --- /dev/null +++ b/rdlibrary/rdlibrary.pro @@ -0,0 +1,66 @@ +# rdlibrary.pro +# +# The QMake project file for RDLibrary. +# +# (C) Copyright 2003-2005 Fred Gleason +# +# $Id: rdlibrary.pro,v 1.11.2.3 2014/01/08 02:08:38 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +x11 { + SOURCES += audio_cart.cpp + SOURCES += cdripper.cpp + SOURCES += disk_gauge.cpp + SOURCES += disk_ripper.cpp + SOURCES += edit_cart.cpp + SOURCES += edit_macro.cpp + SOURCES += edit_notes.cpp + SOURCES += edit_schedulercodes.cpp + SOURCES += filter.cpp + SOURCES += lib_listview.cpp + SOURCES += list_reports.cpp + SOURCES += macro_cart.cpp + SOURCES += rdlibrary.cpp + SOURCES += record_cut.cpp + SOURCES += validate_cut.cpp +} + +x11 { + HEADERS += audio_cart.h + HEADERS += cdripper.h + HEADERS += disk_gauge.h + HEADERS += disk_ripper.h + HEADERS += edit_cart.h + HEADERS += edit_macro.h + HEADERS += edit_notes.h + HEADERS += edit_schedulercodes.h + HEADERS += filter.h + HEADERS += lib_listview.h + HEADERS += list_reports.h + HEADERS += macro_cart.h + HEADERS += rdlibrary.h + HEADERS += record_cut.h + HEADERS += validate_cut.h +} + +TRANSLATIONS += rdlibrary_cs.ts +TRANSLATIONS += rdlibrary_de.ts +TRANSLATIONS += rdlibrary_es.ts +TRANSLATIONS += rdlibrary_fr.ts +TRANSLATIONS += rdlibrary_nb.ts +TRANSLATIONS += rdlibrary_nn.ts +TRANSLATIONS += rdlibrary_pt_BR.ts diff --git a/rdlibrary/rdlibrary_cs.ts b/rdlibrary/rdlibrary_cs.ts new file mode 100644 index 00000000..6a19bf68 --- /dev/null +++ b/rdlibrary/rdlibrary_cs.ts @@ -0,0 +1,1549 @@ + + + AudioCart + + Copying audio... + Kopíruje se zvuk... + + + Add + Přidat + + + Delete + Smazat + + + Copy + Kopírovat + + + Paste + Vložit + + + WT + WT + + + DESCRIPTION + POPIS + + + LENGTH + DÉLKA + + + LAST PLAYED + NAPOSLEDY HRÁNO + + + # OF PLAYS + # PŘEHRÁNÍ + + + ORIGIN + PŮVOD + + + OUTCUE + OUTCUE + + + START DATE + POČÁTEČNÍ DATUM + + + END DATE + KONCOVÉ DATUM + + + DAYPART START + ZAČÁTEK ČÁSTI DNE + + + DAYPART END + KONEC ČÁSTI DNE + + + NAME + NÁZEV + + + Cuts + Záběry + + + Cut Info + Informace o záběru + + + Record + Nahrávat + + + Edit +Audio + Upravit +zvuk + + + Edit +Markers + Upravit +značky + + + Import + Zavést + + + Export + Vyvést + + + Rip CD + Vytáhnout z CD + + + Are you sure you want to delete + Jste si jistý, že chcete smazat + + + Delete Cut + Smazat záběr + + + RDCatch Event Exists + Událost RDCatch existuje + + + This cut is used in one or more RDCatch events! +Do you still want to delete it? + Tento záběr se použije na jednu nebo více událostí RDCatch! +Přesto smazat? + + + Empty Clipboard + Vyprázdnit schránku + + + Deleting this cut will also empty the clipboard. +Do you still want to proceed? + Smazání tohoto záběru vyprázdní také schránku. +Přesto smazat? + + + Clipboard Empty + Schránka prázdná + + + Clipboard is currently empty. + Schránka je nyní prázdná. + + + Audio Exists + Zvuk existuje + + + This will overwrite the existing recording. +Do you want to proceed? + Toto přepíše (smaže) stávající nahrávku. +Přesto pokračovat? + + + [new cart] + [nový vozík] + + + Never + Nikdy + + + None + Žádný + + + 1 Cut + 1 záběr + + + RDLibrary + RDLibrary + + + Unable to delete audio! + Soubor(y) se zvukem nelze smazat! + + + No audio is present in the cut! + V záběru není přítomen žádný zvuk! + + + This cart cannot contain any additional cuts! + + + + RDLibrary - Edit Cart + + + + Delete Cuts + + + + cuts + + + + One or more cuts are used in one or more RDCatch events! +Do you still want to delete? + + + + Unable to delete audio for cut + + + + Copy Cut + + + + No data copied - you must select a single cut! + + + + Paste Cut + + + + You must select a single cut! + + + + + CdRipper + + Artist: + Umělec: + + + Album: + Album: + + + Other: + Jiné: + + + Apply FreeDB Values to Cart + Použít hodnoty FreeDB na vozík + + + Tracks + Skladby + + + TRACK + STOPA + + + LENGTH + DÉLKA + + + TITLE + NÁZEV + + + OTHER + JINÉ + + + TYPE + TYP + + + &Rip +Track + &Vytáhnout +stopu + + + Normalize + Normalizovat + + + Level: + Úroveň: + + + dBFS + dbFS + + + Autotrim + Automatické zastřižení + + + Channels: + Kanály: + + + Audio Exists + Zvuk existuje + + + This will overwrite the existing recording. +Do you want to proceed? + Toto přepíše (smaže) stávající nahrávku. +Přesto pokračovat? + + + Empty Clipboard + Vyprázdnit schránku + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + Vytažení tohoto záběru vyprázdní také schránku. +Přesto smazat? + + + No Access + Kein Zugriff + + + Unable to open the file for writing! + Kann die Datei nicht zum schreiben öffnen! + + + OK + OK + + + Audio Track + Zvuková stopa + + + Data Track + Datová stopa + + + Rip Complete + Vytažení dokončeno + + + Rip complete! + Vytažení dokončeno! + + + Rip Aborted + Rip abgebrochen + + + The rip has been aborted. + Der Rip wurde abgebrochen. + + + Rip Failed + Rip fehlgeschlagen + + + The ripper encountered an error. +Please check your ripper configuration and try again. + Der Ripper hat einen Fehler bemerkt. +Bitte überprüfen sie ihre Ripperkonfiguration und versuchen sie es erneut. + + + RDLibrary - Importer Error + RDLibrary - Chyba při zavedení + + + RDLibrary - Ripper Error + RDLibrary - Chyba ve vytahovači + + + Abort +Rip + Zrušit +vytahování + + + Rip Track + Vytáhnout stopu + + + Title: + + + + [none] + + + + Ripper Error + + + + Unable to create temporary directory! + + + + + DiskRipper + + Rip Disk + Vytáhnout z CD + + + Artist: + Umělec: + + + Album: + Album: + + + Other: + Jiné: + + + Apply FreeDB Values to Carts + Použít hodnoty FreeDB na vozíky + + + Tracks + Stopy + + + TRACK + STOPA + + + LENGTH + DÉLKA + + + TITLE + NÁZEV + + + OTHER + JINÉ + + + TYPE + TYP + + + CUT + ZÁBĚR + + + Disk Progress + Celkový postup + + + Track Progress + Postup stopy + + + Set +&Cut + Nastavit +&záběr + + + Set All +&New Carts + Nastavit všechny +&nové vozíky + + + Normalize + Normalizovat + + + Level: + Úroveň: + + + dBFS + dbFS + + + Autotrim + Automatické zastřižení + + + Channels: + Kanály: + + + &Close + &Zavřít + + + Cut Conflict + Střet záběru + + + That cut has already been assigned a track! + Tento záběr již byl přiřazen ke stopě! + + + Cut Exists + Záběr existuje + + + A recording already exists. +Do you want to overwrite it? + Nahrávka již existuje. +Chcete ji přepsat? + + + Empty Clipboard + Vyprázdnit schránku + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + Vytažení tohoto záběru vyprázdní také schránku. +Přesto smazat? + + + Library Error + Chyba v knihovně + + + Insufficient free carts available in group! + Nedostatek volných vozíků ve skupině! + + + Audio Track + Zvuková stopa + + + Data Track + Datová stopa + + + Rip Complete + Vytažení dokončeno + + + Rip complete! + Vytažení dokončeno! + + + Rip Aborted + Rip abgebrochen + + + The rip has been aborted. + Der Rip wurde abgebrochen. + + + Rip Failed + Rip fehlgeschlagen + + + The ripper encountered an error. +Please check your ripper configuration and try again. + Der Ripper hat einen Fehler bemerkt. +Bitte überprüfen sie ihre Ripperkonfiguration und versuchen sie es erneut. + + + Total Progress + Celkový postup + + + No Access + Kein Zugriff + + + Unable to open the file for writing! + Kann die Datei nicht zum schreiben öffnen! + + + OK + OK + + + &Rip +Disc + Vytáhnout +z CD + + + RDLibrary - Importer Error + RDLibrary - Chyba při zavedení + + + RDLibrary - Ripper Error + RDLibrary - Chyba ve vytahovači + + + Abort +Rip + Zrušit +vytahování + + + Rip +Disk + Vytáhnout +z CD + + + Rip aborted! + Vytažení +zrušeno! + + + Ripper Error + + + + Unable to create temporary directory! + + + + Cut + + + + Track + + + + Add Cart +Per Track + + + + Add Single +Cart + + + + Set +&Cart/Cut + + + + [continued] + + + + Modify +Cart Label + + + + Clear +Selection + + + + Error + + + + Unable to allocate carts in group + + + + Unable to allocate cart in group + + + + + EditCart + + Number: + Číslo: + + + Group: + Skupina: + + + Type: + Typ: + + + Average Length: + Průměrná délka: + + + Enforce Length + Vynutit délku + + + Forced Length: + Vynucená délka: + + + Preserve Pitch + Zachovat výšku tónu + + + &Title: + &Název: + + + &Start Date: + &Počáteční datum: + + + &End Date: + &Koncové datum: + + + &Artist: + &Umělec: + + + &Year Released: + &Rok vydání: + + + U&sage: + Po&užití: + + + Scheduler Codes + Kódy rozvrhovače + + + Al&bum: + Al&bum: + + + Re&cord Label: + Označení &nahrávky: + + + C&lient: + &Zákazník: + + + A&gency: + A&gentura: + + + &Publisher: + Vy&davatel: + + + Compos&er: + Skladat&el: + + + &User Defined: + Stanoveno už&ivatelem: + + + Schedule Cuts: + Rozvrhnout záběry: + + + Execute Asynchronously + Vykonat asynchronně + + + &Edit +Script + &Upravit +skript + + + &OK + &OK + + + &Cancel + Z&rušit + + + AUDIO + ZVUK + + + MACRO + MAKRO + + + UNKNOWN + NEZNÁMÝ + + + TFN + TFN + + + Sequentially + Postupně + + + Randomly + Náhodně + + + + Project-Id-Version: amarok +Report-Msgid-Bugs-To: http://bugs.kde.org +POT-Creation-Date: 2010-05-20 04:55+0200 +PO-Revision-Date: 2010-05-22 09:34+0200 +Last-Translator: Pavel Fric +Language-Team: Czech <kde-i18n-doc@kde.org> +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +X-Generator: Lokalize 1.0 +Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; + + + + Missing Title + Chybí název + + + You must provide at least a Cart Title! + Musíte zadat alespoň název vozíku! + + + Length Mismatch + Nesoulad v délkách + + + One or more cut lengths exceed the timescaling +limits of the system! Do you still want to save? + Jedna nebo více záběrových délek překračuje časové omezení +systému! Přesto chcete uložit? + + + Duplicate Title + Zdvojený název + + + The cart title must be unique! + Název vozíku musí být jedinečný! + + + &Edit +Notes + &Upravit +poznámky + + + RDLibrary - Edit Cart + + + + This cart cannot contain any additional cuts! + + + + Cond&uctor: + + + + Song &ID: + + + + Unknown + + + + &Beats per Minute: + + + + Use Event Length for Now && Next Updates + + + + + EditMacro + + Edit Macro + Upravit makro + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditNotes + + Notes for cart + + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditSchedulerCodes + + Select Scheduler Codes + + + + Available Codes + + + + Assigned Codes + + + + ASSIGN to Carts + + + + REMOVE from Carts + + + + &OK + &OK + + + &Cancel + Z&rušit + + + + Filter + + Library Filter + Filtr knihovny + + + &OK + &OK + + + C&lear + &Vyprázdnit + + + &Cancel + Z&rušit + + + &Filter: + &Filtr: + + + + ListReports + + RDLibrary Reports + + + + Cart Report + + + + Cut Report + + + + Type: + Typ: + + + &Generate + + + + &Close + &Zavřít + + + ALL + VŠE + + + Cart Data Dump (fixed width) + + + + Cart Data Dump (CSV) + + + + Prepend Field Names + + + + + MacroCart + + Add + Přidat + + + Delete + Smazat + + + Copy + Kopírovat + + + Paste + Vložit + + + LINE + ŘÁDEK + + + COMMAND + PŘÍKAZ + + + Macros + Makra + + + Edit + Upravit + + + Run +Line + Spustit +řádek + + + Run +Cart + Spustit +vozík + + + --- End of cart --- + --- Konec vozíku --- + + + + MainWidget + + Please Wait... + Počkejte, prosím... + + + rdlibrary : + rdlibrary: + + + Can't Connect + Nelze spojit + + + Filter: + Filtr: + + + &Search + &Hledat + + + &Clear + &Smazat + + + Group: + Skupina + + + Scheduler Code: + Kódy rozvrhovače: + + + Show Audio Carts + Ukázat zvukové karty + + + Show Macro Carts + Ukázat makro karty + + + CART + VOZÍK + + + GROUP + SKUPINA + + + LENGTH + DÉLKA + + + TITLE + NÁZEV + + + ARTIST + UMĚLEC + + + START + ZAČÁTEK + + + END + KONEC + + + CLIENT + ZÁKAZNÍK + + + AGENCY + AGENTURA + + + USER DEFINED + STANOVENO UŽIVATELEM + + + CUTS + ZÁBĚRY + + + LAST CUT PLAYED + NAPOSLEDY HRANÝ ZÁBĚR + + + PLAY ORDER + POŘADÍ PŘEHRÁVÁNÍ + + + ENFORCE LENGTH + VYNUTIT DÉLKU + + + PRESERVE PITCH + ZACHOVAT VÝŠKU TÓNU + + + LENGTH DEVIATION + ODCHYLKA DÉLKY + + + OWNED BY + PATŘÍ + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &Rip +CD + &Vytáhnout +z CD + + + Re&ports + Z&právy + + + &Close + &Zavřít + + + ALL + VŠE + + + + Project-Id-Version: amarok +Report-Msgid-Bugs-To: http://bugs.kde.org +POT-Creation-Date: 2010-05-20 04:55+0200 +PO-Revision-Date: 2010-05-22 09:34+0200 +Last-Translator: Pavel Fric +Language-Team: Czech <kde-i18n-doc@kde.org> +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +X-Generator: Lokalize 1.0 +Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; + + + + Are you sure you want to delete cart(s) + Jste si jistý, že chcete smazat tento vozík(y) + + + Delete Cart(s) + Smazat vozík(y) + + + Cart %06u is used in one or more RDCatch events! +Do you still want to delete it? + Vozík %06u je používán jednou nebo více událostmi RDCatch. +Přesto smazat? + + + RDCatch Event Exists + Událost RDCatch existuje + + + Deleting cart %06u will also empty the clipboard. + Do you still want to proceed? + Smazání vozíku %06u vyprázdní také schránku + Přesto pokračovat? + + + Empty Clipboard + Vyprázdnit schránku + + + Sequence + Sekvence + + + Random + Náhodný + + + TFN + TFN + + + RDLibrary - Host: + RDLibrary - Server: + + + , User: + , Uživatel: + + + Show Note Bubbles + Ukázat bzbliny s poznámkami + + + RDLibrary + RDLibrary + + + Unable to delete audio! + Soubor(y) se zvukem nelze smazat! + + + Show Only First + Ukázat pouze první + + + Matches + Shody + + + Host + + + + User + + + + COMPOSER + + + + CONDUCTOR + + + + PUBLISHER + + + + Allow Cart Dragging + + + + Error + + + + Unknown command-line option + + + + ALBUM + + + + LABEL + + + + + RecordCut + + RDLibrary - Record + RDLibrary - Nahrávání + + + &Description + &Popis + + + &Outcue + &OUTCUE + + + Origin + Původ + + + ISRC + ISRC + + + Weight + Váha + + + Last Played + Naposledy přehráno + + + # of Plays + # přehrání + + + Cut is EVERGREEN + Záběr je EVERGREEN + + + Air Date/Time + Datum/Čas poslání + + + Enabled + Povoleno + + + Disabled + Zakázáno + + + &Start + &Začátek + + + End + Konec + + + Daypart + Denní doba + + + &Start Time + &Počáteční čas + + + End Time + Koncový čas + + + Day of the Week + Den v týdnu + + + Monday + Pondělí + + + Tuesday + Úterý + + + Wednesday + Středa + + + Thursday + Čtvrtek + + + Friday + Pátek + + + Saturday + Sobota + + + Sunday + Neděle + + + Set All + Nastavit vše + + + Clear All + Smazat vše + + + NO SYNC! + ŽÁDNÉ SEŘIZOVÁNÍ! + + + Channels + Kanály + + + Record Mode + Režim nahrávání + + + AutoTrim + Automatické zastřižení + + + &Close + &Zavřít + + + Manual + Ruční + + + VOX + VOX + + + On + Zapnuto + + + Off + Vypnuto + + + Audio Exists + Zvuk existuje + + + This will overwrite the existing recording. +Do you want to proceed? + Toto přepíše (smaže) stávající nahrávkun. +Přesto pokračovat? + + + Empty Clipboard + Vyprázdnit schránku + + + This will empty the clipboard. +Do you still want to proceed? + Toto vyprázdní schránku. +Přesto pokračovat? + + + Missing Description + Chybí popis + + + You must provide a Cut Description! + Musíte zadat název záběru! + + + Invalid ISRC + Neplatný ISRC + + + The ISRC data is malformed or invalid! + Data ISRC jsou poškozena nebo neplatná! + + + Invalid Date + Neplatné datum + + + The Start Date is invalid! + Počáteční datum je neplatné! + + + The End Date is invalid! + Koncové datum je neplatné! + + + The End Date is prior to the Start Date! + Koncové datum leží před počátečním datem! + + + The End Date has already passed! +Do you still want to save? + Koncové datum již vypršelo! +Přesto uložit? + + + Invalid Time + Neplatný čas + + + The Start Time is invalid! + Počáteční čas je neplatný! + + + The End Time is invalid! + Koncový čas je neplatný! + + + The StartTime cannot be the same as the End Time! + Počáteční datum a koncové datum nemohou být stejné! + + + Can't Connect + Nelze spojit + + + Unable to connect to Core AudioEngine + Spojení s Core AudioEngine se nezdařilo + + + &ISCI Code + Kód &ISCI + + + AES ALARM + + + + diff --git a/rdlibrary/rdlibrary_de.ts b/rdlibrary/rdlibrary_de.ts new file mode 100644 index 00000000..73d60f27 --- /dev/null +++ b/rdlibrary/rdlibrary_de.ts @@ -0,0 +1,1526 @@ + + + AudioCart + + Copying audio... + Kopiere Audio... + + + Add + Hinzufügen + + + Delete + Löschen + + + Copy + Kopieren + + + Paste + Einfügen + + + WT + WT + + + DESCRIPTION + BESCHREIBUNG + + + LENGTH + LÄNGE + + + LAST PLAYED + ZUL. GESPIELT + + + # OF PLAYS + # GESPIELT + + + ORIGIN + HERKUNFT + + + OUTCUE + OUTCUE + + + START DATE + STARTDATUM + + + END DATE + ENDDATUM + + + DAYPART START + TAGESTEIL START + + + DAYPART END + TAGESTEIL ENDE + + + NAME + NAME + + + Cuts + Cuts + + + Cut Info + Cut Info + + + Record + Aufnahme + + + Edit +Audio + Audio +editieren + + + Edit +Markers + Marker +editieren + + + Import + Importieren + + + Export + Exportieren + + + Rip CD + CD rippen + + + Are you sure you want to delete + Sind sie sicher dies löschen zu wollen + + + Delete Cut + Cut löschen + + + RDCatch Event Exists + RDCatch Event existiert nicht + + + This cut is used in one or more RDCatch events! +Do you still want to delete it? + Dieser Cut wird in einem oder mehreren RDCatch-Events +verwendet! Trotzdem löschen? + + + Empty Clipboard + Zwischenablage leeren + + + Deleting this cut will also empty the clipboard. +Do you still want to proceed? + Diesen Cut zu löschen wird auch die Zwischenablage +leeren. Trotzdem fortfahren? + + + Clipboard Empty + Zwischenablage leer + + + Clipboard is currently empty. + Zwischenablage ist momentan leer. + + + Audio Exists + Audio existiert + + + This will overwrite the existing recording. +Do you want to proceed? + Dies wird die derzeitige Aufnahme löschen. +Trotzdem fortfahren? + + + [new cart] + [neuer cart] + + + Never + Nie + + + None + Keine + + + 1 Cut + 1 Cut + + + RDLibrary + RDLibrary + + + Unable to delete audio! + Kann die Audiodatei(en) nicht löschen! + + + No audio is present in the cut! + + + + This cart cannot contain any additional cuts! + + + + RDLibrary - Edit Cart + + + + Delete Cuts + + + + cuts + + + + One or more cuts are used in one or more RDCatch events! +Do you still want to delete? + + + + Unable to delete audio for cut + + + + Copy Cut + + + + No data copied - you must select a single cut! + + + + Paste Cut + + + + You must select a single cut! + + + + + CdRipper + + Artist: + Künstler: + + + Album: + Album: + + + Other: + Andere: + + + Apply FreeDB Values to Cart + FreeDB-Werte auf Cart anwenden + + + Tracks + Tracks + + + TRACK + TRACK + + + LENGTH + LÄNGE + + + TITLE + TITEL + + + OTHER + ANDERE + + + TYPE + TYP + + + &Rip +Track + Track +&Rippen + + + Normalize + Normalisieren + + + Level: + Level: + + + dBFS + dBFS + + + Autotrim + Autotrim + + + Channels: + Kanäle: + + + Audio Exists + Audio existiert + + + This will overwrite the existing recording. +Do you want to proceed? + Dies wird die derzeitige Aufnahme löschen. +Trotzdem fortfahren? + + + Empty Clipboard + Zwischenablage leeren + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + Diesen Cut zu rippen wird auch die Zwischenablage +leeren. Trotzdem fortfahren? + + + No Access + Kein Zugriff + + + Unable to open the file for writing! + Kann die Datei nicht zum schreiben öffnen! + + + OK + OK + + + Audio Track + Audio Track + + + Data Track + Datentrack + + + Rip Complete + Rip vollständig + + + Rip complete! + Rip vollständig! + + + Rip Aborted + Rip abgebrochen + + + The rip has been aborted. + Der Rip wurde abgebrochen. + + + Rip Failed + Rip fehlgeschlagen + + + The ripper encountered an error. +Please check your ripper configuration and try again. + Der Ripper hat einen Fehler bemerkt. +Bitte überprüfen sie ihre Ripperkonfiguration und versuchen sie es erneut. + + + RDLibrary - Importer Error + RDLibrary - Importfehler + + + RDLibrary - Ripper Error + RDLibrary - Ripperfehler + + + Abort +Rip + Rippen +abbrechen + + + Rip Track + Titel rippen + + + Title: + + + + [none] + + + + Ripper Error + + + + Unable to create temporary directory! + + + + + DiskRipper + + Rip Disk + CD Rippen + + + Artist: + Künstler: + + + Album: + Album: + + + Other: + Andere: + + + Apply FreeDB Values to Carts + FreeDB-Werte auf Carts anwenden + + + Tracks + Tracks + + + TRACK + TRACK + + + LENGTH + LÄNGE + + + TITLE + TITEL + + + OTHER + ANDERE + + + TYPE + TYP + + + CUT + CUT + + + Disk Progress + Gesamtfortschritt + + + Track Progress + Titelfortschritt + + + Set +&Cut + &Cut +setzen + + + Set All +&New Carts + Alle &Neuen +Carts setzen + + + Normalize + Normalisieren + + + Level: + Level: + + + dBFS + dBFS + + + Autotrim + Autotrim + + + Channels: + Kanäle: + + + &Close + S&chließen + + + Cut Conflict + Cut-Konflikt + + + That cut has already been assigned a track! + Dieser Cut ist bereits einem Titel zugewiesen worden! + + + Cut Exists + Cut existiert + + + A recording already exists. +Do you want to overwrite it? + Eine Aufnahme existiert bereits. +Wollen sie sie überschreiben? + + + Empty Clipboard + Zwischenablage leeren + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + Diesen Cut zu rippen wird auch die Zwischenablage +leeren. Trotzdem fortfahren? + + + Library Error + Bibliotheksfehler + + + Insufficient free carts available in group! + Nicht genug freie Carts in der Gruppe! + + + Audio Track + Audio Track + + + Data Track + Datentrack + + + Rip Complete + Rip vollständig + + + Rip complete! + Rip vollständig! + + + Rip Aborted + Rip abgebrochen + + + The rip has been aborted. + Der Rip wurde abgebrochen. + + + Rip Failed + Rip fehlgeschlagen + + + The ripper encountered an error. +Please check your ripper configuration and try again. + Der Ripper hat einen Fehler bemerkt. +Bitte überprüfen sie ihre Ripperkonfiguration und versuchen sie es erneut. + + + Total Progress + Totalfortschritt + + + No Access + Kein Zugriff + + + Unable to open the file for writing! + Kann die Datei nicht zum schreiben öffnen! + + + OK + OK + + + &Rip +Disc + CD +&Rippen + + + RDLibrary - Importer Error + RDLibrary - Importfehler + + + RDLibrary - Ripper Error + RDLibrary - Ripperfehler + + + Abort +Rip + Rippen +abbrechen + + + Rip +Disk + CD +Rippen + + + Rip aborted! + Rip abgebrochen! + + + Ripper Error + + + + Unable to create temporary directory! + + + + Cut + + + + Track + + + + Add Cart +Per Track + + + + Add Single +Cart + + + + Set +&Cart/Cut + + + + [continued] + + + + Modify +Cart Label + + + + Clear +Selection + + + + Error + + + + Unable to allocate carts in group + + + + Unable to allocate cart in group + + + + + EditCart + + Number: + Nummer: + + + Group: + Gruppe: + + + Type: + Typ: + + + Average Length: + Durchschnittslänge: + + + Enforce Length + Länge erzwingen + + + Forced Length: + erzwungene Länge: + + + Preserve Pitch + Pitch schützen + + + &Title: + &Titel: + + + &Start Date: + &Startdatum: + + + &End Date: + &Enddatum: + + + &Artist: + &Künstler: + + + &Year Released: + &Jahr des Erscheinens: + + + U&sage: + &Verwendung: + + + Scheduler Codes + Scheduler Codes + + + Al&bum: + Al&bum: + + + Re&cord Label: + Aufnahmebezei&chnung: + + + C&lient: + &Kunde: + + + A&gency: + A&gentur: + + + &Publisher: + &Herausgeber: + + + Compos&er: + Kompon&ist: + + + &User Defined: + Ben&utzerdefiniert: + + + Schedule Cuts: + Cuts einplanen: + + + Execute Asynchronously + asynchron ausführen + + + &Edit +Script + Skript +&Editieren + + + &OK + &OK + + + &Cancel + &Abbrechen + + + AUDIO + AUDIO + + + MACRO + MACRO + + + UNKNOWN + UNBEKANNT + + + TFN + TFN + + + Sequentially + Sequentiell + + + Randomly + Zufällig + + + + + + + Missing Title + Fehlender Titel + + + You must provide at least a Cart Title! + Sie müssen zumindest einen CartTitel angeben! + + + Length Mismatch + Länge stimmt nicht überein + + + One or more cut lengths exceed the timescaling +limits of the system! Do you still want to save? + Ein oder mehrere Cutlängen überschreiten die Zeit- +Limits des Systems! Wollen sie trotzdem speichern? + + + Duplicate Title + Doppelter Titel + + + The cart title must be unique! + Der Cart-Titel muss einzigartig sein! + + + &Edit +Notes + Notizen +&editieren + + + RDLibrary - Edit Cart + + + + This cart cannot contain any additional cuts! + + + + Cond&uctor: + + + + Song &ID: + + + + Unknown + + + + &Beats per Minute: + + + + Use Event Length for Now && Next Updates + + + + + EditMacro + + Edit Macro + Makro editieren + + + &OK + &OK + + + &Cancel + &Abbrechen + + + + EditNotes + + Notes for cart + + + + &OK + &OK + + + &Cancel + &Abbrechen + + + + EditSchedulerCodes + + Select Scheduler Codes + + + + Available Codes + + + + Assigned Codes + + + + ASSIGN to Carts + + + + REMOVE from Carts + + + + &OK + &OK + + + &Cancel + &Abbrechen + + + + Filter + + Library Filter + Bibliotheksfilter + + + &OK + &OK + + + C&lear + &Löschen + + + &Cancel + &Abbrechen + + + &Filter: + &Filter: + + + + ListReports + + RDLibrary Reports + + + + Cart Report + + + + Cut Report + + + + Type: + Typ: + + + &Generate + + + + &Close + S&chließen + + + ALL + ALLE + + + Cart Data Dump (fixed width) + + + + Cart Data Dump (CSV) + + + + Prepend Field Names + + + + + MacroCart + + Add + Hinzufügen + + + Delete + Löschen + + + Copy + Kopieren + + + Paste + Einfügen + + + LINE + ZEILE + + + COMMAND + KOMMANDO + + + Macros + Makros + + + Edit + editieren + + + Run +Line + Zeile +starten + + + Run +Cart + Cart +starten + + + --- End of cart --- + --- Ende des Carts --- + + + + MainWidget + + Please Wait... + Bitte warten... + + + rdlibrary : + rdlibrary : + + + Can't Connect + Kann nicht verbinden + + + Filter: + Filter: + + + &Search + &Suchen + + + &Clear + &Löschen + + + Group: + Gruppe: + + + Scheduler Code: + Scheduler Code: + + + Show Audio Carts + Audio Carts anzeigen + + + Show Macro Carts + Makro-Carts anzeigen + + + CART + CART + + + GROUP + GRUPPE + + + LENGTH + LÄNGE + + + TITLE + TITEL + + + ARTIST + KÜNSTLER + + + START + START + + + END + ENDE + + + CLIENT + KUNDE + + + AGENCY + AGENTUR + + + USER DEFINED + BENUTZERDEFINIERT + + + CUTS + CUTS + + + LAST CUT PLAYED + LETZTER GESPIELTER CUT + + + PLAY ORDER + ABSPIELREIHENFOLGE + + + ENFORCE LENGTH + LÄNGE ERZWINGEN + + + PRESERVE PITCH + PITCH SCHÜTZEN + + + LENGTH DEVIATION + LÄNGENABWEICHUNG + + + OWNED BY + GEHÖRT + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &Rip +CD + CD +&Rippen + + + Re&ports + Re&porte + + + &Close + S&chließen + + + ALL + ALLE + + + + + + + Are you sure you want to delete cart(s) + Sind sie sicher diese(n) Cart(s) löschen zu wollen + + + Delete Cart(s) + Cart(s) löschen + + + Cart %06u is used in one or more RDCatch events! +Do you still want to delete it? + Cart %06u wird von einem oder mehreren RDCatch-Events +verwendet. Trotzdem löschen? + + + RDCatch Event Exists + RDCatch-Event existiert + + + Deleting cart %06u will also empty the clipboard. + Do you still want to proceed? + Den Cart %06u zu löschen wird auch die Zwischenablage leeren + Trotzdem fortfahren? + + + Empty Clipboard + Zwischenablage leeren + + + Sequence + Sequenz + + + Random + Zufall + + + TFN + TFN + + + RDLibrary - Host: + RDLibrary-Host : + + + , User: + , Benutzer: + + + Show Note Bubbles + Zeige Notizen + + + RDLibrary + RDLibrary + + + Unable to delete audio! + Kann die Audiodatei(en) nicht löschen! + + + Show Only First + Zeige nur erste + + + Matches + Treffer + + + Host + + + + User + + + + COMPOSER + + + + CONDUCTOR + + + + PUBLISHER + + + + Allow Cart Dragging + + + + Error + + + + Unknown command-line option + + + + ALBUM + + + + LABEL + + + + + RecordCut + + RDLibrary - Record + RDLibrary - Aufnahme + + + &Description + &BESCHREIBUNG + + + &Outcue + &OUTCUE + + + Origin + HERKUNFT + + + ISRC + ISRC + + + Weight + Gewichtung + + + Last Played + ZUL. GESPIELT + + + # of Plays + # GESPIELT + + + Cut is EVERGREEN + Cut ist EVERGREEN + + + Air Date/Time + Sendezeit/-Datum + + + Enabled + Aktiviert + + + Disabled + deaktiviert + + + &Start + &START + + + End + Ende + + + Daypart + Tageszeit + + + &Start Time + &Startzeit + + + End Time + Endzeit + + + Day of the Week + Wochentag + + + Monday + Montag + + + Tuesday + Dienstag + + + Wednesday + Mittwoch + + + Thursday + Donnerstag + + + Friday + Freitag + + + Saturday + Samstag + + + Sunday + Sonntag + + + Set All + Alle Setzen + + + Clear All + Alle Löschen + + + NO SYNC! + KEINE SYNCHRONISIERUNG! + + + Channels + Kanäle + + + Record Mode + Aufnahmemodus + + + AutoTrim + Autotrim + + + &Close + S&chließen + + + Manual + Manuell + + + VOX + VOX + + + On + An + + + Off + Aus + + + Audio Exists + Audio existiert + + + This will overwrite the existing recording. +Do you want to proceed? + Dies wird die derzeitige Aufnahme löschen. +Trotzdem fortfahren? + + + Empty Clipboard + Zwischenablage leeren + + + This will empty the clipboard. +Do you still want to proceed? + Dies wird die Zwischenablage +leeren. Trotzdem fortfahren? + + + Missing Description + Fehlende Beschreibung + + + You must provide a Cut Description! + Sie müssen zumindest eine Cut-Beschreibung angeben! + + + Invalid ISRC + Ungültiges ISRC + + + The ISRC data is malformed or invalid! + Die ISRC-Daten sind ungültig! + + + Invalid Date + Ungültiges Datum + + + The Start Date is invalid! + Das Startdatum ist ungültig! + + + The End Date is invalid! + Das Enddatum ist ungültig! + + + The End Date is prior to the Start Date! + Das End- liegt vor dem Start-Datum! + + + The End Date has already passed! +Do you still want to save? + Das Enddatum ist bereits vergangen! +Trotzdem speichern? + + + Invalid Time + Ungültige Zeit + + + The Start Time is invalid! + Die Startzeit ist ungültig! + + + The End Time is invalid! + Die Endzeit ist ungültig! + + + The StartTime cannot be the same as the End Time! + Die Start- und End-Zeit können nicht gleich sein! + + + Can't Connect + Kann nicht verbinden + + + Unable to connect to Core AudioEngine + Kann nicht zur CoreAudioEngine verbinden + + + &ISCI Code + &ISCI Code + + + AES ALARM + + + + diff --git a/rdlibrary/rdlibrary_es.ts b/rdlibrary/rdlibrary_es.ts new file mode 100644 index 00000000..815dc319 --- /dev/null +++ b/rdlibrary/rdlibrary_es.ts @@ -0,0 +1,1531 @@ + + + AudioCart + + Copying audio... + Copiando audio... + + + Add + Añadir + + + Delete + Eliminar + + + Copy + Copiar + + + Paste + Pegar + + + WT + WT + + + DESCRIPTION + DESCRIPCIÓN + + + LENGTH + DURACIÓN + + + LAST PLAYED + ÚLTIMA REPROD + + + # OF PLAYS + # DE REPROD + + + ORIGIN + ORIGEN + + + OUTCUE + OUTCUE + + + START DATE + FECHA INICIO + + + END DATE + FECHA FIN + + + DAYPART START + INICIO DE DAYPART + + + DAYPART END + FIN DE DAYPART + + + NAME + NOMBRE + + + Cuts + Audios + + + Cut Info + Info. audio + + + Record + Grabar + + + Are you sure you want to delete + ¿Desea eliminar + + + Delete Cut + Eliminar audio + + + Empty Clipboard + Vaciar portapapeles + + + Deleting this cut will also empty the clipboard. +Do you still want to proceed? + Eliminando este audio también dejará el portapapeles vacío. +¿Desea continuar la eliminación? + + + Clipboard Empty + Portapapeles vacío + + + Clipboard is currently empty. + El portapapeles está vacío. + + + Never + Nunca + + + None + Ninguno + + + 1 Cut + 1 audio + + + [new cart] + [nuevo cartucho] + + + Import + Importar + + + Export + Exportar + + + This cut is used in one or more RDCatch events! +Do you still want to delete it? + ¡Este audio está en uso por uno o más eventos de RDCatch! +¿Desea eliminarlo de todas formas? + + + RDCatch Event Exists + Ya existe un evento RDCatch + + + Audio Exists + El audio existe + + + This will overwrite the existing recording. +Do you want to proceed? + Esto sobreescribirá la grabación existente. +¿Desea continuar? + + + Edit +Markers + Editar +Marcadores + + + Rip CD + Leer CD + + + Edit +Audio + Editar +Audio + + + RDLibrary + RDLibrary + + + Unable to delete audio! + ¡No se pudo eliminar el audio! + + + No audio is present in the cut! + ¡No hay audios en este cut! + + + This cart cannot contain any additional cuts! + + + + RDLibrary - Edit Cart + + + + Delete Cuts + + + + cuts + + + + One or more cuts are used in one or more RDCatch events! +Do you still want to delete? + + + + Unable to delete audio for cut + + + + Copy Cut + + + + No data copied - you must select a single cut! + + + + Paste Cut + + + + You must select a single cut! + + + + + CdRipper + + Artist: + Artista: + + + Album: + Álbum: + + + Other: + Otro: + + + Apply FreeDB Values to Cart + Usar datos obtenidos de FreeDB + + + Tracks + Pistas + + + TRACK + PISTA + + + LENGTH + DURACIÓN + + + TITLE + TÍTULO + + + OTHER + OTROS + + + TYPE + TIPO + + + &Rip +Track + Lee&r +Pista + + + Normalize + Normalizar + + + Level: + Nivel: + + + dBFS + dBFS + + + Autotrim + Autorecorte + + + Channels: + Canales: + + + Empty Clipboard + Vaciar portapapeles + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + Leyendo este audio también vaciará el portapapeles. +¿Desea continuar? + + + No Access + Sin acceso + + + Unable to open the file for writing! + No se puede abrir el archivo para escribir en él + + + OK + Aceptar + + + Audio Track + Pista de audio + + + Data Track + Pista de datos + + + Rip Complete + Lectura completada + + + Rip complete! + ¡Lectura completada! + + + Rip Aborted + Lectura cancelada + + + The rip has been aborted. + La lectura ha sido cancelada. + + + Rip Failed + La lectura falló + + + The ripper encountered an error. +Please check your ripper configuration and try again. + El lector de CD encontró un error. +Por favor, chequee la configuración e intente de nuevo. + + + This will overwrite the existing recording. +Do you want to proceed? + Esta acción sobreescribirá la grabación existente. +¿Desea continuar? + + + Audio Exists + El audio ya existe + + + RDLibrary - Importer Error + RDLibrary - Error al importar + + + RDLibrary - Ripper Error + RDLibrary - Error al leer + + + Abort +Rip + Abortar +Lectura + + + Rip Track + Leyendo pista + + + Title: + + + + [none] + + + + Ripper Error + + + + Unable to create temporary directory! + + + + + DiskRipper + + Artist: + Artista: + + + Album: + Álbum: + + + Other: + Otros: + + + Apply FreeDB Values to Carts + Usar información de FreeDB + + + Tracks + Pistas + + + TRACK + PISTA + + + LENGTH + DURACIÓN + + + TITLE + TÍTULO + + + OTHER + OTROS + + + TYPE + TIPO + + + CUT + AUDIO + + + Disk Progress + Progreso en el Disco + + + Track Progress + Progreso en la pista + + + Set +&Cut + Asignar +&Audio + + + Normalize + Normalizar + + + Level: + Nivel: + + + dBFS + dBFS + + + Autotrim + Autorecorte + + + Channels: + Canales: + + + &Close + &Cerrar + + + Cut Conflict + Conflicto en los audios + + + That cut has already been assigned a track! + Este audio ya había sido asignado a una pista + + + Cut Exists + El audio ya existe + + + A recording already exists. +Do you want to overwrite it? + Ya hay una grabación. +¿Desea sobreescribirla? + + + Empty Clipboard + Portapapeles vacío + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + Al leer el disco se vaciará el portapapeles. +¿Desea continuar? + + + Audio Track + Pista de audio + + + Data Track + Pista de datos + + + Rip Complete + Lectura completada + + + Rip complete! + ¡Lectura completada! + + + Rip Aborted + Lectura cancelada + + + The rip has been aborted. + La lectura ha sido cancelada. + + + Rip Failed + La lectura falló. + + + The ripper encountered an error. +Please check your ripper configuration and try again. + El lector encontró un error. +Por favor, chequee la configuración e intente de nuevo. + + + Total Progress + Progreso total + + + No Access + Sin acceso + + + Unable to open the file for writing! + No es posible escribir en el archivo. + + + OK + Aceptar + + + Rip Disk + Leer disco + + + Library Error + Error en las bibliotecas + + + Insufficient free carts available in group! + No hay suficientes cartuchos disponibles en el grupo. + + + Set All +&New Carts + Crear como +&cartuchos + + + &Rip +Disc + Lee&r +disco + + + RDLibrary - Importer Error + RDLIbrary - Error al importar + + + RDLibrary - Ripper Error + RDLibrary - Error de lectura + + + Abort +Rip + Abortar +Lectura + + + Rip +Disk + Leer +Disco + + + Rip aborted! + ¡Lectura +Abortada! + + + Ripper Error + + + + Unable to create temporary directory! + + + + Cut + + + + Track + + + + Add Cart +Per Track + + + + Add Single +Cart + + + + Set +&Cart/Cut + + + + [continued] + + + + Modify +Cart Label + + + + Clear +Selection + + + + Error + + + + Unable to allocate carts in group + + + + Unable to allocate cart in group + + + + + EditCart + + Number: + Número: + + + Group: + Grupo: + + + Type: + Tipo: + + + Enforce Length + Forzar duración + + + Preserve Pitch + Preservar pitch + + + &Title: + &Título + + + &Start Date: + Fecha de &Inicio: + + + &End Date: + Fecha &Final: + + + &Artist: + &Artista: + + + Al&bum: + Ál&bum: + + + Re&cord Label: + E&tiq. de grabación: + + + C&lient: + C&liente: + + + A&gency: + A&gencia: + + + &User Defined: + &Uso reservado: + + + Schedule Cuts: + Audios programad.: + + + &Edit +Script + &Editar +Script + + + &OK + Acepta&r + + + &Cancel + &Cancelar + + + AUDIO + AUDIO + + + MACRO + MACRO + + + UNKNOWN + DESCONOCIDO + + + TFN + TFN + + + Sequentially + Secuencial + + + Randomly + Aleatorio + + + Missing Title + No hay título + + + You must provide at least a Cart Title! + ¡Usted debe indicar al menos un título para el cartucho! + + + Length Mismatch + La duración no concuerda + + + One or more cut lengths exceed the timescaling +limits of the system! Do you still want to save? + La duración de uno o varios audios exceden +los límites del sistema. ¿Desea continuar? + + + Average Length: + Duración Promedio: + + + Forced Length: + Duración obligada: + + + Execute Asynchronously + Ejecutar de forma asíncrona + + + &Year Released: + Año de &Publicación: + + + &Publisher: + &Publicador: + + + Compos&er: + Composi&tor: + + + U&sage: + U&so: + + + Scheduler Codes + Códigos musicalizador + + + + + + + Duplicate Title + Título duplicado + + + The cart title must be unique! + ¡El título del cartucho debe ser único! + + + &Edit +Notes + &Editar +Notas + + + RDLibrary - Edit Cart + + + + This cart cannot contain any additional cuts! + + + + Cond&uctor: + + + + Song &ID: + + + + Unknown + + + + &Beats per Minute: + + + + Use Event Length for Now && Next Updates + + + + + EditMacro + + Edit Macro + Editar macro + + + &OK + Acepta&r + + + &Cancel + &Cancelar + + + + EditNotes + + Notes for cart + Notas para el cartucho + + + &OK + Acepta&r + + + &Cancel + &Cancelar + + + + EditSchedulerCodes + + Select Scheduler Codes + Elija Códigos para Musicalizar + + + Available Codes + Códigos disponibles + + + Assigned Codes + Códigos Asignados + + + ASSIGN to Carts + ASIGNAR a cartuchos + + + REMOVE from Carts + REMOVER de Cartuchos + + + &OK + Acepta&r + + + &Cancel + &Cancelar + + + + Filter + + Library Filter + Filtro de la biblioteca + + + &OK + Acepta&r + + + C&lear + &Limpiar + + + &Cancel + &Cancelar + + + &Filter: + &Filtro: + + + + ListReports + + RDLibrary Reports + Reportes de RDLibrary + + + Cart Report + Reporte de Cartuchos + + + Cut Report + Reporte de Audios + + + Cart Data Dump + Vaciado de datos de Cartuchos + + + Type: + Tipo: + + + &Generate + &Generar + + + &Close + &Cerrar + + + ALL + TODAS + + + Cart Data Dump (fixed width) + + + + Cart Data Dump (CSV) + + + + Prepend Field Names + + + + + MacroCart + + Add + Añadir + + + Delete + Borrar + + + Copy + Copiar + + + Paste + Pegar + + + LINE + LÍNEA + + + COMMAND + COMANDO + + + Macros + Macros + + + Edit + Editar + + + Run +Line + Ejecutar +línea + + + Run +Cart + Ejecutar +Cartucho + + + --- End of cart --- + --- Fin del cartucho --- + + + + MainWidget + + Can't Connect + No puedo conectar + + + Filter: + Filtro: + + + &Clear + &Limpiar + + + Group: + Grupo: + + + Show Audio Carts + Mostrar cart. de audio + + + Show Macro Carts + Mostrar cart. macro + + + CART + CARTUCHO + + + GROUP + GRUPO + + + LENGTH + DURACIÓN + + + TITLE + TÍTULO + + + ARTIST + ARTISTA + + + START + INICIO + + + END + FIN + + + CLIENT + CLIENTE + + + AGENCY + AGENCIA + + + USER DEFINED + RESERVADO + + + CUTS + AUDIOS + + + LAST CUT PLAYED + ÚLT. AUDIO REPR. + + + PLAY ORDER + ORDEN DE REPROD. + + + ENFORCE LENGTH + OBLIGAR DURACIÓN + + + PRESERVE PITCH + PRESERVAR PITCH + + + LENGTH DEVIATION + DESVIACIÓN DE LA DURACIÓN + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + &Borrar + + + &Close + &Cerrar + + + ALL + TODAS + + + Empty Clipboard + Vaciar portapapeles + + + Sequence + Secuencia + + + Random + Aleatorio + + + TFN + + + + RDLibrary - Host: + RDLibrary - Servidor: + + + , User: + , Usuario: + + + &Rip +CD + &Leer +CD + + + OWNED BY + PROPIEDAD DE + + + RDCatch Event Exists + Evento RDCatch ya existe + + + Re&ports + Re&porte + + + Scheduler Code: + Códs. Musicaliz.: + + + + + + + Are you sure you want to delete cart(s) + ¿Está seguro de eliminar el o los cartuchos? + + + Delete Cart(s) + Eliminar cartucho(s) + + + Cart %06u is used in one or more RDCatch events! +Do you still want to delete it? + El cartucho %06u está siendo usado en eventos RDCatch +¿Aún así desea eliminarlos? + + + Deleting cart %06u will also empty the clipboard. + Do you still want to proceed? + Al eliminar el cartucho %06u también se vaciará el portapapeles. + ¿Desea continuar? + + + rdlibrary : + rdlibrary : + + + &Search + Bu&scar: + + + Please Wait... + Espere... + + + Show Note Bubbles + Most. notas flotantes + + + RDLibrary + RDLibrary + + + Unable to delete audio! + ¡No puedo eliminar el audio! + + + Show Only First + Mostrar sólo primeros + + + Matches + hallazgos + + + Host + + + + User + + + + COMPOSER + + + + CONDUCTOR + + + + PUBLISHER + + + + Allow Cart Dragging + + + + Error + + + + Unknown command-line option + + + + ALBUM + + + + LABEL + + + + + RecordCut + + RDLibrary - Record + RDLibrary - Grabar + + + &Description + &Descripción + + + &Outcue + &Outcue + + + Origin + Origen + + + Weight + Peso + + + Last Played + Últ. Reprod + + + # of Plays + # de reprod + + + Cut is EVERGREEN + Audio es EVERGREEN + + + Air Date/Time + Fecha/hora al aire + + + Enabled + Activado + + + Disabled + Desactiv. + + + &Start + &Inicio + + + End + Fin + + + Daypart + Daypart + + + &Start Time + &Hora de Inicio + + + End Time + Hora de fin + + + Day of the Week + Día de la semana + + + Monday + Lunes + + + Tuesday + Martes + + + Wednesday + Miércoles + + + Thursday + Jueves + + + Friday + Viernes + + + Saturday + Sábado + + + Sunday + Domingo + + + NO SYNC! + ¡NO SINC.! + + + Channels + Canales + + + Record Mode + Modo grabación + + + AutoTrim + AutoRecortar + + + &Close + &Cerrar + + + Manual + Manual + + + VOX + VOX + + + On + Activo + + + Off + Desact. + + + This will overwrite the existing recording. +Do you want to proceed? + Esta acción sobreescribirá la grabación existente. +¿Desea continuar? + + + Empty Clipboard + Vaciar portapapeles + + + This will empty the clipboard. +Do you still want to proceed? + Esta acción vaciará el portapapeles. +¿Aún así desea continuar? + + + Missing Description + Descripción no encontrada + + + You must provide a Cut Description! + ¡Debe proveer una descripción para el audio! + + + Invalid Date + Fecha inválida + + + The Start Date is invalid! + ¡La fecha de inicio es inválida! + + + The End Date is invalid! + ¡La fecha de fin es inválida! + + + The End Date is prior to the Start Date! + La fecha de fin es anterior a la fecha de inicio + + + The End Date has already passed! +Do you still want to save? + ¡La fecha de fin ya pasó! +¿Aún así desea guardar la información? + + + Invalid Time + Hora inválida + + + The Start Time is invalid! + ¡La hora de inicio es inválida! + + + The End Time is invalid! + ¡La hora defin es inválida! + + + Can't Connect + No puedo conectarme + + + Unable to connect to Core AudioEngine + No es posible conectarse al Core AudioEngine + + + Audio Exists + El audio ya existe + + + ISRC + ISRC + + + Invalid ISRC + ISRC inválido + + + The ISRC data is malformed or invalid! + ¡Los datos de ISRC son inválidos o mal formados! + + + The StartTime cannot be the same as the End Time! + ¡La hora de inicio no puede ser la misma que la de fin! + + + Set All + Selec. todo + + + Clear All + Quita todo + + + &ISCI Code + Código &ISCI + + + AES ALARM + + + + diff --git a/rdlibrary/rdlibrary_fr.ts b/rdlibrary/rdlibrary_fr.ts new file mode 100644 index 00000000..3734ce89 --- /dev/null +++ b/rdlibrary/rdlibrary_fr.ts @@ -0,0 +1,1368 @@ + + + AudioCart + + Copying audio... + + + + Add + + + + Delete + + + + Copy + + + + Paste + + + + WT + + + + DESCRIPTION + + + + LENGTH + + + + LAST PLAYED + + + + # OF PLAYS + + + + ORIGIN + + + + OUTCUE + + + + START DATE + + + + END DATE + + + + DAYPART START + + + + DAYPART END + + + + NAME + + + + Cut Info + + + + Record + + + + Edit +Audio + + + + Edit +Markers + + + + Import + + + + Export + + + + Rip CD + + + + Are you sure you want to delete + + + + Delete Cut + + + + RDCatch Event Exists + + + + Empty Clipboard + + + + Deleting this cut will also empty the clipboard. +Do you still want to proceed? + + + + Clipboard Empty + + + + Clipboard is currently empty. + + + + Audio Exists + + + + This will overwrite the existing recording. +Do you want to proceed? + + + + [new cart] + + + + Never + + + + None + + + + RDLibrary + + + + No audio is present in the cut! + + + + This cart cannot contain any additional cuts! + + + + RDLibrary - Edit Cart + + + + Delete Cuts + + + + cuts + + + + One or more cuts are used in one or more RDCatch events! +Do you still want to delete? + + + + Unable to delete audio for cut + + + + Copy Cut + + + + No data copied - you must select a single cut! + + + + Paste Cut + + + + You must select a single cut! + + + + + CdRipper + + Artist: + + + + Album: + + + + Other: + + + + Apply FreeDB Values to Cart + + + + Tracks + + + + TRACK + + + + LENGTH + + + + TITLE + + + + OTHER + + + + TYPE + + + + &Rip +Track + + + + Normalize + + + + Level: + + + + dBFS + + + + Autotrim + + + + Channels: + + + + Audio Exists + + + + This will overwrite the existing recording. +Do you want to proceed? + + + + Empty Clipboard + + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + + + + Audio Track + + + + Data Track + + + + RDLibrary - Importer Error + + + + RDLibrary - Ripper Error + + + + Rip Complete + + + + Rip complete! + + + + Abort +Rip + + + + Rip Track + + + + Title: + + + + [none] + + + + Ripper Error + + + + Unable to create temporary directory! + + + + + DiskRipper + + Rip Disk + + + + Artist: + + + + Album: + + + + Other: + + + + Apply FreeDB Values to Carts + + + + Tracks + + + + TRACK + + + + LENGTH + + + + TITLE + + + + OTHER + + + + TYPE + + + + CUT + + + + Disk Progress + + + + Track Progress + + + + Normalize + + + + Level: + + + + dBFS + + + + Autotrim + + + + Channels: + + + + &Close + + + + Cut Conflict + + + + That cut has already been assigned a track! + + + + Cut Exists + + + + A recording already exists. +Do you want to overwrite it? + + + + Empty Clipboard + + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + + + + Audio Track + + + + Data Track + + + + Rip Complete + + + + Rip complete! + + + + &Rip +Disc + + + + RDLibrary - Importer Error + + + + RDLibrary - Ripper Error + + + + Total Progress + + + + Abort +Rip + + + + Rip +Disk + + + + Rip aborted! + + + + Ripper Error + + + + Unable to create temporary directory! + + + + Cut + + + + Track + + + + Add Cart +Per Track + + + + Add Single +Cart + + + + Set +&Cart/Cut + + + + [continued] + + + + Modify +Cart Label + + + + Clear +Selection + + + + Error + + + + Unable to allocate carts in group + + + + Unable to allocate cart in group + + + + + EditCart + + Number: + + + + Group: + + + + Type: + + + + Average Length: + + + + Enforce Length + + + + Forced Length: + + + + Preserve Pitch + + + + &Title: + + + + &Start Date: + + + + &End Date: + + + + &Artist: + + + + &Year Released: + + + + U&sage: + + + + Scheduler Codes + + + + Al&bum: + + + + Re&cord Label: + + + + C&lient: + + + + A&gency: + + + + &Publisher: + + + + Compos&er: + + + + &User Defined: + + + + Execute Asynchronously + + + + &Edit +Script + + + + &OK + + + + &Cancel + + + + AUDIO + + + + MACRO + + + + UNKNOWN + + + + TFN + + + + + + + + Missing Title + + + + You must provide at least a Cart Title! + + + + Length Mismatch + + + + One or more cut lengths exceed the timescaling +limits of the system! Do you still want to save? + + + + Duplicate Title + + + + The cart title must be unique! + + + + &Edit +Notes + + + + RDLibrary - Edit Cart + + + + This cart cannot contain any additional cuts! + + + + Cond&uctor: + + + + Song &ID: + + + + Unknown + + + + &Beats per Minute: + + + + Use Event Length for Now && Next Updates + + + + + EditMacro + + Edit Macro + + + + &OK + + + + &Cancel + + + + + EditNotes + + Notes for cart + + + + &OK + + + + &Cancel + + + + + EditSchedulerCodes + + Select Scheduler Codes + + + + Available Codes + + + + Assigned Codes + + + + ASSIGN to Carts + + + + REMOVE from Carts + + + + &OK + + + + &Cancel + + + + + Filter + + Library Filter + + + + &OK + + + + C&lear + + + + &Cancel + + + + &Filter: + + + + + ListReports + + RDLibrary Reports + + + + Cart Report + + + + Cut Report + + + + Type: + + + + &Generate + + + + &Close + + + + ALL + + + + Cart Data Dump (fixed width) + + + + Cart Data Dump (CSV) + + + + Prepend Field Names + + + + + MacroCart + + Add + + + + Delete + + + + Copy + + + + Paste + + + + LINE + + + + COMMAND + + + + Macros + + + + Edit + + + + Run +Line + + + + Run +Cart + + + + --- End of cart --- + + + + + MainWidget + + Please Wait... + + + + rdlibrary : + + + + Can't Connect + + + + Filter: + + + + &Search + + + + &Clear + + + + Group: + + + + Scheduler Code: + + + + Show Audio Carts + + + + Show Macro Carts + + + + CART + + + + GROUP + + + + LENGTH + + + + TITLE + + + + ARTIST + + + + START + + + + END + + + + CLIENT + + + + AGENCY + + + + USER DEFINED + + + + CUTS + + + + LAST CUT PLAYED + + + + ENFORCE LENGTH + + + + PRESERVE PITCH + + + + LENGTH DEVIATION + + + + OWNED BY + + + + &Add + + + + &Edit + + + + &Delete + + + + &Rip +CD + + + + Re&ports + + + + &Close + + + + ALL + + + + + + + + Are you sure you want to delete cart(s) + + + + Delete Cart(s) + + + + Cart %06u is used in one or more RDCatch events! +Do you still want to delete it? + + + + RDCatch Event Exists + + + + Deleting cart %06u will also empty the clipboard. + Do you still want to proceed? + + + + Empty Clipboard + + + + TFN + + + + Show Note Bubbles + + + + RDLibrary + + + + Unable to delete audio! + + + + Show Only First + + + + Matches + + + + Host + + + + User + + + + COMPOSER + + + + CONDUCTOR + + + + PUBLISHER + + + + Allow Cart Dragging + + + + Error + + + + Unknown command-line option + + + + ALBUM + + + + LABEL + + + + + RecordCut + + RDLibrary - Record + + + + &Description + + + + &Outcue + + + + Origin + + + + ISRC + + + + Weight + + + + Last Played + + + + # of Plays + + + + Cut is EVERGREEN + + + + Air Date/Time + + + + Enabled + + + + Disabled + + + + &Start + + + + End + + + + Daypart + + + + &Start Time + + + + End Time + + + + Day of the Week + + + + Monday + + + + Tuesday + + + + Wednesday + + + + Thursday + + + + Friday + + + + Saturday + + + + Sunday + + + + Set All + + + + Clear All + + + + Channels + + + + Record Mode + + + + AutoTrim + + + + &Close + + + + Manual + + + + VOX + + + + On + + + + Off + + + + Audio Exists + + + + This will overwrite the existing recording. +Do you want to proceed? + + + + Empty Clipboard + + + + This will empty the clipboard. +Do you still want to proceed? + + + + Missing Description + + + + You must provide a Cut Description! + + + + Invalid ISRC + + + + The ISRC data is malformed or invalid! + + + + Invalid Date + + + + The Start Date is invalid! + + + + The End Date is invalid! + + + + The End Date is prior to the Start Date! + + + + The End Date has already passed! +Do you still want to save? + + + + Invalid Time + + + + The Start Time is invalid! + + + + The End Time is invalid! + + + + The StartTime cannot be the same as the End Time! + + + + Can't Connect + + + + Unable to connect to Core AudioEngine + + + + &ISCI Code + + + + AES ALARM + + + + diff --git a/rdlibrary/rdlibrary_nb.ts b/rdlibrary/rdlibrary_nb.ts new file mode 100644 index 00000000..958ddfa9 --- /dev/null +++ b/rdlibrary/rdlibrary_nb.ts @@ -0,0 +1,1522 @@ + + + AudioCart + + Copying audio... + Kopierer lyd... + + + Add + Legg til + + + Delete + Slett + + + Copy + Kopier + + + Paste + Lim inn + + + WT + VT + + + DESCRIPTION + SKILDRING + + + LENGTH + LENGD + + + LAST PLAYED + SIST SPELT + + + # OF PLAYS + SPELT GGR + + + ORIGIN + OPPHAV + + + OUTCUE + UTSPOR + + + START DATE + STARTDATO + + + END DATE + SLUTTDATO + + + DAYPART START + DAGDEL START + + + DAYPART END + DAGDEL SLUTT + + + NAME + NAMN + + + Cuts + Kutt + + + Cut Info + Info om kutt + + + Record + Ta opp + + + Edit +Audio + Rediger lyd + + + Edit +Markers + Rediger +markørar + + + Import + Importer + + + Export + Eksporter + + + Rip CD + Ripp CD + + + Are you sure you want to delete + Er du sikker på at du vil sletta + + + Delete Cut + Slett kutt + + + RDCatch Event Exists + RDCatch-hending eksisterer + + + This cut is used in one or more RDCatch events! +Do you still want to delete it? + Dette kuttet er brukt i ei eller fleire RDCatch-hendingar. +Er du sikker på at du vil sletta det? + + + Empty Clipboard + Tøm utklyppstavla + + + Deleting this cut will also empty the clipboard. +Do you still want to proceed? + Viss du slettar dette kuttet, vil du òg tømma utklyppstavla. +Vil du halda fram? + + + Clipboard Empty + Tom utklyppstavle + + + Clipboard is currently empty. + Utklyppstavla er tom. + + + Audio Exists + Lyd eksisterer + + + This will overwrite the existing recording. +Do you want to proceed? + Dette byter ut opptaket du alt har. +Vil du halda fram? + + + [new cart] + [ny korg] + + + Never + Aldri + + + None + Ingen + + + 1 Cut + 1 kutt + + + RDLibrary + + + + No audio is present in the cut! + + + + This cart cannot contain any additional cuts! + + + + RDLibrary - Edit Cart + + + + Delete Cuts + + + + cuts + + + + One or more cuts are used in one or more RDCatch events! +Do you still want to delete? + + + + Unable to delete audio for cut + + + + Copy Cut + + + + No data copied - you must select a single cut! + + + + Paste Cut + + + + You must select a single cut! + + + + + CdRipper + + Artist: + Artist: + + + Album: + Album: + + + Other: + Anna: + + + Apply FreeDB Values to Cart + Bruk FreeDB-opplysningar på korga + + + Tracks + Spor + + + TRACK + SPOR + + + LENGTH + LENGD + + + TITLE + TITTEL + + + OTHER + ANNA + + + TYPE + TYPE + + + &Rip +Track + &Ripp +sporet + + + Normalize + Normaliser + + + Level: + Nivå: + + + dBFS + duMN + + + Autotrim + Autotrim + + + Channels: + Kanalar: + + + Audio Exists + Lyd eksisterer + + + This will overwrite the existing recording. +Do you want to proceed? + Dette byter ut opptaket du alt har. +Vil du halda fram? + + + Empty Clipboard + Tøm utklyppstavla + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + Viss du rippar dette sporet, tømer du utklyppstavla. +Vil du halda fram? + + + No Access + Ingen tilgang + + + Unable to open the file for writing! + Greidde ikkje skriva til fila! + + + OK + OK + + + Audio Track + Lydspor + + + Data Track + Dataspor + + + Rip Complete + Ferdig å rippa + + + Rip complete! + Ferdig å rippa! + + + Rip Aborted + Avbraut rippinga + + + The rip has been aborted. + Rippinga er avbroten. + + + Rip Failed + Rippinga mislukka + + + The ripper encountered an error. +Please check your ripper configuration and try again. + Rippinga vart mislukka. +Sjå over innstillingane for ripping, og prøv ein gong til. + + + RDLibrary - Importer Error + + + + RDLibrary - Ripper Error + + + + Abort +Rip + + + + Rip Track + + + + Title: + + + + [none] + + + + Ripper Error + + + + Unable to create temporary directory! + + + + + DiskRipper + + Rip Disk + Ripp plata + + + Artist: + Artist: + + + Album: + Album: + + + Other: + Anna: + + + Apply FreeDB Values to Carts + Bruk FreeDB-opplysningar på korgene + + + Tracks + Spor + + + TRACK + SPOR + + + LENGTH + LENGD + + + TITLE + TITTEL + + + OTHER + ANNA + + + TYPE + TYPE + + + CUT + Kutt + + + Disk Progress + Framgang for plata + + + Track Progress + Framgang for sporet + + + Set +&Cut + Set +&Kutt + + + Set All +&New Carts + Set alle +&Nye korger + + + Normalize + Normaliser + + + Level: + Nivå: + + + dBFS + duMN + + + Autotrim + Autotrim + + + Channels: + Kanalar: + + + &Rip +Disk + &Ripp +plata + + + &Close + &Lukk + + + Cut Conflict + Konflikt mellom kutt + + + That cut has already been assigned a track! + Dette kuttet er alt tildelt eit spor! + + + Cut Exists + Kuttet eksisterer + + + A recording already exists. +Do you want to overwrite it? + Det finst alt eit opptak. +Vil du byta det ut? + + + Empty Clipboard + Tøm utklyppstavla + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + Viss du rippar dette kuttet, vil du òg tøma utklyppstavla. +Vil du halda fram? + + + Library Error + Bibliotekfeil + + + Insufficient free carts available in group! + Det er ikkje nok ledige korger i gruppa! + + + Audio Track + Lydspor + + + Data Track + Dataspor + + + Rip Complete + Ferdig å rippa + + + Rip complete! + Ferdig å rippa! + + + Rip Aborted + Avbraut rippinga + + + The rip has been aborted. + Rippinga er avbroten. + + + Rip Failed + Rippinga mislukka + + + The ripper encountered an error. +Please check your ripper configuration and try again. + Rippinga vart mislukka. +Sjå over innstillingane for ripping, og prøv ein gong til. + + + Total Progress + Framgang totalt + + + No Access + Ingen tilgang + + + Unable to open the file for writing! + Greidde ikkje skriva til fila! + + + OK + OK + + + &Rip +Disc + + + + RDLibrary - Importer Error + + + + RDLibrary - Ripper Error + + + + Abort +Rip + + + + Rip +Disk + + + + Rip aborted! + + + + Ripper Error + + + + Unable to create temporary directory! + + + + Cut + + + + Track + + + + Add Cart +Per Track + + + + Add Single +Cart + + + + Set +&Cart/Cut + + + + [continued] + + + + Modify +Cart Label + + + + Clear +Selection + + + + Error + + + + Unable to allocate carts in group + + + + Unable to allocate cart in group + + + + + EditCart + + Number: + Nummer: + + + Group: + Gruppe: + + + Type: + Type: + + + Average Length: + Snittlengd: + + + Enforce Length + Tving lengd + + + Forced Length: + Tvungen lengd: + + + Preserve Pitch + Hald tonehøgd + + + &Title: + &Tittel: + + + &Start Date: + &Startdato: + + + &End Date: + Slu&ttdato: + + + &Artist: + &Artist: + + + &Year Released: + &Utgjevingsår: + + + U&sage: + &Bruk: + + + Scheduler Codes + Planleggarkodar + + + Al&bum: + A&lbum: + + + Re&cord Label: + &Plateselskap: + + + C&lient: + K&lient: + + + A&gency: + A&gent: + + + &Publisher: + Ut&gjevar: + + + Compos&er: + &Komponist: + + + &User Defined: + Br&ukardefinert: + + + Schedule Cuts: + Planlegg kutt: + + + Execute Asynchronously + Utfør asynkront + + + &Edit +Script + &Rediger +skript + + + &OK + &OK + + + &Cancel + &Avbryt + + + AUDIO + LYD + + + MACRO + MAKRO + + + UNKNOWN + UKJENT + + + TFN + TFN + + + Sequentially + I rekkjefylgje + + + Randomly + Tilfeldig + + + + + + + Missing Title + Manglar namn + + + You must provide at least a Cart Title! + Du må i alle fall skriva inn eit namn på korga! + + + Length Mismatch + Lengd passar ikkje + + + One or more cut lengths exceed the timescaling +limits of the system! Do you still want to save? + Eitt eller fleire kutt er lenger enn det systemet +kan handtera! Vil du lagra likevel? + + + &Edit +Notes + + + + Duplicate Title + + + + The cart title must be unique! + + + + RDLibrary - Edit Cart + + + + This cart cannot contain any additional cuts! + + + + Cond&uctor: + + + + Song &ID: + + + + Unknown + + + + &Beats per Minute: + + + + Use Event Length for Now && Next Updates + + + + + EditMacro + + Edit Macro + Rediger makro + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditNotes + + Notes for cart + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditSchedulerCodes + + Select Scheduler Codes + + + + Available Codes + + + + Assigned Codes + + + + ASSIGN to Carts + + + + REMOVE from Carts + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + Filter + + Library Filter + Bibliotekfilter + + + &OK + &OK + + + C&lear + &Tøm + + + &Cancel + &Avbryt + + + &Filter: + &Filter: + + + + ListReports + + RDLibrary Reports + + + + Cart Report + + + + Cut Report + + + + Type: + Type: + + + &Generate + + + + &Close + &Lukk + + + ALL + ALT + + + Cart Data Dump (fixed width) + + + + Cart Data Dump (CSV) + + + + Prepend Field Names + + + + + MacroCart + + Add + Legg til + + + Delete + Slett + + + Copy + Kopier + + + Paste + Lim inn + + + LINE + LINE + + + COMMAND + KOMMANDO + + + Macros + Makroar + + + Edit + Rediger + + + Run +Line + Køyr +line + + + Run +Cart + Køyr +korg + + + --- End of cart --- + --- Slutten på korga --- + + + + MainWidget + + Please Wait... + Vent litt... + + + rdlibrary : + rdlibrary : + + + Can't Connect + Greier ikkje kopla til + + + Filter: + Filter: + + + &Search + &Søk + + + &Clear + &Tøm + + + Group: + Gruppe: + + + Scheduler Code: + Planleggarkode: + + + Show Audio Carts + Vis lydkorger + + + Show Macro Carts + Vis makrokorger + + + CART + KORG + + + GROUP + GRUPPE + + + LENGTH + LENGD + + + TITLE + TITTEL + + + ARTIST + ARTIST + + + START + START + + + END + SLUTT + + + CLIENT + KLIENT + + + AGENCY + AGENT + + + USER DEFINED + BRUKARDEFINERT + + + CUTS + KUTT + + + LAST CUT PLAYED + SISTE KUTT SPELT + + + PLAY ORDER + SPELEREKKJEFYLGJE + + + ENFORCE LENGTH + TVING LENGD + + + PRESERVE PITCH + HALD TONEHØGD + + + LENGTH DEVIATION + LENGD-FRÅVIK + + + OWNED BY + ÅTT AV + + + &Add + L&egg til + + + &Edit + &Rediger + + + &Delete + &Slett + + + &Rip +CD + &Ripp +CD + + + Re&ports + Ra&pportar + + + &Close + &Lukk + + + ALL + ALT + + + + + + + Are you sure you want to delete cart(s) + Er du sikker på at du vil sletta korg(ene) + + + Delete Cart(s) + Slett korg(ene) + + + Cart %06u is used in one or more RDCatch events! +Do you still want to delete it? + Korga %06u er brukt i ei eller fleire RDCatch-hendingar. +Vil du sletta ho likevel? + + + RDCatch Event Exists + RDCatch-hending eksisterer + + + Deleting cart %06u will also empty the clipboard. + Do you still want to proceed? + Viss du slettar korga %06u, tømer du utklyppstavla. + Vil du halda fram? + + + Empty Clipboard + Tøm utklyppstavla + + + Sequence + Rekkjefylgje + + + Random + Tilfeldig + + + TFN + TFN + + + RDLibrary - Host: + RDLibrary -- Vert: + + + , User: + , brukar: + + + Show Note Bubbles + + + + RDLibrary + + + + Unable to delete audio! + + + + Show Only First + + + + Matches + + + + Host + + + + User + + + + COMPOSER + + + + CONDUCTOR + + + + PUBLISHER + + + + Allow Cart Dragging + + + + Error + + + + Unknown command-line option + + + + ALBUM + + + + LABEL + + + + + RecordCut + + RDLibrary - Record + RDLibrary - Opptak + + + &Description + Skil&dring + + + &Outcue + &Utspor + + + Origin + Opphav + + + ISRC + ISRC + + + Weight + Vekt + + + Last Played + Sist spelt + + + # of Plays + Spelt gonger + + + Cut is EVERGREEN + Kuttet er ein SLAGER + + + Air Date/Time + Påluft dato/tid + + + Enabled + + + + Disabled + Av + + + &Start + &Start + + + End + Slutt + + + Daypart + Dagdel + + + &Start Time + &Starttid + + + End Time + Sluttid + + + Day of the Week + Vekedag + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Set All + Set alle + + + Clear All + Tøm alle + + + NO SYNC! + INGEN SYNK! + + + Channels + Kanalar + + + Record Mode + Opptaksmåte + + + AutoTrim + Autotrim + + + &Close + &Lukk + + + Manual + Manuelt + + + VOX + VOX + + + On + + + + Off + Av + + + Audio Exists + Lyd eksisterer + + + This will overwrite the existing recording. +Do you want to proceed? + Dette byter ut opptaket du alt har. +Vil du halda fram? + + + Empty Clipboard + Tøm utklyppstavla + + + This will empty the clipboard. +Do you still want to proceed? + Dette tømer utklyppstavla. +Vil du halda fram? + + + Missing Description + Manglar skildring + + + You must provide a Cut Description! + Du må skriva inn ei skildring for kuttet! + + + Invalid ISRC + Ugyldig ISRC + + + The ISRC data is malformed or invalid! + ISRC-dataa er feilforma eller ugyldige! + + + Invalid Date + Ugyldig dato + + + The Start Date is invalid! + Startdatoen er ugyldig! + + + The End Date is invalid! + Sluttdatoen er ugyldig! + + + The End Date is prior to the Start Date! + Sluttdatoen er før startdatoen! + + + The End Date has already passed! +Do you still want to save? + Sluttdatoen har allereie vore! +Vil du lagra likevel? + + + Invalid Time + Ugyldig tid + + + The Start Time is invalid! + Starttida er ugyldig! + + + The End Time is invalid! + Sluttida er ugyldig! + + + The StartTime cannot be the same as the End Time! + Starttida kan ikkje vera den same som sluttida! + + + Can't Connect + Greier ikkje kopla til + + + Unable to connect to Core AudioEngine + Greier ikkje kopla til CoreAudioEnginge + + + &ISCI Code + + + + AES ALARM + + + + diff --git a/rdlibrary/rdlibrary_nn.ts b/rdlibrary/rdlibrary_nn.ts new file mode 100644 index 00000000..958ddfa9 --- /dev/null +++ b/rdlibrary/rdlibrary_nn.ts @@ -0,0 +1,1522 @@ + + + AudioCart + + Copying audio... + Kopierer lyd... + + + Add + Legg til + + + Delete + Slett + + + Copy + Kopier + + + Paste + Lim inn + + + WT + VT + + + DESCRIPTION + SKILDRING + + + LENGTH + LENGD + + + LAST PLAYED + SIST SPELT + + + # OF PLAYS + SPELT GGR + + + ORIGIN + OPPHAV + + + OUTCUE + UTSPOR + + + START DATE + STARTDATO + + + END DATE + SLUTTDATO + + + DAYPART START + DAGDEL START + + + DAYPART END + DAGDEL SLUTT + + + NAME + NAMN + + + Cuts + Kutt + + + Cut Info + Info om kutt + + + Record + Ta opp + + + Edit +Audio + Rediger lyd + + + Edit +Markers + Rediger +markørar + + + Import + Importer + + + Export + Eksporter + + + Rip CD + Ripp CD + + + Are you sure you want to delete + Er du sikker på at du vil sletta + + + Delete Cut + Slett kutt + + + RDCatch Event Exists + RDCatch-hending eksisterer + + + This cut is used in one or more RDCatch events! +Do you still want to delete it? + Dette kuttet er brukt i ei eller fleire RDCatch-hendingar. +Er du sikker på at du vil sletta det? + + + Empty Clipboard + Tøm utklyppstavla + + + Deleting this cut will also empty the clipboard. +Do you still want to proceed? + Viss du slettar dette kuttet, vil du òg tømma utklyppstavla. +Vil du halda fram? + + + Clipboard Empty + Tom utklyppstavle + + + Clipboard is currently empty. + Utklyppstavla er tom. + + + Audio Exists + Lyd eksisterer + + + This will overwrite the existing recording. +Do you want to proceed? + Dette byter ut opptaket du alt har. +Vil du halda fram? + + + [new cart] + [ny korg] + + + Never + Aldri + + + None + Ingen + + + 1 Cut + 1 kutt + + + RDLibrary + + + + No audio is present in the cut! + + + + This cart cannot contain any additional cuts! + + + + RDLibrary - Edit Cart + + + + Delete Cuts + + + + cuts + + + + One or more cuts are used in one or more RDCatch events! +Do you still want to delete? + + + + Unable to delete audio for cut + + + + Copy Cut + + + + No data copied - you must select a single cut! + + + + Paste Cut + + + + You must select a single cut! + + + + + CdRipper + + Artist: + Artist: + + + Album: + Album: + + + Other: + Anna: + + + Apply FreeDB Values to Cart + Bruk FreeDB-opplysningar på korga + + + Tracks + Spor + + + TRACK + SPOR + + + LENGTH + LENGD + + + TITLE + TITTEL + + + OTHER + ANNA + + + TYPE + TYPE + + + &Rip +Track + &Ripp +sporet + + + Normalize + Normaliser + + + Level: + Nivå: + + + dBFS + duMN + + + Autotrim + Autotrim + + + Channels: + Kanalar: + + + Audio Exists + Lyd eksisterer + + + This will overwrite the existing recording. +Do you want to proceed? + Dette byter ut opptaket du alt har. +Vil du halda fram? + + + Empty Clipboard + Tøm utklyppstavla + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + Viss du rippar dette sporet, tømer du utklyppstavla. +Vil du halda fram? + + + No Access + Ingen tilgang + + + Unable to open the file for writing! + Greidde ikkje skriva til fila! + + + OK + OK + + + Audio Track + Lydspor + + + Data Track + Dataspor + + + Rip Complete + Ferdig å rippa + + + Rip complete! + Ferdig å rippa! + + + Rip Aborted + Avbraut rippinga + + + The rip has been aborted. + Rippinga er avbroten. + + + Rip Failed + Rippinga mislukka + + + The ripper encountered an error. +Please check your ripper configuration and try again. + Rippinga vart mislukka. +Sjå over innstillingane for ripping, og prøv ein gong til. + + + RDLibrary - Importer Error + + + + RDLibrary - Ripper Error + + + + Abort +Rip + + + + Rip Track + + + + Title: + + + + [none] + + + + Ripper Error + + + + Unable to create temporary directory! + + + + + DiskRipper + + Rip Disk + Ripp plata + + + Artist: + Artist: + + + Album: + Album: + + + Other: + Anna: + + + Apply FreeDB Values to Carts + Bruk FreeDB-opplysningar på korgene + + + Tracks + Spor + + + TRACK + SPOR + + + LENGTH + LENGD + + + TITLE + TITTEL + + + OTHER + ANNA + + + TYPE + TYPE + + + CUT + Kutt + + + Disk Progress + Framgang for plata + + + Track Progress + Framgang for sporet + + + Set +&Cut + Set +&Kutt + + + Set All +&New Carts + Set alle +&Nye korger + + + Normalize + Normaliser + + + Level: + Nivå: + + + dBFS + duMN + + + Autotrim + Autotrim + + + Channels: + Kanalar: + + + &Rip +Disk + &Ripp +plata + + + &Close + &Lukk + + + Cut Conflict + Konflikt mellom kutt + + + That cut has already been assigned a track! + Dette kuttet er alt tildelt eit spor! + + + Cut Exists + Kuttet eksisterer + + + A recording already exists. +Do you want to overwrite it? + Det finst alt eit opptak. +Vil du byta det ut? + + + Empty Clipboard + Tøm utklyppstavla + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + Viss du rippar dette kuttet, vil du òg tøma utklyppstavla. +Vil du halda fram? + + + Library Error + Bibliotekfeil + + + Insufficient free carts available in group! + Det er ikkje nok ledige korger i gruppa! + + + Audio Track + Lydspor + + + Data Track + Dataspor + + + Rip Complete + Ferdig å rippa + + + Rip complete! + Ferdig å rippa! + + + Rip Aborted + Avbraut rippinga + + + The rip has been aborted. + Rippinga er avbroten. + + + Rip Failed + Rippinga mislukka + + + The ripper encountered an error. +Please check your ripper configuration and try again. + Rippinga vart mislukka. +Sjå over innstillingane for ripping, og prøv ein gong til. + + + Total Progress + Framgang totalt + + + No Access + Ingen tilgang + + + Unable to open the file for writing! + Greidde ikkje skriva til fila! + + + OK + OK + + + &Rip +Disc + + + + RDLibrary - Importer Error + + + + RDLibrary - Ripper Error + + + + Abort +Rip + + + + Rip +Disk + + + + Rip aborted! + + + + Ripper Error + + + + Unable to create temporary directory! + + + + Cut + + + + Track + + + + Add Cart +Per Track + + + + Add Single +Cart + + + + Set +&Cart/Cut + + + + [continued] + + + + Modify +Cart Label + + + + Clear +Selection + + + + Error + + + + Unable to allocate carts in group + + + + Unable to allocate cart in group + + + + + EditCart + + Number: + Nummer: + + + Group: + Gruppe: + + + Type: + Type: + + + Average Length: + Snittlengd: + + + Enforce Length + Tving lengd + + + Forced Length: + Tvungen lengd: + + + Preserve Pitch + Hald tonehøgd + + + &Title: + &Tittel: + + + &Start Date: + &Startdato: + + + &End Date: + Slu&ttdato: + + + &Artist: + &Artist: + + + &Year Released: + &Utgjevingsår: + + + U&sage: + &Bruk: + + + Scheduler Codes + Planleggarkodar + + + Al&bum: + A&lbum: + + + Re&cord Label: + &Plateselskap: + + + C&lient: + K&lient: + + + A&gency: + A&gent: + + + &Publisher: + Ut&gjevar: + + + Compos&er: + &Komponist: + + + &User Defined: + Br&ukardefinert: + + + Schedule Cuts: + Planlegg kutt: + + + Execute Asynchronously + Utfør asynkront + + + &Edit +Script + &Rediger +skript + + + &OK + &OK + + + &Cancel + &Avbryt + + + AUDIO + LYD + + + MACRO + MAKRO + + + UNKNOWN + UKJENT + + + TFN + TFN + + + Sequentially + I rekkjefylgje + + + Randomly + Tilfeldig + + + + + + + Missing Title + Manglar namn + + + You must provide at least a Cart Title! + Du må i alle fall skriva inn eit namn på korga! + + + Length Mismatch + Lengd passar ikkje + + + One or more cut lengths exceed the timescaling +limits of the system! Do you still want to save? + Eitt eller fleire kutt er lenger enn det systemet +kan handtera! Vil du lagra likevel? + + + &Edit +Notes + + + + Duplicate Title + + + + The cart title must be unique! + + + + RDLibrary - Edit Cart + + + + This cart cannot contain any additional cuts! + + + + Cond&uctor: + + + + Song &ID: + + + + Unknown + + + + &Beats per Minute: + + + + Use Event Length for Now && Next Updates + + + + + EditMacro + + Edit Macro + Rediger makro + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditNotes + + Notes for cart + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditSchedulerCodes + + Select Scheduler Codes + + + + Available Codes + + + + Assigned Codes + + + + ASSIGN to Carts + + + + REMOVE from Carts + + + + &OK + &OK + + + &Cancel + &Avbryt + + + + Filter + + Library Filter + Bibliotekfilter + + + &OK + &OK + + + C&lear + &Tøm + + + &Cancel + &Avbryt + + + &Filter: + &Filter: + + + + ListReports + + RDLibrary Reports + + + + Cart Report + + + + Cut Report + + + + Type: + Type: + + + &Generate + + + + &Close + &Lukk + + + ALL + ALT + + + Cart Data Dump (fixed width) + + + + Cart Data Dump (CSV) + + + + Prepend Field Names + + + + + MacroCart + + Add + Legg til + + + Delete + Slett + + + Copy + Kopier + + + Paste + Lim inn + + + LINE + LINE + + + COMMAND + KOMMANDO + + + Macros + Makroar + + + Edit + Rediger + + + Run +Line + Køyr +line + + + Run +Cart + Køyr +korg + + + --- End of cart --- + --- Slutten på korga --- + + + + MainWidget + + Please Wait... + Vent litt... + + + rdlibrary : + rdlibrary : + + + Can't Connect + Greier ikkje kopla til + + + Filter: + Filter: + + + &Search + &Søk + + + &Clear + &Tøm + + + Group: + Gruppe: + + + Scheduler Code: + Planleggarkode: + + + Show Audio Carts + Vis lydkorger + + + Show Macro Carts + Vis makrokorger + + + CART + KORG + + + GROUP + GRUPPE + + + LENGTH + LENGD + + + TITLE + TITTEL + + + ARTIST + ARTIST + + + START + START + + + END + SLUTT + + + CLIENT + KLIENT + + + AGENCY + AGENT + + + USER DEFINED + BRUKARDEFINERT + + + CUTS + KUTT + + + LAST CUT PLAYED + SISTE KUTT SPELT + + + PLAY ORDER + SPELEREKKJEFYLGJE + + + ENFORCE LENGTH + TVING LENGD + + + PRESERVE PITCH + HALD TONEHØGD + + + LENGTH DEVIATION + LENGD-FRÅVIK + + + OWNED BY + ÅTT AV + + + &Add + L&egg til + + + &Edit + &Rediger + + + &Delete + &Slett + + + &Rip +CD + &Ripp +CD + + + Re&ports + Ra&pportar + + + &Close + &Lukk + + + ALL + ALT + + + + + + + Are you sure you want to delete cart(s) + Er du sikker på at du vil sletta korg(ene) + + + Delete Cart(s) + Slett korg(ene) + + + Cart %06u is used in one or more RDCatch events! +Do you still want to delete it? + Korga %06u er brukt i ei eller fleire RDCatch-hendingar. +Vil du sletta ho likevel? + + + RDCatch Event Exists + RDCatch-hending eksisterer + + + Deleting cart %06u will also empty the clipboard. + Do you still want to proceed? + Viss du slettar korga %06u, tømer du utklyppstavla. + Vil du halda fram? + + + Empty Clipboard + Tøm utklyppstavla + + + Sequence + Rekkjefylgje + + + Random + Tilfeldig + + + TFN + TFN + + + RDLibrary - Host: + RDLibrary -- Vert: + + + , User: + , brukar: + + + Show Note Bubbles + + + + RDLibrary + + + + Unable to delete audio! + + + + Show Only First + + + + Matches + + + + Host + + + + User + + + + COMPOSER + + + + CONDUCTOR + + + + PUBLISHER + + + + Allow Cart Dragging + + + + Error + + + + Unknown command-line option + + + + ALBUM + + + + LABEL + + + + + RecordCut + + RDLibrary - Record + RDLibrary - Opptak + + + &Description + Skil&dring + + + &Outcue + &Utspor + + + Origin + Opphav + + + ISRC + ISRC + + + Weight + Vekt + + + Last Played + Sist spelt + + + # of Plays + Spelt gonger + + + Cut is EVERGREEN + Kuttet er ein SLAGER + + + Air Date/Time + Påluft dato/tid + + + Enabled + + + + Disabled + Av + + + &Start + &Start + + + End + Slutt + + + Daypart + Dagdel + + + &Start Time + &Starttid + + + End Time + Sluttid + + + Day of the Week + Vekedag + + + Monday + Måndag + + + Tuesday + Tysdag + + + Wednesday + Onsdag + + + Thursday + Torsdag + + + Friday + Fredag + + + Saturday + Laurdag + + + Sunday + Sundag + + + Set All + Set alle + + + Clear All + Tøm alle + + + NO SYNC! + INGEN SYNK! + + + Channels + Kanalar + + + Record Mode + Opptaksmåte + + + AutoTrim + Autotrim + + + &Close + &Lukk + + + Manual + Manuelt + + + VOX + VOX + + + On + + + + Off + Av + + + Audio Exists + Lyd eksisterer + + + This will overwrite the existing recording. +Do you want to proceed? + Dette byter ut opptaket du alt har. +Vil du halda fram? + + + Empty Clipboard + Tøm utklyppstavla + + + This will empty the clipboard. +Do you still want to proceed? + Dette tømer utklyppstavla. +Vil du halda fram? + + + Missing Description + Manglar skildring + + + You must provide a Cut Description! + Du må skriva inn ei skildring for kuttet! + + + Invalid ISRC + Ugyldig ISRC + + + The ISRC data is malformed or invalid! + ISRC-dataa er feilforma eller ugyldige! + + + Invalid Date + Ugyldig dato + + + The Start Date is invalid! + Startdatoen er ugyldig! + + + The End Date is invalid! + Sluttdatoen er ugyldig! + + + The End Date is prior to the Start Date! + Sluttdatoen er før startdatoen! + + + The End Date has already passed! +Do you still want to save? + Sluttdatoen har allereie vore! +Vil du lagra likevel? + + + Invalid Time + Ugyldig tid + + + The Start Time is invalid! + Starttida er ugyldig! + + + The End Time is invalid! + Sluttida er ugyldig! + + + The StartTime cannot be the same as the End Time! + Starttida kan ikkje vera den same som sluttida! + + + Can't Connect + Greier ikkje kopla til + + + Unable to connect to Core AudioEngine + Greier ikkje kopla til CoreAudioEnginge + + + &ISCI Code + + + + AES ALARM + + + + diff --git a/rdlibrary/rdlibrary_pt_BR.ts b/rdlibrary/rdlibrary_pt_BR.ts new file mode 100644 index 00000000..ed9a8391 --- /dev/null +++ b/rdlibrary/rdlibrary_pt_BR.ts @@ -0,0 +1,1524 @@ + + + AudioCart + + Copying audio... + Copiando áudio... + + + Add + Adicionar + + + Delete + Deletar + + + Copy + Copiar + + + Paste + Colar + + + WT + WT + + + DESCRIPTION + DESCRIÇÃO + + + LENGTH + DURAÇÃO + + + LAST PLAYED + ÚLTIMO VEZ EXECUTADA + + + # OF PLAYS + # AO AR + + + ORIGIN + ORIGEM + + + OUTCUE + COMENTÁRIO + + + START DATE + DATA DE INÍCIO + + + END DATE + DATA DE TÉRMINO + + + DAYPART START + DIAS PERMITIDOS INÍCIO + + + DAYPART END + DIAS PERMITIDOS TÉRMINO + + + NAME + NOME + + + Cuts + Conteúdos + + + Cut Info + Info + + + Record + Gravar + + + Edit +Audio + Editar +Áudio + + + Edit +Markers + Editar +Marcadores + + + Import + Importar + + + Export + Exportar + + + Rip CD + Extrair CD + + + Are you sure you want to delete + Tem certeza que quer deletar + + + Delete Cut + Deletar Conteúdo + + + RDCatch Event Exists + Evento de RDCaptura existente + + + This cut is used in one or more RDCatch events! +Do you still want to delete it? + Este Conteúdo é usado em um ou mais Eventos do RDCaptura +Você quer deletá-lo mesmo assim? + + + Empty Clipboard + Esvaziar Clipboard + + + Deleting this cut will also empty the clipboard. +Do you still want to proceed? + Delatar este Conteúdo também esvaziará o clipboard. +Você ainda quer proceder? + + + Clipboard Empty + Clipboard Vazio + + + Clipboard is currently empty. + Clipboard está vazio. + + + Audio Exists + Áudio Existe + + + This will overwrite the existing recording. +Do you want to proceed? + Esta ação sobrescreverá a gravação existente. +Você quer proceder? + + + [new cart] + [novo cartão] + + + Never + Nunca + + + None + Nenhum + + + 1 Cut + 1 Conteúdo + + + RDLibrary + + + + No audio is present in the cut! + + + + This cart cannot contain any additional cuts! + + + + RDLibrary - Edit Cart + + + + Delete Cuts + + + + cuts + + + + One or more cuts are used in one or more RDCatch events! +Do you still want to delete? + + + + Unable to delete audio for cut + + + + Copy Cut + + + + No data copied - you must select a single cut! + + + + Paste Cut + + + + You must select a single cut! + + + + + CdRipper + + Artist: + Artista: + + + Album: + Álbum: + + + Other: + Outro: + + + Apply FreeDB Values to Cart + Aplicar Valores do FreeDB ao Cartão + + + Tracks + Faixas + + + TRACK + FAIXAS + + + LENGTH + DURAÇÃO + + + TITLE + TÍTULO + + + OTHER + OUTRO + + + TYPE + TIPO + + + &Rip +Track + &Extrair +Faixa + + + Normalize + Normalizar + + + Level: + Nível + + + dBFS + dBFS + + + Autotrim + AutoCorte + + + Channels: + Canais: + + + Audio Exists + Áudio Existe + + + This will overwrite the existing recording. +Do you want to proceed? + Esta ação sobrescreverá a gravação existente. +Você quer proceder? + + + Empty Clipboard + Esvaziar Clipboard + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + Extrair este Conteúdo também esvaziará o clipboard. +Você ainda quer proceder? + + + No Access + Sem Acesso + + + Unable to open the file for writing! + Não foi possível abrir o arquivo para escrita! + + + OK + OK + + + Audio Track + Faixa de Áudio + + + Data Track + Faixa de Dados + + + Rip Complete + Extração Completa + + + Rip complete! + Extração Completa! + + + Rip Aborted + Extração Abortada + + + The rip has been aborted. + A Extração foi abortada + + + Rip Failed + Extração falhou + + + The ripper encountered an error. +Please check your ripper configuration and try again. + O dispositivo de extração encontrou um Erro. +Por Favor, cheque suas configurações e tente novamente. + + + Abort +Rip + + + + RDLibrary - Importer Error + + + + RDLibrary - Ripper Error + + + + Rip Track + + + + Title: + + + + [none] + + + + Ripper Error + + + + Unable to create temporary directory! + + + + + DiskRipper + + Rip Disk + Extrair Disco + + + Artist: + Artista: + + + Album: + Álbum: + + + Other: + Outro: + + + Apply FreeDB Values to Carts + Aplicar Valores do FreeDB ao Cartão + + + Tracks + Faixas + + + TRACK + FAIXA + + + LENGTH + DURAÇÃO + + + TITLE + TÍTULO + + + OTHER + OUTRO + + + TYPE + TIPO + + + CUT + CONTEÚDO + + + Disk Progress + Progresso do Disco + + + Track Progress + Progresso da Faixa + + + Set +&Cut + Selecionar +&Conteúdo + + + Set All +&New Carts + Sel Todos +&Cartões + + + Normalize + Normalizar + + + Level: + Nível: + + + dBFS + dBFS + + + Autotrim + AutoCorte + + + Channels: + Canais: + + + &Rip +Disk + &Extrair +Disco + + + &Close + &Fechar + + + Cut Conflict + Confllito de Conteúdo + + + That cut has already been assigned a track! + Este conteúdo já foi destinado a uma faixa! + + + Cut Exists + COnteúdo Existente + + + A recording already exists. +Do you want to overwrite it? + Uma gravação já existe. +Você quer sobrescrevê-la? + + + Empty Clipboard + Esvaziar Clipboard + + + Ripping this cut will also empty the clipboard. +Do you still want to proceed? + Extrair este Conteúdo também esvaziará o clipboard. +Você ainda quer proceder? + + + Library Error + Erro na Biblioteca + + + Insufficient free carts available in group! + Cartão vazios insuficientes neste grupo! + + + Audio Track + Faixa de Áudio + + + Data Track + Faixa de Dados + + + Rip Complete + Extração Completa + + + Rip complete! + Extração Completa! + + + Rip Aborted + Extração Abortada + + + The rip has been aborted. + A Extração foi abortada + + + Rip Failed + Extração falhou + + + The ripper encountered an error. +Please check your ripper configuration and try again. + O dispositivo de extração encontrou um Erro. +Por Favor, cheque suas configurações e tente novamente. + + + Total Progress + Progresso Total + + + No Access + Sem Acesso + + + Unable to open the file for writing! + Não foi possível abrir o arquivo para escrita! + + + OK + OK + + + &Rip +Disc + + + + Abort +Rip + + + + Rip +Disk + + + + Rip aborted! + + + + RDLibrary - Importer Error + + + + RDLibrary - Ripper Error + + + + Ripper Error + + + + Unable to create temporary directory! + + + + Cut + + + + Track + + + + Add Cart +Per Track + + + + Add Single +Cart + + + + Set +&Cart/Cut + + + + [continued] + + + + Modify +Cart Label + + + + Clear +Selection + + + + Error + + + + Unable to allocate carts in group + + + + Unable to allocate cart in group + + + + + EditCart + + Number: + Número: + + + Group: + Grupo: + + + Type: + Tipo: + + + Average Length: + Duração Média: + + + Enforce Length + Forçar Duração + + + Forced Length: + Duração Forçada: + + + Preserve Pitch + Preservar Pitch + + + &Title: + &Título + + + &Start Date: + &Data de Início: + + + &End Date: + &Data de Término: + + + &Artist: + &Artista: + + + &Year Released: + &Ano de Lançamento: + + + U&sage: + &Uso: + + + Scheduler Codes + Códigos do Agendador + + + Al&bum: + &Álbum: + + + Re&cord Label: + Gravadora/Selo: + + + C&lient: + &Cliente: + + + A&gency: + &Agência + + + &Publisher: + &Editora: + + + Compos&er: + &Compositor: + + + &User Defined: + &Uso Genérico: + + + Schedule Cuts: + Agendar Conteúdos: + + + Execute Asynchronously + Executar sem Sincronia + + + &Edit +Notes + &Editar +Notas + + + &Edit +Script + &Editar +Script + + + &OK + &OK + + + &Cancel + &Cancelar + + + AUDIO + ÁUDIO + + + MACRO + MACRO + + + UNKNOWN + DESCONHECIDO + + + TFN + TFN + + + Sequentially + Sequencialmente + + + Randomly + Randomicamente + + + + + + + Missing Title + Sem Título + + + You must provide at least a Cart Title! + Você deve dar no mínimo um título ao Cartão! + + + Duplicate Title + Duplicar Título + + + The cart title must be unique! + O Título do Cartão deve ser Único! + + + Length Mismatch + Duração Desencontrada + + + One or more cut lengths exceed the timescaling +limits of the system! Do you still want to save? + Uma ou mais durações de Conteúdos excedem a escala de tempo +limite do sistema! Você ainda quer salvar? + + + RDLibrary - Edit Cart + + + + This cart cannot contain any additional cuts! + + + + Cond&uctor: + + + + Song &ID: + + + + Unknown + + + + &Beats per Minute: + + + + Use Event Length for Now && Next Updates + + + + + EditMacro + + Edit Macro + Editar Macro + + + &OK + &OK + + + &Cancel + &Cancelar + + + + EditNotes + + Notes for cart + + + + &OK + &OK + + + &Cancel + &Cancelar + + + + EditSchedulerCodes + + Select Scheduler Codes + + + + Available Codes + + + + Assigned Codes + + + + ASSIGN to Carts + + + + REMOVE from Carts + + + + &OK + &OK + + + &Cancel + &Cancelar + + + + Filter + + Library Filter + Filtro + + + &OK + &OK + + + C&lear + &Limpar + + + &Cancel + &Cancelar + + + &Filter: + &Filtrar: + + + + ListReports + + RDLibrary Reports + + + + Cart Report + + + + Cut Report + + + + Type: + Tipo: + + + &Generate + + + + &Close + &Fechar + + + ALL + TODOS + + + Cart Data Dump (fixed width) + + + + Cart Data Dump (CSV) + + + + Prepend Field Names + + + + + MacroCart + + Add + Adicionar + + + Delete + Deletar + + + Copy + Copiar + + + Paste + Colar + + + LINE + LINHA + + + COMMAND + COMANDO + + + Macros + Macros + + + Edit + Editar + + + Run +Line + Executar +Linha + + + Run +Cart + Executar +Cartão + + + --- End of cart --- + -- Fim do Cartão -- + + + + MainWidget + + Please Wait... + Por favor, espere... + + + rdlibrary : + RDBiblio: + + + Can't Connect + Sem conexão + + + Filter: + Filtro: + + + &Search + &Procura + + + &Clear + &Limpe + + + Group: + Grupo: + + + Scheduler Code: + Códigos: + + + Show Audio Carts + Mostrar Áudio + + + Show Macro Carts + + + + Show Note Bubbles + Mostrar Notas + + + CART + CARTÃO + + + GROUP + GRUPO + + + LENGTH + DURAÇÃO + + + TITLE + TÍTULO + + + ARTIST + ARTISTA + + + START + INÍCIO + + + END + FIM + + + CLIENT + CLIENTE + + + AGENCY + AGÊNCIA + + + USER DEFINED + USO GENÉRICO + + + CUTS + CONTEÚDOS + + + LAST CUT PLAYED + ÚLTIMO CONTEÚDO EXECUTADO + + + PLAY ORDER + ORDEM DE EXECUÇÃO + + + ENFORCE LENGTH + FORÇAR DURAÇÃO + + + PRESERVE PITCH + PRESERVAR PITCH + + + LENGTH DEVIATION + DESVIO DE DURAÇÃO + + + OWNED BY + DONO + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &Rip +CD + &Extrair +CD + + + Re&ports + &Relatórios + + + &Close + &Fechar + + + ALL + TODOS + + + + + + + Are you sure you want to delete cart(s) + Tem certeza que quer deletar cartão(s) + + + Delete Cart(s) + Deletar Cartão(s) + + + Cart %06u is used in one or more RDCatch events! +Do you still want to delete it? + Cartão %06u é usado em um ou mais eventos do RDCaptura! +Você ainda quer deletá-lo? + + + RDCatch Event Exists + Evento do RDCaptura Existente + + + Deleting cart %06u will also empty the clipboard. + Do you still want to proceed? + Deletar o Cartão %06u também esvaziará o clipboard. + Você ainda quer proceder? + + + Empty Clipboard + Esvaziar Clipboard + + + Sequence + Sequência + + + Random + Randômico + + + TFN + TFN + + + RDLibrary - Host: + RDBiblio - Cliente: + + + , User: + , Usuário: + + + Show Only First + + + + Matches + + + + RDLibrary + + + + Unable to delete audio! + + + + Host + + + + User + + + + COMPOSER + + + + CONDUCTOR + + + + PUBLISHER + + + + Allow Cart Dragging + + + + Error + + + + Unknown command-line option + + + + ALBUM + + + + LABEL + + + + + RecordCut + + RDLibrary - Record + RDBiblio - Gravacão + + + &Description + &Descrição + + + &Outcue + &Comentário + + + Origin + Origem + + + ISRC + ISRC + + + Weight + Peso + + + Last Played + Última vez Executada + + + # of Plays + # Ao Ar + + + Cut is EVERGREEN + Conteúdo sempre PERMITIDO + + + Air Date/Time + Hora/Data Ar + + + Enabled + Habilitado + + + Disabled + Desabilitado + + + &Start + &Início + + + End + Término + + + Daypart + Hora Ar + + + &Start Time + &Início + + + End Time + Término + + + Day of the Week + Dias da Semana + + + Monday + Segunda + + + Tuesday + Terça + + + Wednesday + Quarta + + + Thursday + Quinta + + + Friday + Sexta + + + Saturday + Sábado + + + Sunday + Domingo + + + Set All + Todos + + + Clear All + Limpar + + + NO SYNC! + SEM SINCRONIA! + + + Channels + Canais + + + Record Mode + Gravação + + + AutoTrim + AutoCorte + + + &Close + &Fechar + + + Manual + Manual + + + VOX + VOZ + + + On + Ligado + + + Off + Desligado + + + Audio Exists + Áudio Existe + + + This will overwrite the existing recording. +Do you want to proceed? + Esta ação sobrescreverá a gravação existente. +Você quer proceder? + + + Empty Clipboard + Esvaziar Clipboard + + + This will empty the clipboard. +Do you still want to proceed? + Esta Ação esvaziará o clipboard. +Você ainda quer proceder? + + + Missing Description + Descrição Faltante + + + You must provide a Cut Description! + Você deve dar descrição ao Conteúdo! + + + Invalid ISRC + ISRC Inválido + + + The ISRC data is malformed or invalid! + Os dados de ISRC está mal formado ou inválido! + + + Invalid Date + Data Inválida + + + The Start Date is invalid! + A Data de Início é inválida! + + + The End Date is invalid! + A Data de Término é inválida! + + + The End Date is prior to the Start Date! + A Data de Término deve vir antes da Data de início! + + + The End Date has already passed! +Do you still want to save? + A Data de Teŕmino já se passou! +Você ainda quer salvar? + + + Invalid Time + Hora Inválida + + + The Start Time is invalid! + A Hora de Início é inválida! + + + The End Time is invalid! + A Hora de Término é inválida! + + + The StartTime cannot be the same as the End Time! + A Hora de início não pode ser a mesma que a Hora de Término! + + + Can't Connect + Não foi possível Conectar + + + Unable to connect to Core AudioEngine + Não foi possível conectar ao Sistema de Áudio + + + &ISCI Code + + + + AES ALARM + + + + diff --git a/rdlibrary/record_cut.cpp b/rdlibrary/record_cut.cpp new file mode 100644 index 00000000..30ef30d7 --- /dev/null +++ b/rdlibrary/record_cut.cpp @@ -0,0 +1,1119 @@ +// record_cut.cpp +// +// Record a Rivendell Cut +// +// (C) Copyright 2002-2004,2014 Fred Gleason +// +// $Id: record_cut.cpp,v 1.90.6.5 2014/01/09 01:11:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +RecordCut::RecordCut(RDCart *cart,QString cut,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + bool valid; + bool is_track=cart->owner().isEmpty(); + bool allow_modification=lib_user->modifyCarts()&&is_track; + bool allow_editing=lib_user->editAudio()&&is_track; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Bold); + small_font.setPixelSize(10); + QFont large_font=QFont("Helvetica",18,QFont::Bold); + large_font.setPixelSize(18); + QFont timer_font=QFont("Helvetica",20,QFont::Bold); + timer_font.setPixelSize(20); + QFont day_font=QFont("helvetica",10,QFont::Normal); + day_font.setPixelSize(10); + + setCaption(tr("RDLibrary - Record")); + rec_cut=new RDCut(cut); + is_playing=false; + is_ready=false; + is_recording=false; + is_closing=false; + rec_timer_value=0; + + // + // Load Audio Assignments + // + rec_card_no[0]=rdlibrary_conf->inputCard(); + rec_port_no[0]=rdlibrary_conf->inputPort(); + rec_card_no[1]=rdlibrary_conf->outputCard(); + rec_port_no[1]=rdlibrary_conf->outputPort(); + rec_play_handle=-1; + + // + // CAE Connection + // + connect(rdcae,SIGNAL(isConnected(bool)),this,SLOT(initData(bool))); + connect(rdcae,SIGNAL(playing(int)),this,SLOT(playedData(int))); + connect(rdcae,SIGNAL(playStopped(int)),this,SLOT(playStoppedData(int))); + connect(rdcae,SIGNAL(recordLoaded(int,int)), + this,SLOT(recordLoadedData(int,int))); + connect(rdcae,SIGNAL(recordUnloaded(int,int,unsigned)), + this,SLOT(recordUnloadedData(int,int,unsigned))); + connect(rdcae,SIGNAL(recording(int,int)),this,SLOT(recordedData(int,int))); + connect(rdcae,SIGNAL(recordStopped(int,int)), + this,SLOT(recordStoppedData(int,int))); + connect(rdcae,SIGNAL(inputStatusChanged(int,int,bool)), + this,SLOT(aesAlarmData(int,int,bool))); + + // + // Audio Parameters + // + rec_card_no[0]=rdlibrary_conf->inputCard(); + rec_card_no[1]=rdlibrary_conf->outputCard(); + rec_name=rec_cut->cutName(); + switch(rec_cut->codingFormat()) { + case 0: + rec_format=RDCae::Pcm16; + break; + + case 1: + rec_format=RDCae::MpegL2; + break; + + default: + rec_format=RDCae::Pcm16; + break; + } + rec_channels=rec_cut->channels(); + rec_samprate=rec_cut->sampleRate(); + rec_bitrate=rec_cut->bitRate(); + rec_length=rec_cut->length(); + + // + // Cut Description + // + cut_description_edit=new QLineEdit(this,"cut_description_edit"); + cut_description_edit->setGeometry(10,30,355,19); + cut_description_edit->setMaxLength(64); + QLabel *cut_description_label=new QLabel(cut_description_edit, + tr("&Description"),this, + "cut_description_label"); + cut_description_label->setGeometry(15,11,120,19); + cut_description_label->setFont(font); + cut_description_label->setAlignment(AlignLeft|ShowPrefix); + + // + // Cut Outcue + // + cut_outcue_edit=new QLineEdit(this,"cut_outcue_edit"); + cut_outcue_edit->setGeometry(10,75,355,19); + cut_outcue_edit->setMaxLength(64); + QLabel *cut_outcue_label=new QLabel(cut_outcue_edit,tr("&Outcue"),this, + "cut_outcue_label"); + cut_outcue_label->setGeometry(15,56,120,19); + cut_outcue_label->setFont(font); + cut_outcue_label->setAlignment(AlignLeft|ShowPrefix); + + // + // Cut ISCI Code + // + cut_isci_edit=new QLineEdit(this,"cut_isci_edit"); + cut_isci_edit->setGeometry(10,120,355,19); + cut_isci_edit->setMaxLength(32); + QLabel *cut_isci_label=new QLabel(cut_isci_edit,tr("&ISCI Code"),this, + "cut_isci_label"); + cut_isci_label->setGeometry(15,101,120,19); + cut_isci_label->setFont(font); + cut_isci_label->setAlignment(AlignLeft|ShowPrefix); + + // + // Cut Origin + // + cut_origin_edit=new QLineEdit(this,"cut_origin_edit"); + cut_origin_edit->setGeometry(10,165,190,19); + cut_origin_edit->setReadOnly(true); + cut_origin_edit->setMaxLength(64); + QLabel *cut_origin_label=new QLabel(cut_origin_edit,tr("Origin"),this, + "cut_origin_label"); + cut_origin_label->setGeometry(15,146,120,19); + cut_origin_label->setFont(font); + cut_origin_label->setAlignment(AlignLeft|ShowPrefix); + + // + // Cut ISRC + // + cut_isrc_edit=new QLineEdit(this,"cut_isrc_edit"); + cut_isrc_edit->setGeometry(220,165,145,19); + cut_isrc_edit->setMaxLength(64); + QLabel *cut_isrc_label=new QLabel(cut_isrc_edit,tr("ISRC"),this, + "cut_isrc_label"); + cut_isrc_label->setGeometry(225,146,120,19); + cut_isrc_label->setFont(font); + cut_isrc_label->setAlignment(AlignLeft|ShowPrefix); + + // + // Cut Weight + // + cut_weight_box=new QSpinBox(this,"cut_weight_box"); + cut_weight_box->setGeometry(10,210,61,19); + cut_weight_box->setRange(0,100); + QLabel *cut_weight_label=new QLabel(cut_weight_box,tr("Weight"),this, + "cut_weight_label"); + cut_weight_label->setGeometry(10,191,61,19); + cut_weight_label->setFont(font); + cut_weight_label->setAlignment(AlignHCenter|ShowPrefix); + + // + // Cut Play Date Time + // + cut_playdate_edit=new QLineEdit(this,"cut_playdate_edit"); + cut_playdate_edit->setGeometry(100,210,150,19); + cut_playdate_edit->setReadOnly(true); + cut_playdate_edit->setMaxLength(64); + QLabel *cut_playdate_label=new QLabel(cut_playdate_edit,tr("Last Played"), + this,"cut_playdate_label"); + cut_playdate_label->setGeometry(105,191,120,19); + cut_playdate_label->setFont(font); + cut_playdate_label->setAlignment(AlignLeft|ShowPrefix); + + // + // Cut Play Counter + // + cut_playcounter_edit=new QLineEdit(this,"cut_playcounter_edit"); + cut_playcounter_edit->setGeometry(285,210,80,19); + cut_playcounter_edit->setAlignment(AlignRight); + cut_playcounter_edit->setReadOnly(true); + cut_playcounter_edit->setMaxLength(64); + QLabel *cut_playcounter_label= + new QLabel(cut_playcounter_edit,tr("# of Plays"), + this,"cut_playcounter_label"); + cut_playcounter_label->setGeometry(290,191,120,19); + cut_playcounter_label->setFont(font); + cut_playcounter_label->setAlignment(AlignLeft|ShowPrefix); + + // + // Evergreen Checkbox + // + rec_evergreen_box=new QCheckBox(this,"rec_evergreen_box"); + rec_evergreen_box->setGeometry(10,245,15,15); + rec_evergreen_label=new QLabel(rec_evergreen_box,tr("Cut is EVERGREEN"), + this,"rec_evergreen_label"); + rec_evergreen_label->setGeometry(30,245,sizeHint().width()-40,15); + rec_evergreen_label->setFont(font); + rec_evergreen_label->setAlignment(AlignVCenter|AlignLeft); + connect(rec_evergreen_box,SIGNAL(toggled(bool)), + this,SLOT(evergreenToggledData(bool))); + + // + // Cut Air Date Times + // + cut_killdatetime_label=new QLabel(tr("Air Date/Time"), + this,"cut_killdatetime_label"); + cut_killdatetime_label->setGeometry(50,268,100,19); + cut_killdatetime_label->setAlignment(Qt::AlignHCenter); + cut_killdatetime_label->setFont(font); + QButtonGroup *button_group=new QButtonGroup(this,"air_dates_group"); + button_group->hide(); + connect(button_group,SIGNAL(clicked(int)),this,SLOT(airDateButtonData(int))); + cut_startdatetime_enable_button=new QRadioButton(tr("Enabled"),this, + "air_date_enabled_button"); + cut_startdatetime_enable_button->setGeometry(40,290,100,20); + button_group->insert(cut_startdatetime_enable_button,true); + cut_startdatetime_disable_button=new QRadioButton(tr("Disabled"),this, + "air_date_disabled_button"); + cut_startdatetime_disable_button->setGeometry(40,310,100,20); + button_group->insert(cut_startdatetime_disable_button,false); + + cut_startdatetime_edit=new QDateTimeEdit(this,"cut_startdatetime_edit"); + cut_startdatetime_edit->setGeometry(165,289,170,19); + cut_startdatetime_label=new QLabel(cut_startdatetime_edit,tr("&Start"),this, + "cut_startdatetime_label"); + cut_startdatetime_label->setGeometry(120,293,40,12); + cut_startdatetime_label->setFont(small_font); + cut_startdatetime_label->setAlignment(AlignRight|ShowPrefix); + + cut_enddatetime_edit=new QDateTimeEdit(this,"cut_enddatetime_edit"); + cut_enddatetime_edit->setGeometry(165,309,170,19); + cut_enddatetime_label=new QLabel(cut_enddatetime_edit,tr("End"),this, + "cut_enddatetime_label"); + cut_enddatetime_label->setGeometry(120,313,40,12); + cut_enddatetime_label->setFont(small_font); + cut_enddatetime_label->setAlignment(AlignRight|ShowPrefix); + + // + // Cut Daypart + // + cut_daypart_label=new QLabel(tr("Daypart"),this); + cut_daypart_label->setGeometry(50,348,65,19); + cut_daypart_label->setAlignment(Qt::AlignHCenter); + cut_daypart_label->setFont(font); + button_group=new QButtonGroup(this,"daypart_group"); + button_group->hide(); + connect(button_group,SIGNAL(clicked(int)),this,SLOT(daypartButtonData(int))); + cut_starttime_enable_button=new QRadioButton(tr("Enabled"),this, + "daypart_enabled_button"); + cut_starttime_enable_button->setGeometry(57,370,100,20); + button_group->insert(cut_starttime_enable_button,true); + cut_starttime_disable_button=new QRadioButton(tr("Disabled"),this, + "daypart_disabled_button"); + cut_starttime_disable_button->setGeometry(57,390,100,20); + button_group->insert(cut_starttime_disable_button,false); + + cut_starttime_edit=new RDTimeEdit(this,"cut_starttime_edit"); + cut_starttime_edit->setGeometry(222,369,90,19); + cut_starttime_label=new QLabel(cut_starttime_edit,tr("&Start Time"),this, + "cut_starttime_label"); + cut_starttime_label->setGeometry(137,373,80,12); + cut_starttime_label->setFont(small_font); + cut_starttime_label->setAlignment(AlignRight|ShowPrefix); + + cut_endtime_edit=new RDTimeEdit(this,"cut_endtime_edit"); + cut_endtime_edit->setGeometry(222,389,90,19); + cut_endtime_label=new QLabel(cut_endtime_edit,tr("End Time"),this, + "cut_endtime_label"); + cut_endtime_label->setGeometry(137,393,80,12); + cut_endtime_label->setFont(small_font); + cut_endtime_label->setAlignment(AlignRight|ShowPrefix); + + // + // Days of the Week + // + rec_dayofweek_label=new QLabel(tr("Day of the Week"),this); + rec_dayofweek_label->setGeometry(50,428,125,19); + rec_dayofweek_label->setAlignment(Qt::AlignHCenter); + rec_dayofweek_label->setFont(font); + rec_weekpart_button[0]=new QCheckBox(this,"cut_weekpart_button[0]"); + rec_weekpart_button[0]->setGeometry(40,447,15,15); + rec_weekpart_label[0]=new QLabel(rec_weekpart_button[0],tr("Monday"), + this,"rec_weekpart_label[0]"); + rec_weekpart_label[0]->setGeometry(62,445,80,20); + rec_weekpart_label[0]->setFont(day_font); + rec_weekpart_label[0]->setAlignment(AlignVCenter|AlignLeft); + + rec_weekpart_button[1]=new QCheckBox(this,"cut_weekpart_button[1]"); + rec_weekpart_button[1]->setGeometry(120,447,15,15); + rec_weekpart_label[1]=new QLabel(rec_weekpart_button[1],tr("Tuesday"), + this,"rec_weekpart_label[0]"); + rec_weekpart_label[1]->setGeometry(142,445,80,20); + rec_weekpart_label[1]->setFont(day_font); + rec_weekpart_label[1]->setAlignment(AlignVCenter|AlignLeft); + + rec_weekpart_button[2]=new QCheckBox(this,"cut_weekpart_button[2]"); + rec_weekpart_button[2]->setGeometry(200,447,15,15); + rec_weekpart_label[2]=new QLabel(rec_weekpart_button[2],tr("Wednesday"), + this,"rec_weekpart_label[0]"); + rec_weekpart_label[2]->setGeometry(222,445,80,20); + rec_weekpart_label[2]->setFont(day_font); + rec_weekpart_label[2]->setAlignment(AlignVCenter|AlignLeft); + + rec_weekpart_button[3]=new QCheckBox(this,"cut_weekpart_button[3]"); + rec_weekpart_button[3]->setGeometry(80,467,15,15); + rec_weekpart_label[3]=new QLabel(rec_weekpart_button[3],tr("Thursday"), + this,"rec_weekpart_label[3]"); + rec_weekpart_label[3]->setGeometry(102,465,80,20); + rec_weekpart_label[3]->setFont(day_font); + rec_weekpart_label[3]->setAlignment(AlignVCenter|AlignLeft); + + rec_weekpart_button[4]=new QCheckBox(this,"cut_weekpart_button[4]"); + rec_weekpart_button[4]->setGeometry(180,467,15,15); + rec_weekpart_label[4]=new QLabel(rec_weekpart_button[4],tr("Friday"), + this,"rec_weekpart_label[4]"); + rec_weekpart_label[4]->setGeometry(202,465,80,20); + rec_weekpart_label[4]->setFont(day_font); + rec_weekpart_label[4]->setAlignment(AlignVCenter|AlignLeft); + + rec_weekpart_button[5]=new QCheckBox(this,"cut_weekpart_button[5]"); + rec_weekpart_button[5]->setGeometry(80,487,15,15); + rec_weekpart_label[5]=new QLabel(rec_weekpart_button[5],tr("Saturday"), + this,"rec_weekpart_label[5]"); + rec_weekpart_label[5]->setGeometry(102,485,80,20); + rec_weekpart_label[5]->setFont(day_font); + rec_weekpart_label[5]->setAlignment(AlignVCenter|AlignLeft); + + rec_weekpart_button[6]=new QCheckBox(this,"cut_weekpart_button[6]"); + rec_weekpart_button[6]->setGeometry(180,485,15,15); + rec_weekpart_label[6]=new QLabel(rec_weekpart_button[6],tr("Sunday"), + this,"rec_weekpart_label[6]"); + rec_weekpart_label[6]->setGeometry(202,485,80,20); + rec_weekpart_label[6]->setFont(day_font); + rec_weekpart_label[6]->setAlignment(AlignVCenter|AlignLeft); + + rec_set_button=new QPushButton(tr("Set All"),this,"rec_set_button"); + rec_set_button->setGeometry(sizeHint().width()-80,441,55,30); + rec_set_button->setFont(small_font); + connect(rec_set_button,SIGNAL(clicked()),this,SLOT(setAllData())); + + rec_clear_button=new QPushButton(tr("Clear All"),this,"rec_clear_button"); + rec_clear_button->setGeometry(sizeHint().width()-80,476,55,30); + rec_clear_button->setFont(small_font); + connect(rec_clear_button,SIGNAL(clicked()),this,SLOT(clearAllData())); + + // + // Audio Meter + // + rec_meter=new RDStereoMeter(this,"rec_meter"); + rec_meter->setGeometry(20,520,rec_meter->geometry().width(), + rec_meter->geometry().height()); + rec_meter->setReference(0); + rec_meter->setMode(RDSegMeter::Independent); + QTimer *timer=new QTimer(this,"meter_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(meterData())); + timer->start(RD_METER_UPDATE_INTERVAL); + + // + // AES Alarm + // + rec_aes_alarm_label=new QLabel(this,"rec_aes_alarm_label"); + rec_aes_alarm_label->setGeometry(15,592,110,22); + rec_aes_alarm_label->setAlignment(AlignHCenter|AlignVCenter); + rec_aes_alarm_label->setFont(large_font); + rec_aes_alarm_label->setPalette(QColor(red)); + rec_aes_alarm_label->setText(tr("AES ALARM")); + rec_aes_alarm_label->hide(); + + // + // Record Timer + // + rec_timer=new QTimer(this,"rec_timer"); + connect(rec_timer,SIGNAL(timeout()),this,SLOT(recTimerData())); + rec_timer_label=new QLabel(this,"rec_timer_label"); + rec_timer_label->setGeometry(130,580,120,50); + rec_timer_label->setFont(timer_font); + rec_timer_label->setAlignment(AlignLeft|AlignVCenter); + rec_timer_label->setText(RDGetTimeLength(rec_length,true)); + + // + // Channels + // + rec_channels_box=new QComboBox(this,"rec_channels_box"); + rec_channels_box->setGeometry(20,635,60,35); + rec_channels_edit=new QLineEdit(this,"rec_channels_box"); + rec_channels_edit->setGeometry(20,635,60,35); + QLabel *rec_channels_box_label=new QLabel(rec_channels_box,tr("Channels"), + this,"rec_channels_box_label"); + rec_channels_box_label->setGeometry(10,616,80,16); + rec_channels_box_label->setAlignment(AlignHCenter); + rec_channels_box_label->setFont(font); + connect(rec_channels_box,SIGNAL(activated(int)), + this,SLOT(channelsData(int))); + + // + // Record Button + // + rec_record_button=new RDTransportButton(RDTransportButton::Record, + this,"rec_record_button"); + rec_record_button->setGeometry(100,620,80,50); + rec_record_button->setDefault(true); + connect(rec_record_button,SIGNAL(clicked()),this,SLOT(recordData())); + + // + // Play Button + // + rec_play_button=new RDTransportButton(RDTransportButton::Play, + this,"rec_play_button"); + rec_play_button->setGeometry(190,620,80,50); + rec_play_button->setDefault(true); + connect(rec_play_button,SIGNAL(clicked()),this,SLOT(playData())); + + // + // Stop Button + // + rec_stop_button=new RDTransportButton(RDTransportButton::Stop, + this,"rec_stop_button"); + rec_stop_button->setGeometry(280,620,80,50); + rec_stop_button->setDefault(true); + rec_stop_button->setState(RDTransportButton::On); + rec_stop_button->setOnColor(QColor(red)); + connect(rec_stop_button,SIGNAL(clicked()),this,SLOT(stopData())); + + // + // Record Mode + // + rec_mode_box=new QComboBox(this,"rec_mode_box"); + rec_mode_box->setGeometry(10,695,100,35); + QLabel *rec_mode_box_label=new QLabel(rec_mode_box,tr("Record Mode"),this, + "rec_mode_box_label"); + rec_mode_box_label->setGeometry(10,676,100,16); + rec_mode_box_label->setAlignment(AlignHCenter); + rec_mode_box_label->setFont(font); + + // + // AutoTrim Mode + // + rec_trim_box=new QComboBox(this,"rec_trim_box"); + rec_trim_box->setGeometry(145,695,70,35); + QLabel *rec_trim_box_label=new QLabel(rec_trim_box,tr("AutoTrim"),this, + "rec_trim_box_label"); + rec_trim_box_label->setGeometry(130,676,100,16); + rec_trim_box_label->setAlignment(AlignHCenter); + rec_trim_box_label->setFont(font); + + // + // Close Button + // + QPushButton *close_button=new QPushButton(this,"close_button"); + close_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + close_button->setDefault(true); + close_button->setFont(font); + close_button->setText(tr("&Close")); + connect(close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Populate Fields + // + cut_description_edit->setText(rec_cut->description()); + cut_outcue_edit->setText(rec_cut->outcue()); + cut_origin_name=rec_cut->originName(); + cut_origin_datetime=rec_cut->originDatetime(&valid); + if(valid) { + cut_origin_edit->setText(cut_origin_name+" - "+ + cut_origin_datetime.toString("M/d/yyyy hh:mm:ss")); + } + cut_isci_edit->setText(rec_cut->isci()); + cut_isrc_edit->setText(rec_cut->isrc(RDCut::FormattedIsrc)); + cut_weight_box->setValue(rec_cut->weight()); + if(rec_cut->playCounter()>0) { + cut_playdate_edit-> + setText(rec_cut->lastPlayDatetime(&valid).toString("M/d/yyyy hh:mm:ss")); + } + else { + cut_playdate_edit->setText("Never"); + } + cut_playcounter_edit-> + setText(QString().sprintf("%d",rec_cut->playCounter())); + rec_evergreen_box->setChecked(rec_cut->evergreen()); + evergreenToggledData(rec_evergreen_box->isChecked()); + cut_startdatetime_edit->setDateTime(rec_cut->startDatetime(&valid)); + cut_enddatetime_edit->setDateTime(rec_cut->endDatetime(&valid)); + cut_startdatetime_enable_button->setChecked(valid); + cut_startdatetime_disable_button->setChecked(!valid); + airDateButtonData(valid); + cut_starttime_edit->setTime(rec_cut->startDaypart(&valid)); + cut_endtime_edit->setTime(rec_cut->endDaypart(&valid)); + cut_starttime_enable_button->setChecked(valid); + cut_starttime_disable_button->setChecked(!valid); + daypartButtonData(valid); + for(int i=0;i<7;i++) { + if(rec_cut->weekPart(i+1)) { + rec_weekpart_button[i]->setChecked(true); + } + } + rec_channels_box->insertItem("1"); + rec_channels_box->insertItem("2"); + rec_channels_box->setCurrentItem(rec_cut->channels()-1); + rec_channels_edit->setText(QString().sprintf("%d",rec_cut->channels())); + rec_mode_box->insertItem(tr("Manual")); + rec_mode_box->insertItem(tr("VOX")); + switch(rdlibrary_conf->defaultRecordMode()) { + case RDLibraryConf::Manual: + rec_mode_box->setCurrentItem(0); + break; + + case RDLibraryConf::Vox: + rec_mode_box->setCurrentItem(1); + break; + } + rec_trim_box->insertItem(tr("On")); + rec_trim_box->insertItem(tr("Off")); + if(rdlibrary_conf->defaultTrimState()) { + rec_trim_box->setCurrentItem(0); + } + else { + rec_trim_box->setCurrentItem(1); + } + aesAlarmData(rec_card_no[0],rec_port_no[0], + rdcae->inputStatus(rec_card_no[0],rec_port_no[0])); + + // + // Set Control Perms + // + cut_description_edit->setReadOnly(!allow_modification); + cut_outcue_edit->setReadOnly(!allow_modification); + cut_isci_edit->setReadOnly(!allow_modification); + cut_starttime_edit->setReadOnly(!allow_modification); + cut_endtime_edit->setReadOnly(!allow_modification); + if(!allow_modification) { + cut_weight_box->setRange(cut_weight_box->value(),cut_weight_box->value()); + if(cut_startdatetime_enable_button->isChecked()) { + cut_startdatetime_edit->dateEdit()-> + setRange(cut_startdatetime_edit->dateEdit()->date(), + cut_startdatetime_edit->dateEdit()->date()); + cut_startdatetime_edit->timeEdit()-> + setRange(cut_startdatetime_edit->timeEdit()->time(), + cut_startdatetime_edit->timeEdit()->time()); + cut_enddatetime_edit->dateEdit()-> + setRange(cut_enddatetime_edit->dateEdit()->date(), + cut_enddatetime_edit->dateEdit()->date()); + } + if(cut_starttime_enable_button->isChecked()) { + cut_enddatetime_edit->timeEdit()-> + setRange(cut_enddatetime_edit->timeEdit()->time(), + cut_enddatetime_edit->timeEdit()->time()); + } + } + rec_evergreen_box->setEnabled(allow_modification); + if(!allow_modification) { + cut_startdatetime_enable_button->setDisabled(true); + cut_startdatetime_disable_button->setDisabled(true); + cut_starttime_enable_button->setDisabled(true); + cut_starttime_disable_button->setDisabled(true); + rec_set_button->setDisabled(true); + rec_clear_button->setDisabled(true); + } + for(int i=0;i<7;i++) { + rec_weekpart_button[i]->setEnabled(allow_modification); + } + rec_record_button-> + setEnabled(allow_editing&&(rec_card_no[0]>=0)&&(rec_port_no[0]>=0)); + rec_mode_box->setEnabled(allow_editing); + rec_trim_box->setEnabled(allow_editing); + if(allow_editing) { + rec_channels_edit->hide(); + } + else { + rec_channels_box->hide(); + } +} + + +RecordCut::~RecordCut() +{ + delete rec_meter; + delete cut_description_edit; + delete cut_outcue_edit; + delete rec_timer; + delete rec_record_button; + delete rec_play_button; + delete rec_stop_button; +} + +QSize RecordCut::sizeHint() const +{ + return QSize(375,740); +} + + +QSizePolicy RecordCut::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RecordCut::airDateButtonData(int id) +{ + bool valid; + QDateTime datetime; + + cut_startdatetime_edit->setEnabled(id); + cut_startdatetime_label->setEnabled(id); + cut_enddatetime_edit->setEnabled(id); + cut_enddatetime_label->setEnabled(id); + if(id) { + datetime=rec_cut->startDatetime(&valid); + if(valid&&(!datetime.isNull())) { + cut_startdatetime_edit->setDateTime(datetime); + cut_enddatetime_edit->setDateTime(rec_cut->endDatetime(&valid)); + } + else { + cut_startdatetime_edit-> + setDateTime(QDateTime(QDate::currentDate(),QTime())); + cut_enddatetime_edit-> + setDateTime(QDateTime(QDate::currentDate(),QTime(23,59,59))); + } + } +} + + +void RecordCut::daypartButtonData(int id) +{ + cut_starttime_edit->setEnabled(id); + cut_starttime_label->setEnabled(id); + cut_endtime_edit->setEnabled(id); + cut_endtime_label->setEnabled(id); +} + + +void RecordCut::setAllData() +{ + for(int i=0;i<7;i++) { + rec_weekpart_button[i]->setChecked(true); + } +} + + +void RecordCut::clearAllData() +{ + for(int i=0;i<7;i++) { + rec_weekpart_button[i]->setChecked(false); + } +} + + +void RecordCut::channelsData(int id) +{ + rec_channels=id+1; +} + + +void RecordCut::recordData() +{ + // QString filename; + + if((!is_ready)&&(!is_recording)&&(!is_playing)) { + if(rec_cut->length()>0) { + if(QMessageBox::warning(this,tr("Audio Exists"), + tr("This will overwrite the existing recording.\nDo you want to proceed?"), + QMessageBox::Yes, + QMessageBox::No)==QMessageBox::No) { + return; + } + if(cut_clipboard!=NULL) { + if(rec_cut->cutName()==cut_clipboard->cutName()) { + if(QMessageBox::warning(this,tr("Empty Clipboard"), + tr("This will empty the clipboard.\nDo you still want to proceed?"), + QMessageBox::Yes, + QMessageBox::No)==QMessageBox::No) { + return; + } + delete cut_clipboard; + cut_clipboard=NULL; + } + } + } + RDCart *cart=new RDCart(rec_cut->cartNumber()); + cart->removeCutAudio(rdstation_conf,lib_user,rec_cut->cutName(),lib_config); + delete cart; + switch(rdlibrary_conf->defaultFormat()) { + case 0: + rec_cut->setCodingFormat(0); + rec_format=RDCae::Pcm16; + break; + + case 1: + rec_cut->setCodingFormat(1); + rec_format=RDCae::MpegL2; + break; + + default: + rec_cut->setCodingFormat(0); + rec_format=RDCae::Pcm16; + break; + } + rec_samprate=lib_system->sampleRate(); + rec_cut->setSampleRate(rec_samprate); + rec_bitrate=rdlibrary_conf->defaultBitrate(); + rec_cut->setBitRate(rec_bitrate); + rec_channels=rec_channels_box->currentItem()+1; + rec_cut->setChannels(rec_channels); + rec_cut->setOriginDatetime(QDateTime::currentDateTime()); + rec_cut->setOriginName(rdstation_conf->name()); + cut_origin_name=rdstation_conf->name(); + cut_origin_datetime=QDateTime::currentDateTime(); + cut_origin_edit->setText(cut_origin_name+" - "+ + cut_origin_datetime.toString("M/d/yyyy hh:mm:ss")); + rdcae->loadRecord(rec_card_no[0],rec_port_no[0],rec_name,rec_format, + rec_channels,rec_samprate,rec_bitrate*rec_channels); + } +} + + +void RecordCut::playData() +{ + int start=rec_cut->startPoint(true); + int end=rec_cut->endPoint(true); + + if((!is_recording)&&(!is_playing)&&(!is_ready)) { // Start Play + rdcae->loadPlay(rec_card_no[1],rec_cut->cutName(), + &rec_stream_no[1],&rec_play_handle); + RDSetMixerOutputPort(rdcae,rec_card_no[1],rec_stream_no[1],rec_port_no[1]); + rdcae->positionPlay(rec_play_handle,start); + rdcae->setPlayPortActive(rec_card_no[1],rec_port_no[1],rec_stream_no[1]); + rdcae->setOutputVolume(rec_card_no[1],rec_stream_no[1],rec_port_no[1], + 0+rec_cut->playGain()); + rdcae->play(rec_play_handle,end-start,RD_TIMESCALE_DIVISOR,false); + } + if(is_ready&&(!is_recording)) { + if(rec_mode_box->currentItem()==1) { + rdcae-> + record(rec_card_no[0],rec_port_no[0],rdlibrary_conf->maxLength(), + rdlibrary_conf->voxThreshold()); + } + else { + rdcae-> + record(rec_card_no[0],rec_port_no[0],rdlibrary_conf->maxLength(),0); + } + } +} + + +void RecordCut::stopData() +{ + if(is_playing) { + rdcae->stopPlay(rec_play_handle); + return; + } + if(is_recording) { + rdcae->stopRecord(rec_card_no[0],rec_port_no[0]); + return; + } + if(is_ready) { + rdcae->unloadRecord(rec_card_no[0],rec_port_no[0]); + rec_record_button->off(); + rec_play_button->off(); + rec_stop_button->on(); + is_ready=false; + } +} + + +void RecordCut::recordLoadedData(int card,int stream) +{ + rec_timer_value=-1; + recTimerData(); + rec_record_button->on(); + rec_play_button->flash(); + rec_stop_button->off(); + is_ready=true; + is_recording=false; +} + + +void RecordCut::recordedData(int card,int stream) +{ + rec_timer->start(RECORD_CUT_TIMER_INTERVAL); + rec_play_button->on(); + is_ready=false; + is_recording=true; +} + + +void RecordCut::playedData(int handle) +{ + rec_play_button->on(); + rec_stop_button->off(); + rec_timer_value=-1; + recTimerData(); + rec_timer->start(RECORD_CUT_TIMER_INTERVAL); + is_playing=true; + is_recording=false; +} + + +void RecordCut::playStoppedData(int handle) +{ + rdcae->unloadPlay(rec_play_handle); + rec_timer->stop(); + rec_play_button->off(); + rec_stop_button->on(); + rec_meter->resetClipLight(); + is_playing=false; + is_recording=false; + rec_meter->setLeftSolidBar(-10000); + rec_meter->setRightSolidBar(-10000); + if(is_closing) { + is_closing=false; + closeData(); + } +} + + +void RecordCut::recordStoppedData(int card,int stream) +{ + //printf("recordStoppedData()\n"); + rdcae->unloadRecord(rec_card_no[0],rec_port_no[0]); + rec_timer->stop(); + rec_play_button->off(); + rec_stop_button->on(); + rec_record_button->off(); + rec_meter->resetClipLight(); + is_playing=false; + is_recording=false; +} + + +void RecordCut::recordUnloadedData(int card,int stream,unsigned len) +{ + //printf("recordUnloadedData(%d,%d,%u)\n",card,stream,len); + QString filename; + + rec_meter->setLeftSolidBar(-100000); + rec_meter->setRightSolidBar(-100000); + + RDSettings *s=new RDSettings(); + s->setSampleRate(rec_samprate); + s->setBitRate(rec_bitrate); + s->setChannels(rec_channels); + s->setFormat((RDSettings::Format)rec_format); + rec_cut->checkInRecording(rdstation_conf->name(),s,len); + if(rec_trim_box->currentItem()==0) { + rec_cut->autoTrim(RDCut::AudioBoth,rdlibrary_conf->trimThreshold()); + } + rec_length=rec_cut->length(); + if(is_closing) { + is_closing=false; + closeData(); + } +} + + +void RecordCut::closeData() +{ + if(cut_description_edit->text().isEmpty()) { + QMessageBox::information(this,tr("Missing Description"), + tr("You must provide a Cut Description!"), + QMessageBox::Ok); + return; + } + QString isrc=cut_isrc_edit->text(); + if(!isrc.isEmpty()) { + isrc.remove("-"); + if(isrc.length()!=12) { + QMessageBox::information(this,tr("Invalid ISRC"), + tr("The ISRC data is malformed or invalid!"), + QMessageBox::Ok); + return; + } + } + rec_cut->setEvergreen(rec_evergreen_box->isChecked()); + if(cut_startdatetime_enable_button->isChecked()) { + if(!cut_startdatetime_edit->dateTime().isValid()) { + QMessageBox::warning(this,tr("Invalid Date"), + tr("The Start Date is invalid!")); + return; + } + if(!cut_enddatetime_edit->dateTime().isValid()) { + QMessageBox::warning(this,tr("Invalid Date"), + tr("The End Date is invalid!")); + return; + } + if(cut_enddatetime_edit->dateTime()dateTime()) { + QMessageBox::warning(this,tr("Invalid Date"), + tr("The End Date is prior to the Start Date!")); + return; + } + if((cut_enddatetime_edit->dateTime()isChecked())) { + switch(QMessageBox::warning(this,tr("Invalid Date"), + tr("The End Date has already passed!\nDo you still want to save?"), + QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::No: + case QMessageBox::NoButton: + return; + + default: + break; + } + } + } + if(cut_starttime_enable_button->isChecked()) { + if(!cut_starttime_edit->time().isValid()) { + QMessageBox::warning(this,tr("Invalid Time"), + tr("The Start Time is invalid!")); + return; + } + if(!cut_endtime_edit->time().isValid()) { + QMessageBox::warning(this,tr("Invalid Time"), + tr("The End Time is invalid!")); + return; + } + if(cut_endtime_edit->time()==cut_starttime_edit->time()) { + QMessageBox::warning(this,tr("Invalid Time"), + tr("The StartTime cannot be the same as the End Time!")); + return; + } + } + if(is_playing||is_recording||is_ready) { + stopData(); + is_closing=true; + return; + } + if((cut_startdatetime_enable_button->isChecked())&& + (cut_startdatetime_edit->dateTime().time().isNull())) { + rec_cut-> + setStartDatetime(QDateTime(cut_startdatetime_edit->dateTime().date(), + cut_startdatetime_edit->dateTime().time(). + addMSecs(1)),true); + } + else { + rec_cut->setStartDatetime(cut_startdatetime_edit->dateTime(), + cut_startdatetime_enable_button->isChecked()); + } + if((cut_startdatetime_enable_button->isChecked())&& + (cut_enddatetime_edit->dateTime().time().isNull())) { + rec_cut-> + setEndDatetime(QDateTime(cut_enddatetime_edit->dateTime().date(), + cut_enddatetime_edit->dateTime().time(). + addMSecs(1)),true); + } + else { + rec_cut->setEndDatetime(cut_enddatetime_edit->dateTime(), + cut_startdatetime_enable_button->isChecked()); + } + rec_cut->setStartDaypart(cut_starttime_edit->time(), + cut_starttime_enable_button->isChecked()); + rec_cut->setEndDaypart(cut_endtime_edit->time(), + cut_starttime_enable_button->isChecked()); + for(int i=0;i<7;i++) { + rec_cut->setWeekPart(i+1,rec_weekpart_button[i]->isChecked()); + } + rec_cut->setDescription(cut_description_edit->text()); + rec_cut->setOutcue(cut_outcue_edit->text()); + rec_cut->setIsrc(isrc); + rec_cut->setIsci(cut_isci_edit->text()); + rec_cut->setWeight(cut_weight_box->value()); + rec_cut->setLength(rec_length); + RDCart *cart=new RDCart(rec_cut->cartNumber()); + cart->resetRotation(); + delete cart; + done(0); +} + + +void RecordCut::initData(bool state) +{ + if(!state) { + QMessageBox::warning(this,tr("Can't Connect"), + tr("Unable to connect to Core AudioEngine")); + exit(1); + } +} + + +void RecordCut::recTimerData() +{ + rec_timer_value+=RECORD_CUT_TIMER_INTERVAL; + rec_timer_label->setText(RDGetTimeLength(rec_timer_value,true)); +} + + +void RecordCut::aesAlarmData(int card,int port,bool state) +{ + if((card==rdlibrary_conf->inputCard())&& + (port==rdlibrary_conf->inputPort())) { + if(rdaudioport_conf->inputPortType(rdlibrary_conf->inputPort())!= + RDAudioPort::Analog) { + if(state) { + rec_aes_alarm_label->hide(); + } + else { + rec_aes_alarm_label->show(); + } + } + } +} + + +void RecordCut::meterData() +{ + short levels[2]; + + if(is_ready||is_recording) { + rdcae->inputMeterUpdate(rec_card_no[0],rec_port_no[0],levels); + rec_meter->setLeftSolidBar(levels[0]); + rec_meter->setRightSolidBar(levels[1]); + } + if(is_playing) { + rdcae->outputMeterUpdate(rec_card_no[1],rec_port_no[1],levels); + rec_meter->setLeftSolidBar(levels[0]); + rec_meter->setRightSolidBar(levels[1]); + } +} + + +void RecordCut::evergreenToggledData(bool state) +{ + cut_killdatetime_label->setDisabled(state); + cut_startdatetime_enable_button->setDisabled(state); + cut_startdatetime_disable_button->setDisabled(state); + cut_startdatetime_label->setDisabled(state); + cut_startdatetime_edit->setDisabled(state); + cut_enddatetime_edit->setDisabled(state); + cut_enddatetime_label->setDisabled(state); + cut_daypart_label->setDisabled(state); + cut_starttime_enable_button->setDisabled(state); + cut_starttime_disable_button->setDisabled(state); + cut_starttime_edit->setDisabled(state); + cut_starttime_label->setDisabled(state); + cut_endtime_edit->setDisabled(state); + cut_endtime_label->setDisabled(state); + rec_dayofweek_label->setDisabled(state); + for(int i=0;i<7;i++) { + rec_weekpart_button[i]->setDisabled(state); + rec_weekpart_label[i]->setDisabled(state); + } + rec_set_button->setDisabled(state); + rec_clear_button->setDisabled(state); + if (!state) { + airDateButtonData(cut_startdatetime_enable_button->isChecked()); + daypartButtonData(cut_starttime_enable_button->isChecked()); + } + + update(); +} + + +void RecordCut::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + if(rec_evergreen_box->isChecked()) { + p->setPen(palette().color(QPalette::Disabled,QColorGroup::Foreground)); + } + else { + p->setPen(palette().color(QPalette::Active,QColorGroup::Foreground)); + } + p->drawRect(30,275,sizeHint().width()-60,60); + p->drawRect(37,355,sizeHint().width()-74,60); + p->drawRect(20,436,sizeHint().width()-40,75); + p->end(); +} + + +void RecordCut::closeEvent(QCloseEvent *e) +{ + closeData(); +} + + +void RecordCut::AutoTrim(RDWaveFile *name) +{ + if(name->hasEnergy()) { + rec_cut->setStartPoint(name->startTrim(rdlibrary_conf->trimThreshold())); + rec_cut->setEndPoint(name->endTrim(rdlibrary_conf->trimThreshold())); + } +} diff --git a/rdlibrary/record_cut.h b/rdlibrary/record_cut.h new file mode 100644 index 00000000..3091a6ff --- /dev/null +++ b/rdlibrary/record_cut.h @@ -0,0 +1,148 @@ +// record_cut.h +// +// Record a Rivendell cut. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: record_cut.h,v 1.33.6.1 2012/08/02 20:37:58 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RECORD_CUT_H +#define RECORD_CUT_H + +#define RECORD_CUT_TIMER_INTERVAL 100 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + + +class RecordCut : public QDialog +{ + Q_OBJECT + public: + RecordCut(RDCart *cart,QString cut,QWidget *parent=0,const char *name=0); + ~RecordCut(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void airDateButtonData(int); + void daypartButtonData(int); + void setAllData(); + void clearAllData(); + void channelsData(int); + void recordData(); + void playData(); + void stopData(); + void recordLoadedData(int,int); + void recordedData(int,int); + void recordStoppedData(int,int); + void recordUnloadedData(int,int,unsigned); + void playedData(int); + void playStoppedData(int); + void closeData(); + void initData(bool); + void recTimerData(); + void aesAlarmData(int,int,bool); + void meterData(); + void evergreenToggledData(bool); + + protected: + void paintEvent(QPaintEvent *e); + void closeEvent(QCloseEvent *e); + + private: + void AutoTrim(RDWaveFile *name); + RDCut *rec_cut; + unsigned rec_length; + QString cut_origin_name; + QDateTime cut_origin_datetime; + QLineEdit *cut_description_edit; + QLineEdit *cut_outcue_edit; + QLineEdit *cut_origin_edit; + QLineEdit *cut_isrc_edit; + QLineEdit *cut_isci_edit; + QSpinBox *cut_weight_box; + QLineEdit *cut_playdate_edit; + QLineEdit *cut_playcounter_edit; + QLabel *cut_killdatetime_label; + QRadioButton *cut_startdatetime_enable_button; + QRadioButton *cut_startdatetime_disable_button; + QLabel *cut_startdatetime_label; + QDateTimeEdit *cut_startdatetime_edit; + QLabel *cut_enddatetime_label; + QDateTimeEdit *cut_enddatetime_edit; + QLabel *cut_daypart_label; + QRadioButton *cut_starttime_enable_button; + QRadioButton *cut_starttime_disable_button; + RDTimeEdit *cut_starttime_edit; + QLabel *cut_starttime_label; + RDTimeEdit *cut_endtime_edit; + QLabel *cut_endtime_label; + QTimer *rec_timer; + QLabel *rec_timer_label; + QLabel *rec_aes_alarm_label; + int rec_timer_value; + RDTransportButton *rec_record_button; + RDTransportButton *rec_play_button; + RDTransportButton *rec_stop_button; + RDStereoMeter *rec_meter; + QString rec_name; + QComboBox *rec_channels_box; + QLineEdit *rec_channels_edit; + QComboBox *rec_mode_box; + QComboBox *rec_trim_box; + QLabel *rec_dayofweek_label; + QPushButton *rec_set_button; + QPushButton *rec_clear_button; + QCheckBox *rec_weekpart_button[7]; + QLabel *rec_weekpart_label[7]; + int rec_card_no[2]; + int rec_stream_no[2]; + int rec_port_no[2]; + int rec_play_handle; + RDCae::AudioCoding rec_format; + unsigned rec_channels; + unsigned rec_samprate; + unsigned rec_bitrate; + bool is_playing; + bool is_ready; + bool is_recording; + bool is_closing; + QCheckBox *rec_evergreen_box; + QLabel *rec_evergreen_label; +}; + + +#endif + diff --git a/rdlibrary/validate_cut.cpp b/rdlibrary/validate_cut.cpp new file mode 100644 index 00000000..bfcc8672 --- /dev/null +++ b/rdlibrary/validate_cut.cpp @@ -0,0 +1,77 @@ +// validate_cut.cpp +// +// Validate a Rivendell Audio Cut +// +// (C) Copyright 2006 Fred Gleason +// +// $Id: validate_cut.cpp,v 1.4.16.2 2014/05/22 19:37:45 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +QString ValidateCutFields() +{ + QString sql; + + sql=QString("select WEIGHT,DESCRIPTION,LENGTH,LAST_PLAY_DATETIME,")+ + "PLAY_COUNTER,ORIGIN_DATETIME,ORIGIN_NAME,OUTCUE,CUT_NAME,LENGTH,"+ + "EVERGREEN,START_DATETIME,END_DATETIME,START_DAYPART,END_DAYPART,"+ + "MON,TUE,WED,THU,FRI,SAT,SUN from CUTS"; + + return sql; +} + + +RDCart::Validity ValidateCut(RDSqlQuery *q,unsigned offset, + RDCart::Validity prev_validity, + const QDateTime &datetime) +{ + if(prev_validity==RDCart::AlwaysValid) { + return RDCart::AlwaysValid; + } + if(q->value(offset).toInt()==0) { // Length + return prev_validity; + } + if(q->value(offset+1).toString()=="Y") { // Evergreen + return RDCart::EvergreenValid; + } + if(q->value(offset+5+datetime.date().dayOfWeek()).toString()!="Y") { + return prev_validity; + } + if(!q->value(offset+2).isNull()) { // Start DateTime + if(q->value(offset+2).toDateTime()>datetime) { + return RDCart::FutureValid; + } + } + if(!q->value(offset+3).isNull()) { // End DateTime + if(q->value(offset+3).toDateTime()value(offset+4).isNull()) { // Start Daypart + if(q->value(offset+4).toTime()>datetime.time()) { + return prev_validity; + } + } + if(!q->value(offset+5).isNull()) { // End Daypart + if(q->value(offset+5).toTime() +// +// $Id: validate_cut.h,v 1.5.10.1 2014/05/22 14:30:46 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef VALIDATE_CUT_H +#define VALIDATE_CUT_H + +#include +#include + +#include + +QString ValidateCutFields(); +RDCart::Validity ValidateCut(RDSqlQuery *q,unsigned offset, + RDCart::Validity prev_validity, + const QDateTime &datetime); + +#endif // VALIDATE_CUT_H diff --git a/rdlogedit/Makefile.am b/rdlogedit/Makefile.am new file mode 100644 index 00000000..69dea6e5 --- /dev/null +++ b/rdlogedit/Makefile.am @@ -0,0 +1,99 @@ +## automake.am +## +## Automake.am for rivendell/rdlogedit +## +## Use automake to process this into a Makefile.in +## +## (C) Copyright 2002-2005 Fred Gleason +## +## $Id: Makefile.am,v 1.37.8.4 2013/12/27 22:12:28 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdlogedit_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rdlogedit_*.qm + +all: + @QT_BIN@/lupdate rdlogedit.pro + @QT_BIN@/lrelease rdlogedit.pro + +bin_PROGRAMS = rdlogedit + +dist_rdlogedit_SOURCES = add_meta.cpp add_meta.h\ + drop_listview.cpp drop_listview.h\ + edit_chain.cpp edit_chain.h\ + edit_log.cpp edit_log.h\ + edit_logline.cpp edit_logline.h\ + edit_marker.cpp edit_marker.h\ + edit_track.cpp edit_track.h\ + import_track.cpp import_track.h\ + list_listviewitem.cpp list_listviewitem.h\ + list_reports.cpp list_reports.h\ + list_logs.cpp list_logs.h\ + log_listview.cpp log_listview.h\ + rdlogedit.cpp rdlogedit.h globals.h\ + voice_tracker.cpp voice_tracker.h + +nodist_rdlogedit_SOURCES = moc_add_meta.cpp\ + moc_drop_listview.cpp\ + moc_edit_chain.cpp\ + moc_edit_log.cpp\ + moc_edit_logline.cpp\ + moc_edit_marker.cpp\ + moc_edit_track.cpp\ + moc_import_track.cpp\ + moc_list_logs.cpp\ + moc_list_reports.cpp\ + moc_log_listview.cpp\ + moc_rdlogedit.cpp\ + moc_voice_tracker.cpp + +rdlogedit_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdlogedit.pro\ + rdlogedit_cs.ts\ + rdlogedit_de.ts\ + rdlogedit_es.ts\ + rdlogedit_fr.ts\ + rdlogedit_nb.ts\ + rdlogedit_nn.ts\ + rdlogedit_pt_BR.ts + +CLEANFILES = *~\ + *.exe\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/rdlogedit/add_meta.cpp b/rdlogedit/add_meta.cpp new file mode 100644 index 00000000..0aba30a2 --- /dev/null +++ b/rdlogedit/add_meta.cpp @@ -0,0 +1,154 @@ +// add_meta.cpp +// +// Add a Rivendell RDCatch Event +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: add_meta.cpp,v 1.9 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +AddMeta::AddMeta(QWidget *parent,const char *name) + : QDialog(parent,name,true,Qt::WStyle_Customize|Qt::WStyle_DialogBorder) +{ + setCaption(""); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont day_font=QFont("Helvetica",12,QFont::Normal); + day_font.setPixelSize(12); + + // + // Title Label + // + QLabel *label=new QLabel(tr("Insert a:"),this,"title_label"); + label->setGeometry(0,0,sizeHint().width(),30); + label->setFont(label_font); + label->setAlignment(AlignCenter); + + // + // Marker Button + // + QPushButton *button=new QPushButton(this,"marker_button"); + button->setGeometry(10,30,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("&Marker")); + connect(button,SIGNAL(clicked()),this,SLOT(markerData())); + + // + // Voice Track Button + // + button=new QPushButton(this,"track_button"); + button->setGeometry(10,80,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("Voice &Track")); + connect(button,SIGNAL(clicked()),this,SLOT(trackData())); + + // + // Chain Button + // + button=new QPushButton(this,"chain_button"); + button->setGeometry(10,130,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("Log C&hain")); + connect(button,SIGNAL(clicked()),this,SLOT(chainData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(10,sizeHint().height()-60,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + button->setDefault(true); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +AddMeta::~AddMeta() +{ +} + + +QSize AddMeta::sizeHint() const +{ + return QSize(200,240); +} + + +QSizePolicy AddMeta::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddMeta::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void AddMeta::markerData() +{ + done(RDLogLine::Marker); +} + + +void AddMeta::chainData() +{ + done(RDLogLine::Chain); +} + + +void AddMeta::trackData() +{ + done(RDLogLine::Track); +} + + +void AddMeta::cancelData() +{ + done(-1); +} diff --git a/rdlogedit/add_meta.h b/rdlogedit/add_meta.h new file mode 100644 index 00000000..6f186b3d --- /dev/null +++ b/rdlogedit/add_meta.h @@ -0,0 +1,57 @@ +// add_meta.h +// +// Add a Rivendell RDCatch Event +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: add_meta.h,v 1.6 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_META_H +#define ADD_META_H + +#include +#include +#include +#include +#include +#include +#include +#include + + +class AddMeta : public QDialog +{ + Q_OBJECT + public: + AddMeta(QWidget *parent=0,const char *name=0); + ~AddMeta(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + void closeEvent(QCloseEvent *e); + + private slots: + void markerData(); + void chainData(); + void trackData(); + void cancelData(); +}; + + +#endif + diff --git a/rdlogedit/drop_listview.cpp b/rdlogedit/drop_listview.cpp new file mode 100644 index 00000000..d14bb3ee --- /dev/null +++ b/rdlogedit/drop_listview.cpp @@ -0,0 +1,56 @@ +// drop_listview.cpp +// +// The Log ListView widget for RDLogEdit. +// +// (C) Copyright 2002-2013 Fred Gleason +// +// $Id: drop_listview.cpp,v 1.1.2.1 2013/12/27 22:12:28 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include + +#include + +#include + +DropListView::DropListView(QWidget *parent,const char *name) + : RDListView(parent,name) +{ + setAcceptDrops(true); +} + + +void DropListView::dragEnterEvent(QDragEnterEvent *e) +{ + e->accept(RDCartDrag::canDecode(e)); +} + + +void DropListView::dropEvent(QDropEvent *e) +{ + RDLogLine ll; + int line=-1; + QPoint pos(e->pos().x(),e->pos().y()-header()->sectionRect(0).height()); + + if(RDCartDrag::decode(e,&ll)) { + RDListViewItem *item=(RDListViewItem *)itemAt(pos); + if(item!=NULL) { + line=item->text(13).toInt(); + } + emit cartDropped(line,&ll); + } +} diff --git a/rdlogedit/drop_listview.h b/rdlogedit/drop_listview.h new file mode 100644 index 00000000..65b1e4e0 --- /dev/null +++ b/rdlogedit/drop_listview.h @@ -0,0 +1,45 @@ +// drop_listview.h +// +// The Log ListView widget for RDLogEdit. +// +// (C) Copyright 2002-2013 Fred Gleason +// +// $Id: drop_listview.h,v 1.1.2.1 2013/12/27 22:12:28 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef DROP_LISTVIEW_H +#define DROP_LISTVIEW_H + +#include +#include + +class DropListView : public RDListView +{ + Q_OBJECT + public: + DropListView(QWidget *parent,const char *name=0); + + signals: + void cartDropped(int line,RDLogLine *ll); + + protected: + void dragEnterEvent(QDragEnterEvent *e); + void dropEvent(QDropEvent *e); +}; + + +#endif // DROP_LISTVIEW_H diff --git a/rdlogedit/edit_chain.cpp b/rdlogedit/edit_chain.cpp new file mode 100644 index 00000000..01edf9e2 --- /dev/null +++ b/rdlogedit/edit_chain.cpp @@ -0,0 +1,362 @@ +// edit_chain.cpp +// +// Edit a Rivendell Log Chain Entry +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_chain.cpp,v 1.14 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +EditChain::EditChain(RDLogLine *line,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Edit Log Chain")); + + edit_logline=line; + + // + // Create Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont radio_font=QFont("Helvetica",10,QFont::Normal); + radio_font.setPixelSize(10); + + // + // Time Type + // + edit_timetype_box=new QCheckBox(this,"edit_timetype_box"); + edit_timetype_box->setGeometry(10,22,15,15); + edit_timetype_label=new QLabel(edit_timetype_box,tr("Start at:"), + this,"edit_timetype_label"); + edit_timetype_label->setGeometry(30,21,85,17); + edit_timetype_label->setFont(label_font); + edit_timetype_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Start Time + // + edit_time_edit=new RDTimeEdit(this,"edit_time_edit"); + edit_time_edit->setGeometry(85,19,85,20); + edit_time_edit->setDisplay(RDTimeEdit::Hours|RDTimeEdit::Minutes| + RDTimeEdit::Seconds|RDTimeEdit::Tenths); + connect(edit_time_edit,SIGNAL(valueChanged(const QTime &)), + this,SLOT(timeChangedData(const QTime &))); + + // + // Grace Time + // + edit_grace_group + =new QButtonGroup(1,Qt::Vertical, + tr("Action If Previous Event Still Playing"), + this,"edit_grace_group"); + edit_grace_group->setGeometry(175,11,435,50); + edit_grace_group->setFont(label_font); + edit_grace_group->setRadioButtonExclusive(true); + QRadioButton *radio_button= + new QRadioButton(tr("Start Immediately"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + radio_button=new QRadioButton(tr("Make Next"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + radio_button=new QRadioButton(tr("Wait up to"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + edit_grace_box=new QTimeEdit(this,"edit_grace_box"); + edit_grace_box->setGeometry(543,31,60,20); + edit_grace_box->setDisplay(QTimeEdit::Minutes|QTimeEdit::Seconds); + connect(edit_timetype_box,SIGNAL(toggled(bool)), + this,SLOT(timeToggledData(bool))); + connect(edit_grace_group,SIGNAL(clicked(int)), + this,SLOT(graceClickedData(int))); + + // + // Transition Type + // + edit_transtype_box=new QComboBox(this,"edit_transtype_box"); + edit_transtype_box->setGeometry(385,68,110,26); + edit_transtype_box->insertItem(tr("Play")); + edit_transtype_box->insertItem(tr("Segue")); + edit_transtype_box->insertItem(tr("Stop")); + edit_time_label=new QLabel(edit_transtype_box,tr("Transition Type:"), + this,"edit_transtype_label"); + edit_time_label->setGeometry(10,68,370,26); + edit_time_label->setFont(label_font); + edit_time_label->setAlignment(AlignRight|AlignVCenter); + + // + // Label + // + edit_label_edit=new QLineEdit(this,"edit_label_edit"); + edit_label_edit->setGeometry(10,116,sizeHint().width()-90,18); + edit_label_edit->setMaxLength(64); + QLabel *label=new QLabel(tr("Log Name"),this,"label_label"); + label->setFont(label_font); + label->setGeometry(12,100,160,14); + connect(edit_label_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(labelChangedData(const QString &))); + + // + // Select Log Button + // + QPushButton *button=new QPushButton(this,"select_button"); + button->setGeometry(sizeHint().width()-70,111,60,28); + button->setDefault(true); + button->setFont(radio_font); + button->setText(tr("Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectLogData())); + + // + // Comment + // + edit_comment_edit=new QLineEdit(this,"edit_comment_edit"); + edit_comment_edit->setGeometry(10,156,sizeHint().width()-20,18); + edit_comment_edit->setReadOnly(true); + label=new QLabel(tr("Log Description"),this,"comment_label"); + label->setFont(label_font); + label->setGeometry(12,140,160,14); + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(button_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + edit_time_edit->setTime(edit_logline->startTime(RDLogLine::Logged)); + if(edit_logline->timeType()==RDLogLine::Hard) { + edit_timetype_box->setChecked(true); + timeToggledData(true); + } + else { + timeToggledData(false); + } + timeChangedData(edit_time_edit->time()); + switch(edit_logline->graceTime()) { + case -1: + edit_grace_group->setButton(1); + graceClickedData(1); + break; + + case 0: + edit_grace_group->setButton(0); + graceClickedData(0); + break; + + default: + edit_grace_group->setButton(2); + edit_grace_box->setTime(QTime().addMSecs(edit_logline->graceTime())); + //edit_grace_box->setValue(edit_logline->graceTime()); + graceClickedData(2); + break; + } + edit_transtype_box->setCurrentItem(edit_logline->transType()); + edit_label_edit->setText(edit_logline->markerLabel()); + labelChangedData(edit_label_edit->text()); +} + + +EditChain::~EditChain() +{ +} + + +QSize EditChain::sizeHint() const +{ + return QSize(625,260); +} + + +QSizePolicy EditChain::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditChain::timeChangedData(const QTime &time) +{ + QString str; + + if(edit_timetype_box->isChecked()) { + str=QString(tr("Transition If Previous Cart Ends Before")); + edit_time_label-> + setText(QString().sprintf("%s %s:",(const char *)str, + (const char *)edit_time_edit->time(). + toString("hh:mm:ss.zzz").left(10))); + } +} + + +void EditChain::timeToggledData(bool state) +{ + QString str; + + edit_time_edit->setEnabled(state); + edit_grace_group->setEnabled(state); + if(state) { + graceClickedData(edit_grace_group->selectedId()); + str=QString(tr("Transition If Previous Cart Ends Before")); + edit_time_label-> + setText(QString().sprintf("%s %s:",(const char *)str, + (const char *)edit_time_edit->time(). + toString("hh:mm:ss.zzz").left(10))); + } + else { + edit_grace_box->setDisabled(true); + edit_time_label->setText(tr("Transition Type:")); + } +} + + +void EditChain::graceClickedData(int id) +{ + switch(id) { + case 0: + edit_grace_box->setDisabled(true); + break; + + case 1: + edit_grace_box->setDisabled(true); + break; + + case 2: + edit_grace_box->setEnabled(true); + break; + } +} + + +void EditChain::selectTimeData(int id) +{ + if(id==RDLogLine::Relative) { + edit_time_edit->setDisabled(true); + edit_time_label->setDisabled(true); + edit_grace_box->setDisabled(true); + } + else { + edit_time_edit->setEnabled(true); + edit_time_label->setEnabled(true); + } +} + + +void EditChain::selectLogData() +{ + QString logname; + + ListLogs *list=new ListLogs(&logname,this,"list_log_dialog"); + if(list->exec()<0) { + delete list; + return; + } + delete list; + edit_label_edit->setText(logname); + labelChangedData(logname); +} + + +void EditChain::labelChangedData(const QString &logname) +{ + QString sql= + QString().sprintf("select DESCRIPTION from LOGS where NAME=\"%s\"", + (const char *)logname); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + edit_comment_edit->clear(); + return; + } + edit_comment_edit->setText(q->value(0).toString()); + delete q; +} + + +void EditChain::okData() +{ + if(edit_timetype_box->isChecked()) { + edit_logline->setTimeType(RDLogLine::Hard); + edit_logline->setStartTime(RDLogLine::Logged,edit_time_edit->time()); + switch(edit_grace_group->selectedId()) { + case 0: + edit_logline->setGraceTime(0); + break; + + case 1: + edit_logline->setGraceTime(-1); + break; + + case 2: + edit_logline->setGraceTime(QTime().msecsTo(edit_grace_box->time())); + //edit_logline->setGraceTime(edit_grace_box->value()); + break; + } + } + else { + edit_logline->setTimeType(RDLogLine::Relative); + edit_logline->setStartTime(RDLogLine::Logged,QTime()); + edit_logline->setGraceTime(0); + } + edit_logline-> + setTransType((RDLogLine::TransType)edit_transtype_box->currentItem()); + edit_logline->setMarkerLabel(edit_label_edit->text()); + edit_logline->setMarkerComment(edit_comment_edit->text()); + done(edit_logline->id()); +} + + +void EditChain::cancelData() +{ + done(-1); +} + + +void EditChain::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/rdlogedit/edit_chain.h b/rdlogedit/edit_chain.h new file mode 100644 index 00000000..191b335f --- /dev/null +++ b/rdlogedit/edit_chain.h @@ -0,0 +1,78 @@ +// edit_chain.h +// +// Edit a Rivendell Log Entry +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: edit_chain.h,v 1.8 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_CHAIN_H +#define EDIT_CHAIN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class EditChain : public QDialog +{ + Q_OBJECT + public: + EditChain(RDLogLine *,QWidget *parent=0,const char *name=0); + ~EditChain(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void timeChangedData(const QTime &); + void timeToggledData(bool state); + void graceClickedData(int id); + void selectTimeData(int); + void selectLogData(); + void labelChangedData(const QString &); + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + RDLogLine *edit_logline; + RDTimeEdit *edit_time_edit; + QLabel *edit_time_label; + QCheckBox *edit_timetype_box; + QLabel *edit_timetype_label; + QCheckBox *edit_time_box; + QComboBox *edit_transtype_box; + QLineEdit *edit_comment_edit; + QLineEdit *edit_label_edit; + QButtonGroup *edit_grace_group; + QFont normal_font; + QTimeEdit *edit_grace_box; +}; + + +#endif + diff --git a/rdlogedit/edit_log.cpp b/rdlogedit/edit_log.cpp new file mode 100644 index 00000000..90024214 --- /dev/null +++ b/rdlogedit/edit_log.cpp @@ -0,0 +1,1748 @@ +// edit_log.cpp +// +// Edit a Rivendell Log +// +// (C) Copyright 2002-2008 Fred Gleason +// +// $Id: edit_log.cpp,v 1.91.6.10.2.2 2014/05/22 16:12:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// +// Icons +// +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" +#include "../icons/marker.xpm" +#include "../icons/chain.xpm" +#include "../icons/track_cart.xpm" +#include "../icons/notemarker.xpm" +#include "../icons/music.xpm" +#include "../icons/mic16.xpm" +#include "../icons/traffic.xpm" + +EditLog::EditLog(QString logname,vector *clipboard, + vector *new_logs,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + QStringList services_list; + + edit_logname=logname; + edit_clipboard=clipboard; + edit_newlogs=new_logs; + edit_default_trans=RDLogLine::Play; + bool adding_allowed=rduser->addtoLog(); + bool deleting_allowed=rduser->removefromLog(); + bool editing_allowed=rduser->arrangeLog(); + bool saveas_allowed=rduser->createLog(); + + setCaption(tr("Edit Log")); + + // + // Config Data + // + edit_default_trans=rdlogedit_conf->defaultTransType(); + edit_output_card=rdlogedit_conf->outputCard(); + edit_output_port=rdlogedit_conf->outputPort(); + edit_start_macro=rdlogedit_conf->startCart(); + edit_end_macro=rdlogedit_conf->endCart(); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont title_font=QFont("Helvetica",12,QFont::Normal); + title_font.setPixelSize(12); + QFont length_font=QFont("Helvetica",10,QFont::Bold); + length_font.setPixelSize(10); + + + // + // Create Icons + // + edit_playout_map=new QPixmap(play_xpm); + edit_macro_map=new QPixmap(rml5_xpm); + edit_marker_map=new QPixmap(marker_xpm); + edit_chain_map=new QPixmap(chain_xpm); + edit_track_cart_map=new QPixmap(track_cart_xpm); + edit_notemarker_map=new QPixmap(notemarker_xpm); + edit_music_map=new QPixmap(music_xpm); + edit_mic16_map=new QPixmap(mic16_xpm); + edit_traffic_map=new QPixmap(traffic_xpm); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Log Header + // + edit_log=new RDLog(edit_logname,false); + + // + // Log Events + // + edit_log_event=new RDLogEvent(RDLog::tableName(edit_logname)); + edit_log_event->load(true); + + // + // Log Name + // + edit_logname_label=new QLabel(logname,this,"edit_logname_label"); + edit_logname_label->setBackgroundColor(QColor(lightGray)); + edit_logname_label->setAlignment(AlignLeft|AlignVCenter); + edit_logname_label->setFont(title_font); + edit_logname_label_label=new QLabel(tr("Log Name:"), + this,"edit_logname_label_label"); + edit_logname_label_label->setBackgroundColor(QColor(lightGray)); + edit_logname_label_label->setFont(label_font); + edit_logname_label_label->setAlignment(AlignRight|AlignVCenter); + + // + // Track Counts + // + edit_track_label=new QLabel(this,"edit_track_label"); + edit_track_label->setBackgroundColor(QColor(lightGray)); + edit_track_label->setAlignment(AlignLeft|AlignVCenter); + edit_track_label->setFont(title_font); + edit_track_label_label=new QLabel(tr("Tracks:"), + this,"edit_track_label_label"); + edit_track_label_label->setBackgroundColor(QColor(lightGray)); + edit_track_label_label->setFont(label_font); + edit_track_label_label->setAlignment(AlignRight|AlignVCenter); + + // + // Log Origin + // + edit_origin_label=new QLabel(edit_log->originUser()+QString(" - ")+ + edit_log->originDatetime().toString("MM/dd/yyyy - hh:mm:ss"), + this,"edit_origin_label"); + edit_origin_label->setBackgroundColor(QColor(lightGray)); + edit_origin_label->setAlignment(AlignLeft|AlignVCenter); + edit_origin_label->setFont(title_font); + edit_origin_label_label=new QLabel(tr("Origin:"), + this,"edit_origin_label_label"); + edit_origin_label_label->setBackgroundColor(QColor(lightGray)); + edit_origin_label_label->setFont(label_font); + edit_origin_label_label->setAlignment(AlignRight|AlignVCenter); + + // + // Description + // + edit_description_edit=new QLineEdit(this,"edit_description_edit"); + edit_description_edit->setValidator(validator); + connect(edit_description_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(descriptionChangedData(const QString &))); + edit_description_label=new QLabel(edit_description_edit,tr("Description:"), + this,"edit_description_label"); + edit_description_label->setFont(label_font); + edit_description_label->setAlignment(AlignRight|AlignVCenter); + + // + // Purge Date + // + edit_purgedate_box=new QCheckBox(this,"edit_purgedate_box"); + edit_purgedate_label=new QLabel(edit_purgedate_box,tr("Delete on"), + this,"edit_purgedate_label"); + edit_purgedate_label->setFont(label_font); + edit_purgedate_label->setAlignment(AlignRight|AlignVCenter); + edit_purgedate_edit=new QDateEdit(this,"edit_purgedate_edit"); + edit_purgedate_button= + new QPushButton(tr("Select"),this,"edit_purgedate_button"); + edit_purgedate_button->setFont(label_font); + connect(edit_purgedate_box,SIGNAL(toggled(bool)), + edit_purgedate_edit,SLOT(setEnabled(bool))); + connect(edit_purgedate_box,SIGNAL(toggled(bool)), + edit_purgedate_button,SLOT(setEnabled(bool))); + connect(edit_purgedate_button,SIGNAL(clicked()), + this,SLOT(selectPurgeDateData())); + + // + // Service + // + edit_service_box=new QComboBox(this,"edit_service_box"); + edit_service_edit=new QLineEdit(this,"edit_service_edit"); + edit_service_edit->setReadOnly(true); + edit_service_label=new QLabel(edit_service_box,tr("Service:"), + this,"edit_service_label"); + edit_service_label->setFont(label_font); + edit_service_label->setAlignment(AlignRight|AlignVCenter); + connect(edit_service_box,SIGNAL(activated(const QString &)), + this,SLOT(serviceActivatedData(const QString &))); + + // + // Auto Refresh + // + edit_autorefresh_box=new QComboBox(this,"edit_autorefresh_box"); + edit_autorefresh_box->insertItem(tr("Yes")); + edit_autorefresh_box->insertItem(tr("No")); + edit_autorefresh_edit=new QLineEdit(this,"edit_autorefresh_edit"); + edit_autorefresh_edit->setReadOnly(true); + edit_autorefresh_label= + new QLabel(edit_autorefresh_box,tr("Enable AutoRefresh:"), + this,"edit_autorefresh_label"); + edit_autorefresh_label->setFont(label_font); + edit_autorefresh_label->setAlignment(AlignRight|AlignVCenter); + + // + // Start Date + // + edit_startdate_edit=new QDateEdit(this,"edit_startdate_edit"); + edit_startdate_label=new QLabel(edit_startdate_edit,tr("Start Date:"),this, + "edit_startdate_label"); + edit_startdate_label->setFont(label_font); + edit_startdate_label->setAlignment(AlignRight|AlignVCenter); + connect(edit_startdate_edit,SIGNAL(valueChanged(const QDate &)), + this,SLOT(dateValueChangedData(const QDate &))); + + + // + // End Date + // + edit_enddate_edit=new QDateEdit(this,"edit_enddate_edit"); + edit_enddate_label=new QLabel(edit_startdate_edit,tr("End Date:"), + this,"edit_enddate_label"); + edit_enddate_label->setFont(label_font); + edit_enddate_label->setAlignment(AlignRight|AlignVCenter); + connect(edit_enddate_edit,SIGNAL(valueChanged(const QDate &)), + this,SLOT(dateValueChangedData(const QDate &))); + + // + // Start Date Checkbox + // + edit_startdate_box=new QCheckBox(this,"edit_startdate_box"); + connect(edit_startdate_box,SIGNAL(toggled(bool)), + this,SLOT(startDateEnabledData(bool))); + edit_startdate_box_label=new QLabel(edit_startdate_box, + tr("Start Date Enabled"),this); + edit_startdate_box_label->setFont(label_font); + edit_startdate_box_label->setAlignment(AlignLeft|AlignVCenter); + + // + // End Date Checkbox + // + edit_enddate_box=new QCheckBox(this,"edit_enddate_box"); + connect(edit_enddate_box,SIGNAL(toggled(bool)), + this,SLOT(endDateEnabledData(bool))); + edit_enddate_box_label=new QLabel(edit_enddate_box,tr("End Date Enabled"), + this); + edit_enddate_box_label->setFont(label_font); + edit_enddate_box_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Time Counter Section + // + edit_time_label=new QLabel(tr("Run Length"),this); + edit_time_label->setFont(label_font); + edit_time_label->setAlignment(AlignCenter); + + // + // Stop Time Counter + // + edit_stoptime_edit=new QLineEdit(this,"edit_stoptime_edit"); + edit_stoptime_label=new QLabel(edit_stoptime_edit,tr("Next Stop:"),this); + edit_stoptime_label->setFont(label_font); + edit_stoptime_label->setAlignment(AlignRight|AlignVCenter); + + // + // End Time Counter + // + edit_endtime_edit=new QLineEdit(this,"edit_endtime_edit"); + edit_endtime_label=new QLabel(edit_endtime_edit,tr("Log End:"),this); + edit_endtime_label->setFont(label_font); + edit_endtime_label->setAlignment(AlignRight|AlignVCenter); + + // + // Log Event List + // + edit_log_list=new DropListView(this,"edit_log_list"); + edit_log_list->setAllColumnsShowFocus(true); + edit_log_list->setSelectionMode(QListView::Extended); + edit_log_list->setItemMargin(5); + //edit_log_list->setSorting(-1); + edit_log_list->addColumn(""); + edit_log_list->setColumnAlignment(0,Qt::AlignHCenter); + edit_log_list->addColumn(tr("TIME")); + edit_log_list->setColumnAlignment(1,Qt::AlignRight); + edit_log_list->addColumn(tr("TRANS")); + edit_log_list->setColumnAlignment(2,Qt::AlignHCenter); + edit_log_list->addColumn(tr("CART")); + edit_log_list->setColumnAlignment(3,Qt::AlignHCenter); + edit_log_list->addColumn(tr("GROUP")); + edit_log_list->setColumnAlignment(4,Qt::AlignHCenter); + edit_log_list->addColumn(tr("LENGTH")); + edit_log_list->setColumnAlignment(5,Qt::AlignRight); + edit_log_list->addColumn(tr("TITLE")); + edit_log_list->setColumnAlignment(6,Qt::AlignLeft); + edit_log_list->addColumn(tr("ARTIST")); + edit_log_list->setColumnAlignment(7,Qt::AlignLeft); + edit_log_list->addColumn(tr("CLIENT")); + edit_log_list->setColumnAlignment(8,Qt::AlignLeft); + edit_log_list->addColumn(tr("AGENCY")); + edit_log_list->setColumnAlignment(9,Qt::AlignLeft); + edit_log_list->addColumn(tr("LABEL")); + edit_log_list->setColumnAlignment(10,Qt::AlignHCenter); + edit_log_list->addColumn(tr("SOURCE")); + edit_log_list->setColumnAlignment(11,Qt::AlignHCenter); + edit_log_list->addColumn(tr("LINE ID")); + edit_log_list->setColumnAlignment(12,Qt::AlignHCenter); + edit_log_list->addColumn(tr("COUNT")); + edit_log_list->setColumnAlignment(13,Qt::AlignHCenter); + edit_log_list->setHardSortColumn(13); + edit_log_list->setColumnSortType(13,RDListView::LineSort); + if(editing_allowed) { + connect(edit_log_list,SIGNAL(doubleClicked(QListViewItem *)), + this,SLOT(doubleClickData(QListViewItem *))); + connect(edit_log_list,SIGNAL(cartDropped(int,RDLogLine *)), + this,SLOT(cartDroppedData(int,RDLogLine *))); + } + connect(edit_log_list,SIGNAL(clicked(QListViewItem *)), + this,SLOT(clickedData(QListViewItem *))); + connect(edit_log_list,SIGNAL(selectionChanged()), + this,SLOT(selectionChangedData())); + + // + // Insert Cart Button + // + edit_cart_button=new QPushButton(this,"edit_cart_button"); + edit_cart_button->setPalette(QPalette(backgroundColor(),QColor(lightGray))); + edit_cart_button->setFont(button_font); + edit_cart_button->setText(tr("Insert\nCart")); + connect(edit_cart_button,SIGNAL(clicked()), + this,SLOT(insertCartButtonData())); + + // + // Insert Marker Button + // + edit_marker_button=new QPushButton(this,"edit_marker_button"); + edit_marker_button-> + setPalette(QPalette(backgroundColor(),QColor(lightGray))); + edit_marker_button->setFont(button_font); + edit_marker_button->setText(tr("Insert\nMeta")); + connect(edit_marker_button,SIGNAL(clicked()), + this,SLOT(insertMarkerButtonData())); + + // + // Edit Button + // + edit_edit_button=new QPushButton(this,"edit_edit_button"); + edit_edit_button->setPalette(QPalette(backgroundColor(),QColor(lightGray))); + edit_edit_button->setFont(button_font); + edit_edit_button->setText(tr("Edit")); + connect(edit_edit_button,SIGNAL(clicked()),this,SLOT(editButtonData())); + + // + // Delete Button + // + edit_delete_button=new QPushButton(this,"edit_delete_button"); + edit_delete_button-> + setPalette(QPalette(backgroundColor(),QColor(lightGray))); + edit_delete_button->setFont(button_font); + edit_delete_button->setText(tr("Delete")); + connect(edit_delete_button,SIGNAL(clicked()),this,SLOT(deleteButtonData())); + + // + // Up Button + // + edit_up_button=new RDTransportButton(RDTransportButton::Up, + this,"delete_button"); + edit_up_button->setPalette(QPalette(backgroundColor(),QColor(lightGray))); + connect(edit_up_button,SIGNAL(clicked()),this,SLOT(upButtonData())); + + // + // Down Button + // + edit_down_button=new RDTransportButton(RDTransportButton::Down, + this,"delete_button"); + edit_down_button->setPalette(QPalette(backgroundColor(),QColor(lightGray))); + connect(edit_down_button,SIGNAL(clicked()),this,SLOT(downButtonData())); + + // + // Cut Button + // + edit_cut_button=new QPushButton(this,"edit_cut_button"); + edit_cut_button->setPalette(QPalette(backgroundColor(),QColor(lightGray))); + edit_cut_button->setFont(button_font); + edit_cut_button->setText(tr("Cut")); + connect(edit_cut_button,SIGNAL(clicked()),this,SLOT(cutButtonData())); + + // + // Copy Button + // + edit_copy_button=new QPushButton(this,"edit_copy_button"); + edit_copy_button->setPalette(QPalette(backgroundColor(),QColor(lightGray))); + edit_copy_button->setFont(button_font); + edit_copy_button->setText(tr("Copy")); + connect(edit_copy_button,SIGNAL(clicked()),this,SLOT(copyButtonData())); + + // + // Paste Button + // + edit_paste_button=new QPushButton(this,"edit_paste_button"); + edit_paste_button->setPalette(QPalette(backgroundColor(),QColor(lightGray))); + edit_paste_button->setFont(button_font); + edit_paste_button->setText(tr("Paste")); + connect(edit_paste_button,SIGNAL(clicked()),this,SLOT(pasteButtonData())); + + // + // Save Button + // + edit_save_button=new QPushButton(this,"edit_save_button"); + edit_save_button->setFont(button_font); + edit_save_button->setText(tr("&Save")); + connect(edit_save_button,SIGNAL(clicked()),this,SLOT(saveData())); + + // + // SaveAs Button + // + edit_saveas_button=new QPushButton(this,"edit_saveas_button"); + edit_saveas_button->setFont(button_font); + edit_saveas_button->setText(tr("Save\n&As")); + connect(edit_saveas_button,SIGNAL(clicked()),this,SLOT(saveasData())); + + // + // Reports Button + // + edit_reports_button=new QPushButton(this,"edit_reports_button"); + edit_reports_button->setFont(button_font); + edit_reports_button->setText(tr("&Reports")); + connect(edit_reports_button,SIGNAL(clicked()),this,SLOT(reportsData())); + + // + // Cart Player + // +#ifdef WIN32 + edit_player=NULL; +#else + edit_player= + new RDSimplePlayer(rdcae,rdripc,edit_output_card,edit_output_port, + edit_start_macro,edit_end_macro,this,"edit_player"); + edit_player->playButton()-> + setPalette(QPalette(backgroundColor(),QColor(lightGray))); + edit_player->stopButton()-> + setPalette(QPalette(backgroundColor(),QColor(lightGray))); + edit_player->stopButton()->setOnColor(red); +#endif // WIN32 + + // + // Ok Button + // + edit_ok_button=new QPushButton(this,"edit_ok_button"); + edit_ok_button->setDefault(true); + edit_ok_button->setFont(button_font); + edit_ok_button->setText(tr("&OK")); + connect(edit_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + edit_cancel_button=new QPushButton(this,"edit_cancel_button"); + edit_cancel_button->setFont(button_font); + edit_cancel_button->setText(tr("&Cancel")); + connect(edit_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + edit_description_edit->setText(edit_log->description()); + + QDate purge_date=edit_log->purgeDate(); + if(purge_date.isNull()) { + edit_purgedate_edit->setDate(QDate::currentDate().addMonths(1)); + edit_purgedate_edit->setDisabled(true); + edit_purgedate_button->setDisabled(true); + } + else { + edit_purgedate_box->setChecked(true); + edit_purgedate_edit->setDate(purge_date); + } + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec) { + services_list = rduser->services(); + } else { // RDStation::HostSec + sql=QString("select NAME from SERVICES"); + q=new RDSqlQuery(sql); + while(q->next()) { + services_list.append( q->value(0).toString() ); + } + delete q; + } + int n=-1; + int ncounter=0; + QString service=edit_log->service(); + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end(); ++it ) { + edit_service_box->insertItem(*it); + if(*it==service) { + n=ncounter; + edit_service_edit->setText(*it); + } + ncounter++; + } + if(n>=0) { + edit_service_box->setCurrentItem(n); + } + if(edit_log->autoRefresh()) { + edit_autorefresh_box->setCurrentItem(0); + edit_autorefresh_edit->setText(tr("Yes")); + } + else { + edit_autorefresh_box->setCurrentItem(1); + edit_autorefresh_edit->setText(tr("No")); + } + if(!edit_log->startDate().isNull()) { + edit_startdate_box->setChecked(true); + edit_startdate_edit->setDate(edit_log->startDate()); + } + else { + edit_startdate_edit->setDisabled(true); + edit_startdate_label->setDisabled(true); + edit_startdate_box->setChecked(false); + } + if(!edit_log->endDate().isNull()) { + edit_enddate_box->setChecked(true); + edit_enddate_edit->setDate(edit_log->endDate()); + } + else { + edit_enddate_edit->setDisabled(true); + edit_enddate_label->setDisabled(true); + edit_enddate_box->setChecked(false); + } + RefreshList(); + serviceActivatedData(edit_service_box->currentText()); + edit_changed=false; + UpdateTracks(); + + // + // Set Control Perms + // + edit_description_edit->setReadOnly(!editing_allowed); + if(saveas_allowed) { + edit_service_edit->hide(); + edit_autorefresh_edit->hide(); + } + else { + edit_service_box->hide(); + edit_autorefresh_box->hide(); + } + if(!editing_allowed) { + if(edit_startdate_box->isChecked()) { + edit_startdate_edit->setRange(edit_startdate_edit->date(), + edit_startdate_edit->date()); + } + if(edit_enddate_box->isChecked()) { + edit_enddate_edit->setRange(edit_enddate_edit->date(), + edit_enddate_edit->date()); + } + } + edit_startdate_box->setEnabled(editing_allowed); + edit_enddate_box->setEnabled(editing_allowed); + edit_startdate_box->setEnabled(editing_allowed); + edit_enddate_box->setEnabled(editing_allowed); + edit_cart_button->setEnabled(adding_allowed&&editing_allowed); + edit_marker_button->setEnabled(adding_allowed&&editing_allowed); + edit_edit_button->setEnabled(editing_allowed&&editing_allowed); + edit_delete_button->setEnabled(deleting_allowed&&editing_allowed); + edit_up_button->setEnabled(editing_allowed); + edit_down_button->setEnabled(editing_allowed); + edit_cut_button-> + setEnabled(adding_allowed&&deleting_allowed&&editing_allowed); + edit_copy_button->setEnabled(adding_allowed&&editing_allowed); + edit_paste_button->setEnabled(adding_allowed&&editing_allowed); + edit_saveas_button->setEnabled(saveas_allowed); +} + + +EditLog::~EditLog() +{ +} + + +QSize EditLog::sizeHint() const +{ + return QSize(800,600); +} + + +QSizePolicy EditLog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditLog::descriptionChangedData(const QString &) +{ + edit_changed=true; +} + + +void EditLog::selectPurgeDateData() +{ + QDate date=edit_purgedate_edit->date(); + RDDateDialog *d=new RDDateDialog(2008,QDate::currentDate().year()+5,this); + if(d->exec(&date)==0) { + edit_purgedate_edit->setDate(date); + edit_changed=true; + } +} + + +void EditLog::serviceActivatedData(const QString &svcname) +{ + edit_changed=true; + edit_group_list.loadSvc(svcname); + if(!ValidateSvc()) { + QMessageBox::warning(this,tr("Invalid Carts"), + tr("This log contains one or more carts\nthat are invalid for the selected service!")); + } +} + + +void EditLog::startDateEnabledData(bool state) +{ + if(state) { + edit_startdate_edit->setDate(QDate::currentDate()); + } + edit_startdate_edit->setEnabled(state); + edit_startdate_label->setEnabled(state); + edit_changed=true; +} + + +void EditLog::endDateEnabledData(bool state) +{ + if(state) { + edit_enddate_edit->setDate(QDate::currentDate()); + } + edit_enddate_edit->setEnabled(state); + edit_enddate_label->setEnabled(state); + edit_changed=true; +} + + +void EditLog::dateValueChangedData(const QDate &) +{ + edit_changed=true; +} + + +void EditLog::insertCartButtonData() +{ + int line; + int id; + + QListViewItem *item=SingleSelection(); + if(item==NULL) { + return; + } + if((line=item->text(13).toInt())<0) { + line=0; + } + id=item->text(12).toInt(); + edit_log_event->insert(line,1); + edit_log_event->logLine(line)->setTransType(edit_default_trans); + edit_log_event->logLine(line)->setFadeupGain(-3000); + edit_log_event->logLine(line)->setFadedownGain(-3000); + EditLogLine *edit=new EditLogLine(edit_log_event->logLine(line), + &edit_filter,&edit_group, + edit_service_box->currentText(), + &edit_group_list,edit_log_event,line, + this,"edit_logline"); + int ret=edit->exec(); + if(ret>=0) { + edit_log_event->refresh(line); + edit_changed=true; + } + else { + edit_log_event->remove(line,1); + delete edit; + return; + } + delete edit; + RefreshList(); + SelectRecord(id); + UpdateSelection(); +} + + +void EditLog::insertMarkerButtonData() +{ + int line; + int id; + int ret; + EditMarker *edit_marker; + EditTrack *edit_track; + EditChain *edit_chain; + + QListViewItem *item=SingleSelection(); + if(item==NULL) { + return; + } + line=item->text(13).toInt(); + id=item->text(12).toInt(); + AddMeta *meta=new AddMeta(this,"add_meta_dialog"); + switch((RDLogLine::Type)meta->exec()) { + case RDLogLine::Marker: + edit_log_event->insert(line,1); + edit_log_event->logLine(line)->setType(RDLogLine::Marker); + edit_marker=new EditMarker(edit_log_event->logLine(line), + this,"edit_marker"); + ret=edit_marker->exec(); + if(ret>=0) { + edit_log_event->refresh(line); + edit_changed=true; + } + else { + edit_log_event->remove(line,1); + } + delete edit_marker; + break; + + case RDLogLine::Track: + edit_log_event->insert(line,1); + edit_log_event->logLine(line)->setType(RDLogLine::Track); + edit_log_event->logLine(line)->setTransType(RDLogLine::Segue); + edit_log_event->logLine(line)->setMarkerComment(tr("Voice Track")); + edit_track=new EditTrack(edit_log_event->logLine(line), + this,"edit_marker"); + ret=edit_track->exec(); + if(ret>=0) { + edit_log_event->refresh(line); + edit_changed=true; + } + else { + edit_log_event->remove(line,1); + } + delete edit_track; + break; + + case RDLogLine::Chain: + edit_log_event->insert(line,1); + edit_log_event->logLine(line)->setType(RDLogLine::Chain); + edit_chain=new EditChain(edit_log_event->logLine(line), + this,"edit_marker"); + ret=edit_chain->exec(); + if(ret>=0) { + edit_log_event->refresh(line); + edit_changed=true; + } + else { + edit_log_event->remove(line,1); + } + delete edit_chain; + break; + + default: + break; + } + RefreshList(); + UpdateTracks(); + SelectRecord(id); + UpdateSelection(); +} + + +void EditLog::clickedData(QListViewItem *item) +{ +#ifndef WIN32 + RDListViewItem *rditem=SingleSelection(); + if(rditem==NULL) { + edit_player->setCart(0); + return; + } + else { + edit_player->setCart(rditem->text(3).toUInt()); + } +#endif // WIN32 +} + + +void EditLog::selectionChangedData() +{ + UpdateSelection(); +} + + +void EditLog::doubleClickData(QListViewItem *item) +{ + editButtonData(); +} + + +void EditLog::editButtonData() +{ + EditLogLine *edit_cart; + EditMarker *edit_marker; + EditTrack *edit_track; + EditChain *edit_chain; + + RDListViewItem *item=SingleSelection(); + if(item==NULL) { + return; + } + int id=item->text(12).toInt(); + int line=item->text(13).toInt(); + if(id==END_MARKER_ID) { + return; + } + switch(edit_log_event->logLine(line)->type()) { + case RDLogLine::Cart: + case RDLogLine::Macro: + edit_cart=new EditLogLine(edit_log_event->logLine(line),& + edit_filter,&edit_group, + edit_service_box->currentText(), + &edit_group_list,edit_log_event,line, + this,"edit_logline"); + if(edit_cart->exec()>=0) { + edit_log_event->refresh(item->text(13).toInt()); + edit_changed=true; + } + delete edit_cart; + break; + + case RDLogLine::Marker: + edit_marker=new EditMarker(edit_log_event->logLine(line), + this,"edit_logline"); + if(edit_marker->exec()>=0) { + edit_changed=true; + } + delete edit_marker; + break; + + case RDLogLine::Track: + edit_track=new EditTrack(edit_log_event->logLine(line), + this,"edit_logline"); + if(edit_track->exec()>=0) { + edit_changed=true; + } + delete edit_track; + break; + + case RDLogLine::Chain: + edit_chain=new EditChain(edit_log_event->logLine(line), + this,"edit_logline"); + if(edit_chain->exec()>=0) { + edit_changed=true; + } + delete edit_chain; + break; + + default: + break; + } + RefreshList(); + SelectRecord(id); + UpdateSelection(); +} + + +void EditLog::deleteButtonData() +{ + int count=0; + + QListViewItem *next=edit_log_list->firstChild(); + QListViewItem *item=NULL; + int line=0; + bool select_end=false; + + while(next!=NULL) { + if(edit_log_list->isSelected(next)) { + if(next->text(12).toInt()!=END_MARKER_ID) { + if(count==0) { + line=next->text(13).toInt(); + item=next; + } + count++; + if(next->text(13).toInt()==edit_log_event->size()-1) { + select_end=true; + } + item=next->nextSibling(); + } + } + next=next->nextSibling(); + } + DeleteLines(line,count); +} + + +void EditLog::upButtonData() +{ + QListViewItem *item=SingleSelection(); + if((item==NULL)||(item->text(13).toInt()==0)|| + (item->text(12).toInt()==END_MARKER_ID)) { + return; + } + int id=item->text(12).toInt(); + sscanf((const char *)item->text(12),"%u",&id); + edit_log_event->move(item->text(13).toInt(), + item->text(13).toInt()-1); + edit_changed=true; + RefreshList(); + SelectRecord(id); + UpdateSelection(); +} + + +void EditLog::downButtonData() +{ + QListViewItem *item=SingleSelection(); + + if((item==NULL)||(item->text(13).toInt()==(edit_log_list->childCount()-2))|| + (item->text(12).toInt()==END_MARKER_ID)) { + return; + } + int id=item->text(12).toInt(); + edit_log_event->move(item->text(13).toInt(), + item->text(13).toInt()+1); + edit_changed=true; + RefreshList(); + SelectRecord(id); + UpdateSelection(); +} + + +void EditLog::cutButtonData() +{ + copyButtonData(); + deleteButtonData(); + UpdateTracks(); + UpdateSelection(); +} + + +void EditLog::copyButtonData() +{ + QListViewItem *next=edit_log_list->firstChild(); + + edit_clipboard->clear(); + while(next!=NULL) { + if((edit_log_list->isSelected(next))&& + (next->text(12).toInt()!=END_MARKER_ID)) { + edit_clipboard-> + push_back(*edit_log_event->logLine(next->text(13).toInt())); + } + next=next->nextSibling(); + } +} + + +void EditLog::pasteButtonData() +{ + QListViewItem *item=SingleSelection(); + if((item==NULL)||(edit_clipboard->size()==0)) { + return; + } + int line=item->text(13).toInt(); + int id=item->text(12).toInt(); + edit_log_event->insert(line,edit_clipboard->size()); + for(unsigned i=0;isize();i++) { + edit_clipboard->at(i).setId(edit_log_event->logLine(line+i)->id()); + *edit_log_event->logLine(line+i)=edit_clipboard->at(i); + edit_log_event->logLine(line+i)->clearExternalData(); + edit_log_event->logLine(line+i)->setSource(RDLogLine::Manual); + } + edit_changed=true; + RefreshList(); + UpdateTracks(); + SelectRecord(id); + UpdateSelection(); +} + + +void EditLog::cartDroppedData(int line,RDLogLine *ll) +{ + RDListViewItem *item=NULL; + bool appended=false; + + if((line<0)||(line==edit_log_event->size())) { + line=edit_log_event->size(); + appended=true; + } + if(ll->cartNumber()==0) { // Empty Cart + if(!appended) { + DeleteLines(line,1); + } + return; + } + edit_log_event->insert(line,1); + edit_log_event->setLogLine(line,ll); + edit_log_event->logLine(line)->setTransType(edit_default_trans); + edit_log_event->logLine(line)->setFadeupGain(-3000); + edit_log_event->logLine(line)->setFadedownGain(-3000); + edit_log_event->refresh(line); + edit_changed=true; + if(appended) { + item=(RDListViewItem *)edit_log_list->lastItem(); + item->setText(13,QString().sprintf("%d",item->text(13).toInt()+1)); + } + else { + item=(RDListViewItem *)edit_log_list-> + findItem(QString().sprintf("%d",line),13); + item->setText(13,QString().sprintf("%d",item->text(13).toInt()+1)); + while((item=(RDListViewItem *)item->nextSibling())!=NULL) { + item->setText(13,QString().sprintf("%d",item->text(13).toInt()+1)); + } + } + item=new RDListViewItem(edit_log_list); + item->setText(13,QString().sprintf("%d",line)); + RefreshLine(item); + edit_log_list->sort(); + edit_log_list->clearSelection(); + item->setSelected(true); +} + + +void EditLog::saveData() +{ + if(!ValidateSvc()) { + if(QMessageBox::warning(this,tr("Invalid Carts"), + tr("The log contains carts that are disabled\nfor the selected service!\n\nDo you still want to save?"),QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) { + return; + } + } + if(!DeleteTracks()) { + QMessageBox::warning(this,tr("RDLogEdit"), + tr("Unable to save log, audio deletion error!")); + return; + } + edit_log_event->save(); + edit_changed=false; + edit_log->setAutoRefresh(edit_autorefresh_box->currentItem()==0); + edit_log-> + setModifiedDatetime(QDateTime(QDate::currentDate(),QTime::currentTime())); +} + + +void EditLog::saveasData() +{ + if(!ValidateSvc()) { + if(QMessageBox::warning(this,tr("Invalid Carts"), + tr("The log contains carts that are disabled\nfor the selected service!\n\nDo you still want to save?"),QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) { + return; + } + } + QString logname; + QString svcname=edit_service_box->currentText(); + RDSqlQuery *q; + QString sql; + RDAddLog *log=NULL; + + if(rduser->createLog()) { + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec) { + log=new RDAddLog(&logname,&svcname,NULL,tr("Add Log"),this,"add_log", + rduser); + } else { // RDStation::HostSec + log=new RDAddLog(&logname,&svcname,NULL,tr("Add Log"),this,"add_log"); + } + if(log->exec()<0) { + return; + } + sql=QString().sprintf("insert into LOGS set \ +NAME=\"%s\",TYPE=0,DESCRIPTION=\"%s log\",ORIGIN_USER=\"%s\",\ +ORIGIN_DATETIME=NOW(),LINK_DATETIME=NOW(),SERVICE=\"%s\"", + (const char *)logname, + (const char *)logname, + (const char *)rdripc->user(), + (const char *)svcname); + q=new RDSqlQuery(sql); + if(!q->isActive()) { + QMessageBox::warning(this,tr("Log Exists"),tr("Log Already Exists!")); + delete q; + return; + } + delete q; + delete edit_log; + edit_newlogs->push_back(logname); + edit_log=new RDLog(logname,true); + QString logtable=logname; + logtable.replace(" ","_"); + RDCreateLogTable(RDLog::tableName(logtable)); + edit_log_event->setLogName(RDLog::tableName(logtable)); + for(int i=0;icount();i++) { + if(edit_service_box->text(i)==svcname) { + edit_service_box->setCurrentItem(i); + } + } + SaveLog(); + edit_logname_label->setText(logname); + edit_origin_label-> + setText(edit_log->originUser()+QString(" - ")+ + edit_log->originDatetime().toString("MM/dd/yyyy - hh:mm:ss")); + } + delete log; + RefreshList(); + edit_changed=false; + edit_deleted_tracks.clear(); +} + + +void EditLog::reportsData() +{ + QDate start_date; + if(edit_startdate_box->isChecked()) { + start_date=edit_startdate_edit->date(); + } + QDate end_date; + if(edit_enddate_box->isChecked()) { + end_date=edit_enddate_edit->date(); + } + ListReports *lr= + new ListReports(edit_log->name(),edit_description_edit->text(), + edit_service_box->currentText(),start_date,end_date, + edit_autorefresh_box->currentItem()==0, + edit_log_event,this,"lr"); + lr->exec(); + delete lr; +} + + +void EditLog::okData() +{ + if(!ValidateSvc()) { + if(QMessageBox::warning(this,tr("Invalid Carts"), + tr("The log contains carts that are disabled\nfor the selected service!\n\nDo you still want to save?"),QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) { + return; + } + } + SaveLog(); + DeleteTracks(); +#ifndef WIN32 + edit_player->stop(); +#endif // WIN32 + done(0); +} + + +void EditLog::cancelData() +{ + if(edit_changed) { + switch(QMessageBox::question(this, + tr("RDLogEdit"), + tr("The log has been modified.\nDo you want to save your changes?"), + QMessageBox::Yes,QMessageBox::No, + QMessageBox::Cancel)) { + case QMessageBox::Yes: + if(!ValidateSvc()) { + QMessageBox::warning(this,tr("Invalid Carts"), + tr("The log contains carts that are disabled\nfor the selected service!")); + return; + } + SaveLog(); + break; + + case QMessageBox::Cancel: + case QMessageBox::NoButton: + return; + break; + } + } +#ifndef WIN32 + edit_player->stop(); +#endif // WIN32 + done(1); +} + + +void EditLog::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void EditLog::resizeEvent(QResizeEvent *e) +{ + edit_logname_label->setGeometry(155,11,size().width()-500,18); + edit_logname_label_label->setGeometry(70,11,80,18); + edit_origin_label->setGeometry(size().width()-300,11,200,18); + edit_origin_label_label->setGeometry(size().width()-345,11,40,18); + edit_track_label->setGeometry(size().width()-425,11,40,18); + edit_track_label_label->setGeometry(size().width()-510,11,80,18); + edit_description_edit->setGeometry(110,40,size().width()-390,20); + edit_description_label->setGeometry(10,40,95,20); + edit_purgedate_box->setGeometry(size().width()-255,42,15,15); + edit_purgedate_label->setGeometry(size().width()-240,40,60,20); + edit_purgedate_edit->setGeometry(size().width()-170,40,100,20); + edit_purgedate_button->setGeometry(size().width()-60,37,50,26); + edit_service_box->setGeometry(110,68,120,22); + edit_service_edit->setGeometry(110,68,120,22); + edit_service_label->setGeometry(10,68,95,22); + edit_autorefresh_box->setGeometry(180,94,50,22); + edit_autorefresh_edit->setGeometry(180,94,50,22); + edit_autorefresh_label->setGeometry(10,94,165,22); + edit_startdate_edit->setGeometry(315,68,100,22); + edit_startdate_label->setGeometry(240,68,70,22); + edit_enddate_edit->setGeometry(490,68,100,22); + edit_enddate_label->setGeometry(415,68,70,22); + edit_startdate_box->setGeometry(250,98,15,15); + edit_enddate_box->setGeometry(430,98,15,15); + edit_startdate_box_label->setGeometry(270,96,175,20); + edit_enddate_box_label->setGeometry(450,96,140,20); + + edit_time_label->setGeometry(655,62,75,20); + edit_stoptime_label->setGeometry(625,82,65,18); + edit_stoptime_edit->setGeometry(695,82,60,18); + edit_endtime_label->setGeometry(625,102,65,18); + edit_endtime_edit->setGeometry(695,102,60,18); + + edit_log_list->setGeometry(10,128, + size().width()-20,size().height()-258); + edit_cart_button->setGeometry(20,size().height()-125,80,50); + edit_marker_button->setGeometry(110,size().height()-125,80,50); + edit_edit_button->setGeometry(200,size().height()-125,80,50); + edit_delete_button->setGeometry(290,size().height()-125,80,50); + edit_up_button->setGeometry(390,size().height()-125,50,50); + edit_down_button->setGeometry(450,size().height()-125,50,50); + edit_cut_button-> + setGeometry(size().width()-280,size().height()-125,80,50); + edit_copy_button-> + setGeometry(size().width()-190,size().height()-125,80,50); + edit_paste_button-> + setGeometry(size().width()-100,size().height()-125,80,50); + edit_save_button->setGeometry(10,size().height()-60,80,50); + edit_saveas_button->setGeometry(100,size().height()-60,80,50); + edit_reports_button->setGeometry(250,size().height()-60,80,50); +#ifndef WIN32 + edit_player->playButton()->setGeometry(400,size().height()-60,80,50); + edit_player->stopButton()->setGeometry(490,size().height()-60,80,50); +#endif // WIN32 + edit_ok_button-> + setGeometry(size().width()-180,size().height()-60,80,50); + edit_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void EditLog::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->fillRect(60,8,size().width()-120,24,QColor(lightGray)); + p->fillRect(9,size().height()-130,size().width()-20,60, + QColor(lightGray)); + + p->setPen(black); + p->setBrush(black); + p->moveTo(624,70); + p->lineTo(760,70); + p->lineTo(760,124); + p->lineTo(624,124); + p->lineTo(624,70); + + p->end(); + delete p; +} + + +void EditLog::DeleteLines(int line,int count) +{ + RDListViewItem *item=NULL; + RDListViewItem *next=NULL; + if(count>0) { + for(int i=line;i<(line+count);i++) { + if(edit_log_event->logLine(i)->source()==RDLogLine::Tracker) { + edit_deleted_tracks. + push_back(edit_log_event->logLine(i)->cartNumber()); + } + } + item=(RDListViewItem *)edit_log_list-> + findItem(QString().sprintf("%d",line),13); + for(int i=0;inextSibling(); + delete item; + item=next; + } + if(next!=NULL) { + next->setSelected(true); + } + edit_log_event->remove(line,count); + edit_changed=true; + RenumberList(line); + } + UpdateTracks(); + UpdateSelection(); +} + + +void EditLog::SaveLog() +{ + edit_log->setDescription(edit_description_edit->text()); + if(edit_purgedate_box->isChecked()) { + edit_log->setPurgeDate(edit_purgedate_edit->date()); + } + else { + edit_log->setPurgeDate(QDate()); + } + edit_log->setService(edit_service_box->currentText()); + if(edit_startdate_box->isChecked()) { + edit_log->setStartDate(edit_startdate_edit->date()); + } + else { + edit_log->setStartDate(QDate()); + } + if(edit_enddate_box->isChecked()) { + edit_log->setEndDate(edit_enddate_edit->date()); + } + else { + edit_log->setEndDate(QDate()); + } + edit_log->setAutoRefresh(edit_autorefresh_box->currentItem()==0); + edit_log_event->save(); + edit_log-> + setModifiedDatetime(QDateTime(QDate::currentDate(),QTime::currentTime())); +} + + +void EditLog::RefreshLine(RDListViewItem *item) +{ + int line=item->text(13).toInt(); + if(line<0) { + return; + } + RDLogLine *logline=edit_log_event->logLine(line); + switch(logline->timeType()) { + case RDLogLine::Hard: + item->setText(1,QString("T")+edit_log_event-> + logLine(line)->startTime(RDLogLine::Logged). + toString("hh:mm:ss.zzz").left(10)); + break; + + default: + if(logline-> + startTime(RDLogLine::Logged).isNull()) { + item->setText(1,edit_log_event-> + blockStartTime(line). + toString("hh:mm:ss.zzz").left(10)); + } + else { + item->setText(1,edit_log_event-> + logLine(line)->startTime(RDLogLine::Logged). + toString("hh:mm:ss.zzz").left(10)); + } + break; + } + switch(logline->transType()) { + case RDLogLine::Play: + item->setText(2,tr("PLAY")); + item->setTextColor(2,item->textColor(1),QFont::Normal); + break; + case RDLogLine::Stop: + item->setText(2,tr("STOP")); + item->setTextColor(2,item->textColor(1),QFont::Normal); + break; + case RDLogLine::Segue: + item->setText(2,tr("SEGUE")); + if(logline->hasCustomTransition()) { + item->setTextColor(2,RD_CUSTOM_TRANSITION_COLOR,QFont::Bold); + } + else { + item->setTextColor(2,item->textColor(1),QFont::Normal); + } + break; + + default: + break; + } + switch(logline->type()) { + case RDLogLine::Cart: + switch(logline->source()) { + case RDLogLine::Tracker: + item->setPixmap(0,*edit_track_cart_map); + break; + + default: + item->setPixmap(0,*edit_playout_map); + break; + } + item->setText(3,QString(). + sprintf("%06u",logline->cartNumber())); + if(logline->title().isEmpty()) { + item->setText(4,""); + item->setText(5,tr("[cart not found]")); + } + else { + item->setText(4,logline->groupName()); + item->setTextColor(4,logline->groupColor(),QFont::Bold); + if((logline->source()!=RDLogLine::Tracker)|| + logline->originUser().isEmpty()|| + (!logline->originDateTime().isValid())) { + item->setText(6,logline->title()); + } + else { + item->setText(6,QString(). + sprintf("%s -- %s %s", + (const char *)logline->title(), + (const char *)logline->originUser(), + (const char *)logline->originDateTime(). + toString("M/d hh:mm"))); + } + } + item-> + setText(5,RDGetTimeLength(logline->forcedLength(),false,false)); + item->setText(7,logline->artist()); + item->setText(8,logline->client()); + item->setText(9,logline->agency()); + break; + + case RDLogLine::Macro: + item->setPixmap(0,*edit_macro_map); + item->setText(3,QString(). + sprintf("%06u",logline->cartNumber())); + if(logline->title().isEmpty()) { + item->setText(4,""); + item->setText(6,tr("[cart not found]")); + } + else { + item->setText(4,logline->groupName()); + item->setTextColor(4,logline->groupColor(),QFont::Bold); + item->setText(6,logline->title()); + } + item-> + setText(5,RDGetTimeLength(logline->forcedLength(),false,false)); + item->setText(7,logline->artist()); + item->setText(8,logline->client()); + item->setText(9,logline->agency()); + break; + + case RDLogLine::Marker: + item->setPixmap(0,*edit_notemarker_map); + item->setText(3,tr("MARKER")); + item->setText(4,""); + item->setText(6,RDTruncateAfterWord(edit_log_event-> + logLine(line)->markerComment(),5,true)); + item->setText(10,logline->markerLabel()); + break; + + case RDLogLine::Track: + item->setPixmap(0,*edit_mic16_map); + item->setText(3,tr("TRACK")); + item->setText(4,""); + item->setText(6,RDTruncateAfterWord(edit_log_event-> + logLine(line)->markerComment(),5,true)); + break; + + case RDLogLine::Chain: + item->setPixmap(0,*edit_chain_map); + item->setText(3,tr("LOG CHAIN")); + item->setText(4,""); + item->setText(6,logline->markerLabel()); + item->setText(7,RDTruncateAfterWord(edit_log_event-> + logLine(line)->markerComment(),5,true)); + break; + + case RDLogLine::MusicLink: + item->setPixmap(0,*edit_music_map); + item->setText(3,tr("LINK")); + item->setText(4,""); + item->setText(5,RDGetTimeLength(logline->linkLength(),false,false)); + item->setText(6,tr("[music import]")); + break; + + case RDLogLine::TrafficLink: + item->setPixmap(0,*edit_traffic_map); + item->setText(3,tr("LINK")); + item->setText(4,""); + item->setText(5,RDGetTimeLength(logline->linkLength(),false,false)); + item->setText(6,tr("[traffic import]")); + break; + + default: + break; + } + switch(logline->source()) { + case RDLogLine::Manual: + item->setText(11,tr("Manual")); + break; + + case RDLogLine::Traffic: + item->setText(11,tr("Traffic")); + break; + + case RDLogLine::Music: + item->setText(11,tr("Music")); + break; + + case RDLogLine::Template: + item->setText(11,tr("RDLogManager")); + break; + + case RDLogLine::Tracker: + item->setText(11,tr("Voice Tracker")); + break; + } + item-> + setText(12,QString().sprintf("%d",logline->id())); + UpdateColor(item,logline); +} + + +void EditLog::RefreshList() +{ + RDListViewItem *l; + + edit_log_list->clear(); + l=new RDListViewItem(edit_log_list); + l->setText(6,tr("--- end of log ---")); + l->setText(12,QString().sprintf("%d",END_MARKER_ID)); + l->setText(13,QString().sprintf("%d",edit_log_event->size())); + for(int i=edit_log_event->size()-1;i>=0;i--) { + l=new RDListViewItem(edit_log_list); + l->setText(13,QString().sprintf("%d",i)); + RefreshLine(l); + } +} + + +void EditLog::UpdateSelection() +{ + RDListViewItem *rditem=SingleSelection(); + if(rditem==NULL) { // Multiple items selected? + edit_endtime_edit->setText(""); + edit_stoptime_label->setText(tr("Selected:")); + QListViewItem *next=edit_log_list->firstChild(); + int start_line=-1; + int end_line=-1; + while(next!=NULL) { + if(edit_log_list->isSelected(next)) { + if((start_line<0)&&(next->text(12).toInt()!=END_MARKER_ID)) { + start_line=next->text(13).toInt(); + } + if(next->text(12).toInt()!=END_MARKER_ID) { + end_line=next->text(13).toInt(); + } + } + next=next->nextSibling(); + } + if(start_line>=0) { + edit_stoptime_edit->setText(RDGetTimeLength(edit_log_event-> + length(start_line,end_line+1),true,false)); + } + return; + } + if(rditem->text(12).toInt()>0) { + edit_endtime_edit->setText(RDGetTimeLength(edit_log_event-> + length(rditem->text(13).toInt(),edit_log_event->size()),true,false)); + edit_stoptime_label->setText(tr("Next Stop:")); + int stoplen=edit_log_event->lengthToStop(rditem->text(13).toInt()); + if(stoplen>=0) { + edit_stoptime_edit->setText(RDGetTimeLength(stoplen,true,false)); + } + else { + edit_stoptime_edit->setText(""); + } + } + else { + edit_endtime_edit->setText(""); + edit_stoptime_edit->setText(""); + } +} + + +bool EditLog::UpdateColor(RDListViewItem *item,RDLogLine *logline) +{ + bool ret=true; + QDateTime now=QDateTime(QDate::currentDate(),QTime::currentTime()); + + switch(logline->type()) { + case RDLogLine::Cart: + switch(logline->validity(now)) { + case RDCart::AlwaysValid: + if(edit_group_list.isGroupValid(item->text(4))|| + item->text(4).isEmpty()) { + item->setBackgroundColor(palette().color(QPalette::Active, + QColorGroup::Base)); + } + else { + item->setBackgroundColor(RD_CART_INVALID_SERVICE_COLOR); + ret=false; + } + break; + + case RDCart::ConditionallyValid: + item->setBackgroundColor(RD_CART_CONDITIONAL_COLOR); + break; + + case RDCart::FutureValid: + item->setBackgroundColor(RD_CART_FUTURE_COLOR); + break; + + case RDCart::EvergreenValid: + item->setBackgroundColor(RD_CART_EVERGREEN_COLOR); + break; + + case RDCart::NeverValid: + item->setBackgroundColor(RD_CART_ERROR_COLOR); + item->setText(6,tr("[INVALID CART]")); + break; + } + break; + + default: + if(edit_group_list.isGroupValid(item->text(4))|| + item->text(4).isEmpty()) { + item->setBackgroundColor(palette().color(QPalette::Active, + QColorGroup::Base)); + } + else { + item->setBackgroundColor(RD_CART_INVALID_SERVICE_COLOR); + ret=false; + } + break; + } + return ret; +} + + +void EditLog::RenumberList(int line) +{ + QListViewItem *prev=NULL; + QListViewItem *item=edit_log_list->firstChild(); + if(item==NULL) { + return; + } + for(int i=0;inextSibling(); + } + while(item!=NULL) { + item->setText(13,QString().sprintf("%d",line++)); + prev=item; + item=item->nextSibling(); + } + prev->setText(12,QString().sprintf("%d",END_MARKER_ID)); +} + + +void EditLog::SelectRecord(int id) +{ + QListViewItem *item=edit_log_list->firstChild(); + + while(item!=NULL) { + if(item->text(12).toInt()==id) { + edit_log_list->setSelected(item,true); + edit_log_list->ensureItemVisible(item); + return; + } + item=item->nextSibling(); + } +} + + +RDListViewItem *EditLog::SingleSelection() +{ + RDListViewItem *item=NULL; + RDListViewItem *next=(RDListViewItem *)edit_log_list->firstChild(); + + while(next!=NULL) { + if(edit_log_list->isSelected(next)) { + if(item==NULL) { + item=next; + } + else { + return NULL; + } + } + next=(RDListViewItem *)next->nextSibling(); + } + return item; +} + + +bool EditLog::ValidateSvc() +{ + RDLogLine *logline=NULL; + bool valid=true; + RDListViewItem *item=(RDListViewItem *)edit_log_list->firstChild(); + while(item!=NULL) { + if((logline=edit_log_event->logLine(item->text(13).toInt()))!=NULL) { + valid&=UpdateColor(item,logline); + } + item=(RDListViewItem *)item->nextSibling(); + } + return valid; +} + + +void EditLog::UpdateTracks() +{ + unsigned markers=0; + unsigned tracks=0; + RDLogLine *logline; + + for(int i=0;isize();i++) { + logline=edit_log_event->logLine(i); + if(logline->type()==RDLogLine::Track) { + markers++; + } + if(logline->source()==RDLogLine::Tracker) { + tracks++; + } + } + edit_track_label-> + setText(QString().sprintf("%u / %u",tracks,markers+tracks)); +} + + +bool EditLog::DeleteTracks() +{ + RDCart *cart; + for(unsigned i=0;iremove(rdstation_conf,rduser,log_config)) { + delete cart; + return false; + } + delete cart; + } + return true; +} diff --git a/rdlogedit/edit_log.h b/rdlogedit/edit_log.h new file mode 100644 index 00000000..6597cc48 --- /dev/null +++ b/rdlogedit/edit_log.h @@ -0,0 +1,183 @@ +// edit_log.h +// +// Create a Rivendell Log +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_log.h,v 1.36.8.2 2014/02/20 16:33:55 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_LOG_H +#define EDIT_LOG_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +// +// Widget Settings +// +#define END_MARKER_ID -2 + +class EditLog : public QDialog +{ + Q_OBJECT + public: + EditLog(QString logname,vector *clipboard, + vector *new_logs,QWidget *parent=0,const char *name=0); + ~EditLog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void descriptionChangedData(const QString &); + void selectPurgeDateData(); + void serviceActivatedData(const QString &svcname); + void dateValueChangedData(const QDate &); + void startDateEnabledData(bool); + void endDateEnabledData(bool); + void insertCartButtonData(); + void insertMarkerButtonData(); + void clickedData(QListViewItem *item); + void selectionChangedData(); + void doubleClickData(QListViewItem *item); + void editButtonData(); + void deleteButtonData(); + void upButtonData(); + void downButtonData(); + void cutButtonData(); + void copyButtonData(); + void pasteButtonData(); + void cartDroppedData(int line,RDLogLine *ll); + void saveData(); + void saveasData(); + void reportsData(); + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + void resizeEvent(QResizeEvent *e); + void paintEvent(QPaintEvent *); + + private: + void DeleteLines(int line,int count); + void SaveLog(); + void RefreshLine(RDListViewItem *item); + void RefreshList(); + void UpdateSelection(); + void RenumberList(int line); + bool UpdateColor(RDListViewItem *item,RDLogLine *logline); + void SelectRecord(int id); + void UpdateTracks(); + bool DeleteTracks(); + bool ValidateSvc(); + RDListViewItem *SingleSelection(); + RDLog *edit_log; + RDLogEvent *edit_log_event; + std::vector *edit_clipboard; + std::vector edit_deleted_tracks; + std::vector *edit_newlogs; + QString edit_logname; + QLabel *edit_description_label; + QLineEdit *edit_description_edit; + QLabel *edit_service_label; + QComboBox *edit_service_box; + QLineEdit *edit_service_edit; + QLabel *edit_autorefresh_label; + QComboBox *edit_autorefresh_box; + QLineEdit *edit_autorefresh_edit; + QDateEdit *edit_startdate_edit; + QDateEdit *edit_enddate_edit; + QLabel *edit_startdate_label; + QLabel *edit_startdate_box_label; + QLabel *edit_enddate_box_label; + QCheckBox *edit_startdate_box; + QLabel *edit_enddate_label; + QCheckBox *edit_enddate_box; + DropListView *edit_log_list; + QString edit_filter; + QString edit_group; + QPixmap *edit_playout_map; + QPixmap *edit_macro_map; + QPixmap *edit_marker_map; + QPixmap *edit_chain_map; + QPixmap *edit_track_cart_map; + QPixmap *edit_notemarker_map; + QPixmap *edit_music_map; + QPixmap *edit_mic16_map; + QPixmap *edit_traffic_map; + QLabel *edit_logname_label_label; + QLabel *edit_logname_label; + QLabel *edit_origin_label_label; + QLabel *edit_origin_label; + QLabel *edit_track_label_label; + QLabel *edit_track_label; + bool edit_changed; + QPushButton *edit_cart_button; + QPushButton *edit_marker_button; + QPushButton *edit_edit_button; + QPushButton *edit_delete_button; + RDTransportButton *edit_up_button; + RDTransportButton *edit_down_button; + QPushButton *edit_cut_button; + QPushButton *edit_copy_button; + QPushButton *edit_paste_button; + QPushButton *edit_save_button; + QPushButton *edit_saveas_button; + QPushButton *edit_reports_button; + RDTransportButton *edit_play_button; + RDTransportButton *edit_stop_button; + QPushButton *edit_ok_button; + QPushButton *edit_cancel_button; + RDGroupList edit_group_list; + RDLogLine::TransType edit_default_trans; + int edit_output_card; + int edit_output_port; + unsigned edit_start_macro; + unsigned edit_end_macro; + RDSimplePlayer *edit_player; + QLabel *edit_time_label; + QLabel *edit_stoptime_label; + QLineEdit *edit_stoptime_edit; + QLabel *edit_endtime_label; + QLineEdit *edit_endtime_edit; + QCheckBox *edit_purgedate_box; + QLabel *edit_purgedate_label; + QDateEdit *edit_purgedate_edit; + QPushButton *edit_purgedate_button; +}; + + +#endif + diff --git a/rdlogedit/edit_logline.cpp b/rdlogedit/edit_logline.cpp new file mode 100644 index 00000000..ad3ebcf5 --- /dev/null +++ b/rdlogedit/edit_logline.cpp @@ -0,0 +1,421 @@ +// edit_logline.cpp +// +// Edit a Rivendell Log Entry +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_logline.cpp,v 1.40.8.1 2012/11/26 20:19:41 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include +#include +#include + +#include +#include + +EditLogLine::EditLogLine(RDLogLine *line,QString *filter,QString *group, + QString svcname,RDGroupList *grplist, + RDLogEvent *log,int lineno, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Edit Log Entry")); + + edit_logline=line; + edit_filter=filter; + edit_group=group; + edit_service=svcname; + edit_group_list=grplist; + edit_log_event=log; + edit_line=lineno; + + // + // Create Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont normal_font=QFont("Helvetica",12,QFont::Normal); + normal_font.setPixelSize(12); + QFont radio_font=QFont("Helvetica",10,QFont::Normal); + radio_font.setPixelSize(10); + + // + // Time Type + // + edit_timetype_box=new QCheckBox(this,"edit_timetype_box"); + edit_timetype_box->setGeometry(10,22,15,15); + edit_timetype_label=new QLabel(edit_timetype_box,tr("Start at:"), + this,"edit_timetype_label"); + edit_timetype_label->setGeometry(30,21,80,17); + edit_timetype_label->setFont(label_font); + edit_timetype_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Start Time + // + edit_time_edit=new RDTimeEdit(this,"edit_time_edit"); + edit_time_edit->setGeometry(85,19,85,20); + edit_time_edit->setDisplay(RDTimeEdit::Hours|RDTimeEdit::Minutes| + RDTimeEdit::Seconds|RDTimeEdit::Tenths); + connect(edit_time_edit,SIGNAL(valueChanged(const QTime &)), + this,SLOT(timeChangedData(const QTime &))); + + // + // Grace Time + // + edit_grace_group + =new QButtonGroup(1,Qt::Vertical, + tr("Action If Previous Event Still Playing"), + this,"edit_grace_group"); + edit_grace_group->setGeometry(175,11,435,50); + edit_grace_group->setFont(label_font); + edit_grace_group->setRadioButtonExclusive(true); + QRadioButton *radio_button= + new QRadioButton(tr("Start Immediately"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + radio_button=new QRadioButton(tr("Make Next"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + radio_button=new QRadioButton(tr("Wait up to"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + + edit_grace_edit=new RDTimeEdit(this,"edit_grace_edit"); + edit_grace_edit->setGeometry(538,31,65,20); + edit_grace_edit-> + setDisplay(RDTimeEdit::Minutes|RDTimeEdit::Seconds|RDTimeEdit::Tenths); + connect(edit_timetype_box,SIGNAL(toggled(bool)), + this,SLOT(timeToggledData(bool))); + connect(edit_grace_group,SIGNAL(clicked(int)), + this,SLOT(graceClickedData(int))); + + // + // Transition Type + // + edit_transtype_box=new QComboBox(this,"edit_transtype_box"); + edit_transtype_box->setGeometry(485,68,110,26); + edit_transtype_box->insertItem(tr("Play")); + edit_transtype_box->insertItem(tr("Segue")); + edit_transtype_box->insertItem(tr("Stop")); + edit_time_label=new QLabel(edit_transtype_box,tr("Transition Type:"), + this,"edit_transtype_label"); + edit_time_label->setGeometry(190,68,290,26); + edit_time_label->setFont(label_font); + edit_time_label->setAlignment(AlignRight|AlignVCenter); + + // Overlap Box + edit_overlap_box=new QCheckBox(this,"edit_overlap_box"); + edit_overlap_box->setGeometry(30,72,15,15); + edit_overlap_label=new QLabel(edit_overlap_box,tr("No Fade on Segue Out"), + this,"edit_overlap_label"); + edit_overlap_label->setGeometry(50,68,130,26); + edit_overlap_label->setFont(button_font); + edit_overlap_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); + + // + // Cart Number + // + edit_cart_edit=new QLineEdit(this,"edit_cart_edit"); + edit_cart_edit->setGeometry(10,116,60,18); + QLabel *label=new QLabel(tr("Cart"),this,"cart_label"); + label->setFont(label_font); + label->setGeometry(12,100,60,14); + + // + // Title + // + edit_title_edit=new QLineEdit(this,"edit_title_edit"); + edit_title_edit->setGeometry(75,116,260,18); + edit_title_edit->setReadOnly(true); + label=new QLabel(tr("Title"),this,"title_label"); + label->setFont(label_font); + label->setGeometry(77,100,110,14); + + // + // Artist + // + edit_artist_edit=new QLineEdit(this,"edit_artist_edit"); + edit_artist_edit->setGeometry(340,116,sizeHint().width()-350,18); + edit_artist_edit->setReadOnly(true); + label=new QLabel(tr("Artist"),this,"artist_label"); + label->setFont(label_font); + label->setGeometry(342,100,110,14); + + // + // Cart Button + // + QPushButton *button=new QPushButton(this,"cart_button"); + button->setGeometry(20,144,80,50); + button->setFont(button_font); + button->setText(tr("Select\nCart")); + connect(button,SIGNAL(clicked()),this,SLOT(selectCartData())); + + // + // Ok Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(button_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + edit_time_edit->setTime(edit_logline->startTime(RDLogLine::Logged)); + if(edit_logline->timeType()==RDLogLine::Hard) { + edit_timetype_box->setChecked(true); + timeToggledData(true); + } + else { + timeToggledData(false); + } + timeChangedData(edit_time_edit->time()); + switch(edit_logline->graceTime()) { + case -1: + edit_grace_group->setButton(1); + graceClickedData(1); + break; + + case 0: + edit_grace_group->setButton(0); + graceClickedData(0); + break; + + default: + edit_grace_group->setButton(2); + graceClickedData(2); + edit_grace_edit->setTime(QTime().addMSecs(edit_logline->graceTime())); + break; + } + edit_transtype_box->setCurrentItem(edit_logline->transType()); + if(edit_logline->segueStartPoint(RDLogLine::LogPointer)<0 + && edit_logline->segueEndPoint(RDLogLine::LogPointer)<0 + && edit_logline->endPoint(RDLogLine::LogPointer)<0 + && edit_logline->fadedownPoint(RDLogLine::LogPointer)<0) { + edit_overlap_box->setEnabled(true); + edit_overlap_label->setEnabled(true); + if(edit_logline->segueGain()==0) { + edit_overlap_box->setChecked(true); + } + else { + edit_overlap_box->setChecked(false); + } + } + else { + edit_overlap_box->setEnabled(false); + edit_overlap_label->setEnabled(false); + } + FillCart(edit_logline->cartNumber()); +} + + +EditLogLine::~EditLogLine() +{ +} + + +QSize EditLogLine::sizeHint() const +{ + return QSize(625,230); +} + + +QSizePolicy EditLogLine::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditLogLine::selectCartData() +{ + bool ok; + int cartnum=edit_cart_edit->text().toInt(&ok); + if(!ok) { + cartnum=-1; + } + if(log_cart_dialog->exec(&cartnum,RDCart::All,&edit_service,1, + rduser->name(),rduser->password())==0) { + FillCart(cartnum); + } +} + + +void EditLogLine::timeChangedData(const QTime &time) +{ + QString str; + + if(edit_timetype_box->isChecked()) { + str=QString(tr("Transition If Previous Cart Ends Before")); + edit_time_label-> + setText(QString().sprintf("%s %s:",(const char *)str, + (const char *)edit_time_edit->time(). + toString("hh:mm:ss.zzz").left(10))); + } +} + + +void EditLogLine::timeToggledData(bool state) +{ + QString str; + + edit_time_edit->setEnabled(state); + edit_grace_group->setEnabled(state); + if(state) { + graceClickedData(edit_grace_group->selectedId()); + str=QString(tr("Transition If Previous Cart Ends Before")); + edit_time_label-> + setText(QString().sprintf("%s %s:",(const char *)str, + (const char *)edit_time_edit->time(). + toString("hh:mm:ss.zzz").left(10))); + } + else { + edit_grace_edit->setDisabled(true); + edit_time_label->setText(tr("Transition Type:")); + } +} + + +void EditLogLine::graceClickedData(int id) +{ + switch(id) { + case 0: + edit_grace_edit->setDisabled(true); + break; + + case 1: + edit_grace_edit->setDisabled(true); + break; + + case 2: + edit_grace_edit->setEnabled(true); + break; + } +} + + +void EditLogLine::okData() +{ + if(edit_cart_edit->text().isEmpty()) { + QMessageBox::warning(this,tr("Missing Cart"), + tr("You must supply a cart number!")); + return; + } + RDCart *cart=new RDCart(edit_cart_edit->text().toUInt()); + if(cart->exists()) { + if(!edit_group_list->isGroupValid(cart->groupName())) { + delete cart; + QMessageBox::warning(this,tr("Disabled Cart"), + tr("This cart belongs to a disabled\ngroup for the specified service!")); + return; + } + } + delete cart; + if(edit_timetype_box->isChecked()&& + edit_log_event->exists(edit_time_edit->time(),edit_line)) { + QMessageBox::warning(this,tr("Duplicate Start Time"), + tr("An event is already scheduled with this start time!")); + return; + } + if(edit_timetype_box->isChecked()) { + edit_logline->setTimeType(RDLogLine::Hard); + edit_logline->setStartTime(RDLogLine::Logged,edit_time_edit->time()); + switch(edit_grace_group->selectedId()) { + case 0: + edit_logline->setGraceTime(0); + break; + + case 1: + edit_logline->setGraceTime(-1); + break; + + case 2: + edit_logline->setGraceTime(QTime().msecsTo(edit_grace_edit->time())); + break; + } + } + else { + edit_logline->setTimeType(RDLogLine::Relative); + edit_logline->setStartTime(RDLogLine::Logged,QTime()); + edit_logline->setGraceTime(0); + } + edit_logline-> + setTransType((RDLogLine::TransType)edit_transtype_box->currentItem()); + edit_logline->setCartNumber(edit_cart_edit->text().toUInt()); + if(edit_logline->segueStartPoint(RDLogLine::LogPointer)<0 + && edit_logline->segueEndPoint(RDLogLine::LogPointer)<0 + && edit_logline->endPoint(RDLogLine::LogPointer)<0 + && edit_logline->fadedownPoint(RDLogLine::LogPointer)<0) { + if(edit_overlap_box->isChecked()) { + edit_logline->setSegueGain(0); + } + else { + edit_logline->setSegueGain(RD_FADE_DEPTH); + } + } + done(edit_logline->id()); +} + + +void EditLogLine::cancelData() +{ + done(-1); +} + + +void EditLogLine::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void EditLogLine::FillCart(int cartnum) +{ + RDCart *cart=new RDCart(cartnum); + if(cartnum!=0) { + edit_cart_edit->setText(QString().sprintf("%05u",cartnum)); + } + edit_title_edit->setText(cart->title()); + edit_artist_edit->setText(cart->artist()); + delete cart; +} diff --git a/rdlogedit/edit_logline.h b/rdlogedit/edit_logline.h new file mode 100644 index 00000000..6fc8b591 --- /dev/null +++ b/rdlogedit/edit_logline.h @@ -0,0 +1,88 @@ +// edit_logline.h +// +// Edit a Rivendell Log Entry +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: edit_logline.h,v 1.17 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_LOGLINE_H +#define EDIT_LOGLINE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +class EditLogLine : public QDialog +{ + Q_OBJECT + public: + EditLogLine(RDLogLine *,QString *filter,QString *group,QString svcname, + RDGroupList *grplist,RDLogEvent *log,int lineno, + QWidget *parent=0,const char *name=0); + ~EditLogLine(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void selectCartData(); + void timeChangedData(const QTime &); + void timeToggledData(bool state); + void graceClickedData(int id); + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + void FillCart(int cartnum); + RDLogLine *edit_logline; + RDTimeEdit *edit_time_edit; + QLabel *edit_time_label; + QCheckBox *edit_timetype_box; + QLabel *edit_timetype_label; + QCheckBox *edit_time_box; + QComboBox *edit_transtype_box; + QCheckBox *edit_overlap_box; + QLabel *edit_overlap_label; + QLineEdit *edit_cart_edit; + QLineEdit *edit_title_edit; + QLineEdit *edit_artist_edit; + QString *edit_filter; + QString *edit_group; + QButtonGroup *edit_grace_group; + RDTimeEdit *edit_grace_edit; + QString edit_service; + RDGroupList *edit_group_list; + RDLogEvent *edit_log_event; + int edit_line; +}; + + +#endif + diff --git a/rdlogedit/edit_marker.cpp b/rdlogedit/edit_marker.cpp new file mode 100644 index 00000000..71f5b64d --- /dev/null +++ b/rdlogedit/edit_marker.cpp @@ -0,0 +1,318 @@ +// edit_marker.cpp +// +// Edit a Rivendell Log Marker Entry +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_marker.cpp,v 1.20 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include + +EditMarker::EditMarker(RDLogLine *line,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Edit Log Marker")); + + edit_logline=line; + + // + // Create Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont radio_font=QFont("Helvetica",10,QFont::Normal); + radio_font.setPixelSize(10); + + // + // Time Type + // + edit_timetype_box=new QCheckBox(this,"edit_timetype_box"); + edit_timetype_box->setGeometry(10,22,15,15); + edit_timetype_label=new QLabel(edit_timetype_box,tr("Start at:"), + this,"edit_timetype_label"); + edit_timetype_label->setGeometry(30,21,85,17); + edit_timetype_label->setFont(label_font); + edit_timetype_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Start Time + // + edit_time_edit=new RDTimeEdit(this,"edit_time_edit"); + edit_time_edit->setGeometry(85,19,85,20); + edit_time_edit->setDisplay(RDTimeEdit::Hours|RDTimeEdit::Minutes| + RDTimeEdit::Seconds|RDTimeEdit::Tenths); + connect(edit_time_edit,SIGNAL(valueChanged(const QTime &)), + this,SLOT(timeChangedData(const QTime &))); + + // + // Grace Time + // + edit_grace_group + =new QButtonGroup(1,Qt::Vertical, + tr("Action If Previous Event Still Playing"), + this,"edit_grace_group"); + edit_grace_group->setGeometry(175,11,435,50); + edit_grace_group->setFont(label_font); + edit_grace_group->setRadioButtonExclusive(true); + QRadioButton *radio_button= + new QRadioButton(tr("Start Immediately"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + radio_button=new QRadioButton(tr("Make Next"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + radio_button=new QRadioButton(tr("Wait up to"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + edit_grace_box=new QTimeEdit(this,"edit_grace_box"); + edit_grace_box->setGeometry(543,31,60,20); + edit_grace_box->setDisplay(QTimeEdit::Minutes|QTimeEdit::Seconds); + connect(edit_timetype_box,SIGNAL(toggled(bool)), + this,SLOT(timeToggledData(bool))); + connect(edit_grace_group,SIGNAL(clicked(int)), + this,SLOT(graceClickedData(int))); + + // + // Transition Type + // + edit_transtype_box=new QComboBox(this,"edit_transtype_box"); + edit_transtype_box->setGeometry(385,68,110,26); + edit_transtype_box->insertItem(tr("Play")); + edit_transtype_box->insertItem(tr("Segue")); + edit_transtype_box->insertItem(tr("Stop")); + edit_time_label=new QLabel(edit_transtype_box,"Transition Type:", + this,"edit_transtype_label"); + edit_time_label->setGeometry(10,68,370,26); + edit_time_label->setFont(label_font); + edit_time_label->setAlignment(AlignRight|AlignVCenter); + + // + // Comment + // + edit_comment_edit=new QLineEdit(this,"edit_comment_edit"); + edit_comment_edit->setGeometry(10,116,sizeHint().width()-20,18); + edit_comment_edit->setMaxLength(255); + QLabel *label=new QLabel(tr("Comment"),this,"comment_label"); + label->setFont(label_font); + label->setGeometry(12,100,70,14); + + // + // Label + // + edit_label_edit=new QLineEdit(this,"edit_label_edit"); + edit_label_edit->setGeometry(10,156,100,18); + edit_label_edit->setMaxLength(10); + label=new QLabel(tr("Label"),this,"label_label"); + label->setFont(label_font); + label->setGeometry(12,140,60,14); + + // + // Ok Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(button_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + edit_time_edit->setTime(edit_logline->startTime(RDLogLine::Logged)); + if(edit_logline->timeType()==RDLogLine::Hard) { + edit_timetype_box->setChecked(true); + timeToggledData(true); + } + else { + timeToggledData(false); + } + timeChangedData(edit_time_edit->time()); + switch(edit_logline->graceTime()) { + case -1: + edit_grace_group->setButton(1); + graceClickedData(1); + break; + + case 0: + edit_grace_group->setButton(0); + graceClickedData(0); + break; + + default: + edit_grace_group->setButton(2); + edit_grace_box->setTime(QTime().addMSecs(edit_logline->graceTime())); + //edit_grace_box->setValue(edit_logline->graceTime()); + graceClickedData(2); + break; + } + edit_transtype_box->setCurrentItem(edit_logline->transType()); + edit_comment_edit->setText(edit_logline->markerComment()); + edit_label_edit->setText(edit_logline->markerLabel()); +} + + +EditMarker::~EditMarker() +{ +} + + +QSize EditMarker::sizeHint() const +{ + return QSize(625,230); +} + + +QSizePolicy EditMarker::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditMarker::timeChangedData(const QTime &time) +{ + QString str; + + if(edit_timetype_box->isChecked()) { + str=QString(tr("Transition If Previous Cart Ends Before")); + edit_time_label-> + setText(QString().sprintf("%s %s:",(const char *)str, + (const char *)edit_time_edit->time(). + toString("hh:mm:ss.zzz").left(10))); + } +} + + +void EditMarker::timeToggledData(bool state) +{ + QString str; + + edit_time_edit->setEnabled(state); + edit_grace_group->setEnabled(state); + if(state) { + graceClickedData(edit_grace_group->selectedId()); + str=QString(tr("Transition If Previous Cart Ends Before")); + edit_time_label-> + setText(QString().sprintf("%s %s:",(const char *)str, + (const char *)edit_time_edit->time(). + toString("hh:mm:ss.zzz").left(10))); + } + else { + edit_grace_box->setDisabled(true); + edit_time_label->setText(tr("Transition Type:")); + } +} + + +void EditMarker::graceClickedData(int id) +{ + switch(id) { + case 0: + edit_grace_box->setDisabled(true); + break; + + case 1: + edit_grace_box->setDisabled(true); + break; + + case 2: + edit_grace_box->setEnabled(true); + break; + } +} + + +void EditMarker::selectTimeData(int id) +{ + if(id==RDLogLine::Relative) { + edit_time_edit->setDisabled(true); + edit_time_label->setDisabled(true); + edit_grace_box->setDisabled(true); + } + else { + edit_time_edit->setEnabled(true); + edit_time_label->setEnabled(true); + } +} + + +void EditMarker::okData() +{ + if(edit_timetype_box->isChecked()) { + edit_logline->setTimeType(RDLogLine::Hard); + edit_logline->setStartTime(RDLogLine::Logged,edit_time_edit->time()); + switch(edit_grace_group->selectedId()) { + case 0: + edit_logline->setGraceTime(0); + break; + + case 1: + edit_logline->setGraceTime(-1); + break; + + case 2: + edit_logline->setGraceTime(QTime().msecsTo(edit_grace_box->time())); + //edit_logline->setGraceTime(edit_grace_box->value()); + break; + } + } + else { + edit_logline->setTimeType(RDLogLine::Relative); + edit_logline->setStartTime(RDLogLine::Logged,QTime()); + edit_logline->setGraceTime(0); + } + edit_logline-> + setTransType((RDLogLine::TransType)edit_transtype_box->currentItem()); + edit_logline->setMarkerComment(edit_comment_edit->text()); + edit_logline->setMarkerLabel(edit_label_edit->text()); + done(edit_logline->id()); +} + + +void EditMarker::cancelData() +{ + done(-1); +} + + +void EditMarker::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/rdlogedit/edit_marker.h b/rdlogedit/edit_marker.h new file mode 100644 index 00000000..6887724d --- /dev/null +++ b/rdlogedit/edit_marker.h @@ -0,0 +1,76 @@ +// edit_marker.h +// +// Edit a Rivendell Log Entry +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: edit_marker.h,v 1.10 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_MARKER_H +#define EDIT_MARKER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class EditMarker : public QDialog +{ + Q_OBJECT + public: + EditMarker(RDLogLine *,QWidget *parent=0,const char *name=0); + ~EditMarker(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void timeChangedData(const QTime &); + void timeToggledData(bool state); + void graceClickedData(int id); + void selectTimeData(int); + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + RDLogLine *edit_logline; + RDTimeEdit *edit_time_edit; + QLabel *edit_time_label; + QCheckBox *edit_timetype_box; + QLabel *edit_timetype_label; + QCheckBox *edit_time_box; + QComboBox *edit_transtype_box; + QLineEdit *edit_comment_edit; + QLineEdit *edit_label_edit; + QButtonGroup *edit_grace_group; + QFont normal_font; + QTimeEdit *edit_grace_box; +}; + + +#endif + diff --git a/rdlogedit/edit_track.cpp b/rdlogedit/edit_track.cpp new file mode 100644 index 00000000..e8e36ef9 --- /dev/null +++ b/rdlogedit/edit_track.cpp @@ -0,0 +1,306 @@ +// edit_track.cpp +// +// Edit a Rivendell Voice Track Log Entry +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_track.cpp,v 1.9 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include + +EditTrack::EditTrack(RDLogLine *line,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Edit Voice Track Marker")); + + edit_logline=line; + + // + // Create Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont radio_font=QFont("Helvetica",10,QFont::Normal); + radio_font.setPixelSize(10); + + // + // Time Type + // + edit_timetype_box=new QCheckBox(this,"edit_timetype_box"); + edit_timetype_box->setGeometry(10,22,15,15); + edit_timetype_label=new QLabel(edit_timetype_box,tr("Start at:"), + this,"edit_timetype_label"); + edit_timetype_label->setGeometry(30,21,85,17); + edit_timetype_label->setFont(label_font); + edit_timetype_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Start Time + // + edit_time_edit=new RDTimeEdit(this,"edit_time_edit"); + edit_time_edit->setGeometry(85,19,85,20); + edit_time_edit->setDisplay(RDTimeEdit::Hours|RDTimeEdit::Minutes| + RDTimeEdit::Seconds|RDTimeEdit::Tenths); + connect(edit_time_edit,SIGNAL(valueChanged(const QTime &)), + this,SLOT(timeChangedData(const QTime &))); + + // + // Grace Time + // + edit_grace_group + =new QButtonGroup(1,Qt::Vertical, + tr("Action If Previous Event Still Playing"), + this,"edit_grace_group"); + edit_grace_group->setGeometry(175,11,435,50); + edit_grace_group->setFont(label_font); + edit_grace_group->setRadioButtonExclusive(true); + QRadioButton *radio_button= + new QRadioButton(tr("Start Immediately"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + radio_button=new QRadioButton(tr("Make Next"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + radio_button=new QRadioButton(tr("Wait up to"),edit_grace_group); + edit_grace_group->insert(radio_button); + radio_button->setFont(radio_font); + edit_grace_box=new QTimeEdit(this,"edit_grace_box"); + edit_grace_box->setGeometry(543,31,60,20); + edit_grace_box->setDisplay(QTimeEdit::Minutes|QTimeEdit::Seconds); + connect(edit_timetype_box,SIGNAL(toggled(bool)), + this,SLOT(timeToggledData(bool))); + connect(edit_grace_group,SIGNAL(clicked(int)), + this,SLOT(graceClickedData(int))); + + // + // Transition Type + // + edit_transtype_box=new QComboBox(this,"edit_transtype_box"); + edit_transtype_box->setGeometry(385,68,110,26); + edit_transtype_box->insertItem(tr("Play")); + edit_transtype_box->insertItem(tr("Segue")); + edit_transtype_box->insertItem(tr("Stop")); + edit_time_label=new QLabel(edit_transtype_box,"Transition Type:", + this,"edit_transtype_label"); + edit_time_label->setGeometry(10,68,370,26); + edit_time_label->setFont(label_font); + edit_time_label->setAlignment(AlignRight|AlignVCenter); + + // + // Comment + // + edit_comment_edit=new QLineEdit(this,"edit_comment_edit"); + edit_comment_edit->setGeometry(10,116,sizeHint().width()-20,18); + edit_comment_edit->setMaxLength(255); + QLabel *label=new QLabel(tr("Comment"),this,"comment_label"); + label->setFont(label_font); + label->setGeometry(12,100,70,14); + + // + // Ok Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(button_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + edit_time_edit->setTime(edit_logline->startTime(RDLogLine::Logged)); + if(edit_logline->timeType()==RDLogLine::Hard) { + edit_timetype_box->setChecked(true); + timeToggledData(true); + } + else { + timeToggledData(false); + } + timeChangedData(edit_time_edit->time()); + switch(edit_logline->graceTime()) { + case -1: + edit_grace_group->setButton(1); + graceClickedData(1); + break; + + case 0: + edit_grace_group->setButton(0); + graceClickedData(0); + break; + + default: + edit_grace_group->setButton(2); + edit_grace_box->setTime(QTime().addMSecs(edit_logline->graceTime())); + //edit_grace_box->setValue(edit_logline->graceTime()); + graceClickedData(2); + break; + } + edit_transtype_box->setCurrentItem(edit_logline->transType()); + edit_comment_edit->setText(edit_logline->markerComment()); +} + + +EditTrack::~EditTrack() +{ +} + + +QSize EditTrack::sizeHint() const +{ + return QSize(625,230); +} + + +QSizePolicy EditTrack::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditTrack::timeChangedData(const QTime &time) +{ + QString str; + + if(edit_timetype_box->isChecked()) { + str=QString(tr("Transition If Previous Cart Ends Before")); + edit_time_label-> + setText(QString().sprintf("%s %s:",(const char *)str, + (const char *)edit_time_edit->time(). + toString("hh:mm:ss.zzz").left(10))); + } +} + + +void EditTrack::timeToggledData(bool state) +{ + QString str; + + edit_time_edit->setEnabled(state); + edit_grace_group->setEnabled(state); + if(state) { + graceClickedData(edit_grace_group->selectedId()); + str=QString(tr("Transition If Previous Cart Ends Before")); + edit_time_label-> + setText(QString().sprintf("%s %s:",(const char *)str, + (const char *)edit_time_edit->time(). + toString("hh:mm:ss.zzz").left(10))); + } + else { + edit_grace_box->setDisabled(true); + edit_time_label->setText(tr("Transition Type:")); + } +} + + +void EditTrack::graceClickedData(int id) +{ + switch(id) { + case 0: + edit_grace_box->setDisabled(true); + break; + + case 1: + edit_grace_box->setDisabled(true); + break; + + case 2: + edit_grace_box->setEnabled(true); + break; + } +} + + +void EditTrack::selectTimeData(int id) +{ + if(id==RDLogLine::Relative) { + edit_time_edit->setDisabled(true); + edit_time_label->setDisabled(true); + edit_grace_box->setDisabled(true); + } + else { + edit_time_edit->setEnabled(true); + edit_time_label->setEnabled(true); + } +} + + +void EditTrack::okData() +{ + if(edit_timetype_box->isChecked()) { + edit_logline->setTimeType(RDLogLine::Hard); + edit_logline->setStartTime(RDLogLine::Logged,edit_time_edit->time()); + switch(edit_grace_group->selectedId()) { + case 0: + edit_logline->setGraceTime(0); + break; + + case 1: + edit_logline->setGraceTime(-1); + break; + + case 2: + edit_logline->setGraceTime(QTime().msecsTo(edit_grace_box->time())); + //edit_logline->setGraceTime(edit_grace_box->value()); + break; + } + } + else { + edit_logline->setTimeType(RDLogLine::Relative); + edit_logline->setStartTime(RDLogLine::Logged,QTime()); + edit_logline->setGraceTime(0); + } + edit_logline-> + setTransType((RDLogLine::TransType)edit_transtype_box->currentItem()); + edit_logline->setMarkerComment(edit_comment_edit->text()); + done(edit_logline->id()); +} + + +void EditTrack::cancelData() +{ + done(-1); +} + + +void EditTrack::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/rdlogedit/edit_track.h b/rdlogedit/edit_track.h new file mode 100644 index 00000000..a043959f --- /dev/null +++ b/rdlogedit/edit_track.h @@ -0,0 +1,78 @@ +// edit_track.h +// +// Edit a Rivendell Voice Track Log Entry +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_track.h,v 1.8 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_TRACK_H +#define EDIT_TRACK_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class EditTrack : public QDialog +{ + Q_OBJECT + public: + EditTrack(RDLogLine *,QWidget *parent=0,const char *name=0); + ~EditTrack(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void timeChangedData(const QTime &); + void timeToggledData(bool state); + void graceClickedData(int id); + void selectTimeData(int); + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + RDLogLine *edit_logline; + RDTimeEdit *edit_time_edit; + QLabel *edit_time_label; + QCheckBox *edit_timetype_box; + QLabel *edit_timetype_label; + QCheckBox *edit_time_box; + QComboBox *edit_transtype_box; + QCheckBox *edit_overlap_box; + QLabel *edit_overlap_label; + QLineEdit *edit_comment_edit; + QButtonGroup *edit_grace_group; + QFont normal_font; + QTimeEdit *edit_grace_box; + QLabel *edit_grace_label; +}; + + +#endif + diff --git a/rdlogedit/globals.h b/rdlogedit/globals.h new file mode 100644 index 00000000..ddab3510 --- /dev/null +++ b/rdlogedit/globals.h @@ -0,0 +1,52 @@ +// globals.h +// +// Global Variable Declarations for RDLogEdit +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: globals.h,v 1.8 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef GLOBALS_H +#define GLOBALS_H + +#include +#include +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#endif // WIN32 + +// +// Global Resources +// +extern RDStation *rdstation_conf; +extern RDUser *rduser; +extern RDRipc *rdripc; +extern RDConfig *log_config; +extern RDLogeditConf *rdlogedit_conf; +extern RDCartDialog *log_cart_dialog; +extern bool import_running; +extern RDSystem *rdsystem; +#ifndef WIN32 +extern RDCae *rdcae; +#endif // WIN32 + +#endif // GLOBALS_H diff --git a/rdlogedit/import_track.cpp b/rdlogedit/import_track.cpp new file mode 100644 index 00000000..932345b5 --- /dev/null +++ b/rdlogedit/import_track.cpp @@ -0,0 +1,200 @@ +// import_track.cpp +// +// Insert Audio for a Voice Track +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: import_track.cpp,v 1.7 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +extern RDStation *rdstation_conf; + + +ImportTrack::ImportTrack(QString *filter,QString *group, + QWidget *parent,const char *name) + : QDialog(parent,name,true,Qt::WStyle_Customize|Qt::WStyle_DialogBorder) +{ + setCaption(""); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont day_font=QFont("Helvetica",12,QFont::Normal); + day_font.setPixelSize(12); + + add_filter=filter; + add_group=group; + + // + // Title Label + // + QLabel *label=new QLabel(tr("Insert audio from a:"),this,"title_label"); + label->setGeometry(0,0,sizeHint().width(),30); + label->setFont(label_font); + label->setAlignment(AlignCenter); + + // + // Cart Button + // + QPushButton *button=new QPushButton(this,"cart_button"); + button->setGeometry(10,30,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("&Cart")); + button->setDisabled(true); + QString sql=QString("select CHANNEL from DECKS \ + where (CARD_NUMBER>=0)&&(CHANNEL>0)&&(CHANNEL<=9)"); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + button->setEnabled(true); + } + delete q; + connect(button,SIGNAL(clicked()),this,SLOT(cartData())); + + // + // Import Button + // + button=new QPushButton(this,"import_button"); + button->setGeometry(10,80,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("&File")); + button->setDisabled(true); + sql=QString("select CHANNEL from DECKS \ + where (CARD_NUMBER>=0)&&(CHANNEL>128)&&(CHANNEL<=137)"); + q=new RDSqlQuery(sql); + if(q->first()) { + button->setEnabled(true); + } + delete q; + connect(button,SIGNAL(clicked()),this,SLOT(importData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(10,140,sizeHint().width()-20,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + button->setDefault(true); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +ImportTrack::~ImportTrack() +{ +} + + +QSize ImportTrack::sizeHint() const +{ + return QSize(200,200); +} + + +QSizePolicy ImportTrack::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ImportTrack::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void ImportTrack::cartData() +{ +/* + EditRecording *recording= + new EditRecording(add_id,NULL,add_filter,this,"recording"); + if(recording->exec()<0) { + delete recording; + done(-1); + return; + } + delete recording; + done((int)RDRecording::Recording); +*/ +} + + +void ImportTrack::importData() +{ +/* + EditPlayout *playout= + new EditPlayout(add_id,NULL,add_filter,this,"playout"); + if(playout->exec()<0) { + delete playout; + done(-1); + return; + } + delete playout; + done((int)RDRecording::Playout); +*/ +} + + +void ImportTrack::cancelData() +{ + done(-1); +} + + +void ImportTrack::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Escape: + cancelData(); + break; + + default: + QWidget::keyPressEvent(e); + break; + } +} diff --git a/rdlogedit/import_track.h b/rdlogedit/import_track.h new file mode 100644 index 00000000..371a69c6 --- /dev/null +++ b/rdlogedit/import_track.h @@ -0,0 +1,66 @@ +// import_track.h +// +// Import Audio for a Voice Track +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: import_track.h,v 1.5 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef IMPORT_TRACK_H +#define IMPORT_TRACK_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class ImportTrack : public QDialog +{ + Q_OBJECT + public: + ImportTrack(QString *filter,QString *group, + QWidget *parent=0,const char *name=0); + ~ImportTrack(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + void closeEvent(QCloseEvent *e); + + private slots: + void cartData(); + void importData(); + void cancelData(); + + protected: + void keyPressEvent(QKeyEvent *e); + + private: + int add_id; + QString *add_filter; + QString *add_group; +}; + + +#endif // IMPORT_TRACK_H diff --git a/rdlogedit/list_listviewitem.cpp b/rdlogedit/list_listviewitem.cpp new file mode 100644 index 00000000..d5884f31 --- /dev/null +++ b/rdlogedit/list_listviewitem.cpp @@ -0,0 +1,118 @@ +// list_listviewitem.cpp +// +// A QListViewItem class for RDLogEdit. +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: list_listviewitem.cpp,v 1.6 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include +#include + +#include + +#include "../icons/greenball.xpm" +#include "../icons/redball.xpm" +#include "../icons/whiteball.xpm" + + +ListListViewItem::ListListViewItem(QListView *parent) + : QListViewItem(parent) +{ + list_track_column=-1; + list_tracks=-1; + list_total_tracks=0; + list_parent=parent; + + // + // Create Icons + // + list_whiteball_map=new QPixmap(whiteball_xpm); + list_greenball_map=new QPixmap(greenball_xpm); + list_redball_map=new QPixmap(redball_xpm); +} + + +int ListListViewItem::trackColumn() const +{ + return list_track_column; +} + + +void ListListViewItem::setTrackColumn(int col) +{ + list_track_column=col; +} + + +int ListListViewItem::tracks() const +{ + return list_tracks; +} + + +void ListListViewItem::setTracks(int quan) +{ + list_tracks=quan; +} + + +int ListListViewItem::totalTracks() const +{ + return list_total_tracks; +} + + +void ListListViewItem::setTotalTracks(int quan) +{ + list_total_tracks=quan; +} + + +void ListListViewItem::paintCell(QPainter *p,const QColorGroup &cg,int column, + int width,int align) +{ + if(column!=list_track_column) { + QListViewItem::paintCell(p,cg,column,width,align); + return; + } + QColor fg=cg.text(); + QColor bg=cg.base(); + if(isSelected()) { + fg=cg.highlightedText(); + bg=cg.highlight(); + } + QString str=QString().sprintf("%u / %u",list_tracks,list_total_tracks); + QPixmap *icon=list_whiteball_map; + if(list_total_tracks>0) { + if(list_tracks==list_total_tracks) { + icon=list_greenball_map; + } + else { + icon=list_redball_map; + } + } + QFontMetrics *m=new QFontMetrics(p->font()); + p->setBackgroundColor(bg); + p->eraseRect(0,0,width,height()); + p->setPen(fg); + p->drawPixmap(list_parent->itemMargin(),(height()-icon->size().height())/2, + *icon); + p->drawText(icon->size().width()+10,3*(height()-m->height())/2,str); + delete m; +} diff --git a/rdlogedit/list_listviewitem.h b/rdlogedit/list_listviewitem.h new file mode 100644 index 00000000..c6edf93d --- /dev/null +++ b/rdlogedit/list_listviewitem.h @@ -0,0 +1,57 @@ +// list_listviewitem.h +// +// A QListViewItem class for RDLogEdit. +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: list_listviewitem.h,v 1.5 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef LIST_LISTVIEWITEM_H +#define LIST_LISTVIEWITEM_H + +#include +#include + +#include + + +class ListListViewItem : public QListViewItem +{ + public: + ListListViewItem(QListView *parent); + int trackColumn() const; + void setTrackColumn(int col); + int tracks() const; + void setTracks(int quan); + int totalTracks() const; + void setTotalTracks(int quan); + void paintCell(QPainter *p,const QColorGroup &cg,int column, + int width,int align); + + private: + int list_track_column; + int list_tracks; + int list_total_tracks; + QPixmap *list_whiteball_map; + QPixmap *list_redball_map; + QPixmap *list_greenball_map; + QListView *list_parent; +}; + + +#endif // LIST_LISTVIEWITEM_H diff --git a/rdlogedit/list_logs.cpp b/rdlogedit/list_logs.cpp new file mode 100644 index 00000000..82c96c10 --- /dev/null +++ b/rdlogedit/list_logs.cpp @@ -0,0 +1,172 @@ +// list_logs.cpp +// +// Select a Rivendell Log +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_logs.cpp,v 1.9 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + + +ListLogs::ListLogs(QString *logname,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont button_font("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + + list_logname=logname; + + setCaption(tr("Select a Log")); + + // + // Log List + // + list_log_list=new QListView(this,"list_log_list"); + list_log_list->setGeometry(10,10, + sizeHint().width()-20,sizeHint().height()-80); + list_log_list->setAllColumnsShowFocus(true); + list_log_list->setItemMargin(5); + connect(list_log_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + list_log_list->addColumn(tr("NAME")); + list_log_list->setColumnAlignment(0,Qt::AlignLeft); + list_log_list->addColumn(tr("DESCRIPTION")); + list_log_list->setColumnAlignment(1,Qt::AlignLeft); + list_log_list->addColumn(tr("SERVICE")); + list_log_list->setColumnAlignment(2,Qt::AlignLeft); + + // + // Load Button + // + QPushButton *button=new QPushButton(this,"load_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okButtonData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(button_font); + button->setText(tr("&Cancel")); + button->setDefault(true); + connect(button,SIGNAL(clicked()),this,SLOT(cancelButtonData())); + + RefreshList(); +} + + +QSize ListLogs::sizeHint() const +{ + return QSize(400,300); +} + + +QSizePolicy ListLogs::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListLogs::closeEvent(QCloseEvent *e) +{ + done(1); +} + + +void ListLogs::doubleClickedData(QListViewItem *,const QPoint &,int) +{ + okButtonData(); +} + + +void ListLogs::okButtonData() +{ + QListViewItem *item=list_log_list->selectedItem(); + if(item==NULL) { + return; + } + *list_logname=item->text(0); + done(0); +} + + +void ListLogs::cancelButtonData() +{ + done(-1); +} + + +void ListLogs::RefreshList() +{ + RDSqlQuery *q; + QString sql; + QListViewItem *l; + + list_log_list->clear(); // Note: clear here, in case user has no perms. + + sql="select NAME,DESCRIPTION,SERVICE from LOGS where TYPE=0"; + + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec) { + QStringList services_list; + QString sql_where; + + services_list = rduser->services(); + if(services_list.size()==0) { + return; + } + + sql_where=" and ("; + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end(); ++it ) { + sql_where+=QString().sprintf("SERVICE=\"%s\"||", + (const char *)*it); + } + sql_where=sql_where.left(sql_where.length()-2); + sql_where+=")"; + + sql=sql+sql_where; + } // else no filter for RDStation::HostSec + + q=new RDSqlQuery(sql); + while(q->next()) { + l=new QListViewItem(list_log_list); + l->setText(0,q->value(0).toString()); + l->setText(1,q->value(1).toString()); + l->setText(2,q->value(2).toString()); + } + delete q; +} diff --git a/rdlogedit/list_logs.h b/rdlogedit/list_logs.h new file mode 100644 index 00000000..3f0bbfac --- /dev/null +++ b/rdlogedit/list_logs.h @@ -0,0 +1,54 @@ +// list_logs.h +// +// Select a Rivendell Log +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_logs.h,v 1.5 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_LOGS_H +#define LIST_LOGS_H + +#include +#include +#include +#include + + +class ListLogs : public QDialog +{ + Q_OBJECT + + public: + ListLogs(QString *logname,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void doubleClickedData(QListViewItem *,const QPoint &,int); + void closeEvent(QCloseEvent *); + void okButtonData(); + void cancelButtonData(); + + private: + void RefreshList(); + QListView *list_log_list; + QString *list_logname; +}; + + +#endif diff --git a/rdlogedit/list_reports.cpp b/rdlogedit/list_reports.cpp new file mode 100644 index 00000000..d640931a --- /dev/null +++ b/rdlogedit/list_reports.cpp @@ -0,0 +1,338 @@ +// list_reports.cpp +// +// List and Generate Log Reports +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: list_reports.cpp,v 1.7 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +ListReports::ListReports(const QString &logname,const QString &description, + const QString service_name,const QDate &start_date, + const QDate &end_date,bool auto_refresh, + RDLogEvent *events, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + list_log_name=logname; + list_description=description; + list_service_name=service_name; + list_start_date=start_date; + list_end_date=end_date; + list_auto_refresh=auto_refresh; + list_events=events; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("RDLibrary Reports")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont select_font=QFont("Helvetica",12,QFont::Normal); + select_font.setPixelSize(12); + + // + // Reports List + // + list_reports_box=new QComboBox(this,"list_reports_box"); + list_reports_box->setGeometry(50,10,sizeHint().width()-60,19); + list_reports_box->insertItem(tr("Log Listing")); + list_reports_box->insertItem(tr("Log Exception Report")); + QLabel *list_reports_label= + new QLabel(list_reports_box,tr("Type:"), + this,"list_reports_label"); + list_reports_label->setGeometry(10,10,35,19); + list_reports_label->setFont(font); + list_reports_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Effective Date + // + list_date_edit=new QDateEdit(this,"list_date_edit"); + list_date_edit->setGeometry(110,34,100,19); + QLabel *list_date_label= + new QLabel(list_date_edit,tr("Effective Date:"), + this,"list_date_label"); + list_date_label->setGeometry(10,34,95,19); + list_date_label->setFont(font); + list_date_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QPushButton *button=new QPushButton(this,"select_button"); + button->setGeometry(215,32,60,24); + button->setFont(select_font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectDateData())); + list_date_edit->setDate(QDate::currentDate()); + + // + // Generate Button + // + button=new QPushButton(this,"generate_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(font); + button->setText(tr("&Generate")); + connect(button,SIGNAL(clicked()),this,SLOT(generateData())); + + // + // Close Button + // + button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(font); + button->setText(tr("&Close")); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +ListReports::~ListReports() +{ +} + + +QSize ListReports::sizeHint() const +{ + return QSize(350,132); +} + + +QSizePolicy ListReports::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListReports::selectDateData() +{ + QDate today=QDate::currentDate(); + QDate date=list_date_edit->date(); + RDDateDialog *d=new RDDateDialog(today.year()-1,today.year()+1,this); + if(d->exec(&date)==0) { + list_date_edit->setDate(date); + } + delete d; +} + + +void ListReports::generateData() +{ + QString report; + + switch(list_reports_box->currentItem()) { + case 0: // Event Report + GenerateLogReport(&report); + break; + + case 1: // XLoad Report + GenerateExceptionReport(&report,list_date_edit->date()); + break; + + default: + return; + } + if(!report.isEmpty()) { + RDTextFile(report); + } +} + + +void ListReports::closeData() +{ + done(-1); +} + + +void ListReports::GenerateLogReport(QString *report) +{ + // + // Generate Header + // + QString refresh="No "; + if(list_auto_refresh) { + refresh="Yes"; + } + QString start_date=tr("[none]"); + if(!list_start_date.isNull()) { + start_date=list_start_date.toString("MM/dd/yyyy"); + } + QString end_date=tr("[none]"); + if(!list_end_date.isNull()) { + end_date=list_end_date.toString("MM/dd/yyyy"); + } + *report=" Rivendell Log Listing\n"; + *report+=QString(). + sprintf("Generated: %s Log: %-30s Description: %s\n", + (const char *)QDateTime(QDate::currentDate(),QTime::currentTime()). + toString("MM/dd/yyyy - hh:mm:ss"), + (const char *)list_log_name.left(30), + (const char *)list_description.left(27)); + *report+=QString(). + sprintf("Service: %-10s AutoRefresh Enabled: %-3s Start Date: %-10s End Date: %s\n", + (const char *)list_service_name, + (const char *)refresh, + (const char *)start_date,(const char *)end_date); + *report+="\n"; + *report+="-Type-- -Time---- Trans -Cart- -Group---- -Length- -Title--------------------------- -Artist----------------------- -Source----- Line\n"; + + // + // Generate Event Listing + // + RDLogLine *logline; + for(int i=0;isize();i++) { + logline=list_events->logLine(i); + + // + // Type + // + *report+=QString().sprintf("%-7s ", + (const char *)RDLogLine::typeText(logline->type())); + + // + // Time + // + if(logline->timeType()==RDLogLine::Hard) { + *report+="H"; + } + else { + *report+=" "; + } + if(!logline->startTime(RDLogLine::Imported).isNull()) { + *report+=QString().sprintf("%-8s ", + (const char *)logline-> + startTime(RDLogLine::Logged). + toString("hh:mm:ss")); + } + else { + *report+=" "; + } + + // + // Transition Type + // + *report+=QString().sprintf("%-5s ", + (const char *)RDLogLine::transText(logline->transType()).left(5)); + + switch(logline->type()) { + case RDLogLine::Cart: + case RDLogLine::Macro: + *report+=QString().sprintf("%06u ",logline->cartNumber()); + *report+=QString().sprintf("%-10s ", + (const char *)logline->groupName()); + *report+=QString().sprintf("%8s ",(const char *) + RDGetTimeLength(logline->forcedLength(), + false,false)); + *report+= + QString().sprintf("%-33s ", + (const char *)logline->title().left(33)); + *report+= + QString().sprintf("%-30s ", + (const char *)logline->artist().left(30)); + break; + + case RDLogLine::Marker: + case RDLogLine::Track: + *report+=" "; + *report+=" "; + *report+=" :00 "; + *report+= + QString().sprintf("%-30s ", + (const char *)logline->markerComment().left(30)); + *report+=" "; + break; + + case RDLogLine::TrafficLink: + *report+=" "; + *report+=" "; + *report+=" :00 "; + *report+="Traffic Import "; + *report+=" "; + break; + + case RDLogLine::MusicLink: + *report+=" "; + *report+=" "; + *report+=" :00 "; + *report+="Music Import "; + *report+=" "; + break; + + + case RDLogLine::Chain: + *report+=" "; + *report+=" "; + *report+=" "; + *report+= + QString().sprintf("%-30s ", + (const char *)logline->markerLabel().left(30)); + *report+=" "; + break; + break; + + case RDLogLine::OpenBracket: + case RDLogLine::CloseBracket: + case RDLogLine::UnknownType: + break; + } + + // + // Source + // + *report+=QString().sprintf("%-12s ", + (const char *)RDLogLine::sourceText(logline->source())); + + // + // Line + // + *report+=QString().sprintf("%4d",i); + + // + // End of Line + // + *report+="\n"; + } +} + + +void ListReports::GenerateExceptionReport(QString *report,const QDate &date) +{ + int errs=list_events->validate(report,date); + if(errs==0) { + QMessageBox::information(this,tr("Log Check"),tr("No exceptions found.")); + *report=""; + } +} diff --git a/rdlogedit/list_reports.h b/rdlogedit/list_reports.h new file mode 100644 index 00000000..04017166 --- /dev/null +++ b/rdlogedit/list_reports.h @@ -0,0 +1,66 @@ +// list_reports.h +// +// List and Generate Log Reports +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: list_reports.h,v 1.5 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_REPORTS_H +#define LIST_REPORTS_H + +#include +#include +#include +#include + +#include +#include + +class ListReports : public QDialog +{ + Q_OBJECT + public: + ListReports(const QString &logname,const QString &description, + const QString service_name,const QDate &start_date, + const QDate &end_date,bool auto_refresh,RDLogEvent *events, + QWidget *parent=0,const char *name=0); + ~ListReports(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void selectDateData(); + void generateData(); + void closeData(); + + private: + void GenerateLogReport(QString *report); + void GenerateExceptionReport(QString *report,const QDate &date); + QComboBox *list_reports_box; + QString list_log_name; + QString list_description; + QString list_service_name; + QDate list_start_date; + QDate list_end_date; + bool list_auto_refresh; + RDLogEvent *list_events; + QDateEdit *list_date_edit; +}; + + +#endif // LIST_REPORTS_H diff --git a/rdlogedit/log_listview.cpp b/rdlogedit/log_listview.cpp new file mode 100644 index 00000000..fc6983e9 --- /dev/null +++ b/rdlogedit/log_listview.cpp @@ -0,0 +1,112 @@ +// log_listview.cpp +// +// The Log ListView widget for RDLogEdit. +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: log_listview.cpp,v 1.10 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include + +#include + + +LogListView::LogListView(QWidget *parent,const char *name) + : RDListView(parent,name) +{ + log_parent=parent; + + // + // Right Button Menu + // + log_menu=new QPopupMenu(this,"log_menu"); + connect(log_menu,SIGNAL(aboutToShow()),this,SLOT(aboutToShowData())); + log_menu->insertItem(tr("PLAY Transition"),this,SLOT(playData()),0,0); + log_menu->insertItem(tr("SEGUE Transition"),this,SLOT(segueData()),0,1); + log_menu->insertItem(tr("STOP Transition"),this,SLOT(stopData()),0,2); +} + + +void LogListView::aboutToShowData() +{ + RDListViewItem *item=(RDListViewItem *)selectedItem(); + log_menu->setItemEnabled(0,item->line()!=TRACKER_MAX_LINENO); + log_menu->setItemEnabled(1,item->line()!=TRACKER_MAX_LINENO); + log_menu->setItemEnabled(2,item->line()!=TRACKER_MAX_LINENO); + log_transition_type=item->text(2).lower(); + log_menu->setItemChecked(0,log_transition_type==tr("play")); + log_menu->setItemChecked(1,log_transition_type==tr("segue")); + log_menu->setItemChecked(2,log_transition_type==tr("stop")); +} + + +void LogListView::playData() +{ + if(log_transition_type=="play") { + return; + } + emit transitionChanged(((RDListViewItem *)selectedItem())->line(), + RDLogLine::Play); +} + + +void LogListView::segueData() +{ + if(log_transition_type=="segue") { + return; + } + emit transitionChanged(((RDListViewItem *)selectedItem())->line(), + RDLogLine::Segue); +} + + +void LogListView::stopData() +{ + if(log_transition_type=="stop") { + return; + } + emit transitionChanged(((RDListViewItem *)selectedItem())->line(), + RDLogLine::Stop); +} + + +void LogListView::contentsMousePressEvent(QMouseEvent *e) +{ + QListView::contentsMousePressEvent(e); + log_menu_item=(RDListViewItem *)selectedItem(); + switch(e->button()) { + case QMouseEvent::RightButton: + //log_menu->setGeometry(log_parent->geometry().x()+ + // geometry().x()+e->pos().x()+2, + // log_parent->geometry().y()+ + // geometry().y()+e->pos().y()+ + // header()->geometry().height()+2, + // log_menu->sizeHint().width(), + // log_menu->sizeHint().height()); + log_menu->setGeometry(e->globalX(),e->globalY(), + log_menu->sizeHint().width(), + log_menu->sizeHint().height()); + + log_menu->exec(); + break; + + default: + e->ignore(); + break; + } +} diff --git a/rdlogedit/log_listview.h b/rdlogedit/log_listview.h new file mode 100644 index 00000000..127a1a9b --- /dev/null +++ b/rdlogedit/log_listview.h @@ -0,0 +1,64 @@ +// log_listview.h +// +// The Log ListView widget for RDLogEdit. +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: log_listview.h,v 1.7 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef LOG_LISTVIEW_H +#define LOG_LISTVIEW_H + +#include +#include +#include + +#include +#include +#include + +#define TRACKER_MAX_LINENO 2147483647 + +class LogListView : public RDListView +{ + Q_OBJECT + + public: + LogListView(QWidget *parent,const char *name=0); + + private slots: + void aboutToShowData(); + void playData(); + void segueData(); + void stopData(); + + signals: + void transitionChanged(int line,RDLogLine::TransType trans); + + protected: + void contentsMousePressEvent(QMouseEvent *e); + + private: + QPopupMenu *log_menu; + RDListViewItem *log_menu_item; + QWidget *log_parent; + QString log_transition_type; +}; + + +#endif // LOG_LISTVIEW_H diff --git a/rdlogedit/rdlogedit.cpp b/rdlogedit/rdlogedit.cpp new file mode 100644 index 00000000..08448682 --- /dev/null +++ b/rdlogedit/rdlogedit.cpp @@ -0,0 +1,913 @@ +// rdlogedit.cpp +// +// The Log Editor Utility for Rivendell. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: rdlogedit.cpp,v 1.77.4.9.2.1 2014/05/21 18:19:43 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WIN32 +#include +#include +#include +#include +#endif // WIN32 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifndef WIN32 +#include +#endif // WIN32 + +// +// Icons +// +#include "../icons/rivendell-22x22.xpm" +#include "../icons/greencheckmark.xpm" +#include "../icons/redx.xpm" +#include "../icons/greenball.xpm" +#include "../icons/redball.xpm" +#include "../icons/whiteball.xpm" + +// +// Global Resources +// +RDStation *rdstation_conf; +RDUser *rduser; +RDRipc *rdripc; +RDConfig *log_config; +RDLogeditConf *rdlogedit_conf; +RDSystem *rdsystem; +RDCartDialog *log_cart_dialog; +bool import_running=false; +#ifndef WIN32 +RDCae *rdcae; + + +void SigHandler(int signo) +{ + pid_t pLocalPid; + + switch(signo) { + case SIGCHLD: + pLocalPid=waitpid(-1,NULL,WNOHANG); + while(pLocalPid>0) { + pLocalPid=waitpid(-1,NULL,WNOHANG); + } + import_running=false; + signal(SIGCHLD,SigHandler); + return; + } +} +#endif // WIN32 + + +MainWidget::MainWidget(QWidget *parent,const char *name,WFlags f) + :QMainWindow(parent,name,f) +{ + QString str1; + QString str2; + log_log_list=NULL; + bool skip_db_check=false; + unsigned schema=0; + QString sql; + RDSqlQuery *q; + + // + // Read Command Options + // + RDCmdSwitch *cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdlogedit","\n"); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + } + delete cmd; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Ensure that the system daemons are running + // +#ifndef WIN32 + RDInitializeDaemons(); +#endif // WIN32 + + // + // Load Local Configs + // + log_config=new RDConfig(); + log_config->load(); + str1=QString("RDLogEdit")+"v"+VERSION+" - "+tr("Host"); + str2=tr("User")+": ["+tr("Unknown")+"]"; + setCaption(QString().sprintf("%s: %s, %s",(const char *)str1, + (const char *)log_config->stationName(), + (const char *)str2)); + log_import_path=RDGetHomeDir(); + + // + // Open Database + // + QString err; + log_db=RDInitDb(&schema,&err); + if(!log_db) { + QMessageBox::warning(this,tr("Can't Connect"),err); + exit(0); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { +#ifdef WIN32 + QMessageBox::warning(this,tr("RDLogEdit -- Database Skew"), + tr("This version of RDLogEdit is incompatible with the version installed on the server.\nSee your system administrator for an update!")); +#else + fprintf(stderr, + "rdlogedit: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); +#endif // WIN32 + exit(256); + } + + // + // Allocate Global Resources + // + rdstation_conf=new RDStation(log_config->stationName()); + + // + // CAE Connection + // +#ifndef WIN32 + rdcae=new RDCae(rdstation_conf,log_config,parent,name); + rdcae->connectHost(); +#endif // WIN32 + + // + // RIPC Connection + // +#ifndef WIN32 + rdripc=new RDRipc(log_config->stationName()); + connect(rdripc,SIGNAL(connected(bool)),this,SLOT(connectedData(bool))); + connect(rdripc,SIGNAL(userChanged()),this,SLOT(userData())); + rdripc->connectHost("localhost",RIPCD_TCP_PORT,log_config->password()); +#else + rdripc=NULL; +#endif // WIN32 + + // + // System Configuration + // + rdsystem=new RDSystem(); + + // + // RDLogEdit Configuration + // + rdlogedit_conf=new RDLogeditConf(log_config->stationName()); + + // + // Cart Picker + // +#ifdef WIN32 + log_cart_dialog=new RDCartDialog(&log_filter,&log_group,&log_schedcode, + NULL,NULL,rdstation_conf,rdsystem, + log_config,this); +#else + log_cart_dialog=new RDCartDialog(&log_filter,&log_group,&log_schedcode, + rdcae,rdripc,rdstation_conf,rdsystem, + log_config,this); +#endif + + // + // User + // +#ifndef WIN32 + rduser=NULL; + + // + // Load Audio Assignments + // + RDSetMixerPorts(log_config->stationName(),rdcae); +#else + rduser=new RDUser(RD_USER_LOGIN_NAME); +#endif // WIN32 + + // + // Create Fonts + // + QFont default_font("Helvetica",12,QFont::Normal); + default_font.setPixelSize(12); + qApp->setFont(default_font); + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + + // + // Create Icons + // + log_rivendell_map=new QPixmap(rivendell_xpm); + setIcon(*log_rivendell_map); + log_greencheckmark_map=new QPixmap(greencheckmark_xpm); + log_redx_map=new QPixmap(redx_xpm); + log_whiteball_map=new QPixmap(whiteball_xpm); + log_greenball_map=new QPixmap(greenball_xpm); + log_redball_map=new QPixmap(redball_xpm); + + // + // Service Selector + // + log_service_box=new QComboBox(this); + log_service_box->setFont(default_font); + connect(log_service_box,SIGNAL(activated(const QString &)), + this,SLOT(filterChangedData(const QString &))); + log_service_box->insertItem(tr("ALL")); + sql="select NAME from SERVICES order by NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + log_service_box->insertItem(q->value(0).toString()); + } + delete q; + log_service_label=new QLabel(log_service_box,tr("Service")+":",this); + log_service_label->setFont(button_font); + log_service_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Filter + // + log_filter_edit=new QLineEdit(this); + log_filter_edit->setFont(default_font); + connect(log_filter_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(filterChangedData(const QString &))); + log_filter_label=new QLabel(log_filter_edit,tr("Filter")+":",this); + log_filter_label->setFont(button_font); + log_filter_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + log_filter_button=new QPushButton(tr("Clear"),this); + log_filter_button->setFont(button_font); + connect(log_filter_button,SIGNAL(clicked()),this,SLOT(filterClearedData())); + + // + // Log List + // + log_log_list=new QListView(this,"log_log_list"); + log_log_list->setFont(default_font); + log_log_list->setAllColumnsShowFocus(true); + log_log_list->setItemMargin(5); + connect(log_log_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(logDoubleclickedData(QListViewItem *,const QPoint &,int))); + log_log_list->addColumn(""); + log_log_list->setColumnAlignment(0,Qt::AlignCenter); + log_log_list->addColumn(tr("LOG NAME")); + log_log_list->setColumnAlignment(1,Qt::AlignHCenter); + log_log_list->addColumn(tr("DESCRIPTION")); + log_log_list->setColumnAlignment(2,Qt::AlignLeft); + log_log_list->addColumn(tr("SERVICE")); + log_log_list->setColumnAlignment(3,Qt::AlignLeft); + log_log_list->addColumn(tr("MUSIC")); + log_log_list->setColumnAlignment(4,Qt::AlignCenter); + log_log_list->addColumn(tr("TRAFFIC")); + log_log_list->setColumnAlignment(5,Qt::AlignCenter); + log_log_list->addColumn(tr("TRACKS")); + log_log_list->setColumnAlignment(6,Qt::AlignHCenter); + log_log_list->addColumn(tr("VALID FROM")); + log_log_list->setColumnAlignment(7,Qt::AlignHCenter); + log_log_list->addColumn(tr("VALID TO")); + log_log_list->setColumnAlignment(8,Qt::AlignHCenter); + log_log_list->addColumn(tr("AUTO REFRESH")); + log_log_list->setColumnAlignment(9,Qt::AlignHCenter); + log_log_list->addColumn(tr("ORIGIN")); + log_log_list->setColumnAlignment(10,Qt::AlignLeft); + log_log_list->addColumn(tr("LAST LINKED")); + log_log_list->setColumnAlignment(11,Qt::AlignLeft); + log_log_list->addColumn(tr("LAST MODIFIED")); + log_log_list->setColumnAlignment(12,Qt::AlignLeft); + + RefreshList(); + + // + // Add Button + // + log_add_button=new QPushButton(this,"log_add_button"); + log_add_button->setFont(button_font); + log_add_button->setText(tr("&Add")); + connect(log_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + log_edit_button=new QPushButton(this,"log_edit_button"); + log_edit_button->setFont(button_font); + log_edit_button->setText(tr("&Edit")); + connect(log_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + log_delete_button=new QPushButton(this,"log_delete_button"); + log_delete_button->setFont(button_font); + log_delete_button->setText(tr("&Delete")); + connect(log_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Tracker Button + // + log_track_button=new QPushButton(this,"log_track_button"); + log_track_button->setFont(button_font); + log_track_button->setText(tr("Voice\n&Tracker")); + connect(log_track_button,SIGNAL(clicked()),this,SLOT(trackData())); +#ifdef WIN32 + log_track_button->hide(); +#endif + + // + // Log Report Button + // + log_report_button=new QPushButton(this,"log_report_button"); + log_report_button->setFont(button_font); + log_report_button->setText(tr("Log\nReport")); + connect(log_report_button,SIGNAL(clicked()),this,SLOT(reportData())); + + // + // Close Button + // + log_close_button=new QPushButton(this,"log_close_button"); + log_close_button->setFont(button_font); + log_close_button->setText(tr("&Close")); + connect(log_close_button,SIGNAL(clicked()),this,SLOT(quitMainWidget())); + +#ifndef WIN32 + // + // Setup Signal Handling + // + ::signal(SIGCHLD,SigHandler); +#endif // WIN32 +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(640,480); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::connectedData(bool state) +{ +} + + +void MainWidget::userData() +{ + QString str1; + QString str2; + + str1=QString("RDLogEdit")+" v"+VERSION+" - "+tr("Host"); + str2=QString(tr("User")); + setCaption(str1+": "+log_config->stationName()+", "+str2+": "+ + rdripc->user()); + if(rduser!=NULL) { + delete rduser; + } + rduser=new RDUser(rdripc->user()); + + // + // Set Control Perms + // + log_add_button->setEnabled(rduser->createLog()); + log_delete_button->setEnabled(rduser->deleteLog()); + log_track_button->setEnabled(rduser->voicetrackLog()); + + // Update the list of logs if applicable. + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec) { + RefreshList(); + } +} + + +void MainWidget::addData() +{ + QString logname; + QString svcname; + RDSqlQuery *q; + QString sql; + std::vector newlogs; + RDAddLog *log; + + if(rduser->createLog()) { + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec) { + log=new RDAddLog(&logname,&svcname,NULL,tr("Add Log"),this,"add_log", + rduser); + } else { // RDStation::HostSec + log=new RDAddLog(&logname,&svcname,NULL,tr("Add Log"),this,"add_log"); + } + if(log->exec()!=0) { + delete log; + return; + } + delete log; + sql=QString().sprintf("INSERT INTO LOGS SET NAME=\"%s\",TYPE=0,\ + DESCRIPTION=\"%s log\",ORIGIN_USER=\"%s\",\ + ORIGIN_DATETIME=NOW(),LINK_DATETIME=NOW(),\ + SERVICE=\"%s\"", + (const char *)logname, + (const char *)logname, +#ifdef WIN32 + RD_USER_LOGIN_NAME, +#else + (const char *)rdripc->user(), +#endif // WIN32 + (const char *)svcname); + q=new RDSqlQuery(sql); + if(!q->isActive()) { + QMessageBox::warning(this,tr("Log Exists"),tr("Log Already Exists!")); + delete q; + return; + } + delete q; + RDCreateLogTable(RDLog::tableName(logname)); + EditLog *editlog=new EditLog(logname,&log_clipboard,&newlogs,this); + editlog->exec(); + delete editlog; + ListListViewItem *item=new ListListViewItem(log_log_list); + item->setText(1,logname); + RefreshItem(item); + log_log_list->setSelected(item,true); + log_log_list->ensureItemVisible((QListViewItem *)item); + for(unsigned i=0;isetText(1,newlogs[i]); + RefreshItem(item); + } + } +} + + +void MainWidget::editData() +{ + ListListViewItem *item=(ListListViewItem *)log_log_list->selectedItem(); + std::vector newlogs; + + if(item==NULL) { + return; + } + EditLog *log=new EditLog(item->text(1),&log_clipboard,&newlogs,this); + log->exec(); + delete log; + RefreshItem(item); + for(unsigned i=0;isetText(1,newlogs[i]); + RefreshItem(item); + } +} + + +void MainWidget::deleteData() +{ + QString filename; + QString str1; + QString str2; + unsigned tracks=0; + QListViewItem *item=log_log_list->selectedItem(); + + if(item==NULL) { + return; + } + if(rduser->deleteLog()) { + if(QMessageBox::question(this,tr("Delete Log"), + tr(QString().sprintf("Are you sure you want to delete the \"%s\" log?", + (const char *)item->text(1))), + QMessageBox::Yes, + QMessageBox::No)!=QMessageBox::Yes) { + return; + } + RDLog *log=new RDLog(item->text(1)); + if((tracks=log->completedTracks())>0) { + str1=QString(tr("This will also delete the")); + str2=QString(tr("voice tracks associated with this log.\nContinue?")); + if(QMessageBox::question(this,tr("Tracks Exist"), + QString().sprintf("%s %u %s", + (const char *)str1, + tracks, + (const char *)str2), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + delete log; + return; + } + } + if(!log->remove(rdstation_conf,rduser,log_config)) { + QMessageBox::warning(this,tr("RDLogEdit"), + tr("Unable to delete log, audio deletion error!")); + delete log; + return; + } + delete log; + delete item; + } +} + + +void MainWidget::trackData() +{ +#ifndef WIN32 + ListListViewItem *item=(ListListViewItem *)log_log_list->selectedItem(); + if(item==NULL) { + return; + } + VoiceTracker *dialog=new VoiceTracker(item->text(1),&log_import_path); + dialog->exec(); + delete dialog; + RefreshItem(item); +#endif // WIN32 +} + + +void MainWidget::reportData() +{ + QString report; + QString sql; + RDSqlQuery *q; + + // + // Generate Header + // + report=" Rivendell Log Listing\n"; + report+=QString(). + sprintf("Generated: %s\n", + (const char *)QDateTime(QDate::currentDate(),QTime::currentTime()). + toString("MM/dd/yyyy - hh:mm:ss")); + report+="\n"; + report+="Rdy -Log Name-------------------- -Description----------------- -Service------------ Mus Tfc Tracks- Start Date -End Date- -Mod Date-\n"; + + // + // Report Body + // + sql="select NAME,DESCRIPTION,SERVICE,MUSIC_LINKS,MUSIC_LINKED,\ + TRAFFIC_LINKS,TRAFFIC_LINKED,COMPLETED_TRACKS,SCHEDULED_TRACKS,\ + START_DATE,END_DATE,MODIFIED_DATETIME from LOGS order by NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + // + // Summary Status + // + if(((q->value(3).toInt()==0)||(q->value(4).toString()=="Y"))&& + ((q->value(5).toInt()==0)||(q->value(6).toString()=="Y"))&& + (q->value(7).toUInt()==q->value(8).toUInt())) { + report+=" Y "; + } + else { + report+=" N "; + } + + // + // Log Name + // + report+=QString().sprintf("%-29s ", + (const char *)q->value(0).toString().left(29)); + + // + // Description + // + report+=QString().sprintf("%-29s ", + (const char *)q->value(1).toString().left(29)); + + // + // Service + // + report+=QString().sprintf("%-20s ", + (const char *)q->value(2).toString().left(20)); + + // + // Music Linked + // + if(q->value(3).toInt()>0) { + report+=QString().sprintf(" %s ", + (const char *)q->value(4).toString()); + } + else { + report+="n/a "; + } + + // + // Traffic Linked + // + if(q->value(5).toInt()>0) { + report+=QString().sprintf(" %s ", + (const char *)q->value(6).toString()); + } + else { + report+="n/a "; + } + + // + // Voice Tracks + // + report+= + QString().sprintf("%3u/%3u ",q->value(8).toUInt(),q->value(7).toUInt()); + + // + // Start Date + // + if(q->value(9).toDate().isNull()) { + report+="[none] "; + } + else { + report+=QString().sprintf("%s ", + (const char *)q->value(9).toDate().toString("MM/dd/yyyy")); + } + + // + // End Date + // + if(q->value(10).toDate().isNull()) { + report+="[none] "; + } + else { + report+=QString().sprintf("%s ", + (const char *)q->value(10).toDate().toString("MM/dd/yyyy")); + } + + // + // Last Modified Date + // + report+=QString().sprintf("%s", + (const char *)q->value(11).toDate().toString("MM/dd/yyyy")); + + // + // End of Line + // + report+="\n"; + } + delete q; + + RDTextFile(report); +} + + +void MainWidget::filterChangedData(const QString &str) +{ + RefreshList(); +} + + +void MainWidget::filterClearedData() +{ + log_filter_edit->clear(); + filterChangedData(""); +} + + +void MainWidget::logDoubleclickedData(QListViewItem *,const QPoint &,int) +{ + editData(); +} + + +void MainWidget::quitMainWidget() +{ + log_db->removeDatabase(log_config->mysqlDbname()); + exit(0); +} + + +void MainWidget::resizeEvent(QResizeEvent *e) +{ + if(log_log_list==NULL) { + return; + } + log_service_label->setGeometry(10,10,70,20); + log_service_box->setGeometry(85,10,140,20); + log_filter_label->setGeometry(230,10,50,20); + log_filter_edit->setGeometry(285,10,size().width()-360,20); + log_filter_button->setGeometry(size().width()-60,8,50,25); + log_log_list->setGeometry(10,37,size().width()-20,size().height()-107); + log_add_button->setGeometry(10,size().height()-55,80,50); + log_edit_button->setGeometry(100,size().height()-55,80,50); + log_delete_button->setGeometry(190,size().height()-55,80,50); + log_track_button->setGeometry(300,size().height()-55,80,50); + log_report_button->setGeometry(400,size().height()-55,80,50); + log_close_button->setGeometry(size().width()-90,size().height()-55,80,50); +} + + +void MainWidget::RefreshItem(ListListViewItem *item) +{ + RDSqlQuery *q; + QString sql; + + sql=QString().sprintf("select DESCRIPTION,SERVICE,START_DATE,END_DATE,\ + ORIGIN_USER,ORIGIN_DATETIME,COMPLETED_TRACKS,\ + SCHEDULED_TRACKS,MUSIC_LINKS,MUSIC_LINKED,\ + TRAFFIC_LINKS,TRAFFIC_LINKED,LINK_DATETIME,\ + MODIFIED_DATETIME,AUTO_REFRESH from LOGS\ + where (TYPE=0)&&(LOG_EXISTS=\"Y\")&&(NAME=\"%s\")", + (const char *)item->text(1)); + q=new RDSqlQuery(sql); + if(q->next()) { + item->setText(2,q->value(0).toString()); + item->setText(3,q->value(1).toString()); + if((q->value(6).toInt()==q->value(7).toInt())&& + ((q->value(8).toInt()==0)||(q->value(9).toString()=="Y"))&& + ((q->value(10).toInt()==0)||(q->value(11).toString()=="Y"))) { + item->setPixmap(0,*log_greencheckmark_map); + } + else { + item->setPixmap(0,*log_redx_map); + } + if(q->value(8).toInt()==0) { + item->setPixmap(4,*log_whiteball_map); + } + else { + if(q->value(9).toString()=="Y") { + item->setPixmap(4,*log_greenball_map); + } + else { + item->setPixmap(4,*log_redball_map); + } + } + if(q->value(10).toInt()==0) { + item->setPixmap(5,*log_whiteball_map); + } + else { + if(q->value(11).toString()=="Y") { + item->setPixmap(5,*log_greenball_map); + } + else { + item->setPixmap(5,*log_redball_map); + } + } + item->setTracks(q->value(6).toInt()); + item->setTotalTracks(q->value(7).toInt()); + item->setTrackColumn(6); + if(!q->value(2).toDate().isNull()) { + item->setText(7,q->value(2).toDate().toString("MM/dd/yyyy")); + } + else { + item->setText(7,tr("Always")); + } + if(!q->value(3).toDate().isNull()) { + item->setText(8,q->value(3).toDate().toString("MM/dd/yyyy")); + } + else { + item->setText(8,tr("TFN")); + } + item->setText(9,q->value(14).toString()); + item->setText(10,q->value(4).toString()+QString(" - ")+ + q->value(5).toDateTime().toString("MM/dd/yyyy - hh:mm:ss")); + item-> + setText(11,q->value(12).toDateTime().toString("MM/dd/yyyy - hh:mm:ss")); + item-> + setText(12,q->value(13).toDateTime().toString("MM/dd/yyyy - hh:mm:ss")); + } + delete q; +} + + +void MainWidget::RefreshList() +{ + RDSqlQuery *q; + QString sql; + ListListViewItem *item; + + log_log_list->clear(); // Note: clear here, in case user has no perms. + + sql="select NAME from LOGS where (TYPE=0)&&(LOG_EXISTS=\"Y\")"; + + if(log_service_box->currentItem()!=0) { + sql+="&&(SERVICE=\""+RDEscapeString(log_service_box->currentText())+"\")"; + } + QString filter=log_filter_edit->text(); + if(!filter.isEmpty()) { + sql+="&&((NAME like \"%%"+RDEscapeString(filter)+"%%\")||"; + sql+="(DESCRIPTION like \"%%"+RDEscapeString(filter)+"%%\")||"; + sql+="(SERVICE like \"%%"+RDEscapeString(filter)+"%%\"))"; + } + + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec + && rduser != NULL) { + QStringList services_list; + QString sql_where; + + services_list = rduser->services(); + if(services_list.size()==0) { + return; + } + + sql_where=" and ("; + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end(); ++it ) { + sql_where+=QString().sprintf("SERVICE=\"%s\"||", + (const char *)*it); + } + sql_where=sql_where.left(sql_where.length()-2); + sql_where+=")"; + + sql=sql+sql_where; + } // else no filter for RDStation::HostSec + + q=new RDSqlQuery(sql); + while(q->next()) { + item=new ListListViewItem(log_log_list); + item->setText(1,q->value(0).toString()); + RefreshItem(item); + } + delete q; +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QString tr_path; + QString qt_path; +#ifdef WIN32 + QSettings settings; + settings.insertSearchPath(QSettings::Windows,"/SalemRadioLabs"); + tr_path=QString().sprintf("%s\\", + (const char *)settings. + readEntry("/Rivendell/InstallDir")); + qt_path=tr_path; +#else + tr_path=QString(PREFIX)+QString("/share/rivendell/"); + qt_path=QString(QTDIR)+QString("/translation/"); +#endif // WIN32 + QTranslator qt(0); + qt.load(qt_path+QString("qt_")+QTextCodec::locale(),"."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(tr_path+QString("librd_")+QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(tr_path+QString("librdhpi_")+QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(tr_path+QString("rdlogedit_")+QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(w->geometry().x(),w->geometry().y()), + w->sizeHint())); + w->show(); + return a.exec(); +} diff --git a/rdlogedit/rdlogedit.h b/rdlogedit/rdlogedit.h new file mode 100644 index 00000000..9a726ede --- /dev/null +++ b/rdlogedit/rdlogedit.h @@ -0,0 +1,106 @@ +// rdlogedit.h +// +// The Log Editor Utility for Rivendell. +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: rdlogedit.h,v 1.28.4.1 2014/01/08 23:32:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDLOGEDIT_H +#define RDLOGEDIT_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + + +class MainWidget : public QMainWindow +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0,WFlags f=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void connectedData(bool state); + void userData(); + void addData(); + void editData(); + void deleteData(); + void trackData(); + void reportData(); + void filterChangedData(const QString &str); + void filterClearedData(); + void logDoubleclickedData(QListViewItem *item,const QPoint &pt,int col); + void quitMainWidget(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshItem(ListListViewItem *item); + void RefreshList(); + QSqlDatabase *log_db; + QString log_filename; + QString log_import_path; + QLabel *log_user_label; + int log_card_no; + int log_stream_no; + QLabel *log_service_label; + QComboBox *log_service_box; + QLabel *log_filter_label; + QLineEdit *log_filter_edit; + QPushButton *log_filter_button; + QListView *log_log_list; + std::vector log_clipboard; + QPushButton *log_add_button; + QPushButton *log_edit_button; + QPushButton *log_delete_button; + QPushButton *log_track_button; + QPushButton *log_report_button; + QPushButton *log_close_button; + QPixmap *log_rivendell_map; + QPixmap *log_greencheckmark_map; + QPixmap *log_redx_map; + QPixmap *log_whiteball_map; + QPixmap *log_greenball_map; + QPixmap *log_redball_map; + QString log_filter; + QString log_group; + QString log_schedcode; +}; + + +#endif // RDLOGEDIT_H diff --git a/rdlogedit/rdlogedit.pro b/rdlogedit/rdlogedit.pro new file mode 100644 index 00000000..fd04cd01 --- /dev/null +++ b/rdlogedit/rdlogedit.pro @@ -0,0 +1,80 @@ +# rdlogedit.pro +# +# The rdlogedit/ QMake project file for Rivendell +# +# (C) Copyright 2003-2004 Fred Gleason +# +# $Id: rdlogedit.pro,v 1.17.2.3 2013/12/27 22:12:29 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +TARGET = rdlogedit + +win32 { + DEFINES += WIN32 + DEFINES += VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE=\"rivendell\" + DEFINES += PACKAGE_VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE_NAME=\"rivendell\" + DEFINES += PACKAGE_BUGREPORT=\"fredg@paravelsystems.com\" +} + +SOURCES += add_meta.cpp +SOURCES += drop_listview.cpp +SOURCES += edit_chain.cpp +SOURCES += edit_log.cpp +SOURCES += edit_logline.cpp +SOURCES += edit_marker.cpp +SOURCES += edit_track.cpp +SOURCES += list_listviewitem.cpp +SOURCES += list_logs.cpp +SOURCES += list_reports.cpp +SOURCES += rdlogedit.cpp +x11 { + SOURCES += voice_tracker.cpp +} + +HEADERS += add_meta.h +HEADERS += drop_listview.h +HEADERS += edit_chain.h +HEADERS += edit_log.h +HEADERS += edit_logline.h +HEADERS += edit_marker.h +HEADERS += edit_track.h +HEADERS += globals.h +HEADERS += list_listviewitem.h +HEADERS += list_logs.h +HEADERS += list_reports.h +HEADERS += rdlogedit.h +x11 { + HEADERS += voice_tracker.h +} + +RES_FILE += ..\icons\rivendell.res + +INCLUDEPATH += ..\lib + +LIBS = -lqui -L..\lib -llib + +CONFIG += qt + +TRANSLATIONS += rdlogedit_cs.ts +TRANSLATIONS += rdlogedit_de.ts +TRANSLATIONS += rdlogedit_es.ts +TRANSLATIONS += rdlogedit_fr.ts +TRANSLATIONS += rdlogedit_nb.ts +TRANSLATIONS += rdlogedit_nn.ts +TRANSLATIONS += rdlogedit_pt_BR.ts diff --git a/rdlogedit/rdlogedit_cs.ts b/rdlogedit/rdlogedit_cs.ts new file mode 100644 index 00000000..097657fd --- /dev/null +++ b/rdlogedit/rdlogedit_cs.ts @@ -0,0 +1,1103 @@ + + + AddMeta + + Insert a: + Vložit: + + + &Marker + &Značka + + + Voice &Track + Stopa &hlasu + + + Log C&hain + Ř&etězec zápisu + + + &Cancel + Z&rušit + + + + EditChain + + Edit Log Chain + Upravit řetězec zápisu + + + Start at: + Začít na: + + + Action If Previous Event Still Playing + Činnost, když předchozí událost ještě běží + + + Start Immediately + Spustit ihned + + + Make Next + Jako další + + + Wait up to + Počkat až do + + + Play + Přehrát + + + Segue + Přechod + + + Stop + Zastavit + + + Transition Type: + Typ přechodu: + + + Log Name + Název zápisu + + + Select + Vybrat + + + Log Description + Popis zápisu + + + &OK + &OK + + + &Cancel + Z&rušit + + + Transition If Previous Cart Ends Before + Přechod, když předchozí vozík skončí dříve + + + + EditLog + + Edit Log + Upravit zápis + + + Log Name: + Název zápisu: + + + Tracks: + Stopy: + + + Origin: + Původ: + + + Description: + Popis: + + + Service: + Služba: + + + Yes + Ano + + + No + Ne + + + Enable AutoRefresh: + Povolit automatické obnovení: + + + Start Date: + Počáteční datum: + + + End Date: + Koncové datum: + + + Start Date Enabled + Počáteční datum povoleno + + + End Date Enabled + Koncové datum povoleno + + + TIME + ČAS + + + TRANS + PŘECHOD + + + CART + VOZÍK + + + GROUP + SKUPINA + + + LENGTH + DÉLKA + + + TITLE + NÁZEV + + + ARTIST + UMĚLEC + + + CLIENT + ZÁKAZNÍK + + + AGENCY + AGENTURA + + + LABEL + ŠTÍTEK + + + SOURCE + ZDROJ + + + LINE ID + ID ŘÁDKU + + + COUNT + POČÍTADLO + + + Insert +Cart + Vložit +vozík + + + Insert +Meta + Vložit +popisná data + + + Edit + Upravit + + + Delete + Smazat + + + Cut + Vyjmout + + + Copy + Kopírovat + + + Paste + Vložit + + + &Save + &Uložit + + + Save +&As + Uložit +&jako + + + &Reports + Z&právy + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Carts + Neplatné vozíky + + + This log contains one or more carts +that are invalid for the selected service! + Tento zápis obsahuje jeden nebo více vozíků, +jež jsou pro vybranou službu neplatné! + + + Voice Track + Stopa hlasu + + + The log contains carts that are disabled +for the selected service! + +Do you still want to save? + Tento zápis obsahuje vozíky, +jež nejsou pro vybranou službu dostupné! + +Přesto chcete uložit? + + + Add Log + Přidat zápis + + + Log Exists + Zápis existuje + + + Log Already Exists! + Zápis již existuje! + + + RDLogEdit + RDLogEdit + + + The log has been modified. +Do you want to save your changes? + Zápis byl změněn. +Chcete uložit změny? + + + The log contains carts that are disabled +for the selected service! + Tento zápis obsahuje vozíky, +jež jsou pro vybranou službu zakázány! + + + PLAY + PŘEHRÁT + + + STOP + ZASTAVIT + + + SEGUE + PŘECHOD + + + [cart not found] + [vozík nenalezen] + + + MARKER + ZNAČKA + + + TRACK + STOPA + + + LOG CHAIN + ŘETĚZEC ZÁPISU + + + LINK + ODKAZ + + + [music import] + [zavedení hudby] + + + [traffic import] + [zavedení přenosu] + + + Manual + Ruční + + + Traffic + Přenos + + + Music + Hudba + + + RDLogManager + RDLogManager + + + Voice Tracker + Rozdělovač hlasu + + + --- end of log --- + --- konec zápisu --- + + + [INVALID CART] + [NEPLATNÝ VOZÍK] + + + Next Stop: + Další zastavení: + + + Log End: + Konec zápisu: + + + Run Length + Délka běhu + + + Selected: + Vybráno: + + + Delete on + Smazat na + + + Select + Vybrat + + + Unable to save log, audio deletion error! + Soubor se zápisem nelze uložit, chyba při mazání zvuku! + + + + EditLogLine + + Edit Log Entry + Upravit záznam zápisu + + + Start at: + Začít na: + + + Action If Previous Event Still Playing + Činnost, když předchozí událost ještě běží + + + Start Immediately + Spustit ihned + + + Make Next + Jako další + + + Wait up to + Počkat až do + + + Play + Přehrát + + + Segue + Přechod + + + Stop + Zastavit + + + Transition Type: + Typ přechodu: + + + Cart + Vozík + + + Title + Název + + + Artist + Umělec + + + Select +Cart + Vybrat +vozík + + + &OK + &OK + + + &Cancel + Z&rušit + + + Transition If Previous Cart Ends Before + Přechod, když předchozí vozík skončí dříve + + + Missing Cart + Chybí vozík + + + You must supply a cart number! + Musíte zadat číslo vozíku! + + + Disabled Cart + Zakázaný vozík + + + This cart belongs to a disabled +group for the specified service! + Tento vozík náleží do zakázané skupiny +vybrané služby! + + + No Fade on Segue Out + Žádné prolínání při přechodu ven + + + Duplicate Start Time + Zdvojený čas začátku + + + An event is already scheduled with this start time! + Již existuje událost s tímto začátečním časem! + + + + EditMarker + + Edit Log Marker + Upravit značku zápisu + + + Start at: + Začít na: + + + Action If Previous Event Still Playing + Činnost, když předchozí událost ještě běží + + + Start Immediately + Spustit ihned + + + Make Next + Jako další + + + Wait up to + Počkat až do + + + Play + Přehrát + + + Segue + Přechod + + + Stop + Zastavit + + + Comment + Poznámka + + + Label + Štítek + + + &OK + &OK + + + &Cancel + Z&rušit + + + Transition If Previous Cart Ends Before + Přechod, když předchozí vozík skončí dříve + + + Transition Type: + Typ přechodu: + + + + EditTrack + + Edit Voice Track Marker + Upravit značku zápisu stopy hlasu + + + Start at: + Začít na: + + + Action If Previous Event Still Playing + Činnost, když předchozí událost ještě běží + + + Start Immediately + Spustit ihned + + + Make Next + Jako další + + + Wait up to + Počkat až do + + + Play + Přehrát + + + Segue + Přechod + + + Stop + Zastavit + + + Comment + Poznámka + + + &OK + &OK + + + &Cancel + Z&rušit + + + Transition If Previous Cart Ends Before + Přechod, když předchozí vozík skončí dříve + + + Transition Type: + Typ přechodu: + + + + ListLogs + + Select a Log + Vybrat zápis + + + NAME + NÁZEV + + + DESCRIPTION + POPIS + + + SERVICE + SLUŽBA + + + &OK + &OK + + + &Cancel + Z&rušit + + + + ListReports + + RDLibrary Reports + Zprávy RDLibrary + + + Log Listing + Seznam zápisů + + + Log Exception Report + Zpráva o chybách v zápisu + + + Type: + Typ: + + + &Generate + Vy&tvořit + + + &Close + &Zavřít + + + [none] + [žádný] + + + Log Check + Přezkoušení zápisu + + + No exceptions found. + Nenalezena žádná chyba. + + + Effective Date: + Platné datum: + + + &Select + &Vybrat + + + + MainWidget + + RDLogEdit - Host + RDLogEdit - Server + + + User: [Unknown] + Uživatel: [Neznámý] + + + Can't Connect + Nelze spojit + + + LOG NAME + NÁZEV ZÁPISU + + + DESCRIPTION + POPIS + + + SERVICE + SLUŽBA + + + MUSIC + HUDBA + + + TRAFFIC + PŘENOS + + + TRACKS + STOPY + + + VALID FROM + PLATNÉ OD + + + VALID TO + PLATNÉ DO + + + AUTO REFRESH + AUTOOBNOVA + + + ORIGIN + PŮVOD + + + LAST LINKED + NAPOSLEDY SPOJENO + + + LAST MODIFIED + NAPOSLEDY ZMĚNĚNO + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + Voice +&Tracker + &Rozdělovač +hlasu + + + Log +Report + ZPRÁVA +o zápisu + + + &Close + &Zavřít + + + User + Uživatel + + + Add Log + Přidat zápis + + + Log Exists + Zápis existuje + + + Log Already Exists! + Zápis již existuje! + + + Delete Log + Smazat zápis + + + This will also delete the + Toto smaže i + + + voice tracks associated with this log. +Continue? + stopy hlasů spojených s tímto zápisem. +Pokračovat? + + + Tracks Exist + Stopa existuje + + + Always + Vždy + + + TFN + TFN + + + RDLogEdit + RDLogedit + + + Unable to delete log, audio deletion error! + Soubor se zápisem nelze smazat, chyba při mazání zvuku! + + + RDLogEdit -- Database Skew + RDLogEdit - Nesouměrnost v databázi + + + This version of RDLogEdit is incompatible with the version installed on the server. +See your system administrator for an update! + Tato verze RDLogEdit je neslučitelná s verzí nainstalovanou na serveru. +Vyhledejte svého správce systému kvůli aktualizaci! + + + Host + + + + Unknown + + + + Service + + + + ALL + + + + Filter + + + + Clear + + + + + VoiceTracker + + Voice Tracker + Rozdělovač hlasu + + + Edit Cue Markers + + + + Undo Segue Changes + + + + Set Start Point Here + + + + Set End Point Here + + + + Set to Hook Markers + + + + Start + + + + Record + + + + Save + + + + &Previous +Track + + + + &Next +Track + + + + Remaining + + + + Tracks + + + + Time + + + + + + + + TIME + ČAS + + + TRANS + PŘECHOD + + + CART + VOZÍK + + + GROUP + SKUPINA + + + LENGTH + DÉLKA + + + TITLE + NÁZEV + + + ARTIST + UMĚLEC + + + Do Over + + + + Hit Post + + + + Insert +Track + + + + Delete +Track + + + + &Close + &Zavřít + + + No VoiceTrack Group + + + + No voicetracking group has been defined for this service, +therefore only existing transitions will be editable. + + + + Import + + + + Cart Creation Failure + + + + Unable to create new cart for voice track! + + + + RDLogEdit + + + + Audio Deletion Error! + + + + TRACK + STOPA + + + Voice Track + Stopa hlasu + + + Track List + + + + No more tracks! + + + + [end of log] + + + + [cart not found] + [vozík nenalezen] + + + MARKER + ZNAČKA + + + LOG CHAIN + ŘETĚZEC ZÁPISU + + + LINK + ODKAZ + + + [music import] + [zavedení hudby] + + + [traffic import] + [zavedení přenosu] + + + PLAY + PŘEHRÁT + + + SEGUE + PŘECHOD + + + STOP + ZASTAVIT + + + Abort + + + + Segue Changed + + + + Save segue changes? + + + + RDLogEdit - Voice Tracker + + + + This cart cannot contain any additional cuts! + + + + ALBUM + + + + LABEL + ŠTÍTEK + + + diff --git a/rdlogedit/rdlogedit_de.ts b/rdlogedit/rdlogedit_de.ts new file mode 100644 index 00000000..1726c8c1 --- /dev/null +++ b/rdlogedit/rdlogedit_de.ts @@ -0,0 +1,1102 @@ + + + AddMeta + + Insert a: + Füge ein: + + + &Marker + &Marker + + + Voice &Track + Voice &Track + + + Log C&hain + Log C&hain + + + &Cancel + Abbre&chen + + + + EditChain + + Edit Log Chain + Log Chain editieren + + + Start at: + Starte um: + + + Action If Previous Event Still Playing + Aktion wenn vorheriges Event noch läuft + + + Start Immediately + Sofort starten + + + Make Next + Als Nächstes + + + Wait up to + Warte bis zu + + + Play + Abspielen + + + Segue + Übergang + + + Stop + Stop + + + Transition Type: + Übergangstyp: + + + Log Name + Logname + + + Select + Auswählen + + + Log Description + Logbeschreibung + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Transition If Previous Cart Ends Before + Übergang wenn der vorheriger Cart eher aufhört + + + + EditLog + + Edit Log + Log editieren + + + Log Name: + Logname + + + Tracks: + Tracks: + + + Origin: + Herkunft: + + + Description: + Beschreibung: + + + Service: + Service: + + + Yes + Ja + + + No + Nein + + + Enable AutoRefresh: + AutoRefresh einschalten: + + + Start Date: + Startdatum: + + + End Date: + Enddatum: + + + Start Date Enabled + Start Datum ein + + + End Date Enabled + Enddatum an + + + TIME + Zeit + + + TRANS + ÜBERGANG + + + CART + CART + + + GROUP + GRUPPE + + + LENGTH + LÄNGE + + + TITLE + TITEL + + + ARTIST + KÜNSTLER + + + CLIENT + KUNDE + + + AGENCY + AGENTUR + + + LABEL + LABEL + + + SOURCE + QUELLE + + + LINE ID + LINE ID + + + COUNT + ZÄHLER + + + Insert +Cart + Cart +einfügen + + + Insert +Meta + Meta +einfügen + + + Edit + editieren + + + Delete + löschen + + + Cut + Cut + + + Copy + Kopieren + + + Paste + Einfügen + + + &Save + &Speichern + + + Save +&As + Speichern +&Als + + + &Reports + &Reporte + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Carts + Ungültige Carts + + + This log contains one or more carts +that are invalid for the selected service! + Dieses Log enthält einen oder mehrere Carts, +die für den gewählten Service ungültig sind! + + + Voice Track + Voice Track + + + The log contains carts that are disabled +for the selected service! + +Do you still want to save? + Dieses Log enthält Carts die für den +ausgewählten Service nicht verfügbar sind! + +Wollen Sie trotzdem speichern? + + + Add Log + Log Hinzufügen + + + Log Exists + Log existiert + + + Log Already Exists! + Log existiert bereits! + + + RDLogEdit + RDLogEdit + + + The log has been modified. +Do you want to save your changes? + Das Log modifiziert. +Wollen Sie ihre Änderungen speichern? + + + The log contains carts that are disabled +for the selected service! + Dieses Log enthält einen oder mehrere Carts, +die für den gewählten Service ungültig sind! + + + PLAY + PLAY + + + STOP + STOP + + + SEGUE + ÜBERGANG + + + [cart not found] + [cart nicht gefunden] + + + MARKER + MARKER + + + TRACK + TRACK + + + LOG CHAIN + LOG CHAIN + + + LINK + LINK + + + [music import] + [musikimport] + + + [traffic import] + [trafficimport] + + + Manual + Manuell + + + Traffic + Traffic + + + Music + Musik + + + RDLogManager + RDLogManager + + + Voice Tracker + Voice Tracker + + + --- end of log --- + --- ende des logs --- + + + [INVALID CART] + [UNGÜLTIGER CART] + + + Next Stop: + Nächste Stop: + + + Log End: + Log Ende: + + + Run Length + Laufzeit + + + Selected: + Ausgewählt: + + + Delete on + Lösche am + + + Select + Auswählen + + + Unable to save log, audio deletion error! + Kann Logdatei nicht speichern, Audiolöschfehler! + + + + EditLogLine + + Edit Log Entry + Logeintrag editieren + + + Start at: + Starte um: + + + Action If Previous Event Still Playing + Aktion wenn vorheriges Event noch läuft + + + Start Immediately + Sofort starten + + + Make Next + Als Nächstes + + + Wait up to + Warte bis zu + + + Play + Abspielen + + + Segue + Übergang + + + Stop + Stop + + + Transition Type: + Übergangstyp: + + + Cart + Cart + + + Title + Titel + + + Artist + Künstler + + + Select +Cart + Cart +auswählen + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Transition If Previous Cart Ends Before + Übergang wenn der vorheriger Cart eher aufhört + + + Missing Cart + Fehlender Cart + + + You must supply a cart number! + Sie müssen eine Cartnummer angeben! + + + Disabled Cart + Abgeschalteter Cart + + + This cart belongs to a disabled +group for the specified service! + Dieser Cart gehört einer abgeschalteten +Gruppe des ausgewählten Service! + + + No Fade on Segue Out + Kein Faden beim Segue Out + + + Duplicate Start Time + Doppelte Startzeit + + + An event is already scheduled with this start time! + Es existiert bereits ein Event mit dieser Startzeit! + + + + EditMarker + + Edit Log Marker + Log Marker editieren + + + Start at: + Starte um: + + + Action If Previous Event Still Playing + Aktion wenn vorheriges Event noch läuft + + + Start Immediately + Sofort starten + + + Make Next + Als Nächstes + + + Wait up to + Warte bis zu + + + Play + Abspielen + + + Segue + Übergang + + + Stop + Stop + + + Comment + Kommentar + + + Label + Label + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Transition If Previous Cart Ends Before + Übergang wenn der vorheriger Cart eher aufhört + + + Transition Type: + Übergangstyp: + + + + EditTrack + + Edit Voice Track Marker + Voice Track Marker editieren + + + Start at: + Starte um: + + + Action If Previous Event Still Playing + Aktion wenn vorheriges Event noch läuft + + + Start Immediately + Sofort starten + + + Make Next + Als Nächstes + + + Wait up to + Warte bis zu + + + Play + Abspielen + + + Segue + Übergang + + + Stop + Stop + + + Comment + Kommentar + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Transition If Previous Cart Ends Before + Übergang wenn der vorheriger Cart eher aufhört + + + Transition Type: + Übergangstyp: + + + + ListLogs + + Select a Log + Ein Log auswählen + + + NAME + NAME + + + DESCRIPTION + BESCHREIBUNG + + + SERVICE + SERVICE + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + ListReports + + RDLibrary Reports + RDLibrary Reports + + + Log Listing + Log Liste + + + Log Exception Report + Log Fehlerbericht + + + Type: + Typ: + + + &Generate + &Generieren + + + &Close + &Schliessen + + + [none] + [keine] + + + Log Check + Log Überprüfung + + + No exceptions found. + Keine Fehler gefunden. + + + Effective Date: + Effektives Datum: + + + &Select + Au&swählen + + + + MainWidget + + RDLogEdit - Host + RDLogEdit - Host + + + User: [Unknown] + Benutzer: [Unbekannt] + + + Can't Connect + Kann nicht verbinden + + + LOG NAME + LOGNAME + + + DESCRIPTION + BESCHREIBUNG + + + SERVICE + SERVICE + + + MUSIC + MUSIK + + + TRAFFIC + TRAFFIC + + + TRACKS + TRACKS + + + VALID FROM + GÜLTIG VON + + + VALID TO + GÜLTIG BIS + + + AUTO REFRESH + AUTO REFRESH + + + ORIGIN + HERKUNFT + + + LAST LINKED + ZULETZT GELINKT + + + LAST MODIFIED + ZULETZT GEÄNDERT + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + Voice +&Tracker + Voice +&Tracker + + + Log +Report + Log +Report + + + &Close + &Schliessen + + + User + Benutzer + + + Add Log + Log Hinzufügen + + + Log Exists + Log existiert + + + Log Already Exists! + Log existiert bereits! + + + Delete Log + Log Löschen + + + This will also delete the + Dies löscht ebenfalls die + + + voice tracks associated with this log. +Continue? + Voice Tracks die mit diesem Log verbunden sind. +Fortfahren? + + + Tracks Exist + Track existiert + + + Always + Immer + + + TFN + TFN + + + RDLogEdit + RDLogEdit + + + Unable to delete log, audio deletion error! + Kann Logdatei nicht löschen, Audiolöschfehler! + + + RDLogEdit -- Database Skew + + + + This version of RDLogEdit is incompatible with the version installed on the server. +See your system administrator for an update! + + + + Host + + + + Unknown + + + + Service + + + + ALL + + + + Filter + + + + Clear + + + + + VoiceTracker + + Voice Tracker + Voice Tracker + + + Edit Cue Markers + + + + Undo Segue Changes + + + + Set Start Point Here + + + + Set End Point Here + + + + Set to Hook Markers + + + + Start + + + + Record + + + + Save + + + + &Previous +Track + + + + &Next +Track + + + + Remaining + + + + Tracks + + + + Time + + + + + + + + TIME + Zeit + + + TRANS + ÜBERGANG + + + CART + CART + + + GROUP + GRUPPE + + + LENGTH + LÄNGE + + + TITLE + TITEL + + + ARTIST + KÜNSTLER + + + Do Over + + + + Hit Post + + + + Insert +Track + + + + Delete +Track + + + + &Close + &Schliessen + + + No VoiceTrack Group + + + + No voicetracking group has been defined for this service, +therefore only existing transitions will be editable. + + + + Import + + + + Cart Creation Failure + + + + Unable to create new cart for voice track! + + + + RDLogEdit + RDLogEdit + + + Audio Deletion Error! + + + + TRACK + TRACK + + + Voice Track + Voice Track + + + Track List + + + + No more tracks! + + + + [end of log] + + + + [cart not found] + [cart nicht gefunden] + + + MARKER + MARKER + + + LOG CHAIN + LOG CHAIN + + + LINK + LINK + + + [music import] + [musikimport] + + + [traffic import] + [trafficimport] + + + PLAY + PLAY + + + SEGUE + ÜBERGANG + + + STOP + STOP + + + Abort + + + + Segue Changed + + + + Save segue changes? + + + + RDLogEdit - Voice Tracker + + + + This cart cannot contain any additional cuts! + + + + ALBUM + + + + LABEL + LABEL + + + diff --git a/rdlogedit/rdlogedit_es.ts b/rdlogedit/rdlogedit_es.ts new file mode 100644 index 00000000..07aebe5b --- /dev/null +++ b/rdlogedit/rdlogedit_es.ts @@ -0,0 +1,1109 @@ + + + AddMeta + + Insert a: + Insertar: + + + &Marker + &Marcador + + + Log C&hain + Enca&denar a Lista + + + &Cancel + &Cancelar + + + Voice &Track + Pista de &voz + + + + EditChain + + Edit Log Chain + Editar encadenamiento + + + Start at: + Inicia en: + + + Action If Previous Event Still Playing + Acción si el evento previo no ha terminado + + + Start Immediately + Iniciar de inmediato + + + Make Next + Convertir en el siguente + + + Wait up to + Espe. hasta + + + Play + Reproducir + + + Segue + Segue + + + Stop + Parar + + + Transition Type: + Tipo de transición: + + + Log Name + Nombre de la Lista + + + Select + Seleccionar + + + Log Description + Descripción + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Transition If Previous Cart Ends Before + Transic. si cart. previo termina antes de + + + + EditLog + + Edit Log + Editar Lista + + + Log Name: + Nombre: + + + Origin: + Por: + + + Description: + Descripción: + + + Service: + Servicio: + + + Start Date: + Fecha de inicio: + + + End Date: + Fecha fin: + + + Start Date Enabled + Fecha de inicio activada + + + End Date Enabled + Fecha de fin activada + + + TIME + TIEMPO + + + TRANS + TRANS + + + CART + CARTUCHO + + + GROUP + GRUPO + + + LENGTH + DURACIÓN + + + TITLE + TÍTULO + + + ARTIST + ARTISTA + + + CLIENT + CLIENTE + + + AGENCY + AGENCIA + + + LABEL + ETIQUETA + + + LINE ID + ID LÍNEA + + + COUNT + CUENTA + + + Insert +Cart + Insertar +Cartucho + + + Insert +Meta + Insertar +Meta + + + Edit + Editar + + + Delete + Eliminar + + + Cut + Cortar + + + Copy + Copiar + + + Paste + Pegar + + + &Save + &Guardar + + + Save +&As + Guardar +&como + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Carts + Cartuchos inválidos + + + This log contains one or more carts +that are invalid for the selected service! + ¡Esta Lista contiene uno o más cartuchos +que son inválidos para el dispositivo elegido! + + + The log contains carts that are disabled +for the selected service! + ¡La Lista contiene cartuchos que están +desactivados para el dispositivo seleccionado! + + + Add Log + Agregar Lista + + + Log Exists + La Lista ya existe + + + Log Already Exists! + ¡El playlist o Lista ya existe! + + + RDLogEdit + + + + The log has been modified. +Do you want to save your changes? + La Lista ha sido modificada. +¿Desea guardar los cambios? + + + PLAY + REPROD + + + STOP + PARAR + + + SEGUE + SEGUE + + + [cart not found] + [cartucho no encontrado] + + + MARKER + MARCADOR + + + LOG CHAIN + ENCADENAR A LISTA + + + --- end of log --- + --- fin de lista --- + + + SOURCE + FUENTE + + + Manual + Manual + + + Traffic + Tráfico + + + Music + Música + + + RDLogManager + RDLogManager + + + TRACK + PISTA + + + Voice Tracker + Pista de voz + + + Tracks: + Pistas: + + + Voice Track + Pista de voz + + + LINK + ENLACE + + + [traffic import] + [importar tráfico] + + + [music import] + [importar música] + + + The log contains carts that are disabled +for the selected service! + +Do you still want to save? + ¡La Lista contiene cartuchos que están +desactivados para el servicio actual! + +¿Aún así desea guardarlo? + + + [INVALID CART] + [CARTUCHO INVÁLIDO] + + + Yes + + + + No + No + + + Enable AutoRefresh: + Activar AutoActualizar: + + + &Reports + &Reportes + + + Next Stop: + Próx.parad: + + + Log End: + Fin Lista: + + + Run Length + Durac. total + + + Selected: + Seleccionado: + + + Delete on + Borrar el + + + Select + Seleccionar + + + Unable to save log, audio deletion error! + No es posible guardar la Lista, ¡error por eliminación de audio! + + + + EditLogLine + + Edit Log Entry + Editar entrada + + + Start at: + Inicia en: + + + Action If Previous Event Still Playing + Acción si el evento previo no ha terminado + + + Start Immediately + Iniciar de inmediato + + + Make Next + Convertir en el siguente + + + Wait up to + Esp. hasta + + + Play + Reproducir + + + Segue + Segue + + + Stop + Parar + + + Transition Type: + Tipo de transición: + + + Cart + Cartucho + + + Title + Título + + + Artist + Artista + + + Select +Cart + Seleccionar +cartucho + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Transition If Previous Cart Ends Before + Transic. si cart. previo termina antes de + + + Missing Cart + Cartucho no encontrado + + + You must supply a cart number! + ¡Debe introducir un número de cartucho! + + + Disabled Cart + Cartucho desactivado + + + This cart belongs to a disabled +group for the specified service! + ¡Este cartucho pertenece a un grupo que está +desactivado para el servicio especificado! + + + No Fade on Segue Out + Sin "fade" en un segue de salida + + + Duplicate Start Time + Tiempo de inicio duplicado + + + An event is already scheduled with this start time! + ¡Se programó un evento para esta misma hora de inicio! + + + + EditMarker + + Edit Log Marker + Editar marcador + + + Start at: + Inicia en: + + + Action If Previous Event Still Playing + Acción si el evento previo no ha terminado + + + Start Immediately + Iniciar de inmediato + + + Make Next + Convertir en el siguente + + + Wait up to + Esp. hasta + + + Play + Reproducir + + + Segue + Segue + + + Stop + Parar + + + Comment + Comentario + + + Label + Etiqueta + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Transition If Previous Cart Ends Before + Transic. si cart. previo termina antes de + + + Transition Type: + Tipo de transición: + + + + EditTrack + + Edit Voice Track Marker + Editar marcador de Voicetrack + + + Start at: + Inicia en: + + + Action If Previous Event Still Playing + Acción si el evento previo no ha terminado + + + Start Immediately + Iniciar de inmediato + + + Make Next + Convertir en el siguente + + + Wait up to + Esp. hasta + + + Play + Reproducir + + + Segue + Segue + + + Stop + Parar + + + Comment + Comentario + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Transition If Previous Cart Ends Before + Transic. si cart. previo termina antes de + + + Transition Type: + Tipo de transición: + + + + ListLogs + + Select a Log + Seleccione una Lista + + + NAME + NOMBRE + + + DESCRIPTION + DESCRIPCIÓN + + + SERVICE + SERVICIO + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + ListReports + + RDLibrary Reports + Reportes de RDLibrary + + + Log Listing + Listas de reproducción + + + Log Exception Report + Reporte de Excepciones + + + Type: + Tipo: + + + &Generate + &Generar + + + &Close + &Cerrar + + + Log Check + Chequear Listas + + + No exceptions found. + No se encontraron excepciones. + + + [none] + [ninguno] + + + Effective Date: + Fecha efectiva: + + + &Select + &Seleccionar + + + + MainWidget + + RDLogEdit - Host + RDLogEdit - Computador + + + User: [Unknown] + Usuario: [Desconocido] + + + Can't Connect + No puedo conectarme + + + LOG NAME + NOMBRE DE LA LISTA + + + DESCRIPTION + DESCRIPCIÓN + + + SERVICE + SERVICIO + + + VALID FROM + VÁLIDO DESDE + + + VALID TO + VÁLIDO HASTA + + + ORIGIN + ORIGEN + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + &Borrar + + + &Close + &Cerrar + + + User + Usuario + + + Add Log + Agregar lista + + + Log Exists + La Lista ya existe + + + Log Already Exists! + ¡La lista de reproducción ya existe! + + + Always + Siempre + + + TFN + + + + This will also delete the + Esto también borrará los + + + voice tracks associated with this log. +Continue? + voicetracks asociados a esta lista. +¿Desea continuar? + + + Tracks Exist + La pista ya existe + + + TRACKS + PISTAS + + + Voice +&Tracker + Pistas +de &Voz + + + Delete Log + Eliminar Lista + + + MUSIC + MÚSICA + + + TRAFFIC + TRÁFICO + + + LAST LINKED + ÚLTIMO ENLACE + + + LAST MODIFIED + ÚLTIMO CAMBIO + + + AUTO REFRESH + AUTO ACTUALIZAR + + + Log +Report + Reporte +de Listas + + + RDLogEdit + + + + Unable to delete log, audio deletion error! + ¡No es posible eliminar la lista, error de eliminación de audios! + + + RDLogEdit -- Database Skew + RDLogEdit -- Asimetría en la Base de Datos + + + This version of RDLogEdit is incompatible with the version installed on the server. +See your system administrator for an update! + Esta versión de RDLogEdit es incompatible con la versión instalada en el servidor. +¡Solicite una actualización al administrador! + + + Host + + + + Unknown + + + + ALL + + + + Service + + + + Filter + + + + Clear + + + + + VoiceTracker + + Voice Tracker + Pista de voz + + + Edit Cue Markers + Editar marcadores + + + Undo Segue Changes + Deshacer cambios en Segue + + + Set Start Point Here + Colocar punto de inicio aquí + + + Set End Point Here + Colocar punto de fin aquí + + + Set to Hook Markers + Colocar en los marcadores "Hook" + + + Start + Inicio + + + Record + Grabar + + + Save + Guardar + + + &Previous +Track + Pista +&Anterior + + + &Next +Track + Pista +&Siguiente + + + Remaining + Restan + + + Tracks + Pistas + + + Time + Tiempo + + + + + + + TIME + TIEMPO + + + TRANS + TRANS + + + CART + CARTUCHO + + + GROUP + GRUPO + + + LENGTH + DURACIÓN + + + TITLE + TÍTULO + + + ARTIST + ARTISTA + + + Do Over + Sobre- +escribir + + + Hit Post + + + + Insert +Track + Insertar +Pista + + + Delete +Track + Borrar +Pista + + + &Close + &Cerrar + + + No VoiceTrack Group + No hay grupos para las pistas de voz + + + No voicetracking group has been defined for this service, +therefore only existing transitions will be editable. + No se ha definido un grupo para las pistas de voz, por ende +sólo podrás editar transiciones ya existentes. + + + Import + Importar + + + Cart Creation Failure + Falló la creación de cartuchos + + + Unable to create new cart for voice track! + ¡No fue posible crear un nuevo cartucho para la pista de voz! + + + RDLogEdit + RDLogEdit + + + Audio Deletion Error! + ¡Error eliminando audio! + + + TRACK + PISTA + + + Voice Track + Pista de voz + + + Track List + Listado de pistas + + + No more tracks! + ¡No hay más pistas! + + + [end of log] + [fin de la lista] + + + [cart not found] + [cartucho no encontrado] + + + MARKER + MARCADOR + + + LOG CHAIN + ENCADENAR A LISTA + + + LINK + ENLACE + + + [music import] + [importar música] + + + [traffic import] + [importar tráfico] + + + PLAY + REPROD + + + SEGUE + SEGUE + + + STOP + PARAR + + + Abort + Abortar + + + Segue Changed + Segue modificado + + + Save segue changes? + ¿Guardar cambios en Segue? + + + RDLogEdit - Voice Tracker + + + + This cart cannot contain any additional cuts! + + + + ALBUM + + + + LABEL + ETIQUETA + + + diff --git a/rdlogedit/rdlogedit_fr.ts b/rdlogedit/rdlogedit_fr.ts new file mode 100644 index 00000000..24135a59 --- /dev/null +++ b/rdlogedit/rdlogedit_fr.ts @@ -0,0 +1,1080 @@ + + + AddMeta + + Insert a: + + + + &Marker + + + + Voice &Track + + + + Log C&hain + + + + &Cancel + + + + + EditChain + + Edit Log Chain + + + + Start at: + + + + Action If Previous Event Still Playing + + + + Start Immediately + + + + Make Next + + + + Wait up to + + + + Play + + + + Segue + + + + Stop + + + + Transition Type: + + + + Log Name + + + + Select + + + + Log Description + + + + &OK + + + + &Cancel + + + + Transition If Previous Cart Ends Before + + + + + EditLog + + Edit Log + + + + Log Name: + + + + Tracks: + + + + Origin: + + + + Description: + + + + Service: + + + + Yes + + + + No + + + + Enable AutoRefresh: + + + + Start Date: + + + + End Date: + + + + Start Date Enabled + + + + End Date Enabled + + + + TIME + + + + TRANS + + + + CART + + + + GROUP + + + + LENGTH + + + + TITLE + + + + ARTIST + + + + CLIENT + + + + AGENCY + + + + LABEL + + + + SOURCE + + + + LINE ID + + + + COUNT + + + + Insert +Cart + + + + Insert +Meta + + + + Edit + + + + Delete + + + + Cut + + + + Copy + + + + Paste + + + + &Save + + + + Save +&As + + + + &Reports + + + + &OK + + + + &Cancel + + + + Invalid Carts + + + + This log contains one or more carts +that are invalid for the selected service! + + + + Voice Track + + + + The log contains carts that are disabled +for the selected service! + +Do you still want to save? + + + + Add Log + + + + Log Exists + + + + Log Already Exists! + + + + RDLogEdit + + + + The log has been modified. +Do you want to save your changes? + + + + The log contains carts that are disabled +for the selected service! + + + + PLAY + + + + STOP + + + + SEGUE + + + + [cart not found] + + + + MARKER + + + + TRACK + + + + LOG CHAIN + + + + LINK + + + + [music import] + + + + [traffic import] + + + + Manual + + + + Traffic + + + + Music + + + + RDLogManager + + + + Voice Tracker + + + + --- end of log --- + + + + [INVALID CART] + + + + Next Stop: + + + + Log End: + + + + Run Length + + + + Selected: + + + + Delete on + + + + Select + + + + Unable to save log, audio deletion error! + + + + + EditLogLine + + Edit Log Entry + + + + Start at: + + + + Action If Previous Event Still Playing + + + + Start Immediately + + + + Make Next + + + + Wait up to + + + + Play + + + + Segue + + + + Stop + + + + Transition Type: + + + + Cart + + + + Title + + + + Artist + + + + Select +Cart + + + + &OK + + + + &Cancel + + + + Transition If Previous Cart Ends Before + + + + Missing Cart + + + + You must supply a cart number! + + + + Disabled Cart + + + + This cart belongs to a disabled +group for the specified service! + + + + No Fade on Segue Out + + + + Duplicate Start Time + + + + An event is already scheduled with this start time! + + + + + EditMarker + + Edit Log Marker + + + + Start at: + + + + Action If Previous Event Still Playing + + + + Start Immediately + + + + Make Next + + + + Wait up to + + + + Play + + + + Segue + + + + Stop + + + + Comment + + + + Label + + + + &OK + + + + &Cancel + + + + Transition If Previous Cart Ends Before + + + + Transition Type: + + + + + EditTrack + + Edit Voice Track Marker + + + + Start at: + + + + Action If Previous Event Still Playing + + + + Start Immediately + + + + Make Next + + + + Wait up to + + + + Play + + + + Segue + + + + Stop + + + + Comment + + + + &OK + + + + &Cancel + + + + Transition If Previous Cart Ends Before + + + + Transition Type: + + + + + ListLogs + + Select a Log + + + + NAME + + + + DESCRIPTION + + + + SERVICE + + + + &OK + + + + &Cancel + + + + + ListReports + + RDLibrary Reports + + + + Log Listing + + + + Log Exception Report + + + + Type: + + + + &Generate + + + + &Close + + + + [none] + + + + Log Check + + + + No exceptions found. + + + + Effective Date: + + + + &Select + + + + + MainWidget + + Can't Connect + + + + LOG NAME + + + + DESCRIPTION + + + + SERVICE + + + + MUSIC + + + + TRAFFIC + + + + TRACKS + + + + VALID FROM + + + + VALID TO + + + + AUTO REFRESH + + + + ORIGIN + + + + LAST LINKED + + + + LAST MODIFIED + + + + &Add + + + + &Edit + + + + &Delete + + + + Voice +&Tracker + + + + Log +Report + + + + &Close + + + + User + + + + Add Log + + + + Log Exists + + + + Log Already Exists! + + + + Delete Log + + + + This will also delete the + + + + voice tracks associated with this log. +Continue? + + + + Tracks Exist + + + + Always + + + + TFN + + + + RDLogEdit + + + + Unable to delete log, audio deletion error! + + + + RDLogEdit -- Database Skew + + + + This version of RDLogEdit is incompatible with the version installed on the server. +See your system administrator for an update! + + + + Host + + + + Unknown + + + + Service + + + + ALL + + + + Filter + + + + Clear + + + + + VoiceTracker + + Voice Tracker + + + + Edit Cue Markers + + + + Undo Segue Changes + + + + Set Start Point Here + + + + Set End Point Here + + + + Set to Hook Markers + + + + Start + + + + Record + + + + Save + + + + &Previous +Track + + + + &Next +Track + + + + Remaining + + + + Tracks + + + + Time + + + + + + + + TIME + + + + TRANS + + + + CART + + + + GROUP + + + + LENGTH + + + + TITLE + + + + ARTIST + + + + Do Over + + + + Hit Post + + + + Insert +Track + + + + Delete +Track + + + + &Close + + + + No VoiceTrack Group + + + + No voicetracking group has been defined for this service, +therefore only existing transitions will be editable. + + + + Import + + + + Cart Creation Failure + + + + Unable to create new cart for voice track! + + + + RDLogEdit + + + + Audio Deletion Error! + + + + TRACK + + + + Voice Track + + + + Track List + + + + No more tracks! + + + + [end of log] + + + + [cart not found] + + + + MARKER + + + + LOG CHAIN + + + + LINK + + + + [music import] + + + + [traffic import] + + + + PLAY + + + + SEGUE + + + + STOP + + + + Abort + + + + Segue Changed + + + + Save segue changes? + + + + RDLogEdit - Voice Tracker + + + + This cart cannot contain any additional cuts! + + + + ALBUM + + + + LABEL + + + + diff --git a/rdlogedit/rdlogedit_nb.ts b/rdlogedit/rdlogedit_nb.ts new file mode 100644 index 00000000..8a98dc18 --- /dev/null +++ b/rdlogedit/rdlogedit_nb.ts @@ -0,0 +1,1124 @@ + + + AddMeta + + Insert a: + Set inn: + + + &Marker + ein &markør + + + Voice &Track + eit røys&t-spor + + + Log C&hain + Ei logg&kjede + + + &Cancel + &Avbryt + + + + EditChain + + Edit Log Chain + Rediger loggkjede + + + Start at: + Start på: + + + Action If Previous Event Still Playing + Handling viss den førre hendinga spelar enno + + + Start Immediately + Start med ein gong + + + Make Next + Gjer til neste + + + Wait up to + Vent opp til + + + Play + Spel + + + Segue + Krysston + + + Stop + Stopp + + + Overlap + Overlapp + + + Transition Type: + Overgangstype: + + + Log Name + Loggnamn + + + Select + Vel + + + Log Description + Loggskildring + + + &OK + &OK + + + &Cancel + &Avbryt + + + Transition If Previous Cart Ends Before + Overgang viss førre korg endar før + + + + EditLog + + Edit Log + Rediger logg + + + Log Name: + Loggnamn: + + + Tracks: + Spor: + + + Origin: + Opphav: + + + Description: + Skildring: + + + Service: + Tenest: + + + Yes + Ja + + + No + Nei + + + Enable AutoRefresh: + Skru på AutoOppdater: + + + Start Date: + Startdato: + + + End Date: + Sluttdato: + + + Start Date Enabled + Startdato på + + + End Date Enabled + Sluttdato på + + + TIME + TID + + + TRANS + OVERG + + + CART + KORG + + + GROUP + GRUPPE + + + LENGTH + LENGD + + + TITLE + TITTEL + + + ARTIST + ARTIST + + + CLIENT + KLIENT + + + AGENCY + AGENT + + + LABEL + SELSKAP + + + SOURCE + KJELDE + + + LINE ID + LINE-ID + + + COUNT + TELLING + + + Insert +Cart + Set inn +korg + + + Insert +Meta + Set inn +meta + + + Edit + Rediger + + + Delete + Slett + + + Cut + Klypp ut + + + Copy + Kopier + + + Paste + Lim inn + + + &Save + &Lagra + + + Save +&As + Lagra &som + + + &Reports + Ra&pportar + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Carts + Ugyldige korger + + + This log contains one or more carts +that are invalid for the selected service! + Denne loggen inneheld ei eller fleire +korger som er ugyldige for denne tenesta! + + + Voice Track + Røyst-spor + + + The log contains carts that are disabled +for the selected service! + +Do you still want to save? + Loggen inneheld korger som er skrudd av +for denne tenesta! + +Vil du lagra likevel? + + + Add Log + Legg til logg + + + Log Exists + Loggen eksisterer + + + Log Already Exists! + Loggen finst frå før! + + + RDLogEdit + RDLogEdit + + + The log has been modified. +Do you want to save your changes? + Loggen er endra. +Vil du lagra endringane? + + + The log contains carts that are disabled +for the selected service! + Loggen inneheld korger som er +skrudd av for denne tenesta! + + + PLAY + SPEL + + + STOP + STOPP + + + SEGUE + KRYSSTON + + + OVERLAP + OVERLAPP + + + [cart not found] + [fann ikkje korga] + + + MARKER + MARKØR + + + TRACK + SPOR + + + LOG CHAIN + LOGGKJEDE + + + LINK + LENKJE + + + [music import] + [musikkimport] + + + [traffic import] + [trafikkimport] + + + Manual + Manuelt + + + Traffic + Trafikk + + + Music + Musikk + + + RDLogManager + RDLogManager + + + Voice Tracker + Spor røyst + + + --- end of log --- + --- slutt på loggen --- + + + [INVALID CART] + [UGYLDIG KORG] + + + Delete on + + + + Select + Vel + + + Run Length + + + + Next Stop: + + + + Log End: + + + + Selected: + + + + Unable to save log, audio deletion error! + + + + + EditLogLine + + Edit Log Entry + Rediger loggoppføring + + + Start at: + Start på: + + + Action If Previous Event Still Playing + Handling viss den førre hendinga spelar enno + + + Start Immediately + Start med ein gong + + + Make Next + Gjer til neste + + + Wait up to + Vent opp til + + + Play + Spel + + + Segue + Krysston + + + Stop + Stopp + + + Overlap + Overlapp + + + Transition Type: + Overgangstype: + + + No Fade When Segueing At End + Inga uttoning når du overtonar ved slutten + + + Cart + Korg + + + Title + Tittel + + + Artist + Artist + + + Select +Cart + Vel korg + + + &OK + &OK + + + &Cancel + &Avbryt + + + Transition If Previous Cart Ends Before + Overgang viss førre korg endar før + + + Missing Cart + Manglar korg + + + You must supply a cart number! + Du må skriva inn eit korgnummer! + + + Disabled Cart + Korga er skrudd av + + + This cart belongs to a disabled +group for the specified service! + Denne korga høyrer til ei gruppe +som er skrudd av for denne tenesta! + + + No Fade on Segue Out + + + + Duplicate Start Time + + + + An event is already scheduled with this start time! + + + + + EditMarker + + Edit Log Marker + Rediger loggmarkør + + + Start at: + Start på: + + + Action If Previous Event Still Playing + Handling viss den førre hendinga spelar enno + + + Start Immediately + Start med ein gong + + + Make Next + Gjer til neste + + + Wait up to + Vent opp til + + + Play + Spel + + + Segue + Krysston + + + Stop + Stopp + + + Overlap + Overlapp + + + Comment + Kommentar + + + Label + Selskap + + + &OK + &OK + + + &Cancel + &Avbryt + + + Transition If Previous Cart Ends Before + Overgang viss førre korg endar før + + + Transition Type: + Overgangstype: + + + + EditTrack + + Edit Voice Track Marker + Rediger røystspormarkør + + + Start at: + Start på: + + + Action If Previous Event Still Playing + Handling viss den førre hendinga spelar enno + + + Start Immediately + Start med ein gong + + + Make Next + Gjer til neste + + + Wait up to + Vent opp til + + + Play + Spel + + + Segue + Krysston + + + Stop + Stopp + + + Overlap + Overlapp + + + Comment + Kommentar + + + &OK + &OK + + + &Cancel + &Avbryt + + + Transition If Previous Cart Ends Before + Overgang viss førre korg endar før + + + Transition Type: + Overgangstype: + + + + ListLogs + + Select a Log + Vel ein logg + + + NAME + NAMN + + + DESCRIPTION + SKILDRING + + + SERVICE + TENEST + + + &OK + &OK + + + &Cancel + &Avbryt + + + + ListReports + + RDLibrary Reports + RDLibrary-rapportar + + + Log Listing + Loggopplisting + + + Log Exception Report + Rapport for loggunntak + + + Type: + Type: + + + &Generate + La&g + + + &Close + &Lukk + + + [none] + [ingen] + + + Log Check + Loggsjekk + + + No exceptions found. + Fann ingen unntak. + + + Effective Date: + + + + &Select + + + + + MainWidget + + RDLogEdit - Host + RdLogEdit - Vert + + + User: [Unknown] + Brukar: [Ukjent] + + + Can't Connect + Greier ikkje kopla til + + + LOG NAME + LOGGNAMN + + + DESCRIPTION + SKILDRING + + + SERVICE + TENEST + + + MUSIC + MUSIKK + + + TRAFFIC + TRAFIKK + + + TRACKS + SPOR + + + VALID FROM + GYLDIG FRÅ + + + VALID TO + GYLDIG TIL + + + AUTO REFRESH + AUTO-OPPDATER + + + ORIGIN + OPPHAV + + + LAST LINKED + SIST LENKA + + + LAST MODIFIED + SIST ENDRA + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + Voice +&Tracker + Røys&t- +sporar + + + Log +Report + Logg- +rapport + + + &Close + &Lukk + + + User + Brukar + + + Add Log + Legg til logg + + + Log Exists + Loggen eksisterer + + + Log Already Exists! + Loggen finst frå før! + + + Delete Log + Slett logg + + + This will also delete the + Dette slettar òg + + + voice tracks associated with this log. +Continue? + røystspor som er kopla til denne loggen. +Vil du halda fram? + + + Tracks Exist + Sporet eksisterer + + + Always + Alltid + + + TFN + TFN + + + RDLogEdit + RDLogEdit + + + Unable to delete log, audio deletion error! + + + + RDLogEdit -- Database Skew + + + + This version of RDLogEdit is incompatible with the version installed on the server. +See your system administrator for an update! + + + + Host + + + + Unknown + + + + Service + + + + ALL + + + + Filter + + + + Clear + + + + + VoiceTracker + + Voice Tracker + Spor røyst + + + Edit Cue Markers + + + + Undo Segue Changes + + + + Set Start Point Here + + + + Set End Point Here + + + + Set to Hook Markers + + + + Start + + + + Record + + + + Save + + + + &Previous +Track + + + + &Next +Track + + + + Remaining + + + + Tracks + + + + Time + + + + + + + + TIME + TID + + + TRANS + OVERG + + + CART + KORG + + + GROUP + GRUPPE + + + LENGTH + LENGD + + + TITLE + TITTEL + + + ARTIST + ARTIST + + + Do Over + + + + Hit Post + + + + Insert +Track + + + + Delete +Track + + + + &Close + &Lukk + + + No VoiceTrack Group + + + + No voicetracking group has been defined for this service, +therefore only existing transitions will be editable. + + + + Import + + + + Cart Creation Failure + + + + Unable to create new cart for voice track! + + + + RDLogEdit + RDLogEdit + + + Audio Deletion Error! + + + + TRACK + SPOR + + + Voice Track + Røyst-spor + + + Track List + + + + No more tracks! + + + + [end of log] + + + + [cart not found] + [fann ikkje korga] + + + MARKER + MARKØR + + + LOG CHAIN + LOGGKJEDE + + + LINK + LENKJE + + + [music import] + [musikkimport] + + + [traffic import] + [trafikkimport] + + + PLAY + SPEL + + + SEGUE + KRYSSTON + + + STOP + STOPP + + + Abort + + + + Segue Changed + + + + Save segue changes? + + + + RDLogEdit - Voice Tracker + + + + This cart cannot contain any additional cuts! + + + + ALBUM + + + + LABEL + SELSKAP + + + diff --git a/rdlogedit/rdlogedit_nn.ts b/rdlogedit/rdlogedit_nn.ts new file mode 100644 index 00000000..8a98dc18 --- /dev/null +++ b/rdlogedit/rdlogedit_nn.ts @@ -0,0 +1,1124 @@ + + + AddMeta + + Insert a: + Set inn: + + + &Marker + ein &markør + + + Voice &Track + eit røys&t-spor + + + Log C&hain + Ei logg&kjede + + + &Cancel + &Avbryt + + + + EditChain + + Edit Log Chain + Rediger loggkjede + + + Start at: + Start på: + + + Action If Previous Event Still Playing + Handling viss den førre hendinga spelar enno + + + Start Immediately + Start med ein gong + + + Make Next + Gjer til neste + + + Wait up to + Vent opp til + + + Play + Spel + + + Segue + Krysston + + + Stop + Stopp + + + Overlap + Overlapp + + + Transition Type: + Overgangstype: + + + Log Name + Loggnamn + + + Select + Vel + + + Log Description + Loggskildring + + + &OK + &OK + + + &Cancel + &Avbryt + + + Transition If Previous Cart Ends Before + Overgang viss førre korg endar før + + + + EditLog + + Edit Log + Rediger logg + + + Log Name: + Loggnamn: + + + Tracks: + Spor: + + + Origin: + Opphav: + + + Description: + Skildring: + + + Service: + Tenest: + + + Yes + Ja + + + No + Nei + + + Enable AutoRefresh: + Skru på AutoOppdater: + + + Start Date: + Startdato: + + + End Date: + Sluttdato: + + + Start Date Enabled + Startdato på + + + End Date Enabled + Sluttdato på + + + TIME + TID + + + TRANS + OVERG + + + CART + KORG + + + GROUP + GRUPPE + + + LENGTH + LENGD + + + TITLE + TITTEL + + + ARTIST + ARTIST + + + CLIENT + KLIENT + + + AGENCY + AGENT + + + LABEL + SELSKAP + + + SOURCE + KJELDE + + + LINE ID + LINE-ID + + + COUNT + TELLING + + + Insert +Cart + Set inn +korg + + + Insert +Meta + Set inn +meta + + + Edit + Rediger + + + Delete + Slett + + + Cut + Klypp ut + + + Copy + Kopier + + + Paste + Lim inn + + + &Save + &Lagra + + + Save +&As + Lagra &som + + + &Reports + Ra&pportar + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Carts + Ugyldige korger + + + This log contains one or more carts +that are invalid for the selected service! + Denne loggen inneheld ei eller fleire +korger som er ugyldige for denne tenesta! + + + Voice Track + Røyst-spor + + + The log contains carts that are disabled +for the selected service! + +Do you still want to save? + Loggen inneheld korger som er skrudd av +for denne tenesta! + +Vil du lagra likevel? + + + Add Log + Legg til logg + + + Log Exists + Loggen eksisterer + + + Log Already Exists! + Loggen finst frå før! + + + RDLogEdit + RDLogEdit + + + The log has been modified. +Do you want to save your changes? + Loggen er endra. +Vil du lagra endringane? + + + The log contains carts that are disabled +for the selected service! + Loggen inneheld korger som er +skrudd av for denne tenesta! + + + PLAY + SPEL + + + STOP + STOPP + + + SEGUE + KRYSSTON + + + OVERLAP + OVERLAPP + + + [cart not found] + [fann ikkje korga] + + + MARKER + MARKØR + + + TRACK + SPOR + + + LOG CHAIN + LOGGKJEDE + + + LINK + LENKJE + + + [music import] + [musikkimport] + + + [traffic import] + [trafikkimport] + + + Manual + Manuelt + + + Traffic + Trafikk + + + Music + Musikk + + + RDLogManager + RDLogManager + + + Voice Tracker + Spor røyst + + + --- end of log --- + --- slutt på loggen --- + + + [INVALID CART] + [UGYLDIG KORG] + + + Delete on + + + + Select + Vel + + + Run Length + + + + Next Stop: + + + + Log End: + + + + Selected: + + + + Unable to save log, audio deletion error! + + + + + EditLogLine + + Edit Log Entry + Rediger loggoppføring + + + Start at: + Start på: + + + Action If Previous Event Still Playing + Handling viss den førre hendinga spelar enno + + + Start Immediately + Start med ein gong + + + Make Next + Gjer til neste + + + Wait up to + Vent opp til + + + Play + Spel + + + Segue + Krysston + + + Stop + Stopp + + + Overlap + Overlapp + + + Transition Type: + Overgangstype: + + + No Fade When Segueing At End + Inga uttoning når du overtonar ved slutten + + + Cart + Korg + + + Title + Tittel + + + Artist + Artist + + + Select +Cart + Vel korg + + + &OK + &OK + + + &Cancel + &Avbryt + + + Transition If Previous Cart Ends Before + Overgang viss førre korg endar før + + + Missing Cart + Manglar korg + + + You must supply a cart number! + Du må skriva inn eit korgnummer! + + + Disabled Cart + Korga er skrudd av + + + This cart belongs to a disabled +group for the specified service! + Denne korga høyrer til ei gruppe +som er skrudd av for denne tenesta! + + + No Fade on Segue Out + + + + Duplicate Start Time + + + + An event is already scheduled with this start time! + + + + + EditMarker + + Edit Log Marker + Rediger loggmarkør + + + Start at: + Start på: + + + Action If Previous Event Still Playing + Handling viss den førre hendinga spelar enno + + + Start Immediately + Start med ein gong + + + Make Next + Gjer til neste + + + Wait up to + Vent opp til + + + Play + Spel + + + Segue + Krysston + + + Stop + Stopp + + + Overlap + Overlapp + + + Comment + Kommentar + + + Label + Selskap + + + &OK + &OK + + + &Cancel + &Avbryt + + + Transition If Previous Cart Ends Before + Overgang viss førre korg endar før + + + Transition Type: + Overgangstype: + + + + EditTrack + + Edit Voice Track Marker + Rediger røystspormarkør + + + Start at: + Start på: + + + Action If Previous Event Still Playing + Handling viss den førre hendinga spelar enno + + + Start Immediately + Start med ein gong + + + Make Next + Gjer til neste + + + Wait up to + Vent opp til + + + Play + Spel + + + Segue + Krysston + + + Stop + Stopp + + + Overlap + Overlapp + + + Comment + Kommentar + + + &OK + &OK + + + &Cancel + &Avbryt + + + Transition If Previous Cart Ends Before + Overgang viss førre korg endar før + + + Transition Type: + Overgangstype: + + + + ListLogs + + Select a Log + Vel ein logg + + + NAME + NAMN + + + DESCRIPTION + SKILDRING + + + SERVICE + TENEST + + + &OK + &OK + + + &Cancel + &Avbryt + + + + ListReports + + RDLibrary Reports + RDLibrary-rapportar + + + Log Listing + Loggopplisting + + + Log Exception Report + Rapport for loggunntak + + + Type: + Type: + + + &Generate + La&g + + + &Close + &Lukk + + + [none] + [ingen] + + + Log Check + Loggsjekk + + + No exceptions found. + Fann ingen unntak. + + + Effective Date: + + + + &Select + + + + + MainWidget + + RDLogEdit - Host + RdLogEdit - Vert + + + User: [Unknown] + Brukar: [Ukjent] + + + Can't Connect + Greier ikkje kopla til + + + LOG NAME + LOGGNAMN + + + DESCRIPTION + SKILDRING + + + SERVICE + TENEST + + + MUSIC + MUSIKK + + + TRAFFIC + TRAFIKK + + + TRACKS + SPOR + + + VALID FROM + GYLDIG FRÅ + + + VALID TO + GYLDIG TIL + + + AUTO REFRESH + AUTO-OPPDATER + + + ORIGIN + OPPHAV + + + LAST LINKED + SIST LENKA + + + LAST MODIFIED + SIST ENDRA + + + &Add + &Legg til + + + &Edit + R&ediger + + + &Delete + &Slett + + + Voice +&Tracker + Røys&t- +sporar + + + Log +Report + Logg- +rapport + + + &Close + &Lukk + + + User + Brukar + + + Add Log + Legg til logg + + + Log Exists + Loggen eksisterer + + + Log Already Exists! + Loggen finst frå før! + + + Delete Log + Slett logg + + + This will also delete the + Dette slettar òg + + + voice tracks associated with this log. +Continue? + røystspor som er kopla til denne loggen. +Vil du halda fram? + + + Tracks Exist + Sporet eksisterer + + + Always + Alltid + + + TFN + TFN + + + RDLogEdit + RDLogEdit + + + Unable to delete log, audio deletion error! + + + + RDLogEdit -- Database Skew + + + + This version of RDLogEdit is incompatible with the version installed on the server. +See your system administrator for an update! + + + + Host + + + + Unknown + + + + Service + + + + ALL + + + + Filter + + + + Clear + + + + + VoiceTracker + + Voice Tracker + Spor røyst + + + Edit Cue Markers + + + + Undo Segue Changes + + + + Set Start Point Here + + + + Set End Point Here + + + + Set to Hook Markers + + + + Start + + + + Record + + + + Save + + + + &Previous +Track + + + + &Next +Track + + + + Remaining + + + + Tracks + + + + Time + + + + + + + + TIME + TID + + + TRANS + OVERG + + + CART + KORG + + + GROUP + GRUPPE + + + LENGTH + LENGD + + + TITLE + TITTEL + + + ARTIST + ARTIST + + + Do Over + + + + Hit Post + + + + Insert +Track + + + + Delete +Track + + + + &Close + &Lukk + + + No VoiceTrack Group + + + + No voicetracking group has been defined for this service, +therefore only existing transitions will be editable. + + + + Import + + + + Cart Creation Failure + + + + Unable to create new cart for voice track! + + + + RDLogEdit + RDLogEdit + + + Audio Deletion Error! + + + + TRACK + SPOR + + + Voice Track + Røyst-spor + + + Track List + + + + No more tracks! + + + + [end of log] + + + + [cart not found] + [fann ikkje korga] + + + MARKER + MARKØR + + + LOG CHAIN + LOGGKJEDE + + + LINK + LENKJE + + + [music import] + [musikkimport] + + + [traffic import] + [trafikkimport] + + + PLAY + SPEL + + + SEGUE + KRYSSTON + + + STOP + STOPP + + + Abort + + + + Segue Changed + + + + Save segue changes? + + + + RDLogEdit - Voice Tracker + + + + This cart cannot contain any additional cuts! + + + + ALBUM + + + + LABEL + SELSKAP + + + diff --git a/rdlogedit/rdlogedit_pt_BR.ts b/rdlogedit/rdlogedit_pt_BR.ts new file mode 100644 index 00000000..200f622b --- /dev/null +++ b/rdlogedit/rdlogedit_pt_BR.ts @@ -0,0 +1,1110 @@ + + + AddMeta + + Insert a: + Inserir um(a): + + + &Marker + &Marcador + + + Voice &Track + &Faixa de Voz + + + Log C&hain + Corrente de Lista + + + &Cancel + &Cancelar + + + + EditChain + + Edit Log Chain + Editar Corrente de Lista + + + Start at: + Inicie às: + + + Action If Previous Event Still Playing + +Ação se Evento anterior estiver sendo executado + + + Start Immediately + Iniciar Imediatamente + + + Make Next + Ser Próxima + + + Wait up to + Esperar até + + + Play + Simples + + + Segue + Sobre + + + Stop + Pare + + + Transition Type: + Tipo de Transição: + + + Log Name + Nome da Lista + + + Select + Selecionar + + + Log Description + Descrição da Lista + + + &OK + &OK + + + &Cancel + &Cancelar + + + Transition If Previous Cart Ends Before + Transição de Cartão anterior terminar antes + + + + EditLog + + Edit Log + Editar Lista + + + Log Name: + Nome: + + + Tracks: + Faixas: + + + Origin: + Origem: + + + Description: + Descrição: + + + Delete on + Deletar + + + Select + Sel + + + Service: + Serviço: + + + Yes + Sim + + + No + Não + + + Enable AutoRefresh: + Habilitar AutoAtualização: + + + Start Date: + Data de Início: + + + End Date: + Data de Término: + + + Start Date Enabled + Data de Início habilitada + + + End Date Enabled + Data de Término hab + + + Run Length + Duração + + + Next Stop: + Até PARE: + + + Log End: + Até FIM: + + + TIME + HORA + + + TRANS + TRANS + + + CART + CARTÃO + + + GROUP + GRUPO + + + LENGTH + DURAÇÃO + + + TITLE + TÍTULO + + + ARTIST + ARTISTA + + + CLIENT + CLIENTE + + + AGENCY + AGÊNCIA + + + LABEL + SELO + + + SOURCE + FONTE + + + LINE ID + ID DE LINHA + + + COUNT + CONTADOR + + + Insert +Cart + Inserir +Cartão + + + Insert +Meta + Inserir +Meta + + + + Edit + Editar + + + Delete + Deletar + + + Cut + Recortar + + + Copy + Copiar + + + Paste + Colar + + + &Save + &Salvar + + + Save +&As + &Salvar +Como + + + &Reports + &Relatórios + + + &OK + &OK + + + &Cancel + &Cancelar + + + Invalid Carts + Cartões Inválidos + + + This log contains one or more carts +that are invalid for the selected service! + A Lista contém um ou mais cartões +que são inválidos para o serviço selecionado! + + + Voice Track + Faixa de Voz + + + The log contains carts that are disabled +for the selected service! + +Do you still want to save? + A Lista contém cartões que estão desabilitados +para o serviço selecionado! + +Você ainda quer salvar? + + + Add Log + Adicionar Lista + + + Log Exists + Lista Existente + + + Log Already Exists! + Lista já Existe! + + + RDLogEdit + RDListas + + + The log has been modified. +Do you want to save your changes? + A Lista foi modificada. +Você quer salvar suas mudanças? + + + The log contains carts that are disabled +for the selected service! + A Lista contém cartões que estão desabilitados +para o serviço selecionado! + + + PLAY + SIMPLES + + + STOP + PARE + + + SEGUE + SOBRE + + + [cart not found] + [cartão não encontrado] + + + MARKER + MARCADOR + + + TRACK + FAIXA + + + LOG CHAIN + CORRENTE DE LISTA + + + LINK + LINK + + + [music import] + [importar músicas] + + + [traffic import] + [importar tráfego] + + + Manual + Manual + + + Traffic + Tráfego + + + Music + Músicas + + + RDLogManager + RDControle + + + Voice Tracker + Faixas de Voz + + + --- end of log --- + -- fim da lista-- + + + Selected: + Selecionado: + + + [INVALID CART] + CARTÃO INVÁLIDO + + + Unable to save log, audio deletion error! + + + + + EditLogLine + + Edit Log Entry + Editar Entrada na Lista + + + Start at: + Inicie às: + + + Action If Previous Event Still Playing + Ação se Evento anterior estiver sendo executado + + + Start Immediately + Iniciar Imediatamente + + + Make Next + Ser Próxima + + + Wait up to + Esperar até + + + Play + Simples + + + Segue + Sobre + + + Stop + Pare + + + Transition Type: + Tipo de Transição: + + + No Fade on Segue Out + Sem Fade na Saída SOBRE + + + Cart + Cartão + + + Title + Título + + + Artist + Artista + + + Select +Cart + Selecionar + + + &OK + &OK + + + &Cancel + &Cancelar + + + Transition If Previous Cart Ends Before + Transição de Cartão anterior terminar antes + + + Missing Cart + Cartão Faltando + + + You must supply a cart number! + Você deve dar um número ao Cartão! + + + Disabled Cart + Cartão Desabilitado + + + This cart belongs to a disabled +group for the specified service! + Este cartão pertence a um grupo desabilitado +para o Serviço especificado! + + + Duplicate Start Time + Duplicar Hora de Início + + + An event is already scheduled with this start time! + Um evento já foi agendado para esta hora! + + + + EditMarker + + Edit Log Marker + Editar Marcador de Lista + + + Start at: + Inicie às: + + + Action If Previous Event Still Playing + Ação se Evento anterior estiver sendo executado + + + Start Immediately + Iniciar Imediatamente + + + Make Next + Ser Próxima + + + Wait up to + Esperar até + + + Play + Simples + + + Segue + Sobre + + + Stop + Pare + + + Comment + Comentário + + + Label + Selo + + + &OK + &OK + + + &Cancel + &Cancelar + + + Transition If Previous Cart Ends Before + Transição se Cartão anterior terminar antes + + + Transition Type: + Tipo de Transição: + + + + EditTrack + + Edit Voice Track Marker + Editar Marcador de Faixa de Voz + + + Start at: + Inicie às: + + + Action If Previous Event Still Playing + +Ação se Evento anterior estiver sendo executado + + + Start Immediately + Iniciar Imediatamente + + + Make Next + Ser Próxima + + + Wait up to + Esperar até + + + Play + Simples + + + Segue + Sobre + + + Stop + Pare + + + Comment + Comentário + + + &OK + &OK + + + &Cancel + &Cancelar + + + Transition If Previous Cart Ends Before + Transição de Cartão anterior terminar antes + + + Transition Type: + Tipo de Transição: + + + + ListLogs + + Select a Log + Selecionar a Lista + + + NAME + NOME + + + DESCRIPTION + DESCRIÇÃO + + + SERVICE + SERVIÇO + + + &OK + &OK + + + &Cancel + &Cancelar + + + + ListReports + + RDLibrary Reports + Relatórios da RDBiblio + + + Log Listing + Descrição da Lista + + + Log Exception Report + Relatório de Exceção de Lista + + + Type: + Tipo: + + + Effective Date: + Data Efetiva: + + + &Select + &Selecionar + + + &Generate + &Gerar + + + &Close + &Fechar + + + [none] + [nenhum] + + + Log Check + Checar Lista + + + No exceptions found. + Exceções não Encontradas. + + + + MainWidget + + RDLogEdit - Host + RDListas - Cliente + + + User: [Unknown] + Usuário: [Desconhecido] + + + Can't Connect + Não foi possível Conectar + + + LOG NAME + NOME DA LISTA + + + DESCRIPTION + DESCRIÇÃO + + + SERVICE + SERVIÇO + + + MUSIC + MÚSICAS + + + TRAFFIC + TRÁFEGO + + + TRACKS + FAIXAS + + + VALID FROM + VÁLIDO A PARTIR DE + + + VALID TO + VÁLIDO ATÉ + + + AUTO REFRESH + AUTO ATUALIZAÇÃO + + + ORIGIN + ORIGEM + + + LAST LINKED + ÚLTIMO LINKADO + + + LAST MODIFIED + ÚLTIMO MODIFICADO + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + Voice +&Tracker + &Editar +Faixa de Voz + + + Log +Report + Relatório + + + &Close + &Fechar + + + User + Usuário + + + Add Log + Adicionar Lista + + + Log Exists + Lista Existente + + + Log Already Exists! + Lista já Existe! + + + Delete Log + Deletar Lista + + + This will also delete the + Esta ação também deletarará @ + + + voice tracks associated with this log. +Continue? + faixas de voz associadas a esta Lista. +Continuar? + + + Tracks Exist + Faixa Existente + + + Always + Sempre + + + TFN + + + + RDLogEdit + RDListas + + + Unable to delete log, audio deletion error! + + + + RDLogEdit -- Database Skew + + + + This version of RDLogEdit is incompatible with the version installed on the server. +See your system administrator for an update! + + + + Host + + + + Unknown + + + + Service + + + + ALL + + + + Filter + + + + Clear + + + + + VoiceTracker + + Voice Tracker + Faixas de Voz + + + Edit Cue Markers + Editar Marcador de Escuta + + + Undo Segue Changes + Desfazer Mudanças de Sobre + + + Set Start Point Here + Marcar Início aqui + + + Set End Point Here + Marcar Término aqui + + + Start + Comece + + + Record + Gravar + + + Save + Salvar + + + &Previous +Track + &Última +Faixa + + + &Next +Track + &Próxima +Faixa + + + Remaining + Faltando + + + Tracks + Faixas + + + Time + Tempo + + + + + + + TIME + HORA + + + TRANS + TRANS + + + CART + CARTÃO + + + GROUP + GRUPO + + + LENGTH + DURAÇÃO + + + TITLE + TÍTULO + + + ARTIST + ARTISTA + + + Do Over + Gravar +por cima + + + Hit Post + Chegue no +Marcador + + + Insert +Track + Inserir +Faixa + + + Delete +Track + Deletar +Faixa + + + &Close + &Fechar + + + No VoiceTrack Group + Não há Grupo para Faixa de Voz + + + No voicetracking group has been defined for this service, +therefore only existing transitions will be editable. + Não foi definido um grupo para faixas de voz neste serviço, +Assim sendo, somente transições existentes serão editáveis. + + + Import + Importar + + + Cart Creation Failure + Falha na criação de Cartão + + + Unable to create new cart for voice track! + Não foi possível criar um novo cartão para esta faixa de voz! + + + TRACK + FAIXA + + + Voice Track + Faixa de Voz + + + Track List + Lista de Faixas + + + No more tracks! + Não há mais faixas! + + + [end of log] + [Fim da Lista] + + + [cart not found] + [cartão não encontrado] + + + MARKER + MARCADOR + + + LOG CHAIN + CORRENTE DE LISTA + + + LINK + ENLACE + + + [music import] + [importar de música] + + + [traffic import] + [importar de tráfego] + + + PLAY + SIMPLES + + + SEGUE + SOBRE + + + STOP + PARE + + + Abort + Abortar + + + Segue Changed + Sobre Modificado + + + Save segue changes? + Salvar mudanças nos "Sobres"? + + + Set to Hook Markers + + + + RDLogEdit + RDListas + + + Audio Deletion Error! + + + + RDLogEdit - Voice Tracker + + + + This cart cannot contain any additional cuts! + + + + ALBUM + + + + LABEL + SELO + + + diff --git a/rdlogedit/voice_tracker.cpp b/rdlogedit/voice_tracker.cpp new file mode 100644 index 00000000..63b3f3ca --- /dev/null +++ b/rdlogedit/voice_tracker.cpp @@ -0,0 +1,4146 @@ +// voice_tracker.cpp +// +// A Rivendell Voice Tracker +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: voice_tracker.cpp,v 1.84.2.4.2.2 2014/05/21 18:19:43 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// +// Icons +// +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" +#include "../icons/marker.xpm" +#include "../icons/chain.xpm" +#include "../icons/track_cart.xpm" +#include "../icons/music.xpm" +#include "../icons/notemarker.xpm" +#include "../icons/traffic.xpm" +#include "../icons/mic16.xpm" + + +VoiceTracker::VoiceTracker(const QString &logname,QString *import_path, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_log_name=logname; + edit_import_path=import_path; + edit_coding=RDCae::Pcm16; + edit_track_cart=NULL; + edit_sliding=false; + edit_scrolling=false; + track_line=-1; + track_loaded=false; + track_offset=false; + segue_loaded=false; + track_recording=false; + track_changed=false; + track_recording_pos=0; + track_record_ran=false; + track_aborting=false; + track_block_valid=false; + track_time_remaining=0; + track_time_counter=0; + track_start_time=QTime(0,0,0); + track_size_altered=false; + for(unsigned i=0;i<3;i++) { + edit_scroll_pos[i]=-1; + edit_track_line[i]=-1; + edit_segue_start_offset[i]=0; + edit_track_cuts[i]=NULL; + wpg[i]=NULL; + } + menu_clicked_point=-1; + edit_shift_pressed=false; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumWidth(sizeHint().width()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Voice Tracker")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont label_font=QFont("Hevetica",12,QFont::Normal); + label_font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Bold); + small_font.setPixelSize(10); + QFont timer_font=QFont("Helvetica",20,QFont::Bold); + timer_font.setPixelSize(20); + + // + // Create Icons + // + edit_playout_map=new QPixmap(play_xpm); + edit_macro_map=new QPixmap(rml5_xpm); + edit_marker_map=new QPixmap(marker_xpm); + edit_chain_map=new QPixmap(chain_xpm); + edit_track_cart_map=new QPixmap(track_cart_xpm); + edit_music_map=new QPixmap(music_xpm); + edit_mic16_map=new QPixmap(mic16_xpm); + edit_notemarker_map=new QPixmap(notemarker_xpm); + edit_traffic_map=new QPixmap(traffic_xpm); + + // + // Create Palettes + // + track_record_palette=QPalette(TRACKER_RECORD_BUTTON_COLOR,backgroundColor()); + track_start_palette=QPalette(TRACKER_START_BUTTON_COLOR,backgroundColor()); + track_done_palette=QPalette(TRACKER_DONE_BUTTON_COLOR,backgroundColor()); + track_abort_palette=QPalette(TRACKER_ABORT_BUTTON_COLOR,backgroundColor()); + + // + // Create Track and Target Region + // + track_track_rect=new QRect(0,0,TRACKER_X_WIDTH,3*TRACKER_Y_HEIGHT); + for(int i=0;i<3;i++) { + track_trackzones_rect[i]= + new QRect(0,i*TRACKER_Y_HEIGHT,TRACKER_X_WIDTH,TRACKER_Y_HEIGHT); + } + for(unsigned i=0;istationName()); + edit_input_card=conf->inputCard(); + edit_input_port=conf->inputPort(); + edit_output_card=conf->outputCard(); + edit_output_port=conf->outputPort(); + edit_format=conf->format(); + edit_samprate=rdsystem->sampleRate(); + edit_bitrate=conf->bitrate(); + edit_chans=conf->defaultChannels(); + play_start_macro=conf->startCart(); + play_end_macro=conf->endCart(); + record_start_macro=conf->recStartCart(); + record_end_macro=conf->recEndCart(); + track_preroll=conf->tailPreroll(); + edit_scroll_threshold=TRACKER_X_WIDTH-track_preroll/TRACKER_MSECS_PER_PIXEL; + edit_settings=new RDSettings(); + conf->getSettings(edit_settings); + delete conf; + + RDLibraryConf *lconf=new RDLibraryConf(log_config->stationName(),0); + edit_tail_preroll=lconf->tailPreroll(); + edit_threshold_level=lconf->trimThreshold(); + delete lconf; + + // + // Voicetrack Group + // + RDLog *log=new RDLog(logname); + RDSvc *svc=new RDSvc(log->service()); + track_group=new RDGroup(svc->trackGroup()); + track_tracks=log->scheduledTracks()-log->completedTracks(); + delete svc; + delete log; + + // + // Play Decks + // + for(int i=0;i<3;i++) { + edit_deck[i]=new RDPlayDeck(rdcae,i); + edit_deck[i]->setCard(edit_output_card); + edit_deck[i]->setPort(edit_output_port); + connect(edit_deck[i],SIGNAL(stateChanged(int,RDPlayDeck::State)), + this,SLOT(stateChangedData(int,RDPlayDeck::State))); + connect(edit_deck[i],SIGNAL(segueStart(int)), + this,SLOT(segueStartData(int))); + } + + // + // Record Slot Connections + // + connect(rdcae,SIGNAL(recordLoaded(int,int)), + this,SLOT(recordLoadedData(int,int))); + connect(rdcae,SIGNAL(recording(int,int)), + this,SLOT(recordingData(int,int))); + connect(rdcae,SIGNAL(recordStopped(int,int)), + this,SLOT(recordStoppedData(int,int))); + connect(rdcae,SIGNAL(recordUnloaded(int,int,unsigned)), + this,SLOT(recordUnloadedData(int,int,unsigned))); + + // + // Log Machine + // + track_log=new RDLog(edit_log_name,false); + track_log_event=new RDLogEvent(RDLog::tableName(edit_log_name)); + track_log_event->load(); + + // + // Right-Click Menu + // + track_menu=new QPopupMenu(this,"track_menu"); + connect(track_menu,SIGNAL(aboutToShow()),this,SLOT(updateMenuData())); + connect(track_menu,SIGNAL(aboutToHide()),this,SLOT(hideMenuData())); + track_menu-> + insertItem(tr("Edit Cue Markers"),this,SLOT(editAudioData()),0,0); + track_menu-> + insertItem(tr("Undo Segue Changes"),this,SLOT(undoChangesData()),0,1); + track_menu-> + insertItem(tr("Set Start Point Here"),this,SLOT(setStartPointData()),0,2); + track_menu-> + insertItem(tr("Set End Point Here"),this,SLOT(setEndPointData()),0,3); + track_menu-> + insertItem(tr("Set to Hook Markers"),this,SLOT(setHookPointData()),0,4); + + // + // Track 1 Button + // + track_track1_button=new QPushButton(this,"track_track1_button"); + track_track1_button->setGeometry(sizeHint().width()-90,15,70,70); + track_track1_button->setPalette(track_start_palette); + track_track1_button->setFont(font); + track_track1_button->setText(tr("Start")); + connect(track_track1_button,SIGNAL(clicked()),this,SLOT(track1Data())); + + // + // Record Button + // + track_record_button=new QPushButton(this,"track_record_button"); + track_record_button->setGeometry(sizeHint().width()-90,95,70,70); + track_record_button->setPalette(track_record_palette); + track_record_button->setFont(font); + track_record_button->setText(tr("Record")); + connect(track_record_button,SIGNAL(clicked()),this,SLOT(recordData())); + + // + // Track 2 Button + // + track_track2_button=new QPushButton(this,"track_track2_button"); + track_track2_button->setGeometry(sizeHint().width()-90,175,70,70); + track_track2_button->setPalette(track_start_palette); + track_track2_button->setFont(font); + track_track2_button->setText(tr("Start")); + connect(track_track2_button,SIGNAL(clicked()),this,SLOT(track2Data())); + if(!rdlogedit_conf->enableSecondStart()) { + track_track2_button->hide(); + } + + // + // Finished Button + // + track_finished_button=new QPushButton(this,"track_finished_button"); + if(rdlogedit_conf->enableSecondStart()) { + track_finished_button->setGeometry(sizeHint().width()-90,255,70,70); + } + else { + track_finished_button->setGeometry(sizeHint().width()-90,175,70,70); + } + track_finished_button->setPalette(track_done_palette); + track_finished_button->setFont(font); + track_finished_button->setText(tr("Save")); + connect(track_finished_button,SIGNAL(clicked()),this,SLOT(finishedData())); + + // + // Previous Button + // + track_previous_button=new QPushButton(this,"track_previous_button"); + track_previous_button-> + setGeometry(sizeHint().width()-290,sizeHint().height()-60,80,50); + track_previous_button->setFont(font); + track_previous_button->setText(tr("&Previous\nTrack")); + connect(track_previous_button,SIGNAL(clicked()),this,SLOT(previousData())); + + // + // Next Button + // + track_next_button=new QPushButton(this,"track_next_button"); + track_next_button-> + setGeometry(sizeHint().width()-200,sizeHint().height()-60,80,50); + track_next_button->setFont(font); + track_next_button->setText(tr("&Next\nTrack")); + connect(track_next_button,SIGNAL(clicked()),this,SLOT(nextData())); + + // + // Play Button + // + track_play_button=new RDTransportButton(RDTransportButton::Play,this, + "track_play_button"); + track_play_button->setGeometry(20,265,80,50); + track_play_button-> + setPalette(QPalette(backgroundColor(),colorGroup().mid())); + connect(track_play_button,SIGNAL(clicked()), + this,SLOT(playData())); + + // + // Stop Button + // + track_stop_button=new RDTransportButton(RDTransportButton::Stop,this, + "track_stop_button"); + track_stop_button->setGeometry(110,265,80,50); + track_stop_button-> + setPalette(QPalette(backgroundColor(),colorGroup().mid())); + track_stop_button->setOnColor(red); + track_stop_button->on(); + connect(track_stop_button,SIGNAL(clicked()),this,SLOT(stopData())); + + // + // Audio Meter + // + track_meter=new RDStereoMeter(this,"track_meter"); + track_meter->setGeometry(205,260,track_meter->sizeHint().width(), + track_meter->sizeHint().height()); + track_meter->setMode(RDSegMeter::Peak); + track_meter_timer=new QTimer(this,"track_meter_timer"); + connect(track_meter_timer,SIGNAL(timeout()),this,SLOT(meterData())); + + // + // Track Length Readout + // + edit_length_label=new QLabel(this,"edit_length_label"); + edit_length_label->setText("-:--:--.-"); + edit_length_label->setGeometry(565,255,110,25); + edit_length_label->setBackgroundColor(white); + edit_length_label->setAlignment(AlignCenter); + edit_length_label->setFont(timer_font); + + // + // Tracks Remaining Readout + // + QLabel *label=new QLabel(tr("Remaining"),this,"label"); + label->setGeometry(555,288,116,14); + label->setFont(small_font); + label->setAlignment(Qt::AlignHCenter); + label->setPalette(QPalette(backgroundColor(),colorGroup().mid())); + edit_tracks_remaining_label=new QLabel(this,"edit_tracks_remaining_label"); + edit_tracks_remaining_label->setText("0"); + edit_tracks_remaining_label->setGeometry(565,313,40,18); + edit_tracks_remaining_label->setBackgroundColor(white); + edit_tracks_remaining_label->setAlignment(AlignCenter); + edit_tracks_remaining_label->setFont(label_font); + label=new QLabel(tr("Tracks"),this,"label"); + label->setGeometry(565,300,40,14); + label->setFont(small_font); + label->setAlignment(Qt::AlignHCenter); + label->setPalette(QPalette(backgroundColor(),colorGroup().mid())); + + edit_time_remaining_label=new QLabel(this,"edit_time_remaining_label"); + edit_time_remaining_label->setText("0:00:00.0"); + edit_time_remaining_label->setGeometry(615,313,60,18); + edit_time_remaining_label->setBackgroundColor(white); + edit_time_remaining_label->setAlignment(AlignCenter); + edit_time_remaining_label->setFont(label_font); + edit_time_remaining_palette[0]=edit_time_remaining_label->palette(); + edit_time_remaining_palette[1]=edit_time_remaining_label->palette(); + edit_time_remaining_palette[1]. + setColor(QPalette::Active,QColorGroup::Foreground,red); + edit_time_remaining_palette[1]. + setColor(QPalette::Inactive,QColorGroup::Foreground,red); + label=new QLabel(tr("Time"),this,"label"); + label->setGeometry(615,300,60,14); + label->setFont(small_font); + label->setAlignment(Qt::AlignHCenter); + label->setPalette(QPalette(backgroundColor(),colorGroup().mid())); + + // + // Log List + // + track_log_list=new LogListView(this,"track_log_list"); + track_log_list-> + setGeometry(10,335,sizeHint().width()-120,sizeHint().height()-405); + track_log_list->setAllColumnsShowFocus(true); + track_log_list->setItemMargin(5); + connect(track_log_list,SIGNAL(clicked(QListViewItem *,const QPoint &,int)), + this,SLOT(logClickedData(QListViewItem *,const QPoint &,int))); + connect(track_log_list,SIGNAL(transitionChanged(int,RDLogLine::TransType)), + this,SLOT(transitionChangedData(int,RDLogLine::TransType))); + track_log_list->addColumn(tr(" ")); + track_log_list->setColumnAlignment(0,AlignCenter); + track_log_list->addColumn(tr("TIME")); + track_log_list->setColumnAlignment(1,AlignCenter); + track_log_list->addColumn(tr("TRANS")); + track_log_list->setColumnAlignment(2,AlignCenter); + track_log_list->addColumn(tr("CART")); + track_log_list->setColumnAlignment(3,AlignCenter); + track_log_list->addColumn(tr("GROUP")); + track_log_list->setColumnAlignment(4,AlignCenter); + track_log_list->addColumn(tr("LENGTH")); + track_log_list->setColumnAlignment(5,AlignRight); + track_log_list->addColumn(tr("TITLE")); + track_log_list->setColumnAlignment(6,AlignLeft); + track_log_list->addColumn(tr("ARTIST")); + track_log_list->setColumnAlignment(7,AlignLeft); + track_log_list->addColumn(tr("ALBUM")); + track_log_list->setColumnAlignment(8,AlignLeft); + track_log_list->addColumn(tr("LABEL")); + track_log_list->setColumnAlignment(9,AlignLeft); + for(int i=0;icolumns();i++) { + track_log_list->setColumnSortType(i,RDListView::LineSort); + } + + // + // Reset Button + // + track_reset_button=new QPushButton(this,"track_reset_button"); + track_reset_button-> + setGeometry(sizeHint().width()-90,sizeHint().height()-160,70,70); + track_reset_button->setFont(font); + track_reset_button->setText(tr("Do Over")); + connect(track_reset_button,SIGNAL(clicked()),this,SLOT(resetData())); + + // + // Hit Post Button + // + track_post_button=new QPushButton(this,"track_post_button"); + track_post_button->setGeometry(sizeHint().width()-90,360,70,70); + track_post_button->setFont(font); + track_post_button->setText(tr("Hit Post")); + connect(track_post_button,SIGNAL(clicked()),this,SLOT(postData())); + + // + // Insert Track Button + // + track_insert_button=new QPushButton(this,"track_insert_button"); + track_insert_button->setGeometry(20,sizeHint().height()-60,80,50); + track_insert_button->setFont(font); + track_insert_button->setText(tr("Insert\nTrack")); + connect(track_insert_button,SIGNAL(clicked()),this,SLOT(insertData())); + + // + // Delete Track Button + // + track_delete_button=new QPushButton(this,"track_delete_button"); + track_delete_button->setGeometry(110,sizeHint().height()-60,80,50); + track_delete_button->setFont(font); + track_delete_button->setText(tr("Delete\nTrack")); + connect(track_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Close Button + // + track_close_button=new QPushButton(this,"track_close_button"); + track_close_button-> + setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + track_close_button->setFont(font); + track_close_button->setText(tr("&Close")); + connect(track_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + for(int i=0;isize();i++) { + if(track_log_event->logLine(i)->type()==RDLogLine::Track) { + track_line=i; + track_loaded=true; + LoadTrack(track_line); + LoadBlockLength(track_line); + i=track_log_event->size(); + } + } + RefreshList(); + track_log_list->ensureVisible(0,track_log_list-> + itemPos(track_log_list->selectedItem()),0,track_log_list->size().height()/2); + UpdateControls(); + UpdateRemaining(); + + if(track_group->name().isEmpty()) { + QMessageBox::warning(this,tr("No VoiceTrack Group"), + tr("No voicetracking group has been defined for this service,\ntherefore only existing transitions will be editable.")); + } +} + + +VoiceTracker::~VoiceTracker() +{ + for(int i=0;i<3;i++) { + delete wpg[i]; + wpg[i]=NULL; + } +} + + +QSize VoiceTracker::sizeHint() const +{ + return QSize(800,700); +} + + +QSizePolicy VoiceTracker::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void VoiceTracker::keyPressEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Less: + if(!edit_wave_name[0].isEmpty() && !TransportActive()) + DragTrack(0,400); + else + if(!edit_wave_name[1].isEmpty() && !TransportActive()) + DragTrack(1,400); + else + if(!edit_wave_name[2].isEmpty() && !TransportActive()) + DragTrack(2,400); + + break; + + case Qt::Key_Greater: + if(!edit_wave_name[0].isEmpty() && !TransportActive()) + DragTrack(0,-400); + else + if(!edit_wave_name[1].isEmpty() && !TransportActive()) + DragTrack(1,-400); + else + if(!edit_wave_name[2].isEmpty() && !TransportActive()) + DragTrack(2,-400); + break; + + case Qt::Key_Shift: + edit_shift_pressed=true; + break; + + default: + QWidget::keyPressEvent(e); + break; + } +} + + +void VoiceTracker::keyReleaseEvent(QKeyEvent *e) +{ + switch(e->key()) { + case Qt::Key_Shift: + edit_shift_pressed=false; + break; + + default: + QWidget::keyPressEvent(e); + break; + } +} + + +void VoiceTracker::wheelEvent(QWheelEvent *e) +{ + if(edit_shift_pressed) { + if(e->y()delta()); + } + else { + if(e->y()<(TRACKER_Y_ORIGIN+2*TRACKER_Y_HEIGHT)) { + DragTrack(1,e->delta()); + } + else { + if(e->y()<(TRACKER_Y_ORIGIN+3*TRACKER_Y_HEIGHT)) { + DragTrack(2,e->delta()); + } + } + } + } + else { + if(!edit_wave_name[0].isEmpty() && !TransportActive()) + DragTrack(0,e->delta()); + else + if(!edit_wave_name[1].isEmpty() && !TransportActive()) + DragTrack(1,e->delta()); + else + if(!edit_wave_name[2].isEmpty() && !TransportActive()) + DragTrack(2,e->delta()); + } +} + + +void VoiceTracker::updateMenuData() +{ + if(!edit_wave_name[edit_rightclick_track].isEmpty()) { + if(edit_rightclick_track==1 && track_loaded) { + track_menu->setItemEnabled(0,false); + } + else { + track_menu->setItemEnabled(0,true); + } + } + else { + track_menu->setItemEnabled(0,false); + } + track_menu->setItemEnabled(1,track_changed); + track_menu->setItemEnabled(2, + (!edit_wave_name[edit_rightclick_track].isEmpty())); + track_menu->setItemEnabled(3, + (!edit_wave_name[edit_rightclick_track].isEmpty())); + + if(!edit_wave_name[edit_rightclick_track].isEmpty()) { + RDCut hook_cut=RDCut(edit_logline[edit_rightclick_track]->cartNumber(), + edit_logline[edit_rightclick_track]->cutNumber()); + if(hook_cut.hookStartPoint()>=0 && hook_cut.hookEndPoint()>=0) { + track_menu->setItemEnabled(4,true); + } + else { + track_menu->setItemEnabled(4,false); + } + } + else { + track_menu->setItemEnabled(4,false); + } +// if(edit_wave_name[edit_rightclick_track].isEmpty() +// || edit_logline[edit_rightclick_track]->segueGain()==0) { +// track_menu->setItemEnabled(5,false); +// } +// else { +// track_menu->setItemEnabled(5,true); +// } + menu_clicked_point=edit_rightclick_pos; + DrawTrackMap(edit_rightclick_track); + WriteTrackMap(edit_rightclick_track); +} + + +void VoiceTracker::hideMenuData() +{ + menu_clicked_point=-1; + DrawTrackMap(edit_rightclick_track); + WriteTrackMap(edit_rightclick_track); +} + + +void VoiceTracker::playData() +{ + if(TransportActive()) { + return; + } + track_redraw_count=0; + for(int i=0;i<3;i++) { + track_redraw[i]=false; + } + int start= + edit_wave_origin[0]-edit_logline[0]->startPoint(); + if(start<0) { + start=0; + } + if((start<=(edit_logline[0]->segueEndPoint()- + edit_logline[0]->startPoint()))&& + (!edit_wave_name[0].isEmpty())) { + if(start>(edit_logline[0]->segueStartPoint()- + edit_logline[0]->startPoint())) { + edit_segue_start_offset[1]=start- + (edit_logline[0]->segueStartPoint()- + edit_logline[0]->startPoint()); + if(edit_wave_name[1].isEmpty()) { + edit_segue_start_offset[2]=edit_segue_start_offset[1]; + } + else { + if(start>(edit_logline[1]->segueStartPoint()- + edit_logline[1]->startPoint())) { + edit_segue_start_offset[2]=edit_segue_start_offset[1]- + edit_logline[1]->segueStartPoint()- + edit_logline[1]->startPoint(); + } + else { + edit_segue_start_offset[2]=0; + } + } + } + else { + edit_segue_start_offset[1]=0; + } + edit_deck[0]->setCart(edit_logline[0],false); + edit_deck[0]-> + play(start,edit_logline[0]->segueStartPoint(), + edit_logline[0]->segueEndPoint()); + } + else { + if(edit_wave_name[1].isEmpty()) { + start=edit_wave_origin[2]- + edit_logline[2]->startPoint(); + if(start<=(edit_logline[2]->segueEndPoint()- + edit_logline[2]->startPoint())) { + start=edit_wave_origin[2]-edit_logline[2]-> + startPoint(RDLogLine::CartPointer); + if(start<0) { + start=0; + } + } + edit_deck[2]->setCart(edit_logline[2],false); + edit_deck[2]-> + play(start,edit_logline[2]->segueStartPoint(), + edit_logline[2]->segueEndPoint()); + } + else { + start=edit_wave_origin[1]- + edit_logline[1]->startPoint(); + if(start<=(edit_logline[1]->segueEndPoint()- + edit_logline[1]->startPoint())) { + if(start<0) { + start=0; + } + if(start>(edit_logline[1]->segueStartPoint()- + edit_logline[1]->startPoint())) { + edit_segue_start_offset[2]=start- + (edit_logline[1]->segueStartPoint()- + edit_logline[1]->startPoint()); + } + else { + edit_segue_start_offset[2]=0; + } + edit_deck[1]->setCart(edit_logline[1],false); + edit_deck[1]-> + play(start,edit_logline[1]->segueStartPoint(), + edit_logline[1]->segueEndPoint()); + } + else { + start=edit_wave_origin[2]- + edit_logline[2]->startPoint(); + if(start<=(edit_logline[2]->segueEndPoint()- + edit_logline[2]->startPoint())) { + start=edit_wave_origin[2]- + edit_logline[2]->startPoint(); + if(start<0) { + start=0; + } + } + edit_deck[2]->setCart(edit_logline[2],false); + edit_deck[2]-> + play(start,edit_logline[2]->segueStartPoint(), + edit_logline[2]->segueEndPoint()); + } + } + } +} + + +void VoiceTracker::stopData() +{ + edit_deck[0]->stop(); + edit_deck[1]->stop(); + edit_deck[2]->stop(); +} + + +void VoiceTracker::track1Data() +{ + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + if(item==NULL) { + return; + } + if(track_track1_button->text()==tr("Import")) { + if(!ImportTrack(item)) { + QMessageBox::warning(this,tr("Cart Creation Failure"), + tr("Unable to create new cart for voice track!")); + return; + } + UpdateRemaining(); + UpdateControls(); + return; + } + if(!InitTrack()) { + QMessageBox::warning(this,tr("Cart Creation Failure"), + tr("Unable to create new cart for voice track!")); + return; + } + rdcae->loadRecord(edit_input_card,edit_input_port, + edit_track_cuts[1]->cutName(), + edit_coding,edit_chans,edit_samprate,edit_bitrate); + playData(); + UpdateControls(); +} + + +void VoiceTracker::recordData() +{ + if(edit_deck_state==VoiceTracker::DeckIdle) { + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + if(item==NULL) { + return; + } + if(track_record_button->text()==tr("Import")) { + if(!ImportTrack(item)) { + QMessageBox::warning(this,tr("Cart Creation Failure"), + tr("Unable to create new cart for voice track!")); + return; + } + UpdateRemaining(); + UpdateControls(); + return; + } + if(!InitTrack()) { + QMessageBox::warning(this,tr("Cart Creation Failure"), + tr("Unable to create new cart for voice track!")); + return; + } + rdcae->loadRecord(edit_input_card,edit_input_port, + edit_track_cuts[1]->cutName(), + edit_coding,edit_chans,edit_samprate,edit_bitrate); + edit_sliding=true; + edit_cursor_pos=-edit_wave_origin[2]/TRACKER_MSECS_PER_PIXEL; + } + if(!edit_sliding) { + edit_wave_origin[2]=edit_wave_origin[0]-edit_deck[0]->currentPosition()- + edit_logline[0]->startPoint()+ + edit_logline[2]->startPoint(); + DrawTrackMap(2); + WriteTrackMap(2); + edit_sliding=true; + } + track_event_player->exec(record_start_macro); + edit_wave_name[1]=RDCut::pathName(edit_track_cuts[1]->cutName()); + wpg[1]=new RDWavePainter(edit_wave_map[1],edit_track_cuts[1], + rdstation_conf,rduser,log_config); + wpg[1]->end(); + rdcae->record(edit_input_card,edit_input_port,0,0); + track_record_ran=true; + track_record_start_time=GetCurrentTime(); + if(edit_deck_state==VoiceTracker::DeckTrack1) { + track_time_remaining+=edit_deck[0]->currentPosition()+ + edit_logline[0]->startPoint()- + edit_logline[0]->segueStartPoint(); + } + track_time_remaining_start=track_time_remaining; + edit_deck[0]->duckDown(edit_logline[0]->endPoint()- + edit_logline[0]->startPoint()- + edit_deck[0]->currentPosition()); + edit_deck_state=VoiceTracker::DeckTrack2; + track_start_time=track_log_event->blockStartTime(track_line); + if(!edit_wave_name[0].isEmpty() && track_start_time>QTime(0,0,0)){ + track_start_time=track_start_time.addMSecs(-edit_logline[0]-> + segueLength(RDLogLine::Segue)); + track_start_time=track_start_time.addMSecs(edit_deck[0]->currentPosition()); + } + DrawTrackMap(1); + UpdateControls(); +} + + +void VoiceTracker::track2Data() +{ + if((edit_deck_state!=VoiceTracker::DeckTrack1)&& + (edit_deck_state!=VoiceTracker::DeckTrack2)) { + return; + } + if(!edit_sliding) { + edit_wave_origin[2]=edit_wave_origin[0]-edit_deck[0]->currentPosition(); + DrawTrackMap(2); + WriteTrackMap(2); + } + else { + edit_sliding=false; + } + if(edit_wave_name[1].isEmpty()) { + edit_segue_start_point[0]=edit_deck[0]->currentPosition(); + } + else { + edit_segue_start_point[1]=track_recording_pos; + } + edit_deck_state=VoiceTracker::DeckTrack3; + + int new_end=edit_deck[0]->currentPosition()+ + edit_logline[0]->startPoint()+TRACKER_FORCED_SEGUE; + if(!edit_wave_name[0].isEmpty() && + edit_logline[0]->endPoint()>new_end && + edit_deck[0]->state()==RDPlayDeck::Playing) { + if(edit_logline[0]->fadedownPoint()>(new_end-TRACKER_FORCED_SEGUE) || + edit_logline[0]->fadedownGain()==0) { + edit_logline[0]->setFadedownPoint(new_end-TRACKER_FORCED_SEGUE, + RDLogLine::LogPointer); + edit_logline[0]->setEndPoint(new_end, + RDLogLine::LogPointer); + edit_logline[0]->setSegueEndPoint(new_end, + RDLogLine::LogPointer); + edit_logline[0]->setFadedownGain(RD_FADE_DEPTH); + edit_deck[0]->stop(TRACKER_FORCED_SEGUE,RD_FADE_DEPTH); + } + } + + StartNext(0,2); + UpdateControls(); +} + + +void VoiceTracker::finishedData() +{ + switch(edit_deck_state) { + case VoiceTracker::DeckIdle: + if(track_changed) { + SaveTrack(track_line); + } + break; + + case VoiceTracker::DeckTrack1: + track_aborting=true; + stopData(); + rdcae->unloadRecord(edit_input_card,edit_input_port); + edit_deck_state=VoiceTracker::DeckIdle; + resetData(); + break; + + case VoiceTracker::DeckTrack2: + if(rdlogedit_conf->enableSecondStart()) { + if(edit_wave_name[2].isEmpty()|| + ((edit_logline[2]->transType()!=RDLogLine::Segue))) { + FinishTrack(); + } + else { + track_aborting=true; + stopData(); + rdcae->stopRecord(edit_input_card,edit_input_port); + edit_deck_state=VoiceTracker::DeckIdle; + resetData(); + } + } + else { + FinishTrack(); + } + break; + + case VoiceTracker::DeckTrack3: + FinishTrack(); + break; + } + UpdateRemaining(); + UpdateControls(); +} + + +void VoiceTracker::postData() +{ + if(edit_wave_name[2].isEmpty()) { + return; + } + if(!track_changed) { + PushSegues(); + track_changed=true; + } + int talk_end=edit_logline[2]->talkEndPoint(); + if(talk_endstartPoint()) { + talk_end=edit_logline[2]->startPoint(); + } + int segue_start=edit_logline[1]->endPoint()- + edit_logline[1]->startPoint()- + (talk_end-edit_logline[2]->startPoint()); + if(segue_startstartPoint()) { + segue_start=edit_logline[1]->startPoint()+10; + } + if(segue_start>edit_logline[1]->endPoint()) { + segue_start=edit_logline[1]->endPoint()-10; + } + edit_logline[1]->setSegueStartPoint(segue_start,RDLogLine::LogPointer); + edit_logline[1]->setSegueGain(0); + edit_logline[1]-> + setAverageSegueLength(edit_logline[1]-> + segueStartPoint()- + edit_logline[1]->startPoint()); + edit_wave_origin[2]=edit_wave_origin[1]- + (segue_start-edit_logline[1]->startPoint()); + + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + RenderTransition(item->line()); + UpdateControls(); + UpdateRemaining(); +} + + +void VoiceTracker::resetData() +{ + if(track_loaded&&(edit_logline[1]->type()==RDLogLine::Cart)) { + if(edit_track_cart!=NULL) { + delete edit_track_cart; + } + edit_track_cart=new RDCart(edit_logline[1]->cartNumber()); + edit_logline[1]->setCartNumber(0); + edit_logline[1]->setType(RDLogLine::Track); + edit_logline[1]->setSource(RDLogLine::Manual); + edit_logline[1]->setOriginUser(""); + edit_logline[1]->setOriginDateTime(QDateTime()); + // printf("CART: %u TITLE: %s\n",edit_track_cart->number(),(const char *)edit_track_cart->title()); + edit_logline[1]->setMarkerComment(edit_track_cart->title()); + edit_logline[1]->setForcedLength(0); + edit_logline[1]->clearTrackData(RDLogLine::AllTrans); + track_log_event->removeCustomTransition(edit_track_line[1]); + if(!edit_track_cart->remove(rdstation_conf,rduser,log_config)) { + QMessageBox::warning(this,tr("RDLogEdit"),tr("Audio Deletion Error!")); + } + delete edit_track_cart; + edit_track_cart=NULL; + if(edit_track_cuts[1]!=NULL) { + delete edit_track_cuts[1]; + edit_track_cuts[1]=NULL; + } + edit_wave_name[1]=""; + delete wpg[1]; + wpg[1]=NULL; + if(!edit_wave_name[2].isEmpty()) { + track_log_event->removeCustomTransition(edit_track_line[2]); + } + } + else { + track_log_event->removeCustomTransition(edit_track_line[1]); + } + SaveTrack(track_line); + LoadTrack(track_line); + for(int i=0;i<3;i++) { + DrawTrackMap(i); + WriteTrackMap(i); + } + RDListViewItem *real_item=(RDListViewItem *)track_log_list->selectedItem(); + RDListViewItem *item=NULL; + if(track_offset) { + item=GetItemByLine(real_item->line()-1); + } + else { + item=real_item; + } + if(item==NULL) { + return; + } + if(track_loaded) { + item->setPixmap(0,*edit_mic16_map); + item->setText(3,tr("TRACK")); + item->setText(4,""); + item->setText(5,""); + track_tracks++; + } + LoadBlockLength(track_line); + RefreshLine(real_item); + if(!track_offset) { + item=(RDListViewItem *)real_item->nextSibling(); + } + if((real_item!=item)&&(item!=NULL)) { + RefreshLine(item); + } + UpdateRemaining(); + UpdateControls(); +} + + +void VoiceTracker::insertData() +{ + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + if(item==NULL) { + return; + } + int line=item->line(); + SaveTrack(line); + if(line==TRACKER_MAX_LINENO) { + line=track_log_event->size(); + } + track_log_event->insert(line,1,true); + track_log_event->logLine(line)->setType(RDLogLine::Track); + track_log_event->logLine(line)->setTransType(RDLogLine::Segue); + track_log_event->logLine(line)->setMarkerComment(tr("Voice Track")); + EditTrack *edit=new EditTrack(track_log_event->logLine(line),this); + if(edit->exec()>=0) { + while(item!=NULL) { + if(item->line()!=TRACKER_MAX_LINENO) { + item->setLine(item->line()+1); + } + item=(RDListViewItem *)item->nextSibling(); + } + item=new RDListViewItem(track_log_list); + item->setLine(line); + RefreshLine(item); + track_log_list->setSelected(item,true); + track_log_list->ensureVisible(0,track_log_list->itemPos(item), + 0,track_log_list->size().height()/2); + track_tracks++; + track_size_altered=true; + track_line=-1; + logClickedData(item,QPoint(),0); + UpdateRemaining(); + UpdateControls(); + } + else { + track_log_event->remove(line,1); + } + delete edit; +} + + +void VoiceTracker::insertData(int line,RDLogLine *logline,bool warn) +{ + SaveTrack(line); + track_log_event->insert(line,1,true); + *track_log_event->logLine(line)=*logline; + RDListViewItem *item=GetItemByLine(line); + while(item!=NULL) { + if(item->line()!=TRACKER_MAX_LINENO) { + item->setLine(item->line()+1); + } + item=(RDListViewItem *)item->nextSibling(); + } + item=new RDListViewItem(track_log_list); + item->setLine(line); + RefreshLine(item); + track_log_list->ensureVisible(0,track_log_list->itemPos(item), + 0,track_log_list->size().height()/2); + track_tracks++; + track_size_altered=true; + track_line=-1; + track_changed=false; + logClickedData(item,QPoint(),0); + UpdateRemaining(); + UpdateControls(); +} + + +void VoiceTracker::deleteData() +{ + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + if(track_offset) { + item=GetItemByLine(item->line()-1); + } + if(item==NULL) { + return; + } + deleteData(item->line(),true); +} + + +void VoiceTracker::deleteData(int line,bool warn) +{ + SaveTrack(line); + track_log_event->remove(line,1,true); + RDListViewItem *l=(RDListViewItem *)GetItemByLine(line)->nextSibling(); + while(l!=NULL) { + if(l->line()!=TRACKER_MAX_LINENO) { + l->setLine(l->line()-1); + } + l=(RDListViewItem *)l->nextSibling(); + } + if((l=(RDListViewItem *)GetItemByLine(line)->nextSibling())!=NULL) { + track_log_list->setSelected(l,true); + } + delete GetItemByLine(line); + track_line=-1; + logClickedData(l,QPoint(),0); + track_tracks--; + track_size_altered=true; + UpdateControls(); + UpdateRemaining(); +} + + +void VoiceTracker::previousData() +{ + RDListViewItem *current=(RDListViewItem *)track_log_list->selectedItem(); + if(current==NULL) { + return; + } + RDListViewItem *item=(RDListViewItem *)track_log_list->firstChild(); + RDListViewItem *previous=NULL; + while(item!=current) { + if(item->line()!=TRACKER_MAX_LINENO) { + if((track_log_event->logLine(item->line())->type()==RDLogLine::Track)|| + (track_log_event->logLine(item->line())->source()== + RDLogLine::Tracker)) { + previous=item; + } + } + item=(RDListViewItem *)item->nextSibling(); + } + if(previous==NULL) { + QMessageBox::information(this,tr("Track List"),tr("No more tracks!")); + return; + } + track_log_list->setSelected(previous,true); + track_log_list->ensureVisible(0,track_log_list->itemPos(previous), + 0,track_log_list->size().height()/2); + logClickedData(previous,QPoint(),0); + track_loaded=true; +} + + +void VoiceTracker::nextData() +{ + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + if(item==NULL) { + return; + } + item=(RDListViewItem *)item->nextSibling(); + while(item!=NULL) { + if(item->line()!=TRACKER_MAX_LINENO) { + if((track_log_event->logLine(item->line())->type()==RDLogLine::Track)|| + (track_log_event->logLine(item->line())->source()== + RDLogLine::Tracker)) { + track_log_list->setSelected(item,true); + track_log_list->ensureVisible(0,track_log_list->itemPos(item), + 0,track_log_list->size().height()/2); + logClickedData(item,QPoint(),0); + track_loaded=true; + return; + } + } + item=(RDListViewItem *)item->nextSibling(); + } + QMessageBox::information(this,tr("Track List"), + tr("No more tracks!")); +} + + +void VoiceTracker::editAudioData() +{ + RDCart *rdcart=new RDCart(edit_logline[edit_rightclick_track]->cartNumber()); + RDEditAudio *edit= + new RDEditAudio(rdcart,edit_logline[edit_rightclick_track]->cutName(), + rdcae,rduser,rdstation_conf,log_config,edit_output_card, + edit_output_port,edit_tail_preroll, + edit_threshold_level,this); + if(edit->exec()!=-1) { + rdcart->updateLength(); + edit_logline[edit_rightclick_track]->refreshPointers(); + if(edit_logline[edit_rightclick_track]->fadeupPoint()< + edit_logline[edit_rightclick_track]->startPoint() && + edit_logline[edit_rightclick_track]->fadeupPoint()>=0) { + edit_logline[edit_rightclick_track]->setFadeupPoint( + edit_logline[edit_rightclick_track]->startPoint(),RDLogLine::LogPointer); + } + if(edit_logline[edit_rightclick_track]->fadeupPoint()> + edit_logline[edit_rightclick_track]->endPoint()) { + edit_logline[edit_rightclick_track]->setFadeupPoint( + edit_logline[edit_rightclick_track]->endPoint(),RDLogLine::LogPointer); + } + if(edit_logline[edit_rightclick_track]->fadedownPoint()< + edit_logline[edit_rightclick_track]->startPoint() && + edit_logline[edit_rightclick_track]->fadedownPoint()>=0) { + edit_logline[edit_rightclick_track]->setFadedownPoint( + edit_logline[edit_rightclick_track]->startPoint(),RDLogLine::LogPointer); + } + if(edit_logline[edit_rightclick_track]->fadedownPoint()> + edit_logline[edit_rightclick_track]->endPoint()) { + edit_logline[edit_rightclick_track]->setFadedownPoint( + edit_logline[edit_rightclick_track]->endPoint(),RDLogLine::LogPointer); + } + DrawTrackMap(edit_rightclick_track); + WriteTrackMap(edit_rightclick_track); + } + delete edit; + delete rdcart; +} + + +void VoiceTracker::setStartPointData() +{ + if(!track_changed) { + PushSegues(); + track_changed=true; + } + + int fadeup_diff=edit_logline[edit_rightclick_track]->fadeupPoint()- + edit_logline[edit_rightclick_track]->startPoint(); + + int newpoint=edit_rightclick_pos*TRACKER_MSECS_PER_PIXEL+ + edit_wave_origin[edit_rightclick_track]; + if(newpoint<0) + newpoint=0; + if(newpoint>edit_logline[edit_rightclick_track]->endPoint()) + newpoint=edit_logline[edit_rightclick_track]->endPoint(); + edit_logline[edit_rightclick_track]-> + setStartPoint(newpoint,RDLogLine::LogPointer); + + if(edit_logline[edit_rightclick_track]-> + endPoint(RDLogLine::LogPointer)<0) + edit_logline[edit_rightclick_track]-> + setEndPoint(edit_logline[edit_rightclick_track]-> + endPoint(RDLogLine::CartPointer), + RDLogLine::LogPointer); + + edit_logline[edit_rightclick_track]-> + setFadeupPoint(edit_logline[edit_rightclick_track]->startPoint()+ + fadeup_diff,RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->fadeupPoint(RDLogLine::CartPointer)> + edit_logline[edit_rightclick_track]->fadeupPoint()) + edit_logline[edit_rightclick_track]-> + setFadeupPoint(edit_logline[edit_rightclick_track]-> + fadeupPoint(RDLogLine::CartPointer),RDLogLine::LogPointer); + + + if(edit_logline[edit_rightclick_track]->fadeupPoint()< + edit_logline[edit_rightclick_track]->startPoint()) + edit_logline[edit_rightclick_track]-> + setFadeupPoint(edit_logline[edit_rightclick_track]->startPoint(), + RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->fadeupPoint()> + edit_logline[edit_rightclick_track]->endPoint()) + edit_logline[edit_rightclick_track]-> + setFadeupPoint(edit_logline[edit_rightclick_track]->endPoint(), + RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->fadedownPoint()< + edit_logline[edit_rightclick_track]->startPoint() && + edit_logline[edit_rightclick_track]->fadedownPoint()>=0) + edit_logline[edit_rightclick_track]-> + setFadedownPoint(edit_logline[edit_rightclick_track]->startPoint(), + RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->segueStartPoint()< + edit_logline[edit_rightclick_track]->startPoint() && + edit_logline[edit_rightclick_track]->segueStartPoint()>=0) + edit_logline[edit_rightclick_track]-> + setSegueStartPoint(edit_logline[edit_rightclick_track]->startPoint(), + RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->fadeupPoint(RDLogLine::CartPointer)>=0) + edit_logline[edit_rightclick_track]->setFadeupGain(RD_FADE_DEPTH); + + edit_logline[edit_rightclick_track]->setForcedLength( + edit_logline[edit_rightclick_track]->endPoint()- + edit_logline[edit_rightclick_track]->startPoint()); + + edit_logline[edit_rightclick_track]->setHasCustomTransition(true); + + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + RenderTransition(item->line()); + UpdateControls(); + UpdateRemaining(); + RefreshList(); + item=(RDListViewItem *)track_log_list->selectedItem(); + track_log_list->ensureVisible(0,track_log_list->itemPos(item),0,track_log_list->size().height()/2); +} + + +void VoiceTracker::setEndPointData() +{ + if(!track_changed) { + PushSegues(); + track_changed=true; + } + + int fadedown_diff=edit_logline[edit_rightclick_track]->endPoint()- + edit_logline[edit_rightclick_track]->fadedownPoint(); + + int newpoint=edit_rightclick_pos*TRACKER_MSECS_PER_PIXEL+ + edit_wave_origin[edit_rightclick_track]; + if(newpoint> + edit_logline[edit_rightclick_track]->endPoint(RDLogLine::CartPointer)) + newpoint=edit_logline[edit_rightclick_track]-> + endPoint(RDLogLine::CartPointer); + if(newpoint< + edit_logline[edit_rightclick_track]->startPoint()) + newpoint=edit_logline[edit_rightclick_track]-> + startPoint(); + edit_logline[edit_rightclick_track]-> + setEndPoint(newpoint,RDLogLine::LogPointer); + + if(edit_logline[edit_rightclick_track]-> + startPoint(RDLogLine::LogPointer)<0) + edit_logline[edit_rightclick_track]-> + setStartPoint(edit_logline[edit_rightclick_track]-> + startPoint(RDLogLine::CartPointer), + RDLogLine::LogPointer); + + edit_logline[edit_rightclick_track]-> + setFadedownPoint(edit_logline[edit_rightclick_track]->endPoint()- + fadedown_diff,RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->fadedownPoint(RDLogLine::CartPointer)>=0 + && edit_logline[edit_rightclick_track]->fadedownPoint(RDLogLine::CartPointer)< + edit_logline[edit_rightclick_track]->fadedownPoint()) + edit_logline[edit_rightclick_track]-> + setFadedownPoint(edit_logline[edit_rightclick_track]-> + fadedownPoint(RDLogLine::CartPointer),RDLogLine::LogPointer); + + if(edit_logline[edit_rightclick_track]->fadedownPoint()> + edit_logline[edit_rightclick_track]->endPoint()) + edit_logline[edit_rightclick_track]-> + setFadedownPoint(edit_logline[edit_rightclick_track]->endPoint(), + RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->segueStartPoint()> + edit_logline[edit_rightclick_track]->endPoint()) + edit_logline[edit_rightclick_track]-> + setSegueStartPoint(edit_logline[edit_rightclick_track]->endPoint(), + RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->fadeupPoint()> + edit_logline[edit_rightclick_track]->endPoint()) + edit_logline[edit_rightclick_track]-> + setFadeupPoint(edit_logline[edit_rightclick_track]->endPoint(), + RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->segueStartPoint()< + edit_logline[edit_rightclick_track]->startPoint() && + edit_logline[edit_rightclick_track]->segueStartPoint()>=0) + edit_logline[edit_rightclick_track]-> + setSegueStartPoint(edit_logline[edit_rightclick_track]->startPoint(), + RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->fadedownPoint()< + edit_logline[edit_rightclick_track]->startPoint() && + edit_logline[edit_rightclick_track]->fadedownPoint()>=0) + edit_logline[edit_rightclick_track]-> + setFadedownPoint(edit_logline[edit_rightclick_track]->startPoint(), + RDLogLine::LogPointer); + + if(edit_logline[edit_rightclick_track]->fadedownPoint(RDLogLine::CartPointer)>=0) + edit_logline[edit_rightclick_track]->setFadedownGain(RD_FADE_DEPTH); + + + edit_logline[edit_rightclick_track]-> + setSegueEndPoint(edit_logline[edit_rightclick_track]->endPoint(), + RDLogLine::LogPointer); + edit_logline[edit_rightclick_track]->setForcedLength( + edit_logline[edit_rightclick_track]->endPoint()- + edit_logline[edit_rightclick_track]->startPoint()); + + if(edit_logline[edit_rightclick_track+1]!=NULL) { + edit_logline[edit_rightclick_track+1]->setHasCustomTransition(true); + } + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + RenderTransition(item->line()); + UpdateControls(); + UpdateRemaining(); + RefreshList(); + item=(RDListViewItem *)track_log_list->selectedItem(); + track_log_list->ensureVisible(0,track_log_list->itemPos(item),0,track_log_list->size().height()/2); +} + + +void VoiceTracker::setHookPointData() +{ + if(!track_changed) { + PushSegues(); + track_changed=true; + } + + RDCut hook_cut=RDCut(edit_logline[edit_rightclick_track]->cartNumber(), + edit_logline[edit_rightclick_track]->cutNumber()); + if(hook_cut.hookStartPoint()>=0 && hook_cut.hookEndPoint()>=0 && + hook_cut.hookStartPoint()setStartPoint( + hook_cut.hookStartPoint(),RDLogLine::LogPointer); + edit_logline[edit_rightclick_track]->setFadeupPoint( + hook_cut.hookStartPoint(),RDLogLine::LogPointer); + edit_logline[edit_rightclick_track]->setEndPoint( + hook_cut.hookEndPoint(),RDLogLine::LogPointer); + edit_logline[edit_rightclick_track]->setSegueEndPoint( + hook_cut.hookEndPoint(),RDLogLine::LogPointer); + edit_logline[edit_rightclick_track]->setSegueStartPoint( + hook_cut.hookEndPoint()-500,RDLogLine::LogPointer); + edit_logline[edit_rightclick_track]->setFadedownPoint( + hook_cut.hookEndPoint()-500,RDLogLine::LogPointer); + edit_logline[edit_rightclick_track]->setFadedownGain(RD_FADE_DEPTH); + } + else { + return; + } + + if(edit_logline[edit_rightclick_track]->endPoint()> + edit_logline[edit_rightclick_track]->endPoint(RDLogLine::CartPointer)) + edit_logline[edit_rightclick_track]->setEndPoint( + edit_logline[edit_rightclick_track]->endPoint(RDLogLine::CartPointer), + RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->endPoint()< + edit_logline[edit_rightclick_track]->startPoint()) + edit_logline[edit_rightclick_track]->setEndPoint( + edit_logline[edit_rightclick_track]->startPoint(), + RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->segueStartPoint()< + edit_logline[edit_rightclick_track]->startPoint() && + edit_logline[edit_rightclick_track]->segueStartPoint()>=0) + edit_logline[edit_rightclick_track]-> + setSegueStartPoint(edit_logline[edit_rightclick_track]->startPoint(), + RDLogLine::LogPointer); + if(edit_logline[edit_rightclick_track]->fadedownPoint()< + edit_logline[edit_rightclick_track]->startPoint() && + edit_logline[edit_rightclick_track]->fadedownPoint()>=0) + edit_logline[edit_rightclick_track]-> + setFadedownPoint(edit_logline[edit_rightclick_track]->startPoint(), + RDLogLine::LogPointer); + + edit_logline[edit_rightclick_track]->setForcedLength( + edit_logline[edit_rightclick_track]->endPoint()- + edit_logline[edit_rightclick_track]->startPoint()); + + edit_logline[edit_rightclick_track]->setHasCustomTransition(true); + if(edit_logline[edit_rightclick_track+1]!=NULL) { + edit_logline[edit_rightclick_track+1]->setHasCustomTransition(true); + } + + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + RenderTransition(item->line()); + UpdateControls(); + UpdateRemaining(); + RefreshList(); + item=(RDListViewItem *)track_log_list->selectedItem(); + track_log_list->ensureVisible(0,track_log_list->itemPos(item),0,track_log_list->size().height()/2); +} + + +void VoiceTracker::undoChangesData() +{ + PopSegues(); + track_changed=false; + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + RenderTransition(item->line()); + RefreshLine(item); + if(GetItemByLine(item->line()+1)!=NULL){ + RefreshLine(GetItemByLine(item->line()+1)); + } +} + + +void VoiceTracker::stateChangedData(int id,RDPlayDeck::State state) +{ + // printf("stateChangeData(%d,%d)\n",id,state); + + if(state==RDPlayDeck::Playing) { + track_play_button->on(); + track_stop_button->off(); + track_event_player->exec(play_start_macro); + } + else { + if((edit_deck_state==VoiceTracker::DeckTrack1)&& + (state==RDPlayDeck::Finished)&&(!track_record_ran)) { + finishedData(); + return; + } + else { + for(int i=0;i<3;i++) { + if(edit_deck[i]->state()==RDPlayDeck::Playing) { + return; + } + } + if(track_recording) { + return; + } + track_play_button->off(); + track_stop_button->on(); + track_event_player->exec(play_end_macro); + edit_deck_state=VoiceTracker::DeckIdle; + positionData(id,-1); + } + } + switch(state) { + case RDPlayDeck::Playing: + case RDPlayDeck::Stopping: + if(!track_meter_timer->isActive()) { + track_meter_timer->start(RD_METER_UPDATE_INTERVAL); + } + UpdateControls(); + break; + + default: + if(!TransportActive()) { + track_meter_timer->stop(); + track_meter->setLeftPeakBar(-10000); + track_meter->setRightPeakBar(-10000); + edit_scrolling=false; + for(unsigned i=0;i<3;i++) { + edit_scroll_pos[i]=-1; + edit_segue_start_offset[i]=0; + } + } + RenderTransition(((RDListViewItem *)track_log_list->selectedItem())-> + line()); + UpdateControls(); + break; + } +} + + +void VoiceTracker::positionData(int id,int msecs) +{ + int edit_scroll_diff; + if(msecs<=0) { + QPainter *p=new QPainter(this); + ClearCursor(p); + delete p; + return; + } + + if((id==1)&&track_recording) { + edit_length_label->setText(RDGetTimeLength(msecs,true)); + track_time_counter=track_time_remaining_start-msecs; + if(edit_deck_state==VoiceTracker::DeckTrack2) { + track_time_remaining= + track_time_remaining_start-msecs; + UpdateRemaining(); + } + } + for(int i=id-1;i>=0;i--) { + if(edit_deck[i]->state()==RDPlayDeck::Playing) { + return; + } + } + if(edit_scroll_pos[id]>=0) + edit_scroll_diff=msecs-edit_scroll_pos[id]; + else + edit_scroll_diff=0; + edit_scroll_pos[id]=msecs; + msecs+=edit_logline[id]->startPoint(); + switch(edit_deck_state) { + case VoiceTracker::DeckIdle: + break; + + case VoiceTracker::DeckTrack1: + if(edit_sliding) { + edit_wave_origin[0]=edit_wave_origin[2]- + edit_logline[2]->startPoint()+msecs; + track_redraw[0]=true; + } + break; + + case VoiceTracker::DeckTrack2: + switch(id) { + case 0: + if(!edit_scrolling) { + edit_wave_origin[0]=edit_wave_origin[2]- + edit_logline[2]->startPoint()+msecs; + } + edit_wave_origin[1]=edit_wave_origin[0]- + edit_segue_start_point[0]; + break; + + case 1: + if(!edit_scrolling) { + edit_wave_origin[1]=edit_wave_origin[2]+msecs- + edit_logline[2]->startPoint(); + } + edit_wave_origin[0]= + edit_wave_origin[1]+edit_segue_start_point[0]; + break; + } + track_redraw[0]=true; + track_redraw[1]=true; + break; + + case VoiceTracker::DeckTrack3: + if((id==0)||(id==1)) { + track_redraw[0]=true; + track_redraw[1]=true; + } + else { + return; + } + break; + } + + if(edit_scrolling&&(edit_scroll_diff>=0)) { + edit_wave_origin[0]+=edit_scroll_diff; + track_redraw[0]=true; + if(!edit_wave_name[1].isEmpty()) { + edit_wave_origin[1]+=edit_scroll_diff; + track_redraw[1]=true; + } + if(!edit_sliding) { + edit_wave_origin[2]+=edit_scroll_diff; + track_redraw[2]=true; + } + } + if(track_recording && (edit_deck[2]->state()==RDPlayDeck::Playing || + edit_deck[2]->state()==RDPlayDeck::Stopping)) { + track_redraw[2]=true; + } + if(track_redraw_count++==TRACKER_SCROLL_SCALE) { + for(unsigned i=0;i<3;i++) { + if(track_redraw[i]) { + DrawTrackMap(i); + WriteTrackMap(i); + track_redraw[i]=false; + } + } + track_redraw_count=0; + } + QPainter *p=new QPainter(this); + p->setPen(black); + p->setBrush(black); + ClearCursor(p); + int x=-1; + if(msecs>=0) { + if((msecs>edit_wave_origin[id])&& + (msecs<(edit_wave_origin[id]+edit_wave_width))) { + x=(int)(((double)(msecs-edit_wave_origin[id]))* + ((double)(edit_wave_map[id]->size().width()))/ + ((double)TRACKER_START_WIDTH))+10; + p->moveTo(x,10); + p->lineTo(x,248); + if(x>edit_scroll_threshold) { + edit_scrolling=true; + } + } + } + p->end(); + delete p; + edit_cursor_pos=x; +// edit_wave_pos[id]=msecs; +} + + +void VoiceTracker::segueStartData(int id) +{ + switch(edit_deck_state) { + case VoiceTracker::DeckIdle: + for(int i=id+1;i<3;i++) { + if(!edit_wave_name[i].isEmpty()) { + if(edit_logline[i]->transType()==RDLogLine::Stop) { + stopData(); + } + else { + StartNext(id); + } + return; + } + } + break; + + case VoiceTracker::DeckTrack1: + edit_sliding=true; + + if(!edit_wave_name[2].isEmpty()) { + edit_wave_origin[2]= + edit_wave_origin[0]-edit_deck[0]->currentPosition()- + edit_logline[0]->startPoint()+ + edit_logline[2]->startPoint(); + } + + break; + + case VoiceTracker::DeckTrack2: + break; + + case VoiceTracker::DeckTrack3: + break; + } +} + + +void VoiceTracker::logClickedData(QListViewItem *item,const QPoint &pt, + int col) +{ + CheckChanges(); + if(item==NULL) { + track_loaded=false; + segue_loaded=false; + edit_length_label->setText("-:--:--.-"); + return; + } + RefreshLine(((RDListViewItem *)item)); + RenderTransition(((RDListViewItem *)item)->line()); +} + + +void VoiceTracker::transitionChangedData(int line,RDLogLine::TransType trans) +{ + track_log_event->logLine(line)->setTransType(trans); + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + if(item==NULL) { + return; + } + RefreshLine(item); + if((trans==RDLogLine::Segue)&&(edit_wave_name[1].isEmpty())) { + resetData(); + } + else { + RenderTransition(item->line()); + } + SaveTrack(track_line); +} + + +void VoiceTracker::meterData() +{ + double ratio[2]={0.0000000001,0.0000000001}; + short level[2]; + + if(track_recording) { + track_recording_pos= + (int)((GetCurrentTime()-track_record_start_time)*1000.0); + positionData(1,track_recording_pos); + } + + for(int i=0;i<3;i++) { + if((edit_deck[i]->state()==RDPlayDeck::Playing)|| + (edit_deck[i]->state()==RDPlayDeck::Stopping)) { + positionData(i,edit_deck[i]->currentPosition()); + rdcae-> + outputMeterUpdate(edit_deck[i]->card(),edit_deck[i]->port(),level); + for(int j=0;j<2;j++) { + ratio[j]+=pow(10.0,((double)level[j])/1000.0); + } + } + if(track_recording) { + rdcae-> + inputMeterUpdate(edit_input_card,edit_input_port,level); + for(int j=0;j<2;j++) { + ratio[j]+=pow(10.0,((double)level[j])/1000.0); + } + } + } + track_meter->setLeftPeakBar((int)(log10(ratio[0])*1000.0)); + track_meter->setRightPeakBar((int)(log10(ratio[1])*1000.0)); +} + + +void VoiceTracker::recordLoadedData(int card,int stream) +{ + // printf("recordLoadedData(%d,%d)\n",card,stream); + if((card!=edit_input_card)||(stream!=edit_input_port)) { + return; + } +} + + +void VoiceTracker::recordingData(int card,int stream) +{ + //printf("recordingData(%d,%d)\n",card,stream); + if((card!=edit_input_card)||(stream!=edit_input_port)) { + return; + } + edit_segue_start_point[0]=edit_logline[0]->startPoint()+ + edit_deck[0]->currentPosition(); + if(!edit_wave_name[1].isEmpty()) { + if((edit_logline[1]->transType()!=RDLogLine::Segue)) { + edit_segue_start_point[0]= + edit_logline[0]->endPoint(); + } + } +// edit_segue_gain[0]=0; + edit_wave_origin[1]=edit_wave_origin[0]+ + edit_deck[0]->currentPosition(); + // rdcae->fadeOutputVolume(edit_deck[0]->card(),edit_deck[0]->stream(), +// edit_deck[0]->port(),edit_segue_gain[0], +// edit_logline[0]->endPoint(RDLogLine::CartPointer)- +// edit_segue_start_point[0]); + if(!track_meter_timer->isActive()) { + track_meter_timer->start(RD_METER_UPDATE_INTERVAL); + } + track_recording=true; +} + + +void VoiceTracker::recordStoppedData(int card,int stream) +{ + // printf("recordStoppedData(%d,%d)\n",card,stream); + if((card!=edit_input_card)||(stream!=edit_input_port)) { + return; + } + rdcae->unloadRecord(edit_input_card,edit_input_port); + track_event_player->exec(record_end_macro); +} + + +void VoiceTracker::recordUnloadedData(int card,int stream,unsigned msecs) +{ + // printf("recordUnloadedData(%d,%d)\n",card,stream); + if((card!=edit_input_card)||(stream!=edit_input_port)) { + return; + } + track_recording=false; + if(!track_aborting) { + edit_track_cuts[1]-> + checkInRecording(rdstation_conf->name(),edit_settings,msecs); + edit_track_cuts[1]->setSampleRate(rdsystem->sampleRate()); + edit_track_cart->updateLength(); + edit_track_cart->resetRotation(); + edit_logline[1]-> + loadCart(edit_track_cart->number(),RDLogLine::Segue,0,false); + edit_logline[1]->setEvent(0,RDLogLine::Segue,false); + edit_logline[1]->setType(RDLogLine::Cart); + edit_logline[1]->setSource(RDLogLine::Tracker); + edit_logline[1]->setOriginUser(rduser->name()); + edit_logline[1]->setOriginDateTime(QDateTime(QDate::currentDate(), + QTime::currentTime())); + edit_logline[1]-> + setSegueStartPoint(edit_segue_start_point[1],RDLogLine::LogPointer); + edit_logline[1]-> + setSegueEndPoint(edit_logline[1]->endPoint(), + RDLogLine::LogPointer); + edit_logline[1]->setSegueGain(0); + edit_logline[1]->setSegueEndPoint(edit_logline[1]->endPoint(),RDLogLine::LogPointer); + edit_logline[1]-> + setFadeupPoint(edit_track_cuts[1]->startPoint(),RDLogLine::LogPointer); + edit_logline[1]->setFadeupGain(RD_FADE_DEPTH); + edit_logline[1]-> + setFadedownPoint(edit_track_cuts[1]->endPoint(),RDLogLine::LogPointer); + edit_logline[1]->setFadedownGain(RD_FADE_DEPTH); + edit_logline[1]->setHasCustomTransition(true); + if(!edit_wave_name[2].isEmpty()) { + edit_logline[2]->setHasCustomTransition(true); + } + if(!edit_wave_name[2].isEmpty()) { + edit_logline[1]-> + setAverageSegueLength(edit_logline[1]-> + segueStartPoint()- + edit_logline[1]-> + startPoint()); + } + edit_wave_origin[1]=edit_logline[1]->startPoint()- + (edit_logline[0]->segueStartPoint()- + edit_wave_origin[0]); + DrawTrackMap(1); + WriteTrackMap(1); + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + if(track_offset) { + item=GetItemByLine(item->line()-1); + } + if(item==NULL) { + return; + } + item->setPixmap(0,*edit_track_cart_map); + item->setText(3,QString().sprintf("%06u",edit_track_cart->number())); + item->setText(4,track_group->name()); + item->setText(5,RDGetTimeLength(edit_track_cart->forcedLength())); + SaveTrack(track_line); + RefreshLine(item); + if(!edit_wave_name[2].isEmpty()) { + RefreshLine((RDListViewItem *)item->nextSibling()); + } + } + else { + positionData(1,-1); + stateChangedData(1,RDPlayDeck::Finished); + } + if(!TransportActive()) { + stateChangedData(2,RDPlayDeck::Finished); + } + UpdateControls(); +} + + +void VoiceTracker::closeData() +{ + stopData(); + CheckChanges(); + if(track_size_altered) { + track_log_event->save(); + } + done(0); +} + + +void VoiceTracker::paintEvent(QPaintEvent *e) +{ + QPainter *p=NULL; + + if(track_line<0) { + p=new QPainter(); + for(int i=0;i<3;i++) { + p->begin(edit_wave_map[i],""); + p->setPen(TRACKER_TEXT_COLOR); + p->setBackgroundColor(gray); + p->eraseRect(0,0,edit_wave_map[i]->size().width(), + edit_wave_map[i]->size().height()); + p->end(); + } + delete p; + } + p=new QPainter(this); + + p->setPen(black); + + p->fillRect(TRACKER_X_ORIGIN,TRACKER_Y_ORIGIN,TRACKER_X_WIDTH-1-2,238, + white); + p->fillRect(TRACKER_X_ORIGIN-2,TRACKER_Y_HEIGHT*3+TRACKER_Y_ORIGIN-1, + TRACKER_X_WIDTH+2,TRACKER_Y_HEIGHT+6,colorGroup().mid()); + + p->moveTo(TRACKER_X_ORIGIN-2,TRACKER_Y_ORIGIN-2); + p->lineTo(TRACKER_X_WIDTH+TRACKER_X_ORIGIN-1,TRACKER_Y_ORIGIN-2); + p->moveTo(TRACKER_X_ORIGIN-1,TRACKER_Y_ORIGIN-1); + p->lineTo(TRACKER_X_WIDTH+TRACKER_X_ORIGIN,TRACKER_Y_ORIGIN-1); + + p->moveTo(TRACKER_X_ORIGIN-2,TRACKER_Y_ORIGIN-2); + p->lineTo(TRACKER_X_ORIGIN-2,TRACKER_Y_HEIGHT*3+TRACKER_Y_ORIGIN-1); + p->moveTo(TRACKER_X_ORIGIN-1,TRACKER_Y_ORIGIN-1); + p->lineTo(TRACKER_X_ORIGIN-1,TRACKER_Y_HEIGHT*3+TRACKER_Y_ORIGIN-2); + + p->moveTo(TRACKER_X_ORIGIN-2,TRACKER_Y_HEIGHT*3+TRACKER_Y_ORIGIN-2); + p->lineTo(TRACKER_X_WIDTH+TRACKER_X_ORIGIN-1, + TRACKER_Y_HEIGHT*3+TRACKER_Y_ORIGIN-2); + p->moveTo(TRACKER_X_ORIGIN+TRACKER_X_ORIGIN-1, + TRACKER_Y_HEIGHT*3+TRACKER_Y_ORIGIN-1); + p->lineTo(TRACKER_X_WIDTH+TRACKER_X_ORIGIN, + TRACKER_Y_HEIGHT*3+TRACKER_Y_ORIGIN-1); + + p->moveTo(TRACKER_X_WIDTH+TRACKER_X_ORIGIN,TRACKER_Y_ORIGIN-2); + p->lineTo(TRACKER_X_WIDTH+TRACKER_X_ORIGIN, + TRACKER_Y_HEIGHT*3+TRACKER_Y_ORIGIN-1); + p->moveTo(TRACKER_X_WIDTH+TRACKER_X_ORIGIN-1,TRACKER_Y_ORIGIN-1); + p->lineTo(TRACKER_X_WIDTH+TRACKER_X_ORIGIN-1, + TRACKER_Y_HEIGHT*3+TRACKER_Y_ORIGIN-2); + + p->moveTo(TRACKER_X_ORIGIN-2,TRACKER_Y_HEIGHT+TRACKER_Y_ORIGIN-2); + p->lineTo(TRACKER_X_WIDTH+TRACKER_X_ORIGIN-1, + TRACKER_Y_HEIGHT+TRACKER_Y_ORIGIN-2); + p->moveTo(TRACKER_X_ORIGIN-1,TRACKER_Y_HEIGHT+TRACKER_Y_ORIGIN-1); + p->lineTo(TRACKER_X_WIDTH+TRACKER_X_ORIGIN-1, + TRACKER_Y_HEIGHT+TRACKER_Y_ORIGIN-1); + + p->moveTo(TRACKER_X_ORIGIN-2,TRACKER_Y_HEIGHT*2+TRACKER_Y_ORIGIN-2); + p->lineTo(TRACKER_X_WIDTH+TRACKER_X_ORIGIN, + TRACKER_Y_HEIGHT*2+TRACKER_Y_ORIGIN-2); + p->moveTo(TRACKER_X_ORIGIN-1,TRACKER_Y_HEIGHT*2+TRACKER_Y_ORIGIN-1); + p->lineTo(TRACKER_X_WIDTH+TRACKER_X_ORIGIN-1, + TRACKER_Y_HEIGHT*2+TRACKER_Y_ORIGIN-1); + + p->moveTo(TRACKER_X_ORIGIN-2,TRACKER_Y_HEIGHT*3+TRACKER_Y_ORIGIN-1); + p->lineTo(TRACKER_X_WIDTH-1+TRACKER_X_ORIGIN+1, + TRACKER_Y_HEIGHT*3+TRACKER_Y_ORIGIN-1); + p->lineTo(TRACKER_X_WIDTH-1+TRACKER_X_ORIGIN+1, + TRACKER_Y_HEIGHT*4+TRACKER_Y_ORIGIN-5+10); + p->lineTo(TRACKER_X_ORIGIN-2,TRACKER_Y_HEIGHT*4+TRACKER_Y_ORIGIN-5+10); + p->lineTo(TRACKER_X_ORIGIN-2,TRACKER_Y_HEIGHT*3+TRACKER_Y_ORIGIN-1); + + WriteTrackMap(0); + WriteTrackMap(1); + WriteTrackMap(2); + + delete p; +} + + +void VoiceTracker::mousePressEvent(QMouseEvent *e) +{ + if(TransportActive()) { + return; + } + switch(e->button()) { + case QMouseEvent::LeftButton: + edit_current_track=GetClick(e,edit_previous_point); + break; + + case QMouseEvent::RightButton: + edit_rightclick_track=GetClick(e,edit_previous_point); + edit_rightclick_pos=edit_previous_point->x(); + if(edit_rightclick_track>=0) { + track_menu->setGeometry(e->globalX(),e->globalY()+20, + track_menu->sizeHint().width(), + track_menu->sizeHint().height()); + track_menu->exec(); + } + break; + + default: + break; + } +} + + +void VoiceTracker::mouseReleaseEvent(QMouseEvent *e) +{ + switch(e->button()) { + case QMouseEvent::LeftButton: + if(edit_current_track>=0) { + track_meter->setLeftPeakBar(-10000); + track_meter->setRightPeakBar(-10000); + } + edit_current_track=-1; + break; + + case QMouseEvent::RightButton: + edit_rightclick_track=-1; + break; + + case QMouseEvent::MidButton: + if(e->y()startPoint())/TRACKER_MSECS_PER_PIXEL)+250); + } + else { + if(e->y()<(TRACKER_Y_ORIGIN+2*TRACKER_Y_HEIGHT)) { + DragTrack(0,((edit_wave_origin[1]-edit_logline[1]->startPoint())/TRACKER_MSECS_PER_PIXEL)+250); + } + else { + if(e->y()<(TRACKER_Y_ORIGIN+3*TRACKER_Y_HEIGHT)) { + DragTrack(0,((edit_wave_origin[2]-edit_logline[2]->startPoint())/TRACKER_MSECS_PER_PIXEL)+250); + } + } + } + break; + + default: + break; + } +} + + +void VoiceTracker::mouseMoveEvent(QMouseEvent *e) +{ + if(TransportActive()) { + return; + } + QPoint pt; + int trackno=GetClick(e,&pt); + if(edit_current_track<0) { + QCursor *cursor=track_arrow_cursor; + if((trackno>=0)&&(track_track_rect->contains(pt))) { + if(!edit_wave_name[trackno].isEmpty()) { + track_current_target=VoiceTracker::TargetSize; + for(unsigned i=0;icontains(pt)&& + (track_target_track[i]==trackno)) { + cursor=track_cross_cursor; + track_current_target=(VoiceTracker::Target)i; + } + } + if(track_current_target==VoiceTracker::TargetSize) { + switch(edit_logline[trackno]->transType()) { + case RDLogLine::Segue: + cursor=track_hand_cursor; + break; + + case RDLogLine::Play: + case RDLogLine::Stop: + case RDLogLine::NoTrans: + if(trackno==0) { + cursor=track_hand_cursor; + } + else { + cursor=track_arrow_cursor; + } + break; + } + } + } + } + if(track_current_cursor!=cursor) { + setCursor(*cursor); + track_current_cursor=cursor; + } + return; + } + if(trackno!=edit_current_track) { + return; + } + if(track_current_cursor==track_hand_cursor) { + DragTrack(edit_current_track,pt.x()-edit_previous_point->x()); + *edit_previous_point=pt; + } + if(track_current_cursor==track_cross_cursor) { + DragTarget(edit_current_track,pt); + } +} + + +void VoiceTracker::LoadTrack(int line) +{ + edit_deck_state=DeckIdle; + edit_cursor_pos=-1; + + if(line<0) { + for(int i=0;i<3;i++) { + if(!(edit_wave_name[i].isEmpty())) { + delete wpg[i]; + wpg[i]=NULL; + } + edit_wave_name[i]=""; + edit_logline[i]=NULL; + edit_wave_origin[i]=0; + edit_wave_width=0; + } + } + else { + // + // Track Mappings + // + if(track_loaded) { + if(track_offset) { + edit_track_line[0]=line-2; + edit_track_line[1]=line-1; + edit_track_line[2]=line; + } + else { + edit_track_line[0]=line-1; + edit_track_line[1]=line; + edit_track_line[2]=line+1; + } + } + else { + if(segue_loaded) { +// edit_track_line[0]=line-1; +// edit_track_line[1]=-1; +// edit_track_line[2]=line; + edit_track_line[0]=line-1; + edit_track_line[1]=line; + edit_track_line[2]=line+1; + } + else { + edit_track_line[0]=-1; + edit_track_line[1]=-1; + edit_track_line[2]=-1; + } + } + + // + // Audio Filenames + // + for(unsigned i=0;i<3;i++) { + edit_wave_name[i]=GetCutName(edit_track_line[i],&edit_track_cuts[i]); + if(!(edit_wave_name[i].isEmpty())) { + if(wpg[i]!=NULL) { + delete wpg[i]; + } + wpg[i]=new RDWavePainter(edit_wave_map[i],edit_track_cuts[i], + rdstation_conf,rduser,log_config); + wpg[i]->end(); + } + } + + // + // Track 0 Parameters + // + if(edit_wave_name[0].isEmpty()) { + edit_logline[0]=track_dummy0_logline; // No initial track, so fake it + edit_logline[0]->clear(); + edit_logline[0]->setStartPoint(0,RDLogLine::CartPointer); + edit_logline[0]->setStartPoint(-1,RDLogLine::LogPointer); + edit_logline[0]->setEndPoint(0,RDLogLine::CartPointer); + edit_logline[0]->setEndPoint(-1,RDLogLine::LogPointer); + edit_wave_origin[0]=0; + } + else { + edit_logline[0]=track_log_event->logLine(edit_track_line[0]); + edit_logline[0]->refreshPointers(); + edit_wave_origin[0]=edit_logline[0]->segueStartPoint()-track_preroll; + } + + // + // Track 1 Parameters + // + edit_logline[1]=track_log_event->logLine(edit_track_line[1]); + if(!edit_wave_name[1].isEmpty()) { + edit_logline[1]->refreshPointers(); + } + if((track_log_event->logLine(edit_track_line[1])!=NULL)&& + (!edit_wave_name[1].isEmpty())) { + edit_wave_origin[1]=edit_logline[1]->startPoint()-track_preroll; + edit_length_label-> + setText(RDGetTimeLength(edit_logline[1]->forcedLength(),true)); + if(((edit_logline[1]->transType()!=RDLogLine::Segue))&& + (!edit_wave_name[0].isEmpty())) { + edit_wave_origin[0]=edit_logline[0]->endPoint()-track_preroll; + } + } + else { + edit_wave_origin[1]=0; + edit_length_label->setText("0:00:00.0"); + } + + // + // Track 2 Parameters + // + if(edit_wave_name[2].isEmpty()) { + edit_logline[2]=track_dummy2_logline; // No final track, so fake it + edit_logline[2]->clear(); + edit_logline[2]->setStartPoint(0,RDLogLine::CartPointer); + edit_logline[2]->setStartPoint(-1,RDLogLine::LogPointer); + edit_logline[2]->setEndPoint(0,RDLogLine::CartPointer); + edit_logline[2]->setEndPoint(-1,RDLogLine::LogPointer); + edit_wave_origin[2]=0; + } + else { + edit_logline[2]=track_log_event->logLine(edit_track_line[2]); + edit_logline[2]->refreshPointers(); + if(edit_logline[2]->transType()!=RDLogLine::Segue) { + if(!edit_wave_name[1].isEmpty()) { + edit_wave_origin[2]=edit_logline[2]->startPoint()- + (edit_logline[1]->endPoint()-edit_logline[1]->startPoint()+ + track_preroll); + } + else + { + edit_wave_origin[2]=edit_logline[2]->startPoint()-track_preroll; + edit_wave_origin[0]=edit_logline[0]->endPoint()-track_preroll; + } + } + else { + if(edit_wave_name[1].isEmpty()) { + edit_wave_origin[2]=edit_logline[2]->startPoint()-track_preroll; + } + else { + edit_wave_origin[2]=edit_logline[2]->startPoint()- + (edit_logline[1]->segueStartPoint()-edit_logline[1]->startPoint()+ + track_preroll); + } + } + } + edit_wave_width=TRACKER_START_WIDTH; + } + track_start_time=track_log_event->blockStartTime(line); + DrawTrackMap(0); + DrawTrackMap(1); + DrawTrackMap(2); + UpdateControls(); +} + + +void VoiceTracker::SaveTrack(int line) +{ + if((line<0)||(line==TRACKER_MAX_LINENO)) { + return; + } + if((line>0)&&(track_log_event->logLine(line-1)->type()==RDLogLine::Track)) { + line--; + } + track_log_event->save(); + track_log-> + setModifiedDatetime(QDateTime(QDate::currentDate(),QTime::currentTime())); + track_changed=false; + track_size_altered=false; +} + + +bool VoiceTracker::ImportTrack(RDListViewItem *item) +{ + bool metadata=false; + + if(!InitTrack()) { + return false; + } + RDWaveData *wdata=new RDWaveData(); + RDImportAudio *import= + new RDImportAudio(edit_track_cuts[1]->cutName(),edit_import_path, + edit_settings,&metadata,wdata,NULL,rdstation_conf,rduser, + &import_running,log_config,this); + if(import->exec(true,false)<0) { + delete import; + delete wdata; + resetData(); + return true; + } + delete import; + delete wdata; + + if(!edit_wave_name[0].isEmpty()) { + edit_logline[0]-> + setSegueStartPoint(edit_logline[0]-> + segueStartPoint(RDLogLine::CartPointer), + RDLogLine::LogPointer); + edit_logline[0]->setSegueGain(0); + edit_logline[0]->setSegueEndPoint(edit_logline[0]->endPoint(),RDLogLine::LogPointer); + edit_logline[1]->setTransType(RDLogLine::Segue); + edit_logline[0]-> + setAverageSegueLength(edit_logline[0]-> + segueStartPoint()- + edit_logline[0]-> + startPoint()); + } + + edit_track_cart->updateLength(); + edit_track_cart->resetRotation(); + edit_logline[1]-> + loadCart(edit_track_cart->number(),RDLogLine::Segue,0,false); + edit_logline[1]->setEvent(0,RDLogLine::Segue,false); + edit_logline[1]->setType(RDLogLine::Cart); + edit_logline[1]->setSource(RDLogLine::Tracker); + edit_logline[1]->setOriginUser(rduser->name()); + edit_logline[1]->setOriginDateTime(QDateTime(QDate::currentDate(), + QTime::currentTime())); + edit_logline[1]->setFadeupPoint(edit_track_cuts[1]->startPoint(), + RDLogLine::LogPointer); + edit_logline[1]->setFadeupGain(RD_FADE_DEPTH); + edit_logline[1]->setFadedownPoint(edit_track_cuts[1]->endPoint(), + RDLogLine::LogPointer); + edit_logline[1]->setFadedownGain(RD_FADE_DEPTH); + edit_logline[1]->setEndPoint(-1,RDLogLine::LogPointer); + edit_logline[1]->setSegueEndPoint(edit_track_cuts[1]->endPoint(), + RDLogLine::LogPointer); + edit_logline[1]->setHasCustomTransition(true); + if(!edit_wave_name[2].isEmpty()) { + edit_logline[2]->setHasCustomTransition(true); + edit_logline[1]-> + setAverageSegueLength(edit_logline[1]-> + segueStartPoint()- + edit_logline[1]-> + startPoint()); + } + item->setPixmap(0,*edit_track_cart_map); + item->setText(3,QString().sprintf("%06u",edit_track_cart->number())); + item->setText(4,track_group->name()); + item->setText(5,RDGetTimeLength(edit_track_cart->forcedLength())); + postData(); + SaveTrack(track_line); + LoadTrack(track_line); + WriteTrackMap(0); + WriteTrackMap(1); + WriteTrackMap(2); + RefreshLine(item); + if(!edit_wave_name[2].isEmpty()) { + RefreshLine((RDListViewItem *)item->nextSibling()); + } + + return true; +} + + +void VoiceTracker::RenderTransition(int line) +{ + if(line==TRACKER_MAX_LINENO) { + track_loaded=false; + segue_loaded=false; + edit_length_label->setText("-:--:--.-"); + } + else { + if(IsTrack(line,&track_offset)) { + track_loaded=true; + } + else { + track_loaded=false; + edit_length_label->setText("-:--:--.-"); + } + segue_loaded=true; + } + track_line=line; + LoadTrack(track_line); + LoadBlockLength(line); + UpdateRemaining(); + update(); + UpdateControls(); +} + + +void VoiceTracker::LoadBlockLength(int line) +{ + int nominal_length=0; + int actual_length=0; + + track_block_valid=track_log_event-> + blockLength(&nominal_length,&actual_length,line); + track_time_remaining=nominal_length-actual_length; +} + + +void VoiceTracker::RefreshList() +{ + RDListViewItem *item=NULL; + track_log_list->clear(); + item=new RDListViewItem(track_log_list); + item->setLine(TRACKER_MAX_LINENO); + item->setText(6,tr("[end of log]")); + for(int i=track_log_event->size()-1;i>=0;i--) { + item=new RDListViewItem(track_log_list); + item->setId(track_log_event->logLine(i)->id()); + item->setLine(i); + RefreshLine(item); + if(track_line==i) { + track_log_list->setSelected(item,true); + track_log_list->ensureVisible(0,track_log_list->itemPos(item),0,track_log_list->size().height()/2); + } + } +} + + +void VoiceTracker::RefreshLine(RDListViewItem *item) +{ + RDLogLine *logline=track_log_event->logLine(item->line()); + if(logline==NULL) { + return; + } + switch(logline->type()) { + case RDLogLine::Cart: + switch(logline->source()) { + case RDLogLine::Tracker: + item->setPixmap(0,*edit_track_cart_map); + break; + + default: + item->setPixmap(0,*edit_playout_map); + break; + } + item->setText(3,QString().sprintf("%06u",logline->cartNumber())); + item->setText(5,RDGetTimeLength(logline->forcedLength())); + if(logline->title().isEmpty()) { + item->setText(4,""); + item->setText(6,tr("[cart not found]")); + } + else { + item->setText(4,logline->groupName()); + if(logline->originUser().isEmpty()|| + (!logline->originDateTime().isValid())) { + item->setText(6,logline->title()); + } + else { + item->setText(6,QString(). + sprintf("%s -- %s %s", + (const char *)logline->title(), + (const char *)logline->originUser(), + (const char *)logline->originDateTime(). + toString("M/d hh:mm"))); + } + } + item->setText(7,logline->artist()); + item->setText(8,logline->album()); + item->setText(9,logline->label()); + break; + + case RDLogLine::Macro: + item->setPixmap(0,*edit_macro_map); + item->setText(3,QString().sprintf("%06u",logline->cartNumber())); + item->setText(5,RDGetTimeLength(logline->forcedLength())); + if(logline->title().isEmpty()) { + item->setText(4,""); + item->setText(6,tr("[cart not found]")); + } + else { + item->setText(4,logline->groupName()); + item->setText(6,logline->title()); + } + item->setText(7,logline->artist()); + item->setText(8,logline->album()); + item->setText(9,logline->label()); + break; + + case RDLogLine::Marker: + item->setPixmap(0,*edit_notemarker_map); + item->setText(3,tr("MARKER")); + item->setText(6,RDTruncateAfterWord(logline->markerComment(),5,true)); + break; + + case RDLogLine::Chain: + item->setPixmap(0,*edit_chain_map); + item->setText(3,tr("LOG CHAIN")); + item->setText(6,logline->markerLabel()); + item->setText(7,RDTruncateAfterWord(logline->markerComment(),5,true)); + break; + + case RDLogLine::Track: + item->setPixmap(0,*edit_mic16_map); + item->setText(3,tr("TRACK")); + item->setText(6,RDTruncateAfterWord(logline->markerComment(),5,true)); + break; + + case RDLogLine::MusicLink: + item->setPixmap(0,*edit_music_map); + item->setText(3,tr("LINK")); + item->setText(6,tr("[music import]")); + break; + + case RDLogLine::TrafficLink: + item->setPixmap(0,*edit_traffic_map); + item->setText(3,tr("LINK")); + item->setText(6,tr("[traffic import]")); + break; + + default: + break; + } + if(!logline->startTime(RDLogLine::Logged).isNull()) { + if(logline->timeType()==RDLogLine::Hard) { + item->setText(1,logline->startTime(RDLogLine::Imported). + toString("Hhh:mm:ss.zzz").left(11)); + } + else { + item->setText(1,logline->startTime(RDLogLine::Imported). + toString("hh:mm:ss.zzz").left(10)); + } + } + switch(logline->transType()) { + case RDLogLine::Play: + item->setText(2,tr("PLAY")); + item->setTextColor(2,item->textColor(1),QFont::Normal); + break; + + case RDLogLine::Segue: + item->setText(2,tr("SEGUE")); + if(logline->hasCustomTransition()) { + item->setTextColor(2,RD_CUSTOM_TRANSITION_COLOR,QFont::Bold); + } + else { + item->setTextColor(2,item->textColor(1),QFont::Normal); + } + break; + + case RDLogLine::Stop: + item->setText(2,tr("STOP")); + item->setTextColor(2,item->textColor(1),QFont::Normal); + break; + + default: + break; + } +} + + +void VoiceTracker::StartNext(int finishing_id,int next_id) +{ + int duckin; + if(next_id==-1) { + next_id=finishing_id+1; + } + for(int i=next_id;i<3;i++) { + if(!edit_wave_name[i].isEmpty()) { + edit_deck[i]->setCart(edit_logline[i],true); + if(edit_wave_name[i-1].isEmpty()) { + duckin=edit_logline[i-2]->segueEndPoint()- + edit_logline[i-2]->segueStartPoint(); + edit_deck[i-2]->stop(duckin); + } + else { + duckin=edit_logline[i-1]->segueEndPoint()- + edit_logline[i-1]->segueStartPoint(); + edit_deck[i-1]->stop(duckin); + } + if(track_recording) + duckin=-1; + edit_deck[i]-> + play(edit_segue_start_offset[i], + edit_logline[i]->segueStartPoint(), + edit_logline[i]->segueEndPoint(),duckin); + return; + } + } +} + + +QString VoiceTracker::GetCutName(int line,RDCut **cut) +{ + if((line<0)||(line>=track_log_event->size())) { + return QString(); + } + QString wavname; + QString pathname; + RDLogLine *logline=track_log_event->logLine(line); + if(*cut!=NULL) { + delete *cut; + *cut=NULL; + } + if(line==(track_log_event->size()-1)) { + logline->setEvent(0,RDLogLine::Stop,false); + } + else { + logline->setEvent(0,track_log_event->logLine(line+1)->transType(),false); + } + if(!logline->cutName().isEmpty()) { + *cut=new RDCut(logline->cutName()); + pathname=RDCut::pathName(logline->cutName()); + /* + if(!QFile::exists(pathname)) { + return QString(); + } + */ + } + return pathname; +} + + +int VoiceTracker::GetClick(QMouseEvent *e,QPoint *p) +{ + p->setX(e->x()-TRACKER_X_ORIGIN); + if((e->x()<=TRACKER_X_ORIGIN)|| + (e->x()>=(TRACKER_X_ORIGIN+TRACKER_X_WIDTH))|| + (e->y()<=TRACKER_Y_ORIGIN)|| + (e->y()>=(TRACKER_Y_ORIGIN+3*TRACKER_Y_HEIGHT))) { + return -1; + } + if(e->y()setY(e->y()-TRACKER_Y_ORIGIN); + return 0; + } + if(e->y()<(TRACKER_Y_ORIGIN+2*TRACKER_Y_HEIGHT)) { + p->setY(e->y()-(TRACKER_Y_ORIGIN+TRACKER_Y_HEIGHT)); + return 1; + } + p->setY(e->y()-(TRACKER_Y_ORIGIN+2*TRACKER_Y_HEIGHT)); + return 2; +} + + +void VoiceTracker::DragTrack(int trackno,int xdiff) +{ + if(edit_wave_name[trackno].isEmpty()) { + return; + } +// if((!track_changed)&&(trackno>0)&&(track_line!=0)) { + if((!track_changed)&&(trackno>0)) { + PushSegues(); + } + + // + // Calculate the Offset + // + int tdiff=xdiff*TRACKER_MSECS_PER_PIXEL; + int tend=0; + switch(trackno) { + case 1: + if(!edit_wave_name[0].isEmpty()) { + if((edit_wave_origin[1]-edit_logline[1]->startPoint()-tdiff)> + (edit_wave_origin[0]-edit_logline[0]->startPoint())) { + tdiff=(edit_wave_origin[1]-edit_logline[1]->startPoint())- + (edit_wave_origin[0]-edit_logline[0]->startPoint()); + } + tend=edit_wave_origin[0]- + edit_logline[0]->segueEndPoint()+ + edit_logline[1]->startPoint()+100; + if((edit_wave_origin[1]-tdiff) + setSegueStartPoint(edit_logline[0]->segueStartPoint()+tdiff, + RDLogLine::LogPointer); +// edit_logline[0]->setSegueGain(0); + edit_logline[0]-> + setAverageSegueLength(edit_logline[0]-> + segueStartPoint()- + edit_logline[0]-> + startPoint()); + } + break; + + case 2: + if(edit_wave_name[1].isEmpty()) { + if(!edit_wave_name[0].isEmpty()) { + if((edit_wave_origin[2]-edit_logline[2]->startPoint()-tdiff)> + (edit_wave_origin[0]-edit_logline[0]->startPoint())) { + tdiff=(edit_wave_origin[2]-edit_logline[2]->startPoint())- + (edit_wave_origin[0]-edit_logline[0]->startPoint()); + } + tend=edit_wave_origin[0]- + edit_logline[0]->segueEndPoint()+ + edit_logline[2]->startPoint()+100; + if((edit_wave_origin[2]-tdiff) + setSegueStartPoint(edit_logline[0]->segueStartPoint()+tdiff, + RDLogLine::LogPointer); +// edit_logline[0]->setSegueGain(0); + edit_logline[0]-> + setAverageSegueLength(edit_logline[0]-> + segueStartPoint()- + edit_logline[0]-> + startPoint()); + } + } + else { + if((edit_wave_origin[2]-edit_logline[2]->startPoint()-tdiff)> + (edit_wave_origin[1]-edit_logline[1]->startPoint())) { + tdiff=(edit_wave_origin[2]-edit_logline[2]->startPoint())- + (edit_wave_origin[1]-edit_logline[1]->startPoint()); + } + tend=edit_wave_origin[1]- + edit_logline[1]->segueEndPoint()+ + edit_logline[2]->startPoint()+100; + if((edit_wave_origin[2]-tdiff) + setSegueStartPoint(edit_logline[1]->segueStartPoint()+tdiff, + RDLogLine::LogPointer); + // edit_logline[1]->setSegueGain(0); + edit_logline[1]-> + setAverageSegueLength(edit_logline[1]-> + segueStartPoint()- + edit_logline[1]-> + startPoint()); + } + break; + } + + // + // Ignore Meaningless Edits + // + bool state=false; + for(int i=0;iblockStartTime(track_line); + for(int i=0;i<3;i++) { + DrawTrackMap(i); + WriteTrackMap(i); + } + if((!state)||(tdiff==0)) { + return; + } + + // + // Apply the Offset + // + track_changed=true; + edit_logline[trackno]->setHasCustomTransition(true); + + if(edit_wave_name[2].isEmpty()) { + if((edit_wave_origin[0]- + edit_logline[0]->endPoint())>0) { + track_track1_button->setDisabled(true); + track_record_button->setDisabled(true); + } + } + else { + if(edit_wave_origin[2]>0) { + track_track1_button->setDisabled(true); + track_record_button->setDisabled(true); + } + } + LoadBlockLength(track_line); + RDListViewItem *item=NULL; + if(track_log_event->logLine(track_line)->type()==RDLogLine::Track) { + item=GetItemByLine(track_line+1); + } + else { + item=GetItemByLine(track_line); + } + if(item!=NULL) { + RefreshLine(item); + if(GetItemByLine(item->line()+1)!=NULL) { + RefreshLine(GetItemByLine(item->line()+1)); + } + } + UpdateRemaining(); + UpdateControls(); +} + + +void VoiceTracker::DragTarget(int trackno,const QPoint &pt) +{ + // printf("DragTarget(%d,(%d,%d)) TARGET: %d\n",trackno,pt.x(),pt.y(),track_current_target); + + if(!track_changed) { + PushSegues(); + track_changed=true; + UpdateControls(); + } + switch(track_current_target) { + case VoiceTracker::FadedownPoint: + edit_logline[trackno]-> + setDuckDownGain((TRACKER_GAIN_MARGIN-pt.y())*TRACKER_MB_PER_PIXEL); + if(edit_logline[trackno]->duckDownGain()>TRACKER_MAX_GAIN) { + edit_logline[trackno]->setDuckDownGain(TRACKER_MAX_GAIN); + } + if(edit_logline[trackno]->duckDownGain()setDuckDownGain(TRACKER_MIN_GAIN); + } + case VoiceTracker::TrackFadedownPoint: + if((edit_logline[trackno]->fadedownPoint()<=0 || + edit_logline[trackno]->fadedownPoint()>=edit_logline[trackno]->endPoint()) + && edit_logline[trackno]->fadedownGain()==0) { + edit_logline[trackno]->setFadedownGain(RD_FADE_DEPTH); + } + edit_logline[trackno]->setSegueGain(0); + if(edit_logline[trackno]->fadedownPoint(RDLogLine::LogPointer)<0) { + edit_logline[trackno]->setFadedownGain(RD_FADE_DEPTH); + } + if(trackno<2) { + if((edit_logline[trackno+1]->transType()==RDLogLine::Segue) + && (!track_loaded)) { + edit_logline[trackno]->setEndPoint( + edit_logline[trackno]->segueEndPoint(),RDLogLine::LogPointer); + } + } + edit_logline[trackno]-> + setFadedownPoint(pt.x()*TRACKER_MSECS_PER_PIXEL+ + edit_wave_origin[trackno],RDLogLine::LogPointer); + if(edit_logline[trackno]->fadedownPoint()>edit_logline[trackno]-> + endPoint()) { + edit_logline[trackno]->setFadedownPoint(edit_logline[trackno]-> + endPoint(),RDLogLine::LogPointer); + } + if(edit_logline[trackno]->fadedownPoint()< + edit_logline[trackno]->fadeupPoint()) { + edit_logline[trackno]-> + setFadedownPoint(edit_logline[trackno]->fadeupPoint(), + RDLogLine::LogPointer);; + } + if(edit_logline[trackno]->fadedownPoint(RDLogLine::CartPointer)>=0 + && edit_logline[trackno]->fadedownPoint()> + edit_logline[trackno]->fadedownPoint(RDLogLine::CartPointer)) { + edit_logline[trackno]-> + setFadedownPoint(edit_logline[trackno]->fadedownPoint(RDLogLine::CartPointer), + RDLogLine::LogPointer); + } + DrawTrackMap(trackno); + WriteTrackMap(trackno); + track_meter->setLeftPeakBar(edit_logline[trackno]->duckDownGain()-1600); + track_meter->setRightPeakBar(edit_logline[trackno]->duckDownGain()-1600); + if(edit_logline[trackno+1]!=NULL) { + edit_logline[trackno+1]->setHasCustomTransition(true); + } + break; + + case VoiceTracker::FadedownGain: + case VoiceTracker::TrackFadedownGain: + if(edit_logline[trackno]->fadedownPoint()>edit_logline[trackno]->endPoint() + || edit_logline[trackno]->fadedownPoint()<0) { + edit_logline[trackno]->setFadedownPoint(edit_logline[trackno]->endPoint(),RDLogLine::LogPointer); + } + edit_logline[trackno]-> + setFadedownGain((TRACKER_GAIN_MARGIN-pt.y())*TRACKER_MB_PER_PIXEL); + if(edit_logline[trackno]->fadedownGain()>TRACKER_MAX_GAIN) { + edit_logline[trackno]->setFadedownGain(TRACKER_MAX_GAIN); + } + if(edit_logline[trackno]->fadedownGain()setFadedownGain(TRACKER_MIN_GAIN); + } + if(edit_logline[trackno]->fadedownPoint(RDLogLine::CartPointer)>=0 + && edit_logline[trackno]->fadedownPoint(RDLogLine::CartPointer)< + edit_logline[trackno]->endPoint() + ) { + edit_logline[trackno]->setFadedownGain(RD_FADE_DEPTH); + } + DrawTrackMap(trackno); + WriteTrackMap(trackno); + track_meter->setLeftPeakBar(edit_logline[trackno]->fadedownGain()-1600); + track_meter->setRightPeakBar(edit_logline[trackno]->fadedownGain()-1600); + if(edit_logline[trackno+1]!=NULL) { + edit_logline[trackno+1]->setHasCustomTransition(true); + } + break; + + case VoiceTracker::FadeupPoint: + edit_logline[trackno]-> + setDuckUpGain((TRACKER_GAIN_MARGIN-pt.y())*TRACKER_MB_PER_PIXEL); + if(edit_logline[trackno]->duckUpGain()>TRACKER_MAX_GAIN) { + edit_logline[trackno]->setDuckUpGain(TRACKER_MAX_GAIN); + } + if(edit_logline[trackno]->duckUpGain()setDuckUpGain(TRACKER_MIN_GAIN); + } + case VoiceTracker::TrackFadeupPoint: + if(edit_logline[trackno]->fadeupPoint()<=edit_logline[trackno]->startPoint() + && edit_logline[trackno]->fadeupGain()==0) { + edit_logline[trackno]->setFadeupGain(RD_FADE_DEPTH); + } + if(edit_logline[trackno]->fadeupPoint(RDLogLine::LogPointer)<0) { + edit_logline[trackno]->setFadeupGain(RD_FADE_DEPTH); + } + edit_logline[trackno]-> + setFadeupPoint(pt.x()*TRACKER_MSECS_PER_PIXEL+ + edit_wave_origin[trackno],RDLogLine::LogPointer); + if(edit_logline[trackno]->fadeupPoint()> + edit_logline[trackno]->fadedownPoint() + && edit_logline[trackno]->fadedownPoint()>=0) { + edit_logline[trackno]->setFadeupPoint(edit_logline[trackno]-> + fadedownPoint(),RDLogLine::LogPointer); + } + if(edit_logline[trackno]->fadeupPoint() + startPoint()) { + edit_logline[trackno]->setFadeupPoint(edit_logline[trackno]-> + startPoint(),RDLogLine::LogPointer); + } + if(edit_logline[trackno]->fadeupPoint()< + edit_logline[trackno]->fadeupPoint(RDLogLine::CartPointer)) { + edit_logline[trackno]-> + setFadeupPoint(edit_logline[trackno]->fadeupPoint(RDLogLine::CartPointer), + RDLogLine::LogPointer); + } + DrawTrackMap(trackno); + WriteTrackMap(trackno); + track_meter->setLeftPeakBar(edit_logline[trackno]->duckUpGain()-1600); + track_meter->setRightPeakBar(edit_logline[trackno]->duckUpGain()-1600); + edit_logline[trackno]->setHasCustomTransition(true); + break; + + case VoiceTracker::FadeupGain: + case VoiceTracker::TrackFadeupGain: + if(edit_logline[trackno]->fadeupPoint()startPoint()) { + edit_logline[trackno]->setFadeupPoint(edit_logline[trackno]->startPoint(),RDLogLine::LogPointer); + } + edit_logline[trackno]-> + setFadeupGain((TRACKER_GAIN_MARGIN-pt.y())*TRACKER_MB_PER_PIXEL); + if(edit_logline[trackno]->fadeupGain()>TRACKER_MAX_GAIN) { + edit_logline[trackno]->setFadeupGain(TRACKER_MAX_GAIN); + } + if(edit_logline[trackno]->fadeupGain()setFadeupGain(TRACKER_MIN_GAIN); + } + if(edit_logline[trackno]->fadeupPoint(RDLogLine::CartPointer)> + edit_logline[trackno]->startPoint()) { + edit_logline[trackno]->setFadeupGain(RD_FADE_DEPTH); + } + DrawTrackMap(trackno); + WriteTrackMap(trackno); + track_meter->setLeftPeakBar(edit_logline[trackno]->fadeupGain()-1600); + track_meter->setRightPeakBar(edit_logline[trackno]->fadeupGain()-1600); + edit_logline[trackno]->setHasCustomTransition(true); + break; + + case VoiceTracker::TargetSize: + break; + } + track_changed=true; + RDListViewItem *item=NULL; + if(track_log_event->logLine(track_line)->type()==RDLogLine::Track) { + item=GetItemByLine(track_line+1); + } + else { + item=GetItemByLine(track_line); + } + if(item!=NULL) { + RefreshLine(item); + if(GetItemByLine(item->line()+1)!=NULL) { + RefreshLine(GetItemByLine(item->line()+1)); + } + } + UpdateControls(); +} + + +void VoiceTracker::DrawTrackMap(int trackno) +{ + QTime track_time; + QPainter *p=NULL; + int xpos=0; + QColor back_color; + switch(trackno) { + case 0: + if(edit_wave_name[0].isEmpty()) { + p=new QPainter(edit_wave_map[0]); + p->setBackgroundColor(gray); + p->eraseRect(0,0,edit_wave_map[0]->size().width(), + edit_wave_map[0]->size().height()); + p->end(); + delete p; + } + else { + wpg[0]->begin(edit_wave_map[0]); + wpg[0]->setFont(QFont("Helvetica",12,QFont::Bold)); + wpg[0]->setPen(TRACKER_TEXT_COLOR); + wpg[0]->setBackgroundColor(backgroundColor()); + wpg[0]->eraseRect(0,0,edit_wave_map[0]->size().width(), + edit_wave_map[0]->size().height()); + if(!edit_wave_name[0].isEmpty()) { + wpg[0]->drawWaveByMsecs(0,edit_wave_map[0]->width(), + edit_wave_origin[0], + edit_wave_origin[0]+edit_wave_width,800, + RDWavePainter::Mono,black, + edit_logline[0]-> + startPoint(RDLogLine::CartPointer), + edit_logline[0]-> + endPoint(RDLogLine::CartPointer)); + + // + // Draw Segue Markers + // + if(edit_logline[0]->segueStartPoint(RDLogLine::CartPointer)>=0) { + xpos=(edit_logline[0]->segueStartPoint(RDLogLine::CartPointer)- + edit_wave_origin[0])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[0],edit_wave_map[0]->height(),xpos, + RD_SEGUE_MARKER_COLOR,20,true); + xpos=(edit_logline[0]->segueEndPoint(RDLogLine::CartPointer)- + edit_wave_origin[0])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[0],edit_wave_map[0]->height(),xpos, + RD_SEGUE_MARKER_COLOR,20,false); + } + + // + // Draw Start Marker + // + xpos=(edit_logline[0]->startPoint(RDLogLine::CartPointer)- + edit_wave_origin[0])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[0],edit_wave_map[0]->height(),xpos, + RD_START_END_MARKER_COLOR,10,true); + + // + // Draw End Marker + // + xpos=(edit_logline[0]->endPoint(RDLogLine::CartPointer)- + edit_wave_origin[0])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[0],edit_wave_map[0]->height(),xpos, + RD_START_END_MARKER_COLOR,10,false); + + // + // Draw Fadedown Marker + // + if(edit_logline[0]->fadedownPoint(RDLogLine::CartPointer)>=0) { + xpos=(edit_logline[0]->fadedownPoint(RDLogLine::CartPointer)- + edit_wave_origin[0])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[0],edit_wave_map[0]->height(),xpos, + RD_FADE_MARKER_COLOR,30,true); + } + + // + // Draw Rubber Bands + // + DrawRubberBand(wpg[0],0); + + // + // Draw Menu Marker + // + if(menu_clicked_point>=0 && edit_rightclick_track==0) { + DrawCursor(wpg[0],edit_wave_map[0]->height(),menu_clicked_point, + RD_START_END_MARKER_COLOR,10,true); + DrawCursor(wpg[0],edit_wave_map[0]->height(),menu_clicked_point, + RD_START_END_MARKER_COLOR,10,false); + } + } + wpg[0]->setPen(TRACKER_TEXT_COLOR); + wpg[0]->drawText(5,14,QString().sprintf("%s - %s", + (const char *)edit_logline[0]->title(), + (const char *)edit_logline[0]->artist())); + wpg[0]->end(); + } + break; + + case 1: + if(edit_wave_name[1].isEmpty()) { + p=new QPainter(edit_wave_map[1]); + if(track_loaded) { + p->setBackgroundColor(backgroundColor()); + p->setFont(QFont("Helvetica",12,QFont::Bold)); + p->setPen(TRACKER_TEXT_COLOR); + p->eraseRect(0,0,edit_wave_map[1]->size().width(), + edit_wave_map[1]->size().height()); + p->drawText(5,14,edit_logline[1]->markerComment()); + } + else { + p->setBackgroundColor(gray); + p->eraseRect(0,0,edit_wave_map[1]->size().width(), + edit_wave_map[1]->size().height()); + } + if(track_start_time>QTime(0,0,0)) { + p->setFont(QFont("Helvetica",12,QFont::Bold)); + p->setPen(TRACKER_TEXT_COLOR); + p->drawText(550,75,QString().sprintf("Start %s", + (const char*)track_start_time.toString("h:mm:ss"))); + } + p->end(); + delete p; + } + else { + if((edit_logline[1]->transType()==RDLogLine::Segue)) { + back_color=backgroundColor(); + } + else { + back_color=lightGray; + } + switch(edit_deck_state) { + case VoiceTracker::DeckTrack2: + case VoiceTracker::DeckTrack3: + p=new QPainter(edit_wave_map[1]); + p->setPen(TRACKER_RECORD_COLOR); + p->setBrush(TRACKER_RECORD_COLOR); + p->setBackgroundColor(back_color); + p->eraseRect(0,0,edit_wave_map[1]->size().width(), + edit_wave_map[1]->size().height()); + p->fillRect(-edit_wave_origin[1]/ + TRACKER_MSECS_PER_PIXEL, + TRACKER_Y_HEIGHT/4, + track_recording_pos/TRACKER_MSECS_PER_PIXEL, + TRACKER_Y_HEIGHT/2,TRACKER_RECORD_COLOR); + p->setFont(QFont("Helvetica",12,QFont::Bold)); + if(track_start_time>QTime(0,0,0)) { + p->setPen(TRACKER_TEXT_COLOR); + track_time=track_start_time; + track_time=track_time.addMSecs( + track_time_remaining_start-track_time_counter); + p->drawText(550,75,QString().sprintf("Time %s", + (const char*)track_time.toString("h:mm:ss"))); + } + p->end(); + delete p; + break; + + default: + wpg[1]->begin(edit_wave_map[1]); + wpg[1]->setFont(QFont("Helvetica",12,QFont::Bold)); + wpg[1]->setPen(TRACKER_TEXT_COLOR); + wpg[1]->setBackgroundColor(back_color); + wpg[1]->eraseRect(0,0,edit_wave_map[1]->size().width(), + edit_wave_map[1]->size().height()); + if(!edit_wave_name[1].isEmpty()) { + wpg[1]->drawWaveByMsecs(0,edit_wave_map[1]->width(), + edit_wave_origin[1], + edit_wave_origin[1]+edit_wave_width,800, + RDWavePainter::Mono,black, + edit_logline[1]-> + startPoint(RDLogLine::CartPointer), + edit_logline[1]-> + endPoint(RDLogLine::CartPointer)); + } + if(track_line>=0) { + + // + // Draw Segue Markers + // + if(edit_logline[1]->segueStartPoint(RDLogLine::CartPointer)>=0) { + xpos=(edit_logline[1]->segueStartPoint(RDLogLine::CartPointer)- + edit_wave_origin[1])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[1],edit_wave_map[1]->height(),xpos, + RD_SEGUE_MARKER_COLOR,20,true); + xpos=(edit_logline[1]->segueEndPoint(RDLogLine::CartPointer)- + edit_wave_origin[1])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[1],edit_wave_map[1]->height(),xpos, + RD_SEGUE_MARKER_COLOR,20,false); + } + + // + // Draw Fadeup Marker + // + if(edit_logline[1]->fadeupPoint(RDLogLine::CartPointer)>=0) { + xpos=(edit_logline[1]->fadeupPoint(RDLogLine::CartPointer)- + edit_wave_origin[1])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[1],edit_wave_map[1]->height(),xpos, + RD_FADE_MARKER_COLOR,30,false); + } + + // + // Draw Start Marker + // + xpos=(edit_logline[1]->startPoint(RDLogLine::CartPointer)- + edit_wave_origin[1])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[1],edit_wave_map[1]->height(),xpos, + RD_START_END_MARKER_COLOR,10,true); + + // + // Draw Fadedown Marker + // + if(edit_logline[1]->fadedownPoint(RDLogLine::CartPointer)>=0) { + xpos=(edit_logline[1]->fadedownPoint(RDLogLine::CartPointer)- + edit_wave_origin[1])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[1],edit_wave_map[1]->height(),xpos, + RD_FADE_MARKER_COLOR,30,true); + } + + // + // Draw End Marker + // + xpos=(edit_logline[1]->endPoint(RDLogLine::CartPointer)- + edit_wave_origin[1])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[1],edit_wave_map[1]->height(),xpos, + RD_START_END_MARKER_COLOR,10,false); + + // + // Draw Rubber Bands + // + DrawRubberBand(wpg[1],1); + + // + // Draw Menu Marker + // + if(menu_clicked_point>=0 && edit_rightclick_track==1) { + DrawCursor(wpg[1],edit_wave_map[1]->height(),menu_clicked_point, + RD_START_END_MARKER_COLOR,10,true); + DrawCursor(wpg[1],edit_wave_map[1]->height(),menu_clicked_point, + RD_START_END_MARKER_COLOR,10,false); + } + wpg[1]->setPen(TRACKER_TEXT_COLOR); + wpg[1]->drawText(5,14,edit_logline[1]->title()); + } + if(track_start_time>QTime(0,0,0)) { + wpg[1]->drawText(550,75,QString().sprintf("Start %s", + (const char*)track_start_time.toString("h:mm:ss"))); + } + wpg[1]->end(); + break; + } + } + break; + + case 2: + if(edit_wave_name[2].isEmpty()) { + p=new QPainter(edit_wave_map[2]); + p->setBackgroundColor(gray); + p->eraseRect(0,0,edit_wave_map[2]->size().width(), + edit_wave_map[2]->size().height()); + p->end(); + delete p; + } + else { + if((edit_logline[2]->transType()==RDLogLine::Segue)) { + back_color=backgroundColor(); + } + else { + back_color=lightGray; + } + wpg[2]->begin(edit_wave_map[2]); + wpg[2]->setFont(QFont("Helvetica",12,QFont::Bold)); + wpg[2]->setBackgroundColor(back_color); + wpg[2]->eraseRect(0,0,edit_wave_map[2]->size().width(), + edit_wave_map[2]->size().height()); + if(!edit_wave_name[2].isEmpty()) { + wpg[2]->drawWaveByMsecs(0,edit_wave_map[2]->width(), + edit_wave_origin[2], + edit_wave_origin[2]+edit_wave_width,800, + RDWavePainter::Mono,black, + edit_logline[2]->startPoint(RDLogLine::CartPointer), + edit_logline[2]->endPoint(RDLogLine::CartPointer)); + + // + // Draw Talk Markers + // + if(edit_logline[2]->talkEndPoint()>0) { + int tsxpos; + int texpos; + if(edit_logline[2]->talkStartPoint()==0){ + tsxpos=(edit_logline[2]->startPoint()- + edit_wave_origin[2])/TRACKER_MSECS_PER_PIXEL; + } + else { + tsxpos=(edit_logline[2]->talkStartPoint()- + edit_wave_origin[2])/TRACKER_MSECS_PER_PIXEL; + } + if(edit_logline[2]->talkEndPoint()==0) { + texpos=(edit_logline[2]->startPoint()- + edit_wave_origin[2])/TRACKER_MSECS_PER_PIXEL; + } + else { + if(edit_logline[2]->talkStartPoint()==0) { + texpos=(edit_logline[2]->startPoint()+ + edit_logline[2]->talkEndPoint()- + edit_wave_origin[2])/TRACKER_MSECS_PER_PIXEL; + } + else { + texpos=(edit_logline[2]->talkEndPoint()- + edit_wave_origin[2])/TRACKER_MSECS_PER_PIXEL; + } + } + if(tsxpos!=texpos){ + DrawCursor(wpg[2],edit_wave_map[2]->height(),tsxpos, + RD_TALK_MARKER_COLOR,20,true); + DrawCursor(wpg[2],edit_wave_map[2]->height(),texpos, + RD_TALK_MARKER_COLOR,20,false); + } + } + + // + // Draw Fadeup Marker + // + if(edit_logline[2]->fadeupPoint(RDLogLine::CartPointer)>=0) { + xpos=(edit_logline[2]->fadeupPoint(RDLogLine::CartPointer)- + edit_wave_origin[2])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[2],edit_wave_map[2]->height(),xpos, + RD_FADE_MARKER_COLOR,30,false); + } + + // + // Draw Start Marker + // + xpos=(edit_logline[2]->startPoint(RDLogLine::CartPointer)- + edit_wave_origin[2])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[2],edit_wave_map[2]->height(),xpos, + RD_START_END_MARKER_COLOR,10,true); + + // + // Draw End Marker + // + xpos=(edit_logline[2]->endPoint(RDLogLine::CartPointer)- + edit_wave_origin[2])/TRACKER_MSECS_PER_PIXEL; + DrawCursor(wpg[2],edit_wave_map[2]->height(),xpos, + RD_START_END_MARKER_COLOR,10,false); + + // + // Draw Menu Marker + // + if(menu_clicked_point>=0 && edit_rightclick_track==2) { + DrawCursor(wpg[2],edit_wave_map[2]->height(),menu_clicked_point, + RD_START_END_MARKER_COLOR,10,true); + DrawCursor(wpg[2],edit_wave_map[2]->height(),menu_clicked_point, + RD_START_END_MARKER_COLOR,10,false); + } + + // + // Draw Rubber Bands + // + DrawRubberBand(wpg[2],2); + } + wpg[2]->setPen(TRACKER_TEXT_COLOR); + wpg[2]->drawText(5,14,QString().sprintf("%s - %s", + (const char *)edit_logline[2]->title(), + (const char *)edit_logline[2]->artist())); + if(track_recording && (edit_deck[2]->state()==RDPlayDeck::Playing || + edit_deck[2]->state()==RDPlayDeck::Stopping)) { + int talk_len=edit_logline[2]->talkLength(); + if(talk_len>0 && edit_deck[2]->currentPosition()> + edit_logline[2]->talkStartPoint()){ + talk_len-=edit_deck[2]->currentPosition()- + edit_logline[2]->talkStartPoint(); + } + wpg[2]->drawText(550,75,QString().sprintf("Talk :%d", + (talk_len+500)/1000)); + } + else { + wpg[2]->drawText(550,75,QString().sprintf("Talk :%d", + (edit_logline[2]->talkLength()+500)/1000)); + } + + wpg[2]->end(); + } + break; + } +} + + +void VoiceTracker::DrawCursor(RDWavePainter *wp,int height,int xpos, + const QColor &color,int arrow_offset, + bool left_arrow) +{ + wp->setPen(color); + wp->setBrush(color); + wp->moveTo(xpos,0); + wp->lineTo(xpos,height); + int arrow_x=8; + if(left_arrow) { + arrow_x=-8; + } + QPointArray *pa=new QPointArray(3); + pa->setPoint(0,xpos,arrow_offset); + pa->setPoint(1,xpos+arrow_x,arrow_offset-5); + pa->setPoint(2,xpos+arrow_x,arrow_offset+5); + wp->drawPolygon(*pa); + pa->setPoint(0,xpos,height-arrow_offset); + pa->setPoint(1,xpos+arrow_x,height-(arrow_offset-5)); + pa->setPoint(2,xpos+arrow_x,height-(arrow_offset+5)); + wp->drawPolygon(*pa); + delete pa; +} + + +void VoiceTracker::DrawRubberBand(RDWavePainter *wp,int trackno) +{ + int xpos=0; + int ypos=0; + + wp->setPen(TRACKER_RUBBERBAND_COLOR); + wp->setBrush(TRACKER_RUBBERBAND_COLOR); + + int draw_fadeup_gain=edit_logline[trackno]->fadeupGain(); + int draw_fadedown_gain=edit_logline[trackno]->fadedownGain(); + int draw_fadedown_point=edit_logline[trackno]->fadedownPoint(); + int draw_duckup_gain=edit_logline[trackno]->duckUpGain(); + int draw_duckdown_gain=edit_logline[trackno]->duckDownGain(); + int draw_end_point=edit_logline[trackno]->endPoint(); + if(edit_logline[trackno]->fadedownPoint(RDLogLine::LogPointer)<0) { + draw_fadedown_gain=RD_FADE_DEPTH; + } + if(edit_logline[trackno]->fadeupPoint(RDLogLine::LogPointer)<0) { + draw_fadeup_gain=RD_FADE_DEPTH; + } + + if(draw_fadeup_gainfadeupPoint()<=edit_logline[trackno]->startPoint() + && draw_fadeup_gain==0) + draw_fadeup_gain=TRACKER_MIN_GAIN; + if(edit_logline[trackno]->fadedownPoint()<0 && draw_fadedown_gain==0) + draw_fadedown_gain=TRACKER_MIN_GAIN; + if(edit_logline[trackno]->fadedownPoint()>=edit_logline[trackno]->endPoint() + && draw_fadedown_gain==0) + draw_fadedown_gain=TRACKER_MIN_GAIN; + if(edit_logline[trackno]->segueGain()<0 + && edit_logline[trackno]->segueStartPoint()>=0 + && edit_logline[trackno]->segueStartPoint()transType()==RDLogLine::Segue) { + draw_fadedown_point=edit_logline[trackno]->segueStartPoint(); + draw_fadedown_gain=edit_logline[trackno]->segueGain(); + } + } + } + if(trackno<2) { + if((edit_logline[trackno+1]->transType()==RDLogLine::Segue) + && (!track_loaded)) { + draw_end_point=edit_logline[trackno]->segueEndPoint(); + if(draw_fadedown_point>draw_end_point) { + draw_fadedown_point=draw_end_point; + } + } + } + + // + // Fade Up + // + xpos=(edit_logline[trackno]->startPoint()- + edit_wave_origin[trackno])/TRACKER_MSECS_PER_PIXEL; + if(trackno==0) { + ypos=TRACKER_GAIN_MARGIN- + draw_duckdown_gain/TRACKER_MB_PER_PIXEL- + (int)((double)draw_fadeup_gain* + (1-(double)draw_duckdown_gain/TRACKER_MIN_GAIN)) + /TRACKER_MB_PER_PIXEL; + } + else { + ypos=TRACKER_GAIN_MARGIN- + draw_duckup_gain/TRACKER_MB_PER_PIXEL- + (int)((double)draw_fadeup_gain* + (1-(double)draw_duckup_gain/TRACKER_MIN_GAIN)) + /TRACKER_MB_PER_PIXEL; + + } + wp->moveTo(xpos,ypos); + switch(trackno) { + case 1: + DrawTarget(wp,VoiceTracker::TrackFadeupGain,trackno,xpos,ypos); + break; + + case 2: + DrawTarget(wp,VoiceTracker::FadeupGain,trackno,xpos,ypos); + break; + } + xpos=(edit_logline[trackno]->fadeupPoint()- + edit_wave_origin[trackno])/TRACKER_MSECS_PER_PIXEL; + switch(trackno) { + case 0: + ypos=TRACKER_GAIN_MARGIN- + draw_duckdown_gain/TRACKER_MB_PER_PIXEL; + break; + + case 1: + ypos=TRACKER_GAIN_MARGIN; + break; + + case 2: + ypos=TRACKER_GAIN_MARGIN- + draw_duckup_gain/TRACKER_MB_PER_PIXEL; + break; + } + wp->lineTo(xpos,ypos); + switch(trackno) { + case 1: + DrawTarget(wp,VoiceTracker::TrackFadeupPoint,trackno,xpos,ypos); + break; + + case 2: + DrawTarget(wp,VoiceTracker::FadeupPoint,trackno,xpos,ypos); + break; + } + + // + // Body of cut + // + xpos=(edit_logline[trackno]->fadeupPoint()- + edit_wave_origin[trackno])/TRACKER_MSECS_PER_PIXEL; + wp->moveTo(xpos,ypos); + if(draw_fadedown_point>= + edit_logline[trackno]->fadeupPoint()) + xpos=(draw_fadedown_point- + edit_wave_origin[trackno])/TRACKER_MSECS_PER_PIXEL; + else + xpos=(draw_end_point- + edit_wave_origin[trackno])/TRACKER_MSECS_PER_PIXEL; + + wp->lineTo(xpos,ypos); + + // + // Fade Down + switch(trackno) { + case 0: + DrawTarget(wp,VoiceTracker::FadedownPoint,trackno,xpos,ypos); + break; + + case 1: + DrawTarget(wp,VoiceTracker::TrackFadedownPoint,trackno,xpos,ypos); + break; + } + xpos=(draw_end_point- + edit_wave_origin[trackno])/TRACKER_MSECS_PER_PIXEL; + if(trackno==2) { + ypos=TRACKER_GAIN_MARGIN- + draw_duckup_gain/TRACKER_MB_PER_PIXEL- + (int)((double)draw_fadedown_gain* + (1-(double)draw_duckup_gain/TRACKER_MIN_GAIN)) + /TRACKER_MB_PER_PIXEL; + } + else { + ypos=TRACKER_GAIN_MARGIN- + edit_logline[trackno]->duckDownGain()/TRACKER_MB_PER_PIXEL- + (int)((double)draw_fadedown_gain* + (1-(double)draw_duckdown_gain/TRACKER_MIN_GAIN)) + /TRACKER_MB_PER_PIXEL; + } + wp->lineTo(xpos,ypos); + switch(trackno) { + case 0: + DrawTarget(wp,VoiceTracker::FadedownGain,trackno,xpos,ypos); + break; + + case 1: + DrawTarget(wp,VoiceTracker::TrackFadedownGain,trackno,xpos,ypos); + break; + } +} + + +void VoiceTracker::DrawTarget(RDWavePainter *wp,VoiceTracker::Target target, + int trackno,int xpos,int ypos) +{ + track_target_rect[target]->setX(xpos-TRACKER_GAIN_MARGIN); + track_target_rect[target]->setY(ypos-TRACKER_GAIN_MARGIN); + track_target_rect[target]->setWidth(TRACKER_GAIN_MARGIN*2); + track_target_rect[target]->setHeight(TRACKER_GAIN_MARGIN*2); + track_target_track[target]=trackno; + wp->drawRect(*(track_target_rect[target])); +} + + +void VoiceTracker::WriteTrackMap(int trackno) +{ + QPainter *p=new QPainter(this); + switch(trackno) { + case 0: + p->drawPixmap(TRACKER_X_ORIGIN,TRACKER_Y_ORIGIN,*edit_wave_map[0]); + break; + + case 1: + p->drawPixmap(TRACKER_X_ORIGIN,TRACKER_Y_HEIGHT+TRACKER_Y_ORIGIN, + *edit_wave_map[1]); + break; + + case 2: + p->drawPixmap(TRACKER_X_ORIGIN,TRACKER_Y_HEIGHT*2+TRACKER_Y_ORIGIN, + *edit_wave_map[2]); + break; + } + p->end(); + delete p; +} + + +bool VoiceTracker::TransportActive() +{ + return track_recording||PlayoutActive(); +} + + +bool VoiceTracker::PlayoutActive() +{ + for(int i=0;i<3;i++) { + if((edit_deck[i]->state()==RDPlayDeck::Playing)|| + (edit_deck[i]->state()==RDPlayDeck::Stopping)) { + return true; + } + } + return false; +} + + +void VoiceTracker::UpdateControls() +{ + bool transport_idle=!TransportActive(); + + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + if((item==NULL)||(item->line()==TRACKER_MAX_LINENO)) { + track_track1_button->setDisabled(true); + track_track1_button->setText(tr("Start")); + track_track1_button->setPalette(track_start_palette); + track_record_button->setDisabled(true); + track_record_button->setText(tr("Record")); + track_track2_button->setDisabled(true); + track_finished_button->setDisabled(true); + track_reset_button->setDisabled(true); + track_post_button->setDisabled(true); + track_play_button->setDisabled(true); + track_stop_button->setDisabled(true); + track_next_button->setEnabled(transport_idle); + track_previous_button->setEnabled(transport_idle); + track_insert_button->setEnabled(transport_idle&&CanInsertTrack()); + track_delete_button->setEnabled(transport_idle&&CanDeleteTrack()); + track_close_button->setEnabled(true); + track_log_list->setEnabled(transport_idle); + return; + } + RDLogLine *real_logline=track_log_event->logLine(item->line()); + RDLogLine *logline=NULL; + if(track_offset) { + logline=track_log_event->logLine(item->line()-1); + } + else { + logline=real_logline; + } + if(track_loaded) { + if(logline->type()==RDLogLine::Track) { // Unfinished Track + switch(edit_deck_state) { + case VoiceTracker::DeckIdle: + if(edit_wave_name[0].isEmpty()) { + track_track1_button->setEnabled(!track_group->name().isEmpty()); + track_track1_button->setText(tr("Import")); + track_track1_button->setPalette(track_record_palette); + track_record_button->setEnabled(!track_group->name().isEmpty()); + track_record_button->setText(tr("Record")); + track_record_button->setFocus(); + } + else { + if((logline->transType()==RDLogLine::Segue)) { + track_track1_button-> + setEnabled(!track_group->name().isEmpty()); + track_track1_button->setText(tr("Start")); + track_track1_button->setPalette(track_start_palette); + track_track1_button->setFocus(); + track_record_button-> + setEnabled(!track_group->name().isEmpty()); + track_record_button->setText(tr("Import")); + } + else { + track_track1_button-> + setEnabled(!track_group->name().isEmpty()); + track_track1_button->setText(tr("Import")); + track_track1_button->setPalette(track_record_palette); + track_record_button-> + setEnabled(!track_group->name().isEmpty()); + track_record_button->setText(tr("Record")); + track_record_button->setFocus(); + } + } + track_track2_button->setDisabled(true); + track_finished_button->setPalette(track_done_palette); + track_finished_button->setText(tr("Save")); + track_finished_button->setEnabled(track_changed); + track_reset_button-> + setEnabled(real_logline->hasCustomTransition()); + track_post_button->setDisabled(true); + track_play_button->setEnabled(true); + track_stop_button->setEnabled(true); + track_next_button->setEnabled(transport_idle); + track_previous_button->setEnabled(transport_idle); + track_insert_button->setEnabled(transport_idle&&CanInsertTrack()); + track_delete_button->setEnabled(transport_idle&&CanDeleteTrack()); + track_close_button->setEnabled(true); + track_log_list->setEnabled(transport_idle); + break; + + case VoiceTracker::DeckTrack1: + track_track1_button->setDisabled(true); + track_track1_button->setText(tr("Start")); + track_track1_button->setPalette(track_start_palette); + track_record_button->setEnabled(true); + track_record_button->setText(tr("Record")); + track_record_button->setFocus(); + track_track2_button->setDisabled(true); + track_finished_button->setPalette(track_abort_palette); + track_finished_button->setText(tr("Abort")); + track_finished_button->setEnabled(true); + track_reset_button->setDisabled(true); + track_post_button->setDisabled(true); + track_play_button->setDisabled(true); + track_stop_button->setDisabled(true); + track_next_button->setDisabled(true); + track_previous_button->setDisabled(true); + track_insert_button->setDisabled(true); + track_delete_button->setDisabled(true); + track_close_button->setDisabled(true); + track_log_list->setDisabled(true); + break; + + case VoiceTracker::DeckTrack2: + track_track1_button->setDisabled(true); + track_track1_button->setText(tr("Start")); + track_track1_button->setPalette(track_start_palette); + track_record_button->setDisabled(true); + track_record_button->setText(tr("Record")); + if(edit_wave_name[2].isEmpty()) { + track_finished_button->setPalette(track_done_palette); + track_finished_button->setText(tr("Save")); + track_finished_button->setFocus(); + track_track2_button->setDisabled(true); + } + else { + if((edit_logline[2]->transType()==RDLogLine::Segue)) { + if(rdlogedit_conf->enableSecondStart()) { + track_finished_button->setPalette(track_abort_palette); + track_finished_button->setText(tr("Abort")); + } + else { + track_finished_button->setPalette(track_done_palette); + track_finished_button->setText(tr("Save")); + } + track_track2_button->setEnabled(true); + } + else { + track_finished_button->setText(tr("Save")); + track_finished_button->setPalette(track_done_palette); + track_track2_button->setDisabled(true); + } + track_track2_button->setFocus(); + } + track_finished_button->setEnabled(true); + track_reset_button->setDisabled(true); + track_insert_button->setDisabled(true); + track_delete_button->setDisabled(true); + track_post_button->setDisabled(true); + track_play_button->setDisabled(true); + track_stop_button->setDisabled(true); + track_next_button->setDisabled(true); + track_previous_button->setDisabled(true); + track_close_button->setDisabled(true); + track_log_list->setDisabled(true); + break; + + case VoiceTracker::DeckTrack3: + track_track1_button->setDisabled(true); + track_track1_button->setText(tr("Start")); + track_track1_button->setPalette(track_start_palette); + track_record_button->setDisabled(true); + track_record_button->setText(tr("Record")); + track_track2_button->setDisabled(true); + track_finished_button->setPalette(track_done_palette); + track_finished_button->setText(tr("Save")); + track_finished_button->setEnabled(true); + track_finished_button->setFocus(); + track_reset_button->setDisabled(true); + track_post_button->setDisabled(true); + track_insert_button->setDisabled(true); + track_delete_button->setDisabled(true); + track_play_button->setDisabled(true); + track_stop_button->setDisabled(true); + track_next_button->setDisabled(true); + track_previous_button->setDisabled(true); + track_close_button->setDisabled(true); + track_log_list->setDisabled(true); + break; + } + } + else { // Completed Track + track_track1_button->setDisabled(true); + track_track1_button->setText(tr("Start")); + track_track1_button->setPalette(track_start_palette); + track_record_button->setDisabled(true); + track_record_button->setText(tr("Record")); + track_track2_button->setDisabled(true); + track_finished_button->setEnabled(track_changed); + track_reset_button->setEnabled(transport_idle); + track_post_button-> + setEnabled(transport_idle&&(!edit_wave_name[2].isEmpty())); + track_play_button->setEnabled(true); + track_stop_button->setEnabled(true); + track_next_button->setEnabled(transport_idle); + track_previous_button->setEnabled(transport_idle); + if(transport_idle) { + track_next_button->setFocus(); + } + track_insert_button->setEnabled(transport_idle&&CanInsertTrack()); + track_delete_button->setEnabled(transport_idle&&CanDeleteTrack()); + track_close_button->setEnabled(true); + track_log_list->setEnabled(transport_idle); + } + } + else { // Straight Segue + track_track1_button->setDisabled(true); + track_track1_button->setText(tr("Start")); + track_track1_button->setPalette(track_start_palette); + track_record_button->setDisabled(true); + track_record_button->setText(tr("Record")); + track_track2_button->setDisabled(true); + track_finished_button->setEnabled(track_changed); + track_reset_button->setEnabled(real_logline->hasCustomTransition()); + track_post_button->setDisabled(true); + track_play_button->setEnabled(true); + track_stop_button->setEnabled(true); + track_next_button->setEnabled(transport_idle); + track_previous_button->setEnabled(transport_idle); + if(transport_idle) { + track_next_button->setFocus(); + } + track_insert_button->setEnabled(transport_idle&&CanInsertTrack()); + track_delete_button->setEnabled(transport_idle&&CanDeleteTrack()); + track_close_button->setEnabled(true); + track_log_list->setEnabled(transport_idle); + } +} + + +void VoiceTracker::UpdateRemaining() +{ + edit_tracks_remaining_label->setText(QString().sprintf("%d",track_tracks)); + if(track_block_valid) { + edit_time_remaining_label-> + setText(QString().sprintf("%s",(const char *) + RDGetTimeLength(track_time_remaining, + true,true))); + if(track_time_remaining>=0) { + edit_time_remaining_label->setPalette(edit_time_remaining_palette[0]); + } + else { + edit_time_remaining_label->setPalette(edit_time_remaining_palette[1]); + } + } + else { + edit_time_remaining_label->setText("-:--:--.-"); + edit_time_remaining_label->setPalette(edit_time_remaining_palette[0]); + } +} + + +bool VoiceTracker::TrackAvailable() +{ + if(!track_group->exists()) { + return false; + } + if((track_group->freeCartQuantity()<=0)&&edit_wave_name[1].isEmpty()) { + return false; + } + return true; +} + + +void VoiceTracker::LogLine(const QString &line) +{ + fprintf(stderr,"%s: %s\n", + (const char *)QTime::currentTime().toString("hh:mm:ss.zzz"), + (const char *)line); +} + + +bool VoiceTracker::InitTrack() +{ + int cutnum; + + track_recording=false; + track_record_ran=false; + track_recording_pos=0; + track_aborting=false; + if(edit_track_cart!=NULL) { + delete edit_track_cart; + edit_track_cart=NULL; + } + bool ok=false; + unsigned next_cart=0; + RDCart *cart=NULL; + while(!ok) { + if((next_cart=track_group->nextFreeCart())==0) { + return false; + } + cart=new RDCart(next_cart); + ok=cart->create(track_group->name(),RDCart::Audio); + delete cart; + } + edit_track_cart=new RDCart(next_cart); + edit_track_cart->setOwner(track_log->name()); + edit_track_cart->setTitle(edit_logline[1]->markerComment()); + if(edit_track_cuts[1]!=NULL) { + delete edit_track_cuts[1]; + } + if((cutnum=edit_track_cart->addCut(edit_format,edit_bitrate,edit_chans))<0) { + QMessageBox::warning(this,tr("RDLogEdit - Voice Tracker"), + tr("This cart cannot contain any additional cuts!")); + return false; + } + edit_track_cuts[1]=new RDCut(edit_track_cart->number(),cutnum); + switch(edit_format) { + case 0: + edit_coding=RDCae::Pcm16; + break; + + case 1: + edit_coding=RDCae::MpegL2; + break; + + default: + edit_coding=RDCae::Pcm16; + break; + } + edit_deck_state=VoiceTracker::DeckTrack1; + edit_sliding=false; + for(unsigned i=0;i<3;i++) { + edit_segue_start_point[i]=-1; +// edit_segue_gain[i]=-1; + } + edit_logline[1]-> + setFadeupPoint(edit_logline[1]->startPoint(),RDLogLine::LogPointer); + edit_logline[1]->setFadedownGain(RD_FADE_DEPTH); + edit_logline[1]-> + setFadedownPoint(edit_logline[1]->endPoint(),RDLogLine::LogPointer); + edit_logline[1]->setFadeupGain(RD_FADE_DEPTH); + track_tracks--; + + return true; +} + + +void VoiceTracker::FinishTrack() +{ + edit_logline[0]-> + setSegueStartPoint(edit_segue_start_point[0],RDLogLine::LogPointer); + edit_logline[0]->setSegueGain(0); + edit_logline[0]-> + setAverageSegueLength(edit_logline[0]->segueStartPoint()- + edit_logline[0]->startPoint()); + if(!edit_wave_name[1].isEmpty()) { + rdcae->stopRecord(edit_input_card,edit_input_port); + edit_logline[1]->setEndPoint(-1,RDLogLine::LogPointer); + } + stopData(); + edit_deck_state=VoiceTracker::DeckIdle; +} + + +double VoiceTracker::GetCurrentTime() +{ + struct timeval tv; + + memset(&tv,0,sizeof(tv)); + gettimeofday(&tv,NULL); + return (double)tv.tv_sec+(double)tv.tv_usec/1000000.0; +} + + +bool VoiceTracker::IsTrack(int line,bool *offset) +{ + *offset=false; + if(track_log_event->logLine(line)==NULL) { + return false; + } + if((track_log_event->logLine(line)->type()==RDLogLine::Track)|| + (track_log_event->logLine(line)->source()==RDLogLine::Tracker)) { + return true; + } + if(track_log_event->logLine(line-1)==NULL) { + return false; + } +/* if((track_log_event->logLine(line-1)->type()==RDLogLine::Track)|| + (track_log_event->logLine(line-1)->source()==RDLogLine::Tracker)) { + *offset=true; + return true; + }*/ + return false; +} + + +bool VoiceTracker::CanInsertTrack() +{ + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + if(item==NULL) { + return false; + } + if(item->line()==TRACKER_MAX_LINENO) { + if(track_log_event->size()<=0) { + return true; + } + return track_log_event->logLine(track_log_event->size()-1)->type() + !=RDLogLine::Track; + } + bool state=track_log_event->logLine(item->line())->type()==RDLogLine::Track; + if(item->line()>0) { + state=state|| + (track_log_event->logLine(item->line()-1)->type()==RDLogLine::Track); + } + + return !state; +} + + +bool VoiceTracker::CanDeleteTrack() +{ + RDListViewItem *item=(RDListViewItem *)track_log_list->selectedItem(); + if(track_offset) { + item=GetItemByLine(item->line()-1); + } + if((item==NULL)||(item->line()==TRACKER_MAX_LINENO)) { + return false; + } + return track_log_event->logLine(item->line())->type()==RDLogLine::Track; +} + + +void VoiceTracker::ClearCursor(QPainter *p) +{ + if(edit_cursor_pos>=0) { + for(int i=0;i<3;i++) { + p->drawPixmap(edit_cursor_pos,12+79*i,*edit_wave_map[i], + edit_cursor_pos-12,0,1, + edit_wave_map[i]->size().height()); + } + } +} + + +RDListViewItem *VoiceTracker::GetItemByLine(int line) +{ + RDListViewItem *item=(RDListViewItem *)track_log_list->firstChild(); + while(item!=NULL) { + if(item->line()==line) { + return item; + } + item=(RDListViewItem *)item->nextSibling(); + } + return NULL; +} + + +void VoiceTracker::CheckChanges() +{ + if(track_changed) { + switch(QMessageBox::question(this,tr("Segue Changed"), + tr("Save segue changes?"), + QMessageBox::Yes,QMessageBox::No)) { + case QMessageBox::Yes: + finishedData(); + break; + + case QMessageBox::No: + case QMessageBox::NoButton: + PopSegues(); + break; + } + } + track_changed=false; +} + + +void VoiceTracker::PushSegues() +{ + for(unsigned i=0;i<3;i++) { + if(edit_logline[i]!=NULL) { + *(edit_saved_logline[i])=*(edit_logline[i]); + } + } +} + + +void VoiceTracker::PopSegues() +{ + for(unsigned i=0;i<3;i++) { + if(edit_logline[i]!=NULL) { + *(edit_logline[i])=*(edit_saved_logline[i]); + } + } +} diff --git a/rdlogedit/voice_tracker.h b/rdlogedit/voice_tracker.h new file mode 100644 index 00000000..14a00bbf --- /dev/null +++ b/rdlogedit/voice_tracker.h @@ -0,0 +1,293 @@ +// voice_tracker.h +// +// A Rivendell Voice Tracker +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: voice_tracker.h,v 1.50 2010/09/16 19:52:08 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef VOICE_TRACKER_H +#define VOICE_TRACKER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Widget Settings +// +#define TRACKER_TEXT_COLOR red +#define TRACKER_RUBBERBAND_COLOR "#008000" +#define TRACKER_RECORD_COLOR green +#define TRACKER_RECORD_BUTTON_COLOR red +#define TRACKER_START_BUTTON_COLOR green +#define TRACKER_ABORT_BUTTON_COLOR red +#define TRACKER_DONE_BUTTON_COLOR blue +#define TRACKER_START_WIDTH 19633 +#define TRACKER_MSECS_PER_PIXEL 29 +//#define TRACKER_MB_PER_PIXEL 141 +#define TRACKER_MB_PER_PIXEL 42 +#define TRACKER_GAIN_MARGIN 4 +#define TRACKER_MAX_GAIN 0 +#define TRACKER_MIN_GAIN -3000 +#define TRACKER_X_ORIGIN 12 +#define TRACKER_X_WIDTH sizeHint().width()-123 +#define TRACKER_Y_ORIGIN 12 +#define TRACKER_Y_HEIGHT 79 +#define TRACKER_SCROLL_SCALE 2 +#define TRACKER_SCROLL_SCALE 2 +#define TRACKER_FORCED_SEGUE 1000 + +class VoiceTracker : public QDialog +{ + Q_OBJECT + public: + VoiceTracker(const QString &logname,QString *import_path, + QWidget *parent=0,const char *name=0); + ~VoiceTracker(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void updateMenuData(); + void hideMenuData(); + virtual void keyPressEvent(QKeyEvent *e); + virtual void keyReleaseEvent(QKeyEvent *e); + virtual void wheelEvent(QWheelEvent *e); + void playData(); + void stopData(); + void track1Data(); + void recordData(); + void track2Data(); + void finishedData(); + void postData(); + void resetData(); + void insertData(); + void insertData(int line,RDLogLine *logline,bool warn); + void deleteData(); + void deleteData(int line,bool warn); + void previousData(); + void nextData(); + void editAudioData(); + void undoChangesData(); + void setStartPointData(); + void setEndPointData(); + void setHookPointData(); + void stateChangedData(int id,RDPlayDeck::State state); + void positionData(int id,int msecs); + void segueStartData(int id); + void logClickedData(QListViewItem *item,const QPoint &pt,int col); + void transitionChangedData(int line,RDLogLine::TransType trans); + void meterData(); + void recordLoadedData(int card,int stream); + void recordingData(int card,int stream); + void recordStoppedData(int card,int stream); + void recordUnloadedData(int cart,int stream,unsigned msecs); + void closeData(); + + protected: + void paintEvent(QPaintEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + + private: + enum DeckState {DeckIdle=0,DeckTrack1=1,DeckTrack2=2,DeckTrack3=3}; + enum Target {FadeupGain=0,FadeupPoint=1,FadedownGain=2,FadedownPoint=3, + TrackFadeupGain=4,TrackFadeupPoint=5, + TrackFadedownGain=6,TrackFadedownPoint=7,TargetSize=8}; + void LoadTrack(int line); + void SaveTrack(int line); + bool ImportTrack(RDListViewItem *item); + void RenderTransition(int line); + void LoadBlockLength(int line); + void RefreshList(); + void RefreshLine(RDListViewItem *item); + void StartNext(int finishing_id,int next_id=-1); + QString GetCutName(int line,RDCut **cut); + int GetClick(QMouseEvent *e,QPoint *p); + void DragTrack(int trackno,int xdiff); + void DragTarget(int trackno,const QPoint &pt); + void DrawTrackMap(int trackno); + void DrawCursor(RDWavePainter *wp,int height,int xpos,const QColor &color, + int arrow_offset,bool left_arrow); + void DrawRubberBand(RDWavePainter *wp,int trackno); + void DrawTarget(RDWavePainter *wp,VoiceTracker::Target target, + int trackno,int xpos,int ypos); + void WriteTrackMap(int trackno); + bool TransportActive(); + bool PlayoutActive(); + void UpdateControls(); + void UpdateRemaining(); + bool TrackAvailable(); + void LogLine(const QString &line); + bool InitTrack(); + void FinishTrack(); + double GetCurrentTime(); + bool IsTrack(int line,bool *offset); + bool CanInsertTrack(); + bool CanDeleteTrack(); + void ClearCursor(QPainter *p); + RDListViewItem *GetItemByLine(int line); + void CheckChanges(); + void PushSegues(); + void PopSegues(); + RDStereoMeter *track_meter; + QTimer *track_meter_timer; + RDTransportButton *track_play_button; + RDTransportButton *track_stop_button; + QPushButton *track_track1_button; + QPushButton *track_record_button; + QPushButton *track_track2_button; + QPushButton *track_finished_button; + QPushButton *track_post_button; + QPushButton *track_reset_button; + QPushButton *track_previous_button; + QPushButton *track_next_button; + QPushButton *track_insert_button; + QPushButton *track_delete_button; + QPushButton *track_close_button; + RDLog *track_log; + RDLogEvent *track_log_event; + RDEventPlayer *track_event_player; + QString edit_log_name; + int track_line; + unsigned track_tracks; + int track_time_remaining; + int track_time_remaining_start; + int track_time_counter; + bool track_block_valid; + QTime track_start_time; + LogListView *track_log_list; + QLabel *edit_length_label; + QLabel *edit_tracks_remaining_label; + QLabel *edit_time_remaining_label; + QPalette edit_time_remaining_palette[2]; + QPixmap *edit_wave_map[3]; + QString edit_wave_name[3]; + RDWavePainter *wpg[3]; + //int edit_wave_pos[3]; + int edit_scroll_pos[3]; + int edit_wave_origin[3]; + RDLogLine *edit_logline[3]; + RDLogLine *edit_saved_logline[3]; + int edit_segue_start_point[3]; + int edit_segue_gain[3]; + int edit_segue_start_offset[3]; + RDPlayDeck *edit_deck[3]; + int edit_track_line[3]; + bool track_redraw[3]; + unsigned track_redraw_count; + RDCart *edit_track_cart; + + //RDCut *edit_track_cut; + RDCut *edit_track_cuts[3]; + + RDGroup *track_group; + int edit_wave_width; + int edit_cursor_pos; + QPixmap *edit_playout_map; + QPixmap *edit_macro_map; + QPixmap *edit_marker_map; + QPixmap *edit_chain_map; + QPixmap *edit_track_cart_map; + QPixmap *edit_music_map; + QPixmap *edit_notemarker_map; + QPixmap *edit_traffic_map; + QPixmap *edit_mic16_map; + int edit_input_card; + int edit_input_port; + int edit_output_card; + int edit_output_port; + int edit_tail_preroll; + int edit_threshold_level; + RDCae::AudioCoding edit_coding; + unsigned edit_format; + unsigned edit_samprate; + unsigned edit_bitrate; + unsigned edit_chans; + unsigned play_start_macro; + unsigned play_end_macro; + unsigned record_start_macro; + unsigned record_end_macro; + DeckState edit_deck_state; + bool edit_sliding; + bool edit_scrolling; + int edit_scroll_threshold; + QPoint *edit_previous_point; + int edit_current_track; + int edit_rightclick_track; + int edit_rightclick_pos; + QCursor *track_current_cursor; + QCursor *track_arrow_cursor; + QCursor *track_hand_cursor; + QCursor *track_cross_cursor; + bool track_loaded; + bool track_offset; + bool segue_loaded; + bool track_recording; + bool track_changed; + double track_record_start_time; + int track_recording_pos; + bool track_aborting; + bool track_record_ran; + RDLogLine *track_dummy0_logline; + RDLogLine *track_dummy2_logline; + QString track_import_filter; + QString track_import_group; + int track_preroll; + bool track_size_altered; + QPalette track_start_palette; + QPalette track_record_palette; + QPalette track_done_palette; + QPalette track_abort_palette; + QPopupMenu *track_menu; + int menu_clicked_point; + QString *edit_import_path; + RDSettings *edit_settings; + QRect *track_track_rect; + QRect *track_trackzones_rect[3]; + QRect *track_target_rect[VoiceTracker::TargetSize]; + int track_target_track[VoiceTracker::TargetSize]; + VoiceTracker::Target track_current_target; + bool edit_shift_pressed; +}; + + +#endif diff --git a/rdlogin/Makefile.am b/rdlogin/Makefile.am new file mode 100644 index 00000000..535adb11 --- /dev/null +++ b/rdlogin/Makefile.am @@ -0,0 +1,72 @@ +## automake.am +## +## Automake.am for rivendell/rdlogin +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.22.8.2 2013/01/01 21:36:31 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdlogin_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rdlogin_*.qm + +all: + @QT_BIN@/lupdate rdlogin.pro + @QT_BIN@/lrelease rdlogin.pro + +bin_PROGRAMS = rdlogin + +dist_rdlogin_SOURCES = rdlogin.cpp rdlogin.h + +nodist_rdlogin_SOURCES = moc_rdlogin.cpp + +rdlogin_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdlogin.pro\ + rdlogin_cs.ts\ + rdlogin_de.ts\ + rdlogin_es.ts\ + rdlogin_fr.ts\ + rdlogin_nb.ts\ + rdlogin_nn.ts\ + rdlogin_pt_BR.ts + +CLEANFILES = *~\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/rdlogin/rdlogin.cpp b/rdlogin/rdlogin.cpp new file mode 100644 index 00000000..c4ddb3cb --- /dev/null +++ b/rdlogin/rdlogin.cpp @@ -0,0 +1,361 @@ +// rdlogin.cpp +// +// The User Login/Logout Utility for Rivendell. +// +// (C) Copyright 2002-2008 Fred Gleason +// +// $Id: rdlogin.cpp,v 1.35.4.2 2014/01/21 21:59:32 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +// +// Icons +// +#include "../icons/rivendell-22x22.xpm" + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + login_user_width=160; + + QString str; + QString sql; + RDSqlQuery *q; + bool skip_db_check=false; + unsigned schema=0; + + // + // Read Command Options + // + RDCmdSwitch *cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdlogin","\n"); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + } + delete cmd; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont default_font("Helvetica",12,QFont::Normal); + default_font.setPixelSize(12); + qApp->setFont(default_font); + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",16,QFont::Bold); + label_font.setPixelSize(12); + QFont small_label_font=QFont("Helvetica",12,QFont::Bold); + small_label_font.setPixelSize(12); + QFont line_edit_font=QFont("Helvetica",12,QFont::Normal); + line_edit_font.setPixelSize(12); + + // + // Create And Set Icon + // + login_rivendell_map=new QPixmap(rivendell_xpm); + setIcon(*login_rivendell_map); + + // + // Text Validator + // + RDTextValidator *validator=new RDTextValidator(this,"validator"); + + // + // Ensure that the system daemons are running + // + RDInitializeDaemons(); + + // + // Load Configs + // + login_config=new RDConfig(); + login_config->load(); + + str=QString(tr("RDLogin - Station:")); + setCaption(QString().sprintf("%s %s",(const char *)str, + (const char *)login_config->stationName())); + + // + // Open Database + // + QString err(tr("rdlogin : ")); + login_db = RDInitDb(&schema,&err); + if(!login_db) { + QMessageBox::warning(this,tr("Can't Connect"),err); + exit(0); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr,"rdlogin: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + + // + // RIPC Connection + // + login_ripc=new RDRipc(login_config->stationName()); + connect(login_ripc,SIGNAL(connected(bool)),this,SLOT(connectedData(bool))); + connect(login_ripc,SIGNAL(userChanged()),this,SLOT(userData())); + login_ripc->connectHost("localhost",RIPCD_TCP_PORT, + login_config->password()); + + // + // Station + // + login_station=new RDStation(login_config->stationName()); + + // + // User Label + // + login_label=new QLabel(this,"login_label"); + login_label->setFont(label_font); + login_label->setAlignment(AlignCenter); + login_label->setText(tr("Current User: unknown")); + + // + // User Name + // + login_username_box=new QComboBox(this,"login_username_box"); + login_username_box->setFont(line_edit_font); + login_username_box->setFocus(); + QFontMetrics fm(line_edit_font); + sql="select LOGIN_NAME from USERS where ADMIN_CONFIG_PRIV=\"N\"\ + order by LOGIN_NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + login_username_box->insertItem(q->value(0).toString()); + if(fm.width(q->value(0).toString())>login_user_width) { + login_user_width=fm.width(q->value(0).toString()); + } + } + delete q; + if(login_user_width>900) { + login_user_width=900; + } + login_username_label=new QLabel(login_username_box,tr("&Username:"), + this,"login_username_label"); + login_username_label->setFont(small_label_font); + login_username_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Password + // + login_password_edit=new QLineEdit(this,"login_password_edit"); + login_password_edit->setFont(line_edit_font); + login_password_edit->setMaxLength(16); + login_password_edit->setValidator(validator); + login_password_edit->setEchoMode(QLineEdit::Password); + login_password_label=new QLabel(login_password_edit,tr("&Password:"), + this,"login_password_label"); + login_password_label->setFont(small_label_font); + login_password_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + connect(login_password_edit,SIGNAL(returnPressed()),this,SLOT(loginData())); + + // + // Login Button + // + login_button=new QPushButton(this,"login_button"); + login_button->setFont(button_font); + login_button->setText(tr("&Set User")); + connect(login_button,SIGNAL(clicked()),this,SLOT(loginData())); + + // + // Logout Button + // + logout_button=new QPushButton(this,"logout_button"); + logout_button->setFont(button_font); + logout_button->setText(tr("&Default\nUser")); + connect(logout_button,SIGNAL(clicked()),this,SLOT(logoutData())); + + // + // Cancel Button + // + cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setFont(button_font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + resizeEvent(NULL); +} + + +MainWidget::~MainWidget() +{ + delete login_db; + delete login_ripc; + delete login_station; + delete login_label; + delete login_username_box; + delete login_password_edit; +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(120+login_user_width,160); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::connectedData(bool state) +{ +} + + +void MainWidget::userData() +{ + QString str; + + str=QString(tr("Current User:")); + login_label->setText(QString().sprintf("%s %s",(const char *)str, + (const char *)login_ripc->user())); + resizeEvent(NULL); +} + + +void MainWidget::loginData() +{ + RDUser *user=new RDUser(login_username_box->currentText()); + if(user->checkPassword(login_password_edit->text(),false)) { + login_ripc->setUser(login_username_box->currentText()); + login_password_edit->clear(); + delete user; + qApp->processEvents(); + cancelData(); + } + else { + QMessageBox::warning(this,tr("RDLogin"),tr("Invalid Password!")); + delete user; + } +} + + +void MainWidget::logoutData() +{ + QString default_name=login_station->defaultName(); + login_ripc->setUser(default_name); + login_password_edit->clear(); + for(int i=0;icount();i++) { + if(login_username_box->text(i)==default_name) { + login_username_box->setCurrentItem(i); + qApp->processEvents(); + cancelData(); + return; + } + } +} + + +void MainWidget::cancelData() +{ + exit(0); +} + + +void MainWidget::quitMainWidget() +{ + login_db->removeDatabase(login_config->mysqlDbname()); + qApp->quit(); +} + + +void MainWidget::resizeEvent(QResizeEvent *e) +{ + login_label->setGeometry(0,10,size().width(),21); + login_username_box->setGeometry(110,40,size().width()-120,19); + login_username_label->setGeometry(10,40,85,19); + login_password_edit->setGeometry(110,61,size().width()-120,19); + login_password_label->setGeometry(10,61,85,19); + login_button->setGeometry(size().width()-270,size().height()-60,80,50); + logout_button->setGeometry(size().width()-180,size().height()-60,80,50); + cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(), + "."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rdlogin_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} diff --git a/rdlogin/rdlogin.h b/rdlogin/rdlogin.h new file mode 100644 index 00000000..91241048 --- /dev/null +++ b/rdlogin/rdlogin.h @@ -0,0 +1,80 @@ +// rdlogin.h +// +// The User Login/Logout Utility for Rivendell. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: rdlogin.h,v 1.14 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDLOGIN_H +#define RDLOGIN_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + ~MainWidget(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void connectedData(bool state); + void userData(); + void loginData(); + void logoutData(); + void cancelData(); + void quitMainWidget(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + RDConfig *login_config; + QSqlDatabase *login_db; + RDStation *login_station; + RDRipc *login_ripc; + Q_UINT16 login_ripc_hostport; + QLabel *login_label; + QLabel *login_username_label; + QComboBox *login_username_box; + QLabel *login_password_label; + QLineEdit *login_password_edit; + QPixmap *login_rivendell_map; + QPushButton *login_button; + QPushButton *logout_button; + QPushButton *cancel_button; + int login_user_width; +}; + + +#endif // RDLOGIN_H diff --git a/rdlogin/rdlogin.pro b/rdlogin/rdlogin.pro new file mode 100644 index 00000000..b7f5fcfe --- /dev/null +++ b/rdlogin/rdlogin.pro @@ -0,0 +1,43 @@ +# rdlogin.pro +# +# The QMake project file for RDLogin. +# +# (C) Copyright 2003-2005 Fred Gleason +# +# $Id: rdlogin.pro,v 1.7.8.1 2013/01/01 21:36:31 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +x11 { + SOURCES += rdlogin.cpp +} + +x11 { + HEADERS += rdlogin.h +} + +TRANSLATIONS += rdlogin_cs.ts +TRANSLATIONS += rdlogin_de.ts +TRANSLATIONS += rdlogin_es.ts +TRANSLATIONS += rdlogin_fr.ts +TRANSLATIONS += rdlogin_nb.ts +TRANSLATIONS += rdlogin_nn.ts +TRANSLATIONS += rdlogin_pt_BR.ts diff --git a/rdlogin/rdlogin_cs.ts b/rdlogin/rdlogin_cs.ts new file mode 100644 index 00000000..5e5f73bd --- /dev/null +++ b/rdlogin/rdlogin_cs.ts @@ -0,0 +1,55 @@ + + + MainWidget + + RDLogin - Station: + RDLogin - Stanice: + + + rdlogin : + rdlogin : + + + Can't Connect + Nelze spojit + + + Current User: unknown + Nynější uživatel: neznámý + + + &Username: + &Uživatelské jméno: + + + &Password: + He&slo: + + + &Set User + &Nastavit uživatele + + + &Default +User + &Výchozí +uživatel + + + &Cancel + Z&rušit + + + Current User: + Nynější uživatel: + + + RDLogin + RDLogin + + + Invalid Password! + Ungültiges Paßwort! + + + diff --git a/rdlogin/rdlogin_de.ts b/rdlogin/rdlogin_de.ts new file mode 100644 index 00000000..5996ab9b --- /dev/null +++ b/rdlogin/rdlogin_de.ts @@ -0,0 +1,54 @@ + + + MainWidget + + RDLogin - Station: + RDLogin - Station: + + + rdlogin : + rdlogin : + + + Can't Connect + Kann nicht verbinden + + + Current User: unknown + Derzeitiger Nutzer: unbekannt + + + &Username: + Ben&utzername: + + + &Password: + &Paßwort: + + + &Set User + Benutzer &Setzen + + + &Default +User + Stan&dardbenutzer + + + &Cancel + Abbre&chen + + + Current User: + Derzeitiger Benutzer: + + + RDLogin + RDLogin + + + Invalid Password! + Ungültiges Paßwort! + + + diff --git a/rdlogin/rdlogin_es.ts b/rdlogin/rdlogin_es.ts new file mode 100644 index 00000000..28a609e5 --- /dev/null +++ b/rdlogin/rdlogin_es.ts @@ -0,0 +1,55 @@ + + + MainWidget + + RDLogin - Station: + RDLogin - Estación: + + + Can't Connect + No puedo conectarme + + + Current User: + Usuario actual: + + + RDLogin + RDLogin + + + &Set User + &Asignar Usuario + + + &Default +User + Usuario por +&Omisión + + + Invalid Password! + ¡Contraseña inválida! + + + &Cancel + &Cancelar + + + Current User: unknown + Usuario actual: desconocido + + + &Username: + &Usuario: + + + &Password: + &Contraseña: + + + rdlogin : + rdlogin : + + + diff --git a/rdlogin/rdlogin_fr.ts b/rdlogin/rdlogin_fr.ts new file mode 100644 index 00000000..de8c5818 --- /dev/null +++ b/rdlogin/rdlogin_fr.ts @@ -0,0 +1,54 @@ + + + MainWidget + + RDLogin - Station: + + + + rdlogin : + + + + Can't Connect + + + + Current User: unknown + + + + &Username: + + + + &Password: + + + + &Set User + + + + &Default +User + + + + &Cancel + + + + Current User: + + + + RDLogin + + + + Invalid Password! + + + + diff --git a/rdlogin/rdlogin_nb.ts b/rdlogin/rdlogin_nb.ts new file mode 100644 index 00000000..1564395c --- /dev/null +++ b/rdlogin/rdlogin_nb.ts @@ -0,0 +1,55 @@ + + + MainWidget + + RDLogin - Station: + RDLogin - stasjon: + + + rdlogin : + rdlogin: + + + Can't Connect + Greier ikkje kopla til + + + Current User: unknown + Brukarnamn no: ukjent + + + &Username: + Br&ukarnamn + + + &Password: + &Passord: + + + &Set User + &Set brukar + + + &Default +User + Stan&dard- +brukar + + + &Cancel + &Avbryt + + + Current User: + Brukarnamn no: + + + RDLogin + RDLogin + + + Invalid Password! + Ugyldig passord! + + + diff --git a/rdlogin/rdlogin_nn.ts b/rdlogin/rdlogin_nn.ts new file mode 100644 index 00000000..1564395c --- /dev/null +++ b/rdlogin/rdlogin_nn.ts @@ -0,0 +1,55 @@ + + + MainWidget + + RDLogin - Station: + RDLogin - stasjon: + + + rdlogin : + rdlogin: + + + Can't Connect + Greier ikkje kopla til + + + Current User: unknown + Brukarnamn no: ukjent + + + &Username: + Br&ukarnamn + + + &Password: + &Passord: + + + &Set User + &Set brukar + + + &Default +User + Stan&dard- +brukar + + + &Cancel + &Avbryt + + + Current User: + Brukarnamn no: + + + RDLogin + RDLogin + + + Invalid Password! + Ugyldig passord! + + + diff --git a/rdlogin/rdlogin_pt_BR.ts b/rdlogin/rdlogin_pt_BR.ts new file mode 100644 index 00000000..59bae6dd --- /dev/null +++ b/rdlogin/rdlogin_pt_BR.ts @@ -0,0 +1,56 @@ + + + MainWidget + + RDLogin - Station: + RDLogin - Estação: + + + rdlogin : + rdlogin : + + + Can't Connect + Não foi possível conectar + + + Current User: unknown + Usuário atual: Desconhecido + + + &Username: + &Usuário: + + + &Password: + &Senha: + + + &Set User + &Escolher +Usuário + + + &Default +User + &Usuário +Padrão + + + &Cancel + &Cancelar + + + Current User: + Usuário Atual: + + + RDLogin + RDLogin + + + Invalid Password! + Senha Inválida! + + + diff --git a/rdlogmanager/Makefile.am b/rdlogmanager/Makefile.am new file mode 100644 index 00000000..126c4b19 --- /dev/null +++ b/rdlogmanager/Makefile.am @@ -0,0 +1,124 @@ +## automake.am +## +## Automake.am for rivendell/rdlogmanager +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.39.8.4 2013/01/01 21:36:31 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdlogmanager_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rdlogmanager_*.qm + +all: + @QT_BIN@/lupdate rdlogmanager.pro + @QT_BIN@/lrelease rdlogmanager.pro + +bin_PROGRAMS = rdlogmanager + +dist_rdlogmanager_SOURCES = add_clock.cpp add_clock.h\ + add_event.cpp add_event.h\ + clock_listview.cpp clock_listview.h\ + commandline_ops.cpp globals.h\ + edit_clock.cpp edit_clock.h\ + edit_event.cpp edit_event.h\ + edit_eventline.cpp edit_eventline.h\ + edit_grid.cpp edit_grid.h\ + edit_note.cpp edit_note.h\ + edit_perms.cpp edit_perms.h\ + edit_schedrules.cpp edit_schedrules.h\ + edit_schedcoderules.cpp edit_schedcoderules.h\ + edit_track.cpp edit_track.h\ + generate_log.cpp generate_log.h\ + import_listview.cpp import_listview.h\ + lib_listview.cpp lib_listview.h\ + list_clocks.cpp list_clocks.h\ + list_events.cpp list_events.h\ + list_grids.cpp list_grids.h\ + list_svcs.cpp list_svcs.h\ + pick_report_dates.cpp pick_report_dates.h\ + rdlogmanager.cpp rdlogmanager.h\ + rename_item.cpp rename_item.h\ + svc_rec.cpp svc_rec.h\ + svc_rec_dialog.cpp svc_rec_dialog.h + +nodist_rdlogmanager_SOURCES = moc_add_clock.cpp\ + moc_add_event.cpp\ + moc_clock_listview.cpp\ + moc_edit_clock.cpp\ + moc_edit_event.cpp\ + moc_edit_eventline.cpp\ + moc_edit_grid.cpp\ + moc_edit_note.cpp\ + moc_edit_perms.cpp\ + moc_edit_schedrules.cpp\ + moc_edit_schedcoderules.cpp\ + moc_edit_track.cpp\ + moc_generate_log.cpp\ + moc_import_listview.cpp\ + moc_lib_listview.cpp\ + moc_list_clocks.cpp\ + moc_list_events.cpp\ + moc_list_grids.cpp\ + moc_list_svcs.cpp\ + moc_pick_report_dates.cpp\ + moc_rdlogmanager.cpp\ + moc_rename_item.cpp\ + moc_svc_rec.cpp\ + moc_svc_rec_dialog.cpp + +rdlogmanager_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdlogmanager.pro\ + rdlogmanager_cs.ts\ + rdlogmanager_de.ts\ + rdlogmanager_es.ts\ + rdlogmanager_fr.ts\ + rdlogmanager_nb.ts\ + rdlogmanager_nn.ts\ + rdlogmanager_pt_BR.ts + +CLEANFILES = *~\ + *.exe\ + *.idb\ + *ilk\ + *.qm\ + *.obj\ + *.pdb\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/rdlogmanager/add_clock.cpp b/rdlogmanager/add_clock.cpp new file mode 100644 index 00000000..be4a4470 --- /dev/null +++ b/rdlogmanager/add_clock.cpp @@ -0,0 +1,172 @@ +// add_clock.cpp +// +// Add a Rivendell Service +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: add_clock.cpp,v 1.13.8.1 2012/04/23 17:22:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +AddClock::AddClock(QString *logname,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + clock_name=logname; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Add Log Clock")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Create Validators + // + RDTextValidator *validator=new RDTextValidator(); + validator->addBannedChar('('); + validator->addBannedChar(')'); + validator->addBannedChar('!'); + validator->addBannedChar('@'); + validator->addBannedChar('#'); + validator->addBannedChar('$'); + validator->addBannedChar('%'); + validator->addBannedChar('^'); + validator->addBannedChar('&'); + validator->addBannedChar('*'); + validator->addBannedChar('{'); + validator->addBannedChar('}'); + validator->addBannedChar('['); + validator->addBannedChar(']'); + validator->addBannedChar(':'); + validator->addBannedChar(';'); + validator->addBannedChar(34); + validator->addBannedChar('<'); + validator->addBannedChar('>'); + validator->addBannedChar('.'); + validator->addBannedChar(','); + validator->addBannedChar('\\'); + validator->addBannedChar('-'); + validator->addBannedChar('_'); + validator->addBannedChar('/'); + validator->addBannedChar('+'); + validator->addBannedChar('='); + validator->addBannedChar('~'); + validator->addBannedChar('?'); + validator->addBannedChar('|'); + + // + // Clock Name + // + clock_name_edit=new QLineEdit(this,"clock_name_edit"); + clock_name_edit->setGeometry(145,11,sizeHint().width()-155,19); + clock_name_edit->setMaxLength(58); // MySQL limitation! + clock_name_edit->setValidator(validator); + QLabel *clock_name_label=new QLabel(clock_name_edit,tr("&New Clock Name:"), + this,"clock_name_label"); + clock_name_label->setGeometry(10,11,130,19); + clock_name_label->setFont(font); + clock_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + clock_name_edit->setText(*clock_name); + clock_name_edit->selectAll(); +} + + +AddClock::~AddClock() +{ + delete clock_name_edit; +} + + +QSize AddClock::sizeHint() const +{ + return QSize(400,105); +} + + +QSizePolicy AddClock::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddClock::okData() +{ + *clock_name=clock_name_edit->text(); + done(0); +} + + +void AddClock::cancelData() +{ + done(-1); +} + + +void AddClock::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/rdlogmanager/add_clock.h b/rdlogmanager/add_clock.h new file mode 100644 index 00000000..5d3be5d8 --- /dev/null +++ b/rdlogmanager/add_clock.h @@ -0,0 +1,60 @@ +// add_clock.h +// +// Add a Rivendell Log Manager Clock +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: add_clock.h,v 1.5.8.1 2012/04/23 17:22:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_CLOCK_H +#define ADD_CLOCK_H + +#include +#include +#include +#include +#include +#include +#include + +#include + + +class AddClock : public QDialog +{ + Q_OBJECT + public: + AddClock(QString *logname,QWidget *parent=0,const char *name=0); + ~AddClock(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + QLineEdit *clock_name_edit; + QString *clock_name; +}; + + +#endif + diff --git a/rdlogmanager/add_event.cpp b/rdlogmanager/add_event.cpp new file mode 100644 index 00000000..c3f337f8 --- /dev/null +++ b/rdlogmanager/add_event.cpp @@ -0,0 +1,174 @@ +// add_event.cpp +// +// Add a Rivendell Service +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: add_event.cpp,v 1.13.8.1 2012/04/23 17:22:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +AddEvent::AddEvent(QString *logname,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + event_name=logname; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Add Log Event")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Create Validators + // + RDTextValidator *validator=new RDTextValidator(); + validator->addBannedChar('('); + validator->addBannedChar(')'); + validator->addBannedChar('!'); + validator->addBannedChar('@'); + validator->addBannedChar('#'); + validator->addBannedChar('$'); + validator->addBannedChar('%'); + validator->addBannedChar('^'); + validator->addBannedChar('&'); + validator->addBannedChar('*'); + validator->addBannedChar('{'); + validator->addBannedChar('}'); + validator->addBannedChar('['); + validator->addBannedChar(']'); + validator->addBannedChar(':'); + validator->addBannedChar(';'); + validator->addBannedChar(34); + validator->addBannedChar('<'); + validator->addBannedChar('>'); + validator->addBannedChar('.'); + validator->addBannedChar(','); + validator->addBannedChar('\\'); + validator->addBannedChar('-'); + validator->addBannedChar('_'); + validator->addBannedChar('/'); + validator->addBannedChar('+'); + validator->addBannedChar('='); + validator->addBannedChar('~'); + validator->addBannedChar('?'); + validator->addBannedChar('|'); + + // + // Event Name + // + event_name_edit=new QLineEdit(this,"event_name_edit"); + event_name_edit->setGeometry(145,11,sizeHint().width()-155,19); + event_name_edit->setMaxLength(58); // MySQL limitation! + event_name_edit->setValidator(validator); + QLabel *event_name_label=new QLabel(event_name_edit,tr("&New Event Name:"), + this,"event_name_label"); + event_name_label->setGeometry(10,11,130,19); + event_name_label->setFont(font); + event_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + event_name_edit->setText(*event_name); + event_name_edit->selectAll(); +} + + +AddEvent::~AddEvent() +{ + delete event_name_edit; +} + + +QSize AddEvent::sizeHint() const +{ + return QSize(400,105); +} + + +QSizePolicy AddEvent::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void AddEvent::okData() +{ + *event_name=event_name_edit->text(); + done(0); +} + + +void AddEvent::cancelData() +{ + done(-1); +} + + +void AddEvent::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/rdlogmanager/add_event.h b/rdlogmanager/add_event.h new file mode 100644 index 00000000..3b937348 --- /dev/null +++ b/rdlogmanager/add_event.h @@ -0,0 +1,60 @@ +// add_event.h +// +// Add a Rivendell Log Manager Event +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: add_event.h,v 1.5.8.1 2012/04/23 17:22:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ADD_EVENT_H +#define ADD_EVENT_H + +#include +#include +#include +#include +#include +#include +#include + +#include + + +class AddEvent : public QDialog +{ + Q_OBJECT + public: + AddEvent(QString *logname,QWidget *parent=0,const char *name=0); + ~AddEvent(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + QLineEdit *event_name_edit; + QString *event_name; +}; + + +#endif + diff --git a/rdlogmanager/clock_listview.cpp b/rdlogmanager/clock_listview.cpp new file mode 100644 index 00000000..ffb276b2 --- /dev/null +++ b/rdlogmanager/clock_listview.cpp @@ -0,0 +1,82 @@ +// clock_listview.cpp +// +// The Clock Carts ListView widget for RDLogManager. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: clock_listview.cpp,v 1.7.10.1 2014/06/02 22:26:19 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include +#include + +#include + +#include +#include + + +ClockListView::ClockListView(QWidget *parent,const char *name) + : RDListView(parent,name) +{ + clock_parent=parent; + + // + // Right Button Menu + // + clock_menu=new QPopupMenu(this,"clock_menu"); + connect(clock_menu,SIGNAL(aboutToShow()),this,SLOT(aboutToShowData())); + clock_menu-> + insertItem(tr("Edit Event"),this,SLOT(editEventData()),0,0); +} + + +void ClockListView::aboutToShowData() +{ + clock_menu->setItemEnabled(0,(clock_menu_item!=NULL)&& + (!clock_menu_item->text(4).isEmpty())); +} + + +void ClockListView::editEventData() +{ + emit editLine(clock_menu_item->text(4).toInt()); +} + + +void ClockListView::contentsMousePressEvent(QMouseEvent *e) +{ + QListView::contentsMousePressEvent(e); + clock_menu_item=(RDListViewItem *)selectedItem(); + switch(e->button()) { + case QMouseEvent::RightButton: + clock_menu->setGeometry(clock_parent->geometry().x()+ + geometry().x()+e->pos().x()+2, + clock_parent->geometry().y()+ + geometry().y()+e->pos().y()+ + header()->geometry().height()+2- + contentsY(), + clock_menu->sizeHint().width(), + clock_menu->sizeHint().height()); + clock_menu->exec(); + break; + + default: + e->ignore(); + break; + } +} diff --git a/rdlogmanager/clock_listview.h b/rdlogmanager/clock_listview.h new file mode 100644 index 00000000..f8191aa5 --- /dev/null +++ b/rdlogmanager/clock_listview.h @@ -0,0 +1,58 @@ +// clock_listview.h +// +// The Clock ListView widget for RDLogManager. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: clock_listview.h,v 1.5 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef CLOCK_LISTVIEW_H +#define CLOCK_LISTVIEW_H + +#include +#include +#include + +#include +#include + +class ClockListView : public RDListView +{ + Q_OBJECT + + public: + ClockListView(QWidget *parent,const char *name=0); + + signals: + void editLine(int count); + + private slots: + void aboutToShowData(); + void editEventData(); + + protected: + void contentsMousePressEvent(QMouseEvent *e); + + private: + QPopupMenu *clock_menu; + RDListViewItem *clock_menu_item; + QWidget *clock_parent; +}; + + +#endif // CLOCK_LISTVIEW_H diff --git a/rdlogmanager/commandline_ops.cpp b/rdlogmanager/commandline_ops.cpp new file mode 100644 index 00000000..bb259422 --- /dev/null +++ b/rdlogmanager/commandline_ops.cpp @@ -0,0 +1,261 @@ +// commandline_ops.cpp +// +// Command Line Operations for RDLogManager +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: commandline_ops.cpp,v 1.1.2.6.2.1 2014/05/20 14:01:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +int RunLogOperation(int argc,char *argv[],const QString &svcname, + int start_offset,bool protect_existing,bool gen_log, + bool merge_mus,bool merge_tfc) +{ + QString sql; + RDSqlQuery *q; + QString report; + QString unused_report; + QString svcname_table=svcname; + svcname_table.replace(" ","_"); + unsigned schema=0; + + QApplication a(argc,argv,false); + + // + // Load Local Configs + // + RDConfig *config=new RDConfig(); + config->load(); + + // + // Open Database + // + QString err; + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + fprintf(stderr,"rdlogmanager: unable to connect to database\n"); + return 256; + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr, + "rdlogmanager: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + + // + // Some Basic Structures + // + rdstation_conf=new RDStation(config->stationName()); +#ifndef WIN32 + rduser=new RDUser(rdstation_conf->defaultName()); +#endif // WIN32 + RDSvc *svc=new RDSvc(svcname); + if(!svc->exists()) { + fprintf(stderr,"rdlogmanager: no such service\n"); + return 256; + } + QDate start_date=QDate::currentDate().addDays(1+start_offset); + QString logname=RDDateDecode(svc->nameTemplate(),start_date); + RDLog *log=new RDLog(logname); + + // + // Generate Log + // + if(gen_log) { + if(protect_existing&&log->exists()) { + fprintf(stderr,"log \"%s\" already exists\n", + (const char *)log->name().utf8()); + exit(256); + } + log->removeTracks(rdstation_conf,rduser,config); + srand(QTime::currentTime().msec()); + sql=RDCreateStackTableSql(svcname_table); + q=new RDSqlQuery(sql); + if(!q->isActive()) { + fprintf(stderr,"SQL: %s\n",(const char *)sql); + fprintf(stderr,"SQL Error: %s\n", + (const char *)q->lastError().databaseText()); + } + delete q; + if(!svc->generateLog(start_date, + RDDateDecode(svc->nameTemplate(),start_date), + RDDateDecode(svc->nameTemplate(),start_date.addDays(1)), + &unused_report)) { + fprintf(stderr,"rdlogmanager: unable to generate log\n"); + return 256; + } + log->updateTracks(); + + // + // Generate Exception Report + // + RDLogEvent *event= + new RDLogEvent(QString().sprintf("%s_LOG",(const char *)logname)); + event->load(); + if((event->validate(&report,start_date)!=0)|| + (!unused_report.isEmpty())) { + printf("%s\n\n%s",(const char*)report,(const char*)unused_report); + } + delete event; + } + + // + // Merge Music + // + if(merge_mus) { + if(!log->exists()) { + fprintf(stderr,"rdlogmanager: log does not exist\n"); + return 256; + } + if(protect_existing&& + (log->linkState(RDLog::SourceMusic)==RDLog::LinkDone)) { + fprintf(stderr,"rdlogmanager: music for log \"%s\" is already imported\n", + (const char *)log->name().utf8()); + return 256; + } + report=""; + log->removeTracks(rdstation_conf,rduser,config); + svc->clearLogLinks(RDSvc::Traffic,start_date,logname); + svc->clearLogLinks(RDSvc::Music,start_date,logname); + if(svc->linkLog(RDSvc::Music,start_date,logname,&report)) { + printf("%s\n",(const char*)report); + } + else { + fprintf(stderr, + "rdlogmanager: unable to open music schedule file at \"%s\"\n", + (const char *)svc->importFilename(RDSvc::Music,start_date)); + exit(256); + } + } + + // + // Merge Traffic + // + if(merge_tfc) { + if(!log->exists()) { + fprintf(stderr,"rdlogmanager: log does not exist\n"); + return 256; + } + if(protect_existing&& + (log->linkState(RDLog::SourceTraffic)==RDLog::LinkDone)) { + fprintf(stderr, + "rdlogmanager: traffic for log \"%s\" is already imported\n", + (const char *)log->name().utf8()); + return 256; + } + report=""; + svc->clearLogLinks(RDSvc::Traffic,start_date,logname); + if(svc->linkLog(RDSvc::Traffic,start_date,logname,&report)) { + printf("%s\n",(const char*)report); + } + else { + fprintf(stderr, + "rdlogmanager: unable to open traffic schedule file at \"%s\"\n", + (const char *)svc->importFilename(RDSvc::Traffic,start_date)); + } + } + + // + // Clean Up + // + delete log; + delete svc; + return 0; +} + + +int RunReportOperation(int argc,char *argv[],const QString &rptname, + bool protect_existing,int start_offset,int end_offset) +{ + unsigned schema=0; + QString out_path; + + QApplication a(argc,argv,false); + + if(end_offsetload(); + + // + // Open Database + // + QString err; + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + fprintf(stderr,"rdlogmanager: unable to connect to database\n"); + return 256; + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr, + "rdlogmanager: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + rdstation_conf=new RDStation(config->stationName()); + + // + // Open Report Generator + // + RDReport *report=new RDReport(rptname); + if(!report->exists()) { + fprintf(stderr,"rdlogmanager: no such report\n"); + return 256; + } + + // + // Generate Report + // + QDate yesterday=QDate::currentDate().addDays(-1); + if(protect_existing&&report->outputExists(yesterday.addDays(start_offset))) { + fprintf(stderr,"report \"%s\" for %s already exists\n", + (const char *)rptname.utf8(), + (const char *)yesterday.addDays(start_offset).toString()); + exit(256); + } + if(!report->generateReport(yesterday.addDays(start_offset), + yesterday.addDays(end_offset),rdstation_conf, + &out_path)) { + fprintf(stderr,"rdlogmanager: report generation failed [%s]\n", + (const char *)RDReport::errorText(report->errorCode())); + return 256; + } + return 0; +} diff --git a/rdlogmanager/edit_clock.cpp b/rdlogmanager/edit_clock.cpp new file mode 100644 index 00000000..2b5ef7b5 --- /dev/null +++ b/rdlogmanager/edit_clock.cpp @@ -0,0 +1,767 @@ +// edit_clock.cpp +// +// Edit Rivendell Log Clock +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_clock.cpp,v 1.27.10.1 2014/06/24 18:27:05 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +EditClock::EditClock(QString clockname,bool new_clock, + std::vector *new_clocks, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString str; + + str=QString(tr("Edit Clock:")); + setCaption(QString().sprintf("%s %s",(const char *)str, + (const char *)clockname)); + edit_name=clockname; + edit_new_clock=new_clock; + edit_new_clocks=new_clocks; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + edit_title_font=new QFont("Helvetica",24,QFont::Bold); + edit_title_font->setPixelSize(24); + edit_title_metrics=new QFontMetrics(*edit_title_font); + + // + // Clock Names + // + edit_clockname_label=new QLabel(clockname,this,"edit_clockname_label"); + edit_clockname_label->setGeometry(10,10,280,20); + edit_clockname_label->setFont(bold_font); + edit_shortname_edit=new QLineEdit(this,"edit_shortname_edit"); + edit_shortname_edit->setGeometry(350,10,40,20); + edit_shortname_edit->setMaxLength(3); + QLabel *label=new QLabel(edit_shortname_edit,tr("Code:"), + this,"edit_shortname_label"); + label->setGeometry(295,10,50,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Clock List + // + edit_clocks_list=new ClockListView(this,"edit_clocks_list"); + edit_clocks_list->setGeometry(10,35,CENTER_LINE-20,sizeHint().height()-250); + edit_clocks_list->setAllColumnsShowFocus(true); + edit_clocks_list->setItemMargin(5); + edit_clocks_list->addColumn(tr("Start")); + edit_clocks_list->addColumn(tr("End")); + edit_clocks_list->addColumn(tr("Event")); + edit_clocks_list->addColumn(tr("Length")); + edit_clocks_list->setColumnAlignment(3,AlignRight); + edit_clocks_list->addColumn(tr("Count")); + edit_clocks_list->setColumnAlignment(4,AlignCenter); + connect(edit_clocks_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this,SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + connect(edit_clocks_list,SIGNAL(selectionChanged(QListViewItem *)), + this,SLOT(selectionChangedData(QListViewItem *))); + connect(edit_clocks_list,SIGNAL(editLine(int)), + this,SLOT(editEventData(int))); + + // + // Add Button + // + QPushButton *button=new QPushButton(this,"add_button"); + button->setGeometry(70,sizeHint().height()-210,80,50); + button->setFont(bold_font); + button->setText(tr("&Add")); + connect(button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + button=new QPushButton(this,"edit_button"); + button->setGeometry(160,sizeHint().height()-210,80,50); + button->setFont(bold_font); + button->setText(tr("&Edit")); + connect(button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + button=new QPushButton(this,"delete_button"); + button->setGeometry(250,sizeHint().height()-210,80,50); + button->setFont(bold_font); + button->setText(tr("&Delete")); + connect(button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Remarks + // + edit_remarks_edit=new QTextEdit(this,"edit_remarks_edit"); + edit_remarks_edit->setGeometry(10,sizeHint().height()-140,CENTER_LINE-20,130); + edit_remarks_edit->setTextFormat(QTextEdit::PlainText); + label=new QLabel(edit_remarks_edit,tr("Remarks"),this,"edit_remarks_label"); + label->setGeometry(15,sizeHint().height()-155,CENTER_LINE-20,15); + label->setFont(bold_font); + label->setAlignment(AlignLeft|AlignVCenter); + + // + // Scheduler-Rules button + // + button=new QPushButton(this,"schedrules_button"); + button->setGeometry(CENTER_LINE+20,sizeHint().height()-60,70,50); + button->setFont(bold_font); + button->setText(tr("Scheduler\nRules")); + connect(button,SIGNAL(clicked()),this,SLOT(schedRules())); + + // + // Save Button + // + button=new QPushButton(this,"save_button"); + button->setGeometry(CENTER_LINE+110,sizeHint().height()-60,70,50); + button->setFont(bold_font); + button->setText(tr("&Save")); + connect(button,SIGNAL(clicked()),this,SLOT(saveData())); + + // + // Save As Button + // + button=new QPushButton(this,"saveas_button"); + button->setGeometry(CENTER_LINE+190,sizeHint().height()-60,70,50); + button->setFont(bold_font); + button->setText(tr("Save &As")); + connect(button,SIGNAL(clicked()),this,SLOT(saveAsData())); + + // + // Service Associations Button + // + button=new QPushButton(this,"svc_button"); + button->setGeometry(CENTER_LINE+(sizeHint().width()-CENTER_LINE)/2-25, + sizeHint().height()-60,70,50); + button->setFont(bold_font); + button->setText(tr("&Services\nList")); + connect(button,SIGNAL(clicked()),this,SLOT(svcData())); + + // + // Color Button + // + edit_color_button=new QPushButton(this,"edit_color_button"); + edit_color_button-> + setGeometry(CENTER_LINE+(sizeHint().width()-CENTER_LINE)/2+55, + sizeHint().height()-60,70,50); + edit_color_button->setFont(bold_font); + edit_color_button->setText(tr("Colo&r")); + connect(edit_color_button,SIGNAL(clicked()),this,SLOT(colorData())); + + // + // Clock Display + // + edit_clock_label=new QLabel(this,"edit_clock_label"); + edit_clock_label-> + setGeometry(CENTER_LINE+10,10, + sizeHint().width()-CENTER_LINE-20,sizeHint().height()-80); + + // + // OK Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-160,sizeHint().height()-60,70,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-80,sizeHint().height()-60,70,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Data + // + sched_rules_list = new SchedRulesList(clockname); + edit_clock=new RDClock(); + edit_clock->setName(clockname); + edit_clock->load(); + edit_shortname_edit->setText(edit_clock->shortName()); + if(edit_clock->color().isValid()) { + edit_color_button-> + setPalette(QPalette(edit_clock->color(),backgroundColor())); + } + edit_remarks_edit->setText(edit_clock->remarks()); + edit_modified=false; + RefreshList(); +} + + +QSize EditClock::sizeHint() const +{ + return QSize(1024,698); +} + + +QSizePolicy EditClock::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditClock::selectionChangedData(QListViewItem *l) +{ + if(l==NULL) { + UpdateClock(); + return; + } + RDListViewItem *item=(RDListViewItem *)l; + if(item->text(3).isEmpty()) { + UpdateClock(); + return; + } + UpdateClock(item->text(4).toInt()); +} + + +void EditClock::addData() +{ + int line=0; + RDEventLine eventline; + + RDListViewItem *item=(RDListViewItem *)edit_clocks_list->selectedItem(); + if(item!=NULL) { + if(item->text(4).isEmpty()) { + line=edit_clock->size(); + } + else { + line=item->text(4).toInt(); + } + } + EditEventLine *edit_eventline=new EditEventLine(&eventline,edit_clock,-1, + this,"edit_eventline"); + if(edit_eventline->exec()<0) { + return; + } + delete edit_eventline; + edit_clock->insert(eventline.name(),line); + edit_clock->eventLine(line)->setStartTime(eventline.startTime()); + edit_clock->eventLine(line)->setLength(eventline.length()); + edit_clock->eventLine(line)->load(); + edit_modified=true; + RefreshList(line); +} + + +void EditClock::editData() +{ + RDListViewItem *item=(RDListViewItem *)edit_clocks_list->selectedItem(); + if(item==NULL) { + return; + } + if(item->text(4).isEmpty()) { + return; + } + int line=item->text(4).toInt(); + line=item->text(4).toInt(); + EditEventLine *edit_eventline=new EditEventLine(edit_clock->eventLine(line), + edit_clock,line, + this,"edit_eventline"); + if(edit_eventline->exec()<0) { + delete edit_eventline; + return; + } + delete edit_eventline; + edit_clock->eventLine(line)->load(); + edit_modified=true; + RefreshList(); +} + + +void EditClock::deleteData() +{ + QString str; + + RDListViewItem *item=(RDListViewItem *)edit_clocks_list->selectedItem(); + if(item==NULL) { + return; + } + if(item->text(4).isEmpty()) { + return; + } + str=QString(tr("Are you sure you want to\ndelete")); + if(QMessageBox::question(this,tr("Delete Event"), + QString().sprintf("%s \'%s\'?",(const char *)str, + (const char *)item->text(3)), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + return; + } + edit_clock->remove(item->text(4).toInt()); + edit_modified=true; + RefreshList(); +} + + +void EditClock::schedRules() +{ + unsigned edit_artistsep = edit_clock->getArtistSep(); + QString clock_name = edit_clock->name(); + bool rules_modified = edit_clock->getRulesModified(); + + EditSchedRules *dialog=new EditSchedRules(clock_name,&edit_artistsep,sched_rules_list,&rules_modified,this,"dialog"); + dialog->exec(); + + if (edit_clock->getArtistSep()!=edit_artistsep) + { + edit_modified=true; + } + edit_clock->setArtistSep(edit_artistsep); + + edit_clock->setRulesModified(rules_modified); + if(rules_modified) + { + edit_modified=true; + } + + delete dialog; +} + + +void EditClock::svcData() +{ + EditPerms *dialog=new EditPerms(edit_name,EditPerms::ObjectClock, + this,"dialog"); + dialog->exec(); + delete dialog; +} + + +void EditClock::saveData() +{ + if(!ValidateCode()) { + return; + } + Save(); + edit_new_clock=false; +} + + +void EditClock::saveAsData() +{ + QString clockname=edit_name; + QString sql; + RDSqlQuery *q; + QString str; + + if(!ValidateCode()) { + return; + } + QString old_name=edit_name; + if(edit_modified) { + switch(QMessageBox::question(this,tr("Clock Modified"), + tr("The clock has been modified.\nDo you want to save?"),QMessageBox::Yes,QMessageBox::No,QMessageBox::Cancel)) { + case QMessageBox::Yes: + Save(); + break; + + case QMessageBox::Cancel: + case QMessageBox::NoButton: + return; + break; + } + } + if(edit_shortname_edit->text().isEmpty()) { + QMessageBox::warning(this,tr("Missing Clock Code"), + tr("You must specify a clock code!")); + return; + } + sql= + QString().sprintf("select SHORT_NAME from CLOCKS where SHORT_NAME=\"%s\"", + (const char *) + RDEscapeString(edit_shortname_edit->text())); + q=new RDSqlQuery(sql); + if(q->first()) { + QMessageBox::warning(this,tr("Code Exists"), + tr("The clock code is already in use!")); + delete q; + return; + } + delete q; + + AddClock *addclock=new AddClock(&clockname,this,"addclock"); + if(addclock->exec()<0) { + delete addclock; + return; + } + delete addclock; + edit_name=clockname; + sql=QString().sprintf("select NAME from CLOCKS where NAME=\"%s\"", + (const char *)clockname); + q=new RDSqlQuery(sql); + if(q->first()) { + if(QMessageBox::question(this,tr("Clock Exists"), + tr("Clock already exists! Overwrite?"),QMessageBox::Yes,QMessageBox::No)!=QMessageBox::Yes) { + delete q; + return; + } + } + delete q; + edit_clock->setName(clockname); + sql=RDCreateClockTableSql(clockname); + q=new RDSqlQuery(sql); + delete q; + + + Save(); + edit_new_clocks->push_back(clockname); + CopyClockPerms(old_name,clockname); + if(edit_new_clock) { + AbandonClock(old_name); + } + edit_clockname_label->setText(clockname); + UpdateClock(); + str=QString(tr("Edit Clock:")); + setCaption(QString().sprintf("%s %s",(const char *)str, + (const char *)edit_name)); +} + + +void EditClock::doubleClickedData(QListViewItem *item,const QPoint &,int) +{ + editData(); +} + + +void EditClock::colorData() +{ + QColor color=QColorDialog::getColor(edit_color_button->backgroundColor(), + this,"color_dialog"); + if(color.isValid()) { + edit_color_button->setPalette(QPalette(color,backgroundColor())); + } +} + + +void EditClock::editEventData(int line) +{ + std::vector new_events; + + RDEventLine *event=edit_clock->eventLine(line); + if(event==NULL) { + return; + } + EditEvent *dialog=new EditEvent(event->name(),false,&new_events, + this,"dialog"); + if(dialog->exec()<-1) { + delete dialog; + return; + } + delete dialog; + RefreshNames(); +} + + +void EditClock::okData() +{ + if(!ValidateCode()) { + return; + } + Save(); + done(0); +} + + +void EditClock::cancelData() +{ + if(edit_modified) { + switch(QMessageBox::question(this,tr("Clock Modified"), + tr("The clock has been modified.\nDo you want to save?"),QMessageBox::Yes,QMessageBox::No,QMessageBox::Cancel)) { + case QMessageBox::Yes: + Save(); + done(0); + break; + + case QMessageBox::No: + done(-1); + break; + + case QMessageBox::NoButton: + return; + } + } + else { + done(-1); + } +} + + +void EditClock::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->moveTo(CENTER_LINE,10); + p->lineTo(CENTER_LINE,sizeHint().height()-10); + + p->end(); +} + + +void EditClock::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void EditClock::Save() +{ + edit_clock->setColor(edit_color_button->backgroundColor()); + edit_clock->setShortName(edit_shortname_edit->text()); + edit_clock->setRemarks(edit_remarks_edit->text()); + edit_clock->save(); + if(edit_clock->getRulesModified()) + { + sched_rules_list->Save(edit_clock->name()); + edit_clock->setRulesModified(false); + } + edit_modified=false; +} + + +void EditClock::RefreshList(int select_line) +{ + UpdateClock(); + RDListViewItem *prev_item=(RDListViewItem *)edit_clocks_list->selectedItem(); + + if((prev_item!=NULL)&&(select_line>=0)) { + select_line=prev_item->text(4).toInt(); + } + RDListViewItem *item; + RDEventLine *eventline; + + edit_clocks_list->clear(); + item=new RDListViewItem(edit_clocks_list); + item->setText(2,tr("--- End of clock ---")); + for(int i=edit_clock->size()-1;i>=0;i--) { + if((eventline=edit_clock->eventLine(i))!=NULL) { + item=new RDListViewItem(edit_clocks_list); + item->setText(0,eventline->startTime().toString("mm:ss.zzz").left(7)); + item->setText(1,eventline->startTime(). + addMSecs(eventline->length()).toString("mm:ss.zzz"). + left(7)); + item->setText(3,RDGetTimeLength(eventline->length(),false,true)); + item->setText(2,QString().sprintf("%s [%s]", + (const char *)eventline->name(), + (const char *)eventline->properties())); + item->setText(4,QString().sprintf("%d",i)); + if(eventline->color().isValid()) { + item->setBackgroundColor(eventline->color()); + } + if(i==select_line) { + edit_clocks_list->setSelected(item,true); + } + } + } +} + + +void EditClock::RefreshNames() +{ + QString sql; + RDSqlQuery *q; + RDEventLine *eventline=NULL; + RDListViewItem *item=(RDListViewItem *)edit_clocks_list->firstChild(); + while(item!=NULL) { + if(!item->text(4).isEmpty()) { + if((eventline=edit_clock->eventLine(item->text(4).toInt()))!=NULL) { + sql=QString().sprintf("select PROPERTIES from EVENTS\ + where NAME=\"%s\"", + (const char *)RDEscapeString(eventline->name())); + q=new RDSqlQuery(sql); + if(q->next()) { + item-> + setText(2,QString().sprintf("%s [%s]", + (const char *)eventline->name(), + (const char *)q->value(0).toString())); + } + delete q; + } + } + item=(RDListViewItem *)item->nextSibling(); + } +} + + +void EditClock::UpdateClock(int line) +{ + QPixmap *map=new QPixmap(edit_clock_label->size()); + map->fill(); + QPainter *p=new QPainter(); + p->begin(map); + p->setPen(QColor(black)); + p->setBrush(QColor(black)); + p->setFont(*edit_title_font); + + // + // Title + // + p->drawText((edit_clock_label->size().width()- + edit_title_metrics->width(edit_clock->name()))/2, + 50,edit_clock->name()); + + // + // Pie Circle + // + p->translate(edit_clock_label->size().width()/2, + edit_clock_label->size().height()/2); + p->rotate(-90.0); + int size_x=edit_clock_label->size().width()-2*PIE_X_MARGIN; + int size_y=edit_clock_label->size().width()-2*PIE_X_MARGIN; + p->drawArc(-size_x/2,-size_y/2,size_x,size_y,0,5760); + + // + // Segments + // + for(int i=0;isize();i++) { + if(i==line) { + p->setBrush(edit_clocks_list->palette(). + color(QPalette::Active,QColorGroup::Highlight)); + p->drawPie(-size_x/2,-size_y/2,size_x,size_y, + -QTime().secsTo(edit_clock->eventLine(line)->startTime())*5760/3600, + -(edit_clock->eventLine(line)->length()/1000)*5760/3600); + } + else { + if(edit_clock->eventLine(i)->color().isValid()) { + p->setBrush(edit_clock->eventLine(i)->color()); + } + else { + p->setBrush(palette().color(QPalette::Active,QColorGroup::Base)); + } + p->drawPie(-size_x/2,-size_y/2,size_x,size_y, + -QTime().secsTo(edit_clock->eventLine(i)->startTime())*5760/3600, + -(edit_clock->eventLine(i)->length()/1000)*5760/3600); + } + } + p->end(); + delete p; + edit_clock_label->setPixmap(*map); + delete map; +} + + +void EditClock::CopyClockPerms(QString old_name,QString new_name) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + sql=QString().sprintf("select SERVICE_NAME from CLOCK_PERMS where\ + CLOCK_NAME=\"%s\"", + (const char *)RDEscapeString(old_name)); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into CLOCK_PERMS set\ + CLOCK_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *)RDEscapeString(new_name), + (const char *)RDEscapeString(q->value(0).toString())); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; +} + + +void EditClock::AbandonClock(QString name) +{ + if(name==edit_name) { + return; + } + QString sql=QString().sprintf("delete from CLOCKS where NAME=\"%s\"", + (const char *)name); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + + sql=QString("drop table `")+RDClock::tableName(name)+"`"; + q=new RDSqlQuery(sql); + delete q; +} + + +bool EditClock::ValidateCode() +{ + if(edit_shortname_edit->text().isEmpty()) { + QMessageBox::information(this,tr("Invalid Code"), + tr("You must provide a clock code!")); + return false; + } + RDSqlQuery *q= + new RDSqlQuery(QString(). + sprintf("select SHORT_NAME from CLOCKS\ + where (SHORT_NAME=\"%s\")&&\ + (NAME!=\"%s\")", + (const char *) + RDEscapeString(edit_shortname_edit->text()), + (const char *)RDEscapeString(edit_name))); + if(q->next()) { + QMessageBox::information(this,tr("Duplicate Code"), + tr("That code is already in use!")); + delete q; + return false; + } + delete q; + + return true; +} diff --git a/rdlogmanager/edit_clock.h b/rdlogmanager/edit_clock.h new file mode 100644 index 00000000..96baf8c8 --- /dev/null +++ b/rdlogmanager/edit_clock.h @@ -0,0 +1,104 @@ +// edit_clock.h +// +// Edit A Rivendell Log Clock +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_clock.h,v 1.14 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_CLOCK_H +#define EDIT_CLOCK_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +// +// Layout +// +#define CENTER_LINE 400 +#define PIE_X_MARGIN 100 +#define PIE_Y_MARGIN 125 + +class EditClock : public QDialog +{ + Q_OBJECT + public: + EditClock(QString clockname,bool new_clock,std::vector *new_clocks, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void selectionChangedData(QListViewItem *); + void addData(); + void editData(); + void deleteData(); + void svcData(); +// + void schedRules(); +// + void saveData(); + void saveAsData(); + void doubleClickedData(QListViewItem *,const QPoint &,int); + void colorData(); + void editEventData(int line); + void okData(); + void cancelData(); + + protected: + void paintEvent(QPaintEvent *e); + void closeEvent(QCloseEvent *e); + + private: + void Save(); + void RefreshList(int select_line=-1); + void RefreshNames(); + void UpdateClock(int line=-1); + void CopyClockPerms(QString old_name,QString new_name); + void AbandonClock(QString name); + bool ValidateCode(); + ClockListView *edit_clocks_list; + RDClock *edit_clock; + QPushButton *edit_color_button; + QLabel *edit_clockname_label; + QLineEdit *edit_shortname_edit; + QLabel *edit_clock_label; + QFont *edit_title_font; + QFontMetrics *edit_title_metrics; + bool edit_modified; + QString edit_name; + bool edit_new_clock; + std::vector *edit_new_clocks; + SchedRulesList* sched_rules_list; + QTextEdit *edit_remarks_edit; +}; + + +#endif + diff --git a/rdlogmanager/edit_event.cpp b/rdlogmanager/edit_event.cpp new file mode 100644 index 00000000..05029d9c --- /dev/null +++ b/rdlogmanager/edit_event.cpp @@ -0,0 +1,1673 @@ +// edit_event.cpp +// +// Edit a Rivendell Log Event +// +// (C) Copyright 2002-2004,2008 Fred Gleason +// +// $Id: edit_event.cpp,v 1.53.2.4.2.1 2014/06/24 18:27:06 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// +// Icons +// +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" + + +EditEvent::EditEvent(QString eventname,bool new_event, + std::vector *new_events, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString str; + + event_saved=false; + event_name=eventname; + event_new_event=new_event; + event_new_events=new_events; + event_event=new RDEvent(eventname); + str=QString(tr("Editing Event")); + setCaption(QString(). + sprintf("%s - %s",(const char *)str, + (const char *)event_event->name())); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",10,QFont::Bold); + bold_font.setPixelSize(10); + QFont font=QFont("Helvetica",10,QFont::Normal); + font.setPixelSize(10); + + // + // Create Icons + // + event_playout_map=new QPixmap(play_xpm); + event_macro_map=new QPixmap(rml5_xpm); + + // + // Library Section + // + // Text Filter + // + event_lib_filter_edit=new QLineEdit(this,"event_lib_filter_edit"); + event_lib_filter_edit->setGeometry(55,10,CENTER_LINE-70,14); + connect(event_lib_filter_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(filterChangedData(const QString &))); + QLabel *label=new QLabel(event_lib_filter_edit,tr("Filter:"), + this,"event_lib_filter_label"); + label->setFont(bold_font); + label->setGeometry(10,10,40,14); + label->setAlignment(AlignVCenter|AlignRight); + + // + // Group Filter + // + event_group_box=new QComboBox(this,"event_group_box"); + event_group_box->setGeometry(55,30,CENTER_LINE-70,18); + connect(event_group_box,SIGNAL(activated(const QString &)), + this,SLOT(filterActivatedData(const QString &))); + label=new QLabel(event_group_box,tr("Group:"), + this,"event_lib_filter_label"); + label->setFont(bold_font); + label->setGeometry(10,30,40,18); + label->setAlignment(AlignVCenter|AlignRight); + + // + // Type Filter + // + event_lib_type_group=new QButtonGroup(this,"cart_type_filter"); + event_lib_type_group->setExclusive(true); + event_lib_type_group->hide(); + connect(event_lib_type_group,SIGNAL(clicked(int)),this,SLOT(filterClickedData(int))); + + QRadioButton *rbutton=new QRadioButton(this,"all_button"); + rbutton->setGeometry(55,55,15,15); + event_lib_type_group->insert(rbutton); + label=new QLabel(rbutton,tr("All"),this,"all_button"); + label->setFont(bold_font); + label->setGeometry(75,55,30,15); + label->setAlignment(AlignVCenter|AlignLeft); + rbutton->setChecked(true); + + rbutton=new QRadioButton(this,"audio_button"); + rbutton->setGeometry(125,55,15,15); + event_lib_type_group->insert(rbutton); + label=new QLabel(rbutton,tr("Audio Only"),this,"audio_button_label"); + label->setFont(bold_font); + label->setGeometry(145,55,80,15); + label->setAlignment(AlignVCenter|AlignLeft); + + rbutton=new QRadioButton(this,"macro_button"); + rbutton->setGeometry(235,55,15,15); + event_lib_type_group->insert(rbutton); + label=new QLabel(rbutton,tr("Macros Only"),this,"macro_button_label"); + label->setFont(bold_font); + label->setGeometry(255,55,80,15); + label->setAlignment(AlignVCenter|AlignLeft); + + // + // Cart List + // + event_lib_list=new LibListView(this,"event_lib_list"); + event_lib_list->setGeometry(10,80,CENTER_LINE-20,sizeHint().height()-300); + event_lib_list->setAllColumnsShowFocus(true); + event_lib_list->setItemMargin(5); + event_lib_list->addColumn(""); + event_lib_list->addColumn(tr("CART")); + event_lib_list->addColumn(tr("GROUP")); + event_lib_list->addColumn(tr("LENGTH")); + event_lib_list->setColumnAlignment(3,AlignRight); + event_lib_list->addColumn(tr("TITLE")); + event_lib_list->addColumn(tr("ARTIST")); + event_lib_list->addColumn(tr("START")); + event_lib_list->addColumn(tr("END")); + event_lib_list->addColumn(tr("TYPE")); + connect(event_lib_list,SIGNAL(clicked(QListViewItem *)), + this,SLOT(cartClickedData(QListViewItem *))); + + // + // Empty Cart Source + // + event_empty_cart=new RDEmptyCart(this); + event_empty_cart->setGeometry(CENTER_LINE-227,sizeHint().height()-202,32,32); + + // + // Cart Player + // + QString sql; + RDSqlQuery *q; + event_player = NULL; +#ifndef WIN32 + sql=QString().sprintf("select OUTPUT_CARD,OUTPUT_PORT,START_CART,END_CART \ + from RDLOGEDIT where STATION=\"%s\"", + (const char *)rdstation_conf->name()); + q=new RDSqlQuery(sql); + if(q->first()) { + event_player= + new RDSimplePlayer(rdcae,rdripc,q->value(0).toInt(),q->value(1).toInt(), + q->value(2).toUInt(),q->value(3).toUInt(), + this,"event_player"); + event_player->playButton()-> + setGeometry(CENTER_LINE-180,sizeHint().height()-210,80,50); + event_player->stopButton()-> + setPalette(QPalette(backgroundColor(),QColor(lightGray))); + event_player->stopButton()->setGeometry(CENTER_LINE-90,sizeHint().height()-210,80,50); + event_player->stopButton()->setOnColor(red); + } + delete q; +#endif // WIN32 + + // + // Remarks + // + event_remarks_edit=new QTextEdit(this,"event_remarks_edit"); + event_remarks_edit-> + setGeometry(10,sizeHint().height()-150,CENTER_LINE-20,140); + event_remarks_edit->setTextFormat(QTextEdit::PlainText); + label=new QLabel(event_remarks_edit,tr("REMARKS"),this,"event_remarks_label"); + label->setFont(bold_font); + label->setGeometry(15,sizeHint().height()-165,100,15); + label->setAlignment(AlignVCenter|AlignLeft); + + // + // Load Group List + // + sql="select NAME from GROUPS order by NAME"; + q=new RDSqlQuery(sql); + event_group_box->insertItem(tr("ALL")); + while(q->next()) { + event_group_box->insertItem(q->value(0).toString()); + } + delete q; + + RefreshLibrary(); + + // + // Pre-Position Log Section + // + event_position_header=new QLabel(tr("PRE-POSITION LOG"), + this,"event_position_header"); + event_position_header->setFont(bold_font); + event_position_header->setGeometry(CENTER_LINE+15,10,200,16); + + event_position_box=new QCheckBox(this,"event_position_box"); + event_position_box->setGeometry(CENTER_LINE+15,27,15,22); + connect(event_position_box,SIGNAL(toggled(bool)), + this,SLOT(prepositionToggledData(bool))); + event_position_label=new QLabel(event_position_box,tr("Cue to this event"), + this,"event_position_label"); + event_position_label->setFont(bold_font); + event_position_label->setGeometry(CENTER_LINE+35,27,150,22); + event_position_label->setAlignment(AlignVCenter|AlignLeft); + event_position_edit=new QTimeEdit(this,"event_position_edit"); + event_position_edit->setGeometry(CENTER_LINE+144,26,60,22); + event_position_edit->setDisplay(QTimeEdit::Minutes|QTimeEdit::Seconds); + event_position_unit=new QLabel(event_position_box, + tr("before scheduled start. (First cart will have a STOP transition.)"), + this,"event_position_unit"); + event_position_unit->setFont(bold_font); + event_position_unit->setGeometry(CENTER_LINE+212,27, + sizeHint().width()-CENTER_LINE-232,22); + event_position_unit->setAlignment(AlignVCenter|AlignLeft); + + // + // Timed Start Section + // + event_timetype_header=new QLabel(tr("TIMED START"), + this,"event_timetype_header"); + event_timetype_header->setFont(bold_font); + event_timetype_header->setGeometry(CENTER_LINE+15,62,200,16); + + // + // Time Type + // + event_timetype_box=new QCheckBox(this,"event_timetype_box"); + event_timetype_box->setGeometry(CENTER_LINE+15,85,15,15); + event_timetype_label=new QLabel(event_timetype_box,tr("Use hard start time"), + this,"event_timetype_label"); + event_timetype_label->setGeometry(CENTER_LINE+35,84,120,16); + event_timetype_label->setFont(bold_font); + event_timetype_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Post Point + // + event_post_box=new QCheckBox(this,"event_post_box"); + event_post_box->setGeometry(CENTER_LINE+35,108,15,15); + event_post_label=new QLabel(event_post_box,tr("Make Post Point"), + this,"event_post_label"); + event_post_label->setGeometry(CENTER_LINE+55,107,95,16); + event_post_label->setFont(bold_font); + event_post_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Grace Time + // + event_grace_group= + new QButtonGroup(1,Qt::Vertical, + tr("Action If Previous Event Still Playing"), + this,"event_grace_group"); + event_grace_group->hide(); + + event_grace_group->setFont(bold_font); + event_grace_group->setRadioButtonExclusive(true); + event_grace_label=new QLabel(tr("Action If Previous Event Still Playing"), + this,"event_grace_label"); + event_grace_label->setGeometry(CENTER_LINE+180,75,225,16); + event_grace_label->setFont(bold_font); + event_grace_label->setAlignment(AlignCenter); + event_immediate_button=new QRadioButton(tr("Start immediately"),this); + event_immediate_button->setGeometry(CENTER_LINE+170,100,160,15); + event_immediate_button->setFont(font); + event_grace_group->insert(event_immediate_button); + event_next_button=new QRadioButton(tr("Make next"),this); + event_next_button->setGeometry(CENTER_LINE+310,100,160,15); + event_next_button->setFont(font); + event_grace_group->insert(event_next_button); + event_wait_button=new QRadioButton(tr("Wait up to"),this); + event_wait_button->setGeometry(CENTER_LINE+420,100,160,15); + event_wait_button->setFont(font); + event_grace_group->insert(event_wait_button); + + event_grace_edit=new QTimeEdit(this,"event_grace_edit"); + event_grace_edit->setGeometry(CENTER_LINE+500,95,60,20); + event_grace_edit->setDisplay(QTimeEdit::Minutes|QTimeEdit::Seconds); + connect(event_timetype_box,SIGNAL(toggled(bool)), + this,SLOT(timeToggledData(bool))); + connect(event_grace_group,SIGNAL(clicked(int)), + this,SLOT(graceClickedData(int))); + + // + // Transition Type + // + event_transtype_box=new QComboBox(this,"event_transtype_box"); + event_transtype_box->setGeometry(CENTER_LINE+390,131,110,26); + event_transtype_box->insertItem(tr("Play")); + event_transtype_box->insertItem(tr("Segue")); + event_transtype_box->insertItem(tr("Stop")); +// event_transtype_box->setCurrentItem(2); + connect(event_transtype_box,SIGNAL(activated(int)), + this,SLOT(timeTransitionData(int))); + event_time_label= + new QLabel(event_transtype_box, + tr("Transition if previous event ends before start time:"), + this,"event_transtype_label"); + event_time_label->setGeometry(CENTER_LINE+15,131,370,26); + event_time_label->setFont(bold_font); + event_time_label->setAlignment(AlignRight|AlignVCenter); + + // + // Enforcing Length Section + // + label=new QLabel(tr("ENFORCING LENGTH"),this,"enforcing_length_label"); + label->setFont(bold_font); + label->setGeometry(CENTER_LINE+15,162,200,16); + + event_autofill_box=new QCheckBox(this,"event_autofill_box"); + event_autofill_box->setGeometry(CENTER_LINE+100,182,15,15); + label=new QLabel(event_autofill_box,tr("Use AutoFill"), + this,"event_autofill_label"); + label->setFont(bold_font); + label->setGeometry(CENTER_LINE+120,184,150,15); + label->setAlignment(AlignVCenter|AlignLeft); + + event_autofill_slop_box=new QCheckBox(this,"event_autofill_slop_box"); + event_autofill_slop_box->setGeometry(CENTER_LINE+210,182,15,15); + connect(event_autofill_slop_box,SIGNAL(toggled(bool)), + this,SLOT(autofillWarnToggledData(bool))); + event_autofill_slop_label1=new QLabel(event_autofill_slop_box, + tr("Warn if fill is over or under"), + this,"event_autofill_slop_label1"); + event_autofill_slop_label1->setFont(font); + event_autofill_slop_label1->setGeometry(CENTER_LINE+230,184,140,15); + event_autofill_slop_label1->setAlignment(AlignLeft|AlignVCenter); + + event_autofill_slop_edit=new QTimeEdit(this,"event_autofill_slop_edit"); + event_autofill_slop_edit->setGeometry(CENTER_LINE+440,179,60,22); + event_autofill_slop_edit->setDisplay(QTimeEdit::Minutes|QTimeEdit::Seconds); + event_autofill_slop_label= + new QLabel(event_autofill_slop_edit, + tr("by at least"),this,"event_autofill_slop_edit"); + event_autofill_slop_label->setGeometry(CENTER_LINE+370,184,65,15); + event_autofill_slop_label->setFont(font); + event_autofill_slop_label->setAlignment(AlignRight|AlignVCenter); + + event_timescale_box=new QCheckBox(this,"event_timescale_box"); + event_timescale_box->setGeometry(CENTER_LINE+250,182,15,15); + label=new QLabel(event_timescale_box,tr("Use Timescaling"), + this,"event_timescale_label"); + label->setFont(bold_font); + label->setGeometry(CENTER_LINE+270,182,150,15); + label->setAlignment(AlignVCenter|AlignLeft); + event_timescale_box->hide(); + label->hide(); + + // + // Pre-Import Carts Section + // + label=new QLabel(tr("PRE-IMPORT CARTS"),this,"preimport_carts_label"); + label->setFont(bold_font); + label->setGeometry(CENTER_LINE+15,210,200,16); + + // + // Pre-Import Carts List + // + event_preimport_length_edit=new QLineEdit(this,"event_preimport_length_edit"); + event_preimport_length_edit->setGeometry(sizeHint().width()-140,208,80,20); + event_preimport_length_edit->setReadOnly(true); + label=new QLabel(event_preimport_length_edit,tr("Len:"), + this,"event_preimport_length_label"); + label->setFont(bold_font); + label->setGeometry(sizeHint().width()-330,210,185,16); + label->setAlignment(AlignVCenter|AlignRight); + + + event_preimport_list=new ImportListView(this,"event_preimport_list"); + event_preimport_list->setGeometry(CENTER_LINE+15,227, + sizeHint().width()-CENTER_LINE-75,125); + event_preimport_list->setAllColumnsShowFocus(true); + event_preimport_list->setItemMargin(5); + event_preimport_list->logEvent()-> + setLogName(QString().sprintf("%s_PRE",(const char *)event_name). + replace(' ',"_")); + event_preimport_list->setSortColumn(-1); + connect(event_preimport_list,SIGNAL(sizeChanged(int)), + this,SLOT(preimportChangedData(int))); + event_preimport_list->addColumn(""); + event_preimport_list->addColumn(tr("CART")); + event_preimport_list->addColumn(tr("GROUP")); + event_preimport_list->addColumn(tr("LENGTH")); + event_preimport_list->setColumnAlignment(3,AlignRight); + event_preimport_list->addColumn(tr("TITLE")); + event_preimport_list->addColumn(tr("TRANSITION")); + event_preimport_list->addColumn(tr("COUNT")); + connect(event_preimport_list,SIGNAL(clicked(QListViewItem *)), + this,SLOT(cartClickedData(QListViewItem *))); + connect(event_preimport_list,SIGNAL(lengthChanged(int)), + this,SLOT(preimportLengthChangedData(int))); + event_preimport_up_button= + new RDTransportButton(RDTransportButton::Up,this, + "event_preimport_up_button"); + event_preimport_up_button->setGeometry(sizeHint().width()-50,237,40,40); + connect(event_preimport_up_button,SIGNAL(clicked()), + this,SLOT(preimportUpData())); + event_preimport_down_button= + new RDTransportButton(RDTransportButton::Down,this, + "event_preimport_down_button"); + event_preimport_down_button->setGeometry(sizeHint().width()-50,302,40,40); + connect(event_preimport_down_button,SIGNAL(clicked()), + this,SLOT(preimportDownData())); + + // + // Import Section + // + label=new QLabel(tr("IMPORT"),this,"preimport_carts_label"); + label->setFont(bold_font); + label->setGeometry(CENTER_LINE+15,362,200,16); + + event_source_group=new QButtonGroup(this,"event_source_group"); + event_source_group->hide(); + connect(event_source_group,SIGNAL(clicked(int)), + this,SLOT(importClickedData(int))); + rbutton=new QRadioButton(this,"event_noimport_button"); + event_source_group->insert(rbutton); + rbutton->setGeometry(CENTER_LINE+100,362,15,15); + label=new QLabel(rbutton,tr("None"), + this,"event_noimport_label"); + label->setFont(bold_font); + label->setGeometry(CENTER_LINE+120,362,150,15); + label->setAlignment(AlignVCenter|AlignLeft); + + rbutton=new QRadioButton(this,"event_traffic_button"); + event_source_group->insert(rbutton); + rbutton->setGeometry(CENTER_LINE+200,362,15,15); + label=new QLabel(rbutton,tr("From Traffic"), + this,"event_traffic_label"); + label->setFont(bold_font); + label->setGeometry(CENTER_LINE+220,362,150,15); + label->setAlignment(AlignVCenter|AlignLeft); + + rbutton=new QRadioButton(this,"event_music_button"); + rbutton->setGeometry(CENTER_LINE+300,362,15,15); + event_source_group->insert(rbutton); + label=new QLabel(rbutton,tr("From Music"), + this,"event_music_label"); + label->setFont(bold_font); + label->setGeometry(CENTER_LINE+320,362,150,15); + label->setAlignment(AlignVCenter|AlignLeft); + + rbutton=new QRadioButton(this,"event_scheduler_button"); + rbutton->setGeometry(CENTER_LINE+400,362,15,15); + event_source_group->insert(rbutton); + label=new QLabel(rbutton,tr("Select from:"), + this,"event_scheduler_label"); + label->setFont(bold_font); + label->setGeometry(CENTER_LINE+420,362,150,15); + label->setAlignment(AlignVCenter|AlignLeft); + + +// Scheduler Group + + event_sched_group_box=new QComboBox(this,"event_sched_group_box"); + event_sched_group_box->setGeometry(CENTER_LINE+510,359,100,20); + QString sql2="select NAME from GROUPS order by NAME"; + RDSqlQuery *q2=new RDSqlQuery(sql2); + while(q2->next()) { + event_sched_group_box->insertItem(q2->value(0).toString()); + } + delete q2; + +// Title Separation SpinBox + + event_title_sep_label= + new QLabel(tr("Title Separation"),this,"event_title_sep_label"); + event_title_sep_label->setFont(bold_font); + event_title_sep_label->setGeometry(CENTER_LINE+420,383,100,20); + + + event_title_sep_spinbox = new QSpinBox( this, "event_title_sep_spinbox" ); + event_title_sep_spinbox->setGeometry(CENTER_LINE+510,383,50,20); + event_title_sep_spinbox->setMinValue( 0 ); + event_title_sep_spinbox->setMaxValue( 50000 ); + + +// Must have code.. + + event_have_code_label= + new QLabel(tr("Must have code"),this,"event_have_code_label"); + event_have_code_label->setFont(bold_font); + event_have_code_label->setGeometry(CENTER_LINE+420,404,100,20); + + event_have_code_box=new QComboBox(this,"event_have_code_box"); + event_have_code_box->setGeometry(CENTER_LINE+510,404,100,20); + event_have_code_box->insertItem(""); + sql2="select CODE from SCHED_CODES order by CODE"; + q2=new RDSqlQuery(sql2); + while(q2->next()) { + event_have_code_box->insertItem(q2->value(0).toString()); + } + delete q2; + + + // + // Start Slop Time + // + event_startslop_label= + new QLabel(tr("Import carts scheduled"),this,"start_slop_label"); + event_startslop_label->setFont(bold_font); + event_startslop_label->setGeometry(CENTER_LINE+30,383,140,22); + event_startslop_label->setAlignment(AlignVCenter|AlignLeft); + event_startslop_edit=new QTimeEdit(this,"event_startslop_edit"); + event_startslop_edit->setGeometry(CENTER_LINE+171,383,60,22); + event_startslop_edit->setDisplay(QTimeEdit::Minutes|QTimeEdit::Seconds); + event_startslop_unit=new QLabel(tr("prior to the start of this event."), + this,"event_startslop_label"); + event_startslop_unit->setFont(bold_font); + event_startslop_unit->setGeometry(CENTER_LINE+235,383, + sizeHint().width()-CENTER_LINE-460,22); + event_startslop_unit->setAlignment(AlignVCenter|AlignLeft); + + // + // End Slop Time + // + event_endslop_label= + new QLabel(tr("Import carts scheduled"),this,"end_slop_label"); + event_endslop_label->setFont(bold_font); + event_endslop_label->setGeometry(CENTER_LINE+30,404,140,22); + event_endslop_label->setAlignment(AlignVCenter|AlignLeft); + event_endslop_edit=new QTimeEdit(this,"event_endslop_edit"); + event_endslop_edit->setGeometry(CENTER_LINE+171,404,60,22); + event_endslop_edit->setDisplay(QTimeEdit::Minutes|QTimeEdit::Seconds); + event_endslop_unit=new QLabel(tr("after the end of this event."), + this,"event_endslop_label"); + event_endslop_unit->setFont(bold_font); + event_endslop_unit->setGeometry(CENTER_LINE+235,404, + sizeHint().width()-CENTER_LINE-460,22); + event_endslop_unit->setAlignment(AlignVCenter|AlignLeft); + + // + // First Cart Transition Type + // + event_firsttrans_label= + new QLabel(tr("First cart has a"),this,"first_cart_label"); + event_firsttrans_label->setFont(bold_font); + event_firsttrans_label->setGeometry(CENTER_LINE+30,428,140,22); + event_firsttrans_label->setAlignment(AlignVCenter|AlignLeft); + event_firsttrans_box=new QComboBox(this,"event_firsttrans_box"); + event_firsttrans_box->setGeometry(CENTER_LINE+123,428,90,22); + event_firsttrans_box->insertItem(tr("Play")); + event_firsttrans_box->insertItem(tr("Segue")); + event_firsttrans_box->insertItem(tr("Stop")); + event_firsttrans_unit=new QLabel("transition.",this,"first_cart_label"); + event_firsttrans_unit->setFont(bold_font); + event_firsttrans_unit->setGeometry(CENTER_LINE+215,428, + sizeHint().width()-CENTER_LINE-450,22); + event_firsttrans_unit->setAlignment(AlignVCenter|AlignLeft); + + // + // Default Transition Type + // + event_defaulttrans_label=new QLabel(tr("Imported carts have a"), + this,"default_cart_label"); + event_defaulttrans_label->setFont(bold_font); + event_defaulttrans_label->setGeometry(CENTER_LINE+30,451,180,22); + event_defaulttrans_label->setAlignment(AlignVCenter|AlignLeft); + event_defaulttrans_box=new QComboBox(this,"event_endslop_edit"); + event_defaulttrans_box->setGeometry(CENTER_LINE+163,451,90,22); + event_defaulttrans_box->insertItem(tr("Play")); + event_defaulttrans_box->insertItem(tr("Segue")); + event_defaulttrans_box->insertItem(tr("Stop")); + event_defaulttrans_unit=new QLabel(tr("transition."), + this,"default_cart_unit"); + event_defaulttrans_unit->setFont(bold_font); + event_defaulttrans_unit->setGeometry(CENTER_LINE+255,451, + sizeHint().width()-CENTER_LINE-420,22); + event_defaulttrans_unit->setAlignment(AlignVCenter|AlignLeft); + + // + // Nested Event + // + event_nestevent_label=new QLabel(tr("Import inline traffic with the"), + this,"default_cart_label"); + event_nestevent_label->setFont(bold_font); + event_nestevent_label->setGeometry(CENTER_LINE+30,474,190,22); + event_nestevent_label->setAlignment(AlignVCenter|AlignLeft); + event_nestevent_box=new QComboBox(this,"event_endslop_edit"); + event_nestevent_box->setGeometry(CENTER_LINE+183,474,365,22); + event_nestevent_box->insertItem(tr("[none]")); + event_nestevent_unit=new QLabel(tr("event."), + this,"default_cart_unit"); + event_nestevent_unit->setFont(bold_font); + event_nestevent_unit->setGeometry(CENTER_LINE+553,474,40,22); + event_nestevent_unit->setAlignment(AlignVCenter|AlignLeft); + + // + // Post-Import Carts Section + // + label=new QLabel(tr("POST-IMPORT CARTS"),this,"postimport_carts_label"); + label->setFont(bold_font); + label->setGeometry(CENTER_LINE+15,505,200,16); + + // + // Post-Import Carts List + // + event_postimport_length_edit=new QLineEdit(this,"event_postimport_length_edit"); + event_postimport_length_edit->setGeometry(sizeHint().width()-140,503,80,20); + event_postimport_length_edit->setReadOnly(true); + label=new QLabel(event_postimport_length_edit,tr("Len:"), + this,"event_postimport_length_label"); + label->setFont(bold_font); + label->setGeometry(sizeHint().width()-330,505,185,16); + label->setAlignment(AlignVCenter|AlignRight); + + event_postimport_list=new ImportListView(this,"event_postimport_list"); + event_postimport_list->setGeometry(CENTER_LINE+15,522, + sizeHint().width()-CENTER_LINE-75,125); + event_postimport_list->setAllColumnsShowFocus(true); + event_postimport_list->setItemMargin(5); + event_postimport_list->setSortColumn(-1); + event_postimport_list->setAllowStop(false); + event_postimport_list->logEvent()-> + setLogName(QString().sprintf("%s_POST",(const char *)event_name). + replace(' ',"_")); + event_postimport_list->addColumn(""); + event_postimport_list->addColumn(tr("CART")); + event_postimport_list->addColumn(tr("GROUP")); + event_postimport_list->addColumn(tr("LENGTH")); + event_postimport_list->setColumnAlignment(3,AlignRight); + event_postimport_list->addColumn(tr("TITLE")); + event_postimport_list->addColumn(tr("TRANSITION")); + event_postimport_list->addColumn(tr("COUNT")); + connect(event_postimport_list,SIGNAL(clicked(QListViewItem *)), + this,SLOT(cartClickedData(QListViewItem *))); + connect(event_postimport_list,SIGNAL(lengthChanged(int)), + this,SLOT(postimportLengthChangedData(int))); + event_postimport_up_button= + new RDTransportButton(RDTransportButton::Up,this, + "event_postimport_up_button"); + event_postimport_up_button->setGeometry(sizeHint().width()-50,532,40,40); + connect(event_postimport_up_button,SIGNAL(clicked()), + this,SLOT(postimportUpData())); + event_postimport_down_button= + new RDTransportButton(RDTransportButton::Down,this, + "event_postimport_down_button"); + event_postimport_down_button->setGeometry(sizeHint().width()-50,597,40,40); + connect(event_postimport_down_button,SIGNAL(clicked()), + this,SLOT(postimportDownData())); + + // + // Save Button + // + QPushButton *button=new QPushButton(this,"save_button"); + button->setGeometry(CENTER_LINE+10,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Save")); + connect(button,SIGNAL(clicked()),this,SLOT(saveData())); + + // + // Save As Button + // + button=new QPushButton(this,"save_as_button"); + button->setGeometry(CENTER_LINE+100,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("Save &As")); + connect(button,SIGNAL(clicked()),this,SLOT(saveAsData())); + + // + // Service Association Button + // + button=new QPushButton(this,"svc_button"); + button->setGeometry(CENTER_LINE+(sizeHint().width()-CENTER_LINE)/2-85, + sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Services\nList")); + connect(button,SIGNAL(clicked()),this,SLOT(svcData())); + + // + // Color Button + // + event_color_button=new QPushButton(this,"event_color_button"); + event_color_button-> + setGeometry(CENTER_LINE+(sizeHint().width()-CENTER_LINE)/2+5, + sizeHint().height()-60,80,50); + event_color_button->setFont(bold_font); + event_color_button->setText(tr("C&olor")); + connect(event_color_button,SIGNAL(clicked()),this,SLOT(colorData())); + + // + // OK Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Event + // + event_remarks_edit->setText(event_event->remarks()); + int pos=event_event->preposition(); + if(pos<0) { + event_position_box->setChecked(false); + prepositionToggledData(false); + } + else { + event_position_box->setChecked(true); + event_position_edit->setTime(QTime().addMSecs(pos)); + prepositionToggledData(true); + } + + int grace=0; + switch(event_event->timeType()) { + case RDLogLine::Relative: + event_timetype_box->setChecked(false); + event_grace_group->setButton(0); + timeToggledData(false); + break; + + case RDLogLine::Hard: + event_timetype_box->setChecked(true); + event_post_box->setChecked(event_event->postPoint()); + event_transtype_box->setCurrentItem(event_event->firstTransType()); + switch((grace=event_event->graceTime())) { + case 0: + event_grace_group->setButton(0); + event_grace_edit->setTime(QTime()); + break; + + case -1: + event_grace_group->setButton(1); + event_grace_edit->setTime(QTime()); + break; + + default: + event_grace_group->setButton(2); + event_grace_edit->setTime(QTime().addMSecs(grace)); + break; + } + } + + event_autofill_box->setChecked(event_event->useAutofill()); + int autofill_slop=event_event->autofillSlop(); + if(autofill_slop>=0) { + event_autofill_slop_box->setChecked(true); + event_autofill_slop_edit->setTime(QTime().addMSecs(autofill_slop)); + } + autofillWarnToggledData(event_autofill_slop_box->isChecked()); + event_timescale_box->setChecked(event_event->useTimescale()); + + event_source_group->setButton(event_event->importSource()); + event_startslop_edit->setTime(QTime().addMSecs(event_event->startSlop())); + event_endslop_edit->setTime(QTime().addMSecs(event_event->endSlop())); + event_firsttrans_box->setCurrentItem(event_event->firstTransType()); + event_defaulttrans_box->setCurrentItem(event_event->defaultTransType()); + if (event_event->SchedGroup()!=NULL) { + event_sched_group_box->setCurrentText(event_event->SchedGroup()); + } + event_title_sep_spinbox->setValue(event_event->titleSep()); + event_have_code_box->setCurrentText(event_event->HaveCode()); + QColor color=event_event->color(); + if(color.isValid()) { + event_color_button->setPalette(QPalette(color,backgroundColor())); + } + str=event_event->nestedEvent(); + sql=QString().sprintf("select NAME from EVENTS where NAME!=\"%s\"\ + order by NAME", + (const char *)eventname); + q=new RDSqlQuery(sql); + while(q->next()) { + event_nestevent_box->insertItem(q->value(0).toString()); + if(q->value(0).toString()==str) { + event_nestevent_box->setCurrentItem(event_nestevent_box->count()-1); + } + } + delete q; + + if(!new_event) { + event_preimport_list->logEvent()->load(); + event_preimport_list->refreshList(); + event_postimport_list->logEvent()->load(); + event_postimport_list->refreshList(); + } + + prepositionToggledData(event_position_box->isChecked()); + timeToggledData(event_timetype_box->isChecked()); + importClickedData(event_source_group->selectedId()); + preimportChangedData(event_preimport_list->childCount()); + SetPostTransition(); +} + + +EditEvent::~EditEvent() +{ + delete event_lib_list; + delete event_preimport_list; + delete event_postimport_list; +} + + +QSize EditEvent::sizeHint() const +{ + return QSize(1024,715); +} + + +QSizePolicy EditEvent::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditEvent::filterChangedData(const QString &str) +{ + RefreshLibrary(); +} + + +void EditEvent::filterActivatedData(const QString &str) +{ + RefreshLibrary(); +} + + +void EditEvent::filterClickedData(int id) +{ + RefreshLibrary(); +} + + +void EditEvent::cartClickedData(QListViewItem *item) +{ +#ifndef WIN32 + if (!event_player) return; + if(item==NULL) { + event_player->setCart(0); + return; + } + event_player->setCart(item->text(1).toUInt()); +#endif // WIN32 +} + + +void EditEvent::prepositionToggledData(bool state) +{ + event_position_edit->setEnabled(state); + event_timetype_box->setDisabled(state); + event_timetype_header->setDisabled(state); + event_timetype_label->setDisabled(state); + event_preimport_list->setAllowFirstTrans(!state); + if(event_timetype_box->isChecked()) { + event_grace_label->setDisabled(state); + event_immediate_button->setDisabled(state); + event_next_button->setDisabled(state); + event_wait_button->setDisabled(state); + } + if((RDEventLine::ImportSource)event_source_group->selectedId()!= + RDEventLine::None) { + if(event_preimport_list->childCount()==0) { + event_firsttrans_box->setDisabled(state); + event_firsttrans_label->setDisabled(state); + event_firsttrans_unit->setDisabled(state); + } + } + if(state) { + event_preimport_list->setForceTrans(RDLogLine::Stop); + } + else { + if(event_timetype_box->isChecked()) { + event_preimport_list-> + setForceTrans((RDLogLine::TransType)event_transtype_box-> + currentItem()); + } + else { + event_preimport_list->setForceTrans(RDLogLine::NoTrans); + } + } + event_preimport_list->refreshList(); + SetPostTransition(); +} + + +void EditEvent::timeToggledData(bool state) +{ + event_grace_group->setEnabled(state); + event_grace_label->setEnabled(state); + event_immediate_button->setEnabled(state); + event_next_button->setEnabled(state); + event_wait_button->setEnabled(state); + event_grace_edit->setEnabled(state); + event_post_label->setEnabled(state&&(event_grace_group->selectedId()==0)); + event_post_box->setEnabled(state&&(event_grace_group->selectedId()==0)); + event_preimport_list->setAllowFirstTrans(!state); + if(state) { + event_preimport_list-> + setForceTrans((RDLogLine::TransType)event_transtype_box->currentItem()); + } + else { + if(event_position_box->isChecked()) { + event_preimport_list->setForceTrans(RDLogLine::Stop); + } + else { + event_preimport_list->setForceTrans(RDLogLine::NoTrans); + } + } + event_preimport_list->refreshList(); + if(state) { + graceClickedData(event_grace_group->selectedId()); + event_time_label->setEnabled(true); + event_transtype_box->setEnabled(true); + timeTransitionData(2); + event_position_box->setDisabled(true); + event_position_edit->setDisabled(true); + event_position_header->setDisabled(true); + event_position_label->setDisabled(true); + event_position_unit->setDisabled(true); + event_firsttrans_box->setDisabled(true); + event_firsttrans_label->setDisabled(true); + event_firsttrans_unit->setDisabled(true); + } + else { + event_post_box->setChecked(false); + event_grace_edit->setDisabled(true); + event_time_label->setDisabled(true); + event_transtype_box->setDisabled(true); + if(event_position_box->isChecked()) { + event_position_edit->setEnabled(true); + } + event_position_box->setEnabled(true); + event_position_header->setEnabled(true); + event_position_label->setEnabled(true); + event_position_unit->setEnabled(true); + if(((RDEventLine::ImportSource)event_source_group->selectedId()!= + RDEventLine::None)&&(!event_position_box->isChecked())&& + (event_preimport_list->childCount()==0)) { + event_firsttrans_box->setEnabled(true); + event_firsttrans_label->setEnabled(true); + event_firsttrans_unit->setEnabled(true); + } + } + SetPostTransition(); +} + + +void EditEvent::graceClickedData(int id) +{ + switch(id) { + case 0: + event_post_label->setEnabled(event_timetype_box->isChecked()); + event_post_box->setEnabled(event_timetype_box->isChecked()); + timeTransitionData(RDLogLine::Stop); + event_grace_edit->setDisabled(true); + break; + + case 1: + event_post_label->setDisabled(true); + event_post_box->setDisabled(true); + timeTransitionData(RDLogLine::Segue); + event_grace_edit->setDisabled(true); + break; + + case 2: + event_post_label->setDisabled(true); + event_post_box->setDisabled(true); + timeTransitionData(RDLogLine::Segue); + event_grace_edit->setEnabled(true); + break; + } + SetPostTransition(); +} + + +void EditEvent::timeTransitionData(int id) +{ + if(event_timetype_box->isChecked()) { + event_preimport_list-> + setForceTrans((RDLogLine::TransType)event_transtype_box->currentItem()); + } + else { + event_preimport_list->setForceTrans(RDLogLine::NoTrans); + } + event_preimport_list->refreshList(); + SetPostTransition(); +} + + +void EditEvent::autofillWarnToggledData(bool state) +{ + event_autofill_slop_edit->setEnabled(state); + event_autofill_slop_label->setEnabled(state); +} + + +void EditEvent::importClickedData(int id) +{ + bool state=true; + bool statesched=true; + bool stateschedinv=false; + if(id==0) { + state=false; + statesched=false; + } + if(id==3) { + statesched=false; + stateschedinv=true; + } + event_startslop_edit->setEnabled(statesched); + event_startslop_label->setEnabled(statesched); + event_startslop_unit->setEnabled(statesched); + event_endslop_edit->setEnabled(statesched); + event_endslop_label->setEnabled(statesched); + event_endslop_unit->setEnabled(statesched); + if((!event_timetype_box->isChecked())&&(!event_position_box->isChecked())) { + if((state&&(event_preimport_list->childCount()==0))||(!state)) { + event_firsttrans_box->setEnabled(state); + event_firsttrans_label->setEnabled(state); + event_firsttrans_unit->setEnabled(state); + } + } + event_defaulttrans_box->setEnabled(state); + event_defaulttrans_label->setEnabled(state); + event_defaulttrans_unit->setEnabled(state); + state=(id==2)&&state; + event_nestevent_label->setEnabled(state); + event_nestevent_box->setEnabled(state); + event_nestevent_unit->setEnabled(state); + SetPostTransition(); + event_sched_group_box->setEnabled(stateschedinv); + event_title_sep_label->setEnabled(stateschedinv); + event_title_sep_spinbox->setEnabled(stateschedinv); + event_have_code_box->setEnabled(stateschedinv); + event_have_code_label->setEnabled(stateschedinv); +} + + +void EditEvent::preimportChangedData(int size) +{ + if((size==0)&&(event_source_group->selectedId()!=0)&& + (!event_position_box->isChecked())&&(!event_timetype_box->isChecked())) { + event_firsttrans_box->setEnabled(true); + event_firsttrans_label->setEnabled(true); + event_firsttrans_unit->setEnabled(true); + } + else { + event_firsttrans_box->setDisabled(true); + event_firsttrans_label->setDisabled(true); + event_firsttrans_unit->setDisabled(true); + } + SetPostTransition(); +} + + +void EditEvent::preimportLengthChangedData(int msecs) +{ + event_preimport_length_edit->setText(RDGetTimeLength(msecs,true,false)); +} + + +void EditEvent::preimportUpData() +{ + int line; + QListViewItem *item=event_preimport_list->selectedItem(); + if(item==NULL) { + return; + } + if((line=item->text(6).toInt())<1) { + event_preimport_list->setSelected(item,true); + event_preimport_list->ensureItemVisible(item); + return; + } + event_preimport_list->logEvent()->move(line,line-1); + event_preimport_list->validateTransitions(); + event_preimport_list->refreshList(line-1); +} + + +void EditEvent::preimportDownData() +{ + int line; + QListViewItem *item=event_preimport_list->selectedItem(); + if(item==NULL) { + return; + } + if((line=item->text(6).toInt())>=(event_preimport_list->childCount()-1)) { + event_preimport_list->setSelected(item,true); + event_preimport_list->ensureItemVisible(item); + return; + } + event_preimport_list->logEvent()->move(line,line+1); + event_preimport_list->validateTransitions(); + event_preimport_list->refreshList(line+1); +} + + +void EditEvent::postimportUpData() +{ + int line; + QListViewItem *item=event_postimport_list->selectedItem(); + if(item==NULL) { + return; + } + if((line=item->text(6).toInt())<1) { + event_postimport_list->setSelected(item,true); + event_postimport_list->ensureItemVisible(item); + return; + } + event_postimport_list->logEvent()->move(line,line-1); + event_postimport_list->validateTransitions(); + event_postimport_list->refreshList(line-1); +} + + +void EditEvent::postimportDownData() +{ + int line; + QListViewItem *item=event_postimport_list->selectedItem(); + if(item==NULL) { + return; + } + if((line=item->text(6).toInt())>=(event_postimport_list->childCount()-1)) { + event_postimport_list->setSelected(item,true); + event_postimport_list->ensureItemVisible(item); + return; + } + event_postimport_list->logEvent()->move(line,line+1); + event_postimport_list->validateTransitions(); + event_postimport_list->refreshList(line+1); +} + + +void EditEvent::postimportLengthChangedData(int msecs) +{ + event_postimport_length_edit->setText(RDGetTimeLength(msecs,true,false)); +} + + +void EditEvent::saveData() +{ + Save(); + event_new_event=false; +} + + +void EditEvent::saveAsData() +{ + QString old_name; + QString str; + + old_name=event_name; + AddEvent *add_dialog=new AddEvent(&event_name,this,"add_dialog"); + if(add_dialog->exec()<0) { + delete add_dialog; + return; + } + delete add_dialog; + QString sql=QString().sprintf("select NAME from EVENTS where NAME=\"%s\"", + (const char *)RDEscapeString(event_name)); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + delete event_event; + event_event=new RDEvent(event_name,true); + Save(); + event_new_events->push_back(event_name); + CopyEventPerms(old_name,event_name); + if(event_new_event) { + AbandonEvent(old_name); + } + setCaption(QString(). + sprintf("Editing Event - %s",(const char *)event_event->name())); + } + else { + if(QMessageBox::question(this,tr("RDLogManager"),tr("Event already exists!\nDo you want to overwrite it?"),QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + return; + } + delete event_event; + event_event=new RDEvent(event_name,true); + Save(); + event_new_events->push_back(event_name); + sql=QString().sprintf("delete from EVENT_PERMS where EVENT_NAME=\"%s\"", + (const char *)RDEscapeString(event_name)); + q=new RDSqlQuery(sql); + delete q; + CopyEventPerms(old_name,event_name); + if(event_new_event) { + AbandonEvent(old_name); + } + str=QString(tr("Edit Event")); + setCaption(QString(). + sprintf("%s - %s",(const char *)str, + (const char *)event_event->name())); + } +} + + +void EditEvent::svcData() +{ + EditPerms *dialog=new EditPerms(event_name,EditPerms::ObjectEvent, + this,"dialog"); + dialog->exec(); + delete dialog; +} + + +void EditEvent::colorData() +{ + QColor color=QColorDialog::getColor(event_color_button->backgroundColor(), + this,"color_dialog"); + if(color.isValid()) { + event_color_button->setPalette(QPalette(color,backgroundColor())); + } +} + + +void EditEvent::okData() +{ + Save(); +#ifndef WIN32 + if (event_player){ + event_player->stop(); + } +#endif // WIN32 + done(0); +} + + +void EditEvent::cancelData() +{ +#ifndef WIN32 + if (event_player){ + event_player->stop(); + } +#endif // WIN32 + if(event_saved) { + done(-1); + } + else { + done(-2); + } +} + + +void EditEvent::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void EditEvent::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + p->moveTo(CENTER_LINE,10); + p->lineTo(CENTER_LINE,sizeHint().height()-10); + p->drawRect(CENTER_LINE+160,82,sizeHint().width()-CENTER_LINE-200,45); + p->moveTo(CENTER_LINE+408,383); + p->lineTo(CENTER_LINE+408,450); + p->end(); +} + + +void EditEvent::RefreshLibrary() +{ + QString type_filter; + + switch(event_lib_type_group->selectedId()) { + case 0: + type_filter="((TYPE=1)||(TYPE=2)||(TYPE=3))"; + break; + + case 1: + type_filter="((TYPE=1)||(TYPE=3))"; + break; + + case 2: + type_filter="(TYPE=2)"; + break; + } + QString sql="select TYPE,NUMBER,GROUP_NAME,FORCED_LENGTH,TITLE,ARTIST,\ + START_DATETIME,END_DATETIME from CART"; + QString group=event_group_box->currentText(); + if(group==QString(tr("ALL"))) { + group=""; + } + sql+=QString(). + sprintf(" where %s && %s", + (const char *) + RDCartSearchText(event_lib_filter_edit->text(),group,"",false). + utf8(),(const char *)type_filter); + RDSqlQuery *q=new RDSqlQuery(sql); + QListViewItem *item; + event_lib_list->clear(); + while(q->next()) { + item=new QListViewItem(event_lib_list); + switch((RDCart::Type)q->value(0).toInt()) { + case RDCart::Audio: + item->setPixmap(0,*event_playout_map); + item->setText(8,tr("Audio")); + break; + + case RDCart::Macro: + item->setPixmap(0,*event_macro_map); + item->setText(8,tr("Macro")); + break; + + case RDCart::All: + break; + } + item->setText(1,QString().sprintf("%06u",q->value(1).toInt())); + item->setText(2,q->value(2).toString()); + item->setText(3,RDGetTimeLength(q->value(3).toInt(),false,false)); + item->setText(4,q->value(4).toString()); + item->setText(5,q->value(5).toString()); + if(!q->value(6).toDateTime().isNull()) { + item->setText(6,q->value(7).toDateTime().toString("MM/dd/yyyy")); + } + if(!q->value(7).toDateTime().isNull()) { + item->setText(7,q->value(7).toDateTime().toString("MM/dd/yyyy")); + } + else { + item->setText(7,"TFN"); + } + } + delete q; +} + + +void EditEvent::SetPostTransition() +{ + if((event_position_box->isChecked())|| + (event_timetype_box->isChecked())|| + (event_preimport_list->childCount()!=0)|| + (event_source_group->selectedId()!=0)) { + event_postimport_list->setAllowStop(false); + } + else { + event_postimport_list->setAllowStop(true); + } + if(event_preimport_list->childCount()==0) { + if(event_position_box->isChecked()) { + event_postimport_list->setAllowFirstTrans(false); + event_postimport_list->setForceTrans(RDLogLine::Stop); + } + else { + if(event_timetype_box->isChecked()) { + event_postimport_list-> + setForceTrans((RDLogLine::TransType)event_transtype_box-> + currentItem()); + event_postimport_list->setAllowFirstTrans(false); + } + else { + event_postimport_list->setAllowFirstTrans(true); + event_postimport_list->setForceTrans(RDLogLine::NoTrans); + } + } + } + else { + event_postimport_list->setAllowFirstTrans(true); + event_postimport_list->setForceTrans(RDLogLine::NoTrans); + } + event_postimport_list->refreshList(); +} + + +void EditEvent::Save() +{ + QString properties; + QString listname; + + event_event->setRemarks(event_remarks_edit->text()); + if(event_position_box->isChecked()) { + event_event->setPreposition(QTime().msecsTo(event_position_edit->time())); + } + else { + event_event->setPreposition(-1); + } + if(event_timetype_box->isChecked()) { + event_event->setTimeType(RDLogLine::Hard); + event_event->setPostPoint(event_post_box->isChecked()); + event_event->setFirstTransType((RDLogLine::TransType) + event_transtype_box->currentItem()); + switch((RDLogLine::TransType)event_transtype_box->currentItem()) { + case RDLogLine::Play: + break; + + case RDLogLine::Segue: + break; + + case RDLogLine::Stop: + break; + + default: + break; + } + switch(event_grace_group->selectedId()) { + case 0: + event_event->setGraceTime(0); + break; + + case 1: + event_event->setGraceTime(-1); + break; + + default: + event_event->setGraceTime(QTime().msecsTo(event_grace_edit->time())); + break; + } + } + else { + event_event->setTimeType(RDLogLine::Relative); + event_event->setGraceTime(0); + event_event->setPostPoint(false); + event_event->setFirstTransType(RDLogLine::Play); + } + + event_event->setUseAutofill(event_autofill_box->isChecked()); + if(event_autofill_slop_box->isChecked()) { + event_event-> + setAutofillSlop(QTime().msecsTo(event_autofill_slop_edit->time())); + } + else { + event_event->setAutofillSlop(-1); + } + event_event->setUseTimescale(event_timescale_box->isChecked()); + + switch((RDEventLine::ImportSource)event_source_group->selectedId()) { + case RDEventLine::Traffic: + break; + + case RDEventLine::Music: + break; + + case RDEventLine::Scheduler: + break; + + default: + break; + } + event_event-> + setImportSource((RDEventLine::ImportSource)event_source_group->selectedId()); + event_event->setStartSlop(QTime().msecsTo(event_startslop_edit->time())); + event_event->setEndSlop(QTime().msecsTo(event_endslop_edit->time())); + if(!event_timetype_box->isChecked()) { + event_event-> + setFirstTransType((RDLogLine::TransType)event_firsttrans_box-> + currentItem()); + switch((RDLogLine::TransType)event_firsttrans_box->currentItem()) { + case RDLogLine::Play: + break; + + case RDLogLine::Segue: + break; + + case RDLogLine::Stop: + break; + + default: + break; + } + } + event_event-> + setDefaultTransType((RDLogLine::TransType)event_defaulttrans_box-> + currentItem()); + event_event->setColor(event_color_button->backgroundColor()); + if(event_nestevent_box->currentItem()==0) { + event_event->setNestedEvent(""); + } + else { + event_event->setNestedEvent(event_nestevent_box->currentText()); + } + event_event->setProperties(GetProperties()); + event_event->setSchedGroup(event_sched_group_box->currentText()); + event_event->setTitleSep(event_title_sep_spinbox->value()); + event_event->setHaveCode(event_have_code_box->currentText()); + listname=event_name; + listname.replace(" ","_"); + event_preimport_list->logEvent()-> + setLogName(QString().sprintf("%s_PRE",(const char *)listname)); + event_preimport_list->logEvent()->save(false); + event_postimport_list->logEvent()-> + setLogName(QString().sprintf("%s_POST",(const char *)listname)); + event_postimport_list->logEvent()->save(false); + event_saved=true; +} + + +QString EditEvent::GetProperties() +{ + QString properties; + RDLogLine::TransType trans_type; + QString str; + + if(event_position_box->isChecked()) { + str=QString(tr("Cue")); + properties+= + QString().sprintf("%s(-%s), ",(const char *)str, + (const char *)event_position_edit->time().toString("mm:ss")); + } + if(event_timetype_box->isChecked()) { + trans_type=(RDLogLine::TransType)event_transtype_box->currentItem(); + } + else { + if(event_preimport_list->childCount()>0) { + str=event_preimport_list->firstChild()->text(5); + trans_type=RDLogLine::Play; + if(str==tr("SEGUE")) { + trans_type=RDLogLine::Segue; + } + if(str==tr("STOP")) { + trans_type=RDLogLine::Stop; + } + } + else { + if(event_position_box->isChecked()) { + trans_type=RDLogLine::Stop; + } + else { + trans_type=(RDLogLine::TransType)event_firsttrans_box->currentItem(); + } + } + } + switch(trans_type) { + case RDLogLine::Play: + properties+=tr("PLAY"); + break; + + case RDLogLine::Segue: + properties+=tr("SEGUE"); + break; + + case RDLogLine::Stop: + properties+=tr("STOP"); + break; + + default: + break; + } + + if(event_timetype_box->isChecked()) { + switch(event_grace_group->selectedId()) { + case 0: + properties+=tr(", Timed(Start)"); + break; + + case 1: + properties+=tr(", Timed(MakeNext)"); + break; + + default: + str=QString(tr("Timed(Wait")); + properties+= + QString().sprintf(", %s %s)",(const char *)str,(const char *) + event_grace_edit->time().toString("mm:ss")); + break; + } + if(event_post_box->isChecked()) { + properties+=tr(", Post"); + } + } + if(event_autofill_box->isChecked()) { + properties+=tr(", Fill"); + } + if(event_timescale_box->isChecked()) { + properties+=tr(", Scale"); + } + switch((RDEventLine::ImportSource)event_source_group->selectedId()) { + case RDEventLine::Traffic: + properties+=tr(", Traffic"); + break; + + case RDEventLine::Music: + properties+=tr(", Music"); + break; + + case RDEventLine::Scheduler: + properties+=tr(", Scheduler"); + break; + + + default: + break; + } + if(event_nestevent_box->currentItem()>0) { + properties+=tr(", Inline Traffic"); + } + + return properties; +} + + +void EditEvent::CopyEventPerms(QString old_name,QString new_name) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + sql=QString().sprintf("select SERVICE_NAME from EVENT_PERMS where\ + EVENT_NAME=\"%s\"", + (const char *)RDEscapeString(old_name)); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into EVENT_PERMS set\ + EVENT_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *)RDEscapeString(new_name), + (const char *) + RDEscapeString(q->value(0).toString())); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; +} + + +void EditEvent::AbandonEvent(QString name) +{ + if(name==event_name) { + return; + } + QString sql=QString().sprintf("delete from EVENTS where NAME=\"%s\"", + (const char *)RDEscapeString(name)); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from EVENT_PERMS where EVENT_NAME=\"%s\"", + (const char *)RDEscapeString(name)); + q=new RDSqlQuery(sql); + delete q; + sql=QString("drop table `")+RDEvent::preimportTableName(name)+"`"; + q=new RDSqlQuery(sql); + delete q; + sql=QString("drop table `")+RDEvent::postimportTableName(name)+"`"; + q=new RDSqlQuery(sql); + delete q; +} diff --git a/rdlogmanager/edit_event.h b/rdlogmanager/edit_event.h new file mode 100644 index 00000000..433f66e1 --- /dev/null +++ b/rdlogmanager/edit_event.h @@ -0,0 +1,175 @@ +// edit_event.h +// +// Edit a Rivendell Log Event +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_event.h,v 1.24.8.1 2013/12/30 20:37:01 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_EVENT_H +#define EDIT_EVENT_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +// +// Layout +// +#define CENTER_LINE 400 + +class EditEvent : public QDialog +{ + Q_OBJECT + public: + EditEvent(QString eventname,bool new_event,std::vector *new_events, + QWidget *parent=0,const char *name=0); + ~EditEvent(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void filterChangedData(const QString &str); + void filterActivatedData(const QString &str); + void filterClickedData(int id); + void cartClickedData(QListViewItem *item); + void prepositionToggledData(bool state); + void timeToggledData(bool); + void graceClickedData(int); + void timeTransitionData(int); + void autofillWarnToggledData(bool); + void importClickedData(int); + void preimportChangedData(int size); + void preimportLengthChangedData(int msecs); + void preimportUpData(); + void preimportDownData(); + void postimportUpData(); + void postimportDownData(); + void postimportLengthChangedData(int msecs); + void saveData(); + void saveAsData(); + void svcData(); + void colorData(); + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + void paintEvent(QPaintEvent *e); + + private: + void RefreshLibrary(); + void SetPostTransition(); + void Save(); + void CopyEventPerms(QString old_name,QString new_name); + void AbandonEvent(QString name); + QString GetProperties(); + QString event_name; + RDEvent *event_event; + QLineEdit *event_lib_filter_edit; + QButtonGroup *event_lib_type_group; + QComboBox *event_group_box; + QComboBox *event_sched_group_box; + QSpinBox* event_title_sep_spinbox; + QLabel *event_title_sep_label; + QComboBox* event_have_code_box; + QLabel *event_have_code_label; + LibListView *event_lib_list; + QPixmap *event_playout_map; + QPixmap *event_macro_map; + QLabel *event_position_header; + QLabel *event_position_label; + QLabel *event_position_unit; + QCheckBox *event_position_box; + QTimeEdit *event_position_edit; + QLabel *event_timetype_header; + QCheckBox *event_timetype_box; + QLabel *event_timetype_label; + QCheckBox *event_post_box; + QLabel *event_post_label; + QLabel *event_time_label; + QLabel *event_grace_label; + QButtonGroup *event_grace_group; + QRadioButton *event_immediate_button; + QRadioButton *event_next_button; + QRadioButton *event_wait_button; + QTimeEdit *event_grace_edit; + QComboBox *event_transtype_box; + QCheckBox *event_autofill_box; + QCheckBox *event_autofill_slop_box; + QLabel *event_autofill_slop_label1; + QLabel *event_autofill_slop_label; + QTimeEdit *event_autofill_slop_edit; + QCheckBox *event_timescale_box; + ImportListView *event_preimport_list; + QLineEdit *event_preimport_length_edit; + RDTransportButton *event_preimport_up_button; + RDTransportButton *event_preimport_down_button; + QButtonGroup *event_source_group; + QTimeEdit *event_startslop_edit; + QLabel *event_startslop_label; + QLabel *event_startslop_unit; + QTimeEdit *event_endslop_edit; + QLabel *event_endslop_label; + QLabel *event_endslop_unit; + QComboBox *event_firsttrans_box; + QLabel *event_firsttrans_label; + QLabel *event_firsttrans_unit; + QComboBox *event_defaulttrans_box; + QLabel *event_defaulttrans_label; + QLabel *event_defaulttrans_unit; + QLabel *event_nestevent_label; + QComboBox *event_nestevent_box; + QLabel *event_nestevent_unit; + ImportListView *event_postimport_list; + QLineEdit *event_postimport_length_edit; + RDTransportButton *event_postimport_up_button; + RDTransportButton *event_postimport_down_button; + QPushButton *event_color_button; + bool event_saved; + bool event_new_event; + std::vector *event_new_events; + RDSimplePlayer *event_player; + QTextEdit *event_remarks_edit; + RDEmptyCart *event_empty_cart; +}; + + +#endif + diff --git a/rdlogmanager/edit_eventline.cpp b/rdlogmanager/edit_eventline.cpp new file mode 100644 index 00000000..6c698036 --- /dev/null +++ b/rdlogmanager/edit_eventline.cpp @@ -0,0 +1,239 @@ +// edit_eventline.cpp +// +// Edit Rivendell Log Eventline +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_eventline.cpp,v 1.16 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +EditEventLine::EditEventLine(RDEventLine *eventline,RDClock *clock,int line, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + setCaption(tr("Edit Event Assignment")); + edit_eventline=eventline; + edit_clock=clock; + edit_line=line; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Text Validator + // + // + // Create Validators + // + RDTextValidator *validator=new RDTextValidator(); + validator->addBannedChar('('); + validator->addBannedChar(')'); + validator->addBannedChar('!'); + validator->addBannedChar('@'); + validator->addBannedChar('#'); + validator->addBannedChar('$'); + validator->addBannedChar('%'); + validator->addBannedChar('^'); + validator->addBannedChar('&'); + validator->addBannedChar('*'); + validator->addBannedChar('{'); + validator->addBannedChar('}'); + validator->addBannedChar('['); + validator->addBannedChar(']'); + validator->addBannedChar(':'); + validator->addBannedChar(';'); + validator->addBannedChar(34); + validator->addBannedChar('<'); + validator->addBannedChar('>'); + validator->addBannedChar('.'); + validator->addBannedChar(','); + validator->addBannedChar('\\'); + validator->addBannedChar('-'); + validator->addBannedChar('_'); + + // + // Event Name + // + edit_eventname_edit=new QLineEdit(this,"edit_eventname_edit"); + edit_eventname_edit->setGeometry(65,12,sizeHint().width()-140,18); + edit_eventname_edit->setMaxLength(64); + edit_eventname_edit->setValidator(validator); + QLabel *label=new QLabel(edit_eventname_edit,tr("Event:"), + this,"edit_eventname_label"); + label->setGeometry(10,12,50,18); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // Event Select Button + // + QPushButton *button=new QPushButton(this,"select_button"); + button->setGeometry(sizeHint().width()-60,7,50,30); + button->setFont(font); + button->setText(tr("Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectData())); + + // + // Start Time + // + edit_starttime_edit=new RDTimeEdit(this,"edit_starttime_edit"); + edit_starttime_edit->setGeometry(150,40,70,20); + edit_starttime_edit-> + setDisplay(RDTimeEdit::Minutes|RDTimeEdit::Seconds|RDTimeEdit::Tenths); + edit_starttime_edit->setFont(font); + label=new QLabel(edit_starttime_edit,tr("Start Time:"), + this,"edit_starttime_label"); + label->setGeometry(65,42,80,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // End Time + // + edit_endtime_edit=new RDTimeEdit(this,"edit_length_edit"); + edit_endtime_edit->setGeometry(325,40,70,20); + edit_endtime_edit-> + setDisplay(RDTimeEdit::Minutes|RDTimeEdit::Seconds|RDTimeEdit::Tenths); + label=new QLabel(edit_endtime_edit,tr("End Time:"), + this,"edit_endtime_label"); + label->setGeometry(250,42,70,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + // + // OK Button + // + button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Data + // + if(edit_eventline!=NULL) { + edit_eventname_edit->setText(edit_eventline->name()); + edit_starttime_edit->setTime(edit_eventline->startTime()); + edit_endtime_edit-> + setTime(edit_eventline->startTime().addMSecs(edit_eventline->length())); + } +} + + +QSize EditEventLine::sizeHint() const +{ + return QSize(550,130); +} + + +QSizePolicy EditEventLine::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditEventLine::selectData() +{ + QString eventname; + ListEvents *list_events=new ListEvents(&eventname,this,"add_dialog"); + if(list_events->exec()<0) { + delete list_events; + return; + } + delete list_events; + edit_eventname_edit->setText(eventname); +} + + +void EditEventLine::okData() +{ + if(edit_starttime_edit->time()>edit_endtime_edit->time()) { + QMessageBox::information(this,tr("Invalid Event"), + tr("The event end time cannot be earlier than the start time.")); + return; + } + QString sql=QString().sprintf("select NAME from EVENTS where NAME=\"%s\"", + (const char *)edit_eventname_edit->text()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(!q->first()) { + QMessageBox::information(this,tr("No Such Event"), + tr("There is no such event.")); + delete q; + return; + } + edit_eventname_edit->setText(q->value(0).toString()); + delete q; + if(!edit_clock->validate(edit_starttime_edit->time(), + edit_starttime_edit->time(). + msecsTo(edit_endtime_edit->time()), + edit_line)) { + QMessageBox::information(this,tr("Invalid Event"), + tr("This event overlaps with an\nalready existing event.")); + return; + } + edit_eventline->setName(edit_eventname_edit->text()); + edit_eventline->setStartTime(edit_starttime_edit->time()); + edit_eventline-> + setLength(edit_starttime_edit->time().msecsTo(edit_endtime_edit->time())); + done(0); +} + + +void EditEventLine::cancelData() +{ + done(-1); +} diff --git a/rdlogmanager/edit_eventline.h b/rdlogmanager/edit_eventline.h new file mode 100644 index 00000000..72e96fb2 --- /dev/null +++ b/rdlogmanager/edit_eventline.h @@ -0,0 +1,60 @@ +// edit_clockline.h +// +// Edit A Rivendell Log Clock +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_eventline.h,v 1.7 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_CLOCKLINE_H +#define EDIT_CLOCKLINE_H + +#include +#include +#include +#include + +#include +#include +#include + +class EditEventLine : public QDialog +{ + Q_OBJECT + public: + EditEventLine(RDEventLine *eventline,RDClock *clock,int line, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void selectData(); + void okData(); + void cancelData(); + + private: + RDEventLine *edit_eventline; + QLineEdit *edit_eventname_edit; + RDTimeEdit *edit_starttime_edit; + RDTimeEdit *edit_endtime_edit; + int edit_line; + RDClock *edit_clock; +}; + + +#endif + diff --git a/rdlogmanager/edit_grid.cpp b/rdlogmanager/edit_grid.cpp new file mode 100644 index 00000000..b3c38baa --- /dev/null +++ b/rdlogmanager/edit_grid.cpp @@ -0,0 +1,344 @@ +// edit_grid.cpp +// +// Edit Rivendell Log Grid +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_grid.cpp,v 1.12.8.2 2014/01/21 21:28:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + + +EditGrid::EditGrid(QString servicename,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + QString str; + + str=QString(tr("Edit Grid:")); + setCaption(QString().sprintf("%s %s",(const char *)str, + (const char *)servicename)); + edit_servicename=servicename; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + QFont button_font("Helvetica",10,QFont::Normal); + button_font.setPixelSize(10); + + // + // Hour Buttons + // + QLabel *label; + QSignalMapper *mapper=new QSignalMapper(this,"hour_button_mapper"); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(hourButtonData(int))); + for(int i=0;i<5;i++) { + label=new QLabel(QDate::longDayName(i+1),this,"day_label"); + label->setGeometry(20,14+75*i,90,16); + label->setFont(bold_font); + label->setAlignment(AlignCenter); + for(int j=0;j<24;j++) { + edit_hour_button[i][j]=new RDPushButton(this,"hour_button"); + edit_hour_button[i][j]->setGeometry(10+42*j,30+75*i,42,40); + edit_hour_button[i][j]->setFont(button_font); + edit_hour_button[i][j]->setId(24*i+j); + LabelButton(i+1,j,"---"); + mapper->setMapping(edit_hour_button[i][j],24*i+j); + connect(edit_hour_button[i][j],SIGNAL(clicked()),mapper,SLOT(map())); + connect(edit_hour_button[i][j],SIGNAL(rightClicked(int,const QPoint &)), + this,SLOT(rightHourButtonData(int,const QPoint &))); + } + } + for(int i=5;i<7;i++) { + label=new QLabel(QDate::longDayName(i+1),this,"day_label"); + label->setGeometry(20,44+75*i,90,16); + label->setFont(bold_font); + label->setAlignment(AlignCenter); + for(int j=0;j<24;j++) { + edit_hour_button[i][j]=new RDPushButton(this,"hour_button"); + edit_hour_button[i][j]->setGeometry(10+42*j,60+75*i,42,40); + edit_hour_button[i][j]->setFont(button_font); + edit_hour_button[i][j]->setId(24*i+j); + LabelButton(i+1,j,"---"); + mapper->setMapping(edit_hour_button[i][j],24*i+j); + connect(edit_hour_button[i][j],SIGNAL(clicked()),mapper,SLOT(map())); + connect(edit_hour_button[i][j],SIGNAL(rightClicked(int,const QPoint &)), + this,SLOT(rightHourButtonData(int,const QPoint &))); + } + } + + // + // Right Button Menu + // + edit_right_menu=new QPopupMenu(this,"edit_right_menu"); + connect(edit_right_menu,SIGNAL(aboutToShow()),this,SLOT(aboutToShowData())); + edit_right_menu-> + insertItem(tr("Edit Clock"),this,SLOT(editClockData()),0,0); + edit_right_menu-> + insertItem(tr("Clear Hour"),this,SLOT(clearHourData()),0,1); + + // + // Change All Button + // + QPushButton *all_button=new QPushButton(this,"change_all_button"); + all_button->setGeometry(10,sizeHint().height()-60,80,50); + all_button->setDefault(false); + all_button->setFont(bold_font); + all_button->setText(tr("Change\n&All")); + connect(all_button,SIGNAL(clicked()),this,SLOT(allHourButtonData())); + + // + // Close Button + // + QPushButton *button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&Close")); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Load Buttons + // + LoadButtons(); +} + + +QSize EditGrid::sizeHint() const +{ + return QSize(1024,638); +} + + +QSizePolicy EditGrid::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditGrid::hourButtonData(int id) +{ + int dayofweek=id/24+1; + int hour=id-24*(dayofweek-1); + QString clockname=GetClock(dayofweek,hour); + if(clockname.isEmpty()) { + clockname=current_clockname; + } + ListClocks *listclocks=new ListClocks(&clockname,this,"listclocks"); + if(listclocks->exec()<0) { + delete listclocks; + return; + } + delete listclocks; + current_clockname=clockname; + QString sql=QString().sprintf("update SERVICES set CLOCK%d=\"%s\"\ + where NAME=\"%s\"", + id,(const char *)clockname, + (const char *)edit_servicename); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + LabelButton(dayofweek,hour,clockname); +} + + +void EditGrid::allHourButtonData() +{ + QString clockname=""; + ListClocks *listclocks=new ListClocks(&clockname,this,"listclocks"); + if(listclocks->exec()<0) { + delete listclocks; + return; + } + delete listclocks; + if(QMessageBox::question(this,"RDLogManager - "+tr("Clear Clocks"), + tr("Are you sure you want to update ALL clocks in the grid?")+"\n"+tr("This operation cannot be undone!"),QMessageBox::Yes,QMessageBox::No)==QMessageBox::Yes) { + for(int id=0;id<168;id++) { + QString sql=QString().sprintf("update SERVICES set CLOCK%d=\"%s\"\ + where NAME=\"%s\"", + id,(const char *)clockname, + (const char *)edit_servicename); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + int dayofweek=id/24+1; + int hour=id-24*(dayofweek-1); + LabelButton(dayofweek,hour,clockname); + } + } +} + + +void EditGrid::rightHourButtonData(int id,const QPoint &pt) +{ + edit_rightclick_id=id; + int dayofweek=edit_rightclick_id/24+1; + int hour=edit_rightclick_id-24*(dayofweek-1); + edit_right_menu-> + setGeometry(edit_hour_button[dayofweek-1][hour]->geometry().x()+ + geometry().x()+pt.x()+2, + edit_hour_button[dayofweek-1][hour]->geometry().y()+ + geometry().y()+pt.y(), + edit_right_menu->sizeHint().width(), + edit_right_menu->sizeHint().height()); + edit_right_menu->exec(); +} + + +void EditGrid::aboutToShowData() +{ + int dayofweek=edit_rightclick_id/24+1; + int hour=edit_rightclick_id-24*(dayofweek-1); + edit_right_menu->setItemEnabled(0,!GetClock(dayofweek,hour).isEmpty()); + edit_right_menu->setItemEnabled(1,!GetClock(dayofweek,hour).isEmpty()); +} + + +void EditGrid::editClockData() +{ + std::vector new_clocks; + + int dayofweek=edit_rightclick_id/24+1; + int hour=edit_rightclick_id-24*(dayofweek-1); + QString clockname=GetClock(dayofweek,hour); + if(clockname.isEmpty()) { + return; + } + EditClock *dialog=new EditClock(clockname,false,&new_clocks,this,"dialog"); + if(dialog->exec()<0) { + delete dialog; + return; + } + delete dialog; + LoadButtons(); +} + + +void EditGrid::clearHourData() +{ + int dayofweek=edit_rightclick_id/24+1; + int hour=edit_rightclick_id-24*(dayofweek-1); + QString sql=QString().sprintf("update SERVICES set CLOCK%d=\"\"\ + where NAME=\"%s\"", + edit_rightclick_id, + (const char *)edit_servicename); + RDSqlQuery *q=new RDSqlQuery(sql); + delete q; + LabelButton(dayofweek,hour,""); +} + + +void EditGrid::closeData() +{ + done(-1); +} + + +void EditGrid::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QColor(black)); + for(int i=0;i<5;i++) { + p->drawRect(5,21+75*i,sizeHint().width()-10,55); + } + for(int i=5;i<7;i++) { + p->drawRect(5,51+75*i,sizeHint().width()-10,55); + } + p->end(); +} + + +void EditGrid::closeEvent(QCloseEvent *e) +{ + closeData(); +} + + +void EditGrid::LoadButtons() +{ + for(int i=0;i<7;i++) { + for(int j=0;j<24;j++) { + LabelButton(i+1,j,GetClock(i+1,j)); + } + } +} + + +void EditGrid::LabelButton(int dayofweek,int hour,QString clockname) +{ + QString code=QString("---"); + QColor color=backgroundColor(); + + QString sql=QString().sprintf("select SHORT_NAME,COLOR from CLOCKS\ + where NAME=\"%s\"", + (const char *)clockname); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + code=q->value(0).toString(); + if(!q->value(1).isNull()) { + color=QColor(q->value(1).toString()); + } + } + edit_hour_button[dayofweek-1][hour]-> + setText(QString().sprintf("%02d-%02d\n%s",hour,hour+1,(const char *)code)); + edit_hour_button[dayofweek-1][hour]-> + setPalette(QPalette(color,backgroundColor())); +} + + +QString EditGrid::GetClock(int dayofweek,int hour) +{ + QString sql=QString().sprintf("select CLOCK%d from SERVICES where\ + NAME=\"%s\"", + 24*(dayofweek-1)+hour, + (const char *)edit_servicename); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->first()) { + return q->value(0).toString(); + } + return QString(); +} + diff --git a/rdlogmanager/edit_grid.h b/rdlogmanager/edit_grid.h new file mode 100644 index 00000000..d139808a --- /dev/null +++ b/rdlogmanager/edit_grid.h @@ -0,0 +1,70 @@ +// edit_grid.h +// +// Edit A Rivendell Log Grid +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_grid.h,v 1.8.8.1 2013/10/11 17:16:49 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_GRID_H +#define EDIT_GRID_H + +#include +#include +#include +#include + +#include + +#include +#include + + +class EditGrid : public QDialog +{ + Q_OBJECT + public: + EditGrid(QString servicename,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void hourButtonData(int id); + void allHourButtonData(); + void rightHourButtonData(int id,const QPoint &pt); + void aboutToShowData(); + void editClockData(); + void clearHourData(); + void closeData(); + + protected: + void paintEvent(QPaintEvent *e); + void closeEvent(QCloseEvent *e); + + private: + void LoadButtons(); + void LabelButton(int dayofweek,int hour,QString code); + QString GetClock(int dayofweek,int hour); + QString edit_servicename; + QString current_clockname; + RDPushButton *edit_hour_button[7][24]; + QPopupMenu *edit_right_menu; + int edit_rightclick_id; +}; + + +#endif diff --git a/rdlogmanager/edit_note.cpp b/rdlogmanager/edit_note.cpp new file mode 100644 index 00000000..6a453ff7 --- /dev/null +++ b/rdlogmanager/edit_note.cpp @@ -0,0 +1,115 @@ +// edit_note.cpp +// +// Edit a Rivendell LogManager Note +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_note.cpp,v 1.7.8.1 2012/04/23 17:22:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +EditNote::EditNote(QString *text,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + setCaption(tr("Edit Log Note")); + edit_text=text; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // The Text Editor + // + edit_text_edit=new QTextEdit(this,"edit_text_edit"); + edit_text_edit->setGeometry(10,10, + sizeHint().width()-20,sizeHint().height()-80); + edit_text_edit->setText(*edit_text); + + // + // OK Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +QSize EditNote::sizeHint() const +{ + return QSize(400,250); +} + + +QSizePolicy EditNote::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditNote::okData() +{ + *edit_text=edit_text_edit->text(); + done(0); +} + + +void EditNote::cancelData() +{ + done(-1); +} + + +void EditNote::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/rdlogmanager/edit_note.h b/rdlogmanager/edit_note.h new file mode 100644 index 00000000..79ae76cc --- /dev/null +++ b/rdlogmanager/edit_note.h @@ -0,0 +1,53 @@ +// edit_note.h +// +// Edit a Rivendell LogManager Note +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_note.h,v 1.5.8.1 2012/04/23 17:22:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_NOTE_H +#define EDIT_NOTE_H + +#include +#include +#include + + +class EditNote : public QDialog +{ + Q_OBJECT + public: + EditNote(QString *text,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + void closeEvent(QCloseEvent *e); + + private slots: + void okData(); + void cancelData(); + + private: + QString *edit_text; + QTextEdit *edit_text_edit; +}; + + +#endif // EDIT_NOTE_H + diff --git a/rdlogmanager/edit_perms.cpp b/rdlogmanager/edit_perms.cpp new file mode 100644 index 00000000..8053e235 --- /dev/null +++ b/rdlogmanager/edit_perms.cpp @@ -0,0 +1,207 @@ +// edit_perms.cpp +// +// Edit RDLogManager Service Associations +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_perms.cpp,v 1.10.8.1 2012/04/23 17:22:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +EditPerms::EditPerms(QString object_name,ObjectType type, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + QString str; + + sel_type=type; + sel_name=object_name; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + str=QString(tr("Service Associations")); + setCaption(QString().sprintf("%s - %s", + (const char *)sel_name,(const char *)str)); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + // + // Services Selector + // + svc_object_sel=new RDListSelector(this,"svc_object_sel"); + svc_object_sel->setGeometry(10,10,380,130); + svc_object_sel->sourceSetLabel(tr("Available Services")); + svc_object_sel->destSetLabel(tr("Enabled Services")); + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Populate Fields + // + switch(sel_type) { + case EditPerms::ObjectEvent: + object_type="EVENT"; + break; + + case EditPerms::ObjectClock: + object_type="CLOCK"; + break; + } + // FIXME: should this be filtered based on the user if usersec is enabled? + sql=QString().sprintf("select SERVICE_NAME from %s_PERMS \ + where %s_NAME=\"%s\"", + (const char *)object_type, + (const char *)object_type, + (const char *)object_name); + q=new RDSqlQuery(sql); + while(q->next()) { + svc_object_sel->destInsertItem(q->value(0).toString()); + } + delete q; + sql=QString().sprintf("select NAME from SERVICES"); + q=new RDSqlQuery(sql); + while(q->next()) { + if(svc_object_sel->destFindItem(q->value(0).toString())==0) { + svc_object_sel->sourceInsertItem(q->value(0).toString()); + } + } + delete q; +} + + +EditPerms::~EditPerms() +{ +} + + +QSize EditPerms::sizeHint() const +{ + return QSize(400,212); +} + + +QSizePolicy EditPerms::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditPerms::okData() +{ + RDSqlQuery *q; + QString sql; + + // + // Add New Objects + // + for(unsigned i=0;idestCount();i++) { + sql=QString().sprintf("select %s_NAME from %s_PERMS \ + where SERVICE_NAME=\"%s\" && %s_NAME=\"%s\"", + (const char *)object_type, + (const char *)object_type, + (const char *)svc_object_sel->destText(i), + (const char *)object_type, + (const char *)sel_name); + q=new RDSqlQuery(sql); + if(q->size()==0) { + delete q; + sql=QString(). + sprintf("insert into %s_PERMS (SERVICE_NAME,%s_NAME) \ + values (\"%s\",\"%s\")", + (const char *)object_type, + (const char *)object_type, + (const char *)svc_object_sel->destText(i), + (const char *)sel_name); + q=new RDSqlQuery(sql); + } + delete q; + } + + // + // Delete Old Hosts + // + sql=QString().sprintf("delete from %s_PERMS where %s_NAME=\"%s\"", + (const char *)object_type, + (const char *)object_type, + (const char *)sel_name); + for(unsigned i=0;idestCount();i++) { + sql+=QString().sprintf(" && SERVICE_NAME<>\"%s\"", + (const char *)svc_object_sel->destText(i)); + } + q=new RDSqlQuery(sql); + delete q; + + done(0); +} + + +void EditPerms::cancelData() +{ + done(-1); +} + + +void EditPerms::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/rdlogmanager/edit_perms.h b/rdlogmanager/edit_perms.h new file mode 100644 index 00000000..7e5b19c5 --- /dev/null +++ b/rdlogmanager/edit_perms.h @@ -0,0 +1,61 @@ +// edit_perms.h +// +// Edit RDLogManager Service Associations +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: edit_perms.h,v 1.6.8.1 2012/04/23 17:22:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_PERMS_H +#define EDIT_PERMS_H + +#include +#include + +#include + +#include + + +class EditPerms : public QDialog +{ + Q_OBJECT + public: + enum ObjectType {ObjectEvent=1,ObjectClock=2}; + EditPerms(QString object_name,ObjectType type, + QWidget *parent=0,const char *name=0); + ~EditPerms(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + RDListSelector *svc_object_sel; + ObjectType sel_type; + QString sel_name; + QString object_type; +}; + + +#endif + diff --git a/rdlogmanager/edit_schedcoderules.cpp b/rdlogmanager/edit_schedcoderules.cpp new file mode 100644 index 00000000..37878037 --- /dev/null +++ b/rdlogmanager/edit_schedcoderules.cpp @@ -0,0 +1,199 @@ +// edit_schedcoderules.cpp +// +// Change rules for scheduler codes dialog +// +// Stefan Gabriel +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + + + +editSchedCodeRules::editSchedCodeRules(QListViewItem *item,SchedRulesList *sched_rules_list, QWidget* parent, const char* name) + : QDialog( parent, name, true) +{ + item_edit = item; + + if ( !name ) + setName( "editSchedCodeRules" ); + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Edit Rules for Code")); + + + // Create Font + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + + buttonOk = new QPushButton( this, "buttonOk" ); + buttonOk->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + buttonOk->setText( tr( "&OK" ) ); + buttonOk->setDefault( true ); + buttonOk->setFont( font ); + connect( buttonOk, SIGNAL( clicked() ), this, SLOT( okData() ) ); + + buttonCancel = new QPushButton( this, "buttonCancel" ); + buttonCancel->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + buttonCancel->setText( tr( "&Cancel" ) ); + buttonCancel->setFont( font ); + connect( buttonCancel, SIGNAL( clicked() ), this, SLOT( cancelData() ) ); + + label_code_name = new QLabel( this, "label_code_name" ); + label_code_name->setGeometry( QRect( 40, 10, 150, 20 ) ); + label_code_name->setText( tr( "Code:" ) ); + label_code_name->setFont( font ); + label_code_name->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + label_max_row = new QLabel( this, "label_max_row" ); + label_max_row->setGeometry( QRect( 30, 80, 160, 20 ) ); + label_max_row->setText( tr( "Max. in a row:" ) ); + label_max_row->setFont( font ); + label_max_row->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + label_min_wait = new QLabel( this, "label_min_wait" ); + label_min_wait->setGeometry( QRect( 30, 110, 160, 20 ) ); + label_min_wait->setText( tr( "Min. wait:" ) ); + label_min_wait->setFont( font ); + label_min_wait->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + label_not_after = new QLabel( this, "label_not_after" ); + label_not_after->setGeometry( QRect( 30, 140, 160, 20 ) ); + label_not_after->setText( tr( "Do not schedule after:" ) ); + label_not_after->setFont( font ); + label_not_after->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + label_or_after = new QLabel( this, "label_or_after" ); + label_or_after->setGeometry( QRect( 30, 180, 160, 20 ) ); + label_or_after->setText( tr( "Or after:" ) ); + label_or_after->setFont( font ); + label_or_after->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + label_or_after_II = new QLabel( this, "label_or_after_II" ); + label_or_after_II->setGeometry( QRect( 30, 220, 160, 20 ) ); + label_or_after_II->setText( tr( "Or after:" ) ); + label_or_after_II->setFont( font ); + label_or_after_II->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) ); + + spinBox_max_row = new QSpinBox( this, "spinBox_max_row" ); + spinBox_max_row->setGeometry( QRect( 200, 80, 70, 20 ) ); + spinBox_max_row->setMaxValue( 999 ); + spinBox_max_row->setLineStep( 1 ); + spinBox_max_row->setValue( item->text(1).toInt() ); + + spinBox_min_wait = new QSpinBox( this, "spinBox_min_wait" ); + spinBox_min_wait->setGeometry( QRect( 200, 110, 70, 20 ) ); + spinBox_min_wait->setMaxValue( 999 ); + spinBox_max_row->setLineStep( 1 ); + spinBox_min_wait->setValue( item->text(2).toInt() ); + + label_code = new QLabel( this, "label_code" ); + label_code->setGeometry( QRect( 200, 10, 90, 20 ) ); + label_code->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignLeft ) ); + label_code->setText( item->text(0) ); + + comboBox_not_after = new QComboBox( FALSE, this, "comboBox_not_after" ); + comboBox_not_after->setGeometry( QRect( 200, 140, 180, 30 ) ); + comboBox_not_after->setDuplicatesEnabled( FALSE ); + + comboBox_or_after = new QComboBox( FALSE, this, "comboBox_or_after" ); + comboBox_or_after->setGeometry( QRect( 200, 180, 180, 30 ) ); + comboBox_or_after->setDuplicatesEnabled( FALSE ); + + comboBox_or_after_II = new QComboBox( FALSE, this, "comboBox_or_after_II" ); + comboBox_or_after_II->setGeometry( QRect( 200, 220, 180, 30 ) ); + comboBox_or_after_II->setDuplicatesEnabled( FALSE ); + + comboBox_not_after->insertItem(""); + comboBox_or_after->insertItem(""); + comboBox_or_after_II->insertItem(""); + for (int i=0; igetNumberOfItems(); i++) + { + comboBox_not_after->insertItem(sched_rules_list->getItemSchedCode(i)); + comboBox_or_after->insertItem(sched_rules_list->getItemSchedCode(i)); + comboBox_or_after_II->insertItem(sched_rules_list->getItemSchedCode(i)); + } + comboBox_not_after->setCurrentText(item->text(3)); + comboBox_or_after->setCurrentText(item->text(4)); + comboBox_or_after->setCurrentText(item->text(5)); + + label_description = new QLabel( this, "label_description" ); + label_description->setGeometry( QRect( 200, 40, 300, 40 ) ); + label_description->setAlignment( int( QLabel::AlignTop | QLabel::AlignLeft ) ); + label_description->setText( item->text(6) ); +} + + +editSchedCodeRules::~editSchedCodeRules() +{ +} + +QSize editSchedCodeRules::sizeHint() const +{ + return QSize(500,350); +} + + +QSizePolicy editSchedCodeRules::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + + +void editSchedCodeRules::okData() +{ + item_edit->setText(1,spinBox_max_row->text()); + item_edit->setText(2,spinBox_min_wait->text()); + item_edit->setText(3,comboBox_not_after->currentText()); + item_edit->setText(4,comboBox_or_after->currentText()); + item_edit->setText(5,comboBox_or_after_II->currentText()); + done(0); +} + + +void editSchedCodeRules::cancelData() +{ + done(-1); +} + + +void editSchedCodeRules::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/rdlogmanager/edit_schedcoderules.h b/rdlogmanager/edit_schedcoderules.h new file mode 100644 index 00000000..4a5c90cc --- /dev/null +++ b/rdlogmanager/edit_schedcoderules.h @@ -0,0 +1,77 @@ +// edit_schedcoderules.h +// +// Change rules for scheduler codes dialog +// +// Stefan Gabriel +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + + +#ifndef EDIT_SCHEDCODERULES_H +#define EDIT_SCHEDCODERULES_H + +#include +#include +#include +#include +#include +#include + +#include +#include + +class QSpinBox; + +class editSchedCodeRules : public QDialog +{ + Q_OBJECT + +public: + editSchedCodeRules(QListViewItem *item, SchedRulesList *sched_rules_list, QWidget* parent = 0, const char* name = 0); + ~editSchedCodeRules(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + +private: + QPushButton* buttonOk; + QPushButton* buttonCancel; + QLabel* label_code_name; + QLabel* label_max_row; + QLabel* label_min_wait; + QLabel* label_not_after; + QLabel* label_or_after; + QLabel* label_or_after_II; + QSpinBox* spinBox_max_row; + QSpinBox* spinBox_min_wait; + QLabel* label_code; + QComboBox* comboBox_not_after; + QComboBox* comboBox_or_after; + QComboBox* comboBox_or_after_II; + QLabel* label_description; + QListViewItem *item_edit; + + private slots: + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); +}; + +#endif + diff --git a/rdlogmanager/edit_schedrules.cpp b/rdlogmanager/edit_schedrules.cpp new file mode 100644 index 00000000..10ece584 --- /dev/null +++ b/rdlogmanager/edit_schedrules.cpp @@ -0,0 +1,299 @@ +// edit_schedrules.cpp +// +// Edit scheduler rules of a clock +// +// Stefan Gabriel +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + + +EditSchedRules::EditSchedRules(QString clock,unsigned *artistsep,SchedRulesList *schedruleslist,bool *rules_modified,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_artistsep=artistsep; + edit_rules_modified=rules_modified; + sched_rules_list = schedruleslist; + clockname = clock; + + + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("Scheduler Rules")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + artistSepLabel = new QLabel( this, "artistSepLabel" ); + artistSepLabel->setGeometry( QRect( 10, 10, 130, 20 ) ); + artistSepLabel->setFont(font); + artistSepLabel->setText(tr("Artist Separation:")); + + artistSepSpinBox = new QSpinBox( this, "artistSepSpinBox" ); + artistSepSpinBox->setGeometry( QRect( 160, 10, 70, 20 ) ); + artistSepSpinBox->setMaxValue( 10000 ); + artistSepSpinBox->setValue( *edit_artistsep ); + + + // + // Edit Button + // + QPushButton *list_edit_button=new QPushButton(this,"list_edit_button"); + list_edit_button->setGeometry(10,sizeHint().height()-60,80,50); + list_edit_button->setFont(font); + list_edit_button->setText(tr("&Edit")); + connect(list_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Import Button + // + QPushButton *list_import_button=new QPushButton(this,"list_import_button"); + list_import_button->setGeometry(100,sizeHint().height()-60,80,50); + list_import_button->setFont(font); + list_import_button->setText(tr("&Import")); + connect(list_import_button,SIGNAL(clicked()),this,SLOT(importData())); + + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + + // List + list_schedCodes_view=new QListView(this,"list_schedCodes_view"); + list_schedCodes_view->setGeometry(10,60,size().width()-20,size().height()-140); + list_schedCodes_view->setAllColumnsShowFocus(true); + list_schedCodes_view->addColumn(tr("CODE")); + list_schedCodes_view->addColumn(tr("MAX. IN A ROW")); + list_schedCodes_view->addColumn(tr("MIN. WAIT")); + list_schedCodes_view->addColumn(tr("DO NOT SCHEDULE AFTER")); + list_schedCodes_view->addColumn(tr("OR AFTER")); + list_schedCodes_view->addColumn(tr("OR AFTER")); + list_schedCodes_view->addColumn(tr("DESCRIPTION")); + + QLabel *list_box_label=new QLabel(list_schedCodes_view,tr("Scheduler Codes:"),this,"list_box_label"); + list_box_label->setFont(font); + list_box_label->setGeometry(10,40,200,20); + connect(list_schedCodes_view, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + edit_modified=false; + Load(); +} + + +EditSchedRules::~EditSchedRules() +{ +} + + +QSize EditSchedRules::sizeHint() const +{ + return QSize(650,450); +} + + +QSizePolicy EditSchedRules::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + +void EditSchedRules::Load() +{ + QString str; + QListViewItem *item; + + list_schedCodes_view->clear(); + for (int i=0; igetNumberOfItems(); i++) + { + item=new QListViewItem(list_schedCodes_view); + item->setText(0,sched_rules_list->getItemSchedCode(i)); + str=QString().sprintf("%d",sched_rules_list->getItemMaxRow(i)); + item->setText(1,str); + str=QString().sprintf("%d",sched_rules_list->getItemMinWait(i)); + item->setText(2,str); + item->setText(3,sched_rules_list->getItemNotAfter(i)); + item->setText(4,sched_rules_list->getItemOrAfter(i)); + item->setText(5,sched_rules_list->getItemOrAfterII(i)); + item->setText(6,sched_rules_list->getItemDescription(i)); + } +} + + +void EditSchedRules::Close() +{ + QListViewItem *item; + int number_of_items; + + number_of_items = list_schedCodes_view->childCount(); + + *edit_rules_modified=true; + + for (int i=0; i< number_of_items; i++) + { + item=list_schedCodes_view->firstChild(); + sched_rules_list->insertItem(i,item->text(1).toInt(),item->text(2).toInt(),item->text(3),item->text(4),item->text(5)); + list_schedCodes_view->takeItem(item); + } +} + + +void EditSchedRules::editData() +{ + QListViewItem *item=list_schedCodes_view->selectedItem(); + if(item==NULL) { + return; + } + editSchedCodeRules *edit_CodeRules=new editSchedCodeRules(item,sched_rules_list,this,"edit_CodeRules"); + if(edit_CodeRules->exec()>=0) + { + edit_modified=true; + } + delete edit_CodeRules; + edit_CodeRules=NULL; +} + + +void EditSchedRules::importData() +{ + QString clockname = ""; + QString str; + QListViewItem *item; + QString sql; + RDSqlQuery *q; + + ListClocks *listclocks=new ListClocks(&clockname,this,"listclocks"); + listclocks->setCaption(tr("Import Rules from Clock")); + if(listclocks->exec()<0) { + delete listclocks; + return; + } + delete listclocks; + SchedRulesList *import_list=new SchedRulesList(clockname); + + list_schedCodes_view->clear(); + for (int i=0; igetNumberOfItems(); i++) + { + item=new QListViewItem(list_schedCodes_view); + item->setText(0,import_list->getItemSchedCode(i)); + str=QString().sprintf("%d",import_list->getItemMaxRow(i)); + item->setText(1,str); + str=QString().sprintf("%d",import_list->getItemMinWait(i)); + item->setText(2,str); + item->setText(3,import_list->getItemNotAfter(i)); + item->setText(4,import_list->getItemOrAfter(i)); + item->setText(5,import_list->getItemOrAfterII(i)); + item->setText(6,import_list->getItemDescription(i)); + } + delete import_list; + + sql=QString().sprintf("select ARTISTSEP from CLOCKS where NAME=\"%s\"",(const char *)clockname); + q=new RDSqlQuery(sql); + if (q->first()) + { + *edit_artistsep = q->value(0).toUInt(); + artistSepSpinBox->setValue( *edit_artistsep ); + } + delete q; + edit_modified=true; +} + + +void EditSchedRules::doubleClickedData(QListViewItem *item,const QPoint &pt,int col) +{ + editData(); +} + + + +void EditSchedRules::okData() +{ + *edit_artistsep = artistSepSpinBox->value(); + Close(); + done(0); +} + + +void EditSchedRules::cancelData() +{ + if(edit_modified) { + switch(QMessageBox::question(this,tr("Rules Modified"), + tr("The rules have been modified.\nDo you want to save?"),QMessageBox::Yes,QMessageBox::No,QMessageBox::Cancel)) { + case QMessageBox::Yes: + Close(); + done(0); + break; + + case QMessageBox::No: + done(-1); + break; + + case QMessageBox::NoButton: + return; + } + } + else { + done(-1); + } +} + + +void EditSchedRules::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/rdlogmanager/edit_schedrules.h b/rdlogmanager/edit_schedrules.h new file mode 100644 index 00000000..554f0d7c --- /dev/null +++ b/rdlogmanager/edit_schedrules.h @@ -0,0 +1,72 @@ +// edit_schedrules.h +// +// Edit scheduler rules of a clock +// +// Stefan Gabriel +// +// +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_SCHEDRULES_H +#define EDIT_SCHEDRULES_H + +#include +#include +#include +#include +#include +#include + +#include + +class QSpinBox; + +class EditSchedRules : public QDialog +{ + Q_OBJECT + public: + EditSchedRules(QString clock,unsigned *artistsep,SchedRulesList *schedruleslist,bool *rules_modified,QWidget *parent=0,const char *name=0); + ~EditSchedRules(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void editData(); + void importData(); + void doubleClickedData(QListViewItem *item,const QPoint &pt,int col); + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + void Load(); + void Close(); + QLabel* artistSepLabel; + QSpinBox* artistSepSpinBox; + QListView *list_schedCodes_view; + QString clockname; + unsigned* edit_artistsep; + bool* edit_rules_modified; + SchedRulesList* sched_rules_list; + bool edit_modified; +}; + + + +#endif + diff --git a/rdlogmanager/edit_track.cpp b/rdlogmanager/edit_track.cpp new file mode 100644 index 00000000..a3a445d5 --- /dev/null +++ b/rdlogmanager/edit_track.cpp @@ -0,0 +1,115 @@ +// edit_track.cpp +// +// Edit a Rivendell LogManager Track +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_track.cpp,v 1.6.8.1 2012/04/23 17:22:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +EditTrack::EditTrack(QString *text,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + setCaption(tr("Edit Voice Track Marker")); + edit_text=text; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // The Text Editor + // + edit_text_edit=new QTextEdit(this,"edit_text_edit"); + edit_text_edit->setGeometry(10,10, + sizeHint().width()-20,sizeHint().height()-80); + edit_text_edit->setText(*edit_text); + + // + // OK Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +QSize EditTrack::sizeHint() const +{ + return QSize(400,250); +} + + +QSizePolicy EditTrack::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void EditTrack::okData() +{ + *edit_text=edit_text_edit->text(); + done(0); +} + + +void EditTrack::cancelData() +{ + done(-1); +} + + +void EditTrack::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/rdlogmanager/edit_track.h b/rdlogmanager/edit_track.h new file mode 100644 index 00000000..acc245f0 --- /dev/null +++ b/rdlogmanager/edit_track.h @@ -0,0 +1,53 @@ +// edit_track.h +// +// Edit a Rivendell LogManager Track +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: edit_track.h,v 1.5.8.1 2012/04/23 17:22:47 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EDIT_TRACK_H +#define EDIT_TRACK_H + +#include +#include +#include + + +class EditTrack : public QDialog +{ + Q_OBJECT + public: + EditTrack(QString *text,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + protected: + void closeEvent(QCloseEvent *e); + + private: + QString *edit_text; + QTextEdit *edit_text_edit; +}; + + +#endif // EDIT_TRACK_H + diff --git a/rdlogmanager/generate_log.cpp b/rdlogmanager/generate_log.cpp new file mode 100644 index 00000000..8f1f6c10 --- /dev/null +++ b/rdlogmanager/generate_log.cpp @@ -0,0 +1,587 @@ +// generate_log.cpp +// +// Generate a Rivendell Log +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: generate_log.cpp,v 1.37.6.2 2014/01/10 21:59:32 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// +// Icons +// +#include "../icons/whiteball.xpm" +#include "../icons/greenball.xpm" +#include "../icons/redball.xpm" + + +GenerateLog::GenerateLog(QWidget *parent,const char *name,int cmd_switch,QString *cmd_service,QDate *cmd_date) + : QDialog(parent,name,true) +{ + QStringList services_list; + bool cmdservicefit=false; + cmdswitch=cmd_switch; + cmdservice = cmd_service; + cmddate = cmd_date; + + QString str1=tr("Generate Log - User: "); + setCaption(QString().sprintf("%s%s",(const char *)str1, + (const char *)rdripc->user())); + + gen_music_enabled=false; + gen_traffic_enabled=false; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + QFont small_font=QFont("Helvetica",10,QFont::Bold); + small_font.setPixelSize(10); + + // + // Create Icons + // + gen_whiteball_map=new QPixmap(whiteball_xpm); + gen_greenball_map=new QPixmap(greenball_xpm); + gen_redball_map=new QPixmap(redball_xpm); + + // + // Progress Dialog + // + gen_progress_dialog=new QProgressDialog(tr("Generating Log..."),tr("Cancel"), + 24,this,"gen_progress_dialog",true); + gen_progress_dialog->setCaption("Progress"); + gen_progress_dialog->setCancelButton(NULL); + + // + // Service Name + // + gen_service_box=new QComboBox(this,"gen_service_box"); + gen_service_box->setGeometry(70,10,sizeHint().width()-80,20); + connect(gen_service_box,SIGNAL(activated(int)), + this,SLOT(serviceActivatedData(int))); + QLabel *label=new QLabel(gen_service_box,tr("Service:"), + this,"gen_service_label"); + label->setGeometry(10,10,55,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec) { + services_list = rduser->services(); + } else { // RDStation::HostSec + QString sql="select NAME from SERVICES"; + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + services_list.append( q->value(0).toString() ); + } + delete q; + } + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end(); + ++it ) { + gen_service_box->insertItem(*it); + if (cmdswitch != 0 && *cmdservice == *it) + cmdservicefit=true; + } + + // + // Date + // + gen_date_edit=new QDateEdit(this,"gen_date_edit"); + gen_date_edit->setGeometry(70,38,100,20); + label=new QLabel(gen_date_edit,tr("Date:"), + this,"gen_date_label"); + label->setGeometry(10,38,55,20); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter); + if (cmdswitch==0) + gen_date_edit->setDate(QDate::currentDate().addDays(1)); + else + gen_date_edit->setDate(*cmddate); + + connect(gen_date_edit,SIGNAL(valueChanged(const QDate &)), + this,SLOT(dateChangedData(const QDate &))); + + // + // Date Select Button + // + QPushButton *button=new QPushButton(this,"select_button"); + button->setGeometry(180,33,50,30); + button->setFont(bold_font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectDateData())); + + // + // Create Log Button + // + gen_create_button=new QPushButton(this,"gen_create_button"); + gen_create_button->setGeometry(10,70,sizeHint().width()-20,30); + gen_create_button->setFont(bold_font); + gen_create_button->setText(tr("&Create New Log")); + connect(gen_create_button,SIGNAL(clicked()),this,SLOT(createData())); + + // + // Merge Music Log Button + // + gen_music_button=new QPushButton(this,"gen_music_button"); + gen_music_button->setGeometry(10,130,100,30); + gen_music_button->setFont(bold_font); + gen_music_button->setText(tr("Merge &Music")); + connect(gen_music_button,SIGNAL(clicked()),this,SLOT(musicData())); + + // + // Merge Traffic Log Button + // + gen_traffic_button=new QPushButton(this,"gen_traffic_button"); + gen_traffic_button->setGeometry(10,170,100,30); + gen_traffic_button->setFont(bold_font); + gen_traffic_button->setText(tr("Merge &Traffic")); + connect(gen_traffic_button,SIGNAL(clicked()),this,SLOT(trafficData())); + + // + // Status Lights + // + // Headers + // + label=new QLabel(tr("Import Data"),this); + label->setGeometry(120,105,120,14); + label->setFont(bold_font); + label->setAlignment(AlignCenter); + + label=new QLabel(tr("Available"),this); + label->setGeometry(120,119,60,14); + label->setFont(small_font); + label->setAlignment(AlignCenter); + + label=new QLabel(tr("Merged"),this); + label->setGeometry(180,119,60,14); + label->setFont(small_font); + label->setAlignment(AlignCenter); + + // + // Music Indicators + // + gen_mus_avail_label=new QLabel(this,"gen_mus_avail_label"); + gen_mus_avail_label->setPixmap(*gen_whiteball_map); + gen_mus_avail_label->setGeometry(120,139,60,14); + gen_mus_avail_label->setFont(small_font); + gen_mus_avail_label->setAlignment(AlignCenter); + + gen_mus_merged_label=new QLabel(this,"gen_mus_merged_label"); + gen_mus_merged_label->setPixmap(*gen_whiteball_map); + gen_mus_merged_label->setGeometry(180,139,60,14); + gen_mus_merged_label->setFont(small_font); + gen_mus_merged_label->setAlignment(AlignCenter); + + // + // Traffic Indicators + // + gen_tfc_avail_label=new QLabel(this,"gen_tfc_avail_label"); + gen_tfc_avail_label->setPixmap(*gen_whiteball_map); + gen_tfc_avail_label->setGeometry(120,179,60,14); + gen_tfc_avail_label->setFont(small_font); + gen_tfc_avail_label->setAlignment(AlignCenter); + + gen_tfc_merged_label=new QLabel(this,"gen_tfc_merged_label"); + gen_tfc_merged_label->setPixmap(*gen_whiteball_map); + gen_tfc_merged_label->setGeometry(180,179,60,14); + gen_tfc_merged_label->setFont(small_font); + gen_tfc_merged_label->setAlignment(AlignCenter); + + + // + // Close Button + // + button=new QPushButton(this,"close_button"); + button->setGeometry(10,sizeHint().height()-60,sizeHint().width()-20,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("C&lose")); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); + + UpdateControls(); + + // + // File Scan Timer + // + QTimer *timer=new QTimer(this,"file_scan_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(fileScanData())); + timer->start(GENERATE_LOG_FILESCAN_INTERVAL); + + if(cmdswitch==1 && cmdservicefit) + { + gen_service_box->setCurrentText(*cmdservice); + createData(); + } + if(cmdswitch==2 && cmdservicefit) + { + gen_service_box->setCurrentText(*cmdservice); + musicData(); + } + if(cmdswitch==3 && cmdservicefit) + { + gen_service_box->setCurrentText(*cmdservice); + trafficData(); + } +} + + +QSize GenerateLog::sizeHint() const +{ + return QSize(240,270); +} + + +QSizePolicy GenerateLog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void GenerateLog::serviceActivatedData(int index) +{ + UpdateControls(); +} + + +void GenerateLog::dateChangedData(const QDate &date) +{ + UpdateControls(); +} + + +void GenerateLog::selectDateData() +{ + QDate date=gen_date_edit->date(); + QDate current_date=QDate::currentDate(); + + RDDateDialog *datedialog= + new RDDateDialog(current_date.year(),current_date.year()+1, + this,"datedialog"); + if(datedialog->exec(&date)<0) { + delete datedialog; + return; + } + gen_date_edit->setDate(date); + delete datedialog; + UpdateControls(); +} + + +void GenerateLog::createData() +{ + QString report; + QString unused_report; + QString str1; + QString str2; + unsigned tracks=0; + + // + // Generate Log + // + RDSvc *svc=new RDSvc(gen_service_box->currentText(),this,"svc"); + QString logname=RDDateDecode(svc->nameTemplate(),gen_date_edit->date()); + RDLog *log=new RDLog(logname); + if(log->exists()) { + str1=QString(tr("The log for")); + str2=QString(tr("already exists. Recreating it\nwill remove any merged Music or Traffic events.\n\nRecreate?")); + if(QMessageBox::question(this,tr("Log Exists"), + QString().sprintf("%s %s %s",(const char *)str1, + (const char *)gen_date_edit->date().toString("MM/dd/yyyy"), + (const char *)str2), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + delete log; + delete svc; + return; + } + if((tracks=log->completedTracks())>0) { + str1=QString(tr("This will also delete the")); + str2=QString(tr("voice tracks associated with this log.\nContinue?")); + if(QMessageBox::warning(this,tr("Tracks Exist"), + QString().sprintf("%s %u %s", + (const char *)str1, + tracks, + (const char *)str2), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + delete log; + delete svc; + return; + } + } + } + log->removeTracks(rdstation_conf,rduser,log_config); + + // + // Scheduler + // + QString sql; + RDSqlQuery *q; + + srand(QTime::currentTime().msec()); + sql=RDCreateStackTableSql(gen_service_box->currentText().replace(" ","_")); + + q=new RDSqlQuery(sql); + if(!q->isActive()) { + fprintf(stderr,"SQL: %s\n",(const char *)sql); + fprintf(stderr,"SQL Error: %s\n", + (const char *)q->lastError().databaseText()); + delete q; + } + delete q; + + connect(svc,SIGNAL(generationProgress(int)), + gen_progress_dialog,SLOT(setProgress(int))); + svc->generateLog(gen_date_edit->date(), + RDDateDecode(svc->nameTemplate(),gen_date_edit->date()), + RDDateDecode(svc->nameTemplate(),gen_date_edit->date(). + addDays(1)),&unused_report); + log->updateTracks(); + delete log; + delete svc; + + // + // Generate Exception Report + // + RDLogEvent *event= + new RDLogEvent(QString().sprintf("%s_LOG",(const char *)logname)); + event->load(); + if((event->validate(&report,gen_date_edit->date())==0)&& + unused_report.isEmpty()) { + QMessageBox::information(this,tr("No Errors"),tr("No exceptions found.")); + } + else { + RDTextFile(report+"\n\n"+unused_report); + } + delete event; + + UpdateControls(); +} + + +void GenerateLog::musicData() +{ + unsigned tracks=0; + + RDSvc *svc=new RDSvc(gen_service_box->currentText(),this,"svc"); + QString logname=RDDateDecode(svc->nameTemplate(),gen_date_edit->date()); + RDLog *log=new RDLog(logname); + if(((log->linkState(RDLog::SourceMusic)==RDLog::LinkDone)|| + (log->linkState(RDLog::SourceTraffic)==RDLog::LinkDone))) { + QString str1=QString(tr("The log for")); + QString str2=QString(tr("already contains merged music and/or traffic data.\nRemerging it will remove this data. Remerge?")); + if(QMessageBox::question(this,tr("Music Exists"), + QString().sprintf("%s %s %s",(const char *)str1, + (const char *)gen_date_edit->date().toString("MM/dd/yyyy"), + (const char *)str2), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + delete log; + delete svc; + return; + } + if((tracks=log->completedTracks())>0) { + str1=QString(tr("This will also delete the")); + str2=QString(tr("voice tracks associated with this log.\nContinue?")); + if(QMessageBox::warning(this,tr("Tracks Exist"), + QString().sprintf("%s %u %s", + (const char *)str1, + tracks, + (const char *)str2), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + delete log; + delete svc; + return; + } + } + log->removeTracks(rdstation_conf,rduser,log_config); + svc->clearLogLinks(RDSvc::Traffic,gen_date_edit->date(),logname); + svc->clearLogLinks(RDSvc::Music,gen_date_edit->date(),logname); + } + connect(svc,SIGNAL(generationProgress(int)), + gen_progress_dialog,SLOT(setProgress(int))); + QString report; + svc->linkLog(RDSvc::Music,gen_date_edit->date(),logname,&report); + delete log; + delete svc; + if(!report.isEmpty()) { + RDTextFile(report); + } + UpdateControls(); +} + + +void GenerateLog::trafficData() +{ + RDSvc *svc=new RDSvc(gen_service_box->currentText(),this,"svc"); + QString logname=RDDateDecode(svc->nameTemplate(),gen_date_edit->date()); + RDLog *log=new RDLog(logname); + if((log->linkState(RDLog::SourceTraffic)==RDLog::LinkDone)) { + QString str1=QString(tr("The log for")); + QString str2=QString(tr("already contains merged traffic data. Remerging it\nwill remove this data. Remerge?")); + if(QMessageBox::question(this,tr("Traffic Exists"), + QString().sprintf("%s %s %s",(const char *)str1, + (const char *)gen_date_edit->date().toString("MM/dd/yyyy"), + (const char *)str2), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + delete log; + delete svc; + return; + } + svc->clearLogLinks(RDSvc::Traffic,gen_date_edit->date(),logname); + } + connect(svc,SIGNAL(generationProgress(int)), + gen_progress_dialog,SLOT(setProgress(int))); + + QString report; + svc->linkLog(RDSvc::Traffic,gen_date_edit->date(),logname,&report); + delete log; + delete svc; + if(!report.isEmpty()) { + RDTextFile(report); + } + UpdateControls(); +} + + +void GenerateLog::fileScanData() +{ + RDSvc *svc=new RDSvc(gen_service_box->currentText(),this,"svc"); + QString logname=RDDateDecode(svc->nameTemplate(),gen_date_edit->date()); + RDLog *log=new RDLog(logname); + if(gen_music_enabled) { + if(QFile::exists(svc-> + importFilename(RDSvc::Music,gen_date_edit->date()))) { + gen_music_button->setEnabled(true); + gen_mus_avail_label->setPixmap(*gen_greenball_map); + } + else { + gen_music_button->setDisabled(true); + gen_mus_avail_label->setPixmap(*gen_redball_map); + } + } + else { + gen_mus_avail_label->setPixmap(*gen_whiteball_map); + } + if(gen_traffic_enabled) { + if(QFile::exists(svc-> + importFilename(RDSvc::Traffic,gen_date_edit->date()))) { + gen_traffic_button-> + setEnabled((!gen_music_enabled)|| + (log->linkState(RDLog::SourceMusic)==RDLog::LinkDone)); + gen_tfc_avail_label->setPixmap(*gen_greenball_map); + } + else { + gen_traffic_button->setDisabled(true); + gen_tfc_avail_label->setPixmap(*gen_redball_map); + } + } + else { + gen_tfc_avail_label->setPixmap(*gen_whiteball_map); + } + delete log; + delete svc; +} + + +void GenerateLog::closeData() +{ + done(0); +} + + +void GenerateLog::UpdateControls() +{ + RDSvc *svc=new RDSvc(gen_service_box->currentText(),this,"svc"); + QString logname=RDDateDecode(svc->nameTemplate(),gen_date_edit->date()); + RDLog *log=new RDLog(logname); + if(log->exists()) { + if(log->linkQuantity(RDLog::SourceMusic)>0) { + gen_music_enabled=true; + if(log->linkState(RDLog::SourceMusic)==RDLog::LinkDone) { + gen_mus_merged_label->setPixmap(*gen_greenball_map); + } + else { + gen_mus_merged_label->setPixmap(*gen_redball_map); + } + } + else { + gen_music_enabled=false; + gen_mus_merged_label->setPixmap(*gen_whiteball_map); + } + if(log->linkQuantity(RDLog::SourceTraffic)>0) { + gen_traffic_enabled=true; + if(log->linkState(RDLog::SourceTraffic)==RDLog::LinkDone) { + gen_tfc_merged_label->setPixmap(*gen_greenball_map); + } + else { + gen_tfc_merged_label->setPixmap(*gen_redball_map); + } + } + else { + gen_traffic_enabled=false; + gen_tfc_merged_label->setPixmap(*gen_whiteball_map); + } + } + else { + gen_music_button->setDisabled(true); + gen_mus_merged_label->setPixmap(*gen_whiteball_map); + gen_traffic_button->setDisabled(true); + gen_tfc_merged_label->setPixmap(*gen_whiteball_map); + gen_music_enabled=false; + gen_traffic_enabled=false; + } + delete log; + delete svc; + fileScanData(); +} diff --git a/rdlogmanager/generate_log.h b/rdlogmanager/generate_log.h new file mode 100644 index 00000000..1874783c --- /dev/null +++ b/rdlogmanager/generate_log.h @@ -0,0 +1,79 @@ +// generate_log.h +// +// Generate a Rivendell Log +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: generate_log.h,v 1.9 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef GENERATE_LOG_H +#define GENERATE_LOG_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#define GENERATE_LOG_FILESCAN_INTERVAL 5000 + +class GenerateLog : public QDialog +{ + Q_OBJECT + public: + GenerateLog(QWidget *parent=0,const char *name=0,int cmd_schwitch=0,QString *cmd_service=NULL,QDate *cmd_date=NULL); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void serviceActivatedData(int index); + void dateChangedData(const QDate &date); + void selectDateData(); + void createData(); + void musicData(); + void trafficData(); + void fileScanData(); + void closeData(); + + private: + void UpdateControls(); + QComboBox *gen_service_box; + QDateEdit *gen_date_edit; + QProgressDialog *gen_progress_dialog; + QPushButton *gen_create_button; + QPushButton *gen_music_button; + QPushButton *gen_traffic_button; + QLabel *gen_tfc_avail_label; + QLabel *gen_tfc_merged_label; + QLabel *gen_mus_avail_label; + QLabel *gen_mus_merged_label; + QPixmap *gen_whiteball_map; + QPixmap *gen_greenball_map; + QPixmap *gen_redball_map; + bool gen_music_enabled; + bool gen_traffic_enabled; + int cmdswitch; + QString *cmdservice; + QDate *cmddate; +}; + + +#endif + diff --git a/rdlogmanager/globals.h b/rdlogmanager/globals.h new file mode 100644 index 00000000..b70970b2 --- /dev/null +++ b/rdlogmanager/globals.h @@ -0,0 +1,44 @@ +// globals.h +// +// Global Variable Declarations for RDLogManager +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: globals.h,v 1.7.4.1 2013/11/13 23:36:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef GLOBALS_H +#define GLOBALS_H + +#include +#include +#include +#include +#include + +// +// Global Resources +// +extern RDStation *rdstation_conf; +extern RDUser *rduser; +extern RDRipc *rdripc; +extern RDCae *rdcae; +extern RDConfig *log_config; +extern QString *event_filter; +extern QString *clock_filter; +extern bool skip_db_check; + +#endif // GLOBALS_H diff --git a/rdlogmanager/import_listview.cpp b/rdlogmanager/import_listview.cpp new file mode 100644 index 00000000..204f9b13 --- /dev/null +++ b/rdlogmanager/import_listview.cpp @@ -0,0 +1,488 @@ +// import_listview.cpp +// +// The Import Carts ListView widget for RDLogManager. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: import_listview.cpp,v 1.21.8.2 2013/12/30 19:56:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +// +// Icons +// +#include "../icons/play.xpm" +#include "../icons/rml5.xpm" +#include "../icons/mic16.xpm" +#include "../icons/notemarker.xpm" + + +ImportListView::ImportListView(QWidget *parent,const char *name) + : QListView(parent,name) +{ + import_parent=parent; + + // + // Create Icons + // + import_playout_map=new QPixmap(play_xpm); + import_macro_map=new QPixmap(rml5_xpm); + import_notemarker_map=new QPixmap(notemarker_xpm); + import_mic16_map=new QPixmap(mic16_xpm); + + // + // Right Button Menu + // + import_menu=new QPopupMenu(this,"import_menu"); + connect(import_menu,SIGNAL(aboutToShow()),this,SLOT(aboutToShowData())); + import_menu-> + insertItem(tr("Insert Log Note"),this,SLOT(insertNoteMenuData()),0,0); + import_menu-> + insertItem(tr("Edit Log Note"),this,SLOT(editNoteMenuData()),0,1); + import_menu->insertSeparator(); + import_menu-> + insertItem(tr("Insert Voice Track"),this,SLOT(insertTrackMenuData()),0,2); + import_menu-> + insertItem(tr("Edit Voice Track"),this,SLOT(editTrackMenuData()),0,3); + import_menu->insertSeparator(); + import_menu-> + insertItem(tr("Set PLAY Transition"),this,SLOT(playMenuData()),0,4); + import_menu-> + insertItem(tr("Set SEGUE Transition"),this,SLOT(segueMenuData()),0,5); + import_menu-> + insertItem(tr("Set STOP Transition"),this,SLOT(stopMenuData()),0,6); + import_menu->insertSeparator(); + import_menu-> + insertItem(tr("Delete"),this,SLOT(deleteMenuData()),0,8); + + import_force_trans=RDLogLine::NoTrans; + import_allow_stop=true; + import_allow_first_trans=true; + import_log=new RDLogEvent(); + + setAcceptDrops(true); +} + + +void ImportListView::setForceTrans(RDLogLine::TransType trans) +{ + import_force_trans=trans; + validateTransitions(); +} + + +void ImportListView::setAllowStop(bool state) +{ + import_allow_stop=state; +} + + +void ImportListView::setAllowFirstTrans(bool state) +{ + import_allow_first_trans=state; +} + + +RDLogEvent *ImportListView::logEvent() +{ + return import_log; +} + + +void ImportListView::refreshList(int line) +{ + QListViewItem *item; + QListViewItem *select_item=NULL; + QString sql; + RDLogLine *logline; + int total_len=0; + + clear(); + for(int i=import_log->size()-1;i>=0;i--) { + item=new QListViewItem(this); + if((logline=import_log->logLine(i))!=NULL) { + switch(logline->type()) { + case RDLogLine::Cart: + item->setPixmap(0,*import_playout_map); + item->setText(1,QString().sprintf("%06u",logline->cartNumber())); + item->setText(2,logline->groupName()); + item->setText(4,logline->title()); + break; + + case RDLogLine::Macro: + item->setPixmap(0,*import_macro_map); + item->setText(1,QString().sprintf("%06u",logline->cartNumber())); + item->setText(2,logline->groupName()); + item->setText(4,logline->title()); + break; + + case RDLogLine::Marker: + item->setPixmap(0,*import_notemarker_map); + item->setText(2,tr("Marker")); + item->setText(4,tr("[Log Note]")); + break; + + case RDLogLine::Track: + item->setPixmap(0,*import_mic16_map); + item->setText(2,tr("Track")); + item->setText(4,tr("[Voice Track]")); + break; + + default: + break; + } + item->setText(3,RDGetTimeLength(logline->forcedLength(),false,false)); + total_len+=logline->forcedLength(); + switch(logline->transType()) { + case RDLogLine::Play: + item->setText(5,tr("PLAY")); + break; + + case RDLogLine::Segue: + item->setText(5,tr("SEGUE")); + break; + + case RDLogLine::Stop: + item->setText(5,tr("STOP")); + break; + + default: + break; + } + item->setText(6,QString().sprintf("%d",i)); + if(i==line) { + select_item=item; + } + } + } + if(select_item!=NULL) { + setSelected(select_item,true); + ensureItemVisible(select_item); + } + emit lengthChanged(total_len); +} + + +void ImportListView::validateTransitions() +{ + if(logEvent()->size()>0) { + if(import_force_trans!=RDLogLine::NoTrans) { + logEvent()->logLine(0)->setTransType(import_force_trans); + } + else { + if((logEvent()->logLine(0)->transType()==RDLogLine::Stop)&& + (!import_allow_stop)) { + logEvent()->logLine(0)->setTransType(RDLogLine::Segue); + } + } + } + for(int i=1;isize();i++) { + if(logEvent()->logLine(i)->transType()==RDLogLine::Stop) { + logEvent()->logLine(1)->setTransType(RDLogLine::Segue); + } + } +} + + +void ImportListView::aboutToShowData() +{ + if(import_menu_item==NULL) { + import_menu->setItemChecked(0,false); + import_menu->setItemEnabled(0,true); + import_menu->setItemChecked(1,false); + import_menu->setItemEnabled(1,false); + import_menu->setItemChecked(2,false); + import_menu->setItemEnabled(2,true); + import_menu->setItemChecked(3,false); + import_menu->setItemEnabled(3,false); + import_menu->setItemChecked(4,false); + import_menu->setItemEnabled(4,false); + import_menu->setItemChecked(5,false); + import_menu->setItemEnabled(5,false); + import_menu->setItemChecked(6,false); + import_menu->setItemEnabled(6,false); + import_menu->setItemChecked(7,false); + import_menu->setItemEnabled(7,false); + import_menu->setItemChecked(8,false); + import_menu->setItemEnabled(8,false); + return; + } + if(import_menu_logline->type()==RDLogLine::Marker) { + import_menu->setItemEnabled(1,true); + } + else { + import_menu->setItemEnabled(1,false); + } + if(import_menu_logline->type()==RDLogLine::Track) { + import_menu->setItemEnabled(3,true); + } + else { + import_menu->setItemEnabled(3,false); + } + import_menu->setItemChecked(4,false); + import_menu->setItemChecked(5,false); + import_menu->setItemChecked(6,false); + import_menu->setItemChecked(7,false); + if(import_menu_line==0) { + import_menu->setItemEnabled(4,import_allow_first_trans); + import_menu->setItemEnabled(5,import_allow_first_trans); + import_menu->setItemEnabled(7,import_allow_first_trans); + if((import_menu_line==0)&&import_allow_stop&&import_allow_first_trans) { +// import_menu->setItemEnabled(4,true); + import_menu->setItemEnabled(6,true); + } + else { + import_menu->setItemEnabled(6,false); + } + } + else { + import_menu->setItemEnabled(4,true); + import_menu->setItemEnabled(5,true); + import_menu->setItemEnabled(7,true); + if((import_menu_line==0)&&import_allow_stop) { + import_menu->setItemEnabled(6,true); + import_menu->setItemEnabled(6,true); + } + else { + import_menu->setItemEnabled(6,false); + } + } + switch(import_menu_logline->transType()) { + case RDLogLine::Play: + import_menu->setItemChecked(4,true); + break; + + case RDLogLine::Segue: + import_menu->setItemChecked(5,true); + break; + + case RDLogLine::Stop: + import_menu->setItemChecked(6,true); + break; + + default: + break; + } + import_menu->setItemEnabled(8,true); +} + + +void ImportListView::insertNoteMenuData() +{ + QString note; + EditNote *note_dialog=new EditNote(¬e,this,"note_dialog"); + if(note_dialog->exec()<0) { + delete note_dialog; + return; + } + delete note_dialog; + if(import_menu_item==NULL) { + import_menu_line=0; + } + import_log->insert(import_menu_line,1); + import_log->logLine(import_menu_line)->setType(RDLogLine::Marker); + import_log->logLine(import_menu_line)->setMarkerComment(note); + import_log->logLine(import_menu_line)->setTitle(tr("[Log Note]")); + import_log->logLine(import_menu_line)->setTransType(RDLogLine::Segue); + validateTransitions(); + refreshList(import_menu_line); + emit sizeChanged(childCount()); +} + + +void ImportListView::editNoteMenuData() +{ + QString text=import_log->logLine(import_menu_line)->markerComment(); + EditNote *edit_dialog=new EditNote(&text,this,"edit_dialog"); + if(edit_dialog->exec()<0) { + delete edit_dialog; + return; + } + import_log->logLine(import_menu_line)->setMarkerComment(text); +} + + +void ImportListView::insertTrackMenuData() +{ + QString note; + EditTrack *track_dialog=new EditTrack(¬e,this,"track_dialog"); + if(track_dialog->exec()<0) { + delete track_dialog; + return; + } + delete track_dialog; + if(import_menu_item==NULL) { + import_menu_line=0; + } + import_log->insert(import_menu_line,1); + import_log->logLine(import_menu_line)->setType(RDLogLine::Track); + import_log->logLine(import_menu_line)->setMarkerComment(note); + import_log->logLine(import_menu_line)->setTitle(tr("[Voice Track]")); + import_log->logLine(import_menu_line)->setTransType(RDLogLine::Segue); + validateTransitions(); + refreshList(import_menu_line); + emit sizeChanged(childCount()); +} + + +void ImportListView::editTrackMenuData() +{ + QString text=import_log->logLine(import_menu_line)->markerComment(); + EditTrack *edit_dialog=new EditTrack(&text,this,"edit_dialog"); + if(edit_dialog->exec()<0) { + delete edit_dialog; + return; + } + import_log->logLine(import_menu_line)->setMarkerComment(text); +} + + +void ImportListView::playMenuData() +{ + import_menu_logline->setTransType(RDLogLine::Play); + import_menu_item->setText(5,tr("PLAY")); +} + + +void ImportListView::segueMenuData() +{ + import_menu_logline->setTransType(RDLogLine::Segue); + import_menu_item->setText(5,tr("SEGUE")); +} + + +void ImportListView::stopMenuData() +{ + import_menu_logline->setTransType(RDLogLine::Stop); + import_menu_item->setText(5,tr("STOP")); +} + + +void ImportListView::deleteMenuData() +{ + import_log->remove(import_menu_item->text(6).toInt(),1); + validateTransitions(); + refreshList(); + emit sizeChanged(childCount()); +} + + +void ImportListView::contentsMousePressEvent(QMouseEvent *e) +{ + QListView::contentsMousePressEvent(e); + import_menu_item=selectedItem(); + if(import_menu_item==NULL) { + import_menu_logline=NULL; + } + else { + if((import_menu_logline=import_log-> + logLine(import_menu_line=import_menu_item->text(6).toInt()))==NULL) { + return; + } + } + switch(e->button()) { + case QMouseEvent::RightButton: + import_menu->setGeometry(import_parent->geometry().x()+ + geometry().x()+e->pos().x()+2, + import_parent->geometry().y()+ + geometry().y()+e->pos().y()+ + header()->geometry().height()+2, + import_menu->sizeHint().width(), + import_menu->sizeHint().height()); + import_menu->exec(); + break; + + default: + e->ignore(); + break; + } +} + + +void ImportListView::contentsMouseDoubleClickEvent(QMouseEvent *e) +{ + QListView::contentsMouseDoubleClickEvent(e); + import_menu_item=selectedItem(); + if(import_menu_item==NULL) { + return; + } + if(import_log-> + logLine(import_menu_item->text(6).toInt())->type()==RDLogLine::Marker) { + editNoteMenuData(); + } +} + + +void ImportListView::focusOutEvent(QFocusEvent *e) +{ + QListViewItem *item=selectedItem(); + if(item==NULL) { + return; + } + setSelected(item,false); +} + + +void ImportListView::dragEnterEvent(QDragEnterEvent *e) +{ + e->accept(RDCartDrag::canDecode(e)); +} + + +void ImportListView::dropEvent(QDropEvent *e) +{ + QListViewItem *item; + unsigned cartnum; + int line=0; + QPoint pos(e->pos().x(),e->pos().y()-header()->sectionRect(0).height()); + + if(RDCartDrag::decode(e,&cartnum)) { + if(cartnum==0) { + if((item=itemAt(pos))==NULL) { + return; + } + import_log->remove(item->text(6).toInt(),1); + } + else { + if((item=itemAt(pos))==NULL) { + line=childCount(); + } + else { + line=item->text(6).toInt(); + } + import_log->insert(line,1); + import_log->logLine(line)-> + loadCart(cartnum,RDLogLine::Segue,0,false); + import_log->logLine(line)->setTransType(RDLogLine::Segue); + } + } + validateTransitions(); + refreshList(line); + emit sizeChanged(childCount()); +} diff --git a/rdlogmanager/import_listview.h b/rdlogmanager/import_listview.h new file mode 100644 index 00000000..59fdadcd --- /dev/null +++ b/rdlogmanager/import_listview.h @@ -0,0 +1,86 @@ +// import_listview.h +// +// The Import Carts ListView widget for RDLogManager. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: import_listview.h,v 1.14 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef IMPORT_LISTVIEW_H +#define IMPORT_LISTVIEW_H + +#include +#include +#include + +#include + +class ImportListView : public QListView +{ + Q_OBJECT + + public: + ImportListView(QWidget *parent,const char *name=0); + void setForceTrans(RDLogLine::TransType trans); + void setAllowStop(bool state); + void setAllowFirstTrans(bool state); + RDLogEvent *logEvent(); + void refreshList(int line=-1); + void validateTransitions(); + + signals: + void sizeChanged(int size); + void lengthChanged(int msecs); + + private slots: + void aboutToShowData(); + void insertNoteMenuData(); + void editNoteMenuData(); + void insertTrackMenuData(); + void editTrackMenuData(); + void playMenuData(); + void segueMenuData(); + void stopMenuData(); + void deleteMenuData(); + + protected: + void contentsMousePressEvent(QMouseEvent *e); + void contentsMouseDoubleClickEvent(QMouseEvent *e); + void focusOutEvent(QFocusEvent *e); + void dragEnterEvent(QDragEnterEvent *e); + void dropEvent(QDropEvent *e); + + private: + RDLogEvent *import_log; + QPixmap *import_playout_map; + QPixmap *import_macro_map; + QPixmap *import_notemarker_map; + QPixmap *import_mic16_map; + QPopupMenu *import_menu; + int import_menu_line; + RDLogLine *import_menu_logline; + QListViewItem *import_menu_item; + RDLogLine::TransType import_force_trans; + bool import_allow_stop; + bool import_allow_first_trans; + QWidget *import_parent; +}; + + +#endif // IMPORT_LISTVIEW_H diff --git a/rdlogmanager/lib_listview.cpp b/rdlogmanager/lib_listview.cpp new file mode 100644 index 00000000..b3fe8bbc --- /dev/null +++ b/rdlogmanager/lib_listview.cpp @@ -0,0 +1,57 @@ +// lib_listview.cpp +// +// The Library ListView widget for RDLogManager. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: lib_listview.cpp,v 1.7.8.1 2013/12/27 22:12:29 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#include + +#include + + +LibListView::LibListView(QWidget *parent,const char *name) + : QListView(parent,name) +{ +} + + +void LibListView::focusOutEvent(QFocusEvent *e) +{ + QListViewItem *item=selectedItem(); + if(item==NULL) { + return; + } + setSelected(item,false); +} + + +void LibListView::contentsMousePressEvent(QMouseEvent *e) +{ + QListView::contentsMousePressEvent(e); + QListViewItem *item=selectedItem(); + if(item==NULL) { + return; + } + RDCartDrag *d=new RDCartDrag(item->text(1).toUInt(),item->pixmap(0),this); + d->dragCopy(); + + emit clicked(item); +} diff --git a/rdlogmanager/lib_listview.h b/rdlogmanager/lib_listview.h new file mode 100644 index 00000000..2fa35163 --- /dev/null +++ b/rdlogmanager/lib_listview.h @@ -0,0 +1,45 @@ +// lib_listview.h +// +// The Library ListView widget for RDLogManager. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: lib_listview.h,v 1.6 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// + +#ifndef LIB_LISTVIEW_H +#define LIB_LISTVIEW_H + +#include +#include + + +class LibListView : public QListView +{ + Q_OBJECT + + public: + LibListView(QWidget *parent,const char *name=0); + + protected: + void focusOutEvent(QFocusEvent *e); + void contentsMousePressEvent(QMouseEvent *e); +}; + + +#endif // LIB_LISTVIEW_H diff --git a/rdlogmanager/list_clocks.cpp b/rdlogmanager/list_clocks.cpp new file mode 100644 index 00000000..6b92b958 --- /dev/null +++ b/rdlogmanager/list_clocks.cpp @@ -0,0 +1,698 @@ +// list_clocks.cpp +// +// List Rivendell Log Clocks +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_clocks.cpp,v 1.28.8.2 2014/01/10 19:32:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +ListClocks::ListClocks(QString *clockname,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QStringList services_list; + QString str1=tr("Log Clocks - User: "); + setCaption(QString().sprintf("%s%s",(const char *)str1, + (const char *)rdripc->user())); + edit_clockname=clockname; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Event Filter + // + edit_filter_box=new QComboBox(this,"edit_filter_box"); + edit_filter_label=new QLabel(edit_filter_box,tr("Filter:"),this); + edit_filter_label->setFont(bold_font); + edit_filter_label->setAlignment(AlignRight|AlignVCenter); + connect(edit_filter_box,SIGNAL(activated(int)), + this,SLOT(filterActivatedData(int))); + + // + // Clocks List + // + edit_clocks_list=new QListView(this,"edit_clocks_list"); + edit_clocks_list->setAllColumnsShowFocus(true); + edit_clocks_list->setItemMargin(5); + edit_clocks_list->addColumn(tr("Name")); + edit_clocks_list->addColumn(tr("Code")); + edit_clocks_list->addColumn(tr("Color")); + edit_clocks_list->setColumnAlignment(2,AlignCenter); + connect(edit_clocks_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this,SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + // + // Add Button + // + edit_add_button=new QPushButton(this); + edit_add_button->setFont(bold_font); + edit_add_button->setText(tr("&Add")); + connect(edit_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + edit_edit_button=new QPushButton(this); + edit_edit_button->setFont(bold_font); + edit_edit_button->setText(tr("&Edit")); + connect(edit_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + edit_delete_button=new QPushButton(this); + edit_delete_button->setFont(bold_font); + edit_delete_button->setText(tr("&Delete")); + connect(edit_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Rename Button + // + edit_rename_button=new QPushButton(this); + edit_rename_button->setFont(bold_font); + edit_rename_button->setText(tr("&Rename")); + connect(edit_rename_button,SIGNAL(clicked()),this,SLOT(renameData())); + + // + // Close Button + // + edit_close_button=new QPushButton(this); + edit_close_button->setFont(bold_font); + edit_close_button->setText(tr("C&lose")); + connect(edit_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Clear Button + // + edit_clear_button=new QPushButton(this); + edit_clear_button->setFont(bold_font); + edit_clear_button->setText(tr("C&lear")); + connect(edit_clear_button,SIGNAL(clicked()),this,SLOT(clearData())); + + // + // OK Button + // + edit_ok_button=new QPushButton(this); + edit_ok_button->setFont(bold_font); + edit_ok_button->setText(tr("&OK")); + connect(edit_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + edit_cancel_button=new QPushButton(this); + edit_cancel_button->setFont(bold_font); + edit_cancel_button->setText(tr("&Cancel")); + connect(edit_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + if(edit_clockname==NULL) { + edit_close_button->setDefault(true); + edit_clear_button->hide(); + edit_ok_button->hide(); + edit_cancel_button->hide(); + } + else { + edit_ok_button->setDefault(true); + edit_add_button->hide(); + edit_edit_button->hide(); + edit_delete_button->hide(); + edit_rename_button->hide(); + edit_close_button->hide(); + } + + // + // Populate Data + // + edit_filter_box->insertItem(tr("ALL")); + edit_filter_box->insertItem(tr("NONE")); + + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec) { + services_list = rduser->services(); + } else { // RDStation::HostSec + QString sql="select NAME from SERVICES"; + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + services_list.append( q->value(0).toString() ); + } + delete q; + } + services_list.sort(); + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end(); + ++it ) { + edit_filter_box->insertItem(*it); + if(*clock_filter==*it) { + edit_filter_box->setCurrentItem(edit_filter_box->count()-1); + } + } + RefreshList(); + + if(edit_clockname!=NULL) { + QListViewItem *item=edit_clocks_list->firstChild(); + while(item!=NULL) { + if(item->text(0)==*edit_clockname) { + edit_clocks_list->setSelected(item,true); + } + item=item->nextSibling(); + } + } +} + + +QSize ListClocks::sizeHint() const +{ + return QSize(600,400); +} + + +QSizePolicy ListClocks::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListClocks::addData() +{ + QString clockname; + QString clockname_esc; + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + std::vector new_clocks; + + AddClock *add_dialog=new AddClock(&clockname,this,"add_dialog"); + if(add_dialog->exec()<0) { + delete add_dialog; + return; + } + delete add_dialog; + sql=QString().sprintf("select NAME from CLOCKS where NAME=\"%s\"", + (const char *)clockname); + q=new RDSqlQuery(sql); + if(q->first()) { + QMessageBox:: + information(this,tr("Clock Exists"), + tr("An clock with that name already exists!")); + delete q; + return; + } + delete q; + sql=QString().sprintf("insert into CLOCKS set NAME=\"%s\",ARTISTSEP=15", + (const char *)clockname); + q=new RDSqlQuery(sql); + delete q; + sql=RDCreateClockTableSql(clockname); + q=new RDSqlQuery(sql); + delete q; + EditClock *clock_dialog=new EditClock(clockname,true,&new_clocks, + this,"clock_dialog"); + if(clock_dialog->exec()<0) { + clockname_esc=clockname; + clockname_esc.replace(" ","_"); + clockname_esc+="_CLK"; + sql=QString().sprintf("drop table %s",(const char *)clockname_esc); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("delete from CLOCKS where NAME=\"%s\"", + (const char *)clockname); + q=new RDSqlQuery(sql); + delete q; + } + else { + if(edit_filter_box->currentItem()==0) { + sql="select NAME from SERVICES"; + q=new RDSqlQuery(sql); + while(q->next()) { + // FIXME: not sure if the usersec service filter should be applied + // here, or if all services should be brought over and later filtered + // by edit_perms.cpp dialog. + sql=QString().sprintf("insert into CLOCK_PERMS set\ + CLOCK_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *)clockname, + (const char *)q->value(0).toString()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + } + else { + sql=QString().sprintf("insert into CLOCK_PERMS set\ + CLOCK_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *)clockname, + (const char *)edit_filter_box->currentText()); + q=new RDSqlQuery(sql); + delete q; + } + QListViewItem *item=new QListViewItem(edit_clocks_list); + item->setText(0,clockname); + RefreshItem(item,&new_clocks); + edit_clocks_list->setSelected(item,true); + } + delete clock_dialog; +} + + +void ListClocks::editData() +{ + std::vector new_clocks; + QListViewItem *item=edit_clocks_list->selectedItem(); + if(item==NULL) { + return; + } + EditClock *clock_dialog= + new EditClock(item->text(0),false,&new_clocks,this,"clock_dialog"); + if(clock_dialog->exec()<0) { + delete clock_dialog; + return; + } + delete clock_dialog; + RefreshItem(item,&new_clocks); +} + + +void ListClocks::deleteData() +{ + QString str1; + QString str2; + int n; + QString svc_list; + QListViewItem *item=edit_clocks_list->selectedItem(); + if(item==NULL) { + return; + } + str1=QString(tr("Are you sure you want to\ndelete")); + if(QMessageBox::question(this,tr("Delete Clock"), + QString().sprintf("%s \'%s\'?",(const char *)str1, + (const char *)item->text(0)), + QMessageBox::Yes,QMessageBox::No) + !=QMessageBox::Yes) { + return; + } + if((n=ActiveClocks(item->text(0),&svc_list))>0) { + str1=QString(tr("is in use in the following grid(s):")); + str2=QString(tr("Do you still want to delete it?")); + if(QMessageBox::warning(this,tr("Clock In Use"), + QString().sprintf("\'%s\' %s:\n\n%s\n%s", + (const char *)item->text(0), + (const char *)str1, + (const char *)svc_list, + (const char *)str2), + QMessageBox::Yes, + QMessageBox::No)!=QMessageBox::Yes) { + return; + } + } + DeleteClock(item->text(0)); + RefreshList(); +} + + +void ListClocks::renameData() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + QListViewItem *item=edit_clocks_list->selectedItem(); + if(item==NULL) { + return; + } + QString new_name=item->text(0); + RenameItem *rename_dialog= + new RenameItem(&new_name,"CLOCKS",this,"event_dialog"); + if(rename_dialog->exec()<-1) { + delete rename_dialog; + return; + } + delete rename_dialog; + + // + // Rename Grid References + // + sql="select NAME from SERVICES"; + // FIXME: not sure if the usersec service filter should be applied here, or + // if all services should be brought over + q=new RDSqlQuery(sql); + while(q->next()) { + for(int i=0;i<168;i++) { + sql=QString().sprintf("update SERVICES set CLOCK%d=\"%s\"\ + where CLOCK%d=\"%s\"", + i,(const char *)new_name, + i,(const char *)item->text(0)); + q1=new RDSqlQuery(sql); + delete q1; + } + } + delete q; + + // + // Rename Meta Table + // + QString old_name_esc=item->text(0); + old_name_esc.replace(" ","_"); + QString new_name_esc=new_name; + new_name_esc.replace(" ","_"); + sql=QString().sprintf("alter table %s_CLK rename to %s_CLK", + (const char *)old_name_esc, + (const char *)new_name_esc); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("alter table %s_RULES rename to %s_RULES", + (const char *)old_name_esc, + (const char *)new_name_esc); + q=new RDSqlQuery(sql); + delete q; + + // + // Rename Service Permissions + // + sql=QString().sprintf("update CLOCK_PERMS set CLOCK_NAME=\"%s\"\ + where CLOCK_NAME=\"%s\"", + (const char *)new_name, + (const char *)item->text(0)); + q=new RDSqlQuery(sql); + delete q; + + // + // Rename Primary Key + // + sql=QString().sprintf("update CLOCKS set NAME=\"%s\" where NAME=\"%s\"", + (const char *)new_name, + (const char *)item->text(0)); + q=new RDSqlQuery(sql); + delete q; + + item->setText(0,new_name); + RefreshItem(item); +} + + +void ListClocks::filterActivatedData(int id) +{ + RefreshList(); +} + + +void ListClocks::doubleClickedData(QListViewItem *item,const QPoint &,int) +{ + if(edit_clockname==NULL) { + editData(); + } + else { + okData(); + } +} + + +void ListClocks::closeData() +{ + *clock_filter=edit_filter_box->currentText(); + done(0); +} + + +void ListClocks::clearData() +{ + QListViewItem *item=edit_clocks_list->selectedItem(); + if(item!=NULL) { + edit_clocks_list->setSelected(item,false); + } +} + + +void ListClocks::okData() +{ + QListViewItem *item=edit_clocks_list->selectedItem(); + *clock_filter=edit_filter_box->currentText(); + if(item==NULL) { + *edit_clockname=""; + } + else { + *edit_clockname=item->text(0); + } + done(0); +} + + +void ListClocks::cancelData() +{ + done(-1); +} + + +void ListClocks::resizeEvent(QResizeEvent *e) +{ + edit_filter_box->setGeometry(65,10,size().width()-75,20); + edit_filter_label->setGeometry(10,10,50,20); + edit_clocks_list->setGeometry(10,45, + size().width()-20,size().height()-115); + edit_add_button->setGeometry(10,size().height()-60,80,50); + edit_edit_button->setGeometry(100,size().height()-60,80,50); + edit_delete_button->setGeometry(190,size().height()-60,80,50); + edit_rename_button->setGeometry(310,size().height()-60,80,50); + edit_close_button-> + setGeometry(size().width()-90,size().height()-60,80,50); + edit_clear_button->setGeometry(10,size().height()-60,80,50); + edit_ok_button-> + setGeometry(size().width()-180,size().height()-60,80,50); + edit_cancel_button-> + setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void ListClocks::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void ListClocks::RefreshList() +{ + QString filter; + + if(edit_filter_box->currentItem()==1) { + filter=GetNoneFilter(); + } + else { + if(edit_filter_box->currentItem()>1) { + filter=GetClockFilter(edit_filter_box->currentText()); + } + } + + edit_clocks_list->clear(); + QString sql=QString().sprintf("select NAME,SHORT_NAME,COLOR from CLOCKS %s", + (const char *)filter); + RDSqlQuery *q=new RDSqlQuery(sql); + QListViewItem *item=NULL; + while(q->next()) { + item=new QListViewItem(edit_clocks_list); + WriteItem(item,q); + } + delete q; +} + + +void ListClocks::RefreshItem(QListViewItem *item, + std::vector *new_clocks) +{ + QListViewItem *new_item; + UpdateItem(item,item->text(0)); + + if(new_clocks!=NULL) { + for(unsigned i=0;isize();i++) { + if((new_item=edit_clocks_list->findItem(new_clocks->at(i),0))==NULL) { + new_item=new QListViewItem(edit_clocks_list); + } + UpdateItem(new_item,new_clocks->at(i)); + } + } +} + + +void ListClocks::UpdateItem(QListViewItem *item,QString name) +{ + QString sql=QString().sprintf("select NAME,SHORT_NAME,COLOR from CLOCKS\ + where NAME=\"%s\"",(const char *)name); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->next()) { + item->setText(0,name); + WriteItem(item,q); + } + delete q; +} + + +void ListClocks::WriteItem(QListViewItem *item,RDSqlQuery *q) +{ + QPixmap *pix; + QPainter *p=new QPainter(); + + item->setText(0,q->value(0).toString()); + item->setText(1,q->value(1).toString()); + pix=new QPixmap(QSize(15,15)); + p->begin(pix); + p->fillRect(0,0,15,15,QColor(q->value(2).toString())); + p->end(); + item->setPixmap(2,*pix); + + delete p; +} + + +int ListClocks::ActiveClocks(QString clockname,QString *svc_list) +{ + int n=0; + QString sql; + RDSqlQuery *q; + QString svcname; + + sql="select NAME from SERVICES where "; + for(int i=0;i<167;i++) { + sql+=QString().sprintf("(CLOCK%d=\"%s\")||",i,(const char *)clockname); + } + sql+=QString().sprintf("(CLOCK167=\"%s\")",(const char *)clockname); + q=new RDSqlQuery(sql); + while(q->next()) { + n++; + *svc_list+= + QString().sprintf(" %s\n",(const char *)q->value(0).toString()); + } + delete q; + + return n; +} + + +void ListClocks::DeleteClock(QString clockname) +{ + QString sql; + RDSqlQuery *q; + QString base_name=clockname; + base_name.replace(" ","_"); + + // + // Delete Active Clocks + // + for(int i=0;i<168;i++) { + sql=QString().sprintf("update SERVICES set CLOCK%d=NULL\ + where CLOCK%d=\"%s\"", + i,i,(const char *)clockname); + q=new RDSqlQuery(sql); + delete q; + } + + // + // Delete Service Associations + // + sql=QString().sprintf("delete from CLOCK_PERMS where CLOCK_NAME=\"%s\"", + (const char *)clockname); + q=new RDSqlQuery(sql); + delete q; + + // + // Delete Clock Definition + // + sql=QString().sprintf("delete from CLOCKS where NAME=\"%s\"", + (const char *)clockname); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("drop table %s_CLK",(const char *)base_name); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("drop table %s_RULES",(const char *)base_name); + q=new RDSqlQuery(sql); + delete q; +} + + +QString ListClocks::GetClockFilter(QString svc_name) +{ + QString filter="where "; + QString sql=QString().sprintf("select CLOCK_NAME from CLOCK_PERMS\ + where SERVICE_NAME=\"%s\"", + (const char *)svc_name); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->size()>0) { + while(q->next()) { + filter+=QString().sprintf("(NAME=\"%s\")||", + (const char *)q->value(0).toString()); + } + filter=filter.left(filter.length()-2); + } + else { + filter="(SERVICE_NAME=\"\")"; + } + delete q; + + return filter; +} + + +QString ListClocks::GetNoneFilter() +{ + QString sql; + RDSqlQuery *q; + QString filter; + + sql="select CLOCK_NAME from CLOCK_PERMS"; + q=new RDSqlQuery(sql); + if(q->size()>0) { + filter="where "; + } + while(q->next()) { + filter+=QString().sprintf("(NAME!=\"%s\")&&", + (const char *)q->value(0).toString()); + } + if(q->size()>0) { + filter=filter.left(filter.length()-2); + } + delete q; + + return filter; +} + diff --git a/rdlogmanager/list_clocks.h b/rdlogmanager/list_clocks.h new file mode 100644 index 00000000..7a0e5c0c --- /dev/null +++ b/rdlogmanager/list_clocks.h @@ -0,0 +1,89 @@ +// list_clocks.h +// +// List Rivendell Log Clocks +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_clocks.h,v 1.15.8.2 2014/01/10 19:32:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_CLOCKS_H +#define LIST_CLOCKS_H + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +class ListClocks : public QDialog +{ + Q_OBJECT + public: + ListClocks(QString *clockname=NULL,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void renameData(); + void doubleClickedData(QListViewItem *,const QPoint &,int); + void filterActivatedData(int id); + void closeData(); + void clearData(); + void okData(); + void cancelData(); + + protected: + void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e); + + private: + void RefreshList(); + void RefreshItem(QListViewItem *item,std::vector *new_clocks=NULL); + void UpdateItem(QListViewItem *item,QString name); + void WriteItem(QListViewItem *item,RDSqlQuery *q); + int ActiveClocks(QString clockname,QString *svc_list); + void DeleteClock(QString clockname); + QString GetClockFilter(QString svc_name); + QString GetNoneFilter(); + QListView *edit_clocks_list; + QString *edit_clockname; + QLabel *edit_filter_label; + QComboBox *edit_filter_box; + QPushButton *edit_add_button; + QPushButton *edit_edit_button; + QPushButton *edit_delete_button; + QPushButton *edit_rename_button; + QPushButton *edit_close_button; + QPushButton *edit_clear_button; + QPushButton *edit_ok_button; + QPushButton *edit_cancel_button; +}; + + +#endif + diff --git a/rdlogmanager/list_events.cpp b/rdlogmanager/list_events.cpp new file mode 100644 index 00000000..62d95a23 --- /dev/null +++ b/rdlogmanager/list_events.cpp @@ -0,0 +1,662 @@ +// list_events.cpp +// +// List a Rivendell Log Event +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_events.cpp,v 1.31.8.2 2014/01/10 19:32:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +ListEvents::ListEvents(QString *eventname,QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QStringList services_list; + QString str1=tr("Log Events - User: "); + setCaption(QString().sprintf("%s%s",(const char *)str1, + (const char *)rdripc->user())); + edit_eventname=eventname; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Event Filter + // + edit_filter_box=new QComboBox(this); + edit_filter_label=new QLabel(edit_filter_box,tr("Filter:"),this); + edit_filter_label->setGeometry(10,10,50,20); + edit_filter_label->setFont(bold_font); + edit_filter_label->setAlignment(AlignRight|AlignVCenter); + connect(edit_filter_box,SIGNAL(activated(int)), + this,SLOT(filterActivatedData(int))); + + // + // Events List + // + edit_events_list=new QListView(this,"edit_events_list"); + edit_events_list->setAllColumnsShowFocus(true); + edit_events_list->setItemMargin(5); + edit_events_list->addColumn(tr("Name")); + edit_events_list->addColumn(tr("Properties")); + edit_events_list->addColumn(tr("Color")); + edit_events_list->setColumnAlignment(2,AlignCenter); + connect(edit_events_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this,SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + // + // Add Button + // + edit_add_button=new QPushButton(this); + edit_add_button->setFont(bold_font); + edit_add_button->setText(tr("&Add")); + connect(edit_add_button,SIGNAL(clicked()),this,SLOT(addData())); + + // + // Edit Button + // + edit_edit_button=new QPushButton(this); + edit_edit_button->setFont(bold_font); + edit_edit_button->setText(tr("&Edit")); + connect(edit_edit_button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Delete Button + // + edit_delete_button=new QPushButton(this); + edit_delete_button->setFont(bold_font); + edit_delete_button->setText(tr("&Delete")); + connect(edit_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); + + // + // Rename Button + // + edit_rename_button=new QPushButton(this); + edit_rename_button->setFont(bold_font); + edit_rename_button->setText(tr("&Rename")); + connect(edit_rename_button,SIGNAL(clicked()),this,SLOT(renameData())); + + // + // Close Button + // + edit_close_button=new QPushButton(this); + edit_close_button->setFont(bold_font); + edit_close_button->setText(tr("&OK")); + connect(edit_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + // + // Ok Button + // + edit_ok_button=new QPushButton(this); + edit_ok_button->setFont(bold_font); + edit_ok_button->setText(tr("&Ok")); + connect(edit_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + edit_cancel_button=new QPushButton(this); + edit_cancel_button->setFont(bold_font); + edit_cancel_button->setText(tr("&Cancel")); + connect(edit_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + if(edit_eventname==NULL) { + edit_close_button->setDefault(true); + edit_ok_button->hide(); + edit_cancel_button->hide(); + } + else { + edit_ok_button->setDefault(true); + edit_add_button->hide(); + edit_edit_button->hide(); + edit_delete_button->hide(); + edit_rename_button->hide(); + edit_close_button->hide(); + } + + // + // Populate Data + // + edit_filter_box->insertItem(tr("ALL")); + edit_filter_box->insertItem(tr("NONE")); + + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec) { + services_list = rduser->services(); + } else { // RDStation::HostSec + QString sql="select NAME from SERVICES"; + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + services_list.append( q->value(0).toString() ); + } + delete q; + } + services_list.sort(); + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end(); + ++it ) { + edit_filter_box->insertItem(*it); + if(*event_filter==*it) { + edit_filter_box->setCurrentItem(edit_filter_box->count()-1); + } + } + + RefreshList(); +} + + +QSize ListEvents::sizeHint() const +{ + return QSize(600,400); +} + + +QSizePolicy ListEvents::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListEvents::addData() +{ + QString logname; + RDEvent *event; + RDSqlQuery *q; + RDSqlQuery *q1; + std::vector new_events; + + AddEvent *add_dialog=new AddEvent(&logname,this,"add_dialog"); + if(add_dialog->exec()<0) { + delete add_dialog; + return; + } + delete add_dialog; + QString sql=QString().sprintf("select NAME from EVENTS where NAME=\"%s\"", + (const char *)logname); + q=new RDSqlQuery(sql); + if(q->first()) { + QMessageBox:: + information(this,tr("Event Exists"), + tr("An event with that name already exists!")); + delete q; + return; + } + delete q; + event=new RDEvent(logname,true); + delete event; + EditEvent *event_dialog=new EditEvent(logname,true,&new_events, + this,"event_dialog"); + if(event_dialog->exec()<-1) { + sql=QString().sprintf("delete from EVENTS where NAME=\"%s\"", + (const char *)logname); + q=new RDSqlQuery(sql); + delete q; + return; + } + else { + if(edit_filter_box->currentItem()==0) { + sql="select NAME from SERVICES"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("insert into EVENT_PERMS set\ + EVENT_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *)logname, + (const char *)q->value(0).toString()); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + } + else { + sql=QString().sprintf("insert into EVENT_PERMS set\ + EVENT_NAME=\"%s\",SERVICE_NAME=\"%s\"", + (const char *)logname, + (const char *)edit_filter_box->currentText()); + q=new RDSqlQuery(sql); + delete q; + } + } + delete event_dialog; + QListViewItem *item=new QListViewItem(edit_events_list); + item->setText(0,logname); + RefreshItem(item,&new_events); + edit_events_list->setSelected(item,true); + edit_events_list->ensureItemVisible(item); +} + + +void ListEvents::editData() +{ + std::vector new_events; + + QListViewItem *item=edit_events_list->selectedItem(); + if(item==NULL) { + return; + } + EditEvent *event_dialog= + new EditEvent(item->text(0),false,&new_events,this,"event_dialog"); + if(event_dialog->exec()<-1) { + delete event_dialog; + return; + } + delete event_dialog; + RefreshItem(item,&new_events); +} + + +void ListEvents::deleteData() +{ + int n; + QString clock_list; + QString str1; + QString str2; + + QListViewItem *item=edit_events_list->selectedItem(); + if(item==NULL) { + return; + } + str1=QString(tr("Are you sure you want to\ndelete")); + if(QMessageBox::question(this,tr("Delete Event"), + QString().sprintf("%s \'%s\'?",(const char *)str1, + (const char *)item->text(0)), + QMessageBox::Yes,QMessageBox::No) + !=QMessageBox::Yes) { + return; + } + if((n=ActiveEvents(item->text(0),&clock_list))>0) { + str1=QString(tr("is in use in the following clocks:")); + str2=QString(tr("Do you still want to delete it?")); + if(QMessageBox::warning(this,tr("Event In Use"), + QString().sprintf("\'%s\' %s\n\n%s\n%s", + (const char *)item->text(0), + (const char *)str1, + (const char *)clock_list, + (const char *)str2), + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + return; + } + } + DeleteEvent(item->text(0)); + delete item; + RefreshList(); +} + + +void ListEvents::renameData() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + QString clock_name_esc; + QListViewItem *item=edit_events_list->selectedItem(); + if(item==NULL) { + return; + } + QString new_name=item->text(0); + RenameItem *rename_dialog= + new RenameItem(&new_name,"EVENTS",this,"event_dialog"); + if(rename_dialog->exec()<-1) { + delete rename_dialog; + return; + } + delete rename_dialog; + + // + // Rename Clock References + // + sql="select NAME from CLOCKS"; + q=new RDSqlQuery(sql); + while(q->next()) { + clock_name_esc=q->value(0).toString(); + clock_name_esc.replace(" ","_"); + sql=QString().sprintf("update %s_CLK set EVENT_NAME=\"%s\"\ + where EVENT_NAME=\"%s\"", + (const char *)clock_name_esc, + (const char *)new_name, + (const char *)item->text(0)); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Rename Meta Tables + // + QString old_name_esc=item->text(0); + old_name_esc.replace(" ","_"); + QString new_name_esc=new_name; + new_name_esc.replace(" ","_"); + sql=QString().sprintf("alter table %s_PRE rename to %s_PRE", + (const char *)old_name_esc, + (const char *)new_name_esc); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("alter table %s_POST rename to %s_POST", + (const char *)old_name_esc, + (const char *)new_name_esc); + q=new RDSqlQuery(sql); + delete q; + + // + // Rename Service Permissions + // + sql=QString().sprintf("update EVENT_PERMS set EVENT_NAME=\"%s\"\ + where EVENT_NAME=\"%s\"", + (const char *)new_name, + (const char *)item->text(0)); + q=new RDSqlQuery(sql); + delete q; + + // + // Rename Primary Key + // + sql=QString().sprintf("update EVENTS set NAME=\"%s\" where NAME=\"%s\"", + (const char *)new_name, + (const char *)item->text(0)); + q=new RDSqlQuery(sql); + delete q; + + item->setText(0,new_name); + RefreshItem(item); +} + + +void ListEvents::filterActivatedData(int id) +{ + RefreshList(); +} + + +void ListEvents::doubleClickedData(QListViewItem *item,const QPoint &,int) +{ + if(edit_eventname==NULL) { + editData(); + } + else { + okData(); + } +} + + +void ListEvents::closeData() +{ + done(0); +} + + +void ListEvents::okData() +{ + QListViewItem *item=edit_events_list->selectedItem(); + *event_filter=edit_filter_box->currentText(); + if(item==NULL) { + done(-1); + return; + } + *edit_eventname=item->text(0); + done(0); +} + + +void ListEvents::cancelData() +{ + done(-1); +} + + +void ListEvents::resizeEvent(QResizeEvent *e) +{ + edit_filter_box->setGeometry(65,10,size().width()-75,20); + edit_events_list->setGeometry(10,45,size().width()-20,size().height()-125); + edit_add_button->setGeometry(10,size().height()-60,80,50); + edit_edit_button->setGeometry(100,size().height()-60,80,50); + edit_delete_button->setGeometry(190,size().height()-60,80,50); + edit_rename_button->setGeometry(310,size().height()-60,80,50); + edit_close_button->setGeometry(size().width()-90,size().height()-60,80,50); + edit_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + edit_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void ListEvents::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void ListEvents::RefreshList() +{ + QString filter; + + if(edit_filter_box->currentItem()==1) { // NONE Filter + filter=GetNoneFilter(); + } + else { + if(edit_filter_box->currentItem()>1) { + filter=GetEventFilter(edit_filter_box->currentText()); + } + } + + edit_events_list->clear(); + QString sql=QString().sprintf("select NAME,PROPERTIES,COLOR from EVENTS %s", + (const char *)filter); + RDSqlQuery *q=new RDSqlQuery(sql); + QListViewItem *item=NULL; + while(q->next()) { + item=new QListViewItem(edit_events_list); + WriteItem(item,q); + } + delete q; +} + + +void ListEvents::RefreshItem(QListViewItem *item, + std::vector *new_events) +{ + QListViewItem *new_item; + UpdateItem(item,item->text(0)); + + if(new_events!=NULL) { + for(unsigned i=0;isize();i++) { + if((new_item=edit_events_list->findItem(new_events->at(i),0))==NULL) { + new_item=new QListViewItem(edit_events_list); + } + UpdateItem(new_item,new_events->at(i)); + } + } +} + + +void ListEvents::UpdateItem(QListViewItem *item,QString name) +{ + QString sql=QString().sprintf("select NAME,PROPERTIES,COLOR from EVENTS\ + where NAME=\"%s\"",(const char *)name); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->next()) { + item->setText(0,name); + WriteItem(item,q); + } + delete q; +} + + +void ListEvents::WriteItem(QListViewItem *item,RDSqlQuery *q) +{ + QPixmap *pix; + QPainter *p=new QPainter(); + + item->setText(0,q->value(0).toString()); + item->setText(1,q->value(1).toString()); + pix=new QPixmap(QSize(15,15)); + p->begin(pix); + p->fillRect(0,0,15,15,QColor(q->value(2).toString())); + p->end(); + item->setPixmap(2,*pix); + + delete p; +} + + +int ListEvents::ActiveEvents(QString event_name,QString *clock_list) +{ + int n=0; + QString sql; + RDSqlQuery *q,*q1; + QString clockname; + + sql="select NAME from CLOCKS"; + q=new RDSqlQuery(sql); + while(q->next()) { + clockname=q->value(0).toString(); + clockname.replace(" ","_"); + sql=QString().sprintf("select EVENT_NAME from %s_CLK\ + where EVENT_NAME=\"%s\"",(const char *)clockname, + (const char *)event_name); + q1=new RDSqlQuery(sql); + if(q1->first()) { + *clock_list+= + QString().sprintf(" %s\n",(const char *)q->value(0).toString()); + n++; + } + delete q1; + } + delete q; + return n; +} + + +void ListEvents::DeleteEvent(QString event_name) +{ + QString sql; + RDSqlQuery *q,*q1; + QString clockname; + QString base_name=event_name; + base_name.replace(" ","_"); + + // + // Delete Active Clock Entries + // + sql="select NAME from CLOCKS"; + q=new RDSqlQuery(sql); + while(q->next()) { + clockname=q->value(0).toString(); + clockname.replace(" ","_"); + sql=QString().sprintf("delete from %s_CLK\ + where EVENT_NAME=\"%s\"",(const char *)clockname, + (const char *)event_name); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; + + // + // Delete Service Associations + // + sql=QString().sprintf("delete from EVENT_PERMS where EVENT_NAME=\"%s\"", + (const char *)event_name); + q=new RDSqlQuery(sql); + delete q; + + // + // Delete Event Definition + // + sql=QString().sprintf("delete from EVENTS where NAME=\"%s\"", + (const char *)event_name); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("drop table %s_PRE",(const char *)base_name); + q=new RDSqlQuery(sql); + delete q; + sql=QString().sprintf("drop table %s_POST",(const char *)base_name); + q=new RDSqlQuery(sql); +} + + +QString ListEvents::GetEventFilter(QString svc_name) +{ + QString filter="where "; + QString sql=QString().sprintf("select EVENT_NAME from EVENT_PERMS\ + where SERVICE_NAME=\"%s\"", + (const char *)svc_name); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->size()>0) { + while(q->next()) { + filter+=QString().sprintf("(NAME=\"%s\")||", + (const char *)q->value(0).toString()); + } + filter=filter.left(filter.length()-2); + } + else { + filter="(SERVICE_NAME=\"\")"; + } + delete q; + + return filter; +} + + +QString ListEvents::GetNoneFilter() +{ + QString sql; + RDSqlQuery *q; + QString filter; + + sql="select EVENT_NAME from EVENT_PERMS"; + q=new RDSqlQuery(sql); + if(q->size()>0) { + filter="where "; + } + while(q->next()) { + filter+=QString().sprintf("(NAME!=\"%s\")&&", + (const char *)q->value(0).toString()); + } + if(q->size()>0) { + filter=filter.left(filter.length()-2); + } + delete q; + + return filter; +} diff --git a/rdlogmanager/list_events.h b/rdlogmanager/list_events.h new file mode 100644 index 00000000..6e1754bb --- /dev/null +++ b/rdlogmanager/list_events.h @@ -0,0 +1,87 @@ +// list_events.h +// +// List Rivendell Log Events +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_events.h,v 1.17.8.2 2014/01/10 19:32:55 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_EVENTS_H +#define LIST_EVENTS_H + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +class ListEvents : public QDialog +{ + Q_OBJECT + public: + ListEvents(QString *eventname,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void addData(); + void editData(); + void deleteData(); + void renameData(); + void doubleClickedData(QListViewItem *,const QPoint &,int); + void filterActivatedData(int id); + void closeData(); + void okData(); + void cancelData(); + + protected: + void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e); + + private: + void RefreshList(); + void RefreshItem(QListViewItem *item,std::vector *new_events=NULL); + void UpdateItem(QListViewItem *item,QString name); + void WriteItem(QListViewItem *item,RDSqlQuery *q); + int ActiveEvents(QString event_name,QString *clock_list); + void DeleteEvent(QString event_name); + QString GetEventFilter(QString svc_name); + QString GetNoneFilter(); + QListView *edit_events_list; + QString *edit_eventname; + QLabel *edit_filter_label; + QComboBox *edit_filter_box; + QPushButton *edit_add_button; + QPushButton *edit_edit_button; + QPushButton *edit_delete_button; + QPushButton *edit_rename_button; + QPushButton *edit_close_button; + QPushButton *edit_ok_button; + QPushButton *edit_cancel_button; +}; + + +#endif + diff --git a/rdlogmanager/list_grids.cpp b/rdlogmanager/list_grids.cpp new file mode 100644 index 00000000..02669a75 --- /dev/null +++ b/rdlogmanager/list_grids.cpp @@ -0,0 +1,171 @@ +// list_grids.cpp +// +// List Rivendell Log Grids +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_grids.cpp,v 1.10 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +ListGrids::ListGrids(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + setCaption(tr("Log Grids")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Grids List + // + edit_grids_list=new QListView(this,"edit_grids_list"); + edit_grids_list->setGeometry(10,10, + sizeHint().width()-20,sizeHint().height()-80); + edit_grids_list->setAllColumnsShowFocus(true); + edit_grids_list->setItemMargin(5); + edit_grids_list->addColumn(tr("Name")); + edit_grids_list->addColumn(tr("Description")); + connect(edit_grids_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this,SLOT(doubleClickedData(QListViewItem *,const QPoint &,int))); + + // + // Edit Button + // + QPushButton *button=new QPushButton(this,"edit_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Edit")); + connect(button,SIGNAL(clicked()),this,SLOT(editData())); + + // + // Close Button + // + button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("C&lose")); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); + + RefreshList(); +} + + +QSize ListGrids::sizeHint() const +{ + return QSize(400,300); +} + + +QSizePolicy ListGrids::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListGrids::editData() +{ + QListViewItem *item=edit_grids_list->selectedItem(); + if(item==NULL) { + return; + } + EditGrid *grid_dialog=new EditGrid(item->text(0),this,"grid_dialog"); + grid_dialog->exec(); + delete grid_dialog; +} + + +void ListGrids::doubleClickedData(QListViewItem *item,const QPoint &,int) +{ + editData(); +} + + +void ListGrids::closeData() +{ + done(0); +} + + +void ListGrids::RefreshList() +{ + QListViewItem *prev_item=edit_grids_list->selectedItem(); + QString sql="select NAME,DESCRIPTION from SERVICES"; + + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec + && rduser != NULL) { + QStringList services_list; + QString sql_where; + + services_list = rduser->services(); + if(services_list.size()==0) { + return; + } + + sql_where=" where ("; + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end(); ++it ) { + sql_where+=QString().sprintf("NAME=\"%s\"||", + (const char *)*it); + } + sql_where=sql_where.left(sql_where.length()-2); + sql_where+=")"; + + sql=sql+sql_where; + } // else no filter for RDStation::HostSec + + edit_grids_list->clear(); + RDSqlQuery *q=new RDSqlQuery(sql); + QListViewItem *item=NULL; + while(q->next()) { + item=new QListViewItem(edit_grids_list); + item->setText(0,q->value(0).toString()); + item->setText(1,q->value(1).toString()); + } + delete q; + if(prev_item!=NULL) { + edit_grids_list->setSelected(item,true); + } +} diff --git a/rdlogmanager/list_grids.h b/rdlogmanager/list_grids.h new file mode 100644 index 00000000..fdceb912 --- /dev/null +++ b/rdlogmanager/list_grids.h @@ -0,0 +1,56 @@ +// list_grids.h +// +// List Rivendell Log Grids +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: list_grids.h,v 1.5 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_GRIDS_H +#define LIST_GRIDS_H + +#include +#include +#include +#include +#include + +#include +#include + + +class ListGrids : public QDialog +{ + Q_OBJECT + public: + ListGrids(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void editData(); + void doubleClickedData(QListViewItem *,const QPoint &,int); + void closeData(); + + private: + void RefreshList(); + QListView *edit_grids_list; +}; + + +#endif + diff --git a/rdlogmanager/list_svcs.cpp b/rdlogmanager/list_svcs.cpp new file mode 100644 index 00000000..2f8c6f35 --- /dev/null +++ b/rdlogmanager/list_svcs.cpp @@ -0,0 +1,223 @@ +// list_svcs.cpp +// +// List Rivendell Services and Report Ages +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: list_svcs.cpp,v 1.10 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include +#include +#include +#include + + +ListSvcs::ListSvcs(QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + setCaption(tr("Rivendell Services")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Log List + // + list_log_list=new QListView(this,"list_log_list"); + list_log_list->setAllColumnsShowFocus(true); + list_log_list->setItemMargin(5); + list_log_list->addColumn(tr("SERVICE")); + list_log_list->setColumnAlignment(0,Qt::AlignLeft); + list_log_list->addColumn(tr("OLDEST REPORT")); + list_log_list->setColumnAlignment(1,Qt::AlignCenter); + connect(list_log_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(listDoubleClickedData(QListViewItem *,const QPoint &,int))); + + // + // Generate Report Button + // + list_generate_button=new QPushButton(this,"list_generate_button"); + list_generate_button->setFont(bold_font); + list_generate_button->setText(tr("&Generate\nReports")); + connect(list_generate_button,SIGNAL(clicked()),this,SLOT(generateData())); + + // + // Purge Button + // + list_purge_button=new QPushButton(this,"list_purge_button"); + list_purge_button->setFont(bold_font); + list_purge_button->setText(tr("&Purge\nData")); + connect(list_purge_button,SIGNAL(clicked()),this,SLOT(purgeData())); + + // + // Close Button + // + list_close_button=new QPushButton(this,"close_button"); + list_close_button->setDefault(true); + list_close_button->setFont(bold_font); + list_close_button->setText(tr("C&lose")); + connect(list_close_button,SIGNAL(clicked()),this,SLOT(closeData())); + + RefreshList(); +} + + +QSize ListSvcs::sizeHint() const +{ + return QSize(400,300); +} + + +QSizePolicy ListSvcs::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ListSvcs::generateData() +{ + QListViewItem *item=list_log_list->selectedItem(); + if(item==NULL) { + return; + } + PickReportDates *dialog=new PickReportDates(item->text(0),this); + dialog->exec(); + delete dialog; +} + + +void ListSvcs::purgeData() +{ + QListViewItem *item=list_log_list->selectedItem(); + if(item==NULL) { + return; + } + SvcRecDialog *dialog=new SvcRecDialog(item->text(0),this,"dialog"); + dialog->exec(); + delete dialog; + RefreshLine(item); +} + + +void ListSvcs::listDoubleClickedData(QListViewItem *item,const QPoint &pt, + int c) +{ + generateData(); +} + + +void ListSvcs::closeData() +{ + done(0); +} + + +void ListSvcs::resizeEvent(QResizeEvent *e) +{ + list_log_list->setGeometry(10,10,size().width()-20,size().height()-80); + list_generate_button->setGeometry(10,size().height()-60,80,50); + list_purge_button->setGeometry(100,size().height()-60,80,50); + list_close_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void ListSvcs::RefreshList() +{ + RDSqlQuery *q1; + QString tablename; + QListViewItem *item; + list_log_list->clear(); + QString sql="select NAME from SERVICES order by NAME"; + + if (rdstation_conf->broadcastSecurity() == RDStation::UserSec + && rduser != NULL) { + QStringList services_list; + QString sql_where; + + services_list = rduser->services(); + if(services_list.size()==0) { + return; + } + + sql_where=" and ("; + for ( QStringList::Iterator it = services_list.begin(); + it != services_list.end(); ++it ) { + sql_where+=QString().sprintf("SERVICE=\"%s\"||", + (const char *)*it); + } + sql_where=sql_where.left(sql_where.length()-2); + sql_where+=")"; + + sql=sql+sql_where; + } // else no filter for RDStation::HostSec + + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + item=new QListViewItem(list_log_list); + item->setText(0,q->value(0).toString()); + tablename=q->value(0).toString(); + tablename.replace(" ","_"); + sql=QString().sprintf("select EVENT_DATETIME from `%s_SRT` \ + order by EVENT_DATETIME",(const char *)tablename); + q1=new RDSqlQuery(sql); + if(q1->first()) { + item->setText(1,q1->value(0).toDate().toString("MM/dd/yyyy")); + } + else { + item->setText(1,tr("[none]")); + } + delete q1; + } + delete q; +} + + +void ListSvcs::RefreshLine(QListViewItem *item) +{ + QString sql; + RDSqlQuery *q; + QString tablename=item->text(0); + tablename.replace(" ","_"); + sql=QString().sprintf("select EVENT_DATETIME from `%s_SRT` \ + order by EVENT_DATETIME",(const char *)tablename); + q=new RDSqlQuery(sql); + if(q->first()) { + item->setText(1,q->value(0).toDate().toString("MM/dd/yyyy")); + } + else { + item->setText(1,tr("[none]")); + } + delete q; +} diff --git a/rdlogmanager/list_svcs.h b/rdlogmanager/list_svcs.h new file mode 100644 index 00000000..8c64255e --- /dev/null +++ b/rdlogmanager/list_svcs.h @@ -0,0 +1,60 @@ +// list_svcs.h +// +// List Rivendell Services and Report Ages +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: list_svcs.h,v 1.6 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIST_SVCS_H +#define LIST_SVCS_H + +#include +#include +#include +#include + + +class ListSvcs : public QDialog +{ + Q_OBJECT + public: + ListSvcs(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void generateData(); + void purgeData(); + void listDoubleClickedData(QListViewItem *item,const QPoint &pt,int c); + void closeData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void RefreshList(); + void RefreshLine(QListViewItem *item); + QListView *list_log_list; + QPushButton *list_generate_button; + QPushButton *list_purge_button; + QPushButton *list_close_button; +}; + + +#endif + diff --git a/rdlogmanager/pick_report_dates.cpp b/rdlogmanager/pick_report_dates.cpp new file mode 100644 index 00000000..5e68c54b --- /dev/null +++ b/rdlogmanager/pick_report_dates.cpp @@ -0,0 +1,244 @@ +// pick_report_date.cpp +// +// Select a Set of Dates for a Rivendell Report +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: pick_report_dates.cpp,v 1.8.8.2 2013/01/22 20:59:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +PickReportDates::PickReportDates(const QString &svcname, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString sql; + RDSqlQuery *q; + QDate yesterday_date=QDate::currentDate().addDays(-1); + + edit_svcname=svcname; + setCaption(tr("Select Report Dates")); + + // + // Fix the Window Size + // + setMaximumWidth(sizeHint().width()); + setMaximumHeight(sizeHint().height()); + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Report List + // + edit_report_box=new QComboBox(this,"edit_report_box"); + edit_report_box->setGeometry(75,11,sizeHint().width()-85,19); + QLabel *label=new QLabel(edit_report_box,tr("&Report:"), + this,"edit_report_label"); + label->setGeometry(10,11,60,19); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + sql=QString().sprintf("select REPORT_NAME from REPORT_SERVICES\ + where SERVICE_NAME=\"%s\" order by REPORT_NAME", + (const char *)svcname); + q=new RDSqlQuery(sql); + while(q->next()) { + edit_report_box->insertItem(q->value(0).toString()); + } + delete q; + + // + // Start Date + // + edit_startdate_edit=new QDateEdit(this,"edit_startdate_edit"); + edit_startdate_edit->setGeometry(150,35,100,22); + edit_startdate_edit->setDate(yesterday_date); + label=new QLabel(edit_startdate_edit,tr("&Start Date:"), + this,"edit_startdate_label"); + label->setGeometry(75,36,70,19); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + QPushButton *button=new QPushButton(this,"startdate_button"); + button->setGeometry(260,33,50,27); + button->setFont(font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectStartDateData())); + + // + // End Date + // + edit_enddate_edit=new QDateEdit(this,"edit_enddate_edit"); + edit_enddate_edit->setGeometry(150,65,100,22); + edit_enddate_edit->setDate(yesterday_date); + label=new QLabel(edit_enddate_edit,tr("&End Date:"), + this,"edit_enddate_label"); + label->setGeometry(75,66,70,19); + label->setFont(bold_font); + label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); + button=new QPushButton(this,"enddate_button"); + button->setGeometry(260,63,50,27); + button->setFont(font); + button->setText(tr("&Select")); + connect(button,SIGNAL(clicked()),this,SLOT(selectEndDateData())); + + // + // Generate Button + // + button=new QPushButton(this,"list_purge_button"); + button->setGeometry(10,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Generate\nReport")); + connect(button,SIGNAL(clicked()),this,SLOT(generateData())); + + // + // Close Button + // + button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("C&lose")); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +PickReportDates::~PickReportDates() +{ +} + + +QSize PickReportDates::sizeHint() const +{ + return QSize(400,160); +} + + +QSizePolicy PickReportDates::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void PickReportDates::selectStartDateData() +{ + RDDateDialog *dialog=new RDDateDialog(2002,QDate::currentDate().year(),this); + QDate date=edit_startdate_edit->date(); + if(dialog->exec(&date)<0) { + delete dialog; + return; + } + edit_startdate_edit->setDate(date); + edit_enddate_edit->setDate(date); + delete dialog; +} + + +void PickReportDates::selectEndDateData() +{ + RDDateDialog *dialog=new RDDateDialog(2002,QDate::currentDate().year(),this); + QDate date=edit_enddate_edit->date(); + if(dialog->exec(&date)<0) { + delete dialog; + return; + } + edit_enddate_edit->setDate(date); + delete dialog; +} + + +void PickReportDates::generateData() +{ + if(edit_startdate_edit->date()>edit_enddate_edit->date()) { + QMessageBox::warning(this,tr("Invalid Date Range"), + tr("The end date cannot be earlier than the start date!")); + return; + } + RDReport *report=new RDReport(edit_report_box->currentText(),this); + if((edit_startdate_edit->date()!=edit_enddate_edit->date())&& + (!RDReport::multipleDaysAllowed(report->filter()))) { + QMessageBox::warning(this,tr("Invalid Date Range"), + tr("This report type cannot span multiple dates!")); + delete report; + return; + } + if((edit_startdate_edit->date().month()!=edit_enddate_edit->date().month())&& + (!RDReport::multipleMonthsAllowed(report->filter()))) { + QMessageBox::warning(this,tr("Invalid Date Range"), + tr("This report type cannot span multiple months!")); + delete report; + return; + } +#ifdef WIN32 + QString filename=RDDateDecode(report->exportPath(RDReport::Windows), + edit_startdate_edit->date()); +#else + QString filename=RDDateDecode(report->exportPath(RDReport::Linux), + edit_startdate_edit->date()); +#endif + QFile file(filename); + if(file.exists()) { + if(QMessageBox::question(this,"File Exists", + "The report file already exists. Overwrite?", + QMessageBox::Yes,QMessageBox::No)!= + QMessageBox::Yes) { + delete report; + return; + } + } + QString out_path; + report->generateReport(edit_startdate_edit->date(), + edit_enddate_edit->date(),rdstation_conf,&out_path); + switch(report->errorCode()) { + case RDReport::ErrorOk: + QMessageBox::information(this,tr("Report Complete"), + tr("Report generated in")+" \""+out_path+ + "\"."); + break; + + case RDReport::ErrorCantOpen: + QMessageBox::warning(this,"File Error","Unable to open report file!"); + break; + + case RDReport::ErrorCanceled: + break; + } + delete report; +} + + +void PickReportDates::closeData() +{ + done(0); +} diff --git a/rdlogmanager/pick_report_dates.h b/rdlogmanager/pick_report_dates.h new file mode 100644 index 00000000..d73f5b84 --- /dev/null +++ b/rdlogmanager/pick_report_dates.h @@ -0,0 +1,56 @@ +// pick_report_date.h +// +// Select a Set of Dates for a Rivendell Report +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: pick_report_dates.h,v 1.5 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef PICK_REPORT_DATE_H +#define PICK_REPORT_DATE_H + +#include +#include +#include +#include + + +class PickReportDates : public QDialog +{ + Q_OBJECT + public: + PickReportDates(const QString &svcname, + QWidget *parent=0,const char *name=0); + ~PickReportDates(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void selectStartDateData(); + void selectEndDateData(); + void generateData(); + void closeData(); + + private: + QComboBox *edit_report_box; + QDateEdit *edit_startdate_edit; + QDateEdit *edit_enddate_edit; + QString edit_svcname; +}; + + +#endif // PIC_REPORT_DATES_H diff --git a/rdlogmanager/rdlogmanager.cpp b/rdlogmanager/rdlogmanager.cpp new file mode 100644 index 00000000..98497331 --- /dev/null +++ b/rdlogmanager/rdlogmanager.cpp @@ -0,0 +1,502 @@ +// rdlogmanager.cpp +// +// The Log Editor Utility for Rivendell. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rdlogmanager.cpp,v 1.43.4.4.2.1 2014/05/20 14:01:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WIN32 +#include +#include +#include +#include +#include +#endif // WIN32 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// +// Icons +// +#include "../icons/rivendell-22x22.xpm" + +// +// Global Resources +// +RDStation *rdstation_conf; +RDUser *rduser; +RDRipc *rdripc; +RDCae *rdcae; +RDConfig *log_config; +QString *event_filter; +QString *clock_filter; +bool skip_db_check=false; + + +#ifndef WIN32 +void SigHandler(int signo) +{ + pid_t pLocalPid; + + switch(signo) { + case SIGCHLD: + pLocalPid=waitpid(-1,NULL,WNOHANG); + while(pLocalPid>0) { + pLocalPid=waitpid(-1,NULL,WNOHANG); + } + signal(SIGCHLD,SigHandler); + break; + } +} +#endif // WIN32 + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + unsigned schema=0; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Ensure that the system daemons are running + // +#ifndef WIN32 + RDInitializeDaemons(); +#endif // WIN32 + + // + // Load Local Configs + // + log_config=new RDConfig(); + log_config->load(); + setCaption(tr("RDLogManager")); + + // + // Open Database + // + QString err; + log_db=RDInitDb(&schema,&err); + if(!log_db) { + QMessageBox::warning(this,tr("Can't Connect"),err); + exit(0); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { +#ifdef WIN32 + QMessageBox::warning(this,tr("RDLogEdit -- Database Skew"), + tr("This version of RDLogManager is incompatible with the version installed on the server.\nSee your system administrator for an update!")); +#else + fprintf(stderr, + "rdlogmanager: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); +#endif // WIN32 + exit(256); + } + new RDDbHeartbeat(log_config->mysqlHeartbeatInterval(),this); + + // + // Allocate Global Resources + // + rdstation_conf=new RDStation(log_config->stationName()); + + // + // CAE Connection + // +#ifndef WIN32 + rdcae=new RDCae(rdstation_conf,log_config,parent,name); + rdcae->connectHost(); +#endif // WIN32 + + // + // RIPC Connection + // + rdripc=new RDRipc(log_config->stationName()); + connect(rdripc,SIGNAL(userChanged()),this,SLOT(userData())); + rdripc->connectHost("localhost",RIPCD_TCP_PORT,log_config->password()); + + // + // User + // + rduser=NULL; + + // + // Generate Fonts + // + QFont default_font("Helvetica",12,QFont::Normal); + default_font.setPixelSize(12); + qApp->setFont(default_font); + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + QFont day_font=QFont("Helvetica",12,QFont::Normal); + day_font.setPixelSize(12); + + // + // Create And Set Icon + // + log_rivendell_map=new QPixmap(rivendell_xpm); + setIcon(*log_rivendell_map); + + // + // Filters + // + event_filter=new QString(); + clock_filter=new QString(); + + // + // Title Label + // + QLabel *label=new QLabel(tr("RDLogManager"),this,"title_label"); + label->setGeometry(0,5,sizeHint().width(),32); + label->setFont(label_font); + label->setAlignment(AlignHCenter); + label=new QLabel(tr("Select an operation:"),this,"instruction_label"); + label->setGeometry(0,25,sizeHint().width(),16); + label->setFont(day_font); + label->setAlignment(AlignCenter); + + // + // Edit Events Button + // + log_events_button=new QPushButton(this,"events_button"); + log_events_button->setGeometry(10,45,sizeHint().width()-20,50); + log_events_button->setFont(button_font); + log_events_button->setText(tr("Edit &Events")); + connect(log_events_button,SIGNAL(clicked()),this,SLOT(eventsData())); + + // + // Edit Clocks Button + // + log_clocks_button=new QPushButton(this,"clocks_button"); + log_clocks_button->setGeometry(10,95,sizeHint().width()-20,50); + log_clocks_button->setFont(button_font); + log_clocks_button->setText(tr("Edit C&locks")); + connect(log_clocks_button,SIGNAL(clicked()),this,SLOT(clocksData())); + + // + // Edit Grids Button + // + log_grids_button=new QPushButton(this,"grid_button"); + log_grids_button->setGeometry(10,145,sizeHint().width()-20,50); + log_grids_button->setFont(button_font); + log_grids_button->setText(tr("Edit G&rids")); + connect(log_grids_button,SIGNAL(clicked()),this,SLOT(gridsData())); + + // + // Generate Logs Button + // + log_logs_button=new QPushButton(this,"logs_button"); + log_logs_button->setGeometry(10,195,sizeHint().width()-20,50); + log_logs_button->setFont(button_font); + log_logs_button->setText(tr("&Generate Logs")); + connect(log_logs_button,SIGNAL(clicked()),this,SLOT(generateData())); + + // + // Generate Reports Button + // + log_reports_button=new QPushButton(this,"reports_button"); + log_reports_button->setGeometry(10,245,sizeHint().width()-20,50); + log_reports_button->setFont(button_font); + log_reports_button->setText(tr("Manage &Reports")); + connect(log_reports_button,SIGNAL(clicked()),this,SLOT(reportsData())); + + // + // Close Button + // + log_close_button=new QPushButton(this,"close_button"); + log_close_button->setGeometry(10,sizeHint().height()-60, + sizeHint().width()-20,50); + log_close_button->setFont(button_font); + log_close_button->setText(tr("&Close")); + log_close_button->setDefault(true); + connect(log_close_button,SIGNAL(clicked()),this,SLOT(quitMainWidget())); + +#ifndef WIN32 + signal(SIGCHLD,SigHandler); +#endif // WIN32 +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(200,360); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::userData() +{ + QString str1=tr("RDLogManager - User: "); + setCaption(QString().sprintf("%s%s",(const char *)str1, + (const char *)rdripc->user())); + + if(rduser!=NULL) { + delete rduser; + } + rduser=new RDUser(rdripc->user()); + + // + // Set Control Perms + // + bool templates_allowed=rduser->modifyTemplate(); + bool creation_allowed=rduser->createLog(); + bool rec_allowed=rduser->deleteRec(); + log_events_button->setEnabled(templates_allowed); + log_clocks_button->setEnabled(templates_allowed); + log_grids_button->setEnabled(templates_allowed); + log_logs_button->setEnabled(creation_allowed); + log_reports_button->setEnabled(creation_allowed|rec_allowed); +} + + +void MainWidget::eventsData() +{ + ListEvents *events=new ListEvents(NULL,this,"list_events"); + events->exec(); + delete events; +} + + +void MainWidget::clocksData() +{ + ListClocks *clocks=new ListClocks(NULL,this,"list_clocks"); + clocks->exec(); + delete clocks; +} + + +void MainWidget::gridsData() +{ + ListGrids *grids=new ListGrids(this,"list_grids"); + grids->exec(); + delete grids; +} + + +void MainWidget::generateData() +{ + GenerateLog *generatelog=new GenerateLog(this,"list_grids"); + generatelog->exec(); + delete generatelog; +} + + +void MainWidget::reportsData() +{ + ListSvcs *recs=new ListSvcs(this,"list_recs"); + recs->exec(); + delete recs; +} + + +void MainWidget::quitMainWidget() +{ + log_db->removeDatabase(log_config->mysqlDbname()); + exit(0); +} + + +int gui_main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QString tr_path; + QString qt_path; +#ifdef WIN32 + QSettings settings; + settings.insertSearchPath(QSettings::Windows,"/SalemRadioLabs"); + tr_path=QString().sprintf("%s\\", + (const char *)settings. + readEntry("/Rivendell/InstallDir")); + qt_path=tr_path; +#else + tr_path=QString(PREFIX)+QString("/share/rivendell/"); + qt_path=QString(QTDIR)+QString("/translation/"); +#endif // WIN32 + QTranslator qt(0); + qt.load(qt_path+QString("qt_")+QTextCodec::locale(),"."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(tr_path+QString("librd_")+QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(tr_path+QString("librdhpi_")+QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(tr_path+QString("rdlogmanager_")+QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(w->geometry().x(),w->geometry().y()), + w->sizeHint())); + w->show(); + return a.exec(); +} + + +int main(int argc,char *argv[]) +{ + // + // Read Command Options + // + bool cmd_protect_existing=false; + bool cmd_generate=false; + bool cmd_merge_music=false; + bool cmd_merge_traffic=false; + QString cmd_service=NULL; + QString cmd_report=NULL; + int cmd_start_offset=0; + int cmd_end_offset=0; + QDate cmd_start_date = QDate::currentDate().addDays(1); + + RDCmdSwitch *cmd= + new RDCmdSwitch(argc,argv,"rdlogmanager",RDLOGMANAGER_USAGE); + for(unsigned i=0;ikeys();i++) { + if (cmd->key(i)=="-P") { + cmd_protect_existing = true; + } + if (cmd->key(i)=="-g") { + cmd_generate = true; + } + if (cmd->key(i)=="-m") { + cmd_merge_music = true; + } + if (cmd->key(i)=="-t") { + cmd_merge_traffic = true; + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + cmd->setProcessed(i,true); + } + if (cmd->key(i)=="-s") { + if (i+1keys()) { + i++; + cmd_service = cmd->key(i); + } + else { + fprintf(stderr,"rdlogmanager: missing argument to \"-s\"\n"); + exit(256); + } + } + if (cmd->key(i)=="-r") { + if (i+1keys()) { + i++; + cmd_report = cmd->key(i); + } + else { + fprintf(stderr,"rdlogmanager: missing argument to \"-r\"\n"); + exit(256); + } + } + if (cmd->key(i)=="-d") { + if (i+1keys()) { + i++; + cmd_start_offset=cmd->key(i).toInt(); + } + else { + fprintf(stderr,"rdlogmanager: missing argument to \"-d\"\n"); + exit(256); + } + } + if (cmd->key(i)=="-e") { + if (i+1keys()) { + i++; + cmd_end_offset=cmd->key(i).toInt(); + } + else { + fprintf(stderr,"rdlogmanager: missing argument to \"-e\"\n"); + exit(256); + } + } + } + delete cmd; + if((!cmd_report.isNull())&& + (cmd_generate||cmd_merge_traffic||cmd_merge_music)) { + fprintf(stderr, + "rdlogmanager: log and report operations are mutually exclusive\n"); + exit(256); + } + + if(cmd_generate||cmd_merge_traffic||cmd_merge_music) { + return RunLogOperation(argc,argv,cmd_service,cmd_start_offset, + cmd_protect_existing,cmd_generate, + cmd_merge_music,cmd_merge_traffic); + } + if(!cmd_report.isEmpty()) { + return RunReportOperation(argc,argv,cmd_report,cmd_protect_existing, + cmd_start_offset,cmd_end_offset); + } + return gui_main(argc,argv); +} diff --git a/rdlogmanager/rdlogmanager.h b/rdlogmanager/rdlogmanager.h new file mode 100644 index 00000000..5e54686b --- /dev/null +++ b/rdlogmanager/rdlogmanager.h @@ -0,0 +1,86 @@ +// rdlogmanager.h +// +// The Log Manager Utility for Rivendell. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rdlogmanager.h,v 1.14.6.2.2.1 2014/05/20 14:01:51 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDLOGMANAGER_H +#define RDLOGMANAGER_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define RDLOGMANAGER_USAGE "[-P] [-g] [-m] [-t] [-r ] [-d ] [-e ] -s \n\n-P\n Do not overwrite existing logs or imports.\n\n-g\n Generate a new log for the specified service.\n\n-m\n Merge the Music log for the specified service.\n\n-t\n Merge the Traffic log for the specified service.\n\n-r \n Generate report .\n\n-d \n Specify a start date offset. For log operations, this will be added\n to tomorrow's date to arrive at a target date, whereas for report\n operations it will be added to yesterday's date to arrive at a target\n date. Default value is '0'.\n\n-e \n Specify an end date offset. This will be added to yesterday's date\n to arrive at a target end date. Valid only for certain report types.\n Default value is '0'.\n\n-s \n Specify service for log operations.\n\n" + +// +// Command Line Operations +// +extern int RunLogOperation(int argc,char *argv[],const QString &svcname, + int start_offset,bool protect_existing,bool gen_log, + bool merge_mus,bool merge_tfc); +extern int RunReportOperation(int argc,char *argv[],const QString &rptname, + bool protect_existing,int start_offset, + int end_offset); + + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void userData(); + void eventsData(); + void clocksData(); + void gridsData(); + void generateData(); + void reportsData(); + void quitMainWidget(); + + private: + void LoadConfig(); + QSqlDatabase *log_db; + QString log_filename; + QLabel *log_user_label; + QPushButton *log_events_button; + QPushButton *log_clocks_button; + QPushButton *log_grids_button; + QPushButton *log_logs_button; + QPushButton *log_reports_button; + QPushButton *log_close_button; + QPixmap *log_rivendell_map; +}; + + +#endif diff --git a/rdlogmanager/rdlogmanager.pro b/rdlogmanager/rdlogmanager.pro new file mode 100644 index 00000000..8142c326 --- /dev/null +++ b/rdlogmanager/rdlogmanager.pro @@ -0,0 +1,101 @@ +# rdlogmanager.pro +# +# The rdlogmanager/ QMake project file for Rivendell +# +# (C) Copyright 2003-2004 Fred Gleason +# +# $Id: rdlogmanager.pro,v 1.21.2.3 2013/01/01 21:36:31 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +TARGET = rdlogmanager + +win32 { + DEFINES += WIN32 + DEFINES += VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE=\"rivendell\" + DEFINES += PACKAGE_VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE_NAME=\"rivendell\" + DEFINES += PACKAGE_BUGREPORT=\"fredg@paravelsystems.com\" +} + +SOURCES += add_clock.cpp +SOURCES += add_event.cpp +SOURCES += clock_listview.cpp +SOURCES += commandline_ops.cpp +SOURCES += edit_clock.cpp +SOURCES += edit_event.cpp +SOURCES += edit_eventline.cpp +SOURCES += edit_grid.cpp +SOURCES += edit_note.cpp +SOURCES += edit_perms.cpp +SOURCES += edit_schedrules.cpp +SOURCES += edit_schedcoderules.cpp +SOURCES += edit_track.cpp +SOURCES += generate_log.cpp +SOURCES += import_listview.cpp +SOURCES += lib_listview.cpp +SOURCES += list_clocks.cpp +SOURCES += list_events.cpp +SOURCES += list_grids.cpp +SOURCES += list_svcs.cpp +SOURCES += pick_report_dates.cpp +SOURCES += rdlogmanager.cpp +SOURCES += rename_item.cpp +SOURCES += svc_rec.cpp +SOURCES += svc_rec_dialog.cpp + +HEADERS += add_clock.h +HEADERS += add_event.h +HEADERS += clock_listview.h +HEADERS += edit_clock.h +HEADERS += edit_event.h +HEADERS += edit_eventline.h +HEADERS += edit_grid.h +HEADERS += edit_note.h +HEADERS += edit_perms.h +HEADERS += edit_schedrules.h +HEADERS += edit_schedcoderules.h +HEADERS += edit_track.h +HEADERS += generate_log.h +HEADERS += globals.h +HEADERS += import_listview.h +HEADERS += lib_listview.h +HEADERS += list_clocks.h +HEADERS += list_events.h +HEADERS += list_grids.h +HEADERS += list_svcs.h +HEADERS += pick_report_dates.h +HEADERS += rdlogmanager.h +HEADERS += rename_item.h +HEADERS += svc_rec.h +HEADERS += svc_rec_dialog.h + +RES_FILE += ..\icons\rivendell.res + +INCLUDEPATH += ..\lib + +LIBS = -lqui -L..\lib -llib + +CONFIG += qt + +TRANSLATIONS += rdlogmanager_cs.ts +TRANSLATIONS += rdlogmanager_de.ts +TRANSLATIONS += rdlogmanager_es.ts +TRANSLATIONS += rdlogmanager_fr.ts +TRANSLATIONS += rdlogmanager_nb.ts +TRANSLATIONS += rdlogmanager_nn.ts +TRANSLATIONS += rdlogmanager_pt_BR.ts diff --git a/rdlogmanager/rdlogmanager_cs.ts b/rdlogmanager/rdlogmanager_cs.ts new file mode 100644 index 00000000..1c5f2cbf --- /dev/null +++ b/rdlogmanager/rdlogmanager_cs.ts @@ -0,0 +1,1375 @@ + + + AddClock + + Add Log Clock + Přidat nové hodiny zápisu + + + &New Clock Name: + &Název nových hodin: + + + &OK + &OK + + + &Cancel + Z&rušit + + + + AddEvent + + Add Log Event + Přidat událost zápisu + + + &New Event Name: + &Název nové události: + + + &OK + &OK + + + &Cancel + Z&rušit + + + + ClockListView + + Edit Event + Upravit událost + + + + EditClock + + Edit Clock: + Upravit hodiny: + + + Code: + Kód: + + + Start + Začátek + + + End + Konec + + + Event + Událost + + + Length + Délka + + + Count + Počet + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + Scheduler +Rules + Pravidla pro +rozvrhovač + + + &Save + &Uložit + + + Save &As + Uložit &jako + + + &Services +List + Seznam +&služeb + + + Colo&r + &Barva + + + &OK + &OK + + + &Cancel + Z&rušit + + + Are you sure you want to +delete + Jste si jistý, že chcete smazat + + + Delete Event + Smazat událost + + + Clock Modified + Hodiny změněny + + + The clock has been modified. +Do you want to save? + Hodiny byly změněny. +Chcete je uložit? + + + Missing Clock Code + Chybí kód hodin + + + You must specify a clock code! + Musíte zadat kód hodin! + + + Code Exists + Kód existuje + + + The clock code is already in use! + Kód hodin se již používá! + + + Clock Exists + Hodiny existují + + + Clock already exists! Overwrite? + Hodiny již existují! Přepsat? + + + --- End of clock --- + --- Konec hodin --- + + + Invalid Code + Neplatný kód + + + You must provide a clock code! + Musíte zadat kód hodin! + + + Duplicate Code + Zdvojený kód + + + That code is already in use! + Tento kód se již používá! + + + Remarks + Poznámky + + + + EditEvent + + Editing Event + Upravit událost + + + Filter: + Filtr: + + + Group: + Skupina: + + + All + Vše + + + Audio Only + Pouze zvuk + + + Macros Only + Pouze makra + + + CART + VOZÍK + + + GROUP + SKUPINA + + + LENGTH + DÉLKA + + + TITLE + NÁZEV + + + ARTIST + UMĚLEC + + + START + ZAČÁTEK + + + END + KONEC + + + TYPE + TYP + + + ALL + VŠE + + + PRE-POSITION LOG + ZÁPIS PŘED-POLOHY + + + Cue to this event + CUE k této události + + + before scheduled start. (First cart will have a STOP transition.) + před naplánovaným začátkem. (První vozík bude mít přechod ZASTAVENÍ.) + + + TIMED START + PEVNÝ ZAČÁTEK + + + Use hard start time + Použít pevný počáteční čas + + + Make Post Point + Udělat bod vyvěšení + + + Action If Previous Event Still Playing + Činnost, když předchozí událost ještě běží + + + Start immediately + Spustit ihned + + + Make next + Jako další + + + Wait up to + Počkat až do + + + Play + Přehrát + + + Segue + Přechod + + + Stop + Zastavit + + + Transition if previous event ends before start time: + Přechod, když předchozí událost končí před počátečním časem: + + + ENFORCING LENGTH + VYNUCENÁ DÉLKA + + + Use AutoFill + Použít automatické vyplnění + + + Warn if fill is over or under + Varovat, když je automatické vyplnění větší nebo menší + + + by at least + než alespoň + + + Use Timescaling + Použít změnu času + + + TRANSITION + PŘECHOD + + + COUNT + POČÍTADLO + + + None + Žádný + + + From Traffic + Z přenosu + + + From Music + Z hudby + + + Select from: + Vybrat z: + + + Title Separation + Odstup názvů + + + Must have code + Vynutit kód + + + Import carts scheduled + Rozvrženy vozíky zavedení + + + prior to the start of this event. + před začátkem této události. + + + after the end of this event. + po začátku této události. + + + First cart has a + První vozík má + + + Imported carts have a + Zavedené vozíky mají + + + transition. + přechod. + + + Import inline traffic with the + Zavést vložený přenos s + + + [none] + [žádný] + + + event. + událost. + + + POST-IMPORT CARTS + VOZÍKY PO ZAVEDENÍ + + + &Save + &Uložit + + + Save &As + Uložit &jako + + + &Services +List + Seznam +&služeb + + + C&olor + &Barva + + + &OK + &OK + + + &Cancel + Z&rušit + + + RDLogManager + RDLogManager + + + Event already exists! +Do you want to overwrite it? + Událost již existuje! +Chcete ji přepsat? + + + Edit Event + Upravit událost + + + Audio + Zvuk + + + Macro + Makro + + + Cue + CUE + + + SEGUE + PŘECHOD + + + STOP + ZASTAVIT + + + PLAY + PŘEHRÁT + + + , Timed(Start) + , Pevný (Začátek) + + + , Timed(MakeNext) + , Načasovaný (Jako další) + + + Timed(Wait + Načasovaný (Čekat + + + , Post + , Po + + + , Fill + , Vyplnit + + + , Scale + , Změnit velikost + + + , Traffic + , Přenos + + + , Music + , Hudba + + + , Scheduler + , Rozvrhovač + + + , Inline Traffic + , Vložený přenos + + + REMARKS + POZNÁMKY + + + Len: + Délka: + + + PRE-IMPORT CARTS + + + + IMPORT + + + + + EditEventLine + + Edit Event Assignment + Upravit přiřazení události + + + Event: + Událost: + + + Select + Vybrat + + + Start Time: + Počáteční čas: + + + End Time: + Koncový čas: + + + &OK + &OK + + + &Cancel + Z&rušit + + + Invalid Event + Neplatná událost + + + The event end time cannot be earlier than the start time. + Koncový čas události nemůže ležet před počáteční časem. + + + No Such Event + Žádná taková událost + + + There is no such event. + Není žádná taková událost. + + + This event overlaps with an +already existing event. + Tato událost se překrývá s již +existující událostí. + + + + EditGrid + + Edit Grid: + Upravit mřížku: + + + Edit Clock + Upravit hodiny + + + &Close + &Zavřít + + + Clear Hour + Smazat hodiny + + + Change +&All + + + + Clear Clocks + + + + Are you sure you want to update ALL clocks in the grid? + + + + This operation cannot be undone! + + + + + EditNote + + Edit Log Note + Upravit poznámku k zápisu + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditPerms + + Service Associations + Přiřazení služeb + + + Available Services + Dostupné služby + + + Enabled Services + Povolené služby + + + &OK + &OK + + + &Cancel + Z&rušit + + + + EditSchedRules + + &Edit + &Upravit + + + &Import + &Zavést + + + &OK + &OK + + + &Cancel + Z&rušit + + + CODE + KÓD + + + MAX. IN A ROW + NEJVÍCE ZA SEBOU + + + MIN. WAIT + NEJMENŠÍ DOBA ČEKÁNÍ + + + DO NOT SCHEDULE AFTER + NEHRÁT PO + + + OR AFTER + NEBO PO + + + DESCRIPTION + POPIS + + + Scheduler Codes: + Kódy rozvrhovače: + + + Rules Modified + Pravidla změněna + + + The rules have been modified. +Do you want to save? + Pravidla byla změněna. +Chcete je uložit? + + + Scheduler Rules + + + + Artist Separation: + + + + Import Rules from Clock + + + + + EditTrack + + Edit Voice Track Marker + Upravit značku zápisu stopy hlasu + + + &OK + &OK + + + &Cancel + Z&rušit + + + + GenerateLog + + Generating Log... + Vytváří se zápis... + + + Cancel + Zrušit + + + Service: + Služba: + + + Date: + Datum: + + + &Select + &Vybrat + + + &Create New Log + &Vytvořit nový zápis + + + Merge &Music + Sloučit &hudbu + + + Merge &Traffic + Sloučit &přenos + + + Import Data + Zavést data + + + Available + Dostupné + + + Merged + Sloučeno + + + C&lose + &Zavřít + + + The log for + Zápis pro + + + already exists. Recreating it +will remove any merged Music or Traffic events. + +Recreate? + již existuje. Jeho znovuvytvoření odstraní +jakékoli události sloučené hudby nebo přenosu. + +Vytvořit znovu? + + + Log Exists + Zápis existuje + + + This will also delete the + Toto smaže i + + + voice tracks associated with this log. +Continue? + stopy hlasů spojených s tímto zápisem. +Pokračovat? + + + Tracks Exist + Stopa existuje + + + No Errors + Žádné chyby + + + No exceptions found. + Nenalezena žádná chyba. + + + already contains merged music and/or traffic data. +Remerging it will remove this data. Remerge? + již obsahuje sloučená data hudby a/nebo přenosu. +Opětovné sloučení tato data smaže. Sloučit znovu? + + + Music Exists + Hudba existuje + + + already contains merged traffic data. Remerging it +will remove this data. Remerge? + již obsahuje sloučená data přenosu. +Opětovné sloučení tato data smaže. Sloučit znovu? + + + Traffic Exists + Přenos existuje + + + Generate Log - User: + Vytvořit zápis - Uživatel: + + + + ImportListView + + Insert Log Note + Vložit poznámku k zápisu + + + Edit Log Note + Upravit poznámku k zápisu + + + Insert Voice Track + Vložit stopu hlasu + + + Edit Voice Track + Upravit stopu hlasu + + + Set PLAY Transition + Nastavit přechod PŘEHRÁT + + + Set SEGUE Transition + Nastavit přechod PŘECHOD + + + Set STOP Transition + Nastavit přechod ZASTAVIT + + + Delete + Smazat + + + Marker + Značka + + + [Log Note] + [Poznámka k zápisu] + + + Track + Stopa + + + [Voice Track] + [Stopa hlasu] + + + PLAY + PŘEHRÁT + + + SEGUE + PŘECHOD + + + STOP + ZASTAVIT + + + + ListClocks + + Filter: + Filtr: + + + Name + Název + + + Code + Kód + + + Color + Barva + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &Rename + &Přejmenovat + + + C&lose + &Zavřít + + + C&lear + &Vyprázdnit + + + &OK + &OK + + + &Cancel + Z&rušit + + + ALL + VŠE + + + NONE + ŽÁDNÝ + + + Clock Exists + Hodiny existují + + + An clock with that name already exists! + Hodiny s tímto názvem již existují! + + + Are you sure you want to +delete + Jste si jistý, že chcete smazat + + + Delete Clock + Smazat hodiny + + + is in use in the following grid(s): + se používá následující mřížkou(ami): + + + Do you still want to delete it? + Stále ještě chcete smazat? + + + Clock In Use + Používané hodiny + + + Log Clocks - User: + Zápis - Uživatel hodin: + + + + ListEvents + + Filter: + Filtr: + + + Name + Název + + + Properties + Vlastnosti + + + Color + Barva + + + &Add + &Přidat + + + &Edit + &Upravit + + + &Delete + S&mazat + + + &Rename + &Přejmenovat + + + &OK + &OK + + + &Ok + &OK + + + &Cancel + Z&rušit + + + ALL + VŠE + + + NONE + ŽÁDNÝ + + + Event Exists + Událost existuje + + + An event with that name already exists! + Událost s tímto názvem již existuje! + + + Are you sure you want to +delete + Jste si jistý, že chcete smazat + + + Delete Event + Smazat událost + + + is in use in the following clocks: + se používá následujícími hodinami: + + + Do you still want to delete it? + Stále ještě chcete smazat? + + + Event In Use + Používaná událost + + + Log Events - User: + Zápis - Události - Uživatel: + + + + ListGrids + + Log Grids + Mřížky zápisu + + + Name + Název + + + Description + Popis + + + &Edit + &Upravit + + + C&lose + &Zavřít + + + + ListSvcs + + Rivendell Services + Služby Rivendell + + + SERVICE + SLUŽBA + + + OLDEST REPORT + NEJSTARŠÍ ZPRÁVA + + + &Generate +Reports + &Vytvořit +zprávy + + + &Purge +Data + &Smazat +data + + + C&lose + &Zavřít + + + [none] + [žádný] + + + + MainWidget + + Can't Connect + Nelze spojit + + + RDLogManager + RDLogManager + + + Select an operation: + Vyberte operaci: + + + Edit &Events + Upravit &události + + + Edit C&locks + Upravit &hodiny + + + Edit G&rids + Upravit &mřížky + + + &Generate Logs + &Vytvořit zápisy + + + Manage &Reports + Spravovat zpráv&y + + + &Close + &Zavřít + + + RDLogManager - User: + RDLogManager - Uživatel: + + + RDLogEdit -- Database Skew + RDLogEdit - Nesouměrnost v databázi + + + This version of RDLogManager is incompatible with the version installed on the server. +See your system administrator for an update! + Tato verze RDLogManager je neslučitelná s verzí nainstalovanou na serveru. +Vyhledejte svého správce systému kvůli aktualizaci! + + + + PickReportDates + + Select Report Dates + Vybrat data zprávy + + + &Report: + &Zpráva: + + + &Start Date: + &Počáteční datum: + + + &Select + &Vybrat + + + &End Date: + &Koncové datum: + + + &Generate +Report + &Vytvořit +zprávu + + + C&lose + &Zavřít + + + Invalid Date Range + Neplatný rozsah data + + + The end date cannot be earlier than the start date! + Koncové datum se nemůže nacházet před počáteční datem! + + + This report type cannot span multiple dates! + Tato zpráva nemůže zahrnout více dní! + + + This report type cannot span multiple months! + Tato zpráva nemůže zahrnout více měsíců! + + + Report Complete + Zpráva úplná + + + Report complete! + Zpráva úplná! + + + Report generated in + + + + + RenameItem + + Rename + Přejmenovat + + + &OK + &OK + + + &Cancel + Z&rušit + + + Name Conflict + Střet názvů + + + That name already exists! + Název již existuje! + + + + SvcRec + + Mo + Po + + + Tu + Út + + + We + St + + + Th + Čt + + + Fr + + + + Sa + So + + + Su + Ne + + + + SvcRecDialog + + Report Data + Data zprávy + + + &Purge +Data + &Smazat +data + + + &Close + &Zavřít + + + Delete Report Data + Smazat data zprávy + + + Are you sure you want to delete report data for + Jste si jistý, že chcete smazat data zprávy pro + + + + editSchedCodeRules + + &OK + &OK + + + &Cancel + Z&rušit + + + Code: + Kód: + + + Max. in a row: + Nejvíce za sebou: + + + Min. wait: + Nejmenší doba čekání: + + + Do not schedule after: + Nezařazovat po: + + + Or after: + nebo po: + + + Edit Rules for Code + + + + diff --git a/rdlogmanager/rdlogmanager_de.ts b/rdlogmanager/rdlogmanager_de.ts new file mode 100644 index 00000000..bf8d90f4 --- /dev/null +++ b/rdlogmanager/rdlogmanager_de.ts @@ -0,0 +1,1374 @@ + + + AddClock + + Add Log Clock + Neue Loguhr hinzufügen + + + &New Clock Name: + &Name der neuen Uhr: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + AddEvent + + Add Log Event + Log Event hinzufügen + + + &New Event Name: + &Neuer Eventname: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + ClockListView + + Edit Event + Event editieren + + + + EditClock + + Edit Clock: + Uhr editieren: + + + Code: + Code: + + + Start + Start + + + End + Ende + + + Event + Event + + + Length + Länge + + + Count + Zähler + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + Scheduler +Rules + Scheduler +Regeln + + + &Save + &Speichern + + + Save &As + Speichern &Als + + + &Services +List + &Services +Liste + + + Colo&r + Fa&rbe + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Are you sure you want to +delete + Löschen von + + + Delete Event + Event Löschen + + + Clock Modified + Uhr modifiziert + + + The clock has been modified. +Do you want to save? + Die Uhr wurde modifiziert. +Wollen Sie sie speichern? + + + Missing Clock Code + Uhr Code fehlt + + + You must specify a clock code! + Sie müssen einen Uhr-Code eingeben! + + + Code Exists + Code existiert + + + The clock code is already in use! + Der Uhrcode wird bereits verwendet! + + + Clock Exists + Uhr existiert + + + Clock already exists! Overwrite? + Uhr existiert bereits! Überschreiben? + + + --- End of clock --- + --- Ende der Uhr --- + + + Invalid Code + Ungültiger Code + + + You must provide a clock code! + Sie müssen einen Uhrcode angeben! + + + Duplicate Code + Doppelter Code + + + That code is already in use! + Dieser Code wird bereits verwendet! + + + Remarks + Bemerkungen + + + + EditEvent + + Editing Event + Event editieren + + + Filter: + Filter: + + + Group: + Gruppe: + + + All + Alle + + + Audio Only + Nur Audio + + + Macros Only + Nur Makros + + + CART + CART + + + GROUP + GRUPPE + + + LENGTH + LÄNGE + + + TITLE + TITEL + + + ARTIST + KÜNSTLER + + + START + START + + + END + ENDE + + + TYPE + TYP + + + ALL + ALLE + + + PRE-POSITION LOG + VOR-POSTIONSLOG + + + Cue to this event + Cue zu diesem Event + + + before scheduled start. (First cart will have a STOP transition.) + vor dem geplanten Start. (Der erste Cart wird einen STOP-Übergang haben.) + + + TIMED START + FESTER START + + + Use hard start time + Harte Startzeit verwenden + + + Make Post Point + Post Point machen + + + Action If Previous Event Still Playing + Aktion wenn vorheriges Event noch läuft + + + Start immediately + Sofort starten + + + Make next + Als Nächstes + + + Wait up to + Warte bis zu + + + Play + Abspielen + + + Segue + Übergang + + + Stop + Stop + + + Transition if previous event ends before start time: + Übergang wenn vorheriges Event vor der Startzeit endet: + + + ENFORCING LENGTH + ERZWUNGENE LÄNGE + + + Use AutoFill + AutoFill verwenden + + + Warn if fill is over or under + Warnen, wenn AutoFill mehr oder weniger + + + by at least + als mindestens + + + Use Timescaling + Verwende Zeitskalierung + + + TRANSITION + ÜBERGANG + + + COUNT + ZÄHLER + + + None + Keine + + + From Traffic + Von Traffic + + + From Music + Von Musik + + + Select from: + Wähle aus: + + + Title Separation + Titelabstand + + + Must have code + Erzwinge Code + + + Import carts scheduled + Import-Carts geplant + + + prior to the start of this event. + vor dem Start dieses Events. + + + after the end of this event. + nach dem Start dieses Events. + + + First cart has a + erster Cart hat einen + + + Imported carts have a + Importierte Carts haben eine + + + transition. + Übergang. + + + Import inline traffic with the + Importiere Inline-Traffic mit dem + + + [none] + [keine] + + + event. + Event. + + + POST-IMPORT CARTS + CARTS NACH DEM IMPORT + + + &Save + &Speichern + + + Save &As + Speichern &Als + + + &Services +List + &Services +Liste + + + C&olor + &Farbe + + + &OK + &OK + + + &Cancel + Abbre&chen + + + RDLogManager + RDLogManager + + + Event already exists! +Do you want to overwrite it? + Event existiert bereits! +Wollen Sie es überschreiben? + + + Edit Event + Event editieren + + + Audio + Audio + + + Macro + Makro + + + Cue + CUE + + + SEGUE + ÜBERGANG + + + STOP + STOP + + + PLAY + PLAY + + + , Timed(Start) + , Fest (Start) + + + , Timed(MakeNext) + , Zeitstart(AlsNächstes) + + + Timed(Wait + Zeitstart(Warte + + + , Post + , Nach + + + , Fill + , Füllen + + + , Scale + , Scale + + + , Traffic + , Traffic + + + , Music + , Musik + + + , Scheduler + , Scheduler + + + , Inline Traffic + , Inline Traffic + + + REMARKS + BEMERKUNGEN + + + Len: + Länge: + + + PRE-IMPORT CARTS + + + + IMPORT + + + + + EditEventLine + + Edit Event Assignment + Event-Zuordnung editieren + + + Event: + Event: + + + Select + Auswählen + + + Start Time: + Startzeit: + + + End Time: + Endzeit: + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Invalid Event + Ungültiges Event + + + The event end time cannot be earlier than the start time. + Die Endzeit des Events kann nicht vor der Startzeit liegen. + + + No Such Event + Kein solches Event + + + There is no such event. + Es gibt kein solches Event. + + + This event overlaps with an +already existing event. + Dieses Event überschneidet sich mit +einem bereits existierendem Event. + + + + EditGrid + + Edit Grid: + Grid editieren: + + + Edit Clock + Uhr editieren + + + &Close + &Schliessen + + + Clear Hour + Stunde löschen + + + Change +&All + + + + Clear Clocks + + + + Are you sure you want to update ALL clocks in the grid? + + + + This operation cannot be undone! + + + + + EditNote + + Edit Log Note + Log Notiz editieren + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + EditPerms + + Service Associations + Service-Zuordnungen + + + Available Services + Verfügbare Services + + + Enabled Services + Verwendete Services + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + EditSchedRules + + &Edit + &Editieren + + + &Import + &Importieren + + + &OK + &OK + + + &Cancel + Abbre&chen + + + CODE + CODE + + + MAX. IN A ROW + MAX HINTEREINANDER + + + MIN. WAIT + MIN WARTEZEIT + + + DO NOT SCHEDULE AFTER + SPIELE NICHT NACH + + + OR AFTER + ODER NACH + + + DESCRIPTION + BESCHREIBUNG + + + Scheduler Codes: + Scheduler Codes: + + + Rules Modified + Regeln modifiziert + + + The rules have been modified. +Do you want to save? + Die Regeln wurden geändert. +Wollen Sie sie speichern? + + + Scheduler Rules + + + + Artist Separation: + + + + Import Rules from Clock + + + + + EditTrack + + Edit Voice Track Marker + Voice Track Marker editieren + + + &OK + &OK + + + &Cancel + Abbre&chen + + + + GenerateLog + + Generating Log... + Generiere Log... + + + Cancel + Abbrechen + + + Service: + Service: + + + Date: + Datum: + + + &Select + Au&swählen + + + &Create New Log + &Neues Log erstellen + + + Merge &Music + &Musik zusammenführen + + + Merge &Traffic + &Traffic zusammenführen + + + Import Data + Daten importieren + + + Available + Verfügbar + + + Merged + Verbunden + + + C&lose + &Schliessen + + + The log for + Das Log für + + + already exists. Recreating it +will remove any merged Music or Traffic events. + +Recreate? + existiert bereits. Es erneut zu erstellen +wird alle verbundene Musik oder Traffic Events entfernen. + +Neu erstellen? + + + Log Exists + Log existiert + + + This will also delete the + Dies löscht ebenfalls die + + + voice tracks associated with this log. +Continue? + Voice Tracks die mit diesem Log verbunden sind. +Fortfahren? + + + Tracks Exist + Track existiert + + + No Errors + Keine Fehler + + + No exceptions found. + Keine Fehler gefunden. + + + already contains merged music and/or traffic data. +Remerging it will remove this data. Remerge? + enthält bereits eingebundene Musik- und/oder Trafficdaten. +Erneutes einbinden wird diese löschen. Erneut einbinden? + + + Music Exists + Musik existiert + + + already contains merged traffic data. Remerging it +will remove this data. Remerge? + enthält bereits verbundene Trafficdaten. Erneutes +Einbinden wird diese entfernen. Fortfahren? + + + Traffic Exists + Traffix existiert + + + Generate Log - User: + Generiere Log - User: + + + + ImportListView + + Insert Log Note + Log-Notiz einfügen + + + Edit Log Note + Log Notiz editieren + + + Insert Voice Track + Voice Track einfügen + + + Edit Voice Track + Voice Track editieren + + + Set PLAY Transition + PLAY-Übergang setzen + + + Set SEGUE Transition + SEGUE-Übergang setzen + + + Set STOP Transition + STOP-Übergang setzen + + + Delete + löschen + + + Marker + Marker + + + [Log Note] + [log notiz] + + + Track + Track + + + [Voice Track] + [Voice Track] + + + PLAY + PLAY + + + SEGUE + ÜBERGANG + + + STOP + STOP + + + + ListClocks + + Filter: + Filter: + + + Name + Name + + + Code + Code + + + Color + Farbe + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &Rename + &Umbenennen + + + C&lose + &Schliessen + + + C&lear + &Löschen + + + &OK + &OK + + + &Cancel + Abbre&chen + + + ALL + ALLE + + + NONE + KEINE + + + Clock Exists + Uhr existiert + + + An clock with that name already exists! + Eine Uhr mit diesem Namen existiert bereits! + + + Are you sure you want to +delete + Löschen von + + + Delete Clock + Uhr löschen + + + is in use in the following grid(s): + wird von folgenden grid(s) verwendet: + + + Do you still want to delete it? + Wollen Sie immernoch löschen? + + + Clock In Use + Uhr in Verwendung + + + Log Clocks - User: + Log-Uhrenbenutzer: + + + + ListEvents + + Filter: + Filter: + + + Name + Name + + + Properties + Eigenschaften + + + Color + Farbe + + + &Add + &Hinzufügen + + + &Edit + &Editieren + + + &Delete + &Löschen + + + &Rename + &Umbenennen + + + &OK + &OK + + + &Ok + &OK + + + &Cancel + Abbre&chen + + + ALL + ALLE + + + NONE + KEINE + + + Event Exists + Event existiert + + + An event with that name already exists! + Ein Event mit diesem Namen existiert bereits! + + + Are you sure you want to +delete + Löschen von + + + Delete Event + Event Löschen + + + is in use in the following clocks: + wird von folgenden Uhren verwendet: + + + Do you still want to delete it? + Wollen Sie immernoch löschen? + + + Event In Use + Event in Verwendung + + + Log Events - User: + Log-Events-Benutzer: + + + + ListGrids + + Log Grids + Log Grids + + + Name + Name + + + Description + Beschreibung + + + &Edit + &Editieren + + + C&lose + &Schliessen + + + + ListSvcs + + Rivendell Services + Rivendell Services + + + SERVICE + SERVICE + + + OLDEST REPORT + ÄLTESTER REPORT + + + &Generate +Reports + Reports +&Generieren + + + &Purge +Data + Daten +&Löschen + + + C&lose + &Schliessen + + + [none] + [keine] + + + + MainWidget + + Can't Connect + Kann nicht verbinden + + + RDLogManager + RDLogManager + + + Select an operation: + Wählen Sie eine Operation: + + + Edit &Events + &Events editieren + + + Edit C&locks + &Uhren editieren + + + Edit G&rids + &Grids editieren + + + &Generate Logs + Logs &Generieren + + + Manage &Reports + &Reporte managen + + + &Close + &Schliessen + + + RDLogManager - User: + RDLogManager - Benutzer: + + + RDLogEdit -- Database Skew + + + + This version of RDLogManager is incompatible with the version installed on the server. +See your system administrator for an update! + + + + + PickReportDates + + Select Report Dates + Reportdaten auswählen + + + &Report: + &Report: + + + &Start Date: + &Startdatum: + + + &Select + Au&swählen + + + &End Date: + &Enddatum: + + + &Generate +Report + &Generiere +Report + + + C&lose + &Schliessen + + + Invalid Date Range + Ungültiger Datenbereich + + + The end date cannot be earlier than the start date! + Das Enddatum kann nicht vor dem Startdatum liegen! + + + This report type cannot span multiple dates! + Dieser Report kann nicht mehrere Tage umfassen! + + + This report type cannot span multiple months! + Dieser Report kann nicht mehrere Monate einschliessen! + + + Report Complete + Report komplett + + + Report complete! + Report komplett! + + + Report generated in + + + + + RenameItem + + Rename + Umbenennen + + + &OK + &OK + + + &Cancel + Abbre&chen + + + Name Conflict + Namenskonflikt + + + That name already exists! + Dieser Name existiert bereits! + + + + SvcRec + + Mo + Mo + + + Tu + Di + + + We + Mi + + + Th + Do + + + Fr + Fr + + + Sa + Sa + + + Su + So + + + + SvcRecDialog + + Report Data + Reportdaten + + + &Purge +Data + Daten +&Löschen + + + &Close + &Schliessen + + + Delete Report Data + Reportdaten löschen + + + Are you sure you want to delete report data for + Reportdaten wirklich löschen für + + + + editSchedCodeRules + + &OK + &OK + + + &Cancel + Abbre&chen + + + Code: + Code: + + + Max. in a row: + Max. hintereinander: + + + Min. wait: + Mindestwartezeit: + + + Do not schedule after: + Plane nicht nach: + + + Or after: + oder nach: + + + Edit Rules for Code + + + + diff --git a/rdlogmanager/rdlogmanager_es.ts b/rdlogmanager/rdlogmanager_es.ts new file mode 100644 index 00000000..b3a60a17 --- /dev/null +++ b/rdlogmanager/rdlogmanager_es.ts @@ -0,0 +1,1378 @@ + + + AddClock + + Add Log Clock + Añadir Torta + + + &New Clock Name: + &Nombre de la Torta: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + AddEvent + + Add Log Event + Añadir Evento + + + &New Event Name: + &Nombre del Evento: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + ClockListView + + Edit Event + Editar Evento + + + + EditClock + + Edit Clock: + Editar Torta: + + + Code: + Código: + + + Start + Inicio + + + End + Fin + + + Event + Evento + + + Length + Duración + + + Count + Cuenta + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + &Borrar + + + &Save + &Guardar + + + Save &As + Guardar +&como + + + &Services +List + Lista de +&Servicios + + + Colo&r + Colo&r + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Are you sure you want to +delete + ¿Realmente desea +eliminar + + + Delete Event + Eliminar Evento + + + Clock Modified + Cambios almacenados + + + The clock has been modified. +Do you want to save? + Se han hecho modificaciones. +¿Desea guardarlas? + + + Clock Exists + Ya existe una torta + + + Clock already exists! Overwrite? + Ya existe una torta con ese nombre. ¿Sobreescribir? + + + --- End of clock --- + --- Fin de la torta --- + + + Invalid Code + Código inválido + + + You must provide a clock code! + ¡Debe indicar un código para la torta! + + + Duplicate Code + Código duplicado + + + That code is already in use! + ¡Ese código ya está en uso! + + + Code Exists + El código ya existe + + + The clock code is already in use! + ¡El código para la torta ya está en uso! + + + Missing Clock Code + Falta el código + + + You must specify a clock code! + ¡Debe suministrar un código para la torta horaria! + + + Scheduler +Rules + Reglas de +horario + + + Remarks + Comentarios + + + + EditEvent + + Editing Event + Editar Evento + + + Filter: + Filtro: + + + Group: + Grupo: + + + All + Todo + + + Audio Only + Sólo Audios + + + Macros Only + Sólo Macros + + + CART + CARTUCHO + + + GROUP + GRUPO + + + LENGTH + DURACIÓN + + + TITLE + TÍTULO + + + ARTIST + ARTISTA + + + START + INICIO + + + END + FIN + + + TYPE + TIPO + + + ALL + TODO + + + PRE-POSITION LOG + LISTA PRE-POSICIÓN + + + Cue to this event + Señalar este evento + + + before scheduled start. (First cart will have a STOP transition.) + antes de su inicio programado (el 1er cartucho tendrá transición PARAR) + + + TIMED START + INICIO PROGRAMADO + + + Use hard start time + Usar inicio forzado + + + Make Post Point + Hacer Post Point + + + Action If Previous Event Still Playing + Acción si hay algún evento sonando + + + Start immediately + Iniciar de inmediato + + + Make next + Hacer siguiente + + + Wait up to + Espera hasta + + + Play + Reproducir + + + Segue + Segue + + + Stop + Parar + + + Transition if previous event ends before start time: + Transición si evento termina antes que éste inicie: + + + ENFORCING LENGTH + FORZAR DURACIÓN + + + Use AutoFill + Usar Autofill + + + Use Timescaling + Usar Timescaling + + + TRANSITION + TRANSICIÓN + + + COUNT + CUENTA + + + None + Ninguno + + + From Traffic + De Tráfico + + + From Music + De Música + + + Import carts scheduled + Importar carts programados + + + prior to the start of this event. + antes del inicio de este evento. + + + after the end of this event. + después del fin del evento. + + + First cart has a + Transic 1er cart + + + Imported carts have a + Transic. cart. importados + + + transition. + . + + + POST-IMPORT CARTS + CARTUCHOS AL TERMINAR + + + &Save + &Guardar + + + Save &As + Guardar &como + + + &Services +List + Lista de +&Servicios + + + C&olor + C&olor + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + RDLogManager + RDLogManager + + + Edit Event + Editar Evento + + + Audio + Audio + + + Macro + Macro + + + Cue + Cue + + + SEGUE + SEGUE + + + STOP + PARAR + + + PLAY + REPROD + + + , Timed(Start) + , Tiempo(Inicio) + + + , Timed(MakeNext) + , Tiempo(HacerSiguiente) + + + Timed(Wait + Tiempo(Esperar + + + , Post + , Post + + + , Fill + , Llenar + + + , Scale + , Escalar + + + , Traffic + , Tráfico + + + , Music + , Música + + + Event already exists! +Do you want to overwrite it? + ¡El evento ya exista! +¿Quiere sobreescribirlo? + + + Warn if fill is over or under + Advertir si relleno está encima o debajo + + + by at least + por al menos + + + [none] + [ninguno] + + + event. + . + + + Import inline traffic with the + Importar tráfico con el evento + + + , Inline Traffic + , tráfico en línea + + + Select from: + Elegir desde: + + + Title Separation + Separar títulos + + + Must have code + Con el código + + + , Scheduler + , Programador + + + REMARKS + COMENTARIOS + + + Len: + Long: + + + PRE-IMPORT CARTS + PRE-IMPORTAR CARTUCHOS + + + IMPORT + IMPORTAR + + + + EditEventLine + + Edit Event Assignment + Editar Asignación de Evento + + + Event: + Evento: + + + Select + Elegir + + + Start Time: + Hora Inicio: + + + End Time: + Hora de Fin: + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Invalid Event + Evento inválido + + + The event end time cannot be earlier than the start time. + La hora de finalización no puede ser menor a la hora de inicio. + + + No Such Event + No existe el evento + + + There is no such event. + El evento especificado no existe. + + + This event overlaps with an +already existing event. + Este evento se superpone con +un evento ya existente. + + + + EditGrid + + Edit Grid: + Editar Parrilla: + + + &Close + &Cerrar + + + Edit Clock + Editar Torta + + + Clear Hour + Limpiar tortas + + + Change +&All + + + + Clear Clocks + + + + Are you sure you want to update ALL clocks in the grid? + + + + This operation cannot be undone! + + + + + EditNote + + Edit Log Note + Editar nota de la lista + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + EditPerms + + Service Associations + Asociaciones de Servicios + + + Available Services + Servicios Disponibles + + + Enabled Services + Servicios Activos + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + EditSchedRules + + &Edit + &Editar + + + &Import + &Importar + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + CODE + CÓDIGO + + + MAX. IN A ROW + MAX EN UNA FILA + + + MIN. WAIT + MIN. ESPERA + + + DO NOT SCHEDULE AFTER + NO PROGRAMAR DESPUÉS + + + OR AFTER + O DESPUÉS + + + DESCRIPTION + DESCRIPCIÓN + + + Scheduler Codes: + Códigos para programación: + + + Rules Modified + Reglas modificadas + + + The rules have been modified. +Do you want to save? + Las reglas han sido modificadas. +¿Desea guardarlas? + + + Scheduler Rules + Reglas de Horario + + + Artist Separation: + Separac. p/Artista: + + + Import Rules from Clock + Importar reglas desde Torta + + + + EditTrack + + Edit Voice Track Marker + Editar Marcador de la pista de voz + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + + GenerateLog + + Generating Log... + Generando Lista... + + + Cancel + Cancelar + + + Service: + Servicio: + + + Date: + Fecha: + + + &Select + &Elegir + + + C&lose + &Cerrar + + + The log for + La lista para + + + Log Exists + La lista ya existe + + + No Errors + No hubo errores + + + No exceptions found. + No se encontraron errores. + + + This will also delete the + Esto también borrará las + + + voice tracks associated with this log. +Continue? + pistas de voz asociadas a esta lista. +¿Continuar? + + + Tracks Exist + La pista ya existe + + + &Create New Log + &Crear nueva lista + + + Merge &Music + Fusionar &Música + + + Merge &Traffic + Fusionar &Tráfico + + + already exists. Recreating it +will remove any merged Music or Traffic events. + +Recreate? + ya existe. Al recrearlo +se eliminará cualquier evento de Música o Tráfico fusionados. + +¿Recrear? + + + Music Exists + La Música ya existe + + + Traffic Exists + El Tráfico ya existe + + + already contains merged music and/or traffic data. +Remerging it will remove this data. Remerge? + ya contiene datos de música o tráfico fusionados. +Remezclarlos removerá estos datos. ¿Remezclar? + + + already contains merged traffic data. Remerging it +will remove this data. Remerge? + ya contiene datos de tráfico fusionados. Remezclarlos +removerá estos datos. ¿Remezclar? + + + Available + Disponible + + + Merged + Fusionados + + + Import Data + Datos a importar + + + Generate Log - User: + Generar lista - Usuario: + + + + ImportListView + + Insert Log Note + Insertar nota de la lista + + + Edit Log Note + Editar nota de la lista + + + Set PLAY Transition + Asignar transición REPROD + + + Set SEGUE Transition + Asignar transición SEGUE + + + Set STOP Transition + Asignar transición PARAR + + + Delete + Borrar + + + Marker + Marcador + + + [Log Note] + [Nota de lista] + + + PLAY + REPROD + + + SEGUE + SEGUE + + + STOP + PARAR + + + Track + Pista + + + [Voice Track] + [Pista de voz] + + + Insert Voice Track + Insertar pista de voz + + + Edit Voice Track + Editar pista de voz + + + + ListClocks + + Filter: + Filtro: + + + Name + Nombre + + + Code + Código + + + Color + Color + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + &Borrar + + + C&lose + &Cerrar + + + C&lear + &Limpiar + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + ALL + TODO + + + Clock Exists + Ya existe una torta + + + An clock with that name already exists! + ¡Una torta con ese nombre ya existe! + + + Are you sure you want to +delete + Realmente desea +eliminar + + + Delete Clock + Eliminar torta + + + is in use in the following grid(s): + está en uso en las siguiente(s) parrilla(s): + + + Do you still want to delete it? + ¿Desea eliminarla de cualquier forma? + + + Clock In Use + Torta en uso + + + &Rename + &Renombrar + + + NONE + NINGUNA + + + Log Clocks - User: + Tortas - Usuario: + + + + ListEvents + + Filter: + Filtro: + + + Name + Nombre + + + Properties + Propiedades + + + Color + Color + + + &Add + &Añadir + + + &Edit + &Editar + + + &Delete + &Borrar + + + &OK + &Aceptar + + + &Ok + &Aceptar + + + &Cancel + &Cancelar + + + ALL + TODO + + + Event Exists + El evento ya existe + + + An event with that name already exists! + ¡Un evento con ese nombre ya existe! + + + Are you sure you want to +delete + Realmente desea +eliminar + + + Delete Event + Eliminar Evento + + + is in use in the following clocks: + está en uso en las siguientes tortas: + + + Do you still want to delete it? + ¿Aún así desea eliminarla? + + + Event In Use + El evento está en uso + + + &Rename + &Renombrar + + + NONE + NINGUNO + + + Log Events - User: + Eventos - Usuario: + + + + ListGrids + + Log Grids + Parrillas + + + Name + Nombre + + + Description + Descripción + + + &Edit + &Editar + + + C&lose + &Cerrar + + + + ListSvcs + + Rivendell Services + Servicios Rivendell + + + SERVICE + SERVICIO + + + OLDEST REPORT + REPORTE MAS ANTIGUO + + + C&lose + &Cerrar + + + [none] + [ninguno] + + + &Purge +Data + &Purgar datos + + + &Generate +Reports + &Generar +Reportes + + + + MainWidget + + Can't Connect + No puedo conectarme + + + RDLogManager + + + + Select an operation: + Elija una operación: + + + Edit &Events + Editar &Eventos + + + Edit C&locks + Editar &Tortas + + + Edit G&rids + Edtar &Parrillas + + + &Generate Logs + &Generar Listas + + + &Close + &Cerrar + + + Manage &Reports + Admin. &Reportes + + + RDLogManager - User: + RDLogManager - Usuario: + + + RDLogEdit -- Database Skew + RDLOgEdit -- Asimetría en la base de datos + + + This version of RDLogManager is incompatible with the version installed on the server. +See your system administrator for an update! + Esta versión de RDLogManager no es compatible con la versión instalada en el servidor. +¡Solicite al administrador del sistema una actualización! + + + + PickReportDates + + Select Report Dates + Elija las fechas para el reporte + + + &Report: + &Reporte: + + + &Start Date: + Fecha &Inicio: + + + &Select + &Elegir + + + &End Date: + Fecha &Final: + + + &Generate +Report + &Generar +Reporte + + + C&lose + C&errar + + + Invalid Date Range + Rango de fechas inválido + + + The end date cannot be earlier than the start date! + ¡La hora de finalización no puede ser menor a la hora de inicio! + + + This report type cannot span multiple dates! + ¡Este reporte no puede emitir múltiples fechas! + + + This report type cannot span multiple months! + ¡Este reporte no puede emitir múltiples meses! + + + Report Complete + Reporte completado + + + Report complete! + ¡Reporte completado! + + + Report generated in + + + + + RenameItem + + Rename + Renombrar + + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Name Conflict + Conflicto de nombres + + + That name already exists! + ¡Ese nombre ya existe! + + + + SvcRec + + Mo + Lu + + + Tu + Ma + + + We + Mi + + + Th + Ju + + + Fr + Vi + + + Sa + + + + Su + Do + + + + SvcRecDialog + + Report Data + Reporte de datos + + + &Close + &Cerrar + + + Delete Report Data + Borrar Reporte de Datos + + + Are you sure you want to delete report data for + Desea eliminar el reporte de datos para + + + &Purge +Data + &Borrar +Datos + + + + editSchedCodeRules + + &OK + &Aceptar + + + &Cancel + &Cancelar + + + Code: + Código: + + + Max. in a row: + Máx. por fila: + + + Min. wait: + Espera Mín.: + + + Do not schedule after: + No programar después de: + + + Or after: + O después de: + + + Edit Rules for Code + Editar reglas para el código + + + diff --git a/rdlogmanager/rdlogmanager_fr.ts b/rdlogmanager/rdlogmanager_fr.ts new file mode 100644 index 00000000..7b9fbb6b --- /dev/null +++ b/rdlogmanager/rdlogmanager_fr.ts @@ -0,0 +1,1353 @@ + + + AddClock + + Add Log Clock + + + + &New Clock Name: + + + + &OK + + + + &Cancel + + + + + AddEvent + + Add Log Event + + + + &New Event Name: + + + + &OK + + + + &Cancel + + + + + ClockListView + + Edit Event + + + + + EditClock + + Edit Clock: + + + + Code: + + + + Start + + + + End + + + + Event + + + + Length + + + + Count + + + + &Add + + + + &Edit + + + + &Delete + + + + Scheduler +Rules + + + + &Save + + + + Save &As + + + + &Services +List + + + + Colo&r + + + + &OK + + + + &Cancel + + + + Are you sure you want to +delete + + + + Delete Event + + + + Clock Modified + + + + The clock has been modified. +Do you want to save? + + + + Missing Clock Code + + + + You must specify a clock code! + + + + Code Exists + + + + The clock code is already in use! + + + + Clock Exists + + + + Clock already exists! Overwrite? + + + + --- End of clock --- + + + + Invalid Code + + + + You must provide a clock code! + + + + Duplicate Code + + + + That code is already in use! + + + + Remarks + + + + + EditEvent + + Editing Event + + + + Filter: + + + + Group: + + + + All + + + + Audio Only + + + + Macros Only + + + + CART + + + + GROUP + + + + LENGTH + + + + TITLE + + + + ARTIST + + + + START + + + + END + + + + TYPE + + + + ALL + + + + PRE-POSITION LOG + + + + Cue to this event + + + + before scheduled start. (First cart will have a STOP transition.) + + + + TIMED START + + + + Use hard start time + + + + Make Post Point + + + + Action If Previous Event Still Playing + + + + Start immediately + + + + Make next + + + + Wait up to + + + + Play + + + + Segue + + + + Stop + + + + Transition if previous event ends before start time: + + + + ENFORCING LENGTH + + + + Use AutoFill + + + + Warn if fill is over or under + + + + by at least + + + + Use Timescaling + + + + TRANSITION + + + + COUNT + + + + None + + + + From Traffic + + + + From Music + + + + Select from: + + + + Title Separation + + + + Must have code + + + + Import carts scheduled + + + + prior to the start of this event. + + + + after the end of this event. + + + + First cart has a + + + + Imported carts have a + + + + transition. + + + + Import inline traffic with the + + + + [none] + + + + event. + + + + POST-IMPORT CARTS + + + + &Save + + + + Save &As + + + + &Services +List + + + + C&olor + + + + &OK + + + + &Cancel + + + + RDLogManager + + + + Event already exists! +Do you want to overwrite it? + + + + Edit Event + + + + Audio + + + + Macro + + + + Cue + + + + SEGUE + + + + STOP + + + + PLAY + + + + , Timed(Start) + + + + , Timed(MakeNext) + + + + Timed(Wait + + + + , Post + + + + , Fill + + + + , Scale + + + + , Traffic + + + + , Music + + + + , Scheduler + + + + , Inline Traffic + + + + REMARKS + + + + Len: + + + + PRE-IMPORT CARTS + + + + IMPORT + + + + + EditEventLine + + Edit Event Assignment + + + + Event: + + + + Select + + + + Start Time: + + + + End Time: + + + + &OK + + + + &Cancel + + + + Invalid Event + + + + The event end time cannot be earlier than the start time. + + + + No Such Event + + + + There is no such event. + + + + This event overlaps with an +already existing event. + + + + + EditGrid + + Edit Grid: + + + + Edit Clock + + + + &Close + + + + Clear Hour + + + + Change +&All + + + + Clear Clocks + + + + Are you sure you want to update ALL clocks in the grid? + + + + This operation cannot be undone! + + + + + EditNote + + Edit Log Note + + + + &OK + + + + &Cancel + + + + + EditPerms + + Service Associations + + + + Available Services + + + + Enabled Services + + + + &OK + + + + &Cancel + + + + + EditSchedRules + + &Edit + + + + &Import + + + + &OK + + + + &Cancel + + + + CODE + + + + MAX. IN A ROW + + + + MIN. WAIT + + + + DO NOT SCHEDULE AFTER + + + + OR AFTER + + + + DESCRIPTION + + + + Scheduler Codes: + + + + Rules Modified + + + + The rules have been modified. +Do you want to save? + + + + Scheduler Rules + + + + Artist Separation: + + + + Import Rules from Clock + + + + + EditTrack + + Edit Voice Track Marker + + + + &OK + + + + &Cancel + + + + + GenerateLog + + Generating Log... + + + + Cancel + + + + Service: + + + + Date: + + + + &Select + + + + &Create New Log + + + + Merge &Music + + + + Merge &Traffic + + + + Import Data + + + + Available + + + + Merged + + + + C&lose + + + + The log for + + + + already exists. Recreating it +will remove any merged Music or Traffic events. + +Recreate? + + + + Log Exists + + + + This will also delete the + + + + voice tracks associated with this log. +Continue? + + + + Tracks Exist + + + + No Errors + + + + No exceptions found. + + + + already contains merged music and/or traffic data. +Remerging it will remove this data. Remerge? + + + + Music Exists + + + + already contains merged traffic data. Remerging it +will remove this data. Remerge? + + + + Traffic Exists + + + + Generate Log - User: + + + + + ImportListView + + Insert Log Note + + + + Edit Log Note + + + + Insert Voice Track + + + + Edit Voice Track + + + + Set PLAY Transition + + + + Set SEGUE Transition + + + + Set STOP Transition + + + + Delete + + + + Marker + + + + [Log Note] + + + + Track + + + + [Voice Track] + + + + PLAY + + + + SEGUE + + + + STOP + + + + + ListClocks + + Filter: + + + + Name + + + + Code + + + + Color + + + + &Add + + + + &Edit + + + + &Delete + + + + &Rename + + + + C&lose + + + + C&lear + + + + &OK + + + + &Cancel + + + + ALL + + + + NONE + + + + Clock Exists + + + + An clock with that name already exists! + + + + Are you sure you want to +delete + + + + Delete Clock + + + + is in use in the following grid(s): + + + + Do you still want to delete it? + + + + Clock In Use + + + + Log Clocks - User: + + + + + ListEvents + + Filter: + + + + Name + + + + Properties + + + + Color + + + + &Add + + + + &Edit + + + + &Delete + + + + &Rename + + + + &OK + + + + &Ok + + + + &Cancel + + + + ALL + + + + NONE + + + + Event Exists + + + + An event with that name already exists! + + + + Are you sure you want to +delete + + + + Delete Event + + + + is in use in the following clocks: + + + + Do you still want to delete it? + + + + Event In Use + + + + Log Events - User: + + + + + ListGrids + + Log Grids + + + + Name + + + + Description + + + + &Edit + + + + C&lose + + + + + ListSvcs + + Rivendell Services + + + + SERVICE + + + + OLDEST REPORT + + + + &Generate +Reports + + + + &Purge +Data + + + + C&lose + + + + [none] + + + + + MainWidget + + Can't Connect + + + + RDLogManager + + + + Select an operation: + + + + Edit &Events + + + + Edit C&locks + + + + Edit G&rids + + + + &Generate Logs + + + + Manage &Reports + + + + &Close + + + + RDLogManager - User: + + + + RDLogEdit -- Database Skew + + + + This version of RDLogManager is incompatible with the version installed on the server. +See your system administrator for an update! + + + + + PickReportDates + + Select Report Dates + + + + &Report: + + + + &Start Date: + + + + &Select + + + + &End Date: + + + + &Generate +Report + + + + C&lose + + + + Invalid Date Range + + + + The end date cannot be earlier than the start date! + + + + This report type cannot span multiple dates! + + + + This report type cannot span multiple months! + + + + Report Complete + + + + Report generated in + + + + + RenameItem + + Rename + + + + &OK + + + + &Cancel + + + + Name Conflict + + + + That name already exists! + + + + + SvcRec + + Mo + + + + Tu + + + + We + + + + Th + + + + Fr + + + + Sa + + + + Su + + + + + SvcRecDialog + + Report Data + + + + &Purge +Data + + + + &Close + + + + Delete Report Data + + + + Are you sure you want to delete report data for + + + + + editSchedCodeRules + + &OK + + + + &Cancel + + + + Code: + + + + Max. in a row: + + + + Min. wait: + + + + Do not schedule after: + + + + Or after: + + + + Edit Rules for Code + + + + diff --git a/rdlogmanager/rdlogmanager_nb.ts b/rdlogmanager/rdlogmanager_nb.ts new file mode 100644 index 00000000..b6ae2944 --- /dev/null +++ b/rdlogmanager/rdlogmanager_nb.ts @@ -0,0 +1,1405 @@ + + + AddClock + + Add Log Clock + Legg til loggklokke + + + &New Clock Name: + &Namn på ny klokke: + + + &OK + &OK + + + &Cancel + &Avbryt + + + + AddEvent + + Add Log Event + Legg til logghending + + + &New Event Name: + &Namn på ny hending: + + + &OK + &OK + + + &Cancel + &Avbryt + + + + ClockListView + + Edit Event + Rediger hending + + + + EditClock + + Edit Clock: + Rediger klokke: + + + Code: + Kode: + + + Start + Start + + + End + Slutt + + + Event + Hending + + + Length + Lengd + + + Count + Tellign + + + &Add + Legg &til + + + &Edit + R&ediger + + + &Delete + &Slett + + + Scheduler +Rules + Planleggar- +reglar + + + &Save + &Lagra + + + Save &As + Lagra &som + + + &Services +List + Liste over +tene&ster + + + Colo&r + Fa&rge + + + &OK + &OK + + + &Cancel + &Avbryt + + + Are you sure you want to +delete + Er du sikker på at du vil +sletta + + + Delete Event + Slett hending + + + Clock Modified + Klokka er endra + + + The clock has been modified. +Do you want to save? + Klokka er endra. +Vil du lagra? + + + Missing Clock Code + Manglar klokkekode + + + You must specify a clock code! + Du må gje ein klokkekode! + + + Code Exists + Koden eksisterer + + + The clock code is already in use! + Klokkekoden er alt i bruk! + + + Clock Exists + Klokka eksisterer + + + Clock already exists! Overwrite? + Klokka finst frå før! Skriv over? + + + --- End of clock --- + --- Slutt på klokka --- + + + Invalid Code + Ugyldig kode + + + You must provide a clock code! + Du må gje ein klokkekode! + + + Duplicate Code + Dublettkode + + + That code is already in use! + Denne koden er alt i bruk! + + + Remarks + + + + + EditEvent + + Editing Event + Redigerer hending + + + Filter: + Filter: + + + Group: + Gruppe: + + + All + Alt + + + Audio Only + Berre lyd + + + Macros Only + Berre makroar + + + CART + KORG + + + GROUP + GRUPPE + + + LENGTH + LENGD + + + TITLE + TITTEL + + + ARTIST + ARTIST + + + START + START + + + END + SLUTT + + + TYPE + TYPE + + + ALL + ALT + + + PRE-POSITION LOG + LOGG FOR FØR-POSISJON + + + Cue to this event + Spol til denne hendinga + + + before scheduled start. (First cart will have a STOP transition.) + før den planlagde starten (Fyrste korga får ein STOPP-overgang.) + + + TIMED START + TIDLAGT START + + + Use hard start time + Bruk hard starttid + + + Make Post Point + Lag Etter-punkt + + + Action If Previous Event Still Playing + Handling viss førre hendinga spelar enno + + + Start immediately + Start med ein gong + + + Make next + Gjer til neste + + + Wait up to + Vent opp til + + + Play + Spel + + + Segue + Krysston + + + Stop + Stopp + + + Overlap + Overlapp + + + Transition if previous event ends before start time: + Overgang viss førre hendinga sluttar før starttida: + + + ENFORCING LENGTH + TVINGELENGD + + + Use AutoFill + Bruk Autofyll + + + Warn if fill is over or under + Åtvar viss fyllet er over eller under + + + by at least + med minst + + + Use Timescaling + Bruk tidsskalering + + + TRANSITION + OVERGANG + + + COUNT + TELLING + + + None + Ingen + + + From Traffic + Frå trafikk + + + From Music + Frå musikk + + + Select from: + Vel frå: + + + Title Separation + Titteloppdeling + + + Must have code + Må ha kode + + + Import carts scheduled + Importer korger planlagt + + + prior to the start of this event. + før starten av denne hendinga. + + + after the end of this event. + etter slutten på denne hendinga. + + + First cart has a + Fyrste korga har + + + Imported carts have a + Importerte korger har + + + transition. + ein overgang. + + + Import inline traffic with the + Importer innlinje-trafikk med + + + [none] + [ingen] + + + event. + hending. + + + POST-IMPORT CARTS + ETTER-IMPORT-KORGER + + + &Save + &Lagra + + + Save &As + Lagra &som + + + &Services +List + Liste over +tene&ster + + + C&olor + Far&ge + + + &OK + &OK + + + &Cancel + &Avbryt + + + RDLogManager + RDLogManager + + + Event already exists! +Do you want to overwrite it? + Hendinga finst frå før! +Vil du byta henne ut? + + + Edit Event + Rediger hending + + + Audio + Lyd + + + Macro + Makro + + + Cue + Sporing + + + SEGUE + KRYSSTON + + + STOP + STOPP + + + OVERLAP + OVERLAPP + + + PLAY + SPEL + + + , Timed(Start) + , Tidlagt(Start) + + + , Timed(MakeNext) + , Tidlagt(Gjer-neste) + + + Timed(Wait + Tidlagt (Vent + + + , Post + , Etter + + + , Fill + , Fyll + + + , Scale + , Skalering + + + , Traffic + , Trafikk + + + , Music + , Musikk + + + , Scheduler + , Planleggar + + + , Inline Traffic + , Innlinje-trafikk + + + REMARKS + + + + Len: + + + + PRE-IMPORT CARTS + + + + IMPORT + + + + + EditEventLine + + Edit Event Assignment + Rediger hendingstildeling + + + Event: + Hending: + + + Select + Vel + + + Start Time: + Starttid: + + + End Time: + Sluttid: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Event + Ugyldig hending + + + The event end time cannot be earlier than the start time. + Sluttida for hendinga kan ikkje vera før starttida. + + + No Such Event + Inga slik hending + + + There is no such event. + Det finst ikkje noko slik hending. + + + This event overlaps with an +already existing event. + Denne hendinga overlappar +ei anna hending som finst frå før. + + + + EditGrid + + Edit Grid: + Rediger gitter: + + + Edit Clock + Rediger klokke + + + &Close + &Lukk + + + Clear Hour + + + + Change +&All + + + + Clear Clocks + + + + Are you sure you want to update ALL clocks in the grid? + + + + This operation cannot be undone! + + + + + EditNote + + Edit Log Note + Rediger loggnote + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditPerms + + Service Associations + Tenestesameiningar + + + Available Services + Tilgjengelege tenester + + + Enabled Services + Påskrudde tenester + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditSchedRules + + &Edit + R&ediger + + + &Import + &Importer + + + &OK + &OK + + + &Cancel + &Avbryt + + + CODE + KODE + + + MAX. IN A ROW + MAKS PÅ EI RAD + + + MIN. WAIT + MINSTE VENTING + + + DO NOT SCHEDULE AFTER + IKKJE PLANLEGG ETTER + + + OR AFTER + ELLER ETTER + + + DESCRIPTION + SKILDRING + + + Scheduler Codes: + Planleggarkodar: + + + Rules Modified + Reglane er endra + + + The rules have been modified. +Do you want to save? + Reglane er endra. +Vil du lagra? + + + Scheduler Rules + + + + Artist Separation: + + + + Import Rules from Clock + + + + + EditTrack + + Edit Voice Track Marker + Rediger markør for røyst-spor + + + &OK + &OK + + + &Cancel + &Avbryt + + + + GenerateLog + + Generate Log + Lag logg + + + Generating Log... + Lagar logg... + + + Cancel + Avbryt + + + Service: + Tenest: + + + Date: + Dato: + + + &Select + &Vel + + + &Create New Log + Lag &Ny logg + + + Merge &Music + Flett &Musikk + + + Merge &Traffic + Flett &Trafikk + + + Import Data + Importer data + + + Available + Tilgjengeleg + + + Merged + Fletta + + + C&lose + &Lukk + + + The log for + Loggen for + + + already exists. Recreating it +will remove any merged Music or Traffic events. + +Recreate? + finst alt. Om du lagar han på nytt, +vil det fjerna alle innfletta Musikk- eller Trafikk-hendingar. + +Lag på nytt? + + + Log Exists + Loggen eksisterer + + + This will also delete the + Dette slettar òg + + + voice tracks associated with this log. +Continue? + røystspor som er kopla til denne loggen. +Hald fram? + + + Tracks Exist + Sporet eksisterer + + + No Errors + Ingen feil + + + No exceptions found. + Fann ingen unntak. + + + already contains merged music and/or traffic data. +Remerging it will remove this data. Remerge? + inneheld alt fletta musikk- og/eller trafikkdata. +Flettar du på nytt, vil du fjerna desse dataa. Flett på nytt? + + + Music Exists + Musikken eksisterer + + + already contains merged traffic data. Remerging it +will remove this data. Remerge? + inneheld alt fletta trafikkdata. +Flettar du på nytt, vil du fjerna desse dataa. Flett på nytt? + + + Traffic Exists + Trafikken eksisterer + + + Generate Log - User: + + + + + ImportListView + + Insert Log Note + Set inn loggnote + + + Edit Log Note + Rediger loggnote + + + Insert Voice Track + Set inn røystspor + + + Edit Voice Track + Rediger røystspor + + + Set PLAY Transition + Set SPEL-overgang + + + Set SEGUE Transition + Set KRYSSTONING-overgang + + + Set STOP Transition + Set STOPP-overgang + + + Set OVERLAP Transition + Set OVERLAPP-overgang + + + Delete + Slett + + + Marker + Markør + + + [Log Note] + [Loggnote] + + + Track + Spor + + + [Voice Track] + [Røystspor] + + + PLAY + SPEL + + + SEGUE + KRYSSTON + + + STOP + STOPP + + + OVERLAP + OVERLAPP + + + + ListClocks + + Log Clocks + Loggklokker + + + Filter: + Filter: + + + Name + Namn + + + Code + Kode + + + Color + Farge + + + &Add + Legg &til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Rename + &Døyp om + + + C&lose + &Lukk + + + C&lear + &Reinsk + + + &OK + &OK + + + &Cancel + &Avbryt + + + ALL + ALT + + + NONE + INGEN + + + Clock Exists + Klokka eksisterer + + + An clock with that name already exists! + Det finst alt ei klokke med dette namnet! + + + Are you sure you want to +delete + Er du sikker på at du vil +sletta + + + Delete Clock + Slett klokka + + + is in use in the following grid(s): + er i bruk av desse gitra: + + + Do you still want to delete it? + Vil du framleis sletta? + + + Clock In Use + Klokka er i bruk + + + Log Clocks - User: + + + + + ListEvents + + Log Events + Logghendingar + + + Filter: + Filter: + + + Name + Namn + + + Properties + Eigenskapar + + + Color + Farge + + + &Add + Legg &til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Rename + &Døyp om + + + &OK + &OK + + + &Ok + &Ok + + + &Cancel + &Avbryt + + + ALL + ALT + + + NONE + INGEN + + + Event Exists + Hendinga eksisterer + + + An event with that name already exists! + Det finst alt ei hending med det namnet! + + + Are you sure you want to +delete + Er du sikker på at du vil +sletta + + + Delete Event + Slett hendinga + + + is in use in the following clocks: + er i bruk av desse klokkene: + + + Do you still want to delete it? + Vil du framleis sletta? + + + Event In Use + Hendinga er i bruk + + + Log Events - User: + + + + + ListGrids + + Log Grids + Loggitter + + + Name + Namn + + + Description + Skildring + + + &Edit + R&ediger + + + C&lose + &Lukk + + + + ListSvcs + + Rivendell Services + Rivendell-tenester + + + SERVICE + TENEST + + + OLDEST REPORT + ELDSTE RAPPORT + + + &Generate +Reports + La&g +rapportar + + + &Purge +Data + &Tøm +data + + + C&lose + &Lukk + + + [none] + [ingen] + + + + MainWidget + + Can't Connect + Greier ikkje kopla til + + + RDLogManager + RDLogManager + + + Select an operation: + Vel ei handling: + + + Edit &Events + Redig&er hendingar + + + Edit C&locks + Rediger &klokker + + + Edit G&rids + Rediger &gitter + + + &Generate Logs + Lag lo&ggar + + + Manage &Reports + Handter &Rapportar + + + &Close + &Lukk + + + RDLogManager - User: + + + + RDLogEdit -- Database Skew + + + + This version of RDLogManager is incompatible with the version installed on the server. +See your system administrator for an update! + + + + + PickReportDates + + Select Report Dates + Vel rapportdatoar + + + &Report: + &Rapport: + + + &Start Date: + &Startdato: + + + &Select + &Vel + + + &End Date: + Slu&ttdato: + + + &Generate +Report + La&g +rapport + + + C&lose + &Lukk + + + Invalid Date Range + Ugyldige datoar + + + The end date cannot be earlier than the start date! + Sluttdatoen kan ikkje vera før startdatoen! + + + This report type cannot span multiple dates! + Denne rapporttypen kan ikkje gå over fleire datoar! + + + This report type cannot span multiple months! + Denne rapporttypen kan ikkje gå over fleire månader! + + + Report Complete + Rapporten ferdig + + + Report complete! + Rapporten er ferdig! + + + Report generated in + + + + + RenameItem + + Rename + Døyp om + + + &OK + &OK + + + &Cancel + &Avbryt + + + Name Conflict + Konflikt om namn + + + That name already exists! + Det namnet finst frå før! + + + + SvcRec + + Mo + + + + Tu + Ty + + + We + On + + + Th + To + + + Fr + Fr + + + Sa + La + + + Su + Su + + + + SvcRecDialog + + Report Data + Rapportdata + + + &Purge +Data + &Tøm +data + + + &Close + &Lukk + + + Delete Report Data + Slett rapportdata + + + Are you sure you want to delete report data for + Er du sikker på at du vil sletta rapportdata for + + + + editSchedCodeRules + + &OK + &OK + + + &Cancel + &Avbryt + + + Code: + Kode: + + + Max. in a row: + Maks på ei rad: + + + Min. wait: + Min. venting: + + + Do not schedule after: + Ikkje planlegg etter: + + + Or after: + Eller etter: + + + Edit Rules for Code + + + + diff --git a/rdlogmanager/rdlogmanager_nn.ts b/rdlogmanager/rdlogmanager_nn.ts new file mode 100644 index 00000000..b6ae2944 --- /dev/null +++ b/rdlogmanager/rdlogmanager_nn.ts @@ -0,0 +1,1405 @@ + + + AddClock + + Add Log Clock + Legg til loggklokke + + + &New Clock Name: + &Namn på ny klokke: + + + &OK + &OK + + + &Cancel + &Avbryt + + + + AddEvent + + Add Log Event + Legg til logghending + + + &New Event Name: + &Namn på ny hending: + + + &OK + &OK + + + &Cancel + &Avbryt + + + + ClockListView + + Edit Event + Rediger hending + + + + EditClock + + Edit Clock: + Rediger klokke: + + + Code: + Kode: + + + Start + Start + + + End + Slutt + + + Event + Hending + + + Length + Lengd + + + Count + Tellign + + + &Add + Legg &til + + + &Edit + R&ediger + + + &Delete + &Slett + + + Scheduler +Rules + Planleggar- +reglar + + + &Save + &Lagra + + + Save &As + Lagra &som + + + &Services +List + Liste over +tene&ster + + + Colo&r + Fa&rge + + + &OK + &OK + + + &Cancel + &Avbryt + + + Are you sure you want to +delete + Er du sikker på at du vil +sletta + + + Delete Event + Slett hending + + + Clock Modified + Klokka er endra + + + The clock has been modified. +Do you want to save? + Klokka er endra. +Vil du lagra? + + + Missing Clock Code + Manglar klokkekode + + + You must specify a clock code! + Du må gje ein klokkekode! + + + Code Exists + Koden eksisterer + + + The clock code is already in use! + Klokkekoden er alt i bruk! + + + Clock Exists + Klokka eksisterer + + + Clock already exists! Overwrite? + Klokka finst frå før! Skriv over? + + + --- End of clock --- + --- Slutt på klokka --- + + + Invalid Code + Ugyldig kode + + + You must provide a clock code! + Du må gje ein klokkekode! + + + Duplicate Code + Dublettkode + + + That code is already in use! + Denne koden er alt i bruk! + + + Remarks + + + + + EditEvent + + Editing Event + Redigerer hending + + + Filter: + Filter: + + + Group: + Gruppe: + + + All + Alt + + + Audio Only + Berre lyd + + + Macros Only + Berre makroar + + + CART + KORG + + + GROUP + GRUPPE + + + LENGTH + LENGD + + + TITLE + TITTEL + + + ARTIST + ARTIST + + + START + START + + + END + SLUTT + + + TYPE + TYPE + + + ALL + ALT + + + PRE-POSITION LOG + LOGG FOR FØR-POSISJON + + + Cue to this event + Spol til denne hendinga + + + before scheduled start. (First cart will have a STOP transition.) + før den planlagde starten (Fyrste korga får ein STOPP-overgang.) + + + TIMED START + TIDLAGT START + + + Use hard start time + Bruk hard starttid + + + Make Post Point + Lag Etter-punkt + + + Action If Previous Event Still Playing + Handling viss førre hendinga spelar enno + + + Start immediately + Start med ein gong + + + Make next + Gjer til neste + + + Wait up to + Vent opp til + + + Play + Spel + + + Segue + Krysston + + + Stop + Stopp + + + Overlap + Overlapp + + + Transition if previous event ends before start time: + Overgang viss førre hendinga sluttar før starttida: + + + ENFORCING LENGTH + TVINGELENGD + + + Use AutoFill + Bruk Autofyll + + + Warn if fill is over or under + Åtvar viss fyllet er over eller under + + + by at least + med minst + + + Use Timescaling + Bruk tidsskalering + + + TRANSITION + OVERGANG + + + COUNT + TELLING + + + None + Ingen + + + From Traffic + Frå trafikk + + + From Music + Frå musikk + + + Select from: + Vel frå: + + + Title Separation + Titteloppdeling + + + Must have code + Må ha kode + + + Import carts scheduled + Importer korger planlagt + + + prior to the start of this event. + før starten av denne hendinga. + + + after the end of this event. + etter slutten på denne hendinga. + + + First cart has a + Fyrste korga har + + + Imported carts have a + Importerte korger har + + + transition. + ein overgang. + + + Import inline traffic with the + Importer innlinje-trafikk med + + + [none] + [ingen] + + + event. + hending. + + + POST-IMPORT CARTS + ETTER-IMPORT-KORGER + + + &Save + &Lagra + + + Save &As + Lagra &som + + + &Services +List + Liste over +tene&ster + + + C&olor + Far&ge + + + &OK + &OK + + + &Cancel + &Avbryt + + + RDLogManager + RDLogManager + + + Event already exists! +Do you want to overwrite it? + Hendinga finst frå før! +Vil du byta henne ut? + + + Edit Event + Rediger hending + + + Audio + Lyd + + + Macro + Makro + + + Cue + Sporing + + + SEGUE + KRYSSTON + + + STOP + STOPP + + + OVERLAP + OVERLAPP + + + PLAY + SPEL + + + , Timed(Start) + , Tidlagt(Start) + + + , Timed(MakeNext) + , Tidlagt(Gjer-neste) + + + Timed(Wait + Tidlagt (Vent + + + , Post + , Etter + + + , Fill + , Fyll + + + , Scale + , Skalering + + + , Traffic + , Trafikk + + + , Music + , Musikk + + + , Scheduler + , Planleggar + + + , Inline Traffic + , Innlinje-trafikk + + + REMARKS + + + + Len: + + + + PRE-IMPORT CARTS + + + + IMPORT + + + + + EditEventLine + + Edit Event Assignment + Rediger hendingstildeling + + + Event: + Hending: + + + Select + Vel + + + Start Time: + Starttid: + + + End Time: + Sluttid: + + + &OK + &OK + + + &Cancel + &Avbryt + + + Invalid Event + Ugyldig hending + + + The event end time cannot be earlier than the start time. + Sluttida for hendinga kan ikkje vera før starttida. + + + No Such Event + Inga slik hending + + + There is no such event. + Det finst ikkje noko slik hending. + + + This event overlaps with an +already existing event. + Denne hendinga overlappar +ei anna hending som finst frå før. + + + + EditGrid + + Edit Grid: + Rediger gitter: + + + Edit Clock + Rediger klokke + + + &Close + &Lukk + + + Clear Hour + + + + Change +&All + + + + Clear Clocks + + + + Are you sure you want to update ALL clocks in the grid? + + + + This operation cannot be undone! + + + + + EditNote + + Edit Log Note + Rediger loggnote + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditPerms + + Service Associations + Tenestesameiningar + + + Available Services + Tilgjengelege tenester + + + Enabled Services + Påskrudde tenester + + + &OK + &OK + + + &Cancel + &Avbryt + + + + EditSchedRules + + &Edit + R&ediger + + + &Import + &Importer + + + &OK + &OK + + + &Cancel + &Avbryt + + + CODE + KODE + + + MAX. IN A ROW + MAKS PÅ EI RAD + + + MIN. WAIT + MINSTE VENTING + + + DO NOT SCHEDULE AFTER + IKKJE PLANLEGG ETTER + + + OR AFTER + ELLER ETTER + + + DESCRIPTION + SKILDRING + + + Scheduler Codes: + Planleggarkodar: + + + Rules Modified + Reglane er endra + + + The rules have been modified. +Do you want to save? + Reglane er endra. +Vil du lagra? + + + Scheduler Rules + + + + Artist Separation: + + + + Import Rules from Clock + + + + + EditTrack + + Edit Voice Track Marker + Rediger markør for røyst-spor + + + &OK + &OK + + + &Cancel + &Avbryt + + + + GenerateLog + + Generate Log + Lag logg + + + Generating Log... + Lagar logg... + + + Cancel + Avbryt + + + Service: + Tenest: + + + Date: + Dato: + + + &Select + &Vel + + + &Create New Log + Lag &Ny logg + + + Merge &Music + Flett &Musikk + + + Merge &Traffic + Flett &Trafikk + + + Import Data + Importer data + + + Available + Tilgjengeleg + + + Merged + Fletta + + + C&lose + &Lukk + + + The log for + Loggen for + + + already exists. Recreating it +will remove any merged Music or Traffic events. + +Recreate? + finst alt. Om du lagar han på nytt, +vil det fjerna alle innfletta Musikk- eller Trafikk-hendingar. + +Lag på nytt? + + + Log Exists + Loggen eksisterer + + + This will also delete the + Dette slettar òg + + + voice tracks associated with this log. +Continue? + røystspor som er kopla til denne loggen. +Hald fram? + + + Tracks Exist + Sporet eksisterer + + + No Errors + Ingen feil + + + No exceptions found. + Fann ingen unntak. + + + already contains merged music and/or traffic data. +Remerging it will remove this data. Remerge? + inneheld alt fletta musikk- og/eller trafikkdata. +Flettar du på nytt, vil du fjerna desse dataa. Flett på nytt? + + + Music Exists + Musikken eksisterer + + + already contains merged traffic data. Remerging it +will remove this data. Remerge? + inneheld alt fletta trafikkdata. +Flettar du på nytt, vil du fjerna desse dataa. Flett på nytt? + + + Traffic Exists + Trafikken eksisterer + + + Generate Log - User: + + + + + ImportListView + + Insert Log Note + Set inn loggnote + + + Edit Log Note + Rediger loggnote + + + Insert Voice Track + Set inn røystspor + + + Edit Voice Track + Rediger røystspor + + + Set PLAY Transition + Set SPEL-overgang + + + Set SEGUE Transition + Set KRYSSTONING-overgang + + + Set STOP Transition + Set STOPP-overgang + + + Set OVERLAP Transition + Set OVERLAPP-overgang + + + Delete + Slett + + + Marker + Markør + + + [Log Note] + [Loggnote] + + + Track + Spor + + + [Voice Track] + [Røystspor] + + + PLAY + SPEL + + + SEGUE + KRYSSTON + + + STOP + STOPP + + + OVERLAP + OVERLAPP + + + + ListClocks + + Log Clocks + Loggklokker + + + Filter: + Filter: + + + Name + Namn + + + Code + Kode + + + Color + Farge + + + &Add + Legg &til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Rename + &Døyp om + + + C&lose + &Lukk + + + C&lear + &Reinsk + + + &OK + &OK + + + &Cancel + &Avbryt + + + ALL + ALT + + + NONE + INGEN + + + Clock Exists + Klokka eksisterer + + + An clock with that name already exists! + Det finst alt ei klokke med dette namnet! + + + Are you sure you want to +delete + Er du sikker på at du vil +sletta + + + Delete Clock + Slett klokka + + + is in use in the following grid(s): + er i bruk av desse gitra: + + + Do you still want to delete it? + Vil du framleis sletta? + + + Clock In Use + Klokka er i bruk + + + Log Clocks - User: + + + + + ListEvents + + Log Events + Logghendingar + + + Filter: + Filter: + + + Name + Namn + + + Properties + Eigenskapar + + + Color + Farge + + + &Add + Legg &til + + + &Edit + R&ediger + + + &Delete + &Slett + + + &Rename + &Døyp om + + + &OK + &OK + + + &Ok + &Ok + + + &Cancel + &Avbryt + + + ALL + ALT + + + NONE + INGEN + + + Event Exists + Hendinga eksisterer + + + An event with that name already exists! + Det finst alt ei hending med det namnet! + + + Are you sure you want to +delete + Er du sikker på at du vil +sletta + + + Delete Event + Slett hendinga + + + is in use in the following clocks: + er i bruk av desse klokkene: + + + Do you still want to delete it? + Vil du framleis sletta? + + + Event In Use + Hendinga er i bruk + + + Log Events - User: + + + + + ListGrids + + Log Grids + Loggitter + + + Name + Namn + + + Description + Skildring + + + &Edit + R&ediger + + + C&lose + &Lukk + + + + ListSvcs + + Rivendell Services + Rivendell-tenester + + + SERVICE + TENEST + + + OLDEST REPORT + ELDSTE RAPPORT + + + &Generate +Reports + La&g +rapportar + + + &Purge +Data + &Tøm +data + + + C&lose + &Lukk + + + [none] + [ingen] + + + + MainWidget + + Can't Connect + Greier ikkje kopla til + + + RDLogManager + RDLogManager + + + Select an operation: + Vel ei handling: + + + Edit &Events + Redig&er hendingar + + + Edit C&locks + Rediger &klokker + + + Edit G&rids + Rediger &gitter + + + &Generate Logs + Lag lo&ggar + + + Manage &Reports + Handter &Rapportar + + + &Close + &Lukk + + + RDLogManager - User: + + + + RDLogEdit -- Database Skew + + + + This version of RDLogManager is incompatible with the version installed on the server. +See your system administrator for an update! + + + + + PickReportDates + + Select Report Dates + Vel rapportdatoar + + + &Report: + &Rapport: + + + &Start Date: + &Startdato: + + + &Select + &Vel + + + &End Date: + Slu&ttdato: + + + &Generate +Report + La&g +rapport + + + C&lose + &Lukk + + + Invalid Date Range + Ugyldige datoar + + + The end date cannot be earlier than the start date! + Sluttdatoen kan ikkje vera før startdatoen! + + + This report type cannot span multiple dates! + Denne rapporttypen kan ikkje gå over fleire datoar! + + + This report type cannot span multiple months! + Denne rapporttypen kan ikkje gå over fleire månader! + + + Report Complete + Rapporten ferdig + + + Report complete! + Rapporten er ferdig! + + + Report generated in + + + + + RenameItem + + Rename + Døyp om + + + &OK + &OK + + + &Cancel + &Avbryt + + + Name Conflict + Konflikt om namn + + + That name already exists! + Det namnet finst frå før! + + + + SvcRec + + Mo + + + + Tu + Ty + + + We + On + + + Th + To + + + Fr + Fr + + + Sa + La + + + Su + Su + + + + SvcRecDialog + + Report Data + Rapportdata + + + &Purge +Data + &Tøm +data + + + &Close + &Lukk + + + Delete Report Data + Slett rapportdata + + + Are you sure you want to delete report data for + Er du sikker på at du vil sletta rapportdata for + + + + editSchedCodeRules + + &OK + &OK + + + &Cancel + &Avbryt + + + Code: + Kode: + + + Max. in a row: + Maks på ei rad: + + + Min. wait: + Min. venting: + + + Do not schedule after: + Ikkje planlegg etter: + + + Or after: + Eller etter: + + + Edit Rules for Code + + + + diff --git a/rdlogmanager/rdlogmanager_pt_BR.ts b/rdlogmanager/rdlogmanager_pt_BR.ts new file mode 100644 index 00000000..b86fc8af --- /dev/null +++ b/rdlogmanager/rdlogmanager_pt_BR.ts @@ -0,0 +1,1378 @@ + + + AddClock + + Add Log Clock + Adicionar Relógio + + + &New Clock Name: + &Nome do Novo Relógio: + + + &OK + &OK + + + &Cancel + &Cancelar + + + + AddEvent + + Add Log Event + Adicionar Evento + + + &New Event Name: + &Nome do Novo Evento + + + &OK + + + + &Cancel + &Cancelar + + + + ClockListView + + Edit Event + Editar Evento + + + + EditClock + + Edit Clock: + Editar Relogio: + + + Code: + Código: + + + Start + Início + + + End + Fim + + + Event + Evento + + + Length + Duração + + + Count + Contador + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + Remarks + Observações + + + Scheduler +Rules + Regras do +Agendador + + + &Save + &Salvar + + + Save &As + &Salvar +Como + + + &Services +List + Lista de +&Serviços + + + Colo&r + &Cor + + + &OK + &OK + + + &Cancel + &Cancelar + + + Are you sure you want to +delete + Tem certeza que quer +deletar + + + Delete Event + Deletar Evento + + + Clock Modified + Relógio Modififcado + + + The clock has been modified. +Do you want to save? + O Relógio foi Modificado. +Você quer salvar? + + + Missing Clock Code + Está faltando o Código do Relógio + + + You must specify a clock code! + Você deve especificar um código para o Relógio! + + + Code Exists + Código existente: + + + The clock code is already in use! + O Código do Relógio já está em uso! + + + Clock Exists + Relógio Existente + + + Clock already exists! Overwrite? + Relógio existente! Sobreescrever + + + --- End of clock --- + -- Fim do Relógio -- + + + Invalid Code + Código Inválido + + + You must provide a clock code! + Você deve dar um código ao Relógio! + + + Duplicate Code + Código Duplicado + + + That code is already in use! + Este Código já está em uso! + + + + EditEvent + + Editing Event + Editando Evento + + + Filter: + Filtro: + + + Group: + Grupo: + + + All + Todos + + + Audio Only + Somente Áudio + + + Macros Only + Somente Macros + + + CART + CARTÃO + + + GROUP + GRUPO + + + LENGTH + DURAÇÃO + + + TITLE + TÍTULO + + + ARTIST + ARTISTA + + + START + INÍCIO + + + END + TÉRMINO + + + TYPE + TIPO + + + REMARKS + OBSERVAÇÕES + + + ALL + TODOS + + + PRE-POSITION LOG + PRE-POSCIONAR LISTA + + + Cue to this event + Marcar este Evento + + + before scheduled start. (First cart will have a STOP transition.) + antes do agendado começar. (Primeiro Cartão terá uma transição PARE) + + + TIMED START + HORA CERTA + + + Use hard start time + Usar Hora Certa + + + Make Post Point + Fazer Marcação + + + Action If Previous Event Still Playing + Ação se anterior estiver sendo executada + + + Start immediately + Iniciar Imediatamente + + + Make next + Ser a Próxima + + + Wait up to + Esperar até + + + Play + Simples + + + Segue + Sobre + + + Stop + Pare + + + Transition if previous event ends before start time: + Transição se evento anterior acabar antes do horário de início: + + + ENFORCING LENGTH + FORÇANDO DURAÇÃO + + + Use AutoFill + Preencher + + + Warn if fill is over or under + Avisar: Alongou ou Encurtou + + + by at least + Pelo menos + + + Use Timescaling + Usar Escala de Tempo + + + Len: + Dur: + + + TRANSITION + TRANSIÇÃO + + + COUNT + CONTADOR + + + None + Nenhum + + + From Traffic + Do Tráfego + + + From Music + De Músicas + + + Select from: + Selecionar de: + + + Title Separation + Separação título + + + Must have code + Deve ter código + + + Import carts scheduled + Importar Cartões Agendados + + + prior to the start of this event. + Antes do Início deste Evento. + + + after the end of this event. + Após o fim deste Evento. + + + First cart has a + Primeiro Cartão tem + + + Imported carts have a + Cartões importados têm + + + transition. + transição. + + + Import inline traffic with the + Importar Tráfego interno com + + + [none] + [nenhum] + + + event. + evento. + + + POST-IMPORT CARTS + CARTÕES PÓS-IMPORTAÇÃO + + + &Save + &Salvar + + + Save &As + &Salvar Como + + + &Services +List + &Lista de +Serviços + + + C&olor + &Cor + + + &OK + &OK + + + &Cancel + &Cancelar + + + RDLogManager + RDControle + + + Event already exists! +Do you want to overwrite it? + Evento já Existe! +Você quer sobreescrêve-lo? + + + Edit Event + Editar Evento + + + Audio + Áudio + + + Macro + Macro + + + Cue + Marca + + + SEGUE + SOBRE + + + STOP + PARE + + + PLAY + SIMPLES + + + , Timed(Start) + , Hora Certa(Início) + + + , Timed(MakeNext) + , Hora Certa(Ser Próximo) + + + Timed(Wait + Hora Certa(Esperar) + + + , Post + , Pós + + + , Fill + , Preencher + + + , Scale + , Escala + + + , Traffic + , Tráfego + + + , Music + , Música + + + , Scheduler + , Agendador + + + , Inline Traffic + , Tráfego Interno + + + PRE-IMPORT CARTS + + + + IMPORT + + + + + EditEventLine + + Edit Event Assignment + Editar Configuração de Evento + + + Event: + Evento: + + + Select + Selecionar + + + Start Time: + Início: + + + End Time: + Término: + + + &OK + &OK + + + &Cancel + &Cancelar + + + Invalid Event + Evento Inválido + + + The event end time cannot be earlier than the start time. + A hora de término do Evento não pode ser anterior à hora de início + + + No Such Event + Este Evento não Existe + + + There is no such event. + Este Evento não Existe + + + This event overlaps with an +already existing event. + Este Evento atropela um outro +evento existente. + + + + EditGrid + + Edit Grid: + Editar Grade: + + + Edit Clock + Editar Relógio + + + Clear Hour + Limpar Hora + + + &Close + &Fechar + + + Change +&All + + + + Clear Clocks + + + + Are you sure you want to update ALL clocks in the grid? + + + + This operation cannot be undone! + + + + + EditNote + + Edit Log Note + Editar nota de Lista + + + &OK + &OK + + + &Cancel + &Cancelar + + + + EditPerms + + Service Associations + Associacoes de Servicos + + + Available Services + Serviços Disponíveis + + + Enabled Services + Serviços Habilitados + + + &OK + &OK + + + &Cancel + &Cancelar + + + + EditSchedRules + + &Edit + &Editar + + + &Import + &Importar + + + &OK + &OK + + + &Cancel + &Cancelar + + + CODE + CÓDIGO + + + MAX. IN A ROW + MAX NA SEQUÊNCIA + + + MIN. WAIT + MIN. ESPERA + + + DO NOT SCHEDULE AFTER + NÃO AGENDE DEPOIS DE + + + OR AFTER + OU APÓS + + + DESCRIPTION + DESCRIÇÃO + + + Scheduler Codes: + Códigos do Agendador: + + + Rules Modified + Regras Modificadas + + + The rules have been modified. +Do you want to save? + As Regras froam modificadas. +Você quer salvar? + + + Scheduler Rules + + + + Artist Separation: + + + + Import Rules from Clock + + + + + EditTrack + + Edit Voice Track Marker + Editar marcadores de Faixa de Voz + + + &OK + &OK + + + &Cancel + &Cancelar + + + + GenerateLog + + Generate Log - User: + Gerar Lista - Usuário: + + + Generating Log... + Gerando Lista... + + + Cancel + Cancelar + + + Service: + Serviço + + + Date: + Data: + + + &Select + &Sel + + + &Create New Log + &Criar Nova Lista + + + Merge &Music + Agregar &Música + + + Merge &Traffic + Agregar &Tráfego + + + Import Data + Importar Dados + + + Available + Disponível + + + Merged + Agregados + + + C&lose + &Fechar + + + The log for + A Lista para + + + already exists. Recreating it +will remove any merged Music or Traffic events. + +Recreate? + já Existe. Recriando-a +removerá todos os Eventos de Tráfego e Música. + +Recriar? + + + Log Exists + Lista Existe + + + This will also delete the + Esta ação também deletará + + + voice tracks associated with this log. +Continue? + Faixas de voz associadas a esta lista. +Continue + + + Tracks Exist + Faixas Existentes + + + No Errors + Sem Erros + + + No exceptions found. + Exceções não encontradas. Parabéns. + + + already contains merged music and/or traffic data. +Remerging it will remove this data. Remerge? + já contém dados de músicas e/ou tráfego agregados. +Re-agregar removerá estes dados. Re-agregar? + + + Music Exists + Música Existente + + + already contains merged traffic data. Remerging it +will remove this data. Remerge? + já contém dados de tráfego agregados. +Re-agregar removerá estes dados. Re-agregar? + + + Traffic Exists + Tráfego Existente + + + + ImportListView + + Insert Log Note + Inserir nota de Lista + + + Edit Log Note + Editar nota de Lista + + + Insert Voice Track + Inserir Faixa de Voz + + + Edit Voice Track + Editar Faixa de Voz + + + Set PLAY Transition + Setar transição SIMPLES + + + Set SEGUE Transition + Setar transição SOBRE + + + Set STOP Transition + Setar transição PARE + + + Delete + Deletar + + + Marker + Marcador + + + [Log Note] + [Nota de Lista] + + + Track + Faixa + + + [Voice Track] + [Faixa de Voz] + + + PLAY + SIMPLES + + + SEGUE + SOBRE + + + STOP + PARE + + + + ListClocks + + Log Clocks - User: + Relógios - Usuário: + + + Filter: + Filtro: + + + Name + Nome: + + + Code + Código + + + Color + Cor + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &Rename + &Renomear + + + C&lose + &Fechar + + + C&lear + &Limpar + + + &OK + &OK + + + &Cancel + &Cancelar + + + ALL + TODOS + + + NONE + NENHUM + + + Clock Exists + Relógio Existente + + + An clock with that name already exists! + Um Relógio com este nome já existe! + + + Are you sure you want to +delete + Tem certeza que quer +deletar + + + Delete Clock + Deletar Relógio + + + is in use in the following grid(s): + está em uso nas seguintes grade(s): + + + Do you still want to delete it? + Tem certeza que quer deletá-lo? + + + Clock In Use + Relógio em Uso + + + + ListEvents + + Log Events - User: + Eventos - Usuário: + + + Filter: + Filtro: + + + Name + Nome + + + Properties + Propriedades + + + Color + Cor + + + &Add + &Adicionar + + + &Edit + &Editar + + + &Delete + &Deletar + + + &Rename + &Renomear + + + &OK + &OK + + + &Ok + &OK + + + &Cancel + &Cancelar + + + ALL + TODOS + + + NONE + NENHUM + + + Event Exists + Evento Existente + + + An event with that name already exists! + Um Evento com este nome já existe! + + + Are you sure you want to +delete + Tem certeza que quer +deletar + + + Delete Event + Deletar Evento + + + is in use in the following clocks: + está em uso nas seguintes relógio(s): + + + Do you still want to delete it? + Você ainda quer deletá-lo? + + + Event In Use + Evento em Uso + + + + ListGrids + + Log Grids + Grades + + + Name + Nome + + + Description + Descrição + + + &Edit + &Editar + + + C&lose + &Fechar + + + + ListSvcs + + Rivendell Services + Serviços do Rivendell + + + SERVICE + SERVIÇO + + + OLDEST REPORT + RELATÓRIO MAIS VELHO + + + &Generate +Reports + &Gerar +Relatórios + + + &Purge +Data + &Remover +Dados + + + C&lose + &Fechar + + + [none] + [nenhum] + + + + MainWidget + + RDLogManager + RDControle + + + Can't Connect + Não foi possível conectar + + + Select an operation: + Selecionar uma operação: + + + Edit &Events + Editar &Eventos + + + Edit C&locks + Editar &Relógios + + + Edit G&rids + Editar &Grades + + + &Generate Logs + &Gerar Listas + + + Manage &Reports + Gerenciar &Relatórios + + + &Close + &Fechar + + + RDLogManager - User: + RDControle - Usuario: + + + RDLogEdit -- Database Skew + + + + This version of RDLogManager is incompatible with the version installed on the server. +See your system administrator for an update! + + + + + PickReportDates + + Select Report Dates + Selecionar datas de Relatório + + + &Report: + &Relatório + + + &Start Date: + & Início: + + + &Select + &Sel + + + &End Date: + &Término: + + + &Generate +Report + &Gerar +Relatório + + + C&lose + &Fechar + + + Invalid Date Range + Intervalo de Datas Inválido + + + The end date cannot be earlier than the start date! + O Término não pode ser anterior à data de início! + + + This report type cannot span multiple dates! + Este tipo de relatório não pode atravessar múltiplas datas! + + + This report type cannot span multiple months! + Este tipo de relatório não pode atravessar múltiplos meses! + + + Report Complete + Relatório Completo + + + Report complete! + Relatório Completo! + + + Report generated in + + + + + RenameItem + + Rename + Renomear + + + &OK + &OK + + + &Cancel + &Cancelar + + + Name Conflict + Conflito de Nome + + + That name already exists! + Este nome nome já existe! + + + + SvcRec + + Mo + Seg + + + Tu + Ter + + + We + Qua + + + Th + Qui + + + Fr + Sex + + + Sa + Sab + + + Su + Dom + + + + SvcRecDialog + + Report Data + Dados de Relatório + + + &Purge +Data + &Remover +Dados + + + &Close + &Fechar + + + Delete Report Data + Deletar dados de Relatório + + + Are you sure you want to delete report data for + Tem certeza que quer deletar dados de relatório para + + + + editSchedCodeRules + + &OK + &OK + + + &Cancel + &Cancelar + + + Code: + Código: + + + Max. in a row: + Max. na Sequência: + + + Min. wait: + Min. Espera: + + + Do not schedule after: + Não agende depois de: + + + Or after: + Ou depois de: + + + Edit Rules for Code + + + + diff --git a/rdlogmanager/rename_item.cpp b/rdlogmanager/rename_item.cpp new file mode 100644 index 00000000..c06b607d --- /dev/null +++ b/rdlogmanager/rename_item.cpp @@ -0,0 +1,158 @@ +// rename_item.cpp +// +// Edit a Rivendell LogManager Note +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rename_item.cpp,v 1.8 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +RenameItem::RenameItem(QString *text,QString table, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + edit_text=text; + edit_tablename=table; + + setCaption(tr("Rename")); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont bold_font=QFont("Helvetica",12,QFont::Bold); + bold_font.setPixelSize(12); + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Create Validators + // + RDTextValidator *validator=new RDTextValidator(); + validator->addBannedChar('('); + validator->addBannedChar(')'); + validator->addBannedChar('!'); + validator->addBannedChar('@'); + validator->addBannedChar('#'); + validator->addBannedChar('$'); + validator->addBannedChar('%'); + validator->addBannedChar('^'); + validator->addBannedChar('&'); + validator->addBannedChar('*'); + validator->addBannedChar('{'); + validator->addBannedChar('}'); + validator->addBannedChar('['); + validator->addBannedChar(']'); + validator->addBannedChar(':'); + validator->addBannedChar(';'); + validator->addBannedChar(34); + validator->addBannedChar('<'); + validator->addBannedChar('>'); + validator->addBannedChar('.'); + validator->addBannedChar(','); + validator->addBannedChar('\\'); + validator->addBannedChar('-'); + validator->addBannedChar('_'); + validator->addBannedChar('/'); + + // + // The Name Editor + // + edit_name_edit=new QLineEdit(this,"edit_name_edit"); + edit_name_edit->setGeometry(10,10,sizeHint().width()-20,20); + edit_name_edit->setValidator(validator); + edit_name_edit->setText(*text); + + // + // OK Button + // + QPushButton *button=new QPushButton(this,"ok_button"); + button->setGeometry(sizeHint().width()-180,sizeHint().height()-60,80,50); + button->setDefault(true); + button->setFont(bold_font); + button->setText(tr("&OK")); + connect(button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(bold_font); + button->setText(tr("&Cancel")); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +QSize RenameItem::sizeHint() const +{ + return QSize(400,100); +} + + +QSizePolicy RenameItem::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void RenameItem::okData() +{ + if(edit_name_edit->text()==*edit_text) { + done(-1); + return; + } + QString sql=QString().sprintf("select NAME from %s where NAME=\"%s\"", + (const char *)edit_tablename, + (const char *)edit_name_edit->text()); + RDSqlQuery *q=new RDSqlQuery(sql); + if(q->next()) { + delete q; + QMessageBox::warning(this,tr("Name Conflict"), + tr("That name already exists!")); + return; + } + delete q; + *edit_text=edit_name_edit->text(); + done(0); +} + + +void RenameItem::cancelData() +{ + done(-1); +} diff --git a/rdlogmanager/rename_item.h b/rdlogmanager/rename_item.h new file mode 100644 index 00000000..2ee1518f --- /dev/null +++ b/rdlogmanager/rename_item.h @@ -0,0 +1,51 @@ +// rename_item.h +// +// Rename an RDLogManager Event or Clock +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: rename_item.h,v 1.5 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RENAME_ITEM_H +#define RENAME_ITEM_H + +#include +#include +#include + + +class RenameItem : public QDialog +{ + Q_OBJECT + public: + RenameItem(QString *text,QString table,QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void okData(); + void cancelData(); + + private: + QLineEdit *edit_name_edit; + QString *edit_text; + QString edit_tablename; +}; + + +#endif // EDIT_NOTE_H + diff --git a/rdlogmanager/svc_rec.cpp b/rdlogmanager/svc_rec.cpp new file mode 100644 index 00000000..f33994f5 --- /dev/null +++ b/rdlogmanager/svc_rec.cpp @@ -0,0 +1,422 @@ +// svc_rec.cpp +// +// A Qt-based application for testing General Purpose Outputs (GPO). +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: svc_rec.cpp,v 1.8 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include +#include +#include +#include +#include +#include + +// +// Global Classes +// +SvcRec::SvcRec(const QString &svcname, + QWidget *parent,const char *name) + :QWidget(parent,name) +{ + QString sql; + RDSqlQuery *q; + pick_service_name=svcname; + + // + // Generate Fonts + // + pick_day_font[0]=QFont("Helvetica",12,QFont::Normal); + pick_day_font[0].setPixelSize(12); + pick_day_font[1]=QFont("Helvetica",12,QFont::Bold); + pick_day_font[1].setPixelSize(12); + + // + // Generate Date Boundaries + // + pick_tablename=svcname; + pick_tablename.replace(" ","_"); + QDate current_date=QDate::currentDate(); + pick_high_year=current_date.year(); + pick_low_year=pick_high_year; + sql=QString().sprintf("select EVENT_DATETIME from `%s_SRT`\ + order by EVENT_DATETIME", + (const char *)pick_tablename); + q=new RDSqlQuery(sql); + if(q->first()) { + pick_low_year=q->value(0).toDate().year(); + } + delete q; + + // + // Month + // + pick_month_box=new QComboBox(this,"pick_month_box"); + pick_month_box->setGeometry(0,0,120,26); + for(int i=1;i<13;i++) { + pick_month_box->insertItem(QDate::longMonthName(i)); + } + connect(pick_month_box,SIGNAL(activated(int)), + this,SLOT(monthActivatedData(int))); + + // + // Year + // + pick_year_box=new QComboBox(this,"pick_year_box"); + pick_year_box->setGeometry(130,0,90,26); + for(int i=pick_low_year;i<(pick_high_year+1);i++) { + pick_year_box->insertItem(QString().sprintf("%04d",i)); + } + connect(pick_year_box,SIGNAL(activated(int)), + this,SLOT(yearActivatedData(int))); + pick_year_spin=NULL; + + // + // Date Labels + // + QPalette weekend_palette=palette(); + weekend_palette.setColor(QPalette::Active,QColorGroup::Background, + palette().color(QPalette::Active, + QColorGroup::Mid)); + weekend_palette.setColor(QPalette::Inactive,QColorGroup::Background, + palette().color(QPalette::Active, + QColorGroup::Mid)); + + QLabel *label=new QLabel(tr("Mo"),this,"monday_label"); + label->setGeometry(SVC_REC_X_ORIGIN,30,30,30); + label->setFont(pick_day_font[1]); + label->setAlignment(AlignCenter); + + label=new QLabel(tr("Tu"),this,"tuesday_label"); + label->setGeometry(SVC_REC_X_ORIGIN+SVC_REC_X_INTERVAL, + SVC_REC_Y_ORIGIN,30,30); + label->setFont(pick_day_font[1]); + label->setAlignment(AlignCenter); + + label=new QLabel(tr("We"),this,"wednesday_label"); + label->setGeometry(SVC_REC_X_ORIGIN+SVC_REC_X_INTERVAL*2, + SVC_REC_Y_ORIGIN,30,30); + label->setFont(pick_day_font[1]); + label->setAlignment(AlignCenter); + + label=new QLabel(tr("Th"),this,"thursday_label"); + label->setGeometry(SVC_REC_X_ORIGIN+SVC_REC_X_INTERVAL*3, + SVC_REC_Y_ORIGIN,30,30); + label->setFont(pick_day_font[1]); + label->setAlignment(AlignCenter); + + label=new QLabel(tr("Fr"),this,"friday_label"); + label->setGeometry(SVC_REC_X_ORIGIN+SVC_REC_X_INTERVAL*4, + SVC_REC_Y_ORIGIN,30,30); + label->setFont(pick_day_font[1]); + label->setAlignment(AlignCenter); + + label=new QLabel(tr("Sa"),this,"saturday_label"); + label->setGeometry(SVC_REC_X_ORIGIN+SVC_REC_X_INTERVAL*5, + SVC_REC_Y_ORIGIN,30,30); + label->setFont(pick_day_font[1]); + label->setAlignment(AlignCenter); + label->setPalette(weekend_palette); + + label=new QLabel(tr("Su"),this,"sunday_label"); + label->setGeometry(SVC_REC_X_ORIGIN+SVC_REC_X_INTERVAL*6, + SVC_REC_Y_ORIGIN,30,30); + label->setFont(pick_day_font[1]); + label->setAlignment(AlignCenter); + label->setPalette(weekend_palette); + + + for(int i=0;i<6;i++) { + for(int j=0;j<7;j++) { + pick_date_label[i][j]=new QLabel(this,"date_label"); + pick_date_label[i][j]-> + setGeometry(SVC_REC_X_ORIGIN+SVC_REC_X_INTERVAL*j, + SVC_REC_Y_ORIGIN+20+SVC_REC_Y_INTERVAL*i,30,30); + pick_date_label[i][j]->setAlignment(AlignCenter); + } + } + PrintDays(); + setDate(current_date); +} + + +SvcRec::~SvcRec() +{ +} + + +QSize SvcRec::sizeHint() const +{ + return QSize(220,175); +} + + +QSizePolicy SvcRec::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +QString SvcRec::serviceName() const +{ + return pick_service_name; +} + + +QDate SvcRec::date() const +{ + return pick_date; +} + + +bool SvcRec::setDate(QDate date) +{ + if(!date.isValid()) { + date=QDate::currentDate(); + } + if((date.year()pick_high_year)) { + return false; + } + pick_date=date; + pick_month_box->setCurrentItem(date.month()-1); + if(pick_year_box!=NULL) { + pick_year_box->setCurrentItem(date.year()-pick_low_year); + } + else { + pick_year_spin->setValue(date.year()); + } + GetActiveDays(date); + PrintDays(); + return true; +} + + +bool SvcRec::dayActive(int day) const +{ + return pick_active_days[day-1]; +} + + +void SvcRec::deleteDay() +{ + QString sql; + RDSqlQuery *q; + + QString tablename=pick_service_name; + tablename.replace(" ","_"); + sql=QString().sprintf("delete from `%s_SRT` where \ + (EVENT_DATETIME>=\"%s\")&&\ + (EVENT_DATETIME<=\"%s\")", + (const char *)tablename, + (const char *)date().toString("yyyy-MM-dd 00:00:00"), + (const char *)date().toString("yyyy-MM-dd 23:59:59")); + q=new RDSqlQuery(sql); + delete q; + GetActiveDays(pick_date); + PrintDays(); +} + + +void SvcRec::monthActivatedData(int id) +{ + QDate date=QDate(pick_date.year(),id+1,1); + if(pick_date.day()<=date.daysInMonth()) { + pick_date=QDate(pick_date.year(),id+1,pick_date.day()); + } + else { + pick_date=QDate(pick_date.year(),id+1,date.daysInMonth()); + } + GetActiveDays(pick_date); + PrintDays(); +} + + +void SvcRec::yearActivatedData(int id) +{ + QDate date=QDate(pick_low_year+pick_year_box->currentItem(), + pick_date.month(),1); + if(pick_date.day()<=date.daysInMonth()) { + pick_date=QDate(pick_low_year+pick_year_box->currentItem(), + pick_date.month(),pick_date.day()); + } + else { + pick_date=QDate(pick_low_year+pick_year_box->currentItem(), + pick_date.month(),date.daysInMonth()); + } + GetActiveDays(pick_date); + PrintDays(); +} + + +void SvcRec::yearChangedData(int year) +{ + QDate date=QDate(pick_year_spin->value(),pick_date.month(),1); + if(pick_date.day()<=date.daysInMonth()) { + pick_date=QDate(pick_year_spin->value(), + pick_date.month(),pick_date.day()); + } + else { + pick_date=QDate(pick_year_spin->value(), + pick_date.month(),date.daysInMonth()); + } + GetActiveDays(pick_date); + PrintDays(); +} + + +void SvcRec::mousePressEvent(QMouseEvent *e) +{ + if((e->pos().x()pos().x()>(SVC_REC_X_ORIGIN+SVC_REC_X_INTERVAL*7))|| + (e->pos().y()pos().y()>(SVC_REC_Y_ORIGIN+SVC_REC_Y_INTERVAL*7))) { + QWidget::mousePressEvent(e); + return; + } + int dow=(e->pos().x()-SVC_REC_X_ORIGIN)/SVC_REC_X_INTERVAL; + int week=(e->pos().y()-SVC_REC_Y_ORIGIN)/SVC_REC_Y_INTERVAL-1; + if((dow<0)||(dow>6)||(week<0)||(week>6)) { + return; + } + if(pick_date_label[week][dow]->text().isEmpty()) { + return; + } + pick_date=QDate(pick_date.year(),pick_date.month(), + pick_date_label[week][dow]->text().toInt()); + PrintDays(); + emit dateSelected(pick_date,pick_active_days[pick_date.day()-1]); +} + + +void SvcRec::PrintDays() +{ + QDate top_date; + + // + // Clear Days + // + QPalette weekend_palette=palette(); + weekend_palette.setColor(QPalette::Active,QColorGroup::Background, + palette().color(QPalette::Active, + QColorGroup::Mid)); + weekend_palette.setColor(QPalette::Inactive,QColorGroup::Background, + palette().color(QPalette::Active, + QColorGroup::Mid)); + for(int i=0;i<6;i++) { + for(int j=0;j<5;j++) { + pick_date_label[i][j]->clear(); + pick_date_label[i][j]->setPalette(palette()); + } + } + for(int i=0;i<6;i++) { + for(int j=5;j<7;j++) { + pick_date_label[i][j]->clear(); + pick_date_label[i][j]->setPalette(weekend_palette); + } + } + + // + // Get Top of Month + // + if(pick_year_box!=NULL) { + top_date=QDate(pick_low_year+pick_year_box->currentItem(), + pick_month_box->currentItem()+1,1); + } + else { + top_date=QDate(pick_year_spin->value(),pick_month_box->currentItem()+1,1); + } + + // + // Print Days + // + int dow_offset=top_date.dayOfWeek()-1; + for(int i=1;i<(top_date.daysInMonth()+1);i++) { + PrintDay(i,dow_offset); + if(pick_date.day()==i) { + SelectDay(i,dow_offset,true); + } + } +} + + +void SvcRec::PrintDay(int day,int dow_offset) +{ + int slot=day+dow_offset-1; + int week=slot/7; + int dow=slot-7*week; + pick_date_label[week][dow]->setText(QString().sprintf("%d",day)); + if(pick_active_days[day-1]) { + pick_date_label[week][dow]->setFont(pick_day_font[1]); + } + else { + pick_date_label[week][dow]->setFont(pick_day_font[0]); + } +} + + +void SvcRec::SelectDay(int day,int dow_offset,bool state) +{ + int slot=day+dow_offset-1; + int week=slot/7; + int dow=slot-7*week; + QPalette pal=palette(); + if(state) { + pal.setColor(QPalette::Active,QColorGroup::Foreground, + palette(). + color(QPalette::Active,QColorGroup::HighlightedText)); + pal.setColor(QPalette::Active,QColorGroup::Background, + palette().color(QPalette::Active,QColorGroup::Highlight)); + pal.setColor(QPalette::Inactive,QColorGroup::Foreground, + palette(). + color(QPalette::Active,QColorGroup::HighlightedText)); + pal.setColor(QPalette::Inactive,QColorGroup::Background, + palette().color(QPalette::Active,QColorGroup::Highlight)); + } + else { + pal.setColor(QPalette::Active,QColorGroup::Foreground, + palette().color(QPalette::Active,QColorGroup::Text)); + pal.setColor(QPalette::Active,QColorGroup::Background, + palette().color(QPalette::Active,QColorGroup::Background)); + pal.setColor(QPalette::Inactive,QColorGroup::Foreground, + palette().color(QPalette::Active,QColorGroup::Text)); + pal.setColor(QPalette::Inactive,QColorGroup::Background, + palette().color(QPalette::Active,QColorGroup::Background)); + } + pick_date_label[week][dow]->setPalette(pal); +} + + +void SvcRec::GetActiveDays(const QDate &date) +{ + QString sql; + RDSqlQuery *q; + + for(int i=0;i<=31;i++) { + sql=QString().sprintf("select ID from `%s_SRT` where \ + (EVENT_DATETIME>=\"%s-%02d 00:00:00\")&&\ + (EVENT_DATETIME<=\"%s-%02d 23:59:59\")", + (const char *)pick_tablename, + (const char *)date.toString("yyyy-MM"),i+1, + (const char *)date.toString("yyyy-MM"),i+1); + q=new RDSqlQuery(sql); + pick_active_days[i]=q->first(); + delete q; + } +} + diff --git a/rdlogmanager/svc_rec.h b/rdlogmanager/svc_rec.h new file mode 100644 index 00000000..7de45c0a --- /dev/null +++ b/rdlogmanager/svc_rec.h @@ -0,0 +1,90 @@ +// svc_rec.h +// +// A Calendar Widget. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: svc_rec.h,v 1.5 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef SVC_REC_H +#define SVC_REC_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Display Settings +// +#define SVC_REC_X_ORIGIN 20 +#define SVC_REC_X_INTERVAL 25 +#define SVC_REC_Y_ORIGIN 30 +#define SVC_REC_Y_INTERVAL 20 + +class SvcRec : public QWidget +{ + Q_OBJECT + public: + SvcRec(const QString &svcname,QWidget *parent=0,const char *name=0); + ~SvcRec(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + QString serviceName() const; + QDate date() const; + bool setDate(QDate date); + bool dayActive(int day) const; + void deleteDay(); + + signals: + void dateSelected(const QDate &date,bool active); + + private slots: + void monthActivatedData(int id); + void yearActivatedData(int id); + void yearChangedData(int year); + + protected: + void mousePressEvent(QMouseEvent *e); + + private: + void PrintDays(); + void PrintDay(int day,int dow_offset); + void SelectDay(int day,int dow_offset,bool state); + void GetActiveDays(const QDate &date); + QComboBox *pick_month_box; + QComboBox *pick_year_box; + QSpinBox *pick_year_spin; + QLabel *pick_date_label[6][7]; + QDate pick_date; + QString pick_tablename; + int pick_low_year; + int pick_high_year; + bool pick_active_days[31]; + QFont pick_day_font[2]; + QString pick_service_name; +}; + + +#endif // SVC_REC_H diff --git a/rdlogmanager/svc_rec_dialog.cpp b/rdlogmanager/svc_rec_dialog.cpp new file mode 100644 index 00000000..2c3363f6 --- /dev/null +++ b/rdlogmanager/svc_rec_dialog.cpp @@ -0,0 +1,141 @@ +// svc_rec_dialog.cpp +// +// A Services/Reports Management Dialog. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: svc_rec_dialog.cpp,v 1.10 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +// +// Global Classes +// +SvcRecDialog::SvcRecDialog(const QString &svcname, + QWidget *parent,const char *name) + :QDialog(parent,name,true) +{ + QFont font; + + font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + + setCaption(QString().sprintf("%s %s",(const char *)svcname, + (const char *)tr("Report Data"))); + + // + // Datepicker + // + date_picker=new SvcRec(svcname,this,"date_picker"); + date_picker->setGeometry(10,10, + date_picker->sizeHint().width(), + date_picker->sizeHint().height()); + connect(date_picker,SIGNAL(dateSelected(const QDate &,bool)), + this,SLOT(dateSelectedData(const QDate &,bool))); + + // + // Delete Button + // + date_delete_button=new QPushButton(this,"date_delete_button"); + date_delete_button-> + setGeometry(10,sizeHint().height()-60,80,50); + date_delete_button->setFont(font); + date_delete_button->setText(tr("&Purge\nData")); + connect(date_delete_button,SIGNAL(clicked()),this,SLOT(deleteData())); +#ifndef WIN32 + date_delete_button->setEnabled(rduser->deleteRec()&& + date_picker->dayActive(date_picker->date().day())); +#endif // WIN32 + + // + // Close Button + // + QPushButton *button=new QPushButton(this,"close_button"); + button->setGeometry(sizeHint().width()-90,sizeHint().height()-60,80,50); + button->setFont(font);\ + button->setText(tr("&Close")); + button->setDefault(true); + connect(button,SIGNAL(clicked()),this,SLOT(closeData())); +} + + +SvcRecDialog::~SvcRecDialog() +{ +} + + +QSize SvcRecDialog::sizeHint() const +{ + return QSize(date_picker->sizeHint().width()+20, + date_picker->sizeHint().height()+85); +} + + +QSizePolicy SvcRecDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void SvcRecDialog::dateSelectedData(const QDate &,bool active) +{ +#ifdef WIN32 + date_delete_button-> + setEnabled(date_picker->dayActive(date_picker->date().day())); +#else + date_delete_button->setEnabled(rduser->deleteRec()&& + date_picker->dayActive(date_picker->date().day())); +#endif // WIN32 +} + + +void SvcRecDialog::deleteData() +{ + if(QMessageBox::question(this,tr("Delete Report Data"), + QString().sprintf("%s %s?", + (const char *)tr("Are you sure you want to delete report data for"), + (const char *)date_picker->date().toString("MM/dd/yyyy")), + QMessageBox::Yes,QMessageBox::No)!=QMessageBox::Yes) { + return; + } + date_picker->deleteDay(); + date_delete_button->setDisabled(true); +} + + +void SvcRecDialog::closeData() +{ + done(-1); +} diff --git a/rdlogmanager/svc_rec_dialog.h b/rdlogmanager/svc_rec_dialog.h new file mode 100644 index 00000000..18f58b29 --- /dev/null +++ b/rdlogmanager/svc_rec_dialog.h @@ -0,0 +1,63 @@ +// svc_rec_dialog.h +// +// A Services/Reports Management Dialog. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: svc_rec_dialog.h,v 1.6 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef DELETE_SVC_REC_DIALOG_H +#define DELETE_SVC_REC_DIALOG_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +class SvcRecDialog : public QDialog +{ + Q_OBJECT + public: + SvcRecDialog(const QString &svcname,QWidget *parent=0, + const char *name=0); + ~SvcRecDialog(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void dateSelectedData(const QDate &,bool active); +// void generateData(); + void deleteData(); + void closeData(); + + private: + SvcRec *date_picker; + QDate *date_date; +// QPushButton *date_generate_button; + QPushButton *date_delete_button; +}; + + +#endif // SVC_REC_DIALOG_H diff --git a/rdmonitor/Makefile.am b/rdmonitor/Makefile.am new file mode 100644 index 00000000..d54679da --- /dev/null +++ b/rdmonitor/Makefile.am @@ -0,0 +1,75 @@ +## automake.am +## +## Automake.am for rivendell/rdmonitor +## +## (C) Copyright 2012 Fred Gleason +## +## $Id: Makefile.am,v 1.1.2.4 2013/11/08 03:57:14 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdmonitor_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rdmonitor_*.qm + +all: + @QT_BIN@/lupdate rdmonitor.pro + @QT_BIN@/lrelease rdmonitor.pro + +bin_PROGRAMS = rdmonitor + +dist_rdmonitor_SOURCES = positiondialog.cpp positiondialog.h\ + rdmonitor.cpp rdmonitor.h\ + status_tip.cpp status_tip.h + +nodist_rdmonitor_SOURCES = moc_positiondialog.cpp\ + moc_rdmonitor.cpp + +rdmonitor_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdmonitor.pro\ + rdmonitor_cs.ts\ + rdmonitor_de.ts\ + rdmonitor_es.ts\ + rdmonitor_fr.ts\ + rdmonitor_nb.ts\ + rdmonitor_nn.ts\ + rdmonitor_pt_BR.ts + +CLEANFILES = *~\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/rdmonitor/positiondialog.cpp b/rdmonitor/positiondialog.cpp new file mode 100644 index 00000000..a9182211 --- /dev/null +++ b/rdmonitor/positiondialog.cpp @@ -0,0 +1,176 @@ +// positiondialog.cpp +// +// Dialog to set RDMonitor screen position. +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: positiondialog.cpp,v 1.1.2.2 2013/11/11 20:34:27 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include "positiondialog.h" + +PositionDialog::PositionDialog(QDesktopWidget *dw,RDMonitorConfig *config, + QWidget *parent) + : QDialog(parent) +{ + pos_desktop_widget=dw; + pos_config=config; + + setCaption("RDMonitor"); + + // + // Fonts + // + QFont button_font("helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + + QFont list_font("helvetica",12,QFont::Normal); + list_font.setPixelSize(12); + + // + // Screen Number + // + pos_screen_number_box=new QComboBox(this); + pos_screen_number_box->setFont(list_font); + pos_screen_number_label= + new QLabel(pos_screen_number_box,tr("Screen")+":",this); + pos_screen_number_label->setFont(button_font); + pos_screen_number_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Position + // + pos_position_box=new QComboBox(this); + pos_position_box->setFont(list_font); + pos_position_box->setFont(list_font); + pos_position_label= + new QLabel(pos_position_box,tr("Position")+":",this); + pos_position_label->setFont(button_font); + pos_position_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + for(int i=0;i + insertItem(RDMonitorConfig::positionText((RDMonitorConfig::Position)i)); + } + + // + // X Offset + // + pos_x_offset_spin=new QSpinBox(this); + pos_x_offset_spin->setFont(list_font); + pos_x_offset_spin->setRange(0,99); + pos_x_offset_label=new QLabel(pos_x_offset_spin,tr("X Offset")+":",this); + pos_x_offset_label->setFont(button_font); + pos_x_offset_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Y Offset + // + pos_y_offset_spin=new QSpinBox(this); + pos_y_offset_spin->setFont(list_font); + pos_y_offset_spin->setRange(0,99); + pos_y_offset_label=new QLabel(pos_y_offset_spin,tr("Y Offset")+":",this); + pos_y_offset_label->setFont(button_font); + pos_y_offset_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // OK Button + // + pos_ok_button=new QPushButton(tr("OK"),this); + pos_ok_button->setFont(button_font); + connect(pos_ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + pos_cancel_button=new QPushButton(tr("Cancel"),this); + pos_cancel_button->setFont(button_font); + connect(pos_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + setMaximumSize(sizeHint()); + setMinimumSize(sizeHint()); +} + + +QSize PositionDialog::sizeHint() const +{ + return QSize(240,170); +} + + +QSizePolicy PositionDialog::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int PositionDialog::exec() +{ + pos_screen_number_box->clear(); + for(int i=0;inumScreens();i++) { + pos_screen_number_box->insertItem(QString().sprintf("%d",i)); + if(i==pos_config->screenNumber()) { + pos_screen_number_box->setCurrentItem(i); + } + } + pos_position_box->setCurrentItem((int)pos_config->position()); + pos_x_offset_spin->setValue(pos_config->xOffset()); + pos_y_offset_spin->setValue(pos_config->yOffset()); + + return QDialog::exec(); +} + + +void PositionDialog::okData() +{ + pos_config->setScreenNumber(pos_screen_number_box->currentItem()); + pos_config-> + setPosition((RDMonitorConfig::Position)pos_position_box->currentItem()); + pos_config->setXOffset(pos_x_offset_spin->value()); + pos_config->setYOffset(pos_y_offset_spin->value()); + + done(0); +} + + +void PositionDialog::cancelData() +{ + done(-1); +} + + +void PositionDialog::resizeEvent(QResizeEvent *e) +{ + pos_screen_number_label->setGeometry(10,10,65,20); + pos_screen_number_box->setGeometry(80,10,70,20); + + pos_position_label->setGeometry(10,32,65,20); + pos_position_box->setGeometry(80,32,150,20); + + pos_x_offset_label->setGeometry(10,54,65,20); + pos_x_offset_spin->setGeometry(80,54,40,20); + + pos_y_offset_label->setGeometry(10,76,65,20); + pos_y_offset_spin->setGeometry(80,76,40,20); + + pos_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + pos_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void PositionDialog::closeEvent(QCloseEvent *e) +{ + cancelData(); +} diff --git a/rdmonitor/positiondialog.h b/rdmonitor/positiondialog.h new file mode 100644 index 00000000..7061ddf1 --- /dev/null +++ b/rdmonitor/positiondialog.h @@ -0,0 +1,68 @@ +// positiondialog.h +// +// Dialog to set RDMonitor screen position. +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: positiondialog.h,v 1.1.2.1 2013/11/08 03:57:15 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef POSITIONDIALOG_H +#define POSITIONDIALOG_H + +#include +#include +#include +#include +#include +#include + +#include + +class PositionDialog : public QDialog +{ + Q_OBJECT + public: + PositionDialog(QDesktopWidget *dw,RDMonitorConfig *config,QWidget *parent=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + public slots: + int exec(); + + private slots: + void okData(); + void cancelData(); + + private: + void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e); + QLabel *pos_screen_number_label; + QComboBox *pos_screen_number_box; + QLabel *pos_position_label; + QComboBox *pos_position_box; + QLabel *pos_x_offset_label; + QSpinBox *pos_x_offset_spin; + QLabel *pos_y_offset_label; + QSpinBox *pos_y_offset_spin; + QPushButton *pos_ok_button; + QPushButton *pos_cancel_button; + QDesktopWidget *pos_desktop_widget; + RDMonitorConfig *pos_config; +}; + + +#endif // POSITIONDIALOG_H diff --git a/rdmonitor/rdmonitor.cpp b/rdmonitor/rdmonitor.cpp new file mode 100644 index 00000000..c0da842d --- /dev/null +++ b/rdmonitor/rdmonitor.cpp @@ -0,0 +1,410 @@ +// rdmonitor.cpp +// +// System Monitor for Rivendell +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: rdmonitor.cpp,v 1.1.2.13 2014/02/10 20:54:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// Icons +// +#include "../icons/rivendell-22x22.xpm" +#include "../icons/greenball.xpm" +#include "../icons/redball.xpm" + +void SigHandler(int signo) +{ + switch(signo) { + case SIGTERM: + case SIGINT: + exit(0); + break; + } +} + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name,Qt::WStyle_Customize|Qt::WStyle_NoBorder|Qt::WStyle_StaysOnTop|WX11BypassWM) +{ + QString str; + mon_dialog_x=0; + mon_dialog_y=0; + mon_rdselect_x=0; + mon_rdselect_y=0; + + // + // Read Command Options + // + RDCmdSwitch *cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdmonitor","\n"); + delete cmd; + + // + // Hide at startup + // + setGeometry(0,0,0,0); + + // + // Generate Fonts + // + QFont font=QFont("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + mon_metrics=new QFontMetrics(font); + + // + // Create And Set Icon + // + setIcon(QPixmap(rivendell_xpm)); + + // + // Dialogs + // + mon_rdconfig=new RDConfig(); + mon_rdconfig->load(); + mon_desktop_widget=new QDesktopWidget(); + mon_config=new RDMonitorConfig(); + mon_config->load(); + mon_position_dialog=new PositionDialog(mon_desktop_widget,mon_config,this); + mon_position_dialog->setGeometry(0,0,mon_position_dialog->sizeHint().width(), + mon_position_dialog->sizeHint().height()); + + // + // Name Label + // + mon_name_label=new QLabel(this); + mon_name_label->setFont(font); + + // + // Status Icons + // + mon_green_label=new QLabel(this); + mon_green_label->setPixmap(QPixmap(greenball_xpm)); + mon_green_label->hide(); + + mon_red_label=new QLabel(this); + mon_red_label->setPixmap(QPixmap(redball_xpm)); + mon_red_label->hide(); + + // + // Validation Timer + // + mon_validate_timer=new QTimer(this); + connect(mon_validate_timer,SIGNAL(timeout()),this,SLOT(validate())); + mon_validate_timer->start(5000); + + mon_tooltip=new StatusTip(this); + + mon_name_label->setText(mon_rdconfig->label()); + SetPosition(); + + ::signal(SIGTERM,SigHandler); + ::signal(SIGINT,SigHandler); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::validate() +{ + bool db_ok=false; + bool snd_ok=false; + int schema=0; + std::vector bad_cuts; + + // + // Get Configurations + // + mon_rdconfig->load(); + mon_name_label->setText(mon_rdconfig->label()); + + // + // Check Audio Store + // + snd_ok=RDAudioStoreValid(mon_rdconfig); + + // + // Check Database + // + db_ok=RDDbValid(mon_rdconfig,&schema); + + // + // Record Results + // + mon_tooltip-> + setStatus(QRect(0,0,size().width(),size().height()),db_ok,schema,snd_ok); + SetSummaryState(db_ok&&(schema==RD_VERSION_DATABASE)&&snd_ok); + SetPosition(); +} + + +void MainWidget::quitMainWidget() +{ + exit(0); +} + + +void MainWidget::mousePressEvent(QMouseEvent *e) +{ + if(e->button()!=QMouseEvent::RightButton) { + e->ignore(); + return; + } + e->accept(); + mon_position_dialog->setGeometry(mon_dialog_x,mon_dialog_y, + mon_position_dialog->sizeHint().width(), + mon_position_dialog->sizeHint().height()); + if(mon_position_dialog->exec()==0) { + mon_config->save(); + SetPosition(); + } +} + + +void MainWidget::mouseDoubleClickEvent(QMouseEvent *e) +{ + if(e->button()!=QMouseEvent::LeftButton) { + e->ignore(); + return; + } + e->accept(); + QDir dir(RD_DEFAULT_RDSELECT_DIR); + dir.setFilter(QDir::Files|QDir::Readable); + dir.setNameFilter("*.conf"); + if(dir.entryList().size()>1) { + system(QString().sprintf("rdselect -geometry +%d+%d", + mon_rdselect_x,mon_rdselect_y)); + validate(); + } +} + + +void MainWidget::paintEvent(QPaintEvent *e) +{ + QPainter *p=new QPainter(this); + p->setPen(QPen(Qt::black,2)); + p->drawRect(1,1,size().width(),size().height()); + + delete p; +} + + +void MainWidget::resizeEvent(QResizeEvent *e) +{ + mon_name_label->setGeometry(10,5,size().width()-30,size().height()-10); + mon_green_label->setGeometry(size().width()-20,5,15,20); + mon_red_label->setGeometry(size().width()-20,5,15,20); +} + + +void MainWidget::SetSummaryState(bool state) +{ + if(state) { + mon_red_label->hide(); + mon_green_label->show(); + } + else { + mon_green_label->hide(); + mon_red_label->show(); + } +} + + +void MainWidget::SetPosition() +{ + int width=mon_metrics->width(mon_name_label->text())+40; + QRect geo=mon_desktop_widget->screenGeometry(mon_config->screenNumber()); + QRect main_geo=mon_desktop_widget->geometry(); + int x=0; + int dx=mon_config->xOffset(); + int y=0; + int dy=mon_config->yOffset(); + int dw=mon_position_dialog->size().width()+30; + int dh=mon_position_dialog->size().height()+30; + + switch(mon_config->position()) { + case RDMonitorConfig::UpperLeft: + x=geo.x()+dx; + y=geo.y()+dy; + break; + + case RDMonitorConfig::UpperCenter: + x=geo.x()+(geo.width()-width)/2; + y=geo.y()+dy; + break; + + case RDMonitorConfig::UpperRight: + x=geo.x()-dx+geo.width()-width; + y=geo.y()+dy; + break; + + case RDMonitorConfig::LowerLeft: + x=geo.x()+dx; + y=geo.y()-dy+geo.height()-RDMONITOR_HEIGHT; + break; + + case RDMonitorConfig::LowerCenter: + x=geo.x()+(geo.width()-width)/2; + y=geo.y()-dy+geo.height()-RDMONITOR_HEIGHT; + break; + + case RDMonitorConfig::LowerRight: + x=geo.x()-dx+geo.width()-width; + y=geo.y()-dy+geo.height()-RDMONITOR_HEIGHT; + break; + + case RDMonitorConfig::LastPosition: + break; + } + + // + // Ensure sane values + // + if(x<0) { + x=0; + } + if(x>(main_geo.width()-width)) { + x=main_geo.width()-width; + } + if(y<0) { + y=0; + } + if(y>(main_geo.height()-RDMONITOR_HEIGHT)) { + y=main_geo.height()-RDMONITOR_HEIGHT; + } + + // + // Set the dialog position + // + switch(mon_config->position()) { + case RDMonitorConfig::UpperLeft: + mon_dialog_x=x; + mon_rdselect_x=x; + mon_dialog_y=y+RDMONITOR_HEIGHT; + mon_rdselect_y=y+RDMONITOR_HEIGHT; + break; + + case RDMonitorConfig::UpperCenter: + mon_dialog_x=x+(width-dw)/2; + mon_dialog_y=y+RDMONITOR_HEIGHT; + mon_rdselect_x=x+(width-RDSELECT_WIDTH)/2; + mon_rdselect_y=y+RDMONITOR_HEIGHT; + break; + + case RDMonitorConfig::UpperRight: + mon_dialog_x=x+width-dw; + mon_dialog_y=y+RDMONITOR_HEIGHT; + mon_rdselect_x=x+width-RDSELECT_WIDTH; + mon_rdselect_y=y+RDMONITOR_HEIGHT; + break; + + case RDMonitorConfig::LowerLeft: + mon_dialog_x=x; + mon_rdselect_x=x; + mon_dialog_y=y-dh; + mon_rdselect_y=y-RDSELECT_HEIGHT-30; + break; + + case RDMonitorConfig::LowerCenter: + mon_dialog_x=x+(width-dw)/2; + mon_dialog_y=y-dh; + mon_rdselect_x=x+(width-RDSELECT_WIDTH)/2; + mon_rdselect_y=y-RDSELECT_HEIGHT-30; + break; + + case RDMonitorConfig::LowerRight: + mon_dialog_x=x+width-dw; + mon_rdselect_x=x+width-RDSELECT_WIDTH; + mon_dialog_y=y-dh; + mon_rdselect_y=y-RDSELECT_HEIGHT-30; + break; + + case RDMonitorConfig::LastPosition: + break; + } + setGeometry(x,y,width,RDMONITOR_HEIGHT); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(), + "."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rdmonitor_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->show(); + return a.exec(); +} diff --git a/rdmonitor/rdmonitor.h b/rdmonitor/rdmonitor.h new file mode 100644 index 00000000..66e262c1 --- /dev/null +++ b/rdmonitor/rdmonitor.h @@ -0,0 +1,83 @@ +// rdmonitor.h +// +// System Monitor Applet for Rivendell +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: rdmonitor.h,v 1.1.2.6 2013/11/08 03:57:15 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDMONITOR_H +#define RDMONITOR_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "positiondialog.h" +#include "status_tip.h" + +#define RDSELECT_WIDTH 400 +#define RDSELECT_HEIGHT 300 + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSizePolicy sizePolicy() const; + + private slots: + void validate(); + void quitMainWidget(); + + protected: + void mousePressEvent(QMouseEvent *e); + void mouseDoubleClickEvent(QMouseEvent *e); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + + private: + void SetSummaryState(bool state); + void SetPosition(); + QLabel *mon_name_label; + QLabel *mon_green_label; + QLabel *mon_red_label; + QTimer *mon_validate_timer; + QFontMetrics *mon_metrics; + PositionDialog *mon_position_dialog; + int mon_dialog_x; + int mon_dialog_y; + int mon_rdselect_x; + int mon_rdselect_y; + StatusTip *mon_tooltip; + QDesktopWidget *mon_desktop_widget; + RDMonitorConfig *mon_config; + RDConfig *mon_rdconfig; +}; + + +#endif // RDMONITOR_H diff --git a/rdmonitor/rdmonitor.pro b/rdmonitor/rdmonitor.pro new file mode 100644 index 00000000..da8b14dc --- /dev/null +++ b/rdmonitor/rdmonitor.pro @@ -0,0 +1,40 @@ +# rdmonitor.pro +# +# The QMake project file for RDMonitor. +# +# (C) Copyright 2012 Fred Gleason +# +# $Id: rdmonitor.pro,v 1.1.2.2 2013/01/01 21:36:32 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +x11 { + SOURCES += rdmonitor.cpp + SOURCES += status_tip.cpp +} + +x11 { + HEADERS += rdmonitor.h + HEADERS += status_tip.h +} + +TRANSLATIONS += rdmonitor_cs.ts +TRANSLATIONS += rdmonitor_de.ts +TRANSLATIONS += rdmonitor_es.ts +TRANSLATIONS += rdmonitor_fr.ts +TRANSLATIONS += rdmonitor_nb.ts +TRANSLATIONS += rdmonitor_nn.ts +TRANSLATIONS += rdmonitor_pt_BR.ts diff --git a/rdmonitor/rdmonitor_cs.ts b/rdmonitor/rdmonitor_cs.ts new file mode 100644 index 00000000..094e296f --- /dev/null +++ b/rdmonitor/rdmonitor_cs.ts @@ -0,0 +1,21 @@ + + + QObject + + Status: OK + Stav: OK + + + Audio Store: FAILED + Uložení zvuku: NEPODAŘILO SE + + + Database: CONNECTION FAILED + Databáze: SPOJENÍ SE NEZDAŘILO + + + Database: SCHEMA SKEWED + Databáze: SCHÉMA ZKRESLENO + + + diff --git a/rdmonitor/rdmonitor_de.ts b/rdmonitor/rdmonitor_de.ts new file mode 100644 index 00000000..5ef7004e --- /dev/null +++ b/rdmonitor/rdmonitor_de.ts @@ -0,0 +1,21 @@ + + + QObject + + Status: OK + + + + Audio Store: FAILED + + + + Database: CONNECTION FAILED + + + + Database: SCHEMA SKEWED + + + + diff --git a/rdmonitor/rdmonitor_es.ts b/rdmonitor/rdmonitor_es.ts new file mode 100644 index 00000000..5ef7004e --- /dev/null +++ b/rdmonitor/rdmonitor_es.ts @@ -0,0 +1,21 @@ + + + QObject + + Status: OK + + + + Audio Store: FAILED + + + + Database: CONNECTION FAILED + + + + Database: SCHEMA SKEWED + + + + diff --git a/rdmonitor/rdmonitor_fr.ts b/rdmonitor/rdmonitor_fr.ts new file mode 100644 index 00000000..5ef7004e --- /dev/null +++ b/rdmonitor/rdmonitor_fr.ts @@ -0,0 +1,21 @@ + + + QObject + + Status: OK + + + + Audio Store: FAILED + + + + Database: CONNECTION FAILED + + + + Database: SCHEMA SKEWED + + + + diff --git a/rdmonitor/rdmonitor_nb.ts b/rdmonitor/rdmonitor_nb.ts new file mode 100644 index 00000000..5ef7004e --- /dev/null +++ b/rdmonitor/rdmonitor_nb.ts @@ -0,0 +1,21 @@ + + + QObject + + Status: OK + + + + Audio Store: FAILED + + + + Database: CONNECTION FAILED + + + + Database: SCHEMA SKEWED + + + + diff --git a/rdmonitor/rdmonitor_nn.ts b/rdmonitor/rdmonitor_nn.ts new file mode 100644 index 00000000..5ef7004e --- /dev/null +++ b/rdmonitor/rdmonitor_nn.ts @@ -0,0 +1,21 @@ + + + QObject + + Status: OK + + + + Audio Store: FAILED + + + + Database: CONNECTION FAILED + + + + Database: SCHEMA SKEWED + + + + diff --git a/rdmonitor/rdmonitor_pt_BR.ts b/rdmonitor/rdmonitor_pt_BR.ts new file mode 100644 index 00000000..5ef7004e --- /dev/null +++ b/rdmonitor/rdmonitor_pt_BR.ts @@ -0,0 +1,21 @@ + + + QObject + + Status: OK + + + + Audio Store: FAILED + + + + Database: CONNECTION FAILED + + + + Database: SCHEMA SKEWED + + + + diff --git a/rdmonitor/status_tip.cpp b/rdmonitor/status_tip.cpp new file mode 100644 index 00000000..1727b017 --- /dev/null +++ b/rdmonitor/status_tip.cpp @@ -0,0 +1,66 @@ +// status_tip.cpp +// +// Custom ToolTip for RDMonitor's Status Bubble +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: status_tip.cpp,v 1.1.2.2 2012/10/22 23:09:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include + +StatusTip::StatusTip(QWidget *widget,QToolTipGroup *group) + : QToolTip(widget,group) +{ + setStatus(QRect(),true,0,true); +} + + +void StatusTip::setStatus(const QRect &rect,bool db_status,int schema, + bool snd_status) +{ + tip_rect=rect; + if(db_status&&(schema==RD_VERSION_DATABASE)&&snd_status) { + tip_text=QObject::tr("Status: OK"); + } + else { + tip_text=""; + if(!db_status) { + tip_text=QObject::tr("Database: CONNECTION FAILED"); + } + else { + if(schema!=RD_VERSION_DATABASE) { + tip_text=QObject::tr("Database: SCHEMA SKEWED"); + } + } + if(!snd_status) { + if(!tip_text.isEmpty()) { + tip_text+="\n"; + } + tip_text+=QObject::tr("Audio Store: FAILED"); + } + } +} + + +void StatusTip::maybeTip(const QPoint &pt) +{ + tip(tip_rect,tip_text); +} diff --git a/rdmonitor/status_tip.h b/rdmonitor/status_tip.h new file mode 100644 index 00000000..eed76adb --- /dev/null +++ b/rdmonitor/status_tip.h @@ -0,0 +1,42 @@ +// status_tip.h +// +// Custom ToolTip for RDMonitor's Status Bubble +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: status_tip.h,v 1.1.2.2 2012/10/22 23:09:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef STATUS_TIP_H +#define STATUS_TIP_H + +#include + +class StatusTip : public QToolTip +{ + public: + StatusTip(QWidget *widget,QToolTipGroup *group=0); + void setStatus(const QRect &rect,bool db_status,int schema,bool snd_status); + + protected: + void maybeTip(const QPoint &pt); + + private: + QString tip_text; + QRect tip_rect; +}; + +#endif // STATUS_TIP_H diff --git a/rdpanel/Makefile.am b/rdpanel/Makefile.am new file mode 100644 index 00000000..10d4aed9 --- /dev/null +++ b/rdpanel/Makefile.am @@ -0,0 +1,71 @@ +## automake.am +## +## Automake.am for rivendell/rdpanel +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.18.8.2 2013/01/01 21:36:32 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdpanel_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rdpanel_*.qm + +all: + @QT_BIN@/lupdate rdpanel.pro + @QT_BIN@/lrelease rdpanel.pro + +bin_PROGRAMS = rdpanel + +dist_rdpanel_SOURCES = globals.h\ + rdpanel.cpp rdpanel.h + +nodist_rdpanel_SOURCES = moc_rdpanel.cpp + +rdpanel_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdpanel.pro\ + rdpanel_cs.ts\ + rdpanel_de.ts\ + rdpanel_es.ts\ + rdpanel_fr.ts\ + rdpanel_pt_BR.ts + +CLEANFILES = *~\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/rdpanel/globals.h b/rdpanel/globals.h new file mode 100644 index 00000000..9d26d29b --- /dev/null +++ b/rdpanel/globals.h @@ -0,0 +1,45 @@ +// globals.h +// +// Global Variable Declarations for RDPanel +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: globals.h,v 1.5.14.1 2012/11/26 20:19:41 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef GLOBALS_H +#define GLOBALS_H + +#include +#include +#include +#include +#include +#include + +// +// Global Resources +// +extern RDStation *rdstation_conf; +extern RDSystem *rdsystem_conf; +extern RDAirPlayConf *rdairplay_conf; +extern RDAudioPort *rdaudioport_conf; +extern RDUser *rduser; +extern RDRipc *rdripc; +extern RDCartDialog *panel_cart_dialog; + + +#endif // GLOBALS_H diff --git a/rdpanel/rdpanel.cpp b/rdpanel/rdpanel.cpp new file mode 100644 index 00000000..a678a56d --- /dev/null +++ b/rdpanel/rdpanel.cpp @@ -0,0 +1,468 @@ +// rdpanel.cpp +// +// A Dedicated Cart Wall Utility for Rivendell. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rdpanel.cpp,v 1.27.4.9 2014/02/11 23:46:30 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +// +// Global Resources +// +RDStation *rdstation_conf; +RDSystem *rdsystem_conf; +RDAirPlayConf *rdairplay_conf; +RDAudioPort *rdaudioport_conf; +RDUser *rduser; +RDRipc *rdripc; +#include +RDCartDialog *panel_cart_dialog; + +// +// Icons +// +#include "../icons/rivendell-22x22.xpm" + + +void SigHandler(int signo) +{ + pid_t pLocalPid; + + switch(signo) { + case SIGCHLD: + pLocalPid=waitpid(-1,NULL,WNOHANG); + while(pLocalPid>0) { + pLocalPid=waitpid(-1,NULL,WNOHANG); + } + signal(SIGCHLD,SigHandler); + return; + } +} + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + QPixmap *pm; + QPainter *pd; + bool skip_db_check=false; + unsigned schema=0; + + // + // Fix the Window Size + // +#ifndef RESIZABLE + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); +#endif // RESIZABLE + + // + // Load the command-line arguments + // + RDCmdSwitch *cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdpanel", + RDPANEL_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + } + + // + // Generate Fonts + // + QFont button_font=QFont("Helvetica",16,QFont::Bold); + button_font.setPixelSize(16); + + // + // Create Icons + // + lib_rivendell_map=new QPixmap(rivendell_xpm); + setIcon(*lib_rivendell_map); + + // + // Ensure that system daemons are running + // + RDInitializeDaemons(); + + // + // Load Local Configs + // + panel_config=new RDConfig(); + panel_config->load(); + + // + // Open Database + // + QString err(tr("rdpanel : ")); + QSqlDatabase *login_db=RDInitDb(&schema,&err); + if(!login_db) { + QMessageBox::warning(this,tr("Can't Connect"),err); + exit(0); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr,"rdlogin: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + new RDDbHeartbeat(panel_config->mysqlHeartbeatInterval(),this); + + // + // Master Clock Timer + // + panel_master_timer=new QTimer(this,"panel_master_timer"); + connect(panel_master_timer,SIGNAL(timeout()),this,SLOT(masterTimerData())); + panel_master_timer->start(MASTER_TIMER_INTERVAL); + + // + // Allocate Global Resources + // + rdstation_conf=new RDStation(panel_config->stationName()); + rdsystem_conf=new RDSystem(); + rdairplay_conf=new RDAirPlayConf(panel_config->stationName(),"RDPANEL"); + panel_skin_pixmap=new QPixmap(rdairplay_conf->skinPath()); + if(panel_skin_pixmap->isNull()||(panel_skin_pixmap->width()<1024)|| + (panel_skin_pixmap->height()<738)) { + delete panel_skin_pixmap; + panel_skin_pixmap=NULL; + } + else { + setErasePixmap(*panel_skin_pixmap); + } + + // + // CAE Connection + // + panel_cae=new RDCae(rdstation_conf,panel_config,parent,name); + panel_cae->connectHost(); + + // + // RIPC Connection + // + rdripc=new RDRipc(panel_config->stationName()); + connect(rdripc,SIGNAL(userChanged()),this,SLOT(userData())); + connect(rdripc,SIGNAL(rmlReceived(RDMacro *)), + this,SLOT(rmlReceivedData(RDMacro *))); +// rdripc->connectHost("localhost",RIPCD_TCP_PORT,panel_config->password()); + + // + // User + // + rduser=NULL; + + // + // Meter Timer + // + QTimer *timer=new QTimer(this,"meter_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(meterData())); + timer->start(METER_INTERVAL); + + // + // Macro Player + // + panel_player=new RDEventPlayer(rdripc,this); + + // + // Cart Picker + // + panel_cart_dialog= + new RDCartDialog(&panel_filter,&panel_group,&panel_schedcode,panel_cae, + rdripc,rdstation_conf,rdsystem_conf,panel_config,this); + + // + // Sound Panel Array + // + if (rdairplay_conf->panels(RDAirPlayConf::StationPanel) || + rdairplay_conf->panels(RDAirPlayConf::UserPanel)){ + int card=-1; + panel_panel= + new RDSoundPanel(RDPANEL_PANEL_BUTTON_COLUMNS,RDPANEL_PANEL_BUTTON_ROWS, + rdairplay_conf->panels(RDAirPlayConf::StationPanel), + rdairplay_conf->panels(RDAirPlayConf::UserPanel), + rdairplay_conf->flashPanel(), + rdairplay_conf->buttonLabelTemplate(),true,panel_player, + rdripc,panel_cae,rdstation_conf,panel_cart_dialog, + this,"panel_panel"); + panel_panel->setLogfile(panel_config->airplayLogname()); + panel_panel->setGeometry(10,10,panel_panel->sizeHint().width(), + panel_panel->sizeHint().height()); + if(panel_skin_pixmap!=NULL) { + pm=new QPixmap(1024,738); + pd=new QPainter(pm); + pd->drawPixmap(-10,-10,*panel_skin_pixmap); + pd->end(); + panel_panel->setErasePixmap(*pm); + delete pd; + delete pm; + } + panel_panel->setPauseEnabled(rdairplay_conf->panelPauseEnabled()); + panel_panel->setCard(0,rdairplay_conf->card(RDAirPlayConf::SoundPanel1Channel)); + panel_panel->setPort(0,rdairplay_conf->port(RDAirPlayConf::SoundPanel1Channel)); + panel_panel->setFocusPolicy(QWidget::NoFocus); + if((card=rdairplay_conf->card(RDAirPlayConf::SoundPanel2Channel))<0) { + panel_panel->setCard(1,panel_panel->card(RDAirPlayConf::MainLog1Channel)); + panel_panel->setPort(1,panel_panel->port(RDAirPlayConf::MainLog1Channel)); + } + else { + panel_panel->setCard(1,card); + panel_panel->setPort(1,rdairplay_conf->port(RDAirPlayConf::SoundPanel2Channel)); + } + if((card=rdairplay_conf->card(RDAirPlayConf::SoundPanel3Channel))<0) { + panel_panel->setCard(2,panel_panel->card(RDAirPlayConf::MainLog2Channel)); + panel_panel->setPort(2,panel_panel->port(RDAirPlayConf::MainLog2Channel)); + } + else { + panel_panel->setCard(2,card); + panel_panel->setPort(2,rdairplay_conf->port(RDAirPlayConf::SoundPanel3Channel)); + } + if((card=rdairplay_conf->card(RDAirPlayConf::SoundPanel4Channel))<0) { + panel_panel->setCard(3,panel_panel->card(RDAirPlayConf::SoundPanel1Channel)); + panel_panel->setPort(3,panel_panel->port(RDAirPlayConf::SoundPanel1Channel)); + } + else { + panel_panel->setCard(3,card); + panel_panel->setPort(3,rdairplay_conf->port(RDAirPlayConf::SoundPanel4Channel)); + } + if((card=rdairplay_conf->card(RDAirPlayConf::SoundPanel5Channel))<0) { + panel_panel->setCard(4,panel_panel->card(RDAirPlayConf::CueChannel)); + panel_panel->setPort(4,panel_panel->port(RDAirPlayConf::CueChannel)); + } + else { + panel_panel->setCard(4,card); + panel_panel->setPort(4,rdairplay_conf->port(RDAirPlayConf::SoundPanel5Channel)); + } + + // + // Calculate Valid Ports for Reading Meter Data (No Duplicates) + // + for(int i=4;i>=0;i--) { + meter_data_valid[i]=(panel_panel->card(i)>=0); + for(int j=0;jcard(i)==panel_panel->card(j))&& + (panel_panel->port(i)==panel_panel->port(j))) { + meter_data_valid[i]=false; + } + } + } + + // + // Set Fader Display Numbers + // + int next_output=1; + for(int i=0;icard(i)==panel_panel->card(j))&& + (panel_panel->port(i)==panel_panel->port(j))) { + unique=false; + output=panel_panel->outputText(j).toInt(); + } + } + if(unique) { + next_output++; + } + panel_panel->setOutputText(i,QString().sprintf("%d",output)); + } + + // + // Set RML Strings + // + panel_panel-> + setRmls(0,rdairplay_conf->startRml(RDAirPlayConf::SoundPanel1Channel), + rdairplay_conf->stopRml(RDAirPlayConf::SoundPanel1Channel)); + panel_panel-> + setRmls(1,rdairplay_conf->startRml(RDAirPlayConf::SoundPanel2Channel), + rdairplay_conf->stopRml(RDAirPlayConf::SoundPanel2Channel)); + panel_panel-> + setRmls(2,rdairplay_conf->startRml(RDAirPlayConf::SoundPanel3Channel), + rdairplay_conf->stopRml(RDAirPlayConf::SoundPanel3Channel)); + panel_panel-> + setRmls(3,rdairplay_conf->startRml(RDAirPlayConf::SoundPanel4Channel), + rdairplay_conf->stopRml(RDAirPlayConf::SoundPanel4Channel)); + panel_panel-> + setRmls(4,rdairplay_conf->startRml(RDAirPlayConf::SoundPanel5Channel), + rdairplay_conf->stopRml(RDAirPlayConf::SoundPanel5Channel)); + panel_panel->setSvcName(rdairplay_conf->defaultSvc()); + connect(rdripc,SIGNAL(userChanged()),panel_panel,SLOT(changeUser())); + connect(panel_master_timer,SIGNAL(timeout()), + panel_panel,SLOT(tickClock())); + } + + // + // Audio Meter + // + panel_stereo_meter=new RDStereoMeter(this,"panel_stereo_meter"); + panel_stereo_meter-> + setGeometry(20, + sizeHint().height()-panel_stereo_meter->sizeHint().height()-7, + panel_stereo_meter->sizeHint().width(), + panel_stereo_meter->sizeHint().height()); + panel_stereo_meter->setMode(RDSegMeter::Peak); + panel_stereo_meter->setFocusPolicy(QWidget::NoFocus); + if(panel_config->useStreamMeters()) { + panel_stereo_meter->hide(); + } + + // + // Empty Cart + // + panel_empty_cart=new RDEmptyCart(this); + panel_empty_cart->setGeometry(373,sizeHint().height()-52,32,32); + if(!rdstation_conf->enableDragdrop()) { + panel_empty_cart->hide(); + } + + rdripc->connectHost("localhost",RIPCD_TCP_PORT,panel_config->password()); + + // + // Signal Handlers + // + signal(SIGCHLD,SigHandler); +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(935,738); +} + + +void MainWidget::rmlReceivedData(RDMacro *rml) +{ + RunLocalMacros(rml); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::userData() +{ + if(rduser!=NULL) { + delete rduser; + } + rduser=new RDUser(rdripc->user()); + SetCaption(); + rdripc->sendOnairFlag(); +} + + +void MainWidget::meterData() +{ +#ifdef SHOW_METER_SLOTS + printf("meterData()\n"); +#endif + double ratio[2]={0.0,0.0}; + short level[2]; + + for(int i=0;i + outputMeterUpdate(panel_panel->card(i),panel_panel->port(i),level); + for(int j=0;j<2;j++) { + ratio[j]+=pow(10.0,((double)level[j])/1000.0); + } + } + } + panel_stereo_meter->setLeftPeakBar((int)(log10(ratio[0])*1000.0)); + panel_stereo_meter->setRightPeakBar((int)(log10(ratio[1])*1000.0)); +} + + +void MainWidget::masterTimerData() +{ +} + + +void MainWidget::closeEvent(QCloseEvent *e) +{ + panel_db->removeDatabase(panel_config->mysqlDbname()); + exit(0); +} + + +void MainWidget::RunLocalMacros(RDMacro *rml) +{ +} + + +void MainWidget::SetCaption() +{ + setCaption(QString("RDPanel")+" v"+VERSION+" - "+tr("Station")+": "+ + panel_config->stationName()+", "+tr("User")+": "+ + rdripc->user()); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(),"."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rdpanel_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} diff --git a/rdpanel/rdpanel.h b/rdpanel/rdpanel.h new file mode 100644 index 00000000..34169482 --- /dev/null +++ b/rdpanel/rdpanel.h @@ -0,0 +1,86 @@ +// rdpanel.h +// +// A Dedicated Cart Wall Utility for Rivendell. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rdpanel.h,v 1.16.4.1 2013/12/30 21:11:59 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDPANEL_H +#define RDPANEL_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// +// Settings +// +#define MASTER_TIMER_INTERVAL 100 +#define METER_INTERVAL 50 +#define RDPANEL_PANEL_BUTTON_ROWS 7 +#define RDPANEL_PANEL_BUTTON_COLUMNS 9 +#define RDPANEL_USAGE "\n" + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void userData(); + void masterTimerData(); + void meterData(); + void rmlReceivedData(RDMacro *rml); + + protected: + void closeEvent(QCloseEvent *e); + + private: + void RunLocalMacros(RDMacro *rml); + void SetCaption(); + RDConfig *panel_config; + QSqlDatabase *panel_db; + QTimer *panel_master_timer; + RDCae *panel_cae; + RDStereoMeter *panel_stereo_meter; + RDSoundPanel *panel_panel; + RDEventPlayer *panel_player; + bool meter_data_valid[PANEL_MAX_OUTPUTS]; + QPixmap *lib_rivendell_map; + QString panel_filter; + QString panel_group; + QString panel_schedcode; + QPixmap *panel_skin_pixmap; + RDEmptyCart *panel_empty_cart; +}; + + +#endif // RDPANEL_H diff --git a/rdpanel/rdpanel.pro b/rdpanel/rdpanel.pro new file mode 100644 index 00000000..277305bf --- /dev/null +++ b/rdpanel/rdpanel.pro @@ -0,0 +1,36 @@ +# rdairplay.pro +# +# The QMake project file for RDPanel. +# +# (C) Copyright 2003-2007 Fred Gleason +# +# $Id: rdpanel.pro,v 1.3.8.1 2013/01/01 21:36:32 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +x11 { + SOURCES += rdpanel.cpp +} + +x11 { + HEADERS += rdpanel.h +} + +TRANSLATIONS += rdpanel_cs.ts +TRANSLATIONS += rdpanel_de.ts +TRANSLATIONS += rdpanel_es.ts +TRANSLATIONS += rdpanel_fr.ts +TRANSLATIONS += rdpanel_pt_BR.ts diff --git a/rdpanel/rdpanel_cs.ts b/rdpanel/rdpanel_cs.ts new file mode 100644 index 00000000..d8bf4030 --- /dev/null +++ b/rdpanel/rdpanel_cs.ts @@ -0,0 +1,21 @@ + + + MainWidget + + rdpanel : + rdpanel: + + + Can't Connect + Nelze spojit + + + Station + + + + User + + + + diff --git a/rdpanel/rdpanel_de.ts b/rdpanel/rdpanel_de.ts new file mode 100644 index 00000000..59b1618d --- /dev/null +++ b/rdpanel/rdpanel_de.ts @@ -0,0 +1,21 @@ + + + MainWidget + + rdpanel : + + + + Can't Connect + + + + Station + + + + User + + + + diff --git a/rdpanel/rdpanel_es.ts b/rdpanel/rdpanel_es.ts new file mode 100644 index 00000000..62cb90b8 --- /dev/null +++ b/rdpanel/rdpanel_es.ts @@ -0,0 +1,21 @@ + + + MainWidget + + rdpanel : + rdpanel : + + + Can't Connect + No puedo conectarme + + + Station + + + + User + + + + diff --git a/rdpanel/rdpanel_fr.ts b/rdpanel/rdpanel_fr.ts new file mode 100644 index 00000000..59b1618d --- /dev/null +++ b/rdpanel/rdpanel_fr.ts @@ -0,0 +1,21 @@ + + + MainWidget + + rdpanel : + + + + Can't Connect + + + + Station + + + + User + + + + diff --git a/rdpanel/rdpanel_pt_BR.ts b/rdpanel/rdpanel_pt_BR.ts new file mode 100644 index 00000000..59b1618d --- /dev/null +++ b/rdpanel/rdpanel_pt_BR.ts @@ -0,0 +1,21 @@ + + + MainWidget + + rdpanel : + + + + Can't Connect + + + + Station + + + + User + + + + diff --git a/rdrepld-suse.in b/rdrepld-suse.in new file mode 100644 index 00000000..59b839f9 --- /dev/null +++ b/rdrepld-suse.in @@ -0,0 +1,147 @@ +#! /bin/sh +## +## A Rivendell init script for LSB-compliant Linux systems. +## +## (C) Copyright 2010 Fred Gleason +## +## $Id: rdrepld-suse.in,v 1.3 2010/12/16 13:15:37 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of version 2 of the GNU General Public License as +## published by the Free Software Foundation; +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, +## Boston, MA 02111-1307 USA +## + +# chkconfig: 35 66 34 +# description: Rivendell replication daemon +# config: /etc/rc.conf + +### BEGIN INIT INFO +# Provides: rdrepld +# Required-Start: rivendell +# Required-Stop: rivendell +# Default-Start: 2 3 5 +# Default-Stop: 0 1 6 +# Description: Start the Rivendell replication daemon +### END INIT INFO + + +function StartDaemons { + @LOCAL_PREFIX@/bin/rdrepld 2> /dev/null +} + + +function StopDaemons { + if [ -f /var/run/rivendell/rdrepld.pid ] ; then + kill `cat /var/run/rivendell/rdrepld.pid` > /dev/null 2> /dev/null + fi + sleep 2 +} + +# Set path for script functions +export PATH=$PATH:/usr/local/bin:/usr/local/sbin + +# +# If the LSB Init functions exist, use them, otherwise roll our own +# +if test -f /lib/lsb/init-functions ; then + . /lib/lsb/init-functions +else + function log_success_msg() { + echo "$1 ... done." + } + function log_failure_msg() { + echo "$1 ... done." + } +fi + +# Check for missing binaries +if [ ! -x @LOCAL_PREFIX@/bin/rdrepld ] ; then + echo "rdrepld not installed" + exit 5 +fi + +# Check for existence of needed config file and read it +if [ ! -r /etc/rd.conf ] ; then + echo "Missing /etc/rd.conf" + exit 6 +fi + + +case "$1" in + start) + $0 silent-status + if test $? -eq 3 ; then + StartDaemons + fi + $0 silent-status + if test $? -eq 0 ; then + log_success_msg "Starting Rivendell replication daemon" + exit 0 + else + log_failure_msg "Starting Rivendell replication daemon" + exit 1 + fi + ;; + stop) + StopDaemons + $0 silent-status + if test $? -eq 0 ; then + log_failure_msg "Stopping Rivendell replication daemon" + exit 1 + else + log_success_msg "Stopping Rivendell replication daemon" + exit 0 + fi + ;; + restart) + $0 silent-status + if test $? -eq 0 ; then + $0 stop + fi + $0 silent-status + if test $? -eq 0 ; then + exit 1 + fi + $0 start + $0 silent-status + if test $? -eq 0 ; then + exit 0 + fi + exit 1 + ;; + force-reload) + $0 restart + ;; + status) + $0 silent-status + EXIT_CODE=$? + if test $EXIT_CODE -eq 0 ; then + echo "Rivendell replication daemon running." + else + echo "Rivendell replication daemon stopped." + fi + exit $EXIT_CODE + ;; + silent-status) + if test -f /var/run/rivendell/rdrepld.pid ; then + if test -d /proc/`cat /var/run/rivendell/rdrepld.pid` ; then + exit 0 + fi + fi + exit 3 + ;; + *) + echo "Usage: $0 {start|stop|restart|force-reload|status}" + exit 1 + ;; +esac diff --git a/rdrepld/Makefile.am b/rdrepld/Makefile.am new file mode 100644 index 00000000..7a263bb5 --- /dev/null +++ b/rdrepld/Makefile.am @@ -0,0 +1,45 @@ +## automake.am +## +## rdrepld/ Makefile.am for Rivendell +## +## (C) Copyright 2010 Fred Gleason +## +## $Id: Makefile.am,v 1.2 2010/07/29 19:32:37 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# QT's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rdrepld +dist_rdrepld_SOURCES = globals.h\ + rdrepld.cpp rdrepld.h \ + replconfig.cpp replconfig.h\ + replfactory.cpp replfactory.h\ + citadelxds.cpp citadelxds.h +nodist_rdrepld_SOURCES = moc_rdrepld.cpp +rdrepld_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +CLEANFILES = *~ moc_* +DISTCLEANFILES = moc_* +MAINTAINERCLEANFILES = *~ Makefile.in configure aclocal.m4 moc_* *.tar.gz diff --git a/rdrepld/citadelxds.cpp b/rdrepld/citadelxds.cpp new file mode 100644 index 00000000..3ec2d629 --- /dev/null +++ b/rdrepld/citadelxds.cpp @@ -0,0 +1,464 @@ +// citadelxds.cpp +// +// Replicator implementation for the Citadel XDS Portal +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: citadelxds.cpp,v 1.6 2012/03/02 22:33:51 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define RD_MAX_CART_NUMBER 999999 + +CitadelXds::CitadelXds(ReplConfig *config) + : ReplFactory(config) +{ + QString sql; + RDSqlQuery *q; + + sql="select LAST_ISCI_XREFERENCE from VERSION"; + q=new RDSqlQuery(sql); + if(q->first()) { + xds_isci_datetime=q->value(0).toDateTime(); + } + delete q; +} + + +void CitadelXds::startProcess() +{ + CheckIsciXreference(); + CheckCarts(); +} + + +bool CitadelXds::processCart(const unsigned cartnum) +{ + QString sql; + RDSqlQuery *q; + bool ret=false; + + sql=QString().sprintf("select FILENAME from ISCI_XREFERENCE \ + where (CART_NUMBER=%u)&&(LATEST_DATE>=now())&&\ + ((TYPE=\"R\")||(TYPE=\"B\"))",cartnum); + q=new RDSqlQuery(sql); + if(q->first()) { + ret=PostCut(RDCut::cutName(cartnum,1),q->value(0).toString()); + } + delete q; + return ret; +} + + +void CitadelXds::CheckIsciXreference() +{ + QString sql; + RDSqlQuery *q; + + QFileInfo *fi=new QFileInfo(rdsystem->isciXreferencePath()); + if(fi->exists()) { + if(fi->lastModified()>xds_isci_datetime) { + if(LoadIsciXreference(rdsystem->isciXreferencePath())) { + sql="update VERSION set LAST_ISCI_XREFERENCE=now()"; + q=new RDSqlQuery(sql); + delete q; + xds_isci_datetime=QDateTime(QDate::currentDate(),QTime::currentTime()); + PurgeCuts(); + } + } + } + else { + rdconfig->log("rdrepld",RDConfig::LogErr, + QString().sprintf("unable to load ISCI cross reference file \"%s\"", + (const char *)rdsystem->isciXreferencePath())); + } + delete fi; +} + + +bool CitadelXds::LoadIsciXreference(const QString &filename) +{ + FILE *f=NULL; + char line[1024]; + QString sql; + RDSqlQuery *q; + RDStringList fields; + unsigned cartnum; + QStringList datelist; + QDate date; + bool ok=false; + unsigned linenum=3; + + if((f=fopen(filename,"r"))==NULL) { + rdconfig->log("rdrepld",RDConfig::LogErr, + QString().sprintf("unable to load ISCI cross reference file \"%s\" [%s]", + (const char *)rdsystem->isciXreferencePath(), + strerror(errno))); + return false; + } + + // + // Purge Old Data + // + sql="delete from ISCI_XREFERENCE"; + q=new RDSqlQuery(sql); + delete q; + + // + // Skip Header + // + fgets(line,1024,f); + fgets(line,1024,f); + + // + // Load Records + // + while(fgets(line,1024,f)!=NULL) { + fields=fields.split(",",line,"\""); + if(fields.size()==9) { + for(unsigned i=0;ilog("rdrepld",RDConfig::LogWarning,QString(). + sprintf("invalid date in line %d of \"%s\"", + linenum,(const char *)filename)); + } + } + else { + rdconfig->log("rdrepld",RDConfig::LogWarning,QString(). + sprintf("invalid FILENAME field \"%s\" in line %d of \"%s\"", + (const char *)fields[8],linenum,(const char *)filename)); + } + } + else { + rdconfig->log("rdrepld",RDConfig::LogWarning,QString(). + sprintf("invalid date in line %d of \"%s\"", + linenum,(const char *)filename)); + } + } + else { + rdconfig->log("rdrepld",RDConfig::LogDebug,QString(). + sprintf("missing/invalid cart number in line %d of \"%s\"", + linenum,(const char *)filename)); + } + } + else { + rdconfig->log("rdrepld",RDConfig::LogWarning,QString(). + sprintf("line %d malformed in \"%s\"", + linenum,(const char *)filename)); + } + linenum++; + } + + // + // Clean Up + // + rdconfig->log("rdrepld",RDConfig::LogInfo, + QString().sprintf("loaded ISCI cross reference file \"%s\"", + (const char *)rdsystem->isciXreferencePath())); + fclose(f); + return true; +} + + +bool CitadelXds::ValidateFilename(const QString &filename) +{ + bool ret=true; + + // + // List of illegal characters taken from 'Illegal Characters4.doc' + // from Citadel + // + ret=ret&&(filename.find(" ")<0); + ret=ret&&(filename.find("\"")<0); + ret=ret&&(filename.find("%")<0); + ret=ret&&(filename.find("*")<0); + ret=ret&&(filename.find("+")<0); + ret=ret&&(filename.find("/")<0); + ret=ret&&(filename.find(":")<0); + ret=ret&&(filename.find(";")<0); + ret=ret&&(filename.find("<")<0); + ret=ret&&(filename.find("=")<0); + ret=ret&&(filename.find(">")<0); + ret=ret&&(filename.find("?")<0); + ret=ret&&(filename.find("@")<0); + ret=ret&&(filename.find("[")<0); + ret=ret&&(filename.find("\\")<0); + ret=ret&&(filename.find("]")<0); + ret=ret&&(filename.find("^")<0); + ret=ret&&(filename.find("{")<0); + ret=ret&&(filename.find("|")<0); + ret=ret&&(filename.find("}")<0); + + return ret; +} + + +void CitadelXds::CheckCarts() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + RDSqlQuery *q2; + QString now=QDateTime(QDate::currentDate(),QTime::currentTime()).addDays(-6). + toString("yyyy-MM-dd hh:mm:ss"); + + // + // Generate Update List + // + sql="select CART_NUMBER,FILENAME from ISCI_XREFERENCE \ + where (LATEST_DATE>=now())&&((TYPE=\"R\")||(TYPE=\"B\"))"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("select REPL_CART_STATE.ID from \ + REPL_CART_STATE left join CUTS \ + on REPL_CART_STATE.CART_NUMBER=CUTS.CART_NUMBER \ + where (CUTS.ORIGIN_DATETIME\"%s\")&&\ + (REPL_CART_STATE.REPOST=\"N\")", + (const char *)RDEscapeString(config()->name()), + q->value(0).toUInt(), + (const char *)RDEscapeString(q->value(1).toString()), + (const char *)now); + q1=new RDSqlQuery(sql); + if(!q1->first()) { + if(PostCut(RDCut::cutName(q->value(0).toUInt(),1), + q->value(1).toString())) { + sql=QString().sprintf("select ID from REPL_CART_STATE where \ + (REPLICATOR_NAME=\"%s\")&&\ + (CART_NUMBER=%u)&&\ + (POSTED_FILENAME=\"%s\")", + (const char *)RDEscapeString(config()->name()), + q->value(0).toUInt(), + (const char *)RDEscapeString(q->value(1). + toString())); + q2=new RDSqlQuery(sql); + if(q2->first()) { + sql=QString().sprintf("update REPL_CART_STATE set\ + ITEM_DATETIME=now(),\ + REPOST=\"N\" where \ + (REPLICATOR_NAME=\"%s\")&&\ + (CART_NUMBER=%u)&&\ + (POSTED_FILENAME=\"%s\")", + (const char *)RDEscapeString(config()->name()), + q->value(0).toUInt(), + (const char *)RDEscapeString(q->value(1). + toString())); + } + else { + sql=QString().sprintf("insert into REPL_CART_STATE set \ + ITEM_DATETIME=now(),\ + REPOST=\"N\",\ + REPLICATOR_NAME=\"%s\",\ + CART_NUMBER=%u,\ + POSTED_FILENAME=\"%s\"", + (const char *)RDEscapeString(config()->name()), + q->value(0).toUInt(), + (const char *)RDEscapeString(q->value(1). + toString())); + } + delete q2; + q2=new RDSqlQuery(sql); + delete q2; + } + } + delete q1; + } + delete q; +} + + +bool CitadelXds::PostCut(const QString &cutname,const QString &filename) +{ + // + // Export File + // + RDAudioConvert::ErrorCode conv_err; + RDUpload::ErrorCode upload_err; + float speed_ratio=1.0; + RDCut *cut=new RDCut(cutname); + if(!cut->exists()) { + delete cut; + return false; + } + if(cut->length()==0) { + delete cut; + return true; + } + RDCart *cart=new RDCart(cut->cartNumber()); + if(cart->enforceLength()) { + speed_ratio=(float)cut->length()/(float)cart->forcedLength(); + } + RDSettings *settings=new RDSettings(); + QString tempfile=RDTempDir()+"/"+filename; + RDAudioConvert *conv=new RDAudioConvert(rdconfig->stationName()); + conv->setSourceFile(RDCut::pathName(cutname)); + conv->setDestinationFile(tempfile); + conv->setRange(cut->startPoint(),cut->endPoint()); + conv->setSpeedRatio(speed_ratio); + settings->setFormat(config()->format()); + settings->setChannels(config()->channels()); + settings->setSampleRate(config()->sampleRate()); + settings->setBitRate(config()->bitRate()); + settings->setQuality(config()->quality()); + settings->setNormalizationLevel(config()->normalizeLevel()/1000); + conv->setDestinationSettings(settings); + delete cart; + delete cut; + switch(conv_err=conv->convert()) { + case RDAudioConvert::ErrorOk: + break; + + default: + rdconfig->log("rdrepld",RDConfig::LogErr, + QString().sprintf("CitadelXds: audio conversion failed: %s, cutname: %s", + (const char *)RDAudioConvert::errorText(conv_err), + (const char *)cutname)); + delete conv; + delete settings; + return false; + } + delete conv; + delete settings; + + // + // Upload File + // + RDUpload *upload=new RDUpload(rdconfig->stationName()); + upload->setSourceFile(tempfile); + upload->setDestinationUrl(config()->url()+"/"+filename); + switch(upload_err=upload->runUpload(config()->urlUsername(), + config()->urlPassword(), + rdconfig->logXloadDebugData())) { + case RDUpload::ErrorOk: + break; + + default: + rdconfig->log("rdrepld",RDConfig::LogErr, + QString().sprintf("CitadelXds: audio upload failed: %s", + (const char *)RDUpload::errorText(upload_err))); + unlink(tempfile); + delete upload; + return false; + } + unlink(tempfile); + delete upload; + rdconfig->log("rdrepld",RDConfig::LogInfo, + QString().sprintf("CitadelXds: uploaded cut %s to %s/%s", + (const char *)cutname, + (const char *)config()->url(), + (const char *)filename)); + + return true; +} + + +void CitadelXds::PurgeCuts() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + RDSqlQuery *q2; + RDDelete *conv; + RDDelete::ErrorCode conv_err; + + sql=QString().sprintf("select ID,POSTED_FILENAME from REPL_CART_STATE \ + where REPLICATOR_NAME=\"%s\"", + (const char *)RDEscapeString(config()->name())); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString(). + sprintf("select ID from ISCI_XREFERENCE where FILENAME=\"%s\"", + (const char *)RDEscapeString(q->value(1).toString())); + q1=new RDSqlQuery(sql); + if(!q1->first()) { + QString path=config()->url(); + if(path.right(1)!="/") { + path+="/"; + } + QUrl url(path+q->value(1).toString()); + conv=new RDDelete(); + conv->setTargetUrl(url); + if((conv_err=conv->runDelete(config()->urlUsername(), + config()->urlPassword(), + rdconfig->logXloadDebugData()))== + RDDelete::ErrorOk) { + sql=QString().sprintf("delete from REPL_CART_STATE where ID=%d", + q->value(0).toInt()); + q2=new RDSqlQuery(sql); + delete q2; + rdconfig->log("rdrepld",RDConfig::LogInfo, + QString().sprintf("purged \"%s\" for replicator \"%s\"", + (const char *)url.toString(), + (const char *)config()->name())); + } + else { + rdconfig->log("rdrepld",RDConfig::LogErr, + QString().sprintf("unable to delete \"%s\" for replicator \"%s\" [%s]", + (const char *)url.toString(), + (const char *)config()->name(), + (const char *)RDDelete::errorText(conv_err))); + } + delete conv; + } + delete q1; + } + delete q; +} diff --git a/rdrepld/citadelxds.h b/rdrepld/citadelxds.h new file mode 100644 index 00000000..9f8dc896 --- /dev/null +++ b/rdrepld/citadelxds.h @@ -0,0 +1,46 @@ +// citadelxds.h +// +// Replicator implementation for the Citadel XDS Portal +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: citadelxds.h,v 1.3 2011/10/17 18:48:41 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef CITADELXDS_H +#define CITADELXDS_H + +#include + +class CitadelXds : public ReplFactory +{ + public: + CitadelXds(ReplConfig *config); + void startProcess(); + bool processCart(const unsigned cartnum); + + private: + void CheckIsciXreference(); + bool LoadIsciXreference(const QString &filename); + bool ValidateFilename(const QString &filename); + void CheckCarts(); + bool PostCut(const QString &cutname,const QString &filename); + void PurgeCuts(); + QDateTime xds_isci_datetime; +}; + + +#endif // CITADELXDS_H diff --git a/rdrepld/globals.h b/rdrepld/globals.h new file mode 100644 index 00000000..56411ee2 --- /dev/null +++ b/rdrepld/globals.h @@ -0,0 +1,32 @@ +// globals.h +// +// The Rivendell Replicator Daemon Global Definitions +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: globals.h,v 1.2 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef GLOBALS_H +#define GLOBALS_H + +#include +#include + +extern RDConfig *rdconfig; +extern RDSystem *rdsystem; + +#endif // GLOBALS_H diff --git a/rdrepld/rdrepld.cpp b/rdrepld/rdrepld.cpp new file mode 100644 index 00000000..5a3d0b20 --- /dev/null +++ b/rdrepld/rdrepld.cpp @@ -0,0 +1,301 @@ +// rdcatchd.cpp +// +// The Rivendell Replicator Daemon +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: rdrepld.cpp,v 1.4 2011/06/21 22:20:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +RDConfig *rdconfig; +RDSystem *rdsystem; + +void SigHandler(int signum) +{ + pid_t local_pid; + + switch(signum) { + case SIGINT: + case SIGTERM: + RDDeletePid(RD_PID_DIR,"rdrepld.pid"); + exit(0); + break; + + case SIGCHLD: + local_pid=waitpid(-1,NULL,WNOHANG); + while(local_pid>0) { + local_pid=waitpid(-1,NULL,WNOHANG); + } + signal(SIGCHLD,SigHandler); + return; + } +} + + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + bool skip_db_check=false; + unsigned schema=0; + + // + // Load the config + // + rdconfig=new RDConfig(); + rdconfig->load(); + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdrepld",RDREPLD_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + } + + // + // Make sure we're the only instance running + // + if(RDCheckDaemon(RD_RDREPLD_PID)) { + printf("rdrepld: aborting - multiple instances not allowed"); + exit(1); + } + + // + // Initialize Data Structures + // + debug=false; + + // + // Calculate Temporary Directory + // + repl_temp_dir=RDTempDir(); + + // + // Open Database + // + QString err (tr("ERROR rdrepld aborting - ")); + + repl_db=RDInitDb(&schema,&err); + if(!repl_db) { + printf(err.ascii()); + exit(1); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr,"rdrepld: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + connect (RDDbStatus(),SIGNAL(logText(RDConfig::LogPriority,const QString &)), + this,SLOT(log(RDConfig::LogPriority,const QString &))); + + // + // System Configuration + // + rdsystem=new RDSystem(); + + // + // Station Configuration + // + repl_station=new RDStation(rdconfig->stationName()); + + // + // Detach + // + if(qApp->argc()==1) { + RDDetach(rdconfig->logCoreDumpDirectory()); + } + else { + debug=true; + } + + ::signal(SIGINT,SigHandler); + ::signal(SIGTERM,SigHandler); + ::signal(SIGCHLD,SigHandler); + if(!RDWritePid(RD_PID_DIR,"rdrepld.pid")) { + printf("rdrepld: aborting - can't write pid file\n"); + exit(1); + } + + // + // Start the Main Loop + // + repl_loop_timer=new QTimer(this,"repl_loop_timer"); + connect(repl_loop_timer,SIGNAL(timeout()),this,SLOT(mainLoop())); + repl_loop_timer->start(RD_RDREPL_SCAN_INTERVAL,true); + + rdconfig->log("rdrepld",RDConfig::LogNotice,"started"); +} + + +void MainObject::mainLoop() +{ + LoadReplicators(); + ProcessCarts(); + FreeReplicators(); + repl_loop_timer->start(RD_RDREPL_SCAN_INTERVAL,true); +} + + +void MainObject::log(RDConfig::LogPriority prio,const QString &msg) +{ + rdconfig->log("rdrepld",prio,msg); +} + + +void MainObject::ProcessCarts() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + RDSqlQuery *q2; + QString repl_name; + QString where; + bool stale; + + for(unsigned i=0;iconfig()->name(); + sql=QString(). + sprintf("select GROUP_NAME from REPLICATOR_MAP \ + where REPLICATOR_NAME=\"%s\"", + (const char *)RDEscapeString(repl_name)); + q=new RDSqlQuery(sql); + while(q->next()) { + where+=QString(). + sprintf("(GROUP_NAME=\"%s\")||", + (const char *)RDEscapeString(q->value(0).toString())); + } + delete q; + where=where.left(where.length()-2); + sql=QString().sprintf("select NUMBER,TYPE,METADATA_DATETIME \ + from CART where %s", + (const char *)where); + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("select ID,ITEM_DATETIME from REPL_CART_STATE \ + where (REPLICATOR_NAME=\"%s\")&&\ + (CART_NUMBER=%u)", + (const char *)RDEscapeString(repl_name), + q->value(0).toUInt()); + q1=new RDSqlQuery(sql); + if(q1->first()) { + stale=q->value(2).toDateTime()>q1->value(1).toDateTime(); + } + else { + stale=true; + } + if(stale) { + if(repl_replicators[i]->processCart(q->value(0).toUInt())) { + if(q1->isValid()) { + sql=QString().sprintf("update REPL_CART_STATE set \ + ITEM_DATETIME=now() where ID=%u", + q1->value(0).toUInt()); + } + else { + sql=QString().sprintf("insert into REPL_CART_STATE set \ + REPLICATOR_NAME=\"%s\",\ + CART_NUMBER=%u,\ + ITEM_DATETIME=now()", + (const char *)RDEscapeString(repl_name), + q->value(0).toUInt()); + } + q2=new RDSqlQuery(sql); + delete q2; + } + } + delete q1; + } + delete q; + } +} + + +void MainObject::LoadReplicators() +{ + QString sql; + RDSqlQuery *q; + ReplConfig *config; + + sql=QString(). + sprintf("select NAME,TYPE_ID,FORMAT,CHANNELS,SAMPRATE,\ + BITRATE,QUALITY,URL,URL_USERNAME,URL_PASSWORD,\ + ENABLE_METADATA,NORMALIZATION_LEVEL from \ + REPLICATORS where STATION_NAME=\"%s\"", + (const char *)RDEscapeString(rdconfig->stationName())); + q=new RDSqlQuery(sql); + while(q->next()) { + config=new ReplConfig(); + config->setName(q->value(0).toString()); + config->setType((RDReplicator::Type)q->value(1).toUInt()); + config->setFormat((RDSettings::Format)q->value(2).toUInt()); + config->setChannels(q->value(3).toUInt()); + config->setSampleRate(q->value(4).toUInt()); + config->setBitRate(q->value(5).toUInt()); + config->setQuality(q->value(6).toUInt()); + config->setUrl(q->value(7).toString()); + config->setUrlUsername(q->value(8).toString()); + config->setUrlPassword(q->value(9).toString()); + config->setEnableMetadata(RDBool(q->value(10).toString())); + config->setNormalizeLevel(q->value(11).toInt()); + switch(config->type()) { + case RDReplicator::TypeCitadelXds: + repl_replicators.push_back(new CitadelXds(config)); + break; + + case RDReplicator::TypeLast: + break; + } + repl_replicators.back()->startProcess(); + } + delete q; +} + + +void MainObject::FreeReplicators() +{ + for(unsigned i=0;i +// +// $Id: rdrepld.h,v 1.2 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDREPLD_H +#define RDREPLD_H + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#define RDREPLD_USAGE "[-d][--event-id=]\n\nOptions:\n\n-d\n Set 'debug' mode, causing rdrepld(8) to stay in the foreground\n and print debugging info on standard output.\n\n" +#define RD_RDREPLD_PID "rdrepl.pid" +#define RD_RDREPL_SCAN_INTERVAL 10000 + +class MainObject : public QObject +{ + Q_OBJECT + public: + MainObject(QObject *parent=0,const char *name=0); + + private slots: + void mainLoop(); + void log(RDConfig::LogPriority prio,const QString &line); + + private: + void ProcessCarts(); + void LoadReplicators(); + void FreeReplicators(); + QTimer *repl_loop_timer; + QString repl_temp_dir; + RDStation *repl_station; + QSqlDatabase *repl_db; + std::vector repl_replicators; + bool debug; +}; + + +#endif // RDREPLD_H diff --git a/rdrepld/replconfig.cpp b/rdrepld/replconfig.cpp new file mode 100644 index 00000000..f15112ec --- /dev/null +++ b/rdrepld/replconfig.cpp @@ -0,0 +1,216 @@ +// replconfig.cpp +// +// A container class for a Rivendell replication configuration +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: replconfig.cpp,v 1.2 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +ReplConfig::ReplConfig() +{ + clear(); +} + + +RDReplicator::Type ReplConfig::type() const +{ + return repl_type; +} + + +void ReplConfig::setType(RDReplicator::Type type) +{ + repl_type=type; +} + + +QString ReplConfig::name() const +{ + return repl_name; +} + + +void ReplConfig::setName(const QString &str) +{ + repl_name=str; +} + + +QString ReplConfig::stationName() const +{ + return repl_station_name; +} + + +void ReplConfig::setStationName(const QString &str) +{ + repl_station_name=str; +} + + +QString ReplConfig::description() const +{ + return repl_description; +} + + +void ReplConfig::setDescription(const QString &str) +{ + repl_description=str; +} + + +RDSettings::Format ReplConfig::format() const +{ + return repl_format; +} + + +void ReplConfig::setFormat(RDSettings::Format fmt) +{ + repl_format=fmt; +} + + +unsigned ReplConfig::channels() const +{ + return repl_channels; +} + + +void ReplConfig::setChannels(unsigned chans) +{ + repl_channels=chans; +} + + +unsigned ReplConfig::sampleRate() const +{ + return repl_sample_rate; +} + + +void ReplConfig::setSampleRate(unsigned rate) +{ + repl_sample_rate=rate; +} + + +unsigned ReplConfig::bitRate() const +{ + return repl_bit_rate; +} + + +void ReplConfig::setBitRate(unsigned rate) +{ + repl_bit_rate=rate; +} + + +unsigned ReplConfig::quality() const +{ + return repl_quality; +} + + +void ReplConfig::setQuality(unsigned qual) +{ + repl_quality=qual; +} + + +QString ReplConfig::url() const +{ + return repl_url; +} + + +void ReplConfig::setUrl(const QString &str) +{ + repl_url=str; +} + + +QString ReplConfig::urlUsername() const +{ + return repl_url_username; +} + + +void ReplConfig::setUrlUsername(const QString &str) +{ + repl_url_username=str; +} + + +QString ReplConfig::urlPassword() const +{ + return repl_url_password; +} + + +void ReplConfig::setUrlPassword(const QString &str) +{ + repl_url_password=str; +} + + +bool ReplConfig::enableMetadata() const +{ + return repl_enable_metadata; +} + + +void ReplConfig::setEnableMetadata(bool state) +{ + repl_enable_metadata=state; +} + + +int ReplConfig::normalizeLevel() const +{ + return repl_normalize_level; +} + + +void ReplConfig::setNormalizeLevel(int lvl) +{ + repl_normalize_level=lvl; +} + + +void ReplConfig::clear() +{ + repl_name=""; + repl_station_name=""; + repl_description=""; + repl_format=RDSettings::Pcm16; + repl_channels=2; + repl_sample_rate=RD_DEFAULT_SAMPLE_RATE; + repl_bit_rate=0; + repl_quality=0; + repl_url=""; + repl_url_username=""; + repl_url_password=""; + repl_enable_metadata=false; + repl_normalize_level=0; +} diff --git a/rdrepld/replconfig.h b/rdrepld/replconfig.h new file mode 100644 index 00000000..5dc93f77 --- /dev/null +++ b/rdrepld/replconfig.h @@ -0,0 +1,83 @@ +// replconfig.h +// +// A container class for a Rivendell replication configuration +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: replconfig.h,v 1.2 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef REPLCONFIG_H +#define REPLCONFIG_H + +#include + +#include +#include + +class ReplConfig +{ + public: + ReplConfig(); + RDReplicator::Type type() const; + void setType(RDReplicator::Type type); + QString name() const; + void setName(const QString &str); + QString stationName() const; + void setStationName(const QString &str); + QString description() const; + void setDescription(const QString &str); + RDSettings::Format format() const; + void setFormat(RDSettings::Format fmt); + unsigned channels() const; + void setChannels(unsigned chans); + unsigned sampleRate() const; + void setSampleRate(unsigned rate); + unsigned bitRate() const; + void setBitRate(unsigned rate); + unsigned quality() const; + void setQuality(unsigned qual); + QString url() const; + void setUrl(const QString &str); + QString urlUsername() const; + void setUrlUsername(const QString &str); + QString urlPassword() const; + void setUrlPassword(const QString &str); + bool enableMetadata() const; + void setEnableMetadata(bool state); + int normalizeLevel() const; + void setNormalizeLevel(int lvl); + void clear(); + + private: + QString repl_name; + RDReplicator::Type repl_type; + QString repl_station_name; + QString repl_description; + RDSettings::Format repl_format; + unsigned repl_channels; + unsigned repl_sample_rate; + unsigned repl_bit_rate; + unsigned repl_quality; + QString repl_url; + QString repl_url_username; + QString repl_url_password; + bool repl_enable_metadata; + int repl_normalize_level; +}; + + +#endif // REPLCONFIG_H diff --git a/rdrepld/replfactory.cpp b/rdrepld/replfactory.cpp new file mode 100644 index 00000000..35196427 --- /dev/null +++ b/rdrepld/replfactory.cpp @@ -0,0 +1,40 @@ +// replfactory.cpp +// +// Virtual base class for replicator methods +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: replfactory.cpp,v 1.2 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +ReplFactory::ReplFactory(ReplConfig *config) +{ + repl_config=config; +} + + +ReplFactory::~ReplFactory() +{ + delete repl_config; +} + + +ReplConfig *ReplFactory::config() const +{ + return repl_config; +} diff --git a/rdrepld/replfactory.h b/rdrepld/replfactory.h new file mode 100644 index 00000000..ad1d2861 --- /dev/null +++ b/rdrepld/replfactory.h @@ -0,0 +1,43 @@ +// replfactory.h +// +// Virtual base class for replicator methods +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: replfactory.h,v 1.2 2010/07/29 19:32:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef REPLFACTORY_H +#define REPLFACTORY_H + +#include +#include + +class ReplFactory +{ + public: + ReplFactory(ReplConfig *config); + ~ReplFactory(); + ReplConfig *config() const; + virtual void startProcess()=0; + virtual bool processCart(const unsigned cartnum)=0; + + private: + ReplConfig *repl_config; +}; + + +#endif // REPLCONFIG_H diff --git a/rdselect/Makefile.am b/rdselect/Makefile.am new file mode 100644 index 00000000..15d6c370 --- /dev/null +++ b/rdselect/Makefile.am @@ -0,0 +1,73 @@ +## automake.am +## +## Automake.am for rivendell/rdselect +## +## (C) Copyright 2012 Fred Gleason +## +## $Id: Makefile.am,v 1.1.2.4 2013/01/01 21:36:32 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdselect_*.qm $(DESTDIR)$(prefix)/share/rivendell + chmod 4755 $(prefix)/bin/rdselect + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rdselect_*.qm + +all: + @QT_BIN@/lupdate rdselect.pro + @QT_BIN@/lrelease rdselect.pro + +bin_PROGRAMS = rdselect + +dist_rdselect_SOURCES = rdselect.cpp rdselect.h + +nodist_rdselect_SOURCES = moc_rdselect.cpp + +rdselect_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdselect.pro\ + rdselect_cs.ts\ + rdselect_de.ts\ + rdselect_es.ts\ + rdselect_fr.ts\ + rdselect_nb.ts\ + rdselect_nn.ts\ + rdselect_pt_BR.ts + +CLEANFILES = *~\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/rdselect/rdselect.cpp b/rdselect/rdselect.cpp new file mode 100644 index 00000000..ea057137 --- /dev/null +++ b/rdselect/rdselect.cpp @@ -0,0 +1,384 @@ +// rdselect.h +// +// System Selector for Rivendell +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: rdselect.cpp,v 1.1.2.9 2014/01/21 21:59:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +// +// Icons +// +#include "../icons/rivendell-22x22.xpm" +#include "../icons/greencheckmark.xpm" +#include "../icons/redx.xpm" + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + // + // Read Command Options + // + RDCmdSwitch *cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdselect","\n"); + delete cmd; + + // + // Read Configuration + // + monitor_config=new RDMonitorConfig(); + monitor_config->load(); + QDesktopWidget *dw=qApp->desktop(); + int width=sizeHint().width(); + int height=sizeHint().height(); + switch(monitor_config->position()) { + case RDMonitorConfig::UpperLeft: + setGeometry(0,RDMONITOR_HEIGHT,width,sizeHint().height()); + break; + + case RDMonitorConfig::UpperCenter: + setGeometry((dw->size().width()-width)/2,RDMONITOR_HEIGHT,width,height); + break; + + case RDMonitorConfig::UpperRight: + setGeometry(dw->size().width()-width,RDMONITOR_HEIGHT,width,height); + break; + + case RDMonitorConfig::LowerLeft: + setGeometry(0,dw->size().height()-height+RDMONITOR_HEIGHT,width,height); + break; + + case RDMonitorConfig::LowerCenter: + setGeometry((dw->size().width()-width)/2, + dw->size().height()-height+RDMONITOR_HEIGHT,width,height); + break; + + case RDMonitorConfig::LowerRight: + setGeometry(dw->size().width()-width, + dw->size().height()-height+RDMONITOR_HEIGHT,width,height); + break; + + case RDMonitorConfig::LastPosition: + break; + } + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont default_font("Helvetica",12,QFont::Normal); + default_font.setPixelSize(12); + qApp->setFont(default_font); + QFont button_font=QFont("Helvetica",12,QFont::Bold); + button_font.setPixelSize(12); + QFont label_font=QFont("Helvetica",16,QFont::Bold); + label_font.setPixelSize(16); + + // + // Create And Set Icons + // + login_rivendell_map=new QPixmap(rivendell_xpm); + setIcon(*login_rivendell_map); + setCaption(tr("RDSelect")+" v"+VERSION); + greencheckmark_map=new QPixmap(greencheckmark_xpm); + redx_map=new QPixmap(redx_xpm); + + // + // Load Configs + // + select_current_id=-1; + char target[1500]; + ssize_t n; + if((n=readlink(RD_CONF_FILE,target,1500))>0) { + target[n]=0; + } + else { + target[0]=0; + } + QDir config_dir(RD_DEFAULT_RDSELECT_DIR); + config_dir.setFilter(QDir::Files|QDir::Readable); + config_dir.setNameFilter("*.conf"); + select_filenames=config_dir.entryList(); + for(unsigned i=0;isetFilename(select_filenames[i]); + select_configs.back()->load(); + } + + // + // Current System Label + // + select_current_label=new QLabel(this); + select_current_label->setFont(label_font); + select_current_label->setAlignment(AlignCenter); + + // + // Selector Box + // + select_box=new QListBox(this); + select_box->setFont(default_font); + connect(select_box,SIGNAL(doubleClicked(QListBoxItem *)), + this,SLOT(doubleClickedData(QListBoxItem *))); + for(unsigned i=0;iinsertItem(select_configs[i]->label()); + } + select_label=new QLabel(select_box,tr("Available Systems"),this); + select_label->setFont(button_font); + + // + // Ok Button + // + ok_button=new QPushButton(this); + ok_button->setFont(button_font); + ok_button->setText(tr("Select")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setFont(button_font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + SetSystem(select_current_id); + SetCurrentItem(select_current_id); + select_box->clearSelection(); + + // + // Check for Root User + // + + setuid(geteuid()); // So the SETUID bit works as expected + if(getuid()!=0) { + QMessageBox::information(this,tr("RDSelect"), + tr("Only root can run this utility!")); + exit(256); + } +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(400,300); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::doubleClickedData(QListBoxItem *item) +{ + okData(); +} + + +void MainWidget::okData() +{ + if(RDModulesActive()) { + QMessageBox::information(this,tr("RDSelect"), + tr("One or more Rivendell modules are still open.")); + return; + } + + if(!VerifyShutdown()) { + return; + } + if(!Shutdown(select_current_id)) { + SetSystem(-1); + QMessageBox::warning(this,tr("RDSelect"), + tr("Unable to shutdown current configuration")+ + "\n["+strerror(errno)+"]."); + return; + } + if(!Startup(select_box->currentItem())) { + SetSystem(-1); + QMessageBox::warning(this,tr("RDSelect"), + tr("Unable to start up new configuration")); + } + SetSystem(select_box->currentItem()); + exit(0); +} + + +void MainWidget::cancelData() +{ + exit(0); +} + + +void MainWidget::resizeEvent(QResizeEvent *e) +{ + select_current_label->setGeometry(0,10,size().width(),21); + select_label->setGeometry(10,35,size().width()-20,20); + select_box->setGeometry(10,55,size().width()-20,size().height()-125); + ok_button->setGeometry(size().width()-180,size().height()-60,80,50); + cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +bool MainWidget::Shutdown(int id) +{ + RDConfig *conf=select_configs[id]; + + if(system("/etc/init.d/rivendell stop")!=0) { + return false; + } + system(QString("umount ")+conf->audioRoot()); + + return true; +} + + +bool MainWidget::Startup(int id) +{ + RDConfig *conf=select_configs[id]; + + if(!conf->audioStoreMountSource().isEmpty()) { + QString cmd=QString("mount"); + if(!conf->audioStoreMountType().isEmpty()) { + cmd+=" -t "+conf->audioStoreMountType(); + } + if(!conf->audioStoreMountOptions().isEmpty()) { + cmd+=" -o "+conf->audioStoreMountOptions(); + } + cmd+=" "+conf->audioStoreMountSource()+" "+ + conf->audioRoot(); + if(system(cmd)!=0) { + return false; + } + } + unlink(RD_CONF_FILE); + symlink(select_filenames[id],RD_CONF_FILE); + if(system("/etc/init.d/rivendell start")!=0) { + return false; + } + + return true; +} + + +void MainWidget::SetSystem(int id) +{ + QString text=tr("None"); + if(id>=0) { + text=select_configs[id]->label(); + } + select_current_label->setText(tr("Current System:")+" "+text); + select_current_id=id; +} + + +bool MainWidget::VerifyShutdown() const +{ + return true; +} + + +void MainWidget::SetCurrentItem(int id) +{ + QPixmap *pix=redx_map; + int schema=0; + bool db_ok=RDDbValid(select_configs[select_current_id],&schema); + bool snd_ok=RDAudioStoreValid(select_configs[select_current_id]); + + if(db_ok&(schema==RD_VERSION_DATABASE)&&snd_ok) { + pix=greencheckmark_map; + } + for(unsigned i=0;icount();i++) { + if((int)i==id) { + select_box->changeItem(*pix,select_configs[i]->label(),i); + } + else { + select_box->changeItem(select_configs[i]->label(),i); + } + } +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(), + "."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rdselect_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->show(); + return a.exec(); +} diff --git a/rdselect/rdselect.h b/rdselect/rdselect.h new file mode 100644 index 00000000..6832949f --- /dev/null +++ b/rdselect/rdselect.h @@ -0,0 +1,77 @@ +// rdselect.h +// +// System Selector for Rivendell +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: rdselect.h,v 1.1.2.3 2012/10/22 18:22:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDSELECT_H +#define RDSELECT_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void doubleClickedData(QListBoxItem *item); + void okData(); + void cancelData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + bool Shutdown(int id); + bool Startup(int id); + void SetSystem(int id); + bool VerifyShutdown() const; + void SetCurrentItem(int id); + std::vector select_configs; + QStringList select_filenames; + int select_current_id; + QLabel *select_current_label; + QLabel *select_label; + QListBox *select_box; + QPixmap *login_rivendell_map; + QPushButton *ok_button; + QPushButton *cancel_button; + QPixmap *greencheckmark_map; + QPixmap *redx_map; + RDMonitorConfig *monitor_config; +}; + + +#endif // RDLOGIN_H diff --git a/rdselect/rdselect.pro b/rdselect/rdselect.pro new file mode 100644 index 00000000..d58c1d50 --- /dev/null +++ b/rdselect/rdselect.pro @@ -0,0 +1,38 @@ +# rdselect.pro +# +# The QMake project file for RDSelect. +# +# (C) Copyright 2012 Fred Gleason +# +# $Id: rdselect.pro,v 1.1.2.2 2013/01/01 21:36:33 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +x11 { + SOURCES += rdselect.cpp +} + +x11 { + HEADERS += rdselect.h +} + +TRANSLATIONS += rdselect_cs.ts +TRANSLATIONS += rdselect_de.ts +TRANSLATIONS += rdselect_es.ts +TRANSLATIONS += rdselect_fr.ts +TRANSLATIONS += rdselect_nb.ts +TRANSLATIONS += rdselect_nn.ts +TRANSLATIONS += rdselect_pt_BR.ts diff --git a/rdselect/rdselect_cs.ts b/rdselect/rdselect_cs.ts new file mode 100644 index 00000000..634d4b37 --- /dev/null +++ b/rdselect/rdselect_cs.ts @@ -0,0 +1,45 @@ + + + MainWidget + + &Cancel + &Zrušit + + + RDSelect + RDSelect + + + None + Žádný + + + Current System: + Nynější sytém: + + + Available Systems + Dostupné sytémy + + + Select + Vybrat + + + Only root can run this utility! + Pouze superuživatel (root) může spouštět tento program! + + + Unable to shutdown current configuration + Nelze vypnout nynější nastavení + + + Unable to start up new configuration + Nelze spustit nové nastavení + + + One or more Rivendell modules are still open. + Jeden nebo více modulů Rivendell je stále ještě otevřeno. + + + diff --git a/rdselect/rdselect_de.ts b/rdselect/rdselect_de.ts new file mode 100644 index 00000000..89d1be35 --- /dev/null +++ b/rdselect/rdselect_de.ts @@ -0,0 +1,45 @@ + + + MainWidget + + &Cancel + + + + RDSelect + + + + None + + + + Current System: + + + + Available Systems + + + + Select + + + + Only root can run this utility! + + + + Unable to shutdown current configuration + + + + Unable to start up new configuration + + + + One or more Rivendell modules are still open. + + + + diff --git a/rdselect/rdselect_es.ts b/rdselect/rdselect_es.ts new file mode 100644 index 00000000..89d1be35 --- /dev/null +++ b/rdselect/rdselect_es.ts @@ -0,0 +1,45 @@ + + + MainWidget + + &Cancel + + + + RDSelect + + + + None + + + + Current System: + + + + Available Systems + + + + Select + + + + Only root can run this utility! + + + + Unable to shutdown current configuration + + + + Unable to start up new configuration + + + + One or more Rivendell modules are still open. + + + + diff --git a/rdselect/rdselect_fr.ts b/rdselect/rdselect_fr.ts new file mode 100644 index 00000000..89d1be35 --- /dev/null +++ b/rdselect/rdselect_fr.ts @@ -0,0 +1,45 @@ + + + MainWidget + + &Cancel + + + + RDSelect + + + + None + + + + Current System: + + + + Available Systems + + + + Select + + + + Only root can run this utility! + + + + Unable to shutdown current configuration + + + + Unable to start up new configuration + + + + One or more Rivendell modules are still open. + + + + diff --git a/rdselect/rdselect_nb.ts b/rdselect/rdselect_nb.ts new file mode 100644 index 00000000..89d1be35 --- /dev/null +++ b/rdselect/rdselect_nb.ts @@ -0,0 +1,45 @@ + + + MainWidget + + &Cancel + + + + RDSelect + + + + None + + + + Current System: + + + + Available Systems + + + + Select + + + + Only root can run this utility! + + + + Unable to shutdown current configuration + + + + Unable to start up new configuration + + + + One or more Rivendell modules are still open. + + + + diff --git a/rdselect/rdselect_nn.ts b/rdselect/rdselect_nn.ts new file mode 100644 index 00000000..89d1be35 --- /dev/null +++ b/rdselect/rdselect_nn.ts @@ -0,0 +1,45 @@ + + + MainWidget + + &Cancel + + + + RDSelect + + + + None + + + + Current System: + + + + Available Systems + + + + Select + + + + Only root can run this utility! + + + + Unable to shutdown current configuration + + + + Unable to start up new configuration + + + + One or more Rivendell modules are still open. + + + + diff --git a/rdselect/rdselect_pt_BR.ts b/rdselect/rdselect_pt_BR.ts new file mode 100644 index 00000000..89d1be35 --- /dev/null +++ b/rdselect/rdselect_pt_BR.ts @@ -0,0 +1,45 @@ + + + MainWidget + + &Cancel + + + + RDSelect + + + + None + + + + Current System: + + + + Available Systems + + + + Select + + + + Only root can run this utility! + + + + Unable to shutdown current configuration + + + + Unable to start up new configuration + + + + One or more Rivendell modules are still open. + + + + diff --git a/ripcd/Makefile.am b/ripcd/Makefile.am new file mode 100644 index 00000000..72a2c014 --- /dev/null +++ b/ripcd/Makefile.am @@ -0,0 +1,120 @@ +## automake.am +## +## Rivendell Interprocess Communication Daemon Makefile.am +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.43.8.10 2014/02/17 02:19:02 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + + +bin_PROGRAMS = ripcd + +dist_ripcd_SOURCES = acu1p.cpp acu1p.h\ + am16.cpp am16.h\ + bt10x1.cpp bt10x1.h\ + bt16x1.cpp bt16x1.h\ + bt16x2.cpp bt16x2.h\ + bt8x2.cpp bt8x2.h\ + btacs82.cpp btacs82.h\ + btsentinel4web.cpp btsentinel4web.h\ + btss124.cpp btss124.h\ + btss164.cpp btss164.h\ + btss42.cpp btss42.h\ + btss44.cpp btss44.h\ + btss82.cpp btss82.h\ + btsrc16.cpp btsrc16.h\ + btsrc8iii.cpp btsrc8iii.h\ + harlond.cpp harlond.h\ + livewire_lwrpaudio.cpp livewire_lwrpaudio.h\ + livewire_lwrpgpio.cpp livewire_lwrpgpio.h\ + livewire_mcastgpio.cpp livewire_mcastgpio.h\ + local_audio.cpp local_audio.h\ + local_gpio.cpp local_gpio.h\ + local_macros.cpp maint_routines.cpp\ + loaddrivers.cpp\ + quartz1.cpp quartz1.h\ + ripcd.cpp ripcd.h globals.h\ + ripcd_connection.cpp ripcd_connection.h\ + ripcd_socket.cpp ripcd_socket.h\ + sas32000.cpp sas32000.h\ + sas64000.cpp sas64000.h\ + sas64000gpi.cpp sas64000gpi.h\ + sasusi.cpp sasusi.h\ + starguide3.cpp starguide3.h\ + starguide_feed.cpp starguide_feed.h\ + switcher.cpp switcher.h\ + unity4000.cpp unity4000.h\ + unity_feed.cpp unity_feed.h\ + vguest.cpp vguest.h + +nodist_ripcd_SOURCES = moc_am16.cpp\ + moc_acu1p.cpp\ + moc_bt10x1.cpp\ + moc_bt16x1.cpp\ + moc_bt16x2.cpp\ + moc_bt8x2.cpp\ + moc_btacs82.cpp\ + moc_btsentinel4web.cpp\ + moc_btsrc16.cpp\ + moc_btsrc8iii.cpp\ + moc_btss124.cpp\ + moc_btss164.cpp\ + moc_btss42.cpp\ + moc_btss44.cpp\ + moc_btss82.cpp\ + moc_harlond.cpp\ + moc_livewire_lwrpaudio.cpp\ + moc_livewire_lwrpgpio.cpp\ + moc_livewire_mcastgpio.cpp\ + moc_local_audio.cpp\ + moc_local_gpio.cpp\ + moc_quartz1.cpp\ + moc_ripcd.cpp\ + moc_ripcd_socket.cpp\ + moc_sas32000.cpp\ + moc_sas64000.cpp\ + moc_sas64000gpi.cpp\ + moc_sasusi.cpp\ + moc_starguide3.cpp\ + moc_switcher.cpp\ + moc_unity4000.cpp\ + moc_vguest.cpp + +ripcd_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = ripcd.pro + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in diff --git a/ripcd/acu1p.cpp b/ripcd/acu1p.cpp new file mode 100644 index 00000000..01297da8 --- /dev/null +++ b/ripcd/acu1p.cpp @@ -0,0 +1,354 @@ +// acu1p.cpp +// +// Rivendell switcher driver for the Sine Systems ACU-1 (Prophet) +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: acu1p.cpp,v 1.1.2.2 2012/12/13 03:14:00 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + + +Acu1p::Acu1p(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + char str[9]; + + // + // Get Matrix Parameters + // + bt_matrix=matrix->matrix(); + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + bt_gpis=matrix->gpis(); + bt_gpos=matrix->gpos(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + bt_notify=new QSocketNotifier(bt_device->socket(),QSocketNotifier::Read,this); + connect(bt_notify,SIGNAL(activated(int)),this,SLOT(readyReadData(int))); + delete tty; + + // + // Initialize Relays + // + bt_gpo_mask=0; + str[0]=0xAA; + str[1]=ACU1P_UNIT_ID; + str[2]=0x38; + str[3]=bt_gpo_mask; + bt_device->writeBlock(str,4); + + // + // Interval OneShots + // + bt_gpi_oneshot=new RDOneShot(this); + connect(bt_gpi_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpiOneshotData(void*))); + bt_gpo_oneshot=new RDOneShot(this); + connect(bt_gpo_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpoOneshotData(void*))); + + // + // Poll Timer + // + bt_poll_timer=new QTimer(this); + connect(bt_poll_timer,SIGNAL(timeout()),this,SLOT(pollData())); + bt_poll_timer->start(ACU1P_POLL_INTERVAL); +} + + +Acu1p::~Acu1p() +{ + delete bt_notify; + delete bt_device; + delete bt_gpi_oneshot; + delete bt_gpo_oneshot; +} + + +RDMatrix::Type Acu1p::type() +{ + return RDMatrix::Acu1p; +} + + +unsigned Acu1p::gpiQuantity() +{ + return bt_gpis; +} + + +unsigned Acu1p::gpoQuantity() +{ + return bt_gpos; +} + + +bool Acu1p::primaryTtyActive() +{ + return true; +} + + +bool Acu1p::secondaryTtyActive() +{ + return false; +} + + +void Acu1p::processCommand(RDMacro *cmd) +{ + char str[9]; + + switch(cmd->command()) { + case RDMacro::GO: + if((cmd->argQuantity()!=5)|| + ((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))|| + (cmd->arg(2).toInt()<1)||(cmd->arg(3).toInt()>bt_gpos)|| + (cmd->arg(2).toInt()>bt_gpos)|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(1).toString().lower()!="i"))|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(3).toInt()!=-1)&&(cmd->arg(1).toString().lower()=="i"))|| + (cmd->arg(4).toInt()<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(3).toInt()==0) { // Turn OFF + if(cmd->arg(4).toInt()==0) { + if(cmd->arg(1).toString().lower()=="i") { + if(bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + bt_gpi_state[cmd->arg(2).toInt()-1]=false; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + SetRelay(cmd->arg(2).toInt()-1,false); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + } + } + else { + if(cmd->echoRequested()) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + } + return; + } + } + else { + if(cmd->arg(3).toInt()==-1) { // Clear input + bt_gpi_mask[cmd->arg(2).toInt()-1]=false; + bt_device->writeBlock("*0SPA",5); + } + else { + if(cmd->arg(4).toInt()==0) { // Turn ON + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + SetRelay(cmd->arg(2).toInt()-1,true); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + } + } + else { // Pulse + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + bt_gpi_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + if(cmd->arg(1).toString().lower()=="o") { + PulseRelay(cmd->arg(2).toInt()-1); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpo_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + } + } + } + if(cmd->echoRequested()) { + cmd->acknowledge(true); + emit rmlEcho(cmd); + } + break; + + case RDMacro::SA: + if((cmd->arg(1).toInt()<=0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()!=1)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + else { + str[0]=0xAA; + str[1]=ACU1P_UNIT_ID; + str[2]=0x31; + str[3]=0x01<<(cmd->arg(1).toInt()-1); + bt_device->writeBlock(str,4); + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SR: + if((cmd->arg(1).toInt()<=0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()!=1)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + else { + str[0]=0xAA; + str[1]=ACU1P_UNIT_ID; + str[2]=0x32; + str[3]=0x01<<(cmd->arg(1).toInt()-1); + bt_device->writeBlock(str,4); + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()!=1)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + str[0]=0xAA; + str[1]=ACU1P_UNIT_ID; + str[2]=0x51; + if(cmd->arg(1).toInt()==0) { + str[3]=0x00; + str[4]=0xFF; + } + else { + str[3]=0x01<<(cmd->arg(1).toInt()-1); + str[4]=~str[3]; + } + bt_device->writeBlock(str,5); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void Acu1p::pollData() +{ + char data[]={0xAA,ACU1P_UNIT_ID,0x39}; + bt_device->writeBlock(data,3); +} + + +void Acu1p::readyReadData(int sock) +{ + char data[255]; + int n=0; + + while((n=bt_device->readBlock(data,255))>0) { + if(n==2) { + ProcessGpi(256*(0xFF&data[1])+(0xFF&data[0])); + } + } +} + + +void Acu1p::gpiOneshotData(void *data) +{ +} + + +void Acu1p::gpoOneshotData(void *data) +{ + emit gpoChanged(bt_matrix,(long)data,false); +} + + +void Acu1p::ProcessGpi(uint16_t gpi_data) +{ + for(int i=0;iwriteBlock(str,4); +} + + +void Acu1p::PulseRelay(int gpo) +{ + char str[9]; + uint8_t mask=1<writeBlock(str,4); +} diff --git a/ripcd/acu1p.h b/ripcd/acu1p.h new file mode 100644 index 00000000..53691929 --- /dev/null +++ b/ripcd/acu1p.h @@ -0,0 +1,82 @@ +// acu1p.h +// +// Rivendell switcher driver for the Sine Systems ACU-1 (Prophet) +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: acu1p.h,v 1.1.2.2 2012/12/13 03:14:00 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef ACU1P_H +#define ACU1P_H + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define ACU1P_UNIT_ID 1 +#define ACU1P_POLL_INTERVAL 100 +#define ACU1P_GPIO_PINS 16 + +class Acu1p : public Switcher +{ + Q_OBJECT + public: + Acu1p(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~Acu1p(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void pollData(); + void readyReadData(int sock); + void gpiOneshotData(void *data); + void gpoOneshotData(void *data); + + private: + void ProcessGpi(uint16_t gpi_data); + void SetRelay(int gpo,bool state); + void PulseRelay(int gpo); + RDTTYDevice *bt_device; + QSocketNotifier *bt_notify; + QTimer *bt_poll_timer; + bool bt_gpi_state[ACU1P_GPIO_PINS]; + bool bt_gpi_mask[ACU1P_GPIO_PINS]; + uint8_t bt_gpo_mask; + RDOneShot *bt_gpi_oneshot; + RDOneShot *bt_gpo_oneshot; + int bt_matrix; + int bt_inputs; + int bt_outputs; + int bt_gpis; + int bt_gpos; +}; + + +#endif // ACU1P_H diff --git a/ripcd/am16.cpp b/ripcd/am16.cpp new file mode 100644 index 00000000..6699d403 --- /dev/null +++ b/ripcd/am16.cpp @@ -0,0 +1,262 @@ +// am16.cpp +// +// A Rivendell switcher driver for the 360 Systems AM16 +// +// (C) Copyright 2002-2013 Fred Gleason +// +// $Id: am16.cpp,v 1.1.2.1 2013/06/28 00:33:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include + + +Am16::Am16(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + unsigned sockopt; + + // + // Get Matrix Parameters + // + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + bt_midi_socket=-1; + bt_notifier=NULL; + bt_sysex_active=false; + bt_data_ptr=0; + + if((bt_midi_socket=open(matrix->gpioDevice(),O_RDWR))<0) { + syslog(LOG_WARNING,"unable to open MIDI device at \"%s\"", + (const char *)matrix->gpioDevice()); + return; + } + sockopt=O_NONBLOCK; + fcntl(bt_midi_socket,F_SETFL,sockopt); + + bt_notifier=new QSocketNotifier(bt_midi_socket,QSocketNotifier::Read,this); + connect(bt_notifier,SIGNAL(activated(int)),this,SLOT(readyReadData(int))); + + // + // Timeout Timer + // + bt_timeout_timer=new QTimer(this); + connect(bt_timeout_timer,SIGNAL(timeout()),this,SLOT(timeoutData())); +} + + +Am16::~Am16() +{ + if(bt_notifier!=NULL) { + delete bt_notifier; + } + if(bt_midi_socket>=0) { + close(bt_midi_socket); + } +} + + +RDMatrix::Type Am16::type() +{ + return RDMatrix::Am16; +} + + +unsigned Am16::gpiQuantity() +{ + return 0; +} + + +unsigned Am16::gpoQuantity() +{ + return 0; +} + + +bool Am16::primaryTtyActive() +{ + return false; +} + + +bool Am16::secondaryTtyActive() +{ + return false; +} + + +void Am16::processCommand(RDMacro *cmd) +{ + char data[1024]; + + switch(cmd->command()) { + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>bt_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + + // + // Save the desired values + // + bt_pending_inputs.push_back(cmd->arg(1).toInt()); + bt_pending_outputs.push_back(cmd->arg(2).toInt()); + + // + // Request the current crosspoint map + // + if(bt_pending_inputs.size()==1) { + data[0]=AM16_SYSEX_START; + data[1]=0x00; + data[2]=0x00; + data[3]=AM16_SYSTEMS_ID; + data[4]=AM16_DEVICE_NUMBER; + data[5]=AM16_DEVICE_ADDRESS; + data[6]=0x07; // Request Program NN + data[7]=AM16_PATCH_NUMBER; + data[8]=AM16_SYSEX_END; + write(bt_midi_socket,data,9); + bt_timeout_timer->start(AM16_TIMEOUT_INTERVAL,true); + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void Am16::readyReadData(int sock) +{ + char data[1024]; + int n; + + while((n=read(sock,data,1024))>0) { + for(int i=0;i0) { + bt_timeout_timer->stop(); + + // + // Apply Changes + // + for(int i=(int)bt_pending_inputs.size()-1;i>=0;i--) { + msg[7+bt_pending_outputs[i]]=0xFF&bt_pending_inputs[i]; + } + bt_pending_inputs.clear(); + bt_pending_outputs.clear(); + + // + // Send to Programs + // + write(bt_midi_socket,msg,len); + msg[7]++; + write(bt_midi_socket,msg,len); + + // + // Toggle Active Programs + // + msg[0]=0xC1; // Channel 1 + msg[1]=AM16_PATCH_NUMBER+1; + write(bt_midi_socket,msg,2); + msg[1]=AM16_PATCH_NUMBER; + write(bt_midi_socket,msg,2); + } + break; + + case 0x0B: // ACK / NCK + switch(0xFF&msg[7]) { + case 0: + // ACK -- command was successful! + break; + + case 0x7E: + syslog(LOG_NOTICE,"AM16 driver: data error"); + break; + + case 0x7F: + syslog(LOG_NOTICE, + "AM16 driver: memory protect mode is on, cannot change crosspoints"); + break; + + default: + syslog(LOG_NOTICE,"AM16 driver: received unknown ACK code [%d]", + 0xFF&msg[7]); + break; + } + break; + + default: + for(int i=0;i +// +// $Id: am16.h,v 1.1.2.1 2013/06/28 00:33:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// +// -- Driver Design Rationale FFG 6/27/2013 -- +// +// The AM16 was originally designed for use by musicians rather than +// broadcasters (it has a port for a foot pedal, for crying out loud!). +// Thus, it assumes that crosspoint changes are applied in batches +// ('patches' in MIDI parlance), necessitating a surprisingly complex +// procedure to change a single crosspoint without disturbing any of +// the others. The approach this driver takes is as follows: +// +// 1) Request a copy of the crosspoint map for the patch defined by +// AM16_PATCH_NUMBER from the AM16. +// 2) If we don't get the crosspoint map after waiting AM16_TIMEOUT_INTERVAL +// milliseconds, abort the operation (this to guard against unplugged +// MIDI cables and such). +// 3) Change the requested crosspoints on the map, then use it to update +// patches AM16_PATCH_NUMBER and AM16_PATCH_NUMBER+1 on the AM16. +// 4) Change the current patch on the AM16 to AM16_PATCH_NUMBER+1 and then +// immediately back to AM16_PATCH_NUMBER. (This bit of goofiness is +// required because the AM16 will not apply changes to a patch to +// the actual crosspoints while that patch is active.) +// + +#ifndef AM16_H +#define AM16_H + +#include + +#include +#include + +#include +#include +#include + +#include + +#define AM16_SYSEX_START 0xF0 +#define AM16_SYSEX_END 0xF7 +#define AM16_SYSTEMS_ID 0x1C // 360 Systems +#define AM16_DEVICE_NUMBER 0x04 // AM16/B (rev 2.00 or greater) +#define AM16_DEVICE_ADDRESS 0x01 // Configured in the hardware +#define AM16_PATCH_NUMBER 0x00 // Program to use for crosspoint updates +#define AM16_TIMEOUT_INTERVAL 1000 // How long to wait for crosspoint map + +class Am16 : public Switcher +{ + Q_OBJECT + public: + Am16(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~Am16(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void readyReadData(int sock); + void timeoutData(); + + private: + void ProcessMessage(char *msg,int len); + int bt_inputs; + int bt_outputs; + int bt_midi_socket; + bool bt_sysex_active; + char bt_data_buffer[1024]; + int bt_data_ptr; + std::vector bt_pending_inputs; + std::vector bt_pending_outputs; + QSocketNotifier *bt_notifier; + QTimer *bt_timeout_timer; +}; + + +#endif // AM16_H diff --git a/ripcd/bt10x1.cpp b/ripcd/bt10x1.cpp new file mode 100644 index 00000000..a69c1461 --- /dev/null +++ b/ripcd/bt10x1.cpp @@ -0,0 +1,119 @@ +// bt10x1.cpp +// +// A Rivendell switcher driver for the BroadcastTools 10x1 +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: bt10x1.cpp,v 1.11 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + + +Bt10x1::Bt10x1(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Get Matrix Parameters + // + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; +} + + +Bt10x1::~Bt10x1() +{ + delete bt_device; +} + + +RDMatrix::Type Bt10x1::type() +{ + return RDMatrix::Bt10x1; +} + + +unsigned Bt10x1::gpiQuantity() +{ + return 0; +} + + +unsigned Bt10x1::gpoQuantity() +{ + return 0; +} + + +bool Bt10x1::primaryTtyActive() +{ + return true; +} + + +bool Bt10x1::secondaryTtyActive() +{ + return false; +} + + +void Bt10x1::processCommand(RDMacro *cmd) +{ + char str[9]; + + switch(cmd->command()) { + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()!=1)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toInt()==0) { + sprintf(str,"*m\x0d"); + bt_device->writeBlock(str,3); + } + else { + sprintf(str,"*%02d\x0d",cmd->arg(1).toInt()); + bt_device->writeBlock(str,4); + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} diff --git a/ripcd/bt10x1.h b/ripcd/bt10x1.h new file mode 100644 index 00000000..dac463a6 --- /dev/null +++ b/ripcd/bt10x1.h @@ -0,0 +1,56 @@ +// bt10x1.h +// +// A Rivendell switcher driver for the BroadcastTools 10x1 +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: bt10x1.h,v 1.9 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BT10X1_H +#define BT10X1_H + +#include +#include +#include +#include + +#include + +#define BT10X1_MIN_GAIN -99 +#define BT10X1_MAX_GAIN 28 + +class Bt10x1 : public Switcher +{ + Q_OBJECT + public: + Bt10x1(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~Bt10x1(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private: + RDTTYDevice *bt_device; + int bt_inputs; + int bt_outputs; +}; + + +#endif // BT10X1_H diff --git a/ripcd/bt16x1.cpp b/ripcd/bt16x1.cpp new file mode 100644 index 00000000..b7c11f28 --- /dev/null +++ b/ripcd/bt16x1.cpp @@ -0,0 +1,119 @@ +// bt16x1.cpp +// +// A Rivendell switcher driver for the BroadcastTools 16x1 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: bt16x1.cpp,v 1.11 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + + +Bt16x1::Bt16x1(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Get Matrix Parameters + // + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; +} + + +Bt16x1::~Bt16x1() +{ + delete bt_device; +} + + +RDMatrix::Type Bt16x1::type() +{ + return RDMatrix::Bt16x1; +} + + +unsigned Bt16x1::gpiQuantity() +{ + return 0; +} + + +unsigned Bt16x1::gpoQuantity() +{ + return 0; +} + + +bool Bt16x1::primaryTtyActive() +{ + return true; +} + + +bool Bt16x1::secondaryTtyActive() +{ + return false; +} + + +void Bt16x1::processCommand(RDMacro *cmd) +{ + char str[9]; + + switch(cmd->command()) { + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()!=1)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toInt()==0) { + sprintf(str,"*m\x0d"); + bt_device->writeBlock(str,3); + } + else { + sprintf(str,"*%02d\x0d",cmd->arg(1).toInt()); + bt_device->writeBlock(str,4); + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} diff --git a/ripcd/bt16x1.h b/ripcd/bt16x1.h new file mode 100644 index 00000000..510f5729 --- /dev/null +++ b/ripcd/bt16x1.h @@ -0,0 +1,56 @@ +// bt16x1.h +// +// A Rivendell switcher driver for the BroadcastTools 16x1 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: bt16x1.h,v 1.9 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BT16X1_H +#define BT16X1_H + +#include +#include +#include +#include + +#include + +#define BT16X1_MIN_GAIN -99 +#define BT16X1_MAX_GAIN 28 + +class Bt16x1 : public Switcher +{ + Q_OBJECT + public: + Bt16x1(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~Bt16x1(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private: + RDTTYDevice *bt_device; + int bt_inputs; + int bt_outputs; +}; + + +#endif // BT16X1_H diff --git a/ripcd/bt16x2.cpp b/ripcd/bt16x2.cpp new file mode 100644 index 00000000..1ad35bee --- /dev/null +++ b/ripcd/bt16x2.cpp @@ -0,0 +1,365 @@ +// bt16x2.cpp +// +// A Rivendell switcher driver for the BroadcastTools 16x2 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: bt16x2.cpp,v 1.14 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include + + +Bt16x2::Bt16x2(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Initialize Data Structures + // + bt_istate=0; + for(int i=0;imatrix(); + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + bt_gpis=matrix->gpis(); + bt_gpos=matrix->gpos(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; + + // + // Interval OneShots + // + bt_gpi_oneshot=new RDOneShot(this); + connect(bt_gpi_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpiOneshotData(void*))); + bt_gpo_oneshot=new RDOneShot(this); + connect(bt_gpo_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpoOneshotData(void*))); + + // + // The Poll Timer + // + QTimer *timer=new QTimer(this,"poll_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(processStatus())); + timer->start(BT16X2_POLL_INTERVAL); +} + + +Bt16x2::~Bt16x2() +{ + delete bt_device; + delete bt_gpi_oneshot; + delete bt_gpo_oneshot; +} + + +RDMatrix::Type Bt16x2::type() +{ + return RDMatrix::Bt16x2; +} + + +unsigned Bt16x2::gpiQuantity() +{ + return bt_gpis; +} + + +unsigned Bt16x2::gpoQuantity() +{ + return bt_gpos; +} + + +bool Bt16x2::primaryTtyActive() +{ + return true; +} + + +bool Bt16x2::secondaryTtyActive() +{ + return false; +} + + +void Bt16x2::processCommand(RDMacro *cmd) +{ + char str[9]; + + switch(cmd->command()) { + case RDMacro::GO: + if((cmd->argQuantity()!=5)|| + ((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))|| + (cmd->arg(2).toInt()<1)||(cmd->arg(3).toInt()>bt_gpos)|| + (cmd->arg(2).toInt()>bt_gpos)|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(1).toString().lower()!="i"))|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(3).toInt()!=-1)&&(cmd->arg(1).toString().lower()=="i"))|| + (cmd->arg(4).toInt()<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(3).toInt()==0) { // Turn OFF + if(cmd->arg(4).toInt()==0) { + if(cmd->arg(1).toString().lower()=="i") { + if(bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + bt_gpi_state[cmd->arg(2).toInt()-1]=false; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%02dF",BT16X2_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + } + } + else { + if(cmd->echoRequested()) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + } + return; + } + } + else { + if(cmd->arg(3).toInt()==-1) { // Clear input + bt_gpi_mask[cmd->arg(2).toInt()-1]=false; + bt_device->writeBlock("*0SPA",5); + } + else { + if(cmd->arg(4).toInt()==0) { // Turn ON + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%02dL",BT16X2_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + } + } + else { // Pulse + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + bt_gpi_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%02dP",BT16X2_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpo_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + } + } + } + if(cmd->echoRequested()) { + cmd->acknowledge(true); + emit rmlEcho(cmd); + } + break; + + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toInt()==0) { + sprintf(str,"*%dM%d",BT16X2_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,4); + } + else { + sprintf(str,"*%d%02d%d",BT16X2_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void Bt16x2::processStatus() +{ + char buffer[256]; + int n; + int gpi; + + while((n=bt_device->readBlock(buffer,255))>0) { + for(int i=0;iwriteBlock("*0SPA",5); +} + + +void Bt16x2::gpoOneshotData(void *data) +{ + emit gpoChanged(bt_matrix,(long)data,false); +} diff --git a/ripcd/bt16x2.h b/ripcd/bt16x2.h new file mode 100644 index 00000000..72fe6e78 --- /dev/null +++ b/ripcd/bt16x2.h @@ -0,0 +1,71 @@ +// bt16x2.h +// +// A Rivendell switcher driver for the BroadcastTools 16x2 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: bt16x2.h,v 1.11 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BT16X2_H +#define BT16X2_H + +#include +#include +#include +#include +#include + +#include + +#define BT16X2_UNIT_ID 0 +#define BT16X2_POLL_INTERVAL 100 +#define BT16X2_GPIO_PINS 16 + +class Bt16x2 : public Switcher +{ + Q_OBJECT + public: + Bt16x2(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~Bt16x2(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void processStatus(); + void gpiOneshotData(void *data); + void gpoOneshotData(void *data); + + private: + RDTTYDevice *bt_device; + RDOneShot *bt_gpi_oneshot; + RDOneShot *bt_gpo_oneshot; + int bt_matrix; + int bt_inputs; + int bt_outputs; + int bt_gpis; + int bt_gpos; + int bt_istate; + bool bt_gpi_state[BT16X2_GPIO_PINS]; + bool bt_gpi_mask[BT16X2_GPIO_PINS]; +}; + + +#endif // BT16X2_H diff --git a/ripcd/bt8x2.cpp b/ripcd/bt8x2.cpp new file mode 100644 index 00000000..8d2e63d2 --- /dev/null +++ b/ripcd/bt8x2.cpp @@ -0,0 +1,150 @@ +// bt8x2.cpp +// +// A Rivendell switcher driver for the BroadcastTools 8x2 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: bt8x2.cpp,v 1.11 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + + +Bt8x2::Bt8x2(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Get Matrix Parameters + // + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; +} + + +Bt8x2::~Bt8x2() +{ + delete bt_device; +} + + +RDMatrix::Type Bt8x2::type() +{ + return RDMatrix::Bt8x2; +} + + +unsigned Bt8x2::gpiQuantity() +{ + return 0; +} + + +unsigned Bt8x2::gpoQuantity() +{ + return 0; +} + + +bool Bt8x2::primaryTtyActive() +{ + return true; +} + + +bool Bt8x2::secondaryTtyActive() +{ + return false; +} + + +void Bt8x2::processCommand(RDMacro *cmd) +{ + char str[9]; + + switch(cmd->command()) { + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toInt()==0) { + sprintf(str,"*m%d\x0d",cmd->arg(2).toInt()); + bt_device->writeBlock(str,4); + } + else { + sprintf(str,"*M%01d\x0d",cmd->arg(2).toInt()); + bt_device->writeBlock(str,4); + sprintf(str,"*%01d%01d0\x0d", + cmd->arg(1).toInt(),3+cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SA: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%01d%01d0\x0d", + cmd->arg(1).toInt(),3+cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SR: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%01d%01d0\x0d", + cmd->arg(1).toInt(),5+cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} diff --git a/ripcd/bt8x2.h b/ripcd/bt8x2.h new file mode 100644 index 00000000..d55bded8 --- /dev/null +++ b/ripcd/bt8x2.h @@ -0,0 +1,56 @@ +// bt8x2.h +// +// A Rivendell switcher driver for the BroadcastTools 8x2 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: bt8x2.h,v 1.9 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BT8X2_H +#define BT8X2_H + +#include +#include +#include +#include + +#include + +#define BT8X2_MIN_GAIN -99 +#define BT8X2_MAX_GAIN 28 + +class Bt8x2 : public Switcher +{ + Q_OBJECT + public: + Bt8x2(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~Bt8x2(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private: + RDTTYDevice *bt_device; + int bt_inputs; + int bt_outputs; +}; + + +#endif // BT8X2_H diff --git a/ripcd/btacs82.cpp b/ripcd/btacs82.cpp new file mode 100644 index 00000000..b5021b93 --- /dev/null +++ b/ripcd/btacs82.cpp @@ -0,0 +1,436 @@ +// btacs82.cpp +// +// A Rivendell switcher driver for the BroadcastTools SS 8.2 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: btacs82.cpp,v 1.14 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include + + +BtAcs82::BtAcs82(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Initialize Data Structures + // + bt_istate=0; + for(int i=0;imatrix(); + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + bt_gpis=matrix->gpis(); + bt_gpos=matrix->gpos(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; + + // + // Interval OneShots + // + bt_gpi_oneshot=new RDOneShot(this); + connect(bt_gpi_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpiOneshotData(void*))); + bt_gpo_oneshot=new RDOneShot(this); + connect(bt_gpo_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpoOneshotData(void*))); + + // + // The Poll Timer + // + QTimer *timer=new QTimer(this,"poll_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(processStatus())); + timer->start(BTACS82_POLL_INTERVAL); +} + + +BtAcs82::~BtAcs82() +{ + delete bt_device; + delete bt_gpi_oneshot; + delete bt_gpo_oneshot; +} + + +RDMatrix::Type BtAcs82::type() +{ + return RDMatrix::BtAcs82; +} + + +unsigned BtAcs82::gpiQuantity() +{ + return bt_gpis; +} + + +unsigned BtAcs82::gpoQuantity() +{ + return bt_gpos; +} + + +bool BtAcs82::primaryTtyActive() +{ + return true; +} + + +bool BtAcs82::secondaryTtyActive() +{ + return false; +} + + +void BtAcs82::processCommand(RDMacro *cmd) +{ + char str[9]; + int lvl=0; + + switch(cmd->command()) { + case RDMacro::GO: + if((cmd->argQuantity()!=5)|| + ((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))|| + (cmd->arg(2).toInt()<1)||(cmd->arg(3).toInt()>bt_gpos)|| + (cmd->arg(2).toInt()>bt_gpos)|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(1).toString().lower()!="i"))|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(3).toInt()!=-1)&&(cmd->arg(1).toString().lower()=="i"))|| + (cmd->arg(4).toInt()<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(3).toInt()==0) { // Turn OFF + if(cmd->arg(4).toInt()==0) { + if(cmd->arg(1).toString().lower()=="i") { + if(bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + bt_gpi_state[cmd->arg(2).toInt()-1]=false; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%dF",BTACS82_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + } + } + else { + if(cmd->echoRequested()) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + } + return; + } + } + else { + if(cmd->arg(3).toInt()==-1) { // Clear input + bt_gpi_mask[cmd->arg(2).toInt()-1]=false; + bt_device->writeBlock("*0SPA",5); + } + else { + if(cmd->arg(4).toInt()==0) { // Turn ON + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%dL",BTACS82_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + } + } + else { // Pulse + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + bt_gpi_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%dP",BTACS82_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpo_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + } + } + } + if(cmd->echoRequested()) { + cmd->acknowledge(true); + emit rmlEcho(cmd); + } + break; + + case RDMacro::SA: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%d%02d%d",BTACS82_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SR: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%d%02dM%d",BTACS82_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toInt()==0) { + sprintf(str,"*%dM%d",BTACS82_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,4); + } + else { + sprintf(str,"*%d%02d%d",BTACS82_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + for(int i=1;iarg(1).toInt();i++) { + sprintf(str,"*%d%02dM%d",BTACS82_UNIT_ID, + i,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + for(int i=cmd->arg(1).toInt()+1;i<9;i++) { + sprintf(str,"*%d%02dM%d",BTACS82_UNIT_ID, + i,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SL: + if((cmd->arg(1).toInt()<=0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()>0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(2).toInt()==0) { + lvl=0; + } + if((cmd->arg(2).toInt()<0)&&(cmd->arg(2).toInt()>=-3)) { + lvl=1; + } + if((cmd->arg(2).toInt()<-3)&&(cmd->arg(2).toInt()>=-6)) { + lvl=2; + } + if((cmd->arg(2).toInt()<-6)&&(cmd->arg(2).toInt()>=-10)) { + lvl=3; + } + if((cmd->arg(2).toInt()<-10)&&(cmd->arg(2).toInt()>=-15)) { + lvl=4; + } + if((cmd->arg(2).toInt()<-15)) { + lvl=5; + } + sprintf(str,"*%dDM%02d%d",BTACS82_UNIT_ID, + cmd->arg(1).toInt(),lvl); + bt_device->writeBlock(str,7); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void BtAcs82::processStatus() +{ + char buffer[256]; + int n; + int gpi; + + while((n=bt_device->readBlock(buffer,255))>0) { + for(int i=0;iwriteBlock("*0SPA",5); +} + + +void BtAcs82::gpoOneshotData(void *data) +{ + emit gpoChanged(bt_matrix,(long)data,false); +} diff --git a/ripcd/btacs82.h b/ripcd/btacs82.h new file mode 100644 index 00000000..db05b85b --- /dev/null +++ b/ripcd/btacs82.h @@ -0,0 +1,72 @@ +// btacs82.h +// +// A Rivendell switcher driver for the BroadcastTools ACS 8.2 +// +// (C) Copyright 2002-2008 Fred Gleason +// +// $Id: btacs82.h,v 1.11 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BTACS82_H +#define BTACS82_H + +#include +#include +#include +#include +#include + +#include + +#define BTACS82_UNIT_ID 0 +#define BTACS82_POLL_INTERVAL 100 +#define BTACS82_GPIO_PINS 16 + + +class BtAcs82 : public Switcher +{ + Q_OBJECT + public: + BtAcs82(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~BtAcs82(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void processStatus(); + void gpiOneshotData(void *data); + void gpoOneshotData(void *data); + + private: + RDTTYDevice *bt_device; + RDOneShot *bt_gpi_oneshot; + RDOneShot *bt_gpo_oneshot; + int bt_matrix; + int bt_inputs; + int bt_outputs; + int bt_gpis; + int bt_gpos; + int bt_istate; + bool bt_gpi_state[BTACS82_GPIO_PINS]; + bool bt_gpi_mask[BTACS82_GPIO_PINS]; +}; + + +#endif // BTACS82_H diff --git a/ripcd/btsentinel4web.cpp b/ripcd/btsentinel4web.cpp new file mode 100644 index 00000000..c7957648 --- /dev/null +++ b/ripcd/btsentinel4web.cpp @@ -0,0 +1,176 @@ +// btsentinel4web.cpp +// +// Rivendell switcher driver for the BroadcastTools Sentinel4Web AES switcher +// +// (C) Copyright 2002-2013 Fred Gleason +// +// $Id: btsentinel4web.cpp,v 1.1.2.1 2014/02/17 02:19:03 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + + +BtSentinel4Web::BtSentinel4Web(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + bt_address=matrix->ipAddress(RDMatrix::Primary); + bt_port=matrix->ipPort(RDMatrix::Primary); + + // + // Socket + // + bt_socket=new QSocket(this); + connect(bt_socket,SIGNAL(connected()),this,SLOT(connectedData())); + connect(bt_socket,SIGNAL(error(int)),this,SLOT(errorData(int))); + connect(bt_socket,SIGNAL(readyRead()),this,SLOT(readyReadData())); + + // + // Watchdog + // + bt_watchdog_timer=new QTimer(this); + connect(bt_watchdog_timer,SIGNAL(timeout()),this,SLOT(watchdogData())); + + bt_watchdog_reset_timer=new QTimer(this); + connect(bt_watchdog_reset_timer,SIGNAL(timeout()),this,SLOT(watchdogResetData())); + + + bt_socket->connectToHost(bt_address.toString(),bt_port); + bt_watchdog_timer->start(BTSENTINEL4WEB_WATCHDOG_INTERVAL,true); +} + + +BtSentinel4Web::~BtSentinel4Web() +{ + delete bt_socket; +} + + +RDMatrix::Type BtSentinel4Web::type() +{ + return RDMatrix::BtSentinel4Web; +} + + +unsigned BtSentinel4Web::gpiQuantity() +{ + return 0; +} + + +unsigned BtSentinel4Web::gpoQuantity() +{ + return 0; +} + + +bool BtSentinel4Web::primaryTtyActive() +{ + return false; +} + + +bool BtSentinel4Web::secondaryTtyActive() +{ + return false; +} + + +void BtSentinel4Web::processCommand(RDMacro *cmd) +{ + unsigned input; + unsigned output; + QString msg; + + switch(cmd->command()) { + case RDMacro::ST: + input=cmd->arg(1).toUInt(); + if(input>BTSENTINEL4WEB_INPUTS) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + output=cmd->arg(2).toUInt(); + if(output>BTSENTINEL4WEB_OUTPUTS) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(input==0) { + msg="*0MA"; + } + else { + msg=QString().sprintf("*0%02u",input); + } + bt_socket->writeBlock(msg,msg.length()); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void BtSentinel4Web::connectedData() +{ + bt_socket->writeBlock("*0U",3); + ripcd_config->log("ripcd",RDConfig::LogInfo,"connected to BT Sentinel4Web device at "+ + bt_socket->peerAddress().toString()); +} + + +void BtSentinel4Web::errorData(int err) +{ + watchdogData(); +} + + +void BtSentinel4Web::readyReadData() +{ + char data[1500]; + + while(bt_socket->readBlock(data,1500)>0); + bt_watchdog_timer->stop(); + bt_socket->writeBlock("*0U",3); + bt_watchdog_timer->start(BTSENTINEL4WEB_WATCHDOG_INTERVAL,true); +} + + +void BtSentinel4Web::watchdogData() +{ + ripcd_config->log("ripcd",RDConfig::LogWarning,"lost connection to BT Sentinel4Web device at "+ + bt_socket->peerAddress().toString()); + bt_watchdog_reset_timer->start(BTSENTINEL4WEB_WATCHDOG_INTERVAL,true); +} + + +void BtSentinel4Web::watchdogResetData() +{ + delete bt_socket; + bt_socket=new QSocket(this); + connect(bt_socket,SIGNAL(connected()),this,SLOT(connectedData())); + connect(bt_socket,SIGNAL(error(int)),this,SLOT(errorData(int))); + connect(bt_socket,SIGNAL(readyRead()),this,SLOT(readyReadData())); + + bt_socket->connectToHost(bt_address.toString(),bt_port); + bt_watchdog_timer->start(BTSENTINEL4WEB_WATCHDOG_INTERVAL,true); +} diff --git a/ripcd/btsentinel4web.h b/ripcd/btsentinel4web.h new file mode 100644 index 00000000..ee2e6367 --- /dev/null +++ b/ripcd/btsentinel4web.h @@ -0,0 +1,75 @@ +// btsentinel4web.h +// +// Rivendell switcher driver for the BroadcastTools Sentinel4Web AES switcher +// +// (C) Copyright 2002-2013 Fred Gleason +// +// $Id: btsentinel4web.h,v 1.1.2.1 2014/02/17 02:19:03 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BTSENTINEL4WEB_H +#define BTSENTINEL4WEB_H + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define BTSENTINEL4WEB_INPUTS 4 +#define BTSENTINEL4WEB_OUTPUTS 1 +#define BTSENTINEL4WEB_WATCHDOG_INTERVAL 10000 + +class BtSentinel4Web : public Switcher +{ + Q_OBJECT + public: + BtSentinel4Web(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~BtSentinel4Web(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void connectedData(); + void errorData(int err); + void readyReadData(); + void watchdogData(); + void watchdogResetData(); + + private: + QSocket *bt_socket; + QHostAddress bt_address; + uint16_t bt_port; + QTimer *bt_watchdog_timer; + QTimer *bt_watchdog_reset_timer; +}; + + +#endif // BTSENTINEL4WEB_H diff --git a/ripcd/btsrc16.cpp b/ripcd/btsrc16.cpp new file mode 100644 index 00000000..05c2b8e1 --- /dev/null +++ b/ripcd/btsrc16.cpp @@ -0,0 +1,346 @@ +// btsrc16.cpp +// +// A Rivendell switcher driver for the BroadcastTools SRC-16 +// +// (C) Copyright 2002-2005,2010 Fred Gleason +// +// $Id: +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include + + +BtSrc16::BtSrc16(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Initialize Data Structures + // + bt_istate=0; + for(int i=0;imatrix(); + bt_gpis=matrix->gpis(); + bt_gpos=matrix->gpos(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; + + // + // Interval OneShots + // + bt_gpi_oneshot=new RDOneShot(this); + connect(bt_gpi_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpiOneshotData(void*))); + bt_gpo_oneshot=new RDOneShot(this); + connect(bt_gpo_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpoOneshotData(void*))); + + // + // The Poll Timer + // + QTimer *timer=new QTimer(this,"poll_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(processStatus())); + timer->start(BTSRC16_POLL_INTERVAL); +} + + +BtSrc16::~BtSrc16() +{ + delete bt_device; + delete bt_gpi_oneshot; + delete bt_gpo_oneshot; +} + + +RDMatrix::Type BtSrc16::type() +{ + return RDMatrix::BtSrc16; +} + + +unsigned BtSrc16::gpiQuantity() +{ + return bt_gpis; +} + + +unsigned BtSrc16::gpoQuantity() +{ + return 0; +} + + +bool BtSrc16::primaryTtyActive() +{ + return true; +} + + +bool BtSrc16::secondaryTtyActive() +{ + return false; +} + + +void BtSrc16::processCommand(RDMacro *cmd) +{ + char str[9]; + + switch(cmd->command()) { + case RDMacro::GO: + if((cmd->argQuantity()!=5)|| + ((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))|| + (cmd->arg(2).toInt()<1)||(cmd->arg(3).toInt()>bt_gpos)|| + (cmd->arg(2).toInt()>bt_gpos)|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(1).toString().lower()!="i"))|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(3).toInt()!=-1)&&(cmd->arg(1).toString().lower()=="i"))|| + (cmd->arg(4).toInt()<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(3).toInt()==0) { // Turn OFF + if(cmd->arg(4).toInt()==0) { + if(cmd->arg(1).toString().lower()=="i") { + if(bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + bt_gpi_state[cmd->arg(2).toInt()-1]=false; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%02dF\r\n",BTSRC16_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,9); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + } + } + else { + if(cmd->echoRequested()) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + } + return; + } + } + else { + if(cmd->arg(3).toInt()==-1) { // Clear input + bt_gpi_mask[cmd->arg(2).toInt()-1]=false; + bt_device->writeBlock("*0SPA\r\n",7); + } + else { + if(cmd->arg(4).toInt()==0) { // Turn ON + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%02dL\r\n", + BTSRC16_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,9); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + } + } + else { // Pulse + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + bt_gpi_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%02dP%02d\r\n", + BTSRC16_UNIT_ID,cmd->arg(2).toInt(), + cmd->arg(4).toInt()/100+1); + bt_device->writeBlock(str,11); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpo_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + } + } + } + if(cmd->echoRequested()) { + cmd->acknowledge(true); + emit rmlEcho(cmd); + } + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void BtSrc16::processStatus() +{ + char buffer[256]; + int n; + int gpi; + + while((n=bt_device->readBlock(buffer,255))>0) { + for(int i=0;iwriteBlock("*0SPA",5); +} + + +void BtSrc16::gpoOneshotData(void *data) +{ + emit gpoChanged(bt_matrix,(long)data,false); +} diff --git a/ripcd/btsrc16.h b/ripcd/btsrc16.h new file mode 100644 index 00000000..1a839d5c --- /dev/null +++ b/ripcd/btsrc16.h @@ -0,0 +1,70 @@ +// btsrc16.h +// +// A Rivendell switcher driver for the BroadcastTools SRC-16 +// +// (C) Copyright 2002-2005,2010 Fred Gleason +// +// $Id: btsrc16.h,v 1.3 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BTSRC16_H +#define BTSRC16_H + +#include +#include +#include +#include +#include + +#include + +#define BTSRC16_UNIT_ID 0 +#define BTSRC16_POLL_INTERVAL 100 +#define BTSRC16_GPIO_PINS 16 + + +class BtSrc16 : public Switcher +{ + Q_OBJECT + public: + BtSrc16(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~BtSrc16(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void processStatus(); + void gpiOneshotData(void *data); + void gpoOneshotData(void *data); + + private: + RDTTYDevice *bt_device; + RDOneShot *bt_gpi_oneshot; + RDOneShot *bt_gpo_oneshot; + int bt_matrix; + int bt_gpis; + int bt_gpos; + int bt_istate; + bool bt_gpi_state[BTSRC16_GPIO_PINS]; + bool bt_gpi_mask[BTSRC16_GPIO_PINS]; +}; + + +#endif // BTSRC16_H diff --git a/ripcd/btsrc8iii.cpp b/ripcd/btsrc8iii.cpp new file mode 100644 index 00000000..876c3c68 --- /dev/null +++ b/ripcd/btsrc8iii.cpp @@ -0,0 +1,330 @@ +// btsrc8iii.cpp +// +// A Rivendell switcher driver for the BroadcastTools SRC-8 III +// +// (C) Copyright 2002-2005,2010 Fred Gleason +// +// $Id: btsrc8iii.cpp,v 1.3 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include + + +BtSrc8Iii::BtSrc8Iii(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Initialize Data Structures + // + bt_istate=0; + for(int i=0;imatrix(); + bt_gpis=matrix->gpis(); + bt_gpos=matrix->gpos(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; + + // + // Interval OneShots + // + bt_gpi_oneshot=new RDOneShot(this); + connect(bt_gpi_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpiOneshotData(void*))); + bt_gpo_oneshot=new RDOneShot(this); + connect(bt_gpo_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpoOneshotData(void*))); + + // + // The Poll Timer + // + QTimer *timer=new QTimer(this,"poll_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(processStatus())); + timer->start(BTSRC8III_POLL_INTERVAL); +} + + +BtSrc8Iii::~BtSrc8Iii() +{ + delete bt_device; + delete bt_gpi_oneshot; + delete bt_gpo_oneshot; +} + + +RDMatrix::Type BtSrc8Iii::type() +{ + return RDMatrix::BtSrc8III; +} + + +unsigned BtSrc8Iii::gpiQuantity() +{ + return bt_gpis; +} + + +unsigned BtSrc8Iii::gpoQuantity() +{ + return bt_gpos; +} + + +bool BtSrc8Iii::primaryTtyActive() +{ + return true; +} + + +bool BtSrc8Iii::secondaryTtyActive() +{ + return false; +} + + +void BtSrc8Iii::processCommand(RDMacro *cmd) +{ + char str[9]; + + switch(cmd->command()) { + case RDMacro::GO: + if((cmd->argQuantity()!=5)|| + ((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))|| + (cmd->arg(2).toInt()<1)||(cmd->arg(3).toInt()>bt_gpos)|| + (cmd->arg(2).toInt()>bt_gpos)|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(1).toString().lower()!="i"))|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(3).toInt()!=-1)&&(cmd->arg(1).toString().lower()=="i"))|| + (cmd->arg(4).toInt()<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(3).toInt()==0) { // Turn OFF + if(cmd->arg(4).toInt()==0) { + if(cmd->arg(1).toString().lower()=="i") { + if(bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + bt_gpi_state[cmd->arg(2).toInt()-1]=false; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%dF\r\n",BTSRC8III_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,8); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + } + } + else { + if(cmd->echoRequested()) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + } + return; + } + } + else { + if(cmd->arg(3).toInt()==-1) { // Clear input + bt_gpi_mask[cmd->arg(2).toInt()-1]=false; + bt_device->writeBlock("*0SPA\r\n",7); + } + else { + if(cmd->arg(4).toInt()==0) { // Turn ON + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%dL\r\n", + BTSRC8III_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,8); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + } + } + else { // Pulse + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + bt_gpi_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%dP%02d\r\n", + BTSRC8III_UNIT_ID,cmd->arg(2).toInt(), + cmd->arg(4).toInt()/100+1); + bt_device->writeBlock(str,10); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpo_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + } + } + } + if(cmd->echoRequested()) { + cmd->acknowledge(true); + emit rmlEcho(cmd); + } + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void BtSrc8Iii::processStatus() +{ + char buffer[256]; + int n; + int gpi; + + while((n=bt_device->readBlock(buffer,255))>0) { + for(int i=0;iwriteBlock("*0SPA",5); +} + + +void BtSrc8Iii::gpoOneshotData(void *data) +{ + emit gpoChanged(bt_matrix,(long)data,false); +} diff --git a/ripcd/btsrc8iii.h b/ripcd/btsrc8iii.h new file mode 100644 index 00000000..5002ff96 --- /dev/null +++ b/ripcd/btsrc8iii.h @@ -0,0 +1,69 @@ +// btsrc8iii.h +// +// A Rivendell switcher driver for the BroadcastTools SRC-8 III +// +// (C) Copyright 2002-2005,2010 Fred Gleason +// +// $Id: btsrc8iii.h,v 1.3 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BTSRC8III_H +#define BTSRC8III_H + +#include +#include +#include +#include +#include + +#include + +#define BTSRC8III_UNIT_ID 0 +#define BTSRC8III_POLL_INTERVAL 100 +#define BTSRC8III_GPIO_PINS 8 + +class BtSrc8Iii : public Switcher +{ + Q_OBJECT + public: + BtSrc8Iii(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~BtSrc8Iii(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void processStatus(); + void gpiOneshotData(void *data); + void gpoOneshotData(void *data); + + private: + RDTTYDevice *bt_device; + RDOneShot *bt_gpi_oneshot; + RDOneShot *bt_gpo_oneshot; + int bt_matrix; + int bt_gpis; + int bt_gpos; + int bt_istate; + bool bt_gpi_state[BTSRC8III_GPIO_PINS]; + bool bt_gpi_mask[BTSRC8III_GPIO_PINS]; +}; + + +#endif // BTSRC8III_H diff --git a/ripcd/btss124.cpp b/ripcd/btss124.cpp new file mode 100644 index 00000000..c2a637b7 --- /dev/null +++ b/ripcd/btss124.cpp @@ -0,0 +1,161 @@ +// btss124.cpp +// +// A Rivendell switcher driver for the BroadcastTools SS 12.4 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: btss124.cpp,v 1.11 2010/08/03 23:39:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include + + +BtSs124::BtSs124(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Get Matrix Parameters + // + bt_matrix=matrix->matrix(); + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; +} + + +BtSs124::~BtSs124() +{ + delete bt_device; +} + + +RDMatrix::Type BtSs124::type() +{ + return RDMatrix::BtSs124; +} + + +unsigned BtSs124::gpiQuantity() +{ + return 0; +} + + +unsigned BtSs124::gpoQuantity() +{ + return 0; +} + + +bool BtSs124::primaryTtyActive() +{ + return true; +} + + +bool BtSs124::secondaryTtyActive() +{ + return false; +} + + +void BtSs124::processCommand(RDMacro *cmd) +{ + char str[9]; + + switch(cmd->command()) { + case RDMacro::SA: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>4)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%d%02d%d",BTSS124_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SR: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>4)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%d%02dM%d",BTSS124_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>4)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toInt()==0) { + sprintf(str,"*%dM%d",BTSS124_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,4); + } + else { + sprintf(str,"*%d%02d%d",BTSS124_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + for(int i=1;iarg(1).toInt();i++) { + sprintf(str,"*%d%02dM%d",BTSS124_UNIT_ID, + i,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + for(int i=cmd->arg(1).toInt()+1;i<9;i++) { + sprintf(str,"*%d%02dM%d",BTSS124_UNIT_ID, + i,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} diff --git a/ripcd/btss124.h b/ripcd/btss124.h new file mode 100644 index 00000000..c84038f3 --- /dev/null +++ b/ripcd/btss124.h @@ -0,0 +1,56 @@ +// btss124.h +// +// A Rivendell switcher driver for the BroadcastTools SS 8.2 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: btss124.h,v 1.9 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BTSS124_H +#define BTSS124_H + +#include +#include +#include +#include + +#include + +#define BTSS124_UNIT_ID 0 + +class BtSs124 : public Switcher +{ + Q_OBJECT + public: + BtSs124(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~BtSs124(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private: + RDTTYDevice *bt_device; + int bt_matrix; + int bt_inputs; + int bt_outputs; +}; + + +#endif // BTSS124_H diff --git a/ripcd/btss164.cpp b/ripcd/btss164.cpp new file mode 100644 index 00000000..02aea0da --- /dev/null +++ b/ripcd/btss164.cpp @@ -0,0 +1,432 @@ +// btss164.cpp +// +// A Rivendell switcher driver for the BroadcastTools SS 16.4 +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: btss164.cpp,v 1.15 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include + + +BtSs164::BtSs164(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Initialize Data Structures + // + bt_istate=0; + for(int i=0;imatrix(); + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + bt_gpis=matrix->gpis(); + bt_gpos=matrix->gpos(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; + + // + // Interval OneShots + // + bt_gpi_oneshot=new RDOneShot(this); + connect(bt_gpi_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpiOneshotData(void*))); + bt_gpo_oneshot=new RDOneShot(this); + connect(bt_gpo_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpoOneshotData(void*))); + + // + // The Poll Timer + // + QTimer *timer=new QTimer(this,"poll_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(processStatus())); + timer->start(BTSS164_POLL_INTERVAL); +} + + +RDMatrix::Type BtSs164::type() +{ + return RDMatrix::BtSs164; +} + + +unsigned BtSs164::gpiQuantity() +{ + return bt_gpis; +} + + +unsigned BtSs164::gpoQuantity() +{ + return bt_gpos; +} + + +bool BtSs164::primaryTtyActive() +{ + return true; +} + + +bool BtSs164::secondaryTtyActive() +{ + return false; +} + + +BtSs164::~BtSs164() +{ + delete bt_device; + delete bt_gpi_oneshot; + delete bt_gpo_oneshot; +} + + +void BtSs164::processCommand(RDMacro *cmd) +{ + char str[9]; + + switch(cmd->command()) { + case RDMacro::GO: + if((cmd->argQuantity()!=5)|| + ((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))|| + (cmd->arg(2).toInt()<1)||(cmd->arg(3).toInt()>bt_gpos)|| + (cmd->arg(2).toInt()>bt_gpos)|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(1).toString().lower()!="i"))|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(3).toInt()!=-1)&&(cmd->arg(1).toString().lower()=="i"))|| + (cmd->arg(4).toInt()<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(3).toInt()==0) { // Turn OFF + if(cmd->arg(4).toInt()==0) { + if(cmd->arg(1).toString().lower()=="i") { + if(bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + bt_gpi_state[cmd->arg(2).toInt()-1]=false; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + if(cmd->arg(2).toInt()<8) { + sprintf(str,"*%dOR%dF",BTSS164_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + else { + sprintf(str,"*%dOOR%02dF",BTSS164_UNIT_ID, + cmd->arg(2).toInt()-8); + bt_device->writeBlock(str,8); + } + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + } + } + else { + if(cmd->echoRequested()) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + } + return; + } + } + else { + if(cmd->arg(3).toInt()==-1) { // Clear input + bt_gpi_mask[cmd->arg(2).toInt()-1]=false; + bt_device->writeBlock("*0SPA",5); + } + else { + if(cmd->arg(4).toInt()==0) { // Turn ON + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + if(cmd->arg(2).toInt()<8) { + sprintf(str,"*%dOR%dL",BTSS164_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + else { + sprintf(str,"*%dOOR%02dL",BTSS164_UNIT_ID, + cmd->arg(2).toInt()-8); + bt_device->writeBlock(str,8); + } + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + } + } + else { // Pulse + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + bt_gpi_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + if(cmd->arg(1).toString().lower()=="o") { + if(cmd->arg(2).toInt()<8) { + sprintf(str,"*%dOR%dP",BTSS164_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + else { + sprintf(str,"*%dOOR%02dP",BTSS164_UNIT_ID, + cmd->arg(2).toInt()-8); + bt_device->writeBlock(str,8); + } + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpo_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + } + } + } + if(cmd->echoRequested()) { + cmd->acknowledge(true); + emit rmlEcho(cmd); + } + break; + + case RDMacro::SA: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>4)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%d%02d%d",BTSS164_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SR: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>4)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%d%02dM%d",BTSS164_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>4)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toInt()==0) { + sprintf(str,"*%dM%d",BTSS164_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,4); + } + else { + sprintf(str,"*%dM%d",BTSS164_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,4); + sprintf(str,"*%d%02d%d",BTSS164_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void BtSs164::processStatus() +{ + char buffer[256]; + int n; + int gpi; + + while((n=bt_device->readBlock(buffer,255))>0) { + for(int i=0;iwriteBlock("*0SPA",5); +} + + +void BtSs164::gpoOneshotData(void *data) +{ + emit gpoChanged(bt_matrix,(long)data,false); +} diff --git a/ripcd/btss164.h b/ripcd/btss164.h new file mode 100644 index 00000000..531dafee --- /dev/null +++ b/ripcd/btss164.h @@ -0,0 +1,71 @@ +// btss164.h +// +// A Rivendell switcher driver for the BroadcastTools SS16.4 +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: btss164.h,v 1.10 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BTSS164_H +#define BTSS164_H + +#include +#include +#include +#include +#include + +#include + +#define BTSS164_UNIT_ID 0 +#define BTSS164_POLL_INTERVAL 100 +#define BTSS164_GPIO_PINS 24 + +class BtSs164 : public Switcher +{ + Q_OBJECT + public: + BtSs164(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~BtSs164(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void processStatus(); + void gpiOneshotData(void *data); + void gpoOneshotData(void *data); + + private: + RDTTYDevice *bt_device; + RDOneShot *bt_gpi_oneshot; + RDOneShot *bt_gpo_oneshot; + int bt_matrix; + int bt_inputs; + int bt_outputs; + int bt_gpis; + int bt_gpos; + int bt_istate; + bool bt_gpi_state[BTSS164_GPIO_PINS]; + bool bt_gpi_mask[BTSS164_GPIO_PINS]; +}; + + +#endif // BTSS164_H diff --git a/ripcd/btss42.cpp b/ripcd/btss42.cpp new file mode 100644 index 00000000..fba200f0 --- /dev/null +++ b/ripcd/btss42.cpp @@ -0,0 +1,418 @@ +// btss42.cpp +// +// A Rivendell switcher driver for the BroadcastTools SS 4.2 +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: btss42.cpp,v 1.12 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include + + +BtSs42::BtSs42(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Initialize Data Structures + // + bt_istate=0; + for(int i=0;imatrix(); + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + bt_gpis=matrix->gpis(); + bt_gpos=matrix->gpos(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; + + // + // Interval OneShots + // + bt_gpi_oneshot=new RDOneShot(this); + connect(bt_gpi_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpiOneshotData(void*))); + bt_gpo_oneshot=new RDOneShot(this); + connect(bt_gpo_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpoOneshotData(void*))); + + // + // The Poll Timer + // + QTimer *timer=new QTimer(this,"poll_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(processStatus())); + timer->start(BTSS42_POLL_INTERVAL); +} + + +BtSs42::~BtSs42() +{ + delete bt_device; + delete bt_gpi_oneshot; + delete bt_gpo_oneshot; +} + + +RDMatrix::Type BtSs42::type() +{ + return RDMatrix::BtSs42; +} + + +unsigned BtSs42::gpiQuantity() +{ + return bt_gpis; +} + + +unsigned BtSs42::gpoQuantity() +{ + return bt_gpos; +} + + +bool BtSs42::primaryTtyActive() +{ + return true; +} + + +bool BtSs42::secondaryTtyActive() +{ + return false; +} + + +void BtSs42::processCommand(RDMacro *cmd) +{ + char str[9]; + + switch(cmd->command()) { + case RDMacro::GO: + if((cmd->argQuantity()!=5)|| + ((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))|| + (cmd->arg(2).toInt()<1)||(cmd->arg(3).toInt()>bt_gpos)|| + (cmd->arg(2).toInt()>bt_gpos)|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(1).toString().lower()!="i"))|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(3).toInt()!=-1)&&(cmd->arg(1).toString().lower()=="i"))|| + (cmd->arg(4).toInt()<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(3).toInt()==0) { // Turn OFF + if(cmd->arg(4).toInt()==0) { + if(cmd->arg(1).toString().lower()=="i") { + if(bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + bt_gpi_state[cmd->arg(2).toInt()-1]=false; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + if(cmd->arg(2).toInt()<=4) { + sprintf(str,"*%dOO%dF",BTSS42_UNIT_ID,cmd->arg(2).toInt()); + } + else { + sprintf(str,"*%dOR%dF",BTSS42_UNIT_ID,cmd->arg(2).toInt()-4); + } + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + } + } + else { + if(cmd->echoRequested()) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + } + return; + } + } + else { + if(cmd->arg(3).toInt()==-1) { // Clear input + bt_gpi_mask[cmd->arg(2).toInt()-1]=false; + bt_device->writeBlock("*0SPA",5); + } + else { + if(cmd->arg(4).toInt()==0) { // Turn ON + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + if(cmd->arg(2).toInt()<=4) { + sprintf(str,"*%dOO%dL",BTSS42_UNIT_ID,cmd->arg(2).toInt()); + } + else { + sprintf(str,"*%dOR%dL",BTSS42_UNIT_ID,cmd->arg(2).toInt()-4); + } + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + } + } + else { // Pulse + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + bt_gpi_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + if(cmd->arg(1).toString().lower()=="o") { + if(cmd->arg(2).toInt()<=4) { + sprintf(str,"*%dOO%dP",BTSS42_UNIT_ID,cmd->arg(2).toInt()); + } + else { + sprintf(str,"*%dOR%dP",BTSS42_UNIT_ID,cmd->arg(2).toInt()-4); + } + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpo_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + } + } + } + if(cmd->echoRequested()) { + cmd->acknowledge(true); + emit rmlEcho(cmd); + } + break; + + case RDMacro::SA: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%d%02d%d",BTSS42_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SR: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%d%02dM%d",BTSS42_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toInt()==0) { + sprintf(str,"*%dM%d",BTSS42_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,4); + } + else { + sprintf(str,"*%d%02d%d",BTSS42_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + for(int i=1;iarg(1).toInt();i++) { + sprintf(str,"*%d%02dM%d",BTSS42_UNIT_ID, + i,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + for(int i=cmd->arg(1).toInt()+1;i<5;i++) { + sprintf(str,"*%d%02dM%d",BTSS42_UNIT_ID, + i,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void BtSs42::processStatus() +{ + char buffer[256]; + int n; + int gpi; + + while((n=bt_device->readBlock(buffer,255))>0) { + for(int i=0;iwriteBlock("*0SPA",5); +} + + +void BtSs42::gpoOneshotData(void *data) +{ + emit gpoChanged(bt_matrix,(long)data,false); +} diff --git a/ripcd/btss42.h b/ripcd/btss42.h new file mode 100644 index 00000000..3bbedb05 --- /dev/null +++ b/ripcd/btss42.h @@ -0,0 +1,71 @@ +// btss42.h +// +// A Rivendell switcher driver for the BroadcastTools SS 4.2 +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: btss42.h,v 1.10 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BTSS42_H +#define BTSS42_H + +#include +#include +#include +#include +#include + +#include + +#define BTSS42_UNIT_ID 0 +#define BTSS42_POLL_INTERVAL 100 +#define BTSS42_GPIO_PINS 16 + +class BtSs42 : public Switcher +{ + Q_OBJECT + public: + BtSs42(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~BtSs42(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void processStatus(); + void gpiOneshotData(void *data); + void gpoOneshotData(void *data); + + private: + RDTTYDevice *bt_device; + RDOneShot *bt_gpi_oneshot; + RDOneShot *bt_gpo_oneshot; + int bt_matrix; + int bt_inputs; + int bt_outputs; + int bt_gpis; + int bt_gpos; + int bt_istate; + bool bt_gpi_state[BTSS42_GPIO_PINS]; + bool bt_gpi_mask[BTSS42_GPIO_PINS]; +}; + + +#endif // BTSS42_H diff --git a/ripcd/btss44.cpp b/ripcd/btss44.cpp new file mode 100644 index 00000000..fee5cac5 --- /dev/null +++ b/ripcd/btss44.cpp @@ -0,0 +1,418 @@ +// btss44.cpp +// +// A Rivendell switcher driver for the BroadcastTools SS 4.4 +// +// (C) Copyright 2002-2005,2009 Fred Gleason +// +// $Id: btss44.cpp,v 1.3.8.1 2014/03/02 03:15:23 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include + +BtSs44::BtSs44(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Initialize Data Structures + // + bt_istate=0; + for(int i=0;imatrix(); + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + bt_gpis=matrix->gpis(); + bt_gpos=matrix->gpos(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; + + // + // Interval OneShots + // + bt_gpi_oneshot=new RDOneShot(this); + connect(bt_gpi_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpiOneshotData(void*))); + bt_gpo_oneshot=new RDOneShot(this); + connect(bt_gpo_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpoOneshotData(void*))); + + // + // The Poll Timer + // + QTimer *timer=new QTimer(this,"poll_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(processStatus())); + timer->start(BTSS44_POLL_INTERVAL); +} + + +BtSs44::~BtSs44() +{ + delete bt_device; + delete bt_gpi_oneshot; + delete bt_gpo_oneshot; +} + + +RDMatrix::Type BtSs44::type() +{ + return RDMatrix::BtSs44; +} + + +unsigned BtSs44::gpiQuantity() +{ + return bt_gpis; +} + + +unsigned BtSs44::gpoQuantity() +{ + return bt_gpos; +} + + +bool BtSs44::primaryTtyActive() +{ + return true; +} + + +bool BtSs44::secondaryTtyActive() +{ + return false; +} + + +void BtSs44::processCommand(RDMacro *cmd) +{ + char str[9]; + + switch(cmd->command()) { + case RDMacro::GO: +// NEW + if((cmd->argQuantity()!=5)|| + ((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))|| + (cmd->arg(2).toInt()<1)||(cmd->arg(3).toInt()>bt_gpos)|| + (cmd->arg(2).toInt()>bt_gpos)|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(1).toString().lower()!="i"))|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(3).toInt()!=-1)&&(cmd->arg(1).toString().lower()=="i"))|| + (cmd->arg(4).toInt()<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(3).toInt()==0) { // Turn OFF + if(cmd->arg(4).toInt()==0) { + if(cmd->arg(1).toString().lower()=="i") { + if(bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + bt_gpi_state[cmd->arg(2).toInt()-1]=false; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + if(cmd->arg(2).toInt()<=4) { + sprintf(str,"*%dOO%dF",BTSS44_UNIT_ID,cmd->arg(2).toInt()); + } + else { + sprintf(str,"*%dOR%dF",BTSS44_UNIT_ID,cmd->arg(2).toInt()-4); + } + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + } + } + else { + if(cmd->echoRequested()) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + } + return; + } + } + else { + if(cmd->arg(3).toInt()==-1) { // Clear input + bt_gpi_mask[cmd->arg(2).toInt()-1]=false; + bt_device->writeBlock("*0SPA",5); + } + else { + if(cmd->arg(4).toInt()==0) { // Turn ON + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + if(cmd->arg(2).toInt()<=4) { + sprintf(str,"*%dOO%dL",BTSS44_UNIT_ID,cmd->arg(2).toInt()); + } + else { + sprintf(str,"*%dOR%dL",BTSS44_UNIT_ID,cmd->arg(2).toInt()-4); + } + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + } + } + else { // Pulse + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + bt_gpi_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + if(cmd->arg(1).toString().lower()=="o") { + if(cmd->arg(2).toInt()<=4) { + sprintf(str,"*%dOO%dP",BTSS44_UNIT_ID,cmd->arg(2).toInt()); + } + else { + sprintf(str,"*%dOR%dP",BTSS44_UNIT_ID,cmd->arg(2).toInt()-4); + } + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpo_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + } + } + } + if(cmd->echoRequested()) { + cmd->acknowledge(true); + emit rmlEcho(cmd); + } + break; + + case RDMacro::SA: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>bt_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%d%02d%d",BTSS44_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SR: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>bt_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%d%02dM%d",BTSS44_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>bt_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toInt()==0) { + sprintf(str,"*%dM%d",BTSS44_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,4); + } + else { + sprintf(str,"*%d%02d%d",BTSS44_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + for(int i=1;iarg(1).toInt();i++) { + sprintf(str,"*%d%02dM%d",BTSS44_UNIT_ID, + i,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + for(int i=cmd->arg(1).toInt()+1;i<5;i++) { + sprintf(str,"*%d%02dM%d",BTSS44_UNIT_ID, + i,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void BtSs44::processStatus() +{ + char buffer[256]; + int n; + int gpi; + + while((n=bt_device->readBlock(buffer,255))>0) { + for(int i=0;iwriteBlock("*0SPA",5); +} + + +void BtSs44::gpoOneshotData(void *data) +{ + emit gpoChanged(bt_matrix,(long)data,false); +} diff --git a/ripcd/btss44.h b/ripcd/btss44.h new file mode 100644 index 00000000..8dab7741 --- /dev/null +++ b/ripcd/btss44.h @@ -0,0 +1,71 @@ +// btss44.h +// +// A Rivendell switcher driver for the BroadcastTools SS 4.4 +// +// (C) Copyright 2002-2005,2009 Fred Gleason +// +// $Id: btss44.h,v 1.3 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BTSS44_H +#define BTSS44_H + +#include +#include +#include +#include +#include + +#include + +#define BTSS44_UNIT_ID 0 +#define BTSS44_POLL_INTERVAL 100 +#define BTSS44_GPIO_PINS 16 + +class BtSs44 : public Switcher +{ + Q_OBJECT + public: + BtSs44(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~BtSs44(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void processStatus(); + void gpiOneshotData(void *data); + void gpoOneshotData(void *data); + + private: + RDTTYDevice *bt_device; + RDOneShot *bt_gpi_oneshot; + RDOneShot *bt_gpo_oneshot; + int bt_matrix; + int bt_inputs; + int bt_outputs; + int bt_gpis; + int bt_gpos; + int bt_istate; + bool bt_gpi_state[BTSS44_GPIO_PINS]; + bool bt_gpi_mask[BTSS44_GPIO_PINS]; +}; + + +#endif // BTSS44_H diff --git a/ripcd/btss82.cpp b/ripcd/btss82.cpp new file mode 100644 index 00000000..ba43b0f8 --- /dev/null +++ b/ripcd/btss82.cpp @@ -0,0 +1,403 @@ +// btss82.cpp +// +// A Rivendell switcher driver for the BroadcastTools SS 8.2 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: btss82.cpp,v 1.14 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include + + +BtSs82::BtSs82(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Initialize Data Structures + // + bt_istate=0; + for(int i=0;imatrix(); + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + bt_gpis=matrix->gpis(); + bt_gpos=matrix->gpos(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + bt_device=new RDTTYDevice(); + if(tty->active()) { + bt_device->setName(tty->port()); + bt_device->setSpeed(tty->baudRate()); + bt_device->setWordLength(tty->dataBits()); + bt_device->setParity(tty->parity()); + bt_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; + + // + // Interval OneShots + // + bt_gpi_oneshot=new RDOneShot(this); + connect(bt_gpi_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpiOneshotData(void*))); + bt_gpo_oneshot=new RDOneShot(this); + connect(bt_gpo_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpoOneshotData(void*))); + + // + // The Poll Timer + // + QTimer *timer=new QTimer(this,"poll_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(processStatus())); + timer->start(BTSS82_POLL_INTERVAL); +} + + +BtSs82::~BtSs82() +{ + delete bt_device; + delete bt_gpi_oneshot; + delete bt_gpo_oneshot; +} + + +RDMatrix::Type BtSs82::type() +{ + return RDMatrix::BtSs82; +} + + +unsigned BtSs82::gpiQuantity() +{ + return bt_gpis; +} + + +unsigned BtSs82::gpoQuantity() +{ + return bt_gpos; +} + + +bool BtSs82::primaryTtyActive() +{ + return true; +} + + +bool BtSs82::secondaryTtyActive() +{ + return false; +} + + +void BtSs82::processCommand(RDMacro *cmd) +{ + char str[9]; + + switch(cmd->command()) { + case RDMacro::GO: + if((cmd->argQuantity()!=5)|| + ((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))|| + (cmd->arg(2).toInt()<1)||(cmd->arg(3).toInt()>bt_gpos)|| + (cmd->arg(2).toInt()>bt_gpos)|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(1).toString().lower()!="i"))|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(3).toInt()!=-1)&&(cmd->arg(1).toString().lower()=="i"))|| + (cmd->arg(4).toInt()<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(3).toInt()==0) { // Turn OFF + if(cmd->arg(4).toInt()==0) { + if(cmd->arg(1).toString().lower()=="i") { + if(bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + bt_gpi_state[cmd->arg(2).toInt()-1]=false; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%dF",BTSS82_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,false); + } + } + else { + if(cmd->echoRequested()) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + } + return; + } + } + else { + if(cmd->arg(3).toInt()==-1) { // Clear input + bt_gpi_mask[cmd->arg(2).toInt()-1]=false; + bt_device->writeBlock("*0SPA",5); + } + else { + if(cmd->arg(4).toInt()==0) { // Turn ON + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%dL",BTSS82_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + } + } + else { // Pulse + if(cmd->arg(1).toString().lower()=="i") { + if(!bt_gpi_state[cmd->arg(2).toInt()-1]) { + emit gpiChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpi_state[cmd->arg(2).toInt()-1]=true; + } + bt_gpi_mask[cmd->arg(2).toInt()-1]=true; + bt_gpi_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + if(cmd->arg(1).toString().lower()=="o") { + sprintf(str,"*%dOR%dP",BTSS82_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + emit gpoChanged(bt_matrix,cmd->arg(2).toInt()-1,true); + bt_gpo_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + } + } + } + } + if(cmd->echoRequested()) { + cmd->acknowledge(true); + emit rmlEcho(cmd); + } + break; + + case RDMacro::SA: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%d%02d%d",BTSS82_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SR: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"*%d%02dM%d",BTSS82_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>2)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toInt()==0) { + sprintf(str,"*%dM%d",BTSS82_UNIT_ID,cmd->arg(2).toInt()); + bt_device->writeBlock(str,4); + } + else { + sprintf(str,"*%d%02d%d",BTSS82_UNIT_ID, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + bt_device->writeBlock(str,5); + for(int i=1;iarg(1).toInt();i++) { + sprintf(str,"*%d%02dM%d",BTSS82_UNIT_ID, + i,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + for(int i=cmd->arg(1).toInt()+1;i<9;i++) { + sprintf(str,"*%d%02dM%d",BTSS82_UNIT_ID, + i,cmd->arg(2).toInt()); + bt_device->writeBlock(str,6); + } + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void BtSs82::processStatus() +{ + char buffer[256]; + int n; + int gpi; + + while((n=bt_device->readBlock(buffer,255))>0) { + for(int i=0;iwriteBlock("*0SPA",5); +} + + +void BtSs82::gpoOneshotData(void *data) +{ + emit gpoChanged(bt_matrix,(long)data,false); +} diff --git a/ripcd/btss82.h b/ripcd/btss82.h new file mode 100644 index 00000000..101a8dac --- /dev/null +++ b/ripcd/btss82.h @@ -0,0 +1,71 @@ +// btss82.h +// +// A Rivendell switcher driver for the BroadcastTools SS 8.2 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: btss82.h,v 1.11.8.1 2012/12/11 03:49:48 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef BTSS82_H +#define BTSS82_H + +#include +#include +#include +#include +#include + +#include + +#define BTSS82_UNIT_ID 0 +#define BTSS82_POLL_INTERVAL 100 +#define BTSS82_GPIO_PINS 16 + +class BtSs82 : public Switcher +{ + Q_OBJECT + public: + BtSs82(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~BtSs82(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void processStatus(); + void gpiOneshotData(void *data); + void gpoOneshotData(void *data); + + private: + RDTTYDevice *bt_device; + RDOneShot *bt_gpi_oneshot; + RDOneShot *bt_gpo_oneshot; + int bt_matrix; + int bt_inputs; + int bt_outputs; + int bt_gpis; + int bt_gpos; + int bt_istate; + bool bt_gpi_state[BTSS82_GPIO_PINS]; + bool bt_gpi_mask[BTSS82_GPIO_PINS]; +}; + + +#endif // BTSS82_H diff --git a/ripcd/globals.h b/ripcd/globals.h new file mode 100644 index 00000000..75d79e5c --- /dev/null +++ b/ripcd/globals.h @@ -0,0 +1,37 @@ +// globals.h +// +// Global declarations for the Rivendell Interprocess Communication Daemon +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: globals.h,v 1.11 2010/07/29 19:32:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + + +// +// Global Objects +// +extern RDConfig *ripcd_config; +extern RDCae *rdcae; +extern RDStation *rdstation; +extern QString ripcd_active_locks[MAX_MATRICES]; +extern void LogLine(RDConfig::LogPriority prio,const QString &line); + diff --git a/ripcd/harlond.cpp b/ripcd/harlond.cpp new file mode 100644 index 00000000..04ac4613 --- /dev/null +++ b/ripcd/harlond.cpp @@ -0,0 +1,446 @@ +// harlond.cpp +// +// A Rivendell switcher driver for the Harlond Virtual Mixer +// +// (C) Copyright 2002-2012 Fred Gleason +// +// $Id: harlond.cpp,v 1.2.2.2 2012/08/06 00:12:07 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include "globals.h" +#include "harlond.h" + +Harlond::Harlond(RDMatrix *matrix,QObject *parent) + : Switcher(matrix,parent) +{ + bt_recv_buffer=""; + + // + // Get Matrix Parameters + // + bt_ip_address=matrix->ipAddress(RDMatrix::Primary); + bt_tcp_port=matrix->ipPort(RDMatrix::Primary); + bt_password=matrix->password(RDMatrix::Primary); + bt_matrix=matrix->matrix(); + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + bt_start_cart=matrix->startCart(RDMatrix::Primary); + bt_stop_cart=matrix->stopCart(RDMatrix::Primary); + + // + // Reset Timers + // + bt_reset_mapper=new QSignalMapper(this); + connect(bt_reset_mapper,SIGNAL(mapped(int)),this,SLOT(resetTimeoutData(int))); + for(int i=0;isetMapping(bt_reset_timers.back(),i); + connect(bt_reset_timers.back(),SIGNAL(timeout()), + bt_reset_mapper,SLOT(map())); + } + + // + // Initialize TCP/IP Connection + // + bt_socket=new QSocket(this); + connect(bt_socket,SIGNAL(connected()),this,SLOT(socketConnectedData())); + connect(bt_socket,SIGNAL(disconnected()),this,SLOT(socketDisconnectedData())); + connect(bt_socket,SIGNAL(readyRead()),this,SLOT(socketReadyReadData())); + connect(bt_socket,SIGNAL(error(QAbstractSocket::SocketError)), + this,SLOT(socketErrorData(QAbstractSocket::SocketError))); + bt_watchdog_timer=new QTimer(this); + connect(bt_watchdog_timer,SIGNAL(timeout()),this,SLOT(watchdogTimeoutData())); + bt_watchdog_timer->start(5000,true); +} + + +Harlond::~Harlond() +{ + for(unsigned i=0;icommand()) { + case RDMacro::FS: // Fire Salvo + if(cmd->argQuantity()<2) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(!ProcessSalvo(cmd->rollupArgs(1))) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + + case RDMacro::GO: // GPO Set + if(cmd->argQuantity()!=5) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(!ProcessGpo(cmd->arg(2).toInt(),cmd->arg(3).toBool(), + cmd->arg(4).toInt())) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SL: // Switch Level + if(cmd->argQuantity()!=3) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(!SetInputLevel(cmd->arg(1).toInt(),cmd->arg(2).toInt())) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SA: // Switch Add + case RDMacro::SR: // Switch Remove + case RDMacro::ST: // Switch Take + if(cmd->argQuantity()!=3) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(!ProcessCrosspoint(cmd->command(),cmd->arg(1).toInt(), + cmd->arg(2).toInt())) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + break; + } +} + + +void Harlond::resetTimeoutData(int line) +{ + ProcessGpo(line,!bt_reset_states[line],0); +} + + +void Harlond::socketConnectedData() +{ + QString str=QString("PW ")+bt_password+"!"; + bt_socket->writeBlock(str,str.length()); + if(bt_start_cart>0) { + executeMacroCart(bt_start_cart); + } +} + + +void Harlond::socketDisconnectedData() +{ + bt_watchdog_timer->start(HARLOND_RECONNECT_INTERVAL,true); + LogLine(RDConfig::LogWarning,tr("connection to harlond device at ")+ + bt_ip_address.toString()+ + QString().sprintf(":%d ",bt_tcp_port)+ + tr("closed unexpectedly, attempting reconnect")); + if(bt_stop_cart>0) { + executeMacroCart(bt_stop_cart); + } +} + + +void Harlond::socketReadyReadData() +{ + char data[1500]; + int n; + while((n=bt_socket->readBlock(data,1500))>0) { + for(int i=0;istart(HARLOND_RECONNECT_INTERVAL,true); + switch(err) { + case QSocket::ErrConnectionRefused: + LogLine(RDConfig::LogWarning,tr("connection to harlond device at ")+ + bt_ip_address.toString()+QString().sprintf(":%d ",bt_tcp_port)+ + tr("refused, attempting reconnect")); + break; + + default: + LogLine(RDConfig::LogWarning,tr("received network error")+ + QString().sprintf(" %d ",err)+tr("from harlond device at ")+ + bt_ip_address.toString()+QString().sprintf(":%d ",bt_tcp_port)+", "+ + tr("attempting reconnect")); + break; + } +} + + +void Harlond::watchdogTimeoutData() +{ + if(bt_socket->state()!=QSocket::Connected) { + bt_socket->connectToHost(bt_ip_address.toString(),bt_tcp_port); + } +} + + +void Harlond::ProcessResponse(const QString &str) +{ + // LogLine(RDConfig::LogNotice,str); + QStringList cmds=cmds.split(" ",str); + + if(cmds[0]=="PW") { + if(cmds.size()==2) { + if(cmds[1]=="+") { + LogLine(RDConfig::LogInfo,tr("connection to harlond device at ")+ + bt_ip_address.toString()+QString().sprintf(":%d ",bt_tcp_port)+ + tr("established")); + bt_socket->writeBlock("SS!",3); + return; + } + } + LogLine(RDConfig::LogInfo,tr("connection to harlond device at ")+ + bt_ip_address.toString()+QString().sprintf(":%d ",bt_tcp_port)+ + tr("refused, invalid password")); + } + + if(cmds[0]=="ON") { + if(cmds.size()==2) { + emit gpiChanged(bt_matrix,cmds[1].toInt()-1,true); + } + } + + if(cmds[0]=="OF") { + if(cmds.size()==2) { + emit gpiChanged(bt_matrix,cmds[1].toInt()-1,false); + } + } +} + + +bool Harlond::ProcessSalvo(const QString &str) +{ + QString arg=QString("LL ")+str+"!"; + bt_socket->writeBlock(arg,arg.length()); + return true; +} + + +bool Harlond::ProcessGpo(int line,bool state,int msecs) +{ + QString code="OF"; + QString str; + + if((line<1)||(line>bt_inputs)) { + return false; + } + if(state) { + code="ON"; + } + bt_reset_states[line]=state; + str=code+QString().sprintf(" %02d!",line); + bt_socket->writeBlock(str,str.length()); + bt_reset_timers[line]->stop(); + if(msecs>0) { + bt_reset_timers[line]->start(msecs,true); + } + + return true; +} + + +bool Harlond::SetInputLevel(int input,int db) +{ + QString str; + + if((input<1)||(input>bt_inputs)) { + return false; + } + str=QString().sprintf("VL %02d %04d!",input,db); + bt_socket->writeBlock(str,str.length()); + + return true; +} + + +bool Harlond::ProcessCrosspoint(RDMacro::Command cmd,int input,int output) +{ + bool ret=false; + + if((input<1)||(input>bt_inputs)) { + return false; + } + switch(cmd) { + case RDMacro::ST: + ret=TakeCrosspoint(input,output); + break; + + case RDMacro::SA: + ret=AddCrosspoint(input,output); + break; + + case RDMacro::SR: + ret=RemoveCrosspoint(input,output); + break; + + default: + break; + } + return ret; +} + + +bool Harlond::TakeCrosspoint(int input,int output) +{ + QString str; + QString code=GetBussCode(output); + + if(code.isEmpty()) { + return false; + } + AddCrosspoint(input,output); + for(int i=1;iwriteBlock(str,str.length()); + return true; +} + + +bool Harlond::RemoveCrosspoint(int input,int output) +{ + QString str; + QString code=GetBussCode(output); + + if(code.isEmpty()) { + return false; + } + str=code+QString().sprintf(" %02d -!",input); + bt_socket->writeBlock(str,str.length()); + return true; +} + + +QString Harlond::GetBussCode(int output) +{ + QString code=""; + QString str; + + if((bt_outputs<1)||(output>=bt_outputs)) { + return QString(); + } + switch(output) { + case 1: // Program + code="PG"; + break; + + case 2: // Audition + code="AU"; + break; + + case 3: // Utility + code="UT"; + break; + + case 4: // Cue + code="QU"; + break; + + default: + return QString(); + } + return code; +} diff --git a/ripcd/harlond.h b/ripcd/harlond.h new file mode 100644 index 00000000..ff3af016 --- /dev/null +++ b/ripcd/harlond.h @@ -0,0 +1,90 @@ +// harlond.h +// +// A Rivendell switcher driver for the Harlond Virtual Mixer +// +// (C) Copyright 2002-2012 Fred Gleason +// +// $Id: harlond.h,v 1.2.2.2 2012/08/06 00:12:07 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef HARLOND_H +#define HARLOND_H + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include "switcher.h" + +#define HARLOND_RECONNECT_INTERVAL 10000 + +class Harlond : public Switcher +{ + Q_OBJECT + public: + Harlond(RDMatrix *matrix,QObject *parent=0); + ~Harlond(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void resetTimeoutData(int line); + void socketConnectedData(); + void socketDisconnectedData(); + void socketReadyReadData(); + void socketErrorData(int err); + void watchdogTimeoutData(); + + private: + void ProcessResponse(const QString &str); + bool ProcessSalvo(const QString &str); + bool ProcessGpo(int line,bool state,int msecs); + bool SetInputLevel(int input,int db); + bool ProcessCrosspoint(RDMacro::Command cmd,int input,int output); + bool TakeCrosspoint(int input,int output); + bool AddCrosspoint(int input,int output); + bool RemoveCrosspoint(int input,int output); + QString GetBussCode(int output); + QSocket *bt_socket; + QString bt_recv_buffer; + QTimer *bt_watchdog_timer; + QHostAddress bt_ip_address; + uint16_t bt_tcp_port; + QString bt_password; + int bt_matrix; + int bt_inputs; + int bt_outputs; + unsigned bt_start_cart; + unsigned bt_stop_cart; + QSignalMapper *bt_reset_mapper; + std::vector bt_reset_timers; + std::vector bt_reset_states; +}; + + +#endif // HARLOND_H diff --git a/ripcd/livewire_lwrpaudio.cpp b/ripcd/livewire_lwrpaudio.cpp new file mode 100644 index 00000000..f342bd44 --- /dev/null +++ b/ripcd/livewire_lwrpaudio.cpp @@ -0,0 +1,266 @@ +// livewire_lwrpaudio.cpp +// +// A Rivendell LWRP audio switcher driver for LiveWire networks. +// +// (C) Copyright 2002-2013 Fred Gleason +// +// $Id: livewire_lwrpaudio.cpp,v 1.1.2.1 2013/11/17 04:27:06 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + + +LiveWireLwrpAudio::LiveWireLwrpAudio(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + QString sql; + RDSqlQuery *q; + + // + // Get Matrix Parameters + // + livewire_stationname=rdstation->name(); + livewire_matrix=matrix->matrix(); + + // + // Load The Node List + // + sql=QString().sprintf("select HOSTNAME,TCP_PORT,PASSWORD,BASE_OUTPUT \ + from SWITCHER_NODES where (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)",(const char *)livewire_stationname, + livewire_matrix); + q=new RDSqlQuery(sql); + while(q->next()) { + livewire_nodes.push_back(new RDLiveWire(livewire_nodes.size(),this)); + connect(livewire_nodes.back(),SIGNAL(connected(unsigned)), + this,SLOT(nodeConnectedData(unsigned))); + connect(livewire_nodes.back(), + SIGNAL(sourceChanged(unsigned,RDLiveWireSource *)), + this, + SLOT(sourceChangedData(unsigned,RDLiveWireSource *))); + connect(livewire_nodes.back(), + SIGNAL(destinationChanged(unsigned,RDLiveWireDestination *)), + this, + SLOT(destinationChangedData(unsigned,RDLiveWireDestination *))); + connect(livewire_nodes.back(), + SIGNAL(gpoConfigChanged(unsigned,unsigned,unsigned)), + this, + SLOT(gpoConfigChangedData(unsigned,unsigned,unsigned))); + connect(livewire_nodes.back(), + SIGNAL(gpiChanged(unsigned,unsigned,unsigned,bool)), + this, + SLOT(gpiChangedData(unsigned,unsigned,unsigned,bool))); + connect(livewire_nodes.back(), + SIGNAL(gpoChanged(unsigned,unsigned,unsigned,bool)), + this, + SLOT(gpoChangedData(unsigned,unsigned,unsigned,bool))); + connect(livewire_nodes.back(), + SIGNAL(watchdogStateChanged(unsigned,const QString &)), + this,SLOT(watchdogStateChangedData(unsigned,const QString &))); + livewire_nodes.back()->connectToHost(q->value(0).toString(), + q->value(1).toInt(), + q->value(2).toString(), + q->value(3).toUInt()); + } + delete q; +} + + +LiveWireLwrpAudio::~LiveWireLwrpAudio() +{ + for(unsigned i=0;icommand()) { + case RDMacro::ST: + input=cmd->arg(1).toUInt(); + if(input>RD_LIVEWIRE_MAX_SOURCE) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + output=cmd->arg(2).toUInt(); + if(output>RD_LIVEWIRE_MAX_SOURCE) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + + // + // Find the destination node + // + for(unsigned i=0;i=node->baseOutput())&& + (output<(node->baseOutput()+node->destinations()))) { + dest_node=node; + } + } + if(dest_node==NULL) { // No such output! + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + dest_node->setRoute(input,output-dest_node->baseOutput()); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void LiveWireLwrpAudio::nodeConnectedData(unsigned id) +{ + LogLine(RDConfig::LogInfo,QString(). + sprintf("connection established to LiveWire node at \"%s\"", + (const char *)livewire_nodes[id]->hostname())); +} + + +void LiveWireLwrpAudio::sourceChangedData(unsigned id,RDLiveWireSource *src) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("delete from INPUTS where \ + (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&\ + (NODE_HOSTNAME=\"%s\")&&\ + (NODE_TCP_PORT=%d)&&\ + (NODE_SLOT=%d)", + (const char *)livewire_stationname, + livewire_matrix, + (const char *)livewire_nodes[id]->hostname(), + livewire_nodes[id]->tcpPort(), + src->slotNumber()); + q=new RDSqlQuery(sql); + delete q; + + if(src->rtpEnabled()) { + sql=QString().sprintf("insert into INPUTS set \ + STATION_NAME=\"%s\",\ + MATRIX=%d,\ + NODE_HOSTNAME=\"%s\",\ + NODE_TCP_PORT=%d,\ + NODE_SLOT=%d,\ + NAME=\"%s\",\ + NUMBER=%d", + (const char *)livewire_stationname, + livewire_matrix, + (const char *)livewire_nodes[id]->hostname(), + livewire_nodes[id]->tcpPort(), + src->slotNumber(), + (const char *)src->primaryName(), + src->channelNumber()); + q=new RDSqlQuery(sql); + delete q; + } +} + + +void LiveWireLwrpAudio::destinationChangedData(unsigned id,RDLiveWireDestination *dst) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("delete from OUTPUTS where \ + (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&\ + (NODE_HOSTNAME=\"%s\")&&\ + (NODE_TCP_PORT=%d)&&\ + (NODE_SLOT=%d)", + (const char *)livewire_stationname, + livewire_matrix, + (const char *)livewire_nodes[id]->hostname(), + livewire_nodes[id]->tcpPort(), + dst->slotNumber()); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("insert into OUTPUTS set \ + STATION_NAME=\"%s\",\ + MATRIX=%d,\ + NODE_HOSTNAME=\"%s\",\ + NODE_TCP_PORT=%d,\ + NODE_SLOT=%d,\ + NAME=\"%s\",\ + NUMBER=%d", + (const char *)livewire_stationname, + livewire_matrix, + (const char *)livewire_nodes[id]->hostname(), + livewire_nodes[id]->tcpPort(), + dst->slotNumber(), + (const char *)dst->primaryName(), + livewire_nodes[id]->baseOutput()+dst->slotNumber()-1); + q=new RDSqlQuery(sql); + delete q; +} + + +void LiveWireLwrpAudio::watchdogStateChangedData(unsigned id,const QString &msg) +{ + LogLine(RDConfig::LogNotice,msg); +} diff --git a/ripcd/livewire_lwrpaudio.h b/ripcd/livewire_lwrpaudio.h new file mode 100644 index 00000000..211021bf --- /dev/null +++ b/ripcd/livewire_lwrpaudio.h @@ -0,0 +1,66 @@ +// livewire_lwrpaudio.h +// +// A Rivendell LWRP audio switcher driver for LiveWire networks. +// +// (C) Copyright 2002-2013 Fred Gleason +// +// $Id: livewire_lwrpaudio.h,v 1.1.2.1 2013/11/17 04:27:06 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIVEWIRE_LWRPAUDIO_H +#define LIVEWIRE_LWRPAUDIO_H + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +class LiveWireLwrpAudio : public Switcher +{ + Q_OBJECT + public: + LiveWireLwrpAudio(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~LiveWireLwrpAudio(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void nodeConnectedData(unsigned id); + void sourceChangedData(unsigned id,RDLiveWireSource *src); + void destinationChangedData(unsigned id,RDLiveWireDestination *dst); + void watchdogStateChangedData(unsigned id,const QString &msg); + + private: + QString livewire_stationname; + int livewire_matrix; + std::vector livewire_nodes; +}; + + +#endif // LIVEWIRE_LWRPAUDIO_H diff --git a/ripcd/livewire_lwrpgpio.cpp b/ripcd/livewire_lwrpgpio.cpp new file mode 100644 index 00000000..9a5f9000 --- /dev/null +++ b/ripcd/livewire_lwrpgpio.cpp @@ -0,0 +1,227 @@ +// livewire_lwrpgpio.cpp +// +// A Rivendell LWRP GPIO driver for LiveWire networks. +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: livewire_lwrpgpio.cpp,v 1.1.2.1 2013/11/17 02:03:21 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + +#include "livewire_lwrpgpio.h" + +LiveWireLwrpGpio::LiveWireLwrpGpio(RDMatrix *matrix,QObject *parent, + const char *name) + : Switcher(matrix,parent,name) +{ + gpio_is_virtual=matrix->layer()=='V'; + + // + // Node Interface + // + gpio_livewire=new RDLiveWire(0,this); + if(gpio_is_virtual) { + connect(gpio_livewire,SIGNAL(gpiChanged(unsigned,unsigned,unsigned,bool)), + this,SLOT(gpiChangedData(unsigned,unsigned,unsigned,bool))); + connect(gpio_livewire,SIGNAL(gpoChanged(unsigned,unsigned,unsigned,bool)), + this,SLOT(gpoChangedData(unsigned,unsigned,unsigned,bool))); + } + else { + connect(gpio_livewire,SIGNAL(gpiChanged(unsigned,unsigned,unsigned,bool)), + this,SLOT(gpoChangedData(unsigned,unsigned,unsigned,bool))); + connect(gpio_livewire,SIGNAL(gpoChanged(unsigned,unsigned,unsigned,bool)), + this,SLOT(gpiChangedData(unsigned,unsigned,unsigned,bool))); + } + connect(gpio_livewire,SIGNAL(connected(unsigned)), + this,SLOT(connectedData(unsigned))); + connect(gpio_livewire,SIGNAL(watchdogStateChanged(unsigned,const QString &)), + this,SLOT(watchdogStateChangedData(unsigned,const QString &))); + gpio_livewire->connectToHost(matrix->ipAddress(RDMatrix::Primary).toString(), + RD_LIVEWIRE_DEFAULT_TCP_PORT, + matrix->password(RDMatrix::Primary),0); +} + + +LiveWireLwrpGpio::~LiveWireLwrpGpio() +{ + delete gpio_livewire; +} + + +RDMatrix::Type LiveWireLwrpGpio::type() +{ + return RDMatrix::LiveWireLwrpGpio; +} + + +unsigned LiveWireLwrpGpio::gpiQuantity() +{ + return gpio_livewire->gpis(); +} + + +unsigned LiveWireLwrpGpio::gpoQuantity() +{ + return gpio_livewire->gpos(); +} + + +bool LiveWireLwrpGpio::primaryTtyActive() +{ + return false; +} + + +bool LiveWireLwrpGpio::secondaryTtyActive() +{ + return false; +} + + +void LiveWireLwrpGpio::processCommand(RDMacro *cmd) +{ + int slot; + int line; + + switch(cmd->command()) { + case RDMacro::GO: + if((cmd->argQuantity()!=5)|| + (cmd->arg(2).toInt()<1)|| + ((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(((cmd->arg(1).toString().lower()=="i")&& + (cmd->arg(2).toUInt()>gpio_gpi_limit))|| + ((cmd->arg(1).toString().lower()=="o")&& + (cmd->arg(2).toUInt()>gpio_gpo_limit))) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + slot=(cmd->arg(2).toInt()-1)/5; + line=(cmd->arg(2).toInt()-1)%5; + if(cmd->arg(1).toString().lower()=="i") { + if(cmd->arg(3).toInt()==0) { + if(gpio_is_virtual) { + gpio_livewire->gpoReset(slot,line,cmd->arg(4).toInt()); + } + else { + gpio_livewire->gpiReset(slot,line,cmd->arg(4).toInt()); + } + } + else { + if(gpio_is_virtual) { + gpio_livewire->gpoSet(slot,line,cmd->arg(4).toInt()); + } + else { + gpio_livewire->gpiSet(slot,line,cmd->arg(4).toInt()); + } + } + } + if(cmd->arg(1).toString().lower()=="o") { + if(cmd->arg(3).toInt()==0) { + if(gpio_is_virtual) { + gpio_livewire->gpiReset(slot,line,cmd->arg(4).toInt()); + } + else { + gpio_livewire->gpoReset(slot,line,cmd->arg(4).toInt()); + } + } + else { + if(gpio_is_virtual) { + gpio_livewire->gpiSet(slot,line,cmd->arg(4).toInt()); + } + else { + gpio_livewire->gpoSet(slot,line,cmd->arg(4).toInt()); + } + } + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void LiveWireLwrpGpio::gpiChangedData(unsigned id,unsigned slot,unsigned line, + bool state) +{ + emit gpoChanged(matrixNumber(),slot*RD_LIVEWIRE_GPIO_BUNDLE_SIZE+line,state); +} + + +void LiveWireLwrpGpio::gpoChangedData(unsigned id,unsigned slot,unsigned line, + bool state) +{ + emit gpiChanged(matrixNumber(),slot*RD_LIVEWIRE_GPIO_BUNDLE_SIZE+line,state); +} + + +void LiveWireLwrpGpio::connectedData(unsigned id) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("update MATRICES set GPIS=%u,GPOS=%u ", + RD_LIVEWIRE_GPIO_BUNDLE_SIZE*gpio_livewire->gpis(), + RD_LIVEWIRE_GPIO_BUNDLE_SIZE*gpio_livewire->gpos())+ + "where (STATION_NAME=\""+RDEscapeString(stationName())+"\")&&"+ + QString().sprintf("(MATRIX=%u)",matrixNumber()); + q=new RDSqlQuery(sql); + delete q; + + for(int i=0;igpis();i++) { + insertGpioEntry(false,i+1); + } + for(int i=0;igpos();i++) { + insertGpioEntry(true,i+1); + } + if(gpio_is_virtual) { + gpio_gpi_limit=RD_LIVEWIRE_GPIO_BUNDLE_SIZE*gpio_livewire->gpos(); + gpio_gpo_limit=RD_LIVEWIRE_GPIO_BUNDLE_SIZE*gpio_livewire->gpis(); + } + else { + gpio_gpi_limit=RD_LIVEWIRE_GPIO_BUNDLE_SIZE*gpio_livewire->gpis(); + gpio_gpo_limit=RD_LIVEWIRE_GPIO_BUNDLE_SIZE*gpio_livewire->gpos(); + } + + syslog(LOG_DEBUG,"livewire LWRP gpio driver connected to %s at %s:%d", + (const char *)gpio_livewire->deviceName(), + (const char *)gpio_livewire->hostname(), + 0xFFFF&gpio_livewire->tcpPort()); +} + + +void LiveWireLwrpGpio::watchdogStateChangedData(unsigned id,const QString &msg) +{ + syslog(LOG_WARNING,"livewire LWRP driver watchdog update for device %s at %s:%d: %s", + (const char *)gpio_livewire->deviceName(), + (const char *)gpio_livewire->hostname(), + 0xFFFF&gpio_livewire->tcpPort(), + (const char *)msg); +} diff --git a/ripcd/livewire_lwrpgpio.h b/ripcd/livewire_lwrpgpio.h new file mode 100644 index 00000000..37713214 --- /dev/null +++ b/ripcd/livewire_lwrpgpio.h @@ -0,0 +1,72 @@ +// livewire_lwrpgpio.h +// +// A Rivendell LWRP GPIO driver for LiveWire networks. +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: livewire_lwrpgpio.h,v 1.1.2.1 2013/11/17 02:03:21 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIVEWIRE_LWRPGPIO_H +#define LIVEWIRE_LWRPGPIO_H + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +class LiveWireLwrpGpio : public Switcher +{ + Q_OBJECT + public: + LiveWireLwrpGpio(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~LiveWireLwrpGpio(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void gpiChangedData(unsigned id,unsigned slot,unsigned line,bool state); + void gpoChangedData(unsigned id,unsigned slot,unsigned line,bool state); + void connectedData(unsigned id); + void watchdogStateChangedData(unsigned id,const QString &msg); + + private: + RDLiveWire *gpio_livewire; + bool gpio_is_virtual; + unsigned gpio_gpi_limit; + unsigned gpio_gpo_limit; +}; + + +#endif // LIVEWIRE_LWRPGPIO_H diff --git a/ripcd/livewire_mcastgpio.cpp b/ripcd/livewire_mcastgpio.cpp new file mode 100644 index 00000000..fada5168 --- /dev/null +++ b/ripcd/livewire_mcastgpio.cpp @@ -0,0 +1,414 @@ +// livewire_mcastgpio.cpp +// +// A Rivendell multicast GPIO driver for LiveWire networks. +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: livewire_mcastgpio.cpp,v 1.1.2.1 2013/11/17 03:40:27 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +LiveWireMcastGpio::LiveWireMcastGpio(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + livewire_gpio_notify=NULL; + + long sockopt; + struct sockaddr_in sa; + QString sql; + RDSqlQuery *q; + + // + // Get Matrix Parameters + // + livewire_stationname=rdstation->name(); + livewire_matrix=matrix->matrix(); + livewire_gpios=matrix->gpis(); + livewire_interface_addr=matrix->ipAddress(RDMatrix::Primary); + + // + // Initialize Serial Numbers + // + time_t t; + t=time(&t); + srand(t); + livewire_gpio_send_serial=rand(); + + // + // Timers + // + livewire_gpi_timer_mapper=new QSignalMapper(this); + connect(livewire_gpi_timer_mapper,SIGNAL(mapped(int)), + this,SLOT(gpiTimeoutData(int))); + for(unsigned i=0;isetMapping(livewire_gpi_timers.back(),i); + connect(livewire_gpi_timers.back(),SIGNAL(timeout()), + livewire_gpi_timer_mapper,SLOT(map())); + } + livewire_gpo_timer_mapper=new QSignalMapper(this); + connect(livewire_gpo_timer_mapper,SIGNAL(mapped(int)), + this,SLOT(gpoTimeoutData(int))); + for(unsigned i=0;isetMapping(livewire_gpo_timers.back(),i); + connect(livewire_gpo_timers.back(),SIGNAL(timeout()), + livewire_gpo_timer_mapper,SLOT(map())); + livewire_gpo_states.push_back(false); + } + + // + // GPIO Write Socket + // + if((livewire_gpio_write_socket=socket(PF_INET,SOCK_DGRAM,0))<0) { + syslog(LOG_ERR,"unable to create GPIO write socket [%s]",strerror(errno)); + return; + } + sockopt=O_NONBLOCK; + fcntl(livewire_gpio_write_socket,F_SETFL,sockopt); + memset(&sa,0,sizeof(sa)); + sa.sin_family=AF_INET; + sa.sin_port=htons(htons(RD_LIVEWIRE_GPIO_SEND_PORT)); + sa.sin_addr.s_addr= + htonl(matrix->ipAddress(RDMatrix::Primary).ip4Addr()); + if(bind(livewire_gpio_write_socket,(struct sockaddr *)&sa,sizeof(sa))<0) { + syslog(LOG_ERR,"unable to bind GPIO write socket [%s]",strerror(errno)); + return; + } + + // + // GPIO Read Socket + // + if((livewire_gpio_read_socket=socket(PF_INET,SOCK_DGRAM,0))<0) { + syslog(LOG_ERR,"unable to create GPIO read socket [%s]",strerror(errno)); + return; + } + sockopt=O_NONBLOCK; + fcntl(livewire_gpio_read_socket,F_SETFL,sockopt); + memset(&sa,0,sizeof(sa)); + sa.sin_family=AF_INET; + sa.sin_port=htons(RD_LIVEWIRE_GPIO_RECV_PORT); + sa.sin_addr.s_addr=htonl(INADDR_ANY); + if(bind(livewire_gpio_read_socket,(struct sockaddr *)&sa,sizeof(sa))<0) { + syslog(LOG_ERR,"unable to bind GPIO socket [%s]",strerror(errno)); + return; + } + livewire_gpio_notify= + new QSocketNotifier(livewire_gpio_read_socket,QSocketNotifier::Read,this); + connect(livewire_gpio_notify,SIGNAL(activated(int)), + this,SLOT(gpioActivatedData(int))); + subscribe(QHostAddress(RD_LIVEWIRE_GPIO_MCAST_ADDR)); + + // + // Source Table + // + sql=QString("select SLOT,SOURCE_NUMBER,IP_ADDRESS from LIVEWIRE_GPIO_SLOTS ")+ + "where (STATION_NAME=\""+RDEscapeString(livewire_stationname)+"\")&&"+ + QString().sprintf("(MATRIX=%d) ",livewire_matrix)+ + "order by SLOT"; + q=new RDSqlQuery(sql); + while(q->next()) { + livewire_source_numbers[q->value(0).toInt()]=q->value(1).toInt(); + livewire_surface_addresses[q->value(0).toInt()]= + QHostAddress(q->value(2).toString()); + } + delete q; +} + + +LiveWireMcastGpio::~LiveWireMcastGpio() +{ + if(livewire_gpio_notify!=NULL) { + close(livewire_gpio_read_socket); + delete livewire_gpio_notify; + close(livewire_gpio_write_socket); + } + for(unsigned i=0;icommand()) { + case RDMacro::GO: + if((cmd->argQuantity()!=5)|| + (cmd->arg(2).toInt()<1)|| + (cmd->arg(2).toInt()>(int)livewire_gpios)|| + ((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + + if(cmd->arg(1).toString().lower()=="i") { + emit gpiChanged(livewire_matrix,cmd->arg(2).toInt()-1, + cmd->arg(3).toInt()); + if(cmd->arg(4).toInt()>0) { + livewire_gpi_timers[cmd->arg(2).toInt()-1]-> + start(cmd->arg(4).toInt(),true); + } + } + if(cmd->arg(1).toString().lower()=="o") { + slot=(cmd->arg(2).toInt()-1)/5; + line=(cmd->arg(2).toInt()-1)%5; + if(livewire_source_numbers[slot]<=0) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(4).toInt()>0) { + livewire_gpo_timers[cmd->arg(2).toInt()-1]-> + start(cmd->arg(4).toInt(),true); + } + ProcessGpo(livewire_source_numbers[slot],line,cmd->arg(3).toInt()); + livewire_gpo_states[cmd->arg(2).toInt()-1]=cmd->arg(3).toInt(); + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void LiveWireMcastGpio::gpioActivatedData(int sock) +{ + int n; + char data[1500]; + struct sockaddr_in sa; + socklen_t sa_len=sizeof(sa); + uint32_t serial; + + while((n=recvfrom(livewire_gpio_read_socket,data,1500,MSG_DONTWAIT, + (struct sockaddr *)(&sa),&sa_len))>0) { + serial=((0xFF&data[4])<<24)+((0xFF&data[5])<<16)+((0xFF&data[6])<<8)+ + (0xFF&data[7]); + if(livewire_gpio_recv_serials[sa.sin_addr.s_addr]!=(serial-1)) { + livewire_gpio_recv_serials[sa.sin_addr.s_addr]=serial; + ProcessGpi(QHostAddress(ntohl(sa.sin_addr.s_addr)), + ((0xFF&data[23])<<8)+(0xFF&data[24]),0x08-(0xff&data[25]), + (data[27]&0x40)!=0,(data[27]&0x0A)!=0); + } + } +} + + +void LiveWireMcastGpio::gpiTimeoutData(int gpi) +{ + emit gpiChanged(livewire_matrix,gpi,false); +} + + +void LiveWireMcastGpio::gpoTimeoutData(int gpo) +{ + int slot=gpo/5; + int line=gpo%5; + + if(livewire_source_numbers[slot]>0) { + ProcessGpo(livewire_source_numbers[slot],line,!livewire_gpo_states[gpo]); + livewire_gpo_states[gpo]=!livewire_gpo_states[gpo]; + } +} + + +void LiveWireMcastGpio::ProcessGpi(const QHostAddress &src_addr,int chan, + unsigned line,bool state,bool pulse) +{ + for(std::map::const_iterator it=livewire_source_numbers.begin(); + it!=livewire_source_numbers.end();it++) { + if((it->second==chan)&& + ((livewire_surface_addresses[it->first].isNull())|| + (livewire_surface_addresses[it->first]==src_addr))) { + emit gpiChanged(livewire_matrix,5*it->first+line,state); + if(pulse) { + livewire_gpi_timers[5*it->first+line]-> + start(RD_LIVEWIRE_GPIO_PULSE_WIDTH,true); + } + } + } +} + + +void LiveWireMcastGpio::ProcessGpo(int chan,unsigned line,bool state) +{ + // + // Destination Address + // + struct sockaddr_in sa; + memset(&sa,0,sizeof(sa)); + sa.sin_family=AF_INET; + sa.sin_port=htons(RD_LIVEWIRE_GPIO_SEND_PORT); + sa.sin_addr.s_addr= + htonl(QHostAddress(RD_LIVEWIRE_GPIO_MCAST_ADDR).toIPv4Address()); + + /* + * FIXME: Sending this to the mcast addr causes ALL instances + * of the source to switch. How does one specify a particular + * surface? Sending to the surface addr does not work! + * + + for(std::map::const_iterator it=livewire_source_numbers.begin(); + it!=livewire_source_numbers.end();it++) { + if((it->second==chan)&&(!livewire_surface_addresses[it->first].isNull())) { + sa.sin_addr.s_addr= + htonl(livewire_surface_addresses[it->first].toIPv4Address()); + } + } + syslog(LOG_NOTICE,"using %s", + (const char *)QHostAddress(ntohl(sa.sin_addr.s_addr)).toString()); + */ + + char data[28]={0x03,0x00,0x02,0x07,0xC6,0x04,0x55,0x1E, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 'I','N','D','I',0x00,0x01,0x00,0x00, + 0x00,0x00,0x07,0x00}; + data[4]=0xFF&(livewire_gpio_send_serial>>24); + data[5]=0xFF&(livewire_gpio_send_serial>>16); + data[6]=0xFF&(livewire_gpio_send_serial>>8); + data[7]=0xFF&livewire_gpio_send_serial; + data[23]=0xFF&(chan>>8); + data[24]=0xFF&chan; + data[25]=0xFF&(0x0D-line); + data[27]=0xFF&state; + sendto(livewire_gpio_write_socket,data,28,MSG_DONTWAIT, + (struct sockaddr *)(&sa),sizeof(sa)); + livewire_gpio_send_serial++; + data[4]=0xFF&(livewire_gpio_send_serial>>24); + data[5]=0xFF&(livewire_gpio_send_serial>>16); + data[6]=0xFF&(livewire_gpio_send_serial>>8); + data[7]=0xFF&livewire_gpio_send_serial; + sendto(livewire_gpio_write_socket,data,28,MSG_DONTWAIT, + (struct sockaddr *)(&sa),sizeof(sa)); + livewire_gpio_send_serial++; +} + + +QString LiveWireMcastGpio::AddressString(uint32_t addr) const +{ + return QString().sprintf("%d.%d.%d.%d", + 0xFF&addr, + 0xFF&(addr>>8), + 0xFF&(addr>>16), + 0xFF&(addr>>24)); +} + + +void LiveWireMcastGpio::subscribe(const QHostAddress &addr) const +{ + subscribe(htonl(addr.toIPv4Address())); +} + + +void LiveWireMcastGpio::subscribe(const uint32_t addr) const +{ + struct ip_mreqn mreq; + + memset(&mreq,0,sizeof(mreq)); + mreq.imr_multiaddr.s_addr=addr; + mreq.imr_address.s_addr=htonl(livewire_interface_addr.toIPv4Address()); + mreq.imr_ifindex=0; + if(setsockopt(livewire_gpio_read_socket,SOL_IP,IP_ADD_MEMBERSHIP,&mreq, + sizeof(mreq))!=0) { + if(errno!=EADDRINUSE) { + syslog(LOG_WARNING,"unable to subscribe to %s on %s [%s]", + (const char *)AddressString(addr), + (const char *)livewire_interface_addr.toString(), + strerror(errno)); + } + } +} + + +void LiveWireMcastGpio::unsubscribe(const QHostAddress &addr) const +{ + unsubscribe(htonl(addr.toIPv4Address())); +} + + +void LiveWireMcastGpio::unsubscribe(const uint32_t addr) const +{ + struct ip_mreqn mreq; + + memset(&mreq,0,sizeof(mreq)); + mreq.imr_multiaddr.s_addr=htonl(addr); + mreq.imr_address.s_addr=htonl(livewire_interface_addr.toIPv4Address()); + mreq.imr_ifindex=0; + if(setsockopt(livewire_gpio_read_socket,SOL_IP,IP_DROP_MEMBERSHIP,&mreq, + sizeof(mreq))!=0) { + if(errno!=ENODEV) { + syslog(LOG_WARNING,"unable to unsubscribe from %s on %s [%s]", + (const char *)AddressString(addr), + (const char *)livewire_interface_addr.toString(), + strerror(errno)); + } + } +} diff --git a/ripcd/livewire_mcastgpio.h b/ripcd/livewire_mcastgpio.h new file mode 100644 index 00000000..ffffb23b --- /dev/null +++ b/ripcd/livewire_mcastgpio.h @@ -0,0 +1,92 @@ +// livewire_mcastgpio.h +// +// A Rivendell multicast GPIO driver for LiveWire networks. +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: livewire_mcastgpio.h,v 1.1.2.1 2013/11/17 03:40:27 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LIVEWIRE_MCASTGPIO_H +#define LIVEWIRE_MCASTGPIO_H + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +class LiveWireMcastGpio : public Switcher +{ + Q_OBJECT + public: + LiveWireMcastGpio(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~LiveWireMcastGpio(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void gpioActivatedData(int sock); + void gpiTimeoutData(int gpo); + void gpoTimeoutData(int gpo); + + private: + void ProcessGpi(const QHostAddress &src_addr,int chan,unsigned line, + bool state,bool pulse); + void ProcessGpo(int chan,unsigned line,bool state); + QString AddressString(uint32_t addr) const; + void subscribe(const QHostAddress &addr) const; + void subscribe(const uint32_t addr) const; + void unsubscribe(const QHostAddress &addr) const; + void unsubscribe(const uint32_t addr) const; + QString livewire_stationname; + int livewire_matrix; + unsigned livewire_gpios; + QHostAddress livewire_interface_addr; + int livewire_gpio_read_socket; + int livewire_gpio_write_socket; + QSocketNotifier *livewire_gpio_notify; + std::map livewire_source_numbers; + std::map livewire_surface_addresses; + uint32_t livewire_gpio_send_serial; + std::map livewire_gpio_recv_serials; + QSignalMapper *livewire_gpi_timer_mapper; + std::vector livewire_gpi_timers; + QSignalMapper *livewire_gpo_timer_mapper; + std::vector livewire_gpo_timers; + std::vector livewire_gpo_states; +}; + + +#endif // LIVEWIRE_MCASTGPIO_H diff --git a/ripcd/loaddrivers.cpp b/ripcd/loaddrivers.cpp new file mode 100644 index 00000000..c498c89a --- /dev/null +++ b/ripcd/loaddrivers.cpp @@ -0,0 +1,213 @@ +// loaddrivers.cpp +// +// Load Switcher drivers for ripcd(8) +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: loaddrivers.cpp,v 1.1.8.9 2014/02/17 02:19:03 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +bool MainObject::LoadSwitchDriver(int matrix_num) +{ + RDMatrix *matrix=new RDMatrix(rdstation->name(),matrix_num); + + switch(matrix->type()) { + case RDMatrix::Acu1p: + ripcd_switcher[matrix_num]=new Acu1p(matrix,this); + break; + + case RDMatrix::Am16: + ripcd_switcher[matrix_num]=new Am16(matrix,this); + break; + + case RDMatrix::Bt10x1: + ripcd_switcher[matrix_num]=new Bt10x1(matrix,this); + break; + + case RDMatrix::Bt16x1: + ripcd_switcher[matrix_num]=new Bt16x1(matrix,this); + break; + + case RDMatrix::Bt16x2: + ripcd_switcher[matrix_num]=new Bt16x2(matrix,this); + break; + + case RDMatrix::Bt8x2: + ripcd_switcher[matrix_num]=new Bt8x2(matrix,this); + break; + + case RDMatrix::BtAcs82: + ripcd_switcher[matrix_num]=new BtAcs82(matrix,this); + break; + + case RDMatrix::BtSentinel4Web: + ripcd_switcher[matrix_num]=new BtSentinel4Web(matrix,this); + break; + + case RDMatrix::BtSrc16: + ripcd_switcher[matrix_num]=new BtSrc16(matrix,this); + break; + + case RDMatrix::BtSrc8III: + ripcd_switcher[matrix_num]=new BtSrc8Iii(matrix,this); + break; + + case RDMatrix::BtSs124: + ripcd_switcher[matrix_num]=new BtSs124(matrix,this); + break; + + case RDMatrix::BtSs164: + ripcd_switcher[matrix_num]=new BtSs164(matrix,this); + break; + + case RDMatrix::BtSs42: + ripcd_switcher[matrix_num]=new BtSs42(matrix,this); + break; + + case RDMatrix::BtSs44: + ripcd_switcher[matrix_num]=new BtSs44(matrix,this); + break; + + case RDMatrix::BtSs82: + ripcd_switcher[matrix_num]=new BtSs82(matrix,this); + break; + + case RDMatrix::Harlond: + ripcd_switcher[matrix_num]=new Harlond(matrix,this); + break; + + case RDMatrix::LiveWireLwrpAudio: + ripcd_switcher[matrix_num]=new LiveWireLwrpAudio(matrix,this); + break; + + case RDMatrix::LiveWireMcastGpio: + ripcd_switcher[matrix_num]=new LiveWireMcastGpio(matrix,this); + break; + + case RDMatrix::LiveWireLwrpGpio: + ripcd_switcher[matrix_num]=new LiveWireLwrpGpio(matrix,this); + break; + + case RDMatrix::LocalAudioAdapter: + ripcd_switcher[matrix_num]=new LocalAudio(matrix,this); + break; + + case RDMatrix::LocalGpio: + ripcd_switcher[matrix_num]=new LocalGpio(matrix,this); + break; + + case RDMatrix::LogitekVguest: + ripcd_switcher[matrix_num]=new VGuest(matrix,this); + break; + + case RDMatrix::Quartz1: + ripcd_switcher[matrix_num]=new Quartz1(matrix,this); + break; + + case RDMatrix::Sas32000: + ripcd_switcher[matrix_num]=new Sas32000(matrix,this); + break; + + case RDMatrix::Sas64000: + ripcd_switcher[matrix_num]=new Sas64000(matrix,this); + break; + + case RDMatrix::Sas64000Gpi: + ripcd_switcher[matrix_num]=new Sas64000Gpi(matrix,this); + break; + + case RDMatrix::SasUsi: + ripcd_switcher[matrix_num]=new SasUsi(matrix,this); + break; + + case RDMatrix::StarGuideIII: + ripcd_switcher[matrix_num]=new StarGuide3(matrix,this); + break; + + case RDMatrix::Unity4000: + ripcd_switcher[matrix_num]=new Unity4000(matrix,this); + break; + + default: + ripcd_switcher[matrix_num]=NULL; + delete matrix; + return false; + } + if(ripcd_switcher[matrix_num]->primaryTtyActive()) { + ripcd_switcher_tty[matrix_num][0]= + matrix->port(RDMatrix::Primary); + ripcd_switcher_tty[matrix_num][0]=-1; + ripcd_tty_inuse[matrix->port(RDMatrix::Primary)]=true; + } + if(ripcd_switcher[matrix_num]->secondaryTtyActive()) { + ripcd_switcher_tty[matrix_num][1]= + matrix->port(RDMatrix::Primary); + ripcd_switcher_tty[matrix_num][1]=-1; + ripcd_tty_inuse[matrix->port(RDMatrix::Backup)]=true; + } + connect(ripcd_switcher[matrix_num],SIGNAL(rmlEcho(RDMacro *)), + this,SLOT(sendRml(RDMacro *))); + connect(ripcd_switcher[matrix_num], + SIGNAL(gpiChanged(int,int,bool)), + this,SLOT(gpiChangedData(int,int,bool))); + connect(ripcd_switcher[matrix_num], + SIGNAL(gpoChanged(int,int,bool)), + this,SLOT(gpoChangedData(int,int,bool))); + connect(ripcd_switcher[matrix_num], + SIGNAL(gpiState(int,unsigned,bool)), + this,SLOT(gpiStateData(int,unsigned,bool))); + connect(ripcd_switcher[matrix_num], + SIGNAL(gpoState(int,unsigned,bool)), + this,SLOT(gpoStateData(int,unsigned,bool))); + delete matrix; + + return true; +} diff --git a/ripcd/local_audio.cpp b/ripcd/local_audio.cpp new file mode 100644 index 00000000..0560597b --- /dev/null +++ b/ripcd/local_audio.cpp @@ -0,0 +1,155 @@ +// local_audio.cpp +// +// A Rivendell switcher driver for the BroadcastTools 10x1 +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: local_audio.cpp,v 1.9 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include + + +LocalAudio::LocalAudio(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Get Matrix Parameters + // + bt_inputs=matrix->inputs(); + bt_outputs=matrix->outputs(); + bt_card=matrix->card(); +} + + +LocalAudio::~LocalAudio() +{ +} + + +RDMatrix::Type LocalAudio::type() +{ + return RDMatrix::LocalAudioAdapter; +} + + +unsigned LocalAudio::gpiQuantity() +{ + return 0; +} + + +unsigned LocalAudio::gpoQuantity() +{ + return 0; +} + + +bool LocalAudio::primaryTtyActive() +{ + return false; +} + + +bool LocalAudio::secondaryTtyActive() +{ + return false; +} + + +void LocalAudio::processCommand(RDMacro *cmd) +{ + switch(cmd->command()) { + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<=0)||(cmd->arg(2).toInt()>bt_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toInt()==0) { + for(int i=0;i + setPassthroughVolume(bt_card,i,cmd->arg(2).toInt()-1,-10000); + } + } + else { + rdcae->setPassthroughVolume(bt_card,cmd->arg(1).toInt()-1, + cmd->arg(2).toInt()-1,0); + for(int i=0;i<(cmd->arg(1).toInt()-1);i++) { + rdcae-> + setPassthroughVolume(bt_card,i,cmd->arg(2).toInt()-1,-10000); + } + for(int i=cmd->arg(1).toInt();i + setPassthroughVolume(bt_card,i,cmd->arg(2).toInt()-1,-10000); + } + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SA: + if((cmd->arg(1).toInt()<=0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<=0)||(cmd->arg(2).toInt()>bt_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + rdcae->setPassthroughVolume(bt_card,cmd->arg(1).toInt()-1, + cmd->arg(2).toInt()-1,0); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SR: + if((cmd->arg(1).toInt()<=0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<=0)||(cmd->arg(2).toInt()>bt_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + rdcae->setPassthroughVolume(bt_card,cmd->arg(1).toInt()-1, + cmd->arg(2).toInt()-1,RD_MUTE_DEPTH); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SX: + if((cmd->arg(1).toInt()<=0)||(cmd->arg(1).toInt()>bt_inputs)|| + (cmd->arg(2).toInt()<=0)||(cmd->arg(2).toInt()>bt_outputs)|| + (cmd->arg(3).toInt()arg(3).toInt()>0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + rdcae->setPassthroughVolume(bt_card,cmd->arg(1).toInt()-1, + cmd->arg(2).toInt()-1,cmd->arg(3).toInt()); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} diff --git a/ripcd/local_audio.h b/ripcd/local_audio.h new file mode 100644 index 00000000..e3c267b9 --- /dev/null +++ b/ripcd/local_audio.h @@ -0,0 +1,53 @@ +// local_audio.h +// +// A Rivendell switcher driver for the BroadcastTools 10x1 +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: local_audio.h,v 1.8 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LOCAL_AUDIO_H +#define LOCAL_AUDIO_H + +#include +#include +#include +#include + +#include + +class LocalAudio : public Switcher +{ + Q_OBJECT + public: + LocalAudio(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~LocalAudio(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private: + int bt_inputs; + int bt_outputs; + int bt_card; +}; + + +#endif // LOCAL_AUDIO_H diff --git a/ripcd/local_gpio.cpp b/ripcd/local_gpio.cpp new file mode 100644 index 00000000..8ef81eb0 --- /dev/null +++ b/ripcd/local_gpio.cpp @@ -0,0 +1,193 @@ +// local_gpio.cpp +// +// A Rivendell switcher driver for MeasurementComputing GPIO cards. +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: local_gpio.cpp,v 1.16.8.1 2013/03/03 23:30:16 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + +LocalGpio::LocalGpio(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Get Matrix Parameters + // + gpio_matrix=matrix->matrix(); + gpio_gpis=matrix->gpis(); + gpio_gpos=matrix->gpos(); + + // + // Initialize data structures + // + for(int i=0;isetDevice(matrix->gpioDevice()); + if((gpio_open=gpio_gpio->open())) { + if(gpio_gpis==0) { + gpio_gpio->setMode(RDGpio::Output); + } + if(gpio_gpos==0) { + gpio_gpio->setMode(RDGpio::Input); + } + connect(gpio_gpio,SIGNAL(inputChanged(int,bool)), + this,SLOT(gpiChangedData(int,bool))); + connect(gpio_gpio,SIGNAL(outputChanged(int,bool)), + this,SLOT(gpoChangedData(int,bool))); + } + + // + // Interval OneShot + // + gpio_gpi_oneshot=new RDOneShot(this); + connect(gpio_gpi_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpiOneshotData(void*))); +} + + +LocalGpio::~LocalGpio() +{ + delete gpio_gpio; + delete gpio_gpi_oneshot; +} + + +RDMatrix::Type LocalGpio::type() +{ + return RDMatrix::LocalGpio; +} + + +unsigned LocalGpio::gpiQuantity() +{ + return gpio_gpis; +} + + +unsigned LocalGpio::gpoQuantity() +{ + return gpio_gpos; +} + + +bool LocalGpio::primaryTtyActive() +{ + return false; +} + + +bool LocalGpio::secondaryTtyActive() +{ + return false; +} + + +void LocalGpio::processCommand(RDMacro *cmd) +{ + switch(cmd->command()) { + case RDMacro::GO: + if((!gpio_open)||(cmd->argQuantity()!=5)|| + ((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>gpio_gpos)|| + ((cmd->arg(3).toInt()!=1)&&(cmd->arg(3).toInt()!=0)&& + (cmd->arg(3).toInt()!=-1))||(cmd->arg(4).toInt()<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toString().lower()=="i") { + if(cmd->arg(3).toInt()==0) { + emit gpiChanged(gpio_matrix,cmd->arg(2).toInt()-1,false); + gpio_gpi_mask[cmd->arg(2).toInt()-1]=true; + if(cmd->arg(4).toInt()>0) { + gpio_gpi_oneshot-> + start((void *)(cmd->arg(2).toInt()-1),cmd->arg(4).toInt()); + } + } + else { + if(cmd->arg(3).toInt()==1) { + emit gpiChanged(gpio_matrix,cmd->arg(2).toInt()-1,true); + gpio_gpi_mask[cmd->arg(2).toInt()-1]=true; + if(cmd->arg(4).toInt()>0) { + gpio_gpi_oneshot-> + start((void *)(cmd->arg(2).toInt()-1),cmd->arg(4).toInt()); + } + } + else { + gpiOneshotData((void *)(cmd->arg(2).toInt()-1)); + } + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(1).toString().lower()=="o") { + if(cmd->arg(3).toInt()==0) { + gpio_gpio->gpoReset(cmd->arg(2).toInt()-1,cmd->arg(4).toInt()); + } + else { + if(cmd->arg(3).toInt()==1) { + gpio_gpio->gpoSet(cmd->arg(2).toInt()-1,cmd->arg(4).toInt()); + } + else { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + return; + } + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void LocalGpio::gpiChangedData(int line,bool state) +{ + emit gpiChanged(gpio_matrix,line,state); +} + + +void LocalGpio::gpoChangedData(int line,bool state) +{ + emit gpoChanged(gpio_matrix,line,state); +} + + +void LocalGpio::gpiOneshotData(void *data) +{ + gpio_gpi_mask[(long)data]=false; + gpiChangedData((long)data,gpio_gpio->inputState((long)data)); +} diff --git a/ripcd/local_gpio.h b/ripcd/local_gpio.h new file mode 100644 index 00000000..84f5374f --- /dev/null +++ b/ripcd/local_gpio.h @@ -0,0 +1,63 @@ +// local_gpio.h +// +// A Rivendell switcher driver for MeasurementComputing GPIO cards. +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: local_gpio.h,v 1.14 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef LOCAL_GPIO_H +#define LOCAL_GPIO_H + +#include +#include +#include +#include +#include + +#include + +class LocalGpio : public Switcher +{ + Q_OBJECT + public: + LocalGpio(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~LocalGpio(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void gpiChangedData(int line,bool state); + void gpoChangedData(int line,bool state); + void gpiOneshotData(void *data); + + private: + RDGpio *gpio_gpio; + RDOneShot *gpio_gpi_oneshot; + int gpio_matrix; + int gpio_gpis; + int gpio_gpos; + bool gpio_open; + bool gpio_gpi_mask[GPIO_MAX_LINES]; +}; + + +#endif // LOCAL_GPIO_H diff --git a/ripcd/local_macros.cpp b/ripcd/local_macros.cpp new file mode 100644 index 00000000..1997df2c --- /dev/null +++ b/ripcd/local_macros.cpp @@ -0,0 +1,936 @@ +// local_macros.cpp +// +// Local RML Macros for the Rivendell Interprocess Communication Daemon +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: local_macros.cpp,v 1.60.2.1 2013/06/20 20:00:09 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +void MainObject::gpiChangedData(int matrix,int line,bool state) +{ + if(state) { + LogLine(RDConfig::LogInfo,QString().sprintf("GPI %d:%d ON",matrix,line+1)); + } + else { + LogLine(RDConfig::LogInfo,QString().sprintf("GPI %d:%d OFF",matrix,line+1)); + } + ripcd_gpi_state[matrix][line]=state; + BroadcastCommand(QString().sprintf("GI %d %d %d %d!",matrix,line,state, + ripcd_gpi_mask[matrix][line])); + if(!ripcd_gpi_mask[matrix][line]) { + return; + } + if(ripcd_gpi_macro[matrix][line][state]>0) { + ExecCart(ripcd_gpi_macro[matrix][line][state]); + } +} + + +void MainObject::gpoChangedData(int matrix,int line,bool state) +{ + if(state) { + LogLine(RDConfig::LogInfo,QString().sprintf("GPO %d:%d ON",matrix,line+1)); + } + else { + LogLine(RDConfig::LogInfo,QString().sprintf("GPO %d:%d OFF",matrix,line+1)); + } + ripcd_gpo_state[matrix][line]=state; + BroadcastCommand(QString().sprintf("GO %d %d %d %d!",matrix,line,state, + ripcd_gpo_mask[matrix][line])); + if(!ripcd_gpo_mask[matrix][line]) { + return; + } + if(ripcd_gpo_macro[matrix][line][state]>0) { + ExecCart(ripcd_gpo_macro[matrix][line][state]); + } +} + + +void MainObject::gpiStateData(int matrix,unsigned line,bool state) +{ + // LogLine(RDConfig::LogWarning,QString().sprintf("gpiStateData(%d,%d,%d)",matrix,line,state)); + + BroadcastCommand(QString().sprintf("GI %d %u %d %d!",matrix,line,state, + ripcd_gpi_mask[matrix][line])); +} + + +void MainObject::gpoStateData(int matrix,unsigned line,bool state) +{ + // LogLine(RDConfig::LogWarning,QString().sprintf("gpoStateData(%d,%d,%d)",matrix,line,state)); + + BroadcastCommand(QString().sprintf("GO %d %u %d %d!",matrix,line,state, + ripcd_gpo_mask[matrix][line])); +} + + +void MainObject::ttyTrapData(int cartnum) +{ + ExecCart(cartnum); +} + + +void MainObject::ttyScanData() +{ + char buf[256]; + int n; + + for(int i=0;ireadBlock(buf,255))>0) { + ripcd_tty_trap[i]->scan(buf,n); + } + } + } +} + + +void MainObject::ExecCart(int cartnum) +{ + RDMacro rml; + rml.setRole(RDMacro::Cmd); + rml.setCommand(RDMacro::EX); + rml.setAddress(rdstation->address()); + rml.setEchoRequested(false); + rml.setArgQuantity(1); + rml.setArg(0,cartnum); + sendRml(&rml); +} + + +void MainObject::LoadLocalMacros() +{ + QString sql; + RDSqlQuery *q; + unsigned tty_port; + + for(int i=0;iname()); + q=new RDSqlQuery(sql); + while(q->next()) { + if(!LoadSwitchDriver(q->value(0).toInt())) { + LogLine(RDConfig::LogErr,QString(). + sprintf("attempted to load unknown switcher driver for matrix %d", + q->value(0).toInt())); + } + } + delete q; + + // + // Initialize TTYs + // + sql=QString().sprintf("select PORT_ID,PORT,BAUD_RATE,DATA_BITS,PARITY,\ + TERMINATION from TTYS where (STATION_NAME=\"%s\")&&\ + (ACTIVE=\"Y\")", + (const char *)rdstation->name()); + q=new RDSqlQuery(sql); + while(q->next()) { + tty_port=q->value(0).toUInt(); + if(!ripcd_tty_inuse[tty_port]) { + ripcd_tty_dev[tty_port]=new RDTTYDevice(); + ripcd_tty_dev[tty_port]->setName(q->value(1).toString()); + ripcd_tty_dev[tty_port]->setSpeed(q->value(2).toInt()); + ripcd_tty_dev[tty_port]->setWordLength(q->value(3).toInt()); + ripcd_tty_dev[tty_port]-> + setParity((RDTTYDevice::Parity)q->value(4).toInt()); + if(ripcd_tty_dev[tty_port]->open(IO_ReadWrite)) { + ripcd_tty_term[tty_port]=(RDTty::Termination)q->value(5).toInt(); + ripcd_tty_inuse[tty_port]=true; + ripcd_tty_trap[tty_port]=new RDCodeTrap(this); + connect(ripcd_tty_trap[tty_port],SIGNAL(trapped(int)), + this,SLOT(ttyTrapData(int))); + } + else { + delete ripcd_tty_dev[tty_port]; + ripcd_tty_dev[tty_port]=NULL; + } + } + } + delete q; + QTimer *timer=new QTimer(this,"tty_scan_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(ttyScanData())); + timer->start(RIPCD_TTY_READ_INTERVAL); +} + + +void MainObject::RunLocalMacros(RDMacro *rml) +{ + int matrix_num; + int gpi; + int tty_port; + int severity=0; + QString str; + QString sql; + QString cmd; + RDSqlQuery *q; + QHostAddress addr; + RDUser *rduser; + char logstr[RD_RML_MAX_LENGTH]; + char bin_buf[RD_RML_MAX_LENGTH]; + int d; + RDMatrix::GpioType gpio_type; + QByteArray data; + + rml->generateString(logstr,RD_RML_MAX_LENGTH-1); + LogLine(RDConfig::LogInfo,QString().sprintf("received rml: \'%s\' from %s", + (const char *)logstr,(const char *)rml->address().toString())); + + ForwardConvert(rml); + + switch(rml->command()) { + case RDMacro::BO: + tty_port=rml->arg(0).toInt(); + if((tty_port<0)||(tty_port>MAX_TTYS)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + return; + } + } + if(ripcd_tty_dev[tty_port]==NULL) { + rml->acknowledge(false); + sendRml(rml); + return; + } + for(int i=1;i<(rml->argQuantity());i++) { + sscanf((const char *)rml->arg(i).toString(),"%x",&d); + bin_buf[i-1]=0xFF&d; + } + ripcd_tty_dev[tty_port]->writeBlock(bin_buf,rml->argQuantity()-1); + rml->acknowledge(true); + sendRml(rml); + return; + break; + + case RDMacro::DB: + if(rml->argQuantity()!=1) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + if(fork()==0) { + cmd=QString().sprintf("mysqldump -c Rivendell -h %s -u %s -p%s > %s", + (const char *)ripcd_config->mysqlHostname(), + (const char *)ripcd_config->mysqlUsername(), + (const char *)ripcd_config->mysqlPassword(), + (const char *)rml->arg(0).toString()); + system((const char *)cmd); + exit(0); + } + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + break; + + case RDMacro::GI: + if(rml->argQuantity()!=5) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + matrix_num=rml->arg(0).toInt(); + if(rml->arg(1).toString().lower()=="i") { + gpio_type=RDMatrix::GpioInput; + } + else { + if(rml->arg(1).toString().lower()=="o") { + gpio_type=RDMatrix::GpioOutput; + } + else { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + } + gpi=rml->arg(2).toInt()-1; + if((ripcd_switcher[matrix_num]==NULL)|| + (gpi>(MAX_GPIO_PINS-1))|| + (gpi<0)|| + (rml->arg(3).toInt()<0)||(rml->arg(3).toInt()>1)|| + (rml->arg(4).toInt()<-1)||(rml->arg(4).toInt()>999999)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + switch(gpio_type) { + case RDMatrix::GpioInput: + ripcd_gpi_macro[matrix_num][gpi][rml->arg(3).toInt()]= + rml->arg(4).toInt(); + BroadcastCommand(QString().sprintf("GC %d %d %d %d!",matrix_num,gpi, + ripcd_gpi_macro[matrix_num][gpi][0], + ripcd_gpi_macro[matrix_num][gpi][1])); + LogLine(RDConfig::LogWarning,QString().sprintf("cart: %u", + ripcd_gpi_macro[matrix_num][gpi][rml->arg(3).toInt()])); + break; + + case RDMatrix::GpioOutput: + ripcd_gpo_macro[matrix_num][gpi][rml->arg(3).toInt()]= + rml->arg(4).toInt(); + BroadcastCommand(QString().sprintf("GD %d %d %d %d!",matrix_num,gpi, + ripcd_gpo_macro[matrix_num][gpi][0], + ripcd_gpo_macro[matrix_num][gpi][1])); + break; + } + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + break; + + case RDMacro::GE: + if(rml->argQuantity()!=4) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + matrix_num=rml->arg(0).toInt(); + if(rml->arg(1).toString().lower()=="i") { + gpio_type=RDMatrix::GpioInput; + } + else { + if(rml->arg(1).toString().lower()=="o") { + gpio_type=RDMatrix::GpioOutput; + } + else { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + } + gpi=rml->arg(2).toInt()-1; + if((ripcd_switcher[matrix_num]==NULL)|| + (gpi>(MAX_GPIO_PINS-1))|| + (gpi<0)|| + (rml->arg(3).toInt()<0)||(rml->arg(3).toInt()>1)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + switch(gpio_type) { + case RDMatrix::GpioInput: + if(rml->arg(3).toInt()==1) { + ripcd_gpi_mask[matrix_num][gpi]=true; + BroadcastCommand(QString().sprintf("GM %d %d 1!",matrix_num,gpi)); + } + else { + ripcd_gpi_mask[matrix_num][gpi]=false; + BroadcastCommand(QString().sprintf("GM %d %d 0!",matrix_num,gpi)); + } + break; + + case RDMatrix::GpioOutput: + if(rml->arg(3).toInt()==1) { + ripcd_gpo_mask[matrix_num][gpi]=true; + BroadcastCommand(QString().sprintf("GN %d %d 1!",matrix_num,gpi)); + } + else { + ripcd_gpo_mask[matrix_num][gpi]=false; + BroadcastCommand(QString().sprintf("GN %d %d 0!",matrix_num,gpi)); + } + break; + } + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + break; + + case RDMacro::JC: + if(rml->argQuantity()!=2) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + rdcae->connectJackPorts(rml->arg(0).toString(),rml->arg(1).toString()); + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + break; + + case RDMacro::JD: + if(rml->argQuantity()!=2) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + rdcae->disconnectJackPorts(rml->arg(0).toString(),rml->arg(1).toString()); + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + break; + + case RDMacro::LO: + if(rml->argQuantity()>2) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + if(rml->argQuantity()==0) { + rduser=new RDUser(rdstation->defaultName()); + } + else { + rduser=new RDUser(rml->arg(0).toString()); + if(!rduser->exists()) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + delete rduser; + return; + } + if(!rduser->checkPassword(rml->arg(1).toString(),false)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + delete rduser; + return; + } + } + SetUser(rduser->name()); + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + delete rduser; + break; + + case RDMacro::MB: + if(rml->argQuantity()<3) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + severity=rml->arg(1).toInt(); + if((severity<1)||(severity>3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + if(fork()==0) { + if(getuid()==0) { + if(setegid(ripcd_config->gid())<0) { + LogLine(RDConfig::LogWarning,QString(). + sprintf("unable to set group id %d for RDPopup", + ripcd_config->gid())); + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + } + if(seteuid(ripcd_config->uid())<0) { + LogLine(RDConfig::LogWarning,QString(). + sprintf("unable to set user id %d for RDPopup", + ripcd_config->uid())); + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + } + } + if(system(QString(). + sprintf("rdpopup -display %s %s %s", + (const char *)rml->arg(0).toString(), + (const char *)rml->arg(1).toString(), + (const char *)RDEscapeString(rml->rollupArgs(2))))<0) { + LogLine(RDConfig::LogWarning,"RDPopup returned an error"); + } + exit(0); + } + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + break; + + case RDMacro::MT: + if(rml->argQuantity()!=3) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + if((rml->arg(0).toUInt()==0)|| + (rml->arg(0).toUInt()>RD_MAX_MACRO_TIMERS)|| + (rml->arg(2).toUInt()>999999)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + if((rml->arg(1).toUInt()==0)|| + (rml->arg(2).toUInt()==0)) { + ripc_macro_cart[rml->arg(0).toUInt()-1]=0; + ripc_macro_timer[rml->arg(0).toUInt()-1]->stop(); + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + return; + } + ripc_macro_cart[rml->arg(0).toUInt()-1]=rml->arg(2).toUInt(); + ripc_macro_timer[rml->arg(0).toUInt()-1]->stop(); + ripc_macro_timer[rml->arg(0).toUInt()-1]-> + start(rml->arg(1).toInt(),true); + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + return; + + case RDMacro::RN: + if(rml->argQuantity()<1) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + if(fork()==0) { + QString cmd=rml->arg(0).toString(); + for(int i=1;i<=rml->argQuantity();i++) { + cmd+=" "+rml->arg(i).toString(); + } + if(getuid()==0) { + if(setgid(ripcd_config->gid())<0) { + LogLine(RDConfig::LogWarning,QString(). + sprintf("unable to set group id %d for RN", + ripcd_config->gid())); + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + } + if(setuid(ripcd_config->uid())<0) { + LogLine(RDConfig::LogWarning,QString(). + sprintf("unable to set user id %d for RN", + ripcd_config->uid())); + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + } + } + system((const char *)cmd); + exit(0); + } + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + break; + + case RDMacro::SI: + tty_port=rml->arg(0).toInt(); + if((tty_port<0)||(tty_port>MAX_TTYS)||(rml->argQuantity()!=3)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + if(ripcd_tty_dev[tty_port]==NULL) { + rml->acknowledge(false); + sendRml(rml); + return; + } + for(int i=2;i<(rml->argQuantity()-1);i++) { + str+=(rml->arg(i).toString()+" "); + } + str+=rml->arg(rml->argQuantity()-1).toString(); + ripcd_tty_trap[tty_port]->addTrap(rml->arg(1).toInt(), + str,str.length()); + rml->acknowledge(true); + sendRml(rml); + return; + break; + + case RDMacro::SC: + tty_port=rml->arg(0).toInt(); + if((tty_port<0)||(tty_port>MAX_TTYS)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + return; + } + } + if(ripcd_tty_dev[tty_port]==NULL) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + switch(rml->argQuantity()) { + case 1: + ripcd_tty_trap[tty_port]->clear(); + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + break; + + case 2: + ripcd_tty_trap[tty_port]->removeTrap(rml->arg(1).toInt()); + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + break; + + case 3: + ripcd_tty_trap[tty_port]->removeTrap(rml->arg(1).toInt(), + (const char *)rml->arg(2).toString(), + rml->arg(2).toString().length()); + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + break; + + default: + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + break; + } + break; + + case RDMacro::SO: + tty_port=rml->arg(0).toInt(); + if((tty_port<0)||(tty_port>MAX_TTYS)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + return; + } + } + if(ripcd_tty_dev[tty_port]==NULL) { + rml->acknowledge(false); + sendRml(rml); + return; + } + for(int i=1;i<(rml->argQuantity()-1);i++) { + str+=(rml->arg(i).toString()+" "); + } + str+=rml->arg(rml->argQuantity()-1).toString(); + switch(ripcd_tty_term[tty_port]) { + case RDTty::CrTerm: + str+=QString().sprintf("\x0d"); + break; + + case RDTty::LfTerm: + str+=QString().sprintf("\x0a"); + break; + + case RDTty::CrLfTerm: + str+=QString().sprintf("\x0d\x0a"); + break; + + default: + break; + } + data=RDStringToData(str); + ripcd_tty_dev[tty_port]->writeBlock((const char *)data,data.size()); + rml->acknowledge(true); + sendRml(rml); + return; + break; + + case RDMacro::CL: + case RDMacro::FS: + case RDMacro::GO: + case RDMacro::ST: + case RDMacro::SA: + case RDMacro::SD: + case RDMacro::SG: + case RDMacro::SR: + case RDMacro::SL: + case RDMacro::SX: + if((rml->arg(0).toInt()<0)||(rml->arg(0).toInt()>=MAX_MATRICES)) { + if(!rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + if(ripcd_switcher[rml->arg(0).toInt()]==NULL) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + } + else { + ripcd_switcher[rml->arg(0).toInt()]->processCommand(rml); + } + break; + + case RDMacro::SY: + if(rml->argQuantity()!=1) { + return; + } + tty_port=rml->arg(0).toInt(); + if((tty_port<0)||(tty_port>=MAX_TTYS)) { + return; + } + + // + // Shutdown TTY Port + // + if(ripcd_tty_dev[tty_port]!=NULL) { + ripcd_tty_dev[tty_port]->close(); + delete ripcd_tty_dev[tty_port]; + ripcd_tty_dev[tty_port]=NULL; + ripcd_tty_inuse[tty_port]=false; + delete ripcd_tty_trap[tty_port]; + ripcd_tty_trap[tty_port]=NULL; + } + + // + // Try to Restart + // + sql=QString().sprintf("select PORT_ID,PORT,BAUD_RATE,DATA_BITS,PARITY,\ + TERMINATION from TTYS where (STATION_NAME=\"%s\")&& \ + (ACTIVE=\"Y\")&&(PORT_ID=%d)", + (const char *)rdstation->name(),tty_port); + q=new RDSqlQuery(sql); + if(q->first()) { + if(!ripcd_tty_inuse[tty_port]) { + ripcd_tty_dev[tty_port]=new RDTTYDevice(); + ripcd_tty_dev[tty_port]->setName(q->value(1).toString()); + ripcd_tty_dev[tty_port]->setSpeed(q->value(2).toInt()); + ripcd_tty_dev[tty_port]->setWordLength(q->value(3).toInt()); + ripcd_tty_dev[tty_port]-> + setParity((RDTTYDevice::Parity)q->value(4).toInt()); + if(ripcd_tty_dev[tty_port]->open(IO_ReadWrite)) { + ripcd_tty_term[tty_port]=(RDTty::Termination)q->value(5).toInt(); + ripcd_tty_inuse[tty_port]=true; + ripcd_tty_trap[tty_port]=new RDCodeTrap(this); + connect(ripcd_tty_trap[tty_port],SIGNAL(trapped(int)), + this,SLOT(ttyTrapData(int))); + } + else { + delete ripcd_tty_dev[tty_port]; + ripcd_tty_dev[tty_port]=NULL; + } + } + } + delete q; + break; + + case RDMacro::SZ: + if(rml->argQuantity()!=1) { + return; + } + matrix_num=rml->arg(0).toInt(); + if((matrix_num<0)||(matrix_num>=MAX_MATRICES)) { + return; + } + + // + // Shutdown the old switcher + // + for(int i=0;i<2;i++) { + if(ripcd_switcher_tty[matrix_num][i]>-1) { + ripcd_tty_inuse[ripcd_switcher_tty[matrix_num][i]]=false; + ripcd_switcher_tty[matrix_num][i]=-1; + } + } + delete ripcd_switcher[matrix_num]; + ripcd_switcher[matrix_num]=NULL; + + // + // Startup the new + // + if(!LoadSwitchDriver(matrix_num)) { + LogLine(RDConfig::LogErr,QString(). + sprintf("attempted to load unknown switcher driver for matrix %d", + matrix_num)); + } + break; + + case RDMacro::TA: + if((rml->argQuantity()!=1)|| + (rml->arg(0).toInt()<0)||(rml->arg(0).toInt()>1)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + if((rml->arg(0).toInt()==0)&&ripc_onair_flag) { + BroadcastCommand("TA 0!"); + LogLine(RDConfig::LogInfo,"onair flag OFF"); + } + if((rml->arg(0).toInt()==1)&&(!ripc_onair_flag)) { + BroadcastCommand("TA 1!"); + LogLine(RDConfig::LogInfo,"onair flag ON"); + } + ripc_onair_flag=rml->arg(0).toInt(); + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + break; + + case RDMacro::UO: + if(rml->argQuantity()<3) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + if(!addr.setAddress(rml->arg(0).toString())) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + if((rml->arg(1).toInt()<0)||(rml->arg(1).toInt()>0xFFFF)) { + if(rml->echoRequested()) { + rml->acknowledge(false); + sendRml(rml); + } + return; + } + for(int i=2;i<(rml->argQuantity()-1);i++) { + str+=(rml->arg(i).toString()+" "); + } + str+=rml->arg(rml->argQuantity()-1).toString(); + LogLine(RDConfig::LogDebug,QString(). + sprintf("Sending \"%s\" to %s:%d",(const char *)str, + (const char *)addr.toString(),rml->arg(1).toInt())); + data=RDStringToData(str); + ripcd_rml_send->writeBlock((const char *)data,data.size(),addr, + (Q_UINT16)(rml->arg(1).toInt())); + if(rml->echoRequested()) { + rml->acknowledge(true); + sendRml(rml); + } + break; + + default: +// LogLine(RDConfig::LogDebug,QString().sprintf("unhandled rml: \'%s\' from %s", +// (const char *)logstr,(const char *)rml->address().toString())); + break; + } +} + + +void MainObject::ForwardConvert(RDMacro *rml) const +{ + // + // Convert old RML syntax to current forms + // + switch(rml->command()) { + case RDMacro::GE: + if(rml->argQuantity()==3) { + rml->setArgQuantity(4); + for(int i=2;i>=1;i--) { + rml->setArg(i+1,rml->arg(i)); + } + rml->setArg(1,"I"); + } + break; + + case RDMacro::GI: + if(rml->argQuantity()==3) { + rml->setArgQuantity(4); + rml->setArg(3,0); + } + if(rml->argQuantity()==4) { + rml->setArgQuantity(5); + for(int i=3;i>=1;i--) { + rml->setArg(i+1,rml->arg(i)); + } + rml->setArg(1,"I"); + } + break; + + case RDMacro::GO: + if(rml->argQuantity()==4) { + rml->setArgQuantity(5); + for(int i=3;i>=1;i--) { + rml->setArg(i+1,rml->arg(i)); + } + rml->setArg(1,"O"); + } + break; + + default: + break; + } +} diff --git a/ripcd/maint_routines.cpp b/ripcd/maint_routines.cpp new file mode 100644 index 00000000..4277df78 --- /dev/null +++ b/ripcd/maint_routines.cpp @@ -0,0 +1,56 @@ +// ripcd.cpp +// +// Rivendell Maintenance Routines +// +// (C) Copyright 2008 Fred Gleason +// +// $Id: maint_routines.cpp,v 1.4 2010/07/29 19:32:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include + +void MainObject::RunSystemMaintRoutine() +{ + if(fork()==0) { + system("rdmaint --system"); + system("rdpurgecasts"); + exit(0); + } + + LogLine(RDConfig::LogInfo,"ran system-wide maintenance routines"); +} + + +void MainObject::RunLocalMaintRoutine() +{ + if(fork()==0) { + system("rdmaint"); + exit(0); + } + LogLine(RDConfig::LogInfo,"ran local maintenance routines"); +} + + +int MainObject::GetMaintInterval() const +{ + return (int)(RD_MAINT_MIN_INTERVAL+ + (RD_MAINT_MAX_INTERVAL-RD_MAINT_MIN_INTERVAL)* + (double)random()/(double)RAND_MAX); +} diff --git a/ripcd/quartz1.cpp b/ripcd/quartz1.cpp new file mode 100644 index 00000000..09ed5abf --- /dev/null +++ b/ripcd/quartz1.cpp @@ -0,0 +1,269 @@ +// quartz1.cpp +// +// A Rivendell switcher driver for the Quartz Type 1 Switcher Protocol +// +// (C) Copyright 2002-2004,2008 Fred Gleason +// +// $Id: quartz1.cpp,v 1.11 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include +#include + +Quartz1::Quartz1(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + RDTty *tty; + sas_matrix=matrix->matrix(); + sas_ptr[0]=0; + sas_ptr[1]=0; + + // + // Get Matrix Parameters + // + sas_porttype[0]=matrix->portType(RDMatrix::Primary); + sas_ipaddress[0]=matrix->ipAddress(RDMatrix::Primary); + sas_ipport[0]=matrix->ipPort(RDMatrix::Primary); + sas_port[0]=matrix->port(RDMatrix::Primary); + sas_porttype[1]=matrix->portType(RDMatrix::Backup); + sas_ipaddress[1]=matrix->ipAddress(RDMatrix::Backup); + sas_ipport[1]=matrix->ipPort(RDMatrix::Backup); + sas_port[1]=matrix->port(RDMatrix::Backup); + sas_inputs=matrix->inputs(); + sas_outputs=matrix->outputs(); + sas_layer=matrix->layer(); + + // + // Reconnection Timers + // + QSignalMapper *mapper=new QSignalMapper(this,"reconnect_mapper"); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(ipConnect(int))); + for(int i=0;i<2;i++) { + sas_reconnect_timer[i]=new QTimer(this,"sas_reconnect_timer"); + mapper->setMapping(sas_reconnect_timer[i],i); + connect(sas_reconnect_timer[i],SIGNAL(timeout()),mapper,SLOT(map())); + } + + // + // Initialize the connections + // + QSignalMapper *connected_mapper=new QSignalMapper(this,"connected_mapper"); + connect(connected_mapper,SIGNAL(mapped(int)),this,SLOT(connectedData(int))); + QSignalMapper *closed_mapper=new QSignalMapper(this,"closed_mapper"); + connect(closed_mapper,SIGNAL(mapped(int)), + this,SLOT(connectionClosedData(int))); + for(int i=0;i<2;i++) { + switch(sas_porttype[i]) { + case RDMatrix::TtyPort: + tty=new RDTty(rdstation->name(),sas_port[i]); + sas_device[i]=new RDTTYDevice(); + if(tty->active()) { + sas_device[i]->setName(tty->port()); + sas_device[i]->setSpeed(tty->baudRate()); + sas_device[i]->setWordLength(tty->dataBits()); + sas_device[i]->setParity(tty->parity()); + sas_device[i]->open(IO_Raw|IO_ReadWrite); + } + delete tty; + + case RDMatrix::TcpPort: + sas_socket[i]=new QSocket(this,"sas_socket"); + connected_mapper->setMapping(sas_socket[i],i); + connect(sas_socket[i],SIGNAL(connected()), + connected_mapper,SLOT(map())); + closed_mapper->setMapping(sas_socket[i],i); + connect(sas_socket[i],SIGNAL(connectionClosed()), + closed_mapper,SLOT(map())); + switch(i) { + case 0: + connect(sas_socket[i],SIGNAL(error(int)), + this,SLOT(error0Data(int))); + break; + + case 1: + connect(sas_socket[i],SIGNAL(error(int)), + this,SLOT(error1Data(int))); + break; + } + ipConnect(i); + break; + + case RDMatrix::NoPort: + break; + } + } +} + + +RDMatrix::Type Quartz1::type() +{ + return RDMatrix::Quartz1; +} + + +unsigned Quartz1::gpiQuantity() +{ + return 0; +} + + +unsigned Quartz1::gpoQuantity() +{ + return 0; +} + + +bool Quartz1::primaryTtyActive() +{ + return sas_porttype[0]==RDMatrix::TtyPort; +} + + +bool Quartz1::secondaryTtyActive() +{ + return sas_porttype[1]==RDMatrix::TtyPort; +} + + +void Quartz1::processCommand(RDMacro *cmd) +{ + char str[9]; + QString label; + + switch(cmd->command()) { + case RDMacro::FS: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>32)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,".F%d\x0D",cmd->arg(1).toInt()); + SendCommand(str); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::ST: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>sas_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,".S%c%0d,%d\x0D",sas_layer, + cmd->arg(2).toInt(),cmd->arg(1).toInt()); + SendCommand(str); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void Quartz1::ipConnect(int conn) +{ + sas_socket[conn]-> + connectToHost(sas_ipaddress[conn].toString(),sas_ipport[conn]); +} + + +void Quartz1::connectedData(int conn) +{ + LogLine(RDConfig::LogInfo,QString(). + sprintf("Connection to Quartz1 device at %s:%d established", + (const char *)sas_ipaddress[conn].toString(), + sas_ipport[conn])); +} + + +void Quartz1::connectionClosedData(int conn) +{ + LogLine(RDConfig::LogNotice,QString(). + sprintf("Connection to Quartz1 device at %s:%d closed unexpectedly, attempting reconnect", + (const char *)sas_ipaddress[conn].toString(), + sas_ipport[conn])); + sas_reconnect_timer[conn]->start(QUARTZ1_RECONNECT_INTERVAL,true); +} + + +void Quartz1::errorData(int conn,int err) +{ + switch((QSocket::Error)err) { + case QSocket::ErrConnectionRefused: + LogLine(RDConfig::LogNotice,QString().sprintf( + "Connection to Quartz1 device at %s:%d refused, attempting reconnect", + (const char *)sas_ipaddress[conn].toString(), + sas_ipport[conn])); + sas_reconnect_timer[conn]->start(QUARTZ1_RECONNECT_INTERVAL,true); + break; + + case QSocket::ErrHostNotFound: + LogLine(RDConfig::LogWarning,QString().sprintf( + "Error on connection to Quartz1 device at %s:%d: Host Not Found", + (const char *)sas_ipaddress[conn].toString(), + sas_ipport[conn])); + break; + + case QSocket::ErrSocketRead: + LogLine(RDConfig::LogWarning,QString().sprintf( + "Error on connection to Quartz1 device at %s:%d: Socket Read Error", + (const char *)sas_ipaddress[conn].toString(), + sas_ipport[conn])); + break; + } +} + + +void Quartz1::error0Data(int err) +{ + errorData(0,err); +} + + +void Quartz1::error1Data(int err) +{ + errorData(1,err); +} + + +void Quartz1::SendCommand(const char *str) +{ + // LogLine(QString().sprintf("SENDING: %s",str)); + for(int i=0;i<2;i++) { + switch(sas_porttype[i]) { + case RDMatrix::TtyPort: + sas_device[i]->writeBlock(str,strlen(str)); + break; + + case RDMatrix::TcpPort: + sas_socket[i]->writeBlock(str,strlen(str)); + break; + + case RDMatrix::NoPort: + break; + } + } +} diff --git a/ripcd/quartz1.h b/ripcd/quartz1.h new file mode 100644 index 00000000..58cec993 --- /dev/null +++ b/ripcd/quartz1.h @@ -0,0 +1,80 @@ +// quartz1.h +// +// A Rivendell switcher driver for the Quartz Type 1 Switcher Protocol +// +// (C) Copyright 2002-2004,2008 Fred Gleason +// +// $Id: quartz1.h,v 1.8 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef QUARTZ1_H +#define QUARTZ1_H + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define QUARTZ1_RECONNECT_INTERVAL 10000 +#define QUARTZ1_MAX_LENGTH 256 + +class Quartz1 : public Switcher +{ + Q_OBJECT + public: + Quartz1(RDMatrix *matrix,QObject *parent=0,const char *name=0); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void ipConnect(int conn); + void connectedData(int conn); + void connectionClosedData(int conn); + void errorData(int conn,int err); + void error0Data(int err); + void error1Data(int err); + + private: + void SendCommand(const char *str); + RDTTYDevice *sas_device[2]; + QSocket *sas_socket[2]; + char sas_buffer[2][QUARTZ1_MAX_LENGTH]; + unsigned sas_ptr[2]; + QHostAddress sas_ipaddress[2]; + int sas_matrix; + char sas_layer; + int sas_port[2]; + int sas_ipport[2]; + int sas_inputs; + int sas_outputs; + QTimer *sas_reconnect_timer[2]; + RDMatrix::PortType sas_porttype[2]; + int sas_input_line[2]; + int sas_output_line[2]; +}; + + +#endif // QUARTZ1_H diff --git a/ripcd/ripcd.cpp b/ripcd/ripcd.cpp new file mode 100644 index 00000000..9e5b6709 --- /dev/null +++ b/ripcd/ripcd.cpp @@ -0,0 +1,888 @@ +// ripcd.cpp +// +// Rivendell Interprocess Communication Daemon +// +// (C) Copyright 2002-2007,2010 Fred Gleason +// +// $Id: ripcd.cpp,v 1.77.4.3 2013/11/17 04:27:06 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// +// Global Objects +// +RDConfig *ripcd_config; +RDCae *rdcae; +RDStation *rdstation; + + +void SigHandler(int signo) +{ + pid_t pLocalPid; + + switch(signo) { + case SIGCHLD: + pLocalPid=waitpid(-1,NULL,WNOHANG); + while(pLocalPid>0) { + pLocalPid=waitpid(-1,NULL,WNOHANG); + } + ::signal(SIGCHLD,SigHandler); + ::signal(SIGTERM,SigHandler); + ::signal(SIGINT,SigHandler); + return; + + case SIGTERM: + LogLine(RDConfig::LogInfo,"ripcd exiting normally"); + RDDeletePid(RD_PID_DIR,"ripcd.pid"); + exit(0); + break; + + case SIGINT: + LogLine(RDConfig::LogInfo,"ripcd exiting on SIGINT"); + RDDeletePid(RD_PID_DIR,"ripcd.pid"); + exit(0); + break; + } +} + + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + bool skip_db_check=false; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"ripcd",RIPCD_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + } + delete cmd; + + // + // Load Local Configs + // + ripcd_config=new RDConfig(RD_CONF_FILE); + ripcd_config->load(); + + // + // Make sure we're the only instance running + // + if(RDCheckDaemon(RD_RIPCD_PID)) { + LogLine(RDConfig::LogErr, + "ERROR ripcd aborting - multiple instances not allowed"); + exit(1); + } + + // + // Initialize Data Structures + // + debug=false; + for(int i=0;iok()) { + exit(1); + } + connect(server,SIGNAL(connection(int)),this,SLOT(newConnection(int))); + + // + // Macro Timers + // + QSignalMapper *mapper=new QSignalMapper(this,"macro_timer_mapper"); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(macroTimerData(int))); + for(int i=0;isetMapping(ripc_macro_timer[i],i); + connect(ripc_macro_timer[i],SIGNAL(timeout()),mapper,SLOT(map())); + } + + // + // Open Database + // + unsigned schema=0; + QString err (tr("ripcd: ")); + ripcd_db = RDInitDb (&schema,&err); + if(!ripcd_db) { + printf ("%s\n",err.ascii()); + exit (1); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr,"database version mismatch, should be %u, is %u", + RD_VERSION_DATABASE,schema); + exit(256); + } + connect (RDDbStatus(),SIGNAL(logText(RDConfig::LogPriority,const QString &)), + this,SLOT(log(RDConfig::LogPriority,const QString &))); + + // + // Station + // + rdstation=new RDStation(ripcd_config->stationName()); + rdstation->setUserName(rdstation->defaultName()); + ripcd_host_addr=rdstation->address(); + + // + // CAE Connection + // + rdcae=new RDCae(rdstation,ripcd_config,parent,name); + rdcae->connectHost(); + + if(qApp->argc()==1) { + RDDetach(ripcd_config->logCoreDumpDirectory()); + } + else { + debug=true; + } + ::signal(SIGCHLD,SigHandler); + ::signal(SIGTERM,SigHandler); + ::signal(SIGINT,SigHandler); + if(!RDWritePid(RD_PID_DIR,"ripcd.pid",ripcd_config->uid())) { + printf("ripcd: can't write pid file\n"); + exit(1); + } + + // + // The RML Sockets + // + ripcd_rml_send=new QSocketDevice(QSocketDevice::Datagram); + + ripcd_rml_echo=new QSocketDevice(QSocketDevice::Datagram); + ripcd_rml_echo->bind(QHostAddress(),RD_RML_ECHO_PORT); + ripcd_rml_echo->setBlocking(false); + + ripcd_rml_noecho=new QSocketDevice(QSocketDevice::Datagram); + ripcd_rml_noecho->bind(QHostAddress(),RD_RML_NOECHO_PORT); + ripcd_rml_noecho->setBlocking(false); + + ripcd_rml_reply=new QSocketDevice(QSocketDevice::Datagram); + ripcd_rml_reply->bind(QHostAddress(),RD_RML_REPLY_PORT); + ripcd_rml_reply->setBlocking(false); + + LoadGpiTable(); + + // + // Initialize local RMLs + // + LoadLocalMacros(); + + // + // Start RML Polling + // + QTimer *timer=new QTimer(this,"timer"); + timer->changeInterval(RIPCD_RML_READ_INTERVAL); + connect(timer,SIGNAL(timeout()),this,SLOT(readRml())); + timer->start(true); + + // + // Database Backup Timer + // + databaseBackup(); + ripcd_backup_timer=new QTimer(this,"ripcd_backup_timer"); + connect(ripcd_backup_timer,SIGNAL(timeout()),this,SLOT(databaseBackup())); + ripcd_backup_timer->start(86400000); + + // + // Maintenance Routine Timer + // + srandom(QTime::currentTime().msec()); + ripcd_maint_timer=new QTimer(this,"ripcd_maint_timer"); + connect(ripcd_maint_timer,SIGNAL(timeout()),this,SLOT(checkMaintData())); + int interval=GetMaintInterval(); + if(!ripcd_config->disableMaintChecks()) { + ripcd_maint_timer->start(interval); + } + else { + log(RDConfig::LogInfo,"maintenance checks disabled on this host!"); + } + + LogLine(RDConfig::LogInfo,"started"); +} + + +MainObject::~MainObject() +{ + delete server; + delete ripcd_db; +} + +void MainObject::log(RDConfig::LogPriority prio,const QString &msg) +{ + LogLine(prio,msg); +} + + +void MainObject::newConnection(int fd) +{ + unsigned i=0; + + while((isocket,SIGNAL(readyReadID(int)), + this,SLOT(socketData(int))); + connect(ripcd_conns[i]->socket,SIGNAL(connectionClosedID(int)), + this,SLOT(socketKill(int))); +} + + +void MainObject::sendRml(RDMacro *rml) +{ + char buf[RD_RML_MAX_LENGTH]; + int n; + + if((n=rml->generateString(buf,RD_RML_MAX_LENGTH))<0) { + return; + } + buf[n]=0; + switch(rml->role()) { + case RDMacro::Cmd: + ripcd_rml_send->writeBlock(buf,n,rml->address(),rml->port()); + break; + + case RDMacro::Reply: + if(!(ripcd_host_addr==rml->address())) { + ripcd_rml_send->writeBlock(buf,n,rml->address(),RD_RML_REPLY_PORT); + } + break; + + default: + break; + } +} + + +void MainObject::readRml() +{ + ReadRmlSocket(ripcd_rml_echo,RDMacro::Cmd,true); + ReadRmlSocket(ripcd_rml_noecho,RDMacro::Cmd,false); + ReadRmlSocket(ripcd_rml_reply,RDMacro::Reply,false); +} + + +void MainObject::databaseBackup() +{ + QString cmd; + QDateTime datetime=QDateTime::currentDateTime(); + int life; + + if((life=rdstation->backupLife())<=0) { + return; + } + if(fork()==0) { + cmd=QString().sprintf("find %s -name *.sql -ctime +%d -exec rm \\{\\} \\;", + (const char *)rdstation->backupPath(), + rdstation->backupLife()); + system((const char *)cmd); + cmd=QString(). + sprintf("mysqldump -c Rivendell -h %s -u %s -p%s > %s/%s.sql", + (const char *)ripcd_config->mysqlHostname(), + (const char *)ripcd_config->mysqlUsername(), + (const char *)ripcd_config->mysqlPassword(), + (const char *)rdstation->backupPath(), + (const char *)datetime.date().toString("yyyyMMdd")); + system((const char *)cmd); + exit(0); + } +} + + +void MainObject::socketData(int ch) +{ + ParseCommand(ch); +} + + +void MainObject::socketKill(int ch) +{ + KillSocket(ch); +} + + +void MainObject::checkMaintData() +{ + QString sql; + RDSqlQuery *q; + QDateTime current_datetime= + QDateTime(QDate::currentDate(),QTime::currentTime()); + bool run=false; + + RunLocalMaintRoutine(); + + // + // Should we try to run system maintenance? + // + if(!rdstation->systemMaint()) { + return; + } + + // + // Get the system-wide maintenance timestamp + // + sql="lock tables VERSION write"; + q=new RDSqlQuery(sql); + delete q; + sql="select LAST_MAINT_DATETIME from VERSION"; + q=new RDSqlQuery(sql); + if(q->first()) { + run=1000*q->value(0).toDateTime().secsTo(current_datetime)> + RD_MAINT_MAX_INTERVAL; + } + delete q; + sql="unlock tables"; + q=new RDSqlQuery(sql); + delete q; + + // + // Run the routines + // + if(run) { + RunSystemMaintRoutine(); + } +} + + +void MainObject::macroTimerData(int num) +{ + ExecCart(ripc_macro_cart[num]); + ripc_macro_cart[num]=0; +} + + +void MainObject::SetUser(QString username) +{ + rdstation->setUserName(username); + BroadcastCommand(QString().sprintf("RU %s!",(const char *)username)); +} + + +void MainObject::ParseCommand(int ch) +{ + char buf[256]; + int c; + RipcdConnection *conn=ripcd_conns[ch]; + + while((c=conn->socket->readBlock(buf,256))>0) { + buf[c]=0; + for(int i=0;iargnumargs[conn->argnum][conn->argptr]=0; + conn->argnum++; + conn->argptr=0; + } + else { + LogLine(RDConfig::LogWarning,QString(). + sprintf("*** ParseCommand1: argument list truncated. LocalBuffer: %s ***",buf)); + } + } + if(buf[i]=='!') { + conn->args[conn->argnum++][conn->argptr]=0; + DispatchCommand(ch); + conn->argnum=0; + conn->argptr=0; + if(conn->socket==NULL) { + return; + } + } + if((isgraph(buf[i]))&&(buf[i]!='!')) { + if(conn->argptrargs[conn->argnum][conn->argptr]=buf[i]; + conn->argptr++; + } + else { + if(debug) { + LogLine(RDConfig::LogWarning,QString(). + sprintf("*** ParseCommand2: argument list truncated. LocalBuffer: %s ***",buf)); + } + } + } + } + } +} + + +void MainObject::DispatchCommand(int ch) +{ + QString default_name; + char str[RD_RML_MAX_LENGTH]; + RDMacro macro; + char buffer[RD_RML_MAX_LENGTH]; + char cmd[RD_RML_MAX_LENGTH+4]; + int echo=0; + QHostAddress addr; + RipcdConnection *conn=ripcd_conns[ch]; + unsigned port; + + // + // Common Commands + // Authentication not required to execute these! + // + if(!strcmp(conn->args[0],"DC")) { // Drop Connection + conn->socket->close(); + KillSocket(ch); + return; + } + if(!strcmp(conn->args[0],"PW")) { // Password Authenticate + if(!strcmp(conn->args[1],ripcd_config->password())) { + conn->auth=true; + EchoCommand(ch,"PW +!"); + return; + } + else { + conn->auth=false; + EchoCommand(ch,"PW -!"); + return; + } + } + + // + // Priviledged Commands + // Authentication required to execute these! + // + if(!conn->auth) { + EchoArgs(ch,'-'); + return; + } + + if(!strcmp(conn->args[0],"RU")) { // Request User + EchoCommand(ch,(const char *)QString(). + sprintf("RU %s!",(const char *)rdstation->userName())); + return; + } + + if(!strcmp(conn->args[0],"SU")) { // Set User + SetUser(conn->args[1]); + } + + if(!strcmp(conn->args[0],"MS")) { // Send RML Command + if(conn->argnum<4) { + return; + } + strcpy(str,conn->args[3]); + for(int i=4;iargnum;i++) { + strcat(str," "); + strcat(str,conn->args[i]); + } + strcat(str,"!"); + } + if(macro.parseString(str,strlen(str))) { + addr.setAddress(conn->args[1]); + macro.setAddress(addr); + sscanf(conn->args[2],"%u",&port); + macro.setPort(port); + macro.setRole(RDMacro::Cmd); + +/* + char temp[RD_RML_MAX_LENGTH]; + macro.generateString(temp,RD_RML_MAX_LENGTH); + LogLine(QString().sprintf("RECEIVED: %s ADDR: %s\n",temp,(const char *)macro.address().toString())); +*/ + + if(!macro.address().isNull()) { + if(macro.address()==rdstation->address()&& + ((macro.port()==RD_RML_ECHO_PORT)|| + (macro.port()==RD_RML_NOECHO_PORT))) { // Local Loopback + macro.generateString(buffer,RD_RML_MAX_LENGTH); + if(macro.echoRequested()) { + echo=1; + } + sprintf(cmd,"MS %s %d %s",(const char *)macro.address().toString(), + echo,buffer); + RunLocalMacros(¯o); + BroadcastCommand(cmd); + } + else { + sendRml(¯o); + } + } + } + + if(!strcmp(conn->args[0],"ME")) { // Send RML Reply + if(conn->argnum<4) { + return; + } + strcpy(str,conn->args[3]); + for(int i=4;iargnum;i++) { + strcat(str," "); + strcat(str,conn->args[i]); + } + strcat(str,"!"); + } + if(macro.parseString(str,strlen(str))) { + QHostAddress addr; + addr.setAddress(conn->args[1]); + macro.setAddress(addr); + macro.setRole(RDMacro::Reply); + if(macro.address()==rdstation->address()) { // Local Loopback + macro.generateString(buffer,RD_RML_MAX_LENGTH); + sprintf(cmd,"ME %s 0 %s",(const char *)macro.address().toString(), + buffer); + BroadcastCommand(cmd); + } + else { + sendRml(¯o); + } + } + + if(!strcmp(conn->args[0],"RG")) { // Reload the GPI Table + LoadGpiTable(); + } + + if(!strcmp(conn->args[0],"GI")) { // Send Complete GPI Status + int matrix; + sscanf(conn->args[1],"%d",&matrix); + SendGpi(ch,matrix); + } + + if(!strcmp(conn->args[0],"GO")) { // Send Complete GPO Status + int matrix; + sscanf(conn->args[1],"%d",&matrix); + SendGpo(ch,matrix); + } + + if(!strcmp(conn->args[0],"GM")) { // Send Complete GPI Mask States + int matrix; + sscanf(conn->args[1],"%d",&matrix); + SendGpiMask(ch,matrix); + } + + if(!strcmp(conn->args[0],"GN")) { // Send Complete GPI Mask States + int matrix; + sscanf(conn->args[1],"%d",&matrix); + SendGpoMask(ch,matrix); + } + + if(!strcmp(conn->args[0],"GC")) { // Send Complete GPI Cart Assignments + int matrix; + sscanf(conn->args[1],"%d",&matrix); + SendGpiCart(ch,matrix); + } + + if(!strcmp(conn->args[0],"GD")) { // Send Complete GPO Cart Assignments + int matrix; + sscanf(conn->args[1],"%d",&matrix); + SendGpoCart(ch,matrix); + } + + if(!strcmp(conn->args[0],"TA")) { // Send Onair Flag State + EchoCommand(ch,QString().sprintf("TA %d!",ripc_onair_flag)); + } +} + + +void MainObject::KillSocket(int ch) +{ + delete ripcd_conns[ch]; + ripcd_conns[ch]=NULL; +} + + +void MainObject::EchoCommand(int ch,const char *command) +{ + if(ripcd_conns[ch]->socket->state()==QSocket::Connection) { + ripcd_conns[ch]->socket->writeBlock(command,strlen(command)); + } +} + + +void MainObject::BroadcastCommand(const char *command) +{ + for(unsigned i=0;iargnum;i++) { + strcat(command,ripcd_conns[ch]->args[i]); + strcat(command," "); + } + l=strlen(command); + command[l]=append; + command[l+1]='!'; + command[l+2]=0; + EchoCommand(ch,command); +} + + +void MainObject::ReadRmlSocket(QSocketDevice *dev,RDMacro::Role role, + bool echo) +{ + char buffer[RD_RML_MAX_LENGTH]; + char cmd[RD_RML_MAX_LENGTH+4]; + QString output; + int n; + QHostAddress peer_addr; + RDMacro macro; + + while((n=dev->readBlock(buffer,RD_RML_MAX_LENGTH))>0) { + buffer[n]=0; + if(macro.parseString(buffer,n)) { + macro.setRole(role); + macro.setAddress(dev->peerAddress()); + macro.setEchoRequested(echo); + macro.generateString(buffer,RD_RML_MAX_LENGTH); + switch(role) { + case RDMacro::Cmd: + sprintf(cmd,"MS %s %d %s",(const char *)macro.address().toString(), + echo,buffer); + RunLocalMacros(¯o); + BroadcastCommand(cmd); + break; + + case RDMacro::Reply: + sprintf(cmd,"ME %s %d %s",(const char *)macro.address().toString(), + echo,buffer); + break; + + default: + break; + } + } + else { + LogLine(RDConfig::LogWarning, + QString().sprintf("received malformed rml: \"%s\" from %s:%u", + buffer, + (const char *)dev->peerAddress().toString(), + dev->peerPort())); + if(echo) { + macro.setRole(RDMacro::Reply); + macro.setCommand(RDMacro::NN); + macro.setArg(0,"-"); + macro.setArgQuantity(1); + macro.setAddress(dev->peerAddress()); + sendRml(¯o); + } + } + } +} + + +void MainObject::LoadGpiTable() +{ + for(int i=0;istationName()); + RDSqlQuery *q=new RDSqlQuery(sql); + while(q->next()) { + ripcd_gpi_macro[q->value(0).toInt()][q->value(1).toInt()-1][0]= + q->value(2).toInt(); + ripcd_gpi_macro[q->value(0).toInt()][q->value(1).toInt()-1][1]= + q->value(3).toInt(); + } + delete q; + + sql=QString().sprintf("select MATRIX,NUMBER,OFF_MACRO_CART,MACRO_CART \ + from GPOS where STATION_NAME=\"%s\"", + (const char *)ripcd_config->stationName()); + q=new RDSqlQuery(sql); + while(q->next()) { + ripcd_gpo_macro[q->value(0).toInt()][q->value(1).toInt()-1][0]= + q->value(2).toInt(); + ripcd_gpo_macro[q->value(0).toInt()][q->value(1).toInt()-1][1]= + q->value(3).toInt(); + } + delete q; +} + + +void MainObject::SendGpi(int ch,int matrix) +{ + if(ripcd_switcher[matrix]==NULL) { + return; + } + for(unsigned i=0;igpiQuantity();i++) { + EchoCommand(ch,QString().sprintf("GI %d %d %d %d!", + matrix,i,ripcd_gpi_state[matrix][i], + ripcd_gpi_mask[matrix][i])); + } +} + + +void MainObject::SendGpo(int ch,int matrix) +{ + if(ripcd_switcher[matrix]==NULL) { + return; + } + for(unsigned i=0;igpoQuantity();i++) { + EchoCommand(ch,QString().sprintf("GO %d %d %d %d!", + matrix,i,ripcd_gpo_state[matrix][i], + ripcd_gpo_mask[matrix][i])); + } +} + + +void MainObject::SendGpiMask(int ch,int matrix) +{ + if(ripcd_switcher[matrix]==NULL) { + return; + } + for(unsigned i=0;igpiQuantity();i++) { + EchoCommand(ch,QString().sprintf("GM %d %d %d!", + matrix,i,ripcd_gpi_mask[matrix][i])); + } +} + + +void MainObject::SendGpoMask(int ch,int matrix) +{ + if(ripcd_switcher[matrix]==NULL) { + return; + } + for(unsigned i=0;igpoQuantity();i++) { + EchoCommand(ch,QString().sprintf("GN %d %d %d!", + matrix,i,ripcd_gpo_mask[matrix][i])); + } +} + + +void MainObject::SendGpiCart(int ch,int matrix) +{ + if(ripcd_switcher[matrix]==NULL) { + return; + } + for(unsigned i=0;igpiQuantity();i++) { + EchoCommand(ch,QString().sprintf("GC %d %d %d %d!", + matrix,i,ripcd_gpi_macro[matrix][i][0], + ripcd_gpi_macro[matrix][i][1])); + } +} + + +void MainObject::SendGpoCart(int ch,int matrix) +{ + if(ripcd_switcher[matrix]==NULL) { + return; + } + for(unsigned i=0;igpoQuantity();i++) { + EchoCommand(ch,QString().sprintf("GD %d %d %d %d!", + matrix,i,ripcd_gpo_macro[matrix][i][0], + ripcd_gpo_macro[matrix][i][1])); + } +} + + +void LogLine(RDConfig::LogPriority prio,const QString &line) +{ + FILE *logfile; + + ripcd_config->log("ripcd",prio,line); + + if((!ripcd_config) || ripcd_config->ripcdLogname().isEmpty()) { + return; + } + + QDateTime current=QDateTime::currentDateTime(); + logfile=fopen(ripcd_config->ripcdLogname(),"a"); + if(logfile==NULL) { + return; + } + chmod(ripcd_config->ripcdLogname(),S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); + fprintf(logfile,"%02d/%02d/%4d - %02d:%02d:%02d.%03d : %s\n", + current.date().month(), + current.date().day(), + current.date().year(), + current.time().hour(), + current.time().minute(), + current.time().second(), + current.time().msec(), + (const char *)line); + fclose(logfile); +} + +/* This is an overloaded virtual function to tell a session manager not to restart this daemon. */ +void QApplication::saveState(QSessionManager &sm) { + sm.setRestartHint(QSessionManager::RestartNever); + LogLine(RDConfig::LogDebug,"ripcd saveState(), set restart hint to Never"); + return; +}; + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/ripcd/ripcd.h b/ripcd/ripcd.h new file mode 100644 index 00000000..5f6f800d --- /dev/null +++ b/ripcd/ripcd.h @@ -0,0 +1,138 @@ +// ripcd.h +// +// Rivendell Interprocess Communication Daemon +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: ripcd.h,v 1.55 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RIPCD_H +#define RIPCD_H + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// +// Global RIPCD Definitions +// +#define RIPCD_MAX_LENGTH 256 +#define RIPCD_RML_READ_INTERVAL 100 +#define RIPCD_TTY_READ_INTERVAL 100 +#define RIPCD_USAGE "[-d]\n\nSupplying the '-d' flag will set 'debug' mode, causing ripcd(8) to stay\nin the foreground and print debugging info on standard output.\n" + +class MainObject : public QObject +{ + Q_OBJECT + public: + MainObject(QObject *parent=0,const char *name=0); + ~MainObject(); + + public slots: + void newConnection(int fd); + + private slots: + void log(RDConfig::LogPriority prio,const QString &msg); + void sendRml(RDMacro *rml); + void readRml(); + void gpiChangedData(int matrix,int line,bool state); + void gpoChangedData(int matrix,int line,bool state); + void gpiStateData(int matrix,unsigned line,bool state); + void gpoStateData(int matrix,unsigned line,bool state); + void ttyTrapData(int cartnum); + void ttyScanData(); + void databaseBackup(); + void macroTimerData(int num); + void socketData(int); + void socketKill(int); + void checkMaintData(); + + private: + void SetUser(QString username); + void ExecCart(int cartnum); + void ParseCommand(int); + void DispatchCommand(int); + void KillSocket(int); + void EchoCommand(int,const char *); + void BroadcastCommand(const char *); + void EchoArgs(int,const char); + void ReadRmlSocket(QSocketDevice *dev,RDMacro::Role role,bool echo); + QString StripPoint(QString); + void LoadLocalMacros(); + void RunLocalMacros(RDMacro *rml); + void LoadGpiTable(); + void SendGpi(int ch,int matrix); + void SendGpo(int ch,int matrix); + void SendGpiMask(int ch,int matrix); + void SendGpoMask(int ch,int matrix); + void SendGpiCart(int ch,int matrix); + void SendGpoCart(int ch,int matrix); + void RunSystemMaintRoutine(); + void RunLocalMaintRoutine(); + int GetMaintInterval() const; + void ForwardConvert(RDMacro *rml) const; + bool LoadSwitchDriver(int matrix_num); + QSqlDatabase *ripcd_db; + QString ripcd_host; + bool debug; + QServerSocket *server; + std::vector ripcd_conns; + QSocketDevice *ripcd_rml_send; + QSocketDevice *ripcd_rml_echo; + QSocketDevice *ripcd_rml_noecho; + QSocketDevice *ripcd_rml_reply; + QHostAddress ripcd_host_addr; + Switcher *ripcd_switcher[MAX_MATRICES]; + bool ripcd_gpi_state[MAX_MATRICES][MAX_GPIO_PINS]; + bool ripcd_gpo_state[MAX_MATRICES][MAX_GPIO_PINS]; + int ripcd_gpi_macro[MAX_MATRICES][MAX_GPIO_PINS][2]; + int ripcd_gpo_macro[MAX_MATRICES][MAX_GPIO_PINS][2]; + bool ripcd_gpi_mask[MAX_MATRICES][MAX_GPIO_PINS]; + bool ripcd_gpo_mask[MAX_MATRICES][MAX_GPIO_PINS]; + bool ripcd_tty_inuse[MAX_TTYS]; + int ripcd_switcher_tty[MAX_MATRICES][2]; + RDTTYDevice *ripcd_tty_dev[MAX_TTYS]; + RDTty::Termination ripcd_tty_term[MAX_TTYS]; + RDCodeTrap *ripcd_tty_trap[MAX_TTYS]; + QTimer *ripcd_backup_timer; + bool ripc_onair_flag; + QTimer *ripc_macro_timer[RD_MAX_MACRO_TIMERS]; + unsigned ripc_macro_cart[RD_MAX_MACRO_TIMERS]; + QTimer *ripcd_maint_timer; +}; + + +#endif // RIPCD_H diff --git a/ripcd/ripcd.pro b/ripcd/ripcd.pro new file mode 100644 index 00000000..e6b22b9e --- /dev/null +++ b/ripcd/ripcd.pro @@ -0,0 +1,55 @@ +# ripcd.pro +# +# The ripcd/ QMake project file for Rivendell +# +# (C) Copyright 2003-2005 Fred Gleason +# +# $Id: ripcd.pro,v 1.3 2007/02/14 21:57:04 fredg Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +TARGET = ripcd + +win32 { + DEFINES += WIN32 +} + +SOURCES += rdlogedit.cpp +SOURCES += edit_log.cpp +SOURCES += edit_logline.cpp +SOURCES += edit_marker.cpp +SOURCES += edit_chain.cpp +SOURCES += add_meta.cpp +SOURCES += list_logs.cpp + +HEADERS += rdlogedit.h +HEADERS += edit_log.h +HEADERS += edit_logline.h +HEADERS += edit_marker.h +HEADERS += edit_chain.h +HEADERS += add_meta.h +HEADERS += list_logs.h +HEADERS += globals.h + +RES_FILE += ..\icons\rivendell.res + +INCLUDEPATH += ..\..\libradio\radio ..\lib + +LIBS = -lqui -L..\..\libradio\radio -lradio -L..\lib -llib + +CONFIG += qt + +TRANSLATIONS += rdlogedit_es.ts diff --git a/ripcd/ripcd_connection.cpp b/ripcd/ripcd_connection.cpp new file mode 100644 index 00000000..a87518a9 --- /dev/null +++ b/ripcd/ripcd_connection.cpp @@ -0,0 +1,40 @@ +// ripcd_connection.cpp +// +// Rivendell Interprocess Communication Daemon +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: ripcd_connection.cpp,v 1.1 2010/08/03 18:41:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +RipcdConnection::RipcdConnection(int id,int fd) +{ + socket=NULL; + istate=0; + argnum=0; + argptr=0; + auth=false; + socket=new RDSocket(id); + socket->setSocket(fd); +} + + +RipcdConnection::~RipcdConnection() +{ + delete socket; +} diff --git a/ripcd/ripcd_connection.h b/ripcd/ripcd_connection.h new file mode 100644 index 00000000..cce77fad --- /dev/null +++ b/ripcd/ripcd_connection.h @@ -0,0 +1,46 @@ +// ripcd_connection.h +// +// Rivendell Interprocess Communication Daemon +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: ripcd_connection.h,v 1.1 2010/08/03 18:41:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RIPCD_CONNECTION_H +#define RIPCD_CONNECTION_H + +#include +#include + +#include +#include + +class RipcdConnection +{ + public: + RipcdConnection(int id,int fd); + ~RipcdConnection(); + RDSocket *socket; + char args[RD_RML_MAX_ARGS][RD_RML_MAX_LENGTH]; + int istate; + int argnum; + int argptr; + bool auth; +}; + + +#endif // RIPCD_CONNECTION_H diff --git a/ripcd/ripcd_socket.cpp b/ripcd/ripcd_socket.cpp new file mode 100644 index 00000000..e309d50e --- /dev/null +++ b/ripcd/ripcd_socket.cpp @@ -0,0 +1,54 @@ +// ripcd_socket.cpp +// +// Rivendell Interprocess Communication Daemon +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: ripcd_socket.cpp,v 1.9 2010/07/29 19:32:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +RipcdSocket::RipcdSocket(Q_UINT16 port,int backlog,QObject *parent, + const char *name) + : QServerSocket(port,0,parent,name) +{ +} + + +RipcdSocket::RipcdSocket(const QHostAddress &address,Q_UINT16 port,int backlog, + QObject *parent,const char *name) + : QServerSocket(address,port,0,parent,name) +{ +} + + +void RipcdSocket::newConnection(int fd) +{ + emit connection(fd); +} diff --git a/ripcd/ripcd_socket.h b/ripcd/ripcd_socket.h new file mode 100644 index 00000000..3fb1295a --- /dev/null +++ b/ripcd/ripcd_socket.h @@ -0,0 +1,50 @@ +// ripcd_socket.h +// +// Rivendell Interprocess Communication Daemon +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: ripcd_socket.h,v 1.6 2010/07/29 19:32:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RIPCD_SOCKET_H +#define RIPCD_SOCKET_H + +#include +#include +#include +#include + + +class RipcdSocket : public QServerSocket +{ + Q_OBJECT + public: + RipcdSocket(Q_UINT16 port,int backlog=0,QObject *parent=0, + const char *name=0); + RipcdSocket(const QHostAddress &address,Q_UINT16 port,int backlog=0, + QObject *parent=0,const char *name=0); + void newConnection(int socket); + + signals: + void connection(int); + + private: + QServerSocket *socket; +}; + + +#endif diff --git a/ripcd/sas32000.cpp b/ripcd/sas32000.cpp new file mode 100644 index 00000000..7691ef71 --- /dev/null +++ b/ripcd/sas32000.cpp @@ -0,0 +1,168 @@ +// sas32000.cpp +// +// A Rivendell switcher driver for the SAS32000 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: sas32000.cpp,v 1.14.8.1 2013/03/03 22:58:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + + +Sas32000::Sas32000(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Get Matrix Parameters + // + sas_inputs=matrix->inputs(); + sas_outputs=matrix->outputs(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + sas_device=new RDTTYDevice(); + if(tty->active()) { + sas_device->setName(tty->port()); + sas_device->setSpeed(tty->baudRate()); + sas_device->setWordLength(tty->dataBits()); + sas_device->setParity(tty->parity()); + sas_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; + + // + // Queue Timer + // + sas_timer=new QTimer(this,"sas_timer"); + connect(sas_timer,SIGNAL(timeout()),this,SLOT(runQueue())); +} + + +Sas32000::~Sas32000() +{ + delete sas_device; +} + + +RDMatrix::Type Sas32000::type() +{ + return RDMatrix::Sas32000; +} + + +unsigned Sas32000::gpiQuantity() +{ + return 0; +} + + +unsigned Sas32000::gpoQuantity() +{ + return 0; +} + + +bool Sas32000::primaryTtyActive() +{ + return true; +} + + +bool Sas32000::secondaryTtyActive() +{ + return false; +} + + +void Sas32000::processCommand(RDMacro *cmd) +{ + char str[9]; + char sign='1'; + + switch(cmd->command()) { + case RDMacro::ST: + SendCommand(cmd,"DT1%02d%02d"); + break; + + case RDMacro::SA: + SendCommand(cmd,"DS1%02d%02d"); + break; + + case RDMacro::SR: + SendCommand(cmd,"DS0%02d%02d"); + break; + + case RDMacro::SL: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>sas_inputs)|| + (cmd->arg(2).toInt()arg(2).toInt()>SAS32000_MAX_GAIN)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + } + if(cmd->arg(2).toInt()<0) { + sign='0'; + } + sprintf(str,"DL%02d%c%03d",cmd->arg(1).toInt(),sign, + 10*abs(cmd->arg(2).toInt())); + sas_device->writeBlock(str,8); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void Sas32000::runQueue() +{ + if(sas_commands.size()==0) { + return; + } + sas_device->writeBlock((const char *)sas_commands.front(),7); + sas_commands.pop(); + if(sas_commands.size()==0) { + sas_timer->stop(); + } +} + + +void Sas32000::SendCommand(RDMacro *cmd,const char *format) +{ + char str[8]; + + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>sas_inputs)|| + (cmd->arg(2).toInt()<0)||(cmd->arg(2).toInt()>sas_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + } + sprintf(str,format,cmd->arg(1).toInt(),cmd->arg(2).toInt()); + sas_commands.push(QString(str)); + if(!sas_timer->isActive()) { + sas_timer->start(SAS32000_COMMAND_DELAY); + } + cmd->acknowledge(true); + emit rmlEcho(cmd); +} diff --git a/ripcd/sas32000.h b/ripcd/sas32000.h new file mode 100644 index 00000000..c6db66e1 --- /dev/null +++ b/ripcd/sas32000.h @@ -0,0 +1,67 @@ +// sas32000.h +// +// A Rivendell switcher driver for the SAS32000 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: sas32000.h,v 1.11.8.1 2013/03/03 22:58:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef SAS32000_H +#define SAS32000_H + +#include + +#include + +#include +#include +#include +#include + +#include + +#define SAS32000_MIN_GAIN -99 +#define SAS32000_MAX_GAIN 28 +#define SAS32000_COMMAND_DELAY 10 + +class Sas32000 : public Switcher +{ + Q_OBJECT + public: + Sas32000(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~Sas32000(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void runQueue(); + + private: + void SendCommand(RDMacro *cmd,const char *format); + RDTTYDevice *sas_device; + int sas_inputs; + int sas_outputs; + std::queue sas_commands; + QTimer *sas_timer; +}; + + +#endif // SAS32000_H diff --git a/ripcd/sas64000.cpp b/ripcd/sas64000.cpp new file mode 100644 index 00000000..d601f3e0 --- /dev/null +++ b/ripcd/sas64000.cpp @@ -0,0 +1,118 @@ +// sas64000.cpp +// +// A Rivendell switcher driver for the SAS64000 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: sas64000.cpp,v 1.12.8.1 2013/03/03 23:30:16 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + + +Sas64000::Sas64000(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Get Matrix Parameters + // + sas_inputs=matrix->inputs(); + sas_outputs=matrix->outputs(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + sas_device=new RDTTYDevice(); + if(tty->active()) { + sas_device->setName(tty->port()); + sas_device->setSpeed(tty->baudRate()); + sas_device->setWordLength(tty->dataBits()); + sas_device->setParity(tty->parity()); + sas_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; +} + + +Sas64000::~Sas64000() +{ + delete sas_device; +} + + +RDMatrix::Type Sas64000::type() +{ + return RDMatrix::Sas64000; +} + + +unsigned Sas64000::gpiQuantity() +{ + return 0; +} + + +unsigned Sas64000::gpoQuantity() +{ + return 0; +} + + +bool Sas64000::primaryTtyActive() +{ + return true; +} + + +bool Sas64000::secondaryTtyActive() +{ + return false; +} + + +void Sas64000::processCommand(RDMacro *cmd) +{ + switch(cmd->command()) { + case RDMacro::ST: + SendCommand(cmd,"\x54%03d%03d"); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void Sas64000::SendCommand(RDMacro *cmd,const char *format) +{ + char str[8]; + + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>sas_inputs)|| + (cmd->arg(2).toInt()<0)||(cmd->arg(2).toInt()>sas_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + } + sprintf(str,format,cmd->arg(1).toInt(),cmd->arg(2).toInt()); + sas_device->writeBlock(str,7); + cmd->acknowledge(true); + emit rmlEcho(cmd); +} diff --git a/ripcd/sas64000.h b/ripcd/sas64000.h new file mode 100644 index 00000000..caffbf7c --- /dev/null +++ b/ripcd/sas64000.h @@ -0,0 +1,54 @@ +// sas64000.h +// +// A Rivendell switcher driver for the SAS64000 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: sas64000.h,v 1.10.8.1 2013/03/03 23:30:16 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef SAS64000_H +#define SAS64000_H + +#include +#include +#include +#include + +#include + +class Sas64000 : public Switcher +{ + Q_OBJECT + public: + Sas64000(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~Sas64000(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private: + void SendCommand(RDMacro *cmd,const char *format); + RDTTYDevice *sas_device; + int sas_inputs; + int sas_outputs; +}; + + +#endif // SAS64000_H diff --git a/ripcd/sas64000gpi.cpp b/ripcd/sas64000gpi.cpp new file mode 100644 index 00000000..0033bf85 --- /dev/null +++ b/ripcd/sas64000gpi.cpp @@ -0,0 +1,170 @@ +// sas64000gpi.cpp +// +// A Rivendell switcher driver for the SAS64000 connected via +// a GPI-1600 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: sas64000gpi.cpp,v 1.13 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + + +Sas64000Gpi::Sas64000Gpi(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + // + // Get Matrix Parameters + // + sas_matrix=matrix->matrix(); + sas_inputs=matrix->inputs(); + sas_outputs=matrix->outputs(); + sas_gpis=matrix->gpis(); + sas_gpos=matrix->gpos(); + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + sas_device=new RDTTYDevice(); + if(tty->active()) { + sas_device->setName(tty->port()); + sas_device->setSpeed(tty->baudRate()); + sas_device->setWordLength(tty->dataBits()); + sas_device->setParity(tty->parity()); + sas_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; + + // + // Interval OneShots + // + sas_gpo_oneshot=new RDOneShot(this); + connect(sas_gpo_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpoOneshotData(void*))); +} + + +Sas64000Gpi::~Sas64000Gpi() +{ + delete sas_device; +} + + +RDMatrix::Type Sas64000Gpi::type() +{ + return RDMatrix::Sas64000Gpi; +} + + +unsigned Sas64000Gpi::gpiQuantity() +{ + return sas_gpis; +} + + +unsigned Sas64000Gpi::gpoQuantity() +{ + return sas_gpos; +} + + +bool Sas64000Gpi::primaryTtyActive() +{ + return true; +} + + +bool Sas64000Gpi::secondaryTtyActive() +{ + return false; +} + + +void Sas64000Gpi::processCommand(RDMacro *cmd) +{ + char str[9]; + char cmd_byte; + + switch(cmd->command()) { + case RDMacro::ST: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>sas_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(str,"\xFE%c%c%c%c%c\xFF", + (char)((cmd->arg(2).toInt()-1)/16)&0x0F, + (char)((cmd->arg(2).toInt()-1)%16)&0x0F, + (char)((cmd->arg(1).toInt()-1)%128), + (char)((cmd->arg(1).toInt()-1)/128), + (char)(((cmd->arg(1).toInt()-1)%128)+ + ((cmd->arg(1).toInt()-1)/128))&0x7F); + sas_device->writeBlock(str,7); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::GO: + if((cmd->arg(1).toString().lower()!="o")|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_gpos)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(4).toInt()==0) { // Latch + if(cmd->arg(3).toInt()==0) { // Off + cmd_byte=0xF9; + emit gpoChanged(sas_matrix,cmd->arg(2).toInt()-1,false); + } + else { + cmd_byte=0xFA; + emit gpoChanged(sas_matrix,cmd->arg(2).toInt()-1,true); + } + } + else { // Pulse + if(cmd->arg(3).toInt()==0) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + cmd_byte=0xFB; + sas_gpo_oneshot->start((void *)(cmd->arg(2).toInt()-1),500); + emit gpoChanged(sas_matrix,cmd->arg(2).toInt()-1,true); + } + sprintf(str,"%c%c\xFF",cmd_byte,cmd->arg(2).toInt()-1); + sas_device->writeBlock(str,3); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void Sas64000Gpi::gpoOneshotData(void *data) +{ + emit gpoChanged(sas_matrix,(long)data,false); +} diff --git a/ripcd/sas64000gpi.h b/ripcd/sas64000gpi.h new file mode 100644 index 00000000..5c6da279 --- /dev/null +++ b/ripcd/sas64000gpi.h @@ -0,0 +1,62 @@ +// sas64000gpi.h +// +// A Rivendell switcher driver for the SAS64000 connected via +// a GPI-1600 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: sas64000gpi.h,v 1.10 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef SAS64000GPI_H +#define SAS64000GPI_H + +#include +#include +#include +#include +#include + +#include + +class Sas64000Gpi : public Switcher +{ + Q_OBJECT + public: + Sas64000Gpi(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~Sas64000Gpi(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void gpoOneshotData(void *data); + + private: + RDTTYDevice *sas_device; + RDOneShot *sas_gpo_oneshot; + int sas_matrix; + int sas_inputs; + int sas_outputs; + int sas_gpis; + int sas_gpos; +}; + + +#endif // SAS64000_H diff --git a/ripcd/sasusi.cpp b/ripcd/sasusi.cpp new file mode 100644 index 00000000..d5847463 --- /dev/null +++ b/ripcd/sasusi.cpp @@ -0,0 +1,641 @@ +// sasusi.cpp +// +// A Rivendell switcher driver for the SAS User Serial Interface Protocol +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: sasusi.cpp,v 1.24 2011/12/28 18:59:19 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +SasUsi::SasUsi(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + QString sql; + RDSqlQuery *q; + + RDTty *tty; + sas_matrix=matrix->matrix(); + sas_ptr=0; + + // + // Get Matrix Parameters + // + sas_porttype=matrix->portType(RDMatrix::Primary); + sas_ipaddress=matrix->ipAddress(RDMatrix::Primary); + sas_ipport=matrix->ipPort(RDMatrix::Primary); + sas_inputs=matrix->inputs(); + sas_outputs=matrix->outputs(); + sas_gpis=matrix->gpis(); + sas_gpos=matrix->gpos(); + sas_start_cart=matrix->startCart(RDMatrix::Primary); + sas_stop_cart=matrix->stopCart(RDMatrix::Primary); + + // + // Load Switch Table + // + sql=QString(). + sprintf("select ENGINE_NUM,DEVICE_NUM,RELAY_NUM \ + from VGUEST_RESOURCES where (STATION_NAME=\"%s\")&&\ + (MATRIX_NUM=%d) order by NUMBER", + (const char *)ripcd_config->stationName(), + matrix->matrix()); + q=new RDSqlQuery(sql); + while(q->next()) { + sas_console_numbers.push_back(q->value(0).toInt()); + sas_source_numbers.push_back(q->value(1).toInt()); + sas_relay_numbers.push_back(q->value(2).toInt()); + } + delete q; + + // + // Reconnection Timer + // + sas_reconnect_timer=new QTimer(this,"sas_reconnect_timer"); + connect(sas_reconnect_timer,SIGNAL(timeout()),this,SLOT(ipConnect())); + + // + // Initialize the connection + // + switch(sas_porttype) { + case RDMatrix::TtyPort: + tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + sas_device=new RDTTYDevice(); + if(tty->active()) { + sas_device->setName(tty->port()); + sas_device->setSpeed(tty->baudRate()); + sas_device->setWordLength(tty->dataBits()); + sas_device->setParity(tty->parity()); + sas_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; + + case RDMatrix::TcpPort: + sas_socket=new QSocket(this,"sas_socket"); + connect(sas_socket,SIGNAL(connected()),this,SLOT(connectedData())); + connect(sas_socket,SIGNAL(connectionClosed()), + this,SLOT(connectionClosedData())); + connect(sas_socket,SIGNAL(readyRead()), + this,SLOT(readyReadData())); + connect(sas_socket,SIGNAL(error(int)),this,SLOT(errorData(int))); + ipConnect(); + break; + + case RDMatrix::NoPort: + break; + } +} + + +RDMatrix::Type SasUsi::type() +{ + return RDMatrix::SasUsi; +} + + +unsigned SasUsi::gpiQuantity() +{ + return sas_gpis; +} + + +unsigned SasUsi::gpoQuantity() +{ + return sas_gpos; +} + + +bool SasUsi::primaryTtyActive() +{ + return sas_porttype==RDMatrix::TtyPort; +} + + +bool SasUsi::secondaryTtyActive() +{ + return false; +} + + +void SasUsi::processCommand(RDMacro *cmd) +{ + char str[256]; + char cmd_byte; + QString label; + + switch(cmd->command()) { + case RDMacro::CL: + if((cmd->arg(1).toInt()<1)|| + ((cmd->arg(1).toInt()>256)&&(cmd->arg(1).toInt()!=999))|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_inputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + for(int i=3;i<(cmd->argQuantity()-1);i++) { + label+=(cmd->arg(i).toString()+" "); + } + label+=cmd->arg(cmd->argQuantity()-1).toString(); + if(label.length()>8) { + label=label.left(8); + } + for(int i=label.length();i<8;i++) { + label+=" "; + } + snprintf(str,256,"%c21%03d%04d%s\x0D\x0A",26, + cmd->arg(1).toInt(),cmd->arg(2).toInt(),(const char *)label); + SendCommand(str); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::FS: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>256)|| + (sas_porttype!=RDMatrix::TcpPort)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + snprintf(str,256,"%c1%03d\x0D\x0A",0x13,cmd->arg(1).toInt()); + SendCommand(str); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SG: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>sas_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_outputs)|| + (cmd->arg(3).toInt()<-1024)||(cmd->arg(3).toInt()>1024)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + snprintf(str,256,"%c00%04d%04d%04d00548\x0D\x0A",26, + cmd->arg(1).toInt(),cmd->arg(2).toInt(), + cmd->arg(3).toInt()+1024); + SendCommand(str); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SX: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>sas_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_outputs)|| + (cmd->arg(3).toInt()<-1024)||(cmd->arg(3).toInt()>1024)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + snprintf(str,256,"%c10%04d%04d%04d0010\x0D\x0A",26, + cmd->arg(1).toInt(),cmd->arg(2).toInt(), + cmd->arg(3).toInt()+1024); + SendCommand(str); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SL: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>sas_inputs)|| + (cmd->arg(2).toInt()<-1024)||(cmd->arg(2).toInt()>1024)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + snprintf(str,256,"%c10%04d0000%04d0001\x0D\x0A",26, + cmd->arg(1).toInt(),cmd->arg(2).toInt()+1024); + SendCommand(str); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SA: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>sas_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + snprintf(str,256,"%c00%04d%04d102400036\x0D\x0A",26, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + SendCommand(str); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::SR: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>sas_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + snprintf(str,256,"%c00%04d%04d102400032\x0D\x0A",26, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + SendCommand(str); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::ST: + if((cmd->arg(1).toInt()<0)||(cmd->arg(1).toInt()>sas_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + snprintf(str,256,"%c%03d%03d\x0D\x0A",20, + cmd->arg(1).toInt(),cmd->arg(2).toInt()); + SendCommand(str); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::GO: + if((cmd->arg(1).toString().lower()!="o")|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>sas_gpos)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(4).toInt()==0) { // Latch + if(cmd->arg(3).toInt()==0) { // Off + cmd_byte=0x03; + } + else { + cmd_byte=0x02; + } + } + else { + if(cmd->arg(3).toInt()==0) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + cmd_byte=0x01; + } + if(cmd->arg(2).toUInt()arg(2).toUInt()-1]>=0) { + snprintf(str,256,"\x05R%d%04d\x0D\x0A",cmd_byte, + sas_relay_numbers[cmd->arg(2).toUInt()-1]); + SendCommand(str); + cmd->acknowledge(true); + emit rmlEcho(cmd); + } + else { + if((sas_console_numbers[cmd->arg(2).toUInt()-1]>=0)&& + (sas_source_numbers[cmd->arg(2).toUInt()-1]>=0)) { + if(cmd->arg(3).toInt()==0) { // Off + cmd_byte=0; + } + else { + cmd_byte=1; + } + snprintf(str,256,"\x1A%s%d%03d%04d\x0D\x0A","20",cmd_byte, + sas_console_numbers[cmd->arg(2).toUInt()-1], + sas_source_numbers[cmd->arg(2).toUInt()-1]); + SendCommand(str); + cmd->acknowledge(true); + emit rmlEcho(cmd); + } + } + } + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void SasUsi::ipConnect() +{ + sas_socket->connectToHost(sas_ipaddress.toString(),sas_ipport); +} + + +void SasUsi::connectedData() +{ + LogLine(RDConfig::LogInfo,QString(). + sprintf("Connection to SasUsi device at %s:%d established", + (const char *)sas_ipaddress.toString(), + sas_ipport)); + if(sas_start_cart>0) { + ExecuteMacroCart(sas_start_cart); + } +} + + +void SasUsi::connectionClosedData() +{ + LogLine(RDConfig::LogNotice,QString(). + sprintf("Connection to SasUsi device at %s:%d closed unexpectedly, attempting reconnect", + (const char *)sas_ipaddress.toString(), + sas_ipport)); + if(sas_stop_cart>0) { + ExecuteMacroCart(sas_stop_cart); + } + sas_reconnect_timer->start(SASUSI_RECONNECT_INTERVAL,true); +} + + +void SasUsi::readyReadData() +{ + char buffer[256]; + unsigned n; + + while((n=sas_socket->readBlock(buffer,255))>0) { + buffer[n]=0; + for(unsigned i=0;istart(SASUSI_RECONNECT_INTERVAL,true); + break; + + case QSocket::ErrHostNotFound: + LogLine(RDConfig::LogWarning,QString().sprintf( + "Error on connection to SasUsi device at %s:%d: Host Not Found", + (const char *)sas_ipaddress.toString(), + sas_ipport)); + break; + + case QSocket::ErrSocketRead: + LogLine(RDConfig::LogWarning,QString().sprintf( + "Error on connection to SasUsi device at %s:%d: Socket Read Error", + (const char *)sas_ipaddress.toString(), + sas_ipport)); + break; + } +} + + +void SasUsi::SendCommand(char *str) +{ + LogLine(RDConfig::LogDebug,QString().sprintf("sending USI cmd: %s",(const char *)PrettifyCommand(str))); + switch(sas_porttype) { + case RDMatrix::TtyPort: + sas_device->writeBlock(str,strlen(str)); + break; + + case RDMatrix::TcpPort: + sas_socket->writeBlock(str,strlen(str)); + break; + + case RDMatrix::NoPort: + break; + } +} + + +void SasUsi::DispatchCommand() +{ + char buffer[SASUSI_MAX_LENGTH]; + unsigned input; + unsigned output; + int line; + unsigned action; + int console; + int source; + bool state; + bool ok=false; + QString cmd; + QString label; + QString sql; + RDSqlQuery *q; + + //LogLine(RDConfig::LogNotice,QString().sprintf("DISPATCHED: %s",(const char *)sas_buffer)); + + // + // Startup Sequence. Get the input and output lists. The response + // to the ^EI command lets us know when the lists are done. + // + if(QString("login sucessful")==(QString(sas_buffer).lower())) { + sprintf(buffer,"%cX9999\x0D\x0A",5); // Request Input List + SendCommand(buffer); + sprintf(buffer,"%cY9999\x0D\x0A",5); // Request Output List + SendCommand(buffer); + sprintf(buffer,"%cI0001\x0D\x0A",5); // Start Finished + SendCommand(buffer); + return; + } + + // + // Work around the idiotic 'SAS READY' prompt + // + if(sas_buffer[0]==27) { + for(unsigned i=17;iname(), + sas_matrix,input); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("update INPUTS set NAME=\"%s\" where \ + (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&(NUMBER=%d)", + (const char *)label, + (const char *)rdstation->name(), + sas_matrix,input); + } + else { + sql=QString().sprintf("insert into INPUTS set NAME=\"%s\",\ + STATION_NAME=\"%s\",MATRIX=%d,NUMBER=%d", + (const char *)label, + (const char *)rdstation->name(), + sas_matrix,input); + } + delete q; + q=new RDSqlQuery(sql); + delete q; + break; + + case 22: // Output Name [^V] + if(strlen(sas_buffer)<13) { + return; + } + label=sas_buffer+5; + sas_buffer[5]=0; + if(sscanf(sas_buffer+1,"%u",&output)!=1) { + return; + } + sql=QString().sprintf("select NUMBER from OUTPUTS where \ + (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&(NUMBER=%d)", + (const char *)rdstation->name(), + sas_matrix,output); + q=new RDSqlQuery(sql); + if(q->first()) { + sql=QString().sprintf("update OUTPUTS set NAME=\"%s\" where \ + (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&(NUMBER=%d)", + (const char *)label, + (const char *)rdstation->name(), + sas_matrix,output); + } + else { + sql=QString().sprintf("insert into OUTPUTS set NAME=\"%s\",\ + STATION_NAME=\"%s\",MATRIX=%d,NUMBER=%d", + (const char *)label, + (const char *)rdstation->name(), + sas_matrix,output); + } + delete q; + q=new RDSqlQuery(sql); + delete q; + break; + + case 'M': // Console Module Action + if(strlen(sas_buffer)<9) { + return; + } + cmd=QString(sas_buffer); + console=cmd.mid(2,3).toInt(&ok); + if(!ok) { + return; + } + source=cmd.mid(5,4).toInt(&ok); + if(!ok) { + return; + } + for(unsigned i=0;iaddress()); + rml.setEchoRequested(false); + rml.setArgQuantity(1); + rml.setArg(0,cartnum); + emit rmlEcho(&rml); +} + + +QString SasUsi::PrettifyCommand(const char *cmd) const +{ + QString ret; + if(cmd[0]<26) { + ret=QString().sprintf("^%c%s",'@'+cmd[0],cmd+1); + } + else { + ret=cmd; + } + return ret; +} diff --git a/ripcd/sasusi.h b/ripcd/sasusi.h new file mode 100644 index 00000000..19362bac --- /dev/null +++ b/ripcd/sasusi.h @@ -0,0 +1,87 @@ +// sasusi.h +// +// A Rivendell switcher driver for the SAS User Serial Interface Protocol +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: sasusi.h,v 1.16 2011/05/26 21:20:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef SASUSI_H +#define SASUSI_H + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define SASUSI_RECONNECT_INTERVAL 10000 +#define SASUSI_MAX_LENGTH 256 + +class SasUsi : public Switcher +{ + Q_OBJECT + public: + SasUsi(RDMatrix *matrix,QObject *parent=0,const char *name=0); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void ipConnect(); + void connectedData(); + void connectionClosedData(); + void readyReadData(); + void errorData(int err); + + private: + void SendCommand(char *str); + void DispatchCommand(); + void ExecuteMacroCart(unsigned cartnum); + QString PrettifyCommand(const char *cmd) const; + RDTTYDevice *sas_device; + QSocket *sas_socket; + char sas_buffer[SASUSI_MAX_LENGTH]; + unsigned sas_ptr; + QHostAddress sas_ipaddress; + int sas_matrix; + int sas_ipport; + int sas_inputs; + int sas_outputs; + int sas_gpis; + int sas_gpos; + QTimer *sas_reconnect_timer; + unsigned sas_start_cart; + unsigned sas_stop_cart; + RDMatrix::PortType sas_porttype; + std::vector sas_console_numbers; + std::vector sas_source_numbers; + std::vector sas_relay_numbers; +}; + + +#endif // SASUSI_H diff --git a/ripcd/starguide3.cpp b/ripcd/starguide3.cpp new file mode 100644 index 00000000..b7502715 --- /dev/null +++ b/ripcd/starguide3.cpp @@ -0,0 +1,159 @@ +// starguide3.cpp +// +// A Rivendell switcher driver for the StarGuide III Satellite Receiver +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: starguide3.cpp,v 1.14 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include + + +StarGuide3::StarGuide3(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + QString sql; + RDSqlQuery *q; + + // + // Get Matrix Parameters + // + sg_inputs=matrix->inputs(); + sg_outputs=matrix->outputs(); + + // + // Load Feed Data + // + sql=QString().sprintf("select NUMBER,ENGINE_NUM,DEVICE_NUM,CHANNEL_MODE\ + from INPUTS where STATION_NAME=\"%s\" && MATRIX=%d \ + order by NUMBER", + (const char *)rdstation->name(), + matrix->matrix()); + q=new RDSqlQuery(sql); + q->first(); + for(int i=0;iisValid()&&(q->value(0).toInt()==(i+1))) { + sg_feed.back().setProviderId(q->value(1).toInt()); + sg_feed.back().setServiceId(q->value(2).toInt()); + sg_feed.back().setMode((RDMatrix::Mode)q->value(3).toInt()); + q->next(); + } + } + delete q; + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + sg_device=new RDTTYDevice(); + if(tty->active()) { + sg_device->setName(tty->port()); + sg_device->setSpeed(tty->baudRate()); + sg_device->setWordLength(tty->dataBits()); + sg_device->setParity(tty->parity()); + sg_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; +} + + +StarGuide3::~StarGuide3() +{ + delete sg_device; +} + + +RDMatrix::Type StarGuide3::type() +{ + return RDMatrix::StarGuideIII; +} + + +unsigned StarGuide3::gpiQuantity() +{ + return 0; +} + + +unsigned StarGuide3::gpoQuantity() +{ + return false; +} + + +bool StarGuide3::primaryTtyActive() +{ + return true; +} + + +bool StarGuide3::secondaryTtyActive() +{ + return false; +} + + +void StarGuide3::processCommand(RDMacro *cmd) +{ + char str[256]; + char route; + int input=cmd->arg(1).toInt()-1; + int output=cmd->arg(2).toInt()-1; + + if((input<0)||(input>=sg_inputs)|| + (output<0)||(output>=sg_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + switch(sg_feed[input].mode()) { + case RDMatrix::Left: + route='1'; + break; + + case RDMatrix::Right: + route='2'; + break; + + default: + route='0'; + break; + } + switch(cmd->command()) { + case RDMacro::ST: + sprintf(str,"SP A,P,%d\rSP A,S,%d\rAM %c,0%c\r", + sg_feed[input].providerId(), + sg_feed[input].serviceId(), + output+'A', + route); + sg_device->writeBlock(str,strlen(str)); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} diff --git a/ripcd/starguide3.h b/ripcd/starguide3.h new file mode 100644 index 00000000..23ce4ad0 --- /dev/null +++ b/ripcd/starguide3.h @@ -0,0 +1,59 @@ +// starguide3.h +// +// A Rivendell switcher driver for the StarGuide III Satellite Receiver +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: starguide3.h,v 1.9 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef STARGUIDE3_H +#define STARGUIDE3_H + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +class StarGuide3 : public Switcher +{ + Q_OBJECT + public: + StarGuide3(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~StarGuide3(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private: + RDTTYDevice *sg_device; + std::vector sg_feed; + int sg_inputs; + int sg_outputs; +}; + + +#endif // STARGUIDE3_H diff --git a/ripcd/starguide_feed.cpp b/ripcd/starguide_feed.cpp new file mode 100644 index 00000000..6caf1d60 --- /dev/null +++ b/ripcd/starguide_feed.cpp @@ -0,0 +1,72 @@ +// starguide_feed.cpp +// +// A feed data container class for the StarGuide III Satellite Receiver +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: starguide_feed.cpp,v 1.5 2010/07/29 19:32:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + + +StarGuideFeed::StarGuideFeed() +{ +} + + +int StarGuideFeed::providerId() const +{ + return sg_provider_id; +} + + +void StarGuideFeed::setProviderId(int id) +{ + sg_provider_id=id; +} + + +int StarGuideFeed::serviceId() const +{ + return sg_service_id; +} + + +void StarGuideFeed::setServiceId(int id) +{ + sg_service_id=id; +} + + +RDMatrix::Mode StarGuideFeed::mode() const +{ + return sg_mode; +} + + +void StarGuideFeed::setMode(RDMatrix::Mode mode) +{ + sg_mode=mode; +} + + +void StarGuideFeed::clear() +{ + sg_provider_id=-1; + sg_service_id=-1; + sg_mode=RDMatrix::Stereo; +} diff --git a/ripcd/starguide_feed.h b/ripcd/starguide_feed.h new file mode 100644 index 00000000..bbe0b6e5 --- /dev/null +++ b/ripcd/starguide_feed.h @@ -0,0 +1,49 @@ +// starguide_feed.h +// +// A feed data container class for the StarGuide III Satellite Receiver +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: starguide_feed.h,v 1.6 2010/07/29 19:32:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef STARGUIDE_FEED_H +#define STARGUIDE_FEED_H + +#include + +#include + +class StarGuideFeed +{ + public: + StarGuideFeed(); + int providerId() const; + void setProviderId(int id); + int serviceId() const; + void setServiceId(int id); + RDMatrix::Mode mode() const; + void setMode(RDMatrix::Mode mode); + void clear(); + + private: + int sg_provider_id; + int sg_service_id; + RDMatrix::Mode sg_mode; +}; + + +#endif // STARGUIDE_FEED_H diff --git a/ripcd/switcher.cpp b/ripcd/switcher.cpp new file mode 100644 index 00000000..d881820c --- /dev/null +++ b/ripcd/switcher.cpp @@ -0,0 +1,112 @@ +// switcher.cpp +// +// Abstract base class for Rivendell Switcher/GPIO drivers. +// +// (C) Copyright 2002-2007,2010 Fred Gleason +// +// $Id: switcher.cpp,v 1.1.8.3 2013/11/16 01:06:01 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include + +#include + +#include + +Switcher::Switcher(RDMatrix *matrix,QObject *parent,const char *name) + : QObject(parent,name) +{ + switcher_station_name=matrix->station(); + switcher_matrix_number=matrix->matrix(); +} + + +Switcher::~Switcher() +{ +} + + +QString Switcher::stationName() const +{ + return switcher_station_name; +} + + +int Switcher::matrixNumber() const +{ + return switcher_matrix_number; +} + + +void Switcher::sendGpi() +{ +} + + +void Switcher::sendGpo() +{ +} + + +void Switcher::executeMacroCart(unsigned cartnum) +{ + RDMacro rml; + rml.setRole(RDMacro::Cmd); + rml.setCommand(RDMacro::EX); + rml.setAddress(rdstation->address()); + rml.setEchoRequested(false); + rml.setArgQuantity(1); + rml.setArg(0,cartnum); + emit rmlEcho(&rml); +} + + +void Switcher::logBytes(uint8_t *data,int len) +{ + QString str; + + for(int i=0;ifirst()) { + delete q; + sql="insert into "+table+" set STATION_NAME=\""+ + RDEscapeString(stationName())+"\","+ + QString().sprintf("MATRIX=%u,NUMBER=%d",matrixNumber(),line); + q=new RDSqlQuery(sql); + } + delete q; +} diff --git a/ripcd/switcher.h b/ripcd/switcher.h new file mode 100644 index 00000000..b6990d06 --- /dev/null +++ b/ripcd/switcher.h @@ -0,0 +1,68 @@ +// switcher.h +// +// Abstract base class for Rivendell Switcher/GPIO drivers. +// +// (C) Copyright 2002-2007,1020 Fred Gleason +// +// $Id: switcher.h,v 1.1.8.3 2013/11/16 01:06:01 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef SWITCHER_H +#define SWITCHER_H + +#include + +#include + +#include +#include + +class Switcher : public QObject +{ + Q_OBJECT + public: + Switcher(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~Switcher(); + QString stationName() const; + int matrixNumber() const; + virtual RDMatrix::Type type()=0; + virtual unsigned gpiQuantity()=0; + virtual unsigned gpoQuantity()=0; + virtual bool primaryTtyActive()=0; + virtual bool secondaryTtyActive()=0; + virtual void processCommand(RDMacro *cmd)=0; + virtual void sendGpi(); + virtual void sendGpo(); + + signals: + void rmlEcho(RDMacro *cmd); + void gpiChanged(int matrix,int line,bool state); + void gpoChanged(int matrix,int line,bool state); + void gpiState(int matrix,unsigned line,bool state); + void gpoState(int matrix,unsigned line,bool state); + + protected: + void executeMacroCart(unsigned cartnum); + void logBytes(uint8_t *data,int len); + void insertGpioEntry(bool is_gpo,int line); + + private: + QString switcher_station_name; + int switcher_matrix_number; +}; + + +#endif // SWITCHER_H diff --git a/ripcd/unity4000.cpp b/ripcd/unity4000.cpp new file mode 100644 index 00000000..d510b611 --- /dev/null +++ b/ripcd/unity4000.cpp @@ -0,0 +1,165 @@ +// unity4000.cpp +// +// A Rivendell switcher driver for the UNITY4000 +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: unity4000.cpp,v 1.13 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include + + +Unity4000::Unity4000(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + QString sql; + RDSqlQuery *q; + + // + // Get Matrix Parameters + // + unity_inputs=matrix->inputs(); + unity_outputs=matrix->outputs(); + + // + // Load Feed Data + // + sql=QString().sprintf("select NUMBER,FEED_NAME,CHANNEL_MODE from INPUTS \ + where STATION_NAME=\"%s\" && MATRIX=%d \ + order by NUMBER", + (const char *)rdstation->name(), + matrix->matrix()); + q=new RDSqlQuery(sql); + q->first(); + for(int i=0;iisValid()&&(q->value(0).toInt()==(i+1))) { + unity_feed.back().setFeed(q->value(1).toString()); + unity_feed.back().setMode((RDMatrix::Mode)q->value(2).toInt()); + q->next(); + } + } + delete q; + + // + // Initialize the TTY Port + // + RDTty *tty=new RDTty(rdstation->name(),matrix->port(RDMatrix::Primary)); + unity_device=new RDTTYDevice(); + if(tty->active()) { + unity_device->setName(tty->port()); + unity_device->setSpeed(tty->baudRate()); + unity_device->setWordLength(tty->dataBits()); + unity_device->setParity(tty->parity()); + unity_device->open(IO_Raw|IO_ReadWrite); + } + delete tty; +} + + +Unity4000::~Unity4000() +{ + delete unity_device; +} + + +RDMatrix::Type Unity4000::type() +{ + return RDMatrix::Unity4000; +} + + +unsigned Unity4000::gpiQuantity() +{ + return 0; +} + + +unsigned Unity4000::gpoQuantity() +{ + return 0; +} + + +bool Unity4000::primaryTtyActive() +{ + return true; +} + + +bool Unity4000::secondaryTtyActive() +{ + return false; +} + + +void Unity4000::processCommand(RDMacro *cmd) +{ + char str[256]; + char route; + int input=cmd->arg(1).toInt()-1; + int output=cmd->arg(2).toInt()-1; + + if((input<-1)||(input>=unity_inputs)|| + (output<0)||(output>=unity_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + switch(unity_feed[input].mode()) { + case RDMatrix::Left: + route='1'; + break; + + case RDMatrix::Right: + route='2'; + break; + + default: + route='S'; + break; + } + switch(cmd->command()) { + case RDMacro::ST: + if(input==-1) { + sprintf(str,"\x0DMUTE A/%d\x0D",output+1); + unity_device->writeBlock(str,strlen(str)); + } + else { + sprintf(str,"\x0DUNMUTE A/%d\x0D",output+1); + unity_device->writeBlock(str,strlen(str)); + sprintf(str,"\x0DSETAUDIO %d %c %s\x0D", + output+1, + route, + (const char *)unity_feed[input].feed()); + unity_device->writeBlock(str,strlen(str)); + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} diff --git a/ripcd/unity4000.h b/ripcd/unity4000.h new file mode 100644 index 00000000..3b862b74 --- /dev/null +++ b/ripcd/unity4000.h @@ -0,0 +1,59 @@ +// unity4000.h +// +// A Rivendell switcher driver for the UNITY4000 +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: unity4000.h,v 1.9 2010/08/03 23:39:26 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef UNITY4000_H +#define UNITY4000_H + +#include + +#include + +#include +#include +#include +#include + +#include +#include + +class Unity4000 : public Switcher +{ + Q_OBJECT + public: + Unity4000(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~Unity4000(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private: + RDTTYDevice *unity_device; + std::vector unity_feed; + int unity_inputs; + int unity_outputs; +}; + + +#endif // UNITY4000_H diff --git a/ripcd/unity_feed.cpp b/ripcd/unity_feed.cpp new file mode 100644 index 00000000..66580ba8 --- /dev/null +++ b/ripcd/unity_feed.cpp @@ -0,0 +1,59 @@ +// unity_feed.cpp +// +// A feed data container class for the Unity4000 +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: unity_feed.cpp,v 1.5 2010/07/29 19:32:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + + +UnityFeed::UnityFeed() +{ +} + + +QString UnityFeed::feed() const +{ + return unity_feed; +} + + +void UnityFeed::setFeed(QString feed) +{ + unity_feed=feed; +} + + +RDMatrix::Mode UnityFeed::mode() const +{ + return unity_mode; +} + + +void UnityFeed::setMode(RDMatrix::Mode mode) +{ + unity_mode=mode; +} + + +void UnityFeed::clear() +{ + unity_feed=""; + unity_mode=RDMatrix::Stereo; +} diff --git a/ripcd/unity_feed.h b/ripcd/unity_feed.h new file mode 100644 index 00000000..7a092f0a --- /dev/null +++ b/ripcd/unity_feed.h @@ -0,0 +1,46 @@ +// unity_feed.h +// +// A feed data container class for the Unity4000 +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: unity_feed.h,v 1.6 2010/07/29 19:32:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef UNITY_FEED_H +#define UNITY_FEED_H + +#include + +#include + +class UnityFeed +{ + public: + UnityFeed(); + QString feed() const; + void setFeed(QString feed); + RDMatrix::Mode mode() const; + void setMode(RDMatrix::Mode mode); + void clear(); + + private: + QString unity_feed; + RDMatrix::Mode unity_mode; +}; + + +#endif // UNITY_FEED_H diff --git a/ripcd/vguest.cpp b/ripcd/vguest.cpp new file mode 100644 index 00000000..ada1628a --- /dev/null +++ b/ripcd/vguest.cpp @@ -0,0 +1,816 @@ +// vguest.cpp +// +// A Rivendell switcher driver for the Logitek vGuest Protocol +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: vguest.cpp,v 1.36.8.3 2013/11/07 23:00:00 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include +#include + + +VGuest::VGuest(RDMatrix *matrix,QObject *parent,const char *name) + : Switcher(matrix,parent,name) +{ + RDTty *tty; + QString sql; + RDSqlQuery *q; + int n; + + for(int i=0;i<2;i++) { + vguest_device[i]=NULL; + vguest_socket[i]=NULL; + vguest_error_notified[i]=false; + } + + // + // Get Matrix Parameters + // + vguest_matrix=matrix->matrix(); + vguest_device[0]=NULL; + vguest_device[1]=NULL; + vguest_socket[0]=NULL; + vguest_socket[1]=NULL; + vguest_porttype[0]=matrix->portType(RDMatrix::Primary); + vguest_porttype[1]=matrix->portType(RDMatrix::Backup); + vguest_ipaddress[0]=matrix->ipAddress(RDMatrix::Primary); + vguest_ipaddress[1]=matrix->ipAddress(RDMatrix::Backup); + vguest_username[0]=PadString(matrix->username(RDMatrix::Primary),16); + vguest_username[1]=PadString(matrix->username(RDMatrix::Backup),16); + vguest_password[0]=PadString(matrix->password(RDMatrix::Primary),16); + vguest_password[1]=PadString(matrix->password(RDMatrix::Backup),16); + vguest_start_cart[0]=matrix->startCart(RDMatrix::Primary); + vguest_start_cart[1]=matrix->startCart(RDMatrix::Backup); + vguest_stop_cart[0]=matrix->stopCart(RDMatrix::Primary); + vguest_stop_cart[1]=matrix->stopCart(RDMatrix::Backup); + vguest_ipport[0]=matrix->ipPort(RDMatrix::Primary); + vguest_ipport[1]=matrix->ipPort(RDMatrix::Backup); + vguest_inputs=matrix->inputs(); + vguest_outputs=matrix->outputs(); + vguest_gpis=matrix->gpis(); + vguest_gpos=matrix->gpos(); + + // + // Load Engine Data - Inputs + // + sql=QString().sprintf("select NUMBER,ENGINE_NUM,DEVICE_NUM from INPUTS where\ + (STATION_NAME=\"%s\")&&(MATRIX=%d) order by NUMBER", + (const char *)matrix->station(),matrix->matrix()); + q=new RDSqlQuery(sql); + n=1; + while(q->next()) { + while(q->value(0).toInt()>n) { + vguest_input_engine_nums.push_back(-1); + vguest_input_device_nums.push_back(-1); + n++; + } + vguest_input_engine_nums.push_back(q->value(1).toInt()); + vguest_input_device_nums.push_back(q->value(2).toInt()); + n++; + } + delete q; + + // + // Load Engine Data - Outputs + // + sql= + QString().sprintf("select NUMBER,ENGINE_NUM,DEVICE_NUM from OUTPUTS where\ + (STATION_NAME=\"%s\")&&(MATRIX=%d) order by NUMBER", + (const char *)matrix->station(),matrix->matrix()); + q=new RDSqlQuery(sql); + n=1; + while(q->next()) { + while(q->value(0).toInt()>n) { + vguest_output_engine_nums.push_back(-1); + vguest_output_device_nums.push_back(-1); + n++; + } + vguest_output_engine_nums.push_back(q->value(1).toInt()); + vguest_output_device_nums.push_back(q->value(2).toInt()); + n++; + } + delete q; + + // + // Load Engine Data - Relays + // + sql= + QString().sprintf("select NUMBER,ENGINE_NUM,DEVICE_NUM,SURFACE_NUM,\ + RELAY_NUM from VGUEST_RESOURCES where\ + (STATION_NAME=\"%s\")&&(MATRIX_NUM=%d)&&\ + (VGUEST_TYPE=%d) order by NUMBER", + (const char *)matrix->station(),matrix->matrix(), + RDMatrix::VguestTypeRelay); + q=new RDSqlQuery(sql); + n=1; + while(q->next()) { + while(q->value(0).toInt()>n) { + vguest_relays_engine_nums.push_back(-1); + vguest_relays_device_nums.push_back(-1); + vguest_relays_surface_nums.push_back(-1); + vguest_relays_relay_nums.push_back(-1); + n++; + } + vguest_relays_engine_nums.push_back(q->value(1).toInt()); + vguest_relays_device_nums.push_back(q->value(2).toInt()); + vguest_relays_surface_nums.push_back(q->value(3).toInt()); + vguest_relays_relay_nums.push_back(q->value(4).toInt()); + n++; + } + delete q; + + // + // Load Engine Data - Displays + // + sql= + QString().sprintf("select NUMBER,ENGINE_NUM,DEVICE_NUM,SURFACE_NUM\ + from VGUEST_RESOURCES where\ + (STATION_NAME=\"%s\")&&(MATRIX_NUM=%d)&&\ + (VGUEST_TYPE=%d) order by NUMBER", + (const char *)matrix->station(),matrix->matrix(), + RDMatrix::VguestTypeDisplay); + q=new RDSqlQuery(sql); + n=1; + while(q->next()) { + while(q->value(0).toInt()>n) { + vguest_displays_engine_nums.push_back(-1); + vguest_displays_device_nums.push_back(-1); + vguest_displays_surface_nums.push_back(-1); + n++; + } + vguest_displays_engine_nums.push_back(q->value(1).toInt()); + vguest_displays_device_nums.push_back(q->value(2).toInt()); + vguest_displays_surface_nums.push_back(q->value(3).toInt()); + n++; + } + delete q; + + // + // Ping Timers + // + vguest_ping_mapper=new QSignalMapper(this); + connect(vguest_ping_mapper,SIGNAL(mapped(int)),this,SLOT(pingData(int))); + vguest_ping_response_mapper=new QSignalMapper(this); + connect(vguest_ping_response_mapper,SIGNAL(mapped(int)), + this,SLOT(pingResponseData(int))); + for(int i=0;i<2;i++) { + vguest_ping_timer[i]=new QTimer(this); + vguest_ping_mapper->setMapping(vguest_ping_timer[i],i); + connect(vguest_ping_timer[i],SIGNAL(timeout()), + vguest_ping_mapper,SLOT(map())); + + vguest_ping_response_timer[i]=new QTimer(this); + vguest_ping_response_mapper->setMapping(vguest_ping_timer[i],i); + connect(vguest_ping_response_timer[i],SIGNAL(timeout()), + vguest_ping_response_mapper,SLOT(map())); + } + + // + // Reconnection Timer + // + QSignalMapper *reconnect_mapper=new QSignalMapper(this); + connect(reconnect_mapper,SIGNAL(mapped(int)), + this,SLOT(ipConnect(int))); + for(int i=0;i<2;i++) { + vguest_reconnect_timer[i]=new QTimer(this); + reconnect_mapper->setMapping(vguest_reconnect_timer[i],i); + connect(vguest_reconnect_timer[i],SIGNAL(timeout()), + reconnect_mapper,SLOT(map())); + } + + // + // Interval OneShots + // + vguest_gpio_oneshot=new RDOneShot(this); + connect(vguest_gpio_oneshot,SIGNAL(timeout(void *)), + this,SLOT(gpioOneshotData(void*))); + + // + // Initialize the connection + // + for(int i=0;i<2;i++) { + if(vguest_porttype[i]==RDMatrix::TtyPort) { + tty=new RDTty(rdstation->name(),matrix->port((RDMatrix::Role)i)); + vguest_device[i]=new RDTTYDevice(); + if(tty->active()) { + vguest_device[i]->setName(tty->port()); + vguest_device[i]->setSpeed(tty->baudRate()); + vguest_device[i]->setWordLength(tty->dataBits()); + vguest_device[i]->setParity(tty->parity()); + vguest_device[i]->open(IO_Raw|IO_ReadWrite); + } + delete tty; + } + else { + if(vguest_porttype[i]==RDMatrix::TcpPort) { + vguest_socket[i]=new RDSocket(i,this); + connect(vguest_socket[i],SIGNAL(connectedID(int)), + this,SLOT(connectedData(int))); + connect(vguest_socket[i],SIGNAL(connectionClosedID(int)), + this,SLOT(connectionClosedData(int))); + connect(vguest_socket[i],SIGNAL(readyReadID(int)), + this,SLOT(readyReadData(int))); + connect(vguest_socket[i],SIGNAL(errorID(int,int)), + this,SLOT(errorData(int,int))); + ipConnect(i); + } + } + } +} + + +VGuest::~VGuest() +{ + delete vguest_gpio_oneshot; + for(int i=0;i<2;i++) { + delete vguest_reconnect_timer[i]; + delete vguest_ping_response_timer[i]; + delete vguest_ping_timer[i]; + if(vguest_device[i]!=NULL) { + delete vguest_device[i]; + } + if(vguest_socket[i]!=NULL) { + delete vguest_socket[i]; + } + } +} + + +RDMatrix::Type VGuest::type() +{ + return RDMatrix::LogitekVguest; +} + + +unsigned VGuest::gpiQuantity() +{ + return vguest_gpis; +} + + +unsigned VGuest::gpoQuantity() +{ + return vguest_gpos; +} + + +bool VGuest::primaryTtyActive() +{ + return vguest_porttype[0]==RDMatrix::TtyPort; +} + + +bool VGuest::secondaryTtyActive() +{ + return vguest_porttype[1]==RDMatrix::TtyPort; +} + + +void VGuest::processCommand(RDMacro *cmd) +{ + char buffer[VGUEST_MAX_COMMAND_LENGTH]; + char cmd_byte=0; + QString label; + + switch(cmd->command()) { + case RDMacro::SD: + if((cmd->argQuantity()<5)|| + (cmd->arg(1).toUInt()>vguest_displays_engine_nums.size())) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + LogLine(RDConfig::LogWarning,"*** not enough vGuest arguments ***"); + return; + } + if((vguest_displays_engine_nums[cmd->arg(1).toInt()-1]<0)|| + (vguest_displays_device_nums[cmd->arg(1).toInt()-1]<0)|| + (vguest_displays_surface_nums[cmd->arg(1).toInt()-1]<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + LogLine(RDConfig::LogWarning,"*** invalid vGuest hex parameters ***"); + return; + } + label=cmd->rollupArgs(5).left(VGUEST_MAX_TEXT_LENGTH); + sprintf(buffer,"\x02%c\x5C%c%c%c%c%c%c%c%s",8+label.length(), + (char)vguest_displays_engine_nums[cmd->arg(1).toInt()-1], + (char)(vguest_displays_device_nums[cmd->arg(1).toInt()-1]>>8), + (char)(vguest_displays_device_nums[cmd->arg(1).toInt()-1]&0xFF), + (char)vguest_displays_surface_nums[cmd->arg(1).toInt()-1], + (char)(0xFF&cmd->arg(2).toInt()), + (char)(0xFF&cmd->arg(3).toInt()), + (char)(0xFF&cmd->arg(4).toInt()), + (const char *)label); + SendCommand(buffer,10+label.length()); + break; + + case RDMacro::ST: + if((cmd->arg(1).toInt()<1)||(cmd->arg(1).toInt()>vguest_inputs)|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>vguest_outputs)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if((vguest_input_engine_nums[cmd->arg(1).toInt()-1]<0)|| + (vguest_input_device_nums[cmd->arg(1).toInt()-1]<0)|| + (vguest_output_engine_nums[cmd->arg(2).toInt()-1]<0)|| + (vguest_output_device_nums[cmd->arg(2).toInt()-1]<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + sprintf(buffer,"\x02\x08\x54%c%c%c%c%c%c%c", + (char)vguest_output_engine_nums[cmd->arg(2).toInt()-1], + (char)(vguest_output_device_nums[cmd->arg(2).toInt()-1]>>8), + (char)(vguest_output_device_nums[cmd->arg(2).toInt()-1]&0xFF), + VGUEST_DEFAULT_SURFACE_NUMBER, + (char)vguest_input_engine_nums[cmd->arg(1).toInt()-1], + (char)(vguest_input_device_nums[cmd->arg(1).toInt()-1]>>8), + (char)(vguest_input_device_nums[cmd->arg(1).toInt()-1]&0xFF)); + SendCommand(buffer,10); + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + case RDMacro::GO: + if(((cmd->arg(1).toString().lower()!="i")&& + (cmd->arg(1).toString().lower()!="o"))|| + (cmd->arg(2).toInt()<1)||(cmd->arg(2).toInt()>vguest_gpos)|| + (cmd->arg(3).toInt()<0)||(cmd->arg(3).toInt()>1)|| + (cmd->arg(4).toInt()<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + if(cmd->arg(4).toInt()>0) { + cmd_byte=0x51; + } + else { + switch(cmd->arg(3).toInt()) { + case 0: + cmd_byte=0x53; + break; + + case 1: + cmd_byte=0x52; + break; + } + } + if((vguest_relays_engine_nums[cmd->arg(2).toInt()-1]<0)|| + (vguest_relays_device_nums[cmd->arg(2).toInt()-1]<0)|| + (vguest_relays_surface_nums[cmd->arg(2).toInt()-1]<0)|| + (vguest_relays_relay_nums[cmd->arg(2).toInt()-1]<0)) { + cmd->acknowledge(false); + emit rmlEcho(cmd); + return; + } + switch(0xFF&cmd_byte) { + case 0x51: + sprintf(buffer,"\x02\x07\x51%c%c%c%c%c%c", + vguest_relays_engine_nums[cmd->arg(2).toInt()-1], + vguest_relays_device_nums[cmd->arg(2).toInt()-1]>>8, + vguest_relays_device_nums[cmd->arg(2).toInt()-1]&0xFF, + vguest_relays_surface_nums[cmd->arg(2).toInt()-1], + vguest_relays_relay_nums[cmd->arg(2).toInt()-1], + cmd->arg(4).toInt()/50); + SendCommand(buffer,9); + emit gpiChanged(vguest_matrix,cmd->arg(2).toInt()-1,true); + emit gpoChanged(vguest_matrix,cmd->arg(2).toInt()-1,true); + vguest_gpio_oneshot->start((void *)(cmd->arg(2).toInt()-1),2000); + break; + + case 0x52: + case 0x53: + sprintf(buffer,"\x02\x06%c%c%c%c%c%c", + cmd_byte, + vguest_relays_engine_nums[cmd->arg(2).toInt()-1], + vguest_relays_device_nums[cmd->arg(2).toInt()-1]>>8, + vguest_relays_device_nums[cmd->arg(2).toInt()-1]&0xFF, + vguest_relays_surface_nums[cmd->arg(2).toInt()-1], + vguest_relays_relay_nums[cmd->arg(2).toInt()-1]); + SendCommand(buffer,8); + emit gpiChanged(vguest_matrix,cmd->arg(2).toInt()-1, + cmd->arg(3).toInt()); + emit gpoChanged(vguest_matrix,cmd->arg(2).toInt()-1, + cmd->arg(3).toInt()); + } + cmd->acknowledge(true); + emit rmlEcho(cmd); + break; + + default: + cmd->acknowledge(false); + emit rmlEcho(cmd); + break; + } +} + + +void VGuest::ipConnect(int id) +{ + if(!vguest_ipaddress[id].isNull()) { + vguest_socket[id]-> + connectToHost(vguest_ipaddress[id].toString(),vguest_ipport[id]); + } +} + + +void VGuest::connectedData(int id) +{ + vguest_istate[id]=0; +} + + +void VGuest::connectionClosedData(int id) +{ + int interval=GetHoldoff(); + if(!vguest_error_notified[id]) { + LogLine(RDConfig::LogNotice,QString(). + sprintf("Connection to vGuest device at %s:%d closed, attempting reconnect", + (const char *)vguest_ipaddress[id].toString(), + vguest_ipport[id])); + vguest_error_notified[id]=true; + } + if(vguest_stop_cart[id]>0) { + ExecuteMacroCart(vguest_stop_cart[id]); + } + vguest_ping_timer[id]->stop(); + vguest_ping_response_timer[id]->stop(); + vguest_reconnect_timer[id]->start(interval,true); +} + + +void VGuest::readyReadData(int id) +{ + char buffer[255]; + int n=0; + + while((n=vguest_socket[id]->readBlock(buffer,255))>0) { + for(int i=0;istart(interval,true); + break; + + case QSocket::ErrHostNotFound: + if(!vguest_error_notified[id]) { + LogLine(RDConfig::LogWarning,QString().sprintf( + "Error on connection to vGuest device at %s:%d: Host Not Found", + (const char *)vguest_ipaddress[id].toString(), + vguest_ipport[id])); + vguest_error_notified[id]=true; + } + break; + + case QSocket::ErrSocketRead: + if(!vguest_error_notified[id]) { + LogLine(RDConfig::LogWarning,QString().sprintf( + "Error on connection to vGuest device at %s:%d: Socket Read Error", + (const char *)vguest_ipaddress[id].toString(), + vguest_ipport[id])); + vguest_error_notified[id]=true; + } + break; + } +} + + +void VGuest::gpioOneshotData(void *data) +{ + emit gpiChanged(vguest_matrix,(long)data,false); + emit gpoChanged(vguest_matrix,(long)data,false); +} + + +void VGuest::pingData(int id) +{ + char buffer[VGUEST_MAX_COMMAND_LENGTH]; + + buffer[0]=0x04; + buffer[1]=0x01; + buffer[2]=0x03; // LPCore Connection Ping + vguest_socket[id]->writeBlock(buffer,3); + vguest_ping_response_timer[id]->start(VGUEST_PING_INTERVAL,true); +} + + +void VGuest::pingResponseData(int id) +{ + vguest_socket[id]->clearPendingData(); + vguest_socket[id]->close(); + LogLine(RDConfig::LogWarning,"vGuest connection to "+ + vguest_ipaddress[id].toString()+" timed out, restarting connection"); +} + + +void VGuest::SendCommand(char *str,int len) +{ + // LogLine(QString().sprintf("SENT: %s",(const char *)RenderCommand(str,len))); + for(int i=0;i<2;i++) { + switch(vguest_porttype[i]) { + case RDMatrix::TtyPort: + if(vguest_device[i]!=NULL) { + vguest_device[i]->writeBlock(str,len); + } + break; + + case RDMatrix::TcpPort: + if(vguest_socket[i]!=NULL) { + vguest_socket[i]->writeBlock(str,len); + } + break; + + case RDMatrix::NoPort: + break; + } + } +} + + +void VGuest::DispatchCommand(char *cmd,int len,int id) +{ + char buffer[VGUEST_MAX_COMMAND_LENGTH]; + QString str; + int linenum; + + // LogLine(RDConfig::LogNotice, + // QString().sprintf("RCVD: %s",(const char *)RenderCommand(cmd,len))); + + switch(0xFF&cmd[2]) { + case 0xF9: // Username/Password Query + buffer[0]=0x02; + buffer[1]=0x22; + buffer[2]=0xF9; + buffer[3]=VGUEST_ID_BYTE; + sprintf(buffer+4,"%s%s", + (const char *)vguest_username[id], + (const char *)vguest_password[id]); + SendCommand(buffer,36); + break; + + case 0xF0: // Connect Status + switch(0xFF&cmd[3]) { + case 0x0A: // Valid connection + case 0x14: + LogLine(RDConfig::LogInfo,QString().sprintf( + "connection to vGuest device at %s:%d established", + (const char *)vguest_ipaddress[id].toString(), + vguest_ipport[id])); + vguest_error_notified[id]=false; + if(vguest_start_cart[id]>0) { + ExecuteMacroCart(vguest_start_cart[id]); + } + if(vguest_socket[id]!=NULL) { + buffer[0]=0x04; + buffer[1]=0x01; + buffer[2]=0x03; // LPCore Connection Ping + vguest_socket[id]->writeBlock(buffer,3); + } + break; + + case 0x0B: // Invalid Username + case 0x15: + LogLine(RDConfig::LogWarning,QString().sprintf( + "connection to vGuest device at %s:%d refused: username invalid", + (const char *)vguest_ipaddress[id].toString(), + vguest_ipport[id])); + vguest_socket[id]->close(); + connectionClosedData(id); + break; + + case 0x0C: // Invalid Password + case 0x16: + LogLine(RDConfig::LogWarning,QString().sprintf( + "connection to vGuest device at %s:%d refused: password invalid", + (const char *)vguest_ipaddress[id].toString(), + vguest_ipport[id])); + vguest_socket[id]->close(); + connectionClosedData(id); + break; + + case 0x0D: // No vGuest Permission + case 0x17: + LogLine(RDConfig::LogWarning,QString().sprintf( + "connection to vGuest device at %s:%d refused: no vGuest permission", + (const char *)vguest_ipaddress[id].toString(), + vguest_ipport[id])); + vguest_socket[id]->close(); + connectionClosedData(id); + break; + + case 0x0E: // No Profile + case 0x18: + LogLine(RDConfig::LogWarning,QString().sprintf( + "connection to vGuest device at %s:%d refused: no profile assigned", + (const char *)vguest_ipaddress[id].toString(), + vguest_ipport[id])); + vguest_socket[id]->close(); + connectionClosedData(id); + break; + } + break; + + case 0x52: // Turn On + if((linenum=GetRelay(0xFF&cmd[3],256*(0xFF&cmd[4])+(0xFF&cmd[5]), + 0xFF&cmd[6],0xFF&cmd[7]))>=0) { + emit gpiChanged(vguest_matrix,linenum,true); + emit gpoChanged(vguest_matrix,linenum,true); + } + else { + LogLine(RDConfig::LogDebug,QString(). + sprintf("unhandled vGuest command received: %s", + (const char *)RenderCommand(cmd,len))); + } + break; + + case 0x53: // Turn Off + if((linenum=GetRelay(0xFF&cmd[3],256*(0xFF&cmd[4])+(0xFF&cmd[5]), + 0xFF&cmd[6],0xFF&cmd[7]))>=0) { + emit gpiChanged(vguest_matrix,linenum,false); + emit gpoChanged(vguest_matrix,linenum,false); + } + else { + LogLine(RDConfig::LogDebug,QString(). + sprintf("unhandled vGuest command received: %s", + (const char *)RenderCommand(cmd,len))); + } + break; + + case 0x54: // Input Assign + break; + + case 0x55: // Input Mode + break; + + case 0x56: // Fader Level + break; + + default: + LogLine(RDConfig::LogDebug,QString(). + sprintf("unrecognized vGuest command received: %s", + (const char *)RenderCommand(cmd,len))); + break; + } +} + + +void VGuest::MetadataCommand(char *cmd,int len,int id) +{ + switch(0xFF&cmd[2]) { + case 0x03: // Connection Ping + if(vguest_ping_response_timer[id]->isActive()) { + vguest_ping_response_timer[id]->stop(); + } + else { + LogLine(RDConfig::LogDebug,"vGuest system at "+ + vguest_ipaddress[id].toString()+ + " understands ping, activating timeout monitoring"); + } + vguest_ping_timer[id]->start(VGUEST_PING_INTERVAL,true); + break; + } +} + + +QString VGuest::PadString(QString str,unsigned len) +{ + QString out; + out=str.left(len); + while(out.length()address()); + rml.setEchoRequested(false); + rml.setArgQuantity(1); + rml.setArg(0,cartnum); + emit rmlEcho(&rml); +} diff --git a/ripcd/vguest.h b/ripcd/vguest.h new file mode 100644 index 00000000..72294927 --- /dev/null +++ b/ripcd/vguest.h @@ -0,0 +1,120 @@ +// vguest.h +// +// A Rivendell switcher driver for the Logitek vGuest Protocol +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: vguest.h,v 1.17.8.1 2013/11/06 01:32:31 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef VGUEST_H +#define VGUEST_H + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define VGUEST_RECONNECT_MIN_INTERVAL 5000 +#define VGUEST_RECONNECT_MAX_INTERVAL 15000.0 +#define VGUEST_MAX_COMMAND_LENGTH 255 +#define VGUEST_ID_BYTE 0x0C; +#define VGUEST_DEFAULT_SURFACE_NUMBER 1 +#define VGUEST_DEFAULT_PORT 10212 +#define VGUEST_MAX_TEXT_LENGTH 60 +#define VGUEST_PING_INTERVAL 15000 + +class VGuest : public Switcher +{ + Q_OBJECT + public: + VGuest(RDMatrix *matrix,QObject *parent=0,const char *name=0); + ~VGuest(); + RDMatrix::Type type(); + unsigned gpiQuantity(); + unsigned gpoQuantity(); + bool primaryTtyActive(); + bool secondaryTtyActive(); + void processCommand(RDMacro *cmd); + + private slots: + void ipConnect(int id); + void connectedData(int id); + void connectionClosedData(int id); + void readyReadData(int id); + void errorData(int err,int id); + void gpioOneshotData(void *data); + void pingData(int id); + void pingResponseData(int id); + + private: + void SendCommand(char *str,int len); + void DispatchCommand(char *cmd,int len,int id); + void MetadataCommand(char *cmd,int len,int id); + int GetRelay(int enginenum,int devicenum,int surfacenum,int relaynum); + int GetHoldoff(); + QString RenderCommand(char *cmd,int len); + QString PadString(QString str,unsigned len); + void ExecuteMacroCart(unsigned cartnum); + RDTTYDevice *vguest_device[2]; + RDSocket *vguest_socket[2]; + int vguest_matrix; + QHostAddress vguest_ipaddress[2]; + int vguest_ipport[2]; + int vguest_inputs; + QString vguest_username[2]; + QString vguest_password[2]; + unsigned vguest_start_cart[2]; + unsigned vguest_stop_cart[2]; + int vguest_outputs; + int vguest_gpis; + int vguest_gpos; + int vguest_istate[2]; + int vguest_cmd_length[2]; + int vguest_cmd_ptr[2]; + char vguest_cmd_buffer[2][VGUEST_MAX_COMMAND_LENGTH]; + QSignalMapper *vguest_ping_mapper; + QTimer *vguest_ping_timer[2]; + QSignalMapper *vguest_ping_response_mapper; + QTimer *vguest_ping_response_timer[2]; + QTimer *vguest_reconnect_timer[2]; + bool vguest_error_notified[2]; + RDMatrix::PortType vguest_porttype[2]; + std::vectorvguest_input_engine_nums; + std::vectorvguest_input_device_nums; + std::vectorvguest_output_engine_nums; + std::vectorvguest_output_device_nums; + std::vectorvguest_relays_engine_nums; + std::vectorvguest_relays_device_nums; + std::vectorvguest_relays_surface_nums; + std::vectorvguest_relays_relay_nums; + std::vectorvguest_displays_engine_nums; + std::vectorvguest_displays_device_nums; + std::vectorvguest_displays_surface_nums; + RDOneShot *vguest_gpio_oneshot; +}; + + +#endif // VGUEST_H diff --git a/rivendell-gentoo b/rivendell-gentoo new file mode 100755 index 00000000..12c5fe7f --- /dev/null +++ b/rivendell-gentoo @@ -0,0 +1,69 @@ +#!/sbin/runscript + +## +## A Rivendell init script for Gentoo Linux. +## +## (C) Copyright 2005 Fred Gleason +## +## $Id: rivendell-gentoo,v 1.6 2011/05/02 18:49:36 cvs Exp $ +## +## Adapted from the Gentoo init script for Rivendell +## by Andres Toomsalu +## +## Modified 2011 by Emery Hemingway +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of version 2 of the GNU General Public License as +## published by the Free Software Foundation; +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, +## Boston, MA 02111-1307 USA +## + +description="Rivendell system daemons" + +user="rivendell" +group="rivendell" +pid_dir="/var/run/rivendell" + +daemons="caed ripcd rdcatchd" + +depend() { + use alsasound apache2 jackd mysql +} + +start() { + ebegin "Starting Rivendell" + + checkpath --directory --mode 0775 --owner $user:$group /var/snd + checkpath --file --mode 0664 --owner $user:$group /var/snd/* + + ipcrm -M 0x5005 2> /dev/null + + for daemon in $daemons + do + veinfo "Starting $daemon" + start-stop-daemon --start --pidfile $pid_dir/$daemon.pid \ + --user $user:$group --umask 0113 \ + --exec /usr/bin/$daemon + done + eend $? +} + +stop() { + ebegin "Stopping Rivendell" + killall rdimport > /dev/null 2> /dev/null + + for daemon in $daemons + do + start-stop-daemon --stop --pidfile $pid_dir/$daemon.pid + done + eend $? +} diff --git a/rivendell-suse.in b/rivendell-suse.in new file mode 100755 index 00000000..8fd1c6d3 --- /dev/null +++ b/rivendell-suse.in @@ -0,0 +1,252 @@ +#! /bin/bash +## +## Rivendell init script for LSB and chkconfig(8) compliant Linux systems. +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: rivendell-suse.in,v 1.16.4.1 2013/11/13 18:30:57 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of version 2 of the GNU General Public License as +## published by the Free Software Foundation; +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, +## Boston, MA 02111-1307 USA +## + +# chkconfig: 35 65 35 +# description: Rivendell system daemons +# config: /etc/rc.conf + +### BEGIN INIT INFO +# Provides: rivendell +# Required-Start: $remote_fs alsasound +# Required-Stop: $remote_fs alsasound +# Should-Start: @MYSQL_PKG@ +# Default-Start: 2 3 5 +# Default-Stop: 0 1 6 +# Description: Start the Rivendell system daemons +### END INIT INFO + + +function StartDaemons { + if test $GPIO_START = yes ; then + if test -x /etc/init.d/gpio ; then + /etc/init.d/gpio status > /dev/null + if test $? -eq 3 ; then + /etc/init.d/gpio start + fi + fi + fi + if test $HPI_START = yes ; then + if test -x /etc/init.d/asihpi ; then + /etc/init.d/asihpi status > /dev/null + if test $? -eq 3 ; then + /etc/init.d/asihpi start + sleep 2 + fi + fi + fi + if test $LIVEWIRE_START = yes ; then + if test -x /etc/init.d/axiad ; then + /etc/init.d/axiad status > /dev/null + if test $? -eq 3 ; then + /etc/init.d/axiad start + fi + fi + fi + $JACK_COMMAND > /dev/null 2> /dev/null & + echo -n $! > /var/run/rivendell/jackd.pid + ipcrm -M 0x5005 2> /dev/null + @LOCAL_PREFIX@/bin/caed 2> /dev/null + sleep 1 + if test -x @LOCAL_PREFIX@/bin/ripcd ; then + @LOCAL_PREFIX@/bin/ripcd 2> /dev/null + sleep 1 + fi + if test -x @LOCAL_PREFIX@/bin/rdcatchd ; then + @LOCAL_PREFIX@/bin/rdcatchd 2> /dev/null + fi +} + + +function StopDaemons { + killall rdimport > /dev/null 2> /dev/null + if [ -f /var/run/rivendell/rdcatchd.pid ] ; then + kill `cat /var/run/rivendell/rdcatchd.pid` > /dev/null 2> /dev/null + fi + if [ -f /var/run/rivendell/ripcd.pid ] ; then + kill `cat /var/run/rivendell/ripcd.pid` > /dev/null 2> /dev/null + fi + if [ -f /var/run/rivendell/caed.pid ] ; then + kill `cat /var/run/rivendell/caed.pid` > /dev/null 2> /dev/null + fi + if [ -n "$JACK_COMMAND" ] ; then +# +# FIXME +# Why are three kill(1) invocations necessary to stop jackd(1)? +# + if [ -f /var/run/rivendell/jackd.pid ] ; then + kill `cat /var/run/rivendell/jackd.pid` > /dev/null 2> /dev/null + kill `cat /var/run/rivendell/jackd.pid` > /dev/null 2> /dev/null + kill `cat /var/run/rivendell/jackd.pid` > /dev/null 2> /dev/null + rm -f /var/run/rivendell/jackd.pid + fi + fi + sleep 2 +} + +# Set path for script functions +export PATH=$PATH:/usr/local/bin:/usr/local/sbin + +# +# If the LSB Init functions exist, use them, otherwise roll our own +# +if test -f /lib/lsb/init-functions ; then + . /lib/lsb/init-functions +else + function log_success_msg() { + echo "$1 ... done." + } + function log_failure_msg() { + echo "$1 ... done." + } +fi + +# Default sysconfig values +GPIO_START="no" +HPI_START="no" +LIVEWIRE_START="no" +JACK_START="no" +JACK_SAMPLE_RATE="48000" +JACK_ALSA_DEVICE="hw:0" +JACK_USE_REALTIME="no" + +# Override defaults, if we have the sysconfig file +test -f /etc/sysconfig/rivendell && . /etc/sysconfig/rivendell + +# Build a jackd command line +if [ $JACK_START = yes ] ; then + if [ $JACK_USE_REALTIME = yes ] ; then + JACK_COMMAND="jackd -R" + else + JACK_COMMAND="jackd" + fi + JACK_COMMAND="$JACK_COMMAND -d alsa -d $JACK_ALSA_DEVICE -r $JACK_SAMPLE_RATE" +fi + +# Check for missing binaries +if [ ! -x @LOCAL_PREFIX@/bin/caed ] ; then + echo "caed not installed" + exit 5 +fi +#if [ ! -x @LOCAL_PREFIX@/bin/ripcd ] ; then +# echo "ripcd not installed" +# exit 5 +#fi +#if [ ! -x @LOCAL_PREFIX@/bin/rdcatchd ] ; then +# echo "rdcatchd not installed" +# exit 5 +#fi + +# Check for existence of needed config file and read it +if [ ! -r /etc/rd.conf ] ; then + echo "Missing /etc/rd.conf" + exit 6 +fi + +# Check for existence of PID file directory and create it if necessary. +if [ ! -d /var/run/rivendell ] ; then + mkdir -p /var/run/rivendell +fi +if [ ! -d /var/run/rivendell ] ; then + echo "Missing /var/run/rivendell directory" + exit 6 +fi + +case "$1" in + start) + $0 silent-status + if test $? -eq 3 ; then + StartDaemons + fi + $0 silent-status + if test $? -eq 0 ; then + log_success_msg "Starting Rivendell system daemons" + exit 0 + else + log_failure_msg "Starting Rivendell system daemons" + exit 1 + fi + ;; + stop) + StopDaemons + $0 silent-status + if test $? -eq 0 ; then + log_failure_msg "Stopping Rivendell system daemons" + exit 1 + else + log_success_msg "Stopping Rivendell system daemons" + exit 0 + fi + ;; + restart) + $0 silent-status + if test $? -eq 0 ; then + $0 stop + fi + $0 silent-status + if test $? -eq 0 ; then + exit 1 + fi + $0 start + $0 silent-status + if test $? -eq 0 ; then + exit 0 + fi + exit 1 + ;; + force-reload) + $0 restart + ;; + status) + $0 silent-status + EXIT_CODE=$? + if test $EXIT_CODE -eq 0 ; then + echo "Rivendell system daemons running." + else + echo "Rivendell system daemons stopped." + fi + exit $EXIT_CODE + ;; + silent-status) + if test -f /var/run/rivendell/caed.pid ; then + if test -d /proc/`cat /var/run/rivendell/caed.pid` ; then + if test ! -x @LOCAL_PREFIX@/bin/ripcd ; then + exit 0 + fi + if test -f /var/run/rivendell/ripcd.pid ; then + if test -d /proc/`cat /var/run/rivendell/ripcd.pid` ; then + if test -f /var/run/rivendell/rdcatchd.pid ; then + if test -d /proc/`cat /var/run/rivendell/rdcatchd.pid` ; then + exit 0 + fi + fi + fi + fi + fi + fi + exit 3 + ;; + *) + echo "Usage: $0 {start|stop|restart|force-reload|status}" + exit 1 + ;; +esac diff --git a/rivendell.ism b/rivendell.ism new file mode 100755 index 0000000000000000000000000000000000000000..b731c64a3191b3592270ce09981a2599c1367238 GIT binary patch literal 499284 zcmeFaTXQ5wmL?VeSyjB>y4l^_o!Mm#XLfsb7Hs4l*xPL0P|P82lbNV)T5}8rRwYSn zqkw7v)okvX%=%GpdewtW4>Fm_q<^3{nSOyx?|P7afz0$S>HE&{OF zd3AliKmDS3MXwaEtj#}Pd|x~))*G8RzS3ym`0Bd;|JC)}|N4iAvvGeq{OpEGT2d3< zSG>~XDgVAFZ@DjTVGHo4!DN*N?M`O%!ND(%cl%!)9L3Hwp@tCj8bWLIpnr87nJNQ)@<7t01IT#$x=Lh@Qq08LoU}i3dwoGP+ z(}PEoQMN*%g>s4T>=5HPJ=i_Q?`XnNUH&cB6SH}LI^P@bA4%`#dn=R)uX|X4=mrNM zTzOFX#S@;t70QP*^!J0cd(*|q)9>dOlk=*LXQHawp8_dfZgIGPAUP}1<< zdMZcI{8t(+p@iSP+E9}C-93=R`){Bym}^P>2QyS(kd}8R`=3wtA00oM9vmHJy1rT_ zd~;yhdOE3=3C}NU;qYMhV9G{1srL3dWIj5LhX?-;{=LS->->|STfE7`TRgmtN8Vk# z=ZZo;kfp>^nQ3wX|H}<)BEAM(b3`V z1R}XkP^S08b9)D)quudjA1uDRJO0HOVsktj|Mk&$f2i`7Lo4!gX-P`9r3L&Oo5o&M zJ?Hq&7sZPyoR^UZ#N}{2n+eIX>=ISsZ-x42mA(s&eg4D2sBt2k78~X{LB| zGd!WKpFkcjm&9oHE28gSg;=2-LFKG=#NM8bMMOw`L_{G}ii8Fz;iGLZFklx|JG@jN zJelgm>VuKK^!5)LEyGnD_UE5H?oaD!xKtp#mSeE?)6wGVlNV>#e-2acl|RG3{e#E- z-6K%toPU8BQECTP#nCiouXOy<`{4~iEM~eRx*49Z&ocEI1oj^rXUI6D_rvqn4dDvS zxyKU-!=(maTp~Oh&K?$p+6pRy(Uv#8`gJ!#;d{?JYP#Hi-o^(#c+LTSO{~Dz#Ugy; zd9Qe%3h&M5-Qsc5)gU zIB7_HgYq%{+rOe&OlBsT>ItG+##f-u!fIS&Dw6a8Q|AV&FD@0m&awH?A*vXaY;wEE z&$V;^Xww@N57DWs+6vodDx?}LI6I!CI8=3lR7MevTJ^2LLh0Zk9q4AU+uwh5L@$9h z5e3dYPeA^b|6Fkh#a~#(4a8eKt*%%ekMxgVx=$a$L!uTh9yq#w;G0z{kT#B#&6hq9 zIv!2y^;@_XYJexwpASD|kyXK!t1f7Bub zvbQ&y&}WZ6*>`>Eo)~m#asLU8*n^R;PTj`HcL^f~Ip<95WfW5?;$KQ0Ml&`9wPs;KnQgug)clbB{z2hZ>-3gD~Yi!|@ z?u+VsAgb@RMh{nBcM7n0qtV5mZ&D4?WO%DV8TmHf_8zNlY~xRrNd3{{`O(B|*tFBL zC8Tden3W#&&1*&wfw-o4<-M|9QR|-HnsH{s>EuvHKIQND23sBf9W_?W|HLd1ic+t@ zOMLU&{DXyK)I6z1H^UQz;;h1^fO{AQku-@1kg}@3`Aj@EV{9?F!G$T;O z{^7qMzvH{1X%7cSliks7e=y#yup#72s_d*prt@n`h8N+3Zexi$fHw0Tb|+MwZ)CWi z%7v<>n%)o3QEa?V1$JM&$Ood?UlYy#y0Efy&mZj{OviKD<=GCZEfqKu`mS7sZ$<-x z+S?o`cQNLi-#!IHwEMw5LJEKAe%1qUjU!3wxUg+dK+T;X6e7#@!Ryw47frc2PJe7R63 zU9ItSZ!#113)fS9X`Vbh?^O1Q2y-qTZ-xqTnlc&0TmccE%T+7`BmONQGOr>^kkt~J zrb4MH9cX(=q3HFBVya7=(uCddg+r^$H132mTss=WwOBxUKh%qUKRP7(SWBPf65&}6 zKa2wWQ$m?eK=v8$A-)@)Hi8VUgNrjA|MgLS7bt5s(o-!H)fh#k-VkfzO%Ytf&&I>g zmxjj5B|@G2z~RusdBIY!pjx;Wp3yHu=ZM-ga}mETph8OibNm?6+baI-L!L7Yz&it2D3_J^Ot2VF)n@`h5m@IDiN64l8DAIc@dvqYt4k73Hw z8%r2FxkH9ZF8CS%|0-~hZGY(=t0`Ub6*Y>6`B4}!i0og?$NLm#am6I@Fj$#FzB=z4 zm2G#mwM62Xixhae;g~vHDd0qZei&qH(nnHDsX%B!DtsBxs&~layP<}vd6c}qdYc_w zy&5W%9&UJ*YIIS&%YMaw?*8&?K4!i{{ z686_~aXsDv9trF6IlT*tT8P6LXS(PAzZ0tVJ6WanhcZTq;ey~oa9d+zYt+_ zp#Jr(s+I{Yf^-`0_GdHNvl2=VXsuVjr>t8$6(tdSeOhD1hx<|uDalo8@yE?}d8PHs;HPI`guJbXZv4NJg&uTcIMgNjy|o zi|&LH;aM9weyK`{`W!L;6fzk!i|lw6W2e5Xuh8YUL{cg3O6Dhcc^{q%a0(mmB0+|x z{7ysplUb5Yu#Bg(1;g9Qe44GQu27EAtpfiF8WS;UZUw5moG<4q@~CO5;#d#=iKfhJ zLAEo0$5#$gX{t8h$pjct0E)6L&KKdE@^}23L;|=h{c0aT23Q8a=Tny%Y|YSjl+uRn zX7n2Ge9Bx0cF}9zGzs_o175f|k~4#g;?J7Go{3Y9?5)-B$d?N*lfG^if{vE8mW~78 z3ZM=GY1v!i`=NFSWJ&F=f3jR6Jc}H9`&{28>;okr$M-?ZWnXba*+7rA)%i9!lu-Kw z;ol?=xq;*&v3)t8Wl6sBrX?X!lf?*iNt~zPp(xmL3Ewc+Io_xgv7VYK;a+$OJt^ox zxK|~fa4$T!S|Hk^s2Q3M_d>1rB%koU3B2K6Xw>d*6$=b^fr0Noo=gw+k^DE$ z@}B$dOtDZ4XD`&*`=xsv*wQ6mk7NW=utw<)^=%4S4_3xkMC(!zr%Zy2zZFU^O@{>* z&HUFlgpS`7Ecz`=ihcX}wo=bKicX{D_2a+d_SV45Xs)Ac z%ii||gJl+p-C&@mGRF+FN>N`OJ{n>WA$mg(64qAo2{*%Igxn%tH6&0jhf-pD{-yBg zL*DvJ;M*3IU&XLoRyw@JJleY=zY$7h#8~ZxOrg+%k7TM0^v-|U95u#+extL|9Q67d z?Z!@TW3b(9ZVWrkW~?)YXE zA%q%F-Vi>t`5TgwDcVZNBvY+kk19o4n5YcSZ{P{$Us9pGCh488i@6lrx@rkoYF5Zh z%Nkt_;ogWqlkOiT_H2qL~4 zo-xpkU1QzE&kljsjINGuhMJgAmeII!Ih2aRtcAnaL~N(2?Cy?#tRXL->M5;^LPByc7LvB`~rWyM=v-+ysyU3cqGYujpEH1ni zviIZEgj9ogo)97Mx(Eal9psX?L{OOGO%cu|(am~%pfb6Ul8*n@thq1)lU%QQeyA(y z3949$YWYNi?(-3@<@933P->p6py@WoW0F%jM(O2?|Uebk`{oqCZ1rdAqJO z*CoR4edYNgD~TR34|G|Wj25ywJ-zBmFXXahZH9-*l%+6F&OhgL3Fi-rcuMDDQ^9B; zgng03I=K!G|Gj2pu`b#6Nk#87*Y=*6RT6#WpAV4dDnNrMZn|_vyvdZAyV0(PjF$9} zs7ZDb1rk{Z_Ms1~@r%N2UF}r%DN8$ZUxPgXCb(Jh$s2?4lRv$)nH>|I(79wlNhGqxOkzbQnhb{0n!=^9}gPKMSZcH(ImyoZ*@n^zh#w&`TtRBy1AY_TQG zFCkQAWvEIe(w}bDEq~r)<0Tb_17OxwNQH4E9m%x(@H0y|Wc<~&nJ~Vgfghc!9k-%SXV8< zNss8VS3%eY(QhA{NUUWAMcey1Jk^SPuQdn|u-h73GitQBx;{NWxjwx(-?=z@y0|Rv z6V`n2)BTInCiI09 zgq~2#=7oO*aub-1n*xEA#6F)NS$dp8wWGyC_@>USRzlNrKj{;NVq}>Ux4QmU?YI&9A1xTgQ@&fn^p1os3 zwL2UxNPB^T<~?K5Sf|qr8sWdUeM{oIQEQ%?!o_R@r2Gvf+s%#kaBFj8d#BgfXm(qzovlHC zbF06#a$_~=~Jw?_z`XwKjFuHB-2LL zjwe^M#r2El^Y5Q8_D;_m9BayhS4%evWYEaciD~)K**C{cF6(!nw$cLzC0|2Tr%z7K zT@xzlImPv%g(U3{>1j|~(V`ykFj>Y)l|AK~8{33ut*iqc^msCN{G z)Icvwe-PKQg<28?Q4)wtY_xnF#2yH8c6m9^Rt=pqb7Sx~6!4F#>J`lk*Dx$HYi;ob zErcVYziK}wYQ+rE1QfIy!`IbR6}_@}w<2}KY0>YUPy71_40D0NV2zt3lxTNU!q@7* zn0ihjrgS02>c{zK1;EpZR&_xRsMNTCf3(2zj=3&~u_wFlAL4WwUDeVF_G6ua5P)3! z+!<_Utd4FZZ#Vs?AMWs_Se^6wmxls+W7M9^s6s_eZ3LxzM^iQpcyKiyf|{p zyHfgK30KOTcX_TND5>NF-uwY?{;;vxY84;yZ>N87<}?ju+1gI4*=rwPKE1m5`ubOk z@2@^x{B}{Wi6L9=#r5eKvgLe{=u}GIwaKAIsb;lCJO2|=L9DZ_Yb-AT04jz2@I*#H zt3B$r``yMycc;0v(eCcFH@1e&osHgL&=@qfcDkKWdu1cQiREg_PhtY(Ivr_1;@ec* z2BTWv_6CxP%MrE)RgMx&GI+O6b)*862wNnnSJz%S>)+a6lI}H?Mqeo_u;2Qrbk$s6 zT{C!JQ9SykWck(iRD|I`8ZRlg{3}D#fhCh|#miCPxIzdoJ?HiJ=QWoEd1pev7f1Zs z9}Nbh?)LUZv$r|eXpgtHHn#iQgN?0mr?=f4cenek?#lf7^V9RE7vEiFt#%rzX0?lr z9vp{8W8CO<2<@TiYA$!B%HutGn6R=(Tsc&CamV9ghbqw_!z@(P(y$FQ1)VA&FT8 z=0}BKzfiOI2M3fHV;NjUE_*gm6DLXO3}3Z5-rDT6Hn%n!{a$CI-P#^+47%ga#%80r zwb|b3_r`Hb+_u_{m77%C(WQ~LG^XP)vm~t5XUMdAmu5SqxH^nx!}AHZGl@%BmU&!q;^2IV zoO8)OxhSjlaWLPJfqkE_@CWXJAJFkujgGZCRIA%_KXQ4{KQ<@$CwMu_ekApT&Kxzi zTdmFZCi=12+GuY!ha3HFcXMOh*xc$3w;P>Cx3zL-t~$QWMyoQuFX3Cd?e5labF{rN z8h4PWJL>f|wwt}3jZwSV8~3+*+u+2P@hv6NDESUiOr5dkFu^%rF0f%3ltzDNwAtD2 z0)7|)gXoP~8-pQaTD#jCZ}m5a<56q$GCm|RK$^YY)-jCFXW!5Mde<=>>?yajQq^S& z_rfO_#%|7%&@gft_7}gs*7Yg>6kYO$1|Ro6&WdAo_m+^t>MY}lf@Ze zBrpWq@IDEeH$i(E>xX8?eV4 z)JNOR{$P7^dpKxpzuflhz>;Xe2|By@=Gn>l$v2Bjr(o4ZYIfTly}NjNdM&q74@sWn zJ-9}w!iFny--~g(s6>+VuJ*DM3KbNeGU4#@;+xBpXCLpJo-MAv99&$U zot!`YayWQ#$_RP)%fadSmkIQLSJF=^S&jDp?)^CJxvIgxYR@HJ!d-hVsbsaDbM5YK zwf;WJw4gbMBRWffu13v%4+bP6SqN~!ljjdk4)!cmf_I(2mZ#kS5nzXgK)oC{d z+Zzq|>~PjQ@Y7-FqJ>?Uz1xGvX!9i-7dshs{ZRoF^q*22eoUG9kY|6w!zaa`7JpX! zv*Mo@KgD9A|ALqPf`@-uZ15+1N58$<9${kO##WzxXus3k=r_j0jc#XiFdjEs_}}JB zmy?Y$#eL+|Yqif;WuZiF+?9orN^ZkKc{?j(OgS@5?Wx!%yK9px#@%YoE`{uqz=1^7 zO9i}oDKcAlRq-!pE#C}(J+y#W46&4$C=&Lzrj7%^p0^#?E+SYjX_v3*P6b+uv^VTdT(=RyNPJw%g)?KKCA|c6bX}5^#i` zT%4UPp5z=M3l+H%VBfgxUHd+*Wwp-#ag)g(KWTDdTSqMw9BNgWnOF>W{fMNJ)xLpD z;X1ytg&GaQhxgeZhw@H_8&;cc-yvfukS~zbR{`@vLKrpX&=!Bw3@vd;j zdj?6r4=?p$lIik+<#_!7^EV$BKQxH$LqK$r=Jg{3o_{RUJQFz{0$D5Tw)|(_zB>X& z`Fr4(86A2{MXSC15;E5^I4GIHVVHh~?ZYCLb*4^(<=Sp+4F@};-bQ0<6Bc-H)CY*! z?rd~Nt?pp6G48fTFW)JsWIcRT1c4AHMp%kUxEHAVr3j0cMO(ULfebBontb1jId`Mf zY=OYJY18{ZLFq`&{VibQe^CB@Sp18&d*NSn9CZILI~2Fu7C|eTdFWDoL?2*#FiLIwSG>n2efs3&E0r-H zP}2Wkv-lxnR3EaGMyq-DlYfJSoi8u`1MD!-DHo?QLR z=Mw$wyVLVl^Jn!Ax9&D8Bji>Qh*i^BdtY(Gi*8qY~vkLzHS(YEJ z-P>zyc6!DAZ?A>gzWeUGPrtu-aS0N8escajNv%KZo6Q&kgkUnrasK`3?$j2a7*CTm-?H)WPq^m{vyxX8zi9^hPT0EdY}vm&K> zyLwkDV#qPy7rN)HocWq9nVf6;J(V&CFFR;*0xjF9Yog3qx zU%e^4*0CGvQd8{eU7KRhuiTVvM2YvYly0dVa_O#(kcU@qL92C)eM&}HQzj)@ck!;R zaF4Irj%KsjJN8;#*3V3vlS@0jYunQItlq?}-to^T`>p1u*T_dnn@6kU%W(6qEekcQ z+^SZicRc&~1T!JW(^*~1(gJsFU0TcPEo@_GpPhYr_1o`qy=J%W+A4c~_4f2gYR{k4 zb(X((=N4JzD>tdVi6$+cUtC^a)wU|SedmTnb*$btWZUf@{2c4@&gz zAcr3vP7dmt>+jvQfxd#(o76$N=gIYxZ=cpRD!O~uW<^!3-Y_VHCnt+K!DhGa-XyJh z)%IXM5InD^S0|*sPcc=oByF)q_16fXY(xd_+O)Km)fzak`85hcz-0adVEcCkQttZP z%Yp|v5ltqx3&281;v##XD3oU`rC5fb~`fT|liolc{%JsxfUZGeK^tx|aN?*^Q92uvBH zq^X+bk=+4LvgF~rij3PwwLrc=WRy$Zp4Z2%CpvMr9pfty=Dm7@6&5m$7*7B z2b)eFO~(aG^UFT)a>MRKQUmfrLUevdIe*8IN3_&$)JD}dL<&*rDk76?Ew-=7Km4}p@qsVYp}&Xp393LeQ*$s&mO$yS2Fd*SE#oudYv!h46=aF3LW+sk4H7>$QjN&JMEb z2hAN!RqJ(-xiM%DHhROxPHVV>B==jS)~}krk;&5dh>Mf_6?U$e9vsZE@&8TW*JR)&b-V{6e+VhSAl?UL>O3?}CeOmt6?*v6u=i+%=sZsS zcVc;Rddj;dLEmGSGuEWBww9BgA264KH1LBKJ{xhj7Nn-c-Y8#r<44G?5b^nA6SO}O zaru#@RQw}b68j%Z|NfEm?;o>&i+>^!{eNol{f}Etq&{pr+59JM7yAFCO%eR3Z8Wm@ zvo@{Af7V6~ZZwO3-sb9#e-K@~BpyS1)?~{+5P5%hmrDW!`&qU$lq6#&t893oqSqsl z(tN%S}^xgZi|1v*lvjZy~S+J&n9)A;@;C%7f)&YDRbkij_3}cVzI0~2to3+dPG7JnW{n1NszN(-`6x4& z*6tUhMgx|~8p@RcIqZ^DG*KBI z!1O=)X~5nY6O}xR@>d`f-)M8v*U2%Q8#^2EKT`Pu|qJ;0k zsv1_hm}4gS?&1-=-X=@5Ve+{83aoU;0#?HoItJ@RY}tLcCf5GqyV2Mq)7e6%D?{3Q1a^)YRN;OHBa3(8k9o+)08C+TeM=_d+pq~V=A={d;=egcTRfjwSEs6@{7;P5A(pryfyDm&I#MW`(awC) zB<+$c5$43w82kdt4Qrax-)o>`5d-*v)4?)uIpjyl8XkxIrO(6XkiWXoz~T{7H)v|f zK8IekeOS!4N$)tKE*w!6ju;3WQ4Nk5{@FHs2_DfF9MKdU(GncxS#Su?tmupgy2M!l_0x~ZLSBfD(3w}rxcy{&Dm(e-#tp~=otp;cCuXBf{em=_mTM)xOCXr4uh7;K9P-6tlv}K1E6VLPOiT6^I3H&kSz&I%L4 z*K#AigH@%bi!+GPrw-%sViX*e5u+q@DsdnT_O-ff>I7TULI8{8guZ7PRUZv7jw|Xu zeD?h0yYob*H2|zZ#86~7!2&CzFtAUhiGD~bh1RjWmhnR&@*K~6a|wklGF^Ipgq<*p zbtnexjtSdj3*Kj0tfR>h zSEN#~3)M%n<0;W~Rbqg&%m8VV%ZF{KLu&$h-;*r$@vsXKXg3c}F0Wx#M7pL&(K76S z^R0}7zIRS9uda`ffT@;_l$&jVwK8_umZ@h*H>EXpOdFETDm6vY;{9QxBSYwHj~3tn zE2krOa{cWXOOv=)cR6bP21d(~>d!AvuNTwBH>X$Em)}1=IeW1XQU$?nZNccQ2&`xk zyGYMCWApAerDIa1h7NaaJbdxh+3D4{gqJVQk)`382_IW+;cN?|zBcM^b)85rc2A!y z&aW1Ikg#NVC>7)L)Rcj{u&1OaiLHfA2yD@}CKLjKQE0TG*HR7DR)$Q&M4*JuP ziPqIFRlk3P_03l29@xa-T9A&j!un62ou2=EafaMzv=yc;mNMe!LPo(1E7@P*UeFR$ zKw!T96XqT(ZLbyMUJsomYJftw1Clc$8=O4(mC#|6W(A7$sDq&k0?(o7O?*l{KWqZH zbk)|#a^=w0cHq#|T7;zz9);y)t)pF!Henu!woMqc4co#Be4%Xzye6O5WjnAsr@wES z3o?$D00aQ|XV`|FZ#9GtfDxvB1WD1S;qD0N==`}7@D2>?7Z9VYiwp+;qDsDKtk=XQ zu8s$nSfp?PDg1nKdHuZ!tS;0AO)%(Y-x_Bgo7hr6VzveIJ0ol82%&$l+8=+^6Y%*8 zM!+{;s1k1 zBthR1N*k6M8V2R)I8ybwdPk?vwe_M1Mm_qO6&W{%X>!CaJ?eMsb)MMqKctbwYqJO#?QwloLmwQ|p!YSljiaN=j9N9pT0MxQ5!A`*mJkd)uyr3I#(gEI|KzK)#T3)-zY=LnNmNnHaC?X% z={iRd&O@aD(jE2SA$bx8qiroI+*fjkUnxoh@KnWWt6XqqoREFDyJciA1V6sKytq_; zrG$kV!m&c};%4pk_a7bgAB_tM3WLSPHxq|V$j$EC2!b1-YSJyLXA7=R0R43cqVJZw-=lw1T1Q5K2|z8;`FlQI}0 zuJK+OPb&z*)|cKOd0H#vlmy-v7W3c6wDPS%LlN;p)nDB z<)lKuNs01~259Q3q^xh|^8jFs^(td~taRTNCt)ZLYq#ip_l1-G@AL z{E3C}#?v_#mDI{AoC&)O421o#4jvUcIKmW;A0X1e50DZSet=n)z?ceaH`QeusgDSh^3vZ4^4!ku^62!Gh1PZKph=X)K~_~QpPLHP*jEs;%J7J8lw2YRFsI`6BRyVmgu2tQ14di7*0~ zeF6i$UD)==C6KJNz3(~}+A(H#zG!U93p$=Nm(&w>@h>9jO1c&C2(SN;@^d`1x2|#p9RgrW4Ce$k03zr)&CyZSD(i@z!#d)gCqa_2 zl5=RMH%NUb%Gk9FmkIJJc&uIxLMRKB8OG@)T8-orGa5Lj*UcmmbG+e4i!}oL6>=_- zTJ?XdJt%a-^g4eaCinx=!4DBy{$QN=13uu707z*s(lazF11kH%p$JWJ?ipbdE~CGV z3czeCXlKxrXN$=*ETPL@ST1e1(1jWM2FsKEmz#w3K~n1*Hm%~0Qqa+3m1Vg|HfA?65tK$1Hy41QRZ z3)L89SSxLOWdv2B!t^z->xE9i4_>{vmcS<}!!z3gvE@j)<)DU!_r36W5L>MXk9RA0 zn+8(3hGHV$z@R{qyuW*Nekn-p;&OO)a&<3EokbA#UvK6M+$%0CBA1ym^H^8t@H-FPE1i<_VX?E8hOu*~JrtpA6U+@XU)C zn0OT$hU`M@(7mOwy7@)z9fOUGt zdQdnQXTWv1#)r@YI8Oq$nPzvRkYs6mDT^9tf^{8!Zy38aBgBBbys)sukOqPYsEjxj z#f}J-W(c6y8XEM=!4|ddkzr$Azf=X7U}LS|uN5;zhZ9efK&CAe#4?ei8!McjTO&|wz%YnWY(7+#=5de`=qCAR;d7-B~(d?C}Tcx111gqb_S%pIZB z4sm>3=U8@xnLA`=oXfLn(!o{26?6fQ?6nTVeL&2lYW(01M_k}vEN8aYKQzW-!g~Fm zV)v!KM-$DmPf{LFz$p&`Dmc{&{$4@MC^9uQH>?x6c|@%uB9;#h{P0^daY4wNi^vA3b$Pz$?I5+S;g zKbWdDzDD9?8Bt|mA4VD!;;`XPw!)4RfYpc& z<_dh>(b3`V1olccWh=SqpF^^txAqET9DF4fHl&mzrpQIAh;@aaBF9UqcXXi=%1I}M z%-WFyL@e6flz1l0#4-l}1)QH;ezUlaLmHA|NM%w(n?Edo<&$w+qWy{M^PI%j674V1 zDV&okTcZ72A~3K-7q5uGXo5&g7p`)H9P!trkx$T?kv{-R)o!<->O=J6qCA@=dIvUPRDlY#M?*gVFW1K4T27)stn(%vr^VKDKjAXswu&MYg+pujVVF)DaT6pZ> z0oB)(K9UczGIF85PvrAi098OI5+XWQjwUL2trLZ+9LVJo0$ocKU%&>HzL{1pY15gO zl9eU?r1ewDym${R!GvfWg#jc{3L9VYiWnSNz*EjeJd456VnQ_T(zw8KV{(*dNt;5@ zJc?SNyGxUUOot#uR=k)Vhe{ApB;Emg#9Hi3v`Q#h-WJ?7FGi@kMW-wjpv-NxcGr8=Pe+PO9UgA-0dYTj9EGFHM+k%Qpgn$z$be$zNb7h%D z4cLbqbSh0@z7i@dK55qW*aG9N0YooDDP{i{dmf?na98~J7HUOFPR7Zz$c&=CgIp6c zO6kcov)%kmQ!{;l1JT zuw*vmU{p!*fj(vFaeq4e%%s(7moi^Ro7=cyjs#{?bb?)UN}g+yP{6@!N8WKndQGA` z94|57n>R*B+KdMNvmG#jkl&5XxaEjpB^z>F`{+o=FG|Ijy@JGeNM&!TqgSf75bSP9 zYQ%W5U^Zq-ImHOs;bo@SL(XdQpxxSQntigq+Y{eg=32oqCNE2-9gYwinuaS=sL=M3 z>BTSes<+ViKiNNqiqsC=wwJ|iRf!ZRi{T>q&uI0UtyPes8m;mJ)*`E7sFh>oN2FA!$aoC)KMb1;rbu~%-V(IK_Zqg1 zH_E~e22VY2AyBtP@Uh}hBDK%^g2mBu)(F~CT2*ANSpgF&d;^XFPe;ha__v(c#Hs+r zkn9z%B~ER86H?qog*640g0JE16{kwPAgG3s#YI1wFkWPRwd^mn=4hKq3KdxtAqk~` zksvOe2uw)GQ1FXNxa#H$Xo&>C$}ItZXVXfF6XTh_CN4THG}{|bAB~lQeSX&D7FVmJ z420EN*^016B0y<@?r}-#R3=T`-|%~do+*B>Yokc2vnzs#r<0WRkM5F1~_9W`29c}*ZeLRi-~4=)O#^AlI1 zW}D2HRi;X*ka=Fr={x}loGYe-yU?E)j*xjw9Inc|KE9yjpjChXaniE*BNKHwCog!* zew7GfWI~sMgta6-tcxd<1dBsy%M4KV^O*1e28g`WQ~;6uk^ZrIHjvoc63KFeE8r*R zZ=Nl%w8V=iNO(iv$^0#-e2_3~U~~mn0D%2LXuL$um>lSd${^B;NT9Q$*p^XeIUwj@ z+n^qXsy;ZIit2-IEG(Za5N3ux%78W0K1c8?3*cK>_$%aRw~hjXrPeaQu*gGnu}Hic zzNSM1D7ApvdKhVh*(~U^5^PJYUeU4=e|251^UW5Qgq$v)=~gn*W}-^;V{dW(!Wl;fgw{z<#Xy^pZ|Mxp%J_D~siU!Fy{Ihl zHVgoX8#HBnIgb?fu*40TB5|4$H(*qS05e_LrruN8p25)c|P1@^yHU`3+I!Qf~Z;*v#4Hx{-GQbZ=oaQ~pTbDxMkBl;Hez{1^kBjmE zo)DhEuaW{{gZ8$i4Hey|0es-U9y1E~?+(_(gAk?69r1r7%#5%r^mp$+|WON>vHC>}M(|xJ>xfl`gzf0_mziHB;W~t{IDP zR@8KnJeO|ll$WMbiyQ-Mw5vI=74~yUu@o-|;`%vMe{P66p-W!nmxl-aJ&odip(!XARD#gS1>IJ5IPwm3rkc0 zbjgSX9g7K5RvW}l3S=#0O&Tk7TUcp_mP3V_KAaig z4wFkbvc!1Js+;!EK_#6W$<8GzxsAS*317iP;ZR4**l0XL7Ss@Nc8t`xLvFJcuehND zO#LNxSEk(vP$)n0g&xalN1nBgw$y}e7BJ4(lh=m9_^xVUi7CXiAR93A?}R3tX{2ah z49Vu zES;H#gw;c=1T>$HJ%qd3CA<_XeuxnX%sPrg(AcrAhCGmMJ0D$Mym+q27dno{lgL{! zTA563xmhru3iVxI{P}69Ldy6VWAM4 zc0n$k4E3mjv3{wvbACdR==n-9UTOtvPid(tw;~*YZIyx ztkZN9G+LE%`4wb-O@ZoTP#i@&4&l17-u6Jf6~h^e_B9f1BkNSnFWjnC%d`zf4Jm5D zbEc$?O#tFV$Tcd{Nf`ibNtQpe!EIP#sZY{iKPzR1P_dJ3PV_1A&WZT0jvB@nuoba} zECemyw~PSb4?hBM*304~@d127xcUH0!M5)}f5fzDJ^&tb-!sMi>Lr)R{t34kmz9eMfus>P7;h z)hgMY?0-I<9v>XeCkOkpqV(qy^$K((BVpZAGE5rxgVV=|TW{^p=2+-nn^7TijYNfH zD(KZ>dC(ZzBv2$JC5I9mq&AJiKE0MK2^uk|gV$r)FqcLxs6;374ORF>(*Q*!w}Lxn z5v+#JdU6xOxc;RPKYnkt-!V!+sk|Xj!!T{h;BEt9Hlmi*bmEu^QA;3(8Q=kwdw8a% z1$`gNi^{-A=v)KrK2^byMjCcUXg0rk=xwiqcx0v0GFdb9e#lpkJiJ@t+pO1 z)G#Y?gusx<79-bso<(N;@*J^%q1kS|8v8jv@7|wNXE|ftjFy9>ZUMAN?gK(bUelE{p(S*I)g6HaaBgq1H%{_0bI3YyJ&!72#^KjM z7BE>EScI7Ef-8vZ*V-eDb`u|CokJLcGmxVGQ6~s9Vd>Azj}GTw9F7ZsbJ+YHOTEBO zgE8>>=zVz0K8J}+<*tggH2#Cn>%8sfw{Q;7PHhez|VSI(t{SMOe+`oX|N{Hiw^ z{T$_&M1VC=Q7RhGvhKQ>=K;ZEl&MH&tV3W+H>=QMIQOJJ2vPfu*k*r0Y8V=%%h$Y4|428Jf+L>S^2 zngCundmp%@1~0p7)dPtYUi zlP3FATU zh!d1(yRr;khs@GoJ<$3}JV`;vncizWI$B&~A~`HO+FzPFppAA*ZFDLiNF);-{2joQ zGFbFF6J51Y=q{Y2yKqEz;fU_S5nYWVx(i2iHIC?NfQwzRbDN-@RQ^;~V(M}*XBbjA zK|6=Xm;)`#PbMq>L^q5}i3oaE$T_5Cqn~IZniQcZX0dtSoNR-=PlBX~gAt^BfL1}w z`nXiX#iiWr(oOJ^4M{m@X~v<8Z!-Hk?UG;Wx*&_EKAFOVvM!wncQUJK)7i8tML}%Y za0B{Ei46_)v__fXXxSlv5;8kPinm)9jot#rrApMCfD*bT396_AgD@5f#QR949(#Pp z4=L2?b_v1v;Jx!-AiV{-$0QYm(J)>9V0Q%E$QhTnxmp$D@SwL-c=Nd~tOadPhv;ev zz)9x;fzt>EioJ7kC#AW(ff~qGa|q^0JhNVOcMCeeXewFg2~td;WTT>zrGbekx*Ch- zu(ZWN)&;e7(IB1e(x${jCY`V`B__^=TPQKfz*I6o?!Bz3;W1s`wiy9RYG_m$UDxnn z8|)AA|jVM5!O^;ZQ)+1AK%AyUqGdYI9)zeW2yMy zE6+F?akSbc)S!|MpO9i4k|AaN5|a*q9Z9@`gjbK69=2#i5R~IyLQv^)fdrwDDpX}$ zz)$!P9L0nOZc7jfq>Jy*M;d%mJv_$H0b9`Ov+?c@cIQd?8a|9(HkPCS^&?P5u^sAP zrm-sR=+t_y|6+Yaq#HXpR~GnfVjPV#loHFhmnKouo40Z$4nl%fOYCzl+J^Qkek=Al z(E(l&#UMFcEouT>0e26n(S>)!n&UEkIzY^TPrE5x5BXIh!H@*4l+t0 zw=S(ToYQpZip=3|0X%0Pa?Tx(tY7zt=+a69h9agH;^FL93G~{l>%#_k7!SV1AY-5qVI*CI3PuF>cS)XRW=z<&!B&6M2lVBj@-igpMY<}?F z{FKYH7Wh9@pb$Vn@ygccdtgJ6@-4}LZHe{C4fa5)VtsP`8=jMd7+U0!<>Z! zKmo_&?N2@_UjIK)@Qo6g6>s)&^)38Yyj{FgyvzN!-`mFF)wKs}_o6HvOYyjmd%t_o zC|*T&2f7F!;r3G~UP%M3AOD+w_wk<~JpL!e8oqIS&OH|@W&W)zA|Jw?l^-0wKt|t- z>uX>a_BoR)3DJPvkK6o?0m{8mym^S9Qp5izTtZdO9^>S``}LKI9qEc5ULck8xDnO< ze^qP$Z*j?ewgz-vp6|hn>w~X#Nyt~(DJT?JX{`-c9Oy5X~5dc9z5&?m}hH9j@m34tVuRH$XxSGS^<#-R^#>| zlHD`N2_jxOh22kk7ms0Wn0L8NOeu31^FrK}8fwMF_S#?&Rz{$q%C zCUXFc5>YJ)$Xz<}fR9B~)8WLqhG3^K@A%CC=Gzm$5;P*k9$Z|P^f1Isp zP_dg=RLfg1i!dh$gKIQRG3woJ9oWb;znP+yk~&d>knC0Gq)cS3XxNfWRYTISR>+S~ z1!9l1#BOMbJ;DvOcwLkUQ6rfm#-k_`N#|)1HNq89CPa;J4jQI1A^Hxa$_FDDe-ojS zMBsA51U*yUFXpDdF*-^tC6ynggBn$=b_r=65=2%vm5hLoR__B}m-s74i^;~U{jz?L ztd^EU(}$ammbNOm-DT8<_6X-E4FP1(D8|$2!8GL$xn!S@5rRlELWHu5Gmm6O2zRJ9 zYPp#d+alVS)@9GAQCeC)Pn~W~xwK*>*~*n#L}ID|-XZiU8}af;Le$m&Ih_;dE;Jxp z7a&F38~8qSXWZp*Js5WGy?#L>DixYt_!a3$Zg08e5p)(7`57sPW8}&C-qVdp+}0y$ z0^PE|*8Z3rfgw}AkR{@DjscHo1&;VIU49Qod_0ceJP9K3D9;kz*7aExRK!u9rHa4= z66ge(M#3YXmG04HG*m_42!6$pPl-Pvd!1pcE15i_J3`|xr;QWp!i=R`#6MM&L3#Op zPe~0gL>u5iK>F2C1Vj^Vi@M{+%~F`s1{W!A@Z)MAb>J`2mb#&cAac0KorL5^p3~$> zT$GaBG@61+KUQXc>kRRfdD2`Uuu;YP-K3MM*6xDQl1W*=o7>){Gz&QXD;srhPGh9 zd8t!_J+;NCVt#|QZo0tkrfUA_)Hb(L01YfF6X!g-jN3SI{h1zWVF zq=v14UKVb_OUY%{x4RHYJHlBp@bL@?U2}*Cr}exJy)12VAF@=8)~493O)*)UV%Ri= zgSkVPNLoc#0zz6&gLJD(K>EAaIAY1bU}7_KscUPH5wppDw+e8Ci(-j-zxy>xLG*K~ zs5DH40$0kk>QV-SfI+VUu>^fG*r|dqmQyLr(hZ} z6RRl+%s4Uwj+<6fvRW)?7Q~Iwmf&=;SNzu@`tXP*y`7_Lu7ibfPuKIs)Z6 zdw{7q`G~X4#NwnEe57K2Gq4E=`Ll!R9Qj)F{_OKXKN!;}#sVTRc!E|*@F0`b;UbJc zQv;7|L4ah6;_IXZOfU!y;p%0X!mcQoK#K}H;Vni~k?SXuLm-wtuQ^UpvF*gZMyzN~ zTMfzlTV^vr>%d`={bqb*@#ZUN-d>MtprVHY4C7H%FR%sTWK7Ol6QW|`M9ErqLW#`y zz#_ulrtpTpXH2mUn-NfykAQI1A()7;)Z9BmCSvA_aGwWnU~*bRO)l7{s5q`ffNs8k zjzhRgXe_b)FuSQgj~6Cf_GgvFnXghsEh1d+m8u0I%VdCqplG?vVwQSa7EFh_^VBP@ zh|^XXY?lcd0-(dCz=tB3w@u)^q_QA(kl?fWprANL60Oa~E+L7O%a|kM8;U3*NG_!C zV&#U@XFi1&HmA%Am0+Js;YB_S%(&6sWd9gRot{HW+VnLIIifXGsgeWFBSajI(n|Va zIEM_w5wr|8QFN&R5YG*itmijg9l`~>p}m19Yg8kXIKVp*9Odkj>J|&l2$iafH3`~@ zkI2fabRh(vmyr#xVz*@-B7`IS2qAtSc$^D7QDF)^)g(McrNm*El|hVFw57>pqf)@I zajP{V6pQFaC_`!*D#%7C%%nltb{0?@YBUIH=1@c?TqL)}dtok`qXK}7Tz7|K6lODJ zy-n&na19irwPX10;>oX)#b4R8EF&c6`VKL5FaI6Q+?0nS@Pp%UH|fyr&=)OPLsJbb zjwADD899U$fk#wfbcP+$!7H0{Fl)g`>d@QA4SejNNj=5yQX8F9PCRF#vQ1t#;psff(3$dh7$e@7_u(sg$rihFx=jxIYm8tEz#}&b8dwpuhi!I3=MWHO+ex#`< z6|Q^J5Roe2q>o{|`f2XqXf{94hdY71|*t*U$>BRCxc;_ z8Eg2p=dRL39N|6y|IHFX`~B5)-#O`xmYZ({#cADP#E~OE2tW$lVB?lziYjeEN4LP) zAh7^WL;E-ijbhqj6*3b6$emD6RZT?EgS;^>2`OMjc+^HR(TL(>RH%bmJSPe;?pi}+ z<@@=CgXct2iZ%vHTv}p@8QxA4IMH!&_LNzX!ow8;g>Zmw#;~{G$eZ(&$|(y0#f}!B zk^ppw#)$He*j3m9Fboe!JC5ZD`qqh{l>No^cNdqx@?R%3A-0Q6RDxA|!%U^$r$p5$ z0TL8x9tc3Nge~Uo+*iaSZ(uV4?wFcwG#zg&C(}}#&J^UR8zC@hhsj8*^tCsZtojc` zIEx)3S@$R`i9Ps%uH;`Zb@)Ty6hE*}`9m>)AAL?Tx*+@|E+LusxFo4j+;gEZ5t`r)m~}SH8p|GmUxQr5f!~5dBuu%NhBe$ATvo%sWx?@V|_+?95y4zJx_-Uv{Q?ubXcZW zsvfvL5xQ`QmD#aq>l3V-qwY9(m$}2@1<}LI&C^)*n#e4-N@;@Y)otW`+v|7%Aaa6B z6`=^%*^yNxV^bFhVu~_Eqll{#P3hE;p<6B)Ng z?f7-hw_??run39dS>HnsE(Tzz2^`Xl(d?rWYC6lB$O!jk(LO87bWjPYV6*@>K~US* z$FZfrWSbsq!05nv^f_aeU5dNN44$f^5lhmh<}B^m z)rox15!SNJSpLu_o|wvXp|B>or%GGZD~{TPl$j4`z2aUfX#!+M4YzQ>aSje9{ZpqQ zu!rVa=nW#0TgdH=_mBJliD+T`Pb_K1B&)5cUeR_*fD>7Fg9&Dey**fY=7VF4c50BJ*aABYYuw0UQAg zD^Mp1sxsq%`={AJId8~Wf1E99q6v-8ejzqARG~mi%!g1Zuj{{%6S+}VBLO*|chzgC zMEq&AGSR1)cocNN0pEpq0jP~1BWPzk@;Ubw&-_NgG{a>8%`o zZ-6^Hvcd?rptH^{v$vtFp4W=hTUS{bJa(kz29=`jM4Sxf;tfHFMTzztH1>vCvxt}F z0q~HzA!BUuaZb##^cU-Zk}g*hSkhp`s8}7o1Y-l6Ekjufu&64y{2q+(LUDF{gDqSc zCB8Ft(|RjGQ$eFJkf8r*S-C72FIz-PxJ&~8j~?8C7fHlYr?=FjJH&(0lUV>5Yw{|W z;MEbAz{1IJNxE``atYAQz@_{&u(tHEp__r;!NW<;7Gwc1q~N<%FeDMfaC>biZ>D9P zPs^Qq?3uhB&JBMEe+HT#SiFWC*9kug%W<(wS5=a;$P7{pu>qi--}ns?tqTCkJP@q? zTgjK%-AnRiU{PiTnVASsDI%NLJ~)B^Hq&psDJrIcHG2lXH^>Ev)xq+n-?wU}qUulL zPu6J(nxN4G;}9J=bQz!KF7>uEBOnJidE zaSDhmHdp{O!O#@rrVUvPa^~OS<{++^VSl)rDl0g#G7=VmByy!)VPeY?bipe$uj=q< zfZq5lWJT4BXxXSZOG+9X;a2qFHfL)w0xzJe%b+%ZEAsB+Rj~zvb=HI??;(8eYOJxX z8S{rO27;ZIOG5hI*i|2m6RoVBB?-a23#=xV%pfv<_O{p2(J~(iW0}yRBDK~41oW~x zh*>U-Zmi7hjMHZ(O|5nbZI#Jb<+d`mNL6JE*V$|bQI}AqOnT8^rGr_aLINWMI7&uV z+;2w$bYyMBN)-1Yl{F||Y*HS<6*yAR($e6OE)W+P=8<}d*MVe3GmR z{6?PT2;*Fy)yyz11~g{ zwX(%}c6%o;%NzUmfWeSv1fNnpOPEGH2RGn|3ULHC;3ztT78cH_U${9Sj*L6t2yVbp zo@FAf1U7h-XC;evi)bsZ$g^~)5i^x%VXyIAo@Lwu=ki_(BAm;6=^Nr)o~28L=%zeN zY)#T2c$8;3Ye{0CJj%1=NSw>FK&x>M>y$@%R`bporp6U{mP!6NmuG1%;#{6(AQ_&w zJj)pdIF~jPSireFs|mWQZ{Z2^x;#s%Bl(Ox^4V=ccex!LMWy87LHl@GbNpYOg5XwZ z2pCWqQg{nekNqlkFpp>>j(87_Xd{mJJ{<9VIHHX>qK!DBjfn2bv+P&UpUm|FXi}CI z)pl{`a@hSCdm~MY06_t%>)_D#I-O~0?PVjfn%2%XM@a%TvXWK=COrp0s@zkrVjik| zKbQJJ+vWQOqvw|k(g=OdDrI3AVVaB_v|YhKhF%K7TLW-8dOV)aC$sS~Hh%|f&KyR8nRpbk z?D061#?r zFxe-T^eWc7Y)PN!=BF)jFS*$Q=$vvMNA@S945$y(&O4kHV)f-cY@IF(#pju{k_4|> z5s13S5gi;09R4?_NGqi{$U1D0plb(kRyGUC*cweIpzAVmBnAU?Qif4%c}wtfU=)Zo z7xx`rF0fMnP4Eg-2i6mdP!K;1I;3Jo65X>7D-8hG?i2H}E#@UxWe1sxdCA;Jo(tiM zdD+&45+-hQFjO3uAe3llAO&GKQ^j7cqm}q7rTxyj5#$j8^Je&frWAYcMCeHlyl>np zL7rj(pBf_caV(4UOpAf^EE1v>5T0UpkOc2_jSe=^KDpH2F!q^v1k+oTA3uZVB=U|Z zzm6zB?n22c?0c?d06`>zr7MD^D}tpff~6~hh1` zWFd3VgHea9N8F*{1a5?<_@lgx00HIfb{@la-npciC^h3@p!6Otl#KnG(GXBFut?5N za+{wN{j={*zQ6Kgj9KTn&3=&v!6Bnn?u}8*4&0x_iDEZjU~}R2;p0kkqOVz4RkbAC}v>cEKY`coofnXlyC$w z$@(%pf|vv)<`JWYBfbhp5EG8*G^w7Q*9r)NZF3rJ-AXf=MTH_YFeKaY)|fB`{0Bxy z%WnYqoU0lkBjy5PG(~n9@b7ua8Y=s-RwM%FNLzqull5ElqXSxo?;h@c-UcBYi)0zB4g zKkbog_(09^)f@%Ef}yXx5U-|)I3EvqdUq+-EARoJ#iPUB36@YT&0V|AWpwbUM;TUP z8ku5k)3d!?abCAwkGw<%xNTVQdjr)-#2j)3W9ii7(fRWiU!9#^eM|rNrdc48&Rqj^ zyHEs#Ed@eP{ViB_8O?2;KE}@TG~zj{L)9vRw=kla+L247NGDiSn*ut3*}VUFGCkM_ zjOugFSHD;_7DYmo(d}!KF^&ZViy9nFc1OGY!Fbn(ZIvr%xh@4#CXg{#VX>O(|G@JQ zZo&a6n#lFhjbjEPJDsIN=4>JR!fwWSe=gb+c&!3z^XUfE&g!(N3#W1mGkYd)jB@WY zXy0g_M(O1`O{4?qVogttIF0krL$>?Xu%-Y2+cjXgBW)(rDnU`P)3wS_pM~Ts;6ouK z2tuYTW?DN+jZ9dbXTK_p3x=kpgCqnmoeNofVQ}$V^T>7D7gr1SDUl4VRKuQGa~+lx zQCmp!bePJ~YfU6Z#OW3ow7@8YNHU#+sTJBez;8Soqt~-xHY;oK3hEw^f4gq#LN)%x z8mQI-bHwydLsIRgI8(V~o05;*&T}H8iD`2xOQJ9Sxvy$veBug z#Yv&fqQORbVTLl4E-azNMY2JDzOBKR7SX173!)h*O5tgXf3}~OmuBf20SE=<1qWU++@E${UW_kS|Jb1 z1q}~pE|6UKFJ%^{DdJL;t7Ex`vmBCT85{X^U!P_-96rRuMXufR{>(>EKc_gWmo=><>T3x`n=OP{!zJ=&cbJ zLvC6!{9#Iuf2uCfVAm~GA$fpdnRE{wybW9HB#Y!nz^ z{2izHuHz%!bV}buP6V9Izt|0ZGd!Bj5B83g{d_r>K@6GTFKLN*CgFNw6s?z5*(xO= zJ22N*S2yc~MEp5+X7&ZEHr#q<`9Hr=Q~m6wxJZ=6Y`kX^sA@NI^3Ok>*FKK@jt-{d zIT36B0a~$(9M#Ota&@~xnd)!l8|kjQ#F z0>WW)N4Zlr56Bz$F(N2h*&@{5D$iLMJ`+Rd03oX>R2Z#5pzBt#&zUC$G=XkEu|~pg zFc{scJCa9pbm+Zm=^)~D#48Y<@lDAA1e`a(UR(=GpEYKf ztO08cFH@3t(>!GE8xz8HFC2+vp#Tw_>R#!%4#x)3!r+@2ien&^W<+!%5Io5_b68#k z7}NJdu7jD%4EG}N9)9YUQn=!}8i``OEpa@H(pm3TY8)-&f zxuNM@FIBJzRhdH)*UUvVJ$mD#eMZf?0aH7IW8=`KNF)R;F_0p7Nji-0839_P7&m35 zH5QUUc_+f0OZr11pInJ8^(f1zgG4Hsql+ztDml7GNs4Z*9di2{I%J^I3abJla&&?9 z#hy+V+%5d6n^{pWY{7_Jz=pz7^5cBRA>;hwS#AXdbUBKGz0&TfCTvI=5fc}hmbd`3 zq(F=Q1EwRA_Hau-MAI5P%}7#PEcFAn34tJyX#sm=p$~v__yBNVdFC^UY_9HgGXR5V zY`|bB?URToxn2@qO{ddks+rCs>**oIJ>UZ9Nl($#)F4Ms^EvaQw2^!RQpNfkzc*m* z9f?CRYG}iGcyf7-^$#QcWx?2Bd3dDZ^6DBZIXOKi<&ZIw4TOiSKrsq7Sq9Nq5Ak^0 zOTZPtv@+m68XHV1(e7A$_}h5DAHuJQMEZzd_&x*Mny2+wgla*cB%UPhY00%m^(}iA*1Nr3`787jn!F_=78jlxSo;e zHC6dp@K8^o0R!~+4 z7D)|Uy#k-o3_(^w;M0K*DZ6Qe7E1N(U(k6%vs=vlz_0Q#^E>Q2zmWS)okNUBFyFy# z5A1%$5O(3rAPGV%XrSRGk`IE|oyYNg?9Q#aED9zI;v=>OJG_F=)@|9O*@y6EqCRok z)SCQMSBFWz#AtQVVjG)!+Cw&JHp*|CbSi$YGr}r(!Oa&)kD6!UXuYhTp$k$Tg_b@! zJN=Ksov&5_Svc%4(2$z|`2Yn?{l=^_#|zju=vUCVPY_D^^^4QX1tkT>fa;Nc2}Feq zTuD@*53*5F3wK09Tuj@H{pg%QSqxJpK3*i*3TZ_0=$wHbk6MFS*g_3U zbgS<9z%9-^Kb@SPFD@el!lHtKXHyH)qJs4#u89LpWHwmCY66smf-rR{+UJ|yp7_{V zu4Mc>3v{l2v8n~ouio-@HcizkY%!T-gsEPu8)v$i0k=nX9OQP*nqHipedXiGRTpSG zAH;E?PuVcSld$BRX6W6=Nx^`Y1O)E7MLdV;*^+VR$X*COTDOk!St3MLiWmRTfbarY z`Ot8{I_Olw7TsiW5N7W5_a7a_;Jz+K4P1M?&uxYB`dGjj#3?&IVJz zE!Y{E!L-5}>eGxa=7Tm|J}7o3c5#V%J%ZMeD*-egAPon*(!}Q$_5|wPpC3&Fk9v>56u9D>!@I zKqM?RC?z+JFq?4{7DZ|v-p);iHr*yeqsOBSh;}H4rJD>9`bHAVvNh>lQYA|&aF^}$ zmW>dX9`&7$;mk@4D~uSsN^^SR$Y2SbtL6w$<_d+w5yeO%N=_^_MZdh|M_e;y0@UYx zvfagR7B=_-l0tFALq~-g1&_{Z#Ry>WEJhDwUr{|~xO+dm6X6flOb{iD2v^9P7>Xru z5`+;%85t2EJTllFA(tH_x1U;oJ^aLYn$Fr9hIVMi$wVIRkY(>wA|%YL(_y&qS#B?h zBg5U?x@XKVrhs0us{<4}cXeokLDuK^foxQF7P~rddpr4y6o|h-^y+tD9|yvW@&gXw zU(h?cA&LB;7NSMa(0w!&_t;`_RNWp9zEvLf(o|-bUyu@5HSM4erR8LzLmXmHERQ!Z zdMG{y7g^poI1RnyTUKgpcr#uAkDYM;8|t5w?VNcQ*%Vk5D$mE5L-nT-h-3X zg2Pja&6dBoblZ0mtc=x7N7*b4QB4maVLi0pK-D;&R2f>a9IJT(t6V{c0MQgsAu(M5 zfqM;5Bjm+@!CaZZWM(6PI)&;D1`jMj0Ts`?)pz+pfKm}r<;0Uk?_&dYC_Ub$yCGld0(*TRPl9kws@;Vfo$8~1c z7te2;Mg`4{8UIjqE9bO{3{Y7tvk?lw;hwSu4sW3A?SpRaOHR$ephu3oc0!ewMM}#A z9qRTy8m9m zC?p_iA6zqnvOaDf5oU9HUpzlMeS)x#hgI^vJrN_$YR-|eOQ`j2KPX zV-&fDUXWifD1bl@ID{<&hG!>NnC$blTk^dkRHaE=tq76Ua>7h1`^$GD(GRt?GSSK0 zj#lt;s;L#WzhJ~6;&_?N70ToWPw7BS7pLb}K-bT(>8piF6#nhhI9{{^Xu623;_R{=yTdB<-7-(>DH&kJe+fLIrp#u3 z9jj#WYKt5`-$szf=d*gU7lQSdy)2bAHZtVux0C|-?8z02FjvRS@E@Brkc@f+hda0l z3epBl>8C6)6uW|#g>sU|nSO%1=sy4emY3T#E+?061*rr#xGX`ql!dr3ZOKdGzMB|m z$x7l9I6M~u5S87QDT8haIE|Tcfs!G641@_{kheu%E2&>|2q>XQY4}yRj4Rm2Ou}L^ z^5A5ZXi^RcZMTHb#ybHBS8e~J!Dy~9@U$O__vkzwjE!ixKtKzBYyj-3W_FV7#l5%V~_<%s`<+N-lRc zOb^O23~XBvJ%K+QMOI2sP3P@!xnEuvSt;fY{2uK)x<5>kWp6{Bp%!+bB;Ir*Uo(lm z3lk7X0Xl11olDYHQ)wmTM#7~T$}?mZGy%d>;2+Cxd0WTX^x6mXYx|&>)J?OsYDxcj zCykWPsd;qL#9@Q6nrVw!;0o1gTaa3qhg(c5FuzG`2lO|RUO}r4%wnfjYd7f!`&-Simb(gulz8M|NkHD(p86QE63ZT^6*pvlqP-|(&$Z> zBAy55P)4tY482%f&rdGDSzO2QDqUm&;;u$i{1E9ALU%2(6Ix;?P{qLu6gxqJlsKn& z;Ksf@Qao_gQ65SAEfFm=Rd_DXifCzxXlXe^MxGVX(o#bkp+FHUkwY1WXdnzkNf0vZ zqeYGg-LBdy`)fro{CEmqA_VQ&1NAXdmv|-IXF@`E(o+*yWe=6rrn9Rxmz`@*Wk?yQ zo&!ce>fTrY+~)Cwz0+?l>9Ar!loyu^nf`xO+kEITG#?#9KFacggSjOuNEsR90i}~| z-G=B>NEpM!+3&63&3XKp->bMCkY^5LJ93o_X2S=ncu+$!aw|Q!gnATYBb;ZX=SUqn z8c(h-F25&9ODv2pCDq`Uc@0o)!FMc6U9PnwhDb{c5#ogUB|Hj+i6J6;U{a&ni=PEll0B=tjex4PRiW6vSkW=ms|UH?^Vx4K<_lqxD#mFq`pjU+Ia zRhO)5Rn;xuTSbbNl?V=u1Q{U6!vKDmrvQySBzc^Nq zAP;$QzHhDlfA%@|7Ae_|V|DY^z31%TwbxpE{q42IW9J1CgJTj%IgcM!Lpz4)r`6jP zw{LcfhhW47!kQzX$TQE-tEG~X*A9z$kuD|}G)?%Z`Z@+0vG^BxTr8ATNRj~Y7?4f= z6t%(+bs3uo`S7M>?R^u@PYhJ_8XNQ@11aEf58lc_*@j4su=+#Zw_8_MAr&tHWP-Qkt1O0B>V@Hr>DYdu2ibD?J3v32!E%Bq0;LQF2@sdrEhLKK@CQe4<|>jgTDE>(~m$hG(K$%}CUI!gN%&Sio4VbgSk(dfZK+ zl-8~?v`+XwPYQ_N9-kufOp44iDKgKb$UKt_B*I&cc~WE^rZM1msY|36O5vyM8Pv2% zp`>O+cxCyP6%er32#*s5g%GhLR+dtA{Y!6NV{~ApOdy*TWAO!`LZ#5OxI;GG8=$%{ zHUps5d&`UOBQY`JO?K86-viz;_}PHoymPu4jDO*2;^vF z0o+G2-HPed)=3mU94}HupLY>p-($uv3998M>2n&h;-~5#6!}1ca<3@JvdV?HGgAR1 z=i%-u5ynF^HyQ)xu`Fh*aF@M=*75A-%AgTRQZNE%g45w@t+1S!C{q^L(T&J~Ajch7 zm?-A0cv^d?_QhUjkQo--L~*O;66Xym@RjqlB*sbmEO{sVRspJ+2w*E6C=Z|)%(3yJ zdSBgy}~{6? z=OIEHN>lt_>>lmm((dk2y_x|qVM$RNh*x8B$S_mME8yads zN(Xun!6_!;uQ}cfoV5#(Uw=_xd4SE|Am~g1BNqz30i^i{faV{p6aRpp;E&pGjNe64 z)JZR~3A}n%2jdevIDPbU!3GXlxoFt&5^0BOCcrw`HMEb+;3BWQx0gn$Bd< z?<$9e2``&t%U*HDkO_xt*jm7o?64#Ir8*O_QG2>IFmO&}GedDTnGLv_Gvn+ps&mq$ zZa#ZRvHbaQuiXcul;|A5e}rN+P*J68`2*4-sbXc7V&#u8Mc+2(Gp)lWff{xdc8-N7+Vlw4lI|$atU|gcYBEXs zcx*$U-=<6y|#Z(x}9h=khG+;P=9)mFcR*_?KJdZa!z`n>N&(^-Uw7m8H_If7E z3?*gEHPJ~cwvW7CiVZ>H&Uy8srv#URM#A%n!D3mYJ=(5YjKOMJXS7O8c4-&@LtJQr zPx+-~RU{Nd=L{bRCW?YM8V!nz#hFQG585Z~tP zRE`x>)rx14i9Dp4UF?1q9;tWN*vkDzvZxykxVW$cO4^X2vPMFyp`eVCF-8vWXVzyJKl7YC= z&GP8E&~}d&x!z%m%ABqac`a54pHTl|ujV|2UW48D!*i!O!kL3L6Pfq1Ja+m zilnY_9%9~_5c!`8`uUc1Ma0x4W8ra{Y}YmQH~tP#>qW~(E`q!}#Dzb@1LF3KO*m(u zvCc28tS{_rZzIC*!Ajrxa&T7|6<6^_Lv9)g$~kFKc9o&+YE)LlcN$@dbZAa@VT*#P z4zR0W2kh|yk%hi%1v^Y{7FN1~DNoXb!Q47+xki{uw3_bglM-AaYJjbpm_u+G30`x_ z@rP@UKU{Pu6+|!1qQXD2%G5OEp;VwTOMWR$pr)b%oVT{O#(~O?D&AlQ^*Y0tH;>=L z4a>DV5N}Z;gUn*hZEPFHN)s?B81*vpi}APFz#uiANN}B5?E9_G5$yD|b-4^+l9K>9 zq}HH>9l(fgwbm}8DmU8?yIoOSA@XeL8;6H_K&R$lmwG@Zy+U3U0maTf4v}_vkZVv8 ziQCpuyo&;RlKVAizc!@{rwoBbTg$v>XV$1-t%iD=2QQki_0tl<=|DVF!$((>0g0#C zEYa36EZqAGos+{BR4;C(WKPm%h9D>42#cp)Avrbn1@?f-pv4^r67ciVP!PR&#Tdo} z#YMr=6IeD^Q*7#zYx!6J^us@5_~H>W`2`{apuz93$?|O2Y%$zjl-A3f_2@vKR7o6G zL&sG$q1~`d5q5B813uG_)nyuw9l}s!sAFq)zrA;QFo-~4y)YH5KLh$fkK1H+g9SH( z$Oz+4hSsexLXDlm2)�u}Aq6?BRi)j;)z14z6QXoLl2K!?I02o;8fHUxD+GN8;3->S2~1!lo;I0196 z+e2dWj5XytWOg7hOHSd4*hh}IH3#mcmuK?q#8&j(o?eiOJco&yWJ`jM282I{RE$vQsv1<~09%wUfaW^^G;Mk`oH)s=YCW^26HgMb z9G@WIOavEFoOqicIXU1=4u3GLwgWxJT$zt}z96N0Cm9tMb`(YwR8pSS116c2U63H(Pt1uG~|h zCP9FhvYSw$$lbj3!_Q~n-3IyI>@AMc+9HowU^~CO>wh8gCpq&b3@eV%QVJIhRAQ8j&t1FfQu}5Io1C zLmLtKK<$&_S=G2Bj9qu}v?p>44T_tGiOGOQXo_qX6P9MZFkI=3%g*hO3C-8s4z1IbUoJvRW_@IsR}Dw0So?x93D{*?mls z1TkvFeMj1lJJw*%U_j6}%k55|Uc&J${P0c&T`faqIQb^S~ZUXluxDzPhS|t!UWlLDU_C31T1*6wS_l zYP6~*vc{*^&i$N(oZ!5CHq*qr9<5?W1VTW|4 zv6P@Xi_DHiWuD0Dz_?95%Uj}XoxEtyE9M~lc>j4JdBb$$67fjlsTq`!yF6}jlZ6Aw1 zu~l155upg7tTbA+>_7(<>4v9g5SSoZDQqsJX?~adEY^48CWh1{e1jFz;BEOMT9~l_ zz_XS$v%BO%0WU<qsllsH zyK?SQi(#LMm>%=7nZONQG1`cNOew;SvBu)6@zP#Uy7i3)^`SE191*XMWYfG~BQ%6@78?aDb{Y_BM^Cm-A69~SvxL!jwlr$D+u<~_t z5fcH-O1PF_*bB)h_p4Zo?0bj_Szg@PUUq^+l1=;h3sffz6Ov1ErM~f{Av2&rlmUG} zQ?ua0-vO)v#eoNMHC5%ts1!;|CqW37EH5+ZYpaE2V6(m*g6y=AWpAuqE+S#rp;C z-?jJ(**#3VZv&nK`i+HuW0G}yXEhFdLKGpom?*AU1Ffg_m6P^ibSa~F?~Hy+TP-$d zPj`u8hm(0sLk<2Rn>e#?@jG>7J!wTbmfvNa;NapLMmF2|h8nsC?lKjDeOuMg)%pP8 z+!Qgg!pDj8^;4rZSmQ1%@~+J^m|ipsiF0s7jk1PZZi^Z&(Gvkb2ij%IT8D-nxKuBm zH7Q#`aL{krad_ScNKcb=irswbp|{vQe%9+e-iK=sYl~O9Z0ZtAu7|@(r|7!4^mmSM zm5%J#Q@tkrJ#rsmRaju=E5!#Eo>5l#00X6q10PgH8P+imYb!p0Elg{S57q$O@WC3` zjPSu41i?Hb33(+XK3IcpC>~J92WvpW#0P7T80M*$%o8VhDFHrMgJ{P?DfnOwVk6lE zK3Idki+NHB7%r=b;~AfQd&zcd5&R2KX*@$>s1}>Ou8ByxufSaSFrIG_+XRN8g&UwOJYeRSQ_5}E_?!9_yoA{32@;P z;KC@jJr_h{nK+zZSOX}t*_}B)=B`{9$eH!#09J~e7^uTd@)(2r#$GBO z$qgLrX+5q@NW}!9l8DfQC60WT<5rqNbwDn1b(4!RacgH|V|{a59al^3N3GL?6E$Ll zZ`|U;m2x+6r8qB&QJ}E8;zGe$E%-CHm+!5wF2Q5CS!StQqQ@41!50hhvR4|F%#bRG*!Jl*6c|V5UQiZ41XK$5n4bbFt^)e zUjw7T256@eVi?VWjNnrhpL?;nV~_HQVFx_z6Q?K58rdKO(7c9;;8S!67`bU=1J-Ls z<;Hs=O_U6Tp^Qw4tKH0Y3bDfjY7XLuxiL82BA{6`kR;9*JkLF?#QHPJfOJ8ms?@90?oS~G09gdh z#Hc%F9P+K59sUl`y{9Q6A_1$XV5)(z`rGZ9E*w$aY?}$hUgHsPSs{^DXn+LE6Baf@ zaT4DN!x>>=yt{?p2}7P_IT7l?=G2`ec8%yF?qQx(_rds* z^rl}z!PIFIK84w3om04S%8)-6(~-aE(*}5jm8PwLWmE8^WLOhlBIq$4SpRT&&eQD< zvrDUJD73~iLw2*nw++5j4@28(^w)b#4MJa} zKPeH-MU@cT5%vHfGK&v3myvXTN7C`?fOnC5;0Q|rkN7De%|Rb^Ps-LFt`&oiyhOWY z@AQaCh)eDUd#Af6^fP=qXinstIgKV7UIh{qLx{Jy8cl|yhWZLb68O=a@Ucm1v9z-J zX*~czL_fh{V4a6HekPh)=_@8{m~%5_VNi`o>z5UimSz2LzavL$I*;bQY^<8jAJd|` z5#qr>n1NuqkUuUz-oYh$YxDP)D{xD@AzMH>{N@@0K7U+p6E?@aE)w${lHT$41i9(jd*#Dt<*qfT zmItk;W$S1U07o2}k|TKANe`L)I_-W2K##F8wR^-v_DD*;sf%8&2}7)4WUw)SS!ntW zSywZ-l#CN}6zNVcjw%6NxjCxRM+NM_;h2Tqw7$-WGg(Ab9`OK-_w0+Fw1G`5x7{SA zfL;+g#Xv|31BcGSIFi~VXQ2z(+e6x_BOnb@kI1lF4y2x>Taa|T0``5Wz;2u|8F)@y zv2B?30={P@mZTVQROfW(PJ+=%N$zG#xE^j{ervh9#UzDk2seuuZ<-;GN>DXz0@(76 zvWK)k;N1)LS1WA>nkFn14loob`p>{I4oe7mln$eHk7{9TJe7{kWBk)wWw~S|-d*q^ zJi{?5L%Qc-Brb~cBNvdp<|_V;eg{7S|?&O`Es4uC;ZYAs%Z-0+wQGbp8vy>lH=8j#|yYgac=GU_Tm z;2q{|I#-BgNG>IlgmW;d2D!s_3C&Ju!oe9zG-NMu3OmGcM-{m}vNHlFz{5!e>)_296Xy zo8~jHpYRz6JOV}&KAYt;@{{o4oIFfMcvl`KLli6@pUEPi1D*e4?i^HL{85smzV8z3}OTtP@>*(Nmq9xGFJ9@73o20Wddag5^r28{^u5+AZLbB+&&T^8G{n2w>!AUwzqvyJal4>-1uIo5S z$7=X|Qn8ZPh{n%#zLKCcDsSdXw_)_$%$E+@=((A1iYt?5zA3g$n)#;qGHK?UV$7tO zZ;CUMX1*!bOquzncr#_@n_|wCnQw|aQ)a$2^Mv!AGV`TfFnVt0OG{z&+{~A@!|1u0 zFRh8ub2DGs7o+DoU%AyYd_Jx7mD_cq=Z02OJe=0~PNjG_t@E8q@o-w_JC)+$w9a>m z?)<1;K~=PQQR=()~U zQU*rPb-t2BFnX@@m4pY;bDggw8jPOnd?oc@^jzmF$q1w8I$yEzhtFqqzP#uln(wU6 zSMDi{%Ikb3?N9Vv=R2F?!>rDCHpPcoo$qXl53@So*%TjUb-t1_CF)n_DIi2rZ3ZFTh?_3I> zIi0T@-H6)P`O^Osjpwe;m-nB<&vm|c)BWYH&X-Ai;_^CQrnHZr>wKAPA%3p&WtN)w zxz3kqF5~Aq-@7Ru-qrcuP1o_R&X-Bwqjun}7lDHZv6B~O#_3AJ^ZBQ7FBi8zVM#ij^@Pq^;*_EhO_*8J1sA_Cv!+)reqm;v3Wo?*$EePa+#b2`vtqQk z$ZL3hR=i9V&Dqpz%Rbd5wzW>wIvPdhwmz*298&Rq?IA#(&>tRNQx{6~4*( z-{p(%vBvjRWBxr@&sa^>te+OtPl|uUqW`$~CqVAW;@52?%Wufff64+So4&?x*ZFay z_(AcT#m(Y}#aqSO#XsYt-{Qxu;x_+4BUEKnO-Q20;vw`ksAA&L9=(cUsaoXCmRzJu z{|Aa-=C#@owYib`hkY1A_GCP7GOrj zZ21H}%3;Ei)v*hR!y?(?3#7wRH8Ze4UtG!#T^SPE!TXvqD|3<}mBA{1l6SdLDwpEx z{m#K2Lt)n1j}wq6!wSo6bW>`XumENg8}QY_^p!RvXp3fK9QnCg$ZCb*W#jV^e-2e?m@V~KK>WUP$0gH;gK^#l_{Vt#Td?N&d$9v+ZJZGq}G&t2op!p0$(%&Y$=Kj<)^1eXedbji}!supqLFB+kE zAb%5&6an7=&N6Os^a|GHV)3&4xb%eds*0{^+Gz?L6$YdhnBx&~!!OysE@cQk)>qZ{SA?3A&!#Y8c#^ zMY#|HKx&6OIohzO5Fj+S0ZStpbwr$6BNx8-GDMrfG`-pGW9#H_xuXq3%2`y`%L>gI z9JV$D{~yZHB~ZRaD4RTq)>*gGPqAN7P7uecs;DRaNuhZB&`pp*JQ9SgyzYLh|5HhPRP1;H`~XpPVYLY zMmZR0sTgJbi*IpHa^OVt-zHAYZ?3&vu5XraRiD2TJ~G=FYM|cRN_064w2o#@hceY* z*&`zgfveo3XI=JJZN|_qi8X{uNWZr^#|G!>Mi&7=CbCFD{Y%sUs9&ya)E=OiC`NOW z^{h|i1+%emsL2=!etO2a$qUMDoIX70^!Lr>qWz+Q`3AWLOPi_AbKl^tof>T%%7#fH zuQ8Iqv0)BG*zkFzx6=TD_d0tBV?{2J4;R-rKH6M)_r2|RuCH~ki_=(9EP07sVApjT z$z}1cj9hTrfe><%+pI=VLxFf=83!>|Cc04K_K%IogB788U}7k07I55n4p-Gy?S zW*E^RM5p4k31}eXLJ)hok_+N8fn*6T6>end{xdWPD*msNcCmEao=I|m(Z@@jKGOU? zWBb6!&SC4|Q^A_zVuE7?nJICdbZPf)BNmyTDj3O1LoUL#U5J+c15NnuiPK6To+3ps zB2qevynr7aZgKUu z@kpSQL%OIT*?F?~CJhNM$1cy*l_^0>2UWIF)vPrP>$;A1DjKcq)^~NZ7Jcd#Wuo#zMA*t4drTA039=GtNDjikXfY^_f za_S|+bKf7iz%)mrxcl-p|BdsanTsEFPkW`|?Io$Wcv*5LUfMr7IsWmFe)RO|(>u>l zW>>?!@8EB7S$q~(fcNbm$+;LfP3~{4EElfM{d`5kP!+2a z{D=-A5DH}t+lYVX8(Cd_u(RS0Eb5sc|F(LLs@iI`jIZy9I;F!K#hBk9oG&7R<_)r| zml3K%dMGX-*5(?PX+nQqK}e1~f5lD>*;c~4rK=-J3ix3#r(aFN9|CunYjIp-NaeG! zv9&zEx%gfN#QvSDP~6{GUt3=DClt}+3J$Q~5cd*KA4D%*EfkVf9@n%3+ne)iTd0EL zI=V)jJ^%BoE1AwJx z>dw{*F6*d*A$;rWT&rI5=3nCUyd^z*jI=tKOd;O_p>PrNyaseO_CWrrHUttwZE5u`czS=!1e zVYtg=j>&Shx!qqy9Zgc}ZgBEB`%8`xO^bpd~>RvXj%^ zkyA>WL^cG8pIVX4g^8n;VO2!|g^WA0d{{Ze#LtU+;QvCammjFL4uo-x_=IQ0m3cf( zW?>}PVl={gbN)6|$7StBjW9$I3yC-=twaDyl+op}S*>Ueo6S$f=JnH)a{W;WPu}d804&twGPZU%K_YNEDyw{p&*#rkpu(iZr$u%Jyby-T zB=^>^gCWXKZe6)UDsXm*{fWQ}HE9x0LQm|1c3T2qB-F=79OR69Tl5cHKX-bv{z%as zIEd>uE$;CezCy81={Uf()C`{>8~XOh#*r94e|`jA)H{CYl?XcV7H{7?CHmOe3-4w&b=)KCVv9hcD^9YFaWn3k(4&rSOl6^}8%B+YK z+gL&lXU+7mNTHJfTc@z0F%%n;y_;x|l0hAGY6sL%wQvkY73a^BS8z>T=kJ{Qr|@NA%%T* z(ml3yhin0TS1ozqs?L9~zPW;_yBbl~SeN&@ z-96h%{L{8!o<@(UvP!j~Q-`@y%KdbWuyLH@4AF2) zPVkP;xRJ-dT~&FUsTtQZzv5bm><)X}ZXddF2H$NRKB|=GZ6CHL76^XZdRzN#hO9k} z>VAl8=etiGiN!x{P4hIW=$Xnn|5Yn&(Yo5k=D=(`!uqzm-2>N0<%#V^UYuYFeTk?` zMSX=9!!l8W_n&QacA?dIwpDpz8`BqP%$JCo zGGMoHi1APEPUQP|y2*P#0|bKX;gqjXOdV#^<8C4mcH*GQO#ii0FTlzb@5hY?_AQ8JX7LIH+*UD}HAdk1kUB0|^eA0ma*(-|q& zA~vFVzvCO}kfNj?k4#>Q8J|y94x)d)K@<)Q6*k+0RYikWN~@_hO2?N|^qg?a4gvQ- z*jMOhWXgA}NLjCqIKfi%odxt*aq9^jet|bl1_@*b=%@!t+(&fsp~l5P{9sRgdPyP6 z%lGRN+$hw|-;^i^MR3YqhkOL7_LT8My2Jf{!Escgj{?h zDF$qdmzU=5-A}t+AQy^&NB}15w;OvY%D2Uf(fQTAwsm=O1MNiwE($^z0{j-!U$U+sFs9R3hI zGOWTX5d=;cU8nZdhTu9a;BqHn&-GEJQKZ{D*Kd!jY{^@|Hs|j%xBfPwD0bEs-$N+H z+7gYe*R@D&XU=$*f>0u%8a^Kf5;#7uJIDEvrWk86 zm)FNwbMr)qHD!=XS1>HHnM#QD1Qw)Dnt@o5gR}6V8_I_=-V@^#5A|I1`_;uJJvS!= zISp5!^-GyRg9Mx>AF-~k@QMpPXp@yA#W5%gXAA}~BlFZftwZ7hP$!{g`V&o6)=Pf=h=sIVL(UMr#79SairJoG8xJ5w zMj{3mYtk@Yx*V!`E0^^8=ctY4xr0A;dAJ0jl?$(iW$hSaAY4%>H_Xwm~ z!bVec81hJC=B&i|a}>WvM0$+f4(AHBWfmjGIB8AL?zvjeE05J68+tH&Q<5>5LARA! zNiJbrqhh;vb%?TQJ>buvU7^Bg2X6^NN`MKaj69jb!!ZG~${i=l!7!*Yq?jtpkz>Vy z4)N+o=MVeZx5Bg+T(ZySrP94Kpw}G#mN1Zp1La6d*udv zL2}T&z4x}fO+=LPZvo-hoFMp(8%t{s<`15>p7l-R;7SNGWQohs zWdIb?idRT0uQGoAwdKZh3Xk;gZ>c8}UKbK$1LRr7x3n&=uh?t%cYB>u^BoJD5V5P)QkNa(;0LUYycZJ#%nsx2z_S{Gw%c3$0!dkYb-YUSrM< z{XVLMv;p4b&JIaHF|{% z&Db|;f^B7JIWeh9@8Nz?lk{0y!zjHZ*K9iEDzbRGmKCeGPyB&z#-XAcQ(~wSbAhxO zl35^!pn%1C?44%g8MGq@?AV~`Fk7=gqsrZ@-cG^yW-CNZTmBZ6z`z$a*A(=5hJ~V9 z@c5|PvywI~c!ctE?~}Fjv7{PA7YZ8JgU6WZhK#`r@!Ht!r2SQ}`^!FJBiYcz&Tcle zVieK-dz)>BlI#JO7y)3ox@FOE{tdxIvr{>vpCUfM;6!ZdDNwEc7+^Ibriq&`u6%-L zo*yH6q_|3rm&lHlp^6uJAn@j^%As5u`V_X#a2Q6?hGWF^co-LJP4UkexX_!ZQnGZP zbCff(N@_qW$K;!dTVw1le+kR9_l z=*!1E2zu#wP7hdKKIVa|E5|%-_R8^$K794qoXdLcSWfhrW2m*)G>ArK$X$HafWuc- zE6YLLX}&@!MtzLsb0_yyairNrL{#?Km<+8LyBk@898?p-+hC!mVmV>3Zi9i?i9Y1e z7i$jX<6_<=q-D7BFHy#`I3m>5Kj8<)uNSqA){%Ci)`mjVUqy|^@)%wXOK5?OP#pnc zpb_?)20R6pYo&IfJ-OU1hQId4 z*_h=fR*~2A0?lq4!Oyn|+QjTujaZX~GG6Wf4mJGh%R-5eYq2+RIiWNuYELEWocNmJ zYAC#t!hC1$6dT}c4N4q9&b%%LB_lHqLdz;ARfTy0ZDToVP*X%w$4(7Xr);N-(R&5~ z;uK0`l@FM8`HN(7AR#<4He*cjOkM=m95VAD1~kYQospttS?VF;Lf3L^GqAe}DjCK} zD~4a)m~mz?rE_xFI_6Fn;z*5x0|5FhH#p;2F*-pbONm^)U&i_r2P3%Cu4q4&%D4bD zyMxbIgv;eoaVm`ssf|WV5Q5$_Z*|tHGov%Vx|4 ze}wYkvZ3}+COu(s2B`l!Y9lb|k*kWTVs4es1fT)(hrHB@3G+rN?q@7_fr%i0wllzR zF{y}VVFvepb#OQENMLlE{Ur=Du-k=Z=1F5!Il?TOcHE-3&U~P zNE~#hI4My!#uSS($766J(`K@Jh1y;elwOgNkT5nW*f5UBj!l2quA`OS9_iOgFSj*Q<4ckp{Y8GErm^DHiuHieu zLE3&m-c|9=Q<%uK0B-R*8uEw9(XT-&+&{|fzO?@v_kjHw_y}AP<01%nt+C0evRlbo z2@qOb=8?tRyi`TvRidZIl;i?D`h_sz-#&*yqQ-p|?BKQ7cTk16O#Q}xJf?S(^x%VMZ; zx?&mbnfO4Jk;g7qi}c(U&5lvS&J}MlBq%B#Xa+|G9dhoY1blLL#--my{rskBttn|2uDRpXunLb-`hXj|$0U!ys26Pufg!VdxN&f5tm|eD&XC!r@w;Ph2n}az zGpoZaTED=_l+f{&k&Nu)U*Wt_xpfJGR{{6oaAhj8KErvP#4fg5*fF;UJfcKb?p zg8z-f$3K;DU3P*YZd`&DDtqG+kwI@BNCz|q5a z80RLzsySVs>sFKOIKel$!RFHMVPaUw7XEmE%0kj}hlQNP1yoAMiAmud=gx^3=XmgY zKRo{|p8Kx4fN^THX&=Ijwj7z)jqK59Y}lgCG0c}7-&R6QUIRus~0AleOQiWGs^m?C2n zx!6f>U~qt%$z#~SMFXq*a67}GohH=MA`{(k&F2DLv!Zjj)b-?TRal7>15B!c6gao9 zg|1uW5c2O)PttLC|0-<_Uo$RT}NQj_2uds=c@MCxA6(_jc6_My$peB%DEjui$-jAJ`wFuY`a62H+1aV11P2s@Q_? zL?)t$*$Erx%`(boSrr=F164I_RQF)Ak2z7qT;TwbmtE+5*iX8X$N`V zaW%wkXv=AnZXd+BiA%)DRg+a%Q44A~0}@!whTHW+GPSJt`FXhzx5P9hGL7Xvp#e>( z@^j1w3-!m($*5->fxZfI#vqw2gJP5}petVg>@cy#xQ8kP{_g95o1f z{v4NdWWI+R9&k;t{6&Ugu-5bZxIlqT-{LOf%3E>^eY*g^H{x%SB7a?6AgcNzOiBD% zSdi_bCtGk4NtimgCZqingE2o!W`9bDtL1bb0HGVU>D{}Q6$(SkDfEfWqh6aAM>gj(Y*V_SWaAIww$Nr} z*RIhu&v2G1dyqF2F>9=|V5h?KgN>Yw2OBw=_#Zy2dPMQ z#VGRD8+*tc#T@6B+XkDXzDZLjBd|b?O@%b&Lqd0{lI4dwiY&%e^0vVQ!@FEm7D!F| z;vqG1i8t>%W-?TS^&lbIn<gC8FE~%dNI9#lSdC-jP3fmYZpz<%H!3rn;1s(x!!C`3DUfV84jjzUSwbEpOqoy_(Mo$_0etd?!uiUQPE>H)%2<<&IdBYnw$&X)G6cobA?r^ zwwV*g!ng(zjyHP_=ijtWh;gs@HK0hZ*OjBcA%fJ0-ZXioa$1YDDvl|Sz*l0Ilx%%w zGuUqR9=FY*dG5V%3Nqd+-D=VuOd!qkD!|Gf{&*6S#($Gdj9i$gch4Yjs%70W!c3DHWF{-%p?s| z;29iD)rfM#c%;HX7?r$!dw1OfZJg&JCo`osZeg$YFf<_Yc(gpyB$JX1;dQ{?G{A8? zK7D6y@^9O7t28C+vnWSHt(`)+KBijH1#U$k5gcMMLzw)U#&gwa4-E&B(_3nQE_&&x z91x;TnT?(_61d50nHx*Z=w-G!QO8lBQ10Mp5;UYrgAEv{RZC){yQT;bF?%SBa%f=V z8UjGFeb`wG5&bQ?Zk;8wn!`U8rfEe$joFuYShtXEzDDb z9Kz)2wuWZaplW9oUR)1x%2F~;i7rU2k9G$P%&cJ;)p~W>&djP&;0?GDSX_q_IE;*E zg*Izxcp;-}tY1IDd@gQD1`5cP+r2h!#4IlTTRg4G(D$Ob%V}T=>s%(`HQoUfD^+i@ zK*I%_7d8CGUc$Jvd~bedbz2UXvwf4(!kTTaL^pcA($Fq$=`26!^iNv{#po%$r#2cH+&QS?63Qk4@RFDfTmvB8vmZE1| zHIHyT2m?K$-Vz|_Xh4^@*oB(CszO3W#$83>JA@mAnjGBN4Y;}n5|MEY#ccxCW^Ipx zS@lTZ_S8I$X6)F*hTUKS!;r}si}}bF{Q8RXKF8|7iQI`TSyz9)AXv5>7DVT?YS424 zZMkTn5G_*a6a?_67&DrxcN~SNVT?XQ`;L+{j6zYCjgXZZ!y@`u&)VAQ;X{W1T*jbM z$-~xjyOPLEhbRfk{txlTV<;CwFqBAG@e{QU+j0a#$#i88=YDaFx^mZF+F!Cx$*jkg!5e=-ij?m}nI3`+F%wTU#&B1&xc~zq zIS<#gIYH0l*iW`HgqRjDktLr`UKAJHjvj7(9QXt^GBs|}a{jWhY#Z$qG1uT!uaH~4 zT8t#EB8;MV>Ep9?C*%-xr#o-l8#kM3ZN!&6C>6_rBEOClaXlu0E7+$pxFhLRk7G?+@w8` z8=8e;f0>4AvVaiX{gQ69{AoE>khke8@;yNSa{Xci)Tz%66S@0y?!zVz27pdJkugjw zV2xEeC)y@Z9Tph5rXquN*bogw9zWd?jmq}Km>+6g!*|e!BT2Fx z6(ZHpAIiA0mbu|4){SriHE4ka5LtugD$ye)A(1CyCnnCANzR2D6Rt6)jLV+>2WSRp z_@Cg92bf6f+%zL0;{MA0Wpi*$m`pfF3~apK+iBRQ2E~&?q+P?CT(HZKQfx+z{) zIYEKqvL`;OPTaVL^TK;zs}AFYYNYnmB0aolfn~Lc6h`YclFY`TaU}JU1YLTu+$`d# z5zsXLs1&uNR0%X-h?(snVTx!xLli;*xu^ zFiDagMkn)ma2Vl>PuhCbDmHAQIc1W7BZ&mWNl*d`o(BR@@RU55R76@VE{gc0?9T}Z z*JJ4?s4K#c9QzrzCyKH`Pj2UmJ5y;SnU=^tpPyw~axyvUO*Tg>_{h8nzgJZR&n<2$ zDT*kb4a$@?CWpkr34IEGxR2dfH26BBfuPkbg5Gd#pJdds*1%n*XRVue%UVRW?OEPQ zw7-;{OB@1JPrB9`EtsDrS2EeFzv2g=LJ!p07{L&(wBQhj3O^W>$ssqyR=LqS!Z~-p zQwD;G=L(!eji@BR=BATspH_+^d1)x`J(R*OwSzy&F6ELZ;gwg6%qkN%e0hPV6btho zcvF9R1kv1!^#T`Vfn}LZF7_^RB)WBDXG8!^)5@k)G{mxkiYy38I@QQ*)4x!e_fE1- z5PkFlaUTS-9@w9muAVpL+u_ffTA$%_A3GJ3ZYZmes~O2DAMKS|BXmnOhd2KV)b=`0? zBv3{q#$mf_NKK>&MxvaLpF1fcek_`W?zOBWsZ#Kl9Pfu9Rck$oD~bHTQbYDZmu%3- zN0@=#%%u~R8^A6c!-15J<}Z#F+hKYm+zXhPapayrl|(h08;pKo4wQ{tf`XLBhG1)g zVr1#n?LHu_7ux1ihsJP*dBLvyEoLHy8U>os$xE>Q$RR5YP6oK$jWCSq$mr8f%xehr zsxbgoY4RRc6j+rhPcu6eF!9KNsX)ux%@{GT^vv#e*e2f*A?V+rBAO&>g>2CtlptC~ z>YhD!Aicf79z)#JJ!baKqcnim)ab$$2aGcCTZ@^*jz!+Bq1kNBT4WPq29)XzhkD)x>;f7%y zF#@J0XLqg=$K?IpLSaG@x_dwZ%iUfgtM&s7H$nn$Kom{N$Rn{+!%g)0;oKxKVqhAL z{al|Y12+Sc(Ub@Uqm|6HrB0r1+ zW}=F47pE6fe_08^nH_~HDhT1JBE*9l1F$qvWz$uhQm?CF)iH@VR{gb_*7K8#iG`Fj z>?CsrnaEr|47zDRLnl6)0x`0QeIpb4wsWgm9 z>0Fx(7Lh0{&MrfMe}#5Dgvkf2*)y+!WP*-pj?H3<43wCXiU30m*~`cSK=CUM8fSB1 zN1=j^>x_@cNdj!tohQIYa? ze8zC2b+Ws!=JYDj2xnFXaf_`b%0eQk43n?NOS<@GSKdnh!Px;qtS|Nw9-KIzzHt^4 z>Ya~~ZL{5D4Us9y@|3E?^D=*MAdNY*M(BG<+ZF2xopxvHkw_5qxPEl-Z1J?$Lr@cY zjytBLiKr0fO0Zd(MEI;bg#heP3KfpuAX-=8AmlH&lg_fZLOI=&mf#Z8%c3)r=bO$p znC$u|3*FBdLH$0+?=sOuu5ri02{XO&VbqSCaS5dKsze2LA~!Q}p~4WXSS=G#ijPuW ziAT;tn6wM;|0Vjl%xmiA*FIXC=XGRzoC7r( zIcFfN7Z3wp`n|nb!mC01^XHb(1~LLZY4=V#h-f~i3YK2Yw!QpwJp=~P5VeU+=_ClJdRwGnK7I4kw${{n+R;!UARjYA}8}T=^R;y8n z#+;&f{Aww36H|)v56+eFHp*%_kz`pgI_aA!N7F=gw4wl-${r6h)d|E*b%JgrvG!(a z6PB6Ugy6{1>G1(WWsMU&Q=1^o)FvQDoHCuMXJGhl8~OjxK63xz#_9|VCH%44fh2$* zF{CH_Zo_0HuJ$#NN4*Kby@=st>gMrpLJ-i@WxBcC$OQ)rJIF1Y4J6Y^9*7eHMAM10 zS!b#nSXOQpsTQ52y&M?n;~Fw$^4K^@D2@aoT&89o5hn!^%|1>Yse1%*rJn)Wq~IcY zsa)=q=`2s;lS1RB0hbLjQ(Z{C%8v+3+dqcPK*h{JrwkmeAmr1kR(qPt!*fdDX&Z=- z)-rEWytTsHX|Tk)XQu{8tAs zod@A`1VV1ftDT3v7V;*!s!TvB1C5fkcZ&3fgsH=16k#C9*WZjifm)~=t-y7 zJ>u15%oBO^I6IF#IA;tv*^cU1)oIM+;W%U9C{>a65b96{=V$Wpn=$ZXWgokf={pa? znE-?}jC4i-M^s@SiZIT^k?AN;*)u}fsZ>|3J}abM!PZ%VZe;U*lk_l4IKG5Z-GhUN z*p4zloXrDqR)J{hN$RoF<6QMT5N8F5iBU2$wLAvS3IJ#93h9w!BOE%UBa;{EzA*YBRfY;v@u5*W~vfqs9L>mFw=V; z^X3HeToVnO(%n4n-4)z(4b*emy9NP$KvmPmbT^NScLf)H6N9#&(!soR|H z=8^KQAf>O~usz+)qa}jDb?JJ>Y6G~{Z!zOzdEPiaCd|>$TT39x+-0bt9Ikz z+SEi1MCJ4_w2Y&@&GrG5h&@9Yx!r4A?qkc1L!g;GjGvoL4NT=EgV~|r=8do9$+c4h zR#A7H%5ZOEk*W2%kGY{|wu5m|gEEs6m4`>6Xz%k!vGn%Bz{SPT2lEhy0JyU{k8rwK zjD)e@PfnOi`d1SJly~CL!>xH1^hCrEq0Vp7R*|?tDh4cV%~&!fQ6se9z?Mkc2PUvI zzdgS&zqP!yvgyvt*BCg&#^bTiv6rC?Y~DXanznI|u@B)TB!3Ve0v(4*Z!r%+mxC{G z)c{b2V#33cNxt!~@J1RE+ie2Rz#?S>cgR~V8C&CQ0#N5(0_=QZMegnowm0Y3wpQo2 z*Eb)$yScuzQJhCzx=YRj%Wf3s#*1tDaxYC3*NXF#_+U))%2H6B=;o_OuYIix<5Q?R zij3UX5Ir%8yc)32zKk^3^5xPvI!1^o9v0u8n8o++OpNKzH^=W5Z_q&Y-SKIC^1X=} z6!^YW`L#(l2y@o*+SbbY+Jg_4Hy02tp#NQTb4m&X!#d`aMvpnWi^t>I!OGV1@9r$G zEiMuj^x9P`*!qRzY3XB1TfZn>zI=Qa4=+i_myhT4)fJ53 zTJg#;0r2Xv!0NSQPWJU<%=Qhg)BP!&F|<>>Lb}*P`>)Dsu55vOE-!+@Ke9v0O}kRa55uA<+og&6nJU+(OpO~;#KIp;5hH(diVWiB6lldH5G#H- zMcjXDiU4?fiY@-LDYQjU{uT}e$d_BwB$?aO%1DZP%k$eio6C~4hkWT<4&e5UpC`dB zZ3x8K>P3b41jlp9O_c-_<{Cqgmg(&k0)|xiDre3)zBa+(yl$D-RWdKO{Dx&--;zaw zH?;jDChN!Q5d^QY8tAup4K-1p)!5usRJ#U=6#P=^eTzdg7Dc_2-1=3)HUU5Ls@?nT z60QAq>E3>4!Z6P_g?WBgckI2YZ))&b zVVWRyUm(P>mLMk)UZuI02?Wp~DQa{1U2IR3TLR2*gR~=($}%Vtr5_YnQTS7q8oS)$ z=E}zQgN2pV)rIx>%_U^~(*Iub(Tc*OdQB=tOJFF>W|0ZA{#lLG9$@gsi@1t|Fh+h-5q0|Up z(WBPs!O6}Fb@k$0aw*445YkvGj;b!s;fRoZMGc$xcu>AYcy&jQ^19clC-xl5F$Hy4 zAP`k?t&M0L?)CiU#(T@F8>=g8?^7A_+2F)t-1y%c>VRnb~QGGoAY4jYP9k>92>l2exx2I=j z=fby@l!lN3?07V4T+-6vVm)5&u0b&Ny&2%*eiv!vi*xgvuI9?x);5yUtuBACyjq-N zl5bn*e(UJ;QET_)w1;Sr2uNZYGmzL=S=w$RSPk2Vj(hqiH*Vax{hRvVPk)F1xh6N; z54+tHgwA87&+*WX?aP>AWh063z#SN&-ikOQCi*MRc|39NHOX*s&I8)H>Tv;0f*qC6 zl5;NJ#*QdNKt%Ky05XYjt^^`*42mLyN3Ou6D-cfF)Pc6FLC)v8hqwaT)(4W#?`*%f zzPa+xmzNfo?rm%?-&^^4fQ2Xk{&s(PZF?(yy0#7fdc1041M;YC7oNNf`bylu8sz4U zdFa09JU*Z|y|ywgx`ojtPd?h(UcOIG4x+(1Ax}1FVrLUXcW-@ufyzsSRcdiGoIwii zY(NcPX7RYB7;*ee*47~luiX1687${;fBgdtE}DbMK)V8gTt`M;IAV6=MXW?|?u)xi zW8-sUOLuS2FE7sDo|<2tx;-~NJAHe8esOVj_U`h;(!|`CTqmi!bNsm1+C#9n)Sa7M zoF1P>-MOi$soPUybBnj{-kV;!J-;-$e0O^K-t5@jC12M?u`DbD*se)X)%(kskbAH? zzq7XZo;k!z<=A$vFYLnj=hfgk!jK8~9|W%+7|MVOZyOBW+5|zlisoIuqKS~r)zeo& zH3tEN?nH4s;VgkTkgPVK2*&GX2932`S`jR+D%}2EBC%nUr@(vBZe!T}^(Gi@ra!>S zUZ$vpO!5@{DICASt&Q@r2-@5=Wj~~de9eSXQA&P;W1x^M<*h&yX+HKL^*H<8jc%ey zG|6UdFSHEg4JPb5wv6P~MF=?>CdQU;PmE10Pc1Jk+?$x4{SvI< z8@`|bdLN9hpZ>kHBK`v{{!P;&51@=Z>9n6hm-@XngB`;kkkq*YN&(T#eeep4#g8h5 zX$FEX-j&qfVKJkGA*yuW6pWsPMWOwhur{{meuYKM;DTb&ld$OeLr&K8X@7(TmfFYd zBjgI+m0&`489fP$2C>;PRd-|{EM&vh6ddkXScLMuzLsy{E5vyOvvR+}B7E;cbB+v@F^GQsb#7@gGjVJ$=izbP0! ziHgb{d0WqL`06ma#al+KH|S;FhE1pntBKuBck!dJ@Yd<^F%EtNFpr*~D5yfoV&SxN zu&0pIuVFje?Y^NX`4+x{#*Prrhe$TBm4n}=*#858c0_dl*yQ>Erqz}5=3civ>YkLX z-QD)_NqMs0E^#vLP*TwI2jceINBwr$f@_)p54a!znS$=TxEO_||O2Mr5%q~Fvj-nlby z4!B4>vQI>#h;Ml_X;YpH8?!9|AW#dY^af9O7ujVZx8r;QxkZUM&19182EF9yH(M4&F~lH%z&BUB-OoTW!^{)NsyLve z)h_qIkUK}}`c^7S@GUzwV6rT`BO61H=HzWTh>Eg}0_lgCFtA;ZkCjL5r-sZMS4*$+ z_!>}N8v+hy$vvKuDT`h~@h4Baz0XQH6$rmi<1%SIVAk_fl{NuPYhb~-!2;jvcuuZ3 z5N|Ll>sWwvTgUBPgi@9*tXd2X@iTIN#%XPwtt^qt|8cwQK9UXmShvhZl+-?ek;}XW zPpVb=$m|;rdvI(*MCf8nc4_XErS3xpbbPxjXBAN>9bdeywp8Ni%RD=| zwgyNbyWM86*;WA!d~tKTwckB#EkNWLAN$h0vFtLUDY(Zev7N%YNizV>*_eDf4md(Ga#N)g`l-x19SRnq zQDUkz3eZDbT8Fr_niZGQ3g{q0@Sa*d*8?Mk0sV;V{DhM%s}FAR4A7k+R0tkWD}a zhw{0fxbZ#GD=f=nSgaGXM!q(%&Flmq>549tfiTwOZ2M%U4J=aQ_LHenD>7uta);40 zFM|<=%8)FsRd5h>byylO_C3Edgxub%Qf?Kquq3LubdSo`k#J*h59#3mX4Udx`=I+& zSf~V$mizeCvYnPNu$`&5iV~tAso{Rr(PFRqI>-P9;?D%?FTk3jHoz;+hG}u_tT+}G z8MF;Xg~?d>04ix4F{~8^6BP!wO4_Pp~7~l6>PugYssC)W&KWH`R z%8n?*>MRZ1DRHuZn?2^i1M1}?cyeF^Mzpa^CeuB3y8Uif)p;{l*zx+Pr0l5=%N_&> z>iGxdUa#|{-4|oBva!Hy45sYNVOp*kBB1725I`z9a&uXXEK7(03c9_?-8tpcQ6Z2U zvT!IkcNG^%%8%g2C=a`kk@np3l@FgO&?qyU9vxwwi3NmT^E^P3UyM(Tefh;~{4X7t zMrh}hpcR$KV1Wtb!rJQGmggVBqf}c0v~p8rl-eSoke{@fzZQ-j_zfO+fhGGe|Nr#w z^V3>rfCb!Kd3*$fs4c>Msw#iFHKim_HN?BuL{`mEnCx<{M2#d#3^#|MpHp`ZTBw&C zgF--_8r<X$z#gyol0ZhdjImxK~s%n#e`Bd}h08)4}+mNi8HyKuVG!YJHAdGMt2 z1ZNX(l|YgfSb6XC2ogS2ML45doudkC4n_d1QOR!jB@b$2$?aa+?#MVkYq!zs(K8~B zBxSH82C6|UrC*$zCFRgwX{HS{vz9}knwJ*+BugHg(Mi%ri^^vIh6<@leArlrUGzGS z;deSH`zNSc9``zA<8=4N(n=F-oYV_NSo%Q|i^jxRuIh*eQ%C?V5o{y#ZuElQa|q}duZq*}x5Gl5iUp_|u7jIS>>DO4raYFFR@q_T`g z@c$!)qzaabf-Vav>IiPs7Tr)7{b0NT8>C|zp;iY(8q36 zfkHv{p2er=8)_2V7?U+ncgso_!vFgCn{m$+_gcrD< zAD?#i)D3g8-xIqIMKlCvh}}}9Sp1^ug7AqA6>y)nG9HIj4ZwVXRSjCe!qzNNPzXzW zHiKSJ7dQ}sCdHMYXe}}XWq=O`Hi#zyABYyO|U}RL7TuJ)eYuN$SY!5 z(%@IwT(Rgb>NN zZ$sqks#nk;9x0I3j&ibPLb}l9cY^&Dw_d9s9iv%>r$0$ z=2l2KkSjuD@V1SK&yGk5&V#TUUE*G}Dbg{7sa7IE}Spp{X(D>euk^y9tM8c3+AmEbdS?kV;|`hW@cL+5U}n+DSA6hJj^YWGpv_t|uMphs=m09TySH zfQulqLu>#MPpRl}Mx?<)U&xH|TP2QX9`N26wG2QGBleqXKk8PB@+a!8>l@H*Zmr?l)TducPM#dz&jNBWLc)P@3R6xU3S-su5+Vgyul)T}-0Sn` z8GnLec$BTaF5nj|xyH_7fc0cK2dGhXmAix31&@3}y6yp4;45etCZHr4^jV29`p~87 z#|5g~(lP?n+PQ-WnOXmMs76I1l#ZJl1?934xD(SQwZIaQ<%Ja>UH#`M_; z_PaokYzG~GDP(OQ5f_K~t%aBpJqS{ZV|Rf&a?5}PU~S`M;YZ58lvN;#L3gl$eE^lh z?M@T$<;eankSOlt5jfo6zSScz=Ogl9BYP2r67{o)JpjFs?zb%8_)lhR^X zO^GAmULNa8<~`bZ=bd-T)$U_B4ngX?HKR@5h@>_+P+NY?^sk?mD3cik?mi%D)4@gu zt_du%YBw3vof3KZctlC;w6xE-x7421U#i-=l(0TdT3mn>8GBcdxv^Q>NedEUJWuPC zK^RcUFQR$H>FA{cfN)R|(1JOtrzSot`dGbRtkzyD#~tGys&D{x#d9+&ABb&;eiAkCTmxA>HltBXzmq09thJv`P7VHE16O}T=>J4K<4*DC=M7@zCXoI8x zE|yS`PGLa%;A?TU&Gt>sxS^WS;GRo`im}PI1S+nvYzLFHg-OqY7SWake$?1WG7SSe zz6pg_bxvqPur4(-#Y#zV#hT$)iUNf3I^LvI!<)#{m8?{?MCf?$;^|GEgBVy5&>d99 zw*BEgqWU3*b{@?&5)((&7Pvhcws`-ZBnk-3AW3 zh%Wb@{yT3I29tARGk5QdP0o!^$^Qd0ecCaY0d`grkZWf2@D^^iHQJDj-_@s5&U?UiXwvCvSRal-&5>JMVttE0F@Rrrw79^Ic9SiM;SNi)wa zTC0&&2CiOyM{Xj7U}N`jx~c?7Oxz zpij^lPMfHiOie?>tQzvNT4jNd6k{9plxCA861|4CI8GWvnk;Te9vdKUJ)unlexcR0 z!CG$Z0a(aTqkoKe<~Cx8y_p@_Ch&o)s0zL~4S*gdxLH%0mB5~U7e{3d;!VKzBKTnK z2B*$k^R@RwM&s-g8j&W7wzIN>OTkKx7@O2iArq8v?%~Z7c6Newc6R;U{WeX)4rIiA z=zJ0Zpa|9T4l0JK8nUSkvjgCx+5t)2%m@L7#NqEqX4;=}D86R~X zpNh{!CxB$tWuG?>fqsVq(AO{?FqPQK2q(bsRz~`bpxBWk5<|^$X~SVH3bO`x7zuM->Z;eaY@f9&f$Z*@K^5w&tVm)3@Obj!_wKi|P=iaYpF0 zAB%KpF<@Pdc_?ZPXpxQ}lCsifu|d9_jCdL6rVb@woQJxw86M&c7j}^5@nPX(o79dy zVaLrUTFb@(Ve29S9UJ4RGu(4?a7QQ@d;SoyXFLS#(Y&!;Y*0b)F3m9z1jtY$RJ8%Z zuGxM(bYpuzgr)za^%;}8VGqJln?t0XI>{VD4%Y@N*fc_{T#a2cYy|5iU>@4W7FNa@ zMYC-h4%Q)Wc?}x`P|vbh!z~r|?lY{EY4dAbr;0Jkz-%BMNA@DZ4PlM6v34;#o(;?}@1{Y?$UZ#)81_gD7Z>gBe_T{DR+gWw~Py z3XG11gO!PCTntET#(*eAsHisJTEoE@>A|xY&uh z2&nL*-~eg;xmmL!U^Fn$9UGp;W3$1D(&*T1iXSy6Xx&Ia(z>L>pPzMgfufj&oMip` za(dRy4V0sBL0sqapPhBh3Fg1R$ywJBh=3gPn>#nF3YD|$LL!Ow-XSgINh|eql@>&Q zH7vsTw~64gg|sR@r?f5fTGN(cH?n`{8VfANxc}!IqS`tpl+X}l#HfPOp#6KyJ0fPf zMiVFQ5jwZbkUX$)$RP)<(<2-yf|9p~ATJmNYJ0$}?suQC4pqzga$r>VP(TI&lh@g8 zV7LVM94=be-5=Z+_*q?FjKs56()y^tN$?>TuIUVI*sW-_QtM?cK){AJP9GwVlMGa& z@EFhKnyH5osoYxiY&g=e@m!OXGkm{b&J6jpeu4TvfltGPWdWqId&6KJCN_-yA6H-J zMmI!E7w*cAER912b>Uv^;extw^>)>y8t$WCjF5KuHb-Hf{#xZgn0bZ8=gz;&+2tnf$%pJ%qc? z(^1H=#vvlXaY1@*Ah@w@(f3!e>4ve|Ps~Ll#yqY39ZVYn5Y;)crq)`8)G!dme%tmE zceEW2fJk{JOx0D}I++WNG%A@H+7yXgGD3OM* zg>V791VH#rz*VD(z-NHNDC}L&xIB3*KRXb; zwPCBXg&U{LE#TPFTa!gz@JI5N10C=aF-xza|)u*SOODNDl8{EM0zBh z-&!sy@kc}5(Od6;|Ko_i83e~Yir^&fOg42`vEn~(bC`odjjN*J`jm2rAH-b4Y*tPr zoe}u%L*xK_26GYU(q=-y*;P$jbcoc0CNgpt&dPnfZFl~a+3k4CI!2mfxclWXW z_dqD=0#owyZW<{GNa1#IoSiGb_+m>FELrNEOb;?xP+@naT^(Zys0i#vZVX^Zjyry9 zHWVC6j~qlN?cMz&-m#7l9=Xz}e2i1=$N53rN#Zl?D8SdLq(loO=kWZ{03TgOTDhNV z1mfMQ82~sr2N0%^C3gZt7T3cM0iz!p=R;)t*I?XgN>S^1r5g4EcHy)cAa;$pp;8ib z^u;HtK+b*n#q?Nwjs;fPN)0rAljGInIT2yyii0X@tSgn4fn+OcpI6o#a5plqik-L8 z0Py4H{LwR_C60@8qhz!kEF6}}mv6ZZR3heFBtmZFSnPEk>gEdHgu(f(k9Tm}^xFLW zaM7< zol-(V{MZX%eWs;)+|Lv~GuzCxF)YRgvmJ=FL0Mof6+Y1;ks!Gb2@gV`5ihwM5Rx?g zICCot?^EA;g;!<9?oe6eU%5%iv>cOi<{(Tt|A@?1ink7K>E39^A~ENYpy|~VZh_cM zhZ)|G^pW)frA#(6`wX^=&^`o`2Ma_*SMWt$29}m_Mxe$A_@4Jb@ib6p@X7LNAdTIJ zscZq<@%fivaMQqnChH2;KxW5wTtMo8Q?Jv2Y+!4R&AN3^ng$@9c{Q}K3^)ys@h@~> zk;eGipTnSVqSwCGoXDQRHuc;`=V!oN95ASd)ml(zz*)`=ff=BQZ(cN$`VN2yL&Q$c z2qpkq2_6@Q2r;MWIQ9%c8VvqL4*So9=rd%5>I|^Qf#GZk0%m|inKS=&D2KthdDfNz z!uZkH98a~SfgwXhkIw=@V%zx{j^@u2QIN5ai~0~Q??Lg>vp|*x8lMf3gze!-OCxsA zh6qv%3R!w@WP+)oDOJI2%rhKrCw5`0zGDR2*!--)%ZOswkgWb}%nLyju0bWvOal8J zws%|Lj3U#>Lv>%ny1+z|Fo>AOq5N|PW;~2dIB8my-PVMzV<~J0*x*D{w7VhpYq>p= zr&iJU!LvKCmTUmdye07o46uxK*Yp|dTXYfaB&~heMd=dRT+4ecbb~*L@1xD|UQXw!Mw758D{z6!r%r zH^?lOR!oz?L63Jp9xw3p+I@uKb5F`v#H#sTxCsr+YGSm(0Es3E zF9<*lV7Szr`AYtTe&OH$c`~!Is~VfSwn?UNC+)f?^t2Dr*= z6&K$dI>MGhCyn~u6;2HTI0NX=<3;Yg@E8{*&qT1j7oNUVc4Z(CH86PG9u1&i9q_eXIW7y0;8bt2n+WQ#v!-x$N~Dd#&>ji+*;;QHWHcajqqn7pv}8 zM5;77=*;lSOAqyDc9}8W+Rhg`1zbk*7w7;JM^*&N=UOhRw1K2Q>4xB4dK6Ofpf`QU zw4fai>KpyTPYDcZRz}t6%ArOD&mB)P6z$Ey8VeB24mz ziO}P_MTGs~;`*KnTXrT)VAQBj zP{%{Lx`TT?gx+Y=GRJqd25!-vv&uF9u<>JX zV*L&$j!Y>my@+0fV|=zLBgg4=@kLz^|MIg!|CDkZCiU75&gPx1Oqbp&6(aE(=E^3W zF-r)vcDEwqsK0=ncGzUmYKPqsdgg$@=){d!3sG)=ytoX|X%P!^Ri|pyyRb7N%gU`q!w*Jw8#lDy@ zxzF*e@d3UQv9PeeR8*m~SDO;kW{sC>TU46T0|z=Co$UVe$t%U(?pTTa2?c!W7VX%C z$%L9j_2c*A@6e?kosg*-47J6J4WKmN+A*fZUyW!$&O@f16LV=kxA(7O_T5+QDn!CN zo%5ECEe!=E>gyS&U^L(h46?mb?%%NYGx{ek&<{<0e>OdLLRlQZq|&PY!g5ftNpYWk zFm17q#zGhR$d|O^O&beY=w#7XYAjiyr+hlIb{BH=^74H8-wsGjdud{D4bYrC2+~Dh zD~Z_{DQkLn?NN7K0+~Y2_2ej=;xO0Dk_EaZ{4C7~#2Lc!rwW9LalVPW$5Vtw5-%rL z@6Z-NitCRt9*{RN6H9%o!@CA0CUs_}8EBqt-JDEpRucuNCiwxX8+b=Cwpmf`T7q_m zFrSMnmox}|n_~Y#Y%IMjfFm<7>#aefbYdlcTUYazpwhf_R z(M%eA#*1^?5SA_ab2CfLw6;iL6}h3bV}a3O8~os$$m4DqJDnIA%;~_0*{EGAMfTNp zygfI7Sub|0PBN%wDF-D{sh85r1&Usclar# ze~ml0RqRx0Oq%OL60kBn>tpHkyoltY|4IocC9wa|ma}8mZHjsVB({q4FF+Q>D0|o{-I}eyQM8=(jkzri}fwO)jVl51L$4Y!7|l z*#09}Iq;+gBR|{ZK4axtxFYx!qXKS|DYK6KQF}$y?254H|0Iw^7_LDQf%Hd87Al7C z+Aj;{;iq1p0ki8>d#@%F1?%+z0)5?Volh&MV}XHsV#EIx%ikEOhy+_CqNDeOQqc$t zUpuKJs91W$LKhp#MLri~Ww#c0E+U)Pk!h1w2>SHQ2kQT0v!9{TG{dWInW6BNl2`wJ zG!AR!YU@A#%kcyw_}#zkon5`Vmw9bOjb%HO?CS1ch(F5z9Nq4it#J!+2eIMeb=^9{ z`;|szmX8`09edHCps|k{>hz{HlB>50i>=rpTA{>7oEXv|;YEn$e>{5FYE6vMT;UEj zzdy>^)ZQD!S67l6E|=mwE93ba#R#dr?L6itna7_;&rRi%6IpI6Ukrgv=D}{~ z(kqd|@zYplx}~HilZ3z8**jtei!*{joZ=<2jZ$1wRA}jqly?rYvLnR{I(gC&rFbBa zp<*k@-sR62B`QhL#Q)l&*=%Bbp&u@8jY5}n$I=t&bWgA-dPwcr;K%!zWYXeW!D{~K z-l_zOaHkNGDX**}jXcqA$p3ZUQegi}g(R_H4TAAETmPjJX#7bmZOFghY_WhZt-MVk zw8+9ai)#kY8e*)Jj(00>us%eS2+IDO$z{n5qDXm3v zI|o@k=C=Jbe!Y7mgcJ1qsP5G_D+sI5u-BiMLJg?GZxETUw~9YV!mTNi5{^BfxVyw+ z?3HfY4*5ZkQlCI)X zA}LI}J{Sx%fvnzPd#7fT`8-rnG5`87^K3HPJ0K0EY%e}(AuW=8= z`P8M#pc&UR{D9y=z%c>JLMT{^(!=a$E$gX3HP?+f=PE!Z#S<^f1ko3ecivp$eAOq& zHGjEhyaWLCA~yaO>owZ^7HJ(O|EaFn;xWI}VFo4%T%6en6y~Xw>TdF4s03#WBLHL4 z?jy97UeS2yX&qgF`RmmN9^Jz?>Ker1)s zY`HoZcr|%CctAm*>N(iaC_mSrw#!vBu?1p1kPhuT4;!+>^n`aFl}hxB*-;GKM3THr z1(|Uu*o_dNs%MCJy#z^ZoD+P79aD-LLvVK_8rlU;psek#vvw&Zxlb)UuJ)e?^1liLoPjmyVI6R z`6WdCE;Z>PqjRu>tBn;vy^gWg%v09C=GG$sB?9%$Y;ww{26+G!v%G8eQ|a7O695^I=SN=V&9GcLEZ`nJ@ERom;oZF>xfCeF=z6aMJl&*%|MKZa@FFHAj3bjXbtAYDid# zf;9(wEaG_y%LNB}ET}~C%X#4QNBs8_7LG#HwZY3{-_f+RF8)&+>E~xW$03$ko^E@& z$3n||^dqB|e71)C`N>Ob$j8!`?U4HzA+Eq$@nblf+wm%+oyvr6T=^H;iE3SEag_a(R zdk>%N64cmccmJUZ=nP&gQpTI1Ugorkh`6z|V*h%-NQl=$61wj=8l=^fmw&cx2g^Qh z#J?0#2jS`ao#DxFYdGHB86DSys*6tm3IT2U!>XoeKTZUXQr&a=>f~%n)c*10U!hgw z?N{4}dxyue)5|S-No4qKIObN7?1La@9-Ckk0QjG^uX zYYuog_R&JY5XEJCX~p2ceQf_w;_cn>IKC9FK!v_C*Duun@o?W?;Oqkh{iyl#w$E3e z-Ftxs!-4Bw$+Vf7Y*;D`Q34S0*#5IE@>u7QvZcqe<5^;6#k?f_l_ylSL2m0nu&NEB z&@;DpH(x9>r-G?e$o^<7GB8GkPdA^43tX|mgjMAeYFZD#2A1dc%Bz=W-0F@6SgCdA z0T<(gSEGY(hkK(P2SJoe1fTxZ{fE~|u~6!}$3N7b1uUYXM%h=XO`_(;RQj;PNrOP- zk_PSSpy=xlXHL>ZeW(U?A@Tcg@APDJcn~H`DvOnMxut%N#khPfR<_FUQ3pZ91iBL83-$(jnK_>99125+FJ@5NIoK{h^IKl;%IpAot?)&@T8 zC#BlQs_y-p>zhy0i+AtuIPv+T#falnSD{Q%2WZk)tg@qlJ5XeR69Dx?Wp2o1C zbbSZn??o9Z{umZf1iU1!G@1eLMTw=+OfcG^4m4Vdn{{gfjm9#%hE1&3|hJ}%BBxoAgI#krMhVHeen45gaFb~y%?C*q> z^*7KVzRPl54|ae1YJ74GnPVU_0nhti>u|s8EA<^!%E9L5;KeFQ-l&w-1B~(h?(XK- zfA@DEKYo0!@?B;uI=er=xPHz#fPZIQY_6=nc)qgsVsmL_u!@LN>jG?iKo=Wp8|_(u zl2ZLDTh&nG_fIBgAM){+!hiMgL9G0p`+raV$@#ngdPCVX!ZCfZZ=VwmX!QdI;a!%N zSL@w?VvE1V(#p!(`YHt_Ybycz9q;drS;Bnb*H=~t>o2G_U26*thPK&j@1MPyUiVd| z;Ow3<1?s6E%yqRM*ES2IgR5x)v(~H2gU!{A0X52N;|p2alU-e2TOX{k%#Fst6^*Gk z^x=aNsM>Q{U0&bVY{SOSgz^V@*b+7Y@O~Vo%(0~6c zw;{v!oE-K%gktyVhl}a;m1^ORIm`>Or}w1CIkDpnPL_Hy8hhhcd&BPzPfxJkvLvyC z>Lfa(nRlaeDUR`BazWY;@2-=(u>0-q!O5%r;n5M4wYN_(d<*H(gHL+fD^{>-jcD2J z!-JFK!@XYA+e3qOz3}!rxD*<^`uh0r^r*Kpd3$z$dDnaLKlip*2W;*3+6%UdD?7lI zh235gdU6HtxI(140@Yk4y{s+SQ`%rY+f&jzx0hb1nze4yAGoO*H?`xYhTOcR$_De7 z%KPf3A-M7Qlitp{jlN86&p2~iiXLHw9v~K%Ku3CQFL6d(Y{z|PWQunCo2R~Pmaee^ z&W0AfQSS-M2~=wA?KK@}wml$sG5&5=BQ;sl)YW8#H`!U|V8ETdudyE-yAuszFo*9q6 zJ{X>y9`B}S#)D;!v>X5C@c3l=^aRcP_$1$Pt$>>Fs^g^>975(?dz|jp@!q<&alE{_ z@*;JGJ@IP{eEYixr)lN}hcp|oEIhN(W2WC6?H=!s#$(w!BA|uY)_+Y?-e0G%-9C2S zVG}<8ytlvff=Vk-bOTFt+q4@;3hFQ3!)~CT{u*c_kJbf5!@&~u62Y9K;mL366WJat zsnX1lN^}Xm{m8VSX$ZK4)!VA$IYJiH~Z(n z$37k({vW&B(6z%8$o6n&bhveTa&mYOyISn4Cx6;IUKgR{%BzD?y!7!B-VME7ZHyC^ zZlibd-O=veXsZc|whJ_1QN|l2kdAl%=@gXT#c>b`&iV_0@=0&VaS7Z;>#!fFBUB}B zXwX9Waa+t!l*CE&DtHzfZB3DH;4N|I*Nxz=LkT)|{x2ZnMw(Zx<*EWp`9?dxYA^-! zx6j)7Rn?Fbfz>i>FSF~hS0}JL*Iw2pfZdAe`b)?Tu^IPy^wowQFq!a753>te%9{wv z5W%Or>wt?HbL+V2_T9)qN8{t&{ljl}IYjg2XfFZL!@g#@*>wQBvE5EEjPCSY-qHmB zq-W&liPNJvkuAyny(f^Uy~D2~0M7dB$^RnEVNl1Poi&ve<_eZ^WpB8$A3JM0w3I7L z!j*m6SrdEWYR|5NdpqbWcC}~4QTfK670=vR(~ff0v$m^T^^~zt=Q~{W)Vf&o&bnN+ zJ8)V(##^cFQebQ~bl5>4YO}Kz!!zo|j0A5>OOUAuDQyD9&w@H`B01cQN-l|9>#xuQ z6VhLTS#APa6px(Pk>46Hf?hODf( z^GC~@kj$ggt-aCsH!{5*9!Mr@yqr-7TJk1C*kGWPRzfaGY~m>FWSd5cfi6K%j=vo_ zJ&`OoV}voRZ7z#n5*Urf30))5F7}l%of0Inh) z#NQ(Yg$&!iIE`Hamtu>Y5UUEjL^@-z13)7-f@f($2_LD7D--34dc zySt6$BK2uW)h=!7@F$IHTw)o>3FE$ULcDu*UYB%TLPrvh^UGgCC5y#PB(CqEKQE5A zqC(>hC{=->Ei-d5G~rU>XyZ*pizIhupMsE=eu@zH^aOcp4qtVFjJF7j8$_yIJ6k$z zK})tc0n%1y@@ogh(RhD6s?qaBzTt)81kjxZ+c;jv_K^TP(T*p-0HoJc+*mhAl5VW+ z@v_7MyRkRy5%vwyt<{wZpk2E>xc=CC@@F(KZE4w*rDfBVmJK$Sjd((2!d8oFuD~)P zJOHm&yD9>#bu-`^8@%)!l&`1P_cyVTj=x6ZOJV?;?(N++L3lyMKJ3tLfMAk)K%BF-A00lt4O5 zM0sghT-f!@I9Bkb$qSbY?LwZ>I%gt}XqYxOfVI9$5bf;K`9CYBK(pKv{NyRCW?V)L z)awq zW;F&f4Y5^q23a&Ma@eq@n!RQk1hIK(yR>eij*-T$nchEO@!}%0UAfR_fCeta-@{1X zkMB9S8Fq6ox^ojtP>D`o?v& zqc1cLO|e|jbhu<_J>ahh+!>i$gXjX@u$S;-z#nHq5e>C(Xu^p)ijgU z%r@8}KTe=B>)=abZg1afg-!3@mat>EWPE;5*)V&NXeNFMbu!kJ_99Wc*u>cg=Cs|t zmlB`@)X)Edg&S{3W^63nOI&cv#(A(+20O5^xb49UtPrRS7|gbRQw=oh&o)sSBKjl& zIT_V5gZG~>Evyc0IT_^$KnHP(*ubmt2q>G@*vJg*0 z)A(v2Db|fA5I?l32p01}iRK3Vn<6{8nYC^iMcZ56lpLs=!LL4uzHNYd1r&yo26_c- zrB{53A#Z(-pa6|>>K)8eOH07jco(~`Y+1b+pKMZzNeO7js0e}(>|o4oxP*2!+}R%; zyxRTe-88obF8_r9N-wk_xn#T{!G^0*B{>NA%rv+{wz)zD0X?_HE@5vBQ1M%xa@*}l z0oB`}vAvpEMT79RclLU68JW3T30Up8jb-c}u)>hO%q;8e+VZJ+JlH9%W6RFByc9SK zDq-3v-ndBde`Q3$Y%;WkG;0cLnZ2(r*19$;+go4w0-d zxff0HuI3NvEWinKSG=-zo6^=-cgf5wDWIha0?`N}jn~Ie&5=>HAV@a|0RBFAB#iiW z+p2Qrp-{GL`2E>0-cRC3To24#gGg{Jz)3mpM4n#!n}umP#nJjgakxV3Hl;cP8-R5~ z1z^fpKI&6$%H3!Wpqgx42_AY|3SqXXEsG6nj;;zpA}bk17L~HMMj;r6phY^1(xJ|W z@<|F@<=HuA_>x>(nQ~qT=MSN8FWf>jOCH^nGV^kWQUy%67oyR9997YPT!mu29E;!7zcFChB2@++F0vm zQd@bEFs65)CBXw4=3*YuC1w`q!hMc}B>@@QiZv}h(?wflh(j~0EM9=LPP&N1+?0oP zxGOM>FY&~@s=1_6eP6M1j4hb30y`$5$ivx7~Znex4tl`FSrKeZU};u(KV4>9cOFxQJkzvnuV;v?v1RW z!9dnvfDN+d zM`w`xGueIPb~(7VInhdHaSPwOx*oo@@=T66Vg%Ua4Y(V~!t_~+xC2fw+cJQ>USmuWi*R?E z8F$Bq6#+H#Q1j|eSAdd4Rv-Z{;@oA+{B&|1%N}q2XLMU9f6~V=hw88un~|e@{e+S4Nc%6`(#4z?V4JJRz)yQrC9~a_$6AjRd75G z$nG;}8ovWk_@ydR<4%8tCTq_@C*G93cdPC)4xc)Vwy24@28c0@?Rp1rCP@@-fgq;J z)Sk@T+8};XBORIJNDT?^KS|DYY1pEf`AgD@ZiduY8~rc9Utfw0as%shGbvhHsQ$9B z7jFKz1-|f?KW?Ef{N)r#J~}<%xXbwb4JxlM%w2B;`?@z)@ZKq^W-5BQ6r{{-c7bEcm#IGI;6i)mdZHLg0SY^J@| z21;>)@hZ?lh$A1u5mOyVitY4m+p93i7d;|eVw7L@G5DU^E>-Ne3D<)CwuzG=EHg7@ z=B~YMf9?dp|zHg;Jc*h z#{{O9)@7!`5*xwf&-~q!nj8YX={dO!1cxgY`1#}y$VE6PaDT8PK!B7Ef(`V-yWAiM z{KX=QpvwiX8wBBy8(XKFskCcyR0femH+l(*1lA0N(6~EzmV<&wlg-}g5$gC(Bjz)F z8IezYVHhexD+}*1V{Z0h2Y3O&_PWVaDzY)FE zZZJlcF(5&HPS93uT5OA+1ri1~H9RJ5RxgiCs7T9;WVhsnStuM8v!b+JAH);{5lKi= z!ltlFQV4?AA<81y8;&mTlQPTr1!We$TZvmIvpDFi%_CZK9#${O;K~XYP4ZD^N3nNa zqAi62Y!*a-Bq&&LB?1dvO!Tok$_SDJz(BZz47>`!1$1k2yx?VPqHT*`$iJWfrtZLz-!#@pYxcimaL5-dWCUQh)s>`#$}x~=X&5X+8@Itl zQ2rPf)NBm5*vReGwn-`IS0Vu5R&)YYs3nln(eIH_h|x%uDEZlvF`D1SrZ+JN7M5TT z*GtM#)P3R6MWPbhLU?HFZt0Q%Zqe`P#Eg4Qp$$(}!V;pa@-mW6-;GZOB+d*{O_Xz& z)e=H?8}QoS1e8NJKnuyaHUSNB?52paCcl`3@KQd^={R{BC8R6fwbV>PrIKdWH5op5SS(sv zkrhOd5yiqFP^$#`;MJ-xPpM9r1CJZMJ^Up;Gk>XwmO*5&aJv?LXno-XLm_;c8!BcP zrydUANH3>df{_l3jYY{Qv2f7k3Y52XdU2zQN@4E?0x^79cr3RqY24`)VLcUzQt$`7 zp-n7YSDPhjSwPBY+_HQv_7z)4ww~>G%}yc9!q(wG=Z1#vKW#f}k8iJZ8?}N5tWy_s z7nlV*C$=Nn)QWwi2@_XXv>~VmP$L!+d{dy97>|NVh-j11SJ+jlb!aRXqhuFBw?~^V zl&0rgO%X^Pgwc|baE~Q`>$!W(Ig+`@f>>vvbc4#Q7lN~tL|~*jBqh2#fB@S{{;Rte zL?DnTn&{c0UJA2<3MWPxFrgOcm-HAnpQv6#M69~I-eU4zf>$qc`rqKDP!h%*jmxR~ z5B;9)vN8csuo_4nu^Ef96yF`_Q?;0c!qlY&fG9`{PBC+n`uOnW2_@NfBRw_vbh0Z4 z90u$KOFCH6ZlP?$VqdWoRt}=M6f)gZ2?`=EWo?gUGA@{Cl)QE+j~NIwflABZAwk;z8RixOG?F5tbhfsBJAdg;3~kC z*Fsl4yDIBESFu*hbHc!E&zd86Rn}S5Dr+wX4xg>P`>QL;1|XC#va+bMN5l}%Izp-w17Z!5h)VQB};=;$vDWY zzuJsNrpTob06Is;HO7cRm?xHlEcsLHO`UqFZ4 z#(;-=kFkZW%W$h3Sj|mQ2ZS3bgiAMip{2yNAu$mArceofn{63|14ja?Fr+%AVF?4J zk%&@5tvo2xZKzg;pjOeKPHm&I-6(eeSptW5$jo5xPmXshFCyFaa$Qjk@{FaQ~v!=dnh-&eT zjVr3fXM5IM&Ppuc8@H9q`p;*3R~*N~>|pk*<1nQ|bnM*fKN_DiZ7l3Rg&qurM0=z&kj@e}FS+UAgjpTp5Qe z<8Wn;T$v+R=E#+`;mRDjGDqZ6dsgcTJX;i?yF4P1>loIE9ljBbwwxJdgORtDVQS-M zhS<7TWFZ3hSS!Sdu@I4GL>Ft5`?ObVU@Mlz8+LFHiI7;iS-Xx`{L|icNNBb7QfeP6 zr`Ag=C5VQ9R$R_QZ=$@46V8^DFb|f94M)_XDAKn>>H%-zp{)}ke%FSiiYVKIz!XVBDKC-+Oit0)3cCgx!O8+N+6W>&aGqF^`G z@!^rXB2P6XM5J?rvMASu}M2_C`MROi_JHgT;od<9veU&ymtaeyFvEcR7fLSQ;I zAZ=C}5Fqnn(Xm=-E?Z{sF+^Vz`^PJsw6lOyO=W4|l4NGMO(BO2Axp9iWseJQ08VzUD$BVr!Y~=JaVAA@u@d(Y_*13`OOgrHfNtH*WH+M-f^EU3=RHwx zE&*rs8Aj#BLSNUiu)WOp8Rb+uivG`pPXQ=vb_1&Ux=Iw>Aq{)y#T~~*cmvO5Pz|EE zzTD>+QAO5R(acDy`N>HVJY|yKm}*QrtjNUPRxNtaT%z_yaqtGh{te~OoFSShqSb>r znkcerq6mdS?HdujRTD*2(N8&5LgY0gjEeErXSG?gU|^*#>a&P|iV<-&A|ThaKHIZ_ z2v~_NG!5Q1^2V2kdpoe*D#w|6t`Gg^D(DG%Zy^;ieH4|H-t5`s+Rl{*pNO#B^y~K`IOS%Cp6=-8@3=q&ZgvYFA z#@emq_K1wqD4k5L0U3g&GR8Hibi`jOoF8D|3e;LzSzQ4%bJOVxaB$_VxB~H9S#u$y zF~`-+5Sk&a?R|91R+MD{QsAahRJ(}5v)rpc36}qK4Q)-M9{s1L~l< z79|v6j}4Et*4SQcPmO7)Vs7<54T%5mRWVnTVAUwWs!;-!Z{!=J1gk~~Rz(T;MpR_g zth=jHV)<;(nnT#^v#=B^4GU~0>u;+Fgwwng_AJgi6|0fm6nR5KYs1_Prhu~9QiUr^ z2oAZ7uO!UOZS7)(2alDRnAwKa0HD#0H`I++)D4)^%GywhY+g#Nuv85$MK)KpwF=EV zvKjZu>CxVZIM7Btk%xTEw(ppMsDa8>^eYw&OGGu8;o|q1iABL_5s zWA9za19j=%V--;04!#{7A0FT;I*H4-_?K;6!swP!j#MBUM}MSzQI?SjWb1Uax3f3g z+TDxeF7gdC_o|;jam`tAi2r+KZl1fVbGygKR7nh4Q}-W?1$j0ct_`L5_KL$7_3MCV z9tn?xm6`XqGNs9M`n4>O6_Giw=HQO_Wkj6_%TAP=TGfijvY^GscJpC=MWMtv9xC$H z7~EYB2*a_{UY=YM$Y;W`hO{4}12X-{(#bPQ=4l(79p1!%b4zd!hgL~F8`uyEpdG_N zqGMfj*KBcxwiK=kXpreTUJ!0k7ZcP%5-2fsi6Ql@eBajfAEGrXxbY~bUktbOuufdu zt5L`53dMPf6-6?=rLYcmX{B5AdIv!4ke#3A^RQeeewc!h!^Aoh=r- zjY;;+!hRqG`hEb2i7c_v#R!VnHu{*w;X%=r#X}3!15lrF*c_;(cc_~A8imiR#J+~G zArZ?3hMT`5aae2ot`LM$ zlsATCM4w(^l;8rZ+_cLL*+zeva%FX$M0nX~mB)n^=mz=lV!8O7OhVEPG!7(sh_eOZ zP(Bw%nB{unvBnEw*PX<$qk;Q3phN{&U)Hk#`A~{dWWkoxQE2RF5kqG^7F2b4mlq52 z3W4KLfVBP%674ZOIM?xFE$m#^5+g}~ox$T&CJs0*O!|~HHA<gad1#EWc3XoQ=!65aILp-xYlqUyhlPrj>i)t_#kj!zEv zUp4R}JAJnCeI6qzu{z^)Ud4+ln$L(psGXO zBul!BdlHL2e9J2qt3ssbzdh-EoMT@Ok9RpAJ6mDzIJn(s_Z=D)x-UhVh<=bfmsV=T zS+)?0oi<%*CN!tOr0iMcNRGb+6!Z1EFdVriXmnRIe>^IhFrILisW?njwg#0L2)c zm2}P&oy8ludC`3@RR)Iyi<)A`LQ;4jiI71)Y-M;zM8kt#iK(&Xp*eu;Kna=86egmW z=W0e-SwOGzt+iGYTIvZ4|G>Upi7DlhFrJ*HX#2IYnr5N(Kmk%$r#S3#lmd;a7fHq4 z_!fCmle2Pw-_m%smm^#Kk08zG4H7n5Buhb11R-3iRMny+R(kd4SqYi$b{Ha|1?kJ( ze6irN`6nfSVXP_%U;=RY$Yu(7mWibds!||Ra@F%YikIVK$n>^aC8|AP8Qwuu1*6$u zG-5;TW{opQ1(TWO6A5nH)y#=jkN7pi{Qx^s+U#)bPXv93MY-l<3mHwatOGd^Efk=R zYE6TUJKnO;v8~nwXy2)72O&jHPG83-$tSad8*`Aeykk9t4 zCFaY8$2XRk&v}aWSkJbFvBK8)iC$L6J4)Lv!+KK+AL6+T)WYf)I7etHSZ1;+kt$S2XNzn>B30BV zNUWm4N-UUW51;Ido@*Y!P_X5XZcomp?$^tMra zZ@zK;*NXOH7s!}N(fezj76Px6d7xgqz<0(fUlVXsA!?!ik6h%&#su>NAU|SGj4_Ew z9iwg%;|b)UW|0UHH%5g>izt9a*0pzJme84-i0N&z`KO#=9-piWLB7uRf2-bV8xAF;AfK6Djvcd0wv-G zg{iM&JO0q(e--hEDaRxJ5HEX7{r{veve1H`{EhwB1cer1pEJnHuY$$OnW${NRtr>N z4A@bzo-}kZuRqaI@Y(!=7>ubsxTsAC0Rk6l=HY1i5yVxMYE;D}N&zn?P|ysbN^E4c zj4bCI_uZ=TZ5>xpU;3J*anOvUsqA9xX2K}YSAio5qk2bYQx%iWn0zd5P|1YJZZ*BV zquh3slNAU=Y-KUzN@3D$wfPY%O1P4FTOtQHTOm$$1Bn!hQxOmol{nPwy`AUlBD(pe zp__C!gKjc|h3Fpe z27D11(Y{(F+7EM*$RNix`{e#>yTNPqm#>ktzo^nvKtB@-g8ugTKiUG<1R{@TNqTor zrDSfhQZguDpvVa~X6g06p6>D&B7y!A=jJAff*a6}Y9}PtjdyiLkJ{WXq@Vgh5o#%T z0F}in@axM>Im2o_1grz!J}UXDP0la-s==)%7WN$o&mOUhSGN-@a;r0!y-=b;93UIK z3l98dQPO2tP#8T%fV@1~_G9j4>+O&t3g*_uzG`og*W+2p`C=3hw-)amMXs{)NE3T$ zB(Q~PrR_QKQmb-acNHM?s7?aNQvp~j!&W;$L$HA99vEnsZd5U-CkP@H(`sf)Du7r5 zhFCw-DhlG>fOgIs}#IDh%mrOPZkYO3Vf90{3aQmCd^zKt+WO6P`H8Pi( zA2lB58`+s#9h8(-MGHnASx^b$p=KM9p@R6XbUN`YcfWcBNg{huN}2z~lm8CYFO;#d zL)1KU5D4&7C4-tC+@PV3aL6QqCW=9aAY2dUXo!aL;ng_~oP;wjPsg>ysUgOKI#EK7 z)S(eZj{a1hr;^*<4L?d5xNts|GoMw$sAYqtFQ*Bj$JgoV1cu&ZZqF$Sb^9~g$7FSLD)Zro2IxHSYdiMHqa(sPx`8tJRwU$j;Q4Qwb z_D*by4k`M@StE~tJ<03|4l6a5(Qt|WoIa`ab4_fj%e zCD&KYQYkGY4I~pkgt#pJZ%R&9gV2sQ^{RWi30J^Q=NNwA;p`gq&V`5|TJ4G;l3o?m zxqkGiuT#Zgqd1*ktCuYy8Q^ix=y4YN`eRR`fbmcD0x_ z4$%g{WDjpaV{GhEC=OuQB%!@t32D}`l`?rMH)*kqa+hR@M5+j7UP(wOBWh|9Ny}A6 zca(b?IijKDPnF@)<`E%g5vmsnb5kO6(k(}VE%_ng%7@3b&oQD3Z?5G(Bq$eP#eU-y zqXkB;iezDkH9iuj5_^z3AH_0@4z%h6b?U!^;PB?|diqI0X}HTG%V!OM?|W!e#U&gmp=cv!;%tCD zc{JoXMD?O5;dt^twyGlSj4@Nup(=7naA!HdDpjlj@{^>4RRMESq$d^GNz|!I44X}z zysqG~#qpcGU4nv?vE`1`)yy8Oqm6STjhU@hGW%}BnS_KY*(3pT7_RC3@vON)Wx?&8 zoL!_-_{@8{mgQD#8RwG(Bo@pSl;-NVXpl(=Bs*$>JH4H6cYX!Sh0FhmPToc&t_SpZ zG&Uy%C?P9ub4O5E%8#l5qNH!SR~CJf56sOov0~TpZb@5F40@$DOs&U1eUw_OO!^Y> zi|`ZHze0 zO2M$fl(IMZAsxABQ4668$3j(?T*q=N)Itxq{sqr~a2$n@w(L_U?X*$~h3!D~cAZjL zurVYOXiOxm1Loc2y9$ORLf?uncl4@)=Zy;I8I$I$&D7^GRx?h)ovVuMjAKP6hIU8T zsnAEE3}R)5ZL66T*Rf52>52Y&Krc7L?LZ5}awY4Os8%H`h2yPNw5LtnPJ^;baEm$v z6icVi#8zf-1+t}%i!UA?kPlKmVj8JbM@+9k1&PEplgtq}1jAi!V4nUG+H!-Yxb4AY z2A0T02fM-2{Jiy0mDpSa^fF||{HEg+7-5D@({uhpwqRYeX-6(9JtWFEv#a1Z8^vHq z;^|y@$l^nWNJD{(2IFdO=`qu4$s=*t!gPx zya>7_ui^1aP6&=V_yMsdP(Y{qEj13h+6aJLL|ds{mG=TW zNJW+E8yda8N$XFsRZ%jGMHVX2F$%EB1S#!;N(=KSq}eL0mRE#_Bweui%3CmkB@=Ls zqj&%D)S1a%RX? z=j%ZT86&)2PEwWs*^gaf)3^@HY_Yg2kWt*GTC@B>BnV@01-jPsf1Ed79?;cRA5kn zW=CmiRw6tNff1Si?bry}JfKH&!vB?xivX02;N!dNn`Yq)K&ZV!SUMiyPced~h|su< z+~+upmCvn=yo%`J{!Peb?%(Ci#^`3bHmWPm1Gjf(;tPsWFCTcMJ)cggC6s37TH zI&J+&m6b6RmqH9q$jC38;3b3GFRp!}(uxGaObkZ5J=t#lShAN_Xcyrpy|WoJEfy=T z;;d}4ZDWv?kT5;Jy?%T5`^l%4o^vX`pd#>xj`g!atcf2xtn(5 zCG{5o=Vz?jjb6eTD?=iN2A~U&E>@#qC-+zi5X0BYZlOx z-b=J27D!Qrz(hMdStyEL)oxH*2;Rk;=%(3nV?A`^O?30UiE^Im2gP10?euh9%aXB} zkSbiH8P0563xKjaD~kgvnT)F=l(#R>Zf|uKxLBrEf!A%X0>!$qGBxA8)B71AZ2p=S z9z_uL7eQ3IO)JnN>1g_3WlOLfEI+`BDqgYLVN+7xk%Sv(C}!r#RrTY^#ntWI+2!T_ z^?8ibh?V9u5?ed^*f4!i*?vl9C$<^SW1>T$iAyG-(#uL_mHO@3^a`E^<%u;BTh{Td43D<-n5=$~AdEr@bUWZ-V&4`4_EY9a35?U&# zgH9~Bn-K|f5)5HfMkLH$Ged*Wd4$pYb$NL$8WAH~%#|0h1W+qt2^vM_Txp{uh@{{s zZHAwNj70!5L#)+UiXwEAhvLX8Sc)O;rbK#eNCa>E0mt!h!s^ou1)SwBkTz37EDkA) z$i(5a9#;k_?fUYE$@uzy`o=H@x?%CG?Ilq-_-s;^;=xM}+R7g1B~I3|D9Ku!cJu^3 zL~vVCI4(d}sYfB%z@!`GX~4*^1^U5B%?YJCWqld7RXU{FrzBt7M#T*HB;ut4B8l;8 z%iuttmi>aLj<(C6%OB=4wVv(F(X__-NXn7@Ok!sS)6exU9q$qvq+hN@B%pq zgxwT94Z%8LA>NLEfEM9AMGtN~C#tHB!oIqOHQV9s#!WwJcXrDl#jREL#3n}kCyH(v zLs34JBEW?atI%6rg%PWU@2fHm^H~_7W9)PlMkr#OtEe^2) z6AQA)hI)!{BV)Mnr@4gCLaGBxDNvsXP#^~7IC1yi4Jxyrxz#fDJ{bEmYo8o^d4X}Q zo>PM+0td~&3)w4QF%rB6a}wE+8I-G*XvKn-RxD`A>uan?(d2t0IHvSq(ekyEfGmTR zRvU?pUbKW3uD_PWK-NVo4dbE8vvLQWRVk>y5h!zdlt{5Hy_&G+7ByGkI?-PX>;Uv0 zih#{Bi96^~I+DwXmkEVKAggY9i$}<*l|}8*RY9>wNs`?S*~`PL=Mf)&L;NNX{kC$R zoG|VXkc(Rm@fpu9%aLSWYtRXFrOKCL-r&H6&&2O+Ey>cj8a<3MKXJZe5WkiI4 zc&*?gZJc13yJBLIk1L~FQyNf3Zj*qOuLyLT1UxVacwiFnz$9SNIr?LDjLT;xu_)SV z<8eLBk7%a3!HaMY%cD)goeCL`Uw6AUm`%6=-81YFPlt z9F^Ez3-Vw@TWpigWtXlr%m(weW-fBcc`_Gk-M>Q1fVFmdJCvK3tZ&t<=nqBmtp(Y7 zwx`>}?d6gWp6)q?B+$1EdF3~1``4CJSRrT>BRLcU6ZZ}roDzxFD1Kg|IRtDW0<^jA zX$;^uuu#^M(s`RF0K`_|007)orQ)R(2e(6+{TP6DXQ@U3Bvf(?Q3+MRaxt2XG|dL zyUF>*UGgA8npmO}Zp>O$?^s~8R;`lPz{Aw1^Gofz>vp3T9uU~z zxsY#Kf;}V5@F1c?$yeoHcJ@DU2y*(w6FCeeQ4V<#fw# zv~!l_GBXlupRq5*mPw8AY8kRQ&_EPRHiYP8> zkEhYK>k-APohH-h#!N)3WU)x4n__-s1$Ql_%WMMj5=6*!?LV*HWEL4k^L94zJW6@q zBF*7Ghnwg$cGYmNo@sz2^oD39@3fL;eHzD9E*uLR}^Jk%6Y+~W_G_2h0SUv z`LgF>#Uf3>n=n#F2kw6GnL>x+j+XTWGm&|*j<&v)26p*O^@ge!u9!I?R{X*a>n3rI z8}OkU%gW8I-7(D^d=et{$u2M_yfd-rsc1`OPNQ)ur*3%uZdishN!yojn2VeCif0z!iCoVpcQ_1wS_O z*W@BNM>5x)~LRay;orCL-Ju2eh&SC@X)MZ^IG$}z%S6c>mBCBLW zAb^U3+`hgwx9Bghps~>f!lwfK5I)d`S_ew4QWSm#5$ zsA`zo<^&qpL76N`a7||QHdFXT!R#-8vmIj{*KhCjc=9HwupVe+p=h(ogUu2b`+CvE zp6PZvpk9@z-53+94bA(zEn7epFiAw2t0H{Jocsdu!B7oNwwp;@FjlwDf$9YWRBp86 zAA1?`4`B)}8P}!e2lOyA?DiGm4~v{4D8mw((&4)K9FAkvJ%VuBu9W=nAKI(t$%s|W z=-%!hZl;r4n7pMf018i}NrR@YP}_}#5rqT|oKV^gxQCRqj;JA5Nx{hi)Mm^{2=TLM z`M7WK-bhx&&dW>;U1$!T5blugf*uQ?!#VgIRlzfpdYWbl6e+(|8M~fQCDJS+})QgCw_#es@8_dkXU6vMeItj zNwp8MTq3>gxLPx@*DH(9`it3|8ZS1r)B+YYzz zLJ6}(FB3tCzsC=ek>o^#Ofn4N`Q>{45Bau@#T@foDGugT&giQHtn9S`$|CK*Is16E zL!rLwcY!eZ(Xa|diSXEB(*}WriH# zO9rPZjH;uin1#a=BUE%PCQDT2Ei@Nc0YDJ!9Y8XAZ*gZKM8J|EMpss?5NXqp7dt)B zi_%mN4j54wzFi&uA>RV2UirES-WJvpwPN&BiM_=-)(kBjwf(L!DLMBGwHAo=Ix2p3H0^dxx zg)1l%zReY6tEpmY%NA9SMkmM~B+6EB=&!<7b)`Kx{`xThfkXY1DzDUn&|y=oEB!3kK0nMM4(aV$%^5Gy4b5 z9vn_HJ*J)N;o9eiw-UuUZ~t89a@BnB`Wfnw`B;^r_BjrNs4?U z!lUCQbrsT?TI5is#`5BXu@=bMGFv4fP~|9!l%f!0k1Wp3JZ z6k&mvSLW8uc3Il7eQ6KKl%1K}7nRTT<+YWJ44Ikm z!xkdJGKx_1E9h9Tb!W5}*GoY#3}HGk(A-VXUTb&}65?^OmJAetWB=^p3TLrA4C%m* zkku&^YXQg*c{|#ouE{Aop1i)kMwQh1wBFdOfs{>z9!&5O2DX$-Ck43+63zG)XLW|xDyFb1mr}+KW#odQ9 zEDMrxL?@vQhLYZ>B1X$ZxYU=ZDV?pj_a+ZFZIsURtQfGddM^+5eR+L(KA8r`ge{Ua zbst95ca!X@YT^(Xrl}jKtQ+vE8^EF)_|Aqnn0Zy3g|cS+0gN%lcmm8Nu9;!QO9Y?&yltqY=22bC;&Uq`ECeiI zm=*tS`Nb_r3p9gmwJ0p^y2O(*cbzc_gcT#o$z9h3p{DV}Bii9xkj#2C7zb1C?C%Eo ztrZMrAzU+!>Q2J^;MT+DxU+{)P83~5X0vsTlol0F4_S=BL*dccb}-<2TIgwnoc=W|Tl)_~EV?`Pr8Hp6>B z8L5aB`E)Qf7!S2L7qF_R00W?08PD=qb5-e0z`VVhS2ow!LR{~WSZ{HxKy*NNq@er1nj%ISp#qy@BiqJVcHiZm~~Z@ih@doZ^_2PD7FsrW*%XtM+qQm3t73)AxUNWKxHrR&NQE3h9_+Y?t1XBO zNVRFb7f@GdZgQ{UaOyACE{bEJJd%+?sz`XFRgd}dz0;nE1N2@LVdP3U14%4yg7Yb-E zo|88gDbWEaDWbg;t9}}rRUz%Al7A@*#A67CAaR3x*E9^`{7USbJt>e$&R=t>g)Oeo z#ZNJrO>bObaJQS66y4r=b$n<+#502s3g;Ow_7&Jn6?)Us>b?|2x+({w!{TYt`@|U~ zwkVQhr`3Ety}rM3PlRAuSYbFQ{ZUEY5#UGfuCAwEgJl^Dtu?aTu;nVFq}zC*ARrue z6>5b z9lU?ZN!X{yEqw^XJqo)?PrmOe)GPutBi@G=urI<@ihfr^Y`_RT9eFcySBu1qgHl7 ziRBT#GWKF2s1-_Pro@`i;eKkS6#M8P-RAW}5hrFmGKP}x7t(D)idsSvaOD>rwq`Ok zkiwFjK#I5*qLpSqfV2sM4pvd!x?2&x1ge`e_LGMkGJLm%O*8S2O#S8MO0~XxbngTos&#;FTpI znh@PA$|@Na!JhkEC7w=69Rz}+NvMjHNEN8~-7pGr6T2=Gq!r5;U!iqe4?AbW#ROlm z5Rr|&zL=mVSD!EQls#3g)~~ki-HdInHUtb-{72_6^BYgg9$ed zpzceKiw~w1Q4$cp00ExJX*aW=1S=nd7af*FH42x9$YlwotyEUr^-4li1G67+x5`~2 z%n4mOcugpzl9`s|8q1(4q}<2|bLjO9xz7Q03x_w7V}_gEov0Kq`kkSCO@!uzri5$- zYch-wu`S_ic-fYT7a0h=CPgx?UMtAQ5gQ-e;%_?;8z#tuhq^hXM_%I$dw|8;qG^dC zNwSGJNfwC`Gg6>u0q!f8&i-hBx0XRy@)9FuCOhkRa`~1>ZmLsaoi#n*EUm^cz4y3@ zsM#-g<+y}0%&PoM4l_zf^>ERM2}J?M&M}mKUm>TIZ`q7kS$4#srgIELqJUKm*Ew_jBh%&8YN}%juDL{14%@EEHd{^i}*|r>XQ+SDE zC-MuS2Ss~d)MMFB+Ir{#No9#+K`S6y=1B-FFH{?RkkQ1;7Y!;iS_5YMs6tifi~ARy zH_<>Hoi_>L6S~C~MiRPDyZ)SC@QJwkVv!RNRQ-j1>*|Z$j9S)d!ZNO^h^NjaTNp2S zZF>!P?0Q}E)L_o$!16`U9hR!-(N&yXLxkn-_UXxP62}_nyncRzHW9>DoC^MX;MGpK z#4z$-i&2BM7z5&Rai2rPE!st4-YB>ci_0l^G!bLtX1-2+K*beXm+rWWsc(D|iN`~} zZ7%>)dGm0j#lCv-XTms1R&saYC4@05IaW>K-Yv&!ze7<4Hj?bHPn@Y8rRKGUR>7EFk=ATia+-RTjj^En|f^b+s+Hr;;qvPPT-mi!&qaXx`CTRS~Jt-Q6asdu1Vy@`(Ps z2!r$fHcqTE5Rx@qzOGY#zOA-r`}*e7^y1xnLOB2)esZ|*6!ydYt;4Oue@-LM`MX4O z>f%q6ur~jGvX8V51nGz~F6_k6G%UGYB*t@*6+_C|5DyU-z)?pGN%Y=tfX8dV>^>O4sS#9mlW&)iM~Xk z7W8V%teIKnf{~Y!-bcatt&2*B082rL`N`ry#UkW7B-`ilEAKwRJfWSuF%q( zV!2zC)B0O|k5y+!JSNBh4Q<2k<}2B!;(GLjZGFHo2Njr-}9tOny?0H z$x3<z%ER+|W@ zkVLgnHIu)q=zc!gY;R?V-7;(a`1I)L@Hhk;>`dOC-Cy3h%$Wa@z>)0G&4xQWd9s5p z&&mfkwz8$8lp$Tad`O08qac%rlv1XGh?|pLH-p7tAM$ORt7534KuzxWx$(nNhy#~J z;dX}WM>_5kJf#U*d$|!z!WaD=?+B%XEHuk3hNuQAY8 zD^ABjt#FI3Tw@&^hhM~TxG_217+p7U9B#~yRSQ+(kU3v0ShCxbBqV~y)pD`7O{cv+ zvsNfBdaJa9tCH@5CG{pLuHhJUCMdg@CK^4zN&HXtibQFRm?Enr2#78sCw{cztRTlgs(_H$qK|_R>sfYnryOHM$!bA25GlvIdoKa- zIwMBW_pc)X5`RoP+Vm8f9HGLa^I*{{g{oF~TyuF7&#peT&dZgdzusHZN$lyGGO@*W z4SGQqz`(Rm9qPmUP5V@Qw?2zH44m&vAm_6Lgn?l?28-ug0C-=}qg zj6;B;klHad6IMf@mQKow&4TKhA2{aqR3XbkE{A$ zlS)DSx>5fS=xXLj#b(bu8kOIjrh;2F5}nHNgs>~?PG;r`R=TJqjWkV!j3zXH|7y#Q zU1D=?Ceyo5abIZ46PSt+oibBV9Z=ko1i6z0*Ut0iO@dAVYfI=k#HfHx?C3}bg4O#= zW(FyaVRtfWZHlDGwt2tJ40w2YOpZaSRDrp0&Npo_g7a1xs_LWrFM9=v+zoom`xkxb zOY#x$kTk{W{mn=eUoPrYQOtH1wS2@8IDJby;xG*yS2IgIhf04ux%iN(Z5b_4+Ij4* z0qg$}YGOLoKyg!imaH-G=vdRKR3lyA7&S3`5XIyhlWPW68(|>rlW*)<>7INxO5~a+ z85i{Ne+z0yJL6Zc>hU?Rz>rb@+4*(<>iVvKM!xCIUH|U=q)&9$hui+emHojXc$9RU z^v~W=O6&t+8iWD->5JYk%3Xr0borTm$%k@rW!Z%8O3@4zjH2^6uLXuHS~OdM$@zY z`Ni9}lPP-}o_IcQ>cE&y{p{*?i!nBS%9gSp++cH-8o>Pf{c2i zLLi>`D?Wcd_Z`5c??W-fozd~{>V1!H^O#~M)Sm~9#hw7jhirYh4`7wU$ZCsMZpdhh zGy{I0`QG)fK(+?Fm%9drPjC8!Z}l&Ap!|PZV4T@#QXEF)t$@G9wjjjA2yJS-}93eYd`!r~lLPBobHuO=VE zlxObN(KY#*UjpR4BVe$I?)6s+ZGmhs{_f-T^!I%`U=h2*%x&`LfUM8QD(?bFn?Zt0 zlLg+oXillQxbs|4_PGFbcGhpsug+G_T;jO3_q>># zx8JjxgDso-o=`)|Cj8O3{{pWGj?@t^Lf4*-?^N}I8D!LV0|a^&-fwQ>ko@z-uqXES z03?c!fD;SCTYLf(D6-oE_{2xRfghipoV~yPa3*nJ>BUdsmq;#aI2D98gWwu8EWEBD z(Ft;Dt=C^3|84B};{`I%;s6MYc7osY{t2*5hW*9W{p714MM)TG0iEYEqws$2u2&s& zZ*$e=!L+V=bRLbXT1vny6053-7->m38{Im?bb;bA%VGql>W0O67?E$zLq5*7+|+8t zI8AtLwP6!xN=&T>SbD^zL&T-MqPWz2fB|YiK5s_!-?3qhRV+wJ&9P^RNX@pNBOf*U zc)W1b?6DvjHJemo5$3?4xwOP0U(!dwaMb}&mDSAYUqD)B3^#B4tA5$|;dIjfbba5y z<=`s&@bL_VPOLaEPAKMuD~QJO{`V#@RlNZn^Lnch?nV0rr0Q(ghwPh!vU@r}*RzA` z?%#o&j7rDJP|>We!$C&SN)Iruut%1`x(Cx*)O%_-Zg_S(B zA_nu9Pgdo9oTwLEEaMz4Zg;`Zs5H?;B=~^3yK%~{#>q|(HhOtLmz*ZXtIG4Keo+!slMLIIV57(FQpxb^hzP~^FVbY&mUEjZZ zpY@sz6}9~Wsf#%9y#F2CA7;;cDEzJemXht*fT!0V45ACe!|C2%Ut`=yN(k?Y9q*Qh zoIKrP+2bdfU@rUTQ`}&;W=wW6mYIzq%F%Kk+Ra`Ou(>V>9NyoFn%ia+NkVNw!P{rz z&NKHGbR!nUm-CIog5L8jZjAm1Qtk7Fe*MW8O)|s%)fM|JDA4-Neh*OcNBng^{kUHL zzd13>?knQk$R#o?FqvG~`MB8f@b&ey_2y{+aOIiHD4m^vA%9Q)zU)Wx8@#&)O5S7s z|HuC?f7`hlkbq~Q_CkXTr8O0wYRjMLXGsEWg);ptU_GAPO+R%`p+k}sgnMb~&owDz zJ#3(fVa8nLJigHV9;n%l0gU=3A8Z8-2ox7nNm@hm?7{_GZY z#|q`Xy}v~M3q%a$t?4JvgMHHHEh;c!uCq*t*#y|$ma!>XnpzXMzxrZRc*$wpmj*?j zyZu=Y-P@lv>fHXUP51U^jo5y8(X@a2=@vP>uT_$Z`SoOS1?k1xh^04J)*Jxh#yO|O zD11hHXj1**7%-4fY%c~I56dOpuG+**@SrcB1>K* z#$a^&venUp<={dW2*W>z&{7zQ*@j&Lep(7;;Q^?_$u%S?mz$!*yvXxVj)i2U!qCu@ zHiK=qV}>=rYckyS6QX9FN_@LH^C&VOR=Ba-%i?ex9Sxv67;>jzQnpBjq9w+ z9zeaOxBFXt?fPrisHkklR81g|fMn$APcr3&fuQpRS((myQ^Z z_;4oyjSWOL%kIS3f(34<7GK2I9J^<8YN~@<=lV!*90_)FHWgq>*s3v_s1AI5fAQu$ z!VB)_clQ_P?uNO0PX$2iI(mx046|Fh6w6;arr040xG{F{XXMF-et{V(P z$Sbid&EQvKu55aWdd-3;cP4Ml69FZer$%O@0$6o|5`ODjP;NW0c66IPENW0ji>%S^ z>E4i6`}M!PySo3EcQ=>I&!=~9wfCaS5~`&hgLg-_S$X0|09ZQQPkktF z_;^BncPy$3Ms+g&@xACXkxDup9=oSSoJQj$d?iYfeWU9Yrkp{()ys794#jJV0(Nyb zy})9nA8y}c3VU;pUexh;3k>Qr1z6)uudh%WK3v=y=ZR?QQ`bnX;boA$2(~*+g~47r zXFMQ2j+a*Et5)A%eTjE_Fb>yNW*!#T8h7GxtreIY960i#NY!=!bVe1EB0Zg?rJcQ^ z#taCdPI1U-NLR8ch}2@%sfmD9yts^5wPxVo!Sypvy18u9vsyD4@-vQAAr`ODPEO}X z;aKdTn})k*TZ6FuWlg1O!X9_NdK`+am8e#u=&eAjpmrN^4*TY-4-u{N(r6%&rhboF zA8bGiL|0YQ296#!rQ3VLyEskzJmTxmIJvfPViTV!G>DSamZ=G1LB4qe>|{N315ehd z6MC{X-Qbfo0)BoDVJ#bB5pW1VSzqO3t$QdiTCmE=#m((!>2X!Q4;;fIuFT&Y zHj^9mYh5tiszRN{k6aQ#7YxRxOWt?q(}2_w!tZFuM(u6~Sk*_lW2XJfi`P?R??$vu zZF+#(-o@*={R1zj(p&WcldB&trq@?mI_#+u?Pt6IsI3&FuxNH%x-HmO{haxG_5oUufzauMrvX)Nk+|8Mc1aAs{sd!`%GSAnst=THxd**6!EUrv0R*Y8oMw3OZyG{H zZ;-C101Li?Zt${GzwgcvKrD3PaT<9AGP{B3;X)4EA99oVo1EaW4*Vk)8S2fdk5nuaE}w+Ziz> zo(R$jW0ps64d>8srP^1W3n++Ua1J(i3_vMocT1h{pd9}CAaCuMy{;D)t){{36>X6c zW64_2+Ggz@A0Hk|xcKo$^NjWJe_aDa4I<^u*iG{hi6K=FJ;C#Ncptk!%&N`xro_4DawVC}Y{I-(LIyBTF=hprX9FHZQE3bG}NuOh8!4 zK2it8!lJ_|e0LgBxrM8-2pTXbiF00(y?L0mva$cHQBA*{GaM5yYu1f!p;A~Mzzi99 zv;}5C3>c(sjmth~JX0xis6GldK053qg~mX~&!OAUPD1^NW3ARa3~#)+FfqU`V@WwwOc?$;g%vtC}`%jr}# zpDESbp}PAQxOLq`;+`On&kND_51RoX&zoOzsDbjw=8O%5n;0e0KAUl;mL=mzGAnee zKg6`RXYrL(;SZAb8XT{()~R4x$w`xNO)JauPiC5O**{p0RV`r4 zlM&CdP`YNT&HQ?DH3=Z<`E#fz_JzE$azUKAb+NM#=oum&XF zv_fjHDGEVoNjLHF@*)GzZu~K|GC`zeYEAo)YHGrucN&GrqlecW;4d{sQEU^l!1C5P$RUHXn#e-O7j)U~wy> z{6>M=2}1k71VaC||CT&UEEb*nuikhW9bTe%svWBi5Ns%0a%&fHRG8rX861ON)4U(zSX!GOzo&Amb zyyv)kctm&rprq_68<{ME06Zc*+|Ttr$B(Ba6v{n+LGGCr0as)`_r55oEO}QTK4y~y ze2r9Nf^fR+ZN2LOdw&bke|P>zqz%=9W-PUNOWCQr!Xo5+ZkWM&J!IxO;wSk{m@gaV zr7^brV&?GQLYK?POzkG}M_y$)m@-#?yu>Y0oW}!CTI)#uoZqkXVZ;f0!hrDZ{4grR0-L|BB|-#r3!P8 zZyR^%=Bs8yp4TBFLVQ~UZYt!w6?1Cdi>G$nD~KD@-=&*nNU=5(tO=^D zHN5{+bw>=Qn+tJj+k$X;c?xM1vDzJSyq&UC`|>Ww_=N@=mS`mLsRJqnoNk_@*a{|C zm!+4=U9HL606*RKe`P7)t4~(`(X!qYNT`GzLuEJBfcsJ+PhZQ&h4He2ZnsqqFIn^+ zc;QxfJ7lxV%}BGB7ZYM2DkYFE6GTu|fTI`RU0z?@yua&wa!eTZ^HENpyd<&2QK zFAzZ=fQ#Tumr)dBQsmx2b0I?QkgdZN4Q4v#v2dK8-@!KdA>6-RkH7 zl3X3gOUOz(A&?b}?f;UF{4xX|YT&Ze zKYbjo{8ZxNVv@~iXy!M{O2?Rf*!E~G6lM_}Ht>^9GHkR9!uE?K63Uh} zggFVAn2sp3GmLMU@*2H@a{oI+-;EBz33c*K;J4@ABLSC1w%~-WEo$OJWg(G2_8C-P zxKlUn7aBiUY!>dZEX8JTyO3(LwotAdKFi9XK=LgX9!6j=FEt$)NnU-^^| z_GjDR>iJ7%sBS<#sm~895Woh+r8WOuBuD4cdv>;gV5;848c&_Ap^&Ar$F-w%9Xo%( z()>*k3Ka`Q^DhW_FUptRgjnYA_-0Ndx*tng=2AC14KFcpHuV+A1k^CERDm{BPLuKL zu=`OP7mn^bJvc@AMZhbVVko5OKL>arAhr_eft2)S=H zM8eH+{-uGH4-*SchP#@!4XNu)MSK7X&OF7a4bj)Od!$yaa`USXPe4nK8E5U1_#*(U zFRf7djH8JHhoKAAPpzU5aTplmhYkb13ipqL7f0k1y7lY+r+_res=8zNDSAi@m6?I2v|$QWp0E-t^P+SI_4zxfBGog2FRD#75JOG!1y+R%!+ZD!l3pR$GqUQl}!)A4BCEOAktmqEnsSKXk^p-Sy z>7?R?%vyCJRuuTU<)Ts55to&C2qaP(1z4n=H56x&SGU|-aEhAoR=N>l@@qExVX-`9 zo8Yz_%WZ5~>~DWrsk*$B+Gq1C&$SZbEtIKmGJ2Gx66Tb1)HsnlH74CzC9m^gl|qP_*Ll zPE|NXH3l?XaRn>edz;&H9PK6TO20%C{PeLpxToOKdt@j zlC*2^jU-HX9&DmSAU<`aub;oPS_<}R7ulK?i;iV?@;FqG($Fq>T=xq?Psmj@tQHFR zeAePq#kYo0ojA0tAq-h1^lFPS5b5q~#rM$4A(ENWs}vsqLw8VLKk>^$W|{a( z1e<&D=_{?S3<9D?2A?-a10+}nJ@7DvI9t+)$@#L1*tn>FOnkt2b;LsKv*04#oOmMEtmuYMA+H2B{Ild zwdG&@q4%xs=Ox!{BulrDWJ-HxyOzCqX|Ht=a?#K4*n)*hG_JLz@?zE9N=TLNjGP%= zd+DM6+*@Xfw>I;In?f#Q#S657i8Ct(Y`%dAYe1xD+dD%Ezw&k$B`jM)FpZ}iHAS5-~7=>3EQT8vxEHZ|`jMZ+ZMiQQtt z{&;zFPlYYp6DFu^>2{-~pbK32YbiXTMJ_lbP{{$k zR1iGMBHN<;17@fFV9krS`|?iLmJ7LPa=7h4`iw0zHFA%gWF}gHd{OtqzkILoKjj>UPQ9>=vw3GL)1|jcg-E=HxmJ_T=_LYMvs;OA z++WB}GiEw-A3rTLjyf_TVX$cDpRxtiuK7t8;^ANi4#jT#P!c7o~ zmV+avRK{~OdrjqPt8Ldv7tFCC%$-FgY3(*tGWokg`crSZ2TjD#k`m?`HbyZ z;{|*tVPR>1si;C}u2dFr?(wlOXKYC;2X9#-19Fqh|Zd;cP?zWa5%3X%9u`@E%X zOG5#P`gq1Jm<;#=582%--`}|R6Yfu5pl_P`=6rVHg0lDkvr4P`7lwn1P0IW9jcJSb zXbg1W9{G@VylG<~3pZKzl^R12XP-Hm76bs1zzIoFlrv;*q`m?dNmOPD48EcFP+8KLqit;?7NV-dyoY2*rJX*S@0Ao5vJlbD8^JPwx)S zZ||&~SlD@g}~8a(G!~E|d8XC&Sl@QqUwMLU;rBB?>d5*q3aQ&aOq9px!snvZUzf zIXfrO5z!SVTM#{c^$J%!t~32|J%uK4ZE9wNIu}T~!UxhO64-0$)c~^Ga;^2;(t4TX z+D&;6F>4s_y&L%$VFMHr9sNGqASc|ZIP&zxj80P)7|c(N-BI^ zd`6Y#|0SLRnLSOFS6;F{Mf$-5r#3xN7zgC^!T)_KzKJ+QP3`bbHJ440*EZ7WAZOTC&OeVL6B7y;LK0 zx-$19!4N9X0X0>Q3+@T4d39eZI2G<&>|E2v{@FSg+=T~qu4%T1dl1AS zy=uR!*+c=oKE$A}!`6AXf;$!zs4r~z|6=(Y6BSWlOGI?sJ+V{-VbN=+l?4?`k67wr z!@0=&g01Xmapxd1c^xZl(g-1+zVZk4|D}1Kk(OzOSKTq7@VOSR{_}Ve#>(B+fBDyw zDIoaWzaE@lzrGi|Hm1h1ZAx~1_pjt1YhnVZ)jkqrRdY&K`$Q?|A6>rr_K@c)f30;dN_P^PYGB*`n|Jln~JCayEO6-o`+b+x=YWOhwNgvJ8M(FjT(sXeUeq$M9MIxCLo)UK(# zdO4F8)s>}2$felN3Os+Q93i#0nFnqXJpLp`ZmO7^h9u^<1<|H{YY|>ZcDs>?mhK*t>2y!BD1J!o+7QQkpKQ|NTcK+H?B1$GifE^h zlBuYyGmRqA4&?vVm%#p~1UP#G$Kt-(`A?NWlYYSd{bq*&d}`%w3aLew&RHBYbk+#4 zQa;|TqQUyZ_k=~&TP|J+22rN`DKr`(SlR4Qr7Lx~0%rA`+xFGO_3lj& zPVw`jyH}sAV5}m;UVNYnHKGc?A!NSZDgGb}x8_L7IQE3%?h=dfuH3eLF;+EekAhzq z7!_f*I836-_r=>)H({`nr`ZuF(XyfichRUbO-p&dvKANIF7K4?J1=6gT6CsKx))z| zW+TP%hOxfW{4m7Tm@F}{O}{n*0+o`^-=S+@n+|BaOVyR=XD>IhO`kE|uiUFeBMb3- zQzUU^Ul(UEmHLD_qdva^_Ls^uNq2MoOLr1U3=utx^e)Md)SAMMK~kD_{b4B3M6!B^ z-Mtzn^J%QY4)Kl0EW%`V_e$)q?Cb}1w>H;HGm-WHs6A#8uu|-6lXVth48@z62lMvb zr7aVBsZD+oG9M*$Bg;Q9pQ>w(egt+^I$-VA!8hXf$~Ut7GYoZ$bp07brBu|Z>YbOV z4$hlk3?pgtD~frz>+L*TF-Q~l{bDgR?U~T(?Vpj`136dSGiS~H;6KNqglnq4dJ1dR zS%li3&#Y@%l zL_U{vB>ic<Nw(LHvL;%L4wOj`;U3@p zn$#!r>#)QvZL`vvncrY;l?AfLudlUqi>niIuXOJl!UM5Cb*nOX#x)N=FnBO<%z&~K z3dW*zG4okl^;D3Wo2HyC`!2WunH5jIEFHvOz}|UzMetRBA+Gu4A;uB`)Qi~oTWr>3 z^DC@%l>CRfV@t&RN}Cy&C2)CeJ5ZQAE7#rZ#ZU>(6hZvoDlXS}d zz=6r*M-r-*WJo`xT*KN(U0NUC$~{r#`L<0+k6&HRP;R(cPx`+~dW%<)7hm&8aP4fr zm=JvPJyD<33-DymV<_9t3&v3^CG5*SIvPD;@PmJ4mAq`YIuv--d2aB4fsA&>=(mPjNBxWyiA4fN!CaKs_u*sua_XHJ?E5I zVU6&r3!}#n!W~J5c99b-YqRUBT~0|JQ%jfYeTvrKq6rtCl-;qD%#gm3$|}=5b9%a- zUmJ#CxoLB!n)UfU_)yuMJrLZe9~Q6ga(u!?Zau-fvzANwB~1M;H|ZfyXJZF<8!Ii5 zvuuYm1KB?-x>Q;<)*jJ-8a&7e)S|HVosjp7-|pA-!L>Imzn&;{o>Q(>VZ}~-mWR0T zsSACtsAtPD{5gJqBLsDPb9sIDT;-}hD=hS|xR*UN?$C=E`ZABcynB1zj!yBuJNAph zuKy0tvOuCo4)w%;hlrxbF0)6X5k6}~JHm;r=X~yH7GjCamfNx#JEYrZy+>GjKgJ?# z1ugX;)5jBACP=cc&DQ5Waxow5f!t3N?Xu_n{CsB#U;hrHxzAP|9{YZdPW`NTOM}?S z(NBqfUD=!2_DVnZ)7%2vo8AHO*cMWPYQM}wJM#pdYJuDMnz+;#e8tYEjS1d~NHAx< z%zJfC-2t^)S!nhpC^FGW=WAtqyc@gy{L|Ka;^)f96I(`&2rEgj=EFXh@w|lPk`Mb_ zQi7Uw@etyMs5^|Xp>9&{qTxwa&eypfv@u42} z#h%qESKO~<;p4MQSLJxzpC!r`(`W0EKficsJ@Rwq%Whcv7%8`JB8^LI|g-+B|)l}g^lY@!q4yS6(0Gy z6RBHvO468C`!f%vbDw43R-KV&qz<*7b$oKP zceZ=_d~g5hh^0y0DUAnU`Ndnn-?jMEqSXAo!{?)`_vasQ*$loXA;3Py1#($2z!p^!^;HlvcMzq=*A#Zv5;hi?|0FVrSbhdQcC59a8&mP}8%U7n7 zGDbd2m@Q*Ov>y7o(8t5=Gpn`u)w9Wj?Ok?QlD_rRSH&@JkI?Gp^4`NcyNWcn-rc{g z5;{W^izVaDR4)tKL`K|NUAOAxYXCcDpfj}DGbgwrc5 zdc}&=+px{8GRZCY64nwby035-Ym})TOuh9-6*_Uq(q;_xAXxK(M-zWqC>Wx= zY%i@y*#1l0A4$BsKbgdrA{409SNi&e?te0R<}YymmV$oN{CU;qt53drK?b9N>ru%x znVD@^DhyE~5b4kGczmYCF`%;p{fmbTL*(xZ7_wta=g3wVi}wY zr&1yNy{X8c7?nQVydn;8r3MpM6(ZB6VMYzCExaqQUhZ-0`3%5%?RK7UF*$rbKKyoc zFy3<##JR-q>0jT!ec?+LLg|VI2evjoku*1@(nlRm8v-J?G-y{RMIV1ObFwaK-E1;D z3%`#J&Q8ZihoQqPWwEj@x75$E9G6e!%GNtc&-~yKiRnesm@Nq!T~-Rax6;wf)Xsceq77sJ>n(xnR3E9Z$VBwg- zurk_6-Avn2)oG_arLckQBa(`^ift^8M~C0rK30n^gwrO*8(hcUSL4ya;n}mD{UsDC zz4W3WaZ$ph8>J>fvLvcsl4KT)XV2PzkTJs9S23$2>qRZ}d%O#I&V0&CDEmb%j;$sO z(efa3I=Bmo1+auf>B>p|EK4<)J!|{k^bc{UvgU@3OV7 zhx^|>pPZf`=6Db*0WbPrYjeMwYu!7#l!NW2?hXEAjd>sjznXt+51!__VQUu*Ocsx1uv zaC2p2h1QM6(58m}ln6>`?1x+1t7|O^lP7($$G+zK7ngTV5QD+WlkK&&)wS&n{x=>X ziYzq`t(){Ca#QnX=hu|fu+7#6keNMTYcSjZz^Xq$?q25=+r}l03q*B$lbcs}-%LMP z4m6ZJ7(Ch9TG?dQn;az&RLK^ALK>``M#E*Rt7~f;J{3LwefNuAZ^Ya6T(dDzGV*S!biQ`b*qcDK~nDS(c$UI(Lpc5 z1EImD#&vfSmJJP_e|>UvcHG;WzB<3Zy6ZjqKYF{v0Ti^mu>wVKWTH7Tf4du!0vs7= zj*K5in1`c`q>WX(N_52Ec9q=Q-PM&X{me;j3MVz=q;{OtkdwDmbz(kk>j|9n2u@u7 zsJFLiPhX>iXzaNSMUU)7&qIqtpq;~ZSJ{d#w&T1vHh;eT&0`-nTNSd7Xb3HO?e+U@{%B>ryTl$xxn>uR#jo9u0}|KQ%i*T9s=`-gk`hr8qbN&5?XC@;j| z?X0d3dplz~_-yp`ewqerF`lF!5&@lTt*rG<_P;(j+8v#O7iNEkYbN8b4@akGC;RD| z$zYA0^CrJLIyv1vI|TqZIn8HWBcLX{>ST3=z0TY?n547a_+V4hI9c0XUrDzDw)`3# z@!9_2S?ambA9A6ZQF^R3-yWjuoLX3PXkTl@urAqG+3o9Bb;+QI{jU}BfEoD6|@;q@Gh~p z@5~k)8WESc8vbfC=I)U7YLPN5h#2g*Q+$TRcw&`R>J_$$u>FmV4s0YQS%+id&2>ZG z&xm%zxJ7gquWzvO-}j7UMY!U?fwn5*DE=F0Ap}Qp-vF7$QHlH<#d-r}!E;oP2dXc} z(XN$XfE72^xq2kM9|mhOy?SNh%qt!y8K}8v$-slr;n!yndz|b=pP4@=KIZY{=>Oi| zMXnv4BE3g@;85=7D4)t+(6&~5cjzdznT z81FPm(Pn`L49aASb*hv7|8fS)?-QSh0%vmtqI}dFu`2_o@uqf**xf*?#0d?~Eg-iBtBqpr1C<*2Jng}UD1sH--mqW3ms4DF$5bs2A^ zwyQz0)!1PVyQ{6vS_;pk7d;Zat*#=bBBiti6hDjVI7#GiGAX$#ajj3`4s=MLM6;Yk zwAfK*E36sO%AWNvc?11sE!SkVK-m5&T*=pE`s3Ak(%Clh&=-2uDKISliZg$_wvEU< zKHE7MPktwa_vlbIS>xqQI?$3g8KDM)q_j$P$zqd6VJ6!$QVMhxfpYTg*yV|Axj9dm zpxPFy_*Ie7c#_yP676zdnbN6I!x3{Z=xNj1=cgy5!^wdxl42*BGv?<6<6%n{%NPse z`)~HY*Wb^7_ss#pNsX3%Xa0`YHZW3o(%0j?;@vP+L=YR880G2Q6mGmb#5{<pI{9b~2HJ9YvW0{zD8e<~Sc*_Qm^9&J8!ch}AXO1n%|5XN3TwLXWu%Ayyu5!hK^JCL##TqVE!)xH5NZq~~F|JpBFWF{5TW zPwL(Xvu?ROe!9Aj$d-k5Fh2YSsG%u|AN8KD4qd_SVmV6`Y-3UsSbrF7;8nz%v%VSw z`pjz#6`QzFsU0liG{|AXnoj?Q`7kSNmfURzhNkZL{}VSrYko=MU=bnP5eDP z>4(WZyOmsD{2>tU&}>Yr-mIpP>qvaK+x(&7Nm?!V)P{| zKK54usGep{-aHSGxHYP0I8O#EFiKmso(0Xy&s=jdkY_iil{thbt4NDNtKE1ren*%D zf?>iV)h+W)+lm;WLDsvxa?>eCz;MCNm?J8Jh(p0tQ{$mkkF1KGAo`%KOiW@a!h6Yr z>y0PBkIAsiqT?wj$!udsKBGnw@|TXymq!iJ*?U)z0o^?xT;ldTcMXe<<9g z$-ZU<1(gjLu$8n>)JDS9o|A_(yL)+m_k2Q|4W~@~Nw+5mh)Q>zjwavij82kFVyxAG zcK!!%HX&8G)cs%>Km(a@Ky;SgbQl_=tGzKJJ=u~DZ4XOm3UWu&(W(iO0iPl}WrB4B zF%Ltb{KAicV_ii?#@8g9vmEa*ehZWxew8y0I<~@8L}4HARTTPW5Mw*w$=2Q2#ozEc z&j_DrXlv#;P-G>%c=!UJe8bRL!G5u$Wju9gp4l+NMq2{UMPi1IJ|(sJ_Kil^aF1OX zZIV@Pg$ybTw-?29($L65Q-*0Sl6;L#TyX&>?jJmr0}=RR@fQr-gkV5x;GPocTr*t< zRvU0|Q>wdz6;K#lCIG|T-&GHq_pu=0FwByJkU+%@@W-Ym6jJaLa1J4K7^lb$^xF9z z6D@HAUjJGz=>2TDXvlIg^|2ve3{ReccpRF>SA$7GcOD@o@g^f#EG8wI8})BXK;kUE7wGs*};L{*WZxg7pe4jLZ#^4cbbt_!J;>bAf4sjN&DsxB$9XX#k(BsJsTfB-~au7>RW@C|3(C*7uu2~G})3V#nGga z0wnxRH#j2TIU)t&S;wMR!CM1We5cKXy8}tEdclPpW~gv57Z1)~Os}H(;3x^B9jCF( z-2+BgW>1ofLG-mPVvG1NQyRw>&bhW4bPz6anke45DDi(|LcuU8+9I0Og^djFtQ*qq z%?rGUudD?iCLSyB$^O0?R zLNROJkIVtt7-=+n$~ep{?@Z~KV?M%`BjivFNjS_g;%0$P=)2OwHQQ7WzrIT_yX=LQ zOAAF~vNT>Fpq`z%YPqHkh(P|{cWjYxP0#iK_KY(dHqtAYFWygvN*oVhzCjc?mPe-2 z0wnle{#VO}bBUwzMdENo)@=&{fHolOhSNcpadzunZd&^IE3ld{zC;hb9c7AJ*Vd$l z)kk-}5RsLQB1EYitx~2742mHNap&@@9VQzHR-yAniHt*}Zj2PY6=5p|c0xx>)^r7W ztw=f?AqiI&y2ESRav&>AikU6wwf-I3i6*dU*YwM9H_RS&LL=QvlL|soU{+!!1)%TUs z2Q&h-3xr>Wp>V-maU-r`%VaDG6=Zn4f%f?1Q@~Ii04H;S&`vFL!ENh=l`?>qyI}gX zpkN|r1#4cMWhoYgrmG6982^FNCt`I4A7>QMKoGpn0*+6 zC<@F3lglKa1hn=Swt_V-0ENCG05J?q0OIQ)Lr|3s0eFf>wlNombeGK)f^8lgtlwq6 zu`$ssH5>=`PM5;*4Xc`97E7@&4ofL@X%g- zwLKE0ih14h(Ia!OyFP2{2slsa$U~1(nADKjAt6WO7|IxIAvw)nkMoEz)qGi zLue*5WD9sN(tnmpfW_lt4YEp74GFXo`!1OG!|6?kcc_gAe~5tAV$=#*4WdmM#IP*_ zN!l7|)z;Po%m=Vs#3$+#AH(lCmhpHWB3lGOIUN$KOR5{-DKB6U6q`E%>)r6JMJom< zzDOOxpoof5GdaQ9t`uE45sD@d{4-X@AMBg|hx%0uqY=>PvYd4TY?gw zWX^H&%PmKVPcDHJOx17ByF8!Iu=3{8%01*^;6Vi85ID=%Likb(mlA?;xi!6S@fxb@ z?DX0G$=5KBNGcj#5Bn;}kD=d#*(kvH{jJXt!<>n;ITe;4XeGDf828 z0_C@%sg)5U#!-0Xn63_FM0X}3*sIXVl^&@`FeGlb>ZF>HY5#A^X7oRf($38t%O@aFKXLd0`y0j|MZEUzk$Hpb5$j}n8PL#L!$_87 zf+XUCwwBXpm}W_h5XGQh9*|Bkj^6BowJj_bP;U5>>7Ov9h`A8aVMd?;`8;HW=!N$= zArSb)AWER?-E=~pc$~;i=24TpEsMoW5}mkhoeQqy%mE&W^zi_8Q5# z;mgQ;x)%smL2{o3n-s;ulTVXrkF;Av+#Q;}McKxnrYCI)PWw;0=87R8}9&)b=7k?34x?xI5AW#~s zMoJKqM-EIewoMS$Dgg)fng+f@8pM!uauAx?lVS`a$(aN&Ody-(4de1W6|W0m z@SI@j{<=J9iYOTjgu^n-^msPC4e+AFoDA%$TA7eyZYF2P$K;^PMw~_!F z8&bK-0yc|t^7QyQ`S5ur=0m^d0mNmUglZ449LYezTEAB-t>zk1o)H?-)Q7i>ulJY~ z!P9TYthftiIa^^a$Tg%Hg$lZe*XXE5* zG>o>t1GbY!`|Z++|xK&Y9VN0|0G5NVz4tA&AmLO zE=DmOmCP`>JQ5sZoE5i<8)~U27UML)wbFoZZ-0C_+gyEeaYYD6%5Pf$?kOk6l#Em9 zG8`(o*ZO3FPnfQzU0$pM$aZ2p^@$;V%89$^q?zHwT}H?uepAW_zaf5825X>E5)?cI z0g;~sVl&p^>VTY|Vu&XO>KzHkN-`qBGEdZ2OgZttbx3sQiQU?oU9o` zR-B7L9AEi$(QU^FC`zr^7Rg3i5B-<0!)3qYCWcEktwLgai47ZoqAL)at{^2cEUn4Y z9_(8M5ol9(`!$Okj*H z`HJL0)S9@UpbC!*;v8V8W?D1Z;MRkX+DQy6LF)i%im5ryl#B)`vQ|8c@n0*6uCc_tLea4s}#agA50vwG9`Sy!?hS&)@Tp#1`$W!;u&4l1nBY#atUjkF4F%BED`aCPG- z*T7|$4GK#pQVJkWQ`%d?lGeBmx`LewK+i7UsfJjX!GS1|XdOY^U8`T<;*1QdN|GtN z1{KnlDeg1QGx;o;Xgq0wcFTRm)Uj~X=DUWM2;tZ{`h5;~bbqwztX;ml-VLsW7+=lm zsZqQI`7G}|X(x%WRvIczM70u1WFj}o3hNFq2AgW9pQMWG< zSZc+nD?g=pb;wW4=OO@@2(IS=Kv!HA01VcjWi<{ecroP3X$6T%@UTAC10Li$S7u_3 z#y2EKFg%*<*%ETfV?$UceHu8SmUEf>DTi@XIwUey-LJIt$fxktO0FgvN*77OGsly1 z6^Vy_&vaSE3M5#KB#)VlWi^k_4)UoQOmdCtMg>F^j0%^Sx!9c?Jw2re;eM2-MxTgDg84;I{fCSb4_hyE0~htd)|%QG(rK zEgVI-ip%JzYlm{5LAQ5Tks_ zdT6bNh_Stz9g`(0#r2Gd*gBrHZf`!Q@J|`*F#swHOJkzZRhVFmQrloH)MWQ$e0=(R zXMAw5b2K{HD}80O7Mp67V1y8nt=Nar+AsOa5%CeY-A*XSSqN|-CPk9DESO>SZG6bQ zPi@5_NOW~MQ`i(Ez%*S*;Arpa^2OT^lmBv1A+(#aPfuwEIe5GngjN-R>=V?Xz_|1Z zC&u-N69l3Y6vat-6(m$C_f046LQ7e7BeFdBP01kqHXory14o8YqE%heFoZ$U$V92J zR-X0hSguvXs1?_!OWWv^H!5!+mf+z%7RfO8rziVWoRn#Mx~aSk1@+R;arR_Z0YInD zd(}^_(f5p@{;(yg%AhV8oo6wyY6;XNB{Il0wSU%HOP%t(@wTG-T7rNbeKK!1R7{?? z3gkZv&fzsVGF==slUquF<;a_G6ftahp%}RW{0${=gb>Jvuxmw3{B752&7fsT=xEm( z9c_t>_{Ofakk6KAh>S72)+k8XWBSIP8}i9SgIk6=Q%}+Uw&#k*uzBoSVV7qA=xEoP zJGdqB#y9p{i8ubXYc2Y&#UOm+;J(5Y{B74NSi#?Rt%WMIz(?QMwKC%j+0)UUD|nN? z?OKH>_}i{EB_d2%-{@K`h0;;a-IfUF$h9bJTUCSgk%&Bq!gdNZ#q1E-0$4g!$p4HA z(YSKtIUIQoN1nrxK60dw9O)xR#)cz(Ut(1X{g2iZ}H0*e+dCxS|)7CN+ zIiS+5b;$PI3^}gbPnIn~P`Ki-n8S+s;f}hf2~fGIrrIMmuo08d7`t9Zv}9{CvW#79 z*AV=F2}Ek+rM0OzuMT2qyfjjxXjE*a4m}Gg8n#3YZAi&@VThP;Y%&UYeLJF5_6{NC zy0qeVO&Gc?QAD;*1Zn6J#&W(Lx2;5daUC$uDq%SgUV2WRwyc6#Qd`*t`Xq|v zBy#2it$3LOJ3%e_#GsR#AV*mz?m|oTX2gl#l=;DLbA&!N7?~tdew9#k8gO4BZ`;a( zGZ|9Qv0E?`@>VO1l7_YL+h~t^45vhf=SjW4N9t*L6i0i8dd=T@p)Co0jtmM%jfvJb z>S!FUL^=MpYrTKUjNu#Wv~#j@#!G-iT7=H;-2TL(Y0-dA6!3_;82rLrb>g<1Orvu0 zt0eExFaaqVB4`51rhu=7sYOEKMIHH@E8HX#cXiPC-yuDWU)C*UaosW&RWAUUVEKyc zmaa%?T>Hjkh(>{5>96=e(iSs)Cq5w9RLgzUHhkz#jis8^GsJehSd3d&4%v>uT|rhz z?yVx5Vy9dJG<`s01T&)JaE8EyD2$?vK87Bb*g)gOyEWv*UyIQ+Cgl0skuL5IY@Ogh zI+njRo&#TGg5-eS2vsIo7i534cU}_>q*Jc!oEVp5p~w!jQ+$soJwb$RL_+)^TBAbXN#*P># z1red;p%M}BP$eSZq<}~5s?dGNq)gprblctD9cFNGq6w!hX?6=}bWp?J!cpe5t(()f zE{)GOqDU>n($TocoVImy+SVnW#Y-jwu%qY761TGnyTN&7S+XkIM-8~Ghv)2MvP4`V z2J#Y;)PhW89fP@nWIWuok*$8ug3{4&=SDFwoj5U&a}7wLptloZ2qQIc;v5Gy*i7}o z;`nl206t3~GOii8tp0^07ICudRL&mrR&~h8CkH#Vgi(uC+Z)A)H(322C{^f+-%Kuz z9!7wfTthRts10o2XrhN^a;e%T1Y;s~!$hjm`t^<4Y*_xcmeuNSi4PSD<7nbTIRpAz z;$tI-4=aC%>&4qft@`xnU~m7#LR#)7KcA4ZWC2b!B{L~? znDGx8#GEW^++#$1lKK3|>o#x_8plaRTQ~{f)Cq!OyxcV%Pa5v*;x9DTga%ER*Kk6j z_r<_mOjcNhPSQkS?i8~XVq-{)wjmp8m|@~ODF_u6x5-Z-+K~qx5RPdqDwguMS{DL| zafBDFkhG4FuLVtYgycB#Rvh6Yj?92qT&|d#xQnXEIBJ$5)0xmPQ6IzUm1J8&6q!Kx zyc8>G-Gy;E++D%XQThg?!=x53tXDF@BGC~?ENWowmD!TS>%3QNc%oSW47b@grKM`x z)%!H0+yA0!+LA;=lSD(4L@MpdHztXOCW(fUM0_JDHZ-_>D6oLP?OF@u8(@w~v$E09 zbb{kkzJGG;ti2r2*y~g}NfK?v!HkJVg1WX!XyCaYqt+SXFM_V!wQn>K! z`rZADD=P5_8Elk{C>d$Uq@t#YSS%EkWD@Ba%P*yJ4J!zzWMjtK00tF204Ngq!yA^-Mv0 zCN5LjL>4lMSsj^Y*IF!LkmWWmM1fjkMvm4VI<<;Hw?IGUG>(}LlDmd^7TQw&&3!Gn zB(Z^)XKaP|T3>j~4{0F_m}JYOka|{lbLZwyQ8|RTsz6Ys-!xFOknc;*!7%!GT`5$L z!GCZa+cqG6GYT%wcNr=41P)R$SWL9!b_o_$o1ph9W4m0c0)B&lz`jte^UZQc$Alvn z<^$s~z+)!$Lh73qJro+pwlU~04G)X1FQ4n7J3#fBhRumuevfuK*kDtHYAtEQ*pP|k zhBZLrDi61k4s%K-y2t8~sAbAOn5_+cVVejng?vt)9~~<*WzznlGc-uhNSh#_Sx7qZ9zjHph<;%lDhS3C z=D@-PahqHRem;%qVgrvOA&Cm)yQXUqIwLt)Q3cy#pF(42i+ll*Dg=-8Gr zRL^VF)O_6Bo8|HD@Ah}U$@2L`Ejvf~7mfVC)(S|ycBo91x~NJb@6f1l`%>zU$h8w_k|4frDqEmL37hkY#9A`~NSCb0dLHY^dssq8sS1)bzJ*lGlfFI6;AR*!>; z)omidpqPsGY;@uUkP2876cq$jLohw$+qR>9WOZqmF(*TDf;D2k^E zOzCpGk;97~`>9smG}8WKx?D0LyP!mwXk;f;W@@YlY5^$QY)0^z5-2>RztrpcUIt{L zS8tG&*z_v>nj7V{b7wul(sGCgRAx8P>ab3{EGIiB&V2+OJw0G zH>qHf!g_AMsw7u3V7*%VyfwidU>RWx20PCKnz8J;g*0XA0gIJPJ+YFafpbksTdSvn zbyeAq1QS}G!ax~9YG6RH*}Xod7GP?_a6cCfUkCS?Kr(5`tu-|kLZrNw^57)An6Bm){|!~BmBBuOo% zEOKW6s1}5x%C*VVYr(Piv=|rvv1`tpZ1#pW(1088VkZ=aKJiSQ6kOmWua}d2WKIxD zA^<*%^}#sSsAdF59vnRH?#@4`hA%hcC_i;uNFqllilewx&>2VNMj3RiBVFN0PdM7O zs)o(qcC7-c{B74-N|ZvLd}9?R*n-yn*0od`H!0+!q1A0+519oUP&vUu*aEoYg2h|-#NisO z{=lmUPT3)xgj6xzluh_zzAb@K7T>fgzXz{cPKCaWcIk26_?Jt0xTza$V4XVss0^ z3(A?7P-Vr^kTRgoQF!_OinXGkD2E`4I3Z!`|C*@KmT2S(vWf$Nu(=WyHf_~x%{uE$PUV%e1gep0+)i72p9|yMj#^e<8Luy2u)WjAJ-`5QCK{NBH z!tt2R#8I+bEX5|=s&{-oQ(^c_$%pm#h{D(=;cT!}=OeHpGd}CXnyGvpDOUO-bH%D&LgQesqSv4s*Ygskz zmFWtrU60uEPBJ|>!6x{u;&z>QSNC8^rCO2W?YqOMr3eR}mr@~NLGjl) zaQq1R4+{Rc6ofaoq8x;W2_MG3XQ{V2025WB=8!Cd|Rru3WYc1zE%#YPItnIKPy5Z5#OS@#MN~Jx*x~Vi_ zbN#OJzs~JprcgR4CSX+pzES~E*LNwZ_&2mb`i1ZKu+* z4b~yyc!!;oEGJ38L##Rlx*~LM`%?BJ>!v$E%ZwjHb`xFCLMz=D0}M z*U|GXp#a}@H~9V`794=3uxttWDXkwep~K<|*Gd7xXjq>LYu0rYI*2WS&nC6SeIxLQ zx;VpB)gCh@$o^8nxKbv9Eh*9dSy*tktRgV%-sSBdt;jnr&;8|WDxu1}%k&fMfK)YN zX-HLRfXebJCi=RL5NcIz#$1j=B52`qj}*@nHdeong@VPrtYG;NH&2F-`OF342mqOF z59W<|Ma%cB=R}=d*S0W*W2{tyZ4n+u&kc9Sl`h};xEb$SN*GMm7&q#$ByrOQ9X*ps ziMoMjs}Nq{8<$AF1^uAHjY-s2T@;q=SOrgxh+d9{6@+w8ExC$fp}zWg6@hQE!JrXk zVa9fK2QQ`$bu)BGs3hYvzD!42lz@GbY&IfQdy-8Jca#iL!d(j!z#u^)XSH+cuD6Ok z^7bTxBWk-_`4Y5Zm~Htl+p3&FPi}kA6K%guDe4$hDh?Z!cu}*31%I@Z=-;CX%ktio zZ~8t$7X-lp)1SY%nx5QTUA;(|Zmq%9lDURy(ZZ%trc9p_j9l?@Nkpy+oEOr%$lJx* zv)l?e56M(a7)v=|NG$m@dII9;0f`XGHL+zcfm@AFvz=&cB$ZmxW>mwmV#K${;%p2R z>=%JwhP)Y<#NVSrF;jRwxeiq>MOE-Jt<r?RZnK zc&U>(3Tfr~$aiL)pRVpYjwG#NSCW=o!Qg=!9B--DVOYav8_u_;I!rns0!`*LMPNN7 zDkYpnNE;uScxhg}PR;27AT0*=Dkv~kN^k-bgx}hzFE;i>A15$iR3!8wtKZeXmY*$G zMZxW4lD#T%nits;%kZLcmx?5tgV1PhyBw-vRg0L~nj|KORfcs7?`Ja%8w3C~t6$&dxQmcXtQ0(vD1UYDGLS?wdN3jw8U$&ISadj% zwvaopiO;ynAh)mNJmVR`$Spg8g;iv6#SRtiD=&{>tBeb@9h2A;mW#rZY}<0iTdL`V zgXm(JF;T^hxw5QUDL7x2d4bNg7M@(AnY4t@Biq9a@Yc@nISOUC+&bi&Sti+p#=v$W z{lG=d=$0>|l=~jCin|BDAuZ@dWMy!$Fp0Af-7;F%hoYXq+xAYTx?mg5IpRS@5>+b&6noI3*xy| zm{Pui@&(jfhKNc?6v$~1=_%|Cn=*ilQaCn-gq`?!0cB!WQ|1;kkyuS!O&S0TG9_go z+0_&!sBrG*34mC53X7pGS9olIfDWcVru|_pjU?2mS*k9X`+EotjOt~4RrmTFZCmOA z?mME95H!ajCo%i0Q!)dW7IOlC4cs5rGU}Mq3iT%1@8A)~z=wF8kw@Bj#?FqAact5= z>MeSmx&Gl<%}|g>o0XayZxmG|z9@OaVmIZYNKqPh4l`KWxl@Gf6)|*yUTzLRObc8C zt+pyjxylstnvkR)RqLTEi|s79=KQRi85A51wstE6mf-|J7t*>%hb-tJ^Y!=7_x7KT z&JIq~m(LN~RM?;;w>{+~w3ZWQ=RPMmRiDJ>oRC3|n>_Xf@peLj>l5lqg~sIsapEqt zRMzi^9`l>FVBxnp*sU+`3=2c+-c>vGRO@@9^|YWmw5{<0>}2KgLTk%vo{q4!g4PWn za*k3Ngj_~=2cXPNEV3JbsqqzuP zBLi_cV4fSff6dWs{G7ZB4C&>4y-gvA%9qc~hhixPn!roVUUgosD-yoOy5u$K5g$ceVgJhap-+1_yu>Ju8n;R$(2$#GHB z#2|Pjw4!+o-I2BT$yX?!(J`*+N@T(*?q z+4iZZ*6x}{^~@?&LpRfGECFiKoBo|p zV_AO4Wv%m%!xjl5l8j3UttDDgz?l&OT!YMx*4MmB3N+-E6}qquVT7nu9!ZB~Xlu4G zm=b_Lxx0DStegS~wMPgX~Pt0ZUaAmK=8#*-D zW_2aLkOu&b$9W0TC^PsyRsx8e+GN&%3hU614Da+GRnf@uT-H>piFHy20(o|fhd1M- zB`K}cC_ruLP(#1%=EWv^fKB0UZ(iN~ar)sl zt+S#9?0m|JH*l|*z^*JkeX=}hP6!D_!w?d__|{ISCVhh7RGgf|0ZWTx4qw#>f5^|*BC7?Ka zZJ#v~N#cz=q8+ljEzCQ=omKJitr^R{a0oqGcrg+aI9_@v=t)&TxRUsi>DQcbvp*>6^Ty}MJBN-7> zeJt=Oi_3z{_@*sc0hi!WWTBfjOVUKyVww!!k{tvASYlpUr9&i2tV=qr7uOt^`RCPE zy{6$jq`{UkV4o9|IEnk7R)5X$)0vfm1TRh;PbTQXNqj_yK!fhgxcUv@wcck5{K>)le$yBp0u%gPek5SEJFs3wxq{j8kUB$G+ zYxI0ycB?``Z`B>~ktJ8eH*Mre|8E46QAU_0Dm27Vom#iN+;syN*9~0M2H*M~Uc->m z=&b|9=xEmp8Q^cbRx`xkngBxuIC3qh@`jd9SP`RoXuDm;ijG@!TY1r|^YZ)P(xvkI z1YuVeY|?9%V6JKaLMUyeGABC8^8>6#BD+w<#VH^mkzGlT1zw6<>0wV*#snOVB%908 z>KZ;$axNn=mG=O)nZo>2^EqIX8;GadB+4t=L=TbaX>TUHWcxz8sp^o-bRN5C^@o4w11=jr5tmq`Vi7#$~o# zL?H)#V_YWFo4<`il_$yA@D$@Xds>D~R(PmJQtZsxBVXE!GY(j6X4GnXdZu;+W;Ysv z*?gmW(^%^=_ED zo&O*$n6(&`j$5WwHFcO*ckAZI@ICD5dxFnz8B9kh^vH`14fP)>)nn0zC}h4*fJV=yL6dPOfxD`eu*9`eW)#_bk+yG?2WrwIa!SiKFkV7&Bvx_Tpi!&Hqmk0>9Rh z!5ool%x}KDd>$a-5;MNS!TJ65%Qx=*SAm~lq&VKaRcP5`N z0o?i`*p{ICXP2*MLQg3oem|Q|RDAU|&IYDkX*QscM}nd&IbAm3LMFBrTa;eHMTjlp zaCxJ_*P`Y^RPe29S8JK{0tvzL}TDN7ZvqBxa`QIlj7U(xK5s2ttzz?hAX z9@#V30>B+G%@xeB*r1kP69?N|4#fg0@48|3nJ#uaQemjd`Ru4m;gKp@2GOD}c0YESW6RQDbdMvy!2bx8&IrHA}R5 z@d`}~86cw(i9PmNYUe`R(<-)(Rvb}B&qIm?i9|6g zzPrY=LoZ5SSs5yia)DYF)?ituoQj9r0+%nKA*Lbl44q6VJMtqNm7Usplg{XgBY z(3t&)Yk}NShFM(9U8*_vslT-cUTFCuL(dR*Q3PH^#PpK$=9OK9%+NqUj7}zWpsWrxpGW>s={(PvKT$CJZ{oxpO8FemX=!gW$vw7BfHqR^JBX~>B} zE>WsFMv`OMhFd8yyR(T4T?Iv>bmF`~?+ndB)%(P28pKQOB8RGnma{Tc>IUC1Qx=BT zQ4)8kv<54uDatu4Y{T3yNRRSDd{7#^{m&T6?02E7)2lPx6X zBi|Wrp0O}+rL%?rjDzB0z6mY+4o3!fg@!%%+pJj0`PW0zbAJ6gY&T`eef(;Ku_isP zxi^%D;PF?{cu5TXdeAWU$-<6W^T`gI6M5 zoX(~(<-}u7+CC)y7!(#XYpNo~d$VD!f)Hzp2FVaJq-Jel;+F4_sYHuN%bXVog>@-= z76m7v5KvJbyB6GEUlgpGRq?hBx$!?CH!Sw<8&#?96;i?=HP6Cxi+95^Pd1e9&B7L0 za2t@5j*yK6iKYMIJ_n9>{@T5{#(+T$CNP3gDS5D54G4=wEVx?Kzz(0tegN$woG9hSE`vh&izo39MF_ zyjtjGOQ_~&OEZ3zVwjf(Oe&K}9hvpKAskgqZlDK&qZIr|=ml06m3EGgmBE-M*9b2p zSEwpYUI=~BXKuY?#S&W?<{8*u!~6{B1}sQKyI2TD7`>9hO$8W|2QXLXvqG?zvIxPB z0o2Ugny`0ql{v5S!@{lN)>wx(?|amEq9GGtJJ#zc8%#?Vb#!CdU^EpL335{TuDdt4 zcTy?80O4bz3-VEWWgs768)|T9(Vf;?R3s5R&^mfA6{Th{gD2uGr4h~h!8rsDT#(&i zdk1T19BRl)-KLzELhM9AexehV{5p6snZ67P)sw)01{R42>m_*&o5j2aH|I=6ugeT> zR)b&kxov_V6~IEuPLb_U0g#SNCYE5EQD{`GY8`RKVsQekv4=S<`9ARIsFI?UmpUgPd|@!w{Me5)w9WL1`z``_+w-qE>!qxlD6N=CpMYao*y&v5XZQnw}WD&>TKz z){4m$aYMms_d#?DaU;}DS!!ZMppiys#=z}6l!Z+4?lJ7H@OCREO}*@j4$j`0T8}lO zJ+(mMXn`yfo`R@MTM=ols{JDO0?wBF!dFC*s(mmDlW=b5 zSetaKZxb-@6TLYzZQarjSu6viJ9n>T-VjMiE??+GEnc1f)hKVy@sMxZd`|4XA~TEKXA;;6R#0-CVB4#82*7G;4K20h0PXbI z5b00c5rkk9eAmi*h`&nd?S%qqYclvm%7&&4GdR6YWv1JNa8=oDWekue68j2m7bZPH zUs=4I%=p+$7UYOv}v;mzGzYeUhM{ve5;BgAs^A4WVC{+ zD73YLCpOH5t}QD`;82x0U5@Gd3I zh+i>;t;z!`rq|Rc{T?6o5G<925Lb7!Xbk^Yo=DHTZi4a zEZAw#ho#R2R<-!KHVVC(-c2X>FWHEmsTI=-b%kjW84QK0y<^lX52L}rl!#1h6piV3 z=kKrgDEfQzI$C;48UVVj__3LV7$X0be&2Qduegy0)Y4@@{pagS8n~_u@c|W`FUYS5 z(r{CkU%VYl=cg@tbls9=1F3oi!s$$5s@dCfL3K{4(zH;jN!JE-jxat0r$4*-v9V$kOT9G= ztiVk|Kl;m-qV#NfeIKYf2BItDvdP_Mk!J9y!&z-JVraOe{GdoAE=nlIX$!nKigB!h z1V>p4wg#4?1cR-B<>-%-0c^`(IWp!Pb*=efPGztXkXtf;mROx`7%Ih-%4sEO0X&da zvI9;?iUAiK?TwFi&Q4E{4tvkXw<$~K+2ytD#m9Mrm;+3lc)n1U4-G~@^vzDkl$`!+69W4*e7Qmu5_9q zBPu>^?i-mo2JD}PG*OplctKSO!<% z&XD1o@1J2xp9&K&XnX&RZJcBFoZ_K%VPC7CtN4RWhb_4QR84ky8~%^5YQ^zH_gIT^ zZ^)MBK$#|ohA%m{l}416&zR^%rY9i_ zb9Z#KCZV_&=R^WWn;oS^38i%eDKz1m`zVcKE`;c579&`_VHVU}9n8*>UBH|ageki- zx;exYS4`zw7tNPS?umG0($h3{_nw~|S%UZ6JdMKc?8|)x&$BIrxr_B+5|(4NjHUz1 zwSt^vY$fF>!DU-ieLcImf9IhX(XzP0cu5fGaXRk>=gw6f?BOz-aBjqwO)v-@}K zt7p%!EGOg}eK1571q7ms`t*w`7-Uc(sx`03*EXn{X&jA0MlWvwU|dPHylAK8)2^wK z27y(J#`xNcr18_VY%EoTB~4roCOlpGm7#n3cJM4)yVvQY&+eE9VxE_cWkON{# zp^9aMo@IQDpvNE}g2+~k<1UAonQYwNH)#nO0eitA# zsDMeaUmo{T_=2T0O%EwaPxLxAr(wfAAz#ogV0`$^ z{>k&BvoQW_cm$?jS25CLOGlG00llunB z{#q^8_B5d?krJt;xtUWiACs(NFDXV%JyOHn4Wl%z+l{o7qh~R?mDJ=;>3iHRhw*C9*RP5!MDvW|VUEppuK@PQ3Uz;9y2YVbPSJpCd08 z%6S1wW(yTeG8tU7zZd24vfr6xsF~!fwn)rYfW0wlFas06hL>$&(b!b*HAPt>&$P0p zoUw^QF8{V#`K>f|E}EluE!mxL-~*s}OJF7`Cz&t}6DO_}LhJ>)uVPit#?SU^YamN; za>85*5S~o0Ua?$^(yzeCh8q|pY&3PV3T-|4f@Oh8u^}rE zS{CvMnlWrF_#hC*%XAGY@UB5K8y4A8!OA#)F&q-&XVlije9$U&*R$g!BffjeLpo!EVCv0t@^j4f*Mt~gBeduX&T9MN7-?oPf zQ-A#Rp(6odR+jtf(O-!_9lGZTDuUoeEwlI7A~G>Zn19>+9NzhgkH5^3YR z>03bov&(m$S!Ky80VGlm4dziLIU3P;N(^Z?V~{5cw`;=^{VfMJ6c<7L=x@i7l&h?Y zSopq61+d7}m5-@)olyek{*EsnR7unLYa17Hw1ITM$jl)*p^=;vw{f=U9jF7Z9QnA2 z4dEXmc(G#zHw4SKX24?MGU76Hg@|#o5x`H9zbvDmn$o6}b=TNZFO#6GM9^;x>atYM zOpOZ5Dx}8*c-d=N!KQR61|=iWF8XYWUKK^uYd7EPiiK~h>Dj$`_hEMV`VA>9P#Zrv zA$g61qh~uuJ4e4yPhRl3B&6!rRa0&^KR2-Mt9GJzCe7_N4 zFAmVJHj(9^D^!S0>)<%(3Jt~4 zO-DTs8_kY(t=0$fjh<<^4M)3HfmZ&uYXyDc=-Rcoefrz36~N2icCDOr{)WwEW)X*gbp-rlD6qV_0>uj&Bx1?Ngu2lKG zrI1}uT1V(hpLB=GTq}TE0DwpBR7nMLZuo`q(1`)ji4oC>A<>C3NxDTT?WJ|r75ZT* z?PS^%$s4qSjuH5lZaIIIt(kpot~1D|byoK%F%S0 zgBEp-Y|${Ksd3`FUVCo&x)iVlbaiCpIGTKv0_Ja%k5a(=ZQ?-+SdvjZ!b<)m#5>?U z+ql}RUPMh*A?#<9;72*&tpH<(LgN=HG){C*C!Vg86dEU&bfI7(HuK7Ic7I&1pT!K^ zY;VhVFVn6Oii6%NHsZdsN4!~^mHc{^SpO;5sS=TzUQ_R5%chtPj+L#uh_9LxKH#`5=Rom0 zswb4s%tP2Ah&EM(sP9&&$N~0eTdEN=;6*v&y93_qs1;g|eB0M~$*e(?K|%8^FDEg^ zyPSEDR>fl~R|CF<$voLVcnSm56+Fm?e;oys^kDE#YyUSYlh-|`LGbm*sdW@SRFDjcU&8e(SMH|nmaDUQ{PB>4CHWdlmRg? zs6d9JNfL9FR>3xX!nNMKK1|j3X`B%A2&iZycXX`>X6uzC6?IAc7&xgGHD8HFLX4VM zteGPLzOYwjLVP6W1(@AXZV-!sE6E}7#YBR2&=&&>Fp2kUjPT#9nw>^(Xtt@9x+L_1 zeZ)~?Zgnm>>Ny)Gu~i3Hf9opCE#QcL0YNtHAeTvLR&v2SKff)Tt6*fnV;Pa2RMA0++gJZ{h%*(u>L|9&7PAykKB40Am?JK0TW-!k8{jTLs3=24Mf=6$kPkYV4D>b!q3?*WHCdVB^E zdHn{%-r~zek1rbYUcOv``udc1B-a{I53_K{fz9grpYcdu$TuhG-`-J?yZ?g*^$)-8 z|FHUpVi#o_T1-RzvM5;pM_yDl?D{va`gddW=b9R$QIU0wA_w$f-{ z-rX{G|8`HU{tLa>#r?~>+b4C}xSPIwbFH{(qLSCjdo6e3Nk=ar_0uyr0k}*ZxTvB9##OjjKVH6^_J2u7e%b#OH~2@!{r>8LiM!L3y|hA} z7j;qwfRB+MIcezL=TNnjzXni2@;~%{(+|$)>TR+uid(jQ5@p9@|)LxpxOP?;F z3f?>;imk;&!P|ayG<$u14S6btws5LYZ^u{D^V?~kbWP^P^hc*&Dv%*oLHh>RP^8Js zo2)MjnGW@8^MJ(NL6vO%6w58Zd(3^Px6m50AOt^)ZL@pKbeBbR*l6BKhK+VX*uFQB*GHkx^gyZ87Z@eiQ41Nt zwI;c7F9>v(t;_!y#c6dH)a`@r1m%ujiC+8f&#&)vpV{=s%jx?*Qo_YN6o?wPHnZBT z`?u3O6%s{cihwjO%h zq=&{R!3kfDUAK3&l!Y|9y7~gdlijJC_G1UL#t#;og?lVZvDsr6Qf<~2%KaV!d2^06 z`SQ)pEf${9iJI7SU?gce`mbg;Z-eb@hFIrZXE#rz>^VKzo$IDUb?>PCp7ckrBy7z< zI=}k0>&DoZ_m`-~nxT3ABe5@x)TyaJwB|D1TarJDtgr;p6{tOp>H;Fq#!!Ur!&iG` z2Il|__8wOWlF9uURqhWS2IjeBaaeSatBCAY^6m~UUyS$6o#}d@yuWA;>S;1kI@>}6 zct)K+GY9r|y3a+-`MNMKRn!$C))i02*Fb}=Td^j!s9K+hhz618P(b4oX#_(S?Bwd>or5nhpGR~ z^aIZvWTUsso;>(_mvY6s6Na$1S}L!=EnKuHFW>m{zoXf|Mv14U;MWJ(?{Vpw^Il^6PWl0z)ek+?M;yPf8s?W_@=))9`nJslrk})*j#g$s9$K`|>j{0PURKu92@ zGmvu0%n(8qET|wLMN~vUq$y8Diik>A!LCoA{#8((?;%fl__tse|KH!<=iGbF%pF1; z@GqZy4r}h&XP33tUhB8kUi%yr3VK#=_9RGIl{<(zo|nROYv@H^M6;-|nwq+rwc#g7 z@yGgz<|?%80}UI!L+Tq=xX}eyC=vH4eV4FGQ%DYeI863@Jki)FESv>_;?~ zo0fIwuHn!mJC@~HQ164*+$yLEX1}+r`&{gOU~NPd_-S(xT0ldiFRKX$dZdevARf|w zeZclD{Tt3e7<S7XPW0d(S`6CauFB{0&!4tt)oRXP_f5a>!Z(5G=(fS?x4dqHg;?h&e@E&!SSBb` zg@I8#SmrR`;-qI-f*R=5bGB^kr*kzXbB22T(K_U6Q$^uepUGo zFmZ2b-5S5C#}?fgVfE2Ut1M;Zj(2Z%0UE(o^rTz6(jJxiyie*lS*;3bCLnU31H0>- zmEE$&4Qp+HRaW(}L&(V(uYzUryq#7vp+c@!GkT_ObIt3hGGcgRGhd}r#KpZ^W;6SU zexU#;=V)-}&(b2jQ2zsXS9=syvQs17nQoywcB*dt4?=>Pr-*V37TQo#rNb8Z8FDh+ zLadoRTSKlgRApf<3%s9oU>2+n2or0(&c_pdH69iQZOH>GPf_MGLUE@nX68S8MH`FqnU zn(PHNSFv3z%JM=C_Rj~HCiKl3vLUDk$7av~t1VKc+P7(|JIJ5F9|?s&vhhuYJHzGJ z{;;!Y46(yaljn30k9GUUr7gX^J%q@r_D+5lq7+pevXewzdb9~1>LRCMwgWre4OhHs zb#J`WrGr59FoYZ)JFtPX77!YwMFgEh3IuSqf%|%t^#-u z*Hs7V{qQ%wSNNZDj)P9EcIjS>Ssw*(qw;-=;s4j@B??-zTT$bx zeCY*&*1_V=HF2Jmi%eE!1A1D@!U1UbKa`K)6uO9RKC@3p6k<4otT6_x6Pk@S9Y! zJnhQERrxEJ=HK00y*>BUgJ^qmYId@r;6qS)U0g%pp5i{o#vT@-GaW(JPu2VAr3N__ zojvEpcdEk*&@@XOoT~b`QyQrA^|V0sTfP54{dm)g32bCpZe8mYWz_~8Dy`ICg&o`E6NcfUs&x!t zbd@>~&@xMh80i2;R;lFm4ru_(s?-$i&TGvs>S*D{wOcPBbDZ2by&XIzXg<6mNtc4H zAZBMs;c4F%pLI7BAk&e5J=x@U%+b9&2(!4vJ-;6x0_XUI1U+Km)YT|?ll=h&Kc)T3 z)}43(0d3_qt*hC%Zu17b1s27YZAd=ZgZkBnSgO_>I5FkQTxf=+qgc1AlYrVPEMgfy zu&%;gt*R9U?#ti`F+M$;J<=d6Vk?^+z{YCqM{ojXN{xo-q*wbffzOXOSM^B*#q0GA zKCQwRC!XAoC*-%gY8I{QYhKmc=gK)XUabqrNmJ0*20@ac3c|hf&vzP-;;ePsofHj@A-G(_cnqQJ!AETIfXEj0`7lc?v^Fr~w;I=UN=ZT+>PsN4 zw?sbgmbTfB@%wi{I2{>rF=}s=5l2ne8s=BR69fQ#3Jb3km3U-+cN_FaE(==aK~WwomTDIzp{$084LlPmzhb zcq$U>g-G?l_&{$z3Pu|#;I;D52xNKW8tb`R#w^5Oiag&PMkw>UVM{CnDX51;lOP4D zx0)N~PVkpOa=d!aP?R1!P4X}m++gYR*9NAOWZwU8okl+(L0*#tAkBk6jJ|W59KXYE z!*}{B0S~uWD%u&Dm5M2gZ8gC|rvwiK;_f#J(ZeA^+woqAUX3tBB|~q9=vWf@TI{wu z+3^MaYVzB$4C@45Z`0k}PO2ng(%5zx+4rqfyTU^dQMlgAJoJ0CvrZK~YcEvp@hau)T zl@z_Bie0_gs`Xaw+(3-|rgbiG7ZggZHt4FI8wlHjI@s9$7vLQ0Bqk$oTIc=&&J9{C zJ`dBy{mP-t`05Y6SD@xl85T7cN+bcpvB@HlzFlXMs;2L{JFoM^Nx2qu!1+`B`4J`0 zr;-;2AGXlS(<1h@I!qKqua)8z4_imO6}V%80rdwPJ`tRI@v0(J*soE0S!%;jw?KiS zEFM9H`PVLWae#9X?F(4hM~jDKB9k}7Nt-f<&`(o*LxYdNM88Yn&xNkkncQQVIs;yL zxAoW+9qR~!_pNANwRuCo!fQ=HNrxvl_pKoRDEenpum1q4e|5&3p4Een3sq~CUJk2O zeC*fT6gqZTO?8(Bwd5UVcXYB04e$yD8`;FrexS_u)|!7EKg=EQjP(`k;QIG3+1nVj zaiQSQ&jvriS$|08Uya8xc+|6504c~FEGt&LRpD#0b6oC&+e@rjvOvb%ndta!xkZ7B zXBV_uVA_RiC>2Tbi0f`Is;q%9bvbg>+p|gSp z9_UC`ym~qBiWNIh%a%*kepZ6#Ym`Q%@^0n{Hz_*F&+Pt=d4&VAURBAiCKl60cmqEwbxF-cetV%gS@%C!!1+i7_aOrnxHn zh%T|KOPo=Xy*DahmZ*^8V5Yg=g!zSJ>o~6Qd{8CU1=f@4UEmcGjzz7zz2eH zei%<>ABy;@?lRq41oOfy^(+bN?pQ|-!pnS(dwD72%Aa~6qpIJipo|l!h(>T?KjgU3 zwaScjxeP<3G*o;rhiq9pEH2VGIA$Bbu3(46XDaHb1qp@<&sEl0xZ59WW_wR943N2U zs*~#0@~R4-b36EH_VxPR;#!BFA8yseCo2G}=&;q>=|W7Xf_o^LMGLCl5WZnu)kQm{dS7eDL~q2bRvq>PZ#9zQRCTggSSM+IU~z>fuY<7z{n{`fP%+Zc zF$~4nfevU`OQkC?78SAeb#iu~&luKMy;nQpEW)#-s)#H5x*E%);*II>+rt|P`^#iH zO}Az9RPQ9}gkHcQGR$2P^$<)_ns&Ugfq|L&hFDDIA6qKQ?2b3HqnJ#6Lp6!g``+U9 z?4Y}`xqjV?NUtY~HM66@O4Ys&Tsk|7F;uODB~;H`_qbz1Yk0p{fHE;qfkvM*Aj?0D z1u(O9;d#wi)q!us{Yt3N<)7gUxt*>mnXUiqT`Bi6oU%8xmgF5$A-wY@nCC>=`EG)4 zgYs~*gY$5;KwL)4o3V%HUfMITxBo(}CE{F}YUix|>#~wnQ|YTuVXbr)rS`8g>w0r) z7xuI4Mj)6h%T>WCkh1ETMTvF1V#jC9R`6D^p%lEFsNy-OPSS6~dZ|$G93*d7S`6GxSSXB_kJgH7@jpG z<2FL7s6^&7cIv5G5oerT_FdotL{L2WvUCuC0lc$DIA0WwCV%-ccsH>OhMWMz-;Cl% zp#!LuMX(;Uj*;K)#7JqmxXESV@<^aZZ=MJwi1%H2ytoMjP7a(i7(sd80cI>9#=S2|AxJMluG%5$KkCZB^;UCHW2KlU1vR^9VCb99a zsqoI>fIY}c%_#BsD@bDPbg@?$6THfUp~oPJi+T-1i4#lK&8|1?a!R6mYL!*Ocr?$0 zT&NvQxDvP`H4Z6eXx~uED$qQ#N{4Dc#)bg7=~b99^tmnYp&~W=jo<;ND8uK6a(se^ zJbJ3?_`DHNe<(L;XIdxc*Sn1sD-m6?LpU>teM?oBN~gvKb2Nw=?35FzLt%q!LQ;1; zx><4Nx)D|%UQ{Dh6A+yWtJ;Z30A%Mq#2vP}L*Fa3v(@+TU&HTbi!HhZ)xM=?b02S= z9Okyr&h2}-MuV-&m8hX%?MRiI?&;gKYVht9<6YqHXxsIl(3U%K;CBwy;y+z4`0TC4Bu8xY@{y)BN7|N^I(|=B>=cAy@Q5cE2{dk*yTS zeY0Eh2rT#CHDh9l^`QwbSheH(Y7i@$%zDEr$=)*c;Z?kS4+V zwH$nG@o!fhHt^c9d=6^z&9@4JnjEfv(T0Zt{-LB+Q!|nnnfEu)5DhtvKIGLAzTH;) zzHf{{8q)NIEk@o@`Nm<2AzKX;n%2f}r?9*ZhhQq7R}GK#dMDw{clW9^IoydpU`d%UIKwOSfBMDQ(j>OCVZqz(;gi?4Szbk}#S zY-n6q$5AI8G3g*CO|~-u!Z53_n_wCzJV`D0pA+N+3ZEU%*Um|1_&g>bV&?qd=+0%G zU5za(7d5svcJR5q2LFW&m)~+g5GIWpkO2Bm}rW$qx5_M^EakBnZHH z%lW#%O>x!(0}sw8xVuU;5@ zY|CxhgbT6AckA>o{IpOt38(rYJ`FNxJu&zx_3k4o1M^?1RV?tdynzqbE~x8lY-s9; zCskK{0#OK-Nljhl72h>sN7$K;@7%8RpNH*OcQ(4JvwmfLTXS27;`G`U-AJ}^Z}6^v zWs1u4o45W8hD?_i|<3a7ifNZQfpK#IHy0WQtX2K($1s^_P%bWtp8r^8R)4h*%nZ;j z9QF6ia1! zQ)?$*7;mnorYll9Y&0DniW|Z~jlx1Y6_|qRLR;w-gWfriH$Z;)`gTH*ji?;#kY_Ad zfi_Y%%b%m#ftV@|C459u5l`_IzxKM;W$rsxJ9?0n*6G#;&++Z6rn=_V?v@3Oufw3y zOaH2k@K8dJ2cb@dM3Shcl4KTuXJvo&`2+TPS5M?Uvi|iLx*yh}FXY5up$u~8p+PIQ zGFhmWor2T)ARIi9S%_kPWm z()O)A8_wWe(yO+)9C2+sZ1t~FL$~#9We17xM^s^uf4@XICM#6tC%vZCDa1h%88Hkf zi{@4RoAs4LkWbLL9Y~e?K5TGO3hpXTvUgA$gV>G?$5rT*>MlqiOhK4QKro7_cH~33 zNe|6P7^yk0|V3@D5Y?Tq3W@U)h*d#R=Su3ltS47q?jbdD~d*Ry&CG|Q5X z&p>#;DuxPg227L!uLf5J6hq#tB9;NgB%?#P0|QFRnhos<3@9wWA(+JY`}m_eYJjK? ztYWx6<&M4VX31b(PrdZBz#-F%oydA2CfW8%Jfpp*m93OMc=fCjPcN?U1}PF zBkR0^o-=f0D3_mXZ9HjZXIBSmj)pi1xVC1Iz7Du$vr2?6B_HR`By$|{=4-W;2WaDr zzP{4DxpTK|+cu|n)y8$3w(>QBEqu7DcMd6Z(He68zX3I{7+ z@qOo5Z&;e0>OzhCmV8Y!orpbDn@kr9e9}1f5DP0h=9*(Tf3kMN@q@?WKA{=1gRgC8 z3jB-L#X9>329wX`ita<#v3{`_J6f7M8GCdLg>0@$yR68dY)vI#*RpEO)-5n$^M+OZ zytF_y)da!2SdIDGd?Cl@*<-D|y+|^cnbq7J`lxn=s6>Iq%x|8fO(UBsWG`r76E;U;} zqAtY;+rK_>gpD%Dqq1i)2GghDOy?faKa9 zyo%~`P@}9q$Nfhk8>pAJ9nW}Wgf-KLY|+kvq^LyjT*y(b(k@piJbZMN*<5R`YhBb` zx2XJG^$UV$vYFW>`^u&S6?D`!G_@`0?&_+1IsGD6stAhltu^2Zv@HtDUO7@_>-lha(rydsWYKPiZi%vy51OBSh*?vF3(VfT7nv=# zIzGbw!95a=MSMNIp-Jv;*usaoK?`|0a0_HTBc!gMLBi*3pyc_g)&1N~6Qphrk-#pE8D4(Q(y89DWw9aBSYnM{hY^&py zaSuR^vW|2iouvGv{mo`Ynn-19?T#sCCr8@I*!SzhQeL7EvZZ6pvJ`6RY-%C&Sr;+3$T5Y0eqX-z#AU(i-2jKN*r~ zM0^VNQRpOeUj2M!mFHScYx2tvCTvoqKd@_d^~SDVVBF z+n;8M-}Py_{!MNlDq*R$mm$#w87zHz?}Sz%8iZzxmnUonrO{KD@cUkfG1~nq$POMP z(ffJGRthBZHg}(dTd28|bwRe-!gL{@rjlv>X19kcu(R>RaEfoERKgaf^2u6C9lq7< zp=f8>Vi|p-S%2g=l&l>(!R&bYm&?QOm)E%}fLUq&nge?ik>b2N^hCFv*16P8U$9sWhT}ZmpI?XA#c)Uw$5M9fewH@UPxMCnM5=ShOy;*bJn2PVmd%uiSb%{)S9$Oko!XNUAdW%`vr@q&;HP9>O~rbavV3t!DXho z74ifLT&=wia-qho{@iq>muTt0r~>>kg`%TJvy7W>c4lPs==aOkn7zXq3R$i43qIrI zHO)6C?{39T(J)qK&AzVTELP^@kXmAxq2EBFT9Ck^E!t1>%K~a_Uf9uCR;%yhXQ|a} zfx5rYk7vYFNB1!Y>B;_!2FQI?9ioHe`NQ;gxL$#GqaI<{w1hUV7* z#PIKYEMcd}Ag63Th2dKcz4>lP8A;6F9tXNf%O-Pn7^H()S=$JCVx+$;?pHg^E;F!O z%63IS#;EIQ+ZXZ>NKixyaz70{leb3bMKBb}c@A=2q^fM*zK78%TEqoyu3OgD-DUMh zXzBrBX={W;$O;*$jn)7{uwU&e^HP)AZyksZ2#oCaE znCdr`zT%KEuPf^y8J}>AM&=fLG#4)*V?D4f#sAz zZTTDA67Wf;7L%2<ns z<7PUXfnRHLAUEQO)Y=E3Skm~rIs3~QX4k{Yf*PLrJwc9&u1;l&_Jw6~Wh%d=@pEsj zGfQhOfJz^wvc;m4KpE)TNLgY0hYpmoZ^$!+Q<0_Z9#xg>=0@?qQg4cm{o?3&TQt>m zvSEHB#n5SAJJe!|K|1f>5DzSN8fD*)qlB{0pwwPUYb|*&RI)$8MvOUtNl^94GtEBC zT%vjp%1HlsG*q$?0e?|48E)*2xS_3q!m~Ufg@D7#NvSboXBmcPz_eH146S{8)^}uOOu{apm7r4Dd+K9)=WH z#FUJvl`g4NRcm+c5-uyxZYn%|ceBHhker}sr*rWz{n7z{Jk=?OR8By0%JzU$`eV+g z^#>5KXxnMy01YE$*Ff$AiG{iiay(4I;5`88;}=0t#Cl-O_DHux8nfWZFG$O9X zjH5AVvSL&TiNVj}K-~xFU`Nhgh16^%QAl%+NnjPhjYY;k?jltUo3vc79_jzcXd&-` z?}-Q$SrixX#KDnaqNFb=$m!99c=pq^T0Bp*8VFbpW`2tv$J-R}{oZm{S6X&@=4tX} z5N;6ftyJ7B=mQRg90Q**rGJ8SEvM~okQ3+x_Hq1t!QF}o(2V^C1Ah#I#oEl`cC#j5 zs^%tFL#20M$t~?>DI{9Uzt3hrrY3+f89SE;VNDK~2-q||9Qp$4BZ30UfdmH3#a0?rG1tg3v)Jleqdn{qUqI!}E z8tc2-I+lgX@oGxNEE5*uR$@Ynof=)xc5+zo8dnfesYi%mzUZ~63T224U*P4Ap>MUtFZcGwL%32E~HD<9a7eZ>uaUkp{htg?ENP&3w$|z)+a;e;%HO9dBtMODyq4dwb$M*k zBajYgWo%?a0JI9W7;-LkFwpIgy_y(=;pSClS2O82a=+o{36V|^>CS+6+TBlqW+>Pi zd_x8ES_sL7a<;33N<@ONlfPK!Ii805yYst)ULey>Xzzgds%mWw9^sJ;h3NO~z5*~> z#_oiU%8CMM?;L=;uq|6bxlg08obXQ>sWL?Yr zYk(Qpi?rKcsEV)`Fu^7-^deXGr!XLSqL#79E2d`cOcydD)@cXv$XL`5PSSKphsLtD z1(Jm#cj;!xBd8uT`2?iql%YHYDVT+^+8eQyx+qGq{gj~1QIQGZnnxezfIifQS00-0mVmQptcE05{Cbzn1Tdl@VTkm_8p zfarKvM_Y3!O1BLt%be64Wr5QYm}(5jJRtNOc#8VGohLv}IgI4jA;H*LoV5u}9&gb7 z6_D-p1T%XNBur0%%RT`KFa{OT? zBW^*Nin;6qEEmtyw)>geWSu5w^p(T;*dj`B?5*^qeS@-s_zF&3Lq7qCyg?swuwpbtm~*;4ip zr1Upd_~<1GF*b{V?15wkvlz(xAsu?dAA`hJV*c~?tG%2Zu2mSPSyfc}E#=$FK7xV+ zF3|gv$xcBj@LsZeFN?Dfcf%gq+XHZPc*(x_pbCK0GIk|3N0Ay^C9MnN9Kr59flpM# z1hA)W*YL!r=*xgjpam_e6YN{G21uDYtioxKpxhi2(F@7y$)XmYfdm|+3R*FDKM*(l zS(|-|*?ZtLzSg8x$GaSweFY?3DquKngM__lEb})YQM_3!;@=>NC~2d;z0Kn}Z0e1W z$Y+L8{1Ot!4VkO8+IFWlfZy1MH3~n2E#)^{bEJ#AD+ph*{NRq$d=1l z(|v%B4u8?r<4|JB{@uwOXfR_x=Jzp7M`P>KrjEAOmd4huaJ9e4EjDtxo0=P%>lQSY zwZJdj?>@gZ@CaXWKSczrU|R`qImC!#&t0%a%7ydBeAcTToU%nHx+RgrDZ3VuDa~R4 z{}WOg8OuAq!>NG`W@HT{1v1#)Peb;IS8mVfRG|Ms!uz#$U}xZ0q%8}1ATopsZiAGk zLDjEE$&F(*0Yc1VmRvKqquhJ3YcI+5E@U zBeq3}Or6aQ#U2FtO7<3(Q;4Wa_BW^UF_0;{nPM0y(kARdNUVDryJ+2hdj}hM6eJ#T z25Yws5;h~u89R$GjwF}>cgg=D&zs;5034BK{tChxn%dbZS07A;Au`rIHR^qTXo6f&F*BJ0%j%K)s3?bZI@pv z#&b|$F<`r+t*y%*JuqQE5oklqk2*;`qX%i53b{Ws;Px)s>*|+8VBxW@7(CY$zko~s z+@1?FX}2@8X@%JX5(Ulj`wgU| zJjsS4Y6*`d>PM&87kX|UbKy$lZOO?A?52wjm+XDh9Lw=TGIlvPR7igCPoc$SV$c(p zCE`08n9<7s7cma1o9uFQSRMLoDo?;OA?lJ%1$!Ve_*2rEEKe@eh)d# zn28gX)^&tR3*o`~&? zB<-%LW>bVZ({{eA&qbk2cFQa;xnSlC-S2g%nYTj`By-q^EgR$+6j4dTVA%gj;6pH! zp!mBeOi(a~@wp8$Y0W8i&+XR$ox|NzzK5*4WJ1`7d6koxc47+<%G&?oFjGgUbZ#soT1XI+gc+Edn$!x zmoa?PA)TfIzt4t_bLsh^=mb!eU28B=Ud+YSJ&#BBm+Y`x;3{Q5FK5?6u8A^< z!JH2MW4=kGvA=R#2nR)Y!f63~N!#U+4!-2}z}3rPUmfOCSnB6jsjZo)yHXOE&#` zVo_wjp&Qc|-)fjl`Isn>u+VUj8)YVm;(y^9No}P!xC;-x*X&1;-k^v^O3t!G{2~RrM)7cGjk)bnhLbj#tKo zQ*lm*fNLEh_bT`i zDfNkH7P%bj+$tuM&enS}ixGGqB*L5qyFLqvF3q5g_Fb(B#w4Il!D*HT0Ru#iaf<>IJq&$mu}yR9!k>@;(#wxnQUU{ zD>J^Ik%}=VBCzP6@fZ`5)fDh9*;!aerpl?EKHCSiqb)s`Qgqs-`lAjp+jD~`AbYKi zgPaSK(96d{vJ;$V)vSYD8fh3k{{@nUX2{xTG5+4E79!~YT8i$~YeW!3rJ=iK!gd)&cY}$56EewR^F-Z8I!7Ba-U1Y>E(l$!6ak?}Uso zD+N-l6ga`c26<=glQckLTbc#^El7vf3ieaTc3I?H3k)fx;8KQ09xsN}VP)n~ zqkhh)!p&Dm1xEUh>-x+@XG+0vB*;=&_!d#$40%ALC`RG{!cfr&e!;#D{$si3u!omX zKDOnRvtD4r@u*fzFv)V{o{U>+bXXMf{1N+O5h+^^)L zRSanbBsw6A;k*LUfwa8+JEQ|?Sv%ltF+Y|BIh~(a>{;yLOvrZU#}({X7n_YA0ie&> zysgS9^X@{)?mSNAiQ=WD!mjQy`#466jS@;Zc1nYMZ-J{6Hz8~Ha6?|LGEo_7DAhH)Zh}nDbiuBeXQCFw0q|YRT83 zXQzR`|#h3MiveKbx2&i3^ro?wxE|qTL5{oz=FaA zp9EpV1cQ(97(jhv&()K7XMPXpqhe!(1Jr#pd_Idy;L{-Cat>{~&69a_@RuMZ ziM01Lqyr~K8@Ju}4%K}+B>EzQX8si93L&7JjX6&UNN!HbF2)g>uD+qs`I$7EGyrxM ze$=h=760b?QG=WzaC)gY6s!c0!&<02D z9*Kod+ZqbV{G_nl{m{#m5UuUH`Uf;$b%@xv_*t`00Jdb$PF6?c?iB4r^jM6stePW_ zkz0=trtP~tr({$t%+DbYKx@>pAxhHYay6~lYH;mrh_QOon4nQSf;{BWn3Et`NI6n4Lkw%t02yEcy!KD3MYN(8#aJ{be~^b( zYp+mh1AJt;t-jR7=s53UmqD@~b5#C)NC_?K_K3H-NI@PgeE}pwn?bQ$1W65&vj2vh z5Ui~}y8_!8%f(`iZJ)1PQrI9@X-bC#7oH1k?eSUFND>O-^#HjktVEW0ZOPjt5unYiT?2WDq*FNR zogY+l5$QuYuf$K08;>IY6lF(g1&WLR<@^&+hStuB=yiHui&eazLX)T)qxdz*@vgdH z5$ElecF76CLAEe=wHd`aobvXB%tDq>@is^aE5_mxNHG~>@fai%BD1;oJKP>3DF<}8 zpAhQ|uy)Q4=4WC_&U$l}U?5Z`s`nC5xq(Ko5r--SFhZmoqdYqYK8+)YdBZeYv(=OApaS_atJ=(4tNSr{}6nV zapoV$LKFi!imzCMKZi*^yz7}t)MQ`O_94zcA=bhZU(p0eiT$)wRUxcWZ-?EMz?=hF zIMMa)ICt?b=KFncQ)2_R1P}4 zgR(IOW5mvwrNV$Lk{!5B#4X3K&q0E>3N$eLO2^?27R$?c=2ib)& zV%y^?^#!C`u-TAgdvQvaVW!9FcVKPSCcKp`qY(~Nl&l3%fgt9wXs2H7@Tm?xeFRd| zSPLT-Um$4)wdL(Q{H)!)Fo=NM|B*msG^?0-opG$dgm#vS_8d<*Pa37T$T8_LC=}~pbMt)SylBDLcXD>)^DK9@0m zSWeHf$JEibsG=|)qli2>VX=}e8(9bG%v}N+@Bj6HcH^DM3v&9jHFFY$xD+T zn78cdE_lL0TYH?RCu7d?_9G}(TpIiE6G(c>K`;9=BqEo?WX`zWZ(Cp--wG-H&12t% zjOA!zQMcj{#M|dsCF0j@!8c_B1Jd$74Gq(rvNlNUV;1}PK}ecZAi89kqKb4ip4`>h zwXDLFuec{Gb4_-R{T-LSm$?vZW3Js?u+!r*7T3R>jGR3y<%y5|JEEbG3R{U^qc)Ek z0#_QCb^{GLv>>joIZWAD4!*0_3KtiX0s%2QZ&=JqGsW?Wd4z z`|I@g!8dsJVjf!{9qcRG2OtUMXRx0yL&9loBp&zvP`f&}W2GTS&|*yt2MvVd2aIK#I_v)iLTCI z`_6+@Xb;i&7^Dv?dZdse-BBHa34+o8cb#OA4TH2D0#w}$_dr5dK*H?|w(cRwwc-I> zI_MVH86D%<4yo-2V8MluI;x2=ycTlb$YRCmvjtu5Krj3iau$<`!I}0EKbeS6FC+zgpytsYS7Dw8KhN)LWWJJ? z2JbQTX&}dikiKi456DQd*#P~TUXJ>4TXY_jcJ!-MCfj~t&4HEA@hxUIElI4*_`@aB*@03AKHr%d}D9j`EdnHhL7V}Hf zPjRCpYm&0;9RZff*mlU7VglKSAB7(6WIStkL)SnnHSYL=jz&n@1GJg4zq4UQ6as{v zwSDfA#smU!pd4~HSO>Wda$EpXO7?f>mLb&YRL2G<>^iSWV&uc(USuiZZYJ?9N|E1m z9P0bWOY4JGa@I%HEbbhr_i{*Y>~%t=-jf96_9c&woBlaRPJa7ud(HOR8hfbbJpwCODtV7)-u zv0^qcwcU|{(2M_unST4%_X6461HV!$Qpdq(eLT#B&)E{_lZAmue1PQ0BpM}a+ljbH zElS`%$?pfrB^6&kJX3rHFOnL=@8AiT_1{oY{sPgLg*^y5inDpoQE{7^Cc3$lJ^jVb zr{aVZwLGnmRXdoWtD~`;;C$~rY7@9Z0s*9^1%3V%NNiRXCBFZ^B|Jtc*cp(~oo@=h z1;^5#9q`-$^}gZ&GROFka2{X_D~A@}{}W!=ac>quDh|#P{vhN@oY!Hdehmo(bU=e+ z#Ur$11}jqbTW(Aw7mDfF-35apvc}4iN)5c@rn~3<>JY07jpJL}+D$_P*DxxFVP+ z2?;Vu6Z36>oC7CO#pgpZ?->;I#~oQ22=)JgxMFly8H+pzmoSH7Lb3jc2V6hvJDS?N zcmY!gG=9PjmQXP%$Kt6eDkaG(*z??A!$Pls$$mOqIDx>RE2iONL~$9#W{oore<`Ua zYd!eVYf$wCYvN&$1^!O0wLm`;Sq`Ag-Ky3|I;B*>?#3MbkL2Cif+^ zi0fFYO|DVB0fCe3NFF$(NP!l9j$=BTjAx}YS1A0o+;y8pwe~zDA@?l0|8J0IT3f>c zUQ~QSWBrl}p4{-Ddga34C99)Yw2Od_N03>mAUrZMEqj&Ki@71wndgwtH2Z}QK<*9y zSPegc6poVEX0UQH!%3HP+X5UGGttLaaU-@gaC06yS-t^gR+*Hyx2h~aL`L)$aKK98=#{Hc^P^mu3U#>u%8jo$cqb=nkJt6pNNMyDmhHYN|N>)>R20@5lmJG z5n4QC47fnh%MI!&=r3nWA5!)K=r3z)A@x=Pmy_`hKqP(5V{*>pcZX35_610(Iqb|y zpACRX&OQPeRUb@qy>XtAGdgwMtpqy;z4qppJRweS#Ier~I!A!EB0vDAgGd)o%gS-; z+P9O&EElnygqzYjJpc9$!YpBG)lwX_swcTm!FyByOM)Ca8JL5n&|R zuX;84h36;kZrDP z9kR6Dbpza*w+kWni*Ny)bSdt1(z@Fh@s_0W!|!zuBdfJ`Eu@PM743f@(I0s%O!0GW z$XQ_2JV+@}^!AyMIxOVgy)+5gb6k-_H*LEYer(Re6hif6F*J$KdmMmjOG5&V5l;^G zLz6RCi{ZW!Qi=0)^e#vyMuF;*^>(?+wHzbo&pt;HHJK#R`~_%GYFo>Kwn&NHzMv8n z4k{M^ynCF3Vpj1jNJgvg99vEvbCK9 zTE(o7Hna|KxL|wpASuRa=4U#j!(g>`JS1$*V}weO42##y*;YuLlnh$!LC9r7`&#vf z0;yx;Lfzj*PFr3KQ!H*D_5v|NIV|3UM-ncV4vTjtBpY0cLp}s4Ma0s68WQ-2At>79 zM-{<#jutsoI9lSbF!y$D5TV7f5Xw0L&gn%aeYPv0R<={A+drbdW~^V)raq=${aejS_NANRV+RX- zZcjNOV7yvOQC4|x98%>d!^i~AgNxgei+!$tuD+vD=NQ_W8yd?wy>lLSBPFZFl8`8I zzKvlgLvE7ja`*reDb^bU#y;W7X0STrAft|mHdxO6P>_tlD&w}M7rVI;QmX*Fc|WAw z3=HdEAa%YqNuJ7zCzUA)#xB}_K#sR62j5@hMs(WAc3Q7ZWu^$g{|oN&f&-Ya^eHi{ zBH~JkOf8USP5m5x=5}xh6$fjKW4T@()X(ooTaHnD7LuOjF%^@)=*J86I0zCUl?*gP zGB)K9PyL=}9;T@qk^pEH^L8;LCM|=}dm1tdSvjO*Pvg;E9vF|3z0}~UVBQNh@jqP6 zM9A|tJD}w*lZ($@% z@yi>qg$*9PmFx-7n`LVEu33=vXq(UVAY0CLgstFuqylgxSrOa81}nTu0bsLR6#eLqt$^ zv9E9)Wv2i;cd<*k9%vIV;)n{@-K~aYw40sIb-aCo>sWg?p6@7onCnP;9K1fllK4%# z*+#Bo?FFtp1!5gzmvO~WWFIGCcXHjwUgElkO}iA*8}YDTxYm{ zBW*s!E;e?i_d_3im_ARaxh(C*~ zXL2pt@3|gtM`1H&+DEyLvbPe4A8q#^qgi;B>ppe?PUMkxEw-`KMlaAvw{ShhX4H%G zZ{a%EKFM{Oy`xd1_$AkUthi9zxQFX5_6#ULZ`U^)My01kkn@&Saqm(rLBd|-I@k7Z zm(O*?iJH@2aNXPf%(dATc4%B5+Yqg@cbM3d!Ung$A#Fdc!`{2)r^KLYI)jsthcs}CPn~5cDdkZKh^W)L`YG>=i z2PN#t#1n@kI5u$8p?FM*D-PHDM!uhxZJD<;VZXHT%Vb*aIz?LY{Ie7Gs4cz +# +# $Id: rivendell.pro,v 1.4 2007/02/14 21:48:41 fredg Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = subdirs + +SUBDIRS += lib +SUBDIRS += utils +#SUBDIRS += ripcd +SUBDIRS += rdlogedit +SUBDIRS += rdlogmanager + + diff --git a/rivendell.spec.in b/rivendell.spec.in new file mode 100644 index 00000000..0c0dcbbe --- /dev/null +++ b/rivendell.spec.in @@ -0,0 +1,1084 @@ +## rivendell.spec.in +## +## The Rivendell Radio Automation System +## Copyright (C) 2002-2010 Fred Gleason +## +## $Id: rivendell.spec.in,v 1.98.4.28 2014/01/16 02:44:58 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of version 2 of the GNU General Public License as +## published by the Free Software Foundation; +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, +## Boston, MA 02111-1307 USA +## + +Summary: Radio Broadcast Automation System +Name: rivendell +Version: @VERSION@ +Release: @RPM_RELEASE@ +License: GPL +Packager: Fred Gleason +Group: Productivity/Multimedia/Other +Source: rivendell-@VERSION@.tar.gz +Requires: @QT3_MYSQL_PKG@ @APACHE_PKG@ @QT3_DEVEL_PKG@ curl @USERMODE_PKG@ rivendell-base +BuildRoot: /var/tmp/rivendell-@VERSION@ + +%package base +Summary: The base components for the Rivendell Radio Automation System +Group: Productivity/Multimedia/Other +Requires: @QT3_MYSQL_PKG@ + +%package importers +Summary: Library importers for the Rivendell Broadcast Automation System +Group: Productivity/Multimedia/Other +Requires: rivendell madplay + + +%package devel +Summary: Header files and example code for developing Rivendell Loadable Modules +Group: Productivity/Multimedia/Other + +%package select +Summary: The RDSelect system selector tool for Rivendell. +Group: Productivity/Multimedia/Other +Requires: rivendell + + +%description +Rivendell is a complete radio broadcast automation solution, with +facilities for the acquisition, management, scheduling and playout of +audio content. Modules for the production and management of podcast +audio are also included. + + +%description base +This package contains the common base components for the Rivendell +Radio Broadcast Automation system, including the applications libraries +and Core Audio Engine (CAE) daemon. + + +%description importers +This package contains various importer scripts, which can be used to +import audio from existing legacy automation systems into Rivendell. +Currently, scripts exist for the AirForce Wings, Prophet NexGen and Sierra +Automated Systems SASAuto systems, as well as from another Rivendell system +(useful for 'merging' multiple databases). Additionally, scripts for +initializing switcher matrices for the Christian Radio Consortium +(CRC) Unity4000 network and copying RDCatch event lists between hosts +are included. + + +%description devel +This package contains header files and example code for developing Rivendell +Loadable Modules (RLMs), which can be used to generate custom Now & Next data +outputs for a wide variety of external devices. + + +%description select +This package contains the RDMonitor/RDSelect tool for Rivendell, which can +be used to select which amoung multiple Rivendell instances a host should be +associated with. + +%prep + + +%setup + + +%build +./configure --prefix=@LOCAL_PREFIX@ --libexecdir=@libexecdir@ +make + + +%install +rm -rf $RPM_BUILD_ROOT + +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@ +cp lib/.libs/librd-@VERSION@.so $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/ +ln -s @LOCAL_PREFIX@/@RD_LIB_PATH@/librd-@VERSION@.so $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/librd.so +cp lib/.libs/librd.a $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/ +cp lib/.libs/librd.la $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/ +if test -f rdhpi/.libs/librdhpi-@VERSION@.so ; then + cp rdhpi/.libs/librdhpi-@VERSION@.so $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/ + ln -s @LOCAL_PREFIX@/@RD_LIB_PATH@/librdhpi-@VERSION@.so $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/librdhpi.so + cp rdhpi/.libs/librdhpi.a $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/ + cp rdhpi/.libs/librdhpi.la $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/ +fi +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin +cp cae/.libs/caed $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdadmin/.libs/rdadmin $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdairplay/.libs/rdairplay $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdpanel/.libs/rdpanel $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdcartslots/.libs/rdcartslots $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdcatch/.libs/rdcatch $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdcatchd/.libs/rdcatchd $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdrepld/.libs/rdrepld $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdlibrary/.libs/rdlibrary $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdlogedit/.libs/rdlogedit $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdlogmanager/.libs/rdlogmanager $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdcastmanager/.libs/rdcastmanager $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdlogin/.libs/rdlogin $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdselect/.libs/rdselect $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp rdmonitor/.libs/rdmonitor $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp utils/rdalsaconfig/.libs/rdalsaconfig $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +if test "@DISTRO@" = "redhat" ; then + ln -s /usr/bin/consolehelper $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/rdalsaconfig-root +fi +cp utils/rdcheckcuts/.libs/rdcheckcuts $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp utils/rdcollect/.libs/rdcollect $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp utils/rddgimport/.libs/rddgimport $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp utils/rddiscimport/.libs/rddiscimport $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp utils/rdgen/rdgen $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp utils/rdgpimon/.libs/rdgpimon $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +if test -f rdhpi/.libs/librdhpi-@VERSION@.so ; then + cp utils/rdhpiinfo/.libs/rdhpiinfo $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ + if test "@DISTRO@" = "redhat" ; then + ln -s /usr/bin/consolehelper $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/rdhpiinfo-root + fi +fi +cp utils/rddelete/.libs/rddelete $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp utils/rdimport/.libs/rdimport $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp utils/rdmaint/.libs/rdmaint $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp utils/rdpopup/.libs/rdpopup $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp utils/rdpurgecasts/.libs/rdpurgecasts $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp utils/rdsoftkeys/.libs/rdsoftkeys $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp utils/rmlsend/.libs/rmlsend $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp scripts/rd_audio_sync $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp scripts/rd_config $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp scripts/sage_endec_rwt.sh $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp ripcd/.libs/ripcd $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp importers/.libs/wings_filter $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp importers/.libs/rivendell_filter $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp importers/.libs/nexgen_filter $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp importers/.libs/sas_filter $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp scripts/crc-unity4k.sh $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp importers/.libs/rdcatch_copy $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +cp importers/.libs/panel_copy $RPM_BUILD_ROOT@LOCAL_PREFIX@/bin/ +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/sbin +cp utils/sas_shim/.libs/sas_shim $RPM_BUILD_ROOT@LOCAL_PREFIX@/sbin/ +cp utils/rddbcheck/.libs/rddbcheck $RPM_BUILD_ROOT@LOCAL_PREFIX@/sbin/ +cp utils/rdmarkerset/.libs/rdmarkerset $RPM_BUILD_ROOT@LOCAL_PREFIX@/sbin/ +mkdir -p $RPM_BUILD_ROOT@libexecdir@ +cp web/rdfeed/.libs/rdfeed.xml $RPM_BUILD_ROOT@libexecdir@/ +cp web/rdcastmanager/.libs/rdcastmanager.cgi $RPM_BUILD_ROOT@libexecdir@/ +cat web/rdcastmanager/rdcastmanager.js | helpers/jsmin > $RPM_BUILD_ROOT@libexecdir@/rdcastmanager.js +ln -s @libexecdir@/rdfeed.xml $RPM_BUILD_ROOT@libexecdir@/rdfeed.mp3 +cp icons/greencheckmark.png $RPM_BUILD_ROOT@libexecdir@/ +cp icons/redx.png $RPM_BUILD_ROOT@libexecdir@/ +cp icons/greenball.png $RPM_BUILD_ROOT@libexecdir@/ +cp icons/redball.png $RPM_BUILD_ROOT@libexecdir@/ +cp icons/whiteball.png $RPM_BUILD_ROOT@libexecdir@/ +cp icons/progressbar.gif $RPM_BUILD_ROOT@libexecdir@/ +cp web/rdxport/.libs/rdxport.cgi $RPM_BUILD_ROOT@libexecdir@/ +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp lib/librd_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdadmin/rdadmin_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdairplay/rdairplay_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdcastmanager/rdcastmanager_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdcatch/rdcatch_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +if test -f rdhpi/.libs/librdhpi-@VERSION@.so ; then + cp rdhpi/rdhpi_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +fi +cp rdlibrary/rdlibrary_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogedit/rdlogedit_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogin/rdlogin_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdselect/rdselect_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdmonitor/rdmonitor_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogmanager/rdlogmanager_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp utils/rdgpimon/rdgpimon_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp utils/rmlsend/rmlsend_es.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ + +cp lib/librd_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdadmin/rdadmin_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdairplay/rdairplay_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdcastmanager/rdcastmanager_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdcatch/rdcatch_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +if test -f rdhpi/.libs/librdhpi-@VERSION@.so ; then + cp rdhpi/rdhpi_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +fi +cp rdlibrary/rdlibrary_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogedit/rdlogedit_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogin/rdlogin_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdselect/rdselect_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdmonitor/rdmonitor_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogmanager/rdlogmanager_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp utils/rdgpimon/rdgpimon_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp utils/rmlsend/rmlsend_de.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp lib/librd_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdadmin/rdadmin_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdairplay/rdairplay_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdcastmanager/rdcastmanager_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdcatch/rdcatch_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +if test -f rdhpi/.libs/librdhpi-@VERSION@.so ; then + cp rdhpi/rdhpi_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +fi +cp rdlibrary/rdlibrary_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogedit/rdlogedit_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogin/rdlogin_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdselect/rdselect_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdmonitor/rdmonitor_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogmanager/rdlogmanager_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp utils/rdgpimon/rdgpimon_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp utils/rmlsend/rmlsend_cs.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp lib/librd_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdadmin/rdadmin_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdairplay/rdairplay_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdcastmanager/rdcastmanager_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdcatch/rdcatch_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +if test -f rdhpi/.libs/librdhpi-@VERSION@.so ; then + cp rdhpi/rdhpi_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +fi +cp rdlibrary/rdlibrary_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogedit/rdlogedit_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogin/rdlogin_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdselect/rdselect_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdmonitor/rdmonitor_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogmanager/rdlogmanager_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp utils/rdgpimon/rdgpimon_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp utils/rmlsend/rmlsend_nn.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp lib/librd_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdadmin/rdadmin_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdairplay/rdairplay_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdcastmanager/rdcastmanager_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdcatch/rdcatch_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +if test -f rdhpi/.libs/librdhpi-@VERSION@.so ; then + cp rdhpi/rdhpi_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +fi +cp rdlibrary/rdlibrary_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogedit/rdlogedit_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogin/rdlogin_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdselect/rdselect_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdmonitor/rdmonitor_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogmanager/rdlogmanager_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp utils/rdgpimon/rdgpimon_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp utils/rmlsend/rmlsend_nb.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp lib/librd_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdadmin/rdadmin_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdairplay/rdairplay_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdcastmanager/rdcastmanager_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdcatch/rdcatch_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +if test -f rdhpi/.libs/librdhpi-@VERSION@.so ; then + cp rdhpi/rdhpi_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +fi +cp rdlibrary/rdlibrary_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogedit/rdlogedit_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogin/rdlogin_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdselect/rdselect_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdmonitor/rdmonitor_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp rdlogmanager/rdlogmanager_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp utils/rdgpimon/rdgpimon_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +cp utils/rmlsend/rmlsend_pt_BR.qm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/rivendell/ +mkdir -p $RPM_BUILD_ROOT@APACHE_CONFIG_DIR@ +cp conf/rd-bin.conf $RPM_BUILD_ROOT@APACHE_CONFIG_DIR@/ +mkdir -p $RPM_BUILD_ROOT/etc/init.d +cp rivendell $RPM_BUILD_ROOT/etc/init.d +cp rdrepld-suse $RPM_BUILD_ROOT/etc/init.d/rdrepld +mkdir -p $RPM_BUILD_ROOT/etc/sysconfig +cp rivendell.sys $RPM_BUILD_ROOT/etc/sysconfig/rivendell +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/icons/hicolor/16x16/apps +cp icons/rivendell-16x16.png $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/icons/hicolor/16x16/apps/rivendell.png +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/icons/hicolor/22x22/apps +cp icons/rivendell-22x22.png $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/icons/hicolor/22x22/apps/rivendell.png +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/icons/hicolor/32x32/apps +cp icons/rivendell-32x32.png $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/icons/hicolor/32x32/apps/rivendell.png +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/icons/hicolor/48x48/apps +cp icons/rivendell-48x48.png $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/icons/hicolor/48x48/apps/rivendell.png +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/icons/hicolor/64x64/apps +cp icons/rivendell-64x64.png $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/icons/hicolor/64x64/apps/rivendell.png +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/icons/hicolor/128x128/apps +cp icons/rivendell-128x128.png $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/icons/hicolor/128x128/apps/rivendell.png +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/X11/fvwm2/pixmaps +cp icons/rivendell-16x16.xpm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/X11/fvwm2/pixmaps/mini.rivendell.xpm +cp icons/rivendell-32x32.xpm $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/X11/fvwm2/pixmaps/rivendell.xpm +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications +cp xdg/rivendell-rdadmin.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rdairplay.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rdalsaconfig-root.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rdcartslots.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rdcastmanager.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rdcatch.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rddgimport.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rddiscimport.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rdgpimon.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +if test -f rdhpi/.libs/librdhpi-@VERSION@.so ; then + cp xdg/rivendell-rdhpiinfo-root.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +fi +cp xdg/rivendell-rdlibrary.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rdlogedit.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rdlogin.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rdlogmanager.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rdmonitor.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rdpanel.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rdsoftkeys.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +cp xdg/rivendell-rmlsend.desktop $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/applications/ +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/desktop-directories +cp xdg/*.directory $RPM_BUILD_ROOT@LOCAL_PREFIX@/share/desktop-directories/ +mkdir -p $RPM_BUILD_ROOT/etc/xdg/menus/applications-merged +cp xdg/*.menu $RPM_BUILD_ROOT/etc/xdg/menus/applications-merged/ +mkdir $RPM_BUILD_ROOT/.qt +touch $RPM_BUILD_ROOT/.qt/qt +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell +cp rlm/rlm_test.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_serial.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_twitter.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_facebook.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_udp.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_xmpad.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_ando.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_liqcomp.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_padpoint.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_inno713.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_xds.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_icecast2.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_shoutcast1.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_spottrap.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_filewrite.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +cp rlm/rlm_spinitron_plus.rlm $RPM_BUILD_ROOT@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/ +mkdir -p $RPM_BUILD_ROOT@LOCAL_PREFIX@/include/rlm +cp rlm/rlm.h $RPM_BUILD_ROOT@LOCAL_PREFIX@/include/rlm/ +mkdir -p $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm +cp rlm/Makefile-example $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/Makefile +cp rlm/rlm_test.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_serial.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_udp.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_twitter.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_facebook.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_xmpad.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_ando.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_liqcomp.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_padpoint.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_inno713.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_xds.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_icecast2.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_shoutcast1.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_spottrap.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_filewrite.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +cp rlm/rlm_spinitron_plus.c $RPM_BUILD_ROOT/@LOCAL_PREFIX@/src/rlm/ +mkdir -p $RPM_BUILD_ROOT/@RD_LIB_PATH@/security +cp pam_rd/.libs/pam_rd.so $RPM_BUILD_ROOT/@RD_LIB_PATH@/security/ +if test "@WIN32_SOURCE@" ; then + mkdir -p $RPM_BUILD_ROOT/var/win32 + cp @WIN32_SOURCE@ $RPM_BUILD_ROOT/var/win32/ +fi +mkdir -p $RPM_BUILD_ROOT/etc/pam.d +cp xdg/rdalsaconfig-root-pam $RPM_BUILD_ROOT/etc/pam.d/rdalsaconfig-root +if test -f rdhpi/.libs/librdhpi-@VERSION@.so ; then + cp xdg/rdhpiinfo-root-pam $RPM_BUILD_ROOT/etc/pam.d/rdhpiinfo-root +fi +mkdir -p $RPM_BUILD_ROOT/etc/security/console.apps +cp xdg/rdalsaconfig-root-consolehelper $RPM_BUILD_ROOT/etc/security/console.apps/rdalsaconfig-root +if test -f rdhpi/.libs/librdhpi-@VERSION@.so ; then + cp xdg/rdhpiinfo-root-consolehelper $RPM_BUILD_ROOT/etc/security/console.apps/rdhpiinfo-root +fi + +%post +ldconfig +if test "@DISTRO@" = "suse" ; then + PACKAGE_DOC_DIR=%_docdir/%{name} +fi +if test "@DISTRO@" = "redhat" ; then + PACKAGE_DOC_DIR=%_docdir/%{name}-@VERSION@ +fi +/usr/sbin/groupadd -r -g 150 %{name} &>/dev/null || : +/usr/sbin/useradd -o -u 150 -g %{name} -s /bin/false -r -c "Rivendell radio automation system" -d /var/snd %{name} &>/dev/null || : +if test ! -e /var/snd ; then + mkdir -p /var/snd + chown rivendell:rivendell /var/snd + chmod 775 /var/snd +fi +mkdir -p -m 777 /var/run/rivendell +if test ! -d /etc/rivendell.d ; then + mkdir -p /etc/rivendell.d + chmod 775 /etc/rivendell.d +fi +if test ! -e /etc/rd.conf ; then + cp $PACKAGE_DOC_DIR/rd.conf-sample /etc/rivendell.d/rd-default.conf + ln -s /etc/rivendell.d/rd-default.conf /etc/rd.conf +fi +if test ! -h /etc/rd.conf ; then + mv /etc/rd.conf /etc/rivendell.d/rd-default.conf + ln -s /etc/rivendell.d/rd-default.conf /etc/rd.conf +fi +if test ! -e /etc/asound.conf ; then + cp $PACKAGE_DOC_DIR/asound.conf-sample /etc/asound.conf +fi +if test -f /etc/init.d/mysql ; then + /etc/init.d/mysql start + MYSQL_INIT="/etc/init.d/mysql" +fi +if test -f /etc/init.d/mysqld ; then + /etc/init.d/mysqld start + MYSQL_INIT="/etc/init.d/mysqld" +fi +@LOCAL_PREFIX@/bin/rdadmin --check-db --mysql-admin-user=root --mysql-admin-password +/etc/init.d/rivendell restart +if test "@DISTRO@" = "suse" ; then + /etc/init.d/apache2 restart + insserv -d -f /etc/init.d/apache2 /etc/init.d/rivendell $MYSQL_INIT +fi +if test "@DISTRO@" = "redhat" ; then + /etc/init.d/httpd restart + chkconfig --add httpd + chkconfig --levels 35 httpd on + chkconfig --add rivendell + chkconfig --levels 35 rivendell on + if test $MYSQL_INIT ; then + chkconfig --add mysqld + chkconfig --levels 35 mysqld on + fi +fi +exit 0 + +%preun +if test "$1" = "0" ; then + /etc/init.d/rivendell stop + if test "@DISTRO@" = "suse" ; then + insserv -r -d -f /etc/init.d/rivendell + fi + if test "@DISTRO@" = "redhat" ; then + chkconfig --levels 35 rivendell off + chkconfig --del rivendell + fi +fi +exit 0 + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_test.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_serial.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_udp.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_twitter.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_facebook.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_xmpad.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_ando.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_liqcomp.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_padpoint.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_inno713.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_xds.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_icecast2.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_shoutcast1.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_spottrap.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_filewrite.rlm +@LOCAL_PREFIX@/@RD_LIB_PATH@/rivendell/rlm_spinitron_plus.rlm +@LOCAL_PREFIX@/bin/rdadmin +@LOCAL_PREFIX@/bin/rdairplay +@LOCAL_PREFIX@/bin/rdpanel +@LOCAL_PREFIX@/bin/rdcartslots +@LOCAL_PREFIX@/bin/rdcatch +%attr(4755,root,root)@LOCAL_PREFIX@/bin/rdcatchd +%attr(4755,root,root)@LOCAL_PREFIX@/bin/rdrepld +@LOCAL_PREFIX@/bin/rdgen +@LOCAL_PREFIX@/bin/rdlibrary +@LOCAL_PREFIX@/bin/rdlogedit +@LOCAL_PREFIX@/bin/rdlogmanager +@LOCAL_PREFIX@/bin/rdcastmanager +@LOCAL_PREFIX@/bin/rdlogin +@LOCAL_PREFIX@/bin/rmlsend +@LOCAL_PREFIX@/bin/rdsoftkeys +@LOCAL_PREFIX@/bin/rdpopup +@LOCAL_PREFIX@/bin/rdalsaconfig +@CONSOLEHELPER_RDALSACONFIG@ +@LOCAL_PREFIX@/bin/rdgpimon +@LOCAL_PREFIX@/bin/rddelete +@LOCAL_PREFIX@/bin/rdimport +@LOCAL_PREFIX@/bin/rdpurgecasts +@LOCAL_PREFIX@/bin/rdmaint +@LOCAL_PREFIX@/bin/rdcollect +@LOCAL_PREFIX@/bin/rdcheckcuts +@LOCAL_PREFIX@/bin/rd_audio_sync +@LOCAL_PREFIX@/bin/rd_config +@LOCAL_PREFIX@/bin/sage_endec_rwt.sh +%attr(4755,root,root)@LOCAL_PREFIX@/bin/ripcd +@LOCAL_PREFIX@/sbin/sas_shim +@LOCAL_PREFIX@/sbin/rddbcheck +@LOCAL_PREFIX@/sbin/rdmarkerset +@LOCAL_PREFIX@/share/rivendell/librd_es.qm +@LOCAL_PREFIX@/share/rivendell/rdadmin_es.qm +@LOCAL_PREFIX@/share/rivendell/rdairplay_es.qm +@LOCAL_PREFIX@/share/rivendell/rdcastmanager_es.qm +@LOCAL_PREFIX@/share/rivendell/rdcatch_es.qm +@LOCAL_PREFIX@/share/rivendell/rdgpimon_es.qm +@LOCAL_PREFIX@/share/rivendell/rdlibrary_es.qm +@LOCAL_PREFIX@/share/rivendell/rdlogedit_es.qm +@LOCAL_PREFIX@/share/rivendell/rdlogin_es.qm +@LOCAL_PREFIX@/share/rivendell/rdlogmanager_es.qm +@LOCAL_PREFIX@/share/rivendell/rmlsend_es.qm +@LOCAL_PREFIX@/share/rivendell/librd_cs.qm +@LOCAL_PREFIX@/share/rivendell/rdadmin_cs.qm +@LOCAL_PREFIX@/share/rivendell/rdairplay_cs.qm +@LOCAL_PREFIX@/share/rivendell/rdcastmanager_cs.qm +@LOCAL_PREFIX@/share/rivendell/rdcatch_cs.qm +@LOCAL_PREFIX@/share/rivendell/rdgpimon_cs.qm +@LOCAL_PREFIX@/share/rivendell/rdlibrary_cs.qm +@LOCAL_PREFIX@/share/rivendell/rdlogedit_cs.qm +@LOCAL_PREFIX@/share/rivendell/rdlogin_cs.qm +@LOCAL_PREFIX@/share/rivendell/rdlogmanager_cs.qm +@LOCAL_PREFIX@/share/rivendell/rmlsend_cs.qm +@LOCAL_PREFIX@/share/rivendell/librd_de.qm +@LOCAL_PREFIX@/share/rivendell/rdadmin_de.qm +@LOCAL_PREFIX@/share/rivendell/rdairplay_de.qm +@LOCAL_PREFIX@/share/rivendell/rdcastmanager_de.qm +@LOCAL_PREFIX@/share/rivendell/rdcatch_de.qm +@LOCAL_PREFIX@/share/rivendell/rdgpimon_de.qm +@LOCAL_PREFIX@/share/rivendell/rdlibrary_de.qm +@LOCAL_PREFIX@/share/rivendell/rdlogedit_de.qm +@LOCAL_PREFIX@/share/rivendell/rdlogin_de.qm +@LOCAL_PREFIX@/share/rivendell/rdlogmanager_de.qm +@LOCAL_PREFIX@/share/rivendell/rmlsend_de.qm +@LOCAL_PREFIX@/share/rivendell/librd_nn.qm +@LOCAL_PREFIX@/share/rivendell/rdadmin_nn.qm +@LOCAL_PREFIX@/share/rivendell/rdairplay_nn.qm +@LOCAL_PREFIX@/share/rivendell/rdcastmanager_nn.qm +@LOCAL_PREFIX@/share/rivendell/rdcatch_nn.qm +@LOCAL_PREFIX@/share/rivendell/rdgpimon_nn.qm +@LOCAL_PREFIX@/share/rivendell/rdlibrary_nn.qm +@LOCAL_PREFIX@/share/rivendell/rdlogedit_nn.qm +@LOCAL_PREFIX@/share/rivendell/rdlogin_nn.qm +@LOCAL_PREFIX@/share/rivendell/rdlogmanager_nn.qm +@LOCAL_PREFIX@/share/rivendell/rmlsend_nn.qm +@LOCAL_PREFIX@/share/rivendell/librd_nb.qm +@LOCAL_PREFIX@/share/rivendell/rdadmin_nb.qm +@LOCAL_PREFIX@/share/rivendell/rdairplay_nb.qm +@LOCAL_PREFIX@/share/rivendell/rdcastmanager_nb.qm +@LOCAL_PREFIX@/share/rivendell/rdcatch_nb.qm +@LOCAL_PREFIX@/share/rivendell/rdgpimon_nb.qm +@LOCAL_PREFIX@/share/rivendell/rdlibrary_nb.qm +@LOCAL_PREFIX@/share/rivendell/rdlogedit_nb.qm +@LOCAL_PREFIX@/share/rivendell/rdlogin_nb.qm +@LOCAL_PREFIX@/share/rivendell/rdlogmanager_nb.qm +@LOCAL_PREFIX@/share/rivendell/rmlsend_nb.qm +@LOCAL_PREFIX@/share/rivendell/librd_pt_BR.qm +@LOCAL_PREFIX@/share/rivendell/rdadmin_pt_BR.qm +@LOCAL_PREFIX@/share/rivendell/rdairplay_pt_BR.qm +@LOCAL_PREFIX@/share/rivendell/rdcastmanager_pt_BR.qm +@LOCAL_PREFIX@/share/rivendell/rdcatch_pt_BR.qm +@LOCAL_PREFIX@/share/rivendell/rdgpimon_pt_BR.qm +@LOCAL_PREFIX@/share/rivendell/rdlibrary_pt_BR.qm +@LOCAL_PREFIX@/share/rivendell/rdlogedit_pt_BR.qm +@LOCAL_PREFIX@/share/rivendell/rdlogin_pt_BR.qm +@LOCAL_PREFIX@/share/rivendell/rdlogmanager_pt_BR.qm +@LOCAL_PREFIX@/share/rivendell/rmlsend_pt_BR.qm +/etc/init.d/rdrepld +@LOCAL_PREFIX@/share/icons/hicolor/16x16/apps/rivendell.png +@LOCAL_PREFIX@/share/icons/hicolor/22x22/apps/rivendell.png +@LOCAL_PREFIX@/share/icons/hicolor/32x32/apps/rivendell.png +@LOCAL_PREFIX@/share/icons/hicolor/48x48/apps/rivendell.png +@LOCAL_PREFIX@/share/icons/hicolor/64x64/apps/rivendell.png +@LOCAL_PREFIX@/share/icons/hicolor/128x128/apps/rivendell.png +@LOCAL_PREFIX@/share/X11/fvwm2/pixmaps/mini.rivendell.xpm +@LOCAL_PREFIX@/share/X11/fvwm2/pixmaps/rivendell.xpm +@LOCAL_PREFIX@/share/applications/rivendell-rdadmin.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdlogin.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdairplay.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdmonitor.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdpanel.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdcartslots.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdcatch.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdgpimon.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdalsaconfig-root.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdlibrary.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdlogedit.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdlogmanager.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdcastmanager.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rmlsend.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rdsoftkeys.desktop +@LOCAL_PREFIX@/share/desktop-directories/rivendell-configuration.directory +@LOCAL_PREFIX@/share/desktop-directories/rivendell-logtools.directory +@LOCAL_PREFIX@/share/desktop-directories/rivendell-rivendell.directory +@LOCAL_PREFIX@/share/desktop-directories/rivendell-utilities.directory +/etc/xdg/menus/applications-merged/rivendell-rivendell.menu +/@RD_LIB_PATH@/security/pam_rd.so +/.qt/qt +@libexecdir@/rdfeed.xml +@libexecdir@/rdfeed.mp3 +@libexecdir@/rdcastmanager.cgi +@libexecdir@/rdcastmanager.js +@libexecdir@/greencheckmark.png +@libexecdir@/redx.png +@libexecdir@/greenball.png +@libexecdir@/redball.png +@libexecdir@/whiteball.png +@libexecdir@/progressbar.gif +%attr(6755,root,root) @libexecdir@/rdxport.cgi +@APACHE_CONFIG_DIR@/rd-bin.conf +@WIN32_PATH@ +/etc/pam.d/rdalsaconfig-root +/etc/security/console.apps/rdalsaconfig-root +%doc AUTHORS +%doc ChangeLog +%doc COPYING +%doc INSTALL +%doc NEWS +%doc README +%doc UPGRADING +%doc CODINGSTYLE +%doc conf/rd.conf-sample +%doc conf/my.cnf-master +%doc conf/my.cnf-standby +%doc docs/cae.sxw +%doc docs/catchd.txt +%doc docs/colors +%doc docs/GPIO.txt +%doc docs/ripc.txt +%doc docs/SWITCHERS.txt +%doc docs/JACK.txt +%doc docs/ENCODERS.txt +%doc docs/pam_rd.txt +%doc docs/rml.sxw +%doc docs/MESSAGE_BOX.txt +%doc docs/tables/audio_perms.txt +%doc docs/tables/audio_ports.txt +%doc docs/tables/cart.txt +%doc docs/tables/cartslots.txt +%doc docs/tables/clipboard.txt +%doc docs/tables/cuts.txt +%doc docs/tables/decks.txt +%doc docs/tables/groups.txt +%doc docs/tables/isci_xreference.txt +%doc docs/tables/log_format.txt +%doc docs/tables/logs.txt +%doc docs/tables/panels.txt +%doc docs/tables/rd_airplay.txt +%doc docs/tables/rd_library.txt +%doc docs/tables/rd_logedit.txt +%doc docs/tables/recordings.txt +%doc docs/tables/services.txt +%doc docs/tables/sources.txt +%doc docs/tables/svc_rec_format.txt +%doc docs/tables/stations.txt +%doc docs/tables/triggers.txt +%doc docs/tables/ttys.txt +%doc docs/tables/users.txt +%doc docs/tables/version.txt +%doc docs/asound.conf-sample +%doc docs/web_api.odt +%doc conf/rlm_serial.conf +%doc conf/rlm_udp.conf +%doc conf/rlm_twitter.conf +%doc conf/rlm_facebook.conf +%doc conf/rlm_xmpad.conf +%doc conf/rlm_ando.conf +%doc conf/rlm_liqcomp.conf +%doc conf/rlm_padpoint.conf +%doc conf/rlm_inno713.conf +%doc conf/rlm_xds.conf +%doc conf/rlm_icecast2.conf +%doc conf/rlm_shoutcast1.conf +%doc conf/rlm_spottrap.conf +%doc conf/rlm_filewrite.conf +%doc conf/rlm_spinitron_plus.conf +%doc docs/implemented_macros.txt +%doc utils/sas_shim/rc.sas_shim +%doc docs/datetime_wildcards.txt +%doc docs/reports.txt +%doc docs/NOW+NEXT.txt +%doc docs/WIN32.txt +%doc docs/ALSA.txt +%doc docs/RDMONITOR.txt +%doc docs/scheduler_formats.ods +%doc docs/copy_split_format.odt +%doc docs/ando_interface.odt +%doc scripts/rd_backup +%doc scripts/start_traverso.sh +%doc icons/rivendell-16x16.png +%doc icons/rivendell-22x22.png +%doc icons/rivendell-32x32.png +%doc icons/rivendell-48x48.png +%doc icons/rivendell-64x64.png +%doc icons/rivendell-128x128.png +%doc scripts/rd_mysql_enable_host.sh +%doc scripts/rd_backup_system.sh +%doc scripts/rd_restore_system.sh + + +%files base +%defattr(-,root,root) +@LOCAL_PREFIX@/@RD_LIB_PATH@/librd-@VERSION@.so +@LOCAL_PREFIX@/@RD_LIB_PATH@/librd.a +@LOCAL_PREFIX@/@RD_LIB_PATH@/librd.la +@LOCAL_PREFIX@/@RD_LIB_PATH@/librd.so +%attr(4755,root,root) @LOCAL_PREFIX@/bin/caed +/etc/init.d/rivendell +%config /etc/sysconfig/rivendell +@HPI_FILE1@ +@HPI_FILE2@ +@HPI_FILE3@ +@HPI_FILE4@ +@HPI_FILE5@ +@HPI_FILE6@ +@HPI_FILE7@ +@HPI_FILE8@ +@HPI_FILE9@ +@HPI_FILE10@ +@HPI_FILE11@ +@HPI_FILE12@ +@HPI_FILE13@ +@HPI_FILE14@ +@HPI_FILE15@ + + +%files importers +@LOCAL_PREFIX@/bin/wings_filter +@LOCAL_PREFIX@/bin/rivendell_filter +@LOCAL_PREFIX@/bin/nexgen_filter +@LOCAL_PREFIX@/bin/sas_filter +@LOCAL_PREFIX@/bin/crc-unity4k.sh +@LOCAL_PREFIX@/bin/rdcatch_copy +@LOCAL_PREFIX@/bin/panel_copy +@LOCAL_PREFIX@/bin/rddgimport +@LOCAL_PREFIX@/bin/rddiscimport +@LOCAL_PREFIX@/share/applications/rivendell-rddgimport.desktop +@LOCAL_PREFIX@/share/applications/rivendell-rddiscimport.desktop +%doc docs/WINGS_FILTER.txt +%doc docs/RIVENDELL_FILTER.txt +%doc docs/NEXGEN_FILTER.txt + + +%files devel +@LOCAL_PREFIX@/include/rlm/rlm.h +@LOCAL_PREFIX@/src/rlm/Makefile +@LOCAL_PREFIX@/src/rlm/rlm_test.c +@LOCAL_PREFIX@/src/rlm/rlm_serial.c +@LOCAL_PREFIX@/src/rlm/rlm_udp.c +@LOCAL_PREFIX@/src/rlm/rlm_twitter.c +@LOCAL_PREFIX@/src/rlm/rlm_facebook.c +@LOCAL_PREFIX@/src/rlm/rlm_xmpad.c +@LOCAL_PREFIX@/src/rlm/rlm_ando.c +@LOCAL_PREFIX@/src/rlm/rlm_liqcomp.c +@LOCAL_PREFIX@/src/rlm/rlm_padpoint.c +@LOCAL_PREFIX@/src/rlm/rlm_inno713.c +@LOCAL_PREFIX@/src/rlm/rlm_xds.c +@LOCAL_PREFIX@/src/rlm/rlm_icecast2.c +@LOCAL_PREFIX@/src/rlm/rlm_shoutcast1.c +@LOCAL_PREFIX@/src/rlm/rlm_spottrap.c +@LOCAL_PREFIX@/src/rlm/rlm_filewrite.c +@LOCAL_PREFIX@/src/rlm/rlm_spinitron_plus.c + + +%files select +%attr(4755,root,root) @LOCAL_PREFIX@/bin/rdselect +@LOCAL_PREFIX@/share/rivendell/rdselect_cs.qm +@LOCAL_PREFIX@/share/rivendell/rdselect_de.qm +@LOCAL_PREFIX@/share/rivendell/rdselect_es.qm +@LOCAL_PREFIX@/share/rivendell/rdselect_nb.qm +@LOCAL_PREFIX@/share/rivendell/rdselect_nn.qm +@LOCAL_PREFIX@/share/rivendell/rdselect_pt_BR.qm +@LOCAL_PREFIX@/bin/rdmonitor +@LOCAL_PREFIX@/share/rivendell/rdmonitor_cs.qm +@LOCAL_PREFIX@/share/rivendell/rdmonitor_de.qm +@LOCAL_PREFIX@/share/rivendell/rdmonitor_es.qm +@LOCAL_PREFIX@/share/rivendell/rdmonitor_nb.qm +@LOCAL_PREFIX@/share/rivendell/rdmonitor_nn.qm +@LOCAL_PREFIX@/share/rivendell/rdmonitor_pt_BR.qm + + +%changelog +* Tue Jan 15 2014 Fred Gleason +-- Added RDMarkerSet utility. +* Thu Dec 26 2013 Fred Gleason +-- Added desktop entry for RDMonitor. +* Tue Dec 03 2013 Fred Gleason +-- Added RDDiscImport(1). +* Tue Nov 13 2013 Fred Gleason +-- Split application library and caed(8) into a 'rivendell-base' subpackage. +* Tue Aug 26 2013 Fred Gleason +-- Added the 'rlm_spinitron_plus' RLM. +* Tue May 14 2013 Fred Gleason +-- Added conditional build for HPI components. +* Mon Apr 29 2013 Fred Gleason +-- Added RDDelete(1). +* Fri Mar 29 2013 Fred Gleason +-- Modified XDG system to use consolehelper(1) to start RDAlsaConfig and RDHpiInfo. +-- Added a 'usermode' dependency. +* Tue Mar 26 2013 Fred Gleason +-- Added PNG icons. +* Mon Jan 07 2013 Fred Gleason +-- Added RDDgImport(1). +-- Removed stripping code. +* Tue Jan 01 2013 Fred Gleason +-- Added Czech [CS] translation. +* Fri Nov 16 2012 Fred Gleason +-- Added RDCartSlots +* Mon Oct 22 2012 Fred Gleason +-- Modified the post-installation script to convert rd.conf(5) layout to +be compatible with rdmonitor(1). +* Fri Oct 19 2012 Fred Gleason +-- Added the 'start-rdmonitor.sh' script. +-- Set rdselect(1) SETUID 0. +-- Removed 'rivendell-rdselect.desktop' +* Fri Oct 12 2012 Fred Gleason +-- Added the 'sage_endec_rwt.sh' script. +-- Added a 'curl' dependency. +-- Added rdmonitor(1). +-- Added rdcheckcuts(1). +* Thu Aug 23 2012 Fred Gleason +-- Added the 'rlm_padpoint' RLM. +* Wed Aug 01 2012 Fred Gleason +-- Added a 'qt-devel' dependency. +* Mon Jul 16 2012 Fred Gleason +-- Added rdselect(8). +* Sun Jul 15 2012 Fred Gleason +-- Added 'nextgen_filter' to the 'importers' package. +-- Added a 'madplay' dependency to the 'importers' package. +-- Added 'docs/RIVENDELL_FILTER.txt'. +* Thu Jul 07 2012 Fred Gleason +-- Added the 'rlm_filewrite' RLM. +* Mon May 07 2012 Fred Gleason +-- Added 'doc/datetime_wildcards.txt'. +* Mon Apr 02 2012 Fred Gleason +-- Backported the 'rlm_spottrap' RLM from CVS-Head. +* Wed Dec 21 2011 Fred Gleason +-- Added Shoutcast1 RLM. +* Fri May 20 2011 Fred Gleason +-- Added 'scripts/rd_backup_system.sh' and 'rd_restore_systems.sh'. +* Wed May 11 2011 Fred Gleason +-- Added 'scripts/rd_mysql_enable_host.sh'. +* Mon Feb 14 2011 Fred Gleason +-- Added Win32 setup support. +* Tue Dec 07 2010 Fred Gleason +-- Refactored XDG entries. +* Wed Nov 24 2010 Fred Gleason +-- Removed ivman(8) dependency. +* Mon Nov 08 2010 Fred Gleason +-- Added 'docs/ando_interface.odt'. +* Fri Aug 6 2010 Fred Gleason +-- Added the 'icecast2_rlm' RLM. +* Wed Aug 4 2010 Fred Gleason +-- Added pt_BR translation. +* Mon Jul 26 2010 Fred Gleason +-- Corrected 'web_api.ods' to 'web_api.odt' in the docs list. +* Fri Jul 23 2010 Fred Gleason +-- Added 'isci_xreference.txt'. +* Thu Jul 10 2010 Fred Gleason +-- Added 'web_api.ods' to the docs list. +* Thu Jul 8 2010 Fred Gleason +-- Added rdrepld(8). +* Tue Jul 6 2010 Fred Gleason +-- Added arguments to the post-install script to create the 'rivendell' +user with a UID of '150'. +-- Added arguments to the post-install script to create the 'rivendell' +group with a GID of '150'. +* Fri Jul 2 2010 Fred Gleason +-- Added dependency for ivman(8). +* Fri Jun 25 2010 Fred Gleason +-- Added icons for fvwm(1). +* Wed Jun 16 2010 Fred Gleason +-- Changed invocation order of services in the post script. +* Fri Jun 11 2010 Fred Gleason +-- Removed 'SupportedCards'. +-- Removed 'ToDo'. +* Thu Jun 10 2010 Fred Gleason +-- Added 'UPGRADING'. +-- Removed 'conf/rd.conf-complete-sample' +* Tue May 18 2010 Fred Gleason +-- Added 'asound.conf-sample'. +-- Changed post-install script to use static ALSA configuration. +* Mon May 17 2010 Fred Gleason +-- Enabled binary stripping. +* Tue Apr 27 2010 Fred Gleason +-- Removed rdaconvert(1). +-- Removed rdfilewrite(1). +* Wed Apr 07 2010 Fred Gleason +-- Merged the 'web' subpackage into the main package. +-- Removed toolame(1). +-- Removed 'rd_import_audio', 'rd_export_audio' and 'rd_rip_cd'. +-- Added the 'rlm_xds' RLM. +-- Added 'rdxport.cgi'. +* Mon Feb 01 2010 Fred Gleason +-- Added rdcollect(1). +* Wed Jan 21 2010 Fred Gleason +-- Added German and Nowegian translations. +* Wed Sep 02 2009 Fred Gleason +-- Added the 'rlm_liqcomp' RLM. +* Wed Aug 19 2009 Fred Gleason +-- Added 'docs/scheduler_formats.ods'. +* Tue Aug 04 2009 Fred Gleason +-- Removed the sox(1) dependency. +-- Added rdaconvert(1). +* Mon Aug 03 2009 Fred Gleason +-- Added RDAlsaConfig. +* Tue Jun 30 2009 Fred Gleason +-- Added 'progressbar.gif' and 'rdcastmanager.js'. +* Wed May 13 2009 Fred Gleason +-- Added the 'rlm_inno713' RLM. +* Thu Apr 30 2009 Fred Gleason +-- Corrected the install location of 'rlm.h'. +* Tue Mar 17 2009 Fred Gleason +-- Added 'MESSAGE_BOX.txt'. +* Mon Feb 23 2009 Fred Gleason +-- Added the 'rlm_ando' RLM. +* Tue Feb 10 2009 Fred Gleason +-- Added RDPopup. +* Mon Feb 09 2009 Fred Gleason +-- Added RDSoftKeys. +* Tue Dec 02 2008 Fred Gleason +-- Added the 'rlm_facebook' RLM. +* Mon Dec 01 2008 Fred Gleason +-- Added the 'rlm_udp' and 'rlm_twitter' RLMs. +* Sun Nov 30 2008 Fred Gleason +-- Added the 'pam_rd.so' PAM plugin. +* Sun Nov 30 2008 Fred Gleason +-- Added the 'rlm_xmpad' RLM. +* Sat Nov 29 2008 Fred Gleason +-- Added rdmaint(1). +* Tue Nov 25 2008 Fred Gleason +-- Added the 'rivendell-devel' package. +* Thu Nov 20 2008 Fred Gleason +-- Added 'scripts/start_traverso.sh'. +* Thu Sep 18 2008 Fred Gleason +-- Added 'ENCODERS.txt'. +* Thu Aug 21 2008 Fred Gleason +-- Added a '/.qt/' directory to suppress QSettings error in the apache log +for 'rdfeed.cgi'. +* Thu Jul 17 2008 Fred Gleason +-- Added 'rivendell-filter' to the 'importers' package. +-- Added 'docs/RIVENDELL_FILTER.txt'. +* Thu Apr 03 2008 Fred Gleason +-- Removed the 'displays.txt' file. +* Mon Dec 17 2007 Fred Gleason +-- Fixed broken symlink library paths for x86_64. +* Fri Dec 14 2007 Fred Gleason +-- Added support for x86_64 architecture. +-- Fixed broken symlink creation for 'rdfeed.mp3'. +-- Fixed broken cdda2wav dependency for OpenSuSE 10.3. +* Mon Nov 27 2007 Fred Gleason +-- Added 'rdfeed.mp3' symlink to 'rdfeed.xml'. +-- Added 'whiteball.png' to the web subpackage. +* Tue Oct 10 2007 Fred Gleason +-- Added 'rdcastmanager.cgi'. +* Mon Sep 24 2007 Fred Gleason +-- Added the 'web' subpackage. +-- Added RDCastManager. +-- Added rdpurgecast. +* Mon Sep 24 2007 Fred Gleason +-- Replaced the 'lukemftp' dependency with 'lftp'. +* Fri Sep 14 2007 Fred Gleason +-- Added RDHPIInfo. +* Fri Sep 14 2007 Fred Gleason +-- Added librhpi. +* Fri Jun 08 2007 Fred Gleason +-- Added RDPanel. +* Sun Sep 03 2006 Fred Gleason +-- Removed the rdbackup script. +-- Added the rd_backup script. +* Tue Aug 29 2006 Fred Gleason +-- Added RDDbCheck and RDBackup scripts. +* Thu Jul 06 2006 Fred Gleason +-- Added the '%config' tag to /etc/sysconfig/rivendell. +* Thu Jun 25 2006 Fred Gleason +-- Added an XDG file for RDLogin. +* Fri Mar 24 2006 Fred Gleason +-- Updated to reflect new layout of the 'utils/' directory. +* Thu Mar 09 2006 Fred Gleason +-- Removed the conditional installation of RDImport. +* Mon Feb 14 2006 Fred Gleason +-- Altered the install section so as not to use 'make install'. +* Tue Feb 14 2006 Fred Gleason +-- Removed RDPanel. +* Wed Feb 08 2006 Fred Gleason +-- Altered install paths to use $prefix value from Autoconf. +* Fri Feb 03 2006 Fred Gleason +-- Added a 'cdda2wav' dependency. +* Wed Jan 04 2006 Fred Gleason +-- Added the 'rdfilewrite' utility. +* Wed Dec 14 2005 Fred Gleason +-- Added the 'panel_copy' filter script. +* Mon Nov 07 2005 Fred Gleason +-- Added 'docs/tables/svc_rec_format.txt'. +* Fri Nov 04 2005 Fred Gleason +-- Removed dependencies for 'update-desktop-files' and 'gettext'. +* Thu Nov 04 2005 Fred Gleason +-- Added dependencies for 'update-desktop-files' and 'gettext'. +* Tue Nov 01 2005 Fred Gleason +-- Added SuSE desktop integration. +* Thu Oct 27 2005 Fred Gleason +-- Added the 'rivendell.xpm' icon. +* Mon Oct 24 2005 Fred Gleason +-- Added the 'rd_logedit.txt' table description. +* Mon Aug 29 2005 Fred Gleason +-- Added the 'rdcatch_copy' filter script. +* Fri Aug 12 2005 Fred Gleason +-- Added an 'importers' subpackage. +* Sun Aug 07 2005 Fred Gleason +-- Added 'docs/WINGS_FILTER.txt'. +* Tue Aug 02 2005 Fred Gleason +-- Added the /usr/local/bin/rd_export_file script. +* Sun Jul 24 2005 Fred Gleason +-- Added dependencies for 'wget', 'samba-client' and 'lukemftp'. +* Fri Jun 10 2005 Fred Gleason +-- Added a Spanish [es] translation. +* Wed Jun 01 2005 Fred Gleason +-- Changed the 'mpg123' dependency to 'mpg321'. +* Fri Apr 29 2005 Fred Gleason +-- Added 'docs/ALSA.txt' to the %doc rule. +* Mon Feb 21 2005 Fred Gleason +-- Changed the invocation of '/sbin/ldconfig' to 'ldconfig'. +* Mon Jan 31 2005 Fred Gleason +-- Added 'bc' to Requires: +* Fri Jan 28 2005 Fred Gleason +-- Added 'mpg123' to Requires: +* Tue Jan 04 2005 Fred Gleason +-- Added RDImport to the files list. +* Thu Dec 09 2004 Fred Gleason +-- Added 'docs/WIN32.txt' to the %doc rule. +* Wed Dec 08 2004 Fred Gleason +-- Added 'docs/NOW+NEXT.txt' to the %doc rule. +* Tue Nov 23 2004 Fred Gleason +-- Added 'docs/reports.txt' to the %doc rule. +* Thu Nov 04 2004 Fred Gleason +-- Added 'conf/my.cnf-master' to the %doc rule. +-- Added 'conf/my.cnf-standby' to the %doc rule. +-- Added 'docs/rml.sxw' to the %doc rule. +-- Added '/usr/local/bin/rd_audio_sync'. +-- Added '/usr/local/bin/rd_config'. +* Mon Nov 01 2004 Fred Gleason +-- Added RDGpiMon. +* Tue Sep 14 2004 Fred Gleason +-- Removed GPITest and GPOTest. +* Thu Aug 26 2004 Fred Gleason +-- Added RDImport. +* Wed Jul 28 2004 Fred Gleason +-- Added '/etc/sysconfig/rivendell'. +* Fri Jun 26 2004 Fred Gleason +-- Added 'docs/JACK.txt'. +* Wed Jun 09 2004 Fred Gleason +-- Added a rule to %post to create the pidfile directory. +-- Made 'caed', 'ripcd' and 'rdcatchd' SETUID root. +* Mon Jun 07 2004 Fred Gleason +-- Added 'RDLogManager' +* Tue Jun 01 2004 Fred Gleason +-- Removed 'RDPlay', 'RDRecord' and 'mpeg2wav'. +* Tue May 04 2004 Fred Gleason +-- Added 'librd' shared library. +* Mon May 03 2004 Fred Gleason +-- Added a dependency for 'mysql-shared'. +-- Added 'rd_import_file'. +* Wed Apr 28 2004 Fred Gleason +-- Added 'rdpanel' +* Thu Feb 05 2004 Fred Gleason +-- Added 'docs/SWITCHERS.txt'. +* Thu Jan 29 2004 Fred Gleason +-- Added 'sas_shim'. +* Wed Jan 28 2004 Fred Gleason +-- Added 'docs/implemented_macros.txt' to the documentation directory. +* Wed Dec 23 2003 Fred Gleason +-- Added a dependency for 'qt3-mysql'. +-- Added install rule for 'rc.rivendell'. +* Thu Dec 11 2003 Fred Gleason +-- Added 'conf/rd.conf-sample' and 'conf/rd.conf-complete-sample' to + the doc directory +* Tue Dec 09 2003 Fred Gleason +-- Added dependencies for sox and cdparanoia. +* Sun Dec 07 2003 Fred Gleason +-- Initial spec file creation. diff --git a/rivendell.sys b/rivendell.sys new file mode 100644 index 00000000..e1476d57 --- /dev/null +++ b/rivendell.sys @@ -0,0 +1,67 @@ +## Path: Applications/Rivendell +## Description: Configure the Rivendell system daemons. + +## Type: yesno +## Default no +# +# Start the MeasurementComputing GPIO driver? +# +GPIO_START="no" + +## Type: yesno +## Default no +# +# Start the AudioScience HPI driver? +# +HPI_START="no" + +## Type: yesno +## Default no +# +# Start the Axia LiveWire driver? +# +LIVEWIRE_START="no" + +## Type: yesno +## Default no +# +# Start jackd? +# (NOTE: this option is here for backwards compatibity only! +# A much better method for controlling JACK is to set the 'JACK_START_SERVER' +# environmental variable and use '/etc/jackdrc' for configuration. See +# the jackd man page for details.) +# +JACK_START="no" + +## Type: integer +## Default 48000 +# +# Set the sample rate of the jackd daemon. +# (NOTE: this option is here for backwards compatibity only! +# A much better method for controlling JACK is to set the 'JACK_START_SERVER' +# environmental variable and use '/etc/jackdrc' for configuration. See +# the jackd man page for details.) +# +JACK_SAMPLE_RATE="48000" + +## Type: string +## Default hw:0 +# +# Set the ALSA device for the jackd daemon to use. +# (NOTE: this option is here for backwards compatibity only! +# A much better method for controlling JACK is to set the 'JACK_START_SERVER' +# environmental variable and use '/etc/jackdrc' for configuration. See +# the jackd man page for details.) +# +JACK_ALSA_DEVICE="hw:0" + +## Type: yesno +## Default no +# +# Use realtime scheduling for audio threads. +# (NOTE: this option is here for backwards compatibity only! +# A much better method for controlling JACK is to set the 'JACK_START_SERVER' +# environmental variable and use '/etc/jackdrc' for configuration. See +# the jackd man page for details.) +# +JACK_USE_REALTIME="no" diff --git a/rlm/Makefile-example b/rlm/Makefile-example new file mode 100644 index 00000000..f50cf4e1 --- /dev/null +++ b/rlm/Makefile-example @@ -0,0 +1,42 @@ +## Makefile +## +## An example Makefile for building Rivendell Loadable Modules +## +## (C) Copyright 2008-2013 Fred Gleason +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU Library General Public License +## version 2 as published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## + +OBJS = rlm_ando.rlm\ + rlm_facebook.rlm\ + rlm_icecast2.rlm\ + rlm_inno713.rlm\ + rlm_liqcomp.rlm\ + rlm_padpoint.rlm\ + rlm_serial.rlm\ + rlm_shoutcast1.rlm\ + rlm_spinitron_plus.rlm\ + rlm_spottrap.rlm\ + rlm_test.rlm\ + rlm_twitter.rlm\ + rlm_udp.rlm \ + rlm_xmpad.rlm + +%.rlm: %.c + $(CC) $(CFLAGS) -fPIC -shared $< -o $@ + +all: $(OBJS) + +clean: + rm -f $(OBJS) *~ diff --git a/rlm/Makefile.am b/rlm/Makefile.am new file mode 100644 index 00000000..3fb71bdc --- /dev/null +++ b/rlm/Makefile.am @@ -0,0 +1,90 @@ +## automake.am +## +## Automake.am for rivendell/rlm +## +## (C) Copyright 2008 Fred Gleason +## +## $Id: Makefile.am,v 1.7.4.5 2013/09/12 23:26:11 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CFLAGS = -fPIC -Wall + +RLM_MODULES=rlm_ando.rlm\ + rlm_facebook.rlm\ + rlm_filewrite.rlm\ + rlm_icecast2.rlm\ + rlm_inno713.rlm\ + rlm_liqcomp.rlm\ + rlm_padpoint.rlm\ + rlm_serial.rlm\ + rlm_shoutcast1.rlm\ + rlm_spinitron_plus.rlm\ + rlm_spottrap.rlm\ + rlm_test.rlm\ + rlm_twitter.rlm\ + rlm_udp.rlm\ + rlm_xds.rlm\ + rlm_xmpad.rlm + +all: $(RLM_MODULES) + +%.rlm: %.c + $(CC) $(AM_CFLAGS) -I$(top_srcdir) -shared $< -o $@ + +install: all + mkdir -p $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell + cp $(RLM_MODULES) $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/ + mkdir -p $(headerdir) + cp rlm.h $(headerdir) + +headerdir = $(includedir)/rlm +header_HEADERS = rlm.h + +EXTRA_DIST = Makefile-example\ + rlm.h\ + rlm_ando.c\ + rlm_facebook.c\ + rlm_filewrite.c\ + rlm_icecast2.c\ + rlm_inno713.c\ + rlm_liqcomp.c\ + rlm_padpoint.c\ + rlm_serial.c\ + rlm_shoutcast1.c\ + rlm_spinitron_plus.c\ + rlm_spottrap.c\ + rlm_test.c\ + rlm_twitter.c\ + rlm_udp.c\ + rlm_xds.c\ + rlm_xmpad.c + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + *.rlm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/rlm/rlm.h b/rlm/rlm.h new file mode 100644 index 00000000..351d4457 --- /dev/null +++ b/rlm/rlm.h @@ -0,0 +1,372 @@ +/* rlm.h + * + * The Rivendell Loadable Module Interface + * + * (C) Copyright 2008-2013 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * This interface can be used to create "Rivendell Loadable Modules" [RLMs] + * that enable Rivendell's "Now & Next" capability to supply program associated + * data [PAD] to external devices and systems. Runtime module configuration + * is accomplished in RDAdmin->ManageHosts->RDAirPlay->ConfigureNow&Next. + * + * Compiled plugins are dynamically loadable libraries (DLLs) and have names + * of the form '.rlm'. The following callbacks are provided: + * + * void _RLMStart(void *ptr,const char *arg) + * Called once upon RDAirPlay startup. The plugin should do any necessary + * startup tasks (opening i/o devices, allocating memory, etc) here. The + * single argument 'arg' is a null-terminated string, consisting of the + * 'Argument' parameter supplied in the specific runtime configuration + * from RDAdmin. The 'ptr' argument is an opaque pointer that is + * used as the first argument to the utility functions. + * + * void _RLMFree(void *ptr) + * Called once upon RDAirPlay shutdown. Any system resources allocated + * by the plugin should be released here. The 'ptr' argument is an opaque + * pointer that is be used as the first argument to any of the utility + * functions. + * + * + * void _RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + * const struct rlm_log *log, + * const struct rlm_pad *now, + * const struct rlm_pad *next) + * Called each time RDAirPlay changes play state on a log. The 'svc' + * and 'log' parameters provide information about the current log and + * service respectively. The 'ptr' argument is an opaque pointer that + * is used as the first argument to the utility functions. + * + * WARNING: the structures provided in this callback are dynamically + * allocated, their scope is valid only within the callback! + * + * void _RLMTimerExpired(void *ptr,int timernum) + * Called each time the system RLM timer indicated by 'timernum' expires. + * See the 'RLMStartTimer()' and 'RLMStopTimer()' functions for info on + * using timers. The 'ptr' argument is an opaque pointer that is + * used as the first argument to the utility functions. + * + * void _RLMSerialDataReceived(void *ptr,int handle, + * const char *data,int len) + * Called each time data is received on an open tty/serial device. See + * the 'RLMOpenSerial()' and 'RLMCloseSerial()' functions for info on + * using tty/serial devices. The 'ptr' argument is an opaque pointer + * that is used as the first argument to the utility functions. + */ + +#ifndef RLM_H +#define RLM_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * RLM Interface Version + */ +#define RLM_VERSION 17 + +/* + * Available Timers + */ +#define RLM_MAX_TIMERS 32 + +/* + * Timer Modes + * (for use in the RLMStartTimer() function). + */ +#define RLM_TIMER_REPEATING 0 +#define RLM_TIMER_ONESHOT 1 + +/* + * Parity Modes + * (for use in the RLMOpenSerial() function). + */ +#define RLM_PARITY_NONE 0 +#define RLM_PARITY_EVEN 1 +#define RLM_PARITY_ODD 2 + +/* + * Cart Types + * (for use in the 'rlm_carttype' field of the 'rlm_pad' struct) + */ +#define RLM_CARTTYPE_ALL 0 +#define RLM_CARTTYPE_AUDIO 1 +#define RLM_CARTTYPE_MACRO 2 + +/* + * Log Machine Modes + * (for use in the 'rlm_mode' field of the 'rlm_log' struct) + */ +#define RLM_LOGMODE_LIVEASSIST 1 +#define RLM_LOGMODE_AUTOMATIC 2 +#define RLM_LOGMODE_MANUAL 3 + +/* + * Data Encodings + * (for use in the RLMResolveNowNextEncoded() function). + */ +#define RLM_ENCODE_NONE 0 +#define RLM_ENCODE_XML 1 +#define RLM_ENCODE_URL 2 + +/* + * Service data structure + */ + struct rlm_svc { + char svc_name[256]; /* Service name */ + char svc_pgmcode[256]; /* Program Code */ + char reserved[1536]; /* Reserved for future use */ + }; + +/* + * Log data structure + */ + struct rlm_log { + char log_name[65]; /* Log name */ + uint32_t log_mach; /* Log machine number, 0=Main, 1=Aux 1, 2=Aux2 */ + char log_onair; /* On-air flag, 0=False, 1=True */ + uint32_t log_mode; /* Log machine mode, 1=LiveAssist, 2=Automatic, 3=Manual */ + char reserved[1974]; /* Reserved for future use */ + }; + +/* + * Metadata structure + */ + struct rlm_pad { + uint32_t rlm_cartnum; /* Rivendell cart number */ + uint32_t rlm_len; /* Event length, in milliseconds */ + char rlm_year[5]; /* Cart year */ + char rlm_group[11]; /* Rivendell Group Name */ + char rlm_title[256]; /* Cart 'title' field */ + char rlm_artist[256]; /* Cart 'artist' field */ + char rlm_label[65]; /* Cart 'label' field */ + char rlm_client[65]; /* Cart 'client' field */ + char rlm_agency[65]; /* Cart 'agency' field */ + char rlm_comp[65]; /* Cart 'composer' field */ + char rlm_pub[65]; /* Cart 'publisher' field */ + char rlm_userdef[256]; /* Cart 'user defined' field */ + char rlm_album[256]; /* Cart 'album' field */ + char rlm_isrc[12]; /* Cut International Standard Recording Code */ + char rlm_isci[32]; /* Cut ISCI Code */ + char rlm_carttype; /* Cart type, see RLM_CARTTYPE_* defines */ + char rlm_ext_eventid[33]; /* Event ID, from external scheduler */ + char rlm_ext_data[33]; /* Data, from external scheduler */ + char rlm_ext_annctype[1]; /* Announcement Type, from external scheduler */ + int32_t rlm_start_msec; /* Event start time, milliseconds part */ + int32_t rlm_start_sec; /* Event start time, seconds part */ + int32_t rlm_start_min; /* Event start time, minutes part */ + int32_t rlm_start_hour; /* Event start time, hours part */ + int32_t rlm_start_day; /* Event start date, day of month part */ + int32_t rlm_start_mon; /* Event start date, month of year part */ + int32_t rlm_start_year; /* Event start date, year part */ + char rlm_conductor[65]; /* Cart 'conductor' field */ + char rlm_song_id[33]; /* Cart 'songId' field */ + char rlm_outcue[65]; /* Cut outcue field */ + char rlm_description[65]; /* Cut description field */ + char reserved[305]; /* Reserved for future use */ + }; + +/* + * Communications Functions + * + * + * Send a UDP packet. + * + * The parameter is a null-terminated string consisting of the + * IPv4 destination address in dotted-quad notation, and is the + * destination UDP port number. All structures are in host (*not* network) + * byte order. The data to be sent, of length , is pointed to by + * . + */ + void RLMSendUdp(void *ptr,const char *ipaddr,uint16_t port, + const char *data,int len); + +/* + * Open a tty device (serial port) for output. + * + * The parameter is a null-terminated string consisting of the + * name of the tty device to open (e.g. "/dev/ttyS0"). The , + * and parameters define the communications + * parameters to be used. + * + * RETURNS: if successful, a non-negative integer that should be used + * as the argument for the RLMSendSerial() and RLMCloseSerial() + * functions. If unsuccessful, a negative integer will be returned. + */ + int RLMOpenSerial(void *ptr,const char *devname,int speed, + int parity,int word_length); + +/* + * Output data on a tty device. + * + * Output data of length pointed to by on the tty device + * indicated by the value returned by the RLMOpenSerial() function. + */ + void RLMSendSerial(void *ptr,int handle,const char *data,int len); + +/* + * Close a tty device. + * + * Close the tty device indicated by the value returned by the + * RLMOpenSerial() function. + */ + void RLMCloseSerial(void *ptr,int handle); + +/* + * Convienence Functions + */ + +/* + * Get a string indicating the system time. + * + * Returns a pointer to a null-terminated string indicating the system time, + * formatted as per the argument. The following wildcards are + * supported: + * d the day as number without a leading zero (1-31) + * dd the day as number with a leading zero (01-31) + * ddd the abbreviated localized day name (e.g. 'Mon'..'Sun'). + * dddd the long localized day name (e.g. 'Monday'..'Sunday'). + * M the month as number without a leading zero (1-12) + * MM the month as number with a leading zero (01-12) + * MMM the abbreviated localized month name (e.g. 'Jan'..'Dec'). + * MMMM the long localized month name (e.g. 'January'..'December'). + * yy the year as two digit number (00-99) + * yyyy the year as four digit number (1752-8000) + * h the hour without a leading zero (0..23 or 1..12 if AM/PM + * display) + * hh the hour with a leading zero (00..23 or 01..12 if AM/PM display) + * m the minute without a leading zero (0..59) + * mm the minute with a leading zero (00..59) + * s the second whithout a leading zero (0..59) + * ss the second whith a leading zero (00..59) + * z the milliseconds without leading zeroes (0..999) + * zzz the milliseconds with leading zeroes (000..999) + * AP use AM/PM display. AP will be replaced by either "AM" or "PM". + * ap use am/pm display. ap will be replaced by either "am" or "pm". + * + * RETURNS: A pointer to a null terminated string. This string is statically + * allocated, and may be reused in subsequent calls to the utility functions. + */ + const char *RLMDateTime(void *ptr,int offset_msecs,const char *format); + +/* + * Resolve standard Rivendell Now & Next wildcards, with the possiblity + * to encode the PAD fields. + * + * Returns a pointer to a null-terminated string resulting from resolving + * the 'standard' Rivendell Now & Next wildcards in accordance with the + * data values in the and parameters. The following wildcards + * are supported: + * + * Now Next Field + * ---------------------------------------------- + * %n %N The Rivendell cart number + * %h %H Event length (in milliseconds) + * %g %G The Rivendell group name + * %t %T Title + * %a %A Artist + * %l %L Album + * %y %Y Year + * %b %B Record Label + * %c %C Client + * %e %E Agency + * %m %M Composer + * %p %P Publisher + * %r %R Conductor + * %s %S Song ID + * %u %U User Definied + * %o %O Outcue + * %i %I Description + * %D(
) The current date/time, formatted according to
.
+ * can be any of the wildcards supported by the RLMDateTime() + * function (see above). + * + * Additionally, an encoding can be specified to allow PAD fields to be + * escaped for a particular format. Available encodings are: + * + * RLM_ENCODE_NONE - Perform no character escaping. + * RLM_ENCODE_XML - Escape reserved characters as per XML-v1.0 + * RLM_ENCODE_URL - Escape reserved characters as per RFC 2396 Section 2.4 + * + * RETURNS: A pointer to a null terminated string. This string is statically + * allocated, and may be reused in subsequent calls to the utility functions. + */ + const char *RLMResolveNowNextEncoded(void *ptr,const struct rlm_pad *now, + const struct rlm_pad *next, + const char *format,int encoding); + +/* + * Resolve standard Rivendell Now & Next wildcards + * + * (NOTE: This function is deprecated, and included merely to keep old code + * working. It should *not* be used in new code. For a better alternative, + * see the RLMResolveNowNextEncoded() function above). + * + * Returns a pointer to a null-terminated string resulting from resolving + * the 'standard' Rivendell Now & Next wildcards in accordance with the + * data values in the and parameters. The following wildcards + * are supported: + * + * Now Next Field + * ---------------------------------------------- + * %n %N The Rivendell cart number + * %h %H Event length (in milliseconds) + * %g %G The Rivendell group name + * %t %T Title + * %a %A Artist + * %l %L Album + * %y %Y Year + * %b %B Record Label + * %c %C Client + * %e %E Agency + * %m %M Composer + * %p %P Publisher + * %r %R Conductor + * %s %S Song ID + * %u %U User Definied + * %o %O Outcue + * %d %D Cut Description + * + * RETURNS: A pointer to a null terminated string. This string is statically + * allocated, and may be reused in subsequent calls to the utility functions. + */ + const char *RLMResolveNowNext(void *ptr,const struct rlm_pad *now, + const struct rlm_pad *next,const char *format); + + void RLMLog(void *ptr,int prio,const char *msg); + void RLMStartTimer(void *ptr,int timernum,int msecs,int mode); + void RLMStopTimer(void *ptr,int timernum); + int RLMGetIntegerValue(void *ptr,const char *filename,const char *section, + const char *label,int default_value); + int RLMGetHexValue(void *ptr,const char *filename, + const char *section,const char *label,int default_value); + int RLMGetBooleanValue(void *ptr,const char *filename, + const char *section,const char *label, + int default_value); + const char *RLMGetStringValue(void *ptr,const char *filename, + const char *section,const char *label, + const char *default_value); + + +#ifdef __cplusplus +} +#endif + +#endif /* RLM_H */ diff --git a/rlm/rlm_ando.c b/rlm/rlm_ando.c new file mode 100644 index 00000000..09f11f80 --- /dev/null +++ b/rlm/rlm_ando.c @@ -0,0 +1,217 @@ +/* rlm_ando.c + * + * (C) Copyright 2009 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It sends Now&Next PAD data to an + * ANDO Media Streaming system. Options are specified in the configuration + * file pointed to by the plugin argument. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_ando.rlm rlm_ando.c + */ + +#include +#include +#include +#include +#include + +int rlm_ando_devs; +char *rlm_ando_addresses; +uint16_t *rlm_ando_ports; +char *rlm_ando_titles; +char *rlm_ando_artists; +char *rlm_ando_albums; +char *rlm_ando_labels; +int *rlm_ando_masters; +int *rlm_ando_aux1s; +int *rlm_ando_aux2s; + +int rlm_ando_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_ando_RLMStart(void *ptr,const char *arg) +{ + char address[17]; + char section[256]; + char errtext[256]; + int i=1; + + rlm_ando_devs=0; + rlm_ando_addresses=NULL; + rlm_ando_ports=NULL; + rlm_ando_masters=NULL; + rlm_ando_aux1s=NULL; + rlm_ando_aux2s=NULL; + + sprintf(section,"System%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + if(strlen(address)==0) { + RLMLog(ptr,LOG_WARNING,"rlm_ando: no ando destinations specified"); + return; + } + while(strlen(address)>0) { + rlm_ando_addresses= + realloc(rlm_ando_addresses,(rlm_ando_devs+1)*(rlm_ando_devs+1)*16); + strcpy(rlm_ando_addresses+16*rlm_ando_devs,address); + rlm_ando_ports=realloc(rlm_ando_ports,(rlm_ando_devs+1)*sizeof(uint16_t)); + rlm_ando_ports[rlm_ando_devs]= + RLMGetIntegerValue(ptr,arg,section,"UdpPort",0); + rlm_ando_titles=realloc(rlm_ando_titles,(rlm_ando_devs+1)*256); + strncpy(rlm_ando_titles+256*rlm_ando_devs, + RLMGetStringValue(ptr,arg,section,"Title",""),256); + rlm_ando_artists=realloc(rlm_ando_artists,(rlm_ando_devs+1)*256); + strncpy(rlm_ando_artists+256*rlm_ando_devs, + RLMGetStringValue(ptr,arg,section,"Artist",""),256); + rlm_ando_albums=realloc(rlm_ando_albums,(rlm_ando_devs+1)*256); + strncpy(rlm_ando_albums+256*rlm_ando_devs, + RLMGetStringValue(ptr,arg,section,"Album",""),256); + rlm_ando_labels=realloc(rlm_ando_labels,(rlm_ando_devs+1)*256); + strncpy(rlm_ando_labels+256*rlm_ando_devs, + RLMGetStringValue(ptr,arg,section,"Label",""),256); + rlm_ando_masters=realloc(rlm_ando_masters, + (rlm_ando_devs+1)*sizeof(int)); + rlm_ando_masters[rlm_ando_devs]= + rlm_ando_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_ando_aux1s=realloc(rlm_ando_aux1s, + (rlm_ando_devs+1)*sizeof(int)); + rlm_ando_aux1s[rlm_ando_devs]= + rlm_ando_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_ando_aux2s=realloc(rlm_ando_aux2s, + (rlm_ando_devs+1)*sizeof(int)); + rlm_ando_aux2s[rlm_ando_devs]= + rlm_ando_GetLogStatus(ptr,arg,section,"Aux2Log"); + sprintf(errtext,"rlm_ando: configured destination \"%s:%d\"",address, + rlm_ando_ports[rlm_ando_devs]); + rlm_ando_devs++; + RLMLog(ptr,LOG_INFO,errtext); + sprintf(section,"System%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + } + RLMStartTimer(ptr,0,30000,RLM_TIMER_REPEATING); +} + + +void rlm_ando_RLMFree(void *ptr) +{ + RLMStopTimer(ptr,0); + free(rlm_ando_addresses); + free(rlm_ando_ports); + free(rlm_ando_titles); + free(rlm_ando_artists); + free(rlm_ando_albums); + free(rlm_ando_labels); + free(rlm_ando_masters); + free(rlm_ando_aux1s); + free(rlm_ando_aux2s); +} + + +void rlm_ando_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char fmt[1024]; + char msg[1500]; + int hours; + int minutes; + int seconds; + + for(i=0;ilog_mach) { + case 0: + flag=rlm_ando_masters[i]; + break; + + case 1: + flag=rlm_ando_aux1s[i]; + break; + + case 2: + flag=rlm_ando_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + if(strlen(rlm_ando_labels+256*i)==0) { // Original format + snprintf(fmt,1024,"^%s~%s~%02d:%02d~%%g~%s~%%n|", + rlm_ando_artists+256*i, + rlm_ando_titles+256*i, + now->rlm_len/60000,(now->rlm_len%60000)/1000, + rlm_ando_albums+256*i); + } + else { // Enhanced format + hours=now->rlm_len/3600000; + minutes=(now->rlm_len-hours*3600000)/60000; + seconds=(now->rlm_len-hours*3600000-minutes*60000)/1000; + snprintf(fmt,1024,"^%s~%s~%02d:%02d:%02d~%%g~%%n~%s~%s|", + rlm_ando_artists+256*i, + rlm_ando_titles+256*i, + hours,minutes,seconds, + rlm_ando_albums+256*i, + rlm_ando_labels+256*i); + } + const char *str=RLMResolveNowNext(ptr,now,next,fmt); + RLMSendUdp(ptr,rlm_ando_addresses+i*16,rlm_ando_ports[i],str,strlen(str)); + snprintf(msg,1500,"rlm_ando: sending pad update: \"%s\"", + (const char *)str); + RLMLog(ptr,LOG_INFO,msg); + } + } +} + + +void rlm_ando_RLMTimerExpired(void *ptr,int timernum) +{ + int i; + + switch(timernum) { + case 0: // Heartbeat + for(i=0;i + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It sends Now&Next PAD data + * to the Facebook account(s) specified in the configuration file pointed + * to by the plugin argument. For information about the Facebook service, + * see http://www.facebook.com/. + * + * This module requires the curl(1) network transfer tool, included with + * most Linux distros. It is also available at http://curl.haxx.se/. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_facebook.rlm rlm_facebook.c + */ + +#include +#include +#include +#include +#include +#include + +#include + +int rlm_facebook_devs; +char *rlm_facebook_addresses; +char *rlm_facebook_passwords; +char *rlm_facebook_formats; +int *rlm_facebook_masters; +int *rlm_facebook_aux1s; +int *rlm_facebook_aux2s; +char *rlm_facebook_cookies; + + +int rlm_facebook_BufferDiff(char *sString,int dOrigin,int dDiff,int dMaxSize) +{ + int dOldSize,dNewSize; + int i; + + /* + * Will it fit? + */ + dOldSize=strlen(sString); + if((dOldSize+dDiff)>=dMaxSize) { + return -1; + } + dNewSize=dOldSize+dDiff; + + /* + * Adding characters + */ + if(dDiff>0) { + for(i=dOldSize;i>dOrigin;i--) { + sString[i+dDiff]=sString[i]; + } + return dNewSize; + } + + /* + * No Change + */ + if(dDiff==0) { + return dNewSize; + } + + /* + * Deleting Characters + */ + if(dDiff<0) { + for(i=dOrigin;i'9') && (sString[i]<'A')) || + ((sString[i]>'Z') && (sString[i]<'a')) || + (sString[i]>'z'))) { + if(rlm_facebook_BufferDiff(sString,i,2,dMaxSize)<0) { + return -1; + } + sprintf(sAccum,"%%%2x",sString[i]); + sString[i++]=sAccum[0]; + sString[i++]=sAccum[1]; + sString[i]=sAccum[2]; + } + if(sString[i]==' ') { + sString[i]='+'; + } + i++; + } + return strlen(sString); +} + + +void rlm_facebook_Login(int config) +{ + char cmd[1024]; + + unlink(rlm_facebook_cookies+256*config); /* Cleanup from past session */ + snprintf(cmd,1024, + "curl -o /dev/null -s -A Mozilla/4.0 -c %s http://www.facebook.com/", + rlm_facebook_cookies+256*config); + system(cmd); + snprintf(cmd,1024,"curl -o /dev/null -s --insecure -A Mozilla/4.0 -c %s -b %s -d persistent=1 -d email=%s -d pass=%s https://login.facebook.com/login.php", + rlm_facebook_cookies+256*config, + rlm_facebook_cookies+256*config, + rlm_facebook_addresses+256*config, + rlm_facebook_passwords+256*config); + system(cmd); +} + + +void rlm_facebook_Logout(int config) +{ + if(fork()==0) { + execlp("curl","curl","-A","Mozilla/4.0","-b", + rlm_facebook_cookies+256*config, + "-o","/dev/null","-s", + "http://www.facebook.com/logout.php", + (char *)NULL); + exit(0); + } +} + + +int rlm_facebook_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_facebook_RLMStart(void *ptr,const char *arg) +{ + char address[256]; + char section[256]; + char errtext[256]; + int i=1; + + rlm_facebook_devs=0; + rlm_facebook_addresses=NULL; + rlm_facebook_passwords=NULL; + rlm_facebook_formats=NULL; + rlm_facebook_masters=NULL; + rlm_facebook_aux1s=NULL; + rlm_facebook_aux2s=NULL; + rlm_facebook_cookies=NULL; + + sprintf(section,"Facebook%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"EmailAddress",""),255); + address[255]=0; + if(strlen(address)==0) { + RLMLog(ptr,LOG_WARNING,"rlm_facebook: no facebook accounts specified"); + return; + } + while(strlen(address)>0) { + rlm_facebook_addresses=realloc(rlm_facebook_addresses, + (rlm_facebook_devs+1)*(rlm_facebook_devs+1)*256); + strcpy(rlm_facebook_addresses+256*rlm_facebook_devs,address); + rlm_facebook_EncodeString(rlm_facebook_addresses+256*rlm_facebook_devs,255); + rlm_facebook_passwords=realloc(rlm_facebook_passwords, + (rlm_facebook_devs+1)*(rlm_facebook_devs+1)*256); + strcpy(rlm_facebook_passwords+256*rlm_facebook_devs, + RLMGetStringValue(ptr,arg,section,"Password","")); + rlm_facebook_EncodeString(rlm_facebook_passwords+256*rlm_facebook_devs,255); + rlm_facebook_formats=realloc(rlm_facebook_formats,(rlm_facebook_devs+1)*256); + strncpy(rlm_facebook_formats+256*rlm_facebook_devs, + RLMGetStringValue(ptr,arg,section,"FormatString",""),256); + rlm_facebook_masters=realloc(rlm_facebook_masters, + (rlm_facebook_devs+1)*sizeof(int)); + rlm_facebook_masters[rlm_facebook_devs]= + rlm_facebook_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_facebook_aux1s=realloc(rlm_facebook_aux1s, + (rlm_facebook_devs+1)*sizeof(int)); + rlm_facebook_aux1s[rlm_facebook_devs]= + rlm_facebook_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_facebook_aux2s=realloc(rlm_facebook_aux2s, + (rlm_facebook_devs+1)*sizeof(int)); + rlm_facebook_aux2s[rlm_facebook_devs]= + rlm_facebook_GetLogStatus(ptr,arg,section,"Aux2Log"); + sprintf(errtext,"rlm_facebook: configured account \"%s\"",address); + rlm_facebook_cookies= + realloc(rlm_facebook_cookies,(rlm_facebook_devs+1)*256); + snprintf(rlm_facebook_cookies+rlm_facebook_devs*256,256, + "/tmp/rlm_facebook%d_cookies.txt",rlm_facebook_devs+1); + rlm_facebook_devs++; + RLMLog(ptr,LOG_INFO,errtext); + sprintf(section,"Facebook%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"EmailAddress",""),255); + address[255]=0; + } + + for(i=0;i<(rlm_facebook_devs);i++) { + rlm_facebook_Login(i); + } +} + + +void rlm_facebook_RLMFree(void *ptr) +{ + int i; + + for(i=0;i<(rlm_facebook_devs);i++) { + rlm_facebook_Logout(i); + } + free(rlm_facebook_addresses); + free(rlm_facebook_passwords); + free(rlm_facebook_formats); + free(rlm_facebook_masters); + free(rlm_facebook_aux1s); + free(rlm_facebook_aux2s); + free(rlm_facebook_cookies); +} + + +void rlm_facebook_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char str[1024]; + char pad[1024]; + char msg[1500]; + + for(i=0;ilog_mach) { + case 0: + flag=rlm_facebook_masters[i]; + break; + + case 1: + flag=rlm_facebook_aux1s[i]; + break; + + case 2: + flag=rlm_facebook_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + strncpy(str,RLMResolveNowNext(ptr,now,next, + rlm_facebook_formats+256*i),256); + rlm_facebook_EncodeString(str,1023); + snprintf(pad,1024,"status=%s",str); + if(strlen(now->rlm_title)!=0) { + if(fork()==0) { + execlp("curl","curl","-A","Mozilla/4.0","-b", + rlm_facebook_cookies+256*i, + "-d",pad, + "-d","test_name=INLINE_STATUS_EDITOR", + "-d","action=OTHER_UPDATE", + "-d","post_form_id=aae2d1af1c8ed0cd36ade54bc8f48427", + "-o","/dev/null","-s", + "http://www.facebook.com/updatestatus.php",(char *)NULL); + RLMLog(ptr,LOG_WARNING,"rlm_facebook: unable to execute curl(1)"); + exit(0); + } + } + snprintf(msg,1500,"rlm_facebook: sending pad update: \"%s\"", + (const char *)str); + RLMLog(ptr,LOG_INFO,msg); + } + } +} diff --git a/rlm/rlm_filewrite.c b/rlm/rlm_filewrite.c new file mode 100644 index 00000000..d3c02841 --- /dev/null +++ b/rlm/rlm_filewrite.c @@ -0,0 +1,228 @@ +/* rlm_filewrite.c + * + * (C) Copyright 2012 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It uses Now&Next PAD data + * to write to one or more file(s) on the local system specified in the + * configuration file pointed to by the plugin argument. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_filewrite.rlm rlm_filewrite.c + */ + +#include +#include +#include +#include +#include +#include + +#include + +int rlm_filewrite_devs; +char *rlm_filewrite_filenames; +int *rlm_filewrite_appends; +char *rlm_filewrite_formats; +int *rlm_filewrite_encodings; +int *rlm_filewrite_masters; +int *rlm_filewrite_aux1s; +int *rlm_filewrite_aux2s; + +void rlm_filewrite_ReplaceChar(char c,char *str,int pos) +{ + int i; + + str[pos]=c; + for(i=pos+1;i0) { + rlm_filewrite_filenames=realloc(rlm_filewrite_filenames, + (rlm_filewrite_devs+1)*(rlm_filewrite_devs+1)*256); + strcpy(rlm_filewrite_filenames+256*rlm_filewrite_devs,filename); + rlm_filewrite_appends=realloc(rlm_filewrite_appends, + (rlm_filewrite_devs+1)*sizeof(int)); + rlm_filewrite_appends[rlm_filewrite_devs]= + RLMGetIntegerValue(ptr,arg,section,"Append",0); + rlm_filewrite_formats=realloc(rlm_filewrite_formats,(rlm_filewrite_devs+1)*256); + strncpy(rlm_filewrite_formats+256*rlm_filewrite_devs, + RLMGetStringValue(ptr,arg,section,"FormatString",""),256); + rlm_filewrite_masters=realloc(rlm_filewrite_masters, + (rlm_filewrite_devs+1)*sizeof(int)); + rlm_filewrite_masters[rlm_filewrite_devs]= + rlm_filewrite_GetLogStatus(ptr,arg,section,"MasterLog"); + + rlm_filewrite_encodings=realloc(rlm_filewrite_encodings, + (rlm_filewrite_devs+1)*sizeof(int)); + rlm_filewrite_encodings[rlm_filewrite_devs]= + RLMGetIntegerValue(ptr,arg,section,"Encoding",RLM_ENCODE_NONE); + rlm_filewrite_aux1s=realloc(rlm_filewrite_aux1s, + (rlm_filewrite_devs+1)*sizeof(int)); + rlm_filewrite_aux1s[rlm_filewrite_devs]= + rlm_filewrite_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_filewrite_aux2s=realloc(rlm_filewrite_aux2s, + (rlm_filewrite_devs+1)*sizeof(int)); + rlm_filewrite_aux2s[rlm_filewrite_devs]= + rlm_filewrite_GetLogStatus(ptr,arg,section,"Aux2Log"); + sprintf(errtext,"rlm_filewrite: configured file \"%s\"", + rlm_filewrite_filenames+256*rlm_filewrite_devs); + rlm_filewrite_devs++; + RLMLog(ptr,LOG_INFO,errtext); + sprintf(section,"File%d",i++); + strncpy(filename,RLMGetStringValue(ptr,arg,section,"Filename",""),255); + filename[255]=0; + } +} + + +void rlm_filewrite_RLMFree(void *ptr) +{ + free(rlm_filewrite_filenames); + free(rlm_filewrite_appends); + free(rlm_filewrite_formats); + free(rlm_filewrite_encodings); + free(rlm_filewrite_masters); + free(rlm_filewrite_aux1s); + free(rlm_filewrite_aux2s); +} + + +void rlm_filewrite_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char str[8192]; + char msg[1500]; + FILE *f; + + for(i=0;ilog_mach) { + case 0: + flag=rlm_filewrite_masters[i]; + break; + + case 1: + flag=rlm_filewrite_aux1s[i]; + break; + + case 2: + flag=rlm_filewrite_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + strncpy(str,RLMResolveNowNextEncoded(ptr,now,next, + rlm_filewrite_formats+256*i, + rlm_filewrite_encodings[i]),8192); + rlm_filewrite_ProcessString(str); + if(rlm_filewrite_appends[i]==0) { + f=fopen(rlm_filewrite_filenames+256*i,"w"); + } + else { + f=fopen(rlm_filewrite_filenames+256*i,"a"); + } + if(f!=NULL) { + snprintf(msg,1500,"rlm_filewrite: sending pad update: \"%s\" to \"%s\"", + str,rlm_filewrite_filenames+256*i); + fprintf(f,"%s",str); + fclose(f); + RLMLog(ptr,LOG_INFO,msg); + } + else { + snprintf(msg,1500,"rlm_filewrite: unable to open file \"%s\"", + rlm_filewrite_filenames+256*i); + RLMLog(ptr,LOG_WARNING,msg); + } + } + } +} diff --git a/rlm/rlm_icecast2.c b/rlm/rlm_icecast2.c new file mode 100644 index 00000000..6e3cc056 --- /dev/null +++ b/rlm/rlm_icecast2.c @@ -0,0 +1,295 @@ +/* rlm_icecast2.c + * + * (C) Copyright 2008 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It uses Now&Next PAD data + * to update the metadata on an Icecast2 mountpoint specified in the + * configuration file pointed to by the plugin argument. + * + * This module requires the curl(1) network transfer tool, included with + * most Linux distros. It is also available at http://curl.haxx.se/. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_icecast2.rlm rlm_icecast2.c + */ + +#include +#include +#include +#include +#include +#include + +#include + +int rlm_icecast2_devs; +char *rlm_icecast2_usernames; +char *rlm_icecast2_passwords; +char *rlm_icecast2_hostnames; +int *rlm_icecast2_tcpports; +char *rlm_icecast2_mountpoints; +char *rlm_icecast2_formats; +int *rlm_icecast2_masters; +int *rlm_icecast2_aux1s; +int *rlm_icecast2_aux2s; + + +int rlm_icecast2_BufferDiff(char *sString,int dOrigin,int dDiff,int dMaxSize) +{ + int dOldSize,dNewSize; + int i; + + /* + * Will it fit? + */ + dOldSize=strlen(sString); + if((dOldSize+dDiff)>=dMaxSize) { + return -1; + } + dNewSize=dOldSize+dDiff; + + /* + * Adding characters + */ + if(dDiff>0) { + for(i=dOldSize;i>dOrigin;i--) { + sString[i+dDiff]=sString[i]; + } + return dNewSize; + } + + /* + * No Change + */ + if(dDiff==0) { + return dNewSize; + } + + /* + * Deleting Characters + */ + if(dDiff<0) { + for(i=dOrigin;i'9') && (sString[i]<'A')) || + ((sString[i]>'Z') && (sString[i]<'a')) || + (sString[i]>'z'))) { + if(rlm_icecast2_BufferDiff(sString,i,2,dMaxSize)<0) { + fprintf(stderr,"rlm_icecast2: BufferDiff() failed, maxsize: %d\n", + dMaxSize); + return -1; + } + sprintf(sAccum,"%%%2x",sString[i]); + sString[i++]=sAccum[0]; + sString[i++]=sAccum[1]; + sString[i]=sAccum[2]; + } + if(sString[i]==' ') { + sString[i]='+'; + } + i++; + if(i>=dMaxSize) { + fprintf(stderr,"rlm_icecast2: offset exceeded limit, maxsize: %d\n", + dMaxSize); + return -1; + } + } + return strlen(sString); +} + + +int rlm_icecast2_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_icecast2_RLMStart(void *ptr,const char *arg) +{ + char username[256]; + char section[256]; + char errtext[256]; + int i=1; + + rlm_icecast2_devs=0; + rlm_icecast2_usernames=NULL; + rlm_icecast2_passwords=NULL; + rlm_icecast2_formats=NULL; + rlm_icecast2_masters=NULL; + rlm_icecast2_aux1s=NULL; + rlm_icecast2_aux2s=NULL; + + sprintf(section,"Icecast%d",i++); + strncpy(username,RLMGetStringValue(ptr,arg,section,"Username",""),255); + username[255]=0; + if(strlen(username)==0) { + RLMLog(ptr,LOG_WARNING,"rlm_icecast2: no icecast mountpoints specified"); + return; + } + while(strlen(username)>0) { + rlm_icecast2_usernames=realloc(rlm_icecast2_usernames, + (rlm_icecast2_devs+1)*(rlm_icecast2_devs+1)*256); + strcpy(rlm_icecast2_usernames+256*rlm_icecast2_devs,username); + + rlm_icecast2_passwords=realloc(rlm_icecast2_passwords, + (rlm_icecast2_devs+1)*(rlm_icecast2_devs+1)*256); + strcpy(rlm_icecast2_passwords+256*rlm_icecast2_devs, + RLMGetStringValue(ptr,arg,section,"Password","")); + rlm_icecast2_hostnames=realloc(rlm_icecast2_hostnames, + (rlm_icecast2_devs+1)*(rlm_icecast2_devs+1)*256); + strcpy(rlm_icecast2_hostnames+256*rlm_icecast2_devs, + RLMGetStringValue(ptr,arg,section,"Hostname","")); + rlm_icecast2_tcpports=realloc(rlm_icecast2_tcpports, + (rlm_icecast2_devs+1)*sizeof(int)); + rlm_icecast2_tcpports[rlm_icecast2_devs]= + RLMGetIntegerValue(ptr,arg,section,"Tcpport",0); + rlm_icecast2_mountpoints=realloc(rlm_icecast2_mountpoints, + (rlm_icecast2_devs+1)*(rlm_icecast2_devs+1)*256); + strcpy(rlm_icecast2_mountpoints+256*rlm_icecast2_devs, + RLMGetStringValue(ptr,arg,section,"Mountpoint","")); + rlm_icecast2_formats=realloc(rlm_icecast2_formats,(rlm_icecast2_devs+1)*256); + strncpy(rlm_icecast2_formats+256*rlm_icecast2_devs, + RLMGetStringValue(ptr,arg,section,"FormatString",""),256); + rlm_icecast2_masters=realloc(rlm_icecast2_masters, + (rlm_icecast2_devs+1)*sizeof(int)); + rlm_icecast2_masters[rlm_icecast2_devs]= + rlm_icecast2_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_icecast2_aux1s=realloc(rlm_icecast2_aux1s, + (rlm_icecast2_devs+1)*sizeof(int)); + rlm_icecast2_aux1s[rlm_icecast2_devs]= + rlm_icecast2_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_icecast2_aux2s=realloc(rlm_icecast2_aux2s, + (rlm_icecast2_devs+1)*sizeof(int)); + rlm_icecast2_aux2s[rlm_icecast2_devs]= + rlm_icecast2_GetLogStatus(ptr,arg,section,"Aux2Log"); + sprintf(errtext,"rlm_icecast2: configured mountpoint \"http://%s:%u%s\"", + rlm_icecast2_hostnames+256*rlm_icecast2_devs, + rlm_icecast2_tcpports[rlm_icecast2_devs], + rlm_icecast2_mountpoints+256*rlm_icecast2_devs); + rlm_icecast2_devs++; + RLMLog(ptr,LOG_INFO,errtext); + sprintf(section,"Icecast%d",i++); + strncpy(username,RLMGetStringValue(ptr,arg,section,"Username",""),255); + username[255]=0; + } +} + + +void rlm_icecast2_RLMFree(void *ptr) +{ + free(rlm_icecast2_usernames); + free(rlm_icecast2_passwords); + free(rlm_icecast2_hostnames); + free(rlm_icecast2_tcpports); + free(rlm_icecast2_mountpoints); + free(rlm_icecast2_formats); + free(rlm_icecast2_masters); + free(rlm_icecast2_aux1s); + free(rlm_icecast2_aux2s); +} + + +void rlm_icecast2_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char str[1024]; + char account[1024]; + char url[1024]; + char msg[1500]; + + for(i=0;ilog_mach) { + case 0: + flag=rlm_icecast2_masters[i]; + break; + + case 1: + flag=rlm_icecast2_aux1s[i]; + break; + + case 2: + flag=rlm_icecast2_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + strncpy(str,RLMResolveNowNext(ptr,now,next, + rlm_icecast2_formats+256*i),256); + rlm_icecast2_EncodeString(str,1023); + snprintf(account,1024,"%s:%s",rlm_icecast2_usernames+256*i, + rlm_icecast2_passwords+256*i); + snprintf(url,1024,"http://%s:%d/admin/metadata?mount=%s&mode=updinfo&song=%s", + rlm_icecast2_hostnames+256*i, + rlm_icecast2_tcpports[i], + rlm_icecast2_mountpoints+256*i,str); + if(strlen(now->rlm_title)!=0) { + if(fork()==0) { + execlp("curl","curl","-u",account,"-o","/dev/null","-s", + url,(char *)NULL); + RLMLog(ptr,LOG_WARNING,"rlm_icecast2: unable to execute curl(1)"); + exit(0); + } + } + snprintf(msg,1500,"rlm_icecast2: sending pad update: \"%s\"", + (const char *)str); + RLMLog(ptr,LOG_INFO,msg); + } + } +} diff --git a/rlm/rlm_inno713.c b/rlm/rlm_inno713.c new file mode 100644 index 00000000..fb462527 --- /dev/null +++ b/rlm/rlm_inno713.c @@ -0,0 +1,253 @@ +/* rlm_inno713.c + * + * (C) Copyright 2009 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It sends Now&Next PAD + * to the Innovonics model 713 RDS encoder, as specified in the + * configuration file pointed to by the plugin argument. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_inno713.rlm rlm_inno713.c + */ + +#include +#include +#include +#include +#include +#include + +int rlm_inno713_devs; +char *rlm_inno713_addresses; +uint16_t *rlm_inno713_ports; +int *rlm_inno713_handles; +char *rlm_inno713_dynamicpss; +char *rlm_inno713_pss; +char *rlm_inno713_radiotexts; +int *rlm_inno713_masters; +int *rlm_inno713_aux1s; +int *rlm_inno713_aux2s; + +void rlm_inno713_Upcase(char *str) +{ + int i; + + for(i=0;i0) { + const char *str=RLMResolveNowNext(ptr,now,next,fmt); + if(strlen(str)>0) { + sprintf(pkt,"%s=%s\r\n",tag,str); + rlm_inno713_Upcase(pkt); + if(strlen(addr)>0) { + RLMSendUdp(ptr,addr,port,pkt,strlen(pkt)); + } + if(handle>=0) { + RLMSendSerial(ptr,handle,pkt,strlen(pkt)); + } + } + } +} + + +int rlm_inno713_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_inno713_RLMStart(void *ptr,const char *arg) +{ + char address[17]; + char section[256]; + char errtext[256]; + char device[256]; + int speed; + int parity; + int wsize; + int i=1; + + rlm_inno713_devs=0; + rlm_inno713_addresses=NULL; + rlm_inno713_ports=NULL; + rlm_inno713_handles=NULL; + rlm_inno713_dynamicpss=NULL; + rlm_inno713_masters=NULL; + rlm_inno713_aux1s=NULL; + rlm_inno713_aux2s=NULL; + + sprintf(section,"Rds%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + strncpy(device,RLMGetStringValue(ptr,arg,section,"Device",""),256); + if((strlen(address)==0)&&(strlen(device)==0)) { + RLMLog(ptr,LOG_WARNING,"rlm_inno713: no RDS connections specified"); + return; + } + while((strlen(address)>0)||(strlen(device)>0)) { + rlm_inno713_addresses= + realloc(rlm_inno713_addresses, + (rlm_inno713_devs+1)*(rlm_inno713_devs+1)*16); + strcpy(rlm_inno713_addresses+16*rlm_inno713_devs,address); + rlm_inno713_ports=realloc(rlm_inno713_ports, + (rlm_inno713_devs+1)*sizeof(uint16_t)); + rlm_inno713_ports[rlm_inno713_devs]= + RLMGetIntegerValue(ptr,arg,section,"UdpPort",0); + speed=RLMGetIntegerValue(ptr,arg,section,"Speed",9600); + parity=RLMGetIntegerValue(ptr,arg,section,"Parity",0); + wsize=RLMGetIntegerValue(ptr,arg,section,"WordSize",8); + rlm_inno713_handles=realloc(rlm_inno713_handles, + (rlm_inno713_devs+1)*sizeof(int)); + rlm_inno713_handles[rlm_inno713_devs]= + RLMOpenSerial(ptr,device,speed,parity,wsize); + rlm_inno713_dynamicpss=realloc(rlm_inno713_dynamicpss,(rlm_inno713_devs+1)*256); + strncpy(rlm_inno713_dynamicpss+256*rlm_inno713_devs, + RLMGetStringValue(ptr,arg,section,"DynamicPsString",""),256); + + rlm_inno713_pss=realloc(rlm_inno713_pss,(rlm_inno713_devs+1)*256); + strncpy(rlm_inno713_pss+256*rlm_inno713_devs, + RLMGetStringValue(ptr,arg,section,"PsString",""),256); + rlm_inno713_radiotexts=realloc(rlm_inno713_radiotexts, + (rlm_inno713_devs+1)*256); + strncpy(rlm_inno713_radiotexts+256*rlm_inno713_devs, + RLMGetStringValue(ptr,arg,section,"RadiotextString",""),256); + rlm_inno713_masters=realloc(rlm_inno713_masters, + (rlm_inno713_devs+1)*sizeof(int)); + rlm_inno713_masters[rlm_inno713_devs]= + rlm_inno713_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_inno713_aux1s=realloc(rlm_inno713_aux1s, + (rlm_inno713_devs+1)*sizeof(int)); + rlm_inno713_aux1s[rlm_inno713_devs]= + rlm_inno713_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_inno713_aux2s=realloc(rlm_inno713_aux2s, + (rlm_inno713_devs+1)*sizeof(int)); + rlm_inno713_aux2s[rlm_inno713_devs]= + rlm_inno713_GetLogStatus(ptr,arg,section,"Aux2Log"); + sprintf(errtext,"rlm_inno713: configured destination \"%s:%d\"",address, + rlm_inno713_ports[rlm_inno713_devs]); + RLMLog(ptr,LOG_INFO,errtext); + if(strlen(device)>0) { + if(rlm_inno713_handles[rlm_inno713_devs]<0) { + sprintf(errtext,"rlm_inno713: unable to open serial device \"%s\"",device); + } + else { + sprintf(errtext,"rlm_inno713: configured serial device \"%s\"",device); + } + RLMLog(ptr,LOG_INFO,errtext); + } + rlm_inno713_devs++; + sprintf(section,"Rds%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + strncpy(device,RLMGetStringValue(ptr,arg,section,"Device",""),256); + } +} + + +void rlm_inno713_RLMFree(void *ptr) +{ + int i; + + free(rlm_inno713_addresses); + free(rlm_inno713_ports); + for(i=0;i=0) { + RLMCloseSerial(ptr,rlm_inno713_handles[i]); + } + } + free(rlm_inno713_handles); + free(rlm_inno713_dynamicpss); + free(rlm_inno713_pss); + free(rlm_inno713_radiotexts); + free(rlm_inno713_masters); + free(rlm_inno713_aux1s); + free(rlm_inno713_aux2s); +} + + +void rlm_inno713_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char msg[1500]; + + for(i=0;ilog_mach) { + case 0: + flag=rlm_inno713_masters[i]; + break; + + case 1: + flag=rlm_inno713_aux1s[i]; + break; + + case 2: + flag=rlm_inno713_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + rlm_inno713_SendString(ptr,now,next,"DPS",rlm_inno713_dynamicpss+256*i, + rlm_inno713_addresses+i*16,rlm_inno713_ports[i], + rlm_inno713_handles[i]); + rlm_inno713_SendString(ptr,now,next,"PS",rlm_inno713_pss+256*i, + rlm_inno713_addresses+i*16,rlm_inno713_ports[i], + rlm_inno713_handles[i]); + rlm_inno713_SendString(ptr,now,next,"TEXT",rlm_inno713_radiotexts+256*i, + rlm_inno713_addresses+i*16,rlm_inno713_ports[i], + rlm_inno713_handles[i]); + + const char *str=RLMResolveNowNext(ptr,now,next,rlm_inno713_pss+256*i); + snprintf(msg,1500,"rlm_inno713: sending pad update: \"%s\"",str); + RLMLog(ptr,LOG_INFO,msg); + } + } +} diff --git a/rlm/rlm_liqcomp.c b/rlm/rlm_liqcomp.c new file mode 100644 index 00000000..6f469978 --- /dev/null +++ b/rlm/rlm_liqcomp.c @@ -0,0 +1,189 @@ +/* rlm_liqcomp.c + * + * (C) Copyright 2009 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It sends Now&Next PAD data to a + * Liquid Compass Internet streaming encoder. Options are specified in the + * configuration file pointed to by the plugin argument. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_liqcomp.rlm rlm_liqcomp.c + */ + +#include +#include +#include +#include +#include + +int rlm_liqcomp_devs; +char *rlm_liqcomp_addresses; +uint16_t *rlm_liqcomp_ports; +char *rlm_liqcomp_titles; +char *rlm_liqcomp_artists; +char *rlm_liqcomp_albums; +char *rlm_liqcomp_labels; +int *rlm_liqcomp_masters; +int *rlm_liqcomp_aux1s; +int *rlm_liqcomp_aux2s; + +int rlm_liqcomp_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_liqcomp_RLMStart(void *ptr,const char *arg) +{ + char address[17]; + char section[256]; + char errtext[256]; + int i=1; + + rlm_liqcomp_devs=0; + rlm_liqcomp_addresses=NULL; + rlm_liqcomp_ports=NULL; + rlm_liqcomp_masters=NULL; + rlm_liqcomp_aux1s=NULL; + rlm_liqcomp_aux2s=NULL; + + sprintf(section,"System%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + if(strlen(address)==0) { + RLMLog(ptr,LOG_WARNING,"rlm_liqcomp: no encoder destinations specified"); + return; + } + while(strlen(address)>0) { + rlm_liqcomp_addresses= + realloc(rlm_liqcomp_addresses,(rlm_liqcomp_devs+1)*(rlm_liqcomp_devs+1)*16); + strcpy(rlm_liqcomp_addresses+16*rlm_liqcomp_devs,address); + rlm_liqcomp_ports=realloc(rlm_liqcomp_ports,(rlm_liqcomp_devs+1)*sizeof(uint16_t)); + rlm_liqcomp_ports[rlm_liqcomp_devs]= + RLMGetIntegerValue(ptr,arg,section,"UdpPort",0); + rlm_liqcomp_titles=realloc(rlm_liqcomp_titles,(rlm_liqcomp_devs+1)*256); + strncpy(rlm_liqcomp_titles+256*rlm_liqcomp_devs, + RLMGetStringValue(ptr,arg,section,"Title",""),256); + rlm_liqcomp_artists=realloc(rlm_liqcomp_artists,(rlm_liqcomp_devs+1)*256); + strncpy(rlm_liqcomp_artists+256*rlm_liqcomp_devs, + RLMGetStringValue(ptr,arg,section,"Artist",""),256); + rlm_liqcomp_albums=realloc(rlm_liqcomp_albums,(rlm_liqcomp_devs+1)*256); + strncpy(rlm_liqcomp_albums+256*rlm_liqcomp_devs, + RLMGetStringValue(ptr,arg,section,"Album",""),256); + rlm_liqcomp_labels=realloc(rlm_liqcomp_labels,(rlm_liqcomp_devs+1)*256); + strncpy(rlm_liqcomp_labels+256*rlm_liqcomp_devs, + RLMGetStringValue(ptr,arg,section,"Label",""),256); + rlm_liqcomp_masters=realloc(rlm_liqcomp_masters, + (rlm_liqcomp_devs+1)*sizeof(int)); + rlm_liqcomp_masters[rlm_liqcomp_devs]= + rlm_liqcomp_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_liqcomp_aux1s=realloc(rlm_liqcomp_aux1s, + (rlm_liqcomp_devs+1)*sizeof(int)); + rlm_liqcomp_aux1s[rlm_liqcomp_devs]= + rlm_liqcomp_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_liqcomp_aux2s=realloc(rlm_liqcomp_aux2s, + (rlm_liqcomp_devs+1)*sizeof(int)); + rlm_liqcomp_aux2s[rlm_liqcomp_devs]= + rlm_liqcomp_GetLogStatus(ptr,arg,section,"Aux2Log"); + sprintf(errtext,"rlm_liqcomp: configured destination \"%s:%d\"",address, + rlm_liqcomp_ports[rlm_liqcomp_devs]); + rlm_liqcomp_devs++; + RLMLog(ptr,LOG_INFO,errtext); + sprintf(section,"System%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + } +} + + +void rlm_liqcomp_RLMFree(void *ptr) +{ + free(rlm_liqcomp_addresses); + free(rlm_liqcomp_ports); + free(rlm_liqcomp_titles); + free(rlm_liqcomp_artists); + free(rlm_liqcomp_albums); + free(rlm_liqcomp_labels); + free(rlm_liqcomp_masters); + free(rlm_liqcomp_aux1s); + free(rlm_liqcomp_aux2s); +} + + +void rlm_liqcomp_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char fmt[1500]; + char msg[1500]; + + for(i=0;ilog_mach) { + case 0: + flag=rlm_liqcomp_masters[i]; + break; + + case 1: + flag=rlm_liqcomp_aux1s[i]; + break; + + case 2: + flag=rlm_liqcomp_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + snprintf(fmt,1500,"|%s|%s|%06u|%u|%s|%s|%s|\n", + rlm_liqcomp_titles+256*i, + rlm_liqcomp_artists+256*i, + now->rlm_cartnum, + now->rlm_len, + now->rlm_group, + rlm_liqcomp_albums+256*i, + rlm_liqcomp_labels+256*i); + const char *str=RLMResolveNowNext(ptr,now,next,fmt); + RLMSendUdp(ptr,rlm_liqcomp_addresses+i*16,rlm_liqcomp_ports[i],str, + strlen(str)); + snprintf(msg,1500,"rlm_liqcomp: sending pad update: \"%s\"", + (const char *)str); + RLMLog(ptr,LOG_INFO,msg); + } + } +} diff --git a/rlm/rlm_padpoint.c b/rlm/rlm_padpoint.c new file mode 100644 index 00000000..9617081e --- /dev/null +++ b/rlm/rlm_padpoint.c @@ -0,0 +1,175 @@ +/* rlm_padpoint.c + * + * (C) Copyright 2012 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It sends Now&Next PAD data via + * UDP packets to one or more PadPoint PAD processors as specified in the + * configuration file pointed to by the plugin argument. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_padpoint.rlm rlm_padpoint.c + */ + +#include +#include +#include +#include +#include + +int rlm_padpoint_devs; +char *rlm_padpoint_addresses; +uint16_t *rlm_padpoint_ports; +int *rlm_padpoint_masters; +int *rlm_padpoint_aux1s; +int *rlm_padpoint_aux2s; + +int rlm_padpoint_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_padpoint_RLMStart(void *ptr,const char *arg) +{ + char address[17]; + char section[256]; + char errtext[256]; + int i=1; + + rlm_padpoint_devs=0; + rlm_padpoint_addresses=NULL; + rlm_padpoint_ports=NULL; + rlm_padpoint_masters=NULL; + rlm_padpoint_aux1s=NULL; + rlm_padpoint_aux2s=NULL; + + sprintf(section,"PadPoint%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + if(strlen(address)==0) { + RLMLog(ptr,LOG_WARNING,"rlm_padpoint: no padpoint destinations specified"); + return; + } + while(strlen(address)>0) { + rlm_padpoint_addresses= + realloc(rlm_padpoint_addresses,(rlm_padpoint_devs+1)*(rlm_padpoint_devs+1)*16); + strcpy(rlm_padpoint_addresses+16*rlm_padpoint_devs,address); + rlm_padpoint_ports=realloc(rlm_padpoint_ports,(rlm_padpoint_devs+1)*sizeof(uint16_t)); + rlm_padpoint_ports[rlm_padpoint_devs]= + RLMGetIntegerValue(ptr,arg,section,"UdpPort",0); + rlm_padpoint_masters=realloc(rlm_padpoint_masters, + (rlm_padpoint_devs+1)*sizeof(int)); + rlm_padpoint_masters[rlm_padpoint_devs]= + rlm_padpoint_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_padpoint_aux1s=realloc(rlm_padpoint_aux1s, + (rlm_padpoint_devs+1)*sizeof(int)); + rlm_padpoint_aux1s[rlm_padpoint_devs]= + rlm_padpoint_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_padpoint_aux2s=realloc(rlm_padpoint_aux2s, + (rlm_padpoint_devs+1)*sizeof(int)); + rlm_padpoint_aux2s[rlm_padpoint_devs]= + rlm_padpoint_GetLogStatus(ptr,arg,section,"Aux2Log"); + sprintf(errtext,"rlm_padpoint: configured destination \"%s:%d\"",address, + rlm_padpoint_ports[rlm_padpoint_devs]); + rlm_padpoint_devs++; + RLMLog(ptr,LOG_INFO,errtext); + sprintf(section,"PadPoint%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + } +} + + +void rlm_padpoint_RLMFree(void *ptr) +{ + free(rlm_padpoint_addresses); + free(rlm_padpoint_ports); + free(rlm_padpoint_masters); + free(rlm_padpoint_aux1s); + free(rlm_padpoint_aux2s); +} + + +void rlm_padpoint_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char str[1501]; + char msg[2048]; + + for(i=0;ilog_mach) { + case 0: + flag=rlm_padpoint_masters[i]; + break; + + case 1: + flag=rlm_padpoint_aux1s[i]; + break; + + case 2: + flag=rlm_padpoint_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + snprintf(str,1501,"%06u~%u~%s~%s~%s~%s~%s~%s~%s~%s~%s~%s~%s~%s~%s", + now->rlm_cartnum, + now->rlm_len, + now->rlm_year, + now->rlm_group, + now->rlm_title, + now->rlm_artist, + now->rlm_album, + now->rlm_label, + now->rlm_client, + now->rlm_agency, + now->rlm_comp, + now->rlm_pub, + now->rlm_userdef, + now->rlm_isrc, + now->rlm_isci); + RLMSendUdp(ptr,rlm_padpoint_addresses+i*16,rlm_padpoint_ports[i], + str,strlen(str)); + snprintf(msg,1500,"rlm_padpoint: sending pad update: \"%s\"",str); + RLMLog(ptr,LOG_INFO,msg); + } + } +} diff --git a/rlm/rlm_serial.c b/rlm/rlm_serial.c new file mode 100644 index 00000000..42188b9d --- /dev/null +++ b/rlm/rlm_serial.c @@ -0,0 +1,219 @@ +/* rlm_serial.c + * + * (C) Copyright 2008 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It sends Now&Next PAD data + * to the tty device specified in the configuration file pointed to by the + * plugin argument. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_serial.rlm rlm_serial.c + */ + +#include +#include +#include +#include +#include + +int rlm_serial_devs; +int *rlm_serial_handles; +char *rlm_serial_formats; +int *rlm_serial_encodings; +int *rlm_serial_null_updates; +int *rlm_serial_masters; +int *rlm_serial_aux1s; +int *rlm_serial_aux2s; + +int rlm_serial_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_serial_RLMStart(void *ptr,const char *arg) +{ + int handle; + char device[256]; + int speed; + int parity; + int wsize; + char section[256]; + char errtext[256]; + int i=1; + + rlm_serial_devs=0; + rlm_serial_handles=NULL; + rlm_serial_formats=NULL; + rlm_serial_encodings=NULL; + rlm_serial_null_updates=NULL; + rlm_serial_masters=NULL; + rlm_serial_aux1s=NULL; + rlm_serial_aux2s=NULL; + + sprintf(section,"Serial%d",i++); + strncpy(device,RLMGetStringValue(ptr,arg,section,"Device",""),256); + if(strlen(device)==0) { + RLMLog(ptr,LOG_WARNING,"rlm_serial: no serial devices specified"); + return; + } + while(strlen(device)>0) { + speed=RLMGetIntegerValue(ptr,arg,section,"Speed",9600); + parity=RLMGetIntegerValue(ptr,arg,section,"Parity",0); + wsize=RLMGetIntegerValue(ptr,arg,section,"WordSize",8); + if((handle=RLMOpenSerial(ptr,device,speed,parity,wsize))>=0) { + rlm_serial_handles=realloc(rlm_serial_handles, + (rlm_serial_devs+1)*sizeof(int)); + rlm_serial_handles[rlm_serial_devs]=handle; + rlm_serial_formats=realloc(rlm_serial_formats,(rlm_serial_devs+1)*256); + strncpy(rlm_serial_formats+256*rlm_serial_devs, + RLMGetStringValue(ptr,arg,section,"FormatString",""),256); + rlm_serial_masters=realloc(rlm_serial_masters, + (rlm_serial_devs+1)*sizeof(int)); + rlm_serial_masters[rlm_serial_devs]= + rlm_serial_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_serial_encodings=realloc(rlm_serial_encodings, + (rlm_serial_devs+1)*sizeof(int)); + rlm_serial_encodings[rlm_serial_devs]= + RLMGetIntegerValue(ptr,arg,section,"Encoding",RLM_ENCODE_NONE); + + rlm_serial_null_updates=realloc(rlm_serial_null_updates, + (rlm_serial_devs+1)*sizeof(int)); + rlm_serial_null_updates[rlm_serial_devs]= + RLMGetIntegerValue(ptr,arg,section,"ProcessNullUpdates",0); + + + + rlm_serial_aux1s=realloc(rlm_serial_aux1s, + (rlm_serial_devs+1)*sizeof(int)); + rlm_serial_aux1s[rlm_serial_devs]= + rlm_serial_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_serial_aux2s=realloc(rlm_serial_aux2s, + (rlm_serial_devs+1)*sizeof(int)); + rlm_serial_aux2s[rlm_serial_devs]= + rlm_serial_GetLogStatus(ptr,arg,section,"Aux2Log"); + rlm_serial_devs++; + sprintf(errtext,"rlm_serial: opened device \"%s\"",device); + RLMLog(ptr,LOG_INFO,errtext); + } + else { + sprintf(errtext,"unable to open tty \"%s\"",device); + RLMLog(ptr,LOG_WARNING,errtext); + } + sprintf(section,"Serial%d",i++); + strncpy(device,RLMGetStringValue(ptr,arg,section,"Device",""),256); + } +} + + +void rlm_serial_RLMFree(void *ptr) +{ + int i; + + for(i=0;irlm_cartnum==0) { + return; + } + break; + + case 2: /* Process only non-null NEXT updates */ + if(next->rlm_cartnum==0) { + return; + } + break; + + case 3: /* Process only non-null NOW and NEXT updates */ + if((now->rlm_cartnum==0)||(next->rlm_cartnum==0)) { + return; + } + break; + } + + switch(log->log_mach) { + case 0: + flag=rlm_serial_masters[i]; + break; + + case 1: + flag=rlm_serial_aux1s[i]; + break; + + case 2: + flag=rlm_serial_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + const char *str= + RLMResolveNowNextEncoded(ptr,now,next,rlm_serial_formats+256*i, + rlm_serial_encodings[i]); + RLMSendSerial(ptr,rlm_serial_handles[i],str,strlen(str)); + snprintf(msg,1500,"rlm_serial: sending pad update: \"%s\"", + (const char *)str); + RLMLog(ptr,LOG_INFO,msg); + } + } +} diff --git a/rlm/rlm_shoutcast1.c b/rlm/rlm_shoutcast1.c new file mode 100644 index 00000000..2abdf846 --- /dev/null +++ b/rlm/rlm_shoutcast1.c @@ -0,0 +1,280 @@ +/* rlm_shoutcast1.c + * + * (C) Copyright 2011 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It uses Now&Next PAD data + * to update the metadata on an Icecast2 mountpoint specified in the + * configuration file pointed to by the plugin argument. + * + * This module requires the curl(1) network transfer tool, included with + * most Linux distros. It is also available at http://curl.haxx.se/. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_shoutcast1.rlm rlm_shoutcast1.c + */ + +#include +#include +#include +#include +#include +#include + +#include + +int rlm_shoutcast1_devs; +char *rlm_shoutcast1_passwords; +char *rlm_shoutcast1_hostnames; +int *rlm_shoutcast1_tcpports; +char *rlm_shoutcast1_formats; +int *rlm_shoutcast1_masters; +int *rlm_shoutcast1_aux1s; +int *rlm_shoutcast1_aux2s; + + +int rlm_shoutcast1_BufferDiff(char *sString,int dOrigin,int dDiff,int dMaxSize) +{ + int dOldSize,dNewSize; + int i; + + /* + * Will it fit? + */ + dOldSize=strlen(sString); + if((dOldSize+dDiff)>=dMaxSize) { + return -1; + } + dNewSize=dOldSize+dDiff; + + /* + * Adding characters + */ + if(dDiff>0) { + for(i=dOldSize;i>dOrigin;i--) { + sString[i+dDiff]=sString[i]; + } + return dNewSize; + } + + /* + * No Change + */ + if(dDiff==0) { + return dNewSize; + } + + /* + * Deleting Characters + */ + if(dDiff<0) { + for(i=dOrigin;i'9') && (sString[i]<'A')) || + ((sString[i]>'Z') && (sString[i]<'a')) || + (sString[i]>'z'))) { + if(rlm_shoutcast1_BufferDiff(sString,i,2,dMaxSize)<0) { + return -1; + } + sprintf(sAccum,"%%%2x",sString[i]); + sString[i++]=sAccum[0]; + sString[i++]=sAccum[1]; + sString[i]=sAccum[2]; + } + if(sString[i]==' ') { + sString[i]='+'; + } + i++; + if(i>=dMaxSize) { + return -1; + } + } + return strlen(sString); +} + + +int rlm_shoutcast1_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_shoutcast1_RLMStart(void *ptr,const char *arg) +{ + char password[256]; + char section[256]; + char errtext[256]; + int i=1; + + rlm_shoutcast1_devs=0; + rlm_shoutcast1_passwords=NULL; + rlm_shoutcast1_formats=NULL; + rlm_shoutcast1_masters=NULL; + rlm_shoutcast1_aux1s=NULL; + rlm_shoutcast1_aux2s=NULL; + + sprintf(section,"Shoutcast%d",i++); + strncpy(password,RLMGetStringValue(ptr,arg,section,"Password",""),255); + password[255]=0; + if(strlen(password)==0) { + RLMLog(ptr,LOG_WARNING,"rlm_shoutcast1: no shoutcast servers specified"); + return; + } + while(strlen(password)>0) { + rlm_shoutcast1_passwords=realloc(rlm_shoutcast1_passwords, + (rlm_shoutcast1_devs+1)*(rlm_shoutcast1_devs+1)*256); + strcpy(rlm_shoutcast1_passwords+256*rlm_shoutcast1_devs,password); + rlm_shoutcast1_hostnames=realloc(rlm_shoutcast1_hostnames, + (rlm_shoutcast1_devs+1)*(rlm_shoutcast1_devs+1)*256); + strcpy(rlm_shoutcast1_hostnames+256*rlm_shoutcast1_devs, + RLMGetStringValue(ptr,arg,section,"Hostname","")); + rlm_shoutcast1_tcpports=realloc(rlm_shoutcast1_tcpports, + (rlm_shoutcast1_devs+1)*sizeof(int)); + rlm_shoutcast1_tcpports[rlm_shoutcast1_devs]= + RLMGetIntegerValue(ptr,arg,section,"Tcpport",0); + rlm_shoutcast1_formats=realloc(rlm_shoutcast1_formats,(rlm_shoutcast1_devs+1)*256); + strncpy(rlm_shoutcast1_formats+256*rlm_shoutcast1_devs, + RLMGetStringValue(ptr,arg,section,"FormatString",""),256); + rlm_shoutcast1_masters=realloc(rlm_shoutcast1_masters, + (rlm_shoutcast1_devs+1)*sizeof(int)); + rlm_shoutcast1_masters[rlm_shoutcast1_devs]= + rlm_shoutcast1_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_shoutcast1_aux1s=realloc(rlm_shoutcast1_aux1s, + (rlm_shoutcast1_devs+1)*sizeof(int)); + rlm_shoutcast1_aux1s[rlm_shoutcast1_devs]= + rlm_shoutcast1_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_shoutcast1_aux2s=realloc(rlm_shoutcast1_aux2s, + (rlm_shoutcast1_devs+1)*sizeof(int)); + rlm_shoutcast1_aux2s[rlm_shoutcast1_devs]= + rlm_shoutcast1_GetLogStatus(ptr,arg,section,"Aux2Log"); + sprintf(errtext,"rlm_shoutcast1: configured server \"%s:%d\"",rlm_shoutcast1_hostnames+256*rlm_shoutcast1_devs,rlm_shoutcast1_tcpports[rlm_shoutcast1_devs]); + rlm_shoutcast1_devs++; + RLMLog(ptr,LOG_INFO,errtext); + sprintf(section,"Shoutcast%d",i++); + strncpy(password,RLMGetStringValue(ptr,arg,section,"Password",""),255); + password[255]=0; + } +} + + +void rlm_shoutcast1_RLMFree(void *ptr) +{ + free(rlm_shoutcast1_passwords); + free(rlm_shoutcast1_hostnames); + free(rlm_shoutcast1_tcpports); + free(rlm_shoutcast1_formats); + free(rlm_shoutcast1_masters); + free(rlm_shoutcast1_aux1s); + free(rlm_shoutcast1_aux2s); +} + + +void rlm_shoutcast1_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char str[1024]; + char account[1024]; + char url[1024]; + char msg[1500]; + char user_agent[255]; + + for(i=0;ilog_mach) { + case 0: + flag=rlm_shoutcast1_masters[i]; + break; + + case 1: + flag=rlm_shoutcast1_aux1s[i]; + break; + + case 2: + flag=rlm_shoutcast1_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + strncpy(str,RLMResolveNowNext(ptr,now,next, + rlm_shoutcast1_formats+256*i),256); + rlm_shoutcast1_EncodeString(str,1023); + snprintf(account,1024,":%s",rlm_shoutcast1_passwords+256*i); + snprintf(url,1024,"http://%s:%d/admin.cgi?pass=%s&mode=updinfo&song=%s", + rlm_shoutcast1_hostnames+256*i, + rlm_shoutcast1_tcpports[i], + rlm_shoutcast1_passwords+256*i, + str); + /* + * D.N.A.S v1.9.8 refuses to process updates with the default CURL + * user-agent value, hence we lie to it. + */ + strncpy(user_agent,"User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070219 Firefox/2.0.0.2",255); + if(strlen(now->rlm_title)!=0) { + if(fork()==0) { + execlp("curl","curl","-o","/dev/null","-s","--header",user_agent, + url,(char *)NULL); + RLMLog(ptr,LOG_WARNING,"rlm_shoutcast1: unable to execute curl(1)"); + exit(0); + } + } + snprintf(msg,1500,"rlm_shoutcast1: sending pad update: \"%s\"", + (const char *)str); + RLMLog(ptr,LOG_INFO,msg); + } + } +} diff --git a/rlm/rlm_spinitron_plus.c b/rlm/rlm_spinitron_plus.c new file mode 100644 index 00000000..40f5cd36 --- /dev/null +++ b/rlm/rlm_spinitron_plus.c @@ -0,0 +1,386 @@ +/* rlm_spinitron_plus.c + * + * (C) Copyright 2013 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It sends Now&Next PAD data + * to the Spinitron account(s) specified in the configuration file pointed + * to by the plugin argument. For information about Spinitron, see + * http://www.spinitron.com/. + * + * Inspired by the original spinitron RLM by Eric Berg, Benjamin Yu + * and Max Goldstein. + * + * This module requires the curl(1) network transfer tool, included with + * most Linux distros. It is also available at http://curl.haxx.se/. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_spinitron_plus.rlm rlm_spinitron_plus.c + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define RLM_SPINITRON_PLUS_LOGGER_NAME "Rivendell" + +int rlm_spinitron_plus_devs; +char *rlm_spinitron_plus_stations; +char *rlm_spinitron_plus_usernames; +char *rlm_spinitron_plus_passwords; +int *rlm_spinitron_plus_playlist_modes; +char *rlm_spinitron_plus_titles; +char *rlm_spinitron_plus_artists; +char *rlm_spinitron_plus_albums; +char *rlm_spinitron_plus_labels; +char *rlm_spinitron_plus_composers; +char *rlm_spinitron_plus_notes; +int *rlm_spinitron_plus_masters; +int *rlm_spinitron_plus_aux1s; +int *rlm_spinitron_plus_aux2s; + + +int rlm_spinitron_plus_BufferDiff(char *sString,int dOrigin,int dDiff,int dMaxSize) +{ + int dOldSize,dNewSize; + int i; + + /* + * Will it fit? + */ + dOldSize=strlen(sString); + if((dOldSize+dDiff)>=dMaxSize) { + return -1; + } + dNewSize=dOldSize+dDiff; + + /* + * Adding characters + */ + if(dDiff>0) { + for(i=dOldSize;i>dOrigin;i--) { + sString[i+dDiff]=sString[i]; + } + return dNewSize; + } + + /* + * No Change + */ + if(dDiff==0) { + return dNewSize; + } + + /* + * Deleting Characters + */ + if(dDiff<0) { + for(i=dOrigin;i'9') && (sString[i]<'A')) || + ((sString[i]>'Z') && (sString[i]<'a')) || + (sString[i]>'z'))) { + if(rlm_spinitron_plus_BufferDiff(sString,i,2,dMaxSize)<0) { + return -1; + } + sprintf(sAccum,"%%%2x",sString[i]); + sString[i++]=sAccum[0]; + sString[i++]=sAccum[1]; + sString[i]=sAccum[2]; + } + if(sString[i]==' ') { + sString[i]='+'; + } + i++; + } + return strlen(sString); +} + + +int rlm_spinitron_plus_GetLogStatus(void *ptr,const char *arg, + const char *section,const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_spinitron_plus_RLMStart(void *ptr,const char *arg) +{ + char station[256]; + char section[256]; + char errtext[256]; + char mode[256]; + int pmode; + int i=1; + + rlm_spinitron_plus_devs=0; + rlm_spinitron_plus_stations=NULL; + rlm_spinitron_plus_usernames=NULL; + rlm_spinitron_plus_passwords=NULL; + rlm_spinitron_plus_playlist_modes=NULL; + rlm_spinitron_plus_titles=NULL; + rlm_spinitron_plus_artists=NULL; + rlm_spinitron_plus_albums=NULL; + rlm_spinitron_plus_labels=NULL; + rlm_spinitron_plus_composers=NULL; + rlm_spinitron_plus_notes=NULL; + rlm_spinitron_plus_masters=NULL; + rlm_spinitron_plus_aux1s=NULL; + rlm_spinitron_plus_aux2s=NULL; + + sprintf(section,"Spinitron%d",i++); + strncpy(station,RLMGetStringValue(ptr,arg,section,"Station",""),255); + station[255]=0; + if(strlen(station)==0) { + RLMLog(ptr,LOG_WARNING,"rlm_spinitron_plus: no spinitron accounts specified"); + return; + } + while(strlen(station)>0) { + rlm_spinitron_plus_stations=realloc(rlm_spinitron_plus_stations, + (rlm_spinitron_plus_devs+1)*(rlm_spinitron_plus_devs+1)*256); + strcpy(rlm_spinitron_plus_stations+256*rlm_spinitron_plus_devs,station); + rlm_spinitron_plus_EncodeString(rlm_spinitron_plus_stations+256*rlm_spinitron_plus_devs,255); + + rlm_spinitron_plus_usernames=realloc(rlm_spinitron_plus_usernames, + (rlm_spinitron_plus_devs+1)*(rlm_spinitron_plus_devs+1)*256); + strcpy(rlm_spinitron_plus_usernames+256*rlm_spinitron_plus_devs, + RLMGetStringValue(ptr,arg,section,"Username","")); + rlm_spinitron_plus_EncodeString(rlm_spinitron_plus_usernames+256*rlm_spinitron_plus_devs,255); + + rlm_spinitron_plus_passwords=realloc(rlm_spinitron_plus_passwords, + (rlm_spinitron_plus_devs+1)*(rlm_spinitron_plus_devs+1)*256); + strcpy(rlm_spinitron_plus_passwords+256*rlm_spinitron_plus_devs, + RLMGetStringValue(ptr,arg,section,"Password","")); + rlm_spinitron_plus_EncodeString(rlm_spinitron_plus_passwords+256*rlm_spinitron_plus_devs,255); + + pmode=3; + strcpy(mode,RLMGetStringValue(ptr,arg,section,"PlaylistMode","")); + if(strcasecmp(mode,"full")==0) { + pmode=0; + } + if(strcasecmp(mode,"assist")==0) { + pmode=2; + } + rlm_spinitron_plus_playlist_modes= + realloc(rlm_spinitron_plus_playlist_modes, + (rlm_spinitron_plus_devs+1)*sizeof(int)); + rlm_spinitron_plus_playlist_modes[rlm_spinitron_plus_devs]=pmode; + + rlm_spinitron_plus_titles=realloc(rlm_spinitron_plus_titles,(rlm_spinitron_plus_devs+1)*256); + strncpy(rlm_spinitron_plus_titles+256*rlm_spinitron_plus_devs, + RLMGetStringValue(ptr,arg,section,"Title",""),256); + + rlm_spinitron_plus_artists=realloc(rlm_spinitron_plus_artists,(rlm_spinitron_plus_devs+1)*256); + strncpy(rlm_spinitron_plus_artists+256*rlm_spinitron_plus_devs, + RLMGetStringValue(ptr,arg,section,"Artist",""),256); + + rlm_spinitron_plus_albums=realloc(rlm_spinitron_plus_albums,(rlm_spinitron_plus_devs+1)*256); + strncpy(rlm_spinitron_plus_albums+256*rlm_spinitron_plus_devs, + RLMGetStringValue(ptr,arg,section,"Album",""),256); + + rlm_spinitron_plus_labels=realloc(rlm_spinitron_plus_labels,(rlm_spinitron_plus_devs+1)*256); + strncpy(rlm_spinitron_plus_labels+256*rlm_spinitron_plus_devs, + RLMGetStringValue(ptr,arg,section,"Label",""),256); + + rlm_spinitron_plus_composers=realloc(rlm_spinitron_plus_composers,(rlm_spinitron_plus_devs+1)*256); + strncpy(rlm_spinitron_plus_composers+256*rlm_spinitron_plus_devs, + RLMGetStringValue(ptr,arg,section,"Composer",""),256); + + rlm_spinitron_plus_notes=realloc(rlm_spinitron_plus_notes,(rlm_spinitron_plus_devs+1)*256); + strncpy(rlm_spinitron_plus_notes+256*rlm_spinitron_plus_devs, + RLMGetStringValue(ptr,arg,section,"Notes",""),256); + + + rlm_spinitron_plus_masters=realloc(rlm_spinitron_plus_masters, + (rlm_spinitron_plus_devs+1)*sizeof(int)); + rlm_spinitron_plus_masters[rlm_spinitron_plus_devs]= + rlm_spinitron_plus_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_spinitron_plus_aux1s=realloc(rlm_spinitron_plus_aux1s, + (rlm_spinitron_plus_devs+1)*sizeof(int)); + rlm_spinitron_plus_aux1s[rlm_spinitron_plus_devs]= + rlm_spinitron_plus_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_spinitron_plus_aux2s=realloc(rlm_spinitron_plus_aux2s, + (rlm_spinitron_plus_devs+1)*sizeof(int)); + rlm_spinitron_plus_aux2s[rlm_spinitron_plus_devs]= + rlm_spinitron_plus_GetLogStatus(ptr,arg,section,"Aux2Log"); + sprintf(errtext,"rlm_spinitron_plus: configured account for station \"%s\"", + station); + + rlm_spinitron_plus_devs++; + RLMLog(ptr,LOG_INFO,errtext); + sprintf(section,"Spinitron%d",i++); + strncpy(station,RLMGetStringValue(ptr,arg,section,"Station",""),255); + station[255]=0; + } +} + + +void rlm_spinitron_plus_RLMFree(void *ptr) +{ + free(rlm_spinitron_plus_stations); + free(rlm_spinitron_plus_usernames); + free(rlm_spinitron_plus_passwords); + free(rlm_spinitron_plus_playlist_modes); + free(rlm_spinitron_plus_titles); + free(rlm_spinitron_plus_artists); + free(rlm_spinitron_plus_albums); + free(rlm_spinitron_plus_labels); + free(rlm_spinitron_plus_composers); + free(rlm_spinitron_plus_notes); + free(rlm_spinitron_plus_masters); + free(rlm_spinitron_plus_aux1s); + free(rlm_spinitron_plus_aux2s); +} + + +void rlm_spinitron_plus_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char title[1024]; + char artist[1024]; + char album[1024]; + char label[1024]; + char composer[1024]; + char notes[1024]; + char msg[8192]; + char sysmsg[8192]; + int pm; + + for(i=0;ilog_mach) { + case 0: + flag=rlm_spinitron_plus_masters[i]; + break; + + case 1: + flag=rlm_spinitron_plus_aux1s[i]; + break; + + case 2: + flag=rlm_spinitron_plus_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + strncpy(title,RLMResolveNowNext(ptr,now,next, + rlm_spinitron_plus_titles+256*i),256); + rlm_spinitron_plus_EncodeString(title,1023); + strncpy(artist,RLMResolveNowNext(ptr,now,next, + rlm_spinitron_plus_artists+256*i),256); + rlm_spinitron_plus_EncodeString(artist,1023); + strncpy(album,RLMResolveNowNext(ptr,now,next, + rlm_spinitron_plus_albums+256*i),256); + rlm_spinitron_plus_EncodeString(album,1023); + strncpy(label,RLMResolveNowNext(ptr,now,next, + rlm_spinitron_plus_labels+256*i),256); + rlm_spinitron_plus_EncodeString(label,1023); + strncpy(composer,RLMResolveNowNext(ptr,now,next, + rlm_spinitron_plus_composers+256*i),256); + rlm_spinitron_plus_EncodeString(composer,1023); + strncpy(notes,RLMResolveNowNext(ptr,now,next, + rlm_spinitron_plus_notes+256*i),256); + rlm_spinitron_plus_EncodeString(notes,1023); + if(rlm_spinitron_plus_playlist_modes[i]==3) { + switch(log->log_mode) { + case RLM_LOGMODE_AUTOMATIC: + pm=0; + break; + + case RLM_LOGMODE_LIVEASSIST: + case RLM_LOGMODE_MANUAL: + default: + pm=2; + break; + } + } + else { + pm=rlm_spinitron_plus_playlist_modes[i]; + } + + if(strlen(now->rlm_title)!=0) { + snprintf(msg,8192, + "https://spinitron.com/member/logthis.php?un=%s&pw=%s&sn=%s&aw=%s&dn=%s&ln=%s&sc=%s&se=%s&df=%s&st=%s&sd=%d&pm=%d", + rlm_spinitron_plus_usernames+256*i, + rlm_spinitron_plus_passwords+256*i, + title, + artist, + album, + label, + composer, + notes, + RLM_SPINITRON_PLUS_LOGGER_NAME, + rlm_spinitron_plus_stations+256*i, + now->rlm_len/1000, + pm); + if(fork()==0) { + execlp("curl","curl",msg,(char *)NULL); + RLMLog(ptr,LOG_WARNING,"rlm_spinitron_plus: unable to execute curl(1)"); + exit(0); + } + snprintf(sysmsg,8192,"rlm_spinitron_plus: sending pad update: \"%s\"", + (const char *)msg); + RLMLog(ptr,LOG_DEBUG,sysmsg); + } + } + } +} diff --git a/rlm/rlm_spottrap.c b/rlm/rlm_spottrap.c new file mode 100644 index 00000000..48d4415e --- /dev/null +++ b/rlm/rlm_spottrap.c @@ -0,0 +1,205 @@ +/* rlm_spottrap.c + * + * (C) Copyright 2012 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It processes Now&Next PAD data + * on the basis of Group and Length as specified in the configuration file + * pointed to by the plugin argument. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_spottrap.rlm rlm_spottrap.c + */ + +#include +#include +#include +#include +#include + +int rlm_spottrap_devs; +char *rlm_spottrap_groups; +char *rlm_spottrap_addresses; +int *rlm_spottrap_minimums; +int *rlm_spottrap_maximums; +uint16_t *rlm_spottrap_ports; +char *rlm_spottrap_formats; +char *rlm_spottrap_default_formats; +int *rlm_spottrap_masters; +int *rlm_spottrap_aux1s; +int *rlm_spottrap_aux2s; + +int rlm_spottrap_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_spottrap_RLMStart(void *ptr,const char *arg) +{ + char address[17]; + char section[256]; + char errtext[256]; + int i=1; + + rlm_spottrap_devs=0; + rlm_spottrap_groups=NULL; + rlm_spottrap_addresses=NULL; + rlm_spottrap_minimums=NULL; + rlm_spottrap_maximums=NULL; + rlm_spottrap_ports=NULL; + rlm_spottrap_formats=NULL; + rlm_spottrap_default_formats=NULL; + rlm_spottrap_masters=NULL; + rlm_spottrap_aux1s=NULL; + rlm_spottrap_aux2s=NULL; + + sprintf(section,"Rule%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + if(strlen(address)==0) { + RLMLog(ptr,LOG_WARNING,"rlm_spottrap: no rules specified"); + return; + } + while(strlen(address)>0) { + rlm_spottrap_addresses= + realloc(rlm_spottrap_addresses,(rlm_spottrap_devs+1)*(rlm_spottrap_devs+1)*16); + strcpy(rlm_spottrap_addresses+16*rlm_spottrap_devs,address); + rlm_spottrap_groups=realloc(rlm_spottrap_groups,(rlm_spottrap_devs+1)*16); + strncpy(rlm_spottrap_groups+16*rlm_spottrap_devs, + RLMGetStringValue(ptr,arg,section,"GroupName",""),10); + rlm_spottrap_minimums=realloc(rlm_spottrap_minimums,(rlm_spottrap_devs+1)*sizeof(int)); + rlm_spottrap_minimums[rlm_spottrap_devs]= + RLMGetIntegerValue(ptr,arg,section,"MinimumLength",0); + rlm_spottrap_maximums=realloc(rlm_spottrap_maximums,(rlm_spottrap_devs+1)*sizeof(int)); + rlm_spottrap_maximums[rlm_spottrap_devs]= + RLMGetIntegerValue(ptr,arg,section,"MaximumLength",0); + rlm_spottrap_ports=realloc(rlm_spottrap_ports,(rlm_spottrap_devs+1)*sizeof(uint16_t)); + rlm_spottrap_ports[rlm_spottrap_devs]= + RLMGetIntegerValue(ptr,arg,section,"UdpPort",0); + rlm_spottrap_formats=realloc(rlm_spottrap_formats,(rlm_spottrap_devs+1)*256); + strncpy(rlm_spottrap_formats+256*rlm_spottrap_devs, + RLMGetStringValue(ptr,arg,section,"FormatString",""),256); + rlm_spottrap_default_formats=realloc(rlm_spottrap_default_formats, + (rlm_spottrap_devs+1)*256); + strncpy(rlm_spottrap_default_formats+256*rlm_spottrap_devs, + RLMGetStringValue(ptr,arg,section,"DefaultFormatString",""),256); + rlm_spottrap_masters=realloc(rlm_spottrap_masters, + (rlm_spottrap_devs+1)*sizeof(int)); + rlm_spottrap_masters[rlm_spottrap_devs]= + rlm_spottrap_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_spottrap_aux1s=realloc(rlm_spottrap_aux1s, + (rlm_spottrap_devs+1)*sizeof(int)); + rlm_spottrap_aux1s[rlm_spottrap_devs]= + rlm_spottrap_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_spottrap_aux2s=realloc(rlm_spottrap_aux2s, + (rlm_spottrap_devs+1)*sizeof(int)); + rlm_spottrap_aux2s[rlm_spottrap_devs]= + rlm_spottrap_GetLogStatus(ptr,arg,section,"Aux2Log"); + sprintf(errtext,"rlm_spottrap: configured rule for \"%s:%d\"",address, + rlm_spottrap_ports[rlm_spottrap_devs]); + rlm_spottrap_devs++; + RLMLog(ptr,LOG_INFO,errtext); + sprintf(section,"Rule%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + } +} + + +void rlm_spottrap_RLMFree(void *ptr) +{ + free(rlm_spottrap_addresses); + free(rlm_spottrap_groups); + free(rlm_spottrap_minimums); + free(rlm_spottrap_maximums); + free(rlm_spottrap_ports); + free(rlm_spottrap_formats); + free(rlm_spottrap_default_formats); + free(rlm_spottrap_masters); + free(rlm_spottrap_aux1s); + free(rlm_spottrap_aux2s); +} + + +void rlm_spottrap_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char msg[1500]; + + for(i=0;ilog_mach) { + case 0: + flag=rlm_spottrap_masters[i]; + break; + + case 1: + flag=rlm_spottrap_aux1s[i]; + break; + + case 2: + flag=rlm_spottrap_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + if((strcasecmp(now->rlm_group,rlm_spottrap_groups+16*i)==0)&& + (now->rlm_len>=rlm_spottrap_minimums[i])&& + (now->rlm_len<=rlm_spottrap_maximums[i])) { + const char *str= + RLMResolveNowNext(ptr,now,next,rlm_spottrap_formats+256*i); + RLMSendUdp(ptr,rlm_spottrap_addresses+i*16,rlm_spottrap_ports[i], + str,strlen(str)); + snprintf(msg,1500,"rlm_spottrap: sending pad update: \"%s\"", + (const char *)str); + RLMLog(ptr,LOG_INFO,msg); + } + else { + const char *str= + RLMResolveNowNext(ptr,now,next,rlm_spottrap_default_formats+256*i); + RLMSendUdp(ptr,rlm_spottrap_addresses+i*16,rlm_spottrap_ports[i], + str,strlen(str)); + snprintf(msg,1500,"rlm_spottrap: sending default pad update: \"%s\"", + (const char *)str); + RLMLog(ptr,LOG_INFO,msg); + } + } + } +} diff --git a/rlm/rlm_test.c b/rlm/rlm_test.c new file mode 100644 index 00000000..f2ced0e1 --- /dev/null +++ b/rlm/rlm_test.c @@ -0,0 +1,153 @@ +/* rlm_test.c + * + * (C) Copyright 2008 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a sample Rivendell Loadable Module. All it does is print + * Now & Next data to standard output for each event transition. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_test.rlm rlm_test.c + */ + +#include +#include +#include + + +void rlm_test_RLMStart(void *ptr,const char *arg) +{ + char str[1024]; + sprintf(str,"rlm_test: started on %s", + RLMDateTime(ptr,0,"MM/dd/yyyy at hh:mm:ss")); + RLMLog(ptr,LOG_NOTICE,str); +} + + +void rlm_test_RLMFree(void *ptr) +{ +} + + +void rlm_test_print_carttype(int type) +{ + switch(type) { + case RLM_CARTTYPE_ALL: + printf(" Type:\n"); + break; + + case RLM_CARTTYPE_AUDIO: + printf(" Type: AUDIO\n"); + break; + + case RLM_CARTTYPE_MACRO: + printf(" Type: MACRO\n"); + break; + } +} + +void rlm_test_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + printf("Service: %s\n",svc->svc_name); + printf("Program Code: %s\n",svc->svc_pgmcode); + printf("Log Name: %s\n",log->log_name); + if(log->log_onair==0) { + printf(" OnAir = false\n"); + } + else { + printf(" OnAir = true\n"); + } + switch(log->log_mode) { + case RLM_LOGMODE_LIVEASSIST: + printf(" Mode = Live Assist\n"); + break; + + case RLM_LOGMODE_AUTOMATIC: + printf(" Mode = Automatic\n"); + break; + + case RLM_LOGMODE_MANUAL: + printf(" Mode = Manual\n"); + break; + } + switch(log->log_mach) { + case 0: + printf(" -- On Main Log ---------------------------------------------\n"); + break; + + case 1: + printf(" -- On Aux 1 Log --------------------------------------------\n"); + break; + + case 2: + printf(" -- On Aux 2 Log --------------------------------------------\n"); + break; + } + printf("Playing NOW\n"); + printf(" Cart number: %06u\n",now->rlm_cartnum); + rlm_test_print_carttype(now->rlm_carttype); + printf("Start Date/Time: %04u-%02u-%02u %02u:%02u:%02u.%03u\n", + now->rlm_start_year,now->rlm_start_mon,now->rlm_start_day, + now->rlm_start_hour,now->rlm_start_min,now->rlm_start_sec, + now->rlm_start_msec); + printf(" Length: %u mS\n",now->rlm_len); + printf(" Title: %s\n",now->rlm_title); + printf(" Artist: %s\n",now->rlm_artist); + printf(" Label: %s\n",now->rlm_label); + printf(" Conductor: %s\n",now->rlm_conductor); + printf(" SongId: %s\n",now->rlm_song_id); + printf(" Client: %s\n",now->rlm_client); + printf(" Agency: %s\n",now->rlm_agency); + printf(" Composer: %s\n",now->rlm_comp); + printf(" Publisher: %s\n",now->rlm_pub); + printf(" UserDefined: %s\n",now->rlm_userdef); + printf(" Outcue: %s\n",now->rlm_outcue); + printf("Cut Description: %s\n",now->rlm_description); + printf(" ISRC: %s\n",now->rlm_isrc); + printf(" ISCI Code: %s\n",now->rlm_isci); + printf(" Ext Data: %s\n",now->rlm_ext_data); + printf(" Ext Event ID: %s\n",now->rlm_ext_eventid); + printf(" Ext Annc Type: %s\n",now->rlm_ext_annctype); + printf("\n"); + printf("Playing NEXT\n"); + printf(" Cart number: %06u\n",next->rlm_cartnum); + rlm_test_print_carttype(next->rlm_carttype); + printf("Start Date/Time: %04u-%02u-%02u %02u:%02u:%02u.%03u\n", + next->rlm_start_year,next->rlm_start_mon,next->rlm_start_day, + next->rlm_start_hour,next->rlm_start_min,next->rlm_start_sec, + next->rlm_start_msec); + printf(" Length: %u mS\n",next->rlm_len); + printf(" Title: %s\n",next->rlm_title); + printf(" Artist: %s\n",next->rlm_artist); + printf(" Label: %s\n",next->rlm_label); + printf(" Conductor: %s\n",next->rlm_conductor); + printf(" SongId: %s\n",next->rlm_song_id); + printf(" Client: %s\n",next->rlm_client); + printf(" Agency: %s\n",next->rlm_agency); + printf(" Composer: %s\n",next->rlm_comp); + printf(" Publisher: %s\n",next->rlm_pub); + printf(" UserDefined: %s\n",next->rlm_userdef); + printf(" Outcue: %s\n",next->rlm_outcue); + printf("Cut Description: %s\n",next->rlm_description); + printf(" ISRC: %s\n",next->rlm_isrc); + printf(" ISCI Code: %s\n",next->rlm_isci); + printf(" Ext Data: %s\n",next->rlm_ext_data); + printf(" Ext Event ID: %s\n",next->rlm_ext_eventid); + printf(" Ext Annc Type: %s\n",next->rlm_ext_annctype); +} diff --git a/rlm/rlm_twitter.c b/rlm/rlm_twitter.c new file mode 100644 index 00000000..08bbd14d --- /dev/null +++ b/rlm/rlm_twitter.c @@ -0,0 +1,264 @@ +/* rlm_twitter.c + * + * (C) Copyright 2008 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It sends Now&Next PAD data + * to the Twitter account(s) specified in the configuration file pointed + * to by the plugin argument. For information about the Twitter service, + * see http://www.twitter.com/. + * + * This module requires the curl(1) network transfer tool, included with + * most Linux distros. It is also available at http://curl.haxx.se/. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_twitter.rlm rlm_twitter.c + */ + +#include +#include +#include +#include +#include +#include + +#include + +int rlm_twitter_devs; +char *rlm_twitter_addresses; +char *rlm_twitter_passwords; +char *rlm_twitter_formats; +int *rlm_twitter_masters; +int *rlm_twitter_aux1s; +int *rlm_twitter_aux2s; + + +int rlm_twitter_BufferDiff(char *sString,int dOrigin,int dDiff,int dMaxSize) +{ + int dOldSize,dNewSize; + int i; + + /* + * Will it fit? + */ + dOldSize=strlen(sString); + if((dOldSize+dDiff)>=dMaxSize) { + return -1; + } + dNewSize=dOldSize+dDiff; + + /* + * Adding characters + */ + if(dDiff>0) { + for(i=dOldSize;i>dOrigin;i--) { + sString[i+dDiff]=sString[i]; + } + return dNewSize; + } + + /* + * No Change + */ + if(dDiff==0) { + return dNewSize; + } + + /* + * Deleting Characters + */ + if(dDiff<0) { + for(i=dOrigin;i'9') && (sString[i]<'A')) || + ((sString[i]>'Z') && (sString[i]<'a')) || + (sString[i]>'z'))) { + if(rlm_twitter_BufferDiff(sString,i,2,dMaxSize)<0) { + return -1; + } + sprintf(sAccum,"%%%2x",sString[i]); + sString[i++]=sAccum[0]; + sString[i++]=sAccum[1]; + sString[i]=sAccum[2]; + } + if(sString[i]==' ') { + sString[i]='+'; + } + i++; + } + return strlen(sString); +} + + +int rlm_twitter_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_twitter_RLMStart(void *ptr,const char *arg) +{ + char address[256]; + char section[256]; + char errtext[256]; + int i=1; + + rlm_twitter_devs=0; + rlm_twitter_addresses=NULL; + rlm_twitter_passwords=NULL; + rlm_twitter_formats=NULL; + rlm_twitter_masters=NULL; + rlm_twitter_aux1s=NULL; + rlm_twitter_aux2s=NULL; + + sprintf(section,"Twitter%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"EmailAddress",""),255); + address[255]=0; + if(strlen(address)==0) { + RLMLog(ptr,LOG_WARNING,"rlm_twitter: no twitter accounts specified"); + return; + } + while(strlen(address)>0) { + rlm_twitter_addresses=realloc(rlm_twitter_addresses, + (rlm_twitter_devs+1)*(rlm_twitter_devs+1)*256); + strcpy(rlm_twitter_addresses+256*rlm_twitter_devs,address); + rlm_twitter_passwords=realloc(rlm_twitter_passwords, + (rlm_twitter_devs+1)*(rlm_twitter_devs+1)*256); + strcpy(rlm_twitter_passwords+256*rlm_twitter_devs, + RLMGetStringValue(ptr,arg,section,"Password","")); + rlm_twitter_formats=realloc(rlm_twitter_formats,(rlm_twitter_devs+1)*256); + strncpy(rlm_twitter_formats+256*rlm_twitter_devs, + RLMGetStringValue(ptr,arg,section,"FormatString",""),256); + rlm_twitter_masters=realloc(rlm_twitter_masters, + (rlm_twitter_devs+1)*sizeof(int)); + rlm_twitter_masters[rlm_twitter_devs]= + rlm_twitter_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_twitter_aux1s=realloc(rlm_twitter_aux1s, + (rlm_twitter_devs+1)*sizeof(int)); + rlm_twitter_aux1s[rlm_twitter_devs]= + rlm_twitter_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_twitter_aux2s=realloc(rlm_twitter_aux2s, + (rlm_twitter_devs+1)*sizeof(int)); + rlm_twitter_aux2s[rlm_twitter_devs]= + rlm_twitter_GetLogStatus(ptr,arg,section,"Aux2Log"); + sprintf(errtext,"rlm_twitter: configured account \"%s\"",address); + rlm_twitter_devs++; + RLMLog(ptr,LOG_INFO,errtext); + sprintf(section,"Twitter%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"EmailAddress",""),255); + address[255]=0; + } +} + + +void rlm_twitter_RLMFree(void *ptr) +{ + free(rlm_twitter_addresses); + free(rlm_twitter_passwords); + free(rlm_twitter_formats); + free(rlm_twitter_masters); + free(rlm_twitter_aux1s); + free(rlm_twitter_aux2s); +} + + +void rlm_twitter_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char str[1024]; + char account[1024]; + char pad[1024]; + char msg[1500]; + + for(i=0;ilog_mach) { + case 0: + flag=rlm_twitter_masters[i]; + break; + + case 1: + flag=rlm_twitter_aux1s[i]; + break; + + case 2: + flag=rlm_twitter_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + strncpy(str,RLMResolveNowNext(ptr,now,next, + rlm_twitter_formats+256*i),256); + rlm_twitter_EncodeString(str,1023); + snprintf(account,1024,"%s:%s",rlm_twitter_addresses+256*i, + rlm_twitter_passwords+256*i); + snprintf(pad,1024,"status=%s",str); + if(strlen(now->rlm_title)!=0) { + if(fork()==0) { + execlp("curl","curl","-u",account,"-d",pad,"-o","/dev/null","-s", + "http://twitter.com/statuses/update.xml",(char *)NULL); + RLMLog(ptr,LOG_WARNING,"rlm_twitter: unable to execute curl(1)"); + exit(0); + } + } + snprintf(msg,1500,"rlm_twitter: sending pad update: \"%s\"", + (const char *)str); + RLMLog(ptr,LOG_INFO,msg); + } + } +} diff --git a/rlm/rlm_udp.c b/rlm/rlm_udp.c new file mode 100644 index 00000000..41a8f53a --- /dev/null +++ b/rlm/rlm_udp.c @@ -0,0 +1,205 @@ +/* rlm_udp.c + * + * (C) Copyright 2008 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It sends Now&Next PAD data via + * UDP packets to the destination(s) specified in the configuration file + * pointed to by the plugin argument. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_udp.rlm rlm_udp.c + */ + +#include +#include +#include +#include +#include + +int rlm_udp_devs; +char *rlm_udp_addresses; +uint16_t *rlm_udp_ports; +char *rlm_udp_formats; +int *rlm_udp_encodings; +int *rlm_udp_null_updates; +int *rlm_udp_masters; +int *rlm_udp_aux1s; +int *rlm_udp_aux2s; + +int rlm_udp_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_udp_RLMStart(void *ptr,const char *arg) +{ + char address[17]; + char section[256]; + char errtext[256]; + int i=1; + + rlm_udp_devs=0; + rlm_udp_addresses=NULL; + rlm_udp_ports=NULL; + rlm_udp_formats=NULL; + rlm_udp_encodings=NULL; + rlm_udp_null_updates=NULL; + rlm_udp_masters=NULL; + rlm_udp_aux1s=NULL; + rlm_udp_aux2s=NULL; + + sprintf(section,"Udp%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + if(strlen(address)==0) { + RLMLog(ptr,LOG_WARNING,"rlm_udp: no udp destinations specified"); + return; + } + while(strlen(address)>0) { + rlm_udp_addresses= + realloc(rlm_udp_addresses,(rlm_udp_devs+1)*(rlm_udp_devs+1)*16); + strcpy(rlm_udp_addresses+16*rlm_udp_devs,address); + rlm_udp_ports=realloc(rlm_udp_ports,(rlm_udp_devs+1)*sizeof(uint16_t)); + rlm_udp_ports[rlm_udp_devs]= + RLMGetIntegerValue(ptr,arg,section,"UdpPort",0); + rlm_udp_formats=realloc(rlm_udp_formats,(rlm_udp_devs+1)*256); + strncpy(rlm_udp_formats+256*rlm_udp_devs, + RLMGetStringValue(ptr,arg,section,"FormatString",""),256); + rlm_udp_encodings=realloc(rlm_udp_encodings, + (rlm_udp_devs+1)*sizeof(int)); + rlm_udp_encodings[rlm_udp_devs]= + RLMGetIntegerValue(ptr,arg,section,"Encoding",RLM_ENCODE_NONE); + rlm_udp_null_updates=realloc(rlm_udp_null_updates, + (rlm_udp_devs+1)*sizeof(int)); + rlm_udp_null_updates[rlm_udp_devs]= + RLMGetIntegerValue(ptr,arg,section,"ProcessNullUpdates",0); + rlm_udp_masters=realloc(rlm_udp_masters, + (rlm_udp_devs+1)*sizeof(int)); + rlm_udp_masters[rlm_udp_devs]= + rlm_udp_GetLogStatus(ptr,arg,section,"MasterLog"); + + rlm_udp_aux1s=realloc(rlm_udp_aux1s, + (rlm_udp_devs+1)*sizeof(int)); + rlm_udp_aux1s[rlm_udp_devs]= + rlm_udp_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_udp_aux2s=realloc(rlm_udp_aux2s, + (rlm_udp_devs+1)*sizeof(int)); + rlm_udp_aux2s[rlm_udp_devs]= + rlm_udp_GetLogStatus(ptr,arg,section,"Aux2Log"); + sprintf(errtext,"rlm_udp: configured destination \"%s:%d\"",address, + rlm_udp_ports[rlm_udp_devs]); + rlm_udp_devs++; + RLMLog(ptr,LOG_INFO,errtext); + sprintf(section,"Udp%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + } +} + + +void rlm_udp_RLMFree(void *ptr) +{ + free(rlm_udp_addresses); + free(rlm_udp_ports); + free(rlm_udp_formats); + free(rlm_udp_encodings); + free(rlm_udp_null_updates); + free(rlm_udp_masters); + free(rlm_udp_aux1s); + free(rlm_udp_aux2s); +} + + +void rlm_udp_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char msg[1500]; + + for(i=0;irlm_cartnum==0) { + return; + } + break; + + case 2: /* Process only non-null NEXT updates */ + if(next->rlm_cartnum==0) { + return; + } + break; + + case 3: /* Process only non-null NOW and NEXT updates */ + if((now->rlm_cartnum==0)||(next->rlm_cartnum==0)) { + return; + } + break; + } + + switch(log->log_mach) { + case 0: + flag=rlm_udp_masters[i]; + break; + + case 1: + flag=rlm_udp_aux1s[i]; + break; + + case 2: + flag=rlm_udp_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + const char *str= + RLMResolveNowNextEncoded(ptr,now,next,rlm_udp_formats+256*i, + rlm_udp_encodings[i]); + RLMSendUdp(ptr,rlm_udp_addresses+i*16,rlm_udp_ports[i],str,strlen(str)); + snprintf(msg,1500,"rlm_udp: sending pad update: \"%s\"", + (const char *)str); + RLMLog(ptr,LOG_INFO,msg); + } + } +} diff --git a/rlm/rlm_xds.c b/rlm/rlm_xds.c new file mode 100644 index 00000000..a425c3d9 --- /dev/null +++ b/rlm/rlm_xds.c @@ -0,0 +1,301 @@ +/* rlm_xds.c + * + * (C) Copyright 2010 Fred Gleason + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It sends generates enhanced netcue + * (aka CIC) packets for the Citadel/X-Digital Systems copy-splitting system, + * using a configuration file pointed to by the plugin argument. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_xds.rlm rlm_xds.c + */ + +#include +#include +#include +#include +#include +#include + +int rlm_xds_devs; +char *rlm_xds_isci_prefixes; +char *rlm_xds_addresses; +uint16_t *rlm_xds_ports; +int *rlm_xds_handles; +char *rlm_xds_tty_buffers; +int *rlm_xds_masters; +int *rlm_xds_aux1s; +int *rlm_xds_aux2s; + +unsigned rlm_xds_GetChecksum(const char *pack) +{ + unsigned ret=0; + int i; + + for(i=0;i': + case '?': + case '@': + case '[': + case '\\': + case ']': + case '^': + case '{': + case '|': + case '}': + ret[i]='-'; + break; + } + } + return ret; +} + +int rlm_xds_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_xds_RLMStart(void *ptr,const char *arg) +{ + char address[17]; + char section[256]; + char errtext[256]; + int tty_speed; + int i=1; + + rlm_xds_devs=0; + rlm_xds_addresses=NULL; + rlm_xds_ports=NULL; + rlm_xds_handles=NULL; + rlm_xds_tty_buffers=NULL; + rlm_xds_masters=NULL; + rlm_xds_aux1s=NULL; + rlm_xds_aux2s=NULL; + + sprintf(section,"Udp%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + if(strlen(address)==0) { + RLMLog(ptr,LOG_WARNING,"rlm_xds: no xds destinations specified"); + return; + } + while(strlen(address)>0) { + rlm_xds_addresses= + realloc(rlm_xds_addresses,(rlm_xds_devs+1)*(rlm_xds_devs+1)*16); + strcpy(rlm_xds_addresses+16*rlm_xds_devs,address); + rlm_xds_isci_prefixes=realloc(rlm_xds_isci_prefixes,(rlm_xds_devs+1)*32); + strncpy(rlm_xds_isci_prefixes+32*rlm_xds_devs, + RLMGetStringValue(ptr,arg,section,"IsciPrefix",""),31); + rlm_xds_ports=realloc(rlm_xds_ports,(rlm_xds_devs+1)*sizeof(uint16_t)); + rlm_xds_ports[rlm_xds_devs]= + RLMGetIntegerValue(ptr,arg,section,"UdpPort",0); + rlm_xds_handles=realloc(rlm_xds_handles,(rlm_xds_devs+1)*sizeof(int)); + rlm_xds_handles[rlm_xds_devs]=-1; + tty_speed=RLMGetIntegerValue(ptr,arg,section,"TtySpeed",9600); + printf("speed: %d\n",tty_speed); + rlm_xds_handles[rlm_xds_devs]= + RLMOpenSerial(ptr,RLMGetStringValue(ptr,arg,section,"TtyDevice",""), + tty_speed,RLM_PARITY_NONE,1); + rlm_xds_tty_buffers=realloc(rlm_xds_tty_buffers,(rlm_xds_devs+1)*256); + memset(rlm_xds_tty_buffers+rlm_xds_devs,0,256); + rlm_xds_masters=realloc(rlm_xds_masters, + (rlm_xds_devs+1)*sizeof(int)); + rlm_xds_masters[rlm_xds_devs]= + rlm_xds_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_xds_aux1s=realloc(rlm_xds_aux1s, + (rlm_xds_devs+1)*sizeof(int)); + rlm_xds_aux1s[rlm_xds_devs]= + rlm_xds_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_xds_aux2s=realloc(rlm_xds_aux2s, + (rlm_xds_devs+1)*sizeof(int)); + rlm_xds_aux2s[rlm_xds_devs]= + rlm_xds_GetLogStatus(ptr,arg,section,"Aux2Log"); + if(rlm_xds_handles[rlm_xds_devs]<0) { + sprintf(errtext,"rlm_xds: configured destination \"%s:%d\"",address, + rlm_xds_ports[rlm_xds_devs]); + } + else { + sprintf(errtext,"rlm_xds: configured destination \"%s\"", + (const char *)RLMGetStringValue(ptr,arg,section,"TtyDevice","")); + } + rlm_xds_devs++; + RLMLog(ptr,LOG_INFO,errtext); + sprintf(section,"Udp%d",i++); + strncpy(address,RLMGetStringValue(ptr,arg,section,"IpAddress",""),15); + } +} + + +void rlm_xds_RLMFree(void *ptr) +{ + int i; + + for(i=0;i=0) { + RLMCloseSerial(ptr,rlm_xds_handles[i]); + rlm_xds_handles[i]=-1; + } + } + free(rlm_xds_addresses); + free(rlm_xds_ports); + free(rlm_xds_handles); + free(rlm_xds_tty_buffers); + free(rlm_xds_isci_prefixes); + free(rlm_xds_masters); + free(rlm_xds_aux1s); + free(rlm_xds_aux2s); +} + + +void rlm_xds_RLMPadDataSent(void *ptr,const struct rlm_svc *svc, + const struct rlm_log *log, + const struct rlm_pad *now, + const struct rlm_pad *next) +{ + int i; + int flag=0; + char packet[64]; + char tty_packet[256]; + char msg[1500]; + + if(strlen((now->rlm_ext_eventid))==0) { + return; + } + for(i=0;ilog_mach) { + case 0: + flag=rlm_xds_masters[i]; + break; + + case 1: + flag=rlm_xds_aux1s[i]; + break; + + case 2: + flag=rlm_xds_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + packet[0]=0; + snprintf(packet,64,"0:%s:%s%s:*",svc->svc_pgmcode, + rlm_xds_isci_prefixes+i*32, + rlm_xds_FilterCharacters(now->rlm_ext_eventid)); + if(rlm_xds_handles[i]<0) { + RLMSendUdp(ptr,rlm_xds_addresses+i*16,rlm_xds_ports[i], + packet,strlen(packet)); + snprintf(msg,1500,"rlm_xds: sending CIC NetCue: \"%s\" to %s:%d", + (const char *)packet,rlm_xds_addresses+i*16,rlm_xds_ports[i]); + } + else { + snprintf(tty_packet,256,"NC:%u:%s\r\n", + rlm_xds_GetChecksum(packet),packet); + RLMSendSerial(ptr,rlm_xds_handles[i],tty_packet,strlen(tty_packet)); + RLMSendSerial(ptr,rlm_xds_handles[i],tty_packet,strlen(tty_packet)); + snprintf(msg,1500,"rlm_xds: sending CIC NetCue: \"%s\" to tty", + (const char *)packet); + } + RLMLog(ptr,LOG_INFO,msg); + } + } +} + + +void rlm_xds_RLMSerialDataReceived(void *ptr,int handle, + const char *data,int len) +{ + int dev; + int i; + char *buffer; + + for(dev=0;dev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This is a Rivendell Loadable Module. It sends Now&Next PAD data + * to an XM radio channel, using XM's in-house format. + * plugin argument. + * + * To compile this module, just do: + * + * gcc -shared -o rlm_xmpad.rlm rlm_xmpad.c + */ + +#include +#include +#include +#include +#include + +#define RLM_XMPAD_DELIMITER 0x02 +//#define RLM_XMPAD_DELIMITER 0x7C + + +int rlm_xmpad_devs; +int *rlm_xmpad_ids; +int *rlm_xmpad_handles; +int *rlm_xmpad_recordings; +char *rlm_xmpad_format1s; +char *rlm_xmpad_format2s; +int *rlm_xmpad_display_size1s; +int *rlm_xmpad_display_size2s; +int *rlm_xmpad_masters; +int *rlm_xmpad_aux1s; +int *rlm_xmpad_aux2s; + +int rlm_xmpad_GetLogStatus(void *ptr,const char *arg,const char *section, + const char *logname) +{ + const char *tag=RLMGetStringValue(ptr,arg,section,logname,""); + if(strcasecmp(tag,"yes")==0) { + return 1; + } + if(strcasecmp(tag,"on")==0) { + return 1; + } + if(strcasecmp(tag,"true")==0) { + return 1; + } + if(strcasecmp(tag,"no")==0) { + return 0; + } + if(strcasecmp(tag,"off")==0) { + return 0; + } + if(strcasecmp(tag,"false")==0) { + return 0; + } + if(strcasecmp(tag,"onair")==0) { + return 2; + } + return 0; +} + + +void rlm_xmpad_SendPad(void *ptr,int config,const char *line1, + const char *line2,int len) +{ + char str[1024]; + char sline1[17]; + char sline2[17]; + char flag1[1024]; + char flag2[1024]; + int i; + + // + // Log it + // + sprintf(str,"rlm_xmpad: sending pad update: |%s|%s|%d|",line1,line2,len); + RLMLog(ptr,LOG_INFO,str); + + // + // Generate Display Strings and Flags + // + strncpy(sline1,line1,16); + sline1[16]=0; + flag1[0]=0; + for(i=0;i0) { + speed=RLMGetIntegerValue(ptr,arg,section,"Speed",9600); + parity=RLMGetIntegerValue(ptr,arg,section,"Parity",0); + wsize=RLMGetIntegerValue(ptr,arg,section,"WordSize",8); + if((handle=RLMOpenSerial(ptr,device,speed,parity,wsize))>=0) { + rlm_xmpad_handles=realloc(rlm_xmpad_handles, + (rlm_xmpad_devs+1)*sizeof(int)); + rlm_xmpad_handles[rlm_xmpad_devs]=handle; + rlm_xmpad_ids=realloc(rlm_xmpad_ids,(rlm_xmpad_devs+1)*sizeof(int)); + rlm_xmpad_ids[rlm_xmpad_devs]= + RLMGetIntegerValue(ptr,arg,section,"ProgramID",0); + rlm_xmpad_format1s=realloc(rlm_xmpad_format1s,(rlm_xmpad_devs+1)*256); + strncpy(rlm_xmpad_format1s+256*rlm_xmpad_devs, + RLMGetStringValue(ptr,arg,section,"FormatString1",""),256); + rlm_xmpad_format2s=realloc(rlm_xmpad_format2s,(rlm_xmpad_devs+1)*256); + strncpy(rlm_xmpad_format2s+256*rlm_xmpad_devs, + RLMGetStringValue(ptr,arg,section,"FormatString2",""),256); + rlm_xmpad_display_size1s=realloc(rlm_xmpad_display_size1s, + (rlm_xmpad_devs+1)*sizeof(int)); + rlm_xmpad_display_size1s[rlm_xmpad_devs]= + RLMGetIntegerValue(ptr,arg,section,"DisplaySize1",8); + rlm_xmpad_display_size2s=realloc(rlm_xmpad_display_size2s, + (rlm_xmpad_devs+1)*sizeof(int)); + rlm_xmpad_display_size2s[rlm_xmpad_devs]= + RLMGetIntegerValue(ptr,arg,section,"DisplaySize2",10); + rlm_xmpad_recordings=realloc(rlm_xmpad_recordings, + (rlm_xmpad_devs+1)*sizeof(int)); + rlm_xmpad_recordings[rlm_xmpad_devs]= + RLMGetBooleanValue(ptr,arg,section,"Recording",1); + rlm_xmpad_masters=realloc(rlm_xmpad_masters, + (rlm_xmpad_devs+1)*sizeof(int)); + rlm_xmpad_masters[rlm_xmpad_devs]= + rlm_xmpad_GetLogStatus(ptr,arg,section,"MasterLog"); + rlm_xmpad_aux1s=realloc(rlm_xmpad_aux1s, + (rlm_xmpad_devs+1)*sizeof(int)); + rlm_xmpad_aux1s[rlm_xmpad_devs]= + rlm_xmpad_GetLogStatus(ptr,arg,section,"Aux1Log"); + rlm_xmpad_aux2s=realloc(rlm_xmpad_aux2s, + (rlm_xmpad_devs+1)*sizeof(int)); + rlm_xmpad_aux2s[rlm_xmpad_devs]= + rlm_xmpad_GetLogStatus(ptr,arg,section,"Aux2Log"); + interval=RLMGetIntegerValue(ptr,arg,section,"HeartbeatInterval",30); + if(interval>0) { + RLMStartTimer(ptr,rlm_xmpad_devs,1000*interval,RLM_TIMER_REPEATING); + } + rlm_xmpad_devs++; + sprintf(errtext,"rlm_xmpad: opened device \"%s\"",device); + RLMLog(ptr,LOG_INFO,errtext); + } + else { + sprintf(errtext,"unable to open tty \"%s\"",device); + RLMLog(ptr,LOG_WARNING,errtext); + } + sprintf(section,"Serial%d",i++); + strncpy(device,RLMGetStringValue(ptr,arg,section,"Device",""),256); + } +} + + +void rlm_xmpad_RLMFree(void *ptr) +{ + int i; + + for(i=0;irlm_cartnum==0) { // Suppress null PAD frames + return; + } + for(i=0;ilog_mach) { + case 0: + flag=rlm_xmpad_masters[i]; + break; + + case 1: + flag=rlm_xmpad_aux1s[i]; + break; + + case 2: + flag=rlm_xmpad_aux2s[i]; + break; + } + if((flag==1)||((flag==2)&&(log->log_onair!=0))) { + strncpy(str1,RLMResolveNowNext(ptr,now,next,rlm_xmpad_format1s+256*i),32); + str1[32]=0; + strncpy(str2,RLMResolveNowNext(ptr,now,next,rlm_xmpad_format2s+256*i),32); + str2[32]=0; + rlm_xmpad_SendPad(ptr,i,str1,str2,now->rlm_len); + snprintf(msg,1500,"rlm_xmpad: sending pad update: \"%s | %s\"", + (const char *)str1,(const char *)str2); + RLMLog(ptr,LOG_INFO,msg); + } + } +} + + +void rlm_xmpad_RLMTimerExpired(void *ptr,int timernum) +{ + RLMSendSerial(ptr,rlm_xmpad_handles[timernum],"H0\n",3); +} diff --git a/scripts/Makefile.am b/scripts/Makefile.am new file mode 100644 index 00000000..77f8aac8 --- /dev/null +++ b/scripts/Makefile.am @@ -0,0 +1,58 @@ +## automake.am +## +## Scripts Directory Makefile.am for Rivendell +## +## (C) Copyright 2002-2012 Fred Gleason +## +## $Id: Makefile.am,v 1.20.6.5 2012/11/29 01:37:37 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +install-exec-local: + mkdir -p /etc/X11/xinit/xinitrc.d + cp start-rdmonitor.sh /etc/X11/xinit/xinitrc.d/ + +uninstall-local: + rm -f /etc/X11/xinit/xinitrc.d/start-rdmonitor.sh + +bin_SCRIPTS = crc-unity4k.sh\ + rd_audio_sync\ + rd_config\ + rd_backup\ + rdmemcheck.sh\ + sage_endec_rwt.sh + +EXTRA_DIST = crc-unity4k.sh\ + kill_rd\ + rd_audio_sync\ + rd_backup\ + rd_backup_system.sh\ + rd_config\ + rd_create_db\ + rd_memmon.sh\ + rd_mysql_enable_host.sh\ + rd_restore_system.sh\ + rdmemcheck.sh\ + sage_endec_rwt.sh\ + start_rd\ + start_traverso.sh\ + start-rdmonitor.sh + +CLEANFILES = *~ + +MAINTAINERCLEANFILES = *~\ + Makefile.in diff --git a/scripts/crc-unity4k.sh b/scripts/crc-unity4k.sh new file mode 100755 index 00000000..fcd98829 --- /dev/null +++ b/scripts/crc-unity4k.sh @@ -0,0 +1,377 @@ +#!/bin/bash + +# crc-unity4k.sh +# +# Create a Unity4000 Switcher Configuration for the +# Christian Radio Consortium (CRC) Network +# +# (C) Copyright 2004 Fred Gleason +# +# $Id: crc-unity4k.sh,v 1.3 2007/02/14 21:59:12 fredg Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# Usage: crc-unity4k + +# +# Arguments +# +HOSTNAME=$1 +STATION=$2 +MATRIX=$3 + +# +# Check Argument Sanity +# +if [ -z $HOSTNAME ] ; then + echo "USAGE: crc-unity4k " + exit 1 +fi +if [ -z $STATION ] ; then + echo "USAGE: crc-unity4k " + exit 1 +fi +if [ -z $MATRIX ] ; then + echo "USAGE: crc-unity4k " + exit 1 +fi + +# +# Show Settings and Confirm +# +echo +echo "This will create a set of default CRC input assignments on the following" +echo "database/matrix:" +echo " mySQL Hostname: $HOSTNAME" +echo " Station Name: $STATION" +echo " Matrix Number: $MATRIX" +echo +echo "WARNING: This will OVERWRITE any existing input assignments for" +echo "this matrix!" +echo +echo -n "Continue?" +read REPLY +echo +echo -n "Working..." + +# +# Delete Existing Configuration +# +SQL="delete from INPUTS where (STATION_NAME=\"$STATION\" && MATRIX=$MATRIX)" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# Write New Inputs +# +# +# AA-1 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=1,\ + NAME=\"AA-1 Stereo\",FEED_NAME=\"AA1\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=2,\ + NAME=\"AA-1 Left\",FEED_NAME=\"AA1\",CHANNEL_MODE=1" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=3,\ + NAME=\"AA-1 Right\",FEED_NAME=\"AA1\",CHANNEL_MODE=2" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# AA-2 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=4,\ + NAME=\"AA-2 Stereo\",FEED_NAME=\"AA2\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=5,\ + NAME=\"AA-2 Left\",FEED_NAME=\"AA2\",CHANNEL_MODE=1" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=6,\ + NAME=\"AA-2 Right\",FEED_NAME=\"AA2\",CHANNEL_MODE=2" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# AMC +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=7,\ + NAME=\"AMC\",FEED_NAME=\"AMC\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# CRB +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=8,\ + NAME=\"CRB\",FEED_NAME=\"CRB\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# CSN +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=9,\ + NAME=\"CSN\",FEED_NAME=\"CSN\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# CS2 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=10,\ + NAME=\"CS2\",FEED_NAME=\"CS2\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# FN-1 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=11,\ + NAME=\"FN-1 Stereo\",FEED_NAME=\"FN1\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=12,\ + NAME=\"FN-1 Left\",FEED_NAME=\"FN1\",CHANNEL_MODE=1" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=13,\ + NAME=\"FN-1 Right\",FEED_NAME=\"FN1\",CHANNEL_MODE=2" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# FN-2 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=14,\ + NAME=\"FN-2 Stereo\",FEED_NAME=\"FN2\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=15,\ + NAME=\"FN-2 Left\",FEED_NAME=\"FN2\",CHANNEL_MODE=1" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=16,\ + NAME=\"FN-2 Right\",FEED_NAME=\"FN2\",CHANNEL_MODE=2" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# FN-3 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=17,\ + NAME=\"FN-3 Stereo\",FEED_NAME=\"FN3\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=18,\ + NAME=\"FN-3 Left\",FEED_NAME=\"FN3\",CHANNEL_MODE=1" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=19,\ + NAME=\"FN-3 Right\",FEED_NAME=\"FN3\",CHANNEL_MODE=2" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# FOF +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=20,\ + NAME=\"FOF\",FEED_NAME=\"FOF\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# IRN +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=21,\ + NAME=\"IRN\",FEED_NAME=\"IRN\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# LF1 Stereo +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=22,\ + NAME=\"LF1 Stereo\",FEED_NAME=\"LF1\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# LF1 Left +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=23,\ + NAME=\"LF1 LEft\",FEED_NAME=\"LF1\",CHANNEL_MODE=1" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# LF1 Right +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=24,\ + NAME=\"LF1 Right\",FEED_NAME=\"LF1\",CHANNEL_MODE=2" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# MB1 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=25,\ + NAME=\"MB1\",FEED_NAME=\"MB1\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# MB2 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=26,\ + NAME=\"MB2\",FEED_NAME=\"MB2\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# REF +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=27,\ + NAME=\"REF\",FEED_NAME=\"REF\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# RR1 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=28,\ + NAME=\"RR1\",FEED_NAME=\"RR1\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SGT +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=29,\ + NAME=\"SGT\",FEED_NAME=\"SGT\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SKY +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=30,\ + NAME=\"SKY\",FEED_NAME=\"SKY\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SK2 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=31,\ + NAME=\"SK2\",FEED_NAME=\"SK2\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SMA +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=32,\ + NAME=\"SMA\",FEED_NAME=\"SMA\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SMB +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=33,\ + NAME=\"SMB\",FEED_NAME=\"SMB\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SMC +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=34,\ + NAME=\"SMC\",FEED_NAME=\"SMC\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SNN +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=35,\ + NAME=\"SNN\",FEED_NAME=\"SNN\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SOS +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=36,\ + NAME=\"SOS\",FEED_NAME=\"SOS\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SR1 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=37,\ + NAME=\"SR1\",FEED_NAME=\"SR1\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SR2 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=38,\ + NAME=\"SR2\",FEED_NAME=\"SR2\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SR3 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=39,\ + NAME=\"SR3\",FEED_NAME=\"SR3\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SR4 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=40,\ + NAME=\"SR4\",FEED_NAME=\"SR4\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# SR5 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=41,\ + NAME=\"SR5\",FEED_NAME=\"SR5\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# US1 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=42,\ + NAME=\"US1\",FEED_NAME=\"US1\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# US2 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=43,\ + NAME=\"US2\",FEED_NAME=\"US2\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# US3 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=44,\ + NAME=\"US3\",FEED_NAME=\"US3\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# US4 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=45,\ + NAME=\"US4\",FEED_NAME=\"US4\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# VC1 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=46,\ + NAME=\"VC1\",FEED_NAME=\"VC1\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# VC2 +# +SQL="insert into INPUTS set STATION_NAME=\"$STATION\",MATRIX=$MATRIX,NUMBER=47,\ + NAME=\"VC2\",FEED_NAME=\"VC2\",CHANNEL_MODE=0" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +# +# Update MATRICES Table +# +SQL="update MATRICES set INPUTS=47 where (STATION_NAME=\"$STATION\" && MATRIX=$MATRIX)" +mysql Rivendell -h $HOSTNAME -u rduser -pletmein -e "$SQL" + +echo "done." +echo + + +# End of crc-unity-4k diff --git a/scripts/kill_rd b/scripts/kill_rd new file mode 100755 index 00000000..55cf4e67 --- /dev/null +++ b/scripts/kill_rd @@ -0,0 +1,59 @@ +# kill_rd +# +# Shutdown down the Rivendell system daemons +# +# (C) Copyright 2003 Fred Gleason +# +# $Id: kill_rd,v 1.5 2007/02/14 21:59:12 fredg Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Site Configuration +# +RD_CAED_PID=/var/snd/caed.pid +RD_RIPCD_PID=/var/snd/ripcd.pid +RD_RDCATCHD_PID=/var/snd/rdcatchd.pid + + +# End of site configuration +# ########################################################################## + +echo "Shutting down Rivendell daemons" + +# +# Shut Down Rivendell Daemons +# +if [ -z `ps c --no-headers -o "%a" -C caed` ] ; then + echo -n +else + kill `cat $RD_CAED_PID` +fi +rm -f $RD_CAED_PID +if [ -z `ps c --no-headers -o "%a" -C ripcd` ] ; then + echo -n +else + kill `cat $RD_RIPCD_PID` +fi +rm -f $RD_RIPCD_PID +if [ -z `ps c --no-headers -o "%a" -C rdcatchd` ] ; then + echo -n +else + kill `cat $RD_RDCATCHD_PID` +fi +rm -f $RD_RDCATCHD_PID + + +# End of kill_rd diff --git a/scripts/rd_audio_sync b/scripts/rd_audio_sync new file mode 100755 index 00000000..f6817687 --- /dev/null +++ b/scripts/rd_audio_sync @@ -0,0 +1,82 @@ +#!/bin/bash + +# rd_audio_sync +# +# Syncronize a Rivendell audio archive with the master server. +# +# (C) Copyright 2004 Fred Gleason +# +# $Id: rd_audio_sync,v 1.4 2007/05/16 21:07:08 grauf Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# Usage: +# rd_audio_sync +# + +# +# Configuration and Paths +# +MODULE_NAME=rivendell +CHECK_FILE=repl.chk +BACKUP_DIR=/var/snd.standby +NICE_ADJ=15 +RSYNC=/usr/bin/rsync +NICE=/usr/bin/nice + +# +# Check that rd_audio_sync is not already running +# +lockdir=/var/tmp/rd_audio_sync.lock +if mkdir "$lockdir" 2> /dev/null ; then + #echo >&2 "successfully acquired lock" + + # Remove lockdir when the script finishes, or when it receives a signal + trap 'rm -rf "$lockdir"' 0 # remove directory when script finishes + trap "exit 2" 1 2 3 15 # terminate script when receiving signal +else + echo >&2 "cannot acquire lock, giving up on $lockdir" + exit 0 +fi + +# +# Check that the master is alive and well +# +$RSYNC $1::$MODULE_NAME/$CHECK_FILE > /dev/null 2> /dev/null +if [ $? -ne 0 ] ; then + echo "rd_audio_sync: check file not found, aborting" + exit 1 +fi + +# +# Replicate +# +$NICE -n $NICE_ADJ $RSYNC --times --dirs --delete $1::$MODULE_NAME/*.wav $BACKUP_DIR > /dev/null 2> /dev/null +if [ $? -ne 0 ] ; then + echo "rd_audio_sync: replication returned an error, check rsyncd logs" + exit 2 +fi + +# +# Cleanup partially transferred files left by buggy versions of rsync (i.e. 2.6.8) +# +$NICE -n $NICE_ADJ rm $BACKUP_DIR/.*wav.* 2> /dev/null + +exit 0 + + +# End of rd_audio_sync + + + diff --git a/scripts/rd_backup b/scripts/rd_backup new file mode 100755 index 00000000..990c482a --- /dev/null +++ b/scripts/rd_backup @@ -0,0 +1,72 @@ +#!/bin/bash + +# rd_backup +# +# Dump the local Rivendell database and copy the dump to one or more +# remote hosts. +# +# Copyright (C) 2006 Fred Gleason +# +# $Id: rd_backup,v 1.5 2007/10/08 18:37:33 fredg Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Site Settings +# +SITE_ID="kgu" +SHELF_LIFE=7 +DB_NAME=Rivendell +DB_USER=root +DB_PASSWORD=letmein +BACKUP_DIR=/home/salem/rd_backup + +# +# Generate the backup filename +# +BACKUP_FILE=`date +$BACKUP_DIR/$SITE_ID-%Y%m%d.sql` + +# +# Dump the database +# +mysqldump --opt -u $DB_USER -p$DB_PASSWORD $DB_NAME > $BACKUP_FILE + +# +# Purge old backups +# +find $BACKUP_DIR -mtime +$SHELF_LIFE -type f -exec rm \{\} \; + +# +# Copy to remote hosts +# +# Customize this section to list the remote hosts you wish to copy the +# dump to. Yoou will need two lines for each host: one to copy the data, +# and another to purge old data. +# +# For example, let's say you have a host called 'rivendell.example.com', +# where you want to put the backups into a directory called +# '/home/salem/rdbackup'. You would do: +# +# scp -q $BACKUP_FILE salem@rivendell.example.com:rd_backup/ +# ssh salem@rdkaim "find /home/salem/rd_backup -mtime $SHELF_LIFE -type f -exec rm \{\} \;" +# +# +# Note that the remote machine must be set up to accept automatic logins via +# ssh(1) in order for this to work! +# + + + +# End of rd_backup diff --git a/scripts/rd_backup_system.sh b/scripts/rd_backup_system.sh new file mode 100755 index 00000000..e290eb12 --- /dev/null +++ b/scripts/rd_backup_system.sh @@ -0,0 +1,105 @@ +#! /bin/bash + +# rd_backup_system.sh +# +# Back up a complete Rivendell setup to removable media. +# +# (C) Copyright 2011 Fred Gleason +# +# $Id: rd_backup_system.sh,v 1.3 2011/05/23 11:22:48 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# This script is intended for use as a starting point for a site-specific +# backup routine. Administrators are strongly encouraged to customize it +# for their envirnment! +# + +# +# Site Configuration +# +MYSQL_USERNAME=rduser +MYSQL_PASSWORD=letmein +MYSQL_HOSTNAME=127.0.0.1 +MYSQL_DBNAME=Rivendell +BACKUP_DEVICE=/dev/sdb1 +BACKUP_MOUNT_POINT=/media/rdbackup + +function Continue { + read -a RESP -p "Continue (y/N) " + echo + if [ -z $RESP ] ; then + exit 0 + fi + if [ $RESP != "y" -a $RESP != "Y" ] ; then + exit 0 + fi +} + +# +# Calculate date/time string +# +DATE_STAMP=`date +%Y%m%d%H%M%S` + +# +# Warning Messages +# +echo "This process will backup the Rivendell system to external media." +echo +echo "WARNING: This will completely destroy any data on the external media!" +echo +Continue + +echo "Please verify that the external drive is connected before continuing." +echo +Continue + +# +# Setup environment +# +echo -n "Preparing backup device..." +sleep 5 +mkdir -p $BACKUP_MOUNT_POINT +mount $BACKUP_DEVICE $BACKUP_MOUNT_POINT +mkdir -p $BACKUP_MOUNT_POINT/ +rm -f $BACKUP_MOUNT_POINT/*.sql +mkdir -p $BACKUP_MOUNT_POINT/snd +echo "done." + + +# +# Backup Database +# +echo -n "Backing up database..." +mysqldump -h $MYSQL_HOSTNAME -u $MYSQL_USERNAME -p$MYSQL_PASSWORD $MYSQL_DBNAME > $BACKUP_MOUNT_POINT/db-$DATE_STAMP.sql +ln -s db-$DATE_STAMP.sql $BACKUP_MOUNT_POINT/db.sql +echo "done." + +# +# Backup Audio +# +echo -n "Backup up audio..." +rsync -av --delete /var/snd/ $BACKUP_MOUNT_POINT/snd +echo "done." + +# +# Clean Up +# +umount $BACKUP_MOUNT_POINT +rmdir $BACKUP_MOUNT_POINT +echo +echo "Backup complete!" +echo + +exit 0 diff --git a/scripts/rd_config b/scripts/rd_config new file mode 100755 index 00000000..eb166640 --- /dev/null +++ b/scripts/rd_config @@ -0,0 +1,80 @@ +#!/bin/bash + +# rd_config +# +# Manage Rivendell configurations. +# +# (C) Copyright 2004 Fred Gleason +# +# $Id: rd_config,v 1.4 2011/01/20 15:33:02 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# Usage: +# rd_config master|standby +# + +# +# Configuration and Paths +# +MAIN_CONF=/etc/rd.conf +MAIN_SND=/var/snd +MASTER_CONF=/etc/rd.conf.master +STANDBY_CONF=/etc/rd.conf.standby +MASTER_SND=/var/snd.master +STANDBY_SND=/var/snd.standby +INIT_SCRIPT=/etc/init.d/rivendell +RM=/bin/rm +LN=/bin/ln + +case "$1" in + master) + $INIT_SCRIPT stop + if [ $? -ne 0 ] ; then + echo "rd_config: can't stop current config, aborting" + exit 1 + fi + $RM -f $MAIN_CONF + $RM -f $MAIN_SND + $LN -s $MASTER_CONF $MAIN_CONF + $LN -s $MASTER_SND $MAIN_SND + $INIT_SCRIPT start + if [ $? -ne 0 ] ; then + echo "rd_config: can't start new config" + exit 2 + fi + ;; + + standby) + $INIT_SCRIPT stop + if [ $? -ne 0 ] ; then + echo "rd_config: can't stop current config, aborting" + exit 1 + fi + $RM -f $MAIN_CONF + $RM -f $MAIN_SND + $LN -s $STANDBY_CONF $MAIN_CONF + $LN -s $STANDBY_SND $MAIN_SND + $INIT_SCRIPT start + if [ $? -ne 0 ] ; then + echo "rd_config: can't start new config" + exit 2 + fi + ;; +esac + +# End of rd_config + + + diff --git a/scripts/rd_create_db b/scripts/rd_create_db new file mode 100755 index 00000000..419bd2aa --- /dev/null +++ b/scripts/rd_create_db @@ -0,0 +1,771 @@ +# create_db +# +# Create and initialize a new database for Rivendell. +# +# (C) Copyright 2002-2003 Fred Gleason +# +# $Id: rd_create_db,v 1.25 2007/02/14 21:59:12 fredg Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +# +# Site Configuration +# + +# +# Rivendell mySQL Application Account +# +RD_USER=rduser@localhost +RD_PASSWORD=letmein + +# +# Default Rivendell Administrator +# +RDA_LOGIN_NAME=admin +RDA_PASSWORD= +RDA_FULL_NAME="System Administrator" +RDA_DESCRIPTION="Default Administrator Account" + +# +# Default Rivendell User +# +USER_LOGIN_NAME=user +USER_PASSWORD= +USER_FULL_NAME="Rivendell User" +USER_DESCRIPTION="Default User Account" + +# +# Default Rivendell Service +# +RD_SVC_NAME="Production" +RD_SVC_DESC="Default Audio Service" + +# +# Rivendell Audio Repository +# +RD_AUDIO_ROOT=/var/snd + +# Nothing should need to be changed below here! +# ############################################################################ + +# ############################################################################ +# Create a Rivendell Database +# ############################################################################ +function CreateDB { +# +# Create the database +# +mysql -u $USER -p$PASSWORD -e"CREATE DATABASE IF NOT EXISTS Rivendell" + +# +# Set Security Privledges +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON * TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create USERS table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; +CREATE TABLE IF NOT EXISTS USERS ( + LOGIN_NAME CHAR(8) NOT NULL PRIMARY KEY, + FULL_NAME CHAR(64), + PHONE_NUMBER CHAR(20), + DESCRIPTION CHAR(255), + PASSWORD CHAR(32) NOT NULL, + ADMIN_USERS_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + ADMIN_CONFIG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + CREATE_CARTS_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + DELETE_CARTS_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + MODIFY_CARTS_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + EDIT_AUDIO_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + ASSIGN_CART_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + CREATE_LOG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + DELETE_LOG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + PLAYOUT_LOG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + ARRANGE_LOG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + ADDTO_LOG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + REMOVEFROM_LOG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + EDIT_CATCHES_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N', + INDEX FULL_NAME_IDX (FULL_NAME) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON USERS TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create STATIONS table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS STATIONS ( + NAME CHAR(64) PRIMARY KEY NOT NULL, + DESCRIPTION CHAR(64), + USER_NAME CHAR(8), + DEFAULT_NAME CHAR(8), + INDEX DESCRIPTION_IDX (DESCRIPTION) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON STATIONS TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create CART table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS CART ( + NUMBER INT UNSIGNED NOT NULL PRIMARY KEY, + TYPE INT UNSIGNED NOT NULL, + GROUP_NAME CHAR(10) NOT NULL, + TITLE CHAR(255), + ARTIST CHAR(255), + ALBUM CHAR(255), + YEAR DATE, + ISRC CHAR(12), + LABEL CHAR(64), + CLIENT CHAR(64), + AGENCY CHAR(64), + USER_DEFINED CHAR(255), + FORCED_LENGTH INT UNSIGNED, + CUT_QUANTITY INT UNSIGNED, + LAST_CUT_PLAYED INT UNSIGNED, + PLAY_ORDER INT UNSIGNED, + START_DATETIME DATETIME, + END_DATETIME DATETIME, + ENFORCE_LENGTH ENUM('N','Y') DEFAULT 'N', + PRESERVE_PITCH ENUM('N','Y') DEFAULT 'N', + INDEX GROUP_NAME_IDX (GROUP_NAME), + INDEX TITLE_IDX (TITLE), + INDEX ARTIST_IDX (ARTIST), + INDEX ALBUM_IDX (ALBUM), + INDEX LABEL_IDX (LABEL), + INDEX CLIENT_IDX (CLIENT), + INDEX AGENCY_IDX (AGENCY), + INDEX USER_DEFINED_IDX (USER_DEFINED) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON CART TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create CUTS table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS CUTS ( + CUT_NAME CHAR(12) PRIMARY KEY NOT NULL, + CART_NUMBER INT UNSIGNED NOT NULL, + DESCRIPTION CHAR(64), + OUTCUE CHAR(64), + LENGTH INT UNSIGNED, + ORIGIN_DATETIME DATETIME DEFAULT '0/0/0000 24:00:00', + START_DATETIME DATETIME DEFAULT '0/0/0000 24:00:00', + END_DATETIME DATETIME DEFAULT '0/0/0000 24:00:00', + START_DAYPART TIME DEFAULT '24:00:00', + END_DAYPART TIME DEFAULT '24:00:00', + ORIGIN_NAME CHAR(64), + WEIGHT INT UNSIGNED DEFAULT 1, + LAST_PLAY_DATETIME DATETIME, + PLAY_COUNTER INT UNSIGNED DEFAULT 0, + CODING_FORMAT INT UNSIGNED, + SAMPLE_RATE INT UNSIGNED, + BIT_RATE INT UNSIGNED, + CHANNELS INT UNSIGNED, + PLAY_GAIN INT DEFAULT 0, + START_POINT INT DEFAULT -1, + END_POINT INT DEFAULT -1, + FADEUP_POINT INT DEFAULT -1, + FADEDOWN_POINT INT DEFAULT -1, + SEGUE_START_POINT INT DEFAULT -1, + SEGUE_END_POINT INT DEFAULT -1, + HOOK_START_POINT INT DEFAULT -1, + HOOK_END_POINT INT DEFAULT -1, + TALK_START_POINT INT DEFAULT -1, + TALK_END_POINT INT DEFAULT -1, + INDEX CART_NUMBER_IDX (CART_NUMBER), + INDEX DESCRIPTION_IDX (DESCRIPTION), + INDEX OUTCUE_IDX (OUTCUE), + INDEX ORIGIN_DATETIME_IDX (ORIGIN_DATETIME), + INDEX START_DATETIME_IDX (START_DATETIME), + INDEX END_DATETIME_IDX (END_DATETIME) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON CUTS TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create CLIPBOARD table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS CLIPBOARD ( + CUT_NAME CHAR(12) PRIMARY KEY NOT NULL, + CART_NUMBER INT UNSIGNED NOT NULL, + DESCRIPTION CHAR(64), + OUTCUE CHAR(64), + LENGTH INT UNSIGNED, + ORIGIN_DATETIME DATETIME, + ORIGIN_NAME CHAR(64), + WEIGHT INT UNSIGNED DEFAULT 1, + LAST_PLAY_DATETIME DATETIME, + PLAY_COUNTER INT UNSIGNED DEFAULT 0, + CODING_FORMAT INT UNSIGNED, + SAMPLE_RATE INT UNSIGNED, + BIT_RATE INT UNSIGNED, + CHANNELS INT UNSIGNED, + PLAY_GAIN INT DEFAULT 0, + START_POINT INT DEFAULT -1, + END_POINT INT DEFAULT -1, + FADEUP_POINT INT DEFAULT -1, + FADEDOWN_POINT INT DEFAULT -1, + SEGUE_START_POINT INT DEFAULT -1, + SEGUE_END_POINT INT DEFAULT -1, + HOOK_START_POINT INT DEFAULT -1, + HOOK_END_POINT INT DEFAULT -1, + TALK_START_POINT INT DEFAULT -1, + TALK_END_POINT INT DEFAULT -1, + INDEX CART_NUMBER_IDX (CART_NUMBER), + INDEX DESCRIPTION_IDX (DESCRIPTION), + INDEX OUTCUE_IDX (OUTCUE) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON CLIPBOARD TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create SERVICES table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS SERVICES ( + NAME CHAR(10) NOT NULL PRIMARY KEY, + DESCRIPTION CHAR(255) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON SERVICES TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create GROUPS table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS GROUPS ( + NAME CHAR(10) NOT NULL PRIMARY KEY, + DESCRIPTION CHAR(255) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON GROUPS TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create AUDIO_PERMS table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS AUDIO_PERMS ( + ID INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, + GROUP_NAME CHAR(10), + SERVICE_NAME CHAR(10), + INDEX GROUP_IDX (GROUP_NAME), + INDEX SERVICE_IDX (SERVICE_NAME) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON AUDIO_PERMS TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create RDLIBRARY table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS RDLIBRARY ( + ID INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, + STATION CHAR(40) NOT NULL, + INSTANCE INT UNSIGNED NOT NULL, + INPUT_CARD INT DEFAULT -1, + INPUT_STREAM INT DEFAULT -1, + INPUT_PORT INT DEFAULT -1, + INPUT_TYPE ENUM('A','D') DEFAULT 'A', + OUTPUT_CARD INT DEFAULT -1, + OUTPUT_STREAM INT DEFAULT -1, + OUTPUT_PORT INT DEFAULT -1, + VOX_THRESHOLD INT DEFAULT -5000, + TRIM_THRESHOLD INT DEFAULT -3000, + RECORD_GPI INT DEFAULT -1, + PLAY_GPI INT DEFAULT -1, + STOP_GPI INT DEFAULT -1, + DEFAULT_FORMAT INT UNSIGNED DEFAULT 0, + DEFAULT_CHANNELS INT UNSIGNED DEFAULT 2, + DEFAULT_SAMPRATE INT UNSIGNED DEFAULT 44100, + DEFAULT_LAYER INT UNSIGNED DEFAULT 0, + DEFAULT_BITRATE INT UNSIGNED DEFAULT 0, + DEFAULT_RECORD_MODE INT UNSIGNED DEFAULT 0, + DEFAULT_TRIM_STATE ENUM('N','Y') DEFAULT 'N', + MAXLENGTH INT, + TAIL_PREROLL INT UNSIGNED DEFAULT 1500, + RIPPER_DEVICE CHAR(64) DEFAULT \"/dev/cdrom\", + PARANOIA_LEVEL INT DEFAULT 0, + RIPPER_LEVEL INT DEFAULT 0, + CDDB_SERVER CHAR(64) DEFAULT \"freedb.freedb.org\", + INDEX STATION_IDX (STATION,INSTANCE) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON RDLIBRARY TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create TRIGGERS table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS TRIGGERS ( + ID INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, + CUT_NAME CHAR(12), + TRIGGER_CODE INT UNSIGNED, + OFFSET INT UNSIGNED, + INDEX CUT_NAME_IDX (CUT_NAME) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON TRIGGERS TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create TTYS table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS TTYS ( + ID INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + PORT_ID INT UNSIGNED NOT NULL, + ACTIVE ENUM('N','Y') NOT NULL DEFAULT 'N', + STATION_NAME CHAR(64) NOT NULL, + PORT CHAR(20), + BAUD_RATE INT DEFAULT 9600, + DATA_BITS INT DEFAULT 8, + STOP_BITS INT DEFAULT 1, + PARITY INT DEFAULT 0, + TERMINATION INT DEFAULT 0, + INDEX STATION_NAME_IDX (STATION_NAME), + INDEX ACTIVE_IDX (ACTIVE), + INDEX PORT_ID_IDX (PORT_ID) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON TTYS TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create DECKS table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS DECKS ( + ID INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + STATION_NAME CHAR(64) NOT NULL, + CHANNEL INT UNSIGNED NOT NULL, + CARD_NUMBER INT DEFAULT -1, + STREAM_NUMBER INT DEFAULT -1, + PORT_NUMBER INT DEFAULT -1, + PORT_TYPE ENUM('A','D') DEFAULT 'A', + DEFAULT_FORMAT INT DEFAULT 0, + DEFAULT_CHANNELS INT DEFAULT 2, + DEFAULT_SAMPRATE INT DEFAULT 44100, + DEFAULT_BITRATE INT DEFAULT 0, + DEFAULT_THRESHOLD INT DEFAULT 0, + SWITCH_TYPE INT DEFAULT 0, + TTY_ID INT, + INDEX STATION_NAME_IDX (STATION_NAME), + INDEX CHANNEL_IDX (CHANNEL) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON DECKS TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create SOURCES table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS SOURCES ( + ID INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + STATION_NAME CHAR(64) NOT NULL, + CHANNEL INT UNSIGNED NOT NULL, + SOURCE_NAME CHAR(64) NOT NULL, + SERIAL_COMMAND CHAR(64), + GPO_LINE INT UNSIGNED, + INDEX STATION_NAME_IDX (STATION_NAME), + INDEX CHANNEL_IDX (CHANNEL), + INDEX SOURCE_NAME_IDX (SOURCE_NAME) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON SOURCES TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create RECORDINGS table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS RECORDINGS ( + ID INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + STATION_NAME CHAR(64) NOT NULL, + CHANNEL INT UNSIGNED NOT NULL, + CUT_NAME CHAR(12) NOT NULL, + SUN ENUM('N','Y') DEFAULT 'N', + MON ENUM('N','Y') DEFAULT 'N', + TUE ENUM('N','Y') DEFAULT 'N', + WED ENUM('N','Y') DEFAULT 'N', + THU ENUM('N','Y') DEFAULT 'N', + FRI ENUM('N','Y') DEFAULT 'N', + SAT ENUM('N','Y') DEFAULT 'N', + SOURCE_NAME CHAR(64), + DESCRIPTION CHAR(64), + START_TIME TIME, + LENGTH INT UNSIGNED, + START_GPI INT DEFAULT -1, + END_GPI INT DEFAULT -1, + TRIM_THRESHOLD INT UNSIGNED, + STARTDATE_OFFSET INT UNSIGNED DEFAULT 0, + ENDDATE_OFFSET INT UNSIGNED DEFAULT 0, + FORMAT INT DEFAULT 0, + CHANNELS INT DEFAULT 2, + SAMPRATE INT DEFAULT 44100, + BITRATE INT DEFAULT 0, + INDEX STATION_NAME_IDX (STATION_NAME), + INDEX CHANNEL_IDX (CHANNEL), + INDEX CUT_NAME_IDX (CUT_NAME), + INDEX SOURCE_NAME_IDX (SOURCE_NAME), + INDEX SUN_IDX (SUN), + INDEX MON_IDX (MON), + INDEX TUE_IDX (TUE), + INDEX WED_IDX (WED), + INDEX THU_IDX (THU), + INDEX FRI_IDX (FRI), + INDEX SAT_IDX (SAT) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON RECORDINGS TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create AUDIO_PORTS table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS AUDIO_PORTS ( + ID INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + STATION_NAME CHAR(64) NOT NULL, + CARD_NUMBER INT NOT NULL, + CLOCK_SOURCE INT DEFAULT 0, + INPUT_0_LEVEL INT DEFAULT 0, + INPUT_0_TYPE INT DEFAULT 0, + INPUT_1_LEVEL INT DEFAULT 0, + INPUT_1_TYPE INT DEFAULT 0, + INPUT_2_LEVEL INT DEFAULT 0, + INPUT_2_TYPE INT DEFAULT 0, + INPUT_3_LEVEL INT DEFAULT 0, + INPUT_3_TYPE INT DEFAULT 0, + INPUT_4_LEVEL INT DEFAULT 0, + INPUT_4_TYPE INT DEFAULT 0, + INPUT_5_LEVEL INT DEFAULT 0, + INPUT_5_TYPE INT DEFAULT 0, + INPUT_6_LEVEL INT DEFAULT 0, + INPUT_6_TYPE INT DEFAULT 0, + INPUT_7_LEVEL INT DEFAULT 0, + INPUT_7_TYPE INT DEFAULT 0, + OUTPUT_0_LEVEL INT DEFAULT 0, + OUTPUT_1_LEVEL INT DEFAULT 0, + OUTPUT_2_LEVEL INT DEFAULT 0, + OUTPUT_3_LEVEL INT DEFAULT 0, + OUTPUT_4_LEVEL INT DEFAULT 0, + OUTPUT_5_LEVEL INT DEFAULT 0, + OUTPUT_6_LEVEL INT DEFAULT 0, + OUTPUT_7_LEVEL INT DEFAULT 0, + INDEX STATION_NAME_IDX (STATION_NAME), + INDEX CARD_NUMBER_IDX (CARD_NUMBER) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON AUDIO_PORTS TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" + +# +# Create LOGS table +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS LOGS ( + NAME CHAR(64) NOT NULL PRIMARY KEY, + SERVICE CHAR(10) NOT NULL, + DESCRIPTION CHAR(64), + ORIGIN_USER CHAR(8) NOT NULL, + ORIGIN_DATETIME DATETIME NOT NULL, + START_DATE DATE NOT NULL, + END_DATE DATE NOT NULL, + INDEX SERVICE_IDX (SERVICE), + INDEX DESCRIPTION_IDX (DESCRIPTION), + INDEX ORIGIN_USER_IDX (ORIGIN_USER), + INDEX START_DATE_IDX (START_DATE), + INDEX END_DATE_IDX (END_DATE) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON LOGS TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" +} +# ############################################################################ + + +# ############################################################################ +# Initialize a Rivendell Database +# ############################################################################ +function InitDB { +# +# Create Default Admin Account +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO USERS (LOGIN_NAME,PASSWORD,FULL_NAME,DESCRIPTION,ADMIN_USERS_PRIV,ADMIN_CONFIG_PRIV) + VALUES (\"$RDA_LOGIN_NAME\",PASSWORD(\"$RDA_PASSWORD\"),\"$RDA_FULL_NAME\",\"$RDA_DESCRIPTION\",'Y','Y')" + +# +# Create Default User Account +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO USERS (LOGIN_NAME,PASSWORD,FULL_NAME,DESCRIPTION, + CREATE_CARTS_PRIV,DELETE_CARTS_PRIV,MODIFY_CARTS_PRIV, + EDIT_AUDIO_PRIV,ASSIGN_CART_PRIV,CREATE_LOG_PRIV, + DELETE_LOG_PRIV,PLAYOUT_LOG_PRIV,ARRANGE_LOG_PRIV, + ADDTO_LOG_PRIV,REMOVEFROM_LOG_PRIV,EDIT_CATCHES_PRIV) + VALUES (\"$USER_LOGIN_NAME\",PASSWORD(\"$USER_PASSWORD\"),\"$USER_FULL_NAME\",\"$USER_DESCRIPTION\", + 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')" + +# +# Create Default Workstation +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO STATIONS (NAME,DESCRIPTION,USER_NAME,DEFAULT_NAME) + VALUES (\"DEFAULT\",\"Default Workstation\", + \"$USER_LOGIN_NAME\",\"$USER_LOGIN_NAME\")" + +# +# Create Test Tone Cart +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO CART(TYPE,NUMBER,GROUP_NAME,TITLE,ARTIST,CUT_QUANTITY, + FORCED_LENGTH) + VALUES (1,999999,\"TEST\",\"Test Tone\",\"Salem Radio Labs\",1,10000)" + +# +# Create Default Audio Cut +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO CUTS SET CUT_NAME=\"999999_000\",CART_NUMBER=999999, + DESCRIPTION=\"1 kHz at Reference Level [-16 dBFS]\", + OUTCUE=\"[tone]\",CODING_FORMAT=0, + SAMPLE_RATE=44100,BIT_RATE=0, + CHANNELS=2,LENGTH=10000,START_POINT=0,END_POINT=10000, + ORIGIN_DATETIME=NOW(),ORIGIN_NAME=\"RDGen\"" + +# +# Create Clipboard Entry +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO CLIPBOARD SET CUT_NAME=\"clip\",CART_NUMBER=0, + DESCRIPTION=\"Default Clipboard\"" + +# +# Create Default Service +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO SERVICES (NAME,DESCRIPTION) + VALUES (\"$RD_SVC_NAME\",\"$RD_SVC_DESC\")" + +# +# Create Default Groups +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO GROUPS (NAME,DESCRIPTION) + VALUES (\"TEMP\",\"Temporary Carts\")" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO GROUPS (NAME,DESCRIPTION) + VALUES (\"TEST\",\"Test Carts\")" + +# +# Create Default Audio Permissions +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO AUDIO_PERMS (GROUP_NAME,SERVICE_NAME) + VALUES (\"TEMP\",\"Production\")" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO AUDIO_PERMS (GROUP_NAME,SERVICE_NAME) + VALUES (\"TEST\",\"Production\")" + +# +# Create Default Library Configuration +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO RDLIBRARY (STATION,INSTANCE) + VALUES (\"0.0.0.0|0.0.0.0:0\",0)" + +# +# Create Sample Log +# +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + CREATE TABLE IF NOT EXISTS SAMPLE_LOG ( + ID INT NOT NULL PRIMARY KEY, + COUNT INT NOT NULL, + START_TIME TIME NOT NULL, + CART_NUMBER INT UNSIGNED NOT NULL, + TIME_TYPE INT NOT NULL, + TRANS_TYPE INT NOT NULL, + START_POINT INT NOT NULL DEFAULT -1, + END_POINT INT NOT NULL DEFAULT -1, + SEGUE_START_POINT INT NOT NULL DEFAULT -1, + SEGUE_END_POINT INT NOT NULL DEFAULT -1, + INDEX COUNT_IDX (COUNT), + INDEX CART_NUMBER_IDX (CART_NUMBER), + INDEX START_TIME_IDX (START_TIME) +)" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + GRANT ALL ON SAMPLE_LOG TO $RD_USER IDENTIFIED BY \"$RD_PASSWORD\"" +mysql -u $USER -p$PASSWORD -e"USE Rivendell; + INSERT INTO LOGS (NAME,SERVICE,DESCRIPTION,ORIGIN_USER,ORIGIN_DATETIME) + VALUES (\"SAMPLE\",\"Production\",\"Sample Log\",\"user\",NOW())" +} + +# ############################################################################ + + +# ############################################################################ +# Generate Default Audio +# ############################################################################ +function GenerateAudio { +if [ -d $RD_AUDIO_ROOT ] ; then + echo -n +else + mkdir $RD_AUDIO_ROOT +fi +rdgen -t 10 -l 16 $RD_AUDIO_ROOT/999999_000.wav +chown -R $SHELL_NAME: $RD_AUDIO_ROOT +} +# ############################################################################ + + +# ############################################################################ +# Upgrade a Rivendell Database +# ############################################################################ +function UpgradeDB { +# +# Create the temporary database +# +mysql -u $USER -p$PASSWORD -e"CREATE DATABASE IF NOT EXISTS Rivendell_TEMP" + +# +# Dump primary database to temporary +# +mysqldump -u $USER -p$PASSWORD --opt Rivendell \ +| mysql -u $USER -p$PASSWORD -C Rivendell_TEMP + +# +# Delete the primary database +# +mysql -u $USER -p$PASSWORD -e"DROP DATABASE Rivendell" + +# +# Create Upgraded Rivendell Database +# +CreateDB + +# +# Restore Data from temporary Database +# +mysqldump -u $USER -p$PASSWORD --opt Rivendell_TEMP \ +| mysql -u $USER -p$PASSWORD -C Rivendell + +# +# Delete the temporary database +# +mysql -u $USER -p$PASSWORD -e"DROP DATABASE Rivendell_TEMP" +} +# ############################################################################ + + +# ############################################################################ +# Main Routine +# ############################################################################ +# +# Get the mySQL Administrator Login +# +read -p "mySQL account with Admin access []: " USER +if [ -z $USER ] ; then + echo "You must supply a mySQL administrator account name!" + exit 1 +fi +read -s -p "mySQL Password: " PASSWORD +echo + +# +# Get the shell account user and group names +# +read -p "User account name that will be running Rivendell []: " SHELL_NAME +echo +if [ -z $SHELL_NAME ] ; then + echo "You must supply a valid user account name!" + echo + exit 1 +fi + +# +# Check that mySQL is running and accessible +# +mysql -s -u $USER -p$PASSWORD -e"use mysql" 2> /dev/null +if [ $? -ne 0 ] ; then + echo + echo "*** Unable to connect to the mySQL server. ***" + echo "It's possible that the server is not currently running, or that" + echo "the name/password you've supplied are not correct. Please" + echo "correct the problem and try again." + echo + exit 1 +fi + +# +# Check for an existing Rivendell database +# +mysql -s -u $USER -p$PASSWORD -e"use Rivendell" 2> /dev/null +if [ $? -eq 0 ] ; then + echo + echo "*** A Rivendell database already exists! ***" + echo "You can:" + echo " 1) Overwrite it and create a new one." + echo " [WARNING: overwriting the database will COMPLETELY DESTROY" + echo " any existing data and audio!]" + echo + echo " 2) Upgrade the existing database." + echo + echo " 3) Exit this utility." + echo + read -p "Your choice [3]: " OVERWRITE + echo + case "$OVERWRITE" in + "1") + echo -n "Deleting old Rivendell database..." + mysql -s -u $USER -p$PASSWORD -e"drop database Rivendell" + echo "done." + echo -n "Deleting old audio data..." + rm $RD_AUDIO_ROOT/* + echo "done." + echo -n "Creating new Rivendell database..." + CreateDB + echo "done." + echo -n "Initializing new Rivendell database..." + InitDB + echo "done." + echo -n "Generating new audio data..." + GenerateAudio + echo "done." + echo + exit 0 + ;; + + "2") + echo -n "Upgrading Rivendell database..." + UpgradeDB + echo "done." + echo + exit 0 + ;; + + "3" | "") + echo "Database NOT overwritten or upgraded." + echo + exit 0 + ;; + esac +fi +# ############################################################################ + +# End of rd_create_db + + + diff --git a/scripts/rd_memmon.sh b/scripts/rd_memmon.sh new file mode 100755 index 00000000..2275529b --- /dev/null +++ b/scripts/rd_memmon.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +# rd_memmon.sh +# +# Display a top session showing Rivendell components +# +# (C) Copyright 2010 Fred Gleason +# +# $Id: rd_memmon.sh,v 1.2 2010/10/06 20:40:47 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +RIPCD_PID=`cat /var/run/rivendell/ripcd.pid` +CAED_PID=`cat /var/run/rivendell/caed.pid` +RDCATCHD_PID=`cat /var/run/rivendell/rdcatchd.pid` + +if [ -z $1 ] ; then + top -p $RIPCD_PID,$CAED_PID,$RDCATCHD_PID +else + MODULE_PID=`ps -C $1 -o pid=` + top -p $RIPCD_PID,$CAED_PID,$RDCATCHD_PID,$MODULE_PID +fi + + +# End of rd_memmon.sh diff --git a/scripts/rd_mysql_enable_host.sh b/scripts/rd_mysql_enable_host.sh new file mode 100755 index 00000000..273343a0 --- /dev/null +++ b/scripts/rd_mysql_enable_host.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# +# rd_mysql_enable_host +# +# Enable a remote host in MySQL +# +# (C) Copyright 2011 Fred Gleason +# +# $Id: rd_mysql_enable_host.sh,v 1.1 2011/05/11 21:52:57 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# Usage: +# rd_mysql_enable_host +# + +# +# Site Defines +# +MYSQL=/usr/bin/mysql +MYSQL_ROOT_USER=root +MYSQL_ROOT_PASSWORD= +MYSQL_HOSTNAME=127.0.0.1 +MYSQL_RIVENDELL_USER=rduser +MYSQL_RIVENDELL_PASSWORD=letmein +MYSQL_DBNAME=Rivendell + +if [ -z $1 ] ; then + echo "rd_mysql_enable_host " + exit 256 +fi + +if [ $MYSQL_ROOT_PASSWORD ] ; then + MYSQL_PASSWORD_CMD=-p$MYSQL_ROOT_PASSWORD +fi + +echo "insert into user set Host=\"$1\",User=\"$MYSQL_RIVENDELL_USER\",Password=password(\"$MYSQL_RIVENDELL_PASSWORD\")" | $MYSQL -h $MYSQL_HOSTNAME -u $MYSQL_ROOT_USER $MYSQL_PASSWORD_CMD mysql + +echo "insert into db set Host=\"$1\",Db=\"Rivendell\",User=\"$MYSQL_RIVENDELL_USER\",Select_priv=\"Y\",Insert_priv=\"Y\",Update_priv=\"Y\",Delete_priv=\"Y\",Create_priv=\"Y\",Drop_priv=\"Y\",References_priv=\"Y\",Index_priv=\"Y\",Alter_priv=\"Y\",Create_tmp_table_priv=\"Y\",Lock_tables_priv=\"Y\",Create_view_priv=\"Y\",Show_view_priv=\"Y\",Create_routine_priv=\"Y\",Alter_routine_priv=\"Y\",Execute_priv=\"Y\"" | $MYSQL -h $MYSQL_HOSTNAME -u $MYSQL_ROOT_USER $MYSQL_PASSWORD_CMD mysql + +echo "flush privileges" | $MYSQL -h $MYSQL_HOSTNAME -u $MYSQL_ROOT_USER $MYSQL_PASSWORD_CMD mysql diff --git a/scripts/rd_restore_system.sh b/scripts/rd_restore_system.sh new file mode 100755 index 00000000..fd5c1e19 --- /dev/null +++ b/scripts/rd_restore_system.sh @@ -0,0 +1,100 @@ +#! /bin/bash + +# rd_restore_system.sh +# +# Restore a complete Rivendell setup from removable media. +# +# (C) Copyright 2011 Fred Gleason +# +# $Id: rd_restore_system.sh,v 1.2 2011/05/23 11:22:48 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# This script is intended for use as a starting point for a site-specific +# backup routine. Administrators are strongly encouraged to customize it +# for their envirnment! +# + +# +# Site Configuration +# +MYSQL_USERNAME=rduser +MYSQL_PASSWORD=letmein +MYSQL_HOSTNAME=127.0.0.1 +MYSQL_DBNAME=Rivendell +BACKUP_DEVICE=/dev/sdb1 +BACKUP_MOUNT_POINT=/media/rdbackup + +function Continue { + read -a RESP -p "Continue (y/N) " + echo + if [ -z $RESP ] ; then + exit 0 + fi + if [ $RESP != "y" -a $RESP != "Y" ] ; then + exit 0 + fi +} + +# +# Warning Messages +# +echo "This process will restore the Rivendell system from external media." +echo +echo "WARNING: This will COMPLETELY OVERWRITE the data on the Rivendell system!" +echo +Continue + +echo "Please verify that the external drive is connected before continuing." +echo +Continue + +# +# Setup environment +# +echo -n "Preparing backup device..." +sleep 5 +mkdir -p $BACKUP_MOUNT_POINT +mount $BACKUP_DEVICE $BACKUP_MOUNT_POINT +mkdir -p $BACKUP_MOUNT_POINT/ +echo "done." + + +# +# Restore Database +# +echo -n "Restoring database..." +echo "drop database $MYSQL_DBNAME" | mysql -h $MYSQL_HOSTNAME -u $MYSQL_USERNAME -p$MYSQL_PASSWORD +echo "create database $MYSQL_DBNAME" | mysql -h $MYSQL_HOSTNAME -u $MYSQL_USERNAME -p$MYSQL_PASSWORD +cat $BACKUP_MOUNT_POINT/db.sql | mysql -h $MYSQL_HOSTNAME -u $MYSQL_USERNAME -p$MYSQL_PASSWORD $MYSQL_DBNAME +echo "done." + +# +# Restore Audio +# +echo -n "Restoring audio..." +rsync -av --delete $BACKUP_MOUNT_POINT/snd/ /var/snd +echo "done." + +# +# Clean Up +# +umount $BACKUP_MOUNT_POINT +rmdir $BACKUP_MOUNT_POINT +/etc/init.d/rivendell restart +echo +echo "Restore complete!" +echo + +exit 0 diff --git a/scripts/rdmemcheck.sh b/scripts/rdmemcheck.sh new file mode 100755 index 00000000..c0fb33cc --- /dev/null +++ b/scripts/rdmemcheck.sh @@ -0,0 +1,80 @@ +#!/bin/sh + +# rdmemcheck.sh +# +# Script for monitoring Rivendell memory usage. +# +# (C) Copyright 2010 Fred Gleason +# +# $Id: rdmemcheck.sh,v 1.1 2010/12/21 17:28:43 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +USAGE="rdmemcheck.sh " + +if [ -z $1 ] ; then + echo $USAGE + exit 256; +fi +MODULE=$1 + +# +# Datestamp +# +echo `date +"%m-%d-%Y %H:%M:%S"` $LOGFILE + +# +# Module +# +echo -n "$MODULE -" $LOGFILE +echo -n " vsz:" +echo -n `ps --no-headers -C $MODULE -o vsz` +echo -n " rss:" +echo -n `ps --no-headers -C $MODULE -o rss` +echo + +# +# rdcatchd(8) +# +echo -n "rdcatchd -" $LOGFILE +echo -n " vsz:" +echo -n `ps --no-headers -C rdcatchd -o vsz` +echo -n " rss:" +echo -n `ps --no-headers -C rdcatchd -o rss` +echo + +# +# ripcd(8) +# +echo -n "ripcd -" $LOGFILE +echo -n " vsz:" +echo -n `ps --no-headers -C ripcd -o vsz` +echo -n " rss:" +echo -n `ps --no-headers -C ripcd -o rss` +echo + +# +# caed(8) +# +echo -n "caed -" $LOGFILE +echo -n " vsz:" +echo -n `ps --no-headers -C caed -o vsz` +echo -n " rss:" +echo -n `ps --no-headers -C caed -o rss` +echo + +echo + +#echo $MODULE: $PID diff --git a/scripts/sage_endec_rwt.sh b/scripts/sage_endec_rwt.sh new file mode 100755 index 00000000..dc322bdd --- /dev/null +++ b/scripts/sage_endec_rwt.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +# sage_endec_rwt.sh +# +# Run a Required Weekly Test on a Sage Digital ENDEC +# +# (C) Copyright 2012 Fred Gleason +# +# $Id: sage_endec_rwt.sh,v 1.1.2.1 2012/10/11 19:16:27 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# + +USAGE="sage_endec_rwt.sh " + +if [ -z $1 ] ; then + echo $USAGE + exit 256 +fi +if [ -z $2 ] ; then + echo $USAGE + exit 256 +fi +if [ -z $3 ] ; then + echo $USAGE + exit 256 +fi + +HOSTNAME=$1 +USERNAME=$2 +PASSWORD=$3 + +curl --anyauth --user $USERNAME:$PASSWORD --data rwt=1\&handle=1 http://$HOSTNAME/cgi-bin/pend.cgi + +# End of sage_endec_rwt.sh diff --git a/scripts/start-rdmonitor.sh b/scripts/start-rdmonitor.sh new file mode 100755 index 00000000..8205a2b8 --- /dev/null +++ b/scripts/start-rdmonitor.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +## start-rdmonitor.sh +## +## Start the Rivendell RDMonitor applet +## +## (C) Copyright 2012 Fred Gleason +## +## $Id: start-rdmonitor.sh,v 1.1.2.1 2012/10/20 00:24:46 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of version 2 of the GNU General Public License as +## published by the Free Software Foundation; +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place, Suite 330, +## Boston, MA 02111-1307 USA +## + +rdmonitor & \ No newline at end of file diff --git a/scripts/start_rd b/scripts/start_rd new file mode 100755 index 00000000..e671279e --- /dev/null +++ b/scripts/start_rd @@ -0,0 +1,36 @@ +# start_rd +# +# Start up the Rivendell system daemons +# +# (C) Copyright 2003 Fred Gleason +# +# $Id: start_rd,v 1.5 2007/02/14 21:59:12 fredg Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +BIN_PATH=/usr/local/bin + + +echo "Starting Rivendell daemons" + +# +# Start Rivendell Daemons +# +$BIN_PATH/caed +$BIN_PATH/ripcd +$BIN_PATH/rdcatchd + + +# End of start_rd diff --git a/scripts/start_traverso.sh b/scripts/start_traverso.sh new file mode 100755 index 00000000..a4df88f0 --- /dev/null +++ b/scripts/start_traverso.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +# start_traverso.sh +# +# Load an audio file into the traverso audio DAW using OSC. +# If traverso is not already running, it is first started. +# +# (C) Copyright 2008 Fred Gleason +# +# $Id: start_traverso.sh,v 1.3 2010/07/29 19:32:38 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +if [ -z $1 ] ; then + echo "start_traverso.sh " + exit 256 +fi + +PS_RESULT=`ps --no-header -C traverso -o fname` +if [ -z $PS_RESULT ] ; then + traverso > /dev/null 2> /dev/null & + sleep 2 +fi + +oscsend --path=/traverso/transport/insert_track --value=S:$1 + + +# End of start_traverso.sh diff --git a/slack-desc.in b/slack-desc.in new file mode 100644 index 00000000..dcbeacce --- /dev/null +++ b/slack-desc.in @@ -0,0 +1,19 @@ +# HOW TO EDIT THIS FILE: +# The "handy ruler" below makes it easier to edit a package description. Line +# up the first '|' above the ':' following the base package name, and the '|' +# on the right side marks the last column you can put a character in. You must +# make exactly 11 lines for the formatting to be correct. It's also +# customary to leave one space after the ':'. + + |-----handy-ruler------------------------------------------------------| +rivendell-@VERSION@-i586-@RPM_RELEASE@: rivendell (A Radio Broadcast Automation System) +rivendell-@VERSION@-i586-@RPM_RELEASE@: +rivendell-@VERSION@-i586-@RPM_RELEASE@: Rivendell aims to be a complete radio broadcast automation solution, with +rivendell-@VERSION@-i586-@RPM_RELEASE@: facilities for the acquisition, management, scheduling and playout of +rivendell-@VERSION@-i586-@RPM_RELEASE@: audio content. +rivendell-@VERSION@-i586-@RPM_RELEASE@: +rivendell-@VERSION@-i586-@RPM_RELEASE@: +rivendell-@VERSION@-i586-@RPM_RELEASE@: +rivendell-@VERSION@-i586-@RPM_RELEASE@: +rivendell-@VERSION@-i586-@RPM_RELEASE@: +rivendell-@VERSION@-i586-@RPM_RELEASE@: diff --git a/slack_doinst.sh b/slack_doinst.sh new file mode 100755 index 00000000..cdda4afc --- /dev/null +++ b/slack_doinst.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# +# slack_doinst.sh +# +# Libradio installation package script for Slackware +# +# Copyright 2002-2006 Fred Gleason +# +# $Id: slack_doinst.sh,v 1.3 2007/02/14 21:48:41 fredg Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +/sbin/ldconfig + + +# End of slack_doinst.sh + diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 00000000..c0de7401 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,94 @@ +## automake.am +## +## Automake.am for rivendell/tests +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.14.8.4.2.1 2014/05/30 00:26:30 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +noinst_PROGRAMS = audio_convert_test\ + audio_export_test\ + audio_import_test\ + datedecode_test\ + reserve_carts_test\ + sas_switch_torture\ + sas_torture\ + stringcode_test\ + test_pam\ + timer_test\ + upload_test + +dist_audio_convert_test_SOURCES = audio_convert_test.cpp audio_convert_test.h +audio_convert_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_audio_export_test_SOURCES = audio_export_test.cpp audio_export_test.h +audio_export_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_audio_import_test_SOURCES = audio_import_test.cpp audio_import_test.h +audio_import_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_datedecode_test_SOURCES = datedecode_test.cpp datedecode_test.h +datedecode_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_reserve_carts_test_SOURCES = reserve_carts_test.cpp reserve_carts_test.h +reserve_carts_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_sas_switch_torture_SOURCES = sas_switch_torture.cpp sas_switch_torture.h +nodist_sas_switch_torture_SOURCES = moc_sas_switch_torture.cpp +sas_switch_torture_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_sas_torture_SOURCES = sas_torture.cpp sas_torture.h +nodist_sas_torture_SOURCES = moc_sas_torture.cpp +sas_torture_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_stringcode_test_SOURCES = stringcode_test.cpp stringcode_test.h +stringcode_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_test_pam_SOURCES = test_pam.cpp test_pam.h +test_pam_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +dist_timer_test_SOURCES = timer_test.cpp timer_test.h +nodist_timer_test_SOURCES = moc_timer_test.cpp +timer_test_LDADD = -lqui + + +dist_upload_test_SOURCES = upload_test.cpp upload_test.h +upload_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rivendell_standard.txt\ + visualtraffic.txt + +CLEANFILES = *~\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/tests/audio_convert_test.cpp b/tests/audio_convert_test.cpp new file mode 100644 index 00000000..a353ea48 --- /dev/null +++ b/tests/audio_convert_test.cpp @@ -0,0 +1,202 @@ +// audio_convert_test.cpp +// +// Test the Rivendell file format converter. +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: audio_convert_test.cpp,v 1.3 2011/06/21 22:20:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include + +#include + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + unsigned schema=0; + + destination_settings=new RDSettings(); + start_point=-1; + end_point=-1; + speed_ratio=1.0; + bool ok=false; + RDAudioConvert::ErrorCode conv_err; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"audio_convert_test", + AUDIO_CONVERT_TEST_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--source-file") { + source_filename=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--destination-file") { + destination_filename=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--start-point") { + start_point=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_convert_test: invalid start point\n"); + exit(256); + } + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--end-point") { + end_point=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_convert_test: invalid end point\n"); + exit(256); + } + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--destination-format") { + RDSettings::Format format=(RDSettings::Format)cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_convert_test: invalid destination format\n"); + exit(256); + } + switch(format) { + case RDSettings::Pcm16: + case RDSettings::MpegL2: + case RDSettings::MpegL2Wav: + case RDSettings::MpegL3: + case RDSettings::Flac: + case RDSettings::OggVorbis: + destination_settings->setFormat(format); + cmd->setProcessed(i,true); + break; + + default: + fprintf(stderr,"audio_convert_test: invalid destination format\n"); + exit(256); + } + destination_settings->setFormat(format); + } + if(cmd->key(i)=="--destination-channels") { + unsigned channels=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_convert_test: invalid destination channels\n"); + exit(256); + } + destination_settings->setChannels(channels); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--destination-sample-rate") { + unsigned sample_rate=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_convert_test: invalid destination sample rate\n"); + exit(256); + } + destination_settings->setSampleRate(sample_rate); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--destination-bit-rate") { + unsigned bit_rate=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_convert_test: invalid destination bit rate\n"); + exit(256); + } + destination_settings->setBitRate(bit_rate); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--quality") { + unsigned quality=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_convert_test: invalid destination quality\n"); + exit(256); + } + destination_settings->setQuality(quality); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--normalization-level") { + int normalization_level=cmd->value(i).toInt(&ok); + if((!ok)||(normalization_level>0)) { + fprintf(stderr,"audio_convert_test: invalid normalization level\n"); + exit(256); + } + destination_settings->setNormalizationLevel(normalization_level); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--speed-ratio") { + speed_ratio=cmd->value(i).toFloat(&ok); + if((!ok)||(speed_ratio<=0)) { + fprintf(stderr,"audio_convert_test: invalid speed-ratio\n"); + exit(256); + } + cmd->setProcessed(i,true); + } + } + if(source_filename.isEmpty()) { + fprintf(stderr,"audio_convert_test: missing source-file\n"); + exit(256); + } + if(destination_filename.isEmpty()) { + fprintf(stderr,"audio_convert_test: missing destination-file\n"); + exit(256); + } + if((destination_settings->bitRate()!=0)&& + (destination_settings->quality()!=0)) { + fprintf(stderr,"audio_convert_test: --destination-bit-rate and --destination-quality are mutually exclusive\n"); + exit(256); + } + + // + // Read Configuration + // + rdconfig=new RDConfig(); + rdconfig->load(); + + // + // Open Database + // + QString err (tr("audio_convert_test: ")); + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + fprintf(stderr,err.ascii()); + delete cmd; + exit(256); + } + + RDAudioConvert *conv=new RDAudioConvert(rdconfig->stationName(),this); + conv->setSourceFile(source_filename); + conv->setDestinationFile(destination_filename); + conv->setDestinationSettings(destination_settings); + conv->setRange(start_point,end_point); + conv->setSpeedRatio(speed_ratio); + printf("Converting...\n"); + conv_err=conv->convert(); + printf("Result: %s\n",(const char *)RDAudioConvert::errorText(conv_err)); + delete conv; + + exit(0); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/tests/audio_convert_test.h b/tests/audio_convert_test.h new file mode 100644 index 00000000..6352ea9f --- /dev/null +++ b/tests/audio_convert_test.h @@ -0,0 +1,58 @@ +// audio_convert_test.h +// +// Test the Rivendell file format converter. +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: audio_convert_test.h,v 1.2 2010/07/29 19:32:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef AUDIO_CONVERT_TEST_H +#define AUDIO_CONVERT_TEST_H + +#include + +#include +#include + +#include +#include +#include + +#define AUDIO_CONVERT_TEST_USAGE "[options]\n\nTest the Rivendell audio converter routines\n\nOptions are:\n--source-file=\n\n--destination-file=\n\n--start-point=\n\n--end-point=\n\n--destination-format=\n Supported formats are:\n 0 - PCM16 WAV\n 2 - MPEG Layer 2\n 3 - MPEG Layer 3\n 4 - FLAC\n 5 - OggVorbis\n 6 - MPEG Layer 2 WAV\n\n--destination-channels=\n\n--destination-sample-rate=\n\n--destination-bit-rate=\n\n--destination-quality=\n\n--normalization-level=\n\n--speed-ratio=\n\n" + +// +// Global Variables +// +RDConfig *rdconfig; + + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + QString source_filename; + QString destination_filename; + int start_point; + int end_point; + float speed_ratio; + RDSettings *destination_settings; +}; + + +#endif // AUDIO_CONVERT_TEST_H diff --git a/tests/audio_export_test.cpp b/tests/audio_export_test.cpp new file mode 100644 index 00000000..ccd023f7 --- /dev/null +++ b/tests/audio_export_test.cpp @@ -0,0 +1,224 @@ +// audio_export_test.cpp +// +// Test the Rivendell file format exporter. +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: audio_export_test.cpp,v 1.5.4.1 2013/11/13 23:36:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include + +#include + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + username="user"; + password=""; + destination_settings=new RDSettings(); + cart_number=0; + cut_number=0; + start_point=-1; + end_point=-1; + bool ok=false; + RDAudioConvert::ErrorCode audio_conv_err; + RDAudioExport::ErrorCode conv_err; + unsigned schema=0; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"audio_export_test", + AUDIO_EXPORT_TEST_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--username") { + username=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--password") { + password=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--cart-number") { + cart_number=cmd->value(i).toUInt(&ok); + if((!ok)||(cart_number>999999)) { + fprintf(stderr,"audio_export_test: invalid cart number\n"); + exit(256); + } + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--cut-number") { + cut_number=cmd->value(i).toUInt(&ok); + if((!ok)||(cut_number>999)) { + fprintf(stderr,"audio_export_test: invalid cut number\n"); + exit(256); + } + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--destination-file") { + destination_filename=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--start-point") { + start_point=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_export_test: invalid start point\n"); + exit(256); + } + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--end-point") { + end_point=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_export_test: invalid end point\n"); + exit(256); + } + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--destination-format") { + RDSettings::Format format=(RDSettings::Format)cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_export_test: invalid destination format\n"); + exit(256); + } + switch(format) { + case RDSettings::Pcm16: + case RDSettings::MpegL2: + case RDSettings::MpegL2Wav: + case RDSettings::MpegL3: + case RDSettings::Flac: + case RDSettings::OggVorbis: + destination_settings->setFormat(format); + cmd->setProcessed(i,true); + break; + + default: + fprintf(stderr,"audio_export_test: invalid destination format\n"); + exit(256); + } + destination_settings->setFormat(format); + } + if(cmd->key(i)=="--destination-channels") { + unsigned channels=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_export_test: invalid destination channels\n"); + exit(256); + } + destination_settings->setChannels(channels); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--destination-sample-rate") { + unsigned sample_rate=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_export_test: invalid destination sample rate\n"); + exit(256); + } + destination_settings->setSampleRate(sample_rate); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--destination-bit-rate") { + unsigned bit_rate=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_export_test: invalid destination bit rate\n"); + exit(256); + } + destination_settings->setBitRate(bit_rate); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--quality") { + unsigned quality=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_export_test: invalid destination quality\n"); + exit(256); + } + destination_settings->setQuality(quality); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--normalization-level") { + int normalization_level=cmd->value(i).toInt(&ok); + if((!ok)||(normalization_level>0)) { + fprintf(stderr,"audio_export_test: invalid normalization level\n"); + exit(256); + } + destination_settings->setNormalizationLevel(normalization_level); + cmd->setProcessed(i,true); + } + } + if(cart_number==0) { + fprintf(stderr,"audio_export_test: missing cart-number\n"); + exit(256); + } + if(cut_number==0) { + fprintf(stderr,"audio_export_test: missing cut-number\n"); + exit(256); + } + if(destination_filename.isEmpty()) { + fprintf(stderr,"audio_export_test: missing destination-file\n"); + exit(256); + } + if((destination_settings->bitRate()!=0)&& + (destination_settings->quality()!=0)) { + fprintf(stderr,"audio_export_test: --destination-bit-rate and --destination-quality are mutually exclusive\n"); + exit(256); + } + + // + // Read Configuration + // + rdconfig=new RDConfig(); + rdconfig->load(); + + // + // Open Database + // + QString err (tr("audio_export_test: ")); + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + fprintf(stderr,err.ascii()); + delete cmd; + exit(256); + } + + RDStation *station=new RDStation(rdconfig->stationName()); + RDAudioExport *conv=new RDAudioExport(station,rdconfig,this); + conv->setCartNumber(cart_number); + conv->setCutNumber(cut_number); + conv->setDestinationFile(destination_filename); + conv->setDestinationSettings(destination_settings); + conv->setRange(start_point,end_point); + printf("Exporting...\n"); + conv_err=conv->runExport(username,password,&audio_conv_err); + printf("Result: %s\n", + (const char *)RDAudioExport::errorText(conv_err,audio_conv_err)); + delete conv; + + exit(0); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/tests/audio_export_test.h b/tests/audio_export_test.h new file mode 100644 index 00000000..3b4c8686 --- /dev/null +++ b/tests/audio_export_test.h @@ -0,0 +1,60 @@ +// audio_export_test.h +// +// Test the Rivendell file format converter. +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: audio_export_test.h,v 1.2 2010/07/29 19:32:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef AUDIO_EXPORT_TEST_H +#define AUDIO_EXPORT_TEST_H + +#include + +#include +#include + +#include +#include +#include + +#define AUDIO_EXPORT_TEST_USAGE "[options]\n\nTest the Rivendell audio exporter routines\n\nOptions are:\n--username=\n\n--password=\n\n--cart-number=\n\n--cut-number=\n\n--destination-file=\n\n--start-point=\n\n--end-point=\n\n--destination-format=\n Supported formats are:\n 0 - PCM16 WAV\n 2 - MPEG Layer 2\n 3 - MPEG Layer 3\n 4 - FLAC\n 5 - OggVorbis\n 6 - MPEG Layer 2 WAV\n\n--destination-channels=\n\n--destination-sample-rate=\n\n--destination-bit-rate=\n\n--destination-quality=\n\n--normalization-level=\n\n" + +// +// Global Variables +// +RDConfig *rdconfig; + + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + QString username; + QString password; + unsigned cart_number; + unsigned cut_number; + QString destination_filename; + int start_point; + int end_point; + RDSettings *destination_settings; +}; + + +#endif // AUDIO_EXPORT_TEST_H diff --git a/tests/audio_import_test.cpp b/tests/audio_import_test.cpp new file mode 100644 index 00000000..f5ae7c67 --- /dev/null +++ b/tests/audio_import_test.cpp @@ -0,0 +1,164 @@ +// audio_import_test.cpp +// +// Test Rivendell file importing. +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: audio_import_test.cpp,v 1.5.4.1 2013/11/13 23:36:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include + +#include + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + username="user"; + password=""; + destination_settings=new RDSettings(); + cart_number=0; + cut_number=0; + use_metadata=false; + bool ok=false; + RDAudioConvert::ErrorCode audio_conv_err; + RDAudioImport::ErrorCode conv_err; + unsigned schema=0; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"audio_import_test", + AUDIO_IMPORT_TEST_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--username") { + username=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--password") { + password=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--cart-number") { + cart_number=cmd->value(i).toUInt(&ok); + if((!ok)||(cart_number>999999)) { + fprintf(stderr,"audio_import_test: invalid cart number\n"); + exit(256); + } + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--cut-number") { + cut_number=cmd->value(i).toUInt(&ok); + if((!ok)||(cut_number>999)) { + fprintf(stderr,"audio_import_test: invalid cut number\n"); + exit(256); + } + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--source-file") { + source_filename=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--destination-channels") { + unsigned channels=cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"audio_import_test: invalid destination channels\n"); + exit(256); + } + destination_settings->setChannels(channels); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--normalization-level") { + int normalization_level=cmd->value(i).toInt(&ok); + if((!ok)||(normalization_level>0)) { + fprintf(stderr,"audio_import_test: invalid normalization level\n"); + exit(256); + } + destination_settings->setNormalizationLevel(normalization_level); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--autotrim-level") { + int autotrim_level=cmd->value(i).toInt(&ok); + if((!ok)||(autotrim_level>0)) { + fprintf(stderr,"audio_import_test: invalid autotrim level\n"); + exit(256); + } + destination_settings->setAutotrimLevel(autotrim_level); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--use-metadata") { + use_metadata=true; + cmd->setProcessed(i,true); + } + } + if(cart_number==0) { + fprintf(stderr,"audio_import_test: missing cart-number\n"); + exit(256); + } + if(cut_number==0) { + fprintf(stderr,"audio_import_test: missing cut-number\n"); + exit(256); + } + if(source_filename.isEmpty()) { + fprintf(stderr,"audio_import_test: missing source-file\n"); + exit(256); + } + + // + // Read Configuration + // + rdconfig=new RDConfig(); + rdconfig->load(); + + // + // Open Database + // + QString err (tr("audio_import_test: ")); + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + fprintf(stderr,err.ascii()); + delete cmd; + exit(256); + } + + RDStation *station=new RDStation(rdconfig->stationName()); + RDAudioImport *conv=new RDAudioImport(station,rdconfig,this); + conv->setCartNumber(cart_number); + conv->setCutNumber(cut_number); + conv->setSourceFile(source_filename); + conv->setDestinationSettings(destination_settings); + conv->setUseMetadata(use_metadata); + printf("Importing...\n"); + conv_err=conv->runImport(username,password,&audio_conv_err); + printf("Result: %s\n", + (const char *)RDAudioImport::errorText(conv_err,audio_conv_err)); + delete conv; + + exit(0); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/tests/audio_import_test.h b/tests/audio_import_test.h new file mode 100644 index 00000000..a209ccc0 --- /dev/null +++ b/tests/audio_import_test.h @@ -0,0 +1,59 @@ +// audio_import_test.h +// +// Test Rivendell file importing +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: audio_import_test.h,v 1.2 2010/07/29 19:32:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef AUDIO_IMPORT_TEST_H +#define AUDIO_IMPORT_TEST_H + +#include + +#include +#include + +#include +#include +#include + +#define AUDIO_IMPORT_TEST_USAGE "[options]\n\nTest the Rivendell audio importer routines\n\nOptions are:\n--username=\n\n--password=\n\n--cart-number=\n\n--cut-number=\n\n--source-file=\n\n--destination-channels=\n\n--normalization-level=\n\n--autotrim-level=\n\n--use-metadata\n\n" + +// +// Global Variables +// +RDConfig *rdconfig; + + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + QString username; + QString password; + unsigned cart_number; + unsigned cut_number; + QString source_filename; + RDSettings *destination_settings; + bool use_metadata; +}; + + +#endif // AUDIO_IMPORT_TEST_H diff --git a/tests/datedecode_test.cpp b/tests/datedecode_test.cpp new file mode 100644 index 00000000..bdc65181 --- /dev/null +++ b/tests/datedecode_test.cpp @@ -0,0 +1,91 @@ +// datedecode_test.cpp +// +// Test the Rivendell db connection routines. +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: datedecode_test.cpp,v 1.1.2.3 2013/10/16 21:14:37 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include + +#include +#include + +#include "datedecode_test.h" + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + QString date=""; + QString datetime=""; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"datedecode_test", + DATEDECODE_TEST_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--date") { + date=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--datetime") { + datetime=cmd->value(i); + cmd->setProcessed(i,true); + } + if(!cmd->processed(i)) { + fprintf(stderr,"datedecode_test: unknown option \"%s\"\n", + (const char *)cmd->value(i)); + exit(256); + } + } + if((!date.isEmpty())&&(!datetime.isEmpty())) { + fprintf(stderr, + "datedecode_test: --date and --datetime are mutually exclusive\n"); + exit(256); + } + if(date.isEmpty()&&datetime.isEmpty()) { + fprintf(stderr, + "datedecode_test: you must specify either --date or --datetime\n"); + exit(256); + } + + // + // Process Code + // + if(!date.isEmpty()) { + printf("%s\n", + (const char *)RDDateDecode(date,QDate::currentDate())); + } + if(!datetime.isEmpty()) { + printf("%s\n",(const char *)RDDateTimeDecode(datetime,QDateTime(QDate::currentDate(),QTime::currentTime()))); + } + exit(0); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/tests/datedecode_test.h b/tests/datedecode_test.h new file mode 100644 index 00000000..a3b3e145 --- /dev/null +++ b/tests/datedecode_test.h @@ -0,0 +1,37 @@ +// datedecode_test.h +// +// Test the Rivendell date decoder routines. +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: datedecode_test.h,v 1.1.2.2 2012/05/10 23:12:43 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef DATEDECODE_TEST_H +#define DATEDECODE_TEST_H + +#include + +#define DATEDECODE_TEST_USAGE "[options]\n\nTest the Rivendell date decoding routines\n\nOptions are:\n--date=\n Decode the string using RDDateDecode() and print the result\n on stdout.\n\n--datetime=\n Decode the string using RDDateTimeDecode() and print\n the result on stdout.\n\n" + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); +}; + + +#endif // DATEDECODE_TEST_H diff --git a/tests/reserve_carts_test.cpp b/tests/reserve_carts_test.cpp new file mode 100644 index 00000000..f97c2daf --- /dev/null +++ b/tests/reserve_carts_test.cpp @@ -0,0 +1,133 @@ +// reserve_carts_test.cpp +// +// Test the Rivendell db connection routines. +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: reserve_carts_test.cpp,v 1.1.2.1 2014/05/30 00:26:31 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include "reserve_carts_test.h" + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + RDConfig *config; + QString group_name; + unsigned quantity=0; + bool ok=false; + RDGroup *group=NULL; + std::vector cart_nums; + unsigned schema=0; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"reserve_carts_test", + RESERVE_CARTS_TEST_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--group") { + group_name=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--quantity") { + quantity=cmd->value(i).toUInt(&ok); + if(!ok) { + fprintf(stderr,"invalid --quantity specified\n"); + exit(256); + } + cmd->setProcessed(i,true); + } + if(!cmd->processed(i)) { + fprintf(stderr,"reserve_carts_test: unknown option \"%s\"\n", + (const char *)cmd->value(i)); + exit(256); + } + } + + // + // Sanity Checks + // + if(quantity<1) { + fprintf(stderr,"reserve_carts_test: you must reserve at least one cart\n"); + exit(256); + } + if(group_name.isEmpty()) { + fprintf(stderr,"you must specify a group\n"); + exit(256); + } + + // + // Load Configuration + // + config=new RDConfig(); + config->load(); + + // + // Open Database + // + QString err (tr("upload_test: ")); + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + fprintf(stderr,err.ascii()); + delete cmd; + exit(256); + } + + // + // Run the Test + // + group=new RDGroup(group_name); + if(!group->exists()) { + fprintf(stderr,"group \"%s\" does not exist\n", + (const char *)group_name.utf8()); + exit(256); + } + if(group->reserveCarts(&cart_nums,config->stationName(),RDCart::Audio, + quantity)) { + printf("reserved the following carts:\n"); + for(unsigned i=0;i +// +// $Id: reserve_carts_test.h,v 1.1.2.1 2014/05/30 00:26:31 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RESERVE_CARTS_TEST_H +#define RESERVE_CARTS_TEST_H + +#include + +#define RESERVE_CARTS_TEST_USAGE "[options]\n\nTest the Rivendell cart reservation routines\n\nOptions are:\n--group=\n Name of group to reserve carts in.\n\n--quantity=\n Number of carts to reserve.\n\n" + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); +}; + + +#endif // RESERVE_CARTS_TEST_H diff --git a/tests/rivendell_standard.txt b/tests/rivendell_standard.txt new file mode 100755 index 00000000..20777a6b --- /dev/null +++ b/tests/rivendell_standard.txt @@ -0,0 +1,5 @@ +11:32:14 999004 Short Cart 1 00:01:00 01234567890123456789012345678901 +11:32:29 010005 Luminiferous Ether 00:02:40 01234567890123456789012345678901 +11:51:07 999004 Short Cart 1 00:03:00 01234567890123456789012345678901 +11:51:22 010005 Luminiferous Ether 00:01:00 01234567890123456789012345678901 +11:52:17 999004 Short Cart 1 02:01:00 01234567890123456789012345678901 diff --git a/tests/sas_switch_torture.cpp b/tests/sas_switch_torture.cpp new file mode 100644 index 00000000..39d61af2 --- /dev/null +++ b/tests/sas_switch_torture.cpp @@ -0,0 +1,189 @@ +// sas_switch_torture.cpp +// +// A Qt-based application for playing Microsoft WAV files. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: sas_switch_torture.cpp,v 1.9 2011/06/21 22:20:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + unsigned schema=0; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont font("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Open Database + // + rd_config=new RDConfig(RD_CONF_FILE); + rd_config->load(); + + QString err; + test_db=RDInitDb(&schema,&err); + if(!test_db) { + QMessageBox::warning(this,"Can't Connect", + err,0,1,1); + exit(0); + } + // + // Generate Button + // + QPushButton *button=new QPushButton(this,"generate_button"); + button->setGeometry(10,10,sizeHint().width()-20,50); + button->setText("Generate Test"); + button->setFont(font); + connect(button,SIGNAL(clicked()),this,SLOT(generateData())); + + // + // Remove Button + // + button=new QPushButton(this,"remove_button"); + button->setGeometry(10,70,sizeHint().width()-20,50); + button->setText("Remove Test"); + button->setFont(font); + connect(button,SIGNAL(clicked()),this,SLOT(removeData())); + + // + // Exit Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(10,130,sizeHint().width()-20,50); + button->setText("Exit"); + button->setFont(font); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(200,190); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::generateData() +{ + QString sql; + RDSqlQuery *q; + QString rml; + QString desc; + + // + // Create Schedule + // + QTime time; + for(int i=0;i<86400000;i+=TIME_INTERVAL) { + for(int j=0;jquit(); +} + + +void MainWidget::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} + + diff --git a/tests/sas_switch_torture.h b/tests/sas_switch_torture.h new file mode 100644 index 00000000..937b74c3 --- /dev/null +++ b/tests/sas_switch_torture.h @@ -0,0 +1,63 @@ +// sas_switch_torture.h +// +// Generate Rivendell macro carts and scheduling for torture-testing +// an SAS router +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: sas_switch_torture.h,v 1.6 2010/07/29 19:32:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef SAS_SWITCH_TORTURE_H +#define SAS_SWITCH_TORTURE_H + +#include +#include + +#include + +#define SAS_INPUTS 32 +#define SAS_OUTPUTS 16 +#define SAS_STATION "hithlum" +#define SAS_MATRIX 1 +#define SAS_SLEEP 20 + +#define CART_START 10000 +#define TIME_INTERVAL 2000 + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void generateData(); + void removeData(); + void cancelData(); + void closeEvent(QCloseEvent *e); + + private: + QSqlDatabase *test_db; + QString test_filename; + RDConfig *rd_config; +}; + + +#endif // SAS_SWITCH_TORTURE_H diff --git a/tests/sas_torture.cpp b/tests/sas_torture.cpp new file mode 100644 index 00000000..81cd752a --- /dev/null +++ b/tests/sas_torture.cpp @@ -0,0 +1,200 @@ +// sas_torture.cpp +// +// A Qt-based application for playing Microsoft WAV files. +// +// (C) Copyright 2002 Fred Gleason +// +// $Id: sas_torture.cpp,v 1.10 2011/06/21 22:20:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + unsigned schema=0; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont font("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + + // + // Open Database + // + rd_config=new RDConfig(RD_CONF_FILE); + rd_config->load(); + QString err; + test_db=RDInitDb(&schema,&err); + if(!test_db) { + QMessageBox::warning(this,"Can't Connect", + err,0,1,1); + exit(0); + } + // + // Generate Button + // + QPushButton *button=new QPushButton(this,"generate_button"); + button->setGeometry(10,10,sizeHint().width()-20,50); + button->setText("Generate Test"); + button->setFont(font); + connect(button,SIGNAL(clicked()),this,SLOT(generateData())); + + // + // Remove Button + // + button=new QPushButton(this,"remove_button"); + button->setGeometry(10,70,sizeHint().width()-20,50); + button->setText("Remove Test"); + button->setFont(font); + connect(button,SIGNAL(clicked()),this,SLOT(removeData())); + + // + // Exit Button + // + button=new QPushButton(this,"cancel_button"); + button->setGeometry(10,130,sizeHint().width()-20,50); + button->setText("Exit"); + button->setFont(font); + connect(button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(200,190); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::generateData() +{ + QString sql; + RDSqlQuery *q; + QString rml; + QString desc; + + // + // Create Carts + // + for(int i=0;iquit(); +} + + +void MainWidget::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} + + diff --git a/tests/sas_torture.h b/tests/sas_torture.h new file mode 100644 index 00000000..c78a4baa --- /dev/null +++ b/tests/sas_torture.h @@ -0,0 +1,64 @@ +// sas_torture.h +// +// Generate Rivendell macro carts and scheduling for torture-testing +// an SAS router +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: sas_torture.h,v 1.8 2010/07/29 19:32:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef SAS_TORTURE_H +#define SAS_TORTURE_H + +#include +#include + +#include + +#define SAS_INPUTS 32 +#define SAS_OUTPUTS 16 +#define SAS_STATION "hithlum" +#define SAS_MATRIX 1 +#define SAS_SLEEP 20 + +#define CART_START 10000 +#define TIME_INTERVAL 20000 + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void generateData(); + void removeData(); + void cancelData(); + void closeEvent(QCloseEvent *e); + + private: + void LoadConfig(); + QSqlDatabase *test_db; + QString test_filename; + RDConfig *rd_config; +}; + + +#endif // SAS_TORTURE_H diff --git a/tests/stringcode_test.cpp b/tests/stringcode_test.cpp new file mode 100644 index 00000000..764e5183 --- /dev/null +++ b/tests/stringcode_test.cpp @@ -0,0 +1,113 @@ +// stringcode_test.cpp +// +// Test the Rivendell string encoder routines. +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: stringcode_test.cpp,v 1.1.2.1 2013/10/16 21:14:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include + +#include +#include + +#include "stringcode_test.h" + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + char teststr[1024]; + QString str; + bool xml_encode=false; + bool xml_decode=false; + bool url_encode=false; + bool url_decode=false; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"stringcode_test", + STRINGCODE_TEST_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--xml-encode") { + xml_encode=true; + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--xml-decode") { + xml_decode=true; + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--url-encode") { + url_encode=true; + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--url-decode") { + url_decode=true; + cmd->setProcessed(i,true); + } + if(!cmd->processed(i)) { + fprintf(stderr,"stringcode_test: unknown option \"%s\"\n", + (const char *)cmd->key(i)); + exit(256); + } + } + + if((!xml_encode)&&(!xml_decode)&&(!url_encode)&&(!url_decode)) { + fprintf(stderr,"stringcode_test: nothing to do!\n"); + exit(256); + } + + // + // Get string to test + // + printf("Enter string: "); + fflush(stdout); + if(fgets(teststr,1024,stdin)==NULL) { + teststr[0]=0; + } + str=QString(teststr).replace("\n",""); + + printf("Testing String: |%s|\n",(const char *)str); + if(xml_encode) { + printf(" RDXmlEscape: |%s|\n",(const char *)RDXmlEscape(str)); + } + if(xml_decode) { + printf(" RDXmlUnescape: |%s|\n",(const char *)RDXmlUnescape(str)); + } + if(url_encode) { + printf(" RDUrlEscape: |%s|\n",(const char *)RDUrlEscape(str)); + } + if(url_decode) { + printf(" RDUrlUnescape: |%s|\n",(const char *)RDUrlUnescape(str)); + } + printf("\n"); + + exit(0); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/tests/stringcode_test.h b/tests/stringcode_test.h new file mode 100644 index 00000000..751e0d48 --- /dev/null +++ b/tests/stringcode_test.h @@ -0,0 +1,37 @@ +// stringcode_test.h +// +// Test the Rivendell string encoder routines. +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: stringcode_test.h,v 1.1.2.1 2013/10/16 21:14:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef STRINGCODE_TEST_H +#define STRINGCODE_TEST_H + +#include + +#define STRINGCODE_TEST_USAGE "[options]\n\nTest the Rivendell string encoding routines in RDWeb\n\nOptions are:\n--xml-encode\n Encode using RDXmlEscape()\n\n--xml-decode\n Decode using RDXmlUnescape()\n\n--encode-url\n Encode using RDUrlEscape()\n\n--url-decode\n Decode using RDUrlUnescape()\n\n" + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); +}; + + +#endif // STRINGCODE_TEST_H diff --git a/tests/test_pam.cpp b/tests/test_pam.cpp new file mode 100644 index 00000000..a0c5ea48 --- /dev/null +++ b/tests/test_pam.cpp @@ -0,0 +1,120 @@ +// test_pam.cpp +// +// Test PAM Authentication Service +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: test_pam.cpp,v 1.2 2010/07/29 19:32:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include + +#include + +#include + +// +// NOTE: Since this is just a test harness, we make no attempt to +// free() the response data structures after using them! +// + +int ConversationResponseCallback(int num_msg,const struct pam_message **msg, + struct pam_response **resp, + void *appdata_ptr) +{ + int i; + char *pw; + + *resp=new struct pam_response[num_msg]; + for(i=0;iresp=new char[256]; + switch(msg[i]->msg_style) { + case PAM_PROMPT_ECHO_OFF: + pw=getpass(msg[i]->msg); + strncpy(resp[i]->resp,pw,256); + resp[i]->resp_retcode=0; + break; + + case PAM_PROMPT_ECHO_ON: + printf("%s ",msg[i]->msg); + fflush(NULL); + fgets(resp[i]->resp,256,stdin); + resp[i]->resp[strlen(resp[i]->resp)-1]=0; + resp[i]->resp_retcode=0; + break; + + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + printf("%s\n",msg[i]->msg); + break; + } + } + return 0; +} + + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + int err; + struct pam_conv conv; + pam_handle_t *pamh=NULL; + QString service_name=""; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"test_pam",TEST_PAM_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--service-name") { + service_name=cmd->value(i); + cmd->setProcessed(i,true); + } + } + if(service_name.isEmpty()) { + fprintf(stderr,"test_pam: missing service-name\n"); + exit(256); + } + + memset(&conv,0,sizeof(conv)); + conv.conv=ConversationResponseCallback; + if((err=pam_start(service_name,NULL,&conv,&pamh))!=PAM_SUCCESS) { + perror(pam_strerror(pamh,err)); + exit(256); + } + err=pam_authenticate(pamh,0); + if(err==PAM_SUCCESS) { + printf("Success!\n"); + } + else { + perror(pam_strerror(pamh,err)); + } + pam_end(pamh,err); + exit(0); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/tests/test_pam.h b/tests/test_pam.h new file mode 100644 index 00000000..241838de --- /dev/null +++ b/tests/test_pam.h @@ -0,0 +1,44 @@ +// test_pam.h +// +// Test PAM Authentication Service +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef TEST_PAM_H +#define TEST_PAM_H + +#include + +#include +#include + +#include +#include +#include + +#define TEST_PAM_USAGE "[options]\n\nTest a PAM-based authentication service\n\n--service-name=\n The name of the PAM service to test (as defined in /etc/pam.d/).\n\n" + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); +}; + + +#endif // TEST_PAM_H diff --git a/tests/timer_test.cpp b/tests/timer_test.cpp new file mode 100644 index 00000000..54509855 --- /dev/null +++ b/tests/timer_test.cpp @@ -0,0 +1,85 @@ +// timer_test.cpp +// +// Test QTimer Accuracy +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: timer_test.cpp,v 1.1.2.1 2013/02/07 18:22:06 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include + +MainObject::MainObject(QObject *parent,const char *name) + : QObject(parent,name) +{ + // + // Timer + // + test_timer=new QTimer(this); + connect(test_timer,SIGNAL(timeout()),this,SLOT(timeoutData())); + + // + // Start Run + // + test_interval=60000; + if(gettimeofday(&test_start_tv,NULL) !=0) { + perror("gettimeofday"); + } + test_timer->start(test_interval,true); +} + + +void MainObject::timeoutData() +{ + // + // Calculate Result + // + if(gettimeofday(&test_end_tv,NULL) !=0) { + perror("gettimeofday"); + } + double expected=(double)test_interval/1000.0; + double got=Time(&test_end_tv)-Time(&test_start_tv); + + printf("Expected: %12.3lf Got: %12.3lf Diff: %8.3lf%%\n", + expected,got,100.0*got/expected); + + // + // Start Next Run + // + test_interval*=2; + if(gettimeofday(&test_start_tv,NULL) !=0) { + perror("gettimeofday"); + } + test_timer->start(test_interval,true); +} + + +double MainObject::Time(struct timeval *tv) +{ + return (double)tv->tv_sec+(double)tv->tv_usec/1000000.0; +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/tests/timer_test.h b/tests/timer_test.h new file mode 100644 index 00000000..e89be4ef --- /dev/null +++ b/tests/timer_test.h @@ -0,0 +1,49 @@ +// timer_test.h +// +// Test QTimer Accuracy +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: timer_test.h,v 1.1.2.1 2013/02/07 18:22:06 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef TIMER_TEST_H +#define TIMER_TEST_H + +#include + +#include +#include + +class MainObject : public QObject +{ + Q_OBJECT; + public: + MainObject(QObject *parent=0,const char *name=0); + + private slots: + void timeoutData(); + + private: + double Time(struct timeval *tv); + QTimer *test_timer; + struct timeval test_start_tv; + struct timeval test_end_tv; + int test_interval; +}; + + +#endif // TIMER_TEST_H diff --git a/tests/upload_test.cpp b/tests/upload_test.cpp new file mode 100644 index 00000000..b4fefb93 --- /dev/null +++ b/tests/upload_test.cpp @@ -0,0 +1,106 @@ +// upload_test.cpp +// +// Test Rivendell file uploading. +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: upload_test.cpp,v 1.3 2011/06/21 22:20:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include + +#include + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + username=""; + password=""; + RDUpload::ErrorCode conv_err; + unsigned schema=0; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"upload_test", + UPLOAD_TEST_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--username") { + username=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--password") { + password=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--source-file") { + source_filename=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--destination-url") { + destination_url=cmd->value(i); + cmd->setProcessed(i,true); + } + } + if(source_filename.isEmpty()) { + fprintf(stderr,"upload_test: missing source-file\n"); + exit(256); + } + if(destination_url.isEmpty()) { + fprintf(stderr,"upload_test: missing destination-url\n"); + exit(256); + } + + // + // Read Configuration + // + rdconfig=new RDConfig(); + rdconfig->load(); + + // + // Open Database + // + QString err (tr("upload_test: ")); + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + fprintf(stderr,err.ascii()); + delete cmd; + exit(256); + } + + RDUpload *conv=new RDUpload(rdconfig->stationName(),this); + conv->setSourceFile(source_filename); + conv->setDestinationUrl(destination_url); + printf("Uploading...\n"); + conv_err=conv->runUpload(username,password,rdconfig->logXloadDebugData()); + printf("Result: %s\n",(const char *)RDUpload::errorText(conv_err)); + delete conv; + + exit(0); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/tests/upload_test.h b/tests/upload_test.h new file mode 100644 index 00000000..2416613e --- /dev/null +++ b/tests/upload_test.h @@ -0,0 +1,55 @@ +// upload_test.h +// +// Test Rivendell file uploading +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: upload_test.h,v 1.2 2010/07/29 19:32:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef UPLOAD_TEST_H +#define UPLOAD_TEST_H + +#include + +#include +#include + +#include +#include + +#define UPLOAD_TEST_USAGE "[options]\n\nTest the Rivendell upload routines\n\nOptions are:\n--username=\n\n--password=\n\n--source-file=\n\n--destination-url=\n\n" + +// +// Global Variables +// +RDConfig *rdconfig; + + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + QString username; + QString password; + QString source_filename; + QString destination_url; +}; + + +#endif // UPLOAD_TEST_H diff --git a/tests/visualtraffic.txt b/tests/visualtraffic.txt new file mode 100644 index 00000000..6654084d --- /dev/null +++ b/tests/visualtraffic.txt @@ -0,0 +1,6 @@ + |00:05:00|018585 |Wildfire Homework |Ad Council |0030 + |00:05:30|017417 |GEICO 9160 WIG |GLOBAL |0030 + |00:14:00|017668 |Swiss America |SFR |0060 + |00:15:00|018073 |GEICO 9644 CYCLE SAVER |GLOBAL |0030 + |00:15:01|017911 |Live United Mary |Ad Council |0030 + |00:15:02|018427 |GM 9385 BROKEN KNEES |GLOBAL |0060 diff --git a/utils/Makefile.am b/utils/Makefile.am new file mode 100644 index 00000000..8a1a4ebe --- /dev/null +++ b/utils/Makefile.am @@ -0,0 +1,75 @@ +## automake.am +## +## Automake.am for rivendell/utils +## +## (C) Copyright 2002-2005 Fred Gleason +## +## $Id: Makefile.am,v 1.54.8.6 2014/01/16 02:44:59 cvs Exp $ +## +## 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. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +if HPI_RD_AM + HPIINFO_RD_OPT = rdhpiinfo +endif +if ALSA_RD_AM + ALSACONFIG_RD_OPT = rdalsaconfig +endif +SUBDIRS = $(ALSACONFIG_RD_OPT)\ + $(HPIINFO_RD_OPT)\ + rddbcheck\ + rddgimport\ + rdcheckcuts\ + rdchunk\ + rdcollect\ + rddelete\ + rddiscimport\ + rdgen\ + rdgpimon\ + rdimport\ + rdmaint\ + rdmarkerset\ + rdpopup\ + rdpurgecasts\ + rmlsend\ + rdsoftkeys\ + sas_shim + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +EXTRA_DIST = utils.pro + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/utils/rdalsaconfig/Makefile.am b/utils/rdalsaconfig/Makefile.am new file mode 100644 index 00000000..eadfab70 --- /dev/null +++ b/utils/rdalsaconfig/Makefile.am @@ -0,0 +1,55 @@ +## automake.am +## +## Automake.am for utils/rdalsaconfig +## +## (C) Copyright 2009 Fred Gleason +## +## $Id: Makefile.am,v 1.2.8.1 2012/11/29 01:37:37 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in +## + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/rdhpi +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib -L$(top_srcdir)/rdhpi +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rdalsaconfig + +dist_rdalsaconfig_SOURCES = alsaitem.cpp alsaitem.h\ + rdalsa.cpp rdalsa.h\ + rdalsaconfig.cpp rdalsaconfig.h + +nodist_rdalsaconfig_SOURCES = moc_rdalsaconfig.cpp + +rdalsaconfig_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @LIBALSA@ + +EXTRA_DIST = rdalsaconfig.pro + +CLEANFILES = *~\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/utils/rdalsaconfig/alsaitem.cpp b/utils/rdalsaconfig/alsaitem.cpp new file mode 100644 index 00000000..141ae4ac --- /dev/null +++ b/utils/rdalsaconfig/alsaitem.cpp @@ -0,0 +1,68 @@ +// alsaitem.cpp +// +// QListBoxItem for ALSA PCM devices. +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: alsaitem.cpp,v 1.2 2010/07/29 19:32:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +AlsaItem::AlsaItem(QListBox *listbox,const QString &text) +: QListBoxText(listbox,text) +{ +} + + +AlsaItem::AlsaItem(const QString &text) + : QListBoxText(text) +{ + alsa_card=-1; + alsa_device=-1; +} + + +AlsaItem::AlsaItem(const AlsaItem &item) +{ + setText(item.text()); + setCard(item.card()); + setDevice(item.device()); +} + + +int AlsaItem::card() const +{ + return alsa_card; +} + + +void AlsaItem::setCard(int card) +{ + alsa_card=card; +} + + +int AlsaItem::device() const +{ + return alsa_device; +} + + +void AlsaItem::setDevice(int device) +{ + alsa_device=device; +} diff --git a/utils/rdalsaconfig/alsaitem.h b/utils/rdalsaconfig/alsaitem.h new file mode 100644 index 00000000..8b7e4a00 --- /dev/null +++ b/utils/rdalsaconfig/alsaitem.h @@ -0,0 +1,46 @@ +// alsaitem.h +// +// QListBoxItem for ALSA PCM devices. +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: alsaitem.h,v 1.2 2010/07/29 19:32:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef ALSAITEM_H +#define ALSAITEM_H + +#include + +class AlsaItem : public QListBoxText +{ + public: + AlsaItem(QListBox *listbox,const QString &text=QString::null); + AlsaItem(const QString &text=QString::null); + AlsaItem(const AlsaItem &item); + int card() const; + void setCard(int card); + int device() const; + void setDevice(int device); + + private: + int alsa_card; + int alsa_device; +}; + + +#endif // ALSAITEM_H diff --git a/utils/rdalsaconfig/rdalsa.cpp b/utils/rdalsaconfig/rdalsa.cpp new file mode 100644 index 00000000..23bd291c --- /dev/null +++ b/utils/rdalsaconfig/rdalsa.cpp @@ -0,0 +1,298 @@ +// rdalsa.cpp +// +// Abstract an ALSA configuration. +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: rdalsa.cpp,v 1.2 2010/07/29 19:32:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include + +#include + +RDAlsa::RDAlsa() +{ + clear(); +} + + +unsigned RDAlsa::cards() const +{ + return card_ids.size(); +} + + +QString RDAlsa::cardId(unsigned cardnum) const +{ + if(cardnum>=card_ids.size()) { + return QString("[invalid card]"); + } + return card_ids[cardnum]; +} + + +QString RDAlsa::cardDriver(unsigned cardnum) const +{ + if(cardnum>=card_drivers.size()) { + return QString("[invalid card]"); + } + return card_drivers[cardnum]; +} + + +QString RDAlsa::cardName(unsigned cardnum) const +{ + if(cardnum>=card_names.size()) { + return QString("[invalid card]"); + } + return card_names[cardnum]; +} + + +QString RDAlsa::cardLongName(unsigned cardnum) const +{ + if(cardnum>=card_long_names.size()) { + return QString("[invalid card]"); + } + return card_long_names[cardnum]; +} + + +QString RDAlsa::cardMixerName(unsigned cardnum) const +{ + if(cardnum>=card_mixer_names.size()) { + return QString("[invalid card]"); + } + return card_mixer_names[cardnum]; +} + + +int RDAlsa::pcmDevices(unsigned cardnum) const +{ + if(cardnum>=card_pcm_names.size()) { + return -1; + } + return card_pcm_names[cardnum].size(); +} + + +QString RDAlsa::pcmName(unsigned cardnum,unsigned pcm) const +{ + if(cardnum>=card_pcm_names.size()) { + return QString("[invalid pcm device]"); + } + if(pcm>=card_pcm_names[cardnum].size()) { + return QString("[invalid pcm device]"); + } + return card_pcm_names[cardnum][pcm]; +} + + +int RDAlsa::rivendellCard(int slot) const +{ + return card_rivendell_cards[slot]; +} + + +void RDAlsa::setRivendellCard(int slot,int cardnum) +{ + if(slot>=RD_MAX_CARDS) { + return; + } + card_rivendell_cards[slot]=cardnum; +} + + +int RDAlsa::rivendellDevice(int slot) const +{ + return card_rivendell_devices[slot]; +} + + +void RDAlsa::setRivendellDevice(int slot,int devnum) +{ + if(slot>=RD_MAX_CARDS) { + return; + } + card_rivendell_devices[slot]=devnum; +} + + +bool RDAlsa::load(const QString &filename) +{ + LoadSystemConfig(); + return LoadAsoundConfig(filename); +} + + +bool RDAlsa::save(const QString &filename) +{ + return SaveAsoundConfig(filename); +} + + +void RDAlsa::clear() +{ + card_ids.clear(); + card_drivers.clear(); + card_names.clear(); + card_long_names.clear(); + card_mixer_names.clear(); + card_pcm_names.clear(); + for(unsigned i=0;i=0) { + snd_ctl_card_info(snd_ctl,card_info); + card_ids.push_back(snd_ctl_card_info_get_id(card_info)); + card_drivers.push_back(snd_ctl_card_info_get_driver(card_info)); + card_names.push_back(snd_ctl_card_info_get_name(card_info)); + card_long_names.push_back(snd_ctl_card_info_get_longname(card_info)); + card_mixer_names.push_back(snd_ctl_card_info_get_mixername(card_info)); + std::vector pcms; + if(snd_ctl_pcm_info(snd_ctl,pcm_info)==0) { + pcm=0; + while(pcm>=0) { + pcms.push_back(QString().sprintf("%s [%u]", + (const char *)snd_pcm_info_get_name(pcm_info),pcm+1)); + snd_ctl_pcm_next_device(snd_ctl,&pcm); + } + } + card_pcm_names.push_back(pcms); + snd_ctl_close(snd_ctl); + card++; + } +} + + +bool RDAlsa::LoadAsoundConfig(const QString &filename) +{ + FILE *f=NULL; + char line[1024]; + int istate=0; + int port=0; + int card=0; + int device=0; + QStringList list; + + if((f=fopen(filename,"r"))==NULL) { + return false; + } + while(fgets(line,1024,f)!=NULL) { + QString str=line; + str.replace("\n",""); + if((str!=START_MARKER)&&(str!=END_MARKER)) { + switch(istate) { + case 0: + if(str.left(6)=="pcm.rd") { + port=str.mid(6,1).toInt(); + istate=1; + } + else { + if(str.left(6)=="ctl.rd") { + istate=10; + } + else { + card_other_lines.push_back(str+"\n"); + } + } + break; + + case 1: + list=list.split(" ",str); + if(list[0]=="}") { + if((port>=0)&&(port=0)&&(card_rivendell_devices[i]>=0)) { + fprintf(f,"pcm.rd%d {\n",i); + fprintf(f," type hw\n"); + fprintf(f," card %d\n",card_rivendell_cards[i]); + fprintf(f," device %d\n",card_rivendell_devices[i]); + fprintf(f,"}\n"); + fprintf(f,"ctl.rd%d {\n",i); + fprintf(f," type hw\n"); + fprintf(f," card %d\n",card_rivendell_cards[i]); + fprintf(f,"}\n"); + } + } + fprintf(f,"%s\n",END_MARKER); + + fclose(f); + return true; +} diff --git a/utils/rdalsaconfig/rdalsa.h b/utils/rdalsaconfig/rdalsa.h new file mode 100644 index 00000000..8285eed0 --- /dev/null +++ b/utils/rdalsaconfig/rdalsa.h @@ -0,0 +1,71 @@ +// rdalsa.h +// +// Abstract an ALSA configuration. +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: rdalsa.h,v 1.2 2010/07/29 19:32:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDALSA_H +#define RDALSA_H + +#include + +#include + +#include + +#define START_MARKER "# *** Start of Rivendell configuration generated by rdalsaconfig(1) ***" +#define END_MARKER "# *** End of Rivendell configuration generated by rdalsaconfig(1) ***" + +class RDAlsa +{ + public: + RDAlsa(); + unsigned cards() const; + QString cardId(unsigned cardnum) const; + QString cardDriver(unsigned cardnum) const; + QString cardName(unsigned cardnum) const; + QString cardLongName(unsigned cardnum) const; + QString cardMixerName(unsigned cardnum) const; + int pcmDevices(unsigned cardnum) const; + QString pcmName(unsigned cardnum,unsigned pcm) const; + int rivendellCard(int slot) const; + void setRivendellCard(int slot,int cardnum); + int rivendellDevice(int slot) const; + void setRivendellDevice(int slot,int devnum); + bool load(const QString &filename); + bool save(const QString &filename); + void clear(); + + private: + void LoadSystemConfig(); + bool LoadAsoundConfig(const QString &filename); + bool SaveAsoundConfig(const QString &filename); + std::vector card_ids; + std::vector card_drivers; + std::vector card_names; + std::vector card_long_names; + std::vector card_mixer_names; + std::vector > card_pcm_names; + int card_rivendell_cards[RD_MAX_CARDS]; + int card_rivendell_devices[RD_MAX_CARDS]; + QStringList card_other_lines; +}; + + +#endif // RDALSA_H diff --git a/utils/rdalsaconfig/rdalsaconfig.cpp b/utils/rdalsaconfig/rdalsaconfig.cpp new file mode 100644 index 00000000..a33515e0 --- /dev/null +++ b/utils/rdalsaconfig/rdalsaconfig.cpp @@ -0,0 +1,388 @@ +// rdalsaconfig.cpp +// +// A Qt-based application to display info about ALSA cards. +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: rdalsaconfig.cpp,v 1.2.8.3 2014/01/21 21:59:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +// +// Globals +// +QString alsa_filename; +bool alsa_autogen=false; +bool alsa_manage_daemons=false; +bool alsa_daemon_start_needed=false; + +void StopDaemons() +{ + if(alsa_manage_daemons) { + if(system("/etc/init.d/rivendell status")==0) { + system("/etc/init.d/rivendell stop"); + alsa_daemon_start_needed=true; + } + } +} + + +void StartDaemons() +{ + if(alsa_daemon_start_needed) { + system("/etc/init.d/rivendell start"); + } +} + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + setCaption(tr("RDAlsaConfig")+" v"+VERSION); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont font("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + QFont label_font("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + // + // Available Devices + // + alsa_system_list=new QListBox(this); + alsa_system_list->setFont(font); + alsa_system_label= + new QLabel(alsa_system_list,tr("Available Sound Devices"),this); + alsa_system_label->setFont(label_font); + alsa_system_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Up Button + // + alsa_up_button= + new RDTransportButton(RDTransportButton::Up,this,"alsa_up_button"); + connect(alsa_up_button,SIGNAL(clicked()),this,SLOT(upData())); + + // + // Down Button + // + alsa_down_button= + new RDTransportButton(RDTransportButton::Down,this,"alsa_down_button"); + connect(alsa_down_button,SIGNAL(clicked()),this,SLOT(downData())); + + // + // Selected Devices + // + alsa_config_list=new QListBox(this); + alsa_config_list->setFont(font); + alsa_config_label=new QLabel(alsa_config_list,tr("Active Sound Devices"),this); + alsa_config_label->setFont(label_font); + alsa_config_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Save Button + // + alsa_save_button=new QPushButton(tr("Save"),this); + alsa_save_button->setFont(label_font); + connect(alsa_save_button,SIGNAL(clicked()),this,SLOT(saveData())); + + // + // Cancel Button + // + alsa_cancel_button=new QPushButton(tr("Cancel"),this); + alsa_cancel_button->setFont(label_font); + connect(alsa_cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); + + // + // Load Available Devices and Configuration + // + alsa_alsa=new RDAlsa(); + alsa_alsa->load(alsa_filename); + LoadList(alsa_system_list,alsa_config_list); + + // + // Daemon Management + // + if(alsa_manage_daemons) { + if(geteuid()!=0) { + QMessageBox::warning(this,tr("RDAlsaConfig error"), + tr("The \"--manage-daemons\" switch requires root permissions.")); + exit(256); + } + if(system("/etc/init.d/rivendell status")==0) { + int r=QMessageBox::warning(this,tr("RDAlsaConfig warning"), + tr("Rivendell audio will be interrupted while running this program.\nContinue?"), + QMessageBox::Yes,QMessageBox::No); + if(r!=QMessageBox::Yes) { + exit(256); + } + } + } + StopDaemons(); +} + + +MainWidget::~MainWidget() +{ +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(400,300); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::upData() +{ + MoveItem(alsa_config_list,alsa_system_list); +} + + +void MainWidget::downData() +{ + if(alsa_config_list->count()>=RD_MAX_CARDS) { + return; + } + MoveItem(alsa_system_list,alsa_config_list); +} + + +void MainWidget::saveData() +{ + AlsaItem *item=NULL; + + for(int i=0;iitem(i))==NULL) { + alsa_alsa->setRivendellCard(i,-1); + alsa_alsa->setRivendellDevice(i,-1); + } + else { + alsa_alsa->setRivendellCard(i,item->card()); + alsa_alsa->setRivendellDevice(i,item->device()); + } + } + if(!alsa_alsa->save(alsa_filename)) { + QMessageBox::warning(this,tr("RDAlsaConfig error"), + tr(QString("Unable to save configuration to \"")+ + alsa_filename+"\"")); + return; + } + StartDaemons(); + qApp->quit(); +} + + +void MainWidget::cancelData() +{ + StartDaemons(); + qApp->quit(); +} + + +void MainWidget::resizeEvent(QResizeEvent *e) +{ + alsa_system_label->setGeometry(20,5,size().width()-20,20); + alsa_system_list-> + setGeometry(10,25,size().width()-20,(size().height()-120)/2); + alsa_up_button->setGeometry(size().width()-120,size().height()/2-28,50,30); + alsa_down_button->setGeometry(size().width()-60,size().height()/2-28,50,30); + alsa_config_label->setGeometry(20,size().height()/2-10,size().width()/2,20); + alsa_config_list->setGeometry(10,size().height()/2+10, + size().width()-20,(size().height()-120)/2); + alsa_save_button-> + setGeometry(size().width()-120,size().height()-40,50,30); + alsa_cancel_button-> + setGeometry(size().width()-60,size().height()-40,50,30); +} + + +void MainWidget::closeEvent(QCloseEvent *e) +{ + int r=QMessageBox::question(this,tr("RDAlsaConfig quit"), + tr("Save configuration before exiting?"), + QMessageBox::Yes,QMessageBox::No, + QMessageBox::Cancel); + switch(r) { + case QMessageBox::Yes: + saveData(); + break; + + case QMessageBox::No: + cancelData(); + break; + + default: + break; + } +} + + +void MainWidget::LoadList(QListBox *system,QListBox *config) +{ + for(unsigned i=0;icards();i++) { + for(int j=0;jpcmDevices(i);j++) { + if(PcmUnused(i,j)) { + AlsaItem *item= + new AlsaItem(alsa_alsa->cardLongName(i)+" - "+ + alsa_alsa->pcmName(i,j)); + item->setCard(i); + item->setDevice(j); + system->insertItem(item); + } + } + } + system->sort(); + + for(int i=0;irivendellCard(i)>=0) { + AlsaItem *item= + new AlsaItem(alsa_alsa->cardLongName(alsa_alsa->rivendellCard(i))+" - "+ + alsa_alsa->pcmName(alsa_alsa->rivendellCard(i), + alsa_alsa->rivendellDevice(i))); + item->setCard(alsa_alsa->rivendellCard(i)); + item->setDevice(alsa_alsa->rivendellDevice(i)); + config->insertItem(item); + } + } + config->sort(); +} + + +bool MainWidget::PcmUnused(int card,int device) +{ + for(int i=0;irivendellCard(i))&& + (device==alsa_alsa->rivendellDevice(i))) { + return false; + } + } + return true; +} + + +void MainWidget::MoveItem(QListBox *src,QListBox *dest) +{ + AlsaItem *item=(AlsaItem *)src->selectedItem(); + if(item==NULL) { + return; + } + dest->insertItem(new AlsaItem(*item)); // Force a deep copy + dest->sort(); + delete item; +} + + +Autogen::Autogen(QObject *parent,const char *name) +{ + StopDaemons(); + + // + // Load Available Devices + // + RDAlsa *alsa=new RDAlsa(); + alsa->load(alsa_filename); + + // + // Build Configuration + // + int slot=0; + for(unsigned i=0;icards();i++) { + for(int j=0;jpcmDevices(i);j++) { + alsa->setRivendellCard(slot,i); + alsa->setRivendellDevice(slot,j); + slot++; + } + } + + // + // Save Configuration + // + if(!alsa->save(alsa_filename)) { + exit(256); + } + + StartDaemons(); + + exit(0); +} + + +int main(int argc,char *argv[]) +{ + // + // Load the command-line arguments + // + alsa_filename=RD_ASOUNDRC_FILE; + RDCmdSwitch *cmd=new RDCmdSwitch(argc,argv,"rdalsaconfig", + RDALSACONFIG_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--asoundrc-file") { + alsa_filename=cmd->value(i); + } + if(cmd->key(i)=="--autogen") { + alsa_autogen=true; + } + if(cmd->key(i)=="--manage-daemons") { + alsa_manage_daemons=true; + } + } + + // + // Autogenerate a full configuration + // + if(alsa_autogen) { + QApplication a(argc,argv,false); + new Autogen(NULL,"main"); + return a.exec(); + } + + // + // Start GUI + // + QApplication a(argc,argv); + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} diff --git a/utils/rdalsaconfig/rdalsaconfig.h b/utils/rdalsaconfig/rdalsaconfig.h new file mode 100644 index 00000000..231128e4 --- /dev/null +++ b/utils/rdalsaconfig/rdalsaconfig.h @@ -0,0 +1,84 @@ +// rdalsaconfig.h +// +// A Qt-based application to display info about ALSA cards. +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: rdalsaconfig.h,v 1.3 2010/09/08 20:38:01 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDALSACONFIG_H +#define RDALSACONFIG_H + +#include +#include +#include + +#include + +#include +#include + +#define RDALSACONFIG_USAGE "[--asoundrc-file=] [--autogen] [--manage-daemons]\n\nGenerate an ALSA sound card configuration for Rivendell.\n\nThe following options are available:\n\n --asoundrc-file=\n Read and write configuration from (default value \n \"/etc/asound.conf\").\n\n --autogen\n Generate and save a configuration containing all available PCM devices\n and then exit.\n\n --manage-daemons\n Restart the Rivendell daemons as necessary to make configuration\n changes active (requires root permission).\n\n" + +void StopDaemons(); +void StartDaemons(); + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + ~MainWidget(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void upData(); + void downData(); + void saveData(); + void cancelData(); + + protected: + void resizeEvent(QResizeEvent *e); + void closeEvent(QCloseEvent *e); + + private: + void LoadList(QListBox *system,QListBox *config); + bool PcmUnused(int card,int device); + void MoveItem(QListBox *src,QListBox *dest); + QLabel *alsa_system_label; + QListBox *alsa_system_list; + QLabel *alsa_config_label; + QListBox *alsa_config_list; + RDTransportButton *alsa_up_button; + RDTransportButton *alsa_down_button; + QPushButton *alsa_save_button; + QPushButton *alsa_cancel_button; + RDAlsa *alsa_alsa; +}; + + +class Autogen : public QObject +{ + Q_OBJECT + public: + Autogen(QObject *parent=0,const char *name=0); +}; + + +#endif // RDALSACONFIG_H diff --git a/utils/rdalsaconfig/rdalsaconfig.pro b/utils/rdalsaconfig/rdalsaconfig.pro new file mode 100644 index 00000000..e69de29b diff --git a/utils/rdcheckcuts/Makefile.am b/utils/rdcheckcuts/Makefile.am new file mode 100644 index 00000000..c2bb51c6 --- /dev/null +++ b/utils/rdcheckcuts/Makefile.am @@ -0,0 +1,54 @@ +## automake.am +## +## Automake.am for rivendell/utils/rdcheckcuts +## +## (C) Copyright 2012 Fred Gleason +## +## $Id: Makefile.am,v 1.1.2.2 2012/11/29 01:37:37 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rdcheckcuts + +dist_rdcheckcuts_SOURCES = rdcheckcuts.cpp rdcheckcuts.h + +rdcheckcuts_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdcheckcuts.pro + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/utils/rdcheckcuts/rdcheckcuts.cpp b/utils/rdcheckcuts/rdcheckcuts.cpp new file mode 100644 index 00000000..e3c9173f --- /dev/null +++ b/utils/rdcheckcuts/rdcheckcuts.cpp @@ -0,0 +1,188 @@ +// rdcheckcuts.cpp +// +// Check Rivendell Cuts for Valid Audio +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: rdcheckcuts.cpp,v 1.1.2.3 2013/11/13 23:36:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +MainObject::MainObject(QObject *parent,const char *name) + : QObject(parent,name) +{ + std::vector group_names; + std::vector bad_cuts; + QString sql; + RDSqlQuery *q; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdcheckcuts",RDCHECKCUTS_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--group") { + group_names.push_back(cmd->value(i)); + cmd->setProcessed(i,true); + } + } + if(!cmd->allProcessed()) { + fprintf(stderr,"rdcheckcuts: unknown option\n"); + exit(256); + } + + // + // Open Configuration + // + cut_config=new RDConfig(); + cut_config->load(); + + // + // Open Database + // + if(!OpenDb()) { + fprintf(stderr,"rdcheckcuts: unable to open database\n"); + exit(256); + } + + // + // Build Group List + // + if(group_names.size()==0) { + sql="select NAME from GROUPS order by NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + group_names.push_back(q->value(0).toString()); + } + delete q; + } + + // + // Scan Cuts + // + for(unsigned i=0;icartNumber()); + + printf("Cut %03d [%s] in cart %06u [%s] is missing audio\n", + cut->cutNumber(), + (const char *)cut->description(), + cart->number(), + (const char *)cart->title()); + delete cart; + delete cut; +} + + +bool MainObject::ValidateGroup(const QString &groupname, + std::vector *cutnames) +{ + bool ret=true; + QString sql; + RDSqlQuery *q; + RDStation *station=new RDStation(cut_config->stationName()); + RDAudioInfo *info=new RDAudioInfo(station,cut_config); + RDAudioInfo::ErrorCode err_code; + + sql=QString("select CUTS.CUT_NAME,CUTS.CART_NUMBER,CUTS.LENGTH ")+ + "from CUTS left join CART on CUTS.CART_NUMBER=CART.NUMBER "+ + "where CART.GROUP_NAME=\""+groupname+"\" order by CART_NUMBER"; + q=new RDSqlQuery(sql); + while(q->next()) { + if(q->value(2).toInt()>0) { + info->setCartNumber(q->value(1).toUInt()); + info->setCutNumber(RDCut::cutNumber(q->value(0).toString())); + err_code=info->runInfo("user",""); + switch(err_code) { + case RDAudioInfo::ErrorOk: + break; + + case RDAudioInfo::ErrorNoAudio: + cutnames->push_back(q->value(0).toString()); + ret=false; + break; + + case RDAudioInfo::ErrorInternal: + case RDAudioInfo::ErrorUrlInvalid: + case RDAudioInfo::ErrorService: + case RDAudioInfo::ErrorInvalidUser: + ret=false; + break; + } + } + } + delete info; + delete station; + + return ret; +} + + +bool MainObject::OpenDb() +{ + unsigned schema=0; + + QString err(tr("rdcheckcuts: ")); + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + fprintf(stderr,err.ascii()); + return false; + } + return true; +} + + +void MainObject::CloseDb() +{ + QSqlDatabase::removeDatabase(cut_config->mysqlDbname()); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/utils/rdcheckcuts/rdcheckcuts.h b/utils/rdcheckcuts/rdcheckcuts.h new file mode 100644 index 00000000..768a7e43 --- /dev/null +++ b/utils/rdcheckcuts/rdcheckcuts.h @@ -0,0 +1,49 @@ +// rdcheckcuts.h +// +// Check Rivendell Cuts for Valid Audio +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: rdcheckcuts.h,v 1.1.2.1 2012/10/13 04:53:19 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDCHECKCUTS_H +#define RDCHECKCUTS_H + +#include + +#include + +#include + +#define RDCHECKCUTS_USAGE "[options]\n\nCheck Rivendell cuts for valid audio\n\n--group=\n Name of group to scan. This option may be given multiple times.\n If no group is specified, then ALL groups will be scanned.\n" + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + void RenderCut(const QString &cutname); + bool ValidateGroup(const QString &groupname,std::vector *cutnames); + bool OpenDb(); + void CloseDb(); + RDConfig *cut_config; +}; + + +#endif // RDCHECKCUTS_H diff --git a/utils/rdcheckcuts/rdcheckcuts.pro b/utils/rdcheckcuts/rdcheckcuts.pro new file mode 100644 index 00000000..e69de29b diff --git a/utils/rdchunk/Makefile.am b/utils/rdchunk/Makefile.am new file mode 100644 index 00000000..56868412 --- /dev/null +++ b/utils/rdchunk/Makefile.am @@ -0,0 +1,72 @@ +## automake.am +## +## Automake.am for rivendell/utils/rdchunk +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.5.8.1 2012/11/29 01:37:37 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdchunk_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rdchunk_*.qm + +all: + @QT_BIN@/lupdate rdchunk.pro + @QT_BIN@/lrelease rdchunk.pro + +bin_PROGRAMS = rdchunk + +dist_rdchunk_SOURCES = rdchunk.cpp rdchunk.h + +nodist_rdchunk_SOURCES = moc_rdchunk.cpp + +rdchunk_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdchunk.pro\ + rdchunk_de.ts\ + rdchunk_es.ts\ + rdchunk_fr.ts\ + rdchunk_pt_BR.ts + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/utils/rdchunk/rdchunk.cpp b/utils/rdchunk/rdchunk.cpp new file mode 100644 index 00000000..0bbee9ad --- /dev/null +++ b/utils/rdchunk/rdchunk.cpp @@ -0,0 +1,745 @@ +// rdchunk.cpp +// +// A Qt-based application for playing Microsoft WAV files. +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: rdchunk.cpp,v 1.3.8.3 2014/01/21 21:59:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + y_chunk_button=40; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Generate Fonts + // + QFont font("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + QFont label_font("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + wave_loaded=false; + wavefile=NULL; + fmt_button=NULL; + data_button=NULL; + fact_button=NULL; + cart_button=NULL; + bext_button=NULL; + mext_button=NULL; + wave_base="RDChunk"; + setCaption(wave_base); + + // + // Load Button + // + QPushButton *button=new QPushButton(tr("Load"),this,"load_button"); + button->setGeometry(10,10,sizeHint().width()-20,30); + connect(button,SIGNAL(clicked()),this,SLOT(loadWaveFile())); + + // + // Chunk Label + // + wave_chunk_label=new QLabel(tr("Chunks"),this,"wave_chunk_label"); + wave_chunk_label->setGeometry(25,55,sizeHint().width()-50,20); + wave_chunk_label->setAlignment(AlignCenter); + wave_chunk_label->setFont(label_font); + wave_chunk_label->hide(); +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(120,y_chunk_button+10); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::createChunkButtons() +{ + int xptr=20; + int yptr=78; + + // + // Create chunk buttons + // + if(wavefile->getFormatChunk()) { + fmt_button=new QPushButton(this,"fmt"); + fmt_button->setText("Format"); + fmt_button->setGeometry(xptr,yptr,80,25); + fmt_button->show(); + yptr+=30; + connect(fmt_button,SIGNAL(clicked()),this,SLOT(displayFmt())); + } + if(wavefile->getDataChunk()) { + data_button=new QPushButton(this,"data"); + data_button->setText("Data"); + data_button->setGeometry(xptr,yptr,80,25); + data_button->show(); + yptr+=30; + connect(data_button,SIGNAL(clicked()),this,SLOT(displayData())); + } + if(wavefile->getFactChunk()) { + fact_button=new QPushButton(this,"fact"); + fact_button->setText("Fact"); + fact_button->setGeometry(xptr,yptr,80,25); + fact_button->show(); + yptr+=30; + connect(fact_button,SIGNAL(clicked()),this,SLOT(displayFact())); + } + if(wavefile->getCartChunk()) { + cart_button=new QPushButton(this,"cart"); + cart_button->setText("Cart"); + cart_button->setGeometry(xptr,yptr,80,25); + cart_button->show(); + yptr+=30; + connect(cart_button,SIGNAL(clicked()),this,SLOT(displayCart())); + } + if(wavefile->getBextChunk()) { + bext_button=new QPushButton(this,"bext"); + bext_button->setText("Bext"); + bext_button->setGeometry(xptr,yptr,80,25); + bext_button->show(); + yptr+=30; + connect(bext_button,SIGNAL(clicked()),this,SLOT(displayBext())); + } + if(wavefile->getMextChunk()) { + mext_button=new QPushButton(this,"mext"); + mext_button->setText("Mext"); + mext_button->setGeometry(xptr,yptr,80,25); + mext_button->show(); + yptr+=30; + connect(mext_button,SIGNAL(clicked()),this,SLOT(displayMext())); + } + if(wavefile->getLevlChunk()) { + levl_button=new QPushButton(this,"levl"); + levl_button->setText("Levl"); + levl_button->setGeometry(xptr,yptr,80,25); + levl_button->show(); + yptr+=30; + connect(levl_button,SIGNAL(clicked()),this,SLOT(displayLevl())); + } + if(wavefile->getAIR1Chunk()) { + AIR1_button=new QPushButton(this,"AIR1"); + AIR1_button->setText("AIR1"); + AIR1_button->setGeometry(xptr,yptr,80,25); + AIR1_button->show(); + yptr+=30; + connect(AIR1_button,SIGNAL(clicked()),this,SLOT(displayAIR1())); + } + y_chunk_button=yptr; + wave_chunk_label->show(); + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + setGeometry(geometry().x(),geometry().y(),sizeHint().width(), + sizeHint().height()); +} + + +void MainWidget::destroyChunkButtons() +{ + if(fmt_button!=NULL) { + fmt_button->hide(); + delete fmt_button; + fmt_button=NULL; + } + + if(data_button!=NULL) { + data_button->hide(); + delete data_button; + data_button=NULL; + } + + if(fact_button!=NULL) { + fact_button->hide(); + delete fact_button; + fact_button=NULL; + } + + if(cart_button!=NULL) { + cart_button->hide(); + delete cart_button; + cart_button=NULL; + } + + if(bext_button!=NULL) { + bext_button->hide(); + delete bext_button; + bext_button=NULL; + } + + if(mext_button!=NULL) { + mext_button->hide(); + delete mext_button; + mext_button=NULL; + } + wave_chunk_label->hide(); + y_chunk_button=40; + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + setGeometry(geometry().x(),geometry().y(),sizeHint().width(), + sizeHint().height()); +} + + +void MainWidget::loadWaveFile() +{ + QString str; + + delete wavefile; + wavefile=NULL; + destroyChunkButtons(); + wave_name=QFileDialog::getOpenFileName(wave_path,RD_AUDIO_FILE_FILTER,this); + if(wave_name.isEmpty()) { + wave_loaded=false; + wave_path=getenv("HOME"); + wave_base=tr("RHPIPlay"); + update(); + return; + } + wavefile=new RDWaveFile(wave_name); + if(wavefile->openWave()) { + wave_loaded=true; + wave_path=RDGetPathPart(wave_name); + wave_base="RHPIPlay - "; + if(wavefile->getCartChunk()) { + wave_base+=wavefile->getCartTitle(); + } + else { + wave_base+=RDGetBasePart(wave_name); + } + createChunkButtons(); + update(); + } + else { + QMessageBox::warning(this,tr("RDChunk"),tr("Unable to open file!")); + delete wavefile; + wavefile=NULL; + } +} + + +void MainWidget::quitMainWidget() +{ + qApp->quit(); +} + + +void MainWidget::paintEvent(QPaintEvent *paintevent) +{ + QPainter *p=new QPainter(this); + p->setFont(QFont("arial",12,QFont::Bold)); + + if(wave_loaded) { + p->moveTo(10,65); + p->lineTo(sizeHint().width()-10,65); + p->lineTo(sizeHint().width()-10,y_chunk_button); + p->lineTo(10,y_chunk_button); + p->lineTo(10,65); + } +} + + +void MainWidget::displayFmt() +{ + char string[256]; + QString output; + QString str1; + QString str2; + + // + // Basic Data, common to all valid WAV files + // + switch(wavefile->getFormatTag()) { + case WAVE_FORMAT_PCM: + str1=QString(tr("Format: PCM")); + str2=QString(tr("Linear")); + sprintf(string,"%s%d %s\n",(const char *)str1, + wavefile->getBitsPerSample(),(const char *)str2); + output=output.append(string); + break; + case WAVE_FORMAT_MPEG: + str1=QString(tr("Format: MPEG Layer")); + sprintf(string,"%s %d\n",(const char *)str1,wavefile->getHeadLayer()); + output=output.append(string); + break; + case WAVE_FORMAT_VORBIS: + str1=QString(tr("Format: OggVorbis")); + sprintf(string,"%s\n",(const char *)str1); + output=output.append(string); + break; + default: + str1=QString(tr("Format: Unknown")); + sprintf(string,"Format: %s\n",(const char *)str1); + output=output.append(string); + break; + } + + str1=QString(tr("Channels:")); + sprintf(string,"%s %d\n",(const char *)str1,wavefile->getChannels()); + output=output.append(string); + + str1=QString(tr("Sample Rate:")); + str2=QString(tr("samples/sec")); + sprintf(string,"%s %d %s\n",(const char *)str1,wavefile->getSamplesPerSec(), + (const char *)str2); + output=output.append(string); + + str1=QString(tr("Average Data Rate:")); + str2=QString(tr("bytes/sec")); + sprintf(string,"%s %d %s\n",(const char *)str1,wavefile->getAvgBytesPerSec(), + (const char *)str2); + output=output.append(string); + + str1=QString(tr("Frame Size:")); + str2=QString(tr("byte3s")); + sprintf(string,"%s %d %s\n",(const char *)str1,wavefile->getBlockAlign(), + (const char *)str2); + output=output.append(string); + + // + // PCM Linear specific data + // + if(wavefile->getFormatTag()==WAVE_FORMAT_PCM) { + str1=QString(tr("Sample Size:")); + str2=QString(tr("bits/chan/sample")); + sprintf(string,"%s %d %s\n",(const char *)str1, + wavefile->getBitsPerSample(), + (const char *)str2); + output=output.append(string); + } + + // + // MPEG-1 specific data + // + if(wavefile->getFormatTag()==WAVE_FORMAT_MPEG) { + str1=QString(tr("Bit Rate:")); + str2=QString(tr("bits/sec")); + sprintf(string,"%s %d %s\n",(const char *)str1,wavefile->getHeadBitRate(), + (const char *)str2); + output=output.append(string); + sprintf(string,tr("Codec Mode(s): ")); + if((wavefile->getHeadMode()&ACM_MPEG_STEREO)!=0) { + strcat(string,tr("Stereo ")); + } + if((wavefile->getHeadMode()&ACM_MPEG_JOINTSTEREO)!=0) { + strcat(string,tr("JointStereo ")); + } + if((wavefile->getHeadMode()&ACM_MPEG_DUALCHANNEL)!=0) { + strcat(string,tr("DualChannel ")); + } + if((wavefile->getHeadMode()&ACM_MPEG_SINGLECHANNEL)!=0) { + strcat(string,tr("SingleChannel ")); + } + strcat(string,"\n"); + output=output.append(string); + + switch(wavefile->getHeadEmphasis()) { + case 1: + str1=QString(tr("None")); + sprintf(string,"Emphasis: %s\n",(const char *)str1); + output=output.append(string); + break; + case 2: + str1=QString(tr("50/15 ms")); + sprintf(string,"Emphasis: %s\n",(const char *)str1); + output=output.append(string); + break; + case 3: + str1=QString(tr("Reserved")); + sprintf(string,"Emphasis: %s\n",(const char *)str1); + output=output.append(string); + break; + case 4: + str1=QString(tr("CCITT J.17")); + sprintf(string,"Emphasis: %s\n",(const char *)str1); + output=output.append(string); + break; + default: + str1=QString(tr("Unknown")); + sprintf(string,"Emphasis: %s\n",(const char *)str1); + output=output.append(string); + break; + } + sprintf(string,tr("Flags: ")); + if((wavefile->getHeadFlags()&ACM_MPEG_PRIVATEBIT)!=0) { + strcat(string,tr("Private ")); + } + if((wavefile->getHeadFlags()&ACM_MPEG_COPYRIGHT)!=0) { + strcat(string,tr("Copyright ")); + } + if((wavefile->getHeadFlags()&ACM_MPEG_ORIGINALHOME)!=0) { + strcat(string,tr("Home ")); + } + if((wavefile->getHeadFlags()&ACM_MPEG_PROTECTIONBIT)!=0) { + strcat(string,"Protect "); + } + if((wavefile->getHeadFlags()&ACM_MPEG_ID_MPEG1)!=0) { + strcat(string,tr("MPEG ")); + } + strcat(string,"\n"); + output=output.append(string); + } + QMessageBox::information(this,tr("FMT Chunk"),output); + +} + +void MainWidget::displayData() +{ + QString str1; + QString str2; + char string[256]; + QString output; + + str1=QString(tr("Data Size:")); + str2=QString(tr("bytes")); + sprintf(string,"%s %d %s\n",(const char *)str1,wavefile->getDataLength(), + (const char *)str2); + output=output.append(string); + + QMessageBox::information(this,tr("DATA Chunk"),output); +} + + +void MainWidget::displayFact() +{ + QString str1; + QString str2; + char string[256]; + QString output; + + str1=QString(tr("Sample Size:")); + str2=QString(tr("samples")); + sprintf(string,"%s %d %s\n",(const char *)str1,wavefile->getSampleLength(), + (const char *)str2); + output=output.append(string); + + QMessageBox::information(this,"FACT Chunk",output); +} + + +void MainWidget::displayCart() +{ + QString str1; + QString str2; + char string[256]; + QString output; + bool timers_found=false; + +/* + sprintf(string,"Cart Chunk Version: %c.%c.%c\n", + (wavefile->getCartVersion()>>24)&255, + (wavefile->getCartVersion()>>16)&255, + (wavefile->getCartVersion()>>8)&255); + output=output.append(string); +*/ + output=output.append(tr("TITLE: ")); + output=output.append(wavefile->getCartTitle()); + output=output.append("\n"); + output=output.append(tr("ARTIST: ")); + output=output.append(wavefile->getCartArtist()); + output=output.append("\n"); + output=output.append(tr("CUT ID: ")); + output=output.append(wavefile->getCartCutID()); + output=output.append("\n"); + output=output.append(tr("CLIENT ID: ")); + output=output.append(wavefile->getCartClientID()); + output=output.append("\n"); + output=output.append(tr("CATEGORY: ")); + output=output.append(wavefile->getCartCategory()); + output=output.append("\n"); + output=output.append(tr("CLASSIFICATION: ")); + output=output.append(wavefile->getCartClassification()); + output=output.append("\n"); + output=output.append(tr("OUT CUE: ")); + output=output.append(wavefile->getCartOutCue()); + output=output.append("\n"); + output=output.append(tr("START DATE: ")); + output=output.append(wavefile->getCartStartDate().toString()); + output=output.append("\n"); + output=output.append(tr("START TIME: ")); + output=output.append(wavefile->getCartStartTime().toString()); + output=output.append("\n"); + output=output.append(tr("END DATE: ")); + output=output.append(wavefile->getCartEndDate().toString()); + output=output.append("\n"); + output=output.append(tr("END TIME: ")); + output=output.append(wavefile->getCartEndTime().toString()); + output=output.append("\n"); + output=output.append(tr("PRODUCER ID: ")); + output=output.append(wavefile->getCartProducerAppID()); + output=output.append("\n"); + output=output.append(tr("PRODUCER VERSION: ")); + output=output.append(wavefile->getCartProducerAppVer()); + output=output.append("\n"); + output=output.append(tr("USER DEFINED: ")); + output=output.append(wavefile->getCartUserDef()); + output=output.append("\n"); + if(wavefile->getCartLevelRef()>0) { + str1=QString(tr("LEVEL REFERENCE:")); + str2=QString(tr("dB")); + sprintf(string,"%s %5.1lf %s\n",(const char *)str1, + 20*log10((float)wavefile->getCartLevelRef()/32767), + (const char *)str2); + } + else { + str1=QString(tr("LEVEL REFERENCE:")); + str2=QString(tr("Undefined")); + sprintf(string,"%s %s\n",(const char *)str1,(const char *)str2); + } + output=output.append(string); + output=output.append(tr("URL: ")); + output=output.append(wavefile->getCartURL()); + output=output.append("\n"); + output=output.append(tr("CART TIMER(S): ")); + for(int i=0;igetCartTimerLabel(i).isEmpty()) { + output=output.append(wavefile->getCartTimerLabel(i)); + sprintf(string,": %u\n",wavefile->getCartTimerSample(i)); + output=output.append(string); + timers_found=true; + } + } + if(!timers_found) { + output=output.append("\n"); + } + output=output.append(tr("TAG TEXT: ")); + output=output.append(wavefile->getCartTagText()); + output=output.append("\n"); + + QMessageBox::information(this,tr("CART Chunk"),output); +} + + + +void MainWidget::displayBext() +{ + char string[256]; + QString output; + QString str; + + output=output.append(tr("DESCRIPTION: ")); + output=output.append(wavefile->getBextDescription()); + output=output.append("\n"); + output=output.append(tr("ORIGINATOR: ")); + output=output.append(wavefile->getBextOriginator()); + output=output.append("\n"); + output=output.append(tr("ORIGINATOR REFERENCE: ")); + output=output.append(wavefile->getBextOriginatorRef()); + output=output.append("\n"); + output=output.append(tr("ORIGINATION DATE: ")); + output=output.append(wavefile->getBextOriginationDate().toString()); + output=output.append("\n"); + output=output.append(tr("ORIGINATION TIME: ")); + output=output.append(wavefile->getBextOriginationTime().toString()); + output=output.append("\n"); + str=QString(tr("VERSION:")); + sprintf(string,"%s %d\n",(const char *)str,wavefile->getBextVersion()); + output=output.append(string); + output=output.append(tr("CODING HISTORY: ")); + output=output.append(wavefile->getBextCodingHistory()); + output=output.append("\n"); + + QMessageBox::information(this,tr("BEXT Chunk"),output); +} + + +void MainWidget::displayMext() +{ + QString output; + QString str1; + QString str2; + + output=output.append(tr("MPEG Data Composition: ")); + if(wavefile->getMextHomogenous()) { + output=output.append(tr("Homogenous")); + output=output.append("\n"); + if(wavefile->getMextPaddingUsed()) { + output=output.append(tr("The padding bit is active.")); + output=output.append("\n"); + } + else { + output=output.append(tr("The padding bit is inactive.")); + output=output.append("\n"); + } + if(wavefile->getMextHackedBitRate()) { + output=output.append(tr("The bit rate is non-standard.")); + output=output.append("\n"); + } + } + else { + output=output.append(tr("Non-homogenous")); + output=output.append("\n"); + } + if(wavefile->getMextFreeFormat()) { + output=output.append(tr("MPEG Format: Free Format")); + output=output.append("\n"); + } + else { + output=output.append(tr("MPEG Format: Constant Bit Rate")); + output=output.append("\n"); + } + str1=QString(tr("MPEG Frame Size:")); + str2=QString(tr("bytes")); + output=output.append(QString().sprintf("%s %d %s",(const char *)str1, + wavefile->getMextFrameSize(), + (const char *)str2)); + output=output.append("\n"); + str1=QString(tr("Ancillary Bytes:")); + str2=QString(tr("bytes")); + output=output.append(QString().sprintf("%s %d %s\n",(const char *)str1, + wavefile->getMextAncillaryLength(), + (const char *)str2)); + output=output.append("\n"); + if(wavefile->getMextAncillaryLength()>0) { + output=output.append(tr("Ancillary Data: ")); + if(wavefile->getMextLeftEnergyPresent()) { + output=output.append(tr(" LeftEnergy")); + } + if(wavefile->getMextRightEnergyPresent()) { + output=output.append(tr(" RightEnergy")); + } + if(wavefile->getMextPrivateDataPresent()) { + output=output.append(tr(" PrivateData")); + } + output=output.append("\n"); + } + + QMessageBox::information(this,tr("MEXT Chunk"),output); +} + + +void MainWidget::displayLevl() +{ + QString output; + QString str; + + output=output.append(tr("Version: ")); + output=output.append(QString().sprintf("%d\n",wavefile->getLevlVersion())); + output=output.append(tr("Samples per Peak: ")); + output= + output.append(QString().sprintf("%d\n",wavefile->getLevlBlockSize())); + output=output.append(tr("Sample Channels: ")); + output=output.append(QString().sprintf("%d\n",wavefile->getLevlChannels())); + output=output.append(tr("Overall Peak: ")); + if(wavefile->getLevlPeak()==0) { + output=output.append(tr("Unknown")); + output=output.append("\n"); + } + else { + str=QString(tr("dBFS")); + output=output.append(QString().sprintf("%5.1f %s\n", + 20.0*log10((double)wavefile->getLevlPeak()/32768.0), + (const char *)str)); + } + output=output.append(tr("Timestamp: ")); + output= + output.append(wavefile->getLevlTimestamp().toString("MM-dd-yyyy hh:mm:ss")); + + QMessageBox::information(this,tr("LEVL Chunk"),output); +} + + +void MainWidget::displayAIR1() +{ +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(), + "."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rdutils_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} + + diff --git a/utils/rdchunk/rdchunk.h b/utils/rdchunk/rdchunk.h new file mode 100644 index 00000000..b6b29406 --- /dev/null +++ b/utils/rdchunk/rdchunk.h @@ -0,0 +1,84 @@ +// rdchunk.h +// +// Utility for examining chunk data in WAV files. +// +// (C) Copyright 2002-2004,2008 Fred Gleason +// +// $Id: rdchunk.h,v 1.3.8.1 2013/12/05 17:37:48 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDCHUNK_H +#define RDCHUNK_H + +#include +#include +#include + +#include + +#define MIXER_X 150 +#define MIXER_Y 200 +#define METER_UPDATE_INTERVAL 50 + + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + void paintEvent(QPaintEvent *); + + private slots: + void loadWaveFile(); + void quitMainWidget(); + void displayFmt(); + void displayData(); + void displayFact(); + void displayCart(); + void displayBext(); + void displayMext(); + void displayLevl(); + void displayAIR1(); + + private: + void createChunkButtons(); + void destroyChunkButtons(); + QTimer *meter_timer; + RDWaveFile *wavefile; + int y_chunk_button; + bool wave_loaded; + QString wave_name; + QString wave_path; + QString wave_base; + QPushButton *fmt_button; + QPushButton *data_button; + QPushButton *fact_button; + QPushButton *cart_button; + QPushButton *bext_button; + QPushButton *mext_button; + QPushButton *levl_button; + QPushButton *AIR1_button; + QLabel *wave_chunk_label; + int play_port; +}; + + +#endif diff --git a/utils/rdchunk/rdchunk.pro b/utils/rdchunk/rdchunk.pro new file mode 100644 index 00000000..9d6be157 --- /dev/null +++ b/utils/rdchunk/rdchunk.pro @@ -0,0 +1,28 @@ +# rdchunk.pro +# +# The utils/rdchunk/ QMake project file for Rivendell +# +# (C) Copyright 2003-2006,2008 Fred Gleason +# +# $Id: rdchunk.pro,v 1.2 2010/08/04 23:07:02 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +SOURCES += rdchunk.cpp +HEADERS += rdchunk.h + +TRANSLATIONS += rdchunk_es.ts +TRANSLATIONS += rdchunk_fr.ts +TRANSLATIONS += rdchunk_de.ts +TRANSLATIONS += rdchunk_pt_BR.ts diff --git a/utils/rdchunk/rdchunk_de.ts b/utils/rdchunk/rdchunk_de.ts new file mode 100644 index 00000000..f7e23ab9 --- /dev/null +++ b/utils/rdchunk/rdchunk_de.ts @@ -0,0 +1,373 @@ + + + MainWidget + + Load + Laden + + + RHPIPlay + RHPIPlay + + + Format: PCM + Format: PCM + + + Linear + Linear + + + Format: MPEG Layer + Format: MPEG Layer + + + Format: OggVorbis + Format: OggVorbis + + + Format: Unknown + Format: Unknown + + + Channels: + Kanäle: + + + Sample Rate: + Samplerate: + + + samples/sec + samples/sec + + + Average Data Rate: + Durchschnittliche Datenrate: + + + bytes/sec + bytes/sec + + + Frame Size: + Framegröße: + + + byte3s + byte3s + + + Sample Size: + Samplegröße: + + + bits/chan/sample + Bits/Kanal/Sample + + + Bit Rate: + Bitrate: + + + bits/sec + bits/sec + + + Codec Mode(s): + Codec Mode(s): + + + Stereo + Stereo + + + JointStereo + JointStereo + + + DualChannel + Zwei Kanäle + + + SingleChannel + Ein Kanal + + + None + Keine + + + 50/15 ms + 50/15 ms + + + Reserved + Reserviert + + + CCITT J.17 + CCITT J.17 + + + Unknown + unbekannt + + + Flags: + Flags: + + + Private + Privat + + + Copyright + Copyright + + + Home + Home + + + MPEG + MPEG + + + FMT Chunk + FMT Chunk + + + Data Size: + Datengröße: + + + bytes + bytes + + + DATA Chunk + DATA Chunk + + + samples + samples + + + TITLE: + TITEL: + + + ARTIST: + KÜNSTLER: + + + CUT ID: + CUT ID: + + + CLIENT ID: + KUNDEN ID: + + + CATEGORY: + KATEGORIE: + + + CLASSIFICATION: + KLASSIFIKATION: + + + OUT CUE: + OUTCUE: + + + START DATE: + STARTDATUM: + + + START TIME: + STARTZEIT: + + + END DATE: + ENDDATUM: + + + END TIME: + ENDZEIT: + + + PRODUCER ID: + PRODUZENTEN-ID: + + + PRODUCER VERSION: + PRODUZENTEN-VERSION: + + + USER DEFINED: + BENUTZERDEFINIERT: + + + LEVEL REFERENCE: + LEVELREFERENZ: + + + dB + dB + + + Undefined + Nicht definiert + + + URL: + URL: + + + CART TIMER(S): + CART TIMER: + + + TAG TEXT: + TAG TEXT: + + + CART Chunk + CART Chunk + + + DESCRIPTION: + BESCHREIBUNG: + + + ORIGINATOR: + HERKUNFT: + + + ORIGINATOR REFERENCE: + HERKUNFTSREFERENZ: + + + ORIGINATION DATE: + HERKUNFTSDATUM: + + + ORIGINATION TIME: + HERKUNFTSZEIT: + + + VERSION: + VERSION: + + + CODING HISTORY: + CODING-HISTORIE: + + + BEXT Chunk + BEXT Chunk + + + MPEG Data Composition: + MPEG Datenkomposition: + + + Homogenous + Homogen + + + The padding bit is active. + Das Padding-Bit ist aktiv. + + + The padding bit is inactive. + Das Padding-Bit ist inaktiv. + + + The bit rate is non-standard. + Die Bitrate weicht vom Standard ab. + + + Non-homogenous + Nicht homogen + + + MPEG Format: Free Format + MPEG Format: Freies Format + + + MPEG Format: Constant Bit Rate + MPEG Format: Konstante Bitrate + + + MPEG Frame Size: + MPEG Frame Size: + + + Ancillary Bytes: + Ancillary Bytes: + + + Ancillary Data: + Ancillary Data: + + + LeftEnergy + LeftEnergy + + + RightEnergy + RightEnergy + + + PrivateData + PrivateData + + + MEXT Chunk + MEXT Chunk + + + Version: + Version: + + + Samples per Peak: + Samples pro Peak: + + + Sample Channels: + Sample Kanäle: + + + Overall Peak: + Overall Peak: + + + dBFS + dBFS + + + Timestamp: + Timestamp: + + + LEVL Chunk + LEVL Chunk + + + Chunks + Chunks + + + RDChunk + RDChunk + + + Unable to open file! + Kann die Datei nicht öffnen! + + + diff --git a/utils/rdchunk/rdchunk_es.ts b/utils/rdchunk/rdchunk_es.ts new file mode 100644 index 00000000..73a9c65c --- /dev/null +++ b/utils/rdchunk/rdchunk_es.ts @@ -0,0 +1,373 @@ + + + MainWidget + + Load + Cargar + + + RHPIPlay + + + + Format: PCM + Formato: PCM + + + Linear + Lineal + + + Format: MPEG Layer + Formato: MPEG Capa + + + Format: OggVorbis + Formato: OGGVorbis + + + Format: Unknown + Formato: Desconocido + + + Channels: + Canales: + + + Sample Rate: + Tasa de muestreo: + + + samples/sec + muestras/seg + + + Average Data Rate: + Tasa promedio de datos: + + + bytes/sec + bytes/seg + + + Frame Size: + Tamaño de marco: + + + byte3s + + + + Sample Size: + Tamaño de muestra: + + + bits/chan/sample + bits/canal/muestra + + + Bit Rate: + Tasa de Bit: + + + bits/sec + bits/seg + + + Codec Mode(s): + Modo(s) de Codec: + + + Stereo + Estéreo + + + JointStereo + + + + DualChannel + + + + SingleChannel + + + + None + Ninguno + + + 50/15 ms + + + + Reserved + Reservado + + + CCITT J.17 + + + + Unknown + Desconocido + + + Flags: + Banderas: + + + Private + Privado + + + Copyright + + + + Home + + + + MPEG + + + + FMT Chunk + + + + Data Size: + Tamaño de datos: + + + bytes + bytes + + + DATA Chunk + + + + samples + muestras + + + TITLE: + TÍTULO: + + + ARTIST: + ARTISTA: + + + CUT ID: + ID AUDIO: + + + CLIENT ID: + ID CLIENTE: + + + CATEGORY: + CATEGORÍA: + + + CLASSIFICATION: + CLASIFICACIÓN: + + + OUT CUE: + + + + START DATE: + FECHA INICIO: + + + START TIME: + HORA INICIO: + + + END DATE: + FECHA FIN: + + + END TIME: + HORA FIN: + + + PRODUCER ID: + ID PRODUCTOR: + + + PRODUCER VERSION: + VERSIÓN DEL PRODUCTOR: + + + USER DEFINED: + DEFINIDO POR USUARIO: + + + LEVEL REFERENCE: + NIVEL DE REFERENCIA: + + + dB + dB + + + Undefined + Indefinido + + + URL: + URL: + + + CART TIMER(S): + + + + TAG TEXT: + TEXTO ETIQ: + + + CART Chunk + + + + DESCRIPTION: + DESCRIPCIÓN: + + + ORIGINATOR: + ORIGEN: + + + ORIGINATOR REFERENCE: + REFERENCIA DEL ORIGEN: + + + ORIGINATION DATE: + FECHA DE ORIGEN: + + + ORIGINATION TIME: + HORA DE ORIGEN: + + + VERSION: + VERSION: + + + CODING HISTORY: + + + + BEXT Chunk + + + + MPEG Data Composition: + Composición de datos MPEG: + + + Homogenous + Homogéneo + + + The padding bit is active. + + + + The padding bit is inactive. + + + + The bit rate is non-standard. + La tasa de bits no es estándar. + + + Non-homogenous + No homogéneo + + + MPEG Format: Free Format + Formato MPEG: formato libre + + + MPEG Format: Constant Bit Rate + Formato MPEG: Tasa de bit constante + + + MPEG Frame Size: + Tamaño frame MPEG: + + + Ancillary Bytes: + + + + Ancillary Data: + + + + LeftEnergy + + + + RightEnergy + + + + PrivateData + + + + MEXT Chunk + + + + Version: + Versión: + + + Samples per Peak: + Muestras por pico: + + + Sample Channels: + Canales de muestra: + + + Overall Peak: + + + + dBFS + + + + Timestamp: + + + + LEVL Chunk + + + + Chunks + + + + RDChunk + + + + Unable to open file! + ¡No pude abrir el archivo! + + + diff --git a/utils/rdchunk/rdchunk_fr.ts b/utils/rdchunk/rdchunk_fr.ts new file mode 100644 index 00000000..7cb9dbf8 --- /dev/null +++ b/utils/rdchunk/rdchunk_fr.ts @@ -0,0 +1,373 @@ + + + MainWidget + + Load + + + + RHPIPlay + + + + Format: PCM + + + + Linear + + + + Format: MPEG Layer + + + + Format: OggVorbis + + + + Format: Unknown + + + + Channels: + + + + Sample Rate: + + + + samples/sec + + + + Average Data Rate: + + + + bytes/sec + + + + Frame Size: + + + + byte3s + + + + Sample Size: + + + + bits/chan/sample + + + + Bit Rate: + + + + bits/sec + + + + Codec Mode(s): + + + + Stereo + + + + JointStereo + + + + DualChannel + + + + SingleChannel + + + + None + + + + 50/15 ms + + + + Reserved + + + + CCITT J.17 + + + + Unknown + + + + Flags: + + + + Private + + + + Copyright + + + + Home + + + + MPEG + + + + FMT Chunk + + + + Data Size: + + + + bytes + + + + DATA Chunk + + + + samples + + + + TITLE: + + + + ARTIST: + + + + CUT ID: + + + + CLIENT ID: + + + + CATEGORY: + + + + CLASSIFICATION: + + + + OUT CUE: + + + + START DATE: + + + + START TIME: + + + + END DATE: + + + + END TIME: + + + + PRODUCER ID: + + + + PRODUCER VERSION: + + + + USER DEFINED: + + + + LEVEL REFERENCE: + + + + dB + + + + Undefined + + + + URL: + + + + CART TIMER(S): + + + + TAG TEXT: + + + + CART Chunk + + + + DESCRIPTION: + + + + ORIGINATOR: + + + + ORIGINATOR REFERENCE: + + + + ORIGINATION DATE: + + + + ORIGINATION TIME: + + + + VERSION: + + + + CODING HISTORY: + + + + BEXT Chunk + + + + MPEG Data Composition: + + + + Homogenous + + + + The padding bit is active. + + + + The padding bit is inactive. + + + + The bit rate is non-standard. + + + + Non-homogenous + + + + MPEG Format: Free Format + + + + MPEG Format: Constant Bit Rate + + + + MPEG Frame Size: + + + + Ancillary Bytes: + + + + Ancillary Data: + + + + LeftEnergy + + + + RightEnergy + + + + PrivateData + + + + MEXT Chunk + + + + Version: + + + + Samples per Peak: + + + + Sample Channels: + + + + Overall Peak: + + + + dBFS + + + + Timestamp: + + + + LEVL Chunk + + + + Chunks + + + + RDChunk + + + + Unable to open file! + + + + diff --git a/utils/rdchunk/rdchunk_pt_BR.ts b/utils/rdchunk/rdchunk_pt_BR.ts new file mode 100644 index 00000000..a3c2698e --- /dev/null +++ b/utils/rdchunk/rdchunk_pt_BR.ts @@ -0,0 +1,373 @@ + + + MainWidget + + Load + + + + Chunks + + + + RHPIPlay + + + + RDChunk + + + + Unable to open file! + + + + Format: PCM + + + + Linear + + + + Format: MPEG Layer + + + + Format: OggVorbis + + + + Format: Unknown + + + + Channels: + + + + Sample Rate: + + + + samples/sec + + + + Average Data Rate: + + + + bytes/sec + + + + Frame Size: + + + + byte3s + + + + Sample Size: + + + + bits/chan/sample + + + + Bit Rate: + + + + bits/sec + + + + Codec Mode(s): + + + + Stereo + + + + JointStereo + + + + DualChannel + + + + SingleChannel + + + + None + + + + 50/15 ms + + + + Reserved + + + + CCITT J.17 + + + + Unknown + + + + Flags: + + + + Private + + + + Copyright + + + + Home + + + + MPEG + + + + FMT Chunk + + + + Data Size: + + + + bytes + + + + DATA Chunk + + + + samples + + + + TITLE: + + + + ARTIST: + + + + CUT ID: + + + + CLIENT ID: + + + + CATEGORY: + + + + CLASSIFICATION: + + + + OUT CUE: + + + + START DATE: + + + + START TIME: + + + + END DATE: + + + + END TIME: + + + + PRODUCER ID: + + + + PRODUCER VERSION: + + + + USER DEFINED: + + + + LEVEL REFERENCE: + + + + dB + + + + Undefined + + + + URL: + + + + CART TIMER(S): + + + + TAG TEXT: + + + + CART Chunk + + + + DESCRIPTION: + + + + ORIGINATOR: + + + + ORIGINATOR REFERENCE: + + + + ORIGINATION DATE: + + + + ORIGINATION TIME: + + + + VERSION: + + + + CODING HISTORY: + + + + BEXT Chunk + + + + MPEG Data Composition: + + + + Homogenous + + + + The padding bit is active. + + + + The padding bit is inactive. + + + + The bit rate is non-standard. + + + + Non-homogenous + + + + MPEG Format: Free Format + + + + MPEG Format: Constant Bit Rate + + + + MPEG Frame Size: + + + + Ancillary Bytes: + + + + Ancillary Data: + + + + LeftEnergy + + + + RightEnergy + + + + PrivateData + + + + MEXT Chunk + + + + Version: + + + + Samples per Peak: + + + + Sample Channels: + + + + Overall Peak: + + + + dBFS + + + + Timestamp: + + + + LEVL Chunk + + + + diff --git a/utils/rdcollect/Makefile.am b/utils/rdcollect/Makefile.am new file mode 100644 index 00000000..2efe9de5 --- /dev/null +++ b/utils/rdcollect/Makefile.am @@ -0,0 +1,55 @@ +## automake.am +## +## Automake.am for rivendell/utils/rdcollect +## +## (C) Copyright 2002-2010 Fred Gleason +## +## $Id: Makefile.am,v 1.2.8.2 2012/12/03 16:53:46 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rdcollect + +dist_rdcollect_SOURCES = rdcollect.cpp rdcollect.h + +rdcollect_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdcollect.pro + +CLEANFILES = *~\ + *.exe\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/utils/rdcollect/rdcollect.cpp b/utils/rdcollect/rdcollect.cpp new file mode 100644 index 00000000..874b63c5 --- /dev/null +++ b/utils/rdcollect/rdcollect.cpp @@ -0,0 +1,214 @@ +// rdcollect.cpp +// +// Collect and combine log exports into a single file. +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: rdcollect.cpp,v 1.2.8.1 2012/08/01 19:21:09 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include + +#include +#include + +#include + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + bool ok; + int err; + std::vector line_index; + hours_offset=0; + minutes_offset=3; + seconds_offset=6; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdcollect",RDCOLLECT_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--source-file") { + source_files.push_back(cmd->value(i)); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--destination-file") { + destination_file=cmd->value(i); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--hours-offset") { + hours_offset=cmd->value(i).toUInt(&ok); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--minutes-offset") { + minutes_offset=cmd->value(i).toUInt(&ok); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--seconds-offset") { + seconds_offset=cmd->value(i).toUInt(&ok); + cmd->setProcessed(i,true); + } + } + if(!cmd->allProcessed()) { + fprintf(stderr,"rdcollect: unknown option\n"); + exit(256); + } + if(source_files.size()==0) { + fprintf(stderr,"rdcollect: missing --source-file argument\n"); + exit(256); + } + if(destination_file.isEmpty()) { + fprintf(stderr,"rdcollect: missing --destination-file argument\n"); + exit(256); + } + + // + // Process Data + // + QStringList src_lines; + for(unsigned i=0;i0) { + lines->push_back(line.left(line.length()-1)); + } + file.close(); +} + + +void MainObject::SortLines(QStringList *lines,std::vector *index) +{ + std::vector start_times; + + // + // Initialize Index + // + for(unsigned i=0;isize();i++) { + index->push_back(i); + start_times.push_back(ReadTime((*lines)[i])); + } + + // + // Sort + // + bool modified=true; + while(modified) { + modified=false; + for(unsigned i=1;isize();i++) { + if(start_times[i-1]>start_times[i]) { + QTime time=start_times[i-1]; + start_times[i-1]=start_times[i]; + start_times[i]=time; + unsigned line=index->at(i-1); + index->at(i-1)=index->at(i); + index->at(i)=line; + modified=true; + } + } + } +} + + +int MainObject::WriteOutputFile(const QString &filename, + const QStringList &lines, + std::vector *index) +{ + FILE *f=NULL; + if((f=fopen(filename,"w"))==NULL) { + return errno; + } + for(unsigned i=0;iat(i)]); + } + fclose(f); + return 0; +} + + +void MainObject::AddDirs(const QString &path,QStringList *dirs) +{ + QDir dir(path); + dir.setFilter(QDir::Dirs); + QStringList list=dir.entryList(); + for(unsigned i=0;ipush_back(path+"/"+list[i]); + AddDirs(path+"/"+list[i],dirs); + } + } +} + + +QTime MainObject::ReadTime(const QString &line) +{ + return QTime(line.mid(hours_offset,2).toInt(), + line.mid(minutes_offset,2).toInt(), + line.mid(seconds_offset,2).toInt()); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/utils/rdcollect/rdcollect.h b/utils/rdcollect/rdcollect.h new file mode 100644 index 00000000..49e869e5 --- /dev/null +++ b/utils/rdcollect/rdcollect.h @@ -0,0 +1,57 @@ +// rdcollect.h +// +// Collect and combine log exports into a single file. +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDCOLLECT_H +#define RDCOLLECT_H + +#include + +#include +#include + +#define RDCOLLECT_USAGE "[options]\n\nCollect and combine log exports from a set of directories into a single file.\n\n--source-file=\n Name of source file. The path part of this value will be taken as the\n top of the directory tree to recurse, while the name part will be used as\n the name of the source file(s) to search for. This option may be given\n multiple times.\n\n--destination-file=\n Name of file to which to send output.\n\n--hours-offset=\n Start position of the hours field on a data line\n\n--minutes-offset=\n Start position of the minutes field on a data line\n\n--seconds-offset=\n Start position of the seconds field on a data line\n" + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + QStringList GetDirectoryList(const QString &src_file); + void LoadSourceFiles(const QString &src_name,const QStringList &dirs, + QStringList *lines); + void LoadSourceFile(const QString &filename,QStringList *lines); + void SortLines(QStringList *lines,std::vector *index); + int WriteOutputFile(const QString &filename,const QStringList &lines, + std::vector *index); + void AddDirs(const QString &path,QStringList *dirs); + QTime ReadTime(const QString &line); + QStringList source_files; + QString destination_file; + unsigned hours_offset; + unsigned minutes_offset; + unsigned seconds_offset; +}; + + +#endif // RDCOLLECT_H diff --git a/utils/rdcollect/rdcollect.pro b/utils/rdcollect/rdcollect.pro new file mode 100644 index 00000000..97613757 --- /dev/null +++ b/utils/rdcollect/rdcollect.pro @@ -0,0 +1,44 @@ +# rdcollect.pro +# +# The utils/rdcollect QMake project file for Rivendell +# +# (C) Copyright 2003-2007 Fred Gleason +# +# $Id: rdcollect.pro,v 1.2 2010/07/29 19:32:39 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +TARGET = rdcollect + +win32 { + DEFINES += WIN32 + DEFINES += VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE=\"rivendell\" + DEFINES += PACKAGE_VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE_NAME=\"rivendell\" + DEFINES += PACKAGE_BUGREPORT=\"fredg@paravelsystems.com\" +} + +SOURCES += rdcollect.cpp +HEADERS += rdcollect.h + +RES_FILE += ..\..\icons\rivendell.res + +INCLUDEPATH += ..\..\..\libradio\radio ..\..\lib + +LIBS = -lqui -L..\..\..\libradio\radio -lradio -L..\..\lib -llib + +CONFIG += qt diff --git a/utils/rddbcheck/Makefile.am b/utils/rddbcheck/Makefile.am new file mode 100644 index 00000000..4ac6659e --- /dev/null +++ b/utils/rddbcheck/Makefile.am @@ -0,0 +1,51 @@ +## automake.am +## +## Automake.am for rivendell/utils/rddbcheck +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.8.8.1 2012/11/29 01:37:38 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +sbin_PROGRAMS = rddbcheck + +dist_rddbcheck_SOURCES = rddbcheck.cpp rddbcheck.h + +rddbcheck_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rddbcheck/rddbcheck.cpp b/utils/rddbcheck/rddbcheck.cpp new file mode 100644 index 00000000..c1f4978e --- /dev/null +++ b/utils/rddbcheck/rddbcheck.cpp @@ -0,0 +1,825 @@ +// rddbcheck.cpp +// +// A Database Check/Repair Tool for Rivendell. +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: rddbcheck.cpp,v 1.18.4.1.2.1 2014/06/02 18:52:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// MAINTAINER'S NOTE +// Be sure to use QSqlQuery here, *not* RDSqlQuery, otherwise the +// DB connection will be reset when we detect an error! +// + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + bool skip_db_check=false; + unsigned schema=0; + + check_yes=false; + check_no=false; + QString username="user"; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rddbcheck",RDDBCHECK_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + if(cmd->key(i)=="--user") { + username=cmd->value(i); + } + if(cmd->key(i)=="--yes") { + check_yes=true; + } + if(cmd->key(i)=="--no") { + check_no=true; + } + if(cmd->key(i)=="--orphan-group") { + orphan_group_name=cmd->value(i); + } + if(cmd->key(i)=="--dump-cuts-dir") { + dump_cuts_dir=cmd->value(i); + } + } + if(check_yes&&check_no) { + fprintf(stderr,"rddbcheck: '--yes' and '--no' are mutually exclusive\n"); + exit(256); + } + + // + // Check for Root Perms + // + if(geteuid()!=0) { + fprintf(stderr,"rddbcheck: must be user \"root\"\n"); + exit(256); + } + + // + // Check for dump cuts directory + // + if(!dump_cuts_dir.isEmpty()) { + QFileInfo file(dump_cuts_dir); + if(!file.exists()) { + fprintf(stderr,"rddbcheck: directory \"%s\" does not exist.\n", + (const char *)dump_cuts_dir); + exit(256); + } + if(!file.isDir()) { + fprintf(stderr,"rddbcheck: \"%s\" is not a directory.\n", + (const char *)dump_cuts_dir); + exit(256); + } + if(!file.isWritable()) { + fprintf(stderr,"rddbcheck: \"%s\" is not writable.\n", + (const char *)dump_cuts_dir); + exit(256); + } + } + + // + // Read Configuration + // + rdconfig=new RDConfig(); + rdconfig->load(); + + // + // Open Database + // + QString err (tr("rddbcheck: ")); + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + fprintf(stderr,err.ascii()); + delete cmd; + exit(256); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr, + "rddbcheck: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + + // + // Validate Station + // + check_station=new RDStation(rdconfig->stationName()); + if(!check_station->exists()) { + fprintf(stderr,"rddbcheck: no such host [\"%s\"]\n", + (const char *)rdconfig->stationName()); + } + + // + // Validate User + // + check_user=new RDUser(username); + if(!check_user->exists()) { + fprintf(stderr,"rddbcheck: no such user [\"%s\"]\n",(const char *)username); + } + + if(!orphan_group_name.isEmpty()) { + QString sql=QString().sprintf("select NAME from GROUPS where NAME=\"%s\"", + (const char *)orphan_group_name); + printf("SQL: %s\n",(const char *)sql); + QSqlQuery *q=new QSqlQuery(sql); + if(!q->first()) { + fprintf(stderr,"rddbcheck: invalid group \"%s\"\n", + (const char *)orphan_group_name); + delete q; + exit(256); + } + delete q; + } + + // + // Check for Orphaned Voice Tracks + // + printf("Checking voice tracks...\n"); + CheckOrphanedTracks(); + printf("done.\n\n"); + + // + // Check RDLogManager Consistency + // + printf("Checking RDLogManager events...\n"); + CheckEvents(); + printf("done.\n\n"); + printf("Checking RDLogManager clocks...\n"); + CheckClocks(); + printf("done.\n\n"); + + // + // Check for orphaned tables + // + printf("Checking for orphaned tables...\n"); + CheckOrphanedTables(); + printf("done.\n\n"); + + // + // Check for stale reservations + // + printf("Checking for stale cart reservations...\n"); + CheckPendingCarts(); + printf("done.\n\n"); + + // + // Check for orphaned carts + // + printf("Checking for orphaned carts...\n"); + CheckOrphanedCarts(); + printf("done.\n\n"); + + // + // Check for orphaned cuts + // + printf("Checking for orphaned cuts...\n"); + CheckOrphanedCuts(); + printf("done.\n\n"); + + // + // Check Cart->Cut Counts + // + printf("Checking cart->cuts counters...\n"); + CheckCutCounts(); + printf("done.\n\n"); + + // + // Check Orphaned Audio + // + printf("Checking for orphaned audio...\n"); + CheckOrphanedAudio(); + printf("done.\n\n"); + + // + // Validating Audio Lengths + // + printf("Validating audio lengths (this may take some time)...\n"); + ValidateAudioLengths(); + printf("done.\n\n"); + + exit(0); +} + + +void MainObject::CheckOrphanedTracks() +{ + QString logname; + QString sql="select NUMBER,TITLE,OWNER from CART where OWNER!=\"\""; + QSqlQuery *q=new QSqlQuery(sql); + QSqlQuery *q1; + + while(q->next()) { + logname=q->value(2).toString()+"_LOG"; + logname.replace(" ","_"); + sql=QString().sprintf("select ID from %s where CART_NUMBER=%u", + (const char *)logname,q->value(0).toUInt()); + q1=new QSqlQuery(sql); + if(!q1->first()) { + printf(" Found orphaned track %u - \"%s\". Delete? (y/N) ", + q->value(0).toUInt(),(const char *)q->value(1).toString()); + fflush(NULL); + if(UserResponse()) { + RDCart *cart=new RDCart(q->value(0).toUInt()); + cart->remove(check_station,check_user,rdconfig); + delete cart; + RDLog *log=new RDLog(q->value(2).toString()); + if(log->exists()) { + log->updateTracks(); + } + delete log; + } + } + delete q1; + } + delete q; +} + + +void MainObject::CheckClocks() +{ + QString sql; + QSqlQuery *q; + QSqlQuery *q1; + QSqlQuery *q2; + QSqlQuery *q3; + QString clockname; + QString eventname; + + sql="select NAME from CLOCKS"; + q=new QSqlQuery(sql); + while(q->next()) { + clockname=q->value(0).toString(); + clockname.replace(" ","_"); + + // + // Check the CLK Table + // + sql=QString().sprintf ("select EVENT_NAME,ID from %s_CLK", + (const char *)clockname); + q1=new QSqlQuery(sql); + if(q1->isActive()) { + // + // Check the clock -> event linkage + // + while(q1->next()) { + sql=QString().sprintf("select NAME from EVENTS where NAME=\"%s\"", + (const char *)q1->value(0).toString()); + q2=new QSqlQuery(sql); + if(q2->first()) { + if(q1->value(0)!=q2->value(0)) { // Make sure the cases match! + printf(" Clock %s's linkage to event %s is broken -- fix (y/N)? ", + (const char *)clockname, + (const char *)q2->value(0).toString()); + fflush(NULL); + if(UserResponse()) { + sql=QString().sprintf("update %s_CLK set EVENT_NAME=\"%s\"\ + where ID=%d", + (const char *)clockname, + (const char *)q2->value(0).toString(), + q1->value(1).toInt()); + q3=new QSqlQuery(sql); + delete q3; + } + } + } + delete q2; + } + } + else { + printf(" Clock %s is missing the CLK table -- fix (y/N)? ", + (const char *)q->value(0).toString()); + fflush(NULL); + if(UserResponse()) { + sql=RDCreateClockTableSql(clockname); + q2=new QSqlQuery(sql); + delete q2; + } + } + delete q1; + } + delete q; + +} + + +void MainObject::CheckEvents() +{ + QString sql; + QSqlQuery *q; + QSqlQuery *q1; + QSqlQuery *q2; + QString eventname; + + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + while(q->next()) { + eventname=q->value(0).toString(); + eventname.replace(" ","_"); + + // + // Check the PRE Table + // + sql=QString().sprintf ("select ID from %s_PRE",(const char *)eventname); + q1=new QSqlQuery(sql); + if(q1->size()<0) { + printf(" Event %s is missing the PRE table -- fix (y/N)? ", + (const char *)q->value(0).toString()); + fflush(NULL); + if(UserResponse()) { + sql=RDCreateLogTableSql(eventname+"_PRE"); + q2=new QSqlQuery(sql); + delete q2; + } + } + delete q1; + + // + // Check the POST Table + // + sql=QString().sprintf ("select ID from %s_POST",(const char *)eventname); + q1=new QSqlQuery(sql); + if(!q1->isActive()) { + printf(" Event %s is missing the POST table -- fix (y/N)? ", + (const char *)q->value(0).toString()); + fflush(NULL); + if(UserResponse()) { + sql=RDCreateLogTableSql(eventname+"_POST"); + q2=new QSqlQuery(sql); + delete q2; + } + } + delete q1; + } + delete q; +} + + +void MainObject::CheckOrphanedTables() +{ + QSqlQuery *table_q; + QSqlQuery *q; + QString sql; + + // + // Generate Table Query + // + sql="show tables"; + table_q=new QSqlQuery(sql); + + // + // Look for orphaned clocks + // + sql="select NAME from CLOCKS"; + q=new QSqlQuery(sql); + CleanTables("CLK",table_q,q); + CleanTables("RULES",table_q,q); + delete q; + + // + // Look for orphaned events + // + sql="select NAME from EVENTS"; + q=new QSqlQuery(sql); + CleanTables("PRE",table_q,q); + CleanTables("POST",table_q,q); + delete q; + + // + // Look for orphaned logs + // + sql="select NAME from LOGS"; + q=new QSqlQuery(sql); + CleanTables("LOG",table_q,q); + CleanTables("STACK",table_q,q); + delete q; + + // + // Look for orphaned services + // + sql="select NAME from SERVICES"; + q=new QSqlQuery(sql); + CleanTables("SRT",table_q,q); + delete q; + + // + // Look for orphaned feeds + // + sql="select KEY_NAME from FEEDS"; + q=new QSqlQuery(sql); + CleanTables("FIELDS",table_q,q); + CleanTables("FLG",table_q,q); + delete q; + + // + // Look for stale and obsolete tables + // + CleanTables("IMP",table_q); + CleanTables("REC",table_q); + + + delete table_q; +} + + +void MainObject::CheckCutCounts() +{ + QString sql; + QSqlQuery *q; + QSqlQuery *q1; + + sql="select NUMBER,CUT_QUANTITY,TITLE from CART"; + q=new QSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("select CUT_NAME from CUTS \ + where (CART_NUMBER=%u)&&(LENGTH>0)", + q->value(0).toUInt()); + q1=new QSqlQuery(sql); + if(q1->size()!=q->value(1).toInt()) { + printf(" Cart %u [%s] has invalid cut count, fix (y/N)?", + q->value(0).toUInt(),(const char *)q->value(2).toString()); + if(UserResponse()) { + RDCart *cart=new RDCart(q->value(0).toUInt()); + cart->updateLength(); + cart->resetRotation(); + delete cart; + } + } + delete q1; + } + delete q; +} + + +void MainObject::CheckPendingCarts() +{ + QString sql; + QSqlQuery *q; + QDateTime now(QDate::currentDate(),QTime::currentTime()); + + sql=QString("select NUMBER from CART where ")+ + "(PENDING_STATION is not null)&&"+ + "(PENDING_DATETIME<\""+now.addDays(-1). + toString("yyyy-MM-dd hh:mm:ss")+"\")"; + printf("SQL: %s\n",(const char *)sql); + q=new QSqlQuery(sql); + while(q->next()) { + printf(" Cart %06u has stale reservation, delete cart(y/N)?", + q->value(0).toUInt()); + if(UserResponse()) { + RDCart::removeCart(q->value(0).toUInt(),check_station,check_user, + rdconfig); + } + } + delete q; +} + + +void MainObject::CheckOrphanedCarts() +{ + QString sql; + QSqlQuery *q; + QSqlQuery *q1; + + sql="select CART.NUMBER,CART.TITLE from CART left join GROUPS \ + on CART.GROUP_NAME=GROUPS.NAME where GROUPS.NAME is null"; + q=new QSqlQuery(sql); + while(q->next()) { + printf(" Cart %06u [%s] has missing/invalid group.\n", + q->value(0).toUInt(),(const char *)q->value(1).toString()); + if(orphan_group_name.isEmpty()) { + printf(" Rerun rddbcheck with the --orphan-group= switch to fix.\n\n"); + } + else { + printf(" Assign to group \"%s\" (y/N)?",(const char *)orphan_group_name); + if(UserResponse()) { + sql=QString(). + sprintf("update CART set GROUP_NAME=\"%s\" where NUMBER=%u", + (const char *)RDEscapeString(orphan_group_name), + q->value(0).toUInt()); + q1=new QSqlQuery(sql); + delete q1; + } + printf("\n"); + } + } + delete q; +} + + +void MainObject::CheckOrphanedCuts() +{ + QString sql; + QSqlQuery *q; + QSqlQuery *q1; + QSqlQuery *q2; + QFileInfo *file=NULL; + + sql="select CUTS.CUT_NAME,CUTS.DESCRIPTION from CUTS left join CART \ + on CUTS.CART_NUMBER=CART.NUMBER where CART.NUMBER is null"; + q=new QSqlQuery(sql); + while(q->next()) { + printf(" Cut %s [%s] is orphaned.\n", + (const char *)q->value(0).toString(), + (const char *)q->value(1).toString()); + // + // Try to repair it + // + sql=QString().sprintf("select NUMBER from CART where NUMBER=%d", + q->value(0).toString().left(6).toUInt()); + q1=new QSqlQuery(sql); + if(q1->first()) { + printf(" Repair it (y/N)?"); + if(UserResponse()) { + // + // FIXME: Regen Cart Data + // + sql=QString(). + sprintf("update CUTS set CART_NUMBER=%u where CUT_NAME=\"%s\"", + q1->value(0).toUInt(), + (const char *)q->value(0).toString()); + q2=new QSqlQuery(sql); + delete q2; + delete q1; + printf("\n"); + continue; + } + } + printf("\n"); + delete q1; + + // + // Try to recover audio + // + file=new QFileInfo(RDCut::pathName(q->value(0).toString())); + if(!file->exists()) { + printf(" Clear it (y/N)?"); + if(UserResponse()) { + sql=QString().sprintf("delete from CUTS where CUT_NAME=\"%s\"", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + } + } + else { + if(dump_cuts_dir.isEmpty()) { + printf(" Rerun rddbcheck with the --dump-cuts-dir= switch to fix.\n"); + } + else { + printf(" Clear it (y/N)?"); + if(UserResponse()) { + system("mv "+file->filePath()+" "+dump_cuts_dir+"/"); + sql=QString().sprintf("delete from CUTS where CUT_NAME=\"%s\"", + (const char *)q->value(0).toString()); + q1=new QSqlQuery(sql); + delete q1; + printf(" Saved audio in \"%s/%s\"\n",(const char *)dump_cuts_dir, + (const char *)file->fileName()); + } + } + } + printf("\n"); + delete file; + file=NULL; + } + delete q; +} + + +void MainObject::CheckOrphanedAudio() +{ + QDir dir(rdconfig->audioRoot()); + QStringList list=dir.entryList("??????_???.wav",QDir::Files); + for(unsigned i=0;ifirst()) { + printf(" File \"%s/%s\" is orphaned.\n", + (const char *)rdconfig->audioRoot(),(const char *)list[i]); + if(dump_cuts_dir.isEmpty()) { + printf( + " Rerun rddbcheck with the --dump-cuts-dir= switch to fix.\n\n"); + } + else { + printf(" Move to \"%s\" (y/N)? ",(const char *)dump_cuts_dir); + if(UserResponse()) { + system(QString().sprintf("mv %s/%s %s/", + (const char *)rdconfig->audioRoot(), + (const char *)list[i], + (const char *)dump_cuts_dir)); + printf(" Saved audio in \"%s/%s\"\n",(const char *)dump_cuts_dir, + (const char *)list[i]); + } + } + } + delete q; + } + } + } +} + + +void MainObject::ValidateAudioLengths() +{ + QString sql; + QSqlQuery *q; + RDWaveFile *wave=NULL; + + sql="select CUT_NAME,CART_NUMBER,LENGTH from CUTS order by CART_NUMBER"; + q=new QSqlQuery(sql); + while(q->next()) { + if(q->value(2).toInt()>0) { + wave=new RDWaveFile(RDCut::pathName(q->value(0).toString())); + if(wave->openWave()) { + if((int)wave->getExtTimeLength()<(q->value(2).toInt()-100)) { + SetCutLength(q->value(0).toString(),wave->getExtTimeLength()); + } + } + else { + SetCutLength(q->value(0).toString(),0); + } + delete wave; + } + } + delete q; +} + + +void MainObject::SetCutLength(const QString &cutname,int len) +{ + QString sql; + QSqlQuery *q; + RDCut *cut=new RDCut(cutname); + RDCart *cart=new RDCart(cut->cartNumber()); + + printf(" Cut %d [%s] in cart %06u [%s] has invalid length. Correct? (y/N) ", + cut->cutNumber(), + (const char *)cut->description(), + cart->number(), + (const char *)cart->title()); + fflush(NULL); + if(UserResponse()) { + fflush(NULL); + sql=QString().sprintf("update CUTS set START_POINT=0,END_POINT=%d,\ + FADEUP_POINT=-1,FADEDOWN_POINT=-1,\ + SEGUE_START_POINT=-1,SEGUE_END_POINT=-1,\ + TALK_START_POINT=-1,TALK_END_POINT=-1,\ + HOOK_START_POINT=-1,HOOK_END_POINT=-1,\ + PLAY_GAIN=0,LENGTH=%d \ + where CUT_NAME=\"%s\"", + len,len,(const char *)cutname); + q=new QSqlQuery(sql); + delete q; + cart->updateLength(); + cart->resetRotation(); + } + delete cart; + delete cut; +} + + +void MainObject::CleanTables(const QString &ext,QSqlQuery *table_q, + QSqlQuery *name_q) +{ + QString sql; + QSqlQuery *q1; + + table_q->seek(-1); + while(table_q->next()) { + if(!IsTableLinked(name_q,ext,table_q->value(0).toString())) { + printf(" Table %s is orphaned -- delete (y/N)? ", + (const char *)RDEscapeString(table_q->value(0).toString())); + fflush(NULL); + if(UserResponse()) { + sql=QString().sprintf("drop table %s", + (const char *)RDEscapeString(table_q->value(0).toString())); + q1=new QSqlQuery(sql); + delete q1; + } + } + } +} + + +void MainObject::CleanTables(const QString &ext,QSqlQuery *table_q) +{ + QString sql; + QSqlQuery *q1; + + table_q->seek(-1); + while(table_q->next()) { + if(table_q->value(0).toString().right(ext.length())==ext) { + printf(" Table %s is orphaned -- delete (y/N)? ", + (const char *)table_q->value(0).toString()); + fflush(NULL); + if(UserResponse()) { + sql=QString().sprintf("drop table %s", + (const char *)RDEscapeString(table_q->value(0).toString())); + q1=new QSqlQuery(sql); + delete q1; + } + } + } +} + + +bool MainObject::IsTableLinked(QSqlQuery *name_q,const QString &ext, + const QString &table) +{ + QString tablename; + + if(table.right(ext.length())!=ext) { + return true; + } + name_q->seek(-1); + while(name_q->next()) { + tablename=name_q->value(0).toString()+"_"+ext; + tablename.replace(" ","_"); + if(tablename==table) { + return true; + } + } + return false; +} + + +bool MainObject::UserResponse() +{ + char c=0; + + if(check_yes) { + printf("y\n"); + return true; + } + if(check_no) { + printf("n\n"); + return false; + } + while((c!='y')&&(c!='Y')&&(c!='n')&&(c!='N')) { + scanf("%c",&c); + if((c=='y')||(c=='Y')) { + scanf("%c",&c); + return true; + } + if(c=='\n') { + return false; + } + } + scanf("%c",&c); + return false; +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/utils/rddbcheck/rddbcheck.h b/utils/rddbcheck/rddbcheck.h new file mode 100644 index 00000000..67c69892 --- /dev/null +++ b/utils/rddbcheck/rddbcheck.h @@ -0,0 +1,75 @@ +// rddbcheck.h +// +// A Database Check/Repair Tool for Rivendell. +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: rddbcheck.h,v 1.10.6.1 2014/06/02 18:52:22 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDDBCHECK_H +#define RDDBCHECK_H + +#include + +#include +#include + +#include +#include +#include +#include + +#define RDDBCHECK_USAGE "[options]\n\nCheck the Rivendell database and audio store for consistency\nand correctness.\n\n--yes\n Answer all questions with 'yes'\n\n--no\n Answer all questions with 'no'\n\n--user=\n Connect using the Rivendell user (default is \"user\").\n\n--orphan-group=\n Move carts with missing/invalid GROUP information to the \n group.\n\n--dump-cuts-dir=\n Move orphaned cut audio to the directory.\n" + +// +// Global Variables +// +RDConfig *rdconfig; + + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + void CheckOrphanedTracks(); + void CheckClocks(); + void CheckEvents(); + void CheckOrphanedTables(); + void CheckCutCounts(); + void CheckPendingCarts(); + void CheckOrphanedCarts(); + void CheckOrphanedCuts(); + void CheckOrphanedAudio(); + void ValidateAudioLengths(); + void SetCutLength(const QString &cutname,int len); + void CleanTables(const QString &ext,QSqlQuery *table_q,QSqlQuery *name_q); + void CleanTables(const QString &ext,QSqlQuery *table_q); + bool IsTableLinked(QSqlQuery *name_q,const QString &ext,const QString &table); + bool UserResponse(); + bool check_yes; + bool check_no; + QString orphan_group_name; + QString dump_cuts_dir; + RDStation *check_station; + RDUser *check_user; +}; + + +#endif // RDDBCHECK_H diff --git a/utils/rddelete/Makefile.am b/utils/rddelete/Makefile.am new file mode 100644 index 00000000..195b836d --- /dev/null +++ b/utils/rddelete/Makefile.am @@ -0,0 +1,51 @@ +## automake.am +## +## Automake.am for rivendell/utils/rddelete +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.1.2.1 2013/04/29 22:03:23 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rddelete + +dist_rddelete_SOURCES = rddelete.cpp rddelete.h + +nodist_rddelete_SOURCES = moc_rddelete.cpp + +rddelete_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rddelete/rddelete.cpp b/utils/rddelete/rddelete.cpp new file mode 100644 index 00000000..d016bd44 --- /dev/null +++ b/utils/rddelete/rddelete.cpp @@ -0,0 +1,385 @@ +// rddelete.cpp +// +// A Batch Deleter for Rivendell. +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: rddelete.cpp,v 1.1.2.2 2013/11/13 23:36:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include + +/* +void SigHandler(int signo) +{ + switch(signo) { + case SIGTERM: + case SIGINT: + case SIGHUP: + import_run=false; + break; + } +} +*/ + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + // + // Initialize Data Structures + // + bool skip_db_check=false; + unsigned schema=0; + int obj_start=qApp->argc(); + del_carts=false; + del_logs=false; + del_verbose=false; + del_continue_after_error=false; + del_dry_run=false; + del_obj_ptr=0; + + // + // Read Command Options + // + del_cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"rddelete",RDDELETE_USAGE); + if(del_cmd->keys()<1) { + fprintf(stderr,"\n"); + fprintf(stderr,"%s",RDDELETE_USAGE); + fprintf(stderr,"\n"); + delete del_cmd; + exit(256); + } + for(unsigned i=0;ikeys();i++) { + if(del_cmd->key(i)=="--verbose") { + del_verbose=true; + } + if(del_cmd->key(i)=="--continue-after-error") { + del_continue_after_error=true; + } + if(del_cmd->key(i)=="--dry-run") { + del_dry_run=true; + } + if(del_cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + } + if(del_cmd->key(i)=="--carts") { + del_carts=true; + obj_start=i+2; + i=del_cmd->keys(); + break; + } + if(del_cmd->key(i)=="--logs") { + del_logs=true; + obj_start=i+2; + i=del_cmd->keys(); + break; + } + } + + // + // Read Object List + // + for(int i=obj_start;iargc();i++) { + del_obj_ids.push_back(qApp->argv()[i]); + if((del_obj_ids.back()=="--carts")||(del_obj_ids.back()=="--logs")) { + fprintf(stderr, + "rddelete: --carts and --logs switches are mutually exclusive\n"); + exit(256); + } + } + + // + // Read Configuration + // + del_config=new RDConfig(); + del_config->load(); + + // + // Open Database + // + QString err; + + del_db=RDInitDb(&schema,&err); + if(!del_db) { + fprintf(stderr,"rddelete: %s\n",(const char *)err); + exit(1); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr,"rddelete: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + connect (RDDbStatus(),SIGNAL(logText(RDConfig::LogPriority,const QString &)), + this,SLOT(log(RDConfig::LogPriority,const QString &))); + + // + // System Configuration + // + del_system=new RDSystem(); + + // + // Station Configuration + // + del_station=new RDStation(del_config->stationName()); + + // + // User + // + del_user=NULL; + + // + // RIPC Connection + // + del_ripc=new RDRipc(del_config->stationName()); + connect(del_ripc,SIGNAL(userChanged()),this,SLOT(userData())); + del_ripc->connectHost("localhost",RIPCD_TCP_PORT,del_config->password()); + + // + // Print Status Messages + // + if(del_verbose) { + printf("\n"); + printf("RDDelete v%s\n",VERSION); + if(del_carts) { + printf(" Deleting CARTS\n"); + } + if(del_logs) { + printf(" Deleting LOGS\n"); + } + if(del_continue_after_error) { + printf(" Continue after error mode is ON\n"); + } + else { + printf(" Continue after error mode is OFF\n"); + } + if(del_dry_run) { + printf(" Dry run mode is ON\n"); + } + else { + printf(" Dry run mode is OFF\n"); + } + + printf("\n"); + } +} + + +void MainObject::userData() +{ + // + // Get User Context + // + disconnect(del_ripc,SIGNAL(userChanged()),this,SLOT(userData())); + if(del_user!=NULL) { + delete del_user; + } + del_user=new RDUser(del_ripc->user()); + + // + // Process Objects + // + if(del_carts) { + if(!del_user->editAudio()) { + fprintf(stderr,"rdimport: user \"%s\" has no edit audio permission\n", + (const char *)del_user->name()); + exit(256); + } + DeleteCarts(); + } + + if(del_logs) { + if(!del_user->deleteLog()) { + fprintf(stderr,"rdimport: user \"%s\" has no delete log permission\n", + (const char *)del_user->name()); + exit(256); + } + DeleteLogs(); + } + + exit(0); +} + + +void MainObject::log(RDConfig::LogPriority prio,const QString &msg) +{ + del_config->log("rddelete",prio,msg); +} + + +void MainObject::DeleteCarts() +{ + unsigned cartnum=0; + + while(GetNextObject(&cartnum)) { + if(cartnum==0) { + if(!del_continue_after_error) { + exit(256); + } + } + else { + RDCart *cart=new RDCart(cartnum); + if(cart->exists()) { + QString title=cart->title(); + if(!cart->owner().isEmpty()) { + fprintf(stderr,"rddelete: cart %06u [%s] is a voice track\n", + cartnum,(const char *)title); + return; + } + if(del_dry_run) { + if(del_verbose) { + printf("would delete cart %06u [%s]\n",cartnum,(const char *)title); + } + } + else { + if(cart->remove(del_station,del_user,del_config)) { + if(del_verbose) { + printf("deleted cart %06u [%s]\n",cartnum,(const char *)title); + } + } + else { + fprintf(stderr,"unable to delete cart %06u [%s]\n",cartnum, + (const char *)title); + } + } + } + else { + fprintf(stderr,"cart %06u does not exist\n",cartnum); + if(!del_continue_after_error) { + exit(256); + } + } + delete cart; + } + } +} + + +void MainObject::DeleteLogs() +{ + QString logname; + + while(GetNextObject(&logname)) { + if(logname.isEmpty()&&(!del_continue_after_error)) { + exit(256); + } + else { + RDLog *log=new RDLog(logname); + if(log->exists()) { + if(del_dry_run) { + if(del_verbose) { + printf("would delete log \"%s\"\n",(const char *)logname); + } + } + else { + if(log->remove(del_station,del_user,del_config)) { + if(del_verbose) { + printf("deleted log \"%s\"\n",(const char *)logname); + } + } + else { + fprintf(stderr,"unable to delete log \"%s\".", + (const char *)logname); + } + } + } + else { + fprintf(stderr,"rddelete: log \"%s\" does not exist\n", + (const char *)logname); + if(!del_continue_after_error) { + exit(256); + } + } + delete log; + } + } +} + + +bool MainObject::GetNextObject(unsigned *cartnum) +{ + QString id; + bool ok=false; + + if(!GetNextObject(&id)) { + return false; + } + *cartnum=id.toUInt(&ok); + if((!ok)||(*cartnum==0)||(*cartnum>RD_MAX_CART_NUMBER)) { + fprintf(stderr,"invalid cart id: %s\n",(const char *)id); + *cartnum=0; + } + + return true; +} + + +bool MainObject::GetNextObject(QString *logname) +{ + if(del_obj_ids.size()==0) { + return GetNextStdinObject(logname); + } + if(del_obj_ptr>=del_obj_ids.size()) { + return false; + } + *logname=del_obj_ids[del_obj_ptr++]; + + return true; +} + + +bool MainObject::GetNextStdinObject(QString *logname) +{ + char c; + + *logname=""; + + if(read(0,&c,1)<=0) { + return false; + } + while(isspace(c)!=0) { + if(read(0,&c,1)<=0) { + return false; + } + } + *logname+=c; + if(read(0,&c,1)<=0) { + return true; + } + *logname+=c; + while(isspace(c)==0) { + if(read(0,&c,1)<=0) { + return true; + } + *logname+=c; + } + *logname=logname->stripWhiteSpace(); + + return true; +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/utils/rddelete/rddelete.h b/utils/rddelete/rddelete.h new file mode 100644 index 00000000..16e3cfe1 --- /dev/null +++ b/utils/rddelete/rddelete.h @@ -0,0 +1,82 @@ +// rddelete.h +// +// A Batch Deleter for Rivendell. +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: rddelete.h,v 1.1.2.1 2013/04/29 22:03:23 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDDELETE_H +#define RDDELETE_H + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RDDELETE_STDIN_BUFFER_LENGTH 1024 +#define RDDELETE_USAGE "[options] [ ...]\n\nDelete objects from a Rivendell system. Each type of object to be deleted\nis specified by an appropriate switch, followed optionally by\na list of objects. If no list is specified, then rddelete(1) will read\nthe list of objects from standard input.\n\nThe following object types can be deleted:\n--carts\n Delete carts. The values should be cart numbers.\n\n--logs\n Delete logs. The values should be log names.\n\nThe following options are available:\n\n--verbose\n Print progress messages during processing.\n\n--continue-after-error\n Continue processing list of objects even in the face of errors in\n that list.\n\n--dry-run\n Process list of objects, but don't actually delete anything.\n" + +class MainObject : public QObject +{ + Q_OBJECT; + public: + MainObject(QObject *parent=0,const char *name=0); + + private slots: + void userData(); + void log(RDConfig::LogPriority prio,const QString &line); + + private: + void DeleteCarts(); + void DeleteLogs(); + bool GetNextObject(unsigned *cartnum); + bool GetNextObject(QString *logname); + bool GetNextStdinObject(QString *logname); + QSqlDatabase *del_db; + RDSystem *del_system; + RDStation *del_station; + RDCmdSwitch *del_cmd; + RDRipc *del_ripc; + RDUser *del_user; + RDConfig *del_config; + bool del_carts; + bool del_logs; + bool del_verbose; + bool del_continue_after_error; + bool del_dry_run; + std::vector del_obj_ids; + unsigned del_obj_ptr; +}; + + +#endif // RDDELETE_H diff --git a/utils/rddgimport/Makefile.am b/utils/rddgimport/Makefile.am new file mode 100644 index 00000000..7d60b228 --- /dev/null +++ b/utils/rddgimport/Makefile.am @@ -0,0 +1,72 @@ +## automake.am +## +## Automake.am for rivendell/utils/rddgimport +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.1.2.1 2013/01/04 18:41:14 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rddgimport_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rddgimport_*.qm + +all: + @QT_BIN@/lupdate rddgimport.pro + @QT_BIN@/lrelease rddgimport.pro + +bin_PROGRAMS = rddgimport + +dist_rddgimport_SOURCES = event.cpp event.h\ + rddgimport.cpp rddgimport.h + +nodist_rddgimport_SOURCES = moc_rddgimport.cpp + +rddgimport_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rddgimport.pro\ + rddgimport_de.ts\ + rddgimport_es.ts\ + rddgimport_fr.ts\ + rddgimport_nb.ts\ + rddgimport_nn.ts\ + rddgimport_pt_BR.ts + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rddgimport/event.cpp b/utils/rddgimport/event.cpp new file mode 100644 index 00000000..d0989714 --- /dev/null +++ b/utils/rddgimport/event.cpp @@ -0,0 +1,88 @@ +// event.cpp +// +// Abstract a Dial Global Spot Event +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: event.cpp,v 1.1.2.1 2013/01/04 18:41:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +Event::Event() +{ + evt_length=0; +} + + +QTime Event::time() const +{ + return evt_time; +} + + +void Event::setTime(const QTime &time) +{ + evt_time=time; +} + + +int Event::length() const +{ + return evt_length; +} + + +void Event::setLength(int msec) +{ + evt_length=msec; +} + + +QString Event::isci() const +{ + return evt_isci; +} + + +void Event::setIsci(const QString &str) +{ + evt_isci=str; +} + + +QString Event::title() const +{ + return evt_title; +} + + +void Event::setTitle(const QString &str) +{ + evt_title=str; +} + + +QString Event::client() const +{ + return evt_client; +} + + +void Event::setClient(const QString &str) +{ + evt_client=str; +} diff --git a/utils/rddgimport/event.h b/utils/rddgimport/event.h new file mode 100644 index 00000000..ac85fc42 --- /dev/null +++ b/utils/rddgimport/event.h @@ -0,0 +1,53 @@ +// event.h +// +// Abstract a Dial Global Spot Event +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: event.h,v 1.1.2.1 2013/01/04 18:41:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef EVENT_H +#define EVENT_H + +#include +#include + +class Event +{ + public: + Event(); + QTime time() const; + void setTime(const QTime &time); + int length() const; + void setLength(int msec); + QString isci() const; + void setIsci(const QString &str); + QString title() const; + void setTitle(const QString &str); + QString client() const; + void setClient(const QString &str); + + private: + QTime evt_time; + int evt_length; + QString evt_isci; + QString evt_title; + QString evt_client; +}; + + +#endif // EVENT_H diff --git a/utils/rddgimport/rddgimport.cpp b/utils/rddgimport/rddgimport.cpp new file mode 100644 index 00000000..80ed6688 --- /dev/null +++ b/utils/rddgimport/rddgimport.cpp @@ -0,0 +1,670 @@ +// rddgimport.cpp +// +// A Qt-based application for importing Dial Global CDN downloads +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: rddgimport.cpp,v 1.1.2.12 2014/01/21 21:59:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +MainWidget::MainWidget(QWidget *parent,const char *name) + : QWidget(parent,name) +{ + dg_user=NULL; + dg_group=NULL; + dg_svc=NULL; + + QString sql; + RDSqlQuery *q; + + // + // Read Command Options + // + RDCmdSwitch *cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"rddgimport","\n"); + delete cmd; + + // + // Set Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + SetCaption(); + + // + // Load Local Configs + // + dg_config=new RDConfig(); + dg_config->load(); + + // + // Open Database + // + dg_db=QSqlDatabase::addDatabase(dg_config->mysqlDriver()); + if(!dg_db) { + QMessageBox::warning(this,tr("Database Error"), + tr("Can't Connect","Unable to connect to mySQL Server!")); + exit(0); + } + dg_db->setDatabaseName(dg_config->mysqlDbname()); + dg_db->setUserName(dg_config->mysqlUsername()); + dg_db->setPassword(dg_config->mysqlPassword()); + dg_db->setHostName(dg_config->mysqlHostname()); + if(!dg_db->open()) { + QMessageBox::warning(this,tr("Can't Connect"), + tr("Unable to connect to mySQL Server!")); + dg_db->removeDatabase(dg_config->mysqlDbname()); + exit(0); + } + + // + // Fonts + // + QFont main_font("helvetica",12,QFont::Normal); + main_font.setPixelSize(12); + setFont(main_font); + QFont label_font("helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + // + // Configuration Elements + // + dg_station=new RDStation(dg_config->stationName(),this); + dg_library_conf=new RDLibraryConf(dg_config->stationName(),0); + dg_ripc=new RDRipc(dg_config->stationName(),this); + connect(dg_ripc,SIGNAL(userChanged()),this,SLOT(userChangedData())); + dg_ripc->connectHost("localhost",RIPCD_TCP_PORT,dg_config->password()); + + // + // Service Selector + // + dg_service_box=new QComboBox(this); + connect(dg_service_box,SIGNAL(activated(int)), + this,SLOT(serviceActivatedData(int))); + dg_service_label=new QLabel(dg_service_box,tr("Service:"),this); + dg_service_label->setFont(label_font); + dg_service_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // File Selector + // + dg_filename_edit=new QLineEdit(this); + connect(dg_filename_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(filenameChangedData(const QString &))); + dg_filename_label=new QLabel(dg_filename_edit,tr("Filename:"),this); + dg_filename_label->setFont(label_font); + dg_filename_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + dg_filename_button=new QPushButton(tr("Select"),this); + dg_filename_button->setFont(main_font); + connect(dg_filename_button,SIGNAL(clicked()), + this,SLOT(filenameSelectedData())); + + // + // Date Selector + // + dg_date_edit=new QDateEdit(this); + dg_date_edit->setDate(QDate::currentDate()); + dg_date_label=new QLabel(dg_date_edit,tr("Date:"),this); + dg_date_label->setFont(label_font); + dg_date_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + dg_date_button=new QPushButton(tr("Select"),this); + dg_date_button->setFont(main_font); + connect(dg_date_button,SIGNAL(clicked()), + this,SLOT(dateSelectedData())); + + // + // Progress Bar + // + dg_bar=new RDBusyBar(this); + dg_bar->setDisabled(true); + + // + // Messages Area + // + dg_messages_text=new QTextEdit(this); + dg_messages_text->setReadOnly(true); + dg_messages_label=new QLabel(dg_service_box,tr("Messages"),this); + dg_messages_label->setFont(label_font); + dg_messages_label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + + // + // Process Button + // + dg_process_button=new QPushButton(tr("Process"),this); + dg_process_button->setFont(label_font); + dg_process_button->setDisabled(true); + connect(dg_process_button,SIGNAL(clicked()),this,SLOT(processData())); + + // + // Close Button + // + dg_close_button=new QPushButton(tr("Close"),this); + dg_close_button->setFont(label_font); + connect(dg_close_button,SIGNAL(clicked()),this,SLOT(quitMainWidget())); + + // + // Load Service List + // + sql="select NAME,AUTOSPOT_GROUP from SERVICES order by NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + if(!q->value(1).toString().isEmpty()) { + dg_service_box->insertItem(q->value(0).toString()); + } + } + delete q; + if(dg_service_box->count()==0) { + QMessageBox::information(this,tr("RDDgImport"), + tr("No AutoSpot-enabled services found!")); + exit(0); + } + serviceActivatedData(0); +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(400,300); +} + + +void MainWidget::serviceActivatedData(int index) +{ + if(dg_svc!=NULL) { + delete dg_svc; + } + dg_svc=new RDSvc(dg_service_box->currentText()); + if(dg_group!=NULL) { + delete dg_group; + } + dg_group=new RDGroup(dg_svc->autospotGroup()); +} + + +void MainWidget::filenameChangedData(const QString &str) +{ + dg_process_button->setDisabled(str.isEmpty()); +} + + +void MainWidget::filenameSelectedData() +{ + QString filename=dg_filename_edit->text(); + if(filename.isEmpty()) { + filename=RDGetHomeDir(); + } + filename= + QFileDialog::getOpenFileName(filename,tr("Text Files")+" (*.txt *.TXT);;"+ + tr("All Files")+" (*.*)",this); + if(!filename.isEmpty()) { + dg_filename_edit->setText(filename); + filenameChangedData(filename); + } +} + + +void MainWidget::dateSelectedData() +{ + QDate date=dg_date_edit->date(); + QDate now=QDate::currentDate(); + RDDateDialog *d=new RDDateDialog(now.year(),now.year()+1,this); + if(d->exec(&date)==0) { + dg_date_edit->setDate(date); + } + + delete d; +} + + +void MainWidget::processData() +{ + ActivateBar(true); + if(LoadEvents()) { + if(ImportAudio()) { + if(WriteTrafficFile()) { + QMessageBox::information(this,tr("RDDgImport"), + tr("Processing Complete!")); + } + } + } + ActivateBar(false); +} + + +void MainWidget::userChangedData() +{ + if(dg_user!=NULL) { + delete dg_user; + } + dg_user=new RDUser(dg_ripc->user()); + SetCaption(); +} + + +void MainWidget::quitMainWidget() +{ + qApp->quit(); +} + + +void MainWidget::resizeEvent(QResizeEvent *e) +{ + dg_service_label->setGeometry(10,10,80,20); + dg_service_box->setGeometry(95,10,size().width()-180,20); + dg_filename_label->setGeometry(10,37,80,20); + dg_filename_edit->setGeometry(95,37,size().width()-180,20); + dg_filename_button->setGeometry(size().width()-70,35,60,25); + dg_date_label->setGeometry(10,67,80,20); + dg_date_edit->setGeometry(95,67,100,20); + dg_date_button->setGeometry(205,65,60,25); + dg_bar->setGeometry(10,102,size().width()-20,20); + dg_messages_label->setGeometry(10,129,size().width()-20,20); + dg_messages_text->setGeometry(10,151,size().width()-20,size().height()-197); + dg_process_button->setGeometry(10,size().height()-35,70,25); + dg_close_button->setGeometry(size().width()-60,size().height()-35,50,25); +} + + +void MainWidget::SetCaption() +{ + QString username=tr("[unknown]"); + if(dg_user!=NULL) { + username=dg_user->name(); + } + setCaption(tr("RDDgImport")+" v"+VERSION+" "+tr("User")+": "+username); +} + + +bool MainWidget::LoadEvents() +{ + FILE *f=NULL; + char data[1024]; + QString line; + QTime time; + int length; + QString isci; + + dg_events.clear(); + if((f=fopen(dg_filename_edit->text(),"r"))==NULL) { + QMessageBox::warning(this,tr("RDDgImport"), + tr("Unable to open source file")+"["+ + strerror(errno)+"]."); + return false; + } + while(fgets(data,1024,f)!=NULL) { + line=QString(data); + time=GetTime(line.left(8)); + if(time.isValid()) { + length=GetLength(line.mid(80,3)); + if(length>0) { + isci=GetIsci(line.mid(10,15)); + if(!isci.isEmpty()) { + dg_events.push_back(new Event()); + dg_events.back()->setTime(time); + switch(length) { + case 30000: + dg_events.back()->setLength(29000); + break; + + case 60000: + dg_events.back()->setLength(58000); + break; + + default: + LogMessage(tr("WARNING: Non-standard length for ISCI code")+ + " \""+isci+"\"."); + break; + } + dg_events.back()->setIsci(isci); + dg_events.back()->setTitle(line.mid(48,25)); + dg_events.back()->setClient(line.mid(32,11)); + dg_carts[isci]=0; + } + } + } + } + fclose(f); + return true; +} + + +bool MainWidget::ImportAudio() +{ + if(dg_group->freeCartQuantity()<(int)dg_carts.size()) { + QMessageBox::warning(this,tr("RDDgImport"), + tr("Insufficient free carts in target group!")); + return false; + } + for(std::map::const_iterator it=dg_carts.begin(); + it!=dg_carts.end();it++) { + Event *evt=GetEvent(it->first); + if(!CheckSpot(evt->isci())) { + ImportSpot(evt); + } + } + return true; +} + + +bool MainWidget::WriteTrafficFile() +{ + FILE *f=NULL; + QString outname; + + // + // Open Output File + // + outname=RDDateDecode(dg_svc->importPath(RDSvc::Traffic,RDSvc::Linux), + dg_date_edit->date()); + if((f=fopen(outname,"w"))==NULL) { + LogMessage(tr("WARNING: Unable to open traffic output file")+" \""+ + outname+"\" ["+strerror(errno)+"]."); + return false; + } + + // + // Write Records + // + for(unsigned i=0;itime().toString("hh:mm:ss")); + fprintf(f,"%06u ",dg_carts[evt->isci()]); + fprintf(f,"%-34s ",(const char *)evt->title()); + if(evt->length()<600000) { + fprintf(f,"0"); + } + fprintf(f,"%s ",(const char *)RDGetTimeLength(evt->length(),true,false)); + fprintf(f,"%-32s ",(const char *)evt->isci()); + fprintf(f,"%032u",i); + fprintf(f,"\n"); + } + + // + // Clean Up + // + fclose(f); + return true; +} + + +bool MainWidget::CheckSpot(const QString &isci) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + bool ret=false; + QDate today=QDate::currentDate(); + QDate killdate=dg_date_edit->date().addDays(RDDGIMPORT_KILLDATE_OFFSET); + + sql=QString("select CUT_NAME,CUTS.START_DATETIME,CUTS.END_DATETIME ")+ + "from CART left join CUTS on CART.NUMBER=CUTS.CART_NUMBER "+ + "where (CART.GROUP_NAME=\""+RDEscapeString(dg_svc->autospotGroup())+"\")&&" + "(CUTS.ISCI=\""+RDEscapeString(isci)+"\")"; + q=new RDSqlQuery(sql); + while(q->next()) { + dg_carts[isci]=RDCut::cartNumber(q->value(0).toString()); + if(q->value(2).isNull()||(q->value(2).toDateTime().date()value(1).isNull()) { + sql+="START_DATETIME=\""+today.toString("yyyy-MM-dd")+" 00:00:00\","; + } + sql+="END_DATETIME=\""+killdate.toString("yyyy-MM-dd")+" 23:59:59\" "; + sql+="where CUT_NAME=\""+q->value(0).toString()+"\""; + q1=new RDSqlQuery(sql); + delete q1; + } + ret=true; + } + delete q; + + return ret; +} + + +bool MainWidget::ImportSpot(Event *evt) +{ + RDCart *cart; + RDCut *cut; + int cutnum; + RDAudioImport *conv; + RDAudioImport::ErrorCode conv_err; + RDAudioConvert::ErrorCode audio_conv_err; + RDSettings settings; + QString dir=RDGetPathPart(dg_filename_edit->text()); + QDateTime start=QDateTime(QDate::currentDate(),QTime(0,0,0)); + QString audiofile; + + // + // Find File + // + audiofile=dir+"/"+evt->isci()+"."+QString(RDDGIMPORT_FILE_EXTENSION).lower(); + if(!QFile::exists(audiofile)) { + audiofile=dir+"/"+evt->isci()+"."+ + QString(RDDGIMPORT_FILE_EXTENSION).upper(); + if(!QFile::exists(audiofile)) { + LogMessage(tr("Missing audio for")+" "+evt->isci()+" ["+evt->title()+ + " / "+evt->client()+"]."); + return false; + } + } + + // + // Initialize Audio Importer + // + settings.setNormalizationLevel(dg_library_conf->ripperLevel()/100); + settings.setChannels(dg_library_conf->defaultChannels()); + + if((dg_carts[evt->isci()]=dg_group->nextFreeCart())==0) { + LogMessage(tr("Unable to allocate new cart for")+" "+evt->isci()+" ["+ + evt->title()+" / "+evt->client()+"]."); + return false; + } + if(evt==NULL) { + LogMessage(tr("Unable to find event for ISCI code")+" \""+ + evt->isci()+"\"."); + return false; + } + cart=new RDCart(dg_carts[evt->isci()]); + cart->create(dg_group->name(),RDCart::Audio); + if((cutnum=cart->addCut(dg_library_conf->defaultLayer(), + dg_library_conf->defaultBitrate(), + dg_library_conf->defaultChannels(), + evt->isci(),evt->title()))<0) { + LogMessage(tr("WARNING: Unable to create cut for cart")+" \""+ + QString().sprintf("%u",dg_carts[evt->isci()])+"\"."); + delete cart; + return false; + } + cut=new RDCut(dg_carts[evt->isci()],cutnum); + cut->setStartDatetime(start,true); + cut->setEndDatetime(QDateTime(dg_date_edit->date(). + addDays(RDDGIMPORT_KILLDATE_OFFSET), + QTime(23,59,59)),true); + + conv=new RDAudioImport(dg_station,dg_config,this); + conv->setCartNumber(dg_carts[evt->isci()]); + conv->setCutNumber(cutnum); + conv->setSourceFile(audiofile); + conv->setDestinationSettings(&settings); + conv->setUseMetadata(false); + conv_err=conv-> + runImport(dg_user->name(),dg_user->password(),&audio_conv_err); + switch(conv_err) { + case RDAudioImport::ErrorOk: + break; + + default: + LogMessage(tr("Importer error")+" ["+audiofile+"]: "+ + RDAudioImport::errorText(conv_err,audio_conv_err)); + } + cart->setTitle(evt->title()); + cart->setArtist(evt->client()); + cart->setForcedLength(evt->length()); + cart->setEnforceLength(true); + delete conv; + delete cut; + delete cart; + + return true; +} + + +void MainWidget::ActivateBar(bool state) +{ + if(state) { + dg_messages_text->clear(); + } + dg_bar->setEnabled(state); + dg_bar->activate(state); + dg_filename_edit->setDisabled(state); + dg_filename_button->setDisabled(state); + dg_date_edit->setDisabled(state); + dg_date_button->setDisabled(state); + dg_process_button->setDisabled(state); + dg_close_button->setDisabled(state); + qApp->processEvents(); +} + + +Event *MainWidget::GetEvent(const QString &isci) +{ + for(unsigned i=0;iisci()==isci) { + return dg_events[i]; + } + } + return NULL; +} + + +QTime MainWidget::GetTime(const QString &str) const +{ + QStringList fields; + QTime ret; + bool ok=false; + + fields=fields.split(":",str); + if(fields.size()==3) { + int hour=fields[0].toInt(&ok); + if(ok&&(hour>=0)&&(hour<=23)) { + int minute=fields[1].toInt(&ok); + if(ok&&(minute>=0)&&(minute<=59)) { + int second=fields[2].toInt(&ok); + if(ok&&(second>=0)&&(second<=59)) { + ret=QTime(hour,minute,second); + } + } + } + } + return ret; +} + + +int MainWidget::GetLength(const QString &str) const +{ + int ret=0; + int len; + bool ok=false; + + if(str.left(1)==":") { + len=str.right(2).toInt(&ok); + if(ok&&(len>=0)&&(len<=60)) { + ret=len*1000; + } + } + + return ret; +} + + +QString MainWidget::GetIsci(const QString &str) const +{ + QString ret; + + if(str.stripWhiteSpace().length()==15) { + ret=str.stripWhiteSpace(); + } + return ret; +} + + +void MainWidget::LogMessage(const QString &str) +{ + dg_messages_text->append(str+"\n"); + dg_messages_text->scrollToBottom(); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(), + "."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rdgpimon_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} diff --git a/utils/rddgimport/rddgimport.h b/utils/rddgimport/rddgimport.h new file mode 100644 index 00000000..3bd31238 --- /dev/null +++ b/utils/rddgimport/rddgimport.h @@ -0,0 +1,114 @@ +// rddgimport.h +// +// A Qt-based application for importing Dial Global CDN downloads +// +// (C) Copyright 2012 Fred Gleason +// +// $Id: rddgimport.h,v 1.1.2.4 2013/02/05 01:35:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDDGIMPORT_H +#define RDDGIMPORT_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define RDDGIMPORT_USAGE "\n" +#define RDDGIMPORT_KILLDATE_OFFSET 7 +#define RDDGIMPORT_FILE_EXTENSION "mp3" + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + + private slots: + void serviceActivatedData(int index); + void filenameChangedData(const QString &str); + void filenameSelectedData(); + void dateSelectedData(); + void processData(); + void userChangedData(); + void quitMainWidget(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void SetCaption(); + bool LoadEvents(); + bool ImportAudio(); + bool WriteTrafficFile(); + bool CheckSpot(const QString &isci); + bool ImportSpot(Event *evt); + void ActivateBar(bool state); + Event *GetEvent(const QString &isci); + QTime GetTime(const QString &str) const; + int GetLength(const QString &str) const; + QString GetIsci(const QString &str) const; + void LogMessage(const QString &str); + QLabel *dg_service_label; + QComboBox *dg_service_box; + QLabel *dg_filename_label; + QLineEdit *dg_filename_edit; + QPushButton *dg_filename_button; + QLabel *dg_date_label; + QDateEdit *dg_date_edit; + QPushButton *dg_date_button; + QLabel *dg_messages_label; + QTextEdit *dg_messages_text; + RDBusyBar *dg_bar; + QPushButton *dg_process_button; + QPushButton *dg_close_button; + std::map dg_carts; + std::vector dg_events; + RDGroup *dg_group; + RDSvc *dg_svc; + RDRipc *dg_ripc; + RDUser *dg_user; + RDStation *dg_station; + RDLibraryConf *dg_library_conf; + RDConfig *dg_config; + QSqlDatabase *dg_db; +}; + + +#endif // RDDGIMPORT_H diff --git a/utils/rddgimport/rddgimport.pro b/utils/rddgimport/rddgimport.pro new file mode 100644 index 00000000..b5004222 --- /dev/null +++ b/utils/rddgimport/rddgimport.pro @@ -0,0 +1,33 @@ +# utils.pro +# +# The utils/ QMake project file for Rivendell +# +# (C) Copyright 2003-2006 Fred Gleason +# +# $Id: rddgimport.pro,v 1.1.2.1 2013/01/04 18:41:14 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +SOURCES += event.cpp +SOURCES += rddgimport.cpp + +HEADERS += event.h +HEADERS += rddgimport.h + +TRANSLATIONS += rddgimport_de.ts +TRANSLATIONS += rddgimport_es.ts +TRANSLATIONS += rddgimport_fr.ts +TRANSLATIONS += rddgimport_nb.ts +TRANSLATIONS += rddgimport_nn.ts +TRANSLATIONS += rddgimport_pt_BR.ts diff --git a/utils/rddgimport/rddgimport_de.ts b/utils/rddgimport/rddgimport_de.ts new file mode 100644 index 00000000..fc2f92ac --- /dev/null +++ b/utils/rddgimport/rddgimport_de.ts @@ -0,0 +1,114 @@ + + + MainWidget + + Close + + + + Process + + + + Filename: + + + + Select + + + + Date: + + + + RDDgImport + + + + Unable to open source file + + + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Unable to find event for ISCI code + + + + [unknown] + + + + User + + + + Insufficient free carts in target group! + + + + Service: + + + + No AutoSpot-enabled services found! + + + + Messages + + + + Missing audio for + + + + Unable to allocate new cart for + + + + Importer error + + + + Processing Complete! + + + + WARNING: Non-standard length for ISCI code + + + + WARNING: Unable to open traffic output file + + + + WARNING: Unable to create cut for cart + + + + Text Files + + + + All Files + + + + diff --git a/utils/rddgimport/rddgimport_es.ts b/utils/rddgimport/rddgimport_es.ts new file mode 100644 index 00000000..fc2f92ac --- /dev/null +++ b/utils/rddgimport/rddgimport_es.ts @@ -0,0 +1,114 @@ + + + MainWidget + + Close + + + + Process + + + + Filename: + + + + Select + + + + Date: + + + + RDDgImport + + + + Unable to open source file + + + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Unable to find event for ISCI code + + + + [unknown] + + + + User + + + + Insufficient free carts in target group! + + + + Service: + + + + No AutoSpot-enabled services found! + + + + Messages + + + + Missing audio for + + + + Unable to allocate new cart for + + + + Importer error + + + + Processing Complete! + + + + WARNING: Non-standard length for ISCI code + + + + WARNING: Unable to open traffic output file + + + + WARNING: Unable to create cut for cart + + + + Text Files + + + + All Files + + + + diff --git a/utils/rddgimport/rddgimport_fr.ts b/utils/rddgimport/rddgimport_fr.ts new file mode 100644 index 00000000..fc2f92ac --- /dev/null +++ b/utils/rddgimport/rddgimport_fr.ts @@ -0,0 +1,114 @@ + + + MainWidget + + Close + + + + Process + + + + Filename: + + + + Select + + + + Date: + + + + RDDgImport + + + + Unable to open source file + + + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Unable to find event for ISCI code + + + + [unknown] + + + + User + + + + Insufficient free carts in target group! + + + + Service: + + + + No AutoSpot-enabled services found! + + + + Messages + + + + Missing audio for + + + + Unable to allocate new cart for + + + + Importer error + + + + Processing Complete! + + + + WARNING: Non-standard length for ISCI code + + + + WARNING: Unable to open traffic output file + + + + WARNING: Unable to create cut for cart + + + + Text Files + + + + All Files + + + + diff --git a/utils/rddgimport/rddgimport_nb.ts b/utils/rddgimport/rddgimport_nb.ts new file mode 100644 index 00000000..fc2f92ac --- /dev/null +++ b/utils/rddgimport/rddgimport_nb.ts @@ -0,0 +1,114 @@ + + + MainWidget + + Close + + + + Process + + + + Filename: + + + + Select + + + + Date: + + + + RDDgImport + + + + Unable to open source file + + + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Unable to find event for ISCI code + + + + [unknown] + + + + User + + + + Insufficient free carts in target group! + + + + Service: + + + + No AutoSpot-enabled services found! + + + + Messages + + + + Missing audio for + + + + Unable to allocate new cart for + + + + Importer error + + + + Processing Complete! + + + + WARNING: Non-standard length for ISCI code + + + + WARNING: Unable to open traffic output file + + + + WARNING: Unable to create cut for cart + + + + Text Files + + + + All Files + + + + diff --git a/utils/rddgimport/rddgimport_nn.ts b/utils/rddgimport/rddgimport_nn.ts new file mode 100644 index 00000000..fc2f92ac --- /dev/null +++ b/utils/rddgimport/rddgimport_nn.ts @@ -0,0 +1,114 @@ + + + MainWidget + + Close + + + + Process + + + + Filename: + + + + Select + + + + Date: + + + + RDDgImport + + + + Unable to open source file + + + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Unable to find event for ISCI code + + + + [unknown] + + + + User + + + + Insufficient free carts in target group! + + + + Service: + + + + No AutoSpot-enabled services found! + + + + Messages + + + + Missing audio for + + + + Unable to allocate new cart for + + + + Importer error + + + + Processing Complete! + + + + WARNING: Non-standard length for ISCI code + + + + WARNING: Unable to open traffic output file + + + + WARNING: Unable to create cut for cart + + + + Text Files + + + + All Files + + + + diff --git a/utils/rddgimport/rddgimport_pt_BR.ts b/utils/rddgimport/rddgimport_pt_BR.ts new file mode 100644 index 00000000..fc2f92ac --- /dev/null +++ b/utils/rddgimport/rddgimport_pt_BR.ts @@ -0,0 +1,114 @@ + + + MainWidget + + Close + + + + Process + + + + Filename: + + + + Select + + + + Date: + + + + RDDgImport + + + + Unable to open source file + + + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Unable to find event for ISCI code + + + + [unknown] + + + + User + + + + Insufficient free carts in target group! + + + + Service: + + + + No AutoSpot-enabled services found! + + + + Messages + + + + Missing audio for + + + + Unable to allocate new cart for + + + + Importer error + + + + Processing Complete! + + + + WARNING: Non-standard length for ISCI code + + + + WARNING: Unable to open traffic output file + + + + WARNING: Unable to create cut for cart + + + + Text Files + + + + All Files + + + + diff --git a/utils/rddiscimport/Makefile.am b/utils/rddiscimport/Makefile.am new file mode 100644 index 00000000..1deddb88 --- /dev/null +++ b/utils/rddiscimport/Makefile.am @@ -0,0 +1,73 @@ +## automake.am +## +## Automake.am for rivendell/utils/rddiscimport +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.1.2.1 2013/12/03 23:34:35 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rddiscimport_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rddiscimport_*.qm + +all: + @QT_BIN@/lupdate rddiscimport.pro + @QT_BIN@/lrelease rddiscimport.pro + +bin_PROGRAMS = rddiscimport + +dist_rddiscimport_SOURCES = metalibrary.cpp metalibrary.h\ + metarecord.cpp metarecord.h\ + rddiscimport.cpp rddiscimport.h + +nodist_rddiscimport_SOURCES = moc_rddiscimport.cpp + +rddiscimport_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rddiscimport.pro\ + rddiscimport_de.ts\ + rddiscimport_es.ts\ + rddiscimport_fr.ts\ + rddiscimport_nb.ts\ + rddiscimport_nn.ts\ + rddiscimport_pt_BR.ts + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rddiscimport/metalibrary.cpp b/utils/rddiscimport/metalibrary.cpp new file mode 100644 index 00000000..362ba6e9 --- /dev/null +++ b/utils/rddiscimport/metalibrary.cpp @@ -0,0 +1,226 @@ +// metalibrary.cpp +// +// Abstract a library of metadata. +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: metalibrary.cpp,v 1.1.2.3 2013/12/04 22:22:49 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include + +#include + +MetaLibrary::MetaLibrary() +{ +} + + +MetaLibrary::~MetaLibrary() +{ + for(unsigned i=0;idiscId()==disc_id) { + ret++; + } + } + return ret; +} + + +MetaRecord *MetaLibrary::track(const QString &disc_id,int track_num) +{ + for(unsigned i=0;idiscId()==disc_id)&& + (meta_tracks[i]->trackNumber()==track_num)){ + return meta_tracks[i]; + } + } + + return NULL; +} + + +int MetaLibrary::load(const QString &filename) +{ + FILE *f=NULL; + char line[32768]; + QStringList f0; + + // + // Open Source File + // + if((f=fopen(filename,"r"))==NULL) { + return -1; + } + + // + // Load Headers + // + if(fgets(line,32768,f)==NULL) { + fclose(f); + return -1; + } + meta_headers=Split(",",QString(line).lower()); + + // + // Load Lines + // + while(fgets(line,1024,f)!=NULL) { + f0=Split(",",line); + if(f0.size()==meta_headers.size()) { + LoadLine(f0); + } + } + + fclose(f); + + return meta_tracks.size(); +} + + +void MetaLibrary::clear() +{ + for(unsigned i=0;isetDiscId(fields[i]); + } + if(meta_headers[i]=="cut") { + m->setTrackNumber(fields[i].toInt()-1); + } + if(meta_headers[i]=="songid") { + m->setSongId(fields[i]); + } + if(meta_headers[i]=="year") { + m->setYear(fields[i].toInt()); + } + if(meta_headers[i]=="bpm") { + m->setBeatsPerMinute(fields[i].toInt()); + } + if(meta_headers[i]=="title") { + m->setTitle(fields[i]); + } + if(meta_headers[i]=="artist") { + m->setArtist(fields[i]); + } + if(meta_headers[i]=="version") { + m->setVersion(fields[i]); + } + if(meta_headers[i]=="album") { + m->setAlbum(fields[i]); + } + if(meta_headers[i]=="composer") { + m->setComposer(fields[i]); + } + if(meta_headers[i]=="publisher") { + m->setPublisher(fields[i]); + } + if(meta_headers[i]=="client") { + m->setClient(fields[i]); + } + if(meta_headers[i]=="agency") { + m->setAgency(fields[i]); + } + if(meta_headers[i]=="license") { + m->setLicense(fields[i]); + } + if(meta_headers[i]=="recordlabel") { + m->setLabel(fields[i]); + } + if(meta_headers[i]=="isrc") { + m->setIsrc(fields[i]); + } + if(meta_headers[i]=="ending") { + m->setEnding(fields[i]); + } + if(meta_headers[i]=="intro") { + m->setIntroLength(RDSetTimeLength(fields[i])); + } + if(meta_headers[i]=="length") { + m->setLength(RDSetTimeLength(fields[i])); + } + if(meta_headers[i]=="aux3") { + m->setSegueStart(RDSetTimeLength(fields[i])); + } + } +} + + +QStringList MetaLibrary::Split(const QString &sep,const QString &str) +{ + QString buf; + QStringList ret; + bool quoted=false; + + for(unsigned i=0;i +// +// $Id: metalibrary.h,v 1.1.2.1 2013/12/03 23:34:35 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef METALIBRARY_H +#define METALIBRARY_H + +#include + +#include +#include + +#include + +class MetaLibrary +{ + public: + MetaLibrary(); + ~MetaLibrary(); + unsigned totalTracks(); + unsigned tracks(const QString &disc_id); + MetaRecord *track(const QString &disc_id,int track_num); + int load(const QString &filename); + void clear(); + + private: + void LoadLine(const QStringList fields); + QStringList Split(const QString &sep,const QString &str); + std::vector meta_tracks; + QStringList meta_headers; +}; + + +#endif // METALIBRARY_H diff --git a/utils/rddiscimport/metarecord.cpp b/utils/rddiscimport/metarecord.cpp new file mode 100644 index 00000000..625fb2e6 --- /dev/null +++ b/utils/rddiscimport/metarecord.cpp @@ -0,0 +1,337 @@ +// metarecord.cpp +// +// Container class for metadata +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: metarecord.cpp,v 1.1.2.3 2013/12/04 22:22:49 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +MetaRecord::MetaRecord(const QString &disc_id,int track_num) +{ + meta_disc_id=disc_id; + meta_track_number=track_num; +} + + +MetaRecord::MetaRecord() +{ + meta_disc_id=""; + meta_track_number=0; +} + + +QString MetaRecord::discId() const +{ + return meta_disc_id; +} + + +void MetaRecord::setDiscId(const QString &disc_id) +{ + meta_disc_id=disc_id; +} + + +int MetaRecord::trackNumber() const +{ + return meta_track_number; +} + + +void MetaRecord::setTrackNumber(int track_num) +{ + meta_track_number=track_num; +} + + +QString MetaRecord::songId() const +{ + return meta_song_id; +} + + +void MetaRecord::setSongId(const QString &str) +{ + meta_song_id=str; +} + + +QString MetaRecord::title() const +{ + return meta_title; +} + + +void MetaRecord::setTitle(const QString &str) +{ + meta_title=str; +} + + +QString MetaRecord::artist() const +{ + return meta_artist; +} + + +void MetaRecord::setArtist(const QString &str) +{ + meta_artist=str; +} + + +QString MetaRecord::version() const +{ + return meta_version; +} + + +void MetaRecord::setVersion(const QString &str) +{ + meta_version=str; +} + + +QString MetaRecord::ending() const +{ + return meta_ending; +} + + +void MetaRecord::setEnding(const QString &str) +{ + meta_ending=str; +} + + +int MetaRecord::introLength() const +{ + return meta_intro_length; +} + + +void MetaRecord::setIntroLength(int msecs) +{ + meta_intro_length=msecs; +} + + +int MetaRecord::length() const +{ + return meta_length; +} + + +void MetaRecord::setLength(int msecs) +{ + meta_length=msecs; +} + + +int MetaRecord::year() const +{ + return meta_year; +} + + +void MetaRecord::setYear(int year) +{ + meta_year=year; +} + + +QString MetaRecord::album() const +{ + return meta_album; +} + + +void MetaRecord::setAlbum(const QString &str) +{ + meta_album=str; +} + + +QString MetaRecord::composer() const +{ + return meta_composer; +} + + +void MetaRecord::setComposer(const QString &str) +{ + meta_composer=str; +} + + +QString MetaRecord::publisher() const +{ + return meta_publisher; +} + + +void MetaRecord::setPublisher(const QString &str) +{ + meta_publisher=str; +} + + +QString MetaRecord::license() const +{ + return meta_license; +} + + +void MetaRecord::setLicense(const QString &str) +{ + meta_license=str; +} + + +QString MetaRecord::label() const +{ + return meta_label; +} + + +void MetaRecord::setLabel(const QString &str) +{ + meta_label=str; +} + + +QString MetaRecord::client() const +{ + return meta_client; +} + + +void MetaRecord::setClient(const QString &str) +{ + meta_client=str; +} + + +QString MetaRecord::agency() const +{ + return meta_agency; +} + + +void MetaRecord::setAgency(const QString &str) +{ + meta_agency=str; +} + + +QString MetaRecord::isrc() const +{ + return meta_isrc; +} + + +void MetaRecord::setIsrc(const QString &str) +{ + meta_isrc=str; +} + + +int MetaRecord::beatsPerMinute() const +{ + return meta_beats_per_minute; +} + + +void MetaRecord::setBeatsPerMinute(int bpm) +{ + meta_beats_per_minute=bpm; +} + + +int MetaRecord::segueStart() const +{ + return meta_segue_start; +} + + +void MetaRecord::setSegueStart(int msec) +{ + meta_segue_start=msec; +} + + +int MetaRecord::segueEnd() const +{ + return meta_segue_end; +} + + +void MetaRecord::setSegueEnd(int msec) +{ + meta_segue_end=msec; +} + + +void MetaRecord::getMetadata(RDWaveData *data,int track_len) +{ + data->setTitle(meta_title); + data->setArtist(meta_artist); + data->setReleaseYear(meta_year); + data->setAlbum(meta_album); + data->setLabel(meta_label); + data->setComposer(meta_composer); + data->setPublisher(meta_publisher); + data->setIsrc(meta_isrc); + data->setLicensingOrganization(meta_license); + data->setIntroStartPos(0); + data->setIntroEndPos(meta_intro_length); + if(meta_segue_start>=0) { + data->setSegueStartPos(meta_segue_start); + data->setSegueEndPos(track_len); + } + data->setTmciSongId(meta_song_id); + data->setBeatsPerMinute(meta_beats_per_minute); + if(!meta_ending.isEmpty()) { + data->setEndType((RDWaveData::EndType)((const char *)meta_ending)[0]); + } +} + + +void MetaRecord::clear() +{ + meta_song_id=""; + meta_title=""; + meta_artist=""; + meta_version=""; + meta_ending=""; + meta_intro_length=0; + meta_length=-1; + meta_year=0; + meta_album=""; + meta_composer=""; + meta_publisher=""; + meta_license=""; + meta_label=""; + meta_client=""; + meta_agency=""; + meta_isrc=""; + meta_beats_per_minute=0; + meta_segue_start=-1; + meta_segue_end=-1; +} diff --git a/utils/rddiscimport/metarecord.h b/utils/rddiscimport/metarecord.h new file mode 100644 index 00000000..69cf0abc --- /dev/null +++ b/utils/rddiscimport/metarecord.h @@ -0,0 +1,105 @@ +// metarecord.h +// +// Container class for metadata +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: metarecord.h,v 1.1.2.3 2013/12/04 22:22:49 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef METARECORD_H +#define METARECORD_H + +#include + +#include + +class MetaRecord +{ + public: + MetaRecord(const QString &disc_id,int track_num); + MetaRecord(); + QString discId() const; + void setDiscId(const QString &disc_id); + int trackNumber() const; + void setTrackNumber(int track_num); + QString songId() const; + void setSongId(const QString &str); + QString title() const; + void setTitle(const QString &str); + QString artist() const; + void setArtist(const QString &str); + QString version() const; + void setVersion(const QString &str); + QString ending() const; + void setEnding(const QString &str); + int introLength() const; + void setIntroLength(int msecs); + int length() const; + void setLength(int msecs); + int year() const; + void setYear(int year); + QString album() const; + void setAlbum(const QString &str); + QString composer() const; + void setComposer(const QString &str); + QString publisher() const; + void setPublisher(const QString &str); + QString license() const; + void setLicense(const QString &str); + QString label() const; + void setLabel(const QString &str); + QString client() const; + void setClient(const QString &str); + QString agency() const; + void setAgency(const QString &str); + QString isrc() const; + void setIsrc(const QString &str); + int beatsPerMinute() const; + void setBeatsPerMinute(int bpm); + int segueStart() const; + void setSegueStart(int msec); + int segueEnd() const; + void setSegueEnd(int msec); + void getMetadata(RDWaveData *data,int track_len); + void clear(); + + private: + QString meta_disc_id; + int meta_track_number; + QString meta_song_id; + QString meta_title; + QString meta_artist; + QString meta_version; + QString meta_ending; + int meta_intro_length; + int meta_length; + int meta_year; + QString meta_album; + QString meta_composer; + QString meta_license; + QString meta_publisher; + QString meta_label; + QString meta_client; + QString meta_agency; + QString meta_isrc; + int meta_beats_per_minute; + int meta_segue_start; + int meta_segue_end; +}; + + +#endif // METARECORD_H diff --git a/utils/rddiscimport/rddiscimport.cpp b/utils/rddiscimport/rddiscimport.cpp new file mode 100644 index 00000000..fc7fe02c --- /dev/null +++ b/utils/rddiscimport/rddiscimport.cpp @@ -0,0 +1,761 @@ +// rddiscimport.cpp +// +// A Qt-based application for importing TM Century GoldDisc CDs +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: rddiscimport.cpp,v 1.1.2.10 2014/01/21 21:59:33 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +MainWidget::MainWidget(QWidget *parent,const char *name) + : QWidget(parent,name) +{ + dg_user=NULL; + dg_group=NULL; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"RDDiscImport","\n"); + delete cmd; + + // + // Set Window Size + // + setMinimumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + + SetCaption(); + + // + // Load Local Configs + // + dg_config=new RDConfig(); + dg_config->load(); + + // + // Get Temporary File + // + dg_tempfile=RDTempFile(); + + // + // Open Database + // + dg_db=QSqlDatabase::addDatabase(dg_config->mysqlDriver()); + if(!dg_db) { + QMessageBox::warning(this,tr("Database Error"), + tr("Can't Connect","Unable to connect to mySQL Server!")); + exit(0); + } + dg_db->setDatabaseName(dg_config->mysqlDbname()); + dg_db->setUserName(dg_config->mysqlUsername()); + dg_db->setPassword(dg_config->mysqlPassword()); + dg_db->setHostName(dg_config->mysqlHostname()); + if(!dg_db->open()) { + QMessageBox::warning(this,tr("Can't Connect"), + tr("Unable to connect to mySQL Server!")); + dg_db->removeDatabase(dg_config->mysqlDbname()); + exit(0); + } + + // + // Fonts + // + QFont main_font("helvetica",12,QFont::Normal); + main_font.setPixelSize(12); + setFont(main_font); + QFont label_font("helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + setFont(main_font); + + // + // Configuration Elements + // + dg_system=new RDSystem(); + dg_station=new RDStation(dg_config->stationName(),this); + dg_library_conf=new RDLibraryConf(dg_config->stationName(),0); + dg_ripc=new RDRipc(dg_config->stationName(),this); + connect(dg_ripc,SIGNAL(userChanged()),this,SLOT(userChangedData())); + dg_ripc->connectHost("localhost",RIPCD_TCP_PORT,dg_config->password()); + + // + // Metadata Index Library + // + dg_metalibrary=new MetaLibrary(); + + // + // CD Player + // + dg_player=new RDCdPlayer(NULL,this); + connect(dg_player,SIGNAL(mediaChanged()),this,SLOT(mediaChangedData())); + connect(dg_player,SIGNAL(ejected()),this,SLOT(ejectData())); + dg_player->setDevice(dg_library_conf->ripperDevice()); + dg_ripper=new RDCdRipper(NULL,this); + dg_ripper->setDevice(dg_library_conf->ripperDevice()); + dg_ripper->setDestinationFile(dg_tempfile); + dg_importer=new RDAudioImport(dg_station,dg_config,this); + dg_importer->setSourceFile(dg_tempfile); + dg_importer->setUseMetadata(false); + + // + // Index File + // + dg_indexfile_edit=new QLineEdit(this); + dg_indexfile_label=new QLabel(dg_indexfile_edit,tr("Index File")+":",this); + dg_indexfile_label->setFont(label_font); + dg_indexfile_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + dg_indexfile_button=new QPushButton(tr("Select"),this); + dg_indexfile_button->setFont(main_font); + connect(dg_indexfile_button,SIGNAL(clicked()), + this,SLOT(indexFileSelectedData())); + + // + // Group List + // + dg_group_box=new QComboBox(this); + dg_group_label=new QLabel(dg_group_box,tr("Destination Group")+":",this); + dg_group_label->setFont(label_font); + dg_group_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + connect(dg_group_box,SIGNAL(activated(int)), + this,SLOT(groupActivatedData(int))); + + // + // User Defined Field + // + dg_userdef_edit=new QLineEdit(this); + dg_userdef_label=new QLabel(dg_userdef_edit,tr("User Defined")+":",this); + dg_userdef_label->setFont(label_font); + dg_userdef_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + + // + // Track List + // + dg_track_list=new RDListView(this); + //db_track_list->setFont(default_font); + dg_track_list->setAllColumnsShowFocus(true); + dg_track_list->setItemMargin(5); + dg_track_list->setSelectionMode(QListView::Single); + dg_track_list->setSortColumn(-1); + connect(dg_track_list, + SIGNAL(doubleClicked(QListViewItem *,const QPoint &,int)), + this, + SLOT(trackDoubleClickedData(QListViewItem *,const QPoint &,int))); + + dg_track_list->addColumn("#"); + dg_track_list->setColumnAlignment(0,Qt::AlignHCenter); + + dg_track_list->addColumn(tr("Title")); + dg_track_list->setColumnAlignment(1,Qt::AlignLeft); + + dg_track_list->addColumn(tr("Artist")); + dg_track_list->setColumnAlignment(2,Qt::AlignLeft); + + dg_track_list->addColumn(tr("Length")); + dg_track_list->setColumnAlignment(3,Qt::AlignRight); + + // + // Progress Bars + // + dg_disc_label=new QLabel(tr("Disk Progress"),this); + dg_disc_label->setFont(label_font); + dg_disc_label->setDisabled(true); + dg_disc_bar=new QProgressBar(this); + dg_disc_bar->setDisabled(true); + + dg_track_label=new QLabel(tr("Track Progress"),this); + dg_track_label->setFont(label_font); + dg_track_label->setDisabled(true); + dg_track_bar=new QProgressBar(this); + dg_track_bar->setTotalSteps(dg_ripper->totalSteps()+1); + dg_track_bar->setDisabled(true); + connect(dg_ripper,SIGNAL(progressChanged(int)), + dg_track_bar,SLOT(setProgress(int))); + + // + // Disc ID + // + dg_discid_edit=new QLineEdit(this); + dg_discid_label=new QLabel(dg_discid_edit,tr("Disc ID")+":",this); + dg_discid_label->setFont(label_font); + dg_discid_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + connect(dg_discid_edit,SIGNAL(textChanged(const QString &)), + this,SLOT(discIdChangedData(const QString &))); + + // + // Rip Button + // + dg_rip_button=new QPushButton(tr("Rip Disc"),this); + dg_rip_button->setFont(label_font); + connect(dg_rip_button,SIGNAL(clicked()),this,SLOT(ripData())); + + // + // Channels + // + dg_channels_box=new QComboBox(this); + dg_channels_box->insertItem("1"); + dg_channels_box->insertItem("2"); + dg_channels_box->setCurrentItem(dg_library_conf->defaultChannels()-1); + dg_channels_label=new QLabel(dg_channels_box,tr("Channels")+":",this); + dg_channels_label->setFont(label_font); + dg_channels_label->setAlignment(AlignRight|AlignVCenter); + + // + // Autotrim Check Box + // + dg_autotrim_box=new QCheckBox(tr("Autotrim"),this); + dg_autotrim_box->setChecked(true); + dg_autotrim_box->setFont(label_font); + dg_autotrim_box->setChecked(dg_library_conf->trimThreshold()!=0); + connect(dg_autotrim_box,SIGNAL(toggled(bool)), + this,SLOT(autotrimCheckData(bool))); + + // + // Autotrim Level + // + dg_autotrim_spin=new QSpinBox(this); + dg_autotrim_spin->setRange(-99,0); + dg_autotrim_spin->setValue(dg_library_conf->trimThreshold()/100); + dg_autotrim_label=new QLabel(dg_autotrim_spin,tr("Level")+":",this); + dg_autotrim_label->setFont(label_font); + dg_autotrim_label->setAlignment(AlignRight|AlignVCenter); + dg_autotrim_unit=new QLabel(tr("dBFS"),this); + dg_autotrim_unit->setFont(label_font); + dg_autotrim_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Normalize Check Box + // + dg_normalize_box=new QCheckBox(tr("Normalize"),this); + dg_normalize_box->setChecked(true); + dg_normalize_box->setFont(label_font); + dg_normalize_box->setChecked(dg_library_conf->ripperLevel()!=0); + connect(dg_normalize_box,SIGNAL(toggled(bool)), + this,SLOT(normalizeCheckData(bool))); + + // + // Normalize Level + // + dg_normalize_spin=new QSpinBox(this); + dg_normalize_spin->setRange(-30,0); + dg_normalize_spin->setValue(dg_library_conf->ripperLevel()/100); + dg_normalize_label=new QLabel(dg_normalize_spin,tr("Level:"),this); + dg_normalize_label->setFont(label_font); + dg_normalize_label->setAlignment(AlignRight|AlignVCenter); + dg_normalize_unit=new QLabel(tr("dBFS"),this); + dg_normalize_unit->setFont(label_font); + dg_normalize_unit->setAlignment(AlignLeft|AlignVCenter); + + // + // Eject Button + // + dg_eject_button=new RDTransportButton(RDTransportButton::Eject,this,""); + connect(dg_eject_button,SIGNAL(clicked()),dg_player,SLOT(eject())); + + // + // Close Button + // + dg_close_button=new QPushButton(tr("Close"),this); + dg_close_button->setFont(label_font); + connect(dg_close_button,SIGNAL(clicked()),this,SLOT(quitMainWidget())); + + LoadConfig(); + dg_group=new RDGroup(dg_group_name); + if(!dg_player->open()) { + QMessageBox::warning(this,"RDDiscImport - "+tr("Ripper Error"), + tr("Unable to open CD-ROM device at")+" "+ + " \""+dg_library_conf->ripperDevice()+"\"."); + exit(256); + } + if(dg_metalibrary->load(dg_indexfile_edit->text())&& + (!dg_indexfile_edit->text().isEmpty())<0) { + QMessageBox::warning(this,"RDDiscImport - "+tr("Read Error"), + tr("Unable to read index file!")); + return; + } +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(700,700); +} + + +void MainWidget::indexFileSelectedData() +{ + QString filename; + int lines; + + filename=QFileDialog::getOpenFileName(dg_indexfile_edit->text(), + "CSV Files *.csv",this,"", + tr("RDDiscImport - Open Index File")); + dg_metalibrary->clear(); + if((lines=dg_metalibrary->load(filename))<0) { + QMessageBox::warning(this,"RDDiscImport - "+tr("Read Error"), + tr("Unable to read index file!")); + return; + } + else { + dg_indexfile_edit->setText(filename); + QMessageBox::information(this,"RDDiscImport - "+tr("File Read"), + tr("Loaded")+QString().sprintf(" %d ",lines)+ + tr("records.")); + } + SaveConfig(); +} + + +void MainWidget::groupActivatedData(int) +{ + if(dg_group!=NULL) { + delete dg_group; + } + dg_group=new RDGroup(dg_group_box->currentText()); + SaveConfig(); +} + + +void MainWidget::autotrimCheckData(bool state) +{ + dg_autotrim_spin->setEnabled(state); + dg_autotrim_label->setEnabled(state); + dg_autotrim_unit->setEnabled(state); +} + + +void MainWidget::trackDoubleClickedData(QListViewItem *it,const QPoint &pt, + int row) +{ + RDListViewItem *item=(RDListViewItem *)it; + if(item->id()) { + item->setTextColor(Qt::gray); + item->setId(false); + dg_rip_enableds[item->text(0).toInt()-1]=false; + } + else { + item->setTextColor(Qt::black); + item->setId(true); + dg_rip_enableds[item->text(0).toInt()-1]=true; + } +} + + +void MainWidget::normalizeCheckData(bool state) +{ + dg_normalize_spin->setEnabled(state); + dg_normalize_label->setEnabled(state); + dg_normalize_unit->setEnabled(state); +} + + +void MainWidget::mediaChangedData() +{ + dg_rip_enableds.clear(); + dg_track_list->clear(); + for(int i=(dg_player->tracks()-1);i>=0;i--) { + dg_rip_enableds.push_back(false); + RDListViewItem *item=new RDListViewItem(dg_track_list); + item->setId(false); + item->setTextColor(Qt::gray); + item->setText(0,QString().sprintf("%d",i+1)); + item->setText(1,tr("Track")+QString().sprintf(" %d",i+1)); + item->setText(3,RDGetTimeLength(dg_player->trackLength(i+1),false,false)); + } + dg_discid_label->setDisabled(dg_player->tracks()==0); + dg_discid_edit->setDisabled(dg_player->tracks()==0); +} + + +void MainWidget::discIdChangedData(const QString &str) +{ + MetaRecord *meta=NULL; + RDListViewItem *item=NULL; + bool matched=false; + + item=(RDListViewItem *)dg_track_list->firstChild(); + while(item!=NULL) { + if((meta=dg_metalibrary->track(str,item->text(0).toInt()-1))==NULL) { + item->setText(1,tr("Track")+ + QString().sprintf(" %d",item->text(0).toInt())); + item->setText(2,""); + item->setTextColor(Qt::gray); + item->setId(false); + dg_rip_enableds[item->text(0).toInt()-1]=false; + } + else { + item->setText(1,meta->title()); + item->setText(2,meta->artist()); + item->setTextColor(Qt::black); + item->setId(true); + dg_rip_enableds[item->text(0).toInt()-1]=true; + matched=true; + } + item=(RDListViewItem *)item->nextSibling(); + } + dg_rip_button->setEnabled(matched); +} + + +void MainWidget::ripData() +{ + RDCart *cart=NULL; + RDCut *cut=NULL; + RDWaveData *data=NULL; + unsigned cartnum; + RDAudioImport::ErrorCode import_err; + RDAudioConvert::ErrorCode conv_err; + + // + // Sanity Checks + // + if(dg_group->freeCartQuantity()tracks()) { + QMessageBox::warning(this,"RDDiscImport - "+tr("Ripper Error"), + tr("There are insufficient free cart numbers available in the")+ + "\""+dg_group->name()+"\" "+tr("group")+"!"); + return; + } + + // + // Lock Down the GUI + // + LockGui(false); + + // + // Load Importer Settings + // + RDSettings *s=new RDSettings(); + if(dg_library_conf->defaultFormat()==1) { + s->setFormat(RDSettings::MpegL2Wav); + } + else { + s->setFormat(RDSettings::Pcm16); + } + s->setChannels(dg_channels_box->currentItem()+1); + s->setSampleRate(dg_system->sampleRate()); + s->setBitRate(dg_library_conf->defaultBitrate()); + if(dg_normalize_box->isChecked()) { + s->setNormalizationLevel(dg_normalize_spin->value()); + } + if(dg_autotrim_box->isChecked()) { + s->setAutotrimLevel(dg_autotrim_spin->value()); + } + dg_importer->setDestinationSettings(s); + + // + // Rip and Import + // + dg_disc_bar->setTotalSteps(dg_player->tracks()); + for(int i=0;itracks();i++) { + if(dg_rip_enableds[i]) { + MetaRecord *r=dg_metalibrary->track(dg_discid_edit->text(),i); + if(r!=NULL) { + dg_disc_bar->setProgress(i); + dg_track_label->setText(QString().sprintf("Track %d: ",i+1)+ + r->title()+" - "+r->artist()); + dg_ripper->rip(i); + if((cartnum=dg_group->nextFreeCart())>0) { + cart=new RDCart(cartnum); + cart->create(dg_group->name(),RDCart::Audio); + cart->addCut(dg_library_conf->defaultFormat(), + dg_library_conf->defaultBitrate(), + dg_channels_box->currentItem()+1,"",r->discId()); + cut=new RDCut(cartnum,1); + dg_importer->setCartNumber(cartnum); + dg_importer->setCutNumber(1); + if((import_err=dg_importer-> + runImport(dg_user->name(),dg_user->password(),&conv_err))== + RDAudioImport::ErrorOk) { + data=new RDWaveData(); + r->getMetadata(data,dg_player->trackLength(i+1)); + if(!dg_autotrim_box->isChecked()) { + data->setStartPos(0); + data->setEndPos(dg_player->trackLength(i+1)); + } + data->setUserDefined(dg_userdef_edit->text(). + replace("%d",dg_discid_edit->text()). + replace("%t",QString().sprintf("%d",i+1))); + cart->setMetadata(data); + cut->setMetadata(data); + delete data; + } + else { + QMessageBox::warning(this,"RDDiscImport - "+tr("Import Error"), + tr("Unable to import track audio!")+"\n"+ + "["+ + RDAudioImport::errorText(import_err,conv_err)+ + "]."); + return; + } + delete cut; + delete cart; + } + } + } + } + delete s; + + // + // Reset Progress Bars + // + dg_disc_bar->reset(); + dg_track_bar->reset(); + + // + // Unlock the GUI + // + LockGui(true); + + dg_player->eject(); + qApp->processEvents(); + + QMessageBox::information(this,"RDDiscImport - "+tr("Ripper Status"), + tr("Rip Complete!")); +} + + +void MainWidget::ejectData() +{ + dg_track_list->clear(); + dg_discid_label->setDisabled(true); + dg_discid_edit->setDisabled(true); + dg_discid_edit->clear(); + dg_rip_button->setDisabled(true); +} + + +void MainWidget::userChangedData() +{ + QStringList groups; + + if(dg_user!=NULL) { + delete dg_user; + } + dg_group_box->clear(); + + dg_user=new RDUser(dg_ripc->user()); + + groups=dg_user->groups(); + for(unsigned i=0;iinsertItem(groups[i]); + if(dg_group_name==groups[i]) { + dg_group_box->setCurrentItem(i); + } + } + + SetCaption(); +} + + +void MainWidget::quitMainWidget() +{ + if(dg_close_button->isEnabled()) { + SaveConfig(); + unlink(dg_tempfile); + qApp->quit(); + } +} + + +void MainWidget::resizeEvent(QResizeEvent *e) +{ + dg_indexfile_label->setGeometry(10,10,115,20); + dg_indexfile_edit->setGeometry(130,10,size().width()-220,20); + dg_indexfile_button->setGeometry(size().width()-70,7,60,26); + + dg_group_label->setGeometry(10,40,115,20); + dg_group_box->setGeometry(130,40,200,20); + + dg_userdef_label->setGeometry(350,40,95,20); + dg_userdef_edit->setGeometry(450,40,size().width()-460,20); + + dg_track_list->setGeometry(10,72,size().width()-20,size().height()-232); + + dg_disc_label->setGeometry(15,size().height()-157,size().width()-20,20); + dg_disc_bar->setGeometry(10,size().height()-140,size().width()-20,20); + + dg_track_label->setGeometry(15,size().height()-117,size().width()-20,20); + dg_track_bar->setGeometry(10,size().height()-100,size().width()-20,20); + + dg_discid_label->setGeometry(10,size().height()-70,60,20); + dg_discid_edit->setGeometry(75,size().height()-70,60,20); + + dg_rip_button->setGeometry(10,size().height()-43,130,30); + + dg_channels_box->setGeometry(340,size().height()-75,50,20); + dg_channels_label->setGeometry(250,size().height()-75,75,20); + + dg_autotrim_box->setGeometry(200,size().height()-48,80,15); + dg_autotrim_spin->setGeometry(340,size().height()-50,40,20); + dg_autotrim_label->setGeometry(290,size().height()-50,45,20); + dg_autotrim_unit->setGeometry(385,size().height()-50,40,20); + + dg_normalize_box->setGeometry(200,size().height()-21,113,15); + dg_normalize_spin->setGeometry(340,size().height()-23,40,20); + dg_normalize_label->setGeometry(290,size().height()-23,45,20); + dg_normalize_unit->setGeometry(385,size().height()-23,40,20); + + dg_eject_button->setGeometry(size().width()-200,size().height()-60,80,50); + + dg_close_button->setGeometry(size().width()-90,size().height()-60,80,50); +} + + +void MainWidget::LockGui(bool state) +{ + dg_indexfile_edit->setEnabled(state); + dg_indexfile_button->setEnabled(state); + dg_group_box->setEnabled(state); + + dg_disc_label->setDisabled(state); + dg_disc_bar->setDisabled(state); + + dg_track_label->setDisabled(state); + dg_track_bar->setDisabled(state); + + dg_discid_edit->setEnabled(state); + dg_eject_button->setEnabled(state); + + dg_channels_box->setEnabled(state); + + if(state) { + dg_autotrim_box->setEnabled(true); + if(dg_autotrim_box->isChecked()) { + dg_autotrim_spin->setEnabled(true); + } + dg_normalize_box->setEnabled(true); + if(dg_normalize_box->isChecked()) { + dg_normalize_spin->setDisabled(true); + } + } + else { + dg_autotrim_box->setDisabled(true); + dg_autotrim_spin->setDisabled(true); + dg_normalize_box->setDisabled(true); + dg_normalize_spin->setDisabled(true); + } + + dg_rip_button->setEnabled(state); + + dg_close_button->setEnabled(state); +} + + +void MainWidget::SetCaption() +{ + QString username=tr("[unknown]"); + if(dg_user!=NULL) { + username=dg_user->name(); + } + setCaption(tr("RDDiscImport")+" v"+VERSION+" "+tr("User")+": "+username); +} + + +void MainWidget::LoadConfig() +{ + RDProfile *p=new RDProfile(); + p->setSource(RDHomeDir()+"/.rddiscimportrc"); + dg_indexfile_edit->setText(p->stringValue("RDDiscImport","IndexFile")); + dg_group_name=p->stringValue("RDDiscImport","Group"); + dg_userdef_edit->setText(p->stringValue("RDDiscImport","UserDefTemplate", + "Ripped from disc %d track %t")); + delete p; +} + + +void MainWidget::SaveConfig() +{ + FILE *f=NULL; + + if((f=fopen(RDHomeDir()+"/.rddiscimportrc","w"))==NULL) { + return; + } + fprintf(f,"[RDDiscImport]\n"); + fprintf(f,"IndexFile=%s\n",(const char *)dg_indexfile_edit->text()); + fprintf(f,"Group=%s\n",(const char *)dg_group_box->currentText()); + fprintf(f,"UserDefTemplate=%s\n",(const char *)dg_userdef_edit->text()); + dg_group_name=dg_group_box->currentText(); + + fclose(f); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(), + "."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rddiscimport_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} diff --git a/utils/rddiscimport/rddiscimport.h b/utils/rddiscimport/rddiscimport.h new file mode 100644 index 00000000..8ee71f55 --- /dev/null +++ b/utils/rddiscimport/rddiscimport.h @@ -0,0 +1,131 @@ +// rddiscimport.h +// +// A Qt-based application for importing TM Century GoldDisc CDs +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: rddiscimport.h,v 1.1.2.4 2013/12/04 22:15:21 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDDISCIMPORT_H +#define RDDISCIMPORT_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define RDDISCIMPORT_USAGE "\n" + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + + private slots: + void indexFileSelectedData(); + void groupActivatedData(int); + void autotrimCheckData(bool state); + void trackDoubleClickedData(QListViewItem *item,const QPoint &pt,int row); + void ripData(); + void normalizeCheckData(bool state); + void mediaChangedData(); + void discIdChangedData(const QString &str); + void ejectData(); + void userChangedData(); + void quitMainWidget(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + void LockGui(bool state); + void SetCaption(); + void LoadConfig(); + void SaveConfig(); + QLabel *dg_indexfile_label; + QLineEdit *dg_indexfile_edit; + QPushButton *dg_indexfile_button; + QLabel *dg_group_label; + QComboBox *dg_group_box; + QLabel *dg_userdef_label; + QLineEdit *dg_userdef_edit; + RDListView *dg_track_list; + QLabel *dg_disc_label; + QProgressBar *dg_disc_bar; + QLabel *dg_track_label; + QProgressBar *dg_track_bar; + QLabel *dg_discid_label; + QLineEdit *dg_discid_edit; + QPushButton *dg_rip_button; + QLabel *dg_channels_label; + QComboBox *dg_channels_box; + QLabel *dg_autotrim_label; + QCheckBox *dg_autotrim_box; + QSpinBox *dg_autotrim_spin; + QLabel *dg_autotrim_unit; + QLabel *dg_normalize_label; + QCheckBox *dg_normalize_box; + QSpinBox *dg_normalize_spin; + QLabel *dg_normalize_unit; + RDTransportButton *dg_eject_button; + QPushButton *dg_close_button; + MetaLibrary *dg_metalibrary; + RDCdPlayer *dg_player; + RDCdRipper *dg_ripper; + RDAudioImport *dg_importer; + RDGroup *dg_group; + RDRipc *dg_ripc; + RDUser *dg_user; + RDSystem *dg_system; + RDStation *dg_station; + RDLibraryConf *dg_library_conf; + QSqlDatabase *dg_db; + RDConfig *dg_config; + QString dg_group_name; + QString dg_tempfile; + std::vector dg_rip_enableds; +}; + + +#endif // RDDISCIMPORT_H diff --git a/utils/rddiscimport/rddiscimport.pro b/utils/rddiscimport/rddiscimport.pro new file mode 100644 index 00000000..e582cbce --- /dev/null +++ b/utils/rddiscimport/rddiscimport.pro @@ -0,0 +1,35 @@ +# utils.pro +# +# The utils/ QMake project file for Rivendell +# +# (C) Copyright 2003-2006 Fred Gleason +# +# $Id: rddiscimport.pro,v 1.1.2.2 2013/12/04 18:06:36 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +SOURCES += metalibrary.cpp +SOURCES += metarecord.cpp +SOURCES += rddiscimport.cpp + +HEADERS += metalibrary.h +HEADERS += metarecord.h +HEADERS += rddiscimport.h + +TRANSLATIONS += rddiscimport_de.ts +TRANSLATIONS += rddiscimport_es.ts +TRANSLATIONS += rddiscimport_fr.ts +TRANSLATIONS += rddiscimport_nb.ts +TRANSLATIONS += rddiscimport_nn.ts +TRANSLATIONS += rddiscimport_pt_BR.ts diff --git a/utils/rddiscimport/rddiscimport_de.ts b/utils/rddiscimport/rddiscimport_de.ts new file mode 100644 index 00000000..3d66db16 --- /dev/null +++ b/utils/rddiscimport/rddiscimport_de.ts @@ -0,0 +1,166 @@ + + + MainWidget + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Ripper Error + + + + Index File + + + + Select + + + + Destination Group + + + + Title + + + + Artist + + + + Disk Progress + + + + Track Progress + + + + Disc ID + + + + Rip Disc + + + + Channels + + + + Autotrim + + + + Level + + + + dBFS + + + + Normalize + + + + Level: + + + + Close + + + + Read Error + + + + Unable to read index file! + + + + There are insufficient free cart numbers available in the + + + + group + + + + Ripper Status + + + + Rip Complete! + + + + RDDiscImport - Open Index File + + + + File Read + + + + Loaded + + + + records. + + + + Track + + + + [unknown] + + + + RDDiscImport + + + + User + + + + Import Error + + + + Unable to import track audio! + + + + Length + + + + User Defined + + + + Unable to open CD-ROM device at + + + + diff --git a/utils/rddiscimport/rddiscimport_es.ts b/utils/rddiscimport/rddiscimport_es.ts new file mode 100644 index 00000000..3d66db16 --- /dev/null +++ b/utils/rddiscimport/rddiscimport_es.ts @@ -0,0 +1,166 @@ + + + MainWidget + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Ripper Error + + + + Index File + + + + Select + + + + Destination Group + + + + Title + + + + Artist + + + + Disk Progress + + + + Track Progress + + + + Disc ID + + + + Rip Disc + + + + Channels + + + + Autotrim + + + + Level + + + + dBFS + + + + Normalize + + + + Level: + + + + Close + + + + Read Error + + + + Unable to read index file! + + + + There are insufficient free cart numbers available in the + + + + group + + + + Ripper Status + + + + Rip Complete! + + + + RDDiscImport - Open Index File + + + + File Read + + + + Loaded + + + + records. + + + + Track + + + + [unknown] + + + + RDDiscImport + + + + User + + + + Import Error + + + + Unable to import track audio! + + + + Length + + + + User Defined + + + + Unable to open CD-ROM device at + + + + diff --git a/utils/rddiscimport/rddiscimport_fr.ts b/utils/rddiscimport/rddiscimport_fr.ts new file mode 100644 index 00000000..3d66db16 --- /dev/null +++ b/utils/rddiscimport/rddiscimport_fr.ts @@ -0,0 +1,166 @@ + + + MainWidget + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Ripper Error + + + + Index File + + + + Select + + + + Destination Group + + + + Title + + + + Artist + + + + Disk Progress + + + + Track Progress + + + + Disc ID + + + + Rip Disc + + + + Channels + + + + Autotrim + + + + Level + + + + dBFS + + + + Normalize + + + + Level: + + + + Close + + + + Read Error + + + + Unable to read index file! + + + + There are insufficient free cart numbers available in the + + + + group + + + + Ripper Status + + + + Rip Complete! + + + + RDDiscImport - Open Index File + + + + File Read + + + + Loaded + + + + records. + + + + Track + + + + [unknown] + + + + RDDiscImport + + + + User + + + + Import Error + + + + Unable to import track audio! + + + + Length + + + + User Defined + + + + Unable to open CD-ROM device at + + + + diff --git a/utils/rddiscimport/rddiscimport_nb.ts b/utils/rddiscimport/rddiscimport_nb.ts new file mode 100644 index 00000000..3d66db16 --- /dev/null +++ b/utils/rddiscimport/rddiscimport_nb.ts @@ -0,0 +1,166 @@ + + + MainWidget + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Ripper Error + + + + Index File + + + + Select + + + + Destination Group + + + + Title + + + + Artist + + + + Disk Progress + + + + Track Progress + + + + Disc ID + + + + Rip Disc + + + + Channels + + + + Autotrim + + + + Level + + + + dBFS + + + + Normalize + + + + Level: + + + + Close + + + + Read Error + + + + Unable to read index file! + + + + There are insufficient free cart numbers available in the + + + + group + + + + Ripper Status + + + + Rip Complete! + + + + RDDiscImport - Open Index File + + + + File Read + + + + Loaded + + + + records. + + + + Track + + + + [unknown] + + + + RDDiscImport + + + + User + + + + Import Error + + + + Unable to import track audio! + + + + Length + + + + User Defined + + + + Unable to open CD-ROM device at + + + + diff --git a/utils/rddiscimport/rddiscimport_nn.ts b/utils/rddiscimport/rddiscimport_nn.ts new file mode 100644 index 00000000..3d66db16 --- /dev/null +++ b/utils/rddiscimport/rddiscimport_nn.ts @@ -0,0 +1,166 @@ + + + MainWidget + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Ripper Error + + + + Index File + + + + Select + + + + Destination Group + + + + Title + + + + Artist + + + + Disk Progress + + + + Track Progress + + + + Disc ID + + + + Rip Disc + + + + Channels + + + + Autotrim + + + + Level + + + + dBFS + + + + Normalize + + + + Level: + + + + Close + + + + Read Error + + + + Unable to read index file! + + + + There are insufficient free cart numbers available in the + + + + group + + + + Ripper Status + + + + Rip Complete! + + + + RDDiscImport - Open Index File + + + + File Read + + + + Loaded + + + + records. + + + + Track + + + + [unknown] + + + + RDDiscImport + + + + User + + + + Import Error + + + + Unable to import track audio! + + + + Length + + + + User Defined + + + + Unable to open CD-ROM device at + + + + diff --git a/utils/rddiscimport/rddiscimport_pt_BR.ts b/utils/rddiscimport/rddiscimport_pt_BR.ts new file mode 100644 index 00000000..3d66db16 --- /dev/null +++ b/utils/rddiscimport/rddiscimport_pt_BR.ts @@ -0,0 +1,166 @@ + + + MainWidget + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Ripper Error + + + + Index File + + + + Select + + + + Destination Group + + + + Title + + + + Artist + + + + Disk Progress + + + + Track Progress + + + + Disc ID + + + + Rip Disc + + + + Channels + + + + Autotrim + + + + Level + + + + dBFS + + + + Normalize + + + + Level: + + + + Close + + + + Read Error + + + + Unable to read index file! + + + + There are insufficient free cart numbers available in the + + + + group + + + + Ripper Status + + + + Rip Complete! + + + + RDDiscImport - Open Index File + + + + File Read + + + + Loaded + + + + records. + + + + Track + + + + [unknown] + + + + RDDiscImport + + + + User + + + + Import Error + + + + Unable to import track audio! + + + + Length + + + + User Defined + + + + Unable to open CD-ROM device at + + + + diff --git a/utils/rdgen/Makefile.am b/utils/rdgen/Makefile.am new file mode 100644 index 00000000..f927c6f6 --- /dev/null +++ b/utils/rdgen/Makefile.am @@ -0,0 +1,50 @@ +## automake.am +## +## Automake.am for rivendell/utils/rdgen +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.6.8.1 2012/11/29 01:37:38 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rdgen + +dist_rdgen_SOURCES = rdgen.c\ + wavlib.c wavlib.h + +rdgen_LDADD = -lm + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rdgen/rdgen.c b/utils/rdgen/rdgen.c new file mode 100644 index 00000000..41b47628 --- /dev/null +++ b/utils/rdgen/rdgen.c @@ -0,0 +1,317 @@ +/* rdgen.c + * + * A WAV file generator for test tones + * + * (C) Copyright 1997-2003 Fred Gleason + * + * $Id: rdgen.c,v 1.4 2010/07/29 19:32:40 cvs Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define BUFFER_SIZE 16384 +#define SAMPLE_RATE 48000 +#define SAMPLE_SIZE 16 +#define USAGE "rdgen [-f freq][-l level][-c left|right|both][-p now|rev][-t secs][-v] \n" + +int main(int argc,char *argv[]) +{ + int i; + int hFilename; + unsigned char cBuffer[BUFFER_SIZE]; + float fFreq=1000; + float fLevel=0; + float fRatio; + int dChan=0; /* 0=Both, 1=Left, 2=Right */ + char sChan[10]; + int dPhase=0; /* 0=Normal, 1=Reverse */ + char sPhase[10]; + int dTime=0; + int dMatch=0; + int dDebug=0; + int dSampleRate=0; + char sFilename[128]; /* Name of audio device */ + float fGain; + float fAngle; + unsigned long ldCount,ldTimeline=0,ldLimit=BUFFER_SIZE; + short int dSample; + time_t tmTimestamp,tmTime; + struct wavHeader wavHeader; + unsigned dBytes=0,dTotalBytes; + + if(argc<2) { + printf(USAGE); + exit(0); + } + + if(argc==2) { + if(strcmp(argv[1],"-v")==0) { + printf("wavgen v"); + printf(VERNUM); + printf("\n"); + exit(0); + } + } + + /* Get device name */ + if(sscanf(argv[argc-1],"%s",sFilename)!=1) { + printf("wavgen: invalid file anem\n"); + exit(1); + } + + /* Get options */ + for(i=1;i0) { + tmTimestamp+=dTime; + } + else { + tmTimestamp--; + } + + /* Output audio */ + dTotalBytes=wavHeader.dwAvgBytesPerSec*dTime; + + switch(SAMPLE_SIZE) { + case 8: + fGain=127*fRatio; + ldTimeline=0; + ldLimit=BUFFER_SIZE/2; + while(dBytes>8)); + } + else { + cBuffer[i++]=0; + cBuffer[i++]=0; + } + if(dChan==0 || dChan==2) { + if(dPhase==1) { + dSample=-dSample; + } + cBuffer[i++]=0xFF&dSample; + cBuffer[i++]=(0xFF&(dSample>>8)); + } + else { + cBuffer[i++]=0; + cBuffer[i++]=0; + } + } + write(hFilename,cBuffer,BUFFER_SIZE); + dBytes+=BUFFER_SIZE; + ldLimit+=(BUFFER_SIZE/4); + ldTimeline+=(BUFFER_SIZE/4); + time(&tmTime); + } + break; + } + + /* close files and finish */ + FixWav(hFilename,dBytes/wavHeader.wBlockAlign,dBytes); + close(hFilename); + + + exit(0); +} diff --git a/utils/rdgen/wavlib.c b/utils/rdgen/wavlib.c new file mode 100644 index 00000000..71ec0827 --- /dev/null +++ b/utils/rdgen/wavlib.c @@ -0,0 +1,1187 @@ +/* wavlib.c + * + * A C Library for abstracting WAV files + * + * (C) Copyright 1997,1999-2003 Fred Gleason + * + * $Id: wavlib.c,v 1.4 2007/02/14 21:59:12 fredg Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wavlib.h" + +/* #define BUFFER_SIZE 65536 */ +#define BUFFER_SIZE 8192 +#define DEFAULT_WAV_MODE 0644 + +/* + * Global Variables + */ +int iWav=0; +int dWavPause=0; +int hGlobalAudio; + +int IsWav(int hFilename) +{ + int i; + char cBuffer[5]; + + /* Is this a riff file? */ + lseek(hFilename,0,SEEK_SET); + i=read(hFilename,cBuffer,4); + if(i==4) { + cBuffer[4]=0; + if(strcmp("RIFF",cBuffer)!=0) { + return FALSE; + } + } + else { + return FALSE; + } + /* Is this a WAVE file? */ + if(lseek(hFilename,8,SEEK_SET)!=8) { + return FALSE; + } + i=read(hFilename,cBuffer,4); + if(i==4) { + cBuffer[4]=0; + if(strcmp("WAVE",cBuffer)!=0) { + return FALSE; + } + } + else { + return FALSE; + } + return TRUE; +} + + +int OpenWav(char *sFilename,struct wavHeader *wavFilename) +{ + int hFilename; + struct wavChunk wavChunk; + unsigned char cBuffer[16]; + int i; + off_t oDataChunk; + + hFilename=open(sFilename,O_RDWR); + if(hFilename<0) { + return -1; + } + if(!IsWav(hFilename)) { + return -2; + } + + /* + * Find the format chunk + */ + strcpy(wavChunk.sName,"fmt "); + if(FindChunk(hFilename,&wavChunk)<0) { + close(hFilename); + return -1; + } + + /* + * Found the format chunk, now get the data + */ + lseek(hFilename,8,SEEK_CUR); + i=read(hFilename,cBuffer,14); + if(i<14) { + return -1; + } + wavFilename->wFormatTag=cBuffer[0]+256*cBuffer[1]; + wavFilename->wChannels=cBuffer[2]+256*cBuffer[3]; + wavFilename->dwSamplesPerSec=cBuffer[4]+256*cBuffer[5]+ + 65536*cBuffer[6]+16777216*cBuffer[7]; + wavFilename->dwAvgBytesPerSec=cBuffer[8]+256*cBuffer[9]+ + 65536*cBuffer[10]+16777216*cBuffer[11]; + wavFilename->wBlockAlign=cBuffer[12]+256*cBuffer[13]; + if(wavFilename->wFormatTag==WAVE_FORMAT_PCM) { /*Get bits per sample*/ + i=read(hFilename,cBuffer,2); + if(i<2) { + close(hFilename); + return -1; + } + wavFilename->wBitsPerSample=cBuffer[0]+256*cBuffer[1]; + } + + /* + * Find the data chunk + */ + strcpy(wavChunk.sName,"data"); + if(FindChunk(hFilename,&wavChunk)<0) { + close(hFilename); + return -1; + } + wavFilename->dwWaveDataSize=wavChunk.oSize; + oDataChunk=wavChunk.oOffset; /* Save this for restoration later */ + + /* + * Determine total number of samples (preferably from the fact chunk) + */ + strcpy(wavChunk.sName,"fact"); + lseek(hFilename,12,SEEK_SET); + if(FindChunk(hFilename,&wavChunk)<0) { /* Not present, calculate the size */ + wavFilename->dwFileSize=wavFilename->dwWaveDataSize/ + wavFilename->wBlockAlign; + } + else { /* Pull it from the fact chunk */ + lseek(hFilename,8,SEEK_CUR); + i=read(hFilename,cBuffer,4); + if(i!=4) { + close(hFilename); + return -1; + } + wavFilename->dwFileSize=cBuffer[0]+256*cBuffer[1]+65536*cBuffer[2]+ + 16777216*cBuffer[3]; + } + + /* + * Calculate audio length in seconds + */ + wavFilename->tWavLength=wavFilename->dwFileSize/wavFilename->dwSamplesPerSec; + lseek(hFilename,oDataChunk+8,SEEK_SET); + return hFilename; +} + + + +int CreateWav(char *sFilename,struct wavHeader *wavHeader) +{ + int hFilename; + + /* + * Some sanity checks + */ + if(wavHeader->wFormatTag!=WAVE_FORMAT_PCM) { + return -1; + } + /* + * Don't use O_TRUNC here, it can cause a significant (several second or + * more) delay on large files. We'll come back and trim the fat after the + * recording's done. + */ + hFilename=open(sFilename,O_RDWR|O_CREAT,DEFAULT_WAV_MODE); + if(hFilename<0) { + return -1; + } + + /* + * Write the WAVE Header + */ + write(hFilename,"RIFF",4); + WriteDword(hFilename,0); + write(hFilename,"WAVE",4); + + /* + * Write the format chunk + */ + write(hFilename,"fmt ",4); + WriteDword(hFilename,16); + WriteSword(hFilename,wavHeader->wFormatTag); + WriteSword(hFilename,wavHeader->wChannels); + WriteDword(hFilename,wavHeader->dwSamplesPerSec); + WriteDword(hFilename,wavHeader->dwAvgBytesPerSec); + WriteSword(hFilename,wavHeader->wBlockAlign); + WriteSword(hFilename,wavHeader->wBitsPerSample); + + /* + * Write the fact chunk + */ + write(hFilename,"fact",4); + WriteDword(hFilename,4); + WriteDword(hFilename,0); + + /* + * Write the data chunk + */ + write(hFilename,"data",4); + WriteDword(hFilename,0); + + return hFilename; +} + + + +int FixWav(int hFilename,unsigned dSamples,unsigned dBytes) +{ + struct stat statData; + struct wavChunk wavChunk; + + /* + * Get the file size + */ + if(fstat(hFilename,&statData)<0) { + return -1; + } + + /* + * Update the file-size counter + */ + lseek(hFilename,4,SEEK_SET); + WriteDword(hFilename,statData.st_size-8); + + /* + * Update the fact chunk + */ + strcpy(wavChunk.sName,"fact"); + if(FindChunk(hFilename,&wavChunk)>0) { + lseek(hFilename,8,SEEK_CUR); + WriteDword(hFilename,dSamples); + } + + /* + * Update the data chunk + */ + strcpy(wavChunk.sName,"data"); + FindChunk(hFilename,&wavChunk); + lseek(hFilename,4,SEEK_CUR); + WriteDword(hFilename,dBytes); + + return 0; +} + + + +int FindChunk(int hFilename,struct wavChunk *wavChunk) +{ + int i; + off_t oOffset; + char sName[5]={0,0,0,0,0}; + unsigned char dBuffer[4]; + off_t oSize; + + oOffset=lseek(hFilename,12,SEEK_SET); + i=read(hFilename,sName,4); + i=read(hFilename,dBuffer,4); + oSize=dBuffer[0]+(256*dBuffer[1])+(65536*dBuffer[2])+(16777216*dBuffer[3]); + while(i==4) { + if(strcasecmp(wavChunk->sName,sName)==0) { + wavChunk->oOffset=lseek(hFilename,-8,SEEK_CUR); + wavChunk->oSize=oSize; + return 0; + } + lseek(hFilename,oSize,SEEK_CUR); + i=read(hFilename,sName,4); + i=read(hFilename,dBuffer,4); + oSize=dBuffer[0]+(256*dBuffer[1])+(65536*dBuffer[2])+(16777216*dBuffer[3]); + } + return -1; +} + + + +int GetNextChunk(int hFilename,struct wavChunk *wavChunk) +{ + int i; + char sName[5]={0,0,0,0,0}; + unsigned char dBuffer[4]; + off_t oSize; + + i=read(hFilename,sName,4); + i=read(hFilename,dBuffer,4); + oSize=dBuffer[0]+(dBuffer[1]*256)+(dBuffer[2]*65536)+(dBuffer[3]*16777216); + if(i==4) { + strcpy(wavChunk->sName,sName); + wavChunk->oOffset=lseek(hFilename,0,SEEK_CUR); + wavChunk->oSize=oSize; + lseek(hFilename,oSize,SEEK_CUR); + return 0; + } + return -1; +} + + + +int GetListChunk(int hFilename,struct wavList *wavList) +{ + struct wavChunk wavChunk; + int i; + char cBuffer[LIST_SIZE]; + off_t oLimit,oOffset; + char sName[5]={0,0,0,0,0}; + unsigned dBuffer[4]; + char sBuffer[LIST_SIZE]; + off_t oTemp,oSize; + int dReturn=1; + + /* + * Initialize Data Structures + */ + memset(wavList,0,sizeof(wavList)); + + /* + * Find the list chunk + */ + strcpy(wavChunk.sName,"LIST"); + if(FindChunk(hFilename,&wavChunk)<0) { + return -1; + } + oLimit=wavChunk.oOffset+wavChunk.oSize; + + /* + * Setup to start & do some basic sanity checking + */ + oOffset=lseek(hFilename,8,SEEK_CUR); + i=read(hFilename,cBuffer,4); + oOffset+=i; + cBuffer[4]=0; + if(strcasecmp(cBuffer,"INFO")!=0) { /* I don't understand this format! */ + return -1; + } + + /* + * Scan through the chunk + */ + while(oOffsetsIcrd,sBuffer); + dReturn=0; + } + if(strcasecmp(sName,"IART")==0) { + strcpy(wavList->sIart,sBuffer); + } + if(strcasecmp(sName,"ICMT")==0) { + strcpy(wavList->sIcmt,sBuffer); + } + if(strcasecmp(sName,"ICOP")==0) { + strcpy(wavList->sIcop,sBuffer); + } + if(strcasecmp(sName,"IENG")==0) { + strcpy(wavList->sIeng,sBuffer); + } + if(strcasecmp(sName,"IGNR")==0) { + strcpy(wavList->sIgnr,sBuffer); + } + if(strcasecmp(sName,"IKEY")==0) { + strcpy(wavList->sIkey,sBuffer); + } + if(strcasecmp(sName,"IMED")==0) { + strcpy(wavList->sImed,sBuffer); + } + if(strcasecmp(sName,"INAM")==0) { + strcpy(wavList->sInam,sBuffer); + } + if(strcasecmp(sName,"ISFT")==0) { + strcpy(wavList->sIsft,sBuffer); + } + if(strcasecmp(sName,"ISRC")==0) { + strcpy(wavList->sIsrc,sBuffer); + } + if(strcasecmp(sName,"ITCH")==0) { + strcpy(wavList->sItch,sBuffer); + } + if(strcasecmp(sName,"ISBJ")==0) { + strcpy(wavList->sIsbj,sBuffer); + } + if(strcasecmp(sName,"ISRF")==0) { + strcpy(wavList->sIsrf,sBuffer); + } + } + return dReturn; +} + + + +int SetDspDesc(int hAudio,struct wavHeader *wavHeader) +{ + int dRequest; + + /* + * Set sampling format & bits per sample + */ + if(wavHeader->wFormatTag==WAVE_FORMAT_PCM) { + switch(wavHeader->wBitsPerSample) { + case 8: + dRequest=AFMT_U8; + ioctl(hAudio,SNDCTL_DSP_SETFMT,&dRequest); + if(dRequest!=AFMT_U8) { + return -1; + } + break; + case 16: + dRequest=AFMT_S16_LE; + ioctl(hAudio,SNDCTL_DSP_SETFMT,&dRequest); + if(dRequest!=AFMT_S16_LE) { + return -1; + } + break; + default: + return -1; + break; + } + } + else { + return -1; + } + /* Set number of channels */ + if(wavHeader->wChannels>0 && wavHeader->wChannels<3) { + dRequest=wavHeader->wChannels-1; + ioctl(hAudio,SNDCTL_DSP_STEREO,&dRequest); + if(dRequest!=wavHeader->wChannels-1) { + return -1; + } + } + else { + return -1; + } + + /* + * Set sampling rate + */ + dRequest=(int)wavHeader->dwSamplesPerSec; + ioctl(hAudio,SNDCTL_DSP_SPEED,&dRequest); + if((dRequest<(int)(.99*wavHeader->dwSamplesPerSec)) || + (dRequest>(int)(1.01*wavHeader->dwSamplesPerSec))) { + return -1; + } + + return 0; +} + + + + +int PlayWavFile(char *sFilename,char *sAudioDev,unsigned dOptions) +{ + int hAudio; + int i; + + if((hAudio=open(sAudioDev,O_WRONLY))<0) { + return -1; + } + i=PlayWavDesc(sFilename,hAudio,dOptions); + close(hAudio); + if(i<0) { + return -1; + } + return 0; +} + + + + +int PlayWavDesc(char *sFilename,int hAudio,unsigned dOptions) +{ + return PlayWavOffsetDesc(sFilename,hAudio,0,dOptions); +} + + + + +int PlayWavOffsetDesc(char *sFilename,int hAudio,int dOffset,unsigned dOptions) +{ + struct wavHeader wavFilename; + struct wavChunk wavChunk; + int hFilename; + int j,k; + unsigned char cBuffer[BUFFER_SIZE]; + unsigned dWaveOffset=0; + + /* + * Pass the device fd to a global so the signal handlers can get it + */ + hGlobalAudio=hAudio; + + /* + * Signal Handling Stuff + */ + if((dOptions&WAVLIB_PAUSEABLE)!=0) { + (void) signal(SIGTERM,SigStopWav); + (void) signal(SIGUSR1,SigPauseWav); + (void) signal(SIGUSR2,SigResumeWav); + } + + hFilename=OpenWav(sFilename,&wavFilename); + if(hFilename<0) { + return -1; + } + + if(SetDspDesc(hAudio,&wavFilename)<0) { + return -1; + } + + /* + * Calculate Wave Data Offset + */ + dWaveOffset=dOffset*wavFilename.wBlockAlign; + + /* + * OK -- time to play the file! + */ + strcpy(wavChunk.sName,"data"); + if(FindChunk(hFilename,&wavChunk)<0) { + return -1; + } + lseek(hFilename,8+dWaveOffset,SEEK_CUR); + if((dOptions & WAVLIB_TEST)==0) { + j=(wavFilename.dwWaveDataSize-dWaveOffset)/BUFFER_SIZE; + k=(wavFilename.dwWaveDataSize-dWaveOffset)-j*BUFFER_SIZE; + for(iWav=0;iWav0 && dChannels<3) { + dRequest=dChannels-1; + ioctl(hAudio,SNDCTL_DSP_STEREO,&dRequest); + if(dRequest!=dChannels-1) { + close(hFilename); + return -1; + } + } + else { + close(hFilename); + return -1; + } + + /* Set sampling rate */ + dRequest=(int)ldSamplesPerSec; + ioctl(hAudio,SNDCTL_DSP_SPEED,&dRequest); + /* if(dRequest<(int).99*ldSamplesPerSec || + dRequest>(int)1.01*ldSamplesPerSec) { + close(hFilename); + return -1; + } */ + + /* OK, we know the soundcard can handle it */ + /* If this is just a test, exit */ + if((dOptions & WAVLIB_TEST)!=0) { + return 0; + } + + /* Calculate actual bytes/sec overall */ + if(dBitsPerSample<=8) { + dBytesPerSample=1; + } + if(dBitsPerSample>8 && dBitsPerSample<=16) { + dBytesPerSample=2; + } + if(dBitsPerSample>16) { + dBytesPerSample=3; + } + dBlockAlign=dBytesPerSample*dChannels; + dBytesPerSec=ldSamplesPerSec*dBytesPerSample*dChannels; + /* Calculate buffer writes and total sample bytes needed */ + dTotalSampleBytes=dBytesPerSec*dSeconds; + dBufferWrites=dTotalSampleBytes/BUFFER_SIZE+1; + dTotalSampleBytes=dBufferWrites*BUFFER_SIZE; + dTotalWavSize=dTotalSampleBytes+36; + + /* + * Open the file and write the header + * + * First, open the file, using the appropriate permissions + * + * Don't use O_TRUNC here, it can cause a significant (several second or + * more) delay on large files. We'll come back and trim the fat after the + * recording's done. + */ + hFilename=open(sFilename,O_WRONLY|O_CREAT,DEFAULT_WAV_MODE); + if(hFilename<0) { + perror("open"); + return -1; + } + + /* The 'RIFF' field */ + strcpy(cBuffer,"RIFF"); + write(hFilename,cBuffer,4); + + /* The size pointer */ + /* wav files are little endian! */ + cBuffer[0]=dTotalWavSize & 0x000000FF; + cBuffer[1]=(dTotalWavSize & 0x0000FF00) >> 8; + cBuffer[2]=(dTotalWavSize & 0x00FF0000) >> 16; + cBuffer[3]=(dTotalWavSize & 0xFF000000) >> 24; + write(hFilename,cBuffer,4); + + /* The WAVE field */ + strcpy(cBuffer,"WAVE"); + write(hFilename,cBuffer,4); + + /* Now the format chunk */ + /* First the chunk header */ + strcpy(cBuffer,"fmt "); + write(hFilename,cBuffer,4); + + /* The chunk size field */ + cBuffer[0]=0x10; + cBuffer[1]=0; + cBuffer[2]=0; + cBuffer[3]=0; + write(hFilename,cBuffer,4); + + /* The Format Category */ + cBuffer[0]=dFormatTag & 0x00FF; + cBuffer[1]=(dFormatTag & 0xFF00) >> 8; + write(hFilename,cBuffer,2); + + /* Number of Channels */ + cBuffer[0]=dChannels & 0x00FF; + cBuffer[1]=(dChannels & 0xFF00) >> 8; + write(hFilename,cBuffer,2); + + /* Samples/second/channel */ + cBuffer[0]=ldSamplesPerSec & 0x000000FF; + cBuffer[1]=(ldSamplesPerSec & 0x0000FF00) >> 8; + cBuffer[2]=(ldSamplesPerSec & 0x00FF0000) >> 16; + cBuffer[3]=(ldSamplesPerSec & 0xFF000000) >> 24; + write(hFilename,cBuffer,4); + + /* Average bytes per second */ + cBuffer[0]=dBytesPerSec & 0x000000FF; + cBuffer[1]=(dBytesPerSec & 0x0000FF00) >> 8; + cBuffer[2]=(dBytesPerSec & 0x00FF0000) >> 16; + cBuffer[3]=(dBytesPerSec & 0xFF000000) >> 24; + write(hFilename,cBuffer,4); + + /* Data Block Alignment */ + cBuffer[0]=dBlockAlign & 0x00FF; + cBuffer[1]=(dBlockAlign & 0xFF00) >> 8; + write(hFilename,cBuffer,2); + + /* Bits per Sample */ + /* NOTE: This field pertains only to WAVE_FORMAT_PCM format encoding */ + cBuffer[0]=dBitsPerSample & 0x00FF; + cBuffer[1]=(dBitsPerSample & 0xFF00) >> 8; + write(hFilename,cBuffer,2); + + /* Now, the data chunk */ + /* The 'data' field */ + strcpy(cBuffer,"data"); + write(hFilename,cBuffer,4); + + /* The data size field */ + cBuffer[0]=dTotalSampleBytes & 0x000000FF; + cBuffer[1]=(dTotalSampleBytes & 0x0000FF00) >> 8; + cBuffer[2]=(dTotalSampleBytes & 0x00FF0000) >> 16; + cBuffer[3]=(dTotalSampleBytes & 0xFF000000) >> 24; + write(hFilename,cBuffer,4); + + /* Move the audio data */ + for(i=0;iwFormatTag!=WAVE_FORMAT_PCM) { + return -1; + } + + /* + * Flesh out the wavHeader Structure + */ + wavHeader->dwAvgBytesPerSec=wavHeader->wChannels*wavHeader->dwSamplesPerSec* + (wavHeader->wBitsPerSample/8); + wavHeader->wBlockAlign=wavHeader->wChannels*(wavHeader->wBitsPerSample/8); + wavHeader->dwWaveDataSize=wavHeader->dwAvgBytesPerSec*dSeconds; + wavHeader->dwFileSize=wavHeader->dwWaveDataSize/wavHeader->wBlockAlign; + wavHeader->tWavLength=dSeconds; + + if(SetDspDesc(hAudio,wavHeader)<0) { /* Format not supported by hardware */ + return -1; + } + if((dOptions&WAVLIB_TEST)!=0) { /* Just a test, exit */ + return 0; + } + + /* + * Look for silence sense option + */ + if(wavProcess!=NULL) { + if(wavProcess->dSenseTimeout!=0) { + if(wavHeader->wBitsPerSample==8) { + dPosThreshold=(int)(128+(128*DbToLinear(-wavProcess->dfThreshold))); + dNegThreshold=(int)(128-(128*DbToLinear(-wavProcess->dfThreshold))); + dBufferCount=wavHeader->dwAvgBytesPerSec*wavProcess->dSenseTimeout/ + BUFFER_SIZE; + while((dSense==0)&&((dBufferCount--)>0)) { + read(hAudio,cBuffer,BUFFER_SIZE); + for(i=0;idPosThreshold)||(cBuffer[i]wBitsPerSample==16) { + dBuffer=(short *)cBuffer; + dPosThreshold=(int)(32768*DbToLinear(-wavProcess->dfThreshold)); + dNegThreshold=(int)(-32768*DbToLinear(-wavProcess->dfThreshold)); + dBufferCount=wavHeader->dwAvgBytesPerSec*wavProcess->dSenseTimeout/ + BUFFER_SIZE; + while((dSense==0)&&((dBufferCount--)>0)) { + read(hAudio,cBuffer,BUFFER_SIZE); + for(i=0;idPosThreshold)||(dBuffer[i]dwWaveDataSize-(BUFFER_SIZE-dStartWrite))/ + BUFFER_SIZE; + dExcessWrites=(wavHeader->dwWaveDataSize-(BUFFER_SIZE-dStartWrite))- + (dBufferWrites*BUFFER_SIZE); + if(dSense==1) { + write(hFilename,cBuffer+dStartWrite,BUFFER_SIZE-dStartWrite); + } + for(i=0;idwFileSize,wavHeader->dwWaveDataSize); + close(hFilename); + + return 0; +} + + + +int SoundConfigFile(char *sAudioDev,int dParam,int dRequest) + + /* This function performs an ioctl call on the audio device + named by sAudioDev, using the ioctl dParam and the argument + dRequest. The ioctls are those defined in the OSS API. + If successful, the function returns the updated value of + dRequest, otherwise, it returns a -1. + + It is anticipated that this function will be useful mainly + as a way for manipulating the soundcard mixer settings */ + +{ + int dAudioDev; + int i; + + dAudioDev=open(sAudioDev,O_RDONLY); + if(dAudioDev<0) { + return -1; + } + i=SoundConfigDesc(dAudioDev,dParam,dRequest); + close(dAudioDev); + if(i<0) { + return -1; + } + else { + return dRequest; + } +} + + + +double DbToLinear(double dfDb) +{ + return pow(10,dfDb/20); +} + + + +double LinearToDb(double dfLinear) +{ + if(dfLinear==0) { + return -1; + } + return 20*log10(dfLinear); +} + + + +int SoundConfigDesc(int dAudioDev,int dParam,int dRequest) + + /* This function performs an ioctl call on the audio device + open on hAudioDev, using the ioctl dParam and the argument + dRequest. The ioctls are those defined in the OSS API. + If successful, the function returns the updated value of + dRequest, otherwise, it returns a -1. + + It is anticipated that this function will be useful mainly + as a way for manipulating the soundcard mixer settings */ + +{ + int i; + + i=ioctl(dAudioDev,dParam,&dRequest); + if(i<0) { + return -1; + } + else { + return dRequest; + } +} + + + +int Pattern(int dFilename,char *sPattern) + + /* This function finds the looks for the string sPattern +in the file pointed to by dFilename, starting at the current +pointer position. If found, it returns the pointer offset and +with the pointer set to the byte immediately following the pattern. +If the pattern is not found, it returns -1. */ + +{ + int i,j; + int dOffset=0; /* file pointer offset */ + unsigned char cBuffer; + int dPatLength; + + dPatLength=strlen(sPattern); + i=read(dFilename,&cBuffer,1); + if(i<0) { + perror("read"); + return -1; + } + dOffset++; + while(i==1) { + j=0; + while(cBuffer==sPattern[j++] && j<=dPatLength) { + if(j==dPatLength) { /* it's a match! */ + return dOffset; + } + i=read(dFilename,&cBuffer,1); + dOffset++; + } + lseek(dFilename,-(j-1),SEEK_CUR); + dOffset-=(j-1); + i=read(dFilename,&cBuffer,1); + dOffset++; + } + lseek(dFilename,-dOffset,SEEK_CUR); + printf("Offset: %d\n",dOffset); + return (-1); +} + + + + +ssize_t WriteSword(int hFilename,unsigned dValue) +{ + unsigned char cBuffer[2]; + + cBuffer[0]=dValue&0xFF; + cBuffer[1]=(dValue>>8)&0xFF; + + return write(hFilename,cBuffer,2); +} + + + + +ssize_t WriteDword(int hFilename,unsigned dValue) +{ + unsigned char cBuffer[4]; + + cBuffer[0]=dValue&0xFF; + cBuffer[1]=(dValue>>8)&0xFF; + cBuffer[2]=(dValue>>16)&0xFF; + cBuffer[3]=(dValue>>24)&0xFF; + + return write(hFilename,cBuffer,4); +} + + + + +int TailTrim(char *sFilename,int dThreshold) +{ + int i,j; + int hFilename; + struct wavHeader wavHeader; + struct wavChunk wavChunk; + long dEnd; + unsigned char cBuffer[BUFFER_SIZE]; + short *dBuffer; + + /* + * Initialize + */ + dBuffer=(short *)cBuffer; + + /* + * Open the file + */ + hFilename=OpenWav(sFilename,&wavHeader); + if(hFilename<0) { + return hFilename; + } + + /* + * Find the end of the audio data + */ + memset(&wavChunk,0,sizeof(struct wavChunk)); + strcpy(wavChunk.sName,"data"); + if(FindChunk(hFilename,&wavChunk)<0) { + return -1; + } + + /* + lseek(hFilename,wavChunk.oOffset+wavChunk.oSize-(BUFFER_SIZE*500),SEEK_SET); + read(hFilename,cBuffer,BUFFER_SIZE); + for(j=BUFFER_SIZE/2;j>0;j--) { + printf("VALUE: %d\n",dBuffer[j]); + } + exit(0); + */ + + /* + * Scan backwards through the data looking for audio + */ + lseek(hFilename,wavChunk.oOffset+wavChunk.oSize+6,SEEK_SET); + for(i=0;i=0;j--) { + /* printf("Threshold: %d Value: %d\n",dThreshold,dBuffer[j]); */ + if(abs(dBuffer[j])>=dThreshold) { + TruncWav(hFilename,&wavHeader,&wavChunk,lseek(hFilename,0,SEEK_CUR)+j*2); + close(hFilename); + exit(0); + } + } + } + dEnd=wavChunk.oSize-BUFFER_SIZE*(wavChunk.oSize/BUFFER_SIZE); + lseek(hFilename,-dEnd,SEEK_CUR); + read(hFilename,cBuffer,dEnd); + lseek(hFilename,-dEnd,SEEK_CUR); + for(j=dEnd-1;j>=0;j--) { + if(abs(dBuffer[j])>=dThreshold) { + TruncWav(hFilename,&wavHeader,&wavChunk,lseek(hFilename,0,SEEK_CUR)+j); + } + } + + /* + * Finish up + */ + close(hFilename); + return 0; +} + + + + + +int TruncWav(int hFilename,struct wavHeader *wavHeader, + struct wavChunk *wavChunk,unsigned dTruncPoint) +{ + unsigned dBytes; + + if(ftruncate(hFilename,dTruncPoint)<0) { + return -1; + } + dBytes=dTruncPoint-wavChunk->oOffset; + if(FixWav(hFilename,dBytes/(wavHeader->wBitsPerSample/8),dBytes)<0) { + return -1; + } + return 0; +} + diff --git a/utils/rdgen/wavlib.h b/utils/rdgen/wavlib.h new file mode 100644 index 00000000..914241f5 --- /dev/null +++ b/utils/rdgen/wavlib.h @@ -0,0 +1,172 @@ +/* wavlib.h + * + * A C Library for abstracting WAV files + * + * (C) Copyright 1997,1999-2003 Fred Gleason + * + * $Id: wavlib.h,v 1.4 2007/02/14 21:59:12 fredg Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * The package version number + */ +#define VERNUM "2.4.2" + +#ifndef _UNISTD_H +#include +#endif + +#ifndef _TIME_H +#include +#endif + +#ifndef PI +#define PI 3.1415928 +#endif + +#define AUDIO_BUFFER 32768 + +/* + * Some basic values + */ +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +/* + * Aliases for backward compatibility. Use of these names is deprecated. + */ +#define PlayWav PlayWavFile +#define RecWav RecWavFile +#define SoundConfig SoundConfigFile + + +/* Data Structures */ +struct wavHeader { + unsigned short wFormatTag; /* Format Category */ + unsigned short wChannels; /* Number of Audio Channels */ + int dwSamplesPerSec; /* Samples/sec/channel */ + int dwAvgBytesPerSec; /* Average Bytes per Second Overall */ + unsigned short wBlockAlign; /* Data Block Size */ + unsigned short wBitsPerSample; /* Sample Size */ + int dwWaveDataSize; /* Data Chunk Length */ + unsigned dwFileSize; /* Number of Audio Samples */ + time_t tWavLength; /* Length of Audio in seconds */ +}; + +struct wavChunk { + char sName[5]; /* Chunk Name */ + off_t oOffset; /* Offset to start of chunk */ + off_t oSize; /* Size of chunk */ +}; + +struct wavProcess { + double dfThreshold; /* Audio Detect Threshold, in in dBd */ + int dSenseTimeout; /* Audio Detect Timeout, in secs */ + double dfNormalLevel; /* Normalize Level, in dBd */ +}; + +#define LIST_SIZE 256 +struct wavList { + /* STANDARD SCHEME */ /* BDCST SCHEME */ + char sIcrd[LIST_SIZE]; /* Creation Date */ /* Not Present */ + char sIart[LIST_SIZE]; /* Original Artist */ /* Advertiser */ + char sIcmt[LIST_SIZE]; /* Comments */ /* Comments */ + char sIcop[LIST_SIZE]; /* Copyright */ /* Agency */ + char sIeng[LIST_SIZE]; /* Engineer */ /* Producer */ + char sIgnr[LIST_SIZE]; /* Genre */ /* Start Date */ + char sIkey[LIST_SIZE]; /* Key Words */ /* End Date */ + char sImed[LIST_SIZE]; /* Original Medium */ /* ???? */ + char sInam[LIST_SIZE]; /* Name */ /* Outcue */ + char sIsft[LIST_SIZE]; /* Software Package */ /* Account Exec. */ + char sIsrc[LIST_SIZE]; /* Source Supplier */ /* Category */ + char sItch[LIST_SIZE]; /* Digitizer */ /* Talent */ + char sIsbj[LIST_SIZE]; /* Subject */ /* Copy */ + char sIsrf[LIST_SIZE]; /* Digitization Source */ /* ???? */ +}; + + +/* + * Function Prototypes + * + * API Entry Points + */ +extern int IsWav(int); +extern int OpenWav(char *,struct wavHeader *); +extern int CreateWav(char *,struct wavHeader *); +extern int FixWav(int,unsigned,unsigned); +extern int FindChunk(int,struct wavChunk *); +extern int GetNextChunk(int,struct wavChunk *); +extern int GetListChunk(int,struct wavList *); +extern int SetDspDesc(int,struct wavHeader *); +extern int PlayWavFile(char *,char *,unsigned); +extern int PlayWavDesc(char *,int,unsigned); +extern int PlayWavOffsetDesc(char *,int,int,unsigned); +extern int RecWavFile(char *,char *,unsigned,unsigned short,unsigned, + unsigned short,unsigned); +extern int RecordWavFile(char *,char *,int,struct wavHeader *, + struct wavProcess *,unsigned); +extern int RecWavDesc(char *,int,unsigned,unsigned short,unsigned, + unsigned short,unsigned); +extern int RecordWavDesc(char *,int,int,struct wavHeader *, + struct wavProcess *,unsigned); +extern double DbToLinear(double); +extern double LinearToDb(double); +extern int GetMixerCat(char *,int,unsigned); +extern int Pattern(int,char *); +extern int SoundConfigFile(char *,int,int); +extern int SoundConfigDesc(int,int,int); +extern ssize_t WriteSword(int,unsigned); +extern ssize_t WriteDword(int,unsigned); +extern int TailTrim(char *,int); +extern int TruncWav(int,struct wavHeader *,struct wavChunk *,unsigned); + +/* + * Signal Handlers + */ +extern void SigStopWav(int); +extern void SigPauseWav(int); +extern void SigResumeWav(int); + + +/* Microsoft WAVE Format Categories */ +#define WAVE_FORMAT_PCM 0x0001 +#define IBM_FORMAT_MULAW 0x0101 +#define IBM_FORMAT_ALAW 0x0102 +#define IBM_FORMAT_ADPCM 0x0103 + +/* + * Option Values + * + * WAVLIB_TEST will cause the function to do everything it ordinarily + * would except actually play the file. Useful for testing to see if + * a particular format is supported by a device. + */ +#define WAVLIB_TEST 0x40000000 + +/* + * WAVLIB_PAUSEABLE enables audio to be paused by sending SIGUSR1 to the + * process and then resumed by sending SIGUSR2. + */ +#define WAVLIB_PAUSEABLE 0x20000000 + + + + diff --git a/utils/rdgpimon/Makefile.am b/utils/rdgpimon/Makefile.am new file mode 100644 index 00000000..cc17b281 --- /dev/null +++ b/utils/rdgpimon/Makefile.am @@ -0,0 +1,74 @@ +## automake.am +## +## Automake.am for rivendell/utils/rdgpimon +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.13.8.2 2013/01/01 21:36:33 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rdgpimon_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rdgpimon_*.qm + +all: + @QT_BIN@/lupdate rdgpimon.pro + @QT_BIN@/lrelease rdgpimon.pro + +bin_PROGRAMS = rdgpimon + +dist_rdgpimon_SOURCES = gpi_label.cpp gpi_label.h\ + rdgpimon.cpp rdgpimon.h + +nodist_rdgpimon_SOURCES = moc_gpi_label.cpp\ + moc_rdgpimon.cpp + +rdgpimon_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdgpimon.pro\ + rdgpimon_cs.ts\ + rdgpimon_de.ts\ + rdgpimon_es.ts\ + rdgpimon_fr.ts\ + rdgpimon_nb.ts\ + rdgpimon_nn.ts\ + rdgpimon_pt_BR.ts + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rdgpimon/gpi_label.cpp b/utils/rdgpimon/gpi_label.cpp new file mode 100644 index 00000000..aa79f147 --- /dev/null +++ b/utils/rdgpimon/gpi_label.cpp @@ -0,0 +1,139 @@ +// gpi_label.cpp +// +// A Qt-based application for testing general purpose input (GPI) devices. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: gpi_label.cpp,v 1.5 2011/05/27 21:28:25 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#include + + +GpiLabel::GpiLabel(QWidget *parent,const char *name) + : QWidget(parent,name) +{ + gpi_line=-1; + + // + // Generate Fonts + // + QFont line_font("Helvetica",18,QFont::Bold); + line_font.setPixelSize(18); + QFont cart_font("Helvetica",12,QFont::Bold); + cart_font.setPixelSize(12); + + // + // Line Label + // + gpi_line_label=new QLabel(this); + gpi_line_label->setGeometry(0,0,59,33); + gpi_line_label->setFont(line_font); + gpi_line_label->setAlignment(AlignHCenter|AlignVCenter); + gpi_line_label->setPalette(gray); + + // + // On Cart Label + // + QPalette p=palette(); + p.setColor(QPalette::Active,QColorGroup::Foreground,darkGreen); + p.setColor(QPalette::Inactive,QColorGroup::Foreground,darkGreen); + p.setColor(QPalette::Disabled,QColorGroup::Foreground,darkGreen); + gpi_oncart_label=new QLabel(this); + gpi_oncart_label->setGeometry(0,33,59,16); + gpi_oncart_label->setFont(cart_font); + gpi_oncart_label->setAlignment(AlignHCenter|AlignTop); + gpi_oncart_label->setPalette(p); + + // + // Off Cart Label + // + p.setColor(QPalette::Active,QColorGroup::Foreground,darkRed); + p.setColor(QPalette::Inactive,QColorGroup::Foreground,darkRed); + p.setColor(QPalette::Disabled,QColorGroup::Foreground,darkRed); + gpi_offcart_label=new QLabel(this); + gpi_offcart_label->setGeometry(0,49,59,16); + gpi_offcart_label->setFont(cart_font); + gpi_offcart_label->setAlignment(AlignHCenter|AlignTop); + gpi_offcart_label->setPalette(p); +} + + +QSize GpiLabel::sizeHint() const +{ + return QSize(59,69); +} + + +QSizePolicy GpiLabel::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +int GpiLabel::line() const +{ + return gpi_line; +} + + +void GpiLabel::setLine(int line) +{ + gpi_line=line; + gpi_line_label->setText(QString().sprintf("%d",line+1)); +} + + +void GpiLabel::setState(bool state) +{ + if(state) { + gpi_line_label->setPalette(green); + } + else { + gpi_line_label->setPalette(gray); + } +} + + +void GpiLabel::setCart(unsigned off_cartnum,unsigned on_cartnum) +{ + if(off_cartnum==0) { + gpi_offcart_label->setText(""); + } + else { + gpi_offcart_label->setText(QString().sprintf("%06u",off_cartnum)); + } + if(on_cartnum==0) { + gpi_oncart_label->setText(""); + } + else { + gpi_oncart_label->setText(QString().sprintf("%06u",on_cartnum)); + } +} + + +void GpiLabel::setMask(bool state) +{ + gpi_offcart_label->setEnabled(state); + gpi_oncart_label->setEnabled(state); +} + + +void GpiLabel::setGeometry(int x,int y,int w,int h) +{ + QWidget::setGeometry(x,y,w,h); +} diff --git a/utils/rdgpimon/gpi_label.h b/utils/rdgpimon/gpi_label.h new file mode 100644 index 00000000..4a75d237 --- /dev/null +++ b/utils/rdgpimon/gpi_label.h @@ -0,0 +1,55 @@ +// gpi_label.h +// +// A Qt-based application for testing general purpose input (GPI) devices. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: gpi_label.h,v 1.4 2010/07/29 19:32:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef GPI_LABEL_H +#define GPI_LABEL_H + +#include +#include + + +class GpiLabel : public QWidget +{ + Q_OBJECT + public: + GpiLabel(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + int line() const; + void setLine(int line); + void setState(bool state); + void setCart(unsigned off_cartnum,unsigned on_cartnum); + void setMask(bool state); + + public slots: + void setGeometry(int x,int y,int w,int h); + + private: + QLabel *gpi_line_label; + QLabel *gpi_oncart_label; + QLabel *gpi_offcart_label; + int gpi_line; +}; + + +#endif // GPI_LABEL_H diff --git a/utils/rdgpimon/rdgpimon.cpp b/utils/rdgpimon/rdgpimon.cpp new file mode 100644 index 00000000..92961654 --- /dev/null +++ b/utils/rdgpimon/rdgpimon.cpp @@ -0,0 +1,567 @@ +// rdgpimon.cpp +// +// A Qt-based application for testing General Purpose Input (GPI) devices. +// +// (C) Copyright 2002-2003 Fred Gleason +// +// $Id: rdgpimon.cpp,v 1.14.6.4 2014/01/21 21:59:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// +// Icons +// +#include "../icons/rivendell-22x22.xpm" + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + // + // Read Command Options + // + RDCmdSwitch *cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdgpimon","\n"); + delete cmd; + + // + // Set Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Font + // + QFont font("helvetica",10,QFont::Normal); + font.setPixelSize(10); + setFont(font); + QFont main_font("helvetica",12,QFont::Bold); + main_font.setPixelSize(12); + + // + // Create And Set Icon + // + gpi_rivendell_map=new QPixmap(rivendell_xpm); + setIcon(*gpi_rivendell_map); + + // + // Load Local Configs + // + gpi_config=new RDConfig(); + gpi_config->load(); + + // + // Open Database + // + gpi_db=QSqlDatabase::addDatabase(gpi_config->mysqlDriver()); + if(!gpi_db) { + QMessageBox::warning(this,tr("Database Error"), + tr("Can't Connect","Unable to connect to mySQL Server!")); + exit(0); + } + gpi_db->setDatabaseName(gpi_config->mysqlDbname()); + gpi_db->setUserName(gpi_config->mysqlUsername()); + gpi_db->setPassword(gpi_config->mysqlPassword()); + gpi_db->setHostName(gpi_config->mysqlHostname()); + if(!gpi_db->open()) { + QMessageBox::warning(this,tr("Can't Connect"), + tr("Unable to connect to mySQL Server!")); + gpi_db->removeDatabase(gpi_config->mysqlDbname()); + exit(0); + } + new RDDbHeartbeat(gpi_config->mysqlHeartbeatInterval(),this); + + // + // RIPC Connection + // + gpi_ripc=new RDRipc(gpi_config->stationName()); + gpi_ripc->setIgnoreMask(true); + connect(gpi_ripc,SIGNAL(userChanged()),this,SLOT(userData())); + connect(gpi_ripc,SIGNAL(gpiStateChanged(int,int,bool)), + this,SLOT(gpiStateChangedData(int,int,bool))); + connect(gpi_ripc,SIGNAL(gpoStateChanged(int,int,bool)), + this,SLOT(gpoStateChangedData(int,int,bool))); + connect(gpi_ripc,SIGNAL(gpiMaskChanged(int,int,bool)), + this,SLOT(gpiMaskChangedData(int,int,bool))); + connect(gpi_ripc,SIGNAL(gpoMaskChanged(int,int,bool)), + this,SLOT(gpoMaskChangedData(int,int,bool))); + connect(gpi_ripc,SIGNAL(gpiCartChanged(int,int,int,int)), + this,SLOT(gpiCartChangedData(int,int,int,int))); + connect(gpi_ripc,SIGNAL(gpoCartChanged(int,int,int,int)), + this,SLOT(gpoCartChangedData(int,int,int,int))); + gpi_ripc->connectHost("localhost",RIPCD_TCP_PORT,gpi_config->password()); + + // + // RDStation + // + gpi_station=new RDStation(gpi_config->stationName()); + + // + // RDMatrix; + // + gpi_matrix=NULL; + + // + // Type Selector + // + gpi_type_box=new QComboBox(this,"gpi_type_box"); + gpi_type_box->setGeometry(80,10,120,21); + gpi_type_box->insertItem(tr("GPI (Inputs)")); + gpi_type_box->insertItem(tr("GPO (Outputs)")); + QLabel *label= + new QLabel(gpi_type_box,tr("Show:"),this,"gpi_type_label"); + label->setGeometry(20,10,55,21); + label->setFont(main_font); + label->setAlignment(AlignRight|AlignVCenter); + connect(gpi_type_box,SIGNAL(activated(int)), + this,SLOT(matrixActivatedData(int))); + + // + // Matrix Selector + // + gpi_matrix_box=new QComboBox(this,"gpi_matrix_box"); + gpi_matrix_box->setGeometry(280,10,80,21); + for(int i=0;iinsertItem(QString().sprintf("%d",i)); + } + label=new QLabel(gpi_matrix_box,tr("Matrix:"),this,"gpi_matrix_label"); + label->setGeometry(220,10,55,21); + label->setFont(main_font); + label->setAlignment(AlignRight|AlignVCenter); + connect(gpi_matrix_box,SIGNAL(activated(int)), + this,SLOT(matrixActivatedData(int))); + + // + // GPI Indicators + // + for(int i=0;isetGeometry(10+64*j,40+78*i, + gpi_labels[i*GPIMON_COLS+j]-> + sizeHint().width(), + gpi_labels[i*GPIMON_COLS+j]-> + sizeHint().height()); + } + } + + // + // Up Button + // + gpi_up_button= + new RDTransportButton(RDTransportButton::Up,this,"gpi_up_button"); + gpi_up_button->setGeometry(10,sizeHint().height()-60,80,50); + connect(gpi_up_button,SIGNAL(clicked()),this,SLOT(upData())); + + // + // Down Button + // + gpi_down_button= + new RDTransportButton(RDTransportButton::Down,this,"gpi_down_button"); + gpi_down_button->setGeometry(100,sizeHint().height()-60,80,50); + connect(gpi_down_button,SIGNAL(clicked()),this,SLOT(downData())); + + // + // Color Key + // + label=new QLabel(tr("Green = ON Cart"),this); + label->setGeometry(200,sizeHint().height()-50,300,12); + label->setFont(main_font); + label->setAlignment(AlignLeft|AlignVCenter); + QPalette p=palette(); + p.setColor(QPalette::Active,QColorGroup::Foreground,darkGreen); + p.setColor(QPalette::Inactive,QColorGroup::Foreground,darkGreen); + p.setColor(QPalette::Disabled,QColorGroup::Foreground,darkGreen); + label->setPalette(p); + + label=new QLabel(tr("Red = OFF Cart"),this); + label->setGeometry(200,sizeHint().height()-32,300,12); + label->setFont(main_font); + label->setAlignment(AlignLeft|AlignVCenter); + p.setColor(QPalette::Active,QColorGroup::Foreground,darkRed); + p.setColor(QPalette::Inactive,QColorGroup::Foreground,darkRed); + p.setColor(QPalette::Disabled,QColorGroup::Foreground,darkRed); + label->setPalette(p); + + + // + // Close Button + // + gpi_close_button=new QPushButton(this,"gpi_close_button"); + gpi_close_button->setGeometry(sizeHint().width()-90,sizeHint().height()-60, + 80,50); + gpi_close_button->setFont(main_font); + gpi_close_button->setText(tr("&Close")); + connect(gpi_close_button,SIGNAL(clicked()),this,SLOT(quitMainWidget())); + + // + // Start Up Timer + // + QTimer *timer=new QTimer(this,"start_up_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(startUpData())); + timer->start(GPIMON_START_UP_DELAY,true); +} + + +MainWidget::~MainWidget() +{ +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(528,78*GPIMON_ROWS+110); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::userData() +{ + QString str; + + str=QString("RDGpiMon")+" v"+VERSION+" - "+tr("User")+":"; + setCaption(str+" "+gpi_ripc->user()); +} + + +void MainWidget::typeActivatedData(int index) +{ +} + + +void MainWidget::matrixActivatedData(int index) +{ + if(gpi_matrix!=NULL) { + delete gpi_matrix; + } + gpi_matrix= + new RDMatrix(gpi_config->stationName(),gpi_matrix_box->currentItem()); + UpdateLabelsDown(0); + gpi_up_button->setDisabled(true); + switch((RDMatrix::GpioType)gpi_type_box->currentItem()) { + case RDMatrix::GpioInput: + gpi_ripc->sendGpiStatus(gpi_matrix_box->currentItem()); + gpi_ripc->sendGpiMask(gpi_matrix_box->currentItem()); + gpi_ripc->sendGpiCart(gpi_matrix_box->currentItem()); + break; + + case RDMatrix::GpioOutput: + gpi_ripc->sendGpoStatus(gpi_matrix_box->currentItem()); + gpi_ripc->sendGpoMask(gpi_matrix_box->currentItem()); + gpi_ripc->sendGpoCart(gpi_matrix_box->currentItem()); + break; + } +} + + +void MainWidget::gpiStateChangedData(int matrix,int line,bool state) +{ + // printf("gpiStateChanged(%d,%d,%d)\n",matrix,line,state); + + if(gpi_type_box->currentItem()!=RDMatrix::GpioInput) { + return; + } + if(matrix!=gpi_matrix->matrix()) { + return; + } + for(int i=0;i<(GPIMON_ROWS*GPIMON_COLS);i++) { + if(gpi_labels[i]->line()==line) { + gpi_labels[i]->setState(state); + } + } +} + + +void MainWidget::gpoStateChangedData(int matrix,int line,bool state) +{ + // printf("gpoStateChanged(%d,%d,%d)\n",matrix,line,state); + + if(gpi_type_box->currentItem()!=RDMatrix::GpioOutput) { + return; + } + if(matrix!=gpi_matrix->matrix()) { + return; + } + for(int i=0;i<(GPIMON_ROWS*GPIMON_COLS);i++) { + if(gpi_labels[i]->line()==line) { + gpi_labels[i]->setState(state); + } + } +} + + +void MainWidget::gpiMaskChangedData(int matrix,int line,bool state) +{ + if(gpi_type_box->currentItem()!=RDMatrix::GpioInput) { + return; + } + if(matrix!=gpi_matrix->matrix()) { + return; + } + for(int i=0;i<(GPIMON_ROWS*GPIMON_COLS);i++) { + if(gpi_labels[i]->line()==line) { + gpi_labels[i]->setMask(state); + } + } +} + + +void MainWidget::gpoMaskChangedData(int matrix,int line,bool state) +{ + if(gpi_type_box->currentItem()!=RDMatrix::GpioOutput) { + return; + } + if(matrix!=gpi_matrix->matrix()) { + return; + } + for(int i=0;i<(GPIMON_ROWS*GPIMON_COLS);i++) { + if(gpi_labels[i]->line()==line) { + gpi_labels[i]->setMask(state); + } + } +} + + +void MainWidget::gpiCartChangedData(int matrix,int line,int off_cartnum, + int on_cartnum) +{ +// printf("gpiCartChangedData(%d,%d,%d,%d)\n",matrix,line,off_cartnum, +// on_cartnum); + + if(gpi_type_box->currentItem()!=RDMatrix::GpioInput) { + return; + } + if(off_cartnum<0) { + off_cartnum=0; + } + if(on_cartnum<0) { + on_cartnum=0; + } + if(matrix!=gpi_matrix->matrix()) { + return; + } + for(int i=0;i<(GPIMON_ROWS*GPIMON_COLS);i++) { + if(gpi_labels[i]->line()==line) { + gpi_labels[i]->setCart(off_cartnum,on_cartnum); + } + } +} + + +void MainWidget::gpoCartChangedData(int matrix,int line,int off_cartnum, + int on_cartnum) +{ + if(gpi_type_box->currentItem()!=RDMatrix::GpioOutput) { + return; + } + if(off_cartnum<0) { + off_cartnum=0; + } + if(on_cartnum<0) { + on_cartnum=0; + } + if(matrix!=gpi_matrix->matrix()) { + return; + } + for(int i=0;i<(GPIMON_ROWS*GPIMON_COLS);i++) { + if(gpi_labels[i]->line()==line) { + gpi_labels[i]->setCart(off_cartnum,on_cartnum); + } + } +} + + +void MainWidget::startUpData() +{ + matrixActivatedData(0); +} + + +void MainWidget::upData() +{ + UpdateLabelsUp(gpi_first_line-1); + gpi_down_button->setEnabled(true); +} + + +void MainWidget::downData() +{ + UpdateLabelsDown(gpi_last_line+1); + gpi_up_button->setEnabled(true); +} + + +void MainWidget::quitMainWidget() +{ + exit(0); +} + + +void MainWidget::UpdateLabelsUp(int last_line) +{ + QString sql; + RDSqlQuery *q; + int count=0; + int count_limit=GPIMON_ROWS*GPIMON_COLS; + bool last_updated=false; + QString tablename="GPIS"; + + for(int i=0;i<(GPIMON_ROWS*GPIMON_COLS);i++) { + gpi_labels[i]->hide(); + } + switch((RDMatrix::GpioType)gpi_type_box->currentItem()) { + case RDMatrix::GpioInput: + tablename="GPIS"; + break; + + case RDMatrix::GpioOutput: + tablename="GPOS"; + break; + } + sql=QString().sprintf("select NUMBER,OFF_MACRO_CART,MACRO_CART from %s \ + where (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&\ + (NUMBER<=%d) order by NUMBER desc", + (const char *)tablename, + (const char *)gpi_station->name(), + gpi_matrix->matrix(),last_line); + q=new RDSqlQuery(sql); + if(q->size()size(); + } + while(q->next()&&(countsetLine(q->value(0).toInt()-1); + gpi_labels[count_limit-count-1]-> + setCart(q->value(1).toUInt(),q->value(2).toUInt()); + gpi_labels[count_limit-count-1]->show(); + if(!last_updated) { + gpi_last_line=q->value(0).toInt(); + last_updated=true; + } + gpi_first_line=q->value(0).toInt(); + count++; + } + gpi_up_button->setEnabled(q->next()); + delete q; +} + + +void MainWidget::UpdateLabelsDown(int first_line) +{ + QString sql; + RDSqlQuery *q; + int count=0; + bool first_updated=false; + QString tablename="GPIS"; + + for(int i=0;i<(GPIMON_ROWS*GPIMON_COLS);i++) { + gpi_labels[i]->hide(); + } + switch((RDMatrix::GpioType)gpi_type_box->currentItem()) { + case RDMatrix::GpioInput: + tablename="GPIS"; + break; + + case RDMatrix::GpioOutput: + tablename="GPOS"; + break; + } + sql=QString().sprintf("select NUMBER,OFF_MACRO_CART,MACRO_CART from %s \ + where (STATION_NAME=\"%s\")&&\ + (MATRIX=%d)&&\ + (NUMBER>=%d) order by NUMBER", + (const char *)tablename, + (const char *)gpi_station->name(), + gpi_matrix->matrix(),first_line); + q=new RDSqlQuery(sql); + while(q->next()&&(count<(GPIMON_ROWS*GPIMON_COLS))) { + gpi_labels[count]->setLine(q->value(0).toInt()-1); + gpi_labels[count]->setCart(q->value(1).toUInt(),q->value(2).toUInt()); + gpi_labels[count]->show(); + if(!first_updated) { + gpi_first_line=q->value(0).toInt(); + first_updated=true; + } + gpi_last_line=q->value(0).toInt(); + count++; + } + gpi_down_button->setEnabled(q->next()); + delete q; +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Load Translations + // + QTranslator qt(0); + qt.load(QString(QTDIR)+QString("/translations/qt_")+QTextCodec::locale(), + "."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(QString(PREFIX)+QString("/share/rivendell/librd_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(QString(PREFIX)+QString("/share/rivendell/librdhpi_")+ + QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(QString(PREFIX)+QString("/share/rivendell/rdgpimon_")+ + QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} diff --git a/utils/rdgpimon/rdgpimon.h b/utils/rdgpimon/rdgpimon.h new file mode 100644 index 00000000..db8df5d9 --- /dev/null +++ b/utils/rdgpimon/rdgpimon.h @@ -0,0 +1,96 @@ +// rdgpimon.h +// +// A Qt-based application for testing general purpose input (GPI) devices. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: rdgpimon.h,v 1.9 2010/07/29 19:32:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDGPIMON_H +#define RDGPIMON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + + +#define GPIMON_START_UP_DELAY 100 +#define GPIMON_ROWS 4 +#define GPIMON_COLS 8 + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + ~MainWidget(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void userData(); + void typeActivatedData(int index); + void matrixActivatedData(int index); + void gpiStateChangedData(int matrix,int line,bool state); + void gpoStateChangedData(int matrix,int line,bool state); + void gpiMaskChangedData(int matrix,int line,bool state); + void gpoMaskChangedData(int matrix,int line,bool state); + void gpiCartChangedData(int matrix,int line,int off_cartnum,int on_cartnum); + void gpoCartChangedData(int matrix,int line,int off_cartnum,int on_cartnum); + void startUpData(); + void upData(); + void downData(); + void quitMainWidget(); + + private: + void UpdateLabelsUp(int last_line); + void UpdateLabelsDown(int first_line); + RDConfig *gpi_config; + QSqlDatabase *gpi_db; + RDRipc *gpi_ripc; + RDStation *gpi_station; + RDMatrix *gpi_matrix; + QComboBox *gpi_type_box; + QComboBox *gpi_matrix_box; + QPushButton *gpi_close_button; + QPixmap *gpi_rivendell_map; + GpiLabel *gpi_labels[GPIMON_ROWS*GPIMON_COLS]; + RDTransportButton *gpi_up_button; + RDTransportButton *gpi_down_button; + int gpi_first_line; + int gpi_last_line; +}; + + +#endif diff --git a/utils/rdgpimon/rdgpimon.pro b/utils/rdgpimon/rdgpimon.pro new file mode 100644 index 00000000..c98818d4 --- /dev/null +++ b/utils/rdgpimon/rdgpimon.pro @@ -0,0 +1,31 @@ +# utils.pro +# +# The utils/ QMake project file for Rivendell +# +# (C) Copyright 2003-2006 Fred Gleason +# +# $Id: rdgpimon.pro,v 1.6.8.1 2013/01/01 21:36:33 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +SOURCES += rdgpimon.cpp +HEADERS += rdgpimon.h + +TRANSLATIONS += rdgpimon_cs.ts +TRANSLATIONS += rdgpimon_de.ts +TRANSLATIONS += rdgpimon_es.ts +TRANSLATIONS += rdgpimon_fr.ts +TRANSLATIONS += rdgpimon_nb.ts +TRANSLATIONS += rdgpimon_nn.ts +TRANSLATIONS += rdgpimon_pt_BR.ts diff --git a/utils/rdgpimon/rdgpimon_cs.ts b/utils/rdgpimon/rdgpimon_cs.ts new file mode 100644 index 00000000..5d7d675b --- /dev/null +++ b/utils/rdgpimon/rdgpimon_cs.ts @@ -0,0 +1,54 @@ + + + MainWidget + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + GPI (Inputs) + + + + GPO (Outputs) + + + + Show: + + + + Matrix: + + + + Green = ON Cart + + + + Red = OFF Cart + + + + &Close + + + + User + + + + diff --git a/utils/rdgpimon/rdgpimon_de.ts b/utils/rdgpimon/rdgpimon_de.ts new file mode 100644 index 00000000..51e7d49f --- /dev/null +++ b/utils/rdgpimon/rdgpimon_de.ts @@ -0,0 +1,58 @@ + + + MainWidget + + Database Error + Datenbankfehler + + + Can't Connect + Unable to connect to mySQL Server! + Kann keine Verbindung zum mySQL-Server herstellen + + + Can't Connect + Kann keine Verbindung herstellen + + + Unable to connect to mySQL Server! + Kann keine Verbindung zum mySQL-Server herstellen! + + + Matrix: + Matrix: + + + &Close + S&chließen + + + RDGpiMon - User: + RDGpiMon-Benutzer: + + + Show: + Zeigen: + + + GPI (Inputs) + GPI (Eingänge) + + + GPO (Outputs) + GPO (Ausgänge) + + + Green = ON Cart + Grün = ON Cart + + + Red = OFF Cart + Rot = OFF Cart + + + User + + + + diff --git a/utils/rdgpimon/rdgpimon_es.ts b/utils/rdgpimon/rdgpimon_es.ts new file mode 100644 index 00000000..b45b1d75 --- /dev/null +++ b/utils/rdgpimon/rdgpimon_es.ts @@ -0,0 +1,58 @@ + + + MainWidget + + Database Error + Error de base de datos + + + Can't Connect + Unable to connect to mySQL Server! + No puedo conectarme + + + Can't Connect + No puedo conectarme + + + Unable to connect to mySQL Server! + ¡No puedo conectarme al servidor MySQL! + + + Matrix: + Matriz: + + + &Close + &Cerrar + + + RDGpiMon - User: + RDGpiMon - Usuario: + + + Show: + Mostrar: + + + GPI (Inputs) + GPI (Entradas) + + + GPO (Outputs) + GPO (Salidas) + + + Green = ON Cart + Verde = Cartucho ENCENDIDO + + + Red = OFF Cart + Rojo = Cartucho APAGADO + + + User + + + + diff --git a/utils/rdgpimon/rdgpimon_fr.ts b/utils/rdgpimon/rdgpimon_fr.ts new file mode 100644 index 00000000..9e0f922d --- /dev/null +++ b/utils/rdgpimon/rdgpimon_fr.ts @@ -0,0 +1,54 @@ + + + MainWidget + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + Matrix: + + + + &Close + + + + Show: + + + + GPI (Inputs) + + + + GPO (Outputs) + + + + Green = ON Cart + + + + Red = OFF Cart + + + + User + + + + diff --git a/utils/rdgpimon/rdgpimon_nb.ts b/utils/rdgpimon/rdgpimon_nb.ts new file mode 100644 index 00000000..e59f1ac3 --- /dev/null +++ b/utils/rdgpimon/rdgpimon_nb.ts @@ -0,0 +1,58 @@ + + + MainWidget + + Database Error + Databasefeil + + + Can't Connect + Unable to connect to mySQL Server! + Kan ikkje kopla til + + + Can't Connect + Kan ikkje kopla til + + + Unable to connect to mySQL Server! + Greier ikkje kopla til mySQL-tenaren! + + + Matrix: + Matrise: + + + &Close + &Lukk + + + RDGpiMon - User: + RDGpiMon-brukar: + + + GPI (Inputs) + + + + GPO (Outputs) + + + + Show: + + + + Green = ON Cart + + + + Red = OFF Cart + + + + User + + + + diff --git a/utils/rdgpimon/rdgpimon_nn.ts b/utils/rdgpimon/rdgpimon_nn.ts new file mode 100644 index 00000000..e59f1ac3 --- /dev/null +++ b/utils/rdgpimon/rdgpimon_nn.ts @@ -0,0 +1,58 @@ + + + MainWidget + + Database Error + Databasefeil + + + Can't Connect + Unable to connect to mySQL Server! + Kan ikkje kopla til + + + Can't Connect + Kan ikkje kopla til + + + Unable to connect to mySQL Server! + Greier ikkje kopla til mySQL-tenaren! + + + Matrix: + Matrise: + + + &Close + &Lukk + + + RDGpiMon - User: + RDGpiMon-brukar: + + + GPI (Inputs) + + + + GPO (Outputs) + + + + Show: + + + + Green = ON Cart + + + + Red = OFF Cart + + + + User + + + + diff --git a/utils/rdgpimon/rdgpimon_pt_BR.ts b/utils/rdgpimon/rdgpimon_pt_BR.ts new file mode 100644 index 00000000..5d7d675b --- /dev/null +++ b/utils/rdgpimon/rdgpimon_pt_BR.ts @@ -0,0 +1,54 @@ + + + MainWidget + + Database Error + + + + Can't Connect + Unable to connect to mySQL Server! + + + + Can't Connect + + + + Unable to connect to mySQL Server! + + + + GPI (Inputs) + + + + GPO (Outputs) + + + + Show: + + + + Matrix: + + + + Green = ON Cart + + + + Red = OFF Cart + + + + &Close + + + + User + + + + diff --git a/utils/rdhpiinfo/Makefile.am b/utils/rdhpiinfo/Makefile.am new file mode 100644 index 00000000..47baa16c --- /dev/null +++ b/utils/rdhpiinfo/Makefile.am @@ -0,0 +1,52 @@ +## automake.am +## +## Automake.am for utils/rdhpiinfo +## +## (C) Copyright 2002-2007 Fred Gleason +## +## $Id: Makefile.am,v 1.4.8.1 2012/11/29 01:37:38 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in +## + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/rdhpi +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib -L$(top_srcdir)/rdhpi +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rdhpiinfo + +dist_rdhpiinfo_SOURCES = change_mode.cpp change_mode.h\ + rdhpiinfo.cpp rdhpiinfo.h + +nodist_rdhpiinfo_SOURCES = moc_change_mode.cpp\ + moc_rdhpiinfo.cpp + +rdhpiinfo_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @LIBHPI@ + +EXTRA_DIST = rdhpiinfo.pro + +CLEANFILES = *~\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rdhpiinfo/change_mode.cpp b/utils/rdhpiinfo/change_mode.cpp new file mode 100644 index 00000000..a62b92b6 --- /dev/null +++ b/utils/rdhpiinfo/change_mode.cpp @@ -0,0 +1,194 @@ +// change_mode.cpp +// +// Change the mode of an AudioScience Adapter. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: change_mode.cpp,v 1.6 2011/05/18 14:38:13 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include + +#include + +ChangeMode::ChangeMode(unsigned short card,unsigned short type,int mode, + QWidget *parent,const char *name) + : QDialog(parent,name,true) +{ + QString str; + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + setCaption(tr("RdhpiInfo - Change Mode")); + + // + // Create Fonts + // + QFont font=QFont("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + QFont label_font=QFont("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + // + // Adapter Type + // + QLabel *label=new QLabel(QString().sprintf("AudioScience %X",type), + this,"type_label"); + label->setGeometry(10,10,sizeHint().width()-20,15); + label->setFont(label_font); + label->setAlignment(AlignCenter); + + // + // Adapter Mode + // + change_mode_box=new QComboBox(this,"change_type_box"); + change_mode_box->setGeometry(10,35,sizeHint().width()-20,22); + change_mode_box->setFont(font); + int index=0; + for(uint32_t i=1;i<11;i++) { + if(HPI_AdapterSetModeEx(NULL,card,i,HPI_ADAPTER_MODE_QUERY)==0) { + switch(i) { + case HPI_ADAPTER_MODE_4OSTREAM: + change_mode_box->insertItem(tr("Four Output Streams")); + break; + + case HPI_ADAPTER_MODE_6OSTREAM: + change_mode_box->insertItem(tr("Six Output Streams")); + break; + + case HPI_ADAPTER_MODE_8OSTREAM: + change_mode_box->insertItem(tr("Eight Output Streams")); + break; + + case HPI_ADAPTER_MODE_12OSTREAM: + change_mode_box->insertItem(tr("Twelve Output Streams")); + break; + + case HPI_ADAPTER_MODE_16OSTREAM: + switch(type) { + case 0x6585: + change_mode_box-> + insertItem(tr("Multichannel Surround (Two Output Streams)")); + break; + + default: + change_mode_box->insertItem(tr("Sixteen Output Streams")); + break; + } + break; + + case HPI_ADAPTER_MODE_1OSTREAM: + change_mode_box->insertItem(tr("One Output Stream")); + break; + + case HPI_ADAPTER_MODE_1: + change_mode_box->insertItem(tr("Mode 1")); + break; + + case HPI_ADAPTER_MODE_2: + change_mode_box->insertItem(tr("Mode 2")); + break; + + case HPI_ADAPTER_MODE_3: + change_mode_box->insertItem(tr("Mode 3")); + break; + + case HPI_ADAPTER_MODE_MULTICHANNEL: + change_mode_box->insertItem(tr("Surround Sound [SSX]")); + break; + + default: + str=QString(tr("Unknown")); + change_mode_box-> + insertItem(QString().sprintf(" %s [MODE=%u]\n", + (const char *)str,(unsigned)i)); + break; + } + hpi_mode_map[index]=i; + if(mode==(int)i) { + change_mode_box->setCurrentItem(index); + change_index=index; + } + index++; + } + } + + // + // Ok Button + // + QPushButton *ok_button=new QPushButton(this,"ok_button"); + ok_button->setGeometry(sizeHint().width()-140,sizeHint().height()-40,60,30); + ok_button->setDefault(true); + ok_button->setFont(font); + ok_button->setText(tr("&OK")); + connect(ok_button,SIGNAL(clicked()),this,SLOT(okData())); + + // + // Cancel Button + // + QPushButton *cancel_button=new QPushButton(this,"cancel_button"); + cancel_button->setGeometry(sizeHint().width()-70,sizeHint().height()-40, + 60,30); + cancel_button->setFont(font); + cancel_button->setText(tr("&Cancel")); + connect(cancel_button,SIGNAL(clicked()),this,SLOT(cancelData())); +} + + +QSize ChangeMode::sizeHint() const +{ + return QSize(280,110); +} + + +QSizePolicy ChangeMode::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void ChangeMode::closeEvent(QCloseEvent *e) +{ + cancelData(); +} + + +void ChangeMode::okData() +{ + if(change_mode_box->currentItem()==change_index) { + done(-1); + return; + } + if(QMessageBox::warning(this,"RDHPIInfo",tr("The HPI driver will need to be restarted\nafter changing the mode. Continue?"),QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) { + return; + } + done(hpi_mode_map[change_mode_box->currentItem()]); + return; +} + + +void ChangeMode::cancelData() +{ + done(-1); +} diff --git a/utils/rdhpiinfo/change_mode.h b/utils/rdhpiinfo/change_mode.h new file mode 100644 index 00000000..3723101a --- /dev/null +++ b/utils/rdhpiinfo/change_mode.h @@ -0,0 +1,61 @@ +// change_mode.h +// +// Change the mode of an AudioScience Adapter +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: change_mode.h,v 1.5 2011/05/18 14:38:14 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef CHANGE_MODE_H +#define CHANGE_MODE_H + +#define MAX_HPI_MODES 11 + +#include +#include + +#include +#ifndef HPI_ADAPTER_MODE_MULTICHANNEL +#define HPI_ADAPTER_MODE_MULTICHANNEL (9) +#endif + + +class ChangeMode : public QDialog +{ + Q_OBJECT + public: + ChangeMode(unsigned short card,unsigned short type,int mode, + QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + protected: + void closeEvent(QCloseEvent *e); + + private slots: + void okData(); + void cancelData(); + + private: + int change_index; + uint32_t hpi_mode_map[MAX_HPI_MODES]; + QComboBox *change_mode_box; +}; + + +#endif + diff --git a/utils/rdhpiinfo/rdhpiinfo.cpp b/utils/rdhpiinfo/rdhpiinfo.cpp new file mode 100644 index 00000000..c9db9b66 --- /dev/null +++ b/utils/rdhpiinfo/rdhpiinfo.cpp @@ -0,0 +1,420 @@ +// rdhpiinfo.cpp +// +// A Qt-based application for display information on ASI cards. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: rdhpiinfo.cpp,v 1.8.6.4 2014/01/21 21:59:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QWidget(parent,name) +{ + hpi_err_t hpi_err; + + setCaption(tr("RDHPIInfo")+" v"+VERSION); + + // + // Fix the Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Load the command-line arguments + // + RDCmdSwitch *cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdhpiinfo", + RDHPIINFO_USAGE); + delete cmd; + + // + // Generate Fonts + // + QFont font("Helvetica",12,QFont::Normal); + font.setPixelSize(12); + QFont label_font("Helvetica",12,QFont::Bold); + label_font.setPixelSize(12); + + // + // Open HPI + // + if(HPI_SubSysCreate()==NULL) { + printf("HERE\n"); + QMessageBox::warning(this,tr("HPI Error"), + tr("The ASI HPI Driver is not loaded!")); + exit(1); + } + + // + // HPI Version + // + hpi_err=HPI_SubSysGetVersionEx(NULL,&hpi_version); + QLabel *label=new QLabel(tr("HPI Version:"),this,"hpi_version_label"); + label->setGeometry(10,10,85,20); + label->setFont(label_font); + label=new QLabel(QString().sprintf("%X.%02X.%02X", + (unsigned)((hpi_version>>16)&0xffff), + (unsigned)((hpi_version>>8)&0xff), + (unsigned)hpi_version&0xff), + this,"hpi_version"); + label->setGeometry(100,10,100,20); + label->setFont(font); + + // + // Adapter Name + // + info_name_box=new QComboBox(this,"info_name_box"); + info_name_box->setGeometry(100,34,sizeHint().width()-110,20); + info_name_box->setFont(font); + info_name_label=new QLabel(info_name_box,tr("Adapter:"), + this,"info_name_label"); + info_name_label->setGeometry(10,34,85,20); + info_name_label->setFont(label_font); + info_name_label->setAlignment(AlignRight|AlignVCenter); + connect(info_name_box,SIGNAL(activated(int)), + this,SLOT(nameActivatedData(int))); + + // + // Adapter Index + // + label=new QLabel(tr("Adapter Index:"),this,"index_number_label"); + label->setGeometry(10,58,105,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter); + info_index_label=new QLabel(this,"info_index_label"); + info_index_label->setGeometry(120,58,100,20); + info_index_label->setFont(font); + info_index_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Serial Number + // + label=new QLabel(tr("Serial Number:"),this,"serial_number_label"); + label->setGeometry(10,78,105,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter); + info_serial_label=new QLabel(this,"info_serial_label"); + info_serial_label->setGeometry(120,78,100,20); + info_serial_label->setFont(font); + info_serial_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Output Streams + // + label=new QLabel(tr("Input Streams:"),this,"input_streams_label"); + label->setGeometry(10,98,105,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter); + info_istreams_label=new QLabel(this,"info_istreams_label"); + info_istreams_label->setGeometry(120,98,100,20); + info_istreams_label->setFont(font); + info_istreams_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Input Streams + // + label=new QLabel(tr("Output Streams:"),this,"output_streams_label"); + label->setGeometry(10,118,105,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter); + info_ostreams_label=new QLabel(this,"info_ostreams_label"); + info_ostreams_label->setGeometry(120,118,100,20); + info_ostreams_label->setFont(font); + info_ostreams_label->setAlignment(AlignLeft|AlignVCenter); + + // + // DSP Version + // + label=new QLabel(tr("DSP Version:"),this,"dsp_version_label"); + label->setGeometry(10,138,105,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter); + info_dsp_label=new QLabel(this,"info_dsp_label"); + info_dsp_label->setGeometry(120,138,100,20); + info_dsp_label->setFont(font); + info_dsp_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Adapter Version + // + label=new QLabel(tr("Adapter Version:"),this,"adapter_version_label"); + label->setGeometry(10,158,105,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter); + info_adapter_label=new QLabel(this,"info_adapter_label"); + info_adapter_label->setGeometry(120,158,100,20); + info_adapter_label->setFont(font); + info_adapter_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Adapter Mode + // + label=new QLabel(tr("Adapter Mode:"),this,"adapter_mode_label"); + label->setGeometry(10,178,105,20); + label->setFont(label_font); + label->setAlignment(AlignRight|AlignVCenter); + info_mode_label=new QLabel(this,"info_mode_label"); + info_mode_label->setGeometry(120,178,sizeHint().width()-130,20); + info_mode_label->setFont(font); + info_mode_label->setAlignment(AlignLeft|AlignVCenter); + + // + // Change Mode Button + // + info_changemode_button= + new QPushButton(tr("Change Card Mode"),this,"info_changemode_button"); + info_changemode_button->setGeometry(130,200,170,30); + info_changemode_button->setFont(label_font); + connect(info_changemode_button,SIGNAL(clicked()), + this,SLOT(changeModeData())); + + // + // Close Button + // + QPushButton *button=new QPushButton(tr("Close"),this,"close_button"); + button->setGeometry(sizeHint().width()-60,sizeHint().height()-40,50,30); + button->setFont(label_font); + connect(button,SIGNAL(clicked()),qApp,SLOT(quit())); + + LoadAdapters(); + if(info_name_box->count()>0) { + nameActivatedData(0); + } +} + + +MainWidget::~MainWidget() +{ + HPI_SubSysFree(NULL); +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(400,250); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::nameActivatedData(int id) +{ + QString str; + int card=name_map[id]; + info_index_label-> + setText(QString().sprintf("%u",(unsigned)hpi_indexes[card]+1)); + info_serial_label-> + setText(QString().sprintf("%u",(unsigned)hpi_serial[card])); + info_istreams_label-> + setText(QString().sprintf("%d",hpi_istreams[card])); + info_ostreams_label-> + setText(QString().sprintf("%d",hpi_ostreams[card])); + info_dsp_label->setText(QString().sprintf("%d.%d", + hpi_card_version[card]>>13, + (hpi_card_version[card]>>7)&63)); + info_adapter_label-> + setText(QString().sprintf("%c%d", + ((hpi_card_version[card]>>3)&15)+'A', + hpi_card_version[card]&7)); + switch(hpi_mode[card]) { + case 0: // No mode support + info_mode_label->setText(tr("Standard")); + info_changemode_button->setDisabled(true); + break; + + case HPI_ADAPTER_MODE_4OSTREAM: + info_mode_label->setText(tr("Four Output Streams")); + info_changemode_button->setEnabled(true); + break; + + case HPI_ADAPTER_MODE_6OSTREAM: + info_mode_label->setText(tr("Six Output Streams")); + info_changemode_button->setEnabled(true); + break; + + case HPI_ADAPTER_MODE_8OSTREAM: + info_mode_label->setText(tr("Eight Output Streams")); + info_changemode_button->setEnabled(true); + break; + + case HPI_ADAPTER_MODE_12OSTREAM: + info_mode_label->setText(tr("Twelve Output Streams")); + info_changemode_button->setEnabled(true); + break; + + case HPI_ADAPTER_MODE_16OSTREAM: + switch(hpi_type[card]) { + case 0x6585: + info_mode_label-> + setText(tr("Multichannel Surround (Two Output Streams)")); + break; + + default: + info_mode_label->setText(tr("Sixteen Output Streams")); + break; + } + info_changemode_button->setEnabled(true); + break; + + case HPI_ADAPTER_MODE_1OSTREAM: + info_mode_label->setText(tr("One Output Stream")); + info_changemode_button->setEnabled(true); + break; + + case HPI_ADAPTER_MODE_1: + info_mode_label->setText(tr("Mode 1")); + info_changemode_button->setEnabled(true); + break; + + case HPI_ADAPTER_MODE_2: + info_mode_label->setText(tr("Mode 2")); + info_changemode_button->setEnabled(true); + break; + + case HPI_ADAPTER_MODE_3: + info_mode_label->setText(tr("Mode 3")); + info_changemode_button->setEnabled(true); + break; + + case HPI_ADAPTER_MODE_MULTICHANNEL: + info_mode_label->setText(tr("Surround Sound [SSX]")); + info_changemode_button->setEnabled(true); + break; + + default: + info_mode_label->setText(tr("N/A")); + info_changemode_button->setDisabled(true); + if(hpi_mode[card]!=hpi_serial[card]) { + str=QString(tr("rdhpiinfo: unknown adapter mode")); + fprintf(stderr,"%s %d\n",(const char *)str,hpi_mode[card]); + } + break; + } +} + + +void MainWidget::changeModeData() +{ + int card=name_map[info_name_box->currentItem()]; + int mode; + QString str; + hpi_err_t hpi_err; + char hpi_text[100]; + ChangeMode *dialog=new ChangeMode(card,hpi_type[card],hpi_mode[card], + this,"change_mode_dialog"); + if((mode=dialog->exec())<0) { + delete dialog; + return; + } + delete dialog; + hpi_err=HPI_AdapterOpen(NULL,card); + if((hpi_err=HPI_AdapterSetMode(NULL,card,mode))==0) { + QMessageBox::information(this,tr("RdhpiInfo"), + tr("The adapter mode has been changed.\nYou must now restart the HPI driver!")); + } + else { + HPI_GetErrorText(hpi_err,hpi_text); + str=QString(tr("HPI Error")); + QMessageBox::warning(this,tr("RdhpiInfo"), + QString().sprintf("%s %d:\n\"%s\"",(const char *)str, + (int)hpi_err,hpi_text)); + } + hpi_err=HPI_AdapterClose(NULL,card); +} + + +void MainWidget::LoadAdapters() +{ + int num_adapters; + hpi_err_t hpi_err; + + hpi_err=HPI_SubSysGetNumAdapters(NULL,&num_adapters); + for(int i=0;iinsertItem(QString().sprintf("AudioScience %X [%d]", + hpi_type[i],i+1)); + name_map[info_name_box->count()-1]=i; + HpiErr(HPI_AdapterOpen(NULL,hpi_indexes[i]),"HPI_AdapterOpen"); + HpiErr(HPI_AdapterGetInfo(NULL,hpi_indexes[i],&hpi_ostreams[i],&hpi_istreams[i], + &hpi_card_version[i],hpi_serial+i, + &hpi_type[i]),"HPI_AdapterGetInfo"); + HpiErr(HPI_AdapterGetMode(NULL,hpi_indexes[i],&hpi_mode[i]), + "HPI_AdapterGetMode"); + HpiErr(HPI_AdapterClose(NULL,hpi_indexes[i]),"HPI_AdapterClose"); + } + } +} + + +void MainWidget::HpiErr(hpi_err_t err,const char *func_name) const +{ + char hpi_str[200]; + + if(err==HPI_ERROR_INVALID_FUNC) { + return; + } + if(err!=0) { + HPI_GetErrorText(err,hpi_str); + if(func_name==NULL) { + fprintf(stderr,"rdhpiinfo: %s\n",hpi_str); + } + else { + fprintf(stderr,"rdhpiinfo[%s]: %s\n",func_name,hpi_str); + } + } +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(QRect(QPoint(0,0),w->sizeHint())); + w->show(); + return a.exec(); +} diff --git a/utils/rdhpiinfo/rdhpiinfo.h b/utils/rdhpiinfo/rdhpiinfo.h new file mode 100644 index 00000000..a0509e95 --- /dev/null +++ b/utils/rdhpiinfo/rdhpiinfo.h @@ -0,0 +1,79 @@ +// rdhpiinfo.h +// +// A Qt-based application for display info about ASI cards. +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: rdhpiinfo.h,v 1.5.6.1 2012/05/04 14:56:23 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDHPIINFO_H +#define RDHPIINFO_H + +#include +#include +#include +#include + +#include +#if HPI_VER < 0x040600 +typedef uint16_t hpi_err_t; +typedef uint32_t hpi_handle_t; +#endif + +#define RDHPIINFO_USAGE "\n" + +class MainWidget : public QWidget +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + ~MainWidget(); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void nameActivatedData(int id); + void changeModeData(); + + private: + void LoadAdapters(); + void HpiErr(hpi_err_t err,const char *func_name=0) const; + QLabel *info_name_label; + QComboBox *info_name_box; + QLabel *info_index_label; + QLabel *info_serial_label; + QLabel *info_istreams_label; + QLabel *info_ostreams_label; + QLabel *info_dsp_label; + QLabel *info_adapter_label; + QLabel *info_mode_label; + QPushButton *info_changemode_button; + uint32_t hpi_version; + QString hpi_name[HPI_MAX_ADAPTERS]; + int name_map[HPI_MAX_ADAPTERS]; + uint32_t hpi_indexes[HPI_MAX_ADAPTERS]; + uint16_t hpi_ostreams[HPI_MAX_ADAPTERS]; + uint16_t hpi_istreams[HPI_MAX_ADAPTERS]; + uint16_t hpi_card_version[HPI_MAX_ADAPTERS]; + uint32_t hpi_serial[HPI_MAX_ADAPTERS]; + uint16_t hpi_type[HPI_MAX_ADAPTERS]; + uint32_t hpi_mode[HPI_MAX_ADAPTERS]; +}; + + +#endif // RDHPIINFO_H diff --git a/utils/rdhpiinfo/rdhpiinfo.pro b/utils/rdhpiinfo/rdhpiinfo.pro new file mode 100644 index 00000000..e69de29b diff --git a/utils/rdimport/Makefile.am b/utils/rdimport/Makefile.am new file mode 100644 index 00000000..f950e622 --- /dev/null +++ b/utils/rdimport/Makefile.am @@ -0,0 +1,51 @@ +## automake.am +## +## Automake.am for rivendell/utils/rdimport +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.8.8.1 2012/11/29 01:37:38 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rdimport + +dist_rdimport_SOURCES = rdimport.cpp rdimport.h + +nodist_rdimport_SOURCES = moc_rdimport.cpp + +rdimport_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rdimport/rdimport.cpp b/utils/rdimport/rdimport.cpp new file mode 100644 index 00000000..55185728 --- /dev/null +++ b/utils/rdimport/rdimport.cpp @@ -0,0 +1,1568 @@ +// rdimport.cpp +// +// A Batch Importer for Rivendell. +// +// (C) Copyright 2002-2008 Fred Gleason +// +// $Id: rdimport.cpp,v 1.34.4.9.2.3 2014/07/15 00:45:16 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +volatile bool import_run=true; + +void SigHandler(int signo) +{ + switch(signo) { + case SIGTERM: + case SIGINT: + case SIGHUP: + import_run=false; + break; + } +} + + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + // + // Initialize Data Structures + // + bool ok=false; + int n=0; + import_file_key=0; + import_group=NULL; + import_verbose=false; + import_log_mode=false; + import_single_cart=false; + import_use_cartchunk_cutid=false; + import_cart_number_offset=0; + import_cart_number=0; + import_title_from_cartchunk_cutid=false; + import_delete_source=false; + import_delete_cuts=false; + import_drop_box=false; + import_set_user_defined=""; + import_stdin_specified=false; + import_startdate_offset=0; + import_enddate_offset=0; + import_fix_broken_formats=false; + import_persistent_dropbox_id=-1; + import_create_dates=false; + import_create_startdate_offset=0; + import_create_enddate_offset=0; + + // + // Read Command Options + // + import_cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdimport",RDIMPORT_USAGE); + if(import_cmd->keys()<2) { + fprintf(stderr,"\n"); + fprintf(stderr,"%s",RDIMPORT_USAGE); + fprintf(stderr,"\n"); + delete import_cmd; + exit(256); + } + for(unsigned i=0;ikeys()-2;i++) { + if(import_cmd->key(i)=="--verbose") { + import_verbose=true; + } + if(import_cmd->key(i)=="--log-mode") { + import_verbose=true; + import_log_mode=true; + } + if(import_cmd->key(i)=="--to-cart") { + import_cart_number=import_cmd->value(i).toUInt(&ok); + if((!ok)||(import_cart_number<1)||(import_cart_number>999999)) { + fprintf(stderr,"rdimport: invalid cart number\n"); + delete import_cmd; + exit(256); + } + if(import_use_cartchunk_cutid) { + fprintf(stderr,"rdimport: '--to-cart' and '--use-cartchunk-cutid' are mutually exclusive\n"); + delete import_cmd; + exit(256); + } + import_single_cart=true; + } + if(import_cmd->key(i)=="--use-cartchunk-cutid") { + if(import_cart_number!=0) { + fprintf(stderr,"rdimport: '--to-cart' and '--use-cartchunk-cutid' are mutually exclusive\n"); + delete import_cmd; + exit(256); + } + import_use_cartchunk_cutid=true; + } + if(import_cmd->key(i)=="--cart-number-offset") { + import_cart_number_offset=import_cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"rdimport: invalid --cart-number-offset\n"); + exit(256); + } + } + if(import_cmd->key(i)=="--title-from-cartchunk-cutid") { + import_title_from_cartchunk_cutid=true; + } + if(import_cmd->key(i)=="--delete-source") { + import_delete_source=true; + } + if(import_cmd->key(i)=="--delete-cuts") { + import_delete_cuts=true; + } + if(import_cmd->key(i)=="--startdate-offset") { + import_startdate_offset=import_cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"rdimport: invalid startdate-offset\n"); + delete import_cmd; + exit(256); + } + } + if(import_cmd->key(i)=="--enddate-offset") { + import_enddate_offset=import_cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"rdimport: invalid enddate-offset\n"); + delete import_cmd; + exit(256); + } + } + if(import_cmd->key(i)=="--set-daypart-times") { + QStringList f0=QStringList().split(",",import_cmd->value(i)); + if(f0.size()!=2) { + fprintf(stderr,"rdimport: invalid argument to --set-daypart-times\n"); + exit(256); + } + for(unsigned j=0;j<2;j++) { + if(f0[j].length()!=6) { + fprintf(stderr,"rdimport: invalid argument to --set-daypart-times\n"); + exit(256); + } + unsigned hour=f0[j].left(2).toUInt(&ok); + if((!ok)||(hour>23)) { + fprintf(stderr,"rdimport: invalid hour argument to --set-daypart-times\n"); + exit(256); + } + unsigned min=f0[j].mid(2,2).toUInt(&ok); + if((!ok)||(min>59)) { + fprintf(stderr,"rdimport: invalid minute argument to --set-daypart-times\n"); + exit(256); + } + unsigned sec=f0[j].right(2).toUInt(&ok); + if((!ok)||(sec>59)) { + fprintf(stderr,"rdimport: invalid seconds argument to --set-daypart-times\n"); + exit(256); + } + import_dayparts[j].setHMS(hour,min,sec); + } + if(import_dayparts[0]>=import_dayparts[1]) { + fprintf(stderr,"rdimport: daypart cannot end before it begins\n"); + exit(256); + } + } + if(import_cmd->key(i)=="--drop-box") { + import_drop_box=true; + if(import_persistent_dropbox_id<0) { + import_delete_source=true; + } + } + if(import_cmd->key(i)=="--add-scheduler-code") { + import_add_scheduler_codes.push_back(import_cmd->value(i)); + } + if(import_cmd->key(i)=="--set-user-defined") { + import_set_user_defined=import_cmd->value(i); + } + if(import_cmd->key(i)=="--metadata-pattern") { + import_metadata_pattern=import_cmd->value(i); + if(!VerifyPattern(import_metadata_pattern)) { + fprintf(stderr,"rdimport: invalid metadata pattern\n"); + delete import_cmd; + exit(256); + } + } + if(import_cmd->key(i)=="--fix-broken-formats") { + import_fix_broken_formats=true; + } + if(import_cmd->key(i)=="--persistent-dropbox-id") { + import_persistent_dropbox_id=import_cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"rdimport: invalid persistent dropbox id\n"); + delete import_cmd; + exit(256); + } + } + if(import_cmd->key(i)=="--create-startdate-offset") { + import_create_startdate_offset=import_cmd->value(i).toInt(&ok); + if(!ok) { + fprintf(stderr,"rdimport: invalid create-startddate-offset\n"); + delete import_cmd; + exit(256); + } + import_create_dates=true; + } + if(import_cmd->key(i)=="--create-enddate-offset") { + import_create_enddate_offset=import_cmd->value(i).toInt(&ok); + if((!ok) || + (import_create_startdate_offset > import_create_enddate_offset )) { + fprintf(stderr,"rdimport: invalid create-enddate-offset\n"); + delete import_cmd; + exit(256); + } + import_create_dates=true; + } + } + + // + // Read Configuration + // + import_config=new RDConfig(); + import_config->load(); + + // + // Open Database + // + QSqlDatabase *db=QSqlDatabase::addDatabase(import_config->mysqlDriver()); + if(!db) { + fprintf(stderr,"rdimport: unable to initialize connection to database\n"); + delete import_cmd; + exit(256); + } + db->setDatabaseName(import_config->mysqlDbname()); + db->setUserName(import_config->mysqlUsername()); + db->setPassword(import_config->mysqlPassword()); + db->setHostName(import_config->mysqlHostname()); + if(!db->open()) { + fprintf(stderr,"rdimport: unable to connect to database\n"); + db->removeDatabase(import_config->mysqlDbname()); + exit(256); + } + new RDDbHeartbeat(import_config->mysqlHeartbeatInterval(),this); + + // + // RIPC Connection + // + import_ripc=new RDRipc(import_config->stationName()); + connect(import_ripc,SIGNAL(userChanged()),this,SLOT(userData())); + import_ripc-> + connectHost("localhost",RIPCD_TCP_PORT,import_config->password()); + + // + // Station Configuration + // + import_station=new RDStation(import_config->stationName()); + + // + // User + // + import_user=NULL; + + // + // Verify Group + // + for(unsigned i=0;ikeys();i++) { + if(import_cmd->key(i).left(2)!="--") { + import_group=new RDGroup(import_cmd->key(i)); + if(!import_group->exists()) { + fprintf(stderr,"rdimport: invalid group specified\n"); + delete import_group; + delete import_cmd; + exit(256); + } + import_file_key=i+1; + i=import_cmd->keys(); + } + } + if(import_group==NULL) { + fprintf(stderr,"rdimport: invalid group specified\n"); + delete import_cmd; + exit(256); + } + if(import_cart_number>0) { + if(!import_group->cartNumberValid(import_cart_number)) { + fprintf(stderr,"rdimport: invalid cart number for group\n"); + delete import_group; + delete import_cmd; + exit(256); + } + } + + // + // Verify Scheduler Codes + // + for(unsigned i=0;istationName(),0); + import_system=new RDSystem(); + import_format=library_conf->defaultFormat(); + import_samprate=import_system->sampleRate(); + import_bitrate=library_conf->defaultBitrate(); + import_channels=library_conf->defaultChannels(); + import_normalization_level=library_conf->ripperLevel(); + import_autotrim_level=library_conf->trimThreshold(); + import_src_converter=library_conf->srcConverter(); + delete library_conf; + import_segue_level=0; + import_segue_length=0; + + + for(unsigned i=0;ikeys();i++) { + if(import_cmd->key(i)=="--normalization-level") { + n=import_cmd->value(i).toInt(&ok); + if(ok&&(n<=0)) { + import_normalization_level=100*n; + } + else { + fprintf(stderr,"rdimport: invalid normalization level\n"); + delete import_cmd; + exit(256); + } + } + if(import_cmd->key(i)=="--autotrim-level") { + n=import_cmd->value(i).toInt(&ok); + if(ok&&(n<=0)) { + import_autotrim_level=100*n; + } + else { + fprintf(stderr,"rdimport: invalid autotrim level\n"); + delete import_cmd; + exit(256); + } + } + if(import_cmd->key(i)=="--segue-level") { + n=import_cmd->value(i).toInt(&ok); + if(ok&&(n<=0)) { + import_segue_level=100*n; + } + else { + fprintf(stderr,"rdimport: invalid segue level\n"); + delete import_cmd; + exit(256); + } + } + if(import_cmd->key(i)=="--segue-length") { + n=import_cmd->value(i).toInt(&ok); + if(ok&&(n>=0)) { + import_segue_length=n; + } + else { + fprintf(stderr,"rdimport: invalid segue length\n"); + delete import_cmd; + exit(256); + } + } + if(import_cmd->key(i)=="--single-cart") { + import_single_cart=true; + } + } + + // + // Print Status Messages + // + if(import_verbose) { + printf("\n"); + if(import_log_mode) { + PrintLogDateTime(stdout); + printf("rdimport started\n"); + } + printf("RDImport v%s\n",VERSION); + if(import_log_mode) { + printf(" Log mode is ON\n"); + } + else { + printf(" Log mode is OFF\n"); + } + if(import_normalization_level==0) { + printf(" Normalization is OFF\n"); + } + else { + printf(" Normalization level = %d dB\n",import_normalization_level/100); + } + if(import_autotrim_level==0) { + printf(" AutoTrim is OFF\n"); + } + else { + printf(" AutoTrim level = %d dB\n",import_autotrim_level/100); + } + if(import_cart_number==0) { + if(import_use_cartchunk_cutid) { + printf(" Destination cart is taken from CartChunk CutID\n"); + } + else { + printf(" Destination cart is AUTO\n"); + } + } + else { + printf(" Destination cart is %06u\n",import_cart_number); + } + if(import_single_cart) { + printf(" Single cart mode is ON\n"); + } + else { + printf(" Single cart mode is OFF\n"); + } + if(import_title_from_cartchunk_cutid) { + printf(" Destination cart title is taken from CartChunk CutID\n"); + } + if(import_cart_number_offset!=0) { + printf(" Cart number offset is %d\n",import_cart_number_offset); + } + if(import_delete_source) { + printf(" Delete source mode is ON\n"); + } + else { + printf(" Delete source mode is OFF\n"); + } + if(import_delete_cuts) { + printf(" Delete cuts mode is ON\n"); + } + else { + printf(" Delete cuts mode is OFF\n"); + } + if(import_drop_box) { + printf(" DropBox mode is ON\n"); + } + else { + printf(" DropBox mode is OFF\n"); + } + if(import_add_scheduler_codes.size()>0) { + printf(" Adding Scheduler Code(s):"); + for(unsigned i=0;i=0) { + printf(" Persistent DropBox ID = %d\n",import_persistent_dropbox_id); + } + printf(" Files to process:\n"); + for(unsigned i=import_file_key;ikeys();i++) { + printf(" \"%s\"\n",(const char *)import_cmd->key(i)); + } + printf("\n"); + fflush(stdout); + } + + // + // Setup Signal Handling + // + ::signal(SIGTERM,SigHandler); + ::signal(SIGINT,SigHandler); + ::signal(SIGHUP,SigHandler); +} + + +void MainObject::userData() +{ + // + // Get User Context + // + disconnect(import_ripc,SIGNAL(userChanged()),this,SLOT(userData())); + if(import_user!=NULL) { + delete import_user; + } + import_user=new RDUser(import_ripc->user()); + + // + // Verify Permissions + // + if(!import_user->editAudio()) { + fprintf(stderr,"rdimport: user \"%s\" has no edit audio permission\n", + (const char *)import_user->name()); + exit(256); + } + + // + // Process Files + // + if(import_drop_box) { + RunDropBox(); + } + else { + for(unsigned i=import_file_key;ikeys();i++) { + ProcessFileList(import_cmd->key(i)); + } + if(import_stdin_specified) { + bool quote_mode=false; + bool escape_mode=false; + char buffer[PATH_MAX]; + unsigned ptr=0; + while((ptr0) { + buffer[ptr]=0; + ProcessFileList(buffer); + } + } + } + + // + // Clean Up and Exit + // + delete import_group; + delete import_cmd; + + exit(0); +} + + +void MainObject::RunDropBox() +{ + // + // Set Process Priority + // + struct sched_param sp; + memset(&sp,0,sizeof(sp)); + if(sched_setscheduler(getpid(),SCHED_BATCH,&sp)!=0) { + printf(" Unable to set batch permissions, %s",strerror(errno)); + } + + do { + // + // Clear the Checked Flag + // + for(std::list::const_iterator + ci=import_dropbox_list.begin(); + ci!=import_dropbox_list.end();ci++) { + (*ci)->checked=false; + } + + // + // Scan for Eligible Imports + // + for(unsigned i=import_file_key;ikeys();i++) { + ProcessFileList(import_cmd->key(i)); + } + + // + // Take Out the Trash + // + for(std::list::iterator + ci=import_dropbox_list.begin(); + ci!=import_dropbox_list.end();ci++) { + if(!(*ci)->checked) { + delete *ci; + import_dropbox_list.erase(ci); + ci=import_dropbox_list.end(); + } + } + + sleep(RDIMPORT_DROPBOX_SCAN_INTERVAL); + } while(import_run); + if(import_log_mode) { + PrintLogDateTime(); + printf("rdimport stopped\n"); + fflush(stdout); + } +} + + +void MainObject::ProcessFileList(const QString &flist) +{ + QString entry; + + for(unsigned i=0;iname()); + RDWaveData *wavedata=new RDWaveData(); + RDWaveFile *wavefile=new RDWaveFile(filename); + if(wavefile->openWave(wavedata)) { + effective_filename=filename; + } + else { + if(import_fix_broken_formats) { + if(import_verbose) { + PrintLogDateTime(); + printf(" File \"%s\" appears to be malformed, trying workaround ... ", + (const char *)RDGetBasePart(filename).utf8()); + fflush(stdout); + } + delete wavefile; + if((wavefile=FixFile(filename,wavedata))==NULL) { + if(import_verbose) { + printf("failed.\n"); + } + PrintLogDateTime(stderr); + fprintf(stderr, + " File \"%s\" is not readable or not a recognized format, skipping...\n", + (const char *)RDGetBasePart(filename).utf8()); + fflush(stderr); + delete wavefile; + delete wavedata; + delete effective_group; + if(!import_run) { + exit(0); + } + if(!import_temp_fix_filename.isEmpty()) { +// printf("Fixed Name: %s\n",(const char *)import_temp_fix_filename); + QFile::remove(import_temp_fix_filename); + import_temp_fix_filename=""; + } + return MainObject::FileBad; + } + if(import_verbose) { + printf("success.\n"); + fflush(stdout); + } + effective_filename=import_temp_fix_filename; + } + else { + PrintLogDateTime(stderr); + fprintf(stderr, + " File \"%s\" is not readable or not a recognized format, skipping...\n", + (const char *)RDGetBasePart(filename).utf8()); + fflush(stderr); + delete wavefile; + delete wavedata; + delete effective_group; + if(!import_run) { + exit(0); + } + if(!import_temp_fix_filename.isEmpty()) { + QFile::remove(import_temp_fix_filename); + import_temp_fix_filename=""; + } + return MainObject::FileBad; + } + } + + if(!import_metadata_pattern.isEmpty()) { + QString groupname=effective_group->name(); + found_cart=RunPattern(import_metadata_pattern,RDGetBasePart(filename), + wavedata,&groupname); + if(groupname!=effective_group->name()) { + delete effective_group; + effective_group=new RDGroup(groupname); + if(!effective_group->exists()) { + PrintLogDateTime(stderr); + fprintf(stderr," Specified group \"%s\" from file \"%s\" does not exist, using default group...\n", + (const char *)groupname,(const char *)filename.utf8()); + fflush(stderr); + delete effective_group; + effective_group=new RDGroup(import_group->name()); + } + } + } + + if(import_use_cartchunk_cutid||found_cart) { + *cartnum=0; + sscanf(wavedata->cutId(),"%u",cartnum); + (*cartnum)+=import_cart_number_offset; + if((*cartnum==0)||(*cartnum>999999)|| + (effective_group->enforceCartRange()&& + (!effective_group->cartNumberValid(*cartnum)))) { + PrintLogDateTime(stderr); + fprintf(stderr, + " File \"%s\" has an invalid or out of range Cart Number, skipping...\n", + (const char *)RDGetBasePart(filename).utf8()); + fflush(stderr); + wavefile->closeWave(); + delete wavefile; + delete wavedata; + delete effective_group; + return MainObject::FileBad; + } + } + if(*cartnum==0) { + *cartnum=effective_group->nextFreeCart(); + } + if(*cartnum==0) { + PrintLogDateTime(stderr); + fprintf(stderr,"rdimport: no free carts available in specified group\n"); + fflush(stderr); + wavefile->closeWave(); + delete wavefile; + delete wavedata; + delete effective_group; + if(import_drop_box) { + if(!import_run) { + exit(0); + } + if(!import_temp_fix_filename.isEmpty()) { + QFile::remove(import_temp_fix_filename); + import_temp_fix_filename=""; + } + return MainObject::NoCart; + } + exit(256); + } + if(import_delete_cuts) { + DeleteCuts(import_cart_number); + } + RDCart *cart=new RDCart(*cartnum); + if(!cart->exists()) { + cart->create(effective_group->name(),RDCart::Audio); + cart_created=true; + } + int cutnum= + cart->addCut(import_format,import_bitrate,import_channels); + if(cutnum<0) { + fprintf(stderr,"rdimport: no free cuts available in cart %06u\n",*cartnum); + delete cart; + return MainObject::NoCut; + } + RDCut *cut=new RDCut(QString().sprintf("%06u_%03d",*cartnum,cutnum)); + RDAudioImport *conv=new RDAudioImport(import_station,import_config,this); + conv->setCartNumber(cart->number()); + conv->setCutNumber(cutnum); + conv->setSourceFile(wavefile->getName()); + RDSettings *settings=new RDSettings(); + settings->setChannels(import_channels); + switch(import_format) { + case 0: + settings->setFormat(RDSettings::Pcm16); + break; + + case 1: + settings->setFormat(RDSettings::MpegL2Wav); + break; + } + settings->setNormalizationLevel(import_normalization_level/100); + settings->setAutotrimLevel(import_autotrim_level/100); + conv->setDestinationSettings(settings); + conv->setUseMetadata(cart_created); + if(import_verbose) { + PrintLogDateTime(); + if(wavedata->title().length()==0 || ( (wavedata->title().length()>0) && (wavedata->title()[0] == '\0')) ) { + printf(" Importing file \"%s\" to cart %06u ... ", + (const char *)RDGetBasePart(filename).utf8(),*cartnum); + } + else { + printf(" Importing file \"%s\" [%s] to cart %06u ... ", + (const char *)RDGetBasePart(filename).utf8(), + (const char *)wavedata->title().stripWhiteSpace(),*cartnum); + } + fflush(stdout); + } + + switch(conv_err=conv->runImport(import_user->name(),import_user->password(), + &audio_conv_err)) { + case RDAudioImport::ErrorOk: + if(import_verbose) { + printf("done.\n"); + } + break; + + default: + PrintLogDateTime(stderr); + fprintf(stderr," %s, skipping %s...\n", + (const char *)RDAudioImport::errorText(conv_err,audio_conv_err), + (const char *)filename.utf8()); + fflush(stderr); + if(cart_created) { + cart->remove(import_station,import_user,import_config); + } + else { + cart->removeCut(import_station,import_user,cut->cutName(),import_config); + } + delete cut; + delete cart; + wavefile->closeWave(); + delete wavefile; + delete wavedata; + delete effective_group; + if(!import_run) { + exit(0); + } + if(!import_temp_fix_filename.isEmpty()) { + QFile::remove(import_temp_fix_filename); + import_temp_fix_filename=""; + } + return MainObject::FileBad; + break; + } + if(wavedata->metadataFound()) { + if(import_autotrim_level!=0) { + wavedata->setStartPos(-1); + wavedata->setEndPos(-1); + } + if(cart_created) { + cart->setMetadata(wavedata); + } + cut->setMetadata(wavedata); + } + cut->autoSegue(import_segue_level,import_segue_length); + if((wavedata->title().length()==0)|| + ((wavedata->title().length()>0)&&(wavedata->title()[0] == '\0'))) { + QString title=effective_group->defaultTitle(); + QString basename=RDGetBasePart(filename); + int ptr=basename.findRev("."); + title.replace("%p",RDGetPathPart(filename)); + title.replace("%f",basename.left(ptr)); + title.replace("%e",basename.right(basename.length()-ptr-1)); + cut->setDescription(title.utf8()); + if(cart_created) { + cart->setTitle(title.utf8()); + } + } + if(import_title_from_cartchunk_cutid) { + if((wavedata->cutId().length()>0)&&(wavedata->cutId()[0]!='\0')) { + if(cut->description().isEmpty()) { + cut->setDescription(wavedata->cutId()); + } + cart->setTitle(wavedata->cutId()); + } + } + if(!import_metadata_pattern.isEmpty()) { + cart->setTitle(wavedata->title()); + } + if(import_startdate_offset!=0) { + dt=cut->startDatetime(&ok); + if(ok) { + cut->setStartDatetime(dt.addDays(import_startdate_offset),true); + } + } + if(import_enddate_offset!=0) { + dt=cut->endDatetime(&ok); + if(ok) { + cut->setEndDatetime(dt.addDays(import_enddate_offset),true); + } + } + if(import_create_dates) { + dt=cut->startDatetime(&ok); + if (!ok){ + dt=QDateTime(QDate::currentDate(), QTime(0,0,0)); + cut->setStartDatetime(dt.addDays(import_create_startdate_offset),true); + } + dt=cut->endDatetime(&ok); + if(!ok) { + dt=QDateTime(QDate::currentDate(), QTime(23,59,59)); + cut->setEndDatetime(dt.addDays(import_create_enddate_offset),true); + } + } + cut->setOriginName(import_station->name()); + for(unsigned i=0;iaddSchedCode(import_add_scheduler_codes[i]); + } + if(!import_set_user_defined.isEmpty()) { + cart->setUserDefined(import_set_user_defined); + } + if((!import_dayparts[0].isNull())||(!import_dayparts[1].isNull())) { + cut->setStartDaypart(import_dayparts[0],true); + cut->setEndDaypart(import_dayparts[1],true); + } + delete settings; + delete conv; + delete cut; + delete cart; + wavefile->closeWave(); + delete wavefile; + delete wavedata; + delete effective_group; + + if(import_delete_source) { + unlink(filename.utf8()); + if(import_verbose) { + PrintLogDateTime(); + printf(" Deleted file \"%s\"\n",(const char *)RDGetBasePart(filename).utf8()); + fflush(stdout); + } + } + if(!import_run) { + exit(0); + } + if(!import_temp_fix_filename.isEmpty()) { + QFile::remove(import_temp_fix_filename); + import_temp_fix_filename=""; + } + + return MainObject::Success; +} + + +void MainObject::VerifyFile(const QString &filename,unsigned *cartnum) +{ + bool found=false; + QDateTime dt; + + for(std::list::const_iterator + ci=import_dropbox_list.begin(); + ci!=import_dropbox_list.end();ci++) { + if((*ci)->filename==filename) { + found=true; + QFileInfo *file=new QFileInfo(filename); + dt=GetCachedTimestamp(filename); + if(dt.isNull()||(file->lastModified()>dt)) { + if((file->size()==(*ci)->size)&&(!(*ci)->failed)) { + (*ci)->pass++; + } + else { + (*ci)->size=file->size(); + (*ci)->pass=0; + } + if((*ci)->failed) { + (*ci)->checked=true; + if(file->size()!=(*ci)->size) { + (*ci)->failed=false; + (*ci)->size=file->size(); + (*ci)->pass=0; + } + } + if((*ci)->pass>=RDIMPORT_DROPBOX_PASSES) { + switch(ImportFile(filename,cartnum)) { + case MainObject::Success: + WriteTimestampCache(filename,file->lastModified()); + break; + + case MainObject::FileBad: + (*ci)->failed=true; + (*ci)->checked=true; + (*ci)->pass=0; + WriteTimestampCache(filename,file->lastModified()); + break; + + case MainObject::NoCart: + case MainObject::NoCut: + (*ci)->pass=0; + (*ci)->checked=true; + break; + } + } + else { + (*ci)->checked=true; + } + } + delete file; + } + } + if(!found) { + QFile *file=new QFile(filename); + import_dropbox_list.push_back(new struct DropboxList()); + import_dropbox_list.back()->filename=filename; + import_dropbox_list.back()->size=file->size(); + import_dropbox_list.back()->pass=0; + import_dropbox_list.back()->checked=true; + import_dropbox_list.back()->failed=false; + delete file; + } +} + + +RDWaveFile *MainObject::FixFile(const QString &filename,RDWaveData *wavedata) +{ + bool fix_needed=false; + + // + // Determine Fixability + // + int fd=open(filename,O_RDONLY); + if(fd<0) { + return NULL; + } + if(!IsWav(fd)) { + return NULL; + } + if(!FindChunk(fd,"fmt ",&fix_needed)) { + return NULL; + } + if(!FindChunk(fd,"data",&fix_needed)) { + return NULL; + } + if(!fix_needed) { // This shouldn't ever happen! + return NULL; + } + ::close(fd); + + // + // Copy File + // + import_temp_fix_filename= + QString(tempnam(RDTempDir(),"rdfix"))+QString(".wav"); + if(import_temp_fix_filename.isNull()) { + return NULL; + } + if(!RDCopy(filename,import_temp_fix_filename)) { + return NULL; + } + + // + // Apply Fix + // + if(!FixChunkSizes(import_temp_fix_filename)) { + return NULL; + } + RDWaveFile *wf=new RDWaveFile(); + wf->nameWave(import_temp_fix_filename); + if(!wf->openWave(wavedata)) { + delete wf; + return NULL; + } + return wf; +} + + +bool MainObject::IsWav(int fd) +{ + int i; + char buffer[5]; + + // + // Is this a riff file? + // + lseek(fd,0,SEEK_SET); + i=read(fd,buffer,4); + if(i==4) { + buffer[4]=0; + if(strcmp("RIFF",buffer)!=0) { + return false; + } + } + else { + return false; + } + + // + // Is this a WAVE file? + // + if(lseek(fd,8,SEEK_SET)!=8) { + return false; + } + i=read(fd,buffer,4); + if(i==4) { + buffer[4]=0; + if(strcmp("WAVE",buffer)!=0) { + return false; + } + } + else { + return false; + } + return true; +} + + +bool MainObject::FindChunk(int fd,const char *chunk_name,bool *fix_needed) +{ + int i; + char name[5]={0,0,0,0,0}; + unsigned char buffer[4]; + off_t offset; + unsigned chunk_size; + + offset=lseek(fd,12,SEEK_SET); + i=read(fd,name,4); + i=read(fd,buffer,4); + chunk_size=buffer[0]+(256*buffer[1])+(65536*buffer[2])+(16777216*buffer[3]); + while(i==4) { + if(strcasecmp(chunk_name,name)==0) { + return true; + } + lseek(fd,chunk_size,SEEK_CUR); + i=read(fd,name,4); + if(name[0]==0) { // Possible chunk size error + if(isalpha(name[1])==0) { + return false; + } + name[0]=name[1]; + name[1]=name[2]; + name[2]=name[3]; + if(read(fd,name+3,1)<1) { + return false; + } + *fix_needed=true; + } + i=read(fd,buffer,4); + chunk_size= + buffer[0]+(256*buffer[1])+(65536*buffer[2])+(16777216*buffer[3]); + } + return false; +} + + +bool MainObject::FixChunkSizes(const QString &filename) +{ + int i; + char name[5]={0,0,0,0,0}; + unsigned char buffer[4]; + off_t offset; + unsigned chunk_size; + int fd; + + // + // Open File + // + if((fd=open(filename,O_RDWR))<0) { + return false; + } + offset=lseek(fd,12,SEEK_SET); + i=read(fd,name,4); + i=read(fd,buffer,4); + off_t last_offset=lseek(fd,0,SEEK_CUR); + chunk_size=buffer[0]+(256*buffer[1])+(65536*buffer[2])+(16777216*buffer[3]); + while(i==4) { + lseek(fd,chunk_size,SEEK_CUR); + i=read(fd,name,4); + if(name[0]==0) { // Possible chunk size error + if(isalpha(name[1])==0) { + return false; + } + // + // Fix It Up + // + name[0]=name[1]; + name[1]=name[2]; + name[2]=name[3]; + if(read(fd,name+3,1)<1) { + ::close(fd); + return false; + } + off_t pos=lseek(fd,0,SEEK_CUR); + char buf[4]; + lseek(fd,last_offset,SEEK_SET); + read(fd,buf,4); + unsigned size=(0xff&buf[0])+(0xff&(256*buf[1]))+ + (0xff&(65536*buf[2]))+(0xff&(16777216*buf[3]))+1; + buf[0]=size&0xff; + buf[1]=(size>>8)&0xff; + buf[2]=(size>>16)&0xff; + buf[3]=(size>>24)&0xff; + lseek(fd,last_offset,SEEK_SET); + write(fd,buf,4); + lseek(fd,pos,SEEK_SET); + } + last_offset=lseek(fd,0,SEEK_CUR); + i=read(fd,buffer,4); + chunk_size= + buffer[0]+(256*buffer[1])+(65536*buffer[2])+(16777216*buffer[3]); + } + ::close(fd); + return true; +} + + +bool MainObject::RunPattern(const QString &pattern,const QString &filename, + RDWaveData *wavedata,QString *groupname) +{ + bool macro_active=false; + unsigned ptr=0; + QChar field; + QString value; + QChar delimiter; + bool found_cartnum=false; + + // + // Initialize Pattern Parser + // + if((pattern.at(0)=='%')&&(pattern.at(1)!='%')) { + field=pattern.at(1); + value=""; + delimiter=pattern.at(2); + ptr=3; + macro_active=true; + } + else { + delimiter=pattern.at(0); + ptr=1; + } + + for(unsigned i=0;i<=filename.length();i++) { + if(macro_active) { + if((filename.at(i)==delimiter)||(i==filename.length())) { + switch(field) { + case 'a': + wavedata->setArtist(value); + wavedata->setMetadataFound(true); + break; + + case 'b': + wavedata->setLabel(value); + wavedata->setMetadataFound(true); + break; + + case 'c': + wavedata->setClient(value); + wavedata->setMetadataFound(true); + break; + + case 'e': + wavedata->setAgency(value); + wavedata->setMetadataFound(true); + break; + + case 'g': + *groupname=value; + break; + + case 'l': + wavedata->setAlbum(value); + wavedata->setMetadataFound(true); + break; + + case 'm': + wavedata->setComposer(value); + wavedata->setMetadataFound(true); + break; + + case 'n': + wavedata->setCutId(value); + wavedata->setMetadataFound(true); + found_cartnum=true; + break; + + case 'p': + wavedata->setPublisher(value); + wavedata->setMetadataFound(true); + break; + + case 'r': + wavedata->setConductor(value); + wavedata->setMetadataFound(true); + break; + + case 's': + wavedata->setTmciSongId(value); + wavedata->setMetadataFound(true); + break; + + case 't': + wavedata->setTitle(value); + wavedata->setMetadataFound(true); + break; + + case 'u': + wavedata->setUserDefined(value); + wavedata->setMetadataFound(true); + break; + } + value=""; + if((ptr>=pattern.length())||(i==filename.length())) { + return found_cartnum; + } + if((pattern.at(ptr)=='%')&&(pattern.at(ptr+1)!='%')) { + field=pattern.at(ptr+1); + delimiter=pattern.at(ptr+2); + ptr+=3; + macro_active=true; + } + else { + delimiter=pattern.at(ptr); + ptr++; + macro_active=false; + } + } + else { + value+=filename.at(i); + } + } + else { + if((ptr>=pattern.length())||(i==filename.length())) { + return found_cartnum; + } + if(filename.at(i)!=delimiter) { + return found_cartnum; + } + if((pattern.at(ptr)=='%')&&(pattern.at(ptr+1)!='%')) { + field=pattern.at(ptr+1); + delimiter=pattern.at(ptr+2); + ptr+=3; + macro_active=true; + } + else { + delimiter=pattern.at(ptr); + ptr++; + macro_active=false; + } + } + } + return found_cartnum; +} + + +bool MainObject::VerifyPattern(const QString &pattern) +{ + bool macro_active=false; + for(unsigned i=0;iremoveAllCuts(import_station,import_user,import_config); + cart->updateLength(); + cart->resetRotation(); + cart->calculateAverageLength(&dev); + cart->setLengthDeviation(dev); + delete cart; +} + + +QDateTime MainObject::GetCachedTimestamp(const QString &filename) +{ + QString sql; + RDSqlQuery *q; + QDateTime dt; + if(import_persistent_dropbox_id<0) { + return dt; + } + sql=QString().sprintf("select FILE_DATETIME from DROPBOX_PATHS \ + where (DROPBOX_ID=%d)&&(FILE_PATH=\"%s\")", + import_persistent_dropbox_id, + (const char *)RDEscapeString(filename)); + q=new RDSqlQuery(sql); + if(q->first()) { + dt=q->value(0).toDateTime(); + } + delete q; + return dt; +} + + +void MainObject::WriteTimestampCache(const QString &filename, + const QDateTime &dt) +{ + QString sql; + RDSqlQuery *q; + if(import_persistent_dropbox_id<0) { + return; + } + if(GetCachedTimestamp(filename).isNull()) { + sql=QString().sprintf("insert into DROPBOX_PATHS set \ + DROPBOX_ID=%d,\ + FILE_PATH=\"%s\",\ + FILE_DATETIME=\"%s\"", + import_persistent_dropbox_id, + (const char *)RDEscapeString(filename), + (const char *)dt.toString("yyyy-MM-dd hh:mm:ss")); + } + else { + sql=QString().sprintf("update DROPBOX_PATHS set FILE_DATETIME=\"%s\" \ + where (DROPBOX_ID=%d)&&(FILE_PATH=\"%s\")", + (const char *)dt.toString("yyyy-MM-dd hh:mm:ss"), + import_persistent_dropbox_id, + (const char *)RDEscapeString(filename)); + } + q=new RDSqlQuery(sql); + delete q; +} + + +bool MainObject::SchedulerCodeExists(const QString &code) const +{ + QString sql; + RDSqlQuery *q; + bool ret=false; + + sql=QString("select CODE from SCHED_CODES where CODE=\"")+ + RDEscapeString(code)+"\""; + q=new RDSqlQuery(sql); + ret=q->first(); + delete q; + + return ret; +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/utils/rdimport/rdimport.h b/utils/rdimport/rdimport.h new file mode 100644 index 00000000..64a8359c --- /dev/null +++ b/utils/rdimport/rdimport.h @@ -0,0 +1,133 @@ +// rdimport.h +// +// A Batch Importer for Rivendell. +// +// (C) Copyright 2002-2009 Fred Gleason +// +// $Id: rdimport.h,v 1.17.6.3.2.3 2014/07/15 00:45:17 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDIMPORT_H +#define RDIMPORT_H + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RDIMPORT_TEMP_BASENAME "rdimp" +#define RDIMPORT_STDIN_BUFFER_LENGTH 1024 +#define RDIMPORT_DROPBOX_SCAN_INTERVAL 5 +#define RDIMPORT_DROPBOX_PASSES 3 +#define RDIMPORT_USAGE "[options] []*\n\nImport one or more files into the specified group in the library. By\ndefault, a new cart will be created for each file imported. A of \n'-' will cause RDImport to read the list of filespecs from standard input.\n\nThe following options are available:\n\n --verbose\n Print progress messages during processing.\n\n --log-mode\n Prepend date/time information to each line of printed status (implies\n the '--verbose' option).\n\n --normalization-level=\n Specify the level to use for normalizing the audio, in dBFS.\n Specifying '0' will turn off normalization.\n\n --autotrim-level=\n Specify the threshold level to use for autotrimming the audio, in\n dBFS. Specifying '0' will turn off autotrimming.\n\n --single-cart\n If more than one file is imported, place them within multiple cuts\n within a single cart, rather than creating separate carts for each\n file.\n\n --segue-level=\n Specify the threshold level to use for setting the segue markers,\n in dBFS.\n\n --segue-length=\n Length of the added segue in msecs.\n\n --to-cart=\n Specify the cart to import the audio into, rather than using the next\n available cart number for the group. If the cart does not exist, it will\n be created. Each file will be imported into a separate new cut within the\n cart. Use of this option implies the '--single-cart' option as well,\n and is mutually exclusive with the '--use-cartchunk-cutid' option.\n\n --use-cartchunk-cutid\n Import the audio into the cart specified by the CartChunk CutID parameter\n associated with the file. If the cart does not exist, it will be\n created. Use of this option is mutually exclusive with the '--to-cart'\n option.\n\n --title-from-cartchunk-cutid\n Set the cart title from CartChunk CutID.\n\n --cart-number-offset=\n Add to the cart number as determined from metadata pattern\n or --use-cartchunk-cutid\n\n --delete-source\n Delete each source file after successful import. Use with caution!\n\n --delete-cuts\n Delete all cuts within the destination cart before importing. Use\n with caution!\n\n --drop-box\n Operate in DropBox mode. RDImport will run continuously, periodically\n scanning for the specified files, importing and then deleting them when\n found. WARNING: use of this option in command-line mode also implies\n the '--delete-source' option!\n\n --metadata-pattern=\n Attempt to read metadata parameters from the source filename, using\n the pattern . Patterns consist of a sequence of macros and\n regular characters to indicate boundaries between metadata fields.\n The available macros are:\n\n %a - Artist\n %b - Record Label\n %c - Client\n %e - Agency\n %g - Rivendell Group\n %l - Album\n %m - Composer\n %n - Rivendell Cart Number\n %p - Publisher\n %r - Conductor\n %s - Song ID\n %t - Title\n %u - User Defined\n %% - A literal '%'\n\n Detection of either the Rivendell Group [%g] or Rivendell Cart [%n]\n will cause RDImport to attempt to import the file to the specified Group\n and/or Cart, overriding whatever values were specified elsewhere on the\n command line. If the '--set-user-defined=' option has been used,\n then the value specified there will be used instead of %u.\n\n Boundaries between metadata fields are indicated by placing regular\n characters between macros. For example, the pattern '%t_%a_%g_%n.',\n when processing a filename of 'My Song_My Artist_TEMP_123456.mp3',\n would extract 'My Song' as the title and 'My Artist' as the artist,\n while importing it into cart 123456 in the TEMP group.\n\n --startdate-offset=\n If the imported file references a start date, offset the value by\n days.\n\n --enddate-offset=\n If the imported file references an end date, offset the value by\n days.\n\n --create-startdate-offset=\n If the imported file does not reference a start date, create with \n startdate offset by days relative to the current date.\n Cannot be greater than the value for --create-enddate-offset\n (default = 0).\n\n --create-enddate-offset=\n If the imported file does not reference an end date, create with\n end date offset by days relative to the current date.\n Cannot be less than the value the value for --create-startdate-offset\n (default = 0).\n\n --set-daypart-times=,\n Set the start and end daypart times, in the format HHMMSS.\n\n --fix-broken-formats\n Attempt to work around malformed audio input data.\n\n --add-scheduler-code=\n Add Scheduler Code to the target cart. The specified\n code must exist in RDAdmin->SchedulerCodes. This option may be\n specified multiple times.\n\n --set-user-defined=\n Set the User Defined field for the target cart to . This will\n override any value that might otherwise be set (see the\n '--metadata-pattern=' option above).\n\nNOTES\nIt may be necessary to enclose individual clauses in quotes in\norder to protect wildcard characters from expansion by the shell. A typical\nindicator that this is necessary is the failure of RDImport to process newly\nadded files when running in DropBox mode.\n" +#define RDIMPORT_GLOB_SIZE 10 + +class MainObject : public QObject +{ + Q_OBJECT; + public: + MainObject(QObject *parent=0,const char *name=0); + + private slots: + void userData(); + + private: + enum Result {Success=0,FileBad=1,NoCart=2,NoCut=3}; + void RunDropBox(); + void ProcessFileList(const QString &flist); + void ProcessFileEntry(const QString &entry); + MainObject::Result ImportFile(const QString &filename,unsigned *cartnum); + void VerifyFile(const QString &filename,unsigned *cartnum); + RDWaveFile *FixFile(const QString &filename,RDWaveData *wavedata); + bool IsWav(int fd); + bool FindChunk(int fd,const char *name,bool *fix_needed); + bool FixChunkSizes(const QString &filename); + bool RunPattern(const QString &pattern,const QString &filename, + RDWaveData *wavedata,QString *groupname); + bool VerifyPattern(const QString &pattern); + void PrintLogDateTime(FILE *f=stdout); + void DeleteCuts(unsigned cartnum); + QDateTime GetCachedTimestamp(const QString &filename); + void WriteTimestampCache(const QString &filename,const QDateTime &dt); + bool SchedulerCodeExists(const QString &code) const; + RDConfig *import_config; + RDCmdSwitch *import_cmd; + unsigned import_file_key; + RDGroup *import_group; + RDRipc *import_ripc; + RDUser *import_user; + bool import_verbose; + bool import_log_mode; + bool import_use_cartchunk_cutid; + int import_cart_number_offset; + bool import_single_cart; + bool import_title_from_cartchunk_cutid; + bool import_delete_source; + bool import_delete_cuts; + bool import_drop_box; + std::vector import_add_scheduler_codes; + QString import_set_user_defined; + bool import_stdin_specified; + int import_startdate_offset; + int import_enddate_offset; + bool import_create_dates; + int import_create_startdate_offset; + int import_create_enddate_offset; + QTime import_dayparts[2]; + bool import_fix_broken_formats; + int import_persistent_dropbox_id; + unsigned import_format; + unsigned import_samprate; + unsigned import_bitrate; + unsigned import_channels; + int import_src_converter; + int import_normalization_level; + int import_autotrim_level; + int import_segue_level; + int import_segue_length; + unsigned import_cart_number; + QString import_metadata_pattern; + struct DropboxList { + QString filename; + unsigned size; + unsigned pass; + bool checked; + bool failed; + }; + std::list import_dropbox_list; + QString import_temp_fix_filename; + RDSystem *import_system; + RDStation *import_station; +}; + + +#endif // RDIMPORT_H diff --git a/utils/rdmaint/Makefile.am b/utils/rdmaint/Makefile.am new file mode 100644 index 00000000..2356baca --- /dev/null +++ b/utils/rdmaint/Makefile.am @@ -0,0 +1,49 @@ +## automake.am +## +## Automake.am for rivendell/utils/rdmaint +## +## (C) Copyright 2008 Fred Gleason +## +## $Id: Makefile.am,v 1.6.8.1 2012/11/29 01:37:38 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rdmaint + +dist_rdmaint_SOURCES = rdmaint.cpp rdmaint.h + +rdmaint_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rdmaint/rdmaint.cpp b/utils/rdmaint/rdmaint.cpp new file mode 100644 index 00000000..ea42c20b --- /dev/null +++ b/utils/rdmaint/rdmaint.cpp @@ -0,0 +1,277 @@ +// rdmaint.cpp +// +// A Utility for running periodic system maintenance. +// +// (C) Copyright 2008 Fred Gleason +// +// $Id: rdmaint.cpp,v 1.9.4.4 2013/11/13 23:36:39 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + QString sql; + RDSqlQuery *q; + unsigned schema=0; + + // + // Initialize Data Structures + // + maint_verbose=false; + maint_system=false; + + // + // Read Command Options + // + maint_cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(), + "rdmaint",RDMAINT_USAGE); + if(maint_cmd->keys()>3) { + fprintf(stderr,"\n"); + fprintf(stderr,"%s",RDMAINT_USAGE); + fprintf(stderr,"\n"); + delete maint_cmd; + exit(256); + } + for(unsigned i=0;ikeys();i++) { + if(maint_cmd->key(i)=="--verbose") { + maint_verbose=true; + } + if(maint_cmd->key(i)=="--system") { + maint_system=true; + } + } + + // + // Read Configuration + // + maint_config=new RDConfig(); + maint_config->load(); + + // + // Open Database + // + QString err (tr("rdmaint: ")); + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + fprintf(stderr,err.ascii()); + delete maint_cmd; + exit(256); + } + delete maint_cmd; + + // + // Get Station + // + maint_station=new RDStation(maint_config->stationName()); + + // + // Get User + // + sql="select LOGIN_NAME from USERS where ADMIN_CONFIG_PRIV=\"Y\""; + q=new RDSqlQuery(sql); + if(!q->first()) { + fprintf(stderr,"unable to find valid user\n"); + exit(256); + } + maint_user=new RDUser(q->value(0).toString()); + delete q; + + if(maint_system) { + RunSystemMaintenance(); + } + else { + RunLocalMaintenance(); + } + + exit(0); +} + + +void MainObject::RunSystemMaintenance() +{ + QString sql; + RDSqlQuery *q; + + PurgeCuts(); + PurgeLogs(); + PurgeElr(); + sql="update VERSION set LAST_MAINT_DATETIME=now()"; + q=new RDSqlQuery(sql); + delete q; +} + + +void MainObject::RunLocalMaintenance() +{ + PurgeDropboxes(); +} + + +void MainObject::PurgeCuts() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + RDSqlQuery *q2; + QDateTime dt=QDateTime(QDate::currentDate(),QTime::currentTime()); + + sql=QString("select NAME,CUT_SHELFLIFE,DELETE_EMPTY_CARTS from GROUPS ")+ + "where CUT_SHELFLIFE>=0"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString().sprintf("select CART.NUMBER,CUTS.CUT_NAME \ + from CUTS left join CART \ + on CUTS.CART_NUMBER=CART.NUMBER \ + where (CART.GROUP_NAME=\"%s\")&&\ + (CUTS.END_DATETIME<\"%s 00:00:00\")", + (const char *)RDEscapeString(q->value(0).toString()), + (const char *)dt.addDays(-q->value(1).toInt()). + toString("yyyy-MM-dd")); + q1=new RDSqlQuery(sql); + while(q1->next()) { + RDCart *cart=new RDCart(q1->value(0).toUInt()); + if(cart->removeCut(maint_station,maint_user,q1->value(1).toString(), + maint_config)) { + maint_config-> + log("rdmaint",RDConfig::LogInfo,QString().sprintf("purged cut %s", + (const char *)q1->value(1).toString())); + } + else { + maint_config-> + log("rdmaint",RDConfig::LogErr,QString(). + sprintf("unable to purge cut %s: audio deletion error", + (const char *)q1->value(1).toString())); + } + if(q->value(2).toString()=="Y") { // Delete Empty Cart + sql=QString().sprintf("select CUT_NAME from CUTS where CART_NUMBER=%u", + q1->value(0).toUInt()); + q2=new RDSqlQuery(sql); + if(!q2->first()) { + cart->remove(maint_station,maint_user,maint_config); + maint_config-> + log("rdmaint",RDConfig::LogInfo,QString(). + sprintf("deleted purged cart %06u",cart->number())); + } + delete q2; + } + delete cart; + } + delete q1; + } + delete q; +} + + +void MainObject::PurgeLogs() +{ + QString sql; + RDSqlQuery *q; + QDateTime dt=QDateTime(QDate::currentDate(),QTime::currentTime()); + + sql=QString().sprintf("select NAME from LOGS where \ + (PURGE_DATE!=\"0000-00-00\")&&(PURGE_DATE<\"%s\")", + (const char *)dt.date().toString("yyyy-MM-dd")); + q=new RDSqlQuery(sql); + while(q->next()) { + maint_config-> + log("rdmain",RDConfig::LogInfo,QString().sprintf("purged log %s", + (const char *)q->value(0).toString())); + RDLog *log=new RDLog(q->value(0).toString()); + log->remove(maint_station,maint_user,maint_config); + delete log; + } + delete q; +} + + +void MainObject::PurgeElr() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + QDateTime dt=QDateTime(QDate::currentDate(),QTime::currentTime()); + + sql="select NAME,ELR_SHELFLIFE from SERVICES where ELR_SHELFLIFE>=0"; + q=new RDSqlQuery(sql); + while(q->next()) { + QString tablename=q->value(0).toString()+"_SRT"; + tablename.replace(" ","_"); + sql=QString().sprintf("delete from %s where EVENT_DATETIME<\"%s 00:00:00\"", + (const char *)tablename, + (const char *)dt.addDays(-q->value(1).toInt()). + toString("yyyy-MM-dd")); + q1=new RDSqlQuery(sql); + delete q1; + } + delete q; +} + + +void MainObject::PurgeDropboxes() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + sql=QString().sprintf("select DROPBOX_PATHS.FILE_PATH,DROPBOX_PATHS.ID from \ + DROPBOXES left join DROPBOX_PATHS \ + on (DROPBOXES.ID=DROPBOX_PATHS.DROPBOX_ID) \ + where DROPBOXES.STATION_NAME=\"%s\"", + (const char *)RDEscapeString(maint_config-> + stationName())); + q=new RDSqlQuery(sql); + while(q->next()) { + if(!QFile::exists(q->value(0).toString())) { + sql=QString().sprintf("delete from DROPBOX_PATHS where ID=%d", + q->value(1).toInt()); + q1=new RDSqlQuery(sql); + delete q1; + } + } + delete q; +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/utils/rdmaint/rdmaint.h b/utils/rdmaint/rdmaint.h new file mode 100644 index 00000000..ac4f418d --- /dev/null +++ b/utils/rdmaint/rdmaint.h @@ -0,0 +1,59 @@ +// rdmaint.h +// +// A Utility for running periodic system maintenance. +// +// (C) Copyright 2008 Fred Gleason +// +// $Id: rdmaint.h,v 1.6 2010/09/08 20:38:01 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDMAINT_H +#define RDMAINT_H + +#include +#include + +#include +#include +#include +#include + +#define RDMAINT_USAGE "[--help] [--verbose] [--system]\n\nRun Rivendell maintenance routines.\n" + + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + void RunSystemMaintenance(); + void RunLocalMaintenance(); + void PurgeCuts(); + void PurgeLogs(); + void PurgeElr(); + void PurgeDropboxes(); + RDConfig *maint_config; + bool maint_verbose; + bool maint_system; + RDCmdSwitch *maint_cmd; + RDStation *maint_station; + RDUser *maint_user; +}; + + +#endif // RDMAINT_H diff --git a/utils/rdmarkerset/Makefile.am b/utils/rdmarkerset/Makefile.am new file mode 100644 index 00000000..c0039f79 --- /dev/null +++ b/utils/rdmarkerset/Makefile.am @@ -0,0 +1,53 @@ +## automake.am +## +## Automake.am for rivendell/utils/rdmarkerset +## +## (C) Copyright 2002-2014 Fred Gleason +## +## $Id: Makefile.am,v 1.1.2.1 2014/01/16 02:45:00 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +sbin_PROGRAMS = rdmarkerset + +dist_rdmarkerset_SOURCES = rdmarkerset.cpp rdmarkerset.h + +nodist_rdmarkerset_SOURCES = moc_rdmarkerset.cpp + +rdmarkerset_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rdmarkerset/rdmarkerset.cpp b/utils/rdmarkerset/rdmarkerset.cpp new file mode 100644 index 00000000..a31a8bcf --- /dev/null +++ b/utils/rdmarkerset/rdmarkerset.cpp @@ -0,0 +1,349 @@ +// rdmarkerset.cpp +// +// Command-line tool for setting Rivendell Cut Markers +// +// (C) Copyright 2014 Fred Gleason +// +// $Id: rdmarkerset.cpp,v 1.1.2.1 2014/01/16 02:45:00 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + bool ok=false; + bool skip_db_check=false; + unsigned schema=0; + set_all_groups=false; + set_auto_trim=1; + set_verbose=false; + + // + // Read Command Options + // + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdmarkerset",RDMARKERSET_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--skip-db-check") { + skip_db_check=true; + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--all-groups") { + set_all_groups=true; + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--group") { + set_group_names.push_back(cmd->value(i)); + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--auto-trim") { + set_auto_trim=cmd->value(i).toInt(&ok); + if((!ok)||(set_auto_trim>0)) { + fprintf(stderr, + "rdmarkerset: invalid level value specified for --auto-trim\n"); + } + cmd->setProcessed(i,true); + } + if(cmd->key(i)=="--verbose") { + set_verbose=true; + cmd->setProcessed(i,true); + } + if(!cmd->processed(i)) { + fprintf(stderr,"rdmarkerset: unrecognized option \"%s\"\n", + (const char *)cmd->key(i)); + } + } + + // + // Sanity Checks + // + if((!set_all_groups)&&(set_group_names.size()==0)) { + fprintf(stderr,"rdmarkerset: either --all-groups or --group= options must be specified\n"); + exit(256); + } + if(set_all_groups&&(set_group_names.size()>0)) { + fprintf(stderr,"rdmarkerset: the --all-groups and --group= options are mutually exclusive\n"); + exit(256); + } + + // + // Check for Root Perms + // + if(geteuid()!=0) { + fprintf(stderr,"rdmarkerset: must be user \"root\"\n"); + exit(256); + } + + // + // Read Configuration + // + set_config=new RDConfig(); + set_config->load(); + + // + // Open Database + // + QString err (tr("rdmarkerset: ")); + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + fprintf(stderr,err.ascii()); + delete cmd; + exit(256); + } + if((schema!=RD_VERSION_DATABASE)&&(!skip_db_check)) { + fprintf(stderr, + "rdmarkerset: database version mismatch, should be %u, is %u\n", + RD_VERSION_DATABASE,schema); + exit(256); + } + + // + // Validate Station + // + set_station=new RDStation(set_config->stationName()); + if(!set_station->exists()) { + fprintf(stderr,"rdmarkerset: no such host [\"%s\"]\n", + (const char *)set_config->stationName()); + exit(256); + } + + // + // Validate Groups + // + if(set_all_groups) { + QString sql="select NAME from GROUPS order by NAME"; + QSqlQuery *q=new QSqlQuery(sql); + while(q->next()) { + set_group_names.push_back(q->value(0).toString()); + } + delete q; + } + else { + for(unsigned i=0;iexists()) { + fprintf(stderr,"rdmarkerset: no such group named \"%s\"\n", + (const char *)set_group_names[i]); + bad=true; + } + delete grp; + if(bad) { + exit(256); + } + } + } + + // + // RIPCD Connection + // + set_user=NULL; + set_ripc=new RDRipc(set_config->stationName(),this); + connect(set_ripc,SIGNAL(userChanged()),this,SLOT(userChangedData())); + set_ripc->connectHost("localhost",RIPCD_TCP_PORT,set_config->password()); +} + + +void MainObject::userChangedData() +{ + if(set_user!=NULL) { + fprintf(stderr,"rdmarkerset: change of user context ignored\n"); + return; + } + set_user=new RDUser(set_ripc->user()); + + for(unsigned i=0;inext()) { + if(set_auto_trim<0) { + SetAutoTrim(RDCut::cartNumber(q->value(0).toString()), + RDCut::cutNumber(q->value(0).toString()), + q->value(1).toString(),q->value(2).toString()); + } + else { + ClearAutoTrim(RDCut::cartNumber(q->value(0).toString()), + RDCut::cutNumber(q->value(0).toString()), + q->value(1).toString(),q->value(2).toString()); + } + } + delete q; +} + + +void MainObject::SetAutoTrim(unsigned cartnum,int cutnum,const QString &title, + const QString &desc) +{ + RDTrimAudio::ErrorCode err; + RDCart *cart=new RDCart(cartnum); + RDCut *cut=new RDCut(cartnum,cutnum); + RDTrimAudio *trimmer=new RDTrimAudio(set_station,set_config,this); + trimmer->setCartNumber(cartnum); + trimmer->setCutNumber(cutnum); + trimmer->setTrimLevel(100*set_auto_trim); + if((err=trimmer->runTrim(set_user->name(),set_user->password()))== + RDTrimAudio::ErrorOk) { + int start=trimmer->startPoint(); + int end=trimmer->endPoint(); + if(cut->talkStartPoint()>=0) { + if(start>cut->talkStartPoint()) { + cut->setTalkStartPoint(start); + } + } + if(cut->talkEndPoint()>=0) { + if(endtalkEndPoint()) { + cut->setTalkEndPoint(end); + } + } + if(cut->segueStartPoint()>=0) { + if(start>cut->segueStartPoint()) { + cut->setSegueStartPoint(start); + } + } + if(cut->segueEndPoint()>=0) { + if(endsegueEndPoint()) { + cut->setSegueEndPoint(end); + } + } + if(cut->hookStartPoint()>=0) { + if(start>cut->hookStartPoint()) { + cut->setHookStartPoint(start); + } + } + if(cut->hookEndPoint()>=0) { + if(endhookEndPoint()) { + cut->setHookEndPoint(end); + } + } + if(cut->fadeupPoint()>=0) { + if(start>cut->fadeupPoint()) { + cut->setFadeupPoint(-1); + } + } + if(cut->fadedownPoint()>=0) { + if(endfadedownPoint()) { + cut->setFadedownPoint(-1); + } + } + cut->setStartPoint(start); + cut->setEndPoint(end); + cut->setLength(end-start); + cart->updateLength(); + Print(QString().sprintf(" auto-trimming %06u / %03d [", + cartnum,cutnum)+title+" / "+desc+ + QString().sprintf("] to %d dBFS",set_auto_trim)); + } + else { + if(err!=RDTrimAudio::ErrorNoAudio) { + fprintf(stderr,"rdmarkerset: cart %06u, cut %d trimmer error [%s]\n", + cartnum,cutnum,(const char *)RDTrimAudio::errorText(err)); + exit(256); + } + } + delete trimmer; + delete cut; + delete cart; +} + + +void MainObject::ClearAutoTrim(unsigned cartnum,int cutnum,const QString &title, + const QString &desc) +{ + RDAudioInfo::ErrorCode err; + RDCart *cart=new RDCart(cartnum); + RDCut *cut=new RDCut(cartnum,cutnum); + RDAudioInfo *info=new RDAudioInfo(set_station,set_config,this); + info->setCartNumber(cartnum); + info->setCutNumber(cutnum); + if((err=info->runInfo(set_user->name(),set_user->password()))== + RDAudioInfo::ErrorOk) { + cut->setStartPoint(0); + cut->setEndPoint(info->length()); + cut->setLength(info->length()); + cart->updateLength(); + Print(QString().sprintf(" clearing auto-trim from %06u / %03d [", + cartnum,cutnum)+title+" / "+desc+"]"); + } + else { + if(err!=RDAudioInfo::ErrorNoAudio) { + fprintf(stderr,"rdmarkerset: cart %06u, cut %d info error [%s]\n", + cartnum,cutnum,(const char *)RDAudioInfo::errorText(err)); + exit(256); + } + } + delete info; + delete cut; + delete cart; +} + + +void MainObject::Print(const QString &msg) +{ + if(set_verbose) { + printf("%s\n",(const char *)msg); + } +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/utils/rdmarkerset/rdmarkerset.h b/utils/rdmarkerset/rdmarkerset.h new file mode 100644 index 00000000..35d826d1 --- /dev/null +++ b/utils/rdmarkerset/rdmarkerset.h @@ -0,0 +1,69 @@ +// rdmarkerset.h +// +// Command-line tool for setting Rivendell Cut Markers +// +// (C) Copyright 2014 Fred Gleason +// +// $Id: rdmarkerset.h,v 1.1.2.1 2014/01/16 02:45:00 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDMARKERSET_H +#define RDMARKERSET_H + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#define RDMARKERSET_USAGE "[options]\nThe following options are recognized:\n\n--group=\n Apply marker changes to the group specified by . This\n option may be given multiple times.\n\n--all-groups\n Apply marker changes to ALL groups.\n\n--auto-trim=\n Auto-trim the specified cuts to the level indicated by dBFS.\n Specifying a '0' for will remove auto-trim --i.e. move the\n Start and End markers to the extreme start and end of the audio data.\n\n--verbose\n Print messages to stdout describing progress.\n\n" + +class MainObject : public QObject +{ + Q_OBJECT; + public: + MainObject(QObject *parent=0,const char *name=0); + + private slots: + void userChangedData(); + + private: + void ProcessGroup(const QString &group_name); + void SetAutoTrim(unsigned cartnum,int cutnum,const QString &title, + const QString &desc); + void ClearAutoTrim(unsigned cartnum,int cutnum,const QString &title, + const QString &desc); + void Print(const QString &msg); + bool set_all_groups; + std::vector set_group_names; + int set_auto_trim; + bool set_verbose; + RDStation *set_station; + RDRipc *set_ripc; + RDUser *set_user; + RDConfig *set_config; +}; + + +#endif // RDMARKERSET_H diff --git a/utils/rdpopup/Makefile.am b/utils/rdpopup/Makefile.am new file mode 100644 index 00000000..e585ec74 --- /dev/null +++ b/utils/rdpopup/Makefile.am @@ -0,0 +1,49 @@ +## automake.am +## +## Automake.am for rivendell/utils/rdpopup +## +## (C) Copyright 2009 Fred Gleason +## +## $Id: Makefile.am,v 1.5.8.1 2012/11/29 01:37:38 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rdpopup + +dist_rdpopup_SOURCES = rdpopup.cpp rdpopup.h + +rdpopup_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rdpopup/rdpopup.cpp b/utils/rdpopup/rdpopup.cpp new file mode 100644 index 00000000..cf25519e --- /dev/null +++ b/utils/rdpopup/rdpopup.cpp @@ -0,0 +1,124 @@ +// rdpopup.cpp +// +// A utility for displaying messages on the desktop +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: rdpopup.cpp,v 1.4.8.2 2014/01/21 21:59:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +QString WordWrap(const QString &str) +{ + QString ret; + QString residue=str; + + while(residue.length()>TEXT_WIDTH) { + int cutpt=TEXT_WIDTH; + for(int i=TEXT_WIDTH;i>=0;i--) { + if(residue.at(i).isSpace()) { + cutpt=i; + break; + } + } + ret+=residue.left(cutpt)+"\n"; + residue=residue.right(residue.length()-cutpt-1); + } + + ret+=residue; + return ret; +} + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdpopup",RDPOPUP_USAGE); + delete cmd; + + if(argc<2) { + fprintf(stderr,"rdpopup: missing argument(s)\n"); + exit(256); + } + + // + // Open the syslog + // + openlog("rdpopup",LOG_ODELAY,LOG_USER); + + // + // Get Severity Value + // + bool ok=false; + int prio=QString(argv[argc-2]).toInt(&ok); + if(!ok) { + fprintf(stderr,"rdpopup: invalid priority value\n"); + exit(256); + } + + QDateTime dt=QDateTime(QDate::currentDate(),QTime::currentTime()); + QString msg=WordWrap(argv[argc-1]); + QMessageBox *mb; + switch(prio) { + case 1: + mb=new QMessageBox(dt.toString("MM/dd @ hh:mm"),msg, + QMessageBox::Information, + QMessageBox::Ok,QMessageBox:: + NoButton,QMessageBox::NoButton); + break; + + case 2: + mb=new QMessageBox(dt.toString("MM/dd @ hh:mm"),msg, + QMessageBox::Warning,QMessageBox::Ok, + QMessageBox::NoButton,QMessageBox::NoButton); + break; + + case 3: + mb=new QMessageBox(dt.toString("MM/dd @ hh:mm"),msg, + QMessageBox::Critical,QMessageBox::Ok, + QMessageBox::NoButton,QMessageBox::NoButton); + break; + + default: + mb=new QMessageBox(dt.toString("MM/dd @ hh:mm"),msg, + QMessageBox::Information, + QMessageBox::Ok,QMessageBox::NoButton, + QMessageBox::NoButton); + break; + } + QFont font("hevetica",16,QFont::Bold); + font.setPixelSize(16); + mb->setFont(font); + mb->exec(); + delete mb; + + syslog(LOG_INFO,"\"%s\" acknowledged",argv[argc-1]); + closelog(); + + return 0; +} diff --git a/utils/rdpopup/rdpopup.h b/utils/rdpopup/rdpopup.h new file mode 100644 index 00000000..b6a88d76 --- /dev/null +++ b/utils/rdpopup/rdpopup.h @@ -0,0 +1,33 @@ +// rdpopup.h +// +// A utility for displaying messages on the desktop +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: rdpopup.h,v 1.4 2010/07/29 19:32:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDPOPUP_H +#define RDPOPUP_H + + +// +// Settings +// +#define RDPOPUP_USAGE " \n\nWhere is the severity level of the message and is the text to display.\n\nValid severity values are:\n\n 1 - Information\n 2 - Warning\n 3 - Critical\n" +#define TEXT_WIDTH 60 + +#endif // RDPOPUP_H diff --git a/utils/rdpurgecasts/Makefile.am b/utils/rdpurgecasts/Makefile.am new file mode 100644 index 00000000..d08db884 --- /dev/null +++ b/utils/rdpurgecasts/Makefile.am @@ -0,0 +1,49 @@ +## automake.am +## +## Automake.am for rivendell/utils/rdpurgecasts +## +## (C) Copyright 2007 Fred Gleason +## +## $Id: Makefile.am,v 1.4.8.1 2012/11/29 01:37:38 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rdpurgecasts + +dist_rdpurgecasts_SOURCES = rdpurgecasts.cpp rdpurgecasts.h + +rdpurgecasts_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rdpurgecasts/rdpurgecasts.cpp b/utils/rdpurgecasts/rdpurgecasts.cpp new file mode 100644 index 00000000..e6fb4f53 --- /dev/null +++ b/utils/rdpurgecasts/rdpurgecasts.cpp @@ -0,0 +1,178 @@ +// rdpurgecasts.cpp +// +// A Utility to Purge Expired Podcasts. +// +// (C) Copyright 2007 Fred Gleason +// +// $Id: rdpurgecasts.cpp,v 1.7 2011/06/21 22:20:44 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + QString sql; + RDSqlQuery *q; + unsigned schema=0; + + // + // Initialize Data Structures + // + purge_verbose=false; + + // + // Read Command Options + // + purge_cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(), + "rdpurgecasts",RDPURGECASTS_USAGE); + if(purge_cmd->keys()>2) { + fprintf(stderr,"\n"); + fprintf(stderr,"%s",RDPURGECASTS_USAGE); + fprintf(stderr,"\n"); + delete purge_cmd; + exit(256); + } + for(unsigned i=0;ikeys();i++) { + if(purge_cmd->key(i)=="--verbose") { + purge_verbose=true; + } + } + + // + // Read Configuration + // + purge_config=new RDConfig(); + purge_config->load(); + + // + // Open Database + // + QString err (tr("rdpurgecasts: ")); + QSqlDatabase *db=RDInitDb(&schema,&err); + if(!db) { + fprintf(stderr,err.ascii()); + delete purge_cmd; + exit(256); + } + delete purge_cmd; + + // + // Scan Podcasts + // + QDateTime current_datetime= + QDateTime(QDate::currentDate(),QTime::currentTime()); + sql=QString().sprintf("select ID,ORIGIN_DATETIME,SHELF_LIFE from PODCASTS \ + where (SHELF_LIFE>0)&&(STATUS=%u)", + RDPodcast::StatusActive); + q=new RDSqlQuery(sql); + while(q->next()) { + if(q->value(1).toDateTime().addDays(q->value(2).toInt())< + current_datetime) { + PurgeCast(q->value(0).toUInt()); + } + } + delete q; + + exit(0); +} + + +void MainObject::PurgeCast(unsigned id) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + QString cmd; + QDateTime current_datetime= + QDateTime(QDate::currentDate(),QTime::currentTime()); + RDFeed *feed=NULL; + RDPodcast *cast=NULL; + QString errs; + + sql=QString().sprintf("select FEEDS.ID,FEEDS.KEEP_METADATA,FEEDS.KEY_NAME \ + from PODCASTS left join FEEDS \ + on(PODCASTS.FEED_ID=FEEDS.ID) \ + where PODCASTS.ID=%u",id); + q=new RDSqlQuery(sql); + while(q->next()) { + feed=new RDFeed(q->value(0).toUInt()); + cast=new RDPodcast(id); + cast->removeAudio(feed,&errs,purge_config->logXloadDebugData()); + if(purge_verbose) { + printf("purging cast: ID=%d,cmd=\"%s\"\n",id,(const char *)cmd); + } + delete cast; + delete feed; + if(RDBool(q->value(1).toString())) { + sql=QString().sprintf("update PODCASTS set STATUS=%u \ + where ID=%u", + RDPodcast::StatusExpired,id); + q1=new RDSqlQuery(sql); + delete q1; + } + else { + QString keyname=q->value(2).toString(); + keyname.replace(" ","_"); + sql=QString().sprintf("delete from %s_FLG where CAST_ID=%d", + (const char *)keyname,id); + q1=new RDSqlQuery(sql); + delete q1; + + sql=QString().sprintf("delete from PODCASTS where ID=%d",id); + q1=new RDSqlQuery(sql); + delete q1; + } + sql=QString().sprintf("update FEEDS set LAST_BUILD_DATETIME=\"%s\" \ + where ID=%u", + (const char *)current_datetime. + toString("yyyy-MM-dd hh:mm:ss"), + q->value(0).toUInt()); + q1=new RDSqlQuery(sql); + delete q1; + + } + delete q; +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/utils/rdpurgecasts/rdpurgecasts.h b/utils/rdpurgecasts/rdpurgecasts.h new file mode 100644 index 00000000..62043382 --- /dev/null +++ b/utils/rdpurgecasts/rdpurgecasts.h @@ -0,0 +1,49 @@ +// rdpurgecasts.h +// +// A Utility to Purge Expired Podcasts. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdpurgecasts.h,v 1.3 2010/07/29 19:32:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDPURGECASTS_H +#define RDPURGECASTS_H + +#include +#include + +#include +#include + +#define RDPURGECASTS_USAGE "[--help] [--verbose]\n\nPurge expired podcasts.\n" + + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + void PurgeCast(unsigned id); + RDConfig *purge_config; + bool purge_verbose; + RDCmdSwitch *purge_cmd; +}; + + +#endif // RDPURGECASTS_H diff --git a/utils/rdsoftkeys/Makefile.am b/utils/rdsoftkeys/Makefile.am new file mode 100644 index 00000000..e5816eec --- /dev/null +++ b/utils/rdsoftkeys/Makefile.am @@ -0,0 +1,54 @@ +## automake.am +## +## Automake.am for rivendell/utils/rdsoftkeys +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.8.8.2 2012/12/03 16:53:46 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +bin_PROGRAMS = rdsoftkeys + +dist_rdsoftkeys_SOURCES = rdsoftkeys.cpp rdsoftkeys.h + +nodist_rdsoftkeys_SOURCES = moc_rdsoftkeys.cpp + +rdsoftkeys_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdsoftkeys.pro + +CLEANFILES = *~\ + *.exe\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rdsoftkeys/rdsoftkeys.cpp b/utils/rdsoftkeys/rdsoftkeys.cpp new file mode 100644 index 00000000..25593ae7 --- /dev/null +++ b/utils/rdsoftkeys/rdsoftkeys.cpp @@ -0,0 +1,326 @@ +// rdsoftkeys.cpp +// +// A utility for sending RML Commands +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: rdsoftkeys.cpp,v 1.7.8.2 2014/01/08 02:08:41 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#ifndef WIN32 +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +// +// Icons +// +#include "../icons/rivendell-22x22.xpm" + + +MainWidget::MainWidget(QWidget *parent,const char *name) + : QMainWindow(parent,name) +{ + key_ysize=70; + + // + // Read Command Options + // + RDConfig *config=new RDConfig(); + QString map_filename=config->filename(); + delete config; + RDCmdSwitch *cmd= + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdsoftkeys",RDSOFTKEYS_USAGE); + for(unsigned i=0;ikeys();i++) { + if(cmd->key(i)=="--map-file") { + map_filename=cmd->value(i); + } + } + delete cmd; + + // + // Generate Font + // + QFont font("Helvetica",12,QFont::Bold); + font.setPixelSize(12); + QFont label_font("Helvetica",18,QFont::Bold); + label_font.setPixelSize(18); + + setCaption(QString("RDSoftKeys")+" v"+VERSION); + + // + // Create And Set Icon + // + key_icon_map=new QPixmap(rivendell_xpm); + setIcon(*key_icon_map); + + // + // RML Send Socket + // + key_socket=new QSocketDevice(QSocketDevice::Datagram); + + // + // Create Buttons + // + QPushButton *button; + QString rmlcmd; + int n=0; + QString color_name; + QColor color; + QString str1; + QString str2; + int h=0; + int s=0; + int v=0; + + QSignalMapper *mapper=new QSignalMapper(this); + connect(mapper,SIGNAL(mapped(int)),this,SLOT(buttonData(int))); + RDProfile *profile=new RDProfile(); + profile->setSource(map_filename); + key_columns= + profile->intValue("SoftKeys","Columns",RDSOFTKEYS_DEFAULT_COLUMNS); + unsigned col=0; + unsigned row=0; + while(!(rmlcmd=profile->stringValue("SoftKeys",QString(). + sprintf("Command%d",n+1),"")).isEmpty()) { + for(unsigned i=0;isetGeometry(10+90*col,10+60*row,80,50); + button-> + setText(WrapText(button,profile-> + stringValue("SoftKeys",QString(). + sprintf("Legend%d",n+1), + QString().sprintf("Button %d",n+1)))); + if(!(color_name=profile->stringValue("SoftKeys", + QString().sprintf("Color%d",n+1),"")). + isEmpty()) { + color=QColor(color_name); + QPalette pal=QPalette(color,backgroundColor()); + color.getHsv(&h,&s,&v); + if((h>180)&&(h<300)) { + v=255; + } + else { + if(v<168) { + v=255; + } + else { + v=0; + } + } + s=0; + color.setHsv(h,s,v); + pal.setColor(QPalette::Active,QColorGroup::ButtonText,color); + pal.setColor(QPalette::Inactive,QColorGroup::ButtonText,color); + button->setPalette(pal); + } + mapper->setMapping(button,n); + connect(button,SIGNAL(clicked()),mapper,SLOT(map())); + if(++col==key_columns) { + col=0; + row++; + key_ysize+=60; + } + } + } + n++; + } + if((key_macros.size()%key_columns)==0) { + key_ysize-=60; + } + + // + // Set Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); +} + + +QSize MainWidget::sizeHint() const +{ + unsigned x=0; + unsigned y=0; + + if(key_macros.size()>=key_columns) { + x=10+90*key_columns; + y=10+60*key_macros.size()/key_columns; + } + else { + x=10+90*key_macros.size(); + y=70; + } + return QSize(x,key_ysize); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::buttonData(int id) +{ + QHostAddress addr; +#ifndef WIN32 + struct hostent *hostent=gethostbyname(key_addrs[id]); + if(hostent==NULL) { + QMessageBox::warning(this,tr("RDSoftKeys"),hstrerror(h_errno)); + return; + } + if(hostent->h_addr_list!=NULL) { + char str[INET_ADDRSTRLEN]; + inet_ntop(hostent->h_addrtype,*hostent->h_addr_list,str,sizeof(str)); + addr.setAddress(str); + } + else { + addr.setAddress(key_addrs[id]); + } +#else + addr.setAddress(key_addrs[id]); +#endif // WIN32 + key_socket->writeBlock(key_macros[id],key_macros[id].length(), + addr,(Q_UINT16)RD_RML_NOECHO_PORT); +} + + +void MainWidget::closeEvent(QCloseEvent *e) +{ + exit(0); +} + + +QString MainWidget::WrapText(QWidget *w,const QString &text) +{ + QFontMetrics fm(w->font()); + QString str; + QString residue = text; + bool space_found=false; + int l; + int lines=0; + + if(!text.isEmpty()) { + while(!residue.isEmpty()) { + space_found=false; + for(int i=(int)residue.length();i>=0;i--) { + if((i==((int)residue.length()))||(residue.at(i).isSpace())) { + if(fm.boundingRect(residue.left(i)).width()<=w->width()-6) { + space_found=true; + if(!str.isEmpty()) { + str+="\n"; + if(++lines==3) { + return str; + } + } + str+=residue.left(i); + if(i==(int)residue.length()) { + return str; + } + residue=residue.right(residue.length()-i-1); + } + } + } + if(!space_found) { + l=residue.length(); + for(int i=l;i>=0;i--) { + if(fm.boundingRect(residue.left(i)).width()<=(w->width()-6)) { + if(!str.isEmpty()) { + str+="\n"; + if(++lines==3) { + return str; + } + } + str+=residue.left(i); + if(i==(int)residue.length()) { + return str; + } + residue=residue.right(residue.length()-i-1); + } + } + } + } + } + return text; +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv); + QApplication::setStyle(new QWindowsStyle); + + // + // Load Translations + // + QString tr_path; + QString qt_path; +#ifdef WIN32 + QSettings settings; + settings.insertSearchPath(QSettings::Windows,"/SalemRadioLabs"); + tr_path=QString().sprintf("%s\\", + (const char *)settings. + readEntry("/Rivendell/InstallDir")); + qt_path=tr_path; +#else + tr_path=QString(PREFIX)+QString("/share/srlabs/"); + qt_path=QString(QTDIR)+QString("/translation/"); +#endif // WIN32 + QTranslator qt(0); + qt.load(qt_path+QString("qt_")+QTextCodec::locale(),"."); + a.installTranslator(&qt); + + QTranslator libradio(0); + libradio.load(tr_path+QString("libradio_")+QTextCodec::locale(),"."); + a.installTranslator(&libradio); + + QTranslator tests(0); + tests.load(tr_path+QString("rdsoftkeys_")+QTextCodec::locale(),"."); + a.installTranslator(&tests); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->setGeometry(w->geometry().x(),w->geometry().y(),w->sizeHint().width(),w->sizeHint().height()); + w->show(); + return a.exec(); +} diff --git a/utils/rdsoftkeys/rdsoftkeys.h b/utils/rdsoftkeys/rdsoftkeys.h new file mode 100644 index 00000000..668058bb --- /dev/null +++ b/utils/rdsoftkeys/rdsoftkeys.h @@ -0,0 +1,65 @@ +// rdsoftkeys.h +// +// A utility for sending RML Commands +// +// (C) Copyright 2002-2006 Fred Gleason +// +// $Id: rdsoftkeys.h,v 1.5 2010/07/29 19:32:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RDSOFTKEYS_H +#define RDSOFTKEYS_H + +#include + +#include +#include +#include +#include +#include + +#include + +// +// Settings +// +#define RDSOFTKEYS_USAGE "[--map-file=]\n\nWhere is the name of the file load soft key definitions from.\nThe default value is master Rivendell configuration file.\n" +#define RDSOFTKEYS_DEFAULT_COLUMNS 1 + +class MainWidget : public QMainWindow +{ + Q_OBJECT + public: + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void buttonData(int id); + void closeEvent(QCloseEvent *e); + + private: + QString WrapText(QWidget *w,const QString &text); + QPixmap *key_icon_map; + QSocketDevice *key_socket; + unsigned key_columns; + unsigned key_ysize; + std::vector key_macros; + std::vector key_addrs; +}; + + +#endif // RDSOFTKEYS_H diff --git a/utils/rdsoftkeys/rdsoftkeys.pro b/utils/rdsoftkeys/rdsoftkeys.pro new file mode 100644 index 00000000..052eea56 --- /dev/null +++ b/utils/rdsoftkeys/rdsoftkeys.pro @@ -0,0 +1,44 @@ +# rdsoftkeys.pro +# +# The utils/rdsoftkeys QMake project file for Rivendell +# +# (C) Copyright 2003-2006 Fred Gleason +# +# $Id: rdsoftkeys.pro,v 1.3.18.1 2013/01/07 15:35:08 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +TARGET = rdsoftkeys + +win32 { + DEFINES += WIN32 + DEFINES += VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE=\"rivendell\" + DEFINES += PACKAGE_VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE_NAME=\"rivendell\" + DEFINES += PACKAGE_BUGREPORT=\"fredg@paravelsystems.com\" +} + +SOURCES += rdsoftkeys.cpp +HEADERS += rdsoftkeys.h + +RES_FILE += ..\..\icons\rivendell.res + +INCLUDEPATH += ..\..\..\libradio\radio ..\..\lib + +LIBS = -lqui -L..\..\..\libradio\radio -lradio -L..\..\lib -llib + +CONFIG += qt diff --git a/utils/rmlsend/Makefile.am b/utils/rmlsend/Makefile.am new file mode 100644 index 00000000..315b9399 --- /dev/null +++ b/utils/rmlsend/Makefile.am @@ -0,0 +1,73 @@ +## automake.am +## +## Automake.am for rivendell/utils/rmlsend +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.12.8.3 2013/01/01 21:36:33 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +# I18N Stuff +install-exec-local: + mkdir -p $(DESTDIR)$(prefix)/share/rivendell + cp rmlsend_*.qm $(DESTDIR)$(prefix)/share/rivendell + +uninstall: + rm -f $(DESTDIR)$(prefix)/share/rivendell/rmlsend_*.qm + +all: + @QT_BIN@/lupdate rmlsend.pro + @QT_BIN@/lrelease rmlsend.pro + +bin_PROGRAMS = rmlsend + +dist_rmlsend_SOURCES = rmlsend.cpp rmlsend.h + +nodist_rmlsend_SOURCES = moc_rmlsend.cpp + +rmlsend_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rmlsend.pro\ + rmlsend_cs.ts\ + rmlsend_de.ts\ + rmlsend_es.ts\ + rmlsend_fr.ts\ + rmlsend_nb.ts\ + rmlsend_nn.ts\ + rmlsend_pt_BR.ts + +CLEANFILES = *~\ + *.exe\ + *.idb\ + *ilk\ + *.qm\ + *.obj\ + *.pdb\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/rmlsend/rmlsend.cpp b/utils/rmlsend/rmlsend.cpp new file mode 100644 index 00000000..d06a0c15 --- /dev/null +++ b/utils/rmlsend/rmlsend.cpp @@ -0,0 +1,562 @@ +// rmlsend.cpp +// +// A utility for sending RML Commands +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: rmlsend.cpp,v 1.7.8.4 2014/01/21 21:59:34 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef WIN32 +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef WIN32 +#include +#include +#include +#endif // WIN32 +#include +#include +#include +#include +#include +#include + +#include + +// +// Icons +// +#include "../icons/rivendell-22x22.xpm" + +// +// Globals +// +RDCmdSwitch *rdcmdswitch=NULL; + + +MainWidget::MainWidget(QWidget *parent,const char *name) + :QMainWindow(parent,name) +{ + // + // Set Window Size + // + setMinimumWidth(sizeHint().width()); + setMaximumWidth(sizeHint().width()); + setMinimumHeight(sizeHint().height()); + setMaximumHeight(sizeHint().height()); + + // + // Create Fonts + // + QFont font("Helvetica",10,QFont::Normal); + font.setPixelSize(10); + setFont(font); + QFont main_font("Helvetica",12,QFont::Bold); + main_font.setPixelSize(12); + QFont label_font("Helvetica",10,QFont::Bold); + label_font.setPixelSize(10); + + // + // Create And Set Icon + // + rivendell_map=new QPixmap(rivendell_xpm); + setIcon(*rivendell_map); + + setCaption(QString("RMLSend")+" v"+VERSION+" - "+tr("Macro Command Utility")); + + host=new QLineEdit(this,"host"); + host->setGeometry(80,10,180,25); + host->setFont(main_font); + QLabel *label=new QLabel(host,"Sent To:",this,"host_label"); + label->setGeometry(10,16,65,14); + label->setFont(label_font); + label->setAlignment(AlignRight); + for(unsigned i=0;ikeys();i++) { + if(rdcmdswitch->key(i)=="--to-host") { + rdcmdswitch->setProcessed(i,true); + host->setText(rdcmdswitch->value(i)); + } + } + + port_box=new QComboBox(this,"port_box"); + port_box->setGeometry(305,10,130,25); + port_box->setEditable(false); + label=new QLabel(port_box,"Dest:",this,"port_label"); + label->setGeometry(270,16,30,14); + label->setFont(label_font); + label->setAlignment(AlignRight); + port_box->insertItem(tr("RML")); + port_box->insertItem(tr("RML (no echo)")); + port_box->insertItem(tr("Set Port")); + port_box->setCurrentItem(1); + connect(port_box,SIGNAL(activated(int)),this,SLOT(destChangedData(int))); + + port_edit=new QLineEdit(this,"port_edit"); + port_edit->setGeometry(sizeHint().width()-60,10,50,25); + port_edit->setFont(main_font); + port_edit->setDisabled(true); + port_edit_label=new QLabel(port_edit,tr("UDP Port:"),this,"port_edit_label"); + port_edit_label->setGeometry(sizeHint().width()-130,16,65,14); + port_edit_label->setFont(label_font); + port_edit_label->setAlignment(AlignRight); + port_edit_label->setDisabled(true); + + command=new QLineEdit(this,"command"); + command->setGeometry(80,40,sizeHint().width()-90,25); + command->setFont(main_font); + label=new QLabel(command,tr("Command:"),this,"host_label"); + label->setGeometry(10,46,65,14); + label->setFont(label_font); + label->setAlignment(AlignRight); + + response=new QLineEdit(this,"response"); + response->setGeometry(80,70,sizeHint().width()-90,25); + response->setFont(main_font); + response_label=new QLabel(response,tr("Response:"),this,"response_label"); + response_label->setGeometry(10,76,65,14); + response_label->setFont(label_font); + response_label->setAlignment(AlignRight); + + send=new QPushButton(tr("&Send Command"),this,"send"); + send->setGeometry(10,sizeHint().height()-50,120,40); + send->setFont(main_font); + connect(send,SIGNAL(clicked()),this,SLOT(sendCommand())); + + quit=new QPushButton("&Quit",this,"quit"); + quit->setGeometry(sizeHint().width()-80,sizeHint().height()-50,70,40); + quit->setFont(main_font); + quit->setDefault(true); + connect(quit,SIGNAL(clicked()),qApp,SLOT(quit())); + + udp_command=new QSocketDevice(QSocketDevice::Datagram); + + udp_response=new QSocketDevice(QSocketDevice::Datagram); + udp_response->bind(QHostAddress(),RD_RML_REPLY_PORT); + udp_response->setBlocking(false); + + timer=new QTimer(this,"timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(readResponse())); + countdown=-1; + timer->start(100); + + // + // Populate Data + // + bool ok; + unsigned port; + for(unsigned i=0;ikeys();i++) { + if(rdcmdswitch->key(i)=="--to-port") { + rdcmdswitch->setProcessed(i,true); + port=rdcmdswitch->value(i).toUInt(&ok); + if(ok&&(port<0xFFFF)) { + switch(rdcmdswitch->value(i).toUInt()) { + case RD_RML_ECHO_PORT: + port_box->setCurrentItem(0); + break; + + case RD_RML_NOECHO_PORT: + port_box->setCurrentItem(1); + break; + + default: + port_box->setCurrentItem(2); + port_edit->setText(rdcmdswitch->value(i)); + break; + } + } + } + } + destChangedData(port_box->currentItem()); +} + + +QSize MainWidget::sizeHint() const +{ + return QSize(570,150); +} + + +QSizePolicy MainWidget::sizePolicy() const +{ + return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed); +} + + +void MainWidget::sendCommand() +{ + QString dcl_command; + unsigned port=0; + bool ok=true; + + switch((MainWidget::DestMode)port_box->currentItem()) { + case MainWidget::Rml: + port=RD_RML_ECHO_PORT; + break; + + case MainWidget::RmlNoEcho: + port=RD_RML_NOECHO_PORT; + break; + + case MainWidget::Manual: + port=port_edit->text().toInt(&ok); + if((!ok)||(port>0xFFFF)) { + QMessageBox::information(this,tr("RMLSend"), + tr("Invalid Port Number!")); + return; + } + break; + } + response->setText(""); +#ifndef WIN32 + struct hostent *hostent=gethostbyname(host->text()); + if(hostent==NULL) { + QMessageBox::warning(this,tr("RMLSend"),hstrerror(h_errno)); + return; + } + if(hostent->h_addr_list!=NULL) { + char str[INET_ADDRSTRLEN]; + inet_ntop(hostent->h_addrtype,*hostent->h_addr_list,str,sizeof(str)); + host_addr.setAddress(str); + } + else { + host_addr.setAddress(host->text()); + } +#else + host_addr.setAddress(host->text()); +#endif // WIN32 + dcl_command=command->text(); + if(!udp_command->writeBlock(dcl_command,dcl_command.length(), + host_addr,(Q_UINT16)port)) { + QMessageBox::warning(this,tr("RMLSend"),tr("Connection Failed!")); + return; + } + else { + countdown=5; + } +} + + +void MainWidget::readResponse() +{ + char buffer[RD_RML_MAX_LENGTH]; + QString output; + int n; + QHostAddress peer_addr; + + n=udp_response->readBlock(buffer,RD_RML_MAX_LENGTH); + if(n<=0) { + if(countdown==0) { + response->setText(tr("no response")); + countdown=-1; + } + if(countdown!=-1) { + countdown--; + } + return; + } + countdown=-1; + buffer[n]=0; + response->setText(buffer); +} + + +void MainWidget::destChangedData(int id) +{ + switch((MainWidget::DestMode)id) { + case MainWidget::Rml: + port_edit->setDisabled(true); + port_edit_label->setDisabled(true); + response->setEnabled(true); + response_label->setEnabled(true); + timer->start(100); + break; + + case MainWidget::RmlNoEcho: + port_edit->setDisabled(true); + port_edit_label->setDisabled(true); + response->setText(""); + response->setDisabled(true); + response_label->setDisabled(true); + timer->stop(); + break; + + case MainWidget::Manual: + port_edit->setEnabled(true); + port_edit_label->setEnabled(true); + response->setText(""); + response->setDisabled(true); + response_label->setDisabled(true); + timer->stop(); + break; + } +} + +#ifndef WIN32 +MainObject::MainObject(QObject *parent,const char *name) +{ + input_fd=-1; + dest_hostname=RMLSEND_DEFAULT_ADDR; + dest_port=RMLSEND_DEFAULT_PORT; + rml_ptr=0; + + ReadSwitches(); + ResolveName(); + InitStream(); + ProcessCommands(); + CloseStream(); + + exit(0); +} + + +MainObject::~MainObject() +{ +} + + +void MainObject::ReadSwitches() +{ + bool ok; + + for(unsigned i=0;ikeys();i++) { + if(rdcmdswitch->key(i)=="--to-host") { + rdcmdswitch->setProcessed(i,true); + dest_hostname=rdcmdswitch->value(i); + } + if(rdcmdswitch->key(i)=="--to-port") { + rdcmdswitch->setProcessed(i,true); + dest_port=rdcmdswitch->value(i).toUInt(&ok); + if((!ok)||(dest_port>0xFFFF)) { + fprintf(stderr,"rmlsend: invalid destination port\n"); + exit(256); + } + } + if(rdcmdswitch->key(i)=="--from-file") { + rdcmdswitch->setProcessed(i,true); + input_file=rdcmdswitch->value(i); + } + } + if(input_file.isNull()) { + if(rdcmdswitch->processed(rdcmdswitch->keys()-1)) { + fprintf(stderr,"rmlsend: missing command argument\n"); + exit(256); + } + rdcmdswitch->setProcessed(rdcmdswitch->keys()-1,true); + rml_cmd=rdcmdswitch->key(rdcmdswitch->keys()-1); + } + + for(unsigned i=0;ikeys();i++) { + if(!rdcmdswitch->processed(i)) { + printf("\nrmlsend %s\n",RMLSEND_USAGE); + exit(256); + } + } +} + + +void MainObject::ResolveName() +{ + struct hostent *hostent=gethostbyname(dest_hostname); + if(hostent==NULL) { + fprintf(stderr,"rmlsend: %s\n",hstrerror(h_errno)); + exit(256); + } + dest_addr=new QHostAddress(); + if(hostent->h_addr_list!=NULL) { + char str[INET_ADDRSTRLEN]; + inet_ntop(hostent->h_addrtype,*hostent->h_addr_list,str,sizeof(str)); + dest_addr->setAddress(str); + } + else { + dest_addr->setAddress(dest_hostname); + } +} + + +void MainObject::InitStream() +{ + if(!rml_cmd.isNull()) { + return; + } + if(input_file=="-") { + input_fd=0; + } + else { + if((input_fd=open(input_file,O_RDONLY))<0) { + perror("rmlsend"); + exit(256); + } + } +} + + +void MainObject::CloseStream() +{ + if(input_fd>0) { + close(input_fd); + } +} + + +bool MainObject::GetNextChar(char *c) +{ + + if(rml_cmd.isNull()) { + if(read(input_fd,c,1)<=0) { + return true; + } + return false; + } + if(rml_ptr>=rml_cmd.length()) { + return true; + } + *c=rml_cmd.at(rml_ptr++).latin1(); + return false; +} + + +void MainObject::ProcessCommands() +{ + char c; + QSocketDevice *udp_command=new QSocketDevice(QSocketDevice::Datagram); + char rml[RD_RML_MAX_LENGTH]; + unsigned ptr=0; + bool active=false; + + while(!GetNextChar(&c)) { + if(active) { + if(c=='!') { + rml[ptr++]=c; + rml[ptr]=0; + udp_command->writeBlock(rml,ptr,*dest_addr,dest_port); + ptr=0; + active=false; + } + else { + rml[ptr++]=c; + } + if(ptr==RD_RML_MAX_LENGTH) { + fprintf(stderr,"rmlsend: rml command too long\n"); + CloseStream(); + exit(256); + } + } + else { + if(isalpha(c)) { + rml[ptr++]=c; + active=true; + } + } + } +} +#endif // WIN32 + +int main(int argc,char *argv[]) +{ + bool cli_mode=false; + + rdcmdswitch=new RDCmdSwitch(argc,argv,"rmlsend",RMLSEND_USAGE); + for(unsigned i=0;ikeys();i++) { + if(rdcmdswitch->key(i)=="--from-file") { + cli_mode=true; + } + } + if(rdcmdswitch->keys()>0) { + if(rdcmdswitch->key(rdcmdswitch->keys()-1).left(2)!=QString("--")) { + cli_mode=true; + } + } +#ifdef WIN32 + cli_mode=false; +#endif // WIN32 + + if(cli_mode) { +#ifndef WIN32 + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +#endif // WIN32 + } + else { + QApplication a(argc,argv,true); + + // + // Load Translations + // + QString tr_path; + QString qt_path; +#ifdef WIN32 + QSettings settings; + settings.insertSearchPath(QSettings::Windows,"/SalemRadioLabs"); + tr_path=QString().sprintf("%s\\", + (const char *)settings. + readEntry("/Rivendell/InstallDir")); + qt_path=tr_path; +#else + tr_path=QString(PREFIX)+QString("/share/rivendell/"); + qt_path=QString(QTDIR)+QString("/translation/"); +#endif // WIN32 + QTranslator qt(0); + qt.load(qt_path+QString("qt_")+QTextCodec::locale(),"."); + a.installTranslator(&qt); + + QTranslator rd(0); + rd.load(tr_path+QString("librd_")+QTextCodec::locale(),"."); + a.installTranslator(&rd); + + QTranslator rdhpi(0); + rdhpi.load(tr_path+QString("librdhpi_")+QTextCodec::locale(),"."); + a.installTranslator(&rdhpi); + + QTranslator tr(0); + tr.load(tr_path+QString("rmlsend_")+QTextCodec::locale(),"."); + a.installTranslator(&tr); + + // + // Start Event Loop + // + MainWidget *w=new MainWidget(NULL,"main"); + a.setMainWidget(w); + w->show(); + return a.exec(); + } +} diff --git a/utils/rmlsend/rmlsend.h b/utils/rmlsend/rmlsend.h new file mode 100644 index 00000000..67d5bf48 --- /dev/null +++ b/utils/rmlsend/rmlsend.h @@ -0,0 +1,98 @@ +// rmlsend.h +// +// A utility for sending RML Commands +// +// (C) Copyright 2002-2005 Fred Gleason +// +// $Id: rmlsend.h,v 1.5 2010/07/29 19:32:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef RMLSEND_H +#define RMLSEND_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// Settings +// +#define RMLSEND_USAGE "[--to-host=] [--to-port=] [|--from-file=]\n\nWhere is the name or IP address of the host to send the command to\n(default = localhost), is the UDP port to to send the message to\n(default = 5859), is any valid RML code and is the name of a file\ncontaining valid RML code. If '-' is specified as , then rmlsend will\nread the list of RML commands to be sent from standard input.\n\nWhen specifying RML code on the command line, it will likely be necessary\nto escape any special characters (such as spaces or bang [!] characters)\nto protect them from the shell.\n\nExamples:\n rmlsend LL\\ TestLog\\!\n Send the RML command 'LL 1 TestLog!' to the local host.\n\n rmlsend --to-host=host.mydomain.com --to-port=5858 --from-file=test.rml\n Send the RML commands in 'test.rml' to the system at 'host.mydomain.com' at\n port 5858.\n" +#define RMLSEND_DEFAULT_ADDR "localhost" +#define RMLSEND_DEFAULT_PORT 5859 + +class MainWidget : public QMainWindow +{ + Q_OBJECT + public: + enum DestMode {Rml=0,RmlNoEcho=1,Manual=2}; + MainWidget(QWidget *parent=0,const char *name=0); + QSize sizeHint() const; + QSizePolicy sizePolicy() const; + + private slots: + void sendCommand(); + void readResponse(); + void destChangedData(int id); + + private: + QPushButton *send,*quit; + QLineEdit *host,*command,*response; + QLabel *response_label; + QLabel *port_edit_label; + QComboBox *port_box; + QLineEdit *port_edit; + QSocketDevice *udp_command,*udp_response; + QHostAddress host_addr; + QTimer *timer; + int countdown; + QFont main_font; + QPixmap *rivendell_map; +}; + + +class MainObject : public QObject +{ + Q_OBJECT + public: + MainObject(QObject *parent=0,const char *name=0); + ~MainObject(); + + private: + void ReadSwitches(); + void ResolveName(); + void InitStream(); + void CloseStream(); + bool GetNextChar(char *c); + void ProcessCommands(); + int input_fd; + QString input_file; + QString dest_hostname; + QHostAddress *dest_addr; + unsigned dest_port; + QString rml_cmd; + unsigned rml_ptr; +}; + +#endif // RMLSEND_H diff --git a/utils/rmlsend/rmlsend.pro b/utils/rmlsend/rmlsend.pro new file mode 100644 index 00000000..48ba9add --- /dev/null +++ b/utils/rmlsend/rmlsend.pro @@ -0,0 +1,52 @@ +# rmlsend.pro +# +# The utils/ QMake project file for Rivendell +# +# (C) Copyright 2003-2007 Fred Gleason +# +# $Id: rmlsend.pro,v 1.7.8.1 2013/01/01 21:36:33 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = app + +TARGET = rmlsend + +win32 { + DEFINES += WIN32 + DEFINES += VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE=\"rivendell\" + DEFINES += PACKAGE_VERSION=\"$$[VERSION]\" + DEFINES += PACKAGE_NAME=\"rivendell\" + DEFINES += PACKAGE_BUGREPORT=\"fredg@paravelsystems.com\" +} + +SOURCES += rmlsend.cpp +HEADERS += rmlsend.h + +RES_FILE += ..\..\icons\rivendell.res + +INCLUDEPATH += ..\..\..\libradio\radio ..\..\lib + +LIBS = -lqui -L..\..\..\libradio\radio -lradio -L..\..\lib -llib + +CONFIG += qt + +TRANSLATIONS += rmlsend_cs.ts +TRANSLATIONS += rmlsend_de.ts +TRANSLATIONS += rmlsend_es.ts +TRANSLATIONS += rmlsend_fr.ts +TRANSLATIONS += rmlsend_nb.ts +TRANSLATIONS += rmlsend_nn.ts +TRANSLATIONS += rmlsend_pt_BR.ts diff --git a/utils/rmlsend/rmlsend_cs.ts b/utils/rmlsend/rmlsend_cs.ts new file mode 100644 index 00000000..e572f35c --- /dev/null +++ b/utils/rmlsend/rmlsend_cs.ts @@ -0,0 +1,53 @@ + + + MainWidget + + RML + + + + RML (no echo) + + + + Set Port + + + + UDP Port: + + + + Command: + + + + Response: + + + + &Send Command + + + + RMLSend + + + + Invalid Port Number! + + + + Connection Failed! + + + + no response + + + + Macro Command Utility + + + + diff --git a/utils/rmlsend/rmlsend_de.ts b/utils/rmlsend/rmlsend_de.ts new file mode 100644 index 00000000..a72bcb97 --- /dev/null +++ b/utils/rmlsend/rmlsend_de.ts @@ -0,0 +1,57 @@ + + + MainWidget + + RMLSend - Macro Command Utility + RMLSend - Macro Command Utility + + + RML + RML + + + RML (no echo) + RML (kein echo) + + + Set Port + Port setzen + + + UDP Port: + UDP Port: + + + Command: + Befehl: + + + Response: + Antwort: + + + &Send Command + Kommando &senden + + + RMLSend + RMLSend + + + Invalid Port Number! + Ungültiger Portnummer! + + + Connection Failed! + Verbindung fehlgeschlagen! + + + no response + keine Antwort + + + Macro Command Utility + + + + diff --git a/utils/rmlsend/rmlsend_es.ts b/utils/rmlsend/rmlsend_es.ts new file mode 100644 index 00000000..cdf006cc --- /dev/null +++ b/utils/rmlsend/rmlsend_es.ts @@ -0,0 +1,57 @@ + + + MainWidget + + RMLSend - Macro Command Utility + RMLSend - Utilidad para comandos macro + + + RML + RML + + + RML (no echo) + RML (sin eco) + + + Set Port + Asig. puerto + + + UDP Port: + Puerto UDP: + + + Command: + Comando: + + + Response: + Respuesta: + + + &Send Command + &Enviar Comando + + + RMLSend + RMLSend + + + Invalid Port Number! + ¡Número de puerto inválido! + + + Connection Failed! + ¡Conexión fallida! + + + no response + sin respuesta + + + Macro Command Utility + + + + diff --git a/utils/rmlsend/rmlsend_fr.ts b/utils/rmlsend/rmlsend_fr.ts new file mode 100644 index 00000000..e572f35c --- /dev/null +++ b/utils/rmlsend/rmlsend_fr.ts @@ -0,0 +1,53 @@ + + + MainWidget + + RML + + + + RML (no echo) + + + + Set Port + + + + UDP Port: + + + + Command: + + + + Response: + + + + &Send Command + + + + RMLSend + + + + Invalid Port Number! + + + + Connection Failed! + + + + no response + + + + Macro Command Utility + + + + diff --git a/utils/rmlsend/rmlsend_nb.ts b/utils/rmlsend/rmlsend_nb.ts new file mode 100644 index 00000000..144b2838 --- /dev/null +++ b/utils/rmlsend/rmlsend_nb.ts @@ -0,0 +1,57 @@ + + + MainWidget + + RMLSend - Macro Command Utility + RMLSend - makrokommandoprogram + + + RML + RML + + + RML (no echo) + RML (ikkje ekko) + + + Set Port + Set port + + + UDP Port: + UDP-port: + + + Command: + Kommando: + + + Response: + Svar: + + + &Send Command + &Send kommando + + + RMLSend + RMLSend + + + Invalid Port Number! + Ugyldig portnummer! + + + Connection Failed! + Tilkoplinga mislukka! + + + no response + ikkje noko svar + + + Macro Command Utility + + + + diff --git a/utils/rmlsend/rmlsend_nn.ts b/utils/rmlsend/rmlsend_nn.ts new file mode 100644 index 00000000..144b2838 --- /dev/null +++ b/utils/rmlsend/rmlsend_nn.ts @@ -0,0 +1,57 @@ + + + MainWidget + + RMLSend - Macro Command Utility + RMLSend - makrokommandoprogram + + + RML + RML + + + RML (no echo) + RML (ikkje ekko) + + + Set Port + Set port + + + UDP Port: + UDP-port: + + + Command: + Kommando: + + + Response: + Svar: + + + &Send Command + &Send kommando + + + RMLSend + RMLSend + + + Invalid Port Number! + Ugyldig portnummer! + + + Connection Failed! + Tilkoplinga mislukka! + + + no response + ikkje noko svar + + + Macro Command Utility + + + + diff --git a/utils/rmlsend/rmlsend_pt_BR.ts b/utils/rmlsend/rmlsend_pt_BR.ts new file mode 100644 index 00000000..28218f69 --- /dev/null +++ b/utils/rmlsend/rmlsend_pt_BR.ts @@ -0,0 +1,57 @@ + + + MainWidget + + RMLSend - Macro Command Utility + RMLEnvio - Utilitároo de Comandos Macro + + + RML + RML + + + RML (no echo) + RML (no echo) + + + Set Port + Escolher Porta + + + UDP Port: + Porta UDP: + + + Command: + Comando: + + + Response: + Resposta: + + + &Send Command + &Enviar Comando + + + RMLSend + RMLEnvio + + + Invalid Port Number! + Número de Porta Inválida! + + + Connection Failed! + Conexão Falhou! + + + no response + Sem Resposta + + + Macro Command Utility + + + + diff --git a/utils/sas_shim/Makefile.am b/utils/sas_shim/Makefile.am new file mode 100644 index 00000000..afc8eab6 --- /dev/null +++ b/utils/sas_shim/Makefile.am @@ -0,0 +1,53 @@ +## automake.am +## +## Automake.am for rivendell/utils/sas_shim +## +## (C) Copyright 2002-2006 Fred Gleason +## +## $Id: Makefile.am,v 1.7.8.1 2012/11/29 01:37:38 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +sbin_PROGRAMS = sas_shim + +dist_sas_shim_SOURCES = sas_shim.cpp sas_shim.h + +nodist_sas_shim_SOURCES = moc_sas_shim.cpp + +sas_shim_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rc.sas_shim + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/utils/sas_shim/rc.sas_shim b/utils/sas_shim/rc.sas_shim new file mode 100755 index 00000000..ea7b65f3 --- /dev/null +++ b/utils/sas_shim/rc.sas_shim @@ -0,0 +1,159 @@ +#! /bin/sh +# +# Startup script for the sas_shim Daemon +# (C) Copyright 2003-2004 Fred Gleason +# +# $Id: rc.sas_shim,v 1.5 2010/07/29 19:32:40 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +### BEGIN INIT INFO +# Provides: sas_shim +# Required-Start: $remote_fs mysql rivendell +# Required-Stop: $remote_fs +# Default-Start: 2 3 5 +# Default-Stop: 0 1 6 +# Description: Start the SAS Shim Daemon +### END INIT INFO + +. /lib/lsb/init-functions + +# +# Package Definitions +# +PACKAGE_BIN=/usr/local/sbin/sas_shim +PACKAGE_CONFIG=/etc/rd.conf +PACKAGE_PID=/var/run/sas_shim.pid +PACKAGE_NAME="SAS Shim Daemon" + +# Check for missing binaries +if [ ! -x $PACKAGE_BIN ] ; then + echo "$PACKAGE_BIN not installed" + exit 5 +fi + +# Check for existence of needed config file and read it +if [ ! -r $PACKAGE_CONFIG ] ; then + echo "Missing $PACKAGE_CONFIG" + exit 6} +fi + +case "$1" in + start) + if test ! -f $PACKAGE_PID ; then + $PACKAGE_BIN + sleep 1 + else + if test ! -d /proc/`cat $PACKAGE_PID` ; then + $PACKAGE_BIN + sleep 1 + fi + fi + if test -f $PACKAGE_PID ; then + if test -d /proc/`cat $PACKAGE_PID` ; then + log_success_msg "Starting $PACKAGE_NAME" + exit 0 + else + log_failure_msg "Starting $PACKAGE_NAME" + exit 1 + fi + else + log_failure_msg "Starting $PACKAGE_NAME" + exit 1 + fi + ;; + stop) + if test -f $PACKAGE_PID ; then + if test -d /proc/`cat $PACKAGE_PID` ; then + kill `cat $PACKAGE_PID` 2> /dev/null + sleep 1 + fi + fi + if test -f $PACKAGE_PID ; then + if test -d /proc/`cat $PACKAGE_PID` ; then + log_failure_msg "Shutting down $PACKAGE_NAME" + exit 1 + else + log_success_msg "Shutting down $PACKAGE_NAME" + exit 0 + fi + else + log_success_msg "Shutting down $PACKAGE_NAME" + exit 0 + fi + ;; + restart) + if test -f $PACKAGE_PID ; then + if test -d /proc/`cat $PACKAGE_PID` ; then + kill `cat $PACKAGE_PID` + sleep 1 + fi + fi + $PACKAGE_BIN + sleep 1 + if test -f $PACKAGE_PID ; then + if test -d /proc/`cat $PACKAGE_PID` ; then + log_success_msg "Restarting $PACKAGE_NAME" + exit 0 + else + log_success_msg "Restarting $PACKAGE_NAME" + exit 1 + fi + else + echo "failed." + exit 1 + fi + ;; + force-reload) + if test -f $PACKAGE_PID ; then + if test -d /proc/`cat $PACKAGE_PID` ; then + kill `cat $PACKAGE_PID` + sleep 1 + fi + fi + $PACKAGE_BIN + sleep 1 + if test -f $PACKAGE_PID ; then + if test -d /proc/`cat $PACKAGE_PID` ; then + log_success_msg "Reloading $PACKAGE_NAME" + exit 0 + else + log_failure_msg "Restarting $PACKAGE_NAME" + exit 1 + fi + else + log_failure_msg "Restarting $PACKAGE_NAME" + exit 1 + fi + ;; + status) + echo -n "Checking for $PACKAGE_NAME..." + if test -f $PACKAGE_PID ; then + if test -d /proc/`cat $PACKAGE_PID` ; then + echo "running." + exit 0 + else + echo "stale PID file." + exit 1 + fi + else + echo "stopped." + exit 3 + fi + ;; +esac + + +# End of rc.sas_shim diff --git a/utils/sas_shim/sas_shim.cpp b/utils/sas_shim/sas_shim.cpp new file mode 100644 index 00000000..d0e05309 --- /dev/null +++ b/utils/sas_shim/sas_shim.cpp @@ -0,0 +1,232 @@ +// sas_shim.cpp +// +// An RDCatch event import shim for the SAS64000 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: sas_shim.cpp,v 1.8 2010/07/29 19:32:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + + +void SigHandler(int signo) +{ + switch(signo) { + case SIGTERM: + unlink("/var/run/sas_shim.pid"); + exit(0); + break; + } +} + + +MainObject::MainObject(QObject *parent,const char *name) + : QObject(parent,name) +{ + // + // Read Command Options + // + RDCmdSwitch *cmd=new RDCmdSwitch(qApp->argc(),qApp->argv(),"sas_shim","\n"); + delete cmd; + + rd_config=new RDConfig(RD_CONF_FILE); + rd_config->load(); + + // + // Open Database + // + shim_db=QSqlDatabase::addDatabase(rd_config->mysqlDriver()); + if(!shim_db) { + fprintf(stderr,"sas_shim: can't open mySQL database\n"); + exit(1); + } + shim_db->setDatabaseName(rd_config->mysqlDbname()); + shim_db->setUserName(rd_config->mysqlUsername()); + shim_db->setPassword(rd_config->mysqlPassword()); + shim_db->setHostName(rd_config->mysqlHostname()); + if(!shim_db->open()) { + fprintf(stderr,"sas_shim: unable to connect to mySQL Server"); + shim_db->removeDatabase(rd_config->mysqlDbname()); + exit(1); + } + new RDDbHeartbeat(rd_config->mysqlHeartbeatInterval(),this); + + // + // RIPCD Connection + // + shim_ripc=new RDRipc(""); + shim_ripc->connectHost("localhost",RIPCD_TCP_PORT,rd_config->password()); + + // + // Station Configuration + // + shim_rdstation=new RDStation(rd_config->stationName()); + shim_address=shim_rdstation->address(); + + // + // TTY Device + // + shim_tty=new RDTTYDevice(); + shim_tty->setName(rd_config->sasTtyDevice()); + if(!shim_tty->open(IO_ReadOnly)) { + fprintf(stderr,"sas_shim: unabled to open tty device\n"); + exit(1); + } + shim_tty->setSpeed(9600); + shim_tty->setWordLength(8); + shim_tty->setParity(RDTTYDevice::None); + + // + // Poll Timer + // + QTimer *timer=new QTimer(this,"poll_timer"); + connect(timer,SIGNAL(timeout()),this,SLOT(readTtyData())); + timer->start(POLL_INTERVAL); + + // + // Detach + // + RDDetach(rd_config->logCoreDumpDirectory()); + FILE *pidfile=fopen("/var/run/sas_shim.pid","w"); + fprintf(pidfile,"%d",getpid()); + fclose(pidfile); + ::signal(SIGTERM,SigHandler); +} + + +void MainObject::readTtyData() +{ + static char cmd[3]; + static int input; + static int output; + static int istate=0; + char buf[256]; + int n; + + while((n=shim_tty->readBlock(buf,255))>0) { + for(int i=0;i='0')&&(buf[i]<='9')) { + cmd[0]=buf[i]; + istate=4; + } + else { + istate=0; + } + break; + + case 4: // Second Input Digit + if((buf[i]>='0')&&(buf[i]<='9')) { + cmd[1]=buf[i]; + cmd[2]=0; + sscanf(cmd,"%d",&input); + istate=5; + } + else { + istate=0; + } + break; + + case 5: // First Output Digit + if((buf[i]>='0')&&(buf[i]<='9')) { + cmd[0]=buf[i]; + istate=6; + } + else { + istate=0; + } + break; + + case 6: // Second Output Digit + if((buf[i]>='0')&&(buf[i]<='9')) { + cmd[1]=buf[i]; + cmd[2]=0; + sscanf(cmd,"%d",&output); + DispatchRml(input,output); + istate=0; + } + else { + istate=0; + } + break; + + } + } + } +} + + +void MainObject::DispatchRml(int input,int output) +{ + RDMacro rml; + + rml.setCommand(RDMacro::ST); + rml.setRole(RDMacro::Cmd); + rml.setAddress(shim_address); + rml.setEchoRequested(false); + rml.setArgQuantity(3); + rml.setArg(0,rd_config->sasMatrix()); + rml.setArg(1,input); + rml.setArg(2,output); + shim_ripc->sendRml(&rml); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/utils/sas_shim/sas_shim.h b/utils/sas_shim/sas_shim.h new file mode 100644 index 00000000..8251480d --- /dev/null +++ b/utils/sas_shim/sas_shim.h @@ -0,0 +1,59 @@ +// sas_shim.h +// +// An RDCatch event import shim for the SAS64000 +// +// (C) Copyright 2002-2004 Fred Gleason +// +// $Id: sas_shim.h,v 1.6 2010/07/29 19:32:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef SAS_SHIM_H +#define SAS_SHIM_H + +#include +#include +#include + +#include + +#include +#include +#include + +#define POLL_INTERVAL 100 + +class MainObject : public QObject +{ + Q_OBJECT + public: + MainObject(QObject *parent=0,const char *name=0); + + private slots: + void readTtyData(); + + private: + void DispatchRml(int input,int output); + QString shim_station; + RDStation *shim_rdstation; + QHostAddress shim_address; + RDRipc *shim_ripc; + QSqlDatabase *shim_db; + RDTTYDevice *shim_tty; + RDConfig *rd_config; +}; + + +#endif diff --git a/utils/utils.pro b/utils/utils.pro new file mode 100644 index 00000000..47387c33 --- /dev/null +++ b/utils/utils.pro @@ -0,0 +1,26 @@ +# utils.pro +# +# The utils/ QMake project file for Rivendell +# +# (C) Copyright 2003-2006 Fred Gleason +# +# $Id: utils.pro,v 1.9.8.1 2012/11/29 01:37:37 cvs Exp $ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +TEMPLATE = subdirs + +SUBDIRS += rdcollect +SUBDIRS += rdsoftkeys +SUBDIRS += rmlsend diff --git a/web/Makefile.am b/web/Makefile.am new file mode 100644 index 00000000..8b78ca37 --- /dev/null +++ b/web/Makefile.am @@ -0,0 +1,51 @@ +## automake.am +## +## Automake.am for rivendell/web +## +## (C) Copyright 2002-2007 Fred Gleason +## +## $Id: Makefile.am,v 1.4.8.1 2012/11/29 01:37:38 cvs Exp $ +## +## 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. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +SUBDIRS = rdcastmanager\ + rdfeed\ + rdxport\ + tests + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +EXTRA_DIST = web.pro + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/web/rdcastmanager/Makefile.am b/web/rdcastmanager/Makefile.am new file mode 100644 index 00000000..7540aad9 --- /dev/null +++ b/web/rdcastmanager/Makefile.am @@ -0,0 +1,53 @@ +## automake.am +## +## Automake.am for rivendell/web/rdcastmanager +## +## (C) Copyright 2002-2007 Fred Gleason +## +## $Id: Makefile.am,v 1.4.8.1 2012/11/29 01:37:38 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +# The dependency for qt's Meta Object Compiler (moc) +moc_%.cpp: %.h + $(MOC) $< -o $@ + +libexec_PROGRAMS = rdcastmanager.cgi +libexec_SCRIPTS = rdcastmanager.js + +dist_rdcastmanager_cgi_SOURCES = rdcastmanager.cpp rdcastmanager.h + +rdcastmanager_cgi_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdcastmanager.js\ + rdcastmanager.pro + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/web/rdcastmanager/rdcastmanager.cpp b/web/rdcastmanager/rdcastmanager.cpp new file mode 100644 index 00000000..b71dd32d --- /dev/null +++ b/web/rdcastmanager/rdcastmanager.cpp @@ -0,0 +1,1928 @@ +// rdcastmanager.cpp +// +// An RSS Feed Generator for Rivendell. +// +// (C) Copyright 2002-2009 Fred Gleason +// +// $Id: rdcastmanager.cpp,v 1.14.4.1 2013/11/13 23:36:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +char server_name[PATH_MAX]; + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + // + // Initialize Variables + // + cast_session_id=-1; + cast_feed_id=-1; + cast_cast_id=-1; + cast_add_priv=false; + cast_edit_priv=false; + cast_delete_priv=false; + cast_post=NULL; + + // + // Read Configuration + // + cast_config=new RDConfig(); + cast_config->load(); + + // + // Open Database + // + QSqlDatabase *db=QSqlDatabase::addDatabase(cast_config->mysqlDriver()); + if(!db) { + printf("Content-type: text/html\n\n"); + printf("rdcastmanager: unable to initialize connection to database\n"); + Exit(0); + } + db->setDatabaseName(cast_config->mysqlDbname()); + db->setUserName(cast_config->mysqlUsername()); + db->setPassword(cast_config->mysqlPassword()); + db->setHostName(cast_config->mysqlHostname()); + if(!db->open()) { + printf("Content-type: text/html\n\n"); + printf("rdcastmanager: unable to connect to database\n"); + db->removeDatabase(cast_config->mysqlDbname()); + Exit(0); + } + RDSqlQuery *q=new RDSqlQuery("select DB from VERSION"); + if(!q->first()) { + printf("Content-type: text/html\n"); + printf("Status: 500\n\n"); + printf("rdcastmanager: missing/invalid database version!\n"); + db->removeDatabase(cast_config->mysqlDbname()); + Exit(0); + } + if(q->value(0).toUInt()!=RD_VERSION_DATABASE) { + printf("Content-type: text/html\n"); + printf("Status: 500\n\n"); + printf("rdcastmanager: skewed database version!\n"); + db->removeDatabase(cast_config->mysqlDbname()); + Exit(0); + } + delete q; + + // + // Determine Connection Type + // + if(getenv("REQUEST_METHOD")==NULL) { + printf("Content-type: text/html\n\n"); + printf("rdcastmanager: missing REQUEST_METHOD\n"); + db->removeDatabase(cast_config->mysqlDbname()); + Exit(0); + } + if(QString(getenv("REQUEST_METHOD")).lower()!="post") { + ServeLogin(); + Exit(0); + } + + // + // Get the Server Name + // + if(getenv("SERVER_NAME")==NULL) { + printf("Content-type: text/html\n\n"); + printf("rdfeed: missing SERVER_NAME\n"); + exit(0); + } + strncpy(server_name,getenv("SERVER_NAME"),PATH_MAX); + + // + // Read Post Variables and Dispatch + // + RDSystem *system=new RDSystem(); + cast_post= + new RDFormPost(RDFormPost::MultipartEncoded,system->maxPostLength()); + delete system; + if(cast_post->error()!=RDFormPost::ErrorOk) { + RDCgiError(cast_post->errorString(cast_post->error())); + Exit(0); + } + switch(AuthenticatePost()) { + case RDCASTMANAGER_COMMAND_LOGIN: + ServeLogin(); + break; + + case RDCASTMANAGER_COMMAND_LOGOUT: + ServeLogout(); + break; + + case RDCASTMANAGER_COMMAND_LIST_FEEDS: + ServeListFeeds(); + break; + + case RDCASTMANAGER_COMMAND_LIST_CASTS: + ServeListCasts(); + break; + + case RDCASTMANAGER_COMMAND_EDIT_CAST: + ServeEditCast(); + break; + + case RDCASTMANAGER_COMMAND_COMMIT_CAST: + CommitCast(); + break; + + case RDCASTMANAGER_COMMAND_CONFIRM_DELETE_CAST: + ConfirmDeleteCast(); + break; + + case RDCASTMANAGER_COMMAND_DELETE_CAST: + DeleteCast(); + break; + + case RDCASTMANAGER_COMMAND_SUBSCRIPTION_PICK_DATES: + ServeDatePicker(RDCASTMANAGER_COMMAND_SUBSCRIPTION_REPORT); + break; + + case RDCASTMANAGER_COMMAND_SUBSCRIPTION_REPORT: + ServeSubscriptionReport(); + break; + + case RDCASTMANAGER_COMMAND_EPISODE_PICK_DATES: + ServeDatePicker(RDCASTMANAGER_COMMAND_EPISODE_REPORT); + break; + + case RDCASTMANAGER_COMMAND_EPISODE_REPORT: + ServeEpisodeReport(); + break; + + case RDCASTMANAGER_COMMAND_PLAY_CAST: + ServePlay(); + break; + + case RDCASTMANAGER_COMMAND_POST_EPISODE: + PostEpisode(); + break; + + default: + RDCgiError("Invalid post data!"); + break; + } + + Exit(0); +} + + +int MainObject::AuthenticatePost() +{ + int cmd=0; + QString password; + + // + // Check for Command Value + // + if(!cast_post->getValue("COMMAND",&cmd)) { + return RDCASTMANAGER_COMMAND_LOGIN; + } + + // + // Validate Remote Address + // + if(getenv("REMOTE_ADDR")==NULL) { + RDCgiError("Invalid CGI request!"); + Exit(0); + } + cast_client_addr.setAddress(getenv("REMOTE_ADDR")); + if(cast_client_addr.isNull()) { + RDCgiError("Invalid client IP address!"); + Exit(0); + } + + // + // Authenticate New Login + // + if(!cast_post->getValue("SESSION_ID",&cast_session_id)) { + if(!cast_post->getValue("LOGIN_NAME",&cast_login_name)) { + return RDCASTMANAGER_COMMAND_LOGIN; + } + if(!cast_post->getValue("PASSWORD",&password)) { + return RDCASTMANAGER_COMMAND_LOGIN; + } + if((cast_session_id= + RDAuthenticateLogin(cast_login_name,password,cast_client_addr))<0) { + return RDCASTMANAGER_COMMAND_LOGIN; + } + GetContext(); + return cmd; + } + + // + // Authenticate Existing Session + // + cast_login_name=RDAuthenticateSession(cast_session_id,cast_client_addr); + if(cast_login_name.isEmpty()) { + return RDCASTMANAGER_COMMAND_LOGIN; + } + GetContext(); + + return cmd; +} + + +void MainObject::ServeLogin() +{ + printf("Content-type: text/html\n\n"); + printf("\n"); + printf("\n"); + printf("Rivendell RDCastManager -- Login\n"); + printf("\n"); + + printf("\n",RD_WEB_BACKGROUND_COLOR); + printf("\n"); + printf("\n"); + printf("", + RDCASTMANAGER_COMMAND_LIST_FEEDS); + + printf("\n"); + printf("\n"); + printf("\n"); + + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + + printf("\n"); + printf("\n"); + printf("\n"); + + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + + printf("\n"); + printf("
RDCastManager Login
Login Name:
Password:
 
 
\n"); + printf("\n"); + printf("\n"); + Exit(0); +} + + +void MainObject::ServeLogout() +{ + RDLogoutSession(cast_session_id,cast_client_addr); + ServeLogin(); +} + + +void MainObject::ServeListFeeds() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + int total=0; + int active=0; + + cast_key_name=""; + cast_feed_id=-1; + cast_cast_id=-1; + + printf("Content-type: text/html\n\n"); + printf("\n"); + printf("\n"); + printf("Rivendell RDCastManager -- Feed List\n"); + printf("\n"); + + printf("\n",RD_WEB_BACKGROUND_COLOR); + printf("\n"); + + // + // Title Section + // + TitleSection("Available Feeds",RDCASTMANAGER_COMMAND_LIST_FEEDS,3); + + // + // Column Headers + // + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + + // + // Data Rows + // + QString line_colors[2]; + line_colors[0]=RD_WEB_LINE_COLOR1; + line_colors[1]=RD_WEB_LINE_COLOR2; + int current_color=0; + + sql=QString().sprintf("select FEED_PERMS.KEY_NAME from \ + FEED_PERMS left join WEB_CONNECTIONS \ + on(FEED_PERMS.USER_NAME=WEB_CONNECTIONS.LOGIN_NAME) \ + where WEB_CONNECTIONS.SESSION_ID=%ld", + cast_session_id); + q=new RDSqlQuery(sql); + sql=QString().sprintf("select ID,KEY_NAME,CHANNEL_TITLE from FEEDS \ + where "); + while(q->next()) { + sql+=QString().sprintf("(KEY_NAME=\"%s\")||", + (const char *)q->value(0).toString()); + } + delete q; + if(sql.right(2)=="||") { + sql=sql.left(sql.length()-2); + sql+=" order by KEY_NAME"; + q=new RDSqlQuery(sql); + while(q->next()) { + total=0; + active=0; + printf("\n"); + sql=QString().sprintf("select STATUS from PODCASTS where FEED_ID=%u", + q->value(0).toUInt()); + q1=new RDSqlQuery(sql); + while(q1->next()) { + total++; + switch((RDPodcast::Status)q1->value(0).toUInt()) { + case RDPodcast::StatusActive: + case RDPodcast::StatusExpired: + active++; + break; + + case RDPodcast::StatusPending: + break; + } + } + delete q1; + if(active==total) { + printf("\n",(const char *)line_colors[current_color]); + } + else { + printf("\n", + (const char *)line_colors[current_color]); + } + printf("\n" + ,(const char *)line_colors[current_color], + (const char *)q->value(1).toString()); + printf("\n", + (const char *)line_colors[current_color], + (const char *)q->value(2).toString()); + printf("\n", + (const char *)line_colors[current_color],active,total); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + if(current_color==0) { + current_color=1; + } + else { + current_color=0; + } + } + delete q; + } + + // + // Logout Button + // + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + + printf("
 KEY NAMEFEED NAMECASTS 
%s%s%d / %d
\n",(const char *)line_colors[current_color]); + SetContext(RDCASTMANAGER_COMMAND_LIST_CASTS); + printf("\n", + q->value(0).toInt()); + printf("\n", + (const char *)q->value(1).toString()); + printf("\n"); + printf("
 
 \n"); + printf("\n", + RDCASTMANAGER_COMMAND_LOGOUT); + printf("\n", + cast_session_id); + printf("\n"); + printf("
\n"); + printf("\n"); + printf("\n"); + Exit(0); +} + + +void MainObject::ServeListCasts() +{ + QString sql; + RDSqlQuery *q; + QString filter; + bool unexp_only; + bool active_only; + + GetContext(); + if(cast_key_name.isEmpty()) { + RDCgiError("Missing KEY_NAME"); + Exit(0); + } + if(cast_feed_id<0) { + RDCgiError("Missing FEED_ID"); + Exit(0); + } + cast_cast_id=-1; + + GetUserPerms(); + + filter[0]=0; + cast_post->getValue("FILTER",&filter); + unexp_only=(cast_post->value("ONLY_NOT_EXPIRED").toString().lower()=="yes"); + active_only=(cast_post->value("ONLY_ACTIVE").toString().lower()=="yes"); + + printf("Content-type: text/html\n\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("Rivendell RDCastManager -- Podcasts\n"); + printf("\n"); + + printf("\n",RD_WEB_BACKGROUND_COLOR); + + // + // Big Frame Start + // + printf("\n"); + printf("\n"); + printf("
\n"); + + printf("\n"); + + // + // Title Section + // + printf("\n"); + printf("\n",(const char *)cast_key_name); + SetContext(RDCASTMANAGER_COMMAND_LIST_CASTS); + + // + // Filter + // + printf("\n"); + printf("\n",RD_WEB_LINE_COLOR2); + printf("\n"); + printf("\n",RD_WEB_LINE_COLOR2); + printf("\n"); + + printf("\n"); + printf("\n",RD_WEB_LINE_COLOR2); + printf("\n"); + + printf("\n"); + printf("\n"); + + printf("\n"); + printf("\n"); + + + // + // Column Headers + // + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + + // + // Data Rows + // + QString line_colors[2]; + line_colors[0]=RD_WEB_LINE_COLOR1; + line_colors[1]=RD_WEB_LINE_COLOR2; + int current_color=0; + sql="select ID,STATUS,ITEM_TITLE,ORIGIN_DATETIME,SHELF_LIFE,ITEM_CATEGORY,\ + AUDIO_TIME from PODCASTS "+ + RDCastSearch(cast_feed_id,filter,unexp_only,active_only)+ + " order by ORIGIN_DATETIME desc"; + + q=new RDSqlQuery(sql); + while(q->next()) { + printf("\n"); + switch((RDPodcast::Status)q->value(1).toUInt()) { + case RDPodcast::StatusActive: + printf("\n",(const char *)line_colors[current_color]); + break; + + case RDPodcast::StatusPending: + printf("\n",(const char *)line_colors[current_color]); + break; + + case RDPodcast::StatusExpired: + printf("\n",(const char *)line_colors[current_color]); + break; + } + printf("\n", + (const char *)line_colors[current_color], + (const char *)q->value(2).toString()); + printf("\n", + (const char *)line_colors[current_color], + (const char *)RDUtcToLocal(q->value(3).toDateTime()). + toString("hh:mm:ss MM/dd/yyyy")); + if(q->value(4).toInt()>0) { + printf("\n", + (const char *)line_colors[current_color], + (const char *)RDUtcToLocal(q->value(3).toDateTime()). + addDays(q->value(4).toInt()).toString("hh:mm:ss MM/dd/yyyy")); + } + else { + printf("\n", + (const char *)line_colors[current_color]); + } + printf("\n", + (const char *)line_colors[current_color], + (const char *)RDGetTimeLength(q->value(6).toInt(),false,false)); + printf("\n", + (const char *)line_colors[current_color], + (const char *)q->value(5).toString()); + + // + // Play Button + // + if(1==1) { + printf("\n"); + printf("\n"); + printf("\n"); + } + else { + printf("\n"); + } + + // + // Edit Button + // + if(cast_edit_priv) { + printf("\n"); + printf("\n"); + printf("\n"); + } + else { + printf("\n"); + } + + // + // Delete Button + // + if(cast_delete_priv) { + printf("\n"); + printf("\n"); + printf("\n"); + } + else { + printf("\n"); + } + printf("\n"); + if(current_color==0) { + current_color=1; + } + else { + current_color=0; + } + } + delete q; + + // + // Spacer + // + printf("\n"); + printf("\n"); + printf("\n"); + + // + // Post Episode Button + // + if(cast_add_priv) { + printf("\n"); + printf("\n"); + printf("\n"); + } + else { + printf("\n"); + } + + // + // Subscription Report Button + // + printf("\n"); + printf("\n"); + printf("\n"); + + // + // Close Button + // + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + + printf("
%s Podcasts
 Filter:\n",RD_WEB_LINE_COLOR2); + printf("\n",(const char *)filter); + printf("
 Show Only Nonexpired Casts:\n",RD_WEB_LINE_COLOR2); + printf("\n"); + printf("Show Only Active Casts:\n",RD_WEB_LINE_COLOR2); + printf("\n"); + printf("
 
 TITLEPOSTEDEXPIRESLENGTHCATEGORY   
%s%s%sNever%s%s
\n", + (const char *)line_colors[current_color]); + SetContext(RDCASTMANAGER_COMMAND_PLAY_CAST); + printf("\n", + q->value(0).toInt()); + printf("\n"); + printf("\n", + (const char *)line_colors[current_color]); + printf(" \n"); + printf("
\n", + (const char *)line_colors[current_color]); + SetContext(RDCASTMANAGER_COMMAND_EDIT_CAST); + printf("\n", + q->value(0).toInt()); + printf("\n"); + printf("\n", + (const char *)line_colors[current_color]); + printf(" \n"); + printf("
\n", + (const char *)line_colors[current_color]); + SetContext(RDCASTMANAGER_COMMAND_CONFIRM_DELETE_CAST); + printf("\n", + q->value(0).toInt()); + printf("\n"); + printf("\n", + (const char *)line_colors[current_color]); + printf(" \n"); + printf("
 
 
\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("
\n", + RD_WEB_LINE_COLOR1); + SetContext(RDCASTMANAGER_COMMAND_POST_EPISODE); + printf("File:"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n",RD_WEB_LINE_COLOR1); + printf("\n"); + printf("
\n"); + printf("
 
\n"); + SetContext(RDCASTMANAGER_COMMAND_SUBSCRIPTION_PICK_DATES); + printf("\n"); + printf("
\n"); + printf("\n", + cast_session_id); + printf("\n", + RDCASTMANAGER_COMMAND_LIST_FEEDS); + printf("\n"); + printf("
\n"); + + // + // Big Frame End + // + printf("
\n"); + + printf("\n"); + printf("\n"); + Exit(0); +} + + +void MainObject::ServeEditCast(int cast_id) +{ + QString sql; + RDSqlQuery *q; + + GetUserPerms(); + if(!cast_edit_priv) { + RDCgiError("Insufficient privileges for this operation!"); + Exit(0); + } + + if(cast_id<0) { + GetContext(); + if(cast_cast_id<0) { + RDCgiError("Missing CAST_ID"); + Exit(0); + } + } + else { + cast_cast_id=cast_id; + } + if(cast_key_name.isEmpty()) { + RDCgiError("Missing KEY_NAME"); + Exit(0); + } + if(cast_feed_id<0) { + RDCgiError("Missing FEED_ID"); + Exit(0); + } + + sql=QString().sprintf("select ITEM_TITLE,ITEM_AUTHOR,\ + ITEM_CATEGORY,ITEM_LINK,ITEM_DESCRIPTION,\ + ITEM_COMMENTS,ITEM_SOURCE_TEXT,ITEM_SOURCE_URL,\ + ITEM_COMMENTS,SHELF_LIFE,ORIGIN_DATETIME,STATUS,\ + EFFECTIVE_DATETIME \ + from PODCASTS where ID=%d",cast_cast_id); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + RDCgiError("Unable to fetch cast record!"); + Exit(0); + } + QDateTime origin_datetime=RDUtcToLocal(q->value(10).toDateTime()); + QDateTime effective_datetime=RDUtcToLocal(q->value(12).toDateTime()); + + RDFeed *feed=new RDFeed(cast_feed_id); + + printf("Content-type: text/html\n\n"); + printf("\n"); + printf("\n"); + printf("Rivendell RDCastManager -- Editing \"%s\"\n", + (const char *)q->value(0).toString()); + printf("\n"); + + printf("\n",RD_WEB_BACKGROUND_COLOR); + printf("\n"); + + // + // Title Section + // + TitleSection("Editing Podcast",RDCASTMANAGER_COMMAND_EDIT_CAST,1); + + // + // Media Link + // + if(feed->mediaLinkMode()!=RDFeed::LinkNone) { + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + + printf("\n"); + printf("\n"); + printf("\n"); + } + + // + // Cast Data + // + printf("\n"); + SetContext(RDCASTMANAGER_COMMAND_COMMIT_CAST); + + // + // Title + // + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + + // + // Author E-Mail + // + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + + // + // Category + // + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + + // + // Link URL + // + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + + // + // Description + // + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + + // + // Source Text + // + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + + // + // Source Link + // + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + + // + // Comments + // + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + + // + // Origin Datetime + // + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + + // + // Effective Date/Time + // + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + + QDateTime exp=origin_datetime.addDays(q->value(9).toInt()); + if(q->value(11).toInt()==RDPodcast::StatusExpired) { + printf("\n", + RDPodcast::StatusExpired); + if(q->value(9).toInt()==0) { + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + } + else { + printf("\n"); + printf("\n",(const char *)exp.toString("MM")); + printf("\n", + (const char *)exp.toString("dd")); + printf("\n", + (const char *)exp.toString("yyyy")); + printf("\n", + (const char *)exp.toString("hh")); + printf("\n",(const char *)exp.toString("mm")); + printf("\n",(const char *)exp.toString("ss")); + } + } + else { + // + // Expiration + // + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + + if(q->value(9).toInt()==0) { + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + } + else { + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n"); + } + + // + // Posting Status + // + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("\n", + RDPodcast::StatusActive); + } + else { + printf("Hold\n", + RDPodcast::StatusPending); + printf("\n"); + printf("\n", + RDPodcast::StatusActive); + + } + printf("\n"); + printf("\n"); + } + + printf("\n"); + + // + // OK Button + // + printf("\n"); + printf("\n"); + + // + // Cancel Button + // + printf("\n"); + printf("\n"); + printf("\n"); + + // + // Episode Report Button + // + printf("\n"); + printf("\n"); + printf("\n"); + + printf("\n"); + + printf("
Media Link:\n", + RD_WEB_LINE_COLOR1); + printf("%s\n",(const char *)feed->audioUrl(feed->mediaLinkMode(), + server_name,cast_cast_id)); + printf("
 
Title:\n", + RD_WEB_LINE_COLOR1); + printf("\n",(const char *)q->value(0).toString()); + printf("
Author E-Mail:\n", + RD_WEB_LINE_COLOR1); + printf("\n",(const char *)q->value(1).toString()); + printf("
Category:\n", + RD_WEB_LINE_COLOR1); + printf("\n",(const char *)q->value(2).toString()); + printf("
Link URL:\n", + RD_WEB_LINE_COLOR1); + printf("\n",(const char *)q->value(3).toString()); + printf("
Description:\n", + RD_WEB_LINE_COLOR1); + printf("\n",(const char *)q->value(4).toString()); + printf("
Source Text:\n", + RD_WEB_LINE_COLOR1); + printf("\n", + (const char *)q->value(6).toString()); + printf("
Source Link:\n", + RD_WEB_LINE_COLOR1); + printf("\n", + (const char *)q->value(7).toString()); + printf("
Comments:\n", + RD_WEB_LINE_COLOR1); + printf("\n",(const char *)q->value(5).toString()); + printf("
Posted At:\n", + RD_WEB_LINE_COLOR1); + printf("\n", + (const char *)origin_datetime.toString("MM/dd/yyyy - hh:mm:ss")); + printf("
Air Date/Time:\n", + RD_WEB_LINE_COLOR1); + printf("/\n",effective_datetime.date().month()); + printf("/\n",effective_datetime.date().day()); + printf(" -- \n",effective_datetime.date().year()); + printf(":\n",effective_datetime.time().hour()); + printf(":\n",effective_datetime.time().minute()); + printf("\n",effective_datetime.time().second()); + printf("
Cast Expires:\n", + RD_WEB_LINE_COLOR1); + printf("\n"); + printf("
Expires At:\n", + RD_WEB_LINE_COLOR1); + printf("/\n"); + printf("/\n"); + printf(" -- \n"); + printf(":\n"); + printf(":\n"); + printf("\n"); + printf("
Expires At:\n", + RD_WEB_LINE_COLOR1); + printf("/\n",(const char *)exp.toString("MM")); + printf("/\n",(const char *)exp.toString("dd")); + printf(" -- \n",(const char *)exp.toString("yyyy")); + printf(":\n",(const char *)exp.toString("hh")); + printf(":\n",(const char *)exp.toString("mm")); + printf("\n",(const char *)exp.toString("ss")); + printf("
Posting Status:\n",RD_WEB_LINE_COLOR1); + if((q->value(11).toInt()==RDPodcast::StatusPending)) { + printf("Hold\n", + RDPodcast::StatusPending); + printf("\n",RD_WEB_LINE_COLOR1); + printf("Active\n",RD_WEB_LINE_COLOR1); + printf("Active
\n"); + printf("\n"); + printf("
\n"); + int id=cast_cast_id; // UGLY, UGLY UGLY!!! + cast_cast_id=-1; + SetContext(RDCASTMANAGER_COMMAND_LIST_CASTS); + cast_cast_id=id; + printf("\n"); + printf("
\n"); + SetContext(RDCASTMANAGER_COMMAND_EPISODE_PICK_DATES); + printf("\n"); + printf("
\n"); + printf("\n"); + printf("\n"); + + delete feed; + + Exit(0); +} + + +void MainObject::ServePlay() +{ + QString sql; + RDSqlQuery *q; + + GetContext(); + if(cast_key_name.isEmpty()) { + RDCgiError("Missing KEY_NAME"); + Exit(0); + } + if(cast_feed_id<0) { + RDCgiError("Missing FEED_ID"); + Exit(0); + } + if(cast_cast_id<0) { + RDCgiError("Missing CAST_ID"); + Exit(0); + } + + sql=QString().sprintf("select FEEDS.BASE_URL,PODCASTS.AUDIO_FILENAME \ + from FEEDS left join PODCASTS \ + on FEEDS.ID=PODCASTS.FEED_ID \ + where PODCASTS.ID=%d",cast_cast_id); + q=new RDSqlQuery(sql); + if(q->first()) { + printf("Content-type: audio/x-mpeg\n"); + printf("Location: %s/%s\n\n",(const char *)q->value(0).toString(), + (const char *)q->value(1).toString()); + } + else { + printf("Status: 500 Internal Server Error\n"); + printf("Content-type: text/html\n"); + printf("\n"); + printf("The cast ID was not found in the database.\n"); + } + delete q; +} + + +void MainObject::CommitCast() +{ + QString sql; + RDSqlQuery *q; + QString item_title; + QString item_author; + QString item_category; + QString item_link; + QString item_description; + QString item_source_text; + QString item_source_url; + QString item_comments; + QString expires; + int expiration_day=0; + int expiration_month=0; + int expiration_year=0; + int expiration_hour=0; + int expiration_minute=0; + int expiration_second=0; + int effective_day=0; + int effective_month=0; + int effective_year=0; + int effective_hour=0; + int effective_minute=0; + int effective_second=0; + unsigned shelf_life=0; + int status; + + GetUserPerms(); + if(!cast_edit_priv) { + RDCgiError("Insufficient privileges for this operation!"); + Exit(0); + } + + GetContext(); + if(cast_key_name.isEmpty()) { + RDCgiError("Missing KEY_NAME"); + Exit(0); + } + if(cast_feed_id<0) { + RDCgiError("Missing FEED_ID"); + Exit(0); + } + if(cast_cast_id<0) { + RDCgiError("Missing CAST_ID"); + Exit(0); + } + if(!cast_post->getValue("ITEM_TITLE",&item_title)) { + RDCgiError("Missing ITEM_TITLE"); + Exit(0); + } + cast_post->getValue("ITEM_AUTHOR",&item_author); + cast_post->getValue("ITEM_CATEGORY",&item_category); + cast_post->getValue("ITEM_LINK",&item_link); + cast_post->getValue("ITEM_DESCRIPTION",&item_description); + cast_post->getValue("ITEM_SOURCE_TEXT",&item_source_text); + cast_post->getValue("ITEM_SOURCE_URL",&item_source_url); + cast_post->getValue("ITEM_COMMENTS",&item_comments); + if(!cast_post->getValue("EFFECTIVE_DAY",&effective_day)) { + RDCgiError("Missing EFFECTIVE_DAY"); + Exit(0); + } + if(!cast_post->getValue("EFFECTIVE_MONTH",&effective_month)) { + RDCgiError("Missing EFFECTIVE_MONTH"); + Exit(0); + } + if(!cast_post->getValue("EFFECTIVE_YEAR",&effective_year)) { + RDCgiError("Missing EFFECTIVE_YEAR"); + Exit(0); + } + if(!cast_post->getValue("EFFECTIVE_HOUR",&effective_hour)) { + RDCgiError("Missing EFFECTIVE_HOUR"); + Exit(0); + } + if(!cast_post->getValue("EFFECTIVE_MINUTE",&effective_minute)) { + RDCgiError("Missing EFFECTIVE_MINUTE"); + Exit(0); + } + if(!cast_post->getValue("EFFECTIVE_SECOND",&effective_second)) { + RDCgiError("Missing EFFECTIVE_SECOND"); + Exit(0); + } + if(!cast_post->getValue("EXPIRES",&expires)) { + RDCgiError("Missing EXPIRES"); + Exit(0); + } + if(expires.lower()=="yes") { + if(!cast_post->getValue("EXPIRATION_DAY",&expiration_day)) { + RDCgiError("Missing EXPIRATION_DAY"); + Exit(0); + } + if(!cast_post->getValue("EXPIRATION_MONTH",&expiration_month)) { + RDCgiError("Missing EXPIRATION_MONTH"); + Exit(0); + } + if(!cast_post->getValue("EXPIRATION_YEAR",&expiration_year)) { + RDCgiError("Missing EXPIRATION_YEAR"); + Exit(0); + } + if(!cast_post->getValue("EXPIRATION_HOUR",&expiration_hour)) { + RDCgiError("Missing EXPIRATION_HOUR"); + Exit(0); + } + if(!cast_post->getValue("EXPIRATION_MINUTE",&expiration_minute)) { + RDCgiError("Missing EXPIRATION_MINUTE"); + Exit(0); + } + if(!cast_post->getValue("EXPIRATION_SECOND",&expiration_second)) { + RDCgiError("Missing EXPIRATION_SECOND"); + Exit(0); + } + sql=QString().sprintf("select ORIGIN_DATETIME from PODCASTS \ + where ID=%d",cast_cast_id); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + RDCgiError("Unable to access cast record!"); + } + QDateTime dt(QDate(expiration_year,expiration_month,expiration_day), + QTime(expiration_hour,expiration_minute,expiration_second)); + if(dt.isNull()) { + RDCgiError("Invalid expiration date!"); + delete q; + Exit(0); + } + shelf_life=q->value(0).toDateTime().daysTo(dt); + delete q; + } + if(!cast_post->getValue("STATUS",&status)) { + RDCgiError("Missing STATUS"); + Exit(0); + } + QDateTime + effective_datetime(QDate(effective_year,effective_month,effective_day), + QTime(effective_hour,effective_minute,effective_second)); + sql=QString().sprintf("update PODCASTS set \ + STATUS=%d,\ + ITEM_TITLE=\"%s\",\ + ITEM_DESCRIPTION=\"%s\",\ + ITEM_CATEGORY=\"%s\",\ + ITEM_LINK=\"%s\",\ + ITEM_COMMENTS=\"%s\",\ + ITEM_AUTHOR=\"%s\",\ + ITEM_SOURCE_TEXT=\"%s\",\ + ITEM_SOURCE_URL=\"%s\",\ + SHELF_LIFE=%d,\ + EFFECTIVE_DATETIME=\"%s\" \ + where ID=%d", + status, + (const char *)RDEscapeString(item_title), + (const char *)RDEscapeString(item_description), + (const char *)RDEscapeString(item_category), + (const char *)RDEscapeString(item_link), + (const char *)RDEscapeString(item_comments), + (const char *)RDEscapeString(item_author), + (const char *)RDEscapeString(item_source_text), + (const char *)RDEscapeString(item_source_url), + shelf_life, + (const char *)RDLocalToUtc(effective_datetime). + toString("yyyy-MM-dd hh:mm:ss"), + cast_cast_id); + q=new RDSqlQuery(sql); + delete q; + + sql=QString().sprintf("update FEEDS set LAST_BUILD_DATETIME=UTC_TIMESTAMP()\ + where ID=%d",cast_feed_id); + q=new RDSqlQuery(sql); + delete q; + + ServeListCasts(); +} + + +void MainObject::ConfirmDeleteCast() +{ + QString sql; + RDSqlQuery *q; + + GetUserPerms(); + if(!cast_delete_priv) { + RDCgiError("Insufficient privileges for this operation!"); + Exit(0); + } + + GetContext(); + if(cast_key_name.isEmpty()) { + RDCgiError("Missing KEY_NAME"); + Exit(0); + } + if(cast_feed_id<0) { + RDCgiError("Missing FEED_ID"); + Exit(0); + } + if(cast_cast_id<0) { + RDCgiError("Missing CAST_ID"); + Exit(0); + } + + sql=QString().sprintf("select ITEM_TITLE,ORIGIN_DATETIME from PODCASTS \ + where ID=%d",cast_cast_id); + q=new RDSqlQuery(sql); + if(!q->first()) { + RDCgiError("unable to access cast record!"); + Exit(0); + } + printf("Content-type: text/html\n\n"); + printf("\n"); + printf("\n"); + printf("Rivendell RDCastManager -- Confirm Delete\n"); + printf("\n"); + + printf("\n",RD_WEB_BACKGROUND_COLOR); + printf("\n"); + printf("\n"); + printf("\n", + RD_WEB_LINE_COLOR2, + (const char *)q->value(0).toString(), + (const char *)q->value(1).toDateTime().toString("MM/dd/yyyy"), + (const char *)q->value(1).toDateTime().toString("hh:mm:ss")); + printf("\n"); + + printf("\n"); + printf("\n"); + + printf("\n"); + printf("\n"); + printf("
Are you sure you want to delete cast \"%s\", posted on %s at %s?
 
\n"); + printf("\n"); + printf("\n"); + + // + // Yes Button + // + printf("\n"); + printf("\n"); + printf("\n"); + + printf("\n"); + + // + // No Button + // + printf("\n"); + printf("\n"); + printf("\n"); + + printf("\n"); + printf("
\n"); + SetContext(RDCASTMANAGER_COMMAND_DELETE_CAST); + printf("\n"); + printf(" 
\n"); + cast_cast_id=-1; + SetContext(RDCASTMANAGER_COMMAND_LIST_CASTS); + printf("\n"); + printf("
\n"); + + printf("
\n"); +} + + +void MainObject::DeleteCast() +{ + QString sql; + RDSqlQuery *q; + QString errs; + + GetUserPerms(); + if(!cast_delete_priv) { + RDCgiError("Insufficient privileges for this operation!"); + Exit(0); + } + + GetContext(); + if(cast_key_name.isEmpty()) { + RDCgiError("Missing KEY_NAME"); + Exit(0); + } + if(cast_feed_id<0) { + RDCgiError("Missing FEED_ID"); + Exit(0); + } + if(cast_cast_id<0) { + RDCgiError("Missing CAST_ID"); + Exit(0); + } + + RDFeed *feed=new RDFeed(cast_feed_id); + RDPodcast *cast=new RDPodcast(cast_cast_id); + cast->removeAudio(feed,&errs,cast_config->logXloadDebugData()); + delete cast; + delete feed; + + sql=QString().sprintf("delete from PODCASTS where ID=%d",cast_cast_id); + q=new RDSqlQuery(sql); + delete q; + + ServeListCasts(); +} + + +void MainObject::ServeSubscriptionReport() +{ + QString sql; + RDSqlQuery *q; + unsigned rss_total=0; + unsigned audio_total=0; + unsigned total=0; + + GetContext(); + if(cast_key_name.isEmpty()) { + RDCgiError("Missing KEY_NAME"); + Exit(0); + } + if(cast_feed_id<0) { + RDCgiError("Missing FEED_ID"); + Exit(0); + } + cast_cast_id=-1; + RDFeed *feed=new RDFeed(cast_key_name,this); + + printf("Content-type: text/html\n\n"); + printf("\n"); + printf("\n"); + printf("Rivendell RDCastManager -- Subscription Report\n"); + printf("\n"); + + printf("\n",RD_WEB_BACKGROUND_COLOR); + printf("\n"); + + // + // Title Section + // + printf("\n"); + printf("\n"); + + // + // Column Headers + // + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + + + // + // Data Rows + // + QString line_colors[2]; + line_colors[0]=RD_WEB_LINE_COLOR1; + line_colors[1]=RD_WEB_LINE_COLOR2; + int current_color=0; + QString keyname_esc=cast_key_name; + keyname_esc.replace(" ","_"); + sql=QString().sprintf("select ACCESS_DATE,ACCESS_COUNT,CAST_ID from %s_FLG \ + where (ACCESS_DATE>=\"%s\")&&\ + (ACCESS_DATE<=\"%s\") \ + order by ACCESS_DATE,CAST_ID desc", + (const char *)keyname_esc, + (const char *)cast_start_date.toString("yyyy-MM-dd"), + (const char *)cast_end_date.toString("yyyy-MM-dd")); + q=new RDSqlQuery(sql); + while(q->next()) { + if(q->value(2).toUInt()==0) { + printf("\n", + (const char *)line_colors[current_color], + (const char *)q->value(0).toDate(). + toString("MM/dd/yyyy")); + printf("\n", + (const char *)line_colors[current_color], + q->value(1).toUInt()); + printf("\n", + (const char *)line_colors[current_color], + total); + total=0; + rss_total+=q->value(1).toUInt(); + if(current_color==0) { + current_color=1; + } + else { + current_color=0; + } + } + else { + total+=q->value(1).toUInt(); + audio_total+=q->value(1).toUInt(); + } + } + printf("\n"); + printf("\n",rss_total); + printf("\n",audio_total); + delete q; + + delete feed; + + // + // Close Button + // + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + + printf("
\n"); + printf("Subscription Report for \"%s\"\n", + (const char *)feed->channelTitle()); + printf("
DATERSSAUDIO
%s%9u%9u
TOTAL%9u%9u
 
  \n"); + SetContext(RDCASTMANAGER_COMMAND_LIST_CASTS); + printf("\n"); + printf("
\n"); + printf("\n"); + printf("\n"); + Exit(0); +} + + +void MainObject::PostEpisode() +{ + QString media_file; + + GetContext(); + GetUserPerms(); + if(!cast_add_priv) { + RDCgiError("Insufficient privileges for this operation!"); + Exit(0); + } + if(cast_key_name.isEmpty()) { + RDCgiError("Missing KEY_NAME"); + Exit(0); + } + if(cast_feed_id<0) { + RDCgiError("Missing FEED_ID"); + Exit(0); + } + if(!cast_post->getValue("MEDIA_FILE",&media_file)) { + RDCgiError("Missing MEDIA_FILE"); + Exit(0); + } + if(!cast_post->isFile("MEDIA_FILE")) { + RDCgiError("No MEDIA_FILE submitted!"); + Exit(0); + } + RDStation *station=new RDStation(cast_config->stationName(),0); + if(!station->exists()) { + RDCgiError("Server station entry not found!"); + Exit(0); + } + RDFeed::Error err; + RDFeed *feed=new RDFeed(cast_feed_id,this); + int cast_id=feed->postFile(station,media_file,&err, + cast_config->logXloadDebugData(),cast_config); + delete feed; + delete station; + if(err!=RDFeed::ErrorOk) { + RDCgiError(RDFeed::errorString(err)); + Exit(0); + } + ServeEditCast(cast_id); + + Exit(0); +} + + +void MainObject::ServeEpisodeReport() +{ + QString sql; + RDSqlQuery *q; + unsigned total=0; + + GetContext(); + if(cast_key_name.isEmpty()) { + RDCgiError("Missing KEY_NAME"); + Exit(0); + } + if(cast_feed_id<0) { + RDCgiError("Missing FEED_ID"); + Exit(0); + } + if(cast_cast_id<0) { + RDCgiError("Missing CAST_ID"); + Exit(0); + } + RDPodcast *cast=new RDPodcast(cast_cast_id); + + printf("Content-type: text/html\n\n"); + printf("\n"); + printf("\n"); + printf("Rivendell RDCastManager -- Episode Report\n"); + printf("\n"); + + printf("\n",RD_WEB_BACKGROUND_COLOR); + printf("\n"); + + // + // Title Section + // + printf("\n"); + printf("\n"); + + // + // Column Headers + // + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + + + // + // Data Rows + // + QString line_colors[2]; + line_colors[0]=RD_WEB_LINE_COLOR1; + line_colors[1]=RD_WEB_LINE_COLOR2; + int current_color=0; + QString keyname_esc=cast_key_name; + keyname_esc.replace(" ","_"); + sql=QString().sprintf("select ACCESS_DATE,ACCESS_COUNT from %s_FLG \ + where (ACCESS_DATE>=\"%s\")&&\ + (ACCESS_DATE<=\"%s\")&& \ + (CAST_ID=%d) order by ACCESS_DATE", + (const char *)keyname_esc, + (const char *)cast_start_date.toString("yyyy-MM-dd"), + (const char *)cast_end_date.toString("yyyy-MM-dd"), + cast_cast_id); + q=new RDSqlQuery(sql); + while(q->next()) { + printf("\n", + (const char *)line_colors[current_color], + (const char *)q->value(0).toDate(). + toString("MM/dd/yyyy")); + printf("\n", + (const char *)line_colors[current_color], + q->value(1).toUInt()); + if(current_color==0) { + current_color=1; + } + else { + current_color=0; + } + total+=q->value(1).toUInt(); + } + printf("\n"); + printf("\n",total); + delete q; + + delete cast; + + // + // Close Button + // + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + + printf("
\n"); + printf("Episode Report for \"%s\"\n", + (const char *)cast->itemTitle()); + printf("
DATEDOWNLOADS
%s%9u
TOTAL%9u
 
 \n"); + SetContext(RDCASTMANAGER_COMMAND_EDIT_CAST); + printf("\n"); + printf("
\n"); + printf("\n"); + printf("\n"); + Exit(0); +} + + +void MainObject::ServeDatePicker(int cmd) +{ + QDate yesterday_date=QDate::currentDate().addDays(-1); + + GetContext(); + if(cast_key_name.isEmpty()) { + RDCgiError("Missing KEY_NAME"); + Exit(0); + } + if(cast_feed_id<0) { + RDCgiError("Missing FEED_ID"); + Exit(0); + } + + printf("Content-type: text/html\n\n"); + printf("\n"); + printf("\n"); + printf("Rivendell RDCastManager -- Choose Dates\n"); + printf("\n"); + + printf("\n",RD_WEB_BACKGROUND_COLOR); + printf("\n"); + + printf("
\n"); + + printf("\n"); + printf("\n"); + printf("\n"); + + // + // Start Date + // + printf("\n"); + printf("\n"); + printf("\n"); + SetContext(cmd); + printf("\n",(const char *)yesterday_date.addMonths(-1).toString("yyyy")); + printf("\n"); + + // + // End Date + // + printf("\n"); + printf("\n"); + printf("\n",(const char *)yesterday_date.toString("yyyy")); + printf("\n"); + + // + // Next Button + // + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + + printf("
SELECT DATES
Start Date:
/\n",(const char *)yesterday_date.addMonths(-1).toString("MM")); + printf("/\n",(const char *)yesterday_date.addMonths(-1).toString("dd")); + printf("
End Date:/\n",(const char *)yesterday_date.toString("MM")); + printf("/\n",(const char *)yesterday_date.toString("dd")); + printf("
\n"); + printf("
\n"); + printf("\n"); + printf("\n"); + Exit(0); +} + + +void MainObject::TitleSection(const QString &title,int cmd,int colspan) const +{ + printf("\n"); + printf(" \n"); + printf("%s\n", + colspan,(const char *)title); + printf("\n"); + // + // Refresh Button + // + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("
\n"); + SetContext(cmd); + printf("\n"); + printf("
\n"); + printf("\n"); +} + + +void MainObject::GetUserPerms() +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select USERS.ADD_PODCAST_PRIV,\ + USERS.EDIT_PODCAST_PRIV,USERS.DELETE_PODCAST_PRIV \ + from USERS left join WEB_CONNECTIONS \ + on USERS.LOGIN_NAME=WEB_CONNECTIONS.LOGIN_NAME \ + where WEB_CONNECTIONS.SESSION_ID=%ld", + cast_session_id); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + RDCgiError("Unable to load user security settings!"); + Exit(0); + } + cast_add_priv=RDBool(q->value(0).toString()); + cast_edit_priv=RDBool(q->value(1).toString()); + cast_delete_priv=RDBool(q->value(2).toString()); + delete q; +} + + +void MainObject::GetContext() +{ + int day=0; + int month=0; + int year=0; + + // + // Basic Context + // + cast_post->getValue("KEY_NAME",&cast_key_name); + cast_post->getValue("FEED_ID",&cast_feed_id); + cast_post->getValue("CAST_ID",&cast_cast_id); + + // + // Start Date + // + cast_post->getValue("START_DAY",&day); + cast_post->getValue("START_MONTH",&month); + cast_post->getValue("START_YEAR",&year); + cast_start_date=QDate(year,month,day); + + // + // End Date + // + day=0; + month=0; + year=0; + cast_post->getValue("END_DAY",&day); + cast_post->getValue("END_MONTH",&month); + cast_post->getValue("END_YEAR",&year); + cast_end_date=QDate(year,month,day); +} + + +void MainObject::SetContext(int cmd) const +{ + printf("\n", + cmd); + printf("\n", + cast_session_id); + if(!cast_key_name.isEmpty()) { + printf("\n", + (const char *)cast_key_name); + } + if(cast_feed_id>=0) { + printf("\n", + cast_feed_id); + } + if(cast_cast_id>=0) { + printf("\n", + cast_cast_id); + } +} + + +void MainObject::Exit(int code) +{ + if(cast_post!=NULL) { + delete cast_post; + } + exit(code); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/web/rdcastmanager/rdcastmanager.h b/web/rdcastmanager/rdcastmanager.h new file mode 100644 index 00000000..5f512480 --- /dev/null +++ b/web/rdcastmanager/rdcastmanager.h @@ -0,0 +1,94 @@ +// rdcastmanager.h +// +// Web-Based RSS Podcast Manager for Rivendell. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdcastmanager.h,v 1.5 2010/07/29 19:32:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDCASTMANAGER_H +#define RDCASTMANAGER_H + +#include +#include +#include + +#include + +// +// CGI Values +// +#define RDCASTMANAGER_POST_SIZE 4096 +#define RDCASTMANAGER_MAX_FILTER_LENGTH 256 +#define RDCASTMANAGER_COMMAND_LOGIN 0 +#define RDCASTMANAGER_COMMAND_LOGOUT 1 +#define RDCASTMANAGER_COMMAND_LIST_FEEDS 2 +#define RDCASTMANAGER_COMMAND_LIST_CASTS 3 +#define RDCASTMANAGER_COMMAND_EDIT_CAST 4 +#define RDCASTMANAGER_COMMAND_COMMIT_CAST 5 +#define RDCASTMANAGER_COMMAND_CONFIRM_DELETE_CAST 6 +#define RDCASTMANAGER_COMMAND_DELETE_CAST 7 +#define RDCASTMANAGER_COMMAND_SUBSCRIPTION_PICK_DATES 8 +#define RDCASTMANAGER_COMMAND_SUBSCRIPTION_REPORT 9 +#define RDCASTMANAGER_COMMAND_EPISODE_PICK_DATES 10 +#define RDCASTMANAGER_COMMAND_EPISODE_REPORT 11 +#define RDCASTMANAGER_COMMAND_PLAY_CAST 12 +#define RDCASTMANAGER_COMMAND_POST_EPISODE 13 + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + int AuthenticatePost(); + void ServeLogin(); + void ServeLogout(); + void ServeListFeeds(); + void ServeListCasts(); + void ServeEditCast(int cast_id=-1); + void ServePlay(); + void CommitCast(); + void ConfirmDeleteCast(); + void DeleteCast(); + void ServeSubscriptionReport(); + void ServeEpisodeReport(); + void PostEpisode(); + void ServeDatePicker(int cmd); + void TitleSection(const QString &title,int cmd,int colspan) const; + void GetUserPerms(); + void GetContext(); + void SetContext(int cmd) const; + void Exit(int code); + RDFormPost *cast_post; + QString cast_login_name; + long int cast_session_id; + QHostAddress cast_client_addr; + QString cast_key_name; + int cast_feed_id; + int cast_cast_id; + bool cast_add_priv; + bool cast_edit_priv; + bool cast_delete_priv; + QDate cast_start_date; + QDate cast_end_date; + RDConfig *cast_config; +}; + + +#endif // RDCASTMANAGER_H diff --git a/web/rdcastmanager/rdcastmanager.js b/web/rdcastmanager/rdcastmanager.js new file mode 100644 index 00000000..fbbf59ae --- /dev/null +++ b/web/rdcastmanager/rdcastmanager.js @@ -0,0 +1,39 @@ +// rdcastmanager.js +// +// Script for displaying an upload progress dialog in a web browser. +// +// (C) Copyright 2009 Fred Gleason +// +// $Id: rdcastmanager.js,v 1.2 2010/07/29 19:32:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +function StartProgressbar() +{ + var html='\n'+ + ''+ + '\n'+ + '\n'+ + '
\n'+ + 'File uploading, please stand by...
\n'+ + '
\n'; + + document.getElementById("bigframe").innerHTML=html; +} + +function PostCast() +{ + window.setTimeout('StartProgressbar()',10); +} diff --git a/web/rdcastmanager/rdcastmanager.pro b/web/rdcastmanager/rdcastmanager.pro new file mode 100644 index 00000000..e69de29b diff --git a/web/rdfeed/Makefile.am b/web/rdfeed/Makefile.am new file mode 100644 index 00000000..2024f38b --- /dev/null +++ b/web/rdfeed/Makefile.am @@ -0,0 +1,53 @@ +## automake.am +## +## Automake.am for rivendell/web/rdfeed +## +## (C) Copyright 2002-2007 Fred Gleason +## +## $Id: Makefile.am,v 1.7.8.1 2012/11/29 01:37:38 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +install-exec-local: + if test ! -f $(DESTDIR)@libexecdir@/rdfeed.mp3 ; then ln -s $(DESTDIR)@libexecdir@/rdfeed.xml $(DESTDIR)@libexecdir@/rdfeed.mp3 ; fi + +uninstall: + rm -f $(DESTDIR)@libexecdir@/rdfeed.mp3 + +libexec_PROGRAMS = rdfeed.xml + +dist_rdfeed_xml_SOURCES = rdfeed_script.cpp rdfeed_script.h + +rdfeed_xml_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ + +EXTRA_DIST = rdfeed.pro + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/web/rdfeed/rdfeed.pro b/web/rdfeed/rdfeed.pro new file mode 100644 index 00000000..e69de29b diff --git a/web/rdfeed/rdfeed_script.cpp b/web/rdfeed/rdfeed_script.cpp new file mode 100644 index 00000000..4c211b25 --- /dev/null +++ b/web/rdfeed/rdfeed_script.cpp @@ -0,0 +1,397 @@ +// rdfeed_script.cpp +// +// An RSS Feed Generator for Rivendell. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdfeed_script.cpp,v 1.5.4.1 2013/10/16 21:14:38 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +char server_name[PATH_MAX]; + +MainObject::MainObject(QObject *parent,const char *name) + :QObject(parent,name) +{ + char keyname[10]; + int cast_id=-1; + bool count; + + // + // Validate Feed Key Name + // + if(getenv("QUERY_STRING")==NULL) { + printf("Content-type: text/html\n\n"); + printf("rdfeed: missing feed key name\n"); + exit(0); + } + int arg=0; + while((getenv("QUERY_STRING")[arg]!=0)&& + (getenv("QUERY_STRING")[arg]!='&')&&(arg<9)) { + keyname[arg]=getenv("QUERY_STRING")[arg]; + arg++; + } + if(arg==9) { + printf("Content-type: text/html\n\n"); + printf("rdfeed: invalid feed key name\n"); + exit(0); + } + keyname[arg]=0; + RDGetPostInt(getenv("QUERY_STRING")+arg+1,"cast_id",&cast_id); + + // + // Get the Server Name + // + if(getenv("SERVER_NAME")==NULL) { + printf("Content-type: text/html\n\n"); + printf("rdfeed: missing SERVER_NAME\n"); + exit(0); + } + strncpy(server_name,getenv("SERVER_NAME"),PATH_MAX); + + // + // Read Configuration + // + RDConfig *config=new RDConfig(); + config->load(); + + // + // Determine Range + // + if(getenv("HTTP_RANGE")!=NULL) { + count=ShouldCount(getenv("HTTP_RANGE")); + } + else { + count=true; + } + + // + // Open Database + // + QSqlDatabase *db=QSqlDatabase::addDatabase(config->mysqlDriver()); + if(!db) { + printf("Content-type: text/html\n\n"); + printf("rdfeed: unable to initialize connection to database\n"); + exit(0); + } + db->setDatabaseName(config->mysqlDbname()); + db->setUserName(config->mysqlUsername()); + db->setPassword(config->mysqlPassword()); + db->setHostName(config->mysqlHostname()); + if(!db->open()) { + printf("Content-type: text/html\n\n"); + printf("rdfeed: unable to connect to database\n"); + db->removeDatabase(config->mysqlDbname()); + exit(0); + } + RDSqlQuery *q=new RDSqlQuery("select DB from VERSION"); + if(!q->first()) { + printf("Content-type: text/html\n"); + printf("Status: 500\n\n"); + printf("rdfeed: missing/invalid database version!\n"); + db->removeDatabase(config->mysqlDbname()); + exit(0); + } + if(q->value(0).toUInt()!=RD_VERSION_DATABASE) { + printf("Content-type: text/html\n"); + printf("Status: 500\n\n"); + printf("rdfeed: skewed database version!\n"); + db->removeDatabase(config->mysqlDbname()); + exit(0); + } + delete q; + + if(cast_id<0) { + ServeRss(keyname,count); + } + ServeLink(keyname,cast_id,count); +} + + +void MainObject::ServeRss(const char *keyname,bool count) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + sql=QString().sprintf("select CHANNEL_TITLE,CHANNEL_DESCRIPTION,\ + CHANNEL_CATEGORY,CHANNEL_LINK,CHANNEL_COPYRIGHT,\ + CHANNEL_WEBMASTER,CHANNEL_LANGUAGE,\ + LAST_BUILD_DATETIME,ORIGIN_DATETIME,\ + HEADER_XML,CHANNEL_XML,ITEM_XML,BASE_URL,ID, \ + UPLOAD_EXTENSION,CAST_ORDER,REDIRECT_PATH,\ + BASE_PREAMBLE from FEEDS \ + where KEY_NAME=\"%s\"",keyname); + q=new RDSqlQuery(sql); + if(!q->first()) { + printf("Content-type: text/html\n\n"); + printf("rdfeed: no feed matches the supplied key name\n"); + exit(0); + } + + // + // Log the Access + // + if(count) { + RDIncrementFeedCount(keyname); + } + + // + // Redirect if necessary + // + if(!q->value(16).toString().isEmpty()) { + Redirect(q->value(16).toString()); + delete q; + exit(0); + } + + // + // Generate CGI Header + // + printf("Content-type: application/rss+xml\n\n"); + + // + // Render Header XML + // + printf("%s\n",(const char *)q->value(9).toString()); + + // + // Render Channel XML + // + printf("\n"); + printf("%s\n",(const char *)ResolveChannelWildcards(q)); + + // + // Render Item XML + // + sql=QString().sprintf("select ITEM_TITLE,ITEM_DESCRIPTION,ITEM_CATEGORY,\ + ITEM_LINK,ITEM_AUTHOR,ITEM_SOURCE_TEXT,\ + ITEM_SOURCE_URL,ITEM_COMMENTS,\ + AUDIO_FILENAME,AUDIO_LENGTH,AUDIO_TIME,\ + EFFECTIVE_DATETIME,ID from PODCASTS \ + where (FEED_ID=%d)&&(STATUS=%d) \ + order by EFFECTIVE_DATETIME", + q->value(13).toUInt(),RDPodcast::StatusActive); + if(q->value(15).toString()=="N") { + sql+=" desc"; + } + q1=new RDSqlQuery(sql); + while(q1->next()) { + printf("\n"); + printf("%s\n",(const char *) + ResolveAuxWildcards(ResolveItemWildcards(keyname,q1,q), + getenv("QUERY_STRING"), + q->value(13).toUInt(), + q1->value(7).toUInt())); +// printf("%s\n",(const char *)ResolveItemWildcards(q1,q)); + printf("\n"); + } + delete q1; + + printf("\n"); + printf("\n"); + delete q; + + exit(0); +} + + +void MainObject::ServeLink(const char *keyname,int cast_id,bool count) +{ + QString sql; + RDSqlQuery *q; + + sql=QString().sprintf("select FEEDS.BASE_URL,PODCASTS.AUDIO_FILENAME from \ + FEEDS left join PODCASTS \ + on FEEDS.ID=PODCASTS.FEED_ID \ + where (FEEDS.KEY_NAME=\"%s\")&&(PODCASTS.ID=%d)", + (const char *)keyname,cast_id); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + RDCgiError("Unable to retrieve cast record!"); + } + if(count) { + RDIncrementCastCount(keyname,cast_id); + } + printf("Content-type: audio/x-mpeg\n"); + printf("Location: %s/%s\n\n",(const char *)q->value(0).toString(), + (const char *)q->value(1).toString()); + delete q; + + exit(0); +} + + +QString MainObject::ResolveChannelWildcards(RDSqlQuery *chan_q) +{ + QString ret=chan_q->value(10).toString(); + ret.replace("%TITLE%",RDXmlEscape(chan_q->value(0).toString())); + ret.replace("%DESCRIPTION%",RDXmlEscape(chan_q->value(1).toString())); + ret.replace("%CATEGORY%",RDXmlEscape(chan_q->value(2).toString())); + ret.replace("%LINK%",RDXmlEscape(chan_q->value(3).toString())); + ret.replace("%COPYRIGHT%",RDXmlEscape(chan_q->value(4).toString())); + ret.replace("%WEBMASTER%",RDXmlEscape(chan_q->value(5).toString())); + ret.replace("%LANGUAGE%",RDXmlEscape(chan_q->value(6).toString())); + ret.replace("%BUILD_DATE%",chan_q->value(7).toDateTime(). + toString("ddd, d MMM yyyy hh:mm:ss ")+"GMT"); + ret.replace("%PUBLISH_DATE%",chan_q->value(8).toDateTime(). + toString("ddd, d MMM yyyy hh:mm:ss ")+"GMT"); + ret.replace("%GENERATOR%",QString().sprintf("Rivendell %s",VERSION)); + + return ret; +} + + +QString MainObject::ResolveItemWildcards(const QString &keyname, + RDSqlQuery *item_q,RDSqlQuery *chan_q) +{ + RDFeed *feed=new RDFeed(keyname); + QString ret=chan_q->value(11).toString(); + ret.replace("%ITEM_TITLE%",RDXmlEscape(item_q->value(0).toString())); + ret.replace("%ITEM_DESCRIPTION%", + RDXmlEscape(item_q->value(1).toString())); + ret.replace("%ITEM_CATEGORY%", + RDXmlEscape(item_q->value(2).toString())); + ret.replace("%ITEM_LINK%",RDXmlEscape(item_q->value(3).toString())); + ret.replace("%ITEM_AUTHOR%",RDXmlEscape(item_q->value(4).toString())); + ret.replace("%ITEM_SOURCE_TEXT%", + RDXmlEscape(item_q->value(5).toString())); + ret.replace("%ITEM_SOURCE_URL%", + RDXmlEscape(item_q->value(6).toString())); + ret.replace("%ITEM_COMMENTS%", + RDXmlEscape(item_q->value(7).toString())); + ret.replace("%ITEM_AUDIO_URL%", + (const char *)RDXmlEscape(feed-> + audioUrl(RDFeed::LinkCounted,server_name, + item_q->value(12).toUInt()))); + ret.replace("%ITEM_AUDIO_LENGTH%",item_q->value(9).toString()); + ret.replace("%ITEM_AUDIO_TIME%", + RDGetTimeLength(item_q->value(10).toInt(),false,false)); + ret.replace("%ITEM_PUBLISH_DATE%",item_q->value(11).toDateTime(). + toString("ddd, d MMM yyyy hh:mm:ss ")+"GMT"); + ret.replace("%ITEM_GUID%",RDPodcast::guid(chan_q->value(12).toString(), + item_q->value(8).toString(), + chan_q->value(11).toUInt(), + item_q->value(12).toUInt())); + delete feed; + return ret; +} + + +QString MainObject::ResolveAuxWildcards(QString xml,QString keyname, + unsigned feed_id,unsigned cast_id) +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + + keyname.replace(" ","_"); + sql=QString().sprintf("select VAR_NAME from AUX_METADATA where FEED_ID=%u", + feed_id); + q=new RDSqlQuery(sql); + if(q->size()==0) { + delete q; + return xml; + } + sql="select "; + while(q->next()) { + sql+=q->value(0).toString().mid(1,q->value(0).toString().length()-2); + sql+=","; + } + sql=sql.left(sql.length()-1); + sql+=QString().sprintf(" from %s_FIELDS where CAST_ID=%u", + (const char *)keyname,cast_id); + q->seek(-1); + q1=new RDSqlQuery(sql); + while(q1->next()) { + q->next(); + xml.replace(q->value(0).toString(), + RDXmlEscape(q1->value(0).toString())); + } + delete q1; + delete q; + + return xml; +} + + +bool MainObject::ShouldCount(const QString &hdr) +{ + bool ret=false; + QStringList lines=QStringList::split("\n",hdr); + int n; + QString str; + + for(unsigned i=0;i0) { + if(lines[i].left(n).lower()=="bytes") { + str=lines[i].right(lines[i].length()-n-1).stripWhiteSpace(); + n=str.find("-"); + if(n==0) { + ret=true; + } + if(n>0) { + if(str.left(n)=="0") { + ret=true; + } + } + } + } + } + + return ret; +} + + +void MainObject::Redirect(const QString &url) +{ + printf("Status: 301 Moved Permanently\n"); + printf("Location: %s\n",(const char *)url); + printf("Content-type: text/html\n"); + printf("\n"); + printf("The feed has been relocated to %s.\n",(const char *)url); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new MainObject(NULL,"main"); + return a.exec(); +} diff --git a/web/rdfeed/rdfeed_script.h b/web/rdfeed/rdfeed_script.h new file mode 100644 index 00000000..6c748827 --- /dev/null +++ b/web/rdfeed/rdfeed_script.h @@ -0,0 +1,51 @@ +// rdfeed_script.h +// +// An RSS Feed Generator for Rivendell. +// +// (C) Copyright 2002-2007 Fred Gleason +// +// $Id: rdfeed_script.h,v 1.2 2010/07/29 19:32:40 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDFEED_SCRIPT_H +#define RDFEED_SCRIPT_H + +#include +#include + +#include + + +class MainObject : public QObject +{ + public: + MainObject(QObject *parent=0,const char *name=0); + + private: + void ServeRss(const char *keyname,bool count); + void ServeLink(const char *keyname,int cast_id,bool count); + QString ResolveChannelWildcards(RDSqlQuery *chan_q); + QString ResolveItemWildcards(const QString &keyname, + RDSqlQuery *item_q,RDSqlQuery *chan_q); + QString ResolveAuxWildcards(QString xml,QString keyname,unsigned feed_id, + unsigned cast_id); + bool ShouldCount(const QString &hdr); + void Redirect(const QString &url); +}; + + +#endif // RDFEED_SCRIPT_H diff --git a/web/rdxport/Makefile.am b/web/rdxport/Makefile.am new file mode 100644 index 00000000..da5f6da2 --- /dev/null +++ b/web/rdxport/Makefile.am @@ -0,0 +1,62 @@ +## automake.am +## +## Automake.am for rivendell/web/rdxport +## +## (C) Copyright 2010 Fred Gleason +## +## $Id: Makefile.am,v 1.6.6.3 2013/10/11 22:00:52 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +AM_CPPFLAGS = -Wall -DPREFIX=\"$(prefix)\" -DQTDIR=\"@QT_DIR@\" @QT_CXXFLAGS@ +INCLUDES = -I$(top_srcdir)/lib +LIBS = @QT_LIBS@ -L$(top_srcdir)/lib +MOC = @QT_MOC@ + +libexec_PROGRAMS = rdxport.cgi + +install-exec-hook: + chown root $(libexecdir)/rdxport.cgi + chmod 4755 $(libexecdir)/rdxport.cgi + +dist_rdxport_cgi_SOURCES = audioinfo.cpp\ + carts.cpp\ + copyaudio.cpp\ + deleteaudio.cpp\ + groups.cpp\ + export.cpp\ + exportpeaks.cpp\ + import.cpp\ + logs.cpp\ + rdxport.cpp rdxport.h\ + services.cpp\ + trimaudio.cpp + +rdxport_cgi_LDADD = @LIB_RDLIBS@ -lsndfile @LIBVORBIS@ + +EXTRA_DIST = rdxport.pro + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + Makefile.in\ + moc_* diff --git a/web/rdxport/audioinfo.cpp b/web/rdxport/audioinfo.cpp new file mode 100644 index 00000000..0749d825 --- /dev/null +++ b/web/rdxport/audioinfo.cpp @@ -0,0 +1,114 @@ +// audioinfo.cpp +// +// Rivendell web service portal -- AudioInfo service +// +// (C) Copyright 2011 Fred Gleason +// +// $Id: audioinfo.cpp,v 1.4 2012/02/13 23:01:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +void Xport::AudioInfo() +{ + RDWaveFile::Format format=RDWaveFile::Pcm16;; + + // + // Verify Post + // + int cartnum=0; + if(!xport_post->getValue("CART_NUMBER",&cartnum)) { + XmlExit("Missing CART_NUMBER",400); + } + int cutnum=0; + if(!xport_post->getValue("CUT_NUMBER",&cutnum)) { + XmlExit("Missing CUT_NUMBER",400); + } + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cartnum)) { + XmlExit("No such cart",404); + } + + // + // Open Audio File + // + RDWaveFile *wave=new RDWaveFile(RDCut::pathName(cartnum,cutnum)); + if(!wave->openWave()) { + XmlExit("No such audio",404); + } + + // + // Send Data + // + printf("Content-type: application/xml\n\n"); + + switch(wave->getFormatTag()) { + case WAVE_FORMAT_PCM: + format=RDWaveFile::Pcm16; + break; + + case WAVE_FORMAT_IEEE_FLOAT: + format=RDWaveFile::Float32; + break; + + case WAVE_FORMAT_MPEG: + switch(wave->getHeadLayer()) { + case 1: + format=RDWaveFile::MpegL1; + break; + + case 2: + format=RDWaveFile::MpegL2; + break; + + case 3: + format=RDWaveFile::MpegL3; + break; + } + break; + + default: + XmlExit("Unknown audio format",400); + break; + } + printf("\n"); + printf("\n"); + printf(" %u\n",cartnum); + printf(" %u\n",cutnum); + printf(" %d\n",format); + printf(" %d\n",wave->getChannels()); + printf(" %d\n",wave->getSamplesPerSec()); + printf(" %u\n",wave->getSampleLength()); + printf(" %u\n",wave->getExtTimeLength()); + printf("\n"); + delete wave; + Exit(0); +} diff --git a/web/rdxport/carts.cpp b/web/rdxport/carts.cpp new file mode 100644 index 00000000..e13760e2 --- /dev/null +++ b/web/rdxport/carts.cpp @@ -0,0 +1,771 @@ +// carts.cpp +// +// Rivendell web service portal -- Cart services +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: carts.cpp,v 1.8.2.2.2.1 2014/03/19 22:13:01 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +void Xport::AddCart() +{ + RDCart *cart; + RDGroup *group; + QString group_name; + QString type; + RDCart::Type cart_type=RDCart::All; + int cart_number=0; + + // + // Verify Post + // + if(!xport_post->getValue("GROUP_NAME",&group_name)) { + XmlExit("Missing GROUP_NAME",400); + } + if(!xport_post->getValue("TYPE",&type)) { + XmlExit("Missing TYPE",400); + } + if(type.lower()=="audio") { + cart_type=RDCart::Audio; + } + else { + if(type.lower()=="macro") { + cart_type=RDCart::Macro; + } + else { + XmlExit("Invalid TYPE",400); + } + } + xport_post->getValue("CART_NUMBER",&cart_number); + + // + // Verify User Perms + // + if(!xport_user->groupAuthorized(group_name)) { + XmlExit("No such group",404); + } + group=new RDGroup(group_name,this); + if(cart_number==0) { + if((cart_number=group->nextFreeCart())==0) { + delete group; + XmlExit("No free carts in group",500); + } + } + if(!group->cartNumberValid(cart_number)) { + delete group; + XmlExit("Cart number out of range for group",401); + } + delete group; + if(!xport_user->createCarts()) { + XmlExit("Unauthorized",401); + } + + // + // Process Request + // + cart=new RDCart(cart_number); + if(cart->exists()) { + delete cart; + XmlExit("Cart already exists",403); + } + if(!cart->create(group_name,cart_type)) { + delete cart; + XmlExit("Unable to create cart",500); + } + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + printf("\n"); + printf("\n"); + if(cart->exists()) { + printf("%s",(const char *)cart->xml(false)); + } + delete cart; + printf("\n"); + + Exit(0); +} + + +void Xport::ListCarts() +{ + QString sql; + RDSqlQuery *q; + QString where=""; + RDCart *cart; + QString group_name; + QString filter; + int include_cuts; + RDCart::Type cart_type=RDCart::All; + QString type; + + // + // Verify Post + // + xport_post->getValue("GROUP_NAME",&group_name); + xport_post->getValue("FILTER",&filter); + xport_post->getValue("INCLUDE_CUTS",&include_cuts); + xport_post->getValue("TYPE",&type); + if(type.lower()=="audio") { + cart_type=RDCart::Audio; + } + if(type.lower()=="macro") { + cart_type=RDCart::Macro; + } + + // + // Generate Cart List + // + if(group_name.isEmpty()||(group_name==tr("ALL"))) { + where=RDAllCartSearchText(filter,"ALL",xport_user->name(),false); + } + else { + sql=QString(). + sprintf("select GROUP_NAME from USER_PERMS \ + where (GROUP_NAME=\"%s\")&&(USER_NAME=\"%s\")", + (const char *)RDEscapeString(group_name), + (const char *)RDEscapeString(xport_user->name())); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + XmlExit("No such group",404); + } + where=RDCartSearchText(filter,group_name,"",false); + } + if(cart_type!=RDCart::All) { + where+=QString().sprintf("&&(TYPE=%u)",cart_type); + } + sql="select NUMBER from CART where "+where+"order by NUMBER"; + q=new RDSqlQuery(sql); + + // + // Process Request + // + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + printf("\n"); + printf("\n"); + while(q->next()) { + cart=new RDCart(q->value(0).toUInt()); + printf("%s",(const char *)cart->xml(include_cuts)); + delete cart; + } + printf("\n"); + + delete q; + Exit(0); +} + + +void Xport::ListCart() + +{ + QString where=""; + RDCart *cart; + int cart_number; + int include_cuts; + QString value; + + // + // Verify Post + // + if(!xport_post->getValue("CART_NUMBER",&cart_number)) { + XmlExit("Missing CART_NUMBER",400); + } + xport_post->getValue("INCLUDE_CUTS",&include_cuts); + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cart_number)) { + XmlExit("No such cart",404); + } + + // + // Process Request + // + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + printf("\n"); + printf("\n"); + cart=new RDCart(cart_number); + printf("%s",(const char *)cart->xml(include_cuts)); + delete cart; + printf("\n"); + + Exit(0); +} + + +void Xport::EditCart() +{ + QString where=""; + RDCart *cart; + int cart_number; + int include_cuts=0; + QString group_name; + QString value; + int number; + bool ok; + int line; + QString macro; + bool length_changed=false; + + // + // Verify Post + // + if(!xport_post->getValue("CART_NUMBER",&cart_number)) { + XmlExit("Missing CART_NUMBER",400); + } + xport_post->getValue("INCLUDE_CUTS",&include_cuts); + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cart_number)) { + XmlExit("No such cart",404); + } + if(!xport_user->modifyCarts()) { + XmlExit("Unauthorized",401); + } + if(xport_post->getValue("GROUP_NAME",&group_name)) { + if(!xport_user->groupAuthorized(group_name)) { + XmlExit("No such group",404); + } + } + + // + // Process Request + // + cart=new RDCart(cart_number); + if(!cart->exists()) { + delete cart; + XmlExit("No such cart",404); + } + if(xport_post->getValue("FORCED_LENGTH",&value)) { + number=RDSetTimeLength(value); + if(cart->type()==RDCart::Macro) { + delete cart; + XmlExit("Unsupported operation for cart type",403); + } + if(!cart->validateLengths(number)) { + delete cart; + XmlExit("Forced length out of range",403); + } + } + switch(cart->type()) { + case RDCart::Audio: + break; + + case RDCart::Macro: + line=0; + while(xport_post->getValue(QString().sprintf("MACRO%d",line++),&value)) { + value.stripWhiteSpace(); + if(value.right(1)!="!") { + delete cart; + XmlExit("Invalid macro data",400); + } + macro+=value; + } + cart->setMacros(macro); + break; + + case RDCart::All: + break; + } + if(!group_name.isEmpty()) { + cart->setGroupName(group_name); + } + if(xport_post->getValue("TITLE",&value)) { + cart->setTitle(value); + } + if(xport_post->getValue("ARTIST",&value)) { + cart->setArtist(value); + } + if(xport_post->getValue("ALBUM",&value)) { + cart->setAlbum(value); + } + if(xport_post->getValue("YEAR",&value)) { + number=value.toInt(&ok); + if((ok)&&(number>0)) { + cart->setYear(number); + } + } + if(xport_post->getValue("LABEL",&value)) { + cart->setLabel(value); + } + if(xport_post->getValue("CLIENT",&value)) { + cart->setClient(value); + } + if(xport_post->getValue("AGENCY",&value)) { + cart->setAgency(value); + } + if(xport_post->getValue("PUBLISHER",&value)) { + cart->setPublisher(value); + } + if(xport_post->getValue("COMPOSER",&value)) { + cart->setComposer(value); + } + if(xport_post->getValue("USER_DEFINED",&value)) { + cart->setUserDefined(value); + } + if(xport_post->getValue("USAGE_CODE",&value)) { + number=value.toInt(&ok); + if((ok)&&(number>0)) { + cart->setUsageCode((RDCart::UsageCode)number); + } + } + if(xport_post->getValue("ENFORCE_LENGTH",&value)) { + number=value.toInt(&ok); + if((ok)&&(number>=0)&&(number<2)) { + cart->setEnforceLength(number); + length_changed=true; + } + } + if(xport_post->getValue("FORCED_LENGTH",&value)) { + cart->setForcedLength(RDSetTimeLength(value)); + length_changed=true; + } + if(xport_post->getValue("ASYNCRONOUS",&value)) { + number=value.toInt(&ok); + if((ok)&&(number>=0)&&(number<2)) { + cart->setAsyncronous(number); + length_changed=true; + } + } + if(xport_post->getValue("OWNER",&value)) { + cart->setOwner(value); + } + if(xport_post->getValue("NOTES",&value)) { + cart->setNotes(value); + } + if(xport_post->getValue("SCHED_CODES",&value)) { + cart->setSchedCodes(value); + } + if(length_changed) { + cart->updateLength(); + } + + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + printf("\n"); + printf("\n"); + printf("%s",(const char *)cart->xml(include_cuts)); + delete cart; + printf("\n"); + + Exit(0); +} + + +void Xport::RemoveCart() +{ + RDCart *cart; + int cart_number; + + // + // Verify Post + // + if(!xport_post->getValue("CART_NUMBER",&cart_number)) { + XmlExit("Missing CART_NUMBER",400); + } + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cart_number)) { + XmlExit("No such cart",404); + } + if(!xport_user->deleteCarts()) { + XmlExit("Unauthorized",401); + } + + // + // Process Request + // + cart=new RDCart(cart_number); + if(!cart->exists()) { + delete cart; + XmlExit("No such cart",404); + } + if(!cart->remove(NULL,NULL,xport_config)) { + delete cart; + XmlExit("Unable to delete cart",500); + } + delete cart; + XmlExit("OK",200); +} + + +void Xport::AddCut() +{ + RDCart *cart; + RDCut *cut; + int cart_number; + int cut_number; + + // + // Verify Post + // + if(!xport_post->getValue("CART_NUMBER",&cart_number)) { + XmlExit("Missing CART_NUMBER",400); + } + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cart_number)) { + XmlExit("No such cart",404); + } + if(!xport_user->editAudio()) { + XmlExit("Unauthorized",401); + } + + // + // Process Request + // + cart=new RDCart(cart_number); + if(!cart->exists()) { + delete cart; + XmlExit("No such cart",404); + } + if((cut_number=cart->addCut(0,0,2))<0) { + delete cart; + XmlExit("No new cuts available",500); + } + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + printf("\n"); + printf("\n"); + cut=new RDCut(cart_number,cut_number); + if(cut->exists()) { + printf("%s",(const char *)cut->xml()); + } + delete cut; + delete cart; + printf("\n"); + + Exit(0); +} + + +void Xport::ListCuts() +{ + RDCut *cut; + int cart_number; + QString sql; + RDSqlQuery *q; + + // + // Verify Post + // + if(!xport_post->getValue("CART_NUMBER",&cart_number)) { + XmlExit("Missing CART_NUMBER",400); + } + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cart_number)) { + XmlExit("No such cart",404); + } + + // + // Process Request + // + sql=QString().sprintf("select CUT_NAME from CUTS where CART_NUMBER=%u \ + order by CUT_NAME", + cart_number); + q=new RDSqlQuery(sql); + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + printf("\n"); + printf("\n"); + while(q->next()) { + cut=new RDCut(q->value(0).toString()); + if(cut->exists()) { + printf("%s",(const char *)cut->xml()); + } + delete cut; + } + delete q; + printf("\n"); + + Exit(0); +} + + +void Xport::ListCut() +{ + RDCut *cut; + int cart_number; + int cut_number; + + // + // Verify Post + // + if(!xport_post->getValue("CART_NUMBER",&cart_number)) { + XmlExit("Missing CART_NUMBER",400); + } + if(!xport_post->getValue("CUT_NUMBER",&cut_number)) { + XmlExit("Missing CUT_NUMBER",400); + } + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cart_number)) { + XmlExit("No such cart",404); + } + + // + // Process Request + // + cut=new RDCut(cart_number,cut_number); + if(!cut->exists()) { + delete cut; + XmlExit("No such cut",404); + } + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + printf("\n"); + printf("\n"); + printf("%s",(const char *)cut->xml()); + printf("\n"); + delete cut; + + Exit(0); +} + + +void Xport::EditCut() +{ + RDCut *cut; + int cart_number; + int cut_number; + QString str; + int num; + QDateTime datetime; + QTime time; + bool rotation_changed=false; + bool length_changed=false; + + // + // Verify Post + // + if(!xport_post->getValue("CART_NUMBER",&cart_number)) { + XmlExit("Missing CART_NUMBER",400); + } + if(!xport_post->getValue("CUT_NUMBER",&cut_number)) { + XmlExit("Missing CUT_NUMBER",400); + } + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cart_number)) { + XmlExit("No such cart",404); + } + if(!xport_user->editAudio()) { + XmlExit("Unauthorized",401); + } + + // + // Process Request + // + cut=new RDCut(cart_number,cut_number); + if(!cut->exists()) { + delete cut; + XmlExit("No such cut",404); + } + if(xport_post->getValue("EVERGREEN",&num)) { + cut->setEvergreen(num); + rotation_changed=true; + } + if(xport_post->getValue("DESCRIPTION",&str)) { + cut->setDescription(str); + } + if(xport_post->getValue("OUTCUE",&str)) { + cut->setOutcue(str); + } + if(xport_post->getValue("ISRC",&str)) { + cut->setIsrc(str); + } + if(xport_post->getValue("ISCI",&str)) { + cut->setIsci(str); + } + if(xport_post->getValue("START_DATETIME",&datetime)) { + cut->setStartDatetime(datetime,!datetime.isNull()); + length_changed=true; + rotation_changed=true; + } + if(xport_post->getValue("END_DATETIME",&datetime)) { + cut->setEndDatetime(datetime,!datetime.isNull()); + length_changed=true; + rotation_changed=true; + } + if(xport_post->getValue("MON",&num)) { + cut->setWeekPart(1,num); + rotation_changed=true; + } + if(xport_post->getValue("TUE",&num)) { + cut->setWeekPart(2,num); + rotation_changed=true; + } + if(xport_post->getValue("WED",&num)) { + cut->setWeekPart(3,num); + rotation_changed=true; + } + if(xport_post->getValue("THU",&num)) { + cut->setWeekPart(4,num); + rotation_changed=true; + } + if(xport_post->getValue("FRI",&num)) { + cut->setWeekPart(5,num); + rotation_changed=true; + } + if(xport_post->getValue("SAT",&num)) { + cut->setWeekPart(6,num); + rotation_changed=true; + } + if(xport_post->getValue("SUN",&num)) { + cut->setWeekPart(7,num); + rotation_changed=true; + } + if(xport_post->getValue("START_DAYPART",&time)) { + cut->setStartDaypart(time,!time.isNull()); + rotation_changed=true; + } + if(xport_post->getValue("END_DAYPART",&time)) { + cut->setEndDaypart(time,!time.isNull()); + rotation_changed=true; + } + if(xport_post->getValue("WEIGHT",&num)) { + cut->setWeight(num); + rotation_changed=true; + } + if(xport_post->getValue("START_POINT",&num)) { + cut->setStartPoint(num); + length_changed=true; + } + if(xport_post->getValue("END_POINT",&num)) { + cut->setEndPoint(num); + length_changed=true; + } + if(xport_post->getValue("FADEUP_POINT",&num)) { + cut->setFadeupPoint(num); + length_changed=true; + } + if(xport_post->getValue("FADEDOWN_POINT",&num)) { + cut->setFadedownPoint(num); + length_changed=true; + } + if(xport_post->getValue("SEGUE_START_POINT",&num)) { + cut->setSegueStartPoint(num); + length_changed=true; + } + if(xport_post->getValue("SEGUE_END_POINT",&num)) { + cut->setSegueEndPoint(num); + length_changed=true; + } + if(xport_post->getValue("HOOK_START_POINT",&num)) { + cut->setHookStartPoint(num); + length_changed=true; + } + if(xport_post->getValue("HOOK_END_POINT",&num)) { + cut->setHookEndPoint(num); + length_changed=true; + } + if(xport_post->getValue("TALK_START_POINT",&num)) { + cut->setTalkStartPoint(num); + length_changed=true; + } + if(xport_post->getValue("TALK_END_POINT",&num)) { + cut->setTalkEndPoint(num); + length_changed=true; + } + if(length_changed||rotation_changed) { + RDCart *cart=new RDCart(cut->cartNumber()); + if(length_changed) { + cart->updateLength(); + } + if(rotation_changed) { + cart->resetRotation(); + } + delete cart; + } + delete cut; + XmlExit("OK",200); +} + + +void Xport::RemoveCut() +{ + RDCart *cart; + int cart_number; + int cut_number; + + // + // Verify Post + // + if(!xport_post->getValue("CART_NUMBER",&cart_number)) { + XmlExit("Missing CART_NUMBER",400); + } + if(!xport_post->getValue("CUT_NUMBER",&cut_number)) { + XmlExit("Missing CUT_NUMBER",400); + } + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cart_number)) { + XmlExit("No such cart",404); + } + if(!xport_user->editAudio()) { + XmlExit("Unauthorized",401); + } + + // + // Process Request + // + cart=new RDCart(cart_number); + if(!cart->exists()) { + delete cart; + XmlExit("No such cart",404); + } + if(!cart->removeCut(NULL,NULL,RDCut::cutName(cart_number,cut_number), + xport_config)) { + delete cart; + XmlExit("No such cut",404); + } + delete cart; + XmlExit("OK",200); +} diff --git a/web/rdxport/copyaudio.cpp b/web/rdxport/copyaudio.cpp new file mode 100644 index 00000000..3319e258 --- /dev/null +++ b/web/rdxport/copyaudio.cpp @@ -0,0 +1,82 @@ +// copyaudio.cpp +// +// Rivendell web service portal -- CopyAudio service +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: copyaudio.cpp,v 1.4 2012/02/13 23:01:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +void Xport::CopyAudio() +{ + // + // Verify Post + // + int source_cartnum=0; + if(!xport_post->getValue("SOURCE_CART_NUMBER",&source_cartnum)) { + XmlExit("Missing SOURCE_CART_NUMBER",400); + } + int source_cutnum=0; + if(!xport_post->getValue("SOURCE_CUT_NUMBER",&source_cutnum)) { + XmlExit("Missing SOURCE_CUT_NUMBER",400); + } + + int destination_cartnum=0; + if(!xport_post->getValue("DESTINATION_CART_NUMBER",&destination_cartnum)) { + XmlExit("Missing DESTINATION_CART_NUMBER",400); + } + int destination_cutnum=0; + if(!xport_post->getValue("DESTINATION_CUT_NUMBER",&destination_cutnum)) { + XmlExit("Missing DESTINATION_CUT_NUMBER",400); + } + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(source_cartnum)) { + XmlExit("No such cart",404); + } + if(!xport_user->cartAuthorized(destination_cartnum)) { + XmlExit("No such cart",404); + } + + // + // Make the copy + // + unlink(RDCut::pathName(destination_cartnum,destination_cutnum)); + if(link(RDCut::pathName(source_cartnum,source_cutnum), + RDCut::pathName(destination_cartnum,destination_cutnum))!=0) { + XmlExit(strerror(errno),400); + } + XmlExit("OK",200); +} diff --git a/web/rdxport/deleteaudio.cpp b/web/rdxport/deleteaudio.cpp new file mode 100644 index 00000000..09589987 --- /dev/null +++ b/web/rdxport/deleteaudio.cpp @@ -0,0 +1,66 @@ +// deleteaudio.cpp +// +// Rivendell web service portal -- DeleteAudio service +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: deleteaudio.cpp,v 1.6.2.1 2012/07/17 19:29:43 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +void Xport::DeleteAudio() +{ + // + // Verify Post + // + int cartnum=0; + if(!xport_post->getValue("CART_NUMBER",&cartnum)) { + XmlExit("Missing CART_NUMBER",400); + } + int cutnum=0; + if(!xport_post->getValue("CUT_NUMBER",&cutnum)) { + XmlExit("Missing CUT_NUMBER",400); + } + + // + // Process Request + // + if((!xport_user->deleteCarts())&&(!xport_user->adminConfig())) { + XmlExit("User not authorized",401); + } + RDCut *cut=new RDCut(cartnum,cutnum); + if(!cut->exists()) { + delete cut; + XmlExit("No such cut",404); + } + unlink(RDCut::pathName(cartnum,cutnum)); + unlink(RDCut::pathName(cartnum,cutnum)+".energy"); + syslog(LOG_NOTICE,"unlink(%s): %s",(const char *)RDCut::pathName(cartnum,cutnum),strerror(errno)); + delete cut; + XmlExit("OK",200); +} diff --git a/web/rdxport/export.cpp b/web/rdxport/export.cpp new file mode 100644 index 00000000..271f9fab --- /dev/null +++ b/web/rdxport/export.cpp @@ -0,0 +1,202 @@ +// export.cpp +// +// Rivendell web service portal -- Export service +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: export.cpp,v 1.6.2.2 2013/10/02 18:25:12 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +void Xport::Export() +{ + RDAudioConvert::ErrorCode conv_err=RDAudioConvert::ErrorOk; + int resp_code=0; + + // + // Verify Post + // + int cartnum=0; + if(!xport_post->getValue("CART_NUMBER",&cartnum)) { + XmlExit("Missing CART_NUMBER",400); + } + int cutnum=0; + if(!xport_post->getValue("CUT_NUMBER",&cutnum)) { + XmlExit("Missing CUT_NUMBER",400); + } + int format=0; + if(!xport_post->getValue("FORMAT",&format)) { + XmlExit("Missing FORMAT",400); + } + int channels=0; + if(!xport_post->getValue("CHANNELS",&channels)) { + XmlExit("Missing CHANNELS",400); + } + int sample_rate=0; + if(!xport_post->getValue("SAMPLE_RATE",&sample_rate)) { + XmlExit("Missing SAMPLE_RATE",400); + } + int bit_rate=0; + if(!xport_post->getValue("BIT_RATE",&bit_rate)) { + XmlExit("Missing BIT_RATE",400); + } + int quality=0; + if(!xport_post->getValue("QUALITY",&quality)) { + XmlExit("Missing QUALITY",400); + } + int start_point=-1; + if(!xport_post->getValue("START_POINT",&start_point)) { + XmlExit("Missing START_POINT",400); + } + int end_point=-1; + if(!xport_post->getValue("END_POINT",&end_point)) { + XmlExit("Missing END_POINT",400); + } + int normalization_level=0; + if(!xport_post->getValue("NORMALIZATION_LEVEL",&normalization_level)) { + XmlExit("Missing NORMALIZATION_LEVEL",400); + } + int enable_metadata=false; + if(!xport_post->getValue("ENABLE_METADATA",&enable_metadata)) { + XmlExit("Missing ENABLE_METADATA",400); + } + if(!RDCart::exists(cartnum)) { + XmlExit("No such cart",404); + } + if(!RDCut::exists(cartnum,cutnum)) { + XmlExit("No such cut",404); + } + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cartnum)) { + XmlExit("No such cart",404); + } + + // + // Generate Metadata + // + RDWaveData *wavedata=NULL; + float speed_ratio=1.0; + if(enable_metadata!=0) { + wavedata=new RDWaveData(); + } + if(wavedata!=NULL) { + RDCart *cart=new RDCart(cartnum); + RDCut *cut=new RDCut(cartnum,cutnum); + cart->getMetadata(wavedata); + cut->getMetadata(wavedata); + if(cart->enforceLength()) { + speed_ratio=(float)cut->length()/(float)cart->forcedLength(); + } + delete cut; + delete cart; + } + + // + // Export Cut + // + int fd; + ssize_t n; + uint8_t data[2048]; + QString tmpdir=RDTempDir(); + QString tmpfile=tmpdir+"/exported_audio"; + RDSettings *settings=new RDSettings(); + settings->setFormat((RDSettings::Format)format); + settings->setChannels(channels); + settings->setSampleRate(sample_rate); + settings->setBitRate(bit_rate); + settings->setQuality(quality); + settings->setNormalizationLevel(normalization_level); + RDAudioConvert *conv=new RDAudioConvert(xport_config->stationName()); + conv->setSourceFile(RDCut::pathName(cartnum,cutnum)); + conv->setDestinationFile(tmpfile); + conv->setDestinationSettings(settings); + conv->setDestinationWaveData(wavedata); + conv->setRange(start_point,end_point); + conv->setSpeedRatio(speed_ratio); + switch(conv_err=conv->convert()) { + case RDAudioConvert::ErrorOk: + switch(settings->format()) { + case RDSettings::Pcm16: + printf("Content-type: audio/x-wav\n\n"); + break; + + case RDSettings::MpegL1: + case RDSettings::MpegL2: + case RDSettings::MpegL2Wav: + case RDSettings::MpegL3: + printf("Content-type: audio/x-mpeg\n\n"); + break; + + case RDSettings::OggVorbis: + printf("Content-type: audio/ogg\n\n"); + break; + + case RDSettings::Flac: + printf("Content-type: audio/flac\n\n"); + break; + } + fflush(NULL); + if((fd=open(tmpfile,O_RDONLY))>=0) { + while((n=read(fd,data,2048))>0) { + write(1,data,n); + } + } + close(fd); + break; + + case RDAudioConvert::ErrorFormatNotSupported: + case RDAudioConvert::ErrorInvalidSettings: + resp_code=415; + break; + + case RDAudioConvert::ErrorNoSource: + case RDAudioConvert::ErrorNoDestination: + case RDAudioConvert::ErrorInvalidSource: + case RDAudioConvert::ErrorNoSpace: + case RDAudioConvert::ErrorInternal: + case RDAudioConvert::ErrorNoDisc: + case RDAudioConvert::ErrorNoTrack: + case RDAudioConvert::ErrorInvalidSpeed: + case RDAudioConvert::ErrorFormatError: + resp_code=500; + break; + } + delete conv; + delete settings; + if(wavedata!=NULL) { + delete wavedata; + } + unlink(tmpfile); + rmdir(tmpdir); + exit(0); +} diff --git a/web/rdxport/exportpeaks.cpp b/web/rdxport/exportpeaks.cpp new file mode 100644 index 00000000..32eb9ea0 --- /dev/null +++ b/web/rdxport/exportpeaks.cpp @@ -0,0 +1,79 @@ +// exportpeaks.cpp +// +// Rivendell web service portal -- ExportPeaks service +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: exportpeaks.cpp,v 1.4 2012/02/13 23:01:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +void Xport::ExportPeaks() +{ + // + // Verify Post + // + int cartnum=0; + if(!xport_post->getValue("CART_NUMBER",&cartnum)) { + XmlExit("Missing CART_NUMBER",400); + } + int cutnum=0; + if(!xport_post->getValue("CUT_NUMBER",&cutnum)) { + XmlExit("Missing CUT_NUMBER",400); + } + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cartnum)) { + XmlExit("No such cart",404); + } + + // + // Open Audio File + // + RDWaveFile *wave=new RDWaveFile(RDCut::pathName(cartnum,cutnum)); + if(!wave->openWave()) { + XmlExit("No such audio",404); + } + if(!wave->hasEnergy()) { + XmlExit("No peak data available",400); + } + + // + // Send Data + // + printf("Content-type: application/octet-stream\n\n"); + fflush(NULL); + unsigned short *peaks=new unsigned short[wave->energySize()]; + wave->readEnergy(peaks,wave->energySize()); + write(1,peaks,sizeof(unsigned short)*wave->energySize()); + Exit(0); +} diff --git a/web/rdxport/groups.cpp b/web/rdxport/groups.cpp new file mode 100644 index 00000000..15acbb5a --- /dev/null +++ b/web/rdxport/groups.cpp @@ -0,0 +1,110 @@ +// groups.cpp +// +// Rivendell web service portal -- Group services +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: groups.cpp,v 1.5 2012/02/13 23:01:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +void Xport::ListGroups() +{ + QString sql; + RDSqlQuery *q; + RDGroup *group; + + // + // Generate Group List + // + sql=QString().sprintf("select GROUP_NAME from USER_PERMS \ + where USER_NAME=\"%s\" order by GROUP_NAME", + (const char *)RDEscapeString(xport_user->name())); + q=new RDSqlQuery(sql); + + // + // Process Request + // + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + printf("\n"); + printf("\n"); + while(q->next()) { + group=new RDGroup(q->value(0).toString()); + printf("%s",(const char *)group->xml()); + delete group; + } + printf("\n"); + + delete q; + Exit(0); +} + + +void Xport::ListGroup() +{ + QString sql; + RDSqlQuery *q; + RDGroup *group; + + // + // Verify Post + // + QString group_name; + if(!xport_post->getValue("GROUP_NAME",&group_name)) { + XmlExit("Missing GROUP_NAME",400); + } + + // + // Check Group Accessibility + // + sql=QString().sprintf("select GROUP_NAME from USER_PERMS \ + where (USER_NAME=\"%s\")&&(GROUP_NAME=\"%s\")", + (const char *)RDEscapeString(xport_user->name()), + (const char *)RDEscapeString(group_name)); + q=new RDSqlQuery(sql); + if(!q->first()) { + delete q; + XmlExit("No such group",404); + } + + // + // Process Request + // + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + printf("\n"); + group=new RDGroup(q->value(0).toString()); + printf("%s",(const char *)group->xml()); + delete group; + + delete q; + Exit(0); +} diff --git a/web/rdxport/import.cpp b/web/rdxport/import.cpp new file mode 100644 index 00000000..4841629c --- /dev/null +++ b/web/rdxport/import.cpp @@ -0,0 +1,170 @@ +// import.cpp +// +// Rivendell web service portal -- Import service +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: import.cpp,v 1.12.2.2 2014/01/15 19:56:32 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +void Xport::Import() +{ + unsigned length_deviation=0; + unsigned msecs; + int resp_code=0; + + // + // Verify Post + // + int cartnum=0; + if(!xport_post->getValue("CART_NUMBER",&cartnum)) { + XmlExit("Missing CART_NUMBER",400); + } + int cutnum=0; + if(!xport_post->getValue("CUT_NUMBER",&cutnum)) { + XmlExit("Missing CUT_NUMBER",400); + } + int channels=0; + if(!xport_post->getValue("CHANNELS",&channels)) { + XmlExit("Missing CHANNELS",400); + } + int normalization_level=0; + if(!xport_post->getValue("NORMALIZATION_LEVEL",&normalization_level)) { + XmlExit("Missing NORMALIZATION_LEVEL",400); + } + int autotrim_level=0; + if(!xport_post->getValue("AUTOTRIM_LEVEL",&autotrim_level)) { + XmlExit("Missing AUTOTRIM_LEVEL",400); + } + int use_metadata=0; + if(!xport_post->getValue("USE_METADATA",&use_metadata)) { + XmlExit("Missing USE_METADATA",400); + } + QString filename; + if(!xport_post->getValue("FILENAME",&filename)) { + XmlExit("Missing FILENAME",400); + } + if(!RDCart::exists(cartnum)) { + XmlExit("No such cart",404); + } + if(!RDCut::exists(cartnum,cutnum)) { + XmlExit("No such cut",404); + } + if(!xport_post->isFile("FILENAME")) { + XmlExit("Missing file data",400); + } + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cartnum)) { + XmlExit("No such cart",404); + } + if(!xport_user->editAudio()) { + XmlExit("Unauthorized",401); + } + + // + // Load Configuration + // + RDCart *cart=new RDCart(cartnum); + RDCut *cut=new RDCut(cartnum,cutnum); + RDLibraryConf *conf=new RDLibraryConf(xport_config->stationName(),0); + RDSettings *settings=new RDSettings(); + switch(conf->defaultFormat()) { + case 0: + settings->setFormat(RDSettings::Pcm16); + break; + + case 1: + settings->setFormat(RDSettings::MpegL2Wav); + break; + } + settings->setChannels(channels); + settings->setSampleRate(xport_system->sampleRate()); + settings->setBitRate(channels*conf->defaultBitrate()); + settings->setNormalizationLevel(normalization_level); + RDWaveFile *wave=new RDWaveFile(filename); + if(!wave->openWave()) { + delete wave; + XmlExit("Format Not Supported",415); + } + msecs=wave->getExtTimeLength(); + delete wave; + RDAudioConvert *conv=new RDAudioConvert(xport_config->stationName()); + conv->setSourceFile(filename); + conv->setDestinationFile(RDCut::pathName(cartnum,cutnum)); + conv->setDestinationSettings(settings); + RDAudioConvert::ErrorCode conv_err=conv->convert(); + switch(conv_err) { + case RDAudioConvert::ErrorOk: + cut->checkInRecording(xport_config->stationName(),settings,msecs); + if(use_metadata>0) { + cart->setMetadata(conv->sourceWaveData()); + cut->setMetadata(conv->sourceWaveData()); + } + if(autotrim_level!=0) { + cut->autoTrim(RDCut::AudioBoth,100*autotrim_level); + } + cart->updateLength(); + cart->resetRotation(); + cart->calculateAverageLength(&length_deviation); + cart->setLengthDeviation(length_deviation); + resp_code=200; + break; + + case RDAudioConvert::ErrorFormatNotSupported: + case RDAudioConvert::ErrorInvalidSettings: + resp_code=415; + break; + + case RDAudioConvert::ErrorNoSource: + case RDAudioConvert::ErrorNoDestination: + case RDAudioConvert::ErrorInvalidSource: + case RDAudioConvert::ErrorInternal: + case RDAudioConvert::ErrorNoSpace: + case RDAudioConvert::ErrorNoDisc: + case RDAudioConvert::ErrorNoTrack: + case RDAudioConvert::ErrorInvalidSpeed: + resp_code=500; + break; + + case RDAudioConvert::ErrorFormatError: + resp_code=400; + break; + } + delete conv; + delete settings; + delete conf; + delete cut; + delete cart; + XmlExit(RDAudioConvert::errorText(conv_err),resp_code,conv_err); +} diff --git a/web/rdxport/logs.cpp b/web/rdxport/logs.cpp new file mode 100644 index 00000000..580025bd --- /dev/null +++ b/web/rdxport/logs.cpp @@ -0,0 +1,123 @@ +// logs.cpp +// +// Rivendell web service portal -- Log services +// +// (C) Copyright 2013 Fred Gleason +// +// $Id: logs.cpp,v 1.1.2.4 2013/10/23 23:32:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +void Xport::ListLogs() +{ + QString sql; + RDSqlQuery *q; + RDLog *log; + QString service_name=""; + QString trackable; + + // + // Get Options + // + xport_post->getValue("SERVICE_NAME",&service_name); + xport_post->getValue("TRACKABLE",&trackable); + + // + // Generate Log List + // + sql="select NAME from LOGS"; + if((!service_name.isEmpty())||(trackable=="1")) { + sql+=" where"; + if(!service_name.isEmpty()) { + sql+=" (SERVICE=\""+RDEscapeString(service_name)+"\")&&"; + } + if(trackable=="1") { + sql+=" (SCHEDULED_TRACKS>0)&&"; + } + sql=sql.left(sql.length()-2); + } + sql+=" order by NAME"; + q=new RDSqlQuery(sql); + + // + // Process Request + // + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + printf("\n"); + printf("\n"); + while(q->next()) { + log=new RDLog(q->value(0).toString()); + printf("%s",(const char *)log->xml()); + delete log; + } + printf("\n"); + + delete q; + Exit(0); +} + + +void Xport::ListLog() +{ + RDLog *log; + QString name=""; + + // + // Get Options + // + xport_post->getValue("NAME",&name); + + // + // Verify that log exists + // + log=new RDLog(name); + if(!log->exists()) { + delete log; + XmlExit("No such log",404); + } + + // + // Generate Log Listing + // + RDLogEvent *log_event=log->createLogEvent(); + log_event->load(true); + + // + // Process Request + // + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + printf("\n"); + printf("%s\n",(const char *)log_event->xml()); + + Exit(0); +} diff --git a/web/rdxport/rdxport.cpp b/web/rdxport/rdxport.cpp new file mode 100644 index 00000000..55ac386c --- /dev/null +++ b/web/rdxport/rdxport.cpp @@ -0,0 +1,287 @@ +// rdxport.cpp +// +// Rivendell web service portal +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: rdxport.cpp,v 1.10.2.3 2013/10/14 04:23:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +Xport::Xport(QObject *parent,const char *name) + :QObject(parent,name) +{ + xport_user=NULL; + + // + // Read Configuration + // + xport_config=new RDConfig(); + xport_config->load(); + + // + // Drop Root Perms + // + if(setgid(xport_config->gid())<0) { + XmlExit("Unable to set Rivendell group",500); + } + if(setuid(xport_config->uid())<0) { + XmlExit("Unable to set Rivendell user",500); + } + if(getuid()==0) { + XmlExit("Rivendell user should never be \"root\"!",500); + } + + // + // Open Database + // + QSqlDatabase *db=QSqlDatabase::addDatabase(xport_config->mysqlDriver()); + if(!db) { + printf("Content-type: text/html\n\n"); + printf("rdfeed: unable to initialize connection to database\n"); + Exit(0); + } + db->setDatabaseName(xport_config->mysqlDbname()); + db->setUserName(xport_config->mysqlUsername()); + db->setPassword(xport_config->mysqlPassword()); + db->setHostName(xport_config->mysqlHostname()); + if(!db->open()) { + printf("Content-type: text/html\n\n"); + printf("rdxport: unable to connect to database\n"); + db->removeDatabase(xport_config->mysqlDbname()); + Exit(0); + } + RDSqlQuery *q=new RDSqlQuery("select DB from VERSION"); + if(!q->first()) { + printf("Content-type: text/html\n"); + printf("Status: 500\n\n"); + printf("rdxport: missing/invalid database version!\n"); + db->removeDatabase(xport_config->mysqlDbname()); + Exit(0); + } + if(q->value(0).toUInt()!=RD_VERSION_DATABASE) { + printf("Content-type: text/html\n"); + printf("Status: 500\n\n"); + printf("rdxport: skewed database version!\n"); + db->removeDatabase(xport_config->mysqlDbname()); + Exit(0); + } + delete q; + + // + // Determine Connection Type + // + if(getenv("REQUEST_METHOD")==NULL) { + printf("Content-type: text/html\n\n"); + printf("rdxport: missing REQUEST_METHOD\n"); + db->removeDatabase(xport_config->mysqlDbname()); + Exit(0); + } + if(QString(getenv("REQUEST_METHOD")).lower()!="post") { + printf("Content-type: text/html\n\n"); + printf("rdxport: invalid web method\n"); + db->removeDatabase(xport_config->mysqlDbname()); + Exit(0); + } + + // + // Load System Settings + // + xport_system=new RDSystem(); + + // + // Generate Post + // + xport_post=new RDFormPost(RDFormPost::AutoEncoded,false); + if(xport_post->error()!=RDFormPost::ErrorOk) { + XmlExit(xport_post->errorString(xport_post->error()),400); + Exit(0); + } + + // + // Authenticate Connection + // + if(!Authenticate()) { + XmlExit("Invalid User",403); + } + + // + // Read Command Variable and Dispatch + // + int command=xport_post->value("COMMAND").toInt(); + switch(command) { + case RDXPORT_COMMAND_EXPORT: + Export(); + break; + + case RDXPORT_COMMAND_IMPORT: + Import(); + break; + + case RDXPORT_COMMAND_DELETEAUDIO: + DeleteAudio(); + break; + + case RDXPORT_COMMAND_LISTGROUPS: + ListGroups(); + break; + + case RDXPORT_COMMAND_LISTGROUP: + ListGroup(); + break; + + case RDXPORT_COMMAND_ADDCART: + AddCart(); + break; + + case RDXPORT_COMMAND_LISTCARTS: + ListCarts(); + break; + + case RDXPORT_COMMAND_LISTCART: + ListCart(); + break; + + case RDXPORT_COMMAND_EDITCART: + EditCart(); + break; + + case RDXPORT_COMMAND_REMOVECART: + RemoveCart(); + break; + + case RDXPORT_COMMAND_ADDCUT: + AddCut(); + break; + + case RDXPORT_COMMAND_LISTCUTS: + ListCuts(); + break; + + case RDXPORT_COMMAND_LISTCUT: + ListCut(); + break; + + case RDXPORT_COMMAND_EDITCUT: + EditCut(); + break; + + case RDXPORT_COMMAND_REMOVECUT: + RemoveCut(); + break; + + case RDXPORT_COMMAND_EXPORT_PEAKS: + ExportPeaks(); + break; + + case RDXPORT_COMMAND_TRIMAUDIO: + TrimAudio(); + break; + + case RDXPORT_COMMAND_COPYAUDIO: + CopyAudio(); + break; + + case RDXPORT_COMMAND_AUDIOINFO: + AudioInfo(); + break; + + case RDXPORT_COMMAND_LISTLOGS: + ListLogs(); + break; + + case RDXPORT_COMMAND_LISTLOG: + ListLog(); + break; + + case RDXPORT_COMMAND_LISTSERVICES: + ListServices(); + break; + + default: + printf("Content-type: text/html\n\n"); + printf("rdxport: missing/invalid command\n"); + db->removeDatabase(xport_config->mysqlDbname()); + Exit(0); + break; + } + + Exit(0); +} + + +bool Xport::Authenticate() +{ + QString name; + QString passwd; + + if(!xport_post->getValue("LOGIN_NAME",&name)) { + return false; + } + if(!xport_post->getValue("PASSWORD",&passwd)) { + return false; + } + xport_user=new RDUser(name); + + return xport_user->checkPassword(passwd,false); +} + + +void Xport::Exit(int code) +{ + if(xport_post!=NULL) { + delete xport_post; + } + exit(code); +} + + +void Xport::XmlExit(const QString &str,int code,RDAudioConvert::ErrorCode err) +{ + if(xport_post!=NULL) { + delete xport_post; + } + RDXMLResult(str,code,err); + exit(0); +} + + +int main(int argc,char *argv[]) +{ + QApplication a(argc,argv,false); + new Xport(NULL,"main"); + return a.exec(); +} diff --git a/web/rdxport/rdxport.h b/web/rdxport/rdxport.h new file mode 100644 index 00000000..635ec250 --- /dev/null +++ b/web/rdxport/rdxport.h @@ -0,0 +1,72 @@ +// rdxport.h +// +// Rivendell web service portal +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: rdxport.h,v 1.7.2.3 2013/10/14 04:23:54 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + + +#ifndef RDXPORT_H +#define RDXPORT_H + +#include + +#include +#include +#include + +class Xport : public QObject +{ + public: + Xport(QObject *parent=0,const char *name=0); + + private: + bool Authenticate(); + void Export(); + void Import(); + void DeleteAudio(); + void AddCart(); + void ListCarts(); + void ListCart(); + void EditCart(); + void RemoveCart(); + void AddCut(); + void ListCuts(); + void ListCut(); + void EditCut(); + void RemoveCut(); + void ListGroups(); + void ListGroup(); + void ExportPeaks(); + void TrimAudio(); + void CopyAudio(); + void AudioInfo(); + void ListLogs(); + void ListLog(); + void ListServices(); + void Exit(int code); + void XmlExit(const QString &str,int code, + RDAudioConvert::ErrorCode err=RDAudioConvert::ErrorOk); + RDFormPost *xport_post; + RDUser *xport_user; + RDConfig *xport_config; + RDSystem *xport_system; +}; + + +#endif // RDXPORT_H diff --git a/web/rdxport/rdxport.pro b/web/rdxport/rdxport.pro new file mode 100644 index 00000000..e69de29b diff --git a/web/rdxport/services.cpp b/web/rdxport/services.cpp new file mode 100644 index 00000000..94e9fb9a --- /dev/null +++ b/web/rdxport/services.cpp @@ -0,0 +1,77 @@ +// services.cpp +// +// Rivendell web service portal -- Service services +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: services.cpp,v 1.1.2.1 2013/10/11 22:00:53 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +void Xport::ListServices() +{ + QString sql; + RDSqlQuery *q; + RDSvc *svc; + QString trackable; + + // + // Get Options + // + xport_post->getValue("TRACKABLE",&trackable); + + // + // Generate Service List + // + sql="select NAME from SERVICES"; + if(trackable=="1") { + sql+=" where (TRACK_GROUP!=\"\")&&(TRACK_GROUP is not null)"; + } + sql+=" order by NAME"; + q=new RDSqlQuery(sql); + + // + // Process Request + // + printf("Content-type: application/xml\n"); + printf("Status: 200\n\n"); + printf("\n"); + printf("\n"); + while(q->next()) { + svc=new RDSvc(q->value(0).toString()); + printf("%s",(const char *)svc->xml()); + delete svc; + } + printf("\n"); + + delete q; + Exit(0); +} diff --git a/web/rdxport/trimaudio.cpp b/web/rdxport/trimaudio.cpp new file mode 100644 index 00000000..a3e47183 --- /dev/null +++ b/web/rdxport/trimaudio.cpp @@ -0,0 +1,98 @@ +// trimaudio.cpp +// +// Rivendell web service portal -- TrimAudio service +// +// (C) Copyright 2010 Fred Gleason +// +// $Id: trimaudio.cpp,v 1.4 2012/02/13 23:01:50 cvs Exp $ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +void Xport::TrimAudio() +{ + int point; + + // + // Verify Post + // + int cartnum=0; + if(!xport_post->getValue("CART_NUMBER",&cartnum)) { + XmlExit("Missing CART_NUMBER",400); + } + int cutnum=0; + if(!xport_post->getValue("CUT_NUMBER",&cutnum)) { + XmlExit("Missing CUT_NUMBER",400); + } + + int trim_level=0; + if(!xport_post->getValue("TRIM_LEVEL",&trim_level)) { + XmlExit("Missing TRIM_LEVEL",400); + } + + // + // Verify User Perms + // + if(!xport_user->cartAuthorized(cartnum)) { + XmlExit("No such cart",404); + } + + // + // Open Audio File + // + RDWaveFile *wave=new RDWaveFile(RDCut::pathName(cartnum,cutnum)); + if(!wave->openWave()) { + XmlExit("No such audio",404); + } + if(!wave->hasEnergy()) { + XmlExit("No peak data available",400); + } + + // + // Send Data + // + printf("Content-type: application/xml\n\n"); + printf("\n"); + printf("\n"); + printf(" %u\n",cartnum); + printf(" %d\n",cutnum); + printf(" %d\n",trim_level); + point=wave->startTrim(REFERENCE_LEVEL-trim_level); + if(point>=0) { + point=(double)point*1000.0/(double)wave->getSamplesPerSec(); + } + printf(" %d\n",point); + point=wave->endTrim(REFERENCE_LEVEL-trim_level); + if(point>=0) { + point=(double)point*1000.0/(double)wave->getSamplesPerSec(); + } + printf(" %d\n",point); + printf("\n"); + Exit(0); +} diff --git a/web/tests/Makefile.am b/web/tests/Makefile.am new file mode 100644 index 00000000..d1351884 --- /dev/null +++ b/web/tests/Makefile.am @@ -0,0 +1,96 @@ +## automake.am +## +## Automake.am for rivendell/web/tests +## +## (C) Copyright 2010,2013 Fred Gleason +## +## $Id: Makefile.am,v 1.6.6.4 2013/10/14 04:23:55 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +install-exec-am: + mkdir -p $(DESTDIR)@libexecdir@ + cp addcart.html $(DESTDIR)@libexecdir@ + cp addcut.html $(DESTDIR)@libexecdir@ + cp audioinfo.html $(DESTDIR)@libexecdir@ + cp copyaudio.html $(DESTDIR)@libexecdir@ + cp delete_audio.html $(DESTDIR)@libexecdir@ + cp editcart.html $(DESTDIR)@libexecdir@ + cp export.html $(DESTDIR)@libexecdir@ + cp exportpeaks.html $(DESTDIR)@libexecdir@ + cp import.html $(DESTDIR)@libexecdir@ + cp import.html $(DESTDIR)@libexecdir@ + cp listcart.html $(DESTDIR)@libexecdir@ + cp listcarts.html $(DESTDIR)@libexecdir@ + cp listcut.html $(DESTDIR)@libexecdir@ + cp listcuts.html $(DESTDIR)@libexecdir@ + cp listgroup.html $(DESTDIR)@libexecdir@ + cp listgroups.html $(DESTDIR)@libexecdir@ + cp listlog.html $(DESTDIR)@libexecdir@ + cp listlogs.html $(DESTDIR)@libexecdir@ + cp listservices.html $(DESTDIR)@libexecdir@ + cp removecart.html $(DESTDIR)@libexecdir@ + cp removecut.html $(DESTDIR)@libexecdir@ + cp trimaudio.html $(DESTDIR)@libexecdir@ + +uninstall: + rm -f $(DESTDIR)@libexecdir@/addcart.html + rm -f $(DESTDIR)@libexecdir@/addcut.html + rm -f $(DESTDIR)@libexecdir@/audioinfo.html + rm -f $(DESTDIR)@libexecdir@/copyaudio.html + rm -f $(DESTDIR)@libexecdir@/delete_audio.html + rm -f $(DESTDIR)@libexecdir@/editcart.html + rm -f $(DESTDIR)@libexecdir@/export.html + rm -f $(DESTDIR)@libexecdir@/exportpeaks.html + rm -f $(DESTDIR)@libexecdir@/import.html + rm -f $(DESTDIR)@libexecdir@/listcart.html + rm -f $(DESTDIR)@libexecdir@/listcarts.html + rm -f $(DESTDIR)@libexecdir@/listcut.html + rm -f $(DESTDIR)@libexecdir@/listcuts.html + rm -f $(DESTDIR)@libexecdir@/listgroup.html + rm -f $(DESTDIR)@libexecdir@/listgroups.html + rm -f $(DESTDIR)@libexecdir@/listlog.html + rm -f $(DESTDIR)@libexecdir@/listlogs.html + rm -f $(DESTDIR)@libexecdir@/listservices.html + rm -f $(DESTDIR)@libexecdir@/removecart.html + rm -f $(DESTDIR)@libexecdir@/removecut.html + rm -f $(DESTDIR)@libexecdir@/trimaudio.html + +EXTRA_DIST = addcart.html\ + addcut.html\ + audioinfo.html\ + copyaudio.html\ + delete_audio.html\ + editcart.html\ + export.html\ + exportpeaks.html\ + import.html\ + listcart.html\ + listcarts.html\ + listcut.html\ + listcuts.html\ + listgroup.html\ + listgroups.html\ + listlog.html\ + listlogs.html\ + listservices.html\ + removecart.html\ + removecut.html\ + trimaudio.html + +CLEANFILES = *~ +MAINTAINERCLEANFILES = *~\ + Makefile.in diff --git a/web/tests/addcart.html b/web/tests/addcart.html new file mode 100644 index 00000000..d8d8b258 --- /dev/null +++ b/web/tests/addcart.html @@ -0,0 +1,41 @@ + + +Rivendell ADDCART Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
GROUP NAME:
TYPE: +
CART NUMBER:
 
+
+ + diff --git a/web/tests/addcut.html b/web/tests/addcut.html new file mode 100644 index 00000000..528adc7a --- /dev/null +++ b/web/tests/addcut.html @@ -0,0 +1,29 @@ + + +Rivendell ADDCUT Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
 
+
+ + diff --git a/web/tests/audioinfo.html b/web/tests/audioinfo.html new file mode 100644 index 00000000..31b3559b --- /dev/null +++ b/web/tests/audioinfo.html @@ -0,0 +1,33 @@ + + +Rivendell AUDIOINFO Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
CUT NUMBER:
 
+
+ + diff --git a/web/tests/copyaudio.html b/web/tests/copyaudio.html new file mode 100644 index 00000000..49786bc5 --- /dev/null +++ b/web/tests/copyaudio.html @@ -0,0 +1,41 @@ + + +Rivendell COPYAUDIO Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
SOURCE_CART NUMBER:
SOURCE_CUT NUMBER:
DESTINATION_CART NUMBER:
DESTINATION_CUT NUMBER:
 
+
+ + diff --git a/web/tests/delete_audio.html b/web/tests/delete_audio.html new file mode 100644 index 00000000..aa2c24fb --- /dev/null +++ b/web/tests/delete_audio.html @@ -0,0 +1,33 @@ + + +Rivendell DELETE AUDIO Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
CUT NUMBER:
 
+
+ + diff --git a/web/tests/editcart.html b/web/tests/editcart.html new file mode 100644 index 00000000..147b538a --- /dev/null +++ b/web/tests/editcart.html @@ -0,0 +1,43 @@ + + +Rivendell EDITCART Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
INCLUDE CUTS:
TITLE:
 
+
+ + diff --git a/web/tests/export.html b/web/tests/export.html new file mode 100644 index 00000000..f63e7551 --- /dev/null +++ b/web/tests/export.html @@ -0,0 +1,90 @@ + + +Rivendell EXPORT Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
CUT NUMBER:
FORMAT: +
CHANNELS:
SAMPLE RATE:
BIT RATE:
QUALITY: +
START POINT:
END POINT:
NORMALIZATION LEVEL:
ENABLE METADATA:
 
+
+ + diff --git a/web/tests/exportpeaks.html b/web/tests/exportpeaks.html new file mode 100644 index 00000000..08356162 --- /dev/null +++ b/web/tests/exportpeaks.html @@ -0,0 +1,33 @@ + + +Rivendell EXPORT PEAKS Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
CUT NUMBER:
 
+
+ + diff --git a/web/tests/import.html b/web/tests/import.html new file mode 100644 index 00000000..2afb0887 --- /dev/null +++ b/web/tests/import.html @@ -0,0 +1,53 @@ + + +Rivendel IMPORT Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
CUT NUMBER:
CHANNELS:
NORMALIZATION LEVEL:
AUTOTRIM LEVEL:
USE METADATA:
FILE:
 
+
+ + diff --git a/web/tests/listcart.html b/web/tests/listcart.html new file mode 100644 index 00000000..c2ea5063 --- /dev/null +++ b/web/tests/listcart.html @@ -0,0 +1,33 @@ + + +Rivendell LISTCART Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
INCLUDE CUTS:
 
+
+ + diff --git a/web/tests/listcarts.html b/web/tests/listcarts.html new file mode 100644 index 00000000..f1a12db0 --- /dev/null +++ b/web/tests/listcarts.html @@ -0,0 +1,37 @@ + + +Rivendell LISTCARTS Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
GROUP NAME:
FILTER:
INCLUDE CUTS:
 
+
+ + diff --git a/web/tests/listcut.html b/web/tests/listcut.html new file mode 100644 index 00000000..b92833b6 --- /dev/null +++ b/web/tests/listcut.html @@ -0,0 +1,33 @@ + + +Rivendell LISTCUT Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
CUT NUMBER:
 
+
+ + diff --git a/web/tests/listcuts.html b/web/tests/listcuts.html new file mode 100644 index 00000000..4811b4e7 --- /dev/null +++ b/web/tests/listcuts.html @@ -0,0 +1,29 @@ + + +Rivendell LISTCUTS Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
 
+
+ + diff --git a/web/tests/listgroup.html b/web/tests/listgroup.html new file mode 100644 index 00000000..358d60b6 --- /dev/null +++ b/web/tests/listgroup.html @@ -0,0 +1,29 @@ + + +Rivendell LISTGROUP Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
GROUP NAME:
 
+
+ + diff --git a/web/tests/listgroups.html b/web/tests/listgroups.html new file mode 100644 index 00000000..3ca76e1c --- /dev/null +++ b/web/tests/listgroups.html @@ -0,0 +1,25 @@ + + +Rivendell LISTGROUPS Service Test Harness + +
+ + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
 
+
+ + diff --git a/web/tests/listlog.html b/web/tests/listlog.html new file mode 100644 index 00000000..2e2d6d73 --- /dev/null +++ b/web/tests/listlog.html @@ -0,0 +1,29 @@ + + +Rivendell LISTLOG Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
NAME:
 
+
+ + diff --git a/web/tests/listlogs.html b/web/tests/listlogs.html new file mode 100644 index 00000000..f26e49f3 --- /dev/null +++ b/web/tests/listlogs.html @@ -0,0 +1,33 @@ + + +Rivendell LISTLOGS Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
SERVICE NAME:
TRACKABLE:
 
+
+ + diff --git a/web/tests/listservices.html b/web/tests/listservices.html new file mode 100644 index 00000000..e9038eee --- /dev/null +++ b/web/tests/listservices.html @@ -0,0 +1,29 @@ + + +Rivendell LISTSERVICES Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
TRACKABLE:
 
+
+ + diff --git a/web/tests/removecart.html b/web/tests/removecart.html new file mode 100644 index 00000000..e57ac030 --- /dev/null +++ b/web/tests/removecart.html @@ -0,0 +1,29 @@ + + +Rivendell REMOVECART Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
 
+
+ + diff --git a/web/tests/removecut.html b/web/tests/removecut.html new file mode 100644 index 00000000..a6ec7243 --- /dev/null +++ b/web/tests/removecut.html @@ -0,0 +1,33 @@ + + +Rivendell REMOVECUT Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
CUT NUMBER:
 
+
+ + diff --git a/web/tests/trimaudio.html b/web/tests/trimaudio.html new file mode 100644 index 00000000..5da69847 --- /dev/null +++ b/web/tests/trimaudio.html @@ -0,0 +1,37 @@ + + +Rivendell TRIMAUDIO Service Test Harness + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LOGIN NAME:
PASSWORD:
CART NUMBER:
CUT NUMBER:
TRIM LEVEL:
 
+
+ + diff --git a/web/web.pro b/web/web.pro new file mode 100644 index 00000000..e69de29b diff --git a/xdg/Makefile.am b/xdg/Makefile.am new file mode 100644 index 00000000..f5e9678d --- /dev/null +++ b/xdg/Makefile.am @@ -0,0 +1,87 @@ +## automake.am +## +## xdg/automake.am for Rivendell +## +## (C) Copyright 2002-2005 Fred Gleason +## +## $Id: Makefile.am,v 1.11.2.8 2013/12/27 00:04:04 cvs Exp $ +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2 as +## published by the Free Software Foundation. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public +## License along with this program; if not, write to the Free Software +## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +## +## Use automake to process this into a Makefile.in + +install-exec-am: + mkdir -p @prefix@/share/applications + cp rivendell-rdadmin.desktop @prefix@/share/applications/ + cp rivendell-rdairplay.desktop @prefix@/share/applications/ + cp rivendell-rdalsaconfig.desktop @prefix@/share/applications/ + cp rivendell-rdcartslots.desktop @prefix@/share/applications/ + cp rivendell-rdcastmanager.desktop @prefix@/share/applications/ + cp rivendell-rdcatch.desktop @prefix@/share/applications/ + cp rivendell-rddgimport.desktop @prefix@/share/applications/ + cp rivendell-rddiscimport.desktop @prefix@/share/applications/ + cp rivendell-rdgpimon.desktop @prefix@/share/applications/ + cp rivendell-rdhpiinfo.desktop @prefix@/share/applications/ + cp rivendell-rdlibrary.desktop @prefix@/share/applications/ + cp rivendell-rdlogedit.desktop @prefix@/share/applications/ + cp rivendell-rdlogin.desktop @prefix@/share/applications/ + cp rivendell-rdlogmanager.desktop @prefix@/share/applications/ + cp rivendell-rdmonitor.desktop @prefix@/share/applications/ + cp rivendell-rdpanel.desktop @prefix@/share/applications/ + cp rivendell-rdsoftkeys.desktop @prefix@/share/applications/ + cp rivendell-rmlsend.desktop @prefix@/share/applications/ + mkdir -p @prefix@/share/desktop-directories + cp *.directory @prefix@/share/desktop-directories/ + mkdir -p /etc/xdg/menus/applications-merged + cp *.menu /etc/xdg/menus/applications-merged/ + +uninstall: + rm -f @prefix@/share/applications/rivendell-*.desktop + rm -f @prefix@/share/desktop-directories/rivendell-*.directory + rm -f /etc/xdg/menus/applications-merged/rivendell-*.menu + +EXTRA_DIST = rdalsaconfig-root-consolehelper\ + rdalsaconfig-root-pam\ + rdhpiinfo-root-consolehelper\ + rdhpiinfo-root-pam\ + rivendell-configuration.directory\ + rivendell-logtools.directory\ + rivendell-rdadmin.desktop\ + rivendell-rdairplay.desktop\ + rivendell-rdalsaconfig.desktop\ + rivendell-rdalsaconfig-root.desktop\ + rivendell-rdcartslots.desktop\ + rivendell-rdcastmanager.desktop\ + rivendell-rdcatch.desktop\ + rivendell-rddgimport.desktop\ + rivendell-rddiscimport.desktop\ + rivendell-rdgpimon.desktop\ + rivendell-rdhpiinfo.desktop\ + rivendell-rdhpiinfo-root.desktop\ + rivendell-rdlibrary.desktop\ + rivendell-rdlogedit.desktop\ + rivendell-rdlogin.desktop\ + rivendell-rdlogmanager.desktop\ + rivendell-rdmonitor.desktop\ + rivendell-rdpanel.desktop\ + rivendell-rmlsend.desktop\ + rivendell-rdsoftkeys.desktop\ + rivendell-rivendell.directory\ + rivendell-rivendell.menu\ + rivendell-utilities.directory + +CLEANFILES = *~ + +MAINTAINERCLEANFILES = *~\ + Makefile.in diff --git a/xdg/rdalsaconfig-root-consolehelper b/xdg/rdalsaconfig-root-consolehelper new file mode 100644 index 00000000..42c1fd81 --- /dev/null +++ b/xdg/rdalsaconfig-root-consolehelper @@ -0,0 +1,2 @@ +USER=root +PROGRAM=/usr/bin/rdalsaconfig diff --git a/xdg/rdalsaconfig-root-pam b/xdg/rdalsaconfig-root-pam new file mode 100644 index 00000000..b95f5243 --- /dev/null +++ b/xdg/rdalsaconfig-root-pam @@ -0,0 +1,4 @@ +#%PAM-1.0 +auth include config-util +account include config-util +session include config-util diff --git a/xdg/rdhpiinfo-root-consolehelper b/xdg/rdhpiinfo-root-consolehelper new file mode 100644 index 00000000..67378d3b --- /dev/null +++ b/xdg/rdhpiinfo-root-consolehelper @@ -0,0 +1,2 @@ +USER=root +PROGRAM=/usr/bin/rdhpiinfo diff --git a/xdg/rdhpiinfo-root-pam b/xdg/rdhpiinfo-root-pam new file mode 100644 index 00000000..b95f5243 --- /dev/null +++ b/xdg/rdhpiinfo-root-pam @@ -0,0 +1,4 @@ +#%PAM-1.0 +auth include config-util +account include config-util +session include config-util diff --git a/xdg/rivendell-configuration.directory b/xdg/rivendell-configuration.directory new file mode 100644 index 00000000..2781a458 --- /dev/null +++ b/xdg/rivendell-configuration.directory @@ -0,0 +1,6 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Directory +Name=Configuration +Icon=rivendell + diff --git a/xdg/rivendell-logtools.directory b/xdg/rivendell-logtools.directory new file mode 100644 index 00000000..1bc42e33 --- /dev/null +++ b/xdg/rivendell-logtools.directory @@ -0,0 +1,6 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Directory +Name=Log Tools +Icon=rivendell + diff --git a/xdg/rivendell-rdadmin.desktop b/xdg/rivendell-rdadmin.desktop new file mode 100644 index 00000000..036badfe --- /dev/null +++ b/xdg/rivendell-rdadmin.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDAdmin +GenericName=Rivendell Configuration +Exec=rdadmin +Icon=rivendell +Type=Application +Terminal=false diff --git a/xdg/rivendell-rdairplay.desktop b/xdg/rivendell-rdairplay.desktop new file mode 100644 index 00000000..325cdc8e --- /dev/null +++ b/xdg/rivendell-rdairplay.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Application +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDAirPlay +GenericName=Rivendell On-Air Playout +Exec=rdairplay +Icon=rivendell diff --git a/xdg/rivendell-rdalsaconfig-root.desktop b/xdg/rivendell-rdalsaconfig-root.desktop new file mode 100644 index 00000000..f77d959b --- /dev/null +++ b/xdg/rivendell-rdalsaconfig-root.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDAlsaConfig +GenericName=Rivendell ALSA Configuration +Exec=rdalsaconfig-root --manage-daemons +Icon=rivendell +Type=Application +Terminal=false diff --git a/xdg/rivendell-rdalsaconfig.desktop b/xdg/rivendell-rdalsaconfig.desktop new file mode 100644 index 00000000..386ae455 --- /dev/null +++ b/xdg/rivendell-rdalsaconfig.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDAlsaConfig +GenericName=Rivendell ALSA Configuration +Exec=rdalsaconfig --manage-daemons +Icon=rivendell +Type=Application +Terminal=false +X-KDE-SubstituteUID=true +X-KDE-Username=root diff --git a/xdg/rivendell-rdcartslots.desktop b/xdg/rivendell-rdcartslots.desktop new file mode 100644 index 00000000..f812554b --- /dev/null +++ b/xdg/rivendell-rdcartslots.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDCartSlots +GenericName=Rivendell Cart Deck Module +Exec=rdcartslots +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rdcastmanager.desktop b/xdg/rivendell-rdcastmanager.desktop new file mode 100644 index 00000000..af95d2b7 --- /dev/null +++ b/xdg/rivendell-rdcastmanager.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Categories=Qt;KDE;Rivendell +Terminal=false +Name=RDCastManager +GenericName=Rivendell RSS Feed Management +Exec=rdcastmanager +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rdcatch.desktop b/xdg/rivendell-rdcatch.desktop new file mode 100644 index 00000000..7838428c --- /dev/null +++ b/xdg/rivendell-rdcatch.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDCatch +GenericName=Rivendell Event Scheduler +Exec=rdcatch +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rddgimport.desktop b/xdg/rivendell-rddgimport.desktop new file mode 100644 index 00000000..059b2629 --- /dev/null +++ b/xdg/rivendell-rddgimport.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt:KDE;Rivendell; +Name=RDDgImport +GenericName=Rivendell DG Spot Importer +Exec=rddgimport +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rddiscimport.desktop b/xdg/rivendell-rddiscimport.desktop new file mode 100644 index 00000000..abd8dfe8 --- /dev/null +++ b/xdg/rivendell-rddiscimport.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt:KDE;Rivendell; +Name=RDDiscImport +GenericName=Rivendell Batch CD Importer +Exec=rddiscimport +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rdgpimon.desktop b/xdg/rivendell-rdgpimon.desktop new file mode 100644 index 00000000..b589092f --- /dev/null +++ b/xdg/rivendell-rdgpimon.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt:KDE;Rivendell; +Name=RDGpiMon +GenericName=Rivendell GPI Monitor +Exec=rdgpimon +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rdhpiinfo-root.desktop b/xdg/rivendell-rdhpiinfo-root.desktop new file mode 100644 index 00000000..117e8716 --- /dev/null +++ b/xdg/rivendell-rdhpiinfo-root.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDHPIInfo +GenericName=AudioScience Card Information +Exec=rdhpiinfo-root +Icon=rivendell +Type=Application +Terminal=false diff --git a/xdg/rivendell-rdhpiinfo.desktop b/xdg/rivendell-rdhpiinfo.desktop new file mode 100644 index 00000000..34d9a00f --- /dev/null +++ b/xdg/rivendell-rdhpiinfo.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDHPIInfo +GenericName=AudioScience Card Information +Exec=rdhpiinfo +Icon=rivendell +Type=Application +Terminal=false +X-KDE-SubstituteUID=true +X-KDE-Username=root diff --git a/xdg/rivendell-rdlibrary.desktop b/xdg/rivendell-rdlibrary.desktop new file mode 100644 index 00000000..3ce49745 --- /dev/null +++ b/xdg/rivendell-rdlibrary.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDLibrary +GenericName=Rivendell Library +Exec=rdlibrary +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rdlogedit.desktop b/xdg/rivendell-rdlogedit.desktop new file mode 100644 index 00000000..96df01b6 --- /dev/null +++ b/xdg/rivendell-rdlogedit.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDLogEdit +GenericName=Rivendell Log Editor +Exec=rdlogedit +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rdlogin.desktop b/xdg/rivendell-rdlogin.desktop new file mode 100644 index 00000000..e6dccdff --- /dev/null +++ b/xdg/rivendell-rdlogin.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDLogin +GenericName=Rivendell Login +Exec=rdlogin +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rdlogmanager.desktop b/xdg/rivendell-rdlogmanager.desktop new file mode 100644 index 00000000..e80ebbe1 --- /dev/null +++ b/xdg/rivendell-rdlogmanager.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDLogManager +GenericName=Rivendell Log Management +Exec=rdlogmanager +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rdmonitor.desktop b/xdg/rivendell-rdmonitor.desktop new file mode 100644 index 00000000..fcbb59e0 --- /dev/null +++ b/xdg/rivendell-rdmonitor.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDMonitor +GenericName=Rivendell Server Monitor +Exec=rdmonitor +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rdpanel.desktop b/xdg/rivendell-rdpanel.desktop new file mode 100644 index 00000000..c2194547 --- /dev/null +++ b/xdg/rivendell-rdpanel.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDPanel +GenericName=Rivendell SoundPanel Module +Exec=rdpanel +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rdsoftkeys.desktop b/xdg/rivendell-rdsoftkeys.desktop new file mode 100644 index 00000000..c0f1329c --- /dev/null +++ b/xdg/rivendell-rdsoftkeys.desktop @@ -0,0 +1,11 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RDSoftKeys +GenericName=Rivendell RML Button Panel +Exec=rdsoftkeys +Icon=rivendell +Type=Application +Terminal=false + diff --git a/xdg/rivendell-rivendell.directory b/xdg/rivendell-rivendell.directory new file mode 100644 index 00000000..8ad3ecb6 --- /dev/null +++ b/xdg/rivendell-rivendell.directory @@ -0,0 +1,6 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Directory +Name=Rivendell +Icon=rivendell + diff --git a/xdg/rivendell-rivendell.menu b/xdg/rivendell-rivendell.menu new file mode 100644 index 00000000..67bca572 --- /dev/null +++ b/xdg/rivendell-rivendell.menu @@ -0,0 +1,49 @@ + + + +Applications + + Rivendell + rivendell-rivendell.directory + + rivendell-rdairplay.desktop + rivendell-rdcartslots.desktop + rivendell-rdcastmanager.desktop + rivendell-rdcatch.desktop + rivendell-rdlibrary.desktop + rivendell-rdlogin.desktop + rivendell-rdpanel.desktop + + + Configuration + rivendell-configuration.directory + + rivendell-rdadmin.desktop + rivendell-rdalsaconfig.desktop + rivendell-rdalsaconfig-root.desktop + rivendell-rdhpiinfo.desktop + rivendell-rdhpiinfo-root.desktop + + + + Log Tools + rivendell-logtools.directory + + rivendell-rdlogedit.desktop + rivendell-rdlogmanager.desktop + + + + Utilities + rivendell-utilities.directory + + rivendell-rdgpimon.desktop + rivendell-rdsoftkeys.desktop + rivendell-rmlsend.desktop + rivendell-rddgimport.desktop + rivendell-rddiscimport.desktop + + + + diff --git a/xdg/rivendell-rmlsend.desktop b/xdg/rivendell-rmlsend.desktop new file mode 100644 index 00000000..f9322520 --- /dev/null +++ b/xdg/rivendell-rmlsend.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Encoding=UTF-8 +Terminal=false +Categories=Qt;KDE;Rivendell; +Name=RMLSend +GenericName=Rivendell RML Applet +Exec=rmlsend +Icon=rivendell +Type=Application +Terminal=false diff --git a/xdg/rivendell-utilities.directory b/xdg/rivendell-utilities.directory new file mode 100644 index 00000000..a30d1fee --- /dev/null +++ b/xdg/rivendell-utilities.directory @@ -0,0 +1,6 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Directory +Name=Utilities +Icon=rivendell +